Home | History | Annotate | Download | only in linear
      1 /*
      2  * Licensed to the Apache Software Foundation (ASF) under one or more
      3  * contributor license agreements.  See the NOTICE file distributed with
      4  * this work for additional information regarding copyright ownership.
      5  * The ASF licenses this file to You under the Apache License, Version 2.0
      6  * (the "License"); you may not use this file except in compliance with
      7  * the License.  You may obtain a copy of the License at
      8  *
      9  *      http://www.apache.org/licenses/LICENSE-2.0
     10  *
     11  * Unless required by applicable law or agreed to in writing, software
     12  * distributed under the License is distributed on an "AS IS" BASIS,
     13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     14  * See the License for the specific language governing permissions and
     15  * limitations under the License.
     16  */
     17 
     18 package org.apache.commons.math.linear;
     19 
     20 import org.apache.commons.math.MathRuntimeException;
     21 import org.apache.commons.math.linear.MatrixVisitorException;
     22 import org.apache.commons.math.exception.util.LocalizedFormats;
     23 import org.apache.commons.math.util.MathUtils;
     24 import org.apache.commons.math.util.FastMath;
     25 
     26 /**
     27  * Basic implementation of RealMatrix methods regardless of the underlying storage.
     28  * <p>All the methods implemented here use {@link #getEntry(int, int)} to access
     29  * matrix elements. Derived class can provide faster implementations. </p>
     30  *
     31  * @version $Revision: 1073158 $ $Date: 2011-02-21 22:46:52 +0100 (lun. 21 fvr. 2011) $
     32  * @since 2.0
     33  */
     34 public abstract class AbstractRealMatrix implements RealMatrix {
     35 
     36 
     37     /** Cached LU solver.
     38      * @deprecated as of release 2.0, since all methods using this are deprecated
     39      */
     40     @Deprecated
     41     private DecompositionSolver lu;
     42 
     43     /**
     44      * Creates a matrix with no data
     45      */
     46     protected AbstractRealMatrix() {
     47         lu = null;
     48     }
     49 
     50     /**
     51      * Create a new RealMatrix with the supplied row and column dimensions.
     52      *
     53      * @param rowDimension  the number of rows in the new matrix
     54      * @param columnDimension  the number of columns in the new matrix
     55      * @throws IllegalArgumentException if row or column dimension is not positive
     56      */
     57     protected AbstractRealMatrix(final int rowDimension, final int columnDimension)
     58         throws IllegalArgumentException {
     59         if (rowDimension < 1 ) {
     60             throw MathRuntimeException.createIllegalArgumentException(
     61                     LocalizedFormats.INSUFFICIENT_DIMENSION, rowDimension, 1);
     62         }
     63         if (columnDimension <= 0) {
     64             throw MathRuntimeException.createIllegalArgumentException(
     65                     LocalizedFormats.INSUFFICIENT_DIMENSION, columnDimension, 1);
     66         }
     67         lu = null;
     68     }
     69 
     70     /** {@inheritDoc} */
     71     public abstract RealMatrix createMatrix(final int rowDimension, final int columnDimension)
     72         throws IllegalArgumentException;
     73 
     74     /** {@inheritDoc} */
     75     public abstract RealMatrix copy();
     76 
     77     /** {@inheritDoc} */
     78     public RealMatrix add(RealMatrix m) throws IllegalArgumentException {
     79 
     80         // safety check
     81         MatrixUtils.checkAdditionCompatible(this, m);
     82 
     83         final int rowCount    = getRowDimension();
     84         final int columnCount = getColumnDimension();
     85         final RealMatrix out = createMatrix(rowCount, columnCount);
     86         for (int row = 0; row < rowCount; ++row) {
     87             for (int col = 0; col < columnCount; ++col) {
     88                 out.setEntry(row, col, getEntry(row, col) + m.getEntry(row, col));
     89             }
     90         }
     91 
     92         return out;
     93 
     94     }
     95 
     96     /** {@inheritDoc} */
     97     public RealMatrix subtract(final RealMatrix m) throws IllegalArgumentException {
     98 
     99         // 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 }
   1072