| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| package org.apache.commons.math4.linear; |
| |
| import java.io.Serializable; |
| |
| import org.apache.commons.math4.exception.DimensionMismatchException; |
| import org.apache.commons.math4.exception.NotStrictlyPositiveException; |
| import org.apache.commons.math4.exception.NullArgumentException; |
| import org.apache.commons.math4.exception.NumberIsTooLargeException; |
| import org.apache.commons.math4.exception.OutOfRangeException; |
| import org.apache.commons.math4.util.FastMath; |
| import org.apache.commons.math4.util.MathUtils; |
| import org.apache.commons.numbers.core.Precision; |
| |
| /** |
| * Implementation of a diagonal matrix. |
| * |
| * @since 3.1.1 |
| */ |
| public class DiagonalMatrix extends AbstractRealMatrix |
| implements Serializable { |
| /** Serializable version identifier. */ |
| private static final long serialVersionUID = 20121229L; |
| /** Entries of the diagonal. */ |
| private final double[] data; |
| |
| /** |
| * Creates a matrix with the supplied dimension. |
| * |
| * @param dimension Number of rows and columns in the new matrix. |
| * @throws NotStrictlyPositiveException if the dimension is |
| * not positive. |
| */ |
| public DiagonalMatrix(final int dimension) |
| throws NotStrictlyPositiveException { |
| super(dimension, dimension); |
| data = new double[dimension]; |
| } |
| |
| /** |
| * Creates a matrix using the input array as the underlying data. |
| * <br> |
| * The input array is copied, not referenced. |
| * |
| * @param d Data for the new matrix. |
| */ |
| public DiagonalMatrix(final double[] d) { |
| this(d, true); |
| } |
| |
| /** |
| * Creates a matrix using the input array as the underlying data. |
| * <br> |
| * If an array is created specially in order to be embedded in a |
| * this instance and not used directly, the {@code copyArray} may be |
| * set to {@code false}. |
| * This will prevent the copying and improve performance as no new |
| * array will be built and no data will be copied. |
| * |
| * @param d Data for new matrix. |
| * @param copyArray if {@code true}, the input array will be copied, |
| * otherwise it will be referenced. |
| * @exception NullArgumentException if d is null |
| */ |
| public DiagonalMatrix(final double[] d, final boolean copyArray) |
| throws NullArgumentException { |
| MathUtils.checkNotNull(d); |
| data = copyArray ? d.clone() : d; |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * @throws DimensionMismatchException if the requested dimensions are not equal. |
| */ |
| @Override |
| public RealMatrix createMatrix(final int rowDimension, |
| final int columnDimension) |
| throws NotStrictlyPositiveException, |
| DimensionMismatchException { |
| if (rowDimension != columnDimension) { |
| throw new DimensionMismatchException(rowDimension, columnDimension); |
| } |
| |
| return new DiagonalMatrix(rowDimension); |
| } |
| |
| /** {@inheritDoc} */ |
| @Override |
| public RealMatrix copy() { |
| return new DiagonalMatrix(data); |
| } |
| |
| /** |
| * Compute the sum of {@code this} and {@code m}. |
| * |
| * @param m Matrix to be added. |
| * @return {@code this + m}. |
| * @throws MatrixDimensionMismatchException if {@code m} is not the same |
| * size as {@code this}. |
| */ |
| public DiagonalMatrix add(final DiagonalMatrix m) |
| throws MatrixDimensionMismatchException { |
| // Safety check. |
| MatrixUtils.checkAdditionCompatible(this, m); |
| |
| final int dim = getRowDimension(); |
| final double[] outData = new double[dim]; |
| for (int i = 0; i < dim; i++) { |
| outData[i] = data[i] + m.data[i]; |
| } |
| |
| return new DiagonalMatrix(outData, false); |
| } |
| |
| /** |
| * Returns {@code this} minus {@code m}. |
| * |
| * @param m Matrix to be subtracted. |
| * @return {@code this - m} |
| * @throws MatrixDimensionMismatchException if {@code m} is not the same |
| * size as {@code this}. |
| */ |
| public DiagonalMatrix subtract(final DiagonalMatrix m) |
| throws MatrixDimensionMismatchException { |
| MatrixUtils.checkSubtractionCompatible(this, m); |
| |
| final int dim = getRowDimension(); |
| final double[] outData = new double[dim]; |
| for (int i = 0; i < dim; i++) { |
| outData[i] = data[i] - m.data[i]; |
| } |
| |
| return new DiagonalMatrix(outData, false); |
| } |
| |
| /** |
| * Returns the result of postmultiplying {@code this} by {@code m}. |
| * |
| * @param m matrix to postmultiply by |
| * @return {@code this * m} |
| * @throws DimensionMismatchException if |
| * {@code columnDimension(this) != rowDimension(m)} |
| */ |
| public DiagonalMatrix multiply(final DiagonalMatrix m) |
| throws DimensionMismatchException { |
| MatrixUtils.checkMultiplicationCompatible(this, m); |
| |
| final int dim = getRowDimension(); |
| final double[] outData = new double[dim]; |
| for (int i = 0; i < dim; i++) { |
| outData[i] = data[i] * m.data[i]; |
| } |
| |
| return new DiagonalMatrix(outData, false); |
| } |
| |
| /** |
| * Returns the result of postmultiplying {@code this} by {@code m}. |
| * |
| * @param m matrix to postmultiply by |
| * @return {@code this * m} |
| * @throws DimensionMismatchException if |
| * {@code columnDimension(this) != rowDimension(m)} |
| */ |
| @Override |
| public RealMatrix multiply(final RealMatrix m) |
| throws DimensionMismatchException { |
| if (m instanceof DiagonalMatrix) { |
| return multiply((DiagonalMatrix) m); |
| } else { |
| MatrixUtils.checkMultiplicationCompatible(this, m); |
| final int nRows = m.getRowDimension(); |
| final int nCols = m.getColumnDimension(); |
| final double[][] product = new double[nRows][nCols]; |
| for (int r = 0; r < nRows; r++) { |
| for (int c = 0; c < nCols; c++) { |
| product[r][c] = data[r] * m.getEntry(r, c); |
| } |
| } |
| return new Array2DRowRealMatrix(product, false); |
| } |
| } |
| |
| /** {@inheritDoc} */ |
| @Override |
| public double[][] getData() { |
| final int dim = getRowDimension(); |
| final double[][] out = new double[dim][dim]; |
| |
| for (int i = 0; i < dim; i++) { |
| out[i][i] = data[i]; |
| } |
| |
| return out; |
| } |
| |
| /** |
| * Gets a reference to the underlying data array. |
| * |
| * @return 1-dimensional array of entries. |
| */ |
| public double[] getDataRef() { |
| return data; |
| } |
| |
| /** {@inheritDoc} */ |
| @Override |
| public double getEntry(final int row, final int column) |
| throws OutOfRangeException { |
| MatrixUtils.checkMatrixIndex(this, row, column); |
| return row == column ? data[row] : 0; |
| } |
| |
| /** {@inheritDoc} |
| * @throws NumberIsTooLargeException if {@code row != column} and value is non-zero. |
| */ |
| @Override |
| public void setEntry(final int row, final int column, final double value) |
| throws OutOfRangeException, NumberIsTooLargeException { |
| if (row == column) { |
| MatrixUtils.checkRowIndex(this, row); |
| data[row] = value; |
| } else { |
| ensureZero(value); |
| } |
| } |
| |
| /** {@inheritDoc} |
| * @throws NumberIsTooLargeException if {@code row != column} and increment is non-zero. |
| */ |
| @Override |
| public void addToEntry(final int row, |
| final int column, |
| final double increment) |
| throws OutOfRangeException, NumberIsTooLargeException { |
| if (row == column) { |
| MatrixUtils.checkRowIndex(this, row); |
| data[row] += increment; |
| } else { |
| ensureZero(increment); |
| } |
| } |
| |
| /** {@inheritDoc} */ |
| @Override |
| public void multiplyEntry(final int row, |
| final int column, |
| final double factor) |
| throws OutOfRangeException { |
| // we don't care about non-diagonal elements for multiplication |
| if (row == column) { |
| MatrixUtils.checkRowIndex(this, row); |
| data[row] *= factor; |
| } |
| } |
| |
| /** {@inheritDoc} */ |
| @Override |
| public int getRowDimension() { |
| return data.length; |
| } |
| |
| /** {@inheritDoc} */ |
| @Override |
| public int getColumnDimension() { |
| return data.length; |
| } |
| |
| /** {@inheritDoc} */ |
| @Override |
| public double[] operate(final double[] v) |
| throws DimensionMismatchException { |
| return multiply(new DiagonalMatrix(v, false)).getDataRef(); |
| } |
| |
| /** {@inheritDoc} */ |
| @Override |
| public double[] preMultiply(final double[] v) |
| throws DimensionMismatchException { |
| return operate(v); |
| } |
| |
| /** {@inheritDoc} */ |
| @Override |
| public RealVector preMultiply(final RealVector v) throws DimensionMismatchException { |
| final double[] vectorData; |
| if (v instanceof ArrayRealVector) { |
| vectorData = ((ArrayRealVector) v).getDataRef(); |
| } else { |
| vectorData = v.toArray(); |
| } |
| return MatrixUtils.createRealVector(preMultiply(vectorData)); |
| } |
| |
| /** Ensure a value is zero. |
| * @param value value to check |
| * @exception NumberIsTooLargeException if value is not zero |
| */ |
| private void ensureZero(final double value) throws NumberIsTooLargeException { |
| if (!Precision.equals(0.0, value, 1)) { |
| throw new NumberIsTooLargeException(FastMath.abs(value), 0, true); |
| } |
| } |
| |
| /** |
| * Computes the inverse of this diagonal matrix. |
| * <p> |
| * Note: this method will use a singularity threshold of 0, |
| * use {@link #inverse(double)} if a different threshold is needed. |
| * |
| * @return the inverse of {@code m} |
| * @throws SingularMatrixException if the matrix is singular |
| * @since 3.3 |
| */ |
| public DiagonalMatrix inverse() throws SingularMatrixException { |
| return inverse(0); |
| } |
| |
| /** |
| * Computes the inverse of this diagonal matrix. |
| * |
| * @param threshold Singularity threshold. |
| * @return the inverse of {@code m} |
| * @throws SingularMatrixException if the matrix is singular |
| * @since 3.3 |
| */ |
| public DiagonalMatrix inverse(double threshold) throws SingularMatrixException { |
| if (isSingular(threshold)) { |
| throw new SingularMatrixException(); |
| } |
| |
| final double[] result = new double[data.length]; |
| for (int i = 0; i < data.length; i++) { |
| result[i] = 1.0 / data[i]; |
| } |
| return new DiagonalMatrix(result, false); |
| } |
| |
| /** Returns whether this diagonal matrix is singular, i.e. any diagonal entry |
| * is equal to {@code 0} within the given threshold. |
| * |
| * @param threshold Singularity threshold. |
| * @return {@code true} if the matrix is singular, {@code false} otherwise |
| * @since 3.3 |
| */ |
| public boolean isSingular(double threshold) { |
| for (int i = 0; i < data.length; i++) { |
| if (Precision.equals(data[i], 0.0, threshold)) { |
| return true; |
| } |
| } |
| return false; |
| } |
| } |