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