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.Field;
023 import org.apache.commons.math.FieldElement;
024 import org.apache.commons.math.MathRuntimeException;
025
026 /**
027 * Implementation of FieldMatrix<T> using a {@link FieldElement}[][] array to store entries.
028 * <p>
029 * As specified in the {@link FieldMatrix} interface, matrix element indexing
030 * is 0-based -- e.g., <code>getEntry(0, 0)</code>
031 * returns the element in the first row, first column of the matrix.</li></ul>
032 * </p>
033 *
034 * @param <T> the type of the field elements
035 * @version $Revision: 783702 $ $Date: 2009-06-11 04:54:02 -0400 (Thu, 11 Jun 2009) $
036 */
037 public class Array2DRowFieldMatrix<T extends FieldElement<T>> extends AbstractFieldMatrix<T> implements Serializable {
038
039 /** Serializable version identifier */
040 private static final long serialVersionUID = 7260756672015356458L;
041
042 /** Entries of the matrix */
043 protected T[][] data;
044
045 /**
046 * Creates a matrix with no data
047 * @param field field to which the elements belong
048 */
049 public Array2DRowFieldMatrix(final Field<T> field) {
050 super(field);
051 }
052
053 /**
054 * Create a new FieldMatrix<T> with the supplied row and column dimensions.
055 *
056 * @param field field to which the elements belong
057 * @param rowDimension the number of rows in the new matrix
058 * @param columnDimension the number of columns in the new matrix
059 * @throws IllegalArgumentException if row or column dimension is not
060 * positive
061 */
062 public Array2DRowFieldMatrix(final Field<T> field,
063 final int rowDimension, final int columnDimension)
064 throws IllegalArgumentException {
065 super(field, rowDimension, columnDimension);
066 data = buildArray(field, rowDimension, columnDimension);
067 }
068
069 /**
070 * Create a new FieldMatrix<T> using the input array as the underlying
071 * data array.
072 * <p>The input array is copied, not referenced. This constructor has
073 * the same effect as calling {@link #Array2DRowFieldMatrix(FieldElement[][], boolean)}
074 * with the second argument set to <code>true</code>.</p>
075 *
076 * @param d data for new matrix
077 * @throws IllegalArgumentException if <code>d</code> is not rectangular
078 * (not all rows have the same length) or empty
079 * @throws NullPointerException if <code>d</code> is null
080 * @see #Array2DRowFieldMatrix(FieldElement[][], boolean)
081 */
082 public Array2DRowFieldMatrix(final T[][] d)
083 throws IllegalArgumentException, NullPointerException {
084 super(extractField(d));
085 copyIn(d);
086 }
087
088 /**
089 * Create a new FieldMatrix<T> using the input array as the underlying
090 * data array.
091 * <p>If an array is built specially in order to be embedded in a
092 * FieldMatrix<T> and not used directly, the <code>copyArray</code> may be
093 * set to <code>false</code. This will prevent the copying and improve
094 * performance as no new array will be built and no data will be copied.</p>
095 * @param d data for new matrix
096 * @param copyArray if true, the input array will be copied, otherwise
097 * it will be referenced
098 * @throws IllegalArgumentException if <code>d</code> is not rectangular
099 * (not all rows have the same length) or empty
100 * @throws NullPointerException if <code>d</code> is null
101 * @see #Array2DRowFieldMatrix(FieldElement[][])
102 */
103 public Array2DRowFieldMatrix(final T[][] d, final boolean copyArray)
104 throws IllegalArgumentException, NullPointerException {
105 super(extractField(d));
106 if (copyArray) {
107 copyIn(d);
108 } else {
109 if (d == null) {
110 throw new NullPointerException();
111 }
112 final int nRows = d.length;
113 if (nRows == 0) {
114 throw MathRuntimeException.createIllegalArgumentException("matrix must have at least one row");
115 }
116 final int nCols = d[0].length;
117 if (nCols == 0) {
118 throw MathRuntimeException.createIllegalArgumentException("matrix must have at least one column");
119 }
120 for (int r = 1; r < nRows; r++) {
121 if (d[r].length != nCols) {
122 throw MathRuntimeException.createIllegalArgumentException(
123 "some rows have length {0} while others have length {1}",
124 nCols, d[r].length);
125 }
126 }
127 data = d;
128 }
129 }
130
131 /**
132 * Create a new (column) FieldMatrix<T> using <code>v</code> as the
133 * data for the unique column of the <code>v.length x 1</code> matrix
134 * created.
135 * <p>The input array is copied, not referenced.</p>
136 *
137 * @param v column vector holding data for new matrix
138 */
139 public Array2DRowFieldMatrix(final T[] v) {
140 super(extractField(v));
141 final int nRows = v.length;
142 data = buildArray(getField(), nRows, 1);
143 for (int row = 0; row < nRows; row++) {
144 data[row][0] = v[row];
145 }
146 }
147
148 /** {@inheritDoc} */
149 @Override
150 public FieldMatrix<T> createMatrix(final int rowDimension, final int columnDimension)
151 throws IllegalArgumentException {
152 return new Array2DRowFieldMatrix<T>(getField(), rowDimension, columnDimension);
153 }
154
155 /** {@inheritDoc} */
156 @Override
157 public FieldMatrix<T> copy() {
158 return new Array2DRowFieldMatrix<T>(copyOut(), false);
159 }
160
161 /** {@inheritDoc} */
162 @Override
163 public FieldMatrix<T> add(final FieldMatrix<T> m)
164 throws IllegalArgumentException {
165 try {
166 return add((Array2DRowFieldMatrix<T>) m);
167 } catch (ClassCastException cce) {
168 return super.add(m);
169 }
170 }
171
172 /**
173 * Compute the sum of this and <code>m</code>.
174 *
175 * @param m matrix to be added
176 * @return this + m
177 * @throws IllegalArgumentException if m is not the same size as this
178 */
179 public Array2DRowFieldMatrix<T> add(final Array2DRowFieldMatrix<T> m)
180 throws IllegalArgumentException {
181
182 // safety check
183 checkAdditionCompatible(m);
184
185 final int rowCount = getRowDimension();
186 final int columnCount = getColumnDimension();
187 final T[][] outData = buildArray(getField(), rowCount, columnCount);
188 for (int row = 0; row < rowCount; row++) {
189 final T[] dataRow = data[row];
190 final T[] mRow = m.data[row];
191 final T[] outDataRow = outData[row];
192 for (int col = 0; col < columnCount; col++) {
193 outDataRow[col] = dataRow[col].add(mRow[col]);
194 }
195 }
196
197 return new Array2DRowFieldMatrix<T>(outData, false);
198
199 }
200
201 /** {@inheritDoc} */
202 @Override
203 public FieldMatrix<T> subtract(final FieldMatrix<T> m)
204 throws IllegalArgumentException {
205 try {
206 return subtract((Array2DRowFieldMatrix<T>) m);
207 } catch (ClassCastException cce) {
208 return super.subtract(m);
209 }
210 }
211
212 /**
213 * Compute this minus <code>m</code>.
214 *
215 * @param m matrix to be subtracted
216 * @return this + m
217 * @throws IllegalArgumentException if m is not the same size as this
218 */
219 public Array2DRowFieldMatrix<T> subtract(final Array2DRowFieldMatrix<T> m)
220 throws IllegalArgumentException {
221
222 // safety check
223 checkSubtractionCompatible(m);
224
225 final int rowCount = getRowDimension();
226 final int columnCount = getColumnDimension();
227 final T[][] outData = buildArray(getField(), rowCount, columnCount);
228 for (int row = 0; row < rowCount; row++) {
229 final T[] dataRow = data[row];
230 final T[] mRow = m.data[row];
231 final T[] outDataRow = outData[row];
232 for (int col = 0; col < columnCount; col++) {
233 outDataRow[col] = dataRow[col].subtract(mRow[col]);
234 }
235 }
236
237 return new Array2DRowFieldMatrix<T>(outData, false);
238
239 }
240
241 /** {@inheritDoc} */
242 @Override
243 public FieldMatrix<T> multiply(final FieldMatrix<T> m)
244 throws IllegalArgumentException {
245 try {
246 return multiply((Array2DRowFieldMatrix<T>) m);
247 } catch (ClassCastException cce) {
248 return super.multiply(m);
249 }
250 }
251
252 /**
253 * Returns the result of postmultiplying this by <code>m</code>.
254 * @param m matrix to postmultiply by
255 * @return this*m
256 * @throws IllegalArgumentException
257 * if columnDimension(this) != rowDimension(m)
258 */
259 public Array2DRowFieldMatrix<T> multiply(final Array2DRowFieldMatrix<T> m)
260 throws IllegalArgumentException {
261
262 // safety check
263 checkMultiplicationCompatible(m);
264
265 final int nRows = this.getRowDimension();
266 final int nCols = m.getColumnDimension();
267 final int nSum = this.getColumnDimension();
268 final T[][] outData = buildArray(getField(), nRows, nCols);
269 for (int row = 0; row < nRows; row++) {
270 final T[] dataRow = data[row];
271 final T[] outDataRow = outData[row];
272 for (int col = 0; col < nCols; col++) {
273 T sum = getField().getZero();
274 for (int i = 0; i < nSum; i++) {
275 sum = sum.add(dataRow[i].multiply(m.data[i][col]));
276 }
277 outDataRow[col] = sum;
278 }
279 }
280
281 return new Array2DRowFieldMatrix<T>(outData, false);
282
283 }
284
285 /** {@inheritDoc} */
286 @Override
287 public T[][] getData() {
288 return copyOut();
289 }
290
291 /**
292 * Returns a reference to the underlying data array.
293 * <p>
294 * Does <strong>not</strong> make a fresh copy of the underlying data.</p>
295 *
296 * @return 2-dimensional array of entries
297 */
298 public T[][] getDataRef() {
299 return data;
300 }
301
302 /** {@inheritDoc} */
303 @Override
304 public void setSubMatrix(final T[][] subMatrix, final int row, final int column)
305 throws MatrixIndexException {
306 if (data == null) {
307 if (row > 0) {
308 throw MathRuntimeException.createIllegalStateException(
309 "first {0} rows are not initialized yet",
310 row);
311 }
312 if (column > 0) {
313 throw MathRuntimeException.createIllegalStateException(
314 "first {0} columns are not initialized yet",
315 column);
316 }
317 final int nRows = subMatrix.length;
318 if (nRows == 0) {
319 throw MathRuntimeException.createIllegalArgumentException("matrix must have at least one row");
320 }
321
322 final int nCols = subMatrix[0].length;
323 if (nCols == 0) {
324 throw MathRuntimeException.createIllegalArgumentException("matrix must have at least one column");
325 }
326 data = buildArray(getField(), subMatrix.length, nCols);
327 for (int i = 0; i < data.length; ++i) {
328 if (subMatrix[i].length != nCols) {
329 throw MathRuntimeException.createIllegalArgumentException(
330 "some rows have length {0} while others have length {1}",
331 nCols, subMatrix[i].length);
332 }
333 System.arraycopy(subMatrix[i], 0, data[i + row], column, nCols);
334 }
335 } else {
336 super.setSubMatrix(subMatrix, row, column);
337 }
338
339 }
340
341 /** {@inheritDoc} */
342 @Override
343 public T getEntry(final int row, final int column)
344 throws MatrixIndexException {
345 try {
346 return data[row][column];
347 } catch (ArrayIndexOutOfBoundsException e) {
348 throw new MatrixIndexException(
349 "no entry at indices ({0}, {1}) in a {2}x{3} matrix",
350 row, column, getRowDimension(), getColumnDimension());
351 }
352 }
353
354 /** {@inheritDoc} */
355 @Override
356 public void setEntry(final int row, final int column, final T value)
357 throws MatrixIndexException {
358 try {
359 data[row][column] = value;
360 } catch (ArrayIndexOutOfBoundsException e) {
361 throw new MatrixIndexException(
362 "no entry at indices ({0}, {1}) in a {2}x{3} matrix",
363 row, column, getRowDimension(), getColumnDimension());
364 }
365 }
366
367 /** {@inheritDoc} */
368 @Override
369 public void addToEntry(final int row, final int column, final T increment)
370 throws MatrixIndexException {
371 try {
372 data[row][column] = data[row][column].add(increment);
373 } catch (ArrayIndexOutOfBoundsException e) {
374 throw new MatrixIndexException(
375 "no entry at indices ({0}, {1}) in a {2}x{3} matrix",
376 row, column, getRowDimension(), getColumnDimension());
377 }
378 }
379
380 /** {@inheritDoc} */
381 @Override
382 public void multiplyEntry(final int row, final int column, final T factor)
383 throws MatrixIndexException {
384 try {
385 data[row][column] = data[row][column].multiply(factor);
386 } catch (ArrayIndexOutOfBoundsException e) {
387 throw new MatrixIndexException(
388 "no entry at indices ({0}, {1}) in a {2}x{3} matrix",
389 row, column, getRowDimension(), getColumnDimension());
390 }
391 }
392
393 /** {@inheritDoc} */
394 @Override
395 public int getRowDimension() {
396 return (data == null) ? 0 : data.length;
397 }
398
399 /** {@inheritDoc} */
400 @Override
401 public int getColumnDimension() {
402 return ((data == null) || (data[0] == null)) ? 0 : data[0].length;
403 }
404
405 /** {@inheritDoc} */
406 @Override
407 public T[] operate(final T[] v)
408 throws IllegalArgumentException {
409 final int nRows = this.getRowDimension();
410 final int nCols = this.getColumnDimension();
411 if (v.length != nCols) {
412 throw MathRuntimeException.createIllegalArgumentException(
413 "vector length mismatch: got {0} but expected {1}",
414 v.length, nCols);
415 }
416 final T[] out = buildArray(getField(), nRows);
417 for (int row = 0; row < nRows; row++) {
418 final T[] dataRow = data[row];
419 T sum = getField().getZero();
420 for (int i = 0; i < nCols; i++) {
421 sum = sum.add(dataRow[i].multiply(v[i]));
422 }
423 out[row] = sum;
424 }
425 return out;
426 }
427
428 /** {@inheritDoc} */
429 @Override
430 public T[] preMultiply(final T[] v)
431 throws IllegalArgumentException {
432
433 final int nRows = getRowDimension();
434 final int nCols = getColumnDimension();
435 if (v.length != nRows) {
436 throw MathRuntimeException.createIllegalArgumentException(
437 "vector length mismatch: got {0} but expected {1}",
438 v.length, nRows);
439 }
440
441 final T[] out = buildArray(getField(), nCols);
442 for (int col = 0; col < nCols; ++col) {
443 T sum = getField().getZero();
444 for (int i = 0; i < nRows; ++i) {
445 sum = sum.add(data[i][col].multiply(v[i]));
446 }
447 out[col] = sum;
448 }
449
450 return out;
451
452 }
453
454 /** {@inheritDoc} */
455 @Override
456 public T walkInRowOrder(final FieldMatrixChangingVisitor<T> visitor)
457 throws MatrixVisitorException {
458 final int rows = getRowDimension();
459 final int columns = getColumnDimension();
460 visitor.start(rows, columns, 0, rows - 1, 0, columns - 1);
461 for (int i = 0; i < rows; ++i) {
462 final T[] rowI = data[i];
463 for (int j = 0; j < columns; ++j) {
464 rowI[j] = visitor.visit(i, j, rowI[j]);
465 }
466 }
467 return visitor.end();
468 }
469
470 /** {@inheritDoc} */
471 @Override
472 public T walkInRowOrder(final FieldMatrixPreservingVisitor<T> visitor)
473 throws MatrixVisitorException {
474 final int rows = getRowDimension();
475 final int columns = getColumnDimension();
476 visitor.start(rows, columns, 0, rows - 1, 0, columns - 1);
477 for (int i = 0; i < rows; ++i) {
478 final T[] rowI = data[i];
479 for (int j = 0; j < columns; ++j) {
480 visitor.visit(i, j, rowI[j]);
481 }
482 }
483 return visitor.end();
484 }
485
486 /** {@inheritDoc} */
487 @Override
488 public T walkInRowOrder(final FieldMatrixChangingVisitor<T> visitor,
489 final int startRow, final int endRow,
490 final int startColumn, final int endColumn)
491 throws MatrixIndexException, MatrixVisitorException {
492 checkSubMatrixIndex(startRow, endRow, startColumn, endColumn);
493 visitor.start(getRowDimension(), getColumnDimension(),
494 startRow, endRow, startColumn, endColumn);
495 for (int i = startRow; i <= endRow; ++i) {
496 final T[] rowI = data[i];
497 for (int j = startColumn; j <= endColumn; ++j) {
498 rowI[j] = visitor.visit(i, j, rowI[j]);
499 }
500 }
501 return visitor.end();
502 }
503
504 /** {@inheritDoc} */
505 @Override
506 public T walkInRowOrder(final FieldMatrixPreservingVisitor<T> visitor,
507 final int startRow, final int endRow,
508 final int startColumn, final int endColumn)
509 throws MatrixIndexException, MatrixVisitorException {
510 checkSubMatrixIndex(startRow, endRow, startColumn, endColumn);
511 visitor.start(getRowDimension(), getColumnDimension(),
512 startRow, endRow, startColumn, endColumn);
513 for (int i = startRow; i <= endRow; ++i) {
514 final T[] rowI = data[i];
515 for (int j = startColumn; j <= endColumn; ++j) {
516 visitor.visit(i, j, rowI[j]);
517 }
518 }
519 return visitor.end();
520 }
521
522 /** {@inheritDoc} */
523 @Override
524 public T walkInColumnOrder(final FieldMatrixChangingVisitor<T> visitor)
525 throws MatrixVisitorException {
526 final int rows = getRowDimension();
527 final int columns = getColumnDimension();
528 visitor.start(rows, columns, 0, rows - 1, 0, columns - 1);
529 for (int j = 0; j < columns; ++j) {
530 for (int i = 0; i < rows; ++i) {
531 final T[] rowI = data[i];
532 rowI[j] = visitor.visit(i, j, rowI[j]);
533 }
534 }
535 return visitor.end();
536 }
537
538 /** {@inheritDoc} */
539 @Override
540 public T walkInColumnOrder(final FieldMatrixPreservingVisitor<T> visitor)
541 throws MatrixVisitorException {
542 final int rows = getRowDimension();
543 final int columns = getColumnDimension();
544 visitor.start(rows, columns, 0, rows - 1, 0, columns - 1);
545 for (int j = 0; j < columns; ++j) {
546 for (int i = 0; i < rows; ++i) {
547 visitor.visit(i, j, data[i][j]);
548 }
549 }
550 return visitor.end();
551 }
552
553 /** {@inheritDoc} */
554 @Override
555 public T walkInColumnOrder(final FieldMatrixChangingVisitor<T> visitor,
556 final int startRow, final int endRow,
557 final int startColumn, final int endColumn)
558 throws MatrixIndexException, MatrixVisitorException {
559 checkSubMatrixIndex(startRow, endRow, startColumn, endColumn);
560 visitor.start(getRowDimension(), getColumnDimension(),
561 startRow, endRow, startColumn, endColumn);
562 for (int j = startColumn; j <= endColumn; ++j) {
563 for (int i = startRow; i <= endRow; ++i) {
564 final T[] rowI = data[i];
565 rowI[j] = visitor.visit(i, j, rowI[j]);
566 }
567 }
568 return visitor.end();
569 }
570
571 /** {@inheritDoc} */
572 @Override
573 public T walkInColumnOrder(final FieldMatrixPreservingVisitor<T> visitor,
574 final int startRow, final int endRow,
575 final int startColumn, final int endColumn)
576 throws MatrixIndexException, MatrixVisitorException {
577 checkSubMatrixIndex(startRow, endRow, startColumn, endColumn);
578 visitor.start(getRowDimension(), getColumnDimension(),
579 startRow, endRow, startColumn, endColumn);
580 for (int j = startColumn; j <= endColumn; ++j) {
581 for (int i = startRow; i <= endRow; ++i) {
582 visitor.visit(i, j, data[i][j]);
583 }
584 }
585 return visitor.end();
586 }
587
588 /**
589 * Returns a fresh copy of the underlying data array.
590 *
591 * @return a copy of the underlying data array.
592 */
593 private T[][] copyOut() {
594 final int nRows = this.getRowDimension();
595 final T[][] out = buildArray(getField(), nRows, getColumnDimension());
596 // can't copy 2-d array in one shot, otherwise get row references
597 for (int i = 0; i < nRows; i++) {
598 System.arraycopy(data[i], 0, out[i], 0, data[i].length);
599 }
600 return out;
601 }
602
603 /**
604 * Replaces data with a fresh copy of the input array.
605 * <p>
606 * Verifies that the input array is rectangular and non-empty.</p>
607 *
608 * @param in data to copy in
609 * @throws IllegalArgumentException if input array is empty or not
610 * rectangular
611 * @throws NullPointerException if input array is null
612 */
613 private void copyIn(final T[][] in) {
614 setSubMatrix(in, 0, 0);
615 }
616
617 }