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