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.math3.linear;
019
020 import java.io.Serializable;
021
022 import org.apache.commons.math3.exception.DimensionMismatchException;
023 import org.apache.commons.math3.exception.MathIllegalStateException;
024 import org.apache.commons.math3.exception.NoDataException;
025 import org.apache.commons.math3.exception.NotStrictlyPositiveException;
026 import org.apache.commons.math3.exception.NullArgumentException;
027 import org.apache.commons.math3.exception.NumberIsTooSmallException;
028 import org.apache.commons.math3.exception.OutOfRangeException;
029 import org.apache.commons.math3.exception.util.LocalizedFormats;
030 import org.apache.commons.math3.util.MathUtils;
031
032 /**
033 * Implementation of {@link RealMatrix} using a {@code double[][]} array to
034 * store entries.
035 *
036 * @version $Id: Array2DRowRealMatrix.java 1416643 2012-12-03 19:37:14Z tn $
037 */
038 public class Array2DRowRealMatrix extends AbstractRealMatrix implements Serializable {
039 /** Serializable version identifier. */
040 private static final long serialVersionUID = -1067294169172445528L;
041
042 /** Entries of the matrix. */
043 private double data[][];
044
045 /**
046 * Creates a matrix with no data
047 */
048 public Array2DRowRealMatrix() {}
049
050 /**
051 * Create a new RealMatrix with the supplied row and column dimensions.
052 *
053 * @param rowDimension Number of rows in the new matrix.
054 * @param columnDimension Number of columns in the new matrix.
055 * @throws NotStrictlyPositiveException if the row or column dimension is
056 * not positive.
057 */
058 public Array2DRowRealMatrix(final int rowDimension,
059 final int columnDimension)
060 throws NotStrictlyPositiveException {
061 super(rowDimension, columnDimension);
062 data = new double[rowDimension][columnDimension];
063 }
064
065 /**
066 * Create a new {@code RealMatrix} using the input array as the underlying
067 * data array.
068 * <p>The input array is copied, not referenced. This constructor has
069 * the same effect as calling {@link #Array2DRowRealMatrix(double[][], boolean)}
070 * with the second argument set to {@code true}.</p>
071 *
072 * @param d Data for the new matrix.
073 * @throws DimensionMismatchException if {@code d} is not rectangular.
074 * @throws NoDataException if {@code d} row or colum dimension is zero.
075 * @throws NullArgumentException if {@code d} is {@code null}.
076 * @see #Array2DRowRealMatrix(double[][], boolean)
077 */
078 public Array2DRowRealMatrix(final double[][] d)
079 throws DimensionMismatchException, NoDataException, NullArgumentException {
080 copyIn(d);
081 }
082
083 /**
084 * Create a new RealMatrix using the input array as the underlying
085 * data array.
086 * If an array is built specially in order to be embedded in a
087 * RealMatrix and not used directly, the {@code copyArray} may be
088 * set to {@code false}. This will prevent the copying and improve
089 * performance as no new array will be built and no data will be copied.
090 *
091 * @param d Data for new matrix.
092 * @param copyArray if {@code true}, the input array will be copied,
093 * otherwise it will be referenced.
094 * @throws DimensionMismatchException if {@code d} is not rectangular.
095 * @throws NoDataException if {@code d} row or colum dimension is zero.
096 * @throws NullArgumentException if {@code d} is {@code null}.
097 * @see #Array2DRowRealMatrix(double[][])
098 */
099 public Array2DRowRealMatrix(final double[][] d, final boolean copyArray)
100 throws DimensionMismatchException, NoDataException,
101 NullArgumentException {
102 if (copyArray) {
103 copyIn(d);
104 } else {
105 if (d == null) {
106 throw new NullArgumentException();
107 }
108 final int nRows = d.length;
109 if (nRows == 0) {
110 throw new NoDataException(LocalizedFormats.AT_LEAST_ONE_ROW);
111 }
112 final int nCols = d[0].length;
113 if (nCols == 0) {
114 throw new NoDataException(LocalizedFormats.AT_LEAST_ONE_COLUMN);
115 }
116 for (int r = 1; r < nRows; r++) {
117 if (d[r].length != nCols) {
118 throw new DimensionMismatchException(d[r].length, nCols);
119 }
120 }
121 data = d;
122 }
123 }
124
125 /**
126 * Create a new (column) RealMatrix using {@code v} as the
127 * data for the unique column of the created matrix.
128 * The input array is copied.
129 *
130 * @param v Column vector holding data for new matrix.
131 */
132 public Array2DRowRealMatrix(final double[] v) {
133 final int nRows = v.length;
134 data = new double[nRows][1];
135 for (int row = 0; row < nRows; row++) {
136 data[row][0] = v[row];
137 }
138 }
139
140 /** {@inheritDoc} */
141 @Override
142 public RealMatrix createMatrix(final int rowDimension,
143 final int columnDimension)
144 throws NotStrictlyPositiveException {
145 return new Array2DRowRealMatrix(rowDimension, columnDimension);
146 }
147
148 /** {@inheritDoc} */
149 @Override
150 public RealMatrix copy() {
151 return new Array2DRowRealMatrix(copyOut(), false);
152 }
153
154 /**
155 * Compute the sum of {@code this} and {@code m}.
156 *
157 * @param m Matrix to be added.
158 * @return {@code this + m}.
159 * @throws MatrixDimensionMismatchException if {@code m} is not the same
160 * size as {@code this}.
161 */
162 public Array2DRowRealMatrix add(final Array2DRowRealMatrix m)
163 throws MatrixDimensionMismatchException {
164 // Safety check.
165 MatrixUtils.checkAdditionCompatible(this, m);
166
167 final int rowCount = getRowDimension();
168 final int columnCount = getColumnDimension();
169 final double[][] outData = new double[rowCount][columnCount];
170 for (int row = 0; row < rowCount; row++) {
171 final double[] dataRow = data[row];
172 final double[] mRow = m.data[row];
173 final double[] outDataRow = outData[row];
174 for (int col = 0; col < columnCount; col++) {
175 outDataRow[col] = dataRow[col] + mRow[col];
176 }
177 }
178
179 return new Array2DRowRealMatrix(outData, false);
180 }
181
182 /**
183 * Returns {@code this} minus {@code m}.
184 *
185 * @param m Matrix to be subtracted.
186 * @return {@code this - m}
187 * @throws MatrixDimensionMismatchException if {@code m} is not the same
188 * size as {@code this}.
189 */
190 public Array2DRowRealMatrix subtract(final Array2DRowRealMatrix m)
191 throws MatrixDimensionMismatchException {
192 MatrixUtils.checkSubtractionCompatible(this, m);
193
194 final int rowCount = getRowDimension();
195 final int columnCount = getColumnDimension();
196 final double[][] outData = new double[rowCount][columnCount];
197 for (int row = 0; row < rowCount; row++) {
198 final double[] dataRow = data[row];
199 final double[] mRow = m.data[row];
200 final double[] outDataRow = outData[row];
201 for (int col = 0; col < columnCount; col++) {
202 outDataRow[col] = dataRow[col] - mRow[col];
203 }
204 }
205
206 return new Array2DRowRealMatrix(outData, false);
207 }
208
209 /**
210 * Returns the result of postmultiplying {@code this} by {@code m}.
211 *
212 * @param m matrix to postmultiply by
213 * @return {@code this * m}
214 * @throws DimensionMismatchException if
215 * {@code columnDimension(this) != rowDimension(m)}
216 */
217 public Array2DRowRealMatrix multiply(final Array2DRowRealMatrix m)
218 throws DimensionMismatchException {
219 MatrixUtils.checkMultiplicationCompatible(this, m);
220
221 final int nRows = this.getRowDimension();
222 final int nCols = m.getColumnDimension();
223 final int nSum = this.getColumnDimension();
224
225 final double[][] outData = new double[nRows][nCols];
226 // Will hold a column of "m".
227 final double[] mCol = new double[nSum];
228 final double[][] mData = m.data;
229
230 // Multiply.
231 for (int col = 0; col < nCols; col++) {
232 // Copy all elements of column "col" of "m" so that
233 // will be in contiguous memory.
234 for (int mRow = 0; mRow < nSum; mRow++) {
235 mCol[mRow] = mData[mRow][col];
236 }
237
238 for (int row = 0; row < nRows; row++) {
239 final double[] dataRow = data[row];
240 double sum = 0;
241 for (int i = 0; i < nSum; i++) {
242 sum += dataRow[i] * mCol[i];
243 }
244 outData[row][col] = sum;
245 }
246 }
247
248 return new Array2DRowRealMatrix(outData, false);
249 }
250
251 /** {@inheritDoc} */
252 @Override
253 public double[][] getData() {
254 return copyOut();
255 }
256
257 /**
258 * Get a reference to the underlying data array.
259 *
260 * @return 2-dimensional array of entries.
261 */
262 public double[][] getDataRef() {
263 return data;
264 }
265
266 /** {@inheritDoc} */
267 @Override
268 public void setSubMatrix(final double[][] subMatrix, final int row,
269 final int column)
270 throws NoDataException, OutOfRangeException,
271 DimensionMismatchException, NullArgumentException {
272 if (data == null) {
273 if (row > 0) {
274 throw new MathIllegalStateException(LocalizedFormats.FIRST_ROWS_NOT_INITIALIZED_YET, row);
275 }
276 if (column > 0) {
277 throw new MathIllegalStateException(LocalizedFormats.FIRST_COLUMNS_NOT_INITIALIZED_YET, column);
278 }
279 MathUtils.checkNotNull(subMatrix);
280 final int nRows = subMatrix.length;
281 if (nRows == 0) {
282 throw new NoDataException(LocalizedFormats.AT_LEAST_ONE_ROW);
283 }
284
285 final int nCols = subMatrix[0].length;
286 if (nCols == 0) {
287 throw new NoDataException(LocalizedFormats.AT_LEAST_ONE_COLUMN);
288 }
289 data = new double[subMatrix.length][nCols];
290 for (int i = 0; i < data.length; ++i) {
291 if (subMatrix[i].length != nCols) {
292 throw new DimensionMismatchException(subMatrix[i].length, nCols);
293 }
294 System.arraycopy(subMatrix[i], 0, data[i + row], column, nCols);
295 }
296 } else {
297 super.setSubMatrix(subMatrix, row, column);
298 }
299
300 }
301
302 /** {@inheritDoc} */
303 @Override
304 public double getEntry(final int row, final int column)
305 throws OutOfRangeException {
306 MatrixUtils.checkMatrixIndex(this, row, column);
307 return data[row][column];
308 }
309
310 /** {@inheritDoc} */
311 @Override
312 public void setEntry(final int row, final int column, final double value)
313 throws OutOfRangeException {
314 MatrixUtils.checkMatrixIndex(this, row, column);
315 data[row][column] = value;
316 }
317
318 /** {@inheritDoc} */
319 @Override
320 public void addToEntry(final int row, final int column,
321 final double increment)
322 throws OutOfRangeException {
323 MatrixUtils.checkMatrixIndex(this, row, column);
324 data[row][column] += increment;
325 }
326
327 /** {@inheritDoc} */
328 @Override
329 public void multiplyEntry(final int row, final int column,
330 final double factor)
331 throws OutOfRangeException {
332 MatrixUtils.checkMatrixIndex(this, row, column);
333 data[row][column] *= factor;
334 }
335
336 /** {@inheritDoc} */
337 @Override
338 public int getRowDimension() {
339 return (data == null) ? 0 : data.length;
340 }
341
342 /** {@inheritDoc} */
343 @Override
344 public int getColumnDimension() {
345 return ((data == null) || (data[0] == null)) ? 0 : data[0].length;
346 }
347
348 /** {@inheritDoc} */
349 @Override
350 public double[] operate(final double[] v)
351 throws DimensionMismatchException {
352 final int nRows = this.getRowDimension();
353 final int nCols = this.getColumnDimension();
354 if (v.length != nCols) {
355 throw new DimensionMismatchException(v.length, nCols);
356 }
357 final double[] out = new double[nRows];
358 for (int row = 0; row < nRows; row++) {
359 final double[] dataRow = data[row];
360 double sum = 0;
361 for (int i = 0; i < nCols; i++) {
362 sum += dataRow[i] * v[i];
363 }
364 out[row] = sum;
365 }
366 return out;
367 }
368
369 /** {@inheritDoc} */
370 @Override
371 public double[] preMultiply(final double[] v)
372 throws DimensionMismatchException {
373 final int nRows = getRowDimension();
374 final int nCols = getColumnDimension();
375 if (v.length != nRows) {
376 throw new DimensionMismatchException(v.length, nRows);
377 }
378
379 final double[] out = new double[nCols];
380 for (int col = 0; col < nCols; ++col) {
381 double sum = 0;
382 for (int i = 0; i < nRows; ++i) {
383 sum += data[i][col] * v[i];
384 }
385 out[col] = sum;
386 }
387
388 return out;
389
390 }
391
392 /** {@inheritDoc} */
393 @Override
394 public double walkInRowOrder(final RealMatrixChangingVisitor visitor) {
395 final int rows = getRowDimension();
396 final int columns = getColumnDimension();
397 visitor.start(rows, columns, 0, rows - 1, 0, columns - 1);
398 for (int i = 0; i < rows; ++i) {
399 final double[] rowI = data[i];
400 for (int j = 0; j < columns; ++j) {
401 rowI[j] = visitor.visit(i, j, rowI[j]);
402 }
403 }
404 return visitor.end();
405 }
406
407 /** {@inheritDoc} */
408 @Override
409 public double walkInRowOrder(final RealMatrixPreservingVisitor visitor) {
410 final int rows = getRowDimension();
411 final int columns = getColumnDimension();
412 visitor.start(rows, columns, 0, rows - 1, 0, columns - 1);
413 for (int i = 0; i < rows; ++i) {
414 final double[] rowI = data[i];
415 for (int j = 0; j < columns; ++j) {
416 visitor.visit(i, j, rowI[j]);
417 }
418 }
419 return visitor.end();
420 }
421
422 /** {@inheritDoc} */
423 @Override
424 public double walkInRowOrder(final RealMatrixChangingVisitor visitor,
425 final int startRow, final int endRow,
426 final int startColumn, final int endColumn)
427 throws OutOfRangeException, NumberIsTooSmallException {
428 MatrixUtils.checkSubMatrixIndex(this, startRow, endRow, startColumn, endColumn);
429 visitor.start(getRowDimension(), getColumnDimension(),
430 startRow, endRow, startColumn, endColumn);
431 for (int i = startRow; i <= endRow; ++i) {
432 final double[] rowI = data[i];
433 for (int j = startColumn; j <= endColumn; ++j) {
434 rowI[j] = visitor.visit(i, j, rowI[j]);
435 }
436 }
437 return visitor.end();
438 }
439
440 /** {@inheritDoc} */
441 @Override
442 public double walkInRowOrder(final RealMatrixPreservingVisitor visitor,
443 final int startRow, final int endRow,
444 final int startColumn, final int endColumn)
445 throws OutOfRangeException, NumberIsTooSmallException {
446 MatrixUtils.checkSubMatrixIndex(this, startRow, endRow, startColumn, endColumn);
447 visitor.start(getRowDimension(), getColumnDimension(),
448 startRow, endRow, startColumn, endColumn);
449 for (int i = startRow; i <= endRow; ++i) {
450 final double[] rowI = data[i];
451 for (int j = startColumn; j <= endColumn; ++j) {
452 visitor.visit(i, j, rowI[j]);
453 }
454 }
455 return visitor.end();
456 }
457
458 /** {@inheritDoc} */
459 @Override
460 public double walkInColumnOrder(final RealMatrixChangingVisitor visitor) {
461 final int rows = getRowDimension();
462 final int columns = getColumnDimension();
463 visitor.start(rows, columns, 0, rows - 1, 0, columns - 1);
464 for (int j = 0; j < columns; ++j) {
465 for (int i = 0; i < rows; ++i) {
466 final double[] rowI = data[i];
467 rowI[j] = visitor.visit(i, j, rowI[j]);
468 }
469 }
470 return visitor.end();
471 }
472
473 /** {@inheritDoc} */
474 @Override
475 public double walkInColumnOrder(final RealMatrixPreservingVisitor visitor) {
476 final int rows = getRowDimension();
477 final int columns = getColumnDimension();
478 visitor.start(rows, columns, 0, rows - 1, 0, columns - 1);
479 for (int j = 0; j < columns; ++j) {
480 for (int i = 0; i < rows; ++i) {
481 visitor.visit(i, j, data[i][j]);
482 }
483 }
484 return visitor.end();
485 }
486
487 /** {@inheritDoc} */
488 @Override
489 public double walkInColumnOrder(final RealMatrixChangingVisitor visitor,
490 final int startRow, final int endRow,
491 final int startColumn, final int endColumn)
492 throws OutOfRangeException, NumberIsTooSmallException {
493 MatrixUtils.checkSubMatrixIndex(this, startRow, endRow, startColumn, endColumn);
494 visitor.start(getRowDimension(), getColumnDimension(),
495 startRow, endRow, startColumn, endColumn);
496 for (int j = startColumn; j <= endColumn; ++j) {
497 for (int i = startRow; i <= endRow; ++i) {
498 final double[] rowI = data[i];
499 rowI[j] = visitor.visit(i, j, rowI[j]);
500 }
501 }
502 return visitor.end();
503 }
504
505 /** {@inheritDoc} */
506 @Override
507 public double walkInColumnOrder(final RealMatrixPreservingVisitor visitor,
508 final int startRow, final int endRow,
509 final int startColumn, final int endColumn)
510 throws OutOfRangeException, NumberIsTooSmallException {
511 MatrixUtils.checkSubMatrixIndex(this, startRow, endRow, startColumn, endColumn);
512 visitor.start(getRowDimension(), getColumnDimension(),
513 startRow, endRow, startColumn, endColumn);
514 for (int j = startColumn; j <= endColumn; ++j) {
515 for (int i = startRow; i <= endRow; ++i) {
516 visitor.visit(i, j, data[i][j]);
517 }
518 }
519 return visitor.end();
520 }
521
522 /**
523 * Get a fresh copy of the underlying data array.
524 *
525 * @return a copy of the underlying data array.
526 */
527 private double[][] copyOut() {
528 final int nRows = this.getRowDimension();
529 final double[][] out = new double[nRows][this.getColumnDimension()];
530 // can't copy 2-d array in one shot, otherwise get row references
531 for (int i = 0; i < nRows; i++) {
532 System.arraycopy(data[i], 0, out[i], 0, data[i].length);
533 }
534 return out;
535 }
536
537 /**
538 * Replace data with a fresh copy of the input array.
539 *
540 * @param in Data to copy.
541 * @throws NoDataException if the input array is empty.
542 * @throws DimensionMismatchException if the input array is not rectangular.
543 * @throws NullArgumentException if the input array is {@code null}.
544 */
545 private void copyIn(final double[][] in)
546 throws DimensionMismatchException, NoDataException, NullArgumentException {
547 setSubMatrix(in, 0, 0);
548 }
549 }