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