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

no.uib.cipr.matrix.sparse.ArpackSym Maven / Gradle / Ivy

Go to download

Matrix data structures, linear solvers, least squares methods, eigenvalue, and singular value decompositions. For larger random dense matrices (above ~ 350 x 350) matrix-matrix multiplication C = A.B is about 50% faster than MTJ.

There is a newer version: 1.1.0
Show newest version
package no.uib.cipr.matrix.sparse;

import com.github.fommil.netlib.ARPACK;
import no.uib.cipr.matrix.*;
import org.netlib.util.doubleW;
import org.netlib.util.intW;

import java.util.Comparator;
import java.util.Map;
import java.util.TreeMap;
import java.util.logging.Logger;

/**
 * Uses ARPACK to partially solve symmetric eigensystems (ARPACK is designed to
 * compute a subset of eigenvalues/eigenvectors).
 *
 * @author Sam Halliday
 */
public class ArpackSym {

    public enum Ritz {
        /**
         * compute the NEV largest (algebraic) eigenvalues.
         */
        LA,
        /**
         * compute the NEV smallest (algebraic) eigenvalues.
         */
        SA,
        /**
         * compute the NEV largest (in magnitude) eigenvalues.
         */
        LM,
        /**
         * compute the NEV smallest (in magnitude) eigenvalues.
         */
        SM,
        /**
         * compute NEV eigenvalues, half from each end of the spectrum
         */
        BE
    }

    private static final Logger log = Logger.getLogger(ArpackSym.class.getName());

    private final ARPACK arpack = ARPACK.getInstance();

    private static final double TOL = 0.0001;

    private static final boolean EXPENSIVE_CHECKS = true;

    private final Matrix matrix;

    public ArpackSym(Matrix matrix) {
        if (!matrix.isSquare())
            throw new IllegalArgumentException("matrix must be square");
        if (EXPENSIVE_CHECKS)
            for (MatrixEntry entry : matrix) {
                if (entry.get() != matrix.get(entry.column(), entry.row()))
                    throw new IllegalArgumentException(
                            "matrix must be symmetric");
            }
        this.matrix = matrix;
    }

    /**
     * Solve the eigensystem for the number of eigenvalues requested.
     * 

* NOTE: The references to the eigenvectors will keep alive a reference to a * {@code nev * n} double array, so use the {@code copy()} method to free it * up if only a subset is required. * * @param eigenvalues * @param ritz * preference for solutions * @return a map from eigenvalues to corresponding eigenvectors. */ public Map solve(int eigenvalues, Ritz ritz) { if (eigenvalues <= 0) throw new IllegalArgumentException(eigenvalues + " <= 0"); if (eigenvalues >= matrix.numColumns()) throw new IllegalArgumentException(eigenvalues + " >= " + (matrix.numColumns())); int n = matrix.numRows(); intW nev = new intW(eigenvalues); int ncv = Math.min(2 * eigenvalues, n); String bmat = "I"; String which = ritz.name(); doubleW tol = new doubleW(TOL); intW info = new intW(0); int[] iparam = new int[11]; iparam[0] = 1; iparam[2] = 300; iparam[6] = 1; intW ido = new intW(0); // used for initial residual (if info != 0) // and eventually the output residual double[] resid = new double[n]; // Lanczos basis vectors double[] v = new double[n * ncv]; // Arnoldi reverse communication double[] workd = new double[3 * n]; // private work array double[] workl = new double[ncv * (ncv + 8)]; int[] ipntr = new int[11]; int i = 0; while (true) { i++; arpack.dsaupd(ido, bmat, n, which, nev.val, tol, resid, ncv, v, n, iparam, ipntr, workd, workl, workl.length, info); if (ido.val == 99) break; if (ido.val != -1 && ido.val != 1) throw new IllegalStateException("ido = " + ido.val); // could be refactored to handle the other types of mode av(workd, ipntr[0] - 1, ipntr[1] - 1); } ArpackSym.log.fine(i + " iterations for " + n); if (info.val != 0) throw new IllegalStateException("info = " + info.val); double[] d = new double[nev.val]; boolean[] select = new boolean[ncv]; double[] z = java.util.Arrays.copyOfRange(v, 0, nev.val * n); arpack.dseupd(true, "A", select, d, z, n, 0, bmat, n, which, nev, TOL, resid, ncv, v, n, iparam, ipntr, workd, workl, workl.length, info); if (info.val != 0) throw new IllegalStateException("info = " + info.val); int computed = iparam[4]; ArpackSym.log.fine("computed " + computed + " eigenvalues"); Map solution = new TreeMap( new Comparator() { @Override public int compare(Double o1, Double o2) { // highest first return Double.compare(o2, o1); } }); DenseVector eigenvectors = new DenseVector(z, false); for (i = 0; i < computed; i++) { double eigenvalue = d[i]; DenseVectorSub eigenvector = new DenseVectorSub(eigenvectors, i * n, n); solution.put(eigenvalue, eigenvector); } return solution; } private void av(double[] work, int input_offset, int output_offset) { DenseVector w = new DenseVector(work, false); Vector x = new DenseVectorSub(w, input_offset, matrix.numColumns()); Vector y = new DenseVectorSub(w, output_offset, matrix.numColumns()); matrix.mult(x, y); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy