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