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