View Javadoc

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&times;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&times;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&times;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&times;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 }