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