001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017
018package org.apache.commons.math4.legacy.linear;
019
020import java.util.ArrayList;
021import java.util.Locale;
022
023import org.apache.commons.math4.legacy.exception.DimensionMismatchException;
024import org.apache.commons.math4.legacy.exception.NoDataException;
025import org.apache.commons.math4.legacy.exception.NotPositiveException;
026import org.apache.commons.math4.legacy.exception.NotStrictlyPositiveException;
027import org.apache.commons.math4.legacy.exception.NullArgumentException;
028import org.apache.commons.math4.legacy.exception.NumberIsTooSmallException;
029import org.apache.commons.math4.legacy.exception.OutOfRangeException;
030import org.apache.commons.math4.legacy.exception.util.LocalizedFormats;
031import org.apache.commons.math4.core.jdkmath.JdkMath;
032
033/**
034 * Basic implementation of RealMatrix methods regardless of the underlying storage.
035 * <p>All the methods implemented here use {@link #getEntry(int, int)} to access
036 * matrix elements. Derived class can provide faster implementations.</p>
037 *
038 * @since 2.0
039 */
040public abstract class AbstractRealMatrix
041    extends RealLinearOperator
042    implements RealMatrix {
043
044    /** Default format. */
045    private static final RealMatrixFormat DEFAULT_FORMAT = RealMatrixFormat.getInstance(Locale.US);
046    static {
047        // set the minimum fraction digits to 1 to keep compatibility
048        DEFAULT_FORMAT.getFormat().setMinimumFractionDigits(1);
049    }
050
051    /**
052     * Creates a matrix with no data.
053     */
054    protected AbstractRealMatrix() {}
055
056    /**
057     * Create a new RealMatrix with the supplied row and column dimensions.
058     *
059     * @param rowDimension  the number of rows in the new matrix
060     * @param columnDimension  the number of columns in the new matrix
061     * @throws NotStrictlyPositiveException if row or column dimension is not positive
062     */
063    protected AbstractRealMatrix(final int rowDimension,
064        final int columnDimension)
065        throws NotStrictlyPositiveException {
066        if (rowDimension < 1) {
067            throw new NotStrictlyPositiveException(rowDimension);
068        }
069        if (columnDimension < 1) {
070            throw new NotStrictlyPositiveException(columnDimension);
071        }
072    }
073
074    /** {@inheritDoc} */
075    @Override
076    public RealMatrix add(RealMatrix m)
077        throws MatrixDimensionMismatchException {
078        checkAdd(m);
079
080        final int rowCount    = getRowDimension();
081        final int columnCount = getColumnDimension();
082        final RealMatrix out = createMatrix(rowCount, columnCount);
083        for (int row = 0; row < rowCount; ++row) {
084            for (int col = 0; col < columnCount; ++col) {
085                out.setEntry(row, col, getEntry(row, col) + m.getEntry(row, col));
086            }
087        }
088
089        return out;
090    }
091
092    /** {@inheritDoc} */
093    @Override
094    public RealMatrix subtract(final RealMatrix m)
095        throws MatrixDimensionMismatchException {
096        checkAdd(m);
097
098        final int rowCount    = getRowDimension();
099        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 hashcode for the matrix.
979     *
980     * @return hashcode 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}