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