    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.exception.util.LocalizedFormats;
    031    import org.apache.commons.math.fraction.BigFraction;
    032    import org.apache.commons.math.fraction.Fraction;
    033
    034    /**
    035     * A collection of static methods that operate on or return matrices.
    036     *
    037     * @version $Revision: 983921 $ $Date: 2010-08-10 12:46:06 +0200 (mar. 10 ao??t 2010) $
    038     */
    039    public class MatrixUtils {
    040
    041        /**
    042         * Private constructor.
    043         */
    044        private MatrixUtils() {
    045            super();
    046        }
    047
    048        /**
    049         * Returns a {@link RealMatrix} with specified dimensions.
    050         * <p>The type of matrix returned depends on the dimension. Below
    051         * 2<sup>12</sup> elements (i.e. 4096 elements or 64&times;64 for a
    052         * square matrix) which can be stored in a 32kB array, a {@link
    053         * Array2DRowRealMatrix} instance is built. Above this threshold a {@link
    054         * BlockRealMatrix} instance is built.</p>
    055         * <p>The matrix elements are all set to 0.0.</p>
    056         * @param rows number of rows of the matrix
    057         * @param columns number of columns of the matrix
    058         * @return  RealMatrix with specified dimensions
    059         * @see #createRealMatrix(double[][])
    060         */
    061        public static RealMatrix createRealMatrix(final int rows, final int columns) {
    062            return (rows * columns <= 4096) ?
    063                    new Array2DRowRealMatrix(rows, columns) : new BlockRealMatrix(rows, columns);
    064        }
    065
    066        /**
    067         * Returns a {@link FieldMatrix} with specified dimensions.
    068         * <p>The type of matrix returned depends on the dimension. Below
    069         * 2<sup>12</sup> elements (i.e. 4096 elements or 64&times;64 for a
    070         * square matrix), a {@link FieldMatrix} instance is built. Above
    071         * this threshold a {@link BlockFieldMatrix} instance is built.</p>
    072         * <p>The matrix elements are all set to field.getZero().</p>
    073         * @param <T> the type of the field elements
    074         * @param field field to which the matrix elements belong
    075         * @param rows number of rows of the matrix
    076         * @param columns number of columns of the matrix
    077         * @return  FieldMatrix with specified dimensions
    078         * @see #createFieldMatrix(FieldElement[][])
    079         * @since 2.0
    080         */
    081        public static <T extends FieldElement<T>> FieldMatrix<T> createFieldMatrix(final Field<T> field,
    082                                                                                   final int rows,
    083                                                                                   final int columns) {
    084            return (rows * columns <= 4096) ?
    085                    new Array2DRowFieldMatrix<T>(field, rows, columns) : new BlockFieldMatrix<T>(field, rows, columns);
    086        }
    087
    088        /**
    089         * Returns a {@link RealMatrix} whose entries are the the values in the
    090         * the input array.
    091         * <p>The type of matrix returned depends on the dimension. Below
    092         * 2<sup>12</sup> elements (i.e. 4096 elements or 64&times;64 for a
    093         * square matrix) which can be stored in a 32kB array, a {@link
    094         * Array2DRowRealMatrix} instance is built. Above this threshold a {@link
    095         * BlockRealMatrix} instance is built.</p>
    096         * <p>The input array is copied, not referenced.</p>
    097         *
    098         * @param data input array
    099         * @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    }