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