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