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