MayaChemTools

   1 package Vector;
   2 #
   3 # File: Vector.pm
   4 # Author: Manish Sud <msud@san.rr.com>
   5 #
   6 # Copyright (C) 2024 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