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 org.apache.commons.math.MathRuntimeException;
021    import org.apache.commons.math.linear.MatrixVisitorException;
022    import org.apache.commons.math.exception.util.LocalizedFormats;
023    import org.apache.commons.math.util.MathUtils;
024    import org.apache.commons.math.util.FastMath;
025    
026    /**
027     * Basic implementation of RealMatrix methods regardless of the underlying storage.
028     * <p>All the methods implemented here use {@link #getEntry(int, int)} to access
029     * matrix elements. Derived class can provide faster implementations. </p>
030     *
031     * @version $Revision: 1073158 $ $Date: 2011-02-21 22:46:52 +0100 (lun. 21 f??vr. 2011) $
032     * @since 2.0
033     */
034    public abstract class AbstractRealMatrix implements RealMatrix {
035    
036    
037        /** Cached LU solver.
038         * @deprecated as of release 2.0, since all methods using this are deprecated
039         */
040        @Deprecated
041        private DecompositionSolver lu;
042    
043        /**
044         * Creates a matrix with no data
045         */
046        protected AbstractRealMatrix() {
047            lu = null;
048        }
049    
050        /**
051         * Create a new RealMatrix with the supplied row and column dimensions.
052         *
053         * @param rowDimension  the number of rows in the new matrix
054         * @param columnDimension  the number of columns in the new matrix
055         * @throws IllegalArgumentException if row or column dimension is not positive
056         */
057        protected AbstractRealMatrix(final int rowDimension, final int columnDimension)
058            throws IllegalArgumentException {
059            if (rowDimension < 1 ) {
060                throw MathRuntimeException.createIllegalArgumentException(
061                        LocalizedFormats.INSUFFICIENT_DIMENSION, rowDimension, 1);
062            }
063            if (columnDimension <= 0) {
064                throw MathRuntimeException.createIllegalArgumentException(
065                        LocalizedFormats.INSUFFICIENT_DIMENSION, columnDimension, 1);
066            }
067            lu = null;
068        }
069    
070        /** {@inheritDoc} */
071        public abstract RealMatrix createMatrix(final int rowDimension, final int columnDimension)
072            throws IllegalArgumentException;
073    
074        /** {@inheritDoc} */
075        public abstract RealMatrix copy();
076    
077        /** {@inheritDoc} */
078        public RealMatrix add(RealMatrix m) throws IllegalArgumentException {
079    
080            // safety check
081            MatrixUtils.checkAdditionCompatible(this, m);
082    
083            final int rowCount    = getRowDimension();
084            final int columnCount = getColumnDimension();
085            final RealMatrix out = createMatrix(rowCount, columnCount);
086            for (int row = 0; row < rowCount; ++row) {
087                for (int col = 0; col < columnCount; ++col) {
088                    out.setEntry(row, col, getEntry(row, col) + m.getEntry(row, col));
089                }
090            }
091    
092            return out;
093    
094        }
095    
096        /** {@inheritDoc} */
097        public RealMatrix subtract(final RealMatrix m) throws IllegalArgumentException {
098    
099            // safety check
100            MatrixUtils.checkSubtractionCompatible(this, m);
101    
102            final int rowCount    = getRowDimension();
103            final int columnCount = getColumnDimension();
104            final RealMatrix out = createMatrix(rowCount, columnCount);
105            for (int row = 0; row < rowCount; ++row) {
106                for (int col = 0; col < columnCount; ++col) {
107                    out.setEntry(row, col, getEntry(row, col) - m.getEntry(row, col));
108                }
109            }
110    
111            return out;
112    
113        }
114    
115        /** {@inheritDoc} */
116        public RealMatrix scalarAdd(final double d) {
117    
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    
131        /** {@inheritDoc} */
132        public RealMatrix scalarMultiply(final double d) {
133    
134            final int rowCount    = getRowDimension();
135            final int columnCount = getColumnDimension();
136            final RealMatrix out = createMatrix(rowCount, columnCount);
137            for (int row = 0; row < rowCount; ++row) {
138                for (int col = 0; col < columnCount; ++col) {
139                    out.setEntry(row, col, getEntry(row, col) * d);
140                }
141            }
142    
143            return out;
144    
145        }
146    
147        /** {@inheritDoc} */
148        public RealMatrix multiply(final RealMatrix m)
149            throws IllegalArgumentException {
150    
151            // safety check
152            MatrixUtils.checkMultiplicationCompatible(this, m);
153    
154            final int nRows = getRowDimension();
155            final int nCols = m.getColumnDimension();
156            final int nSum  = getColumnDimension();
157            final RealMatrix out = createMatrix(nRows, nCols);
158            for (int row = 0; row < nRows; ++row) {
159                for (int col = 0; col < nCols; ++col) {
160                    double sum = 0;
161                    for (int i = 0; i < nSum; ++i) {
162                        sum += getEntry(row, i) * m.getEntry(i, col);
163                    }
164                    out.setEntry(row, col, sum);
165                }
166            }
167    
168            return out;
169    
170        }
171    
172        /** {@inheritDoc} */
173        public RealMatrix preMultiply(final RealMatrix m)
174            throws IllegalArgumentException {
175            return m.multiply(this);
176        }
177    
178        /** {@inheritDoc} */
179        public double[][] getData() {
180    
181            final double[][] data = new double[getRowDimension()][getColumnDimension()];
182    
183            for (int i = 0; i < data.length; ++i) {
184                final double[] dataI = data[i];
185                for (int j = 0; j < dataI.length; ++j) {
186                    dataI[j] = getEntry(i, j);
187                }
188            }
189    
190            return data;
191    
192        }
193    
194        /** {@inheritDoc} */
195        public double getNorm() {
196            return walkInColumnOrder(new RealMatrixPreservingVisitor() {
197    
198                /** Last row index. */
199                private double endRow;
200    
201                /** Sum of absolute values on one column. */
202                private double columnSum;
203    
204                /** Maximal sum across all columns. */
205                private double maxColSum;
206    
207                /** {@inheritDoc} */
208                public void start(final int rows, final int columns,
209                                  final int startRow, final int endRow,
210                                  final int startColumn, final int endColumn) {
211                    this.endRow = endRow;
212                    columnSum   = 0;
213                    maxColSum   = 0;
214                }
215    
216                /** {@inheritDoc} */
217                public void visit(final int row, final int column, final double value) {
218                    columnSum += FastMath.abs(value);
219                    if (row == endRow) {
220                        maxColSum = FastMath.max(maxColSum, columnSum);
221                        columnSum = 0;
222                    }
223                }
224    
225                /** {@inheritDoc} */
226                public double end() {
227                    return maxColSum;
228                }
229    
230            });
231        }
232    
233        /** {@inheritDoc} */
234        public double getFrobeniusNorm() {
235            return walkInOptimizedOrder(new RealMatrixPreservingVisitor() {
236    
237                /** Sum of squared entries. */
238                private double sum;
239    
240                /** {@inheritDoc} */
241                public void start(final int rows, final int columns,
242                                  final int startRow, final int endRow,
243                                  final int startColumn, final int endColumn) {
244                    sum = 0;
245                }
246    
247                /** {@inheritDoc} */
248                public void visit(final int row, final int column, final double value) {
249                    sum += value * value;
250                }
251    
252                /** {@inheritDoc} */
253                public double end() {
254                    return FastMath.sqrt(sum);
255                }
256    
257            });
258        }
259    
260        /** {@inheritDoc} */
261        public RealMatrix getSubMatrix(final int startRow, final int endRow,
262                                       final int startColumn, final int endColumn)
263            throws MatrixIndexException {
264    
265            MatrixUtils.checkSubMatrixIndex(this, startRow, endRow, startColumn, endColumn);
266    
267            final RealMatrix subMatrix =
268                createMatrix(endRow - startRow + 1, endColumn - startColumn + 1);
269            for (int i = startRow; i <= endRow; ++i) {
270                for (int j = startColumn; j <= endColumn; ++j) {
271                    subMatrix.setEntry(i - startRow, j - startColumn, getEntry(i, j));
272                }
273            }
274    
275            return subMatrix;
276    
277        }
278    
279        /** {@inheritDoc} */
280        public RealMatrix getSubMatrix(final int[] selectedRows, final int[] selectedColumns)
281            throws MatrixIndexException {
282    
283            // safety checks
284            MatrixUtils.checkSubMatrixIndex(this, selectedRows, selectedColumns);
285    
286            // copy entries
287            final RealMatrix subMatrix =
288                createMatrix(selectedRows.length, selectedColumns.length);
289            subMatrix.walkInOptimizedOrder(new DefaultRealMatrixChangingVisitor() {
290    
291                /** {@inheritDoc} */
292                @Override
293                public double visit(final int row, final int column, final double value) {
294                    return getEntry(selectedRows[row], selectedColumns[column]);
295                }
296    
297            });
298    
299            return subMatrix;
300    
301        }
302    
303        /** {@inheritDoc} */
304        public void copySubMatrix(final int startRow, final int endRow,
305                                  final int startColumn, final int endColumn,
306                                  final double[][] destination)
307            throws MatrixIndexException, IllegalArgumentException {
308    
309            // safety checks
310            MatrixUtils.checkSubMatrixIndex(this, startRow, endRow, startColumn, endColumn);
311            final int rowsCount    = endRow + 1 - startRow;
312            final int columnsCount = endColumn + 1 - startColumn;
313            if ((destination.length < rowsCount) || (destination[0].length < columnsCount)) {
314                throw MathRuntimeException.createIllegalArgumentException(
315                        LocalizedFormats.DIMENSIONS_MISMATCH_2x2,
316                        destination.length, destination[0].length,
317                        rowsCount, columnsCount);
318            }
319    
320            // copy entries
321            walkInOptimizedOrder(new DefaultRealMatrixPreservingVisitor() {
322    
323                /** Initial row index. */
324                private int startRow;
325    
326                /** Initial column index. */
327                private int startColumn;
328    
329                /** {@inheritDoc} */
330                @Override
331                public void start(final int rows, final int columns,
332                                  final int startRow, final int endRow,
333                                  final int startColumn, final int endColumn) {
334                    this.startRow    = startRow;
335                    this.startColumn = startColumn;
336                }
337    
338                /** {@inheritDoc} */
339                @Override
340                public void visit(final int row, final int column, final double value) {
341                    destination[row - startRow][column - startColumn] = value;
342                }
343    
344            }, startRow, endRow, startColumn, endColumn);
345    
346        }
347    
348        /** {@inheritDoc} */
349        public void copySubMatrix(int[] selectedRows, int[] selectedColumns, double[][] destination)
350            throws MatrixIndexException, IllegalArgumentException {
351    
352            // safety checks
353            MatrixUtils.checkSubMatrixIndex(this, selectedRows, selectedColumns);
354            if ((destination.length < selectedRows.length) ||
355                (destination[0].length < selectedColumns.length)) {
356                throw MathRuntimeException.createIllegalArgumentException(
357                        LocalizedFormats.DIMENSIONS_MISMATCH_2x2,
358                        destination.length, destination[0].length,
359                        selectedRows.length, selectedColumns.length);
360            }
361    
362            // copy entries
363            for (int i = 0; i < selectedRows.length; i++) {
364                final double[] destinationI = destination[i];
365                for (int j = 0; j < selectedColumns.length; j++) {
366                    destinationI[j] = getEntry(selectedRows[i], selectedColumns[j]);
367                }
368            }
369    
370        }
371    
372        /** {@inheritDoc} */
373        public void setSubMatrix(final double[][] subMatrix, final int row, final int column)
374            throws MatrixIndexException {
375    
376            final int nRows = subMatrix.length;
377            if (nRows == 0) {
378                throw MathRuntimeException.createIllegalArgumentException(LocalizedFormats.AT_LEAST_ONE_ROW);
379            }
380    
381            final int nCols = subMatrix[0].length;
382            if (nCols == 0) {
383                throw MathRuntimeException.createIllegalArgumentException(LocalizedFormats.AT_LEAST_ONE_COLUMN);
384            }
385    
386            for (int r = 1; r < nRows; ++r) {
387                if (subMatrix[r].length != nCols) {
388                    throw MathRuntimeException.createIllegalArgumentException(
389                            LocalizedFormats.DIFFERENT_ROWS_LENGTHS,
390                            nCols, subMatrix[r].length);
391                }
392            }
393    
394            MatrixUtils.checkRowIndex(this, row);
395            MatrixUtils.checkColumnIndex(this, column);
396            MatrixUtils.checkRowIndex(this, nRows + row - 1);
397            MatrixUtils.checkColumnIndex(this, nCols + column - 1);
398    
399            for (int i = 0; i < nRows; ++i) {
400                for (int j = 0; j < nCols; ++j) {
401                    setEntry(row + i, column + j, subMatrix[i][j]);
402                }
403            }
404    
405            lu = null;
406    
407        }
408    
409        /** {@inheritDoc} */
410        public RealMatrix getRowMatrix(final int row)
411            throws MatrixIndexException {
412    
413            MatrixUtils.checkRowIndex(this, row);
414            final int nCols = getColumnDimension();
415            final RealMatrix out = createMatrix(1, nCols);
416            for (int i = 0; i < nCols; ++i) {
417                out.setEntry(0, i, getEntry(row, i));
418            }
419    
420            return out;
421    
422        }
423    
424        /** {@inheritDoc} */
425        public void setRowMatrix(final int row, final RealMatrix matrix)
426            throws MatrixIndexException, InvalidMatrixException {
427    
428            MatrixUtils.checkRowIndex(this, row);
429            final int nCols = getColumnDimension();
430            if ((matrix.getRowDimension() != 1) ||
431                (matrix.getColumnDimension() != nCols)) {
432                throw new InvalidMatrixException(
433                        LocalizedFormats.DIMENSIONS_MISMATCH_2x2,
434                        matrix.getRowDimension(), matrix.getColumnDimension(), 1, nCols);
435            }
436            for (int i = 0; i < nCols; ++i) {
437                setEntry(row, i, matrix.getEntry(0, i));
438            }
439    
440        }
441    
442        /** {@inheritDoc} */
443        public RealMatrix getColumnMatrix(final int column)
444            throws MatrixIndexException {
445    
446            MatrixUtils.checkColumnIndex(this, column);
447            final int nRows = getRowDimension();
448            final RealMatrix out = createMatrix(nRows, 1);
449            for (int i = 0; i < nRows; ++i) {
450                out.setEntry(i, 0, getEntry(i, column));
451            }
452    
453            return out;
454    
455        }
456    
457        /** {@inheritDoc} */
458        public void setColumnMatrix(final int column, final RealMatrix matrix)
459            throws MatrixIndexException, InvalidMatrixException {
460    
461            MatrixUtils.checkColumnIndex(this, column);
462            final int nRows = getRowDimension();
463            if ((matrix.getRowDimension() != nRows) ||
464                (matrix.getColumnDimension() != 1)) {
465                throw new InvalidMatrixException(
466                        LocalizedFormats.DIMENSIONS_MISMATCH_2x2,
467                        matrix.getRowDimension(), matrix.getColumnDimension(), nRows, 1);
468            }
469            for (int i = 0; i < nRows; ++i) {
470                setEntry(i, column, matrix.getEntry(i, 0));
471            }
472    
473        }
474    
475        /** {@inheritDoc} */
476        public RealVector getRowVector(final int row)
477            throws MatrixIndexException {
478            return new ArrayRealVector(getRow(row), false);
479        }
480    
481        /** {@inheritDoc} */
482        public void setRowVector(final int row, final RealVector vector)
483            throws MatrixIndexException, InvalidMatrixException {
484    
485            MatrixUtils.checkRowIndex(this, row);
486            final int nCols = getColumnDimension();
487            if (vector.getDimension() != nCols) {
488                throw new InvalidMatrixException(
489                        LocalizedFormats.DIMENSIONS_MISMATCH_2x2,
490                        1, vector.getDimension(), 1, nCols);
491            }
492            for (int i = 0; i < nCols; ++i) {
493                setEntry(row, i, vector.getEntry(i));
494            }
495    
496        }
497    
498        /** {@inheritDoc} */
499        public RealVector getColumnVector(final int column)
500            throws MatrixIndexException {
501            return new ArrayRealVector(getColumn(column), false);
502        }
503    
504        /** {@inheritDoc} */
505        public void setColumnVector(final int column, final RealVector vector)
506            throws MatrixIndexException, InvalidMatrixException {
507    
508            MatrixUtils.checkColumnIndex(this, column);
509            final int nRows = getRowDimension();
510            if (vector.getDimension() != nRows) {
511                throw new InvalidMatrixException(
512                        LocalizedFormats.DIMENSIONS_MISMATCH_2x2,
513                        vector.getDimension(), 1, nRows, 1);
514            }
515            for (int i = 0; i < nRows; ++i) {
516                setEntry(i, column, vector.getEntry(i));
517            }
518    
519        }
520    
521        /** {@inheritDoc} */
522        public double[] getRow(final int row)
523            throws MatrixIndexException {
524    
525            MatrixUtils.checkRowIndex(this, row);
526            final int nCols = getColumnDimension();
527            final double[] out = new double[nCols];
528            for (int i = 0; i < nCols; ++i) {
529                out[i] = getEntry(row, i);
530            }
531    
532            return out;
533    
534        }
535    
536        /** {@inheritDoc} */
537        public void setRow(final int row, final double[] array)
538            throws MatrixIndexException, InvalidMatrixException {
539    
540            MatrixUtils.checkRowIndex(this, row);
541            final int nCols = getColumnDimension();
542            if (array.length != nCols) {
543                throw new InvalidMatrixException(
544                        LocalizedFormats.DIMENSIONS_MISMATCH_2x2,
545                        1, array.length, 1, nCols);
546            }
547            for (int i = 0; i < nCols; ++i) {
548                setEntry(row, i, array[i]);
549            }
550    
551        }
552    
553        /** {@inheritDoc} */
554        public double[] getColumn(final int column)
555            throws MatrixIndexException {
556    
557            MatrixUtils.checkColumnIndex(this, column);
558            final int nRows = getRowDimension();
559            final double[] out = new double[nRows];
560            for (int i = 0; i < nRows; ++i) {
561                out[i] = getEntry(i, column);
562            }
563    
564            return out;
565    
566        }
567    
568        /** {@inheritDoc} */
569        public void setColumn(final int column, final double[] array)
570            throws MatrixIndexException, InvalidMatrixException {
571    
572            MatrixUtils.checkColumnIndex(this, column);
573            final int nRows = getRowDimension();
574            if (array.length != nRows) {
575                throw new InvalidMatrixException(
576                        LocalizedFormats.DIMENSIONS_MISMATCH_2x2,
577                        array.length, 1, nRows, 1);
578            }
579            for (int i = 0; i < nRows; ++i) {
580                setEntry(i, column, array[i]);
581            }
582    
583        }
584    
585        /** {@inheritDoc} */
586        public abstract double getEntry(int row, int column)
587            throws MatrixIndexException;
588    
589        /** {@inheritDoc} */
590        public abstract void setEntry(int row, int column, double value)
591            throws MatrixIndexException;
592    
593        /** {@inheritDoc} */
594        public abstract void addToEntry(int row, int column, double increment)
595            throws MatrixIndexException;
596    
597        /** {@inheritDoc} */
598        public abstract void multiplyEntry(int row, int column, double factor)
599            throws MatrixIndexException;
600    
601        /** {@inheritDoc} */
602        public RealMatrix transpose() {
603    
604            final int nRows = getRowDimension();
605            final int nCols = getColumnDimension();
606            final RealMatrix out = createMatrix(nCols, nRows);
607            walkInOptimizedOrder(new DefaultRealMatrixPreservingVisitor() {
608    
609                /** {@inheritDoc} */
610                @Override
611                public void visit(final int row, final int column, final double value) {
612                    out.setEntry(column, row, value);
613                }
614    
615            });
616    
617            return out;
618    
619        }
620    
621        /** {@inheritDoc} */
622        @Deprecated
623        public RealMatrix inverse()
624            throws InvalidMatrixException {
625            if (lu == null) {
626                lu = new LUDecompositionImpl(this, MathUtils.SAFE_MIN).getSolver();
627            }
628            return lu.getInverse();
629        }
630    
631        /** {@inheritDoc} */
632        @Deprecated
633        public double getDeterminant()
634            throws InvalidMatrixException {
635            return new LUDecompositionImpl(this, MathUtils.SAFE_MIN).getDeterminant();
636        }
637    
638        /** {@inheritDoc} */
639        public boolean isSquare() {
640            return getColumnDimension() == getRowDimension();
641        }
642    
643        /** {@inheritDoc} */
644        @Deprecated
645        public boolean isSingular() {
646            if (lu == null) {
647                lu = new LUDecompositionImpl(this, MathUtils.SAFE_MIN).getSolver();
648           }
649            return !lu.isNonSingular();
650        }
651    
652        /** {@inheritDoc} */
653        public abstract int getRowDimension();
654    
655        /** {@inheritDoc} */
656        public abstract int getColumnDimension();
657    
658        /** {@inheritDoc} */
659        public double getTrace()
660            throws NonSquareMatrixException {
661            final int nRows = getRowDimension();
662            final int nCols = getColumnDimension();
663            if (nRows != nCols) {
664                throw new NonSquareMatrixException(nRows, nCols);
665           }
666            double trace = 0;
667            for (int i = 0; i < nRows; ++i) {
668                trace += getEntry(i, i);
669            }
670            return trace;
671        }
672    
673        /** {@inheritDoc} */
674        public double[] operate(final double[] v)
675            throws IllegalArgumentException {
676    
677            final int nRows = getRowDimension();
678            final int nCols = getColumnDimension();
679            if (v.length != nCols) {
680                throw MathRuntimeException.createIllegalArgumentException(
681                        LocalizedFormats.VECTOR_LENGTH_MISMATCH,
682                        v.length, nCols);
683            }
684    
685            final double[] out = new double[nRows];
686            for (int row = 0; row < nRows; ++row) {
687                double sum = 0;
688                for (int i = 0; i < nCols; ++i) {
689                    sum += getEntry(row, i) * v[i];
690                }
691                out[row] = sum;
692            }
693    
694            return out;
695    
696        }
697    
698        /** {@inheritDoc} */
699        public RealVector operate(final RealVector v)
700            throws IllegalArgumentException {
701            try {
702                return new ArrayRealVector(operate(((ArrayRealVector) v).getDataRef()), false);
703            } catch (ClassCastException cce) {
704                final int nRows = getRowDimension();
705                final int nCols = getColumnDimension();
706                if (v.getDimension() != nCols) {
707                    throw MathRuntimeException.createIllegalArgumentException(
708                            LocalizedFormats.VECTOR_LENGTH_MISMATCH,
709                            v.getDimension(), nCols);
710                }
711    
712                final double[] out = new double[nRows];
713                for (int row = 0; row < nRows; ++row) {
714                    double sum = 0;
715                    for (int i = 0; i < nCols; ++i) {
716                        sum += getEntry(row, i) * v.getEntry(i);
717                    }
718                    out[row] = sum;
719                }
720    
721                return new ArrayRealVector(out, false);
722            }
723        }
724    
725        /** {@inheritDoc} */
726        public double[] preMultiply(final double[] v)
727            throws IllegalArgumentException {
728    
729            final int nRows = getRowDimension();
730            final int nCols = getColumnDimension();
731            if (v.length != nRows) {
732                throw MathRuntimeException.createIllegalArgumentException(
733                        LocalizedFormats.VECTOR_LENGTH_MISMATCH,
734                        v.length, nRows);
735            }
736    
737            final double[] out = new double[nCols];
738            for (int col = 0; col < nCols; ++col) {
739                double sum = 0;
740                for (int i = 0; i < nRows; ++i) {
741                    sum += getEntry(i, col) * v[i];
742                }
743                out[col] = sum;
744            }
745    
746            return out;
747    
748        }
749    
750        /** {@inheritDoc} */
751        public RealVector preMultiply(final RealVector v)
752            throws IllegalArgumentException {
753            try {
754                return new ArrayRealVector(preMultiply(((ArrayRealVector) v).getDataRef()), false);
755            } catch (ClassCastException cce) {
756    
757                final int nRows = getRowDimension();
758                final int nCols = getColumnDimension();
759                if (v.getDimension() != nRows) {
760                    throw MathRuntimeException.createIllegalArgumentException(
761                            LocalizedFormats.VECTOR_LENGTH_MISMATCH,
762                            v.getDimension(), nRows);
763                }
764    
765                final double[] out = new double[nCols];
766                for (int col = 0; col < nCols; ++col) {
767                    double sum = 0;
768                    for (int i = 0; i < nRows; ++i) {
769                        sum += getEntry(i, col) * v.getEntry(i);
770                    }
771                    out[col] = sum;
772                }
773    
774                return new ArrayRealVector(out);
775    
776            }
777        }
778    
779        /** {@inheritDoc} */
780        public double walkInRowOrder(final RealMatrixChangingVisitor visitor)
781            throws MatrixVisitorException {
782            final int rows    = getRowDimension();
783            final int columns = getColumnDimension();
784            visitor.start(rows, columns, 0, rows - 1, 0, columns - 1);
785            for (int row = 0; row < rows; ++row) {
786                for (int column = 0; column < columns; ++column) {
787                    final double oldValue = getEntry(row, column);
788                    final double newValue = visitor.visit(row, column, oldValue);
789                    setEntry(row, column, newValue);
790                }
791            }
792            lu = null;
793            return visitor.end();
794        }
795    
796        /** {@inheritDoc} */
797        public double walkInRowOrder(final RealMatrixPreservingVisitor visitor)
798            throws MatrixVisitorException {
799            final int rows    = getRowDimension();
800            final int columns = getColumnDimension();
801            visitor.start(rows, columns, 0, rows - 1, 0, columns - 1);
802            for (int row = 0; row < rows; ++row) {
803                for (int column = 0; column < columns; ++column) {
804                    visitor.visit(row, column, getEntry(row, column));
805                }
806            }
807            return visitor.end();
808        }
809    
810        /** {@inheritDoc} */
811        public double walkInRowOrder(final RealMatrixChangingVisitor visitor,
812                                     final int startRow, final int endRow,
813                                     final int startColumn, final int endColumn)
814            throws MatrixIndexException, MatrixVisitorException {
815            MatrixUtils.checkSubMatrixIndex(this, startRow, endRow, startColumn, endColumn);
816            visitor.start(getRowDimension(), getColumnDimension(),
817                          startRow, endRow, startColumn, endColumn);
818            for (int row = startRow; row <= endRow; ++row) {
819                for (int column = startColumn; column <= endColumn; ++column) {
820                    final double oldValue = getEntry(row, column);
821                    final double newValue = visitor.visit(row, column, oldValue);
822                    setEntry(row, column, newValue);
823                }
824            }
825            lu = null;
826            return visitor.end();
827        }
828    
829        /** {@inheritDoc} */
830        public double walkInRowOrder(final RealMatrixPreservingVisitor visitor,
831                                     final int startRow, final int endRow,
832                                     final int startColumn, final int endColumn)
833            throws MatrixIndexException, MatrixVisitorException {
834            MatrixUtils.checkSubMatrixIndex(this, startRow, endRow, startColumn, endColumn);
835            visitor.start(getRowDimension(), getColumnDimension(),
836                          startRow, endRow, startColumn, endColumn);
837            for (int row = startRow; row <= endRow; ++row) {
838                for (int column = startColumn; column <= endColumn; ++column) {
839                    visitor.visit(row, column, getEntry(row, column));
840                }
841            }
842            return visitor.end();
843        }
844    
845        /** {@inheritDoc} */
846        public double walkInColumnOrder(final RealMatrixChangingVisitor visitor)
847            throws MatrixVisitorException {
848            final int rows    = getRowDimension();
849            final int columns = getColumnDimension();
850            visitor.start(rows, columns, 0, rows - 1, 0, columns - 1);
851            for (int column = 0; column < columns; ++column) {
852                for (int row = 0; row < rows; ++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            lu = null;
859            return visitor.end();
860        }
861    
862        /** {@inheritDoc} */
863        public double walkInColumnOrder(final RealMatrixPreservingVisitor visitor)
864            throws MatrixVisitorException {
865            final int rows    = getRowDimension();
866            final int columns = getColumnDimension();
867            visitor.start(rows, columns, 0, rows - 1, 0, columns - 1);
868            for (int column = 0; column < columns; ++column) {
869                for (int row = 0; row < rows; ++row) {
870                    visitor.visit(row, column, getEntry(row, column));
871                }
872            }
873            return visitor.end();
874        }
875    
876        /** {@inheritDoc} */
877        public double walkInColumnOrder(final RealMatrixChangingVisitor visitor,
878                                        final int startRow, final int endRow,
879                                        final int startColumn, final int endColumn)
880        throws MatrixIndexException, MatrixVisitorException {
881            MatrixUtils.checkSubMatrixIndex(this, startRow, endRow, startColumn, endColumn);
882            visitor.start(getRowDimension(), getColumnDimension(),
883                          startRow, endRow, startColumn, endColumn);
884            for (int column = startColumn; column <= endColumn; ++column) {
885                for (int row = startRow; row <= endRow; ++row) {
886                    final double oldValue = getEntry(row, column);
887                    final double newValue = visitor.visit(row, column, oldValue);
888                    setEntry(row, column, newValue);
889                }
890            }
891            lu = null;
892            return visitor.end();
893        }
894    
895        /** {@inheritDoc} */
896        public double walkInColumnOrder(final RealMatrixPreservingVisitor visitor,
897                                        final int startRow, final int endRow,
898                                        final int startColumn, final int endColumn)
899        throws MatrixIndexException, MatrixVisitorException {
900            MatrixUtils.checkSubMatrixIndex(this, startRow, endRow, startColumn, endColumn);
901            visitor.start(getRowDimension(), getColumnDimension(),
902                          startRow, endRow, startColumn, endColumn);
903            for (int column = startColumn; column <= endColumn; ++column) {
904                for (int row = startRow; row <= endRow; ++row) {
905                    visitor.visit(row, column, getEntry(row, column));
906                }
907            }
908            return visitor.end();
909        }
910    
911        /** {@inheritDoc} */
912        public double walkInOptimizedOrder(final RealMatrixChangingVisitor visitor)
913            throws MatrixVisitorException {
914            return walkInRowOrder(visitor);
915        }
916    
917        /** {@inheritDoc} */
918        public double walkInOptimizedOrder(final RealMatrixPreservingVisitor visitor)
919            throws MatrixVisitorException {
920            return walkInRowOrder(visitor);
921        }
922    
923        /** {@inheritDoc} */
924        public double walkInOptimizedOrder(final RealMatrixChangingVisitor visitor,
925                                           final int startRow, final int endRow,
926                                           final int startColumn, final int endColumn)
927            throws MatrixIndexException, MatrixVisitorException {
928            return walkInRowOrder(visitor, startRow, endRow, startColumn, endColumn);
929        }
930    
931        /** {@inheritDoc} */
932        public double walkInOptimizedOrder(final RealMatrixPreservingVisitor visitor,
933                                           final int startRow, final int endRow,
934                                           final int startColumn, final int endColumn)
935            throws MatrixIndexException, MatrixVisitorException {
936            return walkInRowOrder(visitor, startRow, endRow, startColumn, endColumn);
937        }
938    
939        /** {@inheritDoc} */
940        @Deprecated
941        public double[] solve(final double[] b)
942            throws IllegalArgumentException, InvalidMatrixException {
943            if (lu == null) {
944                lu = new LUDecompositionImpl(this, MathUtils.SAFE_MIN).getSolver();
945            }
946            return lu.solve(b);
947        }
948    
949        /** {@inheritDoc} */
950        @Deprecated
951        public RealMatrix solve(final RealMatrix b)
952            throws IllegalArgumentException, InvalidMatrixException  {
953            if (lu == null) {
954                lu = new LUDecompositionImpl(this, MathUtils.SAFE_MIN).getSolver();
955            }
956            return lu.solve(b);
957        }
958    
959        /**
960         * Computes a new
961         * <a href="http://www.math.gatech.edu/~bourbaki/math2601/Web-notes/2num.pdf">
962         * LU decomposition</a> for this matrix, storing the result for use by other methods.
963         * <p>
964         * <strong>Implementation Note</strong>:<br>
965         * Uses <a href="http://www.damtp.cam.ac.uk/user/fdl/people/sd/lectures/nummeth98/linear.htm">
966         * Crout's algorithm</a>, with partial pivoting.</p>
967         * <p>
968         * <strong>Usage Note</strong>:<br>
969         * This method should rarely be invoked directly. Its only use is
970         * to force recomputation of the LU decomposition when changes have been
971         * made to the underlying data using direct array references. Changes
972         * made using setXxx methods will trigger recomputation when needed
973         * automatically.</p>
974         *
975         * @throws InvalidMatrixException if the matrix is non-square or singular.
976         * @deprecated as of release 2.0, replaced by {@link LUDecomposition}
977         */
978        @Deprecated
979        public void luDecompose()
980            throws InvalidMatrixException {
981            if (lu == null) {
982                lu = new LUDecompositionImpl(this, MathUtils.SAFE_MIN).getSolver();
983            }
984        }
985    
986        /**
987         * Get a string representation for this matrix.
988         * @return a string representation for this matrix
989         */
990        @Override
991        public String toString() {
992            final int nRows = getRowDimension();
993            final int nCols = getColumnDimension();
994            final StringBuilder res = new StringBuilder();
995            String fullClassName = getClass().getName();
996            String shortClassName = fullClassName.substring(fullClassName.lastIndexOf('.') + 1);
997            res.append(shortClassName).append("{");
998    
999            for (int i = 0; i < nRows; ++i) {
1000                if (i > 0) {
1001                    res.append(",");
1002                }
1003                res.append("{");
1004                for (int j = 0; j < nCols; ++j) {
1005                    if (j > 0) {
1006                        res.append(",");
1007                    }
1008                    res.append(getEntry(i, j));
1009                }
1010                res.append("}");
1011            }
1012    
1013            res.append("}");
1014            return res.toString();
1015    
1016        }
1017    
1018        /**
1019         * Returns true iff <code>object</code> is a
1020         * <code>RealMatrix</code> instance with the same dimensions as this
1021         * and all corresponding matrix entries are equal.
1022         *
1023         * @param object the object to test equality against.
1024         * @return true if object equals this
1025         */
1026        @Override
1027        public boolean equals(final Object object) {
1028            if (object == this ) {
1029                return true;
1030            }
1031            if (object instanceof RealMatrix == false) {
1032                return false;
1033            }
1034            RealMatrix m = (RealMatrix) object;
1035            final int nRows = getRowDimension();
1036            final int nCols = getColumnDimension();
1037            if (m.getColumnDimension() != nCols || m.getRowDimension() != nRows) {
1038                return false;
1039            }
1040            for (int row = 0; row < nRows; ++row) {
1041                for (int col = 0; col < nCols; ++col) {
1042                    if (getEntry(row, col) != m.getEntry(row, col)) {
1043                        return false;
1044                    }
1045                }
1046            }
1047            return true;
1048        }
1049    
1050        /**
1051         * Computes a hashcode for the matrix.
1052         *
1053         * @return hashcode for matrix
1054         */
1055        @Override
1056        public int hashCode() {
1057            int ret = 7;
1058            final int nRows = getRowDimension();
1059            final int nCols = getColumnDimension();
1060            ret = ret * 31 + nRows;
1061            ret = ret * 31 + nCols;
1062            for (int row = 0; row < nRows; ++row) {
1063                for (int col = 0; col < nCols; ++col) {
1064                   ret = ret * 31 + (11 * (row+1) + 17 * (col+1)) *
1065                       MathUtils.hash(getEntry(row, col));
1066               }
1067            }
1068            return ret;
1069        }
1070    
1071    }