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>