arpackmm: utility to test arpack with matrix market files. (#157)
This commit is contained in:
committed by
Sylvestre Ledru
parent
8840cfdf43
commit
2c1f6ebb5b
@@ -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
@@ -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:
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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.
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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 :*/
|
||||
Executable
+60
@@ -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"
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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
|
||||
--------------------------------------------------
|
||||
|
||||
Reference in New Issue
Block a user