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