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