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.exception.DimensionMismatchException;
023 import org.apache.commons.math.exception.NullArgumentException;
024 import org.apache.commons.math.exception.NoDataException;
025 import org.apache.commons.math.exception.MathIllegalStateException;
026 import org.apache.commons.math.exception.util.LocalizedFormats;
027 import org.apache.commons.math.util.MathUtils;
028
029 /**
030 * Implementation of {@link RealMatrix} using a {@code double[][]} array to
031 * store entries.
032 *
033 * @version $Id: Array2DRowRealMatrix.java 1178186 2011-10-02 13:00:41Z erans $
034 */
035 public class Array2DRowRealMatrix extends AbstractRealMatrix implements Serializable {
036 /** Serializable version identifier. */
037 private static final long serialVersionUID = -1067294169172445528L;
038 /** Entries of the matrix. */
039 protected double data[][];
040
041 /**
042 * Creates a matrix with no data
043 */
044 public Array2DRowRealMatrix() {}
045
046 /**
047 * Create a new RealMatrix with the supplied row and column dimensions.
048 *
049 * @param rowDimension Number of rows in the new matrix.
050 * @param columnDimension Number of columns in the new matrix.
051 * @throws org.apache.commons.math.exception.NotStrictlyPositiveException
052 * if the row or column dimension is not positive.
053 */
054 public Array2DRowRealMatrix(final int rowDimension, final int columnDimension) {
055 super(rowDimension, columnDimension);
056 data = new double[rowDimension][columnDimension];
057 }
058
059 /**
060 * Create a new {@code RealMatrix} using the input array as the underlying
061 * data array.
062 * <p>The input array is copied, not referenced. This constructor has
063 * the same effect as calling {@link #Array2DRowRealMatrix(double[][], boolean)}
064 * with the second argument set to {@code true}.</p>
065 *
066 * @param d Data for the new matrix.
067 * @throws DimensionMismatchException if {@code d} is not rectangular.
068 * @throws NoDataException if {@code d} row or colum dimension is zero.
069 * @throws NullArgumentException if {@code d} is {@code null}.
070 * @see #Array2DRowRealMatrix(double[][], boolean)
071 */
072 public Array2DRowRealMatrix(final double[][] d)
073 throws DimensionMismatchException, NoDataException, NullArgumentException {
074 copyIn(d);
075 }
076
077 /**
078 * Create a new RealMatrix using the input array as the underlying
079 * data array.
080 * If an array is built specially in order to be embedded in a
081 * RealMatrix and not used directly, the {@code copyArray} may be
082 * set to {@code false}. This will prevent the copying and improve
083 * performance as no new array will be built and no data will be copied.
084 *
085 * @param d Data for new matrix.
086 * @param copyArray if {@code true}, the input array will be copied,
087 * otherwise it will be referenced.
088 * @throws DimensionMismatchException if {@code d} is not rectangular
089 * (not all rows have the same length) or empty.
090 * @throws NullArgumentException if {@code d} is {@code null}.
091 * @throws NoDataException if there are not at least one row and one column.
092 * @see #Array2DRowRealMatrix(double[][])
093 */
094 public Array2DRowRealMatrix(final double[][] d, final boolean copyArray) {
095 if (copyArray) {
096 copyIn(d);
097 } else {
098 if (d == null) {
099 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 }