Home | History | Annotate | Download | only in linear
      1 /*
      2  * Licensed to the Apache Software Foundation (ASF) under one or more
      3  * contributor license agreements.  See the NOTICE file distributed with
      4  * this work for additional information regarding copyright ownership.
      5  * The ASF licenses this file to You under the Apache License, Version 2.0
      6  * (the "License"); you may not use this file except in compliance with
      7  * the License.  You may obtain a copy of the License at
      8  *
      9  *      http://www.apache.org/licenses/LICENSE-2.0
     10  *
     11  * Unless required by applicable law or agreed to in writing, software
     12  * distributed under the License is distributed on an "AS IS" BASIS,
     13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     14  * See the License for the specific language governing permissions and
     15  * limitations under the License.
     16  */
     17 
     18 package org.apache.commons.math.linear;
     19 
     20 import java.io.IOException;
     21 import java.io.ObjectInputStream;
     22 import java.io.ObjectOutputStream;
     23 import java.lang.reflect.Array;
     24 import java.math.BigDecimal;
     25 import java.util.Arrays;
     26 
     27 import org.apache.commons.math.Field;
     28 import org.apache.commons.math.FieldElement;
     29 import org.apache.commons.math.MathRuntimeException;
     30 import org.apache.commons.math.exception.util.LocalizedFormats;
     31 import org.apache.commons.math.fraction.BigFraction;
     32 import org.apache.commons.math.fraction.Fraction;
     33 
     34 /**
     35  * A collection of static methods that operate on or return matrices.
     36  *
     37  * @version $Revision: 983921 $ $Date: 2010-08-10 12:46:06 +0200 (mar. 10 aot 2010) $
     38  */
     39 public class MatrixUtils {
     40 
     41     /**
     42      * Private constructor.
     43      */
     44     private MatrixUtils() {
     45         super();
     46     }
     47 
     48     /**
     49      * Returns a {@link RealMatrix} with specified dimensions.
     50      * <p>The type of matrix returned depends on the dimension. Below
     51      * 2<sup>12</sup> elements (i.e. 4096 elements or 64&times;64 for a
     52      * square matrix) which can be stored in a 32kB array, a {@link
     53      * Array2DRowRealMatrix} instance is built. Above this threshold a {@link
     54      * BlockRealMatrix} instance is built.</p>
     55      * <p>The matrix elements are all set to 0.0.</p>
     56      * @param rows number of rows of the matrix
     57      * @param columns number of columns of the matrix
     58      * @return  RealMatrix with specified dimensions
     59      * @see #createRealMatrix(double[][])
     60      */
     61     public static RealMatrix createRealMatrix(final int rows, final int columns) {
     62         return (rows * columns <= 4096) ?
     63                 new Array2DRowRealMatrix(rows, columns) : new BlockRealMatrix(rows, columns);
     64     }
     65 
     66     /**
     67      * Returns a {@link FieldMatrix} with specified dimensions.
     68      * <p>The type of matrix returned depends on the dimension. Below
     69      * 2<sup>12</sup> elements (i.e. 4096 elements or 64&times;64 for a
     70      * square matrix), a {@link FieldMatrix} instance is built. Above
     71      * this threshold a {@link BlockFieldMatrix} instance is built.</p>
     72      * <p>The matrix elements are all set to field.getZero().</p>
     73      * @param <T> the type of the field elements
     74      * @param field field to which the matrix elements belong
     75      * @param rows number of rows of the matrix
     76      * @param columns number of columns of the matrix
     77      * @return  FieldMatrix with specified dimensions
     78      * @see #createFieldMatrix(FieldElement[][])
     79      * @since 2.0
     80      */
     81     public static <T extends FieldElement<T>> FieldMatrix<T> createFieldMatrix(final Field<T> field,
     82                                                                                final int rows,
     83                                                                                final int columns) {
     84         return (rows * columns <= 4096) ?
     85                 new Array2DRowFieldMatrix<T>(field, rows, columns) : new BlockFieldMatrix<T>(field, rows, columns);
     86     }
     87 
     88     /**
     89      * Returns a {@link RealMatrix} whose entries are the the values in the
     90      * the input array.
     91      * <p>The type of matrix returned depends on the dimension. Below
     92      * 2<sup>12</sup> elements (i.e. 4096 elements or 64&times;64 for a
     93      * square matrix) which can be stored in a 32kB array, a {@link
     94      * Array2DRowRealMatrix} instance is built. Above this threshold a {@link
     95      * BlockRealMatrix} instance is built.</p>
     96      * <p>The input array is copied, not referenced.</p>
     97      *
     98      * @param data input array
     99      * @return  RealMatrix containing the values of the array
    100      * @throws IllegalArgumentException if <code>data</code> is not rectangular
    101      *  (not all rows have the same length) or empty
    102      * @throws NullPointerException if either <code>data</code> or
    103      * <code>data[0]</code> is null
    104      * @see #createRealMatrix(int, int)
    105      */
    106     public static RealMatrix createRealMatrix(double[][] data) {
    107         return (data.length * data[0].length <= 4096) ?
    108                 new Array2DRowRealMatrix(data) : new BlockRealMatrix(data);
    109     }
    110 
    111     /**
    112      * Returns a {@link FieldMatrix} whose entries are the the values in the
    113      * the input array.
    114      * <p>The type of matrix returned depends on the dimension. Below
    115      * 2<sup>12</sup> elements (i.e. 4096 elements or 64&times;64 for a
    116      * square matrix), a {@link FieldMatrix} instance is built. Above
    117      * this threshold a {@link BlockFieldMatrix} instance is built.</p>
    118      * <p>The input array is copied, not referenced.</p>
    119      * @param <T> the type of the field elements
    120      * @param data input array
    121      * @return  RealMatrix containing the values of the array
    122      * @throws IllegalArgumentException if <code>data</code> is not rectangular
    123      *  (not all rows have the same length) or empty
    124      * @throws NullPointerException if either <code>data</code> or
    125      * <code>data[0]</code> is null
    126      * @see #createFieldMatrix(Field, int, int)
    127      * @since 2.0
    128      */
    129     public static <T extends FieldElement<T>> FieldMatrix<T> createFieldMatrix(T[][] data) {
    130         return (data.length * data[0].length <= 4096) ?
    131                 new Array2DRowFieldMatrix<T>(data) : new BlockFieldMatrix<T>(data);
    132     }
    133 
    134     /**
    135      * Returns <code>dimension x dimension</code> identity matrix.
    136      *
    137      * @param dimension dimension of identity matrix to generate
    138      * @return identity matrix
    139      * @throws IllegalArgumentException if dimension is not positive
    140      * @since 1.1
    141      */
    142     public static RealMatrix createRealIdentityMatrix(int dimension) {
    143         final RealMatrix m = createRealMatrix(dimension, dimension);
    144         for (int i = 0; i < dimension; ++i) {
    145             m.setEntry(i, i, 1.0);
    146         }
    147         return m;
    148     }
    149 
    150     /**
    151      * Returns <code>dimension x dimension</code> identity matrix.
    152      *
    153      * @param <T> the type of the field elements
    154      * @param field field to which the elements belong
    155      * @param dimension dimension of identity matrix to generate
    156      * @return identity matrix
    157      * @throws IllegalArgumentException if dimension is not positive
    158      * @since 2.0
    159      */
    160     public static <T extends FieldElement<T>> FieldMatrix<T>
    161         createFieldIdentityMatrix(final Field<T> field, final int dimension) {
    162         final T zero = field.getZero();
    163         final T one  = field.getOne();
    164         @SuppressWarnings("unchecked") // zero is type T
    165         final T[][] d = (T[][]) Array.newInstance(zero.getClass(), new int[] { dimension, dimension });
    166         for (int row = 0; row < dimension; row++) {
    167             final T[] dRow = d[row];
    168             Arrays.fill(dRow, zero);
    169             dRow[row] = one;
    170         }
    171         return new Array2DRowFieldMatrix<T>(d, false);
    172     }
    173 
    174     /**
    175      * Returns <code>dimension x dimension</code> identity matrix.
    176      *
    177      * @param dimension dimension of identity matrix to generate
    178      * @return identity matrix
    179      * @throws IllegalArgumentException if dimension is not positive
    180      * @since 1.1
    181      * @deprecated since 2.0, replaced by {@link #createFieldIdentityMatrix(Field, int)}
    182      */
    183     @Deprecated
    184     public static BigMatrix createBigIdentityMatrix(int dimension) {
    185         final BigDecimal[][] d = new BigDecimal[dimension][dimension];
    186         for (int row = 0; row < dimension; row++) {
    187             final BigDecimal[] dRow = d[row];
    188             Arrays.fill(dRow, BigMatrixImpl.ZERO);
    189             dRow[row] = BigMatrixImpl.ONE;
    190         }
    191         return new BigMatrixImpl(d, false);
    192     }
    193 
    194     /**
    195      * Returns a diagonal matrix with specified elements.
    196      *
    197      * @param diagonal diagonal elements of the matrix (the array elements
    198      * will be copied)
    199      * @return diagonal matrix
    200      * @since 2.0
    201      */
    202     public static RealMatrix createRealDiagonalMatrix(final double[] diagonal) {
    203         final RealMatrix m = createRealMatrix(diagonal.length, diagonal.length);
    204         for (int i = 0; i < diagonal.length; ++i) {
    205             m.setEntry(i, i, diagonal[i]);
    206         }
    207         return m;
    208     }
    209 
    210     /**
    211      * Returns a diagonal matrix with specified elements.
    212      *
    213      * @param <T> the type of the field elements
    214      * @param diagonal diagonal elements of the matrix (the array elements
    215      * will be copied)
    216      * @return diagonal matrix
    217      * @since 2.0
    218      */
    219     public static <T extends FieldElement<T>> FieldMatrix<T>
    220         createFieldDiagonalMatrix(final T[] diagonal) {
    221         final FieldMatrix<T> m =
    222             createFieldMatrix(diagonal[0].getField(), diagonal.length, diagonal.length);
    223         for (int i = 0; i < diagonal.length; ++i) {
    224             m.setEntry(i, i, diagonal[i]);
    225         }
    226         return m;
    227     }
    228 
    229     /**
    230      * Returns a {@link BigMatrix} whose entries are the the values in the
    231      * the input array.  The input array is copied, not referenced.
    232      *
    233      * @param data input array
    234      * @return  RealMatrix containing the values of the array
    235      * @throws IllegalArgumentException if <code>data</code> is not rectangular
    236      *  (not all rows have the same length) or empty
    237      * @throws NullPointerException if data is null
    238      * @deprecated since 2.0 replaced by {@link #createFieldMatrix(FieldElement[][])}
    239      */
    240     @Deprecated
    241     public static BigMatrix createBigMatrix(double[][] data) {
    242         return new BigMatrixImpl(data);
    243     }
    244 
    245     /**
    246      * Returns a {@link BigMatrix} whose entries are the the values in the
    247      * the input array.  The input array is copied, not referenced.
    248      *
    249      * @param data input array
    250      * @return  RealMatrix containing the values of the array
    251      * @throws IllegalArgumentException if <code>data</code> is not rectangular
    252      *  (not all rows have the same length) or empty
    253      * @throws NullPointerException if data is null
    254      * @deprecated since 2.0 replaced by {@link #createFieldMatrix(FieldElement[][])}
    255      */
    256     @Deprecated
    257     public static BigMatrix createBigMatrix(BigDecimal[][] data) {
    258         return new BigMatrixImpl(data);
    259     }
    260 
    261     /**
    262      * Returns a {@link BigMatrix} whose entries are the the values in the
    263      * the input array.
    264      * <p>If an array is built specially in order to be embedded in a
    265      * BigMatrix and not used directly, the <code>copyArray</code> may be
    266      * set to <code>false</code. This will prevent the copying and improve
    267      * performance as no new array will be built and no data will be copied.</p>
    268      * @param data data for new matrix
    269      * @param copyArray if true, the input array will be copied, otherwise
    270      * it will be referenced
    271      * @return  BigMatrix containing the values of the array
    272      * @throws IllegalArgumentException if <code>data</code> is not rectangular
    273      *  (not all rows have the same length) or empty
    274      * @throws NullPointerException if <code>data</code> is null
    275      * @see #createRealMatrix(double[][])
    276      * @deprecated since 2.0 replaced by {@link #createFieldMatrix(FieldElement[][])}
    277      */
    278     @Deprecated
    279     public static BigMatrix createBigMatrix(BigDecimal[][] data, boolean copyArray) {
    280         return new BigMatrixImpl(data, copyArray);
    281     }
    282 
    283     /**
    284      * Returns a {@link BigMatrix} whose entries are the the values in the
    285      * the input array.  The input array is copied, not referenced.
    286      *
    287      * @param data input array
    288      * @return  RealMatrix containing the values of the array
    289      * @throws IllegalArgumentException if <code>data</code> is not rectangular
    290      *  (not all rows have the same length) or empty
    291      * @throws NullPointerException if data is null
    292      * @deprecated since 2.0 replaced by {@link #createFieldMatrix(FieldElement[][])}
    293      */
    294     @Deprecated
    295     public static BigMatrix createBigMatrix(String[][] data) {
    296         return new BigMatrixImpl(data);
    297     }
    298 
    299     /**
    300      * Creates a {@link RealVector} using the data from the input array.
    301      *
    302      * @param data the input data
    303      * @return a data.length RealVector
    304      * @throws IllegalArgumentException if <code>data</code> is empty
    305      * @throws NullPointerException if <code>data</code>is null
    306      */
    307     public static RealVector createRealVector(double[] data) {
    308         return new ArrayRealVector(data, true);
    309     }
    310 
    311     /**
    312      * Creates a {@link FieldVector} using the data from the input array.
    313      *
    314      * @param <T> the type of the field elements
    315      * @param data the input data
    316      * @return a data.length FieldVector
    317      * @throws IllegalArgumentException if <code>data</code> is empty
    318      * @throws NullPointerException if <code>data</code>is null
    319      */
    320     public static <T extends FieldElement<T>> FieldVector<T> createFieldVector(final T[] data) {
    321         return new ArrayFieldVector<T>(data, true);
    322     }
    323 
    324     /**
    325      * Creates a row {@link RealMatrix} using the data from the input
    326      * array.
    327      *
    328      * @param rowData the input row data
    329      * @return a 1 x rowData.length RealMatrix
    330      * @throws IllegalArgumentException if <code>rowData</code> is empty
    331      * @throws NullPointerException if <code>rowData</code>is null
    332      */
    333     public static RealMatrix createRowRealMatrix(double[] rowData) {
    334         final int nCols = rowData.length;
    335         final RealMatrix m = createRealMatrix(1, nCols);
    336         for (int i = 0; i < nCols; ++i) {
    337             m.setEntry(0, i, rowData[i]);
    338         }
    339         return m;
    340     }
    341 
    342     /**
    343      * Creates a row {@link FieldMatrix} using the data from the input
    344      * array.
    345      *
    346      * @param <T> the type of the field elements
    347      * @param rowData the input row data
    348      * @return a 1 x rowData.length FieldMatrix
    349      * @throws IllegalArgumentException if <code>rowData</code> is empty
    350      * @throws NullPointerException if <code>rowData</code>is null
    351      */
    352     public static <T extends FieldElement<T>> FieldMatrix<T>
    353         createRowFieldMatrix(final T[] rowData) {
    354         final int nCols = rowData.length;
    355         if (nCols == 0) {
    356             throw MathRuntimeException.createIllegalArgumentException(LocalizedFormats.AT_LEAST_ONE_COLUMN);
    357         }
    358         final FieldMatrix<T> m = createFieldMatrix(rowData[0].getField(), 1, nCols);
    359         for (int i = 0; i < nCols; ++i) {
    360             m.setEntry(0, i, rowData[i]);
    361         }
    362         return m;
    363     }
    364 
    365     /**
    366      * Creates a row {@link BigMatrix} using the data from the input
    367      * array.
    368      *
    369      * @param rowData the input row data
    370      * @return a 1 x rowData.length BigMatrix
    371      * @throws IllegalArgumentException if <code>rowData</code> is empty
    372      * @throws NullPointerException if <code>rowData</code>is null
    373      * @deprecated since 2.0 replaced by {@link #createRowFieldMatrix(FieldElement[])}
    374      */
    375     @Deprecated
    376     public static BigMatrix createRowBigMatrix(double[] rowData) {
    377         final int nCols = rowData.length;
    378         final BigDecimal[][] data = new BigDecimal[1][nCols];
    379         for (int i = 0; i < nCols; ++i) {
    380             data[0][i] = new BigDecimal(rowData[i]);
    381         }
    382         return new BigMatrixImpl(data, false);
    383     }
    384 
    385     /**
    386      * Creates a row {@link BigMatrix} using the data from the input
    387      * array.
    388      *
    389      * @param rowData the input row data
    390      * @return a 1 x rowData.length BigMatrix
    391      * @throws IllegalArgumentException if <code>rowData</code> is empty
    392      * @throws NullPointerException if <code>rowData</code>is null
    393      * @deprecated since 2.0 replaced by {@link #createRowFieldMatrix(FieldElement[])}
    394      */
    395     @Deprecated
    396     public static BigMatrix createRowBigMatrix(BigDecimal[] rowData) {
    397         final int nCols = rowData.length;
    398         final BigDecimal[][] data = new BigDecimal[1][nCols];
    399         System.arraycopy(rowData, 0, data[0], 0, nCols);
    400         return new BigMatrixImpl(data, false);
    401     }
    402 
    403     /**
    404      * Creates a row {@link BigMatrix} using the data from the input
    405      * array.
    406      *
    407      * @param rowData the input row data
    408      * @return a 1 x rowData.length BigMatrix
    409      * @throws IllegalArgumentException if <code>rowData</code> is empty
    410      * @throws NullPointerException if <code>rowData</code>is null
    411      * @deprecated since 2.0 replaced by {@link #createRowFieldMatrix(FieldElement[])}
    412      */
    413     @Deprecated
    414     public static BigMatrix createRowBigMatrix(String[] rowData) {
    415         final int nCols = rowData.length;
    416         final BigDecimal[][] data = new BigDecimal[1][nCols];
    417         for (int i = 0; i < nCols; ++i) {
    418             data[0][i] = new BigDecimal(rowData[i]);
    419         }
    420         return new BigMatrixImpl(data, false);
    421     }
    422 
    423     /**
    424      * Creates a column {@link RealMatrix} using the data from the input
    425      * array.
    426      *
    427      * @param columnData  the input column data
    428      * @return a columnData x 1 RealMatrix
    429      * @throws IllegalArgumentException if <code>columnData</code> is empty
    430      * @throws NullPointerException if <code>columnData</code>is null
    431      */
    432     public static RealMatrix createColumnRealMatrix(double[] columnData) {
    433         final int nRows = columnData.length;
    434         final RealMatrix m = createRealMatrix(nRows, 1);
    435         for (int i = 0; i < nRows; ++i) {
    436             m.setEntry(i, 0, columnData[i]);
    437         }
    438         return m;
    439     }
    440 
    441     /**
    442      * Creates a column {@link FieldMatrix} using the data from the input
    443      * array.
    444      *
    445      * @param <T> the type of the field elements
    446      * @param columnData  the input column data
    447      * @return a columnData x 1 FieldMatrix
    448      * @throws IllegalArgumentException if <code>columnData</code> is empty
    449      * @throws NullPointerException if <code>columnData</code>is null
    450      */
    451     public static <T extends FieldElement<T>> FieldMatrix<T>
    452         createColumnFieldMatrix(final T[] columnData) {
    453         final int nRows = columnData.length;
    454         if (nRows == 0) {
    455             throw MathRuntimeException.createIllegalArgumentException(LocalizedFormats.AT_LEAST_ONE_ROW);
    456         }
    457         final FieldMatrix<T> m = createFieldMatrix(columnData[0].getField(), nRows, 1);
    458         for (int i = 0; i < nRows; ++i) {
    459             m.setEntry(i, 0, columnData[i]);
    460         }
    461         return m;
    462     }
    463 
    464     /**
    465      * Creates a column {@link BigMatrix} using the data from the input
    466      * array.
    467      *
    468      * @param columnData  the input column data
    469      * @return a columnData x 1 BigMatrix
    470      * @throws IllegalArgumentException if <code>columnData</code> is empty
    471      * @throws NullPointerException if <code>columnData</code>is null
    472      * @deprecated since 2.0 replaced by {@link #createColumnFieldMatrix(FieldElement[])}
    473      */
    474     @Deprecated
    475     public static BigMatrix createColumnBigMatrix(double[] columnData) {
    476         final int nRows = columnData.length;
    477         final BigDecimal[][] data = new BigDecimal[nRows][1];
    478         for (int row = 0; row < nRows; row++) {
    479             data[row][0] = new BigDecimal(columnData[row]);
    480         }
    481         return new BigMatrixImpl(data, false);
    482     }
    483 
    484     /**
    485      * Creates a column {@link BigMatrix} using the data from the input
    486      * array.
    487      *
    488      * @param columnData  the input column data
    489      * @return a columnData x 1 BigMatrix
    490      * @throws IllegalArgumentException if <code>columnData</code> is empty
    491      * @throws NullPointerException if <code>columnData</code>is null
    492      * @deprecated since 2.0 replaced by {@link #createColumnFieldMatrix(FieldElement[])}
    493      */
    494     @Deprecated
    495     public static BigMatrix createColumnBigMatrix(BigDecimal[] columnData) {
    496         final int nRows = columnData.length;
    497         final BigDecimal[][] data = new BigDecimal[nRows][1];
    498         for (int row = 0; row < nRows; row++) {
    499             data[row][0] = columnData[row];
    500         }
    501         return new BigMatrixImpl(data, false);
    502     }
    503 
    504     /**
    505      * Creates a column {@link BigMatrix} using the data from the input
    506      * array.
    507      *
    508      * @param columnData  the input column data
    509      * @return a columnData x 1 BigMatrix
    510      * @throws IllegalArgumentException if <code>columnData</code> is empty
    511      * @throws NullPointerException if <code>columnData</code>is null
    512      * @deprecated since 2.0 replaced by {@link #createColumnFieldMatrix(FieldElement[])}
    513      */
    514     @Deprecated
    515     public static BigMatrix createColumnBigMatrix(String[] columnData) {
    516         int nRows = columnData.length;
    517         final BigDecimal[][] data = new BigDecimal[nRows][1];
    518         for (int row = 0; row < nRows; row++) {
    519             data[row][0] = new BigDecimal(columnData[row]);
    520         }
    521         return new BigMatrixImpl(data, false);
    522     }
    523 
    524     /**
    525      * Check if a row index is valid.
    526      * @param m matrix containing the submatrix
    527      * @param row row index to check
    528      * @exception MatrixIndexException if index is not valid
    529      */
    530     public static void checkRowIndex(final AnyMatrix m, final int row) {
    531         if (row < 0 || row >= m.getRowDimension()) {
    532             throw new MatrixIndexException(LocalizedFormats.ROW_INDEX_OUT_OF_RANGE,
    533                                            row, 0, m.getRowDimension() - 1);
    534         }
    535     }
    536 
    537     /**
    538      * Check if a column index is valid.
    539      * @param m matrix containing the submatrix
    540      * @param column column index to check
    541      * @exception MatrixIndexException if index is not valid
    542      */
    543     public static void checkColumnIndex(final AnyMatrix m, final int column)
    544         throws MatrixIndexException {
    545         if (column < 0 || column >= m.getColumnDimension()) {
    546             throw new MatrixIndexException(LocalizedFormats.COLUMN_INDEX_OUT_OF_RANGE,
    547                                            column, 0, m.getColumnDimension() - 1);
    548         }
    549     }
    550 
    551     /**
    552      * Check if submatrix ranges indices are valid.
    553      * Rows and columns are indicated counting from 0 to n-1.
    554      *
    555      * @param m matrix containing the submatrix
    556      * @param startRow Initial row index
    557      * @param endRow Final row index
    558      * @param startColumn Initial column index
    559      * @param endColumn Final column index
    560      * @exception MatrixIndexException  if the indices are not valid
    561      */
    562     public static void checkSubMatrixIndex(final AnyMatrix m,
    563                                            final int startRow, final int endRow,
    564                                            final int startColumn, final int endColumn) {
    565         checkRowIndex(m, startRow);
    566         checkRowIndex(m, endRow);
    567         if (startRow > endRow) {
    568             throw new MatrixIndexException(LocalizedFormats.INITIAL_ROW_AFTER_FINAL_ROW,
    569                                            startRow, endRow);
    570         }
    571 
    572         checkColumnIndex(m, startColumn);
    573         checkColumnIndex(m, endColumn);
    574         if (startColumn > endColumn) {
    575             throw new MatrixIndexException(LocalizedFormats.INITIAL_COLUMN_AFTER_FINAL_COLUMN,
    576                                            startColumn, endColumn);
    577         }
    578 
    579 
    580     }
    581 
    582     /**
    583      * Check if submatrix ranges indices are valid.
    584      * Rows and columns are indicated counting from 0 to n-1.
    585      *
    586      * @param m matrix containing the submatrix
    587      * @param selectedRows Array of row indices.
    588      * @param selectedColumns Array of column indices.
    589      * @exception MatrixIndexException if row or column selections are not valid
    590      */
    591     public static void checkSubMatrixIndex(final AnyMatrix m,
    592                                            final int[] selectedRows, final int[] selectedColumns)
    593         throws MatrixIndexException {
    594         if (selectedRows.length * selectedColumns.length == 0) {
    595             if (selectedRows.length == 0) {
    596                 throw new MatrixIndexException(LocalizedFormats.EMPTY_SELECTED_ROW_INDEX_ARRAY);
    597             }
    598             throw new MatrixIndexException(LocalizedFormats.EMPTY_SELECTED_COLUMN_INDEX_ARRAY);
    599         }
    600 
    601         for (final int row : selectedRows) {
    602             checkRowIndex(m, row);
    603         }
    604         for (final int column : selectedColumns) {
    605             checkColumnIndex(m, column);
    606         }
    607     }
    608 
    609     /**
    610      * Check if matrices are addition compatible
    611      * @param left left hand side matrix
    612      * @param right right hand side matrix
    613      * @exception IllegalArgumentException if matrices are not addition compatible
    614      */
    615     public static void checkAdditionCompatible(final AnyMatrix left, final AnyMatrix right)
    616         throws IllegalArgumentException {
    617         if ((left.getRowDimension()    != right.getRowDimension()) ||
    618             (left.getColumnDimension() != right.getColumnDimension())) {
    619             throw MathRuntimeException.createIllegalArgumentException(
    620                     LocalizedFormats.NOT_ADDITION_COMPATIBLE_MATRICES,
    621                     left.getRowDimension(), left.getColumnDimension(),
    622                     right.getRowDimension(), right.getColumnDimension());
    623         }
    624     }
    625 
    626     /**
    627      * Check if matrices are subtraction compatible
    628      * @param left left hand side matrix
    629      * @param right right hand side matrix
    630      * @exception IllegalArgumentException if matrices are not subtraction compatible
    631      */
    632     public static void checkSubtractionCompatible(final AnyMatrix left, final AnyMatrix right)
    633         throws IllegalArgumentException {
    634         if ((left.getRowDimension()    != right.getRowDimension()) ||
    635             (left.getColumnDimension() != right.getColumnDimension())) {
    636             throw MathRuntimeException.createIllegalArgumentException(
    637                     LocalizedFormats.NOT_SUBTRACTION_COMPATIBLE_MATRICES,
    638                     left.getRowDimension(), left.getColumnDimension(),
    639                     right.getRowDimension(), right.getColumnDimension());
    640         }
    641     }
    642 
    643     /**
    644      * Check if matrices are multiplication compatible
    645      * @param left left hand side matrix
    646      * @param right right hand side matrix
    647      * @exception IllegalArgumentException if matrices are not multiplication compatible
    648      */
    649     public static void checkMultiplicationCompatible(final AnyMatrix left, final AnyMatrix right)
    650         throws IllegalArgumentException {
    651         if (left.getColumnDimension() != right.getRowDimension()) {
    652             throw MathRuntimeException.createIllegalArgumentException(
    653                     LocalizedFormats.NOT_MULTIPLICATION_COMPATIBLE_MATRICES,
    654                     left.getRowDimension(), left.getColumnDimension(),
    655                     right.getRowDimension(), right.getColumnDimension());
    656         }
    657     }
    658 
    659     /**
    660      * Convert a {@link FieldMatrix}/{@link Fraction} matrix to a {@link RealMatrix}.
    661      * @param m matrix to convert
    662      * @return converted matrix
    663      */
    664     public static Array2DRowRealMatrix fractionMatrixToRealMatrix(final FieldMatrix<Fraction> m) {
    665         final FractionMatrixConverter converter = new FractionMatrixConverter();
    666         m.walkInOptimizedOrder(converter);
    667         return converter.getConvertedMatrix();
    668     }
    669 
    670     /** Converter for {@link FieldMatrix}/{@link Fraction}. */
    671     private static class FractionMatrixConverter extends DefaultFieldMatrixPreservingVisitor<Fraction> {
    672 
    673         /** Converted array. */
    674         private double[][] data;
    675 
    676         /** Simple constructor. */
    677         public FractionMatrixConverter() {
    678             super(Fraction.ZERO);
    679         }
    680 
    681         /** {@inheritDoc} */
    682         @Override
    683         public void start(int rows, int columns,
    684                           int startRow, int endRow, int startColumn, int endColumn) {
    685             data = new double[rows][columns];
    686         }
    687 
    688         /** {@inheritDoc} */
    689         @Override
    690         public void visit(int row, int column, Fraction value) {
    691             data[row][column] = value.doubleValue();
    692         }
    693 
    694         /** Get the converted matrix.
    695          * @return converted matrix
    696          */
    697         Array2DRowRealMatrix getConvertedMatrix() {
    698             return new Array2DRowRealMatrix(data, false);
    699         }
    700 
    701     }
    702 
    703     /**
    704      * Convert a {@link FieldMatrix}/{@link BigFraction} matrix to a {@link RealMatrix}.
    705      * @param m matrix to convert
    706      * @return converted matrix
    707      */
    708     public static Array2DRowRealMatrix bigFractionMatrixToRealMatrix(final FieldMatrix<BigFraction> m) {
    709         final BigFractionMatrixConverter converter = new BigFractionMatrixConverter();
    710         m.walkInOptimizedOrder(converter);
    711         return converter.getConvertedMatrix();
    712     }
    713 
    714     /** Converter for {@link FieldMatrix}/{@link BigFraction}. */
    715     private static class BigFractionMatrixConverter extends DefaultFieldMatrixPreservingVisitor<BigFraction> {
    716 
    717         /** Converted array. */
    718         private double[][] data;
    719 
    720         /** Simple constructor. */
    721         public BigFractionMatrixConverter() {
    722             super(BigFraction.ZERO);
    723         }
    724 
    725         /** {@inheritDoc} */
    726         @Override
    727         public void start(int rows, int columns,
    728                           int startRow, int endRow, int startColumn, int endColumn) {
    729             data = new double[rows][columns];
    730         }
    731 
    732         /** {@inheritDoc} */
    733         @Override
    734         public void visit(int row, int column, BigFraction value) {
    735             data[row][column] = value.doubleValue();
    736         }
    737 
    738         /** Get the converted matrix.
    739          * @return converted matrix
    740          */
    741         Array2DRowRealMatrix getConvertedMatrix() {
    742             return new Array2DRowRealMatrix(data, false);
    743         }
    744 
    745     }
    746 
    747     /** Serialize a {@link RealVector}.
    748      * <p>
    749      * This method is intended to be called from within a private
    750      * <code>writeObject</code> method (after a call to
    751      * <code>oos.defaultWriteObject()</code>) in a class that has a
    752      * {@link RealVector} field, which should be declared <code>transient</code>.
    753      * This way, the default handling does not serialize the vector (the {@link
    754      * RealVector} interface is not serializable by default) but this method does
    755      * serialize it specifically.
    756      * </p>
    757      * <p>
    758      * The following example shows how a simple class with a name and a real vector
    759      * should be written:
    760      * <pre><code>
    761      * public class NamedVector implements Serializable {
    762      *
    763      *     private final String name;
    764      *     private final transient RealVector coefficients;
    765      *
    766      *     // omitted constructors, getters ...
    767      *
    768      *     private void writeObject(ObjectOutputStream oos) throws IOException {
    769      *         oos.defaultWriteObject();  // takes care of name field
    770      *         MatrixUtils.serializeRealVector(coefficients, oos);
    771      *     }
    772      *
    773      *     private void readObject(ObjectInputStream ois) throws ClassNotFoundException, IOException {
    774      *         ois.defaultReadObject();  // takes care of name field
    775      *         MatrixUtils.deserializeRealVector(this, "coefficients", ois);
    776      *     }
    777      *
    778      * }
    779      * </code></pre>
    780      * </p>
    781      *
    782      * @param vector real vector to serialize
    783      * @param oos stream where the real vector should be written
    784      * @exception IOException if object cannot be written to stream
    785      * @see #deserializeRealVector(Object, String, ObjectInputStream)
    786      */
    787     public static void serializeRealVector(final RealVector vector,
    788                                            final ObjectOutputStream oos)
    789         throws IOException {
    790         final int n = vector.getDimension();
    791         oos.writeInt(n);
    792         for (int i = 0; i < n; ++i) {
    793             oos.writeDouble(vector.getEntry(i));
    794         }
    795     }
    796 
    797     /** Deserialize  a {@link RealVector} field in a class.
    798      * <p>
    799      * This method is intended to be called from within a private
    800      * <code>readObject</code> method (after a call to
    801      * <code>ois.defaultReadObject()</code>) in a class that has a
    802      * {@link RealVector} field, which should be declared <code>transient</code>.
    803      * This way, the default handling does not deserialize the vector (the {@link
    804      * RealVector} interface is not serializable by default) but this method does
    805      * deserialize it specifically.
    806      * </p>
    807      * @param instance instance in which the field must be set up
    808      * @param fieldName name of the field within the class (may be private and final)
    809      * @param ois stream from which the real vector should be read
    810      * @exception ClassNotFoundException if a class in the stream cannot be found
    811      * @exception IOException if object cannot be read from the stream
    812      * @see #serializeRealVector(RealVector, ObjectOutputStream)
    813      */
    814     public static void deserializeRealVector(final Object instance,
    815                                              final String fieldName,
    816                                              final ObjectInputStream ois)
    817       throws ClassNotFoundException, IOException {
    818         try {
    819 
    820             // read the vector data
    821             final int n = ois.readInt();
    822             final double[] data = new double[n];
    823             for (int i = 0; i < n; ++i) {
    824                 data[i] = ois.readDouble();
    825             }
    826 
    827             // create the instance
    828             final RealVector vector = new ArrayRealVector(data, false);
    829 
    830             // set up the field
    831             final java.lang.reflect.Field f =
    832                 instance.getClass().getDeclaredField(fieldName);
    833             f.setAccessible(true);
    834             f.set(instance, vector);
    835 
    836         } catch (NoSuchFieldException nsfe) {
    837             IOException ioe = new IOException();
    838             ioe.initCause(nsfe);
    839             throw ioe;
    840         } catch (IllegalAccessException iae) {
    841             IOException ioe = new IOException();
    842             ioe.initCause(iae);
    843             throw ioe;
    844         }
    845 
    846     }
    847 
    848     /** Serialize a {@link RealMatrix}.
    849      * <p>
    850      * This method is intended to be called from within a private
    851      * <code>writeObject</code> method (after a call to
    852      * <code>oos.defaultWriteObject()</code>) in a class that has a
    853      * {@link RealMatrix} field, which should be declared <code>transient</code>.
    854      * This way, the default handling does not serialize the matrix (the {@link
    855      * RealMatrix} interface is not serializable by default) but this method does
    856      * serialize it specifically.
    857      * </p>
    858      * <p>
    859      * The following example shows how a simple class with a name and a real matrix
    860      * should be written:
    861      * <pre><code>
    862      * public class NamedMatrix implements Serializable {
    863      *
    864      *     private final String name;
    865      *     private final transient RealMatrix coefficients;
    866      *
    867      *     // omitted constructors, getters ...
    868      *
    869      *     private void writeObject(ObjectOutputStream oos) throws IOException {
    870      *         oos.defaultWriteObject();  // takes care of name field
    871      *         MatrixUtils.serializeRealMatrix(coefficients, oos);
    872      *     }
    873      *
    874      *     private void readObject(ObjectInputStream ois) throws ClassNotFoundException, IOException {
    875      *         ois.defaultReadObject();  // takes care of name field
    876      *         MatrixUtils.deserializeRealMatrix(this, "coefficients", ois);
    877      *     }
    878      *
    879      * }
    880      * </code></pre>
    881      * </p>
    882      *
    883      * @param matrix real matrix to serialize
    884      * @param oos stream where the real matrix should be written
    885      * @exception IOException if object cannot be written to stream
    886      * @see #deserializeRealMatrix(Object, String, ObjectInputStream)
    887      */
    888     public static void serializeRealMatrix(final RealMatrix matrix,
    889                                            final ObjectOutputStream oos)
    890         throws IOException {
    891         final int n = matrix.getRowDimension();
    892         final int m = matrix.getColumnDimension();
    893         oos.writeInt(n);
    894         oos.writeInt(m);
    895         for (int i = 0; i < n; ++i) {
    896             for (int j = 0; j < m; ++j) {
    897                 oos.writeDouble(matrix.getEntry(i, j));
    898             }
    899         }
    900     }
    901 
    902     /** Deserialize  a {@link RealMatrix} field in a class.
    903      * <p>
    904      * This method is intended to be called from within a private
    905      * <code>readObject</code> method (after a call to
    906      * <code>ois.defaultReadObject()</code>) in a class that has a
    907      * {@link RealMatrix} field, which should be declared <code>transient</code>.
    908      * This way, the default handling does not deserialize the matrix (the {@link
    909      * RealMatrix} interface is not serializable by default) but this method does
    910      * deserialize it specifically.
    911      * </p>
    912      * @param instance instance in which the field must be set up
    913      * @param fieldName name of the field within the class (may be private and final)
    914      * @param ois stream from which the real matrix should be read
    915      * @exception ClassNotFoundException if a class in the stream cannot be found
    916      * @exception IOException if object cannot be read from the stream
    917      * @see #serializeRealMatrix(RealMatrix, ObjectOutputStream)
    918      */
    919     public static void deserializeRealMatrix(final Object instance,
    920                                              final String fieldName,
    921                                              final ObjectInputStream ois)
    922       throws ClassNotFoundException, IOException {
    923         try {
    924 
    925             // read the matrix data
    926             final int n = ois.readInt();
    927             final int m = ois.readInt();
    928             final double[][] data = new double[n][m];
    929             for (int i = 0; i < n; ++i) {
    930                 final double[] dataI = data[i];
    931                 for (int j = 0; j < m; ++j) {
    932                     dataI[j] = ois.readDouble();
    933                 }
    934             }
    935 
    936             // create the instance
    937             final RealMatrix matrix = new Array2DRowRealMatrix(data, false);
    938 
    939             // set up the field
    940             final java.lang.reflect.Field f =
    941                 instance.getClass().getDeclaredField(fieldName);
    942             f.setAccessible(true);
    943             f.set(instance, matrix);
    944 
    945         } catch (NoSuchFieldException nsfe) {
    946             IOException ioe = new IOException();
    947             ioe.initCause(nsfe);
    948             throw ioe;
    949         } catch (IllegalAccessException iae) {
    950             IOException ioe = new IOException();
    951             ioe.initCause(iae);
    952             throw ioe;
    953         }
    954 
    955     }
    956 
    957 }
    958