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