All Downloads are FREE. Search and download functionalities are using the official Maven repository.

gov.sandia.cognition.math.matrix.custom.BaseMatrix Maven / Gradle / Ivy

There is a newer version: 4.0.1
Show newest version
/*
 * File:                BaseMatrix.java
 * Authors:             Jeremy D. Wendt
 * Company:             Sandia National Laboratories
 * Project:             Cognitive Foundry
 *
 * Copyright 2015, Sandia Corporation.  Under the terms of Contract
 * DE-AC04-94AL85000, there is a non-exclusive license for use of this work by
 * or on behalf of the U.S. Government. Export of this program may require a
 * license from the United States Government. See CopyrightHistory.txt for
 * complete details.
 */

package gov.sandia.cognition.math.matrix.custom;

import gov.sandia.cognition.math.matrix.AbstractMatrix;
import gov.sandia.cognition.math.matrix.DimensionalityMismatchException;
import gov.sandia.cognition.math.matrix.Matrix;
import gov.sandia.cognition.math.matrix.MatrixEntry;
import gov.sandia.cognition.math.matrix.Vector;
import java.text.NumberFormat;
import java.util.Iterator;

/**
 * This package-private class implements the basic math methods, ensures size
 * constraints are met for the operation, and then calls the
 * matrix-type-specific (diagonal, dense, sparse) version of the basic matrix
 * method.
 *
 * @author Jeremy D. Wendt
 * @since 4.0.0
 */
