    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.Serializable;
    021
    022    import org.apache.commons.math.MathRuntimeException;
    023    import org.apache.commons.math.linear.MatrixVisitorException;
    024    import org.apache.commons.math.exception.util.LocalizedFormats;
    025
    026    /**
    027     * Implementation of RealMatrix using a double[][] array to store entries and
    028     * <a href="http://www.math.gatech.edu/~bourbaki/math2601/Web-notes/2num.pdf">
    029     * LU decomposition</a> to support linear system
    030     * solution and inverse.
    031     * <p>
    032     * The LU decomposition is performed as needed, to support the following operations: <ul>
    033     * <li>solve</li>
    034     * <li>isSingular</li>
    035     * <li>getDeterminant</li>
    036     * <li>inverse</li> </ul></p>
    037     * <p>
    038     * <strong>Usage notes</strong>:<br>
    039     * <ul><li>
    040     * The LU decomposition is cached and reused on subsequent calls.
    041     * If data are modified via references to the underlying array obtained using
    042     * <code>getDataRef()</code>, then the stored LU decomposition will not be
    043     * discarded.  In this case, you need to explicitly invoke
    044     * <code>LUDecompose()</code> to recompute the decomposition
    045     * before using any of the methods above.</li>
    046     * <li>
    047     * As specified in the {@link RealMatrix} interface, matrix element indexing
    048     * is 0-based -- e.g., <code>getEntry(0, 0)</code>
    049     * returns the element in the first row, first column of the matrix.</li></ul>
    050     * </p>
    051     *
    052     * @version $Revision: 1073158 $ $Date: 2011-02-21 22:46:52 +0100 (lun. 21 f??vr. 2011) $
    053     * @deprecated as of 2.0 replaced by {@link Array2DRowRealMatrix}
    054     */
    055    @Deprecated
    056    public class RealMatrixImpl extends AbstractRealMatrix implements Serializable {
    057
    058        /** Serializable version identifier */
    059        private static final long serialVersionUID = -1067294169172445528L;
    060
    061        /** Entries of the matrix */
    062        protected double data[][];
    063
    064        /**
    065         * Creates a matrix with no data
    066         */
    067        public RealMatrixImpl() {
    068        }
    069
    070        /**
    071         * Create a new RealMatrix with the supplied row and column dimensions.
    072         *
    073         * @param rowDimension  the number of rows in the new matrix
    074         * @param columnDimension  the number of columns in the new matrix
    075         * @throws IllegalArgumentException if row or column dimension is not
    076         *  positive
    077         */
    078        public RealMatrixImpl(final int rowDimension, final int columnDimension)
    079            throws IllegalArgumentException {
    080            super(rowDimension, columnDimension);
    081            data = new double[rowDimension][columnDimension];
    082        }
    083
    084        /**
    085         * Create a new RealMatrix using the input array as the underlying
    086         * data array.
    087         * <p>The input array is copied, not referenced. This constructor has
    088         * the same effect as calling {@link #RealMatrixImpl(double[][], boolean)}
    089         * with the second argument set to <code>true</code>.</p>
    090         *
    091         * @param d data for new matrix
    092         * @throws IllegalArgumentException if <code>d</code> is not rectangular
    093         *  (not all rows have the same length) or empty
    094         * @throws NullPointerException if <code>d</code> is null
    095         * @see #RealMatrixImpl(double[][], boolean)
    096         */
    097        public RealMatrixImpl(final double[][] d)
    098            throws IllegalArgumentException, NullPointerException {
    099            copyIn(d);
    100        }
    101
    102        /**
    103         * Create a new RealMatrix using the input array as the underlying
    104         * data array.
    105         * <p>If an array is built specially in order to be embedded in a
    106         * RealMatrix and not used directly, the <code>copyArray</code> may be
    107         * set to <code>false</code. This will prevent the copying and improve
    108         * performance as no new array will be built and no data will be copied.</p>
    109         * @param d data for new matrix
    110         * @param copyArray if true, the input array will be copied, otherwise
    111         * it will be referenced
    112         * @throws IllegalArgumentException if <code>d</code> is not rectangular
    113         *  (not all rows have the same length) or empty
    114         * @throws NullPointerException if <code>d</code> is null
    115         * @see #RealMatrixImpl(double[][])
    116         */
    117        public RealMatrixImpl(final double[][] d, final boolean copyArray)
    118            throws IllegalArgumentException, NullPointerException {
    119            if (copyArray) {
    120                copyIn(d);
    121            } else {
    122                if (d == null) {
    123                    throw new NullPointerException();
    124                }
    125                final int nRows = d.length;
    126                if (nRows == 0) {
    127                    throw MathRuntimeException.createIllegalArgumentException(LocalizedFormats.AT_LEAST_ONE_ROW);
    128                }
    129                final int nCols = d[0].length;
    130                if (nCols == 0) {
    131                    throw MathRuntimeException.createIllegalArgumentException(LocalizedFormats.AT_LEAST_ONE_COLUMN);
    132                }
    133                for (int r = 1; r < nRows; r++) {
    134                    if (d[r].length != nCols) {
    135                        throw MathRuntimeException.createIllegalArgumentException(
    136                                LocalizedFormats.DIFFERENT_ROWS_LENGTHS,
    137                                nCols, d[r].length);
    138                    }
    139                }
    140                data = d;
    141            }
    142        }
    143
    144        /**
    145         * Create a new (column) RealMatrix using <code>v</code> as the
    146         * data for the unique column of the <code>v.length x 1</code> matrix
    147         * created.
    148         * <p>The input array is copied, not referenced.</p>
    149         *
    150         * @param v column vector holding data for new matrix
    151         */
    152        public RealMatrixImpl(final double[] v) {
    153            final int nRows = v.length;
    154            data = new double[nRows][1];
    155            for (int row = 0; row < nRows; row++) {
    156                data[row][0] = v[row];
    157            }
    158        }
    159
    160        /** {@inheritDoc} */
    161        @Override
    162        public RealMatrix createMatrix(final int rowDimension, final int columnDimension)
    163            throws IllegalArgumentException {
    164            return new RealMatrixImpl(rowDimension, columnDimension);
    165        }
    166
    167        /** {@inheritDoc} */
    168        @Override
    169        public RealMatrix copy() {
    170            return new RealMatrixImpl(copyOut(), false);
    171        }
    172
    173        /** {@inheritDoc} */
    174        @Override
    175        public RealMatrix add(final RealMatrix m)
    176            throws IllegalArgumentException {
    177            try {
    178                return add((RealMatrixImpl) m);
    179            } catch (ClassCastException cce) {
    180                return super.add(m);
    181            }
    182        }
    183
    184        /**
    185         * Compute the sum of this and <code>m</code>.
    186         *
    187         * @param m    matrix to be added
    188         * @return     this + m
    189         * @throws  IllegalArgumentException if m is not the same size as this
    190         */
    191        public RealMatrixImpl add(final RealMatrixImpl m)
    192            throws IllegalArgumentException {
    193
    194            // safety check
    195            MatrixUtils.checkAdditionCompatible(this, m);
    196
    197            final int rowCount    = getRowDimension();
    198            final int columnCount = getColumnDimension();
    199            final double[][] outData = new double[rowCount][columnCount];
    200            for (int row = 0; row < rowCount; row++) {
    201                final double[] dataRow    = data[row];
    202                final double[] mRow       = m.data[row];
    203                final double[] outDataRow = outData[row];
    204                for (int col = 0; col < columnCount; col++) {
    205                    outDataRow[col] = dataRow[col] + mRow[col];
    206                }
    207            }
    208
    209            return new RealMatrixImpl(outData, false);
    210
    211        }
    212
    213        /** {@inheritDoc} */
    214        @Override
    215        public RealMatrix subtract(final RealMatrix m)
    216            throws IllegalArgumentException {
    217            try {
    218                return subtract((RealMatrixImpl) m);
    219            } catch (ClassCastException cce) {
    220                return super.subtract(m);
    221            }
    222        }
    223
    224        /**
    225         * Compute  this minus <code>m</code>.
    226         *
    227         * @param m    matrix to be subtracted
    228         * @return     this + m
    229         * @throws  IllegalArgumentException if m is not the same size as this
    230         */
    231        public RealMatrixImpl subtract(final RealMatrixImpl m)
    232            throws IllegalArgumentException {
    233
    234            // safety check
    235            MatrixUtils.checkSubtractionCompatible(this, m);
    236
    237            final int rowCount    = getRowDimension();
    238            final int columnCount = getColumnDimension();
    239            final double[][] outData = new double[rowCount][columnCount];
    240            for (int row = 0; row < rowCount; row++) {
    241                final double[] dataRow    = data[row];
    242                final double[] mRow       = m.data[row];
    243                final double[] outDataRow = outData[row];
    244                for (int col = 0; col < columnCount; col++) {
    245                    outDataRow[col] = dataRow[col] - mRow[col];
    246                }
    247            }
    248
    249            return new RealMatrixImpl(outData, false);
    250
    251        }
    252
    253        /** {@inheritDoc} */
    254        @Override
    255        public RealMatrix multiply(final RealMatrix m)
    256            throws IllegalArgumentException {
    257            try {
    258                return multiply((RealMatrixImpl) m);
    259            } catch (ClassCastException cce) {
    260                return super.multiply(m);
    261            }
    262        }
    263
    264        /**
    265         * Returns the result of postmultiplying this by <code>m</code>.
    266         * @param m    matrix to postmultiply by
    267         * @return     this*m
    268         * @throws     IllegalArgumentException
    269         *             if columnDimension(this) != rowDimension(m)
    270         */
    271        public RealMatrixImpl multiply(final RealMatrixImpl m)
    272            throws IllegalArgumentException {
    273
    274            // safety check
    275            MatrixUtils.checkMultiplicationCompatible(this, m);
    276
    277            final int nRows = this.getRowDimension();
    278            final int nCols = m.getColumnDimension();
    279            final int nSum = this.getColumnDimension();
    280            final double[][] outData = new double[nRows][nCols];
    281            for (int row = 0; row < nRows; row++) {
    282                final double[] dataRow    = data[row];
    283                final double[] outDataRow = outData[row];
    284                for (int col = 0; col < nCols; col++) {
    285                    double sum = 0;
    286                    for (int i = 0; i < nSum; i++) {
    287                        sum += dataRow[i] * m.data[i][col];
    288                    }
    289                    outDataRow[col] = sum;
    290                }
    291            }
    292
    293            return new RealMatrixImpl(outData, false);
    294
    295        }
    296
    297        /** {@inheritDoc} */
    298        @Override
    299        public double[][] getData() {
    300            return copyOut();
    301        }
    302
    303        /**
    304         * Returns a reference to the underlying data array.
    305         * <p>
    306         * Does <strong>not</strong> make a fresh copy of the underlying data.</p>
    307         *
    308         * @return 2-dimensional array of entries
    309         */
    310        public double[][] getDataRef() {
    311            return data;
    312        }
    313
    314        /** {@inheritDoc} */
    315        @Override
    316        public void setSubMatrix(final double[][] subMatrix, final int row, final int column)
    317        throws MatrixIndexException {
    318            if (data == null) {
    319                if (row > 0) {
    320                    throw MathRuntimeException.createIllegalStateException(
    321                            LocalizedFormats.FIRST_ROWS_NOT_INITIALIZED_YET,
    322                            row);
    323                }
    324                if (column > 0) {
    325                    throw MathRuntimeException.createIllegalStateException(
    326                            LocalizedFormats.FIRST_COLUMNS_NOT_INITIALIZED_YET,
    327                            column);
    328                }
    329                final int nRows = subMatrix.length;
    330                if (nRows == 0) {
    331                    throw MathRuntimeException.createIllegalArgumentException(LocalizedFormats.AT_LEAST_ONE_ROW);
    332                }
    333
    334                final int nCols = subMatrix[0].length;
    335                if (nCols == 0) {
    336                    throw MathRuntimeException.createIllegalArgumentException(LocalizedFormats.AT_LEAST_ONE_COLUMN);
    337                }
    338                data = new double[subMatrix.length][nCols];
    339                for (int i = 0; i < data.length; ++i) {
    340                    if (subMatrix[i].length != nCols) {
    341                        throw MathRuntimeException.createIllegalArgumentException(
    342                                LocalizedFormats.DIFFERENT_ROWS_LENGTHS,
    343                                nCols, subMatrix[i].length);
    344                    }
    345                    System.arraycopy(subMatrix[i], 0, data[i + row], column, nCols);
    346                }
    347            } else {
    348                super.setSubMatrix(subMatrix, row, column);
    349            }
    350
    351        }
    352
    353        /** {@inheritDoc} */
    354        @Override
    355        public double getEntry(final int row, final int column)
    356            throws MatrixIndexException {
    357            try {
    358                return data[row][column];
    359            } catch (ArrayIndexOutOfBoundsException e) {
    360                throw new MatrixIndexException(
    361                        LocalizedFormats.NO_SUCH_MATRIX_ENTRY,
    362                        row, column, getRowDimension(), getColumnDimension());
    363            }
    364        }
    365
    366        /** {@inheritDoc} */
    367        @Override
    368        public void setEntry(final int row, final int column, final double value)
    369            throws MatrixIndexException {
    370            try {
    371                data[row][column] = value;
    372            } catch (ArrayIndexOutOfBoundsException e) {
    373                throw new MatrixIndexException(
    374                        LocalizedFormats.NO_SUCH_MATRIX_ENTRY,
    375                        row, column, getRowDimension(), getColumnDimension());
    376            }
    377        }
    378
    379        /** {@inheritDoc} */
    380        @Override
    381        public void addToEntry(final int row, final int column, final double increment)
    382            throws MatrixIndexException {
    383            try {
    384                data[row][column] += increment;
    385            } catch (ArrayIndexOutOfBoundsException e) {
    386                throw new MatrixIndexException(
    387                        LocalizedFormats.NO_SUCH_MATRIX_ENTRY,
    388                        row, column, getRowDimension(), getColumnDimension());
    389            }
    390        }
    391
    392        /** {@inheritDoc} */
    393        @Override
    394        public void multiplyEntry(final int row, final int column, final double factor)
    395            throws MatrixIndexException {
    396            try {
    397                data[row][column] *= factor;
    398            } catch (ArrayIndexOutOfBoundsException e) {
    399                throw new MatrixIndexException(
    400                        LocalizedFormats.NO_SUCH_MATRIX_ENTRY,
    401                        row, column, getRowDimension(), getColumnDimension());
    402            }
    403        }
    404
    405        /** {@inheritDoc} */
    406        @Override
    407        public int getRowDimension() {
    408            return (data == null) ? 0 : data.length;
    409        }
    410
    411        /** {@inheritDoc} */
    412        @Override
    413        public int getColumnDimension() {
    414            return ((data == null) || (data[0] == null)) ? 0 : data[0].length;
    415        }
    416
    417        /** {@inheritDoc} */
    418        @Override
    419        public double[] operate(final double[] v)
    420            throws IllegalArgumentException {
    421            final int nRows = this.getRowDimension();
    422            final int nCols = this.getColumnDimension();
    423            if (v.length != nCols) {
    424                throw MathRuntimeException.createIllegalArgumentException(
    425                        LocalizedFormats.VECTOR_LENGTH_MISMATCH,
    426                        v.length, nCols);
    427            }
    428            final double[] out = new double[nRows];
    429            for (int row = 0; row < nRows; row++) {
    430                final double[] dataRow = data[row];
    431                double sum = 0;
    432                for (int i = 0; i < nCols; i++) {
    433                    sum += dataRow[i] * v[i];
    434                }
    435                out[row] = sum;
    436            }
    437            return out;
    438        }
    439
    440        /** {@inheritDoc} */
    441        @Override
    442        public double[] preMultiply(final double[] v)
    443            throws IllegalArgumentException {
    444
    445            final int nRows = getRowDimension();
    446            final int nCols = getColumnDimension();
    447            if (v.length != nRows) {
    448                throw MathRuntimeException.createIllegalArgumentException(
    449                        LocalizedFormats.VECTOR_LENGTH_MISMATCH,
    450                        v.length, nRows);
    451            }
    452
    453            final double[] out = new double[nCols];
    454            for (int col = 0; col < nCols; ++col) {
    455                double sum = 0;
    456                for (int i = 0; i < nRows; ++i) {
    457                    sum += data[i][col] * v[i];
    458                }
    459                out[col] = sum;
    460            }
    461
    462            return out;
    463
    464        }
    465
    466        /** {@inheritDoc} */
    467        @Override
    468        public double walkInRowOrder(final RealMatrixChangingVisitor visitor)
    469            throws MatrixVisitorException {
    470            final int rows    = getRowDimension();
    471            final int columns = getColumnDimension();
    472            visitor.start(rows, columns, 0, rows - 1, 0, columns - 1);
    473            for (int i = 0; i < rows; ++i) {
    474                final double[] rowI = data[i];
    475                for (int j = 0; j < columns; ++j) {
    476                    rowI[j] = visitor.visit(i, j, rowI[j]);
    477                }
    478            }
    479            return visitor.end();
    480        }
    481
    482        /** {@inheritDoc} */
    483        @Override
    484        public double walkInRowOrder(final RealMatrixPreservingVisitor visitor)
    485            throws MatrixVisitorException {
    486            final int rows    = getRowDimension();
    487            final int columns = getColumnDimension();
    488            visitor.start(rows, columns, 0, rows - 1, 0, columns - 1);
    489            for (int i = 0; i < rows; ++i) {
    490                final double[] rowI = data[i];
    491                for (int j = 0; j < columns; ++j) {
    492                    visitor.visit(i, j, rowI[j]);
    493                }
    494            }
    495            return visitor.end();
    496        }
    497
    498        /** {@inheritDoc} */
    499        @Override
    500        public double walkInRowOrder(final RealMatrixChangingVisitor visitor,
    501                                     final int startRow, final int endRow,
    502                                     final int startColumn, final int endColumn)
    503            throws MatrixIndexException, MatrixVisitorException {
    504            MatrixUtils.checkSubMatrixIndex(this, startRow, endRow, startColumn, endColumn);
    505            visitor.start(getRowDimension(), getColumnDimension(),
    506                          startRow, endRow, startColumn, endColumn);
    507            for (int i = startRow; i <= endRow; ++i) {
    508                final double[] rowI = data[i];
    509                for (int j = startColumn; j <= endColumn; ++j) {
    510                    rowI[j] = visitor.visit(i, j, rowI[j]);
    511                }
    512            }
    513            return visitor.end();
    514        }
    515
    516        /** {@inheritDoc} */
    517        @Override
    518        public double walkInRowOrder(final RealMatrixPreservingVisitor visitor,
    519                                     final int startRow, final int endRow,
    520                                     final int startColumn, final int endColumn)
    521            throws MatrixIndexException, MatrixVisitorException {
    522            MatrixUtils.checkSubMatrixIndex(this, startRow, endRow, startColumn, endColumn);
    523            visitor.start(getRowDimension(), getColumnDimension(),
    524                          startRow, endRow, startColumn, endColumn);
    525            for (int i = startRow; i <= endRow; ++i) {
    526                final double[] rowI = data[i];
    527                for (int j = startColumn; j <= endColumn; ++j) {
    528                    visitor.visit(i, j, rowI[j]);
    529                }
    530            }
    531            return visitor.end();
    532        }
    533
    534        /** {@inheritDoc} */
    535        @Override
    536        public double walkInColumnOrder(final RealMatrixChangingVisitor visitor)
    537            throws MatrixVisitorException {
    538            final int rows    = getRowDimension();
    539            final int columns = getColumnDimension();
    540            visitor.start(rows, columns, 0, rows - 1, 0, columns - 1);
    541            for (int j = 0; j < columns; ++j) {
    542                for (int i = 0; i < rows; ++i) {
    543                    final double[] rowI = data[i];
    544                    rowI[j] = visitor.visit(i, j, rowI[j]);
    545                }
    546            }
    547            return visitor.end();
    548        }
    549
    550        /** {@inheritDoc} */
    551        @Override
    552        public double walkInColumnOrder(final RealMatrixPreservingVisitor visitor)
    553            throws MatrixVisitorException {
    554            final int rows    = getRowDimension();
    555            final int columns = getColumnDimension();
    556            visitor.start(rows, columns, 0, rows - 1, 0, columns - 1);
    557            for (int j = 0; j < columns; ++j) {
    558                for (int i = 0; i < rows; ++i) {
    559                    visitor.visit(i, j, data[i][j]);
    560                }
    561            }
    562            return visitor.end();
    563        }
    564
    565        /** {@inheritDoc} */
    566        @Override
    567        public double walkInColumnOrder(final RealMatrixChangingVisitor visitor,
    568                                        final int startRow, final int endRow,
    569                                        final int startColumn, final int endColumn)
    570            throws MatrixIndexException, MatrixVisitorException {
    571            MatrixUtils.checkSubMatrixIndex(this, startRow, endRow, startColumn, endColumn);
    572            visitor.start(getRowDimension(), getColumnDimension(),
    573                          startRow, endRow, startColumn, endColumn);
    574            for (int j = startColumn; j <= endColumn; ++j) {
    575                for (int i = startRow; i <= endRow; ++i) {
    576                    final double[] rowI = data[i];
    577                    rowI[j] = visitor.visit(i, j, rowI[j]);
    578                }
    579            }
    580            return visitor.end();
    581        }
    582
    583        /** {@inheritDoc} */
    584        @Override
    585        public double walkInColumnOrder(final RealMatrixPreservingVisitor visitor,
    586                                        final int startRow, final int endRow,
    587                                        final int startColumn, final int endColumn)
    588            throws MatrixIndexException, MatrixVisitorException {
    589            MatrixUtils.checkSubMatrixIndex(this, startRow, endRow, startColumn, endColumn);
    590            visitor.start(getRowDimension(), getColumnDimension(),
    591                          startRow, endRow, startColumn, endColumn);
    592            for (int j = startColumn; j <= endColumn; ++j) {
    593                for (int i = startRow; i <= endRow; ++i) {
    594                    visitor.visit(i, j, data[i][j]);
    595                }
    596            }
    597            return visitor.end();
    598        }
    599
    600        /**
    601         * Returns a fresh copy of the underlying data array.
    602         *
    603         * @return a copy of the underlying data array.
    604         */
    605        private double[][] copyOut() {
    606            final int nRows = this.getRowDimension();
    607            final double[][] out = new double[nRows][this.getColumnDimension()];
    608            // can't copy 2-d array in one shot, otherwise get row references
    609            for (int i = 0; i < nRows; i++) {
    610                System.arraycopy(data[i], 0, out[i], 0, data[i].length);
    611            }
    612            return out;
    613        }
    614
    615        /**
    616         * Replaces data with a fresh copy of the input array.
    617         * <p>
    618         * Verifies that the input array is rectangular and non-empty.</p>
    619         *
    620         * @param in data to copy in
    621         * @throws IllegalArgumentException if input array is empty or not
    622         *    rectangular
    623         * @throws NullPointerException if input array is null
    624         */
    625        private void copyIn(final double[][] in) {
    626            setSubMatrix(in, 0, 0);
    627        }
    628
    629    }