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    import org.apache.commons.math.linear.MatrixVisitorException;
027    import org.apache.commons.math.exception.util.LocalizedFormats;
028    
029    /**
030     * Basic implementation of {@link FieldMatrix} methods regardless of the underlying storage.
031     * <p>All the methods implemented here use {@link #getEntry(int, int)} to access
032     * matrix elements. Derived class can provide faster implementations. </p>
033     *
034     * @param <T> the type of the field elements
035     * @version $Revision: 1073158 $ $Date: 2011-02-21 22:46:52 +0100 (lun. 21 f??vr. 2011) $
036     * @since 2.0
037     */
038    public abstract class AbstractFieldMatrix<T extends FieldElement<T>> implements FieldMatrix<T> {
039    
040        /** Field to which the elements belong. */
041        private final Field<T> field;
042    
043        /**
044         * Constructor for use with Serializable
045         */
046        protected AbstractFieldMatrix() {
047            field = null;
048        }
049    
050        /**
051         * Creates a matrix with no data
052         * @param field field to which the elements belong
053         */
054        protected AbstractFieldMatrix(final Field<T> field) {
055            this.field = field;
056        }
057    
058        /**
059         * Create a new FieldMatrix<T> with the supplied row and column dimensions.
060         *
061         * @param field field to which the elements belong
062         * @param rowDimension  the number of rows in the new matrix
063         * @param columnDimension  the number of columns in the new matrix
064         * @throws IllegalArgumentException if row or column dimension is not positive
065         */
066        protected AbstractFieldMatrix(final Field<T> field,
067                                      final int rowDimension, final int columnDimension)
068            throws IllegalArgumentException {
069            if (rowDimension < 1 ) {
070                throw MathRuntimeException.createIllegalArgumentException(
071                        LocalizedFormats.INSUFFICIENT_DIMENSION, rowDimension, 1);
072            }
073            if (columnDimension < 1) {
074                throw MathRuntimeException.createIllegalArgumentException(
075                        LocalizedFormats.INSUFFICIENT_DIMENSION, columnDimension, 1);
076            }
077            this.field = field;
078        }
079    
080        /**
081         * Get the elements type from an array.
082         * @param <T> the type of the field elements
083         * @param d data array
084         * @return field to which array elements belong
085         * @exception IllegalArgumentException if array is empty
086         */
087        protected static <T extends FieldElement<T>> Field<T> extractField(final T[][] d)
088            throws IllegalArgumentException {
089            if (d.length == 0) {
090                throw MathRuntimeException.createIllegalArgumentException(LocalizedFormats.AT_LEAST_ONE_ROW);
091            }
092            if (d[0].length == 0) {
093                throw MathRuntimeException.createIllegalArgumentException(LocalizedFormats.AT_LEAST_ONE_COLUMN);
094            }
095            return d[0][0].getField();
096        }
097    
098        /**
099         * Get the elements type from an array.
100         * @param <T> the type of the field elements
101         * @param d data array
102         * @return field to which array elements belong
103         * @exception IllegalArgumentException if array is empty
104         */
105        protected static <T extends FieldElement<T>> Field<T> extractField(final T[] d)
106            throws IllegalArgumentException {
107            if (d.length == 0) {
108                throw MathRuntimeException.createIllegalArgumentException(LocalizedFormats.AT_LEAST_ONE_ROW);
109            }
110            return d[0].getField();
111        }
112    
113        /** Build an array of elements.
114         * <p>
115         * Complete arrays are filled with field.getZero()
116         * </p>
117         * @param <T> the type of the field elements
118         * @param field field to which array elements belong
119         * @param rows number of rows
120         * @param columns number of columns (may be negative to build partial
121         * arrays in the same way <code>new Field[rows][]</code> works)
122         * @return a new array
123         */
124        @SuppressWarnings("unchecked")
125        protected static <T extends FieldElement<T>> T[][] buildArray(final Field<T> field,
126                                                                      final int rows,
127                                                                      final int columns) {
128            if (columns < 0) {
129                T[] dummyRow = (T[]) Array.newInstance(field.getZero().getClass(), 0);
130                return (T[][]) Array.newInstance(dummyRow.getClass(), rows);
131            }
132            T[][] array =
133                (T[][]) Array.newInstance(field.getZero().getClass(), new int[] { rows, columns });
134            for (int i = 0; i < array.length; ++i) {
135                Arrays.fill(array[i], field.getZero());
136            }
137            return array;
138        }
139    
140        /** Build an array of elements.
141         * <p>
142         * Arrays are filled with field.getZero()
143         * </p>
144         * @param <T> the type of the field elements
145         * @param field field to which array elements belong
146         * @param length of the array
147         * @return a new array
148         */
149        protected static <T extends FieldElement<T>> T[] buildArray(final Field<T> field,
150                                                                    final int length) {
151            @SuppressWarnings("unchecked") // OK because field must be correct class
152            T[] array = (T[]) Array.newInstance(field.getZero().getClass(), length);
153            Arrays.fill(array, field.getZero());
154            return array;
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                        LocalizedFormats.DIMENSIONS_MISMATCH_2x2,
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                        LocalizedFormats.DIMENSIONS_MISMATCH_2x2,
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(LocalizedFormats.AT_LEAST_ONE_ROW);
405            }
406    
407            final int nCols = subMatrix[0].length;
408            if (nCols == 0) {
409                throw MathRuntimeException.createIllegalArgumentException(LocalizedFormats.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                            LocalizedFormats.DIFFERENT_ROWS_LENGTHS,
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                        LocalizedFormats.DIMENSIONS_MISMATCH_2x2,
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                        LocalizedFormats.DIMENSIONS_MISMATCH_2x2,
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                        LocalizedFormats.DIMENSIONS_MISMATCH_2x2,
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                        LocalizedFormats.DIMENSIONS_MISMATCH_2x2,
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                        LocalizedFormats.DIMENSIONS_MISMATCH_2x2,
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                        LocalizedFormats.DIMENSIONS_MISMATCH_2x2,
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                        LocalizedFormats.VECTOR_LENGTH_MISMATCH,
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                            LocalizedFormats.VECTOR_LENGTH_MISMATCH,
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                        LocalizedFormats.VECTOR_LENGTH_MISMATCH,
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                            LocalizedFormats.VECTOR_LENGTH_MISMATCH,
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 StringBuilder res = new StringBuilder();
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        @Override
974        public boolean equals(final Object object) {
975            if (object == this ) {
976                return true;
977            }
978            if (object instanceof FieldMatrix<?> == false) {
979                return false;
980            }
981            FieldMatrix<?> m = (FieldMatrix<?>) object;
982            final int nRows = getRowDimension();
983            final int nCols = getColumnDimension();
984            if (m.getColumnDimension() != nCols || m.getRowDimension() != nRows) {
985                return false;
986            }
987            for (int row = 0; row < nRows; ++row) {
988                for (int col = 0; col < nCols; ++col) {
989                    if (!getEntry(row, col).equals(m.getEntry(row, col))) {
990                        return false;
991                    }
992                }
993            }
994            return true;
995        }
996    
997        /**
998         * Computes a hashcode for the matrix.
999         *
1000         * @return hashcode for matrix
1001         */
1002        @Override
1003        public int hashCode() {
1004            int ret = 322562;
1005            final int nRows = getRowDimension();
1006            final int nCols = getColumnDimension();
1007            ret = ret * 31 + nRows;
1008            ret = ret * 31 + nCols;
1009            for (int row = 0; row < nRows; ++row) {
1010                for (int col = 0; col < nCols; ++col) {
1011                   ret = ret * 31 + (11 * (row+1) + 17 * (col+1)) * getEntry(row, col).hashCode();
1012               }
1013            }
1014            return ret;
1015        }
1016    
1017        /**
1018         * Check if a row index is valid.
1019         * @param row row index to check
1020         * @exception MatrixIndexException if index is not valid
1021         */
1022        protected void checkRowIndex(final int row) {
1023            if (row < 0 || row >= getRowDimension()) {
1024                throw new MatrixIndexException(LocalizedFormats.ROW_INDEX_OUT_OF_RANGE,
1025                                               row, 0, getRowDimension() - 1);
1026            }
1027        }
1028    
1029        /**
1030         * Check if a column index is valid.
1031         * @param column column index to check
1032         * @exception MatrixIndexException if index is not valid
1033         */
1034        protected void checkColumnIndex(final int column)
1035            throws MatrixIndexException {
1036            if (column < 0 || column >= getColumnDimension()) {
1037                throw new MatrixIndexException(LocalizedFormats.COLUMN_INDEX_OUT_OF_RANGE,
1038                                               column, 0, getColumnDimension() - 1);
1039            }
1040        }
1041    
1042        /**
1043         * Check if submatrix ranges indices are valid.
1044         * Rows and columns are indicated counting from 0 to n-1.
1045         *
1046         * @param startRow Initial row index
1047         * @param endRow Final row index
1048         * @param startColumn Initial column index
1049         * @param endColumn Final column index
1050         * @exception MatrixIndexException  if the indices are not valid
1051         */
1052        protected void checkSubMatrixIndex(final int startRow, final int endRow,
1053                                           final int startColumn, final int endColumn) {
1054            checkRowIndex(startRow);
1055            checkRowIndex(endRow);
1056            if (startRow > endRow) {
1057                throw new MatrixIndexException(LocalizedFormats.INITIAL_ROW_AFTER_FINAL_ROW,
1058                                               startRow, endRow);
1059            }
1060    
1061            checkColumnIndex(startColumn);
1062            checkColumnIndex(endColumn);
1063            if (startColumn > endColumn) {
1064                throw new MatrixIndexException(LocalizedFormats.INITIAL_COLUMN_AFTER_FINAL_COLUMN,
1065                                               startColumn, endColumn);
1066            }
1067    
1068    
1069        }
1070    
1071        /**
1072         * Check if submatrix ranges indices are valid.
1073         * Rows and columns are indicated counting from 0 to n-1.
1074         *
1075         * @param selectedRows Array of row indices.
1076         * @param selectedColumns Array of column indices.
1077         * @exception MatrixIndexException if row or column selections are not valid
1078         */
1079        protected void checkSubMatrixIndex(final int[] selectedRows, final int[] selectedColumns) {
1080            if (selectedRows.length * selectedColumns.length == 0) {
1081                if (selectedRows.length == 0) {
1082                    throw new MatrixIndexException(LocalizedFormats.EMPTY_SELECTED_ROW_INDEX_ARRAY);
1083                }
1084                throw new MatrixIndexException(LocalizedFormats.EMPTY_SELECTED_COLUMN_INDEX_ARRAY);
1085            }
1086    
1087            for (final int row : selectedRows) {
1088                checkRowIndex(row);
1089            }
1090            for (final int column : selectedColumns) {
1091                checkColumnIndex(column);
1092            }
1093        }
1094    
1095        /**
1096         * Check if a matrix is addition compatible with the instance
1097         * @param m matrix to check
1098         * @exception IllegalArgumentException if matrix is not addition compatible with instance
1099         */
1100        protected void checkAdditionCompatible(final FieldMatrix<T> m) {
1101            if ((getRowDimension()    != m.getRowDimension()) ||
1102                (getColumnDimension() != m.getColumnDimension())) {
1103                throw MathRuntimeException.createIllegalArgumentException(
1104                        LocalizedFormats.NOT_ADDITION_COMPATIBLE_MATRICES,
1105                        getRowDimension(), getColumnDimension(),
1106                        m.getRowDimension(), m.getColumnDimension());
1107            }
1108        }
1109    
1110        /**
1111         * Check if a matrix is subtraction compatible with the instance
1112         * @param m matrix to check
1113         * @exception IllegalArgumentException if matrix is not subtraction compatible with instance
1114         */
1115        protected void checkSubtractionCompatible(final FieldMatrix<T> m) {
1116            if ((getRowDimension()    != m.getRowDimension()) ||
1117                (getColumnDimension() != m.getColumnDimension())) {
1118                throw MathRuntimeException.createIllegalArgumentException(
1119                        LocalizedFormats.NOT_SUBTRACTION_COMPATIBLE_MATRICES,
1120                        getRowDimension(), getColumnDimension(),
1121                        m.getRowDimension(), m.getColumnDimension());
1122            }
1123        }
1124    
1125        /**
1126         * Check if a matrix is multiplication compatible with the instance
1127         * @param m matrix to check
1128         * @exception IllegalArgumentException if matrix is not multiplication compatible with instance
1129         */
1130        protected void checkMultiplicationCompatible(final FieldMatrix<T> m) {
1131            if (getColumnDimension() != m.getRowDimension()) {
1132                throw MathRuntimeException.createIllegalArgumentException(
1133                        LocalizedFormats.NOT_MULTIPLICATION_COMPATIBLE_MATRICES,
1134                        getRowDimension(), getColumnDimension(),
1135                        m.getRowDimension(), m.getColumnDimension());
1136            }
1137        }
1138    
1139    }