9#include <nk/value/scratch.hpp>
17#include <memory_resource>
21using Complex = std::complex<double>;
28inline void polyEvalHorner(
const Complex *c, std::size_t n,
29 Complex z, Complex &outP, Complex &outDP)
33 for (std::size_t i = 1; i < n; ++i) {
55inline ScratchVec<Complex>
56polyRootsDurandKerner(std::pmr::memory_resource *mr,
57 const double *coeffs, std::size_t coeffsN)
59 std::size_t lo = 0, hi = coeffsN;
60 while (lo < hi && coeffs[lo] == 0.0) ++lo;
61 std::size_t origZeros = 0;
62 while (hi > lo && coeffs[hi - 1] == 0.0) { --hi; ++origZeros; }
64 return ScratchVec<Complex>(origZeros, Complex(0.0, 0.0), mr);
66 ScratchVec<Complex> c(hi - lo, mr);
67 for (std::size_t i = 0; i < c.size(); ++i)
68 c[i] = Complex(coeffs[lo + i] / coeffs[lo], 0.0);
69 const std::size_t n = c.size() - 1;
74 for (std::size_t i = 1; i <= n; ++i)
75 maxCoef = std::max(maxCoef, std::abs(c[i].
real()));
76 const double R = 1.0 + maxCoef;
77 ScratchVec<Complex>
roots(n, mr);
78 constexpr double kTwoPi = 6.28318530717958647692;
79 for (std::size_t k = 0; k < n; ++k) {
80 const double theta = kTwoPi *
static_cast<double>(k)
81 /
static_cast<double>(n) + 0.4;
82 roots[k] = Complex(R * std::cos(theta), R * std::sin(theta));
85 constexpr int kMaxIter = 200;
86 constexpr double kTol = 1e-14;
87 for (
int it = 0; it < kMaxIter; ++it) {
89 for (std::size_t k = 0; k < n; ++k) {
91 polyEvalHorner(c.data(), c.size(), roots[k], p, dp);
92 Complex denom(1.0, 0.0);
93 for (std::size_t j = 0; j < n; ++j)
95 if (std::abs(denom) < 1e-300)
continue;
96 const Complex step = p / denom;
98 const double s = std::abs(step);
99 if (s > maxStep) maxStep = s;
101 if (maxStep < kTol)
break;
103 for (std::size_t i = 0; i < origZeros; ++i)
104 roots.push_back(Complex(0.0, 0.0));
114inline ScratchVec<double>
115polyExpandFromRoots(std::pmr::memory_resource *mr,
116 const Complex *roots, std::size_t rootsN)
118 const int n =
static_cast<int>(rootsN);
119 ScratchVec<Complex>
poly(
static_cast<std::size_t
>(n + 1), mr);
120 poly[0] = Complex(1.0, 0.0);
121 for (
int i = 0; i < n; ++i)
122 for (
int j = i + 1; j >= 1; --j)
123 poly[j] = poly[j] - roots[i] * poly[j - 1];
124 ScratchVec<double> r(
static_cast<std::size_t
>(n + 1), mr);
125 for (
int i = 0; i <= n; ++i)
126 r[i] = poly[i].
real();
Value real(const Value &x, std::pmr::memory_resource *mr=nullptr)
Real part of complex array (y = real(x)).
Value poly(const Value &r, std::pmr::memory_resource *mr=nullptr)
Polynomial with specified roots or characteristic polynomial of a matrix.
Value roots(const Value &p, std::pmr::memory_resource *mr=nullptr)
Computes polynomial roots (roots(p)).