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