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