001 /*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements. See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License. You may obtain a copy of the License at
008 *
009 * http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017
018 package org.apache.commons.math.linear;
019
020 import java.io.IOException;
021 import java.io.ObjectInputStream;
022 import java.io.ObjectOutputStream;
023 import java.lang.reflect.Array;
024 import java.math.BigDecimal;
025 import java.util.Arrays;
026
027 import org.apache.commons.math.Field;
028 import org.apache.commons.math.FieldElement;
029 import org.apache.commons.math.MathRuntimeException;
030 import org.apache.commons.math.fraction.BigFraction;
031 import org.apache.commons.math.fraction.Fraction;
032
033 /**
034 * A collection of static methods that operate on or return matrices.
035 *
036 * @version $Revision: 903046 $ $Date: 2010-01-25 21:07:26 -0500 (Mon, 25 Jan 2010) $
037 */
038 public class MatrixUtils {
039
040 /**
041 * Private constructor.
042 */
043 private MatrixUtils() {
044 super();
045 }
046
047 /**
048 * Returns a {@link RealMatrix} with specified dimensions.
049 * <p>The type of matrix returned depends on the dimension. Below
050 * 2<sup>12</sup> elements (i.e. 4096 elements or 64×64 for a
051 * square matrix) which can be stored in a 32kB array, a {@link
052 * Array2DRowRealMatrix} instance is built. Above this threshold a {@link
053 * BlockRealMatrix} instance is built.</p>
054 * <p>The matrix elements are all set to 0.0.</p>
055 * @param rows number of rows of the matrix
056 * @param columns number of columns of the matrix
057 * @return RealMatrix with specified dimensions
058 * @see #createRealMatrix(double[][])
059 */
060 public static RealMatrix createRealMatrix(final int rows, final int columns) {
061 return (rows * columns <= 4096) ?
062 new Array2DRowRealMatrix(rows, columns) : new BlockRealMatrix(rows, columns);
063 }
064
065 /**
066 * Returns a {@link FieldMatrix} with specified dimensions.
067 * <p>The type of matrix returned depends on the dimension. Below
068 * 2<sup>12</sup> elements (i.e. 4096 elements or 64×64 for a
069 * square matrix), a {@link FieldMatrix} instance is built. Above
070 * this threshold a {@link BlockFieldMatrix} instance is built.</p>
071 * <p>The matrix elements are all set to field.getZero().</p>
072 * @param <T> the type of the field elements
073 * @param field field to which the matrix elements belong
074 * @param rows number of rows of the matrix
075 * @param columns number of columns of the matrix
076 * @return FieldMatrix with specified dimensions
077 * @see #createFieldMatrix(FieldElement[][])
078 * @since 2.0
079 */
080 public static <T extends FieldElement<T>> FieldMatrix<T> createFieldMatrix(final Field<T> field,
081 final int rows,
082 final int columns) {
083 return (rows * columns <= 4096) ?
084 new Array2DRowFieldMatrix<T>(field, rows, columns) : new BlockFieldMatrix<T>(field, rows, columns);
085 }
086
087 /**
088 * Returns a {@link RealMatrix} whose entries are the the values in the
089 * the input array.
090 * <p>The type of matrix returned depends on the dimension. Below
091 * 2<sup>12</sup> elements (i.e. 4096 elements or 64×64 for a
092 * square matrix) which can be stored in a 32kB array, a {@link
093 * Array2DRowRealMatrix} instance is built. Above this threshold a {@link
094 * BlockRealMatrix} instance is built.</p>
095 * <p>The input array is copied, not referenced.</p>
096 *
097 * @param data input array
098 * @return RealMatrix containing the values of the array
099 * @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 public static <T extends FieldElement<T>> FieldMatrix<T>
160 createFieldIdentityMatrix(final Field<T> field, final int dimension) {
161 final T zero = field.getZero();
162 final T one = field.getOne();
163 @SuppressWarnings("unchecked") // zero is type T
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 }