abstract class BaseMatrix
    extends AbstractMatrix
{

    /**
     * Creates a new {@link BaseMatrix}.
     */
    protected BaseMatrix()
    {
        super();
    }

    @Override
    final public Matrix plus(
        final Matrix other)
    {
        final Matrix result;
        if (this instanceof DenseMatrix)
        {
            result = this.clone();
            result.plusEquals(other);
        }
        else if (other instanceof DenseMatrix)
        {
            result = other.clone();
            result.plusEquals(this);
        }
        else if (this instanceof SparseMatrix)
        {
            result = this.clone();
            result.plusEquals(other);
        }
        else if (other instanceof SparseMatrix)
        {
            result = other.clone();
            result.plusEquals(this);
        }
        else if (this instanceof DiagonalMatrix && other instanceof DiagonalMatrix)
        {
            result = this.clone();
            result.plusEquals(other);
        }
        else
        {
            result = this.clone();
            result.plusEquals(other);
        }
        return result;
    }

    @Override
    final public Matrix minus(
        final Matrix other)
    {
        final Matrix result;
        if (this instanceof DenseMatrix)
        {
            result = this.clone();
            result.minusEquals(other);
        }
        else if (other instanceof DenseMatrix)
        {
            result = other.negative();
            result.plusEquals(this);
        }
        else if (this instanceof SparseMatrix)
        {
            result = this.clone();
            result.minusEquals(other);
        }
        else if (other instanceof SparseMatrix)
        {
            result = other.negative();
            result.plusEquals(this);
        }
        else if (this instanceof DiagonalMatrix && other instanceof DiagonalMatrix)
        {
            result = this.clone();
            result.minusEquals(other);
        }
        else
        {
            result = this.clone();
            result.minusEquals(other);
        }
        return result;
    }

    @Override
    final public Matrix dotTimes(
        final Matrix other)
    {
        final Matrix result;
        if (this instanceof DiagonalMatrix)
        {
            result = this.clone();
            result.dotTimesEquals(other);
        }
        else if (other instanceof DiagonalMatrix)
        {
            result = other.clone();
            result.dotTimesEquals(this);
        }
        else if (this instanceof SparseMatrix)
        {
            result = this.clone();
            result.dotTimesEquals(other);
        }
        else if (other instanceof SparseMatrix)
        {
            result = other.clone();
            result.dotTimesEquals(this);
        }
        else if (this instanceof DenseMatrix && other instanceof DenseMatrix)
        {
            result = this.clone();
            result.dotTimesEquals(other);
        }
        else
        {
            result = this.clone();
            result.dotTimesEquals(other);
        }
        return result;
    }

    @Override
    final public void plusEquals(
        final Matrix other)
    {
        if (other instanceof DiagonalMatrix)
        {
            plusEquals((DiagonalMatrix) other);
        }
        else if (other instanceof DenseMatrix)
        {
            this.plusEquals((DenseMatrix) other);
        }
        else if (other instanceof SparseMatrix)
        {
            this.plusEquals((SparseMatrix) other);
        }
        else
        {
            super.plusEquals(other);
        }
    }

    /**
     * Type-specific version of plusEquals for combining whatever type this is
     * with the input sparse matrix.
     *
     * @param other A sparse matrix to add to this
     */
    public abstract void plusEquals(
        final SparseMatrix other);

    /**
     * Type-specific version of plusEquals for combining whatever type this is
     * with the input dense matrix.
     *
     * @param other A dense matrix to add to this
     */
    public abstract void plusEquals(
        final DenseMatrix other);

    /**
     * Type-specific version of plusEquals for combining whatever type this is
     * with the input diagonal matrix.
     *
     * @param other A diagonal matrix to add to this
     */
    public abstract void plusEquals(
        final DiagonalMatrix other);

    @Override
    final public void scaledPlusEquals(
        final double scaleFactor,
        final Matrix other)
    {
        if (other instanceof DiagonalMatrix)
        {
            scaledPlusEquals((DiagonalMatrix) other, scaleFactor);
        }
        else if (other instanceof DenseMatrix)
        {
            this.scaledPlusEquals((DenseMatrix) other, scaleFactor);
        }
        else if (other instanceof SparseMatrix)
        {
            this.scaledPlusEquals((SparseMatrix) other, scaleFactor);
        }
        else
        {
            super.scaledPlusEquals(scaleFactor, other);
        }
    }

    /**
     * Type-specific version of scaledPlusEquals for combining whatever type
     * this is with the input sparse matrix.
     *
     * @param other A sparse matrix to add to this
     * @param scaleFactor The amount to scale other by
     */
    public abstract void scaledPlusEquals(
        final SparseMatrix other,
        final double scaleFactor);

    /**
     * Type-specific version of scaledPlusEquals for combining whatever type
     * this is with the input dense matrix.
     *
     * @param other A dense matrix to add to this
     * @param scaleFactor The amount to scale other by
     */
    public abstract void scaledPlusEquals(
        final DenseMatrix other,
        final double scaleFactor);

    /**
     * Type-specific version of scaledPlusEquals for combining whatever type
     * this is with the input diagonal matrix.
     *
     * @param other A diagonal matrix to add to this
     * @param scaleFactor The amount to scale other by
     */
    public abstract void scaledPlusEquals(
        final DiagonalMatrix other,
        final double scaleFactor);

    @Override
    final public void minusEquals(
        final Matrix other)
    {
        if (other instanceof DiagonalMatrix)
        {
            minusEquals((DiagonalMatrix) other);
        }
        else if (other instanceof DenseMatrix)
        {
            this.minusEquals((DenseMatrix) other);
        }
        else if (other instanceof SparseMatrix)
        {
            this.minusEquals((SparseMatrix) other);
        }
        else
        {
            super.minusEquals(other);
        }
    }

    /**
     * Type-specific version of minusEquals for combining whatever type this is
     * with the input sparse matrix.
     *
     * @param other A sparse matrix to subtract from this
     */
    public abstract void minusEquals(
        final SparseMatrix other);

    /**
     * Type-specific version of minusEquals for combining whatever type this is
     * with the input dense matrix.
     *
     * @param other A dense matrix to subtract from this
     */
    public abstract void minusEquals(
        final DenseMatrix other);

    /**
     * Type-specific version of minusEquals for combining whatever type this is
     * with the input diagonal matrix.
     *
     * @param other A diagonal matrix to subtract from this
     */
    public abstract void minusEquals(
        final DiagonalMatrix other);

    @Override
    final public void dotTimesEquals(
        final Matrix other)
    {
        if (other instanceof DiagonalMatrix)
        {
            dotTimesEquals((DiagonalMatrix) other);
        }
        else if (other instanceof DenseMatrix)
        {
            this.dotTimesEquals((DenseMatrix) other);
        }
        else if (other instanceof SparseMatrix)
        {
            this.dotTimesEquals((SparseMatrix) other);
        }
        else
        {
            super.dotTimesEquals(other);
        }
    }

    /**
     * Type-specific version of dotTimesEquals for combining whatever type this
     * is with the input sparse matrix.
     *
     * @param other A sparse matrix to dot with this
     */
    public abstract void dotTimesEquals(
        final SparseMatrix other);

    /**
     * Type-specific version of dotTimesEquals for combining whatever type this
     * is with the input dense matrix.
     *
     * @param other A dense matrix to dot with this
     */
    public abstract void dotTimesEquals(
        final DenseMatrix other);

    /**
     * Type-specific version of dotTimesEquals for combining whatever type this
     * is with the input diagonal matrix.
     *
     * @param other A diagonal matrix to dot with this
     */
    public abstract void dotTimesEquals(
        final DiagonalMatrix other);

    @Override
    final public Matrix times(
        final Matrix other)
    {
        if (other instanceof DiagonalMatrix)
        {
            return this.times((DiagonalMatrix) other);
        }
        else if (other instanceof DenseMatrix)
        {
            return this.times((DenseMatrix) other);
        }
        else if (other instanceof SparseMatrix)
        {
            return this.times((SparseMatrix) other);
        }
        else
        {
            return super.times(other);
        }
    }

    /**
     * Type-specific version of times for combining whatever type this is with
     * the input sparse matrix.
     *
     * @param other A sparse matrix to multiply with this
     */
    public abstract Matrix times(
        final SparseMatrix other);

    /**
     * Type-specific version of times for combining whatever type this is with
     * the input dense matrix.
     *
     * @param other A dense matrix to multiply with this
     */
    public abstract Matrix times(
        final DenseMatrix other);

    /**
     * Type-specific version of times for combining whatever type this is with
     * the input diagonal matrix.
     *
     * @param other A diagonal matrix to multiply with this
     */
    public abstract Matrix times(
        final DiagonalMatrix other);

    @Override
    final public Vector times(
        final Vector vector)
    {
        if (vector instanceof DenseVector)
        {
            return times((DenseVector) vector);
        }
        else if (vector instanceof SparseVector)
        {
            return this.times((SparseVector) vector);
        }
        else
        {
            return super.times(vector);
        }
    }

    /**
     * Type-specific version of times for combining whatever type this is with
     * the input sparse vector.
     *
     * @param vector A sparse vector to multiply with this
     */
    public abstract Vector times(
        final SparseVector vector);

    /**
     * Type-specific version of times for combining whatever type this is with
     * the input dense vector.
     *
     * @param vector A dense vector to multiply with this
     */
    public abstract Vector times(
        final DenseVector vector);

    /**
     * Package-private method that puts the vector * matrix code in the matrix
     * class instead of in the vector class (why should vectors know the
     * internals of matrices?).
     *
     * @param vector The vector to pre-multiply this by
     * @return The resulting vector from input * this
     * @throws DimensionalityMismatchException if the input vectors's dimensions
     * doesn't match this's numRows.
     */
    public final Vector preTimes(
        final Vector vector)
    {
        if (vector instanceof DenseVector)
        {
            return preTimes((DenseVector) vector);
        }
        else if (vector instanceof SparseVector)
        {
            return this.preTimes((SparseVector) vector);
        }
        else
        {
            // Fallback for compatability.
            vector.assertDimensionalityEquals(this.getNumRows());
            final Vector result = vector.getVectorFactory().createVector(
                this.getNumColumns());
            for (final MatrixEntry entry : this)
            {
                result.increment(entry.getColumnIndex(),
                    entry.getValue() * vector.get(entry.getRowIndex()));
            }
            return result;
        }
    }

    /**
     * Type-specific version of pre-times for combining whatever type this is
     * with the input sparse vector.
     *
     * @param vector A sparse vector to multiply with this
     */
    public abstract Vector preTimes(
        final SparseVector vector);

    /**
     * Type-specific version of pre-times for combining whatever type this is
     * with the input dense vector.
     *
     * @param vector A dense vector to multiply with this
     */
    public abstract Vector preTimes(
        final DenseVector vector);

    /**
     * Helper method checks that the input submatrix range is acceptable for
     * this matrix, including that the max is greater than or equal to the min.
     * Note that the input mins and maxs are inclusive.
     *
     * @param minRow The minimum row to return (inclusive)
     * @param maxRow The maximum row to return (inclusive)
     * @param minCol The minimum column to return (inclusive)
     * @param maxCol The maximum column to return (inclusive)
     * @throws ArrayIndexOutOfBoundsException if the input range is illegal or
     * outside the bounds of this.
     */
    final protected void checkSubmatrixRange(
        final int minRow,
        final int maxRow,
        final int minCol,
        final int maxCol)
    {
        if (maxRow < minRow || maxCol < minCol || minRow < 0 || minCol < 0
            || maxRow
            > getNumRows() || maxCol > getNumColumns())
        {
            throw new ArrayIndexOutOfBoundsException("Input range is invalid: ["
                + minRow + ", " + maxRow + "], [" + minCol + ", " + maxCol + "]");
        }
    }

    /**
     * Checks that the input vector has the same dimensionality as this's
     * numRows (otherwise, there can be no solution for Ax = b).
     *
     * @param b The RHS vector
     * @throws IllegalArgumentException if the input's size doesn't match this's
     * numRows
     */
    final protected void checkSolveDimensions(
        final Vector b)
    {
        if (b.getDimensionality() != this.getNumRows())
        {
            throw new IllegalArgumentException("Input vector (length = "
                + b.getDimensionality()
                + ") can't be \"solved\" with by a matrix with dimensions "
                + getNumRows() + "x" + getNumColumns());
        }
    }

    /**
     * Checks that the input matrix has the same numRows as this's numRows
     * (otherwise, there can be no soluation for Ax = b).
     *
     * @param b The RHS matrix
     * @throws IllegalArgumentException if the input's size doesn't match this's
     * numRows
     */
    final protected void checkSolveDimensions(
        final Matrix b)
    {
        if (b.getNumRows() != this.getNumRows())
        {
            throw new IllegalArgumentException("Input matrix (numRows = "
                + b.getNumRows()
                + ") can't be \"solved\" with by a matrix with dimensions "
                + getNumRows() + "x" + getNumColumns());
        }
    }

    @Override
    final public String toString(
        final NumberFormat format)
    {
        StringBuilder sb = new StringBuilder();
        int m = getNumRows();
        int n = getNumColumns();
        for (int i = 0; i < m; ++i)
        {
            for (int j = 0; j < n; ++j)
            {
                sb.append(format.format(get(i, j))).append(" ");
            }
            sb.append('\n');
        }

        return sb.toString();
    }

    @Override
    public Iterator iterator()
    {
        return new MatrixIterator(this);
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy