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

ch.akuhn.matrix.eigenvalues.FewEigenvalues Maven / Gradle / Ivy

There is a newer version: 1.3.10
Show newest version
package ch.akuhn.matrix.eigenvalues;

import java.util.Arrays;

import org.netlib.arpack.ARPACK;
import org.netlib.util.doubleW;
import org.netlib.util.intW;

import ch.akuhn.matrix.Matrix;
import ch.akuhn.matrix.Vector;

/**
 * Finds a few eigenvalues of a matrix.
 * 

* This class use ARPACK to find a few eigenvalues (λ) and corresponding * eigenvectors (x) for the standard eigenvalue problem: * *

 * Ax = λx
 * 
* * where A is an n × n real * symmetric matrix. *

* The only thing that must be supplied in order to use this class on your * problem is to change the array dimensions appropriately, to specify * which eigenvalues you want to compute and to supply a matrix-vector * product * *

 * w ← Av
 * 
* * in the {@link #callback(Vector)} method. *

* Please refer to the ARPACK guide for further information. *

* Example: * *

 * Matrix A = …square matrix…;
 * Eigenvalues eigen = Eigenvalues.of(A).largest(4);
 * eigen.run();
 * double[] l = eigen.values;
 * Vector[] x = eigen.vectors;
 * 
* * @author Adrian Kuhn (Java) based on ddsimp.f by Richard Lehoucq, * Danny Sorensen, Chao Yang (Fortran) * * @see "http://www.caam.rice.edu/software/ARPACK/UG" * */ @SuppressWarnings("javadoc") public abstract class FewEigenvalues extends Eigenvalues { private enum Which { LA, SA, LM, SM, BE }; private Which which; public static FewEigenvalues of(final Matrix matrix) { assert matrix.isSquare(); return new FewEigenvalues(matrix.columnCount()) { @Override protected Vector callback(Vector vector) { return matrix.mult(vector); } }; } public FewEigenvalues(int n) { super(n); this.greatest(20); } private FewEigenvalues which(Which which, int nev) { this.which = which; this.nev = nev < n ? nev : n - 1; return this; } /** Compute the largest algebraic eigenvalues. */ @Override public FewEigenvalues largest(int nev0) { return which(Which.LA, nev0); } /** Compute the smallest algebraic eigenvalues. */ public FewEigenvalues smallest(int nev0) { return which(Which.SA, nev0); } /** Compute the largest eigenvalues in magnitude. */ public FewEigenvalues greatest(int nev0) { return which(Which.LM, nev0); } /** Compute the smallest eigenvalues in magnitude. */ public FewEigenvalues lowest(int nev0) { return which(Which.SM, nev0); } /** * Compute eigenvalues from both end of the spectrum. When the * nev is odd, compute one more from the high end than from the * low end. */ public FewEigenvalues fromBothEnds(int nev0) { return which(Which.BE, nev0); } /** * Runs the eigenvalue decomposition, using an implicitly restarted Arnoldi * process (IRAP). Please refer to the ARPACK guide for more information. * */ @Override public Eigenvalues run() { final ARPACK arpack = ARPACK.getInstance(); /* * Setting up parameters for DSAUPD call. */ final intW ido = new intW(0); // must start zero final String bmat = "I"; // standard problem final doubleW tol = new doubleW(0); // uses machine precision final intW info = new intW(0); // request random starting vector final double[] resid = new double[n]; // allocate starting vector /* * NVC is the largest number of basis vectors that will be used in the * Implicitly Restarted Arnoldi Process. Work per major iteration is * proportional to N*NCV*NCV. */ final int ncv = Math.min(nev * 4, n); // rule of thumb use twice nev final double[] v = new double[n * ncv]; final double[] workd = new double[3 * n]; final double[] workl = new double[ncv * (ncv + 8)]; // Parameters final int[] iparam = new int[11]; { final int ishfts = 1; // use the exact shift strategy final int maxitr = 300; // max number of Arnoldi iterations final int mode = 1; // use "mode 1" iparam[1 - 1] = ishfts; iparam[3 - 1] = maxitr; iparam[7 - 1] = mode; } final int[] ipntr = new int[11]; // debug setting org.netlib.arpack.arpack_debug.ndigit.val = -3; org.netlib.arpack.arpack_debug.logfil.val = 6; org.netlib.arpack.arpack_debug.msgets.val = 0; org.netlib.arpack.arpack_debug.msaitr.val = 0; org.netlib.arpack.arpack_debug.msapps.val = 0; org.netlib.arpack.arpack_debug.msaupd.val = 0; org.netlib.arpack.arpack_debug.msaup2.val = 0; org.netlib.arpack.arpack_debug.mseigt.val = 0; org.netlib.arpack.arpack_debug.mseupd.val = 0; /* * Main loop (reverse communication loop) * * Repeatedly calls the routine DSAUPD and takes actions indicated by * parameter IDO until either convergence is indicated or maxitr has * been exceeded. */ assert n > 0; assert nev > 0; assert ncv > nev && ncv <= n; while (true) { arpack.dsaupd( ido, // reverse communication parameter bmat, // "I" = standard problem n, // problem size which.name(), // which values are requested? nev, // who many values? tol, // 0 = use machine precision resid, ncv, v, n, iparam, ipntr, workd, workl, workl.length, info); if (!(ido.val == 1 || ido.val == -1)) break; /* * Perform matrix vector multiplication * * y <--- OP*x * * The user should supply his own matrix- vector multiplication * routine here that takes workd(ipntr(1)) as the input, and return * the result to workd(ipntr(2)). */ final int x0 = ipntr[1 - 1] - 1; // Fortran is off-by-one compared // to Java! final int y0 = ipntr[2 - 1] - 1; final Vector x = Vector.copy(workd, x0, n); final Vector y = this.callback(x); assert y.size() == n; y.storeOn(workd, y0); } /* * Either we have convergence or there is an error. */ if (info.val != 0) throw new Error("dsaupd ERRNO = " + info.val + ", see http://www.caam.rice.edu/software/ARPACK/UG/node136.html"); /* * Post-Process using DSEUPD. * * Computed eigenvalues may be extracted. * * The routine DSEUPD now called to do this post processing (other modes * may require more complicated post processing than "mode 1"). */ final boolean rvec = true; // request vectors final boolean[] select = new boolean[ncv]; final double[] d = new double[ncv * 2]; final double sigma = 0; // not used in "mode 1" final intW ierr = new intW(0); final intW nevW = new intW(nev); arpack.dseupd( rvec, "All", select, d, v, n, sigma, bmat, n, which.name(), nevW, tol.val, resid, ncv, v, n, iparam, ipntr, workd, workl, workl.length, ierr); if (ierr.val < 0) throw new Error("dseupd ERRNO = " + info.val + ", see http://www.caam.rice.edu/software/ARPACK/UG/node136.html"); /* * Eigenvalues are returned in the first column of the two dimensional * array D and the corresponding eigenvectors are returned in the first * NCONV (=IPARAM(5)) columns of the two dimensional array V if * requested. Otherwise, an orthogonal basis for the invariant subspace * corresponding to the eigenvalues in D is returned in V. */ final int nconv = iparam[5 - 1]; value = Arrays.copyOf(d, nconv); vector = new Vector[nconv]; for (int i = 0; i < value.length; i++) { vector[i] = Vector.copy(v, i * n, n); } return this; } protected abstract Vector callback(Vector vector); }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy