1/*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements.  See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License.  You may obtain a copy of the License at
8 *
9 *      http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18package org.apache.commons.math.linear;
19
20import java.io.Serializable;
21
22import org.apache.commons.math.MathRuntimeException;
23import org.apache.commons.math.linear.MatrixVisitorException;
24import org.apache.commons.math.exception.util.LocalizedFormats;
25
26/**
27 * Implementation of RealMatrix using a double[][] array to store entries and
28 * <a href="http://www.math.gatech.edu/~bourbaki/math2601/Web-notes/2num.pdf">
29 * LU decomposition</a> to support linear system
30 * solution and inverse.
31 * <p>
32 * The LU decomposition is performed as needed, to support the following operations: <ul>
33 * <li>solve</li>
34 * <li>isSingular</li>
35 * <li>getDeterminant</li>
36 * <li>inverse</li> </ul></p>
37 * <p>
38 * <strong>Usage notes</strong>:<br>
39 * <ul><li>
40 * The LU decomposition is cached and reused on subsequent calls.
41 * If data are modified via references to the underlying array obtained using
42 * <code>getDataRef()</code>, then the stored LU decomposition will not be
43 * discarded.  In this case, you need to explicitly invoke
44 * <code>LUDecompose()</code> to recompute the decomposition
45 * before using any of the methods above.</li>
46 * <li>
47 * As specified in the {@link RealMatrix} interface, matrix element indexing
48 * is 0-based -- e.g., <code>getEntry(0, 0)</code>
49 * returns the element in the first row, first column of the matrix.</li></ul>
50 * </p>
51 *
52 * @version $Revision: 1073158 $ $Date: 2011-02-21 22:46:52 +0100 (lun. 21 févr. 2011) $
53 * @deprecated as of 2.0 replaced by {@link Array2DRowRealMatrix}
54 */
55@Deprecated
56public class RealMatrixImpl extends AbstractRealMatrix implements Serializable {
57
58    /** Serializable version identifier */
59    private static final long serialVersionUID = -1067294169172445528L;
60
61    /** Entries of the matrix */
62    protected double data[][];
63
64    /**
65     * Creates a matrix with no data
66     */
67    public RealMatrixImpl() {
68    }
69
70    /**
71     * Create a new RealMatrix with the supplied row and column dimensions.
72     *
73     * @param rowDimension  the number of rows in the new matrix
74     * @param columnDimension  the number of columns in the new matrix
75     * @throws IllegalArgumentException if row or column dimension is not
76     *  positive
77     */
78    public RealMatrixImpl(final int rowDimension, final int columnDimension)
79        throws IllegalArgumentException {
80        super(rowDimension, columnDimension);
81        data = new double[rowDimension][columnDimension];
82    }
83
84    /**
85     * Create a new RealMatrix using the input array as the underlying
86     * data array.
87     * <p>The input array is copied, not referenced. This constructor has
88     * the same effect as calling {@link #RealMatrixImpl(double[][], boolean)}
89     * with the second argument set to <code>true</code>.</p>
90     *
91     * @param d data for new matrix
92     * @throws IllegalArgumentException if <code>d</code> is not rectangular
93     *  (not all rows have the same length) or empty
94     * @throws NullPointerException if <code>d</code> is null
95     * @see #RealMatrixImpl(double[][], boolean)
96     */
97    public RealMatrixImpl(final double[][] d)
98        throws IllegalArgumentException, NullPointerException {
99        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}
630