       1 package Vector;
       2 #
       3 # $RCSfile: Vector.pm,v $
       4 # $Date: 2015/02/28 20:47:30 $
       5 # $Revision: 1.34 $
       6 #
       7 # Author: Manish Sud <msud@san.rr.com>
       8 #
       9 # Copyright (C) 2015 Manish Sud. All rights reserved.
      10 #
      11 # This file is part of MayaChemTools.
      12 #
      13 # MayaChemTools is free software; you can redistribute it and/or modify it under
      14 # the terms of the GNU Lesser General Public License as published by the Free
      15 # Software Foundation; either version 3 of the License, or (at your option) any
      16 # later version.
      17 #
      18 # MayaChemTools is distributed in the hope that it will be useful, but without
      19 # any warranty; without even the implied warranty of merchantability of fitness
      20 # for a particular purpose.  See the GNU Lesser General Public License for more
      21 # details.
      22 #
      23 # You should have received a copy of the GNU Lesser General Public License
      24 # along with MayaChemTools; if not, see <http://www.gnu.org/licenses/> or
      25 # write to the Free Software Foundation Inc., 59 Temple Place, Suite 330,
      26 # Boston, MA, 02111-1307, USA.
      27 #
      28
      29 use strict;
      30 use Carp;
      31 use Exporter;
      32 use Scalar::Util ();
      33 use StatisticsUtil ();
      34
      35 use vars qw(@ISA @EXPORT @EXPORT_OK %EXPORT_TAGS);
      36
      37 @ISA = qw(Exporter);
      38 @EXPORT = qw(IsVector UnitXVector UnitYVector UnitZVector UnitVector ZeroVector);
      39 @EXPORT_OK = qw(SetValuePrintFormat);
      40
      41 %EXPORT_TAGS = (
      42                 all  => [@EXPORT, @EXPORT_OK]
      43                );
      44
      45 # Setup class variables...
      46 my($ClassName, $ValueFormat);
      47 _InitializeClass();
      48
      49 #
      50 # Using the following explicity overloaded operators, Perl automatically generates methods
      51 # for operations with no explicitly defined methods. Autogenerated methods are possible for
      52 # these operators:
      53 #
      54 #    o Arithmetic operators: += -= *= /= **= %= ++ -- x= .=
      55 #    o Increment and decrement: ++ --
      56 #
      57 # 'fallback' is set to 'false' to raise exception for all other operators.
      58 #
      59 use overload '""' => 'StringifyVector',
      60
      61   '0+' => '_NumifyVector',
      62
      63   '@{}' => '_VectorToArrayOperator',
      64
      65   '+' => '_VectorAdditionOperator',
      66   '-' => '_VectorSubtractionOperator',
      67   '*' => '_VectorMultiplicationOperator',
      68   '/' => '_VectorDivisionOperator',
      69   '**' => '_VectorExponentiationOperator',
      70   '%' => '_VectorModulusOperator',
      71
      72   'x' => '_VectorCrossProductOperator',
      73   '.' => '_VectorDotProductOperator',
      74
      75   'bool' => '_VectorBooleanOperator',
      76   '!' => '_VectorNotBooleanOperator',
      77
      78   '==' => '_VectorEqualOperator',
      79   '!=' => '_VectorNotEqualOperator',
      80   '<' => '_VectorLessThanOperator',
      81   '<=' => '_VectorLessThanEqualOperator',
      82   '>' => '_VectorGreatarThanOperator',
      83   '>=' => '_VectorGreatarThanEqualOperator',
      84
      85   'neg' => '_VectorNegativeValueOperator',
      86
      87   'abs' => '_VectorAbsoluteValueOperator',
      88   'exp' => '_VectorExpNaturalBaseOperator',
      89   'log' => '_VectorLogNaturalBaseOperator',
      90   'sqrt' => '_VectorSquareRootOperator',
      91   'cos' => '_VectorCosineOperator',
      92   'sin' => '_VectorSineOperator',
      93
      94   'fallback' => undef;
      95
      96 # Class constructor...
      97 sub new {
      98   my($Class, @Values) = @_;
      99
     100   # Initialize object...
     101   my $This = {};
     102   bless $This, ref($Class) || $Class;
     103   $This->_InitializeVector();
     104
     105   $This->_AddValues(@Values);
     106
     107   return $This;
     108 }
     109
     110 # Initialize object data...
     111 #
     112 sub _InitializeVector {
     113   my($This) = @_;
     114
     115   @{$This->{Values}} = ();
     116 }
     117
     118 # Initialize class ...
     119 sub _InitializeClass {
     120   #Class name...
     121   $ClassName = __PACKAGE__;
     122
     123   # Print format for vector values...
     124   $ValueFormat = "%g";
     125 }
     126
     127 # Initialize vector values using:
     128 #    o List of values
     129 #    o Reference to an list of values
     130 #    o Another vector object
     131 #
     132 sub _AddValues {
     133   my($This, @Values) = @_;
     134
     135   if (!@Values) {
     136     return;
     137   }
     138
     139   # Set vector values...
     140   my($FirstValue, $TypeOfFirstValue);
     141   $FirstValue = $Values[0];
     142   $TypeOfFirstValue = ref $FirstValue;
     143   if ($TypeOfFirstValue =~ /^(SCALAR|HASH|CODE|REF|GLOB)/) {
     144     croak "Error: ${ClassName}->_AddValues: Trying to add values to vector object with a reference to unsupported value format...";
     145   }
     146
     147   if (_IsVector($FirstValue)) {
     148     # Initialize using Vector...
     149     push @{$This->{Values}}, @{$FirstValue->{Values}};
     150   }
     151   elsif ($TypeOfFirstValue =~ /^ARRAY/) {
     152     # Initialize using array refernce...
     153     push @{$This->{Values}}, @{$FirstValue};
     154   }
     155   else {
     156     # It's a list of values...
     157     push @{$This->{Values}}, @Values;
     158   }
     159 }
     160
     161 # Add values to a vector using a vector, reference to an array or an array...
     162 sub AddValues {
     163   my($This, @Values) = @_;
     164
     165   $This->_AddValues(@Values);
     166
     167   return $This;
     168 }
     169
     170 # Copy vector...
     171 sub Copy {
     172   my($This) = @_;
     173   my($Vector);
     174
     175   # Copy vector values...
     176   $Vector = (ref $This)->new(\@{$This->{Values}});
     177
     178   # Copy value format for stringification...
     179   if (exists $This->{ValueFormat}) {
     180     $Vector->{ValueFormat} = $This->{ValueFormat};
     181   }
     182   return $Vector;
     183 }
     184
     185 # Get 3D vector length...
     186 sub GetLength {
     187   my($This) = @_;
     188
     189   if ($This->GetSize() != 3) {
     190     croak "Error: ${ClassName}->GetGetLength: Object must be a 3D vector...";
     191   }
     192   my($Length, $DotProduct);
     193   $DotProduct = $This . $This;
     194   $Length = sqrt $DotProduct;
     195
     196   return $Length;
     197 }
     198
     199 # Length of a 3D vector by another name...
     200 sub GetMagnitude {
     201   my($This) = @_;
     202   return $This->GetLength();
     203 }
     204
     205 # Normalize 3D vector...
     206 sub Normalize {
     207   my($This) = @_;
     208
     209   if ($This->GetSize() != 3) {
     210     croak "Error: ${ClassName}->GetGetLength: Object must be a 3D vector...";
     211   }
     212   my($Vector, $Length);
     213   $Length = $This->GetLength();
     214   $Vector = $This / $Length;
     215
     216   return $Vector;
     217 }
     218
     219 # Is it a vector object?
     220 sub IsVector ($) {
     221   my($Object) = @_;
     222
     223   return _IsVector($Object);
     224 }
     225
     226 # Get size...
     227 sub GetSize {
     228   my($This) = @_;
     229
     230   return scalar @{$This->{Values}};
     231 }
     232
     233 # Get X value of a 3D vector...
     234 sub GetX {
     235   my($This) = @_;
     236
     237   if ($This->GetSize() != 3) {
     238     croak "Error: ${ClassName}->GetX: Object must be a 3D vector...";
     239   }
     240   return $This->_GetValue(0);
     241 }
     242
     243 # Set X value of a 3D vector...
     244 sub SetX {
     245   my($This, $Value) = @_;
     246
     247   if ($This->GetSize() != 3) {
     248     croak "Error: ${ClassName}->SetX: Object must be a 3D vector...";
     249   }
     250   return $This->_SetValue(0, $Value);
     251 }
     252
     253 # Get Y value of a 3D vector...
     254 sub GetY {
     255   my($This) = @_;
     256
     257   if ($This->GetSize() != 3) {
     258     croak "Error: ${ClassName}->GetY: Object must be a 3D vector...";
     259   }
     260   return $This->_GetValue(1);
     261 }
     262
     263 # Set Y value of a 3D vector...
     264 sub SetY {
     265   my($This, $Value) = @_;
     266
     267   if ($This->GetSize() != 3) {
     268     croak "Error: ${ClassName}->SetY: Object must be a 3D vector...";
     269   }
     270   return $This->_SetValue(1, $Value);
     271 }
     272
     273 # Get Z value of a 3D vector...
     274 sub GetZ {
     275   my($This) = @_;
     276
     277   if ($This->GetSize() != 3) {
     278     croak "Error: ${ClassName}->GetZ: Object must be a 3D vector...";
     279   }
     280   return $This->_GetValue(2);
     281 }
     282
     283 # Set Z value of a 3D vector...
     284 sub SetZ {
     285   my($This, $Value) = @_;
     286
     287   if ($This->GetSize() != 3) {
     288     croak "Error: ${ClassName}->SetZ: Object must be a 3D vector...";
     289   }
     290   return $This->_SetValue(2, $Value);
     291 }
     292
     293 # Set XYZ value of a 3D vector using:
     294 #    o List of values
     295 #    o Reference to an list of values
     296 #    o Another vector object
     297 #
     298 sub SetXYZ {
     299   my($This, @Values) = @_;
     300
     301   if (!@Values) {
     302     croak "Error: ${ClassName}->SetXYZ: No values specified...";
     303   }
     304
     305   if ($This->GetSize() != 3) {
     306     croak "Error: ${ClassName}->SetXYZ: Object must be a 3D vector...";
     307   }
     308
     309   # Set vector values...
     310   my($FirstValue, $TypeOfFirstValue);
     311   $FirstValue = $Values[0];
     312   $TypeOfFirstValue = ref $FirstValue;
     313   if ($TypeOfFirstValue =~ /^(SCALAR|HASH|CODE|REF|GLOB)/) {
     314     croak "Error: ${ClassName}->SetXYZ: A reference to unsupported value format specified...";
     315   }
     316
     317   my($X, $Y, $Z);
     318   if (_IsVector($FirstValue)) {
     319     # SetXYZ using vector...
     320     if ($FirstValue->GetSize() != 3) {
     321       croak "Error: ${ClassName}->SetXYZ: Input object must be a 3D vector...";
     322     }
     323     ($X, $Y, $Z) = @{$FirstValue->{Values}};
     324   }
     325   elsif ($TypeOfFirstValue =~ /^ARRAY/) {
     326     # SetXYZ using array reference...
     327     if (@{$FirstValue} != 3) {
     328       croak "Error: ${ClassName}->SetXYZ: Input array reference must correspond to an array with three values...";
     329     }
     330     ($X, $Y, $Z) = @{$FirstValue};
     331   }
     332   else {
     333     # It's a list of values...
     334     if (@Values != 3) {
     335       croak "Error: ${ClassName}->SetXYZ: Input array must contain three values...";
     336     }
     337     ($X, $Y, $Z) = @Values;
     338   }
     339   $This->{Values}[0] = $X;
     340   $This->{Values}[1] = $Y;
     341   $This->{Values}[2] = $Z;
     342
     343   return $This;
     344 }
     345
     346 # Get XYZ as an array or a reference to an array...
     347 #
     348 sub GetXYZ {
     349   my($This) = @_;
     350
     351   if ($This->GetSize() != 3) {
     352     croak "Error: ${ClassName}->GetXYZ: Object must be a 3D vector...";
     353   }
     354   return wantarray ? @{$This->{Values}} : \@{$This->{Values}};
     355 }
     356
     357 # Get a specific value from vector with indicies starting from 0..
     358 sub GetValue {
     359   my($This, $Index) = @_;
     360
     361   if ($Index < 0) {
     362     croak "Error: ${ClassName}->GetValue: Index value must be a positive number...";
     363   }
     364   if ($Index >= $This->GetSize()) {
     365     croak "Error: ${ClassName}->GetValue: Index value must be less than size of vector...";
     366   }
     367   return $This->_GetValue($Index);
     368 }
     369
     370 # Get a vector value...
     371 sub _GetValue {
     372   my($This, $Index) = @_;
     373
     374   return $This->{Values}[$Index];
     375 }
     376
     377 # Set a specific value in vector with indicies starting from 0..
     378 sub SetValue {
     379   my($This, $Index, $Value, $SkipCheck) = @_;
     380
     381   # Just set it...
     382   if ($SkipCheck) {
     383     return $This->_SetValue($Index, $Value);
     384   }
     385
     386   # Check and set...
     387   if ($Index < 0) {
     388     croak "Error: ${ClassName}->SetValue: Index value must be a positive number...";
     389   }
     390   if ($Index >= $This->GetSize()) {
     391     croak "Error: ${ClassName}->SetValue: Index vaue must be less than size of vector...";
     392   }
     393
     394   return $This->_SetValue($Index, $Value);
     395 }
     396
     397 # Set a vector value...
     398 sub _SetValue {
     399   my($This, $Index, $Value) = @_;
     400
     401   $This->{Values}[$Index] = $Value;
     402
     403   return $This;
     404 }
     405
     406 # Return vector values as an array or reference to an array...
     407 sub GetValues {
     408   my($This) = @_;
     409
     410   return wantarray ? @{$This->{Values}} : \@{$This->{Values}};
     411 }
     412
     413 # Get number of non-zero values in vector...
     414 #
     415 sub GetNumOfNonZeroValues {
     416   my($This) = @_;
     417   my($Count, $Index, $Size);
     418
     419   $Count = 0;
     420   $Size = $This->GetSize();
     421
     422   for $Index (0 .. ($Size -1)) {
     423     if ($This->{Values}[$Index] != 0) {
     424       $Count++;
     425     }
     426   }
     427   return $Count;
     428 }
     429
     430 # Get percent of non-zero values...
     431 #
     432 sub GetPercentOfNonZeroValues {
     433   my($This) = @_;
     434
     435   return $This->GetSize() ? (($This->GetNumOfNonZeroValues()/$This->GetSize())*100) : 0;
     436 }
     437
     438 # Set value print format for an individual object or the whole class...
     439 sub SetValuePrintFormat ($;$) {
     440   my($FirstParameter, $SecondParameter) = @_;
     441
     442   if ((@_ == 2) && (_IsVector($FirstParameter))) {
     443     # Set value print format for the specific object...
     444     my($This, $ValuePrintFormat) = ($FirstParameter, $SecondParameter);
     445
     446     $This->{ValueFormat} = $ValuePrintFormat;
     447   }
     448   else {
     449     # Set value print format for the class...
     450     my($ValuePrintFormat) = ($FirstParameter);
     451
     452     $ValueFormat = $ValuePrintFormat;
     453   }
     454 }
     455
     456 # Zero vector of specified size or size 3...
     457 sub ZeroVector (;$) {
     458   my($Size) = @_;
     459   my($Vector, @Values);
     460
     461   $Size = (defined $Size) ? $Size : 3;
     462   @Values = ('0') x $Size;
     463
     464   $Vector = new Vector(\@Values);
     465   return $Vector;
     466 }
     467
     468 # Unit vector of specified size or size 3...
     469 sub UnitVector (;$) {
     470   my($Size) = @_;
     471   my($Vector, @Values);
     472
     473   $Size = (defined $Size) ? $Size : 3;
     474   @Values = ('1') x $Size;
     475
     476   $Vector = new Vector(\@Values);
     477   return $Vector;
     478 }
     479
     480 # Unit X vector of size 3...
     481 sub UnitXVector () {
     482   my($Vector);
     483
     484   $Vector = new Vector(1, 0, 0);
     485   return $Vector;
     486 }
     487
     488 # Unit Y vector of size 3...
     489 sub UnitYVector () {
     490   my($Vector);
     491
     492   $Vector = new Vector(0, 1, 0);
     493   return $Vector;
     494 }
     495
     496 # Unit Z vector of size 3...
     497 sub UnitZVector () {
     498   my($Vector);
     499
     500   $Vector = new Vector(0, 0, 1);
     501   return $Vector;
     502 }
     503
     504 #
     505 # Vector addition operator supports two addition modes:
     506 #   . Addition of two vectors by adding corresponding vector values
     507 #   . Addition of a scalar value to vector values ($Vector + 1)
     508 #
     509 # Caveats:
     510 #   . Addition of a vector to scalar is not allowed (1 + $Vector)
     511 #
     512 sub _VectorAdditionOperator {
     513   my($This, $Other, $OrderFlipped, $OtherIsVector, $ErrorMsg);
     514
     515   $ErrorMsg = "_VectorAdditionOperator: Vector addition failed";
     516   ($This, $Other, $OrderFlipped, $OtherIsVector) = _ProcessOverloadedOperatorParameters($ErrorMsg, @_);
     517
     518   # Do the addition. Order can be ignored: It's a commumative operation.
     519   my($Vector, $ThisSize, $Index);
     520   $Vector = $This->Copy();
     521   $ThisSize = $This->GetSize();
     522
     523   if ($OtherIsVector) {
     524     # $OrderFlipped is set to false for two vectors...
     525     for $Index (0 .. ($ThisSize -1)) {
     526       $Vector->{Values}[$Index] += $Other->{Values}[$Index];
     527     }
     528   }
     529   else {
     530     if ($OrderFlipped) {
     531       croak "Error: ${ClassName}->${ErrorMsg}: First object must be a vector...";
     532     }
     533     # Scalar addition...
     534     for $Index (0 .. ($ThisSize -1)) {
     535       $Vector->{Values}[$Index] += $Other;
     536     }
     537   }
     538   return $Vector;
     539 }
     540
     541 #
     542 # Vector subtraction operator supports two subtraction modes:
     543 #   . Subtraction of two vectors by subtracting corresponding vector values
     544 #   . Subtraction of a scalar value from vector values ($Vector - 1)
     545 #
     546 # Caveats:
     547 #   . Subtraction of a vector from scalar is not allowed (1 - $Vector)
     548 #
     549 sub _VectorSubtractionOperator {
     550   my($This, $Other, $OrderFlipped, $OtherIsVector, $ErrorMsg);
     551
     552   $ErrorMsg = "_VectorSubtractionOperator: Vector subtracttion failed";
     553   ($This, $Other, $OrderFlipped, $OtherIsVector) = _ProcessOverloadedOperatorParameters($ErrorMsg, @_);
     554
     555   # Do the subtraction...
     556   my($Vector, $ThisSize, $Index);
     557   $Vector = $This->Copy();
     558   $ThisSize = $This->GetSize();
     559
     560   if ($OtherIsVector) {
     561     # $OrderFlipped is set to false for two vectors...
     562     for $Index (0 .. ($ThisSize -1)) {
     563       $Vector->{Values}[$Index] -= $Other->{Values}[$Index];
     564     }
     565   }
     566   else {
     567     # Scalar subtraction...
     568     if ($OrderFlipped) {
     569       croak "Error: ${ClassName}->${ErrorMsg}: First object must be a vector...";
     570     }
     571     for $Index (0 .. ($ThisSize -1)) {
     572       $Vector->{Values}[$Index] -= $Other;
     573     }
     574   }
     575   return $Vector;
     576 }
     577
     578 #
     579 # Vector multiplication operator supports two multiplication modes:
     580 #   . Multiplication of two vectors by multiplying corresponding vector values
     581 #   . Multiplying vector values by a scalar ($Vector * 1)
     582 #
     583 # Caveats:
     584 #   . Multiplication of a scalar by a vector is not allowed (1 * $Vector)
     585 #
     586 sub _VectorMultiplicationOperator {
     587   my($This, $Other, $OrderFlipped, $OtherIsVector, $ErrorMsg);
     588
     589   $ErrorMsg = "_VectorMultiplicationOperator: Vector addition failed";
     590   ($This, $Other, $OrderFlipped, $OtherIsVector) = _ProcessOverloadedOperatorParameters($ErrorMsg, @_);
     591
     592   # Do the multiplication...
     593   my($Vector, $ThisSize, $Index);
     594   $Vector = $This->Copy();
     595   $ThisSize = $This->GetSize();
     596
     597   if ($OtherIsVector) {
     598     # $OrderFlipped is set to false for two vectors...
     599     for $Index (0 .. ($ThisSize -1)) {
     600       $Vector->{Values}[$Index] *= $Other->{Values}[$Index];
     601     }
     602   }
     603   else {
     604     if ($OrderFlipped) {
     605       croak "Error: ${ClassName}->${ErrorMsg}: First object must be a vector...";
     606     }
     607     # Scalar multiplication...
     608     for $Index (0 .. ($ThisSize -1)) {
     609       $Vector->{Values}[$Index] *= $Other;
     610     }
     611   }
     612   return $Vector;
     613 }
     614
     615 #
     616 # Vector division operator supports two division modes:
     617 #   . Division of two vectors by dividing corresponding vector values
     618 #   . Dividing vector values by a scalar ($Vector / 2)
     619 #
     620 # Caveats:
     621 #   . Division of a scalar by a vector is not allowed (1 / $Vector)
     622 #
     623 sub _VectorDivisionOperator {
     624   my($This, $Other, $OrderFlipped, $OtherIsVector, $ErrorMsg);
     625
     626   $ErrorMsg = "_VectorDivisionOperator: Vector division failed";
     627   ($This, $Other, $OrderFlipped, $OtherIsVector) = _ProcessOverloadedOperatorParameters($ErrorMsg, @_);
     628
     629   # Do the division...
     630   my($Vector, $ThisSize, $Index);
     631   $Vector = $This->Copy();
     632   $ThisSize = $This->GetSize();
     633
     634   if ($OtherIsVector) {
     635     # $OrderFlipped is set to false for two vectors...
     636     for $Index (0 .. ($ThisSize -1)) {
     637       $Vector->{Values}[$Index] /= $Other->{Values}[$Index];
     638     }
     639   }
     640   else {
     641     if ($OrderFlipped) {
     642       croak "Error: ${ClassName}->${ErrorMsg}: First object must be a vector...";
     643     }
     644     # Scalar divison...
     645     for $Index (0 .. ($ThisSize -1)) {
     646       $Vector->{Values}[$Index] /=  $Other;
     647     }
     648   }
     649   return $Vector;
     650 }
     651
     652 #
     653 # Vector exponentiation operator supports two exponentiation modes:
     654 #   . Exponentiation of two vectors by exponentiation of  corresponding vector values
     655 #   . Exponentiation of vector values by a scalar ($Vector ** 2)
     656 #
     657 # Caveats:
     658 #   . Exponent of scalar by a vector is not allowed (2 ** $Vector)
     659 #
     660 sub _VectorExponentiationOperator {
     661   my($This, $Other, $OrderFlipped, $OtherIsVector, $ErrorMsg);
     662
     663   $ErrorMsg = "_VectorExponentiationOperator: Vector exponentiation failed";
     664   ($This, $Other, $OrderFlipped, $OtherIsVector) = _ProcessOverloadedOperatorParameters($ErrorMsg, @_);
     665
     666   # Do the exponentiation...
     667   my($Vector, $ThisSize, $Index);
     668   $Vector = $This->Copy();
     669   $ThisSize = $This->GetSize();
     670
     671   if ($OtherIsVector) {
     672     # $OrderFlipped is set to false for two vectors...
     673     for $Index (0 .. ($ThisSize -1)) {
     674       $Vector->{Values}[$Index] **= $Other->{Values}[$Index];
     675     }
     676   }
     677   else {
     678     if ($OrderFlipped) {
     679       croak "Error: ${ClassName}->${ErrorMsg}: First object must be a vector...";
     680     }
     681     # Scalar exponentiation...
     682     for $Index (0 .. ($ThisSize -1)) {
     683       $Vector->{Values}[$Index] **=  $Other;
     684     }
     685   }
     686   return $Vector;
     687 }
     688
     689 #
     690 # Vector modulus operator supports two modulus modes:
     691 #   . Modulus of two vectors by taking modulus between corresponding vector values
     692 #   . Modulus of vector values by a scalar ($Vector % 2)
     693 #
     694 # Caveats:
     695 #   . Modulus of scalar by a vector is not allowed (2 % $Vector)
     696 #
     697 sub _VectorModulusOperator {
     698   my($This, $Other, $OrderFlipped, $OtherIsVector, $ErrorMsg);
     699
     700   $ErrorMsg = "_VectorModulusOperator: Vector exponentiation failed";
     701   ($This, $Other, $OrderFlipped, $OtherIsVector) = _ProcessOverloadedOperatorParameters($ErrorMsg, @_);
     702
     703   # Take the modulus...
     704   my($Vector, $ThisSize, $Index);
     705   $Vector = $This->Copy();
     706   $ThisSize = $This->GetSize();
     707
     708   if ($OtherIsVector) {
     709     # $OrderFlipped is set to false for two vectors...
     710     for $Index (0 .. ($ThisSize -1)) {
     711       $Vector->{Values}[$Index] %= $Other->{Values}[$Index];
     712     }
     713   }
     714   else {
     715     if ($OrderFlipped) {
     716       croak "Error: ${ClassName}->${ErrorMsg}: First object must be a vector...";
     717     }
     718     # Scalar modulus...
     719     for $Index (0 .. ($ThisSize -1)) {
     720       $Vector->{Values}[$Index] %=  $Other;
     721     }
     722   }
     723   return $Vector;
     724 }
     725
     726 #
     727 # Vector dot product operator supports two modes:
     728 #   . Dot product of two 3D vectors
     729 #   . Concatenation of a vector and a scalar
     730 #
     731 sub _VectorDotProductOperator {
     732   my($This, $Other, $OrderFlipped, $OtherIsVector, $ErrorMsg);
     733
     734   $ErrorMsg = "_VectorDotProductOperator: Vector dot product failed";
     735   ($This, $Other, $OrderFlipped, $OtherIsVector) = _ProcessOverloadedOperatorParameters($ErrorMsg, @_);
     736
     737   if ($OtherIsVector) {
     738     # Calculate dot product of two 3D vectors...
     739     my($DotProduct);
     740     if ($This->GetSize() != 3) {
     741       croak "Error: ${ClassName}->${ErrorMsg}: Both vectors must be 3D vectors...";
     742     }
     743     $DotProduct = $This->GetX() * $Other->GetX + $This->GetY() * $Other->GetY() + $This->GetZ * $Other->GetZ();
     744     return $DotProduct;
     745   }
     746   else {
     747     # Do a string concatenation and return the string...
     748     if ($OrderFlipped) {
     749       return $Other . $This->StringifyVector();
     750     }
     751     else {
     752       return $This->StringifyVector() . $Other;
     753     }
     754   }
     755 }
     756
     757 #
     758 # Vector cross product operator genrates a new vector which is the cross
     759 # product of two 3D vectors.
     760 #
     761 # For two vectors, V1 (X1, Y1, Z1) and V2 (X2, Y2, Z2), cross product
     762 # V1 x V2 corresponds: (Y1.Z2 - Z1.Y2), (Z1.X2 - X1.Z2), (X1.Y2 - Y1.X2)
     763 #
     764 sub _VectorCrossProductOperator {
     765   my($This, $Other, $OrderFlipped, $OtherIsVector, $ErrorMsg);
     766
     767   $ErrorMsg = "_VectorCrossProductOperator: Vector cross product failed";
     768   ($This, $Other, $OrderFlipped, $OtherIsVector) = _ProcessOverloadedOperatorParameters($ErrorMsg, @_);
     769
     770   if (!$OtherIsVector) {
     771     croak "Error: ${ClassName}->${ErrorMsg}: Both object must be vectors...";
     772   }
     773
     774   # Calculate cross product of two 3D vectors...
     775   if ($This->GetSize() != 3) {
     776     croak "Error: ${ClassName}->${ErrorMsg}: Both vectors must be 3D vectors...";
     777   }
     778   my($Vector, $X, $Y, $Z);
     779   $X = $This->GetY() * $Other->GetZ() - $This->GetZ() * $Other->GetY();
     780   $Y = $This->GetZ() * $Other->GetX() - $This->GetX() * $Other->GetZ();
     781   $Z = $This->GetX() * $Other->GetY() - $This->GetY() * $Other->GetX();
     782
     783   $Vector = (ref $This)->new($X, $Y, $Z);
     784
     785   return $Vector;
     786 }
     787
     788 #
     789 # Vector booelan operator checks whether a vector contains at least one non-zero
     790 # value...
     791 #
     792 sub _VectorBooleanOperator {
     793   my($This, $Other, $OrderFlipped, $OtherIsVector, $ErrorMsg);
     794
     795   $ErrorMsg = "_VectorBooleanOperator: Vector boolean operation failed";
     796   ($This, $Other, $OrderFlipped, $OtherIsVector) = _ProcessOverloadedOperatorParameters($ErrorMsg, @_);
     797
     798   my($Size, $Index);
     799   $Size = $This->GetSize();
     800
     801   for $Index (0 .. ($Size - 1)) {
     802     if ($This->{Values}[$Index] != 0) {
     803       return 1;
     804     }
     805   }
     806   return 0;
     807 }
     808
     809 #
     810 # Vector not booelan operator checks whether all values of a vector are zero.
     811 #
     812 sub _VectorNotBooleanOperator {
     813   my($This, $Other, $OrderFlipped, $OtherIsVector, $ErrorMsg);
     814
     815   $ErrorMsg = "_VectorNotBooleanOperator: Vector not boolean operation failed";
     816   ($This, $Other, $OrderFlipped, $OtherIsVector) = _ProcessOverloadedOperatorParameters($ErrorMsg, @_);
     817
     818   my($Size, $Index);
     819   $Size = $This->GetSize();
     820
     821   for $Index (0 .. ($Size - 1)) {
     822     if ($This->{Values}[$Index] != 0) {
     823       return 0;
     824     }
     825   }
     826   return 1;
     827 }
     828
     829 #
     830 # Vector equal operator supports two modes:
     831 #   . Comparion of corresponding values in two vectors
     832 #   . Comparing vectors values to a scalar ($Vector == 2)
     833 #
     834 # Caveats:
     835 #   . Comparison of a scalar to vector values is not allowed (2 == $Vector)
     836 #
     837 sub _VectorEqualOperator {
     838   my($This, $Other, $OrderFlipped, $OtherIsVector, $ErrorMsg, $CheckVectorSizes);
     839
     840   $ErrorMsg = "_VectorEqualOperator: Vector equal comparison failed";
     841   $CheckVectorSizes = 0;
     842   ($This, $Other, $OrderFlipped, $OtherIsVector) = _ProcessOverloadedOperatorParameters($ErrorMsg, @_, $CheckVectorSizes);
     843
     844   # Do the comparison...
     845   my($ThisSize, $Index);
     846   $ThisSize = $This->GetSize();
     847
     848   if ($OtherIsVector) {
     849     # $OrderFlipped is set to false for two vectors...
     850     my($OtherSize) = $Other->GetSize();
     851     if ($ThisSize != $OtherSize) {
     852       return 0;
     853     }
     854     for $Index (0 .. ($ThisSize -1)) {
     855       if ($This->{Values}[$Index] != $Other->{Values}[$Index]) {
     856         return 0;
     857       }
     858     }
     859   }
     860   else {
     861     if ($OrderFlipped) {
     862       croak "Error: ${ClassName}->${ErrorMsg}: First object must be a vector...";
     863     }
     864     # Scalar comparison...
     865     for $Index (0 .. ($ThisSize -1)) {
     866       if ($This->{Values}[$Index] != $Other) {
     867         return 0;
     868       }
     869     }
     870   }
     871   return 1;
     872 }
     873
     874 #
     875 # Vector not equal operator supports two modes:
     876 #   . Comparion of corresponding values in two vectors
     877 #   . Comparing vectors values to a scalar ($Vector != 2)
     878 #
     879 # Caveats:
     880 #   . Comparison of a scalar to vector values is not allowed (2 != $Vector2)
     881 #
     882 sub _VectorNotEqualOperator {
     883   my($This, $Other, $OrderFlipped, $OtherIsVector, $ErrorMsg, $CheckVectorSizes);
     884
     885   $ErrorMsg = "_VectorNotEqualOperator: Vector not equal comparison failed";
     886   $CheckVectorSizes = 0;
     887   ($This, $Other, $OrderFlipped, $OtherIsVector) = _ProcessOverloadedOperatorParameters($ErrorMsg, @_, $CheckVectorSizes);
     888
     889   # Do the comparison...
     890   my($ThisSize, $Index);
     891   $ThisSize = $This->GetSize();
     892
     893   if ($OtherIsVector) {
     894     # $OrderFlipped is set to false for two vectors...
     895     my($OtherSize) = $Other->GetSize();
     896     if ($ThisSize != $OtherSize) {
     897       return 1;
     898     }
     899     for $Index (0 .. ($ThisSize -1)) {
     900       if ($This->{Values}[$Index] == $Other->{Values}[$Index]) {
     901         return 0;
     902       }
     903     }
     904   }
     905   else {
     906     if ($OrderFlipped) {
     907       croak "Error: ${ClassName}->${ErrorMsg}: First object must be a vector...";
     908     }
     909     # Scalar comparison...
     910     for $Index (0 .. ($ThisSize -1)) {
     911       if ($This->{Values}[$Index] == $Other) {
     912         return 0;
     913       }
     914     }
     915   }
     916   return 1;
     917 }
     918
     919 #
     920 # Vector less than operator supports two modes:
     921 #   . Comparion of corresponding values in two vectors
     922 #   . Comparing vectors values to a scalar ($Vector < 2)
     923 #
     924 # Caveats:
     925 #   . Comparison of a scalar to vector values is not allowed (2 < $Vector2)
     926 #
     927 sub _VectorLessThanOperator {
     928   my($This, $Other, $OrderFlipped, $OtherIsVector, $ErrorMsg);
     929
     930   $ErrorMsg = "_VectorLessThanOperator: Vector less than comparison failed";
     931   ($This, $Other, $OrderFlipped, $OtherIsVector) = _ProcessOverloadedOperatorParameters($ErrorMsg, @_);
     932
     933   # Do the comparison...
     934   my($ThisSize, $Index);
     935   $ThisSize = $This->GetSize();
     936
     937   if ($OtherIsVector) {
     938     # $OrderFlipped is set to false for two vectors...
     939     for $Index (0 .. ($ThisSize -1)) {
     940       if ($This->{Values}[$Index] >= $Other->{Values}[$Index]) {
     941         return 0;
     942       }
     943     }
     944   }
     945   else {
     946     if ($OrderFlipped) {
     947       croak "Error: ${ClassName}->${ErrorMsg}: First object must be a vector...";
     948     }
     949     # Scalar comparison...
     950     for $Index (0 .. ($ThisSize -1)) {
     951       if ($This->{Values}[$Index] >= $Other) {
     952         return 0;
     953       }
     954     }
     955   }
     956   return 1;
     957 }
     958
     959 #
     960 # Vector less than equla operator supports two modes:
     961 #   . Comparion of corresponding values in two vectors
     962 #   . Comparing vectors values to a scalar ($Vector <= 2)
     963 #
     964 # Caveats:
     965 #   . Comparison of a scalar to vector values is not allowed (2 <= $Vector2)
     966 #
     967 sub _VectorLessThanEqualOperator {
     968   my($This, $Other, $OrderFlipped, $OtherIsVector, $ErrorMsg);
     969
     970   $ErrorMsg = "_VectorLessThanEqualOperator: Vector less than equal comparison failed";
     971   ($This, $Other, $OrderFlipped, $OtherIsVector) = _ProcessOverloadedOperatorParameters($ErrorMsg, @_);
     972
     973   # Do the comparison...
     974   my($ThisSize, $Index);
     975   $ThisSize = $This->GetSize();
     976
     977   if ($OtherIsVector) {
     978     # $OrderFlipped is set to false for two vectors...
     979     for $Index (0 .. ($ThisSize -1)) {
     980       if ($This->{Values}[$Index] > $Other->{Values}[$Index]) {
     981         return 0;
     982       }
     983     }
     984   }
     985   else {
     986     if ($OrderFlipped) {
     987       croak "Error: ${ClassName}->${ErrorMsg}: First object must be a vector...";
     988     }
     989     # Scalar comparison...
     990     for $Index (0 .. ($ThisSize -1)) {
     991       if ($This->{Values}[$Index] > $Other) {
     992         return 0;
     993       }
     994     }
     995   }
     996   return 1;
     997 }
     998
     999 #
    1000 # Vector greatar than operator supports two modes:
    1001 #   . Comparion of corresponding values in two vectors
    1002 #   . Comparing vectors values to a scalar ($Vector > 2)
    1003 #
    1004 # Caveats:
    1005 #   . Comparison of a scalar to vector values is not allowed (2 > $Vector2)
    1006 #
    1007 sub _VectorGreatarThanOperator {
    1008   my($This, $Other, $OrderFlipped, $OtherIsVector, $ErrorMsg);
    1009
    1010   $ErrorMsg = "_VectorGreatarThanOperator: Vector greatar than comparison failed";
    1011   ($This, $Other, $OrderFlipped, $OtherIsVector) = _ProcessOverloadedOperatorParameters($ErrorMsg, @_);
    1012
    1013   # Do the comparison...
    1014   my($ThisSize, $Index);
    1015   $ThisSize = $This->GetSize();
    1016
    1017   if ($OtherIsVector) {
    1018     # $OrderFlipped is set to false for two vectors...
    1019     for $Index (0 .. ($ThisSize -1)) {
    1020       if ($This->{Values}[$Index] <= $Other->{Values}[$Index]) {
    1021         return 0;
    1022       }
    1023     }
    1024   }
    1025   else {
    1026     if ($OrderFlipped) {
    1027       croak "Error: ${ClassName}->${ErrorMsg}: First object must be a vector...";
    1028     }
    1029     # Scalar comparison...
    1030     for $Index (0 .. ($ThisSize -1)) {
    1031       if ($This->{Values}[$Index] <= $Other) {
    1032         return 0;
    1033       }
    1034     }
    1035   }
    1036   return 1;
    1037 }
    1038
    1039 #
    1040 # Vector greatar than equal operator supports two modes:
    1041 #   . Comparion of corresponding values in two vectors
    1042 #   . Comparing vectors values to a scalar ($Vector >= 2)
    1043 #
    1044 # Caveats:
    1045 #   . Comparison of a scalar to vector values is not allowed (2 <= $Vector2)
    1046 #
    1047 sub _VectorGreatarThanEqualOperator {
    1048   my($This, $Other, $OrderFlipped, $OtherIsVector, $ErrorMsg);
    1049
    1050   $ErrorMsg = "_VectorGreatarThanEqualOperator: Vector greatar than equal comparison failed";
    1051   ($This, $Other, $OrderFlipped, $OtherIsVector) = _ProcessOverloadedOperatorParameters($ErrorMsg, @_);
    1052
    1053   # Do the comparison...
    1054   my($ThisSize, $Index);
    1055   $ThisSize = $This->GetSize();
    1056
    1057   if ($OtherIsVector) {
    1058     # $OrderFlipped is set to false for two vectors...
    1059     for $Index (0 .. ($ThisSize -1)) {
    1060       if ($This->{Values}[$Index] < $Other->{Values}[$Index]) {
    1061         return 0;
    1062       }
    1063     }
    1064   }
    1065   else {
    1066     if ($OrderFlipped) {
    1067       croak "Error: ${ClassName}->${ErrorMsg}: First object must be a vector...";
    1068     }
    1069     # Scalar comparison...
    1070     for $Index (0 .. ($ThisSize -1)) {
    1071       if ($This->{Values}[$Index] < $Other) {
    1072         return 0;
    1073       }
    1074     }
    1075   }
    1076   return 1;
    1077 }
    1078
    1079 #
    1080 # Vector negative value operator returns a vector with values corresponding to
    1081 # negative values of a vector
    1082 #
    1083 sub _VectorNegativeValueOperator {
    1084   my($This, $Other, $OrderFlipped, $OtherIsVector, $ErrorMsg);
    1085
    1086   $ErrorMsg = "_VectorNegativeValueOperator: Vector negative value operation failed";
    1087   ($This, $Other, $OrderFlipped, $OtherIsVector) = _ProcessOverloadedOperatorParameters($ErrorMsg, @_);
    1088
    1089   # Take the negative value...
    1090   my($Vector, $ThisSize, $Index);
    1091   $Vector = $This->Copy();
    1092   $ThisSize = $This->GetSize();
    1093
    1094   for $Index (0 .. ($ThisSize -1)) {
    1095     $Vector->{Values}[$Index] = - $This->{Values}[$Index];
    1096   }
    1097   return $Vector;
    1098 }
    1099
    1100 #
    1101 # Vector absolute value operator returns a vector with values corresponding to
    1102 # absolute values of a vector
    1103 #
    1104 sub _VectorAbsoluteValueOperator {
    1105   my($This, $Other, $OrderFlipped, $OtherIsVector, $ErrorMsg);
    1106
    1107   $ErrorMsg = "_VectorAbsoluteValueOperator: Vector absolute value operation failed";
    1108   ($This, $Other, $OrderFlipped, $OtherIsVector) = _ProcessOverloadedOperatorParameters($ErrorMsg, @_);
    1109
    1110   # Take the absolute value...
    1111   my($Vector, $ThisSize, $Index);
    1112   $Vector = $This->Copy();
    1113   $ThisSize = $This->GetSize();
    1114
    1115   for $Index (0 .. ($ThisSize -1)) {
    1116     $Vector->{Values}[$Index] = abs $This->{Values}[$Index];
    1117   }
    1118   return $Vector;
    1119 }
    1120
    1121 #
    1122 # Vector exp natural base operator returns a vector with values corresponding to
    1123 # e raised to the power of values in a vector
    1124 #
    1125 sub _VectorExpNaturalBaseOperator {
    1126   my($This, $Other, $OrderFlipped, $OtherIsVector, $ErrorMsg);
    1127
    1128   $ErrorMsg = "_VectorExpNaturalBaseOperator: Vector exp operation failed";
    1129   ($This, $Other, $OrderFlipped, $OtherIsVector) = _ProcessOverloadedOperatorParameters($ErrorMsg, @_);
    1130
    1131   # Take the absolute value...
    1132   my($Vector, $ThisSize, $Index);
    1133   $Vector = $This->Copy();
    1134   $ThisSize = $This->GetSize();
    1135
    1136   for $Index (0 .. ($ThisSize -1)) {
    1137     $Vector->{Values}[$Index] = exp $This->{Values}[$Index];
    1138   }
    1139   return $Vector;
    1140 }
    1141
    1142 #
    1143 # Vector log natural base operator returns a vector with values corresponding to
    1144 # log of values in a vector
    1145 #
    1146 sub _VectorLogNaturalBaseOperator {
    1147   my($This, $Other, $OrderFlipped, $OtherIsVector, $ErrorMsg);
    1148
    1149   $ErrorMsg = "_VectorLogNaturalBaseOperator: Vector log operation failed";
    1150   ($This, $Other, $OrderFlipped, $OtherIsVector) = _ProcessOverloadedOperatorParameters($ErrorMsg, @_);
    1151
    1152   # Take the absolute value...
    1153   my($Vector, $ThisSize, $Index);
    1154   $Vector = $This->Copy();
    1155   $ThisSize = $This->GetSize();
    1156
    1157   for $Index (0 .. ($ThisSize -1)) {
    1158     $Vector->{Values}[$Index] = log $This->{Values}[$Index];
    1159   }
    1160   return $Vector;
    1161 }
    1162
    1163 #
    1164 # Vector cosine operator returns a vector with values corresponding to cosine of values
    1165 # in a vector. Input vector values are assumed to be in radians.
    1166 #
    1167 sub _VectorCosineOperator {
    1168   my($This, $Other, $OrderFlipped, $OtherIsVector, $ErrorMsg);
    1169
    1170   $ErrorMsg = "_VectorCosineOperator: Vector cos operation failed";
    1171   ($This, $Other, $OrderFlipped, $OtherIsVector) = _ProcessOverloadedOperatorParameters($ErrorMsg, @_);
    1172
    1173   # Take the absolute value...
    1174   my($Vector, $ThisSize, $Index);
    1175   $Vector = $This->Copy();
    1176   $ThisSize = $This->GetSize();
    1177
    1178   for $Index (0 .. ($ThisSize -1)) {
    1179     $Vector->{Values}[$Index] = cos $This->{Values}[$Index];
    1180   }
    1181   return $Vector;
    1182 }
    1183
    1184 #
    1185 # Vector sine operator returns a vector with values corresponding to sine of values
    1186 # in a vector. Input vector values are assumed to be in radians.
    1187 #
    1188 sub _VectorSineOperator {
    1189   my($This, $Other, $OrderFlipped, $OtherIsVector, $ErrorMsg);
    1190
    1191   $ErrorMsg = "_VectorSineOperator: Vector sin operation failed";
    1192   ($This, $Other, $OrderFlipped, $OtherIsVector) = _ProcessOverloadedOperatorParameters($ErrorMsg, @_);
    1193
    1194   # Take the absolute value...
    1195   my($Vector, $ThisSize, $Index);
    1196   $Vector = $This->Copy();
    1197   $ThisSize = $This->GetSize();
    1198
    1199   for $Index (0 .. ($ThisSize -1)) {
    1200     $Vector->{Values}[$Index] = sin $This->{Values}[$Index];
    1201   }
    1202   return $Vector;
    1203 }
    1204
    1205 #
    1206 # Vector square root  returns a vector with values corresponding to sqrt of values
    1207 # in a vector.
    1208 #
    1209 sub _VectorSquareRootOperator {
    1210   my($This, $Other, $OrderFlipped, $OtherIsVector, $ErrorMsg);
    1211
    1212   $ErrorMsg = "_VectorSquareRootOperator: Vector sqrt operation failed";
    1213   ($This, $Other, $OrderFlipped, $OtherIsVector) = _ProcessOverloadedOperatorParameters($ErrorMsg, @_);
    1214
    1215   # Take the absolute value...
    1216   my($Vector, $ThisSize, $Index);
    1217   $Vector = $This->Copy();
    1218   $ThisSize = $This->GetSize();
    1219
    1220   for $Index (0 .. ($ThisSize -1)) {
    1221     $Vector->{Values}[$Index] = sqrt $This->{Values}[$Index];
    1222   }
    1223   return $Vector;
    1224 }
    1225
    1226 # Turn vector into array for @{$Vector} operation...
    1227 sub _VectorToArrayOperator {
    1228   my($This) = @_;
    1229
    1230   return \@{$This->{Values}};
    1231 }
    1232
    1233 # Turn vector into number for $#Vector operation: It's the size of vector...
    1234 sub _NumifyVector {
    1235   my($This) = @_;
    1236
    1237   return $This->GetSize();
    1238 }
    1239
    1240 # Process parameters passed to overloaded operators...
    1241 #
    1242 # For uninary operators, $SecondParameter is not defined.
    1243 sub _ProcessOverloadedOperatorParameters {
    1244   my($ErrorMsg, $FirstParameter, $SecondParameter, $ParametersOrderStatus, $CheckVectorSizesStatus) = @_;
    1245   my($This, $Other, $OrderFlipped, $OtherIsVector, $CheckVectorSizes);
    1246
    1247   ($This, $Other) =  ($FirstParameter, $SecondParameter);
    1248   $OrderFlipped = (defined($ParametersOrderStatus) && $ParametersOrderStatus) ? 1 : 0;
    1249   $CheckVectorSizes = (defined $CheckVectorSizesStatus) ? $CheckVectorSizesStatus : 1;
    1250
    1251   _ValidateVector($ErrorMsg, $This);
    1252
    1253   $OtherIsVector = 0;
    1254   if (defined($Other) && (ref $Other)) {
    1255     # Make sure $Other is a vector...
    1256     _ValidateVector($ErrorMsg, $Other);
    1257     if ($CheckVectorSizes) {
    1258       _ValidateVectorSizesAreEqual($ErrorMsg, $This, $Other);
    1259     }
    1260     $OtherIsVector = 1;
    1261   }
    1262   return ($This, $Other, $OrderFlipped, $OtherIsVector);
    1263 }
    1264
    1265 # Is it a vector object?
    1266 sub _IsVector {
    1267   my($Object) = @_;
    1268
    1269   return (Scalar::Util::blessed($Object) && $Object->isa($ClassName)) ? 1 : 0;
    1270 }
    1271
    1272 # Make sure it's a vector reference...
    1273 sub _ValidateVector {
    1274   my($ErrorMsg, $Vector) = @_;
    1275
    1276   if (!_IsVector($Vector)) {
    1277     croak "Error: ${ClassName}->${ErrorMsg}: Object must be a vector...";
    1278   }
    1279 }
    1280
    1281 # Make sure size of the two vectors contain the same number of values...
    1282 sub _ValidateVectorSizesAreEqual {
    1283   my($ErrorMsg, $Vector1, $Vector2) = @_;
    1284
    1285   if ($Vector1->GetSize() != $Vector2->GetSize()) {
    1286     croak "Error: ${ClassName}->${ErrorMsg}: Size of the vectors must be same...";
    1287   }
    1288 }
    1289
    1290 # Return a string containing vector values...
    1291 sub StringifyVector {
    1292   my($This) = @_;
    1293   my($VectorString, $FormatString, $PrintFormat, $Size, @ValuesFormat);
    1294
    1295   $PrintFormat = (exists $This->{ValueFormat}) ? $This->{ValueFormat} : $ValueFormat;
    1296
    1297   @ValuesFormat = ($PrintFormat) x scalar @{$This->{Values}};
    1298   $FormatString = join ' ', @ValuesFormat;
    1299
    1300   $Size = $This->GetSize();
    1301
    1302   $VectorString = sprintf "<Size: $Size; Values: [ $FormatString ] >", @{$This->{Values}};
    1303
    1304   return $VectorString;
    1305 }
    1306