001    /*
002     * Licensed to the Apache Software Foundation (ASF) under one or more
003     * contributor license agreements.  See the NOTICE file distributed with
004     * this work for additional information regarding copyright ownership.
005     * The ASF licenses this file to You under the Apache License, Version 2.0
006     * (the "License"); you may not use this file except in compliance with
007     * the License.  You may obtain a copy of the License at
008     *
009     *      http://www.apache.org/licenses/LICENSE-2.0
010     *
011     * Unless required by applicable law or agreed to in writing, software
012     * distributed under the License is distributed on an "AS IS" BASIS,
013     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014     * See the License for the specific language governing permissions and
015     * limitations under the License.
016     */
017    
018    package org.apache.commons.math.linear;
019    
020    import java.lang.reflect.Array;
021    import java.util.Arrays;
022    
023    import org.apache.commons.math.Field;
024    import org.apache.commons.math.FieldElement;
025    import org.apache.commons.math.MathRuntimeException;
026    
027    /**
028     * Basic implementation of {@link FieldMatrix} methods regardless of the underlying storage.
029     * <p>All the methods implemented here use {@link #getEntry(int, int)} to access
030     * matrix elements. Derived class can provide faster implementations. </p>
031     *
032     * @param <T> the type of the field elements
033     * @version $Revision: 783702 $ $Date: 2009-06-11 04:54:02 -0400 (Thu, 11 Jun 2009) $
034     * @since 2.0
035     */
036    public abstract class AbstractFieldMatrix<T extends FieldElement<T>> implements FieldMatrix<T> {
037        
038        /** Field to which the elements belong. */
039        private final Field<T> field;
040    
041        /**
042         * Get the elements type from an array.
043         * @param <T> the type of the field elements
044         * @param d data array
045         * @return field to which array elements belong
046         * @exception IllegalArgumentException if array is empty
047         */
048        protected static <T extends FieldElement<T>> Field<T> extractField(final T[][] d)
049            throws IllegalArgumentException {
050            if (d.length == 0) {
051                throw MathRuntimeException.createIllegalArgumentException("matrix must have at least one row"); 
052            }
053            if (d[0].length == 0) {
054                throw MathRuntimeException.createIllegalArgumentException("matrix must have at least one column"); 
055            }
056            return d[0][0].getField();
057        }
058    
059        /**
060         * Get the elements type from an array.
061         * @param <T> the type of the field elements
062         * @param d data array
063         * @return field to which array elements belong
064         * @exception IllegalArgumentException if array is empty
065         */
066        protected static <T extends FieldElement<T>> Field<T> extractField(final T[] d)
067            throws IllegalArgumentException {
068            if (d.length == 0) {
069                throw MathRuntimeException.createIllegalArgumentException("matrix must have at least one row"); 
070            }
071            return d[0].getField();
072        }
073    
074        /** Build an array of elements.
075         * <p>
076         * Complete arrays are filled with field.getZero()
077         * </p>
078         * @param <T> the type of the field elements
079         * @param field field to which array elements belong
080         * @param rows number of rows
081         * @param columns number of columns (may be negative to build partial
082         * arrays in the same way <code>new Field[rows][]</code> works)
083         * @return a new array
084         */
085        @SuppressWarnings("unchecked")
086        protected static <T extends FieldElement<T>> T[][] buildArray(final Field<T> field,
087                                                                      final int rows,
088                                                                      final int columns) {
089            if (columns < 0) {
090                T[] dummyRow = (T[]) Array.newInstance(field.getZero().getClass(), 0); 
091                return (T[][]) Array.newInstance(dummyRow.getClass(), rows);            
092            }
093            T[][] array =
094                (T[][]) Array.newInstance(field.getZero().getClass(), new int[] { rows, columns });
095            for (int i = 0; i < array.length; ++i) {
096                Arrays.fill(array[i], field.getZero());
097            }
098            return array;
099        }
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    }