View Javadoc

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.exception.DimensionMismatchException;
23  import org.apache.commons.math.exception.NullArgumentException;
24  import org.apache.commons.math.exception.NoDataException;
25  import org.apache.commons.math.exception.MathIllegalStateException;
26  import org.apache.commons.math.exception.util.LocalizedFormats;
27  import org.apache.commons.math.util.MathUtils;
28  
29  /**
30   * Implementation of {@link RealMatrix} using a {@code double[][]} array to
31   * store entries.
32   *
33   * @version $Id: Array2DRowRealMatrix.java 1178186 2011-10-02 13:00:41Z erans $
34   */
35  public class Array2DRowRealMatrix extends AbstractRealMatrix implements Serializable {
36      /** Serializable version identifier. */
37      private static final long serialVersionUID = -1067294169172445528L;
38      /** Entries of the matrix. */
39      protected double data[][];
40  
41      /**
42       * Creates a matrix with no data
43       */
44      public Array2DRowRealMatrix() {}
45  
46      /**
47       * Create a new RealMatrix with the supplied row and column dimensions.
48       *
49       * @param rowDimension Number of rows in the new matrix.
50       * @param columnDimension Number of columns in the new matrix.
51       * @throws org.apache.commons.math.exception.NotStrictlyPositiveException
52       * if the row or column dimension is not positive.
53       */
54      public Array2DRowRealMatrix(final int rowDimension, final int columnDimension) {
55          super(rowDimension, columnDimension);
56          data = new double[rowDimension][columnDimension];
57      }
58  
59      /**
60       * Create a new {@code RealMatrix} using the input array as the underlying
61       * data array.
62       * <p>The input array is copied, not referenced. This constructor has
63       * the same effect as calling {@link #Array2DRowRealMatrix(double[][], boolean)}
64       * with the second argument set to {@code true}.</p>
65       *
66       * @param d Data for the new matrix.
67       * @throws DimensionMismatchException if {@code d} is not rectangular.
68       * @throws NoDataException if {@code d} row or colum dimension is zero.
69       * @throws NullArgumentException if {@code d} is {@code null}.
70       * @see #Array2DRowRealMatrix(double[][], boolean)
71       */
72      public Array2DRowRealMatrix(final double[][] d)
73          throws DimensionMismatchException, NoDataException, NullArgumentException {
74          copyIn(d);
75      }
76  
77      /**
78       * Create a new RealMatrix using the input array as the underlying
79       * data array.
80       * If an array is built specially in order to be embedded in a
81       * RealMatrix and not used directly, the {@code copyArray} may be
82       * set to {@code false}. This will prevent the copying and improve
83       * performance as no new array will be built and no data will be copied.
84       *
85       * @param d Data for new matrix.
86       * @param copyArray if {@code true}, the input array will be copied,
87       * otherwise it will be referenced.
88       * @throws DimensionMismatchException if {@code d} is not rectangular
89       * (not all rows have the same length) or empty.
90       * @throws NullArgumentException if {@code d} is {@code null}.
91       * @throws NoDataException if there are not at least one row and one column.
92       * @see #Array2DRowRealMatrix(double[][])
93       */
94      public Array2DRowRealMatrix(final double[][] d, final boolean copyArray) {
95          if (copyArray) {
96              copyIn(d);
97          } else {
98              if (d == null) {
99                  throw new NullArgumentException();
100             }
101             final int nRows = d.length;
102             if (nRows == 0) {
103                 throw new NoDataException(LocalizedFormats.AT_LEAST_ONE_ROW);
104             }
105             final int nCols = d[0].length;
106             if (nCols == 0) {
107                 throw new NoDataException(LocalizedFormats.AT_LEAST_ONE_COLUMN);
108             }
109             for (int r = 1; r < nRows; r++) {
110                 if (d[r].length != nCols) {
111                     throw new DimensionMismatchException(d[r].length, nCols);
112                 }
113             }
114             data = d;
115         }
116     }
117 
118     /**
119      * Create a new (column) RealMatrix using {@code v} as the
120      * data for the unique column of the created matrix.
121      * The input array is copied.
122      *
123      * @param v Column vector holding data for new matrix.
124      */
125     public Array2DRowRealMatrix(final double[] v) {
126         final int nRows = v.length;
127         data = new double[nRows][1];
128         for (int row = 0; row < nRows; row++) {
129             data[row][0] = v[row];
130         }
131     }
132 
133     /** {@inheritDoc} */
134     @Override
135     public RealMatrix createMatrix(final int rowDimension,
136                                    final int columnDimension) {
137         return new Array2DRowRealMatrix(rowDimension, columnDimension);
138     }
139 
140     /** {@inheritDoc} */
141     @Override
142     public RealMatrix copy() {
143         return new Array2DRowRealMatrix(copyOut(), false);
144     }
145 
146     /**
147      * Compute the sum of this matrix with {@code m}.
148      *
149      * @param m Matrix to be added.
150      * @return {@code this} + m.
151      * @throws MatrixDimensionMismatchException
152      * if {@code m} is not the same size as this matrix.
153      */
154     public Array2DRowRealMatrix add(final Array2DRowRealMatrix m) {
155         // Safety check.
156         MatrixUtils.checkAdditionCompatible(this, m);
157 
158         final int rowCount    = getRowDimension();
159         final int columnCount = getColumnDimension();
160         final double[][] outData = new double[rowCount][columnCount];
161         for (int row = 0; row < rowCount; row++) {
162             final double[] dataRow    = data[row];
163             final double[] mRow       = m.data[row];
164             final double[] outDataRow = outData[row];
165             for (int col = 0; col < columnCount; col++) {
166                 outDataRow[col] = dataRow[col] + mRow[col];
167             }
168         }
169 
170         return new Array2DRowRealMatrix(outData, false);
171     }
172 
173     /**
174      * Subtract {@code m} from this matrix.
175      *
176      * @param m Matrix to be subtracted.
177      * @return {@code this} - m.
178      * @throws MatrixDimensionMismatchException
179      * if {@code m} is not the same size as this matrix.
180      */
181     public Array2DRowRealMatrix subtract(final Array2DRowRealMatrix m) {
182         // Safety check.
183         MatrixUtils.checkSubtractionCompatible(this, m);
184 
185         final int rowCount    = getRowDimension();
186         final int columnCount = getColumnDimension();
187         final double[][] outData = new double[rowCount][columnCount];
188         for (int row = 0; row < rowCount; row++) {
189             final double[] dataRow    = data[row];
190             final double[] mRow       = m.data[row];
191             final double[] outDataRow = outData[row];
192             for (int col = 0; col < columnCount; col++) {
193                 outDataRow[col] = dataRow[col] - mRow[col];
194             }
195         }
196 
197         return new Array2DRowRealMatrix(outData, false);
198     }
199 
200     /**
201      * Postmultiplying this matrix by {@code m}.
202      *
203      * @param m Matrix to postmultiply by.
204      * @return {@code this} * m.
205      * @throws DimensionMismatchException if the number of columns of this
206      * matrix is not equal to the number of rows of {@code m}.
207      */
208     public Array2DRowRealMatrix multiply(final Array2DRowRealMatrix m) {
209         // Safety check.
210         MatrixUtils.checkMultiplicationCompatible(this, m);
211 
212         final int nRows = this.getRowDimension();
213         final int nCols = m.getColumnDimension();
214         final int nSum = this.getColumnDimension();
215 
216         final double[][] outData = new double[nRows][nCols];
217         // Will hold a column of "m".
218         final double[] mCol = new double[nSum];
219         final double[][] mData = m.data;
220 
221         // Multiply.
222         for (int col = 0; col < nCols; col++) {
223             // Copy all elements of column "col" of "m" so that
224             // will be in contiguous memory.
225             for (int mRow = 0; mRow < nSum; mRow++) {
226                 mCol[mRow] = mData[mRow][col];
227             }
228 
229             for (int row = 0; row < nRows; row++) {
230                 final double[] dataRow = data[row];
231                 double sum = 0;
232                 for (int i = 0; i < nSum; i++) {
233                     sum += dataRow[i] * mCol[i];
234                 }
235                 outData[row][col] = sum;
236             }
237         }
238 
239         return new Array2DRowRealMatrix(outData, false);
240     }
241 
242     /** {@inheritDoc} */
243     @Override
244     public double[][] getData() {
245         return copyOut();
246     }
247 
248     /**
249      * Get a reference to the underlying data array.
250      *
251      * @return 2-dimensional array of entries.
252      */
253     public double[][] getDataRef() {
254         return data;
255     }
256 
257     /** {@inheritDoc} */
258     @Override
259     public void setSubMatrix(final double[][] subMatrix,
260                              final int row, final int column) {
261         if (data == null) {
262             if (row > 0) {
263                 throw new MathIllegalStateException(LocalizedFormats.FIRST_ROWS_NOT_INITIALIZED_YET, row);
264             }
265             if (column > 0) {
266                 throw new MathIllegalStateException(LocalizedFormats.FIRST_COLUMNS_NOT_INITIALIZED_YET, column);
267             }
268             MathUtils.checkNotNull(subMatrix);
269             final int nRows = subMatrix.length;
270             if (nRows == 0) {
271                 throw new NoDataException(LocalizedFormats.AT_LEAST_ONE_ROW);
272             }
273 
274             final int nCols = subMatrix[0].length;
275             if (nCols == 0) {
276                 throw new NoDataException(LocalizedFormats.AT_LEAST_ONE_COLUMN);
277             }
278             data = new double[subMatrix.length][nCols];
279             for (int i = 0; i < data.length; ++i) {
280                 if (subMatrix[i].length != nCols) {
281                     throw new DimensionMismatchException(subMatrix[i].length, nCols);
282                 }
283                 System.arraycopy(subMatrix[i], 0, data[i + row], column, nCols);
284             }
285         } else {
286             super.setSubMatrix(subMatrix, row, column);
287         }
288 
289     }
290 
291     /** {@inheritDoc} */
292     @Override
293     public double getEntry(final int row, final int column) {
294         MatrixUtils.checkMatrixIndex(this, row, column);
295         return data[row][column];
296     }
297 
298     /** {@inheritDoc} */
299     @Override
300     public void setEntry(final int row, final int column, final double value) {
301         MatrixUtils.checkMatrixIndex(this, row, column);
302         data[row][column] = value;
303     }
304 
305     /** {@inheritDoc} */
306     @Override
307     public void addToEntry(final int row, final int column, final double increment) {
308         MatrixUtils.checkMatrixIndex(this, row, column);
309         data[row][column] += increment;
310     }
311 
312     /** {@inheritDoc} */
313     @Override
314     public void multiplyEntry(final int row, final int column, final double factor) {
315         MatrixUtils.checkMatrixIndex(this, row, column);
316         data[row][column] *= factor;
317     }
318 
319     /** {@inheritDoc} */
320     @Override
321         public int getRowDimension() {
322         return (data == null) ? 0 : data.length;
323     }
324 
325     /** {@inheritDoc} */
326     @Override
327     public int getColumnDimension() {
328         return ((data == null) || (data[0] == null)) ? 0 : data[0].length;
329     }
330 
331     /** {@inheritDoc} */
332     @Override
333     public double[] operate(final double[] v) {
334         final int nRows = this.getRowDimension();
335         final int nCols = this.getColumnDimension();
336         if (v.length != nCols) {
337             throw new DimensionMismatchException(v.length, nCols);
338         }
339         final double[] out = new double[nRows];
340         for (int row = 0; row < nRows; row++) {
341             final double[] dataRow = data[row];
342             double sum = 0;
343             for (int i = 0; i < nCols; i++) {
344                 sum += dataRow[i] * v[i];
345             }
346             out[row] = sum;
347         }
348         return out;
349     }
350 
351     /** {@inheritDoc} */
352     @Override
353     public double[] preMultiply(final double[] v) {
354         final int nRows = getRowDimension();
355         final int nCols = getColumnDimension();
356         if (v.length != nRows) {
357             throw new DimensionMismatchException(v.length, nRows);
358         }
359 
360         final double[] out = new double[nCols];
361         for (int col = 0; col < nCols; ++col) {
362             double sum = 0;
363             for (int i = 0; i < nRows; ++i) {
364                 sum += data[i][col] * v[i];
365             }
366             out[col] = sum;
367         }
368 
369         return out;
370 
371     }
372 
373     /** {@inheritDoc} */
374     @Override
375     public double walkInRowOrder(final RealMatrixChangingVisitor visitor) {
376         final int rows    = getRowDimension();
377         final int columns = getColumnDimension();
378         visitor.start(rows, columns, 0, rows - 1, 0, columns - 1);
379         for (int i = 0; i < rows; ++i) {
380             final double[] rowI = data[i];
381             for (int j = 0; j < columns; ++j) {
382                 rowI[j] = visitor.visit(i, j, rowI[j]);
383             }
384         }
385         return visitor.end();
386     }
387 
388     /** {@inheritDoc} */
389     @Override
390     public double walkInRowOrder(final RealMatrixPreservingVisitor visitor) {
391         final int rows    = getRowDimension();
392         final int columns = getColumnDimension();
393         visitor.start(rows, columns, 0, rows - 1, 0, columns - 1);
394         for (int i = 0; i < rows; ++i) {
395             final double[] rowI = data[i];
396             for (int j = 0; j < columns; ++j) {
397                 visitor.visit(i, j, rowI[j]);
398             }
399         }
400         return visitor.end();
401     }
402 
403     /** {@inheritDoc} */
404     @Override
405     public double walkInRowOrder(final RealMatrixChangingVisitor visitor,
406                                  final int startRow, final int endRow,
407                                  final int startColumn, final int endColumn) {
408         MatrixUtils.checkSubMatrixIndex(this, startRow, endRow, startColumn, endColumn);
409         visitor.start(getRowDimension(), getColumnDimension(),
410                       startRow, endRow, startColumn, endColumn);
411         for (int i = startRow; i <= endRow; ++i) {
412             final double[] rowI = data[i];
413             for (int j = startColumn; j <= endColumn; ++j) {
414                 rowI[j] = visitor.visit(i, j, rowI[j]);
415             }
416         }
417         return visitor.end();
418     }
419 
420     /** {@inheritDoc} */
421     @Override
422     public double walkInRowOrder(final RealMatrixPreservingVisitor visitor,
423                                  final int startRow, final int endRow,
424                                  final int startColumn, final int endColumn) {
425         MatrixUtils.checkSubMatrixIndex(this, startRow, endRow, startColumn, endColumn);
426         visitor.start(getRowDimension(), getColumnDimension(),
427                       startRow, endRow, startColumn, endColumn);
428         for (int i = startRow; i <= endRow; ++i) {
429             final double[] rowI = data[i];
430             for (int j = startColumn; j <= endColumn; ++j) {
431                 visitor.visit(i, j, rowI[j]);
432             }
433         }
434         return visitor.end();
435     }
436 
437     /** {@inheritDoc} */
438     @Override
439     public double walkInColumnOrder(final RealMatrixChangingVisitor visitor) {
440         final int rows    = getRowDimension();
441         final int columns = getColumnDimension();
442         visitor.start(rows, columns, 0, rows - 1, 0, columns - 1);
443         for (int j = 0; j < columns; ++j) {
444             for (int i = 0; i < rows; ++i) {
445                 final double[] rowI = data[i];
446                 rowI[j] = visitor.visit(i, j, rowI[j]);
447             }
448         }
449         return visitor.end();
450     }
451 
452     /** {@inheritDoc} */
453     @Override
454     public double walkInColumnOrder(final RealMatrixPreservingVisitor visitor) {
455         final int rows    = getRowDimension();
456         final int columns = getColumnDimension();
457         visitor.start(rows, columns, 0, rows - 1, 0, columns - 1);
458         for (int j = 0; j < columns; ++j) {
459             for (int i = 0; i < rows; ++i) {
460                 visitor.visit(i, j, data[i][j]);
461             }
462         }
463         return visitor.end();
464     }
465 
466     /** {@inheritDoc} */
467     @Override
468     public double walkInColumnOrder(final RealMatrixChangingVisitor visitor,
469                                     final int startRow, final int endRow,
470                                     final int startColumn, final int endColumn) {
471         MatrixUtils.checkSubMatrixIndex(this, startRow, endRow, startColumn, endColumn);
472         visitor.start(getRowDimension(), getColumnDimension(),
473                       startRow, endRow, startColumn, endColumn);
474         for (int j = startColumn; j <= endColumn; ++j) {
475             for (int i = startRow; i <= endRow; ++i) {
476                 final double[] rowI = data[i];
477                 rowI[j] = visitor.visit(i, j, rowI[j]);
478             }
479         }
480         return visitor.end();
481     }
482 
483     /** {@inheritDoc} */
484     @Override
485     public double walkInColumnOrder(final RealMatrixPreservingVisitor visitor,
486                                     final int startRow, final int endRow,
487                                     final int startColumn, final int endColumn) {
488         MatrixUtils.checkSubMatrixIndex(this, startRow, endRow, startColumn, endColumn);
489         visitor.start(getRowDimension(), getColumnDimension(),
490                       startRow, endRow, startColumn, endColumn);
491         for (int j = startColumn; j <= endColumn; ++j) {
492             for (int i = startRow; i <= endRow; ++i) {
493                 visitor.visit(i, j, data[i][j]);
494             }
495         }
496         return visitor.end();
497     }
498 
499     /**
500      * Get a fresh copy of the underlying data array.
501      *
502      * @return a copy of the underlying data array.
503      */
504     private double[][] copyOut() {
505         final int nRows = this.getRowDimension();
506         final double[][] out = new double[nRows][this.getColumnDimension()];
507         // can't copy 2-d array in one shot, otherwise get row references
508         for (int i = 0; i < nRows; i++) {
509             System.arraycopy(data[i], 0, out[i], 0, data[i].length);
510         }
511         return out;
512     }
513 
514     /**
515      * Replace data with a fresh copy of the input array.
516      *
517      * @param in Data to copy.
518      * @throws NoDataException if the input array is empty.
519      * @throws DimensionMismatchException if the input array is not rectangular.
520      * @throws NullArgumentException if
521      * the input array is {@code null}.
522      */
523     private void copyIn(final double[][] in)
524         throws DimensionMismatchException, NoDataException, NullArgumentException {
525         setSubMatrix(in, 0, 0);
526     }
527 }