arpackmm: utility to test arpack with matrix market files. (#157)

This commit is contained in:
Franck HOUSSEN
2018-12-12 09:39:56 +01:00
committed by Sylvestre Ledru
parent 8840cfdf43
commit 2c1f6ebb5b
14 changed files with 1168 additions and 2 deletions
+3
View File
@@ -50,6 +50,9 @@ EXAMPLES/SIMPLE/[sd]ssimp
EXAMPLES/SIMPLE/[sdcz]nsimp
EXAMPLES/SVD/[sd]svd
EXAMPLES/SYM/[sd]sdrv[123456]
EXAMPLES/MATRIX_MARKET/arpackmm
EXAMPLES/MATRIX_MARKET/resid.out
EXAMPLES/MATRIX_MARKET/v.out
PARPACK/EXAMPLES/MPI/p[sd]ndrv[13]
PARPACK/EXAMPLES/MPI/p[sd]sdrv1
PARPACK/EXAMPLES/MPI/p[cz]ndrv1
+8 -1
View File
@@ -20,6 +20,7 @@ addons:
- liblapack-dev
- diffutils
- findutils
- libeigen3-dev
stages:
# order stages
@@ -60,6 +61,9 @@ jobs:
- stage: xenial
dist: xenial
script: mkdir -p build && cd build && cmake -D EXAMPLES=ON -D MPI=OFF -D ICB=ON .. && make VERBOSE=1 && make test && make package_source;
- stage: xenial
dist: xenial
script: mkdir -p build && cd build && cmake -DEXAMPLES=ON -DMPI=OFF -DICBEXMM=ON .. && make VERBOSE=1 && make test && make package_source;
- stage: xenial
dist: xenial
script: mkdir -p build && cd build && cmake -D EXAMPLES=ON -D MPI=ON -D ICB=ON .. && make VERBOSE=1 && make test && make package_source;
@@ -72,13 +76,16 @@ jobs:
- stage: xenial
dist: xenial
script: ./bootstrap && ./configure --enable-icb && make VERBOSE=1 && make check && make distcheck;
- stage: xenial
dist: xenial
script: ./bootstrap && ./configure --enable-icb-exmm && make VERBOSE=1 && make check && make distcheck;
- stage: xenial
dist: xenial
script: ./bootstrap && ./configure --enable-mpi --enable-icb && make VERBOSE=1 && make check && make distcheck;
# xenial <=> coverage: "recent" systems with ICB
- stage: coverage
dist: xenial
script: mkdir -p build && cd build && cmake -DEXAMPLES=ON -DMPI=ON -DICB=ON -DCOVERALLS=ON .. && make VERBOSE=1 && make test;
script: mkdir -p build && cd build && cmake -DEXAMPLES=ON -DMPI=ON -DICBEXMM=ON -DCOVERALLS=ON .. && make VERBOSE=1 && make test;
after_failure:
+1
View File
@@ -3,6 +3,7 @@ arpack-ng - 3.6.4
[ Franck Houssen ]
* [BUG FIX] ICB: missing workev for *[ds]neupd (real+not-sym) => API/ABI change for *[ds]neupd_c.
* [BUG FIX] autotools - make distcheck: fix circular dependencies.
* arpackmm: utility to test arpack with matrix market files.
-- Sylvestre Ledru <sylvestre@debian.org> Sat, 10 Nov 2018 09:28:08 +0100
+44
View File
@@ -17,6 +17,7 @@ endif ()
option(MPI "Enable parallel support" OFF)
option(ICB "Enable support for *[ae]upd_c with ISO_C_BINDING" OFF)
option(ICBEXMM "Enable support for matrix market example based on ICB" OFF)
#option(SYSTEM_BLAS "Use system BLAS" ON)
#option(SYSTEM_LAPACK "Use system LAPACK" ON)
option(EXAMPLES "Compile ARPACK examples" OFF)
@@ -59,6 +60,35 @@ function(pexamples list_name)
endforeach()
endfunction(pexamples)
if (ICBEXMM)
find_package(Eigen3)
if (NOT Eigen3_FOUND) # If not found, piggy-back pkg-config files.
message(WARNING "CMake didn't find the Eigen3 package. Try to look for pkg-config file...")
find_package(PkgConfig 3.2 REQUIRED)
pkg_check_modules(EIGEN3 REQUIRED eigen3>=3.2)
endif ()
# Look for headers.
find_path(EIGEN3_SPARSE_DIR NAMES Sparse PATHS ${EIGEN3_INCLUDE_DIRS} PATH_SUFFIXES Eigen)
if (NOT EIGEN3_SPARSE_DIR)
message(FATAL_ERROR "-- Eigen/Sparse header not found.")
endif ()
find_path(EIGEN3_ITERATIVE_SOLVER_DIR NAMES IterativeLinearSolvers PATHS ${EIGEN3_INCLUDE_DIRS} PATH_SUFFIXES Eigen)
if (NOT EIGEN3_ITERATIVE_SOLVER_DIR)
message(FATAL_ERROR "-- Eigen/IterativeLinearSolvers header not found.")
endif ()
find_path(EIGEN3_SLU_SOLVER_DIR NAMES SparseLU PATHS ${EIGEN3_INCLUDE_DIRS} PATH_SUFFIXES Eigen)
if (NOT EIGEN3_SLU_SOLVER_DIR)
message(FATAL_ERROR "-- Eigen/SparseLU header not found.")
endif ()
find_path(EIGEN3_SQR_SOLVER_DIR NAMES SparseQR PATHS ${EIGEN3_INCLUDE_DIRS} PATH_SUFFIXES Eigen)
if (NOT EIGEN3_SQR_SOLVER_DIR)
message(FATAL_ERROR "-- Eigen/SparseQR header not found.")
endif ()
set(ICB "ON")
endif ()
# Enable language(s) before any find_package (in particular before MPI find_package).
if (ICB)
enable_language(C CXX) # For testing binding with c/c++.
@@ -508,6 +538,17 @@ if(ICB)
target_link_libraries(icb_arpack_cpp arpack ${BLAS_LIBRARIES} ${LAPACK_LIBRARIES} ${EXTRA_LDLAGS})
add_test(icb_arpack_cpp_tst Tests/icb_arpack_cpp)
if (ICBEXMM)
add_executable(arpackmm EXAMPLES/MATRIX_MARKET/arpackmm.cpp)
target_include_directories(arpackmm PUBLIC ${PROJECT_SOURCE_DIR}/ICB ${EIGEN3_INCLUDE_DIRS}) # Get arpack.h + eigen
target_link_libraries(arpackmm arpack ${BLAS_LIBRARIES} ${LAPACK_LIBRARIES} ${EXTRA_LDLAGS})
configure_file(EXAMPLES/MATRIX_MARKET/As.mtx Tests/As.mtx)
configure_file(EXAMPLES/MATRIX_MARKET/An.mtx Tests/An.mtx)
configure_file(EXAMPLES/MATRIX_MARKET/B.mtx Tests/B.mtx)
configure_file(EXAMPLES/MATRIX_MARKET/arpackmm.sh Tests/arpackmm.sh)
add_test(NAME arpackmm_tst WORKING_DIRECTORY ${arpack_BINARY_DIR}/Tests COMMAND arpackmm.sh)
endif()
if (MPI)
add_executable(icb_parpack_c PARPACK/TESTS/MPI/icb_parpack_c.c)
target_include_directories(icb_parpack_c PUBLIC ${PROJECT_SOURCE_DIR}/ICB ${MPI_C_INCLUDE_DIRS}) # Get parpack.h mpi.h
@@ -646,3 +687,6 @@ if (MPI)
endif()
libsummary("BLAS" "" "${BLAS_LIBRARIES}")
libsummary("LAPACK" "" "${LAPACK_LIBRARIES}")
if (ICBEXMM)
libsummary("EIGEN3" "${EIGEN3_INCLUDE_DIRS}" "")
endif()
+79
View File
@@ -0,0 +1,79 @@
%% MatrixMarket matrix coordinate double symmetric
% This example is 0-based without (optional) nnz
%
% This is a 1D diffusive laplacian matrix (fixed at first end <=> invertible)
%
% 1 1
% . .--.
% / \ | |
% / \ 0 0 | |
% phi_i --o o o--o-- => grad(phi_i) --o o o--o--
% i j i| |j
% | |
% .--.
% -1.
%
% 1 1
% . .--.
% / \ | |
% / \ 0 i| |j
% phi_j --o--o o o-- => grad(phi_j) --o--o o o--
% i j | | 0
% | |
% .--.
% -1.
%
% i j
% | l_ii l_ij | i
% laplacian = | |
% | l_ji l_jj | j
%
% distance(i, j) = d = 1.
%
% l_ii = int_[i,j](grad(phi_i).grad(phi_i)) = d*(-1.)*(-1.) = 1.
% l_ij = int_[i,j](grad(phi_i).grad(phi_j)) = d*(-1.)*( 1.) = -1.
% l_ji = int_[i,j](grad(phi_j).grad(phi_i)) = d*( 1.)*(-1.) = -1.
% l_jj = int_[i,j](grad(phi_j).grad(phi_j)) = d*( 1.)*( 1.) = 1.
%
% i j
% | d_ii d_ij | i
% diffusion = | |
% | d_ji d_jj | j
%
% d_ii = int_[i,j](phi_i.grad(phi_i)) = int_[i,j]((1-x)*(-1.)) = -d*0.5 = -0.5
% d_ij = int_[i,j](phi_i.grad(phi_j)) = int_[i,j]((1-x)*( 1.)) = d*0.5 = 0.5
% d_ji = int_[i,j](phi_j.grad(phi_i)) = int_[i,j]( x *(-1.)) = -d*0.5 = -0.5
% d_jj = int_[i,j](phi_j.grad(phi_j)) = int_[i,j]( x *( 1.)) = d*0.5 = 0.5
%
% A <=> assembly of {kappa*laplacian + rho*diffusion}
% where kappa = 100 and rho = 2
%
% n m [nnz]
% i j Aij
8 8
0 0 1.
1 1 200.
2 2 200.
3 3 200.
4 4 200.
5 5 200.
6 6 200.
7 7 101.
1 0 0.
2 1 -101.
3 2 -101.
4 3 -101.
5 4 -101.
6 5 -101.
7 6 -101.
0 1 0.
1 2 -99.
2 3 -99.
3 4 -99.
4 5 -99.
5 6 -99.
6 7 -99.
+69
View File
@@ -0,0 +1,69 @@
%% MatrixMarket matrix coordinate double symmetric
% This example is 0-based without (optional) nnz
%
% This is a 1D laplacian matrix (fixed at first end <=> invertible)
%
% 1 1
% . .--.
% / \ | |
% / \ 0 0 | |
% phi_i --o o o--o-- => grad(phi_i) --o o o--o--
% i j i| |j
% | |
% .--.
% -1.
%
% 1 1
% . .--.
% / \ | |
% / \ 0 i| |j
% phi_j --o--o o o-- => grad(phi_j) --o--o o o--
% i j | | 0
% | |
% .--.
% -1.
%
% i j
% | l_ii l_ij | i
% laplacian = | |
% | l_ji l_jj | j
%
% distance(i, j) = d = 1.
%
% l_ii = int_[i,j](grad(phi_i).grad(phi_i)) = d*(-1.)*(-1.) = 1.
% l_ij = int_[i,j](grad(phi_i).grad(phi_j)) = d*(-1.)*( 1.) = -1.
% l_ji = int_[i,j](grad(phi_j).grad(phi_i)) = d*( 1.)*(-1.) = -1.
% l_jj = int_[i,j](grad(phi_j).grad(phi_j)) = d*( 1.)*( 1.) = 1.
%
% A <=> assembly of {kappa*laplacian}
% where kappa = 100
%
% n m [nnz]
% i j Aij
8 8
0 0 1.
1 1 200.
2 2 200.
3 3 200.
4 4 200.
5 5 200.
6 6 200.
7 7 100.
1 0 0.00
2 1 -100.00
3 2 -100.00
4 3 -100.00
5 4 -100.00
6 5 -100.00
7 6 -100.00
0 1 0.00
1 2 -100.00
2 3 -100.00
3 4 -100.00
4 5 -100.00
5 6 -100.00
6 7 -100.00
+62
View File
@@ -0,0 +1,62 @@
%% MatrixMarket matrix coordinate double general
% This example is 1-based with (optional) nnz
%
% This is a 1D mass matrix
%
% 1
% .
% / \
% / \ 0
% phi_i --o o o--o--
% i j
%
% 1
% .
% / \
% / \ 0
% phi_j --o--o o o--
% i j
%
% i j
% | i_ii i_ij | i
% inertia = | |
% | i_ji i_jj | j
%
% distance(i, j) = d = 1.
%
% i_ii = int_[i,j](phi_i.phi_i) = int_[i,j]((1-x)(1-x)) = i_jj (area under the curve)
% i_ij = int_[i,j](phi_i.phi_j) = int_[i,j]((1-x) x ) = i_ji
% i_ji = int_[i,j](phi_j.phi_i) = int_[i,j]( x (1-x)) = d*1./6.
% i_jj = int_[i,j](phi_j.phi_j) = int_[i,j]( x x ) = d*1./3.
%
% B <=> mass assembly
%
% n m [nnz]
% i j Bij
8 8 22
1 1 0.333
2 2 0.333
3 3 0.333
4 4 0.333
5 5 0.333
6 6 0.333
7 7 0.333
8 8 0.333
2 1 0.166
3 2 0.166
4 3 0.166
5 4 0.166
6 5 0.166
7 6 0.166
8 7 0.166
1 2 0.166
2 3 0.166
3 4 0.166
4 5 0.166
5 6 0.166
6 7 0.166
7 8 0.166
+12
View File
@@ -0,0 +1,12 @@
if ICBEXMM
LDADD = $(top_builddir)/SRC/libarpack$(LIBSUFFIX).la $(LAPACK_LIBS) $(BLAS_LIBS)
EXTRA_DIST = README
check_PROGRAMS = arpackmm
TESTS = arpackmm.sh
arpackmm_SOURCES = arpackmm.cpp
arpackmm_CPPFLAGS = -I$(top_builddir)/ICB $(EIGEN3_CFLAGS)
arpackmm_LDADD = $(top_builddir)/SRC/libarpack$(LIBSUFFIX).la
endif
+22
View File
@@ -0,0 +1,22 @@
arpackmm: utility to test arpack with matrix market files.
This is meant to run arpack with different options to find
what are the ones that are the best for your particular
problem.
Typically: computing small eigen values may breakdown and/or
be slow (arpack is good at finding large eigen values only).
To compute small eigen values, it may be a better choice
to look for large eigen values with invert or shift+invert.
If solve breaks down, you may increase --nbCV, try --restart,
play with --shiftReal/Imag and/or --invert.
To build this utility, you need:
- to use a fortran compiler which supports iso_c_binding.
- to have installed eigen3 (to deal with the RCI).
- to configure arpack-ng this way:
- autotools:
~arpack-ng> ./configure --enable-icb-exmm; make all check
- cmake:
~arpack-ng/build> cmake -D ICBEXMM=ON ..; make all test
+760
View File
@@ -0,0 +1,760 @@
// This code sample is meant for convenience (not performance):
// - test/run arpack (eigen values / vectors, timing).
// - play with modes: shift, invert, shift + invert.
// - use with user matrices (matrix market format).
#include <iostream>
#include <string>
#include <sstream> // stringstream.
#include <fstream> // [io]fstream.
#include <vector>
#include <complex>
#include <algorithm> // max_element.
#include <chrono>
#include <limits> // epsilon.
#include <cmath> // fabs.
#include <iomanip> // setw.
#include "arpack.h"
#include "debug_c.hpp"
#include <Eigen/Sparse>
#include <Eigen/IterativeLinearSolvers>
#include <Eigen/SparseLU>
#include <Eigen/SparseQR>
using namespace std;
typedef Eigen::SparseMatrix< double> EigMatR; // Real.
typedef Eigen::Triplet < double> EigCooR; // Real.
typedef Eigen::SparseMatrix<complex<double>> EigMatC; // Complex.
typedef Eigen::Triplet <complex<double>> EigCooC; // Complex.
typedef Eigen::Matrix < double, Eigen::Dynamic, 1> EigVecR; // Real.
typedef Eigen::Map <EigVecR> EigMpVR; // Real.
typedef Eigen::Matrix <complex<double>, Eigen::Dynamic, 1> EigVecC; // Complex.
typedef Eigen::Map <EigVecC> EigMpVC; // Complex.
typedef Eigen::BiCGSTAB <EigMatR> EigBiCG;
typedef Eigen::ConjugateGradient<EigMatR> EigCG;
typedef Eigen::SparseLU<EigMatR, Eigen::COLAMDOrdering<int>> EigSLU;
typedef Eigen::SparseQR<EigMatR, Eigen::COLAMDOrdering<int>> EigSQR;
class options {
public:
options() {
fileA = "A.mtx";
fileB = "N.A."; // Not available.
nbEV = 1;
nbCV = 2*nbEV + 1;
stdPb = true; // Standard or generalized (= not standard).
symPb = true;
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;
maxIt = 100;
slv = "BiCG";
slvTol = 1.e-06;
slvMaxIt = 100;
check = true;
verbose = 0;
debug = 0;
restart = false;
};
int readCmdLine(int argc, char ** argv) {
// Check for command line independent parameters.
for (int a = 1; argv && a < argc; a++) {
string clo = argv[a]; // Command line option.
if (clo == "--help") return usage(0);
if (clo == "--A") {
a++; if (a >= argc) {cerr << "Error: bad " << clo << " - need argument" << endl; return usage();}
fileA = argv[a];
}
if (clo == "--nbEV") {
a++; if (a >= argc) {cerr << "Error: bad " << clo << " - need argument" << endl; return usage();}
stringstream nEV(argv[a]);
nEV >> nbEV; if (!nEV) {cerr << "Error: bad " << clo << " - bad argument" << endl; return usage();}
nbCV = 2*nbEV + 1;
}
if (clo == "--genPb") {
stdPb = false;
fileB = "B.mtx";
}
if (clo == "--nonSymPb") symPb = false;
if (clo == "--mag") {
a++; if (a >= argc) {cerr << "Error: bad " << clo << " - need argument" << endl; return usage();}
mag = argv[a]; // small mag (likely poor perf) <=> large mag + invert (likely good perf).
bool ok = (mag == "LM" || mag == "SM" || mag == "LR" || mag == "SR" || mag == "LI" || mag == "SI") ? true : false;
if (!ok) {cerr << "Error: bad " << clo << " - bad argument" << endl; return usage();}
}
if (clo == "--shiftReal") {
shiftReal = true;
a++; if (a >= argc) {cerr << "Error: bad " << clo << " - need argument" << endl; return usage();}
stringstream s(argv[a]);
s >> sigmaReal; if (!s) {cerr << "Error: bad " << clo << " - bad argument" << endl; return usage();}
}
if (clo == "--shiftImag") {
shiftImag = true;
a++; if (a >= argc) {cerr << "Error: bad " << clo << " - need argument" << endl; return usage();}
stringstream s(argv[a]);
s >> sigmaImag; if (!s) {cerr << "Error: bad " << clo << " - bad argument" << endl; return usage();}
}
if (clo == "--invert") invert = true;
if (clo == "--tol") {
a++; if (a >= argc) {cerr << "Error: bad " << clo << " - need argument" << endl; return usage();}
stringstream t(argv[a]);
t >> tol; if (!t) {cerr << "Error: bad " << clo << " - bad argument" << endl; return usage();}
}
if (clo == "--maxIt") {
a++; if (a >= argc) {cerr << "Error: bad " << clo << " - need argument" << endl; return usage();}
stringstream mi(argv[a]);
mi >> maxIt; if (!mi) {cerr << "Error: bad " << clo << " - bad argument" << endl; return usage();}
}
if (clo == "--slv") {
a++; if (a >= argc) {cerr << "Error: bad " << clo << " - need argument" << endl; return usage();}
slv = argv[a];
}
if (clo == "--slvTol") {
a++; if (a >= argc) {cerr << "Error: bad " << clo << " - need argument" << endl; return usage();}
stringstream t(argv[a]);
t >> slvTol; if (!t) {cerr << "Error: bad " << clo << " - bad argument" << endl; return usage();}
}
if (clo == "--slvMaxIt") {
a++; if (a >= argc) {cerr << "Error: bad " << clo << " - need argument" << endl; return usage();}
stringstream mi(argv[a]);
mi >> slvMaxIt; if (!mi) {cerr << "Error: bad " << clo << " - bad argument" << endl; return usage();}
}
if (clo == "--noCheck") check = false;
if (clo == "--verbose") {
a++; if (a >= argc) {cerr << "Error: bad " << clo << " - need argument" << endl; return usage();}
stringstream vb(argv[a]);
vb >> verbose; if (!vb) {cerr << "Error: bad " << clo << " - bad argument" << endl; return usage();}
}
if (clo == "--debug") {
a++; if (a >= argc) {cerr << "Error: bad " << clo << " - need argument" << endl; return usage();}
stringstream dbg(argv[a]);
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;
}
// Check for command line dependent parameters.
for (int a = 1; argv && a < argc; a++) {
string clo = argv[a]; // Command line option.
if (clo == "--nbCV") {
a++; if (a >= argc) {cerr << "Error: bad " << clo << " - need argument" << endl; return usage();}
stringstream nCV(argv[a]);
nCV >> nbCV; if (!nCV) {cerr << "Error: bad " << clo << " - bad argument" << endl; return usage();}
}
if (clo == "--B") {
a++; if (a >= argc) {cerr << "Error: bad " << clo << " - need argument" << endl; return usage();}
fileB = argv[a];
}
}
return 0;
};
int usage(int rc = 1) {
cout << "Usage: running arpack 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 << " default: A.mtx" << endl;
cout << " --B F: file name of matrix B such that A X = lambda B X. (generalized)" << endl;
cout << " default: N.A. for standard problem, or, B.mtx for generalized problem" << 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 << " --genPb: generalized problem." << endl;
cout << " default: standard problem" << endl;
cout << " --nonSymPb: non symmetric problem." << endl;
cout << " default: symmetric problem" << endl;
cout << " --mag M: set magnitude of eigen values to look for (LM, SM, LR, SR, 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 << " --maxIt M: maximum iterations M." << endl;
cout << " default: 100" << endl;
cout << " --slv S: solver (BiCG, CG, LU)" << endl;
cout << " BiCG: iterative method, any matrices" << endl;
cout << " CG: iterative method, sym matrices only" << endl;
cout << " LU: direct method, any matrices" << endl;
cout << " QR: direct method, any matrices" << endl;
cout << " default: BiCG" << endl;
cout << " --slvTol T: tolerance T (if iterative method)." << endl;
cout << " default: 1.e-06" << endl;
cout << " --slvMaxIt M: maximum iterations M (if iterative method)." << endl;
cout << " default: 100" << endl;
cout << " --noCheck: check arpack eigen values/vectors." << 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 resid.out and v.out)." << endl;
cout << " default: false" << endl;
if (rc == 0) exit(0);
return rc;
};
friend ostream & operator<< (ostream & ostr, options const & opt);
string fileA;
string fileB;
int nbEV;
int nbCV;
bool stdPb; // Standard or generalized (= not standard).
bool symPb;
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;
int maxIt;
string slv;
double slvTol;
int slvMaxIt;
bool check;
int verbose;
int debug;
bool restart;
};
ostream & operator<< (ostream & ostr, options const & opt) {
ostr << "OPT: A " << opt.fileA << ", B " << opt.fileB;
ostr << ", nbEV " << opt.nbEV << ", nbCV " << opt.nbCV << ", stdPb " << (opt.stdPb ? "yes" : "no");
ostr << ", symPb " << (opt.symPb ? "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 << ", maxIt " << opt.maxIt << endl;
ostr << "OPT: slv " << opt.slv << ", slvTol " << opt.slvTol << ", slvMaxIt " << opt.slvMaxIt;
ostr << ", check " << (opt.check ? "yes" : "no") << ", verbose " << opt.verbose << ", debug " << opt.debug;
ostr << ", restart " << (opt.restart ? "yes" : "no") << endl;
return ostr;
}
int readMatrixMarket(string const & fileName, EigMatR & M, int const & verbose, string const & msg) {
ifstream inp(fileName);
if (!inp) {cerr << "Error: can not open " << fileName << endl; return 1;}
unsigned int l = 0, n = 0, m = 0, nnz = 0;
vector<unsigned int> i, j;
vector<double> Mij;
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] == '%') 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) { // OK, (optional) nnz has been provided.
i.reserve(nnz);
j.reserve(nnz);
Mij.reserve(nnz);
}
}
}
else { // Body.
unsigned int k = 0, l = 0;
double Mkl = 0.;
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.
nnz = i.size(); // In case nnz was not provided.
if (*max_element(begin(i), end(i)) == n || *max_element(begin(j), end(j)) == m) {
for (size_t k = 0; k < nnz; k++) i[k] -= 1;
for (size_t k = 0; k < nnz; k++) j[k] -= 1;
}
// Create matrix from file.
M = EigMatR(n, m); // Set matrice dimensions.
vector<EigCooR> triplets;
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).
if (verbose == 3) {
cout << endl << msg << endl;
cout << endl << M << endl;
}
return 0;
}
class arpackEV { // Arpack eigen values / vectors.
public:
vector<complex<double>> val; // Eigen values.
vector<EigVecC> vec; // Eigen vectors.
int nbIt;
double rciTime;
};
template<typename SLV>
int arpackSolve(options const & opt, int const & mode,
EigMatR const & A, EigMatR const & B, SLV & solver, arpackEV & out) {
// Arpack set up.
// Note: all in/out parameters (all but work*) 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 = opt.mag.c_str();
int ido = 0; // First call to arpack.
char const * iMat = "I";
char const * gMat = "G";
char const * bMat = (mode == 1) ? iMat : gMat;
int nbDim = A.rows();
double * resid = new double[nbDim]; for (int n = 0; n < nbDim; n++) resid[n] = 0.; // Avoid "bad" starting vector.
if (opt.restart) {
ifstream rfs("resid.out");
if (rfs.is_open()) {
for (int n = 0; n < nbDim; n++) rfs >> resid[n];
if (opt.verbose >= 2) {
cout << endl;
cout << "resid:" << endl;
for (int n = 0; n < nbDim; n++) cout << resid[n] << endl;
cout << endl;
}
}
}
int ldv = nbDim;
double * v = new double[ldv*opt.nbCV]; for (int n = 0; n < ldv*opt.nbCV; n++) v[n] = 0.; // Avoid "bad" starting vector.
if (opt.restart) {
ifstream vfs("v.out");
if (vfs.is_open()) {
int nbCV = 0; vfs >> nbCV; if (opt.nbCV < nbCV) nbCV = opt.nbCV;
for (int n = 0; n < ldv*nbCV; n++) vfs >> v[n];
if (opt.verbose >= 2) {
cout << endl;
cout << "v:" << endl;
for (int n = 0; n < ldv*nbCV; n++) cout << v[n] << endl;
cout << endl;
}
}
}
int iparam[11];
iparam[0] = 1; // Use exact shifts (=> we'll never have ido == 3).
iparam[2] = opt.maxIt; // Maximum number of iterations.
iparam[3] = 1; // Block size.
iparam[4] = 0; // Number of ev found by arpack.
if (mode == 1) {
iparam[6] = mode;
}
else if (mode == 2 || mode == 3) {
if (mode == 2) { // Regular mode.
iparam[6] = mode;
solver.compute(B);
}
else { // Shift invert mode.
iparam[6] = mode;
if (!opt.shiftImag) {
if (fabs(opt.sigmaReal) < numeric_limits<double>::epsilon()) solver.compute(A);
else solver.compute(A - opt.sigmaReal * B); // Only real shift.
}
else {
complex<double> sigma(opt.sigmaReal, opt.sigmaImag);
EigMatC S = A.cast<complex<double>>() - sigma * B.cast<complex<double>>();
solver.compute(S.real()); // S: shifted matrix is real.
}
}
if(solver.info() != Eigen::Success) {cerr << "Error: decomposition KO - check A and/or B are invertible" << endl; return 1;}
}
else {cerr << "Error: arpack mode must be 1, 2 or 3 - KO" << endl; return 1;}
int ipntr[14];
double * workd = new double[3*nbDim];
int lworkl = opt.symPb ? opt.nbCV*opt.nbCV + 8*opt.nbCV : 3*opt.nbCV*opt.nbCV + 6*opt.nbCV;
lworkl++; // The documentation says "LWORKL must be at least ..."
double * workl = new double[lworkl];
int info = 0; // Use random initial residual vector.
if (opt.restart) info = 1;
// Arpack solve.
do {
// Call arpack.
if (opt.symPb) {
dsaupd_c(&ido, bMat, nbDim, which, opt.nbEV, opt.tol, resid, opt.nbCV, v, ldv, iparam, ipntr, workd, workl, lworkl, &info);
if (info == 1) cerr << "Error: dsaupd - KO: maximum number of iterations taken. Increase --maxIt..." << endl;
if (info == 2) cerr << "Error: dsaupd - KO: no shifts could be applied. Increase --nbCV..." << endl;
if (info == -9) cerr << "Error: dsaupd - KO: starting vector is zero. Retry: play with shift..." << endl;
if (info < 0) {cerr << "Error: dsaupd - KO with info " << info << ", nbIt " << iparam[2] << endl; return 1;}
}
else {
dnaupd_c(&ido, bMat, nbDim, which, opt.nbEV, opt.tol, resid, opt.nbCV, v, ldv, iparam, ipntr, workd, workl, lworkl, &info);
if (info == 1) cerr << "Error: dnaupd - KO: maximum number of iterations taken. Increase --maxIt..." << endl;
if (info == 2) cerr << "Error: dnaupd - KO: no shifts could be applied. Increase --nbCV..." << endl;
if (info == -9) cerr << "Error: dnaupd - KO: starting vector is zero. Retry: play with shift..." << endl;
if (info < 0) {cerr << "Error: dnaupd - KO with info " << info << ", nbIt " << iparam[2] << endl; return 1;}
}
// Reverse Communication Interface: perform actions according to arpack.
auto start = chrono::high_resolution_clock::now();
int xIdx = ipntr[0] - 1; // 0-based (Fortran is 1-based).
int yIdx = ipntr[1] - 1; // 0-based (Fortran is 1-based).
EigMpVR X(workd + xIdx, nbDim); // Arpack provides X.
EigMpVR Y(workd + yIdx, nbDim); // Arpack provides Y.
if (ido == -1) {
if (iparam[6] == 1) {
Y = A * X;
}
else if (iparam[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.
if(solver.info() != Eigen::Success) {cerr << "Error: solve KO - increase --slvMaxIt and/or relax --slvTol, or, change --slv" << endl; return 1;}
}
else if (iparam[6] == 3) {
auto Z = B * X; // Z = B * X.
Y = solver.solve(Z); // Y = (A - sigma * B)^-1 * B * X.
if(solver.info() != Eigen::Success) {cerr << "Error: solve KO - increase --slvMaxIt and/or relax --slvTol, or, change --slv" << endl; return 1;}
}
}
else if (ido == 1) {
if (iparam[6] == 1) {
Y = A * X;
}
else if (iparam[6] == 2) {
Y = A * X;
if (opt.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.
if(solver.info() != Eigen::Success) {cerr << "Error: solve KO - increase --slvMaxIt and/or relax --slvTol, or, change --slv" << endl; return 1;}
}
else if (iparam[6] == 3) {
int zIdx = ipntr[2] - 1; // 0-based (Fortran is 1-based).
EigMpVR Z(workd + zIdx, nbDim); // Arpack provides Z.
Y = solver.solve(Z); // Y = (A - sigma * B)^-1 * B * X.
if(solver.info() != Eigen::Success) {cerr << "Error: solve KO - increase --slvMaxIt and/or relax --slvTol, or, change --slv" << endl; return 1;}
}
}
else if (ido == 2) {
if (iparam[6] == 1) Y = X; // Y = I * X.
else if (iparam[6] == 2) Y = B * X; // Y = B * X.
else if (iparam[6] == 3) Y = B * X; // Y = B * X.
}
else if (ido != 99) {cerr << "Error: unexpected ido " << ido << " - KO" << endl; return 1;}
auto stop = chrono::high_resolution_clock::now();
out.rciTime += chrono::duration_cast<chrono::milliseconds>(stop - start).count()/1000.;
} while (ido != 99);
// Get arpack results (computed eigen values and vectors).
out.nbIt = iparam[2]; // Actual number of iterations.
bool rvec = true;
char const * howmny = "A";
int * select = new int[opt.nbCV]; for (int n = 0; n < opt.nbCV; n++) select[n] = 1;
int const nbZ = nbDim*(opt.nbEV+1); // Caution: opt.nbEV+1 for dneupd.
double * z = new double[nbZ]; for (int n = 0; n < nbZ; n++) z[n] = 0.;
int ldz = nbDim;
if (opt.symPb) {
double * d = new double[opt.nbEV]; for (int k = 0; k < opt.nbEV; k++) d[k] = 0.;
dseupd_c(rvec, howmny, select, d, z, ldz, opt.sigmaReal,
bMat, nbDim, which, opt.nbEV, opt.tol, resid, opt.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;}
// Arpack compute the whole spectrum.
int nbConv = iparam[4];
out.val.reserve(nbConv);
for (int i = 0; d && i < nbConv; i++) {
complex<double> lambda(d[i], 0.);
out.val.push_back(lambda);
if (out.val.size() == (size_t) opt.nbEV) break; // If more converged than requested, likely not accurate (check KO).
}
out.vec.reserve(nbConv);
for (int i = 0; z && i < nbConv; i++) {
EigVecR V = EigMpVR(z + i*nbDim, nbDim);
out.vec.push_back(V.cast<complex<double>>());
if (out.vec.size() == (size_t) opt.nbEV) break; // If more converged than requested, likely not accurate (check KO).
}
if (d) {delete [] d; d = NULL;}
}
else {
double * dr = new double[opt.nbEV+1]; for (int k = 0; k < opt.nbEV+1; k++) dr[k] = 0.;
double * di = new double[opt.nbEV+1]; for (int k = 0; k < opt.nbEV+1; k++) di[k] = 0.;
double * workev = new double[3*opt.nbCV];
dneupd_c(rvec, howmny, select, dr, di, z, ldz, opt.sigmaReal, opt.sigmaImag, workev,
bMat, nbDim, which, opt.nbEV, opt.tol, resid, opt.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;}
// Arpack compute only half of the spectrum.
int nbConv = iparam[4];
out.val.reserve(nbConv);
for (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]);
out.val.push_back(lambda);
if (out.val.size() == (size_t) opt.nbEV) break; // If more converged than requested, likely not accurate (check KO).
// Deduce second half of the spectrum.
out.val.push_back(complex<double>(lambda.real(), -1.*lambda.imag()));
if (out.val.size() == (size_t) opt.nbEV) break; // If more converged than requested, likely not accurate (check KO).
}
out.vec.reserve(nbConv);
for (int i = 0; z && i <= nbConv/2; i++) { // Scan half spectrum.
// Get first half of the spectrum.
EigVecR Vr = EigMpVR(z + (2*i+0)*nbDim, nbDim); // Real part.
EigVecR Vi = EigMpVR(z + (2*i+1)*nbDim, nbDim); // Imaginary part.
complex<double> imag(0., 1.);
EigVecC V = Vr.cast<complex<double>>() + imag * Vi.cast<complex<double>>();
out.vec.push_back(V);
if (out.vec.size() == (size_t) opt.nbEV) break; // If more converged than requested, likely not accurate (check KO).
// Deduce second half of the spectrum.
V = Vr.cast<complex<double>>() - imag * Vi.cast<complex<double>>();
out.vec.push_back(V);
if (out.vec.size() == (size_t) opt.nbEV) break; // If more converged than requested, likely not accurate (check KO).
}
if (workev) {delete [] workev; workev = NULL;}
if (dr) {delete [] dr; dr = NULL;}
if (di) {delete [] di; di = NULL;}
}
ofstream rfs("resid.out"); for (int n = 0; n < nbDim; n++) rfs << resid[n] << endl;
ofstream vfs("v.out"); vfs << opt.nbCV << endl; for (int n = 0; n < ldv*opt.nbCV; n++) vfs << v[n] << endl;
// Clean.
if (z) {delete [] z; z = NULL;}
if (select) {delete [] select; select = NULL;}
if (workl) {delete [] workl; workl = NULL;}
if (workd) {delete [] workd; workd = NULL;}
if (v) {delete [] v; v = NULL;}
if (resid) {delete [] resid; resid = NULL;}
return 0;
}
int checkArpackEigVec(options const & opt, EigMatR & A, EigMatR const & B, arpackEV const & out) {
// Check eigen vectors.
for (size_t i = 0; i < out.vec.size(); i++) {
EigVecC V = out.vec[i];
complex<double> lambda = out.val[i];
if (opt.verbose >= 1) {
cout << endl;
cout << "eigen value " << setw(3) << i << ": " << lambda << endl;
if (opt.verbose >= 2) {
cout << endl;
cout << "eigen vector " << setw(3) << i << " (norm " << V.norm() << "): " << endl;
cout << endl << V << endl;
}
}
if (opt.check) {
EigVecC left = A.cast<complex<double>>() * V;
EigVecC right = opt.stdPb ? V : B.cast<complex<double>>() * V;
right *= lambda;
EigVecC diff = left - right;
if (diff.norm() > sqrt(opt.tol)) {
cerr << endl << "Error: bad eigen vector " << setw(3) << i << " (norm " << V.norm() << "):" << endl;
cerr << endl << V << endl;
cerr << endl << "Error: left side (A*V - norm " << left.norm() << "):" << endl;
cerr << endl << left << endl;
cerr << endl << "Error: right side (lambda*" << (opt.stdPb ? "" : "B*") << "V - norm " << right.norm() << "):" << endl;
cerr << endl << right << endl;
cerr << endl << "Error: diff (norm " << diff.norm() << ", sqrt(tol) " << sqrt(opt.tol) << "):" << endl;
cerr << endl << diff << endl;
return 1;
}
else {
if (opt.verbose >= 1) {
cout << endl << "eigen value/vector " << setw(3) << i << ": check OK";
cout << ", diff (norm " << diff.norm() << ", sqrt(tol) " << sqrt(opt.tol) << ")" << endl;
}
}
}
}
return 0;
}
template<typename SLV>
int arpackSolve(options const & opt, EigMatR & A, EigMatR const & B,
SLV & solver, arpackEV & out) {
// If needed, transform the initial problem into a new one that arpack can handle.
auto eps = numeric_limits<double>::epsilon();
bool shiftReal = (opt.shiftReal && fabs(opt.sigmaReal) > eps) ? true : false;
bool shiftImag = (opt.shiftImag && fabs(opt.sigmaImag) > eps) ? true : false;
bool backTransform = false;
int mode = 0;
if (opt.stdPb) {
mode = 1;
if (shiftReal && !shiftImag) {
EigMatR I(A.rows(), A.cols());
I.setIdentity();
A -= opt.sigmaReal*I;
backTransform = true;
}
}
else {
mode = 2;
if (shiftReal || shiftImag) mode = 3;
}
// Solve the problem.
if (opt.verbose >= 1) {
cout << endl;
cout << "ARP: mode " << mode;
cout << ", nbDim " << A.rows();
cout << ", backTransform " << (backTransform ? "yes" : "no") << endl;
}
int rc = arpackSolve<SLV>(opt, mode, A, B, solver, out);
if (rc != 0) {cerr << "Error: arpack solve KO" << endl; return rc;}
if (opt.verbose >= 1) {
cout << endl;
cout << "ARP: nbEV found " << out.val.size();
cout << ", nbIt " << out.nbIt << endl;
}
// If needed, transform back the arpack problem into the initial problem.
if (backTransform) {
for (size_t i = 0; i < out.val.size(); i++) out.val[i] += opt.sigmaReal;
EigMatR I(A.rows(), A.cols());
I.setIdentity();
A += opt.sigmaReal*I; // For later checks.
}
// Check.
return checkArpackEigVec(opt, A, B, out);
}
template<typename SLV>
int arpackSolve(options & opt, SLV & solver) {
// Read A.
EigMatR A;
int rc = readMatrixMarket(opt.fileA, A, opt.verbose, "A:");
if (rc != 0) {cerr << "Error: read A KO" << endl; return rc;}
// Read B.
EigMatR B;
if (!opt.stdPb) {
rc = readMatrixMarket(opt.fileB, B, opt.verbose, "B:");
if (rc != 0) {cerr << "Error: read B KO" << endl; return rc;}
}
// Check A-B compatibility.
if (!opt.stdPb) {
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;}
}
if (opt.nbCV > A.cols()) opt.nbCV = A.cols(); // Cut-off.
// Arpack solve.
arpackEV out;
out.rciTime = 0.;
auto start = chrono::high_resolution_clock::now();
rc = arpackSolve<SLV>(opt, A, B, solver, out);
if (rc != 0) {cerr << "Error: arpack solve KO" << endl; return rc;}
auto stop = chrono::high_resolution_clock::now();
double fullTime = chrono::duration_cast<chrono::milliseconds>(stop - start).count()/1000.;
cout << endl;
cout << "OUT: nb EV found " << out.val.size() << ", nb iterations " << out.nbIt << endl;
cout << "OUT: full time " << fullTime << " s, RCI time " << out.rciTime << " s" << endl;
return 0;
}
int main(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.
if (opt.slv == "BiCG") {
EigBiCG solver;
solver.setTolerance(opt.slvTol);
solver.setMaxIterations(opt.slvMaxIt);
rc = arpackSolve<EigBiCG>(opt, solver);
}
else if (opt.slv == "CG") {
EigCG solver;
solver.setTolerance(opt.slvTol);
solver.setMaxIterations(opt.slvMaxIt);
rc = arpackSolve<EigCG>(opt, solver);
}
else if (opt.slv == "LU") {
EigSLU solver;
rc = arpackSolve<EigSLU>(opt, solver);
}
else if (opt.slv == "QR") {
EigSQR solver;
rc = arpackSolve<EigSQR>(opt, solver);
}
else {cerr << "Error: unknown solver - KO" << endl; return 1;}
if (rc != 0) {cerr << "Error: arpack solve KO" << endl; return rc;}
return 0;
}
// Local Variables:
// mode: c++
// c-file-style:"stroustrup"
// show-trailing-whitespace: t
// End:
/* vim: set sw=2 ts=2 et smartindent :*/
+60
View File
@@ -0,0 +1,60 @@
#!/bin/bash -eu
for symPb in "--A As.mtx" "--nonSymPb --A An.mtx"
do
for genPb in "" "--genPb"
do
for smallMag in "" "--mag SM --noCheck" # SM is known to be difficult to converge.
do
export shiftOpt=""
if [[ "$symPb" == *nonSymPb* ]]; then
if [[ "$genPb" == *genPb* ]]; then
export shiftOpt="--shiftReal 2.5 --shiftImag 2.5 --tol 0.5" # Relax tolerance, tricky to converge.
else
export shiftOpt="--shiftReal 100.0 --shiftImag 100.0"
fi
else
if [[ "$genPb" == *genPb* ]]; then
export shiftOpt="--shiftReal 50.0"
else
export shiftOpt="--shiftReal 100.0"
fi
fi
for shiftRI in "" "$shiftOpt"
do
for invert in "" "--invert"
do
for tol in "" "--tol 1.e-5"
do
for slv in "" "--slv CG" "--slv LU" "--slv QR"
do
export extraGenPb=""
if [[ "$genPb" == *genPb* ]]; then
export extraGenPb="$shiftOpt" # Force shift if genPb.
fi
# Run arpackmm: use --nbCV 6 to ease convergence, and, --verbose 3 for debug.
export CMD="./arpackmm $symPb $genPb $smallMag $shiftRI $invert $tol $slv $extraGenPb --nbCV 6 --verbose 3"
echo "$CMD"
eval "$CMD"
echo ""
echo "========================================================================================"
echo ""
# Run arpackmm: re-run with restart.
export CMD="$CMD --restart"
echo "$CMD"
eval "$CMD"
echo ""
echo "========================================================================================"
echo ""
done
done
done
done
done
done
done
echo "OK"
+9
View File
@@ -1,2 +1,11 @@
SUBDIRS = BAND COMPLEX NONSYM SIMPLE SVD SYM
if ICBEXMM
SUBDIRS += MATRIX_MARKET
endif
DIST_SUBDIRS = BAND COMPLEX NONSYM SIMPLE SVD SYM
if ICBEXMM
DIST_SUBDIRS += MATRIX_MARKET
endif
EXTRA_DIST = README
+2
View File
@@ -15,6 +15,8 @@ Important Features:
* Routines for The Singular Value Decomposition.
* Example driver routines that may be used as templates to implement numerous
Shift-Invert strategies for all problem types, data types and precision.
* arpackmm: utility to test arpack with matrix market files.
Note: to run this utility, you need the eigen library (to handle RCI).
This project started as a joint project between Debian, Octave and Scilab in order to
provide a common and maintained version of arpack.
+37 -1
View File
@@ -66,8 +66,40 @@ AC_ARG_ENABLE([icb],
[AS_VAR_SET([enable_icb], [$enableval])],
[AS_VAR_SET([enable_icb], [no])])
AM_CONDITIONAL([ICB], [test x"$enable_icb" != x"no"])
dnl See if compiling matrix market example based on ICB
AC_ARG_ENABLE([icb-exmm],
[AC_HELP_STRING([--enable-icb-exmm],
[matrix market example based on ISO_C_BINDING])],
[
AS_VAR_SET([enable_icb_exmm], [$enableval])
AS_VAR_SET([enable_icb], [$enableval])
],
[AS_VAR_SET([enable_icb_exmm], [no])])
AM_CONDITIONAL([ICBEXMM], [test x"$enable_icb_exmm" != x"no"])
if test x"$enable_icb_exmm" != x"no"; then
PKG_CHECK_MODULES([EIGEN3], [eigen3 >= 3.2]) dnl Go get eigen3.pc
AC_SUBST([EIGEN3_CFLAGS]) dnl Define EIGEN3_CFLAGS in Makefile.am
dnl TODO: How to pass /path/to/eigen from EIGEN3_CFLAGS to AC_CHECK_HEADERS ?...
dnl AC_CHECK_HEADERS(
dnl [eigen3/Eigen/Sparse], [],
dnl [AC_MSG_ERROR([Error: eigen3/Eigen/Sparse not found])]
dnl )
dnl AC_CHECK_HEADERS(
dnl [eigen3/Eigen/IterativeLinearSolvers], [],
dnl [AC_MSG_ERROR([Error: eigen3/Eigen/IterativeLinearSolvers not found])]
dnl )
dnl AC_CHECK_HEADERS(
dnl [eigen3/Eigen/SparseLU], [],
dnl [AC_MSG_ERROR([Error: eigen3/Eigen/SparseLU not found])]
dnl )
dnl AC_CHECK_HEADERS(
dnl [eigen3/Eigen/SparseQR], [],
dnl [AC_MSG_ERROR([Error: eigen3/Eigen/SparseQR not found])]
dnl )
fi
AM_CONDITIONAL([ICB], [test x"$enable_icb" != x"no"])
if test x"$enable_icb" != x"no"; then
AC_LANG_PUSH([Fortran])
AC_MSG_CHECKING([for iso_c_binding module compilation])
@@ -202,6 +234,9 @@ AC_CONFIG_FILES([
if test x"$enable_icb" != x"no"; then
AC_CONFIG_FILES([ICB/Makefile])
fi
if test x"$enable_icb_exmm" != x"no"; then
AC_CONFIG_FILES([EXAMPLES/MATRIX_MARKET/Makefile])
fi
if test x"$enable_mpi" != x"no"; then
AC_CONFIG_FILES([
PARPACK/Makefile
@@ -235,6 +270,7 @@ CXX : $CXX
CXXFLAGS : $CXXFLAGS
BLAS : $BLAS_LIBS
LAPACK : $LAPACK_LIBS
EIGEN : $EIGEN3_CFLAGS
--------------------------------------------------
Configuration OK
--------------------------------------------------