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