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

ch.akuhn.matrix.SparseMatrix Maven / Gradle / Ivy

package ch.akuhn.matrix;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Random;
import java.util.Scanner;

import ch.akuhn.matrix.Vector.Entry;

/**
 * A sparse matrix
 * 
 * @author Adrian Kuhn
 */
public class SparseMatrix extends KuhnMatrix {

    private static final Random random = new Random();

    private int columns;

    private List rows;

    /**
     * Construct with the given values
     * 
     * @param values
     */
    public SparseMatrix(double[][] values) {
        this.columns = values[0].length;
        this.rows = new ArrayList(values.length);
        for (double[] each : values) {
            addRow(each);
        }
    }

    /**
     * Construct with the given size
     * 
     * @param rows
     * @param columns
     */
    public SparseMatrix(int rows, int columns) {
        this.columns = columns;
        this.rows = new ArrayList(rows);
        for (int times = 0; times < rows; times++) {
            addRow();
        }
    }

    @Override
    public double add(int row, int column, double sum) {
        return rows.get(row).add(column, sum);
    }

    /**
     * Add a new column to the end, increasing the number of columns by 1
     * 
     * @return number of cols BEFORE new one was added
     */
    public int addColumn() {
        columns++;
        for (Vector each : rows) {
            ((KuhnSparseVector) each).resizeTo(columns);
        }
        return columns - 1;
    }

    /**
     * Add a new row to the end, increasing the number of rows by 1
     * 
     * @return number of rows BEFORE new one was added
     */
    public int addRow() {
        rows.add(new KuhnSparseVector(columns));
        return rowCount() - 1;
    }

    protected int addRow(double[] values) {
        rows.add(new KuhnSparseVector(values));
        return rowCount() - 1;
    }

    /**
     * Add the given values to the given row
     * 
     * @param row
     * @param values
     */
    public void addToRow(int row, Vector values) {
        Vector v = rows.get(row);
        for (Entry each : values.entries()) {
            v.add(each.index, each.value);
        }
    }

    /**
     * Convert to a dense 2d double array
     * 
     * @return 2d double array
     */
    public double[][] asDenseDoubleDouble() {
        double[][] dense = new double[rowCount()][columnCount()];
        for (int ri = 0; ri < rows.size(); ri++) {
            Vector row = rows.get(ri);
            for (Entry column : row.entries()) {
                dense[ri][column.index] = column.value;
            }
        }
        return dense;
    }

    @Override
    public int columnCount() {
        return columns;
    }

    @Override
    public boolean equals(Object other) {
        return other instanceof SparseMatrix && rows.equals(((SparseMatrix) other).rows);
    }

    @Override
    public double get(int row, int column) {
        return rows.get(row).get(column);
    }

    @Override
    public int hashCode() {
        return rows.hashCode();
    }

    @Override
    public double put(int row, int column, double value) {
        return rows.get(row).put(column, value);
    }

    @Override
    public Iterable rows() {
        return Collections.unmodifiableCollection(rows);
    }

    @Override
    public Vector row(int row) {
        return this.rows.get(row);
    }

    @Override
    public int rowCount() {
        return rows.size();
    }

    /**
     * Sets the row, no check is made on {@link KuhnSparseVector#size()} Use with
     * care.
     * 
     * @param row
     * @param values
     */
    public void setRow(int row, KuhnSparseVector values) {
        rows.set(row, values);
    }

    @Override
    public int used() {
        int used = 0;
        for (Vector each : rows) {
            used += each.used();
        }
        return used;
    }

    /**
     * Trim each row
     */
    public void trim() {
        for (Vector each : rows) {
            ((KuhnSparseVector) each).trim();
        }
    }

    /**
     * Read matrix from {@link Scanner}
     * 
     * @param scan
     * @return the matrix
     */
    public static SparseMatrix readFrom(Scanner scan) {
        int columns = scan.nextInt();
        int rows = scan.nextInt();
        int used = scan.nextInt();
        SparseMatrix matrix = new SparseMatrix(rows, columns);
        for (int row = 0; row < rows; row++) {
            final int len = scan.nextInt();
            for (int i = 0; i < len; i++) {
                int column = scan.nextInt();
                double value = scan.nextDouble();
                matrix.put(row, column, value);
            }
        }
        if (matrix.used() != used) {
            throw new IllegalStateException("matrix.used() != used");
        }
        return matrix;
    }

    /**
     * Create a random matrix
     * 
     * @param n
     * @param m
     * @param density
     * @return the matrix
     */
    public static SparseMatrix random(int n, int m, double density) {
        SparseMatrix A = new SparseMatrix(n, m);
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
                if (random.nextDouble() > density) {
                    continue;
                }
                A.put(i, j, random.nextDouble());
            }
        }
        return A;
    }

    @Override
    public Vector mult(Vector dense) {
        if (dense.size() != columnCount()) {
            throw new IllegalArgumentException("Vector.size() != columnCount() : " + dense.size());
        }
        double[] y = new double[this.rowCount()];
        double[] x = ((DenseVector) dense).values;
        for (int i = 0; i < y.length; i++) {
            KuhnSparseVector row = (KuhnSparseVector) rows.get(i);
            double sum = 0.0;
            for (int k = 0; k < row.used; k++) {
                sum += x[row.keys[k]] * row.values[k];
            }
            y[i] = sum;
        }
        return Vector.wrap(y);
    }

    @Override
    public Vector transposeMultiply(Vector dense) {
        if (dense.size() != rowCount()) {
            throw new IllegalArgumentException("Vector.size() != rowCount() : " + dense.size());
        }
        double[] y = new double[this.columnCount()];
        double[] x = ((DenseVector) dense).values;
        for (int i = 0; i < x.length; i++) {
            KuhnSparseVector row = (KuhnSparseVector) rows.get(i);
            for (int k = 0; k < row.used; k++) {
                y[row.keys[k]] += x[i] * row.values[k];
            }
        }
        return Vector.wrap(y);
    }

    @Override
    public KuhnMatrix newInstance(int rows, int cols) {
        return new SparseMatrix(rows, cols);
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy