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