Laguerre polynomials
Loading...
Searching...
No Matches
Laguerre18m.h
Go to the documentation of this file.
1// Александр, Дмитрий
2
3#ifndef LAGUERRE18
4#define LAGUERRE18
5
6#include <vector>
7#include <limits>
8#include <numbers> // std::numbers::pi_v<fp_t>, requires -std=c++20
9#include <complex>
10#include <iostream>
11#include <algorithm>
12
13#include "BaseSolver.h"
14#include "ExtendedFunctions.h"
15
16namespace Laguerre{
17using std::complex;
18using std::vector;
19using std::fma;
20
21template<typename T>
23private:
24 //
25 static constexpr T eps = std::numeric_limits<T>::epsilon();
26 static constexpr T big = std::numeric_limits<T>::max();
27 static constexpr T small = std::numeric_limits<T>::min();
28 //
29 static constexpr T PI = std::numbers::pi_v<T>;
30 static constexpr T pi2 = PI*static_cast<T>(2);
31
32
41 inline T cross(std::vector<int>& h, std::vector<T>& a, int c, int i) {
42 // determinant
43 int h_c = h[c];
44 int h_c1 = h[c-1];
45 T a_hc = a[h_c1];
46 return fms(a[i]-a_hc, static_cast<T>(h_c-h_c1), a[h_c]-a_hc, static_cast<T>(i-h_c1));
47 }
48
56 inline void conv_hull(int n, std::vector<T>& a, std::vector<int>& h, int& c) {
57 c = 0;
58
59 for (int i = n - 1; i >= 0; --i) {
60 while (c >= 2 && cross(h, a, c, i) < eps)
61 --c;
62 ++c;
63 h[c] = i;
64 }
65 }
66
75 inline void estimates(vector<T>& alpha, int deg, std::vector<std::complex<T>>& roots, std::vector<int>& conv, int& nz) {
76 int c, i, j, k, nzeros;
77 T a1, a2, ang, r, th;
78 std::vector<int> h(deg + 1);
79 std::vector<T> a(deg + 1);
80
81 // Andrews starting position
82 for (i = 0; i < deg + 1; ++i)
83 a[i] = alpha[i] > 0 ? log(alpha[i]) : -big;
84 conv_hull(deg + 1, a, h, c);
85
86 k = 0;
87 th = pi2/static_cast<T>(deg);
88
89 // Initial Estimates
90 for (i = c - 1; i >= 0; --i) {
91 nzeros = h[i] - h[i + 1];
92 T one_div_nzeros = static_cast<T>(1.0 / nzeros);
93 a1 = pow(alpha[h[i + 1]], one_div_nzeros);
94 a2 = pow(alpha[h[i]], one_div_nzeros);
95
96 // Help :)
97 /*
98 std::cout << "\nalpha[h[i]]: " << alpha[h[i]];
99 std::cout << "\nnzeros: " << nzeros;
100 std::cout << "\nonedivzeros: " << one_div_nzeros;
101 std::cout << "\na2: " << a2 << "\n";
102 */
103
104 if (a1 <= a2 * small){
105 // r is too small
106 r = 0.0;
107 nz += nzeros;
108 for (j = k; j < k + nzeros; ++j){
109 conv[j] = -1;
110 roots[j] = {0.0, 0.0};
111 }
112 }
113 else{
114 T sigma_thh = fma(th, h[i], static_cast<T>(0.7));
115 if (a1 >= a2 * big){
116 // r is too big
117 r = big;
118 nz += nzeros;
119 for (j = k; j < k + nzeros; ++j)
120 conv[j] = -1;
121 }
122 else{
123 // r is ok :big-finger-emoji:
124 r = a1 / a2;
125 }
126 ang = pi2 / static_cast<T>(nzeros);
127 for (j = 0; j < nzeros; ++j){
128 T arg = fma(ang, j, sigma_thh);
129 roots[k + j] = r * std::complex<T>(cos(arg), sin(arg));
130 }
131 }
132 k += nzeros;
133 }
134 }
135
136
149 inline void rcheck_lag(std::vector<T>& p, vector<T>& alpha, int deg, complex<T>& b, complex<T>& c, complex<T> z, T r, int& conv, T& berr, T& cond) {
150 int k;
151 T rr;
152 complex<T> a, zz, zz2;
153
154 // Evaluate polynomial and derivatives
155 zz = complex<T>(1, 0) / z;
156 zz2 = zz*zz;
157 rr = static_cast<T>(1) / r;
158 a = p[0];
159 b = 0;
160 c = 0;
161 berr = alpha[0];
162
163 for (k = 1; k < deg + 1; ++k) {
164 c = fma(zz, c, b);
165 b = fma(zz, b, a);
166 a = fma(zz, a, p[k]);
167 berr = fma(rr, berr, alpha[k]);
168 }
169
170 // Laguerre correction/ backward error and condition
171 bool condition = abs(a) > eps * berr;
172 b = condition ? b/a : b;
173 c = condition ? fms(zz2, fma(-static_cast<T>(2)*zz, b, static_cast<T>(deg)), zz2*zz2, fms(complex<T>(2.0, 0), c / a, b, b)) : c;
174 b = condition ? fms(zz, complex<T>(deg, 0) , zz2, b) : b;
175
176 cond = (!condition)*(berr / fabs(fms(complex<T>(deg, 0), a, zz, b))) + (condition)*cond;
177 berr = (!condition)*(fabs(a) / berr) + (condition)*berr;
178
179 conv = condition ?
180 (complexnotfinite(b, big) || complexnotfinite(c, big) ? -1 : conv)
181 : 1;
182
183 /*
184 if (fabs(a) > eps * berr) {
185 b = b / a;
186 c = fms(zz2, fma(-static_cast<T>(2)*zz, b, static_cast<T>(deg)), zz2*zz2, fms(complex<T>(2.0, 0), c / a, b, b));
187 b = fms(zz, complex<T>(deg, 0) , zz2, b);
188
189 if (complexnotfinite(b, big) || complexnotfinite(c, big))
190 conv = -1;
191 } else {
192 cond = berr / fabs(fms(complex<T>(deg, 0), a, zz, b));
193 berr = fabs(a) / berr;
194 conv = 1;
195 }
196 */
197 }
198
212 inline void check_lag(std::vector<T>& p, std::vector<T>& alpha, int deg, std::complex<T>& b, std::complex<T>& c, std::complex<T> z, T r, int& conv, T& berr, T& cond) {
213 int k;
214 std::complex<T> a;
215
216 // Evaluate polynomial and derivatives
217 a = p[deg];
218 b = 0;
219 c = 0;
220 berr = alpha[deg];
221
222 for (k = deg - 1; k >= 0; --k) {
223 c = fma(z, c, b);
224 b = fma(z, b, a);
225 a = fma(z, a, p[k]);
226 berr = fma(r, berr, alpha[k]);
227 }
228
229 // Laguerre correction/ backward error and condition
230 bool condition = abs(a) > eps * berr;
231 b = condition ? b/a : b;
232 // b^2 + (-{2,0}*c/a)+{2,0}*c/a+(-{2,0}*c/a)
233 c = condition ? fms(b, b, std::complex<T>(2, 0), c/a) : c;
234
235 cond = (!condition)*(berr / (r * fabs(b))) + (condition)*cond;
236 berr = (!condition)*(fabs(a) / berr) + (condition)*berr;
237
238 conv = condition ?
239 (complexnotfinite(b, big) || complexnotfinite(c, big) ? -1 : conv)
240 : 1;
241
242 /*
243 if (abs(a) > eps * berr) {
244 b = b / a;
245 c = fms(b, b, std::complex<T>(2, 0), c/a);
246
247 if (complexnotfinite(b, big) || complexnotfinite(c, big))
248 conv = -1;
249 } else {
250 cond = berr / (r * fabs(b));
251 berr = fabs(a) / berr;
252 conv = 1;
253 }
254 */
255 }
256
257
267 void modify_lag(int deg, std::complex<T>& b, std::complex<T>& c, std::complex<T> z, int j, std::vector<std::complex<T>>& roots) {
268 std::complex<T> t;
269
270 // Aberth correction terms
271 for (int k = 0; k < j - 1; ++k) {
272 t = static_cast<T>(1.0) / (z - roots[k]);
273 b -= t;
274 c = fma(-t, t, c);
275 }
276 // k != j
277 for (int k = j + 1; k <= deg; ++k) {
278 t = static_cast<T>(1.0) / (z - roots[k]);
279 b -= t;
280 c = fma(-t, t, c);
281 }
282
283 // Laguerre correction
284 t = sqrt(fms(complex<T>(static_cast<T>(deg - 1), 0), (static_cast<T>(deg) * c), b, b));
285 c = b + t;
286 b -= t;
287 // std::complex<T> degc(deg, 0);
288 c = abs(b) > abs(c) ? static_cast<T>(deg) / b : static_cast<T>(deg) / c;
289 }
290
291public:
293 //
294 }
295
303 void operator()(std::vector<T>& poly, std::vector<std::complex<T>>& roots, std::vector<int>& conv, int itmax) override{
304 int deg = roots.size();
305 std::vector<T> berr(deg); // Vector to store the backward errors.
306 std::vector<T> cond(deg); // Vector to store the condition numbers.
307 int i, j, nz;
308 T r;
309 std::vector<T> alpha(deg + 1);
310 std::complex<T> b, c, z;
311
312 // Precheck
313 for (i = 0; i <= deg; i++)
314 alpha[i] = fabs(poly[i]);
315
316 if (alpha[deg] < small) {
317 std::cout << "Warning: leading coefficient is too small." << std::endl;
318 return;
319 }
320
321 // Initial estimates
322 conv.assign(deg, 0);
323 nz = 0;
324 estimates(alpha, deg, roots, conv, nz);
325
326 for (i = 0; i <= deg; ++i)
327 alpha[i] *= fma(static_cast<T>(3.8), static_cast<T>(i), static_cast<T>(1));
328 // Main loop
329
330 for (i = 1; i <= itmax; ++i)
331 for (j = 0; j < deg; ++j) {
332 if (conv[j] == 0) {
333 z = roots[j];
334 r = fabs(z);
335 //
336 if (r > 1.0)
337 rcheck_lag(poly, alpha, deg, b, c, z, r, conv[j], berr[j], cond[j]);
338 else
339 check_lag(poly, alpha, deg, b, c, z, r, conv[j], berr[j], cond[j]);
340
341 if (conv[j] == 0) {
342 modify_lag(deg, b, c, z, j, roots);
343 roots[j] -= c;
344 }
345 else {
346 nz++;
347 if (nz == deg){
348 if (*std::min_element(conv.begin(), conv.end()) == 1)
349 return;
350 // Display a warning
351 std::cout << "Some root approximations did not converge or experienced overflow/underflow.\n";
352
353 // Compute backward error and condition number for roots that did not converge.
354 for (j = 0; j < deg; ++j){
355 if (conv[j] != 1) {
356 z = roots[j];
357 r = abs(z);
358
359 if (r > 1.0) {
360 z = static_cast<T>(1.0) / z;
361 r = static_cast<T>(1.0) / r;
362 c = 0;
363 b = poly[0];
364 berr[j] = alpha[0];
365
366 for (i = 1; i < deg + 1; ++i) {
367 c = fma(z, c, b);
368 b = fma(z, b, poly[i]);
369 berr[j] = fma(r, berr[j], alpha[i]);
370 }
371
372 cond[j] = berr[j] / fabs(fms(complex<T>(deg, 0), b, z, c));
373 berr[j] = fabs(b) / berr[j];
374 }
375 else {
376 c = 0.0;
377 b = poly[deg];
378 berr[j] = alpha[deg];
379
380 for (i = deg - 1; i >= 0; --i) {
381 c = fma(z, c, b);
382 b = fma(z, b, poly[i]);
383 berr[j] = fma(r, berr[j], alpha[i]);
384 }
385
386 cond[j] = berr[j] / (r * fabs(c));
387 berr[j] = fabs(b) / berr[j];
388 }
389 }
390 }
391 }
392 }
393 }
394 }
395 }
396
397};
398
399};
400#endif
c0 z
Definition Laguerre15m_or.h:21
p2 de j *z j
Definition Laguerre15m_or.h:23
cohn_schur ra local deg
Definition Laguerre15m_or.h:3
cohn_schur ra local b
Definition Laguerre15m_or.h:3
cohn_schur ra local k
Definition Laguerre15m_or.h:3
Definition BaseSolver.h:7
Definition Laguerre18m.h:22
void modify_lag(int deg, std::complex< T > &b, std::complex< T > &c, std::complex< T > z, int j, std::vector< std::complex< T > > &roots)
Modify Laguerre correction based on Aberth's method.
Definition Laguerre18m.h:267
static constexpr T small
Definition Laguerre18m.h:27
void operator()(std::vector< T > &poly, std::vector< std::complex< T > > &roots, std::vector< int > &conv, int itmax) override
Find the roots of a polynomial using Laguerre's method.
Definition Laguerre18m.h:303
void conv_hull(int n, std::vector< T > &a, std::vector< int > &h, int &c)
Calculate the convex hull of a set of points. Dont forget to calculate Andrews alghoritm to vector a!
Definition Laguerre18m.h:56
T cross(std::vector< int > &h, std::vector< T > &a, int c, int i)
Calculate the determinant between two points.
Definition Laguerre18m.h:41
ModifiedLaguerre18()
Definition Laguerre18m.h:292
static constexpr T big
Definition Laguerre18m.h:26
void estimates(vector< T > &alpha, int deg, std::vector< std::complex< T > > &roots, std::vector< int > &conv, int &nz)
Estimate roots of a polynomial.
Definition Laguerre18m.h:75
void check_lag(std::vector< T > &p, std::vector< T > &alpha, int deg, std::complex< T > &b, std::complex< T > &c, std::complex< T > z, T r, int &conv, T &berr, T &cond)
Perform Laguerre correction, compute backward error, and condition.
Definition Laguerre18m.h:212
static constexpr T PI
Definition Laguerre18m.h:29
void rcheck_lag(std::vector< T > &p, vector< T > &alpha, int deg, complex< T > &b, complex< T > &c, complex< T > z, T r, int &conv, T &berr, T &cond)
Perform Laguerre correction, compute backward error, and condition.
Definition Laguerre18m.h:149
static constexpr T pi2
Definition Laguerre18m.h:30
static constexpr T eps
Definition Laguerre18m.h:25
Definition ExtendedFunctions.h:14
bool complexnotfinite(complex< T > a, T big)
Check if a complex number contains NaN or Inf values.
Definition ExtendedFunctions.h:30
number fms(number a, number b, number c, number d)
Fused multiply-substract a*b+(-d*c)+d*c+(-d*c)
Definition ExtendedFunctions.h:63
complex< number > fma(complex< number > a, complex< number > b, complex< number > c)
Fused multiply-add for complex numbers.
Definition ExtendedFunctions.h:82