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