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

gov.sandia.cognition.math.matrix.mtj.AbstractSparseMatrix Maven / Gradle / Ivy

There is a newer version: 4.0.1
Show newest version
/*
 * File:                AbstractSparseMatrix.java
 * Authors:             Kevin R. Dixon
 * Company:             Sandia National Laboratories
 * Project:             Cognitive Foundry
 *
 * Copyright April 11, 2006, 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.mtj;

import gov.sandia.cognition.annotation.CodeReview;
import gov.sandia.cognition.math.OperationNotConvergedException;
import gov.sandia.cognition.math.matrix.MatrixEntry;
import java.text.NumberFormat;
import no.uib.cipr.matrix.sparse.QMR;

/**
 * Implements some generic operations that any sparse-matrix representation
 * must do.
 *
 * @author Kevin R. Dixon
 * @since  1.0
 *
 */
@CodeReview(
    reviewer="Jonathan McClain",
    date="2006-05-19",
    changesNeeded=false,
    comments="Looks fine."
)
public abstract class AbstractSparseMatrix
    extends AbstractMTJMatrix
{

    /**
     * Creates a new instance of AbstractSparseMatrix using the given MTJ matrix
     * @param internalMatrix
     *          internal MTJ matrix to base this on
     */
    protected AbstractSparseMatrix(
        no.uib.cipr.matrix.Matrix internalMatrix )
    {
        super( internalMatrix );
    }

    /**
     * Compact the memory used by the matrix, getting rid of any zero elements
     */
    public abstract void compact();

    public SparseVector times(
        final AbstractMTJVector vector )
    {
        SparseVector answer = new SparseVector( this.getNumRows() );
        this.timesInto( vector, answer );
        return answer;
    }

    @Override
    public void setElement(
        int rowIndex,
        int columnIndex,
        double value )
    {
        // Only set a value in a SparseVector if it's different than what's
        // in there already!
        // (This is to prevent us from adding zeros into the SparseVector
        // unnecessarily)
        double existing = this.getElement( rowIndex, columnIndex );
        if (existing != value)
        {
            super.setElement( rowIndex, columnIndex, value );
        }

    }

    /**
     * This sparse-vector solver performs iterative solving for "x" in the
     * equation: this*x = b, and the AbstractSparseMatrix "this" can be
     * unstructured (e.g., asymmetric, indefinite, etc.)
     * @param b {@inheritDoc}
     * @return  {@inheritDoc}
     */
    @Override
    public SparseVector solve(
        final AbstractMTJVector b )
    {

        int M = this.getNumRows();
        int N = this.getNumColumns();

        AbstractSparseMatrix Asquare;
        int S = Math.max( M, N );
        if (M != N)
        {
            Asquare = new SparseMatrix( S, S );
            Asquare.setSubMatrix( 0, 0, this );
        }
        else
        {
            Asquare = this;
        }

        AbstractMTJVector bsquare;
        if (S != M)
        {
            bsquare = new SparseVector( S );
            for (int i = 0; i < M; i++)
            {
                bsquare.setElement( i, b.getElement( i ) );
            }
        }
        else
        {
            bsquare = b;
        }

        SparseVector xsquare = new SparseVector( Asquare.getNumColumns() );

        QMR sparseSolver = new QMR( xsquare.getInternalVector() );
        try
        {
            sparseSolver.solve( Asquare.getInternalMatrix(), bsquare.getInternalVector(), xsquare.getInternalVector() );
        }
        catch (Exception ex)
        {
            throw new OperationNotConvergedException(ex);
        }

        SparseVector x;
        if (S != N)
        {
            x = new SparseVector( N );
            for (int i = 0; i < N; i++)
            {
                x.setElement( i, xsquare.getElement( i ) );
            }
        }
        else
        {
            x = xsquare;
        }

        return x;
    }

    public DenseMatrix pseudoInverse(
        double effectiveZero )
    {
        DenseMatrix Ainternal = new DenseMatrix( this );
        return Ainternal.pseudoInverse( effectiveZero );
    }

    /**
     * Creates a string in the "(Row,Column): value" for the nonzero elements
     * @return String representing the sparse matrix
     */
    @Override
    public String toString()
    {
        final StringBuilder result = new StringBuilder(100);

        for (MatrixEntry e : this)
        {
            result.append("(");
            result.append(e.getRowIndex());
            result.append(",");
            result.append(e.getColumnIndex());
            result.append("): ");
            result.append(e.getValue());
            result.append("\n");
        }

        if (result.length() == 0)
        {
            result.append("No nonzero entries");
        }

        return result.toString();
    }

    public String toString(
        final NumberFormat format)
    {
        final StringBuilder result = new StringBuilder();

        for (MatrixEntry e : this)
        {
            result.append("(");
            result.append(e.getRowIndex());
            result.append(",");
            result.append(e.getColumnIndex());
            result.append("): ");
            result.append(format.format(e.getValue()));
            result.append("\n");
        }

        if (result.length() == 0)
        {
            result.append("No nonzero entries");
        }

        return result.toString();
    }

    public SparseVector getColumn(
        int columnIndex )
    {
        int M = this.getNumRows();
        SparseVector columnVector = new SparseVector( M );
        for (int i = 0; i < M; i++)
        {
            double value = this.getElement( i, columnIndex );
            if (value != 0.0)
            {
                columnVector.setElement( i, value );
            }
        }
        return columnVector;
    }

    public SparseVector getRow(
        int rowIndex )
    {
        int N = this.getNumColumns();
        SparseVector rowVector = new SparseVector( N );
        for (int j = 0; j < N; j++)
        {
            double value = this.getElement( rowIndex, j );
            if (value != 0.0)
            {
                rowVector.setElement( j, value );
            }
        }
        return rowVector;
    }

    @Override
    public boolean isSparse()
    {
        return true;
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy