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.lang.reflect.Array;
021 import java.util.ArrayList;
022 import java.util.Arrays;
023
024 import org.apache.commons.math.Field;
025 import org.apache.commons.math.FieldElement;
026 import org.apache.commons.math.exception.DimensionMismatchException;
027 import org.apache.commons.math.exception.NoDataException;
028 import org.apache.commons.math.exception.OutOfRangeException;
029 import org.apache.commons.math.exception.NumberIsTooSmallException;
030 import org.apache.commons.math.exception.NotStrictlyPositiveException;
031 import org.apache.commons.math.exception.NullArgumentException;
032 import org.apache.commons.math.exception.util.LocalizedFormats;
033
034 /**
035 * Basic implementation of {@link FieldMatrix} methods regardless of the underlying storage.
036 * <p>All the methods implemented here use {@link #getEntry(int, int)} to access
037 * matrix elements. Derived class can provide faster implementations. </p>
038 *
039 * @param <T> Type of the field elements.
040 *
041 * @version $Id: AbstractFieldMatrix.java 1178009 2011-10-01 15:15:00Z luc $
042 * @since 2.0
043 */
044 public abstract class AbstractFieldMatrix<T extends FieldElement<T>>
045 implements FieldMatrix<T> {
046 /** Field to which the elements belong. */
047 private final Field<T> field;
048
049 /**
050 * Constructor for use with Serializable
051 */
052 protected AbstractFieldMatrix() {
053 field = null;
054 }
055
056 /**
057 * Creates a matrix with no data
058 * @param field field to which the elements belong
059 */
060 protected AbstractFieldMatrix(final Field<T> field) {
061 this.field = field;
062 }
063
064 /**
065 * Create a new FieldMatrix<T> with the supplied row and column dimensions.
066 *
067 * @param field Field to which the elements belong.
068 * @param rowDimension Number of rows in the new matrix.
069 * @param columnDimension Number of columns in the new matrix.
070 * @throws NotStrictlyPositiveException if row or column dimension is not
071 * positive.
072 */
073 protected AbstractFieldMatrix(final Field<T> field,
074 final int rowDimension,
075 final int columnDimension) {
076 if (rowDimension <= 0) {
077 throw new NotStrictlyPositiveException(LocalizedFormats.DIMENSION,
078 rowDimension);
079 }
080 if (columnDimension <= 0) {
081 throw new NotStrictlyPositiveException(LocalizedFormats.DIMENSION,
082 columnDimension);
083 }
084 this.field = field;
085 }
086
087 /**
088 * Get the elements type from an array.
089 *
090 * @param <T> Type of the field elements.
091 * @param d Data array.
092 * @return the field to which the array elements belong.
093 * @throws NullArgumentException if the array is {@code null}.
094 * @throws NoDataException if the array is empty.
095 */
096 protected static <T extends FieldElement<T>> Field<T> extractField(final T[][] d) {
097 if (d == null) {
098 throw new NullArgumentException();
099 }
100 if (d.length == 0) {
101 throw new NoDataException(LocalizedFormats.AT_LEAST_ONE_ROW);
102 }
103 if (d[0].length == 0) {
104 throw new NoDataException(LocalizedFormats.AT_LEAST_ONE_COLUMN);
105 }
106 return d[0][0].getField();
107 }
108
109 /**
110 * Get the elements type from an array.
111 *
112 * @param <T> Type of the field elements.
113 * @param d Data array.
114 * @return the field to which the array elements belong.
115 * @throws NoDataException if array is empty.
116 */
117 protected static <T extends FieldElement<T>> Field<T> extractField(final T[] d) {
118 if (d.length == 0) {
119 throw new NoDataException(LocalizedFormats.AT_LEAST_ONE_ROW);
120 }
121 return d[0].getField();
122 }
123
124 /** Build an array of elements.
125 * <p>
126 * Complete arrays are filled with field.getZero()
127 * </p>
128 * @param <T> Type of the field elements
129 * @param field field to which array elements belong
130 * @param rows number of rows
131 * @param columns number of columns (may be negative to build partial
132 * arrays in the same way <code>new Field[rows][]</code> works)
133 * @return a new array
134 */
135 @SuppressWarnings("unchecked")
136 protected static <T extends FieldElement<T>> T[][] buildArray(final Field<T> field,
137 final int rows,
138 final int columns) {
139 if (columns < 0) {
140 T[] dummyRow = (T[]) Array.newInstance(field.getRuntimeClass(), 0);
141 return (T[][]) Array.newInstance(dummyRow.getClass(), rows);
142 }
143 T[][] array =
144 (T[][]) Array.newInstance(field.getRuntimeClass(), new int[] { rows, columns });
145 for (int i = 0; i < array.length; ++i) {
146 Arrays.fill(array[i], field.getZero());
147 }
148 return array;
149 }
150
151 /** Build an array of elements.
152 * <p>
153 * Arrays are filled with field.getZero()
154 * </p>
155 * @param <T> the type of the field elements
156 * @param field field to which array elements belong
157 * @param length of the array
158 * @return a new array
159 */
160 protected static <T extends FieldElement<T>> T[] buildArray(final Field<T> field,
161 final int length) {
162 @SuppressWarnings("unchecked") // OK because field must be correct class
163 T[] array = (T[]) Array.newInstance(field.getRuntimeClass(), length);
164 Arrays.fill(array, field.getZero());
165 return array;
166 }
167
168 /** {@inheritDoc} */
169 public Field<T> getField() {
170 return field;
171 }
172
173 /** {@inheritDoc} */
174 public abstract FieldMatrix<T> createMatrix(final int rowDimension, final int columnDimension);
175
176 /** {@inheritDoc} */
177 public abstract FieldMatrix<T> copy();
178
179 /** {@inheritDoc} */
180 public FieldMatrix<T> add(FieldMatrix<T> m) {
181 // safety check
182 checkAdditionCompatible(m);
183
184 final int rowCount = getRowDimension();
185 final int columnCount = getColumnDimension();
186 final FieldMatrix<T> out = createMatrix(rowCount, columnCount);
187 for (int row = 0; row < rowCount; ++row) {
188 for (int col = 0; col < columnCount; ++col) {
189 out.setEntry(row, col, getEntry(row, col).add(m.getEntry(row, col)));
190 }
191 }
192
193 return out;
194 }
195
196 /** {@inheritDoc} */
197 public FieldMatrix<T> subtract(final FieldMatrix<T> m) {
198 // safety check
199 checkSubtractionCompatible(m);
200
201 final int rowCount = getRowDimension();
202 final int columnCount = getColumnDimension();
203 final FieldMatrix<T> out = createMatrix(rowCount, columnCount);
204 for (int row = 0; row < rowCount; ++row) {
205 for (int col = 0; col < columnCount; ++col) {
206 out.setEntry(row, col, getEntry(row, col).subtract(m.getEntry(row, col)));
207 }
208 }
209
210 return out;
211 }
212
213 /** {@inheritDoc} */
214 public FieldMatrix<T> scalarAdd(final T d) {
215
216 final int rowCount = getRowDimension();
217 final int columnCount = getColumnDimension();
218 final FieldMatrix<T> out = createMatrix(rowCount, columnCount);
219 for (int row = 0; row < rowCount; ++row) {
220 for (int col = 0; col < columnCount; ++col) {
221 out.setEntry(row, col, getEntry(row, col).add(d));
222 }
223 }
224
225 return out;
226 }
227
228 /** {@inheritDoc} */
229 public FieldMatrix<T> scalarMultiply(final T d) {
230 final int rowCount = getRowDimension();
231 final int columnCount = getColumnDimension();
232 final FieldMatrix<T> out = createMatrix(rowCount, columnCount);
233 for (int row = 0; row < rowCount; ++row) {
234 for (int col = 0; col < columnCount; ++col) {
235 out.setEntry(row, col, getEntry(row, col).multiply(d));
236 }
237 }
238
239 return out;
240 }
241
242 /** {@inheritDoc} */
243 public FieldMatrix<T> multiply(final FieldMatrix<T> m) {
244 // safety check
245 checkMultiplicationCompatible(m);
246
247 final int nRows = getRowDimension();
248 final int nCols = m.getColumnDimension();
249 final int nSum = getColumnDimension();
250 final FieldMatrix<T> out = createMatrix(nRows, nCols);
251 for (int row = 0; row < nRows; ++row) {
252 for (int col = 0; col < nCols; ++col) {
253 T sum = field.getZero();
254 for (int i = 0; i < nSum; ++i) {
255 sum = sum.add(getEntry(row, i).multiply(m.getEntry(i, col)));
256 }
257 out.setEntry(row, col, sum);
258 }
259 }
260
261 return out;
262 }
263
264 /** {@inheritDoc} */
265 public FieldMatrix<T> preMultiply(final FieldMatrix<T> m) {
266 return m.multiply(this);
267 }
268
269 /** {@inheritDoc} */
270 public FieldMatrix<T> power(final int p) {
271 if (p < 0) {
272 throw new IllegalArgumentException("p must be >= 0");
273 }
274
275 if (!isSquare()) {
276 throw new NonSquareMatrixException(getRowDimension(), getColumnDimension());
277 }
278
279 if (p == 0) {
280 return MatrixUtils.createFieldIdentityMatrix(this.getField(), this.getRowDimension());
281 }
282
283 if (p == 1) {
284 return this.copy();
285 }
286
287 final int power = p - 1;
288
289 /*
290 * Only log_2(p) operations is used by doing as follows:
291 * 5^214 = 5^128 * 5^64 * 5^16 * 5^4 * 5^2
292 *
293 * In general, the same approach is used for A^p.
294 */
295
296 final char[] binaryRepresentation = Integer.toBinaryString(power)
297 .toCharArray();
298 final ArrayList<Integer> nonZeroPositions = new ArrayList<Integer>();
299
300 for (int i = 0; i < binaryRepresentation.length; ++i) {
301 if (binaryRepresentation[i] == '1') {
302 final int pos = binaryRepresentation.length - i - 1;
303 nonZeroPositions.add(pos);
304 }
305 }
306
307 ArrayList<FieldMatrix<T>> results = new ArrayList<FieldMatrix<T>>(
308 binaryRepresentation.length);
309
310 results.add(0, this.copy());
311
312 for (int i = 1; i < binaryRepresentation.length; ++i) {
313 final FieldMatrix<T> s = results.get(i - 1);
314 final FieldMatrix<T> r = s.multiply(s);
315 results.add(i, r);
316 }
317
318 FieldMatrix<T> result = this.copy();
319
320 for (Integer i : nonZeroPositions) {
321 result = result.multiply(results.get(i));
322 }
323
324 return result;
325 }
326
327 /** {@inheritDoc} */
328 public T[][] getData() {
329 final T[][] data = buildArray(field, getRowDimension(), getColumnDimension());
330
331 for (int i = 0; i < data.length; ++i) {
332 final T[] dataI = data[i];
333 for (int j = 0; j < dataI.length; ++j) {
334 dataI[j] = getEntry(i, j);
335 }
336 }
337
338 return data;
339 }
340
341 /** {@inheritDoc} */
342 public FieldMatrix<T> getSubMatrix(final int startRow, final int endRow,
343 final int startColumn, final int endColumn) {
344 checkSubMatrixIndex(startRow, endRow, startColumn, endColumn);
345
346 final FieldMatrix<T> subMatrix =
347 createMatrix(endRow - startRow + 1, endColumn - startColumn + 1);
348 for (int i = startRow; i <= endRow; ++i) {
349 for (int j = startColumn; j <= endColumn; ++j) {
350 subMatrix.setEntry(i - startRow, j - startColumn, getEntry(i, j));
351 }
352 }
353
354 return subMatrix;
355
356 }
357
358 /** {@inheritDoc} */
359 public FieldMatrix<T> getSubMatrix(final int[] selectedRows,
360 final int[] selectedColumns) {
361
362 // safety checks
363 checkSubMatrixIndex(selectedRows, selectedColumns);
364
365 // copy entries
366 final FieldMatrix<T> subMatrix =
367 createMatrix(selectedRows.length, selectedColumns.length);
368 subMatrix.walkInOptimizedOrder(new DefaultFieldMatrixChangingVisitor<T>(field.getZero()) {
369
370 /** {@inheritDoc} */
371 @Override
372 public T visit(final int row, final int column, final T value) {
373 return getEntry(selectedRows[row], selectedColumns[column]);
374 }
375
376 });
377
378 return subMatrix;
379
380 }
381
382 /** {@inheritDoc} */
383 public void copySubMatrix(final int startRow, final int endRow,
384 final int startColumn, final int endColumn,
385 final T[][] destination) {
386 // safety checks
387 checkSubMatrixIndex(startRow, endRow, startColumn, endColumn);
388 final int rowsCount = endRow + 1 - startRow;
389 final int columnsCount = endColumn + 1 - startColumn;
390 if ((destination.length < rowsCount) || (destination[0].length < columnsCount)) {
391 throw new MatrixDimensionMismatchException(destination.length,
392 destination[0].length,
393 rowsCount,
394 columnsCount);
395 }
396
397 // copy entries
398 walkInOptimizedOrder(new DefaultFieldMatrixPreservingVisitor<T>(field.getZero()) {
399
400 /** Initial row index. */
401 private int startRow;
402
403 /** Initial column index. */
404 private int startColumn;
405
406 /** {@inheritDoc} */
407 @Override
408 public void start(final int rows, final int columns,
409 final int startRow, final int endRow,
410 final int startColumn, final int endColumn) {
411 this.startRow = startRow;
412 this.startColumn = startColumn;
413 }
414
415 /** {@inheritDoc} */
416 @Override
417 public void visit(final int row, final int column, final T value) {
418 destination[row - startRow][column - startColumn] = value;
419 }
420
421 }, startRow, endRow, startColumn, endColumn);
422
423 }
424
425 /** {@inheritDoc} */
426 public void copySubMatrix(int[] selectedRows, int[] selectedColumns, T[][] destination) {
427 // safety checks
428 checkSubMatrixIndex(selectedRows, selectedColumns);
429 if ((destination.length < selectedRows.length) ||
430 (destination[0].length < selectedColumns.length)) {
431 throw new MatrixDimensionMismatchException(destination.length,
432 destination[0].length,
433 selectedRows.length,
434 selectedColumns.length);
435 }
436
437 // copy entries
438 for (int i = 0; i < selectedRows.length; i++) {
439 final T[] destinationI = destination[i];
440 for (int j = 0; j < selectedColumns.length; j++) {
441 destinationI[j] = getEntry(selectedRows[i], selectedColumns[j]);
442 }
443 }
444
445 }
446
447 /** {@inheritDoc} */
448 public void setSubMatrix(final T[][] subMatrix, final int row, final int column) {
449 if (subMatrix == null) {
450 throw new NullArgumentException();
451 }
452 final int nRows = subMatrix.length;
453 if (nRows == 0) {
454 throw new NoDataException(LocalizedFormats.AT_LEAST_ONE_ROW);
455 }
456
457 final int nCols = subMatrix[0].length;
458 if (nCols == 0) {
459 throw new NoDataException(LocalizedFormats.AT_LEAST_ONE_COLUMN);
460 }
461
462 for (int r = 1; r < nRows; ++r) {
463 if (subMatrix[r].length != nCols) {
464 throw new DimensionMismatchException(nCols, subMatrix[r].length);
465 }
466 }
467
468 checkRowIndex(row);
469 checkColumnIndex(column);
470 checkRowIndex(nRows + row - 1);
471 checkColumnIndex(nCols + column - 1);
472
473 for (int i = 0; i < nRows; ++i) {
474 for (int j = 0; j < nCols; ++j) {
475 setEntry(row + i, column + j, subMatrix[i][j]);
476 }
477 }
478 }
479
480 /** {@inheritDoc} */
481 public FieldMatrix<T> getRowMatrix(final int row) {
482 checkRowIndex(row);
483 final int nCols = getColumnDimension();
484 final FieldMatrix<T> out = createMatrix(1, nCols);
485 for (int i = 0; i < nCols; ++i) {
486 out.setEntry(0, i, getEntry(row, i));
487 }
488
489 return out;
490
491 }
492
493 /** {@inheritDoc} */
494 public void setRowMatrix(final int row, final FieldMatrix<T> matrix) {
495 checkRowIndex(row);
496 final int nCols = getColumnDimension();
497 if ((matrix.getRowDimension() != 1) ||
498 (matrix.getColumnDimension() != nCols)) {
499 throw new MatrixDimensionMismatchException(matrix.getRowDimension(),
500 matrix.getColumnDimension(),
501 1, nCols);
502 }
503 for (int i = 0; i < nCols; ++i) {
504 setEntry(row, i, matrix.getEntry(0, i));
505 }
506
507 }
508
509 /** {@inheritDoc} */
510 public FieldMatrix<T> getColumnMatrix(final int column) {
511
512 checkColumnIndex(column);
513 final int nRows = getRowDimension();
514 final FieldMatrix<T> out = createMatrix(nRows, 1);
515 for (int i = 0; i < nRows; ++i) {
516 out.setEntry(i, 0, getEntry(i, column));
517 }
518
519 return out;
520
521 }
522
523 /** {@inheritDoc} */
524 public void setColumnMatrix(final int column, final FieldMatrix<T> matrix) {
525 checkColumnIndex(column);
526 final int nRows = getRowDimension();
527 if ((matrix.getRowDimension() != nRows) ||
528 (matrix.getColumnDimension() != 1)) {
529 throw new MatrixDimensionMismatchException(matrix.getRowDimension(),
530 matrix.getColumnDimension(),
531 nRows, 1);
532 }
533 for (int i = 0; i < nRows; ++i) {
534 setEntry(i, column, matrix.getEntry(i, 0));
535 }
536
537 }
538
539 /** {@inheritDoc} */
540 public FieldVector<T> getRowVector(final int row) {
541 return new ArrayFieldVector<T>(field, getRow(row), false);
542 }
543
544 /** {@inheritDoc} */
545 public void setRowVector(final int row, final FieldVector<T> vector) {
546 checkRowIndex(row);
547 final int nCols = getColumnDimension();
548 if (vector.getDimension() != nCols) {
549 throw new MatrixDimensionMismatchException(1, vector.getDimension(),
550 1, nCols);
551 }
552 for (int i = 0; i < nCols; ++i) {
553 setEntry(row, i, vector.getEntry(i));
554 }
555
556 }
557
558 /** {@inheritDoc} */
559 public FieldVector<T> getColumnVector(final int column) {
560 return new ArrayFieldVector<T>(field, getColumn(column), false);
561 }
562
563 /** {@inheritDoc} */
564 public void setColumnVector(final int column, final FieldVector<T> vector) {
565 checkColumnIndex(column);
566 final int nRows = getRowDimension();
567 if (vector.getDimension() != nRows) {
568 throw new MatrixDimensionMismatchException(vector.getDimension(), 1,
569 nRows, 1);
570 }
571 for (int i = 0; i < nRows; ++i) {
572 setEntry(i, column, vector.getEntry(i));
573 }
574
575 }
576
577 /** {@inheritDoc} */
578 public T[] getRow(final int row) {
579 checkRowIndex(row);
580 final int nCols = getColumnDimension();
581 final T[] out = buildArray(field, nCols);
582 for (int i = 0; i < nCols; ++i) {
583 out[i] = getEntry(row, i);
584 }
585
586 return out;
587
588 }
589
590 /** {@inheritDoc} */
591 public void setRow(final int row, final T[] array) {
592 checkRowIndex(row);
593 final int nCols = getColumnDimension();
594 if (array.length != nCols) {
595 throw new MatrixDimensionMismatchException(1, array.length, 1, nCols);
596 }
597 for (int i = 0; i < nCols; ++i) {
598 setEntry(row, i, array[i]);
599 }
600
601 }
602
603 /** {@inheritDoc} */
604 public T[] getColumn(final int column) {
605 checkColumnIndex(column);
606 final int nRows = getRowDimension();
607 final T[] out = buildArray(field, nRows);
608 for (int i = 0; i < nRows; ++i) {
609 out[i] = getEntry(i, column);
610 }
611
612 return out;
613
614 }
615
616 /** {@inheritDoc} */
617 public void setColumn(final int column, final T[] array) {
618 checkColumnIndex(column);
619 final int nRows = getRowDimension();
620 if (array.length != nRows) {
621 throw new MatrixDimensionMismatchException(array.length, 1, nRows, 1);
622 }
623 for (int i = 0; i < nRows; ++i) {
624 setEntry(i, column, array[i]);
625 }
626 }
627
628 /** {@inheritDoc} */
629 public abstract T getEntry(int row, int column);
630
631 /** {@inheritDoc} */
632 public abstract void setEntry(int row, int column, T value);
633
634 /** {@inheritDoc} */
635 public abstract void addToEntry(int row, int column, T increment);
636
637 /** {@inheritDoc} */
638 public abstract void multiplyEntry(int row, int column, T factor);
639
640 /** {@inheritDoc} */
641 public FieldMatrix<T> transpose() {
642 final int nRows = getRowDimension();
643 final int nCols = getColumnDimension();
644 final FieldMatrix<T> out = createMatrix(nCols, nRows);
645 walkInOptimizedOrder(new DefaultFieldMatrixPreservingVisitor<T>(field.getZero()) {
646 /** {@inheritDoc} */
647 @Override
648 public void visit(final int row, final int column, final T value) {
649 out.setEntry(column, row, value);
650 }
651 });
652
653 return out;
654 }
655
656 /** {@inheritDoc} */
657 public boolean isSquare() {
658 return getColumnDimension() == getRowDimension();
659 }
660
661 /** {@inheritDoc} */
662 public abstract int getRowDimension();
663
664 /** {@inheritDoc} */
665 public abstract int getColumnDimension();
666
667 /** {@inheritDoc} */
668 public T getTrace() {
669 final int nRows = getRowDimension();
670 final int nCols = getColumnDimension();
671 if (nRows != nCols) {
672 throw new NonSquareMatrixException(nRows, nCols);
673 }
674 T trace = field.getZero();
675 for (int i = 0; i < nRows; ++i) {
676 trace = trace.add(getEntry(i, i));
677 }
678 return trace;
679 }
680
681 /** {@inheritDoc} */
682 public T[] operate(final T[] v) {
683
684 final int nRows = getRowDimension();
685 final int nCols = getColumnDimension();
686 if (v.length != nCols) {
687 throw new DimensionMismatchException(v.length, nCols);
688 }
689
690 final T[] out = buildArray(field, nRows);
691 for (int row = 0; row < nRows; ++row) {
692 T sum = field.getZero();
693 for (int i = 0; i < nCols; ++i) {
694 sum = sum.add(getEntry(row, i).multiply(v[i]));
695 }
696 out[row] = sum;
697 }
698
699 return out;
700 }
701
702 /** {@inheritDoc} */
703 public FieldVector<T> operate(final FieldVector<T> v) {
704 try {
705 return new ArrayFieldVector<T>(field, operate(((ArrayFieldVector<T>) v).getDataRef()), false);
706 } catch (ClassCastException cce) {
707 final int nRows = getRowDimension();
708 final int nCols = getColumnDimension();
709 if (v.getDimension() != nCols) {
710 throw new DimensionMismatchException(v.getDimension(), nCols);
711 }
712
713 final T[] out = buildArray(field, nRows);
714 for (int row = 0; row < nRows; ++row) {
715 T sum = field.getZero();
716 for (int i = 0; i < nCols; ++i) {
717 sum = sum.add(getEntry(row, i).multiply(v.getEntry(i)));
718 }
719 out[row] = sum;
720 }
721
722 return new ArrayFieldVector<T>(field, out, false);
723 }
724 }
725
726 /** {@inheritDoc} */
727 public T[] preMultiply(final T[] v) {
728
729 final int nRows = getRowDimension();
730 final int nCols = getColumnDimension();
731 if (v.length != nRows) {
732 throw new DimensionMismatchException(v.length, nRows);
733 }
734
735 final T[] out = buildArray(field, nCols);
736 for (int col = 0; col < nCols; ++col) {
737 T sum = field.getZero();
738 for (int i = 0; i < nRows; ++i) {
739 sum = sum.add(getEntry(i, col).multiply(v[i]));
740 }
741 out[col] = sum;
742 }
743
744 return out;
745 }
746
747 /** {@inheritDoc} */
748 public FieldVector<T> preMultiply(final FieldVector<T> v) {
749 try {
750 return new ArrayFieldVector<T>(field, preMultiply(((ArrayFieldVector<T>) v).getDataRef()), false);
751 } catch (ClassCastException cce) {
752 final int nRows = getRowDimension();
753 final int nCols = getColumnDimension();
754 if (v.getDimension() != nRows) {
755 throw new DimensionMismatchException(v.getDimension(), nRows);
756 }
757
758 final T[] out = buildArray(field, nCols);
759 for (int col = 0; col < nCols; ++col) {
760 T sum = field.getZero();
761 for (int i = 0; i < nRows; ++i) {
762 sum = sum.add(getEntry(i, col).multiply(v.getEntry(i)));
763 }
764 out[col] = sum;
765 }
766
767 return new ArrayFieldVector<T>(field, out, false);
768 }
769 }
770
771 /** {@inheritDoc} */
772 public T walkInRowOrder(final FieldMatrixChangingVisitor<T> visitor) {
773 final int rows = getRowDimension();
774 final int columns = getColumnDimension();
775 visitor.start(rows, columns, 0, rows - 1, 0, columns - 1);
776 for (int row = 0; row < rows; ++row) {
777 for (int column = 0; column < columns; ++column) {
778 final T oldValue = getEntry(row, column);
779 final T newValue = visitor.visit(row, column, oldValue);
780 setEntry(row, column, newValue);
781 }
782 }
783 return visitor.end();
784 }
785
786 /** {@inheritDoc} */
787 public T walkInRowOrder(final FieldMatrixPreservingVisitor<T> visitor) {
788 final int rows = getRowDimension();
789 final int columns = getColumnDimension();
790 visitor.start(rows, columns, 0, rows - 1, 0, columns - 1);
791 for (int row = 0; row < rows; ++row) {
792 for (int column = 0; column < columns; ++column) {
793 visitor.visit(row, column, getEntry(row, column));
794 }
795 }
796 return visitor.end();
797 }
798
799 /** {@inheritDoc} */
800 public T walkInRowOrder(final FieldMatrixChangingVisitor<T> visitor,
801 final int startRow, final int endRow,
802 final int startColumn, final int endColumn) {
803 checkSubMatrixIndex(startRow, endRow, startColumn, endColumn);
804 visitor.start(getRowDimension(), getColumnDimension(),
805 startRow, endRow, startColumn, endColumn);
806 for (int row = startRow; row <= endRow; ++row) {
807 for (int column = startColumn; column <= endColumn; ++column) {
808 final T oldValue = getEntry(row, column);
809 final T newValue = visitor.visit(row, column, oldValue);
810 setEntry(row, column, newValue);
811 }
812 }
813 return visitor.end();
814 }
815
816 /** {@inheritDoc} */
817 public T walkInRowOrder(final FieldMatrixPreservingVisitor<T> visitor,
818 final int startRow, final int endRow,
819 final int startColumn, final int endColumn) {
820 checkSubMatrixIndex(startRow, endRow, startColumn, endColumn);
821 visitor.start(getRowDimension(), getColumnDimension(),
822 startRow, endRow, startColumn, endColumn);
823 for (int row = startRow; row <= endRow; ++row) {
824 for (int column = startColumn; column <= endColumn; ++column) {
825 visitor.visit(row, column, getEntry(row, column));
826 }
827 }
828 return visitor.end();
829 }
830
831 /** {@inheritDoc} */
832 public T walkInColumnOrder(final FieldMatrixChangingVisitor<T> visitor) {
833 final int rows = getRowDimension();
834 final int columns = getColumnDimension();
835 visitor.start(rows, columns, 0, rows - 1, 0, columns - 1);
836 for (int column = 0; column < columns; ++column) {
837 for (int row = 0; row < rows; ++row) {
838 final T oldValue = getEntry(row, column);
839 final T newValue = visitor.visit(row, column, oldValue);
840 setEntry(row, column, newValue);
841 }
842 }
843 return visitor.end();
844 }
845
846 /** {@inheritDoc} */
847 public T walkInColumnOrder(final FieldMatrixPreservingVisitor<T> visitor) {
848 final int rows = getRowDimension();
849 final int columns = getColumnDimension();
850 visitor.start(rows, columns, 0, rows - 1, 0, columns - 1);
851 for (int column = 0; column < columns; ++column) {
852 for (int row = 0; row < rows; ++row) {
853 visitor.visit(row, column, getEntry(row, column));
854 }
855 }
856 return visitor.end();
857 }
858
859 /** {@inheritDoc} */
860 public T walkInColumnOrder(final FieldMatrixChangingVisitor<T> visitor,
861 final int startRow, final int endRow,
862 final int startColumn, final int endColumn) {
863 checkSubMatrixIndex(startRow, endRow, startColumn, endColumn);
864 visitor.start(getRowDimension(), getColumnDimension(),
865 startRow, endRow, startColumn, endColumn);
866 for (int column = startColumn; column <= endColumn; ++column) {
867 for (int row = startRow; row <= endRow; ++row) {
868 final T oldValue = getEntry(row, column);
869 final T newValue = visitor.visit(row, column, oldValue);
870 setEntry(row, column, newValue);
871 }
872 }
873 return visitor.end();
874 }
875
876 /** {@inheritDoc} */
877 public T walkInColumnOrder(final FieldMatrixPreservingVisitor<T> visitor,
878 final int startRow, final int endRow,
879 final int startColumn, final int endColumn) {
880 checkSubMatrixIndex(startRow, endRow, startColumn, endColumn);
881 visitor.start(getRowDimension(), getColumnDimension(),
882 startRow, endRow, startColumn, endColumn);
883 for (int column = startColumn; column <= endColumn; ++column) {
884 for (int row = startRow; row <= endRow; ++row) {
885 visitor.visit(row, column, getEntry(row, column));
886 }
887 }
888 return visitor.end();
889 }
890
891 /** {@inheritDoc} */
892 public T walkInOptimizedOrder(final FieldMatrixChangingVisitor<T> visitor) {
893 return walkInRowOrder(visitor);
894 }
895
896 /** {@inheritDoc} */
897 public T walkInOptimizedOrder(final FieldMatrixPreservingVisitor<T> visitor) {
898 return walkInRowOrder(visitor);
899 }
900
901 /** {@inheritDoc} */
902 public T walkInOptimizedOrder(final FieldMatrixChangingVisitor<T> visitor,
903 final int startRow, final int endRow,
904 final int startColumn, final int endColumn) {
905 return walkInRowOrder(visitor, startRow, endRow, startColumn, endColumn);
906 }
907
908 /** {@inheritDoc} */
909 public T walkInOptimizedOrder(final FieldMatrixPreservingVisitor<T> visitor,
910 final int startRow, final int endRow,
911 final int startColumn, final int endColumn) {
912 return walkInRowOrder(visitor, startRow, endRow, startColumn, endColumn);
913 }
914
915 /**
916 * Get a string representation for this matrix.
917 * @return a string representation for this matrix
918 */
919 @Override
920 public String toString() {
921 final int nRows = getRowDimension();
922 final int nCols = getColumnDimension();
923 final StringBuffer res = new StringBuffer();
924 String fullClassName = getClass().getName();
925 String shortClassName = fullClassName.substring(fullClassName.lastIndexOf('.') + 1);
926 res.append(shortClassName).append("{");
927
928 for (int i = 0; i < nRows; ++i) {
929 if (i > 0) {
930 res.append(",");
931 }
932 res.append("{");
933 for (int j = 0; j < nCols; ++j) {
934 if (j > 0) {
935 res.append(",");
936 }
937 res.append(getEntry(i, j));
938 }
939 res.append("}");
940 }
941
942 res.append("}");
943 return res.toString();
944 }
945
946 /**
947 * Returns true iff <code>object</code> is a
948 * <code>FieldMatrix</code> instance with the same dimensions as this
949 * and all corresponding matrix entries are equal.
950 *
951 * @param object the object to test equality against.
952 * @return true if object equals this
953 */
954 @Override
955 public boolean equals(final Object object) {
956 if (object == this ) {
957 return true;
958 }
959 if (object instanceof FieldMatrix<?> == false) {
960 return false;
961 }
962 FieldMatrix<?> m = (FieldMatrix<?>) object;
963 final int nRows = getRowDimension();
964 final int nCols = getColumnDimension();
965 if (m.getColumnDimension() != nCols || m.getRowDimension() != nRows) {
966 return false;
967 }
968 for (int row = 0; row < nRows; ++row) {
969 for (int col = 0; col < nCols; ++col) {
970 if (!getEntry(row, col).equals(m.getEntry(row, col))) {
971 return false;
972 }
973 }
974 }
975 return true;
976 }
977
978 /**
979 * Computes a hashcode for the matrix.
980 *
981 * @return hashcode for matrix
982 */
983 @Override
984 public int hashCode() {
985 int ret = 322562;
986 final int nRows = getRowDimension();
987 final int nCols = getColumnDimension();
988 ret = ret * 31 + nRows;
989 ret = ret * 31 + nCols;
990 for (int row = 0; row < nRows; ++row) {
991 for (int col = 0; col < nCols; ++col) {
992 ret = ret * 31 + (11 * (row+1) + 17 * (col+1)) * getEntry(row, col).hashCode();
993 }
994 }
995 return ret;
996 }
997
998 /**
999 * Check if a row index is valid.
1000 *
1001 * @param row Row index to check.
1002 * @throws OutOfRangeException if {@code index} is not valid.
1003 */
1004 protected void checkRowIndex(final int row) {
1005 if (row < 0 || row >= getRowDimension()) {
1006 throw new OutOfRangeException(LocalizedFormats.ROW_INDEX,
1007 row, 0, getRowDimension() - 1);
1008 }
1009 }
1010
1011 /**
1012 * Check if a column index is valid.
1013 *
1014 * @param column Column index to check.
1015 * @throws OutOfRangeException if {@code index} is not valid.
1016 */
1017 protected void checkColumnIndex(final int column) {
1018 if (column < 0 || column >= getColumnDimension()) {
1019 throw new OutOfRangeException(LocalizedFormats.COLUMN_INDEX,
1020 column, 0, getColumnDimension() - 1);
1021 }
1022 }
1023
1024 /**
1025 * Check if submatrix ranges indices are valid.
1026 * Rows and columns are indicated counting from 0 to n-1.
1027 *
1028 * @param startRow Initial row index.
1029 * @param endRow Final row index.
1030 * @param startColumn Initial column index.
1031 * @param endColumn Final column index.
1032 * @throws OutOfRangeException if the indices are not valid.
1033 * @throws NumberIsTooSmallException if {@code endRow < startRow} or
1034 * {@code endColumn < startColumn}.
1035 */
1036 protected void checkSubMatrixIndex(final int startRow, final int endRow,
1037 final int startColumn, final int endColumn) {
1038 checkRowIndex(startRow);
1039 checkRowIndex(endRow);
1040 if (endRow < startRow) {
1041 throw new NumberIsTooSmallException(LocalizedFormats.INITIAL_ROW_AFTER_FINAL_ROW,
1042 endRow, startRow, true);
1043 }
1044
1045 checkColumnIndex(startColumn);
1046 checkColumnIndex(endColumn);
1047 if (endColumn < startColumn) {
1048 throw new NumberIsTooSmallException(LocalizedFormats.INITIAL_COLUMN_AFTER_FINAL_COLUMN,
1049 endColumn, startColumn, true);
1050 }
1051 }
1052
1053 /**
1054 * Check if submatrix ranges indices are valid.
1055 * Rows and columns are indicated counting from 0 to n-1.
1056 *
1057 * @param selectedRows Array of row indices.
1058 * @param selectedColumns Array of column indices.
1059 * @throws NullArgumentException if the arrays are {@code null}.
1060 * @throws NoDataException if the arrays have zero length.
1061 * @throws OutOfRangeException if row or column selections are not valid.
1062 */
1063 protected void checkSubMatrixIndex(final int[] selectedRows, final int[] selectedColumns) {
1064 if (selectedRows == null ||
1065 selectedColumns == null) {
1066 throw new NullArgumentException();
1067 }
1068 if (selectedRows.length == 0 ||
1069 selectedColumns.length == 0) {
1070 throw new NoDataException();
1071 }
1072
1073 for (final int row : selectedRows) {
1074 checkRowIndex(row);
1075 }
1076 for (final int column : selectedColumns) {
1077 checkColumnIndex(column);
1078 }
1079 }
1080
1081 /**
1082 * Check if a matrix is addition compatible with the instance.
1083 *
1084 * @param m Matrix to check.
1085 * @throws MatrixDimensionMismatchException if the matrix is not
1086 * addition-compatible with instance.
1087 */
1088 protected void checkAdditionCompatible(final FieldMatrix<T> m) {
1089 if ((getRowDimension() != m.getRowDimension()) ||
1090 (getColumnDimension() != m.getColumnDimension())) {
1091 throw new MatrixDimensionMismatchException(m.getRowDimension(), m.getColumnDimension(),
1092 getRowDimension(), getColumnDimension());
1093 }
1094 }
1095
1096 /**
1097 * Check if a matrix is subtraction compatible with the instance.
1098 *
1099 * @param m Matrix to check.
1100 * @throws MatrixDimensionMismatchException if the matrix is not
1101 * subtraction-compatible with instance.
1102 */
1103 protected void checkSubtractionCompatible(final FieldMatrix<T> m) {
1104 if ((getRowDimension() != m.getRowDimension()) ||
1105 (getColumnDimension() != m.getColumnDimension())) {
1106 throw new MatrixDimensionMismatchException(m.getRowDimension(), m.getColumnDimension(),
1107 getRowDimension(), getColumnDimension());
1108 }
1109 }
1110
1111 /**
1112 * Check if a matrix is multiplication compatible with the instance.
1113 *
1114 * @param m Matrix to check.
1115 * @throws DimensionMismatchException if the matrix is not
1116 * multiplication-compatible with instance.
1117 */
1118 protected void checkMultiplicationCompatible(final FieldMatrix<T> m) {
1119 if (getColumnDimension() != m.getRowDimension()) {
1120 throw new DimensionMismatchException(m.getRowDimension(), getColumnDimension());
1121 }
1122 }
1123 }