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