    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.io.Serializable;
    021
    022    import org.apache.commons.math.Field;
    023    import org.apache.commons.math.FieldElement;
    024    import org.apache.commons.math.MathRuntimeException;
    025    import org.apache.commons.math.linear.MatrixVisitorException;
    026    import org.apache.commons.math.exception.util.LocalizedFormats;
    027
    028    /**
    029     * Implementation of FieldMatrix<T> using a {@link FieldElement}[][] array to store entries.
    030     * <p>
    031     * As specified in the {@link FieldMatrix} interface, matrix element indexing
    032     * is 0-based -- e.g., <code>getEntry(0, 0)</code>
    033     * returns the element in the first row, first column of the matrix.</li></ul>
    034     * </p>
    035     *
    036     * @param <T> the type of the field elements
    037     * @version $Revision: 1073158 $ $Date: 2011-02-21 22:46:52 +0100 (lun. 21 f??vr. 2011) $
    038     */
    039    public class Array2DRowFieldMatrix<T extends FieldElement<T>> extends AbstractFieldMatrix<T> implements Serializable {
    040
    041        /** Serializable version identifier */
    042        private static final long serialVersionUID = 7260756672015356458L;
    043
    044        /** Entries of the matrix */
    045        protected T[][] data;
    046
    047        /**
    048         * Creates a matrix with no data
    049         * @param field field to which the elements belong
    050         */
    051        public Array2DRowFieldMatrix(final Field<T> field) {
    052            super(field);
    053        }
    054
    055        /**
    056         * Create a new FieldMatrix<T> with the supplied row and column dimensions.
    057         *
    058         * @param field field to which the elements belong
    059         * @param rowDimension  the number of rows in the new matrix
    060         * @param columnDimension  the number of columns in the new matrix
    061         * @throws IllegalArgumentException if row or column dimension is not
    062         *  positive
    063         */
    064        public Array2DRowFieldMatrix(final Field<T> field,
    065                               final int rowDimension, final int columnDimension)
    066            throws IllegalArgumentException {
    067            super(field, rowDimension, columnDimension);
    068            data = buildArray(field, rowDimension, columnDimension);
    069        }
    070
    071        /**
    072         * Create a new FieldMatrix<T> using the input array as the underlying
    073         * data array.
    074         * <p>The input array is copied, not referenced. This constructor has
    075         * the same effect as calling {@link #Array2DRowFieldMatrix(FieldElement[][], boolean)}
    076         * with the second argument set to <code>true</code>.</p>
    077         *
    078         * @param d data for new matrix
    079         * @throws IllegalArgumentException if <code>d</code> is not rectangular
    080         *  (not all rows have the same length) or empty
    081         * @throws NullPointerException if <code>d</code> is null
    082         * @see #Array2DRowFieldMatrix(FieldElement[][], boolean)
    083         */
    084        public Array2DRowFieldMatrix(final T[][] d)
    085            throws IllegalArgumentException, NullPointerException {
    086            super(extractField(d));
    087            copyIn(d);
    088        }
    089
    090        /**
    091         * Create a new FieldMatrix<T> using the input array as the underlying
    092         * data array.
    093         * <p>If an array is built specially in order to be embedded in a
    094         * FieldMatrix<T> and not used directly, the <code>copyArray</code> may be
    095         * set to <code>false</code. This will prevent the copying and improve
    096         * performance as no new array will be built and no data will be copied.</p>
    097         * @param d data for new matrix
    098         * @param copyArray if true, the input array will be copied, otherwise
    099         * it will be referenced
    100         * @throws IllegalArgumentException if <code>d</code> is not rectangular
    101         *  (not all rows have the same length) or empty
    102         * @throws NullPointerException if <code>d</code> is null
    103         * @see #Array2DRowFieldMatrix(FieldElement[][])
    104         */
    105        public Array2DRowFieldMatrix(final T[][] d, final boolean copyArray)
    106            throws IllegalArgumentException, NullPointerException {
    107            super(extractField(d));
    108            if (copyArray) {
    109                copyIn(d);
    110            } else {
    111                if (d == null) {
    112                    throw new NullPointerException();
    113                }
    114                final int nRows = d.length;
    115                if (nRows == 0) {
    116                    throw MathRuntimeException.createIllegalArgumentException(
    117                          LocalizedFormats.AT_LEAST_ONE_ROW);
    118                }
    119                final int nCols = d[0].length;
    120                if (nCols == 0) {
    121                    throw MathRuntimeException.createIllegalArgumentException(
    122                          LocalizedFormats.AT_LEAST_ONE_COLUMN);
    123                }
    124                for (int r = 1; r < nRows; r++) {
    125                    if (d[r].length != nCols) {
    126                        throw MathRuntimeException.createIllegalArgumentException(
    127                              LocalizedFormats.DIFFERENT_ROWS_LENGTHS, nCols, d[r].length);
    128                    }
    129                }
    130                data = d;
    131            }
    132        }
    133
    134        /**
    135         * Create a new (column) FieldMatrix<T> using <code>v</code> as the
    136         * data for the unique column of the <code>v.length x 1</code> matrix
    137         * created.
    138         * <p>The input array is copied, not referenced.</p>
    139         *
    140         * @param v column vector holding data for new matrix
    141         */
    142        public Array2DRowFieldMatrix(final T[] v) {
    143            super(extractField(v));
    144            final int nRows = v.length;
    145            data = buildArray(getField(), nRows, 1);
    146            for (int row = 0; row < nRows; row++) {
    147                data[row][0] = v[row];
    148            }
    149        }
    150
    151        /** {@inheritDoc} */
    152        @Override
    153        public FieldMatrix<T> createMatrix(final int rowDimension, final int columnDimension)
    154            throws IllegalArgumentException {
    155            return new Array2DRowFieldMatrix<T>(getField(), rowDimension, columnDimension);
    156        }
    157
    158        /** {@inheritDoc} */
    159        @Override
    160        public FieldMatrix<T> copy() {
    161            return new Array2DRowFieldMatrix<T>(copyOut(), false);
    162        }
    163
    164        /** {@inheritDoc} */
    165        @Override
    166        public FieldMatrix<T> add(final FieldMatrix<T> m)
    167            throws IllegalArgumentException {
    168            try {
    169                return add((Array2DRowFieldMatrix<T>) m);
    170            } catch (ClassCastException cce) {
    171                return super.add(m);
    172            }
    173        }
    174
    175        /**
    176         * Compute the sum of this and <code>m</code>.
    177         *
    178         * @param m    matrix to be added
    179         * @return     this + m
    180         * @throws  IllegalArgumentException if m is not the same size as this
    181         */
    182        public Array2DRowFieldMatrix<T> add(final Array2DRowFieldMatrix<T> m)
    183            throws IllegalArgumentException {
    184
    185            // safety check
    186            checkAdditionCompatible(m);
    187
    188            final int rowCount    = getRowDimension();
    189            final int columnCount = getColumnDimension();
    190            final T[][] outData = buildArray(getField(), rowCount, columnCount);
    191            for (int row = 0; row < rowCount; row++) {
    192                final T[] dataRow    = data[row];
    193                final T[] mRow       = m.data[row];
    194                final T[] outDataRow = outData[row];
    195                for (int col = 0; col < columnCount; col++) {
    196                    outDataRow[col] = dataRow[col].add(mRow[col]);
    197                }
    198            }
    199
    200            return new Array2DRowFieldMatrix<T>(outData, false);
    201
    202        }
    203
    204        /** {@inheritDoc} */
    205        @Override
    206        public FieldMatrix<T> subtract(final FieldMatrix<T> m)
    207            throws IllegalArgumentException {
    208            try {
    209                return subtract((Array2DRowFieldMatrix<T>) m);
    210            } catch (ClassCastException cce) {
    211                return super.subtract(m);
    212            }
    213        }
    214
    215        /**
    216         * Compute  this minus <code>m</code>.
    217         *
    218         * @param m    matrix to be subtracted
    219         * @return     this + m
    220         * @throws  IllegalArgumentException if m is not the same size as this
    221         */
    222        public Array2DRowFieldMatrix<T> subtract(final Array2DRowFieldMatrix<T> m)
    223            throws IllegalArgumentException {
    224
    225            // safety check
    226            checkSubtractionCompatible(m);
    227
    228            final int rowCount    = getRowDimension();
    229            final int columnCount = getColumnDimension();
    230            final T[][] outData = buildArray(getField(), rowCount, columnCount);
    231            for (int row = 0; row < rowCount; row++) {
    232                final T[] dataRow    = data[row];
    233                final T[] mRow       = m.data[row];
    234                final T[] outDataRow = outData[row];
    235                for (int col = 0; col < columnCount; col++) {
    236                    outDataRow[col] = dataRow[col].subtract(mRow[col]);
    237                }
    238            }
    239
    240            return new Array2DRowFieldMatrix<T>(outData, false);
    241
    242        }
    243
    244        /** {@inheritDoc} */
    245        @Override
    246        public FieldMatrix<T> multiply(final FieldMatrix<T> m)
    247            throws IllegalArgumentException {
    248            try {
    249                return multiply((Array2DRowFieldMatrix<T>) m);
    250            } catch (ClassCastException cce) {
    251                return super.multiply(m);
    252            }
    253        }
    254
    255        /**
    256         * Returns the result of postmultiplying this by <code>m</code>.
    257         * @param m    matrix to postmultiply by
    258         * @return     this*m
    259         * @throws     IllegalArgumentException
    260         *             if columnDimension(this) != rowDimension(m)
    261         */
    262        public Array2DRowFieldMatrix<T> multiply(final Array2DRowFieldMatrix<T> m)
    263            throws IllegalArgumentException {
    264
    265            // safety check
    266            checkMultiplicationCompatible(m);
    267
    268            final int nRows = this.getRowDimension();
    269            final int nCols = m.getColumnDimension();
    270            final int nSum = this.getColumnDimension();
    271            final T[][] outData = buildArray(getField(), nRows, nCols);
    272            for (int row = 0; row < nRows; row++) {
    273                final T[] dataRow    = data[row];
    274                final T[] outDataRow = outData[row];
    275                for (int col = 0; col < nCols; col++) {
    276                    T sum = getField().getZero();
    277                    for (int i = 0; i < nSum; i++) {
    278                        sum = sum.add(dataRow[i].multiply(m.data[i][col]));
    279                    }
    280                    outDataRow[col] = sum;
    281                }
    282            }
    283
    284            return new Array2DRowFieldMatrix<T>(outData, false);
    285
    286        }
    287
    288        /** {@inheritDoc} */
    289        @Override
    290        public T[][] getData() {
    291            return copyOut();
    292        }
    293
    294        /**
    295         * Returns a reference to the underlying data array.
    296         * <p>
    297         * Does <strong>not</strong> make a fresh copy of the underlying data.</p>
    298         *
    299         * @return 2-dimensional array of entries
    300         */
    301        public T[][] getDataRef() {
    302            return data;
    303        }
    304
    305        /** {@inheritDoc} */
    306        @Override
    307        public void setSubMatrix(final T[][] subMatrix, final int row, final int column)
    308        throws MatrixIndexException {
    309            if (data == null) {
    310                if (row > 0) {
    311                    throw MathRuntimeException.createIllegalStateException(
    312                          LocalizedFormats.FIRST_ROWS_NOT_INITIALIZED_YET, row);
    313                }
    314                if (column > 0) {
    315                    throw MathRuntimeException.createIllegalStateException(
    316                          LocalizedFormats.FIRST_COLUMNS_NOT_INITIALIZED_YET, column);
    317                }
    318                final int nRows = subMatrix.length;
    319                if (nRows == 0) {
    320                    throw MathRuntimeException.createIllegalArgumentException(
    321                          LocalizedFormats.AT_LEAST_ONE_ROW);
    322                }
    323
    324                final int nCols = subMatrix[0].length;
    325                if (nCols == 0) {
    326                    throw MathRuntimeException.createIllegalArgumentException(
    327                          LocalizedFormats.AT_LEAST_ONE_COLUMN);
    328                }
    329                data = buildArray(getField(), subMatrix.length, nCols);
    330                for (int i = 0; i < data.length; ++i) {
    331                    if (subMatrix[i].length != nCols) {
    332                        throw MathRuntimeException.createIllegalArgumentException(
    333                              LocalizedFormats.DIFFERENT_ROWS_LENGTHS, nCols, subMatrix[i].length);
    334                    }
    335                    System.arraycopy(subMatrix[i], 0, data[i + row], column, nCols);
    336                }
    337            } else {
    338                super.setSubMatrix(subMatrix, row, column);
    339            }
    340
    341        }
    342
    343        /** {@inheritDoc} */
    344        @Override
    345        public T getEntry(final int row, final int column)
    346            throws MatrixIndexException {
    347            try {
    348                return data[row][column];
    349            } catch (ArrayIndexOutOfBoundsException e) {
    350                throw new MatrixIndexException(
    351                          LocalizedFormats.NO_SUCH_MATRIX_ENTRY, row, column, getRowDimension(), getColumnDimension());
    352            }
    353        }
    354
    355        /** {@inheritDoc} */
    356        @Override
    357        public void setEntry(final int row, final int column, final T value)
    358            throws MatrixIndexException {
    359            try {
    360                data[row][column] = value;
    361            } catch (ArrayIndexOutOfBoundsException e) {
    362                throw new MatrixIndexException(
    363                          LocalizedFormats.NO_SUCH_MATRIX_ENTRY, row, column, getRowDimension(), getColumnDimension());
    364            }
    365        }
    366
    367        /** {@inheritDoc} */
    368        @Override
    369        public void addToEntry(final int row, final int column, final T increment)
    370            throws MatrixIndexException {
    371            try {
    372                data[row][column] = data[row][column].add(increment);
    373            } catch (ArrayIndexOutOfBoundsException e) {
    374                throw new MatrixIndexException(
    375                          LocalizedFormats.NO_SUCH_MATRIX_ENTRY, row, column, getRowDimension(), getColumnDimension());
    376            }
    377        }
    378
    379        /** {@inheritDoc} */
    380        @Override
    381        public void multiplyEntry(final int row, final int column, final T factor)
    382            throws MatrixIndexException {
    383            try {
    384                data[row][column] = data[row][column].multiply(factor);
    385            } catch (ArrayIndexOutOfBoundsException e) {
    386                throw new MatrixIndexException(
    387                          LocalizedFormats.NO_SUCH_MATRIX_ENTRY, row, column, getRowDimension(), getColumnDimension());
    388            }
    389        }
    390
    391        /** {@inheritDoc} */
    392        @Override
    393        public int getRowDimension() {
    394            return (data == null) ? 0 : data.length;
    395        }
    396
    397        /** {@inheritDoc} */
    398        @Override
    399        public int getColumnDimension() {
    400            return ((data == null) || (data[0] == null)) ? 0 : data[0].length;
    401        }
    402
    403        /** {@inheritDoc} */
    404        @Override
    405        public T[] operate(final T[] v)
    406            throws IllegalArgumentException {
    407            final int nRows = this.getRowDimension();
    408            final int nCols = this.getColumnDimension();
    409            if (v.length != nCols) {
    410                throw MathRuntimeException.createIllegalArgumentException(
    411                      LocalizedFormats.VECTOR_LENGTH_MISMATCH, v.length, nCols);
    412            }
    413            final T[] out = buildArray(getField(), nRows);
    414            for (int row = 0; row < nRows; row++) {
    415                final T[] dataRow = data[row];
    416                T sum = getField().getZero();
    417                for (int i = 0; i < nCols; i++) {
    418                    sum = sum.add(dataRow[i].multiply(v[i]));
    419                }
    420                out[row] = sum;
    421            }
    422            return out;
    423        }
    424
    425        /** {@inheritDoc} */
    426        @Override
    427        public T[] preMultiply(final T[] v)
    428            throws IllegalArgumentException {
    429
    430            final int nRows = getRowDimension();
    431            final int nCols = getColumnDimension();
    432            if (v.length != nRows) {
    433                throw MathRuntimeException.createIllegalArgumentException(
    434                      LocalizedFormats.VECTOR_LENGTH_MISMATCH, v.length, nRows);
    435            }
    436
    437            final T[] out = buildArray(getField(), nCols);
    438            for (int col = 0; col < nCols; ++col) {
    439                T sum = getField().getZero();
    440                for (int i = 0; i < nRows; ++i) {
    441                    sum = sum.add(data[i][col].multiply(v[i]));
    442                }
    443                out[col] = sum;
    444            }
    445
    446            return out;
    447
    448        }
    449
    450        /** {@inheritDoc} */
    451        @Override
    452        public T walkInRowOrder(final FieldMatrixChangingVisitor<T> visitor)
    453            throws MatrixVisitorException {
    454            final int rows    = getRowDimension();
    455            final int columns = getColumnDimension();
    456            visitor.start(rows, columns, 0, rows - 1, 0, columns - 1);
    457            for (int i = 0; i < rows; ++i) {
    458                final T[] rowI = data[i];
    459                for (int j = 0; j < columns; ++j) {
    460                    rowI[j] = visitor.visit(i, j, rowI[j]);
    461                }
    462            }
    463            return visitor.end();
    464        }
    465
    466        /** {@inheritDoc} */
    467        @Override
    468        public T walkInRowOrder(final FieldMatrixPreservingVisitor<T> visitor)
    469            throws MatrixVisitorException {
    470            final int rows    = getRowDimension();
    471            final int columns = getColumnDimension();
    472            visitor.start(rows, columns, 0, rows - 1, 0, columns - 1);
    473            for (int i = 0; i < rows; ++i) {
    474                final T[] rowI = data[i];
    475                for (int j = 0; j < columns; ++j) {
    476                    visitor.visit(i, j, rowI[j]);
    477                }
    478            }
    479            return visitor.end();
    480        }
    481
    482        /** {@inheritDoc} */
    483        @Override
    484        public T walkInRowOrder(final FieldMatrixChangingVisitor<T> visitor,
    485                                final int startRow, final int endRow,
    486                                final int startColumn, final int endColumn)
    487            throws MatrixIndexException, MatrixVisitorException {
    488            checkSubMatrixIndex(startRow, endRow, startColumn, endColumn);
    489            visitor.start(getRowDimension(), getColumnDimension(),
    490                          startRow, endRow, startColumn, endColumn);
    491            for (int i = startRow; i <= endRow; ++i) {
    492                final T[] rowI = data[i];
    493                for (int j = startColumn; j <= endColumn; ++j) {
    494                    rowI[j] = visitor.visit(i, j, rowI[j]);
    495                }
    496            }
    497            return visitor.end();
    498        }
    499
    500        /** {@inheritDoc} */
    501        @Override
    502        public T walkInRowOrder(final FieldMatrixPreservingVisitor<T> visitor,
    503                                final int startRow, final int endRow,
    504                                final int startColumn, final int endColumn)
    505            throws MatrixIndexException, MatrixVisitorException {
    506            checkSubMatrixIndex(startRow, endRow, startColumn, endColumn);
    507            visitor.start(getRowDimension(), getColumnDimension(),
    508                          startRow, endRow, startColumn, endColumn);
    509            for (int i = startRow; i <= endRow; ++i) {
    510                final T[] rowI = data[i];
    511                for (int j = startColumn; j <= endColumn; ++j) {
    512                    visitor.visit(i, j, rowI[j]);
    513                }
    514            }
    515            return visitor.end();
    516        }
    517
    518        /** {@inheritDoc} */
    519        @Override
    520        public T walkInColumnOrder(final FieldMatrixChangingVisitor<T> visitor)
    521            throws MatrixVisitorException {
    522            final int rows    = getRowDimension();
    523            final int columns = getColumnDimension();
    524            visitor.start(rows, columns, 0, rows - 1, 0, columns - 1);
    525            for (int j = 0; j < columns; ++j) {
    526                for (int i = 0; i < rows; ++i) {
    527                    final T[] rowI = data[i];
    528                    rowI[j] = visitor.visit(i, j, rowI[j]);
    529                }
    530            }
    531            return visitor.end();
    532        }
    533
    534        /** {@inheritDoc} */
    535        @Override
    536        public T walkInColumnOrder(final FieldMatrixPreservingVisitor<T> visitor)
    537            throws MatrixVisitorException {
    538            final int rows    = getRowDimension();
    539            final int columns = getColumnDimension();
    540            visitor.start(rows, columns, 0, rows - 1, 0, columns - 1);
    541            for (int j = 0; j < columns; ++j) {
    542                for (int i = 0; i < rows; ++i) {
    543                    visitor.visit(i, j, data[i][j]);
    544                }
    545            }
    546            return visitor.end();
    547        }
    548
    549        /** {@inheritDoc} */
    550        @Override
    551        public T walkInColumnOrder(final FieldMatrixChangingVisitor<T> visitor,
    552                                   final int startRow, final int endRow,
    553                                   final int startColumn, final int endColumn)
    554            throws MatrixIndexException, MatrixVisitorException {
    555            checkSubMatrixIndex(startRow, endRow, startColumn, endColumn);
    556            visitor.start(getRowDimension(), getColumnDimension(),
    557                          startRow, endRow, startColumn, endColumn);
    558            for (int j = startColumn; j <= endColumn; ++j) {
    559                for (int i = startRow; i <= endRow; ++i) {
    560                    final T[] rowI = data[i];
    561                    rowI[j] = visitor.visit(i, j, rowI[j]);
    562                }
    563            }
    564            return visitor.end();
    565        }
    566
    567        /** {@inheritDoc} */
    568        @Override
    569        public T walkInColumnOrder(final FieldMatrixPreservingVisitor<T> visitor,
    570                                   final int startRow, final int endRow,
    571                                   final int startColumn, final int endColumn)
    572            throws MatrixIndexException, MatrixVisitorException {
    573            checkSubMatrixIndex(startRow, endRow, startColumn, endColumn);
    574            visitor.start(getRowDimension(), getColumnDimension(),
    575                          startRow, endRow, startColumn, endColumn);
    576            for (int j = startColumn; j <= endColumn; ++j) {
    577                for (int i = startRow; i <= endRow; ++i) {
    578                    visitor.visit(i, j, data[i][j]);
    579                }
    580            }
    581            return visitor.end();
    582        }
    583
    584        /**
    585         * Returns a fresh copy of the underlying data array.
    586         *
    587         * @return a copy of the underlying data array.
    588         */
    589        private T[][] copyOut() {
    590            final int nRows = this.getRowDimension();
    591            final T[][] out = buildArray(getField(), nRows, getColumnDimension());
    592            // can't copy 2-d array in one shot, otherwise get row references
    593            for (int i = 0; i < nRows; i++) {
    594                System.arraycopy(data[i], 0, out[i], 0, data[i].length);
    595            }
    596            return out;
    597        }
    598
    599        /**
    600         * Replaces data with a fresh copy of the input array.
    601         * <p>
    602         * Verifies that the input array is rectangular and non-empty.</p>
    603         *
    604         * @param in data to copy in
    605         * @throws IllegalArgumentException if input array is empty or not
    606         *    rectangular
    607         * @throws NullPointerException if input array is null
    608         */
    609        private void copyIn(final T[][] in) {
    610            setSubMatrix(in, 0, 0);
    611        }
    612
    613    }