1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18 package org.apache.commons.math.linear; 19 20 import java.io.IOException; 21 import java.io.ObjectInputStream; 22 import java.io.ObjectOutputStream; 23 import java.lang.reflect.Array; 24 import java.math.BigDecimal; 25 import java.util.Arrays; 26 27 import org.apache.commons.math.Field; 28 import org.apache.commons.math.FieldElement; 29 import org.apache.commons.math.MathRuntimeException; 30 import org.apache.commons.math.fraction.BigFraction; 31 import org.apache.commons.math.fraction.Fraction; 32 33 /** 34 * A collection of static methods that operate on or return matrices. 35 * 36 * @version $Revision: 789156 $ $Date: 2009-06-28 17:48:15 -0400 (Sun, 28 Jun 2009) $ 37 */ 38 public class MatrixUtils { 39 40 /** 41 * Default constructor. 42 */ 43 public MatrixUtils() { 44 super(); 45 } 46 47 /** 48 * Returns a {@link RealMatrix} with specified dimensions. 49 * <p>The type of matrix returned depends on the dimension. Below 50 * 2<sup>12</sup> elements (i.e. 4096 elements or 64×64 for a 51 * square matrix) which can be stored in a 32kB array, a {@link 52 * Array2DRowRealMatrix} instance is built. Above this threshold a {@link 53 * BlockRealMatrix} instance is built.</p> 54 * <p>The matrix elements are all set to 0.0.</p> 55 * @param rows number of rows of the matrix 56 * @param columns number of columns of the matrix 57 * @return RealMatrix with specified dimensions 58 * @see #createRealMatrix(double[][]) 59 */ 60 public static RealMatrix createRealMatrix(final int rows, final int columns) { 61 return (rows * columns <= 4096) ? 62 new Array2DRowRealMatrix(rows, columns) : new BlockRealMatrix(rows, columns); 63 } 64 65 /** 66 * Returns a {@link FieldMatrix} with specified dimensions. 67 * <p>The type of matrix returned depends on the dimension. Below 68 * 2<sup>12</sup> elements (i.e. 4096 elements or 64×64 for a 69 * square matrix), a {@link FieldMatrix} instance is built. Above 70 * this threshold a {@link BlockFieldMatrix} instance is built.</p> 71 * <p>The matrix elements are all set to field.getZero().</p> 72 * @param <T> the type of the field elements 73 * @param field field to which the matrix elements belong 74 * @param rows number of rows of the matrix 75 * @param columns number of columns of the matrix 76 * @return FieldMatrix with specified dimensions 77 * @see #createFieldMatrix(FieldElement[][]) 78 * @since 2.0 79 */ 80 public static <T extends FieldElement<T>> FieldMatrix<T> createFieldMatrix(final Field<T> field, 81 final int rows, 82 final int columns) { 83 return (rows * columns <= 4096) ? 84 new Array2DRowFieldMatrix<T>(field, rows, columns) : new BlockFieldMatrix<T>(field, rows, columns); 85 } 86 87 /** 88 * Returns a {@link RealMatrix} whose entries are the the values in the 89 * the input array. 90 * <p>The type of matrix returned depends on the dimension. Below 91 * 2<sup>12</sup> elements (i.e. 4096 elements or 64×64 for a 92 * square matrix) which can be stored in a 32kB array, a {@link 93 * Array2DRowRealMatrix} instance is built. Above this threshold a {@link 94 * BlockRealMatrix} instance is built.</p> 95 * <p>The input array is copied, not referenced.</p> 96 * 97 * @param data input array 98 * @return RealMatrix containing the values of the array 99 * @throws IllegalArgumentException if <code>data</code> is not rectangular 100 * (not all rows have the same length) or empty 101 * @throws NullPointerException if either <code>data</code> or 102 * <code>data[0]</code> is null 103 * @see #createRealMatrix(int, int) 104 */ 105 public static RealMatrix createRealMatrix(double[][] data) { 106 return (data.length * data[0].length <= 4096) ? 107 new Array2DRowRealMatrix(data) : new BlockRealMatrix(data); 108 } 109 110 /** 111 * Returns a {@link FieldMatrix} whose entries are the the values in the 112 * the input array. 113 * <p>The type of matrix returned depends on the dimension. Below 114 * 2<sup>12</sup> elements (i.e. 4096 elements or 64×64 for a 115 * square matrix), a {@link FieldMatrix} instance is built. Above 116 * this threshold a {@link BlockFieldMatrix} instance is built.</p> 117 * <p>The input array is copied, not referenced.</p> 118 * @param <T> the type of the field elements 119 * @param data input array 120 * @return RealMatrix containing the values of the array 121 * @throws IllegalArgumentException if <code>data</code> is not rectangular 122 * (not all rows have the same length) or empty 123 * @throws NullPointerException if either <code>data</code> or 124 * <code>data[0]</code> is null 125 * @see #createFieldMatrix(Field, int, int) 126 * @since 2.0 127 */ 128 public static <T extends FieldElement<T>> FieldMatrix<T> createFieldMatrix(T[][] data) { 129 return (data.length * data[0].length <= 4096) ? 130 new Array2DRowFieldMatrix<T>(data) : new BlockFieldMatrix<T>(data); 131 } 132 133 /** 134 * Returns <code>dimension x dimension</code> identity matrix. 135 * 136 * @param dimension dimension of identity matrix to generate 137 * @return identity matrix 138 * @throws IllegalArgumentException if dimension is not positive 139 * @since 1.1 140 */ 141 public static RealMatrix createRealIdentityMatrix(int dimension) { 142 final RealMatrix m = createRealMatrix(dimension, dimension); 143 for (int i = 0; i < dimension; ++i) { 144 m.setEntry(i, i, 1.0); 145 } 146 return m; 147 } 148 149 /** 150 * Returns <code>dimension x dimension</code> identity matrix. 151 * 152 * @param <T> the type of the field elements 153 * @param field field to which the elements belong 154 * @param dimension dimension of identity matrix to generate 155 * @return identity matrix 156 * @throws IllegalArgumentException if dimension is not positive 157 * @since 2.0 158 */ 159 @SuppressWarnings("unchecked") 160 public static <T extends FieldElement<T>> FieldMatrix<T> 161 createFieldIdentityMatrix(final Field<T> field, final int dimension) { 162 final T zero = field.getZero(); 163 final T one = field.getOne(); 164 final T[][] d = (T[][]) Array.newInstance(zero.getClass(), new int[] { dimension, dimension }); 165 for (int row = 0; row < dimension; row++) { 166 final T[] dRow = d[row]; 167 Arrays.fill(dRow, zero); 168 dRow[row] = one; 169 } 170 return new Array2DRowFieldMatrix<T>(d, false); 171 } 172 173 /** 174 * Returns <code>dimension x dimension</code> identity matrix. 175 * 176 * @param dimension dimension of identity matrix to generate 177 * @return identity matrix 178 * @throws IllegalArgumentException if dimension is not positive 179 * @since 1.1 180 * @deprecated since 2.0, replaced by {@link #createFieldIdentityMatrix(Field, int)} 181 */ 182 @Deprecated 183 public static BigMatrix createBigIdentityMatrix(int dimension) { 184 final BigDecimal[][] d = new BigDecimal[dimension][dimension]; 185 for (int row = 0; row < dimension; row++) { 186 final BigDecimal[] dRow = d[row]; 187 Arrays.fill(dRow, BigMatrixImpl.ZERO); 188 dRow[row] = BigMatrixImpl.ONE; 189 } 190 return new BigMatrixImpl(d, false); 191 } 192 193 /** 194 * Returns a diagonal matrix with specified elements. 195 * 196 * @param diagonal diagonal elements of the matrix (the array elements 197 * will be copied) 198 * @return diagonal matrix 199 * @since 2.0 200 */ 201 public static RealMatrix createRealDiagonalMatrix(final double[] diagonal) { 202 final RealMatrix m = createRealMatrix(diagonal.length, diagonal.length); 203 for (int i = 0; i < diagonal.length; ++i) { 204 m.setEntry(i, i, diagonal[i]); 205 } 206 return m; 207 } 208 209 /** 210 * Returns a diagonal matrix with specified elements. 211 * 212 * @param <T> the type of the field elements 213 * @param diagonal diagonal elements of the matrix (the array elements 214 * will be copied) 215 * @return diagonal matrix 216 * @since 2.0 217 */ 218 public static <T extends FieldElement<T>> FieldMatrix<T> 219 createFieldDiagonalMatrix(final T[] diagonal) { 220 final FieldMatrix<T> m = 221 createFieldMatrix(diagonal[0].getField(), diagonal.length, diagonal.length); 222 for (int i = 0; i < diagonal.length; ++i) { 223 m.setEntry(i, i, diagonal[i]); 224 } 225 return m; 226 } 227 228 /** 229 * Returns a {@link BigMatrix} whose entries are the the values in the 230 * the input array. The input array is copied, not referenced. 231 * 232 * @param data input array 233 * @return RealMatrix containing the values of the array 234 * @throws IllegalArgumentException if <code>data</code> is not rectangular 235 * (not all rows have the same length) or empty 236 * @throws NullPointerException if data is null 237 * @deprecated since 2.0 replaced by {@link #createFieldMatrix(FieldElement[][])} 238 */ 239 @Deprecated 240 public static BigMatrix createBigMatrix(double[][] data) { 241 return new BigMatrixImpl(data); 242 } 243 244 /** 245 * Returns a {@link BigMatrix} whose entries are the the values in the 246 * the input array. The input array is copied, not referenced. 247 * 248 * @param data input array 249 * @return RealMatrix containing the values of the array 250 * @throws IllegalArgumentException if <code>data</code> is not rectangular 251 * (not all rows have the same length) or empty 252 * @throws NullPointerException if data is null 253 * @deprecated since 2.0 replaced by {@link #createFieldMatrix(FieldElement[][])} 254 */ 255 @Deprecated 256 public static BigMatrix createBigMatrix(BigDecimal[][] data) { 257 return new BigMatrixImpl(data); 258 } 259 260 /** 261 * Returns a {@link BigMatrix} whose entries are the the values in the 262 * the input array. 263 * <p>If an array is built specially in order to be embedded in a 264 * BigMatrix and not used directly, the <code>copyArray</code> may be 265 * set to <code>false</code. This will prevent the copying and improve 266 * performance as no new array will be built and no data will be copied.</p> 267 * @param data data for new matrix 268 * @param copyArray if true, the input array will be copied, otherwise 269 * it will be referenced 270 * @return BigMatrix containing the values of the array 271 * @throws IllegalArgumentException if <code>data</code> is not rectangular 272 * (not all rows have the same length) or empty 273 * @throws NullPointerException if <code>data</code> is null 274 * @see #createRealMatrix(double[][]) 275 * @deprecated since 2.0 replaced by {@link #createFieldMatrix(FieldElement[][])} 276 */ 277 @Deprecated 278 public static BigMatrix createBigMatrix(BigDecimal[][] data, boolean copyArray) { 279 return new BigMatrixImpl(data, copyArray); 280 } 281 282 /** 283 * Returns a {@link BigMatrix} whose entries are the the values in the 284 * the input array. The input array is copied, not referenced. 285 * 286 * @param data input array 287 * @return RealMatrix containing the values of the array 288 * @throws IllegalArgumentException if <code>data</code> is not rectangular 289 * (not all rows have the same length) or empty 290 * @throws NullPointerException if data is null 291 * @deprecated since 2.0 replaced by {@link #createFieldMatrix(FieldElement[][])} 292 */ 293 @Deprecated 294 public static BigMatrix createBigMatrix(String[][] data) { 295 return new BigMatrixImpl(data); 296 } 297 298 /** 299 * Creates a {@link RealVector} using the data from the input array. 300 * 301 * @param data the input data 302 * @return a data.length RealVector 303 * @throws IllegalArgumentException if <code>data</code> is empty 304 * @throws NullPointerException if <code>data</code>is null 305 */ 306 public static RealVector createRealVector(double[] data) { 307 return new ArrayRealVector(data, true); 308 } 309 310 /** 311 * Creates a {@link FieldVector} using the data from the input array. 312 * 313 * @param <T> the type of the field elements 314 * @param data the input data 315 * @return a data.length FieldVector 316 * @throws IllegalArgumentException if <code>data</code> is empty 317 * @throws NullPointerException if <code>data</code>is null 318 */ 319 public static <T extends FieldElement<T>> FieldVector<T> createFieldVector(final T[] data) { 320 return new ArrayFieldVector<T>(data, true); 321 } 322 323 /** 324 * Creates a row {@link RealMatrix} using the data from the input 325 * array. 326 * 327 * @param rowData the input row data 328 * @return a 1 x rowData.length RealMatrix 329 * @throws IllegalArgumentException if <code>rowData</code> is empty 330 * @throws NullPointerException if <code>rowData</code>is null 331 */ 332 public static RealMatrix createRowRealMatrix(double[] rowData) { 333 final int nCols = rowData.length; 334 final RealMatrix m = createRealMatrix(1, nCols); 335 for (int i = 0; i < nCols; ++i) { 336 m.setEntry(0, i, rowData[i]); 337 } 338 return m; 339 } 340 341 /** 342 * Creates a row {@link FieldMatrix} using the data from the input 343 * array. 344 * 345 * @param <T> the type of the field elements 346 * @param rowData the input row data 347 * @return a 1 x rowData.length FieldMatrix 348 * @throws IllegalArgumentException if <code>rowData</code> is empty 349 * @throws NullPointerException if <code>rowData</code>is null 350 */ 351 public static <T extends FieldElement<T>> FieldMatrix<T> 352 createRowFieldMatrix(final T[] rowData) { 353 final int nCols = rowData.length; 354 if (nCols == 0) { 355 throw MathRuntimeException.createIllegalArgumentException("matrix must have at least one column"); 356 } 357 final FieldMatrix<T> m = createFieldMatrix(rowData[0].getField(), 1, nCols); 358 for (int i = 0; i < nCols; ++i) { 359 m.setEntry(0, i, rowData[i]); 360 } 361 return m; 362 } 363 364 /** 365 * Creates a row {@link BigMatrix} using the data from the input 366 * array. 367 * 368 * @param rowData the input row data 369 * @return a 1 x rowData.length BigMatrix 370 * @throws IllegalArgumentException if <code>rowData</code> is empty 371 * @throws NullPointerException if <code>rowData</code>is null 372 * @deprecated since 2.0 replaced by {@link #createRowFieldMatrix(FieldElement[])} 373 */ 374 @Deprecated 375 public static BigMatrix createRowBigMatrix(double[] rowData) { 376 final int nCols = rowData.length; 377 final BigDecimal[][] data = new BigDecimal[1][nCols]; 378 for (int i = 0; i < nCols; ++i) { 379 data[0][i] = new BigDecimal(rowData[i]); 380 } 381 return new BigMatrixImpl(data, false); 382 } 383 384 /** 385 * Creates a row {@link BigMatrix} using the data from the input 386 * array. 387 * 388 * @param rowData the input row data 389 * @return a 1 x rowData.length BigMatrix 390 * @throws IllegalArgumentException if <code>rowData</code> is empty 391 * @throws NullPointerException if <code>rowData</code>is null 392 * @deprecated since 2.0 replaced by {@link #createRowFieldMatrix(FieldElement[])} 393 */ 394 @Deprecated 395 public static BigMatrix createRowBigMatrix(BigDecimal[] rowData) { 396 final int nCols = rowData.length; 397 final BigDecimal[][] data = new BigDecimal[1][nCols]; 398 System.arraycopy(rowData, 0, data[0], 0, nCols); 399 return new BigMatrixImpl(data, false); 400 } 401 402 /** 403 * Creates a row {@link BigMatrix} using the data from the input 404 * array. 405 * 406 * @param rowData the input row data 407 * @return a 1 x rowData.length BigMatrix 408 * @throws IllegalArgumentException if <code>rowData</code> is empty 409 * @throws NullPointerException if <code>rowData</code>is null 410 * @deprecated since 2.0 replaced by {@link #createRowFieldMatrix(FieldElement[])} 411 */ 412 @Deprecated 413 public static BigMatrix createRowBigMatrix(String[] rowData) { 414 final int nCols = rowData.length; 415 final BigDecimal[][] data = new BigDecimal[1][nCols]; 416 for (int i = 0; i < nCols; ++i) { 417 data[0][i] = new BigDecimal(rowData[i]); 418 } 419 return new BigMatrixImpl(data, false); 420 } 421 422 /** 423 * Creates a column {@link RealMatrix} using the data from the input 424 * array. 425 * 426 * @param columnData the input column data 427 * @return a columnData x 1 RealMatrix 428 * @throws IllegalArgumentException if <code>columnData</code> is empty 429 * @throws NullPointerException if <code>columnData</code>is null 430 */ 431 public static RealMatrix createColumnRealMatrix(double[] columnData) { 432 final int nRows = columnData.length; 433 final RealMatrix m = createRealMatrix(nRows, 1); 434 for (int i = 0; i < nRows; ++i) { 435 m.setEntry(i, 0, columnData[i]); 436 } 437 return m; 438 } 439 440 /** 441 * Creates a column {@link FieldMatrix} using the data from the input 442 * array. 443 * 444 * @param <T> the type of the field elements 445 * @param columnData the input column data 446 * @return a columnData x 1 FieldMatrix 447 * @throws IllegalArgumentException if <code>columnData</code> is empty 448 * @throws NullPointerException if <code>columnData</code>is null 449 */ 450 public static <T extends FieldElement<T>> FieldMatrix<T> 451 createColumnFieldMatrix(final T[] columnData) { 452 final int nRows = columnData.length; 453 if (nRows == 0) { 454 throw MathRuntimeException.createIllegalArgumentException("matrix must have at least one row"); 455 } 456 final FieldMatrix<T> m = createFieldMatrix(columnData[0].getField(), nRows, 1); 457 for (int i = 0; i < nRows; ++i) { 458 m.setEntry(i, 0, columnData[i]); 459 } 460 return m; 461 } 462 463 /** 464 * Creates a column {@link BigMatrix} using the data from the input 465 * array. 466 * 467 * @param columnData the input column data 468 * @return a columnData x 1 BigMatrix 469 * @throws IllegalArgumentException if <code>columnData</code> is empty 470 * @throws NullPointerException if <code>columnData</code>is null 471 * @deprecated since 2.0 replaced by {@link #createColumnFieldMatrix(FieldElement[])} 472 */ 473 @Deprecated 474 public static BigMatrix createColumnBigMatrix(double[] columnData) { 475 final int nRows = columnData.length; 476 final BigDecimal[][] data = new BigDecimal[nRows][1]; 477 for (int row = 0; row < nRows; row++) { 478 data[row][0] = new BigDecimal(columnData[row]); 479 } 480 return new BigMatrixImpl(data, false); 481 } 482 483 /** 484 * Creates a column {@link BigMatrix} using the data from the input 485 * array. 486 * 487 * @param columnData the input column data 488 * @return a columnData x 1 BigMatrix 489 * @throws IllegalArgumentException if <code>columnData</code> is empty 490 * @throws NullPointerException if <code>columnData</code>is null 491 * @deprecated since 2.0 replaced by {@link #createColumnFieldMatrix(FieldElement[])} 492 */ 493 @Deprecated 494 public static BigMatrix createColumnBigMatrix(BigDecimal[] columnData) { 495 final int nRows = columnData.length; 496 final BigDecimal[][] data = new BigDecimal[nRows][1]; 497 for (int row = 0; row < nRows; row++) { 498 data[row][0] = columnData[row]; 499 } 500 return new BigMatrixImpl(data, false); 501 } 502 503 /** 504 * Creates a column {@link BigMatrix} using the data from the input 505 * array. 506 * 507 * @param columnData the input column data 508 * @return a columnData x 1 BigMatrix 509 * @throws IllegalArgumentException if <code>columnData</code> is empty 510 * @throws NullPointerException if <code>columnData</code>is null 511 * @deprecated since 2.0 replaced by {@link #createColumnFieldMatrix(FieldElement[])} 512 */ 513 @Deprecated 514 public static BigMatrix createColumnBigMatrix(String[] columnData) { 515 int nRows = columnData.length; 516 final BigDecimal[][] data = new BigDecimal[nRows][1]; 517 for (int row = 0; row < nRows; row++) { 518 data[row][0] = new BigDecimal(columnData[row]); 519 } 520 return new BigMatrixImpl(data, false); 521 } 522 523 /** 524 * Check if a row index is valid. 525 * @param m matrix containing the submatrix 526 * @param row row index to check 527 * @exception MatrixIndexException if index is not valid 528 */ 529 public static void checkRowIndex(final AnyMatrix m, final int row) { 530 if (row < 0 || row >= m.getRowDimension()) { 531 throw new MatrixIndexException("row index {0} out of allowed range [{1}, {2}]", 532 row, 0, m.getRowDimension() - 1); 533 } 534 } 535 536 /** 537 * Check if a column index is valid. 538 * @param m matrix containing the submatrix 539 * @param column column index to check 540 * @exception MatrixIndexException if index is not valid 541 */ 542 public static void checkColumnIndex(final AnyMatrix m, final int column) 543 throws MatrixIndexException { 544 if (column < 0 || column >= m.getColumnDimension()) { 545 throw new MatrixIndexException("column index {0} out of allowed range [{1}, {2}]", 546 column, 0, m.getColumnDimension() - 1); 547 } 548 } 549 550 /** 551 * Check if submatrix ranges indices are valid. 552 * Rows and columns are indicated counting from 0 to n-1. 553 * 554 * @param m matrix containing the submatrix 555 * @param startRow Initial row index 556 * @param endRow Final row index 557 * @param startColumn Initial column index 558 * @param endColumn Final column index 559 * @exception MatrixIndexException if the indices are not valid 560 */ 561 public static void checkSubMatrixIndex(final AnyMatrix m, 562 final int startRow, final int endRow, 563 final int startColumn, final int endColumn) { 564 checkRowIndex(m, startRow); 565 checkRowIndex(m, endRow); 566 if (startRow > endRow) { 567 throw new MatrixIndexException("initial row {0} after final row {1}", 568 startRow, endRow); 569 } 570 571 checkColumnIndex(m, startColumn); 572 checkColumnIndex(m, endColumn); 573 if (startColumn > endColumn) { 574 throw new MatrixIndexException("initial column {0} after final column {1}", 575 startColumn, endColumn); 576 } 577 578 579 } 580 581 /** 582 * Check if submatrix ranges indices are valid. 583 * Rows and columns are indicated counting from 0 to n-1. 584 * 585 * @param m matrix containing the submatrix 586 * @param selectedRows Array of row indices. 587 * @param selectedColumns Array of column indices. 588 * @exception MatrixIndexException if row or column selections are not valid 589 */ 590 public static void checkSubMatrixIndex(final AnyMatrix m, 591 final int[] selectedRows, final int[] selectedColumns) 592 throws MatrixIndexException { 593 if (selectedRows.length * selectedColumns.length == 0) { 594 if (selectedRows.length == 0) { 595 throw new MatrixIndexException("empty selected row index array"); 596 } 597 throw new MatrixIndexException("empty selected column index array"); 598 } 599 600 for (final int row : selectedRows) { 601 checkRowIndex(m, row); 602 } 603 for (final int column : selectedColumns) { 604 checkColumnIndex(m, column); 605 } 606 } 607 608 /** 609 * Check if matrices are addition compatible 610 * @param left left hand side matrix 611 * @param right right hand side matrix 612 * @exception IllegalArgumentException if matrices are not addition compatible 613 */ 614 public static void checkAdditionCompatible(final AnyMatrix left, final AnyMatrix right) 615 throws IllegalArgumentException { 616 if ((left.getRowDimension() != right.getRowDimension()) || 617 (left.getColumnDimension() != right.getColumnDimension())) { 618 throw MathRuntimeException.createIllegalArgumentException( 619 "{0}x{1} and {2}x{3} matrices are not addition compatible", 620 left.getRowDimension(), left.getColumnDimension(), 621 right.getRowDimension(), right.getColumnDimension()); 622 } 623 } 624 625 /** 626 * Check if matrices are subtraction compatible 627 * @param left left hand side matrix 628 * @param right right hand side matrix 629 * @exception IllegalArgumentException if matrices are not subtraction compatible 630 */ 631 public static void checkSubtractionCompatible(final AnyMatrix left, final AnyMatrix right) 632 throws IllegalArgumentException { 633 if ((left.getRowDimension() != right.getRowDimension()) || 634 (left.getColumnDimension() != right.getColumnDimension())) { 635 throw MathRuntimeException.createIllegalArgumentException( 636 "{0}x{1} and {2}x{3} matrices are not subtraction compatible", 637 left.getRowDimension(), left.getColumnDimension(), 638 right.getRowDimension(), right.getColumnDimension()); 639 } 640 } 641 642 /** 643 * Check if matrices are multiplication compatible 644 * @param left left hand side matrix 645 * @param right right hand side matrix 646 * @exception IllegalArgumentException if matrices are not multiplication compatible 647 */ 648 public static void checkMultiplicationCompatible(final AnyMatrix left, final AnyMatrix right) 649 throws IllegalArgumentException { 650 if (left.getColumnDimension() != right.getRowDimension()) { 651 throw MathRuntimeException.createIllegalArgumentException( 652 "{0}x{1} and {2}x{3} matrices are not multiplication compatible", 653 left.getRowDimension(), left.getColumnDimension(), 654 right.getRowDimension(), right.getColumnDimension()); 655 } 656 } 657 658 /** 659 * Convert a {@link FieldMatrix}/{@link Fraction} matrix to a {@link RealMatrix}. 660 * @param m matrix to convert 661 * @return converted matrix 662 */ 663 public static Array2DRowRealMatrix fractionMatrixToRealMatrix(final FieldMatrix<Fraction> m) { 664 final FractionMatrixConverter converter = new FractionMatrixConverter(); 665 m.walkInOptimizedOrder(converter); 666 return converter.getConvertedMatrix(); 667 } 668 669 /** Converter for {@link FieldMatrix}/{@link Fraction}. */ 670 private static class FractionMatrixConverter extends DefaultFieldMatrixPreservingVisitor<Fraction> { 671 672 /** Converted array. */ 673 private double[][] data; 674 675 /** Simple constructor. */ 676 public FractionMatrixConverter() { 677 super(Fraction.ZERO); 678 } 679 680 /** {@inheritDoc} */ 681 @Override 682 public void start(int rows, int columns, 683 int startRow, int endRow, int startColumn, int endColumn) { 684 data = new double[rows][columns]; 685 } 686 687 /** {@inheritDoc} */ 688 @Override 689 public void visit(int row, int column, Fraction value) { 690 data[row][column] = value.doubleValue(); 691 } 692 693 /** Get the converted matrix. 694 * @return converted matrix 695 */ 696 Array2DRowRealMatrix getConvertedMatrix() { 697 return new Array2DRowRealMatrix(data, false); 698 } 699 700 } 701 702 /** 703 * Convert a {@link FieldMatrix}/{@link BigFraction} matrix to a {@link RealMatrix}. 704 * @param m matrix to convert 705 * @return converted matrix 706 */ 707 public static Array2DRowRealMatrix bigFractionMatrixToRealMatrix(final FieldMatrix<BigFraction> m) { 708 final BigFractionMatrixConverter converter = new BigFractionMatrixConverter(); 709 m.walkInOptimizedOrder(converter); 710 return converter.getConvertedMatrix(); 711 } 712 713 /** Converter for {@link FieldMatrix}/{@link BigFraction}. */ 714 private static class BigFractionMatrixConverter extends DefaultFieldMatrixPreservingVisitor<BigFraction> { 715 716 /** Converted array. */ 717 private double[][] data; 718 719 /** Simple constructor. */ 720 public BigFractionMatrixConverter() { 721 super(BigFraction.ZERO); 722 } 723 724 /** {@inheritDoc} */ 725 @Override 726 public void start(int rows, int columns, 727 int startRow, int endRow, int startColumn, int endColumn) { 728 data = new double[rows][columns]; 729 } 730 731 /** {@inheritDoc} */ 732 @Override 733 public void visit(int row, int column, BigFraction value) { 734 data[row][column] = value.doubleValue(); 735 } 736 737 /** Get the converted matrix. 738 * @return converted matrix 739 */ 740 Array2DRowRealMatrix getConvertedMatrix() { 741 return new Array2DRowRealMatrix(data, false); 742 } 743 744 } 745 746 /** Serialize a {@link RealVector}. 747 * <p> 748 * This method is intended to be called from within a private 749 * <code>writeObject</code> method (after a call to 750 * <code>oos.defaultWriteObject()</code>) in a class that has a 751 * {@link RealVector} field, which should be declared <code>transient</code>. 752 * This way, the default handling does not serialize the vector (the {@link 753 * RealVector} interface is not serializable by default) but this method does 754 * serialize it specifically. 755 * </p> 756 * <p> 757 * The following example shows how a simple class with a name and a real vector 758 * should be written: 759 * <pre><code> 760 * public class NamedVector implements Serializable { 761 * 762 * private final String name; 763 * private final transient RealVector coefficients; 764 * 765 * // omitted constructors, getters ... 766 * 767 * private void writeObject(ObjectOutputStream oos) throws IOException { 768 * oos.defaultWriteObject(); // takes care of name field 769 * MatrixUtils.serializeRealVector(coefficients, oos); 770 * } 771 * 772 * private void readObject(ObjectInputStream ois) throws ClassNotFoundException, IOException { 773 * ois.defaultReadObject(); // takes care of name field 774 * MatrixUtils.deserializeRealVector(this, "coefficients", ois); 775 * } 776 * 777 * } 778 * </code></pre> 779 * </p> 780 * 781 * @param vector real vector to serialize 782 * @param oos stream where the real vector should be written 783 * @exception IOException if object cannot be written to stream 784 * @see #deserializeRealVector(Object, String, ObjectInputStream) 785 */ 786 public static void serializeRealVector(final RealVector vector, 787 final ObjectOutputStream oos) 788 throws IOException { 789 final int n = vector.getDimension(); 790 oos.writeInt(n); 791 for (int i = 0; i < n; ++i) { 792 oos.writeDouble(vector.getEntry(i)); 793 } 794 } 795 796 /** Deserialize a {@link RealVector} field in a class. 797 * <p> 798 * This method is intended to be called from within a private 799 * <code>readObject</code> method (after a call to 800 * <code>ois.defaultReadObject()</code>) in a class that has a 801 * {@link RealVector} field, which should be declared <code>transient</code>. 802 * This way, the default handling does not deserialize the vector (the {@link 803 * RealVector} interface is not serializable by default) but this method does 804 * deserialize it specifically. 805 * </p> 806 * @param instance instance in which the field must be set up 807 * @param fieldName name of the field within the class (may be private and final) 808 * @param ois stream from which the real vector should be read 809 * @exception ClassNotFoundException if a class in the stream cannot be found 810 * @exception IOException if object cannot be read from the stream 811 * @see #serializeRealVector(RealVector, ObjectOutputStream) 812 */ 813 public static void deserializeRealVector(final Object instance, 814 final String fieldName, 815 final ObjectInputStream ois) 816 throws ClassNotFoundException, IOException { 817 try { 818 819 // read the vector data 820 final int n = ois.readInt(); 821 final double[] data = new double[n]; 822 for (int i = 0; i < n; ++i) { 823 data[i] = ois.readDouble(); 824 } 825 826 // create the instance 827 final RealVector vector = new ArrayRealVector(data, false); 828 829 // set up the field 830 final java.lang.reflect.Field f = 831 instance.getClass().getDeclaredField(fieldName); 832 f.setAccessible(true); 833 f.set(instance, vector); 834 835 } catch (NoSuchFieldException nsfe) { 836 IOException ioe = new IOException(); 837 ioe.initCause(nsfe); 838 throw ioe; 839 } catch (IllegalAccessException iae) { 840 IOException ioe = new IOException(); 841 ioe.initCause(iae); 842 throw ioe; 843 } 844 845 } 846 847 /** Serialize a {@link RealMatrix}. 848 * <p> 849 * This method is intended to be called from within a private 850 * <code>writeObject</code> method (after a call to 851 * <code>oos.defaultWriteObject()</code>) in a class that has a 852 * {@link RealMatrix} field, which should be declared <code>transient</code>. 853 * This way, the default handling does not serialize the matrix (the {@link 854 * RealMatrix} interface is not serializable by default) but this method does 855 * serialize it specifically. 856 * </p> 857 * <p> 858 * The following example shows how a simple class with a name and a real matrix 859 * should be written: 860 * <pre><code> 861 * public class NamedMatrix implements Serializable { 862 * 863 * private final String name; 864 * private final transient RealMatrix coefficients; 865 * 866 * // omitted constructors, getters ... 867 * 868 * private void writeObject(ObjectOutputStream oos) throws IOException { 869 * oos.defaultWriteObject(); // takes care of name field 870 * MatrixUtils.serializeRealMatrix(coefficients, oos); 871 * } 872 * 873 * private void readObject(ObjectInputStream ois) throws ClassNotFoundException, IOException { 874 * ois.defaultReadObject(); // takes care of name field 875 * MatrixUtils.deserializeRealMatrix(this, "coefficients", ois); 876 * } 877 * 878 * } 879 * </code></pre> 880 * </p> 881 * 882 * @param matrix real matrix to serialize 883 * @param oos stream where the real matrix should be written 884 * @exception IOException if object cannot be written to stream 885 * @see #deserializeRealMatrix(Object, String, ObjectInputStream) 886 */ 887 public static void serializeRealMatrix(final RealMatrix matrix, 888 final ObjectOutputStream oos) 889 throws IOException { 890 final int n = matrix.getRowDimension(); 891 final int m = matrix.getColumnDimension(); 892 oos.writeInt(n); 893 oos.writeInt(m); 894 for (int i = 0; i < n; ++i) { 895 for (int j = 0; j < m; ++j) { 896 oos.writeDouble(matrix.getEntry(i, j)); 897 } 898 } 899 } 900 901 /** Deserialize a {@link RealMatrix} field in a class. 902 * <p> 903 * This method is intended to be called from within a private 904 * <code>readObject</code> method (after a call to 905 * <code>ois.defaultReadObject()</code>) in a class that has a 906 * {@link RealMatrix} field, which should be declared <code>transient</code>. 907 * This way, the default handling does not deserialize the matrix (the {@link 908 * RealMatrix} interface is not serializable by default) but this method does 909 * deserialize it specifically. 910 * </p> 911 * @param instance instance in which the field must be set up 912 * @param fieldName name of the field within the class (may be private and final) 913 * @param ois stream from which the real matrix should be read 914 * @exception ClassNotFoundException if a class in the stream cannot be found 915 * @exception IOException if object cannot be read from the stream 916 * @see #serializeRealMatrix(RealMatrix, ObjectOutputStream) 917 */ 918 public static void deserializeRealMatrix(final Object instance, 919 final String fieldName, 920 final ObjectInputStream ois) 921 throws ClassNotFoundException, IOException { 922 try { 923 924 // read the matrix data 925 final int n = ois.readInt(); 926 final int m = ois.readInt(); 927 final double[][] data = new double[n][m]; 928 for (int i = 0; i < n; ++i) { 929 final double[] dataI = data[i]; 930 for (int j = 0; j < m; ++j) { 931 dataI[j] = ois.readDouble(); 932 } 933 } 934 935 // create the instance 936 final RealMatrix matrix = new Array2DRowRealMatrix(data, false); 937 938 // set up the field 939 final java.lang.reflect.Field f = 940 instance.getClass().getDeclaredField(fieldName); 941 f.setAccessible(true); 942 f.set(instance, matrix); 943 944 } catch (NoSuchFieldException nsfe) { 945 IOException ioe = new IOException(); 946 ioe.initCause(nsfe); 947 throw ioe; 948 } catch (IllegalAccessException iae) { 949 IOException ioe = new IOException(); 950 ioe.initCause(iae); 951 throw ioe; 952 } 953 954 } 955 956 }