    001    /*
    002     * Licensed to the Apache Software Foundation (ASF) under one or more
    003     * contributor license agreements.  See the NOTICE file distributed with
    004     * this work for additional information regarding copyright ownership.
    005     * The ASF licenses this file to You under the Apache License, Version 2.0
    006     * (the "License"); you may not use this file except in compliance with
    007     * the License.  You may obtain a copy of the License at
    008     *
    009     *      http://www.apache.org/licenses/LICENSE-2.0
    010     *
    011     * Unless required by applicable law or agreed to in writing, software
    012     * distributed under the License is distributed on an "AS IS" BASIS,
    013     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    014     * See the License for the specific language governing permissions and
    015     * limitations under the License.
    016     */
    017
    018    package org.apache.commons.math3.linear;
    019
    020    import java.util.ArrayList;
    021    import java.util.Locale;
    022
    023    import org.apache.commons.math3.exception.NoDataException;
    024    import org.apache.commons.math3.exception.NotPositiveException;
    025    import org.apache.commons.math3.exception.NotStrictlyPositiveException;
    026    import org.apache.commons.math3.exception.DimensionMismatchException;
    027    import org.apache.commons.math3.exception.NullArgumentException;
    028    import org.apache.commons.math3.exception.NumberIsTooSmallException;
    029    import org.apache.commons.math3.exception.OutOfRangeException;
    030    import org.apache.commons.math3.exception.util.LocalizedFormats;
    031    import org.apache.commons.math3.util.MathUtils;
    032    import org.apache.commons.math3.util.FastMath;
    033
    034    /**
    035     * Basic implementation of RealMatrix methods regardless of the underlying storage.
    036     * <p>All the methods implemented here use {@link #getEntry(int, int)} to access
    037     * matrix elements. Derived class can provide faster implementations.</p>
    038     *
    039     * @version $Id: AbstractRealMatrix.java 1416643 2012-12-03 19:37:14Z tn $
    040     * @since 2.0
    041     */
    042    public abstract class AbstractRealMatrix
    043        extends RealLinearOperator
    044        implements RealMatrix {
    045
    046        /** Default format. */
    047        private static final RealMatrixFormat DEFAULT_FORMAT = RealMatrixFormat.getInstance(Locale.US);
    048        static {
    049            // set the minimum fraction digits to 1 to keep compatibility
    050            DEFAULT_FORMAT.getFormat().setMinimumFractionDigits(1);
    051        }
    052
    053        /**
    054         * Creates a matrix with no data
    055         */
    056        protected AbstractRealMatrix() {}
    057
    058        /**
    059         * Create a new RealMatrix with the supplied row and column dimensions.
    060         *
    061         * @param rowDimension  the number of rows in the new matrix
    062         * @param columnDimension  the number of columns in the new matrix
    063         * @throws NotStrictlyPositiveException if row or column dimension is not positive
    064         */
    065        protected AbstractRealMatrix(final int rowDimension,
    066            final int columnDimension)
    067            throws NotStrictlyPositiveException {
    068            if (rowDimension < 1) {
    069                throw new NotStrictlyPositiveException(rowDimension);
    070            }
    071            if (columnDimension < 1) {
    072                throw new NotStrictlyPositiveException(columnDimension);
    073            }
    074        }
    075
    076        /** {@inheritDoc} */
    077        public RealMatrix add(RealMatrix m)
    078            throws MatrixDimensionMismatchException {
    079            MatrixUtils.checkAdditionCompatible(this, m);
    080
    081            final int rowCount    = getRowDimension();
    082            final int columnCount = getColumnDimension();
    083            final RealMatrix out = createMatrix(rowCount, columnCount);
    084            for (int row = 0; row < rowCount; ++row) {
    085                for (int col = 0; col < columnCount; ++col) {
    086                    out.setEntry(row, col, getEntry(row, col) + m.getEntry(row, col));
    087                }
    088            }
    089
    090            return out;
    091        }
    092
    093        /** {@inheritDoc} */
    094        public RealMatrix subtract(final RealMatrix m)
    095            throws MatrixDimensionMismatchException {
    096            MatrixUtils.checkSubtractionCompatible(this, m);
    097
    098            final int rowCount    = getRowDimension();
    099            final int columnCount = getColumnDimension();
    100            final RealMatrix out = createMatrix(rowCount, columnCount);
    101            for (int row = 0; row < rowCount; ++row) {
    102                for (int col = 0; col < columnCount; ++col) {
    103                    out.setEntry(row, col, getEntry(row, col) - m.getEntry(row, col));
    104                }
    105            }
    106
    107            return out;
    108        }
    109
    110        /** {@inheritDoc} */
    111        public RealMatrix scalarAdd(final double d) {
    112            final int rowCount    = getRowDimension();
    113            final int columnCount = getColumnDimension();
    114            final RealMatrix out = createMatrix(rowCount, columnCount);
    115            for (int row = 0; row < rowCount; ++row) {
    116                for (int col = 0; col < columnCount; ++col) {
    117                    out.setEntry(row, col, getEntry(row, col) + d);
    118                }
    119            }
    120
    121            return out;
    122        }
    123
    124        /** {@inheritDoc} */
    125        public RealMatrix scalarMultiply(final double d) {
    126            final int rowCount    = getRowDimension();
    127            final int columnCount = getColumnDimension();
    128            final RealMatrix out = createMatrix(rowCount, columnCount);
    129            for (int row = 0; row < rowCount; ++row) {
    130                for (int col = 0; col < columnCount; ++col) {
    131                    out.setEntry(row, col, getEntry(row, col) * d);
    132                }
    133            }
    134
    135            return out;
    136        }
    137
    138        /** {@inheritDoc} */
    139        public RealMatrix multiply(final RealMatrix m)
    140            throws DimensionMismatchException {
    141            MatrixUtils.checkMultiplicationCompatible(this, m);
    142
    143            final int nRows = getRowDimension();
    144            final int nCols = m.getColumnDimension();
    145            final int nSum  = getColumnDimension();
    146            final RealMatrix out = createMatrix(nRows, nCols);
    147            for (int row = 0; row < nRows; ++row) {
    148                for (int col = 0; col < nCols; ++col) {
    149                    double sum = 0;
    150                    for (int i = 0; i < nSum; ++i) {
    151                        sum += getEntry(row, i) * m.getEntry(i, col);
    152                    }
    153                    out.setEntry(row, col, sum);
    154                }
    155            }
    156
    157            return out;
    158        }
    159
    160        /** {@inheritDoc} */
    161        public RealMatrix preMultiply(final RealMatrix m)
    162            throws DimensionMismatchException {
    163            return m.multiply(this);
    164        }
    165
    166        /** {@inheritDoc} */
    167        public RealMatrix power(final int p)
    168            throws NotPositiveException, NonSquareMatrixException {
    169            if (p < 0) {
    170                throw new NotPositiveException(LocalizedFormats.NOT_POSITIVE_EXPONENT, p);
    171            }
    172
    173            if (!isSquare()) {
    174                throw new NonSquareMatrixException(getRowDimension(), getColumnDimension());
    175            }
    176
    177            if (p == 0) {
    178                return MatrixUtils.createRealIdentityMatrix(this.getRowDimension());
    179            }
    180
    181            if (p == 1) {
    182                return this.copy();
    183            }
    184
    185            final int power = p - 1;
    186
    187            /*
    188             * Only log_2(p) operations is used by doing as follows:
    189             * 5^214 = 5^128 * 5^64 * 5^16 * 5^4 * 5^2
    190             *
    191             * In general, the same approach is used for A^p.
    192             */
    193
    194            final char[] binaryRepresentation = Integer.toBinaryString(power).toCharArray();
    195            final ArrayList<Integer> nonZeroPositions = new ArrayList<Integer>();
    196            int maxI = -1;
    197
    198            for (int i = 0; i < binaryRepresentation.length; ++i) {
    199                if (binaryRepresentation[i] == '1') {
    200                    final int pos = binaryRepresentation.length - i - 1;
    201                    nonZeroPositions.add(pos);
    202
    203                    // The positions are taken in turn, so maxI is only changed once
    204                    if (maxI == -1) {
    205                        maxI = pos;
    206                    }
    207                }
    208            }
    209
    210            RealMatrix[] results = new RealMatrix[maxI + 1];
    211            results[0] = this.copy();
    212
    213            for (int i = 1; i <= maxI; ++i) {
    214                results[i] = results[i-1].multiply(results[i-1]);
    215            }
    216
    217            RealMatrix result = this.copy();
    218
    219            for (Integer i : nonZeroPositions) {
    220                result = result.multiply(results[i]);
    221            }
    222
    223            return result;
    224        }
    225
    226        /** {@inheritDoc} */
    227        public double[][] getData() {
    228            final double[][] data = new double[getRowDimension()][getColumnDimension()];
    229
    230            for (int i = 0; i < data.length; ++i) {
    231                final double[] dataI = data[i];
    232                for (int j = 0; j < dataI.length; ++j) {
    233                    dataI[j] = getEntry(i, j);
    234                }
    235            }
    236
    237            return data;
    238        }
    239
    240        /** {@inheritDoc} */
    241        public double getNorm() {
    242            return walkInColumnOrder(new RealMatrixPreservingVisitor() {
    243
    244                /** Last row index. */
    245                private double endRow;
    246
    247                /** Sum of absolute values on one column. */
    248                private double columnSum;
    249
    250                /** Maximal sum across all columns. */
    251                private double maxColSum;
    252
    253                /** {@inheritDoc} */
    254                public void start(final int rows, final int columns,
    255                                  final int startRow, final int endRow,
    256                                  final int startColumn, final int endColumn) {
    257                    this.endRow = endRow;
    258                    columnSum   = 0;
    259                    maxColSum   = 0;
    260                }
    261
    262                /** {@inheritDoc} */
    263                public void visit(final int row, final int column, final double value) {
    264                    columnSum += FastMath.abs(value);
    265                    if (row == endRow) {
    266                        maxColSum = FastMath.max(maxColSum, columnSum);
    267                        columnSum = 0;
    268                    }
    269                }
    270
    271                /** {@inheritDoc} */
    272                public double end() {
    273                    return maxColSum;
    274                }
    275            });
    276        }
    277
    278        /** {@inheritDoc} */
    279        public double getFrobeniusNorm() {
    280            return walkInOptimizedOrder(new RealMatrixPreservingVisitor() {
    281
    282                /** Sum of squared entries. */
    283                private double sum;
    284
    285                /** {@inheritDoc} */
    286                public void start(final int rows, final int columns,
    287                                  final int startRow, final int endRow,
    288                                  final int startColumn, final int endColumn) {
    289                    sum = 0;
    290                }
    291
    292                /** {@inheritDoc} */
    293                public void visit(final int row, final int column, final double value) {
    294                    sum += value * value;
    295                }
    296
    297                /** {@inheritDoc} */
    298                public double end() {
    299                    return FastMath.sqrt(sum);
    300                }
    301            });
    302        }
    303
    304        /** {@inheritDoc} */
    305        public RealMatrix getSubMatrix(final int startRow, final int endRow,
    306                                       final int startColumn, final int endColumn)
    307            throws OutOfRangeException, NumberIsTooSmallException {
    308            MatrixUtils.checkSubMatrixIndex(this, startRow, endRow, startColumn, endColumn);
    309
    310            final RealMatrix subMatrix =
    311                createMatrix(endRow - startRow + 1, endColumn - startColumn + 1);
    312            for (int i = startRow; i <= endRow; ++i) {
    313                for (int j = startColumn; j <= endColumn; ++j) {
    314                    subMatrix.setEntry(i - startRow, j - startColumn, getEntry(i, j));
    315                }
    316            }
    317
    318            return subMatrix;
    319        }
    320
    321        /** {@inheritDoc} */
    322        public RealMatrix getSubMatrix(final int[] selectedRows,
    323                                       final int[] selectedColumns)
    324            throws NullArgumentException, NoDataException, OutOfRangeException {
    325            MatrixUtils.checkSubMatrixIndex(this, selectedRows, selectedColumns);
    326
    327            final RealMatrix subMatrix =
    328                createMatrix(selectedRows.length, selectedColumns.length);
    329            subMatrix.walkInOptimizedOrder(new DefaultRealMatrixChangingVisitor() {
    330
    331                /** {@inheritDoc} */
    332                @Override
    333                public double visit(final int row, final int column, final double value) {
    334                    return getEntry(selectedRows[row], selectedColumns[column]);
    335                }
    336
    337            });
    338
    339            return subMatrix;
    340        }
    341
    342        /** {@inheritDoc} */
    343        public void copySubMatrix(final int startRow, final int endRow,
    344                                  final int startColumn, final int endColumn,
    345                                  final double[][] destination)
    346            throws OutOfRangeException, NumberIsTooSmallException,
    347            MatrixDimensionMismatchException {
    348            MatrixUtils.checkSubMatrixIndex(this, startRow, endRow, startColumn, endColumn);
    349            final int rowsCount    = endRow + 1 - startRow;
    350            final int columnsCount = endColumn + 1 - startColumn;
    351            if ((destination.length < rowsCount) || (destination[0].length < columnsCount)) {
    352                throw new MatrixDimensionMismatchException(destination.length, destination[0].length,
    353                                                           rowsCount, columnsCount);
    354            }
    355
    356            walkInOptimizedOrder(new DefaultRealMatrixPreservingVisitor() {
    357
    358                /** Initial row index. */
    359                private int startRow;
    360
    361                /** Initial column index. */
    362                private int startColumn;
    363
    364                /** {@inheritDoc} */
    365                @Override
    366                public void start(final int rows, final int columns,
    367                                  final int startRow, final int endRow,
    368                                  final int startColumn, final int endColumn) {
    369                    this.startRow    = startRow;
    370                    this.startColumn = startColumn;
    371                }
    372
    373                /** {@inheritDoc} */
    374                @Override
    375                public void visit(final int row, final int column, final double value) {
    376                    destination[row - startRow][column - startColumn] = value;
    377                }
    378
    379            }, startRow, endRow, startColumn, endColumn);
    380        }
    381
    382        /** {@inheritDoc} */
    383        public void copySubMatrix(int[] selectedRows, int[] selectedColumns,
    384                                  double[][] destination)
    385            throws OutOfRangeException, NullArgumentException, NoDataException,
    386            MatrixDimensionMismatchException {
    387            MatrixUtils.checkSubMatrixIndex(this, selectedRows, selectedColumns);
    388            if ((destination.length < selectedRows.length) ||
    389                (destination[0].length < selectedColumns.length)) {
    390                throw new MatrixDimensionMismatchException(destination.length, destination[0].length,
    391                                                           selectedRows.length, selectedColumns.length);
    392            }
    393
    394            for (int i = 0; i < selectedRows.length; i++) {
    395                final double[] destinationI = destination[i];
    396                for (int j = 0; j < selectedColumns.length; j++) {
    397                    destinationI[j] = getEntry(selectedRows[i], selectedColumns[j]);
    398                }
    399            }
    400        }
    401
    402        /** {@inheritDoc} */
    403        public void setSubMatrix(final double[][] subMatrix, final int row, final int column)
    404            throws NoDataException, OutOfRangeException,
    405            DimensionMismatchException, NullArgumentException {
    406            MathUtils.checkNotNull(subMatrix);
    407            final int nRows = subMatrix.length;
    408            if (nRows == 0) {
    409                throw new NoDataException(LocalizedFormats.AT_LEAST_ONE_ROW);
    410            }
    411
    412            final int nCols = subMatrix[0].length;
    413            if (nCols == 0) {
    414                throw new NoDataException(LocalizedFormats.AT_LEAST_ONE_COLUMN);
    415            }
    416
    417            for (int r = 1; r < nRows; ++r) {
    418                if (subMatrix[r].length != nCols) {
    419                    throw new DimensionMismatchException(nCols, subMatrix[r].length);
    420                }
    421            }
    422
    423            MatrixUtils.checkRowIndex(this, row);
    424            MatrixUtils.checkColumnIndex(this, column);
    425            MatrixUtils.checkRowIndex(this, nRows + row - 1);
    426            MatrixUtils.checkColumnIndex(this, nCols + column - 1);
    427
    428            for (int i = 0; i < nRows; ++i) {
    429                for (int j = 0; j < nCols; ++j) {
    430                    setEntry(row + i, column + j, subMatrix[i][j]);
    431                }
    432            }
    433        }
    434
    435        /** {@inheritDoc} */
    436        public RealMatrix getRowMatrix(final int row) throws OutOfRangeException {
    437            MatrixUtils.checkRowIndex(this, row);
    438            final int nCols = getColumnDimension();
    439            final RealMatrix out = createMatrix(1, nCols);
    440            for (int i = 0; i < nCols; ++i) {
    441                out.setEntry(0, i, getEntry(row, i));
    442            }
    443
    444            return out;
    445        }
    446
    447        /** {@inheritDoc} */
    448        public void setRowMatrix(final int row, final RealMatrix matrix)
    449            throws OutOfRangeException, MatrixDimensionMismatchException {
    450            MatrixUtils.checkRowIndex(this, row);
    451            final int nCols = getColumnDimension();
    452            if ((matrix.getRowDimension() != 1) ||
    453                (matrix.getColumnDimension() != nCols)) {
    454                throw new MatrixDimensionMismatchException(matrix.getRowDimension(),
    455                                                           matrix.getColumnDimension(),
    456                                                           1, nCols);
    457            }
    458            for (int i = 0; i < nCols; ++i) {
    459                setEntry(row, i, matrix.getEntry(0, i));
    460            }
    461        }
    462
    463        /** {@inheritDoc} */
    464        public RealMatrix getColumnMatrix(final int column)
    465            throws OutOfRangeException {
    466            MatrixUtils.checkColumnIndex(this, column);
    467            final int nRows = getRowDimension();
    468            final RealMatrix out = createMatrix(nRows, 1);
    469            for (int i = 0; i < nRows; ++i) {
    470                out.setEntry(i, 0, getEntry(i, column));
    471            }
    472
    473            return out;
    474        }
    475
    476        /** {@inheritDoc} */
    477        public void setColumnMatrix(final int column, final RealMatrix matrix)
    478            throws OutOfRangeException, MatrixDimensionMismatchException {
    479            MatrixUtils.checkColumnIndex(this, column);
    480            final int nRows = getRowDimension();
    481            if ((matrix.getRowDimension() != nRows) ||
    482                (matrix.getColumnDimension() != 1)) {
    483                throw new MatrixDimensionMismatchException(matrix.getRowDimension(),
    484                                                           matrix.getColumnDimension(),
    485                                                           nRows, 1);
    486            }
    487            for (int i = 0; i < nRows; ++i) {
    488                setEntry(i, column, matrix.getEntry(i, 0));
    489            }
    490        }
    491
    492        /** {@inheritDoc} */
    493        public RealVector getRowVector(final int row)
    494            throws OutOfRangeException {
    495            return new ArrayRealVector(getRow(row), false);
    496        }
    497
    498        /** {@inheritDoc} */
    499        public void setRowVector(final int row, final RealVector vector)
    500            throws OutOfRangeException, MatrixDimensionMismatchException {
    501            MatrixUtils.checkRowIndex(this, row);
    502            final int nCols = getColumnDimension();
    503            if (vector.getDimension() != nCols) {
    504                throw new MatrixDimensionMismatchException(1, vector.getDimension(),
    505                                                           1, nCols);
    506            }
    507            for (int i = 0; i < nCols; ++i) {
    508                setEntry(row, i, vector.getEntry(i));
    509            }
    510        }
    511
    512        /** {@inheritDoc} */
    513        public RealVector getColumnVector(final int column)
    514            throws OutOfRangeException {
    515            return new ArrayRealVector(getColumn(column), false);
    516        }
    517
    518        /** {@inheritDoc} */
    519        public void setColumnVector(final int column, final RealVector vector)
    520            throws OutOfRangeException, MatrixDimensionMismatchException {
    521            MatrixUtils.checkColumnIndex(this, column);
    522            final int nRows = getRowDimension();
    523            if (vector.getDimension() != nRows) {
    524                throw new MatrixDimensionMismatchException(vector.getDimension(), 1,
    525                                                           nRows, 1);
    526            }
    527            for (int i = 0; i < nRows; ++i) {
    528                setEntry(i, column, vector.getEntry(i));
    529            }
    530        }
    531
    532        /** {@inheritDoc} */
    533        public double[] getRow(final int row) throws OutOfRangeException {
    534            MatrixUtils.checkRowIndex(this, row);
    535            final int nCols = getColumnDimension();
    536            final double[] out = new double[nCols];
    537            for (int i = 0; i < nCols; ++i) {
    538                out[i] = getEntry(row, i);
    539            }
    540
    541            return out;
    542        }
    543
    544        /** {@inheritDoc} */
    545        public void setRow(final int row, final double[] array)
    546            throws OutOfRangeException, MatrixDimensionMismatchException {
    547            MatrixUtils.checkRowIndex(this, row);
    548            final int nCols = getColumnDimension();
    549            if (array.length != nCols) {
    550                throw new MatrixDimensionMismatchException(1, array.length, 1, nCols);
    551            }
    552            for (int i = 0; i < nCols; ++i) {
    553                setEntry(row, i, array[i]);
    554            }
    555        }
    556
    557        /** {@inheritDoc} */
    558        public double[] getColumn(final int column) throws OutOfRangeException {
    559            MatrixUtils.checkColumnIndex(this, column);
    560            final int nRows = getRowDimension();
    561            final double[] out = new double[nRows];
    562            for (int i = 0; i < nRows; ++i) {
    563                out[i] = getEntry(i, column);
    564            }
    565
    566            return out;
    567        }
    568
    569        /** {@inheritDoc} */
    570        public void setColumn(final int column, final double[] array)
    571            throws OutOfRangeException, MatrixDimensionMismatchException {
    572            MatrixUtils.checkColumnIndex(this, column);
    573            final int nRows = getRowDimension();
    574            if (array.length != nRows) {
    575                throw new MatrixDimensionMismatchException(array.length, 1, nRows, 1);
    576            }
    577            for (int i = 0; i < nRows; ++i) {
    578                setEntry(i, column, array[i]);
    579            }
    580        }
    581
    582        /** {@inheritDoc} */
    583        public void addToEntry(int row, int column, double increment)
    584            throws OutOfRangeException {
    585            MatrixUtils.checkMatrixIndex(this, row, column);
    586            setEntry(row, column, getEntry(row, column) + increment);
    587        }
    588
    589        /** {@inheritDoc} */
    590        public void multiplyEntry(int row, int column, double factor)
    591            throws OutOfRangeException {
    592            MatrixUtils.checkMatrixIndex(this, row, column);
    593            setEntry(row, column, getEntry(row, column) * factor);
    594        }
    595
    596        /** {@inheritDoc} */
    597        public RealMatrix transpose() {
    598            final int nRows = getRowDimension();
    599            final int nCols = getColumnDimension();
    600            final RealMatrix out = createMatrix(nCols, nRows);
    601            walkInOptimizedOrder(new DefaultRealMatrixPreservingVisitor() {
    602
    603                /** {@inheritDoc} */
    604                @Override
    605                public void visit(final int row, final int column, final double value) {
    606                    out.setEntry(column, row, value);
    607                }
    608
    609            });
    610
    611            return out;
    612        }
    613
    614        /** {@inheritDoc} */
    615        public boolean isSquare() {
    616            return getColumnDimension() == getRowDimension();
    617        }
    618
    619        /**
    620         * Returns the number of rows of this matrix.
    621         *
    622         * @return the number of rows.
    623         */
    624        @Override
    625        public abstract int getRowDimension();
    626
    627        /**
    628         * Returns the number of columns of this matrix.
    629         *
    630         * @return the number of columns.
    631         */
    632        @Override
    633        public abstract int getColumnDimension();
    634
    635        /** {@inheritDoc} */
    636        public double getTrace() throws NonSquareMatrixException {
    637            final int nRows = getRowDimension();
    638            final int nCols = getColumnDimension();
    639            if (nRows != nCols) {
    640                throw new NonSquareMatrixException(nRows, nCols);
    641           }
    642            double trace = 0;
    643            for (int i = 0; i < nRows; ++i) {
    644                trace += getEntry(i, i);
    645            }
    646            return trace;
    647        }
    648
    649        /** {@inheritDoc} */
    650        public double[] operate(final double[] v)
    651            throws DimensionMismatchException {
    652            final int nRows = getRowDimension();
    653            final int nCols = getColumnDimension();
    654            if (v.length != nCols) {
    655                throw new DimensionMismatchException(v.length, nCols);
    656            }
    657
    658            final double[] out = new double[nRows];
    659            for (int row = 0; row < nRows; ++row) {
    660                double sum = 0;
    661                for (int i = 0; i < nCols; ++i) {
    662                    sum += getEntry(row, i) * v[i];
    663                }
    664                out[row] = sum;
    665            }
    666
    667            return out;
    668        }
    669
    670        /** {@inheritDoc} */
    671        @Override
    672        public RealVector operate(final RealVector v)
    673            throws DimensionMismatchException {
    674            try {
    675                return new ArrayRealVector(operate(((ArrayRealVector) v).getDataRef()), false);
    676            } catch (ClassCastException cce) {
    677                final int nRows = getRowDimension();
    678                final int nCols = getColumnDimension();
    679                if (v.getDimension() != nCols) {
    680                    throw new DimensionMismatchException(v.getDimension(), nCols);
    681                }
    682
    683                final double[] out = new double[nRows];
    684                for (int row = 0; row < nRows; ++row) {
    685                    double sum = 0;
    686                    for (int i = 0; i < nCols; ++i) {
    687                        sum += getEntry(row, i) * v.getEntry(i);
    688                    }
    689                    out[row] = sum;
    690                }
    691
    692                return new ArrayRealVector(out, false);
    693            }
    694        }
    695
    696        /** {@inheritDoc} */
    697        public double[] preMultiply(final double[] v) throws DimensionMismatchException {
    698
    699            final int nRows = getRowDimension();
    700            final int nCols = getColumnDimension();
    701            if (v.length != nRows) {
    702                throw new DimensionMismatchException(v.length, nRows);
    703            }
    704
    705            final double[] out = new double[nCols];
    706            for (int col = 0; col < nCols; ++col) {
    707                double sum = 0;
    708                for (int i = 0; i < nRows; ++i) {
    709                    sum += getEntry(i, col) * v[i];
    710                }
    711                out[col] = sum;
    712            }
    713
    714            return out;
    715        }
    716
    717        /** {@inheritDoc} */
    718        public RealVector preMultiply(final RealVector v) throws DimensionMismatchException {
    719            try {
    720                return new ArrayRealVector(preMultiply(((ArrayRealVector) v).getDataRef()), false);
    721            } catch (ClassCastException cce) {
    722
    723                final int nRows = getRowDimension();
    724                final int nCols = getColumnDimension();
    725                if (v.getDimension() != nRows) {
    726                    throw new DimensionMismatchException(v.getDimension(), nRows);
    727                }
    728
    729                final double[] out = new double[nCols];
    730                for (int col = 0; col < nCols; ++col) {
    731                    double sum = 0;
    732                    for (int i = 0; i < nRows; ++i) {
    733                        sum += getEntry(i, col) * v.getEntry(i);
    734                    }
    735                    out[col] = sum;
    736                }
    737
    738                return new ArrayRealVector(out, false);
    739            }
    740        }
    741
    742        /** {@inheritDoc} */
    743        public double walkInRowOrder(final RealMatrixChangingVisitor visitor) {
    744            final int rows    = getRowDimension();
    745            final int columns = getColumnDimension();
    746            visitor.start(rows, columns, 0, rows - 1, 0, columns - 1);
    747            for (int row = 0; row < rows; ++row) {
    748                for (int column = 0; column < columns; ++column) {
    749                    final double oldValue = getEntry(row, column);
    750                    final double newValue = visitor.visit(row, column, oldValue);
    751                    setEntry(row, column, newValue);
    752                }
    753            }
    754            return visitor.end();
    755        }
    756
    757        /** {@inheritDoc} */
    758        public double walkInRowOrder(final RealMatrixPreservingVisitor visitor) {
    759            final int rows    = getRowDimension();
    760            final int columns = getColumnDimension();
    761            visitor.start(rows, columns, 0, rows - 1, 0, columns - 1);
    762            for (int row = 0; row < rows; ++row) {
    763                for (int column = 0; column < columns; ++column) {
    764                    visitor.visit(row, column, getEntry(row, column));
    765                }
    766            }
    767            return visitor.end();
    768        }
    769
    770        /** {@inheritDoc} */
    771        public double walkInRowOrder(final RealMatrixChangingVisitor visitor,
    772                                     final int startRow, final int endRow,
    773                                     final int startColumn, final int endColumn)
    774            throws OutOfRangeException, NumberIsTooSmallException {
    775            MatrixUtils.checkSubMatrixIndex(this, startRow, endRow, startColumn, endColumn);
    776            visitor.start(getRowDimension(), getColumnDimension(),
    777                          startRow, endRow, startColumn, endColumn);
    778            for (int row = startRow; row <= endRow; ++row) {
    779                for (int column = startColumn; column <= endColumn; ++column) {
    780                    final double oldValue = getEntry(row, column);
    781                    final double newValue = visitor.visit(row, column, oldValue);
    782                    setEntry(row, column, newValue);
    783                }
    784            }
    785            return visitor.end();
    786        }
    787
    788        /** {@inheritDoc} */
    789        public double walkInRowOrder(final RealMatrixPreservingVisitor visitor,
    790                                     final int startRow, final int endRow,
    791                                     final int startColumn, final int endColumn)
    792            throws OutOfRangeException, NumberIsTooSmallException {
    793            MatrixUtils.checkSubMatrixIndex(this, startRow, endRow, startColumn, endColumn);
    794            visitor.start(getRowDimension(), getColumnDimension(),
    795                          startRow, endRow, startColumn, endColumn);
    796            for (int row = startRow; row <= endRow; ++row) {
    797                for (int column = startColumn; column <= endColumn; ++column) {
    798                    visitor.visit(row, column, getEntry(row, column));
    799                }
    800            }
    801            return visitor.end();
    802        }
    803
    804        /** {@inheritDoc} */
    805        public double walkInColumnOrder(final RealMatrixChangingVisitor visitor) {
    806            final int rows    = getRowDimension();
    807            final int columns = getColumnDimension();
    808            visitor.start(rows, columns, 0, rows - 1, 0, columns - 1);
    809            for (int column = 0; column < columns; ++column) {
    810                for (int row = 0; row < rows; ++row) {
    811                    final double oldValue = getEntry(row, column);
    812                    final double newValue = visitor.visit(row, column, oldValue);
    813                    setEntry(row, column, newValue);
    814                }
    815            }
    816            return visitor.end();
    817        }
    818
    819        /** {@inheritDoc} */
    820        public double walkInColumnOrder(final RealMatrixPreservingVisitor visitor) {
    821            final int rows    = getRowDimension();
    822            final int columns = getColumnDimension();
    823            visitor.start(rows, columns, 0, rows - 1, 0, columns - 1);
    824            for (int column = 0; column < columns; ++column) {
    825                for (int row = 0; row < rows; ++row) {
    826                    visitor.visit(row, column, getEntry(row, column));
    827                }
    828            }
    829            return visitor.end();
    830        }
    831
    832        /** {@inheritDoc} */
    833        public double walkInColumnOrder(final RealMatrixChangingVisitor visitor,
    834                                        final int startRow, final int endRow,
    835                                        final int startColumn, final int endColumn)
    836            throws OutOfRangeException, NumberIsTooSmallException {
    837            MatrixUtils.checkSubMatrixIndex(this, startRow, endRow, startColumn, endColumn);
    838            visitor.start(getRowDimension(), getColumnDimension(),
    839                          startRow, endRow, startColumn, endColumn);
    840            for (int column = startColumn; column <= endColumn; ++column) {
    841                for (int row = startRow; row <= endRow; ++row) {
    842                    final double oldValue = getEntry(row, column);
    843                    final double newValue = visitor.visit(row, column, oldValue);
    844                    setEntry(row, column, newValue);
    845                }
    846            }
    847            return visitor.end();
    848        }
    849
    850        /** {@inheritDoc} */
    851        public double walkInColumnOrder(final RealMatrixPreservingVisitor visitor,
    852                                        final int startRow, final int endRow,
    853                                        final int startColumn, final int endColumn)
    854            throws OutOfRangeException, NumberIsTooSmallException {
    855            MatrixUtils.checkSubMatrixIndex(this, startRow, endRow, startColumn, endColumn);
    856            visitor.start(getRowDimension(), getColumnDimension(),
    857                          startRow, endRow, startColumn, endColumn);
    858            for (int column = startColumn; column <= endColumn; ++column) {
    859                for (int row = startRow; row <= endRow; ++row) {
    860                    visitor.visit(row, column, getEntry(row, column));
    861                }
    862            }
    863            return visitor.end();
    864        }
    865
    866        /** {@inheritDoc} */
    867        public double walkInOptimizedOrder(final RealMatrixChangingVisitor visitor) {
    868            return walkInRowOrder(visitor);
    869        }
    870
    871        /** {@inheritDoc} */
    872        public double walkInOptimizedOrder(final RealMatrixPreservingVisitor visitor) {
    873            return walkInRowOrder(visitor);
    874        }
    875
    876        /** {@inheritDoc} */
    877        public double walkInOptimizedOrder(final RealMatrixChangingVisitor visitor,
    878                                           final int startRow, final int endRow,
    879                                           final int startColumn,
    880                                           final int endColumn)
    881            throws OutOfRangeException, NumberIsTooSmallException {
    882            return walkInRowOrder(visitor, startRow, endRow, startColumn, endColumn);
    883        }
    884
    885        /** {@inheritDoc} */
    886        public double walkInOptimizedOrder(final RealMatrixPreservingVisitor visitor,
    887                                           final int startRow, final int endRow,
    888                                           final int startColumn,
    889                                           final int endColumn)
    890            throws OutOfRangeException, NumberIsTooSmallException {
    891            return walkInRowOrder(visitor, startRow, endRow, startColumn, endColumn);
    892        }
    893
    894        /**
    895         * Get a string representation for this matrix.
    896         * @return a string representation for this matrix
    897         */
    898        @Override
    899        public String toString() {
    900            final StringBuilder res = new StringBuilder();
    901            String fullClassName = getClass().getName();
    902            String shortClassName = fullClassName.substring(fullClassName.lastIndexOf('.') + 1);
    903            res.append(shortClassName);
    904            res.append(DEFAULT_FORMAT.format(this));
    905            return res.toString();
    906        }
    907
    908        /**
    909         * Returns true iff <code>object</code> is a
    910         * <code>RealMatrix</code> instance with the same dimensions as this
    911         * and all corresponding matrix entries are equal.
    912         *
    913         * @param object the object to test equality against.
    914         * @return true if object equals this
    915         */
    916        @Override
    917        public boolean equals(final Object object) {
    918            if (object == this ) {
    919                return true;
    920            }
    921            if (object instanceof RealMatrix == false) {
    922                return false;
    923            }
    924            RealMatrix m = (RealMatrix) object;
    925            final int nRows = getRowDimension();
    926            final int nCols = getColumnDimension();
    927            if (m.getColumnDimension() != nCols || m.getRowDimension() != nRows) {
    928                return false;
    929            }
    930            for (int row = 0; row < nRows; ++row) {
    931                for (int col = 0; col < nCols; ++col) {
    932                    if (getEntry(row, col) != m.getEntry(row, col)) {
    933                        return false;
    934                    }
    935                }
    936            }
    937            return true;
    938        }
    939
    940        /**
    941         * Computes a hashcode for the matrix.
    942         *
    943         * @return hashcode for matrix
    944         */
    945        @Override
    946        public int hashCode() {
    947            int ret = 7;
    948            final int nRows = getRowDimension();
    949            final int nCols = getColumnDimension();
    950            ret = ret * 31 + nRows;
    951            ret = ret * 31 + nCols;
    952            for (int row = 0; row < nRows; ++row) {
    953                for (int col = 0; col < nCols; ++col) {
    954                   ret = ret * 31 + (11 * (row+1) + 17 * (col+1)) *
    955                       MathUtils.hash(getEntry(row, col));
    956               }
    957            }
    958            return ret;
    959        }
    960
    961
    962        /*
    963         * Empty implementations of these methods are provided in order to allow for
    964         * the use of the @Override tag with Java 1.5.
    965         */
    966
    967        /** {@inheritDoc} */
    968        public abstract RealMatrix createMatrix(int rowDimension, int columnDimension)
    969            throws NotStrictlyPositiveException;
    970
    971        /** {@inheritDoc} */
    972        public abstract RealMatrix copy();
    973
    974        /** {@inheritDoc} */
    975        public abstract double getEntry(int row, int column)
    976            throws OutOfRangeException;
    977
    978        /** {@inheritDoc} */
    979        public abstract void setEntry(int row, int column, double value)
    980            throws OutOfRangeException;
    981    }