MayaChemTools

   1 package Matrix;
   2 #
   3 # $RCSfile: Matrix.pm,v $
   4 # $Date: 2015/02/28 20:47:17 $
   5 # $Revision: 1.16 $
   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 Vector;
  34 
  35 use vars qw(@ISA @EXPORT @EXPORT_OK %EXPORT_TAGS);
  36 
  37 @ISA = qw(Exporter);
  38 @EXPORT = qw(IsMatrix IdentityMatrix NewFromRows NewFromColumns NewFromDiagonal UnitMatrix ZeroMatrix);
  39 @EXPORT_OK = qw(SetValuePrintFormat);
  40 
  41 %EXPORT_TAGS = (
  42                 all  => [@EXPORT, @EXPORT_OK]
  43                );
  44 
  45 # Setup class variables...
  46 my($ClassName, $ValueFormat, $MatrixPrintStyle);
  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 '""' => 'StringifyMatrix',
  60 
  61   '@{}' => '_MatrixToArrayOperator',
  62 
  63   '+' => '_MatrixAdditionOperator',
  64   '-' => '_MatrixSubtractionOperator',
  65   '*' => '_MatrixMultiplicationOperator',
  66   '/' => '_MatrixDivisionOperator',
  67   '**' => '_MatrixExponentiationOperator',
  68   '%' => '_MatrixModulusOperator',
  69 
  70   'bool' => '_MatrixBooleanOperator',
  71   '!' => '_MatrixNotBooleanOperator',
  72 
  73   '==' => '_MatrixEqualOperator',
  74   '!=' => '_MatrixNotEqualOperator',
  75   '<' => '_MatrixLessThanOperator',
  76   '<=' => '_MatrixLessThanEqualOperator',
  77   '>' => '_MatrixGreatarThanOperator',
  78   '>=' => '_MatrixGreatarThanEqualOperator',
  79 
  80   'neg' => '_MatrixNegativeValueOperator',
  81 
  82   'abs' => '_MatrixAbsoluteValueOperator',
  83   'exp' => '_MatrixExpNaturalBaseOperator',
  84   'log' => '_MatrixLogNaturalBaseOperator',
  85   'sqrt' => '_MatrixSquareRootOperator',
  86   'cos' => '_MatrixCosineOperator',
  87   'sin' => '_MatrixSineOperator',
  88 
  89   'fallback' => undef;
  90 
  91 # Class constructor...
  92 sub new {
  93   my($Class, $NumOfRows, $NumOfCols) = @_;
  94 
  95   # Initialize object...
  96   my $This = {};
  97   bless $This, ref($Class) || $Class;
  98   $This->_InitializeMatrix($NumOfRows, $NumOfCols);
  99 
 100   return $This;
 101 }
 102 
 103 # Initialize object data...
 104 #
 105 sub _InitializeMatrix {
 106   my($This, $NumOfRows, $NumOfCols) = @_;
 107 
 108   if (!(defined($NumOfRows) && defined($NumOfCols))) {
 109     croak "Error: ${ClassName}->_InitializeMatrix: NumOfRows and NumOfCols must be specified...";
 110   }
 111   if (!(($NumOfRows > 0) && ($NumOfRows > 0))) {
 112     croak "Error: ${ClassName}->_InitializeMatrix: NumOfRows and NumOfCols must be a positive number...";
 113   }
 114   # Initialize matrix elements to zero...
 115   @{$This->{Values}} = ();
 116 
 117   my($RowIndex, @EmptyRow);
 118 
 119   @EmptyRow = ();
 120   @EmptyRow = ('0') x $NumOfCols;
 121 
 122   for $RowIndex (0 .. ($NumOfRows - 1)) {
 123     @{$This->{Values}[$RowIndex]} = ();
 124     @{$This->{Values}[$RowIndex]} = @EmptyRow;
 125   }
 126 }
 127 
 128 # Initialize class ...
 129 sub _InitializeClass {
 130   #Class name...
 131   $ClassName = __PACKAGE__;
 132 
 133   # Print style for matrix rows during StringifyMatrix operation.
 134   # Possible values: AllRowsInOneLine, OneRowPerLine
 135   #
 136   $MatrixPrintStyle = "AllRowsInOneLine";
 137 
 138   # Print format for matrix values...
 139   $ValueFormat = "%g";
 140 }
 141 
 142 # Get matrix size...
 143 #
 144 sub GetSize {
 145   my($This) = @_;
 146 
 147   return ($This->GetNumOfRows(), $This->GetNumOfColumns());
 148 }
 149 
 150 # Get matrix dimensions...
 151 #
 152 sub GetDimension {
 153   my($This) = @_;
 154 
 155   return $This->GetSize();
 156 }
 157 
 158 # Get number of rows in matrix
 159 #
 160 sub GetNumOfRows {
 161   my($This) = @_;
 162   my($NumOfRows);
 163 
 164   # Size of row array...
 165   $NumOfRows = $#{$This->{Values}} + 1;
 166 
 167   return $NumOfRows;
 168 }
 169 
 170 # Get number of columns in matrix
 171 #
 172 sub GetNumOfColumns {
 173   my($This) = @_;
 174   my($NumOfCols);
 175 
 176   # Size of column array for first row assuming sizes of columns are same...
 177   $NumOfCols = $#{$This->{Values}[0]} + 1;
 178 
 179   return $NumOfCols;
 180 }
 181 
 182 # Get reference to array holding matrix values in order to directly manipulate these values...
 183 #
 184 sub GetMatrixValuesReference {
 185   my($This) = @_;
 186 
 187   return \@{$This->{Values}};
 188 }
 189 
 190 # Copy matrix...
 191 #
 192 sub Copy {
 193   my($This) = @_;
 194   my($NumOfRows, $NumOfCols, $RowIndex, $ColIndex, $Matrix);
 195 
 196   # Create a new matrix...
 197   ($NumOfRows, $NumOfCols) = $This->GetSize();
 198   $Matrix = new Matrix($NumOfRows, $NumOfCols);
 199 
 200   # Set matrix values...
 201   for $RowIndex (0 .. ($NumOfRows -1)) {
 202     for $ColIndex (0 .. ($NumOfCols -1)) {
 203       $Matrix->{Values}[$RowIndex][$ColIndex] = $This->{Values}[$RowIndex][$ColIndex];
 204     }
 205   }
 206   return $Matrix;
 207 }
 208 
 209 # Create a new matrix using rows specified in one of the following formats:
 210 #   o List of vector objects
 211 #   o References to list of values
 212 #   o List of strings containing row values delimited by space
 213 #
 214 # Each row must contain the same number of values.
 215 #
 216 # This functionality can be either invoked as a class function or an
 217 # object method.
 218 #
 219 sub NewFromRows {
 220   my($FirstParameter, @OtherParamaters) = @_;
 221 
 222   if (IsMatrix($FirstParameter)) {
 223     return _NewFromRowsOrColumns('FromRows', @OtherParamaters);
 224   }
 225   else {
 226     return _NewFromRowsOrColumns('FromRows', @_);
 227   }
 228 }
 229 
 230 # Create a new matrix using columns specified in one of the following formats:
 231 #   o List of vector objects
 232 #   o References to list of values
 233 #   o List of strings containing columns values delimited by space
 234 #
 235 # Each columns must contain the same number of values.
 236 #
 237 # This functionality can be either invoked as a class function or an
 238 # object method.
 239 #
 240 sub NewFromColumns {
 241   my($FirstParameter, @OtherParamaters) = @_;
 242 
 243   if (IsMatrix($FirstParameter)) {
 244     return _NewFromRowsOrColumns('FromColumns', @OtherParamaters);
 245   }
 246   else {
 247     return _NewFromRowsOrColumns('FromColumns', @_);
 248   }
 249 }
 250 
 251 # Create a new matrix using diagonal values specified in one of the following formats:
 252 #   o A vector object
 253 #   o Reference to list of values
 254 #   o Strings containing diagonal values delimited by space
 255 #
 256 # This functionality can be either invoked as a class function or an
 257 # object method.
 258 #
 259 sub NewFromDiagonal {
 260   my($FirstParameter, @OtherParamaters) = @_;
 261 
 262   if (IsMatrix($FirstParameter)) {
 263     return _NewFromDiagonal(@OtherParamaters);
 264   }
 265   else {
 266     return _NewFromDiagonal(@_);
 267   }
 268 }
 269 
 270 # Create a new matrix using diagonal values specified in one of the following formats:
 271 #   o A vector object
 272 #   o Reference to list of values
 273 #   o Strings containing diagonal values delimited by space
 274 #
 275 sub _NewFromDiagonal {
 276   my(@SpecifiedDiagonalValues) = @_;
 277   my($ErrorMsgPrefix, $CheckSizes, $CombineValues, $ValuesRefs, $DiagonalValuesRef);
 278 
 279   $ErrorMsgPrefix = "Error: ${ClassName}::_NewFromDiagonal";
 280   if (!@SpecifiedDiagonalValues) {
 281     croak "$ErrorMsgPrefix: No diagonal values specified...";
 282   }
 283 
 284   # Collect specified diagonal values...
 285   $CheckSizes = 0; $CombineValues = 1;
 286   $ValuesRefs = _ProcessSpecifiedMatrixValues($ErrorMsgPrefix, $CheckSizes, $CombineValues, @SpecifiedDiagonalValues);
 287   $DiagonalValuesRef = $ValuesRefs->[0];
 288 
 289   # Create a new matrix...
 290   my($Matrix, $NumOfRows, $NumOfCols, $RowIndex);
 291 
 292   $NumOfRows = @{$DiagonalValuesRef};
 293   $NumOfCols = $NumOfRows;
 294 
 295   $Matrix = new Matrix($NumOfRows, $NumOfCols);
 296 
 297   # Set diagonal values...
 298   for $RowIndex (0 .. ($NumOfRows - 1)) {
 299     $Matrix->{Values}[$RowIndex][$RowIndex] = $DiagonalValuesRef->[$RowIndex];
 300   }
 301 
 302   return $Matrix;
 303 }
 304 
 305 # Create a new matrix using rows or columns specified in one of the following formats:
 306 #   o List of vector objects
 307 #   o References to list of values
 308 #   o List of strings containing row values delimited by space
 309 #
 310 # Each row or column must contain the same number of values.
 311 #
 312 sub _NewFromRowsOrColumns {
 313   my($Mode, @SpecifiedValues) = @_;
 314 
 315   if ($Mode !~ /^(FromRows|FromColumns)$/i) {
 316     croak "Error: ${ClassName}::_NewFromRowsOrColumns: Unknown mode: $Mode...";
 317   }
 318   my($ErrorMsgPrefix, $CheckSizes, $CombineValues, $ValuesRefs);
 319 
 320   # Retrieve information about specified values and make sure similar number of values
 321   # are specified for each row or column...
 322   if ($Mode =~ /^FromRows$/i) {
 323     $ErrorMsgPrefix = "Error: ${ClassName}::_NewFromRows";
 324   }
 325   else {
 326     $ErrorMsgPrefix = "Error: ${ClassName}::_NewFromColumns";
 327   }
 328   $CheckSizes = 1; $CombineValues = 0;
 329   $ValuesRefs = _ProcessSpecifiedMatrixValues($ErrorMsgPrefix, $CheckSizes, $CombineValues, @SpecifiedValues);
 330 
 331   # Create a new matrix...
 332   my($Matrix, $NumOfRows, $NumOfCols, $RowIndex, $ColIndex, $RowMode, $Value);
 333 
 334   if ($Mode =~ /^FromRows$/i) {
 335     $NumOfRows = scalar @{$ValuesRefs};
 336     $NumOfCols = scalar @{$ValuesRefs->[0]};
 337     $RowMode = 1;
 338   }
 339   elsif ($Mode =~ /^FromColumns$/i) {
 340     $NumOfRows = scalar @{$ValuesRefs->[0]};
 341     $NumOfCols = scalar @{$ValuesRefs};
 342     $RowMode = 0;
 343   }
 344   $Matrix = new Matrix($NumOfRows, $NumOfCols);
 345 
 346   # Setup matrix values...
 347   for $RowIndex (0 .. ($NumOfRows - 1)) {
 348     for $ColIndex (0 .. ($NumOfCols - 1)) {
 349       $Value = $RowMode ? $ValuesRefs->[$RowIndex]->[$ColIndex]: $ValuesRefs->[$ColIndex]->[$RowIndex];
 350       $Matrix->{Values}[$RowIndex][$ColIndex] = $Value;
 351     }
 352   }
 353 
 354   return $Matrix;
 355 }
 356 
 357 # Process specified matrix values in any of the following supported formats:
 358 #
 359 #   o List of vector objects
 360 #   o References to list of values
 361 #   o List of strings containing row values delimited by space
 362 #
 363 # And return a reference to an array containing references to arrays with specified values.
 364 #
 365 # Value of CombineValuesStatus determines whether all the values specified are combined
 366 # into one array and return its reference as the only entry in the array being returned.
 367 #
 368 sub _ProcessSpecifiedMatrixValues {
 369   my($ErrorMsgPrefix, $CheckSizesStatus, $CombineValuesStatus, @SpecifiedValues) = @_;
 370   my($Value, $TypeOfValue, @ValuesRefs);
 371 
 372   @ValuesRefs = ();
 373   if (!@SpecifiedValues) {
 374     croak "$ErrorMsgPrefix: No values specified...";
 375   }
 376 
 377   # Collect values...
 378   for $Value (@SpecifiedValues) {
 379     $TypeOfValue = ref $Value;
 380 
 381     if (Vector::IsVector($Value)) {
 382       # Feference to vector object...
 383       my($ValuesRef);
 384       $ValuesRef = $Value->GetValues();
 385       if (!@{$ValuesRef}) {
 386         croak "$ErrorMsgPrefix: Specified vector object must contain some values...";
 387       }
 388       push @ValuesRefs, $ValuesRef;
 389     }
 390     elsif ($TypeOfValue =~ /^ARRAY/) {
 391       # Refernece to an array...
 392       if (!@{$Value}) {
 393         croak "$ErrorMsgPrefix: Specified array reference must contain some values...";
 394       }
 395       push @ValuesRefs, $Value;
 396     }
 397     elsif ($TypeOfValue eq '') {
 398       # String value...
 399       my(@Values);
 400       @Values = split(' ', $Value);
 401       if (!@Values) {
 402         croak "$ErrorMsgPrefix: Specified string must contain some values...";
 403       }
 404       push @ValuesRefs, \@Values;
 405     }
 406     else {
 407       croak "$ErrorMsgPrefix: Value format, $TypeOfValue, of a specified value to be added to matrix object is not supported...";
 408     }
 409   }
 410 
 411   # Combine all specified values into one array...
 412   if ($CombineValuesStatus) {
 413     my($ValuesRef, @Values);
 414 
 415     @Values = ();
 416     for $ValuesRef (@ValuesRefs) {
 417       push @Values, @{$ValuesRef};
 418     }
 419     @ValuesRefs = ();
 420     push @ValuesRefs, \@Values;
 421   }
 422 
 423   # Make sure reference to all specified value arrays contain the same number of values...
 424   if ($CheckSizesStatus) {
 425     my($Index, $FirstValueSize);
 426     $FirstValueSize = $#{$ValuesRefs[0]};
 427     for $Index (1 .. $#ValuesRefs) {
 428       if ($FirstValueSize != $#{$ValuesRefs[$Index]}) {
 429         croak "$ErrorMsgPrefix: Number of values in each specified value type to be added to matrix object must be same...";
 430       }
 431     }
 432   }
 433 
 434   return \@ValuesRefs;
 435 }
 436 
 437 # Create a new zero matrix of specified size or default size of 3 x 3.
 438 #
 439 # This functionality can be either invoked as a class function or an
 440 # object method.
 441 #
 442 sub ZeroMatrix (;$$$) {
 443   my($FirstParameter, $SecondParameter, $ThirdParameter) = @_;
 444   my($This, $NumOfRows, $NumOfCols, $Matrix);
 445 
 446   $This = undef;
 447   if (defined($FirstParameter) && IsMatrix($FirstParameter)) {
 448     ($This, $NumOfRows, $NumOfCols) = ($FirstParameter, $SecondParameter, $ThirdParameter);
 449   }
 450   else {
 451     ($This, $NumOfRows, $NumOfCols) = (undef, $FirstParameter, $SecondParameter);
 452   }
 453   ($NumOfRows, $NumOfCols) = (defined($NumOfRows) && defined($NumOfCols)) ? ($NumOfRows, $NumOfCols) : (3, 3);
 454 
 455   # Set up a new zero matrix
 456   $Matrix = new Matrix($NumOfRows, $NumOfCols);
 457 
 458   return $Matrix;
 459 }
 460 
 461 # Create a new unit matrix of specified size or default size of 3 x 3.
 462 #
 463 # This functionality can be either invoked as a class function or an
 464 # object method.
 465 #
 466 sub UnitMatrix (;$$$) {
 467   my($FirstParameter, $SecondParameter, $ThirdParameter) = @_;
 468   my($This, $NumOfRows, $NumOfCols, $Matrix, $RowIndex);
 469 
 470   $This = undef;
 471   if (defined($FirstParameter) && IsMatrix($FirstParameter)) {
 472     ($This, $NumOfRows, $NumOfCols) = ($FirstParameter, $SecondParameter, $ThirdParameter);
 473   }
 474   else {
 475     ($This, $NumOfRows, $NumOfCols) = (undef, $FirstParameter, $SecondParameter);
 476   }
 477   ($NumOfRows, $NumOfCols) = (defined($NumOfRows) && defined($NumOfCols)) ? ($NumOfRows, $NumOfCols) : (3, 3);
 478 
 479   # Set up a new zero matrix
 480   $Matrix = new Matrix($NumOfRows, $NumOfCols);
 481 
 482   if ($NumOfRows != $NumOfCols) {
 483     carp "Warning: ${ClassName}::UnitMatrix: Specified matrix, $NumOfRows x $NumOfCols, is not a square matrix...";
 484   }
 485 
 486   # Initialize diagonal elements to 1...
 487   for $RowIndex (0 .. ($NumOfRows - 1)) {
 488     $Matrix->{Values}[$RowIndex][$RowIndex] = 1.0;
 489   }
 490 
 491   return $Matrix;
 492 }
 493 
 494 # Identity matrix of specified size or size 3 x 3...
 495 #
 496 sub IdentityMatrix (;$$$) {
 497   my($FirstParameter, $SecondParameter, $ThirdParameter) = @_;
 498 
 499   return UnitMatrix($FirstParameter, $SecondParameter, $ThirdParameter);
 500 }
 501 
 502 # Set all matrix values to 0s...
 503 #
 504 sub Zero {
 505   my($This) = @_;
 506 
 507   return $This->SetAllValues(0.0);
 508 }
 509 
 510 # Set all matrix values to 1s...
 511 #
 512 sub One {
 513   my($This) = @_;
 514 
 515   return $This->SetAllValues(1.0);
 516 }
 517 
 518 # Get a matrix value with row and column indicies starting from 0...
 519 #
 520 sub GetValue {
 521   my($This, $RowIndex, $ColIndex, $SkipIndexCheck) = @_;
 522 
 523   if ($SkipIndexCheck) {
 524     $This->_GetValue($RowIndex, $ColIndex);
 525   }
 526 
 527   $This->_ValidateRowAndColumnIndicies("Error: ${ClassName}::GetValue", $RowIndex, $ColIndex);
 528 
 529   return $This->_GetValue($RowIndex, $ColIndex);
 530 }
 531 
 532 # Get a matrix value...
 533 #
 534 sub _GetValue {
 535   my($This, $RowIndex, $ColIndex) = @_;
 536 
 537   return $This->{Values}[$RowIndex][$ColIndex];
 538 }
 539 
 540 # Set a matrix value with row and column indicies starting from 0...
 541 #
 542 sub SetValue {
 543   my($This, $RowIndex, $ColIndex, $Value, $SkipIndexCheck) = @_;
 544 
 545   if ($SkipIndexCheck) {
 546     $This->_SetValue($RowIndex, $ColIndex, $Value);
 547   }
 548 
 549   $This->_ValidateRowAndColumnIndicies("Error: ${ClassName}::SetValue", $RowIndex, $ColIndex);
 550 
 551   return $This->_SetValue($RowIndex, $ColIndex, $Value);
 552 }
 553 
 554 # Set a matrix value...
 555 #
 556 sub _SetValue {
 557   my($This, $RowIndex, $ColIndex, $Value) = @_;
 558 
 559   $This->{Values}[$RowIndex][$ColIndex] = $Value;
 560 
 561   return $This;
 562 }
 563 
 564 # Set all matrix values to a specified value...
 565 #
 566 sub SetAllValues {
 567   my($This, $Value) = @_;
 568   my($NumOfRows, $NumOfCols, $RowIndex, $ColIndex);
 569 
 570   ($NumOfRows, $NumOfCols) = $This->GetSize();
 571   for $RowIndex (0 .. ($NumOfRows - 1)) {
 572     for $ColIndex (0 .. ($NumOfCols - 1)) {
 573       $This->{Values}[$RowIndex][$ColIndex] = $Value;
 574     }
 575   }
 576   return $This;
 577 }
 578 
 579 # Set values of a row in a matrix value with row index starting from 0...
 580 #
 581 sub SetRowValues {
 582   my($This, $RowIndex, @SpecifiedValues) = @_;
 583   my($NumOfRows, $NumOfCols, $ColIndex, $ErrorMsgPrefix, $CheckSizes, $CombineValues, $ValuesRefs, $RowValuesRef, $NumOfRowValues);
 584 
 585   $ErrorMsgPrefix = "Error: ${ClassName}->SetRowValues";
 586 
 587   ($NumOfRows, $NumOfCols) = $This->GetSize();
 588   $This->_ValidateRowIndex($ErrorMsgPrefix, $RowIndex);
 589 
 590   # Collect specified row values...
 591   $CheckSizes = 0; $CombineValues = 1;
 592   $ValuesRefs = _ProcessSpecifiedMatrixValues($ErrorMsgPrefix, $CheckSizes, $CombineValues, @SpecifiedValues);
 593   $RowValuesRef = $ValuesRefs->[0];
 594 
 595   # Check number of specified row values...
 596   $NumOfRowValues = @{$RowValuesRef};
 597   if ($NumOfRowValues != $NumOfCols) {
 598     croak "$ErrorMsgPrefix: Number of specified row values, $NumOfRowValues, must be equal to number of row values, $NumOfCols, in matrix...";
 599   }
 600 
 601   # Set row values...
 602   for $ColIndex (0 .. ($NumOfRowValues - 1)) {
 603     $This->{Values}[$RowIndex][$ColIndex] = $RowValuesRef->[$ColIndex];
 604   }
 605   return $This;
 606 }
 607 
 608 # Add new row values to a matrix...
 609 #
 610 sub AddRowValues {
 611   my($This, @SpecifiedValues) = @_;
 612   my($NumOfRows, $NumOfCols, $RowIndex, $ErrorMsgPrefix, $CheckSizes, $CombineValues, $RowValueRef, $RowValuesRefs, $NumOfNewRows, $NumOfNewCols);
 613 
 614   $ErrorMsgPrefix = "Error: ${ClassName}->AddRowValues";
 615 
 616   ($NumOfRows, $NumOfCols) = $This->GetSize();
 617 
 618   # Collect specified row values...
 619   $CheckSizes = 1; $CombineValues = 0;
 620   $RowValuesRefs = _ProcessSpecifiedMatrixValues($ErrorMsgPrefix, $CheckSizes, $CombineValues, @SpecifiedValues);
 621 
 622   # Check number of specified row values...
 623   $NumOfNewRows = scalar @{$RowValuesRefs};
 624   $NumOfNewCols = scalar @{$RowValuesRefs->[0]};
 625 
 626   if ($NumOfNewCols != $NumOfCols) {
 627     croak "$ErrorMsgPrefix: Number of values in each specified row, $NumOfNewCols, must be equal to number of row values, $NumOfCols, in matrix...";
 628   }
 629 
 630   # Add each row to the matrix...
 631   $RowIndex = $NumOfRows - 1;
 632   for $RowValueRef (@{$RowValuesRefs}) {
 633     $RowIndex++;
 634     @{$This->{Values}[$RowIndex]} = @{$RowValueRef};
 635   }
 636 
 637   return $This;
 638 }
 639 
 640 # Get values of a row in matrix as an array. In scalar context, number of row
 641 # values is returned...
 642 #
 643 sub GetRowValues {
 644   my($This, $RowIndex) = @_;
 645 
 646   return $This->_GetRowOrColumnValues('AsArray', 'FromRow', $RowIndex);
 647 }
 648 
 649 # Get values of a row in matrix as a vector object...
 650 #
 651 sub GetRowValuesAsVector {
 652   my($This, $RowIndex) = @_;
 653 
 654   return $This->_GetRowOrColumnValues('AsVector', 'FromRow', $RowIndex);
 655 }
 656 
 657 # Get values of a row as row matrix object...
 658 #
 659 sub GetRowValuesAsRowMatrix {
 660   my($This, $RowIndex) = @_;
 661 
 662   return $This->_GetRowOrColumnValues('AsRowMatrix', 'FromRow', $RowIndex);
 663 }
 664 
 665 # Get values of a row as column matrix object...
 666 #
 667 sub GetRowValuesAsColumnMatrix {
 668   my($This, $RowIndex) = @_;
 669 
 670   return $This->_GetRowOrColumnValues('AsColumnMatrix', 'FromRow', $RowIndex);
 671 }
 672 
 673 # Get values of a row in matrix as a space delimited string...
 674 #
 675 sub GetRowValuesAsString {
 676   my($This, $RowIndex) = @_;
 677 
 678   return $This->_GetRowOrColumnValues('AsString', 'FromRow', $RowIndex);
 679 }
 680 
 681 # Set values of a column in a matrix value with row index starting from 0...
 682 #
 683 sub SetColumnValues {
 684   my($This, $ColIndex, @SpecifiedValues) = @_;
 685   my($NumOfRows, $NumOfCols, $RowIndex, $ErrorMsgPrefix, $CheckSizes, $CombineValues, $ValuesRefs, $ColValuesRef, $NumOfColValues);
 686 
 687   $ErrorMsgPrefix = "Error: ${ClassName}->SetColumnValues";
 688 
 689   ($NumOfRows, $NumOfCols) = $This->GetSize();
 690   $This->_ValidateColumnIndex($ErrorMsgPrefix, $ColIndex);
 691 
 692   # Collect specified row values...
 693   $CheckSizes = 0; $CombineValues = 1;
 694   $ValuesRefs = _ProcessSpecifiedMatrixValues($ErrorMsgPrefix, $CheckSizes, $CombineValues, @SpecifiedValues);
 695   $ColValuesRef = $ValuesRefs->[0];
 696 
 697   # Check number of specified col values...
 698   $NumOfColValues = @{$ColValuesRef};
 699   if ($NumOfColValues != $NumOfRows) {
 700     croak "$ErrorMsgPrefix: Number of specified col values, $NumOfColValues, must be equal to number of column values, $NumOfRows, in matrix...";
 701   }
 702 
 703   # Set col values...
 704   for $RowIndex (0 .. ($NumOfColValues - 1)) {
 705     $This->{Values}[$RowIndex][$ColIndex] = $ColValuesRef->[$RowIndex];
 706   }
 707   return $This;
 708 }
 709 
 710 # Add new column values to a matrix...
 711 #
 712 sub AddColumnValues {
 713   my($This, @SpecifiedValues) = @_;
 714   my($NumOfRows, $NumOfCols, $RowIndex, $ColIndex, $ErrorMsgPrefix, $CheckSizes, $CombineValues, $ColValueRef, $ColValuesRefs, $NumOfNewRows, $NumOfNewCols);
 715 
 716   $ErrorMsgPrefix = "Error: ${ClassName}->AddColumnValues";
 717 
 718   ($NumOfRows, $NumOfCols) = $This->GetSize();
 719 
 720   # Collect specified column values...
 721   $CheckSizes = 1; $CombineValues = 0;
 722   $ColValuesRefs = _ProcessSpecifiedMatrixValues($ErrorMsgPrefix, $CheckSizes, $CombineValues, @SpecifiedValues);
 723 
 724   # Check number of specified column values...
 725   $NumOfNewCols = scalar @{$ColValuesRefs};
 726   $NumOfNewRows = scalar @{$ColValuesRefs->[0]};
 727 
 728   if ($NumOfNewRows != $NumOfRows) {
 729     croak "$ErrorMsgPrefix: Number of values in each specified column, $NumOfNewRows, must be equal to number of column values, $NumOfRows, in matrix...";
 730   }
 731 
 732   # Add each column to the matrix...
 733   $ColIndex = $NumOfCols - 1;
 734   for $ColValueRef (@{$ColValuesRefs}) {
 735     $ColIndex++;
 736     for $RowIndex (0 .. ($NumOfCols - 1)) {
 737       $This->{Values}[$RowIndex][$ColIndex] = $ColValueRef->[$RowIndex];
 738     }
 739   }
 740 
 741   return $This;
 742 }
 743 
 744 # Get values of a column in matrix as an array. In scalar context, number of column
 745 # values is returned...
 746 #
 747 sub GetColumnValues {
 748   my($This, $ColIndex) = @_;
 749 
 750   return $This->_GetRowOrColumnValues('AsArray', 'FromColumn', $ColIndex);
 751 }
 752 
 753 # Get values of a column in matrix as a vector object...
 754 #
 755 sub GetColumnValuesAsVector {
 756   my($This, $ColIndex) = @_;
 757 
 758   return $This->_GetRowOrColumnValues('AsVector', 'FromColumn', $ColIndex);
 759 }
 760 
 761 # Get values of a column as row matrix object...
 762 #
 763 sub GetColumnValuesAsRowMatrix {
 764   my($This, $ColIndex) = @_;
 765 
 766   return $This->_GetRowOrColumnValues('AsRowMatrix', 'FromColumn', $ColIndex);
 767 }
 768 
 769 # Get values of a column as column matrix object...
 770 #
 771 sub GetColumnValuesAsColumnMatrix {
 772   my($This, $ColIndex) = @_;
 773 
 774   return $This->_GetRowOrColumnValues('AsColumnMatrix', 'FromColumn', $ColIndex);
 775 }
 776 
 777 # Get values of a column in matrix as a space delimited string...
 778 #
 779 sub GetColumnValuesAsString {
 780   my($This, $ColIndex) = @_;
 781 
 782   return $This->_GetRowOrColumnValues('AsString', 'FromColumn', $ColIndex);
 783 }
 784 
 785 # Get row or column values...
 786 #
 787 sub _GetRowOrColumnValues {
 788   my($This, $Mode, $ValueMode, $ValueModeIndex) = @_;
 789 
 790   if ($Mode !~ /^(AsArray|AsVector|AsRowMatrix|AsColumnMatrix|AsString)$/i) {
 791     croak "Error: ${ClassName}->_GetRowOrColumnValues: Unknown mode, $Mode, specified...";
 792   }
 793   if ($ValueMode !~ /^(FromRow|FromColumn)$/i) {
 794     croak "Error: ${ClassName}->_GetRowOrColumnValues: Unknown value mode, $ValueMode, specified...";
 795   }
 796 
 797   # Setup error message prefix...
 798   my($ErrorMsgPrefix);
 799 
 800   $ErrorMsgPrefix = "${ClassName}->_GetRowOrColumnValues";
 801   if ($ValueMode =~ /^FromRow$/i) {
 802     $ErrorMsgPrefix = "Error: ${ClassName}->GetRowValues${Mode}";
 803   }
 804   elsif ($ValueMode =~ /^FromColumn$/i) {
 805     $ErrorMsgPrefix = "Error: ${ClassName}->GetColumnValues${Mode}";
 806   }
 807 
 808   # Validate specified index and collect values...
 809   my($NumOfRows, $NumOfCols, $RowIndex, $ColIndex, @Values);
 810 
 811   @Values  = ();
 812   ($NumOfRows, $NumOfCols) = $This->GetSize();
 813 
 814   if ($ValueMode =~ /^FromRow$/i) {
 815     $RowIndex = $ValueModeIndex;
 816     $This->_ValidateRowIndex($ErrorMsgPrefix, $RowIndex);
 817 
 818     for $ColIndex (0 .. ($NumOfCols - 1)) {
 819       push @Values, $This->{Values}[$RowIndex][$ColIndex];
 820     }
 821   }
 822   elsif ($ValueMode =~ /^FromColumn$/i) {
 823     $ColIndex = $ValueModeIndex;
 824     $This->_ValidateColumnIndex($ErrorMsgPrefix, $ColIndex);
 825 
 826     for $RowIndex (0 .. ($NumOfRows - 1)) {
 827       push @Values, $This->{Values}[$RowIndex][$ColIndex];
 828     }
 829   }
 830 
 831   # Return values...
 832   if ($Mode =~ /^AsRowMatrix$/i) {
 833     return NewFromRows(\@Values);
 834   }
 835   elsif ($Mode =~ /^AsColumnMatrix$/i) {
 836     return NewFromColumns(\@Values);
 837   }
 838   elsif ($Mode =~ /^AsVector$/i) {
 839     return new Vector(@Values);
 840   }
 841   elsif ($Mode =~ /^AsString$/i) {
 842     return join(' ', @Values);
 843   }
 844   else {
 845     return wantarray ? @Values : scalar @Values;
 846   }
 847 }
 848 
 849 # Set values of the diagonal in a square matrix...
 850 #
 851 sub SetDiagonalValues {
 852   my($This, @SpecifiedDiagonalValues) = @_;
 853   my($ErrorMsgPrefix, $NumOfRows, $NumOfCols, $RowIndex, $CheckSizes, $CombineValues, $ValuesRefs, $NumOfDiagonalValues, $DiagonalValuesRef);
 854 
 855   $ErrorMsgPrefix = "Error: ${ClassName}->SetDiagonalValues";
 856   if (!@SpecifiedDiagonalValues) {
 857     croak "$ErrorMsgPrefix: No diagonal values specified...";
 858   }
 859 
 860   ($NumOfRows, $NumOfCols) = $This->GetSize();
 861   if ($NumOfRows != $NumOfCols) {
 862     croak "Error: $ErrorMsgPrefix: Specified matrix, $NumOfRows x $NumOfCols, is not a square matrix...";
 863   }
 864 
 865   # Collect specified diagonal values...
 866   $CheckSizes = 0; $CombineValues = 1;
 867   $ValuesRefs = _ProcessSpecifiedMatrixValues($ErrorMsgPrefix, $CheckSizes, $CombineValues, @SpecifiedDiagonalValues);
 868   $DiagonalValuesRef = $ValuesRefs->[0];
 869   $NumOfDiagonalValues = @{$DiagonalValuesRef};
 870 
 871   if ($NumOfDiagonalValues != $NumOfRows) {
 872     croak "Error: $ErrorMsgPrefix: Number of specified diagonal values, $NumOfDiagonalValues, must be equal to number of rows, $NumOfRows, in square matrix...";
 873   }
 874 
 875   # Set diagonal values...
 876   for $RowIndex (0 .. ($NumOfRows - 1)) {
 877     $This->{Values}[$RowIndex][$RowIndex] = $DiagonalValuesRef->[$RowIndex];
 878   }
 879 
 880   return $This;
 881 }
 882 
 883 # Get values of the diagonal in a square matrix as an array. In scalar context, number of
 884 # diagonal values is returned...
 885 #
 886 sub GetDiagonalValues {
 887   my($This) = @_;
 888 
 889   return $This->_GetDiagonalValues('AsArray');
 890 }
 891 
 892 # Get values of the diagonal in a square matrix as vector object...
 893 #
 894 sub GetDiagonalValuesAsVector {
 895   my($This) = @_;
 896 
 897   return $This->_GetDiagonalValues('AsVector');
 898 }
 899 
 900 # Get values of the diagonal in a square matrix as row matrix object
 901 #
 902 sub GetDiagonalValuesAsRowMatrix {
 903   my($This) = @_;
 904 
 905   return $This->_GetDiagonalValues('AsRowMatrix');
 906 }
 907 
 908 # Get values of the diagonal in a square matrix as column matrix object
 909 #
 910 sub GetDiagonalValuesAsColumnMatrix {
 911   my($This) = @_;
 912 
 913   return $This->_GetDiagonalValues('AsColumnMatrix');
 914 }
 915 
 916 # Get values of the diagonal in a square matrix as a space delimited string...
 917 #
 918 sub GetDiagonalValuesAsString {
 919   my($This) = @_;
 920 
 921   return $This->_GetDiagonalValues('AsString');
 922 }
 923 
 924 # Get diagonal values...
 925 sub _GetDiagonalValues {
 926   my($This, $Mode) = @_;
 927 
 928   if ($Mode !~ /^(AsArray|AsVector|AsRowMatrix|AsColumnMatrix|AsString)$/i) {
 929     croak "Error: ${ClassName}->_GetDiagonalValues: Unknown mode, $Mode, specified...";
 930   }
 931 
 932   # Make sure it's a square matrix...
 933   my($NumOfRows, $NumOfCols, $ErrorMsgPrefix);
 934 
 935   $ErrorMsgPrefix = "${ClassName}->_GetDiagonalValues${Mode}";
 936   ($NumOfRows, $NumOfCols) = $This->GetSize();
 937   if ($NumOfRows != $NumOfCols) {
 938     croak "Error: $ErrorMsgPrefix: Specified matrix, $NumOfRows x $NumOfCols, is not a square matrix...";
 939   }
 940 
 941   # Collect values...
 942   my($RowIndex, @Values);
 943   @Values = ();
 944 
 945   for $RowIndex (0 .. ($NumOfRows - 1)) {
 946     push @Values, $This->{Values}[$RowIndex][$RowIndex];
 947   }
 948 
 949   # Return values...
 950   if ($Mode =~ /^AsRowMatrix$/i) {
 951     return NewFromRows(\@Values);
 952   }
 953   elsif ($Mode =~ /^AsColumnMatrix$/i) {
 954     return NewFromColumns(\@Values);
 955   }
 956   elsif ($Mode =~ /^AsVector$/i) {
 957     return new Vector(@Values);
 958   }
 959   elsif ($Mode =~ /^AsString$/i) {
 960     return join(' ', @Values);
 961   }
 962   else {
 963     return wantarray ? @Values : scalar @Values;
 964   }
 965 }
 966 
 967 # Is it a square matrix?
 968 #
 969 sub IsSquare {
 970   my($This) = @_;
 971   my($NumOfRows, $NumOfCols) = $This->GetSize();
 972 
 973   return ($NumOfRows == $NumOfCols) ? 1 : 0;
 974 }
 975 
 976 # Is it a unit matrix?
 977 #
 978 # A matrix is a unit matrix:
 979 #   o It's a square matrix
 980 #   o All its diagonal elements are ones and its off-diagonal elements are zeros
 981 #
 982 sub IsUnit {
 983   my($This) = @_;
 984 
 985   # Is is a square matrix?
 986   if (!$This->IsSquare()) {
 987     return 0;
 988   }
 989 
 990   # Check matrix values...
 991   my($NumOfRows, $NumOfCols, $RowIndex, $ColIndex, $ExpectedValue);
 992   ($NumOfRows, $NumOfCols) = $This->GetSize();
 993 
 994   for $RowIndex (0 .. ($NumOfRows - 1)) {
 995     for $ColIndex (0 .. ($NumOfCols - 1)) {
 996       $ExpectedValue = ($RowIndex == $ColIndex) ? 1.0 : 0.0;
 997       if ($This->{Values}[$RowIndex][$ColIndex] != $ExpectedValue) {
 998         return 0;
 999       }
1000     }
1001   }
1002   return 1;
1003 }
1004 
1005 # Is it an identity matrix?
1006 #
1007 sub IsIdentity {
1008   my($This) = @_;
1009 
1010   return $This->IsUnit();
1011 }
1012 
1013 # Is it a diagonal matrix?
1014 #
1015 # A matrix is a diagonal matrix:
1016 #   o It's a square matrix
1017 #   o All its off-diagonal elements are zeros and its diagonal elements may or may not
1018 #     be zeros
1019 #
1020 #
1021 sub IsDiagonal {
1022   my($This) = @_;
1023 
1024   # Is is a square matrix?
1025   if (!$This->IsSquare()) {
1026     return 0;
1027   }
1028 
1029   # Check off-diagonal matrix values...
1030   my($NumOfRows, $NumOfCols, $RowIndex, $ColIndex);
1031   ($NumOfRows, $NumOfCols) = $This->GetSize();
1032 
1033   for $RowIndex (0 .. ($NumOfRows - 1)) {
1034     COLINDEX: for $ColIndex (0 .. ($NumOfCols - 1)) {
1035       if ($RowIndex == $ColIndex) {
1036         next COLINDEX;
1037       }
1038       if ($This->{Values}[$RowIndex][$ColIndex] != 0.0) {
1039         return 0;
1040       }
1041     }
1042   }
1043   return 1;
1044 }
1045 
1046 # Is it a lower bidiagonal matrix?
1047 #
1048 # A matrix is a lower bidiagonal matrix:
1049 #   o It's a square matrix
1050 #   o All its main diagonal and lower diagonal elements are non-zeros and all its
1051 #     other elements are zeros
1052 #
1053 sub IsLowerBiDiagonal {
1054   my($This) = @_;
1055 
1056   # Is is a square matrix?
1057   if (!$This->IsSquare()) {
1058     return 0;
1059   }
1060 
1061   # Check matrix values...
1062   my($NumOfRows, $NumOfCols, $RowIndex, $ColIndex, $Value);
1063   ($NumOfRows, $NumOfCols) = $This->GetSize();
1064 
1065   for $RowIndex (0 .. ($NumOfRows - 1)) {
1066     for $ColIndex (0 .. ($NumOfCols - 1)) {
1067       $Value = $This->{Values}[$RowIndex][$ColIndex];
1068       if ($RowIndex == $ColIndex) {
1069         # Main diagonal...
1070         if ($Value == 0.0) {
1071           return 0;
1072         }
1073       }
1074       elsif ($RowIndex == ($ColIndex + 1)) {
1075         # Lower diagonal...
1076         if ($Value == 0.0) {
1077           return 0;
1078         }
1079       }
1080       else {
1081         # Other elements...
1082         if ($Value != 0.0) {
1083           return 0;
1084         }
1085       }
1086     }
1087   }
1088   return 1;
1089 }
1090 
1091 # Is it an upper bidiagonal matrix?
1092 #
1093 # A matrix is an upper bidiagonal matrix:
1094 #   o It's a square matrix
1095 #   o All its main diagonal and upper diagonal elements are non-zeros and all its
1096 #     other elements are zeros
1097 #
1098 sub IsUpperBiDiagonal {
1099   my($This) = @_;
1100 
1101   # Is is a square matrix?
1102   if (!$This->IsSquare()) {
1103     return 0;
1104   }
1105   # Check matrix values...
1106   my($NumOfRows, $NumOfCols, $RowIndex, $ColIndex, $Value);
1107   ($NumOfRows, $NumOfCols) = $This->GetSize();
1108 
1109   for $RowIndex (0 .. ($NumOfRows - 1)) {
1110     for $ColIndex (0 .. ($NumOfCols - 1)) {
1111       $Value = $This->{Values}[$RowIndex][$ColIndex];
1112       if ($RowIndex == $ColIndex) {
1113         # Main diagonal...
1114         if ($Value == 0.0) {
1115           return 0;
1116         }
1117       }
1118       elsif ($RowIndex == ($ColIndex - 1)) {
1119         # Upper diagonal...
1120         if ($Value == 0.0) {
1121           return 0;
1122         }
1123       }
1124       else {
1125         # Other elements...
1126         if ($Value != 0.0) {
1127           return 0;
1128         }
1129       }
1130     }
1131   }
1132   return 1;
1133 }
1134 
1135 # Is it a bidiagonal matrix?
1136 #
1137 # A matrix is a bidiagonal matrix:
1138 #
1139 sub IsBiDiagonal {
1140   my($This) = @_;
1141 
1142   return ($This->IsUpperBiDiagonal() || $This->IsLowerBiDiagonal()) ? 1 : 0;
1143 }
1144 
1145 # Is it a tridiagonal matrix?
1146 #
1147 # A matrix is a  tribidiagonal matrix:
1148 #   o It's a square matrix
1149 #   o All its main diagonal, upper diagonal, and lower diagonal elements are non-zeros and all its
1150 #     other elements are zeros
1151 #
1152 #
1153 sub IsTriDiagonal {
1154   my($This) = @_;
1155 
1156   # Is is a square matrix?
1157   if (!$This->IsSquare()) {
1158     return 0;
1159   }
1160 
1161   # Check matrix values...
1162   my($NumOfRows, $NumOfCols, $RowIndex, $ColIndex, $Value);
1163   ($NumOfRows, $NumOfCols) = $This->GetSize();
1164 
1165   for $RowIndex (0 .. ($NumOfRows - 1)) {
1166     for $ColIndex (0 .. ($NumOfCols - 1)) {
1167       $Value = $This->{Values}[$RowIndex][$ColIndex];
1168       if ($RowIndex == $ColIndex) {
1169         # Main diagonal...
1170         if ($Value == 0.0) {
1171           return 0;
1172         }
1173       }
1174       elsif ($RowIndex == ($ColIndex - 1)) {
1175         # Upper diagonal...
1176         if ($Value == 0.0) {
1177           return 0;
1178         }
1179       }
1180       elsif ($RowIndex == ($ColIndex + 1)) {
1181         # Lower diagonal...
1182         if ($Value == 0.0) {
1183           return 0;
1184         }
1185       }
1186       else {
1187         # Other elements...
1188         if ($Value != 0.0) {
1189           return 0;
1190         }
1191       }
1192     }
1193   }
1194   return 1;
1195 }
1196 
1197 # Is it a lower triangular matrix?
1198 #
1199 # A matrix is a lower triangular matrix:
1200 #   o It's a square matrix
1201 #   o All its entries above the main diagonal are zero
1202 #
1203 sub IsLowerTriangular {
1204   my($This) = @_;
1205 
1206   return $This->_IsLowerTriangularMatrix();
1207 }
1208 
1209 # Is it a left triangular matrix?
1210 #
1211 # A matrix is a left triangular matrix:
1212 #   o It's a square matrix
1213 #   o All its entries above the main diagonal are zero
1214 #
1215 sub IsLeftTriangular {
1216   my($This) = @_;
1217 
1218   return $This->IsLowerTriangular();
1219 }
1220 
1221 # Is it a strictly lower triangular matrix?
1222 #
1223 # A matrix is a strictly lower triangular matrix:
1224 #   o It's a square matrix
1225 #   o All its entries on and above the main diagonal are zero
1226 #
1227 sub IsStrictlyLowerTriangular {
1228   my($This) = @_;
1229   my($DiagonalValue);
1230 
1231   $DiagonalValue = 0;
1232 
1233   return $This->_IsLowerTriangularMatrix($DiagonalValue);
1234 }
1235 
1236 # Is it an unit lower triangular matrix?
1237 #
1238 # A matrix is an unit lower triangular matrix:
1239 #   o It's a square matrix
1240 #   o All its entries main diagonal are one
1241 #   o All its entries above the main diagonal are zero
1242 #
1243 sub IsUnitLowerTriangular {
1244   my($This) = @_;
1245   my($DiagonalValue);
1246 
1247   $DiagonalValue = 1;
1248 
1249   return $This->_IsLowerTriangularMatrix($DiagonalValue);
1250 }
1251 
1252 # Is it a lower unitriangular matrix?
1253 #
1254 sub IsLowerUniTriangular {
1255   my($This) = @_;
1256 
1257   return $This->IsUnitLowerTriangular();
1258 }
1259 
1260 # Is it a lower triangular, strictly lower triangular, or unit lower triangular matrix?
1261 #
1262 sub _IsLowerTriangularMatrix {
1263   my($This, $DiagonalValue) = @_;
1264 
1265   # Is is a square matrix?
1266   if (!$This->IsSquare()) {
1267     return 0;
1268   }
1269   # Check matrix values...
1270   my($NumOfRows, $NumOfCols, $RowIndex, $ColIndex, $CheckDiagonalValues);
1271 
1272   $CheckDiagonalValues = defined($DiagonalValue) ? 1 : 0;
1273   ($NumOfRows, $NumOfCols) = $This->GetSize();
1274 
1275   for $RowIndex (0 .. ($NumOfRows - 1)) {
1276     for $ColIndex (0 .. ($NumOfCols - 1)) {
1277       if ($CheckDiagonalValues && $RowIndex == $ColIndex) {
1278         # Main diagonal...
1279         if ($This->{Values}[$RowIndex][$ColIndex] != $DiagonalValue) {
1280           return 0;
1281         }
1282       }
1283       elsif ($RowIndex < $ColIndex) {
1284         # Elemens above the main diagonal...
1285         if ($This->{Values}[$RowIndex][$ColIndex] != 0.0) {
1286           return 0;
1287         }
1288       }
1289     }
1290   }
1291   return 1;
1292 }
1293 
1294 # Is it an upper triangular matrix?
1295 #
1296 # A matrix is an upper triangular matrix:
1297 #   o It's a square matrix
1298 #   o All its entries below the main diagonal are zero
1299 #
1300 sub IsUpperTriangular {
1301   my($This) = @_;
1302 
1303   return $This->_IsUpperTriangularMatrix();
1304 }
1305 
1306 # Is it a right triangular matrix?
1307 #
1308 # A matrix is a right triangular matrix:
1309 #   o It's a square matrix
1310 #   o All its entries below the main diagonal are zero
1311 #
1312 sub IsRightTriangular {
1313   my($This) = @_;
1314 
1315   return $This->IsUpperTriangular();
1316 }
1317 
1318 # Is it a strictly upper triangular matrix?
1319 #
1320 # A matrix is a strictly upper triangular matrix:
1321 #   o It's a square matrix
1322 #   o All its entries on and below the main diagonal are zero
1323 #
1324 sub IsStrictlyUpperTriangular {
1325   my($This) = @_;
1326   my($DiagonalValue);
1327 
1328   $DiagonalValue = 0;
1329 
1330   return $This->_IsUpperTriangularMatrix($DiagonalValue);
1331 }
1332 
1333 # Is it a unit upper triangular matrix?
1334 #
1335 # A matrix is an unit upper triangular matrix:
1336 #   o It's a square matrix
1337 #   o All its entries main diagonal are one
1338 #   o All its entries below the main diagonal are zero
1339 #
1340 sub IsUnitUpperTriangular {
1341   my($This) = @_;
1342   my($DiagonalValue);
1343 
1344   $DiagonalValue = 1;
1345 
1346   return $This->_IsUpperTriangularMatrix($DiagonalValue);
1347 }
1348 
1349 # Is it a upper unitriangular matrix?
1350 #
1351 sub IsUpperUniTriangular {
1352   my($This) = @_;
1353 
1354   return $This->IsUnitUpperTriangular();
1355 }
1356 
1357 # Is it an upper triangular, strictly upper triangular, or unit upper triangular matrix?
1358 #
1359 sub _IsUpperTriangularMatrix {
1360   my($This, $DiagonalValue) = @_;
1361 
1362   # Is is a square matrix?
1363   if (!$This->IsSquare()) {
1364     return 0;
1365   }
1366   # Check matrix values...
1367   my($NumOfRows, $NumOfCols, $RowIndex, $ColIndex, $CheckDiagonalValues);
1368 
1369   $CheckDiagonalValues = defined($DiagonalValue) ? 1 : 0;
1370   ($NumOfRows, $NumOfCols) = $This->GetSize();
1371 
1372   for $RowIndex (0 .. ($NumOfRows - 1)) {
1373     for $ColIndex (0 .. ($NumOfCols - 1)) {
1374       if ($CheckDiagonalValues && $RowIndex == $ColIndex) {
1375         # Main diagonal...
1376         if ($This->{Values}[$RowIndex][$ColIndex] != $DiagonalValue) {
1377           return 0;
1378         }
1379       }
1380       elsif ($RowIndex > $ColIndex) {
1381         # Elemens below the main diagonal...
1382         if ($This->{Values}[$RowIndex][$ColIndex] != 0.0) {
1383           return 0;
1384         }
1385       }
1386     }
1387   }
1388   return 1;
1389 }
1390 
1391 # Is it a symmetrix matrix?
1392 #
1393 # A matrix is a symmetric matrix:
1394 #   o It's a square matrix
1395 #   o Its elements are symmetric with respect to main diagonal. In other words,
1396 #     elements below the main diagonal are equal to the elements above the main
1397 #     diagonal.
1398 #
1399 # Transpose of a symmetric matrix equals the matrix itself.
1400 #
1401 sub IsSymmetric {
1402   my($This) = @_;
1403 
1404   # Is is a square matrix?
1405   if (!$This->IsSquare()) {
1406     return 0;
1407   }
1408 
1409   my($NumOfRows, $NumOfCols, $RowIndex, $ColIndex);
1410   ($NumOfRows, $NumOfCols) = $This->GetSize();
1411 
1412   for $RowIndex (0 .. ($NumOfRows - 1)) {
1413     for $ColIndex (0 .. ($RowIndex - 1)) {
1414       if ($This->{Values}[$RowIndex][$ColIndex] != $This->{Values}[$ColIndex][$RowIndex]) {
1415         return 0;
1416       }
1417     }
1418   }
1419   return 1;
1420 }
1421 
1422 # Is it a anti symmetrix matrix?
1423 #
1424 # A matrix is an anti symmetric matrix:
1425 #   o It's a square matrix
1426 #   o Its elements are asymmetric with respect to main diagonal. In other words,
1427 #     elements below the main diagonal are equal to the negative of elements above
1428 #     the main diagonal.
1429 #
1430 # Transpose of a anti symmetric matrix equals the negative of the matrix.
1431 #
1432 sub IsAntiSymmetric {
1433   my($This) = @_;
1434 
1435   # Is is a square matrix?
1436   if (!$This->IsSquare()) {
1437     return 0;
1438   }
1439 
1440   my($NumOfRows, $NumOfCols, $RowIndex, $ColIndex);
1441   ($NumOfRows, $NumOfCols) = $This->GetSize();
1442 
1443   for $RowIndex (0 .. ($NumOfRows - 1)) {
1444     for $ColIndex (0 .. ($RowIndex - 1)) {
1445       if ($This->{Values}[$RowIndex][$ColIndex] != -$This->{Values}[$ColIndex][$RowIndex]) {
1446         return 0;
1447       }
1448     }
1449   }
1450   return 1;
1451 }
1452 
1453 # Is it a skew symmetrix matrix?
1454 #
1455 # It's another name for AnitSymmetricMatrix.
1456 #
1457 sub IsSkewSymmetric {
1458   my($This) = @_;
1459 
1460   return $This->IsAntiSymmetric();
1461 }
1462 
1463 # Is it a positive matrix with all its values >= zero?
1464 #
1465 sub IsPositive {
1466   my($This) = @_;
1467 
1468   # Check matrix values...
1469   my($NumOfRows, $NumOfCols, $RowIndex, $ColIndex);
1470   ($NumOfRows, $NumOfCols) = $This->GetSize();
1471 
1472   for $RowIndex (0 .. ($NumOfRows - 1)) {
1473     for $ColIndex (0 .. ($NumOfCols - 1)) {
1474       if ($This->{Values}[$RowIndex][$ColIndex] < 0.0) {
1475         return 0;
1476       }
1477     }
1478   }
1479   return 1;
1480 }
1481 
1482 # Is it a positive matrix with all its values <= zero?
1483 #
1484 sub IsNegative {
1485   my($This) = @_;
1486 
1487   return $This->IsPositive() ? 0 : 1;
1488 }
1489 
1490 # Transpose the matrix by swaping rows with columns...
1491 #
1492 sub Transpose {
1493   my($This) = @_;
1494   my($Matrix, $NumOfRows, $NumOfCols, $RowIndex, $ColIndex);
1495 
1496   # Create the transpose matrix of size $NumOfCols x $NumOfRows
1497   #
1498   ($NumOfRows, $NumOfCols) = $This->GetSize();
1499   $Matrix = new Matrix($NumOfCols, $NumOfRows);
1500 
1501   # Swap rows and columns...
1502   for $RowIndex (0 .. ($NumOfCols - 1)) {
1503     for $ColIndex (0 .. ($NumOfRows - 1)) {
1504       $Matrix->{Values}[$RowIndex][$ColIndex] = $This->{Values}[$ColIndex][$RowIndex];
1505     }
1506   }
1507   return $Matrix;
1508 }
1509 
1510 # Is it a matrix object?
1511 sub IsMatrix ($) {
1512   my($Object) = @_;
1513 
1514   return _IsMatrix($Object);
1515 }
1516 
1517 # Set value print format for an individual object or the whole class during StringifyMatrix operation...
1518 sub SetValuePrintFormat ($;$) {
1519   my($FirstParameter, $SecondParameter) = @_;
1520 
1521   if ((@_ == 2) && (_IsMatrix($FirstParameter))) {
1522     # Set value print format for the specific object...
1523     my($This, $ValuePrintFormat) = ($FirstParameter, $SecondParameter);
1524 
1525     $This->{ValueFormat} = $ValuePrintFormat;
1526   }
1527   else {
1528     # Set value print format for the class...
1529     my($ValuePrintFormat) = ($FirstParameter);
1530 
1531     $ValueFormat = $ValuePrintFormat;
1532   }
1533 }
1534 
1535 # Set print style for matrix rows for an individual object or the whole class during StringifyMatrix
1536 # operation.
1537 #
1538 # Possible values: AllRowsInOneLine, OneRowPerLine. Default: AllRowsInOneLine
1539 #
1540 sub SetMatrixPrintStyle ($;$) {
1541   my($FirstParameter, $SecondParameter) = @_;
1542 
1543   if ((@_ == 2) && (_IsMatrix($FirstParameter))) {
1544     # Set value print format for the specific object...
1545     my($This, $MatrixPrintStyleValue) = ($FirstParameter, $SecondParameter);
1546 
1547     if ($MatrixPrintStyleValue !~ /^(AllRowsInOneLine|OneRowPerLine)$/i) {
1548       croak "Error: ${ClassName}->SetMatrixPrintStyle: Specified MatrixPrintStyle, $MatrixPrintStyleValue, is not valid. Supported values: AllRowsInOneLine, OneRowPerLine...";
1549     }
1550 
1551     $This->{MatrixPrintStyle} = $MatrixPrintStyleValue;
1552   }
1553   else {
1554     # Set value print format for the class...
1555     my($MatrixPrintStyleValue) = ($FirstParameter);
1556 
1557     if ($MatrixPrintStyleValue !~ /^(AllRowsInOneLine|OneRowPerLine)$/i) {
1558       croak "Error: ${ClassName}::SetMatrixPrintStyle: Specified MatrixPrintStyle, $MatrixPrintStyleValue, is not valid. Supported values: AllRowsInOneLine, OneRowPerLine...";
1559     }
1560 
1561     $MatrixPrintStyle = $MatrixPrintStyleValue;
1562   }
1563 }
1564 
1565 # Is it a matrix object?
1566 #
1567 sub _IsMatrix {
1568   my($Object) = @_;
1569 
1570   return (Scalar::Util::blessed($Object) && $Object->isa($ClassName)) ? 1 : 0;
1571 }
1572 
1573 # Make sure it's a matrix reference...
1574 #
1575 sub _ValidateMatrix {
1576   my($ErrorMsg, $Matrix) = @_;
1577 
1578   if (!_IsMatrix($Matrix)) {
1579     croak "Error: ${ClassName}->${ErrorMsg}: Object must be a matrix...";
1580   }
1581 }
1582 
1583 # Make sure both row and column indicies are valid...
1584 #
1585 sub _ValidateRowAndColumnIndicies {
1586   my($This, $ErrorMsgPrefix, $RowIndex, $ColumnIndex) = @_;
1587 
1588   $This->_ValidateRowIndex($ErrorMsgPrefix, $RowIndex);
1589   $This->_ValidateColumnIndex($ErrorMsgPrefix, $ColumnIndex);
1590 
1591   return $This;
1592 }
1593 
1594 # Make sure it's a valid row index...
1595 #
1596 sub _ValidateRowIndex {
1597   my($This, $ErrorMsgPrefix, $RowIndex) = @_;
1598   my($NumOfRows);
1599 
1600   if (!defined $RowIndex) {
1601     croak "$ErrorMsgPrefix: RowIndex must be defined...";
1602   }
1603   $NumOfRows = $This->GetNumOfRows();
1604   if ($RowIndex < 0 || $RowIndex >= $NumOfRows) {
1605     croak "$ErrorMsgPrefix: RowIndex value $RowIndex must be >= 0 and < $NumOfRows, NumOfRows, in matrix...";
1606   }
1607   return $This;
1608 }
1609 
1610 # Make sure it's a valid column index...
1611 #
1612 sub _ValidateColumnIndex {
1613   my($This, $ErrorMsgPrefix, $ColIndex) = @_;
1614   my($NumOfCols);
1615 
1616   if (!defined $ColIndex) {
1617     croak "$ErrorMsgPrefix: ColIndex must be defined...";
1618   }
1619   $NumOfCols = $This->GetNumOfColumns();
1620   if ($ColIndex < 0 || $ColIndex >= $NumOfCols) {
1621     croak "$ErrorMsgPrefix: ColIndex value $ColIndex must be >= 0 and < $NumOfCols, NumOfCols, in matrix...";
1622   }
1623   return $This;
1624 }
1625 
1626 #
1627 # Matrix addition operator supports two addition modes:
1628 #   . Addition of two matrices by adding corresponding matrix values
1629 #   . Addition of a scalar value to matrix values ($Matrix + 1)
1630 #
1631 # Caveats:
1632 #   . Addition of a matrix to scalar is not allowed (1 + $Matrix)
1633 #
1634 sub _MatrixAdditionOperator {
1635   my($This, $Other, $OrderFlipped, $OtherIsMatrix, $ErrorMsg);
1636 
1637   $ErrorMsg = "_MatrixAdditionOperator: Matrix addition failed";
1638   ($This, $Other, $OrderFlipped, $OtherIsMatrix) = _ProcessOverloadedOperatorParameters($ErrorMsg, @_);
1639 
1640   my($Matrix, $NumOfRows, $NumOfCols, $RowIndex, $ColIndex);
1641 
1642   ($NumOfRows, $NumOfCols) = $This->GetSize();
1643   $Matrix = new Matrix($NumOfRows, $NumOfCols);
1644 
1645   if ($OtherIsMatrix) {
1646     # $OrderFlipped is set to false for two matrices...
1647     for $RowIndex (0 .. ($NumOfRows - 1)) {
1648       for $ColIndex (0 .. ($NumOfCols - 1)) {
1649         $Matrix->{Values}[$RowIndex][$ColIndex] = $This->{Values}[$RowIndex][$ColIndex] + $Other->{Values}[$RowIndex][$ColIndex];
1650       }
1651     }
1652   }
1653   else {
1654     # Scalar addition...
1655     if ($OrderFlipped) {
1656       croak "Error: ${ClassName}->${ErrorMsg}: First object must be a matrix...";
1657     }
1658     for $RowIndex (0 .. ($NumOfRows - 1)) {
1659       for $ColIndex (0 .. ($NumOfCols - 1)) {
1660         $Matrix->{Values}[$RowIndex][$ColIndex] = $This->{Values}[$RowIndex][$ColIndex] + $Other;
1661       }
1662     }
1663   }
1664   return $Matrix;
1665 }
1666 
1667 #
1668 # Matrix subtraction operator supports two subtraction modes:
1669 #   . Subtraction of two matrices by subtracting corresponding matrix values
1670 #   . Subtraction of a scalar value from matrix values ($Matrix - 1)
1671 #
1672 # Caveats:
1673 #   . Subtraction of a matrix from scalar is not allowed (1 - $Matrix)
1674 #
1675 sub _MatrixSubtractionOperator {
1676   my($This, $Other, $OrderFlipped, $OtherIsMatrix, $ErrorMsg);
1677 
1678   $ErrorMsg = "_MatrixSubtractionOperator: Matrix subtraction failed";
1679   ($This, $Other, $OrderFlipped, $OtherIsMatrix) = _ProcessOverloadedOperatorParameters($ErrorMsg, @_);
1680 
1681   my($Matrix, $NumOfRows, $NumOfCols, $RowIndex, $ColIndex);
1682 
1683   ($NumOfRows, $NumOfCols) = $This->GetSize();
1684   $Matrix = new Matrix($NumOfRows, $NumOfCols);
1685 
1686   if ($OtherIsMatrix) {
1687     # $OrderFlipped is set to false for two matrices...
1688     for $RowIndex (0 .. ($NumOfRows - 1)) {
1689       for $ColIndex (0 .. ($NumOfCols - 1)) {
1690         $Matrix->{Values}[$RowIndex][$ColIndex] = $This->{Values}[$RowIndex][$ColIndex] - $Other->{Values}[$RowIndex][$ColIndex];
1691       }
1692     }
1693   }
1694   else {
1695     # Scalar subtraction...
1696     if ($OrderFlipped) {
1697       croak "Error: ${ClassName}->${ErrorMsg}: First object must be a matrix...";
1698     }
1699     for $RowIndex (0 .. ($NumOfRows - 1)) {
1700       for $ColIndex (0 .. ($NumOfCols - 1)) {
1701         $Matrix->{Values}[$RowIndex][$ColIndex] = $This->{Values}[$RowIndex][$ColIndex] - $Other;
1702       }
1703     }
1704   }
1705   return $Matrix;
1706 }
1707 
1708 #
1709 # Matrix multiplication operator supports two multiplication modes:
1710 #   . Multiplication of two matrices
1711 #   . Multiplication of matrix values by a scalar ($Matrix * 1)
1712 #
1713 # Caveats:
1714 #   . Multiplication of a scalar by a is not allowed (1 * $Matrix)
1715 #
1716 sub _MatrixMultiplicationOperator {
1717   my($This, $Other, $OrderFlipped, $OtherIsMatrix, $ErrorMsg, $CheckSizes);
1718 
1719   $ErrorMsg = "_MatrixMultiplicationOperator: Matrix multiplication failed";
1720   $CheckSizes = 0;
1721   ($This, $Other, $OrderFlipped, $OtherIsMatrix) = _ProcessOverloadedOperatorParameters($ErrorMsg, @_, $CheckSizes);
1722 
1723   my($Matrix);
1724 
1725   if ($OtherIsMatrix) {
1726     # $OrderFlipped is set to false for two matrices...
1727     my($NumOfRows1, $NumOfCols1, $RowIndex1, $ColIndex1, $NumOfRows2, $NumOfCols2, $ColIndex2, $Value, $RowColIndex);
1728 
1729     ($NumOfRows1, $NumOfCols1) = $This->GetSize();
1730     ($NumOfRows2, $NumOfCols2) = $Other->GetSize();
1731 
1732     if ($NumOfCols1 != $NumOfRows2) {
1733       croak "Error: ${ClassName}->${ErrorMsg}: NumOfCols in first matrix of size $NumOfRows1 x $NumOfCols1 must be equal to NumOfRows in second matrix of size $NumOfRows2 x $NumOfCols2...";
1734     }
1735 
1736     $Matrix = new Matrix($NumOfRows1, $NumOfCols2);
1737 
1738     for $RowIndex1 (0 .. ($NumOfRows1 - 1)) {
1739       for $ColIndex2 (0 .. ($NumOfCols2 - 1)) {
1740         $Value = 0;
1741         for $RowColIndex (0 .. ($NumOfCols1 - 1)) {
1742           $Value += $This->{Values}[$RowIndex1][$RowColIndex] * $Other->[$RowColIndex][$ColIndex2];
1743         }
1744         $Matrix->{Values}[$RowIndex1][$ColIndex2] = $Value;
1745       }
1746     }
1747   }
1748   else {
1749     my($NumOfRows, $NumOfCols, $RowIndex, $ColIndex);
1750 
1751     ($NumOfRows, $NumOfCols) = $This->GetSize();
1752     $Matrix = new Matrix($NumOfRows, $NumOfCols);
1753     # Scalar subtraction...
1754     if ($OrderFlipped) {
1755       croak "Error: ${ClassName}->${ErrorMsg}: First object must be a matrix...";
1756     }
1757     for $RowIndex (0 .. ($NumOfRows - 1)) {
1758       for $ColIndex (0 .. ($NumOfCols - 1)) {
1759         $Matrix->{Values}[$RowIndex][$ColIndex] = $This->{Values}[$RowIndex][$ColIndex] * $Other;
1760       }
1761     }
1762   }
1763   return $Matrix;
1764 }
1765 
1766 #
1767 # Matrix division operator supports two division modes:
1768 #   . Division of two matrices by dividing corresponding matrix values
1769 #   . Division matrix values  by a scalar($Matrix/2)
1770 #
1771 # Caveats:
1772 #   . Division of scalar value by a matrix is not allowed (2/$Matrix)
1773 #
1774 sub _MatrixDivisionOperator {
1775   my($This, $Other, $OrderFlipped, $OtherIsMatrix, $ErrorMsg);
1776 
1777   $ErrorMsg = "_MatrixDivisionOperator: Matrix division failed";
1778   ($This, $Other, $OrderFlipped, $OtherIsMatrix) = _ProcessOverloadedOperatorParameters($ErrorMsg, @_);
1779 
1780   my($Matrix, $NumOfRows, $NumOfCols, $RowIndex, $ColIndex);
1781 
1782   ($NumOfRows, $NumOfCols) = $This->GetSize();
1783   $Matrix = new Matrix($NumOfRows, $NumOfCols);
1784 
1785   if ($OtherIsMatrix) {
1786     # $OrderFlipped is set to false for two matrices...
1787     for $RowIndex (0 .. ($NumOfRows - 1)) {
1788       for $ColIndex (0 .. ($NumOfCols - 1)) {
1789         $Matrix->{Values}[$RowIndex][$ColIndex] = $This->{Values}[$RowIndex][$ColIndex] / $Other->{Values}[$RowIndex][$ColIndex];
1790       }
1791     }
1792   }
1793   else {
1794     # Scalar subtraction...
1795     if ($OrderFlipped) {
1796       croak "Error: ${ClassName}->${ErrorMsg}: First object must be a matrix...";
1797     }
1798     for $RowIndex (0 .. ($NumOfRows - 1)) {
1799       for $ColIndex (0 .. ($NumOfCols - 1)) {
1800         $Matrix->{Values}[$RowIndex][$ColIndex] = $This->{Values}[$RowIndex][$ColIndex] / $Other;
1801       }
1802     }
1803   }
1804   return $Matrix;
1805 }
1806 
1807 #
1808 # Matrix exponentiation operator supports two division modes:
1809 #   . Exponent of two matrices by exponentiation of corresponding matrix values
1810 #   . Exponentiation matrix values  by a scalar ($Matrix ** 2)
1811 #
1812 # Caveats:
1813 #   . Exponentiation of scalar value by a matrix is not allowed (2 ** $Matrix)
1814 #
1815 sub _MatrixExponentiationOperator {
1816   my($This, $Other, $OrderFlipped, $OtherIsMatrix, $ErrorMsg);
1817 
1818   $ErrorMsg = "_MatrixExponentiationOperator: Matrix exponentiation failed";
1819   ($This, $Other, $OrderFlipped, $OtherIsMatrix) = _ProcessOverloadedOperatorParameters($ErrorMsg, @_);
1820 
1821   my($Matrix, $NumOfRows, $NumOfCols, $RowIndex, $ColIndex);
1822 
1823   ($NumOfRows, $NumOfCols) = $This->GetSize();
1824   $Matrix = new Matrix($NumOfRows, $NumOfCols);
1825 
1826   if ($OtherIsMatrix) {
1827     # $OrderFlipped is set to false for two matrices...
1828     for $RowIndex (0 .. ($NumOfRows - 1)) {
1829       for $ColIndex (0 .. ($NumOfCols - 1)) {
1830         $Matrix->{Values}[$RowIndex][$ColIndex] = $This->{Values}[$RowIndex][$ColIndex] ** $Other->{Values}[$RowIndex][$ColIndex];
1831       }
1832     }
1833   }
1834   else {
1835     # Scalar subtraction...
1836     if ($OrderFlipped) {
1837       croak "Error: ${ClassName}->${ErrorMsg}: First object must be a matrix...";
1838     }
1839     for $RowIndex (0 .. ($NumOfRows - 1)) {
1840       for $ColIndex (0 .. ($NumOfCols - 1)) {
1841         $Matrix->{Values}[$RowIndex][$ColIndex] = $This->{Values}[$RowIndex][$ColIndex] ** $Other;
1842       }
1843     }
1844   }
1845   return $Matrix;
1846 }
1847 
1848 #
1849 # Matrix modulus operator supports two division modes:
1850 #   . Modulus of two matrices by taking modulus between corresponding matrix values
1851 #   . Modulus of matrix values  by a scalar ($Matrix % 2)
1852 #
1853 # Caveats:
1854 #   . Modulus of scalar value by a matrix is not allowed (2 % $Matrix)
1855 #
1856 sub _MatrixModulusOperator {
1857   my($This, $Other, $OrderFlipped, $OtherIsMatrix, $ErrorMsg);
1858 
1859   $ErrorMsg = "_MatrixModulusOperator: Matrix modulus failed";
1860   ($This, $Other, $OrderFlipped, $OtherIsMatrix) = _ProcessOverloadedOperatorParameters($ErrorMsg, @_);
1861 
1862   my($Matrix, $NumOfRows, $NumOfCols, $RowIndex, $ColIndex);
1863 
1864   ($NumOfRows, $NumOfCols) = $This->GetSize();
1865   $Matrix = new Matrix($NumOfRows, $NumOfCols);
1866 
1867   if ($OtherIsMatrix) {
1868     # $OrderFlipped is set to false for two matrices...
1869     for $RowIndex (0 .. ($NumOfRows - 1)) {
1870       for $ColIndex (0 .. ($NumOfCols - 1)) {
1871         $Matrix->{Values}[$RowIndex][$ColIndex] = $This->{Values}[$RowIndex][$ColIndex] % $Other->{Values}[$RowIndex][$ColIndex];
1872       }
1873     }
1874   }
1875   else {
1876     # Scalar subtraction...
1877     if ($OrderFlipped) {
1878       croak "Error: ${ClassName}->${ErrorMsg}: First object must be a matrix...";
1879     }
1880     for $RowIndex (0 .. ($NumOfRows - 1)) {
1881       for $ColIndex (0 .. ($NumOfCols - 1)) {
1882         $Matrix->{Values}[$RowIndex][$ColIndex] = $This->{Values}[$RowIndex][$ColIndex] % $Other;
1883       }
1884     }
1885   }
1886   return $Matrix;
1887 }
1888 
1889 #
1890 # Matrix booelan operator checks whether a matrix contains at least one non-zero
1891 # value...
1892 #
1893 sub _MatrixBooleanOperator {
1894   my($This, $Other, $OrderFlipped, $OtherIsMatrix, $ErrorMsg);
1895 
1896   $ErrorMsg = "_MatrixBooleanOperator: Matrix boolean operation failed";
1897   ($This, $Other, $OrderFlipped, $OtherIsMatrix) = _ProcessOverloadedOperatorParameters($ErrorMsg, @_);
1898 
1899   my($NumOfRows, $NumOfCols, $RowIndex, $ColIndex);
1900 
1901   ($NumOfRows, $NumOfCols) = $This->GetSize();
1902   for $RowIndex (0 .. ($NumOfRows - 1)) {
1903     for $ColIndex (0 .. ($NumOfCols - 1)) {
1904       if ($This->{Values}[$RowIndex][$ColIndex] != 0.0) {
1905         return 1;
1906       }
1907     }
1908   }
1909   return 0;
1910 }
1911 
1912 #
1913 # Matrix not booelan operator checks whether a matrix contains only zero values...
1914 # value...
1915 #
1916 sub _MatrixNotBooleanOperator {
1917   my($This, $Other, $OrderFlipped, $OtherIsMatrix, $ErrorMsg);
1918 
1919   $ErrorMsg = "_MatrixNotBooleanOperator: Matrix not boolean operation failed";
1920   ($This, $Other, $OrderFlipped, $OtherIsMatrix) = _ProcessOverloadedOperatorParameters($ErrorMsg, @_);
1921 
1922   my($NumOfRows, $NumOfCols, $RowIndex, $ColIndex);
1923 
1924   ($NumOfRows, $NumOfCols) = $This->GetSize();
1925   for $RowIndex (0 .. ($NumOfRows - 1)) {
1926     for $ColIndex (0 .. ($NumOfCols - 1)) {
1927       if ($This->{Values}[$RowIndex][$ColIndex] != 0.0) {
1928         return 0;
1929       }
1930     }
1931   }
1932   return 1;
1933 }
1934 
1935 #
1936 # Matrix equal operator supports two modes:
1937 #   . Comparison of corresponding values in two matrices
1938 #   . Comparing matrix values to a scalar ($Matrix == 2)
1939 #
1940 # Caveats:
1941 #   . Comparison of a scalar to matrix values is not allowed (2 == $Matrix)
1942 #
1943 sub _MatrixEqualOperator {
1944   my($This, $Other, $OrderFlipped, $OtherIsMatrix, $CheckMatrixSizes, $ErrorMsg);
1945 
1946   $ErrorMsg = "_MatrixEqualOperator: Matrix equal failed";
1947   $CheckMatrixSizes = 0;
1948   ($This, $Other, $OrderFlipped, $OtherIsMatrix) = _ProcessOverloadedOperatorParameters($ErrorMsg, @_, $CheckMatrixSizes);
1949 
1950   my($NumOfRows, $NumOfCols, $RowIndex, $ColIndex);
1951 
1952   ($NumOfRows, $NumOfCols) = $This->GetSize();
1953 
1954   if ($OtherIsMatrix) {
1955     # $OrderFlipped is set to false for two matrices...
1956     my($OtherNumOfRows, $OtherNumOfCols);
1957 
1958     # Check sizes...
1959     ($OtherNumOfRows, $OtherNumOfCols) = $Other->GetSize();
1960     if (!($NumOfRows == $OtherNumOfRows && $NumOfCols == $OtherNumOfCols)) {
1961       return 0;
1962     }
1963 
1964     # Check values...
1965     for $RowIndex (0 .. ($NumOfRows - 1)) {
1966       for $ColIndex (0 .. ($NumOfCols - 1)) {
1967         if ($This->{Values}[$RowIndex][$ColIndex] != $Other->{Values}[$RowIndex][$ColIndex]) {
1968           return 0;
1969         }
1970       }
1971     }
1972   }
1973   else {
1974     # Scalar comparison...
1975     if ($OrderFlipped) {
1976       croak "Error: ${ClassName}->${ErrorMsg}: First object must be a matrix...";
1977     }
1978     for $RowIndex (0 .. ($NumOfRows - 1)) {
1979       for $ColIndex (0 .. ($NumOfCols - 1)) {
1980         if ($This->{Values}[$RowIndex][$ColIndex] != $Other) {
1981           return 0;
1982         }
1983       }
1984     }
1985   }
1986   return 1;
1987 }
1988 
1989 #
1990 # Matrix not equal operator supports two modes:
1991 #   . Comparison of corresponding values in two matrices
1992 #   . Comparing matrix values to a scalar ($Matrix != 2)
1993 #
1994 # Caveats:
1995 #   . Comparison of a scalar to matrix values is not allowed (2 != $Matrix)
1996 #
1997 sub _MatrixNotEqualOperator {
1998   my($This, $Other, $OrderFlipped, $OtherIsMatrix, $CheckMatrixSizes, $ErrorMsg);
1999 
2000   $ErrorMsg = "_MatrixNotEqualOperator: Matrix not equal failed";
2001   $CheckMatrixSizes = 0;
2002   ($This, $Other, $OrderFlipped, $OtherIsMatrix) = _ProcessOverloadedOperatorParameters($ErrorMsg, @_, $CheckMatrixSizes);
2003 
2004   my($NumOfRows, $NumOfCols, $RowIndex, $ColIndex);
2005 
2006   ($NumOfRows, $NumOfCols) = $This->GetSize();
2007 
2008   if ($OtherIsMatrix) {
2009     # $OrderFlipped is set to false for two matrices...
2010     my($OtherNumOfRows, $OtherNumOfCols);
2011 
2012     # Check sizes...
2013     ($OtherNumOfRows, $OtherNumOfCols) = $Other->GetSize();
2014     if (!($NumOfRows == $OtherNumOfRows && $NumOfCols == $OtherNumOfCols)) {
2015       return 1;
2016     }
2017 
2018     # Check values...
2019     for $RowIndex (0 .. ($NumOfRows - 1)) {
2020       for $ColIndex (0 .. ($NumOfCols - 1)) {
2021         if ($This->{Values}[$RowIndex][$ColIndex] == $Other->{Values}[$RowIndex][$ColIndex]) {
2022           return 0;
2023         }
2024       }
2025     }
2026   }
2027   else {
2028     # Scalar comparison...
2029     if ($OrderFlipped) {
2030       croak "Error: ${ClassName}->${ErrorMsg}: First object must be a matrix...";
2031     }
2032     for $RowIndex (0 .. ($NumOfRows - 1)) {
2033       for $ColIndex (0 .. ($NumOfCols - 1)) {
2034         if ($This->{Values}[$RowIndex][$ColIndex] == $Other) {
2035           return 0;
2036         }
2037       }
2038     }
2039   }
2040   return 1;
2041 }
2042 
2043 #
2044 # Matrix less than operator supports two modes:
2045 #   . Comparison of corresponding values in two matrices
2046 #   . Comparing matrix values to a scalar ($Matrix < 2)
2047 #
2048 # Caveats:
2049 #   . Comparison of a scalar to matrix values is not allowed (2 < $Matrix)
2050 #
2051 sub _MatrixLessThanOperator {
2052   my($This, $Other, $OrderFlipped, $OtherIsMatrix, $CheckMatrixSizes, $ErrorMsg);
2053 
2054   $ErrorMsg = "_MatrixLessThanOperator: Matrix less than failed";
2055   $CheckMatrixSizes = 0;
2056   ($This, $Other, $OrderFlipped, $OtherIsMatrix) = _ProcessOverloadedOperatorParameters($ErrorMsg, @_, $CheckMatrixSizes);
2057 
2058   my($NumOfRows, $NumOfCols, $RowIndex, $ColIndex);
2059 
2060   ($NumOfRows, $NumOfCols) = $This->GetSize();
2061 
2062   if ($OtherIsMatrix) {
2063     # $OrderFlipped is set to false for two matrices...
2064     my($OtherNumOfRows, $OtherNumOfCols);
2065 
2066     # Check sizes...
2067     ($OtherNumOfRows, $OtherNumOfCols) = $Other->GetSize();
2068     if (!($NumOfRows == $OtherNumOfRows && $NumOfCols == $OtherNumOfCols)) {
2069       return 0;
2070     }
2071 
2072     # Check values...
2073     for $RowIndex (0 .. ($NumOfRows - 1)) {
2074       for $ColIndex (0 .. ($NumOfCols - 1)) {
2075         if ($This->{Values}[$RowIndex][$ColIndex] >= $Other->{Values}[$RowIndex][$ColIndex]) {
2076           return 0;
2077         }
2078       }
2079     }
2080   }
2081   else {
2082     # Scalar comparison...
2083     if ($OrderFlipped) {
2084       croak "Error: ${ClassName}->${ErrorMsg}: First object must be a matrix...";
2085     }
2086     for $RowIndex (0 .. ($NumOfRows - 1)) {
2087       for $ColIndex (0 .. ($NumOfCols - 1)) {
2088         if ($This->{Values}[$RowIndex][$ColIndex] >= $Other) {
2089           return 0;
2090         }
2091       }
2092     }
2093   }
2094   return 1;
2095 }
2096 
2097 #
2098 # Matrix less than equal operator supports two modes:
2099 #   . Comparion of corresponding values in two matrices
2100 #   . Comparing matrix values to a scalar ($Matrix <= 2)
2101 #
2102 # Caveats:
2103 #   . Comparison of a scalar to matrix values is not allowed (2 <= $Matrix)
2104 #
2105 sub _MatrixLessThanEqualOperator {
2106   my($This, $Other, $OrderFlipped, $OtherIsMatrix, $CheckMatrixSizes, $ErrorMsg);
2107 
2108   $ErrorMsg = "_MatrixLessThanEqualOperator: Matrix less than equal failed";
2109   $CheckMatrixSizes = 0;
2110   ($This, $Other, $OrderFlipped, $OtherIsMatrix) = _ProcessOverloadedOperatorParameters($ErrorMsg, @_, $CheckMatrixSizes);
2111 
2112   my($NumOfRows, $NumOfCols, $RowIndex, $ColIndex);
2113 
2114   ($NumOfRows, $NumOfCols) = $This->GetSize();
2115 
2116   if ($OtherIsMatrix) {
2117     # $OrderFlipped is set to false for two matrices...
2118     my($OtherNumOfRows, $OtherNumOfCols);
2119 
2120     # Check sizes...
2121     ($OtherNumOfRows, $OtherNumOfCols) = $Other->GetSize();
2122     if (!($NumOfRows == $OtherNumOfRows && $NumOfCols == $OtherNumOfCols)) {
2123       return 0;
2124     }
2125 
2126     # Check values...
2127     for $RowIndex (0 .. ($NumOfRows - 1)) {
2128       for $ColIndex (0 .. ($NumOfCols - 1)) {
2129         if ($This->{Values}[$RowIndex][$ColIndex] > $Other->{Values}[$RowIndex][$ColIndex]) {
2130           return 0;
2131         }
2132       }
2133     }
2134   }
2135   else {
2136     # Scalar comparison...
2137     if ($OrderFlipped) {
2138       croak "Error: ${ClassName}->${ErrorMsg}: First object must be a matrix...";
2139     }
2140     for $RowIndex (0 .. ($NumOfRows - 1)) {
2141       for $ColIndex (0 .. ($NumOfCols - 1)) {
2142         if ($This->{Values}[$RowIndex][$ColIndex] > $Other) {
2143           return 0;
2144         }
2145       }
2146     }
2147   }
2148   return 1;
2149 }
2150 
2151 #
2152 # Matrix greatar than operator supports two modes:
2153 #   . Comparison of corresponding values in two matrices
2154 #   . Comparing matrix values to a scalar ($Matrix > 2)
2155 #
2156 # Caveats:
2157 #   . Comparison of a scalar to matrix values is not allowed (2 > $Matrix)
2158 #
2159 sub _MatrixGreatarThanOperator {
2160   my($This, $Other, $OrderFlipped, $OtherIsMatrix, $CheckMatrixSizes, $ErrorMsg);
2161 
2162   $ErrorMsg = "_MatrixGreatarThanOperator: Matrix greatar than failed";
2163   $CheckMatrixSizes = 0;
2164   ($This, $Other, $OrderFlipped, $OtherIsMatrix) = _ProcessOverloadedOperatorParameters($ErrorMsg, @_, $CheckMatrixSizes);
2165 
2166   my($NumOfRows, $NumOfCols, $RowIndex, $ColIndex);
2167 
2168   ($NumOfRows, $NumOfCols) = $This->GetSize();
2169 
2170   if ($OtherIsMatrix) {
2171     # $OrderFlipped is set to false for two matrices...
2172     my($OtherNumOfRows, $OtherNumOfCols);
2173 
2174     # Check sizes...
2175     ($OtherNumOfRows, $OtherNumOfCols) = $Other->GetSize();
2176     if (!($NumOfRows == $OtherNumOfRows && $NumOfCols == $OtherNumOfCols)) {
2177       return 0;
2178     }
2179 
2180     # Check values...
2181     for $RowIndex (0 .. ($NumOfRows - 1)) {
2182       for $ColIndex (0 .. ($NumOfCols - 1)) {
2183         if ($This->{Values}[$RowIndex][$ColIndex] <= $Other->{Values}[$RowIndex][$ColIndex]) {
2184           return 0;
2185         }
2186       }
2187     }
2188   }
2189   else {
2190     # Scalar comparison...
2191     if ($OrderFlipped) {
2192       croak "Error: ${ClassName}->${ErrorMsg}: First object must be a matrix...";
2193     }
2194     for $RowIndex (0 .. ($NumOfRows - 1)) {
2195       for $ColIndex (0 .. ($NumOfCols - 1)) {
2196         if ($This->{Values}[$RowIndex][$ColIndex] <= $Other) {
2197           return 0;
2198         }
2199       }
2200     }
2201   }
2202   return 1;
2203 }
2204 
2205 #
2206 # Matrix greatar than equal operator supports two modes:
2207 #   . Comparison of corresponding values in two matrices
2208 #   . Comparing matrix values to a scalar ($Matrix >= 2)
2209 #
2210 # Caveats:
2211 #   . Comparison of a scalar to matrix values is not allowed (2 >= $Matrix)
2212 #
2213 sub _MatrixGreatarThanEqualOperator {
2214   my($This, $Other, $OrderFlipped, $OtherIsMatrix, $CheckMatrixSizes, $ErrorMsg);
2215 
2216   $ErrorMsg = "_MatrixGreatarThanEqualOperator: Matrix greatar than equal failed";
2217   $CheckMatrixSizes = 0;
2218   ($This, $Other, $OrderFlipped, $OtherIsMatrix) = _ProcessOverloadedOperatorParameters($ErrorMsg, @_, $CheckMatrixSizes);
2219 
2220   my($NumOfRows, $NumOfCols, $RowIndex, $ColIndex);
2221 
2222   ($NumOfRows, $NumOfCols) = $This->GetSize();
2223 
2224   if ($OtherIsMatrix) {
2225     # $OrderFlipped is set to false for two matrices...
2226     my($OtherNumOfRows, $OtherNumOfCols);
2227 
2228     # Check sizes...
2229     ($OtherNumOfRows, $OtherNumOfCols) = $Other->GetSize();
2230     if (!($NumOfRows == $OtherNumOfRows && $NumOfCols == $OtherNumOfCols)) {
2231       return 0;
2232     }
2233 
2234     # Check values...
2235     for $RowIndex (0 .. ($NumOfRows - 1)) {
2236       for $ColIndex (0 .. ($NumOfCols - 1)) {
2237         if ($This->{Values}[$RowIndex][$ColIndex] < $Other->{Values}[$RowIndex][$ColIndex]) {
2238           return 0;
2239         }
2240       }
2241     }
2242   }
2243   else {
2244     # Scalar comparison...
2245     if ($OrderFlipped) {
2246       croak "Error: ${ClassName}->${ErrorMsg}: First object must be a matrix...";
2247     }
2248     for $RowIndex (0 .. ($NumOfRows - 1)) {
2249       for $ColIndex (0 .. ($NumOfCols - 1)) {
2250         if ($This->{Values}[$RowIndex][$ColIndex] < $Other) {
2251           return 0;
2252         }
2253       }
2254     }
2255   }
2256   return 1;
2257 }
2258 
2259 #
2260 # Matrix negative value operator returns a matrix with values corresponding to
2261 # negative values of a matrix
2262 #
2263 sub _MatrixNegativeValueOperator {
2264   my($This, $Other, $OrderFlipped, $OtherIsMatrix, $ErrorMsg);
2265 
2266   $ErrorMsg = "_MatrixNegativeValueOperator: Matrix negative value operation failed";
2267   ($This, $Other, $OrderFlipped, $OtherIsMatrix) = _ProcessOverloadedOperatorParameters($ErrorMsg, @_);
2268 
2269   my($Matrix, $NumOfRows, $NumOfCols, $RowIndex, $ColIndex);
2270 
2271   ($NumOfRows, $NumOfCols) = $This->GetSize();
2272   $Matrix = new Matrix($NumOfRows, $NumOfCols);
2273 
2274   for $RowIndex (0 .. ($NumOfRows - 1)) {
2275     for $ColIndex (0 .. ($NumOfCols - 1)) {
2276       $Matrix->{Values}[$RowIndex][$ColIndex] = - $This->{Values}[$RowIndex][$ColIndex];
2277     }
2278   }
2279   return $Matrix;
2280 }
2281 
2282 #
2283 # Matrix absolute value operator returns a matrix with values corresponding to
2284 # absolute values of a matrix
2285 #
2286 sub _MatrixAbsoluteValueOperator {
2287   my($This, $Other, $OrderFlipped, $OtherIsMatrix, $ErrorMsg);
2288 
2289   $ErrorMsg = "_MatrixAbsoluteValueOperator: Matrix absolute value operation failed";
2290   ($This, $Other, $OrderFlipped, $OtherIsMatrix) = _ProcessOverloadedOperatorParameters($ErrorMsg, @_);
2291 
2292   my($Matrix, $NumOfRows, $NumOfCols, $RowIndex, $ColIndex);
2293 
2294   ($NumOfRows, $NumOfCols) = $This->GetSize();
2295   $Matrix = new Matrix($NumOfRows, $NumOfCols);
2296 
2297   for $RowIndex (0 .. ($NumOfRows - 1)) {
2298     for $ColIndex (0 .. ($NumOfCols - 1)) {
2299       $Matrix->{Values}[$RowIndex][$ColIndex] = abs $This->{Values}[$RowIndex][$ColIndex];
2300     }
2301   }
2302   return $Matrix;
2303 }
2304 
2305 #
2306 # Matrix exp natural base operator returns a matrix with values corresponding to
2307 # e raised to the power of values in a matrix
2308 #
2309 sub _MatrixExpNaturalBaseOperator {
2310   my($This, $Other, $OrderFlipped, $OtherIsMatrix, $ErrorMsg);
2311 
2312   $ErrorMsg = "_MatrixExpNaturalBaseOperator: Matrix exp operation failed";
2313   ($This, $Other, $OrderFlipped, $OtherIsMatrix) = _ProcessOverloadedOperatorParameters($ErrorMsg, @_);
2314 
2315   my($Matrix, $NumOfRows, $NumOfCols, $RowIndex, $ColIndex);
2316 
2317   ($NumOfRows, $NumOfCols) = $This->GetSize();
2318   $Matrix = new Matrix($NumOfRows, $NumOfCols);
2319 
2320   for $RowIndex (0 .. ($NumOfRows - 1)) {
2321     for $ColIndex (0 .. ($NumOfCols - 1)) {
2322       $Matrix->{Values}[$RowIndex][$ColIndex] = exp $This->{Values}[$RowIndex][$ColIndex];
2323     }
2324   }
2325   return $Matrix;
2326 }
2327 
2328 #
2329 # Matrix log natural base operator returns a matrix with values corresponding to
2330 # log of values in a matrix
2331 #
2332 sub _MatrixLogNaturalBaseOperator {
2333   my($This, $Other, $OrderFlipped, $OtherIsMatrix, $ErrorMsg);
2334 
2335   $ErrorMsg = "_MatrixLogNaturalBaseOperator: Matrix log operation failed";
2336   ($This, $Other, $OrderFlipped, $OtherIsMatrix) = _ProcessOverloadedOperatorParameters($ErrorMsg, @_);
2337 
2338   my($Matrix, $NumOfRows, $NumOfCols, $RowIndex, $ColIndex);
2339 
2340   ($NumOfRows, $NumOfCols) = $This->GetSize();
2341   $Matrix = new Matrix($NumOfRows, $NumOfCols);
2342 
2343   for $RowIndex (0 .. ($NumOfRows - 1)) {
2344     for $ColIndex (0 .. ($NumOfCols - 1)) {
2345       $Matrix->{Values}[$RowIndex][$ColIndex] = log $This->{Values}[$RowIndex][$ColIndex];
2346     }
2347   }
2348   return $Matrix;
2349 }
2350 
2351 #
2352 # Matrix square root operator returns a matrix with values corresponding to
2353 # sqrt of values in a matrix
2354 #
2355 sub _MatrixSquareRootOperator {
2356   my($This, $Other, $OrderFlipped, $OtherIsMatrix, $ErrorMsg);
2357 
2358   $ErrorMsg = "_MatrixSquareRootOperator: Matrix sqrt operation failed";
2359   ($This, $Other, $OrderFlipped, $OtherIsMatrix) = _ProcessOverloadedOperatorParameters($ErrorMsg, @_);
2360 
2361   my($Matrix, $NumOfRows, $NumOfCols, $RowIndex, $ColIndex);
2362 
2363   ($NumOfRows, $NumOfCols) = $This->GetSize();
2364   $Matrix = new Matrix($NumOfRows, $NumOfCols);
2365 
2366   for $RowIndex (0 .. ($NumOfRows - 1)) {
2367     for $ColIndex (0 .. ($NumOfCols - 1)) {
2368       $Matrix->{Values}[$RowIndex][$ColIndex] = sqrt $This->{Values}[$RowIndex][$ColIndex];
2369     }
2370   }
2371   return $Matrix;
2372 }
2373 
2374 #
2375 # Matrix sine root operator returns a matrix with values corresponding to
2376 # sin of values in a matrix
2377 #
2378 sub _MatrixSineOperator {
2379   my($This, $Other, $OrderFlipped, $OtherIsMatrix, $ErrorMsg);
2380 
2381   $ErrorMsg = "_MatrixSineOperator: Matrix sin operation failed";
2382   ($This, $Other, $OrderFlipped, $OtherIsMatrix) = _ProcessOverloadedOperatorParameters($ErrorMsg, @_);
2383 
2384   my($Matrix, $NumOfRows, $NumOfCols, $RowIndex, $ColIndex);
2385 
2386   ($NumOfRows, $NumOfCols) = $This->GetSize();
2387   $Matrix = new Matrix($NumOfRows, $NumOfCols);
2388 
2389   for $RowIndex (0 .. ($NumOfRows - 1)) {
2390     for $ColIndex (0 .. ($NumOfCols - 1)) {
2391       $Matrix->{Values}[$RowIndex][$ColIndex] = sin $This->{Values}[$RowIndex][$ColIndex];
2392     }
2393   }
2394   return $Matrix;
2395 }
2396 
2397 #
2398 # Matrix cosine root operator returns a matrix with values corresponding to
2399 # cos of values in a matrix
2400 #
2401 sub _MatrixCosineOperator {
2402   my($This, $Other, $OrderFlipped, $OtherIsMatrix, $ErrorMsg);
2403 
2404   $ErrorMsg = "_MatrixCosineOperator: Matrix cos operation failed";
2405   ($This, $Other, $OrderFlipped, $OtherIsMatrix) = _ProcessOverloadedOperatorParameters($ErrorMsg, @_);
2406 
2407   my($Matrix, $NumOfRows, $NumOfCols, $RowIndex, $ColIndex);
2408 
2409   ($NumOfRows, $NumOfCols) = $This->GetSize();
2410   $Matrix = new Matrix($NumOfRows, $NumOfCols);
2411 
2412   for $RowIndex (0 .. ($NumOfRows - 1)) {
2413     for $ColIndex (0 .. ($NumOfCols - 1)) {
2414       $Matrix->{Values}[$RowIndex][$ColIndex] = cos $This->{Values}[$RowIndex][$ColIndex];
2415     }
2416   }
2417   return $Matrix;
2418 }
2419 
2420 # Turn matrix into array for @{$Matrix} operation...
2421 #
2422 sub _MatrixToArrayOperator {
2423   my($This) = @_;
2424 
2425   return \@{$This->{Values}};
2426 }
2427 
2428 # Always return true in boolean context...
2429 #
2430 sub _BoolifyMatrix {
2431   my($This) = @_;
2432 
2433   return 1;
2434 }
2435 
2436 # Process parameters passed to overloaded operators...
2437 #
2438 # For uninary operators, $SecondParameter is not defined.
2439 sub _ProcessOverloadedOperatorParameters {
2440   my($ErrorMsg, $FirstParameter, $SecondParameter, $ParametersOrderStatus, $CheckMatrixSizesStatus) = @_;
2441   my($This, $Other, $OrderFlipped, $OtherIsMatrix, $CheckMatrixSizes);
2442 
2443   ($This, $Other) =  ($FirstParameter, $SecondParameter);
2444   $OrderFlipped = (defined($ParametersOrderStatus) && $ParametersOrderStatus) ? 1 : 0;
2445   $CheckMatrixSizes = (defined $CheckMatrixSizesStatus) ? $CheckMatrixSizesStatus : 1;
2446 
2447   _ValidateMatrix($ErrorMsg, $This);
2448 
2449   $OtherIsMatrix = 0;
2450   if (defined($Other) && (ref $Other)) {
2451     # Make sure $Other is a matrix...
2452     _ValidateMatrix($ErrorMsg, $Other);
2453     if ($CheckMatrixSizes) {
2454       _ValidateMatrixSizesAreEqual($ErrorMsg, $This, $Other);
2455     }
2456     $OtherIsMatrix = 1;
2457   }
2458   return ($This, $Other, $OrderFlipped, $OtherIsMatrix);
2459 }
2460 
2461 # Make sure size of the two matrices contain the same number of values...
2462 sub _ValidateMatrixSizesAreEqual {
2463   my($ErrorMsg, $Matrix1, $Matrix2) = @_;
2464   my($NumOfRows1, $NumOfCols1, $NumOfRows2, $NumOfCols2);
2465 
2466   ($NumOfRows1, $NumOfCols1) = $Matrix1->GetSize();
2467   ($NumOfRows2, $NumOfCols2) = $Matrix2->GetSize();
2468 
2469   if (!($NumOfRows1 == $NumOfRows2 && $NumOfCols1 == $NumOfCols2)) {
2470     croak "Error: ${ClassName}->${ErrorMsg}: Size of the matrices must be same...";
2471   }
2472 }
2473 
2474 # Return a string containing matrix values...
2475 #
2476 sub StringifyMatrix {
2477   my($This) = @_;
2478   my($MatrixString, $MatrixPrintStyleValue, $PrintFormat, $AllRowsInOneLine, $FormatString, $NumOfRows, $NumOfCols, $RowIndex, $RowNum, $RowString, @ValuesFormat);
2479 
2480   ($NumOfRows, $NumOfCols) = $This->GetSize();
2481 
2482   $MatrixPrintStyleValue = (exists $This->{MatrixPrintStyle}) ? $This->{MatrixPrintStyle} : $MatrixPrintStyle;
2483   $AllRowsInOneLine = ($MatrixPrintStyleValue =~ /^AllRowsInOneLine$/i) ? 1 : 0;
2484 
2485   $PrintFormat = (exists $This->{ValueFormat}) ? $This->{ValueFormat} : $ValueFormat;
2486 
2487   @ValuesFormat = ($PrintFormat) x $NumOfCols;
2488   $FormatString = join ' ', @ValuesFormat;
2489 
2490   $MatrixString = sprintf "<Size: $NumOfRows x $NumOfCols;";
2491   if ($AllRowsInOneLine) {
2492     $MatrixString .= sprintf " Values:";
2493   }
2494   else {
2495     $MatrixString .= sprintf " Values:\n";
2496   }
2497 
2498   $RowNum = 0;
2499   for $RowIndex (0 .. ($NumOfRows -1)) {
2500     $RowNum++;
2501     $RowString = sprintf "Row${RowNum}:[$FormatString]", @{$This->{Values}[$RowIndex]};
2502     if ($AllRowsInOneLine) {
2503       $MatrixString .= " $RowString";
2504     }
2505     else {
2506       $MatrixString .= "$RowString\n";
2507     }
2508   }
2509   $MatrixString .= ">";
2510   return $MatrixString;
2511 }
2512