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