    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 org.apache.commons.math.MathRuntimeException;
    021    import org.apache.commons.math.linear.MatrixVisitorException;
    022    import org.apache.commons.math.exception.util.LocalizedFormats;
    023    import org.apache.commons.math.util.MathUtils;
    024    import org.apache.commons.math.util.FastMath;
    025
    026    /**
    027     * Basic implementation of RealMatrix methods regardless of the underlying storage.
    028     * <p>All the methods implemented here use {@link #getEntry(int, int)} to access
    029     * matrix elements. Derived class can provide faster implementations. </p>
    030     *
    031     * @version $Revision: 1073158 $ $Date: 2011-02-21 22:46:52 +0100 (lun. 21 f??vr. 2011) $
    032     * @since 2.0
    033     */
    034    public abstract class AbstractRealMatrix implements RealMatrix {
    035
    036
    037        /** Cached LU solver.
    038         * @deprecated as of release 2.0, since all methods using this are deprecated
    039         */
    040        @Deprecated
    041        private DecompositionSolver lu;
    042
    043        /**
    044         * Creates a matrix with no data
    045         */
    046        protected AbstractRealMatrix() {
    047            lu = null;
    048        }
    049
    050        /**
    051         * Create a new RealMatrix with the supplied row and column dimensions.
    052         *
    053         * @param rowDimension  the number of rows in the new matrix
    054         * @param columnDimension  the number of columns in the new matrix
    055         * @throws IllegalArgumentException if row or column dimension is not positive
    056         */
    057        protected AbstractRealMatrix(final int rowDimension, final int columnDimension)
    058            throws IllegalArgumentException {
    059            if (rowDimension < 1 ) {
    060                throw MathRuntimeException.createIllegalArgumentException(
    061                        LocalizedFormats.INSUFFICIENT_DIMENSION, rowDimension, 1);
    062            }
    063            if (columnDimension <= 0) {
    064                throw MathRuntimeException.createIllegalArgumentException(
    065                        LocalizedFormats.INSUFFICIENT_DIMENSION, columnDimension, 1);
    066            }
    067            lu = null;
    068        }
    069
    070        /** {@inheritDoc} */
    071        public abstract RealMatrix createMatrix(final int rowDimension, final int columnDimension)
    072            throws IllegalArgumentException;
    073
    074        /** {@inheritDoc} */
    075        public abstract RealMatrix copy();
    076
    077        /** {@inheritDoc} */
    078        public RealMatrix add(RealMatrix m) throws IllegalArgumentException {
    079
    080            // safety check
    081            MatrixUtils.checkAdditionCompatible(this, m);
    082
    083            final int rowCount    = getRowDimension();
    084            final int columnCount = getColumnDimension();
    085            final RealMatrix out = createMatrix(rowCount, columnCount);
    086            for (int row = 0; row < rowCount; ++row) {
    087                for (int col = 0; col < columnCount; ++col) {
    088                    out.setEntry(row, col, getEntry(row, col) + m.getEntry(row, col));
    089                }
    090            }
    091
    092            return out;
    093
    094        }
    095
    096        /** {@inheritDoc} */
    097        public RealMatrix subtract(final RealMatrix m) throws IllegalArgumentException {
    098
    099            // safety check
    100            MatrixUtils.checkSubtractionCompatible(this, m);
    101
    102            final int rowCount    = getRowDimension();
    103            final int columnCount = getColumnDimension();
    104            final RealMatrix out = createMatrix(rowCount, columnCount);
    105            for (int row = 0; row < rowCount; ++row) {
    106                for (int col = 0; col < columnCount; ++col) {
    107                    out.setEntry(row, col, getEntry(row, col) - m.getEntry(row, col));
    108                }
    109            }
    110
    111            return out;
    112
    113        }
    114
    115        /** {@inheritDoc} */
    116        public RealMatrix scalarAdd(final double d) {
    117
    118            final int rowCount    = getRowDimension();
    119            final int columnCount = getColumnDimension();
    120            final RealMatrix out = createMatrix(rowCount, columnCount);
    121            for (int row = 0; row < rowCount; ++row) {
    122                for (int col = 0; col < columnCount; ++col) {
    123                    out.setEntry(row, col, getEntry(row, col) + d);
    124                }
    125            }
    126
    127            return out;
    128
    129        }
    130
    131        /** {@inheritDoc} */
    132        public RealMatrix scalarMultiply(final double d) {
    133
    134            final int rowCount    = getRowDimension();
    135            final int columnCount = getColumnDimension();
    136            final RealMatrix out = createMatrix(rowCount, columnCount);
    137            for (int row = 0; row < rowCount; ++row) {
    138                for (int col = 0; col < columnCount; ++col) {
    139                    out.setEntry(row, col, getEntry(row, col) * d);
    140                }
    141            }
    142
    143            return out;
    144
    145        }
    146
    147        /** {@inheritDoc} */
    148        public RealMatrix multiply(final RealMatrix m)
    149            throws IllegalArgumentException {
    150
    151            // safety check
    152            MatrixUtils.checkMultiplicationCompatible(this, m);
    153
    154            final int nRows = getRowDimension();
    155            final int nCols = m.getColumnDimension();
    156            final int nSum  = getColumnDimension();
    157            final RealMatrix out = createMatrix(nRows, nCols);
    158            for (int row = 0; row < nRows; ++row) {
    159                for (int col = 0; col < nCols; ++col) {
    160                    double sum = 0;
    161                    for (int i = 0; i < nSum; ++i) {
    162                        sum += getEntry(row, i) * m.getEntry(i, col);
    163                    }
    164                    out.setEntry(row, col, sum);
    165                }
    166            }
    167
    168            return out;
    169
    170        }
    171
    172        /** {@inheritDoc} */
    173        public RealMatrix preMultiply(final RealMatrix m)
    174            throws IllegalArgumentException {
    175            return m.multiply(this);
    176        }
    177
    178        /** {@inheritDoc} */
    179        public double[][] getData() {
    180
    181            final double[][] data = new double[getRowDimension()][getColumnDimension()];
    182
    183            for (int i = 0; i < data.length; ++i) {
    184                final double[] dataI = data[i];
    185                for (int j = 0; j < dataI.length; ++j) {
    186                    dataI[j] = getEntry(i, j);
    187                }
    188            }
    189
    190            return data;
    191
    192        }
    193
    194        /** {@inheritDoc} */
    195        public double getNorm() {
    196            return walkInColumnOrder(new RealMatrixPreservingVisitor() {
    197
    198                /** Last row index. */
    199                private double endRow;
    200
    201                /** Sum of absolute values on one column. */
    202                private double columnSum;
    203
    204                /** Maximal sum across all columns. */
    205                private double maxColSum;
    206
    207                /** {@inheritDoc} */
    208                public void start(final int rows, final int columns,
    209                                  final int startRow, final int endRow,
    210                                  final int startColumn, final int endColumn) {
    211                    this.endRow = endRow;
    212                    columnSum   = 0;
    213                    maxColSum   = 0;
    214                }
    215
    216                /** {@inheritDoc} */
    217                public void visit(final int row, final int column, final double value) {
    218                    columnSum += FastMath.abs(value);
    219                    if (row == endRow) {
    220                        maxColSum = FastMath.max(maxColSum, columnSum);
    221                        columnSum = 0;
    222                    }
    223                }
    224
    225                /** {@inheritDoc} */
    226                public double end() {
    227                    return maxColSum;
    228                }
    229
    230            });
    231        }
    232
    233        /** {@inheritDoc} */
    234        public double getFrobeniusNorm() {
    235            return walkInOptimizedOrder(new RealMatrixPreservingVisitor() {
    236
    237                /** Sum of squared entries. */
    238                private double sum;
    239
    240                /** {@inheritDoc} */
    241                public void start(final int rows, final int columns,
    242                                  final int startRow, final int endRow,
    243                                  final int startColumn, final int endColumn) {
    244                    sum = 0;
    245                }
    246
    247                /** {@inheritDoc} */
    248                public void visit(final int row, final int column, final double value) {
    249                    sum += value * value;
    250                }
    251
    252                /** {@inheritDoc} */
    253                public double end() {
    254                    return FastMath.sqrt(sum);
    255                }
    256
    257            });
    258        }
    259
    260        /** {@inheritDoc} */
    261        public RealMatrix getSubMatrix(final int startRow, final int endRow,
    262                                       final int startColumn, final int endColumn)
    263            throws MatrixIndexException {
    264
    265            MatrixUtils.checkSubMatrixIndex(this, startRow, endRow, startColumn, endColumn);
    266
    267            final RealMatrix subMatrix =
    268                createMatrix(endRow - startRow + 1, endColumn - startColumn + 1);
    269            for (int i = startRow; i <= endRow; ++i) {
    270                for (int j = startColumn; j <= endColumn; ++j) {
    271                    subMatrix.setEntry(i - startRow, j - startColumn, getEntry(i, j));
    272                }
    273            }
    274
    275            return subMatrix;
    276
    277        }
    278
    279        /** {@inheritDoc} */
    280        public RealMatrix getSubMatrix(final int[] selectedRows, final int[] selectedColumns)
    281            throws MatrixIndexException {
    282
    283            // safety checks
    284            MatrixUtils.checkSubMatrixIndex(this, selectedRows, selectedColumns);
    285
    286            // copy entries
    287            final RealMatrix subMatrix =
    288                createMatrix(selectedRows.length, selectedColumns.length);
    289            subMatrix.walkInOptimizedOrder(new DefaultRealMatrixChangingVisitor() {
    290
    291                /** {@inheritDoc} */
    292                @Override
    293                public double visit(final int row, final int column, final double value) {
    294                    return getEntry(selectedRows[row], selectedColumns[column]);
    295                }
    296
    297            });
    298
    299            return subMatrix;
    300
    301        }
    302
    303        /** {@inheritDoc} */
    304        public void copySubMatrix(final int startRow, final int endRow,
    305                                  final int startColumn, final int endColumn,
    306                                  final double[][] destination)
    307            throws MatrixIndexException, IllegalArgumentException {
    308
    309            // safety checks
    310            MatrixUtils.checkSubMatrixIndex(this, startRow, endRow, startColumn, endColumn);
    311            final int rowsCount    = endRow + 1 - startRow;
    312            final int columnsCount = endColumn + 1 - startColumn;
    313            if ((destination.length < rowsCount) || (destination[0].length < columnsCount)) {
    314                throw MathRuntimeException.createIllegalArgumentException(
    315                        LocalizedFormats.DIMENSIONS_MISMATCH_2x2,
    316                        destination.length, destination[0].length,
    317                        rowsCount, columnsCount);
    318            }
    319
    320            // copy entries
    321            walkInOptimizedOrder(new DefaultRealMatrixPreservingVisitor() {
    322
    323                /** Initial row index. */
    324                private int startRow;
    325
    326                /** Initial column index. */
    327                private int startColumn;
    328
    329                /** {@inheritDoc} */
    330                @Override
    331                public void start(final int rows, final int columns,
    332                                  final int startRow, final int endRow,
    333                                  final int startColumn, final int endColumn) {
    334                    this.startRow    = startRow;
    335                    this.startColumn = startColumn;
    336                }
    337
    338                /** {@inheritDoc} */
    339                @Override
    340                public void visit(final int row, final int column, final double value) {
    341                    destination[row - startRow][column - startColumn] = value;
    342                }
    343
    344            }, startRow, endRow, startColumn, endColumn);
    345
    346        }
    347
    348        /** {@inheritDoc} */
    349        public void copySubMatrix(int[] selectedRows, int[] selectedColumns, double[][] destination)
    350            throws MatrixIndexException, IllegalArgumentException {
    351
    352            // safety checks
    353            MatrixUtils.checkSubMatrixIndex(this, selectedRows, selectedColumns);
    354            if ((destination.length < selectedRows.length) ||
    355                (destination[0].length < selectedColumns.length)) {
    356                throw MathRuntimeException.createIllegalArgumentException(
    357                        LocalizedFormats.DIMENSIONS_MISMATCH_2x2,
    358                        destination.length, destination[0].length,
    359                        selectedRows.length, selectedColumns.length);
    360            }
    361
    362            // copy entries
    363            for (int i = 0; i < selectedRows.length; i++) {
    364                final double[] destinationI = destination[i];
    365                for (int j = 0; j < selectedColumns.length; j++) {
    366                    destinationI[j] = getEntry(selectedRows[i], selectedColumns[j]);
    367                }
    368            }
    369
    370        }
    371
    372        /** {@inheritDoc} */
    373        public void setSubMatrix(final double[][] subMatrix, final int row, final int column)
    374            throws MatrixIndexException {
    375
    376            final int nRows = subMatrix.length;
    377            if (nRows == 0) {
    378                throw MathRuntimeException.createIllegalArgumentException(LocalizedFormats.AT_LEAST_ONE_ROW);
    379            }
    380
    381            final int nCols = subMatrix[0].length;
    382            if (nCols == 0) {
    383                throw MathRuntimeException.createIllegalArgumentException(LocalizedFormats.AT_LEAST_ONE_COLUMN);
    384            }
    385
    386            for (int r = 1; r < nRows; ++r) {
    387                if (subMatrix[r].length != nCols) {
    388                    throw MathRuntimeException.createIllegalArgumentException(
    389                            LocalizedFormats.DIFFERENT_ROWS_LENGTHS,
    390                            nCols, subMatrix[r].length);
    391                }
    392            }
    393
    394            MatrixUtils.checkRowIndex(this, row);
    395            MatrixUtils.checkColumnIndex(this, column);
    396            MatrixUtils.checkRowIndex(this, nRows + row - 1);
    397            MatrixUtils.checkColumnIndex(this, nCols + column - 1);
    398
    399            for (int i = 0; i < nRows; ++i) {
    400                for (int j = 0; j < nCols; ++j) {
    401                    setEntry(row + i, column + j, subMatrix[i][j]);
    402                }
    403            }
    404
    405            lu = null;
    406
    407        }
    408
    409        /** {@inheritDoc} */
    410        public RealMatrix getRowMatrix(final int row)
    411            throws MatrixIndexException {
    412
    413            MatrixUtils.checkRowIndex(this, row);
    414            final int nCols = getColumnDimension();
    415            final RealMatrix out = createMatrix(1, nCols);
    416            for (int i = 0; i < nCols; ++i) {
    417                out.setEntry(0, i, getEntry(row, i));
    418            }
    419
    420            return out;
    421
    422        }
    423
    424        /** {@inheritDoc} */
    425        public void setRowMatrix(final int row, final RealMatrix matrix)
    426            throws MatrixIndexException, InvalidMatrixException {
    427
    428            MatrixUtils.checkRowIndex(this, row);
    429            final int nCols = getColumnDimension();
    430            if ((matrix.getRowDimension() != 1) ||
    431                (matrix.getColumnDimension() != nCols)) {
    432                throw new InvalidMatrixException(
    433                        LocalizedFormats.DIMENSIONS_MISMATCH_2x2,
    434                        matrix.getRowDimension(), matrix.getColumnDimension(), 1, nCols);
    435            }
    436            for (int i = 0; i < nCols; ++i) {
    437                setEntry(row, i, matrix.getEntry(0, i));
    438            }
    439
    440        }
    441
    442        /** {@inheritDoc} */
    443        public RealMatrix getColumnMatrix(final int column)
    444            throws MatrixIndexException {
    445
    446            MatrixUtils.checkColumnIndex(this, column);
    447            final int nRows = getRowDimension();
    448            final RealMatrix out = createMatrix(nRows, 1);
    449            for (int i = 0; i < nRows; ++i) {
    450                out.setEntry(i, 0, getEntry(i, column));
    451            }
    452
    453            return out;
    454
    455        }
    456
    457        /** {@inheritDoc} */
    458        public void setColumnMatrix(final int column, final RealMatrix matrix)
    459            throws MatrixIndexException, InvalidMatrixException {
    460
    461            MatrixUtils.checkColumnIndex(this, column);
    462            final int nRows = getRowDimension();
    463            if ((matrix.getRowDimension() != nRows) ||
    464                (matrix.getColumnDimension() != 1)) {
    465                throw new InvalidMatrixException(
    466                        LocalizedFormats.DIMENSIONS_MISMATCH_2x2,
    467                        matrix.getRowDimension(), matrix.getColumnDimension(), nRows, 1);
    468            }
    469            for (int i = 0; i < nRows; ++i) {
    470                setEntry(i, column, matrix.getEntry(i, 0));
    471            }
    472
    473        }
    474
    475        /** {@inheritDoc} */
    476        public RealVector getRowVector(final int row)
    477            throws MatrixIndexException {
    478            return new ArrayRealVector(getRow(row), false);
    479        }
    480
    481        /** {@inheritDoc} */
    482        public void setRowVector(final int row, final RealVector vector)
    483            throws MatrixIndexException, InvalidMatrixException {
    484
    485            MatrixUtils.checkRowIndex(this, row);
    486            final int nCols = getColumnDimension();
    487            if (vector.getDimension() != nCols) {
    488                throw new InvalidMatrixException(
    489                        LocalizedFormats.DIMENSIONS_MISMATCH_2x2,
    490                        1, vector.getDimension(), 1, nCols);
    491            }
    492            for (int i = 0; i < nCols; ++i) {
    493                setEntry(row, i, vector.getEntry(i));
    494            }
    495
    496        }
    497
    498        /** {@inheritDoc} */
    499        public RealVector getColumnVector(final int column)
    500            throws MatrixIndexException {
    501            return new ArrayRealVector(getColumn(column), false);
    502        }
    503
    504        /** {@inheritDoc} */
    505        public void setColumnVector(final int column, final RealVector vector)
    506            throws MatrixIndexException, InvalidMatrixException {
    507
    508            MatrixUtils.checkColumnIndex(this, column);
    509            final int nRows = getRowDimension();
    510            if (vector.getDimension() != nRows) {
    511                throw new InvalidMatrixException(
    512                        LocalizedFormats.DIMENSIONS_MISMATCH_2x2,
    513                        vector.getDimension(), 1, nRows, 1);
    514            }
    515            for (int i = 0; i < nRows; ++i) {
    516                setEntry(i, column, vector.getEntry(i));
    517            }
    518
    519        }
    520
    521        /** {@inheritDoc} */
    522        public double[] getRow(final int row)
    523            throws MatrixIndexException {
    524
    525            MatrixUtils.checkRowIndex(this, row);
    526            final int nCols = getColumnDimension();
    527            final double[] out = new double[nCols];
    528            for (int i = 0; i < nCols; ++i) {
    529                out[i] = getEntry(row, i);
    530            }
    531
    532            return out;
    533
    534        }
    535
    536        /** {@inheritDoc} */
    537        public void setRow(final int row, final double[] array)
    538            throws MatrixIndexException, InvalidMatrixException {
    539
    540            MatrixUtils.checkRowIndex(this, row);
    541            final int nCols = getColumnDimension();
    542            if (array.length != nCols) {
    543                throw new InvalidMatrixException(
    544                        LocalizedFormats.DIMENSIONS_MISMATCH_2x2,
    545                        1, array.length, 1, nCols);
    546            }
    547            for (int i = 0; i < nCols; ++i) {
    548                setEntry(row, i, array[i]);
    549            }
    550
    551        }
    552
    553        /** {@inheritDoc} */
    554        public double[] getColumn(final int column)
    555            throws MatrixIndexException {
    556
    557            MatrixUtils.checkColumnIndex(this, column);
    558            final int nRows = getRowDimension();
    559            final double[] out = new double[nRows];
    560            for (int i = 0; i < nRows; ++i) {
    561                out[i] = getEntry(i, column);
    562            }
    563
    564            return out;
    565
    566        }
    567
    568        /** {@inheritDoc} */
    569        public void setColumn(final int column, final double[] array)
    570            throws MatrixIndexException, InvalidMatrixException {
    571
    572            MatrixUtils.checkColumnIndex(this, column);
    573            final int nRows = getRowDimension();
    574            if (array.length != nRows) {
    575                throw new InvalidMatrixException(
    576                        LocalizedFormats.DIMENSIONS_MISMATCH_2x2,
    577                        array.length, 1, nRows, 1);
    578            }
    579            for (int i = 0; i < nRows; ++i) {
    580                setEntry(i, column, array[i]);
    581            }
    582
    583        }
    584
    585        /** {@inheritDoc} */
    586        public abstract double getEntry(int row, int column)
    587            throws MatrixIndexException;
    588
    589        /** {@inheritDoc} */
    590        public abstract void setEntry(int row, int column, double value)
    591            throws MatrixIndexException;
    592
    593        /** {@inheritDoc} */
    594        public abstract void addToEntry(int row, int column, double increment)
    595            throws MatrixIndexException;
    596
    597        /** {@inheritDoc} */
    598        public abstract void multiplyEntry(int row, int column, double factor)
    599            throws MatrixIndexException;
    600
    601        /** {@inheritDoc} */
    602        public RealMatrix transpose() {
    603
    604            final int nRows = getRowDimension();
    605            final int nCols = getColumnDimension();
    606            final RealMatrix out = createMatrix(nCols, nRows);
    607            walkInOptimizedOrder(new DefaultRealMatrixPreservingVisitor() {
    608
    609                /** {@inheritDoc} */
    610                @Override
    611                public void visit(final int row, final int column, final double value) {
    612                    out.setEntry(column, row, value);
    613                }
    614
    615            });
    616
    617            return out;
    618
    619        }
    620
    621        /** {@inheritDoc} */
    622        @Deprecated
    623        public RealMatrix inverse()
    624            throws InvalidMatrixException {
    625            if (lu == null) {
    626                lu = new LUDecompositionImpl(this, MathUtils.SAFE_MIN).getSolver();
    627            }
    628            return lu.getInverse();
    629        }
    630
    631        /** {@inheritDoc} */
    632        @Deprecated
    633        public double getDeterminant()
    634            throws InvalidMatrixException {
    635            return new LUDecompositionImpl(this, MathUtils.SAFE_MIN).getDeterminant();
    636        }
    637
    638        /** {@inheritDoc} */
    639        public boolean isSquare() {
    640            return getColumnDimension() == getRowDimension();
    641        }
    642
    643        /** {@inheritDoc} */
    644        @Deprecated
    645        public boolean isSingular() {
    646            if (lu == null) {
    647                lu = new LUDecompositionImpl(this, MathUtils.SAFE_MIN).getSolver();
    648           }
    649            return !lu.isNonSingular();
    650        }
    651
    652        /** {@inheritDoc} */
    653        public abstract int getRowDimension();
    654
    655        /** {@inheritDoc} */
    656        public abstract int getColumnDimension();
    657
    658        /** {@inheritDoc} */
    659        public double getTrace()
    660            throws NonSquareMatrixException {
    661            final int nRows = getRowDimension();
    662            final int nCols = getColumnDimension();
    663            if (nRows != nCols) {
    664                throw new NonSquareMatrixException(nRows, nCols);
    665           }
    666            double trace = 0;
    667            for (int i = 0; i < nRows; ++i) {
    668                trace += getEntry(i, i);
    669            }
    670            return trace;
    671        }
    672
    673        /** {@inheritDoc} */
    674        public double[] operate(final double[] v)
    675            throws IllegalArgumentException {
    676
    677            final int nRows = getRowDimension();
    678            final int nCols = getColumnDimension();
    679            if (v.length != nCols) {
    680                throw MathRuntimeException.createIllegalArgumentException(
    681                        LocalizedFormats.VECTOR_LENGTH_MISMATCH,
    682                        v.length, nCols);
    683            }
    684
    685            final double[] out = new double[nRows];
    686            for (int row = 0; row < nRows; ++row) {
    687                double sum = 0;
    688                for (int i = 0; i < nCols; ++i) {
    689                    sum += getEntry(row, i) * v[i];
    690                }
    691                out[row] = sum;
    692            }
    693
    694            return out;
    695
    696        }
    697
    698        /** {@inheritDoc} */
    699        public RealVector operate(final RealVector v)
    700            throws IllegalArgumentException {
    701            try {
    702                return new ArrayRealVector(operate(((ArrayRealVector) v).getDataRef()), false);
    703            } catch (ClassCastException cce) {
    704                final int nRows = getRowDimension();
    705                final int nCols = getColumnDimension();
    706                if (v.getDimension() != nCols) {
    707                    throw MathRuntimeException.createIllegalArgumentException(
    708                            LocalizedFormats.VECTOR_LENGTH_MISMATCH,
    709                            v.getDimension(), nCols);
    710                }
    711
    712                final double[] out = new double[nRows];
    713                for (int row = 0; row < nRows; ++row) {
    714                    double sum = 0;
    715                    for (int i = 0; i < nCols; ++i) {
    716                        sum += getEntry(row, i) * v.getEntry(i);
    717                    }
    718                    out[row] = sum;
    719                }
    720
    721                return new ArrayRealVector(out, false);
    722            }
    723        }
    724
    725        /** {@inheritDoc} */
    726        public double[] preMultiply(final double[] v)
    727            throws IllegalArgumentException {
    728
    729            final int nRows = getRowDimension();
    730            final int nCols = getColumnDimension();
    731            if (v.length != nRows) {
    732                throw MathRuntimeException.createIllegalArgumentException(
    733                        LocalizedFormats.VECTOR_LENGTH_MISMATCH,
    734                        v.length, nRows);
    735            }
    736
    737            final double[] out = new double[nCols];
    738            for (int col = 0; col < nCols; ++col) {
    739                double sum = 0;
    740                for (int i = 0; i < nRows; ++i) {
    741                    sum += getEntry(i, col) * v[i];
    742                }
    743                out[col] = sum;
    744            }
    745
    746            return out;
    747
    748        }
    749
    750        /** {@inheritDoc} */
    751        public RealVector preMultiply(final RealVector v)
    752            throws IllegalArgumentException {
    753            try {
    754                return new ArrayRealVector(preMultiply(((ArrayRealVector) v).getDataRef()), false);
    755            } catch (ClassCastException cce) {
    756
    757                final int nRows = getRowDimension();
    758                final int nCols = getColumnDimension();
    759                if (v.getDimension() != nRows) {
    760                    throw MathRuntimeException.createIllegalArgumentException(
    761                            LocalizedFormats.VECTOR_LENGTH_MISMATCH,
    762                            v.getDimension(), nRows);
    763                }
    764
    765                final double[] out = new double[nCols];
    766                for (int col = 0; col < nCols; ++col) {
    767                    double sum = 0;
    768                    for (int i = 0; i < nRows; ++i) {
    769                        sum += getEntry(i, col) * v.getEntry(i);
    770                    }
    771                    out[col] = sum;
    772                }
    773
    774                return new ArrayRealVector(out);
    775
    776            }
    777        }
    778
    779        /** {@inheritDoc} */
    780        public double walkInRowOrder(final RealMatrixChangingVisitor visitor)
    781            throws MatrixVisitorException {
    782            final int rows    = getRowDimension();
    783            final int columns = getColumnDimension();
    784            visitor.start(rows, columns, 0, rows - 1, 0, columns - 1);
    785            for (int row = 0; row < rows; ++row) {
    786                for (int column = 0; column < columns; ++column) {
    787                    final double oldValue = getEntry(row, column);
    788                    final double newValue = visitor.visit(row, column, oldValue);
    789                    setEntry(row, column, newValue);
    790                }
    791            }
    792            lu = null;
    793            return visitor.end();
    794        }
    795
    796        /** {@inheritDoc} */
    797        public double walkInRowOrder(final RealMatrixPreservingVisitor visitor)
    798            throws MatrixVisitorException {
    799            final int rows    = getRowDimension();
    800            final int columns = getColumnDimension();
    801            visitor.start(rows, columns, 0, rows - 1, 0, columns - 1);
    802            for (int row = 0; row < rows; ++row) {
    803                for (int column = 0; column < columns; ++column) {
    804                    visitor.visit(row, column, getEntry(row, column));
    805                }
    806            }
    807            return visitor.end();
    808        }
    809
    810        /** {@inheritDoc} */
    811        public double walkInRowOrder(final RealMatrixChangingVisitor visitor,
    812                                     final int startRow, final int endRow,
    813                                     final int startColumn, final int endColumn)
    814            throws MatrixIndexException, MatrixVisitorException {
    815            MatrixUtils.checkSubMatrixIndex(this, startRow, endRow, startColumn, endColumn);
    816            visitor.start(getRowDimension(), getColumnDimension(),
    817                          startRow, endRow, startColumn, endColumn);
    818            for (int row = startRow; row <= endRow; ++row) {
    819                for (int column = startColumn; column <= endColumn; ++column) {
    820                    final double oldValue = getEntry(row, column);
    821                    final double newValue = visitor.visit(row, column, oldValue);
    822                    setEntry(row, column, newValue);
    823                }
    824            }
    825            lu = null;
    826            return visitor.end();
    827        }
    828
    829        /** {@inheritDoc} */
    830        public double walkInRowOrder(final RealMatrixPreservingVisitor visitor,
    831                                     final int startRow, final int endRow,
    832                                     final int startColumn, final int endColumn)
    833            throws MatrixIndexException, MatrixVisitorException {
    834            MatrixUtils.checkSubMatrixIndex(this, startRow, endRow, startColumn, endColumn);
    835            visitor.start(getRowDimension(), getColumnDimension(),
    836                          startRow, endRow, startColumn, endColumn);
    837            for (int row = startRow; row <= endRow; ++row) {
    838                for (int column = startColumn; column <= endColumn; ++column) {
    839                    visitor.visit(row, column, getEntry(row, column));
    840                }
    841            }
    842            return visitor.end();
    843        }
    844
    845        /** {@inheritDoc} */
    846        public double walkInColumnOrder(final RealMatrixChangingVisitor visitor)
    847            throws MatrixVisitorException {
    848            final int rows    = getRowDimension();
    849            final int columns = getColumnDimension();
    850            visitor.start(rows, columns, 0, rows - 1, 0, columns - 1);
    851            for (int column = 0; column < columns; ++column) {
    852                for (int row = 0; row < rows; ++row) {
    853                    final double oldValue = getEntry(row, column);
    854                    final double newValue = visitor.visit(row, column, oldValue);
    855                    setEntry(row, column, newValue);
    856                }
    857            }
    858            lu = null;
    859            return visitor.end();
    860        }
    861
    862        /** {@inheritDoc} */
    863        public double walkInColumnOrder(final RealMatrixPreservingVisitor visitor)
    864            throws MatrixVisitorException {
    865            final int rows    = getRowDimension();
    866            final int columns = getColumnDimension();
    867            visitor.start(rows, columns, 0, rows - 1, 0, columns - 1);
    868            for (int column = 0; column < columns; ++column) {
    869                for (int row = 0; row < rows; ++row) {
    870                    visitor.visit(row, column, getEntry(row, column));
    871                }
    872            }
    873            return visitor.end();
    874        }
    875
    876        /** {@inheritDoc} */
    877        public double walkInColumnOrder(final RealMatrixChangingVisitor visitor,
    878                                        final int startRow, final int endRow,
    879                                        final int startColumn, final int endColumn)
    880        throws MatrixIndexException, MatrixVisitorException {
    881            MatrixUtils.checkSubMatrixIndex(this, startRow, endRow, startColumn, endColumn);
    882            visitor.start(getRowDimension(), getColumnDimension(),
    883                          startRow, endRow, startColumn, endColumn);
    884            for (int column = startColumn; column <= endColumn; ++column) {
    885                for (int row = startRow; row <= endRow; ++row) {
    886                    final double oldValue = getEntry(row, column);
    887                    final double newValue = visitor.visit(row, column, oldValue);
    888                    setEntry(row, column, newValue);
    889                }
    890            }
    891            lu = null;
    892            return visitor.end();
    893        }
    894
    895        /** {@inheritDoc} */
    896        public double walkInColumnOrder(final RealMatrixPreservingVisitor visitor,
    897                                        final int startRow, final int endRow,
    898                                        final int startColumn, final int endColumn)
    899        throws MatrixIndexException, MatrixVisitorException {
    900            MatrixUtils.checkSubMatrixIndex(this, startRow, endRow, startColumn, endColumn);
    901            visitor.start(getRowDimension(), getColumnDimension(),
    902                          startRow, endRow, startColumn, endColumn);
    903            for (int column = startColumn; column <= endColumn; ++column) {
    904                for (int row = startRow; row <= endRow; ++row) {
    905                    visitor.visit(row, column, getEntry(row, column));
    906                }
    907            }
    908            return visitor.end();
    909        }
    910
    911        /** {@inheritDoc} */
    912        public double walkInOptimizedOrder(final RealMatrixChangingVisitor visitor)
    913            throws MatrixVisitorException {
    914            return walkInRowOrder(visitor);
    915        }
    916
    917        /** {@inheritDoc} */
    918        public double walkInOptimizedOrder(final RealMatrixPreservingVisitor visitor)
    919            throws MatrixVisitorException {
    920            return walkInRowOrder(visitor);
    921        }
    922
    923        /** {@inheritDoc} */
    924        public double walkInOptimizedOrder(final RealMatrixChangingVisitor visitor,
    925                                           final int startRow, final int endRow,
    926                                           final int startColumn, final int endColumn)
    927            throws MatrixIndexException, MatrixVisitorException {
    928            return walkInRowOrder(visitor, startRow, endRow, startColumn, endColumn);
    929        }
    930
    931        /** {@inheritDoc} */
    932        public double walkInOptimizedOrder(final RealMatrixPreservingVisitor visitor,
    933                                           final int startRow, final int endRow,
    934                                           final int startColumn, final int endColumn)
    935            throws MatrixIndexException, MatrixVisitorException {
    936            return walkInRowOrder(visitor, startRow, endRow, startColumn, endColumn);
    937        }
    938
    939        /** {@inheritDoc} */
    940        @Deprecated
    941        public double[] solve(final double[] b)
    942            throws IllegalArgumentException, InvalidMatrixException {
    943            if (lu == null) {
    944                lu = new LUDecompositionImpl(this, MathUtils.SAFE_MIN).getSolver();
    945            }
    946            return lu.solve(b);
    947        }
    948
    949        /** {@inheritDoc} */
    950        @Deprecated
    951        public RealMatrix solve(final RealMatrix b)
    952            throws IllegalArgumentException, InvalidMatrixException  {
    953            if (lu == null) {
    954                lu = new LUDecompositionImpl(this, MathUtils.SAFE_MIN).getSolver();
    955            }
    956            return lu.solve(b);
    957        }
    958
    959        /**
    960         * Computes a new
    961         * <a href="http://www.math.gatech.edu/~bourbaki/math2601/Web-notes/2num.pdf">
    962         * LU decomposition</a> for this matrix, storing the result for use by other methods.
    963         * <p>
    964         * <strong>Implementation Note</strong>:<br>
    965         * Uses <a href="http://www.damtp.cam.ac.uk/user/fdl/people/sd/lectures/nummeth98/linear.htm">
    966         * Crout's algorithm</a>, with partial pivoting.</p>
    967         * <p>
    968         * <strong>Usage Note</strong>:<br>
    969         * This method should rarely be invoked directly. Its only use is
    970         * to force recomputation of the LU decomposition when changes have been
    971         * made to the underlying data using direct array references. Changes
    972         * made using setXxx methods will trigger recomputation when needed
    973         * automatically.</p>
    974         *
    975         * @throws InvalidMatrixException if the matrix is non-square or singular.
    976         * @deprecated as of release 2.0, replaced by {@link LUDecomposition}
    977         */
    978        @Deprecated
    979        public void luDecompose()
    980            throws InvalidMatrixException {
    981            if (lu == null) {
    982                lu = new LUDecompositionImpl(this, MathUtils.SAFE_MIN).getSolver();
    983            }
    984        }
    985
    986        /**
    987         * Get a string representation for this matrix.
    988         * @return a string representation for this matrix
    989         */
    990        @Override
    991        public String toString() {
    992            final int nRows = getRowDimension();
    993            final int nCols = getColumnDimension();
    994            final StringBuilder res = new StringBuilder();
    995            String fullClassName = getClass().getName();
    996            String shortClassName = fullClassName.substring(fullClassName.lastIndexOf('.') + 1);
    997            res.append(shortClassName).append("{");
    998
    999            for (int i = 0; i < nRows; ++i) {
    1000                if (i > 0) {
    1001                    res.append(",");
    1002                }
    1003                res.append("{");
    1004                for (int j = 0; j < nCols; ++j) {
    1005                    if (j > 0) {
    1006                        res.append(",");
    1007                    }
    1008                    res.append(getEntry(i, j));
    1009                }
    1010                res.append("}");
    1011            }
    1012
    1013            res.append("}");
    1014            return res.toString();
    1015
    1016        }
    1017
    1018        /**
    1019         * Returns true iff <code>object</code> is a
    1020         * <code>RealMatrix</code> instance with the same dimensions as this
    1021         * and all corresponding matrix entries are equal.
    1022         *
    1023         * @param object the object to test equality against.
    1024         * @return true if object equals this
    1025         */
    1026        @Override
    1027        public boolean equals(final Object object) {
    1028            if (object == this ) {
    1029                return true;
    1030            }
    1031            if (object instanceof RealMatrix == false) {
    1032                return false;
    1033            }
    1034            RealMatrix m = (RealMatrix) object;
    1035            final int nRows = getRowDimension();
    1036            final int nCols = getColumnDimension();
    1037            if (m.getColumnDimension() != nCols || m.getRowDimension() != nRows) {
    1038                return false;
    1039            }
    1040            for (int row = 0; row < nRows; ++row) {
    1041                for (int col = 0; col < nCols; ++col) {
    1042                    if (getEntry(row, col) != m.getEntry(row, col)) {
    1043                        return false;
    1044                    }
    1045                }
    1046            }
    1047            return true;
    1048        }
    1049
    1050        /**
    1051         * Computes a hashcode for the matrix.
    1052         *
    1053         * @return hashcode for matrix
    1054         */
    1055        @Override
    1056        public int hashCode() {
    1057            int ret = 7;
    1058            final int nRows = getRowDimension();
    1059            final int nCols = getColumnDimension();
    1060            ret = ret * 31 + nRows;
    1061            ret = ret * 31 + nCols;
    1062            for (int row = 0; row < nRows; ++row) {
    1063                for (int col = 0; col < nCols; ++col) {
    1064                   ret = ret * 31 + (11 * (row+1) + 17 * (col+1)) *
    1065                       MathUtils.hash(getEntry(row, col));
    1066               }
    1067            }
    1068            return ret;
    1069        }
    1070
    1071    }