Annotation of loncom/homework/math_parser/QMatrix.pm, revision 1.1

1.1     ! damieng     1: # The LearningOnline Network with CAPA - LON-CAPA
        !             2: # QMatrix
        !             3: #
        !             4: # Copyright (C) 2014 Michigan State University Board of Trustees
        !             5: #
        !             6: # This program is free software: you can redistribute it and/or modify
        !             7: # it under the terms of the GNU General Public License as published by
        !             8: # the Free Software Foundation, either version 3 of the License, or
        !             9: # (at your option) any later version.
        !            10: #
        !            11: # This program is distributed in the hope that it will be useful,
        !            12: # but WITHOUT ANY WARRANTY; without even the implied warranty of
        !            13: # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
        !            14: # GNU General Public License for more details.
        !            15: #
        !            16: # You should have received a copy of the GNU General Public License
        !            17: # along with this program. If not, see <http://www.gnu.org/licenses/>.
        !            18: #
        !            19: 
        !            20: ##
        !            21: # A matrix of quantities
        !            22: ##
        !            23: package Apache::math_parser::QMatrix;
        !            24: 
        !            25: use strict;
        !            26: use warnings;
        !            27: use utf8;
        !            28: 
        !            29: use aliased 'Apache::math_parser::CalcException';
        !            30: use aliased 'Apache::math_parser::Quantity';
        !            31: use aliased 'Apache::math_parser::QVector';
        !            32: use aliased 'Apache::math_parser::QMatrix';
        !            33: 
        !            34: use overload
        !            35:     '""' => \&toString,
        !            36:     '+' => \&qadd,
        !            37:     '-' => \&qsub,
        !            38:     '*' => \&qmult,
        !            39:     '/' => \&qdiv,
        !            40:     '^' => \&qpow;
        !            41: 
        !            42: ##
        !            43: # Constructor
        !            44: # @param {Quantity[][]} quantities
        !            45: ##
        !            46: sub new {
        !            47:     my $class = shift;
        !            48:     my $self = {
        !            49:         _quantities => shift,
        !            50:     };
        !            51:     bless $self, $class;
        !            52:     return $self;
        !            53: }
        !            54: 
        !            55: # Attribute helpers
        !            56: 
        !            57: ##
        !            58: # The components of the matrix.
        !            59: # @returns {Quantity[][]}
        !            60: ##
        !            61: sub quantities {
        !            62:     my $self = shift;
        !            63:     return $self->{_quantities};
        !            64: }
        !            65: 
        !            66: 
        !            67: ##
        !            68: # Returns a readable view of the object
        !            69: # @returns {string}
        !            70: ##
        !            71: sub toString {
        !            72:     my ( $self ) = @_;
        !            73:     my $s = "[";
        !            74:     for (my $i=0; $i < scalar(@{$self->quantities}); $i++) {
        !            75:         $s .= "[";
        !            76:         for (my $j=0; $j < scalar(@{$self->quantities->[$i]}); $j++) {
        !            77:             $s .= $self->quantities->[$i][$j]->toString();
        !            78:             if ($j != scalar(@{$self->quantities->[$i]}) - 1) {
        !            79:                 $s .= "; ";
        !            80:             }
        !            81:         }
        !            82:         $s .= "]";
        !            83:         if ($i != scalar(@{$self->quantities}) - 1) {
        !            84:             $s .= "; ";
        !            85:         }
        !            86:     }
        !            87:     $s .= "]";
        !            88:     return $s;
        !            89: }
        !            90: 
        !            91: ##
        !            92: # Equality test
        !            93: # @param {QMatrix} m
        !            94: # @optional {string|float} tolerance
        !            95: # @returns {boolean}
        !            96: ##
        !            97: sub equals {
        !            98:     my ( $self, $m, $tolerance ) = @_;
        !            99:     if (!$m->isa(QMatrix)) {
        !           100:         return 0;
        !           101:     }
        !           102:     if (scalar(@{$self->quantities}) != scalar(@{$m->quantities})) {
        !           103:         return 0;
        !           104:     }
        !           105:     for (my $i=0; $i < scalar(@{$self->quantities}); $i++) {
        !           106:         if (scalar(@{$self->quantities->[$i]}) != scalar(@{$m->quantities->[$i]})) {
        !           107:             return 0;
        !           108:         }
        !           109:         for (my $j=0; $j < scalar(@{$self->quantities->[$i]}); $j++) {
        !           110:             if (!$self->quantities->[$i][$j]->equals($m->quantities->[$i][$j], $tolerance)) {
        !           111:                 return 0;
        !           112:             }
        !           113:         }
        !           114:     }
        !           115:     return 1;
        !           116: }
        !           117: 
        !           118: ##
        !           119: # Compare this matrix with another one, and returns a code.
        !           120: # @param {Quantity|QVector|QMatrix|QSet|QInterval} m
        !           121: # @optional {string|float} tolerance
        !           122: # @returns {int} Quantity->WRONG_TYPE|WRONG_DIMENSIONS|MISSING_UNITS|ADDED_UNITS|WRONG_UNITS|WRONG_VALUE|IDENTICAL
        !           123: ##
        !           124: sub compare {
        !           125:     my ( $self, $m, $tolerance ) = @_;
        !           126:     if (!$m->isa(QMatrix)) {
        !           127:         return Quantity->WRONG_TYPE;
        !           128:     }
        !           129:     if (scalar(@{$self->quantities}) != scalar(@{$m->quantities})) {
        !           130:         return Quantity->WRONG_DIMENSIONS;
        !           131:     }
        !           132:     my @codes = ();
        !           133:     for (my $i=0; $i < scalar(@{$self->quantities}); $i++) {
        !           134:         if (scalar(@{$self->quantities->[$i]}) != scalar(@{$m->quantities->[$i]})) {
        !           135:             return Quantity->WRONG_DIMENSIONS;
        !           136:         }
        !           137:         for (my $j=0; $j < scalar(@{$self->quantities->[$i]}); $j++) {
        !           138:             push(@codes, $self->quantities->[$i][$j]->compare($m->quantities->[$i][$j], $tolerance));
        !           139:         }
        !           140:     }
        !           141:     my @test_order = (Quantity->WRONG_TYPE, Quantity->WRONG_DIMENSIONS, Quantity->MISSING_UNITS, Quantity->ADDED_UNITS,
        !           142:         Quantity->WRONG_UNITS, Quantity->WRONG_VALUE);
        !           143:     foreach my $test (@test_order) {
        !           144:         foreach my $code (@codes) {
        !           145:             if ($code == $test) {
        !           146:                 return $test;
        !           147:             }
        !           148:         }
        !           149:     }
        !           150:     return Quantity->IDENTICAL;
        !           151: }
        !           152: 
        !           153: ##
        !           154: # Addition
        !           155: # @param {QMatrix} m
        !           156: # @returns {QMatrix}
        !           157: ##
        !           158: sub qadd {
        !           159:     my ( $self, $m ) = @_;
        !           160:     if (!$m->isa(QMatrix)) {
        !           161:         die CalcException->new("Matrix addition: second member is not a matrix.");
        !           162:     }
        !           163:     if (scalar(@{$self->quantities}) != scalar(@{$m->quantities}) || 
        !           164:             scalar(@{$self->quantities->[0]}) != scalar(@{$m->quantities->[0]})) {
        !           165:         die CalcException->new("Matrix addition: the matrices have different sizes.");
        !           166:     }
        !           167:     my @t = (); # 2d array of Quantity
        !           168:     for (my $i=0; $i < scalar(@{$self->quantities}); $i++) {
        !           169:         $t[$i] = [];
        !           170:         for (my $j=0; $j < scalar(@{$self->quantities->[$i]}); $j++) {
        !           171:             $t[$i][$j] = $self->quantities->[$i][$j] + $m->quantities->[$i][$j];
        !           172:         }
        !           173:     }
        !           174:     return QMatrix->new(\@t);
        !           175: }
        !           176: 
        !           177: ##
        !           178: # Substraction
        !           179: # @param {QMatrix} m
        !           180: # @returns {QMatrix}
        !           181: ##
        !           182: sub qsub {
        !           183:     my ( $self, $m ) = @_;
        !           184:     if (!$m->isa(QMatrix)) {
        !           185:         die CalcException->new("Matrix substraction: second member is not a matrix.");
        !           186:     }
        !           187:     if (scalar(@{$self->quantities}) != scalar(@{$m->quantities}) || 
        !           188:             scalar(@{$self->quantities->[0]}) != scalar(@{$m->quantities->[0]})) {
        !           189:         die CalcException->new("Matrix substraction: the matrices have different sizes.");
        !           190:     }
        !           191:     my @t = (); # 2d array of Quantity
        !           192:     for (my $i=0; $i < scalar(@{$self->quantities}); $i++) {
        !           193:         $t[$i] = [];
        !           194:         for (my $j=0; $j < scalar(@{$self->quantities->[$i]}); $j++) {
        !           195:             $t[$i][$j] = $self->quantities->[$i][$j] - $m->quantities->[$i][$j];
        !           196:         }
        !           197:     }
        !           198:     return QMatrix->new(\@t);
        !           199: }
        !           200: 
        !           201: ##
        !           202: # Negation
        !           203: # @returns {QMatrix}
        !           204: ##
        !           205: sub qneg {
        !           206:     my ( $self ) = @_;
        !           207:     my @t = (); # 2d array of Quantity
        !           208:     for (my $i=0; $i < scalar(@{$self->quantities}); $i++) {
        !           209:         $t[$i] = [];
        !           210:         for (my $j=0; $j < scalar(@{$self->quantities->[$i]}); $j++) {
        !           211:             $t[$i][$j] = $self->quantities->[$i][$j]->qneg();
        !           212:         }
        !           213:     }
        !           214:     return QMatrix->new(\@t);
        !           215: }
        !           216: 
        !           217: ##
        !           218: # Element-by-element multiplication by a quantity, vector or matrix (like Maxima)
        !           219: # @param {Quantity|QVector|QMatrix} m
        !           220: # @returns {QMatrix}
        !           221: ##
        !           222: sub qmult {
        !           223:     my ( $self, $m ) = @_;
        !           224:     if (!$m->isa(Quantity) && !$m->isa(QVector) && !$m->isa(QMatrix)) {
        !           225:         die CalcException->new("Matrix element-by-element multiplication: second member is not a quantity, vector or matrix.");
        !           226:     }
        !           227:     if ($m->isa(Quantity)) {
        !           228:         my @t = (); # 2d array of Quantity
        !           229:         for (my $i=0; $i < scalar(@{$self->quantities}); $i++) {
        !           230:             $t[$i] = [];
        !           231:             for (my $j=0; $j < scalar(@{$self->quantities->[$i]}); $j++) {
        !           232:                 $t[$i][$j] = $self->quantities->[$i][$j] * $m;
        !           233:             }
        !           234:         }
        !           235:         return QMatrix->new(\@t);
        !           236:     }
        !           237:     if ($m->isa(QVector)) {
        !           238:         if (scalar(@{$self->quantities}) != scalar(@{$m->quantities})) {
        !           239:             die CalcException->new(
        !           240: "Matrix-Vector element-by-element multiplication: the sizes do not match (use the dot product for matrix product).");
        !           241:         }
        !           242:         my @t = (); # 2d array of Quantity
        !           243:         for (my $i=0; $i < scalar(@{$self->quantities}); $i++) {
        !           244:             $t[$i] = [];
        !           245:             for (my $j=0; $j < scalar(@{$self->quantities->[$i]}); $j++) {
        !           246:                 $t[$i][$j] = $self->quantities->[$i][$j] * $m->quantities->[$i];
        !           247:             }
        !           248:         }
        !           249:         return QMatrix->new(\@t);
        !           250:     }
        !           251:     if (scalar(@{$self->quantities}) != scalar(@{$m->quantities}) || 
        !           252:             scalar(@{$self->quantities->[0]}) != scalar(@{$m->quantities->[0]})) {
        !           253:         die CalcException->new(
        !           254: "Matrix element-by-element multiplication: the matrices have different sizes (use the dot product for matrix product).");
        !           255:     }
        !           256:     my @t = (); # 2d array of Quantity
        !           257:     for (my $i=0; $i < scalar(@{$self->quantities}); $i++) {
        !           258:         $t[$i] = [];
        !           259:         for (my $j=0; $j < scalar(@{$self->quantities->[$i]}); $j++) {
        !           260:             $t[$i][$j] = $self->quantities->[$i][$j] * $m->quantities->[$i][$j];
        !           261:         }
        !           262:     }
        !           263:     return QMatrix->new(\@t);
        !           264: }
        !           265: 
        !           266: ##
        !           267: # Element-by-element division by a quantity, vector or matrix (like Maxima)
        !           268: # @param {Quantity|QVector|QMatrix} m
        !           269: # @returns {QMatrix}
        !           270: ##
        !           271: sub qdiv {
        !           272:     my ( $self, $m ) = @_;
        !           273:     if (!$m->isa(Quantity) && !$m->isa(QVector) && !$m->isa(QMatrix)) {
        !           274:         die CalcException->new("Matrix element-by-element division: second member is not a quantity, vector or matrix.");
        !           275:     }
        !           276:     if ($m->isa(Quantity)) {
        !           277:         my @t = (); # 2d array of Quantity
        !           278:         for (my $i=0; $i < scalar(@{$self->quantities}); $i++) {
        !           279:             $t[$i] = [];
        !           280:             for (my $j=0; $j < scalar(@{$self->quantities->[$i]}); $j++) {
        !           281:                 $t[$i][$j] = $self->quantities->[$i][$j] / $m;
        !           282:             }
        !           283:         }
        !           284:         return QMatrix->new(\@t);
        !           285:     }
        !           286:     if ($m->isa(QVector)) {
        !           287:         if (scalar(@{$self->quantities}) != scalar(@{$m->quantities})) {
        !           288:             die CalcException->new("Matrix-Vector element-by-element division: the sizes do not match.");
        !           289:         }
        !           290:         my @t = (); # 2d array of Quantity
        !           291:         for (my $i=0; $i < scalar(@{$self->quantities}); $i++) {
        !           292:             $t[$i] = [];
        !           293:             for (my $j=0; $j < scalar(@{$self->quantities->[$i]}); $j++) {
        !           294:                 $t[$i][$j] = $self->quantities->[$i][$j] / $m->quantities->[$i];
        !           295:             }
        !           296:         }
        !           297:         return QMatrix->new(\@t);
        !           298:     }
        !           299:     if (scalar(@{$self->quantities}) != scalar(@{$m->quantities}) || 
        !           300:             scalar(@{$self->quantities->[0]}) != scalar(@{$m->quantities->[0]})) {
        !           301:         die CalcException->new("Matrix element-by-element division: the matrices have different sizes.");
        !           302:     }
        !           303:     my @t = (); # 2d array of Quantity
        !           304:     for (my $i=0; $i < scalar(@{$self->quantities}); $i++) {
        !           305:         $t[$i] = [];
        !           306:         for (my $j=0; $j < scalar(@{$self->quantities->[$i]}); $j++) {
        !           307:             $t[$i][$j] = $self->quantities->[$i][$j] / $m->quantities->[$i][$j];
        !           308:         }
        !           309:     }
        !           310:     return QMatrix->new(\@t);
        !           311: }
        !           312: 
        !           313: ##
        !           314: # Noncommutative multiplication by a vector or matrix
        !           315: # @param {QVector|QMatrix} m
        !           316: # @returns {QVector|QMatrix}
        !           317: ##
        !           318: sub qdot {
        !           319:     my ( $self, $m ) = @_;
        !           320:     if (!$m->isa(QVector) && !$m->isa(QMatrix)) {
        !           321:         die CalcException->new("Matrix product: second member is not a vector or a matrix.");
        !           322:     }
        !           323:     if (scalar(@{$self->quantities->[0]}) != scalar(@{$m->quantities})) {
        !           324:         die CalcException->new("Matrix product: the matrices sizes do not match.");
        !           325:     }
        !           326:     if ($m->isa(QVector)) {
        !           327:         my @t = (); # array of Quantity
        !           328:         for (my $i=0; $i < scalar(@{$self->quantities}); $i++) {
        !           329:             $t[$i] = Quantity->new(0);
        !           330:             for (my $j=0; $j < scalar(@{$m->quantities}); $j++) {
        !           331:                 $t[$i] += $self->quantities->[$i][$j] * $m->quantities->[$j];
        !           332:             }
        !           333:         }
        !           334:         return QVector->new(\@t);
        !           335:     }
        !           336:     my @t = (); # array or 2d array of Quantity
        !           337:     for (my $i=0; $i < scalar(@{$self->quantities}); $i++) {
        !           338:         $t[$i] = [];
        !           339:         for (my $j=0; $j < scalar(@{$m->quantities->[0]}); $j++) {
        !           340:             $t[$i][$j] = Quantity->new(0);
        !           341:             for (my $k=0; $k < scalar(@{$m->quantities}); $k++) {
        !           342:                 $t[$i][$j] += $self->quantities->[$i][$k] * $m->quantities->[$k][$j];
        !           343:             }
        !           344:         }
        !           345:     }
        !           346:     return QMatrix->new(\@t);
        !           347: }
        !           348: 
        !           349: ##
        !           350: # Power by a scalar
        !           351: # @param {Quantity} q
        !           352: # @returns {QMatrix}
        !           353: ##
        !           354: sub qpow {
        !           355:     my ( $self, $q ) = @_;
        !           356:     $q->noUnits("Power");
        !           357:     # note: this could be optimized, see "exponentiating by squaring"
        !           358:     my $m = QMatrix->new($self->quantities);
        !           359:     for (my $i=0; $i < $q->value - 1; $i++) {
        !           360:         $m = $m * $self;
        !           361:     }
        !           362:     return $m;
        !           363: }
        !           364: 
        !           365: ##
        !           366: # Equals
        !           367: # @param {Quantity|QVector|QMatrix|QSet|QInterval} m
        !           368: # @optional {string|float} tolerance
        !           369: # @returns {Quantity}
        !           370: ##
        !           371: sub qeq {
        !           372:     my ( $self, $m, $tolerance ) = @_;
        !           373:     my $q = $self->equals($m, $tolerance);
        !           374:     return Quantity->new($q);
        !           375: }
        !           376: 
        !           377: 1;
        !           378: __END__

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>