    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    }