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.io.Serializable;
26  import org.hipparchus.Field;
27  import org.hipparchus.FieldElement;
28  import org.hipparchus.exception.LocalizedCoreFormats;
29  import org.hipparchus.exception.MathIllegalArgumentException;
30  import org.hipparchus.exception.MathIllegalStateException;
31  import org.hipparchus.exception.NullArgumentException;
32  import org.hipparchus.util.MathArrays;
33  import org.hipparchus.util.MathUtils;
34  
35  /**
36   * Implementation of {@link FieldMatrix} using a {@link FieldElement}[][] array to store entries.
37   * <p>
38   * As specified in the {@link FieldMatrix} interface, matrix element indexing
39   * is 0-based -- e.g., {@code getEntry(0, 0)}
40   * returns the element in the first row, first column of the matrix
41   * </p>
42   *
43   * @param <T> the type of the field elements
44   */
45  public class Array2DRowFieldMatrix<T extends FieldElement<T>>
46      extends AbstractFieldMatrix<T>
47      implements Serializable {
48      /** Serializable version identifier */
49      private static final long serialVersionUID = 7260756672015356458L;
50      /** Entries of the matrix */
51      private T[][] data;
52  
53      /**
54       * Creates a matrix with no data
55       * @param field field to which the elements belong
56       */
57      public Array2DRowFieldMatrix(final Field<T> field) {
58          super(field);
59      }
60  
61      /**
62       * Create a new {@code FieldMatrix<T>} with the supplied row and column dimensions.
63       *
64       * @param field Field to which the elements belong.
65       * @param rowDimension Number of rows in the new matrix.
66       * @param columnDimension Number of columns in the new matrix.
67       * @throws MathIllegalArgumentException if row or column dimension is not positive.
68       */
69      public Array2DRowFieldMatrix(final Field<T> field, final int rowDimension,
70                                   final int columnDimension)
71          throws MathIllegalArgumentException {
72          super(field, rowDimension, columnDimension);
73          data = MathArrays.buildArray(field, rowDimension, columnDimension);
74      }
75  
76      /**
77       * Create a new {@code FieldMatrix<T>} using the input array as the underlying
78       * data array.
79       * <p>The input array is copied, not referenced. This constructor has
80       * the same effect as calling {@link #Array2DRowFieldMatrix(FieldElement[][], boolean)}
81       * with the second argument set to {@code true}.</p>
82       *
83       * @param d Data for the new matrix.
84       * @throws MathIllegalArgumentException if {@code d} is not rectangular.
85       * @throws NullArgumentException if {@code d} is {@code null}.
86       * @throws MathIllegalArgumentException if there are not at least one row and one column.
87       * @see #Array2DRowFieldMatrix(FieldElement[][], boolean)
88       */
89      public Array2DRowFieldMatrix(final T[][] d)
90          throws MathIllegalArgumentException, NullArgumentException {
91          this(extractField(d), d);
92      }
93  
94      /**
95       * Create a new {@code FieldMatrix<T>} using the input array as the underlying
96       * data array.
97       * <p>The input array is copied, not referenced. This constructor has
98       * the same effect as calling {@link #Array2DRowFieldMatrix(FieldElement[][], boolean)}
99       * with the second argument set to {@code true}.</p>
100      *
101      * @param field Field to which the elements belong.
102      * @param d Data for the new matrix.
103      * @throws MathIllegalArgumentException if {@code d} is not rectangular.
104      * @throws NullArgumentException if {@code d} is {@code null}.
105      * @throws MathIllegalArgumentException if there are not at least one row and one column.
106      * @see #Array2DRowFieldMatrix(FieldElement[][], boolean)
107      */
108     public Array2DRowFieldMatrix(final Field<T> field, final T[][] d)
109         throws MathIllegalArgumentException, NullArgumentException {
110         super(field);
111         copyIn(d);
112     }
113 
114     /**
115      * Create a new {@code FieldMatrix<T>} using the input array as the underlying
116      * data array.
117      * <p>If an array is built specially in order to be embedded in a
118      * {@code FieldMatrix<T>} and not used directly, the {@code copyArray} may be
119      * set to {@code false}. This will prevent the copying and improve
120      * performance as no new array will be built and no data will be copied.</p>
121      *
122      * @param d Data for the new matrix.
123      * @param copyArray Whether to copy or reference the input array.
124      * @throws MathIllegalArgumentException if {@code d} is not rectangular.
125      * @throws MathIllegalArgumentException if there are not at least one row and one column.
126      * @throws NullArgumentException if {@code d} is {@code null}.
127      * @see #Array2DRowFieldMatrix(FieldElement[][])
128      */
129     public Array2DRowFieldMatrix(final T[][] d, final boolean copyArray)
130         throws MathIllegalArgumentException,
131         NullArgumentException {
132         this(extractField(d), d, copyArray);
133     }
134 
135     /**
136      * Create a new {@code FieldMatrix<T>} using the input array as the underlying
137      * data array.
138      * <p>If an array is built specially in order to be embedded in a
139      * {@code FieldMatrix<T>} and not used directly, the {@code copyArray} may be
140      * set to {@code false}. This will prevent the copying and improve
141      * performance as no new array will be built and no data will be copied.</p>
142      *
143      * @param field Field to which the elements belong.
144      * @param d Data for the new matrix.
145      * @param copyArray Whether to copy or reference the input array.
146      * @throws MathIllegalArgumentException if {@code d} is not rectangular.
147      * @throws MathIllegalArgumentException if there are not at least one row and one column.
148      * @throws NullArgumentException if {@code d} is {@code null}.
149      * @see #Array2DRowFieldMatrix(FieldElement[][])
150      */
151     public Array2DRowFieldMatrix(final Field<T> field, final T[][] d, final boolean copyArray)
152         throws MathIllegalArgumentException, NullArgumentException {
153         super(field);
154         if (copyArray) {
155             copyIn(d);
156         } else {
157             MathUtils.checkNotNull(d);
158             final int nRows = d.length;
159             if (nRows == 0) {
160                 throw new MathIllegalArgumentException(LocalizedCoreFormats.AT_LEAST_ONE_ROW);
161             }
162             final int nCols = d[0].length;
163             if (nCols == 0) {
164                 throw new MathIllegalArgumentException(LocalizedCoreFormats.AT_LEAST_ONE_COLUMN);
165             }
166             for (int r = 1; r < nRows; r++) {
167                 if (d[r].length != nCols) {
168                     throw new MathIllegalArgumentException(LocalizedCoreFormats.DIMENSIONS_MISMATCH,
169                                                            nCols, d[r].length);
170                 }
171             }
172             data = d; // NOPMD - array copy is taken care of by parameter
173         }
174     }
175 
176     /**
177      * Create a new (column) {@code FieldMatrix<T>} using {@code v} as the
178      * data for the unique column of the created matrix.
179      * The input array is copied.
180      *
181      * @param v Column vector holding data for new matrix.
182      * @throws MathIllegalArgumentException if v is empty
183      */
184     public Array2DRowFieldMatrix(final T[] v) throws MathIllegalArgumentException {
185         this(extractField(v), v);
186     }
187 
188     /**
189      * Create a new (column) {@code FieldMatrix<T>} using {@code v} as the
190      * data for the unique column of the created matrix.
191      * The input array is copied.
192      *
193      * @param field Field to which the elements belong.
194      * @param v Column vector holding data for new matrix.
195      */
196     public Array2DRowFieldMatrix(final Field<T> field, final T[] v) {
197         super(field);
198         final int nRows = v.length;
199         data = MathArrays.buildArray(getField(), nRows, 1);
200         for (int row = 0; row < nRows; row++) {
201             data[row][0] = v[row];
202         }
203     }
204 
205     /** {@inheritDoc} */
206     @Override
207     public FieldMatrix<T> createMatrix(final int rowDimension,
208                                        final int columnDimension)
209         throws MathIllegalArgumentException {
210         return new Array2DRowFieldMatrix<T>(getField(), rowDimension, columnDimension);
211     }
212 
213     /** {@inheritDoc} */
214     @Override
215     public FieldMatrix<T> copy() {
216         return new Array2DRowFieldMatrix<T>(getField(), copyOut(), false);
217     }
218 
219     /**
220      * Add {@code m} to this matrix.
221      *
222      * @param m Matrix to be added.
223      * @return {@code this} + m.
224      * @throws MathIllegalArgumentException if {@code m} is not the same
225      * size as this matrix.
226      */
227     public Array2DRowFieldMatrix<T> add(final Array2DRowFieldMatrix<T> m)
228         throws MathIllegalArgumentException {
229         // safety check
230         checkAdditionCompatible(m);
231 
232         final int rowCount    = getRowDimension();
233         final int columnCount = getColumnDimension();
234         final T[][] outData = MathArrays.buildArray(getField(), rowCount, columnCount);
235         for (int row = 0; row < rowCount; row++) {
236             final T[] dataRow    = data[row];
237             final T[] mRow       = m.data[row];
238             final T[] outDataRow = outData[row];
239             for (int col = 0; col < columnCount; col++) {
240                 outDataRow[col] = dataRow[col].add(mRow[col]);
241             }
242         }
243 
244         return new Array2DRowFieldMatrix<T>(getField(), outData, false);
245     }
246 
247     /**
248      * Subtract {@code m} from this matrix.
249      *
250      * @param m Matrix to be subtracted.
251      * @return {@code this} + m.
252      * @throws MathIllegalArgumentException if {@code m} is not the same
253      * size as this matrix.
254      */
255     public Array2DRowFieldMatrix<T> subtract(final Array2DRowFieldMatrix<T> m)
256         throws MathIllegalArgumentException {
257         // safety check
258         checkSubtractionCompatible(m);
259 
260         final int rowCount    = getRowDimension();
261         final int columnCount = getColumnDimension();
262         final T[][] outData = MathArrays.buildArray(getField(), rowCount, columnCount);
263         for (int row = 0; row < rowCount; row++) {
264             final T[] dataRow    = data[row];
265             final T[] mRow       = m.data[row];
266             final T[] outDataRow = outData[row];
267             for (int col = 0; col < columnCount; col++) {
268                 outDataRow[col] = dataRow[col].subtract(mRow[col]);
269             }
270         }
271 
272         return new Array2DRowFieldMatrix<T>(getField(), outData, false);
273 
274     }
275 
276     /**
277      * Postmultiplying this matrix by {@code m}.
278      *
279      * @param m Matrix to postmultiply by.
280      * @return {@code this} * m.
281      * @throws MathIllegalArgumentException if the number of columns of this
282      * matrix is not equal to the number of rows of {@code m}.
283      */
284     public Array2DRowFieldMatrix<T> multiply(final Array2DRowFieldMatrix<T> m)
285         throws MathIllegalArgumentException {
286         // safety check
287         checkMultiplicationCompatible(m);
288 
289         final int nRows = this.getRowDimension();
290         final int nCols = m.getColumnDimension();
291         final int nSum = this.getColumnDimension();
292         final T[][] outData = MathArrays.buildArray(getField(), nRows, nCols);
293         for (int row = 0; row < nRows; row++) {
294             final T[] dataRow    = data[row];
295             final T[] outDataRow = outData[row];
296             for (int col = 0; col < nCols; col++) {
297                 T sum = getField().getZero();
298                 for (int i = 0; i < nSum; i++) {
299                     sum = sum.add(dataRow[i].multiply(m.data[i][col]));
300                 }
301                 outDataRow[col] = sum;
302             }
303         }
304 
305         return new Array2DRowFieldMatrix<T>(getField(), outData, false);
306 
307     }
308 
309     /**
310      * Returns the result of postmultiplying {@code this} by {@code m^T}.
311      * @param m matrix to first transpose and second postmultiply by
312      * @return {@code this * m^T}
313      * @throws MathIllegalArgumentException if
314      * {@code columnDimension(this) != columnDimension(m)}
315      * @since 1.3
316      */
317     public FieldMatrix<T> multiplyTransposed(final Array2DRowFieldMatrix<T> m)
318         throws MathIllegalArgumentException {
319         MatrixUtils.checkSameColumnDimension(this, m);
320 
321         final int nRows = this.getRowDimension();
322         final int nCols = m.getRowDimension();
323         final int nSum  = this.getColumnDimension();
324 
325         final FieldMatrix<T> out   = MatrixUtils.createFieldMatrix(getField(), nRows, nCols);
326         final T[][]          mData = m.data;
327 
328         // Multiply.
329         for (int col = 0; col < nCols; col++) {
330             for (int row = 0; row < nRows; row++) {
331                 final T[] dataRow = data[row];
332                 final T[] mRow    = mData[col];
333                 T sum = getField().getZero();
334                 for (int i = 0; i < nSum; i++) {
335                     sum = sum.add(dataRow[i].multiply(mRow[i]));
336                 }
337                 out.setEntry(row, col, sum);
338             }
339         }
340 
341         return out;
342 
343     }
344 
345     /** {@inheritDoc} */
346     @Override
347     public FieldMatrix<T> multiplyTransposed(final FieldMatrix<T> m) {
348         if (m instanceof Array2DRowFieldMatrix) {
349             return multiplyTransposed((Array2DRowFieldMatrix<T>) m);
350         } else {
351             MatrixUtils.checkSameColumnDimension(this, m);
352 
353             final int nRows = this.getRowDimension();
354             final int nCols = m.getRowDimension();
355             final int nSum  = this.getColumnDimension();
356 
357             final FieldMatrix<T> out = MatrixUtils.createFieldMatrix(getField(), nRows, nCols);
358 
359             // Multiply.
360             for (int col = 0; col < nCols; col++) {
361                 for (int row = 0; row < nRows; row++) {
362                     final T[] dataRow = data[row];
363                     T sum = getField().getZero();
364                     for (int i = 0; i < nSum; i++) {
365                         sum = sum.add(dataRow[i].multiply(m.getEntry(col, i)));
366                     }
367                     out.setEntry(row, col, sum);
368                 }
369             }
370 
371             return out;
372 
373         }
374     }
375 
376     /**
377      * Returns the result of postmultiplying {@code this^T} by {@code m}.
378      * @param m matrix to postmultiply by
379      * @return {@code this^T * m}
380      * @throws MathIllegalArgumentException if
381      * {@code columnDimension(this) != columnDimension(m)}
382      * @since 1.3
383      */
384     public FieldMatrix<T> transposeMultiply(final Array2DRowFieldMatrix<T> m)
385         throws MathIllegalArgumentException {
386         MatrixUtils.checkSameRowDimension(this, m);
387 
388         final int nRows = this.getColumnDimension();
389         final int nCols = m.getColumnDimension();
390         final int nSum  = this.getRowDimension();
391 
392         final FieldMatrix<T> out   = MatrixUtils.createFieldMatrix(getField(), nRows, nCols);
393         final T[][]          mData = m.data;
394 
395         // Multiply.
396         for (int k = 0; k < nSum; k++) {
397             final T[] dataK = data[k];
398             final T[] mK    = mData[k];
399             for (int row = 0; row < nRows; row++) {
400                 final T dataIRow = dataK[row];
401                 for (int col = 0; col < nCols; col++) {
402                     out.addToEntry(row, col, dataIRow.multiply(mK[col]));
403                 }
404             }
405         }
406 
407         return out;
408     }
409 
410     /** {@inheritDoc} */
411     @Override
412     public FieldMatrix<T> transposeMultiply(final FieldMatrix<T> m) {
413         if (m instanceof Array2DRowFieldMatrix) {
414             return transposeMultiply((Array2DRowFieldMatrix<T>) m);
415         } else {
416             MatrixUtils.checkSameRowDimension(this, m);
417 
418             final int nRows = this.getColumnDimension();
419             final int nCols = m.getColumnDimension();
420             final int nSum  = this.getRowDimension();
421 
422             final FieldMatrix<T> out = MatrixUtils.createFieldMatrix(getField(), nRows, nCols);
423 
424             // Multiply.
425             for (int k = 0; k < nSum; k++) {
426                 final T[] dataK = data[k];
427                 for (int row = 0; row < nRows; row++) {
428                     final T dataIRow = dataK[row];
429                     for (int col = 0; col < nCols; col++) {
430                         out.addToEntry(row, col, dataIRow.multiply(m.getEntry(k, col)));
431                     }
432                 }
433             }
434 
435             return out;
436 
437         }
438     }
439 
440     /** {@inheritDoc} */
441     @Override
442     public T[][] getData() {
443         return copyOut();
444     }
445 
446     /**
447      * Get a reference to the underlying data array.
448      * This methods returns internal data, <strong>not</strong> fresh copy of it.
449      *
450      * @return the 2-dimensional array of entries.
451      */
452     public T[][] getDataRef() {
453         return data; // NOPMD - returning an internal array is intentional and documented here
454     }
455 
456     /** {@inheritDoc} */
457     @Override
458     public void setSubMatrix(final T[][] subMatrix, final int row,
459                              final int column)
460         throws MathIllegalArgumentException, NullArgumentException {
461         if (data == null) {
462             if (row > 0) {
463                 throw new MathIllegalStateException(LocalizedCoreFormats.FIRST_ROWS_NOT_INITIALIZED_YET, row);
464             }
465             if (column > 0) {
466                 throw new MathIllegalStateException(LocalizedCoreFormats.FIRST_COLUMNS_NOT_INITIALIZED_YET, column);
467             }
468             final int nRows = subMatrix.length;
469             if (nRows == 0) {
470                 throw new MathIllegalArgumentException(LocalizedCoreFormats.AT_LEAST_ONE_ROW);
471             }
472 
473             final int nCols = subMatrix[0].length;
474             if (nCols == 0) {
475                 throw new MathIllegalArgumentException(LocalizedCoreFormats.AT_LEAST_ONE_COLUMN);
476             }
477             data = MathArrays.buildArray(getField(), subMatrix.length, nCols);
478             for (int i = 0; i < data.length; ++i) {
479                 if (subMatrix[i].length != nCols) {
480                     throw new MathIllegalArgumentException(LocalizedCoreFormats.DIMENSIONS_MISMATCH,
481                                                            nCols, subMatrix[i].length);
482                 }
483                 System.arraycopy(subMatrix[i], 0, data[i + row], column, nCols);
484             }
485         } else {
486             super.setSubMatrix(subMatrix, row, column);
487         }
488 
489     }
490 
491     /** {@inheritDoc} */
492     @Override
493     public T getEntry(final int row, final int column)
494         throws MathIllegalArgumentException {
495       try {
496         return data[row][column];
497       } catch (IndexOutOfBoundsException e) {
498         // throw the exact cause of the exception
499         checkRowIndex(row);
500         checkColumnIndex(column);
501         // should never happen
502         throw e;
503       }
504     }
505 
506     /** {@inheritDoc} */
507     @Override
508     public void setEntry(final int row, final int column, final T value)
509         throws MathIllegalArgumentException {
510         checkRowIndex(row);
511         checkColumnIndex(column);
512 
513         data[row][column] = value;
514     }
515 
516     /** {@inheritDoc} */
517     @Override
518     public void addToEntry(final int row, final int column, final T increment)
519         throws MathIllegalArgumentException {
520         checkRowIndex(row);
521         checkColumnIndex(column);
522 
523         data[row][column] = data[row][column].add(increment);
524     }
525 
526     /** {@inheritDoc} */
527     @Override
528     public void multiplyEntry(final int row, final int column, final T factor)
529         throws MathIllegalArgumentException {
530         checkRowIndex(row);
531         checkColumnIndex(column);
532 
533         data[row][column] = data[row][column].multiply(factor);
534     }
535 
536     /** {@inheritDoc} */
537     @Override
538     public int getRowDimension() {
539         return (data == null) ? 0 : data.length;
540     }
541 
542     /** {@inheritDoc} */
543     @Override
544     public int getColumnDimension() {
545         return ((data == null) || (data[0] == null)) ? 0 : data[0].length;
546     }
547 
548     /** {@inheritDoc} */
549     @Override
550     public T[] operate(final T[] v) throws MathIllegalArgumentException {
551         final int nRows = this.getRowDimension();
552         final int nCols = this.getColumnDimension();
553         if (v.length != nCols) {
554             throw new MathIllegalArgumentException(LocalizedCoreFormats.DIMENSIONS_MISMATCH,
555                                                    v.length, nCols);
556         }
557         final T[] out = MathArrays.buildArray(getField(), nRows);
558         for (int row = 0; row < nRows; row++) {
559             final T[] dataRow = data[row];
560             T sum = getField().getZero();
561             for (int i = 0; i < nCols; i++) {
562                 sum = sum.add(dataRow[i].multiply(v[i]));
563             }
564             out[row] = sum;
565         }
566         return out;
567     }
568 
569     /** {@inheritDoc} */
570     @Override
571     public T[] preMultiply(final T[] v) throws MathIllegalArgumentException {
572         final int nRows = getRowDimension();
573         final int nCols = getColumnDimension();
574         if (v.length != nRows) {
575             throw new MathIllegalArgumentException(LocalizedCoreFormats.DIMENSIONS_MISMATCH,
576                                                    v.length, nRows);
577         }
578 
579         final T[] out = MathArrays.buildArray(getField(), nCols);
580         for (int col = 0; col < nCols; ++col) {
581             T sum = getField().getZero();
582             for (int i = 0; i < nRows; ++i) {
583                 sum = sum.add(data[i][col].multiply(v[i]));
584             }
585             out[col] = sum;
586         }
587 
588         return out;
589     }
590 
591     /** {@inheritDoc} */
592     @Override
593     public FieldMatrix<T> getSubMatrix(final int startRow, final int endRow,
594                                        final int startColumn, final int endColumn)
595         throws MathIllegalArgumentException {
596         MatrixUtils.checkSubMatrixIndex(this, startRow, endRow, startColumn, endColumn);
597         final int rowCount = endRow - startRow + 1;
598         final int columnCount = endColumn - startColumn + 1;
599         final T[][] outData = MathArrays.buildArray(getField(), rowCount, columnCount);
600         for (int i = 0; i < rowCount; ++i) {
601             System.arraycopy(data[startRow + i], startColumn, outData[i], 0, columnCount);
602         }
603 
604         Array2DRowFieldMatrix<T> subMatrix = new Array2DRowFieldMatrix<>(getField());
605         subMatrix.data = outData;
606         return subMatrix;
607     }
608 
609     /** {@inheritDoc} */
610     @Override
611     public T walkInRowOrder(final FieldMatrixChangingVisitor<T> visitor) {
612         final int rows    = getRowDimension();
613         final int columns = getColumnDimension();
614         visitor.start(rows, columns, 0, rows - 1, 0, columns - 1);
615         for (int i = 0; i < rows; ++i) {
616             final T[] rowI = data[i];
617             for (int j = 0; j < columns; ++j) {
618                 rowI[j] = visitor.visit(i, j, rowI[j]);
619             }
620         }
621         return visitor.end();
622     }
623 
624     /** {@inheritDoc} */
625     @Override
626     public T walkInRowOrder(final FieldMatrixPreservingVisitor<T> visitor) {
627         final int rows    = getRowDimension();
628         final int columns = getColumnDimension();
629         visitor.start(rows, columns, 0, rows - 1, 0, columns - 1);
630         for (int i = 0; i < rows; ++i) {
631             final T[] rowI = data[i];
632             for (int j = 0; j < columns; ++j) {
633                 visitor.visit(i, j, rowI[j]);
634             }
635         }
636         return visitor.end();
637     }
638 
639     /** {@inheritDoc} */
640     @Override
641     public T walkInRowOrder(final FieldMatrixChangingVisitor<T> visitor,
642                             final int startRow, final int endRow,
643                             final int startColumn, final int endColumn)
644         throws MathIllegalArgumentException {
645         checkSubMatrixIndex(startRow, endRow, startColumn, endColumn);
646         visitor.start(getRowDimension(), getColumnDimension(),
647                       startRow, endRow, startColumn, endColumn);
648         for (int i = startRow; i <= endRow; ++i) {
649             final T[] rowI = data[i];
650             for (int j = startColumn; j <= endColumn; ++j) {
651                 rowI[j] = visitor.visit(i, j, rowI[j]);
652             }
653         }
654         return visitor.end();
655     }
656 
657     /** {@inheritDoc} */
658     @Override
659     public T walkInRowOrder(final FieldMatrixPreservingVisitor<T> visitor,
660                             final int startRow, final int endRow,
661                             final int startColumn, final int endColumn)
662         throws MathIllegalArgumentException {
663         checkSubMatrixIndex(startRow, endRow, startColumn, endColumn);
664         visitor.start(getRowDimension(), getColumnDimension(),
665                       startRow, endRow, startColumn, endColumn);
666         for (int i = startRow; i <= endRow; ++i) {
667             final T[] rowI = data[i];
668             for (int j = startColumn; j <= endColumn; ++j) {
669                 visitor.visit(i, j, rowI[j]);
670             }
671         }
672         return visitor.end();
673     }
674 
675     /** {@inheritDoc} */
676     @Override
677     public T walkInColumnOrder(final FieldMatrixChangingVisitor<T> visitor) {
678         final int rows    = getRowDimension();
679         final int columns = getColumnDimension();
680         visitor.start(rows, columns, 0, rows - 1, 0, columns - 1);
681         for (int j = 0; j < columns; ++j) {
682             for (int i = 0; i < rows; ++i) {
683                 final T[] rowI = data[i];
684                 rowI[j] = visitor.visit(i, j, rowI[j]);
685             }
686         }
687         return visitor.end();
688     }
689 
690     /** {@inheritDoc} */
691     @Override
692     public T walkInColumnOrder(final FieldMatrixPreservingVisitor<T> visitor) {
693         final int rows    = getRowDimension();
694         final int columns = getColumnDimension();
695         visitor.start(rows, columns, 0, rows - 1, 0, columns - 1);
696         for (int j = 0; j < columns; ++j) {
697             for (int i = 0; i < rows; ++i) {
698                 visitor.visit(i, j, data[i][j]);
699             }
700         }
701         return visitor.end();
702     }
703 
704     /** {@inheritDoc} */
705     @Override
706     public T walkInColumnOrder(final FieldMatrixChangingVisitor<T> visitor,
707                                final int startRow, final int endRow,
708                                final int startColumn, final int endColumn)
709         throws MathIllegalArgumentException {
710     checkSubMatrixIndex(startRow, endRow, startColumn, endColumn);
711         visitor.start(getRowDimension(), getColumnDimension(),
712                       startRow, endRow, startColumn, endColumn);
713         for (int j = startColumn; j <= endColumn; ++j) {
714             for (int i = startRow; i <= endRow; ++i) {
715                 final T[] rowI = data[i];
716                 rowI[j] = visitor.visit(i, j, rowI[j]);
717             }
718         }
719         return visitor.end();
720     }
721 
722     /** {@inheritDoc} */
723     @Override
724     public T walkInColumnOrder(final FieldMatrixPreservingVisitor<T> visitor,
725                                final int startRow, final int endRow,
726                                final int startColumn, final int endColumn)
727         throws MathIllegalArgumentException {
728         checkSubMatrixIndex(startRow, endRow, startColumn, endColumn);
729         visitor.start(getRowDimension(), getColumnDimension(),
730                       startRow, endRow, startColumn, endColumn);
731         for (int j = startColumn; j <= endColumn; ++j) {
732             for (int i = startRow; i <= endRow; ++i) {
733                 visitor.visit(i, j, data[i][j]);
734             }
735         }
736         return visitor.end();
737     }
738 
739     /**
740      * Get a fresh copy of the underlying data array.
741      *
742      * @return a copy of the underlying data array.
743      */
744     private T[][] copyOut() {
745         final int nRows = this.getRowDimension();
746         final T[][] out = MathArrays.buildArray(getField(), nRows, getColumnDimension());
747         // can't copy 2-d array in one shot, otherwise get row references
748         for (int i = 0; i < nRows; i++) {
749             System.arraycopy(data[i], 0, out[i], 0, data[i].length);
750         }
751         return out;
752     }
753 
754     /**
755      * Replace data with a fresh copy of the input array.
756      *
757      * @param in Data to copy.
758      * @throws MathIllegalArgumentException if the input array is empty.
759      * @throws MathIllegalArgumentException if the input array is not rectangular.
760      * @throws NullArgumentException if the input array is {@code null}.
761      */
762     private void copyIn(final T[][] in)
763         throws MathIllegalArgumentException, NullArgumentException {
764         setSubMatrix(in, 0, 0);
765     }
766 
767     /** {@inheritDoc} */
768     @Override
769     public T[] getRow(final int row) throws MathIllegalArgumentException {
770         MatrixUtils.checkRowIndex(this, row);
771         final int nCols = getColumnDimension();
772         final T[] out = MathArrays.buildArray(getField(), nCols);
773         System.arraycopy(data[row], 0, out, 0, nCols);
774         return out;
775     }
776 
777     /** {@inheritDoc} */
778     @Override
779     public void setRow(final int row, final T[] array)
780         throws MathIllegalArgumentException {
781         MatrixUtils.checkRowIndex(this, row);
782         final int nCols = getColumnDimension();
783         if (array.length != nCols) {
784             throw new MathIllegalArgumentException(LocalizedCoreFormats.DIMENSIONS_MISMATCH_2x2,
785                                                    1, array.length, 1, nCols);
786         }
787         System.arraycopy(array, 0, data[row], 0, nCols);
788     }
789 
790 }