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