       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