Laguerre polynomials
Loading...
Searching...
No Matches
L18_or.h
Go to the documentation of this file.
1#include <complex>
2#include <vector>
3#include <cmath>
4#include <iostream>
5#include <algorithm>
6#include <limits>
7
8#include "ExtendedFunctions.h"
9
10const double eps = std::numeric_limits<double>::epsilon();
11const double big = std::numeric_limits<double>::max();
12const double small = std::numeric_limits<double>::min();
13
23double cross(std::vector<int>& h, std::vector<double>& a, int c, int i) {
24 // determinant
25 int h_c = h[c];
26 int h_c1 = h[c-1];
27 double a_hc = a[h_c1];
28 double det = Laguerre::fms(a[i]-a_hc, (double)(h_c-h_c1), a[h_c]-a_hc, (double)(i-h_c1));
29 return det;
30 }
31
40void conv_hull(int n, std::vector<double>& a, std::vector<int>& h, int& c) {
41 c = 0;
42
43 for (int i = n - 1; i >= 0; i--) {
44 while (c >= 2 && cross(h, a, c, i) < eps)
45 c--;
46 c++;
47 h[c] = i;
48 }
49}
50
60void estimates(std::vector<double>& alpha, int deg, std::vector<std::complex<double>>& roots, std::vector<int>& conv, int& nz) {
61 int c, i, j, k, nzeros;
62 double a1, a2, ang, r, th;
63 std::vector<int> h(deg + 1);
64 std::vector<double> a(deg + 1);
65 const double pi2 = 6.2831853071795865;
66 const double sigma = 0.7;
67
68 // Log of absolute value of coefficients
69 for (i = 0; i < deg + 1; i++) {
70 if (alpha[i] > 0) {
71 a[i] = log(alpha[i]);
72 } else {
73 a[i] = -1E+30;
74 }
75 }
76 conv_hull(deg + 1, a, h, c);
77 k = 0;
78 th = pi2 / deg;
79
80 // Initial Estimates
81 for (i = c - 1; i >= 0; i--) {
82 nzeros = h[i] - h[i + 1];
83 a1 = pow(alpha[h[i + 1]], 1.0 / nzeros);
84 a2 = pow(alpha[h[i]], 1.0 / nzeros);
85
86 if (a1 <= a2 * small) {
87 // r is too small
88 r = 0.0;
89 nz += nzeros;
90 for (j = k; j < k + nzeros; j++)
91 conv[j] = -1;
92 for (j = k; j < k + nzeros; j++)
93 roots[j] = {0.0, 0.0};
94 } else if (a1 >= a2 * big) {
95 // r is too big
96 r = big;
97 nz += nzeros;
98 for (j = k; j < k + nzeros; j++)
99 conv[j] = -1;
100 ang = pi2 / nzeros;
101 for (j = 0; j < nzeros; j++)
102 roots[k + j] = r * std::complex<double>(cos(ang * j + th * h[i] + sigma), sin(ang * j + th * h[i] + sigma));
103 } else {
104 // r is just right
105 r = a1 / a2;
106 ang = pi2 / nzeros;
107 for (j = 0; j < nzeros; j++)
108 roots[k + j] = r * std::complex<double>(cos(ang * j + th * h[i] + sigma), sin(ang * j + th * h[i] + sigma));
109 }
110 k += nzeros;
111 }
112}
113
120bool check_nan_inf(std::complex<double> a) {
121 double re_a = real(a);
122 double im_a = imag(a);
123 return std::isnan(re_a) || std::isnan(im_a) || (abs(re_a) > big) || (abs(im_a) > big);
124}
125
140void rcheck_lag(std::vector<double>& p, std::vector<double>& alpha, int deg, std::complex<double>& b, std::complex<double>& c, std::complex<double> z, double r, int& conv, double& berr, double& cond) {
141 int k;
142 double rr;
143 std::complex<double> a, zz;
144
145 // Evaluate polynomial and derivatives
146 zz = 1.0 / z;
147 rr = 1.0 / r;
148 a = p[0];
149 b = 0.0;
150 c = 0.0;
151 berr = alpha[0];
152
153 for (k = 1; k < deg + 1; k++) {
154 c = zz * c + b;
155 b = zz * b + a;
156 a = zz * a + p[k];
157 berr = rr * berr + alpha[k];
158 }
159
160 // Laguerre correction/ backward error and condition
161 if (abs(a) > eps * berr) {
162 b = b / a;
163 c = 2.0 * (c / a);
164 c = pow(zz, 2) * ((double)deg - 2.0 * zz * b + pow(zz, 2) * (pow(b, 2) - c));
165 b = zz * ((double)deg - zz * b);
166
167 if (check_nan_inf(b) || check_nan_inf(c))
168 conv = -1;
169 } else {
170 cond = berr / abs((double)deg * a - zz * b);
171 berr = abs(a) / berr;
172 conv = 1;
173 }
174}
175
190void check_lag(std::vector<double>& p, std::vector<double>& alpha, int deg, std::complex<double>& b, std::complex<double>& c, std::complex<double> z, double r, int& conv, double& berr, double& cond) {
191 int k;
192 std::complex<double> a;
193
194 // Evaluate polynomial and derivatives
195 a = p[deg];
196 b = 0.0;
197 c = 0.0;
198 berr = alpha[deg];
199
200 for (k = deg - 1; k >= 0; k--) {
201 c = z * c + b;
202 b = z * b + a;
203 a = z * a + p[k];
204 berr = r * berr + alpha[k];
205 }
206
207 // Laguerre correction/ backward error and condition
208 if (abs(a) > eps * berr) {
209 b = b / a;
210 c = pow(b, 2) - 2.0 * (c / a);
211
212 if (check_nan_inf(b) || check_nan_inf(c))
213 conv = -1;
214 } else {
215 cond = berr / (r * abs(b));
216 berr = abs(a) / berr;
217 conv = 1;
218 }
219}
220
231void modify_lag(int deg, std::complex<double>& b, std::complex<double>& c, std::complex<double> z, int j, std::vector<std::complex<double>>& roots) {
232 std::complex<double> t;
233
234 // Aberth correction terms
235 for (int k = 0; k < j - 1; k++) {
236 t = 1.0 / (z - roots[k]);
237 b = b - t;
238 c = c - pow(t, 2);
239 }
240
241 for (int k = j + 1; k <= deg; k++) {
242 t = 1.0 / (z - roots[k]);
243 b = b - t;
244 c = c - pow(t, 2);
245 }
246
247 // Laguerre correction
248 t = sqrt(
249 (double)(deg - 1) * (
250 (double)deg * c - pow(b, 2)
251 )
252 );
253 c = b + t;
254 b = b - t;
255
256 if (abs(b) > abs(c)) {
257 c = (double)deg / b;
258 } else {
259 c = (double)deg / c;
260 }
261}
262
274void laguerre(std::vector<double>& poly, int deg, std::vector<std::complex<double>>& roots, std::vector<int>& conv, int itmax) {
275 int i, j, nz;
276 double r;
277 std::vector<double> berr(deg); // Vector to store the backward errors.
278 std::vector<double> cond(deg); // Vector to store the condition numbers.
279 std::vector<double> alpha(deg + 1);
280 std::complex<double> b, c, z;
281
282 // Precheck
283 for (i = 0; i <= deg; i++)
284 alpha[i] = abs(poly[i]);
285
286 if (alpha[deg] < small) {
287 std::cout << "Warning: leading coefficient too small." << std::endl;
288 return;
289 }
290 /*
291 else if (deg == 1) {
292 roots[0] = -poly[0] / poly[1];
293 conv[0] = 1;
294 berr[0] = 0.0;
295 cond[0] = (alpha[0] + alpha[1] * abs(roots[0])) / (abs(roots[0]) * alpha[1]);
296 return;
297 } else if (deg == 2) {
298 b = -poly[1] / (2.0 * poly[2]);
299 c = sqrt(pow(poly[1], 2) - 4.0 * poly[2] * poly[0]) / (2.0 * poly[2]);
300 roots[0] = b - c;
301 roots[1] = b + c;
302 conv[0] = 1;
303 conv[1] = 1;
304 berr[0] = 0.0;
305 berr[1] = 0.0;
306 cond[0] = (alpha[0] + alpha[1] * abs(roots[0]) + alpha[2] * pow(abs(roots[0]), 2)) / (abs(roots[0]) * abs(poly[1] + 2.0 * poly[2] * roots[0]));
307 cond[1] = (alpha[0] + alpha[1] * abs(roots[1]) + alpha[2] * pow(abs(roots[1]), 2)) / (abs(roots[1]) * abs(poly[1] + 2.0 * poly[2] * roots[1]));
308 return;
309 }*/
310
311 // Initial estimates
312 conv.assign(deg, 0);
313 nz = 0;
314 estimates(alpha, deg, roots, conv, nz);
315
316 // Main loop
317 for (i = 1; i <= deg + 1; i++)
318 alpha[i - 1] = alpha[i - 1] * (3.8 * (i - 1) + 1);
319
320 for (i = 1; i <= itmax; i++) {
321 for (j = 0; j < deg; j++) {
322 if (conv[j] == 0) {
323 z = roots[j];
324 r = abs(z);
325 if (r > 1.0) {
326 rcheck_lag(poly, alpha, deg, b, c, z, r, conv[j], berr[j], cond[j]);
327 } else {
328 check_lag(poly, alpha, deg, b, c, z, r, conv[j], berr[j], cond[j]);
329 }
330
331 if (conv[j] == 0) {
332 modify_lag(deg, b, c, z, j, roots);
333 roots[j] = roots[j] - c;
334 } else {
335 nz++;
336 if (nz == deg)
337 goto label10;
338 }
339 }
340 }
341 }
342
343 // Final check
344 label10:
345 if (*std::min_element(conv.begin(), conv.end()) == 1) {
346 return;
347 } else {
348 // Display a warning
349 std::cout << "Some root approximations did not converge or experienced overflow/underflow." << std::endl;
350 // Compute backward error and condition number for roots that did not converge.
351 // Note that this may produce overflow/underflow.
352 for (j = 0; j < deg; j++) {
353 if (conv[j] != 1) {
354 z = roots[j];
355 r = abs(z);
356
357 if (r > 1.0) {
358 z = 1.0 / z;
359 r = 1.0 / r;
360 c = 0.0;
361 b = poly[0];
362 berr[j] = alpha[0];
363
364 for (i = 1; i < deg + 1; i++) {
365 // std::cout << "sob sob " << i << "\n";
366 c = z * c + b;
367 b = z * b + poly[i];
368 berr[j] = r * berr[j] + alpha[i];
369 }
370
371 cond[j] = berr[j] / abs((double)deg * b - z * c);
372 berr[j] = abs(b) / berr[j];
373 } else {
374 c = 0.0;
375 b = poly[deg];
376 berr[j] = alpha[deg];
377
378 for (i = deg - 1; i >= 0; i--) {
379 // std::cout << "hiiiii :3 " << i << "\n";
380 c = z * c + b;
381 b = z * b + poly[i];
382 berr[j] = r * berr[j] + alpha[i];
383 }
384
385 cond[j] = berr[j] / (r * abs(c));
386 berr[j] = abs(b) / berr[j];
387 }
388 }
389 }
390
391 }
392}
const double big
Definition L18_or.h:11
const double small
Definition L18_or.h:12
const double eps
Definition L18_or.h:10
bool check_nan_inf(std::complex< double > a)
Check if a complex number contains NaN or Inf values.
Definition L18_or.h:120
void rcheck_lag(std::vector< double > &p, std::vector< double > &alpha, int deg, std::complex< double > &b, std::complex< double > &c, std::complex< double > z, double r, int &conv, double &berr, double &cond)
Perform Laguerre correction, compute backward error, and condition.
Definition L18_or.h:140
void estimates(std::vector< double > &alpha, int deg, std::vector< std::complex< double > > &roots, std::vector< int > &conv, int &nz)
Estimate roots of a polynomial.
Definition L18_or.h:60
double cross(std::vector< int > &h, std::vector< double > &a, int c, int i)
Calculate the determinant between two points.
Definition L18_or.h:23
void modify_lag(int deg, std::complex< double > &b, std::complex< double > &c, std::complex< double > z, int j, std::vector< std::complex< double > > &roots)
Modify Laguerre correction based on Aberth's method.
Definition L18_or.h:231
void check_lag(std::vector< double > &p, std::vector< double > &alpha, int deg, std::complex< double > &b, std::complex< double > &c, std::complex< double > z, double r, int &conv, double &berr, double &cond)
Perform Laguerre correction, compute backward error, and condition.
Definition L18_or.h:190
void laguerre(std::vector< double > &poly, int deg, std::vector< std::complex< double > > &roots, std::vector< int > &conv, int itmax)
Find the roots of a polynomial using Laguerre's method.
Definition L18_or.h:274
void conv_hull(int n, std::vector< double > &a, std::vector< int > &h, int &c)
Calculate the convex hull of a set of points.
Definition L18_or.h:40
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
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