eu.crisis_economics.abm.firm.io.InputOutputMatrix.java Source code

Java tutorial

Introduction

Here is the source code for eu.crisis_economics.abm.firm.io.InputOutputMatrix.java

Source

/*
 * This file is part of CRISIS, an economics simulator.
 * 
 * Copyright (C) 2015 Ross Richardson
 * Copyright (C) 2015 John Kieran Phillips
 *
 * CRISIS is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * CRISIS is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with CRISIS.  If not, see <http://www.gnu.org/licenses/>.
 */
package eu.crisis_economics.abm.firm.io;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.math3.exception.DimensionMismatchException;
import org.apache.commons.math3.exception.NoDataException;
import org.apache.commons.math3.exception.NotPositiveException;
import org.apache.commons.math3.exception.NotStrictlyPositiveException;
import org.apache.commons.math3.exception.NullArgumentException;
import org.apache.commons.math3.exception.NumberIsTooSmallException;
import org.apache.commons.math3.exception.OutOfRangeException;
import org.apache.commons.math3.linear.MatrixDimensionMismatchException;
import org.apache.commons.math3.linear.MatrixUtils;
import org.apache.commons.math3.linear.NonSquareMatrixException;
import org.apache.commons.math3.linear.RealMatrix;
import org.apache.commons.math3.linear.RealMatrixChangingVisitor;
import org.apache.commons.math3.linear.RealMatrixPreservingVisitor;
import org.apache.commons.math3.linear.RealVector;

import com.google.common.base.Preconditions;

/**
  * A forwarding implementation of the {@link RealMatrix} interface. This class
  * supplements {@link RealMatrix} with named rows and columns. Each row and
  * column in the matrix is linked to a verbose {@link String} name.
  * 
  * @author phillips
  */
public final class InputOutputMatrix implements RealMatrix {

    private RealMatrix matrix;
    private Map<String, Integer> columnsByName;
    private List<String> namesOfColumns;

    /**
      * Create a forwarding {@link RealMatrix} object supplemented with named
      * rows and columns. The rows and columns of this matrix correspond to 
      * {@link String} names. The methods {@link #getNameByIndex(int)} and
      * {@link #getIndexByName(String)} query {@code (a)} {@link String} names by 
      * matrix index and {@code (b)} matrix index by {@link String} names,
      * respectively.<br><br>
      * 
      * The input matrix <code>R</code> must have the following properies:<br>
      * <ul>
      *   <li> It must not be the case that any entire row of <code>R</code> is zero,
      *   <li> It must not be the case that <code>R</code> has dimension zero, and
      *   <li> No element of <code>R</code> may be negative.
      * </ul>
      * 
      * If any of these conditions are untrue of the input matrix,
      * {@link IllegalArgumentException} is raised.<br><br>
      * 
      * The columns of <code>R</code> <u>need not be regularized</u> in such a way
      * that the sum over all elements in each column of <code>R</code> is 
      * equal to <code>1.0</code>. This constructor will modify a copy of
      * the input matrix so as to ensure this.<br><br>
      * 
      * @param matrix
      *        The underlying {@link RealMatrix} to use. This matrix must be 
      *        square. A copy of this matrix is made.
      * @param columnNames
      *        The {@link String} names of each row and column for this matrix.
      *        The length of this collection should be exactly equal to the 
      *        dimension of the input matrix.
      */
    public InputOutputMatrix(final RealMatrix input, final List<String> columnNames) {
        this.matrix = Preconditions.checkNotNull(MatrixUtils.createRealMatrix(input.getData()));
        this.columnsByName = new HashMap<String, Integer>();
        this.namesOfColumns = new ArrayList<String>();
        final int dimension = matrix.getColumnDimension();

        // Check for zero or non-square matrix dimensions
        if (dimension == 0)
            throw new IllegalArgumentException("InputOutputMatrix: matrix dimension is zero.");
        if (dimension != matrix.getRowDimension())
            throw new IllegalArgumentException(
                    "InputOutputMatrix: matrix is not square. The dimensions of the input matrix " + "are ["
                            + matrix.getRowDimension() + ", " + matrix.getColumnDimension() + "].");

        // Check for negative entries
        for (int i = 0; i < matrix.getRowDimension(); ++i)
            for (int j = 0; j < matrix.getRowDimension(); ++j)
                if (matrix.getEntry(i, j) < 0.)
                    throw new IllegalArgumentException("InputOutputMatrix: matrix contains a negative value: "
                            + String.format("[i:%d j:%d value:%g]", i, j, matrix.getEntry(i, j)));

        // Check whether sector names correspond to matrix elements
        if (columnNames.size() != dimension)
            throw new IllegalArgumentException(
                    "InputOutputMatrix: the number of column names specified does not correspond to "
                            + "the dimension of the matrix. Matrix dimension: " + dimension + ", number of "
                            + "names specified: " + columnNames.size() + ".");

        for (int i = 0; i < columnNames.size(); ++i) {
            columnsByName.put(columnNames.get(i), i);
            namesOfColumns.add(columnNames.get(i));
        }

        // Normalize the columns of the matrix so that each column sums to 1.0:
        for (int i = 0; i < dimension; ++i) {
            double sum = 0.;
            for (int j = 0; j < dimension; ++j)
                sum += matrix.getEntry(j, i);
            for (int j = 0; j < dimension; ++j)
                matrix.setEntry(j, i, matrix.getEntry(j, i) / sum);
        }
    }

