View Javadoc

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