Annotation of loncom/homework/math_parser/QVector.pm, revision 1.2

1.1       damieng     1: # The LearningOnline Network with CAPA - LON-CAPA
                      2: # QVector
                      3: #
1.2     ! raeburn     4: # $Id: QVector.pm,v 1.2 2023/03/13 18:30:00 raeburn Exp $
        !             5: #
1.1       damieng     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>