    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.math3.linear;
    019
    020    import java.io.Serializable;
    021
    022    import org.apache.commons.math3.exception.DimensionMismatchException;
    023    import org.apache.commons.math3.exception.MathIllegalStateException;
    024    import org.apache.commons.math3.exception.NoDataException;
    025    import org.apache.commons.math3.exception.NotStrictlyPositiveException;
    026    import org.apache.commons.math3.exception.NullArgumentException;
    027    import org.apache.commons.math3.exception.NumberIsTooSmallException;
    028    import org.apache.commons.math3.exception.OutOfRangeException;
    029    import org.apache.commons.math3.exception.util.LocalizedFormats;
    030    import org.apache.commons.math3.util.MathUtils;
    031
    032    /**
    033     * Implementation of {@link RealMatrix} using a {@code double[][]} array to
    034     * store entries.
    035     *
    036     * @version $Id: Array2DRowRealMatrix.java 1416643 2012-12-03 19:37:14Z tn $
    037     */
    038    public class Array2DRowRealMatrix extends AbstractRealMatrix implements Serializable {
    039        /** Serializable version identifier. */
    040        private static final long serialVersionUID = -1067294169172445528L;
    041
    042        /** Entries of the matrix. */
    043        private double data[][];
    044
    045        /**
    046         * Creates a matrix with no data
    047         */
    048        public Array2DRowRealMatrix() {}
    049
    050        /**
    051         * Create a new RealMatrix with the supplied row and column dimensions.
    052         *
    053         * @param rowDimension Number of rows in the new matrix.
    054         * @param columnDimension Number of columns in the new matrix.
    055         * @throws NotStrictlyPositiveException if the row or column dimension is
    056         * not positive.
    057         */
    058        public Array2DRowRealMatrix(final int rowDimension,
    059                                    final int columnDimension)
    060            throws NotStrictlyPositiveException {
    061            super(rowDimension, columnDimension);
    062            data = new double[rowDimension][columnDimension];
    063        }
    064
    065        /**
    066         * Create a new {@code RealMatrix} using the input array as the underlying
    067         * data array.
    068         * <p>The input array is copied, not referenced. This constructor has
    069         * the same effect as calling {@link #Array2DRowRealMatrix(double[][], boolean)}
    070         * with the second argument set to {@code true}.</p>
    071         *
    072         * @param d Data for the new matrix.
    073         * @throws DimensionMismatchException if {@code d} is not rectangular.
    074         * @throws NoDataException if {@code d} row or colum dimension is zero.
    075         * @throws NullArgumentException if {@code d} is {@code null}.
    076         * @see #Array2DRowRealMatrix(double[][], boolean)
    077         */
    078        public Array2DRowRealMatrix(final double[][] d)
    079            throws DimensionMismatchException, NoDataException, NullArgumentException {
    080            copyIn(d);
    081        }
    082
    083        /**
    084         * Create a new RealMatrix using the input array as the underlying
    085         * data array.
    086         * If an array is built specially in order to be embedded in a
    087         * RealMatrix and not used directly, the {@code copyArray} may be
    088         * set to {@code false}. This will prevent the copying and improve
    089         * performance as no new array will be built and no data will be copied.
    090         *
    091         * @param d Data for new matrix.
    092         * @param copyArray if {@code true}, the input array will be copied,
    093         * otherwise it will be referenced.
    094         * @throws DimensionMismatchException if {@code d} is not rectangular.
    095         * @throws NoDataException if {@code d} row or colum dimension is zero.
    096         * @throws NullArgumentException if {@code d} is {@code null}.
    097         * @see #Array2DRowRealMatrix(double[][])
    098         */
    099        public Array2DRowRealMatrix(final double[][] d, final boolean copyArray)
    100            throws DimensionMismatchException, NoDataException,
    101            NullArgumentException {
    102            if (copyArray) {
    103                copyIn(d);
    104            } else {
    105                if (d == null) {
    106                    throw new NullArgumentException();
    107                }
    108                final int nRows = d.length;
    109                if (nRows == 0) {
    110                    throw new NoDataException(LocalizedFormats.AT_LEAST_ONE_ROW);
    111                }
    112                final int nCols = d[0].length;
    113                if (nCols == 0) {
    114                    throw new NoDataException(LocalizedFormats.AT_LEAST_ONE_COLUMN);
    115                }
    116                for (int r = 1; r < nRows; r++) {
    117                    if (d[r].length != nCols) {
    118                        throw new DimensionMismatchException(d[r].length, nCols);
    119                    }
    120                }
    121                data = d;
    122            }
    123        }
    124
    125        /**
    126         * Create a new (column) RealMatrix using {@code v} as the
    127         * data for the unique column of the created matrix.
    128         * The input array is copied.
    129         *
    130         * @param v Column vector holding data for new matrix.
    131         */
    132        public Array2DRowRealMatrix(final double[] v) {
    133            final int nRows = v.length;
    134            data = new double[nRows][1];
    135            for (int row = 0; row < nRows; row++) {
    136                data[row][0] = v[row];
    137            }
    138        }
    139
    140        /** {@inheritDoc} */
    141        @Override
    142        public RealMatrix createMatrix(final int rowDimension,
    143                                       final int columnDimension)
    144            throws NotStrictlyPositiveException {
    145            return new Array2DRowRealMatrix(rowDimension, columnDimension);
    146        }
    147
    148        /** {@inheritDoc} */
    149        @Override
    150        public RealMatrix copy() {
    151            return new Array2DRowRealMatrix(copyOut(), false);
    152        }
    153
    154        /**
    155         * Compute the sum of {@code this} and {@code m}.
    156         *
    157         * @param m Matrix to be added.
    158         * @return {@code this + m}.
    159         * @throws MatrixDimensionMismatchException if {@code m} is not the same
    160         * size as {@code this}.
    161         */
    162        public Array2DRowRealMatrix add(final Array2DRowRealMatrix m)
    163            throws MatrixDimensionMismatchException {
    164            // Safety check.
    165            MatrixUtils.checkAdditionCompatible(this, m);
    166
    167            final int rowCount    = getRowDimension();
    168            final int columnCount = getColumnDimension();
    169            final double[][] outData = new double[rowCount][columnCount];
    170            for (int row = 0; row < rowCount; row++) {
    171                final double[] dataRow    = data[row];
    172                final double[] mRow       = m.data[row];
    173                final double[] outDataRow = outData[row];
    174                for (int col = 0; col < columnCount; col++) {
    175                    outDataRow[col] = dataRow[col] + mRow[col];
    176                }
    177            }
    178
    179            return new Array2DRowRealMatrix(outData, false);
    180        }
    181
    182        /**
    183         * Returns {@code this} minus {@code m}.
    184         *
    185         * @param m Matrix to be subtracted.
    186         * @return {@code this - m}
    187         * @throws MatrixDimensionMismatchException if {@code m} is not the same
    188         * size as {@code this}.
    189         */
    190        public Array2DRowRealMatrix subtract(final Array2DRowRealMatrix m)
    191            throws MatrixDimensionMismatchException {
    192            MatrixUtils.checkSubtractionCompatible(this, m);
    193
    194            final int rowCount    = getRowDimension();
    195            final int columnCount = getColumnDimension();
    196            final double[][] outData = new double[rowCount][columnCount];
    197            for (int row = 0; row < rowCount; row++) {
    198                final double[] dataRow    = data[row];
    199                final double[] mRow       = m.data[row];
    200                final double[] outDataRow = outData[row];
    201                for (int col = 0; col < columnCount; col++) {
    202                    outDataRow[col] = dataRow[col] - mRow[col];
    203                }
    204            }
    205
    206            return new Array2DRowRealMatrix(outData, false);
    207        }
    208
    209        /**
    210         * Returns the result of postmultiplying {@code this} by {@code m}.
    211         *
    212         * @param m matrix to postmultiply by
    213         * @return {@code this * m}
    214         * @throws DimensionMismatchException if
    215         * {@code columnDimension(this) != rowDimension(m)}
    216         */
    217        public Array2DRowRealMatrix multiply(final Array2DRowRealMatrix m)
    218            throws DimensionMismatchException {
    219            MatrixUtils.checkMultiplicationCompatible(this, m);
    220
    221            final int nRows = this.getRowDimension();
    222            final int nCols = m.getColumnDimension();
    223            final int nSum = this.getColumnDimension();
    224
    225            final double[][] outData = new double[nRows][nCols];
    226            // Will hold a column of "m".
    227            final double[] mCol = new double[nSum];
    228            final double[][] mData = m.data;
    229
    230            // Multiply.
    231            for (int col = 0; col < nCols; col++) {
    232                // Copy all elements of column "col" of "m" so that
    233                // will be in contiguous memory.
    234                for (int mRow = 0; mRow < nSum; mRow++) {
    235                    mCol[mRow] = mData[mRow][col];
    236                }
    237
    238                for (int row = 0; row < nRows; row++) {
    239                    final double[] dataRow = data[row];
    240                    double sum = 0;
    241                    for (int i = 0; i < nSum; i++) {
    242                        sum += dataRow[i] * mCol[i];
    243                    }
    244                    outData[row][col] = sum;
    245                }
    246            }
    247
    248            return new Array2DRowRealMatrix(outData, false);
    249        }
    250
    251        /** {@inheritDoc} */
    252        @Override
    253        public double[][] getData() {
    254            return copyOut();
    255        }
    256
    257        /**
    258         * Get a reference to the underlying data array.
    259         *
    260         * @return 2-dimensional array of entries.
    261         */
    262        public double[][] getDataRef() {
    263            return data;
    264        }
    265
    266        /** {@inheritDoc} */
    267        @Override
    268        public void setSubMatrix(final double[][] subMatrix, final int row,
    269                                 final int column)
    270            throws NoDataException, OutOfRangeException,
    271            DimensionMismatchException, NullArgumentException {
    272            if (data == null) {
    273                if (row > 0) {
    274                    throw new MathIllegalStateException(LocalizedFormats.FIRST_ROWS_NOT_INITIALIZED_YET, row);
    275                }
    276                if (column > 0) {
    277                    throw new MathIllegalStateException(LocalizedFormats.FIRST_COLUMNS_NOT_INITIALIZED_YET, column);
    278                }
    279                MathUtils.checkNotNull(subMatrix);
    280                final int nRows = subMatrix.length;
    281                if (nRows == 0) {
    282                    throw new NoDataException(LocalizedFormats.AT_LEAST_ONE_ROW);
    283                }
    284
    285                final int nCols = subMatrix[0].length;
    286                if (nCols == 0) {
    287                    throw new NoDataException(LocalizedFormats.AT_LEAST_ONE_COLUMN);
    288                }
    289                data = new double[subMatrix.length][nCols];
    290                for (int i = 0; i < data.length; ++i) {
    291                    if (subMatrix[i].length != nCols) {
    292                        throw new DimensionMismatchException(subMatrix[i].length, nCols);
    293                    }
    294                    System.arraycopy(subMatrix[i], 0, data[i + row], column, nCols);
    295                }
    296            } else {
    297                super.setSubMatrix(subMatrix, row, column);
    298            }
    299
    300        }
    301
    302        /** {@inheritDoc} */
    303        @Override
    304        public double getEntry(final int row, final int column)
    305            throws OutOfRangeException {
    306            MatrixUtils.checkMatrixIndex(this, row, column);
    307            return data[row][column];
    308        }
    309
    310        /** {@inheritDoc} */
    311        @Override
    312        public void setEntry(final int row, final int column, final double value)
    313            throws OutOfRangeException {
    314            MatrixUtils.checkMatrixIndex(this, row, column);
    315            data[row][column] = value;
    316        }
    317
    318        /** {@inheritDoc} */
    319        @Override
    320        public void addToEntry(final int row, final int column,
    321                               final double increment)
    322            throws OutOfRangeException {
    323            MatrixUtils.checkMatrixIndex(this, row, column);
    324            data[row][column] += increment;
    325        }
    326
    327        /** {@inheritDoc} */
    328        @Override
    329        public void multiplyEntry(final int row, final int column,
    330                                  final double factor)
    331            throws OutOfRangeException {
    332            MatrixUtils.checkMatrixIndex(this, row, column);
    333            data[row][column] *= factor;
    334        }
    335
    336        /** {@inheritDoc} */
    337        @Override
    338        public int getRowDimension() {
    339            return (data == null) ? 0 : data.length;
    340        }
    341
    342        /** {@inheritDoc} */
    343        @Override
    344        public int getColumnDimension() {
    345            return ((data == null) || (data[0] == null)) ? 0 : data[0].length;
    346        }
    347
    348        /** {@inheritDoc} */
    349        @Override
    350        public double[] operate(final double[] v)
    351            throws DimensionMismatchException {
    352            final int nRows = this.getRowDimension();
    353            final int nCols = this.getColumnDimension();
    354            if (v.length != nCols) {
    355                throw new DimensionMismatchException(v.length, nCols);
    356            }
    357            final double[] out = new double[nRows];
    358            for (int row = 0; row < nRows; row++) {
    359                final double[] dataRow = data[row];
    360                double sum = 0;
    361                for (int i = 0; i < nCols; i++) {
    362                    sum += dataRow[i] * v[i];
    363                }
    364                out[row] = sum;
    365            }
    366            return out;
    367        }
    368
    369        /** {@inheritDoc} */
    370        @Override
    371        public double[] preMultiply(final double[] v)
    372            throws DimensionMismatchException {
    373            final int nRows = getRowDimension();
    374            final int nCols = getColumnDimension();
    375            if (v.length != nRows) {
    376                throw new DimensionMismatchException(v.length, nRows);
    377            }
    378
    379            final double[] out = new double[nCols];
    380            for (int col = 0; col < nCols; ++col) {
    381                double sum = 0;
    382                for (int i = 0; i < nRows; ++i) {
    383                    sum += data[i][col] * v[i];
    384                }
    385                out[col] = sum;
    386            }
    387
    388            return out;
    389
    390        }
    391
    392        /** {@inheritDoc} */
    393        @Override
    394        public double walkInRowOrder(final RealMatrixChangingVisitor visitor) {
    395            final int rows    = getRowDimension();
    396            final int columns = getColumnDimension();
    397            visitor.start(rows, columns, 0, rows - 1, 0, columns - 1);
    398            for (int i = 0; i < rows; ++i) {
    399                final double[] rowI = data[i];
    400                for (int j = 0; j < columns; ++j) {
    401                    rowI[j] = visitor.visit(i, j, rowI[j]);
    402                }
    403            }
    404            return visitor.end();
    405        }
    406
    407        /** {@inheritDoc} */
    408        @Override
    409        public double walkInRowOrder(final RealMatrixPreservingVisitor visitor) {
    410            final int rows    = getRowDimension();
    411            final int columns = getColumnDimension();
    412            visitor.start(rows, columns, 0, rows - 1, 0, columns - 1);
    413            for (int i = 0; i < rows; ++i) {
    414                final double[] rowI = data[i];
    415                for (int j = 0; j < columns; ++j) {
    416                    visitor.visit(i, j, rowI[j]);
    417                }
    418            }
    419            return visitor.end();
    420        }
    421
    422        /** {@inheritDoc} */
    423        @Override
    424        public double walkInRowOrder(final RealMatrixChangingVisitor visitor,
    425                                     final int startRow, final int endRow,
    426                                     final int startColumn, final int endColumn)
    427            throws OutOfRangeException, NumberIsTooSmallException {
    428            MatrixUtils.checkSubMatrixIndex(this, startRow, endRow, startColumn, endColumn);
    429            visitor.start(getRowDimension(), getColumnDimension(),
    430                          startRow, endRow, startColumn, endColumn);
    431            for (int i = startRow; i <= endRow; ++i) {
    432                final double[] rowI = data[i];
    433                for (int j = startColumn; j <= endColumn; ++j) {
    434                    rowI[j] = visitor.visit(i, j, rowI[j]);
    435                }
    436            }
    437            return visitor.end();
    438        }
    439
    440        /** {@inheritDoc} */
    441        @Override
    442        public double walkInRowOrder(final RealMatrixPreservingVisitor visitor,
    443                                     final int startRow, final int endRow,
    444                                     final int startColumn, final int endColumn)
    445            throws OutOfRangeException, NumberIsTooSmallException {
    446            MatrixUtils.checkSubMatrixIndex(this, startRow, endRow, startColumn, endColumn);
    447            visitor.start(getRowDimension(), getColumnDimension(),
    448                          startRow, endRow, startColumn, endColumn);
    449            for (int i = startRow; i <= endRow; ++i) {
    450                final double[] rowI = data[i];
    451                for (int j = startColumn; j <= endColumn; ++j) {
    452                    visitor.visit(i, j, rowI[j]);
    453                }
    454            }
    455            return visitor.end();
    456        }
    457
    458        /** {@inheritDoc} */
    459        @Override
    460        public double walkInColumnOrder(final RealMatrixChangingVisitor visitor) {
    461            final int rows    = getRowDimension();
    462            final int columns = getColumnDimension();
    463            visitor.start(rows, columns, 0, rows - 1, 0, columns - 1);
    464            for (int j = 0; j < columns; ++j) {
    465                for (int i = 0; i < rows; ++i) {
    466                    final double[] rowI = data[i];
    467                    rowI[j] = visitor.visit(i, j, rowI[j]);
    468                }
    469            }
    470            return visitor.end();
    471        }
    472
    473        /** {@inheritDoc} */
    474        @Override
    475        public double walkInColumnOrder(final RealMatrixPreservingVisitor visitor) {
    476            final int rows    = getRowDimension();
    477            final int columns = getColumnDimension();
    478            visitor.start(rows, columns, 0, rows - 1, 0, columns - 1);
    479            for (int j = 0; j < columns; ++j) {
    480                for (int i = 0; i < rows; ++i) {
    481                    visitor.visit(i, j, data[i][j]);
    482                }
    483            }
    484            return visitor.end();
    485        }
    486
    487        /** {@inheritDoc} */
    488        @Override
    489        public double walkInColumnOrder(final RealMatrixChangingVisitor visitor,
    490                                        final int startRow, final int endRow,
    491                                        final int startColumn, final int endColumn)
    492            throws OutOfRangeException, NumberIsTooSmallException {
    493            MatrixUtils.checkSubMatrixIndex(this, startRow, endRow, startColumn, endColumn);
    494            visitor.start(getRowDimension(), getColumnDimension(),
    495                          startRow, endRow, startColumn, endColumn);
    496            for (int j = startColumn; j <= endColumn; ++j) {
    497                for (int i = startRow; i <= endRow; ++i) {
    498                    final double[] rowI = data[i];
    499                    rowI[j] = visitor.visit(i, j, rowI[j]);
    500                }
    501            }
    502            return visitor.end();
    503        }
    504
    505        /** {@inheritDoc} */
    506        @Override
    507        public double walkInColumnOrder(final RealMatrixPreservingVisitor visitor,
    508                                        final int startRow, final int endRow,
    509                                        final int startColumn, final int endColumn)
    510            throws OutOfRangeException, NumberIsTooSmallException {
    511            MatrixUtils.checkSubMatrixIndex(this, startRow, endRow, startColumn, endColumn);
    512            visitor.start(getRowDimension(), getColumnDimension(),
    513                          startRow, endRow, startColumn, endColumn);
    514            for (int j = startColumn; j <= endColumn; ++j) {
    515                for (int i = startRow; i <= endRow; ++i) {
    516                    visitor.visit(i, j, data[i][j]);
    517                }
    518            }
    519            return visitor.end();
    520        }
    521
    522        /**
    523         * Get a fresh copy of the underlying data array.
    524         *
    525         * @return a copy of the underlying data array.
    526         */
    527        private double[][] copyOut() {
    528            final int nRows = this.getRowDimension();
    529            final double[][] out = new double[nRows][this.getColumnDimension()];
    530            // can't copy 2-d array in one shot, otherwise get row references
    531            for (int i = 0; i < nRows; i++) {
    532                System.arraycopy(data[i], 0, out[i], 0, data[i].length);
    533            }
    534            return out;
    535        }
    536
    537        /**
    538         * Replace data with a fresh copy of the input array.
    539         *
    540         * @param in Data to copy.
    541         * @throws NoDataException if the input array is empty.
    542         * @throws DimensionMismatchException if the input array is not rectangular.
    543         * @throws NullArgumentException if the input array is {@code null}.
    544         */
    545        private void copyIn(final double[][] in)
    546            throws DimensionMismatchException, NoDataException, NullArgumentException {
    547            setSubMatrix(in, 0, 0);
    548        }
    549    }