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    *      https://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  /*
19   * This is not the original file distributed by the Apache Software Foundation
20   * It has been modified by the Hipparchus project
21   */
22  
23  package org.hipparchus.linear;
24  
25  import java.util.ArrayList;
26  import java.util.List;
27  import java.util.Locale;
28  
29  import org.hipparchus.exception.LocalizedCoreFormats;
30  import org.hipparchus.exception.MathIllegalArgumentException;
31  import org.hipparchus.exception.NullArgumentException;
32  import org.hipparchus.util.FastMath;
33  import org.hipparchus.util.MathUtils;
34  
35  /**
36   * Basic implementation of RealMatrix methods regardless of the underlying storage.
37   * <p>All the methods implemented here use {@link #getEntry(int, int)} to access
38   * matrix elements. Derived class can provide faster implementations.</p>
39   *
40   */
41  public abstract class AbstractRealMatrix
42      implements RealMatrix, RealLinearOperator {
43  
44      /** Default format. */
45      private static final RealMatrixFormat DEFAULT_FORMAT = RealMatrixFormat.getRealMatrixFormat(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          // This constructor is intentionally empty. Nothing special is needed here.
56      }
57  
58      /**
59       * Create a new RealMatrix with the supplied row and column dimensions.
60       *
61       * @param rowDimension  the number of rows in the new matrix
62       * @param columnDimension  the number of columns in the new matrix
63       * @throws MathIllegalArgumentException if row or column dimension is not positive
64       */
65      protected AbstractRealMatrix(final int rowDimension,
66          final int columnDimension)
67          throws MathIllegalArgumentException {
68          if (rowDimension < 1) {
69              throw new MathIllegalArgumentException(LocalizedCoreFormats.AT_LEAST_ONE_ROW);
70          }
71          if (columnDimension < 1) {
72              throw new MathIllegalArgumentException(LocalizedCoreFormats.AT_LEAST_ONE_COLUMN);
73          }
74      }
75  
76      /** {@inheritDoc} */
77      @Override
78      public RealMatrix add(RealMatrix m)
79          throws MathIllegalArgumentException {
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      /** {@inheritDoc} */
95      @Override
96      public RealMatrix subtract(final RealMatrix m)
97          throws MathIllegalArgumentException {
98          MatrixUtils.checkSubtractionCompatible(this, m);
99  
100         final int rowCount    = getRowDimension();
101         final int columnCount = getColumnDimension();
102         final RealMatrix out = createMatrix(rowCount, columnCount);
103         for (int row = 0; row < rowCount; ++row) {
104             for (int col = 0; col < columnCount; ++col) {
105                 out.setEntry(row, col, getEntry(row, col) - m.getEntry(row, col));
106             }
107         }
108 
109         return out;
110     }
111 
112     /** {@inheritDoc} */
113     @Override
114     public RealMatrix scalarAdd(final double d) {
115         final int rowCount    = getRowDimension();
116         final int columnCount = getColumnDimension();
117         final RealMatrix out = createMatrix(rowCount, columnCount);
118         for (int row = 0; row < rowCount; ++row) {
119             for (int col = 0; col < columnCount; ++col) {
120                 out.setEntry(row, col, getEntry(row, col) + d);
121             }
122         }
123 
124         return out;
125     }
126 
127     /** {@inheritDoc} */
128     @Override
129     public RealMatrix scalarMultiply(final double d) {
130         final int rowCount    = getRowDimension();
131         final int columnCount = getColumnDimension();
132         final RealMatrix out = createMatrix(rowCount, columnCount);
133         for (int row = 0; row < rowCount; ++row) {
134             for (int col = 0; col < columnCount; ++col) {
135                 out.setEntry(row, col, getEntry(row, col) * d);
136             }
137         }
138 
139         return out;
140     }
141 
142     /** {@inheritDoc} */
143     @Override
144     public RealMatrix multiply(final RealMatrix m)
145         throws MathIllegalArgumentException {
146         MatrixUtils.checkMultiplicationCompatible(this, m);
147 
148         final int nRows = getRowDimension();
149         final int nCols = m.getColumnDimension();
150         final int nSum  = getColumnDimension();
151         final RealMatrix out = createMatrix(nRows, nCols);
152         for (int row = 0; row < nRows; ++row) {
153             for (int col = 0; col < nCols; ++col) {
154                 double sum = 0;
155                 for (int i = 0; i < nSum; ++i) {
156                     sum += getEntry(row, i) * m.getEntry(i, col);
157                 }
158                 out.setEntry(row, col, sum);
159             }
160         }
161 
162         return out;
163     }
164 
165     /** {@inheritDoc} */
166     @Override
167     public RealMatrix preMultiply(final RealMatrix m)
168         throws MathIllegalArgumentException {
169         return m.multiply(this);
170     }
171 
172     /** {@inheritDoc} */
173     @Override
174     public RealMatrix power(final int p)
175         throws MathIllegalArgumentException {
176         if (p < 0) {
177             throw new MathIllegalArgumentException(LocalizedCoreFormats.NOT_POSITIVE_EXPONENT, p);
178         }
179 
180         if (!isSquare()) {
181             throw new MathIllegalArgumentException(LocalizedCoreFormats.NON_SQUARE_MATRIX,
182                                                    getRowDimension(), getColumnDimension());
183         }
184 
185         if (p == 0) {
186             return MatrixUtils.createRealIdentityMatrix(this.getRowDimension());
187         }
188 
189         if (p == 1) {
190             return this.copy();
191         }
192 
193         final int power = p - 1;
194 
195         /*
196          * Only log_2(p) operations is used by doing as follows:
197          * 5^214 = 5^128 * 5^64 * 5^16 * 5^4 * 5^2
198          *
199          * In general, the same approach is used for A^p.
200          */
201 
202         final char[]        binaryRepresentation = Integer.toBinaryString(power).toCharArray();
203         final List<Integer> nonZeroPositions     = new ArrayList<>();
204         int                 maxI                 = -1;
205 
206         for (int i = 0; i < binaryRepresentation.length; ++i) {
207             if (binaryRepresentation[i] == '1') {
208                 final int pos = binaryRepresentation.length - i - 1;
209                 nonZeroPositions.add(pos);
210 
211                 // The positions are taken in turn, so maxI is only changed once
212                 if (maxI == -1) {
213                     maxI = pos;
214                 }
215             }
216         }
217 
218         RealMatrix[] results = new RealMatrix[maxI + 1];
219         results[0] = this.copy();
220 
221         for (int i = 1; i <= maxI; ++i) {
222             results[i] = results[i-1].multiply(results[i-1]);
223         }
224 
225         RealMatrix result = this.copy();
226 
227         for (Integer i : nonZeroPositions) {
228             result = result.multiply(results[i]);
229         }
230 
231         return result;
232     }
233 
234     /** {@inheritDoc} */
235     @Override
236     public double[][] getData() {
237         final double[][] data = new double[getRowDimension()][getColumnDimension()];
238 
239         for (int i = 0; i < data.length; ++i) {
240             final double[] dataI = data[i];
241             for (int j = 0; j < dataI.length; ++j) {
242                 dataI[j] = getEntry(i, j);
243             }
244         }
245 
246         return data;
247     }
248 
249     /** {@inheritDoc} */
250     @Override
251     public double getFrobeniusNorm() {
252         return walkInOptimizedOrder(new RealMatrixPreservingVisitor() {
253 
254             /** Sum of squared entries. */
255             private double sum;
256 
257             /** {@inheritDoc} */
258             @Override
259             public void start(final int rows, final int columns,
260                               final int startRow, final int endRow,
261                               final int startColumn, final int endColumn) {
262                 sum = 0;
263             }
264 
265             /** {@inheritDoc} */
266             @Override
267             public void visit(final int row, final int column, final double value) {
268                 sum += value * value;
269             }
270 
271             /** {@inheritDoc} */
272             @Override
273             public double end() {
274                 return FastMath.sqrt(sum);
275             }
276         });
277     }
278 
279     /** {@inheritDoc} */
280     @Override
281     public RealMatrix getSubMatrix(final int startRow, final int endRow,
282                                    final int startColumn, final int endColumn)
283         throws MathIllegalArgumentException {
284         MatrixUtils.checkSubMatrixIndex(this, startRow, endRow, startColumn, endColumn);
285 
286         final RealMatrix subMatrix =
287             createMatrix(endRow - startRow + 1, endColumn - startColumn + 1);
288         for (int i = startRow; i <= endRow; ++i) {
289             for (int j = startColumn; j <= endColumn; ++j) {
290                 subMatrix.setEntry(i - startRow, j - startColumn, getEntry(i, j));
291             }
292         }
293 
294         return subMatrix;
295     }
296 
297     /** {@inheritDoc} */
298     @Override
299     public RealMatrix getSubMatrix(final int[] selectedRows,
300                                    final int[] selectedColumns)
301         throws MathIllegalArgumentException, NullArgumentException {
302         MatrixUtils.checkSubMatrixIndex(this, selectedRows, selectedColumns);
303 
304         final RealMatrix subMatrix =
305             createMatrix(selectedRows.length, selectedColumns.length);
306         subMatrix.walkInOptimizedOrder(new DefaultRealMatrixChangingVisitor() {
307 
308             /** {@inheritDoc} */
309             @Override
310             public double visit(final int row, final int column, final double value) {
311                 return getEntry(selectedRows[row], selectedColumns[column]);
312             }
313 
314         });
315 
316         return subMatrix;
317     }
318 
319     /** {@inheritDoc} */
320     @Override
321     public void copySubMatrix(final int startRow, final int endRow,
322                               final int startColumn, final int endColumn,
323                               final double[][] destination)
324         throws MathIllegalArgumentException {
325         MatrixUtils.checkSubMatrixIndex(this, startRow, endRow, startColumn, endColumn);
326         final int rowsCount    = endRow + 1 - startRow;
327         final int columnsCount = endColumn + 1 - startColumn;
328         if ((destination.length < rowsCount) || (destination[0].length < columnsCount)) {
329             throw new MathIllegalArgumentException(LocalizedCoreFormats.DIMENSIONS_MISMATCH_2x2,
330                                                    destination.length, destination[0].length,
331                                                    rowsCount, columnsCount);
332         }
333 
334         for (int i = 1; i < rowsCount; i++) {
335             if (destination[i].length < columnsCount) {
336                 throw new MathIllegalArgumentException(LocalizedCoreFormats.DIMENSIONS_MISMATCH_2x2,
337                                                        destination.length, destination[i].length,
338                                                        rowsCount, columnsCount);
339             }
340         }
341 
342         walkInOptimizedOrder(new DefaultRealMatrixPreservingVisitor() {
343 
344             /** Initial row index. */
345             private int startRow;
346 
347             /** Initial column index. */
348             private int startColumn;
349 
350             /** {@inheritDoc} */
351             @Override
352             public void start(final int rows, final int columns,
353                               final int startRow, final int endRow,
354                               final int startColumn, final int endColumn) {
355                 this.startRow    = startRow;
356                 this.startColumn = startColumn;
357             }
358 
359             /** {@inheritDoc} */
360             @Override
361             public void visit(final int row, final int column, final double value) {
362                 destination[row - startRow][column - startColumn] = value;
363             }
364 
365         }, startRow, endRow, startColumn, endColumn);
366     }
367 
368     /** {@inheritDoc} */
369     @Override
370     public void copySubMatrix(int[] selectedRows, int[] selectedColumns,
371                               double[][] destination)
372         throws MathIllegalArgumentException, NullArgumentException {
373         MatrixUtils.checkSubMatrixIndex(this, selectedRows, selectedColumns);
374         final int nCols = selectedColumns.length;
375         if ((destination.length < selectedRows.length) ||
376             (destination[0].length < nCols)) {
377             throw new MathIllegalArgumentException(LocalizedCoreFormats.DIMENSIONS_MISMATCH_2x2,
378                                                    destination.length, destination[0].length,
379                                                    selectedRows.length, selectedColumns.length);
380         }
381 
382         for (int i = 0; i < selectedRows.length; i++) {
383             final double[] destinationI = destination[i];
384             if (destinationI.length < nCols) {
385                 throw new MathIllegalArgumentException(LocalizedCoreFormats.DIMENSIONS_MISMATCH_2x2,
386                                                        destination.length, destinationI.length,
387                                                        selectedRows.length, selectedColumns.length);
388             }
389             for (int j = 0; j < selectedColumns.length; j++) {
390                 destinationI[j] = getEntry(selectedRows[i], selectedColumns[j]);
391             }
392         }
393     }
394 
395     /** {@inheritDoc} */
396     @Override
397     public void setSubMatrix(final double[][] subMatrix, final int row, final int column)
398         throws MathIllegalArgumentException, NullArgumentException {
399         MathUtils.checkNotNull(subMatrix);
400         final int nRows = subMatrix.length;
401         if (nRows == 0) {
402             throw new MathIllegalArgumentException(LocalizedCoreFormats.AT_LEAST_ONE_ROW);
403         }
404 
405         final int nCols = subMatrix[0].length;
406         if (nCols == 0) {
407             throw new MathIllegalArgumentException(LocalizedCoreFormats.AT_LEAST_ONE_COLUMN);
408         }
409 
410         for (int r = 1; r < nRows; ++r) {
411             if (subMatrix[r].length != nCols) {
412                 throw new MathIllegalArgumentException(LocalizedCoreFormats.DIMENSIONS_MISMATCH,
413                                                        nCols, subMatrix[r].length);
414             }
415         }
416 
417         MatrixUtils.checkRowIndex(this, row);
418         MatrixUtils.checkColumnIndex(this, column);
419         MatrixUtils.checkRowIndex(this, nRows + row - 1);
420         MatrixUtils.checkColumnIndex(this, nCols + column - 1);
421 
422         for (int i = 0; i < nRows; ++i) {
423             for (int j = 0; j < nCols; ++j) {
424                 setEntry(row + i, column + j, subMatrix[i][j]);
425             }
426         }
427     }
428 
429     /** {@inheritDoc} */
430     @Override
431     public RealMatrix getRowMatrix(final int row) throws MathIllegalArgumentException {
432         MatrixUtils.checkRowIndex(this, row);
433         final int nCols = getColumnDimension();
434         final RealMatrix out = createMatrix(1, nCols);
435         for (int i = 0; i < nCols; ++i) {
436             out.setEntry(0, i, getEntry(row, i));
437         }
438 
439         return out;
440     }
441 
442     /** {@inheritDoc} */
443     @Override
444     public void setRowMatrix(final int row, final RealMatrix matrix)
445         throws MathIllegalArgumentException {
446         MatrixUtils.checkRowIndex(this, row);
447         final int nCols = getColumnDimension();
448         if ((matrix.getRowDimension() != 1) ||
449             (matrix.getColumnDimension() != nCols)) {
450             throw new MathIllegalArgumentException(LocalizedCoreFormats.DIMENSIONS_MISMATCH_2x2,
451                                                    matrix.getRowDimension(), matrix.getColumnDimension(),
452                                                    1, nCols);
453         }
454         for (int i = 0; i < nCols; ++i) {
455             setEntry(row, i, matrix.getEntry(0, i));
456         }
457     }
458 
459     /** {@inheritDoc} */
460     @Override
461     public RealMatrix getColumnMatrix(final int column)
462         throws MathIllegalArgumentException {
463         MatrixUtils.checkColumnIndex(this, column);
464         final int nRows = getRowDimension();
465         final RealMatrix out = createMatrix(nRows, 1);
466         for (int i = 0; i < nRows; ++i) {
467             out.setEntry(i, 0, getEntry(i, column));
468         }
469 
470         return out;
471     }
472 
473     /** {@inheritDoc} */
474     @Override
475     public void setColumnMatrix(final int column, final RealMatrix matrix)
476         throws MathIllegalArgumentException {
477         MatrixUtils.checkColumnIndex(this, column);
478         final int nRows = getRowDimension();
479         if ((matrix.getRowDimension() != nRows) ||
480             (matrix.getColumnDimension() != 1)) {
481             throw new MathIllegalArgumentException(LocalizedCoreFormats.DIMENSIONS_MISMATCH_2x2,
482                                                    matrix.getRowDimension(), matrix.getColumnDimension(),
483                                                    nRows, 1);
484         }
485         for (int i = 0; i < nRows; ++i) {
486             setEntry(i, column, matrix.getEntry(i, 0));
487         }
488     }
489 
490     /** {@inheritDoc} */
491     @Override
492     public RealVector getRowVector(final int row)
493         throws MathIllegalArgumentException {
494         return new ArrayRealVector(getRow(row), false);
495     }
496 
497     /** {@inheritDoc} */
498     @Override
499     public void setRowVector(final int row, final RealVector vector)
500         throws MathIllegalArgumentException {
501         MatrixUtils.checkRowIndex(this, row);
502         final int nCols = getColumnDimension();
503         if (vector.getDimension() != nCols) {
504             throw new MathIllegalArgumentException(LocalizedCoreFormats.DIMENSIONS_MISMATCH_2x2,
505                                                    1, vector.getDimension(),
506                                                    1, nCols);
507         }
508         for (int i = 0; i < nCols; ++i) {
509             setEntry(row, i, vector.getEntry(i));
510         }
511     }
512 
513     /** {@inheritDoc} */
514     @Override
515     public RealVector getColumnVector(final int column)
516         throws MathIllegalArgumentException {
517         return new ArrayRealVector(getColumn(column), false);
518     }
519 
520     /** {@inheritDoc} */
521     @Override
522     public void setColumnVector(final int column, final RealVector vector)
523         throws MathIllegalArgumentException {
524         MatrixUtils.checkColumnIndex(this, column);
525         final int nRows = getRowDimension();
526         if (vector.getDimension() != nRows) {
527             throw new MathIllegalArgumentException(LocalizedCoreFormats.DIMENSIONS_MISMATCH_2x2,
528                                                    vector.getDimension(), 1,
529                                                    nRows, 1);
530         }
531         for (int i = 0; i < nRows; ++i) {
532             setEntry(i, column, vector.getEntry(i));
533         }
534     }
535 
536     /** {@inheritDoc} */
537     @Override
538     public double[] getRow(final int row) throws MathIllegalArgumentException {
539         MatrixUtils.checkRowIndex(this, row);
540         final int nCols = getColumnDimension();
541         final double[] out = new double[nCols];
542         for (int i = 0; i < nCols; ++i) {
543             out[i] = getEntry(row, i);
544         }
545 
546         return out;
547     }
548 
549     /** {@inheritDoc} */
550     @Override
551     public void setRow(final int row, final double[] array)
552         throws MathIllegalArgumentException {
553         MatrixUtils.checkRowIndex(this, row);
554         final int nCols = getColumnDimension();
555         if (array.length != nCols) {
556             throw new MathIllegalArgumentException(LocalizedCoreFormats.DIMENSIONS_MISMATCH_2x2,
557                                                    1, array.length,
558                                                    1, nCols);
559         }
560         for (int i = 0; i < nCols; ++i) {
561             setEntry(row, i, array[i]);
562         }
563     }
564 
565     /** {@inheritDoc} */
566     @Override
567     public double[] getColumn(final int column) throws MathIllegalArgumentException {
568         MatrixUtils.checkColumnIndex(this, column);
569         final int nRows = getRowDimension();
570         final double[] out = new double[nRows];
571         for (int i = 0; i < nRows; ++i) {
572             out[i] = getEntry(i, column);
573         }
574 
575         return out;
576     }
577 
578     /** {@inheritDoc} */
579     @Override
580     public void setColumn(final int column, final double[] array)
581         throws MathIllegalArgumentException {
582         MatrixUtils.checkColumnIndex(this, column);
583         final int nRows = getRowDimension();
584         if (array.length != nRows) {
585             throw new MathIllegalArgumentException(LocalizedCoreFormats.DIMENSIONS_MISMATCH_2x2,
586                                                    array.length, 1,
587                                                    nRows, 1);
588         }
589         for (int i = 0; i < nRows; ++i) {
590             setEntry(i, column, array[i]);
591         }
592     }
593 
594     /** {@inheritDoc} */
595     @Override
596     public void addToEntry(int row, int column, double increment)
597         throws MathIllegalArgumentException {
598         MatrixUtils.checkMatrixIndex(this, row, column);
599         setEntry(row, column, getEntry(row, column) + increment);
600     }
601 
602     /** {@inheritDoc} */
603     @Override
604     public void multiplyEntry(int row, int column, double factor)
605         throws MathIllegalArgumentException {
606         MatrixUtils.checkMatrixIndex(this, row, column);
607         setEntry(row, column, getEntry(row, column) * factor);
608     }
609 
610     /** {@inheritDoc} */
611     @Override
612     public RealMatrix transpose() {
613         final int nRows = getRowDimension();
614         final int nCols = getColumnDimension();
615         final RealMatrix out = createMatrix(nCols, nRows);
616         walkInOptimizedOrder(new DefaultRealMatrixPreservingVisitor() {
617 
618             /** {@inheritDoc} */
619             @Override
620             public void visit(final int row, final int column, final double value) {
621                 out.setEntry(column, row, value);
622             }
623 
624         });
625 
626         return out;
627     }
628 
629     /** {@inheritDoc} */
630     @Override
631     public boolean isSquare() {
632         return getColumnDimension() == getRowDimension();
633     }
634 
635     /**
636      * Returns the number of rows of this matrix.
637      *
638      * @return the number of rows.
639      */
640     @Override
641     public abstract int getRowDimension();
642 
643     /**
644      * Returns the number of columns of this matrix.
645      *
646      * @return the number of columns.
647      */
648     @Override
649     public abstract int getColumnDimension();
650 
651     /** {@inheritDoc} */
652     @Override
653     public double getTrace() throws MathIllegalArgumentException {
654         final int nRows = getRowDimension();
655         final int nCols = getColumnDimension();
656         if (nRows != nCols) {
657             throw new MathIllegalArgumentException(LocalizedCoreFormats.NON_SQUARE_MATRIX,
658                                                    nRows, nCols);
659        }
660         double trace = 0;
661         for (int i = 0; i < nRows; ++i) {
662             trace += getEntry(i, i);
663         }
664         return trace;
665     }
666 
667     /** {@inheritDoc} */
668     @Override
669     public double[] operate(final double[] v)
670         throws MathIllegalArgumentException {
671         final int nRows = getRowDimension();
672         final int nCols = getColumnDimension();
673         if (v.length != nCols) {
674             throw new MathIllegalArgumentException(LocalizedCoreFormats.DIMENSIONS_MISMATCH,
675                                                    v.length, nCols);
676         }
677 
678         final double[] out = new double[nRows];
679         for (int row = 0; row < nRows; ++row) {
680             double sum = 0;
681             for (int i = 0; i < nCols; ++i) {
682                 sum += getEntry(row, i) * v[i];
683             }
684             out[row] = sum;
685         }
686 
687         return out;
688     }
689 
690     /** {@inheritDoc} */
691     @Override
692     public RealVector operate(final RealVector v)
693         throws MathIllegalArgumentException {
694         if (v instanceof ArrayRealVector) {
695             return new ArrayRealVector(operate(((ArrayRealVector) v).getDataRef()), false);
696         } else {
697             final int nRows = getRowDimension();
698             final int nCols = getColumnDimension();
699             if (v.getDimension() != nCols) {
700                 throw new MathIllegalArgumentException(LocalizedCoreFormats.DIMENSIONS_MISMATCH,
701                                                        v.getDimension(), nCols);
702             }
703 
704             final double[] out = new double[nRows];
705             for (int row = 0; row < nRows; ++row) {
706                 double sum = 0;
707                 for (int i = 0; i < nCols; ++i) {
708                     sum += getEntry(row, i) * v.getEntry(i);
709                 }
710                 out[row] = sum;
711             }
712 
713             return new ArrayRealVector(out, false);
714         }
715     }
716 
717     /** {@inheritDoc} */
718     @Override
719     public double[] preMultiply(final double[] v) throws MathIllegalArgumentException {
720 
721         final int nRows = getRowDimension();
722         final int nCols = getColumnDimension();
723         if (v.length != nRows) {
724             throw new MathIllegalArgumentException(LocalizedCoreFormats.DIMENSIONS_MISMATCH,
725                                                    v.length, nRows);
726         }
727 
728         final double[] out = new double[nCols];
729         for (int col = 0; col < nCols; ++col) {
730             double sum = 0;
731             for (int i = 0; i < nRows; ++i) {
732                 sum += getEntry(i, col) * v[i];
733             }
734             out[col] = sum;
735         }
736 
737         return out;
738     }
739 
740     /** {@inheritDoc} */
741     @Override
742     public RealVector preMultiply(final RealVector v) throws MathIllegalArgumentException {
743         if (v instanceof ArrayRealVector) {
744             return new ArrayRealVector(preMultiply(((ArrayRealVector) v).getDataRef()), false);
745         } else {
746 
747             final int nRows = getRowDimension();
748             final int nCols = getColumnDimension();
749             if (v.getDimension() != nRows) {
750                 throw new MathIllegalArgumentException(LocalizedCoreFormats.DIMENSIONS_MISMATCH,
751                                                        v.getDimension(), nRows);
752             }
753 
754             final double[] out = new double[nCols];
755             for (int col = 0; col < nCols; ++col) {
756                 double sum = 0;
757                 for (int i = 0; i < nRows; ++i) {
758                     sum += getEntry(i, col) * v.getEntry(i);
759                 }
760                 out[col] = sum;
761             }
762 
763             return new ArrayRealVector(out, false);
764         }
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 MathIllegalArgumentException {
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 MathIllegalArgumentException {
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 MathIllegalArgumentException {
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 MathIllegalArgumentException {
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 MathIllegalArgumentException {
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 MathIllegalArgumentException {
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).append(DEFAULT_FORMAT.format(this));
941         return res.toString();
942     }
943 
944     /**
945      * Returns true iff <code>object</code> is a
946      * <code>RealMatrix</code> instance with the same dimensions as this
947      * and all corresponding matrix entries are equal.
948      *
949      * @param object the object to test equality against.
950      * @return true if object equals this
951      */
952     @Override
953     public boolean equals(final Object object) {
954         if (object == this) {
955             return true;
956         }
957         if (!(object instanceof RealMatrix)) {
958             return false;
959         }
960         RealMatrix m = (RealMatrix) object;
961         final int nRows = getRowDimension();
962         final int nCols = getColumnDimension();
963         if (m.getColumnDimension() != nCols || m.getRowDimension() != nRows) {
964             return false;
965         }
966         for (int row = 0; row < nRows; ++row) {
967             for (int col = 0; col < nCols; ++col) {
968                 if (getEntry(row, col) != m.getEntry(row, col)) {
969                     return false;
970                 }
971             }
972         }
973         return true;
974     }
975 
976     /**
977      * Computes a hashcode for the matrix.
978      *
979      * @return hashcode for matrix
980      */
981     @Override
982     public int hashCode() {
983         int ret = 7;
984         final int nRows = getRowDimension();
985         final int nCols = getColumnDimension();
986         ret = ret * 31 + nRows;
987         ret = ret * 31 + nCols;
988         for (int row = 0; row < nRows; ++row) {
989             for (int col = 0; col < nCols; ++col) {
990                ret = ret * 31 + (11 * (row+1) + 17 * (col+1)) *
991                    MathUtils.hash(getEntry(row, col));
992            }
993         }
994         return ret;
995     }
996 
997 
998     /*
999      * Empty implementations of these methods are provided in order to allow for
1000      * the use of the @Override tag with Java 1.5.
1001      */
1002 
1003     /** {@inheritDoc} */
1004     @Override
1005     public abstract RealMatrix createMatrix(int rowDimension, int columnDimension)
1006         throws MathIllegalArgumentException;
1007 
1008     /** {@inheritDoc} */
1009     @Override
1010     public abstract RealMatrix copy();
1011 
1012     /** {@inheritDoc} */
1013     @Override
1014     public abstract double getEntry(int row, int column)
1015         throws MathIllegalArgumentException;
1016 
1017     /** {@inheritDoc} */
1018     @Override
1019     public abstract void setEntry(int row, int column, double value)
1020         throws MathIllegalArgumentException;
1021 }