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