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