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    package org.apache.commons.math3.linear;
018    
019    import java.io.Serializable;
020    import org.apache.commons.math3.exception.DimensionMismatchException;
021    import org.apache.commons.math3.exception.NotStrictlyPositiveException;
022    import org.apache.commons.math3.exception.OutOfRangeException;
023    import org.apache.commons.math3.exception.MathUnsupportedOperationException;
024    
025    /**
026     * Implementation of a diagonal matrix.
027     * <br/>
028     * Caveat: This implementation is minimal; it is currently solely aimed
029     * at solving issue MATH-924. In particular many methods just throw
030     * {@code MathUnsupportedOperationException}.
031     *
032     * @version $Id$
033     */
034    public class DiagonalMatrix extends AbstractRealMatrix
035        implements Serializable {
036        /** Serializable version identifier. */
037        private static final long serialVersionUID = 20121229L;
038        /** Entries of the diagonal. */
039        private final double[] data;
040    
041        /**
042         * Creates a matrix with the supplied dimension.
043         *
044         * @param dimension Number of rows and columns in the new matrix.
045         * @throws NotStrictlyPositiveException if the dimension is
046         * not positive.
047         */
048        public DiagonalMatrix(final int dimension)
049            throws NotStrictlyPositiveException {
050            super(dimension, dimension);
051            data = new double[dimension];
052        }
053    
054        /**
055         * Creates a matrix using the input array as the underlying data.
056         * <br/>
057         * The input array is copied, not referenced.
058         *
059         * @param d Data for the new matrix.
060         */
061        public DiagonalMatrix(final double[] d) {
062            this(d, true);
063        }
064    
065        /**
066         * Creates a matrix using the input array as the underlying data.
067         * <br/>
068         * If an array is created specially in order to be embedded in a
069         * this instance and not used directly, the {@code copyArray} may be
070         * set to {@code false}.
071         * This will prevent the copying and improve performance as no new
072         * array will be built and no data will be copied.
073         *
074         * @param d Data for new matrix.
075         * @param copyArray if {@code true}, the input array will be copied,
076         * otherwise it will be referenced.
077         */
078        public DiagonalMatrix(final double[] d, final boolean copyArray) {
079            data = copyArray ? d.clone() : d;
080        }
081    
082        /**
083         * {@inheritDoc}
084         *
085         * @throws DimensionMismatchException if the requested dimensions are not equal.
086         */
087        @Override
088        public RealMatrix createMatrix(final int rowDimension,
089                                       final int columnDimension)
090            throws NotStrictlyPositiveException,
091                   DimensionMismatchException {
092            if (rowDimension != columnDimension) {
093                throw new DimensionMismatchException(rowDimension, columnDimension);
094            }
095    
096            return new DiagonalMatrix(rowDimension);
097        }
098    
099        /** {@inheritDoc} */
100        @Override
101        public RealMatrix copy() {
102            return new DiagonalMatrix(data);
103        }
104    
105        /**
106         * Compute the sum of {@code this} and {@code m}.
107         *
108         * @param m Matrix to be added.
109         * @return {@code this + m}.
110         * @throws MatrixDimensionMismatchException if {@code m} is not the same
111         * size as {@code this}.
112         */
113        public DiagonalMatrix add(final DiagonalMatrix m)
114            throws MatrixDimensionMismatchException {
115            // Safety check.
116            MatrixUtils.checkAdditionCompatible(this, m);
117    
118            final int dim = getRowDimension();
119            final double[] outData = new double[dim];
120            for (int i = 0; i < dim; i++) {
121                outData[i] = data[i] + m.data[i];
122            }
123    
124            return new DiagonalMatrix(outData, false);
125        }
126    
127        /**
128         * Returns {@code this} minus {@code m}.
129         *
130         * @param m Matrix to be subtracted.
131         * @return {@code this - m}
132         * @throws MatrixDimensionMismatchException if {@code m} is not the same
133         * size as {@code this}.
134         */
135        public DiagonalMatrix subtract(final DiagonalMatrix m)
136            throws MatrixDimensionMismatchException {
137            MatrixUtils.checkSubtractionCompatible(this, m);
138    
139            final int dim = getRowDimension();
140            final double[] outData = new double[dim];
141            for (int i = 0; i < dim; i++) {
142                outData[i] = data[i] - m.data[i];
143            }
144    
145            return new DiagonalMatrix(outData, false);
146        }
147    
148        /**
149         * Returns the result of postmultiplying {@code this} by {@code m}.
150         *
151         * @param m matrix to postmultiply by
152         * @return {@code this * m}
153         * @throws DimensionMismatchException if
154         * {@code columnDimension(this) != rowDimension(m)}
155         */
156        public DiagonalMatrix multiply(final DiagonalMatrix m)
157            throws DimensionMismatchException {
158            MatrixUtils.checkMultiplicationCompatible(this, m);
159    
160            final int dim = getRowDimension();
161            final double[] outData = new double[dim];
162            for (int i = 0; i < dim; i++) {
163                outData[i] = data[i] * m.data[i];
164            }
165    
166            return new DiagonalMatrix(outData, false);
167        }
168    
169        /**
170         * Returns the result of postmultiplying {@code this} by {@code m}.
171         *
172         * @param m matrix to postmultiply by
173         * @return {@code this * m}
174         * @throws DimensionMismatchException if
175         * {@code columnDimension(this) != rowDimension(m)}
176         */
177        public RealMatrix multiply(final RealMatrix m)
178            throws DimensionMismatchException {
179            if (m instanceof DiagonalMatrix) {
180                return multiply((DiagonalMatrix) m);
181            } else {
182                MatrixUtils.checkMultiplicationCompatible(this, m);
183                final int nRows = m.getRowDimension();
184                final int nCols = m.getColumnDimension();
185                final double[][] product = new double[nRows][nCols];
186                for (int r = 0; r < nRows; r++) {
187                    for (int c = 0; c < nCols; c++) {
188                        product[r][c] = data[r] * m.getEntry(r, c);
189                    }
190                }
191                return new Array2DRowRealMatrix(product, false);
192            }
193        }
194    
195        /** {@inheritDoc} */
196        @Override
197        public double[][] getData() {
198            final int dim = getRowDimension();
199            final double[][] out = new double[dim][dim];
200    
201            for (int i = 0; i < dim; i++) {
202                out[i][i] = data[i];
203            }
204    
205            return out;
206        }
207    
208        /**
209         * Gets a reference to the underlying data array.
210         *
211         * @return 1-dimensional array of entries.
212         */
213        public double[] getDataRef() {
214            return data;
215        }
216    
217        /** {@inheritDoc}
218         * @throws MathUnsupportedOperationException
219         */
220        @Override
221        public void setSubMatrix(final double[][] subMatrix,
222                                 final int row,
223                                 final int column)
224            throws MathUnsupportedOperationException {
225            throw new MathUnsupportedOperationException();
226        }
227    
228        /** {@inheritDoc} */
229        @Override
230        public double getEntry(final int row, final int column)
231            throws OutOfRangeException {
232            MatrixUtils.checkMatrixIndex(this, row, column);
233            return row == column ? data[row] : 0;
234        }
235    
236        /** {@inheritDoc}
237         * @throws MathUnsupportedOperationException if {@code row != column}.
238         */
239        @Override
240        public void setEntry(final int row, final int column, final double value)
241            throws OutOfRangeException,
242                   MathUnsupportedOperationException {
243            if (row != column) {
244                throw new MathUnsupportedOperationException();
245            }
246            MatrixUtils.checkMatrixIndex(this, row, column);
247            data[row] = value;
248        }
249    
250        /** {@inheritDoc}
251         * @throws MathUnsupportedOperationException if {@code row != column}.
252         */
253        @Override
254        public void addToEntry(final int row,
255                               final int column,
256                               final double increment)
257            throws OutOfRangeException,
258                   MathUnsupportedOperationException {
259            if (row != column) {
260                throw new MathUnsupportedOperationException();
261            }
262            MatrixUtils.checkMatrixIndex(this, row, column);
263            data[row] += increment;
264        }
265    
266        /** {@inheritDoc}
267         * @throws MathUnsupportedOperationException if {@code row != column}.
268         */
269        @Override
270        public void multiplyEntry(final int row,
271                                  final int column,
272                                  final double factor)
273            throws OutOfRangeException,
274                   MathUnsupportedOperationException {
275            if (row != column) {
276                throw new MathUnsupportedOperationException();
277            }
278            MatrixUtils.checkMatrixIndex(this, row, column);
279            data[row] *= factor;
280        }
281    
282        /** {@inheritDoc} */
283        @Override
284        public int getRowDimension() {
285            return data == null ? 0 : data.length;
286        }
287    
288        /** {@inheritDoc} */
289        @Override
290        public int getColumnDimension() {
291            return getRowDimension();
292        }
293    
294        /** {@inheritDoc} */
295        @Override
296        public double[] operate(final double[] v)
297            throws DimensionMismatchException {
298            return multiply(new DiagonalMatrix(v, false)).getDataRef();
299        }
300    
301        /** {@inheritDoc} */
302        @Override
303        public double[] preMultiply(final double[] v)
304            throws DimensionMismatchException {
305            return operate(v);
306        }
307    
308        /** {@inheritDoc} */
309        @Override
310        public double walkInRowOrder(final RealMatrixChangingVisitor visitor)
311            throws MathUnsupportedOperationException {
312            throw new MathUnsupportedOperationException();
313        }
314    
315        /** {@inheritDoc} */
316        @Override
317        public double walkInRowOrder(final RealMatrixPreservingVisitor visitor)
318            throws MathUnsupportedOperationException {
319            throw new MathUnsupportedOperationException();
320        }
321    
322        /** {@inheritDoc} */
323        @Override
324        public double walkInRowOrder(final RealMatrixChangingVisitor visitor,
325                                     final int startRow, final int endRow,
326                                     final int startColumn, final int endColumn)
327            throws MathUnsupportedOperationException {
328            throw new MathUnsupportedOperationException();
329        }
330    
331        /** {@inheritDoc} */
332        @Override
333        public double walkInRowOrder(final RealMatrixPreservingVisitor visitor,
334                                     final int startRow, final int endRow,
335                                     final int startColumn, final int endColumn)
336            throws MathUnsupportedOperationException {
337            throw new MathUnsupportedOperationException();
338        }
339    
340        /** {@inheritDoc} */
341        @Override
342        public double walkInColumnOrder(final RealMatrixChangingVisitor visitor)
343            throws MathUnsupportedOperationException {
344            throw new MathUnsupportedOperationException();
345        }
346    
347        /** {@inheritDoc} */
348        @Override
349        public double walkInColumnOrder(final RealMatrixPreservingVisitor visitor)
350            throws MathUnsupportedOperationException {
351            throw new MathUnsupportedOperationException();
352        }
353    
354        /** {@inheritDoc} */
355        @Override
356        public double walkInColumnOrder(final RealMatrixChangingVisitor visitor,
357                                        final int startRow, final int endRow,
358                                        final int startColumn, final int endColumn)
359            throws MathUnsupportedOperationException {
360            throw new MathUnsupportedOperationException();
361        }
362    
363        /** {@inheritDoc} */
364        @Override
365        public double walkInColumnOrder(final RealMatrixPreservingVisitor visitor,
366                                        final int startRow, final int endRow,
367                                        final int startColumn, final int endColumn)
368            throws MathUnsupportedOperationException {
369            throw new MathUnsupportedOperationException();
370        }
371    }