5#ifndef LINE_UTIL_EXPM_H
6#define LINE_UTIL_EXPM_H
67inline int expm_digits10() {
68 const int d = std::numeric_limits<T>::digits10;
69 return d > 0 ? d : 15;
77inline double expm_theta(
int m,
int digits10) {
78 const double lgC = 2.0 * std::lgamma(m + 1.0) - std::lgamma(2.0 * m + 1.0) -
79 std::lgamma(2.0 * m + 2.0);
80 const double log10C = lgC / std::log(10.0);
81 const double t = std::pow(10.0, (-log10C - digits10) / (2.0 * m + 1.0));
82 return t < 5.37 ? t : 5.37;
87double expm_norm1(
const Matrix<T>& A) {
89 for (std::size_t j = 0; j < A.cols(); ++j) {
91 for (std::size_t i = 0; i < A.rows(); ++i)
92 s += num_traits<T>::to_double(
num_abs(T(A(i, j))));
93 if (s > best) best = s;
100Matrix<T> expm_pade(
const Matrix<T>& X,
unsigned m) {
101 const std::size_t n = X.rows();
103 std::vector<T> c(m + 1);
104 c[0] = num_traits<T>::from_int(1);
105 for (
unsigned k = 1; k <= m; ++k) {
106 const T num = num_traits<T>::from_int(
static_cast<long>(m - k + 1));
107 const T den = num_traits<T>::from_int(
static_cast<long>(k)) *
108 num_traits<T>::from_int(
static_cast<long>(2 * m - k + 1));
109 c[k] = c[k - 1] * num / den;
115 for (
unsigned k = 1; k <= m; ++k) {
117 const bool odd = (k % 2u) == 1u;
118 for (std::size_t i = 0; i < n; ++i)
119 for (std::size_t j = 0; j < n; ++j) {
120 const T term = c[k] * P(i, j);
143 "expm is a tolerance-controlled approximation and requires "
144 "transcendental (inexact) arithmetic");
145 const std::size_t n = A.
rows();
146 if (A.
cols() != n)
throw InputError(
"expm: matrix is not square");
147 if (n == 0)
throw InputError(
"expm: empty matrix");
151 for (std::size_t i = 0; i < n && allzero; ++i)
152 for (std::size_t j = 0; j < n; ++j)
153 if (!(A(i, j) == zero)) {
157 if (allzero)
return eye<T>(n);
159 const double nrm = detail::expm_norm1(A);
160 if (!(nrm == nrm) || nrm == std::numeric_limits<double>::infinity())
161 throw NumericError(
"expm: matrix contains a non-finite entry");
163 const int d10 = detail::expm_digits10<T>();
164 const unsigned degrees[5] = {3u, 5u, 7u, 9u, 13u};
168 for (
int k = 0; k < 5; ++k) {
169 if (nrm <= detail::expm_theta(
static_cast<int>(degrees[k]), d10)) {
176 const double theta13 = detail::expm_theta(13, d10);
177 s =
static_cast<int>(std::ceil(std::log2(nrm / theta13)));
179 if (s > 4096)
throw NumericError(
"expm: matrix norm is too large to scale");
186 for (
int k = 0; k < s; ++k) scale *= half;
187 for (std::size_t i = 0; i < n; ++i)
188 for (std::size_t j = 0; j < n; ++j) X(i, j) *= scale;
192 for (
int k = 0; k < s; ++k) E =
matmul(E, E);
200 for (std::size_t i = 0; i < B.
rows(); ++i)
201 for (std::size_t j = 0; j < B.
cols(); ++j) B(i, j) *= t;
NumericError(const std::string &what)
The exception types the port throws.
Dense linear algebra over the templated number type: products, identity, inverse, and powers.
Dense matrix and non-owning view.
Matrix< T > inverse(const Matrix< T > &A)
Inverse by LU with one factorization and n back substitutions.
Matrix< T > matmul(const Matrix< T > &A, const Matrix< T > &B)
Matrix product A B.
Matrix< T > eye(std::size_t n)
Identity of order n.
Matrix< T > expm(const Matrix< T > &A)
Matrix exponential exp(A).
Number-type abstraction for the templated API port.