Add Spectra.
This commit is contained in:
36
thirdparty/include/Spectra/Util/CompInfo.h
vendored
Normal file
36
thirdparty/include/Spectra/Util/CompInfo.h
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
// Copyright (C) 2016-2022 Yixuan Qiu <yixuan.qiu@cos.name>
|
||||
//
|
||||
// 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 SPECTRA_COMP_INFO_H
|
||||
#define SPECTRA_COMP_INFO_H
|
||||
|
||||
namespace Spectra {
|
||||
|
||||
///
|
||||
/// \ingroup Enumerations
|
||||
///
|
||||
/// The enumeration to report the status of computation.
|
||||
///
|
||||
enum class CompInfo
|
||||
{
|
||||
Successful, ///< Computation was successful.
|
||||
|
||||
NotComputed, ///< Used in eigen solvers, indicating that computation
|
||||
///< has not been conducted. Users should call
|
||||
///< the `compute()` member function of solvers.
|
||||
|
||||
NotConverging, ///< Used in eigen solvers, indicating that some eigenvalues
|
||||
///< did not converge. The `compute()`
|
||||
///< function returns the number of converged eigenvalues.
|
||||
|
||||
NumericalIssue ///< Used in various matrix factorization classes, for example in
|
||||
///< Cholesky decomposition it indicates that the
|
||||
///< matrix is not positive definite.
|
||||
};
|
||||
|
||||
} // namespace Spectra
|
||||
|
||||
#endif // SPECTRA_COMP_INFO_H
|
||||
28
thirdparty/include/Spectra/Util/GEigsMode.h
vendored
Normal file
28
thirdparty/include/Spectra/Util/GEigsMode.h
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
// Copyright (C) 2016-2022 Yixuan Qiu <yixuan.qiu@cos.name>
|
||||
//
|
||||
// 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 SPECTRA_GEIGS_MODE_H
|
||||
#define SPECTRA_GEIGS_MODE_H
|
||||
|
||||
namespace Spectra {
|
||||
|
||||
///
|
||||
/// \ingroup Enumerations
|
||||
///
|
||||
/// The enumeration to specify the mode of generalized eigenvalue solver.
|
||||
///
|
||||
enum class GEigsMode
|
||||
{
|
||||
Cholesky, ///< Using Cholesky decomposition to solve generalized eigenvalues.
|
||||
RegularInverse, ///< Regular inverse mode for generalized eigenvalue solver.
|
||||
ShiftInvert, ///< Shift-and-invert mode for generalized eigenvalue solver.
|
||||
Buckling, ///< Buckling mode for generalized eigenvalue solver.
|
||||
Cayley ///< Cayley transformation mode for generalized eigenvalue solver.
|
||||
};
|
||||
|
||||
} // namespace Spectra
|
||||
|
||||
#endif // SPECTRA_GEIGS_MODE_H
|
||||
300
thirdparty/include/Spectra/Util/SelectionRule.h
vendored
Normal file
300
thirdparty/include/Spectra/Util/SelectionRule.h
vendored
Normal file
@@ -0,0 +1,300 @@
|
||||
// Copyright (C) 2016-2022 Yixuan Qiu <yixuan.qiu@cos.name>
|
||||
//
|
||||
// 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 SPECTRA_SELECTION_RULE_H
|
||||
#define SPECTRA_SELECTION_RULE_H
|
||||
|
||||
#include <vector> // std::vector
|
||||
#include <cmath> // std::abs
|
||||
#include <algorithm> // std::sort
|
||||
#include <complex> // std::complex
|
||||
#include <utility> // std::pair
|
||||
#include <stdexcept> // std::invalid_argument
|
||||
|
||||
#include <Eigen/Core>
|
||||
#include "TypeTraits.h"
|
||||
|
||||
namespace Spectra {
|
||||
|
||||
///
|
||||
/// \defgroup Enumerations Enumerations
|
||||
///
|
||||
/// Enumeration types for the selection rule of eigenvalues.
|
||||
///
|
||||
|
||||
///
|
||||
/// \ingroup Enumerations
|
||||
///
|
||||
/// The enumeration of selection rules of desired eigenvalues.
|
||||
///
|
||||
enum class SortRule
|
||||
{
|
||||
LargestMagn, ///< 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.
|
||||
|
||||
LargestReal, ///< Select eigenvalues with largest real part. Only for general eigen solvers.
|
||||
|
||||
LargestImag, ///< Select eigenvalues with largest imaginary part (in magnitude). Only for general eigen solvers.
|
||||
|
||||
LargestAlge, ///< Select eigenvalues with largest algebraic value, considering
|
||||
///< any negative sign. Only for symmetric eigen solvers.
|
||||
|
||||
SmallestMagn, ///< Select eigenvalues with smallest magnitude. Applies to both symmetric and general
|
||||
///< eigen solvers.
|
||||
|
||||
SmallestReal, ///< Select eigenvalues with smallest real part. Only for general eigen solvers.
|
||||
|
||||
SmallestImag, ///< Select eigenvalues with smallest imaginary part (in magnitude). Only for general eigen solvers.
|
||||
|
||||
SmallestAlge, ///< Select eigenvalues with smallest algebraic value. Only for symmetric eigen solvers.
|
||||
|
||||
BothEnds ///< Select eigenvalues half from each end of the spectrum. When
|
||||
///< `nev` is odd, compute more from the high end. Only for symmetric eigen solvers.
|
||||
};
|
||||
|
||||
/// \cond
|
||||
|
||||
// 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 <typename Scalar, SortRule Rule>
|
||||
class SortingTarget
|
||||
{
|
||||
public:
|
||||
static ElemType<Scalar> get(const Scalar& val)
|
||||
{
|
||||
using std::abs;
|
||||
throw std::invalid_argument("incompatible selection rule");
|
||||
return -abs(val);
|
||||
}
|
||||
};
|
||||
|
||||
// Specialization for SortRule::LargestMagn
|
||||
// This covers [float, double, complex] x [SortRule::LargestMagn]
|
||||
template <typename Scalar>
|
||||
class SortingTarget<Scalar, SortRule::LargestMagn>
|
||||
{
|
||||
public:
|
||||
static ElemType<Scalar> get(const Scalar& val)
|
||||
{
|
||||
using std::abs;
|
||||
return -abs(val);
|
||||
}
|
||||
};
|
||||
|
||||
// Specialization for SortRule::LargestReal
|
||||
// This covers [complex] x [SortRule::LargestReal]
|
||||
template <typename RealType>
|
||||
class SortingTarget<std::complex<RealType>, SortRule::LargestReal>
|
||||
{
|
||||
public:
|
||||
static RealType get(const std::complex<RealType>& val)
|
||||
{
|
||||
return -val.real();
|
||||
}
|
||||
};
|
||||
|
||||
// Specialization for SortRule::LargestImag
|
||||
// This covers [complex] x [SortRule::LargestImag]
|
||||
template <typename RealType>
|
||||
class SortingTarget<std::complex<RealType>, SortRule::LargestImag>
|
||||
{
|
||||
public:
|
||||
static RealType get(const std::complex<RealType>& val)
|
||||
{
|
||||
using std::abs;
|
||||
return -abs(val.imag());
|
||||
}
|
||||
};
|
||||
|
||||
// Specialization for SortRule::LargestAlge
|
||||
// This covers [float, double] x [SortRule::LargestAlge]
|
||||
template <typename Scalar>
|
||||
class SortingTarget<Scalar, SortRule::LargestAlge>
|
||||
{
|
||||
public:
|
||||
static Scalar get(const Scalar& val)
|
||||
{
|
||||
return -val;
|
||||
}
|
||||
};
|
||||
|
||||
// Here SortRule::BothEnds is the same as SortRule::LargestAlge, 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 <typename Scalar>
|
||||
class SortingTarget<Scalar, SortRule::BothEnds>
|
||||
{
|
||||
public:
|
||||
static Scalar get(const Scalar& val)
|
||||
{
|
||||
return -val;
|
||||
}
|
||||
};
|
||||
|
||||
// Specialization for SortRule::SmallestMagn
|
||||
// This covers [float, double, complex] x [SortRule::SmallestMagn]
|
||||
template <typename Scalar>
|
||||
class SortingTarget<Scalar, SortRule::SmallestMagn>
|
||||
{
|
||||
public:
|
||||
static ElemType<Scalar> get(const Scalar& val)
|
||||
{
|
||||
using std::abs;
|
||||
return abs(val);
|
||||
}
|
||||
};
|
||||
|
||||
// Specialization for SortRule::SmallestReal
|
||||
// This covers [complex] x [SortRule::SmallestReal]
|
||||
template <typename RealType>
|
||||
class SortingTarget<std::complex<RealType>, SortRule::SmallestReal>
|
||||
{
|
||||
public:
|
||||
static RealType get(const std::complex<RealType>& val)
|
||||
{
|
||||
return val.real();
|
||||
}
|
||||
};
|
||||
|
||||
// Specialization for SortRule::SmallestImag
|
||||
// This covers [complex] x [SortRule::SmallestImag]
|
||||
template <typename RealType>
|
||||
class SortingTarget<std::complex<RealType>, SortRule::SmallestImag>
|
||||
{
|
||||
public:
|
||||
static RealType get(const std::complex<RealType>& val)
|
||||
{
|
||||
using std::abs;
|
||||
return abs(val.imag());
|
||||
}
|
||||
};
|
||||
|
||||
// Specialization for SortRule::SmallestAlge
|
||||
// This covers [float, double] x [SortRule::SmallestAlge]
|
||||
template <typename Scalar>
|
||||
class SortingTarget<Scalar, SortRule::SmallestAlge>
|
||||
{
|
||||
public:
|
||||
static Scalar get(const Scalar& val)
|
||||
{
|
||||
return val;
|
||||
}
|
||||
};
|
||||
|
||||
// Sort eigenvalues
|
||||
template <typename T, SortRule Rule>
|
||||
class SortEigenvalue
|
||||
{
|
||||
private:
|
||||
using Index = Eigen::Index;
|
||||
using IndexArray = std::vector<Index>;
|
||||
|
||||
const T* m_evals;
|
||||
IndexArray m_index;
|
||||
|
||||
public:
|
||||
// Sort indices according to the eigenvalues they point to
|
||||
inline bool operator()(Index i, Index j)
|
||||
{
|
||||
return SortingTarget<T, Rule>::get(m_evals[i]) < SortingTarget<T, Rule>::get(m_evals[j]);
|
||||
}
|
||||
|
||||
SortEigenvalue(const T* start, Index size) :
|
||||
m_evals(start), m_index(size)
|
||||
{
|
||||
for (Index i = 0; i < size; i++)
|
||||
{
|
||||
m_index[i] = i;
|
||||
}
|
||||
std::sort(m_index.begin(), m_index.end(), *this);
|
||||
}
|
||||
|
||||
inline IndexArray index() const { return m_index; }
|
||||
inline void swap(IndexArray& other) { m_index.swap(other); }
|
||||
};
|
||||
|
||||
// Sort values[:len] according to the selection rule, and return the indices
|
||||
template <typename Scalar>
|
||||
std::vector<Eigen::Index> argsort(SortRule selection, const Eigen::Matrix<Scalar, Eigen::Dynamic, 1>& values, Eigen::Index len)
|
||||
{
|
||||
using Index = Eigen::Index;
|
||||
|
||||
// Sort Ritz values and put the wanted ones at the beginning
|
||||
std::vector<Index> ind;
|
||||
switch (selection)
|
||||
{
|
||||
case SortRule::LargestMagn:
|
||||
{
|
||||
SortEigenvalue<Scalar, SortRule::LargestMagn> sorting(values.data(), len);
|
||||
sorting.swap(ind);
|
||||
break;
|
||||
}
|
||||
case SortRule::BothEnds:
|
||||
case SortRule::LargestAlge:
|
||||
{
|
||||
SortEigenvalue<Scalar, SortRule::LargestAlge> sorting(values.data(), len);
|
||||
sorting.swap(ind);
|
||||
break;
|
||||
}
|
||||
case SortRule::SmallestMagn:
|
||||
{
|
||||
SortEigenvalue<Scalar, SortRule::SmallestMagn> sorting(values.data(), len);
|
||||
sorting.swap(ind);
|
||||
break;
|
||||
}
|
||||
case SortRule::SmallestAlge:
|
||||
{
|
||||
SortEigenvalue<Scalar, SortRule::SmallestAlge> sorting(values.data(), len);
|
||||
sorting.swap(ind);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw std::invalid_argument("unsupported selection rule");
|
||||
}
|
||||
|
||||
// For SortRule::BothEnds, the eigenvalues are sorted according to the
|
||||
// SortRule::LargestAlge 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 SymEigsBase::restart())
|
||||
// or is nev (used in SymEigsBase::sort_ritzpair())
|
||||
if (selection == SortRule::BothEnds)
|
||||
{
|
||||
std::vector<Index> ind_copy(ind);
|
||||
for (Index i = 0; i < len; 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[len - 1 - i / 2];
|
||||
}
|
||||
}
|
||||
|
||||
return ind;
|
||||
}
|
||||
|
||||
// Default vector length
|
||||
template <typename Scalar>
|
||||
std::vector<Eigen::Index> argsort(SortRule selection, const Eigen::Matrix<Scalar, Eigen::Dynamic, 1>& values)
|
||||
{
|
||||
return argsort<Scalar>(selection, values, values.size());
|
||||
}
|
||||
|
||||
/// \endcond
|
||||
|
||||
} // namespace Spectra
|
||||
|
||||
#endif // SPECTRA_SELECTION_RULE_H
|
||||
99
thirdparty/include/Spectra/Util/SimpleRandom.h
vendored
Normal file
99
thirdparty/include/Spectra/Util/SimpleRandom.h
vendored
Normal file
@@ -0,0 +1,99 @@
|
||||
// Copyright (C) 2016-2022 Yixuan Qiu <yixuan.qiu@cos.name>
|
||||
//
|
||||
// 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 SPECTRA_SIMPLE_RANDOM_H
|
||||
#define SPECTRA_SIMPLE_RANDOM_H
|
||||
|
||||
#include <Eigen/Core>
|
||||
|
||||
/// \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 <typename Scalar = double>
|
||||
class SimpleRandom
|
||||
{
|
||||
private:
|
||||
using Index = Eigen::Index;
|
||||
using Vector = Eigen::Matrix<Scalar, Eigen::Dynamic, 1>;
|
||||
|
||||
static constexpr unsigned int m_a = 16807; // multiplier
|
||||
static constexpr unsigned long m_max = 2147483647L; // 2^31 - 1
|
||||
long m_rand; // RNG state
|
||||
|
||||
inline long next_long_rand(long seed) const
|
||||
{
|
||||
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_rand(init_seed ? (init_seed & m_max) : 1)
|
||||
{}
|
||||
|
||||
// Return a single random number, ranging from -0.5 to 0.5
|
||||
Scalar random()
|
||||
{
|
||||
m_rand = next_long_rand(m_rand);
|
||||
return Scalar(m_rand) / Scalar(m_max) - Scalar(0.5);
|
||||
}
|
||||
|
||||
// Fill the given vector with random numbers
|
||||
// Ranging from -0.5 to 0.5
|
||||
void random_vec(Vector& vec)
|
||||
{
|
||||
const Index len = vec.size();
|
||||
for (Index i = 0; i < len; i++)
|
||||
{
|
||||
m_rand = next_long_rand(m_rand);
|
||||
vec[i] = Scalar(m_rand);
|
||||
}
|
||||
vec.array() = vec.array() / Scalar(m_max) - Scalar(0.5);
|
||||
}
|
||||
|
||||
// Return a vector of random numbers
|
||||
// Ranging from -0.5 to 0.5
|
||||
Vector random_vec(const Index len)
|
||||
{
|
||||
Vector res(len);
|
||||
random_vec(res);
|
||||
return res;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace Spectra
|
||||
|
||||
/// \endcond
|
||||
|
||||
#endif // SPECTRA_SIMPLE_RANDOM_H
|
||||
99
thirdparty/include/Spectra/Util/TypeTraits.h
vendored
Normal file
99
thirdparty/include/Spectra/Util/TypeTraits.h
vendored
Normal file
@@ -0,0 +1,99 @@
|
||||
// Copyright (C) 2018-2022 Yixuan Qiu <yixuan.qiu@cos.name>
|
||||
//
|
||||
// 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 SPECTRA_TYPE_TRAITS_H
|
||||
#define SPECTRA_TYPE_TRAITS_H
|
||||
|
||||
#include <Eigen/Core>
|
||||
#include <limits>
|
||||
|
||||
/// \cond
|
||||
|
||||
// Clang-Format will have unintended effects:
|
||||
// static constexpr Scalar(min)()
|
||||
// So we turn it off here
|
||||
//
|
||||
// clang-format off
|
||||
|
||||
namespace Spectra {
|
||||
|
||||
// For a real value type "Scalar", we want to know its smallest
|
||||
// positive value, i.e., std::numeric_limits<Scalar>::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 <typename Scalar>
|
||||
struct TypeTraits
|
||||
{
|
||||
static constexpr Scalar epsilon()
|
||||
{
|
||||
return Eigen::numext::numeric_limits<Scalar>::epsilon();
|
||||
}
|
||||
static constexpr Scalar (min)()
|
||||
{
|
||||
return epsilon() * epsilon() * epsilon();
|
||||
}
|
||||
};
|
||||
|
||||
// Full specialization
|
||||
template <>
|
||||
struct TypeTraits<float>
|
||||
{
|
||||
static constexpr float epsilon()
|
||||
{
|
||||
return std::numeric_limits<float>::epsilon();
|
||||
}
|
||||
static constexpr float (min)()
|
||||
{
|
||||
return (std::numeric_limits<float>::min)();
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct TypeTraits<double>
|
||||
{
|
||||
static constexpr double epsilon()
|
||||
{
|
||||
return std::numeric_limits<double>::epsilon();
|
||||
}
|
||||
static constexpr double (min)()
|
||||
{
|
||||
return (std::numeric_limits<double>::min)();
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct TypeTraits<long double>
|
||||
{
|
||||
static constexpr long double epsilon()
|
||||
{
|
||||
return std::numeric_limits<long double>::epsilon();
|
||||
}
|
||||
static constexpr long double (min)()
|
||||
{
|
||||
return (std::numeric_limits<long double>::min)();
|
||||
}
|
||||
};
|
||||
|
||||
// Get the element type of a "scalar"
|
||||
// ElemType<double> => double
|
||||
// ElemType<std::complex<double>> => double
|
||||
template <typename T>
|
||||
using ElemType = typename Eigen::NumTraits<T>::Real;
|
||||
|
||||
} // namespace Spectra
|
||||
|
||||
/// \endcond
|
||||
|
||||
#endif // SPECTRA_TYPE_TRAITS_H
|
||||
16
thirdparty/include/Spectra/Util/Version.h
vendored
Normal file
16
thirdparty/include/Spectra/Util/Version.h
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
// Copyright (C) 2020-2022 Yixuan Qiu <yixuan.qiu@cos.name>
|
||||
//
|
||||
// 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 SPECTRA_VERSION_H
|
||||
#define SPECTRA_VERSION_H
|
||||
|
||||
#define SPECTRA_MAJOR_VERSION 1
|
||||
#define SPECTRA_MINOR_VERSION 0
|
||||
#define SPECTRA_PATCH_VERSION 1
|
||||
|
||||
#define SPECTRA_VERSION (SPECTRA_MAJOR_VERSION * 10000 + SPECTRA_MINOR_VERSION * 100 + SPECTRA_PATCH_VERSION)
|
||||
|
||||
#endif // SPECTRA_VERSION_H
|
||||
Reference in New Issue
Block a user