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