diff --git a/.github/workflows/testSDP.yml b/.github/workflows/testSDP.yml new file mode 100644 index 000000000..3f6d11f9d --- /dev/null +++ b/.github/workflows/testSDP.yml @@ -0,0 +1,30 @@ +name: gcc-test-SDP + +on: [push, pull_request] + +jobs: + build: + name: ${{ matrix.compilers }} + strategy: + fail-fast: false + matrix: + compilers: [g++-4.8, g++-5, g++-6, g++-7, g++-8, g++-9] + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v1 + - run: sudo apt-get update || true; + sudo apt-get install ${{ matrix.compilers }} lp-solve; + sudo apt install gfortran libopenblas-dev liblapack-dev libarpack2-dev; + sudo apt install git; + sudo apt install libpthread-stubs0-dev; + git clone https://github.com/m-reuter/arpackpp; + cd arpackpp; + ./install-openblas.sh; + ./install-arpack-ng.sh; + cp -r external ../test/SDP; + cd ../; + rm -rf buildSDP; + mkdir buildSDP; + cd buildSDP; + cmake -D CMAKE_CXX_COMPILER=${{ matrix.compilers }} ../test/SDP; + make; diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 563e2f5fd..f6715a817 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -38,10 +38,13 @@ else () include_directories (BEFORE ../include/volume) include_directories (BEFORE ../include) include_directories (BEFORE ../include/convex_bodies) + include_directories (BEFORE ../include/random_walks) include_directories (BEFORE ../include/annealing) include_directories (BEFORE ../include/samplers) include_directories (BEFORE ../include/lp_oracles) include_directories (BEFORE ../include/misc) + include_directories (BEFORE ../include/optimization) + include_directories (BEFORE ../include/convex_bodies/spectrahedra) # for Eigen diff --git a/examples/spectrahedra/CMakeLists.txt b/examples/spectrahedra/CMakeLists.txt index 0652983c3..5fb52b24b 100644 --- a/examples/spectrahedra/CMakeLists.txt +++ b/examples/spectrahedra/CMakeLists.txt @@ -5,8 +5,74 @@ # Licensed under GNU LGPL.3, see LICENCE file -add_executable (readWriteSdpaFile readWriteSdpaFile.cpp) +add_executable (read_write_sdpa_file read_write_sdpa_file.cpp) +# Find LAPACK and BLAS +# OPENBLAS or ( ( SystemOpenblas or BLAS) and LAPACK) +## prefer local openblas +find_library(OPENBLAS_LIB openblas PATHS external NO_DEFAULT_PATH) +IF (OPENBLAS_LIB) + set(LAPACK_LIBRARIES ${OPENBLAS_LIB}) #local openblas has lapack build in + find_package( Threads REQUIRED ) + set(LAPACK_LIBRARIES ${LAPACK_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT}) + message( STATUS "LAPACK_LIBRARIES: ${LAPACK_LIBRARIES}" ) + + + # ARPACK + find_library(ARPACK_LIB arpack PATHS external NO_DEFAULT_PATH) + IF (ARPACK_LIB) + message( STATUS "ARPACK_LIB found: ${ARPACK_LIB}" ) + + # Query gfortran to get the libgfortran path + FIND_LIBRARY(GFORTRAN_LIB NAMES libgfortran.so PATHS /usr/lib/gcc/x86_64-linux-gnu/8/) + + # Find libgfortran (static preferred) + # Query gfortran to get the libgfortran path + IF (CMAKE_Fortran_COMPILER) + EXECUTE_PROCESS(COMMAND ${CMAKE_Fortran_COMPILER} -print-file-name=libgfortran.a + OUTPUT_VARIABLE _libgfortran_path + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + IF (NOT EXISTS ${_libgfortran_path}) + EXECUTE_PROCESS(COMMAND ${CMAKE_Fortran_COMPILER} -print-file-name=libgfortran.so + OUTPUT_VARIABLE _libgfortran_path + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + ENDIF () + ENDIF() + + IF(EXISTS ${_libgfortran_path}) + get_filename_component(GFORTRAN_PATH ${_libgfortran_path} PATH) + find_library(GFORTRAN_LIB gfortran PATHS ${GFORTRAN_PATH}) + ELSE() + # if libgfortran wasn't found at this point, the installation is probably broken + # Let's try to find the library nonetheless. + FIND_LIBRARY(GFORTRAN_LIB gfortran) + ENDIF() + + + + IF (GFORTRAN_LIB) + message( STATUS "GFORTRAN_LIB found: ${GFORTRAN_LIB}" ) + + add_executable (boltzmann_hmc_walk boltzmann_hmc_walk.cpp) + TARGET_LINK_LIBRARIES(boltzmann_hmc_walk ${ARPACK_LIB} ${LAPACK_LIBRARIES} ${GFORTRAN_LIB}) + + add_executable (solve_sdp solve_sdp.cpp) + TARGET_LINK_LIBRARIES(solve_sdp ${ARPACK_LIB} ${LAPACK_LIBRARIES} ${GFORTRAN_LIB}) + + ELSE() + MESSAGE(STATUS "gfortran is required but it could not be found") + ENDIF () + + + ELSE() + message(FATAL_ERROR "This program requires the arpack library, and will not be compiled.") + ENDIF() + +ELSE() + message(FATAL_ERROR "This program requires the openblas library, and will not be compiled.") +ENDIF() diff --git a/examples/spectrahedra/README.md b/examples/spectrahedra/README.md index 9c8f6a4e9..014f5de89 100644 --- a/examples/spectrahedra/README.md +++ b/examples/spectrahedra/README.md @@ -1,5 +1,14 @@ # Examples for Spectrahedra +## Table of contents +1. [Compilation](#compilation) + 1. [Dependencies](#dependencies) +2. [Examples](#examples) + 1. [Read/write SDPA format files - read_write_sdpa_file.cpp](#readwrite-sdpa-format-files---read_write_sdpa_filecpp) + 2. [Sample with HMC, Boltzmann distribution - boltzmann_hmc_walk.cpp](#sample-with-hmc-boltzmann-distribution---boltzmann_hmc_walkcpp) + 3. [Randomized SDP Solver - solve_sdp.cpp](#randomized-sdp-solver---solve_sdpcpp) + + ## Compilation In folder examples, first run cmake, to create the makefile: @@ -13,17 +22,48 @@ Then, in folder examples/spectrahedra compile using the makefile: make ``` -## List of examples -- Example 1: Read/write SDPA format files +### Dependencies +To compile some programs in this folder, we need the libraries openblas, lapack and arpack. If you want to compile +using the provided cmakelists file, follow the next steps to install and link them. + + +First we will need a [Fortran compiler](https://gcc.gnu.org/wiki/GFortran) for GCC. In linux: +```bash +sudo apt install gfortran +``` + +In `CMakeLists.txt` in folder `examples/spectrahedra` we use as the default path for `libgfortran.so` the ``/usr/lib/gcc/x86_64-linux-gnu/8/``. Of course, you could give a different path to `libgfortran.so`. + +Then we can install the openblas, lapack and arpack libraries (lapack is included in openblas). +In the folder "examples", clone this repo: + +```bash +git clone https://github.com/m-reuter/arpackpp +cd arpackcpp +``` + +It has two scripts that should easily install the libraries: + +```bash +./install-openblas.sh +./install-arpack-ng.sh +``` + +You can find in the [repo](https://github.com/m-reuter/arpackpp/blob/master/INSTALL.md) detailed +info on installing openblas and arpack. + +Finally copy the folder external back in folder examples/spectrahedra: + +
## Examples -### Example 1: Read/write SDPA format files +### Read/write SDPA format files - read_write_sdpa_file.cpp In this example, we will read a semidefinite program from a SDPA format input file, print it and then write it to a new SDPA format file. Run the example with: ```bash -./readWriteSdpaFile +./read_write_sdpa_file ``` The input file is data/sdp_n2m3.txt. It contains a semidefinite program in SDPA format. A semidefinite program @@ -62,4 +102,84 @@ It represents a spectrahedron in 2 dimensions, described by a linear matrix ineq - 0 -2 1: The second row of A0 - 0 1 -2: The third row of A0 - 1 -0 -0: The first row of A1 -- and so on, till all 3 matrices are defined \ No newline at end of file +- and so on, till all 3 matrices are defined + + +### Sample with HMC, Boltzmann distribution - boltzmann_hmc_walk.cpp + +In this example, we will sample a spectrahedron under the Boltsmann distribution e^(-c*x/T), using +the hamiltonian monte carlo random walk with reflections. We will read the spectrahedron as +in [readWriteSdpaFile.cpp](#readwrite-sdpa-format-files---readwritesdpafilecpp). Run the example with: + +```bash +./boltzmann_hmc_walk +``` + +#### Code Explanation +In boltzmannHmcWalk.cpp, to use the random walk first we need to declare some parameters: + +```bash +HmcWalkSettings settings(walkLength, randomNumberGenerator, objFunction, temperature, diameter); +``` + +- walkLength: how many points the walk will "burn" before returning a sample +- randomNumberGenerator: a class that generates random numbers +- objFunction: the vector c in the boltzmann distribution e^(-c*x/T) +- temperature: T in e^(-c*x/T) +- diameter: diameter of the spectrahedron; can estimate it with a heuristic - method of class Spectrahedron + +and then we can sample the spectrahedron + +```bash +HmcWalk hmcWalk(settings); +hmcWalk.apply(spectrahedron, initialPoint, pointsNum, points); +``` + +- spectrahedron: instance of class Spectrahedron +- initialPoint: an interior point in the spectrahedron +- pointsNum: how many points to sample +- points: a list to return the samples + + +### Randomized SDP Solver - solve_sdp.cpp + +In this example, we will solve a semidefinite program. We will read the program +as in [read_write_sdpa_file.cpp](#readwrite-sdpa-format-files---read_write_sdpa_filecpp). Run the example with: + +```bash +./solve_sdp +``` + +#### Code Explanation +To use the solver, first we declare some parameters: + +```bash +SimulatedAnnealingSettings settings(rel_error); +``` + +Actually, we can further customize the algorithm. The full settings definition is: + +```bash +SimulatedAnnealingSettings settings(rel_error, walkLength, maxNumSteps, k) +``` + +- rel_error: The desired relative error. +- walkLength: Default and recommended is 1. This solver uses the [HMC random walk](#sample-with-hmc-boltzmann-distribution---boltzmann_hmc_walkcpp). + How many points the walk will "burn" before returning a sample. +- maxNumSteps: Default is -1 (infinite). How many steps we will allow the algorithm. +- k: Default is 0.5. Lower values may achieve faster convergence. + +Next we can solve the program: + +```bash +NT min = solve_sdp(spectrahedron, objFunction, settings, initialPoint, sol ,verbose); +``` + +- spectrahedron: Instance of class Spectrahedron (a linear matrix inequality). +- objFunction: The objective function of the program. +- Settings: As above. +- initialPoint: An interior point in the spectrahedron. +- min: The estimated minimum value +- sol: At which point in the spectrahedron (returned by the solver) +- verbose: If true, print useful information. + diff --git a/examples/spectrahedra/boltzmann_hmc_walk.cpp b/examples/spectrahedra/boltzmann_hmc_walk.cpp new file mode 100644 index 000000000..7ee263d33 --- /dev/null +++ b/examples/spectrahedra/boltzmann_hmc_walk.cpp @@ -0,0 +1,83 @@ +// VolEsti (volume computation and sampling library) + +// Copyright (c) 20012-2018 Vissarion Fisikopoulos +// Copyright (c) 2018 Apostolos Chalkis + +//Contributed and/or modified by Repouskos Panagiotis, as part of Google Summer of Code 2019 program. + +// Licensed under GNU LGPL.3, see LICENCE file + +// This examples illustrates how to sample a spectrahedron under the Boltzmann distribution with +// HMC random walk. It will read the spectrahedron from data/sdp_n2m3.txt. + +//#define VOLESTI_DEBUG + + +#include +#include + +#include "random.hpp" +#include "Eigen/Eigen" +#include "cartesian_geom/cartesian_kernel.h" +#include "convex_bodies/spectrahedra/spectrahedron.h" +#include "SDPAFormatManager.h" +#include "random_walks/boltzmann_hmc_walk.hpp" + +typedef double NT; +typedef Eigen::Matrix VT; +typedef Eigen::Matrix MT; +typedef Cartesian Kernel; +typedef typename Kernel::Point Point; +typedef Spectrahedron SPECTRAHEDRON; +typedef BoostRandomNumberGenerator RNGType; +typedef BoltzmannHMCWalk::Walk HmcWalk; +typedef BoltzmannHMCWalk::Walk::Settings HmcWalkSettings; + + +int main(int argc, char* argv[]) { + std::string fileName("data/sdp_n2m3.txt"); + std::string outputFile("new_sdp_n2m3.txt"); + + SPECTRAHEDRON spectrahedron; + Point objFunction; + + // read the spectrahedron + // open a stream to read the input file + std::ifstream in; + in.open(fileName, std::ifstream::in); + + // read the file + SdpaFormatManager sdpaFormatManager; + sdpaFormatManager.loadSDPAFormatFile(in, spectrahedron, objFunction); + + // We will need an initial interior point. In this + // spectrahedron the origin (zero point) is interior + Point initialPoint(spectrahedron.getLMI().dimension()); + + // required parameters for the random walk + int walkLength = 5; + RNGType randomNumberGenerator(spectrahedron.getLMI().dimension()); // this class provides random numbers + NT temperature = 1; + + // estimate the diameter of the body + int pointsNum = 10; + NT diameter = spectrahedron.estimateDiameter(pointsNum, initialPoint); + + // declare the settings and + HmcWalkSettings settings(walkLength, randomNumberGenerator, objFunction, temperature, diameter); + + // declare the random walk + HmcWalk hmcWalk(settings); + + // sample three points from the spectrahedron + pointsNum = 3; + std::list points; + hmcWalk.apply(spectrahedron, initialPoint, pointsNum, points); + + // print sampled points + for (Point point : points) + point.print(); + + return 0; +} + diff --git a/examples/spectrahedra/readWriteSdpaFile.cpp b/examples/spectrahedra/readWriteSdpaFile.cpp index a31137b53..f71b448cf 100644 --- a/examples/spectrahedra/readWriteSdpaFile.cpp +++ b/examples/spectrahedra/readWriteSdpaFile.cpp @@ -15,6 +15,7 @@ #include "vector" #include #include "cartesian_geom/cartesian_kernel.h" +#include "random.hpp" #include "spectrahedron.h" #include "SDPAFormatManager.h" #include "string" diff --git a/examples/spectrahedra/read_write_sdpa_file.cpp b/examples/spectrahedra/read_write_sdpa_file.cpp new file mode 100644 index 000000000..2f103b6de --- /dev/null +++ b/examples/spectrahedra/read_write_sdpa_file.cpp @@ -0,0 +1,66 @@ +// VolEsti (volume computation and sampling library) + +// Copyright (c) 20012-2018 Vissarion Fisikopoulos +// Copyright (c) 2018 Apostolos Chalkis + +//Contributed and/or modified by Repouskos Panagiotis, as part of Google Summer of Code 2019 program. + +// Licensed under GNU LGPL.3, see LICENCE file + +// This examples illustrates how to read and write SDPA format files. +// It will read a semidefinite program from data/sdp_n2m3.txt, print it and then write it to a new file + +#define VOLESTI_DEBUG + +#include +#include + +#include "random.hpp" +#include "Eigen/Eigen" +#include "cartesian_geom/cartesian_kernel.h" +#include "convex_bodies/spectrahedra/spectrahedron.h" +#include "SDPAFormatManager.h" + +typedef double NT; +typedef Eigen::Matrix VT; +typedef Eigen::Matrix MT; +typedef Cartesian Kernel; +typedef typename Kernel::Point Point; +typedef Spectrahedron SPECTRAHEDRON; + + +int main(int argc, char* argv[]) { + std::string fileName("data/sdp_n2m3.txt"); + std::string outputFile("new_sdp_n2m3.txt"); + + SPECTRAHEDRON spectrahedron; + Point objFunction; + + // read the semidefinite program + // and create a vector (objective function) and a spectrahedron + + // open a stream to read the input file + std::ifstream in; + in.open(fileName, std::ifstream::in); + + // read the file + SdpaFormatManager sdpaFormatManager; + sdpaFormatManager.loadSDPAFormatFile(in, spectrahedron, objFunction); + + // print the contents + std::cout << "The objective Function:\n\n"; + objFunction.print(); + std::cout << "\n\nThe matrices of the spectrahedron:\n\n"; + spectrahedron.getLMI().print(); + + // open a stream to an output file + std::filebuf fb; + fb.open(outputFile, std::ios::out); + std::ostream os(&fb); + + // write a SDPA format file using the data we read before + sdpaFormatManager.writeSDPAFormatFile(os, spectrahedron, objFunction); + + return 0; +} + diff --git a/examples/spectrahedra/solve_sdp.cpp b/examples/spectrahedra/solve_sdp.cpp new file mode 100644 index 000000000..590c64115 --- /dev/null +++ b/examples/spectrahedra/solve_sdp.cpp @@ -0,0 +1,72 @@ +// VolEsti (volume computation and sampling library) + +// Copyright (c) 20012-2018 Vissarion Fisikopoulos +// Copyright (c) 2018 Apostolos Chalkis + +//Contributed and/or modified by Repouskos Panagiotis, as part of Google Summer of Code 2019 program. + +// Licensed under GNU LGPL.3, see LICENCE file + +// This examples illustrates how to solve a semidefinite program. +// It will read a semidefinite program from data/sdp_n2m3.txt, solve it and print its solution (minimal value). + + +//#define VOLESTI_DEBUG +#include +#include + +#include "random.hpp" +#include "Eigen/Eigen" +#include "cartesian_geom/cartesian_kernel.h" +#include "convex_bodies/spectrahedra/spectrahedron.h" +#include "SDPAFormatManager.h" +#include "optimization/simulated_annealing.hpp" + + +typedef double NT; +typedef Eigen::Matrix VT; +typedef Eigen::Matrix MT; +typedef Cartesian Kernel; +typedef typename Kernel::Point Point; +typedef Spectrahedron SPECTRAHEDRON; + + +int main(int argc, char* argv[]) { + std::string fileName("data/sdp_n2m3.txt"); + std::string outputFile("new_sdp_n2m3.txt"); + + SPECTRAHEDRON spectrahedron; + Point objFunction; + + // read the spectrahedron + // open a stream to read the input file + std::ifstream in; + in.open(fileName, std::ifstream::in); + + // read the file + SdpaFormatManager sdpaFormatManager; + sdpaFormatManager.loadSDPAFormatFile(in, spectrahedron, objFunction); + + // We will need an initial interior point. In this + // spectrahedron the origin (zero point) is interior + Point initialPoint(spectrahedron.getLMI().dimension()); + + // First some parameters for the solver + // desired relative error + NT rel_error = 0.001; + + // Declare settings + SimulatedAnnealingSettings settings(rel_error); + + // solve the program + Point sol; + bool verbose = true; + NT min = solve_sdp(spectrahedron, objFunction, settings, initialPoint, sol ,verbose); + + // print solution + std::cout << min << "\n" << "point: "; + sol.print(); + + return 0; +} + diff --git a/external/Spectra/include/Spectra/GenEigsBase.h b/external/Spectra/include/Spectra/GenEigsBase.h new file mode 100644 index 000000000..19b12c158 --- /dev/null +++ b/external/Spectra/include/Spectra/GenEigsBase.h @@ -0,0 +1,479 @@ +// Copyright (C) 2018-2019 Yixuan Qiu +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at https://mozilla.org/MPL/2.0/. + +#ifndef GEN_EIGS_BASE_H +#define GEN_EIGS_BASE_H + +#include +#include // std::vector +#include // std::abs, std::pow, std::sqrt +#include // std::min, std::copy +#include // std::complex, std::conj, std::norm, std::abs +#include // std::invalid_argument + +#include "Util/TypeTraits.h" +#include "Util/SelectionRule.h" +#include "Util/CompInfo.h" +#include "Util/SimpleRandom.h" +#include "MatOp/internal/ArnoldiOp.h" +#include "LinAlg/UpperHessenbergQR.h" +#include "LinAlg/DoubleShiftQR.h" +#include "LinAlg/UpperHessenbergEigen.h" +#include "LinAlg/Arnoldi.h" + +namespace Spectra { + + +/// +/// \ingroup EigenSolver +/// +/// This is the base class for general eigen solvers, mainly for internal use. +/// It is kept here to provide the documentation for member functions of concrete eigen solvers +/// such as GenEigsSolver and GenEigsRealShiftSolver. +/// +template < typename Scalar, + int SelectionRule, + typename OpType, + typename BOpType > +class GenEigsBase +{ +private: + typedef Eigen::Index Index; + typedef Eigen::Matrix Matrix; + typedef Eigen::Matrix Vector; + typedef Eigen::Array Array; + typedef Eigen::Array BoolArray; + typedef Eigen::Map MapMat; + typedef Eigen::Map MapVec; + typedef Eigen::Map MapConstVec; + + typedef std::complex Complex; + typedef Eigen::Matrix ComplexMatrix; + typedef Eigen::Matrix ComplexVector; + + typedef ArnoldiOp ArnoldiOpType; + typedef Arnoldi ArnoldiFac; + +protected: + OpType* m_op; // object to conduct matrix operation, + // e.g. matrix-vector product + const Index m_n; // dimension of matrix A + const Index m_nev; // number of eigenvalues requested + const Index m_ncv; // dimension of Krylov subspace in the Arnoldi method + Index m_nmatop; // number of matrix operations called + Index m_niter; // number of restarting iterations + + ArnoldiFac m_fac; // Arnoldi factorization + + ComplexVector m_ritz_val; // Ritz values + ComplexMatrix m_ritz_vec; // Ritz vectors + ComplexVector m_ritz_est; // last row of m_ritz_vec + +private: + BoolArray m_ritz_conv; // indicator of the convergence of Ritz values + int m_info; // status of the computation + + const Scalar m_near_0; // a very small value, but 1.0 / m_near_0 does not overflow + // ~= 1e-307 for the "double" type + const Scalar m_eps; // the machine precision, ~= 1e-16 for the "double" type + const Scalar m_eps23; // m_eps^(2/3), used to test the convergence + + // Real Ritz values calculated from UpperHessenbergEigen have exact zero imaginary part + // Complex Ritz values have exact conjugate pairs + // So we use exact tests here + static bool is_complex(const Complex& v) { return v.imag() != Scalar(0); } + static bool is_conj(const Complex& v1, const Complex& v2) { return v1 == Eigen::numext::conj(v2); } + + // Implicitly restarted Arnoldi factorization + void restart(Index k) + { + using std::norm; + + if(k >= m_ncv) + return; + + DoubleShiftQR decomp_ds(m_ncv); + UpperHessenbergQR decomp_hb(m_ncv); + Matrix Q = Matrix::Identity(m_ncv, m_ncv); + + for(Index i = k; i < m_ncv; i++) + { + if(is_complex(m_ritz_val[i]) && is_conj(m_ritz_val[i], m_ritz_val[i + 1])) + { + // H - mu * I = Q1 * R1 + // H <- R1 * Q1 + mu * I = Q1' * H * Q1 + // H - conj(mu) * I = Q2 * R2 + // H <- R2 * Q2 + conj(mu) * I = Q2' * H * Q2 + // + // (H - mu * I) * (H - conj(mu) * I) = Q1 * Q2 * R2 * R1 = Q * R + const Scalar s = Scalar(2) * m_ritz_val[i].real(); + const Scalar t = norm(m_ritz_val[i]); + + decomp_ds.compute(m_fac.matrix_H(), s, t); + + // Q -> Q * Qi + decomp_ds.apply_YQ(Q); + // H -> Q'HQ + // Matrix Q = Matrix::Identity(m_ncv, m_ncv); + // decomp_ds.apply_YQ(Q); + // m_fac_H = Q.transpose() * m_fac_H * Q; + m_fac.compress_H(decomp_ds); + + i++; + } else { + // QR decomposition of H - mu * I, mu is real + decomp_hb.compute(m_fac.matrix_H(), m_ritz_val[i].real()); + + // Q -> Q * Qi + decomp_hb.apply_YQ(Q); + // H -> Q'HQ = RQ + mu * I + m_fac.compress_H(decomp_hb); + } + } + + m_fac.compress_V(Q); + m_fac.factorize_from(k, m_ncv, m_nmatop); + + retrieve_ritzpair(); + } + + // Calculates the number of converged Ritz values + Index num_converged(Scalar tol) + { + // thresh = tol * max(m_eps23, abs(theta)), theta for Ritz value + Array thresh = tol * m_ritz_val.head(m_nev).array().abs().max(m_eps23); + Array resid = m_ritz_est.head(m_nev).array().abs() * m_fac.f_norm(); + // Converged "wanted" Ritz values + m_ritz_conv = (resid < thresh); + + return m_ritz_conv.cast().sum(); + } + + // Returns the adjusted nev for restarting + Index nev_adjusted(Index nconv) + { + using std::abs; + + Index nev_new = m_nev; + for(Index i = m_nev; i < m_ncv; i++) + if(abs(m_ritz_est[i]) < m_near_0) nev_new++; + + // Adjust nev_new, according to dnaup2.f line 660~674 in ARPACK + nev_new += std::min(nconv, (m_ncv - nev_new) / 2); + if(nev_new == 1 && m_ncv >= 6) + nev_new = m_ncv / 2; + else if(nev_new == 1 && m_ncv > 3) + nev_new = 2; + + if(nev_new > m_ncv - 2) + nev_new = m_ncv - 2; + + // Increase nev by one if ritz_val[nev - 1] and + // ritz_val[nev] are conjugate pairs + if(is_complex(m_ritz_val[nev_new - 1]) && + is_conj(m_ritz_val[nev_new - 1], m_ritz_val[nev_new])) + { + nev_new++; + } + + return nev_new; + } + + // Retrieves and sorts Ritz values and Ritz vectors + void retrieve_ritzpair() + { + UpperHessenbergEigen decomp(m_fac.matrix_H()); + const ComplexVector& evals = decomp.eigenvalues(); + ComplexMatrix evecs = decomp.eigenvectors(); + + SortEigenvalue sorting(evals.data(), evals.size()); + std::vector ind = sorting.index(); + + // Copy the Ritz values and vectors to m_ritz_val and m_ritz_vec, respectively + for(Index i = 0; i < m_ncv; i++) + { + m_ritz_val[i] = evals[ind[i]]; + m_ritz_est[i] = evecs(m_ncv - 1, ind[i]); + } + for(Index i = 0; i < m_nev; i++) + { + m_ritz_vec.col(i).noalias() = evecs.col(ind[i]); + } + } + +protected: + // Sorts the first nev Ritz pairs in the specified order + // This is used to return the final results + virtual void sort_ritzpair(int sort_rule) + { + // First make sure that we have a valid index vector + SortEigenvalue sorting(m_ritz_val.data(), m_nev); + std::vector ind = sorting.index(); + + switch(sort_rule) + { + case LARGEST_MAGN: + break; + case LARGEST_REAL: + { + SortEigenvalue sorting(m_ritz_val.data(), m_nev); + ind = sorting.index(); + } + break; + case LARGEST_IMAG: + { + SortEigenvalue sorting(m_ritz_val.data(), m_nev); + ind = sorting.index(); + } + break; + case SMALLEST_MAGN: + { + SortEigenvalue sorting(m_ritz_val.data(), m_nev); + ind = sorting.index(); + } + break; + case SMALLEST_REAL: + { + SortEigenvalue sorting(m_ritz_val.data(), m_nev); + ind = sorting.index(); + } + break; + case SMALLEST_IMAG: + { + SortEigenvalue sorting(m_ritz_val.data(), m_nev); + ind = sorting.index(); + } + break; + default: + throw std::invalid_argument("unsupported sorting rule"); + } + + ComplexVector new_ritz_val(m_ncv); + ComplexMatrix new_ritz_vec(m_ncv, m_nev); + BoolArray new_ritz_conv(m_nev); + + for(Index i = 0; i < m_nev; i++) + { + new_ritz_val[i] = m_ritz_val[ind[i]]; + new_ritz_vec.col(i).noalias() = m_ritz_vec.col(ind[i]); + new_ritz_conv[i] = m_ritz_conv[ind[i]]; + } + + m_ritz_val.swap(new_ritz_val); + m_ritz_vec.swap(new_ritz_vec); + m_ritz_conv.swap(new_ritz_conv); + } + +public: + /// \cond + + GenEigsBase(OpType* op, BOpType* Bop, Index nev, Index ncv) : + m_op(op), + m_n(m_op->rows()), + m_nev(nev), + m_ncv(ncv > m_n ? m_n : ncv), + m_nmatop(0), + m_niter(0), + m_fac(ArnoldiOpType(op, Bop), m_ncv), + m_info(NOT_COMPUTED), + m_near_0(TypeTraits::min() * Scalar(10)), + m_eps(Eigen::NumTraits::epsilon()), + m_eps23(Eigen::numext::pow(m_eps, Scalar(2.0) / 3)) + { + if(nev < 1 || nev > m_n - 2) + throw std::invalid_argument("nev must satisfy 1 <= nev <= n - 2, n is the size of matrix"); + + if(ncv < nev + 2 || ncv > m_n) + throw std::invalid_argument("ncv must satisfy nev + 2 <= ncv <= n, n is the size of matrix"); + } + + /// + /// Virtual destructor + /// + virtual ~GenEigsBase() {} + + /// \endcond + + /// + /// Initializes the solver by providing an initial residual vector. + /// + /// \param init_resid Pointer to the initial residual vector. + /// + /// **Spectra** (and also **ARPACK**) uses an iterative algorithm + /// to find eigenvalues. This function allows the user to provide the initial + /// residual vector. + /// + void init(const Scalar* init_resid) + { + // Reset all matrices/vectors to zero + m_ritz_val.resize(m_ncv); + m_ritz_vec.resize(m_ncv, m_nev); + m_ritz_est.resize(m_ncv); + m_ritz_conv.resize(m_nev); + + m_ritz_val.setZero(); + m_ritz_vec.setZero(); + m_ritz_est.setZero(); + m_ritz_conv.setZero(); + + m_nmatop = 0; + m_niter = 0; + + // Initialize the Arnoldi factorization + MapConstVec v0(init_resid, m_n); + m_fac.init(v0, m_nmatop); + } + + /// + /// Initializes the solver by providing a random initial residual vector. + /// + /// This overloaded function generates a random initial residual vector + /// (with a fixed random seed) for the algorithm. Elements in the vector + /// follow independent Uniform(-0.5, 0.5) distribution. + /// + void init() + { + SimpleRandom rng(0); + Vector init_resid = rng.random_vec(m_n); + init(init_resid.data()); + } + + /// + /// Conducts the major computation procedure. + /// + /// \param maxit Maximum number of iterations allowed in the algorithm. + /// \param tol Precision parameter for the calculated eigenvalues. + /// \param sort_rule Rule to sort the eigenvalues and eigenvectors. + /// Supported values are + /// `Spectra::LARGEST_MAGN`, `Spectra::LARGEST_REAL`, + /// `Spectra::LARGEST_IMAG`, `Spectra::SMALLEST_MAGN`, + /// `Spectra::SMALLEST_REAL` and `Spectra::SMALLEST_IMAG`, + /// for example `LARGEST_MAGN` indicates that eigenvalues + /// with largest magnitude come first. + /// Note that this argument is only used to + /// **sort** the final result, and the **selection** rule + /// (e.g. selecting the largest or smallest eigenvalues in the + /// full spectrum) is specified by the template parameter + /// `SelectionRule` of GenEigsSolver. + /// + /// \return Number of converged eigenvalues. + /// + Index compute(Index maxit = 1000, Scalar tol = 1e-10, int sort_rule = LARGEST_MAGN) + { + // The m-step Arnoldi factorization + m_fac.factorize_from(1, m_ncv, m_nmatop); + retrieve_ritzpair(); + // Restarting + Index i, nconv = 0, nev_adj; + for(i = 0; i < maxit; i++) + { + nconv = num_converged(tol); + if(nconv >= m_nev) + break; + + nev_adj = nev_adjusted(nconv); + restart(nev_adj); + } + // Sorting results + sort_ritzpair(sort_rule); + + m_niter += i + 1; + m_info = (nconv >= m_nev) ? SUCCESSFUL : NOT_CONVERGING; + + return std::min(m_nev, nconv); + } + + /// + /// Returns the status of the computation. + /// The full list of enumeration values can be found in \ref Enumerations. + /// + int info() const { return m_info; } + + /// + /// Returns the number of iterations used in the computation. + /// + Index num_iterations() const { return m_niter; } + + /// + /// Returns the number of matrix operations used in the computation. + /// + Index num_operations() const { return m_nmatop; } + + /// + /// Returns the converged eigenvalues. + /// + /// \return A complex-valued vector containing the eigenvalues. + /// Returned vector type will be `Eigen::Vector, ...>`, depending on + /// the template parameter `Scalar` defined. + /// + ComplexVector eigenvalues() const + { + const Index nconv = m_ritz_conv.cast().sum(); + ComplexVector res(nconv); + + if(!nconv) + return res; + + Index j = 0; + for(Index i = 0; i < m_nev; i++) + { + if(m_ritz_conv[i]) + { + res[j] = m_ritz_val[i]; + j++; + } + } + + return res; + } + + /// + /// Returns the eigenvectors associated with the converged eigenvalues. + /// + /// \param nvec The number of eigenvectors to return. + /// + /// \return A complex-valued matrix containing the eigenvectors. + /// Returned matrix type will be `Eigen::Matrix, ...>`, + /// depending on the template parameter `Scalar` defined. + /// + ComplexMatrix eigenvectors(Index nvec) const + { + const Index nconv = m_ritz_conv.cast().sum(); + nvec = std::min(nvec, nconv); + ComplexMatrix res(m_n, nvec); + + if(!nvec) + return res; + + ComplexMatrix ritz_vec_conv(m_ncv, nvec); + Index j = 0; + for(Index i = 0; i < m_nev && j < nvec; i++) + { + if(m_ritz_conv[i]) + { + ritz_vec_conv.col(j).noalias() = m_ritz_vec.col(i); + j++; + } + } + + res.noalias() = m_fac.matrix_V() * ritz_vec_conv; + + return res; + } + + /// + /// Returns all converged eigenvectors. + /// + ComplexMatrix eigenvectors() const + { + return eigenvectors(m_nev); + } +}; + + +} // namespace Spectra + +#endif // GEN_EIGS_BASE_H diff --git a/external/Spectra/include/Spectra/GenEigsComplexShiftSolver.h b/external/Spectra/include/Spectra/GenEigsComplexShiftSolver.h new file mode 100644 index 000000000..2c1aee7f5 --- /dev/null +++ b/external/Spectra/include/Spectra/GenEigsComplexShiftSolver.h @@ -0,0 +1,156 @@ +// Copyright (C) 2016-2019 Yixuan Qiu +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at https://mozilla.org/MPL/2.0/. + +#ifndef GEN_EIGS_COMPLEX_SHIFT_SOLVER_H +#define GEN_EIGS_COMPLEX_SHIFT_SOLVER_H + +#include + +#include "GenEigsBase.h" +#include "Util/SelectionRule.h" +#include "MatOp/DenseGenComplexShiftSolve.h" + +namespace Spectra { + + +/// +/// \ingroup EigenSolver +/// +/// This class implements the eigen solver for general real matrices with +/// a complex shift value in the **shift-and-invert mode**. The background +/// knowledge of the shift-and-invert mode can be found in the documentation +/// of the SymEigsShiftSolver class. +/// +/// \tparam Scalar The element type of the matrix. +/// Currently supported types are `float`, `double` and `long double`. +/// \tparam SelectionRule An enumeration value indicating the selection rule of +/// the shifted-and-inverted eigenvalues. +/// The full list of enumeration values can be found in +/// \ref Enumerations. +/// \tparam OpType The name of the matrix operation class. Users could either +/// use the DenseGenComplexShiftSolve wrapper class, or define their +/// own that implements all the public member functions as in +/// DenseGenComplexShiftSolve. +/// +template > +class GenEigsComplexShiftSolver: public GenEigsBase +{ +private: + typedef Eigen::Index Index; + typedef std::complex Complex; + typedef Eigen::Matrix Vector; + typedef Eigen::Matrix ComplexVector; + + const Scalar m_sigmar; + const Scalar m_sigmai; + + // First transform back the Ritz values, and then sort + void sort_ritzpair(int sort_rule) + { + using std::abs; + using std::sqrt; + using std::norm; + + // The eigenvalues we get from the iteration is + // nu = 0.5 * (1 / (lambda - sigma) + 1 / (lambda - conj(sigma))) + // So the eigenvalues of the original problem is + // 1 \pm sqrt(1 - 4 * nu^2 * sigmai^2) + // lambda = sigmar + ----------------------------------- + // 2 * nu + // We need to pick the correct root + // Let (lambdaj, vj) be the j-th eigen pair, then A * vj = lambdaj * vj + // and inv(A - r * I) * vj = 1 / (lambdaj - r) * vj + // where r is any shift value. + // We can use this identity to determine lambdaj + // + // op(v) computes Re(inv(A - r * I) * v) for any real v + // If r is real, then op(v) is also real. Let a = Re(vj), b = Im(vj), + // then op(vj) = op(a) + op(b) * i + // By comparing op(vj) and [1 / (lambdaj - r) * vj], we can determine + // which one is the correct root + + // Select a random shift value + SimpleRandom rng(0); + const Scalar shiftr = rng.random() * m_sigmar + rng.random(); + const Complex shift = Complex(shiftr, Scalar(0)); + this->m_op->set_shift(shiftr, Scalar(0)); + + // Calculate inv(A - r * I) * vj + Vector v_real(this->m_n), v_imag(this->m_n), OPv_real(this->m_n), OPv_imag(this->m_n); + const Scalar eps = Eigen::NumTraits::epsilon(); + for(Index i = 0; i < this->m_nev; i++) + { + v_real.noalias() = this->m_fac.matrix_V() * this->m_ritz_vec.col(i).real(); + v_imag.noalias() = this->m_fac.matrix_V() * this->m_ritz_vec.col(i).imag(); + this->m_op->perform_op(v_real.data(), OPv_real.data()); + this->m_op->perform_op(v_imag.data(), OPv_imag.data()); + + // Two roots computed from the quadratic equation + const Complex nu = this->m_ritz_val[i]; + const Complex root_part1 = m_sigmar + Scalar(0.5) / nu; + const Complex root_part2 = Scalar(0.5) * sqrt(Scalar(1) - Scalar(4) * m_sigmai * m_sigmai * (nu * nu)) / nu; + const Complex root1 = root_part1 + root_part2; + const Complex root2 = root_part1 - root_part2; + + // Test roots + Scalar err1 = Scalar(0), err2 = Scalar(0); + for(int k = 0; k < this->m_n; k++) + { + const Complex rhs1 = Complex(v_real[k], v_imag[k]) / (root1 - shift); + const Complex rhs2 = Complex(v_real[k], v_imag[k]) / (root2 - shift); + const Complex OPv = Complex(OPv_real[k], OPv_imag[k]); + err1 += norm(OPv - rhs1); + err2 += norm(OPv - rhs2); + } + + const Complex lambdaj = (err1 < err2) ? root1 : root2; + this->m_ritz_val[i] = lambdaj; + + if(abs(Eigen::numext::imag(lambdaj)) > eps) + { + this->m_ritz_val[i + 1] = Eigen::numext::conj(lambdaj); + i++; + } else { + this->m_ritz_val[i] = Complex(Eigen::numext::real(lambdaj), Scalar(0)); + } + } + + GenEigsBase::sort_ritzpair(sort_rule); + } +public: + /// + /// Constructor to create a eigen solver object using the shift-and-invert mode. + /// + /// \param op Pointer to the matrix operation object. This class should implement + /// the complex shift-solve operation of \f$A\f$: calculating + /// \f$\mathrm{Re}\{(A-\sigma I)^{-1}v\}\f$ for any vector \f$v\f$. Users could either + /// create the object from the DenseGenComplexShiftSolve wrapper class, or + /// define their own that implements all the public member functions + /// as in DenseGenComplexShiftSolve. + /// \param nev Number of eigenvalues requested. This should satisfy \f$1\le nev \le n-2\f$, + /// where \f$n\f$ is the size of matrix. + /// \param ncv Parameter that controls the convergence speed of the algorithm. + /// Typically a larger `ncv` means faster convergence, but it may + /// also result in greater memory use and more matrix operations + /// in each iteration. This parameter must satisfy \f$nev+2 \le ncv \le n\f$, + /// and is advised to take \f$ncv \ge 2\cdot nev + 1\f$. + /// \param sigmar The real part of the shift. + /// \param sigmai The imaginary part of the shift. + /// + GenEigsComplexShiftSolver(OpType* op, Index nev, Index ncv, const Scalar& sigmar, const Scalar& sigmai) : + GenEigsBase(op, NULL, nev, ncv), + m_sigmar(sigmar), m_sigmai(sigmai) + { + this->m_op->set_shift(m_sigmar, m_sigmai); + } +}; + + +} // namespace Spectra + +#endif // GEN_EIGS_COMPLEX_SHIFT_SOLVER_H diff --git a/external/Spectra/include/Spectra/GenEigsRealShiftSolver.h b/external/Spectra/include/Spectra/GenEigsRealShiftSolver.h new file mode 100644 index 000000000..a7e3da8ea --- /dev/null +++ b/external/Spectra/include/Spectra/GenEigsRealShiftSolver.h @@ -0,0 +1,90 @@ +// Copyright (C) 2016-2019 Yixuan Qiu +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at https://mozilla.org/MPL/2.0/. + +#ifndef GEN_EIGS_REAL_SHIFT_SOLVER_H +#define GEN_EIGS_REAL_SHIFT_SOLVER_H + +#include + +#include "GenEigsBase.h" +#include "Util/SelectionRule.h" +#include "MatOp/DenseGenRealShiftSolve.h" + +namespace Spectra { + + +/// +/// \ingroup EigenSolver +/// +/// This class implements the eigen solver for general real matrices with +/// a real shift value in the **shift-and-invert mode**. The background +/// knowledge of the shift-and-invert mode can be found in the documentation +/// of the SymEigsShiftSolver class. +/// +/// \tparam Scalar The element type of the matrix. +/// Currently supported types are `float`, `double` and `long double`. +/// \tparam SelectionRule An enumeration value indicating the selection rule of +/// the shifted-and-inverted eigenvalues. +/// The full list of enumeration values can be found in +/// \ref Enumerations. +/// \tparam OpType The name of the matrix operation class. Users could either +/// use the wrapper classes such as DenseGenRealShiftSolve and +/// SparseGenRealShiftSolve, or define their +/// own that implements all the public member functions as in +/// DenseGenRealShiftSolve. +/// +template > +class GenEigsRealShiftSolver: public GenEigsBase +{ +private: + typedef Eigen::Index Index; + typedef std::complex Complex; + typedef Eigen::Array ComplexArray; + + const Scalar m_sigma; + + // First transform back the Ritz values, and then sort + void sort_ritzpair(int sort_rule) + { + // The eigenvalues we get from the iteration is nu = 1 / (lambda - sigma) + // So the eigenvalues of the original problem is lambda = 1 / nu + sigma + ComplexArray ritz_val_org = Scalar(1.0) / this->m_ritz_val.head(this->m_nev).array() + m_sigma; + this->m_ritz_val.head(this->m_nev) = ritz_val_org; + GenEigsBase::sort_ritzpair(sort_rule); + } +public: + /// + /// Constructor to create a eigen solver object using the shift-and-invert mode. + /// + /// \param op Pointer to the matrix operation object. This class should implement + /// the shift-solve operation of \f$A\f$: calculating + /// \f$(A-\sigma I)^{-1}v\f$ for any vector \f$v\f$. Users could either + /// create the object from the wrapper class such as DenseGenRealShiftSolve, or + /// define their own that implements all the public member functions + /// as in DenseGenRealShiftSolve. + /// \param nev Number of eigenvalues requested. This should satisfy \f$1\le nev \le n-2\f$, + /// where \f$n\f$ is the size of matrix. + /// \param ncv Parameter that controls the convergence speed of the algorithm. + /// Typically a larger `ncv` means faster convergence, but it may + /// also result in greater memory use and more matrix operations + /// in each iteration. This parameter must satisfy \f$nev+2 \le ncv \le n\f$, + /// and is advised to take \f$ncv \ge 2\cdot nev + 1\f$. + /// \param sigma The real-valued shift. + /// + GenEigsRealShiftSolver(OpType* op, Index nev, Index ncv, Scalar sigma) : + GenEigsBase(op, NULL, nev, ncv), + m_sigma(sigma) + { + this->m_op->set_shift(m_sigma); + } +}; + + +} // namespace Spectra + +#endif // GEN_EIGS_REAL_SHIFT_SOLVER_H diff --git a/external/Spectra/include/Spectra/GenEigsSolver.h b/external/Spectra/include/Spectra/GenEigsSolver.h new file mode 100644 index 000000000..a6960acf6 --- /dev/null +++ b/external/Spectra/include/Spectra/GenEigsSolver.h @@ -0,0 +1,160 @@ +// Copyright (C) 2016-2019 Yixuan Qiu +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at https://mozilla.org/MPL/2.0/. + +#ifndef GEN_EIGS_SOLVER_H +#define GEN_EIGS_SOLVER_H + +#include + +#include "GenEigsBase.h" +#include "Util/SelectionRule.h" +#include "MatOp/DenseGenMatProd.h" + +namespace Spectra { + + +/// +/// \ingroup EigenSolver +/// +/// This class implements the eigen solver for general real matrices, i.e., +/// to solve \f$Ax=\lambda x\f$ for a possibly non-symmetric \f$A\f$ matrix. +/// +/// Most of the background information documented in the SymEigsSolver class +/// also applies to the GenEigsSolver class here, except that the eigenvalues +/// and eigenvectors of a general matrix can now be complex-valued. +/// +/// \tparam Scalar The element type of the matrix. +/// Currently supported types are `float`, `double` and `long double`. +/// \tparam SelectionRule An enumeration value indicating the selection rule of +/// the requested eigenvalues, for example `LARGEST_MAGN` +/// to retrieve eigenvalues with the largest magnitude. +/// The full list of enumeration values can be found in +/// \ref Enumerations. +/// \tparam OpType The name of the matrix operation class. Users could either +/// use the wrapper classes such as DenseGenMatProd and +/// SparseGenMatProd, or define their +/// own that implements all the public member functions as in +/// DenseGenMatProd. +/// +/// An example that illustrates the usage of GenEigsSolver is give below: +/// +/// \code{.cpp} +/// #include +/// #include +/// // is implicitly included +/// #include +/// +/// using namespace Spectra; +/// +/// int main() +/// { +/// // We are going to calculate the eigenvalues of M +/// Eigen::MatrixXd M = Eigen::MatrixXd::Random(10, 10); +/// +/// // Construct matrix operation object using the wrapper class +/// DenseGenMatProd op(M); +/// +/// // Construct eigen solver object, requesting the largest +/// // (in magnitude, or norm) three eigenvalues +/// GenEigsSolver< double, LARGEST_MAGN, DenseGenMatProd > eigs(&op, 3, 6); +/// +/// // Initialize and compute +/// eigs.init(); +/// int nconv = eigs.compute(); +/// +/// // Retrieve results +/// Eigen::VectorXcd evalues; +/// if(eigs.info() == SUCCESSFUL) +/// evalues = eigs.eigenvalues(); +/// +/// std::cout << "Eigenvalues found:\n" << evalues << std::endl; +/// +/// return 0; +/// } +/// \endcode +/// +/// And also an example for sparse matrices: +/// +/// \code{.cpp} +/// #include +/// #include +/// #include +/// #include +/// #include +/// +/// using namespace Spectra; +/// +/// int main() +/// { +/// // A band matrix with 1 on the main diagonal, 2 on the below-main subdiagonal, +/// // and 3 on the above-main subdiagonal +/// const int n = 10; +/// Eigen::SparseMatrix M(n, n); +/// M.reserve(Eigen::VectorXi::Constant(n, 3)); +/// for(int i = 0; i < n; i++) +/// { +/// M.insert(i, i) = 1.0; +/// if(i > 0) +/// M.insert(i - 1, i) = 3.0; +/// if(i < n - 1) +/// M.insert(i + 1, i) = 2.0; +/// } +/// +/// // Construct matrix operation object using the wrapper class SparseGenMatProd +/// SparseGenMatProd op(M); +/// +/// // Construct eigen solver object, requesting the largest three eigenvalues +/// GenEigsSolver< double, LARGEST_MAGN, SparseGenMatProd > eigs(&op, 3, 6); +/// +/// // Initialize and compute +/// eigs.init(); +/// int nconv = eigs.compute(); +/// +/// // Retrieve results +/// Eigen::VectorXcd evalues; +/// if(eigs.info() == SUCCESSFUL) +/// evalues = eigs.eigenvalues(); +/// +/// std::cout << "Eigenvalues found:\n" << evalues << std::endl; +/// +/// return 0; +/// } +/// \endcode +template < typename Scalar = double, + int SelectionRule = LARGEST_MAGN, + typename OpType = DenseGenMatProd > +class GenEigsSolver: public GenEigsBase +{ +private: + typedef Eigen::Index Index; + +public: + /// + /// Constructor to create a solver object. + /// + /// \param op Pointer to the matrix operation object, which should implement + /// the matrix-vector multiplication operation of \f$A\f$: + /// calculating \f$Av\f$ for any vector \f$v\f$. Users could either + /// create the object from the wrapper class such as DenseGenMatProd, or + /// define their own that implements all the public member functions + /// as in DenseGenMatProd. + /// \param nev Number of eigenvalues requested. This should satisfy \f$1\le nev \le n-2\f$, + /// where \f$n\f$ is the size of matrix. + /// \param ncv Parameter that controls the convergence speed of the algorithm. + /// Typically a larger `ncv` means faster convergence, but it may + /// also result in greater memory use and more matrix operations + /// in each iteration. This parameter must satisfy \f$nev+2 \le ncv \le n\f$, + /// and is advised to take \f$ncv \ge 2\cdot nev + 1\f$. + /// + GenEigsSolver(OpType* op, Index nev, Index ncv) : + GenEigsBase(op, NULL, nev, ncv) + {} +}; + + +} // namespace Spectra + +#endif // GEN_EIGS_SOLVER_H diff --git a/external/Spectra/include/Spectra/LinAlg/Arnoldi.h b/external/Spectra/include/Spectra/LinAlg/Arnoldi.h new file mode 100644 index 000000000..b9fa75b51 --- /dev/null +++ b/external/Spectra/include/Spectra/LinAlg/Arnoldi.h @@ -0,0 +1,283 @@ +// Copyright (C) 2018-2019 Yixuan Qiu +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at https://mozilla.org/MPL/2.0/. + +#ifndef ARNOLDI_H +#define ARNOLDI_H + +#include +#include // std::sqrt +#include // std::invalid_argument +#include // std::stringstream + +#include "../MatOp/internal/ArnoldiOp.h" +#include "../Util/TypeTraits.h" +#include "../Util/SimpleRandom.h" +#include "UpperHessenbergQR.h" +#include "DoubleShiftQR.h" + +namespace Spectra { + + +// Arnoldi factorization A * V = V * H + f * e' +// A: n x n +// V: n x k +// H: k x k +// f: n x 1 +// e: [0, ..., 0, 1] +// V and H are allocated of dimension m, so the maximum value of k is m +template +class Arnoldi +{ +private: + typedef Eigen::Index Index; + typedef Eigen::Matrix Matrix; + typedef Eigen::Matrix Vector; + typedef Eigen::Map MapMat; + typedef Eigen::Map MapVec; + typedef Eigen::Map MapConstMat; + typedef Eigen::Map MapConstVec; + +protected: + ArnoldiOpType m_op; // Operators for the Arnoldi factorization + + const Index m_n; // dimension of A + const Index m_m; // maximum dimension of subspace V + Index m_k; // current dimension of subspace V + + Matrix m_fac_V; // V matrix in the Arnoldi factorization + Matrix m_fac_H; // H matrix in the Arnoldi factorization + Vector m_fac_f; // residual in the Arnoldi factorization + Scalar m_beta; // ||f||, B-norm of f + + const Scalar m_near_0; // a very small value, but 1.0 / m_near_0 does not overflow + // ~= 1e-307 for the "double" type + const Scalar m_eps; // the machine precision, ~= 1e-16 for the "double" type + + // Given orthonormal basis functions V, find a nonzero vector f such that V'Bf = 0 + // Assume that f has been properly allocated + void expand_basis(MapConstMat& V, const Index seed, Vector& f, Scalar& fnorm) + { + using std::sqrt; + + const Scalar thresh = m_eps * sqrt(Scalar(m_n)); + Vector Vf(V.cols()); + for(Index iter = 0; iter < 5; iter++) + { + // Randomly generate a new vector and orthogonalize it against V + SimpleRandom rng(seed + 123 * iter); + f.noalias() = rng.random_vec(m_n); + // f <- f - V * V'Bf, so that f is orthogonal to V in B-norm + m_op.trans_product(V, f, Vf); + f.noalias() -= V * Vf; + // fnorm <- ||f|| + fnorm = m_op.norm(f); + + // If fnorm is too close to zero, we try a new random vector, + // otherwise return the result + if(fnorm >= thresh) + return; + } + } + +public: + Arnoldi(const ArnoldiOpType& op, Index m) : + m_op(op), m_n(op.rows()), m_m(m), m_k(0), + m_near_0(TypeTraits::min() * Scalar(10)), + m_eps(Eigen::NumTraits::epsilon()) + {} + + virtual ~Arnoldi() {} + + // Const-reference to internal structures + const Matrix& matrix_V() const { return m_fac_V; } + const Matrix& matrix_H() const { return m_fac_H; } + const Vector& vector_f() const { return m_fac_f; } + Scalar f_norm() const { return m_beta; } + Index subspace_dim() const { return m_k; } + + // Initialize with an operator and an initial vector + void init(MapConstVec& v0, Index& op_counter) + { + m_fac_V.resize(m_n, m_m); + m_fac_H.resize(m_m, m_m); + m_fac_f.resize(m_n); + m_fac_H.setZero(); + + // Verify the initial vector + const Scalar v0norm = m_op.norm(v0); + if(v0norm < m_near_0) + throw std::invalid_argument("initial residual vector cannot be zero"); + + // Points to the first column of V + MapVec v(m_fac_V.data(), m_n); + + // Normalize + v.noalias() = v0 / v0norm; + + // Compute H and f + Vector w(m_n); + m_op.perform_op(v.data(), w.data()); + op_counter++; + + m_fac_H(0, 0) = m_op.inner_product(v, w); + m_fac_f.noalias() = w - v * m_fac_H(0, 0); + + // In some cases f is zero in exact arithmetics, but due to rounding errors + // it may contain tiny fluctuations. When this happens, we force f to be zero + if(m_fac_f.cwiseAbs().maxCoeff() < m_eps) + { + m_fac_f.setZero(); + m_beta = Scalar(0); + } else { + m_beta = m_op.norm(m_fac_f); + } + + // Indicate that this is a step-1 factorization + m_k = 1; + } + + // Arnoldi factorization starting from step-k + virtual void factorize_from(Index from_k, Index to_m, Index& op_counter) + { + using std::sqrt; + + if(to_m <= from_k) return; + + if(from_k > m_k) + { + std::stringstream msg; + msg << "Arnoldi: from_k (= " << from_k << + ") is larger than the current subspace dimension (= " << + m_k << ")"; + throw std::invalid_argument(msg.str()); + } + + const Scalar beta_thresh = m_eps * sqrt(Scalar(m_n)); + + // Pre-allocate vectors + Vector Vf(to_m); + Vector w(m_n); + + // Keep the upperleft k x k submatrix of H and set other elements to 0 + m_fac_H.rightCols(m_m - from_k).setZero(); + m_fac_H.block(from_k, 0, m_m - from_k, from_k).setZero(); + + for(Index i = from_k; i <= to_m - 1; i++) + { + bool restart = false; + // If beta = 0, then the next V is not full rank + // We need to generate a new residual vector that is orthogonal + // to the current V, which we call a restart + if(m_beta < m_near_0) + { + MapConstMat V(m_fac_V.data(), m_n, i); // The first i columns + expand_basis(V, 2 * i, m_fac_f, m_beta); + restart = true; + } + + // v <- f / ||f|| + m_fac_V.col(i).noalias() = m_fac_f / m_beta; // The (i+1)-th column + + // Note that H[i+1, i] equals to the unrestarted beta + m_fac_H(i, i - 1) = restart ? Scalar(0) : m_beta; + + // w <- A * v, v = m_fac_V.col(i) + m_op.perform_op(&m_fac_V(0, i), w.data()); + op_counter++; + + const Index i1 = i + 1; + // First i+1 columns of V + MapConstMat Vs(m_fac_V.data(), m_n, i1); + // h = m_fac_H(0:i, i) + MapVec h(&m_fac_H(0, i), i1); + // h <- V'Bw + m_op.trans_product(Vs, w, h); + + // f <- w - V * h + m_fac_f.noalias() = w - Vs * h; + m_beta = m_op.norm(m_fac_f); + + if(m_beta > Scalar(0.717) * m_op.norm(h)) + continue; + + // f/||f|| is going to be the next column of V, so we need to test + // whether V'B(f/||f||) ~= 0 + m_op.trans_product(Vs, m_fac_f, Vf.head(i1)); + Scalar ortho_err = Vf.head(i1).cwiseAbs().maxCoeff(); + // If not, iteratively correct the residual + int count = 0; + while(count < 5 && ortho_err > m_eps * m_beta) + { + // There is an edge case: when beta=||f|| is close to zero, f mostly consists + // of noises of rounding errors, so the test [ortho_err < eps * beta] is very + // likely to fail. In particular, if beta=0, then the test is ensured to fail. + // Hence when this happens, we force f to be zero, and then restart in the + // next iteration. + if(m_beta < beta_thresh) + { + m_fac_f.setZero(); + m_beta = Scalar(0); + break; + } + + // f <- f - V * Vf + m_fac_f.noalias() -= Vs * Vf.head(i1); + // h <- h + Vf + h.noalias() += Vf.head(i1); + // beta <- ||f|| + m_beta = m_op.norm(m_fac_f); + + m_op.trans_product(Vs, m_fac_f, Vf.head(i1)); + ortho_err = Vf.head(i1).cwiseAbs().maxCoeff(); + count++; + } + } + + // Indicate that this is a step-m factorization + m_k = to_m; + } + + // Apply H -> Q'HQ, where Q is from a double shift QR decomposition + void compress_H(const DoubleShiftQR& decomp) + { + decomp.matrix_QtHQ(m_fac_H); + m_k -= 2; + } + + // Apply H -> Q'HQ, where Q is from an upper Hessenberg QR decomposition + void compress_H(const UpperHessenbergQR& decomp) + { + decomp.matrix_QtHQ(m_fac_H); + m_k--; + } + + // Apply V -> VQ and compute the new f. + // Should be called after compress_H(), since m_k is updated there. + // Only need to update the first k+1 columns of V + // The first (m - k + i) elements of the i-th column of Q are non-zero, + // and the rest are zero + void compress_V(const Matrix& Q) + { + Matrix Vs(m_n, m_k + 1); + for(Index i = 0; i < m_k; i++) + { + const Index nnz = m_m - m_k + i + 1; + MapConstVec q(&Q(0, i), nnz); + Vs.col(i).noalias() = m_fac_V.leftCols(nnz) * q; + } + Vs.col(m_k).noalias() = m_fac_V * Q.col(m_k); + m_fac_V.leftCols(m_k + 1).noalias() = Vs; + + Vector fk = m_fac_f * Q(m_m - 1, m_k - 1) + m_fac_V.col(m_k) * m_fac_H(m_k, m_k - 1); + m_fac_f.swap(fk); + m_beta = m_op.norm(m_fac_f); + } +}; + + +} // namespace Spectra + +#endif // ARNOLDI_H diff --git a/external/Spectra/include/Spectra/LinAlg/BKLDLT.h b/external/Spectra/include/Spectra/LinAlg/BKLDLT.h new file mode 100644 index 000000000..5509749bd --- /dev/null +++ b/external/Spectra/include/Spectra/LinAlg/BKLDLT.h @@ -0,0 +1,522 @@ +// Copyright (C) 2019 Yixuan Qiu +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at https://mozilla.org/MPL/2.0/. + +#ifndef BK_LDLT_H +#define BK_LDLT_H + +#include +#include +#include + +#include "../Util/CompInfo.h" + +namespace Spectra { + + +// Bunch-Kaufman LDLT decomposition +// References: +// 1. Bunch, J. R., & Kaufman, L. (1977). Some stable methods for calculating inertia and solving symmetric linear systems. +// Mathematics of computation, 31(137), 163-179. +// 2. Golub, G. H., & Van Loan, C. F. (2012). Matrix computations (Vol. 3). JHU press. Section 4.4. +// 3. Bunch-Parlett diagonal pivoting +// 4. Ashcraft, C., Grimes, R. G., & Lewis, J. G. (1998). Accurate symmetric indefinite linear equation solvers. +// SIAM Journal on Matrix Analysis and Applications, 20(2), 513-561. +template +class BKLDLT +{ +private: + typedef Eigen::Index Index; + typedef Eigen::Matrix Matrix; + typedef Eigen::Matrix Vector; + typedef Eigen::Map MapVec; + typedef Eigen::Map MapConstVec; + + typedef Eigen::Matrix IntVector; + typedef Eigen::Ref GenericVector; + typedef Eigen::Ref GenericMatrix; + typedef const Eigen::Ref ConstGenericMatrix; + typedef const Eigen::Ref ConstGenericVector; + + Index m_n; + Vector m_data; // storage for a lower-triangular matrix + std::vector m_colptr; // pointers to columns + IntVector m_perm; // [-2, -1, 3, 1, 4, 5]: 0 <-> 2, 1 <-> 1, 2 <-> 3, 3 <-> 1, 4 <-> 4, 5 <-> 5 + std::vector< std::pair > m_permc; // compressed version of m_perm: [(0, 2), (2, 3), (3, 1)] + + bool m_computed; + int m_info; + + // Access to elements + // Pointer to the k-th column + Scalar* col_pointer(Index k) { return m_colptr[k]; } + // A[i, j] -> m_colptr[j][i - j], i >= j + Scalar& coeff(Index i, Index j) { return m_colptr[j][i - j]; } + const Scalar& coeff(Index i, Index j) const { return m_colptr[j][i - j]; } + // A[i, i] -> m_colptr[i][0] + Scalar& diag_coeff(Index i) { return m_colptr[i][0]; } + const Scalar& diag_coeff(Index i) const { return m_colptr[i][0]; } + + // Compute column pointers + void compute_pointer() + { + m_colptr.clear(); + m_colptr.reserve(m_n); + Scalar* head = m_data.data(); + + for(Index i = 0; i < m_n; i++) + { + m_colptr.push_back(head); + head += (m_n - i); + } + } + + // Copy mat - shift * I to m_data + void copy_data(ConstGenericMatrix& mat, int uplo, const Scalar& shift) + { + if(uplo == Eigen::Lower) + { + for(Index j = 0; j < m_n; j++) + { + const Scalar* begin = &mat.coeffRef(j, j); + const Index len = m_n - j; + std::copy(begin, begin + len, col_pointer(j)); + diag_coeff(j) -= shift; + } + } else { + Scalar* dest = m_data.data(); + for(Index i = 0; i < m_n; i++) + { + for(Index j = i; j < m_n; j++, dest++) + { + *dest = mat.coeff(i, j); + } + diag_coeff(i) -= shift; + } + } + } + + // Compute compressed permutations + void compress_permutation() + { + for(Index i = 0; i < m_n; i++) + { + // Recover the permutation action + const Index perm = (m_perm[i] >= 0) ? (m_perm[i]) : (-m_perm[i] - 1); + if(perm != i) + m_permc.push_back(std::make_pair(i, perm)); + } + } + + // Working on the A[k:end, k:end] submatrix + // Exchange k <-> r + // Assume r >= k + void pivoting_1x1(Index k, Index r) + { + // No permutation + if(k == r) + { + m_perm[k] = r; + return; + } + + // A[k, k] <-> A[r, r] + std::swap(diag_coeff(k), diag_coeff(r)); + + // A[(r+1):end, k] <-> A[(r+1):end, r] + std::swap_ranges(&coeff(r + 1, k), col_pointer(k + 1), &coeff(r + 1, r)); + + // A[(k+1):(r-1), k] <-> A[r, (k+1):(r-1)] + Scalar* src = &coeff(k + 1, k); + for(Index j = k + 1; j < r; j++, src++) + { + std::swap(*src, coeff(r, j)); + } + + m_perm[k] = r; + } + + // Working on the A[k:end, k:end] submatrix + // Exchange [k+1, k] <-> [r, p] + // Assume p >= k, r >= k+1 + void pivoting_2x2(Index k, Index r, Index p) + { + pivoting_1x1(k, p); + pivoting_1x1(k + 1, r); + + // A[k+1, k] <-> A[r, k] + std::swap(coeff(k + 1, k), coeff(r, k)); + + // Use negative signs to indicate a 2x2 block + // Also minus one to distinguish a negative zero from a positive zero + m_perm[k] = -m_perm[k] - 1; + m_perm[k + 1] = -m_perm[k + 1] - 1; + } + + // A[r1, c1:c2] <-> A[r2, c1:c2] + // Assume r2 >= r1 > c2 >= c1 + void interchange_rows(Index r1, Index r2, Index c1, Index c2) + { + if(r1 == r2) + return; + + for(Index j = c1; j <= c2; j++) + { + std::swap(coeff(r1, j), coeff(r2, j)); + } + } + + // lambda = |A[r, k]| = max{|A[k+1, k]|, ..., |A[end, k]|} + // Largest (in magnitude) off-diagonal element in the first column of the current reduced matrix + // r is the row index + // Assume k < end + Scalar find_lambda(Index k, Index& r) + { + using std::abs; + + const Scalar* head = col_pointer(k); // => A[k, k] + const Scalar* end = col_pointer(k + 1); + // Start with r=k+1, lambda=A[k+1, k] + r = k + 1; + Scalar lambda = abs(head[1]); + // Scan remaining elements + for(const Scalar* ptr = head + 2; ptr < end; ptr++) + { + const Scalar abs_elem = abs(*ptr); + if(lambda < abs_elem) + { + lambda = abs_elem; + r = k + (ptr - head); + } + } + + return lambda; + } + + // sigma = |A[p, r]| = max {|A[k, r]|, ..., |A[end, r]|} \ {A[r, r]} + // Largest (in magnitude) off-diagonal element in the r-th column of the current reduced matrix + // p is the row index + // Assume k < r < end + Scalar find_sigma(Index k, Index r, Index& p) + { + using std::abs; + + // First search A[r+1, r], ..., A[end, r], which has the same task as find_lambda() + // If r == end, we skip this search + Scalar sigma = Scalar(-1); + if(r < m_n - 1) + sigma = find_lambda(r, p); + + // Then search A[k, r], ..., A[r-1, r], which maps to A[r, k], ..., A[r, r-1] + for(Index j = k; j < r; j++) + { + const Scalar abs_elem = abs(coeff(r, j)); + if(sigma < abs_elem) + { + sigma = abs_elem; + p = j; + } + } + + return sigma; + } + + // Generate permutations and apply to A + // Return true if the resulting pivoting is 1x1, and false if 2x2 + bool permutate_mat(Index k, const Scalar& alpha) + { + using std::abs; + + Index r = k, p = k; + const Scalar lambda = find_lambda(k, r); + + // If lambda=0, no need to interchange + if(lambda > Scalar(0)) + { + const Scalar abs_akk = abs(diag_coeff(k)); + // If |A[k, k]| >= alpha * lambda, no need to interchange + if(abs_akk < alpha * lambda) + { + const Scalar sigma = find_sigma(k, r, p); + + // If sigma * |A[k, k]| >= alpha * lambda^2, no need to interchange + if(sigma * abs_akk < alpha * lambda * lambda) + { + if(abs_akk >= alpha * sigma) + { + // Permutation on A + pivoting_1x1(k, r); + + // Permutation on L + interchange_rows(k, r, 0, k - 1); + return true; + } else { + // There are two versions of permutation here + // 1. A[k+1, k] <-> A[r, k] + // 2. A[k+1, k] <-> A[r, p], where p >= k and r >= k+1 + // + // Version 1 and 2 are used by Ref[1] and Ref[2], respectively + + // Version 1 implementation + p = k; + + // Version 2 implementation + // [r, p] and [p, r] are symmetric, but we need to make sure + // p >= k and r >= k+1, so it is safe to always make r > p + // One exception is when min{r,p} == k+1, in which case we make + // r = k+1, so that only one permutation needs to be performed + /* const Index rp_min = std::min(r, p); + const Index rp_max = std::max(r, p); + if(rp_min == k + 1) + { + r = rp_min; p = rp_max; + } else { + r = rp_max; p = rp_min; + } */ + + // Right now we use Version 1 since it reduces the overhead of interchange + + // Permutation on A + pivoting_2x2(k, r, p); + // Permutation on L + interchange_rows(k, p, 0, k - 1); + interchange_rows(k + 1, r, 0, k - 1); + return false; + } + } + } + } + + return true; + } + + // E = [e11, e12] + // [e21, e22] + // Overwrite E with inv(E) + void inverse_inplace_2x2(Scalar& e11, Scalar& e21, Scalar& e22) const + { + // inv(E) = [d11, d12], d11 = e22/delta, d21 = -e21/delta, d22 = e11/delta + // [d21, d22] + const Scalar delta = e11 * e22 - e21 * e21; + std::swap(e11, e22); + e11 /= delta; + e22 /= delta; + e21 = -e21 / delta; + } + + // Return value is the status, SUCCESSFUL/NUMERICAL_ISSUE + int gaussian_elimination_1x1(Index k) + { + // D = 1 / A[k, k] + const Scalar akk = diag_coeff(k); + // Return NUMERICAL_ISSUE if not invertible + if(akk == Scalar(0)) + return NUMERICAL_ISSUE; + + diag_coeff(k) = Scalar(1) / akk; + + // B -= l * l' / A[k, k], B := A[(k+1):end, (k+1):end], l := L[(k+1):end, k] + Scalar* lptr = col_pointer(k) + 1; + const Index ldim = m_n - k - 1; + MapVec l(lptr, ldim); + for(Index j = 0; j < ldim; j++) + { + MapVec(col_pointer(j + k + 1), ldim - j).noalias() -= (lptr[j] / akk) * l.tail(ldim - j); + } + + // l /= A[k, k] + l /= akk; + + return SUCCESSFUL; + } + + // Return value is the status, SUCCESSFUL/NUMERICAL_ISSUE + int gaussian_elimination_2x2(Index k) + { + // D = inv(E) + Scalar& e11 = diag_coeff(k); + Scalar& e21 = coeff(k + 1, k); + Scalar& e22 = diag_coeff(k + 1); + // Return NUMERICAL_ISSUE if not invertible + if(e11 * e22 - e21 * e21 == Scalar(0)) + return NUMERICAL_ISSUE; + + inverse_inplace_2x2(e11, e21, e22); + + // X = l * inv(E), l := L[(k+2):end, k:(k+1)] + Scalar* l1ptr = &coeff(k + 2, k); + Scalar* l2ptr = &coeff(k + 2, k + 1); + const Index ldim = m_n - k - 2; + MapVec l1(l1ptr, ldim), l2(l2ptr, ldim); + + Eigen::Matrix X(ldim, 2); + X.col(0).noalias() = l1 * e11 + l2 * e21; + X.col(1).noalias() = l1 * e21 + l2 * e22; + + // B -= l * inv(E) * l' = X * l', B = A[(k+2):end, (k+2):end] + for(Index j = 0; j < ldim; j++) + { + MapVec(col_pointer(j + k + 2), ldim - j).noalias() -= (X.col(0).tail(ldim - j) * l1ptr[j] + X.col(1).tail(ldim - j) * l2ptr[j]); + } + + // l = X + l1.noalias() = X.col(0); + l2.noalias() = X.col(1); + + return SUCCESSFUL; + } + +public: + BKLDLT() : + m_n(0), m_computed(false), m_info(NOT_COMPUTED) + {} + + // Factorize mat - shift * I + BKLDLT(ConstGenericMatrix& mat, int uplo = Eigen::Lower, const Scalar& shift = Scalar(0)) : + m_n(mat.rows()), m_computed(false), m_info(NOT_COMPUTED) + { + compute(mat, uplo, shift); + } + + void compute(ConstGenericMatrix& mat, int uplo = Eigen::Lower, const Scalar& shift = Scalar(0)) + { + using std::abs; + + m_n = mat.rows(); + if(m_n != mat.cols()) + throw std::invalid_argument("BKLDLT: matrix must be square"); + + m_perm.setLinSpaced(m_n, 0, m_n - 1); + m_permc.clear(); + + // Copy data + m_data.resize((m_n * (m_n + 1)) / 2); + compute_pointer(); + copy_data(mat, uplo, shift); + + const Scalar alpha = (1.0 + std::sqrt(17.0)) / 8.0; + Index k = 0; + for(k = 0; k < m_n - 1; k++) + { + // 1. Interchange rows and columns of A, and save the result to m_perm + bool is_1x1 = permutate_mat(k, alpha); + + // 2. Gaussian elimination + if(is_1x1) + { + m_info = gaussian_elimination_1x1(k); + } else { + m_info = gaussian_elimination_2x2(k); + k++; + } + + // 3. Check status + if(m_info != SUCCESSFUL) + break; + } + // Invert the last 1x1 block if it exists + if(k == m_n - 1) + { + const Scalar akk = diag_coeff(k); + if(akk == Scalar(0)) + m_info = NUMERICAL_ISSUE; + + diag_coeff(k) = Scalar(1) / diag_coeff(k); + } + + compress_permutation(); + + m_computed = true; + } + + // Solve Ax=b + void solve_inplace(GenericVector b) const + { + if(!m_computed) + throw std::logic_error("BKLDLT: need to call compute() first"); + + // PAP' = LDL' + // 1. b -> Pb + Scalar* x = b.data(); + MapVec res(x, m_n); + Index npermc = m_permc.size(); + for(Index i = 0; i < npermc; i++) + { + std::swap(x[m_permc[i].first], x[m_permc[i].second]); + } + + // 2. Lz = Pb + // If m_perm[end] < 0, then end with m_n - 3, otherwise end with m_n - 2 + const Index end = (m_perm[m_n - 1] < 0) ? (m_n - 3) : (m_n - 2); + for(Index i = 0; i <= end; i++) + { + const Index b1size = m_n - i - 1; + const Index b2size = b1size - 1; + if(m_perm[i] >= 0) + { + MapConstVec l(&coeff(i + 1, i), b1size); + res.segment(i + 1, b1size).noalias() -= l * x[i]; + } else { + MapConstVec l1(&coeff(i + 2, i), b2size); + MapConstVec l2(&coeff(i + 2, i + 1), b2size); + res.segment(i + 2, b2size).noalias() -= (l1 * x[i] + l2 * x[i + 1]); + i++; + } + } + + // 3. Dw = z + for(Index i = 0; i < m_n; i++) + { + const Scalar e11 = diag_coeff(i); + if(m_perm[i] >= 0) + { + x[i] *= e11; + } else { + const Scalar e21 = coeff(i + 1, i), e22 = diag_coeff(i + 1); + const Scalar wi = x[i] * e11 + x[i + 1] * e21; + x[i + 1] = x[i] * e21 + x[i + 1] * e22; + x[i] = wi; + i++; + } + } + + // 4. L'y = w + // If m_perm[end] < 0, then start with m_n - 3, otherwise start with m_n - 2 + Index i = (m_perm[m_n - 1] < 0) ? (m_n - 3) : (m_n - 2); + for(; i >= 0; i--) + { + const Index ldim = m_n - i - 1; + MapConstVec l(&coeff(i + 1, i), ldim); + x[i] -= res.segment(i + 1, ldim).dot(l); + + if(m_perm[i] < 0) + { + MapConstVec l2(&coeff(i + 1, i - 1), ldim); + x[i - 1] -= res.segment(i + 1, ldim).dot(l2); + i--; + } + } + + // 5. x = P'y + for(Index i = npermc - 1; i >= 0; i--) + { + std::swap(x[m_permc[i].first], x[m_permc[i].second]); + } + } + + Vector solve(ConstGenericVector& b) const + { + Vector res = b; + solve_inplace(res); + return res; + } + + int info() const { return m_info; } +}; + + +} // namespace Spectra + +#endif // BK_LDLT_H diff --git a/external/Spectra/include/Spectra/LinAlg/DoubleShiftQR.h b/external/Spectra/include/Spectra/LinAlg/DoubleShiftQR.h new file mode 100644 index 000000000..2191909a4 --- /dev/null +++ b/external/Spectra/include/Spectra/LinAlg/DoubleShiftQR.h @@ -0,0 +1,378 @@ +// Copyright (C) 2016-2019 Yixuan Qiu +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at https://mozilla.org/MPL/2.0/. + +#ifndef DOUBLE_SHIFT_QR_H +#define DOUBLE_SHIFT_QR_H + +#include +#include // std::vector +#include // std::min, std::fill, std::copy +#include // std::abs, std::sqrt, std::pow +#include // std::invalid_argument, std::logic_error + +#include "../Util/TypeTraits.h" + +namespace Spectra { + + +template +class DoubleShiftQR +{ +private: + typedef Eigen::Index Index; + typedef Eigen::Matrix Matrix; + typedef Eigen::Matrix Matrix3X; + typedef Eigen::Matrix Vector; + typedef Eigen::Array IntArray; + + typedef Eigen::Ref GenericMatrix; + typedef const Eigen::Ref ConstGenericMatrix; + + Index m_n; // Dimension of the matrix + Matrix m_mat_H; // A copy of the matrix to be factorized + Scalar m_shift_s; // Shift constant + Scalar m_shift_t; // Shift constant + Matrix3X m_ref_u; // Householder reflectors + IntArray m_ref_nr; // How many rows does each reflector affects + // 3 - A general reflector + // 2 - A Givens rotation + // 1 - An identity transformation + const Scalar m_near_0; // a very small value, but 1.0 / m_safe_min does not overflow + // ~= 1e-307 for the "double" type + const Scalar m_eps; // the machine precision, + // e.g. ~= 1e-16 for the "double" type + const Scalar m_eps_rel; + const Scalar m_eps_abs; + bool m_computed; // Whether matrix has been factorized + + void compute_reflector(const Scalar& x1, const Scalar& x2, const Scalar& x3, Index ind) + { + using std::abs; + + Scalar* u = &m_ref_u.coeffRef(0, ind); + unsigned char* nr = m_ref_nr.data(); + // In general case the reflector affects 3 rows + nr[ind] = 3; + Scalar x2x3 = Scalar(0); + // If x3 is zero, decrease nr by 1 + if(abs(x3) < m_near_0) + { + // If x2 is also zero, nr will be 1, and we can exit this function + if(abs(x2) < m_near_0) + { + nr[ind] = 1; + return; + } else { + nr[ind] = 2; + } + x2x3 = abs(x2); + } else { + x2x3 = Eigen::numext::hypot(x2, x3); + } + + // x1' = x1 - rho * ||x|| + // rho = -sign(x1), if x1 == 0, we choose rho = 1 + Scalar x1_new = x1 - ((x1 <= 0) - (x1 > 0)) * Eigen::numext::hypot(x1, x2x3); + Scalar x_norm = Eigen::numext::hypot(x1_new, x2x3); + // Double check the norm of new x + if(x_norm < m_near_0) + { + nr[ind] = 1; + return; + } + u[0] = x1_new / x_norm; + u[1] = x2 / x_norm; + u[2] = x3 / x_norm; + } + + void compute_reflector(const Scalar* x, Index ind) + { + compute_reflector(x[0], x[1], x[2], ind); + } + + // Update the block X = H(il:iu, il:iu) + void update_block(Index il, Index iu) + { + // Block size + const Index bsize = iu - il + 1; + + // If block size == 1, there is no need to apply reflectors + if(bsize == 1) + { + m_ref_nr.coeffRef(il) = 1; + return; + } + + const Scalar x00 = m_mat_H.coeff(il, il), + x01 = m_mat_H.coeff(il, il + 1), + x10 = m_mat_H.coeff(il + 1, il), + x11 = m_mat_H.coeff(il + 1, il + 1); + // m00 = x00 * (x00 - s) + x01 * x10 + t + const Scalar m00 = x00 * (x00 - m_shift_s) + x01 * x10 + m_shift_t; + // m10 = x10 * (x00 + x11 - s) + const Scalar m10 = x10 * (x00 + x11 - m_shift_s); + + // For block size == 2, do a Givens rotation on M = X * X - s * X + t * I + if(bsize == 2) + { + // This causes nr=2 + compute_reflector(m00, m10, 0, il); + // Apply the reflector to X + apply_PX(m_mat_H.block(il, il, 2, m_n - il), m_n, il); + apply_XP(m_mat_H.block(0, il, il + 2, 2), m_n, il); + + m_ref_nr.coeffRef(il + 1) = 1; + return; + } + + // For block size >=3, use the regular strategy + // m20 = x21 * x10 + const Scalar m20 = m_mat_H.coeff(il + 2, il + 1) * m_mat_H.coeff(il + 1, il); + compute_reflector(m00, m10, m20, il); + + // Apply the first reflector + apply_PX(m_mat_H.block(il, il, 3, m_n - il), m_n, il); + apply_XP(m_mat_H.block(0, il, il + std::min(bsize, Index(4)), 3), m_n, il); + + // Calculate the following reflectors + // If entering this loop, block size is at least 4. + for(Index i = 1; i < bsize - 2; i++) + { + compute_reflector(&m_mat_H.coeffRef(il + i, il + i - 1), il + i); + // Apply the reflector to X + apply_PX(m_mat_H.block(il + i, il + i - 1, 3, m_n - il - i + 1), m_n, il + i); + apply_XP(m_mat_H.block(0, il + i, il + std::min(bsize, Index(i + 4)), 3), m_n, il + i); + } + + // The last reflector + // This causes nr=2 + compute_reflector(m_mat_H.coeff(iu - 1, iu - 2), m_mat_H.coeff(iu, iu - 2), 0, iu - 1); + // Apply the reflector to X + apply_PX(m_mat_H.block(iu - 1, iu - 2, 2, m_n - iu + 2), m_n, iu - 1); + apply_XP(m_mat_H.block(0, iu - 1, il + bsize, 2), m_n, iu - 1); + + m_ref_nr.coeffRef(iu) = 1; + } + + // P = I - 2 * u * u' = P' + // PX = X - 2 * u * (u'X) + void apply_PX(GenericMatrix X, Index stride, Index u_ind) const + { + const Index nr = m_ref_nr.coeff(u_ind); + if(nr == 1) + return; + + const Scalar u0 = m_ref_u.coeff(0, u_ind), + u1 = m_ref_u.coeff(1, u_ind); + const Scalar u0_2 = Scalar(2) * u0, + u1_2 = Scalar(2) * u1; + + const Index nrow = X.rows(); + const Index ncol = X.cols(); + + Scalar* xptr = X.data(); + if(nr == 2 || nrow == 2) + { + for(Index i = 0; i < ncol; i++, xptr += stride) + { + const Scalar tmp = u0_2 * xptr[0] + u1_2 * xptr[1]; + xptr[0] -= tmp * u0; + xptr[1] -= tmp * u1; + } + } else { + const Scalar u2 = m_ref_u.coeff(2, u_ind); + const Scalar u2_2 = Scalar(2) * u2; + for(Index i = 0; i < ncol; i++, xptr += stride) + { + const Scalar tmp = u0_2 * xptr[0] + u1_2 * xptr[1] + u2_2 * xptr[2]; + xptr[0] -= tmp * u0; + xptr[1] -= tmp * u1; + xptr[2] -= tmp * u2; + } + } + } + + // x is a pointer to a vector + // Px = x - 2 * dot(x, u) * u + void apply_PX(Scalar* x, Index u_ind) const + { + const Index nr = m_ref_nr.coeff(u_ind); + if(nr == 1) + return; + + const Scalar u0 = m_ref_u.coeff(0, u_ind), + u1 = m_ref_u.coeff(1, u_ind), + u2 = m_ref_u.coeff(2, u_ind); + + // When the reflector only contains two elements, u2 has been set to zero + const bool nr_is_2 = (nr == 2); + const Scalar dot2 = Scalar(2) * (x[0] * u0 + x[1] * u1 + (nr_is_2 ? 0 : (x[2] * u2))); + x[0] -= dot2 * u0; + x[1] -= dot2 * u1; + if(!nr_is_2) + x[2] -= dot2 * u2; + } + + // XP = X - 2 * (X * u) * u' + void apply_XP(GenericMatrix X, Index stride, Index u_ind) const + { + const Index nr = m_ref_nr.coeff(u_ind); + if(nr == 1) + return; + + const Scalar u0 = m_ref_u.coeff(0, u_ind), + u1 = m_ref_u.coeff(1, u_ind); + const Scalar u0_2 = Scalar(2) * u0, + u1_2 = Scalar(2) * u1; + + const int nrow = X.rows(); + const int ncol = X.cols(); + Scalar *X0 = X.data(), *X1 = X0 + stride; // X0 => X.col(0), X1 => X.col(1) + + if(nr == 2 || ncol == 2) + { + // tmp = 2 * u0 * X0 + 2 * u1 * X1 + // X0 => X0 - u0 * tmp + // X1 => X1 - u1 * tmp + for(Index i = 0; i < nrow; i++) + { + const Scalar tmp = u0_2 * X0[i] + u1_2 * X1[i]; + X0[i] -= tmp * u0; + X1[i] -= tmp * u1; + } + } else { + Scalar* X2 = X1 + stride; // X2 => X.col(2) + const Scalar u2 = m_ref_u.coeff(2, u_ind); + const Scalar u2_2 = Scalar(2) * u2; + for(Index i = 0; i < nrow; i++) + { + const Scalar tmp = u0_2 * X0[i] + u1_2 * X1[i] + u2_2 * X2[i]; + X0[i] -= tmp * u0; + X1[i] -= tmp * u1; + X2[i] -= tmp * u2; + } + } + } + +public: + DoubleShiftQR(Index size) : + m_n(size), + m_near_0(TypeTraits::min() * Scalar(10)), + m_eps(Eigen::NumTraits::epsilon()), + m_eps_rel(m_eps), + m_eps_abs(m_near_0 * (m_n / m_eps)), + m_computed(false) + {} + + DoubleShiftQR(ConstGenericMatrix& mat, const Scalar& s, const Scalar& t) : + m_n(mat.rows()), + m_mat_H(m_n, m_n), + m_shift_s(s), + m_shift_t(t), + m_ref_u(3, m_n), + m_ref_nr(m_n), + m_near_0(TypeTraits::min() * Scalar(10)), + m_eps(Eigen::NumTraits::epsilon()), + m_eps_rel(m_eps), + m_eps_abs(m_near_0 * (m_n / m_eps)), + m_computed(false) + { + compute(mat, s, t); + } + + void compute(ConstGenericMatrix& mat, const Scalar& s, const Scalar& t) + { + using std::abs; + + m_n = mat.rows(); + if(m_n != mat.cols()) + throw std::invalid_argument("DoubleShiftQR: matrix must be square"); + + m_mat_H.resize(m_n, m_n); + m_shift_s = s; + m_shift_t = t; + m_ref_u.resize(3, m_n); + m_ref_nr.resize(m_n); + + // Make a copy of mat + std::copy(mat.data(), mat.data() + mat.size(), m_mat_H.data()); + + // Obtain the indices of zero elements in the subdiagonal, + // so that H can be divided into several blocks + std::vector zero_ind; + zero_ind.reserve(m_n - 1); + zero_ind.push_back(0); + Scalar* Hii = m_mat_H.data(); + for(Index i = 0; i < m_n - 2; i++, Hii += (m_n + 1)) + { + // Hii[1] => m_mat_H(i + 1, i) + const Scalar h = abs(Hii[1]); + if(h <= 0 || h <= m_eps_rel * (abs(Hii[0]) + abs(Hii[m_n + 1]))) + { + Hii[1] = 0; + zero_ind.push_back(i + 1); + } + // Make sure m_mat_H is upper Hessenberg + // Zero the elements below m_mat_H(i + 1, i) + std::fill(Hii + 2, Hii + m_n - i, Scalar(0)); + } + zero_ind.push_back(m_n); + + for(std::vector::size_type i = 0; i < zero_ind.size() - 1; i++) + { + const Index start = zero_ind[i]; + const Index end = zero_ind[i + 1] - 1; + // Compute refelctors and update each block + update_block(start, end); + } + + m_computed = true; + } + + void matrix_QtHQ(Matrix& dest) const + { + if(!m_computed) + throw std::logic_error("DoubleShiftQR: need to call compute() first"); + + dest.noalias() = m_mat_H; + } + + // Q = P0 * P1 * ... + // Q'y = P_{n-2} * ... * P1 * P0 * y + void apply_QtY(Vector& y) const + { + if(!m_computed) + throw std::logic_error("DoubleShiftQR: need to call compute() first"); + + Scalar* y_ptr = y.data(); + const Index n1 = m_n - 1; + for(Index i = 0; i < n1; i++, y_ptr++) + { + apply_PX(y_ptr, i); + } + } + + // Q = P0 * P1 * ... + // YQ = Y * P0 * P1 * ... + void apply_YQ(GenericMatrix Y) const + { + if(!m_computed) + throw std::logic_error("DoubleShiftQR: need to call compute() first"); + + const Index nrow = Y.rows(); + const Index n2 = m_n - 2; + for(Index i = 0; i < n2; i++) + { + apply_XP(Y.block(0, i, nrow, 3), nrow, i); + } + apply_XP(Y.block(0, n2, nrow, 2), nrow, n2); + } +}; + + +} // namespace Spectra + +#endif // DOUBLE_SHIFT_QR_H diff --git a/external/Spectra/include/Spectra/LinAlg/Lanczos.h b/external/Spectra/include/Spectra/LinAlg/Lanczos.h new file mode 100644 index 000000000..2301dd308 --- /dev/null +++ b/external/Spectra/include/Spectra/LinAlg/Lanczos.h @@ -0,0 +1,170 @@ +// Copyright (C) 2018-2019 Yixuan Qiu +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at https://mozilla.org/MPL/2.0/. + +#ifndef LANCZOS_H +#define LANCZOS_H + +#include +#include // std::sqrt +#include // std::invalid_argument +#include // std::stringstream + +#include "Arnoldi.h" + +namespace Spectra { + + +// Lanczos factorization A * V = V * H + f * e' +// A: n x n +// V: n x k +// H: k x k +// f: n x 1 +// e: [0, ..., 0, 1] +// V and H are allocated of dimension m, so the maximum value of k is m +template +class Lanczos: public Arnoldi +{ +private: + typedef Eigen::Index Index; + typedef Eigen::Matrix Matrix; + typedef Eigen::Matrix Vector; + typedef Eigen::Map MapMat; + typedef Eigen::Map MapVec; + typedef Eigen::Map MapConstMat; + typedef Eigen::Map MapConstVec; + + using Arnoldi::m_op; + using Arnoldi::m_n; + using Arnoldi::m_m; + using Arnoldi::m_k; + using Arnoldi::m_fac_V; + using Arnoldi::m_fac_H; + using Arnoldi::m_fac_f; + using Arnoldi::m_beta; + using Arnoldi::m_near_0; + using Arnoldi::m_eps; + +public: + Lanczos(const ArnoldiOpType& op, Index m) : + Arnoldi(op, m) + {} + + // Lanczos factorization starting from step-k + void factorize_from(Index from_k, Index to_m, Index& op_counter) + { + using std::sqrt; + + if(to_m <= from_k) return; + + if(from_k > m_k) + { + std::stringstream msg; + msg << "Lanczos: from_k (= " << from_k << + ") is larger than the current subspace dimension (= " << + m_k << ")"; + throw std::invalid_argument(msg.str()); + } + + const Scalar beta_thresh = m_eps * sqrt(Scalar(m_n)); + + // Pre-allocate vectors + Vector Vf(to_m); + Vector w(m_n); + + // Keep the upperleft k x k submatrix of H and set other elements to 0 + m_fac_H.rightCols(m_m - from_k).setZero(); + m_fac_H.block(from_k, 0, m_m - from_k, from_k).setZero(); + + for(Index i = from_k; i <= to_m - 1; i++) + { + bool restart = false; + // If beta = 0, then the next V is not full rank + // We need to generate a new residual vector that is orthogonal + // to the current V, which we call a restart + if(m_beta < m_near_0) + { + MapConstMat V(m_fac_V.data(), m_n, i); // The first i columns + this->expand_basis(V, 2 * i, m_fac_f, m_beta); + restart = true; + } + + // v <- f / ||f|| + MapVec v(&m_fac_V(0, i), m_n); // The (i+1)-th column + v.noalias() = m_fac_f / m_beta; + + // Note that H[i+1, i] equals to the unrestarted beta + m_fac_H(i, i - 1) = restart ? Scalar(0) : m_beta; + + // w <- A * v + m_op.perform_op(v.data(), w.data()); + op_counter++; + + // H[i+1, i+1] = = v'Bw + m_fac_H(i - 1, i) = m_fac_H(i, i - 1); // Due to symmetry + m_fac_H(i, i) = m_op.inner_product(v, w); + + // f <- w - V * V'Bw = w - H[i+1, i] * V{i} - H[i+1, i+1] * V{i+1} + // If restarting, we know that H[i+1, i] = 0 + if(restart) + m_fac_f.noalias() = w - m_fac_H(i, i) * v; + else + m_fac_f.noalias() = w - m_fac_H(i, i - 1) * m_fac_V.col(i - 1) - m_fac_H(i, i) * v; + + m_beta = m_op.norm(m_fac_f); + + // f/||f|| is going to be the next column of V, so we need to test + // whether V'B(f/||f||) ~= 0 + const Index i1 = i + 1; + MapMat Vs(m_fac_V.data(), m_n, i1); // The first (i+1) columns + m_op.trans_product(Vs, m_fac_f, Vf.head(i1)); + Scalar ortho_err = Vf.head(i1).cwiseAbs().maxCoeff(); + // If not, iteratively correct the residual + int count = 0; + while(count < 5 && ortho_err > m_eps * m_beta) + { + // There is an edge case: when beta=||f|| is close to zero, f mostly consists + // of noises of rounding errors, so the test [ortho_err < eps * beta] is very + // likely to fail. In particular, if beta=0, then the test is ensured to fail. + // Hence when this happens, we force f to be zero, and then restart in the + // next iteration. + if(m_beta < beta_thresh) + { + m_fac_f.setZero(); + m_beta = Scalar(0); + break; + } + + // f <- f - V * Vf + m_fac_f.noalias() -= Vs * Vf.head(i1); + // h <- h + Vf + m_fac_H(i - 1, i) += Vf[i - 1]; + m_fac_H(i, i - 1) = m_fac_H(i - 1, i); + m_fac_H(i, i) += Vf[i]; + // beta <- ||f|| + m_beta = m_op.norm(m_fac_f); + + m_op.trans_product(Vs, m_fac_f, Vf.head(i1)); + ortho_err = Vf.head(i1).cwiseAbs().maxCoeff(); + count++; + } + } + + // Indicate that this is a step-m factorization + m_k = to_m; + } + + // Apply H -> Q'HQ, where Q is from a tridiagonal QR decomposition + void compress_H(const TridiagQR& decomp) + { + decomp.matrix_QtHQ(m_fac_H); + m_k--; + } +}; + + +} // namespace Spectra + +#endif // LANCZOS_H diff --git a/external/Spectra/include/Spectra/LinAlg/TridiagEigen.h b/external/Spectra/include/Spectra/LinAlg/TridiagEigen.h new file mode 100644 index 000000000..b79fe8d11 --- /dev/null +++ b/external/Spectra/include/Spectra/LinAlg/TridiagEigen.h @@ -0,0 +1,219 @@ +// The code was adapted from Eigen/src/Eigenvaleus/SelfAdjointEigenSolver.h +// +// Copyright (C) 2008-2010 Gael Guennebaud +// Copyright (C) 2010 Jitse Niesen +// Copyright (C) 2016-2019 Yixuan Qiu +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at https://mozilla.org/MPL/2.0/. + +#ifndef TRIDIAG_EIGEN_H +#define TRIDIAG_EIGEN_H + +#include +#include +#include + +#include "../Util/TypeTraits.h" + +namespace Spectra { + + +template +class TridiagEigen +{ +private: + typedef Eigen::Index Index; + // For convenience in adapting the tridiagonal_qr_step() function + typedef Scalar RealScalar; + + typedef Eigen::Matrix Matrix; + typedef Eigen::Matrix Vector; + + typedef Eigen::Ref GenericMatrix; + typedef const Eigen::Ref ConstGenericMatrix; + + Index m_n; + Vector m_main_diag; // Main diagonal elements of the matrix + Vector m_sub_diag; // Sub-diagonal elements of the matrix + Matrix m_evecs; // To store eigenvectors + + bool m_computed; + const Scalar m_near_0; // a very small value, ~= 1e-307 for the "double" type + + // Adapted from Eigen/src/Eigenvaleus/SelfAdjointEigenSolver.h + static void tridiagonal_qr_step(RealScalar* diag, + RealScalar* subdiag, Index start, + Index end, Scalar* matrixQ, + Index n) + { + using std::abs; + + RealScalar td = (diag[end-1] - diag[end]) * RealScalar(0.5); + RealScalar e = subdiag[end-1]; + // Note that thanks to scaling, e^2 or td^2 cannot overflow, however they can still + // underflow thus leading to inf/NaN values when using the following commented code: + // RealScalar e2 = numext::abs2(subdiag[end-1]); + // RealScalar mu = diag[end] - e2 / (td + (td>0 ? 1 : -1) * sqrt(td*td + e2)); + // This explain the following, somewhat more complicated, version: + RealScalar mu = diag[end]; + if(td == Scalar(0)) + mu -= abs(e); + else + { + RealScalar e2 = Eigen::numext::abs2(subdiag[end-1]); + RealScalar h = Eigen::numext::hypot(td, e); + if(e2==RealScalar(0)) mu -= (e / (td + (td>RealScalar(0) ? RealScalar(1) : RealScalar(-1)))) * (e / h); + else mu -= e2 / (td + (td>RealScalar(0) ? h : -h)); + } + + RealScalar x = diag[start] - mu; + RealScalar z = subdiag[start]; + Eigen::Map q(matrixQ, n, n); + for(Index k = start; k < end; ++k) + { + Eigen::JacobiRotation rot; + rot.makeGivens(x, z); + + const RealScalar s = rot.s(); + const RealScalar c = rot.c(); + + // do T = G' T G + RealScalar sdk = s * diag[k] + c * subdiag[k]; + RealScalar dkp1 = s * subdiag[k] + c * diag[k + 1]; + + diag[k] = c * (c * diag[k] - s * subdiag[k]) - s * (c * subdiag[k] - s * diag[k + 1]); + diag[k + 1] = s * sdk + c * dkp1; + subdiag[k] = c * sdk - s * dkp1; + + if(k > start) + subdiag[k - 1] = c * subdiag[k - 1] - s * z; + + x = subdiag[k]; + + if(k < end - 1) + { + z = -s * subdiag[k+1]; + subdiag[k + 1] = c * subdiag[k + 1]; + } + + // apply the givens rotation to the unit matrix Q = Q * G + if(matrixQ) + q.applyOnTheRight(k, k + 1, rot); + } + } + +public: + TridiagEigen() : + m_n(0), m_computed(false), + m_near_0(TypeTraits::min() * Scalar(10)) + {} + + TridiagEigen(ConstGenericMatrix& mat) : + m_n(mat.rows()), m_computed(false), + m_near_0(TypeTraits::min() * Scalar(10)) + { + compute(mat); + } + + void compute(ConstGenericMatrix& mat) + { + using std::abs; + + m_n = mat.rows(); + if(m_n != mat.cols()) + throw std::invalid_argument("TridiagEigen: matrix must be square"); + + m_main_diag.resize(m_n); + m_sub_diag.resize(m_n - 1); + m_evecs.resize(m_n, m_n); + m_evecs.setIdentity(); + + // Scale matrix to improve stability + const Scalar scale = std::max(mat.diagonal().cwiseAbs().maxCoeff(), + mat.diagonal(-1).cwiseAbs().maxCoeff()); + // If scale=0, mat is a zero matrix, so we can early stop + if(scale < m_near_0) + { + // m_main_diag contains eigenvalues + m_main_diag.setZero(); + // m_evecs has been set identity + // m_evecs.setIdentity(); + m_computed = true; + return; + } + m_main_diag.noalias() = mat.diagonal() / scale; + m_sub_diag.noalias() = mat.diagonal(-1) / scale; + + Scalar* diag = m_main_diag.data(); + Scalar* subdiag = m_sub_diag.data(); + + Index end = m_n - 1; + Index start = 0; + Index iter = 0; // total number of iterations + int info = 0; // 0 for success, 1 for failure + + const Scalar considerAsZero = TypeTraits::min(); + const Scalar precision = Scalar(2) * Eigen::NumTraits::epsilon(); + + while(end > 0) + { + for(Index i = start; i < end; i++) + if(abs(subdiag[i]) <= considerAsZero || + abs(subdiag[i]) <= (abs(diag[i]) + abs(diag[i + 1])) * precision) + subdiag[i] = 0; + + // find the largest unreduced block + while(end > 0 && subdiag[end - 1] == Scalar(0)) + end--; + + if(end <= 0) + break; + + // if we spent too many iterations, we give up + iter++; + if(iter > 30 * m_n) + { + info = 1; + break; + } + + start = end - 1; + while(start > 0 && subdiag[start - 1] != Scalar(0)) + start--; + + tridiagonal_qr_step(diag, subdiag, start, end, m_evecs.data(), m_n); + } + + if(info > 0) + throw std::runtime_error("TridiagEigen: eigen decomposition failed"); + + // Scale eigenvalues back + m_main_diag *= scale; + + m_computed = true; + } + + const Vector& eigenvalues() const + { + if(!m_computed) + throw std::logic_error("TridiagEigen: need to call compute() first"); + + // After calling compute(), main_diag will contain the eigenvalues. + return m_main_diag; + } + + const Matrix& eigenvectors() const + { + if(!m_computed) + throw std::logic_error("TridiagEigen: need to call compute() first"); + + return m_evecs; + } +}; + + +} // namespace Spectra + +#endif // TRIDIAG_EIGEN_H diff --git a/external/Spectra/include/Spectra/LinAlg/UpperHessenbergEigen.h b/external/Spectra/include/Spectra/LinAlg/UpperHessenbergEigen.h new file mode 100644 index 000000000..4e099f566 --- /dev/null +++ b/external/Spectra/include/Spectra/LinAlg/UpperHessenbergEigen.h @@ -0,0 +1,317 @@ +// The code was adapted from Eigen/src/Eigenvaleus/EigenSolver.h +// +// Copyright (C) 2008 Gael Guennebaud +// Copyright (C) 2010,2012 Jitse Niesen +// Copyright (C) 2016-2019 Yixuan Qiu +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at https://mozilla.org/MPL/2.0/. + +#ifndef UPPER_HESSENBERG_EIGEN_H +#define UPPER_HESSENBERG_EIGEN_H + +#include +#include +#include + +namespace Spectra { + + +template +class UpperHessenbergEigen +{ +private: + typedef Eigen::Index Index; + typedef Eigen::Matrix Matrix; + typedef Eigen::Matrix Vector; + + typedef Eigen::Ref GenericMatrix; + typedef const Eigen::Ref ConstGenericMatrix; + + typedef std::complex Complex; + typedef Eigen::Matrix ComplexMatrix; + typedef Eigen::Matrix ComplexVector; + + Index m_n; // Size of the matrix + Eigen::RealSchur m_realSchur; // Schur decomposition solver + Matrix m_matT; // Schur T matrix + Matrix m_eivec; // Storing eigenvectors + ComplexVector m_eivalues; // Eigenvalues + + bool m_computed; + + void doComputeEigenvectors() + { + using std::abs; + + const Index size = m_eivec.cols(); + const Scalar eps = Eigen::NumTraits::epsilon(); + + // inefficient! this is already computed in RealSchur + Scalar norm(0); + for(Index j = 0; j < size; ++j) + { + norm += m_matT.row(j).segment((std::max)(j-1, Index(0)), size-(std::max)(j-1, Index(0))).cwiseAbs().sum(); + } + + // Backsubstitute to find vectors of upper triangular form + if(norm == Scalar(0)) + return; + + for(Index n = size - 1; n >= 0; n--) + { + Scalar p = m_eivalues.coeff(n).real(); + Scalar q = m_eivalues.coeff(n).imag(); + + // Scalar vector + if(q == Scalar(0)) + { + Scalar lastr(0), lastw(0); + Index l = n; + + m_matT.coeffRef(n,n) = Scalar(1); + for(Index i = n-1; i >= 0; i--) + { + Scalar w = m_matT.coeff(i,i) - p; + Scalar r = m_matT.row(i).segment(l,n-l+1).dot(m_matT.col(n).segment(l, n-l+1)); + + if(m_eivalues.coeff(i).imag() < Scalar(0)) + { + lastw = w; + lastr = r; + } else { + l = i; + if(m_eivalues.coeff(i).imag() == Scalar(0)) + { + if (w != Scalar(0)) + m_matT.coeffRef(i,n) = -r / w; + else + m_matT.coeffRef(i,n) = -r / (eps * norm); + } + else // Solve real equations + { + Scalar x = m_matT.coeff(i,i+1); + Scalar y = m_matT.coeff(i+1,i); + Scalar denom = (m_eivalues.coeff(i).real() - p) * (m_eivalues.coeff(i).real() - p) + m_eivalues.coeff(i).imag() * m_eivalues.coeff(i).imag(); + Scalar t = (x * lastr - lastw * r) / denom; + m_matT.coeffRef(i,n) = t; + if(abs(x) > abs(lastw)) + m_matT.coeffRef(i+1,n) = (-r - w * t) / x; + else + m_matT.coeffRef(i+1,n) = (-lastr - y * t) / lastw; + } + + // Overflow control + Scalar t = abs(m_matT.coeff(i,n)); + if((eps * t) * t > Scalar(1)) + m_matT.col(n).tail(size-i) /= t; + } + } + } else if(q < Scalar(0) && n > 0) { // Complex vector + Scalar lastra(0), lastsa(0), lastw(0); + Index l = n-1; + + // Last vector component imaginary so matrix is triangular + if(abs(m_matT.coeff(n,n-1)) > abs(m_matT.coeff(n-1,n))) + { + m_matT.coeffRef(n-1,n-1) = q / m_matT.coeff(n,n-1); + m_matT.coeffRef(n-1,n) = -(m_matT.coeff(n,n) - p) / m_matT.coeff(n,n-1); + } + else + { + Complex cc = Complex(Scalar(0),-m_matT.coeff(n-1,n)) / Complex(m_matT.coeff(n-1,n-1)-p,q); + m_matT.coeffRef(n-1,n-1) = Eigen::numext::real(cc); + m_matT.coeffRef(n-1,n) = Eigen::numext::imag(cc); + } + m_matT.coeffRef(n,n-1) = Scalar(0); + m_matT.coeffRef(n,n) = Scalar(1); + for(Index i = n-2; i >= 0; i--) + { + Scalar ra = m_matT.row(i).segment(l, n-l+1).dot(m_matT.col(n-1).segment(l, n-l+1)); + Scalar sa = m_matT.row(i).segment(l, n-l+1).dot(m_matT.col(n).segment(l, n-l+1)); + Scalar w = m_matT.coeff(i,i) - p; + + if(m_eivalues.coeff(i).imag() < Scalar(0)) + { + lastw = w; + lastra = ra; + lastsa = sa; + } + else + { + l = i; + if(m_eivalues.coeff(i).imag() == Scalar(0)) + { + Complex cc = Complex(-ra,-sa) / Complex(w,q); + m_matT.coeffRef(i,n-1) = Eigen::numext::real(cc); + m_matT.coeffRef(i,n) = Eigen::numext::imag(cc); + } + else + { + // Solve complex equations + Scalar x = m_matT.coeff(i,i+1); + Scalar y = m_matT.coeff(i+1,i); + Scalar vr = (m_eivalues.coeff(i).real() - p) * (m_eivalues.coeff(i).real() - p) + m_eivalues.coeff(i).imag() * m_eivalues.coeff(i).imag() - q * q; + Scalar vi = (m_eivalues.coeff(i).real() - p) * Scalar(2) * q; + if((vr == Scalar(0)) && (vi == Scalar(0))) + vr = eps * norm * (abs(w) + abs(q) + abs(x) + abs(y) + abs(lastw)); + + Complex cc = Complex(x*lastra-lastw*ra+q*sa,x*lastsa-lastw*sa-q*ra) / Complex(vr,vi); + m_matT.coeffRef(i,n-1) = Eigen::numext::real(cc); + m_matT.coeffRef(i,n) = Eigen::numext::imag(cc); + if(abs(x) > (abs(lastw) + abs(q))) + { + m_matT.coeffRef(i+1,n-1) = (-ra - w * m_matT.coeff(i,n-1) + q * m_matT.coeff(i,n)) / x; + m_matT.coeffRef(i+1,n) = (-sa - w * m_matT.coeff(i,n) - q * m_matT.coeff(i,n-1)) / x; + } + else + { + cc = Complex(-lastra-y*m_matT.coeff(i,n-1),-lastsa-y*m_matT.coeff(i,n)) / Complex(lastw,q); + m_matT.coeffRef(i+1,n-1) = Eigen::numext::real(cc); + m_matT.coeffRef(i+1,n) = Eigen::numext::imag(cc); + } + } + + // Overflow control + Scalar t = std::max(abs(m_matT.coeff(i,n-1)), abs(m_matT.coeff(i,n))); + if((eps * t) * t > Scalar(1)) + m_matT.block(i, n-1, size-i, 2) /= t; + + } + } + + // We handled a pair of complex conjugate eigenvalues, so need to skip them both + n--; + } + } + + // Back transformation to get eigenvectors of original matrix + Vector m_tmp(size); + for(Index j = size-1; j >= 0; j--) + { + m_tmp.noalias() = m_eivec.leftCols(j+1) * m_matT.col(j).segment(0, j+1); + m_eivec.col(j) = m_tmp; + } + } + +public: + + UpperHessenbergEigen() : + m_n(0), m_computed(false) + {} + + UpperHessenbergEigen(ConstGenericMatrix& mat) : + m_n(mat.rows()), m_computed(false) + { + compute(mat); + } + + void compute(ConstGenericMatrix& mat) + { + using std::abs; + using std::sqrt; + + if(mat.rows() != mat.cols()) + throw std::invalid_argument("UpperHessenbergEigen: matrix must be square"); + + m_n = mat.rows(); + // Scale matrix prior to the Schur decomposition + const Scalar scale = mat.cwiseAbs().maxCoeff(); + + // Reduce to real Schur form + Matrix Q = Matrix::Identity(m_n, m_n); + m_realSchur.computeFromHessenberg(mat / scale, Q, true); + if(m_realSchur.info() != Eigen::Success) + throw std::runtime_error("UpperHessenbergEigen: eigen decomposition failed"); + + m_matT = m_realSchur.matrixT(); + m_eivec = m_realSchur.matrixU(); + + // Compute eigenvalues from matT + m_eivalues.resize(m_n); + Index i = 0; + while(i < m_n) + { + // Real eigenvalue + if(i == m_n - 1 || m_matT.coeff(i+1, i) == Scalar(0)) + { + m_eivalues.coeffRef(i) = m_matT.coeff(i, i); + ++i; + } + else // Complex eigenvalues + { + Scalar p = Scalar(0.5) * (m_matT.coeff(i, i) - m_matT.coeff(i+1, i+1)); + Scalar z; + // Compute z = sqrt(abs(p * p + m_matT.coeff(i+1, i) * m_matT.coeff(i, i+1))); + // without overflow + { + Scalar t0 = m_matT.coeff(i+1, i); + Scalar t1 = m_matT.coeff(i, i+1); + Scalar maxval = std::max(abs(p), std::max(abs(t0), abs(t1))); + t0 /= maxval; + t1 /= maxval; + Scalar p0 = p / maxval; + z = maxval * sqrt(abs(p0 * p0 + t0 * t1)); + } + m_eivalues.coeffRef(i) = Complex(m_matT.coeff(i+1, i+1) + p, z); + m_eivalues.coeffRef(i+1) = Complex(m_matT.coeff(i+1, i+1) + p, -z); + i += 2; + } + } + + // Compute eigenvectors + doComputeEigenvectors(); + + // Scale eigenvalues back + m_eivalues *= scale; + + m_computed = true; + } + + const ComplexVector& eigenvalues() const + { + if(!m_computed) + throw std::logic_error("UpperHessenbergEigen: need to call compute() first"); + + return m_eivalues; + } + + ComplexMatrix eigenvectors() + { + using std::abs; + + if(!m_computed) + throw std::logic_error("UpperHessenbergEigen: need to call compute() first"); + + Index n = m_eivec.cols(); + ComplexMatrix matV(n, n); + for(Index j = 0; j < n; ++j) + { + // imaginary part of real eigenvalue is already set to exact zero + if(Eigen::numext::imag(m_eivalues.coeff(j)) == Scalar(0) || j + 1 == n) + { + // we have a real eigen value + matV.col(j) = m_eivec.col(j).template cast(); + matV.col(j).normalize(); + } else { + // we have a pair of complex eigen values + for(Index i = 0; i < n; ++i) + { + matV.coeffRef(i,j) = Complex(m_eivec.coeff(i,j), m_eivec.coeff(i,j+1)); + matV.coeffRef(i,j+1) = Complex(m_eivec.coeff(i,j), -m_eivec.coeff(i,j+1)); + } + matV.col(j).normalize(); + matV.col(j+1).normalize(); + ++j; + } + } + + return matV; + } +}; + + +} // namespace Spectra + +#endif // UPPER_HESSENBERG_EIGEN_H diff --git a/external/Spectra/include/Spectra/LinAlg/UpperHessenbergQR.h b/external/Spectra/include/Spectra/LinAlg/UpperHessenbergQR.h new file mode 100644 index 000000000..a66d95980 --- /dev/null +++ b/external/Spectra/include/Spectra/LinAlg/UpperHessenbergQR.h @@ -0,0 +1,670 @@ +// Copyright (C) 2016-2019 Yixuan Qiu +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at https://mozilla.org/MPL/2.0/. + +#ifndef UPPER_HESSENBERG_QR_H +#define UPPER_HESSENBERG_QR_H + +#include +#include // std::sqrt +#include // std::fill, std::copy +#include // std::logic_error + +namespace Spectra { + + +/// +/// \defgroup Internals Internal Classes +/// +/// Classes for internal use. May be useful to developers. +/// + +/// +/// \ingroup Internals +/// @{ +/// + +/// +/// \defgroup LinearAlgebra Linear Algebra +/// +/// A number of classes for linear algebra operations. +/// + +/// +/// \ingroup LinearAlgebra +/// +/// Perform the QR decomposition of an upper Hessenberg matrix. +/// +/// \tparam Scalar The element type of the matrix. +/// Currently supported types are `float`, `double` and `long double`. +/// +template +class UpperHessenbergQR +{ +private: + typedef Eigen::Index Index; + typedef Eigen::Matrix Matrix; + typedef Eigen::Matrix Vector; + typedef Eigen::Matrix RowVector; + typedef Eigen::Array Array; + + typedef Eigen::Ref GenericMatrix; + typedef const Eigen::Ref ConstGenericMatrix; + + Matrix m_mat_T; + +protected: + Index m_n; + // Gi = [ cos[i] sin[i]] + // [-sin[i] cos[i]] + // Q = G1 * G2 * ... * G_{n-1} + Scalar m_shift; + Array m_rot_cos; + Array m_rot_sin; + bool m_computed; + + // Given x and y, compute 1) r = sqrt(x^2 + y^2), 2) c = x / r, 3) s = -y / r + // If both x and y are zero, set c = 1 and s = 0 + // We must implement it in a numerically stable way + static void compute_rotation(const Scalar& x, const Scalar& y, Scalar& r, Scalar& c, Scalar& s) + { + using std::sqrt; + + const Scalar xsign = (x > Scalar(0)) - (x < Scalar(0)); + const Scalar ysign = (y > Scalar(0)) - (y < Scalar(0)); + const Scalar xabs = x * xsign; + const Scalar yabs = y * ysign; + if(xabs > yabs) + { + // In this case xabs != 0 + const Scalar ratio = yabs / xabs; // so that 0 <= ratio < 1 + const Scalar common = sqrt(Scalar(1) + ratio * ratio); + c = xsign / common; + r = xabs * common; + s = -y / r; + } else { + if(yabs == Scalar(0)) + { + r = Scalar(0); c = Scalar(1); s = Scalar(0); + return; + } + const Scalar ratio = xabs / yabs; // so that 0 <= ratio <= 1 + const Scalar common = sqrt(Scalar(1) + ratio * ratio); + s = -ysign / common; + r = yabs * common; + c = x / r; + } + } + +public: + /// + /// Constructor to preallocate memory. Computation can + /// be performed later by calling the compute() method. + /// + UpperHessenbergQR(Index size) : + m_n(size), + m_rot_cos(m_n - 1), + m_rot_sin(m_n - 1), + m_computed(false) + {} + + /// + /// Constructor to create an object that performs and stores the + /// QR decomposition of an upper Hessenberg matrix `mat`, with an + /// optional shift: \f$H-sI=QR\f$. Here \f$H\f$ stands for the matrix + /// `mat`, and \f$s\f$ is the shift. + /// + /// \param mat Matrix type can be `Eigen::Matrix` (e.g. + /// `Eigen::MatrixXd` and `Eigen::MatrixXf`), or its mapped version + /// (e.g. `Eigen::Map`). + /// Only the upper triangular and the lower subdiagonal parts of + /// the matrix are used. + /// + UpperHessenbergQR(ConstGenericMatrix& mat, const Scalar& shift = Scalar(0)) : + m_n(mat.rows()), + m_shift(shift), + m_rot_cos(m_n - 1), + m_rot_sin(m_n - 1), + m_computed(false) + { + compute(mat, shift); + } + + /// + /// Virtual destructor. + /// + virtual ~UpperHessenbergQR() {}; + + /// + /// Conduct the QR factorization of an upper Hessenberg matrix with + /// an optional shift. + /// + /// \param mat Matrix type can be `Eigen::Matrix` (e.g. + /// `Eigen::MatrixXd` and `Eigen::MatrixXf`), or its mapped version + /// (e.g. `Eigen::Map`). + /// Only the upper triangular and the lower subdiagonal parts of + /// the matrix are used. + /// + virtual void compute(ConstGenericMatrix& mat, const Scalar& shift = Scalar(0)) + { + m_n = mat.rows(); + if(m_n != mat.cols()) + throw std::invalid_argument("UpperHessenbergQR: matrix must be square"); + + m_shift = shift; + m_mat_T.resize(m_n, m_n); + m_rot_cos.resize(m_n - 1); + m_rot_sin.resize(m_n - 1); + + // Make a copy of mat - s * I + std::copy(mat.data(), mat.data() + mat.size(), m_mat_T.data()); + m_mat_T.diagonal().array() -= m_shift; + + Scalar xi, xj, r, c, s; + Scalar *Tii, *ptr; + const Index n1 = m_n - 1; + for(Index i = 0; i < n1; i++) + { + Tii = &m_mat_T.coeffRef(i, i); + + // Make sure mat_T is upper Hessenberg + // Zero the elements below mat_T(i + 1, i) + std::fill(Tii + 2, Tii + m_n - i, Scalar(0)); + + xi = Tii[0]; // mat_T(i, i) + xj = Tii[1]; // mat_T(i + 1, i) + compute_rotation(xi, xj, r, c, s); + m_rot_cos[i] = c; + m_rot_sin[i] = s; + + // For a complete QR decomposition, + // we first obtain the rotation matrix + // G = [ cos sin] + // [-sin cos] + // and then do T[i:(i + 1), i:(n - 1)] = G' * T[i:(i + 1), i:(n - 1)] + + // Gt << c, -s, s, c; + // m_mat_T.block(i, i, 2, m_n - i) = Gt * m_mat_T.block(i, i, 2, m_n - i); + Tii[0] = r; // m_mat_T(i, i) => r + Tii[1] = 0; // m_mat_T(i + 1, i) => 0 + ptr = Tii + m_n; // m_mat_T(i, k), k = i+1, i+2, ..., n-1 + for(Index j = i + 1; j < m_n; j++, ptr += m_n) + { + Scalar tmp = ptr[0]; + ptr[0] = c * tmp - s * ptr[1]; + ptr[1] = s * tmp + c * ptr[1]; + } + + // If we do not need to calculate the R matrix, then + // only the cos and sin sequences are required. + // In such case we only update T[i + 1, (i + 1):(n - 1)] + // m_mat_T.block(i + 1, i + 1, 1, m_n - i - 1) *= c; + // m_mat_T.block(i + 1, i + 1, 1, m_n - i - 1) += s * mat_T.block(i, i + 1, 1, m_n - i - 1); + } + + m_computed = true; + } + + /// + /// Return the \f$R\f$ matrix in the QR decomposition, which is an + /// upper triangular matrix. + /// + /// \return Returned matrix type will be `Eigen::Matrix`, depending on + /// the template parameter `Scalar` defined. + /// + virtual Matrix matrix_R() const + { + if(!m_computed) + throw std::logic_error("UpperHessenbergQR: need to call compute() first"); + + return m_mat_T; + } + + /// + /// Overwrite `dest` with \f$Q'HQ = RQ + sI\f$, where \f$H\f$ is the input matrix `mat`, + /// and \f$s\f$ is the shift. The result is an upper Hessenberg matrix. + /// + /// \param mat The matrix to be overwritten, whose type should be `Eigen::Matrix`, + /// depending on the template parameter `Scalar` defined. + /// + virtual void matrix_QtHQ(Matrix& dest) const + { + if(!m_computed) + throw std::logic_error("UpperHessenbergQR: need to call compute() first"); + + // Make a copy of the R matrix + dest.resize(m_n, m_n); + std::copy(m_mat_T.data(), m_mat_T.data() + m_mat_T.size(), dest.data()); + + // Compute the RQ matrix + const Index n1 = m_n - 1; + for(Index i = 0; i < n1; i++) + { + const Scalar c = m_rot_cos.coeff(i); + const Scalar s = m_rot_sin.coeff(i); + // RQ[, i:(i + 1)] = RQ[, i:(i + 1)] * Gi + // Gi = [ cos[i] sin[i]] + // [-sin[i] cos[i]] + Scalar *Yi, *Yi1; + Yi = &dest.coeffRef(0, i); + Yi1 = Yi + m_n; // RQ(0, i + 1) + const Index i2 = i + 2; + for(Index j = 0; j < i2; j++) + { + const Scalar tmp = Yi[j]; + Yi[j] = c * tmp - s * Yi1[j]; + Yi1[j] = s * tmp + c * Yi1[j]; + } + + /* Vector dest = RQ.block(0, i, i + 2, 1); + dest.block(0, i, i + 2, 1) = c * Yi - s * dest.block(0, i + 1, i + 2, 1); + dest.block(0, i + 1, i + 2, 1) = s * Yi + c * dest.block(0, i + 1, i + 2, 1); */ + } + + // Add the shift to the diagonal + dest.diagonal().array() += m_shift; + } + + /// + /// Apply the \f$Q\f$ matrix to a vector \f$y\f$. + /// + /// \param Y A vector that will be overwritten by the matrix product \f$Qy\f$. + /// + /// Vector type can be `Eigen::Vector`, depending on + /// the template parameter `Scalar` defined. + /// + // Y -> QY = G1 * G2 * ... * Y + void apply_QY(Vector& Y) const + { + if(!m_computed) + throw std::logic_error("UpperHessenbergQR: need to call compute() first"); + + for(Index i = m_n - 2; i >= 0; i--) + { + const Scalar c = m_rot_cos.coeff(i); + const Scalar s = m_rot_sin.coeff(i); + // Y[i:(i + 1)] = Gi * Y[i:(i + 1)] + // Gi = [ cos[i] sin[i]] + // [-sin[i] cos[i]] + const Scalar tmp = Y[i]; + Y[i] = c * tmp + s * Y[i + 1]; + Y[i + 1] = -s * tmp + c * Y[i + 1]; + } + } + + /// + /// Apply the \f$Q\f$ matrix to a vector \f$y\f$. + /// + /// \param Y A vector that will be overwritten by the matrix product \f$Q'y\f$. + /// + /// Vector type can be `Eigen::Vector`, depending on + /// the template parameter `Scalar` defined. + /// + // Y -> Q'Y = G_{n-1}' * ... * G2' * G1' * Y + void apply_QtY(Vector& Y) const + { + if(!m_computed) + throw std::logic_error("UpperHessenbergQR: need to call compute() first"); + + const Index n1 = m_n - 1; + for(Index i = 0; i < n1; i++) + { + const Scalar c = m_rot_cos.coeff(i); + const Scalar s = m_rot_sin.coeff(i); + // Y[i:(i + 1)] = Gi' * Y[i:(i + 1)] + // Gi = [ cos[i] sin[i]] + // [-sin[i] cos[i]] + const Scalar tmp = Y[i]; + Y[i] = c * tmp - s * Y[i + 1]; + Y[i + 1] = s * tmp + c * Y[i + 1]; + } + } + + /// + /// Apply the \f$Q\f$ matrix to another matrix \f$Y\f$. + /// + /// \param Y A matrix that will be overwritten by the matrix product \f$QY\f$. + /// + /// Matrix type can be `Eigen::Matrix` (e.g. + /// `Eigen::MatrixXd` and `Eigen::MatrixXf`), or its mapped version + /// (e.g. `Eigen::Map`). + /// + // Y -> QY = G1 * G2 * ... * Y + void apply_QY(GenericMatrix Y) const + { + if(!m_computed) + throw std::logic_error("UpperHessenbergQR: need to call compute() first"); + + RowVector Yi(Y.cols()), Yi1(Y.cols()); + for(Index i = m_n - 2; i >= 0; i--) + { + const Scalar c = m_rot_cos.coeff(i); + const Scalar s = m_rot_sin.coeff(i); + // Y[i:(i + 1), ] = Gi * Y[i:(i + 1), ] + // Gi = [ cos[i] sin[i]] + // [-sin[i] cos[i]] + Yi.noalias() = Y.row(i); + Yi1.noalias() = Y.row(i + 1); + Y.row(i) = c * Yi + s * Yi1; + Y.row(i + 1) = -s * Yi + c * Yi1; + } + } + + /// + /// Apply the \f$Q\f$ matrix to another matrix \f$Y\f$. + /// + /// \param Y A matrix that will be overwritten by the matrix product \f$Q'Y\f$. + /// + /// Matrix type can be `Eigen::Matrix` (e.g. + /// `Eigen::MatrixXd` and `Eigen::MatrixXf`), or its mapped version + /// (e.g. `Eigen::Map`). + /// + // Y -> Q'Y = G_{n-1}' * ... * G2' * G1' * Y + void apply_QtY(GenericMatrix Y) const + { + if(!m_computed) + throw std::logic_error("UpperHessenbergQR: need to call compute() first"); + + RowVector Yi(Y.cols()), Yi1(Y.cols()); + const Index n1 = m_n - 1; + for(Index i = 0; i < n1; i++) + { + const Scalar c = m_rot_cos.coeff(i); + const Scalar s = m_rot_sin.coeff(i); + // Y[i:(i + 1), ] = Gi' * Y[i:(i + 1), ] + // Gi = [ cos[i] sin[i]] + // [-sin[i] cos[i]] + Yi.noalias() = Y.row(i); + Yi1.noalias() = Y.row(i + 1); + Y.row(i) = c * Yi - s * Yi1; + Y.row(i + 1) = s * Yi + c * Yi1; + } + } + + /// + /// Apply the \f$Q\f$ matrix to another matrix \f$Y\f$. + /// + /// \param Y A matrix that will be overwritten by the matrix product \f$YQ\f$. + /// + /// Matrix type can be `Eigen::Matrix` (e.g. + /// `Eigen::MatrixXd` and `Eigen::MatrixXf`), or its mapped version + /// (e.g. `Eigen::Map`). + /// + // Y -> YQ = Y * G1 * G2 * ... + void apply_YQ(GenericMatrix Y) const + { + if(!m_computed) + throw std::logic_error("UpperHessenbergQR: need to call compute() first"); + + /*Vector Yi(Y.rows()); + for(Index i = 0; i < m_n - 1; i++) + { + const Scalar c = m_rot_cos.coeff(i); + const Scalar s = m_rot_sin.coeff(i); + // Y[, i:(i + 1)] = Y[, i:(i + 1)] * Gi + // Gi = [ cos[i] sin[i]] + // [-sin[i] cos[i]] + Yi.noalias() = Y.col(i); + Y.col(i) = c * Yi - s * Y.col(i + 1); + Y.col(i + 1) = s * Yi + c * Y.col(i + 1); + }*/ + Scalar *Y_col_i, *Y_col_i1; + const Index n1 = m_n - 1; + const Index nrow = Y.rows(); + for(Index i = 0; i < n1; i++) + { + const Scalar c = m_rot_cos.coeff(i); + const Scalar s = m_rot_sin.coeff(i); + + Y_col_i = &Y.coeffRef(0, i); + Y_col_i1 = &Y.coeffRef(0, i + 1); + for(Index j = 0; j < nrow; j++) + { + Scalar tmp = Y_col_i[j]; + Y_col_i[j] = c * tmp - s * Y_col_i1[j]; + Y_col_i1[j] = s * tmp + c * Y_col_i1[j]; + } + } + } + + /// + /// Apply the \f$Q\f$ matrix to another matrix \f$Y\f$. + /// + /// \param Y A matrix that will be overwritten by the matrix product \f$YQ'\f$. + /// + /// Matrix type can be `Eigen::Matrix` (e.g. + /// `Eigen::MatrixXd` and `Eigen::MatrixXf`), or its mapped version + /// (e.g. `Eigen::Map`). + /// + // Y -> YQ' = Y * G_{n-1}' * ... * G2' * G1' + void apply_YQt(GenericMatrix Y) const + { + if(!m_computed) + throw std::logic_error("UpperHessenbergQR: need to call compute() first"); + + Vector Yi(Y.rows()); + for(Index i = m_n - 2; i >= 0; i--) + { + const Scalar c = m_rot_cos.coeff(i); + const Scalar s = m_rot_sin.coeff(i); + // Y[, i:(i + 1)] = Y[, i:(i + 1)] * Gi' + // Gi = [ cos[i] sin[i]] + // [-sin[i] cos[i]] + Yi.noalias() = Y.col(i); + Y.col(i) = c * Yi + s * Y.col(i + 1); + Y.col(i + 1) = -s * Yi + c * Y.col(i + 1); + } + } +}; + + + +/// +/// \ingroup LinearAlgebra +/// +/// Perform the QR decomposition of a tridiagonal matrix, a special +/// case of upper Hessenberg matrices. +/// +/// \tparam Scalar The element type of the matrix. +/// Currently supported types are `float`, `double` and `long double`. +/// +template +class TridiagQR: public UpperHessenbergQR +{ +private: + typedef Eigen::Matrix Matrix; + typedef Eigen::Matrix Vector; + typedef const Eigen::Ref ConstGenericMatrix; + + typedef typename Matrix::Index Index; + + Vector m_T_diag; // diagonal elements of T + Vector m_T_lsub; // lower subdiagonal of T + Vector m_T_usub; // upper subdiagonal of T + Vector m_T_usub2; // 2nd upper subdiagonal of T + +public: + /// + /// Constructor to preallocate memory. Computation can + /// be performed later by calling the compute() method. + /// + TridiagQR(Index size) : + UpperHessenbergQR(size) + {} + + /// + /// Constructor to create an object that performs and stores the + /// QR decomposition of an upper Hessenberg matrix `mat`, with an + /// optional shift: \f$H-sI=QR\f$. Here \f$H\f$ stands for the matrix + /// `mat`, and \f$s\f$ is the shift. + /// + /// \param mat Matrix type can be `Eigen::Matrix` (e.g. + /// `Eigen::MatrixXd` and `Eigen::MatrixXf`), or its mapped version + /// (e.g. `Eigen::Map`). + /// Only the major- and sub- diagonal parts of + /// the matrix are used. + /// + TridiagQR(ConstGenericMatrix& mat, const Scalar& shift = Scalar(0)) : + UpperHessenbergQR(mat.rows()) + { + this->compute(mat, shift); + } + + /// + /// Conduct the QR factorization of a tridiagonal matrix with an + /// optional shift. + /// + /// \param mat Matrix type can be `Eigen::Matrix` (e.g. + /// `Eigen::MatrixXd` and `Eigen::MatrixXf`), or its mapped version + /// (e.g. `Eigen::Map`). + /// Only the major- and sub- diagonal parts of + /// the matrix are used. + /// + void compute(ConstGenericMatrix& mat, const Scalar& shift = Scalar(0)) + { + this->m_n = mat.rows(); + if(this->m_n != mat.cols()) + throw std::invalid_argument("TridiagQR: matrix must be square"); + + this->m_shift = shift; + m_T_diag.resize(this->m_n); + m_T_lsub.resize(this->m_n - 1); + m_T_usub.resize(this->m_n - 1); + m_T_usub2.resize(this->m_n - 2); + this->m_rot_cos.resize(this->m_n - 1); + this->m_rot_sin.resize(this->m_n - 1); + + m_T_diag.array() = mat.diagonal().array() - this->m_shift; + m_T_lsub.noalias() = mat.diagonal(-1); + m_T_usub.noalias() = m_T_lsub; + + // A number of pointers to avoid repeated address calculation + Scalar *c = this->m_rot_cos.data(), // pointer to the cosine vector + *s = this->m_rot_sin.data(), // pointer to the sine vector + r; + const Index n1 = this->m_n - 1; + for(Index i = 0; i < n1; i++) + { + // diag[i] == T[i, i] + // lsub[i] == T[i + 1, i] + // r = sqrt(T[i, i]^2 + T[i + 1, i]^2) + // c = T[i, i] / r, s = -T[i + 1, i] / r + this->compute_rotation(m_T_diag.coeff(i), m_T_lsub.coeff(i), r, *c, *s); + + // For a complete QR decomposition, + // we first obtain the rotation matrix + // G = [ cos sin] + // [-sin cos] + // and then do T[i:(i + 1), i:(i + 2)] = G' * T[i:(i + 1), i:(i + 2)] + + // Update T[i, i] and T[i + 1, i] + // The updated value of T[i, i] is known to be r + // The updated value of T[i + 1, i] is known to be 0 + m_T_diag.coeffRef(i) = r; + m_T_lsub.coeffRef(i) = Scalar(0); + // Update T[i, i + 1] and T[i + 1, i + 1] + // usub[i] == T[i, i + 1] + // diag[i + 1] == T[i + 1, i + 1] + const Scalar tmp = m_T_usub.coeff(i); + m_T_usub.coeffRef(i) = (*c) * tmp - (*s) * m_T_diag.coeff(i + 1); + m_T_diag.coeffRef(i + 1) = (*s) * tmp + (*c) * m_T_diag.coeff(i + 1); + // Update T[i, i + 2] and T[i + 1, i + 2] + // usub2[i] == T[i, i + 2] + // usub[i + 1] == T[i + 1, i + 2] + if(i < n1 - 1) + { + m_T_usub2.coeffRef(i) = -(*s) * m_T_usub.coeff(i + 1); + m_T_usub.coeffRef(i + 1) *= (*c); + } + + c++; + s++; + + // If we do not need to calculate the R matrix, then + // only the cos and sin sequences are required. + // In such case we only update T[i + 1, (i + 1):(i + 2)] + // T[i + 1, i + 1] = c * T[i + 1, i + 1] + s * T[i, i + 1]; + // T[i + 1, i + 2] *= c; + } + + this->m_computed = true; + } + + /// + /// Return the \f$R\f$ matrix in the QR decomposition, which is an + /// upper triangular matrix. + /// + /// \return Returned matrix type will be `Eigen::Matrix`, depending on + /// the template parameter `Scalar` defined. + /// + Matrix matrix_R() const + { + if(!this->m_computed) + throw std::logic_error("TridiagQR: need to call compute() first"); + + Matrix R = Matrix::Zero(this->m_n, this->m_n); + R.diagonal().noalias() = m_T_diag; + R.diagonal(1).noalias() = m_T_usub; + R.diagonal(2).noalias() = m_T_usub2; + + return R; + } + + /// + /// Overwrite `dest` with \f$Q'HQ = RQ + sI\f$, where \f$H\f$ is the input matrix `mat`, + /// and \f$s\f$ is the shift. The result is a tridiagonal matrix. + /// + /// \param mat The matrix to be overwritten, whose type should be `Eigen::Matrix`, + /// depending on the template parameter `Scalar` defined. + /// + void matrix_QtHQ(Matrix& dest) const + { + if(!this->m_computed) + throw std::logic_error("TridiagQR: need to call compute() first"); + + // Make a copy of the R matrix + dest.resize(this->m_n, this->m_n); + dest.setZero(); + dest.diagonal().noalias() = m_T_diag; + // The upper diagonal refers to m_T_usub + // The 2nd upper subdiagonal will be zero in RQ + + // Compute the RQ matrix + // [m11 m12] points to RQ[i:(i+1), i:(i+1)] + // [0 m22] + // + // Gi = [ cos[i] sin[i]] + // [-sin[i] cos[i]] + const Index n1 = this->m_n - 1; + for(Index i = 0; i < n1; i++) + { + const Scalar c = this->m_rot_cos.coeff(i); + const Scalar s = this->m_rot_sin.coeff(i); + const Scalar m11 = dest.coeff(i, i), + m12 = m_T_usub.coeff(i), + m22 = m_T_diag.coeff(i + 1); + + // Update the diagonal and the lower subdiagonal of dest + dest.coeffRef(i , i ) = c * m11 - s * m12; + dest.coeffRef(i + 1, i ) = - s * m22; + dest.coeffRef(i + 1, i + 1) = c * m22; + } + + // Copy the lower subdiagonal to upper subdiagonal + dest.diagonal(1).noalias() = dest.diagonal(-1); + + // Add the shift to the diagonal + dest.diagonal().array() += this->m_shift; + } +}; + +/// +/// @} +/// + + +} // namespace Spectra + +#endif // UPPER_HESSENBERG_QR_H diff --git a/external/Spectra/include/Spectra/MatOp/DenseCholesky.h b/external/Spectra/include/Spectra/MatOp/DenseCholesky.h new file mode 100644 index 000000000..354c9508e --- /dev/null +++ b/external/Spectra/include/Spectra/MatOp/DenseCholesky.h @@ -0,0 +1,110 @@ +// Copyright (C) 2016-2019 Yixuan Qiu +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at https://mozilla.org/MPL/2.0/. + +#ifndef DENSE_CHOLESKY_H +#define DENSE_CHOLESKY_H + +#include +#include +#include +#include "../Util/CompInfo.h" + +namespace Spectra { + + +/// +/// \ingroup MatOp +/// +/// This class defines the operations related to Cholesky decomposition on a +/// positive definite matrix, \f$B=LL'\f$, where \f$L\f$ is a lower triangular +/// matrix. It is mainly used in the SymGEigsSolver generalized eigen solver +/// in the Cholesky decomposition mode. +/// +template +class DenseCholesky +{ +private: + typedef Eigen::Index Index; + typedef Eigen::Matrix Matrix; + typedef Eigen::Matrix Vector; + typedef Eigen::Map MapConstMat; + typedef Eigen::Map MapConstVec; + typedef Eigen::Map MapVec; + typedef const Eigen::Ref ConstGenericMatrix; + + const Index m_n; + Eigen::LLT m_decomp; + int m_info; // status of the decomposition + +public: + /// + /// Constructor to create the matrix operation object. + /// + /// \param mat An **Eigen** matrix object, whose type can be + /// `Eigen::Matrix` (e.g. `Eigen::MatrixXd` and + /// `Eigen::MatrixXf`), or its mapped version + /// (e.g. `Eigen::Map`). + /// + DenseCholesky(ConstGenericMatrix& mat) : + m_n(mat.rows()), m_info(NOT_COMPUTED) + { + if(mat.rows() != mat.cols()) + throw std::invalid_argument("DenseCholesky: matrix must be square"); + + m_decomp.compute(mat); + m_info = (m_decomp.info() == Eigen::Success) ? + SUCCESSFUL : + NUMERICAL_ISSUE; + } + + /// + /// Returns the number of rows of the underlying matrix. + /// + Index rows() const { return m_n; } + /// + /// Returns the number of columns of the underlying matrix. + /// + Index cols() const { return m_n; } + + /// + /// Returns the status of the computation. + /// The full list of enumeration values can be found in \ref Enumerations. + /// + int info() const { return m_info; } + + /// + /// Performs the lower triangular solving operation \f$y=L^{-1}x\f$. + /// + /// \param x_in Pointer to the \f$x\f$ vector. + /// \param y_out Pointer to the \f$y\f$ vector. + /// + // y_out = inv(L) * x_in + void lower_triangular_solve(const Scalar* x_in, Scalar* y_out) const + { + MapConstVec x(x_in, m_n); + MapVec y(y_out, m_n); + y.noalias() = m_decomp.matrixL().solve(x); + } + + /// + /// Performs the upper triangular solving operation \f$y=(L')^{-1}x\f$. + /// + /// \param x_in Pointer to the \f$x\f$ vector. + /// \param y_out Pointer to the \f$y\f$ vector. + /// + // y_out = inv(L') * x_in + void upper_triangular_solve(const Scalar* x_in, Scalar* y_out) const + { + MapConstVec x(x_in, m_n); + MapVec y(y_out, m_n); + y.noalias() = m_decomp.matrixU().solve(x); + } +}; + + +} // namespace Spectra + +#endif // DENSE_CHOLESKY_H diff --git a/external/Spectra/include/Spectra/MatOp/DenseGenComplexShiftSolve.h b/external/Spectra/include/Spectra/MatOp/DenseGenComplexShiftSolve.h new file mode 100644 index 000000000..7f189067c --- /dev/null +++ b/external/Spectra/include/Spectra/MatOp/DenseGenComplexShiftSolve.h @@ -0,0 +1,104 @@ +// Copyright (C) 2016-2019 Yixuan Qiu +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at https://mozilla.org/MPL/2.0/. + +#ifndef DENSE_GEN_COMPLEX_SHIFT_SOLVE_H +#define DENSE_GEN_COMPLEX_SHIFT_SOLVE_H + +#include +#include +#include + +namespace Spectra { + + +/// +/// \ingroup MatOp +/// +/// This class defines the complex shift-solve operation on a general real matrix \f$A\f$, +/// i.e., calculating \f$y=\mathrm{Re}\{(A-\sigma I)^{-1}x\}\f$ for any complex-valued +/// \f$\sigma\f$ and real-valued vector \f$x\f$. It is mainly used in the +/// GenEigsComplexShiftSolver eigen solver. +/// +template +class DenseGenComplexShiftSolve +{ +private: + typedef Eigen::Index Index; + typedef Eigen::Matrix Matrix; + typedef Eigen::Matrix Vector; + typedef Eigen::Map MapConstVec; + typedef Eigen::Map MapVec; + typedef const Eigen::Ref ConstGenericMatrix; + + typedef std::complex Complex; + typedef Eigen::Matrix ComplexMatrix; + typedef Eigen::Matrix ComplexVector; + + typedef Eigen::PartialPivLU ComplexSolver; + + ConstGenericMatrix m_mat; + const Index m_n; + ComplexSolver m_solver; + ComplexVector m_x_cache; + +public: + /// + /// Constructor to create the matrix operation object. + /// + /// \param mat An **Eigen** matrix object, whose type can be + /// `Eigen::Matrix` (e.g. `Eigen::MatrixXd` and + /// `Eigen::MatrixXf`), or its mapped version + /// (e.g. `Eigen::Map`). + /// + DenseGenComplexShiftSolve(ConstGenericMatrix& mat) : + m_mat(mat), m_n(mat.rows()) + { + if(mat.rows() != mat.cols()) + throw std::invalid_argument("DenseGenComplexShiftSolve: matrix must be square"); + } + + /// + /// Return the number of rows of the underlying matrix. + /// + Index rows() const { return m_n; } + /// + /// Return the number of columns of the underlying matrix. + /// + Index cols() const { return m_n; } + + /// + /// Set the complex shift \f$\sigma\f$. + /// + /// \param sigmar Real part of \f$\sigma\f$. + /// \param sigmai Imaginary part of \f$\sigma\f$. + /// + void set_shift(Scalar sigmar, Scalar sigmai) + { + m_solver.compute(m_mat.template cast() - Complex(sigmar, sigmai) * ComplexMatrix::Identity(m_n, m_n)); + m_x_cache.resize(m_n); + m_x_cache.setZero(); + } + + /// + /// Perform the complex shift-solve operation + /// \f$y=\mathrm{Re}\{(A-\sigma I)^{-1}x\}\f$. + /// + /// \param x_in Pointer to the \f$x\f$ vector. + /// \param y_out Pointer to the \f$y\f$ vector. + /// + // y_out = Re( inv(A - sigma * I) * x_in ) + void perform_op(const Scalar* x_in, Scalar* y_out) + { + m_x_cache.real() = MapConstVec(x_in, m_n); + MapVec y(y_out, m_n); + y.noalias() = m_solver.solve(m_x_cache).real(); + } +}; + + +} // namespace Spectra + +#endif // DENSE_GEN_COMPLEX_SHIFT_SOLVE_H diff --git a/external/Spectra/include/Spectra/MatOp/DenseGenMatProd.h b/external/Spectra/include/Spectra/MatOp/DenseGenMatProd.h new file mode 100644 index 000000000..6933dac05 --- /dev/null +++ b/external/Spectra/include/Spectra/MatOp/DenseGenMatProd.h @@ -0,0 +1,82 @@ +// Copyright (C) 2016-2019 Yixuan Qiu +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at https://mozilla.org/MPL/2.0/. + +#ifndef DENSE_GEN_MAT_PROD_H +#define DENSE_GEN_MAT_PROD_H + +#include + +namespace Spectra { + + +/// +/// \defgroup MatOp Matrix Operations +/// +/// Define matrix operations on existing matrix objects +/// + +/// +/// \ingroup MatOp +/// +/// This class defines the matrix-vector multiplication operation on a +/// general real matrix \f$A\f$, i.e., calculating \f$y=Ax\f$ for any vector +/// \f$x\f$. It is mainly used in the GenEigsSolver and +/// SymEigsSolver eigen solvers. +/// +template +class DenseGenMatProd +{ +private: + typedef Eigen::Index Index; + typedef Eigen::Matrix Matrix; + typedef Eigen::Matrix Vector; + typedef Eigen::Map MapConstVec; + typedef Eigen::Map MapVec; + typedef const Eigen::Ref ConstGenericMatrix; + + ConstGenericMatrix m_mat; + +public: + /// + /// Constructor to create the matrix operation object. + /// + /// \param mat An **Eigen** matrix object, whose type can be + /// `Eigen::Matrix` (e.g. `Eigen::MatrixXd` and + /// `Eigen::MatrixXf`), or its mapped version + /// (e.g. `Eigen::Map`). + /// + DenseGenMatProd(ConstGenericMatrix& mat) : + m_mat(mat) + {} + + /// + /// Return the number of rows of the underlying matrix. + /// + Index rows() const { return m_mat.rows(); } + /// + /// Return the number of columns of the underlying matrix. + /// + Index cols() const { return m_mat.cols(); } + + /// + /// Perform the matrix-vector multiplication operation \f$y=Ax\f$. + /// + /// \param x_in Pointer to the \f$x\f$ vector. + /// \param y_out Pointer to the \f$y\f$ vector. + /// + // y_out = A * x_in + void perform_op(const Scalar* x_in, Scalar* y_out) const + { + MapConstVec x(x_in, m_mat.cols()); + MapVec y(y_out, m_mat.rows()); + y.noalias() = m_mat * x; + } +}; + + +} // namespace Spectra + +#endif // DENSE_GEN_MAT_PROD_H diff --git a/external/Spectra/include/Spectra/MatOp/DenseGenRealShiftSolve.h b/external/Spectra/include/Spectra/MatOp/DenseGenRealShiftSolve.h new file mode 100644 index 000000000..d7ba8f2a2 --- /dev/null +++ b/external/Spectra/include/Spectra/MatOp/DenseGenRealShiftSolve.h @@ -0,0 +1,90 @@ +// Copyright (C) 2016-2019 Yixuan Qiu +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at https://mozilla.org/MPL/2.0/. + +#ifndef DENSE_GEN_REAL_SHIFT_SOLVE_H +#define DENSE_GEN_REAL_SHIFT_SOLVE_H + +#include +#include +#include + +namespace Spectra { + + +/// +/// \ingroup MatOp +/// +/// This class defines the shift-solve operation on a general real matrix \f$A\f$, +/// i.e., calculating \f$y=(A-\sigma I)^{-1}x\f$ for any real \f$\sigma\f$ and +/// vector \f$x\f$. It is mainly used in the GenEigsRealShiftSolver eigen solver. +/// +template +class DenseGenRealShiftSolve +{ +private: + typedef Eigen::Index Index; + typedef Eigen::Matrix Matrix; + typedef Eigen::Matrix Vector; + typedef Eigen::Map MapConstVec; + typedef Eigen::Map MapVec; + typedef const Eigen::Ref ConstGenericMatrix; + + ConstGenericMatrix m_mat; + const Index m_n; + Eigen::PartialPivLU m_solver; + +public: + /// + /// Constructor to create the matrix operation object. + /// + /// \param mat An **Eigen** matrix object, whose type can be + /// `Eigen::Matrix` (e.g. `Eigen::MatrixXd` and + /// `Eigen::MatrixXf`), or its mapped version + /// (e.g. `Eigen::Map`). + /// + DenseGenRealShiftSolve(ConstGenericMatrix& mat) : + m_mat(mat), m_n(mat.rows()) + { + if(mat.rows() != mat.cols()) + throw std::invalid_argument("DenseGenRealShiftSolve: matrix must be square"); + } + + /// + /// Return the number of rows of the underlying matrix. + /// + Index rows() const { return m_n; } + /// + /// Return the number of columns of the underlying matrix. + /// + Index cols() const { return m_n; } + + /// + /// Set the real shift \f$\sigma\f$. + /// + void set_shift(Scalar sigma) + { + m_solver.compute(m_mat - sigma * Matrix::Identity(m_n, m_n)); + } + + /// + /// Perform the shift-solve operation \f$y=(A-\sigma I)^{-1}x\f$. + /// + /// \param x_in Pointer to the \f$x\f$ vector. + /// \param y_out Pointer to the \f$y\f$ vector. + /// + // y_out = inv(A - sigma * I) * x_in + void perform_op(const Scalar* x_in, Scalar* y_out) const + { + MapConstVec x(x_in, m_n); + MapVec y(y_out, m_n); + y.noalias() = m_solver.solve(x); + } +}; + + +} // namespace Spectra + +#endif // DENSE_GEN_REAL_SHIFT_SOLVE_H diff --git a/external/Spectra/include/Spectra/MatOp/DenseSymMatProd.h b/external/Spectra/include/Spectra/MatOp/DenseSymMatProd.h new file mode 100644 index 000000000..23ca36e43 --- /dev/null +++ b/external/Spectra/include/Spectra/MatOp/DenseSymMatProd.h @@ -0,0 +1,75 @@ +// Copyright (C) 2016-2019 Yixuan Qiu +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at https://mozilla.org/MPL/2.0/. + +#ifndef DENSE_SYM_MAT_PROD_H +#define DENSE_SYM_MAT_PROD_H + +#include + +namespace Spectra { + + +/// +/// \ingroup MatOp +/// +/// This class defines the matrix-vector multiplication operation on a +/// symmetric real matrix \f$A\f$, i.e., calculating \f$y=Ax\f$ for any vector +/// \f$x\f$. It is mainly used in the SymEigsSolver eigen solver. +/// +template +class DenseSymMatProd +{ +private: + typedef Eigen::Index Index; + typedef Eigen::Matrix Matrix; + typedef Eigen::Matrix Vector; + typedef Eigen::Map MapConstVec; + typedef Eigen::Map MapVec; + typedef const Eigen::Ref ConstGenericMatrix; + + ConstGenericMatrix m_mat; + +public: + /// + /// Constructor to create the matrix operation object. + /// + /// \param mat An **Eigen** matrix object, whose type can be + /// `Eigen::Matrix` (e.g. `Eigen::MatrixXd` and + /// `Eigen::MatrixXf`), or its mapped version + /// (e.g. `Eigen::Map`). + /// + DenseSymMatProd(ConstGenericMatrix& mat) : + m_mat(mat) + {} + + /// + /// Return the number of rows of the underlying matrix. + /// + Index rows() const { return m_mat.rows(); } + /// + /// Return the number of columns of the underlying matrix. + /// + Index cols() const { return m_mat.cols(); } + + /// + /// Perform the matrix-vector multiplication operation \f$y=Ax\f$. + /// + /// \param x_in Pointer to the \f$x\f$ vector. + /// \param y_out Pointer to the \f$y\f$ vector. + /// + // y_out = A * x_in + void perform_op(const Scalar* x_in, Scalar* y_out) const + { + MapConstVec x(x_in, m_mat.cols()); + MapVec y(y_out, m_mat.rows()); + y.noalias() = m_mat.template selfadjointView() * x; + } +}; + + +} // namespace Spectra + +#endif // DENSE_SYM_MAT_PROD_H diff --git a/external/Spectra/include/Spectra/MatOp/DenseSymShiftSolve.h b/external/Spectra/include/Spectra/MatOp/DenseSymShiftSolve.h new file mode 100644 index 000000000..2e2c67f6b --- /dev/null +++ b/external/Spectra/include/Spectra/MatOp/DenseSymShiftSolve.h @@ -0,0 +1,94 @@ +// Copyright (C) 2016-2019 Yixuan Qiu +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at https://mozilla.org/MPL/2.0/. + +#ifndef DENSE_SYM_SHIFT_SOLVE_H +#define DENSE_SYM_SHIFT_SOLVE_H + +#include +#include + +#include "../LinAlg/BKLDLT.h" +#include "../Util/CompInfo.h" + +namespace Spectra { + + +/// +/// \ingroup MatOp +/// +/// This class defines the shift-solve operation on a real symmetric matrix \f$A\f$, +/// i.e., calculating \f$y=(A-\sigma I)^{-1}x\f$ for any real \f$\sigma\f$ and +/// vector \f$x\f$. It is mainly used in the SymEigsShiftSolver eigen solver. +/// +template +class DenseSymShiftSolve +{ +private: + typedef Eigen::Index Index; + typedef Eigen::Matrix Matrix; + typedef Eigen::Matrix Vector; + typedef Eigen::Map MapConstVec; + typedef Eigen::Map MapVec; + typedef const Eigen::Ref ConstGenericMatrix; + + ConstGenericMatrix m_mat; + const int m_n; + BKLDLT m_solver; + +public: + /// + /// Constructor to create the matrix operation object. + /// + /// \param mat An **Eigen** matrix object, whose type can be + /// `Eigen::Matrix` (e.g. `Eigen::MatrixXd` and + /// `Eigen::MatrixXf`), or its mapped version + /// (e.g. `Eigen::Map`). + /// + DenseSymShiftSolve(ConstGenericMatrix& mat) : + m_mat(mat), m_n(mat.rows()) + { + if(mat.rows() != mat.cols()) + throw std::invalid_argument("DenseSymShiftSolve: matrix must be square"); + } + + /// + /// Return the number of rows of the underlying matrix. + /// + Index rows() const { return m_n; } + /// + /// Return the number of columns of the underlying matrix. + /// + Index cols() const { return m_n; } + + /// + /// Set the real shift \f$\sigma\f$. + /// + void set_shift(Scalar sigma) + { + m_solver.compute(m_mat, Uplo, sigma); + if(m_solver.info() != SUCCESSFUL) + throw std::invalid_argument("DenseSymShiftSolve: factorization failed with the given shift"); + } + + /// + /// Perform the shift-solve operation \f$y=(A-\sigma I)^{-1}x\f$. + /// + /// \param x_in Pointer to the \f$x\f$ vector. + /// \param y_out Pointer to the \f$y\f$ vector. + /// + // y_out = inv(A - sigma * I) * x_in + void perform_op(const Scalar* x_in, Scalar* y_out) const + { + MapConstVec x(x_in, m_n); + MapVec y(y_out, m_n); + y.noalias() = m_solver.solve(x); + } +}; + + +} // namespace Spectra + +#endif // DENSE_SYM_SHIFT_SOLVE_H diff --git a/external/Spectra/include/Spectra/MatOp/SparseCholesky.h b/external/Spectra/include/Spectra/MatOp/SparseCholesky.h new file mode 100644 index 000000000..0788596dd --- /dev/null +++ b/external/Spectra/include/Spectra/MatOp/SparseCholesky.h @@ -0,0 +1,111 @@ +// Copyright (C) 2016-2019 Yixuan Qiu +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at https://mozilla.org/MPL/2.0/. + +#ifndef SPARSE_CHOLESKY_H +#define SPARSE_CHOLESKY_H + +#include +#include +#include +#include +#include "../Util/CompInfo.h" + +namespace Spectra { + + +/// +/// \ingroup MatOp +/// +/// This class defines the operations related to Cholesky decomposition on a +/// sparse positive definite matrix, \f$B=LL'\f$, where \f$L\f$ is a lower triangular +/// matrix. It is mainly used in the SymGEigsSolver generalized eigen solver +/// in the Cholesky decomposition mode. +/// +template +class SparseCholesky +{ +private: + typedef Eigen::Index Index; + typedef Eigen::Matrix Vector; + typedef Eigen::Map MapConstVec; + typedef Eigen::Map MapVec; + typedef Eigen::SparseMatrix SparseMatrix; + typedef const Eigen::Ref ConstGenericSparseMatrix; + + const Index m_n; + Eigen::SimplicialLLT m_decomp; + int m_info; // status of the decomposition + +public: + /// + /// Constructor to create the matrix operation object. + /// + /// \param mat An **Eigen** sparse matrix object, whose type can be + /// `Eigen::SparseMatrix` or its mapped version + /// `Eigen::Map >`. + /// + SparseCholesky(ConstGenericSparseMatrix& mat) : + m_n(mat.rows()) + { + if(mat.rows() != mat.cols()) + throw std::invalid_argument("SparseCholesky: matrix must be square"); + + m_decomp.compute(mat); + m_info = (m_decomp.info() == Eigen::Success) ? + SUCCESSFUL : + NUMERICAL_ISSUE; + } + + /// + /// Returns the number of rows of the underlying matrix. + /// + Index rows() const { return m_n; } + /// + /// Returns the number of columns of the underlying matrix. + /// + Index cols() const { return m_n; } + + /// + /// Returns the status of the computation. + /// The full list of enumeration values can be found in \ref Enumerations. + /// + int info() const { return m_info; } + + /// + /// Performs the lower triangular solving operation \f$y=L^{-1}x\f$. + /// + /// \param x_in Pointer to the \f$x\f$ vector. + /// \param y_out Pointer to the \f$y\f$ vector. + /// + // y_out = inv(L) * x_in + void lower_triangular_solve(const Scalar* x_in, Scalar* y_out) const + { + MapConstVec x(x_in, m_n); + MapVec y(y_out, m_n); + y.noalias() = m_decomp.permutationP() * x; + m_decomp.matrixL().solveInPlace(y); + } + + /// + /// Performs the upper triangular solving operation \f$y=(L')^{-1}x\f$. + /// + /// \param x_in Pointer to the \f$x\f$ vector. + /// \param y_out Pointer to the \f$y\f$ vector. + /// + // y_out = inv(L') * x_in + void upper_triangular_solve(const Scalar* x_in, Scalar* y_out) const + { + MapConstVec x(x_in, m_n); + MapVec y(y_out, m_n); + y.noalias() = m_decomp.matrixU().solve(x); + y = m_decomp.permutationPinv() * y; + } +}; + + +} // namespace Spectra + +#endif // SPARSE_CHOLESKY_H diff --git a/external/Spectra/include/Spectra/MatOp/SparseGenMatProd.h b/external/Spectra/include/Spectra/MatOp/SparseGenMatProd.h new file mode 100644 index 000000000..908813957 --- /dev/null +++ b/external/Spectra/include/Spectra/MatOp/SparseGenMatProd.h @@ -0,0 +1,76 @@ +// Copyright (C) 2016-2019 Yixuan Qiu +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at https://mozilla.org/MPL/2.0/. + +#ifndef SPARSE_GEN_MAT_PROD_H +#define SPARSE_GEN_MAT_PROD_H + +#include +#include + +namespace Spectra { + + +/// +/// \ingroup MatOp +/// +/// This class defines the matrix-vector multiplication operation on a +/// sparse real matrix \f$A\f$, i.e., calculating \f$y=Ax\f$ for any vector +/// \f$x\f$. It is mainly used in the GenEigsSolver and SymEigsSolver +/// eigen solvers. +/// +template +class SparseGenMatProd +{ +private: + typedef Eigen::Index Index; + typedef Eigen::Matrix Vector; + typedef Eigen::Map MapConstVec; + typedef Eigen::Map MapVec; + typedef Eigen::SparseMatrix SparseMatrix; + typedef const Eigen::Ref ConstGenericSparseMatrix; + + ConstGenericSparseMatrix m_mat; + +public: + /// + /// Constructor to create the matrix operation object. + /// + /// \param mat An **Eigen** sparse matrix object, whose type can be + /// `Eigen::SparseMatrix` or its mapped version + /// `Eigen::Map >`. + /// + SparseGenMatProd(ConstGenericSparseMatrix& mat) : + m_mat(mat) + {} + + /// + /// Return the number of rows of the underlying matrix. + /// + Index rows() const { return m_mat.rows(); } + /// + /// Return the number of columns of the underlying matrix. + /// + Index cols() const { return m_mat.cols(); } + + /// + /// Perform the matrix-vector multiplication operation \f$y=Ax\f$. + /// + /// \param x_in Pointer to the \f$x\f$ vector. + /// \param y_out Pointer to the \f$y\f$ vector. + /// + // y_out = A * x_in + void perform_op(const Scalar* x_in, Scalar* y_out) const + { + MapConstVec x(x_in, m_mat.cols()); + MapVec y(y_out, m_mat.rows()); + y.noalias() = m_mat * x; + } +}; + + +} // namespace Spectra + +#endif // SPARSE_GEN_MAT_PROD_H diff --git a/external/Spectra/include/Spectra/MatOp/SparseGenRealShiftSolve.h b/external/Spectra/include/Spectra/MatOp/SparseGenRealShiftSolve.h new file mode 100644 index 000000000..df4ec6cf6 --- /dev/null +++ b/external/Spectra/include/Spectra/MatOp/SparseGenRealShiftSolve.h @@ -0,0 +1,95 @@ +// Copyright (C) 2016-2019 Yixuan Qiu +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at https://mozilla.org/MPL/2.0/. + +#ifndef SPARSE_GEN_REAL_SHIFT_SOLVE_H +#define SPARSE_GEN_REAL_SHIFT_SOLVE_H + +#include +#include +#include +#include + +namespace Spectra { + + +/// +/// \ingroup MatOp +/// +/// This class defines the shift-solve operation on a sparse real matrix \f$A\f$, +/// i.e., calculating \f$y=(A-\sigma I)^{-1}x\f$ for any real \f$\sigma\f$ and +/// vector \f$x\f$. It is mainly used in the GenEigsRealShiftSolver eigen solver. +/// +template +class SparseGenRealShiftSolve +{ +private: + typedef Eigen::Index Index; + typedef Eigen::Matrix Vector; + typedef Eigen::Map MapConstVec; + typedef Eigen::Map MapVec; + typedef Eigen::SparseMatrix SparseMatrix; + typedef const Eigen::Ref ConstGenericSparseMatrix; + + ConstGenericSparseMatrix m_mat; + const int m_n; + Eigen::SparseLU m_solver; + +public: + /// + /// Constructor to create the matrix operation object. + /// + /// \param mat An **Eigen** sparse matrix object, whose type can be + /// `Eigen::SparseMatrix` or its mapped version + /// `Eigen::Map >`. + /// + SparseGenRealShiftSolve(ConstGenericSparseMatrix& mat) : + m_mat(mat), m_n(mat.rows()) + { + if(mat.rows() != mat.cols()) + throw std::invalid_argument("SparseGenRealShiftSolve: matrix must be square"); + } + + /// + /// Return the number of rows of the underlying matrix. + /// + Index rows() const { return m_n; } + /// + /// Return the number of columns of the underlying matrix. + /// + Index cols() const { return m_n; } + + /// + /// Set the real shift \f$\sigma\f$. + /// + void set_shift(Scalar sigma) + { + SparseMatrix I(m_n, m_n); + I.setIdentity(); + + m_solver.compute(m_mat - sigma * I); + if(m_solver.info() != Eigen::Success) + throw std::invalid_argument("SparseGenRealShiftSolve: factorization failed with the given shift"); + } + + /// + /// Perform the shift-solve operation \f$y=(A-\sigma I)^{-1}x\f$. + /// + /// \param x_in Pointer to the \f$x\f$ vector. + /// \param y_out Pointer to the \f$y\f$ vector. + /// + // y_out = inv(A - sigma * I) * x_in + void perform_op(const Scalar* x_in, Scalar* y_out) const + { + MapConstVec x(x_in, m_n); + MapVec y(y_out, m_n); + y.noalias() = m_solver.solve(x); + } +}; + + +} // namespace Spectra + +#endif // SPARSE_GEN_REAL_SHIFT_SOLVE_H diff --git a/external/Spectra/include/Spectra/MatOp/SparseRegularInverse.h b/external/Spectra/include/Spectra/MatOp/SparseRegularInverse.h new file mode 100644 index 000000000..ec6614a5a --- /dev/null +++ b/external/Spectra/include/Spectra/MatOp/SparseRegularInverse.h @@ -0,0 +1,102 @@ +// Copyright (C) 2017-2019 Yixuan Qiu +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at https://mozilla.org/MPL/2.0/. + +#ifndef SPARSE_REGULAR_INVERSE_H +#define SPARSE_REGULAR_INVERSE_H + +#include +#include +#include +#include + +namespace Spectra { + + +/// +/// \ingroup MatOp +/// +/// This class defines matrix operations required by the generalized eigen solver +/// in the regular inverse mode. For a sparse and positive definite matrix \f$B\f$, +/// it implements the matrix-vector product \f$y=Bx\f$ and the linear equation +/// solving operation \f$y=B^{-1}x\f$. +/// +/// This class is intended to be used with the SymGEigsSolver generalized eigen solver +/// in the regular inverse mode. +/// +template +class SparseRegularInverse +{ +private: + typedef Eigen::Index Index; + typedef Eigen::Matrix Vector; + typedef Eigen::Map MapConstVec; + typedef Eigen::Map MapVec; + typedef Eigen::SparseMatrix SparseMatrix; + typedef const Eigen::Ref ConstGenericSparseMatrix; + + ConstGenericSparseMatrix m_mat; + const int m_n; + Eigen::ConjugateGradient m_cg; + +public: + /// + /// Constructor to create the matrix operation object. + /// + /// \param mat An **Eigen** sparse matrix object, whose type can be + /// `Eigen::SparseMatrix` or its mapped version + /// `Eigen::Map >`. + /// + SparseRegularInverse(ConstGenericSparseMatrix& mat) : + m_mat(mat), m_n(mat.rows()) + { + if(mat.rows() != mat.cols()) + throw std::invalid_argument("SparseRegularInverse: matrix must be square"); + + m_cg.compute(mat); + } + + /// + /// Return the number of rows of the underlying matrix. + /// + Index rows() const { return m_n; } + /// + /// Return the number of columns of the underlying matrix. + /// + Index cols() const { return m_n; } + + /// + /// Perform the solving operation \f$y=B^{-1}x\f$. + /// + /// \param x_in Pointer to the \f$x\f$ vector. + /// \param y_out Pointer to the \f$y\f$ vector. + /// + // y_out = inv(B) * x_in + void solve(const Scalar* x_in, Scalar* y_out) const + { + MapConstVec x(x_in, m_n); + MapVec y(y_out, m_n); + y.noalias() = m_cg.solve(x); + } + + /// + /// Perform the matrix-vector multiplication operation \f$y=Bx\f$. + /// + /// \param x_in Pointer to the \f$x\f$ vector. + /// \param y_out Pointer to the \f$y\f$ vector. + /// + // y_out = B * x_in + void mat_prod(const Scalar* x_in, Scalar* y_out) const + { + MapConstVec x(x_in, m_n); + MapVec y(y_out, m_n); + y.noalias() = m_mat.template selfadjointView() * x; + } +}; + + +} // namespace Spectra + +#endif // SPARSE_REGULAR_INVERSE_H diff --git a/external/Spectra/include/Spectra/MatOp/SparseSymMatProd.h b/external/Spectra/include/Spectra/MatOp/SparseSymMatProd.h new file mode 100644 index 000000000..ef8f96ee8 --- /dev/null +++ b/external/Spectra/include/Spectra/MatOp/SparseSymMatProd.h @@ -0,0 +1,75 @@ +// Copyright (C) 2016-2019 Yixuan Qiu +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at https://mozilla.org/MPL/2.0/. + +#ifndef SPARSE_SYM_MAT_PROD_H +#define SPARSE_SYM_MAT_PROD_H + +#include +#include + +namespace Spectra { + + +/// +/// \ingroup MatOp +/// +/// This class defines the matrix-vector multiplication operation on a +/// sparse real symmetric matrix \f$A\f$, i.e., calculating \f$y=Ax\f$ for any vector +/// \f$x\f$. It is mainly used in the SymEigsSolver eigen solver. +/// +template +class SparseSymMatProd +{ +private: + typedef Eigen::Index Index; + typedef Eigen::Matrix Vector; + typedef Eigen::Map MapConstVec; + typedef Eigen::Map MapVec; + typedef Eigen::SparseMatrix SparseMatrix; + typedef const Eigen::Ref ConstGenericSparseMatrix; + + ConstGenericSparseMatrix m_mat; + +public: + /// + /// Constructor to create the matrix operation object. + /// + /// \param mat An **Eigen** sparse matrix object, whose type can be + /// `Eigen::SparseMatrix` or its mapped version + /// `Eigen::Map >`. + /// + SparseSymMatProd(ConstGenericSparseMatrix& mat) : + m_mat(mat) + {} + + /// + /// Return the number of rows of the underlying matrix. + /// + Index rows() const { return m_mat.rows(); } + /// + /// Return the number of columns of the underlying matrix. + /// + Index cols() const { return m_mat.cols(); } + + /// + /// Perform the matrix-vector multiplication operation \f$y=Ax\f$. + /// + /// \param x_in Pointer to the \f$x\f$ vector. + /// \param y_out Pointer to the \f$y\f$ vector. + /// + // y_out = A * x_in + void perform_op(const Scalar* x_in, Scalar* y_out) const + { + MapConstVec x(x_in, m_mat.cols()); + MapVec y(y_out, m_mat.rows()); + y.noalias() = m_mat.template selfadjointView() * x; + } +}; + + +} // namespace Spectra + +#endif // SPARSE_SYM_MAT_PROD_H diff --git a/external/Spectra/include/Spectra/MatOp/SparseSymShiftSolve.h b/external/Spectra/include/Spectra/MatOp/SparseSymShiftSolve.h new file mode 100644 index 000000000..1821cc326 --- /dev/null +++ b/external/Spectra/include/Spectra/MatOp/SparseSymShiftSolve.h @@ -0,0 +1,97 @@ +// Copyright (C) 2016-2019 Yixuan Qiu +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at https://mozilla.org/MPL/2.0/. + +#ifndef SPARSE_SYM_SHIFT_SOLVE_H +#define SPARSE_SYM_SHIFT_SOLVE_H + +#include +#include +#include +#include + +namespace Spectra { + + +/// +/// \ingroup MatOp +/// +/// This class defines the shift-solve operation on a sparse real symmetric matrix \f$A\f$, +/// i.e., calculating \f$y=(A-\sigma I)^{-1}x\f$ for any real \f$\sigma\f$ and +/// vector \f$x\f$. It is mainly used in the SymEigsShiftSolver eigen solver. +/// +template +class SparseSymShiftSolve +{ +private: + typedef Eigen::Index Index; + typedef Eigen::Matrix Vector; + typedef Eigen::Map MapConstVec; + typedef Eigen::Map MapVec; + typedef Eigen::SparseMatrix SparseMatrix; + typedef const Eigen::Ref ConstGenericSparseMatrix; + + ConstGenericSparseMatrix m_mat; + const int m_n; + Eigen::SparseLU m_solver; + +public: + /// + /// Constructor to create the matrix operation object. + /// + /// \param mat An **Eigen** sparse matrix object, whose type can be + /// `Eigen::SparseMatrix` or its mapped version + /// `Eigen::Map >`. + /// + SparseSymShiftSolve(ConstGenericSparseMatrix& mat) : + m_mat(mat), m_n(mat.rows()) + { + if(mat.rows() != mat.cols()) + throw std::invalid_argument("SparseSymShiftSolve: matrix must be square"); + } + + /// + /// Return the number of rows of the underlying matrix. + /// + Index rows() const { return m_n; } + /// + /// Return the number of columns of the underlying matrix. + /// + Index cols() const { return m_n; } + + /// + /// Set the real shift \f$\sigma\f$. + /// + void set_shift(Scalar sigma) + { + SparseMatrix mat = m_mat.template selfadjointView(); + SparseMatrix identity(m_n, m_n); + identity.setIdentity(); + mat = mat - sigma * identity; + m_solver.isSymmetric(true); + m_solver.compute(mat); + if(m_solver.info() != Eigen::Success) + throw std::invalid_argument("SparseSymShiftSolve: factorization failed with the given shift"); + } + + /// + /// Perform the shift-solve operation \f$y=(A-\sigma I)^{-1}x\f$. + /// + /// \param x_in Pointer to the \f$x\f$ vector. + /// \param y_out Pointer to the \f$y\f$ vector. + /// + // y_out = inv(A - sigma * I) * x_in + void perform_op(const Scalar* x_in, Scalar* y_out) const + { + MapConstVec x(x_in, m_n); + MapVec y(y_out, m_n); + y.noalias() = m_solver.solve(x); + } +}; + + +} // namespace Spectra + +#endif // SPARSE_SYM_SHIFT_SOLVE_H diff --git a/external/Spectra/include/Spectra/MatOp/internal/ArnoldiOp.h b/external/Spectra/include/Spectra/MatOp/internal/ArnoldiOp.h new file mode 100644 index 000000000..b79704b56 --- /dev/null +++ b/external/Spectra/include/Spectra/MatOp/internal/ArnoldiOp.h @@ -0,0 +1,155 @@ +// Copyright (C) 2018-2019 Yixuan Qiu +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at https://mozilla.org/MPL/2.0/. + +#ifndef ARNOLDI_OP_H +#define ARNOLDI_OP_H + +#include +#include // std::sqrt + +namespace Spectra { + + +/// +/// \ingroup Internals +/// @{ +/// + +/// +/// \defgroup Operators Operators +/// +/// Different types of operators. +/// + +/// +/// \ingroup Operators +/// +/// Operators used in the Arnoldi factorization. +/// +template +class ArnoldiOp +{ +private: + typedef Eigen::Index Index; + typedef Eigen::Matrix Vector; + + OpType& m_op; + BOpType& m_Bop; + Vector m_cache; + +public: + ArnoldiOp(OpType* op, BOpType* Bop) : + m_op(*op), m_Bop(*Bop), m_cache(op->rows()) + {} + + inline Index rows() const { return m_op.rows(); } + + // In generalized eigenvalue problem Ax=lambda*Bx, define the inner product to be = x'By. + // For regular eigenvalue problems, it is the usual inner product = x'y + + // Compute = x'By + // x and y are two vectors + template + Scalar inner_product(const Arg1& x, const Arg2& y) + { + m_Bop.mat_prod(y.data(), m_cache.data()); + return x.dot(m_cache); + } + + // Compute res = = X'By + // X is a matrix, y is a vector, res is a vector + template + void trans_product(const Arg1& x, const Arg2& y, Eigen::Ref res) + { + m_Bop.mat_prod(y.data(), m_cache.data()); + res.noalias() = x.transpose() * m_cache; + } + + // B-norm of a vector, ||x||_B = sqrt(x'Bx) + template + Scalar norm(const Arg& x) + { + using std::sqrt; + return sqrt(inner_product(x, x)); + } + + // The "A" operator to generate the Krylov subspace + inline void perform_op(const Scalar* x_in, Scalar* y_out) + { + m_op.perform_op(x_in, y_out); + } +}; + + + +/// +/// \ingroup Operators +/// +/// Placeholder for the B-operator when \f$B = I\f$. +/// +class IdentityBOp {}; + + + +/// +/// \ingroup Operators +/// +/// Partial specialization for the case \f$B = I\f$. +/// +template +class ArnoldiOp +{ +private: + typedef Eigen::Index Index; + typedef Eigen::Matrix Vector; + + OpType& m_op; + +public: + ArnoldiOp(OpType* op, IdentityBOp* /*Bop*/) : + m_op(*op) + {} + + inline Index rows() const { return m_op.rows(); } + + // Compute = x'y + // x and y are two vectors + template + Scalar inner_product(const Arg1& x, const Arg2& y) const + { + return x.dot(y); + } + + // Compute res = = X'y + // X is a matrix, y is a vector, res is a vector + template + void trans_product(const Arg1& x, const Arg2& y, Eigen::Ref res) const + { + res.noalias() = x.transpose() * y; + } + + // B-norm of a vector. For regular eigenvalue problems it is simply the L2 norm + template + Scalar norm(const Arg& x) + { + return x.norm(); + } + + // The "A" operator to generate the Krylov subspace + inline void perform_op(Scalar* x_in, Scalar* y_out) + { + m_op.perform_op(x_in, y_out); + } +}; + +/// +/// @} +/// + + +} // namespace Spectra + +#endif // ARNOLDI_OP_H diff --git a/external/Spectra/include/Spectra/MatOp/internal/SymGEigsCholeskyOp.h b/external/Spectra/include/Spectra/MatOp/internal/SymGEigsCholeskyOp.h new file mode 100644 index 000000000..d7acdb2ac --- /dev/null +++ b/external/Spectra/include/Spectra/MatOp/internal/SymGEigsCholeskyOp.h @@ -0,0 +1,77 @@ +// Copyright (C) 2016-2019 Yixuan Qiu +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at https://mozilla.org/MPL/2.0/. + +#ifndef SYM_GEIGS_CHOLESKY_OP_H +#define SYM_GEIGS_CHOLESKY_OP_H + +#include +#include "../DenseSymMatProd.h" +#include "../DenseCholesky.h" + +namespace Spectra { + + +/// +/// \ingroup Operators +/// +/// This class defines the matrix operation for generalized eigen solver in the +/// Cholesky decomposition mode. It calculates \f$y=L^{-1}A(L')^{-1}x\f$ for any +/// vector \f$x\f$, where \f$L\f$ is the Cholesky decomposition of \f$B\f$. +/// This class is intended for internal use. +/// +template < typename Scalar = double, + typename OpType = DenseSymMatProd, + typename BOpType = DenseCholesky > +class SymGEigsCholeskyOp +{ +private: + typedef Eigen::Index Index; + typedef Eigen::Matrix Matrix; + typedef Eigen::Matrix Vector; + + OpType& m_op; + BOpType& m_Bop; + Vector m_cache; // temporary working space + +public: + /// + /// Constructor to create the matrix operation object. + /// + /// \param op Pointer to the \f$A\f$ matrix operation object. + /// \param Bop Pointer to the \f$B\f$ matrix operation object. + /// + SymGEigsCholeskyOp(OpType& op, BOpType& Bop) : + m_op(op), m_Bop(Bop), m_cache(op.rows()) + {} + + /// + /// Return the number of rows of the underlying matrix. + /// + Index rows() const { return m_Bop.rows(); } + /// + /// Return the number of columns of the underlying matrix. + /// + Index cols() const { return m_Bop.rows(); } + + /// + /// Perform the matrix operation \f$y=L^{-1}A(L')^{-1}x\f$. + /// + /// \param x_in Pointer to the \f$x\f$ vector. + /// \param y_out Pointer to the \f$y\f$ vector. + /// + // y_out = inv(L) * A * inv(L') * x_in + void perform_op(const Scalar* x_in, Scalar* y_out) + { + m_Bop.upper_triangular_solve(x_in, y_out); + m_op.perform_op(y_out, m_cache.data()); + m_Bop.lower_triangular_solve(m_cache.data(), y_out); + } +}; + + +} // namespace Spectra + +#endif // SYM_GEIGS_CHOLESKY_OP_H diff --git a/external/Spectra/include/Spectra/MatOp/internal/SymGEigsRegInvOp.h b/external/Spectra/include/Spectra/MatOp/internal/SymGEigsRegInvOp.h new file mode 100644 index 000000000..ac00dcb21 --- /dev/null +++ b/external/Spectra/include/Spectra/MatOp/internal/SymGEigsRegInvOp.h @@ -0,0 +1,74 @@ +// Copyright (C) 2017-2019 Yixuan Qiu +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at https://mozilla.org/MPL/2.0/. + +#ifndef SYM_GEIGS_REG_INV_OP_H +#define SYM_GEIGS_REG_INV_OP_H + +#include +#include "../SparseSymMatProd.h" +#include "../SparseRegularInverse.h" + +namespace Spectra { + + +/// +/// \ingroup Operators +/// +/// This class defines the matrix operation for generalized eigen solver in the +/// regular inverse mode. This class is intended for internal use. +/// +template < typename Scalar = double, + typename OpType = SparseSymMatProd, + typename BOpType = SparseRegularInverse > +class SymGEigsRegInvOp +{ +private: + typedef Eigen::Index Index; + typedef Eigen::Matrix Matrix; + typedef Eigen::Matrix Vector; + + OpType& m_op; + BOpType& m_Bop; + Vector m_cache; // temporary working space + +public: + /// + /// Constructor to create the matrix operation object. + /// + /// \param op Pointer to the \f$A\f$ matrix operation object. + /// \param Bop Pointer to the \f$B\f$ matrix operation object. + /// + SymGEigsRegInvOp(OpType& op, BOpType& Bop) : + m_op(op), m_Bop(Bop), m_cache(op.rows()) + {} + + /// + /// Return the number of rows of the underlying matrix. + /// + Index rows() const { return m_Bop.rows(); } + /// + /// Return the number of columns of the underlying matrix. + /// + Index cols() const { return m_Bop.rows(); } + + /// + /// Perform the matrix operation \f$y=B^{-1}Ax\f$. + /// + /// \param x_in Pointer to the \f$x\f$ vector. + /// \param y_out Pointer to the \f$y\f$ vector. + /// + // y_out = inv(B) * A * x_in + void perform_op(const Scalar* x_in, Scalar* y_out) + { + m_op.perform_op(x_in, m_cache.data()); + m_Bop.solve(m_cache.data(), y_out); + } +}; + + +} // namespace Spectra + +#endif // SYM_GEIGS_REG_INV_OP_H diff --git a/external/Spectra/include/Spectra/SymEigsBase.h b/external/Spectra/include/Spectra/SymEigsBase.h new file mode 100644 index 000000000..24d5b5051 --- /dev/null +++ b/external/Spectra/include/Spectra/SymEigsBase.h @@ -0,0 +1,447 @@ +// Copyright (C) 2018-2019 Yixuan Qiu +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at https://mozilla.org/MPL/2.0/. + +#ifndef SYM_EIGS_BASE_H +#define SYM_EIGS_BASE_H + +#include +#include // std::vector +#include // std::abs, std::pow, std::sqrt +#include // std::min, std::copy +#include // std::invalid_argument + +#include "Util/TypeTraits.h" +#include "Util/SelectionRule.h" +#include "Util/CompInfo.h" +#include "Util/SimpleRandom.h" +#include "MatOp/internal/ArnoldiOp.h" +#include "LinAlg/UpperHessenbergQR.h" +#include "LinAlg/TridiagEigen.h" +#include "LinAlg/Lanczos.h" + +namespace Spectra { + + +/// +/// \defgroup EigenSolver Eigen Solvers +/// +/// Eigen solvers for different types of problems. +/// + +/// +/// \ingroup EigenSolver +/// +/// This is the base class for symmetric eigen solvers, mainly for internal use. +/// It is kept here to provide the documentation for member functions of concrete eigen solvers +/// such as SymEigsSolver and SymEigsShiftSolver. +/// +template < typename Scalar, + int SelectionRule, + typename OpType, + typename BOpType > +class SymEigsBase +{ +private: + typedef Eigen::Index Index; + typedef Eigen::Matrix Matrix; + typedef Eigen::Matrix Vector; + typedef Eigen::Array Array; + typedef Eigen::Array BoolArray; + typedef Eigen::Map MapMat; + typedef Eigen::Map MapVec; + typedef Eigen::Map MapConstVec; + + typedef ArnoldiOp ArnoldiOpType; + typedef Lanczos LanczosFac; + +protected: + OpType* m_op; // object to conduct matrix operation, + // e.g. matrix-vector product + const Index m_n; // dimension of matrix A + const Index m_nev; // number of eigenvalues requested + const Index m_ncv; // dimension of Krylov subspace in the Lanczos method + Index m_nmatop; // number of matrix operations called + Index m_niter; // number of restarting iterations + + LanczosFac m_fac; // Lanczos factorization + Vector m_ritz_val; // Ritz values + +private: + Matrix m_ritz_vec; // Ritz vectors + Vector m_ritz_est; // last row of m_ritz_vec, also called the Ritz estimates + BoolArray m_ritz_conv; // indicator of the convergence of Ritz values + int m_info; // status of the computation + + const Scalar m_near_0; // a very small value, but 1.0 / m_near_0 does not overflow + // ~= 1e-307 for the "double" type + const Scalar m_eps; // the machine precision, ~= 1e-16 for the "double" type + const Scalar m_eps23; // m_eps^(2/3), used to test the convergence + + // Implicitly restarted Lanczos factorization + void restart(Index k) + { + if(k >= m_ncv) + return; + + TridiagQR decomp(m_ncv); + Matrix Q = Matrix::Identity(m_ncv, m_ncv); + + for(Index i = k; i < m_ncv; i++) + { + // QR decomposition of H-mu*I, mu is the shift + decomp.compute(m_fac.matrix_H(), m_ritz_val[i]); + + // Q -> Q * Qi + decomp.apply_YQ(Q); + // H -> Q'HQ + // Since QR = H - mu * I, we have H = QR + mu * I + // and therefore Q'HQ = RQ + mu * I + m_fac.compress_H(decomp); + } + + m_fac.compress_V(Q); + m_fac.factorize_from(k, m_ncv, m_nmatop); + + retrieve_ritzpair(); + } + + // Calculates the number of converged Ritz values + Index num_converged(Scalar tol) + { + // thresh = tol * max(m_eps23, abs(theta)), theta for Ritz value + Array thresh = tol * m_ritz_val.head(m_nev).array().abs().max(m_eps23); + Array resid = m_ritz_est.head(m_nev).array().abs() * m_fac.f_norm(); + // Converged "wanted" Ritz values + m_ritz_conv = (resid < thresh); + + return m_ritz_conv.cast().sum(); + } + + // Returns the adjusted nev for restarting + Index nev_adjusted(Index nconv) + { + using std::abs; + + Index nev_new = m_nev; + for(Index i = m_nev; i < m_ncv; i++) + if(abs(m_ritz_est[i]) < m_near_0) nev_new++; + + // Adjust nev_new, according to dsaup2.f line 677~684 in ARPACK + nev_new += std::min(nconv, (m_ncv - nev_new) / 2); + if(nev_new == 1 && m_ncv >= 6) + nev_new = m_ncv / 2; + else if(nev_new == 1 && m_ncv > 2) + nev_new = 2; + + if(nev_new > m_ncv - 1) + nev_new = m_ncv - 1; + + return nev_new; + } + + // Retrieves and sorts Ritz values and Ritz vectors + void retrieve_ritzpair() + { + TridiagEigen decomp(m_fac.matrix_H()); + const Vector& evals = decomp.eigenvalues(); + const Matrix& evecs = decomp.eigenvectors(); + + SortEigenvalue sorting(evals.data(), evals.size()); + std::vector ind = sorting.index(); + + // For BOTH_ENDS, the eigenvalues are sorted according + // to the LARGEST_ALGE rule, so we need to move those smallest + // values to the left + // The order would be + // Largest => Smallest => 2nd largest => 2nd smallest => ... + // We keep this order since the first k values will always be + // the wanted collection, no matter k is nev_updated (used in restart()) + // or is nev (used in sort_ritzpair()) + if(SelectionRule == BOTH_ENDS) + { + std::vector ind_copy(ind); + for(Index i = 0; i < m_ncv; i++) + { + // If i is even, pick values from the left (large values) + // If i is odd, pick values from the right (small values) + if(i % 2 == 0) + ind[i] = ind_copy[i / 2]; + else + ind[i] = ind_copy[m_ncv - 1 - i / 2]; + } + } + + // Copy the Ritz values and vectors to m_ritz_val and m_ritz_vec, respectively + for(Index i = 0; i < m_ncv; i++) + { + m_ritz_val[i] = evals[ind[i]]; + m_ritz_est[i] = evecs(m_ncv - 1, ind[i]); + } + for(Index i = 0; i < m_nev; i++) + { + m_ritz_vec.col(i).noalias() = evecs.col(ind[i]); + } + } + +protected: + // Sorts the first nev Ritz pairs in the specified order + // This is used to return the final results + virtual void sort_ritzpair(int sort_rule) + { + // First make sure that we have a valid index vector + SortEigenvalue sorting(m_ritz_val.data(), m_nev); + std::vector ind = sorting.index(); + + switch(sort_rule) + { + case LARGEST_ALGE: + break; + case LARGEST_MAGN: + { + SortEigenvalue sorting(m_ritz_val.data(), m_nev); + ind = sorting.index(); + } + break; + case SMALLEST_ALGE: + { + SortEigenvalue sorting(m_ritz_val.data(), m_nev); + ind = sorting.index(); + } + break; + case SMALLEST_MAGN: + { + SortEigenvalue sorting(m_ritz_val.data(), m_nev); + ind = sorting.index(); + } + break; + default: + throw std::invalid_argument("unsupported sorting rule"); + } + + Vector new_ritz_val(m_ncv); + Matrix new_ritz_vec(m_ncv, m_nev); + BoolArray new_ritz_conv(m_nev); + + for(Index i = 0; i < m_nev; i++) + { + new_ritz_val[i] = m_ritz_val[ind[i]]; + new_ritz_vec.col(i).noalias() = m_ritz_vec.col(ind[i]); + new_ritz_conv[i] = m_ritz_conv[ind[i]]; + } + + m_ritz_val.swap(new_ritz_val); + m_ritz_vec.swap(new_ritz_vec); + m_ritz_conv.swap(new_ritz_conv); + } + +public: + /// \cond + + SymEigsBase(OpType* op, BOpType* Bop, Index nev, Index ncv) : + m_op(op), + m_n(m_op->rows()), + m_nev(nev), + m_ncv(ncv > m_n ? m_n : ncv), + m_nmatop(0), + m_niter(0), + m_fac(ArnoldiOpType(op, Bop), m_ncv), + m_info(NOT_COMPUTED), + m_near_0(TypeTraits::min() * Scalar(10)), + m_eps(Eigen::NumTraits::epsilon()), + m_eps23(Eigen::numext::pow(m_eps, Scalar(2.0) / 3)) + { + if(nev < 1 || nev > m_n - 1) + throw std::invalid_argument("nev must satisfy 1 <= nev <= n - 1, n is the size of matrix"); + + if(ncv <= nev || ncv > m_n) + throw std::invalid_argument("ncv must satisfy nev < ncv <= n, n is the size of matrix"); + } + + /// + /// Virtual destructor + /// + virtual ~SymEigsBase() {} + + /// \endcond + + /// + /// Initializes the solver by providing an initial residual vector. + /// + /// \param init_resid Pointer to the initial residual vector. + /// + /// **Spectra** (and also **ARPACK**) uses an iterative algorithm + /// to find eigenvalues. This function allows the user to provide the initial + /// residual vector. + /// + void init(const Scalar* init_resid) + { + // Reset all matrices/vectors to zero + m_ritz_val.resize(m_ncv); + m_ritz_vec.resize(m_ncv, m_nev); + m_ritz_est.resize(m_ncv); + m_ritz_conv.resize(m_nev); + + m_ritz_val.setZero(); + m_ritz_vec.setZero(); + m_ritz_est.setZero(); + m_ritz_conv.setZero(); + + m_nmatop = 0; + m_niter = 0; + + // Initialize the Lanczos factorization + MapConstVec v0(init_resid, m_n); + m_fac.init(v0, m_nmatop); + } + + /// + /// Initializes the solver by providing a random initial residual vector. + /// + /// This overloaded function generates a random initial residual vector + /// (with a fixed random seed) for the algorithm. Elements in the vector + /// follow independent Uniform(-0.5, 0.5) distribution. + /// + void init() + { + SimpleRandom rng(0); + Vector init_resid = rng.random_vec(m_n); + init(init_resid.data()); + } + + /// + /// Conducts the major computation procedure. + /// + /// \param maxit Maximum number of iterations allowed in the algorithm. + /// \param tol Precision parameter for the calculated eigenvalues. + /// \param sort_rule Rule to sort the eigenvalues and eigenvectors. + /// Supported values are + /// `Spectra::LARGEST_ALGE`, `Spectra::LARGEST_MAGN`, + /// `Spectra::SMALLEST_ALGE` and `Spectra::SMALLEST_MAGN`, + /// for example `LARGEST_ALGE` indicates that largest eigenvalues + /// come first. Note that this argument is only used to + /// **sort** the final result, and the **selection** rule + /// (e.g. selecting the largest or smallest eigenvalues in the + /// full spectrum) is specified by the template parameter + /// `SelectionRule` of SymEigsSolver. + /// + /// \return Number of converged eigenvalues. + /// + Index compute(Index maxit = 1000, Scalar tol = 1e-10, int sort_rule = LARGEST_ALGE) + { + // The m-step Lanczos factorization + m_fac.factorize_from(1, m_ncv, m_nmatop); + retrieve_ritzpair(); + // Restarting + Index i, nconv = 0, nev_adj; + for(i = 0; i < maxit; i++) + { + nconv = num_converged(tol); + if(nconv >= m_nev) + break; + + nev_adj = nev_adjusted(nconv); + restart(nev_adj); + } + // Sorting results + sort_ritzpair(sort_rule); + + m_niter += i + 1; + m_info = (nconv >= m_nev) ? SUCCESSFUL : NOT_CONVERGING; + + return std::min(m_nev, nconv); + } + + /// + /// Returns the status of the computation. + /// The full list of enumeration values can be found in \ref Enumerations. + /// + int info() const { return m_info; } + + /// + /// Returns the number of iterations used in the computation. + /// + Index num_iterations() const { return m_niter; } + + /// + /// Returns the number of matrix operations used in the computation. + /// + Index num_operations() const { return m_nmatop; } + + /// + /// Returns the converged eigenvalues. + /// + /// \return A vector containing the eigenvalues. + /// Returned vector type will be `Eigen::Vector`, depending on + /// the template parameter `Scalar` defined. + /// + Vector eigenvalues() const + { + const Index nconv = m_ritz_conv.cast().sum(); + Vector res(nconv); + + if(!nconv) + return res; + + Index j = 0; + for(Index i = 0; i < m_nev; i++) + { + if(m_ritz_conv[i]) + { + res[j] = m_ritz_val[i]; + j++; + } + } + + return res; + } + + /// + /// Returns the eigenvectors associated with the converged eigenvalues. + /// + /// \param nvec The number of eigenvectors to return. + /// + /// \return A matrix containing the eigenvectors. + /// Returned matrix type will be `Eigen::Matrix`, + /// depending on the template parameter `Scalar` defined. + /// + virtual Matrix eigenvectors(Index nvec) const + { + const Index nconv = m_ritz_conv.cast().sum(); + nvec = std::min(nvec, nconv); + Matrix res(m_n, nvec); + + if(!nvec) + return res; + + Matrix ritz_vec_conv(m_ncv, nvec); + Index j = 0; + for(Index i = 0; i < m_nev && j < nvec; i++) + { + if(m_ritz_conv[i]) + { + ritz_vec_conv.col(j).noalias() = m_ritz_vec.col(i); + j++; + } + } + + res.noalias() = m_fac.matrix_V() * ritz_vec_conv; + + return res; + } + + /// + /// Returns all converged eigenvectors. + /// + virtual Matrix eigenvectors() const + { + return eigenvectors(m_nev); + } +}; + + +} // namespace Spectra + +#endif // SYM_EIGS_BASE_H diff --git a/external/Spectra/include/Spectra/SymEigsShiftSolver.h b/external/Spectra/include/Spectra/SymEigsShiftSolver.h new file mode 100644 index 000000000..56bd44ec5 --- /dev/null +++ b/external/Spectra/include/Spectra/SymEigsShiftSolver.h @@ -0,0 +1,205 @@ +// Copyright (C) 2016-2019 Yixuan Qiu +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at https://mozilla.org/MPL/2.0/. + +#ifndef SYM_EIGS_SHIFT_SOLVER_H +#define SYM_EIGS_SHIFT_SOLVER_H + +#include + +#include "SymEigsBase.h" +#include "Util/SelectionRule.h" +#include "MatOp/DenseSymShiftSolve.h" + +namespace Spectra { + + +/// +/// \ingroup EigenSolver +/// +/// This class implements the eigen solver for real symmetric matrices using +/// the **shift-and-invert mode**. The background information of the symmetric +/// eigen solver is documented in the SymEigsSolver class. Here we focus on +/// explaining the shift-and-invert mode. +/// +/// The shift-and-invert mode is based on the following fact: +/// If \f$\lambda\f$ and \f$x\f$ are a pair of eigenvalue and eigenvector of +/// matrix \f$A\f$, such that \f$Ax=\lambda x\f$, then for any \f$\sigma\f$, +/// we have +/// \f[(A-\sigma I)^{-1}x=\nu x\f] +/// where +/// \f[\nu=\frac{1}{\lambda-\sigma}\f] +/// which indicates that \f$(\nu, x)\f$ is an eigenpair of the matrix +/// \f$(A-\sigma I)^{-1}\f$. +/// +/// Therefore, if we pass the matrix operation \f$(A-\sigma I)^{-1}y\f$ +/// (rather than \f$Ay\f$) to the eigen solver, then we would get the desired +/// values of \f$\nu\f$, and \f$\lambda\f$ can also be easily obtained by noting +/// that \f$\lambda=\sigma+\nu^{-1}\f$. +/// +/// The reason why we need this type of manipulation is that +/// the algorithm of **Spectra** (and also **ARPACK**) +/// is good at finding eigenvalues with large magnitude, but may fail in looking +/// for eigenvalues that are close to zero. However, if we really need them, we +/// can set \f$\sigma=0\f$, find the largest eigenvalues of \f$A^{-1}\f$, and then +/// transform back to \f$\lambda\f$, since in this case largest values of \f$\nu\f$ +/// implies smallest values of \f$\lambda\f$. +/// +/// To summarize, in the shift-and-invert mode, the selection rule will apply to +/// \f$\nu=1/(\lambda-\sigma)\f$ rather than \f$\lambda\f$. So a selection rule +/// of `LARGEST_MAGN` combined with shift \f$\sigma\f$ will find eigenvalues of +/// \f$A\f$ that are closest to \f$\sigma\f$. But note that the eigenvalues() +/// method will always return the eigenvalues in the original problem (i.e., +/// returning \f$\lambda\f$ rather than \f$\nu\f$), and eigenvectors are the +/// same for both the original problem and the shifted-and-inverted problem. +/// +/// \tparam Scalar The element type of the matrix. +/// Currently supported types are `float`, `double` and `long double`. +/// \tparam SelectionRule An enumeration value indicating the selection rule of +/// the shifted-and-inverted eigenvalues. +/// The full list of enumeration values can be found in +/// \ref Enumerations. +/// \tparam OpType The name of the matrix operation class. Users could either +/// use the wrapper classes such as DenseSymShiftSolve and +/// SparseSymShiftSolve, or define their +/// own that implements all the public member functions as in +/// DenseSymShiftSolve. +/// +/// Below is an example that illustrates the use of the shift-and-invert mode: +/// +/// \code{.cpp} +/// #include +/// #include +/// // is implicitly included +/// #include +/// +/// using namespace Spectra; +/// +/// int main() +/// { +/// // A size-10 diagonal matrix with elements 1, 2, ..., 10 +/// Eigen::MatrixXd M = Eigen::MatrixXd::Zero(10, 10); +/// for(int i = 0; i < M.rows(); i++) +/// M(i, i) = i + 1; +/// +/// // Construct matrix operation object using the wrapper class +/// DenseSymShiftSolve op(M); +/// +/// // Construct eigen solver object with shift 0 +/// // This will find eigenvalues that are closest to 0 +/// SymEigsShiftSolver< double, LARGEST_MAGN, +/// DenseSymShiftSolve > eigs(&op, 3, 6, 0.0); +/// +/// eigs.init(); +/// eigs.compute(); +/// if(eigs.info() == SUCCESSFUL) +/// { +/// Eigen::VectorXd evalues = eigs.eigenvalues(); +/// // Will get (3.0, 2.0, 1.0) +/// std::cout << "Eigenvalues found:\n" << evalues << std::endl; +/// } +/// +/// return 0; +/// } +/// \endcode +/// +/// Also an example for user-supplied matrix shift-solve operation class: +/// +/// \code{.cpp} +/// #include +/// #include +/// #include +/// +/// using namespace Spectra; +/// +/// // M = diag(1, 2, ..., 10) +/// class MyDiagonalTenShiftSolve +/// { +/// private: +/// double sigma_; +/// public: +/// int rows() { return 10; } +/// int cols() { return 10; } +/// void set_shift(double sigma) { sigma_ = sigma; } +/// // y_out = inv(A - sigma * I) * x_in +/// // inv(A - sigma * I) = diag(1/(1-sigma), 1/(2-sigma), ...) +/// void perform_op(double *x_in, double *y_out) +/// { +/// for(int i = 0; i < rows(); i++) +/// { +/// y_out[i] = x_in[i] / (i + 1 - sigma_); +/// } +/// } +/// }; +/// +/// int main() +/// { +/// MyDiagonalTenShiftSolve op; +/// // Find three eigenvalues that are closest to 3.14 +/// SymEigsShiftSolver eigs(&op, 3, 6, 3.14); +/// eigs.init(); +/// eigs.compute(); +/// if(eigs.info() == SUCCESSFUL) +/// { +/// Eigen::VectorXd evalues = eigs.eigenvalues(); +/// // Will get (4.0, 3.0, 2.0) +/// std::cout << "Eigenvalues found:\n" << evalues << std::endl; +/// } +/// +/// return 0; +/// } +/// \endcode +/// +template > +class SymEigsShiftSolver: public SymEigsBase +{ +private: + typedef Eigen::Index Index; + typedef Eigen::Array Array; + + const Scalar m_sigma; + + // First transform back the Ritz values, and then sort + void sort_ritzpair(int sort_rule) + { + Array m_ritz_val_org = Scalar(1.0) / this->m_ritz_val.head(this->m_nev).array() + m_sigma; + this->m_ritz_val.head(this->m_nev) = m_ritz_val_org; + SymEigsBase::sort_ritzpair(sort_rule); + } + +public: + /// + /// Constructor to create a eigen solver object using the shift-and-invert mode. + /// + /// \param op Pointer to the matrix operation object, which should implement + /// the shift-solve operation of \f$A\f$: calculating + /// \f$(A-\sigma I)^{-1}v\f$ for any vector \f$v\f$. Users could either + /// create the object from the wrapper class such as DenseSymShiftSolve, or + /// define their own that implements all the public member functions + /// as in DenseSymShiftSolve. + /// \param nev Number of eigenvalues requested. This should satisfy \f$1\le nev \le n-1\f$, + /// where \f$n\f$ is the size of matrix. + /// \param ncv Parameter that controls the convergence speed of the algorithm. + /// Typically a larger `ncv_` means faster convergence, but it may + /// also result in greater memory use and more matrix operations + /// in each iteration. This parameter must satisfy \f$nev < ncv \le n\f$, + /// and is advised to take \f$ncv \ge 2\cdot nev\f$. + /// \param sigma The value of the shift. + /// + SymEigsShiftSolver(OpType* op, Index nev, Index ncv, Scalar sigma) : + SymEigsBase(op, NULL, nev, ncv), + m_sigma(sigma) + { + this->m_op->set_shift(m_sigma); + } +}; + + +} // namespace Spectra + +#endif // SYM_EIGS_SHIFT_SOLVER_H diff --git a/external/Spectra/include/Spectra/SymEigsSolver.h b/external/Spectra/include/Spectra/SymEigsSolver.h new file mode 100644 index 000000000..8ba3e5096 --- /dev/null +++ b/external/Spectra/include/Spectra/SymEigsSolver.h @@ -0,0 +1,174 @@ +// Copyright (C) 2016-2019 Yixuan Qiu +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at https://mozilla.org/MPL/2.0/. + +#ifndef SYM_EIGS_SOLVER_H +#define SYM_EIGS_SOLVER_H + +#include + +#include "SymEigsBase.h" +#include "Util/SelectionRule.h" +#include "MatOp/DenseSymMatProd.h" + +namespace Spectra { + + +/// +/// \ingroup EigenSolver +/// +/// This class implements the eigen solver for real symmetric matrices, i.e., +/// to solve \f$Ax=\lambda x\f$ where \f$A\f$ is symmetric. +/// +/// **Spectra** is designed to calculate a specified number (\f$k\f$) +/// of eigenvalues of a large square matrix (\f$A\f$). Usually \f$k\f$ is much +/// less than the size of the matrix (\f$n\f$), so that only a few eigenvalues +/// and eigenvectors are computed. +/// +/// Rather than providing the whole \f$A\f$ matrix, the algorithm only requires +/// the matrix-vector multiplication operation of \f$A\f$. Therefore, users of +/// this solver need to supply a class that computes the result of \f$Av\f$ +/// for any given vector \f$v\f$. The name of this class should be given to +/// the template parameter `OpType`, and instance of this class passed to +/// the constructor of SymEigsSolver. +/// +/// If the matrix \f$A\f$ is already stored as a matrix object in **Eigen**, +/// for example `Eigen::MatrixXd`, then there is an easy way to construct such +/// matrix operation class, by using the built-in wrapper class DenseSymMatProd +/// which wraps an existing matrix object in **Eigen**. This is also the +/// default template parameter for SymEigsSolver. For sparse matrices, the +/// wrapper class SparseSymMatProd can be used similarly. +/// +/// If the users need to define their own matrix-vector multiplication operation +/// class, it should implement all the public member functions as in DenseSymMatProd. +/// +/// \tparam Scalar The element type of the matrix. +/// Currently supported types are `float`, `double` and `long double`. +/// \tparam SelectionRule An enumeration value indicating the selection rule of +/// the requested eigenvalues, for example `LARGEST_MAGN` +/// to retrieve eigenvalues with the largest magnitude. +/// The full list of enumeration values can be found in +/// \ref Enumerations. +/// \tparam OpType The name of the matrix operation class. Users could either +/// use the wrapper classes such as DenseSymMatProd and +/// SparseSymMatProd, or define their +/// own that implements all the public member functions as in +/// DenseSymMatProd. +/// +/// Below is an example that demonstrates the usage of this class. +/// +/// \code{.cpp} +/// #include +/// #include +/// // is implicitly included +/// #include +/// +/// using namespace Spectra; +/// +/// int main() +/// { +/// // We are going to calculate the eigenvalues of M +/// Eigen::MatrixXd A = Eigen::MatrixXd::Random(10, 10); +/// Eigen::MatrixXd M = A + A.transpose(); +/// +/// // Construct matrix operation object using the wrapper class DenseSymMatProd +/// DenseSymMatProd op(M); +/// +/// // Construct eigen solver object, requesting the largest three eigenvalues +/// SymEigsSolver< double, LARGEST_ALGE, DenseSymMatProd > eigs(&op, 3, 6); +/// +/// // Initialize and compute +/// eigs.init(); +/// int nconv = eigs.compute(); +/// +/// // Retrieve results +/// Eigen::VectorXd evalues; +/// if(eigs.info() == SUCCESSFUL) +/// evalues = eigs.eigenvalues(); +/// +/// std::cout << "Eigenvalues found:\n" << evalues << std::endl; +/// +/// return 0; +/// } +/// \endcode +/// +/// And here is an example for user-supplied matrix operation class. +/// +/// \code{.cpp} +/// #include +/// #include +/// #include +/// +/// using namespace Spectra; +/// +/// // M = diag(1, 2, ..., 10) +/// class MyDiagonalTen +/// { +/// public: +/// int rows() { return 10; } +/// int cols() { return 10; } +/// // y_out = M * x_in +/// void perform_op(double *x_in, double *y_out) +/// { +/// for(int i = 0; i < rows(); i++) +/// { +/// y_out[i] = x_in[i] * (i + 1); +/// } +/// } +/// }; +/// +/// int main() +/// { +/// MyDiagonalTen op; +/// SymEigsSolver eigs(&op, 3, 6); +/// eigs.init(); +/// eigs.compute(); +/// if(eigs.info() == SUCCESSFUL) +/// { +/// Eigen::VectorXd evalues = eigs.eigenvalues(); +/// // Will get (10, 9, 8) +/// std::cout << "Eigenvalues found:\n" << evalues << std::endl; +/// } +/// +/// return 0; +/// } +/// \endcode +/// +template < typename Scalar = double, + int SelectionRule = LARGEST_MAGN, + typename OpType = DenseSymMatProd > +class SymEigsSolver: public SymEigsBase +{ +private: + typedef Eigen::Index Index; + +public: + /// + /// Constructor to create a solver object. + /// + /// \param op Pointer to the matrix operation object, which should implement + /// the matrix-vector multiplication operation of \f$A\f$: + /// calculating \f$Av\f$ for any vector \f$v\f$. Users could either + /// create the object from the wrapper class such as DenseSymMatProd, or + /// define their own that implements all the public member functions + /// as in DenseSymMatProd. + /// \param nev Number of eigenvalues requested. This should satisfy \f$1\le nev \le n-1\f$, + /// where \f$n\f$ is the size of matrix. + /// \param ncv Parameter that controls the convergence speed of the algorithm. + /// Typically a larger `ncv` means faster convergence, but it may + /// also result in greater memory use and more matrix operations + /// in each iteration. This parameter must satisfy \f$nev < ncv \le n\f$, + /// and is advised to take \f$ncv \ge 2\cdot nev\f$. + /// + SymEigsSolver(OpType* op, Index nev, Index ncv) : + SymEigsBase(op, NULL, nev, ncv) + {} + +}; + + +} // namespace Spectra + +#endif // SYM_EIGS_SOLVER_H diff --git a/external/Spectra/include/Spectra/SymGEigsSolver.h b/external/Spectra/include/Spectra/SymGEigsSolver.h new file mode 100644 index 000000000..8e774284a --- /dev/null +++ b/external/Spectra/include/Spectra/SymGEigsSolver.h @@ -0,0 +1,334 @@ +// Copyright (C) 2016-2019 Yixuan Qiu +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at https://mozilla.org/MPL/2.0/. + +#ifndef SYM_GEIGS_SOLVER_H +#define SYM_GEIGS_SOLVER_H + +#include "SymEigsBase.h" +#include "Util/GEigsMode.h" +#include "MatOp/internal/SymGEigsCholeskyOp.h" +#include "MatOp/internal/SymGEigsRegInvOp.h" + +namespace Spectra { + + +/// +/// \defgroup GEigenSolver Generalized Eigen Solvers +/// +/// Generalized eigen solvers for different types of problems. +/// + +/// +/// \ingroup GEigenSolver +/// +/// This class implements the generalized eigen solver for real symmetric +/// matrices, i.e., to solve \f$Ax=\lambda Bx\f$ where \f$A\f$ is symmetric and +/// \f$B\f$ is positive definite. +/// +/// There are two modes of this solver, specified by the template parameter +/// GEigsMode. See the pages for the specialized classes for details. +/// - The Cholesky mode assumes that \f$B\f$ can be factorized using Cholesky +/// decomposition, which is the preferred mode when the decomposition is +/// available. (This can be easily done in Eigen using the dense or sparse +/// Cholesky solver.) +/// See \ref SymGEigsSolver "SymGEigsSolver (Cholesky mode)" for more details. +/// - The regular inverse mode requires the matrix-vector product \f$Bv\f$ and the +/// linear equation solving operation \f$B^{-1}v\f$. This mode should only be +/// used when the Cholesky decomposition of \f$B\f$ is hard to implement, or +/// when computing \f$B^{-1}v\f$ is much faster than the Cholesky decomposition. +/// See \ref SymGEigsSolver "SymGEigsSolver (Regular inverse mode)" for more details. + +// Empty class template +template < typename Scalar, + int SelectionRule, + typename OpType, + typename BOpType, + int GEigsMode > +class SymGEigsSolver +{}; + + + +/// +/// \ingroup GEigenSolver +/// +/// This class implements the generalized eigen solver for real symmetric +/// matrices using Cholesky decomposition, i.e., to solve \f$Ax=\lambda Bx\f$ +/// where \f$A\f$ is symmetric and \f$B\f$ is positive definite with the Cholesky +/// decomposition \f$B=LL'\f$. +/// +/// This solver requires two matrix operation objects: one for \f$A\f$ that implements +/// the matrix multiplication \f$Av\f$, and one for \f$B\f$ that implements the lower +/// and upper triangular solving \f$L^{-1}v\f$ and \f$(L')^{-1}v\f$. +/// +/// If \f$A\f$ and \f$B\f$ are stored as Eigen matrices, then the first operation +/// can be created using the DenseSymMatProd or SparseSymMatProd classes, and +/// the second operation can be created using the DenseCholesky or SparseCholesky +/// classes. If the users need to define their own operation classes, then they +/// should implement all the public member functions as in those built-in classes. +/// +/// \tparam Scalar The element type of the matrix. +/// Currently supported types are `float`, `double` and `long double`. +/// \tparam SelectionRule An enumeration value indicating the selection rule of +/// the requested eigenvalues, for example `LARGEST_MAGN` +/// to retrieve eigenvalues with the largest magnitude. +/// The full list of enumeration values can be found in +/// \ref Enumerations. +/// \tparam OpType The name of the matrix operation class for \f$A\f$. Users could either +/// use the wrapper classes such as DenseSymMatProd and +/// SparseSymMatProd, or define their +/// own that implements all the public member functions as in +/// DenseSymMatProd. +/// \tparam BOpType The name of the matrix operation class for \f$B\f$. Users could either +/// use the wrapper classes such as DenseCholesky and +/// SparseCholesky, or define their +/// own that implements all the public member functions as in +/// DenseCholesky. +/// \tparam GEigsMode Mode of the generalized eigen solver. In this solver +/// it is Spectra::GEIGS_CHOLESKY. +/// +/// Below is an example that demonstrates the usage of this class. +/// +/// \code{.cpp} +/// #include +/// #include +/// #include +/// #include +/// #include +/// #include +/// #include +/// +/// using namespace Spectra; +/// +/// int main() +/// { +/// // We are going to solve the generalized eigenvalue problem A * x = lambda * B * x +/// const int n = 100; +/// +/// // Define the A matrix +/// Eigen::MatrixXd M = Eigen::MatrixXd::Random(n, n); +/// Eigen::MatrixXd A = M + M.transpose(); +/// +/// // Define the B matrix, a band matrix with 2 on the diagonal and 1 on the subdiagonals +/// Eigen::SparseMatrix B(n, n); +/// B.reserve(Eigen::VectorXi::Constant(n, 3)); +/// for(int i = 0; i < n; i++) +/// { +/// B.insert(i, i) = 2.0; +/// if(i > 0) +/// B.insert(i - 1, i) = 1.0; +/// if(i < n - 1) +/// B.insert(i + 1, i) = 1.0; +/// } +/// +/// // Construct matrix operation object using the wrapper classes +/// DenseSymMatProd op(A); +/// SparseCholesky Bop(B); +/// +/// // Construct generalized eigen solver object, requesting the largest three generalized eigenvalues +/// SymGEigsSolver, SparseCholesky, GEIGS_CHOLESKY> +/// geigs(&op, &Bop, 3, 6); +/// +/// // Initialize and compute +/// geigs.init(); +/// int nconv = geigs.compute(); +/// +/// // Retrieve results +/// Eigen::VectorXd evalues; +/// Eigen::MatrixXd evecs; +/// if(geigs.info() == SUCCESSFUL) +/// { +/// evalues = geigs.eigenvalues(); +/// evecs = geigs.eigenvectors(); +/// } +/// +/// std::cout << "Generalized eigenvalues found:\n" << evalues << std::endl; +/// std::cout << "Generalized eigenvectors found:\n" << evecs.topRows(10) << std::endl; +/// +/// // Verify results using the generalized eigen solver in Eigen +/// Eigen::MatrixXd Bdense = B; +/// Eigen::GeneralizedSelfAdjointEigenSolver es(A, Bdense); +/// +/// std::cout << "Generalized eigenvalues:\n" << es.eigenvalues().tail(3) << std::endl; +/// std::cout << "Generalized eigenvectors:\n" << es.eigenvectors().rightCols(3).topRows(10) << std::endl; +/// +/// return 0; +/// } +/// \endcode + +// Partial specialization for GEigsMode = GEIGS_CHOLESKY +template < typename Scalar, + int SelectionRule, + typename OpType, + typename BOpType > +class SymGEigsSolver: + public SymEigsBase, IdentityBOp> +{ +private: + typedef Eigen::Index Index; + typedef Eigen::Matrix Matrix; + typedef Eigen::Matrix Vector; + + BOpType* m_Bop; + +public: + /// + /// Constructor to create a solver object. + /// + /// \param op Pointer to the \f$A\f$ matrix operation object. It + /// should implement the matrix-vector multiplication operation of \f$A\f$: + /// calculating \f$Av\f$ for any vector \f$v\f$. Users could either + /// create the object from the wrapper classes such as DenseSymMatProd, or + /// define their own that implements all the public member functions + /// as in DenseSymMatProd. + /// \param Bop Pointer to the \f$B\f$ matrix operation object. It + /// represents a Cholesky decomposition of \f$B\f$, and should + /// implement the lower and upper triangular solving operations: + /// calculating \f$L^{-1}v\f$ and \f$(L')^{-1}v\f$ for any vector + /// \f$v\f$, where \f$LL'=B\f$. Users could either + /// create the object from the wrapper classes such as DenseCholesky, or + /// define their own that implements all the public member functions + /// as in DenseCholesky. + /// \param nev Number of eigenvalues requested. This should satisfy \f$1\le nev \le n-1\f$, + /// where \f$n\f$ is the size of matrix. + /// \param ncv Parameter that controls the convergence speed of the algorithm. + /// Typically a larger `ncv` means faster convergence, but it may + /// also result in greater memory use and more matrix operations + /// in each iteration. This parameter must satisfy \f$nev < ncv \le n\f$, + /// and is advised to take \f$ncv \ge 2\cdot nev\f$. + /// + SymGEigsSolver(OpType* op, BOpType* Bop, Index nev, Index ncv) : + SymEigsBase, IdentityBOp>( + new SymGEigsCholeskyOp(*op, *Bop), NULL, nev, ncv + ), + m_Bop(Bop) + {} + + /// \cond + + ~SymGEigsSolver() + { + // m_op contains the constructed SymGEigsCholeskyOp object + delete this->m_op; + } + + Matrix eigenvectors(Index nvec) const + { + Matrix res = SymEigsBase, IdentityBOp>::eigenvectors(nvec); + Vector tmp(res.rows()); + const Index nconv = res.cols(); + for(Index i = 0; i < nconv; i++) + { + m_Bop->upper_triangular_solve(&res(0, i), tmp.data()); + res.col(i).noalias() = tmp; + } + + return res; + } + + Matrix eigenvectors() const + { + return SymGEigsSolver::eigenvectors(this->m_nev); + } + + /// \endcond +}; + + + +/// +/// \ingroup GEigenSolver +/// +/// This class implements the generalized eigen solver for real symmetric +/// matrices in the regular inverse mode, i.e., to solve \f$Ax=\lambda Bx\f$ +/// where \f$A\f$ is symmetric, and \f$B\f$ is positive definite with the operations +/// defined below. +/// +/// This solver requires two matrix operation objects: one for \f$A\f$ that implements +/// the matrix multiplication \f$Av\f$, and one for \f$B\f$ that implements the +/// matrix-vector product \f$Bv\f$ and the linear equation solving operation \f$B^{-1}v\f$. +/// +/// If \f$A\f$ and \f$B\f$ are stored as Eigen matrices, then the first operation +/// can be created using the DenseSymMatProd or SparseSymMatProd classes, and +/// the second operation can be created using the SparseRegularInverse class. There is no +/// wrapper class for a dense \f$B\f$ matrix since in this case the Cholesky mode +/// is always preferred. If the users need to define their own operation classes, then they +/// should implement all the public member functions as in those built-in classes. +/// +/// \tparam Scalar The element type of the matrix. +/// Currently supported types are `float`, `double` and `long double`. +/// \tparam SelectionRule An enumeration value indicating the selection rule of +/// the requested eigenvalues, for example `LARGEST_MAGN` +/// to retrieve eigenvalues with the largest magnitude. +/// The full list of enumeration values can be found in +/// \ref Enumerations. +/// \tparam OpType The name of the matrix operation class for \f$A\f$. Users could either +/// use the wrapper classes such as DenseSymMatProd and +/// SparseSymMatProd, or define their +/// own that implements all the public member functions as in +/// DenseSymMatProd. +/// \tparam BOpType The name of the matrix operation class for \f$B\f$. Users could either +/// use the wrapper class SparseRegularInverse, or define their +/// own that implements all the public member functions as in +/// SparseRegularInverse. +/// \tparam GEigsMode Mode of the generalized eigen solver. In this solver +/// it is Spectra::GEIGS_REGULAR_INVERSE. +/// + +// Partial specialization for GEigsMode = GEIGS_REGULAR_INVERSE +template < typename Scalar, + int SelectionRule, + typename OpType, + typename BOpType > +class SymGEigsSolver: + public SymEigsBase, BOpType> +{ +private: + typedef Eigen::Index Index; + +public: + /// + /// Constructor to create a solver object. + /// + /// \param op Pointer to the \f$A\f$ matrix operation object. It + /// should implement the matrix-vector multiplication operation of \f$A\f$: + /// calculating \f$Av\f$ for any vector \f$v\f$. Users could either + /// create the object from the wrapper classes such as DenseSymMatProd, or + /// define their own that implements all the public member functions + /// as in DenseSymMatProd. + /// \param Bop Pointer to the \f$B\f$ matrix operation object. It should + /// implement the multiplication operation \f$Bv\f$ and the linear equation + /// solving operation \f$B^{-1}v\f$ for any vector \f$v\f$. Users could either + /// create the object from the wrapper class SparseRegularInverse, or + /// define their own that implements all the public member functions + /// as in SparseRegularInverse. + /// \param nev Number of eigenvalues requested. This should satisfy \f$1\le nev \le n-1\f$, + /// where \f$n\f$ is the size of matrix. + /// \param ncv Parameter that controls the convergence speed of the algorithm. + /// Typically a larger `ncv` means faster convergence, but it may + /// also result in greater memory use and more matrix operations + /// in each iteration. This parameter must satisfy \f$nev < ncv \le n\f$, + /// and is advised to take \f$ncv \ge 2\cdot nev\f$. + /// + SymGEigsSolver(OpType* op, BOpType* Bop, Index nev, Index ncv) : + SymEigsBase, BOpType>( + new SymGEigsRegInvOp(*op, *Bop), Bop, nev, ncv + ) + {} + + /// \cond + ~SymGEigsSolver() + { + // m_op contains the constructed SymGEigsRegInvOp object + delete this->m_op; + } + /// \endcond +}; + + +} // namespace Spectra + +#endif // SYM_GEIGS_SOLVER_H diff --git a/external/Spectra/include/Spectra/Util/CompInfo.h b/external/Spectra/include/Spectra/Util/CompInfo.h new file mode 100644 index 000000000..b8e639d66 --- /dev/null +++ b/external/Spectra/include/Spectra/Util/CompInfo.h @@ -0,0 +1,37 @@ +// Copyright (C) 2016-2019 Yixuan Qiu +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at https://mozilla.org/MPL/2.0/. + +#ifndef COMP_INFO_H +#define COMP_INFO_H + +namespace Spectra { + + +/// +/// \ingroup Enumerations +/// +/// The enumeration to report the status of computation. +/// +enum COMPUTATION_INFO +{ + SUCCESSFUL = 0, ///< Computation was successful. + + NOT_COMPUTED, ///< Used in eigen solvers, indicating that computation + ///< has not been conducted. Users should call + ///< the `compute()` member function of solvers. + + NOT_CONVERGING, ///< Used in eigen solvers, indicating that some eigenvalues + ///< did not converge. The `compute()` + ///< function returns the number of converged eigenvalues. + + NUMERICAL_ISSUE ///< Used in Cholesky decomposition, indicating that the + ///< matrix is not positive definite. +}; + + +} // namespace Spectra + +#endif // COMP_INFO_H diff --git a/external/Spectra/include/Spectra/Util/GEigsMode.h b/external/Spectra/include/Spectra/Util/GEigsMode.h new file mode 100644 index 000000000..d03f269d6 --- /dev/null +++ b/external/Spectra/include/Spectra/Util/GEigsMode.h @@ -0,0 +1,34 @@ +// Copyright (C) 2016-2019 Yixuan Qiu +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at https://mozilla.org/MPL/2.0/. + +#ifndef GEIGS_MODE_H +#define GEIGS_MODE_H + +namespace Spectra { + + +/// +/// \ingroup Enumerations +/// +/// The enumeration to specify the mode of generalized eigenvalue solver. +/// +enum GEIGS_MODE +{ + GEIGS_CHOLESKY = 0, ///< Using Cholesky decomposition to solve generalized eigenvalues. + + GEIGS_REGULAR_INVERSE, ///< Regular inverse mode for generalized eigenvalue solver. + + GEIGS_SHIFT_INVERT, ///< Shift-and-invert mode for generalized eigenvalue solver. + + GEIGS_BUCKLING, ///< Buckling mode for generalized eigenvalue solver. + + GEIGS_CAYLEY ///< Cayley transformation mode for generalized eigenvalue solver. +}; + + +} // namespace Spectra + +#endif // GEIGS_MODE_H diff --git a/external/Spectra/include/Spectra/Util/SelectionRule.h b/external/Spectra/include/Spectra/Util/SelectionRule.h new file mode 100644 index 000000000..19f71dcf2 --- /dev/null +++ b/external/Spectra/include/Spectra/Util/SelectionRule.h @@ -0,0 +1,277 @@ +// Copyright (C) 2016-2019 Yixuan Qiu +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at https://mozilla.org/MPL/2.0/. + +#ifndef SELECTION_RULE_H +#define SELECTION_RULE_H + +#include // std::vector +#include // std::abs +#include // std::sort +#include // std::complex +#include // std::pair +#include // std::invalid_argument + +namespace Spectra { + + +/// +/// \defgroup Enumerations +/// +/// Enumeration types for the selection rule of eigenvalues. +/// + +/// +/// \ingroup Enumerations +/// +/// The enumeration of selection rules of desired eigenvalues. +/// +enum SELECT_EIGENVALUE +{ + LARGEST_MAGN = 0, ///< Select eigenvalues with largest magnitude. Magnitude + ///< means the absolute value for real numbers and norm for + ///< complex numbers. Applies to both symmetric and general + ///< eigen solvers. + + LARGEST_REAL, ///< Select eigenvalues with largest real part. Only for general eigen solvers. + + LARGEST_IMAG, ///< Select eigenvalues with largest imaginary part (in magnitude). Only for general eigen solvers. + + LARGEST_ALGE, ///< Select eigenvalues with largest algebraic value, considering + ///< any negative sign. Only for symmetric eigen solvers. + + SMALLEST_MAGN, ///< Select eigenvalues with smallest magnitude. Applies to both symmetric and general + ///< eigen solvers. + + SMALLEST_REAL, ///< Select eigenvalues with smallest real part. Only for general eigen solvers. + + SMALLEST_IMAG, ///< Select eigenvalues with smallest imaginary part (in magnitude). Only for general eigen solvers. + + SMALLEST_ALGE, ///< Select eigenvalues with smallest algebraic value. Only for symmetric eigen solvers. + + BOTH_ENDS ///< Select eigenvalues half from each end of the spectrum. When + ///< `nev` is odd, compute more from the high end. Only for symmetric eigen solvers. +}; + +/// +/// \ingroup Enumerations +/// +/// The enumeration of selection rules of desired eigenvalues. Alias for `SELECT_EIGENVALUE`. +/// +enum SELECT_EIGENVALUE_ALIAS +{ + WHICH_LM = 0, ///< Alias for `LARGEST_MAGN` + WHICH_LR, ///< Alias for `LARGEST_REAL` + WHICH_LI, ///< Alias for `LARGEST_IMAG` + WHICH_LA, ///< Alias for `LARGEST_ALGE` + WHICH_SM, ///< Alias for `SMALLEST_MAGN` + WHICH_SR, ///< Alias for `SMALLEST_REAL` + WHICH_SI, ///< Alias for `SMALLEST_IMAG` + WHICH_SA, ///< Alias for `SMALLEST_ALGE` + WHICH_BE ///< Alias for `BOTH_ENDS` +}; + +/// \cond + +// Get the element type of a "scalar" +// ElemType => double +// ElemType< std::complex > => double +template +class ElemType +{ +public: + typedef T type; +}; + +template +class ElemType< std::complex > +{ +public: + typedef T type; +}; + +// When comparing eigenvalues, we first calculate the "target" +// to sort. For example, if we want to choose the eigenvalues with +// largest magnitude, the target will be -abs(x). +// The minus sign is due to the fact that std::sort() sorts in ascending order. + +// Default target: throw an exception +template +class SortingTarget +{ +public: + static typename ElemType::type get(const Scalar& val) + { + using std::abs; + throw std::invalid_argument("incompatible selection rule"); + return -abs(val); + } +}; + +// Specialization for LARGEST_MAGN +// This covers [float, double, complex] x [LARGEST_MAGN] +template +class SortingTarget +{ +public: + static typename ElemType::type get(const Scalar& val) + { + using std::abs; + return -abs(val); + } +}; + +// Specialization for LARGEST_REAL +// This covers [complex] x [LARGEST_REAL] +template +class SortingTarget, LARGEST_REAL> +{ +public: + static RealType get(const std::complex& val) + { + return -val.real(); + } +}; + +// Specialization for LARGEST_IMAG +// This covers [complex] x [LARGEST_IMAG] +template +class SortingTarget, LARGEST_IMAG> +{ +public: + static RealType get(const std::complex& val) + { + using std::abs; + return -abs(val.imag()); + } +}; + +// Specialization for LARGEST_ALGE +// This covers [float, double] x [LARGEST_ALGE] +template +class SortingTarget +{ +public: + static Scalar get(const Scalar& val) + { + return -val; + } +}; + +// Here BOTH_ENDS is the same as LARGEST_ALGE, but +// we need some additional steps, which are done in +// SymEigsSolver.h => retrieve_ritzpair(). +// There we move the smallest values to the proper locations. +template +class SortingTarget +{ +public: + static Scalar get(const Scalar& val) + { + return -val; + } +}; + +// Specialization for SMALLEST_MAGN +// This covers [float, double, complex] x [SMALLEST_MAGN] +template +class SortingTarget +{ +public: + static typename ElemType::type get(const Scalar& val) + { + using std::abs; + return abs(val); + } +}; + +// Specialization for SMALLEST_REAL +// This covers [complex] x [SMALLEST_REAL] +template +class SortingTarget, SMALLEST_REAL> +{ +public: + static RealType get(const std::complex& val) + { + return val.real(); + } +}; + +// Specialization for SMALLEST_IMAG +// This covers [complex] x [SMALLEST_IMAG] +template +class SortingTarget, SMALLEST_IMAG> +{ +public: + static RealType get(const std::complex& val) + { + using std::abs; + return abs(val.imag()); + } +}; + +// Specialization for SMALLEST_ALGE +// This covers [float, double] x [SMALLEST_ALGE] +template +class SortingTarget +{ +public: + static Scalar get(const Scalar& val) + { + return val; + } +}; + +// Sort eigenvalues and return the order index +template +class PairComparator +{ +public: + bool operator() (const PairType& v1, const PairType& v2) + { + return v1.first < v2.first; + } +}; + +template +class SortEigenvalue +{ +private: + typedef typename ElemType::type TargetType; // Type of the sorting target, will be + // a floating number type, e.g. "double" + typedef std::pair PairType; // Type of the sorting pair, including + // the sorting target and the index + + std::vector pair_sort; + +public: + SortEigenvalue(const T* start, int size) : + pair_sort(size) + { + for(int i = 0; i < size; i++) + { + pair_sort[i].first = SortingTarget::get(start[i]); + pair_sort[i].second = i; + } + PairComparator comp; + std::sort(pair_sort.begin(), pair_sort.end(), comp); + } + + std::vector index() + { + std::vector ind(pair_sort.size()); + for(unsigned int i = 0; i < ind.size(); i++) + ind[i] = pair_sort[i].second; + + return ind; + } +}; + +/// \endcond + + +} // namespace Spectra + +#endif // SELECTION_RULE_H diff --git a/external/Spectra/include/Spectra/Util/SimpleRandom.h b/external/Spectra/include/Spectra/Util/SimpleRandom.h new file mode 100644 index 000000000..7b1e6162a --- /dev/null +++ b/external/Spectra/include/Spectra/Util/SimpleRandom.h @@ -0,0 +1,93 @@ +// Copyright (C) 2016-2019 Yixuan Qiu +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at https://mozilla.org/MPL/2.0/. + +#ifndef SIMPLE_RANDOM_H +#define SIMPLE_RANDOM_H + +#include + +/// \cond + +namespace Spectra { + + +// We need a simple pseudo random number generator here: +// 1. It is used to generate initial and restarted residual vector. +// 2. It is not necessary to be so "random" and advanced. All we hope +// is that the residual vector is not in the space spanned by the +// current Krylov space. This should be met almost surely. +// 3. We don't want to call RNG in C++, since we actually want the +// algorithm to be deterministic. Also, calling RNG in C/C++ is not +// allowed in R packages submitted to CRAN. +// 4. The method should be as simple as possible, so an LCG is enough. +// 5. Based on public domain code by Ray Gardner +// http://stjarnhimlen.se/snippets/rg_rand.c + + +template +class SimpleRandom +{ +private: + typedef Eigen::Index Index; + typedef Eigen::Matrix Vector; + + const unsigned int m_a; // multiplier + const unsigned long m_max; // 2^31 - 1 + long m_rand; + + inline long next_long_rand(long seed) + { + unsigned long lo, hi; + + lo = m_a * (long)(seed & 0xFFFF); + hi = m_a * (long)((unsigned long)seed >> 16); + lo += (hi & 0x7FFF) << 16; + if(lo > m_max) + { + lo &= m_max; + ++lo; + } + lo += hi >> 15; + if(lo > m_max) + { + lo &= m_max; + ++lo; + } + return (long)lo; + } +public: + SimpleRandom(unsigned long init_seed) : + m_a(16807), + m_max(2147483647L), + m_rand(init_seed ? (init_seed & m_max) : 1) + {} + + Scalar random() + { + m_rand = next_long_rand(m_rand); + return Scalar(m_rand) / Scalar(m_max) - Scalar(0.5); + } + + // Vector of random numbers of type Scalar + // Ranging from -0.5 to 0.5 + Vector random_vec(const Index len) + { + Vector res(len); + for(Index i = 0; i < len; i++) + { + m_rand = next_long_rand(m_rand); + res[i] = Scalar(m_rand) / Scalar(m_max) - Scalar(0.5); + } + return res; + } +}; + + +} // namespace Spectra + +/// \endcond + +#endif // SIMPLE_RANDOM_H diff --git a/external/Spectra/include/Spectra/Util/TypeTraits.h b/external/Spectra/include/Spectra/Util/TypeTraits.h new file mode 100644 index 000000000..a4cc05b28 --- /dev/null +++ b/external/Spectra/include/Spectra/Util/TypeTraits.h @@ -0,0 +1,73 @@ +// Copyright (C) 2018-2019 Yixuan Qiu +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at https://mozilla.org/MPL/2.0/. + +#ifndef TYPE_TRAITS_H +#define TYPE_TRAITS_H + +#include +#include + +/// \cond + +namespace Spectra { + + +// For a real value type "Scalar", we want to know its smallest +// positive value, i.e., std::numeric_limits::min(). +// However, we must take non-standard value types into account, +// so we rely on Eigen::NumTraits. +// +// Eigen::NumTraits has defined epsilon() and lowest(), but +// lowest() means negative highest(), which is a very small +// negative value. +// +// Therefore, we manually define this limit, and use eplison()^3 +// to mimic it for non-standard types. + +// Generic definition +template +struct TypeTraits +{ + static inline Scalar min() + { + return Eigen::numext::pow(Eigen::NumTraits::epsilon(), Scalar(3)); + } +}; + +// Full specialization +template <> +struct TypeTraits +{ + static inline float min() + { + return std::numeric_limits::min(); + } +}; + +template <> +struct TypeTraits +{ + static inline double min() + { + return std::numeric_limits::min(); + } +}; + +template <> +struct TypeTraits +{ + static inline long double min() + { + return std::numeric_limits::min(); + } +}; + + +} // namespace Spectra + +/// \endcond + +#endif // TYPE_TRAITS_H diff --git a/external/Spectra/include/Spectra/contrib/LOBPCGSolver.h b/external/Spectra/include/Spectra/contrib/LOBPCGSolver.h new file mode 100644 index 000000000..5ca001f6b --- /dev/null +++ b/external/Spectra/include/Spectra/contrib/LOBPCGSolver.h @@ -0,0 +1,501 @@ +// Written by Anna Araslanova +// Modified by Yixuan Qiu +// License: MIT + +#ifndef LOBPCG_SOLVER +#define LOBPCG_SOLVER + +#include +#include + +#include +#include +#include +#include +#include + +#include "../SymGEigsSolver.h" + + +namespace Spectra { + + /// + /// \ingroup EigenSolver + /// + + /// *** METHOD + /// The class represent the LOBPCG algorithm, which was invented by Andrew Knyazev + /// Theoretical background of the procedure can be found in the articles below + /// - Knyazev, A.V., 2001. Toward the optimal preconditioned eigensolver : Locally optimal block preconditioned conjugate gradient method.SIAM journal on scientific computing, 23(2), pp.517 - 541. + /// - Knyazev, A.V., Argentati, M.E., Lashuk, I. and Ovtchinnikov, E.E., 2007. Block locally optimal preconditioned eigenvalue xolvers(BLOPEX) in HYPRE and PETSc.SIAM Journal on Scientific Computing, 29(5), pp.2224 - 2239. + /// + /// *** CONDITIONS OF USE + /// Locally Optimal Block Preconditioned Conjugate Gradient(LOBPCG) is a method for finding the M smallest eigenvalues + /// and eigenvectors of a large symmetric positive definite generalized eigenvalue problem + /// \f$Ax=\lambda Bx,\f$ + /// where \f$A_{NxN}\f$ is a symmetric matrix, \f$B\f$ is symmetric and positive - definite. \f$A and B\f$ are also assumed large and sparse + /// \f$\textit{M}\f$ should be \f$\<< textit{N}\f$ (at least \f$\textit{5M} < \textit{N} \f$) + /// + /// *** ARGUMENTS + /// Eigen::SparseMatrix A; // N*N - Ax = lambda*Bx, lrage and sparse + /// Eigen::SparseMatrix X; // N*M - initial approximations to eigenvectors (random in general case) + /// Spectra::LOBPCGSolver solver(A, X); + /// *Eigen::SparseMatrix B; // N*N - Ax = lambda*Bx, sparse, positive definite + /// solver.setConstraints(B); + /// *Eigen::SparseMatrix Y; // N*K - constraints, already found eigenvectors + /// solver.setB(B); + /// *Eigen::SparseMatrix T; // N*N - preconditioner ~ A^-1 + /// solver.setPreconditioner(T); + /// + /// *** OUTCOMES + /// solver.solve(); // compute eigenpairs // void + /// solver.info(); // state of converjance // int + /// solver.residuals(); // get residuals to evaluate biases // Eigen::Matrix + /// solver.eigenvalues(); // get eigenvalues // Eigen::Matrix + /// solver.eigenvectors(); // get eigenvectors // Eigen::Matrix + /// + /// *** EXAMPLE + /// \code{.cpp} + /// #include + /// + /// // random A + /// Matrix a; + /// a = (Matrix::Random(10, 10).array() > 0.6).cast() * Matrix::Random(10, 10).array() * 5; + /// a = Matrix((a).triangularView()) + Matrix((a).triangularView()).transpose(); + /// for (int i = 0; i < 10; i++) + /// a(i, i) = i + 0.5; + /// std::cout << a << "\n"; + /// Eigen::SparseMatrix A(a.sparseView()); + /// // random X + /// Eigen::Matrix x; + /// x = Matrix::Random(10, 2).array(); + /// Eigen::SparseMatrix X(x.sparseView()); + /// // solve Ax = lambda*x + /// Spectra::LOBPCGSolver solver(A, X); + /// solver.compute(10, 1e-4); // 10 iterations, L2_tolerance = 1e-4*N + /// std::cout << "info\n" << solver.info() << std::endl; + /// std::cout << "eigenvalues\n" << solver.eigenvalues() << std::endl; + /// std::cout << "eigenvectors\n" << solver.eigenvectors() << std::endl; + /// std::cout << "residuals\n" << solver.residuals() << std::endl; + /// \endcode + /// + + template < typename Scalar = long double> + class LOBPCGSolver { + private: + + typedef Eigen::Matrix Matrix; + typedef Eigen::Matrix Vector; + + typedef std::complex Complex; + typedef Eigen::Matrix ComplexMatrix; + typedef Eigen::Matrix ComplexVector; + + typedef Eigen::SparseMatrix SparseMatrix; + typedef Eigen::SparseMatrix SparseComplexMatrix; + + const int m_n; // dimension of matrix A + const int m_nev; // number of eigenvalues requested + SparseMatrix A, X; + SparseMatrix m_Y, m_B, m_preconditioner; + bool flag_with_constraints, flag_with_B, flag_with_preconditioner; + + public: + SparseMatrix m_residuals; + Matrix m_evectors; + Vector m_evalues; + int m_info; + + private: + + // B-orthonormalize matrix M + int orthogonalizeInPlace(SparseMatrix &M, SparseMatrix &B, \ + SparseMatrix &true_BM, bool has_true_BM = false) { + + SparseMatrix BM; + + if (has_true_BM == false) { + if (flag_with_B) { BM = B * M; } + else { BM = M; } + } + else { + BM = true_BM; + } + + Eigen::SimplicialLDLT chol_MBM(M.transpose() * BM); + + if (chol_MBM.info() != SUCCESSFUL) { + // LDLT decomposition fail + m_info = chol_MBM.info(); + return chol_MBM.info(); + } + + SparseComplexMatrix Upper_MBM = chol_MBM.matrixU().template cast(); + ComplexVector D_MBM_vec = chol_MBM.vectorD().template cast(); + + D_MBM_vec = D_MBM_vec.cwiseSqrt(); + + for (int i = 0; i < D_MBM_vec.rows(); i++) { + D_MBM_vec(i) = Complex(1.0, 0.0) / D_MBM_vec(i); + } + + SparseComplexMatrix D_MBM_mat(D_MBM_vec.asDiagonal()); + + SparseComplexMatrix U_inv(Upper_MBM.rows(), Upper_MBM.cols()); + U_inv.setIdentity(); + Upper_MBM.template triangularView().solveInPlace(U_inv); + + SparseComplexMatrix right_product = U_inv * D_MBM_mat; + M = M*right_product.real(); + if (flag_with_B) { true_BM = B * M; } + else { true_BM = M; } + + return SUCCESSFUL; + } + + void applyConstraintsInPlace(SparseMatrix &X, SparseMatrix&Y, \ + SparseMatrix&B) { + SparseMatrix BY; + if (flag_with_B) { BY = B * Y; } + else { BY = Y; } + + SparseMatrix YBY = Y.transpose() * BY; + SparseMatrix BYX = BY.transpose() * X; + + SparseMatrix YBY_XYX = (Matrix(YBY).bdcSvd(Eigen::ComputeThinU | Eigen::ComputeThinV).solve(Matrix(BYX))).sparseView(); + X = X - Y * YBY_XYX; + } + + /* + return + 'AB + CD' + */ + Matrix stack_4_matricies(Matrix A, Matrix B, \ + Matrix C, Matrix D) { + Matrix result(A.rows() + C.rows(), A.cols() + B.cols()); + result.topLeftCorner(A.rows(), A.cols()) = A; + result.topRightCorner(B.rows(), B.cols()) = B; + result.bottomLeftCorner(C.rows(), C.cols()) = C; + result.bottomRightCorner(D.rows(), D.cols()) = D; + return result; + } + + Matrix stack_9_matricies(Matrix A, Matrix B, Matrix C, \ + Matrix D, Matrix E, Matrix F, \ + Matrix G, Matrix H, Matrix I) { + + Matrix result(A.rows() + D.rows() + G.rows(), A.cols() + B.cols() + C.cols()); + result.block(0, 0, A.rows(), A.cols()) = A; + result.block(0, A.cols(), B.rows(), B.cols()) = B; + result.block(0, A.cols() + B.cols(), C.rows(), C.cols()) = C; + result.block(A.rows(), 0, D.rows(), D.cols()) = D; + result.block(A.rows(), A.cols(), E.rows(), E.cols()) = E; + result.block(A.rows(), A.cols() + B.cols(), F.rows(), F.cols()) = F; + result.block(A.rows() + D.rows(), 0, G.rows(), G.cols()) = G; + result.block(A.rows() + D.rows(), A.cols(), H.rows(), H.cols()) = H; + result.block(A.rows() + D.rows(), A.cols() + B.cols(), I.rows(), I.cols()) = I; + + return result; + } + + void sort_epairs(Vector &evalues, Matrix &evectors, int SelectionRule) { + + std::function cmp; + if (SelectionRule == SMALLEST_ALGE) + cmp = std::less{}; + else + cmp = std::greater{}; + + std::map epairs(cmp); + for (int i = 0; i < m_evectors.cols(); ++i) + epairs.insert(std::make_pair(evalues(i), evectors.col(i))); + + int i = 0; + for (auto& epair : epairs) { + evectors.col(i) = epair.second; + evalues(i) = epair.first; + i++; + } + } + + void removeColumns(SparseMatrix& matrix, std::vector& colToRemove) + { + // remove columns through matrix multiplication + SparseMatrix new_matrix(matrix.cols(), matrix.cols() - int(colToRemove.size())); + int iCol = 0; + std::vector> tripletList; + tripletList.reserve(matrix.cols() - int(colToRemove.size())); + + for (int iRow = 0; iRow < matrix.cols(); iRow++) { + if (std::find(colToRemove.begin(), colToRemove.end(), iRow) == colToRemove.end()) { + tripletList.push_back(Eigen::Triplet(iRow, iCol, 1)); + iCol++; + } + } + + new_matrix.setFromTriplets(tripletList.begin(), tripletList.end()); + matrix = matrix * new_matrix; + } + + int checkConvergence_getBlocksize(SparseMatrix & m_residuals, Scalar tolerance_L2, std::vector & columnsToDelete) { + // square roots from sum of squares by column + int BlockSize = m_nev; + Scalar sum, buffer; + + for (int iCol = 0; iCol < m_nev; iCol++) { + sum = 0; + for (int iRow = 0; iRow < m_n; iRow++) { + buffer = m_residuals.coeff(iRow, iCol); + sum += buffer * buffer; + } + + if (sqrt(sum) < tolerance_L2) { + BlockSize--; + columnsToDelete.push_back(iCol); + } + } + return BlockSize; + } + + + public: + + LOBPCGSolver(const SparseMatrix& A, const SparseMatrix X) : + m_n(A.rows()), + m_nev(X.cols()), + m_info(NOT_COMPUTED), + flag_with_constraints(false), + flag_with_B(false), + flag_with_preconditioner(false), + A(A), + X(X) + { + if (A.rows() != X.rows() || A.rows() != A.cols()) + throw std::invalid_argument("Wrong size"); + + //if (m_n < 5* m_nev) + // throw std::invalid_argument("The problem size is small compared to the block size. Use standard eigensolver"); + } + + void setConstraints(const SparseMatrix& Y) { + m_Y = Y; + flag_with_constraints = true; + } + + void setB(const SparseMatrix& B) { + if (B.rows() != A.rows() || B.cols() != A.cols()) + throw std::invalid_argument("Wrong size"); + m_B = B; + flag_with_B = true; + } + + void setPreconditioner(const SparseMatrix& preconditioner) { + m_preconditioner = preconditioner; + flag_with_preconditioner = true; + } + + void compute(int maxit = 10, Scalar tol_div_n = 1e-7) { + + Scalar tolerance_L2 = tol_div_n * m_n; + int BlockSize; + int max_iter = std::min(m_n, maxit); + + SparseMatrix directions, AX, AR, BX, AD, ADD, DD, BDD, BD, XAD, RAD, DAD, XBD, RBD, BR, sparse_eVecX, sparse_eVecR, sparse_eVecD, inverse_matrix; + Matrix XAR, RAR, XBR, gramA, gramB, eVecX, eVecR, eVecD; + std::vector columnsToDelete; + + if (flag_with_constraints) { + // Apply the constraints Y to X + applyConstraintsInPlace(X, m_Y, m_B); + } + + // Make initial vectors orthonormal + // implicit BX declaration + if (orthogonalizeInPlace(X, m_B, BX) != SUCCESSFUL) { + max_iter = 0; + } + + AX = A * X; + // Solve the following NxN eigenvalue problem for all N eigenvalues and -vectors: + // first approximation via a dense problem + Eigen::EigenSolver eigs(Matrix(X.transpose() * AX)); + + if (eigs.info() != SUCCESSFUL) { + m_info = eigs.info(); + max_iter = 0; + } + else { + m_evalues = eigs.eigenvalues().real(); + m_evectors = eigs.eigenvectors().real(); + sort_epairs(m_evalues, m_evectors, SMALLEST_ALGE); + sparse_eVecX = m_evectors.sparseView(); + + X = X * sparse_eVecX; + AX = AX * sparse_eVecX; + BX = BX * sparse_eVecX; + } + + + for (int iter_num = 0; iter_num < max_iter; iter_num++) { + m_residuals.resize(m_n, m_nev); + for (int i = 0; i < m_nev; i++) { + m_residuals.col(i) = AX.col(i) - m_evalues(i) * BX.col(i); + } + BlockSize = checkConvergence_getBlocksize(m_residuals, tolerance_L2, columnsToDelete); + + if (BlockSize == 0) { + m_info = SUCCESSFUL; + break; + } + + // substitution of the original active mask + if (columnsToDelete.size() > 0) { + removeColumns(m_residuals, columnsToDelete); + if (iter_num > 0) { + removeColumns(directions, columnsToDelete); + removeColumns(AD, columnsToDelete); + removeColumns(BD, columnsToDelete); + } + columnsToDelete.clear(); // for next iteration + } + + if (flag_with_preconditioner) { + // Apply the preconditioner to the residuals + m_residuals = m_preconditioner * m_residuals; + } + + if (flag_with_constraints) { + // Apply the constraints Y to residuals + applyConstraintsInPlace(m_residuals, m_Y, m_B); + } + + if (orthogonalizeInPlace(m_residuals, m_B, BR) != SUCCESSFUL) { + break; + } + AR = A * m_residuals; + + // Orthonormalize conjugate directions + if (iter_num > 0) { + if (orthogonalizeInPlace(directions, m_B, BD, true) != SUCCESSFUL) { + break; + } + AD = A * directions; + } + + // Perform the Rayleigh Ritz Procedure + XAR = Matrix(X.transpose() * AR); + RAR = Matrix(m_residuals.transpose() * AR); + XBR = Matrix(X.transpose() * BR); + + if (iter_num > 0) { + + XAD = X.transpose() * AD; + RAD = m_residuals.transpose() * AD; + DAD = directions.transpose() * AD; + XBD = X.transpose() * BD; + RBD = m_residuals.transpose() * BD; + + gramA = stack_9_matricies(m_evalues.asDiagonal(), XAR, XAD, XAR.transpose(), RAR, RAD, XAD.transpose(), RAD.transpose(), DAD.transpose()); + gramB = stack_9_matricies(Matrix::Identity(m_nev, m_nev), XBR, XBD, XBR.transpose(), Matrix::Identity(BlockSize, BlockSize), RBD, XBD.transpose(), RBD.transpose(), Matrix::Identity(BlockSize, BlockSize)); + + } + else { + gramA = stack_4_matricies(m_evalues.asDiagonal(), XAR, XAR.transpose(), RAR); + gramB = stack_4_matricies(Matrix::Identity(m_nev, m_nev), XBR, XBR.transpose(), Matrix::Identity(BlockSize, BlockSize)); + } + + //calculate the lowest/largest m eigenpairs; Solve the generalized eigenvalue problem. + DenseSymMatProd Aop(gramA); + DenseCholesky Bop(gramB); + + SymGEigsSolver, \ + DenseCholesky, GEIGS_CHOLESKY> geigs(&Aop, &Bop, m_nev, std::min(10, int(gramA.rows()) - 1)); + + geigs.init(); + int nconv = geigs.compute(); + + //Mat evecs; + if (geigs.info() == SUCCESSFUL) { + m_evalues = geigs.eigenvalues(); + m_evectors = geigs.eigenvectors(); + sort_epairs(m_evalues, m_evectors, SMALLEST_ALGE); + } + else { + // Problem With General EgenVec + m_info = geigs.info(); + break; + } + + // Compute Ritz vectors + if (iter_num > 0) { + eVecX = m_evectors.block(0, 0, m_nev, m_nev); + eVecR = m_evectors.block(m_nev, 0, BlockSize, m_nev); + eVecD = m_evectors.block(m_nev + BlockSize, 0, BlockSize, m_nev); + + sparse_eVecX = eVecX.sparseView(); + sparse_eVecR = eVecR.sparseView(); + sparse_eVecD = eVecD.sparseView(); + + DD = m_residuals * sparse_eVecR; // new conjugate directions + ADD = AR * sparse_eVecR; + BDD = BR * sparse_eVecR; + + DD = DD + directions * sparse_eVecD; + ADD = ADD + AD * sparse_eVecD; + BDD = BDD + BD * sparse_eVecD; + } + else { + eVecX = m_evectors.block(0, 0, m_nev, m_nev); + eVecR = m_evectors.block(m_nev, 0, BlockSize, m_nev); + + sparse_eVecX = eVecX.sparseView(); + sparse_eVecR = eVecR.sparseView(); + + DD = m_residuals * sparse_eVecR; + ADD = AR * sparse_eVecR; + BDD = BR * sparse_eVecR; + } + + X = X * sparse_eVecX + DD; + AX = AX * sparse_eVecX + ADD; + BX = BX * sparse_eVecX + BDD; + + directions = DD; + AD = ADD; + BD = BDD; + + } // iteration loop + + // calculate last residuals + m_residuals.resize(m_n, m_nev); + for (int i = 0; i < m_nev; i++) { + m_residuals.col(i) = AX.col(i) - m_evalues(i) * BX.col(i); + } + BlockSize = checkConvergence_getBlocksize(m_residuals, tolerance_L2, columnsToDelete); + + if (BlockSize == 0) { + m_info = SUCCESSFUL; + } + } // compute + + Vector eigenvalues() { + return m_evalues; + } + + Matrix eigenvectors() { + return m_evectors; + } + + Matrix residuals() { + return Matrix(m_residuals); + } + + int info() { return m_info; } + + }; + + +} // namespace Spectra + +#endif // LOBPCG_SOLVER diff --git a/external/Spectra/include/Spectra/contrib/PartialSVDSolver.h b/external/Spectra/include/Spectra/contrib/PartialSVDSolver.h new file mode 100644 index 000000000..dad5b4003 --- /dev/null +++ b/external/Spectra/include/Spectra/contrib/PartialSVDSolver.h @@ -0,0 +1,203 @@ +// Copyright (C) 2018 Yixuan Qiu +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at https://mozilla.org/MPL/2.0/. + +#ifndef PARTIAL_SVD_SOLVER_H +#define PARTIAL_SVD_SOLVER_H + +#include +#include "../SymEigsSolver.h" + + +namespace Spectra { + + +// Abstract class for matrix operation +template +class SVDMatOp +{ +public: + virtual int rows() const = 0; + virtual int cols() const = 0; + + // y_out = A' * A * x_in or y_out = A * A' * x_in + virtual void perform_op(const Scalar* x_in, Scalar* y_out) = 0; + + virtual ~SVDMatOp() {} +}; + +// Operation of a tall matrix in SVD +// We compute the eigenvalues of A' * A +// MatrixType is either Eigen::Matrix or Eigen::SparseMatrix +template +class SVDTallMatOp: public SVDMatOp +{ +private: + typedef Eigen::Matrix Vector; + typedef Eigen::Map MapConstVec; + typedef Eigen::Map MapVec; + typedef const Eigen::Ref ConstGenericMatrix; + + ConstGenericMatrix m_mat; + const int m_dim; + Vector m_cache; + +public: + // Constructor + SVDTallMatOp(ConstGenericMatrix& mat) : + m_mat(mat), + m_dim(std::min(mat.rows(), mat.cols())), + m_cache(mat.rows()) + {} + + // These are the rows and columns of A' * A + int rows() const { return m_dim; } + int cols() const { return m_dim; } + + // y_out = A' * A * x_in + void perform_op(const Scalar* x_in, Scalar* y_out) + { + MapConstVec x(x_in, m_mat.cols()); + MapVec y(y_out, m_mat.cols()); + m_cache.noalias() = m_mat * x; + y.noalias() = m_mat.transpose() * m_cache; + } +}; + +// Operation of a wide matrix in SVD +// We compute the eigenvalues of A * A' +// MatrixType is either Eigen::Matrix or Eigen::SparseMatrix +template +class SVDWideMatOp: public SVDMatOp +{ +private: + typedef Eigen::Matrix Vector; + typedef Eigen::Map MapConstVec; + typedef Eigen::Map MapVec; + typedef const Eigen::Ref ConstGenericMatrix; + + ConstGenericMatrix m_mat; + const int m_dim; + Vector m_cache; + +public: + // Constructor + SVDWideMatOp(ConstGenericMatrix& mat) : + m_mat(mat), + m_dim(std::min(mat.rows(), mat.cols())), + m_cache(mat.cols()) + {} + + // These are the rows and columns of A * A' + int rows() const { return m_dim; } + int cols() const { return m_dim; } + + // y_out = A * A' * x_in + void perform_op(const Scalar* x_in, Scalar* y_out) + { + MapConstVec x(x_in, m_mat.rows()); + MapVec y(y_out, m_mat.rows()); + m_cache.noalias() = m_mat.transpose() * x; + y.noalias() = m_mat * m_cache; + } +}; + +// Partial SVD solver +// MatrixType is either Eigen::Matrix or Eigen::SparseMatrix +template < typename Scalar = double, + typename MatrixType = Eigen::Matrix > +class PartialSVDSolver +{ +private: + typedef Eigen::Matrix Matrix; + typedef Eigen::Matrix Vector; + typedef const Eigen::Ref ConstGenericMatrix; + + ConstGenericMatrix m_mat; + const int m_m; + const int m_n; + SVDMatOp* m_op; + SymEigsSolver< Scalar, LARGEST_ALGE, SVDMatOp >* m_eigs; + int m_nconv; + Matrix m_evecs; + +public: + // Constructor + PartialSVDSolver(ConstGenericMatrix& mat, int ncomp, int ncv) : + m_mat(mat), m_m(mat.rows()), m_n(mat.cols()), m_evecs(0, 0) + { + // Determine the matrix type, tall or wide + if(m_m > m_n) + { + m_op = new SVDTallMatOp(mat); + } else { + m_op = new SVDWideMatOp(mat); + } + + // Solver object + m_eigs = new SymEigsSolver< Scalar, LARGEST_ALGE, SVDMatOp >(m_op, ncomp, ncv); + } + + // Destructor + virtual ~PartialSVDSolver() + { + delete m_eigs; + delete m_op; + } + + // Computation + int compute(int maxit = 1000, Scalar tol = 1e-10) + { + m_eigs->init(); + m_nconv = m_eigs->compute(maxit, tol); + + return m_nconv; + } + + // The converged singular values + Vector singular_values() const + { + Vector svals = m_eigs->eigenvalues().cwiseSqrt(); + + return svals; + } + + // The converged left singular vectors + Matrix matrix_U(int nu) + { + if(m_evecs.cols() < 1) + { + m_evecs = m_eigs->eigenvectors(); + } + nu = std::min(nu, m_nconv); + if(m_m <= m_n) + { + return m_evecs.leftCols(nu); + } + + return m_mat * (m_evecs.leftCols(nu).array().rowwise() / m_eigs->eigenvalues().head(nu).transpose().array().sqrt()).matrix(); + } + + // The converged right singular vectors + Matrix matrix_V(int nv) + { + if(m_evecs.cols() < 1) + { + m_evecs = m_eigs->eigenvectors(); + } + nv = std::min(nv, m_nconv); + if(m_m > m_n) + { + return m_evecs.leftCols(nv); + } + + return m_mat.transpose() * (m_evecs.leftCols(nv).array().rowwise() / m_eigs->eigenvalues().head(nv).transpose().array().sqrt()).matrix(); + } +}; + + +} // namespace Spectra + +#endif // PARTIAL_SVD_SOLVER_H diff --git a/external/arpack++/include/README b/external/arpack++/include/README new file mode 100644 index 000000000..dc4a33dc0 --- /dev/null +++ b/external/arpack++/include/README @@ -0,0 +1,232 @@ +This is the ARPACK++ include directory. + +1) Files included in this directory: + + a) Files that contain ARPACK++ classes definitions: + + i) Base classes: + + file class + ---------- ---------------- + arrseig.h ARrcStdEig + arrgeig.h ARrcGenEig + arseig.h ARStdEig + argeig.h ARGenEig + armat.h ARMatrix + + + ii) Classes that require matrix-vector product functions: + + file class + ---------- ---------------- + arssym.h ARSymStdEig + arsnsym.h ARNonSymStdEig + arscomp.h ARCompStdEig + argsym.h ARSymGenEig + argnsym.h ARNonSymGenEig + argcomp.g ARCompGenEig + + + iii) Classes that require matrices in CSC format (SuperLU version): + + file class + ---------- ---------------- + arlssym.h ARluSymStdEig + arlsnsym.h ARluNonSymStdEig + arlscomp.h ARluCompStdEig + arlgsym.h ARluSymGenEig + arlgnsym.h ARluNonSymGenEig + arlgcomp.h ARluCompGenEig + + + iv) Classes that require matrices in CSC format (UMFPACK version): + + file class + ---------- ---------------- + arussym.h ARluSymStdEig + arusnsym.h ARluNonSymStdEig + aruscomp.h ARluCompStdEig + arugsym.h ARluSymGenEig + arugnsym.h ARluNonSymGenEig + arugcomp.h ARluCompGenEig + + + v) Classes that require matrices in band format: + + file class + ---------- ---------------- + arbssym.h ARluSymStdEig + arbsnsym.h ARluNonSymStdEig + arbscomp.h ARluCompStdEig + arbgsym.h ARluSymGenEig + arbgnsym.h ARluNonSymGenEig + arbgcomp.h ARluCompGenEig + + + vi) Reverse communication classes: + + file class + ---------- ---------------- + arrssym.h ARrcSymStdEig + arrsnsym.h ARrcNonSymStdEig + arrscomp.h ARrcCompStdEig + arrgsym.h ARrcSymGenEig + arrgnsym.h ARrcNonSymGenEig + arrgcomp.h ARrcCompGenEig + + + vii) Matrix classes: + + file class + ---------- ---------------- + arlsmat.h ARluSymMatrix + arlspen.h ARluSymPencil + arlnsmat.h ARluNonSymMatrix + arlnspen.h ARluNonSymPencil + arusmat.h ARumSymMatrix + aruspen.h ARumSymPencil + arunsmat.h ARumNonSymMatrix + arunspen.h ARumNonSymPencil + arbsmat.h ARbdSymMatrix + arbspen.h ARbdSymPencil + arbnsmat.h ARbdNonSymMatrix + arbnspen.h ARbdNonSymPencil + arhbmat.h ARhbMatrix + + + b) Package interface files: + + i) ARPACK FORTRAN interface: + + file Contents + ---------- ----------------------------------------------- + saupp.h Interface with dsaupd and ssaupd subroutines. + seupp.h Interface with dseupd and sseupd subroutines. + naupp.h Interface with dnaupd and snaupd subroutines. + neupp.h Interface with dneupd and sneupd subroutines. + caupp.h Interface with znaupd and cnaupd subroutines. + ceupp.h Interface with zneupd and cneupd subroutines. + debug.h Interface with ARPACK debugging variables. + arpackf.h Fortran to C function prototypes convertion. + + + ii) LAPACK and BLAS1 interface: + + file Contents + ---------- ----------------------------------------------- + lapackc.h Various LAPACK function declarations. + lapackf.h Fortran to C function prototypes convertion. + blas1c.h Various BLAS1 function declarations. + blas1f.h Fortran to C function prototypes convertion. + + + iii) SuperLU interface: + + file Contents + ---------- ----------------------------------------------- + superluc.h Various SuperLU function declarations. + arlspdef.h Altered version of ssp_defs.h, dsp_defs.h, + csp_defs.h and zsp_defs.h header files. + arlsupm.h Unaltered copy of supermatrix.h header file. + arlnames.h Unaltered copy of Cnames.h header file. + arlutil.h Unaltered copy of util.h, superlu_enum_consts.h. + arlcomp.h Unaltered copy of dcomplex.h and scomplex.h. + + + iv) UMFPACK interface: + + file Contents + ---------- ----------------------------------------------- + umfpackc.h Various UMFPACK function declarations. + umfpackf.h Fortran to C function prototypes convertion. + + + c) Other auxiliary files: + + file Contents + ---------- ----------------------------------------------- + arch.h Machine dependent functions and variable types. + arcomp.h "arcomplex" complex type definition. + arerror.h "ArpackError" class definition. + + + +2) Compiler-dependent instructions. + + Some compiler-dependent functions and data types used by arpack++ are + grouped in the file arch.h. This file should be changed to reflect the + characteristics of your system. Another file, arcomp.h, contains the + definition of a class template called arcomplex, created to emulate + the g++ complex class when another compiler is being used. This file + must also be changed if g++ (or CC) is not being used. + + a) Changing ARPACK++ parameters and definitions included in arch.h: + + All ARPACK++ parameters that are not intended to be changed frequently + were included in the arch.h file. Are defined in this file + + i) Some machine and problem-dependent umfpack parameters. + + If the umfpack is to be used, the user can modify some of its + parameters to correctly reflect the environment and the class + of problems being solved. The constants included in arch.h + correspond to a subset of the parameters generated by the um21i + umfpack function. Other relevant parameters can also be passed + to the ARumNonSymMatrix class constructor. + + ii) Some fortran to c conversion functions. + + Because fortran and c++ functions tend to have different + representations in different platforms, a function that + converts a fortran function name to the c++ format is + defined in arch.h. This function can be altered by the user + if the environment being used was not included in arch.h. + + iii) Some fortran to c type conversion rules. + + arch.h also includes the definition of some rules required + to convert INTEGER and LOGICAL FORTRAN types to c++. + + iv) The c++ bool type. + + If the c++ compiler being used does not include a bool type, + this type can also be defined in arch.h. + + + b) Redefining arcomplex class in arcomp.h: + + ARPACK++ uses a self-defined complex class called arcomplex. + Actually, arcomplex is a class template used to represent + both single and double precision complex numbers. It was created + in an effort to permit ARPACK++ to deal with different compilers, + since c++ does not define a unique complex type. + arcomplex is intended to emulate the gnu g++ complex class when + other compilers are being used (when g++ is used, ARPACK++ simply + declares arcomplex to be the standard complex type). arcomp.h + includes a complex class definition for the CC compiler only. At + the present time, no other compiler was used to generate ARPACK++ + programs, so further work must be done to permit the use of the + library with other compilers. + To define a new complex type, the user must create a class + template (called arcomplex) that contains at least three members: + + i) A default constructor; + ii) A copy constructor; and + iii) A constructor that takes two real numbers as parameters (one + is the real and other the imaginary part of the complex number). + + Naturally, all usual mathematical operations on complex numbers, + such as addition, multiplication, multiplication by a real number, + etc, should also be defined. But because most compilers include a + complex data type, the simplest way of defining arcomplex is to use + only the three constructors mentioned above to establish a relation + between the actual complex class and the gnu g++ standard. + + +5) ARPACK (fortran) authors: + + Danny Sorensen (sorensen@caam.rice.edu) + Richard Lehoucq (lehoucq@mcs.anl.gov) + Chao Yang (chao@caam.rice.edu) + Kristi Maschhoff (kristyn@caam.rice.edu) + diff --git a/external/arpack++/include/arbgcomp.h b/external/arpack++/include/arbgcomp.h new file mode 100644 index 000000000..93f682281 --- /dev/null +++ b/external/arpack++/include/arbgcomp.h @@ -0,0 +1,204 @@ +/* + ARPACK++ v1.2 2/20/2000 + c++ interface to ARPACK code. + + MODULE ARBGComp.h. + Arpack++ class ARluCompGenEig definition + (band matrix version). + + ARPACK Authors + Richard Lehoucq + Danny Sorensen + Chao Yang + Dept. of Computational & Applied Mathematics + Rice University + Houston, Texas +*/ + +#ifndef ARBGCOMP_H +#define ARBGCOMP_H + +#include +#include +#include "arch.h" +#include "arbnsmat.h" +#include "arbnspen.h" +#include "arrseig.h" +#include "argcomp.h" + + +template +class ARluCompGenEig: + public virtual + ARCompGenEig, ARFLOAT >, + ARbdNonSymPencil, ARFLOAT > > { + + private: + + // a) Data structure used to store matrices. + + ARbdNonSymPencil, ARFLOAT > Pencil; + + // b) Protected functions: + + virtual void Copy(const ARluCompGenEig& other); + // Makes a deep copy of "other" over "this" object. + // Old values are not deleted (this function is to be used + // by the copy constructor and the assignment operator only). + + + public: + + // c) Public functions: + + // c.1) Functions that allow changes in problem parameters. + + virtual void ChangeShift(arcomplex sigmaRp); + + virtual void SetRegularMode(); + + virtual void SetShiftInvertMode(arcomplex sigmap); + + // c.2) Constructors and destructor. + + ARluCompGenEig() { } + // Short constructor. + + ARluCompGenEig(int nevp, ARbdNonSymMatrix, ARFLOAT>& A, + ARbdNonSymMatrix, ARFLOAT>& B, + const std::string& whichp = "LM", int ncvp = 0, + ARFLOAT tolp = 0.0, int maxitp = 0, + arcomplex* residp = NULL, bool ishiftp = true); + // Long constructor (regular mode). + + ARluCompGenEig(int nevp, ARbdNonSymMatrix, ARFLOAT>& A, + ARbdNonSymMatrix, ARFLOAT>& B, + arcomplex sigma, const std::string& whichp = "LM", + int ncvp = 0, ARFLOAT tolp = 0.0, int maxitp = 0, + arcomplex* residp = NULL, bool ishiftp = true); + // Long constructor (shift and invert mode). + + ARluCompGenEig(const ARluCompGenEig& other) { Copy(other); } + // Copy constructor. + + virtual ~ARluCompGenEig() { } + + // d) Operators. + + ARluCompGenEig& operator=(const ARluCompGenEig& other); + // Assignment operator. + +}; // class ARluCompGenEig. + + +// ------------------------------------------------------------------------ // +// ARluCompGenEig member functions definition. // +// ------------------------------------------------------------------------ // + + +template +inline void ARluCompGenEig:: +Copy(const ARluCompGenEig& other) +{ + + ARCompGenEig, ARFLOAT >, + ARbdNonSymPencil, ARFLOAT> >:: Copy(other); + Pencil = other.Pencil; + this->objOP = &Pencil; + this->objB = &Pencil; + +} // Copy. + + +template +inline void ARluCompGenEig:: +ChangeShift(arcomplex sigmaRp) +{ + + this->objOP->FactorAsB(sigmaRp); + ARrcStdEig >::ChangeShift(sigmaRp); + +} // ChangeShift. + + +template +inline void ARluCompGenEig::SetRegularMode() +{ + + ARStdEig, + ARbdNonSymPencil, ARFLOAT> >:: + SetRegularMode(&Pencil, + &ARbdNonSymPencil, ARFLOAT>::MultInvBAv); + +} // SetRegularMode. + + +template +inline void ARluCompGenEig:: +SetShiftInvertMode(arcomplex sigmap) +{ + + ARCompGenEig, ARFLOAT>, + ARbdNonSymPencil, ARFLOAT> >:: + SetShiftInvertMode(sigmap, &Pencil, + &ARbdNonSymPencil,ARFLOAT>::MultInvAsBv); + +} // SetShiftInvertMode. + + +template +inline ARluCompGenEig:: +ARluCompGenEig(int nevp, ARbdNonSymMatrix, ARFLOAT>& A, + ARbdNonSymMatrix, ARFLOAT>& B, const std::string& whichp, + int ncvp, ARFLOAT tolp, int maxitp, + arcomplex* residp, bool ishiftp) + +{ + + Pencil.DefineMatrices(A, B); + this->NoShift(); + this->DefineParameters(A.ncols(), nevp, &Pencil, + &ARbdNonSymPencil, ARFLOAT>::MultInvBAv, + &Pencil, + &ARbdNonSymPencil, ARFLOAT>::MultBv, + whichp, ncvp, tolp, maxitp, residp, ishiftp); + +} // Long constructor (regular mode). + + +template +inline ARluCompGenEig:: +ARluCompGenEig(int nevp, ARbdNonSymMatrix, ARFLOAT>& A, + ARbdNonSymMatrix, ARFLOAT>& B, + arcomplex sigmap, const std::string& whichp, int ncvp, + ARFLOAT tolp, int maxitp, arcomplex* residp, + bool ishiftp) + +{ + + Pencil.DefineMatrices(A, B); + this->DefineParameters(A.ncols(), nevp, &Pencil, + &ARbdNonSymPencil, ARFLOAT>::MultInvAsBv, + &Pencil, + &ARbdNonSymPencil,ARFLOAT>::MultBv, + whichp, ncvp, tolp, maxitp, residp, ishiftp); + SetShiftInvertMode(sigmap); + +} // Long constructor (shift and invert mode). + + +template +ARluCompGenEig& ARluCompGenEig:: +operator=(const ARluCompGenEig& other) +{ + + if (this != &other) { // Stroustrup suggestion. + this->ClearMem(); + Copy(other); + } + return *this; + +} // operator=. + + +#endif // ARBGCOMP_H diff --git a/external/arpack++/include/arbgnsym.h b/external/arpack++/include/arbgnsym.h new file mode 100644 index 000000000..19a141303 --- /dev/null +++ b/external/arpack++/include/arbgnsym.h @@ -0,0 +1,243 @@ +/* + ARPACK++ v1.2 2/20/2000 + c++ interface to ARPACK code. + + MODULE ARBGNSym.h. + Arpack++ class ARluNonSymGenEig definition + (band matrix version). + + ARPACK Authors + Richard Lehoucq + Danny Sorensen + Chao Yang + Dept. of Computational & Applied Mathematics + Rice University + Houston, Texas +*/ + +#ifndef ARBGNSYM_H +#define ARBGNSYM_H + +#include +#include +#include "arch.h" +#include "arbnsmat.h" +#include "arbnspen.h" +#include "argnsym.h" + + +template +class ARluNonSymGenEig: + public virtual ARNonSymGenEig, + ARbdNonSymPencil > { + + private: + + // a) Data structure used to store matrices. + + ARbdNonSymPencil Pencil; + + // b) Protected functions: + + virtual void Copy(const ARluNonSymGenEig& other); + // Makes a deep copy of "other" over "this" object. + // Old values are not deleted (this function is to be used + // by the copy constructor and the assignment operator only). + + + public: + + // c) Public functions: + + // c.1) Functions that allow changes in problem parameters. + + virtual void ChangeShift(ARFLOAT sigmaRp, ARFLOAT sigmaIp = 0.0); + + virtual void SetRegularMode(); + + virtual void SetShiftInvertMode(ARFLOAT sigmap); + + virtual void SetComplexShiftMode(char partp, ARFLOAT sigmaRp, ARFLOAT sigmaIp); + + // c.2) Constructors and destructor. + + ARluNonSymGenEig() { } + // Short constructor. + + ARluNonSymGenEig(int nevp, ARbdNonSymMatrix& A, + ARbdNonSymMatrix& B, const std::string& whichp = "LM", + int ncvp = 0, ARFLOAT tolp = 0.0, int maxitp = 0, + ARFLOAT* residp = NULL, bool ishiftp = true); + // Long constructor (regular mode). + + ARluNonSymGenEig(int nevp, ARbdNonSymMatrix& A, + ARbdNonSymMatrix& B, ARFLOAT sigma, + const std::string& whichp = "LM", int ncvp = 0, + ARFLOAT tolp = 0.0, int maxitp = 0, + ARFLOAT* residp = NULL, bool ishiftp = true); + // Long constructor (real shift and invert mode). + + ARluNonSymGenEig(int nevp, ARbdNonSymMatrix& A, + ARbdNonSymMatrix& B, char partp, + ARFLOAT sigmaRp, ARFLOAT sigmaIp, const std::string& whichp = "LM", + int ncvp = 0, ARFLOAT tolp = 0.0, int maxitp = 0, + ARFLOAT* residp = NULL, bool ishiftp = true); + // Long constructor (complex shift and invert mode). + + ARluNonSymGenEig(const ARluNonSymGenEig& other) { Copy(other); } + // Copy constructor. + + virtual ~ARluNonSymGenEig() { } + // Destructor. + + // d) Operators. + + ARluNonSymGenEig& operator=(const ARluNonSymGenEig& other); + // Assignment operator. + +}; // class ARluNonSymGenEig. + + +// ------------------------------------------------------------------------ // +// ARluNonSymGenEig member functions definition. // +// ------------------------------------------------------------------------ // + + +template +inline void ARluNonSymGenEig:: +Copy(const ARluNonSymGenEig& other) +{ + + ARNonSymGenEig, + ARbdNonSymPencil >:: Copy(other); + Pencil = other.Pencil; + this->objOP = &Pencil; + this->objB = &Pencil; + this->objA = &Pencil; + +} // Copy. + + +template +inline void ARluNonSymGenEig:: +ChangeShift(ARFLOAT sigmaRp, ARFLOAT sigmaIp) +{ + + if (sigmaIp == 0.0) { + this->objOP->FactorAsB(sigmaRp); + } + else { + this->objOP->FactorAsB(sigmaRp, sigmaIp, this->part); + } + ARrcNonSymGenEig::ChangeShift(sigmaRp, sigmaIp); + +} // ChangeShift. + + +template +inline void ARluNonSymGenEig::SetRegularMode() +{ + + ARStdEig >:: + SetRegularMode(&Pencil, &ARbdNonSymPencil::MultInvBAv); + +} // SetRegularMode. + + +template +inline void ARluNonSymGenEig::SetShiftInvertMode(ARFLOAT sigmap) +{ + + ARNonSymGenEig, + ARbdNonSymPencil >:: + SetShiftInvertMode(sigmap, &Pencil, + &ARbdNonSymPencil::MultInvAsBv); + +} // SetShiftInvertMode. + + +template +inline void ARluNonSymGenEig:: +SetComplexShiftMode(char partp, ARFLOAT sigmaRp, ARFLOAT sigmaIp) +{ + + ARNonSymGenEig, + ARbdNonSymPencil >:: + SetComplexShiftMode(partp, sigmaRp, sigmaIp, &Pencil, + &ARbdNonSymPencil::MultInvAsBv, + &Pencil, &ARbdNonSymPencil::MultAv); + +} // SetComplexShiftMode. + + +template +inline ARluNonSymGenEig:: +ARluNonSymGenEig(int nevp, ARbdNonSymMatrix& A, + ARbdNonSymMatrix& B, const std::string& whichp, int ncvp, + ARFLOAT tolp, int maxitp, ARFLOAT* residp, bool ishiftp) + +{ + + Pencil.DefineMatrices(A, B); + this->NoShift(); + this->DefineParameters(A.ncols(), nevp, &Pencil, + &ARbdNonSymPencil::MultInvBAv, &Pencil, + &ARbdNonSymPencil::MultBv, whichp, + ncvp, tolp, maxitp, residp, ishiftp); + +} // Long constructor (regular mode). + + +template +inline ARluNonSymGenEig:: +ARluNonSymGenEig(int nevp, ARbdNonSymMatrix& A, + ARbdNonSymMatrix& B, ARFLOAT sigmap, + const std::string& whichp, int ncvp, ARFLOAT tolp, + int maxitp, ARFLOAT* residp, bool ishiftp) + +{ + + Pencil.DefineMatrices(A, B); + this->DefineParameters(A.ncols(), nevp, &Pencil, + &ARbdNonSymPencil::MultInvAsBv, &Pencil, + &ARbdNonSymPencil::MultBv, whichp, + ncvp, tolp, maxitp, residp, ishiftp); + SetShiftInvertMode(sigmap); + +} // Long constructor (real shift and invert mode). + + +template +inline ARluNonSymGenEig:: +ARluNonSymGenEig(int nevp, ARbdNonSymMatrix& A, + ARbdNonSymMatrix& B, char partp, + ARFLOAT sigmaRp, ARFLOAT sigmaIp, const std::string& whichp, int ncvp, + ARFLOAT tolp, int maxitp, ARFLOAT* residp, bool ishiftp) + +{ + + Pencil.DefineMatrices(A, B); + this->DefineParameters(A.ncols(), nevp, &Pencil, + &ARbdNonSymPencil::MultInvAsBv, &Pencil, + &ARbdNonSymPencil::MultBv, whichp, + ncvp, tolp, maxitp, residp, ishiftp); + SetComplexShiftMode(partp, sigmaRp, sigmaIp); + +} // Long constructor (complex shift and invert mode). + + +template +ARluNonSymGenEig& ARluNonSymGenEig:: +operator=(const ARluNonSymGenEig& other) +{ + + if (this != &other) { // Stroustrup suggestion. + this->ClearMem(); + Copy(other); + } + return *this; + +} // operator=. + + +#endif // ARBGNSYM_H diff --git a/external/arpack++/include/arbgsym.h b/external/arpack++/include/arbgsym.h new file mode 100644 index 000000000..82926bcae --- /dev/null +++ b/external/arpack++/include/arbgsym.h @@ -0,0 +1,233 @@ +/* + ARPACK++ v1.2 2/20/2000 + c++ interface to ARPACK code. + + MODULE ARBGSym.h. + Arpack++ class ARluSymGenEig definition + (band matrix version). + + ARPACK Authors + Richard Lehoucq + Danny Sorensen + Chao Yang + Dept. of Computational & Applied Mathematics + Rice University + Houston, Texas +*/ + +#ifndef ARBGSYM_H +#define ARBGSYM_H + +#include +#include +#include "arch.h" +#include "arbsmat.h" +#include "arbspen.h" +#include "argsym.h" + + +template +class ARluSymGenEig: + public virtual ARSymGenEig, + ARbdSymPencil > { + + private: + + // a) Data structure used to store matrices. + + ARbdSymPencil Pencil; + + // b) Protected functions: + + virtual void Copy(const ARluSymGenEig& other); + // Makes a deep copy of "other" over "this" object. + // Old values are not deleted (this function is to be used + // by the copy constructor and the assignment operator only). + + + public: + + // c) Public functions: + + // c.1) Functions that allow changes in problem parameters. + + virtual void ChangeShift(ARFLOAT sigmap); + + virtual void SetRegularMode(); + + virtual void SetShiftInvertMode(ARFLOAT sigmap); + + virtual void SetBucklingMode(ARFLOAT sigmap); + + virtual void SetCayleyMode(ARFLOAT sigmap); + + // c.2) Constructors and destructor. + + ARluSymGenEig() { } + // Short constructor. + + ARluSymGenEig(int nevp, ARbdSymMatrix& A, + ARbdSymMatrix& B, const std::string& whichp = "LM", + int ncvp = 0, ARFLOAT tolp = 0.0, int maxitp = 0, + ARFLOAT* residp = NULL, bool ishiftp = true); + // Long constructor (regular mode). + + ARluSymGenEig(char InvertModep, int nevp, ARbdSymMatrix& A, + ARbdSymMatrix& B, ARFLOAT sigma, const std::string& whichp = "LM", + int ncvp = 0, ARFLOAT tolp = 0.0, int maxitp = 0, + ARFLOAT* residp = NULL, bool ishiftp = true); + // Long constructor (shift and invert, buckling and Cayley modes). + + ARluSymGenEig(const ARluSymGenEig& other) { Copy(other); } + // Copy constructor. + + virtual ~ARluSymGenEig() { } + // Destructor. + + // d) Operators. + + ARluSymGenEig& operator=(const ARluSymGenEig& other); + // Assignment operator. + +}; // class ARluSymGenEig. + + +// ------------------------------------------------------------------------ // +// ARluSymGenEig member functions definition. // +// ------------------------------------------------------------------------ // + + +template +inline void ARluSymGenEig:: +Copy(const ARluSymGenEig& other) +{ + + ARSymGenEig, + ARbdSymPencil >:: Copy(other); + Pencil = other.Pencil; + this->objOP = &Pencil; + this->objB = &Pencil; + this->objA = &Pencil; + +} // Copy. + + +template +inline void ARluSymGenEig::ChangeShift(ARFLOAT sigmap) +{ + + this->objOP->FactorAsB(sigmap); + ARrcSymGenEig::ChangeShift(sigmap); + +} // ChangeShift. + + +template +inline void ARluSymGenEig::SetRegularMode() +{ + + ARStdEig >:: + SetRegularMode(&Pencil, &ARbdSymPencil::MultInvBAv); + +} // SetRegularMode. + + +template +inline void ARluSymGenEig:: +SetShiftInvertMode(ARFLOAT sigmap) +{ + + ARSymGenEig, ARbdSymPencil >:: + SetShiftInvertMode(sigmap, &Pencil, &ARbdSymPencil::MultInvAsBv); + this->ChangeMultBx(&Pencil, &ARbdSymPencil::MultBv); + +} // SetShiftInvertMode. + + +template +inline void ARluSymGenEig:: +SetBucklingMode(ARFLOAT sigmap) +{ + + ARSymGenEig, ARbdSymPencil >:: + SetBucklingMode(sigmap, &Pencil, &ARbdSymPencil::MultInvAsBv); + this->ChangeMultBx(&Pencil, &ARbdSymPencil::MultAv); + +} // SetBucklingMode. + + +template +inline void ARluSymGenEig:: +SetCayleyMode(ARFLOAT sigmap) +{ + + ARSymGenEig, ARbdSymPencil >:: + SetCayleyMode(sigmap, &Pencil, &ARbdSymPencil::MultInvAsBv, + &Pencil, &ARbdSymPencil::MultAv); + this->ChangeMultBx(&Pencil, &ARbdSymPencil::MultBv); + +} // SetCayleyMode. + + +template +inline ARluSymGenEig:: +ARluSymGenEig(int nevp, ARbdSymMatrix& A, + ARbdSymMatrix& B, const std::string& whichp, int ncvp, + ARFLOAT tolp, int maxitp, ARFLOAT* residp, bool ishiftp) + +{ + + Pencil.DefineMatrices(A, B); + this->InvertMode = 'S'; + this->NoShift(); + this->DefineParameters(A.ncols(), nevp, &Pencil, + &ARbdSymPencil::MultInvBAv, &Pencil, + &ARbdSymPencil::MultBv, whichp, + ncvp, tolp, maxitp, residp, ishiftp); + +} // Long constructor (regular mode). + + +template +inline ARluSymGenEig:: +ARluSymGenEig(char InvertModep, int nevp, ARbdSymMatrix& A, + ARbdSymMatrix& B, ARFLOAT sigmap, + const std::string& whichp, int ncvp, ARFLOAT tolp, + int maxitp, ARFLOAT* residp, bool ishiftp) + +{ + + Pencil.DefineMatrices(A, B); + this->DefineParameters(A.ncols(), nevp, &Pencil, + &ARbdSymPencil::MultInvAsBv, &Pencil, + &ARbdSymPencil::MultBv, whichp, + ncvp, tolp, maxitp, residp, ishiftp); + this->InvertMode = this->CheckInvertMode(InvertModep); + switch (this->InvertMode) { + case 'B': + this->ChangeMultBx(&Pencil, &ARbdSymPencil::MultAv); + case 'S': + ChangeShift(sigmap); + break; + case 'C': + SetCayleyMode(sigmap); + } + +} // Long constructor (shift and invert, buckling and Cayley modes). + + +template +ARluSymGenEig& ARluSymGenEig:: +operator=(const ARluSymGenEig& other) +{ + + if (this != &other) { // Stroustrup suggestion. + this->ClearMem(); + Copy(other); + } + return *this; + +} // operator=. + + +#endif // ARBGSYM_H diff --git a/external/arpack++/include/arbnsmat.h b/external/arpack++/include/arbnsmat.h new file mode 100644 index 000000000..f56069f70 --- /dev/null +++ b/external/arpack++/include/arbnsmat.h @@ -0,0 +1,431 @@ +/* + ARPACK++ v1.2 2/20/2000 + c++ interface to ARPACK code. + + MODULE ARBNSMat.h. + Arpack++ class ARbdNonSymMatrix definition. + + ARPACK Authors + Richard Lehoucq + Danny Sorensen + Chao Yang + Dept. of Computational & Applied Mathematics + Rice University + Houston, Texas +*/ + + +#include "arbnspen.h" + +#ifndef ARBNSMAT_H +#define ARBNSMAT_H + +#include +#include "arch.h" +#include "armat.h" +#include "arerror.h" +#include "blas1c.h" +#include "lapackc.h" + +template class ARbdNonSymPencil; + +template +class ARbdNonSymMatrix: public ARMatrix { + + friend class ARbdNonSymPencil; + friend class ARbdNonSymPencil; + + protected: + + bool factored; + int ndiagL; + int ndiagU; + int lda; + int info; + int* ipiv; + ARTYPE* A; + ARTYPE* Ainv; + + void ClearMem(); + + virtual void Copy(const ARbdNonSymMatrix& other); + + void ExpandA(); + + void SubtractAsI(ARTYPE sigma); + + void CreateStructure(); + + void ThrowError(); + + public: + + bool IsFactored() { return factored; } + + void FactorA(); + + void FactorAsI(ARTYPE sigma); + + void MultMv(ARTYPE* v, ARTYPE* w); + + void MultMtv(ARTYPE* v, ARTYPE* w); + + void MultMtMv(ARTYPE* v, ARTYPE* w); + + void MultMMtv(ARTYPE* v, ARTYPE* w); + + void Mult0MMt0v(ARTYPE* v, ARTYPE* w); + + void MultInvv(ARTYPE* v, ARTYPE* w); + + void DefineMatrix(int np, int ndiagLp, int ndiagUp, ARTYPE* Ap); + + ARbdNonSymMatrix(): ARMatrix() { factored = false; } + // Short constructor that does nothing. + + ARbdNonSymMatrix(int np, int ndiagLp, int ndiagUp, ARTYPE* Ap); + // Long constructor. + + ARbdNonSymMatrix(const ARbdNonSymMatrix& other) { Copy(other); } + // Copy constructor. + + virtual ~ARbdNonSymMatrix() { ClearMem(); } + // Destructor. + + ARbdNonSymMatrix& operator=(const ARbdNonSymMatrix& other); + // Assignment operator. + +}; + +// ------------------------------------------------------------------------ // +// ARbdNonSymMatrix member functions definition. // +// ------------------------------------------------------------------------ // + + +template +inline void ARbdNonSymMatrix::ClearMem() +{ + + if (factored) { + delete[] Ainv; + delete[] ipiv; + Ainv = NULL; + ipiv = NULL; + } + +} // ClearMem. + + +template +inline void ARbdNonSymMatrix:: +Copy(const ARbdNonSymMatrix& other) +{ + + // Copying very fundamental variables and user-defined parameters. + + this->m = other.m; + this->n = other.n; + this->defined = other.defined; + factored = other.factored; + ndiagL = other.ndiagL; + ndiagU = other.ndiagU; + lda = other.lda; + info = other.info; + A = other.A; + + // Returning from here if "other" was not factored. + + if (!factored) return; + + // Copying vectors. + + Ainv = new ARTYPE[ this->n*lda]; + ipiv = new int[ this->n]; + + copy( this->n*lda, other.Ainv, 1, Ainv, 1); + for (int i=0; i< this->n; i++) ipiv[i] = other.ipiv[i]; + +} // Copy. + + +template +void ARbdNonSymMatrix::ExpandA() +{ + + int i, inca; + + // Copying A to Ainv. + + inca = ndiagL+ndiagU+1; + for (i = 0; i < inca; i++) { + copy( this->n, &A[i], inca, &Ainv[ndiagL+i], lda); + } + +} // ExpandA. + + +template +void ARbdNonSymMatrix::SubtractAsI(ARTYPE sigma) +{ + + // Copying A to Ainv. + + ExpandA(); + + // Subtracting sigma from diagonal elements. + + for (int i=(ndiagL+ndiagU); i<(lda* this->n); i+=lda) Ainv[i] -= sigma; + +} // SubtractAsI. + + +template +inline void ARbdNonSymMatrix::CreateStructure() +{ + + ClearMem(); + Ainv = new ARTYPE[lda* this->n]; + ipiv = new int[ this->n]; + +} // CreateStructure. + + +template +inline void ARbdNonSymMatrix::ThrowError() +{ + + if (info < 0) { // Illegal argument. + throw ArpackError(ArpackError::PARAMETER_ERROR, + "ARbdNonSymMatrix::FactorA"); + } + else if (info) { // Matrix is singular. + throw ArpackError(ArpackError::MATRIX_IS_SINGULAR, + "ARbdNonSymMatrix::FactorA"); + } + +} // ThrowError. + + +template +void ARbdNonSymMatrix::FactorA() +{ + + // Quitting the function if A was not defined. + + if (! this->IsDefined()) { + throw ArpackError(ArpackError::DATA_UNDEFINED, "ARbdNonSymMatrix::FactorA"); + } + + // Reserving memory for some vectors used in matrix decomposition. + + CreateStructure(); + + // Copying A to Ainv; + + ExpandA(); + + // Decomposing A. + + gbtrf( this->n, this->n, ndiagL, ndiagU, Ainv, lda, ipiv, info); + + // Handling errors. + + ThrowError(); + + factored = true; + +} // FactorA. + + +template +void ARbdNonSymMatrix::FactorAsI(ARTYPE sigma) +{ + + // Quitting the function if A was not defined. + + if (! this->IsDefined()) { + throw ArpackError(ArpackError::DATA_UNDEFINED, + "ARbdNonSymMatrix::FactorAsI"); + } + + // Reserving memory for some vectors used in matrix decomposition. + + CreateStructure(); + + // Subtracting sigma*I from A. + + SubtractAsI(sigma); + + // Decomposing AsI. + + gbtrf( this->n, this->n, ndiagL, ndiagU, Ainv, lda, ipiv, info); + + // Handling errors. + + ThrowError(); + + factored = true; + +} // FactorAsI. + + +template +void ARbdNonSymMatrix::MultMv(ARTYPE* v, ARTYPE* w) +{ + + ARTYPE one; + ARTYPE zero; + + one = (ARTYPE)0 + 1.0; + zero = (ARTYPE)0; + + // Quitting the function if A was not defined. + + if (! this->IsDefined()) { + throw ArpackError(ArpackError::DATA_UNDEFINED, "ARbdNonSymMatrix::MultMv"); + } + + // Determining w = M.v. + + gbmv("N", this->m, this->n, ndiagL, ndiagU, one, A, + ndiagL+ndiagU+1, v, 1, zero, w, 1); + +} // MultMv. + + +template +void ARbdNonSymMatrix::MultMtv(ARTYPE* v, ARTYPE* w) +{ + + ARTYPE one; + ARTYPE zero; + + one = (ARTYPE)0 + 1.0; + zero = (ARTYPE)0; + + // Quitting the function if A was not defined. + + if (! this->IsDefined()) { + throw ArpackError(ArpackError::DATA_UNDEFINED, "ARbdNonSymMatrix::MultMtv"); + } + + // Determining w = M'.v. + + gbmv("T", this->m, this->n, ndiagL, ndiagU, one, A, + ndiagL+ndiagU+1, v, 1, zero, w, 1); + +} // MultMtv. + + +template +void ARbdNonSymMatrix::MultMtMv(ARTYPE* v, ARTYPE* w) +{ + + ARTYPE* t = new ARTYPE[ this->m]; + + MultMv(v,t); + MultMtv(t,w); + + delete[] t; + +} // MultMtMv. + + +template +void ARbdNonSymMatrix::MultMMtv(ARTYPE* v, ARTYPE* w) +{ + + ARTYPE* t = new ARTYPE[ this->n]; + + MultMtv(v,t); + MultMv(t,w); + + delete[] t; + +} // MultMMtv. + + +template +void ARbdNonSymMatrix::Mult0MMt0v(ARTYPE* v, ARTYPE* w) +{ + + MultMv(&v[ this->m],w); + MultMtv(v,&w[ this->m]); + +} // Mult0MMt0v. + + +template +void ARbdNonSymMatrix::MultInvv(ARTYPE* v, ARTYPE* w) +{ + + // Quitting the function if A (or AsI) was not factored. + + if (!IsFactored()) { + throw ArpackError(ArpackError::NOT_FACTORED_MATRIX, + "ARbdNonSymMatrix::MultInvv"); + } + + // Overwritting w with v. + + copy( this->n, v, 1, w, 1); + + // Solving A.w = v (or AsI.w = v). + + gbtrs("N", this->n, ndiagL, ndiagU, 1, Ainv, lda, ipiv, w, this->m, info); + + // Handling errors. + + ThrowError(); + +} // MultInvv. + + +template +inline void ARbdNonSymMatrix:: +DefineMatrix(int np, int ndiagLp, int ndiagUp, ARTYPE* Ap) +{ + + // Defining member variables. + + this->m = np; + this->n = np; + ndiagL = ndiagLp; + ndiagU = ndiagUp; + lda = 2*ndiagL+ndiagU+1; + A = Ap; + this->defined = true; + Ainv = NULL; + ipiv = NULL; + info = 0; + +} // DefineMatrix. + + +template +inline ARbdNonSymMatrix:: +ARbdNonSymMatrix(int np, int ndiagLp, + int ndiagUp, ARTYPE* Ap) : ARMatrix(np) +{ + + factored = false; + DefineMatrix(np, ndiagLp, ndiagUp, Ap); + +} // Long constructor. + + +template +ARbdNonSymMatrix& ARbdNonSymMatrix:: +operator=(const ARbdNonSymMatrix& other) +{ + + if (this != &other) { // Stroustrup suggestion. + this->ClearMem(); + Copy(other); + } + return *this; + +} // operator=. + + +#endif // ARBNSMAT_H diff --git a/external/arpack++/include/arbnspen.h b/external/arpack++/include/arbnspen.h new file mode 100644 index 000000000..2284ffa36 --- /dev/null +++ b/external/arpack++/include/arbnspen.h @@ -0,0 +1,470 @@ +/* + ARPACK++ v1.2 2/20/2000 + c++ interface to ARPACK code. + + MODULE ARBNSPen.h. + Arpack++ class ARbdNonSymPencil definition. + + ARPACK Authors + Richard Lehoucq + Danny Sorensen + Chao Yang + Dept. of Computational & Applied Mathematics + Rice University + Houston, Texas +*/ + +#ifndef ARBNSPEN_H +#define ARBNSPEN_H + +#include "arch.h" +#include "arerror.h" +#include "blas1c.h" +#include "lapackc.h" +#include "arbnsmat.h" + + +template +class ARbdNonSymPencil +{ + + protected: + + char part; + ARbdNonSymMatrix* A; + ARbdNonSymMatrix* B; + ARbdNonSymMatrix AsB; +#ifdef ARCOMP_H + ARbdNonSymMatrix, ARFLOAT> AsBc; +#endif + + int max(int a, int b) { return (a>b)?a:b; } + + int min(int a, int b) { return (a dy[], int incy); + + void ComplexAxpy(int n, arcomplex da, ARTYPE dx[], + int incx, arcomplex dy[], int incy); + + virtual void Copy(const ARbdNonSymPencil& other); + + void SubtractAsB(ARTYPE sigma); + +#ifdef ARCOMP_H + void SubtractAsB(ARFLOAT sigmaR, ARFLOAT sigmaI); +#endif + + public: + +#ifdef ARCOMP_H + bool IsFactored() { return (AsB.IsFactored()||AsBc.IsFactored()); } +#else + bool IsFactored() { return AsB.IsFactored(); } +#endif + + void FactorAsB(ARTYPE sigma); + +#ifdef ARCOMP_H + void FactorAsB(ARFLOAT sigmaR, ARFLOAT sigmaI, char partp = 'R'); +#endif + + void MultAv(ARTYPE* v, ARTYPE* w) { A->MultMv(v,w); } + + void MultBv(ARTYPE* v, ARTYPE* w) { B->MultMv(v,w); } + + void MultInvBAv(ARTYPE* v, ARTYPE* w); + +#ifdef ARCOMP_H + void MultInvAsBv(arcomplex* v, arcomplex* w); +#endif + + void MultInvAsBv(ARFLOAT* v, ARFLOAT* w); + + void DefineMatrices(ARbdNonSymMatrix& Ap, + ARbdNonSymMatrix& Bp); + + ARbdNonSymPencil() { part = 'N'; } + // Short constructor that does nothing. + + ARbdNonSymPencil(ARbdNonSymMatrix& Ap, + ARbdNonSymMatrix& Bp); + // Long constructor. + + ARbdNonSymPencil(const ARbdNonSymPencil& other) { Copy(other); } + // Copy constructor. + + virtual ~ARbdNonSymPencil() { } + // Destructor. + + ARbdNonSymPencil& operator=(const ARbdNonSymPencil& other); + // Assignment operator. + +}; + +// ------------------------------------------------------------------------ // +// ARbdNonSymPencil member functions definition. // +// ------------------------------------------------------------------------ // + + +template +inline void ARbdNonSymPencil:: +Copy(const ARbdNonSymPencil& other) +{ + + part = other.part; + A = other.A; + B = other.B; + AsB = other.AsB; +#ifdef ARCOMP_H + AsBc = other.AsBc; +#endif + +} // Copy. + + +template +void ARbdNonSymPencil:: +ComplexCopy(int n, ARFLOAT dx[], int incx, arcomplex dy[], int incy) +{ + + for (int ix=0, iy=0; ix<(n*incx); ix+=incx, iy+=incy) { + dy[iy] = arcomplex(dx[ix], 0.0); + } + +} // ComplexCopy. + + +template +void ARbdNonSymPencil:: +ComplexAxpy(int n, arcomplex da, ARTYPE dx[], int incx, + arcomplex dy[], int incy) +{ + + for (int ix=0, iy=0; ix<(n*incx); ix+=incx, iy+=incy) { + dy[iy] += da*dx[ix]; + } + +} // ComplexAxpy. + + +template +void ARbdNonSymPencil::SubtractAsB(ARTYPE sigma) +{ + + int i, inca, incb, minL, minU, begB, begAsB; + ARTYPE negsig; + + inca = A->ndiagL+A->ndiagU+1; + incb = B->ndiagL+B->ndiagU+1; + negsig = -sigma; + + // Expanding A. + + begAsB = AsB.ndiagL+AsB.ndiagU-A->ndiagU; + for (i = 0; i < inca; i++) { + copy(AsB.n, &A->A[i], inca, &AsB.Ainv[begAsB+i], AsB.lda); + } + + // Transferring part of B (*(-sigma)) if AsB.ndiagU > A->ndiagU. + + if (A->ndiagU < AsB.ndiagU) { + for (i = 0; i < AsB.ndiagU-A->ndiagU; i++) { + copy(AsB.n, &B->A[i], incb, &AsB.Ainv[AsB.ndiagL+i], AsB.lda); + scal(AsB.n, negsig, &AsB.Ainv[AsB.ndiagL+i], AsB.lda); + } + } + + // Subtracting sigma*B from A. + + minL = min(A->ndiagL, B->ndiagL); + minU = min(A->ndiagU, B->ndiagU); + begB = B->ndiagU-minU; + begAsB = AsB.ndiagL+AsB.ndiagU-minU; + + for (i = 0; i < minL+minU+1; i++) { + axpy(AsB.n, -sigma, &B->A[begB+i], incb, &AsB.Ainv[begAsB+i], AsB.lda); + } + + // Transferring part of B (*(-sigma)) if AsB.ndiagL > A->ndiagL. + + if (A->ndiagL < AsB.ndiagL) { + begB = B->ndiagU+1+minL; + begAsB = AsB.ndiagL+AsB.ndiagU+1+minL; + for (i = 0; i < AsB.ndiagL-A->ndiagL; i++) { + copy(AsB.n, &B->A[begB+i], incb, &AsB.Ainv[begAsB+i], AsB.lda); + scal(AsB.n, negsig, &AsB.Ainv[begAsB+i], AsB.lda); + } + } + +} // SubtractAsB (ARTYPE shift). + + +#ifdef ARCOMP_H +template +void ARbdNonSymPencil:: +SubtractAsB(ARFLOAT sigmaR, ARFLOAT sigmaI) +{ + + int i, inca, incb, minL, minU, begB, begAsB; + arcomplex sigma; + + inca = A->ndiagL+A->ndiagU+1; + incb = B->ndiagL+B->ndiagU+1; + sigma = arcomplex(sigmaR, sigmaI); + + // Expanding A. + + begAsB = AsBc.ndiagL+AsBc.ndiagU-A->ndiagU; + for (i = 0; i < inca; i++) { + ComplexCopy(AsBc.n,(ARFLOAT*)(&A->A[i]),inca,&AsBc.Ainv[begAsB+i],AsBc.lda); + } + + // Transferring part of B (*(-sigma)) if AsBc.ndiagU > A->ndiagU. + + if (A->ndiagU < AsBc.ndiagU) { + for (i = 0; i < AsBc.ndiagU-A->ndiagU; i++) { + ComplexCopy(AsBc.n, (ARFLOAT*)(&B->A[i]), incb, + &AsBc.Ainv[AsBc.ndiagL+i], AsBc.lda); + scal(AsBc.n, -sigma, &AsBc.Ainv[AsBc.ndiagL+i], AsBc.lda); + } + } + + // Subtracting sigma*B from A. + + minL = min(A->ndiagL, B->ndiagL); + minU = min(A->ndiagU, B->ndiagU); + begB = B->ndiagU-minU; + begAsB = AsBc.ndiagL+AsBc.ndiagU-minU; + + for (i = 0; i < minL+minU+1; i++) { + ComplexAxpy(AsBc.n, -sigma, &B->A[begB+i], incb, + &AsBc.Ainv[begAsB+i], AsBc.lda); + } + + // Transferring part of B (*(-sigma)) if AsBc.ndiagL > A->ndiagL. + + if (A->ndiagL < AsBc.ndiagL) { + begB = B->ndiagU+1+minL; + begAsB = AsBc.ndiagL+AsBc.ndiagU+1+minL; + for (i = 0; i < AsBc.ndiagL-A->ndiagL; i++) { + ComplexCopy(AsBc.n, (ARFLOAT*)(&B->A[begB+i]), incb, + &AsBc.Ainv[begAsB+i], AsBc.lda); + scal(AsBc.n, -sigma, &AsBc.Ainv[begAsB+i], AsBc.lda); + } + } + +} // SubtractAsB (arcomplex shift). +#endif // ARCOMP_H + + +template +void ARbdNonSymPencil::FactorAsB(ARTYPE sigma) +{ + + // Quitting the function if A and B were not defined. + + if (!(A->IsDefined()&&B->IsDefined())) { + throw ArpackError(ArpackError::DATA_UNDEFINED, + "ARbdNonSymPencil::FactorAsB"); + } + + // Quitting the function if A and B are not square. + + if ((A->nrows() != A->ncols()) || (B->nrows() != B->ncols())) { + throw ArpackError(ArpackError::NOT_SQUARE_MATRIX, + "ARbdNonSymPencil::FactorAsB"); + } + + // Copying A to AsB if sigma = 0. + + if (sigma == (ARTYPE)0) { + + AsB = *A; + if (!AsB.IsFactored()) AsB.FactorA(); + return; + + } + + // Defining matrix AsB. + + if (!AsB.IsDefined()) { + AsB.DefineMatrix(A->ncols(), max(A->ndiagL, B->ndiagL), + max(A->ndiagU, B->ndiagU), A->A); + } + + // Reserving memory for some vectors used in matrix decomposition. + + AsB.CreateStructure(); + + // Subtracting sigma*B from A and storing the result on AsB. + + SubtractAsB(sigma); + + // Decomposing AsB. + + gbtrf(AsB.n, AsB.n, AsB.ndiagL, AsB.ndiagU, + AsB.Ainv, AsB.lda, AsB.ipiv, AsB.info); + + // Handling errors. + + AsB.ThrowError(); + + AsB.factored = true; + +} // FactorAsB (ARTYPE shift). + + +#ifdef ARCOMP_H +template +void ARbdNonSymPencil:: +FactorAsB(ARFLOAT sigmaR, ARFLOAT sigmaI, char partp) +{ + + // Quitting the function if A and B were not defined. + + if (!(A->IsDefined()&&B->IsDefined())) { + throw ArpackError(ArpackError::DATA_UNDEFINED, + "ARbdNonSymPencil::FactorAsB"); + } + + // Quitting the function if A and B are not square. + + if ((A->nrows() != A->ncols()) || (B->nrows() != B->ncols())) { + throw ArpackError(ArpackError::NOT_SQUARE_MATRIX, + "ARbdNonSymPencil::FactorAsB"); + } + + // Defining matrix AsBc. + + if (!AsBc.IsDefined()) { + part = partp; + AsBc.DefineMatrix(A->ncols(), max(A->ndiagL,B->ndiagL), + max(A->ndiagU,B->ndiagU), 0); + } + + // Reserving memory for some vectors used in matrix decomposition. + + AsBc.CreateStructure(); + + // Subtracting sigma*B from A and storing the result on AsBc. + + SubtractAsB(sigmaR, sigmaI); + + // Decomposing AsBc. + + gbtrf(AsBc.n, AsBc.n, AsBc.ndiagL, AsBc.ndiagU, + AsBc.Ainv, AsBc.lda, AsBc.ipiv, AsBc.info); + + // Handling errors. + + AsBc.ThrowError(); + + AsBc.factored = true; + +} // FactorAsB (arcomplex shift). +#endif // ARCOMP_H. + + +template +void ARbdNonSymPencil::MultInvBAv(ARTYPE* v, ARTYPE* w) +{ + + if (!B->IsFactored()) B->FactorA(); + + A->MultMv(v, w); + B->MultInvv(w, w); + +} // MultInvBAv. + + +#ifdef ARCOMP_H +template +void ARbdNonSymPencil:: +MultInvAsBv(arcomplex* v, arcomplex* w) +{ + + AsB.MultInvv((ARTYPE*)v, (ARTYPE*)w); + +} // MultInvAsBv (arcomplex). +#endif // ARCOMP_H. + + +template +void ARbdNonSymPencil::MultInvAsBv(ARFLOAT* v, ARFLOAT* w) +{ + + if (part == 'N') { // shift is real. + + AsB.MultInvv((ARTYPE*)v, (ARTYPE*)w); + + } + else { // shift is complex. + +#ifdef ARCOMP_H + + int i; + arcomplex *tv, *tw; + + tv = new arcomplex[AsBc.ncols()]; + tw = new arcomplex[AsBc.ncols()]; + + for (i=0; i!=AsBc.ncols(); i++) tv[i] = arcomplex(v[i], 0.0); + + AsBc.MultInvv(tv, tw); + + if (part=='I') { + for (i=0; i!=AsBc.ncols(); i++) w[i] = imag(tw[i]); + } + else { + for (i=0; i!=AsBc.ncols(); i++) w[i] = real(tw[i]); + } + + delete[] tv; + delete[] tw; + +#endif // ARCOMP_H. + + } + +} // MultInvAsBv (ARFLOAT). + + +template +inline void ARbdNonSymPencil:: +DefineMatrices(ARbdNonSymMatrix& Ap, + ARbdNonSymMatrix& Bp) +{ + + A = &Ap; + B = &Bp; + +} // DefineMatrices. + + +template +inline ARbdNonSymPencil:: +ARbdNonSymPencil(ARbdNonSymMatrix& Ap, + ARbdNonSymMatrix& Bp) +{ + + DefineMatrices(Ap, Bp); + +} // Long constructor. + + +template +ARbdNonSymPencil& ARbdNonSymPencil:: +operator=(const ARbdNonSymPencil& other) +{ + + if (this != &other) { // Stroustrup suggestion. + Copy(other); + } + return *this; + +} // operator=. + + +#endif // ARBNSPEN_H diff --git a/external/arpack++/include/arbscomp.h b/external/arpack++/include/arbscomp.h new file mode 100644 index 000000000..334cd3a68 --- /dev/null +++ b/external/arpack++/include/arbscomp.h @@ -0,0 +1,165 @@ +/* + ARPACK++ v1.2 2/20/2000 + c++ interface to ARPACK code. + + MODULE ARBSComp.h. + Arpack++ class ARluCompStdEig definition + (band matrix version). + + ARPACK Authors + Richard Lehoucq + Danny Sorensen + Chao Yang + Dept. of Computational & Applied Mathematics + Rice University + Houston, Texas +*/ + +#ifndef ARBSCOMP_H +#define ARBSCOMP_H + +#include +#include +#include "arch.h" +#include "arscomp.h" +#include "arbnsmat.h" +#include "arrseig.h" + + +template +class ARluCompStdEig: + public virtual ARCompStdEig, ARFLOAT> > { + + public: + + // a) Public functions: + + // a.1) Functions that allow changes in problem parameters. + + virtual void ChangeShift(arcomplex sigmaRp); + + virtual void SetRegularMode(); + + virtual void SetShiftInvertMode(arcomplex sigmap); + + // a.2) Constructors and destructor. + + ARluCompStdEig() { } + // Short constructor. + + ARluCompStdEig(int nevp, ARbdNonSymMatrix, ARFLOAT>& A, + const std::string& whichp = "LM", int ncvp = 0, + ARFLOAT tolp = 0.0, int maxitp = 0, + arcomplex* residp = NULL, bool ishiftp = true); + // Long constructor (regular mode). + + ARluCompStdEig(int nevp, ARbdNonSymMatrix, ARFLOAT>& A, + arcomplex sigma, const std::string& whichp = "LM", + int ncvp = 0, ARFLOAT tolp = 0.0, int maxitp = 0, + arcomplex* residp = NULL, bool ishiftp = true); + // Long constructor (shift and invert mode). + + ARluCompStdEig(const ARluCompStdEig& other) { Copy(other); } + // Copy constructor. + + virtual ~ARluCompStdEig() { } + // Destructor. + + + // b) Operators. + + ARluCompStdEig& operator=(const ARluCompStdEig& other); + // Assignment operator. + +}; // class ARluCompStdEig. + + +// ------------------------------------------------------------------------ // +// ARluCompStdEig member functions definition. // +// ------------------------------------------------------------------------ // + + +template +inline void ARluCompStdEig:: +ChangeShift(arcomplex sigmaRp) +{ + + this->objOP->FactorAsI(sigmaRp); + ARrcStdEig >::ChangeShift(sigmaRp); + +} // ChangeShift. + + +template +inline void ARluCompStdEig::SetRegularMode() +{ + + ARStdEig, + ARbdNonSymMatrix,ARFLOAT> >:: + SetRegularMode(this->objOP,&ARbdNonSymMatrix,ARFLOAT>::MultMv); + +} // SetRegularMode. + + +template +inline void ARluCompStdEig:: +SetShiftInvertMode(arcomplex sigmap) +{ + + ARStdEig, + ARbdNonSymMatrix,ARFLOAT> >:: + SetShiftInvertMode(sigmap, this->objOP, + &ARbdNonSymMatrix,ARFLOAT>::MultInvv); + +} // SetShiftInvertMode. + + +template +inline ARluCompStdEig:: +ARluCompStdEig(int nevp, ARbdNonSymMatrix, ARFLOAT>& A, + const std::string& whichp, int ncvp, ARFLOAT tolp, + int maxitp, arcomplex* residp, bool ishiftp) + +{ + + this->NoShift(); + this->DefineParameters(A.ncols(), nevp, &A, + &ARbdNonSymMatrix, ARFLOAT>::MultMv, + whichp, ncvp, tolp, maxitp, residp, ishiftp); + +} // Long constructor (regular mode). + + +template +inline ARluCompStdEig:: +ARluCompStdEig(int nevp, ARbdNonSymMatrix, ARFLOAT>& A, + arcomplex sigmap, const std::string& whichp, int ncvp, + ARFLOAT tolp, int maxitp, arcomplex* residp, + bool ishiftp) + +{ + + this->DefineParameters(A.ncols(), nevp, &A, + &ARbdNonSymMatrix, ARFLOAT>::MultInvv, + whichp, ncvp, tolp, maxitp, residp, ishiftp); + ChangeShift(sigmap); + +} // Long constructor (shift and invert mode). + + +template +ARluCompStdEig& ARluCompStdEig:: +operator=(const ARluCompStdEig& other) +{ + + if (this != &other) { // Stroustrup suggestion. + this->ClearMem(); + Copy(other); + } + return *this; + +} // operator=. + + +#endif // ARBSCOMP_H diff --git a/external/arpack++/include/arbsmat.h b/external/arpack++/include/arbsmat.h new file mode 100644 index 000000000..e38c2ccf1 --- /dev/null +++ b/external/arpack++/include/arbsmat.h @@ -0,0 +1,378 @@ +/* + ARPACK++ v1.2 2/20/2000 + c++ interface to ARPACK code. + + MODULE ARBSMat.h. + Arpack++ class ARbdSymMatrix definition. + + ARPACK Authors + Richard Lehoucq + Danny Sorensen + Chao Yang + Dept. of Computational & Applied Mathematics + Rice University + Houston, Texas +*/ + + +#include "arbspen.h" + +#ifndef ARBSMAT_H +#define ARBSMAT_H + +#include +#include "arch.h" +#include "armat.h" +#include "arerror.h" +#include "blas1c.h" +#include "lapackc.h" + +template class ARbdSymPencil; + +template +class ARbdSymMatrix: public ARMatrix { + + friend class ARbdSymPencil; + + protected: + + bool factored; + char uplo; + int nsdiag; + int lda; + int info; + int* ipiv; + ARTYPE* A; + ARTYPE* Ainv; + + void ClearMem(); + + virtual void Copy(const ARbdSymMatrix& other); + + void ExpandA(); + + void SubtractAsI(ARTYPE sigma); + + void CreateStructure(); + + void ThrowError(); + + public: + + bool IsFactored() { return factored; } + + void FactorA(); + + void FactorAsI(ARTYPE sigma); + + void MultMv(ARTYPE* v, ARTYPE* w); + + void MultInvv(ARTYPE* v, ARTYPE* w); + + void DefineMatrix(int np, int nsdiagp, ARTYPE* Ap, char uplop = 'L'); + + ARbdSymMatrix(): ARMatrix() { factored = false; } + // Short constructor that does nothing. + + ARbdSymMatrix(int np, int nsdiagp, ARTYPE* Ap, char uplop = 'L'); + // Long constructor. + + ARbdSymMatrix(const ARbdSymMatrix& other) { Copy(other); } + // Copy constructor. + + virtual ~ARbdSymMatrix() { ClearMem(); } + // Destructor. + + ARbdSymMatrix& operator=(const ARbdSymMatrix& other); + // Assignment operator. + +}; + +// ------------------------------------------------------------------------ // +// ARbdSymMatrix member functions definition. // +// ------------------------------------------------------------------------ // + + +template +inline void ARbdSymMatrix::ClearMem() +{ + + if (factored) { + delete[] Ainv; + delete[] ipiv; + Ainv = NULL; + ipiv = NULL; + } + +} // ClearMem. + + +template +inline void ARbdSymMatrix:: +Copy(const ARbdSymMatrix& other) +{ + + // Copying very fundamental variables and user-defined parameters. + + this->m = other.m; + this->n = other.n; + this->defined = other.defined; + factored = other.factored; + uplo = other.uplo; + nsdiag = other.nsdiag; + lda = other.lda; + info = other.info; + A = other.A; + + // Returning from here if "other" was not factored. + + if (!factored) return; + + // Copying vectors. + + Ainv = new ARTYPE[this->n*lda]; + ipiv = new int[this->n]; + + copy(this->n*lda, other.Ainv, 1, Ainv, 1); + for (int i=0; in; i++) ipiv[i] = other.ipiv[i]; + +} // Copy. + + +template +void ARbdSymMatrix::ExpandA() +{ + + int i; + + if (uplo == 'U') { + + // Copying the main diagonal of A to Ainv. + + copy(this->n, &A[nsdiag], nsdiag+1, &Ainv[2*nsdiag], lda); + + // Copying the superdiagonals of A to Ainv. + + for (i = 0; i < nsdiag; i++) { + copy(this->n, &A[i], nsdiag+1, &Ainv[nsdiag+i], lda); + copy(this->n-nsdiag+i, &A[i+(nsdiag-i)*(nsdiag+1)], nsdiag+1, + &Ainv[3*nsdiag-i], lda); + } + + } + else { + + // Copying the main diagonal of A to Ainv. + + copy(this->n, &A[0], nsdiag+1, &Ainv[2*nsdiag], lda); + + // Copying the subdiagonals of A to Ainv. + + for (i = 1; i <= nsdiag; i++) { + copy(this->n, &A[i], nsdiag+1, &Ainv[2*nsdiag+i], lda); + copy(this->n-i, &A[i], nsdiag+1, &Ainv[2*nsdiag-i+i*lda], lda); + } + + } + +} // ExpandA. + + +template +void ARbdSymMatrix::SubtractAsI(ARTYPE sigma) +{ + + // Copying A to Ainv. + + ExpandA(); + + // Subtracting sigma from diagonal elements. + + for (int i=(2*nsdiag); i<(lda*this->n); i+=lda) Ainv[i] -= sigma; + +} // SubtractAsI. + + +template +inline void ARbdSymMatrix::CreateStructure() +{ + + ClearMem(); + Ainv = new ARTYPE[lda*this->n]; + ipiv = new int[this->n]; + +} // CreateStructure. + + +template +inline void ARbdSymMatrix::ThrowError() +{ + + if (info < 0) { // Illegal argument. + throw ArpackError(ArpackError::PARAMETER_ERROR, + "ARbdSymMatrix::FactorA"); + } + else if (info) { // Matrix is singular. + throw ArpackError(ArpackError::MATRIX_IS_SINGULAR, + "ARbdSymMatrix::FactorA"); + } + +} // ThrowError. + + +template +void ARbdSymMatrix::FactorA() +{ + + // Quitting the function if A was not defined. + + if (!this->IsDefined()) { + throw ArpackError(ArpackError::DATA_UNDEFINED, "ARbdSymMatrix::FactorA"); + } + + // Reserving memory for some vectors used in matrix decomposition. + + CreateStructure(); + + // Copying A to Ainv; + + ExpandA(); + + // Decomposing A. + + gbtrf(this->n, this->n, nsdiag, nsdiag, Ainv, lda, ipiv, info); + + // Handling errors. + + ThrowError(); + + factored = true; + +} // FactorA. + + +template +void ARbdSymMatrix::FactorAsI(ARTYPE sigma) +{ + + // Quitting the function if A was not defined. + + if (!this->IsDefined()) { + throw ArpackError(ArpackError::DATA_UNDEFINED, "ARbdSymMatrix::FactorAsI"); + } + + // Reserving memory for some vectors used in matrix decomposition. + + CreateStructure(); + + // Subtracting sigma*I from A. + + SubtractAsI(sigma); + + // Decomposing AsI. + + gbtrf(this->n, this->n, nsdiag, nsdiag, Ainv, lda, ipiv, info); + + // Handling errors. + + ThrowError(); + + factored = true; + +} // FactorAsI. + + +template +void ARbdSymMatrix::MultMv(ARTYPE* v, ARTYPE* w) +{ + + ARTYPE one = (ARTYPE)0 + 1.0; + ARTYPE zero = (ARTYPE)0; + + // Quitting the function if A was not defined. + + if (!this->IsDefined()) { + throw ArpackError(ArpackError::DATA_UNDEFINED, "ARbdSymMatrix::MultMv"); + } + + // Determining w = M.v. + + sbmv(&uplo, this->n, nsdiag, one, A, nsdiag+1, v, 1, zero, w, 1); + +} // MultMv. + + +template +void ARbdSymMatrix::MultInvv(ARTYPE* v, ARTYPE* w) +{ + + // Quitting the function if A (or AsI) was not factored. + + if (!IsFactored()) { + throw ArpackError(ArpackError::NOT_FACTORED_MATRIX, + "ARbdSymMatrix::MultInvv"); + } + + // Overwritting w with v. + + copy(this->n, v, 1, w, 1); + + // Solving A.w = v (or AsI.w = v). + + gbtrs("N", this->n, nsdiag, nsdiag, 1, Ainv, lda, ipiv, w, this->m, info); + + // Handling errors. + + ThrowError(); + +} // MultInvv. + + +template +inline void ARbdSymMatrix:: +DefineMatrix(int np, int nsdiagp, ARTYPE* Ap, char uplop) +{ + + // Defining member variables. + + this->m = np; + this->n = np; + nsdiag = nsdiagp; + lda = 3*nsdiag+1; + uplo = uplop; + A = Ap; + this->defined = true; + Ainv = NULL; + ipiv = NULL; + info = 0; + +} // DefineMatrix. + + +template +inline ARbdSymMatrix:: +ARbdSymMatrix(int np, int nsdiagp, + ARTYPE* Ap, char uplop) : ARMatrix(np) +{ + + factored = false; + DefineMatrix(np, nsdiagp, Ap, uplop); + +} // Long constructor. + + +template +ARbdSymMatrix& ARbdSymMatrix:: +operator=(const ARbdSymMatrix& other) +{ + + if (this != &other) { // Stroustrup suggestion. + this->ClearMem(); + Copy(other); + } + return *this; + +} // operator=. + + +#endif // ARBSMAT_H diff --git a/external/arpack++/include/arbsnsym.h b/external/arpack++/include/arbsnsym.h new file mode 100644 index 000000000..808a4246b --- /dev/null +++ b/external/arpack++/include/arbsnsym.h @@ -0,0 +1,163 @@ +/* + ARPACK++ v1.2 2/20/2000 + c++ interface to ARPACK code. + + MODULE ARBSNSym.h. + Arpack++ class ARluNonSymStdEig definition + (band matrix version). + + ARPACK Authors + Richard Lehoucq + Danny Sorensen + Chao Yang + Dept. of Computational & Applied Mathematics + Rice University + Houston, Texas +*/ + +#ifndef ARBSNSYM_H +#define ARBSNSYM_H + +#include +#include +#include "arch.h" +#include "arsnsym.h" +#include "arbnsmat.h" + + +template +class ARluNonSymStdEig: + public virtual ARNonSymStdEig > { + + public: + + // a) Public functions: + + // a.1) Functions that allow changes in problem parameters. + + virtual void ChangeShift(ARFLOAT sigmaRp); + + virtual void SetRegularMode(); + + virtual void SetShiftInvertMode(ARFLOAT sigmap); + + // a.2) Constructors and destructor. + + ARluNonSymStdEig() { } + // Short constructor. + + ARluNonSymStdEig(int nevp, ARbdNonSymMatrix& A, + const std::string& whichp = "LM", int ncvp = 0, + ARFLOAT tolp = 0.0, int maxitp = 0, + ARFLOAT* residp = NULL, bool ishiftp = true); + // Long constructor (regular mode). + + ARluNonSymStdEig(int nevp, ARbdNonSymMatrix& A, + ARFLOAT sigma, const std::string& whichp = "LM", int ncvp = 0, + ARFLOAT tolp = 0.0, int maxitp = 0, + ARFLOAT* residp = NULL, bool ishiftp = true); + // Long constructor (shift and invert mode). + + ARluNonSymStdEig(const ARluNonSymStdEig& other) { Copy(other); } + // Copy constructor. + + virtual ~ARluNonSymStdEig() { } + // Destructor. + + // b) Operators. + + ARluNonSymStdEig& operator=(const ARluNonSymStdEig& other); + // Assignment operator. + +}; // class ARluNonSymStdEig. + + +// ------------------------------------------------------------------------ // +// ARluNonSymStdEig member functions definition. // +// ------------------------------------------------------------------------ // + + +template +inline void ARluNonSymStdEig:: +ChangeShift(ARFLOAT sigmaRp) +{ + + this->sigmaR = sigmaRp; + this->sigmaI = 0.0; + this->mode = 3; + this->iparam[7] = this->mode; + + this->objOP->FactorAsI( this->sigmaR); + this->Restart(); + +} // ChangeShift. + + +template +inline void ARluNonSymStdEig::SetRegularMode() +{ + + ARStdEig >:: + SetRegularMode( this->objOP, &ARbdNonSymMatrix::MultMv); + +} // SetRegularMode. + + +template +inline void ARluNonSymStdEig::SetShiftInvertMode(ARFLOAT sigmap) +{ + + ARStdEig >:: + SetShiftInvertMode(sigmap, this->objOP, + &ARbdNonSymMatrix::MultInvv); + +} // SetShiftInvertMode. + + +template +inline ARluNonSymStdEig:: +ARluNonSymStdEig(int nevp, ARbdNonSymMatrix& A, + const std::string& whichp, int ncvp, ARFLOAT tolp, + int maxitp, ARFLOAT* residp, bool ishiftp) + +{ + + this->NoShift(); + this->DefineParameters(A.ncols(), nevp, &A, + &ARbdNonSymMatrix::MultMv, + whichp, ncvp, tolp, maxitp, residp, ishiftp); + +} // Long constructor (regular mode). + + +template +inline ARluNonSymStdEig:: +ARluNonSymStdEig(int nevp, ARbdNonSymMatrix& A, + ARFLOAT sigmap, const std::string& whichp, int ncvp, ARFLOAT tolp, + int maxitp, ARFLOAT* residp, bool ishiftp) + +{ + + this->DefineParameters(A.ncols(), nevp, &A, + &ARbdNonSymMatrix::MultInvv, + whichp, ncvp, tolp, maxitp, residp, ishiftp); + ChangeShift(sigmap); + +} // Long constructor (shift and invert mode). + + +template +ARluNonSymStdEig& ARluNonSymStdEig:: +operator=(const ARluNonSymStdEig& other) +{ + + if (this != &other) { // Stroustrup suggestion. + this->ClearMem(); + Copy(other); + } + return *this; + +} // operator=. + + +#endif // ARBSNSYM_H diff --git a/external/arpack++/include/arbspen.h b/external/arpack++/include/arbspen.h new file mode 100644 index 000000000..0dbd73bbe --- /dev/null +++ b/external/arpack++/include/arbspen.h @@ -0,0 +1,303 @@ +/* + ARPACK++ v1.2 2/20/2000 + c++ interface to ARPACK code. + + MODULE ARBSPen.h. + Arpack++ class ARbdSymPencil definition. + + ARPACK Authors + Richard Lehoucq + Danny Sorensen + Chao Yang + Dept. of Computational & Applied Mathematics + Rice University + Houston, Texas +*/ + +#ifndef ARBSPEN_H +#define ARBSPEN_H + +#include "arch.h" +#include "arerror.h" +#include "blas1c.h" +#include "lapackc.h" +#include "arbsmat.h" + + +template +class ARbdSymPencil +{ + + protected: + + ARbdSymMatrix* A; + ARbdSymMatrix* B; + ARbdSymMatrix AsB; + + int max(int a, int b) { return (a>b)?a:b; } + + int min(int a, int b) { return (aMultMv(v,w); } + + void MultBv(ARTYPE* v, ARTYPE* w) { B->MultMv(v,w); } + + void MultInvBAv(ARTYPE* v, ARTYPE* w); + + void MultInvAsBv(ARTYPE* v, ARTYPE* w) { AsB.MultInvv(v,w); } + + void DefineMatrices(ARbdSymMatrix& Ap, ARbdSymMatrix& Bp); + + ARbdSymPencil() { AsB.factored = false; } + // Short constructor that does nothing. + + ARbdSymPencil(ARbdSymMatrix& Ap, ARbdSymMatrix& Bp); + // Long constructor. + + ARbdSymPencil(const ARbdSymPencil& other) { Copy(other); } + // Copy constructor. + + virtual ~ARbdSymPencil() { } + // Destructor. + + ARbdSymPencil& operator=(const ARbdSymPencil& other); + // Assignment operator. + +}; + +// ------------------------------------------------------------------------ // +// ARbdSymPencil member functions definition. // +// ------------------------------------------------------------------------ // + + +template +inline void ARbdSymPencil::Copy(const ARbdSymPencil& other) +{ + + A = other.A; + B = other.B; + AsB = other.AsB; + +} // Copy. + + +template +void ARbdSymPencil::SubtractAsB(ARTYPE sigma) +{ + + int i, n, minD, ndA, ndB, ndAsB, lda; + ARTYPE negsig; + + negsig = -sigma; + n = AsB.n; + ndA = A->nsdiag; + ndB = B->nsdiag; + ndAsB = AsB.nsdiag; + lda = AsB.lda; + + // Expanding A. + + if (A->uplo == 'U') { + + // Copying the main diagonal of A. + + copy(n, &A->A[ndA], ndA+1, &AsB.Ainv[2*ndAsB], lda); + + // Copying the superdiagonals of A. + + for (i = 0; i < ndA; i++) { + copy(n, &A->A[i], ndA+1, &AsB.Ainv[2*ndAsB-ndA+i], lda); + copy(n-ndA+i, &A->A[i+(ndA-i)*(ndA+1)], ndA+1, + &AsB.Ainv[2*ndAsB+ndA-i], lda); + } + + } + else { + + // Copying the main diagonal of A to Ainv. + + copy(n, &A->A[0], ndA+1, &AsB.Ainv[2*ndAsB], lda); + + // Copying the subdiagonals of A to Ainv. + + for (i = 1; i <= ndA; i++) { + copy(n, &A->A[i], ndA+1, &AsB.Ainv[2*ndAsB+i], lda); + copy(n-i, &A->A[i], ndA+1, &AsB.Ainv[2*ndAsB-i+i*lda], lda); + } + + } + + // Transferring part of B (*(-sigma)) if AsB.nsdiag > A->nsdiag. + + if (A->nsdiag < AsB.nsdiag) { + + if (B->uplo == 'U') { + + for (i = 0; i < ndAsB-ndA; i++) { + copy(n, &B->A[i], ndB+1, &AsB.Ainv[ndAsB+i], lda); + scal(n, negsig, &AsB.Ainv[ndAsB+i], lda); + copy(n-ndAsB+i, &AsB.Ainv[ndAsB+i+(ndAsB-i)*lda], lda, + &AsB.Ainv[lda-i-1], lda); + } + + } + else { + + for (i = ndA+1; i <= ndAsB; i++) { + copy(n, &B->A[i], ndB+1, &AsB.Ainv[2*ndAsB+i], lda); + scal(n, negsig, &AsB.Ainv[2*ndAsB+i], lda); + copy(n-i, &AsB.Ainv[2*ndAsB+i], lda, + &AsB.Ainv[2*ndAsB-i+i*lda], lda); + } + + } + + } + + // Subtracting sigma*B from A. + + minD = min(ndA, ndB); + + if (B->uplo == 'U') { + + // Subtracting the main diagonal of B. + + axpy(n, negsig, &B->A[ndB], ndB+1, &AsB.Ainv[2*ndAsB], lda); + + // Subtracting the superdiagonals. + + for (i = 0; i < minD; i++) { + axpy(n, negsig, &B->A[ndB-minD+i], ndB+1, + &AsB.Ainv[2*ndAsB-minD+i], lda); + copy(n-minD+i, &AsB.Ainv[2*ndAsB-minD+i+(minD-i)*lda], lda, + &AsB.Ainv[2*ndAsB+minD-i], lda); + } + + } + else { + + // Subtracting the main diagonal of B. + + axpy(n, negsig, &B->A[0], ndB+1, &AsB.Ainv[2*ndAsB], lda); + + // Subtracting the subdiagonals. + + for (i = 1; i <= minD; i++) { + axpy(n, negsig, &B->A[i], ndB+1, &AsB.Ainv[2*ndAsB+i], lda); + copy(n-i, &AsB.Ainv[2*ndAsB+i], lda, + &AsB.Ainv[2*ndAsB-i+i*lda], lda); + } + + } + +} // SubtractAsB (ARTYPE shift). + + +template +void ARbdSymPencil::FactorAsB(ARTYPE sigma) +{ + + // Quitting the function if A and B were not defined. + + if (!(A->IsDefined()&&B->IsDefined())) { + throw ArpackError(ArpackError::DATA_UNDEFINED, + "ARbdSymPencil::FactorAsB"); + } + + // Copying A to AsB if sigma = 0. + + if (sigma == (ARTYPE)0) { + + AsB = *A; + if (!AsB.IsFactored()) AsB.FactorA(); + return; + + } + + // Defining matrix AsB. + + if (!AsB.IsDefined()) { + AsB.DefineMatrix(A->ncols(), max(A->nsdiag, B->nsdiag), A->A); + } + + // Reserving memory for some vectors used in matrix decomposition. + + AsB.CreateStructure(); + + // Subtracting sigma*B from A and storing the result on AsB. + + SubtractAsB(sigma); + + // Decomposing AsB. + + gbtrf(AsB.n, AsB.n, AsB.nsdiag, AsB.nsdiag, + AsB.Ainv, AsB.lda, AsB.ipiv, AsB.info); + + // Handling errors. + + AsB.ThrowError(); + + AsB.factored = true; + +} // FactorAsB (ARTYPE shift). + + +template +void ARbdSymPencil::MultInvBAv(ARTYPE* v, ARTYPE* w) +{ + + if (!B->IsFactored()) B->FactorA(); + + A->MultMv(v, w); + copy(A->ncols(), w, 1, v, 1); + B->MultInvv(w, w); + +} // MultInvBAv. + + +template +inline void ARbdSymPencil:: +DefineMatrices(ARbdSymMatrix& Ap, ARbdSymMatrix& Bp) +{ + + A = &Ap; + B = &Bp; + +} // DefineMatrices. + + +template +inline ARbdSymPencil:: +ARbdSymPencil(ARbdSymMatrix& Ap, ARbdSymMatrix& Bp) +{ + + AsB.factored = false; + DefineMatrices(Ap, Bp); + +} // Long constructor. + + +template +ARbdSymPencil& ARbdSymPencil:: +operator=(const ARbdSymPencil& other) +{ + + if (this != &other) { // Stroustrup suggestion. + Copy(other); + } + return *this; + +} // operator=. + + +#endif // ARBSPEN_H diff --git a/external/arpack++/include/arbssym.h b/external/arpack++/include/arbssym.h new file mode 100644 index 000000000..94d70f68b --- /dev/null +++ b/external/arpack++/include/arbssym.h @@ -0,0 +1,159 @@ +/* + ARPACK++ v1.2 2/20/2000 + c++ interface to ARPACK code. + + MODULE ARBSSym.h. + Arpack++ class ARluSymStdEig definition + (band matrix version). + + ARPACK Authors + Richard Lehoucq + Danny Sorensen + Chao Yang + Dept. of Computational & Applied Mathematics + Rice University + Houston, Texas +*/ + +#ifndef ARBSSYM_H +#define ARBSSYM_H + +#include +#include +#include "arch.h" +#include "arssym.h" +#include "arbsmat.h" + + +template +class ARluSymStdEig: + public virtual ARSymStdEig > { + + public: + + // a) Public functions: + + // a.1) Functions that allow changes in problem parameters. + + virtual void ChangeShift(ARFLOAT sigmaRp); + + virtual void SetRegularMode(); + + virtual void SetShiftInvertMode(ARFLOAT sigmap); + + // a.2) Constructors and destructor. + + ARluSymStdEig() { } + // Short constructor. + + ARluSymStdEig(int nevp, ARbdSymMatrix& A, + const std::string& whichp = "LM", int ncvp = 0, + ARFLOAT tolp = 0.0, int maxitp = 0, + ARFLOAT* residp = NULL, bool ishiftp = true); + // Long constructor (regular mode). + + ARluSymStdEig(int nevp, ARbdSymMatrix& A, + ARFLOAT sigma, const std::string& whichp = "LM", int ncvp = 0, + ARFLOAT tolp = 0.0, int maxitp = 0, + ARFLOAT* residp = NULL, bool ishiftp = true); + // Long constructor (shift and invert mode). + + ARluSymStdEig(const ARluSymStdEig& other) { Copy(other); } + // Copy constructor. + + virtual ~ARluSymStdEig() { } + // Destructor. + + // b) Operators. + + ARluSymStdEig& operator=(const ARluSymStdEig& other); + // Assignment operator. + +}; // class ARluSymStdEig. + + +// ------------------------------------------------------------------------ // +// ARluSymStdEig member functions definition. // +// ------------------------------------------------------------------------ // + + +template +inline void ARluSymStdEig:: +ChangeShift(ARFLOAT sigmaRp) +{ + + this->sigmaR = sigmaRp; + this->sigmaI = 0.0; + this->mode = 3; + this->iparam[7] = this->mode; + + this->objOP->FactorAsI(this->sigmaR); + this->Restart(); + +} // ChangeShift. + + +template +inline void ARluSymStdEig::SetRegularMode() +{ + + ARStdEig >:: + SetRegularMode(this->objOP, &ARbdSymMatrix::MultMv); + +} // SetRegularMode. + + +template +inline void ARluSymStdEig::SetShiftInvertMode(ARFLOAT sigmap) +{ + + ARStdEig >:: + SetShiftInvertMode(sigmap, this->objOP, &ARbdSymMatrix::MultInvv); + +} // SetShiftInvertMode. + + +template +inline ARluSymStdEig:: +ARluSymStdEig(int nevp, ARbdSymMatrix& A, + const std::string& whichp, int ncvp, ARFLOAT tolp, + int maxitp, ARFLOAT* residp, bool ishiftp) +{ + + this->NoShift(); + this->DefineParameters(A.ncols(), nevp, &A, &ARbdSymMatrix::MultMv, + whichp, ncvp, tolp, maxitp, residp, ishiftp); + +} // Long constructor (regular mode). + + +template +inline ARluSymStdEig:: +ARluSymStdEig(int nevp, ARbdSymMatrix& A, + ARFLOAT sigmap, const std::string& whichp, int ncvp, ARFLOAT tolp, + int maxitp, ARFLOAT* residp, bool ishiftp) + +{ + + this->DefineParameters(A.ncols(), nevp, &A, &ARbdSymMatrix::MultInvv, + whichp, ncvp, tolp, maxitp, residp, ishiftp); + ChangeShift(sigmap); + +} // Long constructor (shift and invert mode). + + +template +ARluSymStdEig& ARluSymStdEig:: +operator=(const ARluSymStdEig& other) +{ + + if (this != &other) { // Stroustrup suggestion. + this->ClearMem(); + Copy(other); + } + return *this; + +} // operator=. + + +#endif // ARBSSYM_H diff --git a/external/arpack++/include/arcgsym.h b/external/arpack++/include/arcgsym.h new file mode 100644 index 000000000..45c14f83a --- /dev/null +++ b/external/arpack++/include/arcgsym.h @@ -0,0 +1,242 @@ +/* + ARPACK++ v1.2 2/20/2000 + c++ interface to ARPACK code. + + MODULE ARCGSym.h. + Arpack++ class ARluSymGenEig definition + (CHOLMOD version). + + Author of this class: + Martin Reuter + Date 11/05/2012 + + Arpack++ Author: + Francisco Gomes + + + ARPACK Authors + Richard Lehoucq + Danny Sorensen + Chao Yang + Kristi Maschhoff + Dept. of Computational & Applied Mathematics + Rice University + Houston, Texas +*/ + +#ifndef ARCGSYM_H +#define ARCGSYM_H + +#include +#include +#include "arch.h" +#include "arcsmat.h" +#include "arcspen.h" +#include "argsym.h" + + +template +class ARluSymGenEig: + public virtual ARSymGenEig, + ARchSymPencil > { + + private: + + // a) Data structure used to store matrices. + + ARchSymPencil Pencil; + + // b) Protected functions: + + virtual void Copy(const ARluSymGenEig& other); + // Makes a deep copy of "other" over "this" object. + // Old values are not deleted (this function is to be used + // by the copy constructor and the assignment operator only). + + + public: + + // c) Public functions: + + // c.1) Functions that allow changes in problem parameters. + + virtual void ChangeShift(ARFLOAT sigmap); + + virtual void SetRegularMode(); + + virtual void SetShiftInvertMode(ARFLOAT sigmap); + + virtual void SetBucklingMode(ARFLOAT sigmap); + + virtual void SetCayleyMode(ARFLOAT sigmap); + + // c.2) Constructors and destructor. + + ARluSymGenEig() { } + // Short constructor. + + ARluSymGenEig(int nevp, ARchSymMatrix& A, + ARchSymMatrix& B, const std::string& whichp = "LM", + int ncvp = 0, ARFLOAT tolp = 0.0, int maxitp = 0, + ARFLOAT* residp = NULL, bool ishiftp = true); + // Long constructor (regular mode). + + ARluSymGenEig(char InvertModep, int nevp, ARchSymMatrix& A, + ARchSymMatrix& B, ARFLOAT sigma, const std::string& whichp = "LM", + int ncvp = 0, ARFLOAT tolp = 0.0, int maxitp = 0, + ARFLOAT* residp = NULL, bool ishiftp = true); + // Long constructor (shift and invert, buckling and Cayley modes). + + ARluSymGenEig(const ARluSymGenEig& other) { Copy(other); } + // Copy constructor. + + virtual ~ARluSymGenEig() { } + // Destructor. + + // d) Operators. + + ARluSymGenEig& operator=(const ARluSymGenEig& other); + // Assignment operator. + +}; // class ARluSymGenEig. + + +// ------------------------------------------------------------------------ // +// ARluSymGenEig member functions definition. // +// ------------------------------------------------------------------------ // + + +template +inline void ARluSymGenEig:: +Copy(const ARluSymGenEig& other) +{ + + ARSymGenEig, + ARchSymPencil >:: Copy(other); + Pencil = other.Pencil; + this->objOP = &Pencil; + this->objB = &Pencil; + this->objA = &Pencil; + +} // Copy. + + +template +inline void ARluSymGenEig::ChangeShift(ARFLOAT sigmap) +{ + + this->objOP->FactorAsB(sigmap); + ARrcSymGenEig::ChangeShift(sigmap); + +} // ChangeShift. + + +template +inline void ARluSymGenEig::SetRegularMode() +{ + + ARStdEig >:: + SetRegularMode(&Pencil, &ARchSymPencil::MultInvBAv); + +} // SetRegularMode. + + +template +inline void ARluSymGenEig:: +SetShiftInvertMode(ARFLOAT sigmap) +{ + + ARSymGenEig, ARchSymPencil >:: + SetShiftInvertMode(sigmap, &Pencil, &ARchSymPencil::MultInvAsBv); + this->ChangeMultBx(&Pencil, &ARchSymPencil::MultBv); + +} // SetShiftInvertMode. + + +template +inline void ARluSymGenEig:: +SetBucklingMode(ARFLOAT sigmap) +{ + + ARSymGenEig, ARchSymPencil >:: + SetBucklingMode(sigmap, &Pencil, &ARchSymPencil::MultInvAsBv); + this->ChangeMultBx(&Pencil, &ARchSymPencil::MultAv); + +} // SetBucklingMode. + + +template +inline void ARluSymGenEig:: +SetCayleyMode(ARFLOAT sigmap) +{ + + ARSymGenEig, ARchSymPencil >:: + SetCayleyMode(sigmap, &Pencil, &ARchSymPencil::MultInvAsBv, + &Pencil, &ARchSymPencil::MultAv); + this->ChangeMultBx(&Pencil, &ARchSymPencil::MultBv); + +} // SetCayleyMode. + + +template +inline ARluSymGenEig:: +ARluSymGenEig(int nevp, ARchSymMatrix& A, + ARchSymMatrix& B, const std::string& whichp, int ncvp, + ARFLOAT tolp, int maxitp, ARFLOAT* residp, bool ishiftp) + +{ + + Pencil.DefineMatrices(A, B); + this->InvertMode = 'S'; + this->NoShift(); + this->DefineParameters(A.ncols(), nevp, &Pencil, + &ARchSymPencil::MultInvBAv, &Pencil, + &ARchSymPencil::MultBv, whichp, + ncvp, tolp, maxitp, residp, ishiftp); + +} // Long constructor (regular mode). + + +template +inline ARluSymGenEig:: +ARluSymGenEig(char InvertModep, int nevp, ARchSymMatrix& A, + ARchSymMatrix& B, ARFLOAT sigmap, + const std::string& whichp, int ncvp, ARFLOAT tolp, + int maxitp, ARFLOAT* residp, bool ishiftp) + +{ + + Pencil.DefineMatrices(A, B); + this->DefineParameters(A.ncols(), nevp, &Pencil, + &ARchSymPencil::MultInvAsBv, &Pencil, + &ARchSymPencil::MultBv, whichp, + ncvp, tolp, maxitp, residp, ishiftp); + this->InvertMode = this->CheckInvertMode(InvertModep); + switch (this->InvertMode) { + case 'B': // Buckling mode. + this->ChangeMultBx(&Pencil, &ARchSymPencil::MultAv); + case 'S': // Shift and invert mode. + ChangeShift(sigmap); + break; + case 'C': // Cayley mode. + SetCayleyMode(sigmap); + } + +} // Long constructor (shift and invert, buckling and Cayley modes). + + +template +ARluSymGenEig& ARluSymGenEig:: +operator=(const ARluSymGenEig& other) +{ + + if (this != &other) { // Stroustrup suggestion. + this->ClearMem(); + Copy(other); + } + return *this; + +} // operator=. + + +#endif // ARUGSYM_H diff --git a/external/arpack++/include/arch.h b/external/arpack++/include/arch.h new file mode 100644 index 000000000..135157306 --- /dev/null +++ b/external/arpack++/include/arch.h @@ -0,0 +1,95 @@ +/* + ARPACK++ v1.2 2/20/2000 + c++ interface to ARPACK code. + + MODULE arch.h + Modified version of arch.h (from LAPACK++ 1.1). + Machine dependent functions and variable types. + + ARPACK Authors + Richard Lehoucq + Danny Sorensen + Chao Yang + Dept. of Computational & Applied Mathematics + Rice University + Houston, Texas +*/ + + +#ifndef ARCH_H +#define ARCH_H + +// ARPACK++ arcomplex type definition. +// If you are not using g++ (or CC) and also are not intending +// use complex variables, comment out the following line. + +#include "arcomp.h" + +// STL vector class. +// If the Standard Template Library is not available at your system +// and you do not want to install it, comment out the following line. + +#include + +// If your STL vector class defines a variable other than +// __SGI_STL_VECTOR_H, please change this variable name +// in the ifdef command below. + +#ifdef __SGI_STL_VECTOR_H + #define STL_VECTOR_H +#endif + +// UMFPACK parameters. +// These parameters are used by UMFPACK library functions. Normally +// they are not modified by the user. To use the default value, set +// the parameter to zero. For a complete description of all UMFPACK +// parameters, see the library documentation. + +#define UICNTL7 0 // icntl(7). Block size for the blas (machine-dependent). +#define UICNTL5 0 // icntl(5). Number of columns to examine during pivot search. +#define UCNTL2 0 // cntl(2). Amalgamation parameter. +#define UKEEP7 0 // keep(7). Absolute number of elements a column must have + // to be considered "dense". +#define UKEEP8 0 // keep(8). Relative number of elements a column must have + // to be considered "dense". Dense columns have more + // than max{0,UMFABDEN,UMFREDEN*sqrt(n)} elements. + +// Line length used when reading a dense matrix from a file. + +#define LINELEN 256 + +// Linkage names between C, C++, and Fortran (platform dependent) + +#if defined(RIOS) && !defined(CLAPACK) +#define F77NAME(x) x +#else +// #include +// #define F77NAME(x) name2(x,_) +#define F77NAME(x) x ## _ +#endif + +#if defined(SGI) && !defined(SGI_DEC) +#define SGI_DEC + +extern "C" { + void mkidxname() {} + void mkdatname() {} +} +#endif + + +// Type conversion. + +typedef int ARint; +typedef int ARlogical; + +#ifdef __SUNPRO_CC + + typedef int bool; + int true = 1; + int false = 0; + +#endif + + +#endif // ARCH_H diff --git a/external/arpack++/include/arcomp.h b/external/arpack++/include/arcomp.h new file mode 100644 index 000000000..6a391d026 --- /dev/null +++ b/external/arpack++/include/arcomp.h @@ -0,0 +1,46 @@ +/* + ARPACK++ v1.2 2/20/2000 + c++ interface to ARPACK code. + + MODULE arcomp.h + arcomplex complex type definition. + + ARPACK Authors + Richard Lehoucq + Danny Sorensen + Chao Yang + Dept. of Computational & Applied Mathematics + Rice University + Houston, Texas +*/ + +#ifndef ARCOMP_H +#define ARCOMP_H + +#include + +#ifdef __GNUG__ + +#define arcomplex std::complex + +#endif + +#if defined(__SUNPRO_CC) || defined(__sgi) + + template + class arcomplex: public complex + { + public: + + arcomplex(ARFLOAT x, ARFLOAT y): complex(x,y) { } + arcomplex(): complex() { } + arcomplex(complex x): complex(x) { } + + }; + +#endif + +#endif // ARCOMP_H + + + diff --git a/external/arpack++/include/arcsmat.h b/external/arpack++/include/arcsmat.h new file mode 100644 index 000000000..a97e9fad8 --- /dev/null +++ b/external/arpack++/include/arcsmat.h @@ -0,0 +1,473 @@ +/* + ARPACK++ v1.2 2/20/2000 + c++ interface to ARPACK code. + + MODULE ARCSMat.h. + Arpack++ class ARchSymMatrix definition. + (CHOLMOD wrapper) + + Author of this class: + Martin Reuter + Date 11/05/2012 + + Arpack++ Author: + Francisco Gomes + + ARPACK Authors + Richard Lehoucq + Danny Sorensen + Chao Yang + Dept. of Computational & Applied Mathematics + Rice University + Houston, Texas +*/ + + +#include "arcspen.h" + +#ifndef ARCSMAT_H +#define ARCSMAT_H + +#include +#include +#include "arch.h" +#include "armat.h" +#include "arhbmat.h" +#include "arerror.h" +#include "cholmodc.h" +//#include "blas1c.h" +//#include "superluc.h" +//#include "arlspdef.h" +//#include "arlutil.h" +#include + +template class ARchSymPencil; + +template +class ARchSymMatrix: public ARMatrix { + + friend class ARchSymPencil; + + protected: + + bool factored; + char uplo; + int nnz; + int* irow; + int* pcol; + double threshold; + ARTYPE* a; + ARhbMatrix mat; + cholmod_common c ; + cholmod_sparse *A ; + cholmod_factor *L ; + + bool DataOK(); + + virtual void Copy(const ARchSymMatrix& other); + + void ClearMem(); + + public: + + int nzeros() { return nnz; } + + bool IsFactored() { return factored; } + + void FactorA(); + + void FactorAsI(ARTYPE sigma); + + void MultMv(ARTYPE* v, ARTYPE* w); + + void MultInvv(ARTYPE* v, ARTYPE* w); + + void DefineMatrix(int np, int nnzp, ARTYPE* ap, int* irowp, + int* pcolp, char uplop = 'L', double thresholdp = 0.1, + bool check = true); + + ARchSymMatrix(): ARMatrix() { factored = false; cholmod_start (&c) ;} + // Short constructor that does nothing. + + ARchSymMatrix(int np, int nnzp, ARTYPE* ap, int* irowp, + int* pcolp, char uplop = 'L', double thresholdp = 0.1, + bool check = true); + // Long constructor. + + ARchSymMatrix(const std::string& name, double thresholdp = 0.1, + bool check = true); + // Long constructor (Harwell-Boeing file). + + ARchSymMatrix(const ARchSymMatrix& other) { cholmod_start (&c) ; Copy(other); } + // Copy constructor. + + virtual ~ARchSymMatrix() { ClearMem(); cholmod_finish (&c) ;} + // Destructor. + + ARchSymMatrix& operator=(const ARchSymMatrix& other); + // Assignment operator. + +}; + +// ------------------------------------------------------------------------ // +// ARchSymMatrix member functions definition. // +// ------------------------------------------------------------------------ // + + +template +bool ARchSymMatrix::DataOK() +{ + + int i, j, k; + + // Checking if pcol is in ascending order. + + i = 0; + while ((i!=this->n)&&(pcol[i]<=pcol[i+1])) i++; + if (i!=this->n) return false; + + // Checking if irow components are in order and within bounds. + + for (i=0; i!=this->n; i++) { + j = pcol[i]; + k = pcol[i+1]-1; + if (j<=k) { + if (uplo == 'U') { + if ((irow[j]<0)||(irow[k]>i)) return false; + } + else { // uplo == 'L'. + if ((irow[j]=this->n)) return false; + } + while ((j!=k)&&(irow[j] +void ARchSymMatrix::ClearMem() +{ + + if (factored) { + cholmod_free_factor (&L, &c) ; + } + if (this->defined) { + //cholmod_free_sparse (&A, &c); + //delete[] permc; + //delete[] permr; + //permc = NULL; + //permr = NULL; + + free(A); // don't delete data in A as it came from external + A = NULL; + } + +} // ClearMem. + + + +template +inline void ARchSymMatrix::Copy(const ARchSymMatrix& other) +{ + + // Copying very fundamental variables. + ClearMem(); + + this->defined = other.defined; + // Returning from here if "other" was not initialized. + if (!this->defined) return; + + this->n = other.n; + factored = other.factored; + uplo = other.uplo; + nnz = other.nnz; + irow = other.irow; + pcol = other.pcol; + threshold = other.threshold; + a = other.a; + //c = other.c; + + A = cholmod_copy_sparse(other.A,&c); + + if (L) cholmod_free_factor(&L,&c); + if (factored) + L = cholmod_copy_factor(other.L,&c); + +} // Copy. + + + +template +void ARchSymMatrix::FactorA() +{ + int info; + + //std::cout << "ARchSymMatrix::FactorA" << std::endl; + + // Quitting the function if A was not defined. + if (!this->IsDefined()) { + throw ArpackError(ArpackError::DATA_UNDEFINED, "ARchSymMatrix::FactorA"); + } + + // Deleting previous versions of L. + if (factored) { + cholmod_free_factor (&L, &c) ; + } + + L = cholmod_analyze (A, &c) ; + info = cholmod_factorize (A, L, &c) ; + + + factored = (info != 0); + + if (c.status != CHOLMOD_OK) + { + throw ArpackError(ArpackError::INCONSISTENT_DATA, + "ARchSymMatrix::FactorA"); + + factored = false; + } + +// +// // Handling errors. +// +// if (info < 0) { // Illegal argument. +// throw ArpackError(ArpackError::PARAMETER_ERROR, +// "ARchSymMatrix::FactorA"); +// } +// else if (info > this->n) { // Memory is not sufficient. +// throw ArpackError(ArpackError::MEMORY_OVERFLOW, +// "ARchSymMatrix::FactorA"); +// } +// else if (info > 0) { // Matrix is singular. +// throw ArpackError(ArpackError::MATRIX_IS_SINGULAR, +// "ARchSymMatrix::FactorA"); +// } + +} // FactorA. + + +template +void ARchSymMatrix::FactorAsI(ARTYPE sigma) +{ + + //std::cout <<"ARchSymMatrix::FactorAsI " << std::endl; + + // Quitting the function if A was not defined. + if (!this->IsDefined()) { + throw ArpackError(ArpackError::DATA_UNDEFINED, "ARchSymMatrix::FactorAsI"); + } + + + // Deleting previous versions of L. + if (factored) { + cholmod_free_factor (&L, &c) ; + } + +// FILE *fp ; +// fp = fopen ("A.mat", "w" ) ; +// cholmod_write_sparse(fp,A,NULL,NULL,&c); + + // Factorizing A-sigma*I + double sigma2[2]; + sigma2[0] = -sigma; + sigma2[1] = 0.0; + L = cholmod_analyze (A, &c) ; + int info = cholmod_factorize_p (A,sigma2,NULL,0,L,&c) ; + + factored = (info != 0); + + if (c.status != CHOLMOD_OK) + { + throw ArpackError(ArpackError::INCONSISTENT_DATA, + "ARchSymMatrix::FactorAsI"); + + factored = false; + } + + +} // FactorAsI. + + +template +void ARchSymMatrix::MultMv(ARTYPE* v, ARTYPE* w) +{ + //std::cout << "ARchSymMatrix::MultMv " << std::endl; + + int i, j, k; + ARTYPE t; + + // Quitting the function if A was not defined. + + if (!this->IsDefined()) { + throw ArpackError(ArpackError::DATA_UNDEFINED, "ARchSymMatrix::MultMv"); + } + + // Determining w = M.v. + + for (i=0; i!=this->m; i++) w[i]=(ARTYPE)0; + + if (uplo == 'U') { + + for (i=0; i!=this->n; i++) { + t = v[i]; + k = pcol[i+1]; + if ((k!=pcol[i])&&(irow[k-1]==i)) { + w[i] += t*a[k-1]; + k--; + } + for (j=pcol[i]; jn; i++) { + t = v[i]; + k = pcol[i]; + if ((k!=pcol[i+1])&&(irow[k]==i)) { + w[i] += t*a[k]; + k++; + } + for (j=k; j +void ARchSymMatrix::MultInvv(ARTYPE* v, ARTYPE* w) +{ + //std::cout << "ARchSymMatrix::MultInvv " << std::endl; + + // Quitting the function if A (or AsI) was not factored. + + if (!IsFactored()) { + throw ArpackError(ArpackError::NOT_FACTORED_MATRIX, + "ARchSymMatrix::MultInvv"); + } + + // Solving A.w = v (or AsI.w = v). + + //std::cout<< " b = [ " << v[0]; + //for(int i=1;in;i++) + // std::cout << " , " << v[i]; + //std::cout<< " ]" <n,1,v,&c); + + cholmod_dense *x = cholmod_solve (CHOLMOD_A, L, b, &c) ; + + Get_Cholmod_Dense_Data(x, this->n, w); + + //std::cout<< " x = [ " << w[0]; + //for(int i=1;in;i++) + // std::cout << " , " << w[i]; + //std::cout<< " ]" < +inline void ARchSymMatrix:: +DefineMatrix(int np, int nnzp, ARTYPE* ap, int* irowp, int* pcolp, + char uplop, double thresholdp, bool check) +{ + + this->m = np; + this->n = np; + nnz = nnzp; + a = ap; + irow = irowp; + pcol = pcolp; + pcol[this->n] = nnz; + uplo = uplop; + threshold = thresholdp; + + // Checking data. + if ((check)&&(!DataOK())) { + throw ArpackError(ArpackError::INCONSISTENT_DATA, + "ARchSymMatrix::DefineMatrix"); + } + + // Creating SuperMatrix A. + A = Create_Cholmod_Sparse_Matrix(this->n, this->n, nnz, a, irow, pcol, uplo, &c); + + this->defined = true; + +} // DefineMatrix. + + +template +inline ARchSymMatrix:: +ARchSymMatrix(int np, int nnzp, ARTYPE* ap, int* irowp, + int* pcolp, char uplop, double thresholdp, + bool check) : ARMatrix(np) +{ + cholmod_start (&c) ; + + factored = false; + DefineMatrix(np, nnzp, ap, irowp, pcolp, uplop, thresholdp, check); + +} // Long constructor. + + +template +ARchSymMatrix:: +ARchSymMatrix(const std::string& file, double thresholdp, bool check) +{ + cholmod_start (&c) ; + + factored = false; + + try { + mat.Define(file); + } + catch (ArpackError) { // Returning from here if an error has occurred. + throw ArpackError(ArpackError::CANNOT_READ_FILE, "ARchSymMatrix"); + } + + if ((mat.NCols() == mat.NRows()) && (mat.IsSymmetric())) { + + DefineMatrix(mat.NCols(), mat.NonZeros(), (ARTYPE*)mat.Entries(), + mat.RowInd(), mat.ColPtr(), 'L', thresholdp, check); + } + else { + throw ArpackError(ArpackError::INCONSISTENT_DATA, + "ARchSymMatrix::ARchSymMatrix"); + } +} // Long constructor (Harwell-Boeing file). + + +template +ARchSymMatrix& ARchSymMatrix:: +operator=(const ARchSymMatrix& other) +{ + + if (this != &other) { // Stroustrup suggestion. + ClearMem(); + Copy(other); + } + return *this; + +} // operator=. + + +#endif // ARCSMAT_H diff --git a/external/arpack++/include/arcspen.h b/external/arpack++/include/arcspen.h new file mode 100644 index 000000000..424535fa7 --- /dev/null +++ b/external/arpack++/include/arcspen.h @@ -0,0 +1,434 @@ +/* + ARPACK++ v1.2 2/20/2000 + c++ interface to ARPACK code. + + MODULE ARCSPen.h. + Arpack++ class ARchSymMPencil definition. + (CHOLMOD wrapper) + + Author of this class: + Martin Reuter + Date 11/05/2012 + + Arpack++ Author: + Francisco Gomes + + ARPACK Authors + Richard Lehoucq + Danny Sorensen + Chao Yang + Dept. of Computational & Applied Mathematics + Rice University + Houston, Texas +*/ + +#ifndef ARCSPEN_H +#define ARCSPEN_H + +//#include "arch.h" +//#include "arerror.h" +#include "blas1c.h" +//#include "lapackc.h" +#include "arcsmat.h" + + +template +class ARchSymPencil +{ + + protected: + + ARchSymMatrix* A; + ARchSymMatrix* B; + cholmod_factor *LAsB ; + bool factoredAsB; + cholmod_common c ; + + virtual void Copy(const ARchSymPencil& other); + +// void SparseSaxpy(ARTYPE a, ARTYPE x[], int xind[], int nx, ARTYPE y[], +// int yind[], int ny, ARTYPE z[], int zind[], int& nz); + +// void ExpandAsB(); + +// void SubtractAsB(ARTYPE sigma); + + public: + + bool IsFactored() { return factoredAsB; } + + void FactorAsB(ARTYPE sigma); + + void MultAv(ARTYPE* v, ARTYPE* w) { A->MultMv(v,w); } + + void MultBv(ARTYPE* v, ARTYPE* w) { B->MultMv(v,w); } + + void MultInvBAv(ARTYPE* v, ARTYPE* w); + + void MultInvAsBv(ARTYPE* v, ARTYPE* w); + + void DefineMatrices(ARchSymMatrix& Ap, ARchSymMatrix& Bp); + + ARchSymPencil() { factoredAsB = false; A=NULL; B=NULL; LAsB=NULL; cholmod_start (&c) ; } + // Short constructor that does nothing. + + ARchSymPencil(ARchSymMatrix& Ap, ARchSymMatrix& Bp); + // Long constructor. + + ARchSymPencil(const ARchSymPencil& other) { cholmod_start (&c) ; Copy(other); } + // Copy constructor. + + virtual ~ARchSymPencil() { if (LAsB) cholmod_free_factor(&LAsB,&c); cholmod_finish (&c) ;} + // Destructor. + + ARchSymPencil& operator=(const ARchSymPencil& other); + // Assignment operator. + +}; + +// ------------------------------------------------------------------------ // +// ARchSymPencil member functions definition. // +// ------------------------------------------------------------------------ // + + +template +inline void ARchSymPencil::Copy(const ARchSymPencil& other) +{ + if (LAsB) cholmod_free_factor(&LAsB,&c); + A = other.A; + B = other.B; + factoredAsB = other.factoredAsB; + if (factoredAsB) + LAsB = cholmod_copy_factor(other.LAsB,&c); + +} // Copy. + +/* +template +void ARchSymPencil:: +SparseSaxpy(ARTYPE a, ARTYPE x[], int xind[], int nx, ARTYPE y[], + int yind[], int ny, ARTYPE z[], int zind[], int& nz) +// A strongly sequential (and inefficient) sparse saxpy algorithm. +{ + + int ix, iy; + + nz = 0; + if ((nx == 0) || (a == (ARTYPE)0)) { + copy(ny,y,1,z,1); + for (iy=0; iy!=ny; iy++) zind[iy] = yind[iy]; + nz = ny; + return; + } + if (ny == 0) { + copy(nx,x,1,z,1); + scal(nx,a,z,1); + for (ix=0; ix!=nx; ix++) zind[ix] = xind[ix]; + nz = nx; + return; + } + ix = 0; + iy = 0; + while (true) { + if (xind[ix] == yind[iy]) { + zind[nz] = xind[ix]; + z[nz++] = a*x[ix++]+y[iy++]; + if ((ix == nx)||(iy == ny)) break; + } + else if (xind[ix] < yind[iy]) { + zind[nz] = xind[ix]; + z[nz++] = a*x[ix++]; + if (ix == nx) break; + } + else { + zind[nz] = yind[iy]; + z[nz++] = y[iy++]; + if (iy == ny) break; + } + } + while (iy < ny) { + zind[nz] = yind[iy]; + z[nz++] = y[iy++]; + } + while (ix < nx) { + zind[nz] = xind[ix]; + z[nz++] = x[ix++]; + } + +} // SparseSaxpy. + + +template +void ARchSymPencil::ExpandAsB() +{ + + int i, j, k, n; + int *pcol, *irow, *index, *pos; + ARTYPE *value; + + // Initializing variables. + + n = AsB.n; + index = AsB.index; + value = AsB.value; + irow = &index[n+1]; + pcol = new int[AsB.n+1]; + pos = new int[AsB.n+1]; + for (i=0; i<=n; i++) pcol[i] = index[i]; + for (i=0; i<=n; i++) pos[i] = 0; + + // Counting the elements in each column of AsB. + + if (AsB.uplo == 'U') { + + for (i=0; i!=n; i++) { + k = pcol[i+1]; + if ((k!=pcol[i])&&(irow[k-1]==i)) k--; + for (j=pcol[i]; j0; i--) index[i] += pos[i-1]; + + // Expanding A. + + if (AsB.uplo == 'U') { + + for (i=n-1; i>=0; i--) { + pos[i] = index[i]+pcol[i+1]-pcol[i]; + k = pos[i]-1; + for (j=pcol[i+1]-1; j>=pcol[i]; j--) { + value[k] = value[j]; + irow[k--] = irow[j]; + } + } + for (i=1; iindex[i])&&(irow[k-1]==i)) k--; + for (j=index[i]; j=0; i--) { + k = index[i+1]-1; + for (j=pcol[i+1]-1; j>=pcol[i]; j--) { + value[k] = value[j]; + irow[k--] = irow[j]; + } + pos[i] = index[i]; + } + for (i=0; i<(n-1); i++) { + k = index[i+1]-pcol[i+1]+pcol[i]; + if ((k +void ARchSymPencil::SubtractAsB(ARTYPE sigma) +{ + + int i, acol, bcol, asbcol, scol; + + // Quitting function if A->uplo is not equal to B->uplo. + + if ((A->uplo != B->uplo)&&(sigma != (ARTYPE)0)) { + throw ArpackError(ArpackError::DIFFERENT_TRIANGLES, + "ARchSymPencil::SubtractAsB"); + } + AsB.uplo = A->uplo; + + // Subtracting sigma*B from A. + + AsB.index[0] = 0; + asbcol = 0; + + for (i=0; i!=AsB.n; i++) { + bcol = B->pcol[i]; + acol = A->pcol[i]; + SparseSaxpy(-sigma, &B->a[bcol], &B->irow[bcol], B->pcol[i+1]-bcol, + &A->a[acol], &A->irow[acol], A->pcol[i+1]-acol, + &AsB.value[asbcol], &AsB.index[asbcol+AsB.n+1], scol); + asbcol += scol; + AsB.index[i+1] = asbcol; + } + + // Expanding AsB. + + ExpandAsB(); + + // Adding one to all elements of vector index + // because the decomposition function was written in FORTRAN. + + for (i=0; i<=AsB.n+AsB.nnz; i++) AsB.index[i]++; + +} // SubtractAsB. + +*/ + +template +void ARchSymPencil::FactorAsB(ARTYPE sigma) +{ + + // Quitting the function if A and B were not defined. + + if (!(A->IsDefined()&&B->IsDefined())) { + throw ArpackError(ArpackError::DATA_UNDEFINED, + "ARchSymPencil::FactorAsB"); + } + + + if (LAsB) cholmod_free_factor(&LAsB,&c); + + cholmod_sparse* AsB; + if (sigma != 0.0) + { + std::cout << " Subtracting sigma B (sigma="<A,B->A,alpha,beta,1,0,&c); + } + else + AsB = A->A; + +//FILE *fp; +//fp=fopen("AsB.asc", "w"); +//cholmod_write_sparse(fp,AsB,NULL,NULL,&c); +//FILE *fpa; +//fpa=fopen("As.asc", "w"); +//cholmod_write_sparse(fpa,B->A,NULL,NULL,&c); +//FILE *fpb; +//fpb=fopen("Bs.asc", "w"); +//cholmod_write_sparse(fpb,A->A,NULL,NULL,&c); + + LAsB = cholmod_analyze (AsB, &c) ; + int info = cholmod_factorize (AsB, LAsB, &c) ; + + factoredAsB = (info != 0); + if (c.status != CHOLMOD_OK) + { + //std::cout << " sigma : " << sigma << std::endl; + + Write_Cholmod_Sparse_Matrix("AsB-error.asc",AsB,&c); + + throw ArpackError(ArpackError::INCONSISTENT_DATA, + "ARchSymPencil::FactorAsB"); + + factoredAsB = false; + } + + if (sigma != 0.0) + cholmod_free_sparse(&AsB,&c); + + +} // FactorAsB (ARTYPE shift). + + +template +void ARchSymPencil::MultInvBAv(ARTYPE* v, ARTYPE* w) +{ + + if (!B->IsFactored()) B->FactorA(); + + A->MultMv(v, w); + ::copy(A->ncols(), w, 1, v, 1); + B->MultInvv(w, w); + +} // MultInvBAv. + +template +void ARchSymPencil::MultInvAsBv(ARTYPE* v, ARTYPE* w) +{ + if (!IsFactored()) { + throw ArpackError(ArpackError::NOT_FACTORED_MATRIX, + "ARchSymPencil::MultInvAsBv"); + } + + // Solving A.w = v (or AsI.w = v). + + //create b from v (data is not copied!!) + cholmod_dense * b = Create_Cholmod_Dense_Matrix(A->n,1,v,&c); + + cholmod_dense *x = cholmod_solve (CHOLMOD_A, LAsB, b, &c) ; + + Get_Cholmod_Dense_Data(x, A->n, w); + + free(b); + cholmod_free_dense(&x,&c); + + +} // MultInvAsBv + +template +inline void ARchSymPencil:: +DefineMatrices(ARchSymMatrix& Ap, ARchSymMatrix& Bp) +{ + + A = &Ap; + B = &Bp; + + if (A->n != B->n) { + throw ArpackError(ArpackError::INCOMPATIBLE_SIZES, + "ARchSymMatrix::DefineMatrices"); + } + +} // DefineMatrices. + + +template +inline ARchSymPencil:: +ARchSymPencil(ARchSymMatrix& Ap, ARchSymMatrix& Bp) +{ + cholmod_start (&c) ; + LAsB=NULL; + DefineMatrices(Ap, Bp); + +} // Long constructor. + + +template +ARchSymPencil& ARchSymPencil:: +operator=(const ARchSymPencil& other) +{ + + if (this != &other) { // Stroustrup suggestion. + Copy(other); + } + return *this; + +} // operator=. + + +#endif // ARUSPEN_H diff --git a/external/arpack++/include/arcssym.h b/external/arpack++/include/arcssym.h new file mode 100644 index 000000000..26094e93b --- /dev/null +++ b/external/arpack++/include/arcssym.h @@ -0,0 +1,166 @@ +/* + ARPACK++ v1.2 2/20/2000 + c++ interface to ARPACK code. + + MODULE ARUSSym.h. + Arpack++ class ARluSymStdEig definition + (CHOLMOD version). + + Author of this class: + Martin Reuter + Date 11/05/2012 + + Arpack++ Author: + Francisco Gomes + + + ARPACK Authors + Richard Lehoucq + Danny Sorensen + Chao Yang + Dept. of Computational & Applied Mathematics + Rice University + Houston, Texas +*/ + +#ifndef ARCSSYM_H +#define ARCSSYM_H + +#include +#include +#include "arch.h" +#include "arssym.h" +#include "arcsmat.h" + + +template +class ARluSymStdEig: + public virtual ARSymStdEig > { + + public: + + // a) Public functions: + + // a.1) Functions that allow changes in problem parameters. + + virtual void ChangeShift(ARFLOAT sigmaRp); + + virtual void SetRegularMode(); + + virtual void SetShiftInvertMode(ARFLOAT sigmap); + + // a.2) Constructors and destructor. + + ARluSymStdEig() { } + // Short constructor. + + ARluSymStdEig(int nevp, ARchSymMatrix& A, + const std::string& whichp = "LM", int ncvp = 0, + ARFLOAT tolp = 0.0, int maxitp = 0, + ARFLOAT* residp = NULL, bool ishiftp = true); + // Long constructor (regular mode). + + ARluSymStdEig(int nevp, ARchSymMatrix& A, + ARFLOAT sigma, const std::string& whichp = "LM", int ncvp = 0, + ARFLOAT tolp = 0.0, int maxitp = 0, + ARFLOAT* residp = NULL, bool ishiftp = true); + // Long constructor (shift and invert mode). + + ARluSymStdEig(const ARluSymStdEig& other) { Copy(other); } + // Copy constructor. + + virtual ~ARluSymStdEig() { } + // Destructor. + + // b) Operators. + + ARluSymStdEig& operator=(const ARluSymStdEig& other); + // Assignment operator. + +}; // class ARluSymStdEig. + + +// ------------------------------------------------------------------------ // +// ARluSymStdEig member functions definition. // +// ------------------------------------------------------------------------ // + + +template +inline void ARluSymStdEig::ChangeShift(ARFLOAT sigmaRp) +{ + + this->sigmaR = sigmaRp; + this->sigmaI = 0.0; + this->mode = 3; + this->iparam[7] = this->mode; + + this->objOP->FactorAsI(this->sigmaR); + this->Restart(); + +} // ChangeShift. + + +template +inline void ARluSymStdEig::SetRegularMode() +{ + + ARStdEig >:: + SetRegularMode(this->objOP, &ARchSymMatrix::MultMv); + +} // SetRegularMode. + + +template +inline void ARluSymStdEig::SetShiftInvertMode(ARFLOAT sigmap) +{ + + ARStdEig >:: + SetShiftInvertMode(sigmap, this->objOP, &ARchSymMatrix::MultInvv); + +} // SetShiftInvertMode. + + +template +inline ARluSymStdEig:: +ARluSymStdEig(int nevp, ARchSymMatrix& A, + const std::string& whichp, int ncvp, ARFLOAT tolp, + int maxitp, ARFLOAT* residp, bool ishiftp) +{ + + this->NoShift(); + this->DefineParameters(A.ncols(), nevp, &A, &ARchSymMatrix::MultMv, + whichp, ncvp, tolp, maxitp, residp, ishiftp); + +} // Long constructor (regular mode). + + +template +inline ARluSymStdEig:: +ARluSymStdEig(int nevp, ARchSymMatrix& A, + ARFLOAT sigmap, const std::string& whichp, int ncvp, ARFLOAT tolp, + int maxitp, ARFLOAT* residp, bool ishiftp) + +{ + + this->DefineParameters(A.ncols(), nevp, &A, &ARchSymMatrix::MultInvv, + whichp, ncvp, tolp, maxitp, residp, ishiftp); + this->ChangeShift(sigmap); + +} // Long constructor (shift and invert mode). + + +template +ARluSymStdEig& ARluSymStdEig:: +operator=(const ARluSymStdEig& other) +{ + + if (this != &other) { // Stroustrup suggestion. + this->ClearMem(); + Copy(other); + } + return *this; + +} // operator=. + + +#endif // ARUSSYM_H diff --git a/external/arpack++/include/ardfmat.h b/external/arpack++/include/ardfmat.h new file mode 100644 index 000000000..cacf6b4c4 --- /dev/null +++ b/external/arpack++/include/ardfmat.h @@ -0,0 +1,453 @@ +/* + ARPACK++ v1.2 2/20/2000 + c++ interface to ARPACK code. + + MODULE ARDFMat.h + Matrix template that generates a dense matrix from a file. + + ARPACK authors: + Richard Lehoucq + Kristyn Maschhoff + Danny Sorensen + Chao Yang + Dept. of Computational & Applied Mathematics + Rice University + Houston, Texas +*/ + + +#ifndef ARDFMAT_H +#define ARDFMAT_H + +#include +#include +#include +#include +#include +#include +#include "arch.h" +#include "arerror.h" + + +template +class ARdfMatrix { + + private: + + // const int linelength = 256; + + std::string datafile; // Filename. + std::ifstream file; // File handler. + int m; // Number of rows. + int n; // Number of columns. + int blksize; // Size of each matrix block that is read at once. + int block; // Index of the matrix block that is to be read. + int nblocks; // Number of blocks the matrix contain. + int first; // First row/column stored in val. + int strows; // Number of rows actually stored in val. + int stcols; // Number of columns actually stored in val. + int headsize; // Number of lines in the heading part of the file + // (including the line that contains the matrix size). + bool roword; // A variable that indicates if the data will be read + // using a row-major or a column-major ordering. + ARTYPE* val; // Numerical values of matrix entries. + + void ConvertDouble(char* num); + + void SetComplexPointers(char* num, char* &realp, char* &imagp); + + bool ReadEntry(std::ifstream& file, double& val); + + bool ReadEntry(std::ifstream& file, float& val); + + bool ReadEntry(std::ifstream& file, arcomplex& val); + + bool ReadEntry(std::ifstream& file, arcomplex& val); + + public: + + bool IsDefined() const { return (m!=0); } + + bool IsOutOfCore() const { + return ((m!=0) && ((roword && (blksize +inline void ARdfMatrix::ConvertDouble(char* num) +{ + + char* pd; + + pd = strchr((char*)num,'D'); + if (pd) *pd = 'E'; + pd = strchr((char*)num,'d'); + if (pd) *pd = 'E'; + +} // ConvertDouble. + + +template +inline void ARdfMatrix:: +SetComplexPointers(char* num, char* &realp, char* &imagp) +{ + + realp = num; + while (*realp == ' ') realp++; + imagp = realp; + while (*imagp != ' ') imagp++; + +} // SetComplexPointers. + + +template +inline bool ARdfMatrix::ReadEntry(std::ifstream& file, double& val) +{ + + char num[LINELEN]; + char c; + + if (file.get((char*)num,LINELEN,'\n')) { + file.get(c); + ConvertDouble((char*)num); + val = atof((char*)num); + return true; + } + else { + return false; + } + +} // ReadEntry (double). + + +template +inline bool ARdfMatrix::ReadEntry(std::ifstream& file, float& val) +{ + + double dval; + bool ret; + + ret = ReadEntry(file, dval); + val = (float)dval; + return ret; + +} // ReadEntry (float). + + +template +inline bool ARdfMatrix:: +ReadEntry(std::ifstream& file, arcomplex& val) +{ + + char num[LINELEN]; + char c; + char *realp, *imagp; + + if (file.get((char*)num,LINELEN,'\n')) { + file.get(c); + SetComplexPointers((char*)num, realp, imagp); + ConvertDouble((char*)realp); + ConvertDouble((char*)imagp); + val = arcomplex(atof((char*)realp), atof((char*)imagp)); + return true; + } + else { + return false; + } + +} // ReadEntry (arcomplex). + + +template +inline bool ARdfMatrix:: +ReadEntry(std::ifstream& file, arcomplex& val) +{ + + char num[LINELEN]; + char c; + char *realp, *imagp; + + if (file.get((char*)num,LINELEN,'\n')) { + file.get(c); + SetComplexPointers((char*)num, realp, imagp); + ConvertDouble((char*)realp); + ConvertDouble((char*)imagp); + val = arcomplex(atof((char*)realp), atof((char*)imagp)); + return true; + } + else { + return false; + } + +} // ReadEntry (arcomplex). + + +template +void ARdfMatrix::Rewind() +{ + + char data[LINELEN]; + char c; + + file.seekg(0); + block = 0; + first = 0; + strows = 0; + stcols = 0; + + // Skipping the header. + + for (int i=0; i +void ARdfMatrix::ReadBlock() +{ + + int i, j, last; + ARTYPE value; + + // Repositioning the file pointer if block == 0. + + if (block == 0) Rewind(); + + // Reading a block. + + first = (block++)*blksize; // First row/column to be read. + last = first+blksize; // First row/column of the next block. + + if (roword) { + + // Adjusting last if we are going to read the last block. + + if (last > m) { + last = m; + block = 0; + } + last -= first; + strows = last; + stcols = n; + + // Reading matrix data. + + for (i=0; i n) { + last = n; + block = 0; + } + last -= first; + strows = m; + stcols = last; + + // Reading matrix data. + + j = 0; + while ((j < m*last) && (ReadEntry(file, value))) { + val[j++] = value; + } + + // Exiting if the file is corrupted. + + if (j < m*last) { + throw ArpackError(ArpackError::UNEXPECTED_EOF, "ARdfMatrix"); + } + + } + +} // ReadBlock. + + +template +void ARdfMatrix::Define(const std::string& filename, int blksizep) +{ + + // Declaring variables. + + char c; + char data[LINELEN]; + + // Opening the file. + + datafile = filename; + file.open(datafile.c_str()); + + if (!file) { + throw ArpackError(ArpackError::CANNOT_OPEN_FILE, "ARdfMatrix"); + } + + // Setting initial values. + + blksize = blksizep; + block = 0; + headsize = 0; + first = 0; + strows = 0; + stcols = 0; + + // Reading the file heading. + + do { + file.get((char*)data,LINELEN,'\n'); + file.get(c); + headsize++; + } + while (data[0] == '%'); + + // Reading m and n or returning if a problem was detected. + + if (sscanf(data, "%d %d", &m, &n) != 2) { + throw ArpackError(ArpackError::PARAMETER_ERROR, "ARdfMatrix"); + } + if ((m<1) || (n<1)) { + throw ArpackError(ArpackError::PARAMETER_ERROR, "ARdfMatrix"); + } + + // Defining roword. + + roword = ((blksize != 0) && (m > n)); + + // (Re)Dimensioning val. + + if (val != NULL) delete[] val; + + if (blksize == 0) { + + // Redefining blksize and reading the entire matrix. + + blksize = n; + nblocks = 1; + val = new ARTYPE[m*blksize]; + ReadBlock(); + + } + else if (roword) { + + // m >> n, so we will read only blksize rows (but not now). + + if (blksize > m) blksize = m; + nblocks = (m+blksize-1)/blksize; + val = new ARTYPE[blksize*n]; + if (blksize == m) ReadBlock(); + + } + else { + + // n >> m, so we will read only blksize columns (but not now). + + if (blksize > n) blksize = n; + nblocks = (n+blksize-1)/blksize; + val = new ARTYPE[m*blksize]; + if (blksize == n) ReadBlock(); + + } + +} // Define. + + +template +ARdfMatrix::ARdfMatrix() +{ + + m = 0; + n = 0; + block = 0; + blksize = 0; + headsize = 0; + first = 0; + strows = 0; + stcols = 0; + roword = false; + val = NULL; + +} // Short constructor. + + +template +ARdfMatrix::ARdfMatrix(const std::string& filename, int blksizep) +{ + + val = NULL; + Define(filename, blksizep); + +} // Long constructor. + + +template +ARdfMatrix::~ARdfMatrix() +{ + + if (val != NULL) delete[] val; + +} // Destructor. + + +#endif // ARDFMAT_H + diff --git a/external/arpack++/include/ardgcomp.h b/external/arpack++/include/ardgcomp.h new file mode 100644 index 000000000..41240dce9 --- /dev/null +++ b/external/arpack++/include/ardgcomp.h @@ -0,0 +1,204 @@ +/* + ARPACK++ v1.2 2/20/2000 + c++ interface to ARPACK code. + + MODULE ARDGComp.h. + Arpack++ class ARluCompGenEig definition + (dense matrix version). + + ARPACK Authors + Richard Lehoucq + Danny Sorensen + Chao Yang + Dept. of Computational & Applied Mathematics + Rice University + Houston, Texas +*/ + +#ifndef ARDGCOMP_H +#define ARDGCOMP_H + +#include +#include +#include "arch.h" +#include "ardnsmat.h" +#include "ardnspen.h" +#include "arrseig.h" +#include "argcomp.h" + + +template +class ARluCompGenEig: + public virtual + ARCompGenEig, ARFLOAT >, + ARdsNonSymPencil, ARFLOAT > > { + + private: + + // a) Data structure used to store matrices. + + ARdsNonSymPencil, ARFLOAT > Pencil; + + // b) Protected functions: + + virtual void Copy(const ARluCompGenEig& other); + // Makes a deep copy of "other" over "this" object. + // Old values are not deleted (this function is to be used + // by the copy constructor and the assignment operator only). + + + public: + + // c) Public functions: + + // c.1) Functions that allow changes in problem parameters. + + virtual void ChangeShift(arcomplex sigmaRp); + + virtual void SetRegularMode(); + + virtual void SetShiftInvertMode(arcomplex sigmap); + + // c.2) Constructors and destructor. + + ARluCompGenEig() { } + // Short constructor. + + ARluCompGenEig(int nevp, ARdsNonSymMatrix, ARFLOAT>& A, + ARdsNonSymMatrix, ARFLOAT>& B, + const std::string& whichp = "LM", int ncvp = 0, + ARFLOAT tolp = 0.0, int maxitp = 0, + arcomplex* residp = NULL, bool ishiftp = true); + // Long constructor (regular mode). + + ARluCompGenEig(int nevp, ARdsNonSymMatrix, ARFLOAT>& A, + ARdsNonSymMatrix, ARFLOAT>& B, + arcomplex sigma, const std::string& whichp = "LM", + int ncvp = 0, ARFLOAT tolp = 0.0, int maxitp = 0, + arcomplex* residp = NULL, bool ishiftp = true); + // Long constructor (shift and invert mode). + + ARluCompGenEig(const ARluCompGenEig& other) { Copy(other); } + // Copy constructor. + + virtual ~ARluCompGenEig() { } + + // d) Operators. + + ARluCompGenEig& operator=(const ARluCompGenEig& other); + // Assignment operator. + +}; // class ARluCompGenEig. + + +// ------------------------------------------------------------------------ // +// ARluCompGenEig member functions definition. // +// ------------------------------------------------------------------------ // + + +template +inline void ARluCompGenEig:: +Copy(const ARluCompGenEig& other) +{ + + ARCompGenEig, ARFLOAT >, + ARdsNonSymPencil, ARFLOAT> >:: Copy(other); + Pencil = other.Pencil; + this->objOP = &Pencil; + this->objB = &Pencil; + +} // Copy. + + +template +inline void ARluCompGenEig:: +ChangeShift(arcomplex sigmaRp) +{ + + this->objOP->FactorAsB(sigmaRp); + ARrcStdEig >::ChangeShift(sigmaRp); + +} // ChangeShift. + + +template +inline void ARluCompGenEig::SetRegularMode() +{ + + ARStdEig, + ARdsNonSymPencil, ARFLOAT> >:: + SetRegularMode(&Pencil, + &ARdsNonSymPencil, ARFLOAT>::MultInvBAv); + +} // SetRegularMode. + + +template +inline void ARluCompGenEig:: +SetShiftInvertMode(arcomplex sigmap) +{ + + ARCompGenEig, ARFLOAT>, + ARdsNonSymPencil, ARFLOAT> >:: + SetShiftInvertMode(sigmap, &Pencil, + &ARdsNonSymPencil,ARFLOAT>::MultInvAsBv); + +} // SetShiftInvertMode. + + +template +inline ARluCompGenEig:: +ARluCompGenEig(int nevp, ARdsNonSymMatrix, ARFLOAT>& A, + ARdsNonSymMatrix, ARFLOAT>& B, const std::string& whichp, + int ncvp, ARFLOAT tolp, int maxitp, + arcomplex* residp, bool ishiftp) + +{ + + Pencil.DefineMatrices(A, B); + this->NoShift(); + this->DefineParameters(A.ncols(), nevp, &Pencil, + &ARdsNonSymPencil, ARFLOAT>::MultInvBAv, + &Pencil, + &ARdsNonSymPencil, ARFLOAT>::MultBv, + whichp, ncvp, tolp, maxitp, residp, ishiftp); + +} // Long constructor (regular mode). + + +template +inline ARluCompGenEig:: +ARluCompGenEig(int nevp, ARdsNonSymMatrix, ARFLOAT>& A, + ARdsNonSymMatrix, ARFLOAT>& B, + arcomplex sigmap, const std::string& whichp, int ncvp, + ARFLOAT tolp, int maxitp, arcomplex* residp, + bool ishiftp) + +{ + + Pencil.DefineMatrices(A, B); + this->DefineParameters(A.ncols(), nevp, &Pencil, + &ARdsNonSymPencil, ARFLOAT>::MultInvAsBv, + &Pencil, + &ARdsNonSymPencil, ARFLOAT>::MultBv, + whichp, ncvp, tolp, maxitp, residp, ishiftp); + SetShiftInvertMode(sigmap); + +} // Long constructor (shift and invert mode). + + +template +ARluCompGenEig& ARluCompGenEig:: +operator=(const ARluCompGenEig& other) +{ + + if (this != &other) { // Stroustrup suggestion. + this->ClearMem(); + Copy(other); + } + return *this; + +} // operator=. + + +#endif // ARDGCOMP_H diff --git a/external/arpack++/include/ardgnsym.h b/external/arpack++/include/ardgnsym.h new file mode 100644 index 000000000..ec9c60bd9 --- /dev/null +++ b/external/arpack++/include/ardgnsym.h @@ -0,0 +1,244 @@ +/* + ARPACK++ v1.2 2/20/2000 + c++ interface to ARPACK code. + + MODULE ARDGNSym.h. + Arpack++ class ARluNonSymGenEig definition + (dense matrix version). + + ARPACK Authors + Richard Lehoucq + Danny Sorensen + Chao Yang + Dept. of Computational & Applied Mathematics + Rice University + Houston, Texas +*/ + +#ifndef ARDGNSYM_H +#define ARDGNSYM_H + +#include +#include +#include "arch.h" +#include "ardnsmat.h" +#include "ardnspen.h" +#include "argnsym.h" + + +template +class ARluNonSymGenEig: + public virtual ARNonSymGenEig, + ARdsNonSymPencil > { + + private: + + // a) Data structure used to store matrices. + + ARdsNonSymPencil Pencil; + + // b) Protected functions: + + virtual void Copy(const ARluNonSymGenEig& other); + // Makes a deep copy of "other" over "this" object. + // Old values are not deleted (this function is to be used + // by the copy constructor and the assignment operator only). + + + public: + + // c) Public functions: + + // c.1) Functions that allow changes in problem parameters. + + virtual void ChangeShift(ARFLOAT sigmaRp, ARFLOAT sigmaIp = 0.0); + + virtual void SetRegularMode(); + + virtual void SetShiftInvertMode(ARFLOAT sigmap); + + virtual void SetComplexShiftMode(char partp, ARFLOAT sigmaRp,ARFLOAT sigmaIp); + + // c.2) Constructors and destructor. + + ARluNonSymGenEig() { } + // Short constructor. + + ARluNonSymGenEig(int nevp, ARdsNonSymMatrix& A, + ARdsNonSymMatrix& B, const std::string& whichp = "LM", + int ncvp = 0, ARFLOAT tolp = 0.0, int maxitp = 0, + ARFLOAT* residp = NULL, bool ishiftp = true); + // Long constructor (regular mode). + + ARluNonSymGenEig(int nevp, ARdsNonSymMatrix& A, + ARdsNonSymMatrix& B, ARFLOAT sigma, + const std::string& whichp = "LM", int ncvp = 0, + ARFLOAT tolp = 0.0, int maxitp = 0, + ARFLOAT* residp = NULL, bool ishiftp = true); + // Long constructor (real shift and invert mode). + + ARluNonSymGenEig(int nevp, ARdsNonSymMatrix& A, + ARdsNonSymMatrix& B, char partp, + ARFLOAT sigmaRp, ARFLOAT sigmaIp, const std::string& whichp = "LM", + int ncvp = 0, ARFLOAT tolp = 0.0, int maxitp = 0, + ARFLOAT* residp = NULL, bool ishiftp = true); + // Long constructor (complex shift and invert mode). + + ARluNonSymGenEig(const ARluNonSymGenEig& other) { Copy(other); } + // Copy constructor. + + virtual ~ARluNonSymGenEig() { } + // Destructor. + + // d) Operators. + + ARluNonSymGenEig& operator=(const ARluNonSymGenEig& other); + // Assignment operator. + +}; // class ARluNonSymGenEig. + + +// ------------------------------------------------------------------------ // +// ARluNonSymGenEig member functions definition. // +// ------------------------------------------------------------------------ // + + +template +inline void ARluNonSymGenEig:: +Copy(const ARluNonSymGenEig& other) +{ + + ARNonSymGenEig, + ARdsNonSymPencil >:: Copy(other); + Pencil = other.Pencil; + this->objOP = &Pencil; + this->objB = &Pencil; + this->objA = &Pencil; + +} // Copy. + + +template +inline void ARluNonSymGenEig:: +ChangeShift(ARFLOAT sigmaRp, ARFLOAT sigmaIp) +{ + + if (sigmaIp == 0.0) { + this->objOP->FactorAsB(sigmaRp); + } + else { + this->objOP->FactorAsB(sigmaRp, sigmaIp, this->part); + } + ARrcNonSymGenEig::ChangeShift(sigmaRp, sigmaIp); + +} // ChangeShift. + + +template +inline void ARluNonSymGenEig::SetRegularMode() +{ + + ARStdEig >:: + SetRegularMode(&Pencil, &ARdsNonSymPencil::MultInvBAv); + +} // SetRegularMode. + + +template +inline void ARluNonSymGenEig::SetShiftInvertMode(ARFLOAT sigmap) +{ + + ARNonSymGenEig, + ARdsNonSymPencil >:: + SetShiftInvertMode(sigmap, &Pencil, + &ARdsNonSymPencil::MultInvAsBv); + +} // SetShiftInvertMode. + + +template +inline void ARluNonSymGenEig:: +SetComplexShiftMode(char partp, ARFLOAT sigmaRp, ARFLOAT sigmaIp) +{ + + ARNonSymGenEig, + ARdsNonSymPencil >:: + SetComplexShiftMode(partp, sigmaRp, sigmaIp, &Pencil, + &ARdsNonSymPencil::MultInvAsBv, + &Pencil, &ARdsNonSymPencil::MultAv); + +} // SetComplexShiftMode. + + +template +inline ARluNonSymGenEig:: +ARluNonSymGenEig(int nevp, ARdsNonSymMatrix& A, + ARdsNonSymMatrix& B, const std::string& whichp, int ncvp, + ARFLOAT tolp, int maxitp, ARFLOAT* residp, bool ishiftp) + +{ + + Pencil.DefineMatrices(A, B); + this->NoShift(); + this->DefineParameters(A.ncols(), nevp, &Pencil, + &ARdsNonSymPencil::MultInvBAv, &Pencil, + &ARdsNonSymPencil::MultBv, whichp, + ncvp, tolp, maxitp, residp, ishiftp); + +} // Long constructor (regular mode). + + +template +inline ARluNonSymGenEig:: +ARluNonSymGenEig(int nevp, ARdsNonSymMatrix& A, + ARdsNonSymMatrix& B, ARFLOAT sigmap, + const std::string& whichp, int ncvp, ARFLOAT tolp, + int maxitp, ARFLOAT* residp, bool ishiftp) + +{ + + Pencil.DefineMatrices(A, B); + this->DefineParameters(A.ncols(), nevp, &Pencil, + &ARdsNonSymPencil::MultInvAsBv, &Pencil, + &ARdsNonSymPencil::MultBv, whichp, + ncvp, tolp, maxitp, residp, ishiftp); + SetShiftInvertMode(sigmap); + +} // Long constructor (real shift and invert mode). + + +template +inline ARluNonSymGenEig:: +ARluNonSymGenEig(int nevp, ARdsNonSymMatrix& A, + ARdsNonSymMatrix& B, + char partp, ARFLOAT sigmaRp, ARFLOAT sigmaIp, const std::string& whichp, + int ncvp, ARFLOAT tolp, int maxitp, ARFLOAT* residp, + bool ishiftp) + +{ + + Pencil.DefineMatrices(A, B); + this->DefineParameters(A.ncols(), nevp, &Pencil, + &ARdsNonSymPencil::MultInvAsBv, &Pencil, + &ARdsNonSymPencil::MultBv, whichp, + ncvp, tolp, maxitp, residp, ishiftp); + SetComplexShiftMode(partp, sigmaRp, sigmaIp); + +} // Long constructor (complex shift and invert mode). + + +template +ARluNonSymGenEig& ARluNonSymGenEig:: +operator=(const ARluNonSymGenEig& other) +{ + + if (this != &other) { // Stroustrup suggestion. + this->ClearMem(); + Copy(other); + } + return *this; + +} // operator=. + + +#endif // ARDGNSYM_H diff --git a/external/arpack++/include/ardgsym.h b/external/arpack++/include/ardgsym.h new file mode 100644 index 000000000..31600802b --- /dev/null +++ b/external/arpack++/include/ardgsym.h @@ -0,0 +1,233 @@ +/* + ARPACK++ v1.2 2/20/2000 + c++ interface to ARPACK code. + + MODULE ARDGSym.h. + Arpack++ class ARluSymGenEig definition + (dense matrix version). + + ARPACK Authors + Richard Lehoucq + Danny Sorensen + Chao Yang + Dept. of Computational & Applied Mathematics + Rice University + Houston, Texas +*/ + +#ifndef ARDGSYM_H +#define ARDGSYM_H + +#include +#include +#include "arch.h" +#include "ardsmat.h" +#include "ardspen.h" +#include "argsym.h" + + +template +class ARluSymGenEig: + public virtual ARSymGenEig, + ARdsSymPencil > { + + private: + + // a) Data structure used to store matrices. + + ARdsSymPencil Pencil; + + // b) Protected functions: + + virtual void Copy(const ARluSymGenEig& other); + // Makes a deep copy of "other" over "this" object. + // Old values are not deleted (this function is to be used + // by the copy constructor and the assignment operator only). + + + public: + + // c) Public functions: + + // c.1) Functions that allow changes in problem parameters. + + virtual void ChangeShift(ARFLOAT sigmap); + + virtual void SetRegularMode(); + + virtual void SetShiftInvertMode(ARFLOAT sigmap); + + virtual void SetBucklingMode(ARFLOAT sigmap); + + virtual void SetCayleyMode(ARFLOAT sigmap); + + // c.2) Constructors and destructor. + + ARluSymGenEig() { } + // Short constructor. + + ARluSymGenEig(int nevp, ARdsSymMatrix& A, + ARdsSymMatrix& B, const std::string& whichp = "LM", + int ncvp = 0, ARFLOAT tolp = 0.0, int maxitp = 0, + ARFLOAT* residp = NULL, bool ishiftp = true); + // Long constructor (regular mode). + + ARluSymGenEig(char InvertModep, int nevp, ARdsSymMatrix& A, + ARdsSymMatrix& B, ARFLOAT sigma, const std::string& whichp = "LM", + int ncvp = 0, ARFLOAT tolp = 0.0, int maxitp = 0, + ARFLOAT* residp = NULL, bool ishiftp = true); + // Long constructor (shift and invert, buckling and Cayley modes). + + ARluSymGenEig(const ARluSymGenEig& other) { Copy(other); } + // Copy constructor. + + virtual ~ARluSymGenEig() { } + // Destructor. + + // d) Operators. + + ARluSymGenEig& operator=(const ARluSymGenEig& other); + // Assignment operator. + +}; // class ARluSymGenEig. + + +// ------------------------------------------------------------------------ // +// ARluSymGenEig member functions definition. // +// ------------------------------------------------------------------------ // + + +template +inline void ARluSymGenEig:: +Copy(const ARluSymGenEig& other) +{ + + ARSymGenEig, + ARdsSymPencil >:: Copy(other); + Pencil = other.Pencil; + this->objOP = &Pencil; + this->objB = &Pencil; + this->objA = &Pencil; + +} // Copy. + + +template +inline void ARluSymGenEig::ChangeShift(ARFLOAT sigmap) +{ + + this->objOP->FactorAsB(sigmap); + ARrcSymGenEig::ChangeShift(sigmap); + +} // ChangeShift. + + +template +inline void ARluSymGenEig::SetRegularMode() +{ + + ARStdEig >:: + SetRegularMode(&Pencil, &ARdsSymPencil::MultInvBAv); + +} // SetRegularMode. + + +template +inline void ARluSymGenEig:: +SetShiftInvertMode(ARFLOAT sigmap) +{ + + ARSymGenEig, ARdsSymPencil >:: + SetShiftInvertMode(sigmap, &Pencil, &ARdsSymPencil::MultInvAsBv); + this->ChangeMultBx(&Pencil, &ARdsSymPencil::MultBv); + +} // SetShiftInvertMode. + + +template +inline void ARluSymGenEig:: +SetBucklingMode(ARFLOAT sigmap) +{ + + ARSymGenEig, ARdsSymPencil >:: + SetBucklingMode(sigmap, &Pencil, &ARdsSymPencil::MultInvAsBv); + this->ChangeMultBx(&Pencil, &ARdsSymPencil::MultAv); + +} // SetBucklingMode. + + +template +inline void ARluSymGenEig:: +SetCayleyMode(ARFLOAT sigmap) +{ + + ARSymGenEig, ARdsSymPencil >:: + SetCayleyMode(sigmap, &Pencil, &ARdsSymPencil::MultInvAsBv, + &Pencil, &ARdsSymPencil::MultAv); + this->ChangeMultBx(&Pencil, &ARdsSymPencil::MultBv); + +} // SetCayleyMode. + + +template +inline ARluSymGenEig:: +ARluSymGenEig(int nevp, ARdsSymMatrix& A, + ARdsSymMatrix& B, const std::string& whichp, int ncvp, + ARFLOAT tolp, int maxitp, ARFLOAT* residp, bool ishiftp) + +{ + + Pencil.DefineMatrices(A, B); + this->InvertMode = 'S'; + this->NoShift(); + this->DefineParameters(A.ncols(), nevp, &Pencil, + &ARdsSymPencil::MultInvBAv, &Pencil, + &ARdsSymPencil::MultBv, whichp, + ncvp, tolp, maxitp, residp, ishiftp); + +} // Long constructor (regular mode). + + +template +inline ARluSymGenEig:: +ARluSymGenEig(char InvertModep, int nevp, ARdsSymMatrix& A, + ARdsSymMatrix& B, ARFLOAT sigmap, + const std::string& whichp, int ncvp, ARFLOAT tolp, + int maxitp, ARFLOAT* residp, bool ishiftp) + +{ + + Pencil.DefineMatrices(A, B); + this->DefineParameters(A.ncols(), nevp, &Pencil, + &ARdsSymPencil::MultInvAsBv, &Pencil, + &ARdsSymPencil::MultBv, whichp, + ncvp, tolp, maxitp, residp, ishiftp); + this->InvertMode = this->CheckInvertMode(InvertModep); + switch (this->InvertMode) { + case 'B': + this->ChangeMultBx(&Pencil, &ARdsSymPencil::MultAv); + case 'S': + ChangeShift(sigmap); + break; + case 'C': + SetCayleyMode(sigmap); + } + +} // Long constructor (shift and invert, buckling and Cayley modes). + + +template +ARluSymGenEig& ARluSymGenEig:: +operator=(const ARluSymGenEig& other) +{ + + if (this != &other) { // Stroustrup suggestion. + this->ClearMem(); + Copy(other); + } + return *this; + +} // operator=. + + +#endif // ARDGSYM_H diff --git a/external/arpack++/include/ardnsmat.h b/external/arpack++/include/ardnsmat.h new file mode 100644 index 000000000..a2436b930 --- /dev/null +++ b/external/arpack++/include/ardnsmat.h @@ -0,0 +1,622 @@ +/* + ARPACK++ v1.2 2/20/2000 + c++ interface to ARPACK code. + + MODULE ARDNSMat.h. + Arpack++ class ARdsNonSymMatrix definition. + + ARPACK Authors + Richard Lehoucq + Danny Sorensen + Chao Yang + Dept. of Computational & Applied Mathematics + Rice University + Houston, Texas +*/ + + +#include "ardnspen.h" + +#ifndef ARDNSMAT_H +#define ARDNSMAT_H + +#include +#include +#include "arch.h" +#include "armat.h" +#include "arerror.h" +#include "blas1c.h" +#include "lapackc.h" +#include "ardfmat.h" + +template class ARdsNonSymPencil; + +template +class ARdsNonSymMatrix: public ARMatrix { + + friend class ARdsNonSymPencil; + friend class ARdsNonSymPencil; + + protected: + + bool factored; + int info; + int* ipiv; + ARTYPE* A; + ARTYPE* Ainv; + ARdfMatrix mat; + + void ClearMem(); + + virtual void Copy(const ARdsNonSymMatrix& other); + + void CreateStructure(); + + void ThrowError(); + + public: + + bool IsFactored() { return factored; } + + void FactorA(); + + void FactorAsI(ARTYPE sigma); + + void MultMv(ARTYPE* v, ARTYPE* w); + + void MultMtv(ARTYPE* v, ARTYPE* w); + + void MultMtMv(ARTYPE* v, ARTYPE* w); + + void MultMMtv(ARTYPE* v, ARTYPE* w); + + void Mult0MMt0v(ARTYPE* v, ARTYPE* w); + + void MultInvv(ARTYPE* v, ARTYPE* w); + + void DefineMatrix(int np, ARTYPE* Ap); + + void DefineMatrix(int mp, int np, ARTYPE* Ap); + + ARdsNonSymMatrix(): ARMatrix() { factored = false; } + // Short constructor that does nothing. + + ARdsNonSymMatrix(int np, ARTYPE* Ap); + // Long constructor (square matrix). + + ARdsNonSymMatrix(int mp, int np, ARTYPE* Ap); + // Long constructor (rectangular matrix). + + ARdsNonSymMatrix(const std::string& file, int blksizep = 0); + // Long constructor (Matrix stored in a file). + + ARdsNonSymMatrix(const ARdsNonSymMatrix& other) { Copy(other); } + // Copy constructor. + + virtual ~ARdsNonSymMatrix() { ClearMem(); } + // Destructor. + + ARdsNonSymMatrix& operator=(const ARdsNonSymMatrix& other); + // Assignment operator. + +}; + +// ------------------------------------------------------------------------ // +// ARdsNonSymMatrix member functions definition. // +// ------------------------------------------------------------------------ // + + +template +inline void ARdsNonSymMatrix::ClearMem() +{ + + if (factored) { + delete[] Ainv; + delete[] ipiv; + Ainv = NULL; + ipiv = NULL; + } + +} // ClearMem. + + +template +inline void ARdsNonSymMatrix:: +Copy(const ARdsNonSymMatrix& other) +{ + + // Copying very fundamental variables and user-defined parameters. + + this->m = other.m; + this->n = other.n; + this->defined = other.defined; + factored = other.factored; + info = other.info; + A = other.A; + + // Copying mat. + + if (other.mat.IsDefined()) { + mat.Define(other.mat.Filename(),other.mat.BlockSize()); + } + + // Returning from here if "other" was not factored. + + if (!factored) return; + + // Copying vectors. + + Ainv = new ARTYPE[this->m*this->n]; + ipiv = new int[this->n]; + + copy(this->m*this->n, other.Ainv, 1, Ainv, 1); + for (int i=0; in; i++) ipiv[i] = other.ipiv[i]; + +} // Copy. + + +template +inline void ARdsNonSymMatrix::CreateStructure() +{ + + ClearMem(); + Ainv = new ARTYPE[this->m*this->n]; + ipiv = new int[this->n]; + +} // CreateStructure. + + +template +inline void ARdsNonSymMatrix::ThrowError() +{ + + if (info < 0) { // Illegal argument. + throw ArpackError(ArpackError::PARAMETER_ERROR, + "ARdsNonSymMatrix::FactorA"); + } + else if (info) { // Matrix is singular. + throw ArpackError(ArpackError::MATRIX_IS_SINGULAR, + "ARdsNonSymMatrix::FactorA"); + } + +} // ThrowError. + + +template +void ARdsNonSymMatrix::FactorA() +{ + + // Quitting the function if A was not defined or is rectangular. + + if (!this->IsDefined()) { + throw ArpackError(ArpackError::DATA_UNDEFINED, "ARdsNonSymMatrix::FactorA"); + } + + if (this->m!=this->n) { + throw ArpackError(ArpackError::NOT_SQUARE_MATRIX, + "ARdsNonSymMatrix::FactorA"); + } + + if (mat.IsOutOfCore()) { + throw ArpackError(ArpackError::INSUFICIENT_MEMORY, + "ARdsNonSymMatrix::FactorA"); + } + + // Reserving memory for some vectors used in matrix decomposition. + + CreateStructure(); + + // Copying A to Ainv; + + ::copy(this->m*this->n, A, 1, Ainv, 1); + + // Decomposing A. + + getrf(this->m, this->n, Ainv, this->m, ipiv, info); + + // Handling errors. + + ThrowError(); + + factored = true; + +} // FactorA. + + +template +void ARdsNonSymMatrix::FactorAsI(ARTYPE sigma) +{ + + // Quitting the function if A was not defined or is rectangular. + + if (!this->IsDefined()) { + throw ArpackError(ArpackError::DATA_UNDEFINED, + "ARdsNonSymMatrix::FactorAsI"); + } + + if (this->m!=this->n) { + throw ArpackError(ArpackError::NOT_SQUARE_MATRIX, + "ARdsNonSymMatrix::FactorAsI"); + } + + if (mat.IsOutOfCore()) { + throw ArpackError(ArpackError::INSUFICIENT_MEMORY, + "ARdsNonSymMatrix::FactorAsI"); + } + + // Reserving memory for some vectors used in matrix decomposition. + + CreateStructure(); + + // Subtracting sigma*I from A. + + ::copy(this->m*this->n,A,1,Ainv,1); + for (int i=0; i<(this->m*this->n); i+=this->m+1) Ainv[i]-=sigma; + + // Decomposing AsI. + + getrf(this->m, this->n, Ainv, this->m, ipiv, info); + + // Handling errors. + + ThrowError(); + + factored = true; + +} // FactorAsI. + + +template +void ARdsNonSymMatrix::MultMv(ARTYPE* v, ARTYPE* w) +{ + + int i; + ARTYPE* t; + ARTYPE one; + ARTYPE zero; + + one = (ARTYPE)0 + 1.0; + zero = (ARTYPE)0; + + // Quitting the function if A was not defined. + + if (!this->IsDefined()) { + throw ArpackError(ArpackError::DATA_UNDEFINED, "ARdsNonSymMatrix::MultMv"); + } + + // Determining w = M.v. + + if (mat.IsOutOfCore()) { + + if (this->m>this->n) { + + // Matrix is "tall". + + mat.Rewind(); + for (i=0; in, one, mat.Entries(), + mat.RowsInMemory(), v, 1, zero, &w[mat.FirstIndex()], 1); + } + + } + else { + + // Matrix is "fat". + + mat.Rewind(); + t = new ARTYPE[mat.ColsInMemory()]; + for (i=0; im; i++) w[i] = zero; + for (i=0; im, mat.ColsInMemory(), one, mat.Entries(), + this->m, &v[mat.FirstIndex()], 1, zero, t, 1); + axpy(this->m, one, t, 1, w, 1); + } + delete[] t; + + } + + } + else { + + gemv("N", this->m, this->n, one, A, this->m, v, 1, zero, w, 1); + + } + +} // MultMv. + + +template +void ARdsNonSymMatrix::MultMtv(ARTYPE* v, ARTYPE* w) +{ + + int i; + ARTYPE* t; + ARTYPE one; + ARTYPE zero; + + one = (ARTYPE)0 + 1.0; + zero = (ARTYPE)0; + + // Quitting the function if A was not defined. + + if (!this->IsDefined()) { + throw ArpackError(ArpackError::DATA_UNDEFINED, "ARdsNonSymMatrix::MultMtv"); + } + + // Determining w = M'.v. + + if (mat.IsOutOfCore()) { + + if (this->m<=this->n) { + + // Matrix is "fat". + + mat.Rewind(); + for (i=0; im, mat.ColsInMemory(), one, mat.Entries(), + this->m, v, 1, zero, &w[mat.FirstIndex()], 1); + } + + } + else { + + // Matrix is "tall". + + mat.Rewind(); + t = new ARTYPE[mat.ColsInMemory()]; + for (i=0; im; i++) w[i] = zero; + for (i=0; in, one, mat.Entries(), + mat.RowsInMemory(), &v[mat.FirstIndex()], 1, zero, t, 1); + axpy(mat.RowsInMemory(), one, t, 1, w, 1); + } + delete[] t; + + } + + } + else { + + gemv("T", this->m, this->n, one, A, this->m, v, 1, zero, w, 1); + + } + + +} // MultMtv. + + +template +void ARdsNonSymMatrix::MultMtMv(ARTYPE* v, ARTYPE* w) +{ + + int i; + ARTYPE *t, *s; + ARTYPE one; + ARTYPE zero; + + one = (ARTYPE)0 + 1.0; + zero = (ARTYPE)0; + + if (mat.IsOutOfCore() && (this->m>this->n)) { + + // Special code for "tall" matrices. + + t = new ARTYPE[mat.BlockSize()]; + s = new ARTYPE[this->n]; + + mat.Rewind(); + for (i=0; in; i++) w[i] = zero; + for (i=0; in, one, mat.Entries(), + mat.RowsInMemory(), v, 1, zero, t, 1); + gemv("T", mat.RowsInMemory(), this->n, one, mat.Entries(), + mat.RowsInMemory(), t, 1, zero, s, 1); + axpy(this->n, one, s, 1, w, 1); + + } + + delete[] t; + delete[] s; + + } + else { + + t = new ARTYPE[this->m]; + + MultMv(v,t); + MultMtv(t,w); + + delete[] t; + + } + + +} // MultMtMv. + + +template +void ARdsNonSymMatrix::MultMMtv(ARTYPE* v, ARTYPE* w) +{ + + int i; + ARTYPE *t, *s; + ARTYPE one; + ARTYPE zero; + + one = (ARTYPE)0 + 1.0; + zero = (ARTYPE)0; + + if (mat.IsOutOfCore() && (this->m<=this->n)) { + + // Special code for "fat" matrices. + + t = new ARTYPE[mat.BlockSize()]; + s = new ARTYPE[this->m]; + + mat.Rewind(); + for (i=0; im; i++) w[i] = zero; + for (i=0; im, mat.ColsInMemory(), one, mat.Entries(), + this->m, v, 1, zero, t, 1); + gemv("N", this->m, mat.ColsInMemory(), one, mat.Entries(), + this->m, t, 1, zero, s, 1); + axpy(this->m, one, s, 1, w, 1); + + } + + delete[] t; + delete[] s; + + } + else { + + t = new ARTYPE[this->n]; + + MultMtv(v,t); + MultMv(t,w); + + delete[] t; + + } + +} // MultMMtv. + + +template +void ARdsNonSymMatrix::Mult0MMt0v(ARTYPE* v, ARTYPE* w) +{ + + MultMv(&v[this->m],w); + MultMtv(v,&w[this->m]); + +} // Mult0MMt0v. + + +template +void ARdsNonSymMatrix::MultInvv(ARTYPE* v, ARTYPE* w) +{ + + // Quitting the function if A (or AsI) was not factored. + + if (!IsFactored()) { + throw ArpackError(ArpackError::NOT_FACTORED_MATRIX, + "ARdsNonSymMatrix::MultInvv"); + } + + // Overwritting w with v. + + copy(this->n, v, 1, w, 1); + + // Solving A.w = v (or AsI.w = v). + + getrs("N", this->n, 1, Ainv, this->m, ipiv, w, this->m, info); + + // Handling errors. + + ThrowError(); + +} // MultInvv. + + +template +inline void ARdsNonSymMatrix:: +DefineMatrix(int np, ARTYPE* Ap) +{ + + // Defining member variables. + + this->n = np; + this->m = np; + A = Ap; + this->defined = true; + Ainv = NULL; + ipiv = NULL; + info = 0; + +} // DefineMatrix (square). + + +template +inline void ARdsNonSymMatrix:: +DefineMatrix(int mp, int np, ARTYPE* Ap) +{ + + // Defining member variables. + + this->m = mp; + this->n = np; + A = Ap; + this->defined = true; + Ainv = NULL; + ipiv = NULL; + info = 0; + +} // DefineMatrix (rectangular). + + +template +inline ARdsNonSymMatrix:: +ARdsNonSymMatrix(int np, ARTYPE* Ap) : ARMatrix(np) +{ + + factored = false; + DefineMatrix(np, Ap); + +} // Long constructor (square matrix). + + +template +inline ARdsNonSymMatrix:: +ARdsNonSymMatrix(int mp, int np, ARTYPE* Ap) : ARMatrix(mp, np) +{ + + factored = false; + DefineMatrix(mp, np, Ap); + +} // Long constructor (rectangular matrix). + + +template +ARdsNonSymMatrix::ARdsNonSymMatrix(const std::string& file, int blksizep) +{ + + factored = false; + + try { + mat.Define(file, blksizep); + } + catch (ArpackError) { // Returning from here if an error has occurred. + throw ArpackError(ArpackError::CANNOT_READ_FILE, "ARdsNonSymMatrix"); + } + + if (mat.NCols() == mat.NRows()) { + DefineMatrix(mat.NCols(), (ARTYPE*)mat.Entries()); + } + else { + DefineMatrix(mat.NRows(), mat.NCols(), (ARTYPE*)mat.Entries()); + } + +} // Long constructor (Matrix stored in a file). + + +template +ARdsNonSymMatrix& ARdsNonSymMatrix:: +operator=(const ARdsNonSymMatrix& other) +{ + + if (this != &other) { // Stroustrup suggestion. + ClearMem(); + Copy(other); + } + return *this; + +} // operator=. + + +#endif // ARDNSMAT_H diff --git a/external/arpack++/include/ardnspen.h b/external/arpack++/include/ardnspen.h new file mode 100644 index 000000000..04d2bd414 --- /dev/null +++ b/external/arpack++/include/ardnspen.h @@ -0,0 +1,324 @@ +/* + ARPACK++ v1.2 2/20/2000 + c++ interface to ARPACK code. + + MODULE ARDNSPen.h. + Arpack++ class ARdsNonSymPencil definition. + + ARPACK Authors + Richard Lehoucq + Danny Sorensen + Chao Yang + Dept. of Computational & Applied Mathematics + Rice University + Houston, Texas +*/ + +#ifndef ARDNSPEN_H +#define ARDNSPEN_H + +#include "arch.h" +#include "arerror.h" +#include "blas1c.h" +#include "lapackc.h" +#include "ardnsmat.h" + + +template +class ARdsNonSymPencil +{ + + protected: + + char part; + ARdsNonSymMatrix* A; + ARdsNonSymMatrix* B; + ARdsNonSymMatrix AsB; +#ifdef ARCOMP_H + ARdsNonSymMatrix, ARFLOAT> AsBc; +#endif + + virtual void Copy(const ARdsNonSymPencil& other); + + public: + +#ifdef ARCOMP_H + bool IsFactored() { return (AsB.IsFactored()||AsBc.IsFactored()); } +#else + bool IsFactored() { return AsB.IsFactored(); } +#endif + + void FactorAsB(ARTYPE sigma); + +#ifdef ARCOMP_H + void FactorAsB(ARFLOAT sigmaR, ARFLOAT sigmaI, char partp = 'R'); +#endif + + void MultAv(ARTYPE* v, ARTYPE* w) { A->MultMv(v,w); } + + void MultBv(ARTYPE* v, ARTYPE* w) { B->MultMv(v,w); } + + void MultInvBAv(ARTYPE* v, ARTYPE* w); + +#ifdef ARCOMP_H + void MultInvAsBv(arcomplex* v, arcomplex* w); +#endif + + void MultInvAsBv(ARFLOAT* v, ARFLOAT* w); + + void DefineMatrices(ARdsNonSymMatrix& Ap, + ARdsNonSymMatrix& Bp); + + ARdsNonSymPencil() { part = 'N'; } + // Short constructor that does nothing. + + ARdsNonSymPencil(ARdsNonSymMatrix& Ap, + ARdsNonSymMatrix& Bp); + // Long constructor. + + ARdsNonSymPencil(const ARdsNonSymPencil& other) { Copy(other); } + // Copy constructor. + + virtual ~ARdsNonSymPencil() { } + // Destructor. + + ARdsNonSymPencil& operator=(const ARdsNonSymPencil& other); + // Assignment operator. + +}; + +// ------------------------------------------------------------------------ // +// ARdsNonSymPencil member functions definition. // +// ------------------------------------------------------------------------ // + + +template +inline void ARdsNonSymPencil:: +Copy(const ARdsNonSymPencil& other) +{ + + part = other.part; + A = other.A; + B = other.B; + AsB = other.AsB; +#ifdef ARCOMP_H + AsBc = other.AsBc; +#endif + +} // Copy. + + +template +void ARdsNonSymPencil::FactorAsB(ARTYPE sigma) +{ + + // Quitting the function if A and B were not defined. + + if (!(A->IsDefined()&&B->IsDefined())) { + throw ArpackError(ArpackError::DATA_UNDEFINED, + "ARdsNonSymPencil::FactorAsB"); + } + + // Quitting the function if A and B are not square. + + if ((A->nrows() != A->ncols()) || (B->nrows() != B->ncols())) { + throw ArpackError(ArpackError::NOT_SQUARE_MATRIX, + "ARdsNonSymPencil::FactorAsB"); + } + + // Copying A to AsB if sigma = 0. + + if (sigma == (ARTYPE)0) { + + AsB = *A; + if (!AsB.IsFactored()) AsB.FactorA(); + return; + + } + + // Defining matrix AsB. + + if (!AsB.IsDefined()) { + AsB.DefineMatrix(A->ncols(), A->A); + } + + // Reserving memory for some vectors used in matrix decomposition. + + AsB.CreateStructure(); + + // Subtracting sigma*B from A and storing the result on AsB. + + ::copy(A->m*A->n, A->A, 1, AsB.Ainv, 1); + axpy(A->m*A->n, -sigma, B->A, 1, AsB.Ainv, 1); + + // Decomposing AsB. + + getrf(AsB.m, AsB.n, AsB.Ainv, AsB.m, AsB.ipiv, AsB.info); + + // Handling errors. + + AsB.ThrowError(); + + AsB.factored = true; + +} // FactorAsB (ARTYPE shift). + + +#ifdef ARCOMP_H +template +void ARdsNonSymPencil:: +FactorAsB(ARFLOAT sigmaR, ARFLOAT sigmaI, char partp) +{ + + // Quitting the function if A and B were not defined. + + if (!(A->IsDefined()&&B->IsDefined())) { + throw ArpackError(ArpackError::DATA_UNDEFINED, + "ARdsNonSymPencil::FactorAsB"); + } + + // Quitting the function if A and B are not square. + + if ((A->nrows() != A->ncols()) || (B->nrows() != B->ncols())) { + throw ArpackError(ArpackError::NOT_SQUARE_MATRIX, + "ARdsNonSymPencil::FactorAsB"); + } + + // Defining matrix AsB. + + if (!AsBc.IsDefined()) { + part = partp; + AsBc.DefineMatrix(A->ncols(), 0); + } + + // Reserving memory for some vectors used in matrix decomposition. + + AsBc.CreateStructure(); + + // Subtracting sigma*B from A and storing the result on AsBc. + + arcomplex sigma(sigmaR, sigmaI); + for (int i=0; i<(A->m*A->n); i++) AsBc.Ainv[i] = A->A[i]-sigma*B->A[i]; + + // Decomposing AsBc. + + getrf(AsBc.m, AsBc.n, AsBc.Ainv, AsBc.m, AsBc.ipiv, AsBc.info); + + // Handling errors. + + AsBc.ThrowError(); + + AsBc.factored = true; + +} // FactorAsB (arcomplex shift). +#endif // ARCOMP_H. + + +template +void ARdsNonSymPencil::MultInvBAv(ARTYPE* v, ARTYPE* w) +{ + + if (!B->IsFactored()) B->FactorA(); + + A->MultMv(v, w); + B->MultInvv(w, w); + +} // MultInvBAv. + + +#ifdef ARCOMP_H + +template +void ARdsNonSymPencil:: +MultInvAsBv(arcomplex* v, arcomplex* w) +{ + + AsB.MultInvv((ARTYPE*)v,(ARTYPE*)w); + +} // MultInvAsBv (arcomplex). + +#endif // ARCOMP_H. + + +template +void ARdsNonSymPencil::MultInvAsBv(ARFLOAT* v, ARFLOAT* w) +{ + + if (part == 'N') { // shift is real. + + AsB.MultInvv((ARTYPE*)v,(ARTYPE*)w); + + } + else { // shift is complex. + +#ifdef ARCOMP_H + + int i; + arcomplex *tv, *tw; + + tv = new arcomplex[AsBc.ncols()]; + tw = new arcomplex[AsBc.ncols()]; + + for (i=0; i!=AsBc.ncols(); i++) tv[i] = arcomplex(v[i], 0.0); + + AsBc.MultInvv(tv, tw); + + if (part=='I') { + for (i=0; i!=AsBc.ncols(); i++) w[i] = imag(tw[i]); + } + else { + for (i=0; i!=AsBc.ncols(); i++) w[i] = real(tw[i]); + } + + delete[] tv; + delete[] tw; + +#endif // ARCOMP_H. + + } + +} // MultInvAsBv (ARFLOAT). + + +template +inline void ARdsNonSymPencil:: +DefineMatrices(ARdsNonSymMatrix& Ap, + ARdsNonSymMatrix& Bp) +{ + + A = &Ap; + B = &Bp; + + if ((A->n != B->n)||(A->m != B->m)) { + throw ArpackError(ArpackError::INCOMPATIBLE_SIZES, + "ARdsNonSymMatrix::DefineMatrices"); + } + +} // DefineMatrices. + + +template +inline ARdsNonSymPencil:: +ARdsNonSymPencil(ARdsNonSymMatrix& Ap, + ARdsNonSymMatrix& Bp) +{ + + DefineMatrices(Ap, Bp); + +} // Long constructor. + + +template +ARdsNonSymPencil& ARdsNonSymPencil:: +operator=(const ARdsNonSymPencil& other) +{ + + if (this != &other) { // Stroustrup suggestion. + Copy(other); + } + return *this; + +} // operator=. + + +#endif // ARDNSPEN_H diff --git a/external/arpack++/include/ardscomp.h b/external/arpack++/include/ardscomp.h new file mode 100644 index 000000000..094f5840e --- /dev/null +++ b/external/arpack++/include/ardscomp.h @@ -0,0 +1,166 @@ +/* + ARPACK++ v1.2 2/20/2000 + c++ interface to ARPACK code. + + MODULE ARDSComp.h. + Arpack++ class ARluCompStdEig definition + (dense matrix version). + + ARPACK Authors + Richard Lehoucq + Danny Sorensen + Chao Yang + Dept. of Computational & Applied Mathematics + Rice University + Houston, Texas +*/ + +#ifndef ARDSCOMP_H +#define ARDSCOMP_H + +#include +#include +#include "arch.h" +#include "arscomp.h" +#include "ardnsmat.h" +#include "arrseig.h" + + +template +class ARluCompStdEig: + public virtual ARCompStdEig, ARFLOAT> > { + + public: + + // a) Public functions: + + // a.1) Functions that allow changes in problem parameters. + + virtual void ChangeShift(arcomplex sigmaRp); + + virtual void SetRegularMode(); + + virtual void SetShiftInvertMode(arcomplex sigmap); + + // a.2) Constructors and destructor. + + ARluCompStdEig() { } + // Short constructor. + + ARluCompStdEig(int nevp, ARdsNonSymMatrix, ARFLOAT>& A, + const std::string& whichp = "LM", int ncvp = 0, + ARFLOAT tolp = 0.0, int maxitp = 0, + arcomplex* residp = NULL, bool ishiftp = true); + // Long constructor (regular mode). + + ARluCompStdEig(int nevp, ARdsNonSymMatrix, ARFLOAT>& A, + arcomplex sigma, const std::string& whichp = "LM", + int ncvp = 0, ARFLOAT tolp = 0.0, int maxitp = 0, + arcomplex* residp = NULL, bool ishiftp = true); + // Long constructor (shift and invert mode). + + ARluCompStdEig(const ARluCompStdEig& other) { Copy(other); } + // Copy constructor. + + virtual ~ARluCompStdEig() { } + // Destructor. + + + // b) Operators. + + ARluCompStdEig& operator=(const ARluCompStdEig& other); + // Assignment operator. + +}; // class ARluCompStdEig. + + +// ------------------------------------------------------------------------ // +// ARluCompStdEig member functions definition. // +// ------------------------------------------------------------------------ // + + +template +inline void ARluCompStdEig:: +ChangeShift(arcomplex sigmaRp) +{ + + this->objOP->FactorAsI(sigmaRp); + ARrcStdEig >::ChangeShift(sigmaRp); + +} // ChangeShift. + + +template +inline void ARluCompStdEig::SetRegularMode() +{ + + ARStdEig, + ARdsNonSymMatrix, ARFLOAT> >:: + SetRegularMode(this->objOP, + &ARdsNonSymMatrix, ARFLOAT>::MultMv); + +} // SetRegularMode. + + +template +inline void ARluCompStdEig:: +SetShiftInvertMode(arcomplex sigmap) +{ + + ARStdEig, + ARdsNonSymMatrix, ARFLOAT> >:: + SetShiftInvertMode(sigmap, this->objOP, + &ARdsNonSymMatrix,ARFLOAT>::MultInvv); + +} // SetShiftInvertMode. + + +template +inline ARluCompStdEig:: +ARluCompStdEig(int nevp, ARdsNonSymMatrix, ARFLOAT>& A, + const std::string& whichp, int ncvp, ARFLOAT tolp, + int maxitp, arcomplex* residp, bool ishiftp) + +{ + + this->NoShift(); + this->DefineParameters(A.ncols(), nevp, &A, + &ARdsNonSymMatrix, ARFLOAT>::MultMv, + whichp, ncvp, tolp, maxitp, residp, ishiftp); + +} // Long constructor (regular mode). + + +template +inline ARluCompStdEig:: +ARluCompStdEig(int nevp, ARdsNonSymMatrix, ARFLOAT>& A, + arcomplex sigmap, const std::string& whichp, int ncvp, + ARFLOAT tolp, int maxitp, arcomplex* residp, + bool ishiftp) + +{ + + this->DefineParameters(A.ncols(), nevp, &A, + &ARdsNonSymMatrix, ARFLOAT>::MultInvv, + whichp, ncvp, tolp, maxitp, residp, ishiftp); + ChangeShift(sigmap); + +} // Long constructor (shift and invert mode). + + +template +ARluCompStdEig& ARluCompStdEig:: +operator=(const ARluCompStdEig& other) +{ + + if (this != &other) { // Stroustrup suggestion. + this->ClearMem(); + Copy(other); + } + return *this; + +} // operator=. + + +#endif // ARDSCOMP_H diff --git a/external/arpack++/include/ardsmat.h b/external/arpack++/include/ardsmat.h new file mode 100644 index 000000000..1b16ae231 --- /dev/null +++ b/external/arpack++/include/ardsmat.h @@ -0,0 +1,357 @@ +/* + ARPACK++ v1.2 2/20/2000 + c++ interface to ARPACK code. + + MODULE ARDSMat.h. + Arpack++ class ARdsSymMatrix definition. + + ARPACK Authors + Richard Lehoucq + Danny Sorensen + Chao Yang + Dept. of Computational & Applied Mathematics + Rice University + Houston, Texas +*/ + + +#include "ardspen.h" + +#ifndef ARDSMAT_H +#define ARDSMAT_H + +#include + +#include "arch.h" +#include "armat.h" +#include "arerror.h" +#include "blas1c.h" +#include "lapackc.h" + +template class ARdsSymPencil; + +template +class ARdsSymMatrix: public ARMatrix { + + friend class ARdsSymPencil; + + protected: + + bool factored; + char uplo; + int info; + int* ipiv; + ARTYPE* A; + ARTYPE* Ainv; + + void ClearMem(); + + virtual void Copy(const ARdsSymMatrix& other); + + void SubtractAsI(ARTYPE sigma); + + void CreateStructure(); + + void ThrowError(); + + public: + + bool IsFactored() { return factored; } + + void FactorA(); + + void FactorAsI(ARTYPE sigma); + + void MultMv(ARTYPE* v, ARTYPE* w); + + void MultInvv(ARTYPE* v, ARTYPE* w); + + void DefineMatrix(int np, ARTYPE* Ap, char uplop = 'L'); + + ARdsSymMatrix(): ARMatrix() { factored = false; } + // Short constructor that does nothing. + + ARdsSymMatrix(int np, ARTYPE* Ap, char uplop = 'L'); + // Long constructor. + + ARdsSymMatrix(const ARdsSymMatrix& other) { Copy(other); } + // Copy constructor. + + virtual ~ARdsSymMatrix() { ClearMem(); } + // Destructor. + + ARdsSymMatrix& operator=(const ARdsSymMatrix& other); + // Assignment operator. + +}; + +// ------------------------------------------------------------------------ // +// ARdsSymMatrix member functions definition. // +// ------------------------------------------------------------------------ // + + +template +inline void ARdsSymMatrix::ClearMem() +{ + + if (factored) { + delete[] Ainv; + delete[] ipiv; + Ainv = NULL; + ipiv = NULL; + } + +} // ClearMem. + + +template +inline void ARdsSymMatrix:: +Copy(const ARdsSymMatrix& other) +{ + + // Copying very fundamental variables and user-defined parameters. + + this->m = other.m; + this->n = other.n; + this->defined = other.defined; + factored = other.factored; + uplo = other.uplo; + info = other.info; + A = other.A; + + // Returning from here if "other" was not factored. + + if (!factored) return; + + // Copying vectors. + + Ainv = new ARTYPE[(this->n*this->n+this->n)/2]; + ipiv = new int[this->n]; + + copy((this->n*this->n+this->n)/2, other.Ainv, 1, Ainv, 1); + for (int i=0; in; i++) ipiv[i] = other.ipiv[i]; + +} // Copy. + + +template +void ARdsSymMatrix::SubtractAsI(ARTYPE sigma) +{ + + int i,j; + + // Copying A to Ainv. + + ::copy((this->n*this->n+this->n)/2 ,A, 1, Ainv, 1); + + // Subtracting sigma from diagonal elements. + + if (uplo=='L') { + for (i=0, j=0; in; j+=(this->n-(i++))) Ainv[j] -= sigma; + } + else { + for (i=0, j=0; in; j+=(++i)) Ainv[j] -= sigma; + } + +} // SubtractAsI. + + +template +inline void ARdsSymMatrix::CreateStructure() +{ + + ClearMem(); + Ainv = new ARTYPE[(this->n*this->n+this->n)/2]; + ipiv = new int[this->n]; + +} // CreateStructure. + + +template +inline void ARdsSymMatrix::ThrowError() +{ + + if (info < 0) { // Illegal argument. + throw ArpackError(ArpackError::PARAMETER_ERROR, + "ARdsSymMatrix::FactorA"); + } + else if (info) { // Matrix is singular. + throw ArpackError(ArpackError::MATRIX_IS_SINGULAR, + "ARdsSymMatrix::FactorA"); + } + +} // ThrowError. + + +template +void ARdsSymMatrix::FactorA() +{ + + // Quitting the function if A was not defined. + + if (!this->IsDefined()) { + throw ArpackError(ArpackError::DATA_UNDEFINED, "ARdsSymMatrix::FactorA"); + } + + // Reserving memory for some vectors used in matrix decomposition. + + CreateStructure(); + + // Copying A to Ainv; + + ::copy((this->n*this->n+this->n)/2 ,A, 1, Ainv, 1); + + // Decomposing A. + + sptrf(&uplo, this->n, Ainv, ipiv, info); + + // Handling errors. + + ThrowError(); + + factored = true; + +} // FactorA. + + +template +void ARdsSymMatrix::FactorAsI(ARTYPE sigma) +{ + + // Quitting the function if A was not defined. + + if (!this->IsDefined()) { + throw ArpackError(ArpackError::DATA_UNDEFINED, "ARdsSymMatrix::FactorAsI"); + } + + // Reserving memory for some vectors used in matrix decomposition. + + CreateStructure(); + + // Subtracting sigma*I from A. + + SubtractAsI(sigma); + + // Decomposing AsI. + + sptrf(&uplo, this->n, Ainv, ipiv, info); + + // Handling errors. + + ThrowError(); + + factored = true; + +} // FactorAsI. + + +template +void ARdsSymMatrix::MultMv(ARTYPE* v, ARTYPE* w) +{ + + int i, j; + + ARTYPE zero = (ARTYPE)0; + + // Quitting the function if A was not defined. + + if (!this->IsDefined()) { + throw ArpackError(ArpackError::DATA_UNDEFINED, "ARdsSymMatrix::MultMv"); + } + + // Determining w = M.v (unfortunately, the BLAS does not + // have a routine that works with packed matrices). + + for (i=0; in; i++) w[i] = zero; + + if (uplo=='L') { + + for (i=0, j=0; in; j+=(this->n-(i++))) { + w[i] += dot(this->n-i, &A[j], 1, &v[i], 1); + axpy(this->n-i-1, v[i], &A[j+1], 1, &w[i+1], 1); + } + + } + else { // uplo = 'U' + + for (i=0, j=0; in; j+=(++i)) { + w[i] += dot(i+1, &A[j], 1, v, 1); + axpy(i, v[i], &A[j], 1, w, 1); + } + + } + +} // MultMv. + + +template +void ARdsSymMatrix::MultInvv(ARTYPE* v, ARTYPE* w) +{ + + // Quitting the function if A (or AsI) was not factored. + + if (!IsFactored()) { + throw ArpackError(ArpackError::NOT_FACTORED_MATRIX, + "ARdsSymMatrix::MultInvv"); + } + + // Overwritting w with v. + + copy(this->n, v, 1, w, 1); + + // Solving A.w = v (or AsI.w = v). + + sptrs(&uplo, this->n, 1, Ainv, ipiv, w, this->n, info); + + // Handling errors. + + ThrowError(); + +} // MultInvv. + + +template +inline void ARdsSymMatrix:: +DefineMatrix(int np, ARTYPE* Ap, char uplop) +{ + + // Defining member variables. + + this->m = np; + this->n = np; + uplo = uplop; + A = Ap; + this->defined = true; + Ainv = NULL; + ipiv = NULL; + info = 0; + +} // DefineMatrix. + + +template +inline ARdsSymMatrix:: +ARdsSymMatrix(int np, ARTYPE* Ap, char uplop) : ARMatrix(np) +{ + + factored = false; + DefineMatrix(np, Ap, uplop); + +} // Long constructor. + + +template +ARdsSymMatrix& ARdsSymMatrix:: +operator=(const ARdsSymMatrix& other) +{ + + if (this != &other) { // Stroustrup suggestion. + this->ClearMem(); + Copy(other); + } + return *this; + +} // operator=. + + +#endif // ARDSMAT_H diff --git a/external/arpack++/include/ardsnsym.h b/external/arpack++/include/ardsnsym.h new file mode 100644 index 000000000..fc2afe263 --- /dev/null +++ b/external/arpack++/include/ardsnsym.h @@ -0,0 +1,163 @@ +/* + ARPACK++ v1.2 2/20/2000 + c++ interface to ARPACK code. + + MODULE ARDSNSym.h. + Arpack++ class ARluNonSymStdEig definition + (dense matrix version). + + ARPACK Authors + Richard Lehoucq + Danny Sorensen + Chao Yang + Dept. of Computational & Applied Mathematics + Rice University + Houston, Texas +*/ + +#ifndef ARDSNSYM_H +#define ARDSNSYM_H + +#include +#include +#include "arch.h" +#include "arsnsym.h" +#include "ardnsmat.h" + + +template +class ARluNonSymStdEig: + public virtual ARNonSymStdEig > { + + public: + + // a) Public functions: + + // a.1) Functions that allow changes in problem parameters. + + virtual void ChangeShift(ARFLOAT sigmaRp); + + virtual void SetRegularMode(); + + virtual void SetShiftInvertMode(ARFLOAT sigmap); + + // a.2) Constructors and destructor. + + ARluNonSymStdEig() { } + // Short constructor. + + ARluNonSymStdEig(int nevp, ARdsNonSymMatrix& A, + const std::string& whichp = "LM", int ncvp = 0, + ARFLOAT tolp = 0.0, int maxitp = 0, + ARFLOAT* residp = NULL, bool ishiftp = true); + // Long constructor (regular mode). + + ARluNonSymStdEig(int nevp, ARdsNonSymMatrix& A, + ARFLOAT sigma, const std::string& whichp = "LM", int ncvp = 0, + ARFLOAT tolp = 0.0, int maxitp = 0, + ARFLOAT* residp = NULL, bool ishiftp = true); + // Long constructor (shift and invert mode). + + ARluNonSymStdEig(const ARluNonSymStdEig& other) { Copy(other); } + // Copy constructor. + + virtual ~ARluNonSymStdEig() { } + // Destructor. + + // b) Operators. + + ARluNonSymStdEig& operator=(const ARluNonSymStdEig& other); + // Assignment operator. + +}; // class ARluNonSymStdEig. + + +// ------------------------------------------------------------------------ // +// ARluNonSymStdEig member functions definition. // +// ------------------------------------------------------------------------ // + + +template +inline void ARluNonSymStdEig:: +ChangeShift(ARFLOAT sigmaRp) +{ + + this->sigmaR = sigmaRp; + this->sigmaI = 0.0; + this->mode = 3; + this->iparam[7] = this->mode; + + this->objOP->FactorAsI(this->sigmaR); + this->Restart(); + +} // ChangeShift. + + +template +inline void ARluNonSymStdEig::SetRegularMode() +{ + + ARStdEig >:: + SetRegularMode(this->objOP, &ARdsNonSymMatrix::MultMv); + +} // SetRegularMode. + + +template +inline void ARluNonSymStdEig::SetShiftInvertMode(ARFLOAT sigmap) +{ + + ARStdEig >:: + SetShiftInvertMode(sigmap, this->objOP, + &ARdsNonSymMatrix::MultInvv); + +} // SetShiftInvertMode. + + +template +inline ARluNonSymStdEig:: +ARluNonSymStdEig(int nevp, ARdsNonSymMatrix& A, + const std::string& whichp, int ncvp, ARFLOAT tolp, + int maxitp, ARFLOAT* residp, bool ishiftp) + +{ + + this->NoShift(); + this->DefineParameters(A.ncols(), nevp, &A, + &ARdsNonSymMatrix::MultMv, + whichp, ncvp, tolp, maxitp, residp, ishiftp); + +} // Long constructor (regular mode). + + +template +inline ARluNonSymStdEig:: +ARluNonSymStdEig(int nevp, ARdsNonSymMatrix& A, + ARFLOAT sigmap, const std::string& whichp, int ncvp, ARFLOAT tolp, + int maxitp, ARFLOAT* residp, bool ishiftp) + +{ + + this->DefineParameters(A.ncols(), nevp, &A, + &ARdsNonSymMatrix::MultInvv, + whichp, ncvp, tolp, maxitp, residp, ishiftp); + ChangeShift(sigmap); + +} // Long constructor (shift and invert mode). + + +template +ARluNonSymStdEig& ARluNonSymStdEig:: +operator=(const ARluNonSymStdEig& other) +{ + + if (this != &other) { // Stroustrup suggestion. + this->ClearMem(); + Copy(other); + } + return *this; + +} // operator=. + + +#endif // ARDSNSYM_H diff --git a/external/arpack++/include/ardspen.h b/external/arpack++/include/ardspen.h new file mode 100644 index 000000000..4e16b82b1 --- /dev/null +++ b/external/arpack++/include/ardspen.h @@ -0,0 +1,237 @@ +/* + ARPACK++ v1.2 2/20/2000 + c++ interface to ARPACK code. + + MODULE ARDSPen.h. + Arpack++ class ARdsSymPencil definition. + + ARPACK Authors + Richard Lehoucq + Danny Sorensen + Chao Yang + Dept. of Computational & Applied Mathematics + Rice University + Houston, Texas +*/ + +#ifndef ARDSPEN_H +#define ARDSPEN_H + +#include "arch.h" +#include "arerror.h" +#include "blas1c.h" +#include "lapackc.h" +#include "ardsmat.h" + + +template +class ARdsSymPencil +{ + + protected: + + ARdsSymMatrix* A; + ARdsSymMatrix* B; + ARdsSymMatrix AsB; + + virtual void Copy(const ARdsSymPencil& other); + + void SubtractAsB(ARTYPE sigma); + + public: + + bool IsFactored() { return AsB.IsFactored(); } + + void FactorAsB(ARTYPE sigma); + + void MultAv(ARTYPE* v, ARTYPE* w) { A->MultMv(v,w); } + + void MultBv(ARTYPE* v, ARTYPE* w) { B->MultMv(v,w); } + + void MultInvBAv(ARTYPE* v, ARTYPE* w); + + void MultInvAsBv(ARTYPE* v, ARTYPE* w) { AsB.MultInvv(v,w); } + + void DefineMatrices(ARdsSymMatrix& Ap, ARdsSymMatrix& Bp); + + ARdsSymPencil() { AsB.factored = false; } + // Short constructor that does nothing. + + ARdsSymPencil(ARdsSymMatrix& Ap, ARdsSymMatrix& Bp); + // Long constructor. + + ARdsSymPencil(const ARdsSymPencil& other) { Copy(other); } + // Copy constructor. + + virtual ~ARdsSymPencil() { } + // Destructor. + + ARdsSymPencil& operator=(const ARdsSymPencil& other); + // Assignment operator. + +}; + +// ------------------------------------------------------------------------ // +// ARdsSymPencil member functions definition. // +// ------------------------------------------------------------------------ // + + +template +inline void ARdsSymPencil::Copy(const ARdsSymPencil& other) +{ + + A = other.A; + B = other.B; + AsB = other.AsB; + +} // Copy. + + +template +void ARdsSymPencil::SubtractAsB(ARTYPE sigma) +{ + + int sizeA, i, j, k, l; + + // Copying A into AsB. + + sizeA = (A->ncols()*A->ncols()+A->ncols())/2; + ::copy(sizeA, A->A, 1, AsB.Ainv, 1); + + // Returning if sigma == 0. + + if (sigma == (ARTYPE)0) return; + + // Subtracting sigma*B. + + if (A->uplo == B->uplo) { + + axpy(sizeA, -sigma, B->A, 1, AsB.Ainv, 1); + + } + else if (A->uplo == 'L') { // B->uplo == 'U' + + j = 0; + for (i=0; in; i++) { + for (l=i+1, k=(l*l+l)/2-1; l<=A->n; k+=(l++)) { + AsB.Ainv[j++]-=sigma*B->A[k]; + } + } + + } + else { // A->uplo == 'U' && B->uplo == 'L' + + j = 0; + for (i=0; in; i++) { + for (l=i+1, k=(l*l+l)/2-1; l<=A->n; k+=(l++)) { + AsB.Ainv[k]-=sigma*B->A[j++]; + } + } + + } + +} // SubtractAsB (ARTYPE shift). + + +template +void ARdsSymPencil::FactorAsB(ARTYPE sigma) +{ + + // Quitting the function if A and B were not defined. + + if (!(A->IsDefined()&&B->IsDefined())) { + throw ArpackError(ArpackError::DATA_UNDEFINED, + "ARdsSymPencil::FactorAsB"); + } + + // Copying A to AsB if sigma = 0. + + if (sigma == (ARTYPE)0) { + + AsB = *A; + if (!AsB.IsFactored()) AsB.FactorA(); + return; + + } + + // Defining matrix AsB. + + if (!AsB.IsDefined()) { + AsB.DefineMatrix(A->ncols(), A->A, A->uplo); + } + + // Reserving memory for some vectors used in matrix decomposition. + + AsB.CreateStructure(); + + // Subtracting sigma*B from A and storing the result on AsB. + + SubtractAsB(sigma); + + // Decomposing AsB. + + sptrf(&AsB.uplo, AsB.n, AsB.Ainv, AsB.ipiv, AsB.info); + + // Handling errors. + + AsB.ThrowError(); + + AsB.factored = true; + +} // FactorAsB (ARTYPE shift). + + +template +void ARdsSymPencil::MultInvBAv(ARTYPE* v, ARTYPE* w) +{ + + if (!B->IsFactored()) B->FactorA(); + + A->MultMv(v, w); + copy(A->ncols(), w, 1, v, 1); + B->MultInvv(w, w); + +} // MultInvBAv. + + +template +inline void ARdsSymPencil:: +DefineMatrices(ARdsSymMatrix& Ap, ARdsSymMatrix& Bp) +{ + + A = &Ap; + B = &Bp; + + if ((A->n != B->n)||(A->m != B->m)) { + throw ArpackError(ArpackError::INCOMPATIBLE_SIZES, + "ARdsNonSymMatrix::DefineMatrices"); + } + +} // DefineMatrices. + + +template +inline ARdsSymPencil:: +ARdsSymPencil(ARdsSymMatrix& Ap, ARdsSymMatrix& Bp) +{ + + AsB.factored = false; + DefineMatrices(Ap, Bp); + +} // Long constructor. + + +template +ARdsSymPencil& ARdsSymPencil:: +operator=(const ARdsSymPencil& other) +{ + + if (this != &other) { // Stroustrup suggestion. + Copy(other); + } + return *this; + +} // operator=. + + +#endif // ARDSPEN_H diff --git a/external/arpack++/include/ardssym.h b/external/arpack++/include/ardssym.h new file mode 100644 index 000000000..faee78550 --- /dev/null +++ b/external/arpack++/include/ardssym.h @@ -0,0 +1,159 @@ +/* + ARPACK++ v1.2 2/20/2000 + c++ interface to ARPACK code. + + MODULE ARDSSym.h. + Arpack++ class ARluSymStdEig definition + (dense matrix version). + + ARPACK Authors + Richard Lehoucq + Danny Sorensen + Chao Yang + Dept. of Computational & Applied Mathematics + Rice University + Houston, Texas +*/ + +#ifndef ARDSSYM_H +#define ARDSSYM_H + +#include +#include +#include "arch.h" +#include "arssym.h" +#include "ardsmat.h" + + +template +class ARluSymStdEig: + public virtual ARSymStdEig > { + + public: + + // a) Public functions: + + // a.1) Functions that allow changes in problem parameters. + + virtual void ChangeShift(ARFLOAT sigmaRp); + + virtual void SetRegularMode(); + + virtual void SetShiftInvertMode(ARFLOAT sigmap); + + // a.2) Constructors and destructor. + + ARluSymStdEig() { } + // Short constructor. + + ARluSymStdEig(int nevp, ARdsSymMatrix& A, + const std::string& whichp = "LM", int ncvp = 0, + ARFLOAT tolp = 0.0, int maxitp = 0, + ARFLOAT* residp = NULL, bool ishiftp = true); + // Long constructor (regular mode). + + ARluSymStdEig(int nevp, ARdsSymMatrix& A, + ARFLOAT sigma, const std::string& whichp = "LM", int ncvp = 0, + ARFLOAT tolp = 0.0, int maxitp = 0, + ARFLOAT* residp = NULL, bool ishiftp = true); + // Long constructor (shift and invert mode). + + ARluSymStdEig(const ARluSymStdEig& other) { Copy(other); } + // Copy constructor. + + virtual ~ARluSymStdEig() { } + // Destructor. + + // b) Operators. + + ARluSymStdEig& operator=(const ARluSymStdEig& other); + // Assignment operator. + +}; // class ARluSymStdEig. + + +// ------------------------------------------------------------------------ // +// ARluSymStdEig member functions definition. // +// ------------------------------------------------------------------------ // + + +template +inline void ARluSymStdEig:: +ChangeShift(ARFLOAT sigmaRp) +{ + + this->sigmaR = sigmaRp; + this->sigmaI = 0.0; + this->mode = 3; + this->iparam[7] = this->mode; + + this->objOP->FactorAsI(this->sigmaR); + this->Restart(); + +} // ChangeShift. + + +template +inline void ARluSymStdEig::SetRegularMode() +{ + + ARStdEig >:: + SetRegularMode(this->objOP, &ARdsSymMatrix::MultMv); + +} // SetRegularMode. + + +template +inline void ARluSymStdEig::SetShiftInvertMode(ARFLOAT sigmap) +{ + + ARStdEig >:: + SetShiftInvertMode(sigmap, this->objOP, &ARdsSymMatrix::MultInvv); + +} // SetShiftInvertMode. + + +template +inline ARluSymStdEig:: +ARluSymStdEig(int nevp, ARdsSymMatrix& A, + const std::string& whichp, int ncvp, ARFLOAT tolp, + int maxitp, ARFLOAT* residp, bool ishiftp) +{ + + this->NoShift(); + this->DefineParameters(A.ncols(), nevp, &A, &ARdsSymMatrix::MultMv, + whichp, ncvp, tolp, maxitp, residp, ishiftp); + +} // Long constructor (regular mode). + + +template +inline ARluSymStdEig:: +ARluSymStdEig(int nevp, ARdsSymMatrix& A, + ARFLOAT sigmap, const std::string& whichp, int ncvp, ARFLOAT tolp, + int maxitp, ARFLOAT* residp, bool ishiftp) + +{ + + this->DefineParameters(A.ncols(), nevp, &A, &ARdsSymMatrix::MultInvv, + whichp, ncvp, tolp, maxitp, residp, ishiftp); + ChangeShift(sigmap); + +} // Long constructor (shift and invert mode). + + +template +ARluSymStdEig& ARluSymStdEig:: +operator=(const ARluSymStdEig& other) +{ + + if (this != &other) { // Stroustrup suggestion. + this->ClearMem(); + Copy(other); + } + return *this; + +} // operator=. + + +#endif // ARDSSYM_H diff --git a/external/arpack++/include/arerror.h b/external/arpack++/include/arerror.h new file mode 100644 index 000000000..6f96b479d --- /dev/null +++ b/external/arpack++/include/arerror.h @@ -0,0 +1,348 @@ +/* + ARPACK++ v1.2 2/20/2000 + c++ interface to ARPACK code. + + MODULE ARError.h. + Definition of ArpackError, a class that handles errors + occurred during Arpack execution. + + There are three ways of handling an error: + a) Declaring a variable of type ArpackError and calling + function Set with the correct ErrorCode (see codes below). + b) Calling the constructor ArpackError(ErrorCode) to define + a variable. + c) Calling ArpackError::Set(ErrorCode) directly. + + If an error occurs, a brief description of the error is + displayed on the "cerr" stream, unless the variable + ARPACK_SILENT_MODE is defined. + + ARPACK Authors + Richard Lehoucq + Danny Sorensen + Chao Yang + Dept. of Computational & Applied Mathematics + Rice University + Houston, Texas +*/ + +#ifndef ARERROR_H +#define ARERROR_H + +#include +#include +#include + +//#include "arch.h" + +template< typename T > +struct ArpackError_static +{ + public: + + enum ErrorCode { // Listing all kinds of errors. + + // Innocuous error type. + + NO_ERRORS = 0, + + // Errors in parameter definitions. + + PARAMETER_ERROR = -101, + N_SMALLER_THAN_2 = -102, + NEV_OUT_OF_BOUNDS = -103, + WHICH_UNDEFINED = -104, + PART_UNDEFINED = -105, + INVMODE_UNDEFINED = -106, + RANGE_ERROR = -107, + + // Errors in Aupp and Eupp functions. + + LAPACK_ERROR = -201, + START_RESID_ZERO = -202, + NOT_ACCURATE_EIG = -203, + REORDERING_ERROR = -204, + ARNOLDI_NOT_BUILD = -205, + AUPP_ERROR = -291, + EUPP_ERROR = -292, + + // Errors in main functions. + + CANNOT_PREPARE = -301, + CANNOT_FIND_BASIS = -302, + CANNOT_FIND_VALUES = -303, + CANNOT_FIND_VECTORS = -304, + CANNOT_FIND_SCHUR = -305, + SCHUR_UNDEFINED = -306, + + // Errors due to incorrect function calling sequence. + + CANNOT_GET_VECTOR = -401, + CANNOT_GET_PROD = -402, + CANNOT_PUT_VECTOR = -403, + PREPARE_NOT_OK = -404, + BASIS_NOT_OK = -405, + VALUES_NOT_OK = -406, + VECTORS_NOT_OK = -407, + SCHUR_NOT_OK = -408, + RESID_NOT_OK = -409, + + // Errors in classes that perform LU decompositions. + + MATRIX_IS_SINGULAR = -501, + DATA_UNDEFINED = -502, + INSUFICIENT_MEMORY = -503, + NOT_SQUARE_MATRIX = -504, + NOT_FACTORED_MATRIX = -505, + INCOMPATIBLE_SIZES = -506, + DIFFERENT_TRIANGLES = -507, + INCONSISTENT_DATA = -508, + CANNOT_READ_FILE = -509, + + // Errors in matrix files. + + CANNOT_OPEN_FILE = -551, + WRONG_MATRIX_TYPE = -552, + WRONG_DATA_TYPE = -553, + RHS_IGNORED = -554, + UNEXPECTED_EOF = -555, + + // Other severe errors. + + NOT_IMPLEMENTED = -901, + MEMORY_OVERFLOW = -902, + GENERIC_SEVERE = -999, + + // Warnings. + + NCV_OUT_OF_BOUNDS = 101, + MAXIT_NON_POSITIVE = 102, + MAX_ITERATIONS = 201, + NO_SHIFTS_APPLIED = 202, + CHANGING_AUTOSHIFT = 301, + DISCARDING_FACTORS = 401, + GENERIC_WARNING = 999 + + }; + + protected: + + static ErrorCode code; + +}; +// trick to initialize static member code, which is allowed in template + +template< typename T > +enum ArpackError_static::ErrorCode ArpackError_static::code = NO_ERRORS; +// "code" initialization. + +class ArpackError: public ArpackError_static { + + private: + + static void Print(const std::string& where, const std::string& message); + // Writes error messages on cerr stream. + + public: + + static void Set(ErrorCode error, const std::string& where="AREigenProblem"); + // Set error code and write error messages. + + static int Status() { return (int) code; } + // Returns current value of error code. + + ArpackError(ErrorCode error, const std::string& where="AREigenProblem") { + Set(error,where); + } + // Constructor that set error code. + + ArpackError() { code = NO_ERRORS; }; + // Constructor that does nothing. + +}; + +inline void ArpackError::Print(const std::string& where, const std::string& message) +{ + +#ifndef ARPACK_SILENT_MODE + std::cerr << "Arpack error in " << where << "." << std::endl; + std::cerr << "-> " << message << "." << std::endl; +#endif + +} // Print + +inline void ArpackError::Set(ErrorCode error, const std::string& where) +{ + + code = error; + switch (code) { + case NO_ERRORS : + return; + case NOT_IMPLEMENTED : + Print(where, "This function was not implemented yet"); + return; + case MEMORY_OVERFLOW : + Print(where, "Memory overflow"); + return; + case GENERIC_SEVERE : + Print(where, "Severe error"); + return; + case PARAMETER_ERROR : + Print(where, "Some parameters were not correctly defined"); + return; + case N_SMALLER_THAN_2 : + Print(where, "'n' must be greater than one"); + return; + case NEV_OUT_OF_BOUNDS : + Print(where, "'nev' is out of bounds"); + return; + case WHICH_UNDEFINED : + Print(where, "'which' was not correctly defined"); + return; + case PART_UNDEFINED : + Print(where, "'part' must be one of 'R' or 'I'"); + return; + case INVMODE_UNDEFINED : + Print(where, "'InvertMode' must be one of 'S' or 'B'"); + return; + case RANGE_ERROR : + Print(where, "Range error"); + return; + case LAPACK_ERROR : + Print(where, "Could not perform LAPACK eigenvalue calculation"); + return; + case START_RESID_ZERO : + Print(where, "Starting vector is zero"); + return; + case NOT_ACCURATE_EIG : + Print(where, "Could not find any eigenvalue to sufficient accuracy"); + return; + case REORDERING_ERROR : + Print(where, "Reordering of Schur form was not possible"); + return; + case ARNOLDI_NOT_BUILD : + Print(where, "Could not build an Arnoldi factorization"); + return; + case AUPP_ERROR : + Print(where, "Error in ARPACK Aupd fortran code"); + return; + case EUPP_ERROR : + Print(where, "Error in ARPACK Eupd fortran code"); + return; + case CANNOT_PREPARE : + Print(where, "Could not correctly define internal variables"); + return; + case CANNOT_FIND_BASIS : + Print(where, "Could not find an Arnoldi basis"); + return; + case CANNOT_FIND_VALUES : + Print(where, "Could not find any eigenvalue"); + return; + case CANNOT_FIND_VECTORS: + Print(where, "Could not find any eigenvector"); + return; + case CANNOT_FIND_SCHUR : + Print(where, "Could not find any Schur vector"); + return; + case SCHUR_UNDEFINED : + Print(where, "FindEigenvectors must be used instead of FindSchurVectors"); + return; + case CANNOT_GET_VECTOR : + Print(where, "Vector is not already available"); + return; + case CANNOT_GET_PROD : + Print(where, "Matrix-vector product is not already available"); + return; + case CANNOT_PUT_VECTOR : + Print(where, "Could not store vector"); + return; + case PREPARE_NOT_OK : + Print(where, "DefineParameters must be called prior to this function"); + return; + case BASIS_NOT_OK : + Print(where, "An Arnoldi basis is not available"); + return; + case VALUES_NOT_OK : + Print(where, "Eigenvalues are not available"); + return; + case VECTORS_NOT_OK : + Print(where, "Eigenvectors are not available"); + return; + case SCHUR_NOT_OK : + Print(where, "Schur vectors are not available"); + return; + case RESID_NOT_OK : + Print(where, "Residual vector is not available"); + return; + case MATRIX_IS_SINGULAR : + Print(where, "Matrix is singular and could not be factored"); + return; + case DATA_UNDEFINED : + Print(where, "Matrix data was not defined"); + return; + case INSUFICIENT_MEMORY : + Print(where, "fill-in factor must be increased"); + return; + case NOT_SQUARE_MATRIX : + Print(where, "Matrix must be square to be factored"); + return; + case NOT_FACTORED_MATRIX: + Print(where, "Matrix must be factored before solving a system"); + return; + case INCOMPATIBLE_SIZES : + Print(where, "Matrix dimensions must agree"); + return; + case DIFFERENT_TRIANGLES: + Print(where, "A.uplo and B.uplo must be equal"); + return; + case INCONSISTENT_DATA : + Print(where, "Matrix data contain inconsistencies"); + return; + case CANNOT_READ_FILE : + Print(where, "Data file could not be read"); + return; + case CANNOT_OPEN_FILE : + Print(where, "Invalid path or filename"); + return; + case WRONG_MATRIX_TYPE : + Print(where, "Wrong matrix type"); + return; + case WRONG_DATA_TYPE : + Print(where, "Wrong data type"); + return; + case RHS_IGNORED : + Print(where, "RHS vector will be ignored"); + return; + case UNEXPECTED_EOF : + Print(where, "Unexpected end of file"); + return; + case NCV_OUT_OF_BOUNDS : + Print(where, "'ncv' is out of bounds"); + return; + case MAXIT_NON_POSITIVE : + Print(where, "'maxit' must be greater than zero"); + return; + case MAX_ITERATIONS : + Print(where, "Maximum number of iterations taken"); + return; + case NO_SHIFTS_APPLIED : + Print(where, "No shifts could be applied during a cycle of IRAM iteration"); + return; + case CHANGING_AUTOSHIFT : + Print(where, "Turning to automatic selection of implicit shifts"); + return; + case DISCARDING_FACTORS : + Print(where, "Factors L and U were not copied. Matrix must be factored"); + return; + case GENERIC_WARNING : + default: ; + Print(where, "There is something wrong"); + return; + } + +} // Set. + +//ArpackError::ErrorCode ArpackError::code = NO_ERRORS; +// "code" initialization. + +#endif // ARERROR_H diff --git a/external/arpack++/include/argcomp.h b/external/arpack++/include/argcomp.h new file mode 100644 index 000000000..bce04ea94 --- /dev/null +++ b/external/arpack++/include/argcomp.h @@ -0,0 +1,126 @@ +/* + ARPACK++ v1.2 2/20/2000 + c++ interface to ARPACK code. + + MODULE ARGComp.h. + Arpack++ class ARCompGenEig definition. + + ARPACK Authors + Richard Lehoucq + Danny Sorensen + Chao Yang + Dept. of Computational & Applied Mathematics + Rice University + Houston, Texas +*/ + +#ifndef ARGCOMP_H +#define ARGCOMP_H + +#include +#include +#include "arch.h" +#include "arscomp.h" +#include "argeig.h" + +template +class ARCompGenEig: + virtual public ARGenEig, ARFOP, ARFB>, + virtual public ARCompStdEig { + + public: + + // a) Constructors and destructor. + + ARCompGenEig() { } + // Short constructor (Does nothing but calling base classes constructors). + + ARCompGenEig(int np, int nevp, ARFOP* objOPp, + void (ARFOP::* MultOPxp)(arcomplex[],arcomplex[]), + ARFB* objBp, + void (ARFB::* MultBxp)(arcomplex[],arcomplex[]), + const std::string& whichp = "LM", int ncvp = 0, + ARFLOAT tolp = 0.0, int maxitp = 0, + arcomplex* residp = NULL, bool ishiftp = true); + // Long constructor (regular mode). + + ARCompGenEig(int np, int nevp, ARFOP* objOPp, + void (ARFOP::* MultOPxp)(arcomplex[],arcomplex[]), + ARFB* objBp, + void (ARFB::* MultBxp)(arcomplex[],arcomplex[]), + arcomplex sigmap, + const std::string& whichp = "LM", int ncvp = 0, ARFLOAT tolp = 0.0, + int maxitp = 0, arcomplex* residp = NULL, + bool ishiftp = true); + // Long constructor (shift and invert mode). + + ARCompGenEig(const ARCompGenEig& other) { Copy(other); } + // Copy constructor. + + virtual ~ARCompGenEig() { } + // Destructor. + + // b) Operators. + + ARCompGenEig& operator=(const ARCompGenEig& other); + // Assignment operator. + +}; // class ARCompGenEig. + + +// ------------------------------------------------------------------------ // +// ARCompGenEig member functions definition. // +// ------------------------------------------------------------------------ // + + +template +inline ARCompGenEig:: +ARCompGenEig(int np, int nevp, ARFOP* objOPp, + void (ARFOP::* MultOPxp)(arcomplex[],arcomplex[]), + ARFB* objBp, + void (ARFB::* MultBxp)(arcomplex[], arcomplex[]), + const std::string& whichp, int ncvp, ARFLOAT tolp, + int maxitp, arcomplex* residp, bool ishiftp) + +{ + + this->NoShift(); + this->DefineParameters(np, nevp, objOPp, MultOPxp, objBp, MultBxp, + whichp, ncvp, tolp, maxitp, residp, ishiftp); + +} // Long constructor (regular mode). + + +template +inline ARCompGenEig:: +ARCompGenEig(int np, int nevp, ARFOP* objOPp, + void (ARFOP::* MultOPxp)(arcomplex[],arcomplex[]), + ARFB* objBp, + void (ARFB::* MultBxp)(arcomplex[], arcomplex[]), + arcomplex sigmap, const std::string& whichp, int ncvp, ARFLOAT tolp, + int maxitp, arcomplex* residp, bool ishiftp) + +{ + + this->ChangeShift(sigmap); + this->DefineParameters(np, nevp, objOPp, MultOPxp, objBp, MultBxp, + whichp, ncvp, tolp, maxitp, residp, ishiftp); + +} // Long constructor (shift and invert mode). + + +template +ARCompGenEig& ARCompGenEig:: +operator=(const ARCompGenEig& other) +{ + + if (this != &other) { // Stroustrup suggestion. + this->ClearMem(); + Copy(other); + } + return *this; + +} // operator=. + + +#endif // ARGCOMP_H diff --git a/external/arpack++/include/argeig.h b/external/arpack++/include/argeig.h new file mode 100644 index 000000000..74ccc07f9 --- /dev/null +++ b/external/arpack++/include/argeig.h @@ -0,0 +1,233 @@ +/* + ARPACK++ v1.2 2/20/2000 + c++ interface to ARPACK code. + + MODULE ARGEig.h. + Arpack++ class ARGenEig definition. + Derived from ARStdEig, this class is the + base class for all generalized eigenvalue problems definition. + + ARPACK Authors + Richard Lehoucq + Danny Sorensen + Chao Yang + Dept. of Computational & Applied Mathematics + Rice University + Houston, Texas +*/ + +#ifndef ARGEIG_H +#define ARGEIG_H + +#include +#include +#include "arch.h" +#include "arerror.h" +#include "arrgeig.h" +#include "arseig.h" + +// ARGenEig class definition. + +template +class ARGenEig: + virtual public ARrcGenEig, + virtual public ARStdEig { + + public: + + // a) Notation. + + typedef void (ARFB::* TypeBx)(ARTYPE[], ARTYPE[]); + typedef void (ARFOP::* TypeOPx)(ARTYPE[], ARTYPE[]); + + + protected: + + // b) Protected variables: + + ARFB *objB; // Object that has MultBx as a member function. + TypeBx MultBx; // Function that evaluates the product B*x. + + // c) Protected functions: + + virtual void Copy(const ARGenEig& other); + // Makes a deep copy of "other" over "this" object. + // Old values are not deleted (this function is to be used + // by the copy constructor and the assignment operator only). + + + public: + + // d) Public functions: + + // d.1) Function that stores user defined parameters. + + virtual void DefineParameters(int np, int nevp, ARFOP* objOPp, + TypeOPx MultOPxp, ARFB* objBp, + TypeBx MultBxp, const std::string& whichp="LM", + int ncvp=0, ARFLOAT tolp=0.0, + int maxitp=0, ARTYPE* residp=NULL, + bool ishiftp=true); + // Set values of problem parameters (also called by constructors). + + + // d.2) Function that allow changes in problem parameters. + + void ChangeMultBx(ARFB* objBp, TypeBx MultBxp); + // Changes the matrix-vector function that performs B*x. + + + // d.3) Functions that perform all calculations in one step. + + virtual int FindArnoldiBasis(); + // Determines the Arnoldi basis related to the given problem. + + + // d.4) Constructors and destructor. + + ARGenEig() { } + // Constructor that does nothing but calling base classes constructors. + + ARGenEig(const ARGenEig& other) { Copy(other); } + // Copy constructor. + + virtual ~ARGenEig() { } + // Destructor (presently meaningless). + + // e) Operators. + + ARGenEig& operator=(const ARGenEig& other); + // Assignment operator. + +}; // class ARGenEig. + + +// ------------------------------------------------------------------------ // +// ARGenEig member functions definition. // +// ------------------------------------------------------------------------ // + + +template +inline void ARGenEig:: +Copy(const ARGenEig& other) +{ + + ARStdEig::Copy(other); + objB = other.objB; + MultBx = other.MultBx; + +} // Copy. + + +template +void ARGenEig:: +DefineParameters(int np, int nevp, ARFOP* objOPp, + void (ARFOP::* MultOPxp)(ARTYPE[], ARTYPE[]), ARFB* objBp, + void (ARFB::* MultBxp)(ARTYPE[], ARTYPE[]), const std::string& whichp, + int ncvp, ARFLOAT tolp, int maxitp, ARTYPE* residp, + bool ishiftp) + +{ + + // Setting parameters of generalized problems. + + objB = objBp; + MultBx = MultBxp; + + // Setting common eigen-problem parameters. + + ARStdEig:: + DefineParameters(np, nevp, objOPp, MultOPxp, whichp, + ncvp, tolp, maxitp, residp, ishiftp); + +} // DefineParameters. + + +template +inline void ARGenEig:: +ChangeMultBx(ARFB* objBp, void (ARFB::* MultBxp)(ARTYPE[], ARTYPE[])) +{ + + objB = objBp; + MultBx = MultBxp; + this->Restart(); + +} // ChangeMultBx. + + +template +int ARGenEig::FindArnoldiBasis() +{ + + if (!this->BasisOK) this->Restart(); + + // Changing to auto shift mode. + + if (!this->AutoShift) { + ArpackError::Set(ArpackError::CHANGING_AUTOSHIFT, "FindArnoldiBasis"); + this->AutoShift=true; + } + + // ARPACK main loop. + + while (!this->BasisOK) { + + // Calling Aupp. + + try { this->TakeStep(); } + catch (ArpackError) { + ArpackError(ArpackError::CANNOT_FIND_BASIS, "FindArnoldiBasis"); + return 0; + } + + switch (this->ido) { + case -1: + + // Performing y <- OP*B*x for the first time when mode != 2. + + if (this->mode != 2) { + this->ipntr[3] = this->ipntr[2]+this->n; // not a clever idea, but... + (this->objB->*MultBx)(&this->workd[this->ipntr[1]],&this->workd[this->ipntr[3]]); + } + + case 1: + + // Performing y <- OP*w. + + if (this->mode == 2) { // w = x if mode = 2. + (this->objOP->*(this->MultOPx))(&this->workd[this->ipntr[1]],&this->workd[this->ipntr[2]]); + } + else { // w = B*x otherwise. + (this->objOP->*(this->MultOPx))(&this->workd[this->ipntr[3]],&this->workd[this->ipntr[2]]); + } + break; + + case 2: + + // Performing y <- B*x. + + (this->objB->*MultBx)(&this->workd[this->ipntr[1]],&this->workd[this->ipntr[2]]); + + } + } + return this->nconv; + +} // FindArnoldiBasis. + + +template +ARGenEig& ARGenEig:: +operator=(const ARGenEig& other) +{ + + if (this != &other) { // Stroustrup suggestion. + this->ClearMem(); + Copy(other); + } + return *this; + +} // operator=. + + +#endif // ARGEIG_H + diff --git a/external/arpack++/include/argnsym.h b/external/arpack++/include/argnsym.h new file mode 100644 index 000000000..9590cb7ba --- /dev/null +++ b/external/arpack++/include/argnsym.h @@ -0,0 +1,362 @@ +/* + ARPACK++ v1.2 2/20/2000 + c++ interface to ARPACK code. + + MODULE ARGNSym.h. + Arpack++ class ARNonSymGenEig definition. + + ARPACK Authors + Richard Lehoucq + Danny Sorensen + Chao Yang + Dept. of Computational & Applied Mathematics + Rice University + Houston, Texas +*/ + +#ifndef ARGNSYM_H +#define ARGNSYM_H + +#include +#include +#include "arch.h" +#include "blas1c.h" +#include "lapackc.h" +#include "arsnsym.h" +#include "argeig.h" +#include "arrgnsym.h" + +template +class ARNonSymGenEig: + virtual public ARGenEig, + virtual public ARNonSymStdEig, + virtual public ARrcNonSymGenEig { + + public: + + // a) Notation. + + typedef void (ARFB::* TypeBx)(ARFLOAT[], ARFLOAT[]); + + + protected: + + // b) Protected variables: + + ARFB *objA; // Object that has MultAx as a member function. + TypeBx MultAx; // Function that evaluates the product A*x. + + + // c) Protected functions: + + void RecoverEigenvalues(); + // Uses Rayleigh quotient to recover eigenvalues of the original + // problem when shift is complex. + + virtual void Copy(const ARNonSymGenEig& other); + // Makes a deep copy of "other" over "this" object. + // Old values are not deleted (this function is to be used + // by the copy constructor and the assignment operator only). + + + public: + + // d) Public functions: + + // d.1) Functions that allow changes in problem parameters. + + virtual void SetShiftInvertMode(ARFLOAT sigmaRp, ARFOP* objOPp, + void (ARFOP::* MultOPxp)(ARFLOAT[],ARFLOAT[])); + // Turns the problem to real shift-and-invert mode with sigmaRp as shift. + + virtual void SetComplexShiftMode(char partp, ARFLOAT sigmaRp, + ARFLOAT sigmaIp, ARFOP* objOPp, + void (ARFOP::* MultOPxp)(ARFLOAT[],ARFLOAT[]), + ARFB* objAp, + void (ARFB::* MultAxp)(ARFLOAT[],ARFLOAT[])); + // Turns the problem to complex shift-and-invert mode with shift + // defined by sigmaRp and sigmaIp. MultAx is used to obtain eigenvalues. + + + // d.2) Functions that perform all calculations in one step. + + virtual int FindEigenvalues(); + // Determines nev approximated eigenvalues of the given eigen-problem. + + virtual int FindEigenvectors(bool schurp = false); + // Determines nev approximated eigenvectors of the given eigen-problem + // Optionally also determines nev Schur vectors that span the desired + // invariant subspace. + + virtual int FindSchurVectors(); + // Determines nev Schur vectors that span the desired invariant subspace. + // Redefined in ARSymEig. + + + // d.3) Constructors and destructor. + + ARNonSymGenEig() { this->part = 'R'; } + // Short constructor (Does nothing but calling base classes constructors). + + ARNonSymGenEig(int np, int nevp, ARFOP* objOPp, + void (ARFOP::* MultOPxp)(ARFLOAT[], ARFLOAT[]), + ARFB* objBp, void (ARFB::* MultBxp)(ARFLOAT[], ARFLOAT[]), + const std::string& whichp = "LM", int ncvp = 0, ARFLOAT tolp = 0.0, + int maxitp = 0, ARFLOAT* residp = NULL, bool ishiftp = true); + // Long constructor (regular mode). + + ARNonSymGenEig(int np, int nevp, ARFOP* objOPp, + void (ARFOP::* MultOPxp)(ARFLOAT[], ARFLOAT[]), + ARFB* objBp, void (ARFB::* MultBxp)(ARFLOAT[], ARFLOAT[]), + ARFLOAT sigmap, const std::string& whichp = "LM", int ncvp = 0, + ARFLOAT tolp = 0.0, int maxitp = 0, ARFLOAT* residp = NULL, + bool ishiftp = true); + // Long constructor (real shift and invert mode). + + ARNonSymGenEig(int np, int nevp, ARFOP* objOPp, + void (ARFOP::* MultOPxp)(ARFLOAT[], ARFLOAT[]), ARFB* objAp, + void (ARFB::* MultAxp)(ARFLOAT[], ARFLOAT[]), ARFB* objBp, + void (ARFB::* MultBxp)(ARFLOAT[], ARFLOAT[]), char partp, + ARFLOAT sigmaRp, ARFLOAT sigmaIp, const std::string& whichp = "LM", + int ncvp = 0, ARFLOAT tolp = 0.0, int maxitp = 0, + ARFLOAT* residp = NULL, bool ishiftp = true); + // Long constructor (complex shift and invert mode). + + ARNonSymGenEig(const ARNonSymGenEig& other) { Copy(other); } + // Copy constructor. + + virtual ~ARNonSymGenEig() { } + // Destructor. + + // e) Operators. + + ARNonSymGenEig& operator=(const ARNonSymGenEig& other); + // Assignment operator. + +}; // class ARNonSymGenEig. + + +// ------------------------------------------------------------------------ // +// ARNonSymGenEig member functions definition. // +// ------------------------------------------------------------------------ // + + +template +inline void ARNonSymGenEig:: +Copy(const ARNonSymGenEig& other) +{ + + ARGenEig::Copy(other); + objA = other.objA; + MultAx = other.MultAx; + this->part = other.part; + +} // Copy. + + +template +void ARNonSymGenEig::RecoverEigenvalues() +{ + + int j, ColJ, ColJp1; + ARFLOAT numr, numi, denr, deni; + ARFLOAT* Ax; + + Ax = new ARFLOAT[this->n]; + + for (j=0; jnconv; j++) { + + ColJ = j*this->n; + ColJp1 = ColJ+this->n; + + if (this->EigValI[j] == (ARFLOAT)0.0) { + + // Eigenvalue is real. Computing EigVal = x'(Ax)/x'(Mx). + + (this->objB->*MultAx)(&this->EigVec[ColJ], Ax); + numr = dot(this->n, &this->EigVec[ColJ], 1, Ax, 1); + (this->objB->*(this->MultBx))(&this->EigVec[ColJ], Ax); + denr = dot(this->n, &this->EigVec[ColJ], 1, Ax, 1); + this->EigValR[j] = numr / denr; + + } + else { + + // Eigenvalue is complex. + + // Computing x'(Ax). + + (this->objB->*MultAx)(&this->EigVec[ColJ], Ax); + numr = dot(this->n, &this->EigVec[ColJ], 1, Ax, 1); + numi = dot(this->n, &this->EigVec[ColJp1], 1, Ax, 1); + (this->objB->*MultAx)(&this->EigVec[ColJp1], Ax); + numr = numr + dot(this->n, &this->EigVec[ColJp1], 1, Ax, 1); + numi = -numi + dot(this->n, &this->EigVec[ColJ], 1, Ax, 1); + + // Computing x'(Mx). + + (this->objB->*(this->MultBx))(&this->EigVec[ColJ], Ax); + denr = dot(this->n, &this->EigVec[ColJ], 1, Ax, 1); + deni = dot(this->n, &this->EigVec[ColJp1], 1, Ax, 1); + (this->objB->*(this->MultBx))(&this->EigVec[ColJp1], Ax); + denr = denr + dot(this->n, &this->EigVec[ColJp1], 1, Ax, 1); + deni = -deni + dot(this->n, &this->EigVec[ColJ], 1, Ax, 1); + + // Computing the first eigenvalue of the conjugate pair. + + this->EigValR[j] = (numr*denr+numi*deni) / lapy2(denr, deni); + this->EigValI[j] = (numi*denr-numr*deni) / lapy2(denr, deni); + + // Getting the second eigenvalue of the conjugate pair by taking + // the conjugate of the first. + + this->EigValR[j+1] = this->EigValR[j]; + this->EigValI[j+1] = -this->EigValI[j]; + j++; + + } + + } + + delete[] Ax; + +} // RecoverEigenvalues. + + +template +inline void ARNonSymGenEig:: +SetShiftInvertMode(ARFLOAT sigmaRp, ARFOP* objOPp, + void (ARFOP::* MultOPxp)(ARFLOAT[], ARFLOAT[])) +{ + + this->part = 'R'; + this->objOP = objOPp; + this->MultOPx = MultOPxp; + this->ChangeShift(sigmaRp); + +} // SetShiftInvertMode. + + +template +inline void ARNonSymGenEig:: +SetComplexShiftMode(char partp, ARFLOAT sigmaRp, ARFLOAT sigmaIp, + ARFOP* objOPp, + void (ARFOP::* MultOPxp)(ARFLOAT[], ARFLOAT[]), + ARFB* objAp, void (ARFB::* MultAxp)(ARFLOAT[], ARFLOAT[])) +{ + + this->objOP = objOPp; + this->MultOPx = MultOPxp; + objA = objAp; + MultAx = MultAxp; + this->part = this->CheckPart(partp); + this->ChangeShift(sigmaRp, sigmaIp); + +} // SetComplexShiftMode. + + +template +inline int ARNonSymGenEig::FindEigenvalues() +{ + + this->nconv = ARStdEig::FindEigenvalues(); + if (this->sigmaI != 0.0) RecoverEigenvalues(); + return this->nconv; + +} // FindEigenvalues. + + +template +inline int ARNonSymGenEig::FindEigenvectors(bool schurp) +{ + + this->nconv = ARStdEig::FindEigenvectors(schurp); + if (this->sigmaI != 0.0) RecoverEigenvalues(); + return this->nconv; + +} // FindEigenvectors. + + +template +int ARNonSymGenEig::FindSchurVectors() +{ + + this->nconv = ARStdEig::FindSchurVectors(); + if (this->sigmaI != 0.0) RecoverEigenvalues(); + return this->nconv; + +} // FindSchurVectors. + + +template +inline ARNonSymGenEig:: +ARNonSymGenEig(int np, int nevp, ARFOP* objOPp, + void (ARFOP::* MultOPxp)(ARFLOAT[], ARFLOAT[]), + ARFB* objBp, void (ARFB::* MultBxp)(ARFLOAT[], ARFLOAT[]), + const std::string& whichp, int ncvp, ARFLOAT tolp, int maxitp, + ARFLOAT* residp, bool ishiftp) + +{ + + this->part = 'R'; // Considering mode = 3 in ChangeShift. + this->NoShift(); + this->DefineParameters(np, nevp, objOPp, MultOPxp, objBp, MultBxp, + whichp, ncvp, tolp, maxitp, residp, ishiftp); + +} // Long constructor (regular mode). + + +template +inline ARNonSymGenEig:: +ARNonSymGenEig(int np, int nevp, ARFOP* objOPp, + void (ARFOP::* MultOPxp)(ARFLOAT[], ARFLOAT[]), + ARFB* objBp, void (ARFB::* MultBxp)(ARFLOAT[], ARFLOAT[]), + ARFLOAT sigmap, const std::string& whichp, int ncvp, + ARFLOAT tolp, int maxitp, ARFLOAT* residp, bool ishiftp) + +{ + + SetShiftInvertMode(sigmap, objOPp, MultOPxp); + this->DefineParameters(np, nevp, objOPp, MultOPxp, objBp, MultBxp, + whichp, ncvp, tolp, maxitp, residp, ishiftp); + + +} // Long constructor (real shift and invert mode). + + +template +inline ARNonSymGenEig:: +ARNonSymGenEig(int np, int nevp, ARFOP* objOPp, + void (ARFOP::* MultOPxp)(ARFLOAT[], ARFLOAT[]), + ARFB* objAp, void (ARFB::* MultAxp)(ARFLOAT[], ARFLOAT[]), + ARFB* objBp, void (ARFB::* MultBxp)(ARFLOAT[], ARFLOAT[]), + char partp, ARFLOAT sigmaRp, ARFLOAT sigmaIp, + const std::string& whichp, int ncvp, ARFLOAT tolp, int maxitp, + ARFLOAT* residp, bool ishiftp) + +{ + + SetComplexShiftMode(partp, sigmaRp, sigmaIp, objOPp, + MultOPxp, objAp, MultAxp); + this->DefineParameters(np, nevp, objOPp, MultOPxp, objBp, MultBxp, + whichp, ncvp, tolp, maxitp, residp, ishiftp); + +} // Long constructor (shift and invert mode). + + +template +ARNonSymGenEig& ARNonSymGenEig:: +operator=(const ARNonSymGenEig& other) +{ + + if (this != &other) { // Stroustrup suggestion. + this->ClearMem(); + Copy(other); + } + return *this; + +} // operator=. + + +#endif // ARGNSYM_H + diff --git a/external/arpack++/include/argsym.h b/external/arpack++/include/argsym.h new file mode 100644 index 000000000..8191ba0a5 --- /dev/null +++ b/external/arpack++/include/argsym.h @@ -0,0 +1,326 @@ +/* + ARPACK++ v1.2 2/20/2000 + c++ interface to ARPACK code. + + MODULE ARGSym.h. + Arpack++ class ARSymGenEig definition. + + ARPACK Authors + Richard Lehoucq + Danny Sorensen + Chao Yang + Dept. of Computational & Applied Mathematics + Rice University + Houston, Texas +*/ + +#ifndef ARGSYM_H +#define ARGSYM_H + +#include +#include +#include "arch.h" +#include "arssym.h" +#include "arrgsym.h" +#include "argeig.h" + +template +class ARSymGenEig: + virtual public ARGenEig, + virtual public ARSymStdEig, + virtual public ARrcSymGenEig { + + public: + + // a) Notation. + + typedef void (ARFB::* TypeBx)(ARFLOAT[], ARFLOAT[]); + + + protected: + + // b) Protected variables: + + ARFB *objA; // Object that has MultAx as a member function. + TypeBx MultAx; // Function that evaluates the product A*x. + + // c) Protected functions: + + virtual void Copy(const ARSymGenEig& other); + // Makes a deep copy of "other" over "this" object. + // Old values are not deleted (this function is to be used + // by the copy constructor and the assignment operator only). + + + public: + + // d) Public functions: + + // d.1) Functions that allow changes in problem parameters. + + void SetShiftInvertMode(ARFLOAT sigmap, ARFOP* objOPp, + void (ARFOP::* MultOPxp)(ARFLOAT[], ARFLOAT[])); + // Turns problem to shift and invert mode with shift defined by sigmap. + + void SetBucklingMode(ARFLOAT sigmap, ARFOP* objOPp, + void (ARFOP::* MultOPxp)(ARFLOAT[], ARFLOAT[])); + // Turns problem to buckling mode with shift defined by sigmap. + + void SetCayleyMode(ARFLOAT sigmap, ARFOP* objOPp, + void (ARFOP::* MultOPxp)(ARFLOAT[], ARFLOAT[]), + ARFB* objAp, void (ARFB::* MultAxp)(ARFLOAT[], ARFLOAT[])); + // Turns problem to Cayley mode with shift defined by sigmap. + + + // d.2) Functions that perform all calculations in one step. + + int FindArnoldiBasis(); + // Determines the Arnoldi basis related to the given problem. + + + // d.3) Constructors and destructor. + + ARSymGenEig() { this->InvertMode = 'S'; } + // Short constructor that does almost nothing. + + ARSymGenEig(int np, int nevp, ARFOP* objOPp, + void (ARFOP::* MultOPxp)(ARFLOAT[], ARFLOAT[]), ARFB* objBp, + void (ARFB::* MultBxp)(ARFLOAT[], ARFLOAT[]), + const std::string& whichp = "LM", int ncvp = 0, ARFLOAT tolp = 0.0, + int maxitp = 0, ARFLOAT* residp = NULL, bool ishiftp = true); + // Long constructor (regular mode). + + ARSymGenEig(char invertmodep, int np, int nevp, ARFOP* objOPp, + void (ARFOP::* MultOPxp)(ARFLOAT[], ARFLOAT[]), + ARFB* objBp, void (ARFB::* MultBxp)(ARFLOAT[], ARFLOAT[]), + ARFLOAT sigmap, const std::string& whichp = "LM", int ncvp = 0, + ARFLOAT tolp = 0.0, int maxitp = 0, ARFLOAT* residp = NULL, + bool ishiftp = true); + // Long constructor (shift-and-invert and buckling mode). + + ARSymGenEig(int np, int nevp, ARFOP* objOPp, + void (ARFOP::* MultOPxp)(ARFLOAT[], ARFLOAT[]), ARFB* objAp, + void (ARFB::* MultAxp)(ARFLOAT[], ARFLOAT[]), ARFB* objBp, + void (ARFB::* MultBxp)(ARFLOAT[], ARFLOAT[]), ARFLOAT sigmap, + const std::string& whichp = "LM", int ncvp = 0, ARFLOAT tolp = 0.0, + int maxitp = 0, ARFLOAT* residp = NULL, bool ishiftp = true); + // Long constructor (cayley mode). + + ARSymGenEig(const ARSymGenEig& other) { Copy(other); } + // Copy constructor. + + virtual ~ARSymGenEig() { } + // Destructor. + + // e) Operators. + + ARSymGenEig& operator=(const ARSymGenEig& other); + // Assignment operator. + +}; // class ARSymGenEig. + + +// ------------------------------------------------------------------------ // +// ARSymGenEig member functions definition. // +// ------------------------------------------------------------------------ // + + +template +inline void ARSymGenEig:: +Copy(const ARSymGenEig& other) +{ + + ARGenEig::Copy(other); + objA = other.objA; + MultAx = other.MultAx; + this->InvertMode = other.InvertMode; + +} // Copy. + + +template +void ARSymGenEig:: +SetShiftInvertMode(ARFLOAT sigmap, ARFOP* objOPp, + void (ARFOP::* MultOPxp)(ARFLOAT[], ARFLOAT[])) +{ + + this->InvertMode = 'S'; + this->objOP = objOPp; + this->MultOPx = MultOPxp; + this->ChangeShift(sigmap); + +} // SetShiftInvertMode. + + +template +void ARSymGenEig:: +SetBucklingMode(ARFLOAT sigmap, ARFOP* objOPp, + void (ARFOP::* MultOPxp)(ARFLOAT[], ARFLOAT[])) + +{ + + this->InvertMode = 'B'; + this->objOP = objOPp; + this->MultOPx = MultOPxp; + this->ChangeShift(sigmap); + +} // SetBucklingMode. + + +template +void ARSymGenEig:: +SetCayleyMode(ARFLOAT sigmap, ARFOP* objOPp, + void (ARFOP::* MultOPxp)(ARFLOAT[], ARFLOAT[]), ARFB* objAp, + void (ARFB::* MultAxp)(ARFLOAT[], ARFLOAT[])) + +{ + + this->InvertMode = 'C'; + this->objOP = objOPp; + this->MultOPx = MultOPxp; + objA = objAp; + MultAx = MultAxp; + this->ChangeShift(sigmap); + +} // SetCayleyMode. + + +template +int ARSymGenEig::FindArnoldiBasis() +{ + + ARFLOAT* temp; + + if (this->mode != 5) { // Using base function if not in Cayley mode. + return ARGenEig::FindArnoldiBasis(); + } + else { + + temp = new ARFLOAT[this->n+1]; + + if (!this->BasisOK) this->Restart(); + + // Changing to auto shift mode. + + if (!this->AutoShift) { + ArpackError::Set(ArpackError::CHANGING_AUTOSHIFT, "FindArnoldiBasis"); + this->AutoShift=true; + } + + // ARPACK main loop. + + while (!this->BasisOK) { + + // Calling Aupp. + + try { this->TakeStep(); } + catch (ArpackError) { + ArpackError(ArpackError::CANNOT_FIND_BASIS, "FindArnoldiBasis"); + delete[] temp; + return 0; + } + + switch (this->ido) { + case -1: + + // Performing y <- B*x for the first time. + + this->ipntr[3] = this->ipntr[2]+this->n; // not a clever idea, but... + (this->objB->*(this->MultBx))(&this->workd[this->ipntr[1]],&this->workd[this->ipntr[3]]); + + case 1: + + // Performing y <- OP*(A+sigma*B)*x, B*x is already available. + + (this->objB->*MultAx)(&this->workd[this->ipntr[1]], temp); + axpy(this->n, this->sigmaR, &this->workd[this->ipntr[3]], 1, temp, 1); + (this->objOP->*(this->MultOPx))(temp, &this->workd[this->ipntr[2]]); + break; + + case 2: + + // Performing y <- B*x. + + (this->objB->*(this->MultBx))(&this->workd[this->ipntr[1]],&this->workd[this->ipntr[2]]); + + } + } + + delete[] temp; + + return this->nconv; + } + +} // FindArnoldiBasis. + + +template +inline ARSymGenEig:: +ARSymGenEig(int np, int nevp, ARFOP* objOPp, + void (ARFOP::* MultOPxp)(ARFLOAT[], ARFLOAT[]), + ARFB* objBp, void (ARFB::* MultBxp)(ARFLOAT[], ARFLOAT[]), + const std::string& whichp, int ncvp, ARFLOAT tolp, int maxitp, + ARFLOAT* residp, bool ishiftp) + +{ + + this->InvertMode = 'S'; + this->NoShift(); + this->DefineParameters(np, nevp, objOPp, MultOPxp, objBp, MultBxp, + whichp, ncvp, tolp, maxitp, residp, ishiftp); + +} // Long constructor (regular mode). + + +template +inline ARSymGenEig:: +ARSymGenEig(char InvertModep, int np, int nevp, ARFOP* objOPp, + void (ARFOP::* MultOPxp)(ARFLOAT[], ARFLOAT[]), + ARFB* objBp, void (ARFB::* MultBxp)(ARFLOAT[], ARFLOAT[]), + ARFLOAT sigmap, const std::string& whichp, int ncvp, ARFLOAT tolp, + int maxitp, ARFLOAT* residp, bool ishiftp) + +{ + + this->InvertMode = this->CheckInvertMode(InvertModep); // InvertMode = 'S' or 'B'. + this->ChangeShift(sigmap); + this->DefineParameters(np, nevp, objOPp, MultOPxp, objBp, MultBxp, + whichp, ncvp, tolp, maxitp, residp, ishiftp); + +} // Long constructor (shift-and-invert and buckling mode). + + +template +inline ARSymGenEig:: +ARSymGenEig(int np, int nevp, ARFOP* objOPp, + void (ARFOP::* MultOPxp)(ARFLOAT[], ARFLOAT[]), + ARFB* objAp, void (ARFB::* MultAxp)(ARFLOAT[], ARFLOAT[]), + ARFB* objBp, void (ARFB::* MultBxp)(ARFLOAT[], ARFLOAT[]), + ARFLOAT sigmap, const std::string& whichp, int ncvp, ARFLOAT tolp, + int maxitp, ARFLOAT* residp, bool ishiftp) + +{ + + SetCayleyMode(sigmap, objOPp, this->MultOPx, objAp, MultAxp); + this->DefineParameters(np, nevp, objOPp, MultOPxp, objBp, MultBxp, + whichp, ncvp, tolp, maxitp, residp, ishiftp); + +} // Long constructor (cayley mode). + + +template +ARSymGenEig& ARSymGenEig:: +operator=(const ARSymGenEig& other) +{ + + if (this != &other) { // Stroustrup suggestion. + this->ClearMem(); + Copy(other); + } + return *this; + +} // operator=. + + +#endif // ARGSYM_H + diff --git a/external/arpack++/include/arhbmat.h b/external/arpack++/include/arhbmat.h new file mode 100644 index 000000000..97c4db400 --- /dev/null +++ b/external/arpack++/include/arhbmat.h @@ -0,0 +1,407 @@ +/* + ARPACK++ v1.2 2/20/2000 + c++ interface to ARPACK code. + + MODULE ARHBMat.h + Matrix template that generates a matrix in CSC format + from a Harwell-Boing matrix file. + + ARPACK authors: + Richard Lehoucq + Kristyn Maschhoff + Danny Sorensen + Chao Yang + Dept. of Computational & Applied Mathematics + Rice University + Houston, Texas +*/ + + +#ifndef ARHBMAT_H +#define ARHBMAT_H + +#include +#include +#include +#include +#include +#include "arch.h" +#include "arerror.h" + + +template +class ARhbMatrix { + + private: + + std::string datafile; // Filename. + std::string title; // Title. + std::string name; // Name. + std::string type; // Matrix type. + int m; // Number of rows. + int n; // Number of columns. + int nnz; // Number of nonzero variables. + ARINT* irow; // Row indices. + ARINT* pcol; // Column pointers. + ARTYPE* val; // Numerical values of matrix entries. + + void ConvertDouble(char* num); + + bool ReadEntry(std::ifstream& file, int nval, int fval, int& j, double& val); + + bool ReadEntry(std::ifstream& file, int nval, int fval, int& j, float& val); + + bool ReadEntry(std::ifstream& file, int nval, int fval, + int& j, arcomplex& val); + + bool ReadEntry(std::ifstream& file, int nval, int fval, + int& j, arcomplex& val); + + void ReadFormat(std::ifstream& file, int& n, int& fmt); + + public: + + bool IsDefined() { return (m!=0); } + + bool IsReal() { return (type.size() > 0 && type[0]=='R'); } + + bool IsComplex() { return (type.size() > 0 && type[0]=='C'); } + + bool IsSymmetric() { return (type.size() > 1 && type[1]=='S'); } + + bool IsUnsymmetric() { return (type.size() > 1 && type[1]=='U'); } + + bool IsHermitian() { return (type.size() > 1 && type[1]=='H'); } + + bool IsSkewSymmetric() { return (type.size() > 1 && type[1]=='Z'); } + + const std::string& Filename() { return datafile; } + + const std::string& Title() { return title; } + + const std::string& Name() { return name; } + + const std::string& Type() { return type; } + + int NRows() { return m; } + + int NCols() { return n; } + + int NonZeros() { return nnz; } + + ARINT* RowInd() { return irow; } + + ARINT* ColPtr() { return pcol; } + + ARTYPE* Entries() { return val; } + + void Define(const std::string& filename); + // Function that reads the matrix file. + + ARhbMatrix(); + // Short constructor. + + ARhbMatrix(const std::string& filename) { Define(filename); } + // Long constructor. + + ~ARhbMatrix(); + // Destructor. + +}; // Class ARhbMatrix. + + +// ------------------------------------------------------------------------ // +// ARhbMatrix member functions definition. // +// ------------------------------------------------------------------------ // + + +template +inline void ARhbMatrix::ConvertDouble(char* num) +{ + + char* pd; + + pd = strchr((char*)num,'D'); + if (pd) *pd = 'E'; + pd = strchr((char*)num,'d'); + if (pd) *pd = 'E'; + + +} // ConvertDouble. + + +template +inline bool ARhbMatrix:: +ReadEntry(std::ifstream& file, int nval, int fval, int& j, double& val) +{ + + char num[81]; + char c; + + if (file.get((char*)num,fval,'\n')) { + ConvertDouble((char*)num); + val = atof((char*)num); + if (!((++j)%nval)) do file.get(c); while (c!='\n'); + return true; + } + else { + return false; + } + +} // ReadEntry (double). + + +template +inline bool ARhbMatrix:: +ReadEntry(std::ifstream& file, int nval, int fval, int& j, float& val) +{ + + double dval; + bool ret; + + ret = ReadEntry(file, nval, fval, j, dval); + val = (float)dval; + return ret; + +} // ReadEntry (float). + + +template +inline bool ARhbMatrix:: +ReadEntry(std::ifstream& file, int nval, int fval, + int& j, arcomplex& val) +{ + + char num[81], img[81]; + char c; + + if (file.get((char*)num,fval,'\n')) { + ConvertDouble((char*)num); + if (!((++j)%nval)) do file.get(c); while (c!='\n'); + if (file.get((char*)img,fval,'\n')) { + ConvertDouble((char*)img); + if (!((++j)%nval)) do file.get(c); while (c!='\n'); + val = arcomplex(atof((char*)num), atof((char*)img)); + return true; + } + else { + return false; + } + } + else { + return false; + } + +} // ReadEntry (arcomplex). + + +template +inline bool ARhbMatrix:: +ReadEntry(std::ifstream& file, int nval, int fval, + int& j, arcomplex& val) +{ + + // I hope one day c++ will have a standard complex + // class, so functions like this can be suppressed. + + char num[81], img[81]; + char c; + + if (file.get((char*)num,fval,'\n')) { + ConvertDouble((char*)num); + if (!((++j)%nval)) do file.get(c); while (c!='\n'); + if (file.get((char*)img,fval,'\n')) { + ConvertDouble((char*)img); + if (!((++j)%nval)) do file.get(c); while (c!='\n'); + val = arcomplex(atof((char*)num), atof((char*)img)); + return true; + } + else { + return false; + } + } + else { + return false; + } + +} // ReadEntry (arcomplex). + + +template +void ARhbMatrix::ReadFormat(std::ifstream& file, int& n, int& fmt) +{ + + char c; + + do file.get(c); while ((c != '(') && (c!='\n')); + file >> n; + file.get(c); + while ((c!='I') && (c!='i') && (c!='E') && (c!='e') && + (c!='D') && (c!='d') && (c!='\n')) { + do file.get(c); while ((c != ',') && (c!='\n')); + file >> n; + file.get(c); + } + if ((c==')')||(c=='\n')) { // Reading error! + fmt = 0; + } + else { + file >> fmt; + } + +} // ReadFormat. + + +template +void ARhbMatrix::Define(const std::string& filename) +{ + + // Declaring variables. + + int i, j; + int lintot, linptr, linind, linval, linrhs; + int npcol, fpcol, nirow, firow, nval, fval; + char c; + char num[81]; + char titlechar[73]; + char namechar[9]; + char typechar[4]; + ARTYPE value; + + // Opening file. + + datafile = filename; + std::ifstream file(datafile.c_str()); + + if (!file) { + throw ArpackError(ArpackError::CANNOT_OPEN_FILE, "ARhbMatrix"); + } + + // Reading the first line. + + file.get((char*)titlechar,73,'\n'); + title = std::string(titlechar); + file.get((char*)namechar,9,'\n'); + name = std::string(namechar); + do file.get(c); while (c!='\n'); + + // Reading the second line. + + file >> lintot >> linptr >> linind >> linval >> linrhs; + do file.get(c); while (c!='\n'); + + if ((linptr < 1) || (linind < 1)) { + throw ArpackError(ArpackError::PARAMETER_ERROR, "ARhbMatrix"); + } + + // Reading the third line. + + file.get((char*)typechar,4,'\n'); + type = std::string(typechar); + file >> m >> n >> nnz; + do file.get(c); while (c!='\n'); + + if ( (type.size()<3) || ((type[0] != 'R') && (type[0] != 'C')) || (type[2] != 'A')) { + throw ArpackError(ArpackError::WRONG_MATRIX_TYPE, "ARhbMatrix"); + } + else if ((m < 1) || (n < 1) || (nnz < 1)) { + throw ArpackError(ArpackError::PARAMETER_ERROR, "ARhbMatrix"); + } + + // Reading the fourth line. + + ReadFormat(file, npcol, fpcol); + ReadFormat(file, nirow, firow); + ReadFormat(file, nval, fval); + do file.get(c); while (c!='\n'); + if ((fpcol<1) || (firow<1) || (fval<1)) { + throw ArpackError(ArpackError::WRONG_DATA_TYPE, "ARhbMatrix"); + } + + // Skipping the fifth line. + + if (linrhs) { + do file.get(c); while (c!='\n'); + ArpackError(ArpackError::RHS_IGNORED, "ARhbMatrix"); + } + + // Reading column pointers. + + pcol = new ARINT[n+1]; + fpcol++; + i = 0; + while ((i <= n) && (file.get((char*)num,fpcol,'\n'))) { + pcol[i++] = atoi((char*)num)-1; + if (!(i%npcol)) do file.get(c); while (c!='\n'); + } + if (i%npcol) do file.get(c); while (c!='\n'); + + if (i <= n) { + throw ArpackError(ArpackError::UNEXPECTED_EOF, "ARhbMatrix"); + } + + // Reading row indices. + + irow = new ARINT[nnz]; + firow++; + i = 0; + while ((i < nnz) && (file.get((char*)num,firow,'\n'))) { + irow[i++] = atoi((char*)num)-1; + if (!(i%nirow)) do file.get(c); while (c!='\n'); + } + if (i%nirow) do file.get(c); while (c!='\n'); + + if (i < nnz) { + throw ArpackError(ArpackError::UNEXPECTED_EOF, "ARhbMatrix"); + } + + // Reading matrix elements. + + fval++; + val = new ARTYPE[nnz]; + i = 0; + j = 0; + while ((i < nnz) && (ReadEntry(file, nval, fval, j, value))) { + val[i++] = value; + } + if (j%nval) do file.get(c); while (c!='\n'); + + if (i < nnz) { + throw ArpackError(ArpackError::UNEXPECTED_EOF, "ARhbMatrix"); + } + + // Closing file and reporting success. + + file.close(); + +} // Define. + + +template +ARhbMatrix::ARhbMatrix() +{ + + m = n = nnz = 0; + title[0]= '\0'; + name[0] = '\0'; + type[0] = '\0'; + pcol = NULL; + irow = NULL; + val = NULL; + +} // Short constructor. + + +template +ARhbMatrix::~ARhbMatrix() +{ + + if (irow != NULL) delete[] irow; + if (pcol != NULL) delete[] pcol; + if (val != NULL) delete[] val; + +} // Destructor. + + +#endif // ARHBMAT_H + diff --git a/external/arpack++/include/arlcomp.h b/external/arpack++/include/arlcomp.h new file mode 100644 index 000000000..8b9b5fbc9 --- /dev/null +++ b/external/arpack++/include/arlcomp.h @@ -0,0 +1,153 @@ +/* + ARPACK++ v1.2 2/20/2000 + c++ interface to ARPACK code. + + MODULE ARLComp.h. + ALTERED copy of dcomplex.h and scomplex.h (from SuperLU package). + Structure complex was renamed to lscomplex. + Structure doublecomplex was renamed to ldcomplex. +*/ + +/* + * -- SuperLU routine (version 2.0) -- + * Univ. of California Berkeley, Xerox Palo Alto Research Center, + * and Lawrence Berkeley National Lab. + * November 15, 1997 + * + * + */ +#ifndef __SUPERLU_DCOMPLEX /* allow multiple inclusions */ +#define __SUPERLU_DCOMPLEX + +/* + * This header file is to be included in source files z*.c + */ +#ifndef DCOMPLEX_INCLUDE +#define DCOMPLEX_INCLUDE + +typedef struct { double r, i; } ldcomplex; + + +/* Macro definitions */ + +/*! \brief Complex Addition c = a + b */ +#define z_add(c, a, b) { (c)->r = (a)->r + (b)->r; \ + (c)->i = (a)->i + (b)->i; } + +/*! \brief Complex Subtraction c = a - b */ +#define z_sub(c, a, b) { (c)->r = (a)->r - (b)->r; \ + (c)->i = (a)->i - (b)->i; } + +/*! \brief Complex-Double Multiplication */ +#define zd_mult(c, a, b) { (c)->r = (a)->r * (b); \ + (c)->i = (a)->i * (b); } + +/*! \brief Complex-Complex Multiplication */ +#define zz_mult(c, a, b) { \ + double cr, ci; \ + cr = (a)->r * (b)->r - (a)->i * (b)->i; \ + ci = (a)->i * (b)->r + (a)->r * (b)->i; \ + (c)->r = cr; \ + (c)->i = ci; \ + } + +#define zz_conj(a, b) { \ + (a)->r = (b)->r; \ + (a)->i = -((b)->i); \ + } + +/*! \brief Complex equality testing */ +#define z_eq(a, b) ( (a)->r == (b)->r && (a)->i == (b)->i ) + + +#ifdef __cplusplus +extern "C" { +#endif + +/* Prototypes for functions in dcomplex.c */ +void z_div(ldcomplex *, ldcomplex *, ldcomplex *); +double z_abs(ldcomplex *); /* exact */ +double z_abs1(ldcomplex *); /* approximate */ +void z_exp(ldcomplex *, ldcomplex *); +void d_cnjg(ldcomplex *r, ldcomplex *z); +double d_imag(ldcomplex *); +ldcomplex z_sgn(ldcomplex *); +ldcomplex z_sqrt(ldcomplex *); + + +#ifdef __cplusplus + } +#endif + +#endif + +#endif /* __SUPERLU_DCOMPLEX */ + + +#ifndef __SUPERLU_SCOMPLEX /* allow multiple inclusions */ +#define __SUPERLU_SCOMPLEX + +/* + * This header file is to be included in source files c*.c + */ +#ifndef SCOMPLEX_INCLUDE +#define SCOMPLEX_INCLUDE + +typedef struct { float r, i; } lscomplex; + + +/* Macro definitions */ + +/*! \brief Complex Addition c = a + b */ +#define c_add(c, a, b) { (c)->r = (a)->r + (b)->r; \ + (c)->i = (a)->i + (b)->i; } + +/*! \brief Complex Subtraction c = a - b */ +#define c_sub(c, a, b) { (c)->r = (a)->r - (b)->r; \ + (c)->i = (a)->i - (b)->i; } + +/*! \brief Complex-Double Multiplication */ +#define cs_mult(c, a, b) { (c)->r = (a)->r * (b); \ + (c)->i = (a)->i * (b); } + +/*! \brief Complex-Complex Multiplication */ +#define cc_mult(c, a, b) { \ + float cr, ci; \ + cr = (a)->r * (b)->r - (a)->i * (b)->i; \ + ci = (a)->i * (b)->r + (a)->r * (b)->i; \ + (c)->r = cr; \ + (c)->i = ci; \ + } + +#define cc_conj(a, b) { \ + (a)->r = (b)->r; \ + (a)->i = -((b)->i); \ + } + +/*! \brief Complex equality testing */ +#define c_eq(a, b) ( (a)->r == (b)->r && (a)->i == (b)->i ) + + +#ifdef __cplusplus +extern "C" { +#endif + +/* Prototypes for functions in scomplex.c */ +void c_div(lscomplex *, lscomplex *, lscomplex *); +double c_abs(lscomplex *); /* exact */ +double c_abs1(lscomplex *); /* approximate */ +void c_exp(lscomplex *, lscomplex *); +void r_cnjg(lscomplex *, lscomplex *); +double r_imag(lscomplex *); +lscomplex c_sgn(lscomplex *); +lscomplex c_sqrt(lscomplex *); + + +#ifdef __cplusplus + } +#endif + +#endif + +#endif /* __SUPERLU_SCOMPLEX */ + diff --git a/external/arpack++/include/arlgcomp.h b/external/arpack++/include/arlgcomp.h new file mode 100644 index 000000000..b46921643 --- /dev/null +++ b/external/arpack++/include/arlgcomp.h @@ -0,0 +1,204 @@ +/* + ARPACK++ v1.2 2/20/2000 + c++ interface to ARPACK code. + + MODULE ARLGComp.h. + Arpack++ class ARluCompGenEig definition + (superlu version). + + ARPACK Authors + Richard Lehoucq + Danny Sorensen + Chao Yang + Dept. of Computational & Applied Mathematics + Rice University + Houston, Texas +*/ + +#ifndef ARLGCOMP_H +#define ARLGCOMP_H + +#include +#include +#include "arch.h" +#include "arlnsmat.h" +#include "arlnspen.h" +#include "arrseig.h" +#include "argcomp.h" + + +template +class ARluCompGenEig: + public virtual + ARCompGenEig, ARFLOAT >, + ARluNonSymPencil, ARFLOAT > > { + + private: + + // a) Data structure used to store matrices. + + ARluNonSymPencil, ARFLOAT > Pencil; + + // b) Protected functions: + + virtual void Copy(const ARluCompGenEig& other); + // Makes a deep copy of "other" over "this" object. + // Old values are not deleted (this function is to be used + // by the copy constructor and the assignment operator only). + + + public: + + // c) Public functions: + + // c.1) Functions that allow changes in problem parameters. + + virtual void ChangeShift(arcomplex sigmap); + + virtual void SetRegularMode(); + + virtual void SetShiftInvertMode(arcomplex sigmap); + + // c.2) Constructors and destructor. + + ARluCompGenEig() { } + // Short constructor. + + ARluCompGenEig(int nevp, ARluNonSymMatrix, ARFLOAT>& A, + ARluNonSymMatrix, ARFLOAT>& B, + const std::string& whichp = "LM", int ncvp = 0, + ARFLOAT tolp = 0.0, int maxitp = 0, + arcomplex* residp = NULL, bool ishiftp = true); + // Long constructor (regular mode). + + ARluCompGenEig(int nevp, ARluNonSymMatrix, ARFLOAT>& A, + ARluNonSymMatrix, ARFLOAT>& B, + arcomplex sigma, const std::string& whichp = "LM", + int ncvp = 0, ARFLOAT tolp = 0.0, int maxitp = 0, + arcomplex* residp = NULL, bool ishiftp = true); + // Long constructor (shift and invert mode). + + ARluCompGenEig(const ARluCompGenEig& other) { Copy(other); } + // Copy constructor. + + virtual ~ARluCompGenEig() { } + + // d) Operators. + + ARluCompGenEig& operator=(const ARluCompGenEig& other); + // Assignment operator. + +}; // class ARluCompGenEig. + + +// ------------------------------------------------------------------------ // +// ARluCompGenEig member functions definition. // +// ------------------------------------------------------------------------ // + + +template +inline void ARluCompGenEig:: +Copy(const ARluCompGenEig& other) +{ + + ARCompGenEig, ARFLOAT >, + ARluNonSymPencil, ARFLOAT> >:: Copy(other); + Pencil = other.Pencil; + this->objOP = &Pencil; + this->objB = &Pencil; + if (this->mode > 2) this->objOP->FactorAsB(this->sigmaR); + +} // Copy. + + +template +inline void ARluCompGenEig::ChangeShift(arcomplex sigmap) +{ + + this->objOP->FactorAsB(sigmap); + ARrcStdEig >::ChangeShift(sigmap); + +} // ChangeShift. + + +template +inline void ARluCompGenEig::SetRegularMode() +{ + + ARStdEig, + ARluNonSymPencil, ARFLOAT> >:: + SetRegularMode(&Pencil, + &ARluNonSymPencil, ARFLOAT>::MultInvBAv); + +} // SetRegularMode. + + +template +inline void ARluCompGenEig:: +SetShiftInvertMode(arcomplex sigmap) +{ + + ARCompGenEig, ARFLOAT>, + ARluNonSymPencil, ARFLOAT> >:: + SetShiftInvertMode(sigmap, &Pencil, + &ARluNonSymPencil,ARFLOAT>::MultInvAsBv); + +} // SetShiftInvertMode. + + +template +inline ARluCompGenEig:: +ARluCompGenEig(int nevp, ARluNonSymMatrix, ARFLOAT>& A, + ARluNonSymMatrix, ARFLOAT>& B, const std::string& whichp, + int ncvp, ARFLOAT tolp, int maxitp, + arcomplex* residp, bool ishiftp) + +{ + + Pencil.DefineMatrices(A, B); + this->NoShift(); + this->DefineParameters(A.ncols(), nevp, &Pencil, + &ARluNonSymPencil, ARFLOAT>::MultInvBAv, + &Pencil, + &ARluNonSymPencil, ARFLOAT>::MultBv, + whichp, ncvp, tolp, maxitp, residp, ishiftp); + +} // Long constructor (regular mode). + + +template +inline ARluCompGenEig:: +ARluCompGenEig(int nevp, ARluNonSymMatrix, ARFLOAT>& A, + ARluNonSymMatrix, ARFLOAT>& B, + arcomplex sigmap, const std::string& whichp, int ncvp, + ARFLOAT tolp, int maxitp, arcomplex* residp, + bool ishiftp) + +{ + + Pencil.DefineMatrices(A, B); + this->DefineParameters(A.ncols(), nevp, &Pencil, + &ARluNonSymPencil, ARFLOAT>::MultInvAsBv, + &Pencil, + &ARluNonSymPencil, ARFLOAT>::MultBv, + whichp, ncvp, tolp, maxitp, residp, ishiftp); + SetShiftInvertMode(sigmap); + +} // Long constructor (shift and invert mode). + + +template +ARluCompGenEig& ARluCompGenEig:: +operator=(const ARluCompGenEig& other) +{ + + if (this != &other) { // Stroustrup suggestion. + this->ClearMem(); + Copy(other); + } + return *this; + +} // operator=. + + +#endif // ARLGCOMP_H diff --git a/external/arpack++/include/arlgnsym.h b/external/arpack++/include/arlgnsym.h new file mode 100644 index 000000000..ea9b53e27 --- /dev/null +++ b/external/arpack++/include/arlgnsym.h @@ -0,0 +1,252 @@ +/* + ARPACK++ v1.2 2/20/2000 + c++ interface to ARPACK code. + + MODULE ARLGNSym.h. + Arpack++ class ARluNonSymGenEig definition + (SuperLU version). + + ARPACK Authors + Richard Lehoucq + Danny Sorensen + Chao Yang + Dept. of Computational & Applied Mathematics + Rice University + Houston, Texas +*/ + +#ifndef ARLGNSYM_H +#define ARLGNSYM_H + +#include +#include +#include "arch.h" +#include "arlnsmat.h" +#include "arlnspen.h" +#include "argnsym.h" + + +template +class ARluNonSymGenEig: + public virtual ARNonSymGenEig, + ARluNonSymPencil > { + + protected: + + // a) Data structure used to store matrices. + + ARluNonSymPencil Pencil; + + // b) Protected functions: + + virtual void Copy(const ARluNonSymGenEig& other); + // Makes a deep copy of "other" over "this" object. + // Old values are not deleted (this function is to be used + // by the copy constructor and the assignment operator only). + + + public: + + // c) Public functions: + + // c.1) Functions that allow changes in problem parameters. + + virtual void ChangeShift(ARFLOAT sigmaRp, ARFLOAT sigmaIp = 0.0); + + virtual void SetRegularMode(); + + virtual void SetShiftInvertMode(ARFLOAT sigmap); + + virtual void SetComplexShiftMode(char partp,ARFLOAT sigmaRp,ARFLOAT sigmaIp); + + // c.2) Constructors and destructor. + + ARluNonSymGenEig() { } + // Short constructor. + + ARluNonSymGenEig(int nevp, ARluNonSymMatrix& A, + ARluNonSymMatrix& B, const std::string& whichp = "LM", + int ncvp = 0, ARFLOAT tolp = 0.0, int maxitp = 0, + ARFLOAT* residp = NULL, bool ishiftp = true); + // Long constructor (regular mode). + + ARluNonSymGenEig(int nevp, ARluNonSymMatrix& A, + ARluNonSymMatrix& B, ARFLOAT sigma, + const std::string& whichp = "LM", int ncvp = 0, + ARFLOAT tolp = 0.0, int maxitp = 0, + ARFLOAT* residp = NULL, bool ishiftp = true); + // Long constructor (real shift and invert mode). + + ARluNonSymGenEig(int nevp, ARluNonSymMatrix& A, + ARluNonSymMatrix& B, char partp, + ARFLOAT sigmaRp, ARFLOAT sigmaIp, const std::string& whichp = "LM", + int ncvp = 0, ARFLOAT tolp = 0.0, int maxitp = 0, + ARFLOAT* residp = NULL, bool ishiftp = true); + // Long constructor (complex shift and invert mode). + + ARluNonSymGenEig(const ARluNonSymGenEig& other) { Copy(other); } + // Copy constructor. + + virtual ~ARluNonSymGenEig() { } + // Destructor. + + // d) Operators. + + ARluNonSymGenEig& operator=(const ARluNonSymGenEig& other); + // Assignment operator. + +}; // class ARluNonSymGenEig. + + +// ------------------------------------------------------------------------ // +// ARluNonSymGenEig member functions definition. // +// ------------------------------------------------------------------------ // + + +template +inline void ARluNonSymGenEig:: +Copy(const ARluNonSymGenEig& other) +{ + + ARNonSymGenEig, + ARluNonSymPencil >:: Copy(other); + Pencil = other.Pencil; + this->objOP = &Pencil; + this->objB = &Pencil; + this->objA = &Pencil; + if (this->mode > 2) { + if (this->sigmaI == 0.0) { + this->objOP->FactorAsB(this->sigmaR); + } + else { + this->objOP->FactorAsB(this->sigmaR, this->sigmaI, this->part); + } + } + +} // Copy. + + +template +inline void ARluNonSymGenEig:: +ChangeShift(ARFLOAT sigmaRp, ARFLOAT sigmaIp) +{ + + if (sigmaIp == 0.0) { + this->objOP->FactorAsB(sigmaRp); + } + else { + this->objOP->FactorAsB(sigmaRp, sigmaIp, this->part); + } + ARrcNonSymGenEig::ChangeShift(sigmaRp, sigmaIp); + +} // ChangeShift. + + +template +inline void ARluNonSymGenEig::SetRegularMode() +{ + + ARStdEig >:: + SetRegularMode(&Pencil, &ARluNonSymPencil::MultInvBAv); + +} // SetRegularMode. + + +template +inline void ARluNonSymGenEig::SetShiftInvertMode(ARFLOAT sigmap) +{ + + ARNonSymGenEig, + ARluNonSymPencil >:: + SetShiftInvertMode(sigmap, &Pencil, + &ARluNonSymPencil::MultInvAsBv); + +} // SetShiftInvertMode. + + +template +inline void ARluNonSymGenEig:: +SetComplexShiftMode(char partp, ARFLOAT sigmaRp, ARFLOAT sigmaIp) +{ + + ARNonSymGenEig, + ARluNonSymPencil >:: + SetComplexShiftMode(partp, sigmaRp, sigmaIp, &Pencil, + &ARluNonSymPencil::MultInvAsBv, + &Pencil, &ARluNonSymPencil::MultAv); + +} // SetComplexShiftMode. + + +template +inline ARluNonSymGenEig:: +ARluNonSymGenEig(int nevp, ARluNonSymMatrix& A, + ARluNonSymMatrix& B, const std::string& whichp, int ncvp, + ARFLOAT tolp, int maxitp, ARFLOAT* residp, bool ishiftp) + +{ + + Pencil.DefineMatrices(A, B); + this->NoShift(); + this->DefineParameters(A.ncols(), nevp, &Pencil, + &ARluNonSymPencil::MultInvBAv, &Pencil, + &ARluNonSymPencil::MultBv, whichp, + ncvp, tolp, maxitp, residp, ishiftp); + +} // Long constructor (regular mode). + + +template +inline ARluNonSymGenEig:: +ARluNonSymGenEig(int nevp, ARluNonSymMatrix& A, + ARluNonSymMatrix& B, ARFLOAT sigmap, + const std::string& whichp, int ncvp, ARFLOAT tolp, + int maxitp, ARFLOAT* residp, bool ishiftp) + +{ + + Pencil.DefineMatrices(A, B); + this->DefineParameters(A.ncols(), nevp, &Pencil, + &ARluNonSymPencil::MultInvAsBv, &Pencil, + &ARluNonSymPencil::MultBv, whichp, + ncvp, tolp, maxitp, residp, ishiftp); + SetShiftInvertMode(sigmap); + +} // Long constructor (real shift and invert mode). + + +template +inline ARluNonSymGenEig:: +ARluNonSymGenEig(int nevp, ARluNonSymMatrix& A, + ARluNonSymMatrix& B, + char partp, ARFLOAT sigmaRp, + ARFLOAT sigmaIp, const std::string& whichp, int ncvp, ARFLOAT tolp, + int maxitp, ARFLOAT* residp, bool ishiftp) + +{ + + Pencil.DefineMatrices(A, B); + this->DefineParameters(A.ncols(), nevp, &Pencil, + &ARluNonSymPencil::MultInvAsBv, &Pencil, + &ARluNonSymPencil::MultBv, whichp, + ncvp, tolp, maxitp, residp, ishiftp); + SetComplexShiftMode(partp, sigmaRp, sigmaIp); + +} // Long constructor (complex shift and invert mode). + + +template +ARluNonSymGenEig& ARluNonSymGenEig:: +operator=(const ARluNonSymGenEig& other) +{ + + if (this != &other) { // Stroustrup suggestion. + this->ClearMem(); + Copy(other); + } + return *this; + +} // operator=. + + +#endif // ARLGNSYM_H diff --git a/external/arpack++/include/arlgsym.h b/external/arpack++/include/arlgsym.h new file mode 100644 index 000000000..00f4a73cc --- /dev/null +++ b/external/arpack++/include/arlgsym.h @@ -0,0 +1,235 @@ +/* + ARPACK++ v1.2 2/20/2000 + c++ interface to ARPACK code. + + MODULE ARLGSym.h. + Arpack++ class ARluSymGenEig definition + (SuperLU version). + + ARPACK Authors + Richard Lehoucq + Danny Sorensen + Chao Yang + Kristi Maschhoff + Dept. of Computational & Applied Mathematics + Rice University + Houston, Texas +*/ + +#ifndef ARLGSYM_H +#define ARLGSYM_H + +#include +#include +#include "arch.h" +#include "arlsmat.h" +#include "arlspen.h" +#include "argsym.h" + + +template +class ARluSymGenEig: + public virtual ARSymGenEig, + ARluSymPencil > { + + private: + + // a) Data structure used to store matrices. + + ARluSymPencil Pencil; + + // b) Protected functions: + + virtual void Copy(const ARluSymGenEig& other); + // Makes a deep copy of "other" over "this" object. + // Old values are not deleted (this function is to be used + // by the copy constructor and the assignment operator only). + + + public: + + // c) Public functions: + + // c.1) Functions that allow changes in problem parameters. + + virtual void ChangeShift(ARFLOAT sigmap); + + virtual void SetRegularMode(); + + virtual void SetShiftInvertMode(ARFLOAT sigmap); + + virtual void SetBucklingMode(ARFLOAT sigmap); + + virtual void SetCayleyMode(ARFLOAT sigmap); + + // c.2) Constructors and destructor. + + ARluSymGenEig() { } + // Short constructor. + + ARluSymGenEig(int nevp, ARluSymMatrix& A, + ARluSymMatrix& B, const std::string& whichp = "LM", + int ncvp = 0, ARFLOAT tolp = 0.0, int maxitp = 0, + ARFLOAT* residp = NULL, bool ishiftp = true); + // Long constructor (regular mode). + + ARluSymGenEig(char InvertModep, int nevp, ARluSymMatrix& A, + ARluSymMatrix& B, ARFLOAT sigma, const std::string& whichp = "LM", + int ncvp = 0, ARFLOAT tolp = 0.0, int maxitp = 0, + ARFLOAT* residp = NULL, bool ishiftp = true); + // Long constructor (shift and invert, buckling and Cayley modes). + + ARluSymGenEig(const ARluSymGenEig& other) { Copy(other); } + // Copy constructor. + + virtual ~ARluSymGenEig() { } + // Destructor. + + // d) Operators. + + ARluSymGenEig& operator=(const ARluSymGenEig& other); + // Assignment operator. + +}; // class ARluSymGenEig. + + +// ------------------------------------------------------------------------ // +// ARluSymGenEig member functions definition. // +// ------------------------------------------------------------------------ // + + +template +inline void ARluSymGenEig:: +Copy(const ARluSymGenEig& other) +{ + + ARSymGenEig, + ARluSymPencil >:: Copy(other); + Pencil = other.Pencil; + this->objOP = &Pencil; + this->objB = &Pencil; + this->objA = &Pencil; + if (this->mode > 2) this->objOP->FactorAsB(this->sigmaR); + +} // Copy. + + +template +inline void ARluSymGenEig::ChangeShift(ARFLOAT sigmap) +{ + + this->objOP->FactorAsB(sigmap); + ARrcSymGenEig::ChangeShift(sigmap); + +} // ChangeShift. + + +template +inline void ARluSymGenEig::SetRegularMode() +{ + + ARStdEig >:: + SetRegularMode(&Pencil, &ARluSymPencil::MultInvBAv); + +} // SetRegularMode. + + +template +inline void ARluSymGenEig:: +SetShiftInvertMode(ARFLOAT sigmap) +{ + + ARSymGenEig, ARluSymPencil >:: + SetShiftInvertMode(sigmap, &Pencil, &ARluSymPencil::MultInvAsBv); + this->ChangeMultBx(&Pencil, &ARluSymPencil::MultBv); + +} // SetShiftInvertMode. + + +template +inline void ARluSymGenEig:: +SetBucklingMode(ARFLOAT sigmap) +{ + + ARSymGenEig, ARluSymPencil >:: + SetBucklingMode(sigmap, &Pencil, &ARluSymPencil::MultInvAsBv); + this->ChangeMultBx(&Pencil, &ARluSymPencil::MultAv); + +} // SetBucklingMode. + + +template +inline void ARluSymGenEig:: +SetCayleyMode(ARFLOAT sigmap) +{ + + ARSymGenEig, ARluSymPencil >:: + SetCayleyMode(sigmap, &Pencil, &ARluSymPencil::MultInvAsBv, + &Pencil, &ARluSymPencil::MultAv); + this->ChangeMultBx(&Pencil, &ARluSymPencil::MultBv); + +} // SetCayleyMode. + + +template +inline ARluSymGenEig:: +ARluSymGenEig(int nevp, ARluSymMatrix& A, + ARluSymMatrix& B, const std::string& whichp, int ncvp, + ARFLOAT tolp, int maxitp, ARFLOAT* residp, bool ishiftp) + +{ + + Pencil.DefineMatrices(A, B); + this->InvertMode = 'S'; + this->NoShift(); + this->DefineParameters(A.ncols(), nevp, &Pencil, + &ARluSymPencil::MultInvBAv, &Pencil, + &ARluSymPencil::MultBv, whichp, + ncvp, tolp, maxitp, residp, ishiftp); + +} // Long constructor (regular mode). + + +template +inline ARluSymGenEig:: +ARluSymGenEig(char InvertModep, int nevp, ARluSymMatrix& A, + ARluSymMatrix& B, ARFLOAT sigmap, + const std::string& whichp, int ncvp, ARFLOAT tolp, + int maxitp, ARFLOAT* residp, bool ishiftp) + +{ + + Pencil.DefineMatrices(A, B); + this->DefineParameters(A.ncols(), nevp, &Pencil, + &ARluSymPencil::MultInvAsBv, &Pencil, + &ARluSymPencil::MultBv, whichp, + ncvp, tolp, maxitp, residp, ishiftp); + this->InvertMode = this->CheckInvertMode(InvertModep); + switch (this->InvertMode) { + case 'B': // Buckling mode. + this->ChangeMultBx(&Pencil, &ARluSymPencil::MultAv); + case 'S': // Shift and invert mode. + ChangeShift(sigmap); + break; + case 'C': // Cayley mode. + SetCayleyMode(sigmap); + } + +} // Long constructor (shift and invert, buckling and Cayley modes). + + +template +ARluSymGenEig& ARluSymGenEig:: +operator=(const ARluSymGenEig& other) +{ + + if (this != &other) { // Stroustrup suggestion. + this->ClearMem(); + Copy(other); + } + return *this; + +} // operator=. + + +#endif // ARLGSYM_H diff --git a/external/arpack++/include/arlnames.h b/external/arpack++/include/arlnames.h new file mode 100644 index 000000000..1664f1733 --- /dev/null +++ b/external/arpack++/include/arlnames.h @@ -0,0 +1,464 @@ +/* + ARPACK++ v1.2 2/20/2000 + c++ interface to ARPACK code. + + MODULE ARLNames.h. + Unaltered copy of Cnames.h (from SuperLU package). +*/ + +/* + * -- SuperLU routine (version 2.0) -- + * Univ. of California Berkeley, Xerox Palo Alto Research Center, + * and Lawrence Berkeley National Lab. + * November 1, 1997 + * + */ +#ifndef __SUPERLU_CNAMES /* allow multiple inclusions */ +#define __SUPERLU_CNAMES + +/* + * These macros define how C routines will be called. ADD_ assumes that + * they will be called by fortran, which expects C routines to have an + * underscore postfixed to the name (Suns, and the Intel expect this). + * NOCHANGE indicates that fortran will be calling, and that it expects + * the name called by fortran to be identical to that compiled by the C + * (RS6K's do this). UPCASE says it expects C routines called by fortran + * to be in all upcase (CRAY wants this). + */ + +#define ADD_ 0 +#define ADD__ 1 +#define NOCHANGE 2 +#define UPCASE 3 +#define OLD_CRAY 4 +#define C_CALL 5 + +#ifdef UpCase +#define F77_CALL_C UPCASE +#endif + +#ifdef NoChange +#define F77_CALL_C NOCHANGE +#endif + +#ifdef Add_ +#define F77_CALL_C ADD_ +#endif + +#ifdef Add__ +#define F77_CALL_C ADD__ +#endif + +#ifdef _CRAY +#define F77_CALL_C OLD_CRAY +#endif + +/* Default */ +#ifndef F77_CALL_C +#define F77_CALL_C ADD_ +#endif + + +#if (F77_CALL_C == ADD_) +/* + * These defines set up the naming scheme required to have a fortran 77 + * routine call a C routine + * No redefinition necessary to have following Fortran to C interface: + * FORTRAN CALL C DECLARATION + * call dgemm(...) void dgemm_(...) + * + * This is the default. + */ + +#endif + +#if (F77_CALL_C == ADD__) +/* + * These defines set up the naming scheme required to have a fortran 77 + * routine call a C routine + * for following Fortran to C interface: + * FORTRAN CALL C DECLARATION + * call dgemm(...) void dgemm__(...) + */ +/* BLAS */ +#define sswap_ sswap__ +#define saxpy_ saxpy__ +#define sasum_ sasum__ +#define isamax_ isamax__ +#define scopy_ scopy__ +#define sscal_ sscal__ +#define sger_ sger__ +#define snrm2_ snrm2__ +#define ssymv_ ssymv__ +#define sdot_ sdot__ +#define saxpy_ saxpy__ +#define ssyr2_ ssyr2__ +#define srot_ srot__ +#define sgemv_ sgemv__ +#define strsv_ strsv__ +#define sgemm_ sgemm__ +#define strsm_ strsm__ + +#define dswap_ dswap__ +#define daxpy_ daxpy__ +#define dasum_ dasum__ +#define idamax_ idamax__ +#define dcopy_ dcopy__ +#define dscal_ dscal__ +#define dger_ dger__ +#define dnrm2_ dnrm2__ +#define dsymv_ dsymv__ +#define ddot_ ddot__ +#define dsyr2_ dsyr2__ +#define drot_ drot__ +#define dgemv_ dgemv__ +#define dtrsv_ dtrsv__ +#define dgemm_ dgemm__ +#define dtrsm_ dtrsm__ + +#define cswap_ cswap__ +#define caxpy_ caxpy__ +#define scasum_ scasum__ +#define icamax_ icamax__ +#define ccopy_ ccopy__ +#define cscal_ cscal__ +#define scnrm2_ scnrm2__ +#define caxpy_ caxpy__ +#define cgemv_ cgemv__ +#define ctrsv_ ctrsv__ +#define cgemm_ cgemm__ +#define ctrsm_ ctrsm__ +#define cgerc_ cgerc__ +#define chemv_ chemv__ +#define cher2_ cher2__ + +#define zswap_ zswap__ +#define zaxpy_ zaxpy__ +#define dzasum_ dzasum__ +#define izamax_ izamax__ +#define zcopy_ zcopy__ +#define zscal_ zscal__ +#define dznrm2_ dznrm2__ +#define zaxpy_ zaxpy__ +#define zgemv_ zgemv__ +#define ztrsv_ ztrsv__ +#define zgemm_ zgemm__ +#define ztrsm_ ztrsm__ +#define zgerc_ zgerc__ +#define zhemv_ zhemv__ +#define zher2_ zher2__ + +/* LAPACK */ +#define dlamch_ dlamch__ +#define slamch_ slamch__ +#define xerbla_ xerbla__ +#define lsame_ lsame__ +#define dlacon_ dlacon__ +#define slacon_ slacon__ +#define icmax1_ icmax1__ +#define scsum1_ scsum1__ +#define clacon_ clacon__ +#define dzsum1_ dzsum1__ +#define izmax1_ izmax1__ +#define zlacon_ zlacon__ + +/* Fortran interface */ +#define c_bridge_dgssv_ c_bridge_dgssv__ +#define c_fortran_sgssv_ c_fortran_sgssv__ +#define c_fortran_dgssv_ c_fortran_dgssv__ +#define c_fortran_cgssv_ c_fortran_cgssv__ +#define c_fortran_zgssv_ c_fortran_zgssv__ +#endif + +#if (F77_CALL_C == UPCASE) +/* + * These defines set up the naming scheme required to have a fortran 77 + * routine call a C routine + * following Fortran to C interface: + * FORTRAN CALL C DECLARATION + * call dgemm(...) void DGEMM(...) + */ +/* BLAS */ +#define sswap_ SSWAP +#define saxpy_ SAXPY +#define sasum_ SASUM +#define isamax_ ISAMAX +#define scopy_ SCOPY +#define sscal_ SSCAL +#define sger_ SGER +#define snrm2_ SNRM2 +#define ssymv_ SSYMV +#define sdot_ SDOT +#define saxpy_ SAXPY +#define ssyr2_ SSYR2 +#define srot_ SROT +#define sgemv_ SGEMV +#define strsv_ STRSV +#define sgemm_ SGEMM +#define strsm_ STRSM + +#define dswap_ DSWAP +#define daxpy_ DAXPY +#define dasum_ DASUM +#define idamax_ IDAMAX +#define dcopy_ DCOPY +#define dscal_ DSCAL +#define dger_ DGER +#define dnrm2_ DNRM2 +#define dsymv_ DSYMV +#define ddot_ DDOT +#define dsyr2_ DSYR2 +#define drot_ DROT +#define dgemv_ DGEMV +#define dtrsv_ DTRSV +#define dgemm_ DGEMM +#define dtrsm_ DTRSM + +#define cswap_ CSWAP +#define caxpy_ CAXPY +#define scasum_ SCASUM +#define icamax_ ICAMAX +#define ccopy_ CCOPY +#define cscal_ CSCAL +#define scnrm2_ SCNRM2 +#define cgemv_ CGEMV +#define ctrsv_ CTRSV +#define cgemm_ CGEMM +#define ctrsm_ CTRSM +#define cgerc_ CGERC +#define chemv_ CHEMV +#define cher2_ CHER2 + +#define zswap_ ZSWAP +#define zaxpy_ ZAXPY +#define dzasum_ DZASUM +#define izamax_ IZAMAX +#define zcopy_ ZCOPY +#define zscal_ ZSCAL +#define dznrm2_ DZNRM2 +#define zgemv_ ZGEMV +#define ztrsv_ ZTRSV +#define zgemm_ ZGEMM +#define ztrsm_ ZTRSM +#define zgerc_ ZGERC +#define zhemv_ ZHEMV +#define zher2_ ZHER2 + +/* LAPACK */ +#define dlamch_ DLAMCH +#define slamch_ SLAMCH +#define xerbla_ XERBLA +#define lsame_ LSAME +#define dlacon_ DLACON +#define slacon_ SLACON +#define icmax1_ ICMAX1 +#define scsum1_ SCSUM1 +#define clacon_ CLACON +#define dzsum1_ DZSUM1 +#define izmax1_ IZMAX1 +#define zlacon_ ZLACON + +/* Fortran interface */ +#define c_bridge_dgssv_ C_BRIDGE_DGSSV +#define c_fortran_sgssv_ C_FORTRAN_SGSSV +#define c_fortran_dgssv_ C_FORTRAN_DGSSV +#define c_fortran_cgssv_ C_FORTRAN_CGSSV +#define c_fortran_zgssv_ C_FORTRAN_ZGSSV +#endif + + +#if (F77_CALL_C == OLD_CRAY) +/* + * These defines set up the naming scheme required to have a fortran 77 + * routine call a C routine + * following Fortran to C interface: + * FORTRAN CALL C DECLARATION + * call dgemm(...) void SGEMM(...) + */ +/* BLAS */ +#define sswap_ SSWAP +#define saxpy_ SAXPY +#define sasum_ SASUM +#define isamax_ ISAMAX +#define scopy_ SCOPY +#define sscal_ SSCAL +#define sger_ SGER +#define snrm2_ SNRM2 +#define ssymv_ SSYMV +#define sdot_ SDOT +#define ssyr2_ SSYR2 +#define srot_ SROT +#define sgemv_ SGEMV +#define strsv_ STRSV +#define sgemm_ SGEMM +#define strsm_ STRSM + +#define dswap_ SSWAP +#define daxpy_ SAXPY +#define dasum_ SASUM +#define idamax_ ISAMAX +#define dcopy_ SCOPY +#define dscal_ SSCAL +#define dger_ SGER +#define dnrm2_ SNRM2 +#define dsymv_ SSYMV +#define ddot_ SDOT +#define dsyr2_ SSYR2 +#define drot_ SROT +#define dgemv_ SGEMV +#define dtrsv_ STRSV +#define dgemm_ SGEMM +#define dtrsm_ STRSM + +#define cswap_ CSWAP +#define caxpy_ CAXPY +#define scasum_ SCASUM +#define icamax_ ICAMAX +#define ccopy_ CCOPY +#define cscal_ CSCAL +#define scnrm2_ SCNRM2 +#define caxpy_ CAXPY +#define cgemv_ CGEMV +#define ctrsv_ CTRSV +#define cgemm_ CGEMM +#define ctrsm_ CTRSM +#define cgerc_ CGERC +#define chemv_ CHEMV +#define cher2_ CHER2 + +#define zswap_ ZSWAP +#define zaxpy_ ZAXPY +#define dzasum_ DZASUM +#define izamax_ IZAMAX +#define zcopy_ ZCOPY +#define zscal_ ZSCAL +#define dznrm2_ DZNRM2 +#define zgemv_ ZGEMV +#define ztrsv_ ZTRSV +#define zgemm_ ZGEMM +#define ztrsm_ ZTRSM +#define zgerc_ ZGERC +#define zhemv_ ZHEMV +#define zher2_ ZHER2 + +/* LAPACK */ +#define dlamch_ DLAMCH +#define slamch_ SLAMCH +#define xerbla_ XERBLA +#define lsame_ LSAME +#define dlacon_ DLACON +#define slacon_ SLACON +#define icmax1_ ICMAX1 +#define scsum1_ SCSUM1 +#define clacon_ CLACON +#define dzsum1_ DZSUM1 +#define izmax1_ IZMAX1 +#define zlacon_ ZLACON + +/* Fortran interface */ +#define c_bridge_dgssv_ C_BRIDGE_DGSSV +#define c_fortran_sgssv_ C_FORTRAN_SGSSV +#define c_fortran_dgssv_ C_FORTRAN_DGSSV +#define c_fortran_cgssv_ C_FORTRAN_CGSSV +#define c_fortran_zgssv_ C_FORTRAN_ZGSSV +#endif + + +#if (F77_CALL_C == NOCHANGE) +/* + * These defines set up the naming scheme required to have a fortran 77 + * routine call a C routine + * for following Fortran to C interface: + * FORTRAN CALL C DECLARATION + * call dgemm(...) void dgemm(...) + */ +/* BLAS */ +#define sswap_ sswap +#define saxpy_ saxpy +#define sasum_ sasum +#define isamax_ isamax +#define scopy_ scopy +#define sscal_ sscal +#define sger_ sger +#define snrm2_ snrm2 +#define ssymv_ ssymv +#define sdot_ sdot +#define saxpy_ saxpy +#define ssyr2_ ssyr2 +#define srot_ srot +#define sgemv_ sgemv +#define strsv_ strsv +#define sgemm_ sgemm +#define strsm_ strsm + +#define dswap_ dswap +#define daxpy_ daxpy +#define dasum_ dasum +#define idamax_ idamax +#define dcopy_ dcopy +#define dscal_ dscal +#define dger_ dger +#define dnrm2_ dnrm2 +#define dsymv_ dsymv +#define ddot_ ddot +#define dsyr2_ dsyr2 +#define drot_ drot +#define dgemv_ dgemv +#define dtrsv_ dtrsv +#define dgemm_ dgemm +#define dtrsm_ dtrsm + +#define cswap_ cswap +#define caxpy_ caxpy +#define scasum_ scasum +#define icamax_ icamax +#define ccopy_ ccopy +#define cscal_ cscal +#define scnrm2_ scnrm2 +#define cgemv_ cgemv +#define ctrsv_ ctrsv +#define cgemm_ cgemm +#define ctrsm_ ctrsm +#define cgerc_ cgerc +#define chemv_ chemv +#define cher2_ cher2 + +#define zswap_ zswap +#define zaxpy_ zaxpy +#define dzasum_ dzasum +#define izamax_ izamax +#define zcopy_ zcopy +#define zscal_ zscal +#define dznrm2_ dznrm2 +#define zgemv_ zgemv +#define ztrsv_ ztrsv +#define zgemm_ zgemm +#define ztrsm_ ztrsm +#define zgerc_ zgerc +#define zhemv_ zhemv +#define zher2_ zher2 + +/* LAPACK */ +#define dlamch_ dlamch +#define slamch_ slamch +#define xerbla_ xerbla +#define lsame_ lsame +#define dlacon_ dlacon +#define slacon_ slacon +#define icmax1_ icmax1 +#define scsum1_ scsum1 +#define clacon_ clacon +#define dzsum1_ dzsum1 +#define izmax1_ izmax1 +#define zlacon_ zlacon + +/* Fortran interface */ +#define c_bridge_dgssv_ c_bridge_dgssv +#define c_fortran_sgssv_ c_fortran_sgssv +#define c_fortran_dgssv_ c_fortran_dgssv +#define c_fortran_cgssv_ c_fortran_cgssv +#define c_fortran_zgssv_ c_fortran_zgssv +#endif + + +#endif /* __SUPERLU_CNAMES */ diff --git a/external/arpack++/include/arlnsmat.h b/external/arpack++/include/arlnsmat.h new file mode 100644 index 000000000..07a547f99 --- /dev/null +++ b/external/arpack++/include/arlnsmat.h @@ -0,0 +1,753 @@ +/* + ARPACK++ v1.2 2/20/2000 + c++ interface to ARPACK code. + + MODULE ARLNSMat.h. + Arpack++ class ARluNonSymMatrix definition. + + ARPACK Authors + Richard Lehoucq + Danny Sorensen + Chao Yang + Dept. of Computational & Applied Mathematics + Rice University + Houston, Texas +*/ + + +#include "arlnspen.h" + +#ifndef ARLNSMAT_H +#define ARLNSMAT_H + +#include +#include +#include "arch.h" +#include "armat.h" +#include "arhbmat.h" +#include "arerror.h" +#include "blas1c.h" +#include "superluc.h" +#include "arlspdef.h" +#include "arlutil.h" + +template class ARluNonSymPencil; + +template +class ARluNonSymMatrix: public ARMatrix { + + friend class ARluNonSymPencil; + friend class ARluNonSymPencil; + + protected: + + bool factored; + int order; + int nnz; + int* irow; + int* pcol; + int* permc; + int* permr; + double threshold; + ARTYPE* a; + SuperMatrix A; + SuperMatrix L; + SuperMatrix U; + ARhbMatrix mat; + SuperLUStat_t stat; + + bool DataOK(); + + virtual void Copy(const ARluNonSymMatrix& other); + + void ClearMem(); + + void SubtractAsI(ARTYPE sigma, NCformat& A, NCformat& AsI); + + public: + + int nzeros() { return nnz; } + + bool IsFactored() { return factored; } + + void FactorA(); + + void FactorAsI(ARTYPE sigma); + + void MultMv(ARTYPE* v, ARTYPE* w); + + void MultMtv(ARTYPE* v, ARTYPE* w); + + void MultMtMv(ARTYPE* v, ARTYPE* w); + + void MultMMtv(ARTYPE* v, ARTYPE* w); + + void Mult0MMt0v(ARTYPE* v, ARTYPE* w); + + void MultInvv(ARTYPE* v, ARTYPE* w); + + void DefineMatrix(int np, int nnzp, ARTYPE* ap, int* irowp, + int* pcolp, double thresholdp = 0.1, + int orderp = 1, bool check = true); // Square matrix. + + void DefineMatrix(int mp, int np, int nnzp, ARTYPE* ap, + int* irowp, int* pcolp); // Rectangular matrix. + + ARluNonSymMatrix(); + // Short constructor that does nothing. + + ARluNonSymMatrix(int np, int nnzp, ARTYPE* ap, int* irowp, int* pcolp, + double thresholdp = 0.1, int orderp = 1, bool check = true); + // Long constructor (square matrix). + + ARluNonSymMatrix(int mp, int np, int nnzp, ARTYPE* ap, int* irowp,int* pcolp); + // Long constructor (rectangular matrix). + + ARluNonSymMatrix(const std::string& name, double thresholdp = 0.1, + int orderp = 1, bool check = true); + // Long constructor (Harwell-Boeing file). + + ARluNonSymMatrix(const ARluNonSymMatrix& other) { Copy(other); } + // Copy constructor. + + virtual ~ARluNonSymMatrix() { ClearMem(); } + // Destructor. + + ARluNonSymMatrix& operator=(const ARluNonSymMatrix& other); + // Assignment operator. + +}; + +// ------------------------------------------------------------------------ // +// ARluNonSymMatrix member functions definition. // +// ------------------------------------------------------------------------ // + + +template +bool ARluNonSymMatrix::DataOK() +{ + + int i, j, k; + + // Checking if pcol is in ascending order. + + i = 0; + while ((i!=this->n)&&(pcol[i]<=pcol[i+1])) i++; + if (i!=this->n) return false; + + // Checking if irow components are in order and within bounds. + + for (i=0; i!=this->n; i++) { + j = pcol[i]; + k = pcol[i+1]-1; + if (j<=k) { + if ((irow[j]<0)||(irow[k]>=this->n)) return false; + while ((j!=k)&&(irow[j] +inline void ARluNonSymMatrix:: +Copy(const ARluNonSymMatrix& other) +{ + + // Copying very fundamental variables. + + this->defined = other.defined; + factored = other.factored; + + // Returning from here if "other" was not initialized. + + if (!this->defined) return; + + // Copying user-defined parameters. + + if (other.n == other.m) { + DefineMatrix(other.n, other.nnz, other.a, other.irow, + other.pcol, other.threshold, other.order); + } + else { + DefineMatrix(other.m, other.n, other.nnz, + other.a, other.irow, other.pcol); + } + + // Throwing the original factorization away (this procedure + // is really awkward, but it is necessary because there + // is no copy function for matrices L and U in the SuperLU + // library and it is not a good idea to do this kind of deep + // copy here). + + if (factored) { + ArpackError(ArpackError::LAPACK_ERROR, "ARluNonSymMatrix"); + factored = false; + } + +} // Copy. + + +template +void ARluNonSymMatrix::ClearMem() +{ + + if (factored) { + Destroy_SuperNode_Matrix(&L); + Destroy_CompCol_Matrix(&U); + StatFree(&stat); + } + if (this->defined) { + Destroy_SuperMatrix_Store(&A); // delete A.Store; + delete[] permc; + delete[] permr; + permc = NULL; + permr = NULL; + A.Store = NULL; + } + +} // ClearMem. + + +template +void ARluNonSymMatrix:: +SubtractAsI(ARTYPE sigma, NCformat& A, NCformat& AsI) +{ + + // Defining local variables. + + int i, j, k, end; + ARTYPE* anzval; + ARTYPE* inzval; + + // Telling the compiler that nzval must be viewed as a vector of ARTYPE. + + anzval = (ARTYPE*)A.nzval; + inzval = (ARTYPE*)AsI.nzval; + + // Subtracting sigma from diagonal elements. + + k = 0; + AsI.colptr[0] = 0; + + for (i=0; i!=this->n; i++) { + + j = A.colptr[i]; + end = A.colptr[i+1]; + + // Copying superdiagonal elements of column i. + + while ((A.rowind[j] < i)&&(j < end)) { + inzval[k] = anzval[j]; + AsI.rowind[k++] = A.rowind[j++]; + } + + // Verifying if A(i,i) exists. + + if ((A.rowind[j] == i)&&(j < end)) { // A(i,i) exists, subtracting sigma. + inzval[k] = anzval[j++] - sigma; + } + else { // A(i,i) does not exist. + inzval[k] = -sigma; + } + AsI.rowind[k++] = i; + + // Copying subdiagonal elements of column i. + + while (j < end ) { + inzval[k] = anzval[j]; + AsI.rowind[k++] = A.rowind[j++]; + } + + AsI.colptr[i+1] = k; + + } + + AsI.nnz = AsI.colptr[this->n]; + +} // SubtractAsI. + + +template +void ARluNonSymMatrix::FactorA() +{ + + // Defining local variables. + + int info; + int* etree; + SuperMatrix AC; + + // Quitting the function if A was not defined. + + if (!this->IsDefined()) { + throw ArpackError(ArpackError::DATA_UNDEFINED, "ARluNonSymMatrix::FactorA"); + } + + // Quitting the function if A is not square. + + if (this->m != this->n) { + throw ArpackError(ArpackError::NOT_SQUARE_MATRIX, + "ARluNonSymMatrix::FactorA"); + } + + // Deleting previous versions of L and U. + + if (factored) { + Destroy_SuperNode_Matrix(&L); + Destroy_CompCol_Matrix(&U); + StatFree(&stat); + } + + // Setting default values for gstrf parameters. + + int panel_size = sp_ienv(1); + int relax = sp_ienv(2); + superlu_options_t options; + + /* Set the default input options: + options.Fact = DOFACT; + options.Equil = YES; + options.ColPerm = COLAMD; + options.DiagPivotThresh = 1.0; + options.Trans = NOTRANS; + options.IterRefine = NOREFINE; + options.SymmetricMode = NO; + options.PivotGrowth = NO; + options.ConditionNumber = NO; + options.PrintStat = YES; + */ + set_default_options(&options); + options.DiagPivotThresh = threshold; + + // Reserving memory for etree (used in matrix decomposition). + + etree = new int[this->n]; + + // Defining LUStat. + + //StatInit(panel_size, relax); + StatInit(&stat); + + // Defining the column permutation of matrix A + // (using minimum degree ordering on A'*A). + + get_perm_c(order, &A, permc); + + // Permuting columns of A and + // creating the elimination tree of A'*A. + +// sp_preorder("N", &A, permc, etree, &AC); + sp_preorder(&options, &A, permc, etree, &AC); + + // Decomposing A. + +// gstrf("N",&AC, threshold, drop_tol, relax, panel_size, etree, +// NULL, 0, permr, permc, &L, &U, &info); + gstrf(&options,&AC, relax, panel_size, etree, + NULL, 0, permc, permr, &L, &U, &stat, &info); + + // Deleting AC and etree. + + Destroy_CompCol_Permuted(&AC); + delete[] etree; + + factored = (info == 0); + + // Handling errors. + + if (info < 0) { // Illegal argument. + throw ArpackError(ArpackError::PARAMETER_ERROR, + "ARluNonSymMatrix::FactorA"); + } + else if (info > this->n) { // Memory is not sufficient. + throw ArpackError(ArpackError::MEMORY_OVERFLOW, + "ARluNonSymMatrix::FactorA"); + } + else if (info > 0) { // Matrix is singular. + throw ArpackError(ArpackError::MATRIX_IS_SINGULAR, + "ARluNonSymMatrix::FactorA"); + } + +} // FactorA. + + +template +void ARluNonSymMatrix::FactorAsI(ARTYPE sigma) +{ + + // Quitting the function if A was not defined. + + if (!this->IsDefined()) { + throw ArpackError(ArpackError::DATA_UNDEFINED, + "ARluNonSymMatrix::FactorAsI"); + } + + // Quitting the function if A is not square. + + if (this->m != this->n) { + throw ArpackError(ArpackError::NOT_SQUARE_MATRIX, + "ARluNonSymMatrix::FactorAsI"); + } + + // Defining local variables. + + int info; + int* etree; + int* irowi; + int* pcoli; + ARTYPE* asi; + SuperMatrix AsI; + SuperMatrix AC; + NCformat* Astore; + NCformat* AsIstore; + + // Deleting previous versions of L and U. + + if (factored) { + Destroy_SuperNode_Matrix(&L); + Destroy_CompCol_Matrix(&U); + StatFree(&stat); + } + + // Setting default values for gstrf parameters. + + int panel_size = sp_ienv(1); + int relax = sp_ienv(2); + superlu_options_t options; + + /* Set the default input options: + options.Fact = DOFACT; + options.Equil = YES; + options.ColPerm = COLAMD; + options.DiagPivotThresh = 1.0; + options.Trans = NOTRANS; + options.IterRefine = NOREFINE; + options.SymmetricMode = NO; + options.PivotGrowth = NO; + options.ConditionNumber = NO; + options.PrintStat = YES; + */ + set_default_options(&options); + options.DiagPivotThresh = threshold; + + // Creating a temporary matrix AsI. + + irowi = (int*)SUPERLU_MALLOC(sizeof(int) * (nnz+this->n)); + pcoli = (int*)SUPERLU_MALLOC(sizeof(int) * (this->n+1)); + asi = (ARTYPE*)SUPERLU_MALLOC(sizeof(ARTYPE) * (nnz+this->n)); + Create_CompCol_Matrix(&AsI, this->n, this->n, nnz, asi, irowi, pcoli, SLU_NC, SLU_GE); + + // Subtracting sigma*I from A and storing the result on AsI. + + Astore = (NCformat*)A.Store; + AsIstore = (NCformat*)AsI.Store; + SubtractAsI(sigma, *Astore, *AsIstore); + + // Reserving memory for etree (used in matrix decomposition). + + etree = new int[this->n]; + + // Defining LUStat. + + //StatInit(panel_size, relax); + StatInit(&stat); + + // Defining the column permutation of matrix AsI + // (using minimum degree ordering on AsI'*AsI). + + get_perm_c(order, &AsI, permc); + + // Permuting columns of AsI and + // creating the elimination tree of AsI'*AsI. + + //sp_preorder("N", &AsI, permc, etree, &AC); + sp_preorder(&options, &AsI, permc, etree, &AC); + + // Decomposing AsI. + +// gstrf("N",&AC, threshold, drop_tol, relax, panel_size, etree, +// NULL, 0, permr, permc, &L, &U, &info); + gstrf(&options,&AC, relax, panel_size, etree, + NULL, 0, permc, permr, &L, &U, &stat, &info); + + // Deleting AC, AsI and etree. + + Destroy_CompCol_Permuted(&AC); + Destroy_CompCol_Matrix(&AsI); + delete[] etree; + + factored = (info == 0); + + // Handling errors. + + if (info < 0) { // Illegal argument. + throw ArpackError(ArpackError::PARAMETER_ERROR, + "ARluNonSymMatrix::FactorAsI"); + } + else if (info > this->n) { // Memory is not sufficient. + throw ArpackError(ArpackError::MEMORY_OVERFLOW, + "ARluNonSymMatrix::FactorAsI"); + } + else if (info > 0) { // Matrix is singular. + throw ArpackError(ArpackError::MATRIX_IS_SINGULAR, + "ARluNonSymMatrix::FactorAsI"); + } + +} // FactorAsI. + + +template +void ARluNonSymMatrix::MultMv(ARTYPE* v, ARTYPE* w) +{ + + int i,j; + ARTYPE t; + + // Quitting the function if A was not defined. + + if (!this->IsDefined()) { + throw ArpackError(ArpackError::DATA_UNDEFINED, "ARluNonSymMatrix::MultMv"); + } + + // Determining w = M.v. + + for (i=0; i!=this->m; i++) w[i]=(ARTYPE)0; + + for (i=0; i!=this->n; i++) { + t = v[i]; + for (j=pcol[i]; j!=pcol[i+1]; j++) { + w[irow[j]] += t*a[j]; + } + } + +} // MultMv. + + +template +void ARluNonSymMatrix::MultMtv(ARTYPE* v, ARTYPE* w) +{ + + int i,j; + ARTYPE t; + + // Quitting the function if A was not defined. + + if (!this->IsDefined()) { + throw ArpackError(ArpackError::DATA_UNDEFINED, "ARluNonSymMatrix::MultMtv"); + } + + // Determining w = M'.v. + + for (i=0; i!=this->n; i++) { + t = (ARTYPE)0; + for (j=pcol[i]; j!=pcol[i+1]; j++) { + t += v[irow[j]]*a[j]; + } + w[i] = t; + } + +} // MultMtv. + + +template +void ARluNonSymMatrix::MultMtMv(ARTYPE* v, ARTYPE* w) +{ + + ARTYPE* t = new ARTYPE[this->m]; + + MultMv(v,t); + MultMtv(t,w); + + delete[] t; + +} // MultMtMv. + + +template +void ARluNonSymMatrix::MultMMtv(ARTYPE* v, ARTYPE* w) +{ + + ARTYPE* t = new ARTYPE[this->n]; + + MultMtv(v,t); + MultMv(t,w); + + delete[] t; + +} // MultMMtv. + + +template +void ARluNonSymMatrix::Mult0MMt0v(ARTYPE* v, ARTYPE* w) +{ + + MultMv(&v[this->m],w); + MultMtv(v,&w[this->m]); + +} // Mult0MMt0v. + + +template +void ARluNonSymMatrix::MultInvv(ARTYPE* v, ARTYPE* w) +{ + + // Quitting the function if A (or AsI) was not factored. + + if (!IsFactored()) { + throw ArpackError(ArpackError::NOT_FACTORED_MATRIX, + "ARluNonSymMatrix::MultInvv"); + } + + // Solving A.w = v (or AsI.w = v). + + int info; + SuperMatrix B; + + if (&v != &w) copy(this->n, v, 1, w, 1); + Create_Dense_Matrix(&B, this->n, 1, w, this->n, SLU_DN, SLU_GE); +// gstrs("N", &L, &U, permr, permc, &B, &info); + StatInit(&stat); + trans_t trans = NOTRANS; + gstrs(trans, &L, &U, permc, permr, &B, &stat, &info); + Destroy_SuperMatrix_Store(&B); // delete B.Store; + +} // MultInvv. + + +template +inline void ARluNonSymMatrix:: +DefineMatrix(int np, int nnzp, ARTYPE* ap, int* irowp, int* pcolp, + double thresholdp, int orderp, bool check) +{ + + this->m = np; + this->n = np; + nnz = nnzp; + a = ap; + irow = irowp; + pcol = pcolp; + pcol[this->n] = nnz; + threshold = thresholdp; + order = orderp; + + // Checking data. + + if ((check)&&(!DataOK())) { + throw ArpackError(ArpackError::INCONSISTENT_DATA, + "ARluSymMatrix::DefineMatrix"); + } + + // Creating SuperMatrix A. + + Create_CompCol_Matrix(&A, this->n, this->n, nnz, a, irow, pcol, SLU_NC, SLU_GE); + + // Reserving memory for vectors used in matrix decomposition. + + permc = new int[this->n]; + permr = new int[this->n]; + + this->defined = true; + +} // DefineMatrix (square). + + +template +inline void ARluNonSymMatrix:: +DefineMatrix(int mp, int np, int nnzp, ARTYPE* ap, int* irowp, int* pcolp) +{ + + this->m = mp; + this->n = np; + nnz = nnzp; + a = ap; + irow = irowp; + pcol = pcolp; + pcol[this->n] = nnz; + this->defined = true; + permc = NULL; + permr = NULL; + +} // DefineMatrix (rectangular). + + +template +inline ARluNonSymMatrix::ARluNonSymMatrix(): ARMatrix() +{ + + factored = false; + permc = NULL; + permr = NULL; + +} // Short constructor. + + +template +inline ARluNonSymMatrix:: +ARluNonSymMatrix(int np, int nnzp, ARTYPE* ap, int* irowp, + int* pcolp, double thresholdp, + int orderp, bool check) : ARMatrix(np) +{ + + factored = false; + DefineMatrix(np, nnzp, ap, irowp, pcolp, thresholdp, orderp, check); + +} // Long constructor (square matrix). + + +template +inline ARluNonSymMatrix:: +ARluNonSymMatrix(int mp, int np, int nnzp, ARTYPE* ap, + int* irowp, int* pcolp) : ARMatrix(mp, np) +{ + + factored = false; + DefineMatrix(mp, np, nnzp, ap, irowp, pcolp); + +} // Long constructor (retangular matrix). + + +template +ARluNonSymMatrix:: +ARluNonSymMatrix(const std::string& file, double thresholdp, int orderp, bool check) +{ + + factored = false; + + try { + mat.Define(file); + } + catch (ArpackError) { // Returning from here if an error has occurred. + throw ArpackError(ArpackError::CANNOT_READ_FILE, "ARluNonSymMatrix"); + } + + if (mat.NCols()==mat.NRows()) { + DefineMatrix(mat.NCols(), mat.NonZeros(), (ARTYPE*)mat.Entries(), + mat.RowInd(), mat.ColPtr(), thresholdp, orderp, check); + } + else { + DefineMatrix(mat.NRows(), mat.NCols(), mat.NonZeros(), + (ARTYPE*)mat.Entries(), mat.RowInd(), mat.ColPtr()); + } + +} // Long constructor (Harwell-Boeing file). + + +template +ARluNonSymMatrix& ARluNonSymMatrix:: +operator=(const ARluNonSymMatrix& other) +{ + + if (this != &other) { // Stroustrup suggestion. + ClearMem(); + Copy(other); + } + return *this; + +} // operator=. + + +#endif // ARLNSMAT_H diff --git a/external/arpack++/include/arlnspen.h b/external/arpack++/include/arlnspen.h new file mode 100644 index 000000000..b479ac652 --- /dev/null +++ b/external/arpack++/include/arlnspen.h @@ -0,0 +1,774 @@ +/* + ARPACK++ v1.2 2/20/2000 + c++ interface to ARPACK code. + + MODULE ARLNSPen.h. + Arpack++ class ARluNonSymPencil definition. + + ARPACK Authors + Richard Lehoucq + Danny Sorensen + Chao Yang + Dept. of Computational & Applied Mathematics + Rice University + Houston, Texas +*/ + +#ifndef ARLNSPEN_H +#define ARLNSPEN_H + +#include + +#include "arch.h" +#include "arerror.h" +#include "blas1c.h" +#include "superluc.h" +#include "arlspdef.h" +#include "arlutil.h" +#include "arlnsmat.h" + + +template +class ARluNonSymPencil +{ + + protected: + + bool factored; + int* permc; + int* permr; + char part; + ARluNonSymMatrix* A; + ARluNonSymMatrix* B; + SuperMatrix L; + SuperMatrix U; + SuperLUStat_t stat; + + virtual void Copy(const ARluNonSymPencil& other); + + void ClearMem(); + + void SparseSaxpy(ARTYPE a, ARTYPE x[], int xind[], int nx, ARTYPE y[], + int yind[], int ny, ARTYPE z[], int zind[], int& nz); + +#ifdef ARCOMP_H + void SparseSaxpy(arcomplex a, ARFLOAT x[], int xind[], int nx, + ARFLOAT y[], int yind[], int ny, arcomplex z[], + int zind[], int& nz); +#endif + + void SubtractAsB(int n, ARTYPE sigma, NCformat& A, + NCformat& B, NCformat& AsB); + +#ifdef ARCOMP_H + void SubtractAsB(int n, ARFLOAT sigmaR, ARFLOAT sigmaI, + NCformat& A, NCformat& B, NCformat& AsB); +#endif + + public: + + bool IsFactored() { return factored; } + + void FactorAsB(ARTYPE sigma); + +#ifdef ARCOMP_H + void FactorAsB(ARFLOAT sigmaR, ARFLOAT sigmaI, char partp = 'R'); +#endif + + void MultAv(ARTYPE* v, ARTYPE* w) { A->MultMv(v,w); } + + void MultBv(ARTYPE* v, ARTYPE* w) { B->MultMv(v,w); } + + void MultInvBAv(ARTYPE* v, ARTYPE* w); + +#ifdef ARCOMP_H + void MultInvAsBv(arcomplex* v, arcomplex* w); +#endif + + void MultInvAsBv(ARFLOAT* v, ARFLOAT* w); + + void DefineMatrices(ARluNonSymMatrix& Ap, + ARluNonSymMatrix& Bp); + + ARluNonSymPencil(); + // Short constructor that does nothing. + + ARluNonSymPencil(ARluNonSymMatrix& Ap, + ARluNonSymMatrix& Bp); + // Long constructor. + + ARluNonSymPencil(const ARluNonSymPencil& other) { Copy(other); } + // Copy constructor. + + virtual ~ARluNonSymPencil() { ClearMem(); } + // Destructor. + + ARluNonSymPencil& operator=(const ARluNonSymPencil& other); + // Assignment operator. + +}; + +// ------------------------------------------------------------------------ // +// ARluNonSymPencil member functions definition. // +// ------------------------------------------------------------------------ // + + +template +inline void ARluNonSymPencil:: +Copy(const ARluNonSymPencil& other) +{ + + factored = other.factored; + part = other.part; + A = other.A; + B = other.B; + + // Throwing the original factorization away (this procedure + // is really awkward, but it is necessary because there + // is no copy function for matrices L and U in the SuperLU + // library and it is not a good idea to do this kind of deep + // copy here). + + if (factored) { + ArpackError(ArpackError::DISCARDING_FACTORS, "ARluNonSymPencil"); + factored = false; + } + +} // Copy. + + +template +void ARluNonSymPencil::ClearMem() +{ + + if (factored) { + Destroy_SuperNode_Matrix(&L); + Destroy_CompCol_Matrix(&U); + StatFree(&stat); + delete[] permc; + delete[] permr; + permc = NULL; + permr = NULL; + } + +} // ClearMem. + + +template +void ARluNonSymPencil:: +SparseSaxpy(ARTYPE a, ARTYPE x[], int xind[], int nx, ARTYPE y[], + int yind[], int ny, ARTYPE z[], int zind[], int& nz) +// A strongly sequential (and inefficient) sparse saxpy algorithm. +{ + + int ix, iy; + + nz = 0; + if ((nx == 0) || (a == (ARTYPE)0)) { + copy(ny,y,1,z,1); + for (iy=0; iy!=ny; iy++) zind[iy] = yind[iy]; + nz = ny; + return; + } + if (ny == 0) { + copy(nx,x,1,z,1); + scal(nx,a,z,1); + for (ix=0; ix!=nx; ix++) zind[ix] = xind[ix]; + nz = nx; + return; + } + ix = 0; + iy = 0; + while (true) { + if (xind[ix] == yind[iy]) { + zind[nz] = xind[ix]; + z[nz++] = a*x[ix++]+y[iy++]; + if ((ix == nx)||(iy == ny)) break; + } + else if (xind[ix] < yind[iy]) { + zind[nz] = xind[ix]; + z[nz++] = a*x[ix++]; + if (ix == nx) break; + } + else { + zind[nz] = yind[iy]; + z[nz++] = y[iy++]; + if (iy == ny) break; + } + } + while (iy < ny) { + zind[nz] = yind[iy]; + z[nz++] = y[iy++]; + } + while (ix < nx) { + zind[nz] = xind[ix]; + z[nz++] = x[ix++]; + } + +} // SparseSaxpy (ARTYPE). + + +#ifdef ARCOMP_H +template +void ARluNonSymPencil:: +SparseSaxpy(arcomplex a, ARFLOAT x[], int xind[], int nx, ARFLOAT y[], + int yind[], int ny, arcomplex z[], int zind[], int& nz) +// A strongly sequential (and inefficient) sparse saxpy algorithm. +{ + + int ix, iy; + + nz = 0; + if ((nx == 0) || (a == arcomplex(0.0,0.0))) { + for (iy=0; iy!=ny; iy++) { + z[iy] = arcomplex(y[iy],0.0); + zind[iy] = yind[iy]; + } + nz = ny; + return; + } + if (ny == 0) { + for (ix=0; ix!=ny; ix++) { + z[ix] = a*arcomplex(x[ix],0.0); + zind[ix] = xind[ix]; + } + nz = nx; + return; + } + ix = 0; + iy = 0; + while (true) { + if (xind[ix] == yind[iy]) { + zind[nz] = xind[ix]; + z[nz++] = a*x[ix++]+y[iy++]; + if ((ix == nx)||(iy == ny)) break; + } + else if (xind[ix] < yind[iy]) { + zind[nz] = xind[ix]; + z[nz++] = a*x[ix++]; + if (ix == nx) break; + } + else { + zind[nz] = yind[iy]; + z[nz++] = arcomplex(y[iy++],0.0); + if (iy == ny) break; + } + } + while (iy < ny) { + zind[nz] = yind[iy]; + z[nz++] = arcomplex(y[iy++],0.0); + } + while (ix < nx) { + zind[nz] = xind[ix]; + z[nz++] = arcomplex(x[ix++],0.0); + } + +} // SparseSaxpy (arcomplex). +#endif // ARCOMP_H. + + +template +void ARluNonSymPencil:: +SubtractAsB(int n, ARTYPE sigma, NCformat& A, NCformat& B, NCformat& AsB) +{ + + int i, acol, bcol, asbcol, scol; + ARTYPE* anzval; + ARTYPE* bnzval; + ARTYPE* asbnzval; + + // Telling the compiler that nzval must ve viewed as a vector of ARTYPE. + + anzval = (ARTYPE*)A.nzval; + bnzval = (ARTYPE*)B.nzval; + asbnzval = (ARTYPE*)AsB.nzval; + + // Subtracting sigma*B from A. + + AsB.colptr[0] = 0; + asbcol = 0; + + for (i=0; i!=n; i++) { + bcol = B.colptr[i]; + acol = A.colptr[i]; + SparseSaxpy(-sigma, &bnzval[bcol], &B.rowind[bcol], B.colptr[i+1]-bcol, + &anzval[acol], &A.rowind[acol], A.colptr[i+1]-acol, + &asbnzval[asbcol], &AsB.rowind[asbcol], scol); + asbcol += scol; + AsB.colptr[i+1] = asbcol; + } + + AsB.nnz = AsB.colptr[n]; + +} // SubtractAsB (ARTYPE shift). + + +#ifdef ARCOMP_H +template +void ARluNonSymPencil:: +SubtractAsB(int n, ARFLOAT sigmaR, ARFLOAT sigmaI, + NCformat& A, NCformat& B, NCformat& AsB) +{ + + int i, acol, bcol, asbcol, scol; + ARTYPE* anzval; + ARTYPE* bnzval; + arcomplex* asbnzval; + arcomplex sigma; + + // Telling the compiler that nzval must ve viewed as a vector of ARTYPE. + + anzval = (ARTYPE*)A.nzval; + bnzval = (ARTYPE*)B.nzval; + asbnzval = (arcomplex*)AsB.nzval; + + // Subtracting sigma*B from A. + + sigma = arcomplex(sigmaR, sigmaI); + AsB.colptr[0] = 0; + asbcol = 0; + + for (i=0; i!=n; i++) { + bcol = B.colptr[i]; + acol = A.colptr[i]; + SparseSaxpy(-sigma, &bnzval[bcol], &B.rowind[bcol], B.colptr[i+1]-bcol, + &anzval[acol], &A.rowind[acol], A.colptr[i+1]-acol, + &asbnzval[asbcol], &AsB.rowind[asbcol], scol); + asbcol += scol; + AsB.colptr[i+1] = asbcol; + } + + AsB.nnz = AsB.colptr[n]; + +} // SubtractAsB (arcomplex shift). +#endif // ARCOMP_H. + + +template +void ARluNonSymPencil::FactorAsB(ARTYPE sigma) +{ + + // Quitting the function if A and B were not defined. + + if (!(A->IsDefined()&&B->IsDefined())) { + throw ArpackError(ArpackError::DATA_UNDEFINED, + "ARluNonSymPencil::FactorAsB"); + } + + // Quitting the function if A and B are not square. + + if ((A->nrows() != A->ncols()) || (B->nrows() != B->ncols())) { + throw ArpackError(ArpackError::NOT_SQUARE_MATRIX, + "ARluNonSymPencil::FactorAsB"); + } + + // Defining local variables. + + int nnzi, info; + int* etree; + int* irowi; + int* pcoli; + ARTYPE* asb; + SuperMatrix AsB; + SuperMatrix AC; + NCformat* Astore; + NCformat* Bstore; + NCformat* AsBstore; + + // Deleting old versions of L, U, perm_r and perm_c. + + ClearMem(); + + // Setting default values for gstrf parameters. + + int panel_size = sp_ienv(1); + int relax = sp_ienv(2); + superlu_options_t options; + /* Set the default input options: + options.Fact = DOFACT; + options.Equil = YES; + options.ColPerm = COLAMD; + options.DiagPivotThresh = 1.0; + options.Trans = NOTRANS; + options.IterRefine = NOREFINE; + options.SymmetricMode = NO; + options.PivotGrowth = NO; + options.ConditionNumber = NO; + options.PrintStat = YES; + */ + set_default_options(&options); + options.DiagPivotThresh = A->threshold; + + // Defining A and B format. + + Astore = (NCformat*)A->A.Store; + Bstore = (NCformat*)B->A.Store; + + // Creating a temporary matrix AsB. + + nnzi = Astore->nnz+Bstore->nnz; + irowi = new int[nnzi]; + pcoli = new int[A->ncols()+1]; + asb = new ARTYPE[nnzi]; + Create_CompCol_Matrix(&AsB, A->nrows(), A->ncols(), nnzi, asb, + irowi, pcoli, SLU_NC, SLU_GE); + + // Subtracting sigma*B from A and storing the result on AsB. + + AsBstore = (NCformat*)AsB.Store; + SubtractAsB(A->ncols(), sigma, *Astore, *Bstore, *AsBstore); + + // Reserving memory for some vectors used in matrix decomposition. + + etree = new int[A->ncols()]; + if (permc == NULL) permc = new int[A->ncols()]; + if (permr == NULL) permr = new int[A->ncols()]; + + // Defining LUStat. + +// StatInit(panel_size, relax); + SuperLUStat_t stat; + StatInit(&stat); + + // Defining the column permutation of matrix AsB + // (using minimum degree ordering on AsB'*AsB). + + get_perm_c(A->order, &AsB, permc); + + // Permuting columns of AsB and + // creating the elimination tree of AsB'*AsB. + +// sp_preorder("N", &AsB, permc, etree, &AC); + sp_preorder(&options, &AsB, permc, etree, &AC); + + // Decomposing AsB. + +// gstrf("N",&AC, A->threshold, drop_tol, relax, panel_size, etree, +// NULL, 0, permr, permc, &L, &U, &info); + gstrf(&options, &AC, relax, panel_size, etree, + NULL, 0, permc, permr, &L, &U, &stat, &info); + + // Deleting AC, AsB and etree. + + Destroy_CompCol_Permuted(&AC); + Destroy_CompCol_Matrix(&AsB); + delete[] etree; + + factored = (info == 0); + + // Handling errors. + + if (info < 0) { // Illegal argument. + throw ArpackError(ArpackError::PARAMETER_ERROR, + "ARluNonSymPencil::FactorAsB"); + } + else if (info > A->ncols()) { // Memory is not sufficient. + throw ArpackError(ArpackError::MEMORY_OVERFLOW, + "ARluNonSymPencil::FactorAsB"); + } + else if (info > 0) { // Matrix is singular. + throw ArpackError(ArpackError::MATRIX_IS_SINGULAR, + "ARluNonSymPencil::FactorAsB"); + } + +} // FactorAsB (ARTYPE shift). + + +#ifdef ARCOMP_H +template +void ARluNonSymPencil:: +FactorAsB(ARFLOAT sigmaR, ARFLOAT sigmaI, char partp) +{ + + // Quitting the function if A and B were not defined. + + if (!(A->IsDefined()&&B->IsDefined())) { + throw ArpackError(ArpackError::DATA_UNDEFINED, + "ARluNonSymPencil::FactorAsB"); + } + + // Quitting the function if A and B are not square. + + if ((A->nrows() != A->ncols()) || (B->nrows() != B->ncols())) { + throw ArpackError(ArpackError::NOT_SQUARE_MATRIX, + "ARluNonSymPencil::FactorAsB"); + } + + // Defining local variables. + + int nnzi, info; + int* etree; + int* irowi; + int* pcoli; + arcomplex* asb; + SuperMatrix AsB; + SuperMatrix AC; + NCformat* Astore; + NCformat* Bstore; + NCformat* AsBstore; + + // Deleting old versions of L, U, perm_r and perm_c. + + ClearMem(); + + // Setting default values for gstrf parameters. + + int panel_size = sp_ienv(1); + int relax = sp_ienv(2); + superlu_options_t options; + /* Set the default input options: + options.Fact = DOFACT; + options.Equil = YES; + options.ColPerm = COLAMD; + options.DiagPivotThresh = 1.0; + options.Trans = NOTRANS; + options.IterRefine = NOREFINE; + options.SymmetricMode = NO; + options.PivotGrowth = NO; + options.ConditionNumber = NO; + options.PrintStat = YES; + */ + set_default_options(&options); + options.DiagPivotThresh = A->threshold; + + + // Defining A and B format. + + Astore = (NCformat*)A->A.Store; + Bstore = (NCformat*)B->A.Store; + + // Creating a temporary matrix AsB. + + part = partp; + nnzi = Astore->nnz+Bstore->nnz; + irowi = new int[nnzi]; + pcoli = new int[A->ncols()+1]; + asb = new arcomplex[nnzi]; + Create_CompCol_Matrix(&AsB, A->nrows(), A->ncols(), nnzi, asb, + irowi, pcoli, SLU_NC, SLU_GE); + + // Subtracting sigma*B from A and storing the result on AsB. + + AsBstore = (NCformat*)AsB.Store; + SubtractAsB(A->ncols(), sigmaR, sigmaI, *Astore, *Bstore, *AsBstore); + + // Reserving memory for some vectors used in matrix decomposition. + + etree = new int[A->ncols()]; + if (permc == NULL) permc = new int[A->ncols()]; + if (permr == NULL) permr = new int[A->ncols()]; + + // Defining LUStat. + +// StatInit(panel_size, relax); + SuperLUStat_t stat; + StatInit(&stat); + + // Defining the column permutation of matrix AsB + // (using minimum degree ordering on AsB'*AsB). + + get_perm_c(A->order, &AsB, permc); + + // Permuting columns of AsB and + // creating the elimination tree of AsB'*AsB. + + //sp_preorder("N", &AsB, permc, etree, &AC); + sp_preorder(&options, &AsB, permc, etree, &AC); + + // Decomposing AsB. + +// gstrf("N",&AC, A->threshold, drop_tol, relax, panel_size, etree, NULL, +// 0, permr, permc, &L, &U, &info); + gstrf(&options, &AC, relax, panel_size, etree, + NULL, 0, permc, permr, &L, &U, &stat, &info); + + // Deleting AC, AsB and etree. + + Destroy_CompCol_Permuted(&AC); + Destroy_CompCol_Matrix(&AsB); + delete[] etree; + + factored = (info == 0); + + // Handling errors. + + if (info < 0) { // Illegal argument. + throw ArpackError(ArpackError::PARAMETER_ERROR, + "ARluNonSymPencil::FactorAsB"); + } + else if (info > A->ncols()) { // Memory is not sufficient. + throw ArpackError(ArpackError::MEMORY_OVERFLOW, + "ARluNonSymPencil::FactorAsB"); + } + else if (info > 0) { // Matrix is singular. + throw ArpackError(ArpackError::MATRIX_IS_SINGULAR, + "ARluNonSymPencil::FactorAsB"); + } + +} // FactorAsB (arcomplex shift). +#endif // ARCOMP_H. + + +template +void ARluNonSymPencil::MultInvBAv(ARTYPE* v, ARTYPE* w) +{ + + if (!B->IsFactored()) B->FactorA(); + + A->MultMv(v, w); + B->MultInvv(w, w); + +} // MultInvBAv. + + +#ifdef ARCOMP_H + +template +void ARluNonSymPencil:: +MultInvAsBv(arcomplex* v, arcomplex* w) +{ + + // Quitting the function if AsB was not factored. + + if (!IsFactored()) { + throw ArpackError(ArpackError::NOT_FACTORED_MATRIX, + "ARluNonSymPencil::MultInvAsBv"); + } + + // Solving AsB.w = v. + + int info; + SuperMatrix RHS; + + copy(A->nrows(), v, 1, w, 1); + Create_Dense_Matrix(&RHS, A->nrows(), 1, w, A->nrows(), SLU_DN, SLU_GE); +// gstrs("N", &L, &U, permr, permc, &RHS, &info); + trans_t trans = NOTRANS; + StatInit(&stat); + + gstrs(trans, &L, &U, permc, permr, &RHS, &stat, &info); + + Destroy_SuperMatrix_Store(&RHS); // delete RHS.Store; + +} // MultInvAsBv (arcomplex). + +#endif + + +template +void ARluNonSymPencil::MultInvAsBv(ARFLOAT* v, ARFLOAT* w) +{ + + // Quitting the function if AsB was not factored. + + if (!IsFactored()) { + throw ArpackError(ArpackError::NOT_FACTORED_MATRIX, + "ARluNonSymPencil::MultInvAsBv"); + } + + // Solving AsB.w = v. + + int info; + SuperMatrix RHS; + + if (part == 'N') { // shift is real. + + copy(A->nrows(), v, 1, w, 1); + Create_Dense_Matrix(&RHS, A->nrows(), 1, w, A->nrows(), SLU_DN, SLU_GE); + //gstrs("N", &L, &U, permr, permc, &RHS, &info); + trans_t trans = NOTRANS; + StatInit(&stat); + gstrs(trans, &L, &U, permc, permr, &RHS, &stat, &info); + + } + else { // shift is complex. + +#ifdef ARCOMP_H + + int i; + arcomplex *tv = new arcomplex[A->ncols()]; + + for (i=0; i!=A->ncols(); i++) tv[i] = arcomplex(v[i],0.0); + Create_Dense_Matrix(&RHS, A->ncols(), 1, tv, A->ncols(), SLU_DN, SLU_GE); + //gstrs("N", &L, &U, permr, permc, &RHS, &info); + trans_t trans = NOTRANS; + StatInit(&stat); + gstrs(trans, &L, &U, permc, permr, &RHS, &stat, &info); + + + if (part=='I') { + for (i=0; i!=A->ncols(); i++) w[i] = imag(tv[i]); + } + else { + for (i=0; i!=A->ncols(); i++) w[i] = real(tv[i]); + } + + delete[] tv; + +#endif + + } + + Destroy_SuperMatrix_Store(&RHS); // delete RHS.Store; + +} // MultInvAsBv (ARFLOAT). + + +template +inline void ARluNonSymPencil:: +DefineMatrices(ARluNonSymMatrix& Ap, + ARluNonSymMatrix& Bp) +{ + + A = &Ap; + B = &Bp; + permc = NULL; + permr = NULL; + + if ((A->n != B->n)||(A->m != B->m)) { + throw ArpackError(ArpackError::INCOMPATIBLE_SIZES, + "ARluNonSymMatrix::DefineMatrices"); + } + +} // DefineMatrices. + + +template +inline ARluNonSymPencil::ARluNonSymPencil() +{ + + factored = false; + part = 'N'; + permr = NULL; + permc = NULL; + +} // Short constructor. + + +template +inline ARluNonSymPencil:: +ARluNonSymPencil(ARluNonSymMatrix& Ap, + ARluNonSymMatrix& Bp) +{ + + factored = false; + DefineMatrices(Ap, Bp); + +} // Long constructor. + + +template +ARluNonSymPencil& ARluNonSymPencil:: +operator=(const ARluNonSymPencil& other) +{ + + if (this != &other) { // Stroustrup suggestion. + ClearMem(); + Copy(other); + } + return *this; + +} // operator=. + + +#endif // ARLNSPEN_H diff --git a/external/arpack++/include/arlscomp.h b/external/arpack++/include/arlscomp.h new file mode 100644 index 000000000..ed3b42dc2 --- /dev/null +++ b/external/arpack++/include/arlscomp.h @@ -0,0 +1,188 @@ +/* + ARPACK++ v1.2 2/20/2000 + c++ interface to ARPACK code. + + MODULE ARLSComp.h. + Arpack++ class ARluCompStdEig definition + (superlu version). + + ARPACK Authors + Richard Lehoucq + Danny Sorensen + Chao Yang + Dept. of Computational & Applied Mathematics + Rice University + Houston, Texas +*/ + +#ifndef ARLSCOMP_H +#define ARLSCOMP_H + +#include +#include +#include "arch.h" +#include "arscomp.h" +#include "arlnsmat.h" +#include "arrseig.h" + + +template +class ARluCompStdEig: + public virtual ARCompStdEig, ARFLOAT> > { + + protected: + + // a) Protected function: + + virtual void Copy(const ARluCompStdEig& other); + // Makes a deep copy of "other" over "this" object. + // Old values are not deleted (this function is to be used + // by the copy constructor and the assignment operator only). + + + public: + + // b) Public functions: + + // b.1) Functions that allow changes in problem parameters. + + virtual void ChangeShift(arcomplex sigmap); + + virtual void SetRegularMode(); + + virtual void SetShiftInvertMode(arcomplex sigmap); + + // b.2) Constructors and destructor. + + ARluCompStdEig() { } + // Short constructor. + + ARluCompStdEig(int nevp, ARluNonSymMatrix, ARFLOAT>& A, + const std::string& whichp = "LM", int ncvp = 0, + ARFLOAT tolp = 0.0, int maxitp = 0, + arcomplex* residp = NULL, bool ishiftp = true); + // Long constructor (regular mode). + + ARluCompStdEig(int nevp, ARluNonSymMatrix, ARFLOAT>& A, + arcomplex sigma, const std::string& whichp = "LM", + int ncvp = 0, ARFLOAT tolp = 0.0, int maxitp = 0, + arcomplex* residp = NULL, bool ishiftp = true); + // Long constructor (shift and invert mode). + + ARluCompStdEig(const ARluCompStdEig& other) { Copy(other); } + // Copy constructor. + + virtual ~ARluCompStdEig() { } + // Destructor. + + + // c) Operators. + + ARluCompStdEig& operator=(const ARluCompStdEig& other); + // Assignment operator. + +}; // class ARluCompStdEig. + + +// ------------------------------------------------------------------------ // +// ARluCompStdEig member functions definition. // +// ------------------------------------------------------------------------ // + + +template +inline void ARluCompStdEig:: +Copy(const ARluCompStdEig& other) +{ + + ARStdEig, + ARluNonSymMatrix, ARFLOAT> >:: + Copy(other); + if (this->mode > 2) this->objOP->FactorAsI(this->sigmaR); + +} // Copy. + + +template +inline void ARluCompStdEig::ChangeShift(arcomplex sigmap) +{ + + this->objOP->FactorAsI(sigmap); + ARrcStdEig >::ChangeShift(sigmap); + +} // ChangeShift. + + +template +inline void ARluCompStdEig::SetRegularMode() +{ + + ARStdEig, + ARluNonSymMatrix, ARFLOAT> >:: + SetRegularMode(this->objOP, + &ARluNonSymMatrix, ARFLOAT>::MultMv); + +} // SetRegularMode. + + +template +inline void ARluCompStdEig:: +SetShiftInvertMode(arcomplex sigmap) +{ + + ARStdEig, + ARluNonSymMatrix, ARFLOAT> >:: + SetShiftInvertMode(sigmap, this->objOP, + &ARluNonSymMatrix,ARFLOAT>::MultInvv); + +} // SetShiftInvertMode. + + +template +inline ARluCompStdEig:: +ARluCompStdEig(int nevp, ARluNonSymMatrix, ARFLOAT>& A, + const std::string& whichp, int ncvp, ARFLOAT tolp, + int maxitp, arcomplex* residp, bool ishiftp) + +{ + + this->NoShift(); + this->DefineParameters(A.ncols(), nevp, &A, + &ARluNonSymMatrix, ARFLOAT>::MultMv, + whichp, ncvp, tolp, maxitp, residp, ishiftp); + +} // Long constructor (regular mode). + + +template +inline ARluCompStdEig:: +ARluCompStdEig(int nevp, ARluNonSymMatrix, ARFLOAT>& A, + arcomplex sigmap, const std::string& whichp, int ncvp, + ARFLOAT tolp, int maxitp, arcomplex* residp, + bool ishiftp) + +{ + + this->DefineParameters(A.ncols(), nevp, &A, + &ARluNonSymMatrix, ARFLOAT>::MultInvv, + whichp, ncvp, tolp, maxitp, residp, ishiftp); + ChangeShift(sigmap); + +} // Long constructor (shift and invert mode). + + +template +ARluCompStdEig& ARluCompStdEig:: +operator=(const ARluCompStdEig& other) +{ + + if (this != &other) { // Stroustrup suggestion. + this->ClearMem(); + Copy(other); + } + return *this; + +} // operator=. + + +#endif // ARLSCOMP_H diff --git a/external/arpack++/include/arlsmat.h b/external/arpack++/include/arlsmat.h new file mode 100644 index 000000000..3c0ce079f --- /dev/null +++ b/external/arpack++/include/arlsmat.h @@ -0,0 +1,765 @@ +/* + ARPACK++ v1.2 2/20/2000 + c++ interface to ARPACK code. + + MODULE ARLSMat.h. + Arpack++ class ARluSymMatrix definition. + + ARPACK Authors + Richard Lehoucq + Danny Sorensen + Chao Yang + Dept. of Computational & Applied Mathematics + Rice University + Houston, Texas +*/ + + +#include "arlspen.h" + +#ifndef ARLSMAT_H +#define ARLSMAT_H + +#include +#include +#include "arch.h" +#include "armat.h" +#include "arhbmat.h" +#include "arerror.h" +#include "blas1c.h" +#include "superluc.h" +#include "arlspdef.h" +#include "arlutil.h" + +template class ARluSymPencil; + +template +class ARluSymMatrix: public ARMatrix { + + friend class ARluSymPencil; + + protected: + + bool factored; + char uplo; + int order; + int nnz; + int* irow; + int* pcol; + int* permc; + int* permr; + double threshold; + ARTYPE* a; + SuperMatrix A; + SuperMatrix L; + SuperMatrix U; + ARhbMatrix mat; + SuperLUStat_t stat; + + bool DataOK(); + + virtual void Copy(const ARluSymMatrix& other); + + void ClearMem(); + + void ExpandA(NCformat& A, NCformat& Aexp, ARTYPE sigma = (ARTYPE)0); + + public: + + int nzeros() { return nnz; } + + bool IsFactored() { return factored; } + + void FactorA(); + + void FactorAsI(ARTYPE sigma); + + void MultMv(ARTYPE* v, ARTYPE* w); + + void MultInvv(ARTYPE* v, ARTYPE* w); + + void DefineMatrix(int np, int nnzp, ARTYPE* ap, int* irowp, int* pcolp, + char uplop = 'L', double thresholdp = 0.1, + int orderp = 2, bool check = true); + + ARluSymMatrix(); + // Short constructor that does nothing. + + ARluSymMatrix(int np, int nnzp, ARTYPE* ap, int* irowp, int* pcolp, + char uplop = 'L', double thresholdp = 0.1, + int orderp = 2, bool check = true); + // Long constructor. + + ARluSymMatrix(const std::string& name, double thresholdp = 0.1, + int orderp = 2, bool check = true); + // Long constructor (Harwell-Boeing file). + + ARluSymMatrix(const ARluSymMatrix& other) { Copy(other); } + // Copy constructor. + + virtual ~ARluSymMatrix() { ClearMem(); } + // Destructor. + + ARluSymMatrix& operator=(const ARluSymMatrix& other); + // Assignment operator. + +}; + +// ------------------------------------------------------------------------ // +// ARluSymMatrix member functions definition. // +// ------------------------------------------------------------------------ // + + +template +bool ARluSymMatrix::DataOK() +{ + + int i, j, k; + + // Checking if pcol is in ascending order. + + i = 0; + while ((i!=this->n)&&(pcol[i]<=pcol[i+1])) i++; + if (i!=this->n) return false; + + // Checking if irow components are in order and within bounds. + + for (i=0; i!=this->n; i++) { + j = pcol[i]; + k = pcol[i+1]-1; + if (j<=k) { + if (uplo == 'U') { + if ((irow[j]<0)||(irow[k]>i)) return false; + } + else { // uplo == 'L'. + if ((irow[j]=this->n)) return false; + } + while ((j!=k)&&(irow[j] +inline void ARluSymMatrix::Copy(const ARluSymMatrix& other) +{ + + // Copying very fundamental variables. + + this->defined = other.defined; + factored = other.factored; + + // Returning from here if "other" was not initialized. + + if (!this->defined) return; + + // Copying user-defined parameters. + + DefineMatrix(other.n, other.nnz, other.a, other.irow, other.pcol, + other.uplo, other.threshold, other.order); + + // Throwing the original factorization away (this procedure + // is really awkward, but it is necessary because there + // is no copy function for matrices L and U in the SuperLU + // library and it is not a good idea to do this kind of deep + // copy here). + + if (factored) { + ArpackError(ArpackError::LAPACK_ERROR, "ARluSymMatrix"); + factored = false; + } + +} // Copy. + + +template +void ARluSymMatrix::ClearMem() +{ + + if (factored) { + Destroy_SuperNode_Matrix(&L); + Destroy_CompCol_Matrix(&U); + StatFree(&stat); + } + if (this->defined) { + Destroy_SuperMatrix_Store(&A); // delete A.Store; + delete[] permc; + delete[] permr; + permc = NULL; + permr = NULL; + A.Store = NULL; + } + +} // ClearMem. + + +template +void ARluSymMatrix:: +ExpandA(NCformat& A, NCformat& Aexp, ARTYPE sigma) +{ + + // Defining local variables. + + bool subtract; + int i, j, k; + int *colA, *colE; + int *indA, *indE; + ARTYPE *valA, *valE; + + // Checking if sigma is zero. + + subtract = (sigma != (ARTYPE)0); + + // Simplifying the notation. + + valA = (ARTYPE*)A.nzval; + valE = (ARTYPE*)Aexp.nzval; + indA = (int*)A.rowind; + indE = (int*)Aexp.rowind; + colA = (int*)A.colptr; + colE = (int*)Aexp.colptr; + + // Filling colE with zeros. + + for (i=0; i<=this->n; i++) colE[i] = 0; + + // Counting the elements in each column of A. + + if (uplo == 'U') { + + for (i=0; i!=this->n; i++) { + k = colA[i+1]; + if ((k!=colA[i])&&(indA[k-1]==i)) { + k--; + } + else { + if (subtract) colE[i]++; + } + for (j=colA[i]; jn; i++) { + k = colA[i]; + if ((k!=colA[i+1])&&(indA[k]==i)) { + k++; + } + else { + if (subtract) colE[i]++; + } + for (j=k; jn; i++) colE[i+1]+=colE[i]; + + // Adding colA to colE. + + for (i=this->n; i>0; i--) colE[i] = colE[i-1]+colA[i]; + colE[0] = colA[0]; + + // Expanding A. + + if (uplo == 'U') { + + for (i=0; in; i++) { + for (j=colA[i]; j<(colA[i+1]-1); j++) { + indE[colE[i]] = indA[j]; + indE[colE[indA[j]]] = i; + valE[colE[i]++] = valA[j]; + valE[colE[indA[j]]++] = valA[j]; + } + if ((colA[i]!=colA[i+1])&&(indA[j]==i)) { + indE[colE[i]] = i; + if (subtract) { + valE[colE[i]++] = valA[j]-sigma; + } + else { + valE[colE[i]++] = valA[j]; + } + } + else { + if (subtract) { + indE[colE[i]] = i; + valE[colE[i]++] = -sigma; + } + } + } + + } + else { // uplo == 'L' + + for (i=0; in; i++) { + k=colA[i]; + if ((k!=colA[i+1])&&(indA[k]==i)) { + indE[colE[i]] = i; + if (subtract) { + valE[colE[i]++] = valA[k]-sigma; + } + else { + valE[colE[i]++] = valA[k]; + } + k++; + } + else { + if (subtract) { + indE[colE[i]] = i; + valE[colE[i]++] = -sigma; + } + } + for (j=k; jn; i>0; i--) { + colE[i] = colE[i-1]; + } + colE[0] = 0; + + Aexp.nnz = colE[this->n]; + +} // ExpandA. + + +template +void ARluSymMatrix::FactorA() +{ + + // Quitting the function if A was not defined. + + if (!this->IsDefined()) { + throw ArpackError(ArpackError::DATA_UNDEFINED, "ARluSymMatrix::FactorA"); + } + + // Defining local variables. + + int info; + int* etree; + int* irowi; + int* pcoli; + ARTYPE* aexp; + SuperMatrix Aexp; + SuperMatrix AC; + NCformat* Astore; + NCformat* Aexpstore; + + // Deleting previous versions of L and U. + + if (factored) { + Destroy_SuperNode_Matrix(&L); + Destroy_CompCol_Matrix(&U); + StatFree(&stat); + } + + // Setting default values for gstrf parameters. + + int panel_size = sp_ienv(1); + int relax = sp_ienv(2); + superlu_options_t options; + + /* Set the default input options: + options.Fact = DOFACT; + options.Equil = YES; + options.ColPerm = COLAMD; + options.DiagPivotThresh = 1.0; + options.Trans = NOTRANS; + options.IterRefine = NOREFINE; + options.SymmetricMode = NO; + options.PivotGrowth = NO; + options.ConditionNumber = NO; + options.PrintStat = YES; + */ + set_default_options(&options); + + /* Now we modify the default options to use the symmetric mode. */ + options.SymmetricMode = YES; + options.ColPerm = MMD_AT_PLUS_A; + // options.DiagPivotThresh = 0.001; + options.DiagPivotThresh = threshold; + + // Creating a temporary matrix Aexp. + + irowi = (int*)SUPERLU_MALLOC(sizeof(int) * (nnz*2)); + pcoli = (int*)SUPERLU_MALLOC(sizeof(int) * (this->n+1)); + aexp = (ARTYPE*)SUPERLU_MALLOC(sizeof(ARTYPE) * (nnz*2)); + Create_CompCol_Matrix(&Aexp, this->n, this->n, nnz, aexp, irowi, pcoli, SLU_NC, SLU_GE); + + // Expanding A. + + Astore = (NCformat*)A.Store; + Aexpstore = (NCformat*)Aexp.Store; + ExpandA(*Astore, *Aexpstore); + + // Reserving memory for etree (used in matrix decomposition). + + etree = new int[this->n]; + + // Defining LUStat. + + //StatInit(panel_size, relax); + StatInit(&stat); + + // Defining the column permutation of matrix A + // (using minimum degree ordering). + + get_perm_c(order, &Aexp, permc); + + // Permuting columns of A and creating the elimination tree. + + //sp_preorder("N", &Aexp, permc, etree, &AC); + sp_preorder(&options, &Aexp, permc, etree, &AC); + + // Decomposing A. + +// gstrf("N",&AC, threshold, drop_tol, relax, panel_size, etree, +// NULL, 0, permr, permc, &L, &U, &info); + gstrf(&options,&AC, relax, panel_size, etree, + NULL, 0, permc, permr, &L, &U, &stat, &info); + + // Deleting AC, Aexp and etree. + + Destroy_CompCol_Permuted(&AC); + Destroy_CompCol_Matrix(&Aexp); + delete[] etree; + + factored = (info == 0); + + // Handling errors. + + if (info < 0) { // Illegal argument. + throw ArpackError(ArpackError::PARAMETER_ERROR, + "ARluSymMatrix::FactorA"); + } + else if (info > this->n) { // Memory is not sufficient. + throw ArpackError(ArpackError::MEMORY_OVERFLOW, + "ARluSymMatrix::FactorA"); + } + else if (info > 0) { // Matrix is singular. + throw ArpackError(ArpackError::MATRIX_IS_SINGULAR, + "ARluSymMatrix::FactorA"); + } + +} // FactorA. + + +template +void ARluSymMatrix::FactorAsI(ARTYPE sigma) +{ + + // Quitting the function if A was not defined. + + if (!this->IsDefined()) { + throw ArpackError(ArpackError::DATA_UNDEFINED, "ARluSymMatrix::FactorAsI"); + } + + // Defining local variables. + + int info; + int* etree; + int* irowi; + int* pcoli; + ARTYPE* asi; + SuperMatrix AsI; + SuperMatrix AC; + NCformat* Astore; + NCformat* AsIstore; + + // Deleting previous versions of L and U. + + if (factored) { + Destroy_SuperNode_Matrix(&L); + Destroy_CompCol_Matrix(&U); + StatFree(&stat); + } + + // Setting default values for gstrf parameters. + + int panel_size = sp_ienv(1); + int relax = sp_ienv(2); + superlu_options_t options; + + /* Set the default input options: + options.Fact = DOFACT; + options.Equil = YES; + options.ColPerm = COLAMD; + options.DiagPivotThresh = 1.0; + options.Trans = NOTRANS; + options.IterRefine = NOREFINE; + options.SymmetricMode = NO; + options.PivotGrowth = NO; + options.ConditionNumber = NO; + options.PrintStat = YES; + */ + set_default_options(&options); + + /* Now we modify the default options to use the symmetric mode. */ + options.SymmetricMode = YES; + options.ColPerm = MMD_AT_PLUS_A; + // options.DiagPivotThresh = 0.001; + options.DiagPivotThresh = threshold; + + // Creating a temporary matrix AsI. + + irowi = (int*)SUPERLU_MALLOC(sizeof(int) * (nnz*2+this->n)); + pcoli = (int*)SUPERLU_MALLOC(sizeof(int) * (this->n+1)); + asi = (ARTYPE*)SUPERLU_MALLOC(sizeof(ARTYPE) * (nnz*2+this->n)); + Create_CompCol_Matrix(&AsI, this->n, this->n, nnz, asi, irowi, pcoli, SLU_NC, SLU_GE); + + // Subtracting sigma*I from A and storing the result on AsI. + + Astore = (NCformat*)A.Store; + AsIstore = (NCformat*)AsI.Store; + ExpandA(*Astore, *AsIstore, sigma); + + // Reserving memory for etree (used in matrix decomposition). + + etree = new int[this->n]; + + // Defining LUStat. + + //StatInit(panel_size, relax); + StatInit(&stat); + + // Defining the column permutation of matrix AsI + // (using minimum degree ordering). + + get_perm_c(order, &AsI, permc); + + // Permuting columns of AsI and creating the elimination tree. + + sp_preorder(&options, &AsI, permc, etree, &AC); + + // Decomposing AsI. + +// gstrf("N",&AC, threshold, drop_tol, relax, panel_size, etree, +// NULL, 0, permr, permc, &L, &U, &info); + gstrf(&options,&AC, relax, panel_size, etree, + NULL, 0, permc, permr, &L, &U, &stat, &info); + + // Deleting AC, AsI and etree. + + Destroy_CompCol_Permuted(&AC); + Destroy_CompCol_Matrix(&AsI); + delete[] etree; + + factored = (info == 0); + + // Handling errors. + + if (info < 0) { // Illegal argument. + throw ArpackError(ArpackError::PARAMETER_ERROR, + "ARluSymMatrix::FactorAsI"); + } + else if (info > this->n) { // Memory is not sufficient. + throw ArpackError(ArpackError::MEMORY_OVERFLOW, + "ARluSymMatrix::FactorAsI"); + } + else if (info > 0) { // Matrix is singular. + throw ArpackError(ArpackError::MATRIX_IS_SINGULAR, + "ARluSymMatrix::FactorAsI"); + } + +} // FactorAsI. + + +template +void ARluSymMatrix::MultMv(ARTYPE* v, ARTYPE* w) +{ + + int i, j, k; + ARTYPE t; + + // Quitting the function if A was not defined. + + if (!this->IsDefined()) { + throw ArpackError(ArpackError::DATA_UNDEFINED, "ARluSymMatrix::MultMv"); + } + + // Determining w = M.v. + + for (i=0; i!=this->m; i++) w[i]=(ARTYPE)0; + + if (uplo == 'U') { + + for (i=0; i!=this->n; i++) { + t = v[i]; + k = pcol[i+1]; + if ((k!=pcol[i])&&(irow[k-1]==i)) { + w[i] += t*a[k-1]; + k--; + } + for (j=pcol[i]; jn; i++) { + t = v[i]; + k = pcol[i]; + if ((k!=pcol[i+1])&&(irow[k]==i)) { + w[i] += t*a[k]; + k++; + } + for (j=k; j +void ARluSymMatrix::MultInvv(ARTYPE* v, ARTYPE* w) +{ + + // Quitting the function if A (or AsI) was not factored. + + if (!IsFactored()) { + throw ArpackError(ArpackError::NOT_FACTORED_MATRIX, + "ARluSymMatrix::MultInvv"); + } + + // Solving A.w = v (or AsI.w = v). + + int info; + SuperMatrix B; + + if (&v != &w) copy(this->n, v, 1, w, 1); + Create_Dense_Matrix(&B, this->n, 1, w, this->n, SLU_DN, SLU_GE); +// gstrs("N", &L, &U, permr, permc, &B, &info); + StatInit(&stat); + trans_t trans = NOTRANS; + gstrs(trans, &L, &U, permc, permr, &B, &stat, &info); + Destroy_SuperMatrix_Store(&B); // delete B.Store; + +} // MultInvv. + + +template +inline void ARluSymMatrix:: +DefineMatrix(int np, int nnzp, ARTYPE* ap, int* irowp, int* pcolp, + char uplop, double thresholdp, int orderp, bool check) +{ + + this->m = np; + this->n = np; + nnz = nnzp; + a = ap; + irow = irowp; + pcol = pcolp; + pcol[this->n] = nnz; + uplo = uplop; + threshold = thresholdp; + order = orderp; + + // Checking data. + + if ((check)&&(!DataOK())) { + throw ArpackError(ArpackError::INCONSISTENT_DATA, + "ARluSymMatrix::DefineMatrix"); + } + + // Creating SuperMatrix A. + + Create_CompCol_Matrix(&A, this->n, this->n, nnz, a, irow, pcol, SLU_NC, SLU_GE); + + // Reserving memory for vectors used in matrix decomposition. + + permc = new int[this->n]; + permr = new int[this->n]; + + this->defined = true; + +} // DefineMatrix. + + +template +inline ARluSymMatrix::ARluSymMatrix(): ARMatrix() +{ + + factored = false; + permc = NULL; + permr = NULL; + +} // Short constructor. + + +template +inline ARluSymMatrix:: +ARluSymMatrix(int np, int nnzp, ARTYPE* ap, int* irowp, + int* pcolp, char uplop, double thresholdp, + int orderp, bool check) : ARMatrix(np) +{ + + factored = false; + DefineMatrix(np, nnzp, ap, irowp, pcolp, uplop, thresholdp, orderp, check); + +} // Long constructor. + + +template +ARluSymMatrix:: +ARluSymMatrix(const std::string& file, double thresholdp, int orderp, bool check) +{ + + factored = false; + + try { + mat.Define(file); + } + catch (ArpackError) { // Returning from here if an error has occurred. + throw ArpackError(ArpackError::CANNOT_READ_FILE, "ARluSymMatrix"); + } + + if ((mat.NCols() == mat.NRows()) && (mat.IsSymmetric())) { + + DefineMatrix(mat.NCols(), mat.NonZeros(), (ARTYPE*)mat.Entries(), + mat.RowInd(), mat.ColPtr(), 'L', thresholdp, orderp, check); + } + else { + throw ArpackError(ArpackError::INCONSISTENT_DATA, + "ARluSymMatrix::ARluSymMatrix"); + } + +} // Long constructor (Harwell-Boeing file). + + +template +ARluSymMatrix& ARluSymMatrix:: +operator=(const ARluSymMatrix& other) +{ + + if (this != &other) { // Stroustrup suggestion. + ClearMem(); + Copy(other); + } + return *this; + +} // operator=. + + +#endif // ARLSMAT_H diff --git a/external/arpack++/include/arlsnsym.h b/external/arpack++/include/arlsnsym.h new file mode 100644 index 000000000..e6369ada4 --- /dev/null +++ b/external/arpack++/include/arlsnsym.h @@ -0,0 +1,182 @@ +/* + ARPACK++ v1.2 2/20/2000 + c++ interface to ARPACK code. + + MODULE ARLSNSym.h. + Arpack++ class ARluNonSymStdEig definition + (SuperLU version). + + ARPACK Authors + Richard Lehoucq + Danny Sorensen + Chao Yang + Dept. of Computational & Applied Mathematics + Rice University + Houston, Texas +*/ + +#ifndef ARLSNSYM_H +#define ARLSNSYM_H + +#include +#include +#include "arch.h" +#include "arsnsym.h" +#include "arlnsmat.h" + +template +class ARluNonSymStdEig: + public virtual ARNonSymStdEig > { + + protected: + + // a) Protected function: + + virtual void Copy(const ARluNonSymStdEig& other); + // Makes a deep copy of "other" over "this" object. + // Old values are not deleted (this function is to be used + // by the copy constructor and the assignment operator only). + + + public: + + // b) Public functions: + + // b.1) Functions that allow changes in problem parameters. + + virtual void ChangeShift(ARFLOAT sigmaRp); + + virtual void SetRegularMode(); + + virtual void SetShiftInvertMode(ARFLOAT sigmap); + + // b.2) Constructors and destructor. + + ARluNonSymStdEig() { } + // Short constructor. + + ARluNonSymStdEig(int nevp, ARluNonSymMatrix& A, + const std::string& whichp = "LM", int ncvp = 0, + ARFLOAT tolp = 0.0, int maxitp = 0, + ARFLOAT* residp = NULL, bool ishiftp = true); + // Long constructor (regular mode). + + ARluNonSymStdEig(int nevp, ARluNonSymMatrix& A, + ARFLOAT sigma, const std::string& whichp = "LM", int ncvp = 0, + ARFLOAT tolp = 0.0, int maxitp = 0, + ARFLOAT* residp = NULL, bool ishiftp = true); + // Long constructor (shift and invert mode). + + ARluNonSymStdEig(const ARluNonSymStdEig& other) { Copy(other); } + // Copy constructor. + + virtual ~ARluNonSymStdEig() { } + // Destructor. + + // c) Operators. + + ARluNonSymStdEig& operator=(const ARluNonSymStdEig& other); + // Assignment operator. + +}; // class ARluNonSymStdEig. + + +// ------------------------------------------------------------------------ // +// ARluNonSymStdEig member functions definition. // +// ------------------------------------------------------------------------ // + + +template +inline void ARluNonSymStdEig:: +Copy(const ARluNonSymStdEig& other) +{ + + ARStdEig >:: Copy(other); + if (this->mode > 2) this->objOP->FactorAsI(this->sigmaR); + +} // Copy. + + +template +inline void ARluNonSymStdEig::ChangeShift(ARFLOAT sigmaRp) +{ + + this->sigmaR = sigmaRp; + this->sigmaI = 0.0; + this->mode = 3; + this->iparam[7] = this->mode; + + this->objOP->FactorAsI(this->sigmaR); + this->Restart(); + +} // ChangeShift. + + +template +inline void ARluNonSymStdEig::SetRegularMode() +{ + + ARStdEig >:: + SetRegularMode(this->objOP, &ARluNonSymMatrix::MultMv); + +} // SetRegularMode. + + +template +inline void ARluNonSymStdEig::SetShiftInvertMode(ARFLOAT sigmap) +{ + + ARStdEig >:: + SetShiftInvertMode(sigmap, this->objOP, + &ARluNonSymMatrix::MultInvv); + +} // SetShiftInvertMode. + + +template +inline ARluNonSymStdEig:: +ARluNonSymStdEig(int nevp, ARluNonSymMatrix& A, + const std::string& whichp, int ncvp, ARFLOAT tolp, + int maxitp, ARFLOAT* residp, bool ishiftp) + +{ + + this->NoShift(); + this->DefineParameters(A.ncols(), nevp, &A, + &ARluNonSymMatrix::MultMv, + whichp, ncvp, tolp, maxitp, residp, ishiftp); + +} // Long constructor (regular mode). + + +template +inline ARluNonSymStdEig:: +ARluNonSymStdEig(int nevp, ARluNonSymMatrix& A, + ARFLOAT sigmap, const std::string& whichp, int ncvp, ARFLOAT tolp, + int maxitp, ARFLOAT* residp, bool ishiftp) + +{ + + this->DefineParameters(A.ncols(), nevp, &A, + &ARluNonSymMatrix::MultInvv, + whichp, ncvp, tolp, maxitp, residp, ishiftp); + ChangeShift(sigmap); + +} // Long constructor (shift and invert mode). + + +template +ARluNonSymStdEig& ARluNonSymStdEig:: +operator=(const ARluNonSymStdEig& other) +{ + + if (this != &other) { // Stroustrup suggestion. + this->ClearMem(); + Copy(other); + } + return *this; + +} // operator=. + + +#endif // ARLSNSYM_H diff --git a/external/arpack++/include/arlspdef.h b/external/arpack++/include/arlspdef.h new file mode 100644 index 000000000..3dec1cc73 --- /dev/null +++ b/external/arpack++/include/arlspdef.h @@ -0,0 +1,610 @@ +/* + ARPACK++ v1.2 2/20/2000 + c++ interface to ARPACK code. + + MODULE ARLSpDef.h. + ALTERED version of slu_sdefs.h slu_ddefs.h slu_cdefs.h slu_zdefs.h + (from SuperLU 3.0 package). +*/ + + +#ifndef __SUPERLU_SP_DEFS /* allow multiple inclusions */ +#define __SUPERLU_SP_DEFS + +/* + * File name: sp_defs.h + * Purpose: Sparse matrix types and function prototypes + * History: + */ +#include "arlnames.h" +#include "arlsupm.h" +#include "arlcomp.h" +#include "arlutil.h" +#ifdef _CRAY +#include +#include +#endif + +/* Define my integer type int_t */ +typedef int int_t; /* default */ + +// /* No of marker arrays used in the symbolic factorization, +// each of size n */ +// #define NO_MARKER 3 +// #define NUM_TEMPV(m,w,t,b) ( MAX(m, (t + b)*w) ) +// +// typedef enum {LUSUP, UCOL, LSUB, USUB} MemType; +// typedef enum {HEAD, TAIL} stack_end_t; +// typedef enum {SYSTEM, USER} LU_space_t; + +/* + * Global data structures used in LU factorization - + * + * nsuper: #supernodes = nsuper + 1, numbered [0, nsuper]. + * (xsup,supno): supno[i] is the supernode no to which i belongs; + * xsup(s) points to the beginning of the s-th supernode. + * e.g. supno 0 1 2 2 3 3 3 4 4 4 4 4 (n=12) + * xsup 0 1 2 4 7 12 + * Note: dfs will be performed on supernode rep. relative to the new + * row pivoting ordering + * + * (xlsub,lsub): lsub[*] contains the compressed subscript of + * rectangular supernodes; xlsub[j] points to the starting + * location of the j-th column in lsub[*]. Note that xlsub + * is indexed by column. + * Storage: original row subscripts + * + * During the course of sparse LU factorization, we also use + * (xlsub,lsub) for the purpose of symmetric pruning. For each + * supernode {s,s+1,...,t=s+r} with first column s and last + * column t, the subscript set + * lsub[j], j=xlsub[s], .., xlsub[s+1]-1 + * is the structure of column s (i.e. structure of this supernode). + * It is used for the storage of numerical values. + * Furthermore, + * lsub[j], j=xlsub[t], .., xlsub[t+1]-1 + * is the structure of the last column t of this supernode. + * It is for the purpose of symmetric pruning. Therefore, the + * structural subscripts can be rearranged without making physical + * interchanges among the numerical values. + * + * However, if the supernode has only one column, then we + * only keep one set of subscripts. For any subscript interchange + * performed, similar interchange must be done on the numerical + * values. + * + * The last column structures (for pruning) will be removed + * after the numercial LU factorization phase. + * + * (xlusup,lusup): lusup[*] contains the numerical values of the + * rectangular supernodes; xlusup[j] points to the starting + * location of the j-th column in storage vector lusup[*] + * Note: xlusup is indexed by column. + * Each rectangular supernode is stored by column-major + * scheme, consistent with Fortran 2-dim array storage. + * + * (xusub,ucol,usub): ucol[*] stores the numerical values of + * U-columns outside the rectangular supernodes. The row + * subscript of nonzero ucol[k] is stored in usub[k]. + * xusub[i] points to the starting location of column i in ucol. + * Storage: new row subscripts; that is subscripts of PA. + */ + +typedef struct { + int *xsup; /* supernode and column mapping */ + int *supno; + int *lsub; /* compressed L subscripts */ + int *xlsub; + float *lusup; /* L supernodes */ + int *xlusup; + float *ucol; /* U columns */ + int *usub; + int *xusub; + int nzlmax; /* current max size of lsub */ + int nzumax; /* " " " ucol */ + int nzlumax; /* " " " lusup */ + int n; /* number of columns in the matrix */ + LU_space_t MemModel; /* 0 - system malloc'd; 1 - user provided */ + int num_expansions; + ExpHeader *expanders; /* Array of pointers to 4 types of memory */ + LU_stack_t stack; /* use user supplied memory */ +} sGlobalLU_t; + +typedef struct { + int *xsup; /* supernode and column mapping */ + int *supno; + int *lsub; /* compressed L subscripts */ + int *xlsub; + double *lusup; /* L supernodes */ + int *xlusup; + double *ucol; /* U columns */ + int *usub; + int *xusub; + int nzlmax; /* current max size of lsub */ + int nzumax; /* " " " ucol */ + int nzlumax; /* " " " lusup */ + int n; /* number of columns in the matrix */ + LU_space_t MemModel; /* 0 - system malloc'd; 1 - user provided */ + int num_expansions; + ExpHeader *expanders; /* Array of pointers to 4 types of memory */ + LU_stack_t stack; /* use user supplied memory */ +} dGlobalLU_t; + +typedef struct { + int *xsup; /* supernode and column mapping */ + int *supno; + int *lsub; /* compressed L subscripts */ + int *xlsub; + lscomplex *lusup; /* L supernodes */ + int *xlusup; + lscomplex *ucol; /* U columns */ + int *usub; + int *xusub; + int nzlmax; /* current max size of lsub */ + int nzumax; /* " " " ucol */ + int nzlumax; /* " " " lusup */ + int n; /* number of columns in the matrix */ + LU_space_t MemModel; /* 0 - system malloc'd; 1 - user provided */ + int num_expansions; + ExpHeader *expanders; /* Array of pointers to 4 types of memory */ + LU_stack_t stack; /* use user supplied memory */ +} cGlobalLU_t; + +typedef struct { + int *xsup; /* supernode and column mapping */ + int *supno; + int *lsub; /* compressed L subscripts */ + int *xlsub; + ldcomplex *lusup; /* L supernodes */ + int *xlusup; + ldcomplex *ucol; /* U columns */ + int *usub; + int *xusub; + int nzlmax; /* current max size of lsub */ + int nzumax; /* " " " ucol */ + int nzlumax; /* " " " lusup */ + int n; /* number of columns in the matrix */ + LU_space_t MemModel; /* 0 - system malloc'd; 1 - user provided */ + int num_expansions; + ExpHeader *expanders; /* Array of pointers to 4 types of memory */ + LU_stack_t stack; /* use user supplied memory */ +} zGlobalLU_t; + +// typedef struct { +// int panel_size; +// int relax; +// float diag_pivot_thresh; +// float drop_tol; +// } sfactor_param_t; +// +// typedef struct { +// int panel_size; +// int relax; +// double diag_pivot_thresh; +// double drop_tol; +// } dfactor_param_t; +// +//typedef struct { +// float for_lu; +// float total_needed; +// int expansions; +//} mem_usage_t; + +#ifdef __cplusplus +extern "C" { +#endif + +/* Driver routines */ +extern void +sgssv(superlu_options_t *, SuperMatrix *, int *, int *, SuperMatrix *, + SuperMatrix *, SuperMatrix *, SuperLUStat_t *, int *); +extern void +dgssv(superlu_options_t *, SuperMatrix *, int *, int *, SuperMatrix *, + SuperMatrix *, SuperMatrix *, SuperLUStat_t *, int *); +extern void +cgssv(superlu_options_t *, SuperMatrix *, int *, int *, SuperMatrix *, + SuperMatrix *, SuperMatrix *, SuperLUStat_t *, int *); +extern void +zgssv(superlu_options_t *, SuperMatrix *, int *, int *, SuperMatrix *, + SuperMatrix *, SuperMatrix *, SuperLUStat_t *, int *); +extern void +sgssvx(superlu_options_t *, SuperMatrix *, int *, int *, int *, + char *, float *, float *, SuperMatrix *, SuperMatrix *, + void *, int, SuperMatrix *, SuperMatrix *, + float *, float *, float *, float *, + sGlobalLU_t *, mem_usage_t *, SuperLUStat_t *, int *); +extern void +dgssvx(superlu_options_t *, SuperMatrix *, int *, int *, int *, + char *, double *, double *, SuperMatrix *, SuperMatrix *, + void *, int, SuperMatrix *, SuperMatrix *, + double *, double *, double *, double *, + dGlobalLU_t *, mem_usage_t *, SuperLUStat_t *, int *); +extern void +cgssvx(superlu_options_t *, SuperMatrix *, int *, int *, int *, + char *, float *, float *, SuperMatrix *, SuperMatrix *, + void *, int, SuperMatrix *, SuperMatrix *, + float *, float *, float *, float *, + cGlobalLU_t *, mem_usage_t *, SuperLUStat_t *, int *); +extern void +zgssvx(superlu_options_t *, SuperMatrix *, int *, int *, int *, + char *, double *, double *, SuperMatrix *, SuperMatrix *, + void *, int, SuperMatrix *, SuperMatrix *, + double *, double *, double *, double *, + zGlobalLU_t *, mem_usage_t *, SuperLUStat_t *, int *); + +/* Supernodal LU factor related */ +extern void +sCreate_CompCol_Matrix(SuperMatrix *, int, int, int, float *, + int *, int *, Stype_t, Dtype_t, Mtype_t); +extern void +dCreate_CompCol_Matrix(SuperMatrix *, int, int, int, double *, + int *, int *, Stype_t, Dtype_t, Mtype_t); +extern void +cCreate_CompCol_Matrix(SuperMatrix *, int, int, int, lscomplex *, + int *, int *, Stype_t, Dtype_t, Mtype_t); +extern void +zCreate_CompCol_Matrix(SuperMatrix *, int, int, int, ldcomplex *, + int *, int *, Stype_t, Dtype_t, Mtype_t); +extern void +sCreate_CompRow_Matrix(SuperMatrix *, int, int, int, float *, + int *, int *, Stype_t, Dtype_t, Mtype_t); +extern void +dCreate_CompRow_Matrix(SuperMatrix *, int, int, int, double *, + int *, int *, Stype_t, Dtype_t, Mtype_t); +extern void +cCreate_CompRow_Matrix(SuperMatrix *, int, int, int, lscomplex *, + int *, int *, Stype_t, Dtype_t, Mtype_t); +extern void +zCreate_CompRow_Matrix(SuperMatrix *, int, int, int, ldcomplex *, + int *, int *, Stype_t, Dtype_t, Mtype_t); +extern void +sCopy_CompCol_Matrix(SuperMatrix *, SuperMatrix *); +extern void +dCopy_CompCol_Matrix(SuperMatrix *, SuperMatrix *); +extern void +cCopy_CompCol_Matrix(SuperMatrix *, SuperMatrix *); +extern void +zCopy_CompCol_Matrix(SuperMatrix *, SuperMatrix *); +extern void +sCreate_Dense_Matrix(SuperMatrix *, int, int, float *, int, + Stype_t, Dtype_t, Mtype_t); +extern void +dCreate_Dense_Matrix(SuperMatrix *, int, int, double *, int, + Stype_t, Dtype_t, Mtype_t); +extern void +cCreate_Dense_Matrix(SuperMatrix *, int, int, lscomplex *, int, + Stype_t, Dtype_t, Mtype_t); +extern void +zCreate_Dense_Matrix(SuperMatrix *, int, int, ldcomplex *, int, + Stype_t, Dtype_t, Mtype_t); +extern void +sCreate_SuperNode_Matrix(SuperMatrix *, int, int, int, float *, + int *, int *, int *, int *, int *, + Stype_t, Dtype_t, Mtype_t); +extern void +dCreate_SuperNode_Matrix(SuperMatrix *, int, int, int, double *, + int *, int *, int *, int *, int *, + Stype_t, Dtype_t, Mtype_t); +extern void +cCreate_SuperNode_Matrix(SuperMatrix *, int, int, int, lscomplex *, + int *, int *, int *, int *, int *, + Stype_t, Dtype_t, Mtype_t); +extern void +zCreate_SuperNode_Matrix(SuperMatrix *, int, int, int, ldcomplex *, + int *, int *, int *, int *, int *, + Stype_t, Dtype_t, Mtype_t); +extern void +sCopy_Dense_Matrix(int, int, float *, int, float *, int); +extern void +dCopy_Dense_Matrix(int, int, double *, int, double *, int); +extern void +cCopy_Dense_Matrix(int, int, lscomplex *, int, lscomplex *, int); +extern void +zCopy_Dense_Matrix(int, int, ldcomplex *, int, ldcomplex *, int); + +// extern void Destroy_SuperMatrix_Store(SuperMatrix *); +// extern void Destroy_CompCol_Matrix(SuperMatrix *); +// extern void Destroy_SuperNode_Matrix(SuperMatrix *); +// extern void Destroy_CompCol_Permuted(SuperMatrix *); +// extern void Destroy_Dense_Matrix(SuperMatrix *); +// extern void get_perm_c(int, SuperMatrix *, int *); +// extern void sp_preorder (char*, SuperMatrix*, int*, int*, SuperMatrix*); +// // extern void countnz (const int, int *, int *, int *, sGlobalLU_t *); +// // extern void fixupL (const int, const int *, sGlobalLU_t *); + +extern void sallocateA (int, int, float **, int **, int **); +extern void dallocateA (int, int, double **, int **, int **); +extern void callocateA (int, int, lscomplex **, int **, int **); +extern void zallocateA (int, int, ldcomplex **, int **, int **); +extern void sgstrf (superlu_options_t*, SuperMatrix*, + int, int, int*, void *, int, int *, int *, + SuperMatrix *, SuperMatrix *, sGlobalLU_t *, SuperLUStat_t*, int *); +extern void dgstrf (superlu_options_t*, SuperMatrix*, + int, int, int*, void *, int, int *, int *, + SuperMatrix *, SuperMatrix *, dGlobalLU_t *, SuperLUStat_t*, int *); +extern void cgstrf (superlu_options_t*, SuperMatrix*, + int, int, int*, void *, int, int *, int *, + SuperMatrix *, SuperMatrix *, cGlobalLU_t *, SuperLUStat_t*, int *); +extern void zgstrf (superlu_options_t*, SuperMatrix*, + int, int, int*, void *, int, int *, int *, + SuperMatrix *, SuperMatrix *, zGlobalLU_t *, SuperLUStat_t*, int *); +extern int ssnode_dfs (const int, const int, const int *, const int *, + const int *, int *, int *, sGlobalLU_t *); +extern int dsnode_dfs (const int, const int, const int *, const int *, + const int *, int *, int *, dGlobalLU_t *); +extern int csnode_dfs (const int, const int, const int *, const int *, + const int *, int *, int *, cGlobalLU_t *); +extern int zsnode_dfs (const int, const int, const int *, const int *, + const int *, int *, int *, zGlobalLU_t *); +extern int ssnode_bmod (const int, const int, const int, float *, + float *, sGlobalLU_t *, SuperLUStat_t*); +extern int dsnode_bmod (const int, const int, const int, double *, + double *, dGlobalLU_t *, SuperLUStat_t*); +extern int csnode_bmod (const int, const int, const int, lscomplex *, + lscomplex *, cGlobalLU_t *, SuperLUStat_t*); +extern int zsnode_bmod (const int, const int, const int, ldcomplex *, + ldcomplex *, zGlobalLU_t *, SuperLUStat_t*); +extern void spanel_dfs (const int, const int, const int, SuperMatrix *, + int *, int *, float *, int *, int *, int *, + int *, int *, int *, int *, sGlobalLU_t *); +extern void dpanel_dfs (const int, const int, const int, SuperMatrix *, + int *, int *, double *, int *, int *, int *, + int *, int *, int *, int *, dGlobalLU_t *); +extern void cpanel_dfs (const int, const int, const int, SuperMatrix *, + int *, int *, lscomplex *, int *, int *, int *, + int *, int *, int *, int *, cGlobalLU_t *); +extern void zpanel_dfs (const int, const int, const int, SuperMatrix *, + int *, int *, ldcomplex *, int *, int *, int *, + int *, int *, int *, int *, zGlobalLU_t *); +extern void spanel_bmod (const int, const int, const int, const int, + float *, float *, int *, int *, + sGlobalLU_t *, SuperLUStat_t*); +extern void dpanel_bmod (const int, const int, const int, const int, + double *, double *, int *, int *, + dGlobalLU_t *, SuperLUStat_t*); +extern void cpanel_bmod (const int, const int, const int, const int, + lscomplex *, lscomplex *, int *, int *, + cGlobalLU_t *, SuperLUStat_t*); +extern void zpanel_bmod (const int, const int, const int, const int, + ldcomplex *, ldcomplex *, int *, int *, + zGlobalLU_t *, SuperLUStat_t*); +extern int scolumn_dfs (const int, const int, int *, int *, int *, int *, + int *, int *, int *, int *, int *, sGlobalLU_t *); +extern int dcolumn_dfs (const int, const int, int *, int *, int *, int *, + int *, int *, int *, int *, int *, dGlobalLU_t *); +extern int ccolumn_dfs (const int, const int, int *, int *, int *, int *, + int *, int *, int *, int *, int *, cGlobalLU_t *); +extern int zcolumn_dfs (const int, const int, int *, int *, int *, int *, + int *, int *, int *, int *, int *, zGlobalLU_t *); +extern int scolumn_bmod (const int, const int, float *, + float *, int *, int *, int, sGlobalLU_t *, SuperLUStat_t*); +extern int dcolumn_bmod (const int, const int, double *, + double *, int *, int *, int, dGlobalLU_t *, SuperLUStat_t*); +extern int ccolumn_bmod (const int, const int, lscomplex *, + lscomplex *, int *, int *, int, cGlobalLU_t *, SuperLUStat_t*); +extern int zcolumn_bmod (const int, const int, ldcomplex *, + ldcomplex *, int *, int *, int, zGlobalLU_t *, SuperLUStat_t*); +extern int scopy_to_ucol (int, int, int *, int *, int *, + float *, sGlobalLU_t *); +extern int dcopy_to_ucol (int, int, int *, int *, int *, + double *, dGlobalLU_t *); +extern int ccopy_to_ucol (int, int, int *, int *, int *, + lscomplex *, cGlobalLU_t *); +extern int zcopy_to_ucol (int, int, int *, int *, int *, + ldcomplex *, zGlobalLU_t *); +extern int spivotL (const int, const float, int *, int *, + int *, int *, int *, sGlobalLU_t *, SuperLUStat_t*); +extern int dpivotL (const int, const double, int *, int *, + int *, int *, int *, dGlobalLU_t *, SuperLUStat_t*); +extern int cpivotL (const int, const float, int *, int *, + int *, int *, int *, cGlobalLU_t *, SuperLUStat_t*); +extern int zpivotL (const int, const double, int *, int *, + int *, int *, int *, zGlobalLU_t *, SuperLUStat_t*); +extern void spruneL (const int, const int *, const int, const int, + const int *, const int *, int *, sGlobalLU_t *); +extern void dpruneL (const int, const int *, const int, const int, + const int *, const int *, int *, dGlobalLU_t *); +extern void cpruneL (const int, const int *, const int, const int, + const int *, const int *, int *, cGlobalLU_t *); +extern void zpruneL (const int, const int *, const int, const int, + const int *, const int *, int *, zGlobalLU_t *); +extern void sreadmt (int *, int *, int *, float **, int **, int **); +extern void dreadmt (int *, int *, int *, double **, int **, int **); +extern void creadmt (int *, int *, int *, lscomplex **, int **, int **); +extern void zreadmt (int *, int *, int *, ldcomplex **, int **, int **); +extern void sGenXtrue (int, int, float *, int); +extern void dGenXtrue (int, int, double *, int); +extern void cGenXtrue (int, int, lscomplex *, int); +extern void zGenXtrue (int, int, ldcomplex *, int); +extern void sFillRHS (trans_t, int, float *, int, SuperMatrix *, + SuperMatrix *); +extern void dFillRHS (trans_t, int, double *, int, SuperMatrix *, + SuperMatrix *); +extern void cFillRHS (trans_t, int, lscomplex *, int, SuperMatrix *, + SuperMatrix *); +extern void zFillRHS (trans_t, int, ldcomplex *, int, SuperMatrix *, + SuperMatrix *); +extern void sgstrs (trans_t, SuperMatrix *, SuperMatrix *, int *, int *, + SuperMatrix *, SuperLUStat_t*, int *); +extern void dgstrs (trans_t, SuperMatrix *, SuperMatrix *, int *, int *, + SuperMatrix *, SuperLUStat_t*, int *); +extern void cgstrs (trans_t, SuperMatrix *, SuperMatrix *, int *, int *, + SuperMatrix *, SuperLUStat_t*, int *); +extern void zgstrs (trans_t, SuperMatrix *, SuperMatrix *, int *, int *, + SuperMatrix *, SuperLUStat_t*, int *); + + +/* Driver related */ + +extern void sgsequ (SuperMatrix *, float *, float *, float *, + float *, float *, int *); +extern void dgsequ (SuperMatrix *, double *, double *, double *, + double *, double *, int *); +extern void cgsequ (SuperMatrix *, float *, float *, float *, + float *, float *, int *); +extern void zgsequ (SuperMatrix *, double *, double *, double *, + double *, double *, int *); +extern void slaqgs (SuperMatrix *, float *, float *, float, + float, float, char *); +extern void dlaqgs (SuperMatrix *, double *, double *, double, + double, double, char *); +extern void claqgs (SuperMatrix *, float *, float *, float, + float, float, char *); +extern void zlaqgs (SuperMatrix *, double *, double *, double, + double, double, char *); +extern void sgscon (char *, SuperMatrix *, SuperMatrix *, + float, float *, SuperLUStat_t*, int *); +extern void dgscon (char *, SuperMatrix *, SuperMatrix *, + double, double *, SuperLUStat_t*, int *); +extern void cgscon (char *, SuperMatrix *, SuperMatrix *, + float, float *, SuperLUStat_t*, int *); +extern void zgscon (char *, SuperMatrix *, SuperMatrix *, + double, double *, SuperLUStat_t*, int *); + +extern float sPivotGrowth(int, SuperMatrix *, int *, + SuperMatrix *, SuperMatrix *); +extern double dPivotGrowth(int, SuperMatrix *, int *, + SuperMatrix *, SuperMatrix *); +extern float cPivotGrowth(int, SuperMatrix *, int *, + SuperMatrix *, SuperMatrix *); +extern double zPivotGrowth(int, SuperMatrix *, int *, + SuperMatrix *, SuperMatrix *); +extern void sgsrfs (trans_t, SuperMatrix *, SuperMatrix *, + SuperMatrix *, int *, int *, char *, float *, + float *, SuperMatrix *, SuperMatrix *, + float *, float *, SuperLUStat_t*, int *); +extern void dgsrfs (trans_t, SuperMatrix *, SuperMatrix *, + SuperMatrix *, int *, int *, char *, double *, + double *, SuperMatrix *, SuperMatrix *, + double *, double *, SuperLUStat_t*, int *); +extern void cgsrfs (trans_t, SuperMatrix *, SuperMatrix *, + SuperMatrix *, int *, int *, char *, float *, + float *, SuperMatrix *, SuperMatrix *, + float *, float *, SuperLUStat_t*, int *); +extern void zgsrfs (trans_t, SuperMatrix *, SuperMatrix *, + SuperMatrix *, int *, int *, char *, double *, + double *, SuperMatrix *, SuperMatrix *, + double *, double *, SuperLUStat_t*, int *); + +extern int sp_strsv (char *, char *, char *, SuperMatrix *, + SuperMatrix *, float *, SuperLUStat_t*, int *); +extern int sp_dtrsv (char *, char *, char *, SuperMatrix *, + SuperMatrix *, double *, SuperLUStat_t*, int *); +extern int sp_ctrsv (char *, char *, char *, SuperMatrix *, + SuperMatrix *, lscomplex *, SuperLUStat_t*, int *); +extern int sp_ztrsv (char *, char *, char *, SuperMatrix *, + SuperMatrix *, ldcomplex *, SuperLUStat_t*, int *); +extern int sp_sgemv (char *, float, SuperMatrix *, float *, + int, float, float *, int); +extern int sp_dgemv (char *, double, SuperMatrix *, double *, + int, double, double *, int); +extern int sp_cgemv (char *, lscomplex, SuperMatrix *, lscomplex *, + int, lscomplex, lscomplex *, int); +extern int sp_zgemv (char *, ldcomplex, SuperMatrix *, ldcomplex *, + int, ldcomplex, ldcomplex *, int); + +extern int sp_sgemm (char *, char *, int, int, int, float, + SuperMatrix *, float *, int, float, + float *, int); +extern int sp_dgemm (char *, char *, int, int, int, double, + SuperMatrix *, double *, int, double, + double *, int); +extern int sp_cgemm (char *, char *, int, int, int, lscomplex, + SuperMatrix *, lscomplex *, int, lscomplex, + lscomplex *, int); +extern int sp_zgemm (char *, char *, int, int, int, ldcomplex, + SuperMatrix *, ldcomplex *, int, ldcomplex, + ldcomplex *, int); + +/* Memory-related */ +extern int sLUMemInit (fact_t, void *, int, int, int, int, int, + float, SuperMatrix *, SuperMatrix *, + sGlobalLU_t *, int **, float **); +extern int dLUMemInit (fact_t, void *, int, int, int, int, int, + double, SuperMatrix *, SuperMatrix *, + dGlobalLU_t *, int **, double **); +extern int cLUMemInit (fact_t, void *, int, int, int, int, int, + float, SuperMatrix *, SuperMatrix *, + cGlobalLU_t *, int **, lscomplex **); +extern int zLUMemInit (fact_t, void *, int, int, int, int, int, + double, SuperMatrix *, SuperMatrix *, + zGlobalLU_t *, int **, ldcomplex **); +extern void sSetRWork (int, int, float *, float **, float **); +extern void dSetRWork (int, int, double *, double **, double **); +extern void cSetRWork (int, int, lscomplex *, lscomplex **, lscomplex **); +extern void zSetRWork (int, int, ldcomplex *, ldcomplex **, ldcomplex **); +extern void sLUWorkFree (int *, float *, sGlobalLU_t *); +extern void dLUWorkFree (int *, double *, dGlobalLU_t *); +extern void cLUWorkFree (int *, lscomplex *, cGlobalLU_t *); +extern void zLUWorkFree (int *, ldcomplex *, zGlobalLU_t *); +extern int sLUMemXpand (int, int, MemType, int *, sGlobalLU_t *); +extern int dLUMemXpand (int, int, MemType, int *, dGlobalLU_t *); +extern int cLUMemXpand (int, int, MemType, int *, cGlobalLU_t *); +extern int zLUMemXpand (int, int, MemType, int *, zGlobalLU_t *); + +extern float *floatMalloc(int); +extern double *doubleMalloc(int); +extern lscomplex *complexMalloc(int); +extern ldcomplex *doublecomplexMalloc(int); +extern float *floatCalloc(int); +extern double *doubleCalloc(int); +extern lscomplex *complexCalloc(int); +extern ldcomplex *doublecomplexCalloc(int); +extern int smemory_usage(const int, const int, const int, const int); +extern int dmemory_usage(const int, const int, const int, const int); +extern int cmemory_usage(const int, const int, const int, const int); +extern int zmemory_usage(const int, const int, const int, const int); +extern int sQuerySpace (SuperMatrix *, SuperMatrix *, mem_usage_t *); +extern int dQuerySpace (SuperMatrix *, SuperMatrix *, mem_usage_t *); +extern int cQuerySpace (SuperMatrix *, SuperMatrix *, mem_usage_t *); +extern int zQuerySpace (SuperMatrix *, SuperMatrix *, mem_usage_t *); + +/* Auxiliary routines */ +extern void sreadhb(FILE *, int *, int *, int *, float **, int **, int **); +extern void dreadhb(FILE *, int *, int *, int *, double **, int **, int **); +extern void creadhb(FILE *, int *, int *, int *, lscomplex **, int **, int **); +extern void zreadhb(FILE *, int *, int *, int *, ldcomplex **, int **, int **); +extern void sCompRow_to_CompCol(int, int, int, float*, int*, int*, + float **, int **, int **); +extern void dCompRow_to_CompCol(int, int, int, double*, int*, int*, + double **, int **, int **); +extern void cCompRow_to_CompCol(int, int, int, lscomplex*, int*, int*, + lscomplex **, int **, int **); +extern void zCompRow_to_CompCol(int, int, int, ldcomplex*, int*, int*, + ldcomplex **, int **, int **); +extern void sfill (float *, int, float); +extern void dfill (double *, int, double); +extern void cfill (lscomplex *, int, lscomplex); +extern void zfill (ldcomplex *, int, ldcomplex); +extern void sinf_norm_error (int, SuperMatrix *, float *); +extern void dinf_norm_error (int, SuperMatrix *, double *); +extern void cinf_norm_error (int, SuperMatrix *, lscomplex *); +extern void zinf_norm_error (int, SuperMatrix *, ldcomplex *); +// extern void PrintPerf (SuperMatrix *, SuperMatrix *, mem_usage_t *, +// float, float, float *, float *, char *); + +/* Routines for debugging */ +extern void sPrint_CompCol_Matrix(char *, SuperMatrix *); +extern void dPrint_CompCol_Matrix(char *, SuperMatrix *); +extern void cPrint_CompCol_Matrix(char *, SuperMatrix *); +extern void zPrint_CompCol_Matrix(char *, SuperMatrix *); +extern void sPrint_SuperNode_Matrix(char *, SuperMatrix *); +extern void dPrint_SuperNode_Matrix(char *, SuperMatrix *); +extern void cPrint_SuperNode_Matrix(char *, SuperMatrix *); +extern void zPrint_SuperNode_Matrix(char *, SuperMatrix *); +extern void sPrint_Dense_Matrix(char *, SuperMatrix *); +extern void dPrint_Dense_Matrix(char *, SuperMatrix *); +extern void cPrint_Dense_Matrix(char *, SuperMatrix *); +extern void zPrint_Dense_Matrix(char *, SuperMatrix *); +// extern void print_lu_col(char *, int, int, int *, sGlobalLU_t *); +// extern void check_tempv(int, float *); + +/* Reordering routine */ + + +#ifdef __cplusplus + } +#endif + +#endif /* __SUPERLU_SP_DEFS */ + diff --git a/external/arpack++/include/arlspen.h b/external/arpack++/include/arlspen.h new file mode 100644 index 000000000..52e2bb1a1 --- /dev/null +++ b/external/arpack++/include/arlspen.h @@ -0,0 +1,679 @@ +/* + ARPACK++ v1.2 2/20/2000 + c++ interface to ARPACK code. + + MODULE ARLSPen.h. + Arpack++ class ARluSymPencil definition. + + ARPACK Authors + Richard Lehoucq + Danny Sorensen + Chao Yang + Dept. of Computational & Applied Mathematics + Rice University + Houston, Texas +*/ + +#ifndef ARLSPEN_H +#define ARLSPEN_H + +#include + +#include "arch.h" +#include "arerror.h" +#include "blas1c.h" +#include "superluc.h" +#include "arlspdef.h" +#include "arlutil.h" +#include "arlsmat.h" + + +template +class ARluSymPencil +{ + + protected: + + bool factored; + int* permc; + int* permr; + char part; + char uplo; + ARluSymMatrix* A; + ARluSymMatrix* B; + SuperMatrix L; + SuperMatrix U; + SuperLUStat_t stat; + + virtual void Copy(const ARluSymPencil& other); + + void ClearMem(); + + void SparseSaxpy(ARTYPE a, ARTYPE x[], int xind[], int nx, ARTYPE y[], + int yind[], int ny, ARTYPE z[], int zind[], int& nz); + + void ExpandAsB(int n, NCformat& AsB); + + void SubtractAsB(int n, ARTYPE sigma, NCformat& A, + NCformat& B, NCformat& AsB); + + public: + + bool IsFactored() { return factored; } + + void FactorAsB(ARTYPE sigma); + + void MultAv(ARTYPE* v, ARTYPE* w) { A->MultMv(v,w); } + + void MultBv(ARTYPE* v, ARTYPE* w) { B->MultMv(v,w); } + + void MultInvBAv(ARTYPE* v, ARTYPE* w); + + void MultInvAsBv(ARTYPE* v, ARTYPE* w); + + void DefineMatrices(ARluSymMatrix& Ap, ARluSymMatrix& Bp); + + ARluSymPencil(); + // Short constructor that does nothing. + + ARluSymPencil(ARluSymMatrix& Ap, ARluSymMatrix& Bp); + // Long constructor. + + ARluSymPencil(const ARluSymPencil& other) { Copy(other); } + // Copy constructor. + + virtual ~ARluSymPencil() { ClearMem(); } + // Destructor. + + ARluSymPencil& operator=(const ARluSymPencil& other); + // Assignment operator. + +}; + +// ------------------------------------------------------------------------ // +// ARluSymPencil member functions definition. // +// ------------------------------------------------------------------------ // + + +template +inline void ARluSymPencil:: +Copy(const ARluSymPencil& other) +{ + + factored = other.factored; + part = other.part; + uplo = other.uplo; + A = other.A; + B = other.B; + + // Throwing the original factorization away (this procedure + // is really awkward, but it is necessary because there + // is no copy function for matrices L and U in the SuperLU + // library and it is not a good idea to do this kind of deep + // copy here). + + if (factored) { + ArpackError(ArpackError::DISCARDING_FACTORS, "ARluSymPencil"); + factored = false; + } + +} // Copy. + + +template +void ARluSymPencil::ClearMem() +{ + + if (factored) { + Destroy_SuperNode_Matrix(&L); + Destroy_CompCol_Matrix(&U); + StatFree(&stat); + delete[] permc; + delete[] permr; + permc = NULL; + permr = NULL; + } + +} // ClearMem. + + +template +void ARluSymPencil:: +SparseSaxpy(ARTYPE a, ARTYPE x[], int xind[], int nx, ARTYPE y[], + int yind[], int ny, ARTYPE z[], int zind[], int& nz) +// A strongly sequential (and inefficient) sparse saxpy algorithm. +{ + + int ix, iy; + + nz = 0; + if ((nx == 0) || (a == (ARTYPE)0)) { + copy(ny,y,1,z,1); + for (iy=0; iy!=ny; iy++) zind[iy] = yind[iy]; + nz = ny; + return; + } + if (ny == 0) { + copy(nx,x,1,z,1); + scal(nx,a,z,1); + for (ix=0; ix!=nx; ix++) zind[ix] = xind[ix]; + nz = nx; + return; + } + ix = 0; + iy = 0; + while (true) { + if (xind[ix] == yind[iy]) { + zind[nz] = xind[ix]; + z[nz++] = a*x[ix++]+y[iy++]; + if ((ix == nx)||(iy == ny)) break; + } + else if (xind[ix] < yind[iy]) { + zind[nz] = xind[ix]; + z[nz++] = a*x[ix++]; + if (ix == nx) break; + } + else { + zind[nz] = yind[iy]; + z[nz++] = y[iy++]; + if (iy == ny) break; + } + } + while (iy < ny) { + zind[nz] = yind[iy]; + z[nz++] = y[iy++]; + } + while (ix < nx) { + zind[nz] = xind[ix]; + z[nz++] = x[ix++]; + } + +} // SparseSaxpy. + + +template +void ARluSymPencil::ExpandAsB(int n, NCformat& AsB) +{ + + int i, j, k; + int *pcol, *pos, *col, *ind; + ARTYPE *val; + + // simplifying the notation. + + val = (ARTYPE*)AsB.nzval; + ind = AsB.rowind; + col = AsB.colptr; + + // Initializing vectors. + + pcol = new int[n+1]; + pos = new int[n+1]; + for (i=0; i<=n; i++) pcol[i] = col[i]; + for (i=0; i<=n; i++) pos[i] = 0; + + // Counting the elements in each column of AsB. + + if (uplo == 'U') { + + for (i=0; i!=n; i++) { + k = pcol[i+1]; + if ((k!=pcol[i])&&(ind[k-1]==i)) k--; + for (j=pcol[i]; j0; i--) col[i] += pos[i-1]; + + // Expanding A. + + if (uplo == 'U') { + + for (i=n-1; i>=0; i--) { + pos[i] = col[i]+pcol[i+1]-pcol[i]; + k = pos[i]-1; + for (j=pcol[i+1]-1; j>=pcol[i]; j--) { + val[k] = val[j]; + ind[k--] = ind[j]; + } + } + for (i=1; icol[i])&&(ind[k-1]==i)) k--; + for (j=col[i]; j=0; i--) { + k = col[i+1]-1; + for (j=pcol[i+1]-1; j>=pcol[i]; j--) { + val[k] = val[j]; + ind[k--] = ind[j]; + } + pos[i] = col[i]; + } + for (i=0; i<(n-1); i++) { + k = col[i+1]-pcol[i+1]+pcol[i]; + if ((k +void ARluSymPencil:: +SubtractAsB(int n, ARTYPE sigma, NCformat& matA, NCformat& matB, NCformat& AsB) +{ + + int i, acol, bcol, asbcol, scol; + ARTYPE* anzval; + ARTYPE* bnzval; + ARTYPE* asbnzval; + + // Quitting function if A->uplo is not equal to B->uplo. + + if ((A->uplo != B->uplo)&&(sigma != (ARTYPE)0)) { + throw ArpackError(ArpackError::DIFFERENT_TRIANGLES, + "ARluSymPencil::SubtractAsB"); + } + uplo = A->uplo; + + // Telling the compiler that nzval must ve viewed as a vector of ARTYPE. + + anzval = (ARTYPE*)matA.nzval; + bnzval = (ARTYPE*)matB.nzval; + asbnzval = (ARTYPE*)AsB.nzval; + + // Subtracting sigma*B from A. + + AsB.colptr[0] = 0; + asbcol = 0; + + for (i=0; i!=n; i++) { + bcol = matB.colptr[i]; + acol = matA.colptr[i]; + SparseSaxpy(-sigma, &bnzval[bcol], &matB.rowind[bcol], + matB.colptr[i+1]-bcol, &anzval[acol], &matA.rowind[acol], + matA.colptr[i+1]-acol, &asbnzval[asbcol], + &AsB.rowind[asbcol], scol); + asbcol += scol; + AsB.colptr[i+1] = asbcol; + } + + // Expanding AsB. + + ExpandAsB(n, AsB); + +} // SubtractAsB. + + +// template +// void ARluSymPencil::FactorAsB(ARTYPE sigma) +// { +// +// // Quitting the function if A and B were not defined. +// +// if (!(A->IsDefined()&&B->IsDefined())) { +// throw ArpackError(ArpackError::DATA_UNDEFINED, +// "ARluSymPencil::FactorAsB"); +// } +// +// // Quitting the function if A and B are not square. +// +// if ((A->nrows() != A->ncols()) || (B->nrows() != B->ncols())) { +// throw ArpackError(ArpackError::NOT_SQUARE_MATRIX, +// "ARluSymPencil::FactorAsB"); +// } +// +// // Defining local variables. +// +// int nnzi, info; +// int* etree; +// int* irowi; +// int* pcoli; +// ARTYPE* asb; +// SuperMatrix AsB; +// SuperMatrix AC; +// NCformat* Astore; +// NCformat* Bstore; +// NCformat* AsBstore; +// +// // Deleting old versions of L, U, perm_r and perm_c. +// +// ClearMem(); +// +// // Setting default values for gstrf parameters. +// +// ARTYPE drop_tol = (ARTYPE)0; +// int panel_size = sp_ienv(1); +// int relax = sp_ienv(2); +// +// // Defining A and B format. +// +// Astore = (NCformat*)A->A.Store; +// Bstore = (NCformat*)B->A.Store; +// +// // Creating a temporary matrix AsB. +// +// nnzi = (Astore->nnz+Bstore->nnz)*2; +// irowi = new int[nnzi]; +// pcoli = new int[A->ncols()+1]; +// asb = new ARTYPE[nnzi]; +// Create_CompCol_Matrix(&AsB, A->nrows(), A->ncols(), nnzi, asb, +// irowi, pcoli, NC, GE); +// +// // Subtracting sigma*B from A and storing the result on AsB. +// +// AsBstore = (NCformat*)AsB.Store; +// SubtractAsB(A->ncols(), sigma, *Astore, *Bstore, *AsBstore); +// +// // Reserving memory for some vectors used in matrix decomposition. +// +// etree = new int[A->ncols()]; +// if (permc == NULL) permc = new int[A->ncols()]; +// if (permr == NULL) permr = new int[A->ncols()]; +// +// // Defining LUStat. +// +// StatInit(panel_size, relax); +// +// // Defining the column permutation of matrix AsB +// // (using minimum degree ordering on AsB'*AsB). +// +// get_perm_c(A->order, &AsB, permc); +// +// // Permuting columns of AsB and +// // creating the elimination tree of AsB'*AsB. +// +// sp_preorder("N", &AsB, permc, etree, &AC); +// +// // Decomposing AsB. +// +// gstrf("N",&AC, A->threshold, drop_tol, relax, panel_size, etree, +// NULL, 0, permr, permc, &L, &U, &info); +// +// // Deleting AC, AsB and etree. +// +// Destroy_CompCol_Permuted(&AC); +// Destroy_CompCol_Matrix(&AsB); +// delete[] etree; +// +// factored = (info == 0); +// +// // Handling errors. +// +// if (info < 0) { // Illegal argument. +// throw ArpackError(ArpackError::PARAMETER_ERROR, +// "ARluSymPencil::FactorAsB"); +// } +// else if (info > A->ncols()) { // Memory is not sufficient. +// throw ArpackError(ArpackError::MEMORY_OVERFLOW, +// "ARluSymPencil::FactorAsB"); +// } +// else if (info > 0) { // Matrix is singular. +// throw ArpackError(ArpackError::MATRIX_IS_SINGULAR, +// "ARluSymPencil::FactorAsB"); +// } +// +// } // FactorAsB. + +template +void ARluSymPencil::FactorAsB(ARTYPE sigma) +{ + + // Quitting the function if A and B were not defined. + + if (!(A->IsDefined()&&B->IsDefined())) { + throw ArpackError(ArpackError::DATA_UNDEFINED, + "ARluSymPencil::FactorAsB"); + } + + // Quitting the function if A and B are not square. + + if ((A->nrows() != A->ncols()) || (B->nrows() != B->ncols())) { + throw ArpackError(ArpackError::NOT_SQUARE_MATRIX, + "ARluSymPencil::FactorAsB"); + } + + // Defining local variables. + + int nnzi, info; + int* etree; + int* irowi; + int* pcoli; + ARTYPE* asb; + SuperMatrix AsB; + SuperMatrix AC; + NCformat* Astore; + NCformat* Bstore; + NCformat* AsBstore; + + // Deleting old versions of L, U, perm_r and perm_c. + + ClearMem(); + + // Setting default values for gstrf parameters. + + int panel_size = sp_ienv(1); + int relax = sp_ienv(2); + superlu_options_t options; + /* Set the default input options: + options.Fact = DOFACT; + options.Equil = YES; + options.ColPerm = COLAMD; + options.DiagPivotThresh = 1.0; + options.Trans = NOTRANS; + options.IterRefine = NOREFINE; + options.SymmetricMode = NO; + options.PivotGrowth = NO; + options.ConditionNumber = NO; + options.PrintStat = YES; + */ + set_default_options(&options); + + /* Now we modify the default options to use the symmetric mode. */ + options.SymmetricMode = YES; + options.ColPerm = MMD_AT_PLUS_A; + options.DiagPivotThresh = A->threshold; + + // Defining A and B format. + + Astore = (NCformat*)A->A.Store; + Bstore = (NCformat*)B->A.Store; + + // Creating a temporary matrix AsB. + + nnzi = (Astore->nnz+Bstore->nnz)*2; + irowi = new int[nnzi]; + pcoli = new int[A->ncols()+1]; + asb = new ARTYPE[nnzi]; + Create_CompCol_Matrix(&AsB, A->nrows(), A->ncols(), nnzi, asb, + irowi, pcoli, SLU_NC, SLU_GE); + + // Subtracting sigma*B from A and storing the result on AsB. + + AsBstore = (NCformat*)AsB.Store; + SubtractAsB(A->ncols(), sigma, *Astore, *Bstore, *AsBstore); + + // Reserving memory for some vectors used in matrix decomposition. + + etree = new int[A->ncols()]; + if (permc == NULL) permc = new int[A->ncols()]; + if (permr == NULL) permr = new int[A->ncols()]; + + // Defining LUStat. + +// StatInit(panel_size, relax); + SuperLUStat_t stat; + StatInit(&stat); + + // Defining the column permutation of matrix AsB + // (using minimum degree ordering on AsB'*AsB). + + get_perm_c(A->order, &AsB, permc); + + // Permuting columns of AsB and + // creating the elimination tree of AsB'*AsB. + + sp_preorder(&options, &AsB, permc, etree, &AC); + + // Decomposing AsB. + +// gstrf("N",&AC, A->threshold, drop_tol, relax, panel_size, etree, +// NULL, 0, permr, permc, &L, &U, &info); + gstrf(&options, &AC, relax, panel_size, etree, + NULL, 0, permc, permr, &L, &U, &stat, &info); + + // Deleting AC, AsB and etree. + + Destroy_CompCol_Permuted(&AC); + Destroy_CompCol_Matrix(&AsB); + delete[] etree; + + factored = (info == 0); + + // Handling errors. + + if (info < 0) { // Illegal argument. + throw ArpackError(ArpackError::PARAMETER_ERROR, + "ARluSymPencil::FactorAsB"); + } + else if (info > A->ncols()) { // Memory is not sufficient. + throw ArpackError(ArpackError::MEMORY_OVERFLOW, + "ARluSymPencil::FactorAsB"); + } + else if (info > 0) { // Matrix is singular. + throw ArpackError(ArpackError::MATRIX_IS_SINGULAR, + "ARluSymPencil::FactorAsB"); + } + +} // FactorAsB. + +template +void ARluSymPencil::MultInvBAv(ARTYPE* v, ARTYPE* w) +{ + if (!B->IsFactored()) B->FactorA(); + + A->MultMv(v, w); + copy(A->ncols(), w, 1, v, 1); + B->MultInvv(w, w); + +} // MultInvBAv. + + +template +void ARluSymPencil::MultInvAsBv(ARTYPE* v, ARTYPE* w) +{ + + // Quitting the function if AsB was not factored. + + if (!IsFactored()) { + throw ArpackError(ArpackError::NOT_FACTORED_MATRIX, + "ARluSymPencil::MultInvAsBv"); + } + + // Solving AsB.w = v. + + int info; + SuperMatrix RHS; + + copy(A->nrows(), v, 1, w, 1); + Create_Dense_Matrix(&RHS, A->nrows(), 1, w, A->nrows(), SLU_DN, SLU_GE); +// gstrs("N", &L, &U, permr, permc, &RHS, &info); + trans_t trans = NOTRANS; + StatInit(&stat); + + gstrs(trans, &L, &U, permc, permr, &RHS, &stat, &info); + + Destroy_SuperMatrix_Store(&RHS); // delete RHS.Store; + +} // MultInvAsBv. + + +template +inline void ARluSymPencil:: +DefineMatrices(ARluSymMatrix& Ap, ARluSymMatrix& Bp) +{ + + A = &Ap; + B = &Bp; + permc = NULL; + permr = NULL; + + if ((A->n != B->n)||(A->m != B->m)) { + throw ArpackError(ArpackError::INCOMPATIBLE_SIZES, + "ARluSymMatrix::DefineMatrices"); + } + +} // DefineMatrices. + + +template +inline ARluSymPencil::ARluSymPencil() +{ + + factored = false; + part = 'N'; + permr = NULL; + permc = NULL; + +} // Short constructor. + + +template +inline ARluSymPencil:: +ARluSymPencil(ARluSymMatrix& Ap, ARluSymMatrix& Bp) +{ + + factored = false; + DefineMatrices(Ap, Bp); + +} // Long constructor. + + +template +ARluSymPencil& ARluSymPencil:: +operator=(const ARluSymPencil& other) +{ + + if (this != &other) { // Stroustrup suggestion. + ClearMem(); + Copy(other); + } + return *this; + +} // operator=. + + +#endif // ARLSPEN_H diff --git a/external/arpack++/include/arlssym.h b/external/arpack++/include/arlssym.h new file mode 100644 index 000000000..fdab7e6b3 --- /dev/null +++ b/external/arpack++/include/arlssym.h @@ -0,0 +1,179 @@ +/* + ARPACK++ v1.2 2/20/2000 + c++ interface to ARPACK code. + + MODULE ARLSSym.h. + Arpack++ class ARluSymStdEig definition + (SuperLU version). + + ARPACK Authors + Richard Lehoucq + Danny Sorensen + Chao Yang + Kristi Maschhoff + Dept. of Computational & Applied Mathematics + Rice University + Houston, Texas +*/ + +#ifndef ARLSSYM_H +#define ARLSSYM_H + +#include +#include +#include "arch.h" +#include "arssym.h" +#include "arlsmat.h" + + +template +class ARluSymStdEig: + public virtual ARSymStdEig > { + + protected: + + // a) Protected function: + + virtual void Copy(const ARluSymStdEig& other); + // Makes a deep copy of "other" over "this" object. + // Old values are not deleted (this function is to be used + // by the copy constructor and the assignment operator only). + + + public: + + // b) Public functions: + + // b.1) Functions that allow changes in problem parameters. + + virtual void ChangeShift(ARFLOAT sigmaRp); + + virtual void SetRegularMode(); + + virtual void SetShiftInvertMode(ARFLOAT sigmap); + + // b.2) Constructors and destructor. + + ARluSymStdEig() { } + // Short constructor. + + ARluSymStdEig(int nevp, ARluSymMatrix& A, + const std::string& whichp = "LM", int ncvp = 0, + ARFLOAT tolp = 0.0, int maxitp = 0, + ARFLOAT* residp = NULL, bool ishiftp = true); + // Long constructor (regular mode). + + ARluSymStdEig(int nevp, ARluSymMatrix& A, + ARFLOAT sigma, const std::string& whichp = "LM", int ncvp = 0, + ARFLOAT tolp = 0.0, int maxitp = 0, + ARFLOAT* residp = NULL, bool ishiftp = true); + // Long constructor (shift and invert mode). + + ARluSymStdEig(const ARluSymStdEig& other) { Copy(other); } + // Copy constructor. + + virtual ~ARluSymStdEig() { } + // Destructor. + + // c) Operators. + + ARluSymStdEig& operator=(const ARluSymStdEig& other); + // Assignment operator. + +}; // class ARluSymStdEig. + + +// ------------------------------------------------------------------------ // +// ARluSymStdEig member functions definition. // +// ------------------------------------------------------------------------ // + + +template +inline void ARluSymStdEig::Copy(const ARluSymStdEig& other) +{ + + ARStdEig >:: Copy(other); + if (this->mode > 2) this->objOP->FactorAsI(this->sigmaR); + +} // Copy. + + +template +inline void ARluSymStdEig::ChangeShift(ARFLOAT sigmaRp) +{ + + this->sigmaR = sigmaRp; + this->sigmaI = 0.0; + this->mode = 3; + this->iparam[7] = this->mode; + + this->objOP->FactorAsI(this->sigmaR); + this->Restart(); + +} // ChangeShift. + + +template +inline void ARluSymStdEig::SetRegularMode() +{ + + ARStdEig >:: + SetRegularMode(this->objOP, &ARluSymMatrix::MultMv); + +} // SetRegularMode. + + +template +inline void ARluSymStdEig::SetShiftInvertMode(ARFLOAT sigmap) +{ + + ARStdEig >:: + SetShiftInvertMode(sigmap, this->objOP, &ARluSymMatrix::MultInvv); + +} // SetShiftInvertMode. + + +template +inline ARluSymStdEig:: +ARluSymStdEig(int nevp, ARluSymMatrix& A, + const std::string& whichp, int ncvp, ARFLOAT tolp, + int maxitp, ARFLOAT* residp, bool ishiftp) +{ + + this->NoShift(); + this->DefineParameters(A.ncols(), nevp, &A, &ARluSymMatrix::MultMv, + whichp, ncvp, tolp, maxitp, residp, ishiftp); + +} // Long constructor (regular mode). + + +template +inline ARluSymStdEig:: +ARluSymStdEig(int nevp, ARluSymMatrix& A, + ARFLOAT sigmap, const std::string& whichp, int ncvp, ARFLOAT tolp, + int maxitp, ARFLOAT* residp, bool ishiftp) + +{ + + this->DefineParameters(A.ncols(), nevp, &A, &ARluSymMatrix::MultInvv, + whichp, ncvp, tolp, maxitp, residp, ishiftp); + ChangeShift(sigmap); + +} // Long constructor (shift and invert mode). + + +template +ARluSymStdEig& ARluSymStdEig:: +operator=(const ARluSymStdEig& other) +{ + + if (this != &other) { // Stroustrup suggestion. + this->ClearMem(); + Copy(other); + } + return *this; + +} // operator=. + + +#endif // ARLSSYM_H diff --git a/external/arpack++/include/arlsupm.h b/external/arpack++/include/arlsupm.h new file mode 100644 index 000000000..7c8d2e8a8 --- /dev/null +++ b/external/arpack++/include/arlsupm.h @@ -0,0 +1,185 @@ +/* + ARPACK++ v1.2 2/20/2000 + c++ interface to ARPACK code. + + MODULE ARLSupM.h. + Unaltered copy of supermatrix.h (from SuperLU package). +*/ + +#ifndef __SUPERLU_SUPERMATRIX /* allow multiple inclusions */ +#define __SUPERLU_SUPERMATRIX + + +/******************************************** + * The matrix types are defined as follows. * + ********************************************/ +typedef enum { + SLU_NC, /* column-wise, no supernode */ + SLU_NCP, /* column-wise, column-permuted, no supernode + (The consecutive columns of nonzeros, after permutation, + may not be stored contiguously.) */ + SLU_NR, /* row-wize, no supernode */ + SLU_SC, /* column-wise, supernode */ + SLU_SCP, /* supernode, column-wise, permuted */ + SLU_SR, /* row-wise, supernode */ + SLU_DN, /* Fortran style column-wise storage for dense matrix */ + SLU_NR_loc /* distributed compressed row format */ +} Stype_t; + +typedef enum { + SLU_S, /* single */ + SLU_D, /* double */ + SLU_C, /* single complex */ + SLU_Z /* double complex */ +} Dtype_t; + +typedef enum { + SLU_GE, /* general */ + SLU_TRLU, /* lower triangular, unit diagonal */ + SLU_TRUU, /* upper triangular, unit diagonal */ + SLU_TRL, /* lower triangular */ + SLU_TRU, /* upper triangular */ + SLU_SYL, /* symmetric, store lower half */ + SLU_SYU, /* symmetric, store upper half */ + SLU_HEL, /* Hermitian, store lower half */ + SLU_HEU /* Hermitian, store upper half */ +} Mtype_t; + +typedef struct { + Stype_t Stype; /* Storage type: interprets the storage structure + pointed to by *Store. */ + Dtype_t Dtype; /* Data type. */ + Mtype_t Mtype; /* Matrix type: describes the mathematical property of + the matrix. */ + int nrow; /* number of rows */ + int ncol; /* number of columns */ + void *Store; /* pointer to the actual storage of the matrix */ +} SuperMatrix; + +/*********************************************** + * The storage schemes are defined as follows. * + ***********************************************/ + +/* Stype == SLU_NC (Also known as Harwell-Boeing sparse matrix format) */ +typedef struct { + int nnz; /* number of nonzeros in the matrix */ + void *nzval; /* pointer to array of nonzero values, packed by column */ + int *rowind; /* pointer to array of row indices of the nonzeros */ + int *colptr; /* pointer to array of beginning of columns in nzval[] + and rowind[] */ + /* Note: + Zero-based indexing is used; + colptr[] has ncol+1 entries, the last one pointing + beyond the last column, so that colptr[ncol] = nnz. */ +} NCformat; + +/* Stype == SLU_NR */ +typedef struct { + int nnz; /* number of nonzeros in the matrix */ + void *nzval; /* pointer to array of nonzero values, packed by raw */ + int *colind; /* pointer to array of columns indices of the nonzeros */ + int *rowptr; /* pointer to array of beginning of rows in nzval[] + and colind[] */ + /* Note: + Zero-based indexing is used; + rowptr[] has nrow+1 entries, the last one pointing + beyond the last row, so that rowptr[nrow] = nnz. */ +} NRformat; + +/* Stype == SLU_SC */ +typedef struct { + int nnz; /* number of nonzeros in the matrix */ + int nsuper; /* number of supernodes, minus 1 */ + void *nzval; /* pointer to array of nonzero values, packed by column */ + int *nzval_colptr;/* pointer to array of beginning of columns in nzval[] */ + int *rowind; /* pointer to array of compressed row indices of + rectangular supernodes */ + int *rowind_colptr;/* pointer to array of beginning of columns in rowind[] */ + int *col_to_sup; /* col_to_sup[j] is the supernode number to which column + j belongs; mapping from column to supernode number. */ + int *sup_to_col; /* sup_to_col[s] points to the start of the s-th + supernode; mapping from supernode number to column. + e.g.: col_to_sup: 0 1 2 2 3 3 3 4 4 4 4 4 4 (ncol=12) + sup_to_col: 0 1 2 4 7 12 (nsuper=4) */ + /* Note: + Zero-based indexing is used; + nzval_colptr[], rowind_colptr[], col_to_sup and + sup_to_col[] have ncol+1 entries, the last one + pointing beyond the last column. + For col_to_sup[], only the first ncol entries are + defined. For sup_to_col[], only the first nsuper+2 + entries are defined. */ +} SCformat; + +/* Stype == SLU_SCP */ +typedef struct { + int nnz; /* number of nonzeros in the matrix */ + int nsuper; /* number of supernodes */ + void *nzval; /* pointer to array of nonzero values, packed by column */ + int *nzval_colbeg;/* nzval_colbeg[j] points to beginning of column j + in nzval[] */ + int *nzval_colend;/* nzval_colend[j] points to one past the last element + of column j in nzval[] */ + int *rowind; /* pointer to array of compressed row indices of + rectangular supernodes */ + int *rowind_colbeg;/* rowind_colbeg[j] points to beginning of column j + in rowind[] */ + int *rowind_colend;/* rowind_colend[j] points to one past the last element + of column j in rowind[] */ + int *col_to_sup; /* col_to_sup[j] is the supernode number to which column + j belongs; mapping from column to supernode. */ + int *sup_to_colbeg; /* sup_to_colbeg[s] points to the start of the s-th + supernode; mapping from supernode to column.*/ + int *sup_to_colend; /* sup_to_colend[s] points to one past the end of the + s-th supernode; mapping from supernode number to + column. + e.g.: col_to_sup: 0 1 2 2 3 3 3 4 4 4 4 4 4 (ncol=12) + sup_to_colbeg: 0 1 2 4 7 (nsuper=4) + sup_to_colend: 1 2 4 7 12 */ + /* Note: + Zero-based indexing is used; + nzval_colptr[], rowind_colptr[], col_to_sup and + sup_to_col[] have ncol+1 entries, the last one + pointing beyond the last column. */ +} SCPformat; + +/* Stype == SLU_NCP */ +typedef struct { + int nnz; /* number of nonzeros in the matrix */ + void *nzval; /* pointer to array of nonzero values, packed by column */ + int *rowind;/* pointer to array of row indices of the nonzeros */ + /* Note: nzval[]/rowind[] always have the same length */ + int *colbeg;/* colbeg[j] points to the beginning of column j in nzval[] + and rowind[] */ + int *colend;/* colend[j] points to one past the last element of column + j in nzval[] and rowind[] */ + /* Note: + Zero-based indexing is used; + The consecutive columns of the nonzeros may not be + contiguous in storage, because the matrix has been + postmultiplied by a column permutation matrix. */ +} NCPformat; + +/* Stype == SLU_DN */ +typedef struct { + int lda; /* leading dimension */ + void *nzval; /* array of size lda*ncol to represent a dense matrix */ +} DNformat; + +/* Stype == SLU_NR_loc (Distributed Compressed Row Format) */ +typedef struct { + int nnz_loc; /* number of nonzeros in the local submatrix */ + int m_loc; /* number of rows local to this processor */ + int fst_row; /* global index of the first row */ + void *nzval; /* pointer to array of nonzero values, packed by row */ + int *rowptr; /* pointer to array of beginning of rows in nzval[] + and colind[] */ + int *colind; /* pointer to array of column indices of the nonzeros */ + /* Note: + Zero-based indexing is used; + rowptr[] has n_loc + 1 entries, the last one pointing + beyond the last row, so that rowptr[n_loc] = nnz_loc.*/ +} NRformat_loc; + + +#endif /* __SUPERLU_SUPERMATRIX */ diff --git a/external/arpack++/include/arlutil.h b/external/arpack++/include/arlutil.h new file mode 100644 index 000000000..664ca61bb --- /dev/null +++ b/external/arpack++/include/arlutil.h @@ -0,0 +1,432 @@ +/* + ARPACK++ v1.2 2/20/2000 + c++ interface to ARPACK code. + + MODULE ARLUtil.h. + Unaltered copy of util.h (from SuperLU package) + and superlu_enum_consts.h +*/ + + + +#ifndef __SUPERLU_ENUM_CONSTS /* allow multiple inclusions */ +#define __SUPERLU_ENUM_CONSTS + +/*********************************************************************** + * Enumerate types + ***********************************************************************/ +typedef enum {NO, YES} yes_no_t; +typedef enum {DOFACT, SamePattern, SamePattern_SameRowPerm, FACTORED} fact_t; +typedef enum {NOROWPERM, LargeDiag, MY_PERMR} rowperm_t; +typedef enum {NATURAL, MMD_ATA, MMD_AT_PLUS_A, COLAMD, + METIS_AT_PLUS_A, PARMETIS, ZOLTAN, MY_PERMC} colperm_t; +typedef enum {NOTRANS, TRANS, CONJ} trans_t; +typedef enum {NOEQUIL, ROW, COL, BOTH} DiagScale_t; +typedef enum {NOREFINE, SLU_SINGLE=1, SLU_DOUBLE, SLU_EXTRA} IterRefine_t; +typedef enum {LUSUP, UCOL, LSUB, USUB, LLVL, ULVL} MemType; +typedef enum {HEAD, TAIL} stack_end_t; +typedef enum {SYSTEM, USER} LU_space_t; +typedef enum {ONE_NORM, TWO_NORM, INF_NORM} norm_t; +typedef enum {SILU, SMILU_1, SMILU_2, SMILU_3} milu_t; +#if 0 +typedef enum {NODROP = 0x0000, + DROP_BASIC = 0x0001, /* ILU(tau) */ + DROP_PROWS = 0x0002, /* ILUTP: keep p maximum rows */ + DROP_COLUMN = 0x0004, /* ILUTP: for j-th column, + p = gamma * nnz(A(:,j)) */ + DROP_AREA = 0x0008, /* ILUTP: for j-th column, use + nnz(F(:,1:j)) / nnz(A(:,1:j)) + to limit memory growth */ + DROP_SECONDARY = 0x000E, /* PROWS | COLUMN | AREA */ + DROP_DYNAMIC = 0x0010, + DROP_INTERP = 0x0100} rule_t; +#endif + + +/* + * The following enumerate type is used by the statistics variable + * to keep track of flop count and time spent at various stages. + * + * Note that not all of the fields are disjoint. + */ +typedef enum { + COLPERM, /* find a column ordering that minimizes fills */ + ROWPERM, /* find a row ordering maximizes diagonal. */ + RELAX, /* find artificial supernodes */ + ETREE, /* compute column etree */ + EQUIL, /* equilibrate the original matrix */ + SYMBFAC, /* symbolic factorization. */ + DIST, /* distribute matrix. */ + FACT, /* perform LU factorization */ + COMM, /* communication for factorization */ + SOL_COMM,/* communication for solve */ + RCOND, /* estimate reciprocal condition number */ + SOLVE, /* forward and back solves */ + REFINE, /* perform iterative refinement */ + TRSV, /* fraction of FACT spent in xTRSV */ + GEMV, /* fraction of FACT spent in xGEMV */ + FERR, /* estimate error bounds after iterative refinement */ + NPHASES /* total number of phases */ +} PhaseType; + + +#endif /* __SUPERLU_ENUM_CONSTS */ + + + +#ifndef __SUPERLU_UTIL /* allow multiple inclusions */ +#define __SUPERLU_UTIL + +#include +#include +#include +/* +#ifndef __STDC__ +#include +#endif +*/ +#include + +/*********************************************************************** + * Macros + ***********************************************************************/ +#define FIRSTCOL_OF_SNODE(i) (xsup[i]) +/* No of marker arrays used in the symbolic factorization, + each of size n */ +#define NO_MARKER 3 +#define NUM_TEMPV(m,w,t,b) ( SUPERLU_MAX(m, (t + b)*w) ) + +#ifndef USER_ABORT +#define USER_ABORT(msg) superlu_abort_and_exit(msg) +#endif + +#define ABORT(err_msg) \ + { char msg[256];\ + sprintf(msg,"%s at line %d in file %s\n",err_msg,__LINE__, __FILE__);\ + USER_ABORT(msg); } + + +#ifndef USER_MALLOC +#if 1 +#define USER_MALLOC(size) superlu_malloc(size) +#else +/* The following may check out some uninitialized data */ +#define USER_MALLOC(size) memset (superlu_malloc(size), '\x0F', size) +#endif +#endif + +#define SUPERLU_MALLOC(size) USER_MALLOC(size) + +#ifndef USER_FREE +#define USER_FREE(addr) superlu_free(addr) +#endif + +#define SUPERLU_FREE(addr) USER_FREE(addr) + +#define CHECK_MALLOC(where) { \ + extern int superlu_malloc_total; \ + printf("%s: malloc_total %d Bytes\n", \ + where, superlu_malloc_total); \ +} + +#define SUPERLU_MAX(x, y) ( (x) > (y) ? (x) : (y) ) +#define SUPERLU_MIN(x, y) ( (x) < (y) ? (x) : (y) ) + +/********************************************************* + * Macros used for easy access of sparse matrix entries. * + *********************************************************/ +#define L_SUB_START(col) ( Lstore->rowind_colptr[col] ) +#define L_SUB(ptr) ( Lstore->rowind[ptr] ) +#define L_NZ_START(col) ( Lstore->nzval_colptr[col] ) +#define L_FST_SUPC(superno) ( Lstore->sup_to_col[superno] ) +#define U_NZ_START(col) ( Ustore->colptr[col] ) +#define U_SUB(ptr) ( Ustore->rowind[ptr] ) + + +/*********************************************************************** + * Constants + ***********************************************************************/ +#define EMPTY (-1) +/*#define NO (-1)*/ +#define FALSE 0 +#define TRUE 1 + +#define NO_MEMTYPE 4 /* 0: lusup; + 1: ucol; + 2: lsub; + 3: usub */ + +#define GluIntArray(n) (5 * (n) + 5) + +/* Dropping rules */ +#define NODROP ( 0x0000 ) +#define DROP_BASIC ( 0x0001 ) /* ILU(tau) */ +#define DROP_PROWS ( 0x0002 ) /* ILUTP: keep p maximum rows */ +#define DROP_COLUMN ( 0x0004 ) /* ILUTP: for j-th column, + p = gamma * nnz(A(:,j)) */ +#define DROP_AREA ( 0x0008 ) /* ILUTP: for j-th column, use + nnz(F(:,1:j)) / nnz(A(:,1:j)) + to limit memory growth */ +#define DROP_SECONDARY ( 0x000E ) /* PROWS | COLUMN | AREA */ +#define DROP_DYNAMIC ( 0x0010 ) /* adaptive tau */ +#define DROP_INTERP ( 0x0100 ) /* use interpolation */ + + +#if 1 +#define MILU_ALPHA (1.0e-2) /* multiple of drop_sum to be added to diagonal */ +#else +#define MILU_ALPHA 1.0 /* multiple of drop_sum to be added to diagonal */ +#endif + + +/*********************************************************************** + * Type definitions + ***********************************************************************/ +typedef float flops_t; +typedef unsigned char Logical; + +/* + *-- This contains the options used to control the solution process. + * + * Fact (fact_t) + * Specifies whether or not the factored form of the matrix + * A is supplied on entry, and if not, how the matrix A should + * be factorizaed. + * = DOFACT: The matrix A will be factorized from scratch, and the + * factors will be stored in L and U. + * = SamePattern: The matrix A will be factorized assuming + * that a factorization of a matrix with the same sparsity + * pattern was performed prior to this one. Therefore, this + * factorization will reuse column permutation vector + * ScalePermstruct->perm_c and the column elimination tree + * LUstruct->etree. + * = SamePattern_SameRowPerm: The matrix A will be factorized + * assuming that a factorization of a matrix with the same + * sparsity pattern and similar numerical values was performed + * prior to this one. Therefore, this factorization will reuse + * both row and column scaling factors R and C, both row and + * column permutation vectors perm_r and perm_c, and the + * data structure set up from the previous symbolic factorization. + * = FACTORED: On entry, L, U, perm_r and perm_c contain the + * factored form of A. If DiagScale is not NOEQUIL, the matrix + * A has been equilibrated with scaling factors R and C. + * + * Equil (yes_no_t) + * Specifies whether to equilibrate the system (scale A's row and + * columns to have unit norm). + * + * ColPerm (colperm_t) + * Specifies what type of column permutation to use to reduce fill. + * = NATURAL: use the natural ordering + * = MMD_ATA: use minimum degree ordering on structure of A'*A + * = MMD_AT_PLUS_A: use minimum degree ordering on structure of A'+A + * = COLAMD: use approximate minimum degree column ordering + * = MY_PERMC: use the ordering specified by the user + * + * Trans (trans_t) + * Specifies the form of the system of equations: + * = NOTRANS: A * X = B (No transpose) + * = TRANS: A**T * X = B (Transpose) + * = CONJ: A**H * X = B (Transpose) + * + * IterRefine (IterRefine_t) + * Specifies whether to perform iterative refinement. + * = NO: no iterative refinement + * = SLU_SINGLE: perform iterative refinement in single precision + * = SLU_DOUBLE: perform iterative refinement in double precision + * = SLU_EXTRA: perform iterative refinement in extra precision + * + * DiagPivotThresh (double, in [0.0, 1.0]) (only for sequential SuperLU) + * Specifies the threshold used for a diagonal entry to be an + * acceptable pivot. + * + * SymmetricMode (yest_no_t) + * Specifies whether to use symmetric mode. Symmetric mode gives + * preference to diagonal pivots, and uses an (A'+A)-based column + * permutation algorithm. + * + * PivotGrowth (yes_no_t) + * Specifies whether to compute the reciprocal pivot growth. + * + * ConditionNumber (ues_no_t) + * Specifies whether to compute the reciprocal condition number. + * + * RowPerm (rowperm_t) (only for SuperLU_DIST or ILU) + * Specifies whether to permute rows of the original matrix. + * = NO: not to permute the rows + * = LargeDiag: make the diagonal large relative to the off-diagonal + * = MY_PERMR: use the permutation given by the user + * + * ILU_DropRule (int) + * Specifies the dropping rule: + * = DROP_BASIC: Basic dropping rule, supernodal based ILUTP(tau). + * = DROP_PROWS: Supernodal based ILUTP(p,tau), p = gamma * nnz(A)/n. + * = DROP_COLUMN: Variant of ILUTP(p,tau), for j-th column, + * p = gamma * nnz(A(:,j)). + * = DROP_AREA: Variation of ILUTP, for j-th column, use + * nnz(F(:,1:j)) / nnz(A(:,1:j)) to control memory. + * = DROP_DYNAMIC: Modify the threshold tau during factorizaion: + * If nnz(L(:,1:j)) / nnz(A(:,1:j)) > gamma + * tau_L(j) := MIN(tau_0, tau_L(j-1) * 2); + * Otherwise + * tau_L(j) := MAX(tau_0, tau_L(j-1) / 2); + * tau_U(j) uses the similar rule. + * NOTE: the thresholds used by L and U are separate. + * = DROP_INTERP: Compute the second dropping threshold by + * interpolation instead of sorting (default). + * In this case, the actual fill ratio is not + * guaranteed to be smaller than gamma. + * Note: DROP_PROWS, DROP_COLUMN and DROP_AREA are mutually exclusive. + * ( Default: DROP_BASIC | DROP_AREA ) + * + * ILU_DropTol (double) + * numerical threshold for dropping. + * + * ILU_FillFactor (double) + * Gamma in the secondary dropping. + * + * ILU_Norm (norm_t) + * Specify which norm to use to measure the row size in a + * supernode: infinity-norm, 1-norm, or 2-norm. + * + * ILU_FillTol (double) + * numerical threshold for zero pivot perturbation. + * + * ILU_MILU (milu_t) + * Specifies which version of MILU to use. + * + * ILU_MILU_Dim (double) + * Dimension of the PDE if available. + * + * ReplaceTinyPivot (yes_no_t) (only for SuperLU_DIST) + * Specifies whether to replace the tiny diagonals by + * sqrt(epsilon)*||A|| during LU factorization. + * + * SolveInitialized (yes_no_t) (only for SuperLU_DIST) + * Specifies whether the initialization has been performed to the + * triangular solve. + * + * RefineInitialized (yes_no_t) (only for SuperLU_DIST) + * Specifies whether the initialization has been performed to the + * sparse matrix-vector multiplication routine needed in iterative + * refinement. + * + * PrintStat (yes_no_t) + * Specifies whether to print the solver's statistics. + */ +typedef struct { + fact_t Fact; + yes_no_t Equil; + colperm_t ColPerm; + trans_t Trans; + IterRefine_t IterRefine; + double DiagPivotThresh; + yes_no_t SymmetricMode; + yes_no_t PivotGrowth; + yes_no_t ConditionNumber; + rowperm_t RowPerm; + int ILU_DropRule; + double ILU_DropTol; /* threshold for dropping */ + double ILU_FillFactor; /* gamma in the secondary dropping */ + norm_t ILU_Norm; /* infinity-norm, 1-norm, or 2-norm */ + double ILU_FillTol; /* threshold for zero pivot perturbation */ + milu_t ILU_MILU; + double ILU_MILU_Dim; /* Dimension of PDE (if available) */ + yes_no_t ParSymbFact; + yes_no_t ReplaceTinyPivot; /* used in SuperLU_DIST */ + yes_no_t SolveInitialized; + yes_no_t RefineInitialized; + yes_no_t PrintStat; + int nnzL, nnzU; /* used to store nnzs for now */ + int num_lookaheads; /* num of levels in look-ahead */ + yes_no_t lookahead_etree; /* use etree computed from the + serial symbolic factorization */ + yes_no_t SymPattern; /* symmetric factorization */ +} superlu_options_t; + +/*! \brief Headers for 4 types of dynamatically managed memory */ +typedef struct e_node { + int size; /* length of the memory that has been used */ + void *mem; /* pointer to the new malloc'd store */ +} ExpHeader; + +typedef struct { + int size; + int used; + int top1; /* grow upward, relative to &array[0] */ + int top2; /* grow downward */ + void *array; +} LU_stack_t; + +typedef struct { + int *panel_histo; /* histogram of panel size distribution */ + double *utime; /* running time at various phases */ + flops_t *ops; /* operation count at various phases */ + int TinyPivots; /* number of tiny pivots */ + int RefineSteps; /* number of iterative refinement steps */ + int expansions; /* number of memory expansions */ +} SuperLUStat_t; + +typedef struct { + float for_lu; + float total_needed; +} mem_usage_t; + + +/*********************************************************************** + * Prototypes + ***********************************************************************/ +#ifdef __cplusplus +extern "C" { +#endif + +extern void Destroy_SuperMatrix_Store(SuperMatrix *); +extern void Destroy_CompCol_Matrix(SuperMatrix *); +extern void Destroy_CompRow_Matrix(SuperMatrix *); +extern void Destroy_SuperNode_Matrix(SuperMatrix *); +extern void Destroy_CompCol_Permuted(SuperMatrix *); +extern void Destroy_Dense_Matrix(SuperMatrix *); +extern void get_perm_c(int, SuperMatrix *, int *); +extern void set_default_options(superlu_options_t *options); +extern void ilu_set_default_options(superlu_options_t *options); +extern void sp_preorder (superlu_options_t *, SuperMatrix*, int*, int*, + SuperMatrix*); +extern void superlu_abort_and_exit(char*); +extern void *superlu_malloc (size_t); +extern int *intMalloc (int); +extern int *intCalloc (int); +extern void superlu_free (void*); +extern void SetIWork (int, int, int, int *, int **, int **, int **, + int **, int **, int **, int **); +extern int sp_coletree (int *, int *, int *, int, int, int *); +extern void relax_snode (const int, int *, const int, int *, int *); +extern void heap_relax_snode (const int, int *, const int, int *, int *); +extern int mark_relax(int, int *, int *, int *, int *, int *, int *); +extern void ilu_relax_snode (const int, int *, const int, int *, + int *, int *); +extern void ilu_heap_relax_snode (const int, int *, const int, int *, + int *, int*); +extern void resetrep_col (const int, const int *, int *); +extern int spcoletree (int *, int *, int *, int, int, int *); +extern int *TreePostorder (int, int *); +extern double SuperLU_timer_ (); +extern int sp_ienv (int); +extern int lsame_ (char *, char *); +extern int xerbla_ (char *, int *); +extern void ifill (int *, int, int); +extern void snode_profile (int, int *); +extern void super_stats (int, int *); +extern void check_repfnz(int, int, int, int *); +extern void PrintSumm (char *, int, int, int); +extern void StatInit(SuperLUStat_t *); +extern void StatPrint (SuperLUStat_t *); +extern void StatFree(SuperLUStat_t *); +extern void print_panel_seg(int, int, int, int, int *, int *); +extern int print_int_vec(char *,int, int *); +extern int slu_PrintInt10(char *, int, int *); + +#ifdef __cplusplus + } +#endif + +#endif /* __SUPERLU_UTIL */ diff --git a/external/arpack++/include/armat.h b/external/arpack++/include/armat.h new file mode 100644 index 000000000..52df53e37 --- /dev/null +++ b/external/arpack++/include/armat.h @@ -0,0 +1,56 @@ +/* + ARPACK++ v1.2 2/20/2000 + c++ interface to ARPACK code. + + MODULE ARMat.h + Generic matrix template with a matrix-vector product. + + ARPACK Authors + Richard Lehoucq + Danny Sorensen + Chao Yang + Dept. of Computational & Applied Mathematics + Rice University + Houston, Texas +*/ + +#ifndef ARMAT_H +#define ARMAT_H + +template +class ARMatrix { + + protected: + + int m, n; // Number of rows and columns. + bool defined; + + public: + + ARMatrix() { defined = false; } + // Short constructor. + + ARMatrix(int nrows, int ncols = 0) + // Long constructor. + { + m = nrows; + n = (ncols?ncols:nrows); + defined = false; + } // Constructor. + + virtual ~ARMatrix() { } + // Destructor. + + int nrows() { return m; } + + int ncols() { return n; } + + bool IsDefined() { return defined; } + + virtual void MultMv(ARTYPE* v, ARTYPE* w) = 0; + // Matrix-vector product: w = A*v. + +}; // ARMatrix. + +#endif // ARMAT_H + diff --git a/external/arpack++/include/arpackf.h b/external/arpack++/include/arpackf.h new file mode 100644 index 000000000..6445b469a --- /dev/null +++ b/external/arpack++/include/arpackf.h @@ -0,0 +1,150 @@ +/* + ARPACK++ v1.2 2/20/2000 + c++ interface to ARPACK code. + + MODULE arpackf.h + ARPACK FORTRAN routines. + + ARPACK Authors + Richard Lehoucq + Danny Sorensen + Chao Yang + Dept. of Computational & Applied Mathematics + Rice University + Houston, Texas +*/ + +#ifndef ARPACKF_H +#define ARPACKF_H + +#include "arch.h" + +extern "C" +{ + +// debug "common" statement. + + extern struct { + ARint logfil, ndigit, mgetv0; + ARint msaupd, msaup2, msaitr, mseigt, msapps, msgets, mseupd; + ARint mnaupd, mnaup2, mnaitr, mneigt, mnapps, mngets, mneupd; + ARint mcaupd, mcaup2, mcaitr, mceigt, mcapps, mcgets, mceupd; + } F77NAME(debug); + + +// double precision symmetric routines. + + void F77NAME(dsaupd)(ARint *ido, char *bmat, ARint *n, const char *which, + ARint *nev, double *tol, double *resid, + ARint *ncv, double *V, ARint *ldv, + ARint *iparam, ARint *ipntr, double *workd, + double *workl, ARint *lworkl, ARint *info); + + void F77NAME(dseupd)(ARlogical *rvec, char *HowMny, ARlogical *select, + double *d, double *Z, ARint *ldz, + double *sigma, char *bmat, ARint *n, + const char *which, ARint *nev, double *tol, + double *resid, ARint *ncv, double *V, + ARint *ldv, ARint *iparam, ARint *ipntr, + double *workd, double *workl, + ARint *lworkl, ARint *info); + +// double precision nonsymmetric routines. + + void F77NAME(dnaupd)(ARint *ido, char *bmat, ARint *n, const char *which, + ARint *nev, double *tol, double *resid, + ARint *ncv, double *V, ARint *ldv, + ARint *iparam, ARint *ipntr, double *workd, + double *workl, ARint *lworkl, ARint *info); + + void F77NAME(dneupd)(ARlogical *rvec, char *HowMny, ARlogical *select, + double *dr, double *di, double *Z, + ARint *ldz, double *sigmar, + double *sigmai, double *workev, + char *bmat, ARint *n, const char *which, + ARint *nev, double *tol, double *resid, + ARint *ncv, double *V, ARint *ldv, + ARint *iparam, ARint *ipntr, + double *workd, double *workl, + ARint *lworkl, ARint *info); + +// single precision symmetric routines. + + void F77NAME(ssaupd)(ARint *ido, char *bmat, ARint *n, const char *which, + ARint *nev, float *tol, float *resid, + ARint *ncv, float *V, ARint *ldv, + ARint *iparam, ARint *ipntr, float *workd, + float *workl, ARint *lworkl, ARint *info); + + void F77NAME(sseupd)(ARlogical *rvec, char *HowMny, ARlogical *select, + float *d, float *Z, ARint *ldz, + float *sigma, char *bmat, ARint *n, + const char *which, ARint *nev, float *tol, + float *resid, ARint *ncv, float *V, + ARint *ldv, ARint *iparam, ARint *ipntr, + float *workd, float *workl, + ARint *lworkl, ARint *info); + +// single precision nonsymmetric routines. + + void F77NAME(snaupd)(ARint *ido, char *bmat, ARint *n, const char *which, + ARint *nev, float *tol, float *resid, + ARint *ncv, float *V, ARint *ldv, + ARint *iparam, ARint *ipntr, float *workd, + float *workl, ARint *lworkl, ARint *info); + + void F77NAME(sneupd)(ARlogical *rvec, char *HowMny, ARlogical *select, + float *dr, float *di, float *Z, + ARint *ldz, float *sigmar, + float *sigmai, float *workev, char *bmat, + ARint *n, const char *which, ARint *nev, + float *tol, float *resid, ARint *ncv, + float *V, ARint *ldv, ARint *iparam, + ARint *ipntr, float *workd, float *workl, + ARint *lworkl, ARint *info); + +#ifdef ARCOMP_H + +// single precision complex routines. + + void F77NAME(cnaupd)(ARint *ido, char *bmat, ARint *n, const char *which, + ARint *nev, float *tol, arcomplex *resid, + ARint *ncv, arcomplex *V, ARint *ldv, + ARint *iparam, ARint *ipntr, arcomplex *workd, + arcomplex *workl, ARint *lworkl, + float *rwork, ARint *info); + + void F77NAME(cneupd)(ARlogical *rvec, char *HowMny, ARlogical *select, + arcomplex *d, arcomplex *Z, ARint *ldz, + arcomplex *sigma, arcomplex *workev, + char *bmat, ARint *n, const char *which, ARint *nev, + float *tol, arcomplex *resid, ARint *ncv, + arcomplex *V, ARint *ldv, ARint *iparam, + ARint *ipntr, arcomplex *workd, + arcomplex *workl, ARint *lworkl, + float *rwork, ARint *info); + +// double precision complex routines. + + void F77NAME(znaupd)(ARint *ido, char *bmat, ARint *n, const char *which, + ARint *nev, double *tol, arcomplex *resid, + ARint *ncv, arcomplex *V, ARint *ldv, + ARint *iparam, ARint *ipntr, arcomplex *workd, + arcomplex *workl, ARint *lworkl, + double *rwork, ARint *info); + + void F77NAME(zneupd)(ARlogical *rvec, char *HowMny, ARlogical *select, + arcomplex *d, arcomplex *Z, ARint *ldz, + arcomplex *sigma, arcomplex *workev, + char *bmat, ARint *n, const char *which, ARint *nev, + double *tol, arcomplex *resid, ARint *ncv, + arcomplex *V, ARint *ldv, ARint *iparam, + ARint *ipntr, arcomplex *workd, + arcomplex *workl, ARint *lworkl, + double *rwork, ARint *info); + +} + +#endif // ARCOMP_H + +#endif // ARPACKF_H diff --git a/external/arpack++/include/arrgcomp.h b/external/arpack++/include/arrgcomp.h new file mode 100644 index 000000000..d3b2e3d0c --- /dev/null +++ b/external/arpack++/include/arrgcomp.h @@ -0,0 +1,110 @@ +/* + ARPACK++ v1.2 2/20/2000 + c++ interface to ARPACK code. + + MODULE ARRGComp.h. + Arpack++ class ARrcCompGenEig definition. + + ARPACK Authors + Richard Lehoucq + Danny Sorensen + Chao Yang + Dept. of Computational & Applied Mathematics + Rice University + Houston, Texas +*/ + +#ifndef ARRGCOMP_H +#define ARRGCOMP_H + +#include +#include +#include "arch.h" +#include "arrscomp.h" +#include "arrgeig.h" + +template +class ARrcCompGenEig: + virtual public ARrcGenEig >, + virtual public ARrcCompStdEig { + + public: + + // a) Constructors and destructor. + + ARrcCompGenEig() { } + // Short constructor (Does nothing but calling base classes constructors). + + ARrcCompGenEig(int np, int nevp, const std::string& whichp = "LM", + int ncvp = 0, ARFLOAT tolp = 0.0, int maxitp = 0, + arcomplex* residp = NULL, bool ishiftp = true); + // Long constructor (regular mode). + + ARrcCompGenEig(int np, int nevp, arcomplex sigmap, + const std::string& whichp = "LM", int ncvp = 0, ARFLOAT tolp = 0.0, + int maxitp = 0, arcomplex* residp = NULL, + bool ishiftp = true); + // Long constructor (shift and invert mode). + + ARrcCompGenEig(const ARrcCompGenEig& other) { Copy(other); } + // Copy constructor. + + virtual ~ARrcCompGenEig() { } + // Destructor. + + // b) Operators. + + ARrcCompGenEig& operator=(const ARrcCompGenEig& other); + // Assignment operator. + +}; // class ARrcCompGenEig. + + +// ------------------------------------------------------------------------ // +// ARrcCompGenEig member functions definition. // +// ------------------------------------------------------------------------ // + + +template +inline ARrcCompGenEig:: +ARrcCompGenEig(int np, int nevp, const std::string& whichp, int ncvp, ARFLOAT tolp, + int maxitp, arcomplex* residp, bool ishiftp) + +{ + + this->NoShift(); + this->DefineParameters(np, nevp, whichp, ncvp, tolp, maxitp, residp, ishiftp); + +} // Long constructor (regular mode). + + +template +inline ARrcCompGenEig:: +ARrcCompGenEig(int np, int nevp, arcomplex sigmap, const std::string& whichp, + int ncvp, ARFLOAT tolp, int maxitp, arcomplex* residp, + bool ishiftp) + +{ + + this->ChangeShift(sigmap); + this->DefineParameters(np, nevp, whichp, ncvp, tolp, maxitp, residp, ishiftp); + +} // Long constructor (shif and invert mode). + + +template +ARrcCompGenEig& ARrcCompGenEig:: +operator=(const ARrcCompGenEig& other) +{ + + if (this != &other) { // Stroustrup suggestion. + this->ClearMem(); + Copy(other); + } + return *this; + +} // operator=. + + +#endif // ARRGCOMP_H + diff --git a/external/arpack++/include/arrgeig.h b/external/arpack++/include/arrgeig.h new file mode 100644 index 000000000..d9c709ec1 --- /dev/null +++ b/external/arpack++/include/arrgeig.h @@ -0,0 +1,103 @@ +/* + ARPACK++ v1.2 2/20/2000 + c++ interface to ARPACK code. + + MODULE ARRGEig.h. + Arpack++ class ARrcGenEig definition. + Derived from ARrcStdEig, this class implements the + reverse communication interface for generalized problems. + + ARPACK Authors + Richard Lehoucq + Danny Sorensen + Chao Yang + Dept. of Computational & Applied Mathematics + Rice University + Houston, Texas +*/ + +#ifndef ARRGEIG_H +#define ARRGEIG_H + +#include "arch.h" +#include "arerror.h" +#include "arrseig.h" + +// ARrcGenEig class definition. + +template +class ARrcGenEig: virtual public ARrcStdEig { + + public: + + // a) Public functions: + + // a.1) Functions that allow changes in problem parameters. + + void NoShift(); + // Turns the problem to regular mode. + + + // a.2) Constructors and destructor. + + ARrcGenEig(); + // Short constructor that does almost nothing. + + ARrcGenEig(const ARrcGenEig& other) { Copy(other); } + // Copy constructor. + + virtual ~ARrcGenEig() { } + // Destructor (presently meaningless). + + // b) Operators. + + ARrcGenEig& operator=(const ARrcGenEig& other); + // Assignment operator. + +}; // class ARrcGenEig. + + +// ------------------------------------------------------------------------ // +// ARrcGenEig member functions definition. // +// ------------------------------------------------------------------------ // + + +template +inline void ARrcGenEig::NoShift() +{ + + this->sigmaR = (ARTYPE)0; + this->sigmaI = 0.0; + this->mode = 2; + this->iparam[7] = this->mode; + this->Restart(); + +} // NoShift. + + +template +inline ARrcGenEig::ARrcGenEig() +{ + + this->bmat = 'G'; // This is a generalized problem. + this->NoShift(); + +} // Short constructor. + + +template +ARrcGenEig& ARrcGenEig:: +operator=(const ARrcGenEig& other) +{ + + if (this != &other) { // Stroustrup suggestion. + this->ClearMem(); + Copy(other); + } + return *this; + +} // operator=. + + +#endif // ARRGEIG_H + diff --git a/external/arpack++/include/arrgnsym.h b/external/arpack++/include/arrgnsym.h new file mode 100644 index 000000000..1dbd3be73 --- /dev/null +++ b/external/arpack++/include/arrgnsym.h @@ -0,0 +1,244 @@ +/* + ARPACK++ v1.2 2/20/2000 + c++ interface to ARPACK code. + + MODULE ARRGNSym.h. + Arpack++ class ARrcNonSymGenEig definition. + + ARPACK Authors + Richard Lehoucq + Danny Sorensen + Chao Yang + Dept. of Computational & Applied Mathematics + Rice University + Houston, Texas +*/ + +#ifndef ARRGNSYM_H +#define ARRGNSYM_H + +#include +#include +#include "arch.h" +#include "arrsnsym.h" +#include "arrgeig.h" + +template +class ARrcNonSymGenEig: + virtual public ARrcGenEig, + virtual public ARrcNonSymStdEig { + + protected: + + // a) Protected variables: + + char part; + + + // b) Protected functions: + + char CheckPart(char partp); + + virtual void Copy(const ARrcNonSymGenEig& other); + // Makes a deep copy of "other" over "this" object. + // Old values are not deleted (this function is to be used + // by the copy constructor and the assignment operator only). + + + public: + + // c) Public functions: + + // c.1) Functions that provides access to internal variables' values. + + ARFLOAT GetShiftImag() { return this->sigmaI; } + // Returns the imaginary part of the shift (when in shift and invert mode). + + + // c.2) Functions that allow changes in problem parameters. + + void ChangePart(char partp); + // Changes "part" to 'R' (real) or 'I' (imaginary). + + virtual void ChangeShift(ARFLOAT sigmaRp, ARFLOAT sigmaIp = 0.0); + // Turns the problem to shift-and-invert mode + // with shift defined by sigmaRp and sigmaIp. + + virtual void SetShiftInvertMode(ARFLOAT sigmaRp); + // Turns the problem to real shift-and-invert mode with sigmaRp as shift. + + virtual void SetComplexShiftMode(char partp, ARFLOAT sigmaRp, + ARFLOAT sigmaIp); + // Turns the problem to complex shift-and-invert mode with shift + // defined by sigmaRp and sigmaIp. + + + // c.3) Constructors and destructor. + + ARrcNonSymGenEig() { part = 'R'; } + // Short constructor that does almost nothing. + + ARrcNonSymGenEig(int np, int nevp, const std::string& whichp = "LM", + int ncvp = 0, ARFLOAT tolp = 0.0, int maxitp = 0, + ARFLOAT* residp = NULL, bool ishiftp = true); + // Long constructor (regular mode). + + ARrcNonSymGenEig(int np, int nevp, ARFLOAT sigmap, + const std::string& whichp = "LM", int ncvp = 0, ARFLOAT tolp = 0.0, + int maxitp = 0, ARFLOAT* residp = NULL, + bool ishiftp = true); + // Long constructor (real shift and invert mode). + + ARrcNonSymGenEig(int np, int nevp, + char partp, ARFLOAT sigmaRp, ARFLOAT sigmaIp, + const std::string& whichp = "LM", int ncvp = 0, ARFLOAT tolp = 0.0, + int maxitp = 0, ARFLOAT* residp = NULL, + bool ishiftp = true); + // Long constructor (complex shift and invert mode). + + ARrcNonSymGenEig(const ARrcNonSymGenEig& other) { Copy(other); } + // Copy constructor. + + virtual ~ARrcNonSymGenEig() { } + // Destructor. + + // d) Operators. + + ARrcNonSymGenEig& operator=(const ARrcNonSymGenEig& other); + // Assignment operator. + +}; // class ARrcNonSymGenEig. + + +// ------------------------------------------------------------------------ // +// ARrcNonSymGenEig member functions definition. // +// ------------------------------------------------------------------------ // + + +template +inline char ARrcNonSymGenEig::CheckPart(char partp) +{ + if ((partp != 'R') && (partp != 'I')) { + throw ArpackError(ArpackError::PART_UNDEFINED); + } + return partp; +} // CheckPart. + + +template +inline void ARrcNonSymGenEig:: +Copy(const ARrcNonSymGenEig& other) +{ + + ARrcStdEig::Copy(other); + part = other.part; + +} // Copy. + + +template +inline void ARrcNonSymGenEig::ChangePart(char partp) +{ + + part = CheckPart(partp); + if (part == 'R') { + this->mode = 3; // Real part. + } + else { + this->mode = 4; // Imaginary part. + } + this->iparam[7] = this->mode; + this->Restart(); + +} // ChangePart. + + +template +inline void ARrcNonSymGenEig:: +ChangeShift(ARFLOAT sigmaRp, ARFLOAT sigmaIp) +{ + + this->sigmaR = sigmaRp; + this->sigmaI = sigmaIp; + ChangePart(part); + +} // ChangeShift. + + +template +inline void ARrcNonSymGenEig:: +SetShiftInvertMode(ARFLOAT sigmaRp) +{ + + part = 'R'; + ChangeShift(sigmaRp); + +} // SetShiftInvertMode. + + +template +inline void ARrcNonSymGenEig:: +SetComplexShiftMode(char partp, ARFLOAT sigmaRp, ARFLOAT sigmaIp) +{ + + part = CheckPart(partp); + ChangeShift(sigmaRp, sigmaIp); + +} // SetComplexShiftMode. + + +template +inline ARrcNonSymGenEig:: +ARrcNonSymGenEig(int np, int nevp, const std::string& whichp, int ncvp, ARFLOAT tolp, + int maxitp, ARFLOAT* residp, bool ishiftp) +{ + + part = 'R'; // Considering mode = 3 in ChangeShift. + this->NoShift(); + this->DefineParameters(np, nevp, whichp, ncvp, tolp, maxitp, residp, ishiftp); + +} // Long constructor (regular mode). + + +template +inline ARrcNonSymGenEig:: +ARrcNonSymGenEig(int np, int nevp, ARFLOAT sigmap, const std::string& whichp, int ncvp, + ARFLOAT tolp, int maxitp, ARFLOAT* residp, bool ishiftp) +{ + + SetShiftInvertMode(sigmap); + this->DefineParameters(np, nevp, whichp, ncvp, tolp, maxitp, residp, ishiftp); + + +} // Long constructor (real shift and invert mode). + + +template +inline ARrcNonSymGenEig:: +ARrcNonSymGenEig(int np, int nevp, char partp, ARFLOAT sigmaRp, + ARFLOAT sigmaIp, const std::string& whichp, int ncvp, ARFLOAT tolp, + int maxitp, ARFLOAT* residp, bool ishiftp) +{ + + SetComplexShiftMode(partp, sigmaRp, sigmaIp); + this->DefineParameters(np, nevp, whichp, ncvp, tolp, maxitp, residp, ishiftp); + +} // Long constructor (shift and invert mode). + + +template +ARrcNonSymGenEig& ARrcNonSymGenEig:: +operator=(const ARrcNonSymGenEig& other) +{ + + if (this != &other) { // Stroustrup suggestion. + this->ClearMem(); + Copy(other); + } + return *this; + +} // operator=. + + +#endif // ARRGNSYM_H + diff --git a/external/arpack++/include/arrgsym.h b/external/arpack++/include/arrgsym.h new file mode 100644 index 000000000..86f110d8b --- /dev/null +++ b/external/arpack++/include/arrgsym.h @@ -0,0 +1,236 @@ +/* + ARPACK++ v1.2 2/20/2000 + c++ interface to ARPACK code. + + MODULE ARRGSym.h. + Arpack++ class ARrcSymGenEig definition. + + ARPACK Authors + Richard Lehoucq + Danny Sorensen + Chao Yang + Dept. of Computational & Applied Mathematics + Rice University + Houston, Texas +*/ + +#ifndef ARRGSYM_H +#define ARRGSYM_H + +#include +#include +#include "arch.h" +#include "arrssym.h" +#include "arrgeig.h" + +template +class ARrcSymGenEig: + virtual public ARrcGenEig, + virtual public ARrcSymStdEig { + + protected: + + // a) Protected variable: + + char InvertMode; + + + // b) Protected functions: + + char CheckInvertMode(char InvertModep); + + virtual void Copy(const ARrcSymGenEig& other); + // Makes a deep copy of "other" over "this" object. + // Old values are not deleted (this function is to be used + // by the copy constructor and the assignment operator only). + + + public: + + // c) Public functions: + + // c.1) Functions that allow changes in problem parameters. + + void ChangeInvertMode(char InvertModep); + // Changes "InvertMode" to 'S' (shift-and-invert), + // 'B' (buckling) or 'C' (cayley) mode. + + virtual void ChangeShift(ARFLOAT sigmap); + // Changes shift value. + + virtual void SetShiftInvertMode(ARFLOAT sigmap); + // Turns problem to shift and invert mode with shift defined by sigmap. + + virtual void SetBucklingMode(ARFLOAT sigmap); + // Turns problem to buckling mode with shift defined by sigmap. + + virtual void SetCayleyMode(ARFLOAT sigmap); + // Turns problem to Cayley mode with shift defined by sigmap. + + + // c.2) Constructors and destructor. + + ARrcSymGenEig() { InvertMode = 'S'; } + // Short constructor that does almost nothing. + + ARrcSymGenEig(int np, int nevp, const std::string& whichp = "LM", + int ncvp = 0, ARFLOAT tolp = 0.0, int maxitp = 0, + ARFLOAT* residp = NULL, bool ishiftp = true); + // Long constructor (regular mode). + + ARrcSymGenEig(char invertmodep, int np, int nevp, ARFLOAT sigmap, + const std::string& whichp = "LM", int ncvp = 0, ARFLOAT tolp = 0.0, + int maxitp = 0, ARFLOAT* residp = NULL, bool ishiftp = true); + // Long constructor (shift-and-invert, buckling and Cayley modes). + + ARrcSymGenEig(const ARrcSymGenEig& other) { Copy(other); } + // Copy constructor. + + virtual ~ARrcSymGenEig() { } + // Destructor. + + // d) Operators. + + ARrcSymGenEig& operator=(const ARrcSymGenEig& other); + // Assignment operator. + +}; // class ARrcSymGenEig. + + +// ------------------------------------------------------------------------ // +// ARrcSymGenEig member functions definition. // +// ------------------------------------------------------------------------ // + + +template +inline char ARrcSymGenEig::CheckInvertMode(char InvertModep) +{ + if ((InvertModep != 'S') && (InvertModep != 'B') && (InvertModep != 'C')) { + throw ArpackError(ArpackError::INVMODE_UNDEFINED); + } + return InvertModep; + +} // CheckInvertMode. + + +template +inline void ARrcSymGenEig::Copy(const ARrcSymGenEig& other) +{ + + ARrcStdEig::Copy(other); + InvertMode = other.InvertMode; + +} // Copy. + + +template +inline void ARrcSymGenEig::ChangeInvertMode(char InvertModep) +{ + + InvertMode = CheckInvertMode(InvertModep); + switch (InvertMode) { + case 'S': + this->mode = 3; // Shift and invert mode. + break; + case 'B': + this->mode = 4; // Buckling mode. + break; + case 'C': + this->mode = 5; // Cayley mode. + break; + } + this->iparam[7] = this->mode; + this->Restart(); + +} // ChangeInvertMode. + + +template +inline void ARrcSymGenEig::ChangeShift(ARFLOAT sigmap) +{ + + this->sigmaR = sigmap; + this->sigmaI = 0.0; + ChangeInvertMode(InvertMode); + +} // ChangeShift. + + +template +void ARrcSymGenEig::SetShiftInvertMode(ARFLOAT sigmap) + +{ + + InvertMode = 'S'; + ChangeShift(sigmap); + +} // SetShiftInvertMode. + + +template +void ARrcSymGenEig::SetBucklingMode(ARFLOAT sigmap) + +{ + + InvertMode = 'B'; + ChangeShift(sigmap); + +} // SetBucklingMode. + + +template +void ARrcSymGenEig::SetCayleyMode(ARFLOAT sigmap) + +{ + + InvertMode = 'C'; + ChangeShift(sigmap); + +} // SetCayleyMode. + + +template +inline ARrcSymGenEig:: +ARrcSymGenEig(int np, int nevp, const std::string& whichp, int ncvp, ARFLOAT tolp, + int maxitp, ARFLOAT* residp, bool ishiftp) + +{ + + InvertMode = 'S'; // Considering mode = 3 in ChangeShift. + this->NoShift(); + this->DefineParameters(np, nevp, whichp, ncvp, tolp, maxitp, residp, ishiftp); + +} // Long constructor (regular mode). + + +template +inline ARrcSymGenEig:: +ARrcSymGenEig(char InvertModep, int np, int nevp, + ARFLOAT sigmap, const std::string& whichp, int ncvp, ARFLOAT tolp, + int maxitp, ARFLOAT* residp, bool ishiftp) + +{ + + InvertMode = CheckInvertMode(InvertModep); // InvertMode = 'S', 'B', 'C'. + ChangeShift(sigmap); + this->DefineParameters(np, nevp, whichp, ncvp, tolp, maxitp, residp, ishiftp); + +} // Long constructor (shift-and-invert, buckling and Cayley modes). + + +template +ARrcSymGenEig& ARrcSymGenEig:: +operator=(const ARrcSymGenEig& other) +{ + + if (this != &other) { // Stroustrup suggestion. + this->ClearMem(); + Copy(other); + } + return *this; + +} // operator=. + + +#endif // ARRGSYM_H + diff --git a/external/arpack++/include/arrscomp.h b/external/arpack++/include/arrscomp.h new file mode 100644 index 000000000..409775518 --- /dev/null +++ b/external/arpack++/include/arrscomp.h @@ -0,0 +1,375 @@ +/* + ARPACK++ v1.2 2/20/2000 + c++ interface to ARPACK code. + + MODULE ARRSComp.h. + Arpack++ class ARrcCompStdEig definition. + + ARPACK Authors + Richard Lehoucq + Danny Sorensen + Chao Yang + Dept. of Computational & Applied Mathematics + Rice University + Houston, Texas +*/ + +#ifndef ARRSCOMP_H +#define ARRSCOMP_H + +#include +#include +#include "arch.h" +#include "arerror.h" +#include "debug.h" +#include "arrseig.h" +#include "caupp.h" +#include "ceupp.h" + +template +class ARrcCompStdEig: virtual public ARrcStdEig > { + + protected: + + // a) Protected functions: + + // a.1) Memory control functions. + + void WorkspaceAllocate(); + // Allocates workspace for complex problems. + + + // a.2) Functions that handle original FORTRAN ARPACK code. + + void Aupp(); + // Interface to FORTRAN subroutines CNAUPD and ZNAUPD. + + void Eupp(); + // Interface to FORTRAN subroutines CNEUPD and ZNEUPD. + + public: + + // b) Public functions: + + // b.1) Trace functions. + + void Trace(const int digit = -5, const int getv0 = 0, const int aupd = 1, + const int aup2 = 0, const int aitr = 0, const int eigt = 0, + const int apps = 0, const int gets = 0, const int eupd = 0) + { + cTraceOn(digit, getv0, aupd, aup2, aitr, eigt, apps, gets, eupd); + } + // Turns on trace mode. + + + // b.2) Functions that perform all calculations in one step. + + int Eigenvalues(arcomplex* &EigValp, bool ivec = false, + bool ischur = false); + // Overrides array EigValp with the eigenvalues of the problem. + // Also calculates eigenvectors and Schur vectors if requested. + + int EigenValVectors(arcomplex* &EigVecp, + arcomplex* &EigValp, bool ischur = false); + // Overrides array EigVecp sequentially with the eigenvectors of the + // given eigen-problem. Also stores the eigenvalues in EigValp. + // Calculates Schur vectors if requested. + + + // b.3) Functions that return elements of vectors and matrices. + + arcomplex Eigenvalue(int i); + // Provides i-eth eigenvalue. + + arcomplex Eigenvector(int i, int j); + // Provides element j of the i-eth eigenvector. + + + // b.4) Functions that use STL vector class. + +#ifdef STL_VECTOR_H + + vector >* StlEigenvalues(bool ivec = false, + bool ischur = false); + // Calculates the eigenvalues and stores them in a single STL vector. + // Also calculates eigenvectors and Schur vectors if requested. + + vector >* StlEigenvector(int i); + // Returns the i-th eigenvector in a STL vector. + +#endif // #ifdef STL_VECTOR_H. + + + // b.5) Constructors and destructor. + + ARrcCompStdEig() { } + // Short constructor. + + ARrcCompStdEig(int np, int nevp, const std::string& whichp = "LM", + int ncvp = 0, ARFLOAT tolp = 0.0, int maxitp = 0, + arcomplex* residp = NULL, bool ishiftp = true); + // Long constructor (regular mode). + + ARrcCompStdEig(int np, int nevp, arcomplex sigma, + const std::string& whichp = "LM", int ncvp = 0, ARFLOAT tolp = 0.0, + int maxitp = 0, arcomplex* residp = NULL, + bool ishiftp = true); + // Long constructor (shift and invert mode). + + ARrcCompStdEig(const ARrcCompStdEig& other) { Copy(other); } + // Copy constructor. + + virtual ~ARrcCompStdEig() { } + // Destructor. + + // c) Operators. + + ARrcCompStdEig& operator=(const ARrcCompStdEig& other); + // Assignment operator. + +}; // class ARrcCompStdEig. + + +// ------------------------------------------------------------------------ // +// ARrcCompStdEig member functions definition. // +// ------------------------------------------------------------------------ // + + +template +inline void ARrcCompStdEig::WorkspaceAllocate() +{ + + this->lworkl = this->ncv*(3*this->ncv+6); + this->lworkv = 2*this->ncv; + this->lrwork = this->ncv; + this->workl = new arcomplex[this->lworkl+1]; + this->workv = new arcomplex[this->lworkv+1]; + this->rwork = new ARFLOAT[this->lrwork+1]; + +} // WorkspaceAllocate. + + +template +inline void ARrcCompStdEig::Aupp() +{ + + caupp(this->ido, this->bmat, this->n, this->which, this->nev, this->tol, this->resid, this->ncv, this->V, this->n, + this->iparam, this->ipntr, this->workd, this->workl, this->lworkl, this->rwork, this->info); + +} // Aupp. + + +template +inline void ARrcCompStdEig::Eupp() +{ + + ceupp(this->rvec, this->HowMny, this->EigValR, this->EigVec, this->n, this->sigmaR, this->workv, + this->bmat, this->n, this->which, this->nev, this->tol, this->resid, this->ncv, this->V, this->n, this->iparam, + this->ipntr, this->workd, this->workl, this->lworkl, this->rwork, this->info); + +} // Eupp. + + +template +int ARrcCompStdEig:: +Eigenvalues(arcomplex* &EigValp, bool ivec, bool ischur) +{ + + if (this->ValuesOK) { // Eigenvalues are available . + if (EigValp == NULL) { // Moving eigenvalues. + EigValp = this->EigValR; + this->EigValR = NULL; + this->newVal = false; + this->ValuesOK = false; + } + else { // Copying eigenvalues. + copy(this->nconv,this->EigValR,1,EigValp,1); + } + } + else { + if (this->newVal) { + delete[] this->EigValR; + this->newVal = false; + } + if (EigValp == NULL) { + try { EigValp = new arcomplex[this->ValSize()]; } + catch (ArpackError) { return 0; } + } + this->EigValR = EigValp; + if (ivec) { // Finding eigenvalues and eigenvectors. + this->nconv = this->FindEigenvectors(ischur); + } + else { // Finding eigenvalues only. + this->nconv = this->FindEigenvalues(); + } + this->EigValR = NULL; + } + return this->nconv; + +} // Eigenvalues(EigValp, ivec, ischur). + + +template +int ARrcCompStdEig:: +EigenValVectors(arcomplex* &EigVecp, arcomplex* &EigValp, + bool ischur) +{ + + if (this->ValuesOK) { // Eigenvalues are already available. + this->nconv = Eigenvalues(EigValp, false); + this->nconv = this->Eigenvectors(EigVecp, ischur); + } + else { // Eigenvalues and vectors are not available. + if (this->newVec) { + delete[] this->EigVec; + this->newVec = false; + } + if (this->newVal) { + delete[] this->EigValR; + this->newVal = false; + } + try { + if (EigVecp == NULL) EigVecp = new arcomplex[this->ValSize()*this->n]; + if (EigValp == NULL) EigValp = new arcomplex[this->ValSize()]; + } + catch (ArpackError) { return 0; } + this->EigVec = EigVecp; + this->EigValR = EigValp; + this->nconv = this->FindEigenvectors(ischur); + this->EigVec = NULL; + this->EigValR = NULL; + } + return this->nconv; + +} // EigenValVectors(EigVecp, EigValp, ischur). + + +template +inline arcomplex ARrcCompStdEig::Eigenvalue(int i) +// calcula e retorna um autovalor. + +{ + + // Returning i-eth eigenvalue. + + if (!this->ValuesOK) { + throw ArpackError(ArpackError::VALUES_NOT_OK, "Eigenvalue(i)"); + } + else if ((i>=this->nconv)||(i<0)) { + throw ArpackError(ArpackError::RANGE_ERROR, "Eigenvalue(i)"); + } + return this->EigValR[i]; + +} // Eigenvalue(i). + + +template +inline arcomplex ARrcCompStdEig:: +Eigenvector(int i, int j) +{ + + // Returning element j of i-eth eigenvector. + + if (!this->VectorsOK) { + throw ArpackError(ArpackError::VECTORS_NOT_OK, "Eigenvector(i,j)"); + } + else if ((i>=this->nconv)||(i<0)||(j>=this->n)||(j<0)) { + throw ArpackError(ArpackError::RANGE_ERROR, "Eigenvector(i,j)"); + } + return this->EigVec[i*this->n+j]; + +} // Eigenvector(i,j). + + +#ifdef STL_VECTOR_H + +template +inline vector >* ARrcCompStdEig:: +StlEigenvalues(bool ivec, bool ischur) +{ + + // Returning the eigenvalues in a STL vector. + + vector >* ValR; + arcomplex* ValPtr; + + try { + ValR = new vector >(ValSize()); + } + catch (ArpackError) { return NULL; } + ValPtr = ValR->begin(); + nconv = Eigenvalues(ValPtr, ivec, ischur); + return ValR; + +} // StlEigenvalues. + + +template +inline vector >* ARrcCompStdEig:: +StlEigenvector(int i) +{ + + // Returning the i-th eigenvector in a STL vector. + + vector >* Vec; + + if (!VectorsOK) { + throw ArpackError(ArpackError::VECTORS_NOT_OK, "StlEigenvector(i)"); + } + else if ((i>=ValSize())||(i<0)) { + throw ArpackError(ArpackError::RANGE_ERROR, "StlEigenvector(i)"); + } + try { + Vec = new vector >(&EigVec[i*n], &EigVec[(i+1)*n]); + } + catch (ArpackError) { return NULL; } + return Vec; + +} // StlEigenvector(i). + +#endif // #ifdef STL_VECTOR_H. + + +template +inline ARrcCompStdEig:: +ARrcCompStdEig(int np, int nevp, const std::string& whichp, int ncvp, ARFLOAT tolp, + int maxitp, arcomplex* residp, bool ishiftp) + +{ + + this->NoShift(); + this->DefineParameters(np, nevp, whichp, ncvp, tolp, maxitp, residp, ishiftp); + +} // Long constructor (regular mode). + + +template +inline ARrcCompStdEig:: +ARrcCompStdEig(int np, int nevp, arcomplex sigmap, + const std::string& whichp, int ncvp, ARFLOAT tolp, int maxitp, + arcomplex* residp, bool ishiftp) + +{ + + this->ChangeShift(sigmap); + this->DefineParameters(np, nevp, whichp, ncvp, tolp, maxitp, residp, ishiftp); + +} // Long constructor (shift and invert mode). + + +template +ARrcCompStdEig& ARrcCompStdEig:: +operator=(const ARrcCompStdEig& other) +{ + + if (this != &other) { // Stroustrup suggestion. + this->ClearMem(); + Copy(other); + } + return *this; + +} // operator=. + + +#endif // ARRSCOMP_H + diff --git a/external/arpack++/include/arrseig.h b/external/arpack++/include/arrseig.h new file mode 100644 index 000000000..57cba476c --- /dev/null +++ b/external/arpack++/include/arrseig.h @@ -0,0 +1,1515 @@ +/* + ARPACK++ v1.2 2/20/2000 + c++ interface to ARPACK code. + + MODULE ARRSEig.h. + Arpack++ base class ARrcStdEig definition. + This class implements c++ version of the reverse + communication interface for standard problems. + + ARPACK Authors + Richard Lehoucq + Danny Sorensen + Chao Yang + Dept. of Computational & Applied Mathematics + Rice University + Houston, Texas +*/ + +#ifndef ARRSEIG_H +#define ARRSEIG_H + +#include +#include +#include +#include "arch.h" +#include "arerror.h" +#include "debug.h" +#include "blas1c.h" + + +// ARrcStdEig class definition. + +template +class ARrcStdEig { + + protected: + + // a) Protected variables: + + // a.1) User defined parameters. + + int n; // Dimension of the eigenproblem. + int nev; // Number of eigenvalues to be computed. 0 < nev < n-1. + int ncv; // Number of Arnoldi vectors generated at each iteration. + int maxit; // Maximum number of Arnoldi update iterations allowed. + std::string which; // Specify which of the Ritz values of OP to compute. + ARFLOAT tol; // Stopping criterion (relative accuracy of Ritz values). + ARFLOAT sigmaI; // Imaginary part of shift (for nonsymmetric problems). + ARTYPE sigmaR; // Shift (real part only if problem is nonsymmetric). + ARTYPE *resid; // Initial residual vector. + + + // a.2) Internal variables. + + bool rvec; // Indicates if eigenvectors/Schur vectors were + // requested (or only eigenvalues will be determined). + bool newRes; // Indicates if a new "resid" vector was created. + bool newVal; // Indicates if a new "EigValR" vector was created. + bool newVec; // Indicates if a new "EigVec" vector was created. + bool PrepareOK; // Indicates if internal variables were correctly set. + bool BasisOK; // Indicates if an Arnoldi basis was found. + bool ValuesOK; // Indicates if eigenvalues were calculated. + bool VectorsOK; // Indicates if eigenvectors were determined. + bool SchurOK; // Indicates if Schur vectors were determined. + bool AutoShift; // Indicates if implicit shifts will be generated + // internally (or will be supplied by the user). + char bmat; // Indicates if the problem is a standard ('I') or + // generalized ('G") eigenproblem. + char HowMny; // Indicates if eigenvectors ('A') or Schur vectors ('P') + // were requested (not referenced if rvec = false). + int ido; // Original ARPACK reverse communication flag. + int info; // Original ARPACK error flag. + int mode; // Indicates the type of the eigenproblem (regular, + // shift and invert, etc). + int lworkl; // Dimension of array workl. + int lworkv; // Dimension of array workv. + int lrwork; // Dimension of array rwork. + int iparam[12]; // Vector that handles original ARPACK parameters. + int ipntr[15]; // Vector that handles original ARPACK pointers. + ARFLOAT *rwork; // Original ARPACK internal vector. + ARTYPE *workl; // Original ARPACK internal vector. + ARTYPE *workd; // Original ARPACK internal vector. + ARTYPE *workv; // Original ARPACK internal vector. + ARTYPE *V; // Arnoldi basis / Schur vectors. + + + // a.3) Pure output variables. + + int nconv; // Number of "converged" Ritz values. + ARFLOAT *EigValI; // Imaginary part of eigenvalues (nonsymmetric problems). + ARTYPE *EigValR; // Eigenvalues (real part only if problem is nonsymmetric). + ARTYPE *EigVec; // Eigenvectors. + + + // b) Protected functions: + + // b.1) Memory control functions. + + bool OverV() { return (EigVec == &V[1]); } + // Indicates whether EigVec overrides V or no. + + virtual int ValSize() { return nev; } + // Provides the size of array EigVal. + // Redefined in ARrcNonSymStdEig. + + void ClearFirst(); + // Clears some boolean variables in order to define a entire new problem. + + void ClearBasis(); + // Clear some boolean variables in order to recalculate the arnoldi basis. + + void ClearMem(); + // Clears workspace. + + virtual void ValAllocate(); + // Creates arrays EigValR and EigValI. + // Redefined in ARrcNonSymStdEig. + + virtual void VecAllocate(bool newV = true); + // Creates array EigVec. + + virtual void WorkspaceAllocate(); + // Function that must be defined by a derived class. + // Redefined in ARrc[Sym|NonSym|Complex]StdEig. + + + // b.2) Functions that call the original ARPACK FORTRAN code. + + virtual void Aupp() { + throw ArpackError(ArpackError::NOT_IMPLEMENTED, "Aupp"); + } + // Interface to FORTRAN subroutines __AUPD. + // Must be defined by a derived class. + // Redefined in ARrc[Sym|NonSym|Complex]StdEig. + + void AuppError(); + // Handles errors occurred in function Aupp. + + virtual void Eupp() { + throw ArpackError(ArpackError::NOT_IMPLEMENTED, "Eupp"); + } + // Interface to FORTRAN subroutines __EUPD. + // Must be defined by a derived class. + // Redefined in ARrc[Sym|NonSym|Complex]Eig. + + void EuppError(); + // Handles errors occurred in function Eupp. + + + // b.3) Functions that check user defined parameters. + + int CheckN(int np); + // Does range checking on ncv. + + int CheckNcv(int ncvp); + // Forces ncv to conform to its ranges. + + virtual int CheckNev(int nevp); + // Does range checking on nev. + // Redefined in ARrcNonSymStdEig. + + int CheckMaxit(int maxitp); + // Forces maxit to be greater than zero. + + virtual std::string CheckWhich(const std::string& whichp); + // Determines if the value of variable "which" is valid. + // Redefined in ARrcSymStdEig. + + + // b.4) Functions that set internal variables. + + void Restart(); + + virtual void Prepare(); + // Defines internal variables and allocates working arrays. + + virtual void Copy(const ARrcStdEig& other); + // Makes a deep copy of "other" over "this" object. + // Old values are not deleted (this function is to be used + // by the copy constructor and the assignment operator only). + + public: + + // c) Public functions: + + // c.1) Function that stores user defined parameters. + + virtual void DefineParameters(int np, int nevp, const std::string& whichp="LM", + int ncvp=0, ARFLOAT tolp=0.0, int maxitp=0, + ARTYPE* residp=NULL, bool ishiftp=true); + // Set values of problem parameters (also called by constructors). + // Redefined in ARrcStdEig and ARrcGenEig. + + + // c.2) Functions that detect if output data is ready. + + bool ParametersDefined() { return PrepareOK; } + // Indicates if all internal variables and arrays were defined. + + bool ArnoldiBasisFound() { return BasisOK; } + // Indicates if an Arnoldi basis is available. + + bool EigenvaluesFound() { return ValuesOK; } + // Indicates if the requested eigenvalues are available. + + bool EigenvectorsFound() { return VectorsOK; } + // Indicates if the requested eigenvectors are available. + + bool SchurVectorsFound() { return SchurOK; } + // Indicates if the Schur vectors are available. + + + // c.3) Functions that provides access to internal variables' values. + + int ConvergedEigenvalues() { return nconv; } + // Provides the number of "converged" eigenvalues found so far. + + int GetMaxit() { return maxit; } + // Returns the maximum number of Arnoldi update iterations allowed. + + int GetIter(); + // Returns the actual number of Arnoldi iterations taken. + + ARFLOAT GetTol() { return tol; } + // Returns the stopping criterion. + + int GetN() { return n; } + // Returns the dimension of the problem. + + int GetNev() { return nev; } + // Returns the number of eigenvalues to be computed. + + int GetNcv() { return ncv; } + // Returns the number of Arnoldi vectors generated at each iteration.. + + const std::string& GetWhich() { return which; } + // Returns "which". + + ARTYPE GetShift() { return sigmaR; } + // Returns the shift (when in shift and invert mode). + + bool GetAutoShift() { return AutoShift; } + // Returns "AutoShift". + + int GetMode() { return mode; } + // Returns the type of problem (regular, shift and invert, etc). + + + // c.4) Functions that allow changes in problem parameters. + + void ChangeMaxit(int maxitp); + // Changes the maximum number of Arnoldi update iterations allowed. + + void ChangeTol(ARFLOAT tolp); + // Changes the stopping criterion. + + virtual void ChangeNev(int nevp); + // Changes the number of eigenvalues to be computed. + + virtual void ChangeNcv(int ncvp); + // Changes the number of Arnoldi vectors generated at each iteration.. + + virtual void ChangeWhich(const std::string& whichp); + // Changes "which". + + virtual void ChangeShift(ARTYPE sigmaRp); + // Turns the problem to shift-and-invert mode with shift defined by sigmaRp. + // Redefined in many derived classes. + + virtual void NoShift(); + // Turns the problem to regular mode. + // Redefined in ARrcGenEig. + + void InvertAutoShift(); + // Inverts "AutoShift". + + virtual void SetRegularMode() { NoShift(); } + // Turns problem to regular mode. + + virtual void SetShiftInvertMode(ARTYPE sigmaRp) { ChangeShift(sigmaRp); } + // Turns problem to regular mode. + + // c.5) Trace functions. + + virtual void Trace() { + throw ArpackError(ArpackError::NOT_IMPLEMENTED, "Trace"); + } + // Turns on trace mode. + // Must be defined by a derived class. + // Redefined in ARrc[Sym|NonSym|Complex]StdEig. + + void NoTrace() { TraceOff(); } + // Turns off trace mode. + + + // c.6) Functions that permit step by step execution of ARPACK. + + int GetNp() { return iparam[8]; } + // Returns the number of shifts that must be supplied after a call to + // TakeStep() when shifts are provided by the user (AutoShift = false). + + int GetIdo() { return ido; } + // Indicates the type of operation the user must perform between two + // successive calls to function TakeStep(). + // ido = -1: compute y = OP*x, where GetVector() gives a pointer to the + // vector x, and PutVector() indicates where to store y. + // ido = 1: compute y = OP*x, where GetVector() gives a pointer to the + // vector x, and PutVector() indicates where to store y. + // When solving generalized problems, a pointer to the product + // B*x is also available by using GetProd(). + // ido = 2: compute y = B*x, where GetVector() gives a pointer to the + // vector x, and PutVector() indicates where to store y. + // ido = 3: compute shifts, where PutVector() indicates where to store them. + + virtual ARTYPE* GetVector(); + // When ido = -1, 1 or 2 and the user must perform a product in the form + // y <- M*x, this function indicates where x is stored. When ido = 3, this + // function indicates where the eigenvalues of the current Hessenberg + // matrix are located. + + ARTYPE* GetProd(); + // When ido = 1 and the user must perform a product in the form + // y <- M*B*x, this function indicates where B*x is stored. + + virtual ARTYPE* PutVector(); + // When ido = -1, 1 or 2 and the user must perform a product in the form + // y <- M*x, this function indicates where to store y. When ido = 3, this + // function indicates where to store the shifts. + // Redefined in ARrcSymStdEig. + + virtual int TakeStep(); + // Calls Aupp once if there is no Arnoldi basis available. + + + // c.7) Functions that perform final calculations. + + virtual int FindArnoldiBasis(); + // Determines the Arnoldi basis related to the given problem. + // This function has no meaning for this class. It is maintained + // here for compatibility with all derived classes. + // Redefined in ARStdEig, ARGenEig and ARSymGenEig. + + virtual int FindEigenvalues(); + // Determines nev approximated eigenvalues of the given eigen-problem. + // Redefined in ARNonSymGenEig. + + virtual int FindEigenvectors(bool schurp = false); + // Determines nev approximated eigenvectors of the given eigen-problem + // Optionally also determines nev Schur vectors that span the desired + // invariant subspace. + // Redefined in ARNonSymGenEig. + + virtual int FindSchurVectors(); + // Determines nev Schur vectors that span the desired invariant subspace. + // Redefined in ARrcSymStdEig and ARNonSymGenEig. + + + // c.8) Function that perform calculations using user supplied data structure. + + virtual int Eigenvectors(ARTYPE* &EigVecp, bool ischur = false); + // Overrides array EigVecp sequentially with the eigenvectors of the + // given eigen-problem. Also calculates Schur vectors if requested. + + + // c.9) Functions that return elements of vectors and matrices. + + ARTYPE ArnoldiBasisVector(int i, int j); + // Furnishes element j of the i-eth Arnoldi basis vector. + + ARTYPE SchurVector(int i, int j); + // Furnishes element j of the i-eth Schur vector. + + ARTYPE ResidualVector(int i); + // Furnishes element j of the residual vector. + + + // c.10) Functions that provide raw access to internal vectors and matrices. + + ARTYPE* RawArnoldiBasisVectors(); + // Provides raw access to Arnoldi basis vectors elements. + + ARTYPE* RawArnoldiBasisVector(int i); + // Provides raw access to Arnoldi basis vector i. + + ARTYPE* RawEigenvalues(); + // Provides raw access to eigenvalues. + + ARTYPE* RawEigenvectors(); + // Provides raw access to eigenvectors elements. + + ARTYPE* RawEigenvector(int i); + // Provides raw access to eigenvector i. + + ARTYPE* RawSchurVectors(); + // Provides raw access to Schur vectors elements. + + ARTYPE* RawSchurVector(int i); + // Provides raw access to Schur vector i. + + ARTYPE* RawResidualVector(); + // Provides raw access to residual vector elements. + + + // c.11) Functions that use STL vector class. + +#ifdef STL_VECTOR_H + + vector* StlArnoldiBasisVectors(); + // Returns a copy of the Arnoldi basis in a single STL vector. + + vector* StlArnoldiBasisVector(int i); + // Returns the i-th Arnoldi basis vector in a STL vector. + + vector* StlEigenvectors(bool ischur = false); + // Calculates the eigenvectors and stores them sequentially in a + // single STL vector. Also calculates Schur vectors if requested. + + vector* StlSchurVectors(); + // Returns a copy of the Schur vectors in a single STL vector. + + vector* StlSchurVector(int i); + // Returns the i-th Schur vector in a STL vector. + + vector* StlResidualVector(); + // Returns the residual vector in a STL vector. + +#endif // #ifdef STL_VECTOR_H. + + + // c.12) Constructors and destructor. + + ARrcStdEig(); + // Short constructor that does almost nothing. + + ARrcStdEig(const ARrcStdEig& other) { Copy(other); } + // Copy constructor. + + virtual ~ARrcStdEig() { ClearMem(); } + // Very simple destructor. + + // d) Operators: + + ARrcStdEig& operator=(const ARrcStdEig& other); + // Assignment operator. + +}; // class ARrcStdEig. + + +// ------------------------------------------------------------------------ // +// ARrcStdEig member functions definition. // +// ------------------------------------------------------------------------ // + + +template +inline void ARrcStdEig::ClearFirst() +{ + + PrepareOK = newVal = newVec = newRes = false; + +} // ClearFirst. + + +template +inline void ARrcStdEig::ClearBasis() +{ + + BasisOK = ValuesOK = VectorsOK = SchurOK = false; + +} // ClearBasis. + + +template +void ARrcStdEig::ClearMem() +{ + + // Deleting working arrays. + + if (workl) delete[] workl; + if (workd) delete[] workd; + if (workv) delete[] workv; + if (rwork) delete[] rwork; + if (V) delete[] V; + + workl = NULL; + workd = NULL; + workv = NULL; + rwork = NULL; + V = NULL; + + // Deleting input and output arrays. + + if (newRes) { + delete[] resid; + newRes = false; + resid = NULL; // Salwen. Mar 3, 2000. + } + + if (newVal) { + delete[] EigValR; + delete[] EigValI; + newVal = false; + } + EigValR=NULL; + EigValI=NULL; + + if (newVec) { + delete[] EigVec; + newVec = false; + } + EigVec=NULL; + + // Adjusting boolean variables. + + ClearFirst(); + +} // ClearMem. + + +template +inline void ARrcStdEig::ValAllocate() +{ + + if (EigValR == NULL) { // Creating a new array EigValR. + EigValR = new ARTYPE[ValSize()]; + newVal = true; + } + +} // ValAllocate. + +template +inline void ARrcStdEig::VecAllocate(bool newV) +{ + + if (EigVec == NULL) { + if (newV) { // Creating a new array EigVec. + EigVec = new ARTYPE[ValSize()*n]; + newVec = true; + } + else { // Using V to store EigVec. + EigVec = &V[1]; + } + } + +} // VecAllocate. + + +template +void ARrcStdEig::WorkspaceAllocate() +{ + + lworkl = 0; + lworkv = 0; + lrwork = 0; + +} // WorkspaceAllocate. + + +template +void ARrcStdEig::AuppError() +{ + + switch (info) { + case 0: + return; + case -8: + throw ArpackError(ArpackError::LAPACK_ERROR, "Aupp"); + case -9: + throw ArpackError(ArpackError::START_RESID_ZERO, "Aupp"); + case -9999: + throw ArpackError(ArpackError::ARNOLDI_NOT_BUILD, "Aupp"); + case 1: + ArpackError(ArpackError::MAX_ITERATIONS, "Aupp"); + return; + case 3: + ArpackError(ArpackError::NO_SHIFTS_APPLIED, "Aupp"); + return; + default : + throw ArpackError(ArpackError::AUPP_ERROR, "Aupp"); + } + +} // AuppError. + + +template +void ARrcStdEig::EuppError() +{ + + switch (info) { + case 0: + return; + case -8: + case -9: + throw ArpackError(ArpackError::LAPACK_ERROR, "Eupp"); + case -14: + throw ArpackError(ArpackError::NOT_ACCURATE_EIG, "Eupp"); + case 1: + throw ArpackError(ArpackError::REORDERING_ERROR, "Eupp"); + default : + throw ArpackError(ArpackError::EUPP_ERROR, "Eupp"); + } + +} // EuppError. + + +template +inline int ARrcStdEig::CheckN(int np) +{ + + if (np < 2) { + throw ArpackError(ArpackError::N_SMALLER_THAN_2); + } + return np; + +} // CheckN. + + +template +inline int ARrcStdEig::CheckNcv(int ncvp) +{ + + // Adjusting ncv if ncv <= nev or ncv > n. + + if (ncvp < nev+1) { + if (ncvp) ArpackError::Set(ArpackError::NCV_OUT_OF_BOUNDS); + return ((2*nev+1)>n)?n:(2*nev+1); + } + else if (ncvp > n) { + ArpackError::Set(ArpackError::NCV_OUT_OF_BOUNDS); + return n; + } + else { + return ncvp; + } + +} // CheckNcv. + + +template +inline int ARrcStdEig::CheckNev(int nevp) +{ + + if ((nevp<1)||(nevp>=n)) { + throw ArpackError(ArpackError::NEV_OUT_OF_BOUNDS); + } + return nevp; + +} // CheckNev. + + +template +inline int ARrcStdEig::CheckMaxit(int maxitp) +{ + + if (maxitp >= 1) return maxitp; + if (maxitp < 0) ArpackError::Set(ArpackError::MAXIT_NON_POSITIVE); + return 100*nev; + +} // CheckMaxit. + +template +std::string ARrcStdEig::CheckWhich(const std::string& whichp) +{ + + switch (whichp[0]) { // The first ought to be S or L. + case 'S': + case 'L': + switch (whichp[1]) { // The second must be M, R or I. + case 'M': + case 'R': + case 'I': + return whichp; + } + default : + throw ArpackError(ArpackError::WHICH_UNDEFINED); + } + +} // CheckWhich. + + +template +void ARrcStdEig::Restart() +{ + + nconv=0; // No eigenvalues found yet. + ido =0; // First call to AUPP. + iparam[1]=(int)AutoShift; // Shift strategy used. + iparam[3]=maxit; // Maximum number of Arnoldi iterations allowed. + iparam[4]=1; // Blocksize must be 1. + info =(int)(!newRes); // Starting vector used. + ClearBasis(); + +} // Restart. + + +template +void ARrcStdEig::Prepare() +{ + + // Deleting old stuff. + + ClearMem(); + + // Defining internal variables. + + try { + + if (resid == NULL) { // Using a random starting vector. + resid = new ARTYPE[n]; + newRes = true; + } + + // Setting dimensions of working arrays. + + workd = new ARTYPE[3*n+1]; + V = new ARTYPE[n*ncv+1]; + WorkspaceAllocate(); + + } + catch (ArpackError) { // Returning from here if an error has occurred. + ArpackError(ArpackError::CANNOT_PREPARE, "Prepare"); + return; + } + + Restart(); + + // That's all. + + PrepareOK = true; + +} // Prepare. + + +template +void ARrcStdEig::Copy(const ARrcStdEig& other) +{ + + // Defining local variables. + + int i; + + // Copying variables that belong to fundamental types. + + n = other.n; + nev = other.nev; + ncv = other.ncv; + maxit = other.maxit; + which = other.which; + tol = other.tol; + sigmaI = other.sigmaI; + sigmaR = other.sigmaR; + rvec = other.rvec; + newRes = other.newRes; + newVal = other.newVal; + newVec = other.newVec; + PrepareOK = other.PrepareOK; + BasisOK = other.BasisOK; + ValuesOK = other.ValuesOK; + VectorsOK = other.VectorsOK; + SchurOK = other.SchurOK; + AutoShift = other.AutoShift; + bmat = other.bmat; + HowMny = other.HowMny; + ido = other.ido; + info = other.info; + mode = other.mode; + nconv = other.nconv; + + // Copying arrays with static dimension. + + for (i=0; i<12; i++) iparam[i] = other.iparam[i]; + for (i=0; i<15; i++) ipntr[i] = other.ipntr[i]; + + // Returning from here if "other" was not initialized. + + if (!PrepareOK) return; + + // Copying dynamic variables. + + workd = new ARTYPE[3*n+1]; // workd. + copy(3*n+1,other.workd,1,workd,1); + + V = new ARTYPE[n*ncv+1]; // V. + copy(n*ncv+1,other.V,1,V,1); + + if (newRes) { // resid. + resid = new ARTYPE[n]; + copy(n,other.resid,1,resid,1); + } + else { + resid = other.resid; + } + + if (newVec) { // EigVec. + EigVec = new ARTYPE[ValSize()*n]; + copy(ValSize()*n,other.EigVec,1,EigVec,1); + } + else if (other.EigVec == (&other.V[1])) { + EigVec = &V[1]; + } + else { + EigVec = other.EigVec; + } + + if (newVal) { // EigValR and EigValI. + EigValR = new ARTYPE[ValSize()]; + copy(ValSize(),other.EigValR,1,EigValR,1); + if (other.EigValI != NULL) { + EigValI = new ARFLOAT[ValSize()]; + copy(ValSize(),other.EigValI,1,EigValI,1); + } + else { + EigValI = NULL; + } + } + else { + EigValR = other.EigValR; + EigValI = other.EigValI; + } + + WorkspaceAllocate(); // lworkl, workl, workv and rwork. + if (lworkl) copy(lworkl+1,other.workl,1,workl,1); + if (lworkv) copy(lworkv+1,other.workv,1,workv,1); + if (lrwork) copy(lrwork+1,other.rwork,1,rwork,1); + +} // Copy. + + +template +void ARrcStdEig:: +DefineParameters(int np, int nevp, const std::string& whichp, int ncvp, + ARFLOAT tolp, int maxitp, ARTYPE* residp, bool ishiftp) + +{ + + // Setting user defined parameters. + + try { + n = CheckN(np); + nev = ARrcStdEig::CheckNev(nevp); + ncv = ARrcStdEig::CheckNcv(ncvp); + which = ARrcStdEig::CheckWhich(whichp); + maxit = ARrcStdEig::CheckMaxit(maxitp); + tol = tolp; + resid = residp; + AutoShift = ishiftp; + } + + // Returning from here if an error has occurred. + + catch (ArpackError) { + ArpackError(ArpackError::PARAMETER_ERROR, "DefineParameter"); + return; + } + + // Setting internal variables. + + ClearFirst(); + Prepare(); + +} // DefineParameters. + + +template +int ARrcStdEig::GetIter() +{ + + if (BasisOK || ValuesOK || VectorsOK || SchurOK) { + return iparam[3]; + } + else { + return 0; + } + +} // GetIter. + + +template +inline void ARrcStdEig::ChangeMaxit(int maxitp) +{ + + maxit = CheckMaxit(maxitp); + Restart(); + +} // ChangeMaxit. + + +template +inline void ARrcStdEig::ChangeTol(ARFLOAT tolp) +{ + + if (tolp < tol) Restart(); + tol = tolp; + +} // ChangeTol. + + +template +void ARrcStdEig::ChangeNev(int nevp) +{ + + try { + nev = CheckNev(nevp); + ncv = CheckNcv(ncv); + } + catch (ArpackError) { return; } + if (PrepareOK) Prepare(); + +} // ChangeNev. + + +template +inline void ARrcStdEig::ChangeNcv(int ncvp) +{ + + ncv = CheckNcv(ncvp); + if (PrepareOK) Prepare(); + +} // ChangeNcv. + + +template +void ARrcStdEig::ChangeWhich(const std::string& whichp) +{ + + try { which = CheckWhich(whichp); } + catch (ArpackError) { return; } + Restart(); + +} // ChangeWhich. + + +template +inline void ARrcStdEig::ChangeShift(ARTYPE sigmaRp) +{ + + sigmaR = sigmaRp; + sigmaI = 0.0; + mode = 3; + iparam[7] = mode; + Restart(); + +} // ChangeShift. + + +template +inline void ARrcStdEig::NoShift() +{ + + sigmaR = (ARTYPE)0; + sigmaI = 0.0; + mode = 1; + iparam[7] = mode; + Restart(); + +} // NoShift. + + +template +void ARrcStdEig::InvertAutoShift() +{ + + AutoShift = !AutoShift; + Restart(); + +} // InvertAutoShift. + + +template +ARTYPE* ARrcStdEig::GetVector() +{ + + switch (ido) { + case -1: + case 1: + case 2: + return &workd[ipntr[1]]; + case 3: + return &workl[ipntr[6]]; + default: + throw ArpackError(ArpackError::CANNOT_GET_VECTOR, "GetVector"); + } + +} // GetVector. + + +template +ARTYPE* ARrcStdEig::GetProd() +{ + + if (ido != 1) { + throw ArpackError(ArpackError::CANNOT_GET_PROD, "GetProd"); + } + return &workd[ipntr[3]]; + +} // GetProd. + + +template +ARTYPE* ARrcStdEig::PutVector() +{ + + switch (ido) { + case -1: + case 1: + case 2: + return &workd[ipntr[2]]; + case 3: + return &workl[ipntr[14]]; + default: + throw ArpackError(ArpackError::CANNOT_PUT_VECTOR, "PutVector"); + } + +} // PutVector. + + +template +int ARrcStdEig::TakeStep() +{ + + // Requiring the definition of all internal variables. + + if (!PrepareOK) { + + throw ArpackError(ArpackError::PREPARE_NOT_OK, "TakeStep"); + + } + else if (!BasisOK) { + + // Taking a step if the Arnoldi basis is not available. + + Aupp(); + + // Checking if convergence was obtained. + + if (ido==99) { + nconv = iparam[5]; + AuppError(); + if (info >= 0) BasisOK = true; + } + } + + return ido; + +} // TakeStep. + + +template +inline int ARrcStdEig::FindArnoldiBasis() +{ + + if (!BasisOK) { + throw ArpackError(ArpackError::CANNOT_FIND_BASIS, "FindArnoldiBasis"); + } + return nconv; + +} // FindArnoldiBasis. + + +template +int ARrcStdEig::FindEigenvalues() +{ + + // Determining eigenvalues if they are not available. + + if (!ValuesOK) { + try { + ValAllocate(); + nconv = FindArnoldiBasis(); + rvec = false; + HowMny = 'A'; + if (nconv>0) { + Eupp(); + EuppError(); + } + } + catch (ArpackError) { + ArpackError(ArpackError::CANNOT_FIND_VALUES, "FindEigenvalues"); + return 0; + } + if (newVal) ValuesOK = true; + } + return nconv; + +} // FindEigenvalues. + + +template +int ARrcStdEig::FindEigenvectors(bool schurp) +{ + + // Determining eigenvectors if they are not available. + + if (!VectorsOK) { + try { + ValAllocate(); + VecAllocate(schurp); + nconv = FindArnoldiBasis(); + rvec = true; + HowMny = 'A'; + if (nconv>0) { + Eupp(); + EuppError(); + } + } + catch (ArpackError) { + ArpackError(ArpackError::CANNOT_FIND_VECTORS, "FindEigenvectors"); + return 0; + } + BasisOK = false; + if (newVal) ValuesOK = true; + if (newVec || OverV()) VectorsOK = true; + if (!OverV()) SchurOK = true; + } + return nconv; + +} // FindEigenvectors. + + +template +int ARrcStdEig::FindSchurVectors() +{ + + // Determining Schur vectors if they are not available. + + if (!SchurOK) { + try { + ValAllocate(); + nconv = FindArnoldiBasis(); + rvec = true; + HowMny = 'P'; + if (nconv>0) { + Eupp(); + EuppError(); + } + } + catch (ArpackError) { + ArpackError(ArpackError::CANNOT_FIND_SCHUR, "FindSchurVectors"); + return 0; + } + BasisOK = false; + if (newVal) ValuesOK = true; + SchurOK =true; + } + return nconv; + +} // FindSchurVectors. + + +template +int ARrcStdEig:: +Eigenvectors(ARTYPE* &EigVecp, bool ischur) +{ + + // Overriding EigVecp with the converged eigenvectors. + + if (VectorsOK) { // Eigenvectors are available. + if ((EigVecp == NULL) && (newVec)) { // Moving eigenvectors. + EigVecp = EigVec; + EigVec = NULL; + newVec = false; + VectorsOK = false; + } + else { // Copying eigenvectors. + if (EigVecp == NULL) { + try { EigVecp = new ARTYPE[ValSize()*n]; } + catch (ArpackError) { return 0; } + } + copy(ValSize()*n,EigVec,1,EigVecp,1); + } + } + else { // Eigenvectors are not available. + if (newVec) { + delete[] EigVec; + newVec = false; + } + if (EigVecp == NULL) { + try { EigVecp = new ARTYPE[ValSize()*n]; } + catch (ArpackError) { return 0; } + } + EigVec = EigVecp; + nconv = FindEigenvectors(ischur); + EigVec = NULL; + } + return nconv; + +} // Eigenvectors(EigVecp, ischur). + + +template +inline ARTYPE ARrcStdEig::ArnoldiBasisVector(int i, int j) +{ + + // Returning element j of Arnoldi basis vector i. + + if (!BasisOK) { + throw ArpackError(ArpackError::BASIS_NOT_OK, "ArnoldiBasisVector(i,j)"); + } + else if ((i>=ncv)||(i<0)||(j>=n)||(j<0)) { + throw ArpackError(ArpackError::RANGE_ERROR,"ArnoldiBasisVector(i,j)"); + } + return V[i*n+j+1]; + +} // ArnoldiBasisVector(i,j). + + +template +inline ARTYPE ARrcStdEig::SchurVector(int i, int j) +{ + + // Returning element j of Schur vector i. + + if (!SchurOK) { + throw ArpackError(ArpackError::SCHUR_NOT_OK, "SchurVector(i,j)"); + } + else if ((i>=nconv)||(i<0)||(j>=n)||(j<0)) { + throw ArpackError(ArpackError::RANGE_ERROR, "SchurVector(i,j)"); + } + return V[i*n+j+1]; + +} // SchurVector(i,j). + + +template +inline ARTYPE ARrcStdEig::ResidualVector(int i) +{ + + // Returning element i of the residual vector. + + if ((!newRes)||(!(BasisOK||ValuesOK||VectorsOK||SchurOK))) { + throw ArpackError(ArpackError::RESID_NOT_OK, "ResidualVector(i)"); + } + else if ((i>=n)||(i<0)) { + throw ArpackError(ArpackError::RANGE_ERROR, "ResidualVector(i)"); + } + return resid[i]; + +} // ResidualVector(i). + + +template +inline ARTYPE* ARrcStdEig::RawArnoldiBasisVectors() +{ + + // Returning a constant pointer to Arnoldi basis. + + if (!BasisOK) { + throw ArpackError(ArpackError::BASIS_NOT_OK, "RawArnoldiBasisVectors"); + } + return &V[1]; + +} // RawArnoldiBasisVectors. + + +template +inline ARTYPE* ARrcStdEig::RawArnoldiBasisVector(int i) +{ + + // Returning a constant pointer to Arnoldi basis vector i. + + if (!BasisOK) { + throw ArpackError(ArpackError::BASIS_NOT_OK, "RawArnoldiBasisVector(i)"); + } + else if ((i>=ncv)||(i<0)) { + throw ArpackError(ArpackError::RANGE_ERROR,"RawArnoldiBasisVector(i)"); + } + return &V[i*n+1]; + +} // RawArnoldiBasisVector(i). + + +template +inline ARTYPE* ARrcStdEig::RawEigenvalues() +{ + + if (!ValuesOK) { + throw ArpackError(ArpackError::VALUES_NOT_OK, "RawEigenvalues"); + } + return EigValR; + +} // RawEigenvalues. + + +template +inline ARTYPE* ARrcStdEig::RawEigenvectors() +{ + + if (!VectorsOK) { + throw ArpackError(ArpackError::VECTORS_NOT_OK, "RawEigenvectors"); + } + return EigVec; + +} // RawEigenvectors. + + +template +inline ARTYPE* ARrcStdEig::RawEigenvector(int i) +{ + + // Returning a constant pointer to eigenvector i. + + if (!VectorsOK) { + throw ArpackError(ArpackError::VECTORS_NOT_OK, "RawEigenvector(i)"); + } + else if ((i>=ValSize())||(i<0)) { + throw ArpackError(ArpackError::RANGE_ERROR, "RawEigenvector(i)"); + } + return &EigVec[i*n]; + +} // RawEigenvector(i). + + +template +inline ARTYPE* ARrcStdEig::RawSchurVectors() +{ + + if (!SchurOK) { + throw ArpackError(ArpackError::SCHUR_NOT_OK, "RawSchurVectors"); + } + return &V[1]; + +} // RawSchurVectors. + + +template +inline ARTYPE* ARrcStdEig::RawSchurVector(int i) +{ + + // Returning a constant pointer to Schur vector i. + + if (!SchurOK) { + throw ArpackError(ArpackError::SCHUR_NOT_OK, "RawSchurVector(i)"); + } + else if ((i>=nev)||(i<0)) { + throw ArpackError(ArpackError::RANGE_ERROR, "RawSchurVector(i)"); + } + return &V[i*n+1]; + +} // RawSchurVector(i). + + +template +inline ARTYPE* ARrcStdEig::RawResidualVector() +{ + + if (!newRes) { + throw ArpackError(ArpackError::RESID_NOT_OK, "RawResidualVector"); + } + return resid; + +} // RawResidualVector. + + +#ifdef STL_VECTOR_H // Defining some functions that use STL vector class. + +template +inline vector* ARrcStdEig::StlArnoldiBasisVectors() +{ + + // Returning the Arnoldi basis in a single STL vector. + + vector* StlBasis; + + if (!BasisOK) { + nconv = FindArnoldiBasis(); + } + try { + StlBasis = new vector(&V[1], &V[n*ncv+1]); + } + catch (ArpackError) { return NULL; } + return StlBasis; + +} // StlArnoldiBasisVectors. + + +template +inline vector* ARrcStdEig::StlArnoldiBasisVector(int i) +{ + + // Returning the i-th Arnoldi basis vector in a STL vector. + + vector* StlBasis; + + if (!BasisOK) { + throw ArpackError(ArpackError::BASIS_NOT_OK, "StlArnoldiBasisVector(i)"); + } + else if ((i>=ncv)||(i<0)) { + throw ArpackError(ArpackError::RANGE_ERROR,"StlArnoldiBasisVector(i)"); + } + try { + StlBasis = new vector(&V[i*n+1], &V[(i+1)*n+1]); + } + catch (ArpackError) { return NULL; } + return StlBasis; + +} // StlArnoldiBasisVector(i). + + +template +inline vector* ARrcStdEig::StlEigenvectors(bool ischur) +{ + + // Returning the eigenvector in a single STL vector. + + vector* StlEigVec; + ARTYPE* VecPtr; + + try { StlEigVec = new vector(ValSize()*n); } + catch (ArpackError) { return NULL; } + VecPtr = StlEigVec->begin(); + nconv = Eigenvectors(VecPtr, ischur); + return StlEigVec; + +} // StlEigenvectors. + + +template +inline vector* ARrcStdEig::StlSchurVectors() +{ + + vector* StlSchurVec; + + if (!SchurOK) { + nconv = FindSchurVectors(); + } + try { + StlSchurVec = new vector(&V[1], &V[nev*n+1]); + } + catch (ArpackError) { return NULL; } + return StlSchurVec; + +} // StlSchurVectors. + + +template +inline vector* ARrcStdEig::StlSchurVector(int i) +{ + + // Returning the i-th Schur vector in a STL vector. + + vector* StlSchurVec; + + if (!SchurOK) { + throw ArpackError(ArpackError::SCHUR_NOT_OK, "StlSchurVector(i)"); + } + else if ((i>=nev)||(i<0)) { + throw ArpackError(ArpackError::RANGE_ERROR, "StlSchurVector(i)"); + } + try { + StlSchurVec = new vector(&V[i*n+1], &V[(i+1)*n+1]); + } + catch (ArpackError) { return NULL; } + return StlSchurVec; + +} // StlSchurVector(i). + + +template +inline vector* ARrcStdEig::StlResidualVector() +{ + + // Returning the residual vector in a STL vector. + + vector* StlResid; + + if (!newRes) { + throw ArpackError(ArpackError::RESID_NOT_OK, "StlResidualVector"); + } + try { + StlResid = new vector(resid, &resid[n]); + } + catch (ArpackError) { return NULL; } + return StlResid; + +} // StlResidualVector. + +#endif // #ifdef STL_VECTOR_H. + + +template +inline ARrcStdEig::ARrcStdEig() +{ + + resid = NULL; + rwork = NULL; + workl = NULL; + workd = NULL; + workv = NULL; + V = NULL; + EigValR = NULL; + EigValI = NULL; + EigVec = NULL; + bmat = 'I'; // This is a standard problem. + ClearFirst(); + NoShift(); + NoTrace(); + +} // Short constructor. + + +template +ARrcStdEig& ARrcStdEig:: +operator=(const ARrcStdEig& other) +{ + + if (this != &other) { // Stroustrup suggestion. + ClearMem(); + Copy(other); + } + return *this; + +} // operator=. + + +#endif // ARRSEIG_H + diff --git a/external/arpack++/include/arrsnsym.h b/external/arpack++/include/arrsnsym.h new file mode 100644 index 000000000..106b10df0 --- /dev/null +++ b/external/arpack++/include/arrsnsym.h @@ -0,0 +1,861 @@ +/* + ARPACK++ v1.2 2/20/2000 + c++ interface to ARPACK code. + + MODULE ARRSNSym.h. + Arpack++ class ARrcNonSymStdEig definition. + + ARPACK Authors + Richard Lehoucq + Danny Sorensen + Chao Yang + Dept. of Computational & Applied Mathematics + Rice University + Houston, Texas +*/ + +#ifndef ARRSNSYM_H +#define ARRSNSYM_H + +#include + +#include "arch.h" +#include "arerror.h" +#include "debug.h" +#include "arrseig.h" +#include "naupp.h" +#include "neupp.h" + + +template +class ARrcNonSymStdEig: public virtual ARrcStdEig { + + protected: + + // a) Protected functions: + + // a.1) Memory control functions. + + int ValSize() { return this->nev+1; } + // Provides the size of array EigVal. + + void ValAllocate(); + // Creates arrays EigValR and EigValI. + + void WorkspaceAllocate(); + // Allocates workspace for nonsymmetric problems. + + + // a.2) Functions that handle original FORTRAN ARPACK code. + + void Aupp(); + // Interface to FORTRAN subroutines SNAUPD and DNAUPD. + + void Eupp(); + // Interface to FORTRAN subroutines SNEUPD and DNEUPD. + + + // a.3) Functions that check user defined parameters. + + int CheckNev(int nevp); + // Does Range checking on nev. + + + // a.4) Auxiliary functions required when using STL vector class. + + bool ConjEigVec(int i); + // Indicates if EigVec[i] is the second eigenvector in + // a complex conjugate pair. + +#ifdef ARCOMP_H +#ifdef STL_VECTOR_H + + vector >* GenComplex(vector* RealPart, + vector* ImagPart, + bool conj = false); + // Generates a complex vector Complex = RealPart + I*ImagPart + // (or Complex = RealPart - I*ImagPart, if conj = true). + + vector >* GenComplex(int dim, ARFLOAT* RealPart, + ARFLOAT* ImagPart, + bool conj = false); + // Generates a complex vector Complex = RealPart + I*ImagPart + // (or Complex = RealPart - I*ImagPart, if conj = true). dim + // is the length of RealPart and ImagPart. + + vector >* GenComplex(int dim, ARFLOAT* RealPart); + // Generates a complex vector from a real vector. dim is the + // length of RealPart. + +#endif // STL_VECTOR_H. +#endif // ARCOMP_H. + + public: + + // b) Public functions: + + // b.1) Trace functions. + + void Trace(const int digit = -5, const int getv0 = 0, const int aupd = 1, + const int aup2 = 0, const int aitr = 0, const int eigt = 0, + const int apps = 0, const int gets = 0, const int eupd = 0) + { + nTraceOn(digit, getv0, aupd, aup2, aitr, eigt, apps, gets, eupd); + } + // Turns on trace mode. + + + // b.2) Functions that permit step by step execution of ARPACK. + + ARFLOAT* GetVectorImag(); + // When ido = 3, this function indicates where the imaginary part + // of the eigenvalues of the current Hessenberg matrix are located. + + + // b.3) Functions that perform all calculations in one step. + + int Eigenvalues(ARFLOAT* &EigValRp, ARFLOAT* &EigValIp, + bool ivec = false, bool ischur = false); + // Overrides arrays EigValRp with the real part and EigValIp + // with the imaginary part of the eigenvalues of the problem. + // Calculates eigenvectors and Schur vectors if requested. + + int EigenValVectors(ARFLOAT* &EigVecp, ARFLOAT* &EigValRp, + ARFLOAT* &EigValIp, bool ischur = false); + // Overrides array EigVecp sequentially with the eigenvectors of the + // given eigen-problem. Also stores the eigenvalues in EigValRp and + // EigValIp. Calculates Schur vectors if requested. + + + // b.4) Functions that return elements of vectors and matrices. + +#ifdef ARCOMP_H + arcomplex Eigenvalue(int i); + // Furnishes i-eth eigenvalue. +#endif // ARCOMP_H. + + ARFLOAT EigenvalueReal(int i); + // Provides the real part of the i-eth eigenvalue. + + ARFLOAT EigenvalueImag(int i); + // Provides the imaginary part of the i-eth eigenvalue. + +#ifdef ARCOMP_H + arcomplex Eigenvector(int i, int j); + // Furnishes element j of the i-eth eigenvector. +#endif // ARCOMP_H. + + ARFLOAT EigenvectorReal(int i, int j); + // Provides the real part of element j of the i-eth eigenvector. + + ARFLOAT EigenvectorImag(int i, int j); + // Provides the imaginary part of element j of the i-eth eigenvector. + + + // b.5) Functions that provide raw access to internal vectors and matrices. + + ARFLOAT* RawEigenvaluesImag(); + // Provides raw access to the imaginary part of eigenvalues. + + + // b.6) Functions that use STL vector class. + +#ifdef STL_VECTOR_H + +#ifdef ARCOMP_H + vector >* StlEigenvalues(bool ivec = false, + bool ischur = false); + // Calculates the eigenvalues and stores them in a single STL vector. + // Also calculates eigenvectors and Schur vectors if requested. +#endif // ARCOMP_H. + + vector* StlEigenvaluesReal(); + // Returns the real part of the eigenvalues. + + vector* StlEigenvaluesImag(); + // Returns the imaginary part of the eigenvalues. + +#ifdef ARCOMP_H + vector >* StlEigenvector(int i); + // Returns the i-th eigenvector. +#endif // ARCOMP_H. + + vector* StlEigenvectorReal(int i); + // Returns the real part of the i-th eigenvector. + + vector* StlEigenvectorImag(int i); + // Returns the imaginary part of the i-th eigenvector. + +#endif // STL_VECTOR_H. + + + // b.7) Constructors and destructor. + + ARrcNonSymStdEig() { } + // Short constructor. + + ARrcNonSymStdEig(int np, int nevp, const std::string& whichp = "LM", int ncvp = 0, + ARFLOAT tolp = 0.0, int maxitp = 0, ARFLOAT* residp = NULL, + bool ishiftp = true); + // Long constructor (regular mode). + + ARrcNonSymStdEig(int np, int nevp, ARFLOAT sigma, const std::string& whichp = "LM", + int ncvp = 0, ARFLOAT tolp = 0.0, int maxitp = 0, + ARFLOAT* residp = NULL, bool ishiftp = true); + // Long constructor (shift and invert mode). + + ARrcNonSymStdEig(const ARrcNonSymStdEig& other) { Copy(other); } + // Copy constructor. + + virtual ~ARrcNonSymStdEig() { } + // Destructor. + + // c) Operators. + + ARrcNonSymStdEig& operator=(const ARrcNonSymStdEig& other); + // Assignment operator. + +}; // class ARrcNonSymStdEig. + + +// ------------------------------------------------------------------------ // +// ARrcNonSymStdEig member functions definition. // +// ------------------------------------------------------------------------ // + + +template +inline void ARrcNonSymStdEig::ValAllocate() +{ + + if (this->EigValR == NULL) { + this->EigValR = new ARFLOAT[ValSize()]; + this->EigValI = new ARFLOAT[ValSize()]; + this->newVal = true; + } + +} // ValAllocate. + + +template +inline void ARrcNonSymStdEig::WorkspaceAllocate() +{ + + this->lworkl = 3*this->ncv*(this->ncv+2); + this->lworkv = 3*this->ncv; + this->lrwork = 0; + this->workl = new ARFLOAT[this->lworkl+1]; + this->workv = new ARFLOAT[this->lworkv+1]; + +} // WorkspaceAllocate. + + +template +inline void ARrcNonSymStdEig::Aupp() +{ + + naupp(this->ido,this-> bmat, this->n, this->which, this->nev, this->tol, this->resid, this->ncv, this->V, this->n, + this->iparam, this->ipntr, this->workd, this->workl, this->lworkl, this->info); + +} // Aupp. + + +template +inline void ARrcNonSymStdEig::Eupp() +{ + + neupp(this->rvec, this->HowMny, this->EigValR, this->EigValI, this->EigVec, this->n, this->sigmaR, + this->sigmaI, this->workv, this->bmat, this->n, this->which, this->nev, this->tol, this->resid, this->ncv, this->V, + this->n, this->iparam, this->ipntr, this->workd, this->workl, this->lworkl, this->info); + +} // Eupp. + + +template +inline int ARrcNonSymStdEig::CheckNev(int nevp) +{ + std::cout << nevp << "ddddd22g\n";fflush(stdout); + if ((nevp<=1)||(nevp>=(this->n-1))) { // nev must satisfy 1 < nev < n-1. + std::cout << nevp << "dddd21d22g\n";fflush(stdout); + throw ArpackError(ArpackError::NEV_OUT_OF_BOUNDS); + } + return nevp; + +} // CheckNev. + + +template +bool ARrcNonSymStdEig::ConjEigVec(int i) +{ + + if (this->EigValI[i] == (ARFLOAT)0.0) return false; + int j = i-1; + while ((j >= 0) && (this->EigValI[j] != (ARFLOAT)0.0)) j--; + if (((i-j)%2) == 0) { + return true; + } + else { + return false; + } + +} // ConjEigVec. + + +#ifdef STL_VECTOR_H // Defining functions that use STL vector class. +#ifdef ARCOMP_H + +template +vector >* ARrcNonSymStdEig:: +GenComplex(vector* RealPart, vector* ImagPart, bool conj) +{ + + // Defining variables. + + vector >* Result; + try { + Result = new vector >(ValSize()); + } + catch (ArpackError) { return NULL; } + ARFLOAT* rp = RealPart->begin(); + ARFLOAT* ip = ImagPart->begin(); + ARFLOAT* end = RealPart->end(); + arcomplex* s = Result->begin(); + + // Creating a complex vector. + + if (!conj) { + while (rp != end) *s++ = arcomplex(*rp++, *ip++); + } + else { + while (rp != end) *s++ = arcomplex(*rp++, -(*ip++)); + } + + return Result; + +} // GenComplex (vector version). + + +template +vector >* ARrcNonSymStdEig:: +GenComplex(int dim, ARFLOAT* RealPart, ARFLOAT* ImagPart, bool conj) +{ + + // Defining variables. + + vector >* Result; + try { + Result = new vector >(dim); + } + catch (ArpackError) { return NULL; } + ARFLOAT* rp = RealPart; + ARFLOAT* ip = ImagPart; + ARFLOAT* end = &RealPart[dim]; + arcomplex* s = Result->begin(); + + // Creating a complex vector. + + if (!conj) { + while (rp != end) *s++ = arcomplex(*rp++, *ip++); + } + else { + while (rp != end) *s++ = arcomplex(*rp++, -(*ip++)); + } + + return Result; + +} // GenComplex (ARFLOAT* version). + + +template +vector >* ARrcNonSymStdEig:: +GenComplex(int dim, ARFLOAT* RealPart) +{ + + // Defining variables. + + vector >* Result; + try { + Result = new vector >(dim); + } + catch (ArpackError) { return NULL; } + ARFLOAT* rp = RealPart; + ARFLOAT* end = &RealPart[dim]; + arcomplex* s = Result->begin(); + + // Copying a real vector into a complex vector. + + while (rp != end) *s++ = *rp++; + + return Result; + +} // GenComplex. + +#endif // ARCOMP_H. +#endif // STL_VECTOR_H. + + +template +ARFLOAT* ARrcNonSymStdEig::GetVectorImag() +{ + + if (this->ido != 3) { + throw ArpackError(ArpackError::CANNOT_GET_VECTOR, "GetVectorImag"); + } + return &this->workl[this->ipntr[6]]; + +} // GetVectorImag. + + +template +int ARrcNonSymStdEig:: +Eigenvalues(ARFLOAT* &EigValRp, ARFLOAT* &EigValIp, bool ivec, bool ischur) +{ + + if (this->ValuesOK) { // Eigenvalues are available. + if ((EigValRp == NULL)&&(EigValIp == NULL)) { // Moving eigenvalues. + EigValRp = this->EigValR; + EigValIp = this->EigValI; + this->EigValR = NULL; + this->EigValI = NULL; + this->newVal = false; + this->ValuesOK = false; + } + else { // Copying eigenvalues. + try { + if (EigValRp == NULL) EigValRp = new ARFLOAT[ValSize()]; + if (EigValIp == NULL) EigValIp = new ARFLOAT[ValSize()]; + } + catch (ArpackError) { return 0; } + copy(this->nconv,this->EigValR,1,EigValRp,1); + copy(this->nconv,this->EigValI,1,EigValIp,1); + } + } + else { + if (this->newVal) { + delete[] this->EigValR; + delete[] this->EigValI; + this->newVal = false; + } + try { + if (EigValRp == NULL) EigValRp = new ARFLOAT[ValSize()]; + if (EigValIp == NULL) EigValIp = new ARFLOAT[ValSize()]; + } + catch (ArpackError) { return 0; } + this->EigValR = EigValRp; + this->EigValI = EigValIp; + if (ivec) { // Finding eigenvalues and vectors. + this->nconv = this->FindEigenvectors(ischur); + } + else { // Finding eigenvalues only. + this->nconv = this->FindEigenvalues(); + } + this->EigValR = NULL; + this->EigValI = NULL; + } + return this->nconv; + +} // Eigenvalues(EigValRp, EigValIp, ivec, ischur). + + +template +int ARrcNonSymStdEig:: +EigenValVectors(ARFLOAT* &EigVecp, ARFLOAT* &EigValRp, + ARFLOAT* &EigValIp, bool ischur) +{ + + if (this->ValuesOK) { // Eigenvalues are already available . + this->nconv = Eigenvalues(EigValRp, EigValIp, false); + this->nconv = this->Eigenvectors(EigVecp, ischur); + } + else { // Eigenvalues ans vectors are not available. + if (this->newVec) { + delete[] this->EigVec; + this->newVec = false; + } + if (this->newVal) { + delete[] this->EigValR; + delete[] this->EigValI; + this->newVal = false; + } + try { + if (EigVecp == NULL) EigVecp = new ARFLOAT[ValSize()*this->n]; + if (EigValRp == NULL) EigValRp = new ARFLOAT[ValSize()]; + if (EigValIp == NULL) EigValIp = new ARFLOAT[ValSize()]; + } + catch (ArpackError) { return 0; } + this->EigVec = EigVecp; + this->EigValR = EigValRp; + this->EigValI = EigValIp; + this->nconv = this->FindEigenvectors(ischur); + this->EigVec = NULL; + this->EigValR = NULL; + this->EigValI = NULL; + } + return this->nconv; + +} // EigenValVectors(EigVecp, EigValRp, EigValIp, ischur). + + +#ifdef ARCOMP_H +template +inline arcomplex ARrcNonSymStdEig::Eigenvalue(int i) +{ + + // Returning i-eth eigenvalue. + + if (!this->ValuesOK) { + throw ArpackError(ArpackError::VALUES_NOT_OK, "Eigenvalue(i)"); + } + else if ((i>=this->nconv)||(i<0)) { + throw ArpackError(ArpackError::RANGE_ERROR, "Eigenvalue(i)"); + } + return arcomplex(this->EigValR[i],this->EigValI[i]); + +} // Eigenvalue(i). +#endif // ARCOMP_H + + +template +inline ARFLOAT ARrcNonSymStdEig::EigenvalueReal(int i) +{ + + // Returning the real part of i-eth eigenvalue. + + if (!this->ValuesOK) { + throw ArpackError(ArpackError::VALUES_NOT_OK, "EigenvalueReal(i)"); + } + else if ((i>=this->nconv)||(i<0)) { + throw ArpackError(ArpackError::RANGE_ERROR, "EigenvalueReal(i)"); + } + return this->EigValR[i]; + +} // EigenvalueReal(i). + + +template +inline ARFLOAT ARrcNonSymStdEig::EigenvalueImag(int i) +{ + + // Returning the imaginary part of i-eth eigenvalue. + + if (!this->ValuesOK) { + throw ArpackError(ArpackError::VALUES_NOT_OK, "EigenvalueImag(i)"); + } + else if ((i>=this->nconv)||(i<0)) { + throw ArpackError(ArpackError::RANGE_ERROR, "EigenvalueImag(i)"); + } + return this->EigValI[i]; + +} // EigenvalueImag(i). + + +#ifdef ARCOMP_H +template +inline arcomplex ARrcNonSymStdEig:: +Eigenvector(int i, int j) +{ + + // Returning element j of i-eth eigenvector. + + if ((!this->VectorsOK)||(!this->ValuesOK)) { + throw ArpackError(ArpackError::VECTORS_NOT_OK, "Eigenvector(i,j)"); + } + else if ((i>=this->nconv)||(i<0)||(j>=this->n)||(j<0)) { + throw ArpackError(ArpackError::RANGE_ERROR, "Eigenvector(i,j)"); + } + if (this->EigValI[i]==(ARFLOAT)0.0) { // Real eigenvalue. + return arcomplex(this->EigVec[i*this->n+j],(ARFLOAT)0.0); + } + else { // Complex eigenvalue. + if (this->EigValI[i]>(ARFLOAT)0.0) { // with positive imaginary part. + return arcomplex(this->EigVec[i*this->n+j], this->EigVec[(i+1)*this->n+j]); + } + else { // with negative imaginary part. + return arcomplex(this->EigVec[(i-1)*this->n+j], -this->EigVec[i*this->n+j]); + } + } + +} // Eigenvector(i,j). +#endif // ARCOMP_H + + +template +inline ARFLOAT ARrcNonSymStdEig::EigenvectorReal(int i, int j) +{ + + // Returning the real part of element j of i-eth eigenvector. + + if (!this->VectorsOK) { + throw ArpackError(ArpackError::VECTORS_NOT_OK, "EigenvectorReal(i,j)"); + } + else if ((i>=this->nconv)||(i<0)||(j>=this->n)||(j<0)) { + throw ArpackError(ArpackError::RANGE_ERROR, "EigenvectorReal(i,j)"); + } + return this->EigVec[i*this->n+j]; + +} // EigenvectorReal(i,j). + + +template +inline ARFLOAT ARrcNonSymStdEig::EigenvectorImag(int i, int j) +{ + + // Returning the imaginary part of element j of i-eth eigenvector. + + if ((!this->VectorsOK)||(!this->ValuesOK)) { + throw ArpackError(ArpackError::VECTORS_NOT_OK, "EigenvectorImag(i,j)"); + } + else if ((i>=this->nconv)||(i<0)||(j>=this->n)||(j<0)) { + throw ArpackError(ArpackError::RANGE_ERROR, "EigenvectorImag(i,j)"); + } + if (this->EigValI[i]==(ARFLOAT)0.0) { // Real eigenvalue. + return (ARFLOAT)0.0; + } + else { // Complex eigenvalue. + if (this->EigValI[i]>(ARFLOAT)0.0) { // with positive imaginary part. + return this->EigVec[(i+1)*this->n+j]; + } + else { // with negative imaginary part. + return -this->EigVec[i*this->n+j]; + } + } + +} // EigenvectorImag(i,j). + + +template +inline ARFLOAT* ARrcNonSymStdEig::RawEigenvaluesImag() +{ + + if (!this->ValuesOK) { + throw ArpackError(ArpackError::VALUES_NOT_OK, "RawEigenvaluesImag"); + } + return this->EigValI; + +} // RawEigenvaluesImag. + + +#ifdef STL_VECTOR_H // Defining some functions that use STL vector class. + +#ifdef ARCOMP_H +template +inline vector >* ARrcNonSymStdEig:: +StlEigenvalues(bool ivec, bool ischur) +{ + + // Returning the eigenvalues in a STL vector. + + // Defining temporary variables. + + vector* StlEigValR; + vector* StlEigValI; + ARFLOAT* ValRPtr; + ARFLOAT* ValIPtr; + + try { + StlEigValR = new vector(ValSize()); + StlEigValI = new vector(ValSize()); + } + catch (ArpackError) { return NULL; } + + // Finding Eigenvalues. + + ValRPtr = StlEigValR->begin(); + ValIPtr = StlEigValI->begin(); + nconv = Eigenvalues(ValRPtr, ValIPtr, ivec, ischur); + vector >* Val = GenComplex(StlEigValR, StlEigValI); + + // Deleting temporary variables. + + delete StlEigValR; + delete StlEigValI; + + return Val; + +} // StlEigenvalues. +#endif // ARCOMP_H. + + +template +inline vector* ARrcNonSymStdEig::StlEigenvaluesReal() +{ + + // Returning the real part of the eigenvalues in a STL vector. + + vector* StlEigValR; + + if (!ValuesOK) { + throw ArpackError(ArpackError::VALUES_NOT_OK, "StlEigenvaluesReal"); + } + try { + StlEigValR = new vector(EigValR, &EigValR[ValSize()]); + } + catch (ArpackError) { return NULL; } + return StlEigValR; + +} // StlEigenvaluesReal. + + +template +inline vector* ARrcNonSymStdEig::StlEigenvaluesImag() +{ + + // Returning the imaginary part of the eigenvalues in a STL vector. + + vector* StlEigValI; + + if (!ValuesOK) { + throw ArpackError(ArpackError::VALUES_NOT_OK, "StlEigenvaluesImag"); + } + try { + StlEigValI = new vector(EigValI, &EigValI[ValSize()]); + } + catch (ArpackError) { return NULL; } + return StlEigValI; + +} // StlEigenvaluesImag. + + +#ifdef ARCOMP_H +template +inline vector >* ARrcNonSymStdEig:: +StlEigenvector(int i) +{ + + // Returning the i-th eigenvector in a STL vector. + + if (!VectorsOK) { + throw ArpackError(ArpackError::VECTORS_NOT_OK, "StlEigenvector(i)"); + } + else if ((i>=ValSize())||(i<0)) { + throw ArpackError(ArpackError::RANGE_ERROR, "StlEigenvector(i)"); + } + if (EigValI[i] == (ARFLOAT)0.0) { // Real eigenvector. + return GenComplex(n, &EigVec[i*n]); + } + else if (!ConjEigVec(i)) { // First eigenvector in a conjugate pair. + return GenComplex(n, &EigVec[i*n], &EigVec[(i+1)*n]); + } + else { // Second eigenvector in a conjugate pair. + return GenComplex(n, &EigVec[(i-1)*n], &EigVec[i*n], true); + } + +} // StlEigenvector(i). +#endif // ARCOMP_H. + + +template +inline vector* ARrcNonSymStdEig::StlEigenvectorReal(int i) +{ + + // Returning the real part of the i-th eigenvector in a STL vector. + + vector* Vec; + + if (!VectorsOK) { + throw ArpackError(ArpackError::VECTORS_NOT_OK, "StlEigenvectorReal(i)"); + } + else if ((i>=ValSize())||(i<0)) { + throw ArpackError(ArpackError::RANGE_ERROR, "StlEigenvectorReal(i)"); + } + if (!ConjEigVec(i)) { // Real eigenvector or first in a conj. pair. + try { + Vec = new vector(&EigVec[i*n], &EigVec[(i+1)*n]); + } + catch (ArpackError) { return NULL; } + return Vec; + } + else { // Second eigenvector in a conjugate pair. + try { + Vec = new vector(&EigVec[(i-1)*n], &EigVec[i*n]); + } + catch (ArpackError) { return NULL; } + return Vec; + } + +} // StlEigenvectorReal(i). + + +template +inline vector* ARrcNonSymStdEig::StlEigenvectorImag(int i) +{ + + // Returning the imaginary part of the i-th eigenvector in a STL vector. + + vector* Vec; + + if (!VectorsOK) { + throw ArpackError(ArpackError::VECTORS_NOT_OK, "StlEigenvectorImag(i)"); + } + else if ((i>=ValSize())||(i<0)) { + throw ArpackError(ArpackError::RANGE_ERROR, "StlEigenvectorImag(i)"); + } + if (EigValI[i] == (ARFLOAT)0.0) { // Real eigenvector. + try { + Vec = new vector(ValSize(), (ARFLOAT)0.0); + } + catch (ArpackError) { return NULL; } + return Vec; + } + else if (!ConjEigVec(i)) { // First eigenvector in a conjugate pair. + try { + Vec = new vector(&EigVec[(i+1)*n], &EigVec[(i+2)*n]); + } + catch (ArpackError) { return NULL; } + return Vec; + } + else { // Second eigenvector in a conjugate pair. + try { + Vec = new vector(&EigVec[i*n], &EigVec[(i+1)*n]); + } + catch (ArpackError) { return NULL; } + for (ARFLOAT* s = Vec->begin(); s != Vec->end(); s++) *s = -(*s); + return Vec; + } + +} // StlEigenvectorImag(i). + +#endif // STL_VECTOR_H. + + +template +inline ARrcNonSymStdEig:: +ARrcNonSymStdEig(int np, int nevp, const std::string& whichp, int ncvp, + ARFLOAT tolp, int maxitp, ARFLOAT* residp, bool ishiftp) + +{ + + this->NoShift(); + this->DefineParameters(np, nevp, whichp, ncvp, tolp, maxitp, residp, ishiftp); + +} // Long constructor (regular mode). + + +template +inline ARrcNonSymStdEig:: +ARrcNonSymStdEig(int np, int nevp, ARFLOAT sigmap, const std::string& whichp, int ncvp, + ARFLOAT tolp, int maxitp, ARFLOAT* residp, bool ishiftp) + +{ + + this->ChangeShift(sigmap); + this->DefineParameters(np, nevp, whichp, ncvp, tolp, maxitp, residp, ishiftp); + +} // Long constructor (shift and invert mode). + + +template +ARrcNonSymStdEig& ARrcNonSymStdEig:: +operator=(const ARrcNonSymStdEig& other) +{ + + if (this != &other) { // Stroustrup suggestion. + this->ClearMem(); + Copy(other); + } + return *this; + +} // operator=. + + +#endif // ARRSNSYM_H + diff --git a/external/arpack++/include/arrssym.h b/external/arpack++/include/arrssym.h new file mode 100644 index 000000000..1a38fdd13 --- /dev/null +++ b/external/arpack++/include/arrssym.h @@ -0,0 +1,424 @@ +/* + ARPACK++ v1.2 2/20/2000 + c++ interface to ARPACK code. + + MODULE ARRSSym.h. + Arpack++ class ARrcSymStdEig definition. + + ARPACK Authors + Richard Lehoucq + Danny Sorensen + Chao Yang + Dept. of Computational & Applied Mathematics + Rice University + Houston, Texas +*/ + +#ifndef ARRSSYM_H +#define ARRSSYM_H + +#include +#include +#include "arch.h" +#include "arerror.h" +#include "debug.h" +#include "arrseig.h" +#include "saupp.h" +#include "seupp.h" + + +template +class ARrcSymStdEig: public virtual ARrcStdEig { + + protected: + + // a) Protected functions: + + // a.1) Memory control functions. + + void WorkspaceAllocate(); + // Allocates workspace for symmetric problems. + + + // a.2) Functions that handle original FORTRAN ARPACK code. + + void Aupp(); + // Interface to FORTRAN subroutines SSAUPD and DSAUPD. + + void Eupp(); + // Interface to FORTRAN subroutines SSEUPD and DSEUPD. + + + // a.3) Functions that check user defined parameters. + + std::string CheckWhich(const std::string& whichp); + // Determines if the value of variable "which" is valid. + + + public: + + // b) Public functions: + + // b.1) Trace functions. + + void Trace(const int digit = -5, const int getv0 = 0, const int aupd = 1, + const int aup2 = 0, const int aitr = 0, const int eigt = 0, + const int apps = 0, const int gets = 0, const int eupd = 0) + { + sTraceOn(digit, getv0, aupd, aup2, aitr, eigt, apps, gets, eupd); + } + // Turns on trace mode. + + + // b.2) Functions that permit step by step execution of ARPACK. + + ARFLOAT* PutVector(); + // When ido = -1, 1 or 2 and the user must perform a product in the form + // y <- M*x, this function indicates where to store y. When ido = 3, this + // function indicates where to store the shifts. + + + // b.3) Functions that perform all calculations in one step. + + int FindSchurVectors() { + throw ArpackError(ArpackError::SCHUR_UNDEFINED, "FindSchurVectors"); + return 0; // Only to avoid warning messages emitted by some compilers. + } + // For symmetric problems, Schur vectors are eigenvectors. + + int Eigenvalues(ARFLOAT* &EigValp, bool ivec = false, bool ischur = false); + // Overrides array EigValp with the eigenvalues of the problem. + // Also calculates eigenvectors and Schur vectors if requested. + + int EigenValVectors(ARFLOAT* &EigVecp, ARFLOAT* &EigValp, + bool ischur = false); + // Overrides array EigVecp sequentially with the eigenvectors of the + // given eigen-problem. Also stores the eigenvalues in EigValp. + // Calculates Schur vectors if requested. + + + // b.4) Functions that return elements of vectors and matrices. + + ARFLOAT Eigenvalue(int i); + // Provides i-eth eigenvalue. + + ARFLOAT Eigenvector(int i, int j); + // Provides element j of the i-eth eigenvector. + + + // b.5) Functions that use STL vector class. + +#ifdef STL_VECTOR_H + + vector* StlEigenvalues(bool ivec = false, bool ischur = false); + // Calculates the eigenvalues and stores them in a single STL vector. + // Also calculates eigenvectors and Schur vectors if requested. + + vector* StlEigenvector(int i); + // Returns the i-th eigenvector in a STL vector. + +#endif // #ifdef STL_VECTOR_H. + + + // b.6) Constructors and destructor. + + ARrcSymStdEig() { } + // Short constructor. + + ARrcSymStdEig(int np, int nevp, const std::string& whichp = "LM", int ncvp = 0, + ARFLOAT tolp = 0.0, int maxitp = 0, ARFLOAT* residp = NULL, + bool ishiftp = true); + // Long constructor (regular mode). + + ARrcSymStdEig(int np, int nevp, ARFLOAT sigmap, const std::string& whichp = "LM", + int ncvp = 0, ARFLOAT tolp = 0.0, int maxitp = 0, + ARFLOAT* residp = NULL, bool ishiftp = true); + // Long constructor (shift and invert mode). + + ARrcSymStdEig(const ARrcSymStdEig& other) { Copy(other); } + // Copy constructor. + + virtual ~ARrcSymStdEig() { } + // Destructor. + + // c) Operators. + + ARrcSymStdEig& operator=(const ARrcSymStdEig& other); + // Assignment operator. + +}; // class ARrcSymStdEig. + + +// ------------------------------------------------------------------------ // +// ARrcSymStdEig member functions definition. // +// ------------------------------------------------------------------------ // + + +template +inline void ARrcSymStdEig::WorkspaceAllocate() +{ + + this->lworkl = this->ncv*(this->ncv+9); + this->lworkv = 0; + this->lrwork = 0; + this->workl = new ARFLOAT[this->lworkl+1]; + +} // WorkspaceAllocate. + + +template +inline void ARrcSymStdEig::Aupp() +{ + + saupp(this->ido, this->bmat, this->n, this->which, this->nev, this->tol, this->resid, this->ncv, this->V, this->n, + this->iparam, this->ipntr, this->workd, this->workl, this->lworkl, this->info); + +} // Aupp. + + +template +inline void ARrcSymStdEig::Eupp() +{ + + seupp(this->rvec, this->HowMny, this->EigValR, this->EigVec, this->n, this->sigmaR, this->bmat, + this->n, this->which, this->nev, this->tol, this->resid, this->ncv, this->V, this->n, this->iparam, + this->ipntr, this->workd, this->workl, this->lworkl, this->info); + +} // Eupp. + + +template +std::string ARrcSymStdEig::CheckWhich(const std::string& whichp) +{ + + switch (whichp[0]) { + case 'B': // The options are: BE, ... + return "BE"; + case 'L': // LA, LM, ... + case 'S': // SA, SM. + switch (whichp[1]){ + case 'A': + case 'M': + return whichp; + } + default: + throw ArpackError(ArpackError::WHICH_UNDEFINED); + } + +} // CheckWhich. + + +template +ARFLOAT* ARrcSymStdEig::PutVector() +{ + + switch (this->ido) { + case -1: + case 1: // Returning OP*x. + case 2: + return &this->workd[this->ipntr[2]]; // Returning B*x. + case 3: + return &this->workl[this->ipntr[11]]; // Returning shifts. + default: + throw ArpackError(ArpackError::CANNOT_PUT_VECTOR, "PutVector"); + } + +} // PutVector. + + +template +int ARrcSymStdEig:: +Eigenvalues(ARFLOAT* &EigValp, bool ivec, bool ischur) +{ + + if (this->ValuesOK) { // Eigenvalues are available. + if (EigValp == NULL) { // Moving eigenvalues. + EigValp = this->EigValR; + this->EigValR = NULL; + this->newVal = false; + this->ValuesOK = false; + } + else { // Copying eigenvalues. + copy(this->nconv,this->EigValR,1,EigValp,1); + } + } + else { // Eigenvalues are not available. + if (this->newVal) { + delete[] this->EigValR; + this->newVal = false; + } + if (EigValp == NULL) { + try { EigValp = new ARFLOAT[this->ValSize()]; } + catch (ArpackError) { return 0; } + } + this->EigValR = EigValp; + if (ivec) { // Finding eigenvalues and eigenvectors. + this->nconv = this->FindEigenvectors(ischur); + } + else { // Finding eigenvalues only. + this->nconv = this->FindEigenvalues(); + } + this->EigValR = NULL; + } + return this->nconv; + +} // Eigenvalues(EigValp, ivec, ischur). + + +template +int ARrcSymStdEig:: +EigenValVectors(ARFLOAT* &EigVecp, ARFLOAT* &EigValp, bool ischur) +{ + + if (this->ValuesOK) { // Eigenvalues are already available . + this->nconv = Eigenvalues(EigValp, false); + this->nconv = this->Eigenvectors(EigVecp, ischur); + } + else { // Eigenvalues and vectors are not available. + try { + if (EigVecp == NULL) EigVecp = new ARFLOAT[this->ValSize()*this->n]; + if (EigValp == NULL) EigValp = new ARFLOAT[this->ValSize()]; + } + catch (ArpackError) { return 0; } + if (this->newVec) { + delete[] this->EigVec; + this->newVec = false; + } + if (this->newVal) { + delete[] this->EigValR; + this->newVal = false; + } + this->EigVec = EigVecp; + this->EigValR = EigValp; + this->nconv = this->FindEigenvectors(ischur); + this->EigVec = NULL; + this->EigValR = NULL; + } + return this->nconv; + +} // EigenValVectors(EigVecp, EigValp, ischur). + + +template +inline ARFLOAT ARrcSymStdEig::Eigenvalue(int i) +{ + + // Returning i-eth eigenvalue. + + if (!this->ValuesOK) { + throw ArpackError(ArpackError::VALUES_NOT_OK, "Eigenvalue(i)"); + } + else if ((i>=this->nconv)||(i<0)) { + throw ArpackError(ArpackError::RANGE_ERROR, "Eigenvalue(i)"); + } + return this->EigValR[i]; + +} // Eigenvalue(i). + + +template +inline ARFLOAT ARrcSymStdEig::Eigenvector(int i, int j) +{ + + // Returning element j of i-eth eigenvector. + + if (!this->VectorsOK) { + throw ArpackError(ArpackError::VECTORS_NOT_OK, "Eigenvector(i,j)"); + } + else if ((i>=this->nconv)||(i<0)||(j>=this->n)||(j<0)) { + throw ArpackError(ArpackError::RANGE_ERROR, "Eigenvector(i,j)"); + } + return this->EigVec[i*this->n+j]; + +} // Eigenvector(i,j). + + +#ifdef STL_VECTOR_H + +template +inline vector* ARrcSymStdEig:: +StlEigenvalues(bool ivec, bool ischur) +{ + + // Returning the eigenvalues in a STL vector. + + vector* StlEigValR; + ARFLOAT* ValPtr; + + try { StlEigValR = new vector(ValSize()); } + catch (ArpackError) { return NULL; } + ValPtr = StlEigValR->begin(); + nconv = Eigenvalues(ValPtr, ivec, ischur); + return StlEigValR; + +} // StlEigenvalues. + + +template +inline vector* ARrcSymStdEig::StlEigenvector(int i) +{ + + // Returning the i-th eigenvector in a STL vector. + + vector* Vec; + + if (!VectorsOK) { + throw ArpackError(ArpackError::VECTORS_NOT_OK, "StlEigenvector(i)"); + } + else if ((i>=ValSize())||(i<0)) { + throw ArpackError(ArpackError::RANGE_ERROR, "StlEigenvector(i)"); + } + try { + Vec = new vector(&EigVec[i*n], &EigVec[(i+1)*n]); + } + catch (ArpackError) { return NULL; } + return Vec; + +} // StlEigenvector(i). + +#endif // #ifdef STL_VECTOR_H. + + +template +inline ARrcSymStdEig:: +ARrcSymStdEig(int np, int nevp, const std::string& whichp, int ncvp, + ARFLOAT tolp, int maxitp, ARFLOAT* residp, bool ishiftp) + +{ + + this->NoShift(); + this->DefineParameters(np, nevp, whichp, ncvp, tolp, maxitp, residp, ishiftp); + +} // Long constructor (regular mode). + + +template +inline ARrcSymStdEig:: +ARrcSymStdEig(int np, int nevp, ARFLOAT sigmap, const std::string& whichp, + int ncvp, ARFLOAT tolp, int maxitp, ARFLOAT* residp, + bool ishiftp) + +{ + + this->ChangeShift(sigmap); + this->DefineParameters(np, nevp, whichp, ncvp, tolp, maxitp, residp, ishiftp); + +} // Long constructor (shift and invert mode). + + +template +ARrcSymStdEig& ARrcSymStdEig:: +operator=(const ARrcSymStdEig& other) +{ + + if (this != &other) { // Stroustrup suggestion. + this->ClearMem(); + Copy(other); + } + return *this; + +} // operator=. + + +#endif // ARRSSYM_H + diff --git a/external/arpack++/include/arscomp.h b/external/arpack++/include/arscomp.h new file mode 100644 index 000000000..709833d71 --- /dev/null +++ b/external/arpack++/include/arscomp.h @@ -0,0 +1,118 @@ +/* + ARPACK++ v1.2 2/20/2000 + c++ interface to ARPACK code. + + MODULE ARSComp.h. + Arpack++ class ARCompStdEig definition. + + ARPACK Authors + Richard Lehoucq + Danny Sorensen + Chao Yang + Dept. of Computational & Applied Mathematics + Rice University + Houston, Texas +*/ + +#ifndef ARSCOMP_H +#define ARSCOMP_H + +#include + +#include "arch.h" +#include "arseig.h" +#include "arrscomp.h" + +template +class ARCompStdEig: + virtual public ARStdEig, ARFOP>, + virtual public ARrcCompStdEig { + + public: + + // a) Constructors and destructor. + + ARCompStdEig() { } + // Short constructor. + + ARCompStdEig(int np, int nevp, ARFOP* objOPp, + void (ARFOP::* MultOPxp)(arcomplex[],arcomplex[]), + const std::string& whichp = "LM", int ncvp = 0, + ARFLOAT tolp = 0.0, int maxitp = 0, + arcomplex* residp = NULL, bool ishiftp = true); + // Long constructor (regular mode). + + ARCompStdEig(int np, int nevp, ARFOP* objOPp, + void (ARFOP::* MultOPxp)(arcomplex[],arcomplex[]), + arcomplex sigma, const std::string& whichp = "LM", + int ncvp = 0, ARFLOAT tolp = 0.0, int maxitp = 0, + arcomplex* residp = NULL, bool ishiftp = true); + // Long constructor (shift and invert mode). + + ARCompStdEig(const ARCompStdEig& other) { Copy(other); } + // Copy constructor. + + virtual ~ARCompStdEig() { } + // Destructor. + + // b) Operators. + + ARCompStdEig& operator=(const ARCompStdEig& other); + // Assignment operator. + +}; // class ARCompStdEig. + + +// ------------------------------------------------------------------------ // +// ARCompStdEig member functions definition. // +// ------------------------------------------------------------------------ // + + +template +inline ARCompStdEig:: +ARCompStdEig(int np, int nevp, ARFOP* objOPp, + void (ARFOP::* MultOPxp)(arcomplex[],arcomplex[]), + const std::string& whichp, int ncvp, ARFLOAT tolp, int maxitp, + arcomplex* residp, bool ishiftp) + +{ + + this->NoShift(); + this->DefineParameters(np, nevp, objOPp, MultOPxp, whichp, + ncvp, tolp, maxitp, residp, ishiftp); + +} // Long constructor (regular mode). + + +template +inline ARCompStdEig:: +ARCompStdEig(int np, int nevp, ARFOP* objOPp, + void (ARFOP::* MultOPxp)(arcomplex[],arcomplex[]), + arcomplex sigmap, const std::string& whichp, int ncvp, + ARFLOAT tolp, int maxitp, arcomplex* residp, + bool ishiftp) + +{ + + this->ChangeShift(sigmap); + this->DefineParameters(np, nevp, objOPp, MultOPxp, whichp, + ncvp, tolp, maxitp, residp, ishiftp); + +} // Long constructor (shift and invert mode). + + +template +ARCompStdEig& ARCompStdEig:: +operator=(const ARCompStdEig& other) +{ + + if (this != &other) { // Stroustrup suggestion. + this->ClearMem(); + Copy(other); + } + return *this; + +} // operator=. + + +#endif // ARSCOMP_H diff --git a/external/arpack++/include/arseig.h b/external/arpack++/include/arseig.h new file mode 100644 index 000000000..edac96617 --- /dev/null +++ b/external/arpack++/include/arseig.h @@ -0,0 +1,237 @@ +/* + ARPACK++ v1.2 2/20/2000 + c++ interface to ARPACK code. + + MODULE ARSEig.h. + Arpack++ class ARStdEig definition. + This class is the base class for all + standard and generalized problem templates. + + ARPACK Authors + Richard Lehoucq + Danny Sorensen + Chao Yang + Dept. of Computational & Applied Mathematics + Rice University + Houston, Texas +*/ + +#ifndef ARSEIG_H +#define ARSEIG_H + +#include +#include "arch.h" +#include "arerror.h" +#include "arrseig.h" + +// ARStdEig class definition. + +template +class ARStdEig: virtual public ARrcStdEig { + + public: + + // a) Notation. + + typedef void (ARFOP::* TypeOPx)(ARTYPE[], ARTYPE[]); + + + protected: + + // b) User defined parameters. + + ARFOP *objOP; // Object that has MultOPx as a member function. + TypeOPx MultOPx; // Function that evaluates the product OP*x. + + // c) Protected functions. + + virtual void Copy(const ARStdEig& other); + // Makes a deep copy of "other" over "this" object. + // Old values are not deleted (this function is to be used + // by the copy constructor and the assignment operator only). + + + public: + + // d) Public functions: + + // d.1) Function that stores user defined parameters. + + virtual void DefineParameters(int np, int nevp, ARFOP* objOPp, + TypeOPx MultOPxp, const std::string& whichp="LM", + int ncvp=0, ARFLOAT tolp=0.0, int maxitp=0, + ARTYPE* residp=NULL, bool ishiftp=true); + // Set values of problem parameters (also called by constructors). + // Redefined in ARGenEigenProblem. + + // d.2) Function that allow changes in problem parameters. + + void ChangeMultOPx(ARFOP* objOPp, TypeOPx MultOPxp); + // Changes the matrix-vector function that performs OP*x. + + virtual void SetRegularMode(ARFOP* objOPp, TypeOPx MultOPxp); + // Turns problem to regular mode. + + virtual void SetShiftInvertMode(ARTYPE sigmap, ARFOP* objOPp, + TypeOPx MultOPxp); + // Turns problem to shift and invert mode with shift defined by sigmap. + + // d.3) Function that permits step by step execution of ARPACK. + + virtual void Iterate() { + throw ArpackError(ArpackError::NOT_IMPLEMENTED, "Iterate"); + } + // Takes one iteration of IRA method. + + + // d.4) Function that performs all calculations in one step. + + virtual int FindArnoldiBasis(); + // Determines the Arnoldi basis related to the given problem. + // Redefined in ARGenEigenProblem and ARSymGenEigenProblem. + + + // d.5) Constructor and destructor. + + ARStdEig() { } + // Constructor that does nothing but calling base class constructor. + + ARStdEig(const ARStdEig& other) { Copy(other); } + // Copy constructor. + + virtual ~ARStdEig() { } + // Very simple destructor. + + // e) Operators. + + ARStdEig& operator=(const ARStdEig& other); + // Assignment operator. + +}; // class ARStdEig. + + +// ------------------------------------------------------------------------ // +// ARStdEig member functions definition. // +// ------------------------------------------------------------------------ // + + +template +inline void ARStdEig:: +Copy(const ARStdEig& other) +{ + + ARrcStdEig::Copy(other); + objOP = other.objOP; + MultOPx = other.MultOPx; + +} // Copy. + + +template +void ARStdEig:: +DefineParameters(int np, int nevp, ARFOP* objOPp, + void (ARFOP::* MultOPxp)(ARTYPE[], ARTYPE[]), const std::string& whichp, + int ncvp, ARFLOAT tolp, int maxitp, ARTYPE* residp, + bool ishiftp) + + +{ + + ARrcStdEig::DefineParameters(np, nevp, whichp, ncvp, tolp, + maxitp, residp, ishiftp); + objOP = objOPp; + MultOPx = MultOPxp; + +} // DefineParameters. + + +template +inline void ARStdEig:: +ChangeMultOPx(ARFOP* objOPp, void (ARFOP::* MultOPxp)(ARTYPE[], ARTYPE[])) +{ + + objOP = objOPp; + MultOPx = MultOPxp; + this->Restart(); + +} // ChangeMultOPx. + + +template +inline void ARStdEig:: +SetRegularMode(ARFOP* objOPp, void (ARFOP::* MultOPxp)(ARTYPE[], ARTYPE[])) +{ + + ChangeMultOPx(objOPp, MultOPxp); + this->NoShift(); + +} // SetRegularMode. + + +template +inline void ARStdEig:: +SetShiftInvertMode(ARTYPE sigmap, ARFOP* objOPp, + void (ARFOP::* MultOPxp)(ARTYPE[], ARTYPE[])) +{ + + ChangeMultOPx(objOPp, MultOPxp); + this->ChangeShift(sigmap); + +} // SetShiftInvertMode. + + +template +int ARStdEig::FindArnoldiBasis() +{ + + if (!this->BasisOK) this->Restart(); + + // Changing to auto shift mode. + + if (!this->AutoShift) { + ArpackError::Set(ArpackError::CHANGING_AUTOSHIFT, "FindArnoldiBasis"); + this->AutoShift=true; + } + + // ARPACK main loop. + + while (!this->BasisOK) { + + // Calling Aupp. + + try { this->TakeStep(); } + catch (ArpackError) { + ArpackError(ArpackError::CANNOT_FIND_BASIS, "FindArnoldiBasis"); + return 0; + } + + if ((this->ido == -1) || (this->ido == 1)) { + + // Performing Matrix vector multiplication: y <- OP*x. + + (objOP->*MultOPx)(&this->workd[this->ipntr[1]],&this->workd[this->ipntr[2]]); + + } + + } + return this->nconv; + +} // FindArnoldiBasis. + + +template +ARStdEig& ARStdEig:: +operator=(const ARStdEig& other) +{ + + if (this != &other) { // Stroustrup suggestion. + this->ClearMem(); + Copy(other); + } + return *this; + +} // operator=. + + +#endif // ARSEIG_H + diff --git a/external/arpack++/include/arsnsym.h b/external/arpack++/include/arsnsym.h new file mode 100644 index 000000000..4bb9d5123 --- /dev/null +++ b/external/arpack++/include/arsnsym.h @@ -0,0 +1,117 @@ +/* + ARPACK++ v1.2 2/20/2000 + c++ interface to ARPACK code. + + MODULE ARSNSym.h. + Arpack++ class ARNonSymStdEig definition. + + ARPACK Authors + Richard Lehoucq + Danny Sorensen + Chao Yang + Dept. of Computational & Applied Mathematics + Rice University + Houston, Texas +*/ + +#ifndef ARSNSYM_H +#define ARSNSYM_H + +#include +#include +#include "arch.h" +#include "arseig.h" +#include "arrsnsym.h" + + +template +class ARNonSymStdEig: + public virtual ARStdEig, + public virtual ARrcNonSymStdEig { + + public: + + // a) Constructors and destructor. + + ARNonSymStdEig() { } + // Short constructor. + + ARNonSymStdEig(int np, int nevp, ARFOP* objOPp, + void (ARFOP::* MultOPxp)(ARFLOAT[], ARFLOAT[]), + const std::string& whichp = "LM", int ncvp = 0, ARFLOAT tolp = 0.0, + int maxitp = 0, ARFLOAT* residp = NULL, bool ishiftp = true); + // Long constructor (regular mode). + + ARNonSymStdEig(int np, int nevp, ARFOP* objOPp, + void (ARFOP::* MultOPxp)(ARFLOAT[], ARFLOAT[]), + ARFLOAT sigma, const std::string& whichp = "LM", int ncvp = 0, + ARFLOAT tolp = 0.0, int maxitp = 0, ARFLOAT* residp = NULL, + bool ishiftp = true); + // Long constructor (shift and invert mode). + + ARNonSymStdEig(const ARNonSymStdEig& other) { Copy(other); } + // Copy constructor. + + virtual ~ARNonSymStdEig() { } + // Destructor. + + // b) Operators. + + ARNonSymStdEig& operator=(const ARNonSymStdEig& other); + // Assignment operator. + +}; // class ARNonSymStdEig. + + +// ------------------------------------------------------------------------ // +// ARNonSymStdEig member functions definition. // +// ------------------------------------------------------------------------ // + + +template +inline ARNonSymStdEig:: +ARNonSymStdEig(int np, int nevp, ARFOP* objOPp, + void (ARFOP::* MultOPxp)(ARFLOAT[], ARFLOAT[]), + const std::string& whichp, int ncvp, ARFLOAT tolp, int maxitp, + ARFLOAT* residp, bool ishiftp) + +{ + + this->NoShift(); + this->DefineParameters(np, nevp, objOPp, MultOPxp, whichp, + ncvp, tolp, maxitp, residp, ishiftp); + +} // Long constructor (regular mode). + + +template +inline ARNonSymStdEig:: +ARNonSymStdEig(int np, int nevp, ARFOP* objOPp, + void (ARFOP::* MultOPxp)(ARFLOAT[], ARFLOAT[]), + ARFLOAT sigmap, const std::string& whichp, int ncvp, ARFLOAT tolp, + int maxitp, ARFLOAT* residp, bool ishiftp) + +{ + + this->ChangeShift(sigmap); + this->DefineParameters(np, nevp, objOPp, MultOPxp, whichp, + ncvp, tolp, maxitp, residp, ishiftp); + +} // Long constructor (shift and invert mode). + + +template +ARNonSymStdEig& ARNonSymStdEig:: +operator=(const ARNonSymStdEig& other) +{ + + if (this != &other) { // Stroustrup suggestion. + this->ClearMem(); + Copy(other); + } + return *this; + +} // operator=. + + +#endif // ARSNSYM_H diff --git a/external/arpack++/include/arssym.h b/external/arpack++/include/arssym.h new file mode 100644 index 000000000..41c46e8c0 --- /dev/null +++ b/external/arpack++/include/arssym.h @@ -0,0 +1,118 @@ +/* + ARPACK++ v1.2 2/20/2000 + c++ interface to ARPACK code. + + MODULE ARSSym.h. + Arpack++ class ARSymStdEig definition. + + ARPACK Authors + Richard Lehoucq + Danny Sorensen + Chao Yang + Dept. of Computational & Applied Mathematics + Rice University + Houston, Texas +*/ + +#ifndef ARSSYM_H +#define ARSSYM_H + +#include +#include +#include "arch.h" +#include "arseig.h" +#include "arrssym.h" + + +template +class ARSymStdEig: + public virtual ARStdEig, + public virtual ARrcSymStdEig { + + public: + + // a) Constructors and destructor. + + ARSymStdEig() { } + // Short constructor. + + ARSymStdEig(int np, int nevp, ARFOP* objOPp, + void (ARFOP::* MultOPxp)(ARFLOAT[], ARFLOAT[]), + const std::string& whichp = "LM", int ncvp = 0, ARFLOAT tolp = 0.0, + int maxitp = 0, ARFLOAT* residp = NULL, bool ishiftp = true); + // Long constructor (regular mode). + + ARSymStdEig(int np, int nevp, ARFOP* objOPp, + void (ARFOP::* MultOPxp)(ARFLOAT[], ARFLOAT[]), + ARFLOAT sigmap, const std::string& whichp = "LM", int ncvp = 0, + ARFLOAT tolp = 0.0, int maxitp = 0, ARFLOAT* residp = NULL, + bool ishiftp = true); + // Long constructor (shift and invert mode). + + ARSymStdEig(const ARSymStdEig& other) { Copy(other); } + // Copy constructor. + + virtual ~ARSymStdEig() { } + // Destructor. + + // b) Operators. + + ARSymStdEig& operator=(const ARSymStdEig& other); + // Assignment operator. + +}; // class ARSymStdEig. + + +// ------------------------------------------------------------------------ // +// ARSymStdEig member functions definition. // +// ------------------------------------------------------------------------ // + + +template +inline ARSymStdEig:: +ARSymStdEig(int np, int nevp, ARFOP* objOPp, + void (ARFOP::* MultOPxp)(ARFLOAT[], ARFLOAT[]), + const std::string& whichp, int ncvp, ARFLOAT tolp, + int maxitp, ARFLOAT* residp, bool ishiftp) + +{ + + this->NoShift(); + this->DefineParameters(np, nevp, objOPp, MultOPxp, whichp, + ncvp, tolp, maxitp, residp, ishiftp); + +} // Long constructor (regular mode). + + +template +inline ARSymStdEig:: +ARSymStdEig(int np, int nevp, ARFOP* objOPp, + void (ARFOP::* MultOPxp)(ARFLOAT[], ARFLOAT[]), + ARFLOAT sigmap, const std::string& whichp, int ncvp, ARFLOAT tolp, + int maxitp, ARFLOAT* residp, bool ishiftp) + +{ + + this->ChangeShift(sigmap); + this->DefineParameters(np, nevp, objOPp, MultOPxp, whichp, + ncvp, tolp, maxitp, residp, ishiftp); + +} // Long constructor (shift and invert mode). + + +template +ARSymStdEig& ARSymStdEig:: +operator=(const ARSymStdEig& other) +{ + + if (this != &other) { // Stroustrup suggestion. + this->ClearMem(); + Copy(other); + } + return *this; + +} // operator=. + + +#endif // ARSSYM_H + diff --git a/external/arpack++/include/arugcomp.h b/external/arpack++/include/arugcomp.h new file mode 100644 index 000000000..7f34ca0dd --- /dev/null +++ b/external/arpack++/include/arugcomp.h @@ -0,0 +1,204 @@ +/* + ARPACK++ v1.2 2/20/2000 + c++ interface to ARPACK code. + + MODULE ARUGComp.h. + Arpack++ class ARluCompGenEig definition + (umfpack version). + + ARPACK Authors + Richard Lehoucq + Danny Sorensen + Chao Yang + Dept. of Computational & Applied Mathematics + Rice University + Houston, Texas +*/ + +#ifndef ARUGCOMP_H +#define ARUGCOMP_H + +#include +#include +#include "arch.h" +#include "arunsmat.h" +#include "arunspen.h" +#include "arrseig.h" +#include "argcomp.h" + + +template +class ARluCompGenEig: + public virtual + ARCompGenEig, ARFLOAT >, + ARumNonSymPencil, ARFLOAT > > { + + private: + + // a) Data structure used to store matrices. + + ARumNonSymPencil, ARFLOAT > Pencil; + + // b) Protected functions: + + virtual void Copy(const ARluCompGenEig& other); + // Makes a deep copy of "other" over "this" object. + // Old values are not deleted (this function is to be used + // by the copy constructor and the assignment operator only). + + + public: + + // c) Public functions: + + // c.1) Functions that allow changes in problem parameters. + + virtual void ChangeShift(arcomplex sigmaRp); + + virtual void SetRegularMode(); + + virtual void SetShiftInvertMode(arcomplex sigmap); + + // c.2) Constructors and destructor. + + ARluCompGenEig() { } + // Short constructor. + + ARluCompGenEig(int nevp, ARumNonSymMatrix, ARFLOAT>& A, + ARumNonSymMatrix, ARFLOAT>& B, + const std::string& whichp = "LM", int ncvp = 0, + ARFLOAT tolp = 0.0, int maxitp = 0, + arcomplex* residp = NULL, bool ishiftp = true); + // Long constructor (regular mode). + + ARluCompGenEig(int nevp, ARumNonSymMatrix, ARFLOAT>& A, + ARumNonSymMatrix, ARFLOAT>& B, + arcomplex sigma, const std::string& whichp = "LM", + int ncvp = 0, ARFLOAT tolp = 0.0, int maxitp = 0, + arcomplex* residp = NULL, bool ishiftp = true); + // Long constructor (shift and invert mode). + + ARluCompGenEig(const ARluCompGenEig& other) { Copy(other); } + // Copy constructor. + + virtual ~ARluCompGenEig() { } + + // d) Operators. + + ARluCompGenEig& operator=(const ARluCompGenEig& other); + // Assignment operator. + +}; // class ARluCompGenEig. + + +// ------------------------------------------------------------------------ // +// ARluCompGenEig member functions definition. // +// ------------------------------------------------------------------------ // + + +template +inline void ARluCompGenEig:: +Copy(const ARluCompGenEig& other) +{ + + ARCompGenEig, ARFLOAT >, + ARumNonSymPencil, ARFLOAT> >:: Copy(other); + Pencil = other.Pencil; + this->objOP = &Pencil; + this->objB = &Pencil; + +} // Copy. + + +template +inline void ARluCompGenEig:: +ChangeShift(arcomplex sigmaRp) +{ + + this->objOP->FactorAsB(sigmaRp); + ARrcStdEig >::ChangeShift(sigmaRp); + +} // ChangeShift. + + +template +inline void ARluCompGenEig::SetRegularMode() +{ + + ARStdEig, + ARumNonSymPencil, ARFLOAT> >:: + SetRegularMode(&Pencil, + &ARumNonSymPencil, ARFLOAT>::MultInvBAv); + +} // SetRegularMode. + + +template +inline void ARluCompGenEig:: +SetShiftInvertMode(arcomplex sigmap) +{ + + ARCompGenEig, ARFLOAT>, + ARumNonSymPencil, ARFLOAT> >:: + SetShiftInvertMode(sigmap, &Pencil, + &ARumNonSymPencil,ARFLOAT>::MultInvAsBv); + +} // SetShiftInvertMode. + + +template +inline ARluCompGenEig:: +ARluCompGenEig(int nevp, ARumNonSymMatrix, ARFLOAT>& A, + ARumNonSymMatrix, ARFLOAT>& B, const std::string& whichp, + int ncvp, ARFLOAT tolp, int maxitp, + arcomplex* residp, bool ishiftp) + +{ + + Pencil.DefineMatrices(A, B); + this->NoShift(); + DefineParameters(A.ncols(), nevp, &Pencil, + &ARumNonSymPencil, ARFLOAT>::MultInvBAv, + &Pencil, + &ARumNonSymPencil, ARFLOAT>::MultBv, + whichp, ncvp, tolp, maxitp, residp, ishiftp); + +} // Long constructor (regular mode). + + +template +inline ARluCompGenEig:: +ARluCompGenEig(int nevp, ARumNonSymMatrix, ARFLOAT>& A, + ARumNonSymMatrix, ARFLOAT>& B, + arcomplex sigmap, const std::string& whichp, int ncvp, + ARFLOAT tolp, int maxitp, arcomplex* residp, + bool ishiftp) + +{ + + Pencil.DefineMatrices(A, B); + DefineParameters(A.ncols(), nevp, &Pencil, + &ARumNonSymPencil, ARFLOAT>::MultInvAsBv, + &Pencil, + &ARumNonSymPencil, ARFLOAT>::MultBv, + whichp, ncvp, tolp, maxitp, residp, ishiftp); + SetShiftInvertMode(sigmap); + +} // Long constructor (shift and invert mode). + + +template +ARluCompGenEig& ARluCompGenEig:: +operator=(const ARluCompGenEig& other) +{ + + if (this != &other) { // Stroustrup suggestion. + this->ClearMem(); + Copy(other); + } + return *this; + +} // operator=. + + +#endif // ARUGCOMP_H diff --git a/external/arpack++/include/arugnsym.h b/external/arpack++/include/arugnsym.h new file mode 100644 index 000000000..3061e68bd --- /dev/null +++ b/external/arpack++/include/arugnsym.h @@ -0,0 +1,245 @@ +/* + ARPACK++ v1.2 2/20/2000 + c++ interface to ARPACK code. + + MODULE ARUGNSym.h. + Arpack++ class ARluNonSymGenEig definition + (umfpack version). + + ARPACK Authors + Richard Lehoucq + Danny Sorensen + Chao Yang + Dept. of Computational & Applied Mathematics + Rice University + Houston, Texas +*/ + +#ifndef ARUGNSYM_H +#define ARUGNSYM_H + +#include +#include +#include "arch.h" +#include "arunsmat.h" +#include "arunspen.h" +#include "argnsym.h" + + +template +class ARluNonSymGenEig: + public virtual ARNonSymGenEig, + ARumNonSymPencil > { + + protected: + + // a) Data structure used to store matrices. + + ARumNonSymPencil Pencil; + + // b) Protected functions: + + virtual void Copy(const ARluNonSymGenEig& other); + // Makes a deep copy of "other" over "this" object. + // Old values are not deleted (this function is to be used + // by the copy constructor and the assignment operator only). + + + public: + + // c) Public functions: + + // c.1) Functions that allow changes in problem parameters. + + virtual void ChangeShift(ARFLOAT sigmaRp, ARFLOAT sigmaIp = 0.0); + + virtual void SetRegularMode(); + + virtual void SetShiftInvertMode(ARFLOAT sigmap); + + virtual void SetComplexShiftMode(char partp, ARFLOAT sigmaRp, + ARFLOAT sigmaIp); + + // c.2) Constructors and destructor. + + ARluNonSymGenEig() { } + // Short constructor. + + ARluNonSymGenEig(int nevp, ARumNonSymMatrix& A, + ARumNonSymMatrix& B, const std::string& whichp = "LM", + int ncvp = 0, ARFLOAT tolp = 0.0, int maxitp = 0, + ARFLOAT* residp = NULL, bool ishiftp = true); + // Long constructor (regular mode). + + ARluNonSymGenEig(int nevp, ARumNonSymMatrix& A, + ARumNonSymMatrix& B, ARFLOAT sigma, + const std::string& whichp = "LM", int ncvp = 0, + ARFLOAT tolp = 0.0, int maxitp = 0, + ARFLOAT* residp = NULL, bool ishiftp = true); + // Long constructor (real shift and invert mode). + + ARluNonSymGenEig(int nevp, ARumNonSymMatrix& A, + ARumNonSymMatrix& B, char partp, + ARFLOAT sigmaRp, ARFLOAT sigmaIp, const std::string& whichp = "LM", + int ncvp = 0, ARFLOAT tolp = 0.0, int maxitp = 0, + ARFLOAT* residp = NULL, bool ishiftp = true); + // Long constructor (complex shift and invert mode). + + ARluNonSymGenEig(const ARluNonSymGenEig& other) { Copy(other); } + // Copy constructor. + + virtual ~ARluNonSymGenEig() { } + // Destructor. + + // d) Operators. + + ARluNonSymGenEig& operator=(const ARluNonSymGenEig& other); + // Assignment operator. + +}; // class ARluNonSymGenEig. + + +// ------------------------------------------------------------------------ // +// ARluNonSymGenEig member functions definition. // +// ------------------------------------------------------------------------ // + + +template +inline void ARluNonSymGenEig:: +Copy(const ARluNonSymGenEig& other) +{ + + ARNonSymGenEig, + ARumNonSymPencil >:: Copy(other); + Pencil = other.Pencil; + this->objOP = &Pencil; + this->objB = &Pencil; + this->objA = &Pencil; + +} // Copy. + + +template +inline void ARluNonSymGenEig:: +ChangeShift(ARFLOAT sigmaRp, ARFLOAT sigmaIp) +{ + + if (sigmaIp == 0.0) { + this->objOP->FactorAsB(sigmaRp); + } + else { + this->objOP->FactorAsB(sigmaRp, sigmaIp, this->part); + } + ARrcNonSymGenEig::ChangeShift(sigmaRp, sigmaIp); + +} // ChangeShift. + + +template +inline void ARluNonSymGenEig::SetRegularMode() +{ + + ARStdEig >:: + SetRegularMode(&Pencil, &ARumNonSymPencil::MultInvBAv); + +} // SetRegularMode. + + +template +inline void ARluNonSymGenEig::SetShiftInvertMode(ARFLOAT sigmap) +{ + + ARNonSymGenEig, + ARumNonSymPencil >:: + SetShiftInvertMode(sigmap, &Pencil, + &ARumNonSymPencil::MultInvAsBv); + +} // SetShiftInvertMode. + + +template +inline void ARluNonSymGenEig:: +SetComplexShiftMode(char partp, ARFLOAT sigmaRp, ARFLOAT sigmaIp) +{ + + ARNonSymGenEig, + ARumNonSymPencil >:: + SetComplexShiftMode(partp, sigmaRp, sigmaIp, &Pencil, + &ARumNonSymPencil::MultInvAsBv, + &Pencil, &ARumNonSymPencil::MultAv); + +} // SetComplexShiftMode. + + +template +inline ARluNonSymGenEig:: +ARluNonSymGenEig(int nevp, ARumNonSymMatrix& A, + ARumNonSymMatrix& B, const std::string& whichp, int ncvp, + ARFLOAT tolp, int maxitp, ARFLOAT* residp, bool ishiftp) + +{ + + Pencil.DefineMatrices(A, B); + this->NoShift(); + DefineParameters(A.ncols(), nevp, &Pencil, + &ARumNonSymPencil::MultInvBAv, &Pencil, + &ARumNonSymPencil::MultBv, whichp, + ncvp, tolp, maxitp, residp, ishiftp); + +} // Long constructor (regular mode). + + +template +inline ARluNonSymGenEig:: +ARluNonSymGenEig(int nevp, ARumNonSymMatrix& A, + ARumNonSymMatrix& B, ARFLOAT sigmap, + const std::string& whichp, int ncvp, ARFLOAT tolp, + int maxitp, ARFLOAT* residp, bool ishiftp) + +{ + + Pencil.DefineMatrices(A, B); + DefineParameters(A.ncols(), nevp, &Pencil, + &ARumNonSymPencil::MultInvAsBv, &Pencil, + &ARumNonSymPencil::MultBv, whichp, + ncvp, tolp, maxitp, residp, ishiftp); + SetShiftInvertMode(sigmap); + +} // Long constructor (real shift and invert mode). + + +template +inline ARluNonSymGenEig:: +ARluNonSymGenEig(int nevp, ARumNonSymMatrix& A, + ARumNonSymMatrix& B, + char partp, ARFLOAT sigmaRp, + ARFLOAT sigmaIp, const std::string& whichp, int ncvp, ARFLOAT tolp, + int maxitp, ARFLOAT* residp, bool ishiftp) + +{ + + Pencil.DefineMatrices(A, B); + DefineParameters(A.ncols(), nevp, &Pencil, + &ARumNonSymPencil::MultInvAsBv, &Pencil, + &ARumNonSymPencil::MultBv, whichp, + ncvp, tolp, maxitp, residp, ishiftp); + SetComplexShiftMode(partp, sigmaRp, sigmaIp); + +} // Long constructor (complex shift and invert mode). + + +template +ARluNonSymGenEig& ARluNonSymGenEig:: +operator=(const ARluNonSymGenEig& other) +{ + + if (this != &other) { // Stroustrup suggestion. + this->ClearMem(); + Copy(other); + } + return *this; + +} // operator=. + + +#endif // ARUGNSYM_H diff --git a/external/arpack++/include/arugsym.h b/external/arpack++/include/arugsym.h new file mode 100644 index 000000000..d57dc451c --- /dev/null +++ b/external/arpack++/include/arugsym.h @@ -0,0 +1,234 @@ +/* + ARPACK++ v1.2 2/20/2000 + c++ interface to ARPACK code. + + MODULE ARUGSym.h. + Arpack++ class ARluSymGenEig definition + (UMFPACK version). + + ARPACK Authors + Richard Lehoucq + Danny Sorensen + Chao Yang + Kristi Maschhoff + Dept. of Computational & Applied Mathematics + Rice University + Houston, Texas +*/ + +#ifndef ARUGSYM_H +#define ARUGSYM_H + +#include +#include +#include "arch.h" +#include "arusmat.h" +#include "aruspen.h" +#include "argsym.h" + + +template +class ARluSymGenEig: + public virtual ARSymGenEig, + ARumSymPencil > { + + private: + + // a) Data structure used to store matrices. + + ARumSymPencil Pencil; + + // b) Protected functions: + + virtual void Copy(const ARluSymGenEig& other); + // Makes a deep copy of "other" over "this" object. + // Old values are not deleted (this function is to be used + // by the copy constructor and the assignment operator only). + + + public: + + // c) Public functions: + + // c.1) Functions that allow changes in problem parameters. + + virtual void ChangeShift(ARFLOAT sigmap); + + virtual void SetRegularMode(); + + virtual void SetShiftInvertMode(ARFLOAT sigmap); + + virtual void SetBucklingMode(ARFLOAT sigmap); + + virtual void SetCayleyMode(ARFLOAT sigmap); + + // c.2) Constructors and destructor. + + ARluSymGenEig() { } + // Short constructor. + + ARluSymGenEig(int nevp, ARumSymMatrix& A, + ARumSymMatrix& B, const std::string& whichp = "LM", + int ncvp = 0, ARFLOAT tolp = 0.0, int maxitp = 0, + ARFLOAT* residp = NULL, bool ishiftp = true); + // Long constructor (regular mode). + + ARluSymGenEig(char InvertModep, int nevp, ARumSymMatrix& A, + ARumSymMatrix& B, ARFLOAT sigma, const std::string& whichp = "LM", + int ncvp = 0, ARFLOAT tolp = 0.0, int maxitp = 0, + ARFLOAT* residp = NULL, bool ishiftp = true); + // Long constructor (shift and invert, buckling and Cayley modes). + + ARluSymGenEig(const ARluSymGenEig& other) { Copy(other); } + // Copy constructor. + + virtual ~ARluSymGenEig() { } + // Destructor. + + // d) Operators. + + ARluSymGenEig& operator=(const ARluSymGenEig& other); + // Assignment operator. + +}; // class ARluSymGenEig. + + +// ------------------------------------------------------------------------ // +// ARluSymGenEig member functions definition. // +// ------------------------------------------------------------------------ // + + +template +inline void ARluSymGenEig:: +Copy(const ARluSymGenEig& other) +{ + + ARSymGenEig, + ARumSymPencil >:: Copy(other); + Pencil = other.Pencil; + this->objOP = &Pencil; + this->objB = &Pencil; + this->objA = &Pencil; + +} // Copy. + + +template +inline void ARluSymGenEig::ChangeShift(ARFLOAT sigmap) +{ + + this->objOP->FactorAsB(sigmap); + ARrcSymGenEig::ChangeShift(sigmap); + +} // ChangeShift. + + +template +inline void ARluSymGenEig::SetRegularMode() +{ + + ARStdEig >:: + SetRegularMode(&Pencil, &ARumSymPencil::MultInvBAv); + +} // SetRegularMode. + + +template +inline void ARluSymGenEig:: +SetShiftInvertMode(ARFLOAT sigmap) +{ + + ARSymGenEig, ARumSymPencil >:: + SetShiftInvertMode(sigmap, &Pencil, &ARumSymPencil::MultInvAsBv); + this->ChangeMultBx(&Pencil, &ARumSymPencil::MultBv); + +} // SetShiftInvertMode. + + +template +inline void ARluSymGenEig:: +SetBucklingMode(ARFLOAT sigmap) +{ + + ARSymGenEig, ARumSymPencil >:: + SetBucklingMode(sigmap, &Pencil, &ARumSymPencil::MultInvAsBv); + this->ChangeMultBx(&Pencil, &ARumSymPencil::MultAv); + +} // SetBucklingMode. + + +template +inline void ARluSymGenEig:: +SetCayleyMode(ARFLOAT sigmap) +{ + + ARSymGenEig, ARumSymPencil >:: + SetCayleyMode(sigmap, &Pencil, &ARumSymPencil::MultInvAsBv, + &Pencil, &ARumSymPencil::MultAv); + this->ChangeMultBx(&Pencil, &ARumSymPencil::MultBv); + +} // SetCayleyMode. + + +template +inline ARluSymGenEig:: +ARluSymGenEig(int nevp, ARumSymMatrix& A, + ARumSymMatrix& B, const std::string& whichp, int ncvp, + ARFLOAT tolp, int maxitp, ARFLOAT* residp, bool ishiftp) + +{ + + Pencil.DefineMatrices(A, B); + this->InvertMode = 'S'; + this->NoShift(); + this->DefineParameters(A.ncols(), nevp, &Pencil, + &ARumSymPencil::MultInvBAv, &Pencil, + &ARumSymPencil::MultBv, whichp, + ncvp, tolp, maxitp, residp, ishiftp); + +} // Long constructor (regular mode). + + +template +inline ARluSymGenEig:: +ARluSymGenEig(char InvertModep, int nevp, ARumSymMatrix& A, + ARumSymMatrix& B, ARFLOAT sigmap, + const std::string& whichp, int ncvp, ARFLOAT tolp, + int maxitp, ARFLOAT* residp, bool ishiftp) + +{ + + Pencil.DefineMatrices(A, B); + this->DefineParameters(A.ncols(), nevp, &Pencil, + &ARumSymPencil::MultInvAsBv, &Pencil, + &ARumSymPencil::MultBv, whichp, + ncvp, tolp, maxitp, residp, ishiftp); + this->InvertMode = this->CheckInvertMode(InvertModep); + switch (this->InvertMode) { + case 'B': // Buckling mode. + this->ChangeMultBx(&Pencil, &ARumSymPencil::MultAv); + case 'S': // Shift and invert mode. + this->ChangeShift(sigmap); + break; + case 'C': // Cayley mode. + this->SetCayleyMode(sigmap); + } + +} // Long constructor (shift and invert, buckling and Cayley modes). + + +template +ARluSymGenEig& ARluSymGenEig:: +operator=(const ARluSymGenEig& other) +{ + + if (this != &other) { // Stroustrup suggestion. + this->ClearMem(); + Copy(other); + } + return *this; + +} // operator=. + + +#endif // ARUGSYM_H diff --git a/external/arpack++/include/arunsmat.h b/external/arpack++/include/arunsmat.h new file mode 100644 index 000000000..801b02e33 --- /dev/null +++ b/external/arpack++/include/arunsmat.h @@ -0,0 +1,646 @@ +/* + ARPACK++ v1.2 2/20/2000 + c++ interface to ARPACK code. + + MODULE ARUNSMat.h. + Arpack++ class ARumNonSymMatrix definition. + + ARPACK Authors + Richard Lehoucq + Danny Sorensen + Chao Yang + Dept. of Computational & Applied Mathematics + Rice University + Houston, Texas +*/ + + +#include "arunspen.h" + +#ifndef ARUNSMAT_H +#define ARUNSMAT_H + +#include +#include +#include "arch.h" +#include "armat.h" +#include "arhbmat.h" +#include "arerror.h" +#include "blas1c.h" +#include "umfpackc.h" + +template class ARumNonSymPencil; + +template +class ARumNonSymMatrix: public ARMatrix { + + friend class ARumNonSymPencil; + friend class ARumNonSymPencil; + + protected: + + bool factored; + int fillin; + int nnz; + int lvalue; + int lindex; + int keep[20]; + int icntl[20]; + int info[40]; + int* irow; + int* pcol; + int* index; + double threshold; + ARTYPE cntl[10]; + ARTYPE rinfo[20]; + ARTYPE* a; + ARTYPE* value; + ARhbMatrix mat; + + bool DataOK(); + + void ClearMem(); + + virtual void Copy(const ARumNonSymMatrix& other); + + void SubtractAsI(ARTYPE sigma); + + void CreateStructure(); + + void ThrowError(); + + public: + + int nzeros() { return nnz; } + + int FillFact() { return fillin; } + + bool IsSymmetric() { return bool(icntl[5]); } + + bool IsFactored() { return factored; } + + void FactorA(); + + void FactorAsI(ARTYPE sigma); + + void MultMv(ARTYPE* v, ARTYPE* w); + + void MultMtv(ARTYPE* v, ARTYPE* w); + + void MultMtMv(ARTYPE* v, ARTYPE* w); + + void MultMMtv(ARTYPE* v, ARTYPE* w); + + void Mult0MMt0v(ARTYPE* v, ARTYPE* w); + + void MultInvv(ARTYPE* v, ARTYPE* w); + + void DefineMatrix(int np, int nnzp, ARTYPE* ap, int* irowp, + int* pcolp, double thresholdp = 0.1, + int fillinp = 9, bool simest = false, + bool reducible = true, bool check = true); // Square. + + void DefineMatrix(int mp, int np, int nnzp, ARTYPE* ap, + int* irowp, int* pcolp); // Rectangular. + + ARumNonSymMatrix(): ARMatrix() { factored = false; } + // Short constructor that does nothing. + + ARumNonSymMatrix(int np, int nnzp, ARTYPE* ap, int* irowp, + int* pcolp, double thresholdp = 0.1, + int fillinp = 9, bool simest = false, + bool reducible = true, bool check = true); + // Long constructor (square matrix). + + ARumNonSymMatrix(int mp, int np, int nnzp, ARTYPE* ap, + int* irowp, int* pcolp); + // Long constructor (rectangular matrix). + + ARumNonSymMatrix(const std::string& name, double thresholdp = 0.1, + int fillinp = 9, bool simest = false, + bool reducible = true, bool check = true); + // Long constructor (Harwell-Boeing file). + + ARumNonSymMatrix(const ARumNonSymMatrix& other) { Copy(other); } + // Copy constructor. + + virtual ~ARumNonSymMatrix() { ClearMem(); } + // Destructor. + + ARumNonSymMatrix& operator=(const ARumNonSymMatrix& other); + // Assignment operator. + +}; + +// ------------------------------------------------------------------------ // +// ARumNonSymMatrix member functions definition. // +// ------------------------------------------------------------------------ // + + +template +bool ARumNonSymMatrix::DataOK() +{ + + int i, j, k; + + // Checking if pcol is in ascending order. + + i = 0; + while ((i!=this->n)&&(pcol[i]<=pcol[i+1])) i++; + if (i!=this->n) return false; + + // Checking if irow components are in order and within bounds. + + for (i=0; i!=this->n; i++) { + j = pcol[i]; + k = pcol[i+1]-1; + if (j<=k) { + if ((irow[j]<0)||(irow[k]>=this->n)) return false; + while ((j!=k)&&(irow[j] +inline void ARumNonSymMatrix::ClearMem() +{ + + if (factored) { + delete[] value; + delete[] index; + value = NULL; + index = NULL; + } + +} // ClearMem. + + +template +inline void ARumNonSymMatrix:: +Copy(const ARumNonSymMatrix& other) +{ + + // Local variable. + + int i; + + // Copying very fundamental variables and user-defined parameters. + + this->m = other.m; + this->n = other.n; + this->defined = other.defined; + factored = other.factored; + fillin = other.fillin; + nnz = other.nnz; + lvalue = other.lvalue; + lindex = other.lindex; + irow = other.irow; + pcol = other.pcol; + a = other.a; + threshold = other.threshold; + + // Returning from here if "other" was not initialized. + + if (!this->defined) return; + + // Copying arrays with static dimension. + + for (i=0; i<20; i++) keep[i] = other.keep[i]; + for (i=0; i<20; i++) icntl[i] = other.icntl[i]; + for (i=0; i<40; i++) info[i] = other.info[i]; + for (i=0; i<10; i++) cntl[i] = other.cntl[i]; + for (i=0; i<20; i++) rinfo[i] = other.rinfo[i]; + + // Returning from here if "other" was not factored. + + if (!factored) return; + + value = new ARTYPE[lvalue]; + index = new int[lindex]; + + for (i=0; i +void ARumNonSymMatrix::SubtractAsI(ARTYPE sigma) +{ + + int i, j, k, ki, end; + + // Subtracting sigma from diagonal elements. + + k = 0; + ki = this->n+1; + index[0] = 1; + + for (i=0; i!=this->n; i++) { + + j = pcol[i]; + end = pcol[i+1]; + + // Copying superdiagonal elements of column i. + + while ((irow[j] < i)&&(j < end)) { + value[k++] = a[j]; + index[ki++] = irow[j++]+1; + } + + // Verifying if A(i,i) exists. + + if ((irow[j] == i)&&(j < end)) { // A(i,i) exists, subtracting sigma. + value[k++] = a[j++] - sigma; + } + else { // A(i,i) does not exist. + value[k++] = -sigma; + } + index[ki++] = i+1; + + // Copying subdiagonal elements of column i. + + while (j < end ) { + value[k++] = a[j]; + index[ki++] = irow[j++]+1; + } + + index[i+1] = k+1; + + } + +} // SubtractAsI. + + +template +inline void ARumNonSymMatrix::CreateStructure() +{ + + int dimfact = (((fillin+1)*nnz)<(this->n*this->n)) ? (fillin+1)*nnz : this->n*this->n; + + this->ClearMem(); + + lindex = 30*this->n+dimfact; // ????? + lvalue = dimfact; + + value = new ARTYPE[lvalue]; + index = new int[lindex]; + +} // CreateStructure. + + +template +inline void ARumNonSymMatrix::ThrowError() +{ + + if (info[0] < -2) { // Memory is not suficient. + throw ArpackError(ArpackError::INSUFICIENT_MEMORY, + "ARumNonSymMatrix::FactorA"); + } + else if (info[0] > 3) { // Matrix is singular. + throw ArpackError(ArpackError::MATRIX_IS_SINGULAR, + "ARumNonSymMatrix::FactorA"); + } + else if (info[0] != 0) { // Illegal argument. + throw ArpackError(ArpackError::PARAMETER_ERROR, + "ARumNonSymMatrix::FactorA"); + } + +} // ThrowError. + + +template +void ARumNonSymMatrix::FactorA() +{ + + // Quitting the function if A was not defined. + + if (!this->IsDefined()) { + throw ArpackError(ArpackError::DATA_UNDEFINED,"ARumNonSymMatrix::FactorA"); + } + + // Quitting the function if A is not square. + + if (this->m != this->n) { + throw ArpackError(ArpackError::NOT_SQUARE_MATRIX, + "ARumNonSymMatrix::FactorA"); + } + + // Defining local variables. + + int i; + int *pi, *pj; + + // Reserving memory for some vectors used in matrix decomposition. + + CreateStructure(); + + // Copying A to (value, index); + + copy(nnz, a, 1, value, 1); + pi=pcol; + pj=index; + for (i=0; i<=this->n; i++) *pj++ = (*pi++)+1; + pi=irow; + for (i=0; in, nnz, 0, false, lvalue, lindex, value, + index, keep, cntl, icntl, info, rinfo); + + // Handling errors. + + ThrowError(); + + factored = true; + +} // FactorA. + + +template +void ARumNonSymMatrix::FactorAsI(ARTYPE sigma) +{ + + // Quitting the function if A was not defined. + + if (!this->IsDefined()) { + throw ArpackError(ArpackError::DATA_UNDEFINED, + "ARumNonSymMatrix::FactorAsI"); + } + + // Quitting the function if A is not square. + + if (this->m != this->n) { + throw ArpackError(ArpackError::NOT_SQUARE_MATRIX, + "ARumNonSymMatrix::FactorAsI"); + } + + // Reserving memory for some vectors used in matrix decomposition. + + CreateStructure(); + + // Subtracting sigma*I from A. + + SubtractAsI(sigma); + + // Decomposing AsI. + + um2fa(this->n, nnz, 0, false, lvalue, lindex, value, + index, keep, cntl, icntl, info, rinfo); + + // Handling errors. + + ThrowError(); + + factored = true; + +} // FactorAsI. + + +template +void ARumNonSymMatrix::MultMv(ARTYPE* v, ARTYPE* w) +{ + + int i,j; + ARTYPE t; + + // Quitting the function if A was not defined. + + if (!this->IsDefined()) { + throw ArpackError(ArpackError::DATA_UNDEFINED, "ARumNonSymMatrix::MultMv"); + } + + // Determining w = M.v. + + for (i=0; i!=this->m; i++) w[i]=(ARTYPE)0; + + for (i=0; i!=this->n; i++) { + t = v[i]; + for (j=pcol[i]; j!=pcol[i+1]; j++) { + w[irow[j]] += t*a[j]; + } + } + +} // MultMv. + + +template +void ARumNonSymMatrix::MultMtv(ARTYPE* v, ARTYPE* w) +{ + + int i,j; + ARTYPE t; + + // Quitting the function if A was not defined. + + if (!this->IsDefined()) { + throw ArpackError(ArpackError::DATA_UNDEFINED,"ARumNonSymMatrix::MultMtv"); + } + + // Determining w = M'.v. + + for (i=0; i!=this->n; i++) { + t = (ARTYPE)0; + for (j=pcol[i]; j!=pcol[i+1]; j++) { + t += v[irow[j]]*a[j]; + } + w[i] = t; + } + +} // MultMtv. + + +template +void ARumNonSymMatrix::MultMtMv(ARTYPE* v, ARTYPE* w) +{ + + ARTYPE* t = new ARTYPE[this->m]; + + MultMv(v,t); + MultMtv(t,w); + + delete[] t; + +} // MultMtMv. + + +template +void ARumNonSymMatrix::MultMMtv(ARTYPE* v, ARTYPE* w) +{ + + ARTYPE* t = new ARTYPE[this->n]; + + MultMtv(v,t); + MultMv(t,w); + + delete[] t; + +} // MultMMtv. + + +template +void ARumNonSymMatrix::Mult0MMt0v(ARTYPE* v, ARTYPE* w) +{ + + MultMv(&v[this->m],w); + MultMtv(v,&w[this->m]); + +} // Mult0MMt0v. + + +template +void ARumNonSymMatrix::MultInvv(ARTYPE* v, ARTYPE* w) +{ + + // Quitting the function if A (or AsI) was not factored. + + if (!IsFactored()) { + throw ArpackError(ArpackError::NOT_FACTORED_MATRIX, + "ARumNonSymMatrix::MultInvv"); + } + + // Solving A.w = v (or AsI.w = v). + + ARTYPE* space = new ARTYPE[2*this->n]; + + um2so(this->n, 0, false, lvalue, lindex, value, index, + keep, v, w, space, cntl, icntl, info, rinfo); + + delete[] space; + +} // MultInvv. + + +template +inline void ARumNonSymMatrix:: +DefineMatrix(int np, int nnzp, ARTYPE* ap, int* irowp, + int* pcolp, double thresholdp, int fillinp, + bool simest, bool reducible, bool check) +{ + + // Defining member variables. + + this->m = np; + this->n = np; + nnz = nnzp; + a = ap; + irow = irowp; + pcol = pcolp; + pcol[this->n] = nnz; + fillin = (fillinp>2) ? fillinp : 2; + threshold = thresholdp; + value = NULL; + index = NULL; + + // Preparing umfpack. + + um21i(keep, cntl, icntl, threshold, simest, reducible); + + // Checking data. + + if ((check)&&(!DataOK())) { + throw ArpackError(ArpackError::INCONSISTENT_DATA, + "ARumNonSymMatrix::DefineMatrix"); + } + else { + this->defined = true; + } + +} // DefineMatrix (square). + + +template +inline void ARumNonSymMatrix:: +DefineMatrix(int mp, int np, int nnzp, ARTYPE* ap, int* irowp, int* pcolp) +{ + + // Defining member variables. + + this->m = mp; + this->n = np; + nnz = nnzp; + a = ap; + irow = irowp; + pcol = pcolp; + pcol[this->n] = nnz; + fillin = 0; + this->defined = true; + +} // DefineMatrix (rectangular). + + +template +inline ARumNonSymMatrix:: +ARumNonSymMatrix(int np, int nnzp, ARTYPE* ap, int* irowp, + int* pcolp, double thresholdp, int fillinp, + bool simest, bool reducible, bool check): ARMatrix(np) +{ + + factored = false; + DefineMatrix(np, nnzp, ap, irowp, pcolp, thresholdp, + fillinp, simest, reducible, check); + +} // Long constructor (square matrix). + + +template +inline ARumNonSymMatrix:: +ARumNonSymMatrix(int mp, int np, int nnzp, ARTYPE* ap, + int* irowp, int* pcolp) : ARMatrix(mp, np) +{ + + factored = false; + DefineMatrix(mp, np, nnzp, ap, irowp, pcolp); + +} // Long constructor (rectangular matrix). + + +template +ARumNonSymMatrix:: +ARumNonSymMatrix(const std::string& name, double thresholdp, int fillinp, + bool simest, bool reducible, bool check) +{ + + factored = false; + + try { + mat.Define(name); + } + catch (ArpackError) { // Returning from here if an error has occurred. + throw ArpackError(ArpackError::CANNOT_READ_FILE, "ARumNonSymMatrix"); + } + + if (mat.NCols()==mat.NRows()) { + DefineMatrix(mat.NCols(), mat.NonZeros(), (ARTYPE*)mat.Entries(), + mat.RowInd(), mat.ColPtr(), thresholdp, + fillinp, simest, reducible, check); + } + else { + DefineMatrix(mat.NRows(), mat.NCols(), mat.NonZeros(), + (ARTYPE*)mat.Entries(), mat.RowInd(), mat.ColPtr()); + } + +} // Long constructor (Harwell-Boeing file). + + +template +ARumNonSymMatrix& ARumNonSymMatrix:: +operator=(const ARumNonSymMatrix& other) +{ + + if (this != &other) { // Stroustrup suggestion. + ClearMem(); + Copy(other); + } + return *this; + +} // operator=. + + +#endif // ARUNSMAT_H diff --git a/external/arpack++/include/arunspen.h b/external/arpack++/include/arunspen.h new file mode 100644 index 000000000..771b3746d --- /dev/null +++ b/external/arpack++/include/arunspen.h @@ -0,0 +1,527 @@ +/* + ARPACK++ v1.2 2/20/2000 + c++ interface to ARPACK code. + + MODULE ARUNSPen.h. + Arpack++ class ARumNonSymPencil definition. + + ARPACK Authors + Richard Lehoucq + Danny Sorensen + Chao Yang + Dept. of Computational & Applied Mathematics + Rice University + Houston, Texas +*/ + +#ifndef ARUNSPEN_H +#define ARUNSPEN_H + +#include "arch.h" +#include "arerror.h" +#include "blas1c.h" +#include "umfpackc.h" +#include "arunsmat.h" + + +template +class ARumNonSymPencil +{ + + protected: + + char part; + ARumNonSymMatrix* A; + ARumNonSymMatrix* B; + ARumNonSymMatrix AsB; +#ifdef ARCOMP_H + ARumNonSymMatrix, ARFLOAT> AsBc; +#endif + + virtual void Copy(const ARumNonSymPencil& other); + + void SparseSaxpy(ARTYPE a, ARTYPE x[], int xind[], int nx, ARTYPE y[], + int yind[], int ny, ARTYPE z[], int zind[], int& nz); + +#ifdef ARCOMP_H + void SparseSaxpy(arcomplex a, ARFLOAT x[], int xind[], int nx, + ARFLOAT y[], int yind[], int ny, + arcomplex z[], int zind[], int& nz); +#endif + + void SubtractAsB(ARTYPE sigma); + +#ifdef ARCOMP_H + void SubtractAsB(ARFLOAT sigmaR, ARFLOAT sigmaI); +#endif + + public: + +#ifdef ARCOMP_H + bool IsFactored() { return (AsB.IsFactored()||AsBc.IsFactored()); } +#else + bool IsFactored() { return AsB.IsFactored(); } +#endif + + bool IsSymmetric() { return AsB.IsSymmetric(); } + + void FactorAsB(ARTYPE sigma); + +#ifdef ARCOMP_H + void FactorAsB(ARFLOAT sigmaR, ARFLOAT sigmaI, char partp = 'R'); +#endif + + void MultAv(ARTYPE* v, ARTYPE* w) { A->MultMv(v,w); } + + void MultBv(ARTYPE* v, ARTYPE* w) { B->MultMv(v,w); } + + void MultInvBAv(ARTYPE* v, ARTYPE* w); + +#ifdef ARCOMP_H + void MultInvAsBv(arcomplex* v, arcomplex* w); +#endif + + void MultInvAsBv(ARFLOAT* v, ARFLOAT* w); + + void DefineMatrices(ARumNonSymMatrix& Ap, + ARumNonSymMatrix& Bp); + + ARumNonSymPencil() { part = 'N'; } + // Short constructor that does nothing. + + ARumNonSymPencil(ARumNonSymMatrix& Ap, + ARumNonSymMatrix& Bp); + // Long constructor. + + ARumNonSymPencil(const ARumNonSymPencil& other) { Copy(other); } + // Copy constructor. + + virtual ~ARumNonSymPencil() { } + // Destructor. + + ARumNonSymPencil& operator=(const ARumNonSymPencil& other); + // Assignment operator. + +}; + +// ------------------------------------------------------------------------ // +// ARumNonSymPencil member functions definition. // +// ------------------------------------------------------------------------ // + + +template +inline void ARumNonSymPencil:: +Copy(const ARumNonSymPencil& other) +{ + + part = other.part; + A = other.A; + B = other.B; + AsB = other.AsB; +#ifdef ARCOMP_H + AsBc = other.AsBc; +#endif + +} // Copy. + + +template +void ARumNonSymPencil:: +SparseSaxpy(ARTYPE a, ARTYPE x[], int xind[], int nx, ARTYPE y[], + int yind[], int ny, ARTYPE z[], int zind[], int& nz) +// A strongly sequential (and inefficient) sparse saxpy algorithm. +{ + + int ix, iy; + + nz = 0; + if ((nx == 0) || (a == (ARTYPE)0)) { + copy(ny,y,1,z,1); + for (iy=0; iy!=ny; iy++) zind[iy] = yind[iy]; + nz = ny; + return; + } + if (ny == 0) { + copy(nx,x,1,z,1); + scal(nx,a,z,1); + for (ix=0; ix!=nx; ix++) zind[ix] = xind[ix]; + nz = nx; + return; + } + ix = 0; + iy = 0; + while (true) { + if (xind[ix] == yind[iy]) { + zind[nz] = xind[ix]; + z[nz++] = a*x[ix++]+y[iy++]; + if ((ix == nx)||(iy == ny)) break; + } + else if (xind[ix] < yind[iy]) { + zind[nz] = xind[ix]; + z[nz++] = a*x[ix++]; + if (ix == nx) break; + } + else { + zind[nz] = yind[iy]; + z[nz++] = y[iy++]; + if (iy == ny) break; + } + } + while (iy < ny) { + zind[nz] = yind[iy]; + z[nz++] = y[iy++]; + } + while (ix < nx) { + zind[nz] = xind[ix]; + z[nz++] = x[ix++]; + } + +} // SparseSaxpy (ARTYPE). + + +#ifdef ARCOMP_H +template +void ARumNonSymPencil:: +SparseSaxpy(arcomplex a, ARFLOAT x[], int xind[], int nx, + ARFLOAT y[], int yind[], int ny, + arcomplex z[], int zind[], int& nz) +// A strongly sequential (and inefficient) sparse saxpy algorithm. +{ + + int ix, iy; + + nz = 0; + if ((nx == 0) || (a == arcomplex(0.0,0.0))) { + for (iy=0; iy!=ny; iy++) { + z[iy] = arcomplex(y[iy],0.0); + zind[iy] = yind[iy]; + } + nz = ny; + return; + } + if (ny == 0) { + for (ix=0; ix!=ny; ix++) { + z[ix] = a*arcomplex(x[ix],0.0); + zind[ix] = xind[ix]; + } + nz = nx; + return; + } + ix = 0; + iy = 0; + while (true) { + if (xind[ix] == yind[iy]) { + zind[nz] = xind[ix]; + z[nz++] = a*x[ix++]+y[iy++]; + if ((ix == nx)||(iy == ny)) break; + } + else if (xind[ix] < yind[iy]) { + zind[nz] = xind[ix]; + z[nz++] = a*x[ix++]; + if (ix == nx) break; + } + else { + zind[nz] = yind[iy]; + z[nz++] = arcomplex(y[iy++], 0.0); + if (iy == ny) break; + } + } + while (iy < ny) { + zind[nz] = yind[iy]; + z[nz++] = arcomplex(y[iy++], 0.0); + } + while (ix < nx) { + zind[nz] = xind[ix]; + z[nz++] = arcomplex(x[ix++], 0.0); + } + +} // SparseSaxpy (arcomplex). +#endif // ARCOMP_H. + + +template +void ARumNonSymPencil::SubtractAsB(ARTYPE sigma) +{ + + int i, acol, bcol, asbcol, scol; + + // Subtracting sigma*B from A. + + AsB.index[0] = 0; + asbcol = 0; + + for (i=0; i!=AsB.n; i++) { + bcol = B->pcol[i]; + acol = A->pcol[i]; + SparseSaxpy(-sigma, &B->a[bcol], &B->irow[bcol], B->pcol[i+1]-bcol, + &A->a[acol], &A->irow[acol], A->pcol[i+1]-acol, + &AsB.value[asbcol], &AsB.index[asbcol+AsB.n+1], scol); + asbcol += scol; + AsB.index[i+1] = asbcol; + } + + AsB.nnz = asbcol; + + // Adding one to all elements of vector index + // because the decomposition function was written in FORTRAN. + + for (i=0; i<=AsB.n+AsB.nnz; i++) AsB.index[i]++; + +} // SubtractAsB (ARTYPE shift). + + +#ifdef ARCOMP_H +template +void ARumNonSymPencil:: +SubtractAsB(ARFLOAT sigmaR, ARFLOAT sigmaI) +{ + + int i, acol, bcol, asbcol, scol; + arcomplex sigma; + + // Subtracting sigma*B from A. + + sigma = arcomplex(sigmaR, sigmaI); + AsBc.index[0] = 0; + asbcol = 0; + + for (i=0; i!=AsBc.n; i++) { + bcol = B->pcol[i]; + acol = A->pcol[i]; + SparseSaxpy(-sigma, &B->a[bcol], &B->irow[bcol], B->pcol[i+1]-bcol, + &A->a[acol], &A->irow[acol], A->pcol[i+1]-acol, + &AsBc.value[asbcol], &AsBc.index[asbcol+AsBc.n+1], scol); + asbcol += scol; + AsBc.index[i+1] = asbcol; + } + + AsBc.nnz = asbcol; + + // Adding one to all elements of vector index + // because the decomposition function was written in FORTRAN. + + for (i=0; i<=AsBc.n+AsBc.nnz; i++) AsBc.index[i]++; + +} // SubtractAsB (arcomplex shift). +#endif // ARCOMP_H + + +template +void ARumNonSymPencil::FactorAsB(ARTYPE sigma) +{ + + // Quitting the function if A and B were not defined. + + if (!(A->IsDefined()&&B->IsDefined())) { + throw ArpackError(ArpackError::DATA_UNDEFINED, + "ARumNonSymPencil::FactorAsB"); + } + + // Quitting the function if A and B are not square. + + if ((A->nrows() != A->ncols()) || (B->nrows() != B->ncols())) { + throw ArpackError(ArpackError::NOT_SQUARE_MATRIX, + "ARumNonSymPencil::FactorAsB"); + } + + // Defining matrix AsB. + + if (!AsB.IsDefined()) { + + int fillin = A->fillin > B->fillin ? A->fillin : B->fillin; + AsB.DefineMatrix(A->ncols(), A->nzeros(), A->a, A->irow, + A->pcol, A->threshold, fillin, + (A->IsSymmetric() && B->IsSymmetric()), + A->icntl[3], false); + AsB.nnz = A->nzeros()+B->nzeros(); // temporary value. + + } + + // Reserving memory for some vectors used in matrix decomposition. + + AsB.CreateStructure(); // AsB.nnz must be set to A->nzeros()+B->nzeros(). + + // Subtracting sigma*B from A and storing the result on AsB. + + SubtractAsB(sigma); + + // Decomposing AsB. + + um2fa(AsB.n, AsB.index[AsB.n], 0, false, AsB.lvalue, AsB.lindex, AsB.value, + AsB.index, AsB.keep, AsB.cntl, AsB.icntl, AsB.info, AsB.rinfo); + + // Handling errors. + + AsB.ThrowError(); + + AsB.factored = true; + +} // FactorAsB (ARTYPE shift). + + +#ifdef ARCOMP_H +template +void ARumNonSymPencil:: +FactorAsB(ARFLOAT sigmaR, ARFLOAT sigmaI, char partp) +{ + + // Quitting the function if A and B were not defined. + + if (!(A->IsDefined()&&B->IsDefined())) { + throw ArpackError(ArpackError::DATA_UNDEFINED, + "ARumNonSymPencil::FactorAsB"); + } + + // Quitting the function if A and B are not square. + + if ((A->nrows() != A->ncols()) || (B->nrows() != B->ncols())) { + throw ArpackError(ArpackError::NOT_SQUARE_MATRIX, + "ARumNonSymPencil::FactorAsB"); + } + + // Defining matrix AsB. + + if (!AsBc.IsDefined()) { + + part = partp; + int fillin = A->fillin > B->fillin ? A->fillin : B->fillin; + AsBc.DefineMatrix(A->ncols(), A->nzeros(), 0, 0, + A->pcol, A->threshold, fillin, + (A->IsSymmetric() && B->IsSymmetric()), + A->icntl[3], false); + AsBc.nnz = A->nzeros()+B->nzeros(); // temporary value. + + } + + // Reserving memory for some vectors used in matrix decomposition. + + AsBc.CreateStructure(); // AsBc.nnz must be set to A->nzeros()+B->nzeros(). + + // Subtracting sigma*B from A and storing the result on AsBc. + + SubtractAsB(sigmaR, sigmaI); + + // Decomposing AsB. + + um2fa(AsBc.n, AsBc.index[AsBc.n], 0, false, AsBc.lvalue, AsBc.lindex, + AsBc.value, AsBc.index, AsBc.keep, AsBc.cntl, AsBc.icntl, + AsBc.info, AsBc.rinfo); + + // Handling errors. + + AsBc.ThrowError(); + + AsBc.factored = true; + +} // FactorAsB (arcomplex shift). +#endif // ARCOMP_H. + + +template +void ARumNonSymPencil::MultInvBAv(ARTYPE* v, ARTYPE* w) +{ + + if (!B->IsFactored()) B->FactorA(); + + A->MultMv(v, w); + B->MultInvv(w, w); + +} // MultInvBAv. + + +#ifdef ARCOMP_H + +template +void ARumNonSymPencil:: +MultInvAsBv(arcomplex* v, arcomplex* w) +{ + + AsB.MultInvv((ARTYPE*)v,(ARTYPE*)w); + +} // MultInvAsBv (arcomplex). + +#endif // ARCOMP_H. + + +template +void ARumNonSymPencil::MultInvAsBv(ARFLOAT* v, ARFLOAT* w) +{ + + if (part == 'N') { // shift is real. + + AsB.MultInvv((ARTYPE*)v,(ARTYPE*)w); + + } + else { // shift is complex. + +#ifdef ARCOMP_H + + int i; + arcomplex *tv, *tw; + + tv = new arcomplex[AsBc.ncols()]; + tw = new arcomplex[AsBc.ncols()]; + + for (i=0; i!=AsBc.ncols(); i++) tv[i] = arcomplex(v[i], 0.0); + + AsBc.MultInvv(tv, tw); + + if (part=='I') { + for (i=0; i!=AsBc.ncols(); i++) w[i] = imag(tw[i]); + } + else { + for (i=0; i!=AsBc.ncols(); i++) w[i] = real(tw[i]); + } + + delete[] tv; + delete[] tw; + +#endif // ARCOMP_H. + + } + +} // MultInvAsBv (ARFLOAT). + + +template +inline void ARumNonSymPencil:: +DefineMatrices(ARumNonSymMatrix& Ap, + ARumNonSymMatrix& Bp) +{ + + A = &Ap; + B = &Bp; + + if ((A->n != B->n)||(A->m != B->m)) { + throw ArpackError(ArpackError::INCOMPATIBLE_SIZES, + "ARumNonSymMatrix::DefineMatrices"); + } + +} // DefineMatrices. + + +template +inline ARumNonSymPencil:: +ARumNonSymPencil(ARumNonSymMatrix& Ap, + ARumNonSymMatrix& Bp) +{ + + DefineMatrices(Ap, Bp); + +} // Long constructor. + + +template +ARumNonSymPencil& ARumNonSymPencil:: +operator=(const ARumNonSymPencil& other) +{ + + if (this != &other) { // Stroustrup suggestion. + Copy(other); + } + return *this; + +} // operator=. + + +#endif // ARUNSPEN_H diff --git a/external/arpack++/include/aruscomp.h b/external/arpack++/include/aruscomp.h new file mode 100644 index 000000000..13ddff714 --- /dev/null +++ b/external/arpack++/include/aruscomp.h @@ -0,0 +1,166 @@ +/* + ARPACK++ v1.2 2/20/2000 + c++ interface to ARPACK code. + + MODULE ARUSComp.h. + Arpack++ class ARluCompStdEig definition + (umfpack version). + + ARPACK Authors + Richard Lehoucq + Danny Sorensen + Chao Yang + Dept. of Computational & Applied Mathematics + Rice University + Houston, Texas +*/ + +#ifndef ARUSCOMP_H +#define ARUSCOMP_H + +#include +#include +#include "arch.h" +#include "arscomp.h" +#include "arunsmat.h" +#include "arrseig.h" + + +template +class ARluCompStdEig: + public virtual ARCompStdEig, ARFLOAT> > { + + public: + + // a) Public functions: + + // a.1) Functions that allow changes in problem parameters. + + virtual void ChangeShift(arcomplex sigmaRp); + + virtual void SetRegularMode(); + + virtual void SetShiftInvertMode(arcomplex sigmap); + + // a.2) Constructors and destructor. + + ARluCompStdEig() { } + // Short constructor. + + ARluCompStdEig(int nevp, ARumNonSymMatrix, ARFLOAT>& A, + const std::string& whichp = "LM", int ncvp = 0, + ARFLOAT tolp = 0.0, int maxitp = 0, + arcomplex* residp = NULL, bool ishiftp = true); + // Long constructor (regular mode). + + ARluCompStdEig(int nevp, ARumNonSymMatrix, ARFLOAT>& A, + arcomplex sigma, const std::string& whichp = "LM", + int ncvp = 0, ARFLOAT tolp = 0.0, int maxitp = 0, + arcomplex* residp = NULL, bool ishiftp = true); + // Long constructor (shift and invert mode). + + ARluCompStdEig(const ARluCompStdEig& other) { Copy(other); } + // Copy constructor. + + virtual ~ARluCompStdEig() { } + // Destructor. + + + // b) Operators. + + ARluCompStdEig& operator=(const ARluCompStdEig& other); + // Assignment operator. + +}; // class ARluCompStdEig. + + +// ------------------------------------------------------------------------ // +// ARluCompStdEig member functions definition. // +// ------------------------------------------------------------------------ // + + +template +inline void ARluCompStdEig:: +ChangeShift(arcomplex sigmaRp) +{ + + this->objOP->FactorAsI(sigmaRp); + ARrcStdEig >::ChangeShift(sigmaRp); + +} // ChangeShift. + + +template +inline void ARluCompStdEig::SetRegularMode() +{ + + ARStdEig, + ARumNonSymMatrix, ARFLOAT> >:: + SetRegularMode(this->objOP, + &ARumNonSymMatrix, ARFLOAT>::MultMv); + +} // SetRegularMode. + + +template +inline void ARluCompStdEig:: +SetShiftInvertMode(arcomplex sigmap) +{ + + ARStdEig, + ARumNonSymMatrix, ARFLOAT> >:: + SetShiftInvertMode(sigmap, this->objOP, + &ARumNonSymMatrix,ARFLOAT>::MultInvv); + +} // SetShiftInvertMode. + + +template +inline ARluCompStdEig:: +ARluCompStdEig(int nevp, ARumNonSymMatrix, ARFLOAT>& A, + const std::string& whichp, int ncvp, ARFLOAT tolp, + int maxitp, arcomplex* residp, bool ishiftp) + +{ + + this->NoShift(); + DefineParameters(A.ncols(), nevp, &A, + &ARumNonSymMatrix, ARFLOAT>::MultMv, + whichp, ncvp, tolp, maxitp, residp, ishiftp); + +} // Long constructor (regular mode). + + +template +inline ARluCompStdEig:: +ARluCompStdEig(int nevp, ARumNonSymMatrix, ARFLOAT>& A, + arcomplex sigmap, const std::string& whichp, int ncvp, + ARFLOAT tolp, int maxitp, arcomplex* residp, + bool ishiftp) + +{ + + DefineParameters(A.ncols(), nevp, &A, + &ARumNonSymMatrix, ARFLOAT>::MultInvv, + whichp, ncvp, tolp, maxitp, residp, ishiftp); + ChangeShift(sigmap); + +} // Long constructor (shift and invert mode). + + +template +ARluCompStdEig& ARluCompStdEig:: +operator=(const ARluCompStdEig& other) +{ + + if (this != &other) { // Stroustrup suggestion. + this->ClearMem(); + Copy(other); + } + return *this; + +} // operator=. + + +#endif // ARUSCOMP_H diff --git a/external/arpack++/include/arusmat.h b/external/arpack++/include/arusmat.h new file mode 100644 index 000000000..f5dae63af --- /dev/null +++ b/external/arpack++/include/arusmat.h @@ -0,0 +1,743 @@ +/* + ARPACK++ v1.2 2/20/2000 + c++ interface to ARPACK code. + + MODULE ARUSMat.h. + Arpack++ class ARumSymMatrix definition. + + Modified to work with Umfpack v5.?? + Martin Reuter + Date 02/28/2013 + + Arpack++ Author: + Francisco Gomes + + ARPACK Authors + Richard Lehoucq + Danny Sorensen + Chao Yang + Dept. of Computational & Applied Mathematics + Rice University + Houston, Texas +*/ + + +#include "aruspen.h" + +#ifndef ARUSMAT_H +#define ARUSMAT_H + +#include +#include +#include "arch.h" +#include "armat.h" +#include "arhbmat.h" +#include "arerror.h" +//#include "blas1c.h" +#include "umfpackc.h" + +template class ARumSymPencil; + +template +class ARumSymMatrix: public ARMatrix { + + friend class ARumSymPencil; + + protected: + + bool factored; + char uplo; + int nnz; + /* int fillin; + int lvalue; + int lindex; + int keep[20]; + int icntl[20]; + int info[40]; + ARTYPE cntl[10]; + ARTYPE rinfo[20]; + int* index; + ARTYPE* value;*/ + int* irow; + int* pcol; + int status; + double threshold; + ARTYPE* a; + ARhbMatrix mat; + void* Numeric; + int* Ap; + int* Ai; + ARTYPE* Ax; + + bool DataOK(); + + virtual void Copy(const ARumSymMatrix& other); + + void ClearMem(); + + void ExpandA(ARTYPE sigma = (ARTYPE)0); + +// void CreateStructure(); + + void ThrowError(); + + public: + + int nzeros() { return nnz; } + +// int FillFact() { return fillin; } + + bool IsFactored() { return factored; } + + void FactorA(); + + void FactorAsI(ARTYPE sigma); + + void MultMv(ARTYPE* v, ARTYPE* w); + + void MultInvv(ARTYPE* v, ARTYPE* w); + + void DefineMatrix(int np, int nnzp, ARTYPE* ap, int* irowp, + int* pcolp, char uplop = 'L', double thresholdp = 0.1, + int fillinp = 9, bool reducible = true, bool check = true); + + ARumSymMatrix(): ARMatrix() + { + factored = false; + Numeric = NULL; + Ap = NULL; + Ai = NULL; + Ax = NULL; + } + // Short constructor that does nothing. + + ARumSymMatrix(int np, int nnzp, ARTYPE* ap, int* irowp, + int* pcolp, char uplop = 'L', double thresholdp = 0.1, + int fillinp = 9, bool reducible = true, bool check = true); + // Long constructor. + + ARumSymMatrix(const std::string& name, double thresholdp = 0.1, int fillinp = 9, + bool reducible = true, bool check = true); + // Long constructor (Harwell-Boeing file). + + ARumSymMatrix(const ARumSymMatrix& other) { Copy(other); } + // Copy constructor. + + virtual ~ARumSymMatrix() { ClearMem(); } + // Destructor. + + ARumSymMatrix& operator=(const ARumSymMatrix& other); + // Assignment operator. + +}; + +// ------------------------------------------------------------------------ // +// ARumSymMatrix member functions definition. // +// ------------------------------------------------------------------------ // + + +template +bool ARumSymMatrix::DataOK() +{ + + int i, j, k; + + // Checking if pcol is in ascending order. + + i = 0; + while ((i!=this->n)&&(pcol[i]<=pcol[i+1])) i++; + if (i!=this->n) return false; + + // Checking if irow components are in order and within bounds. + + for (i=0; i!=this->n; i++) { + j = pcol[i]; + k = pcol[i+1]-1; + if (j<=k) { + if (uplo == 'U') { + if ((irow[j]<0)||(irow[k]>i)) return false; + } + else { // uplo == 'L'. + if ((irow[j]=this->n)) return false; + } + while ((j!=k)&&(irow[j] +inline void ARumSymMatrix::ClearMem() +{ + + if (factored) + { + if (Numeric) umfpack_di_free_numeric (&Numeric); + //if (value) delete[] value; + //if (index) delete[] index; + //value = NULL; + //index = NULL; + if (Ai) delete [] Ai; + Ai = NULL; + if (Ap) delete [] Ap; + Ap = NULL; + if (Ax) delete [] Ax; + Ax = NULL; + } + +} // ClearMem. + + + +template +void ARumSymMatrix::Copy(const ARumSymMatrix& other) +{ + + // Copying very fundamental variables. + ClearMem(); + + // Copying very fundamental variables and user-defined parameters. + + this->m = other.m; + this->n = other.n; + this->defined = other.defined; + factored = other.factored; + //fillin = other.fillin; + nnz = other.nnz; + //lvalue = other.lvalue; + //lindex = other.lindex; + irow = other.irow; + pcol = other.pcol; + a = other.a; + threshold = other.threshold; + uplo = other.uplo; + + // Returning from here if "other" was not initialized. + + if (!this->defined) return; + + // Returning from here if "other" was not factored. + + if (!factored) return; + + factored = false; + +} // Copy. + +template +void ARumSymMatrix::ExpandA(ARTYPE sigma) +{ +std::cout <<"ARumSymMatrix::ExpandA(" << sigma << ") ..." << std::flush; + + ClearMem(); + + // Checking if sigma is zero. + bool subtract = (sigma != (ARTYPE)0); + + int mynnz = 2*nnz; + if (subtract) mynnz = 2*nnz + this->n; // some space for the diag entries just in case + + // create triples (i,j,value) + int * tripi = new int[mynnz]; + int * tripj = new int[mynnz]; + ARTYPE* tripx = new ARTYPE[mynnz]; + int count = 0; + int i,j; +// if (uplo == 'U') + { + for (i=0; i != this->n; i++) + { + bool founddiag = false; + for (j=pcol[i]; j<(pcol[i+1]); j++) + { + + if (i == irow[j]) // on diag + { + tripi[count] = i; + tripj[count] = irow[j]; + if (subtract) + { + tripx[count] = a[j]-sigma; + founddiag = true; + } + else tripx[count] = a[j]; + count++; + } + else + { + + tripi[count] = i; + tripj[count] = irow[j]; + tripx[count] = a[j]; + count++; + tripj[count] = i; + tripi[count] = irow[j]; + tripx[count] = a[j]; + count++; + } + } + if (subtract && ! founddiag) + { + tripi[count] = i; + tripj[count] = i; + tripx[count] = -sigma; + count++; + } + } + } + + // convert triples to Ax Ap Ai + Ap = new int[this->n+1]; + Ai = new int[count]; + Ax = new ARTYPE[count]; + status = umfpack_di_triplet_to_col (this->n, this->n, count, tripi, tripj, tripx, Ap, Ai, Ax, (int *)NULL) ; + if (status != UMFPACK_OK) + throw ArpackError(ArpackError::PARAMETER_ERROR, "ARumSymMatrix::ExpandA"); + if (Ap[this->n] != count) + throw ArpackError(ArpackError::PARAMETER_ERROR, "ARumSymMatrix::ExpandA"); + + + // cleanup + delete [] tripi; + delete [] tripj; + delete [] tripx; + + //std::cout << std::endl << std::endl; + //double Control [UMFPACK_CONTROL]; + //Control [UMFPACK_PRL] = 3; + //status = umfpack_di_report_matrix(this->n, this->n,Ap, Ai, Ax,0,Control); + //std::cout << " status: " << status << std::endl; + //std::cout << std::endl << std::endl; + + std::cout <<" done!" << std::endl; + +} + +/*template +void ARumSymMatrix::ExpandA(ARTYPE sigma) +{ + + bool subtract; + int i, j, k, ki; + + // Checking if sigma is zero. + + subtract = (sigma != (ARTYPE)0); + + // Filling index with zeros. + + for (i=0; i<=this->n; i++) index[i] = 0; + + // Counting the elements in each column of A. + + if (uplo == 'U') { + + for (i=0; i!=this->n; i++) { + k = pcol[i+1]; + if ((k!=pcol[i])&&(irow[k-1]==i)) { + k--; + } + else { + if (subtract) index[i]++; + } + for (j=pcol[i]; jn; i++) { + k = pcol[i]; + if ((k!=pcol[i+1])&&(irow[k]==i)) { + k++; + } + else { + if (subtract) index[i]++; + } + for (j=k; jn; i++) index[i+1]+=index[i]; + + // Adding pcol to index. + + for (i=this->n; i>0; i--) index[i] = index[i-1]+pcol[i]; + index[0] = pcol[0]; + + // Expanding A. + + ki = this->n+1; + + if (uplo == 'U') { + + for (i=0; in; i++) { + for (j=pcol[i]; j<(pcol[i+1]-1); j++) { + index[ki+index[i]] = irow[j]+1; + index[ki+index[irow[j]]] = i+1; + value[index[i]++] = a[j]; + value[index[irow[j]]++] = a[j]; + } + if ((pcol[i]!=pcol[i+1])&&(irow[j]==i)) { + index[ki+index[i]] = i+1; + if (subtract) { + value[index[i]++] = a[j]-sigma; + } + else { + value[index[i]++] = a[j]; + } + } + else { + if (subtract) { + index[ki+index[i]] = i+1; + value[index[i]++] = -sigma; + } + } + } + + } + else { // uplo == 'L' + + for (i=0; in; i++) { + k=pcol[i]; + if ((k!=pcol[i+1])&&(irow[k]==i)) { + index[ki+index[i]] = i+1; + if (subtract) { + value[index[i]++] = a[k]-sigma; + } + else { + value[index[i]++] = a[k]; + } + k++; + } + else { + if (subtract) { + index[ki+index[i]] = i+1; + value[index[i]++] = -sigma; + } + } + for (j=k; jn; i>0; i--) { + index[i] = index[i-1]+1; + } + index[0] = 1; + +} // ExpandA.*/ + + +/*template +inline void ARumSymMatrix::CreateStructure() +{ + + int dimfact = (((fillin+1)*nnz*2)<(this->n*this->n)) ? (fillin+1)*nnz*2 : this->n*this->n; + + ClearMem(); + + lindex = 30*this->n+dimfact; // ????? + lvalue = dimfact; + + value = new ARTYPE[lvalue]; + index = new int[lindex]; + +} // CreateStructure. +*/ + +template +inline void ARumSymMatrix::ThrowError() +{ + + if (status== -1) { // Memory is not suficient. + throw ArpackError(ArpackError::INSUFICIENT_MEMORY, + "ARumSymMatrix::FactorA"); + } + else if (status == 1) { // Matrix is singular. + throw ArpackError(ArpackError::MATRIX_IS_SINGULAR, + "ARumSymMatrix::FactorA"); + } + else if (status != 0) { // Illegal argument. + throw ArpackError(ArpackError::PARAMETER_ERROR, + "ARumSymMatrix::FactorA"); + } + +} // ThrowError. + + +template +void ARumSymMatrix::FactorA() +{ + +std::cout <<"ARumSymMatrix::FactorA " << std::endl; + + // Quitting the function if A was not defined. + if (!this->IsDefined()) { + throw ArpackError(ArpackError::DATA_UNDEFINED, "ARumSymMatrix::FactorA"); + } + + ExpandA(); // create Ap Ai Ax + + void *Symbolic ; + status = umfpack_di_symbolic (this->n, this->n, Ap, Ai, Ax, &Symbolic, NULL, NULL) ; + ThrowError(); + status = umfpack_di_numeric (Ap, Ai, Ax, Symbolic, &Numeric, NULL, NULL) ; + ThrowError(); + umfpack_di_free_symbolic (&Symbolic) ; + +/* + + // Reserving memory for some vectors used in matrix decomposition. + + CreateStructure(); + + // Copying A to (value, index); + + ExpandA(); + + // Decomposing A. + + um2fa(this->n, index[this->n], 0, false, lvalue, lindex, value, + index, keep, cntl, icntl, info, rinfo); +*/ + + factored = true; + +} // FactorA. + + +template +void ARumSymMatrix::FactorAsI(ARTYPE sigma) +{ +std::cout <<"ARumSymMatrix::FactorAsI " << sigma << std::endl; + + // Quitting the function if A was not defined. + if (!this->IsDefined()) { + throw ArpackError(ArpackError::DATA_UNDEFINED, "ARumSymMatrix::FactorAsI"); + } + + // Reserving memory for some vectors used in matrix decomposition. + //CreateStructure(); + + // Subtracting sigma*I from A. + ExpandA(sigma); + + // Decomposing AsI. + double Info [UMFPACK_INFO], Control [UMFPACK_CONTROL]; + umfpack_di_defaults (Control) ; + //std::cout << " Ap[n] = " << Ap[this->n] << std::flush; + + void *Symbolic ; + status = umfpack_di_symbolic (this->n, this->n, Ap, Ai, Ax, &Symbolic, Control, Info) ; + //std::cout << " symbolic status: " << status << std::endl; + ThrowError(); + status = umfpack_di_numeric (Ap, Ai, Ax, Symbolic, &Numeric, NULL, NULL) ; + //std::cout << " numeric status: " << status << std::endl; + ThrowError(); + umfpack_di_free_symbolic (&Symbolic) ; + +// // Decomposing AsI. +// um2fa(this->n, index[this->n], 0, false, lvalue, lindex, value, +// index, keep, cntl, icntl, info, rinfo); + + + factored = true; + +} // FactorAsI. + + +template +void ARumSymMatrix::MultMv(ARTYPE* v, ARTYPE* w) +{ +//std::cout <<"ARumSymMatrix::MultMv ..." << std::flush; + + int i,j,k; + ARTYPE t; + + // Quitting the function if A was not defined. + + if (!this->IsDefined()) { + throw ArpackError(ArpackError::DATA_UNDEFINED, "ARumSymMatrix::MultMv"); + } + + // Determining w = M.v. + + for (i=0; i!=this->m; i++) w[i]=(ARTYPE)0; + + if (uplo == 'U') { + + for (i=0; i!=this->n; i++) { + t = v[i]; + k = pcol[i+1]; + if ((k!=pcol[i])&&(irow[k-1]==i)) { + w[i] += t*a[k-1]; + k--; + } + for (j=pcol[i]; jn; i++) { + t = v[i]; + k = pcol[i]; + if ((k!=pcol[i+1])&&(irow[k]==i)) { + w[i] += t*a[k]; + k++; + } + for (j=k; j +void ARumSymMatrix::MultInvv(ARTYPE* v, ARTYPE* w) +{ +//std::cout <<"ARumSymMatrix::MultInvv ..." << std::flush; + + // Quitting the function if A (or AsI) was not factored. + + if (!IsFactored()) { + throw ArpackError(ArpackError::NOT_FACTORED_MATRIX, + "ARumSymMatrix::MultInvv"); + } + + // Solving A.w = v (or AsI.w = v). + +// ARTYPE* space = new ARTYPE[2*this->n]; +// um2so(this->n, 0, false, lvalue, lindex, value, index, +// keep, v, w, space, cntl, icntl, info, rinfo); +// delete[] space; + + status = umfpack_di_solve (UMFPACK_A, Ap, Ai, Ax, w, v, Numeric, NULL, NULL) ; + if (status != UMFPACK_OK) + throw ArpackError(ArpackError::PARAMETER_ERROR, "ARumSymMatrix::MultInvv"); + +} // MultInvv. + + +template +inline void ARumSymMatrix:: +DefineMatrix(int np, int nnzp, ARTYPE* ap, int* irowp, + int* pcolp, char uplop, double thresholdp, + int fillinp, bool reducible, bool check) +{ + + this->m = np; + this->n = np; + nnz = nnzp; + a = ap; + irow = irowp; + pcol = pcolp; + pcol[this->n] = nnz; + uplo = uplop; +// fillin = (fillinp>2) ? fillinp : 2; + threshold = thresholdp; +// value = NULL; +// index = NULL; + +// // Preparing umfpack. +// +// um21i(keep, cntl, icntl, threshold, true, reducible); + + // Checking data. + if ((check)&&(!DataOK())) { + throw ArpackError(ArpackError::INCONSISTENT_DATA, + "ARumSymMatrix::DefineMatrix"); + } + + this->defined = true; + +} // DefineMatrix. + + +template +inline ARumSymMatrix:: +ARumSymMatrix(int np, int nnzp, ARTYPE* ap, int* irowp, + int* pcolp, char uplop, double thresholdp, + int fillinp, bool reducible, bool check) : ARMatrix(np) +{ + Numeric = NULL; + Ap = NULL; + Ai = NULL; + Ax = NULL; + factored = false; + DefineMatrix(np, nnzp, ap, irowp, pcolp, uplop, + thresholdp, fillinp, reducible, check); + +} // Long constructor. + + +template +ARumSymMatrix:: +ARumSymMatrix(const std::string& file, double thresholdp, int fillinp, + bool reducible, bool check) +{ + Numeric = NULL; + Ap = NULL; + Ai = NULL; + Ax = NULL; + + factored = false; + + try { + mat.Define(file); + } + catch (ArpackError) { // Returning from here if an error has occurred. + throw ArpackError(ArpackError::CANNOT_READ_FILE, "ARumSymMatrix"); + } + + if ((mat.NCols() == mat.NRows()) && (mat.IsSymmetric())) { + + DefineMatrix(mat.NCols(), mat.NonZeros(), (ARTYPE*)mat.Entries(), + mat.RowInd(), mat.ColPtr(), 'L', thresholdp, + fillinp, reducible, check); + } + else { + throw ArpackError(ArpackError::INCONSISTENT_DATA, + "ARumSymMatrix::ARluSymMatrix"); + } + +} // Long constructor (Harwell-Boeing file). + + +template +ARumSymMatrix& ARumSymMatrix:: +operator=(const ARumSymMatrix& other) +{ + + if (this != &other) { // Stroustrup suggestion. + ClearMem(); + Copy(other); + } + return *this; + +} // operator=. + + +#endif // ARUSMAT_H diff --git a/external/arpack++/include/arusnsym.h b/external/arpack++/include/arusnsym.h new file mode 100644 index 000000000..644ee27df --- /dev/null +++ b/external/arpack++/include/arusnsym.h @@ -0,0 +1,162 @@ +/* + ARPACK++ v1.2 2/20/2000 + c++ interface to ARPACK code. + + MODULE ARUSNSym.h. + Arpack++ class ARluNonSymStdEig definition + (umfpack version). + + ARPACK Authors + Richard Lehoucq + Danny Sorensen + Chao Yang + Dept. of Computational & Applied Mathematics + Rice University + Houston, Texas +*/ + +#ifndef ARUSNSYM_H +#define ARUSNSYM_H + +#include +#include +#include "arch.h" +#include "arsnsym.h" +#include "arunsmat.h" + + +template +class ARluNonSymStdEig: + public virtual ARNonSymStdEig > { + + public: + + // a) Public functions: + + // a.1) Functions that allow changes in problem parameters. + + virtual void ChangeShift(ARFLOAT sigmaRp); + + virtual void SetRegularMode(); + + virtual void SetShiftInvertMode(ARFLOAT sigmap); + + // a.2) Constructors and destructor. + + ARluNonSymStdEig() { } + // Short constructor. + + ARluNonSymStdEig(int nevp, ARumNonSymMatrix& A, + const std::string& whichp = "LM", int ncvp = 0, + ARFLOAT tolp = 0.0, int maxitp = 0, + ARFLOAT* residp = NULL, bool ishiftp = true); + // Long constructor (regular mode). + + ARluNonSymStdEig(int nevp, ARumNonSymMatrix& A, + ARFLOAT sigma, const std::string& whichp = "LM", int ncvp = 0, + ARFLOAT tolp = 0.0, int maxitp = 0, + ARFLOAT* residp = NULL, bool ishiftp = true); + // Long constructor (shift and invert mode). + + ARluNonSymStdEig(const ARluNonSymStdEig& other) { Copy(other); } + // Copy constructor. + + virtual ~ARluNonSymStdEig() { } + // Destructor. + + // b) Operators. + + ARluNonSymStdEig& operator=(const ARluNonSymStdEig& other); + // Assignment operator. + +}; // class ARluNonSymStdEig. + + +// ------------------------------------------------------------------------ // +// ARluNonSymStdEig member functions definition. // +// ------------------------------------------------------------------------ // + + +template +inline void ARluNonSymStdEig::ChangeShift(ARFLOAT sigmaRp) +{ + + this->sigmaR = sigmaRp; + this->sigmaI = 0.0; + this->mode = 3; + this->iparam[7] = this->mode; + + this->objOP->FactorAsI(this->sigmaR); + this->Restart(); + +} // ChangeShift. + + +template +inline void ARluNonSymStdEig::SetRegularMode() +{ + + ARStdEig >:: + SetRegularMode(this->objOP, &ARumNonSymMatrix::MultMv); + +} // SetRegularMode. + + +template +inline void ARluNonSymStdEig::SetShiftInvertMode(ARFLOAT sigmap) +{ + + ARStdEig >:: + SetShiftInvertMode(sigmap, this->objOP, + &ARumNonSymMatrix::MultInvv); + +} // SetShiftInvertMode. + + +template +inline ARluNonSymStdEig:: +ARluNonSymStdEig(int nevp, ARumNonSymMatrix& A, + const std::string& whichp, int ncvp, ARFLOAT tolp, + int maxitp, ARFLOAT* residp, bool ishiftp) + +{ + + this->NoShift(); + DefineParameters(A.ncols(), nevp, &A, + &ARumNonSymMatrix::MultMv, + whichp, ncvp, tolp, maxitp, residp, ishiftp); + +} // Long constructor (regular mode). + + +template +inline ARluNonSymStdEig:: +ARluNonSymStdEig(int nevp, ARumNonSymMatrix& A, + ARFLOAT sigmap, const std::string& whichp, int ncvp, ARFLOAT tolp, + int maxitp, ARFLOAT* residp, bool ishiftp) + +{ + + DefineParameters(A.ncols(), nevp, &A, + &ARumNonSymMatrix::MultInvv, + whichp, ncvp, tolp, maxitp, residp, ishiftp); + ChangeShift(sigmap); + +} // Long constructor (shift and invert mode). + + +template +ARluNonSymStdEig& ARluNonSymStdEig:: +operator=(const ARluNonSymStdEig& other) +{ + + if (this != &other) { // Stroustrup suggestion. + this->ClearMem(); + Copy(other); + } + return *this; + +} // operator=. + + +#endif // ARUSNSYM_H diff --git a/external/arpack++/include/aruspen.h b/external/arpack++/include/aruspen.h new file mode 100644 index 000000000..bd2a59945 --- /dev/null +++ b/external/arpack++/include/aruspen.h @@ -0,0 +1,543 @@ +/* + ARPACK++ v1.2 2/20/2000 + c++ interface to ARPACK code. + + MODULE ARUSPen.h. + Arpack++ class ARumSymPencil definition. + + Modified to work with Umfpack v5.?? + Martin Reuter + Date 02/28/2013 + + Arpack++ Author: + Francisco Gomes + + + ARPACK Authors + Richard Lehoucq + Danny Sorensen + Chao Yang + Dept. of Computational & Applied Mathematics + Rice University + Houston, Texas +*/ + +#ifndef ARUSPEN_H +#define ARUSPEN_H + +//#include "arch.h" +//#include "arerror.h" +//#include "lapackc.h" +#include "arusmat.h" +#include "blas1c.h" + + +template +class ARumSymPencil +{ + + protected: + + ARumSymMatrix* A; + ARumSymMatrix* B; + //ARumSymMatrix AsB; + void* Numeric; + int* Ap; + int* Ai; + ARTYPE* Ax; + + virtual void Copy(const ARumSymPencil& other); + +// void SparseSaxpy(ARTYPE a, ARTYPE x[], int xind[], int nx, ARTYPE y[], +// int yind[], int ny, ARTYPE z[], int zind[], int& nz); + + void ExpandAsB(ARTYPE sigma); + +// void SubtractAsB(ARTYPE sigma); + void ClearMem(); + + public: + + bool IsFactored() { return (Numeric != NULL); } + + void FactorAsB(ARTYPE sigma); + + void MultAv(ARTYPE* v, ARTYPE* w) { A->MultMv(v,w); } + + void MultBv(ARTYPE* v, ARTYPE* w) { B->MultMv(v,w); } + + void MultInvBAv(ARTYPE* v, ARTYPE* w); + + //void MultInvAsBv(ARTYPE* v, ARTYPE* w) { AsB.MultInvv(v,w); } + void MultInvAsBv(ARTYPE* v, ARTYPE* w); + + void DefineMatrices(ARumSymMatrix& Ap, ARumSymMatrix& Bp); + + //ARumSymPencil() { AsB.factored = false; } + ARumSymPencil() { Numeric = NULL; Ap = NULL; Ai = NULL; Ax = NULL; } + // Short constructor that does nothing. + + ARumSymPencil(ARumSymMatrix& Ap, ARumSymMatrix& Bp); + // Long constructor. + + ARumSymPencil(const ARumSymPencil& other) { Copy(other); } + // Copy constructor. + + virtual ~ARumSymPencil() { } + // Destructor. + + ARumSymPencil& operator=(const ARumSymPencil& other); + // Assignment operator. + +}; + +// ------------------------------------------------------------------------ // +// ARumSymPencil member functions definition. // +// ------------------------------------------------------------------------ // + + +template +inline void ARumSymPencil::ClearMem() +{ + + if (Numeric) umfpack_di_free_numeric (&Numeric); + if (Ai) delete [] Ai; + Ai = NULL; + if (Ap) delete [] Ap; + Ap = NULL; + if (Ax) delete [] Ax; + Ax = NULL; + +} // ClearMem. + + + +template +inline void ARumSymPencil::Copy(const ARumSymPencil& other) +{ + ClearMem(); + A = other.A; + B = other.B; +// AsB = other.AsB; + +} // Copy. + + +/*template +void ARumSymPencil:: +SparseSaxpy(ARTYPE a, ARTYPE x[], int xind[], int nx, ARTYPE y[], + int yind[], int ny, ARTYPE z[], int zind[], int& nz) +// A strongly sequential (and inefficient) sparse saxpy algorithm. +{ + + int ix, iy; + + nz = 0; + if ((nx == 0) || (a == (ARTYPE)0)) { + copy(ny,y,1,z,1); + for (iy=0; iy!=ny; iy++) zind[iy] = yind[iy]; + nz = ny; + return; + } + if (ny == 0) { + copy(nx,x,1,z,1); + scal(nx,a,z,1); + for (ix=0; ix!=nx; ix++) zind[ix] = xind[ix]; + nz = nx; + return; + } + ix = 0; + iy = 0; + while (true) { + if (xind[ix] == yind[iy]) { + zind[nz] = xind[ix]; + z[nz++] = a*x[ix++]+y[iy++]; + if ((ix == nx)||(iy == ny)) break; + } + else if (xind[ix] < yind[iy]) { + zind[nz] = xind[ix]; + z[nz++] = a*x[ix++]; + if (ix == nx) break; + } + else { + zind[nz] = yind[iy]; + z[nz++] = y[iy++]; + if (iy == ny) break; + } + } + while (iy < ny) { + zind[nz] = yind[iy]; + z[nz++] = y[iy++]; + } + while (ix < nx) { + zind[nz] = xind[ix]; + z[nz++] = x[ix++]; + } + +} // SparseSaxpy. + + +template +void ARumSymPencil::ExpandAsB() +{ + + int i, j, k, n; + int *pcol, *irow, *index, *pos; + ARTYPE *value; + + // Initializing variables. + + n = AsB.n; + index = AsB.index; + value = AsB.value; + irow = &index[n+1]; + pcol = new int[AsB.n+1]; + pos = new int[AsB.n+1]; + for (i=0; i<=n; i++) pcol[i] = index[i]; + for (i=0; i<=n; i++) pos[i] = 0; + + // Counting the elements in each column of AsB. + + if (AsB.uplo == 'U') { + + for (i=0; i!=n; i++) { + k = pcol[i+1]; + if ((k!=pcol[i])&&(irow[k-1]==i)) k--; + for (j=pcol[i]; j0; i--) index[i] += pos[i-1]; + + // Expanding A. + + if (AsB.uplo == 'U') { + + for (i=n-1; i>=0; i--) { + pos[i] = index[i]+pcol[i+1]-pcol[i]; + k = pos[i]-1; + for (j=pcol[i+1]-1; j>=pcol[i]; j--) { + value[k] = value[j]; + irow[k--] = irow[j]; + } + } + for (i=1; iindex[i])&&(irow[k-1]==i)) k--; + for (j=index[i]; j=0; i--) { + k = index[i+1]-1; + for (j=pcol[i+1]-1; j>=pcol[i]; j--) { + value[k] = value[j]; + irow[k--] = irow[j]; + } + pos[i] = index[i]; + } + for (i=0; i<(n-1); i++) { + k = index[i+1]-pcol[i+1]+pcol[i]; + if ((k +void ARumSymPencil::SubtractAsB(ARTYPE sigma) +{ + + int i, acol, bcol, asbcol, scol; + + // Quitting function if A->uplo is not equal to B->uplo. + + if ((A->uplo != B->uplo)&&(sigma != (ARTYPE)0)) { + throw ArpackError(ArpackError::DIFFERENT_TRIANGLES, + "ARumSymPencil::SubtractAsB"); + } + AsB.uplo = A->uplo; + + // Subtracting sigma*B from A. + + AsB.index[0] = 0; + asbcol = 0; + + for (i=0; i!=AsB.n; i++) { + bcol = B->pcol[i]; + acol = A->pcol[i]; + SparseSaxpy(-sigma, &B->a[bcol], &B->irow[bcol], B->pcol[i+1]-bcol, + &A->a[acol], &A->irow[acol], A->pcol[i+1]-acol, + &AsB.value[asbcol], &AsB.index[asbcol+AsB.n+1], scol); + asbcol += scol; + AsB.index[i+1] = asbcol; + } + + // Expanding AsB. + + ExpandAsB(); + + // Adding one to all elements of vector index + // because the decomposition function was written in FORTRAN. + + for (i=0; i<=AsB.n+AsB.nnz; i++) AsB.index[i]++; + +} // SubtractAsB. */ + + +template +void ARumSymPencil::ExpandAsB(ARTYPE sigma) +{ +std::cout <<"ARumSymPencil::ExpandAsB(" << sigma << ") ..." << std::flush; + + ClearMem(); + + int mynnz = 2*A->nnz+2*B->nnz; + if (sigma == 0.0) + mynnz = 2*A->nnz; + + // create triples (i,j,value) + int * tripi = new int[mynnz]; + int * tripj = new int[mynnz]; + ARTYPE* tripx = new ARTYPE[mynnz]; + if (tripi == NULL || tripj == NULL || tripx ==NULL) + throw ArpackError(ArpackError::PARAMETER_ERROR, "ARumSymPencil::ExpandAsB out of memory (1)"); + + int count = 0; + int i,j; + for (i=0; i < A->n; i++) + { + // create triplets from A + for (j=A->pcol[i]; j<(A->pcol[i+1]); j++) + { + tripi[count] = i; + tripj[count] = A->irow[j]; + tripx[count] = A->a[j]; + count++; + if (i != A->irow[j]) // not on diag + { + tripj[count] = i; + tripi[count] = A->irow[j]; + tripx[count] = A->a[j]; + count++; + } + } + + if (sigma != 0.0) + { + // create triplets from -sigma B + for (j=B->pcol[i]; j<(B->pcol[i+1]); j++) + { + tripi[count] = i; + tripj[count] = B->irow[j]; + tripx[count] = -sigma * B->a[j]; + count++; + if (i != B->irow[j]) // not on diag + { + tripj[count] = i; + tripi[count] = B->irow[j]; + tripx[count] = tripx[count-1]; + count++; + } + } + } + + } + + //Write_Triplet_Matrix("A-aruspen.asc",tripi,tripj,tripx,count); + + std::cout<< " ( N = " << A->n << " NNZ = " << count << " )" << std::flush; + //std::cout<< " size double " << sizeof(double) << " size ARTYPE " << sizeof(ARTYPE) << std::endl; + // convert triples (A-sigma B) to Ax Ap Ai + Ap = new int[A->n + 1]; + Ai = new int[count]; + Ax = new ARTYPE[count]; + if (!Ap || !Ai || !Ax ) + throw ArpackError(ArpackError::PARAMETER_ERROR, "ARumSymPencil::ExpandAsB out of memory (2)"); + + int status = umfpack_di_triplet_to_col (A->n, A->n, count, tripi, tripj, tripx, Ap, Ai, Ax, (int *)NULL) ; + if (status != UMFPACK_OK) + throw ArpackError(ArpackError::PARAMETER_ERROR, "ARumSymPencil::ExpandAsB triplet to col"); + + // cleanup + delete [] tripi; + delete [] tripj; + delete [] tripx; + + //std::cout << std::endl << std::endl; + //double Control [UMFPACK_CONTROL]; + //Control [UMFPACK_PRL] = 3; + //status = umfpack_di_report_matrix(A->n, A->n,Ap, Ai, Ax,0,Control); + //std::cout << " status: " << status << std::endl; + //std::cout << std::endl << std::endl; + + std::cout <<" done!" << std::endl; +} + +template +void ARumSymPencil::FactorAsB(ARTYPE sigma) +{ + + // Quitting the function if A and B were not defined. + + if (!(A->IsDefined()&&B->IsDefined())) { + throw ArpackError(ArpackError::DATA_UNDEFINED, + "ARumSymPencil::FactorAsB"); + } + + + // Subtracting sigma*B from A and storing the result + ExpandAsB(sigma); + + // Decomposing AsB. + double Info [UMFPACK_INFO], Control [UMFPACK_CONTROL]; + umfpack_di_defaults (Control) ; + //std::cout <<" loaded defaults" << std::endl; + void *Symbolic ; + int status = umfpack_di_symbolic (A->n, A->n, Ap, Ai, Ax, &Symbolic, Control, Info) ; + std::cout << " symbolic status: " << status << std::endl; + if (status != UMFPACK_OK) + throw ArpackError(ArpackError::PARAMETER_ERROR, "ARumSymPencil::FactorAsB symbolic"); + status = umfpack_di_numeric (Ap, Ai, Ax, Symbolic, &Numeric, Control, Info) ; + std::cout << " numeric status: " << status << std::endl; + if (status == 1) + { + std::cout << " WARNING: MATRIX IS SINGULAR " << std::endl; + //throw ArpackError(ArpackError::PARAMETER_ERROR, "ARumSymPencil::FactorAsB numeric (matrix singular)"); + } + if (status < UMFPACK_OK) + { + std::cout << " ERROR CODE: " << status << std::endl; + throw ArpackError(ArpackError::PARAMETER_ERROR, "ARumSymPencil::FactorAsB numeric"); + } + umfpack_di_free_symbolic (&Symbolic) ; + +//exit(0); + + // Decomposing AsB. + + //um2fa(AsB.n, AsB.index[AsB.n], 0, false, AsB.lvalue, AsB.lindex, AsB.value, + // AsB.index, AsB.keep, AsB.cntl, AsB.icntl, AsB.info, AsB.rinfo); + + // Handling errors. + + // AsB.ThrowError(); + + // AsB.factored = true; + +} // FactorAsB (ARTYPE shift). + + +template +void ARumSymPencil::MultInvBAv(ARTYPE* v, ARTYPE* w) +{ + + if (!B->IsFactored()) B->FactorA(); + + A->MultMv(v, w); + copy(A->ncols(), w, 1, v, 1); + B->MultInvv(w, w); + +} // MultInvBAv. + +template +void ARumSymPencil::MultInvAsBv(ARTYPE* v, ARTYPE* w) +{ + if (!Numeric) { + throw ArpackError(ArpackError::NOT_FACTORED_MATRIX, + "ARchSymPencil::MultInvAsBv"); + } + + // Solving A.w = v (or AsI.w = v). + int status = umfpack_di_solve (UMFPACK_A, Ap, Ai, Ax, w, v, Numeric, NULL, NULL) ; + if (status == 1) + { + std::cout << " WARNING: MATRIX IS SINGULAR " << std::endl; + //throw ArpackError(ArpackError::PARAMETER_ERROR, "ARumSymPencil::FactorAsB numeric (matrix singular)"); + } + if (status < UMFPACK_OK) + { + std::cout << " ERROR CODE: " << status << std::endl; + throw ArpackError(ArpackError::PARAMETER_ERROR, "ARumSymPencil::MultInvAsBv"); + + } + +} // MultInvAsBv + +template +inline void ARumSymPencil:: +DefineMatrices(ARumSymMatrix& Ap, ARumSymMatrix& Bp) +{ + + A = &Ap; + B = &Bp; + + if (A->n != B->n) { + throw ArpackError(ArpackError::INCOMPATIBLE_SIZES, + "ARumSymMatrix::DefineMatrices"); + } + +} // DefineMatrices. + + +template +inline ARumSymPencil:: +ARumSymPencil(ARumSymMatrix& Ap, ARumSymMatrix& Bp) +{ + Numeric = NULL; + Ap = NULL; + Ai = NULL; + Ax = NULL; + + //AsB.factored = false; + DefineMatrices(Ap, Bp); + + +} // Long constructor. + + +template +ARumSymPencil& ARumSymPencil:: +operator=(const ARumSymPencil& other) +{ + + if (this != &other) { // Stroustrup suggestion. + Copy(other); + } + return *this; + +} // operator=. + + +#endif // ARUSPEN_H diff --git a/external/arpack++/include/arussym.h b/external/arpack++/include/arussym.h new file mode 100644 index 000000000..f1a53cf82 --- /dev/null +++ b/external/arpack++/include/arussym.h @@ -0,0 +1,158 @@ +/* + ARPACK++ v1.2 2/20/2000 + c++ interface to ARPACK code. + + MODULE ARUSSym.h. + Arpack++ class ARluSymStdEig definition + (UMFPACK version). + + ARPACK Authors + Richard Lehoucq + Danny Sorensen + Chao Yang + Dept. of Computational & Applied Mathematics + Rice University + Houston, Texas +*/ + +#ifndef ARUSSYM_H +#define ARUSSYM_H + +#include +#include +#include "arch.h" +#include "arssym.h" +#include "arusmat.h" + + +template +class ARluSymStdEig: + public virtual ARSymStdEig > { + + public: + + // a) Public functions: + + // a.1) Functions that allow changes in problem parameters. + + virtual void ChangeShift(ARFLOAT sigmaRp); + + virtual void SetRegularMode(); + + virtual void SetShiftInvertMode(ARFLOAT sigmap); + + // a.2) Constructors and destructor. + + ARluSymStdEig() { } + // Short constructor. + + ARluSymStdEig(int nevp, ARumSymMatrix& A, + const std::string& whichp = "LM", int ncvp = 0, + ARFLOAT tolp = 0.0, int maxitp = 0, + ARFLOAT* residp = NULL, bool ishiftp = true); + // Long constructor (regular mode). + + ARluSymStdEig(int nevp, ARumSymMatrix& A, + ARFLOAT sigma, const std::string& whichp = "LM", int ncvp = 0, + ARFLOAT tolp = 0.0, int maxitp = 0, + ARFLOAT* residp = NULL, bool ishiftp = true); + // Long constructor (shift and invert mode). + + ARluSymStdEig(const ARluSymStdEig& other) { Copy(other); } + // Copy constructor. + + virtual ~ARluSymStdEig() { } + // Destructor. + + // b) Operators. + + ARluSymStdEig& operator=(const ARluSymStdEig& other); + // Assignment operator. + +}; // class ARluSymStdEig. + + +// ------------------------------------------------------------------------ // +// ARluSymStdEig member functions definition. // +// ------------------------------------------------------------------------ // + + +template +inline void ARluSymStdEig::ChangeShift(ARFLOAT sigmaRp) +{ + + this->sigmaR = sigmaRp; + this->sigmaI = 0.0; + this->mode = 3; + this->iparam[7] = this->mode; + + this->objOP->FactorAsI(this->sigmaR); + this->Restart(); + +} // ChangeShift. + + +template +inline void ARluSymStdEig::SetRegularMode() +{ + + ARStdEig >:: + SetRegularMode(this->objOP, &ARumSymMatrix::MultMv); + +} // SetRegularMode. + + +template +inline void ARluSymStdEig::SetShiftInvertMode(ARFLOAT sigmap) +{ + + ARStdEig >:: + SetShiftInvertMode(sigmap, this->objOP, &ARumSymMatrix::MultInvv); + +} // SetShiftInvertMode. + + +template +inline ARluSymStdEig:: +ARluSymStdEig(int nevp, ARumSymMatrix& A, + const std::string& whichp, int ncvp, ARFLOAT tolp, + int maxitp, ARFLOAT* residp, bool ishiftp) +{ + + this->NoShift(); + this->DefineParameters(A.ncols(), nevp, &A, &ARumSymMatrix::MultMv, + whichp, ncvp, tolp, maxitp, residp, ishiftp); + +} // Long constructor (regular mode). + + +template +inline ARluSymStdEig:: +ARluSymStdEig(int nevp, ARumSymMatrix& A, + ARFLOAT sigmap, const std::string& whichp, int ncvp, ARFLOAT tolp, + int maxitp, ARFLOAT* residp, bool ishiftp) + +{ + + this->DefineParameters(A.ncols(), nevp, &A, &ARumSymMatrix::MultInvv, + whichp, ncvp, tolp, maxitp, residp, ishiftp); + ChangeShift(sigmap); + +} // Long constructor (shift and invert mode). + + +template +ARluSymStdEig& ARluSymStdEig:: +operator=(const ARluSymStdEig& other) +{ + + if (this != &other) { // Stroustrup suggestion. + this->ClearMem(); + Copy(other); + } + return *this; + +} // operator=. + + +#endif // ARUSSYM_H diff --git a/external/arpack++/include/blas1c.h b/external/arpack++/include/blas1c.h new file mode 100644 index 000000000..b24fca520 --- /dev/null +++ b/external/arpack++/include/blas1c.h @@ -0,0 +1,367 @@ +/* + ARPACK++ v1.2 2/20/2000 + c++ interface to ARPACK code. + + MODULE blas1c.h. + Interface to blas 1 and blas 2 FORTRAN routines. + + ARPACK Authors + Richard Lehoucq + Danny Sorensen + Chao Yang + Dept. of Computational & Applied Mathematics + Rice University + Houston, Texas +*/ + +#include "arch.h" +#include "blas1f.h" + +#ifndef BLAS1C_H +#define BLAS1C_H + +// ASSUM + +inline float assum(const ARint &n, const float dx[], const ARint &incx) { + return F77NAME(sasum)(&n, dx, &incx); +} // assum (float) + +inline double assum(const ARint &n, const double dx[], const ARint &incx) { + return F77NAME(dasum)(&n, dx, &incx); +} // assum (double) + +#ifdef ARCOMP_H +inline float assum(const ARint &n, const arcomplex dx[], + const ARint &incx) { + return F77NAME(scasum)(&n, dx, &incx); +} // assum (arcomplex) + +inline double assum(const ARint &n, const arcomplex dx[], + const ARint &incx) { + return F77NAME(dzasum)(&n, dx, &incx); +} // assum (arcomplex) +#endif + +// AXPY + +inline void axpy(const ARint &n, const float &da, const float dx[], + const ARint &incx, float dy[], const ARint &incy) { + F77NAME(saxpy)(&n, &da, dx, &incx, dy, &incy); +} // axpy (float) + +inline void axpy(const ARint &n, const double &da, const double dx[], + const ARint &incx, double dy[], const ARint &incy) { + F77NAME(daxpy)(&n, &da, dx, &incx, dy, &incy); +} // axpy (double) + +#ifdef ARCOMP_H +inline void axpy(const ARint &n, const arcomplex &da, + const arcomplex dx[], const ARint &incx, + arcomplex dy[], const ARint &incy) { + F77NAME(caxpy)(&n, &da, dx, &incx, dy, &incy); +} // axpy (arcomplex) + +inline void axpy(const ARint &n, const arcomplex &da, + const arcomplex dx[], const ARint &incx, + arcomplex dy[], const ARint &incy) { + F77NAME(zaxpy)(&n, &da, dx, &incx, dy, &incy); +} // axpy (arcomplex) +#endif + +// COPY + +inline void copy(const ARint &n, const float dx[], const ARint &incx, + float dy[], const ARint &incy) { + if (dx != dy) F77NAME(scopy)(&n, dx, &incx, dy, &incy); +} // copy (float) + +inline void copy(const ARint &n, const double dx[], const ARint &incx, + double dy[], const ARint &incy) { + if (dx != dy) F77NAME(dcopy)(&n, dx, &incx, dy, &incy); +} // copy (double) + +#ifdef ARCOMP_H +inline void copy(const ARint &n, const arcomplex dx[], + const ARint &incx, arcomplex dy[], + const ARint &incy) { + if (dx != dy) F77NAME(ccopy)(&n, dx, &incx, dy, &incy); +} // copy (arcomplex) + +inline void copy(const ARint &n, const arcomplex dx[], + const ARint &incx, arcomplex dy[], + const ARint &incy) { + if (dx != dy) F77NAME(zcopy)(&n, dx, &incx, dy, &incy); +} // copy (arcomplex) +#endif + +// DOT + +inline float dot(const ARint &n, const float dx[], const ARint &incx, + const float dy[], const ARint &incy) { + return F77NAME(sdot)(&n, dx, &incx, dy, &incy); +} // dot (float) + +inline double dot(const ARint &n, const double dx[], const ARint &incx, + const double dy[], const ARint &incy) { + return F77NAME(ddot)(&n, dx, &incx, dy, &incy); +} // dot (double) + +#ifdef ARCOMP_H +inline arcomplex dotc(const ARint &n, const arcomplex dx[], + const ARint &incx,const arcomplex dy[], + const ARint &incy) { + arcomplex tmp; + F77NAME(cdotc)(&tmp, &n, dx, &incx, dy, &incy); + return tmp; +} // dotc (arcomplex) + +inline arcomplex dotc(const ARint &n, const arcomplex dx[], + const ARint &incx, const arcomplex dy[], + const ARint &incy) { + arcomplex tmp; + F77NAME(zdotc)(&tmp, &n, dx, &incx, dy, &incy); + return tmp; +} // dotc (arcomplex) + +inline arcomplex dotu(const ARint &n, const arcomplex dx[], + const ARint &incx, const arcomplex dy[], + const ARint &incy) { + arcomplex tmp; + F77NAME(cdotu)(&tmp, &n, dx, &incx, dy, &incy); + return tmp; +} // dotu (arcomplex) + +inline arcomplex dotu(const ARint &n, const arcomplex dx[], + const ARint &incx, const arcomplex dy[], + const ARint &incy) { + arcomplex tmp; + F77NAME(zdotu)(&tmp, &n, dx, &incx, dy, &incy); + return tmp; +} // dotu (arcomplex) +#endif + +// NRM2 + +inline float nrm2(const ARint &n, const float dx[], const ARint &incx) { + return F77NAME(snrm2)(&n, dx, &incx); +} // nrm2 (float) + +inline double nrm2(const ARint &n, const double dx[], const ARint &incx) { + return F77NAME(dnrm2)(&n, dx, &incx); +} // nrm2 (double) + +#ifdef ARCOMP_H +inline float nrm2(const ARint &n, const arcomplex dx[], + const ARint &incx) { + return F77NAME(scnrm2)(&n, dx, &incx); +} // nrm2 (complex ) + +inline double nrm2(const ARint &n, const arcomplex dx[], + const ARint &incx) { + return F77NAME(dznrm2)(&n, dx, &incx); +} // nrm2 (complex ) +#endif + +// ROT + +inline void rot(const ARint &n, float dx[], const ARint &incx, float dy[], + const ARint &incy, const float &c, const float &s) { + F77NAME(srot)(&n, dx, &incx, dy, &incy, &c, &s); +} // rot (float) + +inline void rot(const ARint &n, double dx[], const ARint &incx, + double dy[], const ARint &incy, const double &c, + const double &s) { + F77NAME(drot)(&n, dx, &incx, dy, &incy, &c, &s); +} // rot (double) + +// ROTG + +inline void rotg(float &da, float &db, float &c, float &s) { + F77NAME(srotg)(&da, &db, &c, &s); +} // rotg (float) + +inline void rotg(double &da, double &db, double &c, double &s) { + F77NAME(drotg)(&da, &db, &c, &s); +} // rotg (double) + +// SCAL + +inline void scal(const ARint &n, float &da, float dx[], const ARint &incx) { + F77NAME(sscal)(&n, &da, dx, &incx); +} // scal (float) + +inline void scal(const ARint &n, double &da, double dx[], const ARint &incx) { + F77NAME(dscal)(&n, &da, dx, &incx); +} // scal (double) + +#ifdef ARCOMP_H +inline void scal(const ARint &n, const arcomplex &da, + arcomplex dx[], const ARint &incx) { + F77NAME(cscal)(&n, &da, dx, &incx); +} // scal (arcomplex) + +inline void scal(const ARint &n, const arcomplex &da, + arcomplex dx[], const ARint &incx) { + F77NAME(zscal)(&n, &da, dx, &incx); +} // scal (arcomplex) + +inline void sscal(const ARint &n, const float &da, arcomplex dx[], + const ARint &incx) { + F77NAME(csscal)(&n, &da, dx, &incx); +} // sscal (arcomplex) + +inline void sscal(const ARint &n, const double &da, arcomplex dx[], + const ARint &incx) { + F77NAME(zdscal)(&n, &da, dx, &incx); +} // sscal (arcomplex) +#endif + +// SWAP + +inline void swap(const ARint &n, float dx[], const ARint &incx, + float dy[], const ARint &incy) { + F77NAME(sswap)(&n, dx, &incx, dy, &incy); +} // swap (float) + +inline void swap(const ARint &n, double dx[], const ARint &incx, + double dy[], const ARint &incy) { + F77NAME(dswap)(&n, dx, &incx, dy, &incy); +} // swap (double) + +#ifdef ARCOMP_H +inline void swap(const ARint &n, arcomplex dx[], const ARint &incx, + arcomplex dy[], const ARint &incy) { + F77NAME(cswap)(&n, dx, &incx, dy, &incy); +} // swap (arcomplex) + +inline void swap(const ARint &n, arcomplex dx[], const ARint &incx, + arcomplex dy[], const ARint &incy) { + F77NAME(zswap)(&n, dx, &incx, dy, &incy); +} // swap (arcomplex) +#endif + +// AMAX + +inline ARint amax(const ARint &n, const float dx[], const ARint &incx) { + return F77NAME(isamax)(&n, dx, &incx); +} // amax (float) + +inline ARint amax(const ARint &n, const double dx[], const ARint &incx) { + return F77NAME(idamax)(&n, dx, &incx); +} // amax (double) + +#ifdef ARCOMP_H +inline ARint amax(const ARint &n, const arcomplex dx[], + const ARint &incx) { + return F77NAME(icamax)(&n, dx, &incx); +} // amax (arcomplex) + +inline ARint amax(const ARint &n, const arcomplex dx[], + const ARint &incx) { + return F77NAME(izamax)(&n, dx, &incx); +} // amax (arcomplex) +#endif + +// GEMV + +inline void gemv(const char* trans, const ARint &m, const ARint &n, + const float &alpha, const float a[], const ARint &lda, + const float x[], const ARint &incx, const float &beta, + float y[], const ARint &incy) { + F77NAME(sgemv)(trans, &m, &n, &alpha, a, &lda, + x, &incx, &beta, y, &incy); +} // gemv (float) + +inline void gemv(const char* trans, const ARint &m, const ARint &n, + const double &alpha, const double a[], const ARint &lda, + const double x[], const ARint &incx, const double &beta, + double y[], const ARint &incy) { + F77NAME(dgemv)(trans, &m, &n, &alpha, a, &lda, + x, &incx, &beta, y, &incy); +} // gemv (double) + +#ifdef ARCOMP_H +inline void gemv(const char* trans, const ARint &m, + const ARint &n, const arcomplex &alpha, + const arcomplex a[], const ARint &lda, + const arcomplex x[], const ARint &incx, + const arcomplex &beta, arcomplex y[], + const ARint &incy) { + F77NAME(cgemv)(trans, &m, &n, &alpha, a, &lda, + x, &incx, &beta, y, &incy); +} // gemv (arcomplex) + +inline void gemv(const char* trans, const ARint &m, + const ARint &n, const arcomplex &alpha, + const arcomplex a[], const ARint &lda, + const arcomplex x[], const ARint &incx, + const arcomplex &beta, arcomplex y[], + const ARint &incy) { + F77NAME(zgemv)(trans, &m, &n, &alpha, a, &lda, + x, &incx, &beta, y, &incy); +} // gemv (arcomplex) +#endif + +// GBMV + +inline void gbmv(const char* trans, const ARint &m, const ARint &n, + const ARint &kl, const ARint &ku, const float &alpha, + const float a[], const ARint &lda, const float x[], + const ARint &incx, const float &beta, float y[], + const ARint &incy) { + F77NAME(sgbmv)(trans, &m, &n, &kl, &ku, &alpha, a, &lda, + x, &incx, &beta, y, &incy); +} // gbmv (float) + +inline void gbmv(const char* trans, const ARint &m, const ARint &n, + const ARint &kl, const ARint &ku, const double &alpha, + const double a[], const ARint &lda, const double x[], + const ARint &incx, const double &beta, double y[], + const ARint &incy) { + F77NAME(dgbmv)(trans, &m, &n, &kl, &ku, &alpha, a, &lda, + x, &incx, &beta, y, &incy); +} // gbmv (double) + +#ifdef ARCOMP_H +inline void gbmv(const char* trans, const ARint &m, + const ARint &n, const ARint &kl, + const ARint &ku, const arcomplex &alpha, + const arcomplex a[], const ARint &lda, + const arcomplex x[], const ARint &incx, + const arcomplex &beta, arcomplex y[], + const ARint &incy) { + F77NAME(cgbmv)(trans, &m, &n, &kl, &ku, &alpha, a, &lda, + x, &incx, &beta, y, &incy); +} // gbmv (arcomplex) + +inline void gbmv(const char* trans, const ARint &m, + const ARint &n, const ARint &kl, + const ARint &ku, const arcomplex &alpha, + const arcomplex a[], const ARint &lda, + const arcomplex x[], const ARint &incx, + const arcomplex &beta, arcomplex y[], + const ARint &incy) { + F77NAME(zgbmv)(trans, &m, &n, &kl, &ku, &alpha, a, &lda, + x, &incx, &beta, y, &incy); +} // gbmv (arcomplex) +#endif + +// SBMV + +inline void sbmv(const char* uplo, const ARint &n, const ARint &k, + const float &alpha, const float a[], const ARint &lda, + const float x[], const ARint &incx, const float &beta, + float y[], const ARint &incy) { + F77NAME(ssbmv)(uplo, &n, &k, &alpha, a, &lda, x, &incx, &beta, y, &incy); +} // sbmv (float) + +inline void sbmv(const char* uplo, const ARint &n, const ARint &k, + const double &alpha, const double a[], const ARint &lda, + const double x[], const ARint &incx, const double &beta, + double y[], const ARint &incy) { + F77NAME(dsbmv)(uplo, &n, &k, &alpha, a, &lda, x, &incx, &beta, y, &incy); +} // sbmv (double) + + +#endif // BLAS1C_H diff --git a/external/arpack++/include/blas1f.h b/external/arpack++/include/blas1f.h new file mode 100644 index 000000000..ad0dcaebe --- /dev/null +++ b/external/arpack++/include/blas1f.h @@ -0,0 +1,221 @@ +/* + ARPACK++ v1.2 2/20/2000 + c++ interface to ARPACK code. + + MODULE blas1f.h + BLAS 1 and BLAS 2 FORTRAN routines. + + ARPACK Authors + Richard Lehoucq + Danny Sorensen + Chao Yang + Dept. of Computational & Applied Mathematics + Rice University + Houston, Texas +*/ + +#ifndef BLAS1F_H +#define BLAS1F_H + +#include "arch.h" + +extern "C" +{ + + // Single precision real routines. + + float F77NAME(sasum)(const ARint *n, const float *dx, const ARint *incx); + + void F77NAME(saxpy)(const ARint *n, const float *da, const float *dx, + const ARint *incx, float *dy, const ARint *incy); + + void F77NAME(scopy)(const ARint *n, const float *dx, const ARint *incx, + float *dy, const ARint *incy); + + float F77NAME(sdot)(const ARint *n, const float *dx, const ARint *incx, + const float *dy, const ARint *incy); + + float F77NAME(snrm2)(const ARint *n, const float *dx, const ARint *incx); + + void F77NAME(srot)(const ARint *n, float *dx, const ARint *incx, float *dy, + const ARint *incy, const float *c, const float *s); + + void F77NAME(srotg)(float *da, float *db, float *c, float *s); + + void F77NAME(sscal)(const ARint *n, float *da, float *dx, const ARint *incx); + + void F77NAME(sswap)(const ARint *n, float *dx, const ARint *incx, + float *dy, const ARint *incy); + + ARint F77NAME(isamax)(const ARint *n, const float *dx, const ARint *incx); + + void F77NAME(sgemv)(const char* trans, const ARint *m, const ARint *n, + const float *alpha, const float *a, const ARint *lda, + const float *x, const ARint *incx, const float *beta, + float *y, const ARint *incy); + + void F77NAME(sgbmv)(const char* trans, const ARint *m, const ARint *n, + const ARint *kl, const ARint *ku, const float *alpha, + const float *a, const ARint *lda, const float *x, + const ARint *incx, const float *beta, float *y, + const ARint *incy); + + void F77NAME(ssbmv)(const char* uplo, const ARint *n, const ARint *k, + const float *alpha, const float *a, const ARint *lda, + const float *x, const ARint *incx, const float *beta, + float *y, const ARint *incy); + +// Double precision real routines. + + double F77NAME(dasum)(const ARint *n, const double *dx, const ARint *incx); + + void F77NAME(daxpy)(const ARint *n, const double *da, const double *dx, + const ARint *incx, double *dy, const ARint *incy); + + void F77NAME(dcopy)(const ARint *n, const double *dx, const ARint *incx, + double *dy, const ARint *incy); + + double F77NAME(ddot)(const ARint *n, const double *dx, const ARint *incx, + const double *dy, const ARint *incy); + + double F77NAME(dnrm2)(const ARint *n, const double *dx, const ARint *incx); + + void F77NAME(drot)(const ARint *n, double *dx, const ARint *incx, double *dy, + const ARint *incy, const double *c, const double *s); + + void F77NAME(drotg)(double *da, double *db, double *c, double *s); + + void F77NAME(dscal)(const ARint *n, double *da, double *dx, const ARint *incx); + + void F77NAME(dswap)(const ARint *n, double *dx, const ARint *incx, + double *dy, const ARint *incy); + + ARint F77NAME(idamax)(const ARint *n, const double *dx, const ARint *incx); + + void F77NAME(dgemv)(const char* trans, const ARint *m, const ARint *n, + const double *alpha, const double *a, const ARint *lda, + const double *x, const ARint *incx, const double *beta, + double *y, const ARint *incy); + + void F77NAME(dgbmv)(const char* trans, const ARint *m, const ARint *n, + const ARint *kl, const ARint *ku, const double *alpha, + const double *a, const ARint *lda, const double *x, + const ARint *incx, const double *beta, double *y, + const ARint *incy); + + void F77NAME(dsbmv)(const char* uplo, const ARint *n, const ARint *k, + const double *alpha, const double *a, const ARint *lda, + const double *x, const ARint *incx, const double *beta, + double *y, const ARint *incy); + + // Single precision complex routines. + +#ifdef ARCOMP_H + + void F77NAME(cdotc)(arcomplex *c, const ARint *n, + const arcomplex *cx, const ARint *incx, + const arcomplex *cy, const ARint *incy); + + void F77NAME(cdotu)(arcomplex *c, const ARint *n, + const arcomplex *cx, const ARint *incx, + const arcomplex *cy, const ARint *incy); + + void F77NAME(caxpy)(const ARint *n, const arcomplex *da, + const arcomplex *dx, const ARint *incx, + arcomplex *dy, const ARint *incy); + + void F77NAME(ccopy)(const ARint *n, const arcomplex *dx, + const ARint *incx, arcomplex *dy, + const ARint *incy); + + float F77NAME(scasum)(const ARint *n, const arcomplex *dx, + const ARint *incx); + + float F77NAME(scnrm2)(const ARint *n, const arcomplex *dx, + const ARint *incx); + + void F77NAME(csscal)(const ARint *n, const float *da, arcomplex *dx, + const ARint *incx); + + void F77NAME(cscal)(const ARint *n, const arcomplex *da, + arcomplex *dx, const ARint *incx); + + ARint F77NAME(icamax)(const ARint *n, const arcomplex *dx, + const ARint *incx); + + void F77NAME(cswap)(const ARint *n, arcomplex *dx, + const ARint *incx, arcomplex *dy, + const ARint *incy); + + void F77NAME(cgemv)(const char* trans, const ARint *m, + const ARint *n, const arcomplex *alpha, + const arcomplex *a, const ARint *lda, + const arcomplex *x, const ARint *incx, + const arcomplex *beta, arcomplex *y, + const ARint *incy); + + void F77NAME(cgbmv)(const char* trans, const ARint *m, + const ARint *n, const ARint *kl, + const ARint *ku, const arcomplex *alpha, + const arcomplex *a, const ARint *lda, + const arcomplex *x, const ARint *incx, + const arcomplex *beta, arcomplex *y, + const ARint *incy); + + // Double precision complex routines. + + void F77NAME(zdotc)(arcomplex *c, const ARint *n, + const arcomplex *cx, const ARint *incx, + const arcomplex *cy, const ARint *incy); + + void F77NAME(zdotu)(arcomplex *c, const ARint *n, + const arcomplex *cx, const ARint *incx, + const arcomplex *cy, const ARint *incy); + + void F77NAME(zaxpy)(const ARint *n, const arcomplex *da, + const arcomplex *dx, const ARint *incx, + arcomplex *dy, const ARint *incy); + + void F77NAME(zcopy)(const ARint *n, const arcomplex *dx, + const ARint *incx, arcomplex *dy, + const ARint *incy); + + double F77NAME(dzasum)(const ARint *n, const arcomplex *dx, + const ARint *incx); + + double F77NAME(dznrm2)(const ARint *n, const arcomplex *dx, + const ARint *incx); + + void F77NAME(zdscal)(const ARint *n, const double *da, arcomplex *dx, + const ARint *incx); + + void F77NAME(zscal)(const ARint *n, const arcomplex *da, + arcomplex *dx, const ARint *incx); + + ARint F77NAME(izamax)(const ARint *n, const arcomplex *dx, + const ARint *incx); + + void F77NAME(zswap)(const ARint *n, arcomplex *dx, + const ARint *incx, arcomplex *dy, + const ARint *incy); + + void F77NAME(zgemv)(const char* trans, const ARint *m, + const ARint *n, const arcomplex *alpha, + const arcomplex *a, const ARint *lda, + const arcomplex *x, const ARint *incx, + const arcomplex *beta, arcomplex *y, + const ARint *incy); + + void F77NAME(zgbmv)(const char* trans, const ARint *m, + const ARint *n, const ARint *kl, + const ARint *ku, const arcomplex *alpha, + const arcomplex *a, const ARint *lda, + const arcomplex *x, const ARint *incx, + const arcomplex *beta, arcomplex *y, + const ARint *incy); + +#endif // ARCOMP_H + +} +#endif // BLAS1F_H + diff --git a/external/arpack++/include/caupp.h b/external/arpack++/include/caupp.h new file mode 100644 index 000000000..3bc97c289 --- /dev/null +++ b/external/arpack++/include/caupp.h @@ -0,0 +1,320 @@ +/* + ARPACK++ v1.2 2/20/2000 + c++ interface to ARPACK code. + + MODULE caupp.h. + Interface to ARPACK subroutines znaupd and cnaupd. + + ARPACK Authors + Richard Lehoucq + Danny Sorensen + Chao Yang + Dept. of Computational & Applied Mathematics + Rice University + Houston, Texas +*/ + +#ifndef CAUPP_H +#define CAUPP_H + +#include +#include "arch.h" +#include "arpackf.h" + +inline void caupp(ARint& ido, char bmat, ARint n, const std::string& which, ARint nev, + double& tol, arcomplex resid[], ARint ncv, + arcomplex V[], ARint ldv, ARint iparam[], + ARint ipntr[], arcomplex workd[], + arcomplex workl[], ARint lworkl, double rwork[], + ARint& info) + +/* + c++ version of ARPACK routine znaupd that implements the + Reverse communication interface for the Implicitly Restarted Arnoldi + iteration. This is intended to be used to find a few eigenpairs of a + complex linear operator OP with respect to a semi-inner product defined + by a hermitian positive semi-definite real matrix B. B may be the + identity matrix. NOTE: if both OP and B are real, then naupp should + be used. + + The computed approximate eigenvalues are called Ritz values and + the corresponding approximate eigenvectors are called Ritz vectors. + + caupp is usually called iteratively to solve one of the + following problems: + + Mode 1: A*x = lambda*x. + ===> OP = A and B = I. + + Mode 2: A*x = lambda*M*x, M symmetric positive definite + ===> OP = inv[M]*A and B = M. + ===> (If M can be factored see remark 3 below) + + Mode 3: A*x = lambda*M*x, M symmetric semi-definite + ===> OP = inv[A - sigma*M]*M and B = M. + ===> shift-and-invert mode + If OP*x = amu*x, then lambda = sigma + 1/amu. + + + NOTE: The action of w <- inv[A - sigma*M]*v or w <- inv[M]*v + should be accomplished either by a direct method + using a sparse matrix factorization and solving + + [A - sigma*M]*w = v or M*w = v, + + or through an iterative method for solving these systems. If + an iterative method is used, the convergence test must be more + stringent than the accuracy requirements for the eigenvalue + approximations. + + Parameters: + + ido (Input / Output) Reverse communication flag. ido must be + zero on the first call to caupp. ido will be set + internally to indicate the type of operation to be + performed. Control is then given back to the calling + routine which has the responsibility to carry out the + requested operation and call caupp with the result. The + operand is given in workd[ipntr[1]], the result must be + put in workd[ipntr[2]]. + ido = 0: first call to the reverse communication interface. + ido = -1: compute Y = OP * X where + ipntr[1] is the pointer into workd for X, + ipntr[2] is the pointer into workd for Y. + This is for the initialization phase to force the + starting vector into the range of OP. + ido = 1: compute Y = OP * X where + ipntr[1] is the pointer into workd for X, + ipntr[2] is the pointer into workd for Y. + In mode 3 and 4, the vector B * X is already + available in workd[ipntr[3]]. It does not + need to be recomputed in forming OP * X. + ido = 2: compute Y = B * X where + ipntr[1] is the pointer into workd for X, + ipntr[2] is the pointer into workd for Y. + ido = 3: compute the iparam[8] real and imaginary parts + of the shifts where inptr[14] is the pointer + into workl for placing the shifts. See Remark + 5 below. + ido = 99: done. + bmat (Input) bmat specifies the type of the matrix B that defines + the semi-inner product for the operator OP. + bmat = 'I' -> standard eigenvalue problem A*x = lambda*x; + bmat = 'G' -> generalized eigenvalue problem A*x = lambda*M*x. + n (Input) Dimension of the eigenproblem. + nev (Input) Number of eigenvalues to be computed. 0 < nev <= n-1. + which (Input) Specify which of the Ritz values of OP to compute. + 'LM' - compute the nev eigenvalues of largest magnitude. + 'SM' - compute the nev eigenvalues of smallest magnitude. + 'LR' - compute the nev eigenvalues of largest real part. + 'SR' - compute the nev eigenvalues of smallest real part. + 'LI' - compute the nev eigenvalues of largest imaginary part. + 'SI' - compute the nev eigenvalues of smallest imaginary part. + tol (Input) Stopping criterion: the relative accuracy of the + Ritz value is considered acceptable if BOUNDS[i] <= + tol*abs(RITZ[i]),where ABS(RITZ[i]) is the magnitude when + RITZ[i] is complex. If tol<=0.0 is passed, the machine + precision as computed by the LAPACK auxiliary subroutine + _LAMCH is used. + resid (Input / Output) Array of length n. + On input: + If info==0, a random initial residual vector is used. + If info!=0, resid contains the initial residual vector, + possibly from a previous run. + On output: + resid contains the final residual vector. + ncv (Input) Number of Arnoldi vectors that are generated at each + iteration. After the startup phase in which nev Arnoldi + vectors are generated, the algorithm generates ncv-nev + Arnoldi vectors at each subsequent update iteration. Most of + the cost in generating each Arnoldi vector is in the + matrix-vector product OP*x. + NOTE: ncv must satisfy nev+1 <= ncv <= n. + V (Output) Array of length ncv*n+1. V contains the ncv Arnoldi + basis vectors. The first element V[0] is never referenced. + ldv (Input) Dimension of the basis vectors contained in V. This + parameter MUST be set to n. + iparam (Input / Output) Array of length 12. + iparam[1] = ISHIFT: method for selecting the implicit shifts. + The shifts selected at each iteration are used to restart + the Arnoldi iteration in an implicit fashion. + ------------------------------------------------------------- + ISHIFT = 0: the shifts are to be provided by the user via + reverse communication. The ncv eigenvalues of + the Hessenberg matrix H are returned in the part + of workl array corresponding to RITZ. + ISHIFT = 1: exact shifts with respect to the current + Hessenberg matrix H. This is equivalent to + restarting the iteration from the beginning + after updating the starting vector with a linear + combination of Ritz vectors associated with the + "wanted" eigenvalues. + ISHIFT = 2: other choice of internal shift to be defined. + ------------------------------------------------------------- + iparam[2] is no longer referenced. + iparam[3] = MXITER + On INPUT: maximum number of Arnoldi update iterations allowed. + On OUTPUT: actual number of Arnoldi update iterations taken. + iparam[4] = NB: blocksize to be used in the recurrence. + The code currently works only for NB = 1. + iparam[5] = NCONV: number of "converged" Ritz values. + This represents the number of Ritz values that satisfy + the convergence criterion. + iparam[6] is no longer referenced. + iparam[7] = MODE. On input determines what type of + eigenproblem is being solved. Must be 1, 2 or 3. + iparam[8] = NP. When ido = 3 and the user provides shifts + through reverse communication (iparam[1]=0), caupp returns + NP, the number of shifts the user is to provide. + 0 < NP <=ncv-nev. See Remark 5 below. + iparam[9] = total number of OP*x operations. + iparam[10] = total number of B*x operations if bmat='G'. + iparam[11] = total number of steps of re-orthogonalization. + ipntr (Output) Array of length 15. Pointer to mark the starting + locations in the workd and workl arrays for matrices/vectors + used by the Arnoldi iteration. + ipntr[1] : pointer to the current operand vector X in workd. + ipntr[2] : pointer to the current result vector Y in workd. + ipntr[3] : pointer to the vector B * X in workd when used in + the shift-and-invert mode. + ipntr[4] : pointer to the next available location in workl + that is untouched by the program. + ipntr[5] : pointer to the ncv by ncv upper Hessenberg matrix + H in workl. + ipntr[6] : pointer to the ritz value array RITZ. + ipntr[7] : pointer to the (projected) ritz vector array Q. + ipntr[8] : pointer to the error BOUNDS array in workl. + ipntr[14]: pointer to the NP shifts in workl. See Remark 5. + Note: ipntr[9:13] is only referenced by ceupp. See Remark 2. + ipntr[9] : pointer to the ncv RITZ values of the + original system. + ipntr[10]: Not Used + ipntr[11]: pointer to the ncv corresponding error bounds. + ipntr[12]: pointer to the ncv by ncv upper triangular + Schur matrix for H. + ipntr[13]: pointer to the ncv by ncv matrix of eigenvectors + of the upper Hessenberg matrix H. Only referenced by + ceupp if RVEC = true. See Remark 2 below. + workd (Input / Output) Array of length 3*n+1. + Distributed array to be used in the basic Arnoldi iteration + for reverse communication. The user should not use workd as + temporary workspace during the iteration. + workl (Output) Array of length lworkl+1. Private (replicated) array + on each PE or array allocated on the front end. + lworkl (Input) lworkl must be at least 3*ncv*ncv+5*ncv. + RWORK (Workspace) Array of length ncv. Private (replicated) array on + each PE or array allocated on the front end. + info (Input / Output) On input, if info = 0, a randomly initial + residual vector is used, otherwise resid contains the initial + residual vector, possibly from a previous run. + On output, info works as a error flag: + = 0 : Normal exit. + = 1 : Maximum number of iterations taken. All possible + eigenvalues of OP has been found. iparam[5] + returns the number of wanted converged Ritz values. + = 3 : No shifts could be applied during a cycle of the + Implicitly restarted Arnoldi iteration. One + possibility is to increase the size of ncv relative + to nev. See remark 4 below. + = -1 : n must be positive. + = -2 : nev must be positive. + = -3 : ncv must satisfy nev+1 <= ncv <= n. + = -4 : The maximum number of Arnoldi update iterations + allowed must be greater than zero. + = -5 : which must be one of 'LM','SM','LR','SR','LI','SI'. + = -6 : bmat must be one of 'I' or 'G'. + = -7 : Length of private work array is not sufficient. + = -8 : Error return from LAPACK eigenvalue calculation. + = -9 : Starting vector is zero. + = -10 : iparam[7] must be 1, 2 or 3. + = -11 : iparam[7] = 1 and bmat = 'G' are incompatible. + = -12 : iparam[1] must be equal to 0 or 1. + = -13 : nev and which = 'BE' are incompatible. + = -9999: Could not build an Arnoldi factorization. iparam[5] + returns the size of the current Arnoldi factorization. + The user is advised to check that enough workspace + and array storage has been allocated. + + Remarks: + 1. The computed Ritz values are approximate eigenvalues of OP. The + selection of "which" should be made with this in mind when using + Mode = 3. When operating in Mode = 3 setting which = 'LM' will + compute the nev eigenvalues of the original problem that are + closest to the shift sigma . After convergence, approximate + eigenvalues of the original problem may be obtained with the + ARPACK subroutine ceupp. + 2. If a basis for the invariant subspace corresponding to the converged + Ritz values is needed, the user must call ceupp immediately following + completion of caupp. This is new starting with release 2 of ARPACK. + 3. If M can be factored into a Cholesky factorization M = LL' + then Mode = 2 should not be selected. Instead one should use + Mode = 1 with OP = inv(L)*A*inv(L'). Appropriate triangular + linear systems should be solved with L and L' rather + than computing inverses. After convergence, an approximate + eigenvector z of the original problem is recovered by solving + L'z = x where x is a Ritz vector of OP. + 4. At present there is no a-priori analysis to guide the selection + of ncv relative to nev. The only formal requrement is that ncv + >= nev + 1. However, it is recommended that ncv >= 2*nev. If many + problems of the same type are to be solved, one should experiment + with increasing ncv while keeping nev fixed for a given test + problem. This will usually decrease the required number of OP*x + operations but it also increases the work and storage required to + maintain the orthogonal basis vectors. The optimal "cross-over" + with respect to CPU time is problem dependent and must be + determined empirically. + 5. When iparam[1] = 0, and ido = 3, the user needs to provide the + NP = iparam[8] complex shifts in locations + workl[ipntr[14]], workl[ipntr[14]+1], ... , workl[ipntr[14]+NP]. + Eigenvalues of the current upper Hessenberg matrix are located in + workl[ipntr[6]] through workl[ipntr[6]+ncv-1]. They are ordered + according to the order defined by "which". The associated Ritz + estimates are located in workl[ipntr[8]], workl[ipntr[8]+1], ..., + workl[ipntr[8]+ncv-1]. + + References: + 1. D.C. Sorensen, "Implicit Application of Polynomial Filters in + a k-Step Arnoldi Method", SIAM J. Matr. Anal. Apps., 13 (1992), + pp 357-385. + 2. R.B. Lehoucq, "Analysis and Implementation of an Implicitly + Restarted Arnoldi Iteration", Rice University Technical Report + TR95-13, Department of Computational and Applied Mathematics. + 3. B.N. Parlett & Y. Saad, "_Complex_ Shift and Invert Strategies for + Double precision Matrices", Linear Algebra and its Applications, + vol 88/89, pp 575-595, (1987). +*/ + +{ + + F77NAME(znaupd)(&ido, &bmat, &n, which.c_str(), &nev, &tol, resid, &ncv, + &V[1], &ldv, &iparam[1], &ipntr[1], &workd[1], + &workl[1], &lworkl, &rwork[1], &info); + +} // caupp (arcomplex). + +inline void caupp(ARint& ido, char bmat, ARint n, const std::string& which, ARint nev, + float& tol, arcomplex resid[], ARint ncv, + arcomplex V[], ARint ldv, ARint iparam[], + ARint ipntr[], arcomplex workd[], + arcomplex workl[], ARint lworkl, float rwork[], + ARint& info) + +/* + c++ version of ARPACK routine cnaupd. The only difference between + cnaupd and znaupd is that in the former function all vectors have + single precision elements and in the latter all vectors have double + precision elements. +*/ + +{ + + F77NAME(cnaupd)(&ido, &bmat, &n, which.c_str(), &nev, &tol, resid, &ncv, + &V[1], &ldv, &iparam[1], &ipntr[1], &workd[1], + &workl[1], &lworkl, &rwork[1], &info); + +} // caupp (arcomplex). + +#endif // CAUPP_H + + + diff --git a/external/arpack++/include/ceupp.h b/external/arpack++/include/ceupp.h new file mode 100644 index 000000000..b8dc88656 --- /dev/null +++ b/external/arpack++/include/ceupp.h @@ -0,0 +1,224 @@ +/* + ARPACK++ v1.2 2/20/2000 + c++ interface to ARPACK code. + + MODULE ceupp.h. + Interface to ARPACK subroutines zneupd and cneupd. + + ARPACK Authors + Richard Lehoucq + Danny Sorensen + Chao Yang + Dept. of Computational & Applied Mathematics + Rice University + Houston, Texas +*/ + +#ifndef CEUPP_H +#define CEUPP_H + +#include +#include +#include "arch.h" +#include "arpackf.h" + +inline void ceupp(bool rvec, char HowMny, arcomplex d[], + arcomplex Z[], ARint ldz, arcomplex sigma, + arcomplex workev[], char bmat, ARint n, const std::string& which, + ARint nev, double tol, arcomplex resid[], ARint ncv, + arcomplex V[], ARint ldv, ARint iparam[], + ARint ipntr[], arcomplex workd[], + arcomplex workl[], ARint lworkl, double rwork[], + ARint& info) + +/* + c++ version of ARPACK routine zneupd. + This subroutine returns the converged approximations to eigenvalues + of A*z = lambda*B*z and (optionally): + + (1) the corresponding approximate eigenvectors, + (2) an orthonormal basis for the associated approximate + invariant subspace, + + There is negligible additional cost to obtain eigenvectors. An + orthonormal basis is always computed. There is an additional storage cost + of n*nev if both are requested (in this case a separate array Z must be + supplied). + The approximate eigenvalues and eigenvectors of A*z = lambda*B*z + are derived from approximate eigenvalues and eigenvectors of + of the linear operator OP prescribed by the MODE selection in the + call to caupp. caupp must be called before this routine is called. + These approximate eigenvalues and vectors are commonly called Ritz + values and Ritz vectors respectively. They are referred to as such + in the comments that follow. The computed orthonormal basis for the + invariant subspace corresponding to these Ritz values is referred to + as a Schur basis. + See documentation in the header of the subroutine caupp for + definition of OP as well as other terms and the relation of computed + Ritz values and Ritz vectors of OP with respect to the given problem + A*z = lambda*B*z. For a brief description, see definitions of + iparam[7], MODE and which in the documentation of caupp. + + Parameters: + + rvec (Input) Specifies whether a basis for the invariant subspace + corresponding to the converged Ritz value approximations for + the eigenproblem A*z = lambda*B*z is computed. + rvec = false: Compute Ritz values only. + rvec = true : Compute the Ritz vectors or Schur vectors. + See Remarks below. + HowMny (Input) Specifies the form of the basis for the invariant + subspace corresponding to the converged Ritz values that + is to be computed. + = 'A': Compute nev Ritz vectors; + = 'P': Compute nev Schur vectors; + d (Output) Array of dimension nev+1. D contains the Ritz + approximations to the eigenvalues lambda for A*z = lambda*B*z. + Z (Output) Array of dimension nev*n. If rvec = TRUE. and + HowMny = 'A', then Z contains approximate eigenvectors (Ritz + vectors) corresponding to the NCONV=iparam[5] Ritz values for + eigensystem A*z = lambda*B*z. + If rvec = .FALSE. or HowMny = 'P', then Z is not referenced. + NOTE: If if rvec = .TRUE. and a Schur basis is not required, + the array Z may be set equal to first nev+1 columns of + the Arnoldi basis array V computed by caupp. In this + case the Arnoldi basis will be destroyed and overwritten + with the eigenvector basis. + ldz (Input) Dimension of the vectors contained in Z. This + parameter MUST be set to n. + sigma (Input) If iparam[7] = 3, sigma represents the shift. Not + referenced if iparam[7] = 1 or 2. + workv (Workspace) Array of dimension 2*ncv. + V (Input/Output) Array of dimension n*ncv+1. + Upon Input: V contains the ncv vectors of the Arnoldi basis + for OP as constructed by caupp. + Upon Output: If rvec = TRUE the first NCONV=iparam[5] columns + contain approximate Schur vectors that span the + desired invariant subspace. + NOTE: If the array Z has been set equal to first nev+1 columns + of the array V and rvec = TRUE. and HowMny = 'A', then + the Arnoldi basis held by V has been overwritten by the + desired Ritz vectors. If a separate array Z has been + passed then the first NCONV=iparam[5] columns of V will + contain approximate Schur vectors that span the desired + invariant subspace. + workl (Input / Output) Array of length lworkl+1. + workl[1:ncv*ncv+3*ncv] contains information obtained in + caupp. They are not changed by ceupp. + workl[ncv*ncv+3*ncv+1:3*ncv*ncv+4*ncv] holds the untransformed + Ritz values, the untransformed error estimates of the Ritz + values, the upper triangular matrix for H, and the associated + matrix representation of the invariant subspace for H. + ipntr (Input / Output) Array of length 14. Pointer to mark the + starting locations in the workl array for matrices/vectors + used by caupp and ceupp. + ipntr[9]: pointer to the ncv RITZ values of the original + system. + ipntr[11]: pointer to the ncv corresponding error estimates. + ipntr[12]: pointer to the ncv by ncv upper triangular + Schur matrix for H. + ipntr[13]: pointer to the ncv by ncv matrix of eigenvectors + of the upper Hessenberg matrix H. Only referenced + by ceupp if rvec = TRUE. See Remark 2 below. + info (Output) Error flag. + = 0 : Normal exit. + = 1 : The Schur form computed by LAPACK routine csheqr + could not be reordered by LAPACK routine ztrsen. + Re-enter subroutine ceupp with iparam[5] = ncv and + increase the size of the array D to have + dimension at least dimension ncv and allocate at least + ncv columns for Z. NOTE: Not necessary if Z and V share + the same space. Please notify the authors if this error + occurs. + = -1 : n must be positive. + = -2 : nev must be positive. + = -3 : ncv must satisfy nev+1 <= ncv <= n. + = -5 : which must be one of 'LM','SM','LR','SR','LI','SI'. + = -6 : bmat must be one of 'I' or 'G'. + = -7 : Length of private work workl array is not sufficient. + = -8 : Error return from LAPACK eigenvalue calculation. + This should never happened. + = -9 : Error return from calculation of eigenvectors. + Informational error from LAPACK routine ztrevc. + = -10: iparam[7] must be 1, 2 or 3. + = -11: iparam[7] = 1 and bmat = 'G' are incompatible. + = -12: HowMny = 'S' not yet implemented. + = -13: HowMny must be one of 'A' or 'P' if rvec = TRUE. + = -14: caupp did not find any eigenvalues to sufficient + accuracy. + + NOTE: The following arguments + + bmat, n, which, nev, tol, resid, ncv, V, ldv, iparam, + ipntr, workd, workl, lworkl, rwork, info + + must be passed directly to ceupp following the last call + to caupp. These arguments MUST NOT BE MODIFIED between + the the last call to caupp and the call to ceupp. + + Remarks + 1. Currently only HowMny = 'A' and 'P' are implemented. + 2. Schur vectors are an orthogonal representation for the basis of + Ritz vectors. Thus, their numerical properties are often superior. + Let X' denote the transpose of X. If rvec = .TRUE. then the + relationship A * V[:,1:iparam[5]] = V[:,1:iparam[5]] * T, and + V[:,1:iparam[5]]' * V[:,1:iparam[5]] = I are approximately satisfied. + Here T is the leading submatrix of order iparam[5] of the real + upper quasi-triangular matrix stored workl[ipntr[12]]. +*/ + +{ + + ARint irvec; + ARlogical* iselect; + arcomplex* iZ; + + irvec = (ARint) rvec; + iselect = new ARlogical[ncv]; + iZ = (Z == NULL) ? &V[1] : Z; + + F77NAME(zneupd)(&irvec, &HowMny, iselect, d, iZ, &ldz, &sigma, + &workev[1], &bmat, &n, which.c_str(), &nev, &tol, resid, + &ncv, &V[1], &ldv, &iparam[1], &ipntr[1], + &workd[1], &workl[1], &lworkl, &rwork[1], &info); + + delete[] iselect; + +} // ceupp (arcomplex). + +inline void ceupp(bool rvec, char HowMny, arcomplex d[], + arcomplex Z[], ARint ldz, arcomplex sigma, + arcomplex workev[], char bmat, ARint n, const std::string& which, + ARint nev, float tol, arcomplex resid[], ARint ncv, + arcomplex V[], ARint ldv, ARint iparam[], + ARint ipntr[], arcomplex workd[], + arcomplex workl[], ARint lworkl, float rwork[], + ARint& info) + +/* + c++ version of ARPACK routine cneupd. The only difference between + cneupd and zneupd is that in the former function all vectors have + single precision elements and in the latter all vectors have double + precision elements. +*/ + +{ + + ARint irvec; + ARlogical* iselect; + arcomplex* iZ; + + irvec = (ARint) rvec; + iselect = new ARlogical[ncv]; + iZ = (Z == NULL) ? &V[1] : Z; + + F77NAME(cneupd)(&irvec, &HowMny, iselect, d, iZ, &ldz, &sigma, + &workev[1], &bmat, &n, which.c_str(), &nev, &tol, resid, + &ncv, &V[1], &ldv, &iparam[1], &ipntr[1], + &workd[1], &workl[1], &lworkl, &rwork[1], &info); + + delete[] iselect; + +} // ceupp (arcomplex). + +#endif // CEUPP_H diff --git a/external/arpack++/include/cholmodc.h b/external/arpack++/include/cholmodc.h new file mode 100644 index 000000000..f1300cbb5 --- /dev/null +++ b/external/arpack++/include/cholmodc.h @@ -0,0 +1,161 @@ +/* + ARPACK++ v1.2 2/20/2000 + c++ interface to ARPACK code. + + MODULE CHOLMODc.h. + Interface to CHOLMOD routines. + + Author of this class: + Martin Reuter + Date 11/05/2012 + + Arpack++ Author: + Francisco Gomes + + ARPACK Authors + Richard Lehoucq + Danny Sorensen + Chao Yang + Dept. of Computational & Applied Mathematics + Rice University + Houston, Texas +*/ + +#ifndef CHOLMODC_H +#define CHOLMODC_H + +#include "cholmod.h" +#include + +inline void Write_Cholmod_Sparse_Matrix(const std::string & fname, + cholmod_sparse* A, cholmod_common *c) +{ + std::ofstream myfile; + myfile.open ( fname.c_str() ); + cholmod_triplet * T = cholmod_sparse_to_triplet(A,c); + //std::cout << " [ " << std::endl; + myfile.precision(20); + for (unsigned int i=0;innz;i++) + { + myfile << ((int*)T->i)[i]+1 << " " << ((int*)T->j)[i]+1 << " " << ((double*)T->x)[i] << std::endl; + } + //std::cout << " ] " << std::endl; + myfile.close(); + + cholmod_free_triplet(&T,c); + +} + +// Create_Cholmod_Sparse_Matrix +inline cholmod_sparse* Create_Cholmod_Sparse_Matrix(int m, int n, int nnz, + double* a, int* irow, int* pcol, char uplo, cholmod_common *c) +{ + + cholmod_sparse* A = new cholmod_sparse; + A->nrow = m; + A->ncol = n; + A->nzmax = nnz; + A->p = pcol; + A->i = irow; + A->nz = NULL; + A->x = a; + A->z = NULL; + if (uplo == 'L') A->stype = -1; + else A->stype = 1; + A->itype = CHOLMOD_INT; + A->xtype = CHOLMOD_REAL; // real + A->dtype = CHOLMOD_DOUBLE; // double + A->sorted = 0; + A->packed = 1; + + return A; + + +/* double* hd = new double[nnz]; + int* hi = new int[nnz]; + int* hp = new int[n+1]; + + int col,j; + int counter=0; + int counter2=0; + for (col=0;col= col) ||(uplo == 'U' && row <= col)) + { + hd[counter2] = a[counter]; + hi[counter2] = irow[counter]; + counter2++; + //std::cout << " In : " << std::flush; + } + //else std::cout << " Out : " << std::flush; + + //std::cout << row+1 << " " << col+1 << " " << a[counter] << std::endl; + counter++; + } + + } + hp[n] = counter2; + + + cholmod_sparse* A = new cholmod_sparse; + A->nrow = m; + A->ncol = n; + A->nzmax = counter2; + A->p = hp; + A->i = hi; + A->nz = NULL; + A->x = hd; + A->z = NULL; + if (uplo == 'L') A->stype = -1; + else A->stype = 1; + A->itype = CHOLMOD_INT; + A->xtype = CHOLMOD_REAL; // real + A->dtype = CHOLMOD_DOUBLE; // double + A->sorted = 0; + A->packed = 1; + + //cholmod_sparse* As = cholmod_copy_sparse(A,c); + + return A;*/ + +} // Create_Cholmod_Sparse_Matrix (double). + +// Create_Cholmod_Dense_Matrix (from Triplet) +inline cholmod_dense* Create_Cholmod_Dense_Matrix(int m, int n, + double* a, cholmod_common *c) +{ + + + cholmod_dense* A = new cholmod_dense; + A->nrow = m; + A->ncol = n; + A->nzmax = m*n; + A->d = m; + A->x = a; + A->z = NULL; + A->xtype = CHOLMOD_REAL; // real + A->dtype = CHOLMOD_DOUBLE; // double + +// cholmod_dense* As = cholmod_copy_dense(A,c); + + return A; + +} // Create_Cholmod_Dense_Matrix (double). + +// Create_Cholmod_Dense_Matrix (from Triplet) +inline void Get_Cholmod_Dense_Data(cholmod_dense* A, int n, double* a) +{ + memcpy(a,A->x,n*sizeof(double)); + +// for (int i = 0;ix)[i]; + +} // Create_Cholmod_Dense_Matrix (double). + + + +#endif // CHOLMODC_H diff --git a/external/arpack++/include/debug.h b/external/arpack++/include/debug.h new file mode 100644 index 000000000..2ceab437d --- /dev/null +++ b/external/arpack++/include/debug.h @@ -0,0 +1,135 @@ +/* + ARPACK++ v1.2 2/20/2000 + c++ interface to ARPACK code. + + MODULE debug.h. + Interface to ARPACK FORTRAN debugging facilities. + + ARPACK Authors + Richard Lehoucq + Danny Sorensen + Chao Yang + Dept. of Computational & Applied Mathematics + Rice University + Houston, Texas +*/ + +#ifndef DEBUG_H +#define DEBUG_H + +#include "arch.h" +#include "arpackf.h" + + +inline void TraceOff() + +/* + This function sets all ARPACK FORTRAN debug variables to zero. +*/ + +{ + + F77NAME(debug).logfil = 6; + F77NAME(debug).ndigit = 0; + F77NAME(debug).mgetv0 = 0; + F77NAME(debug).msaupd = 0; + F77NAME(debug).msaup2 = 0; + F77NAME(debug).msaitr = 0; + F77NAME(debug).mseigt = 0; + F77NAME(debug).msapps = 0; + F77NAME(debug).msgets = 0; + F77NAME(debug).mseupd = 0; + F77NAME(debug).mnaupd = 0; + F77NAME(debug).mnaup2 = 0; + F77NAME(debug).mnaitr = 0; + F77NAME(debug).mneigt = 0; + F77NAME(debug).mnapps = 0; + F77NAME(debug).mngets = 0; + F77NAME(debug).mneupd = 0; + F77NAME(debug).mcaupd = 0; + F77NAME(debug).mcaup2 = 0; + F77NAME(debug).mcaitr = 0; + F77NAME(debug).mceigt = 0; + F77NAME(debug).mcapps = 0; + F77NAME(debug).mcgets = 0; + F77NAME(debug).mceupd = 0; + +} // TraceOff. + + +inline void sTraceOn(const ARint digit, const ARint getv0, const ARint aupd, + const ARint aup2, const ARint aitr, const ARint eigt, + const ARint apps, const ARint gets, const ARint eupd) + +/* + This function sets the values of all ARPACK FORTRAN debug + variables corresponding to real symmetric eigenvalue problems. +*/ + +{ + + F77NAME(debug).logfil = 6; + F77NAME(debug).ndigit = digit; + F77NAME(debug).mgetv0 = getv0; + F77NAME(debug).msaupd = aupd; + F77NAME(debug).msaup2 = aup2; + F77NAME(debug).msaitr = aitr; + F77NAME(debug).mseigt = eigt; + F77NAME(debug).msapps = apps; + F77NAME(debug).msgets = gets; + F77NAME(debug).mseupd = eupd; + +} // sTraceOn. + + +inline void nTraceOn(const ARint digit, const ARint getv0, const ARint aupd, + const ARint aup2, const ARint aitr, const ARint eigt, + const ARint apps, const ARint gets, const ARint eupd) + +/* + This function sets the values of all ARPACK FORTRAN debug + variables corresponding to real nonsymmetric eigenvalue problems. +*/ + +{ + + F77NAME(debug).logfil = 6; + F77NAME(debug).ndigit = digit; + F77NAME(debug).mgetv0 = getv0; + F77NAME(debug).mnaupd = aupd; + F77NAME(debug).mnaup2 = aup2; + F77NAME(debug).mnaitr = aitr; + F77NAME(debug).mneigt = eigt; + F77NAME(debug).mnapps = apps; + F77NAME(debug).mngets = gets; + F77NAME(debug).mneupd = eupd; + +} // nTraceOn. + + +inline void cTraceOn(const ARint digit, const ARint getv0, const ARint aupd, + const ARint aup2, const ARint aitr, const ARint eigt, + const ARint apps, const ARint gets, const ARint eupd) + +/* + This function sets the values of all ARPACK FORTRAN debug + variables corresponding to complex eigenvalue problems. +*/ + +{ + + F77NAME(debug).logfil = 6; + F77NAME(debug).ndigit = digit; + F77NAME(debug).mgetv0 = getv0; + F77NAME(debug).mcaupd = aupd; + F77NAME(debug).mcaup2 = aup2; + F77NAME(debug).mcaitr = aitr; + F77NAME(debug).mceigt = eigt; + F77NAME(debug).mcapps = apps; + F77NAME(debug).mcgets = gets; + F77NAME(debug).mceupd = eupd; + +} // cTraceOn. + + +#endif // DEBUG_H diff --git a/external/arpack++/include/lapackc.h b/external/arpack++/include/lapackc.h new file mode 100644 index 000000000..47dd05bc3 --- /dev/null +++ b/external/arpack++/include/lapackc.h @@ -0,0 +1,306 @@ +/* + ARPACK++ v1.2 2/20/2000 + c++ interface to ARPACK code. + + MODULE lapackc.h. + Interface to LAPACK FORTRAN routines. + + ARPACK Authors + Richard Lehoucq + Danny Sorensen + Chao Yang + Dept. of Computational & Applied Mathematics + Rice University + Houston, Texas +*/ + +#include "arch.h" +#include "lapackf.h" + +#ifndef LAPACKC_H +#define LAPACKC_H + + +// LAPY2 + +inline float lapy2(const float &x, const float &y) { + return F77NAME(slapy2)(&x, &y); +} // lapy2 (float) + +inline double lapy2(const double &x, const double &y) { + return F77NAME(dlapy2)(&x, &y); +} // lapy2 (double) + + +// LACPY + +inline void lacpy(const char* uplo, const ARint &m, const ARint &n, + const float a[], const ARint &lda, float b[], + const ARint &ldb) { + F77NAME(slacpy)(uplo, &m, &n, a, &lda, b, &ldb); +} // lacpy (float) + +inline void lacpy(const char* uplo, const ARint &m, const ARint &n, + const double a[], const ARint &lda, double b[], + const ARint &ldb) { + F77NAME(dlacpy)(uplo, &m, &n, a, &lda, b, &ldb); +} // lacpy (double) + +#ifdef ARCOMP_H +inline void lacpy(const char* uplo, const ARint &m, const ARint &n, + const arcomplex a[], const ARint &lda, + arcomplex b[], const ARint &ldb) { + F77NAME(clacpy)(uplo, &m, &n, a, &lda, b, &ldb); +} // lacpy (arcomplex) + +inline void lacpy(const char* uplo, const ARint &m, const ARint &n, + const arcomplex a[], const ARint &lda, + arcomplex b[], const ARint &ldb) { + F77NAME(zlacpy)(uplo, &m, &n, a, &lda, b, &ldb); +} // lacpy (arcomplex) +#endif + + +// GTTRF + +inline void gttrf(const ARint &n, float dl[], float d[], float du[], + float du2[], ARint ipiv[], ARint &info) { + F77NAME(sgttrf)(&n, dl, d, du, du2, ipiv, &info); +} // gttrf (float) + +inline void gttrf(const ARint &n, double dl[], double d[], double du[], + double du2[], ARint ipiv[], ARint &info) { + F77NAME(dgttrf)(&n, dl, d, du, du2, ipiv, &info); +} // gttrf (double) + +#ifdef ARCOMP_H +inline void gttrf(const ARint &n, arcomplex dl[], arcomplex d[], + arcomplex du[], arcomplex du2[], ARint ipiv[], + ARint &info) { + F77NAME(cgttrf)(&n, dl, d, du, du2, ipiv, &info); +} // gttrf (arcomplex) + +inline void gttrf(const ARint &n, arcomplex dl[], arcomplex d[], + arcomplex du[], arcomplex du2[], ARint ipiv[], + ARint &info) { + F77NAME(zgttrf)(&n, dl, d, du, du2, ipiv, &info); +} // gttrf (arcomplex) +#endif + + +// GTTRS + +inline void gttrs(const char* trans, const ARint &n, const ARint &nrhs, + const float dl[], const float d[], const float du[], + const float du2[], const ARint ipiv[], float b[], + const ARint &ldb, ARint &info) { + F77NAME(sgttrs)(trans, &n, &nrhs, dl, d, du, du2, ipiv, b, &ldb, &info); +} // gttrs (float) + +inline void gttrs(const char* trans, const ARint &n, const ARint &nrhs, + const double dl[], const double d[], const double du[], + const double du2[], const ARint ipiv[], double b[], + const ARint &ldb, ARint &info) { + F77NAME(dgttrs)(trans, &n, &nrhs, dl, d, du, du2, ipiv, b, &ldb, &info); +} // gttrs (double) + +#ifdef ARCOMP_H + +inline void gttrs(const char* trans, const ARint &n, const ARint &nrhs, + const arcomplex dl[], const arcomplex d[], + const arcomplex du[], const arcomplex du2[], + const ARint ipiv[], arcomplex b[], + const ARint &ldb, ARint &info) { + F77NAME(cgttrs)(trans, &n, &nrhs, dl, d, du, du2, ipiv, b, &ldb, &info); +} // gttrs (arcomplex) + +inline void gttrs(const char* trans, const ARint &n, const ARint &nrhs, + const arcomplex dl[], const arcomplex d[], + const arcomplex du[], const arcomplex du2[], + const ARint ipiv[], arcomplex b[], + const ARint &ldb, ARint &info) { + F77NAME(zgttrs)(trans, &n, &nrhs, dl, d, du, du2, ipiv, b, &ldb, &info); +} // gttrs (arcomplex) +#endif + + +// GBTRF + +inline void gbtrf(const ARint &m, const ARint &n, const ARint &kl, + const ARint &ku, float ab[], const ARint &ldab, + ARint ipiv[], ARint &info) { + F77NAME(sgbtrf)(&m, &n, &kl, &ku, ab, &ldab, ipiv, &info); +} // gbtrf (float) + +inline void gbtrf(const ARint &m, const ARint &n, const ARint &kl, + const ARint &ku, double ab[], const ARint &ldab, + ARint ipiv[], ARint &info) { + F77NAME(dgbtrf)(&m, &n, &kl, &ku, ab, &ldab, ipiv, &info); +} // gbtrf (double) + +#ifdef ARCOMP_H +inline void gbtrf(const ARint &m, const ARint &n, const ARint &kl, + const ARint &ku, arcomplex ab[], + const ARint &ldab, ARint ipiv[], ARint &info) { + F77NAME(cgbtrf)(&m, &n, &kl, &ku, ab, &ldab, ipiv, &info); +} // gbtrf (arcomplex) + +inline void gbtrf(const ARint &m, const ARint &n, const ARint &kl, + const ARint &ku, arcomplex ab[], + const ARint &ldab, ARint ipiv[], ARint &info) { + F77NAME(zgbtrf)(&m, &n, &kl, &ku, ab, &ldab, ipiv, &info); +} // gbtrf (arcomplex) +#endif + + +// GBTRS + +inline void gbtrs(const char* trans, const ARint &n, const ARint &kl, + const ARint &ku, const ARint &nrhs, const float ab[], + const ARint &ldab, const ARint ipiv[], float b[], + const ARint &ldb, ARint &info) { + F77NAME(sgbtrs)(trans, &n, &kl, &ku, &nrhs, ab, &ldab, ipiv, b, &ldb, &info); +} // gbtrs (float) + +inline void gbtrs(const char* trans, const ARint &n, const ARint &kl, + const ARint &ku, const ARint &nrhs, const double ab[], + const ARint &ldab, const ARint ipiv[], double b[], + const ARint &ldb, ARint &info) { + F77NAME(dgbtrs)(trans, &n, &kl, &ku, &nrhs, ab, &ldab, ipiv, b, &ldb, &info); +} // gbtrs (double) + +#ifdef ARCOMP_H +inline void gbtrs(const char* trans, const ARint &n, const ARint &kl, + const ARint &ku, const ARint &nrhs, + const arcomplex ab[], const ARint &ldab, + const ARint ipiv[], arcomplex b[], + const ARint &ldb, ARint &info) { + F77NAME(cgbtrs)(trans, &n, &kl, &ku, &nrhs, ab, &ldab, ipiv, b, &ldb, &info); +} // gbtrs (arcomplex) + +inline void gbtrs(const char* trans, const ARint &n, const ARint &kl, + const ARint &ku, const ARint &nrhs, + const arcomplex ab[], const ARint &ldab, + const ARint ipiv[], arcomplex b[], + const ARint &ldb, ARint &info) { + F77NAME(zgbtrs)(trans, &n, &kl, &ku, &nrhs, ab, &ldab, ipiv, b, &ldb, &info); +} // gbtrs (arcomplex) +#endif + + +// GETRF + +inline void getrf(const ARint &m, const ARint &n, float A[], + const ARint &lda, ARint ipiv[], ARint &info) { + F77NAME(sgetrf)(&m, &n, A, &lda, ipiv, &info); +} // getrf (float) + +inline void getrf(const ARint &m, const ARint &n, double A[], + const ARint &lda, ARint ipiv[], ARint &info) { + F77NAME(dgetrf)(&m, &n, A, &lda, ipiv, &info); +} // getrf (double) + +#ifdef ARCOMP_H +inline void getrf(const ARint &m, const ARint &n, arcomplex A[], + const ARint &lda, ARint ipiv[], ARint &info) { + F77NAME(cgetrf)(&m, &n, A, &lda, ipiv, &info); +} // getrf (arcomplex) + +inline void getrf(const ARint &m, const ARint &n, arcomplex A[], + const ARint &lda, ARint ipiv[], ARint &info) { + F77NAME(zgetrf)(&m, &n, A, &lda, ipiv, &info); +} // getrf (arcomplex) +#endif + +// GETRS + +inline void getrs(const char* trans, const ARint &n, const ARint &nrhs, + const float A[], const ARint &lda, const ARint ipiv[], + float b[], const ARint &ldb, ARint &info) { + F77NAME(sgetrs)(trans, &n, &nrhs, A, &lda, ipiv, b, &ldb, &info); +} // getrs (float) + +inline void getrs(const char* trans, const ARint &n, const ARint &nrhs, + const double A[], const ARint &lda, const ARint ipiv[], + double b[], const ARint &ldb, ARint &info) { + F77NAME(dgetrs)(trans, &n, &nrhs, A, &lda, ipiv, b, &ldb, &info); +} // getrs (double) + +#ifdef ARCOMP_H +inline void getrs(const char* trans, const ARint &n, const ARint &nrhs, + const arcomplex A[], const ARint &lda, + const ARint ipiv[], arcomplex b[], + const ARint &ldb, ARint &info) { + F77NAME(cgetrs)(trans, &n, &nrhs, A, &lda, ipiv, b, &ldb, &info); +} // getrs (arcomplex) + +inline void getrs(const char* trans, const ARint &n, const ARint &nrhs, + const arcomplex A[], const ARint &lda, + const ARint ipiv[], arcomplex b[], + const ARint &ldb, ARint &info) { + F77NAME(zgetrs)(trans, &n, &nrhs, A, &lda, ipiv, b, &ldb, &info); +} // getrs (arcomplex) +#endif + +// PTTRF + +inline void pttrf(const ARint &n, float d[], float e[], ARint &info) { + F77NAME(spttrf)(&n, d, e, &info); +} // pttrf (float) + +inline void pttrf(const ARint &n, double d[], double e[], ARint &info) { + F77NAME(dpttrf)(&n, d, e, &info); +} // pttrf (double) + +// PTTRS + +inline void pttrs(const ARint &n, const ARint &nrhs, + const float d[], const float e[], float b[], + const ARint &ldb, ARint &info) { + F77NAME(spttrs)(&n, &nrhs, d, e, b, &ldb, &info); +} // pttrs (float) + +inline void pttrs(const ARint &n, const ARint &nrhs, + const double d[], const double e[], double b[], + const ARint &ldb, ARint &info) { + F77NAME(dpttrs)(&n, &nrhs, d, e, b, &ldb, &info); +} // pttrs (double) + + +// SPTRF + +inline void sptrf(const char* trans, const ARint &n, float ap[], + ARint ipiv[], ARint &info) { + F77NAME(ssptrf)(trans, &n, ap, ipiv, &info); +} // sptrf (float) + +inline void sptrf(const char* trans, const ARint &n, double ap[], + ARint ipiv[], ARint &info) { + F77NAME(dsptrf)(trans, &n, ap, ipiv, &info); +} // sptrf (double) + + +// SPTRS + +inline void sptrs(const char* trans, const ARint &n, const ARint &nrhs, + float ap[], ARint ipiv[], float b[], + const ARint &ldb, ARint &info) { + F77NAME(ssptrs)(trans, &n, &nrhs, ap, ipiv, b, &ldb, &info); +} // sptrs (float) + +inline void sptrs(const char* trans, const ARint &n, const ARint &nrhs, + double ap[], ARint ipiv[], double b[], + const ARint &ldb, ARint &info) { + F77NAME(dsptrs)(trans, &n, &nrhs, ap, ipiv, b, &ldb, &info); +} // sptrs (double) + + +inline void second(const float &t) { + F77NAME(second)(&t); +} + +#endif // LAPACKC_H + + + + diff --git a/external/arpack++/include/lapackf.h b/external/arpack++/include/lapackf.h new file mode 100644 index 000000000..2d6209b04 --- /dev/null +++ b/external/arpack++/include/lapackf.h @@ -0,0 +1,207 @@ +/* + ARPACK++ v1.2 2/20/2000 + c++ interface to ARPACK code. + + MODULE lapackf.h. + Interface to LAPACK FORTRAN routines. + + ARPACK Authors + Richard Lehoucq + Danny Sorensen + Chao Yang + Dept. of Computational & Applied Mathematics + Rice University + Houston, Texas +*/ + +#ifndef LAPACKF_H +#define LAPACKF_H + +#include "arch.h" + +extern "C" +{ + + // Single precision real routines. + + float F77NAME(slapy2)(const float *x, const float *y); + + void F77NAME(slacpy)(const char* uplo, const ARint *m, const ARint *n, + const float *a, const ARint *lda, float *b, + const ARint *ldb); + + void F77NAME(sgttrf)(const ARint *n, float *dl, float *d, float *du, + float *du2, ARint *ipiv, ARint *info); + + void F77NAME(sgbtrf)(const ARint *m, const ARint *n, const ARint *kl, + const ARint *ku, float *ab, const ARint *ldab, + ARint *ipiv, ARint *info); + + void F77NAME(sgetrf)(const ARint *m, const ARint *n, float *A, + const ARint *lda, ARint *ipiv, ARint *info); + + void F77NAME(sgttrs)(const char* trans, const ARint *n, + const ARint *nrhs, const float *dl, + const float *d, const float *du, + const float *du2, const ARint *ipiv, + float* b, const ARint *ldb, ARint *info); + + void F77NAME(sgbtrs)(const char* trans, const ARint *n, + const ARint *kl, const ARint *ku, + const ARint *nrhs, const float *ab, + const ARint *ldab, const ARint *ipiv, + float *b, const ARint *ldb, ARint *info); + + void F77NAME(sgetrs)(const char* trans, const ARint *n, + const ARint *nrhs, const float *A, + const ARint *lda, const ARint *ipiv, + float* b, const ARint *ldb, ARint *info); + + void F77NAME(spttrf)(const ARint *n, float *d, float *e, ARint *info); + + void F77NAME(spttrs)(const ARint *n, const ARint *nrhs, + const float *d, const float *e, float *b, + const ARint *ldb, ARint *info); + + void F77NAME(ssptrf)(const char* trans, const ARint *n, + float *ap, ARint *ipiv, ARint *info); + + void F77NAME(ssptrs)(const char* trans, const ARint *n, + const ARint *nrhs, float *ap, ARint *ipiv, + float *b, const ARint *ldb, ARint *info); + + // Double precision real routines. + + double F77NAME(dlapy2)(const double *x, const double *y); + + void F77NAME(dlacpy)(const char* uplo, const ARint *m, const ARint *n, + const double *a, const ARint *lda, double *b, + const ARint *ldb); + + void F77NAME(dgttrf)(const ARint *n, double *dl, double *d, double *du, + double *du2, ARint *ipiv, ARint *info); + + void F77NAME(dgbtrf)(const ARint *m, const ARint *n, const ARint *kl, + const ARint *ku, double *ab, const ARint *ldab, + ARint *ipiv, ARint *info); + + void F77NAME(dgetrf)(const ARint *m, const ARint *n, double *A, + const ARint *lda, ARint *ipiv, ARint *info); + + void F77NAME(dgttrs)(const char* trans, const ARint *n, + const ARint *nrhs, const double *dl, + const double *d, const double *du, + const double *du2, const ARint *ipiv, + double* b, const ARint *ldb, ARint *info); + + void F77NAME(dgbtrs)(const char* trans, const ARint *n, + const ARint *kl, const ARint *ku, + const ARint *nrhs, const double *ab, + const ARint *ldab, const ARint *ipiv, + double *b, const ARint *ldb, ARint *info); + + void F77NAME(dgetrs)(const char* trans, const ARint *n, + const ARint *nrhs, const double *A, + const ARint *lda, const ARint *ipiv, + double* b, const ARint *ldb, ARint *info); + + void F77NAME(dpttrf)(const ARint *n, double *d, double *e, ARint *info); + + void F77NAME(dpttrs)(const ARint *n, const ARint *nrhs, + const double *d, const double *e, double *b, + const ARint *ldb, ARint *info); + + void F77NAME(dsptrf)(const char* trans, const ARint *n, + double *ap, ARint *ipiv, ARint *info); + + void F77NAME(dsptrs)(const char* trans, const ARint *n, + const ARint *nrhs, double *ap, ARint *ipiv, + double *b, const ARint *ldb, ARint *info); + +#ifdef ARCOMP_H + + // Single precision complex routines. + + void F77NAME(clacpy)(const char* uplo, const ARint *m, const ARint *n, + const arcomplex *a, const ARint *lda, + arcomplex *b, const ARint *ldb); + + void F77NAME(cgttrf)(const ARint *n, arcomplex *dl, + arcomplex *d, arcomplex *du, + arcomplex *du2, ARint *ipiv, + ARint *info); + + void F77NAME(cgbtrf)(const ARint *m, const ARint *n, const ARint *kl, + const ARint *ku, arcomplex *ab, + const ARint *ldab, ARint *ipiv, ARint *info); + + void F77NAME(cgetrf)(const ARint *m, const ARint *n, arcomplex *A, + const ARint *lda, ARint *ipiv, ARint *info); + + void F77NAME(cgttrs)(const char *trans, const ARint *n, + const ARint *nrhs, const arcomplex *dl, + const arcomplex *d, const arcomplex *du, + const arcomplex *du2, const ARint *ipiv, + arcomplex* b, const ARint *ldb, + ARint *info); + + void F77NAME(cgbtrs)(const char* trans, const ARint *n, + const ARint *kl, const ARint *ku, + const ARint *nrhs, const arcomplex *ab, + const ARint *ldab, const ARint *ipiv, + arcomplex *b, const ARint *ldb, + ARint *info); + + void F77NAME(cgetrs)(const char* trans, const ARint *n, + const ARint *nrhs, const arcomplex *A, + const ARint *lda, const ARint *ipiv, + arcomplex* b, const ARint *ldb, ARint *info); + + // Double precision complex routines. + + void F77NAME(zlacpy)(const char* uplo, const ARint *m, const ARint *n, + const arcomplex *a, const ARint *lda, + arcomplex *b, const ARint *ldb); + + void F77NAME(zgttrf)(const ARint *n, arcomplex *dl, + arcomplex *d, arcomplex *du, + arcomplex *du2, ARint *ipiv, + ARint *info); + + void F77NAME(zgbtrf)(const ARint *m, const ARint *n, const ARint *kl, + const ARint *ku, arcomplex *ab, + const ARint *ldab, ARint *ipiv, ARint *info); + + void F77NAME(zgetrf)(const ARint *m, const ARint *n, arcomplex *A, + const ARint *lda, ARint *ipiv, ARint *info); + + void F77NAME(zgttrs)(const char *trans, const ARint *n, + const ARint *nrhs, const arcomplex *dl, + const arcomplex *d, const arcomplex *du, + const arcomplex *du2, const ARint *ipiv, + arcomplex* b, const ARint *ldb, + ARint *info); + + void F77NAME(zgbtrs)(const char* trans, const ARint *n, + const ARint *kl, const ARint *ku, + const ARint *nrhs, const arcomplex *ab, + const ARint *ldab, const ARint *ipiv, + arcomplex *b, const ARint *ldb, + ARint *info); + + void F77NAME(zgetrs)(const char* trans, const ARint *n, + const ARint *nrhs, const arcomplex *A, + const ARint *lda, const ARint *ipiv, + arcomplex* b, const ARint *ldb, ARint *info); + +#endif // ARCOMP_H + + void F77NAME(second)(const float *T); + +} +#endif // LAPACKF_H + + + + + diff --git a/external/arpack++/include/naupp.h b/external/arpack++/include/naupp.h new file mode 100644 index 000000000..d29b258c4 --- /dev/null +++ b/external/arpack++/include/naupp.h @@ -0,0 +1,333 @@ +/* + ARPACK++ v1.2 2/20/2000 + c++ interface to ARPACK code. + + MODULE naupp.h. + Interface to ARPACK subroutines dnaupd and snaupd. + + ARPACK Authors + Richard Lehoucq + Danny Sorensen + Chao Yang + Dept. of Computational & Applied Mathematics + Rice University + Houston, Texas +*/ + +#ifndef NAUPP_H +#define NAUPP_H + +#include +#include "arch.h" +#include "arpackf.h" + +inline void naupp(ARint& ido, char bmat, ARint n, const std::string& which, ARint nev, + double& tol, double resid[], ARint ncv, double V[], + ARint ldv, ARint iparam[], ARint ipntr[], double workd[], + double workl[], ARint lworkl, ARint& info) + +/* + c++ version of ARPACK routine dnaupd that implements a variant of + the Arnoldi method. This routine computes approximations to a few + eigenpairs of a linear operator "OP" with respect to a semi-inner + product defined by a symmetric positive semi-definite real matrix + B. B may be the identity matrix. NOTE: If the linear operator "OP" + is real and symmetric with respect to the real positive semi-definite + symmetric matrix B, i.e. B*OP = (OP')*B, then subroutine saupp + should be used instead. + + The computed approximate eigenvalues are called Ritz values and + the corresponding approximate eigenvectors are called Ritz vectors. + + naupp is usually called iteratively to solve one of the + following problems: + + Mode 1: A*x = lambda*x. + ===> OP = A and B = I. + + Mode 2: A*x = lambda*M*x, M symmetric positive definite + ===> OP = inv[M]*A and B = M. + ===> (If M can be factored see remark 3 below) + + Mode 3: A*x = lambda*M*x, M symmetric semi-definite + ===> OP = Real_Part{ inv[A - sigma*M]*M } and B = M. + ===> shift-and-invert mode (in real arithmetic) + If OP*x = amu*x, then + amu = 1/2 * [ 1/(lambda-sigma) + 1/(lambda-conjg(sigma)) ]. + Note: If sigma is real, i.e. imaginary part of sigma is zero; + Real_Part{ inv[A - sigma*M]*M } == inv[A - sigma*M]*M + amu == 1/(lambda-sigma). + + Mode 4: A*x = lambda*M*x, M symmetric semi-definite + ===> OP = Imaginary_Part{ inv[A - sigma*M]*M } and B = M. + ===> shift-and-invert mode (in real arithmetic) + If OP*x = amu*x, then + amu = 1/2i * [ 1/(lambda-sigma) - 1/(lambda-conjg(sigma)) ]. + + Both mode 3 and 4 give the same enhancement to eigenvalues close to + the (complex) shift sigma. However, as lambda goes to infinity, + the operator OP in mode 4 dampens the eigenvalues more strongly than + does OP defined in mode 3. + + NOTE: The action of w <- inv[A - sigma*M]*v or w <- inv[M]*v should + be accomplished either by a direct method using a sparse matrix + factorization and solving + + [A - sigma*M]*w = v or M*w = v, + + or through an iterative method for solving these systems. If an + iterative method is used, the convergence test must be more + stringent than the accuracy requirements for the eigenvalue + approximations. + + Parameters: + + ido (Input / Output) Reverse communication flag. ido must be + zero on the first call to naupp. ido will be set + internally to indicate the type of operation to be + performed. Control is then given back to the calling + routine which has the responsibility to carry out the + requested operation and call naupp with the result. The + operand is given in workd[ipntr[1]], the result must be + put in workd[ipntr[2]]. + ido = 0: first call to the reverse communication interface. + ido = -1: compute Y = OP * X where + ipntr[1] is the pointer into workd for X, + ipntr[2] is the pointer into workd for Y. + This is for the initialization phase to force the + starting vector into the range of OP. + ido = 1: compute Y = OP * X where + ipntr[1] is the pointer into workd for X, + ipntr[2] is the pointer into workd for Y. + In mode 3 and 4, the vector B * X is already + available in workd[ipntr[3]]. It does not + need to be recomputed in forming OP * X. + ido = 2: compute Y = B * X where + ipntr[1] is the pointer into workd for X, + ipntr[2] is the pointer into workd for Y. + ido = 3: compute the iparam[8] real and imaginary parts + of the shifts where inptr[14] is the pointer + into workl for placing the shifts. See Remark + 5 below. + ido = 99: done. + bmat (Input) bmat specifies the type of the matrix B that defines + the semi-inner product for the operator OP. + bmat = 'I' -> standard eigenvalue problem A*x = lambda*x; + bmat = 'G' -> generalized eigenvalue problem A*x = lambda*M*x. + n (Input) Dimension of the eigenproblem. + nev (Input) Number of eigenvalues to be computed. 0 < nev < n-1. + which (Input) Specify which of the Ritz values of OP to compute. + 'LM' - compute the NEV eigenvalues of largest magnitude. + 'SM' - compute the NEV eigenvalues of smallest magnitude. + 'LR' - compute the NEV eigenvalues of largest real part. + 'SR' - compute the NEV eigenvalues of smallest real part. + 'LI' - compute the NEV eigenvalues of largest imaginary part. + 'SI' - compute the NEV eigenvalues of smallest imaginary part. + tol (Input) Stopping criterion: the relative accuracy of the + Ritz value is considered acceptable if BOUNDS[i] <= + tol*abs(RITZ[i]),where ABS(RITZ[i]) is the magnitude when + RITZ[i] is complex. If tol<=0.0 is passed, the machine + precision as computed by the LAPACK auxiliary subroutine + _LAMCH is used. + resid (Input / Output) Array of length n. + On input: + If info==0, a random initial residual vector is used. + If info!=0, resid contains the initial residual vector, + possibly from a previous run. + On output: + resid contains the final residual vector. + ncv (Input) Number of Arnoldi vectors that are generated at each + iteration. After the startup phase in which nev Arnoldi + vectors are generated, the algorithm generates ncv-nev + Arnoldi vectors at each subsequent update iteration. Most of + the cost in generating each Arnoldi vector is in the + matrix-vector product OP*x. + NOTE: 2 <= NCV-NEV in order that complex conjugate pairs of + Ritz values are kept together (see remark 4 below). + V (Output) Double precision array of length ncv*n+1. V contains + the ncv Arnoldi basis vectors. The first element V[0] is never + referenced. + ldv (Input) Dimension of the basis vectors contianed in V. This + parameter MUST be set to n. + iparam (Input / Output) Array of length 12. + iparam[1] = ISHIFT: method for selecting the implicit shifts. + The shifts selected at each iteration are used to restart + the Arnoldi iteration in an implicit fashion. + ------------------------------------------------------------- + ISHIFT = 0: the shifts are provided by the user via + reverse communication. The real and imaginary + parts of the NCV eigenvalues of the Hessenberg + matrix H are returned in the part of the WORKL + array corresponding to RITZR and RITZI. See remark + 5 below. + ISHIFT = 1: exact shifts with respect to the current + Hessenberg matrix H. This is equivalent to + restarting the iteration with a starting vector + that is a linear combination of approximate Schur + vectors associated with the "wanted" Ritz values. + ------------------------------------------------------------- + iparam[2] is no longer referenced. + iparam[3] = MXITER + On INPUT: maximum number of Arnoldi update iterations allowed. + On OUTPUT: actual number of Arnoldi update iterations taken. + iparam[4] = NB: blocksize to be used in the recurrence. + The code currently works only for NB = 1. + iparam[5] = NCONV: number of "converged" Ritz values. + This represents the number of Ritz values that satisfy + the convergence criterion. + iparam[6] is no longer referenced. + iparam[7] = MODE. On INPUT determines what type of + eigenproblem is being solved. Must be 1,2,3,4. + iparam[8] = NP. When ido = 3 and the user provides shifts + through reverse communication (iparam[1]=0), naupp returns + NP, the number of shifts the user is to provide. + 0 < NP <=ncv-nev. See Remark 5 below. + iparam[9] = total number of OP*x operations. + iparam[10] = total number of B*x operations if bmat='G'. + iparam[11] = total number of steps of re-orthogonalization. + ipntr (Output) Array of length 14. Pointer to mark the starting + locations in the workd and workl arrays for matrices/vectors + used by the Arnoldi iteration. + ipntr[1] : pointer to the current operand vector X in workd. + ipntr[2] : pointer to the current result vector Y in workd. + ipntr[3] : pointer to the vector B * X in workd when used in + the shift-and-invert mode. + ipntr[4] : pointer to the next available location in workl + that is untouched by the program. + ipntr[5] : pointer to the ncv by ncv upper Hessenberg matrix + H in workl. + ipntr[6] : pointer to the real part of the ritz value array + RITZR in workl. + ipntr[7] : pointer to the imaginary part of the ritz value + array RITZI in workl. + ipntr[8] : pointer to the Ritz estimates in array workl + associated with the Ritz values located in RITZR + and RITZI in workl. + ipntr[14]: pointer to the np shifts in workl. See Remark 6. + Note: ipntr[9:13] is only referenced by neupp. See Remark 2. + ipntr[9] : pointer to the real part of the ncv RITZ values of + the original system. + ipntr[10]: pointer to the imaginary part of the ncv RITZ values + of the original system. + ipntr[11]: pointer to the ncv corresponding error bounds. + ipntr[12]: pointer to the ncv by ncv upper quasi-triangular + Schur matrix for H. + ipntr[13]: pointer to the ncv by ncv matrix of eigenvectors + of the upper Hessenberg matrix H. Only referenced by + neupp if rvec == TRUE. See Remark 2 below. + workd (Input / Output) Array of length 3*N+1. + Distributed array to be used in the basic Arnoldi iteration + for reverse communication. The user should not use workd as + temporary workspace during the iteration. Upon termination + workd[1:n] contains B*resid[1:n]. If the Ritz vectors are + desired subroutine neupp uses this output. + workl (Output) Array of length lworkl+1. Private (replicated) array + on each PE or array allocated on the front end. + lworkl (Input) lworkl must be at least 3*ncv*(ncv+2). + info (Input / Output) On input, if info = 0, a randomly initial + residual vector is used, otherwise resid contains the initial + residual vector, possibly from a previous run. + On output, info works as a error flag: + = 0 : Normal exit. + = 1 : Maximum number of iterations taken. All possible + eigenvalues of OP has been found. iparam[5] + returns the number of wanted converged Ritz values. + = 3 : No shifts could be applied during a cycle of the + Implicitly restarted Arnoldi iteration. One + possibility is to increase the size of NCV relative + to nev. See remark 4 below. + = -1 : n must be positive. + = -2 : nev must be positive. + = -3 : ncv must satisfy nev+2 <= ncv <= n. + = -4 : The maximum number of Arnoldi update iterations + allowed must be greater than zero. + = -5 : which must be one of 'LM','SM','LR','SR','LI','SI'. + = -6 : bmat must be one of 'I' or 'G'. + = -7 : Length of private work array workl is not sufficient. + = -8 : Error return from LAPACK eigenvalue calculation. + = -9 : Starting vector is zero. + = -10 : iparam[7] must be 1,2,3,4. + = -11 : iparam[7] = 1 and bmat = 'G' are incompatible. + = -12 : iparam[1] must be equal to 0 or 1. + = -13 : nev and which = 'BE' are incompatible. + = -9999: Could not build an Arnoldi factorization. iparam[5] + returns the size of the current Arnoldi factorization. + The user is advised to check that enough workspace + and array storage has been allocated. + + Remarks: + 1. The computed Ritz values are approximate eigenvalues of OP. The + selection of "which" should be made with this in mind when + Mode = 3 and 4. After convergence, approximate eigenvalues of the + original problem may be obtained with the ARPACK subroutine neupp. + 2. If a basis for the invariant subspace corresponding to the converged + Ritz values is needed, the user must call neupp immediately following + completion of naupp. This is new starting with release 2 of ARPACK. + 3. If M can be factored into a Cholesky factorization M = LL' + then Mode = 2 should not be selected. Instead one should use + Mode = 1 with OP = inv(L)*A*inv(L'). Appropriate triangular + linear systems should be solved with L and L' rather + than computing inverses. After convergence, an approximate + eigenvector z of the original problem is recovered by solving + L'z = x where x is a Ritz vector of OP. + 4. At present there is no a-priori analysis to guide the selection + of ncv relative to nev. The only formal requrement is that ncv + >= nev+2. However, it is recommended that ncv >= 2*nev+1. If many + problems of the same type are to be solved, one should experiment + with increasing ncv while keeping ncv fixed for a given test + problem. This will usually decrease the required number of OP*x + operations but it also increases the work and storage required to + maintain the orthogonal basis vectors. The optimal "cross-over" + with respect to CPU time is problem dependent and must be + determined empirically. + 5. When iparam[1] = 0, and ido = 3, the user needs to provide the + NP = iparam[8] real and imaginary parts of the shifts in locations + real part imaginary part + ----------------------- -------------- + 1 workl[ipntr[14]] workl[ipntr[14]+NP] + 2 workl[ipntr[14]+1] workl[ipntr[14]+NP+1] + . . + . . + . . + NP workl[ipntr[14]+NP-1] workl[ipntr[14]+2*NP-1]. + + Only complex conjugate pairs of shifts may be applied and the pairs + must be placed in consecutive locations. The real part of the + eigenvalues of the current upper Hessenberg matrix are located in + workl[ipntr[6]] through workl[ipntr[6]+ncv-1] and the imaginary part + in workl[ipntr[7]] through workl[ipntr[7]+ncv-1]. They are ordered + according to the order defined by which. The complex conjugate pairs + are kept together and the associated Ritz estimates are located in + workl[ipntr[8]], workl[ipntr[8]+1], ... , workl[ipntr[8]+ncv-1]. +*/ + +{ + + F77NAME(dnaupd)(&ido, &bmat, &n, which.c_str(), &nev, &tol, resid, &ncv, + &V[1], &ldv, &iparam[1], &ipntr[1], &workd[1], &workl[1], + &lworkl, &info); + +} // naupp (double). + +inline void naupp(ARint& ido, char bmat, ARint n, const std::string& which, ARint nev, + float& tol, float resid[], ARint ncv, float V[], + ARint ldv, ARint iparam[], ARint ipntr[], float workd[], + float workl[], ARint lworkl, ARint& info) + +/* + c++ version of ARPACK routine snaupd. The only difference between + snaupd and dnaupd is that in the former function all vectors have + single precision elements and in the latter all vectors have double + precision elements. +*/ + +{ + + F77NAME(snaupd)(&ido, &bmat, &n, which.c_str(), &nev, &tol, resid, &ncv, + &V[1], &ldv, &iparam[1], &ipntr[1], &workd[1], &workl[1], + &lworkl, &info); + +} // naupp (float). + +#endif // NAUPP_H + diff --git a/external/arpack++/include/neupp.h b/external/arpack++/include/neupp.h new file mode 100644 index 000000000..2b102d775 --- /dev/null +++ b/external/arpack++/include/neupp.h @@ -0,0 +1,270 @@ +/* + ARPACK++ v1.2 2/20/2000 + c++ interface to ARPACK code. + + MODULE neupp.h. + Interface to ARPACK subroutines dneupd and sneupd. + + ARPACK Authors + Richard Lehoucq + Danny Sorensen + Chao Yang + Dept. of Computational & Applied Mathematics + Rice University + Houston, Texas +*/ + +#ifndef NEUPP_H +#define NEUPP_H + +#include +#include +#include "arch.h" +#include "arpackf.h" + +inline void neupp(bool rvec, char HowMny, double dr[], + double di[], double Z[], ARint ldz, double sigmar, + double sigmai, double workv[], char bmat, ARint n, + const std::string& which, ARint nev, double tol, double resid[], + ARint ncv, double V[], ARint ldv, ARint iparam[], + ARint ipntr[], double workd[], double workl[], + ARint lworkl, ARint& info) + +/* + c++ version of ARPACK routine dneupd. + This subroutine returns the converged approximations to eigenvalues + of A*z = lambda*B*z and (optionally): + + (1) the corresponding approximate eigenvectors, + (2) an orthonormal basis for the associated approximate + invariant subspace, + + There is negligible additional cost to obtain eigenvectors. An + orthonormal basis is always computed. There is an additional storage cost + of n*nev if both are requested (in this case a separate array Z must be + supplied). + The approximate eigenvalues and eigenvectors of A*z = lambda*B*z + are derived from approximate eigenvalues and eigenvectors of + of the linear operator OP prescribed by the MODE selection in the + call to naupp. naupp must be called before this routine is called. + These approximate eigenvalues and vectors are commonly called Ritz + values and Ritz vectors respectively. They are referred to as such + in the comments that follow. The computed orthonormal basis for the + invariant subspace corresponding to these Ritz values is referred to + as a Schur basis. + See documentation in the header of the subroutine naupp for + definition of OP as well as other terms and the relation of computed + Ritz values and Ritz vectors of OP with respect to the given problem + A*z = lambda*B*z. For a brief description, see definitions of + iparam[7], MODE and which in the documentation of naupp. + + Parameters: + + rvec (Input) Specifies whether Ritz vectors corresponding to the + Ritz value approximations to the eigenproblem A*z = lambda*B*z + are computed. + rvec = false: Compute Ritz values only. + rvec = true : Compute the Ritz vectors or Schur vectors. + See Remarks below. + HowMny (Input) Specifies the form of the basis for the invariant + subspace corresponding to the converged Ritz values that + is to be computed. + = 'A': Compute nev Ritz vectors; + = 'P': Compute nev Schur vectors; + dr (Output) Array of dimension nev+1. + If iparam[7] = 1,2 or 3 and sigmai=0.0 then on exit: dr + contains the real part of the Ritz approximations to the + eigenvalues of A*z = lambda*B*z. + If iparam[7] = 3, 4 and sigmai is not equal to zero, then on + exit: dr contains the real part of the Ritz values of OP + computed by naupp. A further computation must be performed by + the user to transform the Ritz values computed for OP by naupp + to those of the original system A*z = lambda*B*z. See remark 3. + di (Output) Array of dimension nev+1. + On exit, di contains the imaginary part of the Ritz value + approximations to the eigenvalues of A*z = lambda*B*z + associated with dr. + NOTE: When Ritz values are complex, they will come in complex + conjugate pairs. If eigenvectors are requested, the + corresponding Ritz vectors will also come in conjugate + pairs and the real and imaginary parts of these are + represented in two consecutive columns of the array Z + (see below). + Z (Output) Array of dimension nev*n if rvec = TRUE and HowMny = + 'A'. if rvec = TRUE. and HowMny = 'A', then the contains + approximate eigenvectors (Ritz vectors) corresponding to the + NCONV=iparam[5] Ritz values for eigensystem A*z = lambda*B*z. + The complex Ritz vector associated with the Ritz value + with positive imaginary part is stored in two consecutive + columns. The first column holds the real part of the Ritz + vector and the second column holds the imaginary part. The + Ritz vector associated with the Ritz value with negative + imaginary part is simply the complex conjugate of the Ritz + vector associated with the positive imaginary part. + If rvec = .FALSE. or HowMny = 'P', then Z is not referenced. + NOTE: If if rvec = .TRUE. and a Schur basis is not required, + the array Z may be set equal to first nev+1 columns of + the Arnoldi basis array V computed by naupp. In this + case the Arnoldi basis will be destroyed and overwritten + with the eigenvector basis. + ldz (Input) Dimension of the vectors contained in Z. This + parameter MUST be set to n. + sigmar (Input) If iparam[7] = 3 or 4, represents the real part of + the shift. Not referenced if iparam[7] = 1 or 2. + sigmai (Input) If iparam[7] = 3 or 4, represents the imaginary part + of the shift. Not referenced if iparam[7] = 1 or 2. See + remark 3 below. + workv (Workspace) Array of dimension 3*ncv. + V (Input/Output) Array of dimension n*ncv+1. + Upon Input: V contains the ncv vectors of the Arnoldi basis + for OP as constructed by naupp. + Upon Output: If rvec = TRUE the first NCONV=iparam[5] columns + contain approximate Schur vectors that span the + desired invariant subspace. See Remark 2 below. + NOTE: If the array Z has been set equal to first nev+1 columns + of the array V and rvec = TRUE. and HowMny = 'A', then + the Arnoldi basis held by V has been overwritten by the + desired Ritz vectors. If a separate array Z has been + passed then the first NCONV=iparam[5] columns of V will + contain approximate Schur vectors that span the desired + invariant subspace. + workl (Input / Output) Array of length lworkl+1. + workl[1:ncv*ncv+3*ncv] contains information obtained in + naupp. They are not changed by neupp. + workl[ncv*ncv+3*ncv+1:3*ncv*ncv+6*ncv] holds the real and + imaginary part of the untransformed Ritz values, the upper + quasi-triangular matrix for H, and the associated matrix + representation of the invariant subspace for H. + ipntr (Input / Output) Array of length 14. Pointer to mark the + starting locations in the workl array for matrices/vectors + used by naupp and neupp. + ipntr[9]: pointer to the real part of the ncv RITZ values + of the original system. + ipntr[10]: pointer to the imaginary part of the ncv RITZ + values of the original system. + ipntr[11]: pointer to the ncv corresponding error bounds. + ipntr[12]: pointer to the ncv by ncv upper quasi-triangular + Schur matrix for H. + ipntr[13]: pointer to the ncv by ncv matrix of eigenvectors + of the upper Hessenberg matrix H. Only referenced + by neupp if rvec = TRUE. See Remark 2 below. + info (Output) Error flag. + = 0 : Normal exit. + = 1 : The Schur form computed by LAPACK routine dlahqr + could not be reordered by LAPACK routine dtrsen. + Re-enter subroutine neupp with iparam[5] = ncv and + increase the size of the arrays DR and DI to have + dimension at least dimension ncv and allocate at least + ncv columns for Z. NOTE: Not necessary if Z and V share + the same space. Please notify the authors if this error + occurs. + = -1 : n must be positive. + = -2 : nev must be positive. + = -3 : ncv must satisfy nev+2 <= ncv <= n. + = -5 : which must be one of 'LM','SM','LR','SR','LI','SI'. + = -6 : bmat must be one of 'I' or 'G'. + = -7 : Length of private work workl array is not sufficient. + = -8 : Error return from calculation of a real Schur form. + Informational error from LAPACK routine dlahqr. + = -9 : Error return from calculation of eigenvectors. + Informational error from LAPACK routine dtrevc. + = -10: iparam[7] must be 1,2,3,4. + = -11: iparam[7] = 1 and bmat = 'G' are incompatible. + = -12: HowMny = 'S' not yet implemented + = -13: HowMny must be one of 'A' or 'P' if rvec = TRUE. + = -14: naupp did not find any eigenvalues to sufficient + accuracy. + + NOTE: The following arguments + + bmat, n, which, nev, tol, resid, ncv, V, ldv, iparam, + ipntr, workd, workl, lworkl, info + + must be passed directly to neupp following the last call + to naupp. These arguments MUST NOT BE MODIFIED between + the the last call to naupp and the call to neupp. + + Remarks + 1. Currently only HowMny = 'A' and 'P' are implemented. + 2. Schur vectors are an orthogonal representation for the basis of + Ritz vectors. Thus, their numerical properties are often superior. + Let X' denote the transpose of X. If rvec = .TRUE. then the + relationship A * V[:,1:iparam[5]] = V[:,1:iparam[5]] * T, and + V[:,1:iparam[5]]' * V[:,1:iparam[5]] = I are approximately satisfied. + Here T is the leading submatrix of order iparam[5] of the real + upper quasi-triangular matrix stored workl[ipntr[12]]. That is, + T is block upper triangular with 1-by-1 and 2-by-2 diagonal blocks; + each 2-by-2 diagonal block has its diagonal elements equal and its + off-diagonal elements of opposite sign. Corresponding to each + 2-by-2 diagonal block is a complex conjugate pair of Ritz values. + The real Ritz values are stored on the diagonal of T. + 3. If iparam[7] = 3 or 4 and sigmai is not equal zero, then the user + must form the iparam[5] Rayleigh quotients in order to transform the + Ritz values computed by naupp for OP to those of A*z = lambda*B*z. + Set rvec = TRUE. and HowMny = 'A', and compute + Z[:,I]' * A * Z[:,I] if di[I] = 0. + If di[I] is not equal to zero and di[I+1] = - D[I], + then the desired real and imaginary parts of the Ritz value are + Z[:,I]' * A * Z[:,I] + Z[:,I+1]' * A * Z[:,I+1], + Z[:,I]' * A * Z[:,I+1] - Z[:,I+1]' * A * Z[:,I], respectively. + Another possibility is to set rvec = .true. and HowMny = 'P' and + compute V[:,1:iparam[5]]' * A * V[:,1:iparam[5]] and then an upper + quasi-triangular matrix of order iparam[5] is computed. See remark + 2 above. +*/ + +{ + + ARint irvec; + ARlogical* iselect; + double* iZ; + + irvec = (ARint) rvec; + iselect = new ARlogical[ncv]; + iZ = (Z == NULL) ? &V[1] : Z; + + F77NAME(dneupd)(&irvec, &HowMny, iselect, dr, di, iZ, &ldz, &sigmar, + &sigmai, &workv[1], &bmat, &n, which.c_str(), &nev, &tol, + resid, &ncv, &V[1], &ldv, &iparam[1], &ipntr[1], + &workd[1], &workl[1], &lworkl, &info); + + delete[] iselect; + +} // neupp (double). + +inline void neupp(bool rvec, char HowMny, float dr[], + float di[], float Z[], ARint ldz, float sigmar, + float sigmai, float workv[], char bmat, ARint n, + const std::string& which, ARint nev, float tol, float resid[], + ARint ncv, float V[], ARint ldv, ARint iparam[], + ARint ipntr[], float workd[], float workl[], + ARint lworkl, ARint& info) + +/* + c++ version of ARPACK routine sneupd. The only difference between + sneupd and dneupd is that in the former function all vectors have + single precision elements and in the latter all vectors have double + precision elements. +*/ + +{ + + ARint irvec; + ARlogical* iselect; + float* iZ; + + irvec = (ARint) rvec; + iselect = new ARlogical[ncv]; + iZ = (Z == NULL) ? &V[1] : Z; + + F77NAME(sneupd)(&irvec, &HowMny, iselect, dr, di, iZ, &ldz, &sigmar, + &sigmai, &workv[1], &bmat, &n, which.c_str(), &nev, &tol, + resid, &ncv, &V[1], &ldv, &iparam[1], &ipntr[1], + &workd[1], &workl[1], &lworkl, &info ); + + delete[] iselect; + +} // neupp (float). + +#endif // NEUPP_H + diff --git a/external/arpack++/include/saupp.h b/external/arpack++/include/saupp.h new file mode 100644 index 000000000..a0c256cbc --- /dev/null +++ b/external/arpack++/include/saupp.h @@ -0,0 +1,321 @@ +/* + ARPACK++ v1.2 2/20/2000 + c++ interface to ARPACK code. + + MODULE saupp.h. + Interface to ARPACK subroutines dsaupd and ssaupd. + + ARPACK Authors + Richard Lehoucq + Danny Sorensen + Chao Yang + Dept. of Computational & Applied Mathematics + Rice University + Houston, Texas +*/ + +#ifndef SAUPP_H +#define SAUPP_H + +#include +#include "arch.h" +#include "arpackf.h" + +inline void saupp(ARint& ido, char bmat, ARint n, const std::string& which, ARint nev, + double& tol, double resid[], ARint ncv, double V[], + ARint ldv, ARint iparam[], ARint ipntr[], double workd[], + double workl[], ARint lworkl, ARint& info) + +/* + c++ version of ARPACK routine dsaupd that implements a variant of + the Lanczos method. This method has been designed to compute + approximations to a few eigenpairs of a linear operator OP that is + real and symmetric with respect to a real positive semi-definite + symmetric matrix B, i.e. + + B*OP = (OP')*B. + + where A' denotes transpose of A. In the standard eigenproblem B is + the identity matrix. Another way to express this condition is + + < x,OPy > = < OPx,y > where < z,w > = z'Bw. + + The computed approximate eigenvalues are called Ritz values and + the corresponding approximate eigenvectors are called Ritz vectors. + + saupp is usually called iteratively to solve one of the + following problems: + + Mode 1: A*x = lambda*x, A symmetric + ===> OP = A and B = I. + + Mode 2: A*x = lambda*M*x, A symmetric, M symmetric positive definite + ===> OP = inv[M]*A and B = M. + ===> (If M can be factored see remark 3 below) + + Mode 3: K*x = lambda*M*x, K symmetric, M symmetric positive semi-definite + ===> OP = (inv[K - sigma*M])*M and B = M. + ===> Shift-and-Invert mode + + Mode 4: K*x = lambda*KG*x, K symmetric positive semi-definite, + KG symmetric indefinite + ===> OP = (inv[K - sigma*KG])*K and B = K. + ===> Buckling mode + + Mode 5: A*x = lambda*M*x, A symmetric, M symmetric positive semi-definite + ===> OP = inv[A - sigma*M]*[A + sigma*M] and B = M. + ===> Cayley transformed mode + + NOTE: The action of w <- inv[A - sigma*M]*v or w <- inv[M]*v should be + accomplished either by a direct method using a sparse matrix + factorization and solving + + [A - sigma*M]*w = v or M*w = v, + + or through an iterative method for solving these systems. If an + iterative method is used, the convergence test must be more + stringent than the accuracy requirements for the eigenvalue + approximations. + + Parameters: + + ido (Input / Output) Reverse communication flag. ido must be + zero on the first call to saupp. ido will be set + internally to indicate the type of operation to be + performed. Control is then given back to the calling + routine which has the responsibility to carry out the + requested operation and call saupp with the result. The + operand is given in workd[ipntr[1]], the result must be + put in workd[ipntr[2]]. (If Mode = 2 see remark 5 below). + ido = 0: first call to the reverse communication interface. + ido = -1: compute Y = OP * X where + ipntr[1] is the pointer into workd for X, + ipntr[2] is the pointer into workd for Y. + This is for the initialization phase to force the + starting vector into the range of OP. + ido = 1: compute Y = OP * X where + ipntr[1] is the pointer into workd for X, + ipntr[2] is the pointer into workd for Y. + In mode 3,4 and 5, the vector B * X is already + available in workd[ipntr[3]]. It does not + need to be recomputed in forming OP * X. + ido = 2: compute Y = B * X where + ipntr[1] is the pointer into workd for X, + ipntr[2] is the pointer into workd for Y. + ido = 3: compute the iparam[8] shifts where + ipntr[11] is the pointer into workl for + placing the shifts. See remark 6 below. + ido = 99: done. + bmat (Input) bmat specifies the type of the matrix B that defines + the semi-inner product for the operator OP. + bmat = 'I' -> standard eigenvalue problem A*x = lambda*x; + bmat = 'G' -> generalized eigenvalue problem A*x = lambda*B*x. + n (Input) Dimension of the eigenproblem. + nev (Input) Number of eigenvalues to be computed. 0 < nev < n. + which (Input) Specify which of the Ritz values of OP to compute. + 'LA' - compute the nev largest (algebraic) eigenvalues. + 'SA' - compute the nev smallest (algebraic) eigenvalues. + 'LM' - compute the nev largest (in magnitude) eigenvalues. + 'SM' - compute the nev smallest (in magnitude) eigenvalues. + 'BE' - compute nev eigenvalues, half from each end of the + spectrum. When NEV is odd, compute one more from the + high end than from the low end. + (see remark 1 below) + tol (Input) Stopping criterion: the relative accuracy of the + Ritz value is considered acceptable if BOUNDS[i] <= + tol*abs(RITZ[i]). If tol<=0.0 is passed, the machine + precision as computed by the LAPACK auxiliary subroutine + _LAMCH is used. + resid (Input / Output) Array of length n. + On input: + If info==0, a random initial residual vector is used. + If info!=0, resid contains the initial residual vector, + possibly from a previous run. + On output: + resid contains the final residual vector. + ncv (Input) Number of Lanczos vectors that are generated at each + iteration. After the startup phase in which nev Lanczos + vectors are generated, the algorithm generates ncv-nev + Lanczos vectors at each subsequent update iteration. Most of + the cost in generating each Lanczos vector is in the + matrix-vector product OP*x. (See remark 4 below). + V (Output) Double precision array of length ncv*n+1. V contains + the ncv Lanczos basis vectors. The first element V[0] is never + referenced. + ldv (Input) Dimension of the basis vectors contianed in V. This + parameter MUST be set to n. + iparam (Input / Output) Array of length 12. + iparam[1] = ISHIFT: method for selecting the implicit shifts. + The shifts selected at each iteration are used to restart + the Arnoldi iteration in an implicit fashion. + ------------------------------------------------------------- + ISHIFT = 0: the shifts are provided by the user via + reverse communication. The NCV eigenvalues of + the current tridiagonal matrix T are returned in + the part of workl array corresponding to RITZ. + See remark 6 below. + ISHIFT = 1: exact shifts with respect to the reduced + tridiagonal matrix T. This is equivalent to + restarting the iteration with a starting vector + that is a linear combination of Ritz vectors + associated with the "wanted" Ritz values. + ------------------------------------------------------------- + iparam[2] is no longer referenced. + iparam[3] = MXITER + On INPUT: maximum number of Arnoldi update iterations allowed. + On OUTPUT: actual number of Arnoldi update iterations taken. + iparam[4] = NB: blocksize to be used in the recurrence. + The code currently works only for NB = 1. + iparam[5] = NCONV: number of "converged" Ritz values. + This represents the number of Ritz values that satisfy + the convergence criterion. + iparam[6] is no longer referenced. + iparam[7] = MODE. On INPUT determines what type of + eigenproblem is being solved. Must be 1,2,3,4,5. + iparam[8] = NP. When ido = 3 and the user provides shifts + through reverse communication (iparam[1]=0), saupp returns + NP, the number of shifts the user is to provide. + 0 < NP <=ncv-nev. See Remark 6 below. + iparam[9] = total number of OP*x operations. + iparam[10] = total number of B*x operations if bmat='G'. + iparam[11] = total number of steps of re-orthogonalization. + ipntr (Output) Array of length 12. Pointer to mark the starting + locations in the workd and workl arrays for matrices/vectors + used by the Lanczos iteration. + ipntr[1] : pointer to the current operand vector X in workd. + ipntr[2] : pointer to the current result vector Y in workd. + ipntr[3] : pointer to the vector B * X in workd when used in + the shift-and-invert mode. + ipntr[4] : pointer to the next available location in workl + that is untouched by the program. + ipntr[5] : pointer to the ncv by 2 tridiagonal matrix T in + workl. + ipntr[6] : pointer to the ncv RITZ values array in workl. + ipntr[7] : pointer to the Ritz estimates in array workl + associated with the Ritz values located in RITZ + in workl. + ipntr[11]: pointer to the np shifts in workl. See Remark 6. + Note: ipntr[8:10] is only referenced by seupp. See Remark 2. + ipntr[8] : pointer to the ncv RITZ values of the original + system. + ipntr[9] : pointer to the ncv corresponding error bounds. + ipntr[10]: pointer to the ncv by ncv matrix of eigenvectors + of the tridiagonal matrix T. Only referenced by + seupp if RVEC = TRUE. See Remarks. + workd (Input / Output) Array of length 3*N+1. + Distributed array to be used in the basic Arnoldi iteration + for reverse communication. The user should not use workd as + temporary workspace during the iteration. Upon termination + workd[1:n] contains B*resid[1:n]. If the Ritz vectors are + desired subroutine seupp uses this output. + workl (Output) Array of length lworkl+1. Private (replicated) array + on each PE or array allocated on the front end. + lworkl (Input) lworkl must be at least ncv*(ncv+8). + info (Input / Output) On input, if info = 0, a randomly initial + residual vector is used, otherwise resid contains the initial + residual vector, possibly from a previous run. + On output, info works as a error flag: + = 0 : Normal exit. + = 1 : Maximum number of iterations taken. All possible + eigenvalues of OP has been found. iparam[5] + returns the number of wanted converged Ritz values. + = 3 : No shifts could be applied during a cycle of the + Implicitly restarted Arnoldi iteration. One + possibility is to increase the size of NCV relative + to nev. See remark 4 below. + = -1 : n must be positive. + = -2 : nev must be positive. + = -3 : ncv must satisfy nev < ncv <= n. + = -4 : The maximum number of Arnoldi update iterations allowed + must be greater than zero. + = -5 : which must be one of 'LM', 'SM', 'LA', 'SA' or 'BE'. + = -6 : bmat must be one of 'I' or 'G'. + = -7 : Length of private work array workl is not sufficient. + = -8 : Error return from trid. eigenvalue calculation; + Informational error from LAPACK routine dsteqr. + = -9 : Starting vector is zero. + = -10 : iparam[7] must be 1,2,3,4,5. + = -11 : iparam[7] = 1 and bmat = 'G' are incompatible. + = -12 : iparam[1] must be equal to 0 or 1. + = -13 : nev and which = 'BE' are incompatible. + = -9999: Could not build an Arnoldi factorization. iparam[5] + returns the size of the current Arnoldi factorization. + The user is advised to check that enough workspace + and array storage has been allocated. + + Remarks: + 1. The converged Ritz values are always returned in ascending + algebraic order. The computed Ritz values are approximate + eigenvalues of OP. The selection of "which" should be made + with this in mind when Mode = 3,4,5. After convergence, + approximate eigenvalues of the original problem may be obtained + with the ARPACK subroutine seupp. + 2. If the Ritz vectors corresponding to the converged Ritz values are + needed, the user must call seupp immediately following completion + of saupp. This is new starting with version 2.1 of ARPACK. + 3. If M can be factored into a Cholesky factorization M = LL' + then Mode = 2 should not be selected. Instead one should use + Mode = 1 with OP = inv(L)*A*inv(L'). Appropriate triangular + linear systems should be solved with L and L' rather + than computing inverses. After convergence, an approximate + eigenvector z of the original problem is recovered by solving + L'z = x where x is a Ritz vector of OP. + 4. At present there is no a-priori analysis to guide the selection + of ncv relative to nev. The only formal requrement is that + ncv > nev. However, it is recommended that ncv >= 2*nev. If many + problems of the same type are to be solved, one should experiment + with increasing ncv while keeping nev fixed for a given test + problem. This will usually decrease the required number of OP*x + operations but it also increases the work and storage required to + maintain the orthogonal basis vectors. The optimal "cross-over" + with respect to CPU time is problem dependent and must be + determined empirically. + 5. If iparam[7] = 2 then in the Reverse commuication interface the + user must do the following. When ido = 1, Y = OP * X is to be + computed. When iparam[7] = 2 OP = inv(B)*A. After computing A*X + the user must overwrite X with A*X. Y is then the solution to the + linear set of equations B*Y = A*X. + 6. When iparam[1] = 0, and ido = 3, the user needs to provide the + NP = iparam[8] shifts in locations: + 1 workl[ipntr[11]] + 2 workl[ipntr[11]+1] + . + . + . + NP workl[ipntr[11]+NP-1]. + The eigenvalues of the current tridiagonal matrix are located in + workl[ipntr[6]] through workl[ipntr[6]+ncv]. They are in the + order defined by which. The associated Ritz estimates are located in + workl[ipntr[8]], workl[ipntr[8]+1], ... , workl[ipntr[8]+ncv-1]. +*/ + +{ + + F77NAME(dsaupd)(&ido, &bmat, &n, which.c_str(), &nev, &tol, resid, &ncv, + &V[1], &ldv, &iparam[1], &ipntr[1], &workd[1], &workl[1], + &lworkl, &info); + +} // saupp (double). + +inline void saupp(ARint& ido, char bmat, ARint n, const std::string& which, ARint nev, + float& tol, float resid[], ARint ncv, float V[], + ARint ldv, ARint iparam[], ARint ipntr[], float workd[], + float workl[], ARint lworkl, ARint& info) + +/* + c++ version of ARPACK routine ssaupd. The only difference between + ssaupd and dsaupd is that in the former function all vectors have + single precision elements and in the latter all vectors have double + precision elements. +*/ + +{ + + F77NAME(ssaupd)(&ido, &bmat, &n, which.c_str(), &nev, &tol, resid, &ncv, + &V[1], &ldv, &iparam[1], &ipntr[1], &workd[1], &workl[1], + &lworkl, &info); + +} // saupp (float). + +#endif // SAUPP_H + diff --git a/external/arpack++/include/seupp.h b/external/arpack++/include/seupp.h new file mode 100644 index 000000000..5e5c60511 --- /dev/null +++ b/external/arpack++/include/seupp.h @@ -0,0 +1,190 @@ +/* + ARPACK++ v1.2 2/20/2000 + c++ interface to ARPACK code. + + MODULE seupp.h. + Interface to ARPACK subroutines dseupd and sseupd. + + ARPACK Authors + Richard Lehoucq + Danny Sorensen + Chao Yang + Dept. of Computational & Applied Mathematics + Rice University + Houston, Texas +*/ + +#ifndef SEUPP_H +#define SEUPP_H + +#include +#include +#include "arch.h" +#include "arpackf.h" + +inline void seupp(bool rvec, char HowMny, double d[], double Z[], + ARint ldz, double sigma, char bmat, ARint n, + const std::string& which, ARint nev, double tol, double resid[], + ARint ncv, double V[], ARint ldv, ARint iparam[], + ARint ipntr[], double workd[], double workl[], + ARint lworkl, ARint& info) + +/* + c++ version of ARPACK routine dseupd. + This subroutine returns the converged approximations to eigenvalues + of A*z = lambda*B*z and (optionally): + + (1) the corresponding approximate eigenvectors, + (2) an orthonormal (Lanczos) basis for the associated approximate + invariant subspace, + + There is negligible additional cost to obtain eigenvectors. An orthonormal + (Lanczos) basis is always computed. There is an additional storage cost + of n*nev if both are requested (in this case a separate array Z must be + supplied). + These quantities are obtained from the Lanczos factorization computed + by saupp for the linear operator OP prescribed by the MODE selection + (see IPARAM[7] in saupp documentation). saupp must be called before + this routine is called. These approximate eigenvalues and vectors are + commonly called Ritz values and Ritz vectors respectively. They are + referred to as such in the comments that follow. The computed orthonormal + basis for the invariant subspace corresponding to these Ritz values is + referred to as a Lanczos basis. + See documentation in the header of the subroutine dsaupp for a definition + of OP as well as other terms and the relation of computed Ritz values + and vectors of OP with respect to the given problem A*z = lambda*B*z. + The approximate eigenvalues of the original problem are returned in + ascending algebraic order. The user may elect to call this routine + once for each desired Ritz vector and store it peripherally if desired. + There is also the option of computing a selected set of these vectors + with a single call. + + Parameters: + + rvec (Input) Specifies whether Ritz vectors corresponding to the + Ritz value approximations to the eigenproblem A*z = lambda*B*z + are computed. + rvec = false: Compute Ritz values only. + rvec = true : Compute Ritz vectors. + HowMny (Input) Specifies how many Ritz vectors are wanted and the + form of Z, the matrix of Ritz vectors. See remark 1 below. + The only option already implemented is HowMny = 'A'. + d (Output) Array of dimension nev. On exit, d contains the Ritz + value approximations to the eigenvalues of A*z = lambda*B*z. + The values are returned in ascending order. If iparam[7] = + 3, 4, 5 then d represents the Ritz values of OP computed by + dsaupp transformed to those of the original eigensystem A*z = + lambda*B*z. If iparam[7] = 1,2 then the Ritz values of OP are + the same as the those of A*z = lambda*B*z. + Z (Output) Array of dimension nev*n if HowMny = 'A'. On + exit, Z contains the B-orthonormal Ritz vectors of the + eigensystem A*z = lambda*B*z corresponding to the Ritz value + approximations. If rvec = false then Z is not referenced. + NOTE: The array Z may be set equal to first nev columns of + the Arnoldi/Lanczos basis array V computed by dsaupp. + ldz (Input) Dimension of the vectors contained in Z. This + parameter MUST be set to n. + sigma (Input) If iparam[7] = 3,4,5 represents the shift. Not + referenced if iparam[7] = 1 or 2. + workl (Input / Output) Array of length lworkl+1. + workl[1:4*ncv] contains information obtained in saupp. + They are not changed by seupp. workl[4*ncv+1:ncv*(ncv+8)] + holds the untransformed Ritz values, the computed error + estimates, and the associated eigenvector matrix of H. + Note: ipntr[8:10] contains the pointer into workl for + addresses of the above information computed by seupp. + ipntr (Input / Output) Array of length 12. Pointer to mark the + starting locations in the workl array for matrices/vectors + used by dsaupp and seupp. + ipntr[8] : pointer to the RITZ values of the original system. + ipntr[9] : pointer to the ncv corresponding error bounds. + ipntr[10]: pointer to the ncv by ncv matrix of eigenvectors + of the tridiagonal matrix T. Only referenced by + seupp if rvec = true. See Remarks. + info (Output) Error flag. + = 0 : Normal exit. + = -1 : n must be positive. + = -2 : nev must be positive. + = -3 : ncv must satisfy nev < ncv <= n. + = -5 : which must be one of 'LM', 'SM', 'LA', 'SA' or 'BE'. + = -6 : bmat must be one of 'I' or 'G'. + = -7 : Length of private work workl array is not sufficient. + = -8 : Error return from trid. eigenvalue calculation; + Information error from LAPACK routine dsteqr. + = -9 : Starting vector is zero. + = -10: iparam[7] must be 1,2,3,4,5. + = -11: iparam[7] = 1 and bmat = 'G' are incompatible. + = -12: nev and which = 'BE' are incompatible. + = -14: dsaupp did not find any eigenvalues to sufficient + accuracy. + = -15: HowMny must be one of 'A' or 'S' if rvec = true. + = -16: HowMny = 'S' not yet implemented. + + NOTE: The following arguments + + bmat, n, which, nev, tol, resid, ncv, V, ldv, iparam, + ipntr, workd, workl, lworkl, info + + must be passed directly to seupp following the last call + to saupp. These arguments MUST NOT BE MODIFIED between + the the last call to saupp and the call to seupp. + + Remarks + 1. The converged Ritz values are always returned in increasing + (algebraic) order. + 2. Currently only HowMny = 'A' is implemented. It is included at + this stage for the user who wants to incorporate it. +*/ + +{ + + ARint irvec; + ARlogical* iselect; + double* iZ; + + irvec = (ARint) rvec; + iselect = new ARlogical[ncv]; + iZ = (Z == NULL) ? &V[1] : Z; + + F77NAME(dseupd)(&irvec, &HowMny, iselect, d, iZ, &ldz, &sigma, &bmat, + &n, which.c_str(), &nev, &tol, resid, &ncv, &V[1], &ldv, &iparam[1], + &ipntr[1], &workd[1], &workl[1], &lworkl, &info ); + + delete[] iselect; + +} // seupp (double). + +inline void seupp(bool rvec, char HowMny, float d[], float Z[], + ARint ldz, float sigma, char bmat, ARint n, + const std::string& which, ARint nev, float tol, float resid[], + ARint ncv, float V[], ARint ldv, ARint iparam[], + ARint ipntr[], float workd[], float workl[], + ARint lworkl, ARint& info) + +/* + c++ version of ARPACK routine sseupd. The only difference between + sseupd and dseupd is that in the former function all vectors have + single precision elements and in the latter all vectors have double + precision elements. +*/ + +{ + + ARint irvec; + ARlogical* iselect; + float* iZ; + + irvec = (ARint) rvec; + iselect = new ARlogical[ncv]; + iZ = (Z == NULL) ? &V[1] : Z; + + F77NAME(sseupd)(&irvec, &HowMny, iselect, d, iZ, &ldz, &sigma, &bmat, + &n, which.c_str(), &nev, &tol, resid, &ncv, &V[1], &ldv, &iparam[1], + &ipntr[1], &workd[1], &workl[1], &lworkl, &info ); + + delete[] iselect; + +} // seupp (float). + +#endif // SEUPP_H + diff --git a/external/arpack++/include/superluc.h b/external/arpack++/include/superluc.h new file mode 100644 index 000000000..cdc7085d9 --- /dev/null +++ b/external/arpack++/include/superluc.h @@ -0,0 +1,165 @@ +/* + ARPACK++ v1.2 2/20/2000 + c++ interface to ARPACK code. + + MODULE SuperLUc.h. + Interface to SuperLU routines. + + ARPACK Authors + Richard Lehoucq + Danny Sorensen + Chao Yang + Dept. of Computational & Applied Mathematics + Rice University + Houston, Texas +*/ + +#ifndef SUPERLUC_H +#define SUPERLUC_H + +#include "arch.h" +#include "arlspdef.h" +#include "arlsupm.h" +#include "arlcomp.h" + +// gstrf. + +inline void gstrf(superlu_options_t *options, SuperMatrix *A, + int relax, int panel_size, int *etree, void *work, int lwork, + int *perm_c, int *perm_r, SuperMatrix *L, SuperMatrix *U, + SuperLUStat_t *stat, int *info) +{ + if (A->Dtype == SLU_D) { // calling the double precision routine. + dGlobalLU_t Glu; + dgstrf(options,A,relax, + panel_size,etree,work,lwork,perm_c,perm_r,L,U,&Glu,stat,info); + } + else if (A->Dtype == SLU_S) { // calling the single precision routine. + sGlobalLU_t Glu; + sgstrf(options,A,relax, + panel_size,etree,work,lwork,perm_c,perm_r,L,U,&Glu,stat,info); + } + else if (A->Dtype == SLU_Z) { // calling the double precision complex routine. +#ifdef ARCOMP_H + zGlobalLU_t Glu; + zgstrf(options,A,relax, + panel_size,etree,work,lwork,perm_c,perm_r,L,U,&Glu,stat,info); +#endif + } + else { // calling the single precision complex routine. +#ifdef ARCOMP_H + cGlobalLU_t Glu; + cgstrf(options,A,relax, + panel_size,etree,work,lwork,perm_c,perm_r,L,U,&Glu,stat,info); +#endif + } + +} // gstrf. + + +inline void gstrs(trans_t trans, SuperMatrix *L, SuperMatrix *U, + int *perm_c, int *perm_r, SuperMatrix *B, SuperLUStat_t* stat, int *info) +{ + + if (L->Dtype == SLU_D) { // calling the double precision routine. + dgstrs(trans,L,U,perm_c,perm_r,B,stat,info); + } + else if (L->Dtype == SLU_S) { // calling the single precision routine. + sgstrs(trans,L,U,perm_c,perm_r,B,stat,info); + } + else if (L->Dtype == SLU_Z) { // calling the double precision complex routine. +#ifdef ARCOMP_H + zgstrs(trans,L,U,perm_c,perm_r,B,stat,info); +#endif + } + else { // calling the single precision complex routine. +#ifdef ARCOMP_H + cgstrs(trans,L,U,perm_c,perm_r,B,stat,info); +#endif + } + +} // gstrs. + + +// Create_CompCol_Matrix. + +inline void Create_CompCol_Matrix(SuperMatrix* A, int m, int n, int nnz, + double* a, int* irow, int* pcol, + Stype_t S, Mtype_t M) +{ + + dCreate_CompCol_Matrix(A,m,n,nnz,a,irow,pcol,S,SLU_D,M); + +} // Create_CompCol_Matrix (double). + +inline void Create_CompCol_Matrix(SuperMatrix* A, int m, int n, int nnz, + float* a, int* irow, int* pcol, + Stype_t S, Mtype_t M) +{ + + sCreate_CompCol_Matrix(A,m,n,nnz,a,irow,pcol,S,SLU_S,M); + +} // Create_CompCol_Matrix (float). + +#ifdef ARCOMP_H + +inline void Create_CompCol_Matrix(SuperMatrix* A, int m, int n, int nnz, + arcomplex* a, int* irow, int* pcol, + Stype_t S, Mtype_t M) +{ + + zCreate_CompCol_Matrix(A,m,n,nnz,(ldcomplex*)a,irow,pcol,S,SLU_Z,M); + +} // Create_CompCol_Matrix (complex). + +inline void Create_CompCol_Matrix(SuperMatrix* A, int m, int n, int nnz, + arcomplex* a, int* irow, int* pcol, + Stype_t S, Mtype_t M) +{ + + cCreate_CompCol_Matrix(A,m,n,nnz,(lscomplex*)a,irow,pcol,S,SLU_C,M); + +} // Create_CompCol_Matrix (complex). + +#endif // ARCOMP_H. + + +// Create_Dense_Matrix. + +inline void Create_Dense_Matrix(SuperMatrix* A, int m, int n, double* x, + int ldx, Stype_t S, Mtype_t M) +{ + + dCreate_Dense_Matrix(A,m,n,x,ldx,S,SLU_D,M); + +} // Create_Dense_Matrix (double). + +inline void Create_Dense_Matrix(SuperMatrix* A, int m, int n, float* x, + int ldx, Stype_t S, Mtype_t M) +{ + + sCreate_Dense_Matrix(A,m,n,x,ldx,S,SLU_S,M); + +} // Create_Dense_Matrix (float). + +#ifdef ARCOMP_H + +inline void Create_Dense_Matrix(SuperMatrix* A, int m, int n, arcomplex* x, + int ldx, Stype_t S, Mtype_t M) +{ + + zCreate_Dense_Matrix(A,m,n,(ldcomplex*)x,ldx,S,SLU_Z,M); + +} // Create_Dense_Matrix (complex). + +inline void Create_Dense_Matrix(SuperMatrix* A, int m, int n, arcomplex* x, + int ldx, Stype_t S, Mtype_t M) +{ + + cCreate_Dense_Matrix(A,m,n,(lscomplex*)x,ldx,S,SLU_C,M); + +} // Create_Dense_Matrix (complex). + +#endif // ARCOMP_H. + +#endif // SUPERLUC_H diff --git a/external/arpack++/include/umfpackc.h b/external/arpack++/include/umfpackc.h new file mode 100644 index 000000000..8c084ad00 --- /dev/null +++ b/external/arpack++/include/umfpackc.h @@ -0,0 +1,216 @@ +/* + ARPACK++ v1.2 2/20/2000 + c++ interface to ARPACK code. + + MODULE UMFPACKc.h. + Interface to UMFPACK routines. + + Author of this class: + Martin Reuter + Date 2/28/2013 + + Arpack++ Author: + Francisco Gomes + + ARPACK Authors + Richard Lehoucq + Danny Sorensen + Chao Yang + Dept. of Computational & Applied Mathematics + Rice University + Houston, Texas +*/ + +#ifndef UMFPACKC_H +#define UMFPACKC_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define UMFPACK_INFO 90 +#define UMFPACK_CONTROL 20 +#define UMFPACK_OK (0) +#define UMFPACK_A (0) /* Ax=b */ +#define UMFPACK_PRL 0 /* print level */ + +void umfpack_di_defaults +( + double Control [UMFPACK_CONTROL] +) ; + + +int umfpack_di_symbolic +( + int n_row, + int n_col, + const int Ap [ ], + const int Ai [ ], + const double Ax [ ], + void **Symbolic, + const double Control [UMFPACK_CONTROL], + double Info [UMFPACK_INFO] +) ; + +int umfpack_di_numeric +( + const int Ap [ ], + const int Ai [ ], + const double Ax [ ], + void *Symbolic, + void **Numeric, + const double Control [UMFPACK_CONTROL], + double Info [UMFPACK_INFO] +) ; + +void umfpack_di_free_symbolic +( + void **Symbolic +) ; + +void umfpack_di_free_numeric +( + void **Numeric +) ; + +int umfpack_di_triplet_to_col +( + int n_row, + int n_col, + int nz, + const int Ti [ ], + const int Tj [ ], + const double Tx [ ], + int Ap [ ], + int Ai [ ], + double Ax [ ], + int Map [ ] +) ; + +int umfpack_di_solve +( + int sys, + const int Ap [ ], + const int Ai [ ], + const double Ax [ ], + double X [ ], + const double B [ ], + void *Numeric, + const double Control [UMFPACK_CONTROL], + double Info [UMFPACK_INFO] +) ; + +int umfpack_di_report_matrix +( + int n_row, + int n_col, + const int Ap [ ], + const int Ai [ ], + const double Ax [ ], + int col_form, + const double Control [UMFPACK_CONTROL] +) ; + +#ifdef __cplusplus + } +#endif + +//#include "umfpack.h" +#include + +inline void Write_Triplet_Matrix(const std::string & fname, int * tripi, + int * tripj, double* tripx, unsigned int nnz) +{ + std::ofstream myfile; + myfile.open ( fname.c_str() ); + myfile.precision(20); + for (unsigned int i=0;innz;i++) + { + myfile << ((int*)T->i)[i]+1 << " " << ((int*)T->j)[i]+1 << " " << ((double*)T->x)[i] << std::endl; + } + //std::cout << " ] " << std::endl; + myfile.close(); + + cholmod_free_triplet(&T,c); + +} + +// Create_Cholmod_Sparse_Matrix +inline cholmod_sparse* Create_Cholmod_Sparse_Matrix(int m, int n, int nnz, + double* a, int* irow, int* pcol, char uplo, cholmod_common *c) +{ + + cholmod_sparse* A = new cholmod_sparse; + A->nrow = m; + A->ncol = n; + A->nzmax = nnz; + A->p = pcol; + A->i = irow; + A->nz = NULL; + A->x = a; + A->z = NULL; + if (uplo == 'L') A->stype = -1; + else A->stype = 1; + A->itype = CHOLMOD_INT; + A->xtype = CHOLMOD_REAL; // real + A->dtype = CHOLMOD_DOUBLE; // double + A->sorted = 0; + A->packed = 1; + + return A; + + + + +} // Create_Cholmod_Sparse_Matrix (double). + +// Create_Cholmod_Dense_Matrix (from Triplet) +inline cholmod_dense* Create_Cholmod_Dense_Matrix(int m, int n, + double* a, cholmod_common *c) +{ + + + cholmod_dense* A = new cholmod_dense; + A->nrow = m; + A->ncol = n; + A->nzmax = m*n; + A->d = m; + A->x = a; + A->z = NULL; + A->xtype = CHOLMOD_REAL; // real + A->dtype = CHOLMOD_DOUBLE; // double + +// cholmod_dense* As = cholmod_copy_dense(A,c); + + return A; + +} // Create_Cholmod_Dense_Matrix (double). + +// Create_Cholmod_Dense_Matrix (from Triplet) +inline void Get_Cholmod_Dense_Data(cholmod_dense* A, int n, double* a) +{ + memcpy(a,A->x,n*sizeof(double)); + +// for (int i = 0;ix)[i]; + +} // Create_Cholmod_Dense_Matrix (double). + +*/ + +#endif // UMFPACKC_H diff --git a/include/SDPAFormatManager.h b/include/SDPAFormatManager.h index 687a3bf56..1178ef7d9 100644 --- a/include/SDPAFormatManager.h +++ b/include/SDPAFormatManager.h @@ -10,6 +10,7 @@ #ifndef VOLESTI_SDPA_FORMAT_MANAGER_H #define VOLESTI_SDPA_FORMAT_MANAGER_H + #include "convex_bodies/spectrahedra/spectrahedron.h" #include diff --git a/include/cartesian_geom/point.h b/include/cartesian_geom/point.h index ac3a7e4d8..a318fa9c5 100644 --- a/include/cartesian_geom/point.h +++ b/include/cartesian_geom/point.h @@ -118,6 +118,7 @@ class point void operator= (const Coeff& coeffs) { this->coeffs = coeffs; + d = coeffs.rows(); } //TODO: avoid point construction in operators +,-,* @@ -172,6 +173,10 @@ class point return true; } + FT distance(point const & p) { + return (this->coeffs - p.coeffs).norm(); + } + FT dot(const point& p) const { return coeffs.dot(p.getCoefficients()); diff --git a/include/convex_bodies/spectrahedra/LMI.h b/include/convex_bodies/spectrahedra/LMI.h index 8598c05a5..a095bb2ba 100644 --- a/include/convex_bodies/spectrahedra/LMI.h +++ b/include/convex_bodies/spectrahedra/LMI.h @@ -10,6 +10,8 @@ #ifndef VOLESTI_LMI_H #define VOLESTI_LMI_H +#include "matrix_operations/EigenvaluesProblems.h" + /// This class handles a linear matrix inequality of the form \[A_0 + \sum x_i A_i <= 0\], /// where <= denotes negative definiteness /// @tparam NT Numeric Type @@ -17,7 +19,57 @@ /// @tparam VT Vector Type template class LMI { + /// The matrices A_0, A_i + std::vector matrices; + + /// The dimension of the vector x + unsigned int d; + + /// The size of the matrices A_i + unsigned int m; + + + /// Creates A LMI object + /// \param[in] matrices The matrices A_0, A_i + LMI(std::vector& matrices) { + typename std::vector::iterator it = matrices.begin(); + + while (it!=matrices.end()) { + this->matrices.push_back(*it); + } + + d = matrices.size() - 1; + m = matrices[0].rows(); + } + /// \returns The dimension of vector x + unsigned int dimension() const { + return d; + } + + /// \returns The size of the matrices + unsigned int sizeOfMatrices() const { + return m; + } + + /// Evaluate \[A_0 + \sum x_i A_i \] + /// \param[in] x The input vector + /// \param[out] ret The output matrix + void evaluate(const VT& x, MT& ret) const { + } + + /// Compute \[x_1*A_1 + ... + x_n A_n] + /// \param[in] x Input vector + /// \param[out] res Output matrix + void evaluateWithoutA0(const VT& x, MT& ret) const { + + } + + /// Compute the gradient of the determinant of the LMI at p + /// \param[in] p Input parameter + /// \param[in] Input vector: lmi(p)*e = 0, e != 0 + /// \param[out] ret The normalized gradient of the determinant of the LMI at p + void normalizedDeterminantGradient(const VT& p, const VT& e, VT& ret) {} }; @@ -48,8 +100,8 @@ class LMI, Eigen::Matrix const & matrices) { - typename std::vector::const_iterator it = matrices.begin(); + LMI(std::vector& matrices) { + typename std::vector::iterator it = matrices.begin(); while (it!=matrices.end()) { this->matrices.push_back(*it); @@ -94,7 +146,7 @@ class LMI, Eigen::Matrix const & getMatrices() const { + std::vector getMatrices() const { return matrices; } @@ -106,7 +158,7 @@ class LMI, Eigen::Matrix, Eigen::Matrix::iterator it; + + int i = 0; + it = matrices.begin(); + ++it; // skip A0 + for (; it != matrices.end(); it++, i++) + res.noalias() += x(i) * (*it); +#else + VT a = vectorMatrix * x; res.resize(m,m); @@ -146,6 +210,8 @@ class LMI, Eigen::Matrix, Eigen::Matrix eigs; + NT eival = eigs.findSymEigenvalue(matrix); + return eival <= 0; + } + + /// evaluate LMI(pos) and check if its negative semidefinite + /// \param pos a vector of our current position + /// \return true is LMI(pos) is negative semidefinite + bool isNegativeSemidefinite(VT const & pos) const { + MT mat; + evaluate(pos, mat); + return isNegativeSemidefinite(mat); + } + }; #endif //VOLESTI_LMI_H diff --git a/include/convex_bodies/spectrahedra/spectrahedron.h b/include/convex_bodies/spectrahedra/spectrahedron.h index a71604316..807f9993c 100644 --- a/include/convex_bodies/spectrahedra/spectrahedron.h +++ b/include/convex_bodies/spectrahedra/spectrahedron.h @@ -11,6 +11,8 @@ #define VOLESTI_SPECTRAHEDRON_H #include "LMI.h" +#include "chrono" + /// This class manipulates a spectrahedron, described by a LMI /// \tparam NT Numeric Type @@ -20,9 +22,42 @@ template class Spectrahedron { public: + /// The numeric/matrix/vector types we use + typedef NT NUMERIC_TYPE; + typedef MT MATRIX_TYPE; + typedef VT VECTOR_TYPE; + /// The type of a pair of NT typedef std::pair pairNT; + /// Among successive calls of this class methods, we may need to pass data + /// from one call to the next, to avoid repeating computations, or to efficiently update values + /// Warning: this struct assists in many methods; perhaps for different methods use different instances + struct PrecomputedValues { + + /// These flags indicate whether the corresponding matrices are computed + /// if yes, we can use them and not compute them fro scratch + bool computed_A = false; + bool computed_C = false; + bool computed_XY = false; + + /// The matrices the method positiveIntersection receives from its previous call + /// if the flag first_positive_intersection is true. + /// Matrix A is also used in coordinateIntersection + MT A, B, C, X, Y; + + /// In method positive_intersect, the distance we are computing corresponds + /// to the minimum positive eigenvalue of a quadratic eigenvalue problem. + /// This will hold the eigenvector for that eigenvalue + VT eigenvector; + + /// Sets all flags to false + void resetFlags() { + computed_XY = computed_C = computed_A = false; + } + }; + + /// The dimension of the spectrahedron unsigned int d; @@ -37,16 +72,180 @@ class Spectrahedron { d = lmi.dimension(); } + + /// Construct the quadratic eigenvalue problem \[At^2 + Bt + C \] for positive_intersect. + /// A = lmi(c) - A0, B = lmi(b) - A0 and C = lmi(c). + /// \param[in] a Input vector + /// \param[in] b Input vector + /// \param[in] c Input vector + /// \param[in, out] precomputedValues Holds matrices A, C + void createMatricesForPositiveIntersection(const VT& a, const VT& b, const VT& c, + PrecomputedValues& precomputedValues) { + // check if matrices A, C are ready + // if not compute them + if (!precomputedValues.computed_A) { + lmi.evaluateWithoutA0(a, precomputedValues.A); + } + + if (!precomputedValues.computed_C) { + lmi.evaluate(c, precomputedValues.C); + } + + // compute Matrix B + lmi.evaluateWithoutA0(b, precomputedValues.B); + } + + /// Computes the distance d we must travel on the parametrized polynomial curve \[at^2 + bt + c \], + /// assuming we start at t=0, and we start increasing t. + /// We construct the quadratic eigenvalue problem \[At^2 + Bt + C \], + /// where A = lmi(c) - A0, B = lmi(b) - A0 and C = lmi(c). + /// Then we do a linearization and transform it to the generalized problem X+lY, + /// which we pass to an external library. + /// \param[in] a Input vector, the coefficient of t \[t^2\] + /// \param[in] b Input vector, the coefficient of t + /// \param[in] c Input Vector, the constant term + /// \param[in, out] precomputedValues Data we move between successive method calls + /// \returns The distance d + NT positiveIntersection(VT const & a, VT const & b, VT const & c, PrecomputedValues& precomputedValues) { + unsigned int matrixDim = lmi.sizeOfMatrices(); + + // create matrices A, B, C + createMatricesForPositiveIntersection(a, b, c, precomputedValues); + + // get the minimum positive eigenvalue of At^2 + Bt + C + EigenvaluesProblems quadraticEigenvaluesProblem; + NT distance = quadraticEigenvaluesProblem.minPosQuadraticEigenvalue(precomputedValues.A, precomputedValues.B, + precomputedValues.C, precomputedValues.X, + precomputedValues.Y, + precomputedValues.eigenvector, + precomputedValues.computed_XY); + + return distance; + } + + + /// Computes the distance d one must travel on the line a + tb, + /// assuming we start at t=0 and that b has zero everywhere and 1 in its i-th coordinate. + /// We must solve the generalized eigenvalue problem A+tB, where A = lmi(a) and B=(lmi) - A0 = A_i + /// If the flag precomputedValues,computed_A is true, the matrix A is not computed. + /// \param[in] a Input vector + /// \param[in] coordinate Indicator of the i-th coordinate, 1 <= coordinate <= dimension + /// \return The pair (positive t, negative t) for which we reach the boundary + pairNT coordinateIntersection(VT const & a, int const coordinate, PrecomputedValues& precomputedValues) { + + // prepare the generalized eigenvalue problem A+lB + // we may not have to compute A! + if (!precomputedValues.computed_A) + lmi.evaluate(a, precomputedValues.A); + + EigenvaluesProblems eigenvaluesProblems; + return eigenvaluesProblems.symGeneralizedProblem(precomputedValues.A, *(lmi.getMatrix(coordinate))); + } + + /// Computes the reflected direction at a point on the boundary of the spectrahedron. + /// \param[in] point A point on the boundary of the spectrahedron + /// \param[in] incomingDirection The direction of the trajectory as it hits the boundary + /// \param[out] reflectedDirection The reflected direction + /// \param[in] precomputedValues Must contain an eigenvalue needed to compute the reflection + void computeReflection(VT const & point, VT const & incomingDirection, VT& reflectedDirection, + PrecomputedValues& precomputedValues) { + + // get the gradient of the determinant of the lmi at point + VT grad; + lmi.normalizedDeterminantGradient(point, precomputedValues.eigenvector, grad); + + // compute reflected direction + // if v is original direction and s the surface normal, + // reflected direction = v - 2 *s + + NT dot = 2 * incomingDirection.dot(grad); + reflectedDirection = incomingDirection - dot * grad; + } + + /// \return The dimension of the spectrahedron unsigned int dimension() const { return d; } /// \return The LMI describing this spectrahedron - LMI const & getLMI() const { + LMI getLMI() const { return lmi; } + /// Estimates the diameter of the spectrahedron. It samples points uniformly with coordinate directions + /// hit and run, and returns the maximum distance between them. + /// \tparam Point + /// \param[in] numPoints The number of points to sample for the estimation + /// \return An estimation of the diameter of the spectrahedron + template + NT estimateDiameter(int const numPoints, Point const & interiorPoint) { + typedef boost::mt19937 RNGType; + + unsigned seed = std::chrono::system_clock::now().time_since_epoch().count(); + RNGType rng(seed); + + std::list randPoints; + + // initialize random numbers generators + boost::random::uniform_real_distribution<> urdist(0, 1); + boost::random::uniform_int_distribution<> uidist(1, d); + + PrecomputedValues precomputedValues; + VT p = interiorPoint.getCoefficients(); + + // sample points with walk length set to 1 + for (int samplingNo=0 ; samplingNo distances = this->coordinateIntersection(p, coordinate, precomputedValues); + + // uniformly set the new point on the segment + // defined by the intersection points + NT lambda = urdist(rng); + NT diff = distances.first + lambda * (distances.second - distances.first); + + p(coordinate - 1) = p(coordinate - 1) + diff; + + // update the precomputedValues, so we can skip + // computations in the next call + precomputedValues.computed_A = true; + precomputedValues.A += diff * *(this->getLMI().getMatrix(coordinate)); + randPoints.push_back(Point(p)); + } + + // find maximum distance among points; + NT maxDistance = 0; + typename std::list::iterator itInner, itOuter = randPoints.begin(); + + for (; itOuter!=randPoints.end() ; ++itOuter) + for (itInner=itOuter ; itInner!=randPoints.end() ; ++itInner) { + NT current = itOuter->distance(*itInner); + if (current > maxDistance) + maxDistance = current; + } + + return maxDistance; + } + + /// Find out is lmi(current position) = mat is in the exterior of the spectrahedron + /// \param mat a matrix where mat = lmi(current position) + /// \return true if position is outside the spectrahedron + bool isExterior(MT const & mat) { + return !lmi.isNegativeSemidefinite(mat); + } + + /// Find out is pos is in the exterior of the spectrahedron + /// \param pos a vector + /// \return true if pos is outside the spectrahedron + bool isExterior(VT const & pos) { + return !lmi.isNegativeSemidefinite(pos); + } }; #endif //VOLESTI_SPECTRAHEDRON_H diff --git a/include/generators/boost_random_number_generator.hpp b/include/generators/boost_random_number_generator.hpp index af80b089d..e7d1f76a0 100644 --- a/include/generators/boost_random_number_generator.hpp +++ b/include/generators/boost_random_number_generator.hpp @@ -22,6 +22,8 @@ struct BoostRandomNumberGenerator; template struct BoostRandomNumberGenerator { + BoostRandomNumberGenerator() {} + BoostRandomNumberGenerator(int d) : _rng(std::chrono::system_clock::now().time_since_epoch().count()) , _urdist(0, 1) diff --git a/include/generators/sdp_generator.h b/include/generators/sdp_generator.h new file mode 100644 index 000000000..9348f24b0 --- /dev/null +++ b/include/generators/sdp_generator.h @@ -0,0 +1,148 @@ +// +// Created by panagiotis on 9/7/2019. +// + +#ifndef VOLESTI_SDP_GENERATOR_H +#define VOLESTI_SDP_GENERATOR_H + +#include /* srand, rand */ +#include /* time */ + +typedef boost::mt19937 RNGType; + + +template +void randomMatrixGOE(Eigen::Matrix& M) { + typedef Eigen::Matrix MT; + typedef Eigen::Matrix VT; + + unsigned m = M.rows(); + boost::normal_distribution<> rdist(0,1); + unsigned seed = std::chrono::system_clock::now().time_since_epoch().count();//4 if fixed for debug + RNGType rng(seed); + + for (unsigned int i=0; i +Spectrahedron, Eigen::Matrix > generateSDP(int n, int m) { + typedef Eigen::Matrix MT; + typedef Eigen::Matrix VT; + + MT ones = MT::Ones(m, m); + MT M = 2* Eigen::MatrixXd::Random(m,m) - ones; + + MT I = Eigen::MatrixXd::Identity(m, m); + std::vector matrices(n + 1); + matrices[0] = -(M * M.transpose()) - I; + + std::cout<<"A0 = "< lmi(matrices); + Spectrahedron spectrahedron(lmi); + return spectrahedron; + + //return optimization::sdp_problem(spectrahedron, obj); +} + + +template +Spectrahedron, Eigen::Matrix > generateSDP2(int n, int m) { + + typedef Eigen::Matrix MT; + typedef Eigen::Matrix VT; + + MT ones = MT::Ones(m, m); + MT M = 2* Eigen::MatrixXd::Random(m,m) - ones; + + MT I = Eigen::MatrixXd::Identity(m, m); + std::vector matrices(n + 1); + matrices[0] = -(M * M.transpose()) - I; + + //std::cout<<"A0 = "< lmi(matrices); + Spectrahedron spectrahedron(lmi); + return spectrahedron; + + //return optimization::sdp_problem(spectrahedron, obj); +} + + +#endif //VOLESTI_SDP_GENERATOR_H diff --git a/include/matrix_operations/DenseProductMatrix.h b/include/matrix_operations/DenseProductMatrix.h new file mode 100644 index 000000000..848e1a7ae --- /dev/null +++ b/include/matrix_operations/DenseProductMatrix.h @@ -0,0 +1,105 @@ +// VolEsti (volume computation and sampling library) + +// Copyright (c) 20012-2020 Vissarion Fisikopoulos +// Copyright (c) 2020 Apostolos Chalkis + +//Contributed and/or modified by Repouskos Panagiotis, as part of Google Summer of Code 2019 program. + +// Licensed under GNU LGPL.3, see LICENCE file + +#ifndef VOLESTI_DENSEPRODUCTMATRIX_H +#define VOLESTI_DENSEPRODUCTMATRIX_H + +#define PARTIAL_LU_DECOMPOSITION + +/// A wrapper class for dense Eigen matrices in Spectra and ARPACK++ +/// This class will be the wrapper to use the Spectra nonsymemmetric standard eigenvalue Cx = lx solver to +/// solve a generalized eigenvalue Ax = lBx. +/// In particular, this class represents the product @f[ C = B^-1 A @f] +/// +/// \tparam NT Numeric Type +template +class DenseProductMatrix { +public: + /// Eigen matrix type + typedef Eigen::Matrix MT; + /// Eigen vector type + typedef Eigen::Matrix VT; + + /// The number of rows + int _rows; + /// The number of cols + int _cols; + + /// Pointer to matrix A + MT const *A; + /// Pointer to matrix B + MT const *B; + + /// The decomposition we will use + /// If PARTIAL_LU_DECOMPOSITION is defined, use the Eigen partial LU decomposition, + /// otherwise full. The partial is faster but assumes that the matrix has full rank. +#if defined(PARTIAL_LU_DECOMPOSITION) + typedef Eigen::PartialPivLU Decomposition; +#else + typedef Eigen::FullPivLU Decomposition; +#endif + + /// The LU decomposition of B + Decomposition Blu; + + /// Constructs an object of this class and computes the LU decomposition of B. + /// + /// \param[in] A The matrix A + /// \param[in] B The matrix B + DenseProductMatrix(MT const *A, MT const *B) : A(A), B(B) { + Blu = Decomposition(*B); + _rows = A->rows(); + _cols = B->cols(); + } + + ///Required by Spectra + /// \return The number of rows + int rows() { + return _rows; + } + + ///Required by Spectra + /// \return The number of columns + int cols() { + return _cols; + } + + /// Required by Spectra. + /// Computes the product Cx = y, i.e. @f[ (B^-1 A)v = y@$]. But B = LU, so Ax = LUy. + /// Let Ax = v, then LUy = v. Then Lw = v and finally Uy = w to get y; + /// \param[in] x_in + /// \param[out] y_out + void perform_op(NT const * x_in, NT* y_out) { + + // Declaring the vectors like this, we don't copy the values of x_in to v + // and next of y to y_out + Eigen::Map const x(const_cast(x_in), _rows); + VT const v = *A * x; + + Eigen::Map y(y_out, _rows); + y = Blu.solve(v); + } + + /// Required by arpack. + /// Computes the product Cx = y, i.e. @f[ (B^-1 A)v = y@$]. But B = LU, so Ax = LUy. + /// Let Ax = v, then LUy = v. Then Lw = v and finally Uy = w to get y; + /// \param[in] x_in + /// \param[out] y_out + void MultMv(NT * x_in, NT* y_out) { + + // Declaring the vectors like this, we don't copy the values of x_in to v + // and next of y to y_out + Eigen::Map const x(const_cast(x_in), _rows); + VT const v = *A * x; + + Eigen::Map y(y_out, _rows); + y = Blu.solve(v); + } +}; +#endif //VOLESTI_DENSEPRODUCTMATRIX_H diff --git a/include/matrix_operations/EigenDenseMatrix.h b/include/matrix_operations/EigenDenseMatrix.h new file mode 100644 index 000000000..df6dd93b3 --- /dev/null +++ b/include/matrix_operations/EigenDenseMatrix.h @@ -0,0 +1,76 @@ +// VolEsti (volume computation and sampling library) + +// Copyright (c) 20012-2020 Vissarion Fisikopoulos +// Copyright (c) 2020 Apostolos Chalkis + +//Contributed and/or modified by Repouskos Panagiotis, as part of Google Summer of Code 2019 program. + +// Licensed under GNU LGPL.3, see LICENCE file + +#ifndef VOLESTI_EIGENDENSEMATRIX_H +#define VOLESTI_EIGENDENSEMATRIX_H + +/// A wrap class to use Eigen dense matrices when solving Eigenvalue problems with ARPACK++ +/// \tparam NT Numeric Type +template +class EigenDenseMatrix { +public: + + /// Eigen matrix type + typedef Eigen::Matrix MT; + /// Eigen vector type + typedef Eigen::Matrix VT; + + /// The matrix + MT const * M; + + /// number of columns + int n; + /// number of rows + int m; + + /// \return Number of rows + int nrows() { return m;} + + /// \return Number of columns + int ncols() { return n;} + + /// \return Number of rows + int rows() { return m;} + + /// \return Number of columns + int cols() { return n;} + + /// Required by ARPACK++ : Multiplies the matrix with vector v + /// \param[in] v The input vector, for example double* + /// \param[out] w The result of M*v + void MultMv(NT* v, NT* w) { + // Declaring the vectors like this, we don't copy the values of v and after to w + Eigen::Map _v(v, m); + Eigen::Map _w(w, m); + + _w = *M * _v; + } + + /// Required by ARPACK++ : Multiplies the matrix with vector v + /// \param[in] v The input vector, for example double* + /// \param[out] w The result of M*v + void perform_op(NT* v, NT* w) { + // Declaring the vectors like this, we don't copy the values of v and after to w + Eigen::Map _v(v, m); + Eigen::Map _w(w, m); + + _w = *M * _v; + } + + + /// Constructs an object + /// \param[in] M An Eigen Matrix + EigenDenseMatrix(MT const * M) { + this->M = M; + n = M->cols(); + m = M->rows(); + } + +}; +#endif //VOLESTI_EIGENDENSEMATRIX_H diff --git a/include/matrix_operations/EigenvaluesProblems.h b/include/matrix_operations/EigenvaluesProblems.h new file mode 100644 index 000000000..7f3ce7e75 --- /dev/null +++ b/include/matrix_operations/EigenvaluesProblems.h @@ -0,0 +1,370 @@ +// VolEsti (volume computation and sampling library) + +// Copyright (c) 20012-2020 Vissarion Fisikopoulos +// Copyright (c) 2020 Apostolos Chalkis + +//Contributed and/or modified by Repouskos Panagiotis, as part of Google Summer of Code 2019 program. + +// Licensed under GNU LGPL.3, see LICENCE file + +#ifndef VOLESTI_EIGENVALUESPROBLEMS_H +#define VOLESTI_EIGENVALUESPROBLEMS_H + +/// Uncomment the solver the function minPosGeneralizedEigenvalue uses +/// Eigen solver for generalized eigenvalue problem +//#define EIGEN_EIGENVALUES_SOLVER +/// Spectra standard eigenvalue problem +//#define SPECTRA_EIGENVALUES_SOLVER +/// ARPACK++ standard eigenvalues solver +#define ARPACK_EIGENVALUES_SOLVER + +#include <../../external/arpack++/include/arssym.h> +#include <../../external/Spectra/include/Spectra/SymEigsSolver.h> +#include "DenseProductMatrix.h" +#include "EigenDenseMatrix.h" + +#include "../../external/Spectra/include/Spectra/SymGEigsSolver.h" +#include "../../external/Spectra/include/Spectra/GenEigsSolver.h" +#include "../../external/arpack++/include/arsnsym.h" + +/// Solve eigenvalues problems +/// \tparam NT Numeric Type +/// \tparam MT Matrix Type +/// \tparam VT Vector Type +template +class EigenvaluesProblems { + +}; + + +/// A specialization of the template class EigenvaluesProblems for dense Eigen matrices and vectors. +/// \tparam NT +template +class EigenvaluesProblems, Eigen::Matrix > { +public: + /// The type for Eigen Matrix + typedef Eigen::Matrix MT; + /// The type for Eigen vector + typedef Eigen::Matrix VT; + /// The type of a complex Eigen Vector for handling eigenvectors +#if defined(EIGEN_EIGENVALUES_SOLVER) || defined (SPECTRA_EIGENVALUES_SOLVER) + typedef typename Eigen::GeneralizedEigenSolver::ComplexVectorType CVT; +#elif defined(ARPACK_EIGENVALUES_SOLVER) + typedef Eigen::Matrix CVT; +#endif + + /// The type of a pair of NT + typedef std::pair NTpair; + + + /// Find the smallest eigenvalue of M + /// \param M a symmetric matrix + /// \return smallest eigenvalue + NT findSymEigenvalue(MT const & M) { + EigenDenseMatrix _M(&M); + +//#define NOT_WORKING +#ifdef NOT_WORKING + // Creating an eigenvalue problem and defining what we need: + // the smallest eigenvalue of M. + ARNonSymStdEig > + dprob(M.cols(), 1, &_M, &EigenDenseMatrix::MultMv, std::string ("LR"), 8, 0.0, 100*15); + + // compute + if (dprob.FindEigenvectors() == 0) { + std::cout << "Failed in findSymEigenvalue\n"; + // if failed with default (and fast) parameters, try with stable (and slow) + dprob.ChangeNcv(M.cols()/10); + if (dprob.FindEigenvectors() == 0) { + std::cout << "\tFailed Again\n"; + return NT(0); + } + } + + if (!dprob.EigenvaluesFound()) { + // if failed to find eigenvalues + return NT(0); + } + + // retrieve eigenvalue of the original system + return dprob.EigenvalueReal(0); +#elif defined(SPECTRA) + // This parameter is for Spectra. It must be larger than #(requested eigenvalues) + 2 + // and smaller than the size of matrix; + int ncv = M.cols()/10 + 5; + if (ncv > M.cols()) ncv = M.cols(); + + Spectra::SymEigsSolver > eigs(&_M, 1, ncv); + // compute + eigs.init(); + eigs.compute(50000); + if(eigs.info() == Spectra::SUCCESSFUL) { + return eigs.eigenvalues()(0); + } + else { + std::cout << "Spectra failed\n"; + return NT(0); + } +#else + Eigen::SelfAdjointEigenSolver solver; + solver.compute(M, Eigen::EigenvaluesOnly); +// typename Eigen::GeneralizedEigenSolver::ComplexVectorType eivals = solver.eigenvalues(); +// NT max = eivals(0).real(); +// +// for (int i = 1; i < eivals.rows(); i++) +// if (eivals(i).real() > max) +// max = eivals(i).real(); + + return solver.eigenvalues().maxCoeff(); +#endif + } + + /// Find the minimum positive and maximum negative eigenvalues of the generalized eigenvalue + /// problem A + lB, where A, B symmetric and A negative definite. + /// \param[in] A Input matrix + /// \param[in] B Input matrix + /// \return The pair (minimum positive, maximum negative) of eigenvalues + NTpair symGeneralizedProblem(MT const & A, MT const & B) { + + int matrixDim = A.rows(); + + // Spectra solves Xv=lYv, where Y positive definite + // Set X = B, Y=-A. Then, the eigenvalues we want are the minimum negative + // and maximum positive eigenvalues of Xv=lYv. + + // Construct matrix operation object using the wrapper classes provided by Spectra + Spectra::DenseSymMatProd op(B); + Spectra::DenseCholesky Bop(-A); + + // Construct generalized eigen solver object + // requesting the minmum negative and largest positive eigenvalues + Spectra::SymGEigsSolver, Spectra::DenseCholesky, Spectra::GEIGS_CHOLESKY> + geigs(&op, &Bop, 2, 5 < matrixDim ? 5 : matrixDim); + + // Initialize and compute + geigs.init(); + int nconv = geigs.compute(); + + // Retrieve results + if (geigs.info() != Spectra::SUCCESSFUL) + return {NT(0), NT(0)}; + + Eigen::VectorXd evalues; + double lambdaMinPositive, lambdaMaxNegative; + + evalues = geigs.eigenvalues(); + + // get the eigenvalues of the original problem + lambdaMinPositive = 1 / evalues(0); + lambdaMaxNegative = 1 / evalues(1); + + return {lambdaMinPositive, lambdaMaxNegative}; + } + + /// Finds the minimum positive real eigenvalue of the generalized eigenvalue problem A + lB and + /// the corresponding eigenvector. + /// If the macro EIGEN_EIGENVALUES_SOLVER is defined, the Generalized Solver of Eigen is used. + /// Otherwise, we transform the generalized to a standard eigenvalue problem and use Spectra. + /// Warning: With Spectra we might get a value smaller than the minimum positive real eigenvalue (the real part + /// of a complex eigenvalue). + /// No restriction on the matrices! + /// \param[in] A Input matrix + /// \param[in] B Input matrix + /// \param[out] eigenvector The eigenvector corresponding to the minimum positive eigenvalue + /// \return The minimum positive eigenvalue + NT minPosGeneralizedEigenvalue(MT const & A, MT const & B, CVT& eigenvector) { + NT lambdaMinPositive = std::numeric_limits::max(); + +#if defined(EIGEN_EIGENVALUES_SOLVER) + // use the Generalized eigenvalue solver of Eigen + + // compute generalized eigenvalues with Eigen solver + Eigen::GeneralizedEigenSolver ges(A, -B); + + // retrieve minimum positive eigenvalue + typename Eigen::GeneralizedEigenSolver::ComplexVectorType alphas = ges.alphas(); + VT betas = ges.betas(); + int index = 0; + + for (int i = 0; i < alphas.rows(); i++) { + + if (betas(i) == 0 || alphas(i).imag() != 0) + continue; + + double lambda = alphas(i).real() / betas(i); + if (lambda > 0 && lambda < lambdaMinPositive) { + lambdaMinPositive = lambda; + index = i; + } + } + + // retrieve corresponding eigenvector + eigenvector = ges.eigenvectors().col(index); +#elif defined(SPECTRA_EIGENVALUES_SOLVER) + // Transform the problem to a standard eigenvalue problem and use the general eigenvalue solver of Spectra + + // This makes the transformation to standard eigenvalue problem. See class for more info. + // We have the generalized problem A + lB, or Av = -lBv + // This class computes the matrix product vector Mv, where M = -B * A^[-1] + MT _B = -1 * B; // TODO avoid this allocation + DenseProductMatrix M(&_B, &A); + + // This parameter is for Spectra. It must be larger than #(requested eigenvalues) + 2 + // and smaller than the size of matrix; + int ncv = 3; + + // Prepare to solve Mx = (1/l)x + // we want the smallest positive eigenvalue in the original problem, + // so in this the largest positive eigenvalue; + Spectra::GenEigsSolver > eigs(&M, 1, ncv); + + // compute + eigs.init(); + eigs.compute(); + + //retrieve result and invert to get required eigenvalue of the original problem + if (eigs.info() != Spectra::SUCCESSFUL) { + eigenvector.setZero(A.rows()); + return NT(0); + } + + lambdaMinPositive = 1/((eigs.eigenvalues())(0).real()); + + // retrieve corresponding eigenvector + int matrixDim = A.rows(); + eigenvector.resize(matrixDim); + for (int i = 0; i < matrixDim; i++) + eigenvector(i) = (eigs.eigenvectors()).col(0)(i); + +#elif defined(ARPACK_EIGENVALUES_SOLVER) + // Transform the problem to a standard eigenvalue problem and use the general eigenvalue solver of ARPACK++ + + // This makes the transformation to standard eigenvalue problem. See class for more info. + // We have the generalized problem A + lB, or Av = -lBv + // This class computes the matrix product vector Mv, where M = -B * A^[-1] + MT _B = -1 * B; // TODO avoid this allocation + DenseProductMatrix M(&_B, &A); + + // Creating an eigenvalue problem and defining what we need: + // the eigenvector of A with largest real. + ARNonSymStdEig > + + dprob(A.cols(), 1, &M, &DenseProductMatrix::MultMv, std::string ("LR"), 8 + +#include "optimization/sliding_window.hpp" +#include "random_walks/boltzmann_hmc_walk.hpp" + + +/// A magic number! +/// when estimating the diameter of the spectrahedron, +/// sample 20 + sqrt(dimension) points to estimate it +#define CONSTANT_1 20 + +/// Holds parameters of the algorithm +/// \tparam Point Class point +template +struct SimulatedAnnealingSettings { + /// The numeric type + typedef typename Point::FT NT; + + /// Desired accuracy (relative error) + NT error; + /// The walk length of the HMC random walk + int walkLength; + /// A bound to the number of steps; if negative it is unbounded + int maxNumSteps; + + /// Starting from an initial temperature, at each step it will decrease by a factor of + /// \[ 1 - 1 / (dimension^k) \]. Default is 0.5 + NT k; + + SimulatedAnnealingSettings(NT const error, int const walkLength = 1, int const maxNumSteps = -1, NT const k = 0.5) : error(error), + walkLength(walkLength), maxNumSteps(maxNumSteps), k(k) {} +}; + + +/// Simulated Annealing algorithm for a semidefinite program +/// Minimize \[ c^T x \], s.t. LMI(x) <= 0 +/// \param[in] spectrahedron A spectrahedron described by a linear matrix inequality +/// \param[in] objectiveFunction The function we minimize +/// \param[in] settings Parameters of the algorithm +/// \param[in] interiorPoint An initial feasible solution to start the algorithm +/// \param[out] solution The vector minimizing the objective function +/// \param[in] verbose True to print messages. Default is false +/// \return The best approximation to the optimal solution +template +double solve_sdp(_Spectrahedron & spectrahedron, Point const & objectiveFunction, _Settings const & settings, + Point const & interiorPoint, Point& solution, bool verbose = false) { + + // fetch the data types we will use + typedef typename _Spectrahedron::NUMERIC_TYPE NT; + typedef typename _Spectrahedron::MATRIX_TYPE MT; + typedef typename _Spectrahedron::VECTOR_TYPE VT; + typedef BoostRandomNumberGenerator RNGType; + typedef BoltzmannHMCWalk::Walk<_Spectrahedron, RNGType > HMC; + + // the algorithm requires the objective function to be normalized + // we will need to remember the norm + VT _objectiveFunctionNormed = objectiveFunction.getCoefficients(); + NT objectiveFunctionNorm = _objectiveFunctionNormed.norm(); + _objectiveFunctionNormed.normalize(); + Point objectiveFunctionNormed = Point(_objectiveFunctionNormed); + + // Estimate the diameter of the spectrahedron + // needed for the random walk and for the simulated annealing algorithm + NT diameter = spectrahedron.estimateDiameter(CONSTANT_1 + std::sqrt(spectrahedron.dimension()), interiorPoint); + + /******** initialization *********/ + solution = interiorPoint; + // the minimum till last iteration + NT currentMin = objectiveFunction.dot(solution); + int stepsCount = 0; + // initial temperature must be the diameter of the body + NT temperature = diameter; + // after each iteration, temperature = temperature * tempDecreaseFactor + NT tempDecreaseFactor = 1.0 - static_cast(1.0 / std::pow(spectrahedron.dimension(), settings.k)); + + // initialize random walk; + RNGType rng(spectrahedron.dimension()); + typename HMC::Settings hmc_settings = typename HMC::Settings(settings.walkLength, rng, objectiveFunction, temperature, diameter); + HMC hmcRandomWalk = HMC(hmc_settings); + // this data structure help us move computations between function calls + typename HMC::PrecomputedValues hmcPrecomputedValues; + NT previous_min = objectiveFunction.dot(solution); + + /******** solve *********/ + // if settings.maxNumSteps is negative there is no + // bound to the number of steps - stop + // when desired relative error is achieved + while (stepsCount < settings.maxNumSteps || settings.maxNumSteps < 0) { + + // sample one point with current temperature + std::list randPoints; + + // get a sample under the Boltzmann distribution + // using the HMC random walk + while (1) { + hmcRandomWalk.apply(spectrahedron, solution, settings.walkLength, randPoints, hmcPrecomputedValues); + + // if the sampled point is not inside the spectrahedron (error in boundary oracle), + // get a new one + if (spectrahedron.isExterior(hmcPrecomputedValues.C)) { + if (verbose) std::cout << "Sampled point outside the spectrahedron.\n"; + randPoints.clear(); + hmcPrecomputedValues.resetFlags(); + } + else { + // update values; + solution = randPoints.back(); + randPoints.clear(); + break; + } + } + + // update current value + currentMin = objectiveFunction.dot(solution); + ++stepsCount; + + // compute relative error + NT relError = relativeError(previous_min, currentMin); + previous_min = currentMin; + + if (verbose) + std::cout << "Step: " << stepsCount << ", Temperature: " << temperature << ", Min: " << currentMin + << ", Relative error: " << relError << "\n"; + + // check if we reached desired accuracy + if (relError < settings.error) + break; + + // decrease the temperature + temperature *= tempDecreaseFactor; + hmcRandomWalk.setTemperature(temperature); + + } /* while (stepsCount < settings.maxNumSteps || settings.maxNumSteps < 0) { */ + + // return the minimum w.r.t. the original objective function + return currentMin*objectiveFunctionNorm; +} + + + +#endif //VOLESTI_SIMULATED_ANNEALING_HPP diff --git a/include/optimization/sliding_window.hpp b/include/optimization/sliding_window.hpp new file mode 100644 index 000000000..9fdcf3602 --- /dev/null +++ b/include/optimization/sliding_window.hpp @@ -0,0 +1,66 @@ +// VolEsti (volume computation and sampling library) + +// Copyright (c) 20012-2020 Vissarion Fisikopoulos +// Copyright (c) 2020 Apostolos Chalkis + +//Contributed and/or modified by Repouskos Panagiotis, as part of Google Summer of Code 2019 program. + +// Licensed under GNU LGPL.3, see LICENCE file + +#ifndef VOLESTI_SLIDING_WINDOW_HPP +#define VOLESTI_SLIDING_WINDOW_HPP + + +/// Computes the relative error +/// \tparam NT Numeric type +/// \param[in] approx The approximated value +/// \param[in] exact The exact value +/// \return The relative error +template +NT relativeError(NT approx, NT exact) { + return std::fabs((exact - approx) / exact); +} + + +/// A sliding window, which allows to get the relative error of approximations +/// \tparam NT Numeric type +template +class SlidingWindow { +public: + + /// The stored approximations + std::list approximations; + /// The size of the window + int windowSize; + /// The number of entries in list approximations + int numEntries; + + /// Constructor + /// \param[in] windowSize The size of the window + SlidingWindow(int windowSize) : windowSize(windowSize) { + numEntries = 0; + } + + /// Adds an approximation in the window + /// \param[in] approximation The new approximation + void push(NT approximation) { + // if window is full, remove the oldest value + if (numEntries >= windowSize) { + approximations.pop_back(); + } + else + numEntries++; + + approximation.push_front(approximation); + } + + /// \return The relative error between the youngest and oldest approximations + double getRelativeError() { + if (numEntries < windowSize) + return 1; + + return relativeError(approximations.back(), approximations.front()); + } +}; + +#endif //VOLESTI_SLIDING_WINDOW_HPP diff --git a/include/random_walks/boltzmann_hmc_walk.hpp b/include/random_walks/boltzmann_hmc_walk.hpp new file mode 100644 index 000000000..454a62eaf --- /dev/null +++ b/include/random_walks/boltzmann_hmc_walk.hpp @@ -0,0 +1,263 @@ +// VolEsti (volume computation and sampling library) + +// Copyright (c) 20012-2020 Vissarion Fisikopoulos +// Copyright (c) 2020 Apostolos Chalkis + +//Contributed and/or modified by Repouskos Panagiotis, as part of Google Summer of Code 2019 program. + +// Licensed under GNU LGPL.3, see LICENCE file + +#ifndef VOLESTI_BOLTZMANN_HMC_WALK_HPP +#define VOLESTI_BOLTZMANN_HMC_WALK_HPP + +#include "spectrahedron.h" +#include "generators/boost_random_number_generator.hpp" +#include "../sampling/sphere.hpp" + +/// The Hamiltonian Monte Carlo random walk, to sample from the Boltzmann distribution, i.e. e^(-c*x/T). +struct BoltzmannHMCWalk { +public: + + struct parameters {}; + parameters param; + + /// The implementation of the walk + /// Currently implemented only for spectrahedra + /// with template specialization + ///@tparam ConvexBody a convex body + ///@tparam RandomNumberGenerator + template + struct Walk { + }; + + + + /// The implementation of the walk for spectrahedra + template + struct Walk, Eigen::Matrix >, RandomNumberGenerator> { + + /// The type of the spectrahedron + typedef Spectrahedron, Eigen::Matrix> SPECTRAHEDRON; + /// Type for internal structure of class Spectrahedron + typedef typename SPECTRAHEDRON::PrecomputedValues PrecomputedValues; + + /// The matrix/vector types we use + typedef typename SPECTRAHEDRON::MATRIX_TYPE MT; + typedef typename SPECTRAHEDRON::VECTOR_TYPE VT; + + /// A struct containing the parameters for the random walk + struct Settings { + /// The number of points to "burn", before keeping the following as a sample + int walk_length; + /// For generating random numbers + RandomNumberGenerator randomNumberGenerator; + /// The c in the distribution + VT c; + /// The T in the distribution + NT temperature; + /// The diameter of the spectrahedron + NT diameter; + /// Set the number of allowed reflections at each step: #reflections < reflectionsBound * dimension + unsigned int reflectionsBound; + /// When determining we can move d long till we reach the boundary, we walk d*dl, for numerical stability + NT dl; + + /// Constructs an object of Settings + /// \param[in] walkLength The number of points to "burn", before keeping the following as a sample + /// \param[in] rng For generating random numbers + /// \param[in] c The c in the distribution + /// \param[in] temperature The T in the distribution + /// \param[in] diameter The diameter of the spectrahedron + /// \param[in] reflectionsBound at each iteration allow reflectionsBound*dimension reflections at most + /// \param[in] dl approach the boundary with a factor of dl, for numerical stability + /// \return An instance of this struct + template + Settings(const int walkLength, const RandomNumberGenerator &randomNumberGenerator, const Point &c, const NT temperature, const NT diameter, + unsigned int reflectionsBound = 10, NT dl = 0.995) : walk_length(walkLength), randomNumberGenerator(randomNumberGenerator), + c(c.getCoefficients()), + temperature(temperature), + diameter(diameter), + reflectionsBound(reflectionsBound), dl(dl) {} + + Settings() {} + }; + + /// The parameters of the random walk + Settings settings; + + Walk() {} + + /// Constructor + /// \param[in] settings The settings of the random walk + Walk(Settings &settings) : settings(settings) {} + + /// Change the settings + /// \param[in] settings The settings of the random walk + void setSettings(Settings &settings) { + this->settings = settings; + } + + + /// Samples random points from the spectrahedron from the Boltzmann distribution + /// \param[in] spectrahedron A spectrahedron + /// \param[in] interiorPoint A point in the interior of the spectrahedron + /// \param[in] pointsNum The number of points to sample + /// \param[out] points The list of the sampled points + /// \tparam Point class Point with NT and VT as declared above in this class + template + void apply(SPECTRAHEDRON &spectrahedron, Point const & interiorPoint, const unsigned int pointsNum, + std::list &points) { + // store intermediate results between successive calls of methods + // of the class spectrahedron, to avoid repeating computations + PrecomputedValues precomputedValues; + VT p = interiorPoint.getCoefficients(); + + // sample #pointsNum points + for (unsigned int i = 1; i <= pointsNum; ++i) { + // burn #walk_length points to get one sample + for (unsigned int j = 0; j < settings.walk_length; ++j) { + getNextPoint(spectrahedron, p, precomputedValues); + } + + // add the sample in the return list + points.push_back(Point(p)); + } + + // the data in preComputedValues may be out of date in the next call + precomputedValues.resetFlags(); + } + + /// Samples random points from the spectrahedron from the Boltzmann distribution + /// \param[in] spectrahedron A spectrahedron + /// \param[in] interiorPoint A point in the interior of the spectrahedron + /// \param[in] pointsNum The number of points to sample + /// \param[out] points The list of the sampled points + /// \param[in, out] precomputedValues transfer data between sucessive calls + /// \tparam Point class Point with NT and VT as declared above in this class + template + void apply(SPECTRAHEDRON &spectrahedron, Point const & interiorPoint, const unsigned int pointsNum, + std::list &points, PrecomputedValues &precomputedValues) { + // store intermediate results between successive calls of methods + // of the class spectrahedron, to avoid repeating computations + + VT p = interiorPoint.getCoefficients(); + + // sample #pointsNum points + for (unsigned int i = 1; i <= pointsNum; ++i) { + // burn #walk_length points to get one sample + for (unsigned int j = 0; j < settings.walk_length; ++j) { + getNextPoint(spectrahedron, p, precomputedValues); + } + + // add the sample in the return list + points.push_back(Point(p)); + } + + // the data in preComputedValues may be out of date in the next call + precomputedValues.resetFlags(); + precomputedValues.computed_C = true; + } + + + /// A single step of the HMC random walk: choose a direction and walk on the trajectory for a random distance. + /// If it hits the boundary, the trajectory is reflected. If #reflections < reflectionsBound * dimension, it returns the same point + /// \param[in] spectrahedron A spectrahedron + /// \param[in, out] p An interior point, and the next point in the random walk + /// \param[in, out] precomputedValues Data for the methods of the class Spectrahedron + /// \tparam Point + template + void getNextPoint(SPECTRAHEDRON &spectrahedron, VT &p, PrecomputedValues &precomputedValues) { + + // initialize + RandomNumberGenerator &rng = settings.randomNumberGenerator; + boost::random::uniform_real_distribution<> urdist(0, 1); + const NT dl = settings.dl; + unsigned int n = spectrahedron.dimension(); + int reflectionsNum = 0; + int reflectionsNumBound = settings.reflectionsBound * n; + VT previousPoint; + VT p0 = p; + + // choose a distance to walk + NT T = rng.sample_urdist() * settings.diameter; + + // The trajectory will be of the form a*t^2 + vt + p + // where a = -c / 2*temperature + // and at each reflection, v and p will change + + // crate vector a + VT a = -settings.c / (2 * settings.temperature); + + // The vector v will be a random a direction + VT v = GetDirection::apply(n, rng).getCoefficients(); + + // Begin a step of the random walk + // Also, count the reflections and respect the bound + while (reflectionsNum++ < reflectionsNumBound) { + + // we are at point p and the trajectory a*t^2 + vt + p + // find how long we can walk till we hit the boundary + NT lambda = spectrahedron.positiveIntersection(a, v, p, precomputedValues); + + // We just solved a quadratic polynomial eigenvalue system At^2 + Bt + C, + // where A = lmi(a) - A0, B = lmi(v) - A0 and C = lmi(p) + // and also did a linearization creating two matrices X, Y. + // For the subsequent calls, we don't have to compute these matrices from scratch, + // but can efficiently update them. + // A remains the same + // C := A*lambda^2 + B*lambda + C + // X, Y will be updated in class Spectrahedron + // Set the flags + precomputedValues.computed_A = true; + precomputedValues.computed_C = true; + precomputedValues.computed_XY = true; + + // if we can walk the remaining distance without reaching he boundary + if (T <= lambda) { + // set the new point p:= (T^2)*a + T*V + p + p += (T * T) * a + T * v; + + // update matrix C + precomputedValues.C += (T * T) * precomputedValues.A + T * precomputedValues.B; + return; + } + + // we hit the boundary and still have to walk + // don't go all the way to the boundary, for numerical stability + lambda *= dl; + + // save current and set new point + previousPoint = p; + p += (lambda * lambda) * a + lambda * v; + + // update remaining distance we must walk + T -= lambda; + + // update matrix C + precomputedValues.C += (lambda * lambda) * precomputedValues.A + lambda * precomputedValues.B; + + // Set v to have the direction of the trajectory at t = lambda + // i.e. the gradient of at^2 + vt + p, for t = lambda + v += (lambda * 2) * a; + + // compute reflected direction + VT reflectedTrajectory; + spectrahedron.computeReflection(p, v, reflectedTrajectory, precomputedValues); + v = reflectedTrajectory; + } + + // if the #reflections exceeded the limit, don't move + if (reflectionsNum == reflectionsNumBound) + p = p0; + } + + /// Sets the temperature in the distribution + /// \param[in] temperature New value of temperature + void setTemperature(NT temperature) { + settings.temperature = temperature; + } + }; + +}; + +#endif //VOLESTI_BOLTZMANN_HMC_WALK_HPP diff --git a/test/SDP/CMakeLists.txt b/test/SDP/CMakeLists.txt new file mode 100644 index 000000000..87f4f0d9e --- /dev/null +++ b/test/SDP/CMakeLists.txt @@ -0,0 +1,135 @@ +# VolEsti (volume computation and sampling library) +# Copyright (c) 20012-2020 Vissarion Fisikopoulos +# Copyright (c) 2018-2020 Apostolos Chalkis +# Contributed and/or modified by Repouskos Panagiotis, as part of Google Summer of Code 2019 program. +# Licensed under GNU LGPL.3, see LICENCE file + +project( VolEsti ) + +enable_testing() + +CMAKE_MINIMUM_REQUIRED(VERSION 2.4.5) + +set(CMAKE_ALLOW_LOOSE_LOOP_CONSTRUCTS true) + +if(COMMAND cmake_policy) + cmake_policy(SET CMP0003 NEW) +endif(COMMAND cmake_policy) + +#if(NOT DEFINED BOOST) +# message(FATAL_ERROR "This program requires the boost library, and will not be compiled.") +#else() +# message(STATUS "BOOST is DEFINED") +#endif() + + +set(CMAKE_EXPORT_COMPILE_COMMANDS "ON") + +include_directories (BEFORE ../../external/Eigen) +include_directories (BEFORE ../../external) +include_directories (BEFORE ../../external/minimum_ellipsoid) +#include_directories (BEFORE ../include/cartesian_geom) +#include_directories (BEFORE ../include/convex_bodies) +include_directories (BEFORE ../../external/LPsolve_src/run_headers) +include_directories (BEFORE ../../external/boost) +#include_directories (BEFORE BOOST) +include_directories (BEFORE ../../include/generators) +include_directories (BEFORE ../../include/volume) +include_directories (BEFORE ../../include) +include_directories (BEFORE ../../include/convex_bodies) +include_directories (BEFORE ../../include/convex_bodies/spectrahedra) +include_directories (BEFORE ../../include//optimization) +include_directories (BEFORE ../../include/matrix_operations) +include_directories (BEFORE ../../include/annealing) +include_directories (BEFORE ../../include/samplers) +include_directories (BEFORE ../../include/lp_oracles) +include_directories (BEFORE ../../include/misc) + +#for Eigen +if (${CMAKE_VERSION} VERSION_LESS "3.12.0") + add_compile_options(-D "EIGEN_NO_DEBUG") +else () + add_compile_definitions("EIGEN_NO_DEBUG") +endif () + +add_definitions(${CMAKE_CXX_FLAGS} "-std=c++11") # enable C++11 standard +add_definitions(${CMAKE_CXX_FLAGS} "-g") # enable debuger +#add_definitions(${CMAKE_CXX_FLAGS} "-Wint-in-bool-context") +#add_definitions(${CMAKE_CXX_FLAGS} "-Wall") + +add_definitions(${CMAKE_CXX_FLAGS} "-O3") # optimization of the compiler +#add_definitions(${CXX_COVERAGE_COMPILE_FLAGS} "-lgsl") +add_definitions(${CXX_COVERAGE_COMPILE_FLAGS} "-lm") +add_definitions(${CXX_COVERAGE_COMPILE_FLAGS} "-ldl") +add_definitions(${CXX_COVERAGE_COMPILE_FLAGS} "-DBOOST_NO_AUTO_PTR") +#add_definitions(${CXX_COVERAGE_COMPILE_FLAGS} "-lgslcblas") +#add_definitions( "-O3 -lgsl -lm -ldl -lgslcblas" ) + + +# Find LAPACK and BLAS +# OPENBLAS or ( ( SystemOpenblas or BLAS) and LAPACK) +## prefer local openblas +find_library(OPENBLAS_LIB openblas PATHS external NO_DEFAULT_PATH) +IF (OPENBLAS_LIB) + set(LAPACK_LIBRARIES ${OPENBLAS_LIB}) #local openblas has lapack build in + + find_package( Threads REQUIRED ) + set(LAPACK_LIBRARIES ${LAPACK_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT}) + message( STATUS "LAPACK_LIBRARIES: ${LAPACK_LIBRARIES}" ) + + + # ARPACK + find_library(ARPACK_LIB arpack PATHS external NO_DEFAULT_PATH) + IF (ARPACK_LIB) + message( STATUS "ARPACK_LIB found: ${ARPACK_LIB}" ) + + # Query gfortran to get the libgfortran path + FIND_LIBRARY(GFORTRAN_LIB NAMES libgfortran.so PATHS /usr/lib/gcc/x86_64-linux-gnu/8/) + + IF (CMAKE_Fortran_COMPILER) + EXECUTE_PROCESS(COMMAND ${CMAKE_Fortran_COMPILER} -print-file-name=libgfortran.a + OUTPUT_VARIABLE _libgfortran_path + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + IF (NOT EXISTS ${_libgfortran_path}) + EXECUTE_PROCESS(COMMAND ${CMAKE_Fortran_COMPILER} -print-file-name=libgfortran.so + OUTPUT_VARIABLE _libgfortran_path + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + ENDIF () + ENDIF() + + IF(EXISTS ${_libgfortran_path}) + get_filename_component(GFORTRAN_PATH ${_libgfortran_path} PATH) + find_library(GFORTRAN_LIB gfortran PATHS ${GFORTRAN_PATH}) + ELSE() + # if libgfortran wasn't found at this point, the installation is probably broken + # Let's try to find the library nonetheless. + FIND_LIBRARY(GFORTRAN_LIB gfortran) + ENDIF() + + IF (GFORTRAN_LIB) + message( STATUS "GFORTRAN_LIB found: ${GFORTRAN_LIB}" ) + + add_library(test_main OBJECT test_main.cpp) + + add_executable(test_solve_sdp test_solve_sdp.cpp $) + add_test(NAME test_solve_sdp COMMAND test_solve_sdp -tc=test_solve_sdp) + TARGET_LINK_LIBRARIES(test_solve_sdp ${ARPACK_LIB} ${LAPACK_LIBRARIES} ${GFORTRAN_LIB}) + + add_executable(test_spec_oracles test_spec_oracles.cpp $) + add_test(NAME test_spec_oracles COMMAND test_spec_oracles -tc=test_spec_oracles) + TARGET_LINK_LIBRARIES(test_spec_oracles ${ARPACK_LIB} ${LAPACK_LIBRARIES} ${GFORTRAN_LIB}) + + ELSE() + MESSAGE(STATUS "gfortran is required but it could not be found") + ENDIF () + + + ELSE() + message(FATAL_ERROR "This program requires the arpack library, and will not be compiled.") + ENDIF() + +ELSE() + message(FATAL_ERROR "This program requires the openblas library, and will not be compiled.") +ENDIF() diff --git a/test/SDP/README.md b/test/SDP/README.md new file mode 100644 index 000000000..acf3b90c3 --- /dev/null +++ b/test/SDP/README.md @@ -0,0 +1,2 @@ +For the dependencies for the compilation, please perform the same +procedure as in examples/spectrahedra/README.md . \ No newline at end of file diff --git a/test/SDP/doctest.h b/test/SDP/doctest.h new file mode 100644 index 000000000..e160b7f78 --- /dev/null +++ b/test/SDP/doctest.h @@ -0,0 +1,5464 @@ +// ====================================================================== +// == DO NOT MODIFY THIS FILE BY HAND - IT IS AUTO GENERATED BY CMAKE! == +// ====================================================================== +// +// doctest.h - the lightest feature-rich C++ single-header testing framework for unit tests and TDD +// +// Copyright (c) 2016-2018 Viktor Kirilov +// +// Distributed under the MIT Software License +// See accompanying file LICENSE.txt or copy at +// https://opensource.org/licenses/MIT +// +// The documentation can be found at the library's page: +// https://github.com/onqtam/doctest/blob/master/doc/markdown/readme.md +// +// ================================================================================================= +// ================================================================================================= +// ================================================================================================= +// +// The library is heavily influenced by Catch - https://github.com/philsquared/Catch +// which uses the Boost Software License - Version 1.0 +// see here - https://github.com/philsquared/Catch/blob/master/LICENSE.txt +// +// The concept of subcases (sections in Catch) and expression decomposition are from there. +// Some parts of the code are taken directly: +// - stringification - the detection of "ostream& operator<<(ostream&, const T&)" and StringMaker<> +// - the Approx() helper class for floating point comparison +// - colors in the console +// - breaking into a debugger +// - signal / SEH handling +// - timer +// +// The expression decomposing templates are taken from lest - https://github.com/martinmoene/lest +// which uses the Boost Software License - Version 1.0 +// see here - https://github.com/martinmoene/lest/blob/master/LICENSE.txt +// +// The type list and the foreach algorithm on it for C++98 are taken from Loki +// - http://loki-lib.sourceforge.net/ +// - https://en.wikipedia.org/wiki/Loki_%28C%2B%2B%29 +// - https://github.com/snaewe/loki-lib +// which uses the MIT Software License +// +// ================================================================================================= +// ================================================================================================= +// ================================================================================================= + +#ifndef DOCTEST_LIBRARY_INCLUDED +#define DOCTEST_LIBRARY_INCLUDED + +// ================================================================================================= +// == VERSION ====================================================================================== +// ================================================================================================= + +#define DOCTEST_VERSION_MAJOR 1 +#define DOCTEST_VERSION_MINOR 2 +#define DOCTEST_VERSION_PATCH 9 +#define DOCTEST_VERSION_STR "1.2.9" + +#define DOCTEST_VERSION \ + (DOCTEST_VERSION_MAJOR * 10000 + DOCTEST_VERSION_MINOR * 100 + DOCTEST_VERSION_PATCH) + +// ================================================================================================= +// == COMPILER VERSION ============================================================================= +// ================================================================================================= + +// ideas for the version stuff are taken from here: https://github.com/cxxstuff/cxx_detect + +#define DOCTEST_COMPILER(MAJOR, MINOR, PATCH) ((MAJOR)*10000000 + (MINOR)*100000 + (PATCH)) + +#if defined(_MSC_VER) && defined(_MSC_FULL_VER) +#if _MSC_VER == _MSC_FULL_VER / 10000 +#define DOCTEST_MSVC DOCTEST_COMPILER(_MSC_VER / 100, _MSC_VER % 100, _MSC_FULL_VER % 10000) +#else +#define DOCTEST_MSVC \ + DOCTEST_COMPILER(_MSC_VER / 100, (_MSC_FULL_VER / 100000) % 100, _MSC_FULL_VER % 100000) +#endif +#elif defined(__clang__) && defined(__clang_minor__) +#define DOCTEST_CLANG DOCTEST_COMPILER(__clang_major__, __clang_minor__, __clang_patchlevel__) +#elif defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__GNUC_PATCHLEVEL__) && \ + !defined(__INTEL_COMPILER) +#define DOCTEST_GCC DOCTEST_COMPILER(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__) +#endif + +#ifndef DOCTEST_MSVC +#define DOCTEST_MSVC 0 +#endif // DOCTEST_MSVC +#ifndef DOCTEST_CLANG +#define DOCTEST_CLANG 0 +#endif // DOCTEST_CLANG +#ifndef DOCTEST_GCC +#define DOCTEST_GCC 0 +#endif // DOCTEST_GCC + +// ================================================================================================= +// == COMPILER WARNINGS HELPERS ==================================================================== +// ================================================================================================= + +#if DOCTEST_CLANG +#ifdef __has_warning +#define DOCTEST_CLANG_HAS_WARNING(x) __has_warning(x) +#endif // __has_warning +#ifdef __has_feature +#define DOCTEST_CLANG_HAS_FEATURE(x) __has_feature(x) +#endif // __has_feature +#define DOCTEST_PRAGMA_TO_STR(x) _Pragma(#x) +#define DOCTEST_CLANG_SUPPRESS_WARNING_PUSH _Pragma("clang diagnostic push") +#define DOCTEST_MSVC_SUPPRESS_WARNING_PUSH +#define DOCTEST_GCC_SUPPRESS_WARNING_PUSH +#define DOCTEST_CLANG_SUPPRESS_WARNING(w) DOCTEST_PRAGMA_TO_STR(clang diagnostic ignored w) +#define DOCTEST_MSVC_SUPPRESS_WARNING(w) +#define DOCTEST_GCC_SUPPRESS_WARNING(w) +#define DOCTEST_CLANG_SUPPRESS_WARNING_POP _Pragma("clang diagnostic pop") +#define DOCTEST_MSVC_SUPPRESS_WARNING_POP +#define DOCTEST_GCC_SUPPRESS_WARNING_POP +#define DOCTEST_CLANG_SUPPRESS_WARNING_WITH_PUSH(w) \ + DOCTEST_CLANG_SUPPRESS_WARNING_PUSH DOCTEST_CLANG_SUPPRESS_WARNING(w) +#define DOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH(w) +#define DOCTEST_GCC_SUPPRESS_WARNING_WITH_PUSH(w) +#elif DOCTEST_GCC +#define DOCTEST_PRAGMA_TO_STR(x) _Pragma(#x) +#define DOCTEST_CLANG_SUPPRESS_WARNING_PUSH +#define DOCTEST_MSVC_SUPPRESS_WARNING_PUSH +#if DOCTEST_GCC >= DOCTEST_COMPILER(4, 7, 0) +#define DOCTEST_GCC_SUPPRESS_WARNING_PUSH _Pragma("GCC diagnostic push") +#else // GCC 4.7+ +#define DOCTEST_GCC_SUPPRESS_WARNING_PUSH +#endif // GCC 4.7+ +#define DOCTEST_CLANG_SUPPRESS_WARNING(w) +#define DOCTEST_MSVC_SUPPRESS_WARNING(w) +#define DOCTEST_GCC_SUPPRESS_WARNING(w) DOCTEST_PRAGMA_TO_STR(GCC diagnostic ignored w) +#define DOCTEST_CLANG_SUPPRESS_WARNING_POP +#define DOCTEST_MSVC_SUPPRESS_WARNING_POP +#if DOCTEST_GCC >= DOCTEST_COMPILER(4, 7, 0) +#define DOCTEST_GCC_SUPPRESS_WARNING_POP _Pragma("GCC diagnostic pop") +#else // GCC 4.7+ +#define DOCTEST_GCC_SUPPRESS_WARNING_POP +#endif // GCC 4.7+ +#define DOCTEST_CLANG_SUPPRESS_WARNING_WITH_PUSH(w) +#define DOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH(w) +#define DOCTEST_GCC_SUPPRESS_WARNING_WITH_PUSH(w) \ + DOCTEST_GCC_SUPPRESS_WARNING_PUSH DOCTEST_GCC_SUPPRESS_WARNING(w) +#elif DOCTEST_MSVC +#define DOCTEST_PRAGMA_TO_STR(x) +#define DOCTEST_CLANG_SUPPRESS_WARNING_PUSH +#define DOCTEST_MSVC_SUPPRESS_WARNING_PUSH __pragma(warning(push)) +#define DOCTEST_GCC_SUPPRESS_WARNING_PUSH +#define DOCTEST_CLANG_SUPPRESS_WARNING(w) +#define DOCTEST_MSVC_SUPPRESS_WARNING(w) __pragma(warning(disable : w)) +#define DOCTEST_GCC_SUPPRESS_WARNING(w) +#define DOCTEST_CLANG_SUPPRESS_WARNING_POP +#define DOCTEST_MSVC_SUPPRESS_WARNING_POP __pragma(warning(pop)) +#define DOCTEST_GCC_SUPPRESS_WARNING_POP +#define DOCTEST_CLANG_SUPPRESS_WARNING_WITH_PUSH(w) +#define DOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH(w) \ + DOCTEST_MSVC_SUPPRESS_WARNING_PUSH DOCTEST_MSVC_SUPPRESS_WARNING(w) +#define DOCTEST_GCC_SUPPRESS_WARNING_WITH_PUSH(w) +#endif // different compilers - warning suppression macros + +#ifndef DOCTEST_CLANG_HAS_WARNING +#define DOCTEST_CLANG_HAS_WARNING(x) 1 +#endif // DOCTEST_CLANG_HAS_WARNING + +#ifndef DOCTEST_CLANG_HAS_FEATURE +#define DOCTEST_CLANG_HAS_FEATURE(x) 0 +#endif // DOCTEST_CLANG_HAS_FEATURE + +// ================================================================================================= +// == COMPILER WARNINGS ============================================================================ +// ================================================================================================= + +DOCTEST_CLANG_SUPPRESS_WARNING_PUSH +DOCTEST_CLANG_SUPPRESS_WARNING("-Wunknown-pragmas") +DOCTEST_CLANG_SUPPRESS_WARNING("-Wnon-virtual-dtor") +DOCTEST_CLANG_SUPPRESS_WARNING("-Wweak-vtables") +DOCTEST_CLANG_SUPPRESS_WARNING("-Wpadded") +DOCTEST_CLANG_SUPPRESS_WARNING("-Wdeprecated") +DOCTEST_CLANG_SUPPRESS_WARNING("-Wmissing-prototypes") +DOCTEST_CLANG_SUPPRESS_WARNING("-Wunused-local-typedef") +DOCTEST_CLANG_SUPPRESS_WARNING("-Wc++11-long-long") +#if DOCTEST_CLANG && DOCTEST_CLANG_HAS_WARNING("-Wzero-as-null-pointer-constant") +DOCTEST_CLANG_SUPPRESS_WARNING("-Wzero-as-null-pointer-constant") +#endif // clang - 0 as null + +DOCTEST_GCC_SUPPRESS_WARNING_PUSH +DOCTEST_GCC_SUPPRESS_WARNING("-Wunknown-pragmas") +DOCTEST_GCC_SUPPRESS_WARNING("-Wpragmas") +DOCTEST_GCC_SUPPRESS_WARNING("-Weffc++") +DOCTEST_GCC_SUPPRESS_WARNING("-Wstrict-overflow") +DOCTEST_GCC_SUPPRESS_WARNING("-Wstrict-aliasing") +DOCTEST_GCC_SUPPRESS_WARNING("-Wctor-dtor-privacy") +DOCTEST_GCC_SUPPRESS_WARNING("-Wmissing-declarations") +DOCTEST_GCC_SUPPRESS_WARNING("-Wnon-virtual-dtor") +DOCTEST_GCC_SUPPRESS_WARNING("-Winline") +DOCTEST_GCC_SUPPRESS_WARNING("-Wlong-long") +DOCTEST_GCC_SUPPRESS_WARNING("-Wzero-as-null-pointer-constant") +DOCTEST_GCC_SUPPRESS_WARNING("-Wunused-local-typedefs") +DOCTEST_GCC_SUPPRESS_WARNING("-Wuseless-cast") + +DOCTEST_MSVC_SUPPRESS_WARNING_PUSH +DOCTEST_MSVC_SUPPRESS_WARNING(4616) // invalid compiler warning +DOCTEST_MSVC_SUPPRESS_WARNING(4619) // invalid compiler warning +DOCTEST_MSVC_SUPPRESS_WARNING(4996) // The compiler encountered a deprecated declaration +DOCTEST_MSVC_SUPPRESS_WARNING(4706) // assignment within conditional expression +DOCTEST_MSVC_SUPPRESS_WARNING(4512) // 'class' : assignment operator could not be generated +DOCTEST_MSVC_SUPPRESS_WARNING(4127) // conditional expression is constant +DOCTEST_MSVC_SUPPRESS_WARNING(4820) // padding +DOCTEST_MSVC_SUPPRESS_WARNING(4625) // copy constructor was implicitly defined as deleted +DOCTEST_MSVC_SUPPRESS_WARNING(4626) // assignment operator was implicitly defined as deleted +DOCTEST_MSVC_SUPPRESS_WARNING(5027) // move assignment operator was implicitly defined as deleted +DOCTEST_MSVC_SUPPRESS_WARNING(5026) // move constructor was implicitly defined as deleted +DOCTEST_MSVC_SUPPRESS_WARNING(4623) // default constructor was implicitly defined as deleted +DOCTEST_MSVC_SUPPRESS_WARNING(4640) // construction of local static object is not thread-safe + +// C4548 - expression before comma has no effect; expected expression with side - effect +// C4986 - exception specification does not match previous declaration +// C4350 - behavior change: 'member1' called instead of 'member2' +// C4668 - 'x' is not defined as a preprocessor macro, replacing with '0' for '#if/#elif' +// C4365 - conversion from 'int' to 'unsigned long', signed/unsigned mismatch +// C4774 - format string expected in argument 'x' is not a string literal +// C4820 - padding in structs + +// only 4 should be disabled globally: +// - C4514 # unreferenced inline function has been removed +// - C4571 # SEH related +// - C4710 # function not inlined +// - C4711 # function 'x' selected for automatic inline expansion + +#define DOCTEST_MAKE_STD_HEADERS_CLEAN_FROM_WARNINGS_ON_WALL_BEGIN \ + DOCTEST_MSVC_SUPPRESS_WARNING_PUSH \ + DOCTEST_MSVC_SUPPRESS_WARNING(4548) \ + DOCTEST_MSVC_SUPPRESS_WARNING(4986) \ + DOCTEST_MSVC_SUPPRESS_WARNING(4350) \ + DOCTEST_MSVC_SUPPRESS_WARNING(4668) \ + DOCTEST_MSVC_SUPPRESS_WARNING(4365) \ + DOCTEST_MSVC_SUPPRESS_WARNING(4774) \ + DOCTEST_MSVC_SUPPRESS_WARNING(4820) \ + DOCTEST_MSVC_SUPPRESS_WARNING(4625) \ + DOCTEST_MSVC_SUPPRESS_WARNING(4626) \ + DOCTEST_MSVC_SUPPRESS_WARNING(5027) \ + DOCTEST_MSVC_SUPPRESS_WARNING(5026) \ + DOCTEST_MSVC_SUPPRESS_WARNING(4623) \ + DOCTEST_MSVC_SUPPRESS_WARNING(5039) + +#define DOCTEST_MAKE_STD_HEADERS_CLEAN_FROM_WARNINGS_ON_WALL_END DOCTEST_MSVC_SUPPRESS_WARNING_POP + +// ================================================================================================= +// == FEATURE DETECTION ============================================================================ +// ================================================================================================= + +#if __cplusplus >= 201103L +#ifndef DOCTEST_CONFIG_WITH_DELETED_FUNCTIONS +#define DOCTEST_CONFIG_WITH_DELETED_FUNCTIONS +#endif // DOCTEST_CONFIG_WITH_DELETED_FUNCTIONS +#ifndef DOCTEST_CONFIG_WITH_RVALUE_REFERENCES +#define DOCTEST_CONFIG_WITH_RVALUE_REFERENCES +#endif // DOCTEST_CONFIG_WITH_RVALUE_REFERENCES +#ifndef DOCTEST_CONFIG_WITH_NULLPTR +#define DOCTEST_CONFIG_WITH_NULLPTR +#endif // DOCTEST_CONFIG_WITH_NULLPTR +#ifndef DOCTEST_CONFIG_WITH_LONG_LONG +#define DOCTEST_CONFIG_WITH_LONG_LONG +#endif // DOCTEST_CONFIG_WITH_LONG_LONG +#ifndef DOCTEST_CONFIG_WITH_STATIC_ASSERT +#define DOCTEST_CONFIG_WITH_STATIC_ASSERT +#endif // DOCTEST_CONFIG_WITH_STATIC_ASSERT +#ifndef DOCTEST_CONFIG_WITH_VARIADIC_MACROS +#define DOCTEST_CONFIG_WITH_VARIADIC_MACROS +#endif // DOCTEST_CONFIG_WITH_VARIADIC_MACROS +#endif // __cplusplus >= 201103L + +// MSVC C++11 feature support table: https://msdn.microsoft.com/en-us/library/hh567368.aspx +// GCC C++11 feature support table: https://gcc.gnu.org/projects/cxx-status.html +// MSVC version table: +// MSVC++ 15.0 _MSC_VER == 1910 (Visual Studio 2017) +// MSVC++ 14.0 _MSC_VER == 1900 (Visual Studio 2015) +// MSVC++ 12.0 _MSC_VER == 1800 (Visual Studio 2013) +// MSVC++ 11.0 _MSC_VER == 1700 (Visual Studio 2012) +// MSVC++ 10.0 _MSC_VER == 1600 (Visual Studio 2010) +// MSVC++ 9.0 _MSC_VER == 1500 (Visual Studio 2008) +// MSVC++ 8.0 _MSC_VER == 1400 (Visual Studio 2005) + +// deleted functions + +#ifndef DOCTEST_CONFIG_WITH_DELETED_FUNCTIONS +#if DOCTEST_MSVC >= DOCTEST_COMPILER(18, 0, 0) +#define DOCTEST_CONFIG_WITH_DELETED_FUNCTIONS +#endif // MSVC +#if DOCTEST_CLANG && DOCTEST_CLANG_HAS_FEATURE(cxx_deleted_functions) +#define DOCTEST_CONFIG_WITH_DELETED_FUNCTIONS +#endif // clang +#if DOCTEST_GCC >= DOCTEST_COMPILER(4, 5, 0) && defined(__GXX_EXPERIMENTAL_CXX0X__) +#define DOCTEST_CONFIG_WITH_DELETED_FUNCTIONS +#endif // GCC +#endif // DOCTEST_CONFIG_WITH_DELETED_FUNCTIONS + +#if defined(DOCTEST_CONFIG_NO_DELETED_FUNCTIONS) && defined(DOCTEST_CONFIG_WITH_DELETED_FUNCTIONS) +#undef DOCTEST_CONFIG_WITH_DELETED_FUNCTIONS +#endif // DOCTEST_CONFIG_NO_DELETED_FUNCTIONS + +// rvalue references + +#ifndef DOCTEST_CONFIG_WITH_RVALUE_REFERENCES +#if DOCTEST_MSVC >= DOCTEST_COMPILER(16, 0, 0) +#define DOCTEST_CONFIG_WITH_RVALUE_REFERENCES +#endif // MSVC +#if DOCTEST_CLANG && DOCTEST_CLANG_HAS_FEATURE(cxx_rvalue_references) +#define DOCTEST_CONFIG_WITH_RVALUE_REFERENCES +#endif // clang +#if DOCTEST_GCC >= DOCTEST_COMPILER(4, 3, 0) && defined(__GXX_EXPERIMENTAL_CXX0X__) +#define DOCTEST_CONFIG_WITH_RVALUE_REFERENCES +#endif // GCC +#endif // DOCTEST_CONFIG_WITH_RVALUE_REFERENCES + +#if defined(DOCTEST_CONFIG_NO_RVALUE_REFERENCES) && defined(DOCTEST_CONFIG_WITH_RVALUE_REFERENCES) +#undef DOCTEST_CONFIG_WITH_RVALUE_REFERENCES +#endif // DOCTEST_CONFIG_NO_RVALUE_REFERENCES + +// nullptr + +#ifndef DOCTEST_CONFIG_WITH_NULLPTR +#if DOCTEST_CLANG && DOCTEST_CLANG_HAS_FEATURE(cxx_nullptr) +#define DOCTEST_CONFIG_WITH_NULLPTR +#endif // clang +#if DOCTEST_GCC >= DOCTEST_COMPILER(4, 6, 0) && defined(__GXX_EXPERIMENTAL_CXX0X__) +#define DOCTEST_CONFIG_WITH_NULLPTR +#endif // GCC +#if DOCTEST_MSVC >= DOCTEST_COMPILER(16, 0, 0) +#define DOCTEST_CONFIG_WITH_NULLPTR +#endif // MSVC +#endif // DOCTEST_CONFIG_WITH_NULLPTR + +#if defined(DOCTEST_CONFIG_NO_NULLPTR) && defined(DOCTEST_CONFIG_WITH_NULLPTR) +#undef DOCTEST_CONFIG_WITH_NULLPTR +#endif // DOCTEST_CONFIG_NO_NULLPTR + +// variadic macros + +#ifndef DOCTEST_CONFIG_WITH_VARIADIC_MACROS +#if DOCTEST_MSVC >= DOCTEST_COMPILER(14, 0, 0) && !defined(__EDGE__) +#define DOCTEST_CONFIG_WITH_VARIADIC_MACROS +#endif // MSVC +#if(DOCTEST_CLANG || DOCTEST_GCC >= DOCTEST_COMPILER(4, 1, 0)) && \ + defined(__GXX_EXPERIMENTAL_CXX0X__) +#define DOCTEST_CONFIG_WITH_VARIADIC_MACROS +#endif // GCC and clang +#endif // DOCTEST_CONFIG_WITH_VARIADIC_MACROS + +#if defined(DOCTEST_CONFIG_NO_VARIADIC_MACROS) && defined(DOCTEST_CONFIG_WITH_VARIADIC_MACROS) +#undef DOCTEST_CONFIG_WITH_VARIADIC_MACROS +#endif // DOCTEST_CONFIG_NO_VARIADIC_MACROS + +// long long + +#ifndef DOCTEST_CONFIG_WITH_LONG_LONG +#if DOCTEST_MSVC >= DOCTEST_COMPILER(14, 0, 0) +#define DOCTEST_CONFIG_WITH_LONG_LONG +#endif // MSVC +#if(DOCTEST_CLANG || DOCTEST_GCC >= DOCTEST_COMPILER(4, 5, 0)) && \ + defined(__GXX_EXPERIMENTAL_CXX0X__) +#define DOCTEST_CONFIG_WITH_LONG_LONG +#endif // GCC and clang +#endif // DOCTEST_CONFIG_WITH_LONG_LONG + +#if defined(DOCTEST_CONFIG_NO_LONG_LONG) && defined(DOCTEST_CONFIG_WITH_LONG_LONG) +#undef DOCTEST_CONFIG_WITH_LONG_LONG +#endif // DOCTEST_CONFIG_NO_LONG_LONG + +// static_assert + +#ifndef DOCTEST_CONFIG_WITH_STATIC_ASSERT +#if DOCTEST_CLANG && DOCTEST_CLANG_HAS_FEATURE(cxx_static_assert) +#define DOCTEST_CONFIG_WITH_STATIC_ASSERT +#endif // clang +#if DOCTEST_GCC >= DOCTEST_COMPILER(4, 3, 0) && defined(__GXX_EXPERIMENTAL_CXX0X__) +#define DOCTEST_CONFIG_WITH_STATIC_ASSERT +#endif // GCC +#if DOCTEST_MSVC >= DOCTEST_COMPILER(16, 0, 0) +#define DOCTEST_CONFIG_WITH_STATIC_ASSERT +#endif // MSVC +#endif // DOCTEST_CONFIG_WITH_STATIC_ASSERT + +#if defined(DOCTEST_CONFIG_NO_STATIC_ASSERT) && defined(DOCTEST_CONFIG_WITH_STATIC_ASSERT) +#undef DOCTEST_CONFIG_WITH_STATIC_ASSERT +#endif // DOCTEST_CONFIG_NO_STATIC_ASSERT + +// other stuff... + +#if defined(DOCTEST_CONFIG_WITH_RVALUE_REFERENCES) || defined(DOCTEST_CONFIG_WITH_LONG_LONG) || \ + defined(DOCTEST_CONFIG_WITH_DELETED_FUNCTIONS) || defined(DOCTEST_CONFIG_WITH_NULLPTR) || \ + defined(DOCTEST_CONFIG_WITH_VARIADIC_MACROS) || defined(DOCTEST_CONFIG_WITH_STATIC_ASSERT) +#define DOCTEST_NO_CPP11_COMPAT +#endif // c++11 stuff + +#if defined(DOCTEST_NO_CPP11_COMPAT) +DOCTEST_CLANG_SUPPRESS_WARNING("-Wc++98-compat") +DOCTEST_CLANG_SUPPRESS_WARNING("-Wc++98-compat-pedantic") +#endif // DOCTEST_NO_CPP11_COMPAT + +#if DOCTEST_MSVC && !defined(DOCTEST_CONFIG_WINDOWS_SEH) +#define DOCTEST_CONFIG_WINDOWS_SEH +#endif // MSVC +#if defined(DOCTEST_CONFIG_NO_WINDOWS_SEH) && defined(DOCTEST_CONFIG_WINDOWS_SEH) +#undef DOCTEST_CONFIG_WINDOWS_SEH +#endif // DOCTEST_CONFIG_NO_WINDOWS_SEH + +#if !defined(_WIN32) && !defined(__QNX__) && !defined(DOCTEST_CONFIG_POSIX_SIGNALS) +#define DOCTEST_CONFIG_POSIX_SIGNALS +#endif // _WIN32 +#if defined(DOCTEST_CONFIG_NO_POSIX_SIGNALS) && defined(DOCTEST_CONFIG_POSIX_SIGNALS) +#undef DOCTEST_CONFIG_POSIX_SIGNALS +#endif // DOCTEST_CONFIG_NO_POSIX_SIGNALS + +#ifndef DOCTEST_CONFIG_NO_EXCEPTIONS +#if(DOCTEST_GCC || DOCTEST_CLANG) && !defined(__EXCEPTIONS) +#define DOCTEST_CONFIG_NO_EXCEPTIONS +#endif // clang and gcc +// in MSVC _HAS_EXCEPTIONS is defined in a header instead of as a project define +// so we can't do the automatic detection for MSVC without including some header +#endif // DOCTEST_CONFIG_NO_EXCEPTIONS + +#ifdef DOCTEST_CONFIG_NO_EXCEPTIONS_BUT_WITH_ALL_ASSERTS +#ifndef DOCTEST_CONFIG_NO_EXCEPTIONS +#define DOCTEST_CONFIG_NO_EXCEPTIONS +#endif // DOCTEST_CONFIG_NO_EXCEPTIONS +#endif // DOCTEST_CONFIG_NO_EXCEPTIONS_BUT_WITH_ALL_ASSERTS + +#if defined(DOCTEST_CONFIG_NO_EXCEPTIONS) && !defined(DOCTEST_CONFIG_NO_TRY_CATCH_IN_ASSERTS) +#define DOCTEST_CONFIG_NO_TRY_CATCH_IN_ASSERTS +#endif // DOCTEST_CONFIG_NO_EXCEPTIONS && !DOCTEST_CONFIG_NO_TRY_CATCH_IN_ASSERTS + +#if defined(DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN) && !defined(DOCTEST_CONFIG_IMPLEMENT) +#define DOCTEST_CONFIG_IMPLEMENT +#endif // DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN + +#if defined _WIN32 || defined __CYGWIN__ +#if DOCTEST_MSVC +#define DOCTEST_SYMBOL_EXPORT __declspec(dllexport) +#define DOCTEST_SYMBOL_IMPORT __declspec(dllimport) +#else // MSVC +#define DOCTEST_SYMBOL_EXPORT __attribute__((dllexport)) +#define DOCTEST_SYMBOL_IMPORT __attribute__((dllimport)) +#endif // MSVC +#else // _WIN32 +#define DOCTEST_SYMBOL_EXPORT __attribute__((visibility("default"))) +#define DOCTEST_SYMBOL_IMPORT +#endif // _WIN32 + +#ifdef DOCTEST_CONFIG_IMPLEMENTATION_IN_DLL +#ifdef DOCTEST_CONFIG_IMPLEMENT +#define DOCTEST_INTERFACE DOCTEST_SYMBOL_EXPORT +#else // DOCTEST_CONFIG_IMPLEMENT +#define DOCTEST_INTERFACE DOCTEST_SYMBOL_IMPORT +#endif // DOCTEST_CONFIG_IMPLEMENT +#else // DOCTEST_CONFIG_IMPLEMENTATION_IN_DLL +#define DOCTEST_INTERFACE +#endif // DOCTEST_CONFIG_IMPLEMENTATION_IN_DLL + +#if DOCTEST_MSVC +#define DOCTEST_NOINLINE __declspec(noinline) +#define DOCTEST_UNUSED +#define DOCTEST_ALIGNMENT(x) +#else // MSVC +#define DOCTEST_NOINLINE __attribute__((noinline)) +#define DOCTEST_UNUSED __attribute__((unused)) +#define DOCTEST_ALIGNMENT(x) __attribute__((aligned(x))) +#endif // MSVC + +#ifndef DOCTEST_CONFIG_NUM_CAPTURES_ON_STACK +#define DOCTEST_CONFIG_NUM_CAPTURES_ON_STACK 5 +#endif // DOCTEST_CONFIG_NUM_CAPTURES_ON_STACK + +// ================================================================================================= +// == FEATURE DETECTION END ======================================================================== +// ================================================================================================= + +// internal macros for string concatenation and anonymous variable name generation +#define DOCTEST_CAT_IMPL(s1, s2) s1##s2 +#define DOCTEST_CAT(s1, s2) DOCTEST_CAT_IMPL(s1, s2) +#ifdef __COUNTER__ // not standard and may be missing for some compilers +#define DOCTEST_ANONYMOUS(x) DOCTEST_CAT(x, __COUNTER__) +#else // __COUNTER__ +#define DOCTEST_ANONYMOUS(x) DOCTEST_CAT(x, __LINE__) +#endif // __COUNTER__ + +// macro for making a string out of an identifier +#ifdef DOCTEST_CONFIG_WITH_VARIADIC_MACROS +#define DOCTEST_TOSTR_IMPL(...) #__VA_ARGS__ +#define DOCTEST_TOSTR(...) DOCTEST_TOSTR_IMPL(__VA_ARGS__) +#else // DOCTEST_CONFIG_WITH_VARIADIC_MACROS +#define DOCTEST_TOSTR_IMPL(x) #x +#define DOCTEST_TOSTR(x) DOCTEST_TOSTR_IMPL(x) +#endif // DOCTEST_CONFIG_WITH_VARIADIC_MACROS + +// counts the number of elements in a C string +#define DOCTEST_COUNTOF(x) (sizeof(x) / sizeof(x[0])) + +#ifndef DOCTEST_CONFIG_ASSERTION_PARAMETERS_BY_VALUE +#define DOCTEST_REF_WRAP(x) x& +#else // DOCTEST_CONFIG_ASSERTION_PARAMETERS_BY_VALUE +#define DOCTEST_REF_WRAP(x) x +#endif // DOCTEST_CONFIG_ASSERTION_PARAMETERS_BY_VALUE + +// not using __APPLE__ because... this is how Catch does it +#if defined(__MAC_OS_X_VERSION_MIN_REQUIRED) +#define DOCTEST_PLATFORM_MAC +#elif defined(__IPHONE_OS_VERSION_MIN_REQUIRED) +#define DOCTEST_PLATFORM_IPHONE +#elif defined(_WIN32) +#define DOCTEST_PLATFORM_WINDOWS +#else +#define DOCTEST_PLATFORM_LINUX +#endif + +#define DOCTEST_GLOBAL_NO_WARNINGS(var) \ + DOCTEST_CLANG_SUPPRESS_WARNING_WITH_PUSH("-Wglobal-constructors") static int var DOCTEST_UNUSED +#define DOCTEST_GLOBAL_NO_WARNINGS_END() DOCTEST_CLANG_SUPPRESS_WARNING_POP + +// should probably take a look at https://github.com/scottt/debugbreak +#ifdef DOCTEST_PLATFORM_MAC +#define DOCTEST_BREAK_INTO_DEBUGGER() __asm__("int $3\n" : :) +#elif DOCTEST_MSVC +#define DOCTEST_BREAK_INTO_DEBUGGER() __debugbreak() +#elif defined(__MINGW32__) +extern "C" __declspec(dllimport) void __stdcall DebugBreak(); +#define DOCTEST_BREAK_INTO_DEBUGGER() ::DebugBreak() +#else // linux +#define DOCTEST_BREAK_INTO_DEBUGGER() ((void)0) +#endif // linux + +#if DOCTEST_CLANG +// to detect if libc++ is being used with clang (the _LIBCPP_VERSION identifier) +#include +#endif // clang + +#ifdef _LIBCPP_VERSION +// not forward declaring ostream for libc++ because I had some problems (inline namespaces vs c++98) +// so the header is used - also it is very light and doesn't drag a ton of stuff +#include +#else // _LIBCPP_VERSION +#ifndef DOCTEST_CONFIG_USE_IOSFWD +namespace std +{ +template +struct char_traits; +template <> +struct char_traits; +template +class basic_ostream; +typedef basic_ostream > ostream; +} // namespace std +#else // DOCTEST_CONFIG_USE_IOSFWD +#include +#endif // DOCTEST_CONFIG_USE_IOSFWD +#endif // _LIBCPP_VERSION + +// static assert macro - because of the c++98 support requires that the message is an +// identifier (no spaces and not a C string) - example without quotes: I_am_a_message +// taken from here: http://stackoverflow.com/a/1980156/3162383 +#ifdef DOCTEST_CONFIG_WITH_STATIC_ASSERT +#define DOCTEST_STATIC_ASSERT(expression, message) static_assert(expression, #message) +#else // DOCTEST_CONFIG_WITH_STATIC_ASSERT +#define DOCTEST_STATIC_ASSERT(expression, message) \ + struct DOCTEST_CAT(__static_assertion_at_line_, __LINE__) \ + { \ + doctest::detail::static_assert_impl::StaticAssertion((expression))> \ + DOCTEST_CAT(DOCTEST_CAT(DOCTEST_CAT(STATIC_ASSERTION_FAILED_AT_LINE_, __LINE__), \ + _), \ + message); \ + }; \ + typedef doctest::detail::static_assert_impl::StaticAssertionTest( \ + sizeof(DOCTEST_CAT(__static_assertion_at_line_, __LINE__)))> \ + DOCTEST_CAT(__static_assertion_test_at_line_, __LINE__) +#endif // DOCTEST_CONFIG_WITH_STATIC_ASSERT + +#ifdef DOCTEST_CONFIG_WITH_NULLPTR +#ifdef _LIBCPP_VERSION +#include +#else // _LIBCPP_VERSION +namespace std +{ +typedef decltype(nullptr) nullptr_t; +} +#endif // _LIBCPP_VERSION +#endif // DOCTEST_CONFIG_WITH_NULLPTR + +#ifndef DOCTEST_CONFIG_DISABLE + +#ifdef DOCTEST_CONFIG_INCLUDE_TYPE_TRAITS +#include +#endif // DOCTEST_CONFIG_INCLUDE_TYPE_TRAITS + +namespace doctest +{ +namespace detail +{ + struct TestSuite + { + const char* m_test_suite; + const char* m_description; + bool m_skip; + bool m_may_fail; + bool m_should_fail; + int m_expected_failures; + double m_timeout; + + TestSuite& operator*(const char* in) { + m_test_suite = in; + // clear state + m_description = 0; + m_skip = false; + m_may_fail = false; + m_should_fail = false; + m_expected_failures = 0; + m_timeout = 0; + return *this; + } + + template + TestSuite& operator*(const T& in) { + in.fill(*this); + return *this; + } + }; +} // namespace detail +} // namespace doctest + +// in a separate namespace outside of doctest because the DOCTEST_TEST_SUITE macro +// introduces an anonymous namespace in which getCurrentTestSuite gets overridden +namespace doctest_detail_test_suite_ns +{ +DOCTEST_INTERFACE doctest::detail::TestSuite& getCurrentTestSuite(); +} // namespace doctest_detail_test_suite_ns + +#endif // DOCTEST_CONFIG_DISABLE + +namespace doctest +{ +// A 24 byte string class (can be as small as 17 for x64 and 13 for x86) that can hold strings with length +// of up to 23 chars on the stack before going on the heap - the last byte of the buffer is used for: +// - "is small" bit - the highest bit - if "0" then it is small - otherwise its "1" (128) +// - if small - capacity left before going on the heap - using the lowest 5 bits +// - if small - 2 bits are left unused - the second and third highest ones +// - if small - acts as a null terminator if strlen() is 23 (24 including the null terminator) +// and the "is small" bit remains "0" ("as well as the capacity left") so its OK +// Idea taken from this lecture about the string implementation of facebook/folly - fbstring +// https://www.youtube.com/watch?v=kPR8h4-qZdk +// TODO: +// - optimizations - like not deleting memory unnecessarily in operator= and etc. +// - resize/reserve/clear +// - substr +// - replace +// - back/front +// - iterator stuff +// - find & friends +// - push_back/pop_back +// - assign/insert/erase +// - relational operators as free functions - taking const char* as one of the params +class DOCTEST_INTERFACE String +{ + static const unsigned len = 24; //!OCLINT avoid private static members + static const unsigned last = len - 1; //!OCLINT avoid private static members + + struct view // len should be more than sizeof(view) - because of the final byte for flags + { + char* ptr; + unsigned size; + unsigned capacity; + }; + + union + { + char buf[len]; + view data; + }; + + void copy(const String& other); + + void setOnHeap() { *reinterpret_cast(&buf[last]) = 128; } + void setLast(unsigned in = last) { buf[last] = char(in); } + +public: + String() { + buf[0] = '\0'; + setLast(); + } + + String(const char* in); + + String(const String& other) { copy(other); } + + ~String() { + if(!isOnStack()) + delete[] data.ptr; + } + + // GCC 4.9/5/6 report Wstrict-overflow when optimizations are ON and it got inlined in the vector class somewhere... + // see commit 574ef95f0cd379118be5011704664e4b5351f1e0 and build https://travis-ci.org/onqtam/doctest/builds/230671611 + DOCTEST_NOINLINE String& operator=(const String& other) { + if(this != &other) { + if(!isOnStack()) + delete[] data.ptr; + + copy(other); + } + + return *this; + } + String& operator+=(const String& other); + + String operator+(const String& other) const { return String(*this) += other; } + +#ifdef DOCTEST_CONFIG_WITH_RVALUE_REFERENCES + String(String&& other); + String& operator=(String&& other); +#endif // DOCTEST_CONFIG_WITH_RVALUE_REFERENCES + + bool isOnStack() const { return (buf[last] & 128) == 0; } + + char operator[](unsigned i) const { return const_cast(this)->operator[](i); } // NOLINT + char& operator[](unsigned i) { + if(isOnStack()) + return reinterpret_cast(buf)[i]; + return data.ptr[i]; + } + + const char* c_str() const { return const_cast(this)->c_str(); } // NOLINT + char* c_str() { + if(isOnStack()) + return reinterpret_cast(buf); + return data.ptr; + } + + DOCTEST_GCC_SUPPRESS_WARNING_WITH_PUSH("-Wmaybe-uninitialized") + unsigned size() const { + if(isOnStack()) + return last - (unsigned(buf[last]) & 31); // using "last" would work only if "len" is 32 + return data.size; + } + DOCTEST_GCC_SUPPRESS_WARNING_POP + + unsigned capacity() const { + if(isOnStack()) + return len; + return data.capacity; + } + + int compare(const char* other, bool no_case = false) const; + int compare(const String& other, bool no_case = false) const; +}; + +// clang-format off +inline bool operator==(const String& lhs, const String& rhs) { return lhs.compare(rhs) == 0; } +inline bool operator!=(const String& lhs, const String& rhs) { return lhs.compare(rhs) != 0; } +inline bool operator< (const String& lhs, const String& rhs) { return lhs.compare(rhs) < 0; } +inline bool operator> (const String& lhs, const String& rhs) { return lhs.compare(rhs) > 0; } +inline bool operator<=(const String& lhs, const String& rhs) { return (lhs != rhs) ? lhs.compare(rhs) < 0 : true; } +inline bool operator>=(const String& lhs, const String& rhs) { return (lhs != rhs) ? lhs.compare(rhs) > 0 : true; } +// clang-format on + +DOCTEST_INTERFACE std::ostream& operator<<(std::ostream& s, const String& in); + +namespace detail +{ +#ifndef DOCTEST_CONFIG_WITH_STATIC_ASSERT + namespace static_assert_impl + { + template + struct StaticAssertion; + + template <> + struct StaticAssertion + {}; + + template + struct StaticAssertionTest + {}; + } // namespace static_assert_impl +#endif // DOCTEST_CONFIG_WITH_STATIC_ASSERT + + template + struct enable_if + {}; + + template + struct enable_if + { typedef TYPE type; }; + + template + struct deferred_false + // cppcheck-suppress unusedStructMember + { static const bool value = false; }; + + // to silence the warning "-Wzero-as-null-pointer-constant" only for gcc 5 for the Approx template ctor - pragmas don't work for it... + inline void* getNull() { return 0; } + + namespace has_insertion_operator_impl + { + typedef char no; + typedef char yes[2]; + + struct any_t + { + template + // cppcheck-suppress noExplicitConstructor + any_t(const DOCTEST_REF_WRAP(T)); + }; + + yes& testStreamable(std::ostream&); + no testStreamable(no); + + no operator<<(const std::ostream&, const any_t&); + + template + struct has_insertion_operator + { + static std::ostream& s; + static const DOCTEST_REF_WRAP(T) t; + static const bool value = sizeof(testStreamable(s << t)) == sizeof(yes); + }; + } // namespace has_insertion_operator_impl + + template + struct has_insertion_operator : has_insertion_operator_impl::has_insertion_operator + {}; + + DOCTEST_INTERFACE void my_memcpy(void* dest, const void* src, unsigned num); + + DOCTEST_INTERFACE std::ostream* createStream(); + DOCTEST_INTERFACE String getStreamResult(std::ostream*); + DOCTEST_INTERFACE void freeStream(std::ostream*); + + template + struct StringMakerBase + { + template + static String convert(const DOCTEST_REF_WRAP(T)) { + return "{?}"; + } + }; + + template <> + struct StringMakerBase + { + template + static String convert(const DOCTEST_REF_WRAP(T) in) { + std::ostream* s = createStream(); + *s << in; + String result = getStreamResult(s); + freeStream(s); + return result; + } + }; + + DOCTEST_INTERFACE String rawMemoryToString(const void* object, unsigned size); + + template + String rawMemoryToString(const DOCTEST_REF_WRAP(T) object) { + return rawMemoryToString(&object, sizeof(object)); + } + + class NullType + { + }; + + template + struct Typelist + { + typedef T Head; + typedef U Tail; + }; + + // type of recursive function + template + struct ForEachType; + + // Recursion rule + template + struct ForEachType, Callable> : public ForEachType + { + enum + { + value = 1 + ForEachType::value + }; + + explicit ForEachType(Callable& callable) + : ForEachType(callable) { +#if DOCTEST_MSVC && DOCTEST_MSVC < DOCTEST_COMPILER(19, 10, 0) + callable.operator()(); +#else // MSVC + callable.template operator()(); +#endif // MSVC + } + }; + + // Recursion end + template + struct ForEachType, Callable> + { + public: + enum + { + value = 0 + }; + + explicit ForEachType(Callable& callable) { +#if DOCTEST_MSVC && DOCTEST_MSVC < DOCTEST_COMPILER(19, 10, 0) + callable.operator()(); +#else // MSVC + callable.template operator()(); +#endif // MSVC + } + }; + + template + const char* type_to_string() { + return "<>"; + } +} // namespace detail + +template +struct Types +{ +private: + typedef typename Types::Result TailResult; + +public: + typedef detail::Typelist Result; +}; + +template <> +struct Types<> +{ typedef detail::NullType Result; }; + +template +struct StringMaker : detail::StringMakerBase::value> +{}; + +template +struct StringMaker +{ + template + static String convert(U* p) { + if(p) + return detail::rawMemoryToString(p); + return "NULL"; + } +}; + +template +struct StringMaker +{ + static String convert(R C::*p) { + if(p) + return detail::rawMemoryToString(p); + return "NULL"; + } +}; + +template +String toString(const DOCTEST_REF_WRAP(T) value) { + return StringMaker::convert(value); +} + +#ifdef DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING +DOCTEST_INTERFACE String toString(char* in); +DOCTEST_INTERFACE String toString(const char* in); +#endif // DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING +DOCTEST_INTERFACE String toString(bool in); +DOCTEST_INTERFACE String toString(float in); +DOCTEST_INTERFACE String toString(double in); +DOCTEST_INTERFACE String toString(double long in); + +DOCTEST_INTERFACE String toString(char in); +DOCTEST_INTERFACE String toString(char signed in); +DOCTEST_INTERFACE String toString(char unsigned in); +DOCTEST_INTERFACE String toString(int short in); +DOCTEST_INTERFACE String toString(int short unsigned in); +DOCTEST_INTERFACE String toString(int in); +DOCTEST_INTERFACE String toString(int unsigned in); +DOCTEST_INTERFACE String toString(int long in); +DOCTEST_INTERFACE String toString(int long unsigned in); + +#ifdef DOCTEST_CONFIG_WITH_LONG_LONG +DOCTEST_INTERFACE String toString(int long long in); +DOCTEST_INTERFACE String toString(int long long unsigned in); +#endif // DOCTEST_CONFIG_WITH_LONG_LONG + +#ifdef DOCTEST_CONFIG_WITH_NULLPTR +DOCTEST_INTERFACE String toString(std::nullptr_t in); +#endif // DOCTEST_CONFIG_WITH_NULLPTR + +class DOCTEST_INTERFACE Approx +{ +public: + explicit Approx(double value); + + Approx operator()(double value) const { + Approx approx(value); + approx.epsilon(m_epsilon); + approx.scale(m_scale); + return approx; + } + +#ifdef DOCTEST_CONFIG_INCLUDE_TYPE_TRAITS + template + explicit Approx(const T& value, + typename detail::enable_if::value>::type* = + static_cast(detail::getNull())) { + *this = Approx(static_cast(value)); + } +#endif // DOCTEST_CONFIG_INCLUDE_TYPE_TRAITS + + // clang-format off + // overloads for double - the first one is necessary as it is in the implementation part of doctest + // as for the others - keeping them for potentially faster compile times + DOCTEST_INTERFACE friend bool operator==(double lhs, Approx const& rhs); + friend bool operator==(Approx const& lhs, double rhs) { return operator==(rhs, lhs); } + friend bool operator!=(double lhs, Approx const& rhs) { return !operator==(lhs, rhs); } + friend bool operator!=(Approx const& lhs, double rhs) { return !operator==(rhs, lhs); } + friend bool operator<=(double lhs, Approx const& rhs) { return lhs < rhs.m_value || lhs == rhs; } + friend bool operator<=(Approx const& lhs, double rhs) { return lhs.m_value < rhs || lhs == rhs; } + friend bool operator>=(double lhs, Approx const& rhs) { return lhs > rhs.m_value || lhs == rhs; } + friend bool operator>=(Approx const& lhs, double rhs) { return lhs.m_value > rhs || lhs == rhs; } + friend bool operator< (double lhs, Approx const& rhs) { return lhs < rhs.m_value && lhs != rhs; } + friend bool operator< (Approx const& lhs, double rhs) { return lhs.m_value < rhs && lhs != rhs; } + friend bool operator> (double lhs, Approx const& rhs) { return lhs > rhs.m_value && lhs != rhs; } + friend bool operator> (Approx const& lhs, double rhs) { return lhs.m_value > rhs && lhs != rhs; } + +#ifdef DOCTEST_CONFIG_INCLUDE_TYPE_TRAITS +#define DOCTEST_APPROX_PREFIX \ + template friend typename detail::enable_if::value, bool>::type + + DOCTEST_APPROX_PREFIX operator==(const T& lhs, const Approx& rhs) { return operator==(double(lhs), rhs); } + DOCTEST_APPROX_PREFIX operator==(const Approx& lhs, const T& rhs) { return operator==(rhs, lhs); } + DOCTEST_APPROX_PREFIX operator!=(const T& lhs, const Approx& rhs) { return !operator==(lhs, rhs); } + DOCTEST_APPROX_PREFIX operator!=(const Approx& lhs, const T& rhs) { return !operator==(rhs, lhs); } + DOCTEST_APPROX_PREFIX operator<=(const T& lhs, const Approx& rhs) { return double(lhs) < rhs.m_value || lhs == rhs; } + DOCTEST_APPROX_PREFIX operator<=(const Approx& lhs, const T& rhs) { return lhs.m_value < double(rhs) || lhs == rhs; } + DOCTEST_APPROX_PREFIX operator>=(const T& lhs, const Approx& rhs) { return double(lhs) > rhs.m_value || lhs == rhs; } + DOCTEST_APPROX_PREFIX operator>=(const Approx& lhs, const T& rhs) { return lhs.m_value > double(rhs) || lhs == rhs; } + DOCTEST_APPROX_PREFIX operator< (const T& lhs, const Approx& rhs) { return double(lhs) < rhs.m_value && lhs != rhs; } + DOCTEST_APPROX_PREFIX operator< (const Approx& lhs, const T& rhs) { return lhs.m_value < double(rhs) && lhs != rhs; } + DOCTEST_APPROX_PREFIX operator> (const T& lhs, const Approx& rhs) { return double(lhs) > rhs.m_value && lhs != rhs; } + DOCTEST_APPROX_PREFIX operator> (const Approx& lhs, const T& rhs) { return lhs.m_value > double(rhs) && lhs != rhs; } +#undef DOCTEST_APPROX_PREFIX +#endif // DOCTEST_CONFIG_INCLUDE_TYPE_TRAITS + + // clang-format on + + Approx& epsilon(double newEpsilon) { + m_epsilon = newEpsilon; + return *this; + } + +#ifdef DOCTEST_CONFIG_INCLUDE_TYPE_TRAITS + template + typename detail::enable_if::value, Approx&>::type epsilon( + const T& newEpsilon) { + m_epsilon = static_cast(newEpsilon); + return *this; + } +#endif // DOCTEST_CONFIG_INCLUDE_TYPE_TRAITS + + Approx& scale(double newScale) { + m_scale = newScale; + return *this; + } + +#ifdef DOCTEST_CONFIG_INCLUDE_TYPE_TRAITS + template + typename detail::enable_if::value, Approx&>::type scale( + const T& newScale) { + m_scale = static_cast(newScale); + return *this; + } +#endif // DOCTEST_CONFIG_INCLUDE_TYPE_TRAITS + + String toString() const; + +private: + double m_epsilon; + double m_scale; + double m_value; +}; + +template <> +inline String toString(const DOCTEST_REF_WRAP(Approx) value) { + return value.toString(); +} + +#if !defined(DOCTEST_CONFIG_DISABLE) + +namespace detail +{ + // the function type this library works with + typedef void (*funcType)(); + + namespace assertType + { + enum Enum + { + // macro traits + + is_warn = 1, + is_check = 2, + is_require = 4, + + is_throws = 8, + is_throws_as = 16, + is_nothrow = 32, + + is_fast = 64, // not checked anywhere - used just to distinguish the types + is_false = 128, + is_unary = 256, + + is_eq = 512, + is_ne = 1024, + + is_lt = 2048, + is_gt = 4096, + + is_ge = 8192, + is_le = 16384, + + // macro types + + DT_WARN = is_warn, + DT_CHECK = is_check, + DT_REQUIRE = is_require, + + DT_WARN_FALSE = is_false | is_warn, + DT_CHECK_FALSE = is_false | is_check, + DT_REQUIRE_FALSE = is_false | is_require, + + DT_WARN_THROWS = is_throws | is_warn, + DT_CHECK_THROWS = is_throws | is_check, + DT_REQUIRE_THROWS = is_throws | is_require, + + DT_WARN_THROWS_AS = is_throws_as | is_warn, + DT_CHECK_THROWS_AS = is_throws_as | is_check, + DT_REQUIRE_THROWS_AS = is_throws_as | is_require, + + DT_WARN_NOTHROW = is_nothrow | is_warn, + DT_CHECK_NOTHROW = is_nothrow | is_check, + DT_REQUIRE_NOTHROW = is_nothrow | is_require, + + DT_WARN_EQ = is_eq | is_warn, + DT_CHECK_EQ = is_eq | is_check, + DT_REQUIRE_EQ = is_eq | is_require, + + DT_WARN_NE = is_ne | is_warn, + DT_CHECK_NE = is_ne | is_check, + DT_REQUIRE_NE = is_ne | is_require, + + DT_WARN_GT = is_gt | is_warn, + DT_CHECK_GT = is_gt | is_check, + DT_REQUIRE_GT = is_gt | is_require, + + DT_WARN_LT = is_lt | is_warn, + DT_CHECK_LT = is_lt | is_check, + DT_REQUIRE_LT = is_lt | is_require, + + DT_WARN_GE = is_ge | is_warn, + DT_CHECK_GE = is_ge | is_check, + DT_REQUIRE_GE = is_ge | is_require, + + DT_WARN_LE = is_le | is_warn, + DT_CHECK_LE = is_le | is_check, + DT_REQUIRE_LE = is_le | is_require, + + DT_WARN_UNARY = is_unary | is_warn, + DT_CHECK_UNARY = is_unary | is_check, + DT_REQUIRE_UNARY = is_unary | is_require, + + DT_WARN_UNARY_FALSE = is_false | is_unary | is_warn, + DT_CHECK_UNARY_FALSE = is_false | is_unary | is_check, + DT_REQUIRE_UNARY_FALSE = is_false | is_unary | is_require, + + DT_FAST_WARN_EQ = is_fast | is_eq | is_warn, + DT_FAST_CHECK_EQ = is_fast | is_eq | is_check, + DT_FAST_REQUIRE_EQ = is_fast | is_eq | is_require, + + DT_FAST_WARN_NE = is_fast | is_ne | is_warn, + DT_FAST_CHECK_NE = is_fast | is_ne | is_check, + DT_FAST_REQUIRE_NE = is_fast | is_ne | is_require, + + DT_FAST_WARN_GT = is_fast | is_gt | is_warn, + DT_FAST_CHECK_GT = is_fast | is_gt | is_check, + DT_FAST_REQUIRE_GT = is_fast | is_gt | is_require, + + DT_FAST_WARN_LT = is_fast | is_lt | is_warn, + DT_FAST_CHECK_LT = is_fast | is_lt | is_check, + DT_FAST_REQUIRE_LT = is_fast | is_lt | is_require, + + DT_FAST_WARN_GE = is_fast | is_ge | is_warn, + DT_FAST_CHECK_GE = is_fast | is_ge | is_check, + DT_FAST_REQUIRE_GE = is_fast | is_ge | is_require, + + DT_FAST_WARN_LE = is_fast | is_le | is_warn, + DT_FAST_CHECK_LE = is_fast | is_le | is_check, + DT_FAST_REQUIRE_LE = is_fast | is_le | is_require, + + DT_FAST_WARN_UNARY = is_fast | is_unary | is_warn, + DT_FAST_CHECK_UNARY = is_fast | is_unary | is_check, + DT_FAST_REQUIRE_UNARY = is_fast | is_unary | is_require, + + DT_FAST_WARN_UNARY_FALSE = is_fast | is_false | is_unary | is_warn, + DT_FAST_CHECK_UNARY_FALSE = is_fast | is_false | is_unary | is_check, + DT_FAST_REQUIRE_UNARY_FALSE = is_fast | is_false | is_unary | is_require + }; + } // namespace assertType + + DOCTEST_INTERFACE const char* assertString(assertType::Enum val); + + // clang-format off + template struct decay_array { typedef T type; }; + template struct decay_array { typedef T* type; }; + template struct decay_array { typedef T* type; }; + + template struct not_char_pointer { enum { value = 1 }; }; + template<> struct not_char_pointer { enum { value = 0 }; }; + template<> struct not_char_pointer { enum { value = 0 }; }; + + template struct can_use_op : not_char_pointer::type> {}; + // clang-format on + + struct TestFailureException + { + }; + + DOCTEST_INTERFACE bool checkIfShouldThrow(assertType::Enum at); + DOCTEST_INTERFACE void fastAssertThrowIfFlagSet(int flags); + + struct TestAccessibleContextState + { + bool no_throw; // to skip exceptions-related assertion macros + bool success; // include successful assertions in output + }; + + struct ContextState; + + DOCTEST_INTERFACE TestAccessibleContextState* getTestsContextState(); + + struct DOCTEST_INTERFACE SubcaseSignature + { + const char* m_name; + const char* m_file; + int m_line; + + SubcaseSignature(const char* name, const char* file, int line) + : m_name(name) + , m_file(file) + , m_line(line) {} + + bool operator<(const SubcaseSignature& other) const; + }; + + // cppcheck-suppress copyCtorAndEqOperator + struct DOCTEST_INTERFACE Subcase + { + SubcaseSignature m_signature; + bool m_entered; + + Subcase(const char* name, const char* file, int line); + Subcase(const Subcase& other); + ~Subcase(); + + operator bool() const { return m_entered; } + }; + + template + String stringifyBinaryExpr(const DOCTEST_REF_WRAP(L) lhs, const char* op, + const DOCTEST_REF_WRAP(R) rhs) { + return toString(lhs) + op + toString(rhs); + } + + struct DOCTEST_INTERFACE Result + { + bool m_passed; + String m_decomposition; + + ~Result(); + + DOCTEST_NOINLINE Result(bool passed = false, const String& decomposition = String()) + : m_passed(passed) + , m_decomposition(decomposition) {} + + DOCTEST_NOINLINE Result(const Result& other) + : m_passed(other.m_passed) + , m_decomposition(other.m_decomposition) {} + + Result& operator=(const Result& other); + + operator bool() { return !m_passed; } + + // clang-format off + // forbidding some expressions based on this table: http://en.cppreference.com/w/cpp/language/operator_precedence + template Result& operator& (const R&) { DOCTEST_STATIC_ASSERT(deferred_false::value, Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison); return *this; } + template Result& operator^ (const R&) { DOCTEST_STATIC_ASSERT(deferred_false::value, Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison); return *this; } + template Result& operator| (const R&) { DOCTEST_STATIC_ASSERT(deferred_false::value, Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison); return *this; } + template Result& operator&& (const R&) { DOCTEST_STATIC_ASSERT(deferred_false::value, Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison); return *this; } + template Result& operator|| (const R&) { DOCTEST_STATIC_ASSERT(deferred_false::value, Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison); return *this; } + template Result& operator== (const R&) { DOCTEST_STATIC_ASSERT(deferred_false::value, Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison); return *this; } + template Result& operator!= (const R&) { DOCTEST_STATIC_ASSERT(deferred_false::value, Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison); return *this; } + template Result& operator< (const R&) { DOCTEST_STATIC_ASSERT(deferred_false::value, Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison); return *this; } + template Result& operator> (const R&) { DOCTEST_STATIC_ASSERT(deferred_false::value, Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison); return *this; } + template Result& operator<= (const R&) { DOCTEST_STATIC_ASSERT(deferred_false::value, Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison); return *this; } + template Result& operator>= (const R&) { DOCTEST_STATIC_ASSERT(deferred_false::value, Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison); return *this; } + template Result& operator= (const R&) { DOCTEST_STATIC_ASSERT(deferred_false::value, Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison); return *this; } + template Result& operator+= (const R&) { DOCTEST_STATIC_ASSERT(deferred_false::value, Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison); return *this; } + template Result& operator-= (const R&) { DOCTEST_STATIC_ASSERT(deferred_false::value, Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison); return *this; } + template Result& operator*= (const R&) { DOCTEST_STATIC_ASSERT(deferred_false::value, Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison); return *this; } + template Result& operator/= (const R&) { DOCTEST_STATIC_ASSERT(deferred_false::value, Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison); return *this; } + template Result& operator%= (const R&) { DOCTEST_STATIC_ASSERT(deferred_false::value, Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison); return *this; } + template Result& operator<<=(const R&) { DOCTEST_STATIC_ASSERT(deferred_false::value, Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison); return *this; } + template Result& operator>>=(const R&) { DOCTEST_STATIC_ASSERT(deferred_false::value, Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison); return *this; } + template Result& operator&= (const R&) { DOCTEST_STATIC_ASSERT(deferred_false::value, Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison); return *this; } + template Result& operator^= (const R&) { DOCTEST_STATIC_ASSERT(deferred_false::value, Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison); return *this; } + template Result& operator|= (const R&) { DOCTEST_STATIC_ASSERT(deferred_false::value, Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison); return *this; } + // clang-format on + }; + +#ifndef DOCTEST_CONFIG_NO_COMPARISON_WARNING_SUPPRESSION + + DOCTEST_CLANG_SUPPRESS_WARNING_PUSH + DOCTEST_CLANG_SUPPRESS_WARNING("-Wsign-conversion") + DOCTEST_CLANG_SUPPRESS_WARNING("-Wsign-compare") + //DOCTEST_CLANG_SUPPRESS_WARNING("-Wdouble-promotion") + //DOCTEST_CLANG_SUPPRESS_WARNING("-Wconversion") + //DOCTEST_CLANG_SUPPRESS_WARNING("-Wfloat-equal") + + DOCTEST_GCC_SUPPRESS_WARNING_PUSH + DOCTEST_GCC_SUPPRESS_WARNING("-Wsign-conversion") + DOCTEST_GCC_SUPPRESS_WARNING("-Wsign-compare") + //DOCTEST_GCC_SUPPRESS_WARNING("-Wdouble-promotion") + //DOCTEST_GCC_SUPPRESS_WARNING("-Wconversion") + //DOCTEST_GCC_SUPPRESS_WARNING("-Wfloat-equal") + + DOCTEST_MSVC_SUPPRESS_WARNING_PUSH + // http://stackoverflow.com/questions/39479163 what's the difference between C4018 and C4389 + DOCTEST_MSVC_SUPPRESS_WARNING(4388) // signed/unsigned mismatch + DOCTEST_MSVC_SUPPRESS_WARNING(4389) // 'operator' : signed/unsigned mismatch + DOCTEST_MSVC_SUPPRESS_WARNING(4018) // 'expression' : signed/unsigned mismatch + //DOCTEST_MSVC_SUPPRESS_WARNING(4805) // 'operation' : unsafe mix of type 'type' and type 'type' in operation + +#endif // DOCTEST_CONFIG_NO_COMPARISON_WARNING_SUPPRESSION + +// clang-format off +#ifndef DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING +#define DOCTEST_COMPARISON_RETURN_TYPE bool +#else // DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING +#define DOCTEST_COMPARISON_RETURN_TYPE typename enable_if::value || can_use_op::value, bool>::type + inline bool eq(const char* lhs, const char* rhs) { return String(lhs) == String(rhs); } + inline bool ne(const char* lhs, const char* rhs) { return String(lhs) != String(rhs); } + inline bool lt(const char* lhs, const char* rhs) { return String(lhs) < String(rhs); } + inline bool gt(const char* lhs, const char* rhs) { return String(lhs) > String(rhs); } + inline bool le(const char* lhs, const char* rhs) { return String(lhs) <= String(rhs); } + inline bool ge(const char* lhs, const char* rhs) { return String(lhs) >= String(rhs); } +#endif // DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING + + template DOCTEST_COMPARISON_RETURN_TYPE eq(const DOCTEST_REF_WRAP(L) lhs, const DOCTEST_REF_WRAP(R) rhs) { return lhs == rhs; } + template DOCTEST_COMPARISON_RETURN_TYPE ne(const DOCTEST_REF_WRAP(L) lhs, const DOCTEST_REF_WRAP(R) rhs) { return lhs != rhs; } + template DOCTEST_COMPARISON_RETURN_TYPE lt(const DOCTEST_REF_WRAP(L) lhs, const DOCTEST_REF_WRAP(R) rhs) { return lhs < rhs; } + template DOCTEST_COMPARISON_RETURN_TYPE gt(const DOCTEST_REF_WRAP(L) lhs, const DOCTEST_REF_WRAP(R) rhs) { return lhs > rhs; } + template DOCTEST_COMPARISON_RETURN_TYPE le(const DOCTEST_REF_WRAP(L) lhs, const DOCTEST_REF_WRAP(R) rhs) { return lhs <= rhs; } + template DOCTEST_COMPARISON_RETURN_TYPE ge(const DOCTEST_REF_WRAP(L) lhs, const DOCTEST_REF_WRAP(R) rhs) { return lhs >= rhs; } + // clang-format on + +#ifndef DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING +#define DOCTEST_CMP_EQ(l, r) l == r +#define DOCTEST_CMP_NE(l, r) l != r +#define DOCTEST_CMP_GT(l, r) l > r +#define DOCTEST_CMP_LT(l, r) l < r +#define DOCTEST_CMP_GE(l, r) l >= r +#define DOCTEST_CMP_LE(l, r) l <= r +#else // DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING +#define DOCTEST_CMP_EQ(l, r) eq(l, r) +#define DOCTEST_CMP_NE(l, r) ne(l, r) +#define DOCTEST_CMP_GT(l, r) gt(l, r) +#define DOCTEST_CMP_LT(l, r) lt(l, r) +#define DOCTEST_CMP_GE(l, r) ge(l, r) +#define DOCTEST_CMP_LE(l, r) le(l, r) +#endif // DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING + +#define DOCTEST_DO_BINARY_EXPRESSION_COMPARISON(op, op_str, op_macro) \ + template \ + DOCTEST_NOINLINE Result operator op(const DOCTEST_REF_WRAP(R) rhs) { \ + bool res = op_macro(lhs, rhs); \ + if(m_assert_type & assertType::is_false) \ + res = !res; \ + if(!res || doctest::detail::getTestsContextState()->success) \ + return Result(res, stringifyBinaryExpr(lhs, op_str, rhs)); \ + return Result(res); \ + } + +#define DOCTEST_FORBIT_EXPRESSION(op) \ + template \ + Expression_lhs& operator op(const R&) { \ + DOCTEST_STATIC_ASSERT(deferred_false::value, \ + Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison); \ + return *this; \ + } + + template + // cppcheck-suppress copyCtorAndEqOperator + struct Expression_lhs + { + L lhs; + assertType::Enum m_assert_type; + + explicit Expression_lhs(L in, assertType::Enum at) + : lhs(in) + , m_assert_type(at) {} + + DOCTEST_NOINLINE operator Result() { + bool res = !!lhs; + if(m_assert_type & assertType::is_false) //!OCLINT bitwise operator in conditional + res = !res; + + if(!res || getTestsContextState()->success) + return Result(res, toString(lhs)); + return Result(res); + } + + // clang-format off + DOCTEST_DO_BINARY_EXPRESSION_COMPARISON(==, " == ", DOCTEST_CMP_EQ) //!OCLINT bitwise operator in conditional + DOCTEST_DO_BINARY_EXPRESSION_COMPARISON(!=, " != ", DOCTEST_CMP_NE) //!OCLINT bitwise operator in conditional + DOCTEST_DO_BINARY_EXPRESSION_COMPARISON(>, " > ", DOCTEST_CMP_GT) //!OCLINT bitwise operator in conditional + DOCTEST_DO_BINARY_EXPRESSION_COMPARISON(<, " < ", DOCTEST_CMP_LT) //!OCLINT bitwise operator in conditional + DOCTEST_DO_BINARY_EXPRESSION_COMPARISON(>=, " >= ", DOCTEST_CMP_GE) //!OCLINT bitwise operator in conditional + DOCTEST_DO_BINARY_EXPRESSION_COMPARISON(<=, " <= ", DOCTEST_CMP_LE) //!OCLINT bitwise operator in conditional + // clang-format on + + // forbidding some expressions based on this table: http://en.cppreference.com/w/cpp/language/operator_precedence + DOCTEST_FORBIT_EXPRESSION(&) + DOCTEST_FORBIT_EXPRESSION(^) + DOCTEST_FORBIT_EXPRESSION(|) + DOCTEST_FORBIT_EXPRESSION(&&) + DOCTEST_FORBIT_EXPRESSION(||) + DOCTEST_FORBIT_EXPRESSION(=) + DOCTEST_FORBIT_EXPRESSION(+=) + DOCTEST_FORBIT_EXPRESSION(-=) + DOCTEST_FORBIT_EXPRESSION(*=) + DOCTEST_FORBIT_EXPRESSION(/=) + DOCTEST_FORBIT_EXPRESSION(%=) + DOCTEST_FORBIT_EXPRESSION(<<=) + DOCTEST_FORBIT_EXPRESSION(>>=) + DOCTEST_FORBIT_EXPRESSION(&=) + DOCTEST_FORBIT_EXPRESSION(^=) + DOCTEST_FORBIT_EXPRESSION(|=) + // these 2 are unfortunate because they should be allowed - they have higher precedence over the comparisons, but the + // ExpressionDecomposer class uses the left shift operator to capture the left operand of the binary expression... + DOCTEST_FORBIT_EXPRESSION(<<) + DOCTEST_FORBIT_EXPRESSION(>>) + }; + +#ifndef DOCTEST_CONFIG_NO_COMPARISON_WARNING_SUPPRESSION + + DOCTEST_CLANG_SUPPRESS_WARNING_POP + DOCTEST_MSVC_SUPPRESS_WARNING_POP + DOCTEST_GCC_SUPPRESS_WARNING_POP + +#endif // DOCTEST_CONFIG_NO_COMPARISON_WARNING_SUPPRESSION + + struct ExpressionDecomposer + { + assertType::Enum m_assert_type; + + ExpressionDecomposer(assertType::Enum at) + : m_assert_type(at) {} + + // The right operator for capturing expressions is "<=" instead of "<<" (based on the operator precedence table) + // but then there will be warnings from GCC about "-Wparentheses" and since "_Pragma()" is problematic this will stay for now... + // https://github.com/philsquared/Catch/issues/870 + // https://github.com/philsquared/Catch/issues/565 + template + Expression_lhs operator<<(const DOCTEST_REF_WRAP(L) operand) { + return Expression_lhs(operand, m_assert_type); + } + }; + + struct DOCTEST_INTERFACE TestCase + { + // not used for determining uniqueness + funcType m_test; // a function pointer to the test case + String m_full_name; // contains the name (only for templated test cases!) + the template type + const char* m_name; // name of the test case + const char* m_type; // for templated test cases - gets appended to the real name + const char* m_test_suite; // the test suite in which the test was added + const char* m_description; + bool m_skip; + bool m_may_fail; + bool m_should_fail; + int m_expected_failures; + double m_timeout; + + // fields by which uniqueness of test cases shall be determined + const char* m_file; // the file in which the test was registered + unsigned m_line; // the line where the test was registered + int m_template_id; // an ID used to distinguish between the different versions of a templated test case + + TestCase(funcType test, const char* file, unsigned line, const TestSuite& test_suite, + const char* type = "", int template_id = -1); + + // for gcc 4.7 + DOCTEST_NOINLINE ~TestCase() {} + + TestCase& operator*(const char* in); + + template + TestCase& operator*(const T& in) { + in.fill(*this); + return *this; + } + + TestCase(const TestCase& other) { *this = other; } + + TestCase& operator=(const TestCase& other); + + bool operator<(const TestCase& other) const; + }; + + // forward declarations of functions used by the macros + DOCTEST_INTERFACE int regTest(const TestCase& tc); + DOCTEST_INTERFACE int setTestSuite(const TestSuite& ts); + + namespace binaryAssertComparison + { + enum Enum + { + eq = 0, + ne, + gt, + lt, + ge, + le + }; + } // namespace binaryAssertComparison + + // clang-format off + template struct RelationalComparator { bool operator()(const DOCTEST_REF_WRAP(L), const DOCTEST_REF_WRAP(R) ) const { return false; } }; + template struct RelationalComparator<0, L, R> { bool operator()(const DOCTEST_REF_WRAP(L) lhs, const DOCTEST_REF_WRAP(R) rhs) const { return eq(lhs, rhs); } }; + template struct RelationalComparator<1, L, R> { bool operator()(const DOCTEST_REF_WRAP(L) lhs, const DOCTEST_REF_WRAP(R) rhs) const { return ne(lhs, rhs); } }; + template struct RelationalComparator<2, L, R> { bool operator()(const DOCTEST_REF_WRAP(L) lhs, const DOCTEST_REF_WRAP(R) rhs) const { return gt(lhs, rhs); } }; + template struct RelationalComparator<3, L, R> { bool operator()(const DOCTEST_REF_WRAP(L) lhs, const DOCTEST_REF_WRAP(R) rhs) const { return lt(lhs, rhs); } }; + template struct RelationalComparator<4, L, R> { bool operator()(const DOCTEST_REF_WRAP(L) lhs, const DOCTEST_REF_WRAP(R) rhs) const { return ge(lhs, rhs); } }; + template struct RelationalComparator<5, L, R> { bool operator()(const DOCTEST_REF_WRAP(L) lhs, const DOCTEST_REF_WRAP(R) rhs) const { return le(lhs, rhs); } }; + // clang-format on + + struct DOCTEST_INTERFACE ResultBuilder + { + assertType::Enum m_assert_type; + const char* m_file; + int m_line; + const char* m_expr; + const char* m_exception_type; + + Result m_result; + bool m_threw; + bool m_threw_as; + bool m_failed; + String m_exception; + + ResultBuilder(assertType::Enum at, const char* file, int line, const char* expr, + const char* exception_type = ""); + + ~ResultBuilder(); + + void setResult(const Result& res) { m_result = res; } + + template + DOCTEST_NOINLINE void binary_assert(const DOCTEST_REF_WRAP(L) lhs, + const DOCTEST_REF_WRAP(R) rhs) { + m_result.m_passed = RelationalComparator()(lhs, rhs); + if(!m_result.m_passed || getTestsContextState()->success) + m_result.m_decomposition = stringifyBinaryExpr(lhs, ", ", rhs); + } + + template + DOCTEST_NOINLINE void unary_assert(const DOCTEST_REF_WRAP(L) val) { + m_result.m_passed = !!val; + + if(m_assert_type & assertType::is_false) //!OCLINT bitwise operator in conditional + m_result.m_passed = !m_result.m_passed; + + if(!m_result.m_passed || getTestsContextState()->success) + m_result.m_decomposition = toString(val); + } + + void unexpectedExceptionOccurred(); + + bool log(); + void react() const; + }; + + namespace assertAction + { + enum Enum + { + nothing = 0, + dbgbreak = 1, + shouldthrow = 2 + }; + } // namespace assertAction + + template + DOCTEST_NOINLINE int fast_binary_assert(assertType::Enum at, const char* file, int line, + const char* expr, const DOCTEST_REF_WRAP(L) lhs, + const DOCTEST_REF_WRAP(R) rhs) { + ResultBuilder rb(at, file, line, expr); + + rb.m_result.m_passed = RelationalComparator()(lhs, rhs); + + if(!rb.m_result.m_passed || getTestsContextState()->success) + rb.m_result.m_decomposition = stringifyBinaryExpr(lhs, ", ", rhs); + + int res = 0; + + if(rb.log()) + res |= assertAction::dbgbreak; + + if(rb.m_failed && checkIfShouldThrow(at)) + res |= assertAction::shouldthrow; + +#ifdef DOCTEST_CONFIG_SUPER_FAST_ASSERTS + // ######################################################################################### + // IF THE DEBUGGER BREAKS HERE - GO 1 LEVEL UP IN THE CALLSTACK TO SEE THE FAILING ASSERTION + // THIS IS THE EFFECT OF HAVING 'DOCTEST_CONFIG_SUPER_FAST_ASSERTS' DEFINED + // ######################################################################################### + if(res & assertAction::dbgbreak) + DOCTEST_BREAK_INTO_DEBUGGER(); + fastAssertThrowIfFlagSet(res); +#endif // DOCTEST_CONFIG_SUPER_FAST_ASSERTS + + return res; + } + + template + DOCTEST_NOINLINE int fast_unary_assert(assertType::Enum at, const char* file, int line, + const char* val_str, const DOCTEST_REF_WRAP(L) val) { + ResultBuilder rb(at, file, line, val_str); + + rb.m_result.m_passed = !!val; + + if(at & assertType::is_false) //!OCLINT bitwise operator in conditional + rb.m_result.m_passed = !rb.m_result.m_passed; + + if(!rb.m_result.m_passed || getTestsContextState()->success) + rb.m_result.m_decomposition = toString(val); + + int res = 0; + + if(rb.log()) + res |= assertAction::dbgbreak; + + if(rb.m_failed && checkIfShouldThrow(at)) + res |= assertAction::shouldthrow; + +#ifdef DOCTEST_CONFIG_SUPER_FAST_ASSERTS + // ######################################################################################### + // IF THE DEBUGGER BREAKS HERE - GO 1 LEVEL UP IN THE CALLSTACK TO SEE THE FAILING ASSERTION + // THIS IS THE EFFECT OF HAVING 'DOCTEST_CONFIG_SUPER_FAST_ASSERTS' DEFINED + // ######################################################################################### + if(res & assertAction::dbgbreak) + DOCTEST_BREAK_INTO_DEBUGGER(); + fastAssertThrowIfFlagSet(res); +#endif // DOCTEST_CONFIG_SUPER_FAST_ASSERTS + + return res; + } + + struct DOCTEST_INTERFACE IExceptionTranslator + { + virtual ~IExceptionTranslator() {} + virtual bool translate(String&) const = 0; + }; + + template + class ExceptionTranslator : public IExceptionTranslator //!OCLINT destructor of virtual class + { + public: + explicit ExceptionTranslator(String (*translateFunction)(T)) + : m_translateFunction(translateFunction) {} + + bool translate(String& res) const { +#ifndef DOCTEST_CONFIG_NO_EXCEPTIONS + try { + throw; + // cppcheck-suppress catchExceptionByValue + } catch(T ex) { // NOLINT + res = m_translateFunction(ex); //!OCLINT parameter reassignment + return true; + } catch(...) {} //!OCLINT - empty catch statement +#endif // DOCTEST_CONFIG_NO_EXCEPTIONS + ((void)res); // to silence -Wunused-parameter + return false; + } + + protected: + String (*m_translateFunction)(T); + }; + + DOCTEST_INTERFACE void registerExceptionTranslatorImpl( + const IExceptionTranslator* translateFunction); + + // FIX FOR VISUAL STUDIO VERSIONS PRIOR TO 2015 - they failed to compile the call to operator<< with + // std::ostream passed as a reference noting that there is a use of an undefined type (which there isn't) + DOCTEST_INTERFACE void writeStringToStream(std::ostream* s, const String& str); + + template + struct StringStreamBase + { + template + static void convert(std::ostream* s, const T& in) { + writeStringToStream(s, toString(in)); + } + + // always treat char* as a string in this context - no matter + // if DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING is defined + static void convert(std::ostream* s, const char* in) { writeStringToStream(s, String(in)); } + }; + + template <> + struct StringStreamBase + { + template + static void convert(std::ostream* s, const T& in) { + *s << in; + } + }; + + template + struct StringStream : StringStreamBase::value> + {}; + + template + void toStream(std::ostream* s, const T& value) { + StringStream::convert(s, value); + } + +#ifdef DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING + DOCTEST_INTERFACE void toStream(std::ostream* s, char* in); + DOCTEST_INTERFACE void toStream(std::ostream* s, const char* in); +#endif // DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING + DOCTEST_INTERFACE void toStream(std::ostream* s, bool in); + DOCTEST_INTERFACE void toStream(std::ostream* s, float in); + DOCTEST_INTERFACE void toStream(std::ostream* s, double in); + DOCTEST_INTERFACE void toStream(std::ostream* s, double long in); + + DOCTEST_INTERFACE void toStream(std::ostream* s, char in); + DOCTEST_INTERFACE void toStream(std::ostream* s, char signed in); + DOCTEST_INTERFACE void toStream(std::ostream* s, char unsigned in); + DOCTEST_INTERFACE void toStream(std::ostream* s, int short in); + DOCTEST_INTERFACE void toStream(std::ostream* s, int short unsigned in); + DOCTEST_INTERFACE void toStream(std::ostream* s, int in); + DOCTEST_INTERFACE void toStream(std::ostream* s, int unsigned in); + DOCTEST_INTERFACE void toStream(std::ostream* s, int long in); + DOCTEST_INTERFACE void toStream(std::ostream* s, int long unsigned in); + +#ifdef DOCTEST_CONFIG_WITH_LONG_LONG + DOCTEST_INTERFACE void toStream(std::ostream* s, int long long in); + DOCTEST_INTERFACE void toStream(std::ostream* s, int long long unsigned in); +#endif // DOCTEST_CONFIG_WITH_LONG_LONG + + struct IContextScope + { + virtual ~IContextScope() {} + virtual void build(std::ostream*) = 0; + }; + + DOCTEST_INTERFACE void addToContexts(IContextScope* ptr); + DOCTEST_INTERFACE void popFromContexts(); + DOCTEST_INTERFACE void useContextIfExceptionOccurred(IContextScope* ptr); + + // cppcheck-suppress copyCtorAndEqOperator + class ContextBuilder + { + friend class ContextScope; + + struct ICapture + { + virtual ~ICapture() {} + virtual void toStream(std::ostream*) const = 0; + }; + + template + struct Capture : ICapture //!OCLINT destructor of virtual class + { + const T* capture; + + explicit Capture(const T* in) + : capture(in) {} + virtual void toStream(std::ostream* s) const { // override + detail::toStream(s, *capture); + } + }; + + struct Chunk + { + char buf[sizeof(Capture)] DOCTEST_ALIGNMENT( + 2 * sizeof(void*)); // place to construct a Capture + }; + + struct Node + { + Chunk chunk; + Node* next; + }; + + Chunk stackChunks[DOCTEST_CONFIG_NUM_CAPTURES_ON_STACK]; + int numCaptures; + Node* head; + Node* tail; + + DOCTEST_GCC_SUPPRESS_WARNING_WITH_PUSH("-Wcast-align") + void build(std::ostream* s) const { + int curr = 0; + // iterate over small buffer + while(curr < numCaptures && curr < DOCTEST_CONFIG_NUM_CAPTURES_ON_STACK) + reinterpret_cast(stackChunks[curr++].buf)->toStream(s); + // iterate over list + Node* curr_elem = head; + while(curr < numCaptures) { + reinterpret_cast(curr_elem->chunk.buf)->toStream(s); + curr_elem = curr_elem->next; + ++curr; + } + } + DOCTEST_GCC_SUPPRESS_WARNING_POP + + // steal the contents of the other - acting as a move constructor... + DOCTEST_NOINLINE ContextBuilder(ContextBuilder& other) + : numCaptures(other.numCaptures) + , head(other.head) + , tail(other.tail) { + other.numCaptures = 0; + other.head = 0; + other.tail = 0; + my_memcpy(stackChunks, other.stackChunks, + unsigned(int(sizeof(Chunk)) * DOCTEST_CONFIG_NUM_CAPTURES_ON_STACK)); + } + + ContextBuilder& operator=(const ContextBuilder&); // NOLINT + + public: + // cppcheck-suppress uninitMemberVar + DOCTEST_NOINLINE ContextBuilder() // NOLINT + : numCaptures(0) + , head(0) + , tail(0) {} + + template + DOCTEST_NOINLINE ContextBuilder& operator<<(T& in) { + Capture temp(&in); + + // construct either on stack or on heap + // copy the bytes for the whole object - including the vtable because we cant construct + // the object directly in the buffer using placement new - need the header... + if(numCaptures < DOCTEST_CONFIG_NUM_CAPTURES_ON_STACK) { + my_memcpy(stackChunks[numCaptures].buf, &temp, sizeof(Chunk)); + } else { + Node* curr = new Node; + curr->next = 0; + if(tail) { + tail->next = curr; + tail = curr; + } else { + head = tail = curr; + } + + my_memcpy(tail->chunk.buf, &temp, sizeof(Chunk)); + } + ++numCaptures; + return *this; + } + + DOCTEST_NOINLINE ~ContextBuilder() { + // free the linked list - the ones on the stack are left as-is + // no destructors are called at all - there is no need + while(head) { + Node* next = head->next; + delete head; + head = next; + } + } + +#ifdef DOCTEST_CONFIG_WITH_RVALUE_REFERENCES + template + ContextBuilder& operator<<(const T&&) { + DOCTEST_STATIC_ASSERT( + deferred_false::value, + Cannot_pass_temporaries_or_rvalues_to_the_streaming_operator_because_it_caches_pointers_to_the_passed_objects_for_lazy_evaluation); + return *this; + } +#endif // DOCTEST_CONFIG_WITH_RVALUE_REFERENCES + }; + + class ContextScope : public IContextScope + { + ContextBuilder contextBuilder; + + public: + DOCTEST_NOINLINE explicit ContextScope(ContextBuilder& temp) + : contextBuilder(temp) { + addToContexts(this); + } + + DOCTEST_NOINLINE ~ContextScope() { + useContextIfExceptionOccurred(this); + popFromContexts(); + } + + void build(std::ostream* s) { contextBuilder.build(s); } + }; + + class DOCTEST_INTERFACE MessageBuilder + { + std::ostream* m_stream; + const char* m_file; + int m_line; + assertType::Enum m_severity; + + public: + MessageBuilder(const char* file, int line, assertType::Enum severity); + ~MessageBuilder(); + + template + MessageBuilder& operator<<(const T& in) { + toStream(m_stream, in); + return *this; + } + + void log(std::ostream&); + bool log(); + void react(); + }; +} // namespace detail + +struct test_suite +{ + const char* data; + test_suite(const char* in) + : data(in) {} + void fill(detail::TestCase& state) const { state.m_test_suite = data; } + void fill(detail::TestSuite& state) const { state.m_test_suite = data; } +}; + +struct description +{ + const char* data; + description(const char* in) + : data(in) {} + void fill(detail::TestCase& state) const { state.m_description = data; } + void fill(detail::TestSuite& state) const { state.m_description = data; } +}; + +struct skip +{ + bool data; + skip(bool in = true) + : data(in) {} + void fill(detail::TestCase& state) const { state.m_skip = data; } + void fill(detail::TestSuite& state) const { state.m_skip = data; } +}; + +struct timeout +{ + double data; + timeout(double in) + : data(in) {} + void fill(detail::TestCase& state) const { state.m_timeout = data; } + void fill(detail::TestSuite& state) const { state.m_timeout = data; } +}; + +struct may_fail +{ + bool data; + may_fail(bool in = true) + : data(in) {} + void fill(detail::TestCase& state) const { state.m_may_fail = data; } + void fill(detail::TestSuite& state) const { state.m_may_fail = data; } +}; + +struct should_fail +{ + bool data; + should_fail(bool in = true) + : data(in) {} + void fill(detail::TestCase& state) const { state.m_should_fail = data; } + void fill(detail::TestSuite& state) const { state.m_should_fail = data; } +}; + +struct expected_failures +{ + int data; + expected_failures(int in) + : data(in) {} + void fill(detail::TestCase& state) const { state.m_expected_failures = data; } + void fill(detail::TestSuite& state) const { state.m_expected_failures = data; } +}; + +#endif // DOCTEST_CONFIG_DISABLE + +#ifndef DOCTEST_CONFIG_DISABLE +template +int registerExceptionTranslator(String (*translateFunction)(T)) { + DOCTEST_CLANG_SUPPRESS_WARNING_WITH_PUSH("-Wexit-time-destructors") + static detail::ExceptionTranslator exceptionTranslator(translateFunction); + DOCTEST_CLANG_SUPPRESS_WARNING_POP + detail::registerExceptionTranslatorImpl(&exceptionTranslator); + return 0; +} + +#else // DOCTEST_CONFIG_DISABLE +template +int registerExceptionTranslator(String (*)(T)) { + return 0; +} +#endif // DOCTEST_CONFIG_DISABLE + +DOCTEST_INTERFACE bool isRunningInTest(); + +// cppcheck-suppress noCopyConstructor +class DOCTEST_INTERFACE Context +{ +#if !defined(DOCTEST_CONFIG_DISABLE) + detail::ContextState* p; + + void parseArgs(int argc, const char* const* argv, bool withDefaults = false); + +#endif // DOCTEST_CONFIG_DISABLE + +public: + explicit Context(int argc = 0, const char* const* argv = 0); + + ~Context(); + + void applyCommandLine(int argc, const char* const* argv); + + void addFilter(const char* filter, const char* value); + void clearFilters(); + void setOption(const char* option, int value); + void setOption(const char* option, const char* value); + + bool shouldExit(); + + int run(); +}; + +} // namespace doctest + +// if registering is not disabled +#if !defined(DOCTEST_CONFIG_DISABLE) + +#ifdef DOCTEST_CONFIG_WITH_VARIADIC_MACROS +#define DOCTEST_EXPAND_VA_ARGS(...) __VA_ARGS__ +#else // DOCTEST_CONFIG_WITH_VARIADIC_MACROS +#define DOCTEST_EXPAND_VA_ARGS +#endif // DOCTEST_CONFIG_WITH_VARIADIC_MACROS + +#define DOCTEST_STRIP_PARENS(x) x +#define DOCTEST_HANDLE_BRACED_VA_ARGS(expr) DOCTEST_STRIP_PARENS(DOCTEST_EXPAND_VA_ARGS expr) + +// registers the test by initializing a dummy var with a function +#define DOCTEST_REGISTER_FUNCTION(f, decorators) \ + DOCTEST_GLOBAL_NO_WARNINGS(DOCTEST_ANONYMOUS(_DOCTEST_ANON_VAR_)) = doctest::detail::regTest( \ + doctest::detail::TestCase(f, __FILE__, __LINE__, \ + doctest_detail_test_suite_ns::getCurrentTestSuite()) * \ + decorators); \ + DOCTEST_GLOBAL_NO_WARNINGS_END() + +#define DOCTEST_IMPLEMENT_FIXTURE(der, base, func, decorators) \ + namespace \ + { \ + struct der : base \ + { \ + void f(); \ + }; \ + static void func() { \ + der v; \ + v.f(); \ + } \ + DOCTEST_REGISTER_FUNCTION(func, decorators) \ + } \ + inline DOCTEST_NOINLINE void der::f() + +#define DOCTEST_CREATE_AND_REGISTER_FUNCTION(f, decorators) \ + static void f(); \ + DOCTEST_REGISTER_FUNCTION(f, decorators) \ + static void f() + +// for registering tests +#define DOCTEST_TEST_CASE(decorators) \ + DOCTEST_CREATE_AND_REGISTER_FUNCTION(DOCTEST_ANONYMOUS(_DOCTEST_ANON_FUNC_), decorators) + +// for registering tests with a fixture +#define DOCTEST_TEST_CASE_FIXTURE(c, decorators) \ + DOCTEST_IMPLEMENT_FIXTURE(DOCTEST_ANONYMOUS(_DOCTEST_ANON_CLASS_), c, \ + DOCTEST_ANONYMOUS(_DOCTEST_ANON_FUNC_), decorators) + +// for converting types to strings without the header and demangling +#ifdef DOCTEST_CONFIG_WITH_VARIADIC_MACROS +#define DOCTEST_TYPE_TO_STRING_IMPL(...) \ + template <> \ + inline const char* type_to_string<__VA_ARGS__>() { \ + return "<" #__VA_ARGS__ ">"; \ + } +#define DOCTEST_TYPE_TO_STRING(...) \ + namespace doctest \ + { \ + namespace detail \ + { \ + DOCTEST_TYPE_TO_STRING_IMPL(__VA_ARGS__) \ + } \ + } \ + typedef int DOCTEST_ANONYMOUS(_DOCTEST_ANON_FOR_SEMICOLON_) +#else // DOCTEST_CONFIG_WITH_VARIADIC_MACROS +#define DOCTEST_TYPE_TO_STRING_IMPL(x) \ + template <> \ + inline const char* type_to_string() { \ + return "<" #x ">"; \ + } +#define DOCTEST_TYPE_TO_STRING(x) \ + namespace doctest \ + { \ + namespace detail \ + { \ + DOCTEST_TYPE_TO_STRING_IMPL(x) \ + } \ + } \ + typedef int DOCTEST_ANONYMOUS(_DOCTEST_ANON_FOR_SEMICOLON_) +#endif // DOCTEST_CONFIG_WITH_VARIADIC_MACROS + +// for typed tests +#define DOCTEST_TEST_CASE_TEMPLATE_IMPL(decorators, T, types, anon) \ + template \ + inline void anon(); \ + struct DOCTEST_CAT(anon, FUNCTOR) \ + { \ + template \ + void operator()() { \ + doctest::detail::regTest( \ + doctest::detail::TestCase(anon, __FILE__, __LINE__, \ + doctest_detail_test_suite_ns::getCurrentTestSuite(), \ + doctest::detail::type_to_string(), Index) * \ + decorators); \ + } \ + }; \ + inline int DOCTEST_CAT(anon, REG_FUNC)() { \ + DOCTEST_CAT(anon, FUNCTOR) registrar; \ + doctest::detail::ForEachType \ + doIt(registrar); \ + return 0; \ + } \ + DOCTEST_GLOBAL_NO_WARNINGS(DOCTEST_CAT(anon, DUMMY)) = DOCTEST_CAT(anon, REG_FUNC)(); \ + DOCTEST_GLOBAL_NO_WARNINGS_END() \ + template \ + inline void anon() + +#ifdef DOCTEST_CONFIG_WITH_VARIADIC_MACROS +#define DOCTEST_TEST_CASE_TEMPLATE(decorators, T, ...) \ + DOCTEST_TEST_CASE_TEMPLATE_IMPL(decorators, T, (__VA_ARGS__), \ + DOCTEST_ANONYMOUS(_DOCTEST_ANON_TMP_)) +#else // DOCTEST_CONFIG_WITH_VARIADIC_MACROS +#define DOCTEST_TEST_CASE_TEMPLATE(decorators, T, types) \ + DOCTEST_TEST_CASE_TEMPLATE_IMPL(decorators, T, types, DOCTEST_ANONYMOUS(_DOCTEST_ANON_TMP_)) +#endif // DOCTEST_CONFIG_WITH_VARIADIC_MACROS + +#define DOCTEST_TEST_CASE_TEMPLATE_DEFINE_IMPL(decorators, T, id, anon) \ + template \ + inline void anon(); \ + struct DOCTEST_CAT(id, _FUNCTOR) \ + { \ + int m_line; \ + DOCTEST_CAT(id, _FUNCTOR) \ + (int line) \ + : m_line(line) {} \ + template \ + void operator()() { \ + doctest::detail::regTest( \ + doctest::detail::TestCase(anon, __FILE__, __LINE__, \ + doctest_detail_test_suite_ns::getCurrentTestSuite(), \ + doctest::detail::type_to_string(), \ + m_line * 1000 + Index) * \ + decorators); \ + } \ + }; \ + template \ + inline void anon() + +#define DOCTEST_TEST_CASE_TEMPLATE_DEFINE(decorators, T, id) \ + DOCTEST_TEST_CASE_TEMPLATE_DEFINE_IMPL(decorators, T, id, DOCTEST_ANONYMOUS(_DOCTEST_ANON_TMP_)) + +#define DOCTEST_TEST_CASE_TEMPLATE_INSTANTIATE_IMPL(id, types, anon) \ + static int DOCTEST_CAT(anon, REG_FUNC)() { \ + DOCTEST_CAT(id, _FUNCTOR) registrar(__LINE__); \ + doctest::detail::ForEachType \ + doIt(registrar); \ + return 0; \ + } \ + DOCTEST_GLOBAL_NO_WARNINGS(DOCTEST_CAT(anon, DUMMY)) = DOCTEST_CAT(anon, REG_FUNC)(); \ + DOCTEST_GLOBAL_NO_WARNINGS_END() typedef int DOCTEST_ANONYMOUS(_DOCTEST_ANON_FOR_SEMICOLON_) + +#ifdef DOCTEST_CONFIG_WITH_VARIADIC_MACROS +#define DOCTEST_TEST_CASE_TEMPLATE_INSTANTIATE(id, ...) \ + DOCTEST_TEST_CASE_TEMPLATE_INSTANTIATE_IMPL(id, (__VA_ARGS__), \ + DOCTEST_ANONYMOUS(_DOCTEST_ANON_TMP_)) +#else // DOCTEST_CONFIG_WITH_VARIADIC_MACROS +#define DOCTEST_TEST_CASE_TEMPLATE_INSTANTIATE(id, types) \ + DOCTEST_TEST_CASE_TEMPLATE_INSTANTIATE_IMPL(id, types, DOCTEST_ANONYMOUS(_DOCTEST_ANON_TMP_)) +#endif // DOCTEST_CONFIG_WITH_VARIADIC_MACROS + +// for subcases +#define DOCTEST_SUBCASE(name) \ + if(const doctest::detail::Subcase & DOCTEST_ANONYMOUS(_DOCTEST_ANON_SUBCASE_) DOCTEST_UNUSED = \ + doctest::detail::Subcase(name, __FILE__, __LINE__)) + +// for grouping tests in test suites by using code blocks +#define DOCTEST_TEST_SUITE_IMPL(decorators, ns_name) \ + namespace ns_name \ + { \ + namespace doctest_detail_test_suite_ns \ + { \ + static DOCTEST_NOINLINE doctest::detail::TestSuite& getCurrentTestSuite() { \ + static doctest::detail::TestSuite data; \ + static bool inited = false; \ + if(!inited) { \ + data* decorators; \ + inited = true; \ + } \ + return data; \ + } \ + } \ + } \ + namespace ns_name + +#define DOCTEST_TEST_SUITE(decorators) \ + DOCTEST_TEST_SUITE_IMPL(decorators, DOCTEST_ANONYMOUS(_DOCTEST_ANON_SUITE_)) + +// for starting a testsuite block +#define DOCTEST_TEST_SUITE_BEGIN(decorators) \ + DOCTEST_GLOBAL_NO_WARNINGS(DOCTEST_ANONYMOUS(_DOCTEST_ANON_VAR_)) = \ + doctest::detail::setTestSuite(doctest::detail::TestSuite() * decorators); \ + DOCTEST_GLOBAL_NO_WARNINGS_END() \ + typedef int DOCTEST_ANONYMOUS(_DOCTEST_ANON_FOR_SEMICOLON_) + +// for ending a testsuite block +#define DOCTEST_TEST_SUITE_END \ + DOCTEST_GLOBAL_NO_WARNINGS(DOCTEST_ANONYMOUS(_DOCTEST_ANON_VAR_)) = \ + doctest::detail::setTestSuite(doctest::detail::TestSuite() * ""); \ + DOCTEST_GLOBAL_NO_WARNINGS_END() \ + typedef int DOCTEST_ANONYMOUS(_DOCTEST_ANON_FOR_SEMICOLON_) + +// for registering exception translators +#define DOCTEST_REGISTER_EXCEPTION_TRANSLATOR_IMPL(translatorName, signature) \ + inline doctest::String translatorName(signature); \ + DOCTEST_GLOBAL_NO_WARNINGS(DOCTEST_ANONYMOUS(_DOCTEST_ANON_TRANSLATOR_)) = \ + doctest::registerExceptionTranslator(translatorName); \ + DOCTEST_GLOBAL_NO_WARNINGS_END() \ + doctest::String translatorName(signature) + +#define DOCTEST_REGISTER_EXCEPTION_TRANSLATOR(signature) \ + DOCTEST_REGISTER_EXCEPTION_TRANSLATOR_IMPL(DOCTEST_ANONYMOUS(_DOCTEST_ANON_TRANSLATOR_), \ + signature) + +// for logging +#define DOCTEST_INFO(x) \ + doctest::detail::ContextScope DOCTEST_ANONYMOUS(_DOCTEST_CAPTURE_)( \ + doctest::detail::ContextBuilder() << x) +#define DOCTEST_CAPTURE(x) DOCTEST_INFO(#x " := " << x) + +#define DOCTEST_ADD_AT_IMPL(type, file, line, mb, x) \ + do { \ + doctest::detail::MessageBuilder mb(file, line, doctest::detail::assertType::type); \ + mb << x; \ + if(mb.log()) \ + DOCTEST_BREAK_INTO_DEBUGGER(); \ + mb.react(); \ + } while((void)0, 0) + +// clang-format off +#define DOCTEST_ADD_MESSAGE_AT(file, line, x) DOCTEST_ADD_AT_IMPL(is_warn, file, line, DOCTEST_ANONYMOUS(_DOCTEST_MESSAGE_), x) +#define DOCTEST_ADD_FAIL_CHECK_AT(file, line, x) DOCTEST_ADD_AT_IMPL(is_check, file, line, DOCTEST_ANONYMOUS(_DOCTEST_MESSAGE_), x) +#define DOCTEST_ADD_FAIL_AT(file, line, x) DOCTEST_ADD_AT_IMPL(is_require, file, line, DOCTEST_ANONYMOUS(_DOCTEST_MESSAGE_), x) +// clang-format on + +#define DOCTEST_MESSAGE(x) DOCTEST_ADD_MESSAGE_AT(__FILE__, __LINE__, x) +#define DOCTEST_FAIL_CHECK(x) DOCTEST_ADD_FAIL_CHECK_AT(__FILE__, __LINE__, x) +#define DOCTEST_FAIL(x) DOCTEST_ADD_FAIL_AT(__FILE__, __LINE__, x) + +#if __cplusplus >= 201402L || (DOCTEST_MSVC >= DOCTEST_COMPILER(19, 10, 0)) +template +constexpr T to_lvalue = x; +#define DOCTEST_TO_LVALUE(...) to_lvalue +#else +#ifdef DOCTEST_CONFIG_WITH_VARIADIC_MACROS +#define DOCTEST_TO_LVALUE(...) TO_LVALUE_CAN_BE_USED_ONLY_IN_CPP14_MODE_OR_WITH_VS_2017_OR_NEWER +#else // DOCTEST_CONFIG_WITH_VARIADIC_MACROS +#define DOCTEST_TO_LVALUE(x) TO_LVALUE_CAN_BE_USED_ONLY_IN_CPP14_MODE_OR_WITH_VS_2017_OR_NEWER +#endif // DOCTEST_CONFIG_WITH_VARIADIC_MACROS +#endif // TO_LVALUE hack for logging macros like INFO() + +// common code in asserts - for convenience +#define DOCTEST_ASSERT_LOG_AND_REACT(rb) \ + if(rb.log()) \ + DOCTEST_BREAK_INTO_DEBUGGER(); \ + rb.react() + +#ifdef DOCTEST_CONFIG_NO_TRY_CATCH_IN_ASSERTS +#define DOCTEST_WRAP_IN_TRY(x) x; +#else // DOCTEST_CONFIG_NO_TRY_CATCH_IN_ASSERTS +#define DOCTEST_WRAP_IN_TRY(x) \ + try { \ + x; \ + } catch(...) { _DOCTEST_RB.unexpectedExceptionOccurred(); } +#endif // DOCTEST_CONFIG_NO_TRY_CATCH_IN_ASSERTS + +#define DOCTEST_ASSERT_IMPLEMENT_2(expr, assert_type) \ + DOCTEST_CLANG_SUPPRESS_WARNING_WITH_PUSH("-Woverloaded-shift-op-parentheses") \ + doctest::detail::ResultBuilder _DOCTEST_RB( \ + doctest::detail::assertType::assert_type, __FILE__, __LINE__, \ + DOCTEST_TOSTR(DOCTEST_HANDLE_BRACED_VA_ARGS(expr))); \ + DOCTEST_WRAP_IN_TRY(_DOCTEST_RB.setResult( \ + doctest::detail::ExpressionDecomposer(doctest::detail::assertType::assert_type) \ + << DOCTEST_HANDLE_BRACED_VA_ARGS(expr))) \ + DOCTEST_ASSERT_LOG_AND_REACT(_DOCTEST_RB) \ + DOCTEST_CLANG_SUPPRESS_WARNING_POP + +#define DOCTEST_ASSERT_IMPLEMENT_1(expr, assert_type) \ + do { \ + DOCTEST_ASSERT_IMPLEMENT_2(expr, assert_type); \ + } while((void)0, 0) + +#ifdef DOCTEST_CONFIG_WITH_VARIADIC_MACROS +#define DOCTEST_WARN(...) DOCTEST_ASSERT_IMPLEMENT_1((__VA_ARGS__), DT_WARN) +#define DOCTEST_CHECK(...) DOCTEST_ASSERT_IMPLEMENT_1((__VA_ARGS__), DT_CHECK) +#define DOCTEST_REQUIRE(...) DOCTEST_ASSERT_IMPLEMENT_1((__VA_ARGS__), DT_REQUIRE) +#define DOCTEST_WARN_FALSE(...) DOCTEST_ASSERT_IMPLEMENT_1((__VA_ARGS__), DT_WARN_FALSE) +#define DOCTEST_CHECK_FALSE(...) DOCTEST_ASSERT_IMPLEMENT_1((__VA_ARGS__), DT_CHECK_FALSE) +#define DOCTEST_REQUIRE_FALSE(...) DOCTEST_ASSERT_IMPLEMENT_1((__VA_ARGS__), DT_REQUIRE_FALSE) +#else // DOCTEST_CONFIG_WITH_VARIADIC_MACROS +#define DOCTEST_WARN(expr) DOCTEST_ASSERT_IMPLEMENT_1(expr, DT_WARN) +#define DOCTEST_CHECK(expr) DOCTEST_ASSERT_IMPLEMENT_1(expr, DT_CHECK) +#define DOCTEST_REQUIRE(expr) DOCTEST_ASSERT_IMPLEMENT_1(expr, DT_REQUIRE) +#define DOCTEST_WARN_FALSE(expr) DOCTEST_ASSERT_IMPLEMENT_1(expr, DT_WARN_FALSE) +#define DOCTEST_CHECK_FALSE(expr) DOCTEST_ASSERT_IMPLEMENT_1(expr, DT_CHECK_FALSE) +#define DOCTEST_REQUIRE_FALSE(expr) DOCTEST_ASSERT_IMPLEMENT_1(expr, DT_REQUIRE_FALSE) +#endif // DOCTEST_CONFIG_WITH_VARIADIC_MACROS + +// clang-format off +#ifdef DOCTEST_CONFIG_WITH_VARIADIC_MACROS +#define DOCTEST_WARN_MESSAGE(cond, msg) do { DOCTEST_INFO(msg); DOCTEST_ASSERT_IMPLEMENT_2((cond), DT_WARN); } while((void)0, 0) +#define DOCTEST_CHECK_MESSAGE(cond, msg) do { DOCTEST_INFO(msg); DOCTEST_ASSERT_IMPLEMENT_2((cond), DT_CHECK); } while((void)0, 0) +#define DOCTEST_REQUIRE_MESSAGE(cond, msg) do { DOCTEST_INFO(msg); DOCTEST_ASSERT_IMPLEMENT_2((cond), DT_REQUIRE); } while((void)0, 0) +#define DOCTEST_WARN_FALSE_MESSAGE(cond, msg) do { DOCTEST_INFO(msg); DOCTEST_ASSERT_IMPLEMENT_2((cond), DT_WARN_FALSE); } while((void)0, 0) +#define DOCTEST_CHECK_FALSE_MESSAGE(cond, msg) do { DOCTEST_INFO(msg); DOCTEST_ASSERT_IMPLEMENT_2((cond), DT_CHECK_FALSE); } while((void)0, 0) +#define DOCTEST_REQUIRE_FALSE_MESSAGE(cond, msg) do { DOCTEST_INFO(msg); DOCTEST_ASSERT_IMPLEMENT_2((cond), DT_REQUIRE_FALSE); } while((void)0, 0) +#else // DOCTEST_CONFIG_WITH_VARIADIC_MACROS +#define DOCTEST_WARN_MESSAGE(cond, msg) do { DOCTEST_INFO(msg); DOCTEST_ASSERT_IMPLEMENT_2(cond, DT_WARN); } while((void)0, 0) +#define DOCTEST_CHECK_MESSAGE(cond, msg) do { DOCTEST_INFO(msg); DOCTEST_ASSERT_IMPLEMENT_2(cond, DT_CHECK); } while((void)0, 0) +#define DOCTEST_REQUIRE_MESSAGE(cond, msg) do { DOCTEST_INFO(msg); DOCTEST_ASSERT_IMPLEMENT_2(cond, DT_REQUIRE); } while((void)0, 0) +#define DOCTEST_WARN_FALSE_MESSAGE(cond, msg) do { DOCTEST_INFO(msg); DOCTEST_ASSERT_IMPLEMENT_2(cond, DT_WARN_FALSE); } while((void)0, 0) +#define DOCTEST_CHECK_FALSE_MESSAGE(cond, msg) do { DOCTEST_INFO(msg); DOCTEST_ASSERT_IMPLEMENT_2(cond, DT_CHECK_FALSE); } while((void)0, 0) +#define DOCTEST_REQUIRE_FALSE_MESSAGE(cond, msg) do { DOCTEST_INFO(msg); DOCTEST_ASSERT_IMPLEMENT_2(cond, DT_REQUIRE_FALSE); } while((void)0, 0) +#endif // DOCTEST_CONFIG_WITH_VARIADIC_MACROS +// clang-format on + +#define DOCTEST_ASSERT_THROWS(expr, assert_type) \ + do { \ + if(!doctest::detail::getTestsContextState()->no_throw) { \ + doctest::detail::ResultBuilder _DOCTEST_RB(doctest::detail::assertType::assert_type, \ + __FILE__, __LINE__, #expr); \ + try { \ + expr; \ + } catch(...) { _DOCTEST_RB.m_threw = true; } \ + DOCTEST_ASSERT_LOG_AND_REACT(_DOCTEST_RB); \ + } \ + } while((void)0, 0) + +#define DOCTEST_ASSERT_THROWS_AS(expr, as, assert_type) \ + do { \ + if(!doctest::detail::getTestsContextState()->no_throw) { \ + doctest::detail::ResultBuilder _DOCTEST_RB( \ + doctest::detail::assertType::assert_type, __FILE__, __LINE__, #expr, \ + DOCTEST_TOSTR(DOCTEST_HANDLE_BRACED_VA_ARGS(as))); \ + try { \ + expr; \ + } catch(const DOCTEST_HANDLE_BRACED_VA_ARGS(as)&) { \ + _DOCTEST_RB.m_threw = true; \ + _DOCTEST_RB.m_threw_as = true; \ + } catch(...) { _DOCTEST_RB.unexpectedExceptionOccurred(); } \ + DOCTEST_ASSERT_LOG_AND_REACT(_DOCTEST_RB); \ + } \ + } while((void)0, 0) + +#define DOCTEST_ASSERT_NOTHROW(expr, assert_type) \ + do { \ + if(!doctest::detail::getTestsContextState()->no_throw) { \ + doctest::detail::ResultBuilder _DOCTEST_RB(doctest::detail::assertType::assert_type, \ + __FILE__, __LINE__, #expr); \ + try { \ + expr; \ + } catch(...) { _DOCTEST_RB.unexpectedExceptionOccurred(); } \ + DOCTEST_ASSERT_LOG_AND_REACT(_DOCTEST_RB); \ + } \ + } while((void)0, 0) + +#define DOCTEST_WARN_THROWS(expr) DOCTEST_ASSERT_THROWS(expr, DT_WARN_THROWS) +#define DOCTEST_CHECK_THROWS(expr) DOCTEST_ASSERT_THROWS(expr, DT_CHECK_THROWS) +#define DOCTEST_REQUIRE_THROWS(expr) DOCTEST_ASSERT_THROWS(expr, DT_REQUIRE_THROWS) + +// clang-format off +#ifdef DOCTEST_CONFIG_WITH_VARIADIC_MACROS +#define DOCTEST_WARN_THROWS_AS(expr, ...) DOCTEST_ASSERT_THROWS_AS(expr, (__VA_ARGS__), DT_WARN_THROWS_AS) +#define DOCTEST_CHECK_THROWS_AS(expr, ...) DOCTEST_ASSERT_THROWS_AS(expr, (__VA_ARGS__), DT_CHECK_THROWS_AS) +#define DOCTEST_REQUIRE_THROWS_AS(expr, ...) DOCTEST_ASSERT_THROWS_AS(expr, (__VA_ARGS__), DT_REQUIRE_THROWS_AS) +#else // DOCTEST_CONFIG_WITH_VARIADIC_MACROS +#define DOCTEST_WARN_THROWS_AS(expr, ex) DOCTEST_ASSERT_THROWS_AS(expr, ex, DT_WARN_THROWS_AS) +#define DOCTEST_CHECK_THROWS_AS(expr, ex) DOCTEST_ASSERT_THROWS_AS(expr, ex, DT_CHECK_THROWS_AS) +#define DOCTEST_REQUIRE_THROWS_AS(expr, ex) DOCTEST_ASSERT_THROWS_AS(expr, ex, DT_REQUIRE_THROWS_AS) +#endif // DOCTEST_CONFIG_WITH_VARIADIC_MACROS +// clang-format on + +#define DOCTEST_WARN_NOTHROW(expr) DOCTEST_ASSERT_NOTHROW(expr, DT_WARN_NOTHROW) +#define DOCTEST_CHECK_NOTHROW(expr) DOCTEST_ASSERT_NOTHROW(expr, DT_CHECK_NOTHROW) +#define DOCTEST_REQUIRE_NOTHROW(expr) DOCTEST_ASSERT_NOTHROW(expr, DT_REQUIRE_NOTHROW) + +// clang-format off +#define DOCTEST_WARN_THROWS_MESSAGE(expr, msg) do { DOCTEST_INFO(msg); DOCTEST_WARN_THROWS(expr); } while((void)0, 0) +#define DOCTEST_CHECK_THROWS_MESSAGE(expr, msg) do { DOCTEST_INFO(msg); DOCTEST_CHECK_THROWS(expr); } while((void)0, 0) +#define DOCTEST_REQUIRE_THROWS_MESSAGE(expr, msg) do { DOCTEST_INFO(msg); DOCTEST_REQUIRE_THROWS(expr); } while((void)0, 0) +#define DOCTEST_WARN_THROWS_AS_MESSAGE(expr, ex, msg) do { DOCTEST_INFO(msg); DOCTEST_WARN_THROWS_AS(expr, ex); } while((void)0, 0) +#define DOCTEST_CHECK_THROWS_AS_MESSAGE(expr, ex, msg) do { DOCTEST_INFO(msg); DOCTEST_CHECK_THROWS_AS(expr, ex); } while((void)0, 0) +#define DOCTEST_REQUIRE_THROWS_AS_MESSAGE(expr, ex, msg) do { DOCTEST_INFO(msg); DOCTEST_REQUIRE_THROWS_AS(expr, ex); } while((void)0, 0) +#define DOCTEST_WARN_NOTHROW_MESSAGE(expr, msg) do { DOCTEST_INFO(msg); DOCTEST_WARN_NOTHROW(expr); } while((void)0, 0) +#define DOCTEST_CHECK_NOTHROW_MESSAGE(expr, msg) do { DOCTEST_INFO(msg); DOCTEST_CHECK_NOTHROW(expr); } while((void)0, 0) +#define DOCTEST_REQUIRE_NOTHROW_MESSAGE(expr, msg) do { DOCTEST_INFO(msg); DOCTEST_REQUIRE_NOTHROW(expr); } while((void)0, 0) +// clang-format on + +#ifdef DOCTEST_CONFIG_WITH_VARIADIC_MACROS +#define DOCTEST_BINARY_ASSERT(assert_type, expr, comp) \ + do { \ + doctest::detail::ResultBuilder _DOCTEST_RB( \ + doctest::detail::assertType::assert_type, __FILE__, __LINE__, \ + DOCTEST_TOSTR(DOCTEST_HANDLE_BRACED_VA_ARGS(expr))); \ + DOCTEST_WRAP_IN_TRY( \ + _DOCTEST_RB.binary_assert( \ + DOCTEST_HANDLE_BRACED_VA_ARGS(expr))) \ + DOCTEST_ASSERT_LOG_AND_REACT(_DOCTEST_RB); \ + } while((void)0, 0) +#else // DOCTEST_CONFIG_WITH_VARIADIC_MACROS +#define DOCTEST_BINARY_ASSERT(assert_type, lhs, rhs, comp) \ + do { \ + doctest::detail::ResultBuilder _DOCTEST_RB(doctest::detail::assertType::assert_type, \ + __FILE__, __LINE__, #lhs ", " #rhs); \ + DOCTEST_WRAP_IN_TRY( \ + _DOCTEST_RB.binary_assert(lhs, \ + rhs)) \ + DOCTEST_ASSERT_LOG_AND_REACT(_DOCTEST_RB); \ + } while((void)0, 0) +#endif // DOCTEST_CONFIG_WITH_VARIADIC_MACROS + +#define DOCTEST_UNARY_ASSERT(assert_type, expr) \ + do { \ + doctest::detail::ResultBuilder _DOCTEST_RB( \ + doctest::detail::assertType::assert_type, __FILE__, __LINE__, \ + DOCTEST_TOSTR(DOCTEST_HANDLE_BRACED_VA_ARGS(expr))); \ + DOCTEST_WRAP_IN_TRY(_DOCTEST_RB.unary_assert(DOCTEST_HANDLE_BRACED_VA_ARGS(expr))) \ + DOCTEST_ASSERT_LOG_AND_REACT(_DOCTEST_RB); \ + } while((void)0, 0) + +#ifdef DOCTEST_CONFIG_WITH_VARIADIC_MACROS +#define DOCTEST_WARN_EQ(...) DOCTEST_BINARY_ASSERT(DT_WARN_EQ, (__VA_ARGS__), eq) +#define DOCTEST_CHECK_EQ(...) DOCTEST_BINARY_ASSERT(DT_CHECK_EQ, (__VA_ARGS__), eq) +#define DOCTEST_REQUIRE_EQ(...) DOCTEST_BINARY_ASSERT(DT_REQUIRE_EQ, (__VA_ARGS__), eq) +#define DOCTEST_WARN_NE(...) DOCTEST_BINARY_ASSERT(DT_WARN_NE, (__VA_ARGS__), ne) +#define DOCTEST_CHECK_NE(...) DOCTEST_BINARY_ASSERT(DT_CHECK_NE, (__VA_ARGS__), ne) +#define DOCTEST_REQUIRE_NE(...) DOCTEST_BINARY_ASSERT(DT_REQUIRE_NE, (__VA_ARGS__), ne) +#define DOCTEST_WARN_GT(...) DOCTEST_BINARY_ASSERT(DT_WARN_GT, (__VA_ARGS__), gt) +#define DOCTEST_CHECK_GT(...) DOCTEST_BINARY_ASSERT(DT_CHECK_GT, (__VA_ARGS__), gt) +#define DOCTEST_REQUIRE_GT(...) DOCTEST_BINARY_ASSERT(DT_REQUIRE_GT, (__VA_ARGS__), gt) +#define DOCTEST_WARN_LT(...) DOCTEST_BINARY_ASSERT(DT_WARN_LT, (__VA_ARGS__), lt) +#define DOCTEST_CHECK_LT(...) DOCTEST_BINARY_ASSERT(DT_CHECK_LT, (__VA_ARGS__), lt) +#define DOCTEST_REQUIRE_LT(...) DOCTEST_BINARY_ASSERT(DT_REQUIRE_LT, (__VA_ARGS__), lt) +#define DOCTEST_WARN_GE(...) DOCTEST_BINARY_ASSERT(DT_WARN_GE, (__VA_ARGS__), ge) +#define DOCTEST_CHECK_GE(...) DOCTEST_BINARY_ASSERT(DT_CHECK_GE, (__VA_ARGS__), ge) +#define DOCTEST_REQUIRE_GE(...) DOCTEST_BINARY_ASSERT(DT_REQUIRE_GE, (__VA_ARGS__), ge) +#define DOCTEST_WARN_LE(...) DOCTEST_BINARY_ASSERT(DT_WARN_LE, (__VA_ARGS__), le) +#define DOCTEST_CHECK_LE(...) DOCTEST_BINARY_ASSERT(DT_CHECK_LE, (__VA_ARGS__), le) +#define DOCTEST_REQUIRE_LE(...) DOCTEST_BINARY_ASSERT(DT_REQUIRE_LE, (__VA_ARGS__), le) + +#define DOCTEST_WARN_UNARY(...) DOCTEST_UNARY_ASSERT(DT_WARN_UNARY, (__VA_ARGS__)) +#define DOCTEST_CHECK_UNARY(...) DOCTEST_UNARY_ASSERT(DT_CHECK_UNARY, (__VA_ARGS__)) +#define DOCTEST_REQUIRE_UNARY(...) DOCTEST_UNARY_ASSERT(DT_REQUIRE_UNARY, (__VA_ARGS__)) +#define DOCTEST_WARN_UNARY_FALSE(...) DOCTEST_UNARY_ASSERT(DT_WARN_UNARY_FALSE, (__VA_ARGS__)) +#define DOCTEST_CHECK_UNARY_FALSE(...) DOCTEST_UNARY_ASSERT(DT_CHECK_UNARY_FALSE, (__VA_ARGS__)) +#define DOCTEST_REQUIRE_UNARY_FALSE(...) DOCTEST_UNARY_ASSERT(DT_REQUIRE_UNARY_FALSE, (__VA_ARGS__)) +#else // DOCTEST_CONFIG_WITH_VARIADIC_MACROS +#define DOCTEST_WARN_EQ(lhs, rhs) DOCTEST_BINARY_ASSERT(DT_WARN_EQ, lhs, rhs, eq) +#define DOCTEST_CHECK_EQ(lhs, rhs) DOCTEST_BINARY_ASSERT(DT_CHECK_EQ, lhs, rhs, eq) +#define DOCTEST_REQUIRE_EQ(lhs, rhs) DOCTEST_BINARY_ASSERT(DT_REQUIRE_EQ, lhs, rhs, eq) +#define DOCTEST_WARN_NE(lhs, rhs) DOCTEST_BINARY_ASSERT(DT_WARN_NE, lhs, rhs, ne) +#define DOCTEST_CHECK_NE(lhs, rhs) DOCTEST_BINARY_ASSERT(DT_CHECK_NE, lhs, rhs, ne) +#define DOCTEST_REQUIRE_NE(lhs, rhs) DOCTEST_BINARY_ASSERT(DT_REQUIRE_NE, lhs, rhs, ne) +#define DOCTEST_WARN_GT(lhs, rhs) DOCTEST_BINARY_ASSERT(DT_WARN_GT, lhs, rhs, gt) +#define DOCTEST_CHECK_GT(lhs, rhs) DOCTEST_BINARY_ASSERT(DT_CHECK_GT, lhs, rhs, gt) +#define DOCTEST_REQUIRE_GT(lhs, rhs) DOCTEST_BINARY_ASSERT(DT_REQUIRE_GT, lhs, rhs, gt) +#define DOCTEST_WARN_LT(lhs, rhs) DOCTEST_BINARY_ASSERT(DT_WARN_LT, lhs, rhs, lt) +#define DOCTEST_CHECK_LT(lhs, rhs) DOCTEST_BINARY_ASSERT(DT_CHECK_LT, lhs, rhs, lt) +#define DOCTEST_REQUIRE_LT(lhs, rhs) DOCTEST_BINARY_ASSERT(DT_REQUIRE_LT, lhs, rhs, lt) +#define DOCTEST_WARN_GE(lhs, rhs) DOCTEST_BINARY_ASSERT(DT_WARN_GE, lhs, rhs, ge) +#define DOCTEST_CHECK_GE(lhs, rhs) DOCTEST_BINARY_ASSERT(DT_CHECK_GE, lhs, rhs, ge) +#define DOCTEST_REQUIRE_GE(lhs, rhs) DOCTEST_BINARY_ASSERT(DT_REQUIRE_GE, lhs, rhs, ge) +#define DOCTEST_WARN_LE(lhs, rhs) DOCTEST_BINARY_ASSERT(DT_WARN_LE, lhs, rhs, le) +#define DOCTEST_CHECK_LE(lhs, rhs) DOCTEST_BINARY_ASSERT(DT_CHECK_LE, lhs, rhs, le) +#define DOCTEST_REQUIRE_LE(lhs, rhs) DOCTEST_BINARY_ASSERT(DT_REQUIRE_LE, lhs, rhs, le) + +#define DOCTEST_WARN_UNARY(v) DOCTEST_UNARY_ASSERT(DT_WARN_UNARY, v) +#define DOCTEST_CHECK_UNARY(v) DOCTEST_UNARY_ASSERT(DT_CHECK_UNARY, v) +#define DOCTEST_REQUIRE_UNARY(v) DOCTEST_UNARY_ASSERT(DT_REQUIRE_UNARY, v) +#define DOCTEST_WARN_UNARY_FALSE(v) DOCTEST_UNARY_ASSERT(DT_WARN_UNARY_FALSE, v) +#define DOCTEST_CHECK_UNARY_FALSE(v) DOCTEST_UNARY_ASSERT(DT_CHECK_UNARY_FALSE, v) +#define DOCTEST_REQUIRE_UNARY_FALSE(v) DOCTEST_UNARY_ASSERT(DT_REQUIRE_UNARY_FALSE, v) +#endif // DOCTEST_CONFIG_WITH_VARIADIC_MACROS + +#ifndef DOCTEST_CONFIG_SUPER_FAST_ASSERTS + +#ifdef DOCTEST_CONFIG_WITH_VARIADIC_MACROS +#define DOCTEST_FAST_BINARY_ASSERT(assert_type, expr, comparison) \ + do { \ + int _DOCTEST_FAST_RES = doctest::detail::fast_binary_assert< \ + doctest::detail::binaryAssertComparison::comparison>( \ + doctest::detail::assertType::assert_type, __FILE__, __LINE__, \ + DOCTEST_TOSTR(DOCTEST_HANDLE_BRACED_VA_ARGS(expr)), \ + DOCTEST_HANDLE_BRACED_VA_ARGS(expr)); \ + if(_DOCTEST_FAST_RES & doctest::detail::assertAction::dbgbreak) \ + DOCTEST_BREAK_INTO_DEBUGGER(); \ + doctest::detail::fastAssertThrowIfFlagSet(_DOCTEST_FAST_RES); \ + } while((void)0, 0) +#else // DOCTEST_CONFIG_WITH_VARIADIC_MACROS +#define DOCTEST_FAST_BINARY_ASSERT(assert_type, lhs, rhs, comparison) \ + do { \ + int _DOCTEST_FAST_RES = doctest::detail::fast_binary_assert< \ + doctest::detail::binaryAssertComparison::comparison>( \ + doctest::detail::assertType::assert_type, __FILE__, __LINE__, #lhs ", " #rhs, lhs, \ + rhs); \ + if(_DOCTEST_FAST_RES & doctest::detail::assertAction::dbgbreak) \ + DOCTEST_BREAK_INTO_DEBUGGER(); \ + doctest::detail::fastAssertThrowIfFlagSet(_DOCTEST_FAST_RES); \ + } while((void)0, 0) +#endif // DOCTEST_CONFIG_WITH_VARIADIC_MACROS + +#define DOCTEST_FAST_UNARY_ASSERT(assert_type, expr) \ + do { \ + int _DOCTEST_FAST_RES = doctest::detail::fast_unary_assert( \ + doctest::detail::assertType::assert_type, __FILE__, __LINE__, \ + DOCTEST_TOSTR(DOCTEST_HANDLE_BRACED_VA_ARGS(expr)), \ + DOCTEST_HANDLE_BRACED_VA_ARGS(expr)); \ + if(_DOCTEST_FAST_RES & doctest::detail::assertAction::dbgbreak) \ + DOCTEST_BREAK_INTO_DEBUGGER(); \ + doctest::detail::fastAssertThrowIfFlagSet(_DOCTEST_FAST_RES); \ + } while((void)0, 0) + +#else // DOCTEST_CONFIG_SUPER_FAST_ASSERTS + +#ifdef DOCTEST_CONFIG_WITH_VARIADIC_MACROS +#define DOCTEST_FAST_BINARY_ASSERT(assert_type, expr, comparison) \ + doctest::detail::fast_binary_assert( \ + doctest::detail::assertType::assert_type, __FILE__, __LINE__, \ + DOCTEST_TOSTR(DOCTEST_HANDLE_BRACED_VA_ARGS(expr)), \ + DOCTEST_HANDLE_BRACED_VA_ARGS(expr)) +#else // DOCTEST_CONFIG_WITH_VARIADIC_MACROS +#define DOCTEST_FAST_BINARY_ASSERT(assert_type, lhs, rhs, comparison) \ + doctest::detail::fast_binary_assert( \ + doctest::detail::assertType::assert_type, __FILE__, __LINE__, #lhs ", " #rhs, lhs, \ + rhs) +#endif // DOCTEST_CONFIG_WITH_VARIADIC_MACROS + +#define DOCTEST_FAST_UNARY_ASSERT(assert_type, expr) \ + doctest::detail::fast_unary_assert(doctest::detail::assertType::assert_type, __FILE__, \ + __LINE__, \ + DOCTEST_TOSTR(DOCTEST_HANDLE_BRACED_VA_ARGS(expr)), \ + DOCTEST_HANDLE_BRACED_VA_ARGS(expr)) + +#endif // DOCTEST_CONFIG_SUPER_FAST_ASSERTS + +// clang-format off +#ifdef DOCTEST_CONFIG_WITH_VARIADIC_MACROS +#define DOCTEST_FAST_WARN_EQ(...) DOCTEST_FAST_BINARY_ASSERT(DT_FAST_WARN_EQ, (__VA_ARGS__), eq) +#define DOCTEST_FAST_CHECK_EQ(...) DOCTEST_FAST_BINARY_ASSERT(DT_FAST_CHECK_EQ, (__VA_ARGS__), eq) +#define DOCTEST_FAST_REQUIRE_EQ(...) DOCTEST_FAST_BINARY_ASSERT(DT_FAST_REQUIRE_EQ, (__VA_ARGS__), eq) +#define DOCTEST_FAST_WARN_NE(...) DOCTEST_FAST_BINARY_ASSERT(DT_FAST_WARN_NE, (__VA_ARGS__), ne) +#define DOCTEST_FAST_CHECK_NE(...) DOCTEST_FAST_BINARY_ASSERT(DT_FAST_CHECK_NE, (__VA_ARGS__), ne) +#define DOCTEST_FAST_REQUIRE_NE(...) DOCTEST_FAST_BINARY_ASSERT(DT_FAST_REQUIRE_NE, (__VA_ARGS__), ne) +#define DOCTEST_FAST_WARN_GT(...) DOCTEST_FAST_BINARY_ASSERT(DT_FAST_WARN_GT, (__VA_ARGS__), gt) +#define DOCTEST_FAST_CHECK_GT(...) DOCTEST_FAST_BINARY_ASSERT(DT_FAST_CHECK_GT, (__VA_ARGS__), gt) +#define DOCTEST_FAST_REQUIRE_GT(...) DOCTEST_FAST_BINARY_ASSERT(DT_FAST_REQUIRE_GT, (__VA_ARGS__), gt) +#define DOCTEST_FAST_WARN_LT(...) DOCTEST_FAST_BINARY_ASSERT(DT_FAST_WARN_LT, (__VA_ARGS__), lt) +#define DOCTEST_FAST_CHECK_LT(...) DOCTEST_FAST_BINARY_ASSERT(DT_FAST_CHECK_LT, (__VA_ARGS__), lt) +#define DOCTEST_FAST_REQUIRE_LT(...) DOCTEST_FAST_BINARY_ASSERT(DT_FAST_REQUIRE_LT, (__VA_ARGS__), lt) +#define DOCTEST_FAST_WARN_GE(...) DOCTEST_FAST_BINARY_ASSERT(DT_FAST_WARN_GE, (__VA_ARGS__), ge) +#define DOCTEST_FAST_CHECK_GE(...) DOCTEST_FAST_BINARY_ASSERT(DT_FAST_CHECK_GE, (__VA_ARGS__), ge) +#define DOCTEST_FAST_REQUIRE_GE(...) DOCTEST_FAST_BINARY_ASSERT(DT_FAST_REQUIRE_GE, (__VA_ARGS__), ge) +#define DOCTEST_FAST_WARN_LE(...) DOCTEST_FAST_BINARY_ASSERT(DT_FAST_WARN_LE, (__VA_ARGS__), le) +#define DOCTEST_FAST_CHECK_LE(...) DOCTEST_FAST_BINARY_ASSERT(DT_FAST_CHECK_LE, (__VA_ARGS__), le) +#define DOCTEST_FAST_REQUIRE_LE(...) DOCTEST_FAST_BINARY_ASSERT(DT_FAST_REQUIRE_LE, (__VA_ARGS__), le) + +#define DOCTEST_FAST_WARN_UNARY(...) DOCTEST_FAST_UNARY_ASSERT(DT_FAST_WARN_UNARY, (__VA_ARGS__)) +#define DOCTEST_FAST_CHECK_UNARY(...) DOCTEST_FAST_UNARY_ASSERT(DT_FAST_CHECK_UNARY, (__VA_ARGS__)) +#define DOCTEST_FAST_REQUIRE_UNARY(...) DOCTEST_FAST_UNARY_ASSERT(DT_FAST_REQUIRE_UNARY, (__VA_ARGS__)) +#define DOCTEST_FAST_WARN_UNARY_FALSE(...) DOCTEST_FAST_UNARY_ASSERT(DT_FAST_WARN_UNARY_FALSE, (__VA_ARGS__)) +#define DOCTEST_FAST_CHECK_UNARY_FALSE(...) DOCTEST_FAST_UNARY_ASSERT(DT_FAST_CHECK_UNARY_FALSE, (__VA_ARGS__)) +#define DOCTEST_FAST_REQUIRE_UNARY_FALSE(...) DOCTEST_FAST_UNARY_ASSERT(DT_FAST_REQUIRE_UNARY_FALSE, (__VA_ARGS__)) +#else // DOCTEST_CONFIG_WITH_VARIADIC_MACROS +#define DOCTEST_FAST_WARN_EQ(l, r) DOCTEST_FAST_BINARY_ASSERT(DT_FAST_WARN_EQ, l, r, eq) +#define DOCTEST_FAST_CHECK_EQ(l, r) DOCTEST_FAST_BINARY_ASSERT(DT_FAST_CHECK_EQ, l, r, eq) +#define DOCTEST_FAST_REQUIRE_EQ(l, r) DOCTEST_FAST_BINARY_ASSERT(DT_FAST_REQUIRE_EQ, l, r, eq) +#define DOCTEST_FAST_WARN_NE(l, r) DOCTEST_FAST_BINARY_ASSERT(DT_FAST_WARN_NE, l, r, ne) +#define DOCTEST_FAST_CHECK_NE(l, r) DOCTEST_FAST_BINARY_ASSERT(DT_FAST_CHECK_NE, l, r, ne) +#define DOCTEST_FAST_REQUIRE_NE(l, r) DOCTEST_FAST_BINARY_ASSERT(DT_FAST_REQUIRE_NE, l, r, ne) +#define DOCTEST_FAST_WARN_GT(l, r) DOCTEST_FAST_BINARY_ASSERT(DT_FAST_WARN_GT, l, r, gt) +#define DOCTEST_FAST_CHECK_GT(l, r) DOCTEST_FAST_BINARY_ASSERT(DT_FAST_CHECK_GT, l, r, gt) +#define DOCTEST_FAST_REQUIRE_GT(l, r) DOCTEST_FAST_BINARY_ASSERT(DT_FAST_REQUIRE_GT, l, r, gt) +#define DOCTEST_FAST_WARN_LT(l, r) DOCTEST_FAST_BINARY_ASSERT(DT_FAST_WARN_LT, l, r, lt) +#define DOCTEST_FAST_CHECK_LT(l, r) DOCTEST_FAST_BINARY_ASSERT(DT_FAST_CHECK_LT, l, r, lt) +#define DOCTEST_FAST_REQUIRE_LT(l, r) DOCTEST_FAST_BINARY_ASSERT(DT_FAST_REQUIRE_LT, l, r, lt) +#define DOCTEST_FAST_WARN_GE(l, r) DOCTEST_FAST_BINARY_ASSERT(DT_FAST_WARN_GE, l, r, ge) +#define DOCTEST_FAST_CHECK_GE(l, r) DOCTEST_FAST_BINARY_ASSERT(DT_FAST_CHECK_GE, l, r, ge) +#define DOCTEST_FAST_REQUIRE_GE(l, r) DOCTEST_FAST_BINARY_ASSERT(DT_FAST_REQUIRE_GE, l, r, ge) +#define DOCTEST_FAST_WARN_LE(l, r) DOCTEST_FAST_BINARY_ASSERT(DT_FAST_WARN_LE, l, r, le) +#define DOCTEST_FAST_CHECK_LE(l, r) DOCTEST_FAST_BINARY_ASSERT(DT_FAST_CHECK_LE, l, r, le) +#define DOCTEST_FAST_REQUIRE_LE(l, r) DOCTEST_FAST_BINARY_ASSERT(DT_FAST_REQUIRE_LE, l, r, le) + +#define DOCTEST_FAST_WARN_UNARY(v) DOCTEST_FAST_UNARY_ASSERT(DT_FAST_WARN_UNARY, v) +#define DOCTEST_FAST_CHECK_UNARY(v) DOCTEST_FAST_UNARY_ASSERT(DT_FAST_CHECK_UNARY, v) +#define DOCTEST_FAST_REQUIRE_UNARY(v) DOCTEST_FAST_UNARY_ASSERT(DT_FAST_REQUIRE_UNARY, v) +#define DOCTEST_FAST_WARN_UNARY_FALSE(v) DOCTEST_FAST_UNARY_ASSERT(DT_FAST_WARN_UNARY_FALSE, v) +#define DOCTEST_FAST_CHECK_UNARY_FALSE(v) DOCTEST_FAST_UNARY_ASSERT(DT_FAST_CHECK_UNARY_FALSE, v) +#define DOCTEST_FAST_REQUIRE_UNARY_FALSE(v) DOCTEST_FAST_UNARY_ASSERT(DT_FAST_REQUIRE_UNARY_FALSE, v) +#endif // DOCTEST_CONFIG_WITH_VARIADIC_MACROS +// clang-format on + +#ifdef DOCTEST_CONFIG_NO_EXCEPTIONS + +#undef DOCTEST_WARN_THROWS +#undef DOCTEST_CHECK_THROWS +#undef DOCTEST_REQUIRE_THROWS +#undef DOCTEST_WARN_THROWS_AS +#undef DOCTEST_CHECK_THROWS_AS +#undef DOCTEST_REQUIRE_THROWS_AS +#undef DOCTEST_WARN_NOTHROW +#undef DOCTEST_CHECK_NOTHROW +#undef DOCTEST_REQUIRE_NOTHROW + +#undef DOCTEST_WARN_THROWS_MESSAGE +#undef DOCTEST_CHECK_THROWS_MESSAGE +#undef DOCTEST_REQUIRE_THROWS_MESSAGE +#undef DOCTEST_WARN_THROWS_AS_MESSAGE +#undef DOCTEST_CHECK_THROWS_AS_MESSAGE +#undef DOCTEST_REQUIRE_THROWS_AS_MESSAGE +#undef DOCTEST_WARN_NOTHROW_MESSAGE +#undef DOCTEST_CHECK_NOTHROW_MESSAGE +#undef DOCTEST_REQUIRE_NOTHROW_MESSAGE + +#ifdef DOCTEST_CONFIG_NO_EXCEPTIONS_BUT_WITH_ALL_ASSERTS + +#define DOCTEST_WARN_THROWS(expr) ((void)0) +#define DOCTEST_CHECK_THROWS(expr) ((void)0) +#define DOCTEST_REQUIRE_THROWS(expr) ((void)0) +#ifdef DOCTEST_CONFIG_WITH_VARIADIC_MACROS +#define DOCTEST_WARN_THROWS_AS(expr, ...) ((void)0) +#define DOCTEST_CHECK_THROWS_AS(expr, ...) ((void)0) +#define DOCTEST_REQUIRE_THROWS_AS(expr, ...) ((void)0) +#else // DOCTEST_CONFIG_WITH_VARIADIC_MACROS +#define DOCTEST_WARN_THROWS_AS(expr, ex) ((void)0) +#define DOCTEST_CHECK_THROWS_AS(expr, ex) ((void)0) +#define DOCTEST_REQUIRE_THROWS_AS(expr, ex) ((void)0) +#endif // DOCTEST_CONFIG_WITH_VARIADIC_MACROS +#define DOCTEST_WARN_NOTHROW(expr) ((void)0) +#define DOCTEST_CHECK_NOTHROW(expr) ((void)0) +#define DOCTEST_REQUIRE_NOTHROW(expr) ((void)0) + +#define DOCTEST_WARN_THROWS_MESSAGE(expr, msg) ((void)0) +#define DOCTEST_CHECK_THROWS_MESSAGE(expr, msg) ((void)0) +#define DOCTEST_REQUIRE_THROWS_MESSAGE(expr, msg) ((void)0) +#define DOCTEST_WARN_THROWS_AS_MESSAGE(expr, ex, msg) ((void)0) +#define DOCTEST_CHECK_THROWS_AS_MESSAGE(expr, ex, msg) ((void)0) +#define DOCTEST_REQUIRE_THROWS_AS_MESSAGE(expr, ex, msg) ((void)0) +#define DOCTEST_WARN_NOTHROW_MESSAGE(expr, msg) ((void)0) +#define DOCTEST_CHECK_NOTHROW_MESSAGE(expr, msg) ((void)0) +#define DOCTEST_REQUIRE_NOTHROW_MESSAGE(expr, msg) ((void)0) + +#else // DOCTEST_CONFIG_NO_EXCEPTIONS_BUT_WITH_ALL_ASSERTS + +#undef DOCTEST_REQUIRE +#undef DOCTEST_REQUIRE_FALSE +#undef DOCTEST_REQUIRE_MESSAGE +#undef DOCTEST_REQUIRE_FALSE_MESSAGE +#undef DOCTEST_REQUIRE_EQ +#undef DOCTEST_REQUIRE_NE +#undef DOCTEST_REQUIRE_GT +#undef DOCTEST_REQUIRE_LT +#undef DOCTEST_REQUIRE_GE +#undef DOCTEST_REQUIRE_LE +#undef DOCTEST_REQUIRE_UNARY +#undef DOCTEST_REQUIRE_UNARY_FALSE +#undef DOCTEST_FAST_REQUIRE_EQ +#undef DOCTEST_FAST_REQUIRE_NE +#undef DOCTEST_FAST_REQUIRE_GT +#undef DOCTEST_FAST_REQUIRE_LT +#undef DOCTEST_FAST_REQUIRE_GE +#undef DOCTEST_FAST_REQUIRE_LE +#undef DOCTEST_FAST_REQUIRE_UNARY +#undef DOCTEST_FAST_REQUIRE_UNARY_FALSE + +#endif // DOCTEST_CONFIG_NO_EXCEPTIONS_BUT_WITH_ALL_ASSERTS + +#endif // DOCTEST_CONFIG_NO_EXCEPTIONS + +// ================================================================================================= +// == WHAT FOLLOWS IS VERSIONS OF THE MACROS THAT DO NOT DO ANY REGISTERING! == +// == THIS CAN BE ENABLED BY DEFINING DOCTEST_CONFIG_DISABLE GLOBALLY! == +// ================================================================================================= +#else // DOCTEST_CONFIG_DISABLE + +#define DOCTEST_IMPLEMENT_FIXTURE(der, base, func, name) \ + namespace \ + { \ + template \ + struct der : base \ + { void f(); }; \ + } \ + template \ + inline void der::f() + +#define DOCTEST_CREATE_AND_REGISTER_FUNCTION(f, name) \ + template \ + static inline void f() + +// for registering tests +#define DOCTEST_TEST_CASE(name) \ + DOCTEST_CREATE_AND_REGISTER_FUNCTION(DOCTEST_ANONYMOUS(_DOCTEST_ANON_FUNC_), name) + +// for registering tests with a fixture +#define DOCTEST_TEST_CASE_FIXTURE(x, name) \ + DOCTEST_IMPLEMENT_FIXTURE(DOCTEST_ANONYMOUS(_DOCTEST_ANON_CLASS_), x, \ + DOCTEST_ANONYMOUS(_DOCTEST_ANON_FUNC_), name) + +// for converting types to strings without the header and demangling +#ifdef DOCTEST_CONFIG_WITH_VARIADIC_MACROS +#define DOCTEST_TYPE_TO_STRING(...) typedef int DOCTEST_ANONYMOUS(_DOCTEST_ANON_FOR_SEMICOLON_) +#define DOCTEST_TYPE_TO_STRING_IMPL(...) +#else // DOCTEST_CONFIG_WITH_VARIADIC_MACROS +#define DOCTEST_TYPE_TO_STRING(x) typedef int DOCTEST_ANONYMOUS(_DOCTEST_ANON_FOR_SEMICOLON_) +#define DOCTEST_TYPE_TO_STRING_IMPL(x) +#endif // DOCTEST_CONFIG_WITH_VARIADIC_MACROS + +// for typed tests +#define DOCTEST_TEST_CASE_TEMPLATE(name, type, types) \ + template \ + inline void DOCTEST_ANONYMOUS(_DOCTEST_ANON_TMP_)() + +#define DOCTEST_TEST_CASE_TEMPLATE_DEFINE(name, type, id) \ + template \ + inline void DOCTEST_ANONYMOUS(_DOCTEST_ANON_TMP_)() + +#define DOCTEST_TEST_CASE_TEMPLATE_INSTANTIATE(id, types) \ + typedef int DOCTEST_ANONYMOUS(_DOCTEST_ANON_FOR_SEMICOLON_) + +// for subcases +#define DOCTEST_SUBCASE(name) + +// for a testsuite block +#define DOCTEST_TEST_SUITE(name) namespace + +// for starting a testsuite block +#define DOCTEST_TEST_SUITE_BEGIN(name) typedef int DOCTEST_ANONYMOUS(_DOCTEST_ANON_FOR_SEMICOLON_) + +// for ending a testsuite block +#define DOCTEST_TEST_SUITE_END typedef int DOCTEST_ANONYMOUS(_DOCTEST_ANON_FOR_SEMICOLON_) + +#define DOCTEST_REGISTER_EXCEPTION_TRANSLATOR(signature) \ + template \ + static inline doctest::String DOCTEST_ANONYMOUS(_DOCTEST_ANON_TRANSLATOR_)(signature) + +#define DOCTEST_INFO(x) ((void)0) +#define DOCTEST_CAPTURE(x) ((void)0) +#define DOCTEST_ADD_MESSAGE_AT(file, line, x) ((void)0) +#define DOCTEST_ADD_FAIL_CHECK_AT(file, line, x) ((void)0) +#define DOCTEST_ADD_FAIL_AT(file, line, x) ((void)0) +#define DOCTEST_MESSAGE(x) ((void)0) +#define DOCTEST_FAIL_CHECK(x) ((void)0) +#define DOCTEST_FAIL(x) ((void)0) + +#ifdef DOCTEST_CONFIG_WITH_VARIADIC_MACROS +#define DOCTEST_WARN(...) ((void)0) +#define DOCTEST_CHECK(...) ((void)0) +#define DOCTEST_REQUIRE(...) ((void)0) +#define DOCTEST_WARN_FALSE(...) ((void)0) +#define DOCTEST_CHECK_FALSE(...) ((void)0) +#define DOCTEST_REQUIRE_FALSE(...) ((void)0) +#else // DOCTEST_CONFIG_WITH_VARIADIC_MACROS +#define DOCTEST_WARN(expr) ((void)0) +#define DOCTEST_CHECK(expr) ((void)0) +#define DOCTEST_REQUIRE(expr) ((void)0) +#define DOCTEST_WARN_FALSE(expr) ((void)0) +#define DOCTEST_CHECK_FALSE(expr) ((void)0) +#define DOCTEST_REQUIRE_FALSE(expr) ((void)0) +#endif // DOCTEST_CONFIG_WITH_VARIADIC_MACROS + +#define DOCTEST_WARN_MESSAGE(cond, msg) ((void)0) +#define DOCTEST_CHECK_MESSAGE(cond, msg) ((void)0) +#define DOCTEST_REQUIRE_MESSAGE(cond, msg) ((void)0) +#define DOCTEST_WARN_FALSE_MESSAGE(cond, msg) ((void)0) +#define DOCTEST_CHECK_FALSE_MESSAGE(cond, msg) ((void)0) +#define DOCTEST_REQUIRE_FALSE_MESSAGE(cond, msg) ((void)0) + +#define DOCTEST_WARN_THROWS(expr) ((void)0) +#define DOCTEST_CHECK_THROWS(expr) ((void)0) +#define DOCTEST_REQUIRE_THROWS(expr) ((void)0) +#ifdef DOCTEST_CONFIG_WITH_VARIADIC_MACROS +#define DOCTEST_WARN_THROWS_AS(expr, ...) ((void)0) +#define DOCTEST_CHECK_THROWS_AS(expr, ...) ((void)0) +#define DOCTEST_REQUIRE_THROWS_AS(expr, ...) ((void)0) +#else // DOCTEST_CONFIG_WITH_VARIADIC_MACROS +#define DOCTEST_WARN_THROWS_AS(expr, ex) ((void)0) +#define DOCTEST_CHECK_THROWS_AS(expr, ex) ((void)0) +#define DOCTEST_REQUIRE_THROWS_AS(expr, ex) ((void)0) +#endif // DOCTEST_CONFIG_WITH_VARIADIC_MACROS +#define DOCTEST_WARN_NOTHROW(expr) ((void)0) +#define DOCTEST_CHECK_NOTHROW(expr) ((void)0) +#define DOCTEST_REQUIRE_NOTHROW(expr) ((void)0) + +#define DOCTEST_WARN_THROWS_MESSAGE(expr, msg) ((void)0) +#define DOCTEST_CHECK_THROWS_MESSAGE(expr, msg) ((void)0) +#define DOCTEST_REQUIRE_THROWS_MESSAGE(expr, msg) ((void)0) +#define DOCTEST_WARN_THROWS_AS_MESSAGE(expr, ex, msg) ((void)0) +#define DOCTEST_CHECK_THROWS_AS_MESSAGE(expr, ex, msg) ((void)0) +#define DOCTEST_REQUIRE_THROWS_AS_MESSAGE(expr, ex, msg) ((void)0) +#define DOCTEST_WARN_NOTHROW_MESSAGE(expr, msg) ((void)0) +#define DOCTEST_CHECK_NOTHROW_MESSAGE(expr, msg) ((void)0) +#define DOCTEST_REQUIRE_NOTHROW_MESSAGE(expr, msg) ((void)0) + +#ifdef DOCTEST_CONFIG_WITH_VARIADIC_MACROS + +#define DOCTEST_WARN_EQ(...) ((void)0) +#define DOCTEST_CHECK_EQ(...) ((void)0) +#define DOCTEST_REQUIRE_EQ(...) ((void)0) +#define DOCTEST_WARN_NE(...) ((void)0) +#define DOCTEST_CHECK_NE(...) ((void)0) +#define DOCTEST_REQUIRE_NE(...) ((void)0) +#define DOCTEST_WARN_GT(...) ((void)0) +#define DOCTEST_CHECK_GT(...) ((void)0) +#define DOCTEST_REQUIRE_GT(...) ((void)0) +#define DOCTEST_WARN_LT(...) ((void)0) +#define DOCTEST_CHECK_LT(...) ((void)0) +#define DOCTEST_REQUIRE_LT(...) ((void)0) +#define DOCTEST_WARN_GE(...) ((void)0) +#define DOCTEST_CHECK_GE(...) ((void)0) +#define DOCTEST_REQUIRE_GE(...) ((void)0) +#define DOCTEST_WARN_LE(...) ((void)0) +#define DOCTEST_CHECK_LE(...) ((void)0) +#define DOCTEST_REQUIRE_LE(...) ((void)0) + +#define DOCTEST_WARN_UNARY(...) ((void)0) +#define DOCTEST_CHECK_UNARY(...) ((void)0) +#define DOCTEST_REQUIRE_UNARY(...) ((void)0) +#define DOCTEST_WARN_UNARY_FALSE(...) ((void)0) +#define DOCTEST_CHECK_UNARY_FALSE(...) ((void)0) +#define DOCTEST_REQUIRE_UNARY_FALSE(...) ((void)0) + +#define DOCTEST_FAST_WARN_EQ(...) ((void)0) +#define DOCTEST_FAST_CHECK_EQ(...) ((void)0) +#define DOCTEST_FAST_REQUIRE_EQ(...) ((void)0) +#define DOCTEST_FAST_WARN_NE(...) ((void)0) +#define DOCTEST_FAST_CHECK_NE(...) ((void)0) +#define DOCTEST_FAST_REQUIRE_NE(...) ((void)0) +#define DOCTEST_FAST_WARN_GT(...) ((void)0) +#define DOCTEST_FAST_CHECK_GT(...) ((void)0) +#define DOCTEST_FAST_REQUIRE_GT(...) ((void)0) +#define DOCTEST_FAST_WARN_LT(...) ((void)0) +#define DOCTEST_FAST_CHECK_LT(...) ((void)0) +#define DOCTEST_FAST_REQUIRE_LT(...) ((void)0) +#define DOCTEST_FAST_WARN_GE(...) ((void)0) +#define DOCTEST_FAST_CHECK_GE(...) ((void)0) +#define DOCTEST_FAST_REQUIRE_GE(...) ((void)0) +#define DOCTEST_FAST_WARN_LE(...) ((void)0) +#define DOCTEST_FAST_CHECK_LE(...) ((void)0) +#define DOCTEST_FAST_REQUIRE_LE(...) ((void)0) + +#define DOCTEST_FAST_WARN_UNARY(...) ((void)0) +#define DOCTEST_FAST_CHECK_UNARY(...) ((void)0) +#define DOCTEST_FAST_REQUIRE_UNARY(...) ((void)0) +#define DOCTEST_FAST_WARN_UNARY_FALSE(...) ((void)0) +#define DOCTEST_FAST_CHECK_UNARY_FALSE(...) ((void)0) +#define DOCTEST_FAST_REQUIRE_UNARY_FALSE(...) ((void)0) + +#else // DOCTEST_CONFIG_WITH_VARIADIC_MACROS + +#define DOCTEST_WARN_EQ(lhs, rhs) ((void)0) +#define DOCTEST_CHECK_EQ(lhs, rhs) ((void)0) +#define DOCTEST_REQUIRE_EQ(lhs, rhs) ((void)0) +#define DOCTEST_WARN_NE(lhs, rhs) ((void)0) +#define DOCTEST_CHECK_NE(lhs, rhs) ((void)0) +#define DOCTEST_REQUIRE_NE(lhs, rhs) ((void)0) +#define DOCTEST_WARN_GT(lhs, rhs) ((void)0) +#define DOCTEST_CHECK_GT(lhs, rhs) ((void)0) +#define DOCTEST_REQUIRE_GT(lhs, rhs) ((void)0) +#define DOCTEST_WARN_LT(lhs, rhs) ((void)0) +#define DOCTEST_CHECK_LT(lhs, rhs) ((void)0) +#define DOCTEST_REQUIRE_LT(lhs, rhs) ((void)0) +#define DOCTEST_WARN_GE(lhs, rhs) ((void)0) +#define DOCTEST_CHECK_GE(lhs, rhs) ((void)0) +#define DOCTEST_REQUIRE_GE(lhs, rhs) ((void)0) +#define DOCTEST_WARN_LE(lhs, rhs) ((void)0) +#define DOCTEST_CHECK_LE(lhs, rhs) ((void)0) +#define DOCTEST_REQUIRE_LE(lhs, rhs) ((void)0) + +#define DOCTEST_WARN_UNARY(val) ((void)0) +#define DOCTEST_CHECK_UNARY(val) ((void)0) +#define DOCTEST_REQUIRE_UNARY(val) ((void)0) +#define DOCTEST_WARN_UNARY_FALSE(val) ((void)0) +#define DOCTEST_CHECK_UNARY_FALSE(val) ((void)0) +#define DOCTEST_REQUIRE_UNARY_FALSE(val) ((void)0) + +#define DOCTEST_FAST_WARN_EQ(lhs, rhs) ((void)0) +#define DOCTEST_FAST_CHECK_EQ(lhs, rhs) ((void)0) +#define DOCTEST_FAST_REQUIRE_EQ(lhs, rhs) ((void)0) +#define DOCTEST_FAST_WARN_NE(lhs, rhs) ((void)0) +#define DOCTEST_FAST_CHECK_NE(lhs, rhs) ((void)0) +#define DOCTEST_FAST_REQUIRE_NE(lhs, rhs) ((void)0) +#define DOCTEST_FAST_WARN_GT(lhs, rhs) ((void)0) +#define DOCTEST_FAST_CHECK_GT(lhs, rhs) ((void)0) +#define DOCTEST_FAST_REQUIRE_GT(lhs, rhs) ((void)0) +#define DOCTEST_FAST_WARN_LT(lhs, rhs) ((void)0) +#define DOCTEST_FAST_CHECK_LT(lhs, rhs) ((void)0) +#define DOCTEST_FAST_REQUIRE_LT(lhs, rhs) ((void)0) +#define DOCTEST_FAST_WARN_GE(lhs, rhs) ((void)0) +#define DOCTEST_FAST_CHECK_GE(lhs, rhs) ((void)0) +#define DOCTEST_FAST_REQUIRE_GE(lhs, rhs) ((void)0) +#define DOCTEST_FAST_WARN_LE(lhs, rhs) ((void)0) +#define DOCTEST_FAST_CHECK_LE(lhs, rhs) ((void)0) +#define DOCTEST_FAST_REQUIRE_LE(lhs, rhs) ((void)0) + +#define DOCTEST_FAST_WARN_UNARY(val) ((void)0) +#define DOCTEST_FAST_CHECK_UNARY(val) ((void)0) +#define DOCTEST_FAST_REQUIRE_UNARY(val) ((void)0) +#define DOCTEST_FAST_WARN_UNARY_FALSE(val) ((void)0) +#define DOCTEST_FAST_CHECK_UNARY_FALSE(val) ((void)0) +#define DOCTEST_FAST_REQUIRE_UNARY_FALSE(val) ((void)0) + +#endif // DOCTEST_CONFIG_WITH_VARIADIC_MACROS + +#endif // DOCTEST_CONFIG_DISABLE + +// BDD style macros +// clang-format off +#define DOCTEST_SCENARIO(name) TEST_CASE(" Scenario: " name) +#ifdef DOCTEST_CONFIG_WITH_VARIADIC_MACROS +#define DOCTEST_SCENARIO_TEMPLATE(name, T, ...) TEST_CASE_TEMPLATE(" Scenario: " name, T, __VA_ARGS__) +#else // DOCTEST_CONFIG_WITH_VARIADIC_MACROS +#define DOCTEST_SCENARIO_TEMPLATE(name, T, types) TEST_CASE_TEMPLATE(" Scenario: " name, T, types) +#endif // DOCTEST_CONFIG_WITH_VARIADIC_MACROS +#define DOCTEST_SCENARIO_TEMPLATE_DEFINE(name, T, id) DOCTEST_TEST_CASE_TEMPLATE_DEFINE(" Scenario: " name, T, id) + +#define DOCTEST_GIVEN(name) SUBCASE(" Given: " name) +#define DOCTEST_WHEN(name) SUBCASE(" When: " name) +#define DOCTEST_AND_WHEN(name) SUBCASE("And when: " name) +#define DOCTEST_THEN(name) SUBCASE(" Then: " name) +#define DOCTEST_AND_THEN(name) SUBCASE(" And: " name) +// clang-format on + +// == SHORT VERSIONS OF THE MACROS +#if !defined(DOCTEST_CONFIG_NO_SHORT_MACRO_NAMES) + +#define TEST_CASE DOCTEST_TEST_CASE +#define TEST_CASE_FIXTURE DOCTEST_TEST_CASE_FIXTURE +#define TYPE_TO_STRING DOCTEST_TYPE_TO_STRING +#define TEST_CASE_TEMPLATE DOCTEST_TEST_CASE_TEMPLATE +#define TEST_CASE_TEMPLATE_DEFINE DOCTEST_TEST_CASE_TEMPLATE_DEFINE +#define TEST_CASE_TEMPLATE_INSTANTIATE DOCTEST_TEST_CASE_TEMPLATE_INSTANTIATE +#define SUBCASE DOCTEST_SUBCASE +#define TEST_SUITE DOCTEST_TEST_SUITE +#define TEST_SUITE_BEGIN DOCTEST_TEST_SUITE_BEGIN +#define TEST_SUITE_END DOCTEST_TEST_SUITE_END +#define REGISTER_EXCEPTION_TRANSLATOR DOCTEST_REGISTER_EXCEPTION_TRANSLATOR +#define INFO DOCTEST_INFO +#define CAPTURE DOCTEST_CAPTURE +#define ADD_MESSAGE_AT DOCTEST_ADD_MESSAGE_AT +#define ADD_FAIL_CHECK_AT DOCTEST_ADD_FAIL_CHECK_AT +#define ADD_FAIL_AT DOCTEST_ADD_FAIL_AT +#define MESSAGE DOCTEST_MESSAGE +#define FAIL_CHECK DOCTEST_FAIL_CHECK +#define FAIL DOCTEST_FAIL +#define TO_LVALUE DOCTEST_TO_LVALUE + +#define WARN DOCTEST_WARN +#define WARN_FALSE DOCTEST_WARN_FALSE +#define WARN_THROWS DOCTEST_WARN_THROWS +#define WARN_THROWS_AS DOCTEST_WARN_THROWS_AS +#define WARN_NOTHROW DOCTEST_WARN_NOTHROW +#define CHECK DOCTEST_CHECK +#define CHECK_FALSE DOCTEST_CHECK_FALSE +#define CHECK_THROWS DOCTEST_CHECK_THROWS +#define CHECK_THROWS_AS DOCTEST_CHECK_THROWS_AS +#define CHECK_NOTHROW DOCTEST_CHECK_NOTHROW +#define REQUIRE DOCTEST_REQUIRE +#define REQUIRE_FALSE DOCTEST_REQUIRE_FALSE +#define REQUIRE_THROWS DOCTEST_REQUIRE_THROWS +#define REQUIRE_THROWS_AS DOCTEST_REQUIRE_THROWS_AS +#define REQUIRE_NOTHROW DOCTEST_REQUIRE_NOTHROW + +#define WARN_MESSAGE DOCTEST_WARN_MESSAGE +#define WARN_FALSE_MESSAGE DOCTEST_WARN_FALSE_MESSAGE +#define WARN_THROWS_MESSAGE DOCTEST_WARN_THROWS_MESSAGE +#define WARN_THROWS_AS_MESSAGE DOCTEST_WARN_THROWS_AS_MESSAGE +#define WARN_NOTHROW_MESSAGE DOCTEST_WARN_NOTHROW_MESSAGE +#define CHECK_MESSAGE DOCTEST_CHECK_MESSAGE +#define CHECK_FALSE_MESSAGE DOCTEST_CHECK_FALSE_MESSAGE +#define CHECK_THROWS_MESSAGE DOCTEST_CHECK_THROWS_MESSAGE +#define CHECK_THROWS_AS_MESSAGE DOCTEST_CHECK_THROWS_AS_MESSAGE +#define CHECK_NOTHROW_MESSAGE DOCTEST_CHECK_NOTHROW_MESSAGE +#define REQUIRE_MESSAGE DOCTEST_REQUIRE_MESSAGE +#define REQUIRE_FALSE_MESSAGE DOCTEST_REQUIRE_FALSE_MESSAGE +#define REQUIRE_THROWS_MESSAGE DOCTEST_REQUIRE_THROWS_MESSAGE +#define REQUIRE_THROWS_AS_MESSAGE DOCTEST_REQUIRE_THROWS_AS_MESSAGE +#define REQUIRE_NOTHROW_MESSAGE DOCTEST_REQUIRE_NOTHROW_MESSAGE + +#define SCENARIO DOCTEST_SCENARIO +#define SCENARIO_TEMPLATE DOCTEST_SCENARIO_TEMPLATE +#define SCENARIO_TEMPLATE_DEFINE DOCTEST_SCENARIO_TEMPLATE_DEFINE +#define GIVEN DOCTEST_GIVEN +#define WHEN DOCTEST_WHEN +#define AND_WHEN DOCTEST_AND_WHEN +#define THEN DOCTEST_THEN +#define AND_THEN DOCTEST_AND_THEN + +#define WARN_EQ DOCTEST_WARN_EQ +#define CHECK_EQ DOCTEST_CHECK_EQ +#define REQUIRE_EQ DOCTEST_REQUIRE_EQ +#define WARN_NE DOCTEST_WARN_NE +#define CHECK_NE DOCTEST_CHECK_NE +#define REQUIRE_NE DOCTEST_REQUIRE_NE +#define WARN_GT DOCTEST_WARN_GT +#define CHECK_GT DOCTEST_CHECK_GT +#define REQUIRE_GT DOCTEST_REQUIRE_GT +#define WARN_LT DOCTEST_WARN_LT +#define CHECK_LT DOCTEST_CHECK_LT +#define REQUIRE_LT DOCTEST_REQUIRE_LT +#define WARN_GE DOCTEST_WARN_GE +#define CHECK_GE DOCTEST_CHECK_GE +#define REQUIRE_GE DOCTEST_REQUIRE_GE +#define WARN_LE DOCTEST_WARN_LE +#define CHECK_LE DOCTEST_CHECK_LE +#define REQUIRE_LE DOCTEST_REQUIRE_LE +#define WARN_UNARY DOCTEST_WARN_UNARY +#define CHECK_UNARY DOCTEST_CHECK_UNARY +#define REQUIRE_UNARY DOCTEST_REQUIRE_UNARY +#define WARN_UNARY_FALSE DOCTEST_WARN_UNARY_FALSE +#define CHECK_UNARY_FALSE DOCTEST_CHECK_UNARY_FALSE +#define REQUIRE_UNARY_FALSE DOCTEST_REQUIRE_UNARY_FALSE + +#define FAST_WARN_EQ DOCTEST_FAST_WARN_EQ +#define FAST_CHECK_EQ DOCTEST_FAST_CHECK_EQ +#define FAST_REQUIRE_EQ DOCTEST_FAST_REQUIRE_EQ +#define FAST_WARN_NE DOCTEST_FAST_WARN_NE +#define FAST_CHECK_NE DOCTEST_FAST_CHECK_NE +#define FAST_REQUIRE_NE DOCTEST_FAST_REQUIRE_NE +#define FAST_WARN_GT DOCTEST_FAST_WARN_GT +#define FAST_CHECK_GT DOCTEST_FAST_CHECK_GT +#define FAST_REQUIRE_GT DOCTEST_FAST_REQUIRE_GT +#define FAST_WARN_LT DOCTEST_FAST_WARN_LT +#define FAST_CHECK_LT DOCTEST_FAST_CHECK_LT +#define FAST_REQUIRE_LT DOCTEST_FAST_REQUIRE_LT +#define FAST_WARN_GE DOCTEST_FAST_WARN_GE +#define FAST_CHECK_GE DOCTEST_FAST_CHECK_GE +#define FAST_REQUIRE_GE DOCTEST_FAST_REQUIRE_GE +#define FAST_WARN_LE DOCTEST_FAST_WARN_LE +#define FAST_CHECK_LE DOCTEST_FAST_CHECK_LE +#define FAST_REQUIRE_LE DOCTEST_FAST_REQUIRE_LE +#define FAST_WARN_UNARY DOCTEST_FAST_WARN_UNARY +#define FAST_CHECK_UNARY DOCTEST_FAST_CHECK_UNARY +#define FAST_REQUIRE_UNARY DOCTEST_FAST_REQUIRE_UNARY +#define FAST_WARN_UNARY_FALSE DOCTEST_FAST_WARN_UNARY_FALSE +#define FAST_CHECK_UNARY_FALSE DOCTEST_FAST_CHECK_UNARY_FALSE +#define FAST_REQUIRE_UNARY_FALSE DOCTEST_FAST_REQUIRE_UNARY_FALSE + +#endif // DOCTEST_CONFIG_NO_SHORT_MACRO_NAMES + +// this is here to clear the 'current test suite' for the current translation unit - at the top +DOCTEST_TEST_SUITE_END(); + +// add stringification for primitive/fundamental types +namespace doctest +{ +namespace detail +{ + DOCTEST_TYPE_TO_STRING_IMPL(bool) + DOCTEST_TYPE_TO_STRING_IMPL(float) + DOCTEST_TYPE_TO_STRING_IMPL(double) + DOCTEST_TYPE_TO_STRING_IMPL(long double) + DOCTEST_TYPE_TO_STRING_IMPL(char) + DOCTEST_TYPE_TO_STRING_IMPL(signed char) + DOCTEST_TYPE_TO_STRING_IMPL(unsigned char) + DOCTEST_TYPE_TO_STRING_IMPL(wchar_t) + DOCTEST_TYPE_TO_STRING_IMPL(short int) + DOCTEST_TYPE_TO_STRING_IMPL(unsigned short int) + DOCTEST_TYPE_TO_STRING_IMPL(int) + DOCTEST_TYPE_TO_STRING_IMPL(unsigned int) + DOCTEST_TYPE_TO_STRING_IMPL(long int) + DOCTEST_TYPE_TO_STRING_IMPL(unsigned long int) +#ifdef DOCTEST_CONFIG_WITH_LONG_LONG + DOCTEST_TYPE_TO_STRING_IMPL(long long int) + DOCTEST_TYPE_TO_STRING_IMPL(unsigned long long int) +#endif // DOCTEST_CONFIG_WITH_LONG_LONG +} // namespace detail +} // namespace doctest + +DOCTEST_CLANG_SUPPRESS_WARNING_POP +DOCTEST_MSVC_SUPPRESS_WARNING_POP +DOCTEST_GCC_SUPPRESS_WARNING_POP + +#endif // DOCTEST_LIBRARY_INCLUDED + +#ifndef DOCTEST_SINGLE_HEADER +#define DOCTEST_SINGLE_HEADER +#endif // DOCTEST_SINGLE_HEADER + +#if defined(DOCTEST_CONFIG_IMPLEMENT) || !defined(DOCTEST_SINGLE_HEADER) +#ifndef DOCTEST_LIBRARY_IMPLEMENTATION +#define DOCTEST_LIBRARY_IMPLEMENTATION + +#ifndef DOCTEST_SINGLE_HEADER +#include "doctest_fwd.h" +#endif // DOCTEST_SINGLE_HEADER + +DOCTEST_CLANG_SUPPRESS_WARNING_PUSH +DOCTEST_CLANG_SUPPRESS_WARNING("-Wunknown-pragmas") +DOCTEST_CLANG_SUPPRESS_WARNING("-Wpadded") +DOCTEST_CLANG_SUPPRESS_WARNING("-Wglobal-constructors") +DOCTEST_CLANG_SUPPRESS_WARNING("-Wexit-time-destructors") +DOCTEST_CLANG_SUPPRESS_WARNING("-Wmissing-prototypes") +DOCTEST_CLANG_SUPPRESS_WARNING("-Wsign-conversion") +DOCTEST_CLANG_SUPPRESS_WARNING("-Wshorten-64-to-32") +DOCTEST_CLANG_SUPPRESS_WARNING("-Wmissing-variable-declarations") +DOCTEST_CLANG_SUPPRESS_WARNING("-Wswitch") +DOCTEST_CLANG_SUPPRESS_WARNING("-Wswitch-enum") +DOCTEST_CLANG_SUPPRESS_WARNING("-Wcovered-switch-default") +DOCTEST_CLANG_SUPPRESS_WARNING("-Wmissing-noreturn") +DOCTEST_CLANG_SUPPRESS_WARNING("-Wunused-local-typedef") +DOCTEST_CLANG_SUPPRESS_WARNING("-Wdisabled-macro-expansion") +DOCTEST_CLANG_SUPPRESS_WARNING("-Wmissing-braces") +DOCTEST_CLANG_SUPPRESS_WARNING("-Wmissing-field-initializers") +DOCTEST_CLANG_SUPPRESS_WARNING("-Wc++11-long-long") +#if DOCTEST_CLANG && DOCTEST_CLANG_HAS_WARNING("-Wzero-as-null-pointer-constant") +DOCTEST_CLANG_SUPPRESS_WARNING("-Wzero-as-null-pointer-constant") +#endif // clang - 0 as null + +DOCTEST_GCC_SUPPRESS_WARNING_PUSH +DOCTEST_GCC_SUPPRESS_WARNING("-Wunknown-pragmas") +DOCTEST_GCC_SUPPRESS_WARNING("-Wpragmas") +DOCTEST_GCC_SUPPRESS_WARNING("-Wconversion") +DOCTEST_GCC_SUPPRESS_WARNING("-Weffc++") +DOCTEST_GCC_SUPPRESS_WARNING("-Wsign-conversion") +DOCTEST_GCC_SUPPRESS_WARNING("-Wstrict-overflow") +DOCTEST_GCC_SUPPRESS_WARNING("-Wmissing-field-initializers") +DOCTEST_GCC_SUPPRESS_WARNING("-Wmissing-braces") +DOCTEST_GCC_SUPPRESS_WARNING("-Wmissing-declarations") +DOCTEST_GCC_SUPPRESS_WARNING("-Winline") +DOCTEST_GCC_SUPPRESS_WARNING("-Wswitch") +DOCTEST_GCC_SUPPRESS_WARNING("-Wswitch-enum") +DOCTEST_GCC_SUPPRESS_WARNING("-Wswitch-default") +DOCTEST_GCC_SUPPRESS_WARNING("-Wunsafe-loop-optimizations") +DOCTEST_GCC_SUPPRESS_WARNING("-Wlong-long") +DOCTEST_GCC_SUPPRESS_WARNING("-Wold-style-cast") +DOCTEST_GCC_SUPPRESS_WARNING("-Wzero-as-null-pointer-constant") +DOCTEST_GCC_SUPPRESS_WARNING("-Wunused-local-typedefs") +DOCTEST_GCC_SUPPRESS_WARNING("-Wuseless-cast") + +DOCTEST_MSVC_SUPPRESS_WARNING_PUSH +DOCTEST_MSVC_SUPPRESS_WARNING(4616) // invalid compiler warning +DOCTEST_MSVC_SUPPRESS_WARNING(4619) // invalid compiler warning +DOCTEST_MSVC_SUPPRESS_WARNING(4996) // The compiler encountered a deprecated declaration +DOCTEST_MSVC_SUPPRESS_WARNING(4267) // 'var' : conversion from 'x' to 'y', possible loss of data +DOCTEST_MSVC_SUPPRESS_WARNING(4706) // assignment within conditional expression +DOCTEST_MSVC_SUPPRESS_WARNING(4512) // 'class' : assignment operator could not be generated +DOCTEST_MSVC_SUPPRESS_WARNING(4127) // conditional expression is constant +DOCTEST_MSVC_SUPPRESS_WARNING(4530) // C++ exception handler used, but unwind semantics not enabled +DOCTEST_MSVC_SUPPRESS_WARNING(4577) // 'noexcept' used with no exception handling mode specified +DOCTEST_MSVC_SUPPRESS_WARNING(4774) // format string expected in argument is not a string literal +DOCTEST_MSVC_SUPPRESS_WARNING(4365) // conversion from 'int' to 'unsigned', signed/unsigned mismatch +DOCTEST_MSVC_SUPPRESS_WARNING(4820) // padding in structs +DOCTEST_MSVC_SUPPRESS_WARNING(4640) // construction of local static object is not thread-safe +DOCTEST_MSVC_SUPPRESS_WARNING(5039) // pointer to potentially throwing function passed to extern C +DOCTEST_MSVC_SUPPRESS_WARNING(5045) // Spectre mitigation stuff + +#if defined(DOCTEST_NO_CPP11_COMPAT) +DOCTEST_CLANG_SUPPRESS_WARNING("-Wc++98-compat") +DOCTEST_CLANG_SUPPRESS_WARNING("-Wc++98-compat-pedantic") +#endif // DOCTEST_NO_CPP11_COMPAT + +#define DOCTEST_LOG_START(s) \ + do { \ + if(!contextState->hasLoggedCurrentTestStart) { \ + logTestStart(s, *contextState->currentTest); \ + DOCTEST_PRINT_TO_OUTPUT_WINDOW_IN_IDE_BEGIN; \ + logTestStart(oss, *contextState->currentTest); \ + DOCTEST_PRINT_TO_OUTPUT_WINDOW_IN_IDE_END; \ + contextState->hasLoggedCurrentTestStart = true; \ + } \ + } while(false) + +#define DOCTEST_PRINT_TO_OUTPUT_WINDOW_IN_IDE_BEGIN \ + if(isDebuggerActive()) { \ + ContextState* p_cs = contextState; \ + bool with_col = p_cs->no_colors; \ + p_cs->no_colors = false; \ + std::ostringstream oss + +#define DOCTEST_PRINT_TO_OUTPUT_WINDOW_IN_IDE_END \ + printToDebugConsole(oss.str().c_str()); \ + p_cs->no_colors = with_col; \ + } \ + ((void)0) + +DOCTEST_MAKE_STD_HEADERS_CLEAN_FROM_WARNINGS_ON_WALL_BEGIN + +// required includes - will go only in one translation unit! +#include +#include +// borland (Embarcadero) compiler requires math.h and not cmath - https://github.com/onqtam/doctest/pull/37 +#ifdef __BORLANDC__ +#include +#endif // __BORLANDC__ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if !DOCTEST_MSVC +#include +#endif // !MSVC + +DOCTEST_MAKE_STD_HEADERS_CLEAN_FROM_WARNINGS_ON_WALL_END + +namespace doctest +{ +namespace detail +{ + // case insensitive strcmp + int stricmp(char const* a, char const* b) { + for(;; a++, b++) { + const int d = tolower(*a) - tolower(*b); + if(d != 0 || !*a) + return d; + } + } + + void my_memcpy(void* dest, const void* src, unsigned num) { memcpy(dest, src, num); } + + template + String fpToString(T value, int precision) { + std::ostringstream oss; + oss << std::setprecision(precision) << std::fixed << value; + std::string d = oss.str(); + size_t i = d.find_last_not_of('0'); + if(i != std::string::npos && i != d.size() - 1) { + if(d[i] == '.') + i++; + d = d.substr(0, i + 1); + } + return d.c_str(); + } + + struct Endianness + { + enum Arch + { + Big, + Little + }; + + static Arch which() { + union _ + { + int asInt; + char asChar[sizeof(int)]; + } u; + + u.asInt = 1; // NOLINT + return (u.asChar[sizeof(int) - 1] == 1) ? Big : Little; // NOLINT + } + }; + + String rawMemoryToString(const void* object, unsigned size) { + // Reverse order for little endian architectures + int i = 0, end = static_cast(size), inc = 1; + if(Endianness::which() == Endianness::Little) { + i = end - 1; + end = inc = -1; + } + + unsigned char const* bytes = static_cast(object); + std::ostringstream oss; + oss << "0x" << std::setfill('0') << std::hex; + for(; i != end; i += inc) + oss << std::setw(2) << static_cast(bytes[i]); + return oss.str().c_str(); + } + + std::ostream* createStream() { return new std::ostringstream(); } + String getStreamResult(std::ostream* s) { + return static_cast(s)->str().c_str(); // NOLINT + } + void freeStream(std::ostream* s) { delete s; } + +#ifndef DOCTEST_CONFIG_DISABLE + + // this holds both parameters for the command line and runtime data for tests + struct ContextState : TestAccessibleContextState //!OCLINT too many fields + { + // == parameters from the command line + + std::vector > filters; + + String order_by; // how tests should be ordered + unsigned rand_seed; // the seed for rand ordering + + unsigned first; // the first (matching) test to be executed + unsigned last; // the last (matching) test to be executed + + int abort_after; // stop tests after this many failed assertions + int subcase_filter_levels; // apply the subcase filters for the first N levels + bool case_sensitive; // if filtering should be case sensitive + bool exit; // if the program should be exited after the tests are ran/whatever + bool duration; // print the time duration of each test case + bool no_exitcode; // if the framework should return 0 as the exitcode + bool no_run; // to not run the tests at all (can be done with an "*" exclude) + bool no_version; // to not print the version of the framework + bool no_colors; // if output to the console should be colorized + bool force_colors; // forces the use of colors even when a tty cannot be detected + bool no_breaks; // to not break into the debugger + bool no_skip; // don't skip test cases which are marked to be skipped + bool gnu_file_line; // if line numbers should be surrounded with :x: and not (x): + bool no_path_in_filenames; // if the path to files should be removed from the output + bool no_line_numbers; // if source code line numbers should be omitted from the output + bool no_skipped_summary; // don't print "skipped" in the summary !!! UNDOCUMENTED !!! + + bool help; // to print the help + bool version; // to print the version + bool count; // if only the count of matching tests is to be retreived + bool list_test_cases; // to list all tests matching the filters + bool list_test_suites; // to list all suites matching the filters + + // == data for the tests being ran + + unsigned numTestsPassingFilters; + unsigned numTestSuitesPassingFilters; + unsigned numFailed; + const TestCase* currentTest; + bool hasLoggedCurrentTestStart; + int numAssertionsForCurrentTestcase; + int numAssertions; + int numFailedAssertionsForCurrentTestcase; + int numFailedAssertions; + bool hasCurrentTestFailed; + + std::vector contexts; // for logging with INFO() and friends + std::vector exceptionalContexts; // logging from INFO() due to an exception + + // stuff for subcases + std::set subcasesPassed; + std::set subcasesEnteredLevels; + std::vector subcasesStack; + int subcasesCurrentLevel; + bool subcasesHasSkipped; + + void resetRunData() { + numTestsPassingFilters = 0; + numTestSuitesPassingFilters = 0; + numFailed = 0; + numAssertions = 0; + numFailedAssertions = 0; + numFailedAssertionsForCurrentTestcase = 0; + } + + // cppcheck-suppress uninitMemberVar + ContextState() + : filters(8) // 8 different filters total + { + resetRunData(); + } + }; + + ContextState* contextState = 0; +#endif // DOCTEST_CONFIG_DISABLE +} // namespace detail + +void String::copy(const String& other) { + if(other.isOnStack()) { + memcpy(buf, other.buf, len); + } else { + setOnHeap(); + data.size = other.data.size; + data.capacity = data.size + 1; + data.ptr = new char[data.capacity]; + memcpy(data.ptr, other.data.ptr, data.size + 1); + } +} + +String::String(const char* in) { + unsigned in_len = strlen(in); + if(in_len <= last) { + memcpy(buf, in, in_len + 1); + setLast(last - in_len); + } else { + setOnHeap(); + data.size = in_len; + data.capacity = data.size + 1; + data.ptr = new char[data.capacity]; + memcpy(data.ptr, in, in_len + 1); + } +} + +String& String::operator+=(const String& other) { + const unsigned my_old_size = size(); + const unsigned other_size = other.size(); + const unsigned total_size = my_old_size + other_size; + if(isOnStack()) { + if(total_size < len) { + // append to the current stack space + memcpy(buf + my_old_size, other.c_str(), other_size + 1); + setLast(last - total_size); + } else { + // alloc new chunk + char* temp = new char[total_size + 1]; + // copy current data to new location before writing in the union + memcpy(temp, buf, my_old_size); // skip the +1 ('\0') for speed + // update data in union + setOnHeap(); + data.size = total_size; + data.capacity = data.size + 1; + data.ptr = temp; + // transfer the rest of the data + memcpy(data.ptr + my_old_size, other.c_str(), other_size + 1); + } + } else { + if(data.capacity > total_size) { + // append to the current heap block + data.size = total_size; + memcpy(data.ptr + my_old_size, other.c_str(), other_size + 1); + } else { + // resize + data.capacity *= 2; + if(data.capacity <= total_size) + data.capacity = total_size + 1; + // alloc new chunk + char* temp = new char[data.capacity]; + // copy current data to new location before releasing it + memcpy(temp, data.ptr, my_old_size); // skip the +1 ('\0') for speed + // release old chunk + delete[] data.ptr; + // update the rest of the union members + data.size = total_size; + data.ptr = temp; + // transfer the rest of the data + memcpy(data.ptr + my_old_size, other.c_str(), other_size + 1); + } + } + + return *this; +} + +#ifdef DOCTEST_CONFIG_WITH_RVALUE_REFERENCES +String::String(String&& other) { + memcpy(buf, other.buf, len); + other.buf[0] = '\0'; + other.setLast(); +} + +String& String::operator=(String&& other) { + if(this != &other) { + if(!isOnStack()) + delete[] data.ptr; + memcpy(buf, other.buf, len); + other.buf[0] = '\0'; + other.setLast(); + } + return *this; +} +#endif // DOCTEST_CONFIG_WITH_RVALUE_REFERENCES + +int String::compare(const char* other, bool no_case) const { + if(no_case) + return detail::stricmp(c_str(), other); + return std::strcmp(c_str(), other); +} + +int String::compare(const String& other, bool no_case) const { + return compare(other.c_str(), no_case); +} + +std::ostream& operator<<(std::ostream& s, const String& in) { return s << in.c_str(); } + +Approx::Approx(double value) + : m_epsilon(static_cast(std::numeric_limits::epsilon()) * 100) + , m_scale(1.0) + , m_value(value) {} + +bool operator==(double lhs, Approx const& rhs) { + // Thanks to Richard Harris for his help refining this formula + return std::fabs(lhs - rhs.m_value) < + rhs.m_epsilon * (rhs.m_scale + std::max(std::fabs(lhs), std::fabs(rhs.m_value))); +} + +String Approx::toString() const { return String("Approx( ") + doctest::toString(m_value) + " )"; } + +#ifdef DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING +String toString(char* in) { return toString(static_cast(in)); } +String toString(const char* in) { return String("\"") + (in ? in : "{null string}") + "\""; } +#endif // DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING +String toString(bool in) { return in ? "true" : "false"; } +String toString(float in) { return detail::fpToString(in, 5) + "f"; } +String toString(double in) { return detail::fpToString(in, 10); } +String toString(double long in) { return detail::fpToString(in, 15); } + +String toString(char in) { + char buf[64]; + std::sprintf(buf, "%d", in); + return buf; +} + +String toString(char signed in) { + char buf[64]; + std::sprintf(buf, "%d", in); + return buf; +} + +String toString(char unsigned in) { + char buf[64]; + std::sprintf(buf, "%ud", in); + return buf; +} + +String toString(int short in) { + char buf[64]; + std::sprintf(buf, "%d", in); + return buf; +} + +String toString(int short unsigned in) { + char buf[64]; + std::sprintf(buf, "%u", in); + return buf; +} + +String toString(int in) { + char buf[64]; + std::sprintf(buf, "%d", in); + return buf; +} + +String toString(int unsigned in) { + char buf[64]; + std::sprintf(buf, "%u", in); + return buf; +} + +String toString(int long in) { + char buf[64]; + std::sprintf(buf, "%ld", in); + return buf; +} + +String toString(int long unsigned in) { + char buf[64]; + std::sprintf(buf, "%lu", in); + return buf; +} + +#ifdef DOCTEST_CONFIG_WITH_LONG_LONG +String toString(int long long in) { + char buf[64]; + std::sprintf(buf, "%lld", in); + return buf; +} +String toString(int long long unsigned in) { + char buf[64]; + std::sprintf(buf, "%llu", in); + return buf; +} +#endif // DOCTEST_CONFIG_WITH_LONG_LONG + +#ifdef DOCTEST_CONFIG_WITH_NULLPTR +String toString(std::nullptr_t) { return "nullptr"; } +#endif // DOCTEST_CONFIG_WITH_NULLPTR + +} // namespace doctest + +#ifdef DOCTEST_CONFIG_DISABLE +namespace doctest +{ +bool isRunningInTest() { return false; } +Context::Context(int, const char* const*) {} +Context::~Context() {} +void Context::applyCommandLine(int, const char* const*) {} +void Context::addFilter(const char*, const char*) {} +void Context::clearFilters() {} +void Context::setOption(const char*, int) {} +void Context::setOption(const char*, const char*) {} +bool Context::shouldExit() { return false; } +int Context::run() { return 0; } +} // namespace doctest +#else // DOCTEST_CONFIG_DISABLE + +#if !defined(DOCTEST_CONFIG_COLORS_NONE) +#if !defined(DOCTEST_CONFIG_COLORS_WINDOWS) && !defined(DOCTEST_CONFIG_COLORS_ANSI) +#ifdef DOCTEST_PLATFORM_WINDOWS +#define DOCTEST_CONFIG_COLORS_WINDOWS +#else // linux +#define DOCTEST_CONFIG_COLORS_ANSI +#endif // platform +#endif // DOCTEST_CONFIG_COLORS_WINDOWS && DOCTEST_CONFIG_COLORS_ANSI +#endif // DOCTEST_CONFIG_COLORS_NONE + +#if DOCTEST_MSVC || defined(__MINGW32__) +#if DOCTEST_MSVC >= DOCTEST_COMPILER(17, 0, 0) +#define DOCTEST_WINDOWS_SAL_IN_OPT _In_opt_ +#else // MSVC +#define DOCTEST_WINDOWS_SAL_IN_OPT +#endif // MSVC +extern "C" __declspec(dllimport) void __stdcall OutputDebugStringA( + DOCTEST_WINDOWS_SAL_IN_OPT const char*); +extern "C" __declspec(dllimport) int __stdcall IsDebuggerPresent(); +#endif // MSVC || __MINGW32__ + +#ifdef DOCTEST_CONFIG_COLORS_ANSI +#include +#endif // DOCTEST_CONFIG_COLORS_ANSI + +#ifdef DOCTEST_PLATFORM_WINDOWS + +// defines for a leaner windows.h +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif // WIN32_LEAN_AND_MEAN +#ifndef VC_EXTRA_LEAN +#define VC_EXTRA_LEAN +#endif // VC_EXTRA_LEAN +#ifndef NOMINMAX +#define NOMINMAX +#endif // NOMINMAX + +DOCTEST_MAKE_STD_HEADERS_CLEAN_FROM_WARNINGS_ON_WALL_BEGIN + +// not sure what AfxWin.h is for - here I do what Catch does +#ifdef __AFXDLL +#include +#else +#include +#endif +#include + +DOCTEST_MAKE_STD_HEADERS_CLEAN_FROM_WARNINGS_ON_WALL_END + +#else // DOCTEST_PLATFORM_WINDOWS + +#include + +#endif // DOCTEST_PLATFORM_WINDOWS + +namespace doctest_detail_test_suite_ns +{ +// holds the current test suite +doctest::detail::TestSuite& getCurrentTestSuite() { + static doctest::detail::TestSuite data; + return data; +} +} // namespace doctest_detail_test_suite_ns + +namespace doctest +{ +namespace detail +{ + TestCase::TestCase(funcType test, const char* file, unsigned line, const TestSuite& test_suite, + const char* type, int template_id) + : m_test(test) + , m_name(0) + , m_type(type) + , m_test_suite(test_suite.m_test_suite) + , m_description(test_suite.m_description) + , m_skip(test_suite.m_skip) + , m_may_fail(test_suite.m_may_fail) + , m_should_fail(test_suite.m_should_fail) + , m_expected_failures(test_suite.m_expected_failures) + , m_timeout(test_suite.m_timeout) + , m_file(file) + , m_line(line) + , m_template_id(template_id) {} + + TestCase& TestCase::operator*(const char* in) { + m_name = in; + // make a new name with an appended type for templated test case + if(m_template_id != -1) { + m_full_name = String(m_name) + m_type; + // redirect the name to point to the newly constructed full name + m_name = m_full_name.c_str(); + } + return *this; + } + + TestCase& TestCase::operator=(const TestCase& other) { + m_test = other.m_test; + m_full_name = other.m_full_name; + m_name = other.m_name; + m_type = other.m_type; + m_test_suite = other.m_test_suite; + m_description = other.m_description; + m_skip = other.m_skip; + m_may_fail = other.m_may_fail; + m_should_fail = other.m_should_fail; + m_expected_failures = other.m_expected_failures; + m_timeout = other.m_timeout; + m_file = other.m_file; + m_line = other.m_line; + m_template_id = other.m_template_id; + + if(m_template_id != -1) + m_name = m_full_name.c_str(); + return *this; + } + + bool TestCase::operator<(const TestCase& other) const { + if(m_line != other.m_line) + return m_line < other.m_line; + const int file_cmp = std::strcmp(m_file, other.m_file); + if(file_cmp != 0) + return file_cmp < 0; + return m_template_id < other.m_template_id; + } + + const char* assertString(assertType::Enum val) { + DOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH( + 4062) // enumerator 'x' in switch of enum 'y' is not handled + switch(val) { //!OCLINT missing default in switch statements + // clang-format off + case assertType::DT_WARN : return "WARN"; + case assertType::DT_CHECK : return "CHECK"; + case assertType::DT_REQUIRE : return "REQUIRE"; + + case assertType::DT_WARN_FALSE : return "WARN_FALSE"; + case assertType::DT_CHECK_FALSE : return "CHECK_FALSE"; + case assertType::DT_REQUIRE_FALSE : return "REQUIRE_FALSE"; + + case assertType::DT_WARN_THROWS : return "WARN_THROWS"; + case assertType::DT_CHECK_THROWS : return "CHECK_THROWS"; + case assertType::DT_REQUIRE_THROWS : return "REQUIRE_THROWS"; + + case assertType::DT_WARN_THROWS_AS : return "WARN_THROWS_AS"; + case assertType::DT_CHECK_THROWS_AS : return "CHECK_THROWS_AS"; + case assertType::DT_REQUIRE_THROWS_AS : return "REQUIRE_THROWS_AS"; + + case assertType::DT_WARN_NOTHROW : return "WARN_NOTHROW"; + case assertType::DT_CHECK_NOTHROW : return "CHECK_NOTHROW"; + case assertType::DT_REQUIRE_NOTHROW : return "REQUIRE_NOTHROW"; + + case assertType::DT_WARN_EQ : return "WARN_EQ"; + case assertType::DT_CHECK_EQ : return "CHECK_EQ"; + case assertType::DT_REQUIRE_EQ : return "REQUIRE_EQ"; + case assertType::DT_WARN_NE : return "WARN_NE"; + case assertType::DT_CHECK_NE : return "CHECK_NE"; + case assertType::DT_REQUIRE_NE : return "REQUIRE_NE"; + case assertType::DT_WARN_GT : return "WARN_GT"; + case assertType::DT_CHECK_GT : return "CHECK_GT"; + case assertType::DT_REQUIRE_GT : return "REQUIRE_GT"; + case assertType::DT_WARN_LT : return "WARN_LT"; + case assertType::DT_CHECK_LT : return "CHECK_LT"; + case assertType::DT_REQUIRE_LT : return "REQUIRE_LT"; + case assertType::DT_WARN_GE : return "WARN_GE"; + case assertType::DT_CHECK_GE : return "CHECK_GE"; + case assertType::DT_REQUIRE_GE : return "REQUIRE_GE"; + case assertType::DT_WARN_LE : return "WARN_LE"; + case assertType::DT_CHECK_LE : return "CHECK_LE"; + case assertType::DT_REQUIRE_LE : return "REQUIRE_LE"; + + case assertType::DT_WARN_UNARY : return "WARN_UNARY"; + case assertType::DT_CHECK_UNARY : return "CHECK_UNARY"; + case assertType::DT_REQUIRE_UNARY : return "REQUIRE_UNARY"; + case assertType::DT_WARN_UNARY_FALSE : return "WARN_UNARY_FALSE"; + case assertType::DT_CHECK_UNARY_FALSE : return "CHECK_UNARY_FALSE"; + case assertType::DT_REQUIRE_UNARY_FALSE : return "REQUIRE_UNARY_FALSE"; + + case assertType::DT_FAST_WARN_EQ : return "FAST_WARN_EQ"; + case assertType::DT_FAST_CHECK_EQ : return "FAST_CHECK_EQ"; + case assertType::DT_FAST_REQUIRE_EQ : return "FAST_REQUIRE_EQ"; + case assertType::DT_FAST_WARN_NE : return "FAST_WARN_NE"; + case assertType::DT_FAST_CHECK_NE : return "FAST_CHECK_NE"; + case assertType::DT_FAST_REQUIRE_NE : return "FAST_REQUIRE_NE"; + case assertType::DT_FAST_WARN_GT : return "FAST_WARN_GT"; + case assertType::DT_FAST_CHECK_GT : return "FAST_CHECK_GT"; + case assertType::DT_FAST_REQUIRE_GT : return "FAST_REQUIRE_GT"; + case assertType::DT_FAST_WARN_LT : return "FAST_WARN_LT"; + case assertType::DT_FAST_CHECK_LT : return "FAST_CHECK_LT"; + case assertType::DT_FAST_REQUIRE_LT : return "FAST_REQUIRE_LT"; + case assertType::DT_FAST_WARN_GE : return "FAST_WARN_GE"; + case assertType::DT_FAST_CHECK_GE : return "FAST_CHECK_GE"; + case assertType::DT_FAST_REQUIRE_GE : return "FAST_REQUIRE_GE"; + case assertType::DT_FAST_WARN_LE : return "FAST_WARN_LE"; + case assertType::DT_FAST_CHECK_LE : return "FAST_CHECK_LE"; + case assertType::DT_FAST_REQUIRE_LE : return "FAST_REQUIRE_LE"; + + case assertType::DT_FAST_WARN_UNARY : return "FAST_WARN_UNARY"; + case assertType::DT_FAST_CHECK_UNARY : return "FAST_CHECK_UNARY"; + case assertType::DT_FAST_REQUIRE_UNARY : return "FAST_REQUIRE_UNARY"; + case assertType::DT_FAST_WARN_UNARY_FALSE : return "FAST_WARN_UNARY_FALSE"; + case assertType::DT_FAST_CHECK_UNARY_FALSE : return "FAST_CHECK_UNARY_FALSE"; + case assertType::DT_FAST_REQUIRE_UNARY_FALSE: return "FAST_REQUIRE_UNARY_FALSE"; + // clang-format on + } + DOCTEST_MSVC_SUPPRESS_WARNING_POP + return ""; + } + + bool checkIfShouldThrow(assertType::Enum at) { + if(at & assertType::is_require) //!OCLINT bitwise operator in conditional + return true; + + if((at & assertType::is_check) //!OCLINT bitwise operator in conditional + && contextState->abort_after > 0 && + contextState->numFailedAssertions >= contextState->abort_after) + return true; + + return false; + } + void throwException() { +#ifndef DOCTEST_CONFIG_NO_EXCEPTIONS + throw TestFailureException(); +#endif // DOCTEST_CONFIG_NO_EXCEPTIONS + } + void fastAssertThrowIfFlagSet(int flags) { + if(flags & assertAction::shouldthrow) //!OCLINT bitwise operator in conditional + throwException(); + } + + // matching of a string against a wildcard mask (case sensitivity configurable) taken from + // https://www.codeproject.com/Articles/1088/Wildcard-string-compare-globbing + int wildcmp(const char* str, const char* wild, bool caseSensitive) { + const char* cp = 0; + const char* mp = 0; + + while((*str) && (*wild != '*')) { + if((caseSensitive ? (*wild != *str) : (tolower(*wild) != tolower(*str))) && + (*wild != '?')) { + return 0; + } + wild++; + str++; + } + + while(*str) { + if(*wild == '*') { + if(!*++wild) { + return 1; + } + mp = wild; + cp = str + 1; + } else if((caseSensitive ? (*wild == *str) : (tolower(*wild) == tolower(*str))) || + (*wild == '?')) { + wild++; + str++; + } else { + wild = mp; //!OCLINT parameter reassignment + str = cp++; //!OCLINT parameter reassignment + } + } + + while(*wild == '*') { + wild++; + } + return !*wild; + } + + //// C string hash function (djb2) - taken from http://www.cse.yorku.ca/~oz/hash.html + //unsigned hashStr(unsigned const char* str) { + // unsigned long hash = 5381; + // char c; + // while((c = *str++)) + // hash = ((hash << 5) + hash) + c; // hash * 33 + c + // return hash; + //} + + // checks if the name matches any of the filters (and can be configured what to do when empty) + bool matchesAny(const char* name, const std::vector& filters, int matchEmpty, + bool caseSensitive) { + if(filters.empty() && matchEmpty) + return true; + for(unsigned i = 0; i < filters.size(); ++i) + if(wildcmp(name, filters[i].c_str(), caseSensitive)) + return true; + return false; + } + +#ifdef DOCTEST_PLATFORM_WINDOWS + + typedef unsigned long long UInt64; + + UInt64 getCurrentTicks() { + static UInt64 hz = 0, hzo = 0; + if(!hz) { + QueryPerformanceFrequency(reinterpret_cast(&hz)); + QueryPerformanceCounter(reinterpret_cast(&hzo)); + } + UInt64 t; + QueryPerformanceCounter(reinterpret_cast(&t)); + return ((t - hzo) * 1000000) / hz; + } +#else // DOCTEST_PLATFORM_WINDOWS + + typedef uint64_t UInt64; + + UInt64 getCurrentTicks() { + timeval t; + gettimeofday(&t, 0); + return static_cast(t.tv_sec) * 1000000 + static_cast(t.tv_usec); + } +#endif // DOCTEST_PLATFORM_WINDOWS + + class Timer + { + public: + Timer() + : m_ticks(0) {} + void start() { m_ticks = getCurrentTicks(); } + unsigned int getElapsedMicroseconds() const { + return static_cast(getCurrentTicks() - m_ticks); + } + unsigned int getElapsedMilliseconds() const { + return static_cast(getElapsedMicroseconds() / 1000); + } + double getElapsedSeconds() const { return getElapsedMicroseconds() / 1000000.0; } + + private: + UInt64 m_ticks; + }; + + TestAccessibleContextState* getTestsContextState() { return contextState; } + + // TODO: remove this from here + void logTestEnd(); + + bool SubcaseSignature::operator<(const SubcaseSignature& other) const { + if(m_line != other.m_line) + return m_line < other.m_line; + if(std::strcmp(m_file, other.m_file) != 0) + return std::strcmp(m_file, other.m_file) < 0; + return std::strcmp(m_name, other.m_name) < 0; + } + + Subcase::Subcase(const char* name, const char* file, int line) + : m_signature(name, file, line) + , m_entered(false) { + ContextState* s = contextState; + + // if we have already completed it + if(s->subcasesPassed.count(m_signature) != 0) + return; + + // check subcase filters + if(s->subcasesCurrentLevel < s->subcase_filter_levels) { + if(!matchesAny(m_signature.m_name, s->filters[6], 1, s->case_sensitive)) + return; + if(matchesAny(m_signature.m_name, s->filters[7], 0, s->case_sensitive)) + return; + } + + // if a Subcase on the same level has already been entered + if(s->subcasesEnteredLevels.count(s->subcasesCurrentLevel) != 0) { + s->subcasesHasSkipped = true; + return; + } + + s->subcasesStack.push_back(*this); + if(s->hasLoggedCurrentTestStart) + logTestEnd(); + s->hasLoggedCurrentTestStart = false; + + s->subcasesEnteredLevels.insert(s->subcasesCurrentLevel++); + m_entered = true; + } + + Subcase::Subcase(const Subcase& other) + : m_signature(other.m_signature.m_name, other.m_signature.m_file, + other.m_signature.m_line) + , m_entered(other.m_entered) {} + + Subcase::~Subcase() { + if(m_entered) { + ContextState* s = contextState; + + s->subcasesCurrentLevel--; + // only mark the subcase as passed if no subcases have been skipped + if(s->subcasesHasSkipped == false) + s->subcasesPassed.insert(m_signature); + + if(!s->subcasesStack.empty()) + s->subcasesStack.pop_back(); + if(s->hasLoggedCurrentTestStart) + logTestEnd(); + s->hasLoggedCurrentTestStart = false; + } + } + + Result::~Result() {} + + Result& Result::operator=(const Result& other) { + m_passed = other.m_passed; + m_decomposition = other.m_decomposition; + + return *this; + } + + // for sorting tests by file/line + int fileOrderComparator(const void* a, const void* b) { + const TestCase* lhs = *static_cast(a); + const TestCase* rhs = *static_cast(b); +#if DOCTEST_MSVC + // this is needed because MSVC gives different case for drive letters + // for __FILE__ when evaluated in a header and a source file + const int res = stricmp(lhs->m_file, rhs->m_file); +#else // MSVC + const int res = std::strcmp(lhs->m_file, rhs->m_file); +#endif // MSVC + if(res != 0) + return res; + return static_cast(lhs->m_line - rhs->m_line); + } + + // for sorting tests by suite/file/line + int suiteOrderComparator(const void* a, const void* b) { + const TestCase* lhs = *static_cast(a); + const TestCase* rhs = *static_cast(b); + + const int res = std::strcmp(lhs->m_test_suite, rhs->m_test_suite); + if(res != 0) + return res; + return fileOrderComparator(a, b); + } + + // for sorting tests by name/suite/file/line + int nameOrderComparator(const void* a, const void* b) { + const TestCase* lhs = *static_cast(a); + const TestCase* rhs = *static_cast(b); + + const int res_name = std::strcmp(lhs->m_name, rhs->m_name); + if(res_name != 0) + return res_name; + return suiteOrderComparator(a, b); + } + + // sets the current test suite + int setTestSuite(const TestSuite& ts) { + doctest_detail_test_suite_ns::getCurrentTestSuite() = ts; + return 0; + } + + // all the registered tests + std::set& getRegisteredTests() { + static std::set data; + return data; + } + + // used by the macros for registering tests + int regTest(const TestCase& tc) { + getRegisteredTests().insert(tc); + return 0; + } + + namespace Color + { + enum Code + { + None = 0, + White, + Red, + Green, + Blue, + Cyan, + Yellow, + Grey, + + Bright = 0x10, + + BrightRed = Bright | Red, + BrightGreen = Bright | Green, + LightGrey = Bright | Grey, + BrightWhite = Bright | White + }; + +#ifdef DOCTEST_CONFIG_COLORS_WINDOWS + HANDLE g_stdoutHandle; + WORD g_originalForegroundAttributes; + WORD g_originalBackgroundAttributes; + bool g_attrsInitted = false; +#endif // DOCTEST_CONFIG_COLORS_WINDOWS + + void init() { +#ifdef DOCTEST_CONFIG_COLORS_WINDOWS + if(!g_attrsInitted) { + g_stdoutHandle = GetStdHandle(STD_OUTPUT_HANDLE); + g_attrsInitted = true; + CONSOLE_SCREEN_BUFFER_INFO csbiInfo; + GetConsoleScreenBufferInfo(g_stdoutHandle, &csbiInfo); + g_originalForegroundAttributes = + csbiInfo.wAttributes & ~(BACKGROUND_GREEN | BACKGROUND_RED | + BACKGROUND_BLUE | BACKGROUND_INTENSITY); + g_originalBackgroundAttributes = + csbiInfo.wAttributes & ~(FOREGROUND_GREEN | FOREGROUND_RED | + FOREGROUND_BLUE | FOREGROUND_INTENSITY); + } +#endif // DOCTEST_CONFIG_COLORS_WINDOWS + } + + std::ostream& operator<<(std::ostream& s, Color::Code +#ifndef DOCTEST_CONFIG_COLORS_NONE + code +#endif // DOCTEST_CONFIG_COLORS_NONE + ) { + const ContextState* p = contextState; + if(p->no_colors) + return s; +#ifdef DOCTEST_CONFIG_COLORS_ANSI + if(isatty(STDOUT_FILENO) == false && p->force_colors == false) + return s; + + const char* col = ""; + // clang-format off + switch(code) { //!OCLINT missing break in switch statement / unnecessary default statement in covered switch statement + case Color::Red: col = "[0;31m"; break; + case Color::Green: col = "[0;32m"; break; + case Color::Blue: col = "[0;34m"; break; + case Color::Cyan: col = "[0;36m"; break; + case Color::Yellow: col = "[0;33m"; break; + case Color::Grey: col = "[1;30m"; break; + case Color::LightGrey: col = "[0;37m"; break; + case Color::BrightRed: col = "[1;31m"; break; + case Color::BrightGreen: col = "[1;32m"; break; + case Color::BrightWhite: col = "[1;37m"; break; + case Color::Bright: // invalid + case Color::None: + case Color::White: + default: col = "[0m"; + } + // clang-format on + s << "\033" << col; +#endif // DOCTEST_CONFIG_COLORS_ANSI + +#ifdef DOCTEST_CONFIG_COLORS_WINDOWS + if(isatty(fileno(stdout)) == false && p->force_colors == false) + return s; + +#define DOCTEST_SET_ATTR(x) \ + SetConsoleTextAttribute(g_stdoutHandle, x | g_originalBackgroundAttributes) + + // clang-format off + switch (code) { + case Color::White: DOCTEST_SET_ATTR(FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE); break; + case Color::Red: DOCTEST_SET_ATTR(FOREGROUND_RED); break; + case Color::Green: DOCTEST_SET_ATTR(FOREGROUND_GREEN); break; + case Color::Blue: DOCTEST_SET_ATTR(FOREGROUND_BLUE); break; + case Color::Cyan: DOCTEST_SET_ATTR(FOREGROUND_BLUE | FOREGROUND_GREEN); break; + case Color::Yellow: DOCTEST_SET_ATTR(FOREGROUND_RED | FOREGROUND_GREEN); break; + case Color::Grey: DOCTEST_SET_ATTR(0); break; + case Color::LightGrey: DOCTEST_SET_ATTR(FOREGROUND_INTENSITY); break; + case Color::BrightRed: DOCTEST_SET_ATTR(FOREGROUND_INTENSITY | FOREGROUND_RED); break; + case Color::BrightGreen: DOCTEST_SET_ATTR(FOREGROUND_INTENSITY | FOREGROUND_GREEN); break; + case Color::BrightWhite: DOCTEST_SET_ATTR(FOREGROUND_INTENSITY | FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE); break; + case Color::None: + case Color::Bright: // invalid + default: DOCTEST_SET_ATTR(g_originalForegroundAttributes); + } + // clang-format on +#undef DOCTEST_SET_ATTR +#endif // DOCTEST_CONFIG_COLORS_WINDOWS + return s; + } + } // namespace Color + + std::vector& getExceptionTranslators() { + static std::vector data; + return data; + } + + void registerExceptionTranslatorImpl(const IExceptionTranslator* translateFunction) { + if(std::find(getExceptionTranslators().begin(), getExceptionTranslators().end(), + translateFunction) == getExceptionTranslators().end()) + getExceptionTranslators().push_back(translateFunction); + } + + String translateActiveException() { +#ifndef DOCTEST_CONFIG_NO_EXCEPTIONS + String res; + std::vector& translators = getExceptionTranslators(); + for(size_t i = 0; i < translators.size(); ++i) + if(translators[i]->translate(res)) + return res; + // clang-format off + try { + throw; + } catch(std::exception& ex) { + return ex.what(); + } catch(std::string& msg) { + return msg.c_str(); + } catch(const char* msg) { + return msg; + } catch(...) { + return "unknown exception"; + } +// clang-format on +#else // DOCTEST_CONFIG_NO_EXCEPTIONS + return ""; +#endif // DOCTEST_CONFIG_NO_EXCEPTIONS + } + + void writeStringToStream(std::ostream* s, const String& str) { *s << str; } + +#ifdef DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING + void toStream(std::ostream* s, char* in) { *s << in; } + void toStream(std::ostream* s, const char* in) { *s << in; } +#endif // DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING + void toStream(std::ostream* s, bool in) { *s << std::boolalpha << in << std::noboolalpha; } + void toStream(std::ostream* s, float in) { *s << in; } + void toStream(std::ostream* s, double in) { *s << in; } + void toStream(std::ostream* s, double long in) { *s << in; } + + void toStream(std::ostream* s, char in) { *s << in; } + void toStream(std::ostream* s, char signed in) { *s << in; } + void toStream(std::ostream* s, char unsigned in) { *s << in; } + void toStream(std::ostream* s, int short in) { *s << in; } + void toStream(std::ostream* s, int short unsigned in) { *s << in; } + void toStream(std::ostream* s, int in) { *s << in; } + void toStream(std::ostream* s, int unsigned in) { *s << in; } + void toStream(std::ostream* s, int long in) { *s << in; } + void toStream(std::ostream* s, int long unsigned in) { *s << in; } + +#ifdef DOCTEST_CONFIG_WITH_LONG_LONG + void toStream(std::ostream* s, int long long in) { *s << in; } + void toStream(std::ostream* s, int long long unsigned in) { *s << in; } +#endif // DOCTEST_CONFIG_WITH_LONG_LONG + + void addToContexts(IContextScope* ptr) { contextState->contexts.push_back(ptr); } + void popFromContexts() { contextState->contexts.pop_back(); } + DOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH(4996) // std::uncaught_exception is deprecated in C++17 + DOCTEST_GCC_SUPPRESS_WARNING_WITH_PUSH("-Wdeprecated-declarations") + void useContextIfExceptionOccurred(IContextScope* ptr) { + if(std::uncaught_exception()) { + std::ostringstream s; + ptr->build(&s); + contextState->exceptionalContexts.push_back(s.str()); + } + } + DOCTEST_GCC_SUPPRESS_WARNING_POP + DOCTEST_MSVC_SUPPRESS_WARNING_POP + + void printSummary(std::ostream& s); + +#if !defined(DOCTEST_CONFIG_POSIX_SIGNALS) && !defined(DOCTEST_CONFIG_WINDOWS_SEH) + void reportFatal(const std::string&) {} + struct FatalConditionHandler + { + void reset() {} + }; +#else // DOCTEST_CONFIG_POSIX_SIGNALS || DOCTEST_CONFIG_WINDOWS_SEH + + void reportFatal(const std::string&); + +#ifdef DOCTEST_PLATFORM_WINDOWS + + struct SignalDefs + { + DWORD id; + const char* name; + }; + // There is no 1-1 mapping between signals and windows exceptions. + // Windows can easily distinguish between SO and SigSegV, + // but SigInt, SigTerm, etc are handled differently. + SignalDefs signalDefs[] = { + {EXCEPTION_ILLEGAL_INSTRUCTION, "SIGILL - Illegal instruction signal"}, + {EXCEPTION_STACK_OVERFLOW, "SIGSEGV - Stack overflow"}, + {EXCEPTION_ACCESS_VIOLATION, "SIGSEGV - Segmentation violation signal"}, + {EXCEPTION_INT_DIVIDE_BY_ZERO, "Divide by zero error"}, + }; + + struct FatalConditionHandler + { + static LONG CALLBACK handleVectoredException(PEXCEPTION_POINTERS ExceptionInfo) { + for(size_t i = 0; i < DOCTEST_COUNTOF(signalDefs); ++i) { + if(ExceptionInfo->ExceptionRecord->ExceptionCode == signalDefs[i].id) { + reportFatal(signalDefs[i].name); + } + } + // If its not an exception we care about, pass it along. + // This stops us from eating debugger breaks etc. + return EXCEPTION_CONTINUE_SEARCH; + } + + FatalConditionHandler() { + isSet = true; + // 32k seems enough for doctest to handle stack overflow, + // but the value was found experimentally, so there is no strong guarantee + guaranteeSize = 32 * 1024; + exceptionHandlerHandle = 0; + // Register as first handler in current chain + exceptionHandlerHandle = AddVectoredExceptionHandler(1, handleVectoredException); + // Pass in guarantee size to be filled + SetThreadStackGuarantee(&guaranteeSize); + } + + static void reset() { + if(isSet) { + // Unregister handler and restore the old guarantee + RemoveVectoredExceptionHandler(exceptionHandlerHandle); + SetThreadStackGuarantee(&guaranteeSize); + exceptionHandlerHandle = 0; + isSet = false; + } + } + + ~FatalConditionHandler() { reset(); } + + private: + static bool isSet; + static ULONG guaranteeSize; + static PVOID exceptionHandlerHandle; + }; + + bool FatalConditionHandler::isSet = false; + ULONG FatalConditionHandler::guaranteeSize = 0; + PVOID FatalConditionHandler::exceptionHandlerHandle = 0; + +#else // DOCTEST_PLATFORM_WINDOWS + + struct SignalDefs + { + int id; + const char* name; + }; + SignalDefs signalDefs[] = {{SIGINT, "SIGINT - Terminal interrupt signal"}, + {SIGILL, "SIGILL - Illegal instruction signal"}, + {SIGFPE, "SIGFPE - Floating point error signal"}, + {SIGSEGV, "SIGSEGV - Segmentation violation signal"}, + {SIGTERM, "SIGTERM - Termination request signal"}, + {SIGABRT, "SIGABRT - Abort (abnormal termination) signal"}}; + + struct FatalConditionHandler + { + static bool isSet; + static struct sigaction oldSigActions[DOCTEST_COUNTOF(signalDefs)]; + static stack_t oldSigStack; + static char altStackMem[4 * SIGSTKSZ]; + + static void handleSignal(int sig) { + std::string name = ""; + for(std::size_t i = 0; i < DOCTEST_COUNTOF(signalDefs); ++i) { + SignalDefs& def = signalDefs[i]; + if(sig == def.id) { + name = def.name; + break; + } + } + reset(); + reportFatal(name); + raise(sig); + } + + FatalConditionHandler() { + isSet = true; + stack_t sigStack; + sigStack.ss_sp = altStackMem; + sigStack.ss_size = sizeof(altStackMem); + sigStack.ss_flags = 0; + sigaltstack(&sigStack, &oldSigStack); + struct sigaction sa = {0}; + + sa.sa_handler = handleSignal; // NOLINT + sa.sa_flags = SA_ONSTACK; + for(std::size_t i = 0; i < DOCTEST_COUNTOF(signalDefs); ++i) { + sigaction(signalDefs[i].id, &sa, &oldSigActions[i]); + } + } + + ~FatalConditionHandler() { reset(); } + static void reset() { + if(isSet) { + // Set signals back to previous values -- hopefully nobody overwrote them in the meantime + for(std::size_t i = 0; i < DOCTEST_COUNTOF(signalDefs); ++i) { + sigaction(signalDefs[i].id, &oldSigActions[i], 0); + } + // Return the old stack + sigaltstack(&oldSigStack, 0); + isSet = false; + } + } + }; + + bool FatalConditionHandler::isSet = false; + struct sigaction FatalConditionHandler::oldSigActions[DOCTEST_COUNTOF(signalDefs)] = {}; + stack_t FatalConditionHandler::oldSigStack = {}; + char FatalConditionHandler::altStackMem[] = {}; + +#endif // DOCTEST_PLATFORM_WINDOWS +#endif // DOCTEST_CONFIG_POSIX_SIGNALS || DOCTEST_CONFIG_WINDOWS_SEH + + void separator_to_stream(std::ostream& s) { + s << Color::Yellow + << "===============================================================================\n"; + } + + // depending on the current options this will remove the path of filenames + const char* fileForOutput(const char* file) { + if(contextState->no_path_in_filenames) { + const char* back = std::strrchr(file, '\\'); + const char* forward = std::strrchr(file, '/'); + if(back || forward) { + if(back > forward) + forward = back; + return forward + 1; + } + } + return file; + } + + void file_line_to_stream(std::ostream& s, const char* file, int line, const char* tail = "") { + s << Color::LightGrey << fileForOutput(file) << (contextState->gnu_file_line ? ":" : "(") + << (contextState->no_line_numbers ? 0 : line) // 0 or the real num depending on the option + << (contextState->gnu_file_line ? ":" : "):") << tail; + } + + const char* getSuccessOrFailString(bool success, assertType::Enum at, const char* success_str) { + if(success) + return success_str; + if(at & assertType::is_warn) //!OCLINT bitwise operator in conditional + return "WARNING: "; + if(at & assertType::is_check) //!OCLINT bitwise operator in conditional + return "ERROR: "; + if(at & assertType::is_require) //!OCLINT bitwise operator in conditional + return "FATAL ERROR: "; + return ""; + } + + Color::Code getSuccessOrFailColor(bool success, assertType::Enum at) { + return success ? Color::BrightGreen : + (at & assertType::is_warn) ? Color::Yellow : Color::Red; + } + + void successOrFailColoredStringToStream(std::ostream& s, bool success, assertType::Enum at, + const char* success_str = "SUCCESS: ") { + s << getSuccessOrFailColor(success, at) << getSuccessOrFailString(success, at, success_str); + } + +#ifdef DOCTEST_PLATFORM_MAC +#include +#include +#include + // The following function is taken directly from the following technical note: + // http://developer.apple.com/library/mac/#qa/qa2004/qa1361.html + // Returns true if the current process is being debugged (either + // running under the debugger or has a debugger attached post facto). + bool isDebuggerActive() { + int mib[4]; + kinfo_proc info; + size_t size; + // Initialize the flags so that, if sysctl fails for some bizarre + // reason, we get a predictable result. + info.kp_proc.p_flag = 0; + // Initialize mib, which tells sysctl the info we want, in this case + // we're looking for information about a specific process ID. + mib[0] = CTL_KERN; + mib[1] = KERN_PROC; + mib[2] = KERN_PROC_PID; + mib[3] = getpid(); + // Call sysctl. + size = sizeof(info); + if(sysctl(mib, DOCTEST_COUNTOF(mib), &info, &size, 0, 0) != 0) { + fprintf(stderr, "\n** Call to sysctl failed - unable to determine if debugger is " + "active **\n\n"); + return false; + } + // We're being debugged if the P_TRACED flag is set. + return ((info.kp_proc.p_flag & P_TRACED) != 0); + } +#elif DOCTEST_MSVC || defined(__MINGW32__) + bool isDebuggerActive() { return ::IsDebuggerPresent() != 0; } +#else + bool isDebuggerActive() { return false; } +#endif // Platform + +#ifdef DOCTEST_PLATFORM_WINDOWS + void myOutputDebugString(const String& text) { ::OutputDebugStringA(text.c_str()); } +#else + // TODO: integration with XCode and other IDEs + void myOutputDebugString(const String&) {} +#endif // Platform + + void printToDebugConsole(const String& text) { + if(isDebuggerActive()) + myOutputDebugString(text); + } + + void addFailedAssert(assertType::Enum at) { + if((at & assertType::is_warn) == 0) { //!OCLINT bitwise operator in conditional + contextState->numFailedAssertions++; + contextState->numFailedAssertionsForCurrentTestcase++; + contextState->hasCurrentTestFailed = true; + } + } + + std::ostream& operator<<(std::ostream& s, const std::vector& contexts) { + if(!contexts.empty()) + s << Color::None << " logged: "; + for(size_t i = 0; i < contexts.size(); ++i) { + s << (i == 0 ? "" : " "); + contexts[i]->build(&s); + s << "\n"; + } + s << "\n"; + return s; + } + + void logTestStart(std::ostream& s, const TestCase& tc) { + separator_to_stream(s); + file_line_to_stream(s, tc.m_file, tc.m_line, "\n"); + if(tc.m_description) + s << Color::Yellow << "DESCRIPTION: " << Color::None << tc.m_description << "\n"; + if(tc.m_test_suite && tc.m_test_suite[0] != '\0') + s << Color::Yellow << "TEST SUITE: " << Color::None << tc.m_test_suite << "\n"; + if(strncmp(tc.m_name, " Scenario:", 11) != 0) + s << Color::None << "TEST CASE: "; + s << Color::None << tc.m_name << "\n"; + + std::vector& subcasesStack = contextState->subcasesStack; + for(unsigned i = 0; i < subcasesStack.size(); ++i) + if(subcasesStack[i].m_signature.m_name[0] != '\0') + s << " " << subcasesStack[i].m_signature.m_name << "\n"; + + s << "\n"; + } + + void logTestEnd() {} + + void logTestException_impl(std::ostream& s, const TestCase& tc, const String& str, bool crash) { + file_line_to_stream(s, tc.m_file, tc.m_line, " "); + successOrFailColoredStringToStream(s, false, + crash ? assertType::is_require : assertType::is_check); + s << Color::Red << (crash ? "test case CRASHED: " : "test case THREW exception: ") + << Color::Cyan << str << "\n"; + + if(!contextState->exceptionalContexts.empty()) { + s << Color::None << " logged: "; + for(size_t i = contextState->exceptionalContexts.size(); i > 0; --i) + s << (i == contextState->exceptionalContexts.size() ? "" : " ") + << contextState->exceptionalContexts[i - 1] << "\n"; + } + s << "\n"; + } + + void logTestException(const TestCase& tc, const String& what, bool crash) { + logTestException_impl(std::cout, tc, what, crash); + DOCTEST_PRINT_TO_OUTPUT_WINDOW_IN_IDE_BEGIN; + logTestException_impl(oss, tc, what, crash); + DOCTEST_PRINT_TO_OUTPUT_WINDOW_IN_IDE_END; + } + +#if defined(DOCTEST_CONFIG_POSIX_SIGNALS) || defined(DOCTEST_CONFIG_WINDOWS_SEH) + void reportFatal(const std::string& message) { + DOCTEST_LOG_START(std::cout); + + contextState->numAssertions += contextState->numAssertionsForCurrentTestcase; + logTestException(*contextState->currentTest, message.c_str(), true); + logTestEnd(); + contextState->numFailed++; + + printSummary(std::cout); + } +#endif // DOCTEST_CONFIG_POSIX_SIGNALS || DOCTEST_CONFIG_WINDOWS_SEH + + void logAssert_impl(std::ostream& s, bool passed, const String& dec, bool threw, + const String& ex, const char* expr, assertType::Enum at, const char* file, + int line) { + file_line_to_stream(s, file, line, " "); + successOrFailColoredStringToStream(s, passed, at); + s << Color::Cyan << assertString(at) << "( " << expr << " ) " << Color::None + << (threw ? "THREW exception: " : (passed ? "is correct!\n" : "is NOT correct!\n")); + if(threw) + s << ex << "\n"; + else + s << " values: " << assertString(at) << "( " << dec << " )\n"; + s << contextState->contexts; + } + + void logAssert(bool passed, const String& dec, bool threw, const String& ex, const char* expr, + assertType::Enum at, const char* file, int line) { + logAssert_impl(std::cout, passed, dec, threw, ex, expr, at, file, line); + DOCTEST_PRINT_TO_OUTPUT_WINDOW_IN_IDE_BEGIN; + logAssert_impl(oss, passed, dec, threw, ex, expr, at, file, line); + DOCTEST_PRINT_TO_OUTPUT_WINDOW_IN_IDE_END; + } + + void logAssertThrows_impl(std::ostream& s, bool threw, const char* expr, assertType::Enum at, + const char* file, int line) { + file_line_to_stream(s, file, line, " "); + successOrFailColoredStringToStream(s, threw, at); + s << Color::Cyan << assertString(at) << "( " << expr << " ) " << Color::None + << (threw ? "threw as expected!" : "did NOT throw at all!") << "\n"; + s << contextState->contexts; + } + + void logAssertThrows(bool threw, const char* expr, assertType::Enum at, const char* file, + int line) { + logAssertThrows_impl(std::cout, threw, expr, at, file, line); + DOCTEST_PRINT_TO_OUTPUT_WINDOW_IN_IDE_BEGIN; + logAssertThrows_impl(oss, threw, expr, at, file, line); + DOCTEST_PRINT_TO_OUTPUT_WINDOW_IN_IDE_END; + } + + void logAssertThrowsAs_impl(std::ostream& s, bool threw, bool threw_as, const char* as, + const String& ex, const char* expr, assertType::Enum at, + const char* file, int line) { + file_line_to_stream(s, file, line, " "); + successOrFailColoredStringToStream(s, threw_as, at); + s << Color::Cyan << assertString(at) << "( " << expr << ", " << as << " ) " << Color::None + << (threw ? (threw_as ? "threw as expected!" : "threw a DIFFERENT exception: ") : + "did NOT throw at all!") + << Color::Cyan << ex << "\n"; + s << contextState->contexts; + } + + void logAssertThrowsAs(bool threw, bool threw_as, const char* as, const String& ex, + const char* expr, assertType::Enum at, const char* file, int line) { + logAssertThrowsAs_impl(std::cout, threw, threw_as, as, ex, expr, at, file, line); + DOCTEST_PRINT_TO_OUTPUT_WINDOW_IN_IDE_BEGIN; + logAssertThrowsAs_impl(oss, threw, threw_as, as, ex, expr, at, file, line); + DOCTEST_PRINT_TO_OUTPUT_WINDOW_IN_IDE_END; + } + + void logAssertNothrow_impl(std::ostream& s, bool threw, const String& ex, const char* expr, + assertType::Enum at, const char* file, int line) { + file_line_to_stream(s, file, line, " "); + successOrFailColoredStringToStream(s, !threw, at); + s << Color::Cyan << assertString(at) << "( " << expr << " ) " << Color::None + << (threw ? "THREW exception: " : "didn't throw!") << Color::Cyan << ex << "\n"; + s << contextState->contexts; + } + + void logAssertNothrow(bool threw, const String& ex, const char* expr, assertType::Enum at, + const char* file, int line) { + logAssertNothrow_impl(std::cout, threw, ex, expr, at, file, line); + DOCTEST_PRINT_TO_OUTPUT_WINDOW_IN_IDE_BEGIN; + logAssertNothrow_impl(oss, threw, ex, expr, at, file, line); + DOCTEST_PRINT_TO_OUTPUT_WINDOW_IN_IDE_END; + } + + ResultBuilder::ResultBuilder(assertType::Enum at, const char* file, int line, const char* expr, + const char* exception_type) + : m_assert_type(at) + , m_file(file) + , m_line(line) + , m_expr(expr) + , m_exception_type(exception_type) + , m_threw(false) + , m_threw_as(false) + , m_failed(false) { +#if DOCTEST_MSVC + if(m_expr[0] == ' ') // this happens when variadic macros are disabled under MSVC + ++m_expr; +#endif // MSVC + } + + ResultBuilder::~ResultBuilder() {} + + void ResultBuilder::unexpectedExceptionOccurred() { + m_threw = true; + + m_exception = translateActiveException(); + } + + bool ResultBuilder::log() { + if((m_assert_type & assertType::is_warn) == 0) //!OCLINT bitwise operator in conditional + contextState->numAssertionsForCurrentTestcase++; + + if(m_assert_type & assertType::is_throws) { //!OCLINT bitwise operator in conditional + m_failed = !m_threw; + } else if(m_assert_type & //!OCLINT bitwise operator in conditional + assertType::is_throws_as) { + m_failed = !m_threw_as; + } else if(m_assert_type & //!OCLINT bitwise operator in conditional + assertType::is_nothrow) { + m_failed = m_threw; + } else { + m_failed = m_result; + } + + if(m_failed || contextState->success) { + DOCTEST_LOG_START(std::cout); + + if(m_assert_type & assertType::is_throws) { //!OCLINT bitwise operator in conditional + logAssertThrows(m_threw, m_expr, m_assert_type, m_file, m_line); + } else if(m_assert_type & //!OCLINT bitwise operator in conditional + assertType::is_throws_as) { + logAssertThrowsAs(m_threw, m_threw_as, m_exception_type, m_exception, m_expr, + m_assert_type, m_file, m_line); + } else if(m_assert_type & //!OCLINT bitwise operator in conditional + assertType::is_nothrow) { + logAssertNothrow(m_threw, m_exception, m_expr, m_assert_type, m_file, m_line); + } else { + logAssert(m_result.m_passed, m_result.m_decomposition, m_threw, m_exception, m_expr, + m_assert_type, m_file, m_line); + } + } + + if(m_failed) + addFailedAssert(m_assert_type); + + return m_failed && isDebuggerActive() && !contextState->no_breaks; // break into debugger + } + + void ResultBuilder::react() const { + if(m_failed && checkIfShouldThrow(m_assert_type)) + throwException(); + } + + MessageBuilder::MessageBuilder(const char* file, int line, assertType::Enum severity) + : m_stream(createStream()) + , m_file(file) + , m_line(line) + , m_severity(severity) {} + + void MessageBuilder::log(std::ostream& s) { + file_line_to_stream(s, m_file, m_line, " "); + s << getSuccessOrFailColor(false, m_severity) + << getSuccessOrFailString(m_severity & assertType::is_warn, m_severity, "MESSAGE: "); + s << Color::None << getStreamResult(m_stream) << "\n"; + s << contextState->contexts; + } + + bool MessageBuilder::log() { + DOCTEST_LOG_START(std::cout); + + log(std::cout); + DOCTEST_PRINT_TO_OUTPUT_WINDOW_IN_IDE_BEGIN; + log(oss); + DOCTEST_PRINT_TO_OUTPUT_WINDOW_IN_IDE_END; + const bool isWarn = m_severity & assertType::is_warn; + + // warn is just a message in this context so we dont treat it as an assert + if(!isWarn) { + contextState->numAssertionsForCurrentTestcase++; + addFailedAssert(m_severity); + } + + return isDebuggerActive() && !contextState->no_breaks && !isWarn; // break into debugger + } + + void MessageBuilder::react() { + if(m_severity & assertType::is_require) //!OCLINT bitwise operator in conditional + throwException(); + } + + MessageBuilder::~MessageBuilder() { freeStream(m_stream); } + + // the implementation of parseFlag() + bool parseFlagImpl(int argc, const char* const* argv, const char* pattern) { + for(int i = argc - 1; i >= 0; --i) { + const char* temp = std::strstr(argv[i], pattern); + if(temp && strlen(temp) == strlen(pattern)) { + // eliminate strings in which the chars before the option are not '-' + bool noBadCharsFound = true; //!OCLINT prefer early exits and continue + while(temp != argv[i]) { + if(*--temp != '-') { + noBadCharsFound = false; + break; + } + } + if(noBadCharsFound && argv[i][0] == '-') + return true; + } + } + return false; + } + + // locates a flag on the command line + bool parseFlag(int argc, const char* const* argv, const char* pattern) { +#ifndef DOCTEST_CONFIG_NO_UNPREFIXED_OPTIONS + if(!parseFlagImpl(argc, argv, pattern)) + return parseFlagImpl(argc, argv, pattern + 3); // 3 for "dt-" + return true; +#else // DOCTEST_CONFIG_NO_UNPREFIXED_OPTIONS + return parseFlagImpl(argc, argv, pattern); +#endif // DOCTEST_CONFIG_NO_UNPREFIXED_OPTIONS + } + + // the implementation of parseOption() + bool parseOptionImpl(int argc, const char* const* argv, const char* pattern, String& res) { + for(int i = argc - 1; i >= 0; --i) { + const char* temp = std::strstr(argv[i], pattern); + if(temp) { //!OCLINT prefer early exits and continue + // eliminate matches in which the chars before the option are not '-' + bool noBadCharsFound = true; + const char* curr = argv[i]; + while(curr != temp) { + if(*curr++ != '-') { + noBadCharsFound = false; + break; + } + } + if(noBadCharsFound && argv[i][0] == '-') { + temp += strlen(pattern); + const unsigned len = strlen(temp); + if(len) { + res = temp; + return true; + } + } + } + } + return false; + } + + // parses an option and returns the string after the '=' character + bool parseOption(int argc, const char* const* argv, const char* pattern, String& res, + const String& defaultVal = String()) { + res = defaultVal; +#ifndef DOCTEST_CONFIG_NO_UNPREFIXED_OPTIONS + if(!parseOptionImpl(argc, argv, pattern, res)) + return parseOptionImpl(argc, argv, pattern + 3, res); // 3 for "dt-" + return true; +#else // DOCTEST_CONFIG_NO_UNPREFIXED_OPTIONS + return parseOptionImpl(argc, argv, pattern, res); +#endif // DOCTEST_CONFIG_NO_UNPREFIXED_OPTIONS + } + + // parses a comma separated list of words after a pattern in one of the arguments in argv + bool parseCommaSepArgs(int argc, const char* const* argv, const char* pattern, + std::vector& res) { + String filtersString; + if(parseOption(argc, argv, pattern, filtersString)) { + // tokenize with "," as a separator + // cppcheck-suppress strtokCalled + char* pch = std::strtok(filtersString.c_str(), ","); // modifies the string + while(pch != 0) { + if(strlen(pch)) + res.push_back(pch); + // uses the strtok() internal state to go to the next token + // cppcheck-suppress strtokCalled + pch = std::strtok(0, ","); + } + return true; + } + return false; + } + + enum optionType + { + option_bool, + option_int + }; + + // parses an int/bool option from the command line + bool parseIntOption(int argc, const char* const* argv, const char* pattern, optionType type, + int& res) { + String parsedValue; + if(!parseOption(argc, argv, pattern, parsedValue)) + return false; + + if(type == 0) { + // boolean + const char positive[][5] = {"1", "true", "on", "yes"}; // 5 - strlen("true") + 1 + const char negative[][6] = {"0", "false", "off", "no"}; // 6 - strlen("false") + 1 + + // if the value matches any of the positive/negative possibilities + for(unsigned i = 0; i < 4; i++) { + if(parsedValue.compare(positive[i], true) == 0) { + res = 1; //!OCLINT parameter reassignment + return true; + } + if(parsedValue.compare(negative[i], true) == 0) { + res = 0; //!OCLINT parameter reassignment + return true; + } + } + } else { + // integer + int theInt = std::atoi(parsedValue.c_str()); // NOLINT + if(theInt != 0) { + res = theInt; //!OCLINT parameter reassignment + return true; + } + } + return false; + } + + void printVersion(std::ostream& s) { + if(contextState->no_version == false) + s << Color::Cyan << "[doctest] " << Color::None << "doctest version is \"" + << DOCTEST_VERSION_STR << "\"\n"; + } + + void printHelp(std::ostream& s) { + printVersion(s); + // clang-format off + s << Color::Cyan << "[doctest]\n" << Color::None; + s << Color::Cyan << "[doctest] " << Color::None; + s << "boolean values: \"1/on/yes/true\" or \"0/off/no/false\"\n"; + s << Color::Cyan << "[doctest] " << Color::None; + s << "filter values: \"str1,str2,str3\" (comma separated strings)\n"; + s << Color::Cyan << "[doctest]\n" << Color::None; + s << Color::Cyan << "[doctest] " << Color::None; + s << "filters use wildcards for matching strings\n"; + s << Color::Cyan << "[doctest] " << Color::None; + s << "something passes a filter if any of the strings in a filter matches\n"; + s << Color::Cyan << "[doctest]\n" << Color::None; + s << Color::Cyan << "[doctest] " << Color::None; + s << "ALL FLAGS, OPTIONS AND FILTERS ALSO AVAILABLE WITH A \"dt-\" PREFIX!!!\n"; + s << Color::Cyan << "[doctest]\n" << Color::None; + s << Color::Cyan << "[doctest] " << Color::None; + s << "Query flags - the program quits after them. Available:\n\n"; + s << " -?, --help, -h prints this message\n"; + s << " -v, --version prints the version\n"; + s << " -c, --count prints the number of matching tests\n"; + s << " -ltc, --list-test-cases lists all matching tests by name\n"; + s << " -lts, --list-test-suites lists all matching test suites\n\n"; + // ================================================================================== << 79 + s << Color::Cyan << "[doctest] " << Color::None; + s << "The available / options/filters are:\n\n"; + s << " -tc, --test-case= filters tests by their name\n"; + s << " -tce, --test-case-exclude= filters OUT tests by their name\n"; + s << " -sf, --source-file= filters tests by their file\n"; + s << " -sfe, --source-file-exclude= filters OUT tests by their file\n"; + s << " -ts, --test-suite= filters tests by their test suite\n"; + s << " -tse, --test-suite-exclude= filters OUT tests by their test suite\n"; + s << " -sc, --subcase= filters subcases by their name\n"; + s << " -sce, --subcase-exclude= filters OUT subcases by their name\n"; + s << " -ob, --order-by= how the tests should be ordered\n"; + s << " - by [file/suite/name/rand]\n"; + s << " -rs, --rand-seed= seed for random ordering\n"; + s << " -f, --first= the first test passing the filters to\n"; + s << " execute - for range-based execution\n"; + s << " -l, --last= the last test passing the filters to\n"; + s << " execute - for range-based execution\n"; + s << " -aa, --abort-after= stop after failed assertions\n"; + s << " -scfl,--subcase-filter-levels= apply filters for the first levels\n"; + s << Color::Cyan << "\n[doctest] " << Color::None; + s << "Bool options - can be used like flags and true is assumed. Available:\n\n"; + s << " -s, --success= include successful assertions in output\n"; + s << " -cs, --case-sensitive= filters being treated as case sensitive\n"; + s << " -e, --exit= exits after the tests finish\n"; + s << " -d, --duration= prints the time duration of each test\n"; + s << " -nt, --no-throw= skips exceptions-related assert checks\n"; + s << " -ne, --no-exitcode= returns (or exits) always with success\n"; + s << " -nr, --no-run= skips all runtime doctest operations\n"; + s << " -nv, --no-version= omit the framework version in the output\n"; + s << " -nc, --no-colors= disables colors in output\n"; + s << " -fc, --force-colors= use colors even when not in a tty\n"; + s << " -nb, --no-breaks= disables breakpoints in debuggers\n"; + s << " -ns, --no-skip= don't skip test cases marked as skip\n"; + s << " -gfl, --gnu-file-line= :n: vs (n): for line numbers in output\n"; + s << " -npf, --no-path-filenames= only filenames and no paths in output\n"; + s << " -nln, --no-line-numbers= 0 instead of real line numbers in output\n"; + // ================================================================================== << 79 + // clang-format on + + s << Color::Cyan << "\n[doctest] " << Color::None; + s << "for more information visit the project documentation\n\n"; + } + + void printSummary(std::ostream& s) { + const ContextState* p = contextState; + + separator_to_stream(s); + + if(p->count || p->list_test_cases) { + s << Color::Cyan << "[doctest] " << Color::None + << "unskipped test cases passing the current filters: " << p->numTestsPassingFilters + << "\n"; + } else if(p->list_test_suites) { + s << Color::Cyan << "[doctest] " << Color::None + << "unskipped test cases passing the current filters: " << p->numTestsPassingFilters + << "\n"; + s << Color::Cyan << "[doctest] " << Color::None + << "test suites with unskipped test cases passing the current filters: " + << p->numTestSuitesPassingFilters << "\n"; + } else { + const bool anythingFailed = p->numFailed > 0 || p->numFailedAssertions > 0; + s << Color::Cyan << "[doctest] " << Color::None << "test cases: " << std::setw(6) + << p->numTestsPassingFilters << " | " + << ((p->numTestsPassingFilters == 0 || anythingFailed) ? Color::None : Color::Green) + << std::setw(6) << p->numTestsPassingFilters - p->numFailed << " passed" + << Color::None << " | " << (p->numFailed > 0 ? Color::Red : Color::None) + << std::setw(6) << p->numFailed << " failed" << Color::None << " | "; + if(p->no_skipped_summary == false) { + const int numSkipped = static_cast(getRegisteredTests().size()) - + p->numTestsPassingFilters; + s << (numSkipped == 0 ? Color::None : Color::Yellow) << std::setw(6) << numSkipped + << " skipped" << Color::None; + } + s << "\n"; + s << Color::Cyan << "[doctest] " << Color::None << "assertions: " << std::setw(6) + << p->numAssertions << " | " + << ((p->numAssertions == 0 || anythingFailed) ? Color::None : Color::Green) + << std::setw(6) << (p->numAssertions - p->numFailedAssertions) << " passed" + << Color::None << " | " << (p->numFailedAssertions > 0 ? Color::Red : Color::None) + << std::setw(6) << p->numFailedAssertions << " failed" << Color::None << " |\n"; + s << Color::Cyan << "[doctest] " << Color::None + << "Status: " << (p->numFailed > 0 ? Color::Red : Color::Green) + << ((p->numFailed > 0) ? "FAILURE!\n" : "SUCCESS!\n"); + } + + // remove any coloring + s << Color::None; + } +} // namespace detail + +bool isRunningInTest() { return detail::contextState != 0; } + +Context::Context(int argc, const char* const* argv) + : p(new detail::ContextState) { + parseArgs(argc, argv, true); +} + +Context::~Context() { delete p; } + +void Context::applyCommandLine(int argc, const char* const* argv) { parseArgs(argc, argv); } + +// parses args +void Context::parseArgs(int argc, const char* const* argv, bool withDefaults) { + using namespace detail; + + // clang-format off + parseCommaSepArgs(argc, argv, "dt-source-file=", p->filters[0]); + parseCommaSepArgs(argc, argv, "dt-sf=", p->filters[0]); + parseCommaSepArgs(argc, argv, "dt-source-file-exclude=",p->filters[1]); + parseCommaSepArgs(argc, argv, "dt-sfe=", p->filters[1]); + parseCommaSepArgs(argc, argv, "dt-test-suite=", p->filters[2]); + parseCommaSepArgs(argc, argv, "dt-ts=", p->filters[2]); + parseCommaSepArgs(argc, argv, "dt-test-suite-exclude=", p->filters[3]); + parseCommaSepArgs(argc, argv, "dt-tse=", p->filters[3]); + parseCommaSepArgs(argc, argv, "dt-test-case=", p->filters[4]); + parseCommaSepArgs(argc, argv, "dt-tc=", p->filters[4]); + parseCommaSepArgs(argc, argv, "dt-test-case-exclude=", p->filters[5]); + parseCommaSepArgs(argc, argv, "dt-tce=", p->filters[5]); + parseCommaSepArgs(argc, argv, "dt-subcase=", p->filters[6]); + parseCommaSepArgs(argc, argv, "dt-sc=", p->filters[6]); + parseCommaSepArgs(argc, argv, "dt-subcase-exclude=", p->filters[7]); + parseCommaSepArgs(argc, argv, "dt-sce=", p->filters[7]); + // clang-format on + + int intRes = 0; + String strRes; + +#define DOCTEST_PARSE_AS_BOOL_OR_FLAG(name, sname, var, default) \ + if(parseIntOption(argc, argv, name "=", option_bool, intRes) || \ + parseIntOption(argc, argv, sname "=", option_bool, intRes)) \ + p->var = !!intRes; \ + else if(parseFlag(argc, argv, name) || parseFlag(argc, argv, sname)) \ + p->var = true; \ + else if(withDefaults) \ + p->var = default + +#define DOCTEST_PARSE_INT_OPTION(name, sname, var, default) \ + if(parseIntOption(argc, argv, name "=", option_int, intRes) || \ + parseIntOption(argc, argv, sname "=", option_int, intRes)) \ + p->var = intRes; \ + else if(withDefaults) \ + p->var = default + +#define DOCTEST_PARSE_STR_OPTION(name, sname, var, default) \ + if(parseOption(argc, argv, name "=", strRes, default) || \ + parseOption(argc, argv, sname "=", strRes, default) || withDefaults) \ + p->var = strRes + + // clang-format off + DOCTEST_PARSE_STR_OPTION("dt-order-by", "dt-ob", order_by, "file"); + DOCTEST_PARSE_INT_OPTION("dt-rand-seed", "dt-rs", rand_seed, 0); + + DOCTEST_PARSE_INT_OPTION("dt-first", "dt-f", first, 1); + DOCTEST_PARSE_INT_OPTION("dt-last", "dt-l", last, 0); + + DOCTEST_PARSE_INT_OPTION("dt-abort-after", "dt-aa", abort_after, 0); + DOCTEST_PARSE_INT_OPTION("dt-subcase-filter-levels", "dt-scfl", subcase_filter_levels, 2000000000); + + DOCTEST_PARSE_AS_BOOL_OR_FLAG("dt-success", "dt-s", success, false); + DOCTEST_PARSE_AS_BOOL_OR_FLAG("dt-case-sensitive", "dt-cs", case_sensitive, false); + DOCTEST_PARSE_AS_BOOL_OR_FLAG("dt-exit", "dt-e", exit, false); + DOCTEST_PARSE_AS_BOOL_OR_FLAG("dt-duration", "dt-d", duration, false); + DOCTEST_PARSE_AS_BOOL_OR_FLAG("dt-no-throw", "dt-nt", no_throw, false); + DOCTEST_PARSE_AS_BOOL_OR_FLAG("dt-no-exitcode", "dt-ne", no_exitcode, false); + DOCTEST_PARSE_AS_BOOL_OR_FLAG("dt-no-run", "dt-nr", no_run, false); + DOCTEST_PARSE_AS_BOOL_OR_FLAG("dt-no-version", "dt-nv", no_version, false); + DOCTEST_PARSE_AS_BOOL_OR_FLAG("dt-no-colors", "dt-nc", no_colors, false); + DOCTEST_PARSE_AS_BOOL_OR_FLAG("dt-force-colors", "dt-fc", force_colors, false); + DOCTEST_PARSE_AS_BOOL_OR_FLAG("dt-no-breaks", "dt-nb", no_breaks, false); + DOCTEST_PARSE_AS_BOOL_OR_FLAG("dt-no-skip", "dt-ns", no_skip, false); + DOCTEST_PARSE_AS_BOOL_OR_FLAG("dt-gnu-file-line", "dt-gfl", gnu_file_line, bool(DOCTEST_GCC) || bool(DOCTEST_CLANG)); + DOCTEST_PARSE_AS_BOOL_OR_FLAG("dt-no-path-filenames", "dt-npf", no_path_in_filenames, false); + DOCTEST_PARSE_AS_BOOL_OR_FLAG("dt-no-line-numbers", "dt-nln", no_line_numbers, false); + DOCTEST_PARSE_AS_BOOL_OR_FLAG("dt-no-skipped-summary", "dt-nss", no_skipped_summary, false); + // clang-format on + +#undef DOCTEST_PARSE_STR_OPTION +#undef DOCTEST_PARSE_INT_OPTION +#undef DOCTEST_PARSE_AS_BOOL_OR_FLAG + + if(withDefaults) { + p->help = false; + p->version = false; + p->count = false; + p->list_test_cases = false; + p->list_test_suites = false; + } + if(parseFlag(argc, argv, "dt-help") || parseFlag(argc, argv, "dt-h") || + parseFlag(argc, argv, "dt-?")) { + p->help = true; + p->exit = true; + } + if(parseFlag(argc, argv, "dt-version") || parseFlag(argc, argv, "dt-v")) { + p->version = true; + p->exit = true; + } + if(parseFlag(argc, argv, "dt-count") || parseFlag(argc, argv, "dt-c")) { + p->count = true; + p->exit = true; + } + if(parseFlag(argc, argv, "dt-list-test-cases") || parseFlag(argc, argv, "dt-ltc")) { + p->list_test_cases = true; + p->exit = true; + } + if(parseFlag(argc, argv, "dt-list-test-suites") || parseFlag(argc, argv, "dt-lts")) { + p->list_test_suites = true; + p->exit = true; + } +} + +// allows the user to add procedurally to the filters from the command line +void Context::addFilter(const char* filter, const char* value) { setOption(filter, value); } + +// allows the user to clear all filters from the command line +void Context::clearFilters() { + for(unsigned i = 0; i < p->filters.size(); ++i) + p->filters[i].clear(); +} + +// allows the user to override procedurally the int/bool options from the command line +void Context::setOption(const char* option, int value) { + setOption(option, toString(value).c_str()); +} + +// allows the user to override procedurally the string options from the command line +void Context::setOption(const char* option, const char* value) { + String argv = String("-") + option + "=" + value; + const char* lvalue = argv.c_str(); + parseArgs(1, &lvalue); +} + +// users should query this in their main() and exit the program if true +bool Context::shouldExit() { return p->exit; } + +// the main function that does all the filtering and test running +int Context::run() { + using namespace detail; + + Color::init(); + + contextState = p; + p->resetRunData(); + + // handle version, help and no_run + if(p->no_run || p->version || p->help) { + if(p->version) + printVersion(std::cout); + if(p->help) + printHelp(std::cout); + + contextState = 0; + + return EXIT_SUCCESS; + } + + printVersion(std::cout); + std::cout << Color::Cyan << "[doctest] " << Color::None << "run with \"--help\" for options\n"; + + unsigned i = 0; // counter used for loops - here for VC6 + + std::set& registeredTests = getRegisteredTests(); + + std::vector testArray; + for(std::set::iterator it = registeredTests.begin(); it != registeredTests.end(); + ++it) + testArray.push_back(&(*it)); + + // sort the collected records + if(!testArray.empty()) { + if(p->order_by.compare("file", true) == 0) { + std::qsort(&testArray[0], testArray.size(), sizeof(TestCase*), fileOrderComparator); + } else if(p->order_by.compare("suite", true) == 0) { + std::qsort(&testArray[0], testArray.size(), sizeof(TestCase*), suiteOrderComparator); + } else if(p->order_by.compare("name", true) == 0) { + std::qsort(&testArray[0], testArray.size(), sizeof(TestCase*), nameOrderComparator); + } else if(p->order_by.compare("rand", true) == 0) { + std::srand(p->rand_seed); + + // random_shuffle implementation + const TestCase** first = &testArray[0]; + for(i = testArray.size() - 1; i > 0; --i) { + int idxToSwap = std::rand() % (i + 1); // NOLINT + + const TestCase* temp = first[i]; + + first[i] = first[idxToSwap]; + first[idxToSwap] = temp; + } + } + } + + if(p->list_test_cases) { + std::cout << Color::Cyan << "[doctest] " << Color::None << "listing all test case names\n"; + separator_to_stream(std::cout); + } + + std::set testSuitesPassingFilters; + if(p->list_test_suites) { + std::cout << Color::Cyan << "[doctest] " << Color::None << "listing all test suites\n"; + separator_to_stream(std::cout); + } + + // invoke the registered functions if they match the filter criteria (or just count them) + for(i = 0; i < testArray.size(); i++) { + const TestCase& data = *testArray[i]; + + if(data.m_skip && !p->no_skip) + continue; + + if(!matchesAny(data.m_file, p->filters[0], 1, p->case_sensitive)) + continue; + if(matchesAny(data.m_file, p->filters[1], 0, p->case_sensitive)) + continue; + if(!matchesAny(data.m_test_suite, p->filters[2], 1, p->case_sensitive)) + continue; + if(matchesAny(data.m_test_suite, p->filters[3], 0, p->case_sensitive)) + continue; + if(!matchesAny(data.m_name, p->filters[4], 1, p->case_sensitive)) + continue; + if(matchesAny(data.m_name, p->filters[5], 0, p->case_sensitive)) + continue; + + p->numTestsPassingFilters++; + + // do not execute the test if we are to only count the number of filter passing tests + if(p->count) + continue; + + // print the name of the test and don't execute it + if(p->list_test_cases) { + std::cout << Color::None << data.m_name << "\n"; + continue; + } + + // print the name of the test suite if not done already and don't execute it + if(p->list_test_suites) { + if((testSuitesPassingFilters.count(data.m_test_suite) == 0) && + data.m_test_suite[0] != '\0') { + std::cout << Color::None << data.m_test_suite << "\n"; + testSuitesPassingFilters.insert(data.m_test_suite); + p->numTestSuitesPassingFilters++; + } + continue; + } + + // skip the test if it is not in the execution range + if((p->last < p->numTestsPassingFilters && p->first <= p->last) || + (p->first > p->numTestsPassingFilters)) + continue; + + // execute the test if it passes all the filtering + { + p->currentTest = &data; + + bool failed = false; + p->hasLoggedCurrentTestStart = false; + p->numFailedAssertionsForCurrentTestcase = 0; + p->subcasesPassed.clear(); + double duration = 0; + Timer timer; + timer.start(); + do { + // if the start has been logged from a previous iteration of this loop + if(p->hasLoggedCurrentTestStart) + logTestEnd(); + p->hasLoggedCurrentTestStart = false; + + // if logging successful tests - force the start log + if(p->success) + DOCTEST_LOG_START(std::cout); + + // reset the assertion state + p->numAssertionsForCurrentTestcase = 0; + p->hasCurrentTestFailed = false; + + // reset some of the fields for subcases (except for the set of fully passed ones) + p->subcasesHasSkipped = false; + p->subcasesCurrentLevel = 0; + p->subcasesEnteredLevels.clear(); + + // reset stuff for logging with INFO() + p->exceptionalContexts.clear(); + +// execute the test +#ifndef DOCTEST_CONFIG_NO_EXCEPTIONS + try { +#endif // DOCTEST_CONFIG_NO_EXCEPTIONS + FatalConditionHandler fatalConditionHandler; // Handle signals + data.m_test(); + fatalConditionHandler.reset(); + if(contextState->hasCurrentTestFailed) + failed = true; +#ifndef DOCTEST_CONFIG_NO_EXCEPTIONS + } catch(const TestFailureException&) { failed = true; } catch(...) { + DOCTEST_LOG_START(std::cout); + logTestException(*contextState->currentTest, translateActiveException(), false); + failed = true; + } +#endif // DOCTEST_CONFIG_NO_EXCEPTIONS + + p->numAssertions += p->numAssertionsForCurrentTestcase; + + // exit this loop if enough assertions have failed + if(p->abort_after > 0 && p->numFailedAssertions >= p->abort_after) { + p->subcasesHasSkipped = false; + std::cout << Color::Red << "Aborting - too many failed asserts!\n"; + } + + } while(p->subcasesHasSkipped == true); + + duration = timer.getElapsedSeconds(); + + if(Approx(p->currentTest->m_timeout).epsilon(DBL_EPSILON) != 0 && + Approx(duration).epsilon(DBL_EPSILON) > p->currentTest->m_timeout) { + failed = true; + DOCTEST_LOG_START(std::cout); + std::cout << Color::Red << "Test case exceeded time limit of " + << std::setprecision(6) << std::fixed << p->currentTest->m_timeout + << "!\n"; + } + + if(p->duration) + std::cout << Color::None << std::setprecision(6) << std::fixed << duration + << " s: " << p->currentTest->m_name << "\n"; + + if(data.m_should_fail) { + DOCTEST_LOG_START(std::cout); + if(failed) + std::cout << Color::Yellow + << "Failed as expected so marking it as not failed\n"; + else + std::cout << Color::Red + << "Should have failed but didn't! Marking it as failed!\n"; + failed = !failed; + } else if(failed && data.m_may_fail) { + DOCTEST_LOG_START(std::cout); + failed = false; + std::cout << Color::Yellow << "Allowed to fail so marking it as not failed\n"; + } else if(data.m_expected_failures > 0) { + DOCTEST_LOG_START(std::cout); + if(p->numFailedAssertionsForCurrentTestcase == data.m_expected_failures) { + failed = false; + std::cout << Color::Yellow << "Failed exactly " << data.m_expected_failures + << " times as expected so marking it as not failed!\n"; + } else { + failed = true; + std::cout << Color::Red << "Didn't fail exactly " << data.m_expected_failures + << " times so marking it as failed!\n"; + } + } + std::cout << Color::None; + + if(p->hasLoggedCurrentTestStart) + logTestEnd(); + + if(failed) // if any subcase has failed - the whole test case has failed + p->numFailed++; + + // stop executing tests if enough assertions have failed + if(p->abort_after > 0 && p->numFailedAssertions >= p->abort_after) + break; + } + } + + printSummary(std::cout); + + contextState = 0; + + if(p->numFailed && !p->no_exitcode) + return EXIT_FAILURE; + return EXIT_SUCCESS; +} +} // namespace doctest + +#endif // DOCTEST_CONFIG_DISABLE + +#ifdef DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN +int main(int argc, char** argv) { return doctest::Context(argc, argv).run(); } +#endif // DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN + +DOCTEST_CLANG_SUPPRESS_WARNING_POP +DOCTEST_MSVC_SUPPRESS_WARNING_POP +DOCTEST_GCC_SUPPRESS_WARNING_POP + +#endif // DOCTEST_LIBRARY_IMPLEMENTATION +#endif // DOCTEST_CONFIG_IMPLEMENT diff --git a/test/SDP/sdp__2_8.txt b/test/SDP/sdp__2_8.txt new file mode 100644 index 000000000..a11846fe2 --- /dev/null +++ b/test/SDP/sdp__2_8.txt @@ -0,0 +1,28 @@ +2 +1 +8 +-0.791489 -0.611184 +-8.67433 -4.31887 -4.07078 -6.49291 -4.93511 -2.93824 -6.31216 -1.50404 +-4.31887 -32.1925 -21.6701 -19.1668 -13.1909 -13.402 -17.7679 -20.0913 +-4.07078 -21.6701 -20.5631 -15.6578 -6.95022 -13.1422 -9.22145 -13.9874 + -6.49291 -19.1668 -15.6578 -20.9036 -0.599751 -7.67295 -15.5547 -9.53252 + -4.93511 -13.1909 -6.95022 -0.599751 -22.8788 -7.65263 -4.94303 -12.8813 +-2.93824 -13.402 -13.1422 -7.67295 -7.65263 -19.5889 -2.51877 -3.10766 +-6.31216 -17.7679 -9.22145 -15.5547 -4.94303 -2.51877 -20.5028 -7.19058 +-1.50404 -20.0913 -13.9874 -9.53252 -12.8813 -3.10766 -7.19058 -25.9886 +-0.492755 -0.365163 1.0705 0.0731272 -0 -0 -0 -0 +-0.365163 1.33987 -0.850178 0.174155 -0 -0 -0 -0 + 1.0705 -0.850178 0.508161 -0.782726 -0 -0 -0 -0 +0.0731272 0.174155 -0.782726 0.522239 -0 -0 -0 -0 + -0 -0 -0 -0 0.492755 0.365163 -1.0705 -0.0731272 + -0 -0 -0 -0 0.365163 -1.33987 0.850178 -0.174155 + -0 -0 -0 -0 -1.0705 0.850178 -0.508161 0.782726 + -0 -0 -0 -0 -0.0731272 -0.174155 0.782726 -0.522239 + 2.7115 -0.191887 0.734984 0.13519 -0 -0 -0 -0 +-0.191887 1.41029 1.74685 1.15143 -0 -0 -0 -0 +0.734984 1.74685 2.05819 0.339095 -0 -0 -0 -0 + 0.13519 1.15143 0.339095 0.642436 -0 -0 -0 -0 + -0 -0 -0 -0 -2.7115 0.191887 -0.734984 -0.13519 + -0 -0 -0 -0 0.191887 -1.41029 -1.74685 -1.15143 + -0 -0 -0 -0 -0.734984 -1.74685 -2.05819 -0.339095 + -0 -0 -0 -0 -0.13519 -1.15143 -0.339095 -0.642436 diff --git a/test/SDP/test_main.cpp b/test/SDP/test_main.cpp new file mode 100644 index 000000000..186632a37 --- /dev/null +++ b/test/SDP/test_main.cpp @@ -0,0 +1,15 @@ +// VolEsti (volume computation and sampling library) + +// Copyright (c) 20012-2018 Vissarion Fisikopoulos +// Copyright (c) 2018 Apostolos Chalkis + +// Licensed under GNU LGPL.3, see LICENCE file + +#define DOCTEST_CONFIG_IMPLEMENT +#include "doctest.h" + +int main(int argc, char** argv) { + doctest::Context context; + context.applyCommandLine(argc, argv); + return context.run(); +} diff --git a/test/SDP/test_solve_sdp.cpp b/test/SDP/test_solve_sdp.cpp new file mode 100644 index 000000000..fcf99dc70 --- /dev/null +++ b/test/SDP/test_solve_sdp.cpp @@ -0,0 +1,75 @@ +// VolEsti (volume computation and sampling library) + +// Copyright (c) 20012-2020 Vissarion Fisikopoulos +// Copyright (c) 2020 Apostolos Chalkis + +//Contributed and/or modified by Repouskos Panagiotis, as part of Google Summer of Code 2019 program. + +// Licensed under GNU LGPL.3, see LICENCE file + +#include "doctest.h" +#include +#include + +#include "random.hpp" +#include "Eigen/Eigen" +#include "cartesian_geom/cartesian_kernel.h" +#include "convex_bodies/spectrahedra/spectrahedron.h" +#include "SDPAFormatManager.h" +#include "optimization/simulated_annealing.hpp" + + +typedef double NT; +typedef Eigen::Matrix VT; +typedef Eigen::Matrix MT; +typedef Cartesian Kernel; +typedef typename Kernel::Point Point; +typedef Spectrahedron SPECTRAHEDRON; + + +void call_test_solve_sdp() { + + // read the sdp + std::string fileName("sdp__2_8.txt"); + std::cout << fileName <<"\n\n";fflush(stdout); + SPECTRAHEDRON spectrahedron; + Point objFunction; + + std::ifstream in; + in.open(fileName, std::ifstream::in); + SdpaFormatManager sdpaFormatManager; + sdpaFormatManager.loadSDPAFormatFile(in, spectrahedron, objFunction); + + // We will need an initial interior point. In this + // spectrahedron the origin (zero point) is interior + Point initialPoint(spectrahedron.getLMI().dimension()); + + // First some parameters for the solver + // desired relative error + NT rel_error = 0.001; + + // Declare settings + SimulatedAnnealingSettings settings(rel_error); + + + + bool correct = false; + int tries = 0; + + // try some times; since it is randomized it may fail... + while (!correct && tries < 5){ + // solve the program + Point sol; + NT min = solve_sdp(spectrahedron, objFunction, settings, initialPoint, sol); + // assume optimal solution = -1.3888 + double relativeError = std::fabs((-1.3888 - min) / -1.3888); + correct = relativeError <= 0.01; + tries++; + } + + CHECK(correct); +} + +TEST_CASE ("test_solve_sdp") { + call_test_solve_sdp(); // test the simulated annealing SDP solver +} \ No newline at end of file diff --git a/test/SDP/test_spec_oracles.cpp b/test/SDP/test_spec_oracles.cpp new file mode 100644 index 000000000..a00a6283a --- /dev/null +++ b/test/SDP/test_spec_oracles.cpp @@ -0,0 +1,122 @@ +// VolEsti (volume computation and sampling library) + +// Copyright (c) 20012-2018 Vissarion Fisikopoulos +// Copyright (c) 2018 Apostolos Chalkis + +//Contributed and/or modified by Repouskos Panagiotis, as part of Google Summer of Code 2019 program. + +// Licensed under GNU LGPL.3, see LICENCE file + +#include "doctest.h" +#include "Eigen/Eigen" +#include +#include "random.hpp" +#include "cartesian_geom/cartesian_kernel.h" +#include "spectrahedron.h" + +typedef double NT; +typedef Eigen::Matrix VT; +typedef Eigen::Matrix MT; +typedef Cartesian Kernel; +typedef typename Kernel::Point Point; +typedef Spectrahedron SPECTRAHEDRON; + + +// create a spectrahedron to test the boundary oracles +void populateValues(SPECTRAHEDRON &spectrahedron, Point &objFunction) { + VT c(2); + c(0) = 1; + c(1) = 1; + objFunction = Point(c); + + MT A0, A1, A2; + A0.setZero(3, 3); + A1.setZero(3, 3); + A2.setZero(3, 3); + + A0(0, 0) = -1; + A0(1, 1) = -2; + A0(1, 2) = A0(2, 1) = 1; + A0(2, 2) = -2; + + A1(0, 0) = -1; + A1(1, 2) = A1(2, 1) = 1; + + A2(0, 2) = A2(2, 0) = -1; + + std::vector matrices; + matrices.push_back(A0); + matrices.push_back(A1); + matrices.push_back(A2); + + LMI lmi(matrices); + spectrahedron = SPECTRAHEDRON(lmi); +} + + +void call_test_coordinate_intersection() { + + // create a spectrahedron to test the boundary oracles + SPECTRAHEDRON spectrahedron; + Point objFunction; + populateValues(spectrahedron, objFunction); + + // create an initial point in the spectrahedron + VT initialPoint; + initialPoint.setZero(2); + + SPECTRAHEDRON::PrecomputedValues precomputedValues; + std::pair ret = spectrahedron.coordinateIntersection(initialPoint, 2, precomputedValues); + + bool correct = true; + + // actual result is + // 1.22474 -1.22474 + + if (std::fabs(ret.first - 1.22474) > 0.0001 || std::fabs(ret.second + 1.22474) > 0.0001) + correct = false; + + CHECK(correct); +} + +void call_test_positive_intersection() { + + // we will test with the curve at^2 + bt + c + // where c = interior point + // and a = objective function + + SPECTRAHEDRON spectrahedron; + Point a; + populateValues(spectrahedron, a); + + // create an initial point in the spectrahedron + // the origin will do! + VT c; + c.setZero(2); + + // create a b + VT b; + b.setZero(2); + b(0) = 1; + b(1) = 1; + + SPECTRAHEDRON::PrecomputedValues precomputedValues; + NT ret = spectrahedron.positiveIntersection(a.getCoefficients(), b, c, precomputedValues); + + bool correct = true; + + // actual result is + // ret = 0.5294590425 + + if (std::fabs(ret - 0.5294590425) > 0.0001) + correct = false; + + CHECK(correct); +} + + +TEST_CASE ("test_spec_oracles") { + call_test_positive_intersection(); // hmc boundary oracle + call_test_coordinate_intersection(); // coordinate hit and run oracle +} + diff --git a/test/test_sdpa_format.cpp b/test/test_sdpa_format.cpp index b6f50cb25..2188f4459 100755 --- a/test/test_sdpa_format.cpp +++ b/test/test_sdpa_format.cpp @@ -11,6 +11,7 @@ #include "Eigen/Eigen" #include "vector" #include +#include "random.hpp" #include "cartesian_geom/cartesian_kernel.h" #include "spectrahedron.h" #include "SDPAFormatManager.h"