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.io.Serializable;
021    
022    import org.apache.commons.math.MathRuntimeException;
023    import org.apache.commons.math.linear.MatrixVisitorException;
024    import org.apache.commons.math.exception.util.LocalizedFormats;
025    
026    /**
027     * Implementation of RealMatrix using a double[][] array to store entries and
028     * <a href="http://www.math.gatech.edu/~bourbaki/math2601/Web-notes/2num.pdf">
029     * LU decomposition</a> to support linear system
030     * solution and inverse.
031     * <p>
032     * The LU decomposition is performed as needed, to support the following operations: <ul>
033     * <li>solve</li>
034     * <li>isSingular</li>
035     * <li>getDeterminant</li>
036     * <li>inverse</li> </ul></p>
037     * <p>
038     * <strong>Usage notes</strong>:<br>
039     * <ul><li>
040     * The LU decomposition is cached and reused on subsequent calls.
041     * If data are modified via references to the underlying array obtained using
042     * <code>getDataRef()</code>, then the stored LU decomposition will not be
043     * discarded.  In this case, you need to explicitly invoke
044     * <code>LUDecompose()</code> to recompute the decomposition
045     * before using any of the methods above.</li>
046     * <li>
047     * As specified in the {@link RealMatrix} interface, matrix element indexing
048     * is 0-based -- e.g., <code>getEntry(0, 0)</code>
049     * returns the element in the first row, first column of the matrix.</li></ul>
050     * </p>
051     *
052     * @version $Revision: 1073158 $ $Date: 2011-02-21 22:46:52 +0100 (lun. 21 f??vr. 2011) $
053     * @deprecated as of 2.0 replaced by {@link Array2DRowRealMatrix}
054     */
055    @Deprecated
056    public class RealMatrixImpl extends AbstractRealMatrix implements Serializable {
057    
058        /** Serializable version identifier */
059        private static final long serialVersionUID = -1067294169172445528L;
060    
061        /** Entries of the matrix */
062        protected double data[][];
063    
064        /**
065         * Creates a matrix with no data
066         */
067        public RealMatrixImpl() {
068        }
069    
070        /**
071         * Create a new RealMatrix with the supplied row and column dimensions.
072         *
073         * @param rowDimension  the number of rows in the new matrix
074         * @param columnDimension  the number of columns in the new matrix
075         * @throws IllegalArgumentException if row or column dimension is not
076         *  positive
077         */
078        public RealMatrixImpl(final int rowDimension, final int columnDimension)
079            throws IllegalArgumentException {
080            super(rowDimension, columnDimension);
081            data = new double[rowDimension][columnDimension];
082        }
083    
084        /**
085         * Create a new RealMatrix using the input array as the underlying
086         * data array.
087         * <p>The input array is copied, not referenced. This constructor has
088         * the same effect as calling {@link #RealMatrixImpl(double[][], boolean)}
089         * with the second argument set to <code>true</code>.</p>
090         *
091         * @param d data for new matrix
092         * @throws IllegalArgumentException if <code>d</code> is not rectangular
093         *  (not all rows have the same length) or empty
094         * @throws NullPointerException if <code>d</code> is null
095         * @see #RealMatrixImpl(double[][], boolean)
096         */
097        public RealMatrixImpl(final double[][] d)
098            throws IllegalArgumentException, NullPointerException {
099            copyIn(d);
100        }
101    
102        /**
103         * Create a new RealMatrix using the input array as the underlying
104         * data array.
105         * <p>If an array is built specially in order to be embedded in a
106         * RealMatrix and not used directly, the <code>copyArray</code> may be
107         * set to <code>false</code. This will prevent the copying and improve
108         * performance as no new array will be built and no data will be copied.</p>
109         * @param d data for new matrix
110         * @param copyArray if true, the input array will be copied, otherwise
111         * it will be referenced
112         * @throws IllegalArgumentException if <code>d</code> is not rectangular
113         *  (not all rows have the same length) or empty
114         * @throws NullPointerException if <code>d</code> is null
115         * @see #RealMatrixImpl(double[][])
116         */
117        public RealMatrixImpl(final double[][] d, final boolean copyArray)
118            throws IllegalArgumentException, NullPointerException {
119            if (copyArray) {
120                copyIn(d);
121            } else {
122                if (d == null) {
123                    throw new NullPointerException();
124                }
125                final int nRows = d.length;
126                if (nRows == 0) {
127                    throw MathRuntimeException.createIllegalArgumentException(LocalizedFormats.AT_LEAST_ONE_ROW);
128                }
129                final int nCols = d[0].length;
130                if (nCols == 0) {
131                    throw MathRuntimeException.createIllegalArgumentException(LocalizedFormats.AT_LEAST_ONE_COLUMN);
132                }
133                for (int r = 1; r < nRows; r++) {
134                    if (d[r].length != nCols) {
135                        throw MathRuntimeException.createIllegalArgumentException(
136                                LocalizedFormats.DIFFERENT_ROWS_LENGTHS,
137                                nCols, d[r].length);
138                    }
139                }
140                data = d;
141            }
142        }
143    
144        /**
145         * Create a new (column) RealMatrix using <code>v</code> as the
146         * data for the unique column of the <code>v.length x 1</code> matrix
147         * created.
148         * <p>The input array is copied, not referenced.</p>
149         *
150         * @param v column vector holding data for new matrix
151         */
152        public RealMatrixImpl(final double[] v) {
153            final int nRows = v.length;
154            data = new double[nRows][1];
155            for (int row = 0; row < nRows; row++) {
156                data[row][0] = v[row];
157            }
158        }
159    
160        /** {@inheritDoc} */
161        @Override
162        public RealMatrix createMatrix(final int rowDimension, final int columnDimension)
163            throws IllegalArgumentException {
164            return new RealMatrixImpl(rowDimension, columnDimension);
165        }
166    
167        /** {@inheritDoc} */
168        @Override
169        public RealMatrix copy() {
170            return new RealMatrixImpl(copyOut(), false);
171        }
172    
173        /** {@inheritDoc} */
174        @Override
175        public RealMatrix add(final RealMatrix m)
176            throws IllegalArgumentException {
177            try {
178                return add((RealMatrixImpl) m);
179            } catch (ClassCastException cce) {
180                return super.add(m);
181            }
182        }
183    
184        /**
185         * Compute the sum of this and <code>m</code>.
186         *
187         * @param m    matrix to be added
188         * @return     this + m
189         * @throws  IllegalArgumentException if m is not the same size as this
190         */
191        public RealMatrixImpl add(final RealMatrixImpl m)
192            throws IllegalArgumentException {
193    
194            // safety check
195            MatrixUtils.checkAdditionCompatible(this, m);
196    
197            final int rowCount    = getRowDimension();
198            final int columnCount = getColumnDimension();
199            final double[][] outData = new double[rowCount][columnCount];
200            for (int row = 0; row < rowCount; row++) {
201                final double[] dataRow    = data[row];
202                final double[] mRow       = m.data[row];
203                final double[] outDataRow = outData[row];
204                for (int col = 0; col < columnCount; col++) {
205                    outDataRow[col] = dataRow[col] + mRow[col];
206                }
207            }
208    
209            return new RealMatrixImpl(outData, false);
210    
211        }
212    
213        /** {@inheritDoc} */
214        @Override
215        public RealMatrix subtract(final RealMatrix m)
216            throws IllegalArgumentException {
217            try {
218                return subtract((RealMatrixImpl) m);
219            } catch (ClassCastException cce) {
220                return super.subtract(m);
221            }
222        }
223    
224        /**
225         * Compute  this minus <code>m</code>.
226         *
227         * @param m    matrix to be subtracted
228         * @return     this + m
229         * @throws  IllegalArgumentException if m is not the same size as this
230         */
231        public RealMatrixImpl subtract(final RealMatrixImpl m)
232            throws IllegalArgumentException {
233    
234            // safety check
235            MatrixUtils.checkSubtractionCompatible(this, m);
236    
237            final int rowCount    = getRowDimension();
238            final int columnCount = getColumnDimension();
239            final double[][] outData = new double[rowCount][columnCount];
240            for (int row = 0; row < rowCount; row++) {
241                final double[] dataRow    = data[row];
242                final double[] mRow       = m.data[row];
243                final double[] outDataRow = outData[row];
244                for (int col = 0; col < columnCount; col++) {
245                    outDataRow[col] = dataRow[col] - mRow[col];
246                }
247            }
248    
249            return new RealMatrixImpl(outData, false);
250    
251        }
252    
253        /** {@inheritDoc} */
254        @Override
255        public RealMatrix multiply(final RealMatrix m)
256            throws IllegalArgumentException {
257            try {
258                return multiply((RealMatrixImpl) m);
259            } catch (ClassCastException cce) {
260                return super.multiply(m);
261            }
262        }
263    
264        /**
265         * Returns the result of postmultiplying this by <code>m</code>.
266         * @param m    matrix to postmultiply by
267         * @return     this*m
268         * @throws     IllegalArgumentException
269         *             if columnDimension(this) != rowDimension(m)
270         */
271        public RealMatrixImpl multiply(final RealMatrixImpl m)
272            throws IllegalArgumentException {
273    
274            // safety check
275            MatrixUtils.checkMultiplicationCompatible(this, m);
276    
277            final int nRows = this.getRowDimension();
278            final int nCols = m.getColumnDimension();
279            final int nSum = this.getColumnDimension();
280            final double[][] outData = new double[nRows][nCols];
281            for (int row = 0; row < nRows; row++) {
282                final double[] dataRow    = data[row];
283                final double[] outDataRow = outData[row];
284                for (int col = 0; col < nCols; col++) {
285                    double sum = 0;
286                    for (int i = 0; i < nSum; i++) {
287                        sum += dataRow[i] * m.data[i][col];
288                    }
289                    outDataRow[col] = sum;
290                }
291            }
292    
293            return new RealMatrixImpl(outData, false);
294    
295        }
296    
297        /** {@inheritDoc} */
298        @Override
299        public double[][] getData() {
300            return copyOut();
301        }
302    
303        /**
304         * Returns a reference to the underlying data array.
305         * <p>
306         * Does <strong>not</strong> make a fresh copy of the underlying data.</p>
307         *
308         * @return 2-dimensional array of entries
309         */
310        public double[][] getDataRef() {
311            return data;
312        }
313    
314        /** {@inheritDoc} */
315        @Override
316        public void setSubMatrix(final double[][] subMatrix, final int row, final int column)
317        throws MatrixIndexException {
318            if (data == null) {
319                if (row > 0) {
320                    throw MathRuntimeException.createIllegalStateException(
321                            LocalizedFormats.FIRST_ROWS_NOT_INITIALIZED_YET,
322                            row);
323                }
324                if (column > 0) {
325                    throw MathRuntimeException.createIllegalStateException(
326                            LocalizedFormats.FIRST_COLUMNS_NOT_INITIALIZED_YET,
327                            column);
328                }
329                final int nRows = subMatrix.length;
330                if (nRows == 0) {
331                    throw MathRuntimeException.createIllegalArgumentException(LocalizedFormats.AT_LEAST_ONE_ROW);
332                }
333    
334                final int nCols = subMatrix[0].length;
335                if (nCols == 0) {
336                    throw MathRuntimeException.createIllegalArgumentException(LocalizedFormats.AT_LEAST_ONE_COLUMN);
337                }
338                data = new double[subMatrix.length][nCols];
339                for (int i = 0; i < data.length; ++i) {
340                    if (subMatrix[i].length != nCols) {
341                        throw MathRuntimeException.createIllegalArgumentException(
342                                LocalizedFormats.DIFFERENT_ROWS_LENGTHS,
343                                nCols, subMatrix[i].length);
344                    }
345                    System.arraycopy(subMatrix[i], 0, data[i + row], column, nCols);
346                }
347            } else {
348                super.setSubMatrix(subMatrix, row, column);
349            }
350    
351        }
352    
353        /** {@inheritDoc} */
354        @Override
355        public double getEntry(final int row, final int column)
356            throws MatrixIndexException {
357            try {
358                return data[row][column];
359            } catch (ArrayIndexOutOfBoundsException e) {
360                throw new MatrixIndexException(
361                        LocalizedFormats.NO_SUCH_MATRIX_ENTRY,
362                        row, column, getRowDimension(), getColumnDimension());
363            }
364        }
365    
366        /** {@inheritDoc} */
367        @Override
368        public void setEntry(final int row, final int column, final double value)
369            throws MatrixIndexException {
370            try {
371                data[row][column] = value;
372            } catch (ArrayIndexOutOfBoundsException e) {
373                throw new MatrixIndexException(
374                        LocalizedFormats.NO_SUCH_MATRIX_ENTRY,
375                        row, column, getRowDimension(), getColumnDimension());
376            }
377        }
378    
379        /** {@inheritDoc} */
380        @Override
381        public void addToEntry(final int row, final int column, final double increment)
382            throws MatrixIndexException {
383            try {
384                data[row][column] += increment;
385            } catch (ArrayIndexOutOfBoundsException e) {
386                throw new MatrixIndexException(
387                        LocalizedFormats.NO_SUCH_MATRIX_ENTRY,
388                        row, column, getRowDimension(), getColumnDimension());
389            }
390        }
391    
392        /** {@inheritDoc} */
393        @Override
394        public void multiplyEntry(final int row, final int column, final double factor)
395            throws MatrixIndexException {
396            try {
397                data[row][column] *= factor;
398            } catch (ArrayIndexOutOfBoundsException e) {
399                throw new MatrixIndexException(
400                        LocalizedFormats.NO_SUCH_MATRIX_ENTRY,
401                        row, column, getRowDimension(), getColumnDimension());
402            }
403        }
404    
405        /** {@inheritDoc} */
406        @Override
407        public int getRowDimension() {
408            return (data == null) ? 0 : data.length;
409        }
410    
411        /** {@inheritDoc} */
412        @Override
413        public int getColumnDimension() {
414            return ((data == null) || (data[0] == null)) ? 0 : data[0].length;
415        }
416    
417        /** {@inheritDoc} */
418        @Override
419        public double[] operate(final double[] v)
420            throws IllegalArgumentException {
421            final int nRows = this.getRowDimension();
422            final int nCols = this.getColumnDimension();
423            if (v.length != nCols) {
424                throw MathRuntimeException.createIllegalArgumentException(
425                        LocalizedFormats.VECTOR_LENGTH_MISMATCH,
426                        v.length, nCols);
427            }
428            final double[] out = new double[nRows];
429            for (int row = 0; row < nRows; row++) {
430                final double[] dataRow = data[row];
431                double sum = 0;
432                for (int i = 0; i < nCols; i++) {
433                    sum += dataRow[i] * v[i];
434                }
435                out[row] = sum;
436            }
437            return out;
438        }
439    
440        /** {@inheritDoc} */
441        @Override
442        public double[] preMultiply(final double[] v)
443            throws IllegalArgumentException {
444    
445            final int nRows = getRowDimension();
446            final int nCols = getColumnDimension();
447            if (v.length != nRows) {
448                throw MathRuntimeException.createIllegalArgumentException(
449                        LocalizedFormats.VECTOR_LENGTH_MISMATCH,
450                        v.length, nRows);
451            }
452    
453            final double[] out = new double[nCols];
454            for (int col = 0; col < nCols; ++col) {
455                double sum = 0;
456                for (int i = 0; i < nRows; ++i) {
457                    sum += data[i][col] * v[i];
458                }
459                out[col] = sum;
460            }
461    
462            return out;
463    
464        }
465    
466        /** {@inheritDoc} */
467        @Override
468        public double walkInRowOrder(final RealMatrixChangingVisitor visitor)
469            throws MatrixVisitorException {
470            final int rows    = getRowDimension();
471            final int columns = getColumnDimension();
472            visitor.start(rows, columns, 0, rows - 1, 0, columns - 1);
473            for (int i = 0; i < rows; ++i) {
474                final double[] rowI = data[i];
475                for (int j = 0; j < columns; ++j) {
476                    rowI[j] = visitor.visit(i, j, rowI[j]);
477                }
478            }
479            return visitor.end();
480        }
481    
482        /** {@inheritDoc} */
483        @Override
484        public double walkInRowOrder(final RealMatrixPreservingVisitor visitor)
485            throws MatrixVisitorException {
486            final int rows    = getRowDimension();
487            final int columns = getColumnDimension();
488            visitor.start(rows, columns, 0, rows - 1, 0, columns - 1);
489            for (int i = 0; i < rows; ++i) {
490                final double[] rowI = data[i];
491                for (int j = 0; j < columns; ++j) {
492                    visitor.visit(i, j, rowI[j]);
493                }
494            }
495            return visitor.end();
496        }
497    
498        /** {@inheritDoc} */
499        @Override
500        public double walkInRowOrder(final RealMatrixChangingVisitor visitor,
501                                     final int startRow, final int endRow,
502                                     final int startColumn, final int endColumn)
503            throws MatrixIndexException, MatrixVisitorException {
504            MatrixUtils.checkSubMatrixIndex(this, startRow, endRow, startColumn, endColumn);
505            visitor.start(getRowDimension(), getColumnDimension(),
506                          startRow, endRow, startColumn, endColumn);
507            for (int i = startRow; i <= endRow; ++i) {
508                final double[] rowI = data[i];
509                for (int j = startColumn; j <= endColumn; ++j) {
510                    rowI[j] = visitor.visit(i, j, rowI[j]);
511                }
512            }
513            return visitor.end();
514        }
515    
516        /** {@inheritDoc} */
517        @Override
518        public double walkInRowOrder(final RealMatrixPreservingVisitor visitor,
519                                     final int startRow, final int endRow,
520                                     final int startColumn, final int endColumn)
521            throws MatrixIndexException, MatrixVisitorException {
522            MatrixUtils.checkSubMatrixIndex(this, startRow, endRow, startColumn, endColumn);
523            visitor.start(getRowDimension(), getColumnDimension(),
524                          startRow, endRow, startColumn, endColumn);
525            for (int i = startRow; i <= endRow; ++i) {
526                final double[] rowI = data[i];
527                for (int j = startColumn; j <= endColumn; ++j) {
528                    visitor.visit(i, j, rowI[j]);
529                }
530            }
531            return visitor.end();
532        }
533    
534        /** {@inheritDoc} */
535        @Override
536        public double walkInColumnOrder(final RealMatrixChangingVisitor visitor)
537            throws MatrixVisitorException {
538            final int rows    = getRowDimension();
539            final int columns = getColumnDimension();
540            visitor.start(rows, columns, 0, rows - 1, 0, columns - 1);
541            for (int j = 0; j < columns; ++j) {
542                for (int i = 0; i < rows; ++i) {
543                    final double[] rowI = data[i];
544                    rowI[j] = visitor.visit(i, j, rowI[j]);
545                }
546            }
547            return visitor.end();
548        }
549    
550        /** {@inheritDoc} */
551        @Override
552        public double walkInColumnOrder(final RealMatrixPreservingVisitor visitor)
553            throws MatrixVisitorException {
554            final int rows    = getRowDimension();
555            final int columns = getColumnDimension();
556            visitor.start(rows, columns, 0, rows - 1, 0, columns - 1);
557            for (int j = 0; j < columns; ++j) {
558                for (int i = 0; i < rows; ++i) {
559                    visitor.visit(i, j, data[i][j]);
560                }
561            }
562            return visitor.end();
563        }
564    
565        /** {@inheritDoc} */
566        @Override
567        public double walkInColumnOrder(final RealMatrixChangingVisitor visitor,
568                                        final int startRow, final int endRow,
569                                        final int startColumn, final int endColumn)
570            throws MatrixIndexException, MatrixVisitorException {
571            MatrixUtils.checkSubMatrixIndex(this, startRow, endRow, startColumn, endColumn);
572            visitor.start(getRowDimension(), getColumnDimension(),
573                          startRow, endRow, startColumn, endColumn);
574            for (int j = startColumn; j <= endColumn; ++j) {
575                for (int i = startRow; i <= endRow; ++i) {
576                    final double[] rowI = data[i];
577                    rowI[j] = visitor.visit(i, j, rowI[j]);
578                }
579            }
580            return visitor.end();
581        }
582    
583        /** {@inheritDoc} */
584        @Override
585        public double walkInColumnOrder(final RealMatrixPreservingVisitor visitor,
586                                        final int startRow, final int endRow,
587                                        final int startColumn, final int endColumn)
588            throws MatrixIndexException, MatrixVisitorException {
589            MatrixUtils.checkSubMatrixIndex(this, startRow, endRow, startColumn, endColumn);
590            visitor.start(getRowDimension(), getColumnDimension(),
591                          startRow, endRow, startColumn, endColumn);
592            for (int j = startColumn; j <= endColumn; ++j) {
593                for (int i = startRow; i <= endRow; ++i) {
594                    visitor.visit(i, j, data[i][j]);
595                }
596            }
597            return visitor.end();
598        }
599    
600        /**
601         * Returns a fresh copy of the underlying data array.
602         *
603         * @return a copy of the underlying data array.
604         */
605        private double[][] copyOut() {
606            final int nRows = this.getRowDimension();
607            final double[][] out = new double[nRows][this.getColumnDimension()];
608            // can't copy 2-d array in one shot, otherwise get row references
609            for (int i = 0; i < nRows; i++) {
610                System.arraycopy(data[i], 0, out[i], 0, data[i].length);
611            }
612            return out;
613        }
614    
615        /**
616         * Replaces data with a fresh copy of the input array.
617         * <p>
618         * Verifies that the input array is rectangular and non-empty.</p>
619         *
620         * @param in data to copy in
621         * @throws IllegalArgumentException if input array is empty or not
622         *    rectangular
623         * @throws NullPointerException if input array is null
624         */
625        private void copyIn(final double[][] in) {
626            setSubMatrix(in, 0, 0);
627        }
628    
629    }