Home | History | Annotate | Download | only in linear
      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 
     18 package org.apache.commons.math.linear;
     19 
     20 import java.io.Serializable;
     21 
     22 import org.apache.commons.math.MathRuntimeException;
     23 import org.apache.commons.math.linear.MatrixVisitorException;
     24 import 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 fvr. 2011) $
     53  * @deprecated as of 2.0 replaced by {@link Array2DRowRealMatrix}
     54  */
     55 @Deprecated
     56 public 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