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