001/* A library for mathematical operations on matrices of Fractions. 002 003 Copyright (c) 2004-2014 The Regents of the University of California. 004 All rights reserved. 005 006 Permission is hereby granted, without written agreement and without 007 license or royalty fees, to use, copy, modify, and distribute this 008 software and its documentation for any purpose, provided that the above 009 copyright notice and the following two paragraphs appear in all copies 010 of this software. 011 012 IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY 013 FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES 014 ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF 015 THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF 016 SUCH DAMAGE. 017 018 THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, 019 INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 020 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE 021 PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF 022 CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, 023 ENHANCEMENTS, OR MODIFICATIONS. 024 025 PT_COPYRIGHT_VERSION_2 026 COPYRIGHTENDKEY 027 028 */ 029package ptolemy.math; 030 031////////////////////////////////////////////////////////////////////////// 032//// FractionMatrixMath 033 034/** 035 A library for mathematical operations on matrices of Fractions. 036 037 <p>Rows and column numbers of matrices are specified with zero-based indices. 038 All calls expect matrix arguments to be non-null. In addition, all 039 rows of the matrix are expected to have the same number of columns. 040 041 @author Adam Cataldo 042 @version $Id$ 043 @since Ptolemy II 5.0 044 @Pt.ProposedRating Red (acataldo) 045 @Pt.AcceptedRating Red (cxh) 046 */ 047public class FractionMatrixMath { 048 // private constructor prevents construction of this class. 049 private FractionMatrixMath() { 050 } 051 052 /** Return a new matrix that is constructed from the argument by 053 * adding the second argument to every element. 054 * @param matrix A matrix of Fractions. 055 * @param z The Fraction to add. 056 * @return A new matrix of Fractions. 057 */ 058 public static final Fraction[][] add(Fraction[][] matrix, Fraction z) { 059 Fraction[][] returnValue = new Fraction[_rows(matrix)][_columns( 060 matrix)]; 061 062 for (int i = 0; i < _rows(matrix); i++) { 063 for (int j = 0; j < _columns(matrix); j++) { 064 returnValue[i][j] = matrix[i][j].add(z); 065 } 066 } 067 068 return returnValue; 069 } 070 071 /** Return a new matrix that is constructed from the argument by 072 * adding the second matrix to the first one. If the two 073 * matrices are not the same size, throw an 074 * IllegalArgumentException. 075 * @param matrix1 The first matrix of Fractions. 076 * @param matrix2 The second matrix of Fractions. 077 * @return A new matrix of Fractions. */ 078 public static final Fraction[][] add(final Fraction[][] matrix1, 079 final Fraction[][] matrix2) { 080 _checkSameDimension("add", matrix1, matrix2); 081 082 Fraction[][] returnValue = new Fraction[_rows(matrix1)][_columns( 083 matrix1)]; 084 085 for (int i = 0; i < _rows(matrix1); i++) { 086 for (int j = 0; j < _columns(matrix1); j++) { 087 returnValue[i][j] = matrix1[i][j].add(matrix2[i][j]); 088 } 089 } 090 091 return returnValue; 092 } 093 094 /** Return a new matrix that is a copy of the matrix argument. 095 * @param matrix A matrix of Fractions. 096 * @return A new matrix of Fractions. 097 */ 098 public static final Fraction[][] allocCopy(final Fraction[][] matrix) { 099 return crop(matrix, 0, 0, _rows(matrix), _columns(matrix)); 100 } 101 102 /** Return a new matrix that is a sub-matrix of the input 103 * matrix argument. The row and column from which to start 104 * and the number of rows and columns to span are specified. 105 * @param matrix A matrix of Fractions. 106 * @param rowStart An int specifying which row to start on. 107 * @param colStart An int specifying which column to start on. 108 * @param rowSpan An int specifying how many rows to copy. 109 * @param colSpan An int specifying how many columns to copy. 110 */ 111 public static final Fraction[][] crop(final Fraction[][] matrix, 112 final int rowStart, final int colStart, final int rowSpan, 113 final int colSpan) { 114 Fraction[][] returnValue = new Fraction[rowSpan][colSpan]; 115 116 for (int i = 0; i < rowSpan; i++) { 117 System.arraycopy(matrix[rowStart + i], colStart, returnValue[i], 0, 118 colSpan); 119 } 120 121 return returnValue; 122 } 123 124 /** Return a new matrix that is constructed by placing the 125 * elements of the input array on the diagonal of the square 126 * matrix, starting from the top left corner down to the bottom 127 * right corner. All other elements are zero. The size of of the 128 * matrix is n x n, where n is the length of the input array. 129 */ 130 public static final Fraction[][] diag(final Fraction[] array) { 131 int n = array.length; 132 133 Fraction[][] returnValue = new Fraction[n][n]; 134 135 // Assume the matrix is zero-filled. 136 for (int i = 0; i < n; i++) { 137 for (int j = 0; j < n; j++) { 138 if (i == j) { 139 returnValue[i][j] = array[i]; 140 } else { 141 returnValue[i][j] = new Fraction(0, 1); 142 } 143 } 144 } 145 146 return returnValue; 147 } 148 149 /** Return a new matrix that is constructed from the argument by 150 * dividing the second argument to every element. 151 * @param matrix A matrix of Fractions. 152 * @param z The Fraction to divide by. 153 * @return A new matrix of Fractions. 154 */ 155 public static final Fraction[][] divide(Fraction[][] matrix, Fraction z) { 156 Fraction[][] returnValue = new Fraction[_rows(matrix)][_columns( 157 matrix)]; 158 159 for (int i = 0; i < _rows(matrix); i++) { 160 for (int j = 0; j < _columns(matrix); j++) { 161 returnValue[i][j] = matrix[i][j].divide(z); 162 } 163 } 164 165 return returnValue; 166 } 167 168 /** Return a new matrix that is constructed by element by element 169 * division of the two matrix arguments. Each element of the 170 * first matrix is divided by the corresponding element of the 171 * second matrix. If the two matrices are not the same size, 172 * throw an IllegalArgumentException. 173 */ 174 public static final Fraction[][] divideElements(final Fraction[][] matrix1, 175 final Fraction[][] matrix2) { 176 int rows = _rows(matrix1); 177 int columns = _columns(matrix1); 178 179 _checkSameDimension("divideElements", matrix1, matrix2); 180 181 Fraction[][] returnValue = new Fraction[rows][columns]; 182 183 for (int i = 0; i < rows; i++) { 184 for (int j = 0; j < columns; j++) { 185 returnValue[i][j] = matrix1[i][j].divide(matrix2[i][j]); 186 } 187 } 188 189 return returnValue; 190 } 191 192 /** Return a new array that is filled with the contents of the matrix. 193 * The Fractions are stored row by row, i.e. using the notation 194 * (row, column), the entries of the array are in the following order 195 * for a (m, n) matrix : 196 * (0, 0), (0, 1), (0, 2), ... , (0, n-1), (1, 0), (1, 1), ..., (m-1)(n-1) 197 * @param matrix A matrix of Fractions. 198 * @return A new array of Fractions. 199 */ 200 public static final Fraction[] fromMatrixToArray( 201 final Fraction[][] matrix) { 202 return fromMatrixToArray(matrix, _rows(matrix), _columns(matrix)); 203 } 204 205 /** Return a new array that is filled with the contents of the matrix. 206 * The maximum numbers of rows and columns to copy are specified so 207 * that entries lying outside of this range can be ignored. The 208 * maximum rows to copy cannot exceed the number of rows in the matrix, 209 * and the maximum columns to copy cannot exceed the number of columns 210 * in the matrix. 211 * The Fractions are stored row by row, i.e. using the notation 212 * (row, column), the entries of the array are in the following order 213 * for a matrix, limited to m rows and n columns : 214 * (0, 0), (0, 1), (0, 2), ... , (0, n-1), (1, 0), (1, 1), ..., (m-1)(n-1) 215 * @param matrix A matrix of Fractions. 216 * @return A new array of Fractions. 217 */ 218 public static final Fraction[] fromMatrixToArray(final Fraction[][] matrix, 219 int maxRow, int maxCol) { 220 Fraction[] returnValue = new Fraction[maxRow * maxCol]; 221 222 for (int i = 0; i < maxRow; i++) { 223 System.arraycopy(matrix[i], 0, returnValue, i * maxCol, maxCol); 224 } 225 226 return returnValue; 227 } 228 229 /** Return an new identity matrix with the specified dimension. The 230 * matrix is square, so only one dimension specifier is needed. 231 * @return Identity matrix in fractions 232 */ 233 public static final Fraction[][] identity(final int dim) { 234 Fraction[][] returnValue = new Fraction[dim][dim]; 235 236 // we rely on the fact Java fills the allocated matrix with 0's 237 for (int i = 0; i < dim; i++) { 238 for (int j = 0; j < dim; j++) { 239 if (i == j) { 240 returnValue[i][i] = new Fraction(1, 1); 241 } else { 242 returnValue[i][j] = new Fraction(0, 1); 243 } 244 } 245 } 246 247 return returnValue; 248 } 249 250 /** Return a new matrix that is constructed by multiplying the matrix 251 * by a scaleFactor. 252 * @param matrix The matrix of Fractions. 253 * @param scaleFactor The Fraction to multiply by. 254 * @return The resulting matrix of Fractions. 255 */ 256 public static final Fraction[][] multiply(final Fraction[][] matrix, 257 final Fraction scaleFactor) { 258 int rows = _rows(matrix); 259 int columns = _columns(matrix); 260 261 Fraction[][] returnValue = new Fraction[rows][columns]; 262 263 for (int i = 0; i < rows; i++) { 264 for (int j = 0; j < columns; j++) { 265 returnValue[i][j] = matrix[i][j].multiply(scaleFactor); 266 } 267 } 268 269 return returnValue; 270 } 271 272 /** Return a new array that is constructed from the argument by 273 * pre-multiplying the matrix by an array (treated as a row vector). 274 * The number of rows of the matrix must equal the number of elements 275 * in the array. The returned array will have a length equal to the number 276 * of columns of the matrix. 277 * @param array The array of Fractions. 278 * @param matrix The matrix of Fractions. 279 * @return The resulting matrix of Fractions. 280 */ 281 public static final Fraction[] multiply(final Fraction[] array, 282 final Fraction[][] matrix) { 283 int rows = _rows(matrix); 284 int columns = _columns(matrix); 285 286 if (rows != array.length) { 287 throw new IllegalArgumentException( 288 "preMultiply : array does not have the same number of " 289 + "elements (" + array.length 290 + ") as the number of rows " + "of the matrix (" 291 + rows + ")"); 292 } 293 294 Fraction[] returnValue = new Fraction[columns]; 295 296 for (int i = 0; i < columns; i++) { 297 Fraction sum = new Fraction(0, 1); 298 299 for (int j = 0; j < rows; j++) { 300 sum = sum.add(matrix[j][i].multiply(array[j])); 301 } 302 303 returnValue[i] = sum; 304 } 305 306 return returnValue; 307 } 308 309 /** Return a new array that is constructed from the argument by 310 * post-multiplying the matrix by an array (treated as a column vector). 311 * The number of columns of the matrix must equal the number of elements 312 * in the array. The returned array will have a length equal to the number 313 * of rows of the matrix. 314 * @param matrix The matrix of Fractions. 315 * @param array The array of Fractions. 316 * @return The resulting matrix of Fractions. 317 */ 318 public static final Fraction[] multiply(final Fraction[][] matrix, 319 final Fraction[] array) { 320 int rows = _rows(matrix); 321 int columns = _columns(matrix); 322 323 if (columns != array.length) { 324 throw new IllegalArgumentException( 325 "postMultiply() : array does not have the same number " 326 + "of elements (" + array.length 327 + ") as the number of " + "columns of the matrix (" 328 + columns + ")"); 329 } 330 331 Fraction[] returnValue = new Fraction[rows]; 332 333 for (int i = 0; i < rows; i++) { 334 Fraction sum = new Fraction(0, 1); 335 336 for (int j = 0; j < columns; j++) { 337 sum = sum.add(matrix[i][j].multiply(array[j])); 338 } 339 340 returnValue[i] = sum; 341 } 342 343 return returnValue; 344 } 345 346 /** Return a new matrix that is constructed from the argument by 347 * multiplying the first matrix by the second one. 348 * Note this operation is not commutative, 349 * so care must be taken in the ordering of the arguments. 350 * The number of columns of matrix1 351 * must equal the number of rows of matrix2. If matrix1 is of 352 * size m x n, and matrix2 is of size n x p, the returned matrix 353 * will have size m x p. 354 * 355 * <p>Note that this method is different from the other multiply() 356 * methods in that this method does not do pointwise multiplication. 357 * 358 * @see #multiplyElements(Fraction[][], Fraction[][]) 359 * @param matrix1 The first matrix of Fractions. 360 * @param matrix2 The second matrix of Fractions. 361 * @return A new matrix of ints. 362 * @exception ArithmeticException If the matrix dimensions don't match up. 363 */ 364 public static final Fraction[][] multiply(Fraction[][] matrix1, 365 Fraction[][] matrix2) throws ArithmeticException { 366 if (_columns(matrix1) != _rows(matrix2)) { 367 throw new ArithmeticException( 368 "Number of columns (" + _columns(matrix1) 369 + ") of matrix1 does note equal number of rows (" 370 + _rows(matrix2) + ") of matrix2."); 371 } 372 373 Fraction[][] returnValue = new Fraction[_rows(matrix1)][_columns( 374 matrix2)]; 375 376 for (int i = 0; i < _rows(matrix1); i++) { 377 for (int j = 0; j < _columns(matrix2); j++) { 378 Fraction sum = new Fraction(0, 1); 379 380 for (int k = 0; k < _columns(matrix1); k++) { 381 sum = sum.add(matrix1[i][k].multiply(matrix2[k][j])); 382 } 383 384 returnValue[i][j] = sum; 385 } 386 } 387 388 return returnValue; 389 } 390 391 /** Return a new matrix that is constructed by element by element 392 * multiplication of the two matrix arguments. If the two 393 * matrices are not the same size, throw an 394 * IllegalArgumentException. 395 * <p>Note that this method does pointwise matrix multiplication. 396 * @param matrix1 The first matrix of Fractions. 397 * @param matrix2 The second matrix of Fractions. 398 * @return A new matrix of ints. 399 */ 400 public static final Fraction[][] multiplyElements( 401 final Fraction[][] matrix1, final Fraction[][] matrix2) { 402 int rows = _rows(matrix1); 403 int columns = _columns(matrix1); 404 405 _checkSameDimension("multiplyElements", matrix1, matrix2); 406 407 Fraction[][] returnValue = new Fraction[rows][columns]; 408 409 for (int i = 0; i < rows; i++) { 410 for (int j = 0; j < columns; j++) { 411 returnValue[i][j] = matrix1[i][j].multiply(matrix2[i][j]); 412 } 413 } 414 415 return returnValue; 416 } 417 418 /** Return a new matrix that is the additive inverse of the 419 * argument matrix. 420 * @param matrix the input matrix of Fractions. 421 * @return the output matrix of Fractions. 422 */ 423 public static final Fraction[][] negative(final Fraction[][] matrix) { 424 int rows = _rows(matrix); 425 int columns = _columns(matrix); 426 427 Fraction[][] returnValue = new Fraction[rows][columns]; 428 429 for (int i = 0; i < rows; i++) { 430 for (int j = 0; j < columns; j++) { 431 returnValue[i][j] = matrix[i][j].negate(); 432 } 433 } 434 435 return returnValue; 436 } 437 438 /** Return a new matrix that is constructed from the argument by 439 * subtracting the second matrix from the first one. If the two 440 * matrices are not the same size, throw an 441 * IllegalArgumentException. 442 * @param matrix1 The matrix to be subtracted from. 443 * @param matrix2 The matrix to subtract. 444 * @return The difference matrix. 445 */ 446 public static final Fraction[][] subtract(final Fraction[][] matrix1, 447 final Fraction[][] matrix2) { 448 _checkSameDimension("subtract", matrix1, matrix2); 449 450 int rows = _rows(matrix1); 451 int columns = _columns(matrix1); 452 453 Fraction[][] returnValue = new Fraction[rows][columns]; 454 455 for (int i = 0; i < rows; i++) { 456 for (int j = 0; j < columns; j++) { 457 returnValue[i][j] = matrix1[i][j].subtract(matrix2[i][j]); 458 } 459 } 460 461 return returnValue; 462 } 463 464 /** Return the sum of the elements of a matrix. 465 * @param matrix The input matrix. 466 * @return The sum of the elements of the matrix. 467 */ 468 public static final Fraction sum(final Fraction[][] matrix) { 469 Fraction sum = new Fraction(0, 1); 470 471 for (Fraction[] element : matrix) { 472 for (int j = 0; j < element.length; j++) { 473 sum = sum.add(element[j]); 474 } 475 } 476 477 return sum; 478 } 479 480 /** Return a new matrix that is formed by converting the Fractions in 481 * the argument matrix to doubles. 482 * @param matrix An matrix of Fractions. 483 * @return A new matrix of doubles. 484 */ 485 public static final double[][] toDoubleMatrix(final Fraction[][] matrix) { 486 int rows = _rows(matrix); 487 int columns = _columns(matrix); 488 489 double[][] returnValue = new double[rows][columns]; 490 491 for (int i = 0; i < rows; i++) { 492 for (int j = 0; j < columns; j++) { 493 returnValue[i][j] = matrix[i][j].toDouble(); 494 } 495 } 496 497 return returnValue; 498 } 499 500 /** Return a new matrix of Fractions that is initialized from a 1-D array. 501 * The format of the array must be (0, 0), (0, 1), ..., (0, n-1), (1, 0), 502 * (1, 1), ..., (m-1, n-1) where the output matrix is to be m x n and 503 * entries are denoted by (row, column). 504 * @param array An array of Fraction. 505 * @param rows An integer representing the number of rows of the new 506 * matrix. 507 * @param cols An integer representing the number of columns of the new 508 * matrix. 509 * @return A new matrix of Fractions. 510 */ 511 public static final Fraction[][] toMatrixFromArray(Fraction[] array, 512 int rows, int cols) { 513 Fraction[][] returnValue = new Fraction[rows][cols]; 514 515 for (int i = 0; i < rows; i++) { 516 System.arraycopy(array, i * cols, returnValue[i], 0, cols); 517 } 518 519 return returnValue; 520 } 521 522 /** Return a new String representing the matrix, formatted as 523 * in Java array initializers. 524 */ 525 public static final String toString(final Fraction[][] matrix) { 526 return toString(matrix, ", ", "{", "}", "{", ", ", "}"); 527 } 528 529 /** Return a new String representing the matrix, formatted as 530 * specified by the ArrayStringFormat argument. 531 * To get a String in the Ptolemy expression language format, 532 * call this method with ArrayStringFormat.exprASFormat as the 533 * format argument. 534 */ 535 public static final String toString(final Fraction[][] matrix, 536 String elementDelimiter, String matrixBegin, String matrixEnd, 537 String vectorBegin, String vectorDelimiter, String vectorEnd) { 538 StringBuffer sb = new StringBuffer(); 539 sb.append(matrixBegin); 540 541 for (int i = 0; i < _rows(matrix); i++) { 542 sb.append(vectorBegin); 543 544 for (int j = 0; j < _columns(matrix); j++) { 545 sb.append(matrix[i][j].toString()); 546 547 if (j < _columns(matrix) - 1) { 548 sb.append(elementDelimiter); 549 } 550 } 551 552 sb.append(vectorEnd); 553 554 if (i < _rows(matrix) - 1) { 555 sb.append(vectorDelimiter); 556 } 557 } 558 559 sb.append(matrixEnd); 560 561 return new String(sb); 562 } 563 564 /** Return the trace of a square matrix, which is the sum of the 565 * diagonal entries A<sub>11</sub> + A<sub>22</sub> + ... + A<sub>nn</sub> 566 * Throw an IllegalArgumentException if the matrix is not square. 567 * Note that the trace of a matrix is equal to the sum of its eigenvalues. 568 * @param matrix A square matrix. 569 * @return The trace of this matrix. 570 */ 571 public static final Fraction trace(final Fraction[][] matrix) { 572 int dim = _checkSquare("trace", matrix); 573 Fraction sum = new Fraction(0, 1); 574 575 for (int i = 0; i < dim; i++) { 576 sum = sum.add(matrix[i][i]); 577 } 578 579 return sum; 580 } 581 582 /** Return a new matrix that is constructed by transposing the input 583 * matrix. If the input matrix is m x n, the output matrix will be 584 * n x m. 585 * @param matrix The input matrix. 586 * @return The matrix transpose. 587 */ 588 public static final Fraction[][] transpose(final Fraction[][] matrix) { 589 int rows = _rows(matrix); 590 int columns = _columns(matrix); 591 592 Fraction[][] returnValue = new Fraction[columns][rows]; 593 594 for (int i = 0; i < rows; i++) { 595 for (int j = 0; j < columns; j++) { 596 returnValue[j][i] = matrix[i][j]; 597 } 598 } 599 600 return returnValue; 601 } 602 603 /** Check that the two matrix arguments are of the same dimension. 604 * If they are not, an IllegalArgumentException is thrown. 605 * @param caller A string representing the caller method name. 606 * @param matrix1 A matrix of ints. 607 * @param matrix2 A matrix of ints. 608 */ 609 protected static final void _checkSameDimension(final String caller, 610 final Fraction[][] matrix1, final Fraction[][] matrix2) { 611 int rows = _rows(matrix1); 612 int columns = _columns(matrix1); 613 614 if (rows != _rows(matrix2) || columns != _columns(matrix2)) { 615 throw new IllegalArgumentException( 616 "ptolemy.math.FractionMatrixMath." + caller 617 + "() : one matrix " + _dimensionString(matrix1) 618 + " is not the same size as another matrix " 619 + _dimensionString(matrix2) + "."); 620 } 621 } 622 623 /** Check that the argument matrix is a square matrix. If the matrix is not 624 * square, an IllegalArgumentException is thrown. 625 * @param caller A string representing the caller method name. 626 * @param matrix A matrix of Fractions. 627 * @return The dimension of the square matrix. 628 */ 629 protected static final int _checkSquare(final String caller, 630 final Fraction[][] matrix) { 631 if (_rows(matrix) != _columns(matrix)) { 632 throw new IllegalArgumentException( 633 "ptolemy.math.FractionMatrixMath." + caller 634 + "() : matrix argument " + _dimensionString(matrix) 635 + " is not a square matrix."); 636 } 637 638 return _rows(matrix); 639 } 640 641 /** Return the number of columns of a matrix. 642 * @param matrix The matrix. 643 * @return The number of columns. 644 */ 645 protected static final int _columns(final Fraction[][] matrix) { 646 return matrix[0].length; 647 } 648 649 /** Return a string that describes the number of rows and columns. 650 * @param matrix The matrix that is to be described. 651 * @return a string describing the dimensions of this matrix. 652 */ 653 protected static final String _dimensionString(final Fraction[][] matrix) { 654 return "[" + _rows(matrix) + " x " + _columns(matrix) + "]"; 655 } 656 657 /** Return the number of rows of a matrix. */ 658 protected static final int _rows(final Fraction[][] matrix) { 659 return matrix.length; 660 } 661}