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 java.util.ArrayList;
21  
22  import org.apache.commons.math.exception.NoDataException;
23  import org.apache.commons.math.exception.NotStrictlyPositiveException;
24  import org.apache.commons.math.exception.DimensionMismatchException;
25  import org.apache.commons.math.exception.NullArgumentException;
26  import org.apache.commons.math.exception.util.LocalizedFormats;
27  import org.apache.commons.math.util.MathUtils;
28  import org.apache.commons.math.util.FastMath;
29  
30  /**
31   * Basic implementation of RealMatrix methods regardless of the underlying storage.
32   * <p>All the methods implemented here use {@link #getEntry(int, int)} to access
33   * matrix elements. Derived class can provide faster implementations. </p>
34   *
35   * @version $Id: AbstractRealMatrix.java 1163515 2011-08-31 07:41:25Z celestin $
36   * @since 2.0
37   */
38  public abstract class AbstractRealMatrix
39      extends RealLinearOperator
40      implements RealMatrix {
41      /**
42       * Creates a matrix with no data
43       */
44      protected AbstractRealMatrix() {}
45  
46      /**
47       * Create a new RealMatrix with the supplied row and column dimensions.
48       *
49       * @param rowDimension  the number of rows in the new matrix
50       * @param columnDimension  the number of columns in the new matrix
51       * @throws NotStrictlyPositiveException if row or column dimension is not positive
52       */
53      protected AbstractRealMatrix(final int rowDimension, final int columnDimension) {
54          if (rowDimension < 1) {
55              throw new NotStrictlyPositiveException(rowDimension);
56          }
57          if (columnDimension < 1) {
58              throw new NotStrictlyPositiveException(columnDimension);
59          }
60      }
61  
62      /** {@inheritDoc} */
63      public abstract RealMatrix createMatrix(final int rowDimension, final int columnDimension);
64  
65      /** {@inheritDoc} */
66      public abstract RealMatrix copy();
67  
68      /** {@inheritDoc} */
69      public RealMatrix add(RealMatrix m) {
70          // Safety check.
71          MatrixUtils.checkAdditionCompatible(this, m);
72  
73          final int rowCount    = getRowDimension();
74          final int columnCount = getColumnDimension();
75          final RealMatrix out = createMatrix(rowCount, columnCount);
76          for (int row = 0; row < rowCount; ++row) {
77              for (int col = 0; col < columnCount; ++col) {
78                  out.setEntry(row, col, getEntry(row, col) + m.getEntry(row, col));
79              }
80          }
81  
82          return out;
83      }
84  
85      /** {@inheritDoc} */
86      public RealMatrix subtract(final RealMatrix m) {
87          // Safety check.
88          MatrixUtils.checkSubtractionCompatible(this, m);
89  
90          final int rowCount    = getRowDimension();
91          final int columnCount = getColumnDimension();
92          final RealMatrix out = createMatrix(rowCount, columnCount);
93          for (int row = 0; row < rowCount; ++row) {
94              for (int col = 0; col < columnCount; ++col) {
95                  out.setEntry(row, col, getEntry(row, col) - m.getEntry(row, col));
96              }
97          }
98  
99          return out;
100     }
101 
102     /** {@inheritDoc} */
103     public RealMatrix scalarAdd(final double d) {
104         final int rowCount    = getRowDimension();
105         final int columnCount = getColumnDimension();
106         final RealMatrix out = createMatrix(rowCount, columnCount);
107         for (int row = 0; row < rowCount; ++row) {
108             for (int col = 0; col < columnCount; ++col) {
109                 out.setEntry(row, col, getEntry(row, col) + d);
110             }
111         }
112 
113         return out;
114     }
115 
116     /** {@inheritDoc} */
117     public RealMatrix scalarMultiply(final double d) {
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     /** {@inheritDoc} */
131     public RealMatrix multiply(final RealMatrix m) {
132         // Safety check.
133         MatrixUtils.checkMultiplicationCompatible(this, m);
134 
135         final int nRows = getRowDimension();
136         final int nCols = m.getColumnDimension();
137         final int nSum  = getColumnDimension();
138         final RealMatrix out = createMatrix(nRows, nCols);
139         for (int row = 0; row < nRows; ++row) {
140             for (int col = 0; col < nCols; ++col) {
141                 double sum = 0;
142                 for (int i = 0; i < nSum; ++i) {
143                     sum += getEntry(row, i) * m.getEntry(i, col);
144                 }
145                 out.setEntry(row, col, sum);
146             }
147         }
148 
149         return out;
150     }
151 
152     /** {@inheritDoc} */
153     public RealMatrix preMultiply(final RealMatrix m) {
154         return m.multiply(this);
155     }
156 
157     /** {@inheritDoc} */
158     public RealMatrix power(final int p) {
159         if (p < 0) {
160             throw new IllegalArgumentException("p must be >= 0");
161         }
162 
163         if (!isSquare()) {
164             throw new NonSquareMatrixException(getRowDimension(), getColumnDimension());
165         }
166 
167         if (p == 0) {
168             return MatrixUtils.createRealIdentityMatrix(this.getRowDimension());
169         }
170 
171         if (p == 1) {
172             return this.copy();
173         }
174 
175         final int power = p - 1;
176 
177         /*
178          * Only log_2(p) operations is used by doing as follows:
179          * 5^214 = 5^128 * 5^64 * 5^16 * 5^4 * 5^2
180          *
181          * In general, the same approach is used for A^p.
182          */
183 
184         final char[] binaryRepresentation = Integer.toBinaryString(power).toCharArray();
185         final ArrayList<Integer> nonZeroPositions = new ArrayList<Integer>();
186         int maxI = -1;
187 
188         for (int i = 0; i < binaryRepresentation.length; ++i) {
189             if (binaryRepresentation[i] == '1') {
190                 final int pos = binaryRepresentation.length - i - 1;
191                 nonZeroPositions.add(pos);
192 
193                 // The positions are taken in turn, so maxI is only changed once
194                 if (maxI == -1) {
195                     maxI = pos;
196                 }
197             }
198         }
199 
200         RealMatrix[] results = new RealMatrix[maxI + 1];
201         results[0] = this.copy();
202 
203         for (int i = 1; i <= maxI; ++i) {
204             results[i] = results[i-1].multiply(results[i-1]);
205         }
206 
207         RealMatrix result = this.copy();
208 
209         for (Integer i : nonZeroPositions) {
210             result = result.multiply(results[i]);
211         }
212 
213         return result;
214     }
215 
216     /** {@inheritDoc} */
217     public double[][] getData() {
218         final double[][] data = new double[getRowDimension()][getColumnDimension()];
219 
220         for (int i = 0; i < data.length; ++i) {
221             final double[] dataI = data[i];
222             for (int j = 0; j < dataI.length; ++j) {
223                 dataI[j] = getEntry(i, j);
224             }
225         }
226 
227         return data;
228     }
229 
230     /** {@inheritDoc} */
231     public double getNorm() {
232         return walkInColumnOrder(new RealMatrixPreservingVisitor() {
233 
234             /** Last row index. */
235             private double endRow;
236 
237             /** Sum of absolute values on one column. */
238             private double columnSum;
239 
240             /** Maximal sum across all columns. */
241             private double maxColSum;
242 
243             /** {@inheritDoc} */
244             public void start(final int rows, final int columns,
245                               final int startRow, final int endRow,
246                               final int startColumn, final int endColumn) {
247                 this.endRow = endRow;
248                 columnSum   = 0;
249                 maxColSum   = 0;
250             }
251 
252             /** {@inheritDoc} */
253             public void visit(final int row, final int column, final double value) {
254                 columnSum += FastMath.abs(value);
255                 if (row == endRow) {
256                     maxColSum = FastMath.max(maxColSum, columnSum);
257                     columnSum = 0;
258                 }
259             }
260 
261             /** {@inheritDoc} */
262             public double end() {
263                 return maxColSum;
264             }
265         });
266     }
267 
268     /** {@inheritDoc} */
269     public double getFrobeniusNorm() {
270         return walkInOptimizedOrder(new RealMatrixPreservingVisitor() {
271 
272             /** Sum of squared entries. */
273             private double sum;
274 
275             /** {@inheritDoc} */
276             public void start(final int rows, final int columns,
277                               final int startRow, final int endRow,
278                               final int startColumn, final int endColumn) {
279                 sum = 0;
280             }
281 
282             /** {@inheritDoc} */
283             public void visit(final int row, final int column, final double value) {
284                 sum += value * value;
285             }
286 
287             /** {@inheritDoc} */
288             public double end() {
289                 return FastMath.sqrt(sum);
290             }
291         });
292     }
293 
294     /** {@inheritDoc} */
295     public RealMatrix getSubMatrix(final int startRow, final int endRow,
296                                    final int startColumn, final int endColumn) {
297         MatrixUtils.checkSubMatrixIndex(this, startRow, endRow, startColumn, endColumn);
298 
299         final RealMatrix subMatrix =
300             createMatrix(endRow - startRow + 1, endColumn - startColumn + 1);
301         for (int i = startRow; i <= endRow; ++i) {
302             for (int j = startColumn; j <= endColumn; ++j) {
303                 subMatrix.setEntry(i - startRow, j - startColumn, getEntry(i, j));
304             }
305         }
306 
307         return subMatrix;
308     }
309 
310     /** {@inheritDoc} */
311     public RealMatrix getSubMatrix(final int[] selectedRows, final int[] selectedColumns) {
312         // safety checks
313         MatrixUtils.checkSubMatrixIndex(this, selectedRows, selectedColumns);
314 
315         // copy entries
316         final RealMatrix subMatrix =
317             createMatrix(selectedRows.length, selectedColumns.length);
318         subMatrix.walkInOptimizedOrder(new DefaultRealMatrixChangingVisitor() {
319 
320             /** {@inheritDoc} */
321             @Override
322             public double visit(final int row, final int column, final double value) {
323                 return getEntry(selectedRows[row], selectedColumns[column]);
324             }
325 
326         });
327 
328         return subMatrix;
329     }
330 
331     /** {@inheritDoc} */
332     public void copySubMatrix(final int startRow, final int endRow,
333                               final int startColumn, final int endColumn,
334                               final double[][] destination) {
335         // safety checks
336         MatrixUtils.checkSubMatrixIndex(this, startRow, endRow, startColumn, endColumn);
337         final int rowsCount    = endRow + 1 - startRow;
338         final int columnsCount = endColumn + 1 - startColumn;
339         if ((destination.length < rowsCount) || (destination[0].length < columnsCount)) {
340             throw new MatrixDimensionMismatchException(destination.length, destination[0].length,
341                                                        rowsCount, columnsCount);
342         }
343 
344         // copy entries
345         walkInOptimizedOrder(new DefaultRealMatrixPreservingVisitor() {
346 
347             /** Initial row index. */
348             private int startRow;
349 
350             /** Initial column index. */
351             private int startColumn;
352 
353             /** {@inheritDoc} */
354             @Override
355             public void start(final int rows, final int columns,
356                               final int startRow, final int endRow,
357                               final int startColumn, final int endColumn) {
358                 this.startRow    = startRow;
359                 this.startColumn = startColumn;
360             }
361 
362             /** {@inheritDoc} */
363             @Override
364             public void visit(final int row, final int column, final double value) {
365                 destination[row - startRow][column - startColumn] = value;
366             }
367 
368         }, startRow, endRow, startColumn, endColumn);
369     }
370 
371     /** {@inheritDoc} */
372     public void copySubMatrix(int[] selectedRows, int[] selectedColumns, double[][] destination) {
373         // safety checks
374         MatrixUtils.checkSubMatrixIndex(this, selectedRows, selectedColumns);
375         if ((destination.length < selectedRows.length) ||
376             (destination[0].length < selectedColumns.length)) {
377             throw new MatrixDimensionMismatchException(destination.length, destination[0].length,
378                                                        selectedRows.length, selectedColumns.length);
379         }
380 
381         // copy entries
382         for (int i = 0; i < selectedRows.length; i++) {
383             final double[] destinationI = destination[i];
384             for (int j = 0; j < selectedColumns.length; j++) {
385                 destinationI[j] = getEntry(selectedRows[i], selectedColumns[j]);
386             }
387         }
388     }
389 
390     /** {@inheritDoc} */
391     public void setSubMatrix(final double[][] subMatrix, final int row, final int column)
392         throws NoDataException, DimensionMismatchException, NullArgumentException {
393         MathUtils.checkNotNull(subMatrix);
394         final int nRows = subMatrix.length;
395         if (nRows == 0) {
396             throw new NoDataException(LocalizedFormats.AT_LEAST_ONE_ROW);
397         }
398 
399         final int nCols = subMatrix[0].length;
400         if (nCols == 0) {
401             throw new NoDataException(LocalizedFormats.AT_LEAST_ONE_COLUMN);
402         }
403 
404         for (int r = 1; r < nRows; ++r) {
405             if (subMatrix[r].length != nCols) {
406                 throw new DimensionMismatchException(nCols, subMatrix[r].length);
407             }
408         }
409 
410         MatrixUtils.checkRowIndex(this, row);
411         MatrixUtils.checkColumnIndex(this, column);
412         MatrixUtils.checkRowIndex(this, nRows + row - 1);
413         MatrixUtils.checkColumnIndex(this, nCols + column - 1);
414 
415         for (int i = 0; i < nRows; ++i) {
416             for (int j = 0; j < nCols; ++j) {
417                 setEntry(row + i, column + j, subMatrix[i][j]);
418             }
419         }
420     }
421 
422     /** {@inheritDoc} */
423     public RealMatrix getRowMatrix(final int row) {
424         MatrixUtils.checkRowIndex(this, row);
425         final int nCols = getColumnDimension();
426         final RealMatrix out = createMatrix(1, nCols);
427         for (int i = 0; i < nCols; ++i) {
428             out.setEntry(0, i, getEntry(row, i));
429         }
430 
431         return out;
432     }
433 
434     /** {@inheritDoc} */
435     public void setRowMatrix(final int row, final RealMatrix matrix) {
436         MatrixUtils.checkRowIndex(this, row);
437         final int nCols = getColumnDimension();
438         if ((matrix.getRowDimension() != 1) ||
439             (matrix.getColumnDimension() != nCols)) {
440             throw new MatrixDimensionMismatchException(matrix.getRowDimension(),
441                                                        matrix.getColumnDimension(),
442                                                        1, nCols);
443         }
444         for (int i = 0; i < nCols; ++i) {
445             setEntry(row, i, matrix.getEntry(0, i));
446         }
447     }
448 
449     /** {@inheritDoc} */
450     public RealMatrix getColumnMatrix(final int column) {
451         MatrixUtils.checkColumnIndex(this, column);
452         final int nRows = getRowDimension();
453         final RealMatrix out = createMatrix(nRows, 1);
454         for (int i = 0; i < nRows; ++i) {
455             out.setEntry(i, 0, getEntry(i, column));
456         }
457 
458         return out;
459     }
460 
461     /** {@inheritDoc} */
462     public void setColumnMatrix(final int column, final RealMatrix matrix) {
463         MatrixUtils.checkColumnIndex(this, column);
464         final int nRows = getRowDimension();
465         if ((matrix.getRowDimension() != nRows) ||
466             (matrix.getColumnDimension() != 1)) {
467             throw new MatrixDimensionMismatchException(matrix.getRowDimension(),
468                                                        matrix.getColumnDimension(),
469                                                        nRows, 1);
470         }
471         for (int i = 0; i < nRows; ++i) {
472             setEntry(i, column, matrix.getEntry(i, 0));
473         }
474     }
475 
476     /** {@inheritDoc} */
477     public RealVector getRowVector(final int row) {
478         return new ArrayRealVector(getRow(row), false);
479     }
480 
481     /** {@inheritDoc} */
482     public void setRowVector(final int row, final RealVector vector) {
483         MatrixUtils.checkRowIndex(this, row);
484         final int nCols = getColumnDimension();
485         if (vector.getDimension() != nCols) {
486             throw new MatrixDimensionMismatchException(1, vector.getDimension(),
487                                                        1, nCols);
488         }
489         for (int i = 0; i < nCols; ++i) {
490             setEntry(row, i, vector.getEntry(i));
491         }
492     }
493 
494     /** {@inheritDoc} */
495     public RealVector getColumnVector(final int column) {
496         return new ArrayRealVector(getColumn(column), false);
497     }
498 
499     /** {@inheritDoc} */
500     public void setColumnVector(final int column, final RealVector vector) {
501         MatrixUtils.checkColumnIndex(this, column);
502         final int nRows = getRowDimension();
503         if (vector.getDimension() != nRows) {
504             throw new MatrixDimensionMismatchException(vector.getDimension(), 1,
505                                                        nRows, 1);
506         }
507         for (int i = 0; i < nRows; ++i) {
508             setEntry(i, column, vector.getEntry(i));
509         }
510     }
511 
512     /** {@inheritDoc} */
513     public double[] getRow(final int row) {
514         MatrixUtils.checkRowIndex(this, row);
515         final int nCols = getColumnDimension();
516         final double[] out = new double[nCols];
517         for (int i = 0; i < nCols; ++i) {
518             out[i] = getEntry(row, i);
519         }
520 
521         return out;
522     }
523 
524     /** {@inheritDoc} */
525     public void setRow(final int row, final double[] array) {
526         MatrixUtils.checkRowIndex(this, row);
527         final int nCols = getColumnDimension();
528         if (array.length != nCols) {
529             throw new MatrixDimensionMismatchException(1, array.length, 1, nCols);
530         }
531         for (int i = 0; i < nCols; ++i) {
532             setEntry(row, i, array[i]);
533         }
534     }
535 
536     /** {@inheritDoc} */
537     public double[] getColumn(final int column) {
538         MatrixUtils.checkColumnIndex(this, column);
539         final int nRows = getRowDimension();
540         final double[] out = new double[nRows];
541         for (int i = 0; i < nRows; ++i) {
542             out[i] = getEntry(i, column);
543         }
544 
545         return out;
546     }
547 
548     /** {@inheritDoc} */
549     public void setColumn(final int column, final double[] array) {
550         MatrixUtils.checkColumnIndex(this, column);
551         final int nRows = getRowDimension();
552         if (array.length != nRows) {
553             throw new MatrixDimensionMismatchException(array.length, 1, nRows, 1);
554         }
555         for (int i = 0; i < nRows; ++i) {
556             setEntry(i, column, array[i]);
557         }
558     }
559 
560     /** {@inheritDoc} */
561     public abstract double getEntry(int row, int column);
562 
563     /** {@inheritDoc} */
564     public abstract void setEntry(int row, int column, double value);
565 
566     /** {@inheritDoc} */
567     public abstract void addToEntry(int row, int column, double increment);
568 
569     /** {@inheritDoc} */
570     public abstract void multiplyEntry(int row, int column, double factor);
571 
572     /** {@inheritDoc} */
573     public RealMatrix transpose() {
574         final int nRows = getRowDimension();
575         final int nCols = getColumnDimension();
576         final RealMatrix out = createMatrix(nCols, nRows);
577         walkInOptimizedOrder(new DefaultRealMatrixPreservingVisitor() {
578 
579             /** {@inheritDoc} */
580             @Override
581             public void visit(final int row, final int column, final double value) {
582                 out.setEntry(column, row, value);
583             }
584 
585         });
586 
587         return out;
588     }
589 
590     /** {@inheritDoc} */
591     public boolean isSquare() {
592         return getColumnDimension() == getRowDimension();
593     }
594 
595     /** {@inheritDoc} */
596 
597     /**
598      * Returns the number of rows of this matrix.
599      *
600      * @return the number of rows.
601      */
602     @Override
603     public abstract int getRowDimension();
604 
605     /**
606      * Returns the number of columns of this matrix.
607      *
608      * @return the number of columns.
609      */
610     @Override
611     public abstract int getColumnDimension();
612 
613     /** {@inheritDoc} */
614     public double getTrace() {
615         final int nRows = getRowDimension();
616         final int nCols = getColumnDimension();
617         if (nRows != nCols) {
618             throw new NonSquareMatrixException(nRows, nCols);
619        }
620         double trace = 0;
621         for (int i = 0; i < nRows; ++i) {
622             trace += getEntry(i, i);
623         }
624         return trace;
625     }
626 
627     /** {@inheritDoc} */
628     public double[] operate(final double[] v) {
629         final int nRows = getRowDimension();
630         final int nCols = getColumnDimension();
631         if (v.length != nCols) {
632             throw new DimensionMismatchException(v.length, nCols);
633         }
634 
635         final double[] out = new double[nRows];
636         for (int row = 0; row < nRows; ++row) {
637             double sum = 0;
638             for (int i = 0; i < nCols; ++i) {
639                 sum += getEntry(row, i) * v[i];
640             }
641             out[row] = sum;
642         }
643 
644         return out;
645     }
646 
647     /** {@inheritDoc} */
648     @Override
649     public RealVector operate(final RealVector v) {
650         try {
651             return new ArrayRealVector(operate(((ArrayRealVector) v).getDataRef()), false);
652         } catch (ClassCastException cce) {
653             final int nRows = getRowDimension();
654             final int nCols = getColumnDimension();
655             if (v.getDimension() != nCols) {
656                 throw new DimensionMismatchException(v.getDimension(), nCols);
657             }
658 
659             final double[] out = new double[nRows];
660             for (int row = 0; row < nRows; ++row) {
661                 double sum = 0;
662                 for (int i = 0; i < nCols; ++i) {
663                     sum += getEntry(row, i) * v.getEntry(i);
664                 }
665                 out[row] = sum;
666             }
667 
668             return new ArrayRealVector(out, false);
669         }
670     }
671 
672     /** {@inheritDoc} */
673     public double[] preMultiply(final double[] v) {
674 
675         final int nRows = getRowDimension();
676         final int nCols = getColumnDimension();
677         if (v.length != nRows) {
678             throw new DimensionMismatchException(v.length, nRows);
679         }
680 
681         final double[] out = new double[nCols];
682         for (int col = 0; col < nCols; ++col) {
683             double sum = 0;
684             for (int i = 0; i < nRows; ++i) {
685                 sum += getEntry(i, col) * v[i];
686             }
687             out[col] = sum;
688         }
689 
690         return out;
691     }
692 
693     /** {@inheritDoc} */
694     public RealVector preMultiply(final RealVector v) {
695         try {
696             return new ArrayRealVector(preMultiply(((ArrayRealVector) v).getDataRef()), false);
697         } catch (ClassCastException cce) {
698 
699             final int nRows = getRowDimension();
700             final int nCols = getColumnDimension();
701             if (v.getDimension() != nRows) {
702                 throw new DimensionMismatchException(v.getDimension(), nRows);
703             }
704 
705             final double[] out = new double[nCols];
706             for (int col = 0; col < nCols; ++col) {
707                 double sum = 0;
708                 for (int i = 0; i < nRows; ++i) {
709                     sum += getEntry(i, col) * v.getEntry(i);
710                 }
711                 out[col] = sum;
712             }
713 
714             return new ArrayRealVector(out, false);
715         }
716     }
717 
718     /** {@inheritDoc} */
719     public double walkInRowOrder(final RealMatrixChangingVisitor visitor) {
720         final int rows    = getRowDimension();
721         final int columns = getColumnDimension();
722         visitor.start(rows, columns, 0, rows - 1, 0, columns - 1);
723         for (int row = 0; row < rows; ++row) {
724             for (int column = 0; column < columns; ++column) {
725                 final double oldValue = getEntry(row, column);
726                 final double newValue = visitor.visit(row, column, oldValue);
727                 setEntry(row, column, newValue);
728             }
729         }
730         return visitor.end();
731     }
732 
733     /** {@inheritDoc} */
734     public double walkInRowOrder(final RealMatrixPreservingVisitor visitor) {
735         final int rows    = getRowDimension();
736         final int columns = getColumnDimension();
737         visitor.start(rows, columns, 0, rows - 1, 0, columns - 1);
738         for (int row = 0; row < rows; ++row) {
739             for (int column = 0; column < columns; ++column) {
740                 visitor.visit(row, column, getEntry(row, column));
741             }
742         }
743         return visitor.end();
744     }
745 
746     /** {@inheritDoc} */
747     public double walkInRowOrder(final RealMatrixChangingVisitor visitor,
748                                  final int startRow, final int endRow,
749                                  final int startColumn, final int endColumn) {
750         MatrixUtils.checkSubMatrixIndex(this, startRow, endRow, startColumn, endColumn);
751         visitor.start(getRowDimension(), getColumnDimension(),
752                       startRow, endRow, startColumn, endColumn);
753         for (int row = startRow; row <= endRow; ++row) {
754             for (int column = startColumn; column <= endColumn; ++column) {
755                 final double oldValue = getEntry(row, column);
756                 final double newValue = visitor.visit(row, column, oldValue);
757                 setEntry(row, column, newValue);
758             }
759         }
760         return visitor.end();
761     }
762 
763     /** {@inheritDoc} */
764     public double walkInRowOrder(final RealMatrixPreservingVisitor visitor,
765                                  final int startRow, final int endRow,
766                                  final int startColumn, final int endColumn) {
767         MatrixUtils.checkSubMatrixIndex(this, startRow, endRow, startColumn, endColumn);
768         visitor.start(getRowDimension(), getColumnDimension(),
769                       startRow, endRow, startColumn, endColumn);
770         for (int row = startRow; row <= endRow; ++row) {
771             for (int column = startColumn; column <= endColumn; ++column) {
772                 visitor.visit(row, column, getEntry(row, column));
773             }
774         }
775         return visitor.end();
776     }
777 
778     /** {@inheritDoc} */
779     public double walkInColumnOrder(final RealMatrixChangingVisitor visitor) {
780         final int rows    = getRowDimension();
781         final int columns = getColumnDimension();
782         visitor.start(rows, columns, 0, rows - 1, 0, columns - 1);
783         for (int column = 0; column < columns; ++column) {
784             for (int row = 0; row < rows; ++row) {
785                 final double oldValue = getEntry(row, column);
786                 final double newValue = visitor.visit(row, column, oldValue);
787                 setEntry(row, column, newValue);
788             }
789         }
790         return visitor.end();
791     }
792 
793     /** {@inheritDoc} */
794     public double walkInColumnOrder(final RealMatrixPreservingVisitor visitor) {
795         final int rows    = getRowDimension();
796         final int columns = getColumnDimension();
797         visitor.start(rows, columns, 0, rows - 1, 0, columns - 1);
798         for (int column = 0; column < columns; ++column) {
799             for (int row = 0; row < rows; ++row) {
800                 visitor.visit(row, column, getEntry(row, column));
801             }
802         }
803         return visitor.end();
804     }
805 
806     /** {@inheritDoc} */
807     public double walkInColumnOrder(final RealMatrixChangingVisitor visitor,
808                                     final int startRow, final int endRow,
809                                     final int startColumn, final int endColumn) {
810         MatrixUtils.checkSubMatrixIndex(this, startRow, endRow, startColumn, endColumn);
811         visitor.start(getRowDimension(), getColumnDimension(),
812                       startRow, endRow, startColumn, endColumn);
813         for (int column = startColumn; column <= endColumn; ++column) {
814             for (int row = startRow; row <= endRow; ++row) {
815                 final double oldValue = getEntry(row, column);
816                 final double newValue = visitor.visit(row, column, oldValue);
817                 setEntry(row, column, newValue);
818             }
819         }
820         return visitor.end();
821     }
822 
823     /** {@inheritDoc} */
824     public double walkInColumnOrder(final RealMatrixPreservingVisitor visitor,
825                                     final int startRow, final int endRow,
826                                     final int startColumn, final int endColumn) {
827         MatrixUtils.checkSubMatrixIndex(this, startRow, endRow, startColumn, endColumn);
828         visitor.start(getRowDimension(), getColumnDimension(),
829                       startRow, endRow, startColumn, endColumn);
830         for (int column = startColumn; column <= endColumn; ++column) {
831             for (int row = startRow; row <= endRow; ++row) {
832                 visitor.visit(row, column, getEntry(row, column));
833             }
834         }
835         return visitor.end();
836     }
837 
838     /** {@inheritDoc} */
839     public double walkInOptimizedOrder(final RealMatrixChangingVisitor visitor) {
840         return walkInRowOrder(visitor);
841     }
842 
843     /** {@inheritDoc} */
844     public double walkInOptimizedOrder(final RealMatrixPreservingVisitor visitor) {
845         return walkInRowOrder(visitor);
846     }
847 
848     /** {@inheritDoc} */
849     public double walkInOptimizedOrder(final RealMatrixChangingVisitor visitor,
850                                        final int startRow, final int endRow,
851                                        final int startColumn, final int endColumn) {
852         return walkInRowOrder(visitor, startRow, endRow, startColumn, endColumn);
853     }
854 
855     /** {@inheritDoc} */
856     public double walkInOptimizedOrder(final RealMatrixPreservingVisitor visitor,
857                                        final int startRow, final int endRow,
858                                        final int startColumn, final int endColumn) {
859         return walkInRowOrder(visitor, startRow, endRow, startColumn, endColumn);
860     }
861 
862     /**
863      * Get a string representation for this matrix.
864      * @return a string representation for this matrix
865      */
866     @Override
867     public String toString() {
868         final int nRows = getRowDimension();
869         final int nCols = getColumnDimension();
870         final StringBuffer res = new StringBuffer();
871         String fullClassName = getClass().getName();
872         String shortClassName = fullClassName.substring(fullClassName.lastIndexOf('.') + 1);
873         res.append(shortClassName).append("{");
874 
875         for (int i = 0; i < nRows; ++i) {
876             if (i > 0) {
877                 res.append(",");
878             }
879             res.append("{");
880             for (int j = 0; j < nCols; ++j) {
881                 if (j > 0) {
882                     res.append(",");
883                 }
884                 res.append(getEntry(i, j));
885             }
886             res.append("}");
887         }
888 
889         res.append("}");
890         return res.toString();
891     }
892 
893     /**
894      * Returns true iff <code>object</code> is a
895      * <code>RealMatrix</code> instance with the same dimensions as this
896      * and all corresponding matrix entries are equal.
897      *
898      * @param object the object to test equality against.
899      * @return true if object equals this
900      */
901     @Override
902     public boolean equals(final Object object) {
903         if (object == this ) {
904             return true;
905         }
906         if (object instanceof RealMatrix == false) {
907             return false;
908         }
909         RealMatrix m = (RealMatrix) object;
910         final int nRows = getRowDimension();
911         final int nCols = getColumnDimension();
912         if (m.getColumnDimension() != nCols || m.getRowDimension() != nRows) {
913             return false;
914         }
915         for (int row = 0; row < nRows; ++row) {
916             for (int col = 0; col < nCols; ++col) {
917                 if (getEntry(row, col) != m.getEntry(row, col)) {
918                     return false;
919                 }
920             }
921         }
922         return true;
923     }
924 
925     /**
926      * Computes a hashcode for the matrix.
927      *
928      * @return hashcode for matrix
929      */
930     @Override
931     public int hashCode() {
932         int ret = 7;
933         final int nRows = getRowDimension();
934         final int nCols = getColumnDimension();
935         ret = ret * 31 + nRows;
936         ret = ret * 31 + nCols;
937         for (int row = 0; row < nRows; ++row) {
938             for (int col = 0; col < nCols; ++col) {
939                ret = ret * 31 + (11 * (row+1) + 17 * (col+1)) *
940                    MathUtils.hash(getEntry(row, col));
941            }
942         }
943         return ret;
944     }
945 }