Files
arpack-ng/EXAMPLES/MATRIX_MARKET/arpackSolver.hpp
T

1188 lines
45 KiB
C++

#ifndef __ARPACKSOLVER_HPP__
#define __ARPACKSOLVER_HPP__
#include "arpack.h"
#include <iostream>
#include <string>
#include <sstream> // stringstream.
#include <fstream> // [io]fstream.
#include <chrono>
#include <iomanip> // setw.
#include <cassert>
#include <vector>
#include <type_traits> // is_same.
#include <cmath> // abs
#include <complex>
#include <limits> // epsilon
#include <Eigen/Sparse>
#include <Eigen/IterativeLinearSolvers>
#include <Eigen/SparseLU>
#include <Eigen/SparseQR>
#include <Eigen/SparseCholesky>
#include <Eigen/Dense>
#include <Eigen/LU>
#include <Eigen/QR>
#include <Eigen/Cholesky>
using namespace std;
// Sparse matrix related types.
typedef Eigen::SparseMatrix< float> EigSMxS; // Real.
typedef Eigen::SparseMatrix< double> EigSMxD; // Real.
typedef Eigen::SparseMatrix<complex< float>> EigSMxC; // Complex.
typedef Eigen::SparseMatrix<complex<double>> EigSMxZ; // Complex.
// Iterative solvers for sparse matrices.
typedef Eigen::BiCGSTAB <EigSMxS> EigSBiCGS; // Real.
typedef Eigen::BiCGSTAB <EigSMxD> EigSBiCGD; // Real.
typedef Eigen::BiCGSTAB <EigSMxC> EigSBiCGC; // Complex.
typedef Eigen::BiCGSTAB <EigSMxZ> EigSBiCGZ; // Complex.
typedef Eigen::ConjugateGradient<EigSMxS> EigSCGS; // Real.
typedef Eigen::ConjugateGradient<EigSMxD> EigSCGD; // Real.
typedef Eigen::ConjugateGradient<EigSMxC> EigSCGC; // Complex.
typedef Eigen::ConjugateGradient<EigSMxZ> EigSCGZ; // Complex.
typedef Eigen::IncompleteLUT< float> EigILUS; // Real.
typedef Eigen::IncompleteLUT< double> EigILUD; // Real.
typedef Eigen::IncompleteLUT<complex< float>> EigILUC; // Complex.
typedef Eigen::IncompleteLUT<complex<double>> EigILUZ; // Complex.
typedef Eigen::BiCGSTAB <EigSMxS, EigILUS> EigSBiCGILUS; // Real.
typedef Eigen::BiCGSTAB <EigSMxD, EigILUD> EigSBiCGILUD; // Real.
typedef Eigen::BiCGSTAB <EigSMxC, EigILUC> EigSBiCGILUC; // Complex.
typedef Eigen::BiCGSTAB <EigSMxZ, EigILUZ> EigSBiCGILUZ; // Complex.
typedef Eigen::ConjugateGradient<EigSMxS, Eigen::Lower|Eigen::Upper, EigILUS> EigSCGILUS; // Real.
typedef Eigen::ConjugateGradient<EigSMxD, Eigen::Lower|Eigen::Upper, EigILUD> EigSCGILUD; // Real.
typedef Eigen::ConjugateGradient<EigSMxC, Eigen::Lower|Eigen::Upper, EigILUC> EigSCGILUC; // Complex.
typedef Eigen::ConjugateGradient<EigSMxZ, Eigen::Lower|Eigen::Upper, EigILUZ> EigSCGILUZ; // Complex.
// Direct solvers for sparse matrices.
typedef Eigen::SimplicialLLT <EigSMxS, Eigen::Lower, Eigen::COLAMDOrdering<int>> EigSLLTS; // Real.
typedef Eigen::SimplicialLLT <EigSMxD, Eigen::Lower, Eigen::COLAMDOrdering<int>> EigSLLTD; // Real.
typedef Eigen::SimplicialLLT <EigSMxC, Eigen::Lower, Eigen::COLAMDOrdering<int>> EigSLLTC; // Complex.
typedef Eigen::SimplicialLLT <EigSMxZ, Eigen::Lower, Eigen::COLAMDOrdering<int>> EigSLLTZ; // Complex.
typedef Eigen::SimplicialLDLT<EigSMxS, Eigen::Lower, Eigen::COLAMDOrdering<int>> EigSLDLTS; // Real.
typedef Eigen::SimplicialLDLT<EigSMxD, Eigen::Lower, Eigen::COLAMDOrdering<int>> EigSLDLTD; // Real.
typedef Eigen::SimplicialLDLT<EigSMxC, Eigen::Lower, Eigen::COLAMDOrdering<int>> EigSLDLTC; // Complex.
typedef Eigen::SimplicialLDLT<EigSMxZ, Eigen::Lower, Eigen::COLAMDOrdering<int>> EigSLDLTZ; // Complex.
typedef Eigen::SparseLU<EigSMxS, Eigen::COLAMDOrdering<int>> EigSLUS; // Real.
typedef Eigen::SparseLU<EigSMxD, Eigen::COLAMDOrdering<int>> EigSLUD; // Real.
typedef Eigen::SparseLU<EigSMxC, Eigen::COLAMDOrdering<int>> EigSLUC; // Complex.
typedef Eigen::SparseLU<EigSMxZ, Eigen::COLAMDOrdering<int>> EigSLUZ; // Complex.
typedef Eigen::SparseQR<EigSMxS, Eigen::COLAMDOrdering<int>> EigSQRS; // Real.
typedef Eigen::SparseQR<EigSMxD, Eigen::COLAMDOrdering<int>> EigSQRD; // Real.
typedef Eigen::SparseQR<EigSMxC, Eigen::COLAMDOrdering<int>> EigSQRC; // Complex.
typedef Eigen::SparseQR<EigSMxZ, Eigen::COLAMDOrdering<int>> EigSQRZ; // Complex.
// Dense matrix related types.
typedef Eigen::Matrix< float, Eigen::Dynamic, Eigen::Dynamic> EigDMxS; // Real.
typedef Eigen::Matrix< double, Eigen::Dynamic, Eigen::Dynamic> EigDMxD; // Real.
typedef Eigen::Matrix<complex< float>, Eigen::Dynamic, Eigen::Dynamic> EigDMxC; // Complex.
typedef Eigen::Matrix<complex<double>, Eigen::Dynamic, Eigen::Dynamic> EigDMxZ; // Complex.
// Direct solvers for dense matrices.
typedef Eigen::LLT<EigDMxS> EigDLLTS; // Real.
typedef Eigen::LLT<EigDMxD> EigDLLTD; // Real.
typedef Eigen::LLT<EigDMxC> EigDLLTC; // Complex.
typedef Eigen::LLT<EigDMxZ> EigDLLTZ; // Complex.
typedef Eigen::LDLT<EigDMxS> EigDLDLTS; // Real.
typedef Eigen::LDLT<EigDMxD> EigDLDLTD; // Real.
typedef Eigen::LDLT<EigDMxC> EigDLDLTC; // Complex.
typedef Eigen::LDLT<EigDMxZ> EigDLDLTZ; // Complex.
typedef Eigen::FullPivLU<EigDMxS> EigDFLUS; // Real.
typedef Eigen::FullPivLU<EigDMxD> EigDFLUD; // Real.
typedef Eigen::FullPivLU<EigDMxC> EigDFLUC; // Complex.
typedef Eigen::FullPivLU<EigDMxZ> EigDFLUZ; // Complex.
typedef Eigen::FullPivHouseholderQR<EigDMxS> EigDFQRS; // Real.
typedef Eigen::FullPivHouseholderQR<EigDMxD> EigDFQRD; // Real.
typedef Eigen::FullPivHouseholderQR<EigDMxC> EigDFQRC; // Complex.
typedef Eigen::FullPivHouseholderQR<EigDMxZ> EigDFQRZ; // Complex.
typedef Eigen::PartialPivLU<EigDMxS> EigDPLUS; // Real.
typedef Eigen::PartialPivLU<EigDMxD> EigDPLUD; // Real.
typedef Eigen::PartialPivLU<EigDMxC> EigDPLUC; // Complex.
typedef Eigen::PartialPivLU<EigDMxZ> EigDPLUZ; // Complex.
typedef Eigen::HouseholderQR<EigDMxS> EigDPQRS; // Real.
typedef Eigen::HouseholderQR<EigDMxD> EigDPQRD; // Real.
typedef Eigen::HouseholderQR<EigDMxC> EigDPQRC; // Complex.
typedef Eigen::HouseholderQR<EigDMxZ> EigDPQRZ; // Complex.
// Definition of arpackSolver class.
typedef Eigen::Matrix<complex<double>, Eigen::Dynamic, 1> EigVecZ;
typedef vector<complex<double>> StdVecZ;
typedef vector<EigVecZ> StdVecEVZ;
// RC: Real or Complex.
// FD: Float or Double.
// EM: Eigen Matrix (sparse or dense).
// SLV: Solver.
template<typename RC, typename FD, typename EM, typename SLV>
class arpackSolver {
// Nested typedef.
typedef Eigen::Map<Eigen::Matrix<RC, Eigen::Dynamic, 1>> EV;
// Public methods.
public:
arpackSolver() {
symPb = true;
nbEV = 1;
nbCV = 2*nbEV+1;
tol = 1.e-6;
sigmaReal = sigmaImag = 0.;
dumpToFile = false;
restartFromFile = false;
mag = "LM";
maxIt = 100;
schur = false;
verbose = 0;
stdPb = true;
mode = 1;
nbIt = 0;
imsTime = 0.;
rciTime = 0.;
nbDim = 0;
resid = nullptr;
v = nullptr;
};
~arpackSolver() {
if (v) {delete [] v; v = nullptr;}
if (resid) {delete [] resid; resid = nullptr;}
};
int createMatrix(string const & fileName, Eigen::SparseMatrix<RC> & M) {
// Read matrix from file.
if (fileName.empty()) { cerr << "Error: matrix file missing" << endl; return 1; }
a_uint n = 0, m = 0;
vector<a_uint> i, j;
vector<RC> Mij;
int rc = readMatrixMarket(fileName, n, m, i, j, Mij);
if (rc != 0) {cerr << "Error: read matrix market file KO" << endl; return rc;}
// Create matrix from file.
M = Eigen::SparseMatrix<RC>(n, m); // Set matrice dimensions.
vector<Eigen::Triplet<RC>> triplets;
a_uint nnz = Mij.size();
triplets.reserve(nnz);
for (size_t k = 0; k < nnz; k++) triplets.emplace_back(i[k], j[k], Mij[k]);
M.setFromTriplets(triplets.begin(), triplets.end()); // Set all (i, j, Mij).
return 0;
};
int createMatrix(string const & fileName, Eigen::Matrix<RC, Eigen::Dynamic, Eigen::Dynamic> & M) {
// Read matrix from file.
a_uint n = 0, m = 0;
vector<a_uint> i, j;
vector<RC> Mij;
int rc = readMatrixMarket(fileName, n, m, i, j, Mij);
if (rc != 0) {cerr << "Error: read matrix market file KO" << endl; return rc;}
// Create matrix from file.
M = Eigen::Matrix<RC, Eigen::Dynamic, Eigen::Dynamic>(n, m); // Set matrice dimensions.
M.setZero(n, m); // Avoid spurious/random values which may break solves (LU, QR, ...).
a_uint nnz = Mij.size();
for (size_t k = 0; k < nnz; k++) M(i[k], j[k]) = Mij[k];
return 0;
};
void dumpParameters() {
if (verbose >= 1) {
cout << endl << "arpackSolver:" << endl;
cout << endl << "symPb: " << symPb << endl;
cout << endl << "nbEV: " << nbEV << endl;
cout << endl << "nbCV: " << nbCV << endl;
cout << endl << "tol: " << tol << endl;
cout << endl << "sigmaReal: " << sigmaReal << endl;
cout << endl << "sigmaImag: " << sigmaImag << endl;
cout << endl << "dumpToFile: " << dumpToFile << endl;
cout << endl << "restartFromFile: " << restartFromFile << endl;
cout << endl << "mag: " << mag << endl;
cout << endl << "maxIt: " << maxIt << endl;
cout << endl << "schur: " << schur << endl;
}
};
int solve(EM & A, EM const * B = nullptr) {
stdPb = !B ? true : false;
if (nbCV > A.cols()) nbCV = A.cols(); // Cut-off arpack workspace dim.
dumpParameters();
if (verbose == 3) {
cout << endl << "arpackSolver:" << endl;
cout << endl << "A:" << endl;
cout << endl << A << endl;
if (B) {
cout << endl << "B:" << endl;
cout << endl << *B << endl;
}
}
nbDim = A.rows();
// If needed, transform the initial problem into a new one that arpack can handle.
auto eps = numeric_limits<FD>::epsilon();
bool shiftReal = (fabs(sigmaReal) > eps) ? true : false;
bool shiftImag = (fabs(sigmaImag) > eps) ? true : false;
bool backTransform = false;
mode = 0;
if (stdPb) {
mode = 1;
// CAUTION: back transform must be done only if mode = 1.
if (shiftReal || shiftImag) {
EM I(A.rows(), A.cols());
I.setIdentity();
RC sigma; makeSigma(sigma);
A -= sigma*I;
backTransform = true;
}
}
else {
// CAUTION: back transform must NOT be done if mode > 1.
mode = 2;
if (shiftReal || shiftImag) mode = 3;
}
if (verbose >= 1) {
cout << endl << "arpackSolver:" << endl;
cout << endl << "mode " << mode << ", backTransform " << (backTransform ? "yes" : "no") << endl;
}
// Solve with arpack.
// Note: when initializing Eigen solvers, API differ depending on solvers.
SLV solver;
int rc = initSolver(solver);
if (rc != 0) {cerr << "Error: initialize solver KO" << endl; return rc;}
rc = solve(A, B, solver);
if (rc != 0) {cerr << "Error: arpack solve KO" << endl; return rc;}
// If needed, transform back the arpack problem into the initial problem.
if (backTransform) {
EM I(A.rows(), A.cols());
I.setIdentity();
RC sigma; makeSigma(sigma);
A += sigma*I;
for (size_t i = 0; i < val.size(); i++) val[i] += sigma;
}
return 0;
};
int checkEigVec(EM const & A, EM const * B = nullptr, double const maxResNorm = 1.e-3) const {
// Check eigen vectors.
string rs = schur ? "Schur" : "Ritz";
if (vec.size() == 0) {
cerr << "Error: no " << rs << " value / vector found" << endl;
return 1;
}
for (size_t i = 0; i < vec.size(); i++) {
EigVecZ V = vec[i];
complex<double> lambda = val[i];
if (verbose >= 1) {
cout << endl << "arpackSolver:" << endl;
cout << endl << rs << " value " << setw(3) << i << ": " << lambda << endl;
if (verbose >= 2) {
cout << endl << rs << " vector " << setw(3) << i << " (norm " << V.norm() << "): " << endl;
cout << endl << V << endl;
}
}
double resNorm = computeResidualNorm(i, A, B);
if (resNorm > maxResNorm) {
cout << endl << "arpackSolver:" << endl;
cout << endl << rs << " value/vector " << setw(3) << i << ": check KO";
cout << ", residual (norm " << resNorm << ", maxResNorm " << maxResNorm << ")" << endl;
return 1;
}
else {
if (verbose >= 1) {
cout << endl << "arpackSolver:" << endl;
cout << endl << rs << " value/vector " << setw(3) << i << ": check OK";
cout << ", residual (norm " << resNorm << ", maxResNorm " << maxResNorm << ")" << endl;
}
}
}
return 0;
};
double computeResidualNorm(size_t const & idx, EM const & A, EM const * B = nullptr) const {
// Check eigen value index.
if (idx >= val.size()) return -1.; // Error.
if (idx >= vec.size()) return -1.; // Error.
// Compute residual norm.
EigVecZ V = vec[idx];
complex<double> lambda = val[idx];
EigVecZ left = A.template cast<complex<double>>() * V;
EigVecZ right = stdPb ? V : B->template cast<complex<double>>() * V;
right *= lambda;
EigVecZ residual = left - right;
return residual.norm();
};
// Private methods.
private:
void makeConstant( float & cst, float const & val) {cst = val;};
void makeConstant( double & cst, double const & val) {cst = val;};
void makeConstant(complex< float> & cst, float const & val) {cst = complex<float>(val, val);};
void makeConstant(complex<double> & cst, double const & val) {cst = complex<double>(val, val);};
int readMatrixMarket(string const & fileName,
a_uint & n, a_uint & m, vector<a_uint> & i, vector<a_uint> & j, vector<RC> & Mij) {
ifstream inp(fileName);
if (!inp) {cerr << "Error: can not open " << fileName << endl; return 1;}
// Read matrix from file.
a_uint l = 0, nnz = 0;
do {
// Skip comments.
string inpLine; getline(inp, inpLine); l++;
while (isspace(*inpLine.begin())) inpLine.erase(inpLine.begin()); // Suppress leading white spaces.
if (inpLine.length() == 0) continue; // Empty line.
if (inpLine[0] == '%' || inpLine[0] == '#') continue; // Comments skipped, begin reading.
// Read matrix market file.
stringstream inpSS(inpLine);
if (n == 0 && m == 0) { // Header.
inpSS >> n >> m;
if (!inpSS) {cerr << "Error: bad header (n, m)" << endl; return 1;}
if (nnz == 0) {
inpSS >> nnz;
if (inpSS && nnz > 0) { // OK, (optional) nnz has been provided.
i.reserve(nnz);
j.reserve(nnz);
Mij.reserve(nnz);
}
else {
nnz = n*m;
i.reserve(nnz);
j.reserve(nnz);
Mij.reserve(nnz);
}
}
}
else { // Body.
a_uint k = 0, l = 0;
RC zero; makeConstant(zero, 0.);
RC Mkl = zero;
inpSS >> k >> l >> Mkl;
if (!inpSS) {cerr << "Error: bad line (" << fileName << ", line " << l << ")" << endl; return 1;}
i.push_back(k);
j.push_back(l);
Mij.push_back(Mkl);
}
}
while (inp);
// Handle 1-based -> 0-based.
if (!i.empty() && !j.empty()) {
if (*max_element(begin(i), end(i)) == n && *max_element(begin(j), end(j)) == m) {
for (size_t k = 0; k < i.size(); k++) { if (i[k] > 0) i[k] -= 1; }
for (size_t k = 0; k < j.size(); k++) { if (j[k] > 0) j[k] -= 1; }
}
}
// Checking indices.
for (size_t k = 0; k < i.size(); k++) {
if (i[k] >= n) {cerr << "Error: bad index (" << fileName << ", i " << i[k] << ")" << endl; return 1;};
}
for (size_t k = 0; k < j.size(); k++) {
if (j[k] >= m) {cerr << "Error: bad index (" << fileName << ", j " << j[k] << ")" << endl; return 1;};
}
return 0;
};
void aupd(a_int * ido, char const * bMat, a_int nbDim, char const * which, float * resid, float * v,
a_int ldv, a_int * iparam, a_int * ipntr, float * workd, float * workl, a_int lworkl, float * & rwork,
a_int * info) {
assert(rwork == nullptr);
if (symPb) {
ssaupd_c(ido, bMat, nbDim, which, nbEV, tol, resid, nbCV, v, ldv, iparam, ipntr, workd, workl, lworkl, info);
}
else {
snaupd_c(ido, bMat, nbDim, which, nbEV, tol, resid, nbCV, v, ldv, iparam, ipntr, workd, workl, lworkl, info);
}
};
void aupd(a_int * ido, char const * bMat, a_int nbDim, char const * which, double * resid, double * v,
a_int ldv, a_int * iparam, a_int * ipntr, double * workd, double * workl, a_int lworkl, double * & rwork,
a_int * info) {
assert(rwork == nullptr);
if (symPb) {
dsaupd_c(ido, bMat, nbDim, which, nbEV, tol, resid, nbCV, v, ldv, iparam, ipntr, workd, workl, lworkl, info);
}
else {
dnaupd_c(ido, bMat, nbDim, which, nbEV, tol, resid, nbCV, v, ldv, iparam, ipntr, workd, workl, lworkl, info);
}
};
void aupd(a_int * ido, char const * bMat, a_int nbDim, char const * which, complex<float> * resid, complex<float> * v,
a_int ldv, a_int * iparam, a_int * ipntr, complex<float> * workd, complex<float> * workl, a_int lworkl, float * & rwork,
a_int * info) {
if (!rwork) rwork = new float[nbCV];
cnaupd_c(ido, bMat, nbDim, which, nbEV, tol, reinterpret_cast<a_fcomplex*>(resid), nbCV,
reinterpret_cast<a_fcomplex*>(v), ldv, iparam, ipntr, reinterpret_cast<a_fcomplex*>(workd),
reinterpret_cast<a_fcomplex*>(workl), lworkl, rwork, info);
};
void aupd(a_int * ido, char const * bMat, a_int nbDim, char const * which, complex<double> * resid, complex<double> * v,
a_int ldv, a_int * iparam, a_int * ipntr, complex<double> * workd, complex<double> * workl, a_int lworkl, double * & rwork,
a_int * info) {
if (!rwork) rwork = new double[nbCV];
znaupd_c(ido, bMat, nbDim, which, nbEV, tol, reinterpret_cast<a_dcomplex*>(resid), nbCV,
reinterpret_cast<a_dcomplex*>(v), ldv, iparam, ipntr, reinterpret_cast<a_dcomplex*>(workd),
reinterpret_cast<a_dcomplex*>(workl), lworkl, rwork, info);
};
void spectrum(RC * d, RC * z, a_int nbDim, a_int * iparam) {
// Arpack compute the whole spectrum.
a_int nbConv = iparam[4];
val.reserve(nbConv);
for (a_int i = 0; d && i < nbConv; i++) {
complex<double> lambda(d[i]);
val.push_back(lambda);
if (val.size() == (size_t) nbEV) break; // If more converged than requested, likely not accurate (check KO).
}
vec.reserve(nbConv);
for (a_int i = 0; z && i < nbConv; i++) {
EV V = EV(z + i*nbDim, nbDim);
vec.push_back(V.template cast<complex<double>>());
if (vec.size() == (size_t) nbEV) break; // If more converged than requested, likely not accurate (check KO).
}
};
void halfSpectrum(RC * dr, RC * di, RC * z, a_int nbDim, a_int * iparam) {
// Arpack compute only half of the spectrum.
a_int nbConv = iparam[4];
val.reserve(nbConv);
for (a_int i = 0; dr && di && i <= nbConv/2; i++) { // Scan first half of the spectrum.
// Get first half of the spectrum.
complex<double> lambda(dr[i], di[i]);
val.push_back(lambda);
if (val.size() == (size_t) nbEV) break; // If more converged than requested, likely not accurate (check KO).
// Deduce second half of the spectrum.
val.push_back(complex<double>(lambda.real(), -1.*lambda.imag()));
if (val.size() == (size_t) nbEV) break; // If more converged than requested, likely not accurate (check KO).
}
vec.reserve(nbConv);
for (a_int i = 0; z && i <= nbConv/2; i++) { // Scan half spectrum.
// Get first half of the spectrum.
EV Vr = EV(z + (2*i+0)*nbDim, nbDim); // Real part.
EV Vi = EV(z + (2*i+1)*nbDim, nbDim); // Imaginary part.
complex<double> imag(0., 1.);
EigVecZ V = Vr.template cast<complex<double>>() + imag * Vi.template cast<complex<double>>();
vec.push_back(V);
if (vec.size() == (size_t) nbEV) break; // If more converged than requested, likely not accurate (check KO).
// Deduce second half of the spectrum.
V = Vr.template cast<complex<double>>() - imag * Vi.template cast<complex<double>>();
vec.push_back(V);
if (vec.size() == (size_t) nbEV) break; // If more converged than requested, likely not accurate (check KO).
}
};
int eupd(a_int rvec, char const * howmny, a_int const * select, float * z,
a_int ldz, char const * bMat, a_int nbDim, char const * which, float * resid, float * v,
a_int ldv, a_int * iparam, a_int * ipntr, float * workd, float * workl, a_int lworkl, float * rwork,
a_int & info) {
assert(rwork == nullptr);
if (symPb) {
float * d = new float[nbEV]; for (a_int k = 0; k < nbEV; k++) d[k] = 0.;
sseupd_c(rvec, howmny, select, d, z, ldz, sigmaReal,
bMat, nbDim, which, nbEV, tol, resid, nbCV, v, ldv, iparam, ipntr, workd, workl, lworkl, &info);
if (info == -14) cerr << "Error: sseupd - KO: ssaupd did not find any eigenvalues to sufficient accuracy" << endl;
if (info < 0 && info != -14 /*-14: don't break*/) {cerr << "Error: sseupd - KO with info " << info << endl; return 1;}
spectrum(d, z, nbDim, iparam);
if (d) {delete [] d; d = nullptr;}
}
else {
float * dr = new float[nbEV+1]; for (a_int k = 0; k < nbEV+1; k++) dr[k] = 0.;
float * di = new float[nbEV+1]; for (a_int k = 0; k < nbEV+1; k++) di[k] = 0.;
float * workev = new float[3*nbCV];
sneupd_c(rvec, howmny, select, dr, di, z, ldz, sigmaReal, sigmaImag, workev,
bMat, nbDim, which, nbEV, tol, resid, nbCV, v, ldv, iparam, ipntr, workd, workl, lworkl, &info);
if (info == -14) cerr << "Error: sneupd - KO: snaupd did not find any eigenvalues to sufficient accuracy" << endl;
if (info < 0 && info != -14 /*-14: don't break*/) {cerr << "Error: sneupd - KO with info " << info << endl; return 1;}
halfSpectrum(dr, di, z, nbDim, iparam);
if (workev) {delete [] workev; workev = nullptr;}
if (dr) {delete [] dr; dr = nullptr;}
if (di) {delete [] di; di = nullptr;}
}
return 0;
};
int eupd(a_int rvec, char const * howmny, a_int const * select, double * z,
a_int ldz, char const * bMat, a_int nbDim, char const * which, double * resid, double * v,
a_int ldv, a_int * iparam, a_int * ipntr, double * workd, double * workl, a_int lworkl, double * rwork,
a_int & info) {
assert(rwork == nullptr);
if (symPb) {
double * d = new double[nbEV]; for (a_int k = 0; k < nbEV; k++) d[k] = 0.;
dseupd_c(rvec, howmny, select, d, z, ldz, sigmaReal,
bMat, nbDim, which, nbEV, tol, resid, nbCV, v, ldv, iparam, ipntr, workd, workl, lworkl, &info);
if (info == -14) cerr << "Error: dseupd - KO: dsaupd did not find any eigenvalues to sufficient accuracy" << endl;
if (info < 0 && info != -14 /*-14: don't break*/) {cerr << "Error: dseupd - KO with info " << info << endl; return 1;}
spectrum(d, z, nbDim, iparam);
if (d) {delete [] d; d = nullptr;}
}
else {
double * dr = new double[nbEV+1]; for (a_int k = 0; k < nbEV+1; k++) dr[k] = 0.;
double * di = new double[nbEV+1]; for (a_int k = 0; k < nbEV+1; k++) di[k] = 0.;
double * workev = new double[3*nbCV];
dneupd_c(rvec, howmny, select, dr, di, z, ldz, sigmaReal, sigmaImag, workev,
bMat, nbDim, which, nbEV, tol, resid, nbCV, v, ldv, iparam, ipntr, workd, workl, lworkl, &info);
if (info == -14) cerr << "Error: dneupd - KO: dnaupd did not find any eigenvalues to sufficient accuracy" << endl;
if (info < 0 && info != -14 /*-14: don't break*/) {cerr << "Error: dneupd - KO with info " << info << endl; return 1;}
halfSpectrum(dr, di, z, nbDim, iparam);
if (workev) {delete [] workev; workev = nullptr;}
if (dr) {delete [] dr; dr = nullptr;}
if (di) {delete [] di; di = nullptr;}
}
return 0;
};
int eupd(a_int rvec, char const * howmny, a_int const * select, complex<float> * z,
a_int ldz, char const * bMat, a_int nbDim, char const * which, complex<float> * resid, complex<float> * v,
a_int ldv, a_int * iparam, a_int * ipntr, complex<float> * workd, complex<float> * workl, a_int lworkl, float * rwork,
a_int & info) {
complex<float> * d = new complex<float>[nbEV+1]; for (a_int k = 0; k < nbEV+1; k++) d[k] = complex<float>(0., 0.);
complex<float> * workev = new complex<float>[2*nbCV];
complex<float> sigma = complex<float>((float) sigmaReal, (float) sigmaImag);
cneupd_c(rvec, howmny, select, reinterpret_cast<a_fcomplex*>(d), reinterpret_cast<a_fcomplex*>(z), ldz,
reinterpret_cast<a_fcomplex &>(sigma), reinterpret_cast<a_fcomplex*>(workev),
bMat, nbDim, which, nbEV, tol, reinterpret_cast<a_fcomplex*>(resid), nbCV,
reinterpret_cast<a_fcomplex*>(v), ldv, iparam, ipntr,
reinterpret_cast<a_fcomplex*>(workd), reinterpret_cast<a_fcomplex*>(workl), lworkl, rwork, &info);
if (info == -14) cerr << "Error: cneupd - KO: cnaupd did not find any eigenvalues to sufficient accuracy" << endl;
if (info < 0 && info != -14 /*-14: don't break*/) {cerr << "Error: cneupd - KO with info " << info << endl; return 1;}
spectrum(d, z, nbDim, iparam);
if (workev) {delete [] workev; workev = nullptr;}
if (d) {delete [] d; d = nullptr;}
return 0;
};
int eupd(a_int rvec, char const * howmny, a_int const * select, complex<double> * z,
a_int ldz, char const * bMat, a_int nbDim, char const * which, complex<double> * resid, complex<double> * v,
a_int ldv, a_int * iparam, a_int * ipntr, complex<double> * workd, complex<double> * workl, a_int lworkl, double * rwork,
a_int & info) {
complex<double> * d = new complex<double>[nbEV+1]; for (a_int k = 0; k < nbEV+1; k++) d[k] = complex<double>(0., 0.);
complex<double> * workev = new complex<double>[2*nbCV];
complex<double> sigma = complex<double>(sigmaReal, sigmaImag);
zneupd_c(rvec, howmny, select, reinterpret_cast<a_dcomplex*>(d), reinterpret_cast<a_dcomplex*>(z), ldz,
reinterpret_cast<a_dcomplex &>(sigma), reinterpret_cast<a_dcomplex*>(workev),
bMat, nbDim, which, nbEV, tol, reinterpret_cast<a_dcomplex*>(resid), nbCV,
reinterpret_cast<a_dcomplex*>(v), ldv, iparam, ipntr,
reinterpret_cast<a_dcomplex*>(workd), reinterpret_cast<a_dcomplex*>(workl), lworkl, rwork, &info);
if (info == -14) cerr << "Error: zneupd - KO: znaupd did not find any eigenvalues to sufficient accuracy" << endl;
if (info < 0 && info != -14 /*-14: don't break*/) {cerr << "Error: zneupd - KO with info " << info << endl; return 1;}
spectrum(d, z, nbDim, iparam);
if (workev) {delete [] workev; workev = nullptr;}
if (d) {delete [] d; d = nullptr;}
return 0;
};
int setMode(int const mode, EM const & A, EM const * B, SLV & solver) {
int rc = 1;
if (mode == 1) {
rc = 0;
}
else if (mode == 2 || mode == 3) {
if (!stdPb && !B) {cerr << "Error: generalized problem without B" << endl; return 1;}
if (mode == 2) { // Invert mode.
solver.compute(*B);
}
else { // Shift invert mode.
RC sigma; makeSigma(sigma);
auto S = A - sigma*(*B);
solver.compute(S);
}
rc = 0;
}
else {cerr << "Error: arpack mode must be 1, 2 or 3 - KO" << endl; rc = 1;}
return rc;
};
template <typename T>
int saveSolve(string const & fileName,
a_int const & nbDim, T * rv) {
ofstream ofs(fileName.c_str(), ofstream::trunc);
if (ofs.is_open()) {
ofs << nbDim << endl;
for (a_int n = 0; rv && n < nbDim; n++) ofs << rv[n] << endl;
ofs.close(); // Make sure the file is written.
}
return 0;
};
template <typename T>
int restartSolve(string const & fileName,
a_int const & nbDim, T * rv,
bool allowZero = true) {
ifstream ifs(fileName.c_str());
if (ifs.is_open()) {
a_int nDim = 0;
ifs >> nDim;
if (nDim != nbDim) {cerr << "Error: bad dim - restart KO" << endl; return 1;}
for (a_int n = 0; rv && n < nbDim; n++) {
RC val; makeConstant(val, 0.);
ifs >> val;
if (abs(val) < 1.e-6 && !allowZero) {
// Do NOT let residual be zero: this stops arpack to iterate (info = -9).
auto eps = numeric_limits<FD>::epsilon();
RC epsilon; makeConstant(epsilon, eps);
val = epsilon;
}
rv[n] = val;
}
if (verbose >= 1) {
cout << endl << "arpackSolver:" << endl;
cout << endl << fileName << ": restart OK" << endl;
if (verbose >= 2) {
for (a_int n = 0; rv && n < nbDim; n++) cout << rv[n] << endl;
}
}
}
return 0;
};
int initPointerSize(a_int & iparamSz, a_int & ipntrSz, string const & aeupd) {
iparamSz = 11; ipntrSz = 14;
if (aeupd == "aupd") {
if (is_same<RC, double>::value && symPb) ipntrSz = 11;
if (is_same<RC, float>::value && symPb) ipntrSz = 11;
return 0;
}
if (aeupd == "eupd") {
if (is_same<RC, double>::value && symPb) {iparamSz = 7; ipntrSz = 11;}
if (is_same<RC, float>::value && symPb) {iparamSz = 7; ipntrSz = 11;}
return 0;
}
return 1;
};
int solve(EM const & A, EM const * B, SLV & solver) {
if (!stdPb && !B) {cerr << "Error: generalized problem without B" << endl; return 1;}
// Arpack set up.
// Note: some in/out parameters passed to d[sn][ae]upd are set to 0. before use.
// d[sn][ae]upd uses dgetv0 to generate a random starting vector (when info is initialized to 0).
// dgetv0 rely on resid/v: resid/v should be initialized to 0.0 to avoid "bad" starting random vectors.
char const * which = mag.c_str();
a_int ido = 0; // First call to arpack.
char const * iMat = "I";
char const * gMat = "G";
char const * bMat = (mode == 1) ? iMat : gMat;
a_int nbDim = A.rows();
auto eps = numeric_limits<FD>::epsilon();
RC epsilon; makeConstant(epsilon, eps);
if (!resid) {
resid = new RC[nbDim];
// Do NOT let residual be zero: this stops arpack to iterate (info = -9).
for (a_int n = 0; n < nbDim; n++) resid[n] = epsilon;
};
a_int ldv = nbDim;
RC cst; makeConstant(cst, 10.);
RC v0 = cst * epsilon; // Start with something close to zero but *not* exactly zero.
if (!v) {
v = new RC[ldv*nbCV];
for (a_int n = 0; n < ldv*nbCV; n++) v[n] = v0;
};
a_int iparamSz = 0, ipntrSz = 0;
int rc = initPointerSize(iparamSz, ipntrSz, "aupd");
if (rc != 0) {cerr << "Error: bad iparam/ipntr initialization for aupd" << endl; return rc;}
vector<a_int> iparamAupd(iparamSz, 0);
iparamAupd[0] = 1; // Use exact shifts (=> we'll never have ido == 3).
iparamAupd[2] = maxIt; // Maximum number of iterations.
iparamAupd[3] = 1; // Block size.
iparamAupd[4] = 0; // Number of ev found by arpack.
iparamAupd[6] = mode;
RC zero; makeConstant(zero, 0.);
vector<a_int> ipntrAupd(ipntrSz, 0);
RC * workd = new RC[3*nbDim]; for (a_int n = 0; n < 3*nbDim; n++) workd[n] = zero; // Avoid "bad" X/Y vector.
a_int lworkl = symPb ? nbCV*nbCV + 8*nbCV : 3*nbCV*nbCV + 6*nbCV;
RC * workl = new RC[lworkl];
a_int info = 0; // Use random initial residual vector.
// Handling restart.
if (restartFromFile) {
info = 1; // Restart.
rc = restartSolve("arpackSolver.resid.out", nbDim, resid, false);
if (rc != 0) {cerr << "Error: bad restart (resid)" << endl; return rc;}
rc = restartSolve("arpackSolver.v.out", ldv*nbCV, v);
if (rc != 0) {cerr << "Error: bad restart (v)" << endl; return rc;}
}
// Initialize solver.
auto start = chrono::high_resolution_clock::now();
rc = setMode(mode, A, B, solver);
if (rc != 0) {cerr << "Error: bad arpack mode" << endl; return rc;}
auto stop = chrono::high_resolution_clock::now();
imsTime = chrono::duration_cast<chrono::milliseconds>(stop - start).count()/1000.;
// Arpack solve.
FD * rwork = nullptr;
do {
// Call arpack.
aupd(&ido, bMat, nbDim, which, resid, v, ldv, iparamAupd.data(), ipntrAupd.data(), workd, workl, lworkl, rwork, &info);
if (info == 1) cerr << "Error: [dz][sn]aupd - KO: maximum number of iterations taken. Increase --maxIt..." << endl;
if (info == 3) cerr << "Error: [dz][sn]aupd - KO: no shifts could be applied. Increase --nbCV..." << endl;
if (info == -9) cerr << "Error: [dz][sn]aupd - KO: starting vector is zero. Retry: play with shift..." << endl;
if (info < 0) {cerr << "Error: [dz][sn]aupd - KO with info " << info << ", nbIt " << iparamAupd[2] << endl; return 1;}
// Reverse Communication Interface: perform actions according to arpack.
start = chrono::high_resolution_clock::now();
a_int xIdx = ipntrAupd[0] - 1; // 0-based (Fortran is 1-based).
a_int yIdx = ipntrAupd[1] - 1; // 0-based (Fortran is 1-based).
EV X(workd + xIdx, nbDim); // Arpack provides X.
EV Y(workd + yIdx, nbDim); // Arpack provides Y.
if (ido == -1) {
if (iparamAupd[6] == 1) {
Y = A * X;
}
else if (iparamAupd[6] == 2) {
Y = A * X;
auto YY = Y; // Use copy of Y (not Y) for solve (avoid potential memory overwrite as Y is both in/out).
Y = solver.solve(YY); // Y = B^-1 * A * X.
}
else if (iparamAupd[6] == 3) {
auto Z = (*B) * X; // Z = B * X.
Y = solver.solve(Z); // Y = (A - sigma * B)^-1 * B * X.
}
}
else if (ido == 1) {
if (iparamAupd[6] == 1) {
Y = A * X;
}
else if (iparamAupd[6] == 2) {
Y = A * X;
if (symPb) X = Y; // Remark 5 in dsaupd documentation.
auto YY = Y; // Use copy of Y (not Y) for solve (avoid potential memory overwrite as Y is both in/out).
Y = solver.solve(YY); // Y = B^-1 * A * X.
}
else if (iparamAupd[6] == 3) {
a_int zIdx = ipntrAupd[2] - 1; // 0-based (Fortran is 1-based).
EV Z(workd + zIdx, nbDim); // Arpack provides Z.
Y = solver.solve(Z); // Y = (A - sigma * B)^-1 * B * X.
}
}
else if (ido == 2) {
if (iparamAupd[6] == 1) Y = X; // Y = I * X.
else if (iparamAupd[6] == 2) Y = (*B) * X; // Y = B * X.
else if (iparamAupd[6] == 3) Y = (*B) * X; // Y = B * X.
}
else if (ido != 99) {cerr << "Error: unexpected ido " << ido << " - KO" << endl; return 1;}
stop = chrono::high_resolution_clock::now();
rciTime += chrono::duration_cast<chrono::milliseconds>(stop - start).count()/1000.;
} while (ido != 99);
// Get arpack results (computed eigen values and vectors).
nbIt = iparamAupd[2]; // Actual number of iterations.
a_int rvec = 1;
char const * howmnyA = "A"; // Ritz vectors.
char const * howmnyP = "P"; // Schur vectors.
char const * howmny = schur ? howmnyP : howmnyA;
a_int * select = new a_int[nbCV]; for (a_int n = 0; n < nbCV; n++) select[n] = 1;
a_int const nbZ = nbDim*(nbEV+1); // Caution: nbEV+1 for dneupd.
RC * z = new RC[nbZ]; for (a_int n = 0; n < nbZ; n++) z[n] = zero;
a_int ldz = nbDim;
rc = initPointerSize(iparamSz, ipntrSz, "eupd");
if (rc != 0) {cerr << "Error: bad iparam/ipntr initialization for eupd" << endl; return rc;}
vector<a_int> iparamEupd(iparamSz, 0);
for (a_int p = 0; p < iparamSz; p++) iparamEupd[p] = iparamAupd[p]; // Initialize eupd parameters with aupd ones.
vector<a_int> ipntrEupd(ipntrSz, 0);
for (a_int p = 0; p < ipntrSz; p++) ipntrEupd[p] = ipntrAupd[p]; // Initialize eupd parameters with aupd ones.
rc = eupd(rvec, howmny, select, z, ldz, bMat, nbDim, which, resid, v, ldv, iparamEupd.data(), ipntrEupd.data(), workd, workl, lworkl, rwork, info);
if (rc != 0) {cerr << "Error: bad arpack eupd" << endl; return rc;}
// Save solve (dump results to file) to allow later restart.
if (dumpToFile) {
saveSolve("arpackSolver.resid.out", nbDim, resid);
saveSolve("arpackSolver.v.out", ldv*nbCV, v);
}
// Clean.
if (rwork) {delete [] rwork; rwork = nullptr;}
if (z) {delete [] z; z = nullptr;}
if (select) {delete [] select; select = nullptr;}
if (workl) {delete [] workl; workl = nullptr;}
if (workd) {delete [] workd; workd = nullptr;}
return 0;
};
void makeSigma( float & sigma) {sigma = (float) sigmaReal;};
void makeSigma( double & sigma) {sigma = sigmaReal;};
void makeSigma(complex< float> & sigma) {sigma = complex< float>((float) sigmaReal, (float) sigmaImag);};
void makeSigma(complex<double> & sigma) {sigma = complex<double>(sigmaReal, sigmaImag);};
virtual int initSolver(SLV & solver) = 0;
virtual void dumpAllParameters() = 0;
// Public members.
public:
// Arpack parameters.
bool symPb; // Symmetric problem.
a_int nbEV;
a_int nbCV;
double tol;
double sigmaReal, sigmaImag; // Eigen value translation: look for lambda+sigma instead of lambda.
bool dumpToFile; // Dump resid and v to arpackSolver.*.out files after solve.
bool restartFromFile; // Restart solve with resid and v values provided in arpackSolver.*.out files.
string mag; // Magnitude <=> "which" arpack parameter.
int maxIt;
bool schur;
int verbose;
// Arpack outputs.
bool stdPb; // Standard or generalized (= not standard).
StdVecZ val; // Eigen values.
StdVecEVZ vec; // Eigen vectors.
int mode;
int nbIt;
double imsTime; // Init mode solver time.
double rciTime; // Reverse communication interface time.
// Protected members.
protected:
a_int nbDim;
// Private members.
private:
RC * resid; // Saved: enable restart from previous solve.
RC * v; // Saved: enable restart from previous solve.
};
// Definition of arpackItrSolver class: specialization of arpackSolver using iterative solvers.
// Note: Eigen provides iterative solvers only for sparse matrices.
// RC: Real or Complex.
// FD: Float or Double.
// EM: Eigen Matrix (sparse only, not dense).
// SLV: Solver.
template<typename RC, typename FD, typename EM, typename SLV>
class arpackItrSolver: public arpackSolver<RC, FD, EM, SLV> {
// Public methods.
public:
arpackItrSolver(): arpackSolver<RC, FD, EM, SLV>() {
slvTol = 1.e-6;
slvMaxIt = 100;
slvILUDropTol = 1.;
slvILUFillFactor = 2;
};
void dumpAllParameters() {
this->dumpParameters();
if (this->verbose >= 1) {
cout << endl << "arpackItrSolver:" << endl;
cout << endl << "slvTol: " << slvTol << endl;
cout << endl << "slvMaxIt: " << slvMaxIt << endl;
cout << endl << "slvILUDropTol: " << slvILUDropTol << endl;
cout << endl << "slvILUFillFactor: " << slvILUFillFactor << endl;
}
};
virtual int initSolver(Eigen::BiCGSTAB<EM> & solver) {
// Solve with arpack using sparse matrices and iterative solvers.
solver.setTolerance(slvTol);
solver.setMaxIterations(slvMaxIt);
return 0;
};
virtual int initSolver(Eigen::ConjugateGradient<EM> & solver) {
// Solve with arpack using sparse matrices and iterative solvers.
solver.setTolerance(slvTol);
solver.setMaxIterations(slvMaxIt);
return 0;
};
virtual int initSolver(Eigen::BiCGSTAB<EM, Eigen::IncompleteLUT<RC>> & solver) {
// Solve with arpack using sparse matrices and iterative solvers.
solver.setTolerance(slvTol);
solver.setMaxIterations(slvMaxIt);
solver.preconditioner().setDroptol(slvILUDropTol);
solver.preconditioner().setFillfactor(slvILUFillFactor);
return 0;
};
virtual int initSolver(Eigen::ConjugateGradient<EM, Eigen::Lower|Eigen::Upper, Eigen::IncompleteLUT<RC>> & solver) {
// Solve with arpack using sparse matrices and iterative solvers.
solver.setTolerance(slvTol);
solver.setMaxIterations(slvMaxIt);
solver.preconditioner().setDroptol(slvILUDropTol);
solver.preconditioner().setFillfactor(slvILUFillFactor);
return 0;
};
// Public members.
public:
// Iterative solvers parameters.
double slvTol; // Tolerance of the iterative mode solver.
int slvMaxIt; // Maximum number of iterations of the iterative mode solver.
double slvILUDropTol; // Drop tolerance of the ILU preconditioner (if any) of the iterative mode solver.
int slvILUFillFactor; // Fill factor of the ILU preconditioner (if any) of the iterative mode solver.
};
// Definition of arpackDrtSolver class: specialization of arpackSolver using direct solvers.
// Note: Eigen provides direct solvers for both sparse and dense matrices.
// RC: Real or Complex.
// FD: Float or Double.
// EM: Eigen Matrix (sparse or dense).
// SLV: Solver.
template<typename RC, typename FD, typename EM, typename SLV>
class arpackDrtSolver: public arpackSolver<RC, FD, EM, SLV> {
// Public methods.
public:
arpackDrtSolver(): arpackSolver<RC, FD, EM, SLV>() {
slvPvtThd = 1.e-6;
slvOffset = 0.;
slvScale = 1.;
};
void dumpAllParameters() {
this->dumpParameters();
if (this->verbose >= 1) {
cout << endl << "arpackDrtSolver:" << endl;
cout << endl << "slvPvtThd: " << slvPvtThd << endl;
cout << endl << "slvOffset: " << slvOffset << endl;
cout << endl << "slvScale: " << slvScale << endl;
}
};
virtual int initSolver(Eigen::SparseLU<EM, Eigen::COLAMDOrdering<int>> & solver) {
// Solve with arpack using sparse matrices and direct solvers.
solver.setPivotThreshold(slvPvtThd);
return 0;
};
virtual int initSolver(Eigen::SparseQR<EM, Eigen::COLAMDOrdering<int>> & solver) {
// Solve with arpack using sparse matrices and direct solvers.
solver.setPivotThreshold(slvPvtThd);
return 0;
};
virtual int initSolver(Eigen::SimplicialLLT<EM, Eigen::Lower, Eigen::COLAMDOrdering<int>> & solver) {
// Solve with arpack using sparse matrices and direct solvers.
solver.setShift(slvOffset, slvScale);
return 0;
};
virtual int initSolver(Eigen::SimplicialLDLT<EM, Eigen::Lower, Eigen::COLAMDOrdering<int>> & solver) {
// Solve with arpack using sparse matrices and direct solvers.
solver.setShift(slvOffset, slvScale);
return 0;
};
virtual int initSolver(Eigen::LLT<EM> & solver) {
// Solve with arpack using dense matrices and direct solvers.
if (this->mode == 1) return 0;
solver = Eigen::LLT<EM>(this->nbDim);
return 0;
};
virtual int initSolver(Eigen::LDLT<EM> & solver) {
// Solve with arpack using dense matrices and direct solvers.
if (this->mode == 1) return 0;
solver = Eigen::LDLT<EM>(this->nbDim);
return 0;
};
virtual int initSolver(Eigen::FullPivLU<EM> & solver) {
// Solve with arpack using dense matrices and direct solvers.
if (this->mode == 1) return 0;
solver = Eigen::FullPivLU<EM>(this->nbDim, this->nbDim);
solver.setThreshold(slvPvtThd);
return 0;
};
virtual int initSolver(Eigen::FullPivHouseholderQR<EM> & solver) {
// Solve with arpack using dense matrices and direct solvers.
if (this->mode == 1) return 0;
solver = Eigen::FullPivHouseholderQR<EM>(this->nbDim, this->nbDim);
solver.setThreshold(slvPvtThd);
return 0;
};
virtual int initSolver(Eigen::PartialPivLU<EM> & solver) {
// Solve with arpack using dense matrices and direct solvers.
if (this->mode == 1) return 0;
solver = Eigen::PartialPivLU<EM>(this->nbDim);
return 0;
};
virtual int initSolver(Eigen::HouseholderQR<EM> & solver) {
// Solve with arpack using dense matrices and direct solvers.
if (this->mode == 1) return 0;
solver = Eigen::HouseholderQR<EM>(this->nbDim, this->nbDim);
return 0;
};
// Public members.
public:
// Direct solvers parameters.
double slvPvtThd; // Pivoting tolerance of the direct mode solver.
double slvOffset; // Cholesky offset (LLT, LDLT) of the direct mode solver.
double slvScale; // Cholesky scale (LLT, LDLT) of the direct mode solver.
};
#endif
// Local Variables:
// mode: c++
// c-file-style:"stroustrup"
// show-trailing-whitespace: t
// End:
/* vim: set sw=2 ts=2 et smartindent :*/