    /**
      * Get the index of a sector name (a {@link String}). This method returns the 
      * {@link Integer} index of the sector name if the sector name is known to this
      * object. Otherwise, this method returns <code>null</code>.
      * 
      * @param name
      *        The name of the sector. This argument must be non-<code>null</code>.
      */
    public Integer getIndexByName(final String name) {
        return columnsByName.get(name);
    }

    /**
      * Get the {@link String} name of a sector by its {@link Integer} index. This
      * method will return a non-<code>null</code> {@link String} provided that
      * the argument is nonzero and less then the dimension of the matrix.
      * 
      * @param index
      *        The index of the sector to query. This argument should be nonzero 
      *        and strictly less than the dimension of the matrix. Otherwise,
      *        {@link IllegalArgumentException} is raised.
      */
    public String getNameByIndex(final int index) {
        if (index >= namesOfColumns.size())
            throw new IllegalArgumentException(
                    "InputOutputMatrix.getNameByIndex: the index specified exceeds the matrix dimension.");
        if (index < 0)
            throw new IllegalArgumentException(
                    "InputOutputMatrix.getNameByIndex: the index specified is negative.");
        return namesOfColumns.get(index);
    }

    /**
      * Get a column from this {@link InputOutputMatrix} with both matrix values
      * and sector names. The column is returned as a {@link Map} indexed by sector 
      * name.
      * 
      * @param columnIndex
      *        The column index to query. This argument should be non-negative
      *        and less than the dimension of this {@link InputOutputMatrix}.
      */
    public Map<String, Double> getColumnWithNames(final int columnIndex) {
        if (columnIndex < 0)
            throw new IllegalArgumentException(
                    getClass().getSimpleName() + ": column index requested is negative.");
        if (columnIndex >= getColumnDimension())
            throw new IllegalArgumentException(getClass().getSimpleName() + ": column index is out of range.");
        final Map<String, Double> result = new HashMap<String, Double>();
        for (int i = 0; i < namesOfColumns.size(); ++i) {
            final String sectorName = namesOfColumns.get(i);
            result.put(sectorName, matrix.getEntry(i, columnIndex));
        }
        return result;
    }

    public RealMatrix add(RealMatrix arg0) throws MatrixDimensionMismatchException {
        return matrix.add(arg0);
    }

    public void addToEntry(int arg0, int arg1, double arg2) throws OutOfRangeException {
        matrix.addToEntry(arg0, arg1, arg2);
    }

    public RealMatrix copy() {
        return matrix.copy();
    }

    public void copySubMatrix(int arg0, int arg1, int arg2, int arg3, double[][] arg4)
            throws OutOfRangeException, NumberIsTooSmallException, MatrixDimensionMismatchException {
        matrix.copySubMatrix(arg0, arg1, arg2, arg3, arg4);
    }

    public void copySubMatrix(int[] arg0, int[] arg1, double[][] arg2)
            throws OutOfRangeException, NullArgumentException, NoDataException, MatrixDimensionMismatchException {
        matrix.copySubMatrix(arg0, arg1, arg2);
    }

    public RealMatrix createMatrix(int arg0, int arg1) throws NotStrictlyPositiveException {
        return matrix.createMatrix(arg0, arg1);
    }

    public double[] getColumn(int arg0) throws OutOfRangeException {
        return matrix.getColumn(arg0);
    }

    public int getColumnDimension() {
        return matrix.getColumnDimension();
    }

    public RealMatrix getColumnMatrix(int arg0) throws OutOfRangeException {
        return matrix.getColumnMatrix(arg0);
    }

    public RealVector getColumnVector(int arg0) throws OutOfRangeException {
        return matrix.getColumnVector(arg0);
    }

    public double[][] getData() {
        return matrix.getData();
    }

    public double getEntry(int arg0, int arg1) throws OutOfRangeException {
        return matrix.getEntry(arg0, arg1);
    }

    public double getFrobeniusNorm() {
        return matrix.getFrobeniusNorm();
    }

    public double getNorm() {
        return matrix.getNorm();
    }

    public double[] getRow(int arg0) throws OutOfRangeException {
        return matrix.getRow(arg0);
    }

    public int getRowDimension() {
        return matrix.getRowDimension();
    }

    public RealMatrix getRowMatrix(int arg0) throws OutOfRangeException {
        return matrix.getRowMatrix(arg0);
    }

    public RealVector getRowVector(int arg0) throws OutOfRangeException {
        return matrix.getRowVector(arg0);
    }

    public RealMatrix getSubMatrix(int arg0, int arg1, int arg2, int arg3)
            throws OutOfRangeException, NumberIsTooSmallException {
        return matrix.getSubMatrix(arg0, arg1, arg2, arg3);
    }

    public RealMatrix getSubMatrix(int[] arg0, int[] arg1)
            throws NullArgumentException, NoDataException, OutOfRangeException {
        return matrix.getSubMatrix(arg0, arg1);
    }

    public double getTrace() throws NonSquareMatrixException {
        return matrix.getTrace();
    }

    public boolean isSquare() {
        return matrix.isSquare();
    }

    public RealMatrix multiply(RealMatrix arg0) throws DimensionMismatchException {
        return matrix.multiply(arg0);
    }

    public void multiplyEntry(int arg0, int arg1, double arg2) throws OutOfRangeException {
        matrix.multiplyEntry(arg0, arg1, arg2);
    }

    public double[] operate(double[] arg0) throws DimensionMismatchException {
        return matrix.operate(arg0);
    }

    public RealVector operate(RealVector arg0) throws DimensionMismatchException {
        return matrix.operate(arg0);
    }

    public RealMatrix power(int arg0) throws NotPositiveException, NonSquareMatrixException {
        return matrix.power(arg0);
    }

    public double[] preMultiply(double[] arg0) throws DimensionMismatchException {
        return matrix.preMultiply(arg0);
    }

    public RealMatrix preMultiply(RealMatrix arg0) throws DimensionMismatchException {
        return matrix.preMultiply(arg0);
    }

    public RealVector preMultiply(RealVector arg0) throws DimensionMismatchException {
        return matrix.preMultiply(arg0);
    }

    public RealMatrix scalarAdd(double arg0) {
        return matrix.scalarAdd(arg0);
    }

    public RealMatrix scalarMultiply(double arg0) {
        return matrix.scalarMultiply(arg0);
    }

    public void setColumn(int arg0, double[] arg1) throws OutOfRangeException, MatrixDimensionMismatchException {
        matrix.setColumn(arg0, arg1);
    }

    public void setColumnMatrix(int arg0, RealMatrix arg1)
            throws OutOfRangeException, MatrixDimensionMismatchException {
        matrix.setColumnMatrix(arg0, arg1);
    }

    public void setColumnVector(int arg0, RealVector arg1)
            throws OutOfRangeException, MatrixDimensionMismatchException {
        matrix.setColumnVector(arg0, arg1);
    }

    public void setEntry(int arg0, int arg1, double arg2) throws OutOfRangeException {
        matrix.setEntry(arg0, arg1, arg2);
    }

    public void setRow(int arg0, double[] arg1) throws OutOfRangeException, MatrixDimensionMismatchException {
        matrix.setRow(arg0, arg1);
    }

    public void setRowMatrix(int arg0, RealMatrix arg1)
            throws OutOfRangeException, MatrixDimensionMismatchException {
        matrix.setRowMatrix(arg0, arg1);
    }

    public void setRowVector(int arg0, RealVector arg1)
            throws OutOfRangeException, MatrixDimensionMismatchException {
        matrix.setRowVector(arg0, arg1);
    }

    public void setSubMatrix(double[][] arg0, int arg1, int arg2)
            throws NoDataException, OutOfRangeException, DimensionMismatchException, NullArgumentException {
        matrix.setSubMatrix(arg0, arg1, arg2);
    }

    public RealMatrix subtract(RealMatrix arg0) throws MatrixDimensionMismatchException {
        return matrix.subtract(arg0);
    }

    public RealMatrix transpose() {
        return matrix.transpose();
    }

    public double walkInColumnOrder(RealMatrixChangingVisitor arg0, int arg1, int arg2, int arg3, int arg4)
            throws OutOfRangeException, NumberIsTooSmallException {
        return matrix.walkInColumnOrder(arg0, arg1, arg2, arg3, arg4);
    }

    public double walkInColumnOrder(RealMatrixChangingVisitor arg0) {
        return matrix.walkInColumnOrder(arg0);
    }

    public double walkInColumnOrder(RealMatrixPreservingVisitor arg0, int arg1, int arg2, int arg3, int arg4)
            throws OutOfRangeException, NumberIsTooSmallException {
        return matrix.walkInColumnOrder(arg0, arg1, arg2, arg3, arg4);
    }

    public double walkInColumnOrder(RealMatrixPreservingVisitor arg0) {
        return matrix.walkInColumnOrder(arg0);
    }

    public double walkInOptimizedOrder(RealMatrixChangingVisitor arg0, int arg1, int arg2, int arg3, int arg4)
            throws OutOfRangeException, NumberIsTooSmallException {
        return matrix.walkInOptimizedOrder(arg0, arg1, arg2, arg3, arg4);
    }

    public double walkInOptimizedOrder(RealMatrixChangingVisitor arg0) {
        return matrix.walkInOptimizedOrder(arg0);
    }

    public double walkInOptimizedOrder(RealMatrixPreservingVisitor arg0, int arg1, int arg2, int arg3, int arg4)
            throws OutOfRangeException, NumberIsTooSmallException {
        return matrix.walkInOptimizedOrder(arg0, arg1, arg2, arg3, arg4);
    }

    public double walkInOptimizedOrder(RealMatrixPreservingVisitor arg0) {
        return matrix.walkInOptimizedOrder(arg0);
    }

    public double walkInRowOrder(RealMatrixChangingVisitor arg0, int arg1, int arg2, int arg3, int arg4)
            throws OutOfRangeException, NumberIsTooSmallException {
        return matrix.walkInRowOrder(arg0, arg1, arg2, arg3, arg4);
    }

    public double walkInRowOrder(RealMatrixChangingVisitor arg0) {
        return matrix.walkInRowOrder(arg0);
    }

    public double walkInRowOrder(RealMatrixPreservingVisitor arg0, int arg1, int arg2, int arg3, int arg4)
            throws OutOfRangeException, NumberIsTooSmallException {
        return matrix.walkInRowOrder(arg0, arg1, arg2, arg3, arg4);
    }

    public double walkInRowOrder(RealMatrixPreservingVisitor arg0) {
        return matrix.walkInRowOrder(arg0);
    }

    /**
      * Returns a brief description of this object. The exact details of the
      * string are subject to change, and should not be regarded as fixed.
      */
    @Override
    public String toString() {
        String result = "Input-Output matrix of dimension " + getColumnDimension() + ". \nSector names: \n";
        for (int i = 0; i < namesOfColumns.size(); ++i)
            result += String.format("%3d: %s\n", i + 1, namesOfColumns.get(i));
        result += "Matrix data:\n";
        for (int i = 0; i < getColumnDimension(); ++i) {
            for (int j = 0; j < getColumnDimension(); ++j)
                result += String.format(" %16.10g", matrix.getEntry(i, j));
            result += "\n";
        }
        return result;
    }
}