From abc351f2e11497e51111d0e5a91df519aba27791 Mon Sep 17 00:00:00 2001 From: Repouskos Panagiotis Date: Tue, 24 Mar 2020 16:54:38 +0200 Subject: [PATCH 01/38] expose Spectrahedron interface to R - create class spectrahedron - expose function to write sdpa format files in R --- R-proj/R/RcppExports.R | 5 + R-proj/R/zzz.R | 1 + R-proj/src/spectrahedron.cpp | 47 +++++ R-proj/src/spectrahedron_module.cpp | 34 ++++ include/SDPAFormatManager.h | 264 ++++++++++++++++++++++++++ include/convex_bodies/LMI.h | 180 ++++++++++++++++++ include/convex_bodies/spectrahedron.h | 47 +++++ 7 files changed, 578 insertions(+) create mode 100644 R-proj/src/spectrahedron.cpp create mode 100644 R-proj/src/spectrahedron_module.cpp create mode 100644 include/SDPAFormatManager.h create mode 100644 include/convex_bodies/LMI.h create mode 100644 include/convex_bodies/spectrahedron.h diff --git a/R-proj/R/RcppExports.R b/R-proj/R/RcppExports.R index deb590ba9..6ee82c58c 100644 --- a/R-proj/R/RcppExports.R +++ b/R-proj/R/RcppExports.R @@ -222,6 +222,11 @@ sample_points <- function(P = NULL, n = NULL, random_walk = NULL, distribution = .Call(`_volesti_sample_points`, P, n, random_walk, distribution) } +#' @export +writeSdpaFile <- function(spectrahedron = NULL, objectiveFunction = NULL, outputFile = NULL) { + invisible(.Call(`_volesti_writeSdpaFile`, spectrahedron, objectiveFunction, outputFile)) +} + #' The main function for volume approximation of a convex Polytope (H-polytope, V-polytope or a zonotope) #' #' For the volume approximation can be used two algorithms. Either SequenceOfBalls or CoolingGaussian. A H-polytope with \eqn{m} facets is described by a \eqn{m\times d} matrix \eqn{A} and a \eqn{m}-dimensional vector \eqn{b}, s.t.: \eqn{Ax\leq b}. A V-polytope is defined as the convex hull of \eqn{m} \eqn{d}-dimensional points which correspond to the vertices of P. A zonotope is desrcibed by the Minkowski sum of \eqn{m} \eqn{d}-dimensional segments. diff --git a/R-proj/R/zzz.R b/R-proj/R/zzz.R index 91e14c5b0..36a821caf 100644 --- a/R-proj/R/zzz.R +++ b/R-proj/R/zzz.R @@ -8,3 +8,4 @@ ## a load action, so this does not have to be placed in .onLoad() or evalqOnLoad(). loadModule("yada", TRUE) +loadModule("spec", TRUE) diff --git a/R-proj/src/spectrahedron.cpp b/R-proj/src/spectrahedron.cpp new file mode 100644 index 000000000..08e428850 --- /dev/null +++ b/R-proj/src/spectrahedron.cpp @@ -0,0 +1,47 @@ +// +// Created by panagiotis on 2/23/20. +// + +#include +#include +#include +#include "cartesian_geom/cartesian_kernel.h" +#include +#include +#include +#include +#include "LMI.h" +#include "spectrahedron.h" +#include "SDPAFormatManager.h" + + + +//' @export +// [[Rcpp::export]] +void writeSdpaFile(Rcpp::Nullable spectrahedron = R_NilValue, + Rcpp::Nullable objectiveFunction = R_NilValue, + Rcpp::Nullable outputFile = R_NilValue) { + + typedef double NT; + typedef Eigen::Matrix VT; + typedef Eigen::Matrix MT; + typedef Cartesian Kernel; + typedef typename Kernel::Point Point; + typedef boost::mt19937 RNGType; + typedef LMI LMI; + typedef Spectrahedron SPECTRAHEDRON; + + std::vector matrices = Rcpp::as > (Rcpp::as (spectrahedron).field("matrices")); + LMI lmi(matrices); + SPECTRAHEDRON _spectrahedron(lmi); + Point c(Rcpp::as (objectiveFunction)); + + std::filebuf fb; + fb.open(Rcpp::as (outputFile), std::ios::out); + std::ostream os(&fb); + + SdpaFormatManager sdpaFormatManager; + sdpaFormatManager.writeSDPAFormatFile(os, _spectrahedron, c); + + return; +} \ No newline at end of file diff --git a/R-proj/src/spectrahedron_module.cpp b/R-proj/src/spectrahedron_module.cpp new file mode 100644 index 000000000..e2fc2f534 --- /dev/null +++ b/R-proj/src/spectrahedron_module.cpp @@ -0,0 +1,34 @@ +// +// Created by panagiotis on 3/24/20. +// + +#include + +class Spectrahedron { +public: + /// A list with the matrices A0, ..., An + Rcpp::List matrices; + + Spectrahedron() {} + + Spectrahedron(Rcpp::List _matrices) : matrices(_matrices) {} +}; + + +RCPP_MODULE(spec){ + using namespace Rcpp ; + + //' An exposed class to represent a Spectrahedron + //' + //' @description A Spectrahedron is a convex polytope defined by a linear matrix inequality of the form \eqn{A_0 + x_1 A_1 + ... + x_n A_n \prec 0}. + //' + //' @field matrices The matrices \eqn{A_0, A_1, ..., A_n} + //' @export + class_("Spectrahedron") + // expose the default constructor + .constructor() + .constructor() + .field( "matrices", &Spectrahedron::matrices); +} + +extern SEXP _rcpp_module_boot_spec(void); diff --git a/include/SDPAFormatManager.h b/include/SDPAFormatManager.h new file mode 100644 index 000000000..50f2d344d --- /dev/null +++ b/include/SDPAFormatManager.h @@ -0,0 +1,264 @@ +// +// Created by panagiotis on 20/7/2019. +// + +#ifndef VOLESTI_SDPA_FORMAT_MANAGER_H +#define VOLESTI_SDPA_FORMAT_MANAGER_H + +#include "spectrahedron.h" + +#include +#include + + +/// Reads/writes files according to the SDPA format for sdps. +/// Currently supported Format: +/// +/// +/// +/// +/// +/// For example: +/// 2 +/// 3 +/// 1 1 +/// +/// +/// \tparam NT Numerical Type +template +class SdpaFormatManager { +private: + typedef std::string::iterator string_it; + typedef std::list listVector; + + typedef Eigen::Matrix MT; + typedef Eigen::Matrix VT; + + /// Return the first non white space/tab character and advance the iterator one position + /// @param[in, out] it current position + /// @param[in] end end of string + /// @return First non white space/tab character + char consumeSymbol(string_it &at, string_it & end) { + while (at != end) { + if (*at != ' ' && *at != '\t') { + char c = *at; + at++; + return c; + } + + at++; + } + + return '\0'; + } + + + /// Determine if current line is a comment + /// @param[in] line The current line + /// @return true if line is a comment, false otherwise + bool isCommentLine(std::string & line) { + string_it at = line.begin(); + string_it end = line.end(); + char c = consumeSymbol(at, end); + return c == '"' || c == '*'; + } + + + /// Get an integer from the string + /// \param[in] string + /// \return an integer + int fetchNumber(std::string &string) { + std::stringstream stream(string); + int num; + stream >> num; + return num; + } + + + /// Read a vector of the form {val1, val2, ..., valn} + /// @param string Contains the vector + /// @return a list with the n numbers + listVector readVector(std::string &string) { + std::stringstream stream(string); + listVector vector; + NT value; + + while (stream >> value) { + vector.push_back(value); + } + + return vector; + } + +public: + + /// Reads an SDPA format file + /// \param[in] is An open stram pointing to the file + /// \param[out] matrices the matrices A0, A1, A2, ..., An + /// \param[out] objectiveFunction The objective function of the sdp + void loadSDPAFormatFile(std::ifstream &is, std::vector &matrices, VT &objectiveFunction) { + std::string line; + std::string::size_type sz; + + std::getline(is, line, '\n'); + + //skip comments + while (isCommentLine(line)) { + std::getline(is, line, '\n'); + } + + //read variables number + int variablesNum = fetchNumber(line); + + if (std::getline(is, line, '\n').eof()) + throw 1; + + //read number of blocks + int blocksNum = fetchNumber(line); + + if (std::getline(is, line, '\n').eof()) + throw 1; + + //read block structure vector + listVector blockStructure = readVector(line); + + if (blockStructure.size() != blocksNum) + throw 1; + + if (std::getline(is, line, '\n').eof()) + throw 1; + + //read constant vector + listVector constantVector = readVector(line); + + while (constantVector.size() < variablesNum) { + if (std::getline(is, line, '\n').eof()) + throw 1; + listVector t = readVector(line); + constantVector.insert(std::end(constantVector), std::begin(t), std::end(t)); + } + + matrices = std::vector(variablesNum + 1); + int matrixDim = 0; + for (auto x : blockStructure) + matrixDim += std::abs((int) x); + + //read constraint matrices + for (int atMatrix = 0; atMatrix < matrices.size(); atMatrix++) { + MT matrix; + matrix.setZero(matrixDim, matrixDim); + + int offset = 0; + + for (auto blockSize : blockStructure) { + + if (blockSize > 0) { //read a block blockSize x blockSize + int at = 0; + int i = 0, j = 0; + + while (at < blockSize * blockSize) { + if (std::getline(is, line, '\n').eof()) + throw 1; + + listVector vec = readVector(line); + + for (double value : vec) { + matrix(offset + i, offset + j) = value; + at++; + if (at % (int) blockSize == 0) { // new row + i++; + j = 0; + } else { //new column + j++; + } + } + } /* while (at0, I want it <0 + if (atMatrix == 0) //F0 has - before it in SDPA format, the rest have + + matrices[atMatrix] = matrix; + else + matrices[atMatrix] = -1 * matrix; + } + + // return lmi and objective function + objectiveFunction.setZero(variablesNum); + int at = 0; + + for (auto value : constantVector) + objectiveFunction(at++) = value; + } + + /// Create a SDPA format file + /// \param[in] os Open stream to file + /// \param[in] matrices The matrices A0, ..., An + /// \param[in] objectiveFunction The objective function of the sdp + void writeSDPAFormatFile(std::ostream &os, std::vector const & matrices, VT const & objectiveFunction) { + int dim = matrices.size() - 1; + MT A0 = matrices[0]; + + os << dim << "\n"; + os << 1 << "\n"; + os << A0.rows() << "\n"; + + os << objectiveFunction.transpose() << "\n"; + + for (int i = 0; i < A0.rows(); i++) + os << A0.row(i) << "\n"; + + for (int at=1 ; at + void loadSDPAFormatFile(std::ifstream &is, Spectrahedron &spectrahedron, Point &objectiveFunction) { + std::vector matrices; + VT coeffs; + loadSDPAFormatFile(is, matrices, coeffs); + LMI lmi(matrices); + spectrahedron = Spectrahedron(lmi); + objectiveFunction = Point(coeffs); + } + + + /// Write a spectrahedron and a vector (objective function) to a SDPA format output file + /// \tparam Point + /// \param[in] is opened stream to output file + /// \param[in] spectrahedron + /// \param[in] objectiveFunction + template + void writeSDPAFormatFile(std::ostream &os, Spectrahedron const & spectrahedron, Point const & objectiveFunction) { + writeSDPAFormatFile(os, spectrahedron.getLMI().getMatrices(), objectiveFunction.getCoefficients()); + } +}; + + +#endif //VOLESTI_SDPA_FORMAT_MANAGER_H + diff --git a/include/convex_bodies/LMI.h b/include/convex_bodies/LMI.h new file mode 100644 index 000000000..301a18da6 --- /dev/null +++ b/include/convex_bodies/LMI.h @@ -0,0 +1,180 @@ +// +// Created by panagiotis on 2/22/20. +// + +#ifndef VOLESTI_LMI_H +#define VOLESTI_LMI_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 +/// @tparam MT Matrix Type +/// @tparam VT Vector Type +template +class LMI { + +}; + + +/// This class handles a linear matrix inequality of the form \[A_0 + \sum x_i A_i\] +/// A template specialization for dense Eigen matrices and vectors +/// @tparam NT Numeric Type +template +class LMI, Eigen::Matrix > { + public: + /// Eigen matrix type + typedef Eigen::Matrix MT; + /// Eigen vector type + typedef Eigen::Matrix VT; + + /// 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; + + /// At each column keep the m*(m+1)/2 distinct elements of each matrix A_i, i=1,...,d + MT vectorMatrix; + + LMI(){} + + /// 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); + it++; + } + + d = matrices.size() - 1; + m = matrices[0].rows(); + setVectorMatrix(); + } + + + /// Create the vectorMatrix, which has at each column the distinct elements of each A_i, i=1,...,d + void setVectorMatrix() { + int newM = m * (m + 1) / 2; + + // allocate memory + vectorMatrix.resize(newM, d); + + // initialze iterator and skip A_0 + typename std::vector::iterator iter = matrices.begin(); + iter++; + + // copy elements + int atMatrix = 0; + + for (; iter != matrices.end(); iter++, atMatrix++) { + int i = 0; + + for (int at_row = 0; at_row < m; at_row++) + for (int at_col = at_row; at_col < m; at_col++) { + vectorMatrix(i++, atMatrix) = (*iter)(at_row, at_col); + } + + } + + } + + /// \returns The dimension of vector x + unsigned int dimension() const { + return d; + } + + /// \return The matrices A0, A1, ..., Ad + std::vector getMatrices() const { + return matrices; + } + + /// \returns The size of the matrices + unsigned int sizeOfMatrices() const { + return m; + } + + /// Evaluate A_0 + \[A_0 + \sum x_i A_i \] + /// \param[in] x The input vector + /// \param[out] ret The output matrix + void evaluate(VT const & x, MT& ret) { + evaluateWithoutA0(x, ret); + + // add A0 + ret += matrices[0]; + } + + /// 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& res) { +//#define EVALUATE_WITHOUT_A0_NAIVE +#if defined(EVALUATE_WITHOUT_A0_NAIVE) + res = MT::Zero(m, m); + typename std::vector::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); + + double *data = res.data(); + double *v = a.data(); + + int at = 0; + + // copy lower triangular + for (int at_col = 0; at_col < m; at_col++) { + int col_offset = at_col * m; + double *target = data + col_offset + at_col; + + for (int at_row = at_col; at_row < m; at_row++) { + *(target++) = *(v++); + } + } + + v = a.data(); + + // copy upper triangular + for (int at_row = 0; at_row < m; at_row++) { + double *target = data + at_row + at_row * m; + + for (int at_col = at_row; at_col < m; at_col++) { + *target = *(v++); + target = target + m; + } + } +#endif + } + + /// 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) { + ret.resize(d); + + // i-th coordinate of the determinant is e^T * A_i * e + for (int i = 0; i < d; i++) { + ret(i) = e.dot(matrices[i+1] * e); + } + + ret.normalize(); + } + + /// \param i An indicator to a matrix + /// \return Pointer to A_i + MT* const getMatrix(const int i) { + return &(matrices[i]); + } +}; + +#endif //VOLESTI_LMI_H diff --git a/include/convex_bodies/spectrahedron.h b/include/convex_bodies/spectrahedron.h new file mode 100644 index 000000000..bcc16a718 --- /dev/null +++ b/include/convex_bodies/spectrahedron.h @@ -0,0 +1,47 @@ +// +// Created by panagiotis on 2/22/20. +// + +#ifndef VOLESTI_SPECTRAHEDRON_H +#define VOLESTI_SPECTRAHEDRON_H + +#include "LMI.h" + +/// This class manipulates a spectrahedron, described by a LMI +/// \tparam NT Numeric Type +/// \tparam MT Matrix Type +/// \tparam VT Vector Type +template +class Spectrahedron { +public: + + /// The type of a pair of NT + typedef std::pair pairNT; + + /// The dimension of the spectrahedron + unsigned int d; + + /// The linear matrix inequality that describes the spectrahedron + LMI lmi; + + Spectrahedron() {} + + /// Creates a spectrahedron + /// \param[in] lmi The linear matrix inequality that describes the spectrahedron + Spectrahedron(const LMI& lmi) : lmi(lmi) { + d = lmi.dimension(); + } + + /// \return The dimension of the spectrahedron + unsigned int dimension() const { + return d; + } + + /// \return The LMI describing this spectrahedron + LMI getLMI() const { + return lmi; + } + +}; + +#endif //VOLESTI_SPECTRAHEDRON_H From 3ed51bdfcafaf94c6a2c0d6c9b33dd7dc4f95caf Mon Sep 17 00:00:00 2001 From: Repouskos Panagiotis Date: Thu, 26 Mar 2020 01:04:02 +0200 Subject: [PATCH 02/38] expose read_sdpa function to R and documentation --- R-proj/NAMESPACE | 4 +- R-proj/R/RcppExports.R | 34 ++++++++++++- R-proj/R/read_sdpa_file.R | 23 +++++++++ R-proj/man/loadSdpaFormatFile.Rd | 23 +++++++++ R-proj/man/readSdpaFormatFile.Rd | 24 +++++++++ R-proj/man/writeSdpaFormatFile.Rd | 35 +++++++++++++ R-proj/src/spectrahedron.cpp | 79 ++++++++++++++++++++++++++--- R-proj/src/spectrahedron_module.cpp | 17 +++++-- include/SDPAFormatManager.h | 6 +-- 9 files changed, 227 insertions(+), 18 deletions(-) create mode 100644 R-proj/R/read_sdpa_file.R create mode 100644 R-proj/man/loadSdpaFormatFile.Rd create mode 100644 R-proj/man/readSdpaFormatFile.Rd create mode 100644 R-proj/man/writeSdpaFormatFile.Rd diff --git a/R-proj/NAMESPACE b/R-proj/NAMESPACE index ee585568c..c46dfca0a 100644 --- a/R-proj/NAMESPACE +++ b/R-proj/NAMESPACE @@ -15,14 +15,16 @@ export(gen_rand_zonotope) export(gen_simplex) export(gen_skinny_cube) export(inner_ball) +export(loadSdpaFormatFile) +export(readSdpaFormatFile) export(rotate_polytope) export(round_polytope) export(sample_points) export(volume) +export(writeSdpaFormatFile) export(zonotope_approximation) exportPattern("^[[:alpha:]]+") importFrom("methods","new") -importFrom("stats", "cov") importFrom("utils","read.csv") importFrom(Rcpp,evalCpp) importFrom(Rcpp,loadModule) diff --git a/R-proj/R/RcppExports.R b/R-proj/R/RcppExports.R index 6ee82c58c..6635fd10e 100644 --- a/R-proj/R/RcppExports.R +++ b/R-proj/R/RcppExports.R @@ -222,9 +222,39 @@ sample_points <- function(P = NULL, n = NULL, random_walk = NULL, distribution = .Call(`_volesti_sample_points`, P, n, random_walk, distribution) } +#' Write a SDPA format file +#' +#' Outputs a spectrahedron (the matrices defining a linear matrix inequality) and a vector (the objective function) +#' to a SDPA format file. +#' +#' @field spectrahedron A spectrahedron in n dimensions; must be an object of class Spectrahedron +#' @field objectiveFunction A numerical vector of length n +#' @field outputFile Name of the output file +#' +#' @examples +#' A0 = matrix(c(-1,0,0,0,-2,1,0,1,-2), nrow=3, ncol=3, byrow = TRUE) +#' A1 = matrix(c(-1,0,0,0,0,1,0,1,0), nrow=3, ncol=3, byrow = TRUE) +#' A2 = matrix(c(0,0,-1,0,0,0,-1,0,0), nrow=3, ncol=3, byrow = TRUE) +#' lmi = list(M0, M1,M2) +#' S = Spectrahedron$new(lmi); +#' objFunction = c(1,1) +#' writeSdpaFormatFile(S, objFunction, "output.txt") +#' @export +writeSdpaFormatFile <- function(spectrahedron = NULL, objectiveFunction = NULL, outputFile = NULL) { + invisible(.Call(`_volesti_writeSdpaFormatFile`, spectrahedron, objectiveFunction, outputFile)) +} + +#' Read a SDPA format file +#' +#' @field inputFile Name of the input file +#' +#' @return A list with two named items: an item "matrices" which is a list of the matrices and an vector "objFunction" +#' +#' @examples +#' l = loadSdpaFormatFile("input.txt") #' @export -writeSdpaFile <- function(spectrahedron = NULL, objectiveFunction = NULL, outputFile = NULL) { - invisible(.Call(`_volesti_writeSdpaFile`, spectrahedron, objectiveFunction, outputFile)) +loadSdpaFormatFile <- function(inputFile = NULL) { + .Call(`_volesti_loadSdpaFormatFile`, inputFile) } #' The main function for volume approximation of a convex Polytope (H-polytope, V-polytope or a zonotope) diff --git a/R-proj/R/read_sdpa_file.R b/R-proj/R/read_sdpa_file.R new file mode 100644 index 000000000..f4f90e58a --- /dev/null +++ b/R-proj/R/read_sdpa_file.R @@ -0,0 +1,23 @@ +#' Read a SDPA format file +#' +#' Read a SDPA format file and return a spectrahedron (an object of class Spectrahedron) which is defined by +#' the linear matrix inequality in the input file, and the objective function. +#' +#' @field path Name of the input file +#' +#' @return A list with two named items: an item "matrices" which is an object of class Spectrahedron and an vector "objFunction" +#' +#' @examples +#' l = loadSdpaFormatFile("input.txt") +#' @export +#' @useDynLib volesti, .registration=TRUE +#' @importFrom Rcpp evalCpp +#' @importFrom Rcpp loadModule +#' @importFrom "methods" "new" +#' @exportPattern "^[[:alpha:]]+" +readSdpaFormatFile <- function(path){ + l = loadSdpaFormatFile(path) + S = Spectrahedron$new(l$matrices) + + return(list("spectrahedron"=S, "objFunction"= l$objFunction)) +} diff --git a/R-proj/man/loadSdpaFormatFile.Rd b/R-proj/man/loadSdpaFormatFile.Rd new file mode 100644 index 000000000..7084f5235 --- /dev/null +++ b/R-proj/man/loadSdpaFormatFile.Rd @@ -0,0 +1,23 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/RcppExports.R +\name{loadSdpaFormatFile} +\alias{loadSdpaFormatFile} +\title{Read a SDPA format file} +\usage{ +loadSdpaFormatFile(inputFile = NULL) +} +\value{ +A list with two named items: an item "matrices" which is a list of the matrices and an vector "objFunction" +} +\description{ +Read a SDPA format file +} +\section{Fields}{ + +\describe{ +\item{\code{inputFile}}{Name of the input file} +}} + +\examples{ +l = loadSdpaFormatFile("input.txt") +} diff --git a/R-proj/man/readSdpaFormatFile.Rd b/R-proj/man/readSdpaFormatFile.Rd new file mode 100644 index 000000000..f40dbe348 --- /dev/null +++ b/R-proj/man/readSdpaFormatFile.Rd @@ -0,0 +1,24 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/read_sdpa_file.R +\name{readSdpaFormatFile} +\alias{readSdpaFormatFile} +\title{Read a SDPA format file} +\usage{ +readSdpaFormatFile(path) +} +\value{ +A list with two named items: an item "matrices" which is an object of class Spectrahedron and an vector "objFunction" +} +\description{ +Read a SDPA format file and return a spectrahedron (an object of class Spectrahedron) which is defined by +the linear matrix inequality in the input file, and the objective function. +} +\section{Fields}{ + +\describe{ +\item{\code{path}}{Name of the input file} +}} + +\examples{ +l = loadSdpaFormatFile("input.txt") +} diff --git a/R-proj/man/writeSdpaFormatFile.Rd b/R-proj/man/writeSdpaFormatFile.Rd new file mode 100644 index 000000000..c9520208b --- /dev/null +++ b/R-proj/man/writeSdpaFormatFile.Rd @@ -0,0 +1,35 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/RcppExports.R +\name{writeSdpaFormatFile} +\alias{writeSdpaFormatFile} +\title{Write a SDPA format file} +\usage{ +writeSdpaFormatFile( + spectrahedron = NULL, + objectiveFunction = NULL, + outputFile = NULL +) +} +\description{ +Outputs a spectrahedron (the matrices defining a linear matrix inequality) and a vector (the objective function) +to a SDPA format file. +} +\section{Fields}{ + +\describe{ +\item{\code{spectrahedron}}{A spectrahedron in n dimensions; must be an object of class Spectrahedron} + +\item{\code{objectiveFunction}}{A numerical vector of length n} + +\item{\code{outputFile}}{Name of the output file} +}} + +\examples{ +A0 = matrix(c(-1,0,0,0,-2,1,0,1,-2), nrow=3, ncol=3, byrow = TRUE) +A1 = matrix(c(-1,0,0,0,0,1,0,1,0), nrow=3, ncol=3, byrow = TRUE) +A2 = matrix(c(0,0,-1,0,0,0,-1,0,0), nrow=3, ncol=3, byrow = TRUE) +lmi = list(M0, M1,M2) +S = Spectrahedron$new(lmi); +objFunction = c(1,1) +writeSdpaFormatFile(S, objFunction, "output.txt") +} diff --git a/R-proj/src/spectrahedron.cpp b/R-proj/src/spectrahedron.cpp index 08e428850..6694ea2d9 100644 --- a/R-proj/src/spectrahedron.cpp +++ b/R-proj/src/spectrahedron.cpp @@ -1,6 +1,4 @@ -// -// Created by panagiotis on 2/23/20. -// +//Contributed and/or modified by Repouskos Panagiotis, as part of Google Summer of Code 2019 program. #include #include @@ -14,11 +12,26 @@ #include "spectrahedron.h" #include "SDPAFormatManager.h" - - +//' Write a SDPA format file +//' +//' Outputs a spectrahedron (the matrices defining a linear matrix inequality) and a vector (the objective function) +//' to a SDPA format file. +//' +//' @field spectrahedron A spectrahedron in n dimensions; must be an object of class Spectrahedron +//' @field objectiveFunction A numerical vector of length n +//' @field outputFile Name of the output file +//' +//' @examples +//' A0 = matrix(c(-1,0,0,0,-2,1,0,1,-2), nrow=3, ncol=3, byrow = TRUE) +//' A1 = matrix(c(-1,0,0,0,0,1,0,1,0), nrow=3, ncol=3, byrow = TRUE) +//' A2 = matrix(c(0,0,-1,0,0,0,-1,0,0), nrow=3, ncol=3, byrow = TRUE) +//' lmi = list(M0, M1,M2) +//' S = Spectrahedron$new(lmi); +//' objFunction = c(1,1) +//' writeSdpaFormatFile(S, objFunction, "output.txt") //' @export // [[Rcpp::export]] -void writeSdpaFile(Rcpp::Nullable spectrahedron = R_NilValue, +void writeSdpaFormatFile(Rcpp::Nullable spectrahedron = R_NilValue, Rcpp::Nullable objectiveFunction = R_NilValue, Rcpp::Nullable outputFile = R_NilValue) { @@ -44,4 +57,58 @@ void writeSdpaFile(Rcpp::Nullable spectrahedron = R_NilValue, sdpaFormatManager.writeSDPAFormatFile(os, _spectrahedron, c); return; +} + +// need this to return a spectrahedron in R +// in function readSdpaFormatManager +class _Spectrahedron { +public: + /// A list with the matrices A0, ..., An + Rcpp::List matrices; + + _Spectrahedron(Rcpp::List _matrices) : matrices(_matrices) {} +}; + +//' Read a SDPA format file +//' +//' @field inputFile Name of the input file +//' +//' @return A list with two named items: an item "matrices" which is a list of the matrices and an vector "objFunction" +//' +//' @examples +//' l = loadSdpaFormatFile("input.txt") +//' @export +// [[Rcpp::export]] +Rcpp::List loadSdpaFormatFile(Rcpp::Nullable inputFile = R_NilValue) { + + typedef double NT; + typedef Eigen::Matrix VT; + typedef Eigen::Matrix MT; + typedef Cartesian Kernel; + typedef typename Kernel::Point Point; + typedef boost::mt19937 RNGType; + typedef LMI LMI; + typedef Spectrahedron SPECTRAHEDRON; + + SPECTRAHEDRON _spectrahedron; + Point c; + + // open stream + std::ifstream os; + os.open(Rcpp::as (inputFile),std::ifstream::in); + + // read file + SdpaFormatManager sdpaFormatManager; + sdpaFormatManager.loadSDPAFormatFile(os, _spectrahedron, c); + + std::vector const & matrices = _spectrahedron.getLMI().getMatrices(); + + // return spectrahedron and objective function + Rcpp::List _matrices; + + for (auto matrix : matrices) + _matrices.push_back(Rcpp::wrap(matrix)); + + Rcpp::List retList = Rcpp::List::create(Rcpp::Named("matrices") = _matrices , Rcpp::_["objFunction"] = Rcpp::wrap(c.getCoefficients())); + return Rcpp::wrap(retList); } \ No newline at end of file diff --git a/R-proj/src/spectrahedron_module.cpp b/R-proj/src/spectrahedron_module.cpp index e2fc2f534..21465546a 100644 --- a/R-proj/src/spectrahedron_module.cpp +++ b/R-proj/src/spectrahedron_module.cpp @@ -1,6 +1,4 @@ -// -// Created by panagiotis on 3/24/20. -// +//Contributed and/or modified by Repouskos Panagiotis, as part of Google Summer of Code 2019 program. #include @@ -18,11 +16,20 @@ class Spectrahedron { RCPP_MODULE(spec){ using namespace Rcpp ; - //' An exposed class to represent a Spectrahedron + //' An exposed class to represent a spectrahedron //' - //' @description A Spectrahedron is a convex polytope defined by a linear matrix inequality of the form \eqn{A_0 + x_1 A_1 + ... + x_n A_n \prec 0}. + //' @description A spectrahedron is a convex body defined by a linear matrix inequality of the form \eqn{A_0 + x_1 A_1 + ... + x_n A_n \preceq 0}. + //' The matrices \eqn{A_i} are symmetric \eqn{m \times m} real matrices and \eqn{\preceq 0} denoted negative semidefiniteness. //' //' @field matrices The matrices \eqn{A_0, A_1, ..., A_n} + //' + //' @example + //' A0 = matrix(c(-1,0,0,0,-2,1,0,1,-2), nrow=3, ncol=3, byrow = TRUE) + //' A1 = matrix(c(-1,0,0,0,0,1,0,1,0), nrow=3, ncol=3, byrow = TRUE) + //' A2 = matrix(c(0,0,-1,0,0,0,-1,0,0), nrow=3, ncol=3, byrow = TRUE) + //' lmi = list(M0, M1,M2) + //' S = Spectrahedron$new(lmi); + //' //' @export class_("Spectrahedron") // expose the default constructor diff --git a/include/SDPAFormatManager.h b/include/SDPAFormatManager.h index 50f2d344d..53ddc8167 100644 --- a/include/SDPAFormatManager.h +++ b/include/SDPAFormatManager.h @@ -1,6 +1,4 @@ -// -// Created by panagiotis on 20/7/2019. -// +//Contributed and/or modified by Repouskos Panagiotis, as part of Google Summer of Code 2019 program. #ifndef VOLESTI_SDPA_FORMAT_MANAGER_H #define VOLESTI_SDPA_FORMAT_MANAGER_H @@ -244,7 +242,7 @@ class SdpaFormatManager { loadSDPAFormatFile(is, matrices, coeffs); LMI lmi(matrices); spectrahedron = Spectrahedron(lmi); - objectiveFunction = Point(coeffs); + objectiveFunction = Point(coeffs); } From 2d96dc4f93da17c67e1353baf6328ba2843c1cad Mon Sep 17 00:00:00 2001 From: Repouskos Panagiotis Date: Thu, 26 Mar 2020 17:01:06 +0200 Subject: [PATCH 03/38] R documentation and examples - fix examples - add data for example - add roxygen comments --- R-proj/R/RcppExports.R | 5 +++-- R-proj/R/read_sdpa_file.R | 5 ++++- R-proj/inst/extdata/sdpa_n2m3.txt | 13 +++++++++++++ R-proj/man/Rcpp_Spectrahedron.Rd | 21 +++++++++++++++++++++ R-proj/man/Spectrahedron.Rd | 12 ++++++++++++ R-proj/man/loadSdpaFormatFile.Rd | 3 ++- R-proj/man/readSdpaFormatFile.Rd | 5 ++++- R-proj/man/writeSdpaFormatFile.Rd | 2 +- R-proj/src/spectrahedron.cpp | 12 ++++++++++-- R-proj/src/spectrahedron_module.cpp | 7 +++++++ 10 files changed, 77 insertions(+), 8 deletions(-) create mode 100644 R-proj/inst/extdata/sdpa_n2m3.txt create mode 100644 R-proj/man/Rcpp_Spectrahedron.Rd create mode 100644 R-proj/man/Spectrahedron.Rd diff --git a/R-proj/R/RcppExports.R b/R-proj/R/RcppExports.R index 6635fd10e..7aedcba8e 100644 --- a/R-proj/R/RcppExports.R +++ b/R-proj/R/RcppExports.R @@ -235,7 +235,7 @@ sample_points <- function(P = NULL, n = NULL, random_walk = NULL, distribution = #' A0 = matrix(c(-1,0,0,0,-2,1,0,1,-2), nrow=3, ncol=3, byrow = TRUE) #' A1 = matrix(c(-1,0,0,0,0,1,0,1,0), nrow=3, ncol=3, byrow = TRUE) #' A2 = matrix(c(0,0,-1,0,0,0,-1,0,0), nrow=3, ncol=3, byrow = TRUE) -#' lmi = list(M0, M1,M2) +#' lmi = list(A0, A1, A2) #' S = Spectrahedron$new(lmi); #' objFunction = c(1,1) #' writeSdpaFormatFile(S, objFunction, "output.txt") @@ -251,7 +251,8 @@ writeSdpaFormatFile <- function(spectrahedron = NULL, objectiveFunction = NULL, #' @return A list with two named items: an item "matrices" which is a list of the matrices and an vector "objFunction" #' #' @examples -#' l = loadSdpaFormatFile("input.txt") +#' path = system.file('extdata', package = 'volesti') +#' l = loadSdpaFormatFile(paste0(path,'/sdpa_n2m3.txt')) #' @export loadSdpaFormatFile <- function(inputFile = NULL) { .Call(`_volesti_loadSdpaFormatFile`, inputFile) diff --git a/R-proj/R/read_sdpa_file.R b/R-proj/R/read_sdpa_file.R index f4f90e58a..cc24de8ad 100644 --- a/R-proj/R/read_sdpa_file.R +++ b/R-proj/R/read_sdpa_file.R @@ -8,7 +8,10 @@ #' @return A list with two named items: an item "matrices" which is an object of class Spectrahedron and an vector "objFunction" #' #' @examples -#' l = loadSdpaFormatFile("input.txt") +#' path = system.file('extdata', package = 'volesti') +#' l = readSdpaFormatFile(paste0(path,'/sdpa_n2m3.txt')) +#' Spectrahedron = l$spectrahedron +#' objFunction = l$objFunction #' @export #' @useDynLib volesti, .registration=TRUE #' @importFrom Rcpp evalCpp diff --git a/R-proj/inst/extdata/sdpa_n2m3.txt b/R-proj/inst/extdata/sdpa_n2m3.txt new file mode 100644 index 000000000..0459374cf --- /dev/null +++ b/R-proj/inst/extdata/sdpa_n2m3.txt @@ -0,0 +1,13 @@ +2 +1 +3 +1 1 +-1 0 0 + 0 -2 1 + 0 1 -2 + 1 -0 -0 +-0 -0 -1 +-0 -1 -0 +-0 -0 1 +-0 -0 -0 + 1 -0 -0 diff --git a/R-proj/man/Rcpp_Spectrahedron.Rd b/R-proj/man/Rcpp_Spectrahedron.Rd new file mode 100644 index 000000000..3ac432e59 --- /dev/null +++ b/R-proj/man/Rcpp_Spectrahedron.Rd @@ -0,0 +1,21 @@ +\docType{class} +\name{Rcpp_Spectrahedron} +\alias{Rcpp_Spectrahedron-class} +\alias{[,Rcpp_Spectrahedron-method} +\alias{[,Rcpp_Spectrahedron,ANY,ANY,ANY-method} +\alias{$<-,Rcpp_Spectrahedron-method} +\alias{$,Rcpp_Spectrahedron-method} +\alias{filepaths<-,Rcpp_Spectrahedron-method} +\title{ +An \code{Rcpp} class to represent spectrahedra, exposed to \code{R} via modules. +} +\description{ +A spectrahedron is a convex body defined by a linear matrix inequality of the form \eqn{A_0 + x_1 A_1 + ... + x_n A_n \preceq 0}. +The matrices \eqn{A_i} are symmetric \eqn{m \times m} real matrices and \eqn{\preceq 0} denoted negative semidefiniteness. +} +\details{ +\describe{ +\item{\code{matrices} }{A list with the matrices \eqn{A_0, A_1, ..., A_n}} + } +} + diff --git a/R-proj/man/Spectrahedron.Rd b/R-proj/man/Spectrahedron.Rd new file mode 100644 index 000000000..6c6df1d8a --- /dev/null +++ b/R-proj/man/Spectrahedron.Rd @@ -0,0 +1,12 @@ +\name{Spectrahedron} +\alias{Spectrahedron} +\title{An \code{R} class to represent spectrahedra.} + +\description{ +A spectrahedron is a convex body defined by a linear matrix inequality of the form \eqn{A_0 + x_1 A_1 + ... + x_n A_n \preceq 0}. +The matrices \eqn{A_i} are symmetric \eqn{m \times m} real matrices and \eqn{\preceq 0} denoted negative semidefiniteness. +} +\section{Fields}{ +\itemize{ +\item{\code{matrices} }{A list with the matrices \eqn{A_0, A_1, ..., A_n}} +}} diff --git a/R-proj/man/loadSdpaFormatFile.Rd b/R-proj/man/loadSdpaFormatFile.Rd index 7084f5235..690dda86b 100644 --- a/R-proj/man/loadSdpaFormatFile.Rd +++ b/R-proj/man/loadSdpaFormatFile.Rd @@ -19,5 +19,6 @@ Read a SDPA format file }} \examples{ -l = loadSdpaFormatFile("input.txt") +path = system.file('extdata', package = 'volesti') +l = loadSdpaFormatFile(paste0(path,'/sdpa_n2m3.txt')) } diff --git a/R-proj/man/readSdpaFormatFile.Rd b/R-proj/man/readSdpaFormatFile.Rd index f40dbe348..19dac7866 100644 --- a/R-proj/man/readSdpaFormatFile.Rd +++ b/R-proj/man/readSdpaFormatFile.Rd @@ -20,5 +20,8 @@ the linear matrix inequality in the input file, and the objective function. }} \examples{ -l = loadSdpaFormatFile("input.txt") +path = system.file('extdata', package = 'volesti') +l = readSdpaFormatFile(paste0(path,'/sdpa_n2m3.txt')) +Spectrahedron = l$spectrahedron +objFunction = l$objFunction } diff --git a/R-proj/man/writeSdpaFormatFile.Rd b/R-proj/man/writeSdpaFormatFile.Rd index c9520208b..5b2908ea7 100644 --- a/R-proj/man/writeSdpaFormatFile.Rd +++ b/R-proj/man/writeSdpaFormatFile.Rd @@ -28,7 +28,7 @@ to a SDPA format file. A0 = matrix(c(-1,0,0,0,-2,1,0,1,-2), nrow=3, ncol=3, byrow = TRUE) A1 = matrix(c(-1,0,0,0,0,1,0,1,0), nrow=3, ncol=3, byrow = TRUE) A2 = matrix(c(0,0,-1,0,0,0,-1,0,0), nrow=3, ncol=3, byrow = TRUE) -lmi = list(M0, M1,M2) +lmi = list(A0, A1, A2) S = Spectrahedron$new(lmi); objFunction = c(1,1) writeSdpaFormatFile(S, objFunction, "output.txt") diff --git a/R-proj/src/spectrahedron.cpp b/R-proj/src/spectrahedron.cpp index 6694ea2d9..69cc99893 100644 --- a/R-proj/src/spectrahedron.cpp +++ b/R-proj/src/spectrahedron.cpp @@ -1,5 +1,12 @@ +// 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 #include #include @@ -25,7 +32,7 @@ //' A0 = matrix(c(-1,0,0,0,-2,1,0,1,-2), nrow=3, ncol=3, byrow = TRUE) //' A1 = matrix(c(-1,0,0,0,0,1,0,1,0), nrow=3, ncol=3, byrow = TRUE) //' A2 = matrix(c(0,0,-1,0,0,0,-1,0,0), nrow=3, ncol=3, byrow = TRUE) -//' lmi = list(M0, M1,M2) +//' lmi = list(A0, A1, A2) //' S = Spectrahedron$new(lmi); //' objFunction = c(1,1) //' writeSdpaFormatFile(S, objFunction, "output.txt") @@ -76,7 +83,8 @@ class _Spectrahedron { //' @return A list with two named items: an item "matrices" which is a list of the matrices and an vector "objFunction" //' //' @examples -//' l = loadSdpaFormatFile("input.txt") +//' path = system.file('extdata', package = 'volesti') +//' l = loadSdpaFormatFile(paste0(path,'/sdpa_n2m3.txt')) //' @export // [[Rcpp::export]] Rcpp::List loadSdpaFormatFile(Rcpp::Nullable inputFile = R_NilValue) { diff --git a/R-proj/src/spectrahedron_module.cpp b/R-proj/src/spectrahedron_module.cpp index 21465546a..2786c88b1 100644 --- a/R-proj/src/spectrahedron_module.cpp +++ b/R-proj/src/spectrahedron_module.cpp @@ -1,5 +1,12 @@ +// 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 class Spectrahedron { From b57a3cf4dfe3d0e148c6117914c9b1905612caa4 Mon Sep 17 00:00:00 2001 From: Repouskos Panagiotis Date: Thu, 26 Mar 2020 18:28:55 +0200 Subject: [PATCH 04/38] tests for sdpa format manager - add copyrights headers - add test that writes and reads a sdpa format file - add the test in test/CMakeLists.txt --- include/SDPAFormatManager.h | 18 +++++++++++++----- include/convex_bodies/LMI.h | 23 ++++++++--------------- include/convex_bodies/spectrahedron.h | 11 ++++++++--- test/CMakeLists.txt | 6 ++++-- test/test_sdpa_format.cpp | 1 + 5 files changed, 34 insertions(+), 25 deletions(-) create mode 100755 test/test_sdpa_format.cpp diff --git a/include/SDPAFormatManager.h b/include/SDPAFormatManager.h index 53ddc8167..69eea91d3 100644 --- a/include/SDPAFormatManager.h +++ b/include/SDPAFormatManager.h @@ -1,5 +1,12 @@ +// 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 + #ifndef VOLESTI_SDPA_FORMAT_MANAGER_H #define VOLESTI_SDPA_FORMAT_MANAGER_H @@ -109,29 +116,30 @@ class SdpaFormatManager { int variablesNum = fetchNumber(line); if (std::getline(is, line, '\n').eof()) - throw 1; + throw std::runtime_error("Unexpected end of file"); //read number of blocks int blocksNum = fetchNumber(line); if (std::getline(is, line, '\n').eof()) - throw 1; + throw std::runtime_error("Unexpected end of file"); //read block structure vector listVector blockStructure = readVector(line); if (blockStructure.size() != blocksNum) - throw 1; + throw std::runtime_error("Wrong number of blocks"); if (std::getline(is, line, '\n').eof()) - throw 1; + throw std::runtime_error("Unexpected end of file"); //read constant vector listVector constantVector = readVector(line); while (constantVector.size() < variablesNum) { if (std::getline(is, line, '\n').eof()) - throw 1; + throw std::runtime_error("Unexpected end of file"); + listVector t = readVector(line); constantVector.insert(std::end(constantVector), std::begin(t), std::end(t)); } diff --git a/include/convex_bodies/LMI.h b/include/convex_bodies/LMI.h index 301a18da6..a68f0105c 100644 --- a/include/convex_bodies/LMI.h +++ b/include/convex_bodies/LMI.h @@ -1,6 +1,11 @@ -// -// Created by panagiotis on 2/22/20. -// +// 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 #ifndef VOLESTI_LMI_H #define VOLESTI_LMI_H @@ -112,17 +117,6 @@ class LMI, 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); @@ -152,7 +146,6 @@ class LMI, Eigen::Matrix) - + add_executable(test_sdpa_format test_sdpa_format.cpp $) add_executable (cheb_test chebychev_test.cpp $) #add_executable (rounding_test rounding_test.cpp $) add_executable (volumeCG_test volumeCG_test.cpp $) @@ -82,7 +82,9 @@ else () add_executable (ZonotopeVol_test ZonotopeVol_test.cpp $) add_executable (cool_bodies_bill_test cooling_bodies_bill_test.cpp $) #add_executable (ZonotopeVolCG_test ZonotopeVolCG_test.cpp $) - + + add_test(NAME test_sdpa_format COMMAND test_sdpa_format -tc=sdpa_format_parser) + add_test(NAME volume_cube COMMAND volume_test -tc=cube) add_test(NAME volume_cross COMMAND volume_test -tc=cross) add_test(NAME volume_birkhoff COMMAND volume_test -tc=birk) diff --git a/test/test_sdpa_format.cpp b/test/test_sdpa_format.cpp new file mode 100755 index 000000000..2c39efe0c --- /dev/null +++ b/test/test_sdpa_format.cpp @@ -0,0 +1 @@ +// 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 "vector" #include #include "cartesian_geom/cartesian_kernel.h" #include "spectrahedron.h" #include "SDPAFormatManager.h" #include "string" #include "iostream" typedef double NT; typedef Eigen::Matrix VT; typedef Eigen::Matrix MT; typedef Cartesian Kernel; typedef typename Kernel::Point Point; typedef Spectrahedron SPECTRAHEDRON; // create the data to write to sdpa file 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_sdpa_format() { //create data to write to file SPECTRAHEDRON spectrahedron; Point objFunction; populateValues(spectrahedron, objFunction); std::string fileName("sdpaFormatTest.txt"); // write the data to a file std::filebuf fb; fb.open(fileName, std::ios::out); std::ostream os(&fb); SdpaFormatManager sdpaFormatManager; sdpaFormatManager.writeSDPAFormatFile(os, spectrahedron, objFunction); os.flush(); // now Read it back! SPECTRAHEDRON spectrahedron1; Point objFunction1; std::ifstream in; in.open(fileName, std::ifstream::in); sdpaFormatManager.loadSDPAFormatFile(in, spectrahedron1, objFunction1); // check if what you wrote and read are the same bool areTheSame = true; while (true) { if (!(objFunction == objFunction1)) { areTheSame = false; break; } std::vector matrices1 = spectrahedron1.getLMI().getMatrices(); int atMatrix1 = 0; for (auto matrix : spectrahedron.getLMI().getMatrices()) { MT matrix1 = matrices1[atMatrix1++]; for (int i=0 ; i Date: Thu, 26 Mar 2020 21:09:43 +0200 Subject: [PATCH 05/38] add example code for sdpa files - create folder examples in root - add an example main to read / write sdpa format files --- examples/CMakeLists.txt | 67 +++++++++++++++++++++ examples/spectrahedra/CMakeLists.txt | 12 ++++ examples/spectrahedra/data/sdp_n2m3.txt | 13 ++++ examples/spectrahedra/readWriteSdpaFile.cpp | 65 ++++++++++++++++++++ include/convex_bodies/LMI.h | 10 +++ 5 files changed, 167 insertions(+) create mode 100644 examples/CMakeLists.txt create mode 100644 examples/spectrahedra/CMakeLists.txt create mode 100644 examples/spectrahedra/data/sdp_n2m3.txt create mode 100644 examples/spectrahedra/readWriteSdpaFile.cpp diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt new file mode 100644 index 000000000..0e4d07aaf --- /dev/null +++ b/examples/CMakeLists.txt @@ -0,0 +1,67 @@ +# 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 + +project( VolEsti ) + + +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) + + +# Find lpsolve library +find_library(LP_SOLVE NAMES liblpsolve55.so PATHS /usr/lib/lp_solve) + +if (NOT LP_SOLVE) + message(FATAL_ERROR "This program requires the lp_solve library, and will not be compiled.") +else () + message(STATUS "Library lp_solve found: ${LP_SOLVE}") + + 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/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} "-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" ) + + add_subdirectory(spectrahedra) + +endif() + + diff --git a/examples/spectrahedra/CMakeLists.txt b/examples/spectrahedra/CMakeLists.txt new file mode 100644 index 000000000..0652983c3 --- /dev/null +++ b/examples/spectrahedra/CMakeLists.txt @@ -0,0 +1,12 @@ +# 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 + + +add_executable (readWriteSdpaFile readWriteSdpaFile.cpp) + + + + diff --git a/examples/spectrahedra/data/sdp_n2m3.txt b/examples/spectrahedra/data/sdp_n2m3.txt new file mode 100644 index 000000000..0459374cf --- /dev/null +++ b/examples/spectrahedra/data/sdp_n2m3.txt @@ -0,0 +1,13 @@ +2 +1 +3 +1 1 +-1 0 0 + 0 -2 1 + 0 1 -2 + 1 -0 -0 +-0 -0 -1 +-0 -1 -0 +-0 -0 1 +-0 -0 -0 + 1 -0 -0 diff --git a/examples/spectrahedra/readWriteSdpaFile.cpp b/examples/spectrahedra/readWriteSdpaFile.cpp new file mode 100644 index 000000000..a31137b53 --- /dev/null +++ b/examples/spectrahedra/readWriteSdpaFile.cpp @@ -0,0 +1,65 @@ +// 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 "Eigen/Eigen" +#include "vector" +#include +#include "cartesian_geom/cartesian_kernel.h" +#include "spectrahedron.h" +#include "SDPAFormatManager.h" +#include "string" +#include "iostream" + +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/include/convex_bodies/LMI.h b/include/convex_bodies/LMI.h index a68f0105c..c56adf05d 100644 --- a/include/convex_bodies/LMI.h +++ b/include/convex_bodies/LMI.h @@ -168,6 +168,16 @@ class LMI, Eigen::Matrix Date: Thu, 26 Mar 2020 21:54:02 +0200 Subject: [PATCH 06/38] fix file format --- test/test_sdpa_format.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test_sdpa_format.cpp b/test/test_sdpa_format.cpp index 2c39efe0c..a40c429c6 100755 --- a/test/test_sdpa_format.cpp +++ b/test/test_sdpa_format.cpp @@ -1 +1 @@ -// 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 "vector" #include #include "cartesian_geom/cartesian_kernel.h" #include "spectrahedron.h" #include "SDPAFormatManager.h" #include "string" #include "iostream" typedef double NT; typedef Eigen::Matrix VT; typedef Eigen::Matrix MT; typedef Cartesian Kernel; typedef typename Kernel::Point Point; typedef Spectrahedron SPECTRAHEDRON; // create the data to write to sdpa file 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_sdpa_format() { //create data to write to file SPECTRAHEDRON spectrahedron; Point objFunction; populateValues(spectrahedron, objFunction); std::string fileName("sdpaFormatTest.txt"); // write the data to a file std::filebuf fb; fb.open(fileName, std::ios::out); std::ostream os(&fb); SdpaFormatManager sdpaFormatManager; sdpaFormatManager.writeSDPAFormatFile(os, spectrahedron, objFunction); os.flush(); // now Read it back! SPECTRAHEDRON spectrahedron1; Point objFunction1; std::ifstream in; in.open(fileName, std::ifstream::in); sdpaFormatManager.loadSDPAFormatFile(in, spectrahedron1, objFunction1); // check if what you wrote and read are the same bool areTheSame = true; while (true) { if (!(objFunction == objFunction1)) { areTheSame = false; break; } std::vector matrices1 = spectrahedron1.getLMI().getMatrices(); int atMatrix1 = 0; for (auto matrix : spectrahedron.getLMI().getMatrices()) { MT matrix1 = matrices1[atMatrix1++]; for (int i=0 ; i #include "cartesian_geom/cartesian_kernel.h" #include "spectrahedron.h" #include "SDPAFormatManager.h" #include "string" #include "iostream" typedef double NT; typedef Eigen::Matrix VT; typedef Eigen::Matrix MT; typedef Cartesian Kernel; typedef typename Kernel::Point Point; typedef Spectrahedron SPECTRAHEDRON; // create the data to write to sdpa file 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_sdpa_format() { //create data to write to file SPECTRAHEDRON spectrahedron; Point objFunction; populateValues(spectrahedron, objFunction); std::string fileName("sdpaFormatTest.txt"); // write the data to a file std::filebuf fb; fb.open(fileName, std::ios::out); std::ostream os(&fb); SdpaFormatManager sdpaFormatManager; sdpaFormatManager.writeSDPAFormatFile(os, spectrahedron, objFunction); os.flush(); // now Read it back! SPECTRAHEDRON spectrahedron1; Point objFunction1; std::ifstream in; in.open(fileName, std::ifstream::in); sdpaFormatManager.loadSDPAFormatFile(in, spectrahedron1, objFunction1); // check if what you wrote and read are the same bool areTheSame = true; while (true) { if (!(objFunction == objFunction1)) { areTheSame = false; break; } std::vector matrices1 = spectrahedron1.getLMI().getMatrices(); int atMatrix1 = 0; for (auto matrix : spectrahedron.getLMI().getMatrices()) { MT matrix1 = matrices1[atMatrix1++]; for (int i = 0; i < matrix.rows(); ++i) { for (int j = 0; j < matrix.cols(); ++j) { if (matrix(i, j) != matrix1(i, j)) { areTheSame = false; break; } } } } break; } CHECK(areTheSame); } TEST_CASE ("sdpa_format_parser") { call_test_sdpa_format(); } \ No newline at end of file From 0c2a65a8a96bcf5c5387a95681b43a5261126843 Mon Sep 17 00:00:00 2001 From: Repouskos Panagiotis Date: Thu, 26 Mar 2020 21:59:06 +0200 Subject: [PATCH 07/38] fix file encoding --- test/test_sdpa_format.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test_sdpa_format.cpp b/test/test_sdpa_format.cpp index a40c429c6..a97f56f05 100755 --- a/test/test_sdpa_format.cpp +++ b/test/test_sdpa_format.cpp @@ -1 +1 @@ -// 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 "vector" #include #include "cartesian_geom/cartesian_kernel.h" #include "spectrahedron.h" #include "SDPAFormatManager.h" #include "string" #include "iostream" typedef double NT; typedef Eigen::Matrix VT; typedef Eigen::Matrix MT; typedef Cartesian Kernel; typedef typename Kernel::Point Point; typedef Spectrahedron SPECTRAHEDRON; // create the data to write to sdpa file 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_sdpa_format() { //create data to write to file SPECTRAHEDRON spectrahedron; Point objFunction; populateValues(spectrahedron, objFunction); std::string fileName("sdpaFormatTest.txt"); // write the data to a file std::filebuf fb; fb.open(fileName, std::ios::out); std::ostream os(&fb); SdpaFormatManager sdpaFormatManager; sdpaFormatManager.writeSDPAFormatFile(os, spectrahedron, objFunction); os.flush(); // now Read it back! SPECTRAHEDRON spectrahedron1; Point objFunction1; std::ifstream in; in.open(fileName, std::ifstream::in); sdpaFormatManager.loadSDPAFormatFile(in, spectrahedron1, objFunction1); // check if what you wrote and read are the same bool areTheSame = true; while (true) { if (!(objFunction == objFunction1)) { areTheSame = false; break; } std::vector matrices1 = spectrahedron1.getLMI().getMatrices(); int atMatrix1 = 0; for (auto matrix : spectrahedron.getLMI().getMatrices()) { MT matrix1 = matrices1[atMatrix1++]; for (int i = 0; i < matrix.rows(); ++i) { for (int j = 0; j < matrix.cols(); ++j) { if (matrix(i, j) != matrix1(i, j)) { areTheSame = false; break; } } } } break; } CHECK(areTheSame); } TEST_CASE ("sdpa_format_parser") { call_test_sdpa_format(); } \ No newline at end of file +// 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 "vector" #include #include "cartesian_geom/cartesian_kernel.h" #include "spectrahedron.h" #include "SDPAFormatManager.h" #include "string" #include "iostream" typedef double NT; typedef Eigen::Matrix VT; typedef Eigen::Matrix MT; typedef Cartesian Kernel; typedef typename Kernel::Point Point; typedef Spectrahedron SPECTRAHEDRON; // create the data to write to sdpa file 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_sdpa_format() { //create data to write to file SPECTRAHEDRON spectrahedron; Point objFunction; populateValues(spectrahedron, objFunction); std::string fileName("sdpaFormatTest.txt"); // write the data to a file std::filebuf fb; fb.open(fileName, std::ios::out); std::ostream os(&fb); SdpaFormatManager sdpaFormatManager; sdpaFormatManager.writeSDPAFormatFile(os, spectrahedron, objFunction); os.flush(); // now Read it back! SPECTRAHEDRON spectrahedron1; Point objFunction1; std::ifstream in; in.open(fileName, std::ifstream::in); sdpaFormatManager.loadSDPAFormatFile(in, spectrahedron1, objFunction1); // check if what you wrote and read are the same bool areTheSame = true; while (true) { if (!(objFunction == objFunction1)) { areTheSame = false; break; } std::vector matrices1 = spectrahedron1.getLMI().getMatrices(); int atMatrix1 = 0; for (auto matrix : spectrahedron.getLMI().getMatrices()) { MT matrix1 = matrices1[atMatrix1++]; for (int i = 0; i < matrix.rows(); ++i) { for (int j = 0; j < matrix.cols(); ++j) { if (matrix(i, j) != matrix1(i, j)) { areTheSame = false; break; } } } } break; } CHECK(areTheSame); } TEST_CASE ("sdpa_format_parser") { call_test_sdpa_format(); } \ No newline at end of file From 4549b469afdccb31c7aa1526a2b173f1d7573a85 Mon Sep 17 00:00:00 2001 From: Panagiotis Repouskos Date: Thu, 26 Mar 2020 22:01:09 +0200 Subject: [PATCH 08/38] use soft wrap with lines --- test/test_sdpa_format.cpp | 121 +++++++++++++++++++++++++++++++++++++- 1 file changed, 120 insertions(+), 1 deletion(-) diff --git a/test/test_sdpa_format.cpp b/test/test_sdpa_format.cpp index a97f56f05..35a6e6e04 100755 --- a/test/test_sdpa_format.cpp +++ b/test/test_sdpa_format.cpp @@ -1 +1,120 @@ -// 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 "vector" #include #include "cartesian_geom/cartesian_kernel.h" #include "spectrahedron.h" #include "SDPAFormatManager.h" #include "string" #include "iostream" typedef double NT; typedef Eigen::Matrix VT; typedef Eigen::Matrix MT; typedef Cartesian Kernel; typedef typename Kernel::Point Point; typedef Spectrahedron SPECTRAHEDRON; // create the data to write to sdpa file 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_sdpa_format() { //create data to write to file SPECTRAHEDRON spectrahedron; Point objFunction; populateValues(spectrahedron, objFunction); std::string fileName("sdpaFormatTest.txt"); // write the data to a file std::filebuf fb; fb.open(fileName, std::ios::out); std::ostream os(&fb); SdpaFormatManager sdpaFormatManager; sdpaFormatManager.writeSDPAFormatFile(os, spectrahedron, objFunction); os.flush(); // now Read it back! SPECTRAHEDRON spectrahedron1; Point objFunction1; std::ifstream in; in.open(fileName, std::ifstream::in); sdpaFormatManager.loadSDPAFormatFile(in, spectrahedron1, objFunction1); // check if what you wrote and read are the same bool areTheSame = true; while (true) { if (!(objFunction == objFunction1)) { areTheSame = false; break; } std::vector matrices1 = spectrahedron1.getLMI().getMatrices(); int atMatrix1 = 0; for (auto matrix : spectrahedron.getLMI().getMatrices()) { MT matrix1 = matrices1[atMatrix1++]; for (int i = 0; i < matrix.rows(); ++i) { for (int j = 0; j < matrix.cols(); ++j) { if (matrix(i, j) != matrix1(i, j)) { areTheSame = false; break; } } } } break; } CHECK(areTheSame); } TEST_CASE ("sdpa_format_parser") { call_test_sdpa_format(); } \ No newline at end of file +// 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 "vector" +#include +#include "cartesian_geom/cartesian_kernel.h" +#include "spectrahedron.h" +#include "SDPAFormatManager.h" +#include "string" +#include "iostream" + +typedef double NT; +typedef Eigen::Matrix VT; +typedef Eigen::Matrix MT; +typedef Cartesian Kernel; +typedef typename Kernel::Point Point; +typedef Spectrahedron SPECTRAHEDRON; + +// create the data to write to sdpa file +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_sdpa_format() { + + //create data to write to file + SPECTRAHEDRON spectrahedron; + Point objFunction; + + populateValues(spectrahedron, objFunction); + + std::string fileName("sdpaFormatTest.txt"); + + // write the data to a file + std::filebuf fb; + fb.open(fileName, std::ios::out); + std::ostream os(&fb); + SdpaFormatManager sdpaFormatManager; + sdpaFormatManager.writeSDPAFormatFile(os, spectrahedron, objFunction); + os.flush(); + + // now Read it back! + SPECTRAHEDRON spectrahedron1; + Point objFunction1; + std::ifstream in; + in.open(fileName, std::ifstream::in); + sdpaFormatManager.loadSDPAFormatFile(in, spectrahedron1, objFunction1); + + // check if what you wrote and read are the same + bool areTheSame = true; + + while (true) { + if (!(objFunction == objFunction1)) { + areTheSame = false; + break; + } + + std::vector matrices1 = spectrahedron1.getLMI().getMatrices(); + + int atMatrix1 = 0; + for (auto matrix : spectrahedron.getLMI().getMatrices()) { + MT matrix1 = matrices1[atMatrix1++]; + + for (int i = 0; i < matrix.rows(); ++i) { + for (int j = 0; j < matrix.cols(); ++j) { + if (matrix(i, j) != matrix1(i, j)) { + areTheSame = false; + break; + } + } + } + } + + break; + } + + + CHECK(areTheSame); +} + + +TEST_CASE ("sdpa_format_parser") { + call_test_sdpa_format(); +} + From 762da8025eb1cdf2cc643958c859ae4d274017ab Mon Sep 17 00:00:00 2001 From: Repouskos Panagiotis Date: Sun, 29 Mar 2020 14:13:36 +0300 Subject: [PATCH 09/38] create folder spectrahedra - move in new folder spectrahedron.h, LMI.h - update CMakeLists.txt in folder examples, tests - update Makevars in R-prog/src and in cran_gen - add documentation for sdpa file example --- R-proj/src/Makevars | 2 +- R-proj/src/Makevars.win | 2 +- cran_gen/Makevars | 2 +- cran_gen/Makevars.win | 2 +- examples/CMakeLists.txt | 1 + examples/spectrahedra/data/README.md | 35 +++++++++++++++++++ .../convex_bodies/{ => spectrahedra}/LMI.h | 0 .../{ => spectrahedra}/spectrahedron.h | 0 test/CMakeLists.txt | 1 + 9 files changed, 41 insertions(+), 4 deletions(-) create mode 100644 examples/spectrahedra/data/README.md rename include/convex_bodies/{ => spectrahedra}/LMI.h (100%) rename include/convex_bodies/{ => spectrahedra}/spectrahedron.h (100%) diff --git a/R-proj/src/Makevars b/R-proj/src/Makevars index fa2b37e3f..7d6552945 100644 --- a/R-proj/src/Makevars +++ b/R-proj/src/Makevars @@ -1,4 +1,4 @@ -PKG_CPPFLAGS=-I../../external/boost -I../../external/LPsolve_src/run_headers -I../../external/minimum_ellipsoid -I../../include -I../../include/volume -I../../include/generators -I../../include/samplers -I../../include/annealing -I../../include/convex_bodies -I../../include/lp_oracles -I../../include/misc +PKG_CPPFLAGS=-I../../external/boost -I../../external/LPsolve_src/run_headers -I../../external/minimum_ellipsoid -I../../include -I../../include/volume -I../../include/generators -I../../include/samplers -I../../include/annealing -I../../include/convex_bodies -I../../include/convex_bodies/spectrahedra -I../../include/lp_oracles -I../../include/misc PKG_CXXFLAGS= -lm -ldl -Wno-ignored-attributes -DBOOST_NO_AUTO_PTR CXX_STD = CXX11 diff --git a/R-proj/src/Makevars.win b/R-proj/src/Makevars.win index a70f47bb1..efef342e6 100644 --- a/R-proj/src/Makevars.win +++ b/R-proj/src/Makevars.win @@ -1,4 +1,4 @@ -PKG_CPPFLAGS=-I../../external/boost -I../../external/LPsolve_src/run_headers -I../../external/minimum_ellipsoid -I../../include -I../../include/volume -I../../include/generators -I../../include/samplers -I../../include/annealing -I../../include/convex_bodies -I../../include/lp_oracles -I../../include/misc +PKG_CPPFLAGS=-I../../external/boost -I../../external/LPsolve_src/run_headers -I../../external/minimum_ellipsoid -I../../include -I../../include/volume -I../../include/convex_bodies/spectrahedra -I../../include/generators -I../../include/samplers -I../../include/annealing -I../../include/convex_bodies -I../../include/lp_oracles -I../../include/misc PKG_CXXFLAGS= -lm -ldl -Wno-ignored-attributes -DBOOST_NO_AUTO_PTR CXX_STD = CXX11 diff --git a/cran_gen/Makevars b/cran_gen/Makevars index 471f24c4c..c007c1377 100644 --- a/cran_gen/Makevars +++ b/cran_gen/Makevars @@ -1,4 +1,4 @@ -PKG_CPPFLAGS=-Iexternal/lpsolve/headers/run_headers -Iexternal/minimum_ellipsoid -Iinclude -Iinclude/volume -Iinclude/lp_oracles -Iinclude/generators -Iinclude/samplers -Iinclude/annealing -Iinclude/convex_bodies +PKG_CPPFLAGS=-Iexternal/lpsolve/headers/run_headers -Iinclude/convex_bodies/spectrahedra -Iexternal/minimum_ellipsoid -Iinclude -Iinclude/volume -Iinclude/lp_oracles -Iinclude/generators -Iinclude/samplers -Iinclude/annealing -Iinclude/convex_bodies PKG_CXXFLAGS= -DBOOST_NO_AUTO_PTR CXX_STD = CXX11 diff --git a/cran_gen/Makevars.win b/cran_gen/Makevars.win index d9a91c106..0b9ac328f 100644 --- a/cran_gen/Makevars.win +++ b/cran_gen/Makevars.win @@ -1,4 +1,4 @@ -PKG_CPPFLAGS=-Iexternal/lpsolve/headers/run_headers -Iexternal/minimum_ellipsoid -Iinclude -Iinclude/volume -Iinclude/generators -Iinclude/lp_oracles -Iinclude/samplers -Iinclude/annealing -Iinclude/convex_bodies +PKG_CPPFLAGS=-Iexternal/lpsolve/headers/run_headers -Iexternal/minimum_ellipsoid -Iinclude/convex_bodies/spectrahedra -Iinclude -Iinclude/volume -Iinclude/generators -Iinclude/lp_oracles -Iinclude/samplers -Iinclude/annealing -Iinclude/convex_bodies PKG_CXXFLAGS= -lm -ldl -DBOOST_NO_AUTO_PTR CXX_STD = CXX11 diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 0e4d07aaf..c90c44c22 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -42,6 +42,7 @@ else () include_directories (BEFORE ../include/samplers) include_directories (BEFORE ../include/lp_oracles) include_directories (BEFORE ../include/misc) + include_directories (BEFORE ../include/convex_bodies/spectrahedra) # for Eigen if (${CMAKE_VERSION} VERSION_LESS "3.12.0") diff --git a/examples/spectrahedra/data/README.md b/examples/spectrahedra/data/README.md new file mode 100644 index 000000000..ed3df343c --- /dev/null +++ b/examples/spectrahedra/data/README.md @@ -0,0 +1,35 @@ +## SDPA format + +The file sdp_n2m3.txt contains a semidefinite program in SDPA format. For details in the SDPA format you can +search the official manual. + +The contents of the file are: + +2
+1
+3
+1 1
+-1 0 0
+ 0 -2 1
+ 0 1 -2
+ 1 -0 -0
+-0 -0 -1
+-0 -1 -0
+-0 -0 1
+-0 -0 -0
+ 1 -0 -0 + +It represents a spectrahedron in 2 dimensions and a linear objective function. The spectrahedron is described +by a linear matrix inequality, of the form x1 A1 + ... + xn An - A0 >= 0, where >= 0 denotes positive semidefiniteness. + +### Explanation line by line +- 2 : The number of dimensions. The vector of the objective function is of length 2 and we need 3 matrices for + the linear matrix inequality, i.e. x A1 + y A2 - A0 >= 0. +- 1 : Please lookup SDPA format for more details. Currently support is only for value 1. +- 3 : The size of the matrices, i.e. 3x3 +- 1 1 : The vector of the objective function, i.e. (1,1) or f(x,y) = x + y +- -1 0 0: The first row of A0 +- 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 diff --git a/include/convex_bodies/LMI.h b/include/convex_bodies/spectrahedra/LMI.h similarity index 100% rename from include/convex_bodies/LMI.h rename to include/convex_bodies/spectrahedra/LMI.h diff --git a/include/convex_bodies/spectrahedron.h b/include/convex_bodies/spectrahedra/spectrahedron.h similarity index 100% rename from include/convex_bodies/spectrahedron.h rename to include/convex_bodies/spectrahedra/spectrahedron.h diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 075ee0ddb..a8c068501 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -45,6 +45,7 @@ else () 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/annealing) include_directories (BEFORE ../include/samplers) include_directories (BEFORE ../include/lp_oracles) From f873f3129d8cefa604a0467f38b6371c08ec66d2 Mon Sep 17 00:00:00 2001 From: Repouskos Panagiotis Date: Wed, 1 Apr 2020 16:20:28 +0300 Subject: [PATCH 10/38] examples/spectrahedra documentation --- examples/spectrahedra/README.md | 65 ++++++++++++++++++++++++++++ examples/spectrahedra/data/README.md | 35 --------------- 2 files changed, 65 insertions(+), 35 deletions(-) create mode 100644 examples/spectrahedra/README.md delete mode 100644 examples/spectrahedra/data/README.md diff --git a/examples/spectrahedra/README.md b/examples/spectrahedra/README.md new file mode 100644 index 000000000..a92b07a38 --- /dev/null +++ b/examples/spectrahedra/README.md @@ -0,0 +1,65 @@ +#Examples for Spectrahedra + +##Compilation +In folder examples, first run cmake, to create the makefile: + +```bash +cmake . +``` + +Then, in folder examples/spectrahedra compile using the makefile: + +```bash +make +``` + +## List of examples +- Example 1: Read/write SDPA format files + +## Examples +### Example 1: Read/write SDPA format files + +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 +``` + +The input file is data/sdp_n2m3.txt. It contains a semidefinite program in SDPA format. A semidefinite program +(dual form) consists of a linear matrix inequality (describing a spectrahedron) of the form A1 + ... + xn An - A0 >= 0, +where >= 0 denotes positive semidefiniteness. For details in the SDPA format you can search the official manual. + +The contents of the file are: + +```bash +2 +1 +3 +1 1 +-1 0 0 + 0 -2 1 + 0 1 -2 + 1 -0 -0 +-0 -0 -1 +-0 -1 -0 +-0 -0 1 +-0 -0 -0 + 1 -0 -0 +``` + + +It represents a spectrahedron in 2 dimensions, described by a linear matrix inequality with +3x3 matrices, and a linear objective function. + +##### Explanation line by line +- 2 : The number of dimensions. The vector of the objective function is of length 2 and we need 3 matrices for + the linear matrix inequality, i.e. x A1 + y A2 - A0 >= 0. +- 1 : Please lookup SDPA format for more details. Currently, support is only for value 1. +- 3 : The size of the matrices, i.e. 3x3 +- 1 1 : The vector of the objective function, i.e. (1,1) or f(x,y) = x + y +- -1 0 0: The first row of A0 +- 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 diff --git a/examples/spectrahedra/data/README.md b/examples/spectrahedra/data/README.md deleted file mode 100644 index ed3df343c..000000000 --- a/examples/spectrahedra/data/README.md +++ /dev/null @@ -1,35 +0,0 @@ -## SDPA format - -The file sdp_n2m3.txt contains a semidefinite program in SDPA format. For details in the SDPA format you can -search the official manual. - -The contents of the file are: - -2
-1
-3
-1 1
--1 0 0
- 0 -2 1
- 0 1 -2
- 1 -0 -0
--0 -0 -1
--0 -1 -0
--0 -0 1
--0 -0 -0
- 1 -0 -0 - -It represents a spectrahedron in 2 dimensions and a linear objective function. The spectrahedron is described -by a linear matrix inequality, of the form x1 A1 + ... + xn An - A0 >= 0, where >= 0 denotes positive semidefiniteness. - -### Explanation line by line -- 2 : The number of dimensions. The vector of the objective function is of length 2 and we need 3 matrices for - the linear matrix inequality, i.e. x A1 + y A2 - A0 >= 0. -- 1 : Please lookup SDPA format for more details. Currently support is only for value 1. -- 3 : The size of the matrices, i.e. 3x3 -- 1 1 : The vector of the objective function, i.e. (1,1) or f(x,y) = x + y -- -1 0 0: The first row of A0 -- 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 From 2d98f218a61bc430e323bc7136db6ebca45ef8b1 Mon Sep 17 00:00:00 2001 From: Repouskos Panagiotis Date: Wed, 1 Apr 2020 16:22:29 +0300 Subject: [PATCH 11/38] examples/spectrahedra documentation fix headers --- examples/spectrahedra/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/spectrahedra/README.md b/examples/spectrahedra/README.md index a92b07a38..9c8f6a4e9 100644 --- a/examples/spectrahedra/README.md +++ b/examples/spectrahedra/README.md @@ -1,6 +1,6 @@ -#Examples for Spectrahedra +# Examples for Spectrahedra -##Compilation +## Compilation In folder examples, first run cmake, to create the makefile: ```bash From 84c52ae7157c8ee2ffb8dd7ccd13bf8d296b01eb Mon Sep 17 00:00:00 2001 From: Repouskos Panagiotis Date: Wed, 1 Apr 2020 16:45:31 +0300 Subject: [PATCH 12/38] rename R modules - rename module in polytopes_modules.cpp to "polytopes" - rename module in spectrahedron_module.cpp to "spectrahedron" - fix dates in copyrights headers in files - add a newline in end of file spectrahedron.h --- R-proj/R/zzz.R | 4 ++-- R-proj/src/polytopes_modules.cpp | 4 ++-- R-proj/src/spectrahedron.cpp | 6 +++--- R-proj/src/spectrahedron_module.cpp | 8 ++++---- include/SDPAFormatManager.h | 8 ++++---- include/convex_bodies/spectrahedra/LMI.h | 4 ++-- include/convex_bodies/spectrahedra/spectrahedron.h | 4 ++-- 7 files changed, 19 insertions(+), 19 deletions(-) diff --git a/R-proj/R/zzz.R b/R-proj/R/zzz.R index 36a821caf..564a20b9c 100644 --- a/R-proj/R/zzz.R +++ b/R-proj/R/zzz.R @@ -7,5 +7,5 @@ ## For R 2.15.1 and later this also works. Note that calling loadModule() triggers ## a load action, so this does not have to be placed in .onLoad() or evalqOnLoad(). -loadModule("yada", TRUE) -loadModule("spec", TRUE) +loadModule("polytopes", TRUE) +loadModule("spectrahedron", TRUE) diff --git a/R-proj/src/polytopes_modules.cpp b/R-proj/src/polytopes_modules.cpp index 464d476e4..1931c8808 100644 --- a/R-proj/src/polytopes_modules.cpp +++ b/R-proj/src/polytopes_modules.cpp @@ -73,7 +73,7 @@ class VPinterVP { }; -RCPP_MODULE(yada){ +RCPP_MODULE(polytopes){ using namespace Rcpp ; @@ -183,4 +183,4 @@ RCPP_MODULE(yada){ .field( "V2", &VPinterVP::V2 ); } -extern SEXP _rcpp_module_boot_yada(void); +extern SEXP _rcpp_module_boot_polytopes(void); diff --git a/R-proj/src/spectrahedron.cpp b/R-proj/src/spectrahedron.cpp index 69cc99893..f32a2cd1f 100644 --- a/R-proj/src/spectrahedron.cpp +++ b/R-proj/src/spectrahedron.cpp @@ -1,7 +1,7 @@ // VolEsti (volume computation and sampling library) -// Copyright (c) 20012-2018 Vissarion Fisikopoulos -// Copyright (c) 2018 Apostolos Chalkis +// 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. @@ -119,4 +119,4 @@ Rcpp::List loadSdpaFormatFile(Rcpp::Nullable inputFile = R_NilValue Rcpp::List retList = Rcpp::List::create(Rcpp::Named("matrices") = _matrices , Rcpp::_["objFunction"] = Rcpp::wrap(c.getCoefficients())); return Rcpp::wrap(retList); -} \ No newline at end of file +} diff --git a/R-proj/src/spectrahedron_module.cpp b/R-proj/src/spectrahedron_module.cpp index 2786c88b1..e39b7fada 100644 --- a/R-proj/src/spectrahedron_module.cpp +++ b/R-proj/src/spectrahedron_module.cpp @@ -1,7 +1,7 @@ // VolEsti (volume computation and sampling library) -// Copyright (c) 20012-2018 Vissarion Fisikopoulos -// Copyright (c) 2018 Apostolos Chalkis +// 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. @@ -20,7 +20,7 @@ class Spectrahedron { }; -RCPP_MODULE(spec){ +RCPP_MODULE(spectrahedron){ using namespace Rcpp ; //' An exposed class to represent a spectrahedron @@ -45,4 +45,4 @@ RCPP_MODULE(spec){ .field( "matrices", &Spectrahedron::matrices); } -extern SEXP _rcpp_module_boot_spec(void); +extern SEXP _rcpp_module_boot_spectrahedron(void); diff --git a/include/SDPAFormatManager.h b/include/SDPAFormatManager.h index 69eea91d3..d154bbeb4 100644 --- a/include/SDPAFormatManager.h +++ b/include/SDPAFormatManager.h @@ -1,7 +1,7 @@ // VolEsti (volume computation and sampling library) -// Copyright (c) 20012-2018 Vissarion Fisikopoulos -// Copyright (c) 2018 Apostolos Chalkis +// 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. @@ -40,8 +40,8 @@ class SdpaFormatManager { typedef Eigen::Matrix VT; /// Return the first non white space/tab character and advance the iterator one position - /// @param[in, out] it current position - /// @param[in] end end of string + /// @param[in, out] it Current position + /// @param[in] end End of string /// @return First non white space/tab character char consumeSymbol(string_it &at, string_it & end) { while (at != end) { diff --git a/include/convex_bodies/spectrahedra/LMI.h b/include/convex_bodies/spectrahedra/LMI.h index c56adf05d..af28ec114 100644 --- a/include/convex_bodies/spectrahedra/LMI.h +++ b/include/convex_bodies/spectrahedra/LMI.h @@ -1,7 +1,7 @@ // VolEsti (volume computation and sampling library) -// Copyright (c) 20012-2018 Vissarion Fisikopoulos -// Copyright (c) 2018 Apostolos Chalkis +// 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. diff --git a/include/convex_bodies/spectrahedra/spectrahedron.h b/include/convex_bodies/spectrahedra/spectrahedron.h index 157454b12..cd9e512c4 100644 --- a/include/convex_bodies/spectrahedra/spectrahedron.h +++ b/include/convex_bodies/spectrahedra/spectrahedron.h @@ -1,7 +1,7 @@ // VolEsti (volume computation and sampling library) -// Copyright (c) 20012-2018 Vissarion Fisikopoulos -// Copyright (c) 2018 Apostolos Chalkis +// 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. From cb40bce174725d43629e090c54b8c6688dc94814 Mon Sep 17 00:00:00 2001 From: Repouskos Panagiotis Date: Wed, 1 Apr 2020 21:22:13 +0300 Subject: [PATCH 13/38] make LMI::getMatrices() return std::vector const & Also fix parameters documentation in R for functions - readSDPAFormatFile - loadSDPAFormatFile - writeSDPAFormatFile --- R-proj/R/RcppExports.R | 8 ++++---- R-proj/R/read_sdpa_file.R | 2 +- R-proj/man/loadSdpaFormatFile.Rd | 9 +++------ R-proj/man/readSdpaFormatFile.Rd | 9 +++------ R-proj/man/writeSdpaFormatFile.Rd | 17 +++++++---------- R-proj/src/spectrahedron.cpp | 10 +++++----- include/convex_bodies/spectrahedra/LMI.h | 2 +- test/test_sdpa_format.cpp | 14 ++++++++------ 8 files changed, 32 insertions(+), 39 deletions(-) diff --git a/R-proj/R/RcppExports.R b/R-proj/R/RcppExports.R index 7aedcba8e..6e614b843 100644 --- a/R-proj/R/RcppExports.R +++ b/R-proj/R/RcppExports.R @@ -227,9 +227,9 @@ sample_points <- function(P = NULL, n = NULL, random_walk = NULL, distribution = #' Outputs a spectrahedron (the matrices defining a linear matrix inequality) and a vector (the objective function) #' to a SDPA format file. #' -#' @field spectrahedron A spectrahedron in n dimensions; must be an object of class Spectrahedron -#' @field objectiveFunction A numerical vector of length n -#' @field outputFile Name of the output file +#' @param spectrahedron A spectrahedron in n dimensions; must be an object of class Spectrahedron +#' @param objectiveFunction A numerical vector of length n +#' @param outputFile Name of the output file #' #' @examples #' A0 = matrix(c(-1,0,0,0,-2,1,0,1,-2), nrow=3, ncol=3, byrow = TRUE) @@ -246,7 +246,7 @@ writeSdpaFormatFile <- function(spectrahedron = NULL, objectiveFunction = NULL, #' Read a SDPA format file #' -#' @field inputFile Name of the input file +#' @param inputFile Name of the input file #' #' @return A list with two named items: an item "matrices" which is a list of the matrices and an vector "objFunction" #' diff --git a/R-proj/R/read_sdpa_file.R b/R-proj/R/read_sdpa_file.R index cc24de8ad..83c10c528 100644 --- a/R-proj/R/read_sdpa_file.R +++ b/R-proj/R/read_sdpa_file.R @@ -3,7 +3,7 @@ #' Read a SDPA format file and return a spectrahedron (an object of class Spectrahedron) which is defined by #' the linear matrix inequality in the input file, and the objective function. #' -#' @field path Name of the input file +#' @param path Name of the input file #' #' @return A list with two named items: an item "matrices" which is an object of class Spectrahedron and an vector "objFunction" #' diff --git a/R-proj/man/loadSdpaFormatFile.Rd b/R-proj/man/loadSdpaFormatFile.Rd index 690dda86b..bb6aa7558 100644 --- a/R-proj/man/loadSdpaFormatFile.Rd +++ b/R-proj/man/loadSdpaFormatFile.Rd @@ -6,18 +6,15 @@ \usage{ loadSdpaFormatFile(inputFile = NULL) } +\arguments{ +\item{inputFile}{Name of the input file} +} \value{ A list with two named items: an item "matrices" which is a list of the matrices and an vector "objFunction" } \description{ Read a SDPA format file } -\section{Fields}{ - -\describe{ -\item{\code{inputFile}}{Name of the input file} -}} - \examples{ path = system.file('extdata', package = 'volesti') l = loadSdpaFormatFile(paste0(path,'/sdpa_n2m3.txt')) diff --git a/R-proj/man/readSdpaFormatFile.Rd b/R-proj/man/readSdpaFormatFile.Rd index 19dac7866..878a11965 100644 --- a/R-proj/man/readSdpaFormatFile.Rd +++ b/R-proj/man/readSdpaFormatFile.Rd @@ -6,6 +6,9 @@ \usage{ readSdpaFormatFile(path) } +\arguments{ +\item{path}{Name of the input file} +} \value{ A list with two named items: an item "matrices" which is an object of class Spectrahedron and an vector "objFunction" } @@ -13,12 +16,6 @@ A list with two named items: an item "matrices" which is an object of class Spec Read a SDPA format file and return a spectrahedron (an object of class Spectrahedron) which is defined by the linear matrix inequality in the input file, and the objective function. } -\section{Fields}{ - -\describe{ -\item{\code{path}}{Name of the input file} -}} - \examples{ path = system.file('extdata', package = 'volesti') l = readSdpaFormatFile(paste0(path,'/sdpa_n2m3.txt')) diff --git a/R-proj/man/writeSdpaFormatFile.Rd b/R-proj/man/writeSdpaFormatFile.Rd index 5b2908ea7..02f8ef56c 100644 --- a/R-proj/man/writeSdpaFormatFile.Rd +++ b/R-proj/man/writeSdpaFormatFile.Rd @@ -10,20 +10,17 @@ writeSdpaFormatFile( outputFile = NULL ) } +\arguments{ +\item{spectrahedron}{A spectrahedron in n dimensions; must be an object of class Spectrahedron} + +\item{objectiveFunction}{A numerical vector of length n} + +\item{outputFile}{Name of the output file} +} \description{ Outputs a spectrahedron (the matrices defining a linear matrix inequality) and a vector (the objective function) to a SDPA format file. } -\section{Fields}{ - -\describe{ -\item{\code{spectrahedron}}{A spectrahedron in n dimensions; must be an object of class Spectrahedron} - -\item{\code{objectiveFunction}}{A numerical vector of length n} - -\item{\code{outputFile}}{Name of the output file} -}} - \examples{ A0 = matrix(c(-1,0,0,0,-2,1,0,1,-2), nrow=3, ncol=3, byrow = TRUE) A1 = matrix(c(-1,0,0,0,0,1,0,1,0), nrow=3, ncol=3, byrow = TRUE) diff --git a/R-proj/src/spectrahedron.cpp b/R-proj/src/spectrahedron.cpp index f32a2cd1f..a6b9e20c9 100644 --- a/R-proj/src/spectrahedron.cpp +++ b/R-proj/src/spectrahedron.cpp @@ -24,9 +24,9 @@ //' Outputs a spectrahedron (the matrices defining a linear matrix inequality) and a vector (the objective function) //' to a SDPA format file. //' -//' @field spectrahedron A spectrahedron in n dimensions; must be an object of class Spectrahedron -//' @field objectiveFunction A numerical vector of length n -//' @field outputFile Name of the output file +//' @param spectrahedron A spectrahedron in n dimensions; must be an object of class Spectrahedron +//' @param objectiveFunction A numerical vector of length n +//' @param outputFile Name of the output file //' //' @examples //' A0 = matrix(c(-1,0,0,0,-2,1,0,1,-2), nrow=3, ncol=3, byrow = TRUE) @@ -78,7 +78,7 @@ class _Spectrahedron { //' Read a SDPA format file //' -//' @field inputFile Name of the input file +//' @param inputFile Name of the input file //' //' @return A list with two named items: an item "matrices" which is a list of the matrices and an vector "objFunction" //' @@ -109,7 +109,7 @@ Rcpp::List loadSdpaFormatFile(Rcpp::Nullable inputFile = R_NilValue SdpaFormatManager sdpaFormatManager; sdpaFormatManager.loadSDPAFormatFile(os, _spectrahedron, c); - std::vector const & matrices = _spectrahedron.getLMI().getMatrices(); + std::vector matrices = _spectrahedron.getLMI().getMatrices(); // return spectrahedron and objective function Rcpp::List _matrices; diff --git a/include/convex_bodies/spectrahedra/LMI.h b/include/convex_bodies/spectrahedra/LMI.h index af28ec114..80524b51c 100644 --- a/include/convex_bodies/spectrahedra/LMI.h +++ b/include/convex_bodies/spectrahedra/LMI.h @@ -94,7 +94,7 @@ class LMI, Eigen::Matrix getMatrices() const { + std::vector const & getMatrices() const { return matrices; } diff --git a/test/test_sdpa_format.cpp b/test/test_sdpa_format.cpp index 35a6e6e04..b6f50cb25 100755 --- a/test/test_sdpa_format.cpp +++ b/test/test_sdpa_format.cpp @@ -93,12 +93,14 @@ void call_test_sdpa_format() { std::vector matrices1 = spectrahedron1.getLMI().getMatrices(); int atMatrix1 = 0; - for (auto matrix : spectrahedron.getLMI().getMatrices()) { + std::vector const & _matrices = spectrahedron.getLMI().getMatrices(); + + for (auto matrix = _matrices.begin(); matrix != _matrices.end() ; matrix++) { MT matrix1 = matrices1[atMatrix1++]; - for (int i = 0; i < matrix.rows(); ++i) { - for (int j = 0; j < matrix.cols(); ++j) { - if (matrix(i, j) != matrix1(i, j)) { + for (int i = 0; i < matrix->rows(); ++i) { + for (int j = 0; j < matrix->cols(); ++j) { + if ((*matrix)(i, j) != matrix1(i, j)) { areTheSame = false; break; } @@ -107,10 +109,10 @@ void call_test_sdpa_format() { } break; - } + } - CHECK(areTheSame); + CHECK(areTheSame); } From 65fe76569e78d18f556b787157bbd19f846dd170 Mon Sep 17 00:00:00 2001 From: Repouskos Panagiotis Date: Sun, 12 Apr 2020 20:55:35 +0300 Subject: [PATCH 14/38] rename typedefs in spectrahedron.cpp - rename SPECTRAHEDRON typedef to Spectrahedron - remove unneeded class _Spectrahedron in spectrahedron.cpp --- R-proj/src/spectrahedron.cpp | 28 ++++++++++------------------ 1 file changed, 10 insertions(+), 18 deletions(-) diff --git a/R-proj/src/spectrahedron.cpp b/R-proj/src/spectrahedron.cpp index a6b9e20c9..96d0168b7 100644 --- a/R-proj/src/spectrahedron.cpp +++ b/R-proj/src/spectrahedron.cpp @@ -44,16 +44,16 @@ void writeSdpaFormatFile(Rcpp::Nullable spectrahedron = R_NilVa typedef double NT; typedef Eigen::Matrix VT; - typedef Eigen::Matrix MT; - typedef Cartesian Kernel; + typedef Eigen::Matrix MT; + typedef Cartesian Kernel; typedef typename Kernel::Point Point; typedef boost::mt19937 RNGType; - typedef LMI LMI; - typedef Spectrahedron SPECTRAHEDRON; + typedef LMI LMI; + typedef Spectrahedron Spectrahedron; std::vector matrices = Rcpp::as > (Rcpp::as (spectrahedron).field("matrices")); LMI lmi(matrices); - SPECTRAHEDRON _spectrahedron(lmi); + Spectrahedron _spectrahedron(lmi); Point c(Rcpp::as (objectiveFunction)); std::filebuf fb; @@ -66,15 +66,7 @@ void writeSdpaFormatFile(Rcpp::Nullable spectrahedron = R_NilVa return; } -// need this to return a spectrahedron in R -// in function readSdpaFormatManager -class _Spectrahedron { -public: - /// A list with the matrices A0, ..., An - Rcpp::List matrices; - _Spectrahedron(Rcpp::List _matrices) : matrices(_matrices) {} -}; //' Read a SDPA format file //' @@ -91,14 +83,14 @@ Rcpp::List loadSdpaFormatFile(Rcpp::Nullable inputFile = R_NilValue typedef double NT; typedef Eigen::Matrix VT; - typedef Eigen::Matrix MT; - typedef Cartesian Kernel; + typedef Eigen::Matrix MT; + typedef Cartesian Kernel; typedef typename Kernel::Point Point; typedef boost::mt19937 RNGType; - typedef LMI LMI; - typedef Spectrahedron SPECTRAHEDRON; + typedef LMI LMI; + typedef Spectrahedron Spectrahedron; - SPECTRAHEDRON _spectrahedron; + Spectrahedron _spectrahedron; Point c; // open stream From bf796923e03ca6d886d8dbbc772dc8404ea4e82f Mon Sep 17 00:00:00 2001 From: Repouskos Panagiotis Date: Thu, 28 May 2020 16:51:33 +0300 Subject: [PATCH 15/38] SDP Solver Simulated annealing for spectrahedra - add libraries spectra, arpack - add random walks Hamiltonian monte carlo with reflections under Boltzmann distribution and coordinate Hit and Run - in folder matrices there are the classes solving the required eigenvalue problems --- .../spectrahedra/semidefiniteProgramming.cpp | 12 + .../Spectra/include/Spectra/GenEigsBase.h | 479 ++++++ .../Spectra/GenEigsComplexShiftSolver.h | 156 ++ .../include/Spectra/GenEigsRealShiftSolver.h | 90 + .../Spectra/include/Spectra/GenEigsSolver.h | 160 ++ .../Spectra/include/Spectra/LinAlg/Arnoldi.h | 283 +++ .../Spectra/include/Spectra/LinAlg/BKLDLT.h | 522 ++++++ .../include/Spectra/LinAlg/DoubleShiftQR.h | 378 ++++ .../Spectra/include/Spectra/LinAlg/Lanczos.h | 170 ++ .../include/Spectra/LinAlg/TridiagEigen.h | 219 +++ .../Spectra/LinAlg/UpperHessenbergEigen.h | 317 ++++ .../Spectra/LinAlg/UpperHessenbergQR.h | 670 ++++++++ .../include/Spectra/MatOp/DenseCholesky.h | 110 ++ .../Spectra/MatOp/DenseGenComplexShiftSolve.h | 104 ++ .../include/Spectra/MatOp/DenseGenMatProd.h | 82 + .../Spectra/MatOp/DenseGenRealShiftSolve.h | 90 + .../include/Spectra/MatOp/DenseSymMatProd.h | 75 + .../Spectra/MatOp/DenseSymShiftSolve.h | 94 + .../include/Spectra/MatOp/SparseCholesky.h | 111 ++ .../include/Spectra/MatOp/SparseGenMatProd.h | 76 + .../Spectra/MatOp/SparseGenRealShiftSolve.h | 95 ++ .../Spectra/MatOp/SparseRegularInverse.h | 102 ++ .../include/Spectra/MatOp/SparseSymMatProd.h | 75 + .../Spectra/MatOp/SparseSymShiftSolve.h | 97 ++ .../Spectra/MatOp/internal/ArnoldiOp.h | 155 ++ .../MatOp/internal/SymGEigsCholeskyOp.h | 77 + .../Spectra/MatOp/internal/SymGEigsRegInvOp.h | 74 + .../Spectra/include/Spectra/SymEigsBase.h | 447 +++++ .../include/Spectra/SymEigsShiftSolver.h | 205 +++ .../Spectra/include/Spectra/SymEigsSolver.h | 174 ++ .../Spectra/include/Spectra/SymGEigsSolver.h | 334 ++++ .../Spectra/include/Spectra/Util/CompInfo.h | 37 + .../Spectra/include/Spectra/Util/GEigsMode.h | 34 + .../include/Spectra/Util/SelectionRule.h | 277 +++ .../include/Spectra/Util/SimpleRandom.h | 93 + .../Spectra/include/Spectra/Util/TypeTraits.h | 73 + .../include/Spectra/contrib/LOBPCGSolver.h | 501 ++++++ .../Spectra/contrib/PartialSVDSolver.h | 203 +++ external/arpack++/include/README | 232 +++ external/arpack++/include/arbgcomp.h | 204 +++ external/arpack++/include/arbgnsym.h | 243 +++ external/arpack++/include/arbgsym.h | 233 +++ external/arpack++/include/arbnsmat.h | 431 +++++ external/arpack++/include/arbnspen.h | 470 +++++ external/arpack++/include/arbscomp.h | 165 ++ external/arpack++/include/arbsmat.h | 378 ++++ external/arpack++/include/arbsnsym.h | 163 ++ external/arpack++/include/arbspen.h | 303 ++++ external/arpack++/include/arbssym.h | 159 ++ external/arpack++/include/arcgsym.h | 242 +++ external/arpack++/include/arch.h | 95 ++ external/arpack++/include/arcomp.h | 46 + external/arpack++/include/arcsmat.h | 473 +++++ external/arpack++/include/arcspen.h | 434 +++++ external/arpack++/include/arcssym.h | 166 ++ external/arpack++/include/ardfmat.h | 453 +++++ external/arpack++/include/ardgcomp.h | 204 +++ external/arpack++/include/ardgnsym.h | 244 +++ external/arpack++/include/ardgsym.h | 233 +++ external/arpack++/include/ardnsmat.h | 622 +++++++ external/arpack++/include/ardnspen.h | 324 ++++ external/arpack++/include/ardscomp.h | 166 ++ external/arpack++/include/ardsmat.h | 357 ++++ external/arpack++/include/ardsnsym.h | 163 ++ external/arpack++/include/ardspen.h | 237 +++ external/arpack++/include/ardssym.h | 159 ++ external/arpack++/include/arerror.h | 348 ++++ external/arpack++/include/argcomp.h | 126 ++ external/arpack++/include/argeig.h | 233 +++ external/arpack++/include/argnsym.h | 362 ++++ external/arpack++/include/argsym.h | 326 ++++ external/arpack++/include/arhbmat.h | 407 +++++ external/arpack++/include/arlcomp.h | 153 ++ external/arpack++/include/arlgcomp.h | 204 +++ external/arpack++/include/arlgnsym.h | 252 +++ external/arpack++/include/arlgsym.h | 235 +++ external/arpack++/include/arlnames.h | 464 +++++ external/arpack++/include/arlnsmat.h | 753 ++++++++ external/arpack++/include/arlnspen.h | 774 +++++++++ external/arpack++/include/arlscomp.h | 188 ++ external/arpack++/include/arlsmat.h | 765 +++++++++ external/arpack++/include/arlsnsym.h | 182 ++ external/arpack++/include/arlspdef.h | 610 +++++++ external/arpack++/include/arlspen.h | 679 ++++++++ external/arpack++/include/arlssym.h | 179 ++ external/arpack++/include/arlsupm.h | 185 ++ external/arpack++/include/arlutil.h | 432 +++++ external/arpack++/include/armat.h | 56 + external/arpack++/include/arpackf.h | 150 ++ external/arpack++/include/arrgcomp.h | 110 ++ external/arpack++/include/arrgeig.h | 103 ++ external/arpack++/include/arrgnsym.h | 244 +++ external/arpack++/include/arrgsym.h | 236 +++ external/arpack++/include/arrscomp.h | 375 ++++ external/arpack++/include/arrseig.h | 1515 +++++++++++++++++ external/arpack++/include/arrsnsym.h | 861 ++++++++++ external/arpack++/include/arrssym.h | 424 +++++ external/arpack++/include/arscomp.h | 118 ++ external/arpack++/include/arseig.h | 237 +++ external/arpack++/include/arsnsym.h | 117 ++ external/arpack++/include/arssym.h | 118 ++ external/arpack++/include/arugcomp.h | 204 +++ external/arpack++/include/arugnsym.h | 245 +++ external/arpack++/include/arugsym.h | 234 +++ external/arpack++/include/arunsmat.h | 646 +++++++ external/arpack++/include/arunspen.h | 527 ++++++ external/arpack++/include/aruscomp.h | 166 ++ external/arpack++/include/arusmat.h | 743 ++++++++ external/arpack++/include/arusnsym.h | 162 ++ external/arpack++/include/aruspen.h | 543 ++++++ external/arpack++/include/arussym.h | 158 ++ external/arpack++/include/blas1c.h | 367 ++++ external/arpack++/include/blas1f.h | 221 +++ external/arpack++/include/caupp.h | 320 ++++ external/arpack++/include/ceupp.h | 224 +++ external/arpack++/include/cholmodc.h | 161 ++ external/arpack++/include/debug.h | 135 ++ external/arpack++/include/lapackc.h | 306 ++++ external/arpack++/include/lapackf.h | 207 +++ external/arpack++/include/naupp.h | 333 ++++ external/arpack++/include/neupp.h | 270 +++ external/arpack++/include/saupp.h | 321 ++++ external/arpack++/include/seupp.h | 190 +++ external/arpack++/include/superluc.h | 165 ++ external/arpack++/include/umfpackc.h | 216 +++ include/cartesian_geom/point.h | 4 + include/convex_bodies/spectrahedra/LMI.h | 101 +- .../spectrahedra/spectrahedron.h | 205 ++- include/generators/sdp_generator.h | 148 ++ include/matrices/DenseProductMatrix.h | 100 ++ include/matrices/EigenDenseMatrix.h | 71 + include/matrices/EigenvaluesProblems.h | 365 ++++ include/optimization/SDPA_FormatManager.h | 200 +++ include/optimization/SimulatedAnnealing.h | 218 +++ include/optimization/SlidingWindow.h | 61 + ...CoordinateDirectionsHitAndRun_RandomWalk.h | 91 + include/random_walks/HMC_RandomWalk.h | 251 +++ test/SDP/CMakeLists.txt | 94 + test/SDP/HMC.cpp | 93 + 139 files changed, 36416 insertions(+), 21 deletions(-) create mode 100644 examples/spectrahedra/semidefiniteProgramming.cpp create mode 100644 external/Spectra/include/Spectra/GenEigsBase.h create mode 100644 external/Spectra/include/Spectra/GenEigsComplexShiftSolver.h create mode 100644 external/Spectra/include/Spectra/GenEigsRealShiftSolver.h create mode 100644 external/Spectra/include/Spectra/GenEigsSolver.h create mode 100644 external/Spectra/include/Spectra/LinAlg/Arnoldi.h create mode 100644 external/Spectra/include/Spectra/LinAlg/BKLDLT.h create mode 100644 external/Spectra/include/Spectra/LinAlg/DoubleShiftQR.h create mode 100644 external/Spectra/include/Spectra/LinAlg/Lanczos.h create mode 100644 external/Spectra/include/Spectra/LinAlg/TridiagEigen.h create mode 100644 external/Spectra/include/Spectra/LinAlg/UpperHessenbergEigen.h create mode 100644 external/Spectra/include/Spectra/LinAlg/UpperHessenbergQR.h create mode 100644 external/Spectra/include/Spectra/MatOp/DenseCholesky.h create mode 100644 external/Spectra/include/Spectra/MatOp/DenseGenComplexShiftSolve.h create mode 100644 external/Spectra/include/Spectra/MatOp/DenseGenMatProd.h create mode 100644 external/Spectra/include/Spectra/MatOp/DenseGenRealShiftSolve.h create mode 100644 external/Spectra/include/Spectra/MatOp/DenseSymMatProd.h create mode 100644 external/Spectra/include/Spectra/MatOp/DenseSymShiftSolve.h create mode 100644 external/Spectra/include/Spectra/MatOp/SparseCholesky.h create mode 100644 external/Spectra/include/Spectra/MatOp/SparseGenMatProd.h create mode 100644 external/Spectra/include/Spectra/MatOp/SparseGenRealShiftSolve.h create mode 100644 external/Spectra/include/Spectra/MatOp/SparseRegularInverse.h create mode 100644 external/Spectra/include/Spectra/MatOp/SparseSymMatProd.h create mode 100644 external/Spectra/include/Spectra/MatOp/SparseSymShiftSolve.h create mode 100644 external/Spectra/include/Spectra/MatOp/internal/ArnoldiOp.h create mode 100644 external/Spectra/include/Spectra/MatOp/internal/SymGEigsCholeskyOp.h create mode 100644 external/Spectra/include/Spectra/MatOp/internal/SymGEigsRegInvOp.h create mode 100644 external/Spectra/include/Spectra/SymEigsBase.h create mode 100644 external/Spectra/include/Spectra/SymEigsShiftSolver.h create mode 100644 external/Spectra/include/Spectra/SymEigsSolver.h create mode 100644 external/Spectra/include/Spectra/SymGEigsSolver.h create mode 100644 external/Spectra/include/Spectra/Util/CompInfo.h create mode 100644 external/Spectra/include/Spectra/Util/GEigsMode.h create mode 100644 external/Spectra/include/Spectra/Util/SelectionRule.h create mode 100644 external/Spectra/include/Spectra/Util/SimpleRandom.h create mode 100644 external/Spectra/include/Spectra/Util/TypeTraits.h create mode 100644 external/Spectra/include/Spectra/contrib/LOBPCGSolver.h create mode 100644 external/Spectra/include/Spectra/contrib/PartialSVDSolver.h create mode 100644 external/arpack++/include/README create mode 100644 external/arpack++/include/arbgcomp.h create mode 100644 external/arpack++/include/arbgnsym.h create mode 100644 external/arpack++/include/arbgsym.h create mode 100644 external/arpack++/include/arbnsmat.h create mode 100644 external/arpack++/include/arbnspen.h create mode 100644 external/arpack++/include/arbscomp.h create mode 100644 external/arpack++/include/arbsmat.h create mode 100644 external/arpack++/include/arbsnsym.h create mode 100644 external/arpack++/include/arbspen.h create mode 100644 external/arpack++/include/arbssym.h create mode 100644 external/arpack++/include/arcgsym.h create mode 100644 external/arpack++/include/arch.h create mode 100644 external/arpack++/include/arcomp.h create mode 100644 external/arpack++/include/arcsmat.h create mode 100644 external/arpack++/include/arcspen.h create mode 100644 external/arpack++/include/arcssym.h create mode 100644 external/arpack++/include/ardfmat.h create mode 100644 external/arpack++/include/ardgcomp.h create mode 100644 external/arpack++/include/ardgnsym.h create mode 100644 external/arpack++/include/ardgsym.h create mode 100644 external/arpack++/include/ardnsmat.h create mode 100644 external/arpack++/include/ardnspen.h create mode 100644 external/arpack++/include/ardscomp.h create mode 100644 external/arpack++/include/ardsmat.h create mode 100644 external/arpack++/include/ardsnsym.h create mode 100644 external/arpack++/include/ardspen.h create mode 100644 external/arpack++/include/ardssym.h create mode 100644 external/arpack++/include/arerror.h create mode 100644 external/arpack++/include/argcomp.h create mode 100644 external/arpack++/include/argeig.h create mode 100644 external/arpack++/include/argnsym.h create mode 100644 external/arpack++/include/argsym.h create mode 100644 external/arpack++/include/arhbmat.h create mode 100644 external/arpack++/include/arlcomp.h create mode 100644 external/arpack++/include/arlgcomp.h create mode 100644 external/arpack++/include/arlgnsym.h create mode 100644 external/arpack++/include/arlgsym.h create mode 100644 external/arpack++/include/arlnames.h create mode 100644 external/arpack++/include/arlnsmat.h create mode 100644 external/arpack++/include/arlnspen.h create mode 100644 external/arpack++/include/arlscomp.h create mode 100644 external/arpack++/include/arlsmat.h create mode 100644 external/arpack++/include/arlsnsym.h create mode 100644 external/arpack++/include/arlspdef.h create mode 100644 external/arpack++/include/arlspen.h create mode 100644 external/arpack++/include/arlssym.h create mode 100644 external/arpack++/include/arlsupm.h create mode 100644 external/arpack++/include/arlutil.h create mode 100644 external/arpack++/include/armat.h create mode 100644 external/arpack++/include/arpackf.h create mode 100644 external/arpack++/include/arrgcomp.h create mode 100644 external/arpack++/include/arrgeig.h create mode 100644 external/arpack++/include/arrgnsym.h create mode 100644 external/arpack++/include/arrgsym.h create mode 100644 external/arpack++/include/arrscomp.h create mode 100644 external/arpack++/include/arrseig.h create mode 100644 external/arpack++/include/arrsnsym.h create mode 100644 external/arpack++/include/arrssym.h create mode 100644 external/arpack++/include/arscomp.h create mode 100644 external/arpack++/include/arseig.h create mode 100644 external/arpack++/include/arsnsym.h create mode 100644 external/arpack++/include/arssym.h create mode 100644 external/arpack++/include/arugcomp.h create mode 100644 external/arpack++/include/arugnsym.h create mode 100644 external/arpack++/include/arugsym.h create mode 100644 external/arpack++/include/arunsmat.h create mode 100644 external/arpack++/include/arunspen.h create mode 100644 external/arpack++/include/aruscomp.h create mode 100644 external/arpack++/include/arusmat.h create mode 100644 external/arpack++/include/arusnsym.h create mode 100644 external/arpack++/include/aruspen.h create mode 100644 external/arpack++/include/arussym.h create mode 100644 external/arpack++/include/blas1c.h create mode 100644 external/arpack++/include/blas1f.h create mode 100644 external/arpack++/include/caupp.h create mode 100644 external/arpack++/include/ceupp.h create mode 100644 external/arpack++/include/cholmodc.h create mode 100644 external/arpack++/include/debug.h create mode 100644 external/arpack++/include/lapackc.h create mode 100644 external/arpack++/include/lapackf.h create mode 100644 external/arpack++/include/naupp.h create mode 100644 external/arpack++/include/neupp.h create mode 100644 external/arpack++/include/saupp.h create mode 100644 external/arpack++/include/seupp.h create mode 100644 external/arpack++/include/superluc.h create mode 100644 external/arpack++/include/umfpackc.h create mode 100644 include/generators/sdp_generator.h create mode 100644 include/matrices/DenseProductMatrix.h create mode 100644 include/matrices/EigenDenseMatrix.h create mode 100644 include/matrices/EigenvaluesProblems.h create mode 100644 include/optimization/SDPA_FormatManager.h create mode 100644 include/optimization/SimulatedAnnealing.h create mode 100644 include/optimization/SlidingWindow.h create mode 100644 include/random_walks/CoordinateDirectionsHitAndRun_RandomWalk.h create mode 100644 include/random_walks/HMC_RandomWalk.h create mode 100644 test/SDP/CMakeLists.txt create mode 100644 test/SDP/HMC.cpp diff --git a/examples/spectrahedra/semidefiniteProgramming.cpp b/examples/spectrahedra/semidefiniteProgramming.cpp new file mode 100644 index 000000000..327adf28c --- /dev/null +++ b/examples/spectrahedra/semidefiniteProgramming.cpp @@ -0,0 +1,12 @@ +// 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). + 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/cartesian_geom/point.h b/include/cartesian_geom/point.h index 83050a646..d3f21ab3a 100644 --- a/include/cartesian_geom/point.h +++ b/include/cartesian_geom/point.h @@ -163,6 +163,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 80524b51c..20dd727c4 100644 --- a/include/convex_bodies/spectrahedra/LMI.h +++ b/include/convex_bodies/spectrahedra/LMI.h @@ -1,15 +1,12 @@ -// 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 +// +// Created by panagiotis on 2/22/20. +// #ifndef VOLESTI_LMI_H #define VOLESTI_LMI_H +#include "matrices/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 +14,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) {} }; @@ -94,7 +141,7 @@ class LMI, Eigen::Matrix const & getMatrices() const { + std::vector getMatrices() const { return matrices; } @@ -106,7 +153,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 +204,7 @@ 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 cd9e512c4..9abebe079 100644 --- a/include/convex_bodies/spectrahedra/spectrahedron.h +++ b/include/convex_bodies/spectrahedra/spectrahedron.h @@ -1,11 +1,6 @@ -// 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 +// +// Created by panagiotis on 2/22/20. +// #ifndef VOLESTI_SPECTRAHEDRON_H #define VOLESTI_SPECTRAHEDRON_H @@ -23,6 +18,33 @@ class Spectrahedron { /// 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 +59,179 @@ 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 { + unsigned int dimension() { return d; } /// \return The LMI describing this spectrahedron - LMI getLMI() const { + LMI getLMI() { 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/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/matrices/DenseProductMatrix.h b/include/matrices/DenseProductMatrix.h new file mode 100644 index 000000000..a53401eff --- /dev/null +++ b/include/matrices/DenseProductMatrix.h @@ -0,0 +1,100 @@ +// +// Created by panagiotis on 2/24/20. +// + +#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/matrices/EigenDenseMatrix.h b/include/matrices/EigenDenseMatrix.h new file mode 100644 index 000000000..cf593b004 --- /dev/null +++ b/include/matrices/EigenDenseMatrix.h @@ -0,0 +1,71 @@ +// +// Created by panagiotis on 2/22/20. +// + +#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/matrices/EigenvaluesProblems.h b/include/matrices/EigenvaluesProblems.h new file mode 100644 index 000000000..4095fd7f8 --- /dev/null +++ b/include/matrices/EigenvaluesProblems.h @@ -0,0 +1,365 @@ +// +// Created by panagiotis on 2/22/20. +// + +#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, 0.000);//, 100*3); + + // compute + if (dprob.FindEigenvectors() == 0) { + std::cout << "Failed\n"; + // if failed with default (and fast) parameters, try with stable (and slow) + dprob.ChangeNcv(A.cols()/10); + if (dprob.FindEigenvectors() == 0) { + std::cout << "\tFailed Again\n"; + return NT(0); + } + } + + + // allocate memory for the eigenvector here + eigenvector.setZero(A.rows()); + + if (!dprob.EigenvaluesFound()) { + // if failed to find eigenvalues + return NT(0); + } + + // retrieve eigenvalue of the original system + lambdaMinPositive = 1/dprob.EigenvalueReal(0); + + eigenvector.setZero(A.rows()); + if (dprob.EigenvectorsFound()) { + //retrieve corresponding eigenvector + for (int i=0 ;i +#include + + +typedef std::string::iterator string_it; +typedef std::list listVector; + + + /** + * Return the first non white space/tab character and advance the iterator one position + * @param it + * @return + */ + char consumeSymbol(string_it &at, string_it &end) { + while (at != end) { + if (*at != ' ' && *at != '\t') { + char c = *at; + at++; + return c; + } + + at++; + } + + return '\0'; + } + + + bool isCommentLine(std::string &line) { + string_it at = line.begin(); + string_it end = line.end(); + + char c = consumeSymbol(at, end); + + return c == '"' || c == '*'; + } + + + int fetchNumber(std::string &string) { + std::stringstream stream(string); + int num; + stream >> num; + return num; + } + + + /** + * Read a vector of the form {val1, val2, ..., valn} + * @param string + * @return + */ + listVector readVector(std::string &string) { + std::stringstream stream(string); + listVector vector; + double value; + + while (stream >> value) { + vector.push_back(value); + } + + return vector; + } + + + template + void loadSDPAFormatFile(std::ifstream &is, LMI &lmi, VT &objectiveFunction) { + std::string line; + std::string::size_type sz; + + std::getline(is, line, '\n'); + + //skip comments + while (isCommentLine(line)) { + std::getline(is, line, '\n'); + } + + //read variables number + int variablesNum = fetchNumber(line); + + if (std::getline(is, line, '\n').eof()) + throw 1; + + //read number of blocks + int blocksNum = fetchNumber(line); + + if (std::getline(is, line, '\n').eof()) + throw 1; + + //read block structure vector + listVector blockStructure = readVector(line); //TODO different if we have one block + + if (blockStructure.size() != blocksNum) + throw 1; + + if (std::getline(is, line, '\n').eof()) + throw 1; + + //read constant vector + listVector constantVector = readVector(line); + + while (constantVector.size() < variablesNum) { + if (std::getline(is, line, '\n').eof()) + throw 1; + listVector t = readVector(line); + constantVector.insert(std::end(constantVector), std::begin(t), std::end(t)); + } + +// for (auto x : constantVector) +// std::cout << x << " "; +// std::cout << "\n"; +// throw 1; + + + std::vector matrices(variablesNum + 1); + int matrixDim = 0; + for (auto x : blockStructure) + matrixDim += std::abs((int) x); + + //read constraint matrices + for (int atMatrix = 0; atMatrix < matrices.size(); atMatrix++) { + MT matrix; + matrix.setZero(matrixDim, matrixDim); + + int offset = 0; + + for (auto blockSize : blockStructure) { + + if (blockSize > 0) { //read a block blockSize x blockSize + int at = 0; + int i = 0, j = 0; + + while (at < blockSize * blockSize) { + if (std::getline(is, line, '\n').eof()) + throw 1; + + listVector vec = readVector(line); + + for (double value : vec) { + matrix(offset + i, offset + j) = value; +// std::cout <0, I want it <0 + if (atMatrix == 0) //F0 has - before it in SDPA format, the rest have + + matrices[atMatrix] = matrix; + else + matrices[atMatrix] = -1 * matrix; + } + + // return lmi and objective function + objectiveFunction.setZero(variablesNum); + int at = 0; + + for (auto value : constantVector) + objectiveFunction(at++) = value; + + lmi = LMI(matrices); + } + + + + +#endif //VOLESTI_SDPA_FORMAT_MANAGER_H diff --git a/include/optimization/SimulatedAnnealing.h b/include/optimization/SimulatedAnnealing.h new file mode 100644 index 000000000..b5a69a2f7 --- /dev/null +++ b/include/optimization/SimulatedAnnealing.h @@ -0,0 +1,218 @@ +// +// Created by panagiotis on 2/28/20. +// + +#ifndef VOLESTI_SIMULATEDANNEALING_H +#define VOLESTI_SIMULATEDANNEALING_H + +#include "SlidingWindow.h" + +/// Simulated Annealing algorithm for the semidefinite program +/// Minimize \[ c^T x \], s.t. LMI(x) <= 0 +/// \tparam Point Class point +/// \tparam MT Matrix type +/// \tparam VT Vector type +template +class SimulatedAnnealing { +public: + + /// The numeric type + typedef typename Point::FT NT; + /// The type of the spectrahedron + typedef Spectrahedron SPECTRAHEDRON; + /// To use to generate random numbers + typedef boost::mt19937 RNGType; + /// The Hamiltonian Monte Carlo random walk with reflections + typedef HMC_RandomWalk HMC; + + /// Holds parameters of the algorithm + struct Settings { + /// 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; + + Settings(NT const error, int const walkLength, int const maxNumSteps = -1, NT const k = 0.5) : error(error), + walkLength(walkLength), maxNumSteps(maxNumSteps), k(k) {} + }; + + + /// The feasible region of the semidefinite program + SPECTRAHEDRON *spectrahedron; + /// The normalized objective function of the semidefinite program + Point objectiveFunction; + /// The norm of the initial objective function + NT objectiveFunctionNorm; + /// The parameters of the algorithm + Settings settings; + /// A feasible point to start the algorithm + Point* interiorPoint; + /// True if we computed the interior point + bool computedInteriorPoint; + /// The diameter of the spectrahedron + NT diameter; + + SimulatedAnnealing() {} + + /// Construct and initialize an instance of this class + /// \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 + SimulatedAnnealing(SPECTRAHEDRON* spectrahedron, Point const & objectiveFunction, Settings const & settings, + Point* interiorPoint = nullptr) : spectrahedron(spectrahedron), settings(settings), + interiorPoint(interiorPoint) { + + // check if we must compute an interior point + if (interiorPoint != nullptr) + computedInteriorPoint = false; + else { + this->interiorPoint = new Point(spectrahedron->dimension()); + computedInteriorPoint = true; + } + + // the algorithm requires the objective function to be normalized + VT _objectiveFunction = objectiveFunction.getCoefficients(); + objectiveFunctionNorm = _objectiveFunction.norm(); + _objectiveFunction.normalize(); + this->objectiveFunction = Point(_objectiveFunction); + + // Estimate the diameter of the spectrahedron + // needed for the random walk + diameter = spectrahedron->estimateDiameter(20 + std::sqrt(spectrahedron->dimension()), *(this->interiorPoint)); + } + + + /// Initialize the hamiltonian monte carlo random walk + /// \param[out] hmcRandomWalk + /// \param[in] temperature + void initializeHMC(HMC& hmcRandomWalk, NT const temperature) { + typedef boost::mt19937 RNGType; + unsigned seed = std::chrono::system_clock::now().time_since_epoch().count(); + RNGType rng(seed); + + typename HMC::Settings settings = typename HMC::Settings(this->settings.walkLength, rng, objectiveFunction, temperature, diameter); + hmcRandomWalk = HMC(settings); + } + + /// Solves the semidefinite program + /// \param[out] x The vector minimizing the objective function + /// \param[in] verbose True to print messages. Default is false + /// \return The best approximation to the optimal solution + NT solve(Point& x, bool verbose = false) { + // initialize + x = *interiorPoint; + NT currentMin = objectiveFunction.dot(x); + int stepsCount = 0; + NT temperature = diameter; + NT tempDecreaseFactor = 1.0 - static_cast(1.0 / std::pow(spectrahedron->dimension(), settings.k)); + + // initialize random walk; + HMC hmc; + initializeHMC(hmc, diameter); + + // if settings.maxNumSteps is negative there is no + // bound to the number of steps + while (stepsCount < settings.maxNumSteps || settings.maxNumSteps < 0) { + + // sample one point with current temperature + std::list randPoints; + hmc.sample(*spectrahedron, x, 1, randPoints); + + // update values; + x = randPoints.back(); + randPoints.clear(); + currentMin = objectiveFunction.dot(x); + ++stepsCount; + + if (verbose) + std::cout << "Step: " << stepsCount << ", Temperature: " << temperature << ", Min: " << currentMin << "\n"; + + // decrease the temperature + temperature *= tempDecreaseFactor; + hmc.setTemperature(temperature); + } + + // return the minimum w.r.t. the original objective function + return currentMin*objectiveFunctionNorm; + } + + /// Solves the semidefinite program. Stops when reaches a relative error < settings.error + /// or hits the maximum number of allowed steps + /// \param[out] x The vector minimizing the objective function + /// \param[in] verbose True to print messages + /// \param[in] The exact minimum of the problem + /// \return The best approximation to the optimal solution + NT solve(Point& x, bool verbose, const NT exact) { + // initialize + x = *interiorPoint; + NT currentMin = objectiveFunction.dot(x); + int stepsCount = 0; + NT temperature = diameter; + NT tempDecreaseFactor = 1.0 - static_cast(1.0 / std::pow(spectrahedron->dimension(), settings.k)); + + // initialize random walk; + HMC hmc; + initializeHMC(hmc, diameter); + typename HMC::PrecomputedValues hmcPrecomputesValues; + + // if settings.maxNumSteps is negative there is no + // bound to the number of steps + while (stepsCount < settings.maxNumSteps || settings.maxNumSteps < 0) { + + // sample one point with current temperature + std::list randPoints; + + while (1) { + hmc.sample(*spectrahedron, x, settings.walkLength, randPoints, hmcPrecomputesValues); + + // if the sampled point is not inside the spectrahedron, + // get a new one + if (spectrahedron->isExterior(hmcPrecomputesValues.C)) { + if (verbose) std::cout << "Sampled point outside the spectrahedron.\n"; + randPoints.clear(); + hmcPrecomputesValues.resetFlags(); + } + else { + // update values; + x = randPoints.back(); + randPoints.clear(); + break; + } + } + + currentMin = objectiveFunction.dot(x); + ++stepsCount; + + // compute relative error + NT relError = relativeError(currentMin, exact); + + 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; + hmc.setTemperature(temperature); + } + + // return the minimum w.r.t. the original objective function + return currentMin*objectiveFunctionNorm; + } + + ~SimulatedAnnealing() { + // if we computed the interior point + if (computedInteriorPoint) delete interiorPoint; + } +}; +#endif //VOLESTI_SIMULATEDANNEALING_H diff --git a/include/optimization/SlidingWindow.h b/include/optimization/SlidingWindow.h new file mode 100644 index 000000000..8ec6fd35d --- /dev/null +++ b/include/optimization/SlidingWindow.h @@ -0,0 +1,61 @@ +// +// Created by panagiotis on 2/28/20. +// + +#ifndef VOLESTI_SLIDINGWINDOW_H +#define VOLESTI_SLIDINGWINDOW_H + + +/// 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_SLIDINGWINDOW_H diff --git a/include/random_walks/CoordinateDirectionsHitAndRun_RandomWalk.h b/include/random_walks/CoordinateDirectionsHitAndRun_RandomWalk.h new file mode 100644 index 000000000..dccf6bf8b --- /dev/null +++ b/include/random_walks/CoordinateDirectionsHitAndRun_RandomWalk.h @@ -0,0 +1,91 @@ +// +// Created by panagiotis on 2/28/20. +// + +#ifndef VOLESTI_COORDINATEDIRECTIONSHITANDRUN_RANDOMWALK_H +#define VOLESTI_COORDINATEDIRECTIONSHITANDRUN_RANDOMWALK_H + +/// The coordinate directions hit and run random walk, to sample a spectrahedron from the uniform distribution. +/// \tparam Point Point type to communicate with the rest library +/// \tparam MT Matrix type for internal computations +/// \tparam VT Vector type for internal computations +/// \tparam RNGType +template +class CoordinateDirectionsHitAndRun_RandomWalk { +public: + + /// The numeric type + typedef typename Point::FT NT; + /// The type of the spectrahedron + typedef Spectrahedron SPECTRAHEDRON; + /// Type for internal structure of class Spectrahedron + typedef typename SPECTRAHEDRON::PrecomputedValues PrecomputedValues; + + /// The number of points to "burn", before keeping the following as a sample + int walkLength; + /// For generating random numbers + RNGType rng; + + /// Constructor + /// \param[in] walkLength The number of points to "burn", before keeping the following as a sample + /// \param[in] rng For generating random numbers + CoordinateDirectionsHitAndRun_RandomWalk(int const walkLength, RNGType const & rng ) : walkLength(walkLength), rng(rng) {} + + /// Samples uniformly random points in the spectrahedron + /// \param[in] spectrahedron The spectrahedron to be sampled + /// \param[in] interiorPoint A point in the interior of the spectrahedron + /// \param[in] numPoints The number of points to sample + /// \param[out] randPoints The list which will hold the samples + void sample(SPECTRAHEDRON &spectrahedron, Point const & interiorPoint, const int numPoints, std::list & randPoints) { + + // 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 <= numPoints; ++i) { + // burn #walk_length points to get one sample + for (unsigned int j = 0; j < walkLength; ++j) { + getNextPoint(spectrahedron, p, precomputedValues); + } + + // add the sample in the return list + randPoints.push_back(Point(p)); + } + + // the data in preComputedValues may be out of date in the next call + precomputedValues.resetFlags(); + } + + + void getNextPoint(SPECTRAHEDRON & spectrahedron, VT &p, PrecomputedValues & precomputedValues) { + int n = spectrahedron.dimension(); + + // initialize random numbers generators + boost::random::uniform_real_distribution<> urdist(0, 1); + boost::random::uniform_int_distribution<> uidist(1, n); + + // uniformly select a line parallel to an axis, + // i.e. an indicator i s.t. x_i = 1 + int coordinate = uidist(rng); + + // get the distances we can travel from p + // on the line p + t* e_coordinate + // before reaching the boundary + std::pair distances = spectrahedron.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 * *(spectrahedron.getLMI().getMatrix(coordinate)); + } +}; +#endif //VOLESTI_COORDINATEDIRECTIONSHITANDRUN_RANDOMWALK_H diff --git a/include/random_walks/HMC_RandomWalk.h b/include/random_walks/HMC_RandomWalk.h new file mode 100644 index 000000000..12abfdc77 --- /dev/null +++ b/include/random_walks/HMC_RandomWalk.h @@ -0,0 +1,251 @@ +// +// Created by panagiotis on 2/23/20. +// + +#ifndef VOLESTI_HMC_RANDOMWALK_H +#define VOLESTI_HMC_RANDOMWALK_H + +#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). +/// \tparam Point Point type to communicate with the rest library +/// \tparam MT Matrix type for internal computations +/// \tparam VT Vector type for internal computations +/// \tparam RNGType +template +class HMC_RandomWalk { +public: + /// The numeric type + typedef typename Point::FT NT; + /// The type of the spectrahedron + typedef Spectrahedron SPECTRAHEDRON; + /// Type for internal structure of class Spectrahedron + typedef typename SPECTRAHEDRON::PrecomputedValues PrecomputedValues; + + /// 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 + RNGType rng; + /// 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 + /// \return An instance of this struct + Settings(const int walkLength, const RNGType& rng, const Point& c, const NT temperature, const NT diameter, + unsigned int reflectionsBound = 10, NT dl = 0.995) : walk_length(walkLength), rng(rng), c(c.getCoefficients()), temperature(temperature), + diameter(diameter), reflectionsBound(reflectionsBound), dl(dl) {} + + Settings() {} + }; + + /// The parameters of the random walk + Settings settings; + + + HMC_RandomWalk() {} + + /// Constructor + /// \param[in] settings The settings of the random walk + HMC_RandomWalk(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 + void sample(SPECTRAHEDRON& spectrahedron, const Point& 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 + void sample(SPECTRAHEDRON& spectrahedron, const Point& 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; + } + + + // Pick a random direction as a normilized vector + Point get_direction(const unsigned int dim) { + + boost::normal_distribution<> rdist(0,1); + NT normal = NT(0); + unsigned seed = std::chrono::system_clock::now().time_since_epoch().count(); + RNGType rng(seed); + + Point p(dim); + NT* data = p.pointerToData(); + + //RNGType rng2 = var.rng; + for (unsigned int i=0; i 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 = urdist(rng) * 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 = get_direction(n).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_HMC_RANDOMWALK_H diff --git a/test/SDP/CMakeLists.txt b/test/SDP/CMakeLists.txt new file mode 100644 index 000000000..10346781e --- /dev/null +++ b/test/SDP/CMakeLists.txt @@ -0,0 +1,94 @@ +# 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/convex_bodies/optimization) +include_directories (BEFORE ../../include/convex_bodies/matrices) +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 + 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}" ) + + add_executable (HMC HMC.cpp) + + + TARGET_LINK_LIBRARIES(HMC ${LAPACK_LIBRARIES}) + TARGET_LINK_LIBRARIES(HMC ${ARPACK_LIB}) + + 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/HMC.cpp b/test/SDP/HMC.cpp new file mode 100644 index 000000000..a01cdc4d3 --- /dev/null +++ b/test/SDP/HMC.cpp @@ -0,0 +1,93 @@ +// +// Created by panagiotis on 2/24/20. +// + +#include "Eigen/Eigen" +#define VOLESTI_DEBUG +#include +#include "random.hpp" +#include "random/uniform_int.hpp" +#include "random/normal_distribution.hpp" +#include "random/uniform_real_distribution.hpp" +//#include "volume.h" +//#include "rotating.h" +#include "misc.h" +#include "linear_extensions.h" +//#include "cooling_balls.h" +//#include "cooling_hpoly.h" +//#include "sample_only.h" +#include +#include "cartesian_geom/cartesian_kernel.h" +#include "matrices/EigenvaluesProblems.h" +#include "spectrahedron.h" +#include "LMI.h" +#include "matrices/EigenDenseMatrix.h" +#include "matrices/DenseProductMatrix.h" +#include "random_walks/HMC_RandomWalk.h" +#include "optimization/SDPA_FormatManager.h" +#include "random_walks/CoordinateDirectionsHitAndRun_RandomWalk.h" +#include "optimization/SimulatedAnnealing.h" + + +int main(int argc, char* argv[]) { + + + typedef double NT; + typedef Eigen::Matrix VT; + typedef Eigen::Matrix MT; + typedef Cartesian Kernel; + typedef typename Kernel::Point Point; + typedef boost::mt19937 RNGType; + typedef Spectrahedron SPECTRAHEDRON; + typedef HMC_RandomWalk HMC_RandomWalk; + typedef SimulatedAnnealing SA; + + std::ifstream inp; + inp.open(argv[1],std::ifstream::in); + LMI lmi; + VT c; + loadSDPAFormatFile(inp, lmi, c); + + unsigned seed = std::chrono::system_clock::now().time_since_epoch().count(); + + SPECTRAHEDRON spectrahedron(lmi); + lmi.print(); +#ifdef SAMPLING + unsigned int n = spectrahedron.dimension(); + + RNGType rng(seed); + + int walkL=1, NN=30; + NT T=0.1, diam=1; + +// SP.ComputeInnerBall(diam, radius); + + std::list randPoints; + + Point _c(c); + HMC_RandomWalk::Settings settings(walkL, rng, _c, T, diam); + HMC_RandomWalk hmc(settings); + Point p(n); + hmc.sample(spectrahedron, p, NN, randPoints); + + + MT RetMat(n, NN); + unsigned int jj = 0; + + for (typename std::list::iterator rpit = randPoints.begin(); rpit!=randPoints.end(); rpit++, jj++) + RetMat.col(jj) = (*rpit).getCoefficients(); + +// std::cout << RetMat; + std::cout << "\n\n\n" << RetMat.transpose() * c << "\n"; + +#endif + + SA::Settings settings(0.001, 1,25,0.25); + SA simulatedAnnealing(&spectrahedron, Point(c), settings); + + Point x; + NT min = simulatedAnnealing.solve(x,true,-0.97226); + + std::cout << min << "\n";// << x.getCoefficients().transpose() << "\n"; + return 0; +} \ No newline at end of file From d7915e0ab370690d997c50387727aa6f04bfdbcd Mon Sep 17 00:00:00 2001 From: Repouskos Panagiotis Date: Thu, 28 May 2020 18:58:40 +0300 Subject: [PATCH 16/38] fix test/SDP/CMakeLists.txt to include dependencies --- test/SDP/CMakeLists.txt | 196 +++++++++++++++++++++++++++++++++++++--- 1 file changed, 183 insertions(+), 13 deletions(-) diff --git a/test/SDP/CMakeLists.txt b/test/SDP/CMakeLists.txt index 10346781e..d9e201bd9 100644 --- a/test/SDP/CMakeLists.txt +++ b/test/SDP/CMakeLists.txt @@ -72,23 +72,193 @@ add_definitions(${CXX_COVERAGE_COMPILE_FLAGS} "-DBOOST_NO_AUTO_PTR") find_library(OPENBLAS_LIB openblas PATHS external NO_DEFAULT_PATH) IF (OPENBLAS_LIB) set(LAPACK_LIBRARIES ${OPENBLAS_LIB}) #local openblas has lapack build in - 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}" ) - - add_executable (HMC HMC.cpp) +ELSE() + find_library(OPENBLAS_LIB openblas PATH_SUFFIXES openblas-base) + IF (OPENBLAS_LIB) + find_library(LAPACK_LIBRARIES lapack) #only add liblapack + IF (NOT LAPACK_LIBRARIES) + message( STATUS "LAPACK_LIBRARIES not found" ) + SET(ABORT_CONFIG TRUE) + ENDIF() + set(LAPACK_LIBRARIES ${LAPACK_LIBRARIES} ${OPENBLAS_LIB}) + ELSE() + message( STATUS "OPENBLAS_LIB not found, trying LAPACK/BLAS..." ) + find_package(LAPACK REQUIRED) # this will also find and add libblas + ENDIF() +ENDIF() +IF (OPENBLAS_LIB) + find_package( Threads REQUIRED ) + set(LAPACK_LIBRARIES ${LAPACK_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT}) +ENDIF() +message( STATUS "LAPACK_LIBRARIES: ${LAPACK_LIBRARIES}" ) - TARGET_LINK_LIBRARIES(HMC ${LAPACK_LIBRARIES}) - TARGET_LINK_LIBRARIES(HMC ${ARPACK_LIB}) +# Find libgfortran (static preferred) +IF(NOT WIN32) + # 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() - message(FATAL_ERROR "This program requires the arpack library, and will not be compiled.") + # 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 (NOT GFORTRAN_LIB) + MESSAGE(STATUS "gfortran is required but it could not be found") + SET(ABORT_CONFIG TRUE) + ENDIF (NOT GFORTRAN_LIB) -ELSE() - message(FATAL_ERROR "This program requires the openblas library, and will not be compiled.") + # we may need libquadmath.a , so add it if it is found + find_library(QUADMATH_LIB quadmath PATHS ${GFORTRAN_PATH}) + IF (QUADMATH_LIB) + list (APPEND GFORTRAN_LIB ${QUADMATH_LIB}) + ENDIF (QUADMATH_LIB) + + IF (APPLE) + # also we need -lgcc_ext.10.5 on (most) MAC + find_library(GCC_EXT_LIB gcc_ext.10.5 PATHS ${GFORTRAN_PATH}) + IF (GCC_EXT_LIB) + list (APPEND GFORTRAN_LIB ${GCC_EXT_LIB}) + ELSE () + MESSAGE(STATUS "gcc_ext is required on MAC but could not be found") + SET(ABORT_CONFIG TRUE) + ENDIF () + ENDIF(APPLE) + +ENDIF(NOT WIN32) + + +# ARPACK +find_library (ARPACK_LIB NAMES arpack PATHS external external/ARPACK) + + +IF (NOT ARPACK_LIB) + MESSAGE(SEND_ERROR "libarpack is required but could not be found") + SET(ABORT_CONFIG TRUE) ENDIF() +message( STATUS "ARPACK_LIB found: ${ARPACK_LIB}" ) + +# SUPERLU +if (SUPERLU) + find_path(SUPERLU_INC supermatrix.h "external/SuperLU/SRC" "/usr/local/include/superlu" ) + IF (NOT SUPERLU_INC) + MESSAGE(STATUS "SuperLU (supermatrix.h) is required but could not be found") + SET(ABORT_CONFIG TRUE) + ENDIF() + make_global_path(SUPERLU_INC "SUPERLU Include Path") + + find_library(SUPERLU_LIB superlu.a libsuperlu.a + PATHS ${SUPERLU_INC} ${SUPERLU_INC}/../ external /usr/local/lib ) + IF (NOT SUPERLU_LIB) + MESSAGE(STATUS "SuperLU Library is required but could not be found") + SET(ABORT_CONFIG TRUE) + ENDIF() + make_global_path(SUPERLU_LIB "SUPERLU Library") + include_directories( ${SUPERLU_INC} ) + message( STATUS "SUPERLU_LIB found: ${SUPERLU_LIB}" ) +endif() + +# Suitesparse +if (UMFPACK OR CHOLMOD) + # Suitesparse CHOLMOD + find_path(SUITESPARSE_DIR SuiteSparse_config/SuiteSparse_config.h "external/SuiteSparse") + IF (NOT SUITESPARSE_DIR) + # nothing in external, search globally for libraries and headers + find_library(CHOLMOD_LIB libcholmod.a) + find_library(COLAMD_LIB libcolamd.a) + find_library(CCOLAMD_LIB libccolamd.a) + find_library(METIS_LIB libmetis.a) + IF (NOT METIS_LIB) + find_library(METIS_LIB libmetis.dylib) + ENDIF() + IF (NOT METIS_LIB) + find_library(METIS_LIB libmetis.so) + ENDIF() + find_library(CAMD_LIB libcamd.a) + find_library(AMD_LIB libamd.a) + + # Suitesparse UMFPACK + find_library(UMFPACK_LIB libumfpack.a) + find_library(SUITESPARSE_LIB libsuitesparseconfig.a) + + FIND_PATH( CHOLMOD_INCLUDE_DIR cholmod.h + PATHS /usr/local/include + /usr/include + /usr/include/suitesparse/ + ${CMAKE_SOURCE_DIR}/MacOS/Libs/cholmod + PATH_SUFFIXES cholmod/ CHOLMOD/ ) + IF (NOT CHOLMOD_INCLUDE_DIR) + MESSAGE(STATUS "SuiteSparse chomod.h is required but could not be found") + SET(ABORT_CONFIG TRUE) + ENDIF() + + include_directories( + ${CHOLMOD_INCLUDE_DIR} + ) + + + ELSE (NOT SUITESPARSE_DIR) + # found suite sparse locally in external dir + make_global_path(SUITESPARSE_DIR "SuiteSparse Directory") + message( STATUS "SUITESPARSE_DIR found: ${SUITESPARSE_DIR}" ) + + find_library(CHOLMOD_LIB libcholmod.a ${SUITESPARSE_DIR}/CHOLMOD/Lib ) + find_library(COLAMD_LIB libcolamd.a ${SUITESPARSE_DIR}/COLAMD/Lib ) + find_library(CCOLAMD_LIB libccolamd.a ${SUITESPARSE_DIR}/CCOLAMD/Lib ) + find_library(METIS_LIB libmetis.a ${SUITESPARSE_DIR}/metis-4.0 ) + IF (NOT METIS_LIB) + find_library(METIS_LIB libmetis.dylib) + ENDIF() + IF (NOT METIS_LIB) + find_library(METIS_LIB libmetis.so) + ENDIF() + find_library(CAMD_LIB libcamd.a ${SUITESPARSE_DIR}/CAMD/Lib ) + find_library(AMD_LIB libamd.a ${SUITESPARSE_DIR}/AMD/Lib ) + + # Suitesparse UMFPACK + find_library(UMFPACK_LIB libumfpack.a ${SUITESPARSE_DIR}/UMFPACK/Lib ) + find_library(SUITESPARSE_LIB libsuitesparseconfig.a ${SUITESPARSE_DIR}/SuiteSparse_config ) + + include_directories( + ${SUITESPARSE_DIR}/CHOLMOD/Include + ${SUITESPARSE_DIR}/SuiteSparse_config + ) + + + ENDIF() + + set(SSPARSE_LIBS + ${UMFPACK_LIB} + ${CHOLMOD_LIB} + ${COLAMD_LIB} + ${CCOLAMD_LIB} + ${METIS_LIB} + ${CAMD_LIB} + ${AMD_LIB} + ${SUITESPARSE_LIB} + ) + + # some linux systems need specifically librt (for SuiteSparse): + if (NOT APPLE) + set (SSPARSE_LIBS ${SSPARSE_LIBS} -lrt) + endif() + + +endif() +add_executable(HMC HMC.cpp) +TARGET_LINK_LIBRARIES(HMC ${LAPACK_LIBRARIES}) +TARGET_LINK_LIBRARIES(HMC ${ARPACK_LIB}) From 5d9def995c2c6248bb4dbcbfa12fa8a27661cebd Mon Sep 17 00:00:00 2001 From: Repouskos Panagiotis Date: Thu, 28 May 2020 20:19:38 +0300 Subject: [PATCH 17/38] fix test/SDP/CMakeLists.txt fix libgfortran --- test/SDP/CMakeLists.txt | 197 ++++------------------------------------ 1 file changed, 20 insertions(+), 177 deletions(-) diff --git a/test/SDP/CMakeLists.txt b/test/SDP/CMakeLists.txt index d9e201bd9..db703d0e1 100644 --- a/test/SDP/CMakeLists.txt +++ b/test/SDP/CMakeLists.txt @@ -72,193 +72,36 @@ add_definitions(${CXX_COVERAGE_COMPILE_FLAGS} "-DBOOST_NO_AUTO_PTR") find_library(OPENBLAS_LIB openblas PATHS external NO_DEFAULT_PATH) IF (OPENBLAS_LIB) set(LAPACK_LIBRARIES ${OPENBLAS_LIB}) #local openblas has lapack build in -ELSE() - find_library(OPENBLAS_LIB openblas PATH_SUFFIXES openblas-base) - IF (OPENBLAS_LIB) - find_library(LAPACK_LIBRARIES lapack) #only add liblapack - IF (NOT LAPACK_LIBRARIES) - message( STATUS "LAPACK_LIBRARIES not found" ) - SET(ABORT_CONFIG TRUE) - ENDIF() - set(LAPACK_LIBRARIES ${LAPACK_LIBRARIES} ${OPENBLAS_LIB}) - ELSE() - message( STATUS "OPENBLAS_LIB not found, trying LAPACK/BLAS..." ) - find_package(LAPACK REQUIRED) # this will also find and add libblas - ENDIF() -ENDIF() -IF (OPENBLAS_LIB) + find_package( Threads REQUIRED ) set(LAPACK_LIBRARIES ${LAPACK_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT}) -ENDIF() -message( STATUS "LAPACK_LIBRARIES: ${LAPACK_LIBRARIES}" ) - - -# Find libgfortran (static preferred) -IF(NOT WIN32) - # 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 (NOT GFORTRAN_LIB) - MESSAGE(STATUS "gfortran is required but it could not be found") - SET(ABORT_CONFIG TRUE) - ENDIF (NOT GFORTRAN_LIB) - - # we may need libquadmath.a , so add it if it is found - find_library(QUADMATH_LIB quadmath PATHS ${GFORTRAN_PATH}) - IF (QUADMATH_LIB) - list (APPEND GFORTRAN_LIB ${QUADMATH_LIB}) - ENDIF (QUADMATH_LIB) - - IF (APPLE) - # also we need -lgcc_ext.10.5 on (most) MAC - find_library(GCC_EXT_LIB gcc_ext.10.5 PATHS ${GFORTRAN_PATH}) - IF (GCC_EXT_LIB) - list (APPEND GFORTRAN_LIB ${GCC_EXT_LIB}) - ELSE () - MESSAGE(STATUS "gcc_ext is required on MAC but could not be found") - SET(ABORT_CONFIG TRUE) - ENDIF () - ENDIF(APPLE) - -ENDIF(NOT WIN32) + message( STATUS "LAPACK_LIBRARIES: ${LAPACK_LIBRARIES}" ) -# ARPACK -find_library (ARPACK_LIB NAMES arpack PATHS external external/ARPACK) + # 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 (NOT ARPACK_LIB) - MESSAGE(SEND_ERROR "libarpack is required but could not be found") - SET(ABORT_CONFIG TRUE) -ENDIF() -message( STATUS "ARPACK_LIB found: ${ARPACK_LIB}" ) - -# SUPERLU -if (SUPERLU) - find_path(SUPERLU_INC supermatrix.h "external/SuperLU/SRC" "/usr/local/include/superlu" ) - IF (NOT SUPERLU_INC) - MESSAGE(STATUS "SuperLU (supermatrix.h) is required but could not be found") - SET(ABORT_CONFIG TRUE) - ENDIF() - make_global_path(SUPERLU_INC "SUPERLU Include Path") - - find_library(SUPERLU_LIB superlu.a libsuperlu.a - PATHS ${SUPERLU_INC} ${SUPERLU_INC}/../ external /usr/local/lib ) - IF (NOT SUPERLU_LIB) - MESSAGE(STATUS "SuperLU Library is required but could not be found") - SET(ABORT_CONFIG TRUE) - ENDIF() - make_global_path(SUPERLU_LIB "SUPERLU Library") - include_directories( ${SUPERLU_INC} ) - message( STATUS "SUPERLU_LIB found: ${SUPERLU_LIB}" ) -endif() - -# Suitesparse -if (UMFPACK OR CHOLMOD) - # Suitesparse CHOLMOD - find_path(SUITESPARSE_DIR SuiteSparse_config/SuiteSparse_config.h "external/SuiteSparse") - IF (NOT SUITESPARSE_DIR) - # nothing in external, search globally for libraries and headers - find_library(CHOLMOD_LIB libcholmod.a) - find_library(COLAMD_LIB libcolamd.a) - find_library(CCOLAMD_LIB libccolamd.a) - find_library(METIS_LIB libmetis.a) - IF (NOT METIS_LIB) - find_library(METIS_LIB libmetis.dylib) - ENDIF() - IF (NOT METIS_LIB) - find_library(METIS_LIB libmetis.so) - ENDIF() - find_library(CAMD_LIB libcamd.a) - find_library(AMD_LIB libamd.a) - - # Suitesparse UMFPACK - find_library(UMFPACK_LIB libumfpack.a) - find_library(SUITESPARSE_LIB libsuitesparseconfig.a) - - FIND_PATH( CHOLMOD_INCLUDE_DIR cholmod.h - PATHS /usr/local/include - /usr/include - /usr/include/suitesparse/ - ${CMAKE_SOURCE_DIR}/MacOS/Libs/cholmod - PATH_SUFFIXES cholmod/ CHOLMOD/ ) - IF (NOT CHOLMOD_INCLUDE_DIR) - MESSAGE(STATUS "SuiteSparse chomod.h is required but could not be found") - SET(ABORT_CONFIG TRUE) - ENDIF() - - include_directories( - ${CHOLMOD_INCLUDE_DIR} - ) + IF (GFORTRAN_LIB) + message( STATUS "GFORTRAN_LIB found: ${GFORTRAN_LIB}" ) - ELSE (NOT SUITESPARSE_DIR) - # found suite sparse locally in external dir - make_global_path(SUITESPARSE_DIR "SuiteSparse Directory") - message( STATUS "SUITESPARSE_DIR found: ${SUITESPARSE_DIR}" ) + add_executable (HMC HMC.cpp) + TARGET_LINK_LIBRARIES(HMC ${GFORTRAN_LIB} ${ARPACK_LIB} ${LAPACK_LIBRARIES}) - find_library(CHOLMOD_LIB libcholmod.a ${SUITESPARSE_DIR}/CHOLMOD/Lib ) - find_library(COLAMD_LIB libcolamd.a ${SUITESPARSE_DIR}/COLAMD/Lib ) - find_library(CCOLAMD_LIB libccolamd.a ${SUITESPARSE_DIR}/CCOLAMD/Lib ) - find_library(METIS_LIB libmetis.a ${SUITESPARSE_DIR}/metis-4.0 ) - IF (NOT METIS_LIB) - find_library(METIS_LIB libmetis.dylib) - ENDIF() - IF (NOT METIS_LIB) - find_library(METIS_LIB libmetis.so) - ENDIF() - find_library(CAMD_LIB libcamd.a ${SUITESPARSE_DIR}/CAMD/Lib ) - find_library(AMD_LIB libamd.a ${SUITESPARSE_DIR}/AMD/Lib ) - - # Suitesparse UMFPACK - find_library(UMFPACK_LIB libumfpack.a ${SUITESPARSE_DIR}/UMFPACK/Lib ) - find_library(SUITESPARSE_LIB libsuitesparseconfig.a ${SUITESPARSE_DIR}/SuiteSparse_config ) - - include_directories( - ${SUITESPARSE_DIR}/CHOLMOD/Include - ${SUITESPARSE_DIR}/SuiteSparse_config - ) + 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() - set(SSPARSE_LIBS - ${UMFPACK_LIB} - ${CHOLMOD_LIB} - ${COLAMD_LIB} - ${CCOLAMD_LIB} - ${METIS_LIB} - ${CAMD_LIB} - ${AMD_LIB} - ${SUITESPARSE_LIB} - ) - - # some linux systems need specifically librt (for SuiteSparse): - if (NOT APPLE) - set (SSPARSE_LIBS ${SSPARSE_LIBS} -lrt) - endif() - - -endif() -add_executable(HMC HMC.cpp) -TARGET_LINK_LIBRARIES(HMC ${LAPACK_LIBRARIES}) -TARGET_LINK_LIBRARIES(HMC ${ARPACK_LIB}) +ELSE() + message(FATAL_ERROR "This program requires the openblas library, and will not be compiled.") +ENDIF() From 251ba80671feb1199356fe0129523e56a369d0c4 Mon Sep 17 00:00:00 2001 From: Repouskos Panagiotis Date: Fri, 29 May 2020 21:15:33 +0300 Subject: [PATCH 18/38] refactor - rename folder matrices to matrix_operations - refactor boltzmann_hmc_walk.hpp to follow the style of the rest random walks - in boost_random_number_generator.hpp create a default (empty) constructor --- include/convex_bodies/spectrahedra/LMI.h | 2 +- .../spectrahedra/spectrahedron.h | 22 +- .../boost_random_number_generator.hpp | 2 + .../DenseProductMatrix.h | 0 .../EigenDenseMatrix.h | 0 .../EigenvaluesProblems.h | 0 include/optimization/SimulatedAnnealing.h | 16 +- include/random_walks/HMC_RandomWalk.h | 251 ----------------- include/random_walks/boltzmann_hmc_walk.hpp | 263 ++++++++++++++++++ 9 files changed, 291 insertions(+), 265 deletions(-) rename include/{matrices => matrix_operations}/DenseProductMatrix.h (100%) rename include/{matrices => matrix_operations}/EigenDenseMatrix.h (100%) rename include/{matrices => matrix_operations}/EigenvaluesProblems.h (100%) delete mode 100644 include/random_walks/HMC_RandomWalk.h create mode 100644 include/random_walks/boltzmann_hmc_walk.hpp diff --git a/include/convex_bodies/spectrahedra/LMI.h b/include/convex_bodies/spectrahedra/LMI.h index 20dd727c4..baf6d650b 100644 --- a/include/convex_bodies/spectrahedra/LMI.h +++ b/include/convex_bodies/spectrahedra/LMI.h @@ -5,7 +5,7 @@ #ifndef VOLESTI_LMI_H #define VOLESTI_LMI_H -#include "matrices/EigenvaluesProblems.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 diff --git a/include/convex_bodies/spectrahedra/spectrahedron.h b/include/convex_bodies/spectrahedra/spectrahedron.h index 9abebe079..16763dc39 100644 --- a/include/convex_bodies/spectrahedra/spectrahedron.h +++ b/include/convex_bodies/spectrahedra/spectrahedron.h @@ -1,11 +1,18 @@ -// -// Created by panagiotis on 2/22/20. -// +// 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_SPECTRAHEDRON_H #define VOLESTI_SPECTRAHEDRON_H #include "LMI.h" +#include "chrono" +#include "random.hpp" /// This class manipulates a spectrahedron, described by a LMI /// \tparam NT Numeric Type @@ -15,6 +22,11 @@ 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; @@ -150,12 +162,12 @@ class Spectrahedron { } /// \return The dimension of the spectrahedron - unsigned int dimension() { + unsigned int dimension() const { return d; } /// \return The LMI describing this spectrahedron - LMI getLMI() { + LMI getLMI() const { return lmi; } 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/matrices/DenseProductMatrix.h b/include/matrix_operations/DenseProductMatrix.h similarity index 100% rename from include/matrices/DenseProductMatrix.h rename to include/matrix_operations/DenseProductMatrix.h diff --git a/include/matrices/EigenDenseMatrix.h b/include/matrix_operations/EigenDenseMatrix.h similarity index 100% rename from include/matrices/EigenDenseMatrix.h rename to include/matrix_operations/EigenDenseMatrix.h diff --git a/include/matrices/EigenvaluesProblems.h b/include/matrix_operations/EigenvaluesProblems.h similarity index 100% rename from include/matrices/EigenvaluesProblems.h rename to include/matrix_operations/EigenvaluesProblems.h diff --git a/include/optimization/SimulatedAnnealing.h b/include/optimization/SimulatedAnnealing.h index b5a69a2f7..e8d779897 100644 --- a/include/optimization/SimulatedAnnealing.h +++ b/include/optimization/SimulatedAnnealing.h @@ -21,9 +21,9 @@ class SimulatedAnnealing { /// The type of the spectrahedron typedef Spectrahedron SPECTRAHEDRON; /// To use to generate random numbers - typedef boost::mt19937 RNGType; + typedef BoostRandomNumberGenerator RNGType; /// The Hamiltonian Monte Carlo random walk with reflections - typedef HMC_RandomWalk HMC; + typedef BoltzmannHMCWalk::Walk HMC; /// Holds parameters of the algorithm struct Settings { @@ -92,10 +92,10 @@ class SimulatedAnnealing { /// Initialize the hamiltonian monte carlo random walk /// \param[out] hmcRandomWalk /// \param[in] temperature - void initializeHMC(HMC& hmcRandomWalk, NT const temperature) { - typedef boost::mt19937 RNGType; - unsigned seed = std::chrono::system_clock::now().time_since_epoch().count(); - RNGType rng(seed); + /// \tparam[in] dim the dimension of the spectrahedron + void initializeHMC(HMC& hmcRandomWalk, NT const temperature, const int dim) { +// unsigned seed = std::chrono::system_clock::now().time_since_epoch().count(); + RNGType rng(dim); typename HMC::Settings settings = typename HMC::Settings(this->settings.walkLength, rng, objectiveFunction, temperature, diameter); hmcRandomWalk = HMC(settings); @@ -159,7 +159,7 @@ class SimulatedAnnealing { // initialize random walk; HMC hmc; - initializeHMC(hmc, diameter); + initializeHMC(hmc, diameter, x.dimension()); typename HMC::PrecomputedValues hmcPrecomputesValues; // if settings.maxNumSteps is negative there is no @@ -170,7 +170,7 @@ class SimulatedAnnealing { std::list randPoints; while (1) { - hmc.sample(*spectrahedron, x, settings.walkLength, randPoints, hmcPrecomputesValues); + hmc.apply(*spectrahedron, x, settings.walkLength, randPoints, hmcPrecomputesValues); // if the sampled point is not inside the spectrahedron, // get a new one diff --git a/include/random_walks/HMC_RandomWalk.h b/include/random_walks/HMC_RandomWalk.h deleted file mode 100644 index 12abfdc77..000000000 --- a/include/random_walks/HMC_RandomWalk.h +++ /dev/null @@ -1,251 +0,0 @@ -// -// Created by panagiotis on 2/23/20. -// - -#ifndef VOLESTI_HMC_RANDOMWALK_H -#define VOLESTI_HMC_RANDOMWALK_H - -#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). -/// \tparam Point Point type to communicate with the rest library -/// \tparam MT Matrix type for internal computations -/// \tparam VT Vector type for internal computations -/// \tparam RNGType -template -class HMC_RandomWalk { -public: - /// The numeric type - typedef typename Point::FT NT; - /// The type of the spectrahedron - typedef Spectrahedron SPECTRAHEDRON; - /// Type for internal structure of class Spectrahedron - typedef typename SPECTRAHEDRON::PrecomputedValues PrecomputedValues; - - /// 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 - RNGType rng; - /// 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 - /// \return An instance of this struct - Settings(const int walkLength, const RNGType& rng, const Point& c, const NT temperature, const NT diameter, - unsigned int reflectionsBound = 10, NT dl = 0.995) : walk_length(walkLength), rng(rng), c(c.getCoefficients()), temperature(temperature), - diameter(diameter), reflectionsBound(reflectionsBound), dl(dl) {} - - Settings() {} - }; - - /// The parameters of the random walk - Settings settings; - - - HMC_RandomWalk() {} - - /// Constructor - /// \param[in] settings The settings of the random walk - HMC_RandomWalk(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 - void sample(SPECTRAHEDRON& spectrahedron, const Point& 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 - void sample(SPECTRAHEDRON& spectrahedron, const Point& 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; - } - - - // Pick a random direction as a normilized vector - Point get_direction(const unsigned int dim) { - - boost::normal_distribution<> rdist(0,1); - NT normal = NT(0); - unsigned seed = std::chrono::system_clock::now().time_since_epoch().count(); - RNGType rng(seed); - - Point p(dim); - NT* data = p.pointerToData(); - - //RNGType rng2 = var.rng; - for (unsigned int i=0; i 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 = urdist(rng) * 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 = get_direction(n).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_HMC_RANDOMWALK_H 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 From de162e6769b89669b2ba62f2c98ef6c25a5bbf50 Mon Sep 17 00:00:00 2001 From: Repouskos Panagiotis Date: Fri, 29 May 2020 21:17:57 +0300 Subject: [PATCH 19/38] add example boltzmannHmcWalk.cpp - update examples/spectrahedron/README.md - remove files CoordinateDirectionsHitAndRun_RandomWalk.h and optimization/SDPA-FormatManager.h (duplicate) --- examples/CMakeLists.txt | 1 + examples/spectrahedra/CMakeLists.txt | 43 ++++ examples/spectrahedra/README.md | 86 +++++++- examples/spectrahedra/boltzmannHmcWalk.cpp | 81 +++++++ include/optimization/SDPA_FormatManager.h | 200 ------------------ ...CoordinateDirectionsHitAndRun_RandomWalk.h | 91 -------- 6 files changed, 208 insertions(+), 294 deletions(-) create mode 100644 examples/spectrahedra/boltzmannHmcWalk.cpp delete mode 100644 include/optimization/SDPA_FormatManager.h delete mode 100644 include/random_walks/CoordinateDirectionsHitAndRun_RandomWalk.h diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index c90c44c22..124f9b0f5 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -38,6 +38,7 @@ 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) diff --git a/examples/spectrahedra/CMakeLists.txt b/examples/spectrahedra/CMakeLists.txt index 0652983c3..4ee570772 100644 --- a/examples/spectrahedra/CMakeLists.txt +++ b/examples/spectrahedra/CMakeLists.txt @@ -8,5 +8,48 @@ add_executable (readWriteSdpaFile readWriteSdpaFile.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/) + + IF (GFORTRAN_LIB) + message( STATUS "GFORTRAN_LIB found: ${GFORTRAN_LIB}" ) + + + add_executable (boltzmannHmcWalk boltzmannHmcWalk.cpp) + TARGET_LINK_LIBRARIES(boltzmannHmcWalk ${GFORTRAN_LIB} ${ARPACK_LIB} ${LAPACK_LIBRARIES}) + + 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..de4a65731 100644 --- a/examples/spectrahedra/README.md +++ b/examples/spectrahedra/README.md @@ -1,5 +1,12 @@ # Examples for Spectrahedra +## Table of contents +1. [Compilation](#compilation) + 1. [Dependencies](#dependencies) +2. [Examples](#examples) + 1. [Example 1: Read/write SDPA format files](#example-1-readwrite-sdpa-format-files) + 2. [Example 2: Sample with HMC, Boltzmann distribution](#example-2-sample-with-hmc-boltzmann-distribution) + ## Compilation In folder examples, first run cmake, to create the makefile: @@ -13,8 +20,45 @@ 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 +``` + +You may have to edit the path in following line in examples/spectrahedra/CMakeLists.txt + +```bash +FIND_LIBRARY(GFORTRAN_LIB NAMES libgfortran.so PATHS /usr/lib/gcc/x86_64-linux-gnu/8/) +``` + +to point to your installation. +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 +``` + +And copy the folder external back in folder examples: + +```bash + cp -r external ../ +``` + +
## Examples ### Example 1: Read/write SDPA format files @@ -62,4 +106,40 @@ 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 + + +### Example 2: Sample with HMC, Boltzmann distribution + +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 [Example 1](#example-1-readwrite-sdpa-format-files). Run the example with: + +```bash +./boltzmannHmcWalk +``` + +#### 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.apply(spectrahedron, initialPoint, pointsNum, points); +``` + +- sepctrahedron: instance of class Spectrahedron +- initialPoint: an interior point in the spectrahedron +- pointsNum: how many points to sample +- points: a list to return the samples + diff --git a/examples/spectrahedra/boltzmannHmcWalk.cpp b/examples/spectrahedra/boltzmannHmcWalk.cpp new file mode 100644 index 000000000..1ebccd816 --- /dev/null +++ b/examples/spectrahedra/boltzmannHmcWalk.cpp @@ -0,0 +1,81 @@ +// 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 "Eigen/Eigen" +#include "vector" +#include +#include "cartesian_geom/cartesian_kernel.h" +#include "spectrahedron.h" +#include "SDPAFormatManager.h" +#include "string" +#include "iostream" +#include "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/include/optimization/SDPA_FormatManager.h b/include/optimization/SDPA_FormatManager.h deleted file mode 100644 index d38beeebb..000000000 --- a/include/optimization/SDPA_FormatManager.h +++ /dev/null @@ -1,200 +0,0 @@ -// -// Created by panagiotis on 20/7/2019. -// - -#ifndef VOLESTI_SDPA_FORMAT_MANAGER_H -#define VOLESTI_SDPA_FORMAT_MANAGER_H - -#include "spectrahedron.h" - -#include -#include - - -typedef std::string::iterator string_it; -typedef std::list listVector; - - - /** - * Return the first non white space/tab character and advance the iterator one position - * @param it - * @return - */ - char consumeSymbol(string_it &at, string_it &end) { - while (at != end) { - if (*at != ' ' && *at != '\t') { - char c = *at; - at++; - return c; - } - - at++; - } - - return '\0'; - } - - - bool isCommentLine(std::string &line) { - string_it at = line.begin(); - string_it end = line.end(); - - char c = consumeSymbol(at, end); - - return c == '"' || c == '*'; - } - - - int fetchNumber(std::string &string) { - std::stringstream stream(string); - int num; - stream >> num; - return num; - } - - - /** - * Read a vector of the form {val1, val2, ..., valn} - * @param string - * @return - */ - listVector readVector(std::string &string) { - std::stringstream stream(string); - listVector vector; - double value; - - while (stream >> value) { - vector.push_back(value); - } - - return vector; - } - - - template - void loadSDPAFormatFile(std::ifstream &is, LMI &lmi, VT &objectiveFunction) { - std::string line; - std::string::size_type sz; - - std::getline(is, line, '\n'); - - //skip comments - while (isCommentLine(line)) { - std::getline(is, line, '\n'); - } - - //read variables number - int variablesNum = fetchNumber(line); - - if (std::getline(is, line, '\n').eof()) - throw 1; - - //read number of blocks - int blocksNum = fetchNumber(line); - - if (std::getline(is, line, '\n').eof()) - throw 1; - - //read block structure vector - listVector blockStructure = readVector(line); //TODO different if we have one block - - if (blockStructure.size() != blocksNum) - throw 1; - - if (std::getline(is, line, '\n').eof()) - throw 1; - - //read constant vector - listVector constantVector = readVector(line); - - while (constantVector.size() < variablesNum) { - if (std::getline(is, line, '\n').eof()) - throw 1; - listVector t = readVector(line); - constantVector.insert(std::end(constantVector), std::begin(t), std::end(t)); - } - -// for (auto x : constantVector) -// std::cout << x << " "; -// std::cout << "\n"; -// throw 1; - - - std::vector matrices(variablesNum + 1); - int matrixDim = 0; - for (auto x : blockStructure) - matrixDim += std::abs((int) x); - - //read constraint matrices - for (int atMatrix = 0; atMatrix < matrices.size(); atMatrix++) { - MT matrix; - matrix.setZero(matrixDim, matrixDim); - - int offset = 0; - - for (auto blockSize : blockStructure) { - - if (blockSize > 0) { //read a block blockSize x blockSize - int at = 0; - int i = 0, j = 0; - - while (at < blockSize * blockSize) { - if (std::getline(is, line, '\n').eof()) - throw 1; - - listVector vec = readVector(line); - - for (double value : vec) { - matrix(offset + i, offset + j) = value; -// std::cout <0, I want it <0 - if (atMatrix == 0) //F0 has - before it in SDPA format, the rest have + - matrices[atMatrix] = matrix; - else - matrices[atMatrix] = -1 * matrix; - } - - // return lmi and objective function - objectiveFunction.setZero(variablesNum); - int at = 0; - - for (auto value : constantVector) - objectiveFunction(at++) = value; - - lmi = LMI(matrices); - } - - - - -#endif //VOLESTI_SDPA_FORMAT_MANAGER_H diff --git a/include/random_walks/CoordinateDirectionsHitAndRun_RandomWalk.h b/include/random_walks/CoordinateDirectionsHitAndRun_RandomWalk.h deleted file mode 100644 index dccf6bf8b..000000000 --- a/include/random_walks/CoordinateDirectionsHitAndRun_RandomWalk.h +++ /dev/null @@ -1,91 +0,0 @@ -// -// Created by panagiotis on 2/28/20. -// - -#ifndef VOLESTI_COORDINATEDIRECTIONSHITANDRUN_RANDOMWALK_H -#define VOLESTI_COORDINATEDIRECTIONSHITANDRUN_RANDOMWALK_H - -/// The coordinate directions hit and run random walk, to sample a spectrahedron from the uniform distribution. -/// \tparam Point Point type to communicate with the rest library -/// \tparam MT Matrix type for internal computations -/// \tparam VT Vector type for internal computations -/// \tparam RNGType -template -class CoordinateDirectionsHitAndRun_RandomWalk { -public: - - /// The numeric type - typedef typename Point::FT NT; - /// The type of the spectrahedron - typedef Spectrahedron SPECTRAHEDRON; - /// Type for internal structure of class Spectrahedron - typedef typename SPECTRAHEDRON::PrecomputedValues PrecomputedValues; - - /// The number of points to "burn", before keeping the following as a sample - int walkLength; - /// For generating random numbers - RNGType rng; - - /// Constructor - /// \param[in] walkLength The number of points to "burn", before keeping the following as a sample - /// \param[in] rng For generating random numbers - CoordinateDirectionsHitAndRun_RandomWalk(int const walkLength, RNGType const & rng ) : walkLength(walkLength), rng(rng) {} - - /// Samples uniformly random points in the spectrahedron - /// \param[in] spectrahedron The spectrahedron to be sampled - /// \param[in] interiorPoint A point in the interior of the spectrahedron - /// \param[in] numPoints The number of points to sample - /// \param[out] randPoints The list which will hold the samples - void sample(SPECTRAHEDRON &spectrahedron, Point const & interiorPoint, const int numPoints, std::list & randPoints) { - - // 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 <= numPoints; ++i) { - // burn #walk_length points to get one sample - for (unsigned int j = 0; j < walkLength; ++j) { - getNextPoint(spectrahedron, p, precomputedValues); - } - - // add the sample in the return list - randPoints.push_back(Point(p)); - } - - // the data in preComputedValues may be out of date in the next call - precomputedValues.resetFlags(); - } - - - void getNextPoint(SPECTRAHEDRON & spectrahedron, VT &p, PrecomputedValues & precomputedValues) { - int n = spectrahedron.dimension(); - - // initialize random numbers generators - boost::random::uniform_real_distribution<> urdist(0, 1); - boost::random::uniform_int_distribution<> uidist(1, n); - - // uniformly select a line parallel to an axis, - // i.e. an indicator i s.t. x_i = 1 - int coordinate = uidist(rng); - - // get the distances we can travel from p - // on the line p + t* e_coordinate - // before reaching the boundary - std::pair distances = spectrahedron.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 * *(spectrahedron.getLMI().getMatrix(coordinate)); - } -}; -#endif //VOLESTI_COORDINATEDIRECTIONSHITANDRUN_RANDOMWALK_H From d4e4449d30647cee4f341ee8a8c8b2fed3e8ab48 Mon Sep 17 00:00:00 2001 From: Repouskos Panagiotis Date: Fri, 29 May 2020 21:23:22 +0300 Subject: [PATCH 20/38] fix type --- examples/spectrahedra/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/spectrahedra/README.md b/examples/spectrahedra/README.md index de4a65731..248d7e332 100644 --- a/examples/spectrahedra/README.md +++ b/examples/spectrahedra/README.md @@ -20,7 +20,7 @@ Then, in folder examples/spectrahedra compile using the makefile: make ``` -###Dependencies +### 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. From 963978b02fcf3cba87d2a5b0ae46b759a1ca0909 Mon Sep 17 00:00:00 2001 From: Repouskos Panagiotis Date: Sat, 30 May 2020 17:04:58 +0300 Subject: [PATCH 21/38] add examples/spectrahedra/semidefiniteProgramming.cpp - fix bug in SimulatedAnnealing.h (minor - missed from previous refactor) - update examples/spectrahedra/readme.md - EigenvaluesProblems.h when calling arpack method findEigenvalues() make sure ncv <= number of rows of matrix --- examples/CMakeLists.txt | 1 + examples/spectrahedra/CMakeLists.txt | 3 + examples/spectrahedra/README.md | 64 +++++++++++++++++-- .../spectrahedra/semidefiniteProgramming.cpp | 64 +++++++++++++++++++ .../matrix_operations/EigenvaluesProblems.h | 2 +- include/optimization/SimulatedAnnealing.h | 40 ++++++++++-- 6 files changed, 160 insertions(+), 14 deletions(-) diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 124f9b0f5..6125dea1b 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -43,6 +43,7 @@ else () 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 4ee570772..5e5c93b87 100644 --- a/examples/spectrahedra/CMakeLists.txt +++ b/examples/spectrahedra/CMakeLists.txt @@ -35,6 +35,9 @@ IF (OPENBLAS_LIB) add_executable (boltzmannHmcWalk boltzmannHmcWalk.cpp) TARGET_LINK_LIBRARIES(boltzmannHmcWalk ${GFORTRAN_LIB} ${ARPACK_LIB} ${LAPACK_LIBRARIES}) + add_executable (semidefiniteProgramming semidefiniteProgramming.cpp) + TARGET_LINK_LIBRARIES(semidefiniteProgramming ${GFORTRAN_LIB} ${ARPACK_LIB} ${LAPACK_LIBRARIES}) + ELSE() MESSAGE(STATUS "gfortran is required but it could not be found") ENDIF () diff --git a/examples/spectrahedra/README.md b/examples/spectrahedra/README.md index 248d7e332..7517d7660 100644 --- a/examples/spectrahedra/README.md +++ b/examples/spectrahedra/README.md @@ -4,8 +4,10 @@ 1. [Compilation](#compilation) 1. [Dependencies](#dependencies) 2. [Examples](#examples) - 1. [Example 1: Read/write SDPA format files](#example-1-readwrite-sdpa-format-files) - 2. [Example 2: Sample with HMC, Boltzmann distribution](#example-2-sample-with-hmc-boltzmann-distribution) + 1. [Read/write SDPA format files - readWriteSdpaFile.cpp](#readwrite-sdpa-format-files---readwritesdpafilecpp) + 2. [Sample with HMC, Boltzmann distribution - boltzmannHmcWalk.cpp](#sample-with-hmc-boltzmann-distribution---boltzmannhmcwalkcpp) + 3. [Randomized SDP Solver - semidefiniteProgramming.cpp](#randomized-sdp-solver---semidefiniteprogrammingcpp) + ## Compilation In folder examples, first run cmake, to create the makefile: @@ -61,7 +63,7 @@ And copy the folder external back in folder examples:
## Examples -### Example 1: Read/write SDPA format files +### Read/write SDPA format files - readWriteSdpaFile.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: @@ -109,11 +111,11 @@ It represents a spectrahedron in 2 dimensions, described by a linear matrix ineq - and so on, till all 3 matrices are defined -### Example 2: Sample with HMC, Boltzmann distribution +### Sample with HMC, Boltzmann distribution - boltzmannHmcWalk.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 [Example 1](#example-1-readwrite-sdpa-format-files). Run the example with: +in [readWriteSdpaFile.cpp](#readwrite-sdpa-format-files---readwritesdpafilecpp). Run the example with: ```bash ./boltzmannHmcWalk @@ -135,11 +137,61 @@ HmcWalkSettings settings(walkLength, randomNumberGenerator, objFunction, tempera and then we can sample the spectrahedron ```bash +HmcWalk hmcWalk(settings); hmcWalk.apply(spectrahedron, initialPoint, pointsNum, points); ``` -- sepctrahedron: instance of class Spectrahedron +- 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 - semidefiniteProgramming.cpp + +In this example, we will solve a semidefinite program. We will read the program +as in [readWriteSdpaFile.cpp](#readwrite-sdpa-format-files---readwritesdpafilecpp). Run the example with: + +```bash +./semidefiniteProgramming +``` + +#### Code Explanation +To use the solver, first we declare some parameters: + +```bash +SA::Settings settings(rel_error); +``` + +Actually, we can further customize the algorithm. The full settings definition is: + +```bash +SA::Settings 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---boltzmannhmcwalkcpp). + 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 declare the solver: + +```bash +SA simulatedAnnealing(&spectrahedron, objFunction, settings, &initialPoint); +``` + +- 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. + +And then we can call the solver: + +```bash +NT min = simulatedAnnealing.solve(sol, verbose); +``` + +- 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/semidefiniteProgramming.cpp b/examples/spectrahedra/semidefiniteProgramming.cpp index 327adf28c..212bd9247 100644 --- a/examples/spectrahedra/semidefiniteProgramming.cpp +++ b/examples/spectrahedra/semidefiniteProgramming.cpp @@ -10,3 +10,67 @@ // 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 "Eigen/Eigen" +#include "vector" +#include +#include "cartesian_geom/cartesian_kernel.h" +#include "spectrahedron.h" +#include "SDPAFormatManager.h" +#include "string" +#include "iostream" +#include "SimulatedAnnealing.h" + +typedef double NT; +typedef Eigen::Matrix VT; +typedef Eigen::Matrix MT; +typedef Cartesian Kernel; +typedef typename Kernel::Point Point; +typedef Spectrahedron SPECTRAHEDRON; +typedef SimulatedAnnealing SA; + + +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 + SA::Settings settings(rel_error); + + // Declare the solver + SA simulatedAnnealing(&spectrahedron, objFunction, settings, &initialPoint); + + // solve the program + Point sol; + bool verbose = true; + NT min = simulatedAnnealing.solve(sol ,verbose); + + // print solution + std::cout << min << "\n" << "point: "; + sol.print(); + + return 0; +} + diff --git a/include/matrix_operations/EigenvaluesProblems.h b/include/matrix_operations/EigenvaluesProblems.h index 4095fd7f8..fd43937d1 100644 --- a/include/matrix_operations/EigenvaluesProblems.h +++ b/include/matrix_operations/EigenvaluesProblems.h @@ -244,7 +244,7 @@ class EigenvaluesProblems, E // the eigenvector of A with largest real. ARNonSymStdEig > - dprob(A.cols(), 1, &M, &DenseProductMatrix::MultMv, std::string ("LR"), 8, 0.000);//, 100*3); + dprob(A.cols(), 1, &M, &DenseProductMatrix::MultMv, std::string ("LR"), 8 randPoints; - hmc.sample(*spectrahedron, x, 1, randPoints); - // update values; - x = randPoints.back(); - randPoints.clear(); + typename HMC::PrecomputedValues hmcPrecomputesValues; + NT previous_min = objectiveFunction.dot(x); + + while (1) { + hmc.apply(*spectrahedron, x, settings.walkLength, randPoints, hmcPrecomputesValues); + + // if the sampled point is not inside the spectrahedron, + // get a new one + if (spectrahedron->isExterior(hmcPrecomputesValues.C)) { + if (verbose) std::cout << "Sampled point outside the spectrahedron.\n"; + randPoints.clear(); + hmcPrecomputesValues.resetFlags(); + } + else { + // update values; + x = randPoints.back(); + randPoints.clear(); + break; + } + } + currentMin = objectiveFunction.dot(x); ++stepsCount; + // compute relative error + NT relError = relativeError(previous_min, currentMin); + if (verbose) - std::cout << "Step: " << stepsCount << ", Temperature: " << temperature << ", Min: " << currentMin << "\n"; + 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; From 72ca7d7dd7b87ec7ea5d02c978a36fec94854ef6 Mon Sep 17 00:00:00 2001 From: Repouskos Panagiotis Date: Thu, 18 Jun 2020 21:23:38 +0300 Subject: [PATCH 22/38] refactor - rename files to match package - in the simulated_annealing.hpp destroy the class and expose the functionality as free functions - update examples and README.md --- examples/spectrahedra/CMakeLists.txt | 10 +- examples/spectrahedra/README.md | 37 ++--- ...mannHmcWalk.cpp => boltzmann_hmc_walk.cpp} | 13 +- ...eSdpaFile.cpp => read_write_sdpa_file.cpp} | 10 +- ...idefiniteProgramming.cpp => solve_sdp.cpp} | 21 +-- include/SDPAFormatManager.h | 4 +- include/cartesian_geom/point.h | 1 + include/optimization/simulated_annealing.hpp | 153 ++++++++++++++++++ .../{SlidingWindow.h => sliding_window.hpp} | 17 +- 9 files changed, 207 insertions(+), 59 deletions(-) rename examples/spectrahedra/{boltzmannHmcWalk.cpp => boltzmann_hmc_walk.cpp} (95%) rename examples/spectrahedra/{readWriteSdpaFile.cpp => read_write_sdpa_file.cpp} (95%) rename examples/spectrahedra/{semidefiniteProgramming.cpp => solve_sdp.cpp} (83%) create mode 100644 include/optimization/simulated_annealing.hpp rename include/optimization/{SlidingWindow.h => sliding_window.hpp} (78%) diff --git a/examples/spectrahedra/CMakeLists.txt b/examples/spectrahedra/CMakeLists.txt index 5e5c93b87..b69e008e0 100644 --- a/examples/spectrahedra/CMakeLists.txt +++ b/examples/spectrahedra/CMakeLists.txt @@ -5,7 +5,7 @@ # 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 @@ -32,11 +32,11 @@ IF (OPENBLAS_LIB) message( STATUS "GFORTRAN_LIB found: ${GFORTRAN_LIB}" ) - add_executable (boltzmannHmcWalk boltzmannHmcWalk.cpp) - TARGET_LINK_LIBRARIES(boltzmannHmcWalk ${GFORTRAN_LIB} ${ARPACK_LIB} ${LAPACK_LIBRARIES}) + add_executable (boltzmann_hmc_walk boltzmann_hmc_walk.cpp) + TARGET_LINK_LIBRARIES(boltzmann_hmc_walk ${GFORTRAN_LIB} ${ARPACK_LIB} ${LAPACK_LIBRARIES}) - add_executable (semidefiniteProgramming semidefiniteProgramming.cpp) - TARGET_LINK_LIBRARIES(semidefiniteProgramming ${GFORTRAN_LIB} ${ARPACK_LIB} ${LAPACK_LIBRARIES}) + add_executable (solve_sdp solve_sdp.cpp) + TARGET_LINK_LIBRARIES(solve_sdp ${GFORTRAN_LIB} ${ARPACK_LIB} ${LAPACK_LIBRARIES}) ELSE() MESSAGE(STATUS "gfortran is required but it could not be found") diff --git a/examples/spectrahedra/README.md b/examples/spectrahedra/README.md index 7517d7660..f0808a652 100644 --- a/examples/spectrahedra/README.md +++ b/examples/spectrahedra/README.md @@ -4,9 +4,9 @@ 1. [Compilation](#compilation) 1. [Dependencies](#dependencies) 2. [Examples](#examples) - 1. [Read/write SDPA format files - readWriteSdpaFile.cpp](#readwrite-sdpa-format-files---readwritesdpafilecpp) - 2. [Sample with HMC, Boltzmann distribution - boltzmannHmcWalk.cpp](#sample-with-hmc-boltzmann-distribution---boltzmannhmcwalkcpp) - 3. [Randomized SDP Solver - semidefiniteProgramming.cpp](#randomized-sdp-solver---semidefiniteprogrammingcpp) + 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 @@ -63,13 +63,13 @@ And copy the folder external back in folder examples:
## Examples -### Read/write SDPA format files - readWriteSdpaFile.cpp +### 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 @@ -111,14 +111,14 @@ It represents a spectrahedron in 2 dimensions, described by a linear matrix ineq - and so on, till all 3 matrices are defined -### Sample with HMC, Boltzmann distribution - boltzmannHmcWalk.cpp +### 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 -./boltzmannHmcWalk +./boltzmann_hmc_walk ``` #### Code Explanation @@ -147,51 +147,44 @@ hmcWalk.apply(spectrahedron, initialPoint, pointsNum, points); - points: a list to return the samples -### Randomized SDP Solver - semidefiniteProgramming.cpp +### Randomized SDP Solver - solve_sdp.cpp In this example, we will solve a semidefinite program. We will read the program -as in [readWriteSdpaFile.cpp](#readwrite-sdpa-format-files---readwritesdpafilecpp). Run the example with: +as in [read_write_sdpa_file.cpp](#readwrite-sdpa-format-files---read_write_sdpa_filecpp). Run the example with: ```bash -./semidefiniteProgramming +./solve_sdp ``` #### Code Explanation To use the solver, first we declare some parameters: ```bash -SA::Settings settings(rel_error); +SimulatedAnnealingSettings settings(rel_error); ``` Actually, we can further customize the algorithm. The full settings definition is: ```bash -SA::Settings settings(rel_error, walkLength, maxNumSteps, k) +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---boltzmannhmcwalkcpp). +- 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 declare the solver: +Next we can solve the program: ```bash -SA simulatedAnnealing(&spectrahedron, objFunction, settings, &initialPoint); +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. - -And then we can call the solver: - -```bash -NT min = simulatedAnnealing.solve(sol, verbose); -``` - - 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/boltzmannHmcWalk.cpp b/examples/spectrahedra/boltzmann_hmc_walk.cpp similarity index 95% rename from examples/spectrahedra/boltzmannHmcWalk.cpp rename to examples/spectrahedra/boltzmann_hmc_walk.cpp index 1ebccd816..eebb2b46f 100644 --- a/examples/spectrahedra/boltzmannHmcWalk.cpp +++ b/examples/spectrahedra/boltzmann_hmc_walk.cpp @@ -11,15 +11,16 @@ // HMC random walk. It will read the spectrahedron from data/sdp_n2m3.txt. //#define VOLESTI_DEBUG -#include "Eigen/Eigen" -#include "vector" + + +#include #include + +#include "Eigen/Eigen" #include "cartesian_geom/cartesian_kernel.h" -#include "spectrahedron.h" +#include "convex_bodies/spectrahedra/spectrahedron.h" #include "SDPAFormatManager.h" -#include "string" -#include "iostream" -#include "boltzmann_hmc_walk.hpp" +#include "random_walks/boltzmann_hmc_walk.hpp" typedef double NT; typedef Eigen::Matrix VT; diff --git a/examples/spectrahedra/readWriteSdpaFile.cpp b/examples/spectrahedra/read_write_sdpa_file.cpp similarity index 95% rename from examples/spectrahedra/readWriteSdpaFile.cpp rename to examples/spectrahedra/read_write_sdpa_file.cpp index a31137b53..6494d090f 100644 --- a/examples/spectrahedra/readWriteSdpaFile.cpp +++ b/examples/spectrahedra/read_write_sdpa_file.cpp @@ -11,14 +11,14 @@ // 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 "Eigen/Eigen" -#include "vector" + #include +#include + +#include "Eigen/Eigen" #include "cartesian_geom/cartesian_kernel.h" -#include "spectrahedron.h" +#include "convex_bodies/spectrahedra/spectrahedron.h" #include "SDPAFormatManager.h" -#include "string" -#include "iostream" typedef double NT; typedef Eigen::Matrix VT; diff --git a/examples/spectrahedra/semidefiniteProgramming.cpp b/examples/spectrahedra/solve_sdp.cpp similarity index 83% rename from examples/spectrahedra/semidefiniteProgramming.cpp rename to examples/spectrahedra/solve_sdp.cpp index 212bd9247..297903791 100644 --- a/examples/spectrahedra/semidefiniteProgramming.cpp +++ b/examples/spectrahedra/solve_sdp.cpp @@ -12,15 +12,15 @@ //#define VOLESTI_DEBUG -#include "Eigen/Eigen" -#include "vector" #include +#include + +#include "Eigen/Eigen" #include "cartesian_geom/cartesian_kernel.h" -#include "spectrahedron.h" +#include "convex_bodies/spectrahedra/spectrahedron.h" #include "SDPAFormatManager.h" -#include "string" -#include "iostream" -#include "SimulatedAnnealing.h" +#include "optimization/simulated_annealing.hpp" + typedef double NT; typedef Eigen::Matrix VT; @@ -28,7 +28,6 @@ typedef Eigen::Matrix MT; typedef Cartesian Kernel; typedef typename Kernel::Point Point; typedef Spectrahedron SPECTRAHEDRON; -typedef SimulatedAnnealing SA; int main(int argc, char* argv[]) { @@ -51,21 +50,17 @@ int main(int argc, char* argv[]) { // 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 - SA::Settings settings(rel_error); - - // Declare the solver - SA simulatedAnnealing(&spectrahedron, objFunction, settings, &initialPoint); + SimulatedAnnealingSettings settings(rel_error); // solve the program Point sol; bool verbose = true; - NT min = simulatedAnnealing.solve(sol ,verbose); + NT min = solve_sdp(spectrahedron, objFunction, settings, initialPoint, sol ,verbose); // print solution std::cout << min << "\n" << "point: "; diff --git a/include/SDPAFormatManager.h b/include/SDPAFormatManager.h index d154bbeb4..23c395242 100644 --- a/include/SDPAFormatManager.h +++ b/include/SDPAFormatManager.h @@ -10,11 +10,11 @@ #ifndef VOLESTI_SDPA_FORMAT_MANAGER_H #define VOLESTI_SDPA_FORMAT_MANAGER_H -#include "spectrahedron.h" - +#include #include #include +#include "convex_bodies/spectrahedra/spectrahedron.h" /// Reads/writes files according to the SDPA format for sdps. /// Currently supported Format: diff --git a/include/cartesian_geom/point.h b/include/cartesian_geom/point.h index d3f21ab3a..1eb387129 100644 --- a/include/cartesian_geom/point.h +++ b/include/cartesian_geom/point.h @@ -109,6 +109,7 @@ class point void operator= (const Coeff& coeffs) { this->coeffs = coeffs; + d = coeffs.rows(); } //TODO: avoid point construction in operators +,-,* diff --git a/include/optimization/simulated_annealing.hpp b/include/optimization/simulated_annealing.hpp new file mode 100644 index 000000000..dcf4b4098 --- /dev/null +++ b/include/optimization/simulated_annealing.hpp @@ -0,0 +1,153 @@ +// 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_SIMULATED_ANNEALING_HPP +#define VOLESTI_SIMULATED_ANNEALING_HPP + +#include + +#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/SlidingWindow.h b/include/optimization/sliding_window.hpp similarity index 78% rename from include/optimization/SlidingWindow.h rename to include/optimization/sliding_window.hpp index 8ec6fd35d..9fdcf3602 100644 --- a/include/optimization/SlidingWindow.h +++ b/include/optimization/sliding_window.hpp @@ -1,9 +1,14 @@ -// -// Created by panagiotis on 2/28/20. -// +// VolEsti (volume computation and sampling library) -#ifndef VOLESTI_SLIDINGWINDOW_H -#define VOLESTI_SLIDINGWINDOW_H +// 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 @@ -58,4 +63,4 @@ class SlidingWindow { } }; -#endif //VOLESTI_SLIDINGWINDOW_H +#endif //VOLESTI_SLIDING_WINDOW_HPP From 5123379491bd1c6f42555f623f5482d02846c42a Mon Sep 17 00:00:00 2001 From: Repouskos Panagiotis Date: Thu, 18 Jun 2020 22:55:26 +0300 Subject: [PATCH 23/38] add tests Add tests in folder tests/SDP to test the sdp solver and the boundary oracles.They have their own CMakeLists.txt --- include/convex_bodies/spectrahedra/LMI.h | 11 +- .../matrix_operations/DenseProductMatrix.h | 11 +- include/matrix_operations/EigenDenseMatrix.h | 11 +- .../matrix_operations/EigenvaluesProblems.h | 11 +- include/optimization/SimulatedAnnealing.h | 244 - test/SDP/CMakeLists.txt | 14 +- test/SDP/HMC.cpp | 93 - test/SDP/doctest.h | 5464 +++++++++++++++++ test/SDP/sdp__2_8.txt | 28 + test/SDP/test_main.cpp | 15 + test/SDP/test_solve_sdp.cpp | 74 + test/SDP/test_spec_oracles.cpp | 121 + 12 files changed, 5744 insertions(+), 353 deletions(-) delete mode 100644 include/optimization/SimulatedAnnealing.h delete mode 100644 test/SDP/HMC.cpp create mode 100644 test/SDP/doctest.h create mode 100644 test/SDP/sdp__2_8.txt create mode 100644 test/SDP/test_main.cpp create mode 100644 test/SDP/test_solve_sdp.cpp create mode 100644 test/SDP/test_spec_oracles.cpp diff --git a/include/convex_bodies/spectrahedra/LMI.h b/include/convex_bodies/spectrahedra/LMI.h index baf6d650b..bf02da07b 100644 --- a/include/convex_bodies/spectrahedra/LMI.h +++ b/include/convex_bodies/spectrahedra/LMI.h @@ -1,6 +1,11 @@ -// -// Created by panagiotis on 2/22/20. -// +// 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_LMI_H #define VOLESTI_LMI_H diff --git a/include/matrix_operations/DenseProductMatrix.h b/include/matrix_operations/DenseProductMatrix.h index a53401eff..848e1a7ae 100644 --- a/include/matrix_operations/DenseProductMatrix.h +++ b/include/matrix_operations/DenseProductMatrix.h @@ -1,6 +1,11 @@ -// -// Created by panagiotis on 2/24/20. -// +// 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 diff --git a/include/matrix_operations/EigenDenseMatrix.h b/include/matrix_operations/EigenDenseMatrix.h index cf593b004..df6dd93b3 100644 --- a/include/matrix_operations/EigenDenseMatrix.h +++ b/include/matrix_operations/EigenDenseMatrix.h @@ -1,6 +1,11 @@ -// -// Created by panagiotis on 2/22/20. -// +// 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 diff --git a/include/matrix_operations/EigenvaluesProblems.h b/include/matrix_operations/EigenvaluesProblems.h index fd43937d1..7f3ce7e75 100644 --- a/include/matrix_operations/EigenvaluesProblems.h +++ b/include/matrix_operations/EigenvaluesProblems.h @@ -1,6 +1,11 @@ -// -// Created by panagiotis on 2/22/20. -// +// 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 diff --git a/include/optimization/SimulatedAnnealing.h b/include/optimization/SimulatedAnnealing.h deleted file mode 100644 index 155343c53..000000000 --- a/include/optimization/SimulatedAnnealing.h +++ /dev/null @@ -1,244 +0,0 @@ -// -// Created by panagiotis on 2/28/20. -// - -#ifndef VOLESTI_SIMULATEDANNEALING_H -#define VOLESTI_SIMULATEDANNEALING_H - -#include "SlidingWindow.h" -#include "boltzmann_hmc_walk.hpp" - -/// Simulated Annealing algorithm for the semidefinite program -/// Minimize \[ c^T x \], s.t. LMI(x) <= 0 -/// \tparam Point Class point -/// \tparam MT Matrix type -/// \tparam VT Vector type -template -class SimulatedAnnealing { -public: - - /// The numeric type - typedef typename Point::FT NT; - /// The type of the spectrahedron - typedef Spectrahedron SPECTRAHEDRON; - /// To use to generate random numbers - typedef BoostRandomNumberGenerator RNGType; - /// The Hamiltonian Monte Carlo random walk with reflections - typedef BoltzmannHMCWalk::Walk HMC; - - /// Holds parameters of the algorithm - struct Settings { - /// 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; - - Settings(NT const error, int const walkLength = 1, int const maxNumSteps = -1, NT const k = 0.5) : error(error), - walkLength(walkLength), maxNumSteps(maxNumSteps), k(k) {} - }; - - - /// The feasible region of the semidefinite program - SPECTRAHEDRON *spectrahedron; - /// The normalized objective function of the semidefinite program - Point objectiveFunction; - /// The norm of the initial objective function - NT objectiveFunctionNorm; - /// The parameters of the algorithm - Settings settings; - /// A feasible point to start the algorithm - Point* interiorPoint; - /// True if we computed the interior point - bool computedInteriorPoint; - /// The diameter of the spectrahedron - NT diameter; - - SimulatedAnnealing() {} - - /// Construct and initialize an instance of this class - /// \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 - SimulatedAnnealing(SPECTRAHEDRON* spectrahedron, Point const & objectiveFunction, Settings const & settings, - Point* interiorPoint = nullptr) : spectrahedron(spectrahedron), settings(settings), - interiorPoint(interiorPoint) { - - // check if we must compute an interior point - if (interiorPoint != nullptr) - computedInteriorPoint = false; - else { - this->interiorPoint = new Point(spectrahedron->dimension()); - computedInteriorPoint = true; - } - - // the algorithm requires the objective function to be normalized - VT _objectiveFunction = objectiveFunction.getCoefficients(); - objectiveFunctionNorm = _objectiveFunction.norm(); - _objectiveFunction.normalize(); - this->objectiveFunction = Point(_objectiveFunction); - - // Estimate the diameter of the spectrahedron - // needed for the random walk - diameter = spectrahedron->estimateDiameter(20 + std::sqrt(spectrahedron->dimension()), *(this->interiorPoint)); - } - - - /// Initialize the hamiltonian monte carlo random walk - /// \param[out] hmcRandomWalk - /// \param[in] temperature - /// \tparam[in] dim the dimension of the spectrahedron - void initializeHMC(HMC& hmcRandomWalk, NT const temperature, const int dim) { -// unsigned seed = std::chrono::system_clock::now().time_since_epoch().count(); - RNGType rng(dim); - - typename HMC::Settings settings = typename HMC::Settings(this->settings.walkLength, rng, objectiveFunction, temperature, diameter); - hmcRandomWalk = HMC(settings); - } - - /// Solves the semidefinite program - /// \param[out] x The vector minimizing the objective function - /// \param[in] verbose True to print messages. Default is false - /// \return The best approximation to the optimal solution - NT solve(Point& x, bool verbose = false) { - // initialize - x = *interiorPoint; - NT currentMin = objectiveFunction.dot(x); - int stepsCount = 0; - NT temperature = diameter; - NT tempDecreaseFactor = 1.0 - static_cast(1.0 / std::pow(spectrahedron->dimension(), settings.k)); - - // initialize random walk; - HMC hmc; - initializeHMC(hmc, diameter, x.dimension()); - - // if settings.maxNumSteps is negative there is no - // bound to the number of steps - while (stepsCount < settings.maxNumSteps || settings.maxNumSteps < 0) { - - // sample one point with current temperature - std::list randPoints; - - typename HMC::PrecomputedValues hmcPrecomputesValues; - NT previous_min = objectiveFunction.dot(x); - - while (1) { - hmc.apply(*spectrahedron, x, settings.walkLength, randPoints, hmcPrecomputesValues); - - // if the sampled point is not inside the spectrahedron, - // get a new one - if (spectrahedron->isExterior(hmcPrecomputesValues.C)) { - if (verbose) std::cout << "Sampled point outside the spectrahedron.\n"; - randPoints.clear(); - hmcPrecomputesValues.resetFlags(); - } - else { - // update values; - x = randPoints.back(); - randPoints.clear(); - break; - } - } - - currentMin = objectiveFunction.dot(x); - ++stepsCount; - - // compute relative error - NT relError = relativeError(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; - hmc.setTemperature(temperature); - } - - // return the minimum w.r.t. the original objective function - return currentMin*objectiveFunctionNorm; - } - - /// Solves the semidefinite program. Stops when reaches a relative error < settings.error - /// or hits the maximum number of allowed steps - /// \param[out] x The vector minimizing the objective function - /// \param[in] verbose True to print messages - /// \param[in] The exact minimum of the problem - /// \return The best approximation to the optimal solution - NT solve(Point& x, bool verbose, const NT exact) { - // initialize - x = *interiorPoint; - NT currentMin = objectiveFunction.dot(x); - int stepsCount = 0; - NT temperature = diameter; - NT tempDecreaseFactor = 1.0 - static_cast(1.0 / std::pow(spectrahedron->dimension(), settings.k)); - - // initialize random walk; - HMC hmc; - initializeHMC(hmc, diameter, x.dimension()); - typename HMC::PrecomputedValues hmcPrecomputesValues; - - // if settings.maxNumSteps is negative there is no - // bound to the number of steps - while (stepsCount < settings.maxNumSteps || settings.maxNumSteps < 0) { - - // sample one point with current temperature - std::list randPoints; - - while (1) { - hmc.apply(*spectrahedron, x, settings.walkLength, randPoints, hmcPrecomputesValues); - - // if the sampled point is not inside the spectrahedron, - // get a new one - if (spectrahedron->isExterior(hmcPrecomputesValues.C)) { - if (verbose) std::cout << "Sampled point outside the spectrahedron.\n"; - randPoints.clear(); - hmcPrecomputesValues.resetFlags(); - } - else { - // update values; - x = randPoints.back(); - randPoints.clear(); - break; - } - } - - currentMin = objectiveFunction.dot(x); - ++stepsCount; - - // compute relative error - NT relError = relativeError(currentMin, exact); - - 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; - hmc.setTemperature(temperature); - } - - // return the minimum w.r.t. the original objective function - return currentMin*objectiveFunctionNorm; - } - - ~SimulatedAnnealing() { - // if we computed the interior point - if (computedInteriorPoint) delete interiorPoint; - } -}; -#endif //VOLESTI_SIMULATEDANNEALING_H diff --git a/test/SDP/CMakeLists.txt b/test/SDP/CMakeLists.txt index db703d0e1..f30a6c546 100644 --- a/test/SDP/CMakeLists.txt +++ b/test/SDP/CMakeLists.txt @@ -38,8 +38,8 @@ 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/convex_bodies/optimization) -include_directories (BEFORE ../../include/convex_bodies/matrices) +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) @@ -89,9 +89,15 @@ IF (OPENBLAS_LIB) IF (GFORTRAN_LIB) message( STATUS "GFORTRAN_LIB found: ${GFORTRAN_LIB}" ) + add_library(test_main OBJECT test_main.cpp) - add_executable (HMC HMC.cpp) - TARGET_LINK_LIBRARIES(HMC ${GFORTRAN_LIB} ${ARPACK_LIB} ${LAPACK_LIBRARIES}) + add_executable(test_solve_sdp test_solve_sdp.cpp $) + TARGET_LINK_LIBRARIES(test_solve_sdp ${GFORTRAN_LIB} ${ARPACK_LIB} ${LAPACK_LIBRARIES}) + add_test(NAME test_solve_sdp COMMAND test_solve_sdp -tc=test_solve_sdp) + + add_executable(test_spec_oracles test_spec_oracles.cpp $) + TARGET_LINK_LIBRARIES(test_spec_oracles ${GFORTRAN_LIB} ${ARPACK_LIB} ${LAPACK_LIBRARIES}) + add_test(NAME test_spec_oracles COMMAND test_spec_oracles -tc=test_spec_oracles) ELSE() MESSAGE(STATUS "gfortran is required but it could not be found") diff --git a/test/SDP/HMC.cpp b/test/SDP/HMC.cpp deleted file mode 100644 index a01cdc4d3..000000000 --- a/test/SDP/HMC.cpp +++ /dev/null @@ -1,93 +0,0 @@ -// -// Created by panagiotis on 2/24/20. -// - -#include "Eigen/Eigen" -#define VOLESTI_DEBUG -#include -#include "random.hpp" -#include "random/uniform_int.hpp" -#include "random/normal_distribution.hpp" -#include "random/uniform_real_distribution.hpp" -//#include "volume.h" -//#include "rotating.h" -#include "misc.h" -#include "linear_extensions.h" -//#include "cooling_balls.h" -//#include "cooling_hpoly.h" -//#include "sample_only.h" -#include -#include "cartesian_geom/cartesian_kernel.h" -#include "matrices/EigenvaluesProblems.h" -#include "spectrahedron.h" -#include "LMI.h" -#include "matrices/EigenDenseMatrix.h" -#include "matrices/DenseProductMatrix.h" -#include "random_walks/HMC_RandomWalk.h" -#include "optimization/SDPA_FormatManager.h" -#include "random_walks/CoordinateDirectionsHitAndRun_RandomWalk.h" -#include "optimization/SimulatedAnnealing.h" - - -int main(int argc, char* argv[]) { - - - typedef double NT; - typedef Eigen::Matrix VT; - typedef Eigen::Matrix MT; - typedef Cartesian Kernel; - typedef typename Kernel::Point Point; - typedef boost::mt19937 RNGType; - typedef Spectrahedron SPECTRAHEDRON; - typedef HMC_RandomWalk HMC_RandomWalk; - typedef SimulatedAnnealing SA; - - std::ifstream inp; - inp.open(argv[1],std::ifstream::in); - LMI lmi; - VT c; - loadSDPAFormatFile(inp, lmi, c); - - unsigned seed = std::chrono::system_clock::now().time_since_epoch().count(); - - SPECTRAHEDRON spectrahedron(lmi); - lmi.print(); -#ifdef SAMPLING - unsigned int n = spectrahedron.dimension(); - - RNGType rng(seed); - - int walkL=1, NN=30; - NT T=0.1, diam=1; - -// SP.ComputeInnerBall(diam, radius); - - std::list randPoints; - - Point _c(c); - HMC_RandomWalk::Settings settings(walkL, rng, _c, T, diam); - HMC_RandomWalk hmc(settings); - Point p(n); - hmc.sample(spectrahedron, p, NN, randPoints); - - - MT RetMat(n, NN); - unsigned int jj = 0; - - for (typename std::list::iterator rpit = randPoints.begin(); rpit!=randPoints.end(); rpit++, jj++) - RetMat.col(jj) = (*rpit).getCoefficients(); - -// std::cout << RetMat; - std::cout << "\n\n\n" << RetMat.transpose() * c << "\n"; - -#endif - - SA::Settings settings(0.001, 1,25,0.25); - SA simulatedAnnealing(&spectrahedron, Point(c), settings); - - Point x; - NT min = simulatedAnnealing.solve(x,true,-0.97226); - - std::cout << min << "\n";// << x.getCoefficients().transpose() << "\n"; - return 0; -} \ 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..be9792662 --- /dev/null +++ b/test/SDP/test_solve_sdp.cpp @@ -0,0 +1,74 @@ +// 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 "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..ae83391bb --- /dev/null +++ b/test/SDP/test_spec_oracles.cpp @@ -0,0 +1,121 @@ +// 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 "vector" +#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 +} + From e31f61bb27fc9ef2e96d543422c5153210352582 Mon Sep 17 00:00:00 2001 From: Repouskos Panagiotis Date: Fri, 10 Jul 2020 10:42:19 +0300 Subject: [PATCH 24/38] fix README.mde compilation instructions --- examples/spectrahedra/README.md | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/examples/spectrahedra/README.md b/examples/spectrahedra/README.md index f0808a652..4ae04ac74 100644 --- a/examples/spectrahedra/README.md +++ b/examples/spectrahedra/README.md @@ -54,11 +54,7 @@ It has two scripts that should easily install the libraries: ./install-arpack-ng.sh ``` -And copy the folder external back in folder examples: - -```bash - cp -r external ../ -``` +And copy the folder external back in folder examples/spectrahedra:
From ae172c9ad3f99548f6f1923f35dbc7773b95c461 Mon Sep 17 00:00:00 2001 From: Repouskos Panagiotis Date: Fri, 10 Jul 2020 11:12:07 +0300 Subject: [PATCH 25/38] fix README.md --- examples/spectrahedra/README.md | 20 +------------------- 1 file changed, 1 insertion(+), 19 deletions(-) diff --git a/examples/spectrahedra/README.md b/examples/spectrahedra/README.md index a323a4549..f46a5f87b 100644 --- a/examples/spectrahedra/README.md +++ b/examples/spectrahedra/README.md @@ -1,6 +1,5 @@ # Examples for Spectrahedra -<<<<<<< HEAD ## Table of contents 1. [Compilation](#compilation) 1. [Dependencies](#dependencies) @@ -10,8 +9,6 @@ 3. [Randomized SDP Solver - solve_sdp.cpp](#randomized-sdp-solver---solve_sdpcpp) -======= ->>>>>>> af41b5b11bf8aacb6e23bc86082b43305de17194 ## Compilation In folder examples, first run cmake, to create the makefile: @@ -25,7 +22,6 @@ Then, in folder examples/spectrahedra compile using the makefile: make ``` -<<<<<<< HEAD ### 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. @@ -64,23 +60,12 @@ And copy the folder external back in folder examples/spectrahedra: ## Examples ### Read/write SDPA format files - read_write_sdpa_file.cpp -======= -## List of examples -- Example 1: Read/write SDPA format files - -## Examples -### Example 1: Read/write SDPA format files ->>>>>>> af41b5b11bf8aacb6e23bc86082b43305de17194 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 -<<<<<<< HEAD ./read_write_sdpa_file -======= -./readWriteSdpaFile ->>>>>>> af41b5b11bf8aacb6e23bc86082b43305de17194 ``` The input file is data/sdp_n2m3.txt. It contains a semidefinite program in SDPA format. A semidefinite program @@ -119,7 +104,6 @@ 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 -<<<<<<< HEAD - and so on, till all 3 matrices are defined @@ -200,6 +184,4 @@ NT min = solve_sdp(spectrahedron, objFunction, settings, initialPoint, sol ,verb - min: The estimated minimum value - sol: At which point in the spectrahedron (returned by the solver) - verbose: If true, print useful information. -======= -- and so on, till all 3 matrices are defined ->>>>>>> af41b5b11bf8aacb6e23bc86082b43305de17194 + From f37902067da34adc9e363afde6a854afc6e5916a Mon Sep 17 00:00:00 2001 From: Repouskos Panagiotis Date: Sun, 12 Jul 2020 21:14:07 +0300 Subject: [PATCH 26/38] fix include --- examples/spectrahedra/boltzmann_hmc_walk.cpp | 1 + examples/spectrahedra/readWriteSdpaFile.cpp | 1 + examples/spectrahedra/read_write_sdpa_file.cpp | 1 + examples/spectrahedra/solve_sdp.cpp | 1 + test/SDP/README.md | 0 test/SDP/test_solve_sdp.cpp | 1 + test/SDP/test_spec_oracles.cpp | 3 ++- 7 files changed, 7 insertions(+), 1 deletion(-) create mode 100644 test/SDP/README.md diff --git a/examples/spectrahedra/boltzmann_hmc_walk.cpp b/examples/spectrahedra/boltzmann_hmc_walk.cpp index eebb2b46f..7ee263d33 100644 --- a/examples/spectrahedra/boltzmann_hmc_walk.cpp +++ b/examples/spectrahedra/boltzmann_hmc_walk.cpp @@ -16,6 +16,7 @@ #include #include +#include "random.hpp" #include "Eigen/Eigen" #include "cartesian_geom/cartesian_kernel.h" #include "convex_bodies/spectrahedra/spectrahedron.h" 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 index 6494d090f..2f103b6de 100644 --- a/examples/spectrahedra/read_write_sdpa_file.cpp +++ b/examples/spectrahedra/read_write_sdpa_file.cpp @@ -15,6 +15,7 @@ #include #include +#include "random.hpp" #include "Eigen/Eigen" #include "cartesian_geom/cartesian_kernel.h" #include "convex_bodies/spectrahedra/spectrahedron.h" diff --git a/examples/spectrahedra/solve_sdp.cpp b/examples/spectrahedra/solve_sdp.cpp index 297903791..590c64115 100644 --- a/examples/spectrahedra/solve_sdp.cpp +++ b/examples/spectrahedra/solve_sdp.cpp @@ -15,6 +15,7 @@ #include #include +#include "random.hpp" #include "Eigen/Eigen" #include "cartesian_geom/cartesian_kernel.h" #include "convex_bodies/spectrahedra/spectrahedron.h" diff --git a/test/SDP/README.md b/test/SDP/README.md new file mode 100644 index 000000000..e69de29bb diff --git a/test/SDP/test_solve_sdp.cpp b/test/SDP/test_solve_sdp.cpp index be9792662..fcf99dc70 100644 --- a/test/SDP/test_solve_sdp.cpp +++ b/test/SDP/test_solve_sdp.cpp @@ -11,6 +11,7 @@ #include #include +#include "random.hpp" #include "Eigen/Eigen" #include "cartesian_geom/cartesian_kernel.h" #include "convex_bodies/spectrahedra/spectrahedron.h" diff --git a/test/SDP/test_spec_oracles.cpp b/test/SDP/test_spec_oracles.cpp index ae83391bb..a00a6283a 100644 --- a/test/SDP/test_spec_oracles.cpp +++ b/test/SDP/test_spec_oracles.cpp @@ -9,7 +9,8 @@ #include "doctest.h" #include "Eigen/Eigen" -#include "vector" +#include +#include "random.hpp" #include "cartesian_geom/cartesian_kernel.h" #include "spectrahedron.h" From 4f35d5459ec19d12fd6b4d2e6e37c36d137c89d6 Mon Sep 17 00:00:00 2001 From: Repouskos Panagiotis Date: Sun, 12 Jul 2020 21:21:42 +0300 Subject: [PATCH 27/38] fix errors from previous merge Accept everything as was in upstream/develop --- R-proj/NAMESPACE | 7 ++- R-proj/R/RcppExports.R | 139 ++++++++++++++++++++++++++--------------- R-proj/src/Makevars | 4 +- 3 files changed, 96 insertions(+), 54 deletions(-) diff --git a/R-proj/NAMESPACE b/R-proj/NAMESPACE index ee585568c..06f96782a 100644 --- a/R-proj/NAMESPACE +++ b/R-proj/NAMESPACE @@ -15,15 +15,18 @@ export(gen_rand_zonotope) export(gen_simplex) export(gen_skinny_cube) export(inner_ball) +export(loadSdpaFormatFile) +export(readSdpaFormatFile) export(rotate_polytope) export(round_polytope) export(sample_points) export(volume) +export(writeSdpaFormatFile) export(zonotope_approximation) exportPattern("^[[:alpha:]]+") importFrom("methods","new") -importFrom("stats", "cov") +importFrom("stats","cov") importFrom("utils","read.csv") importFrom(Rcpp,evalCpp) importFrom(Rcpp,loadModule) -useDynLib(volesti, .registration=TRUE) +useDynLib(volesti, .registration=TRUE) \ No newline at end of file diff --git a/R-proj/R/RcppExports.R b/R-proj/R/RcppExports.R index 1362b3ecc..43fb8ac72 100644 --- a/R-proj/R/RcppExports.R +++ b/R-proj/R/RcppExports.R @@ -3,10 +3,11 @@ #' Construct a copula using uniform sampling from the unit simplex #' -#' Given two families of parallel hyperplanes or a family of parallel hyperplanes and a family of concentric ellispoids centered at the origin intersecting the canonical simplex, this function uniformly samples from the canonical simplex and construct an approximation of the bivariate probability distribution, called copula. +#' Given two families of parallel hyperplanes or a family of parallel hyperplanes and a family of concentric ellispoids centered at the origin intersecting the canonical simplex, this function uniformly samples from the canonical simplex and construct an approximation of the bivariate probability distribution, called copula (see \url{https://en.wikipedia.org/wiki/Copula_(probability_theory)}). +#' At least two families of hyperplanes or one family of hyperplanes and one family of ellipsoids have to be given as input. #' -#' @param r1 A \eqn{d}-dimensional vector that describes the direction of the first family of parallel hyperplanes. -#' @param r2 Optional. A \eqn{d}-dimensional vector that describes the direction of the second family of parallel hyperplanes. +#' @param r1 The \eqn{d}-dimensional normal vector of the first family of parallel hyperplanes. +#' @param r2 Optional. The \eqn{d}-dimensional normal vector of the second family of parallel hyperplanes. #' @param sigma Optional. The \eqn{d\times d} symmetric positive semidefine matrix that describes the family of concentric ellipsoids centered at the origin. #' @param m The number of the slices for the copula. The default value is 100. #' @param n The number of points to sample. The default value is \eqn{5\cdot 10^5}. @@ -15,7 +16,7 @@ #' @references \cite{L. Cales, A. Chalkis, I.Z. Emiris, V. Fisikopoulos, #' \dQuote{Practical volume computation of structured convex bodies, and an application to modeling portfolio dependencies and financial crises,} \emph{Proc. of Symposium on Computational Geometry, Budapest, Hungary,} 2018.} #' -#' @return A \eqn{numSlices\times numSlices} numerical matrix that corresponds to a copula. +#' @return A \eqn{m\times m} numerical matrix that corresponds to a copula. #' @examples #' # compute a copula for two random families of parallel hyperplanes #' h1 = runif(n = 10, min = 1, max = 1000) @@ -32,7 +33,7 @@ #' cop = copula(r1 = h, sigma = E, m = 10, n = 100000) #' #' @export -copula <- function(r1 = NULL, r2 = NULL, sigma = NULL, m = NULL, n = NULL, seed = NULL) { +copula <- function(r1, r2 = NULL, sigma = NULL, m = NULL, n = NULL, seed = NULL) { .Call(`_volesti_copula`, r1, r2, sigma, m, n, seed) } @@ -59,7 +60,7 @@ copula <- function(r1 = NULL, r2 = NULL, sigma = NULL, m = NULL, n = NULL, seed #' # 100 uniform points from the 2-d unit ball #' points = direct_sampling(n = 100, body = list("type" = "ball", "dimension" = 2)) #' @export -direct_sampling <- function(body = NULL, n = NULL, seed = NULL) { +direct_sampling <- function(body, n, seed = NULL) { .Call(`_volesti_direct_sampling`, body, n, seed) } @@ -70,11 +71,14 @@ direct_sampling <- function(body = NULL, n = NULL, seed = NULL) { #' #' @param P A polytope #' +#' @references \cite{E. Gover and N. Krikorian, +#' \dQuote{Determinants and the Volumes of Parallelotopes and Zonotopes,} \emph{Linear Algebra and its Applications, 433(1), 28 - 40,} 2010.} +#' #' @return The exact volume of the input polytope, for zonotopes, simplices in V-representation and polytopes with known exact volume #' @examples #' #' # compute the exact volume of a 5-dimensional zonotope defined by the Minkowski sum of 10 segments -#' Z = gen_rand_zonotope(5, 10) +#' Z = gen_rand_zonotope(2, 5) #' vol = exact_vol(Z) #' #' \donttest{# compute the exact volume of a 2-d arbitrary simplex @@ -91,9 +95,9 @@ exact_vol <- function(P) { .Call(`_volesti_exact_vol`, P) } -#' Compute the percentage of the volume of the unit simplex that is contained in the intersection of a half-space and the unit simplex. +#' Compute the percentage of the volume of the simplex that is contained in the intersection of a half-space and the simplex. #' -#' A half-space \eqn{H} is given as a pair of a vector \eqn{a\in R^d} and a scalar \eqn{z0\in R} s.t.: \eqn{a^Tx\leq z0}. This function calls the Ali's version of the Varsi formula to compute a frustum of the unit simplex. +#' A half-space \eqn{H} is given as a pair of a vector \eqn{a\in R^d} and a scalar \eqn{z0\in R} s.t.: \eqn{a^Tx\leq z0}. This function calls the Ali's version of the Varsi formula to compute a frustum of the simplex. #' #' @param a A \eqn{d}-dimensional vector that defines the direction of the hyperplane. #' @param z0 The scalar that defines the half-space. @@ -104,7 +108,7 @@ exact_vol <- function(P) { #' @references \cite{Ali, Mir M., #' \dQuote{Content of the frustum of a simplex,} \emph{ Pacific J. Math. 48, no. 2, 313--322,} 1973.} #' -#' @return The percentage of the volume of the unit simplex that is contained in the intersection of a given half-space and the unit simplex. +#' @return The percentage of the volume of the simplex that is contained in the intersection of a given half-space and the simplex. #' #' @examples #' # compute the frustum of H: -x1+x2<=0 @@ -118,13 +122,12 @@ frustum_of_simplex <- function(a, z0) { #' Compute an inscribed ball of a convex polytope #' -#' For a H-polytope described by a \eqn{m\times d} matrix \eqn{A} and a \eqn{m}-dimensional vector \eqn{b}, s.t.: \eqn{Ax\leq b}, this function computes the largest inscribed ball (Chebychev ball) by solving the corresponding linear program. -#' For a V-polytope \eqn{d+1} vertices, that define a full dimensional simplex, picked at random and the largest inscribed ball of the simplex is computed. -#' For a zonotope \eqn{P} we compute the minimum \eqn{r} s.t.: \eqn{ r e_i \in P} for all \eqn{i=1, \dots ,d}. Then the ball centered at the origin with radius \eqn{r/ \sqrt{d}} is an inscribed ball. +#' For a H-polytope described by a \eqn{m\times d} matrix \eqn{A} and a \eqn{m}-dimensional vector \eqn{b}, s.t.: \eqn{P=\{x\ |\ Ax\leq b\} }, this function computes the largest inscribed ball (Chebychev ball) by solving the corresponding linear program. +#' For both zonotopes and V-polytopes the function computes the minimum \eqn{r} s.t.: \eqn{ r e_i \in P} for all \eqn{i=1, \dots ,d}. Then the ball centered at the origin with radius \eqn{r/ \sqrt{d}} is an inscribed ball. #' -#' @param P A convex polytope. It is an object from class (a) Hpolytope or (b) Vpolytope or (c) Zonotope. +#' @param P A convex polytope. It is an object from class (a) Hpolytope or (b) Vpolytope or (c) Zonotope or (d) VpolytopeIntersection. #' -#' @return A \eqn{d+1}-dimensional vector that describes the inscribed ball. The first \eqn{d} coordinates corresponds to the center of the ball and the last one to the radius. +#' @return A \eqn{(d+1)}-dimensional vector that describes the inscribed ball. The first \eqn{d} coordinates corresponds to the center of the ball and the last one to the radius. #' #' @examples #' # compute the Chebychev ball of the 2d unit simplex @@ -148,8 +151,7 @@ inner_ball <- function(P) { #' @param m_gen An integer to declare the number of generators for the requested random zonotope or the number of vertices for a V-polytope. #' @param seed Optional. A fixed seed for the random polytope generator. #' -#' @section warning: -#' Do not use this function. +#' @keywords internal #' #' @return A numerical matrix describing the requested polytope poly_gen <- function(kind_gen, Vpoly_gen, Zono_gen, dim_gen, m_gen, seed = NULL) { @@ -162,8 +164,7 @@ poly_gen <- function(kind_gen, Vpoly_gen, Zono_gen, dim_gen, m_gen, seed = NULL) #' @param T Optional. A rotation matrix. #' @param seed Optional. A fixed seed for the random linear map generator. #' -#' @section warning: -#' Do not use this function. +#' @keywords internal #' #' @return A matrix that describes the rotated polytope rotating <- function(P, T = NULL, seed = NULL) { @@ -175,41 +176,40 @@ rotating <- function(P, T = NULL, seed = NULL) { #' @param P A convex polytope (H- or V-representation or zonotope). #' @param seed Optional. A fixed seed for the number generator. #' -#' @section warning: -#' Do not use this function. +#' @keywords internal #' -#' @return A numerical matrix that describes the rounded polytope and contains the round value. +#' @return A numerical matrix that describes the rounded polytope, a numerical matrix of the inverse linear transofmation that is applied on the input polytope, the numerical vector the the input polytope is shifted and the determinant of the matrix of the linear transformation that is applied on the input polytope. rounding <- function(P, seed = NULL) { .Call(`_volesti_rounding`, P, seed) } -#' Sample uniformly or normally distributed points from a convex Polytope (H-polytope, V-polytope or a zonotope). +#' Sample uniformly or normally distributed points from a convex Polytope (H-polytope, V-polytope, zonotope or intersection of two V-polytopes). #' -#' Sample n points with uniform or multidimensional spherical gaussian -with a mode at any point- target distribution. +#' Sample n points with uniform or multidimensional spherical gaussian -with a mode at any point- as the target distribution. #' -#' @param P A convex polytope. It is an object from class (a) Hpolytope or (b) Vpolytope or (c) Zonotope or (d) an intersection of two V-polytopes. +#' @param P A convex polytope. It is an object from class (a) Hpolytope or (b) Vpolytope or (c) Zonotope or (d) VpolytopeIntersection. #' @param n The number of points that the function is going to sample from the convex polytope. #' @param random_walk Optional. A list that declares the random walk and some related parameters as follows: #' \itemize{ #' \item{\code{walk} }{ A string to declare the random walk: i) \code{'CDHR'} for Coordinate Directions Hit-and-Run, ii) \code{'RDHR'} for Random Directions Hit-and-Run, iii) \code{'BaW'} for Ball Walk, iv) \code{'BiW'} for Billiard walk, v) \code{'BCDHR'} boundary sampling by keeping the extreme points of CDHR or vi) \code{'BRDHR'} boundary sampling by keeping the extreme points of RDHR. The default walk is \code{'BiW'} for the uniform distribution or \code{'CDHR'} for the Gaussian distribution.} -#' \item{\code{walk_length} }{ The number of the steps for the random walk. The default value is \eqn{5} for \code{'BiW'} and \eqn{\lfloor 10 + d/10\rfloor} otherwise.} +#' \item{\code{walk_length} }{ The number of the steps per generated point for the random walk. The default value is \eqn{5} for \code{'BiW'} and \eqn{\lfloor 10 + d/10\rfloor} otherwise.} #' \item{\code{nburns} }{ The number of points to burn before start sampling.} -#' \item{\code{starting_point} }{ A \eqn{d}-dimensional numerical vector that declares a starting point in the interior of the polytope for the random walk. The default choice is the center of the Chebychev ball.} +#' \item{\code{starting_point} }{ A \eqn{d}-dimensional numerical vector that declares a starting point in the interior of the polytope for the random walk. The default choice is the center of the ball as that one computed by the function \code{inner_ball()}.} #' \item{\code{BaW_rad} }{ The radius for the ball walk.} #' \item{\code{L} }{ The maximum length of the billiard trajectory.} #' } #' @param distribution Optional. A list that declares the target density and some related parameters as follows: #' \itemize{ -#' \item{\code{density}}{A string: (a) \code{'uniform'} for the uniform distribution or b) \code{'gaussian'} for the multidimensional spherical distribution. The default target distribution is uniform.} +#' \item{\code{density} }{ A string: (a) \code{'uniform'} for the uniform distribution or b) \code{'gaussian'} for the multidimensional spherical distribution. The default target distribution is uniform.} #' \item{\code{variance} }{ The variance of the multidimensional spherical gaussian. The default value is 1.} -#' \item{\code{mode} }{ A \eqn{d}-dimensional numerical vector that declares the mode of the Gaussian distribution. The default choice is the center of the Chebychev ball.} +#' \item{\code{mode} }{ A \eqn{d}-dimensional numerical vector that declares the mode of the Gaussian distribution. The default choice is the center of the as that one computed by the function \code{inner_ball()}.} #' } #' @param seed Optional. A fixed seed for the number generator. #' #' @return A \eqn{d\times n} matrix that contains, column-wise, the sampled points from the convex polytope P. #' @examples -#' # uniform distribution from the 3d unit cube in V-representation using ball walk -#' P = gen_cube(3, 'V') +#' # uniform distribution from the 3d unit cube in H-representation using ball walk +#' P = gen_cube(3, 'H') #' points = sample_points(P, n = 100, random_walk = list("walk" = "BaW", "walk_length" = 5)) #' #' # gaussian distribution from the 2d unit simplex in H-representation with variance = 2 @@ -220,32 +220,68 @@ rounding <- function(P, seed = NULL) { #' #' # uniform points from the boundary of a 2-dimensional random H-polytope #' P = gen_rand_hpoly(2,20) -#' points = sample_points(P, n = 5000, random_walk = list("walk" = "BRDHR")) +#' points = sample_points(P, n = 100, random_walk = list("walk" = "BRDHR")) #' #' @export -sample_points <- function(P = NULL, n = NULL, random_walk = NULL, distribution = NULL, seed = NULL) { +sample_points <- function(P, n, random_walk = NULL, distribution = NULL, seed = NULL) { .Call(`_volesti_sample_points`, P, n, random_walk, distribution, seed) } -#' The main function for volume approximation of a convex Polytope (H-polytope, V-polytope or a zonotope) +#' Write a SDPA format file +#' +#' Outputs a spectrahedron (the matrices defining a linear matrix inequality) and a vector (the objective function) +#' to a SDPA format file. +#' +#' @param spectrahedron A spectrahedron in n dimensions; must be an object of class Spectrahedron +#' @param objectiveFunction A numerical vector of length n +#' @param outputFile Name of the output file +#' +#' @examples +#' A0 = matrix(c(-1,0,0,0,-2,1,0,1,-2), nrow=3, ncol=3, byrow = TRUE) +#' A1 = matrix(c(-1,0,0,0,0,1,0,1,0), nrow=3, ncol=3, byrow = TRUE) +#' A2 = matrix(c(0,0,-1,0,0,0,-1,0,0), nrow=3, ncol=3, byrow = TRUE) +#' lmi = list(A0, A1, A2) +#' S = Spectrahedron$new(lmi); +#' objFunction = c(1,1) +#' writeSdpaFormatFile(S, objFunction, "output.txt") +#' @export +writeSdpaFormatFile <- function(spectrahedron = NULL, objectiveFunction = NULL, outputFile = NULL) { + invisible(.Call(`_volesti_writeSdpaFormatFile`, spectrahedron, objectiveFunction, outputFile)) +} + +#' Read a SDPA format file +#' +#' @param inputFile Name of the input file #' -#' For the volume approximation can be used two algorithms. Either SequenceOfBalls or CoolingGaussian. A H-polytope with \eqn{m} facets is described by a \eqn{m\times d} matrix \eqn{A} and a \eqn{m}-dimensional vector \eqn{b}, s.t.: \eqn{Ax\leq b}. A V-polytope is defined as the convex hull of \eqn{m} \eqn{d}-dimensional points which correspond to the vertices of P. A zonotope is desrcibed by the Minkowski sum of \eqn{m} \eqn{d}-dimensional segments. +#' @return A list with two named items: an item "matrices" which is a list of the matrices and an vector "objFunction" #' -#' @param P A convex polytope. It is an object from class (a) Hpolytope or (b) Vpolytope or (c) Zonotope. +#' @examples +#' path = system.file('extdata', package = 'volesti') +#' l = loadSdpaFormatFile(paste0(path,'/sdpa_n2m3.txt')) +#' @export +loadSdpaFormatFile <- function(inputFile = NULL) { + .Call(`_volesti_loadSdpaFormatFile`, inputFile) +} + +#' The main function for volume approximation of a convex Polytope (H-polytope, V-polytope, zonotope or intersection of two V-polytopes) +#' +#' For the volume approximation can be used three algorithms. Either CoolingBodies (CB) or SequenceOfBalls (SOB) or CoolingGaussian (CG). An H-polytope with \eqn{m} facets is described by a \eqn{m\times d} matrix \eqn{A} and a \eqn{m}-dimensional vector \eqn{b}, s.t.: \eqn{P=\{x\ |\ Ax\leq b\} }. A V-polytope is defined as the convex hull of \eqn{m} \eqn{d}-dimensional points which correspond to the vertices of P. A zonotope is desrcibed by the Minkowski sum of \eqn{m} \eqn{d}-dimensional segments. +#' +#' @param P A convex polytope. It is an object from class a) Hpolytope or b) Vpolytope or c) Zonotope or d) VpolytopeIntersection. #' @param settings Optional. A list that declares which algorithm, random walk and values of parameters to use, as follows: #' \itemize{ -#' \item{\code{algorithm} }{ A string to set the algorithm to use: a) \code{'SoB'} for SequenceOfBalls or b) \code{'CG'} for CoolingGaussian or c) \code{'CB'} for cooling bodies. The defalut algorithm for H-polytopes is \code{'CB'} when \eqn{d\leq 200} and \code{'CG'} when \eqn{d>200}. For the other representations the default algorithm is \code{'CB'}.} -#' \item{\code{error} }{ A numeric value to set the upper bound for the approximation error. The default value is \eqn{1} for \code{'SOB'} and \eqn{0.1} otherwise.} -#' \item{\code{random_walk} }{ A string that declares the random walk method: a) \code{'CDHR'} for Coordinate Directions Hit-and-Run, b) \code{'RDHR'} for Random Directions Hit-and-Run, c) \code{'BaW'} for Ball Walk, or \code{'BiW'} for Billiard walk. The default walk is \code{'CDHR'} for H-polytopes and \code{'BiW'} for the other representations.} +#' \item{\code{algorithm} }{ A string to set the algorithm to use: a) \code{'CB'} for CB algorithm, b) \code{'SoB'} for SOB algorithm or b) \code{'CG'} for CG algorithm. The defalut algorithm for H-polytopes is \code{'CB'} when \eqn{d\leq 200} and \code{'CG'} when \eqn{d>200}. For the other representations the default algorithm is \code{'CB'}.} +#' \item{\code{error} }{ A numeric value to set the upper bound for the approximation error. The default value is \eqn{1} for SOB algorithm and \eqn{0.1} otherwise.} +#' \item{\code{random_walk} }{ A string that declares the random walk method: a) \code{'CDHR'} for Coordinate Directions Hit-and-Run, b) \code{'RDHR'} for Random Directions Hit-and-Run, c) \code{'BaW'} for Ball Walk, or \code{'BiW'} for Billiard walk. For CB and SOB algorithms the default walk is \code{'CDHR'} for H-polytopes and \code{'BiW'} for the other representations. For CG algorithm the default walk is \code{'CDHR'} for H-polytopes and \code{'RDHR'} for the other representations.} #' \item{\code{walk_length} }{ An integer to set the number of the steps for the random walk. The default value is \eqn{\lfloor 10 + d/10\rfloor} for \code{'SOB'} and \eqn{1} otherwise.} -#' \item{\code{win_len} }{ The length of the sliding window for CG algorithm. The default value is \eqn{500+4dimension^2}.} -#' \item{\code{hpoly} }{ A boolean parameter to use H-polytopes in MMC of CB algorithm. The default value is \code{FALSE}.} +#' \item{\code{win_len} }{ The length of the sliding window for CB or CG algorithm. The default value is \eqn{400+3d^2} for CB or \eqn{500+4d^2} for CG.} +#' \item{\code{hpoly} }{ A boolean parameter to use H-polytopes in MMC of CB algorithm when the input polytope is a zonotope. The default value is \code{TRUE} when the order of the zonotope is \eqn{<5}, otherwise it is \code{FALSE}.} #' } #' @param rounding Optional. A boolean parameter for rounding. The default value is \code{TRUE} for V-polytopes and \code{FALSE} otherwise. #' @param seed Optional. A fixed seed for the number generator. #' #' @references \cite{I.Z.Emiris and V. Fisikopoulos, -#' \dQuote{Practical polytope volume approximation,} \emph{ACM Trans. Math. Soft.,} 2014.}, +#' \dQuote{Practical polytope volume approximation,} \emph{ACM Trans. Math. Soft.,} 2018.}, #' @references \cite{A. Chalkis and I.Z.Emiris and V. Fisikopoulos, #' \dQuote{Practical Volume Estimation by a New Annealing Schedule for Cooling Convex Bodies,} \emph{CoRR, abs/1905.05494,} 2019.}, #' @references \cite{B. Cousins and S. Vempala, \dQuote{A practical volume algorithm,} \emph{Springer-Verlag Berlin Heidelberg and The Mathematical Programming Society,} 2015.} @@ -253,17 +289,19 @@ sample_points <- function(P = NULL, n = NULL, random_walk = NULL, distribution = #' #' @return The approximation of the volume of a convex polytope. #' @examples -#' # calling SOB algorithm for a H-polytope (2d unit simplex) -#' P = gen_simplex(2,'H') -#' vol = volume(P) #' -#' # calling CG algorithm for a V-polytope (3d simplex) -#' P = gen_simplex(2,'V') -#' vol = volume(P, settings = list("algorithm" = "CG")) +#' # calling SOB algorithm for a H-polytope (3d unit simplex) +#' HP = gen_cube(3,'H') +#' vol = volume(HP) +#' +#' # calling CG algorithm for a V-polytope (2d simplex) +#' VP = gen_simplex(2,'V') +#' vol = volume(VP, settings = list("algorithm" = "CG")) #' #' # calling CG algorithm for a 2-dimensional zonotope defined as the Minkowski sum of 4 segments #' Z = gen_rand_zonotope(2, 4) -#' vol = volume(Z, settings = list("random_walk" = "RDHR", "walk_length" = 5)) +#' vol = volume(Z, settings = list("random_walk" = "RDHR", "walk_length" = 2)) +#' #' @export volume <- function(P, settings = NULL, rounding = NULL, seed = NULL) { .Call(`_volesti_volume`, P, settings, rounding, seed) @@ -276,8 +314,7 @@ volume <- function(P, settings = NULL, rounding = NULL, seed = NULL) { #' @param settings Optional. A list that declares the values of the parameters of CB algorithm. #' @param seed Optional. A fixed seed for the number generator. #' -#' @section warning: -#' Do not use this function. +#' @keywords internal #' #' @return A List that contains a numerical matrix that describes the PCA approximation as a H-polytope and the ratio of fitness. zono_approx <- function(Z, fit_ratio = NULL, settings = NULL, seed = NULL) { diff --git a/R-proj/src/Makevars b/R-proj/src/Makevars index 1ef84c4f9..9525bd430 100644 --- a/R-proj/src/Makevars +++ b/R-proj/src/Makevars @@ -1,5 +1,7 @@ PKG_CPPFLAGS=-I../../external/boost -I../../external/LPsolve_src/run_headers -I../../external/minimum_ellipsoid -I../../include + PKG_CXXFLAGS= -lm -ldl -Wno-ignored-attributes -DBOOST_NO_AUTO_PTR + CXX_STD = CXX11 PKG_LIBS=-LRproj_externals/lp_solve -llp_solve $(LAPACK_LIBS) $(BLAS_LIBS) $(FLIBS) @@ -9,4 +11,4 @@ $(SHLIB): Rproj_externals/lp_solve/liblp_solve.a Rproj_externals/lp_solve/liblp_solve.a: @(cd Rproj_externals/lp_solve && $(MAKE) liblp_solve.a \ CC="$(CC)" CPPFLAGS="$(CPPFLAGS)" CFLAGS="$(CFLAGS)" \ - CPICFLAGS="$(CPICFLAGS)" AR="$(AR)" RANLIB="$(RANLIB)") + CPICFLAGS="$(CPICFLAGS)" AR="$(AR)" RANLIB="$(RANLIB)") \ No newline at end of file From d7b0c5da3a92a63e3723efb69bf0303bad750de6 Mon Sep 17 00:00:00 2001 From: Repouskos Panagiotis Date: Sun, 12 Jul 2020 21:22:51 +0300 Subject: [PATCH 28/38] newline in end of file --- R-proj/NAMESPACE | 2 +- R-proj/src/Makevars | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/R-proj/NAMESPACE b/R-proj/NAMESPACE index 06f96782a..481b67e4c 100644 --- a/R-proj/NAMESPACE +++ b/R-proj/NAMESPACE @@ -29,4 +29,4 @@ importFrom("stats","cov") importFrom("utils","read.csv") importFrom(Rcpp,evalCpp) importFrom(Rcpp,loadModule) -useDynLib(volesti, .registration=TRUE) \ No newline at end of file +useDynLib(volesti, .registration=TRUE) diff --git a/R-proj/src/Makevars b/R-proj/src/Makevars index 9525bd430..e68acd904 100644 --- a/R-proj/src/Makevars +++ b/R-proj/src/Makevars @@ -11,4 +11,4 @@ $(SHLIB): Rproj_externals/lp_solve/liblp_solve.a Rproj_externals/lp_solve/liblp_solve.a: @(cd Rproj_externals/lp_solve && $(MAKE) liblp_solve.a \ CC="$(CC)" CPPFLAGS="$(CPPFLAGS)" CFLAGS="$(CFLAGS)" \ - CPICFLAGS="$(CPICFLAGS)" AR="$(AR)" RANLIB="$(RANLIB)") \ No newline at end of file + CPICFLAGS="$(CPICFLAGS)" AR="$(AR)" RANLIB="$(RANLIB)") From aa9ed9cee6d5fa93aee36cee62a5ff64180fcea0 Mon Sep 17 00:00:00 2001 From: Repouskos Panagiotis Date: Sun, 12 Jul 2020 21:40:08 +0300 Subject: [PATCH 29/38] remove wrong #include causes error with R interface --- include/convex_bodies/spectrahedra/spectrahedron.h | 1 - 1 file changed, 1 deletion(-) diff --git a/include/convex_bodies/spectrahedra/spectrahedron.h b/include/convex_bodies/spectrahedra/spectrahedron.h index 127cfa851..807f9993c 100644 --- a/include/convex_bodies/spectrahedra/spectrahedron.h +++ b/include/convex_bodies/spectrahedra/spectrahedron.h @@ -12,7 +12,6 @@ #include "LMI.h" #include "chrono" -#include "random.hpp" /// This class manipulates a spectrahedron, described by a LMI From de2e3023d8fdaac98a37ecd833f89ff504713d33 Mon Sep 17 00:00:00 2001 From: Repouskos Panagiotis Date: Sun, 12 Jul 2020 21:56:46 +0300 Subject: [PATCH 30/38] add #include required by spectrahedron.h --- test/test_sdpa_format.cpp | 1 + 1 file changed, 1 insertion(+) 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" From 23964ed63c0b84f348ba6013d00f2e00c325be5e Mon Sep 17 00:00:00 2001 From: Repouskos Panagiotis Date: Tue, 14 Jul 2020 11:42:13 +0300 Subject: [PATCH 31/38] add \dontrun{} in R example --- R-proj/src/spectrahedron.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/R-proj/src/spectrahedron.cpp b/R-proj/src/spectrahedron.cpp index 9bc485b3d..5efe4914e 100644 --- a/R-proj/src/spectrahedron.cpp +++ b/R-proj/src/spectrahedron.cpp @@ -29,6 +29,7 @@ //' @param outputFile Name of the output file //' //' @examples +//'\dontrun{ //' A0 = matrix(c(-1,0,0,0,-2,1,0,1,-2), nrow=3, ncol=3, byrow = TRUE) //' A1 = matrix(c(-1,0,0,0,0,1,0,1,0), nrow=3, ncol=3, byrow = TRUE) //' A2 = matrix(c(0,0,-1,0,0,0,-1,0,0), nrow=3, ncol=3, byrow = TRUE) @@ -36,6 +37,7 @@ //' S = Spectrahedron$new(lmi); //' objFunction = c(1,1) //' writeSdpaFormatFile(S, objFunction, "output.txt") +//'} //' @export // [[Rcpp::export]] void writeSdpaFormatFile(Rcpp::Nullable spectrahedron = R_NilValue, From 1262a82a5767f2d54da0122a703fa2b1d036c6b5 Mon Sep 17 00:00:00 2001 From: Repouskos Panagiotis Date: Fri, 17 Jul 2020 12:55:43 +0300 Subject: [PATCH 32/38] try fix in cmakefiles --- test/SDP/CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/SDP/CMakeLists.txt b/test/SDP/CMakeLists.txt index f30a6c546..b626a57b5 100644 --- a/test/SDP/CMakeLists.txt +++ b/test/SDP/CMakeLists.txt @@ -92,12 +92,12 @@ IF (OPENBLAS_LIB) add_library(test_main OBJECT test_main.cpp) add_executable(test_solve_sdp test_solve_sdp.cpp $) - TARGET_LINK_LIBRARIES(test_solve_sdp ${GFORTRAN_LIB} ${ARPACK_LIB} ${LAPACK_LIBRARIES}) add_test(NAME test_solve_sdp COMMAND test_solve_sdp -tc=test_solve_sdp) + TARGET_LINK_LIBRARIES(test_solve_sdp ${GFORTRAN_LIB} ${ARPACK_LIB} ${LAPACK_LIBRARIES}) add_executable(test_spec_oracles test_spec_oracles.cpp $) - TARGET_LINK_LIBRARIES(test_spec_oracles ${GFORTRAN_LIB} ${ARPACK_LIB} ${LAPACK_LIBRARIES}) add_test(NAME test_spec_oracles COMMAND test_spec_oracles -tc=test_spec_oracles) + TARGET_LINK_LIBRARIES(test_spec_oracles ${GFORTRAN_LIB} ${ARPACK_LIB} ${LAPACK_LIBRARIES}) ELSE() MESSAGE(STATUS "gfortran is required but it could not be found") From c229897b5afe5c39d538688501c87f8c3f1e2157 Mon Sep 17 00:00:00 2001 From: Panagiotis Repouskos Date: Fri, 17 Jul 2020 19:07:53 +0300 Subject: [PATCH 33/38] Create testSDP.yml --- .github/workflows/testSDP.yml | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 .github/workflows/testSDP.yml 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; From 0b83d98fa225dec68e3ca1b98590ea411c54e3bd Mon Sep 17 00:00:00 2001 From: Repouskos Panagiotis Date: Fri, 17 Jul 2020 20:38:16 +0300 Subject: [PATCH 34/38] try fix in cmakefiles --- examples/spectrahedra/CMakeLists.txt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/examples/spectrahedra/CMakeLists.txt b/examples/spectrahedra/CMakeLists.txt index 0411a63f9..fdcad467c 100644 --- a/examples/spectrahedra/CMakeLists.txt +++ b/examples/spectrahedra/CMakeLists.txt @@ -26,12 +26,11 @@ IF (OPENBLAS_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_LIBRARY(GFORTRAN_LIB NAMES libgfortran PATHS /usr/lib/gcc/x86_64-linux-gnu/8/) 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 ${GFORTRAN_LIB} ${ARPACK_LIB} ${LAPACK_LIBRARIES}) From 8ea9c4dd776c0d926b4f0ead6244255115963e80 Mon Sep 17 00:00:00 2001 From: Repouskos Panagiotis Date: Fri, 17 Jul 2020 20:42:41 +0300 Subject: [PATCH 35/38] try fix in cmakefiles --- test/SDP/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/SDP/CMakeLists.txt b/test/SDP/CMakeLists.txt index b626a57b5..d8d8e67c6 100644 --- a/test/SDP/CMakeLists.txt +++ b/test/SDP/CMakeLists.txt @@ -84,7 +84,7 @@ IF (OPENBLAS_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_LIBRARY(GFORTRAN_LIB NAMES libgfortran PATHS /usr/lib/gcc/x86_64-linux-gnu/8/) IF (GFORTRAN_LIB) message( STATUS "GFORTRAN_LIB found: ${GFORTRAN_LIB}" ) From e6a4beea7d7082667df5e053a6e5bda8d39bd4f8 Mon Sep 17 00:00:00 2001 From: Repouskos Panagiotis Date: Fri, 17 Jul 2020 20:49:57 +0300 Subject: [PATCH 36/38] try fix in cmakefiles --- test/SDP/CMakeLists.txt | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/test/SDP/CMakeLists.txt b/test/SDP/CMakeLists.txt index d8d8e67c6..b944b458f 100644 --- a/test/SDP/CMakeLists.txt +++ b/test/SDP/CMakeLists.txt @@ -84,7 +84,29 @@ IF (OPENBLAS_LIB) message( STATUS "ARPACK_LIB found: ${ARPACK_LIB}" ) # Query gfortran to get the libgfortran path - FIND_LIBRARY(GFORTRAN_LIB NAMES libgfortran PATHS /usr/lib/gcc/x86_64-linux-gnu/8/) + #FIND_LIBRARY(GFORTRAN_LIB NAMES libgfortran 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}" ) From 38dc3d2ce153e87f527c522fb54fc9e3ebeba3a2 Mon Sep 17 00:00:00 2001 From: Repouskos Panagiotis Date: Fri, 17 Jul 2020 22:18:04 +0300 Subject: [PATCH 37/38] fix CMakeLists.txt and readne.md --- examples/spectrahedra/CMakeLists.txt | 28 +++++++++++++++++++++++++++- examples/spectrahedra/README.md | 12 ++++-------- test/SDP/README.md | 2 ++ 3 files changed, 33 insertions(+), 9 deletions(-) diff --git a/examples/spectrahedra/CMakeLists.txt b/examples/spectrahedra/CMakeLists.txt index fdcad467c..65be4c38c 100644 --- a/examples/spectrahedra/CMakeLists.txt +++ b/examples/spectrahedra/CMakeLists.txt @@ -26,7 +26,33 @@ IF (OPENBLAS_LIB) message( STATUS "ARPACK_LIB found: ${ARPACK_LIB}" ) # Query gfortran to get the libgfortran path - FIND_LIBRARY(GFORTRAN_LIB NAMES libgfortran PATHS /usr/lib/gcc/x86_64-linux-gnu/8/) + #FIND_LIBRARY(GFORTRAN_LIB NAMES libgfortran 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}" ) diff --git a/examples/spectrahedra/README.md b/examples/spectrahedra/README.md index f46a5f87b..eb9279ead 100644 --- a/examples/spectrahedra/README.md +++ b/examples/spectrahedra/README.md @@ -32,13 +32,6 @@ First we will need a [Fortran compiler](https://gcc.gnu.org/wiki/GFortran) for G sudo apt install gfortran ``` -You may have to edit the path in following line in examples/spectrahedra/CMakeLists.txt - -```bash -FIND_LIBRARY(GFORTRAN_LIB NAMES libgfortran.so PATHS /usr/lib/gcc/x86_64-linux-gnu/8/) -``` - -to point to your installation. Then we can install the openblas, lapack and arpack libraries (lapack is included in openblas). In the folder "examples", clone this repo: @@ -54,7 +47,10 @@ It has two scripts that should easily install the libraries: ./install-arpack-ng.sh ``` -And copy the folder external back in folder examples/spectrahedra: +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:
diff --git a/test/SDP/README.md b/test/SDP/README.md index e69de29bb..acf3b90c3 100644 --- a/test/SDP/README.md +++ 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 From fcab879123dfe0a2a119d37aee8899fa09899ac5 Mon Sep 17 00:00:00 2001 From: Tolis Chalkis Date: Thu, 24 Sep 2020 11:00:00 +0300 Subject: [PATCH 38/38] fix cmakelists (#2) --- examples/spectrahedra/CMakeLists.txt | 6 +++--- examples/spectrahedra/README.md | 2 ++ test/SDP/CMakeLists.txt | 6 +++--- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/examples/spectrahedra/CMakeLists.txt b/examples/spectrahedra/CMakeLists.txt index 65be4c38c..5fb52b24b 100644 --- a/examples/spectrahedra/CMakeLists.txt +++ b/examples/spectrahedra/CMakeLists.txt @@ -26,7 +26,7 @@ IF (OPENBLAS_LIB) message( STATUS "ARPACK_LIB found: ${ARPACK_LIB}" ) # Query gfortran to get the libgfortran path - #FIND_LIBRARY(GFORTRAN_LIB NAMES libgfortran PATHS /usr/lib/gcc/x86_64-linux-gnu/8/) + 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 @@ -58,10 +58,10 @@ IF (OPENBLAS_LIB) message( STATUS "GFORTRAN_LIB found: ${GFORTRAN_LIB}" ) add_executable (boltzmann_hmc_walk boltzmann_hmc_walk.cpp) - TARGET_LINK_LIBRARIES(boltzmann_hmc_walk ${GFORTRAN_LIB} ${ARPACK_LIB} ${LAPACK_LIBRARIES}) + TARGET_LINK_LIBRARIES(boltzmann_hmc_walk ${ARPACK_LIB} ${LAPACK_LIBRARIES} ${GFORTRAN_LIB}) add_executable (solve_sdp solve_sdp.cpp) - TARGET_LINK_LIBRARIES(solve_sdp ${GFORTRAN_LIB} ${ARPACK_LIB} ${LAPACK_LIBRARIES}) + TARGET_LINK_LIBRARIES(solve_sdp ${ARPACK_LIB} ${LAPACK_LIBRARIES} ${GFORTRAN_LIB}) ELSE() MESSAGE(STATUS "gfortran is required but it could not be found") diff --git a/examples/spectrahedra/README.md b/examples/spectrahedra/README.md index eb9279ead..014f5de89 100644 --- a/examples/spectrahedra/README.md +++ b/examples/spectrahedra/README.md @@ -32,6 +32,8 @@ First we will need a [Fortran compiler](https://gcc.gnu.org/wiki/GFortran) for G 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: diff --git a/test/SDP/CMakeLists.txt b/test/SDP/CMakeLists.txt index b944b458f..87f4f0d9e 100644 --- a/test/SDP/CMakeLists.txt +++ b/test/SDP/CMakeLists.txt @@ -84,7 +84,7 @@ IF (OPENBLAS_LIB) message( STATUS "ARPACK_LIB found: ${ARPACK_LIB}" ) # Query gfortran to get the libgfortran path - #FIND_LIBRARY(GFORTRAN_LIB NAMES libgfortran PATHS /usr/lib/gcc/x86_64-linux-gnu/8/) + 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 @@ -115,11 +115,11 @@ IF (OPENBLAS_LIB) 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 ${GFORTRAN_LIB} ${ARPACK_LIB} ${LAPACK_LIBRARIES}) + 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 ${GFORTRAN_LIB} ${ARPACK_LIB} ${LAPACK_LIBRARIES}) + TARGET_LINK_LIBRARIES(test_spec_oracles ${ARPACK_LIB} ${LAPACK_LIBRARIES} ${GFORTRAN_LIB}) ELSE() MESSAGE(STATUS "gfortran is required but it could not be found")