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