5#ifndef LINE_API_PFQN_ASYMPT_COMMON_H
6#define LINE_API_PFQN_ASYMPT_COMMON_H
56T pfqn_det(Matrix<T> A) {
57 const std::size_t n = A.rows();
58 if (A.cols() != n)
throw InputError(
"pfqn_det: matrix is not square");
59 const T zero = num_traits<T>::from_int(0);
60 T d = num_traits<T>::from_int(1);
61 for (std::size_t k = 0; k < n; ++k) {
64 for (std::size_t i = k + 1; i < n; ++i) {
71 if (amax == zero)
return zero;
73 for (std::size_t j = 0; j < n; ++j) std::swap(A(k, j), A(p, j));
77 for (std::size_t i = k + 1; i < n; ++i) {
78 const T f = A(i, k) / A(k, k);
79 for (std::size_t j = k; j < n; ++j) A(i, j) -= f * A(k, j);
93T pfqn_logdet(Matrix<T> A) {
94 static_assert(num_traits<T>::has_transcendental,
95 "pfqn_logdet requires transcendental arithmetic (logarithm)");
97 const std::size_t n = A.rows();
98 if (A.cols() != n)
throw InputError(
"pfqn_logdet: matrix is not square");
99 const T zero = num_traits<T>::from_int(0);
100 T acc = num_traits<T>::from_int(0);
101 for (std::size_t k = 0; k < n; ++k) {
104 for (std::size_t i = k + 1; i < n; ++i) {
111 if (amax == zero)
throw InputError(
"pfqn_logdet: matrix is singular");
113 for (std::size_t j = 0; j < n; ++j) std::swap(A(k, j), A(p, j));
116 for (std::size_t i = k + 1; i < n; ++i) {
117 const T f = A(i, k) / A(k, k);
118 for (std::size_t j = k; j < n; ++j) A(i, j) -= f * A(k, j);
130T num_logfact_int(
long n) {
131 static_assert(num_traits<T>::has_transcendental,
132 "num_logfact_int requires transcendental arithmetic (logarithm)");
133 if (n < 0)
throw InputError(
"num_logfact_int: negative argument");
135 T s = num_traits<T>::from_int(0);
136 for (
long k = 2; k <= n; ++k) s += log(num_traits<T>::from_int(k));
142T num_lgamma(
const T& x) {
143 static_assert(num_traits<T>::has_transcendental,
144 "num_lgamma requires transcendental arithmetic");
148 const T zero = num_traits<T>::from_int(0);
149 if (x <= zero)
throw InputError(
"num_lgamma: argument must be positive");
152 const double xd = num_traits<T>::to_double(x);
153 const double rn = std::floor(xd + 0.5);
154 if (rn >= 1.0 && rn <= 1e6 && x == num_traits<T>::from_int(
static_cast<long>(rn)))
155 return num_logfact_int<T>(
static_cast<long>(rn) - 1);
157 static const double g[9] = {0.99999999999980993, 676.5203681218851, -1259.1392167224028,
158 771.32342877765313, -176.61502916214059, 12.507343278686905,
159 -0.13857109526572012, 9.9843695780195716e-6,
160 1.5056327351493116e-7};
161 const T one = num_traits<T>::from_int(1);
162 const T z = T(x - one);
163 T a = num_traits<T>::from_double(g[0]);
164 for (
int i = 1; i < 9; ++i)
165 a += num_traits<T>::from_double(g[i]) / T(z + num_traits<T>::from_int(i));
166 const T t = T(z + num_traits<T>::from_double(7.5));
167 const T twopi = num_traits<T>::from_double(6.283185307179586476925286766559);
168 return T(num_traits<T>::from_rational(1, 2) * log(twopi) + T(z + num_traits<T>::from_rational(1, 2)) * log(t) -
174T num_factln(
const T& n) {
175 return num_lgamma<T>(T(n + num_traits<T>::from_int(1)));
180T logsumexp(
const std::vector<T>& v) {
181 static_assert(num_traits<T>::has_transcendental,
182 "logsumexp requires transcendental arithmetic");
185 if (v.empty())
throw InputError(
"logsumexp: empty argument");
190 if (!(num_traits<T>::to_double(m) > -std::numeric_limits<double>::infinity()))
return m;
191 T s = num_traits<T>::from_int(0);
192 for (
const T& x : v) s += exp(T(x - m));
193 return T(m + log(s));
224void gauss_legendre(std::size_t n,
const T& a,
const T& b, std::vector<T>& x, std::vector<T>& w,
225 std::size_t count = 0) {
226 static_assert(num_traits<T>::has_transcendental,
227 "gauss_legendre requires transcendental arithmetic (cos, sqrt)");
229 x.assign(n, num_traits<T>::from_int(0));
230 w.assign(n, num_traits<T>::from_int(0));
231 const T one = num_traits<T>::from_int(1);
232 const T two = num_traits<T>::from_int(2);
233 const T half = num_traits<T>::from_rational(1, 2);
234 const T pi = num_traits<T>::from_double(3.14159265358979323846264338328);
235 const T xm = T(half * T(b + a));
236 const T xl = T(half * T(b - a));
237 std::size_t m = (n + 1) / 2;
238 if (count > 0 && count < m) m = count;
239 for (std::size_t i = 0; i < m; ++i) {
241 T z = cos(T(pi * T(num_traits<T>::from_int(
static_cast<long>(i) + 1) - num_traits<T>::from_rational(1, 4)) /
242 T(num_traits<T>::from_int(
static_cast<long>(n)) + half)));
244 for (
int it = 0; it < 200; ++it) {
245 T p1 = one, p2 = num_traits<T>::from_int(0);
246 for (std::size_t j = 0; j < n; ++j) {
249 const T jj = num_traits<T>::from_int(
static_cast<long>(j) + 1);
250 p1 = T(T(T(two * jj - one) * z * p2 - T(jj - one) * p3) / jj);
252 pp = T(num_traits<T>::from_int(
static_cast<long>(n)) * T(z * p1 - p2) / T(z * z - one));
253 const T dz = T(p1 / pp);
255 if (num_traits<T>::to_double(
num_abs(T(dz))) < 1e-40)
break;
257 x[i] = T(xm - xl * z);
258 x[n - 1 - i] = T(xm + xl * z);
259 const T wi = T(two * xl / T(T(one - z * z) * pp * pp));
272void gauss_laguerre(std::size_t n, std::vector<T>& x, std::vector<T>& w) {
273 static_assert(num_traits<T>::has_transcendental,
274 "gauss_laguerre requires transcendental arithmetic");
277 x.assign(n, num_traits<T>::from_int(0));
278 w.assign(n, num_traits<T>::from_int(0));
279 const T one = num_traits<T>::from_int(1);
280 const T nT = num_traits<T>::from_int(
static_cast<long>(n));
281 T z = num_traits<T>::from_int(0);
282 for (std::size_t i = 0; i < n; ++i) {
284 z = num_traits<T>::from_double(3.0) / T(one + num_traits<T>::from_double(2.4) * nT);
286 z += num_traits<T>::from_double(15.0) / T(one + num_traits<T>::from_double(2.5) * nT);
288 const T ai = num_traits<T>::from_int(
static_cast<long>(i) - 1);
289 z += T(one + num_traits<T>::from_double(2.55) * ai) /
290 T(num_traits<T>::from_double(1.9) * ai) * T(z - x[i - 2]);
292 T pp = one, p2 = num_traits<T>::from_int(0);
293 for (
int it = 0; it < 300; ++it) {
295 p2 = num_traits<T>::from_int(0);
296 for (std::size_t j = 0; j < n; ++j) {
299 const T jj = num_traits<T>::from_int(
static_cast<long>(j) + 1);
300 p1 = T(T(T(num_traits<T>::from_int(2 *
static_cast<long>(j) + 1) - z) * p2 -
305 pp = T(T(nT * p1 - nT * p2) / z);
306 const T dz = T(p1 / pp);
308 if (num_traits<T>::to_double(
num_abs(T(dz))) < 1e-40)
break;
312 w[i] = T(-one / T(nT * pp * p2));
330 if constexpr (num_traits<T>::is_exact) {
331 return num_traits<T>::from_int(0);
333 return num_traits<T>::from_double(std::numeric_limits<double>::infinity());
339bool is_inf_marker(
const T& v) {
340 if constexpr (num_traits<T>::is_exact) {
341 return v == num_traits<T>::from_int(0);
343 return !std::isfinite(num_traits<T>::to_double(v));
355 Cx() : re(num_traits<T>::from_int(0)), im(num_traits<T>::from_int(0)) {}
356 Cx(
const T& r,
const T& i) : re(r), im(i) {}
357 explicit Cx(
const T& r) : re(r), im(num_traits<T>::from_int(0)) {}
361Cx<T> cx_add(
const Cx<T>& a,
const Cx<T>& b) {
362 return Cx<T>(T(a.re + b.re), T(a.im + b.im));
366Cx<T> cx_mul(
const Cx<T>& a,
const Cx<T>& b) {
367 return Cx<T>(T(a.re * b.re - a.im * b.im), T(a.re * b.im + a.im * b.re));
371Cx<T> cx_scale(
const Cx<T>& a,
const T& s) {
372 return Cx<T>(T(a.re * s), T(a.im * s));
376Cx<T> cx_div(
const Cx<T>& a,
const Cx<T>& b) {
377 const T d = T(b.re * b.re + b.im * b.im);
378 if (d == num_traits<T>::from_int(0))
throw NumericError(
"cx_div: division by zero");
379 return Cx<T>(T(T(a.re * b.re + a.im * b.im) / d), T(T(a.im * b.re - a.re * b.im) / d));
384Cx<T> cx_expi(
const T& theta) {
385 static_assert(num_traits<T>::has_transcendental,
386 "cx_expi requires transcendental arithmetic");
389 return Cx<T>(cos(theta), sin(theta));
NumericError(const std::string &what)
The exception types the port throws.
Dense matrix and non-owning view.
Number-type abstraction for the templated API port.