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
18package org.apache.commons.math.linear;
19
20import org.apache.commons.math.MathRuntimeException;
21import org.apache.commons.math.linear.MatrixVisitorException;
22import org.apache.commons.math.exception.util.LocalizedFormats;
23import org.apache.commons.math.util.MathUtils;
24import 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 févr. 2011) $
32 * @since 2.0
33 */
34public 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