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