File:  [LON-CAPA] / loncom / homework / math_parser / QVector.pm
Revision 1.2: download - view: text, annotated - select for diffs
Mon Mar 13 22:31:22 2023 UTC (14 months, 3 weeks ago) by raeburn
Branches: MAIN
CVS tags: version_2_12_X, version_2_11_4_msu, HEAD
- Add $Id$ line in comments for display of version.

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

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