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