1058 lines
34 KiB
C++
1058 lines
34 KiB
C++
#include <iostream>
|
|
#include <exception>
|
|
#include <sstream>
|
|
#include <chrono>
|
|
#include <vector>
|
|
#include <tuple>
|
|
|
|
#include "arpackSolver.hpp"
|
|
#include "debug_c.hpp"
|
|
#include "stat_c.hpp"
|
|
|
|
using namespace std;
|
|
|
|
class options {
|
|
public:
|
|
options() {
|
|
fileA = "";
|
|
fileB = "";
|
|
dense = false;
|
|
denseRR = true;
|
|
nbEV = 1;
|
|
nbCV = 2 * nbEV + 1;
|
|
stdPb = true; // Standard or generalized (= not standard).
|
|
symPb = true;
|
|
cpxPb = false;
|
|
simplePrec = false; // Double precision.
|
|
mag = string("LM"); // Large magnitude.
|
|
shiftReal = false;
|
|
shiftImag = false;
|
|
sigmaReal = 0.;
|
|
sigmaImag = 0.; // Eigen value translation: look for lambda+sigma instead
|
|
// of lambda.
|
|
invert =
|
|
false; // Eigen value invertion: look for 1./lambda instead of lambda.
|
|
tol = 1.e-06;
|
|
maxResNorm = 1.e-3;
|
|
maxIt = 100;
|
|
schur = false; // Compute Ritz vectors.
|
|
slv = "BiCG";
|
|
slvItrTol = 1.e-6;
|
|
slvItrMaxIt = 100;
|
|
slvItrPC = "Diag";
|
|
slvDrtPivot = 1.e-6;
|
|
slvDrtOffset = 0.;
|
|
slvDrtScale = 1.;
|
|
check = true;
|
|
verbose = 0;
|
|
debug = 0;
|
|
restart = false;
|
|
};
|
|
|
|
int readCmdLine(int argc, char** argv) {
|
|
// Convert command line to stream.
|
|
|
|
stringstream ssIP; // Independent parameters.
|
|
for (int a = 1; argv && a < argc; a++) {
|
|
ssIP << argv[a] << " ";
|
|
}
|
|
|
|
// Check for command line independent parameters.
|
|
|
|
string clo; // Command line option.
|
|
while (ssIP >> clo) {
|
|
if (clo == "--help" || clo == "-h") return usage();
|
|
if (clo.find("--") == std::string::npos) {
|
|
cerr << "Error: bad " << clo << " - bad argument" << endl;
|
|
return usage();
|
|
}
|
|
|
|
if (clo == "--A") {
|
|
ssIP >> clo;
|
|
if (!ssIP) {
|
|
cerr << "Error: bad " << clo << " - need argument" << endl;
|
|
return usage();
|
|
}
|
|
fileA = clo;
|
|
}
|
|
if (clo == "--dense") {
|
|
dense = true;
|
|
ssIP >> clo;
|
|
if (!ssIP) {
|
|
cerr << "Error: bad " << clo << " - need argument" << endl;
|
|
return usage();
|
|
}
|
|
string rr = clo;
|
|
if (rr != "true" && rr != "false") {
|
|
cerr << "Error: bad " << clo << " - bad argument" << endl;
|
|
return usage();
|
|
}
|
|
denseRR = (rr == "true") ? true : false;
|
|
}
|
|
if (clo == "--nbEV") {
|
|
ssIP >> clo;
|
|
if (!ssIP) {
|
|
cerr << "Error: bad " << clo << " - need argument" << endl;
|
|
return usage();
|
|
}
|
|
stringstream nEV(clo);
|
|
nEV >> nbEV;
|
|
if (!nEV) {
|
|
cerr << "Error: bad " << clo << " - bad argument" << endl;
|
|
return usage();
|
|
}
|
|
nbCV = 2 * nbEV + 1;
|
|
}
|
|
if (clo == "--nonSymPb") symPb = false;
|
|
if (clo == "--cpxPb") {
|
|
symPb = false;
|
|
cpxPb = true;
|
|
}
|
|
if (clo == "--simplePrec") simplePrec = true;
|
|
if (clo == "--mag") {
|
|
ssIP >> clo;
|
|
if (!ssIP) {
|
|
cerr << "Error: bad " << clo << " - need argument" << endl;
|
|
return usage();
|
|
}
|
|
mag = clo; // small mag (likely poor perf) <=> large mag + invert
|
|
// (likely good perf).
|
|
bool ok = (mag == "LM" || mag == "SM" || mag == "LR" || mag == "SR" ||
|
|
mag == "LA" || mag == "SA" || mag == "LI" || mag == "SI")
|
|
? true
|
|
: false;
|
|
if (!ok) {
|
|
cerr << "Error: bad " << clo << " - bad argument" << endl;
|
|
return usage();
|
|
}
|
|
}
|
|
if (clo == "--shiftReal") {
|
|
shiftReal = true;
|
|
ssIP >> clo;
|
|
if (!ssIP) {
|
|
cerr << "Error: bad " << clo << " - need argument" << endl;
|
|
return usage();
|
|
}
|
|
stringstream s(clo);
|
|
s >> sigmaReal;
|
|
if (!s) {
|
|
cerr << "Error: bad " << clo << " - bad argument" << endl;
|
|
return usage();
|
|
}
|
|
}
|
|
if (clo == "--shiftImag") {
|
|
shiftImag = true;
|
|
ssIP >> clo;
|
|
if (!ssIP) {
|
|
cerr << "Error: bad " << clo << " - need argument" << endl;
|
|
return usage();
|
|
}
|
|
stringstream s(clo);
|
|
s >> sigmaImag;
|
|
if (!s) {
|
|
cerr << "Error: bad " << clo << " - bad argument" << endl;
|
|
return usage();
|
|
}
|
|
}
|
|
if (clo == "--invert") invert = true;
|
|
if (clo == "--tol") {
|
|
ssIP >> clo;
|
|
if (!ssIP) {
|
|
cerr << "Error: bad " << clo << " - need argument" << endl;
|
|
return usage();
|
|
}
|
|
stringstream t(clo);
|
|
t >> tol;
|
|
if (!t) {
|
|
cerr << "Error: bad " << clo << " - bad argument" << endl;
|
|
return usage();
|
|
}
|
|
}
|
|
if (clo == "--maxResNorm") {
|
|
ssIP >> clo;
|
|
if (!ssIP) {
|
|
cerr << "Error: bad " << clo << " - need argument" << endl;
|
|
return usage();
|
|
}
|
|
stringstream mrn(clo);
|
|
mrn >> maxResNorm;
|
|
if (!mrn) {
|
|
cerr << "Error: bad " << clo << " - bad argument" << endl;
|
|
return usage();
|
|
}
|
|
}
|
|
if (clo == "--maxIt") {
|
|
ssIP >> clo;
|
|
if (!ssIP) {
|
|
cerr << "Error: bad " << clo << " - need argument" << endl;
|
|
return usage();
|
|
}
|
|
stringstream mi(clo);
|
|
mi >> maxIt;
|
|
if (!mi) {
|
|
cerr << "Error: bad " << clo << " - bad argument" << endl;
|
|
return usage();
|
|
}
|
|
}
|
|
if (clo == "--schur") {
|
|
schur = true;
|
|
}
|
|
if (clo == "--slv") {
|
|
ssIP >> clo;
|
|
if (!ssIP) {
|
|
cerr << "Error: bad " << clo << " - need argument" << endl;
|
|
return usage();
|
|
}
|
|
slv = clo;
|
|
}
|
|
if (clo == "--slvItrTol") {
|
|
ssIP >> clo;
|
|
if (!ssIP) {
|
|
cerr << "Error: bad " << clo << " - need argument" << endl;
|
|
return usage();
|
|
}
|
|
stringstream t(clo);
|
|
t >> slvItrTol;
|
|
if (!t) {
|
|
cerr << "Error: bad " << clo << " - bad argument" << endl;
|
|
return usage();
|
|
}
|
|
}
|
|
if (clo == "--slvItrMaxIt") {
|
|
ssIP >> clo;
|
|
if (!ssIP) {
|
|
cerr << "Error: bad " << clo << " - need argument" << endl;
|
|
return usage();
|
|
}
|
|
stringstream mi(clo);
|
|
int maxIt = 0;
|
|
mi >> slvItrMaxIt;
|
|
if (!mi) {
|
|
cerr << "Error: bad " << clo << " - bad argument" << endl;
|
|
return usage();
|
|
}
|
|
}
|
|
if (clo == "--slvItrPC") {
|
|
ssIP >> clo;
|
|
if (!ssIP) {
|
|
cerr << "Error: bad " << clo << " - need argument" << endl;
|
|
return usage();
|
|
}
|
|
stringstream pc(clo);
|
|
pc >> slvItrPC;
|
|
if (!pc) {
|
|
cerr << "Error: bad " << clo << " - bad argument" << endl;
|
|
return usage();
|
|
}
|
|
}
|
|
if (clo == "--slvDrtPivot") {
|
|
ssIP >> clo;
|
|
if (!ssIP) {
|
|
cerr << "Error: bad " << clo << " - need argument" << endl;
|
|
return usage();
|
|
}
|
|
stringstream pv(clo);
|
|
pv >> slvDrtPivot;
|
|
if (!pv) {
|
|
cerr << "Error: bad " << clo << " - bad argument" << endl;
|
|
return usage();
|
|
}
|
|
}
|
|
if (clo == "--slvDrtOffset") {
|
|
ssIP >> clo;
|
|
if (!ssIP) {
|
|
cerr << "Error: bad " << clo << " - need argument" << endl;
|
|
return usage();
|
|
}
|
|
stringstream of(clo);
|
|
of >> slvDrtOffset;
|
|
if (!of) {
|
|
cerr << "Error: bad " << clo << " - bad argument" << endl;
|
|
return usage();
|
|
}
|
|
}
|
|
if (clo == "--slvDrtScale") {
|
|
ssIP >> clo;
|
|
if (!ssIP) {
|
|
cerr << "Error: bad " << clo << " - need argument" << endl;
|
|
return usage();
|
|
}
|
|
stringstream sc(clo);
|
|
sc >> slvDrtScale;
|
|
if (!sc) {
|
|
cerr << "Error: bad " << clo << " - bad argument" << endl;
|
|
return usage();
|
|
}
|
|
}
|
|
if (clo == "--noCheck") check = false;
|
|
if (clo == "--verbose") {
|
|
ssIP >> clo;
|
|
if (!ssIP) {
|
|
cerr << "Error: bad " << clo << " - need argument" << endl;
|
|
return usage();
|
|
}
|
|
stringstream vb(clo);
|
|
vb >> verbose;
|
|
if (!vb) {
|
|
cerr << "Error: bad " << clo << " - bad argument" << endl;
|
|
return usage();
|
|
}
|
|
}
|
|
if (clo == "--debug") {
|
|
ssIP >> clo;
|
|
if (!ssIP) {
|
|
cerr << "Error: bad " << clo << " - need argument" << endl;
|
|
return usage();
|
|
}
|
|
stringstream dbg(clo);
|
|
dbg >> debug;
|
|
if (!dbg) {
|
|
cerr << "Error: bad " << clo << " - bad argument" << endl;
|
|
return usage();
|
|
}
|
|
if (debug > 3) debug = 3;
|
|
debug_c(6, -6, debug, debug, debug, debug, debug, debug, debug, debug,
|
|
debug, debug, debug, debug, debug, debug, debug, debug, debug,
|
|
debug, debug, debug, debug, debug);
|
|
}
|
|
if (clo == "--restart") restart = true;
|
|
|
|
// Skip dependent parameters.
|
|
if (clo == "--nbCV") { ssIP >> clo; continue; }
|
|
if (clo == "--B") { ssIP >> clo; continue; }
|
|
}
|
|
|
|
// Convert command line to stream.
|
|
|
|
stringstream ssDP; // Dependent parameters.
|
|
for (int a = 1; argv && a < argc; a++) {
|
|
ssDP << argv[a] << " ";
|
|
}
|
|
|
|
// Check for command line dependent parameters.
|
|
|
|
while (ssDP >> clo) {
|
|
if (clo == "--nbCV") {
|
|
ssDP >> clo;
|
|
if (!ssDP) {
|
|
cerr << "Error: bad " << clo << " - need argument" << endl;
|
|
return usage();
|
|
}
|
|
stringstream nCV(clo);
|
|
nCV >> nbCV;
|
|
if (!nCV) {
|
|
cerr << "Error: bad " << clo << " - bad argument" << endl;
|
|
return usage();
|
|
}
|
|
}
|
|
if (clo == "--B") {
|
|
ssDP >> clo;
|
|
if (!ssDP) {
|
|
cerr << "Error: bad " << clo << " - need argument" << endl;
|
|
return usage();
|
|
}
|
|
fileB = clo;
|
|
stdPb = false; // Generalized problem.
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
};
|
|
|
|
int usage() {
|
|
cout << "Usage: running arpack with matrix market files to check for eigen "
|
|
"values/vectors."
|
|
<< endl;
|
|
cout << endl;
|
|
cout << " --A F: file name of matrix A such that A X = lambda "
|
|
"X. (standard)"
|
|
<< endl;
|
|
cout << " the file F must be compliant with the matrix "
|
|
"market format."
|
|
<< endl;
|
|
cout << " default: A.mtx" << endl;
|
|
cout << " --B F: file name of matrix B such that A X = lambda "
|
|
"B X. (generalized)"
|
|
<< endl;
|
|
cout << " the file F must be compliant with the matrix "
|
|
"market format."
|
|
<< endl;
|
|
cout << " default: N.A. for standard problem, or, B.mtx "
|
|
"for generalized problem"
|
|
<< endl;
|
|
cout << " --dense RR: consider A and B as dense matrices." << endl;
|
|
cout << " if RR = true, use more-stable-but-slow "
|
|
"versions of LU / QR (rank revealing)."
|
|
<< endl;
|
|
cout << " if RR = false, use less-stable-but-fast "
|
|
"versions of LU / QR (depends on condition number)."
|
|
<< endl;
|
|
cout << " Notes:" << endl;
|
|
cout << " - only direct solvers are available when "
|
|
"using dense matrices."
|
|
<< endl;
|
|
cout
|
|
<< " - RR does not impact the use of LLT and LDLT."
|
|
<< endl;
|
|
cout << " - thresholds only make sense for "
|
|
"rank-revealing decompositions."
|
|
<< endl;
|
|
cout << " default: consider A and B as sparse matrices"
|
|
<< endl;
|
|
cout << " --nbEV: number of eigen values/vectors to compute."
|
|
<< endl;
|
|
cout << " default: 1" << endl;
|
|
cout << " --nbCV: number of columns of the matrix V." << endl;
|
|
cout << " default: 2*nbEV+1" << endl;
|
|
cout << " --nonSymPb: non symmetric problem (<=> use dn[ae]upd)."
|
|
<< endl;
|
|
cout << " default: symmetric problem (<=> use ds[ae]upd)"
|
|
<< endl;
|
|
cout << " --cpxPb: complex (non symmetric) problem (<=> use "
|
|
"zn[ae]upd)."
|
|
<< endl;
|
|
cout << " default: false (<=> use d*[ae]upd)" << endl;
|
|
cout << " --simplePrec: use simple precision (less accurate, but, "
|
|
"half memory footprint)."
|
|
<< endl;
|
|
cout << " default: false (<=> use double precision: use "
|
|
"[dz]*upd)"
|
|
<< endl;
|
|
cout << " --mag M: set magnitude of eigen values to look for "
|
|
"(LM, SM, LR, SR, LA, SA, LI, SI)."
|
|
<< endl;
|
|
cout << " default: large magnitude (LM)" << endl;
|
|
cout << " --shiftReal S: real shift where sigma = S (look for lambda+S "
|
|
"instead of lambda)."
|
|
<< endl;
|
|
cout << " default: no shift, S = 0." << endl;
|
|
cout << " --shiftImag S: imaginary shift where sigma = S (look for "
|
|
"lambda+S instead of lambda)."
|
|
<< endl;
|
|
cout << " default: no shift, S = 0." << endl;
|
|
cout << " --invert: invert mode (look for 1./lambda instead of "
|
|
"lambda)."
|
|
<< endl;
|
|
cout << " default: no invert" << endl;
|
|
cout << " --tol T: tolerance T." << endl;
|
|
cout << " default: 1.e-06" << endl;
|
|
cout << " --maxResNorm R: maximum residual norm R." << endl;
|
|
cout << " default: 1.e-3" << endl;
|
|
cout << " --maxIt M: maximum iterations M." << endl;
|
|
cout << " default: 100" << endl;
|
|
cout << " --schur: compute Schur vectors." << endl;
|
|
cout << " the Schur decomposition is such that A = "
|
|
"Q^H x T x Q where:"
|
|
<< endl;
|
|
cout << " - the H superscript refers to the "
|
|
"Hermitian transpose: Q^H = (Q^t)^*."
|
|
<< endl;
|
|
cout
|
|
<< " - Q is unitary: Q is such that Q^H x Q = I."
|
|
<< endl;
|
|
cout << " - T is an upper-triangular matrix whose "
|
|
"diagonal elements are the eigenvalues of A."
|
|
<< endl;
|
|
cout << " every square matrix has a Schur "
|
|
"decomposition: columns of Q are the Schur vectors."
|
|
<< endl;
|
|
cout << " for a general matrix A, there is no "
|
|
"relation between Schur vectors of A and eigenvectors of A."
|
|
<< endl;
|
|
cout << " if q_j is the j-th Schur vector, then A x "
|
|
"q_j is a linear combination of q_1, ..., q_j."
|
|
<< endl;
|
|
cout << " Schur vectors q_1, q_2, ..., q_j span an "
|
|
"invariant subspace of A."
|
|
<< endl;
|
|
cout << " the Schur vectors and eigenvectors of A are "
|
|
"the same if A is a normal matrix."
|
|
<< endl;
|
|
cout << " default: compute Ritz vectors (approximations "
|
|
"of eigen vectors)"
|
|
<< endl;
|
|
cout << " --slv S: solver (needed if arpack mode > 1)." << endl;
|
|
cout << " BiCG: iterative method, any matrices"
|
|
<< endl;
|
|
cout << " CG: iterative method, sym matrices only"
|
|
<< endl;
|
|
cout << " LU: direct method, any matrices (pivoting "
|
|
"needed)"
|
|
<< endl;
|
|
cout << " QR: direct method, any matrices (pivoting "
|
|
"needed)"
|
|
<< endl;
|
|
cout << " LLT: direct method, SPD matrices only "
|
|
"(pivoting not needed)"
|
|
<< endl;
|
|
cout << " LDLT: direct method, symmetric positive "
|
|
"semi-definite matrices only (pivoting not needed)"
|
|
<< endl;
|
|
cout << " default: BiCG" << endl;
|
|
cout << " --slvItrTol T: solver tolerance T (for iterative solvers)."
|
|
<< endl;
|
|
cout << " default: 1.e-6" << endl;
|
|
cout << " --slvItrMaxIt M: solver maximum iterations M (for iterative "
|
|
"solvers)."
|
|
<< endl;
|
|
cout << " default: 100" << endl;
|
|
cout << " --slvItrPC PC: solver preconditioner (for iterative solvers)."
|
|
<< endl;
|
|
cout << " PC preconditioner:" << endl;
|
|
cout << " Diag: eigen diagonal preconditioner "
|
|
"(Jacobi)."
|
|
<< endl;
|
|
cout << " ILU#D#F: eigen ILU preconditioner."
|
|
<< endl;
|
|
cout << " D: drop tolerance." << endl;
|
|
cout << " F: fill factor." << endl;
|
|
cout << " default: diagonal preconditioner (Jacobi)"
|
|
<< endl;
|
|
cout << " --slvDrtPivot: P solver pivot P (for direct solvers)." << endl;
|
|
cout << " default: 1.e-06" << endl;
|
|
cout << " --slvDrtOffset: O solver offset O (for direct solvers)." << endl;
|
|
cout << " default: 0." << endl;
|
|
cout << " --slvDrtScale: S solver scale S (for direct solvers)." << endl;
|
|
cout << " default: 1." << endl;
|
|
cout << " --noCheck: check arpack eigen values/vectors." << endl;
|
|
cout << " check will fail if Schur vectors are computed "
|
|
"and A is NOT a normal matrix."
|
|
<< endl;
|
|
cout << " default: check" << endl;
|
|
cout << " --verbose V: verbosity level (up to 3)." << endl;
|
|
cout << " default: 0" << endl;
|
|
cout << " --debug D: debug level (up to 3)." << endl;
|
|
cout << " default: 0" << endl;
|
|
cout << " --restart: restart from previous run (which had produced "
|
|
"arpackSolver.*.out)."
|
|
<< endl;
|
|
cout << " restart from eigen basis approximation "
|
|
"computed during a previous run."
|
|
<< endl;
|
|
cout << " default: false" << endl;
|
|
return 1;
|
|
};
|
|
|
|
friend ostream& operator<<(ostream& ostr, options const& opt);
|
|
|
|
string fileA;
|
|
string fileB;
|
|
bool dense;
|
|
bool denseRR;
|
|
a_int nbEV;
|
|
a_int nbCV;
|
|
bool stdPb; // Standard or generalized (= not standard).
|
|
bool symPb;
|
|
bool cpxPb;
|
|
bool simplePrec;
|
|
string mag; // Magnitude <=> "which" arpack parameter.
|
|
bool shiftReal, shiftImag;
|
|
double sigmaReal, sigmaImag; // Eigen value translation: look for
|
|
// lambda+sigma instead of lambda.
|
|
bool invert; // Eigen value invertion: look for 1./lambda instead of lambda.
|
|
double tol;
|
|
double maxResNorm;
|
|
int maxIt;
|
|
bool schur;
|
|
string slv;
|
|
double slvItrTol;
|
|
int slvItrMaxIt;
|
|
string slvItrPC;
|
|
double slvDrtPivot;
|
|
double slvDrtOffset;
|
|
double slvDrtScale;
|
|
bool check;
|
|
int verbose;
|
|
a_int debug;
|
|
bool restart;
|
|
};
|
|
|
|
ostream& operator<<(ostream& ostr, options const& opt) {
|
|
ostr << "OPT: A " << opt.fileA;
|
|
if (!opt.fileB.empty()) ostr << ", B " << opt.fileB;
|
|
if (opt.dense && opt.denseRR)
|
|
ostr << ", dense yes (RR true)";
|
|
else if (opt.dense && !opt.denseRR)
|
|
ostr << ", dense yes (RR false)";
|
|
else
|
|
ostr << ", dense no";
|
|
ostr << ", nbEV " << opt.nbEV << ", nbCV " << opt.nbCV << ", stdPb "
|
|
<< (opt.stdPb ? "yes" : "no");
|
|
ostr << ", symPb " << (opt.symPb ? "yes" : "no") << ", cpxPb "
|
|
<< (opt.cpxPb ? "yes" : "no");
|
|
ostr << ", simplePrec " << (opt.simplePrec ? "yes" : "no") << ", mag "
|
|
<< opt.mag << endl;
|
|
ostr << "OPT: shiftReal " << (opt.shiftReal ? "yes" : "no") << ", sigmaReal "
|
|
<< opt.sigmaReal;
|
|
ostr << ", shiftImag " << (opt.shiftImag ? "yes" : "no") << ", sigmaImag "
|
|
<< opt.sigmaImag;
|
|
ostr << ", invert " << (opt.invert ? "yes" : "no") << ", tol " << opt.tol
|
|
<< ", maxResNorm " << opt.maxResNorm << ", maxIt " << opt.maxIt;
|
|
ostr << ", " << (opt.schur ? "Schur" : "Ritz") << " vectors" << endl;
|
|
ostr << "OPT: slv " << opt.slv;
|
|
bool itrSlv = true; // Use iterative solvers.
|
|
if (opt.slv.find("LU") != string::npos ||
|
|
opt.slv.find("QR") != string::npos ||
|
|
opt.slv.find("LLT") != string::npos ||
|
|
opt.slv.find("LDLT") != string::npos)
|
|
itrSlv = false;
|
|
if (itrSlv) {
|
|
ostr << ", slvItrPC " << opt.slvItrPC;
|
|
ostr << ", slvItrTol " << opt.slvItrTol;
|
|
ostr << ", slvItrMaxIt " << opt.slvItrMaxIt;
|
|
} else {
|
|
ostr << ", slvDrtPivot " << opt.slvDrtPivot;
|
|
ostr << ", slvDrtOffset " << opt.slvDrtOffset;
|
|
ostr << ", slvDrtScale " << opt.slvDrtScale;
|
|
}
|
|
ostr << endl;
|
|
ostr << "OPT: check " << (opt.check ? "yes" : "no") << ", verbose "
|
|
<< opt.verbose << ", debug " << opt.debug;
|
|
ostr << ", restart " << (opt.restart ? "yes" : "no") << endl;
|
|
return ostr;
|
|
}
|
|
|
|
class output {
|
|
public:
|
|
output() {
|
|
nbVal = 0;
|
|
mode = 0;
|
|
nbIt = 0;
|
|
imsTime = 0.;
|
|
rciTime = 0.;
|
|
};
|
|
|
|
int nbVal; // Eigen values.
|
|
int mode; // Arpack mode.
|
|
int nbIt; // Arpack number of iterations.
|
|
double imsTime; // Init mode solver time.
|
|
double rciTime; // Reverse communication interface time.
|
|
vector<tuple<double, double>> res; // Results: eigen values and associated residual.
|
|
};
|
|
|
|
template <typename RC, typename FD, typename EM, typename SLV>
|
|
int itrSolve(options& opt, output& out, double const& slvItrILUDropTol,
|
|
double const& slvItrILUFillFactor) {
|
|
// Init solver.
|
|
|
|
arpackItrSolver<RC, FD, EM, SLV> as;
|
|
as.symPb = opt.symPb;
|
|
as.nbEV = opt.nbEV;
|
|
as.nbCV = opt.nbCV;
|
|
as.tol = opt.tol;
|
|
as.sigmaReal = opt.sigmaReal;
|
|
as.sigmaImag = opt.sigmaImag;
|
|
as.dumpToFile = true;
|
|
as.restartFromFile = opt.restart;
|
|
as.mag = opt.mag;
|
|
as.maxIt = opt.maxIt;
|
|
as.schur = opt.schur;
|
|
as.verbose = opt.verbose;
|
|
as.slvTol = opt.slvItrTol;
|
|
as.slvMaxIt = opt.slvItrMaxIt;
|
|
as.slvILUDropTol = slvItrILUDropTol;
|
|
as.slvILUFillFactor = slvItrILUFillFactor;
|
|
|
|
// Read A and B matrices.
|
|
|
|
EM A;
|
|
auto start = chrono::high_resolution_clock::now();
|
|
int rc = as.createMatrix(opt.fileA, A);
|
|
if (rc != 0) {
|
|
cerr << "Error: read A KO" << endl;
|
|
return rc;
|
|
}
|
|
auto stop = chrono::high_resolution_clock::now();
|
|
double readATime =
|
|
chrono::duration_cast<chrono::milliseconds>(stop - start).count() / 1000.;
|
|
cout << endl;
|
|
cout << "INP: create A " << readATime << " s" << endl;
|
|
|
|
EM B;
|
|
if (!opt.stdPb) {
|
|
start = chrono::high_resolution_clock::now();
|
|
rc = as.createMatrix(opt.fileB, B);
|
|
if (rc != 0) {
|
|
cerr << "Error: read B KO" << endl;
|
|
return rc;
|
|
}
|
|
stop = chrono::high_resolution_clock::now();
|
|
double readBTime =
|
|
chrono::duration_cast<chrono::milliseconds>(stop - start).count() /
|
|
1000.;
|
|
cout << endl;
|
|
cout << "INP: create B " << readBTime << " s" << endl;
|
|
|
|
if (A.rows() != B.rows()) {
|
|
cerr << "Error: A.rows() != B.rows()" << endl;
|
|
return rc;
|
|
}
|
|
if (A.cols() != B.cols()) {
|
|
cerr << "Error: A.cols() != B.cols()" << endl;
|
|
return rc;
|
|
}
|
|
}
|
|
|
|
// Solve.
|
|
|
|
rc = as.solve(A, opt.stdPb ? nullptr : &B);
|
|
if (rc != 0) {
|
|
cerr << "Error: solve KO" << endl;
|
|
return rc;
|
|
}
|
|
if (opt.check) {
|
|
rc = as.checkEigVec(A, opt.stdPb ? nullptr : &B, opt.maxResNorm);
|
|
if (rc != 0) {
|
|
cerr << "Error: check KO" << endl;
|
|
return rc;
|
|
}
|
|
}
|
|
|
|
// Retrieve outputs.
|
|
|
|
out.nbVal = as.val.size();
|
|
out.mode = as.mode;
|
|
out.nbIt = as.nbIt;
|
|
out.imsTime = as.imsTime;
|
|
out.rciTime = as.rciTime;
|
|
for (auto idx = 0; idx < as.val.size(); idx++) {
|
|
double val = norm(as.val[idx]);
|
|
double res = as.computeResidualNorm(idx, A, opt.stdPb ? nullptr : &B);
|
|
out.res.push_back(tuple<double, double>{val, res});
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
template <typename RC, typename FD, typename EM, typename SLV>
|
|
int drtSolve(options& opt, output& out) {
|
|
// Init solver.
|
|
|
|
arpackDrtSolver<RC, FD, EM, SLV> as;
|
|
as.symPb = opt.symPb;
|
|
as.nbEV = opt.nbEV;
|
|
as.nbCV = opt.nbCV;
|
|
as.tol = opt.tol;
|
|
as.sigmaReal = opt.sigmaReal;
|
|
as.sigmaImag = opt.sigmaImag;
|
|
as.dumpToFile = true;
|
|
as.restartFromFile = opt.restart;
|
|
as.mag = opt.mag;
|
|
as.maxIt = opt.maxIt;
|
|
as.schur = opt.schur;
|
|
as.verbose = opt.verbose;
|
|
as.slvPvtThd = opt.slvDrtPivot;
|
|
as.slvOffset = opt.slvDrtOffset;
|
|
as.slvScale = opt.slvDrtScale;
|
|
|
|
// Read A and B matrices.
|
|
|
|
EM A;
|
|
auto start = chrono::high_resolution_clock::now();
|
|
int rc = as.createMatrix(opt.fileA, A);
|
|
if (rc != 0) {
|
|
cerr << "Error: read A KO" << endl;
|
|
return rc;
|
|
}
|
|
auto stop = chrono::high_resolution_clock::now();
|
|
double readATime =
|
|
chrono::duration_cast<chrono::milliseconds>(stop - start).count() / 1000.;
|
|
cout << endl;
|
|
cout << "INP: create A " << readATime << " s" << endl;
|
|
|
|
EM B;
|
|
if (!opt.stdPb) {
|
|
start = chrono::high_resolution_clock::now();
|
|
rc = as.createMatrix(opt.fileB, B);
|
|
if (rc != 0) {
|
|
cerr << "Error: read B KO" << endl;
|
|
return rc;
|
|
}
|
|
stop = chrono::high_resolution_clock::now();
|
|
double readBTime =
|
|
chrono::duration_cast<chrono::milliseconds>(stop - start).count() /
|
|
1000.;
|
|
cout << endl;
|
|
cout << "INP: create B " << readBTime << " s" << endl;
|
|
|
|
if (A.rows() != B.rows()) {
|
|
cerr << "Error: A.rows() != B.rows()" << endl;
|
|
return rc;
|
|
}
|
|
if (A.cols() != B.cols()) {
|
|
cerr << "Error: A.cols() != B.cols()" << endl;
|
|
return rc;
|
|
}
|
|
}
|
|
|
|
// Solve.
|
|
|
|
rc = as.solve(A, opt.stdPb ? nullptr : &B);
|
|
if (rc != 0) {
|
|
cerr << "Error: solve KO" << endl;
|
|
return rc;
|
|
}
|
|
if (opt.check) {
|
|
rc = as.checkEigVec(A, opt.stdPb ? nullptr : &B, opt.maxResNorm);
|
|
if (rc != 0) {
|
|
cerr << "Error: check KO" << endl;
|
|
return rc;
|
|
}
|
|
}
|
|
|
|
// Retrieve outputs.
|
|
|
|
out.nbVal = as.val.size();
|
|
out.mode = as.mode;
|
|
out.nbIt = as.nbIt;
|
|
out.imsTime = as.imsTime;
|
|
out.rciTime = as.rciTime;
|
|
for (auto idx = 0; idx < as.val.size(); idx++) {
|
|
double val = norm(as.val[idx]);
|
|
double res = as.computeResidualNorm(idx, A, opt.stdPb ? nullptr : &B);
|
|
out.res.push_back(tuple<double, double>{val, res});
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
template <typename RC, typename FD, typename EM, typename SLV1, typename SLV2,
|
|
typename SLV3, typename SLV4>
|
|
int drtSolve(options& opt, output& out) {
|
|
int rc = 1;
|
|
|
|
if (opt.slv == "LU") rc = drtSolve<RC, FD, EM, SLV1>(opt, out);
|
|
if (opt.slv == "QR") rc = drtSolve<RC, FD, EM, SLV2>(opt, out);
|
|
if (opt.slv == "LLT") rc = drtSolve<RC, FD, EM, SLV3>(opt, out);
|
|
if (opt.slv == "LDLT") rc = drtSolve<RC, FD, EM, SLV4>(opt, out);
|
|
|
|
return rc;
|
|
}
|
|
|
|
template <typename RC, typename FD, typename EM, typename SLV1, typename SLV2,
|
|
typename SLV3, typename SLV4>
|
|
int itrSolve(options& opt, output& out) {
|
|
int rc = 1;
|
|
|
|
stringstream clo(opt.slvItrPC);
|
|
string slvItrPC;
|
|
getline(clo, slvItrPC, '#');
|
|
|
|
double slvItrILUDropTol = 1.;
|
|
if (slvItrPC == "ILU") {
|
|
string dropTol;
|
|
getline(clo, dropTol, '#');
|
|
stringstream dt(dropTol);
|
|
dt >> slvItrILUDropTol;
|
|
}
|
|
|
|
int slvItrILUFillFactor = 2;
|
|
if (slvItrPC == "ILU") {
|
|
string fillFactor;
|
|
getline(clo, fillFactor);
|
|
stringstream ff(fillFactor);
|
|
ff >> slvItrILUFillFactor;
|
|
}
|
|
|
|
if (opt.slv == "BiCG") {
|
|
if (slvItrPC == "Diag")
|
|
rc = itrSolve<RC, FD, EM, SLV1>(opt, out, slvItrILUDropTol,
|
|
slvItrILUFillFactor);
|
|
if (slvItrPC == "ILU")
|
|
rc = itrSolve<RC, FD, EM, SLV2>(opt, out, slvItrILUDropTol,
|
|
slvItrILUFillFactor);
|
|
}
|
|
if (opt.slv == "CG") {
|
|
if (slvItrPC == "Diag")
|
|
rc = itrSolve<RC, FD, EM, SLV3>(opt, out, slvItrILUDropTol,
|
|
slvItrILUFillFactor);
|
|
if (slvItrPC == "ILU")
|
|
rc = itrSolve<RC, FD, EM, SLV4>(opt, out, slvItrILUDropTol,
|
|
slvItrILUFillFactor);
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
int run(int argc, char** argv) {
|
|
// Check for options.
|
|
|
|
options opt;
|
|
int rc = opt.readCmdLine(argc, argv);
|
|
if (rc != 0) {
|
|
cerr << "Error: read cmd line KO" << endl;
|
|
return rc;
|
|
}
|
|
cout << opt; // Print options.
|
|
|
|
// Solve with arpack.
|
|
|
|
sstats_c(); // Reset timers.
|
|
sstatn_c(); // Reset timers.
|
|
cstatn_c(); // Reset timers.
|
|
|
|
bool itrSlv = true; // Use iterative solvers.
|
|
if (opt.slv.find("LU") != string::npos ||
|
|
opt.slv.find("QR") != string::npos ||
|
|
opt.slv.find("LLT") != string::npos ||
|
|
opt.slv.find("LDLT") != string::npos)
|
|
itrSlv = false;
|
|
|
|
output out;
|
|
auto start = chrono::high_resolution_clock::now();
|
|
if (opt.dense) {
|
|
if (itrSlv) {
|
|
cerr << "Error: dense matrices does not support iterative solvers"
|
|
<< ", specify --slv XX with XX being a direct solver"
|
|
<< endl;
|
|
return 1;
|
|
}
|
|
|
|
if (opt.simplePrec) {
|
|
if (opt.cpxPb) {
|
|
if (opt.denseRR) {
|
|
rc = drtSolve<complex<float>, float, EigDMxC, EigDFLUC, EigDFQRC,
|
|
EigDLLTC, EigDLDLTC>(opt, out);
|
|
} else {
|
|
rc = drtSolve<complex<float>, float, EigDMxC, EigDPLUC, EigDPQRC,
|
|
EigDLLTC, EigDLDLTC>(opt, out);
|
|
}
|
|
} else {
|
|
if (opt.denseRR) {
|
|
rc = drtSolve<float, float, EigDMxS, EigDFLUS, EigDFQRS, EigDLLTS,
|
|
EigDLDLTS>(opt, out);
|
|
} else {
|
|
rc = drtSolve<float, float, EigDMxS, EigDPLUS, EigDPQRS, EigDLLTS,
|
|
EigDLDLTS>(opt, out);
|
|
}
|
|
}
|
|
} else {
|
|
if (opt.cpxPb) {
|
|
if (opt.denseRR) {
|
|
rc = drtSolve<complex<double>, double, EigDMxZ, EigDFLUZ, EigDFQRZ,
|
|
EigDLLTZ, EigDLDLTZ>(opt, out);
|
|
} else {
|
|
rc = drtSolve<complex<double>, double, EigDMxZ, EigDPLUZ, EigDPQRZ,
|
|
EigDLLTZ, EigDLDLTZ>(opt, out);
|
|
}
|
|
} else {
|
|
if (opt.denseRR) {
|
|
rc = drtSolve<double, double, EigDMxD, EigDFLUD, EigDFQRD, EigDLLTD,
|
|
EigDLDLTD>(opt, out);
|
|
} else {
|
|
rc = drtSolve<double, double, EigDMxD, EigDPLUD, EigDPQRD, EigDLLTD,
|
|
EigDLDLTD>(opt, out);
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
if (opt.simplePrec) {
|
|
if (opt.cpxPb) {
|
|
if (itrSlv) {
|
|
rc = itrSolve<complex<float>, float, EigSMxC, EigSBiCGC, EigSBiCGILUC,
|
|
EigSCGC, EigSCGILUC>(opt, out);
|
|
} else {
|
|
rc = drtSolve<complex<float>, float, EigSMxC, EigSLUC, EigSQRC,
|
|
EigSLLTC, EigSLDLTC>(opt, out);
|
|
}
|
|
} else {
|
|
if (itrSlv) {
|
|
rc = itrSolve<float, float, EigSMxS, EigSBiCGS, EigSBiCGILUS, EigSCGS,
|
|
EigSCGILUS>(opt, out);
|
|
} else {
|
|
rc = drtSolve<float, float, EigSMxS, EigSLUS, EigSQRS, EigSLLTS,
|
|
EigSLDLTS>(opt, out);
|
|
}
|
|
}
|
|
} else {
|
|
if (opt.cpxPb) {
|
|
if (itrSlv) {
|
|
rc = itrSolve<complex<double>, double, EigSMxZ, EigSBiCGZ,
|
|
EigSBiCGILUZ, EigSCGZ, EigSCGILUZ>(opt, out);
|
|
} else {
|
|
rc = drtSolve<complex<double>, double, EigSMxZ, EigSLUZ, EigSQRZ,
|
|
EigSLLTZ, EigSLDLTZ>(opt, out);
|
|
}
|
|
} else {
|
|
if (itrSlv) {
|
|
rc = itrSolve<double, double, EigSMxD, EigSBiCGD, EigSBiCGILUD,
|
|
EigSCGD, EigSCGILUD>(opt, out);
|
|
} else {
|
|
rc = drtSolve<double, double, EigSMxD, EigSLUD, EigSQRD, EigSLLTD,
|
|
EigSLDLTD>(opt, out);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (rc != 0) {
|
|
cerr << "Error: arpack solve KO" << endl;
|
|
return rc;
|
|
}
|
|
|
|
// Output results and stats.
|
|
|
|
auto stop = chrono::high_resolution_clock::now();
|
|
double fullTime =
|
|
chrono::duration_cast<chrono::milliseconds>(stop - start).count() / 1000.;
|
|
cout << endl;
|
|
cout << "OUT: mode " << out.mode << ", nb EV found " << out.nbVal
|
|
<< ", nb iterations " << out.nbIt << endl;
|
|
cout << "OUT: init mode solver " << out.imsTime << " s, RCI time "
|
|
<< out.rciTime << " s" << endl;
|
|
cout << "OUT: full time " << fullTime << " s" << endl;
|
|
|
|
a_int nopx = 0, nbx = 0, nrorth = 0, nitref = 0, nrstrt = 0;
|
|
float tsaupd = 0., tsaup2 = 0., tsaitr = 0., tseigt = 0., tsgets = 0.,
|
|
tsapps = 0., tsconv = 0.;
|
|
float tnaupd = 0., tnaup2 = 0., tnaitr = 0., tneigt = 0., tngets = 0.,
|
|
tnapps = 0., tnconv = 0.;
|
|
float tcaupd = 0., tcaup2 = 0., tcaitr = 0., tceigt = 0., tcgets = 0.,
|
|
tcapps = 0., tcconv = 0.;
|
|
float tmvopx = 0., tmvbx = 0., tgetv0 = 0., titref = 0., trvec = 0.;
|
|
stat_c(nopx, nbx, nrorth, nitref, nrstrt, tsaupd, tsaup2, tsaitr, tseigt,
|
|
tsgets, tsapps, tsconv, tnaupd, tnaup2, tnaitr, tneigt, tngets, tnapps,
|
|
tnconv, tcaupd, tcaup2, tcaitr, tceigt, tcgets, tcapps, tcconv, tmvopx,
|
|
tmvbx, tgetv0, titref, trvec);
|
|
cout << endl;
|
|
cout << "STAT: total number of user OP*x operation "
|
|
<< nopx << endl;
|
|
cout << "STAT: total number of user B*x operation "
|
|
<< nbx << endl;
|
|
cout << "STAT: total number of reorthogonalization steps taken "
|
|
<< nrorth << endl;
|
|
cout << "STAT: total number of it. refinement steps in reorthogonalization "
|
|
<< nitref << endl;
|
|
cout << "STAT: total number of restart steps "
|
|
<< nrstrt << endl;
|
|
|
|
// Output eigen values and residuals.
|
|
|
|
cout << endl;
|
|
for (auto idx = 0; idx < out.res.size(); idx++) {
|
|
tuple<double, double> res = out.res[idx];
|
|
cout << "RES: eigen value " << idx << ": norm " << get<0>(res);
|
|
cout << " (residual norm " << get<1>(res) << ")";
|
|
cout << endl;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int main(int argc, char** argv) {
|
|
int rc = 1;
|
|
try {
|
|
rc = run(argc, argv);
|
|
}
|
|
catch (exception& e) {
|
|
cout << "Error - exception:" << e.what() << endl;
|
|
}
|
|
return rc;
|
|
}
|
|
|
|
// Local Variables:
|
|
// mode: c++
|
|
// c-file-style:"stroustrup"
|
|
// show-trailing-whitespace: t
|
|
// End:
|
|
/* vim: set sw=2 ts=2 et smartindent :*/
|