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