BmnRoot
26.10.0-18-g4e3414f9
Software framework of the BM@N experiment
Toggle main menu visibility
Loading...
Searching...
No Matches
PolynomComplexRoots.h
Go to the documentation of this file.
1
/* Copyright (C) 2020 Facility for Antiproton and Ion Research in Europe,
2
Darmstadt SPDX-License-Identifier: GPL-3.0-only
3
Authors: Pierre-Alain Loizeau [committer] */
4
5
#include <iomanip>
6
#include <iostream>
7
#include <math.h>
8
#include <stdlib.h>
9
10
#define maxiter 500
11
12
//
13
// Extract individual real or complex roots from list of quadratic factors
14
//
15
int
roots
(
float
* a,
int
n
,
float
* wr,
float
* wi)
16
{
17
float
sq, b2, c, disc;
18
int
m
, numroots;
19
20
m
=
n
;
21
numroots = 0;
22
while
(
m
> 1) {
23
b2 = -0.5 * a[
m
- 2];
24
c = a[
m
- 1];
25
disc = b2 * b2 - c;
26
if
(disc < 0.0) {
// complex roots
27
sq =
sqrt
(-disc);
28
wr[
m
- 2] = b2;
29
wi[
m
- 2] = sq;
30
wr[
m
- 1] = b2;
31
wi[
m
- 1] = -sq;
32
numroots += 2;
33
}
else
{
// real roots
34
sq =
sqrt
(disc);
35
wr[
m
- 2] =
fabs
(b2) + sq;
36
if
(b2 < 0.0)
37
wr[
m
- 2] = -wr[
m
- 2];
38
if
(wr[
m
- 2] == 0)
39
wr[
m
- 1] = 0;
40
else
{
41
wr[
m
- 1] = c / wr[
m
- 2];
42
numroots += 2;
43
}
44
wi[
m
- 2] = 0.0;
45
wi[
m
- 1] = 0.0;
46
}
47
m
-= 2;
48
}
49
if
(
m
== 1) {
50
wr[0] = -a[0];
51
wi[0] = 0.0;
52
numroots++;
53
}
54
return
numroots;
55
}
56
//
57
// Deflate polynomial 'a' by dividing out 'quad'. Return quotient
58
// polynomial in 'b' and error metric based on remainder in 'err'.
59
//
60
void
deflate
(
float
* a,
int
n
,
float
* b,
float
* quad,
float
* err)
61
{
62
float
r, s;
63
int
i
;
64
65
r = quad[1];
66
s = quad[0];
67
68
b[1] = a[1] - r;
69
70
for
(
i
= 2;
i
<=
n
;
i
++) {
71
b[
i
] = a[
i
] - r * b[
i
- 1] - s * b[
i
- 2];
72
}
73
*err =
fabs
(b[
n
]) +
fabs
(b[
n
- 1]);
74
}
75
//
76
// Find quadratic factor using Bairstow's method (quadratic Newton method).
77
// A number of ad hoc safeguards are incorporated to prevent stalls due
78
// to common difficulties, such as zero slope at iteration point, and
79
// convergence problems.
80
//
81
// Bairstow's method is sensitive to the starting estimate. It is possible
82
// for convergence to fail or for 'wild' values to trigger an overflow.
83
//
84
// It is advisable to institute traps for these problems. (To do!)
85
//
86
void
find_quad
(
float
* a,
int
n
,
float
* b,
float
* quad,
float
* err,
int
* iter)
87
{
88
float
*c, dn, dr, ds, drn, dsn, eps, r, s;
89
int
i
;
90
91
c =
new
float
[
n
+ 1];
92
c[0] = 1.0;
93
r = quad[1];
94
s = quad[0];
95
eps = 1e-15;
96
*iter = 1;
97
98
do
{
99
if
(*iter >
maxiter
)
100
break
;
101
if
(((*iter) % 200) == 0) {
102
eps *= 10.0;
103
}
104
b[1] = a[1] - r;
105
c[1] = b[1] - r;
106
107
for
(
i
= 2;
i
<=
n
;
i
++) {
108
b[
i
] = a[
i
] - r * b[
i
- 1] - s * b[
i
- 2];
109
c[
i
] = b[
i
] - r * c[
i
- 1] - s * c[
i
- 2];
110
}
111
dn = c[
n
- 1] * c[
n
- 3] - c[
n
- 2] * c[
n
- 2];
112
drn = b[
n
] * c[
n
- 3] - b[
n
- 1] * c[
n
- 2];
113
dsn = b[
n
- 1] * c[
n
- 1] - b[
n
] * c[
n
- 2];
114
115
if
(
fabs
(dn) < 1e-10) {
116
if
(dn < 0.0)
117
dn = -1e-8;
118
else
119
dn = 1e-8;
120
}
121
dr = drn / dn;
122
ds = dsn / dn;
123
r += dr;
124
s += ds;
125
(*iter)++;
126
}
while
((
fabs
(dr) +
fabs
(ds)) > eps);
127
quad[0] = s;
128
quad[1] = r;
129
*err =
fabs
(ds) +
fabs
(dr);
130
delete
[] c;
131
}
132
//
133
// Differentiate polynomial 'a' returning result in 'b'.
134
//
135
void
diff_poly
(
float
* a,
int
n
,
float
* b)
136
{
137
float
coef;
138
int
i
;
139
140
coef = (float)
n
;
141
b[0] = 1.0;
142
for
(
i
= 1;
i
<
n
;
i
++) {
143
b[
i
] = a[
i
] * ((float)(
n
-
i
)) / coef;
144
}
145
}
146
//
147
// Attempt to find a reliable estimate of a quadratic factor using modified
148
// Bairstow's method with provisions for 'digging out' factors associated
149
// with multiple roots.
150
//
151
// This resursive routine operates on the principal that differentiation of
152
// a polynomial reduces the order of all multiple roots by one, and has no
153
// other roots in common with it. If a root of the differentiated polynomial
154
// is a root of the original polynomial, there must be multiple roots at
155
// that location. The differentiated polynomial, however, has lower order
156
// and is easier to solve.
157
//
158
// When the original polynomial exhibits convergence problems in the
159
// neighborhood of some potential root, a best guess is obtained and tried
160
// on the differentiated polynomial. The new best guess is applied
161
// recursively on continually differentiated polynomials until failure
162
// occurs. At this point, the previous polynomial is accepted as that with
163
// the least number of roots at this location, and its estimate is
164
// accepted as the root.
165
//
166
void
recurse
(
float
* a,
int
n
,
float
* b,
int
m
,
float
* quad,
float
* err,
int
* iter)
167
{
168
float
*c, *x, rs[2], tst;
169
170
if
(
fabs
(b[
m
]) < 1e-16)
171
m
--;
// this bypasses roots at zero
172
if
(
m
== 2) {
173
quad[0] = b[2];
174
quad[1] = b[1];
175
*err = 0;
176
*iter = 0;
177
return
;
178
}
179
c =
new
float
[
m
+ 1];
180
x =
new
float
[
n
+ 1];
181
c[0] = x[0] = 1.0;
182
rs[0] = quad[0];
183
rs[1] = quad[1];
184
*iter = 0;
185
find_quad
(b,
m
, c, rs, err, iter);
186
tst =
fabs
(rs[0] - quad[0]) +
fabs
(rs[1] - quad[1]);
187
if
(*err < 1e-12) {
188
quad[0] = rs[0];
189
quad[1] = rs[1];
190
}
191
// tst will be 'large' if we converge to wrong root
192
if
(((*iter > 5) && (tst < 1e-4)) || ((*iter > 20) && (tst < 1e-1))) {
193
diff_poly
(b,
m
, c);
194
recurse
(a,
n
, c,
m
- 1, rs, err, iter);
195
quad[0] = rs[0];
196
quad[1] = rs[1];
197
}
198
delete
[] x;
199
delete
[] c;
200
}
201
//
202
// Top level routine to manage the determination of all roots of the given
203
// polynomial 'a', returning the quadratic factors (and possibly one linear
204
// factor) in 'x'.
205
//
206
void
get_quads
(
float
* a,
int
n
,
float
* quad,
float
* x)
207
{
208
float
*b, *z, err, tmp;
209
int
iter,
i
,
m
;
210
211
if
((tmp = a[0]) != 1.0) {
212
a[0] = 1.0;
213
for
(
i
= 1;
i
<=
n
;
i
++) {
214
a[
i
] /= tmp;
215
}
216
}
217
if
(
n
== 2) {
218
x[0] = a[1];
219
x[1] = a[2];
220
return
;
221
}
else
if
(
n
== 1) {
222
x[0] = a[1];
223
return
;
224
}
225
m
=
n
;
226
b =
new
float
[
n
+ 1];
227
z =
new
float
[
n
+ 1];
228
b[0] = 1.0;
229
for
(
i
= 0;
i
<=
n
;
i
++) {
230
z[
i
] = a[
i
];
231
x[
i
] = 0.0;
232
}
233
do
{
234
if
(
n
>
m
) {
235
quad[0] = 3.14159e-1;
236
quad[1] = 2.78127e-1;
237
}
238
do
{
// This loop tries to assure convergence
239
for
(
i
= 0;
i
< 5;
i
++) {
240
find_quad
(z,
m
, b, quad, &err, &iter);
241
if
((err > 1e-7) || (iter >
maxiter
)) {
242
diff_poly
(z,
m
, b);
243
recurse
(z,
m
, b,
m
- 1, quad, &err, &iter);
244
}
245
deflate
(z,
m
, b, quad, &err);
246
if
(err < 0.001)
247
break
;
248
quad[0] = 9999.;
249
quad[1] = 9999.;
250
}
251
if
(err > 0.01) {
252
printf(
"Error! Convergence failure in quadratic x^2 + r*x + s.\n"
);
253
exit(1);
254
}
255
}
while
(err > 0.01);
256
x[
m
- 2] = quad[1];
257
x[
m
- 1] = quad[0];
258
m
-= 2;
259
for
(
i
= 0;
i
<=
m
;
i
++) {
260
z[
i
] = b[
i
];
261
}
262
}
while
(
m
> 2);
263
if
(
m
== 2) {
264
x[0] = b[1];
265
x[1] = b[2];
266
}
else
267
x[0] = b[1];
268
delete
[] z;
269
delete
[] b;
270
}
271
272
void
polynomComplexRoots
(
float
* wr,
float
* wi,
int
n
,
float
* a,
int
& numr)
273
{
274
float
* quad =
new
float
[2];
275
float
* x =
new
float
[
n
];
276
277
// initialize estimate for 1st root pair
278
quad[0] = 2.71828e-1;
279
quad[1] = 3.14159e-1;
280
281
// get roots
282
get_quads
(a,
n
, quad, x);
283
numr =
roots
(x,
n
, wr, wi);
284
285
delete
[] quad;
286
delete
[] x;
287
}
fabs
friend F32vec4 fabs(const F32vec4 &a)
Definition
P4_F32vec4.h:52
i
int i
Definition
P4_F32vec4.h:22
m
__m128 m
Definition
P4_F32vec4.h:27
polynomComplexRoots
void polynomComplexRoots(float *wr, float *wi, int n, float *a, int &numr)
Definition
PolynomComplexRoots.h:272
roots
int roots(float *a, int n, float *wr, float *wi)
Definition
PolynomComplexRoots.h:15
diff_poly
void diff_poly(float *a, int n, float *b)
Definition
PolynomComplexRoots.h:135
maxiter
#define maxiter
Definition
PolynomComplexRoots.h:10
find_quad
void find_quad(float *a, int n, float *b, float *quad, float *err, int *iter)
Definition
PolynomComplexRoots.h:86
deflate
void deflate(float *a, int n, float *b, float *quad, float *err)
Definition
PolynomComplexRoots.h:60
get_quads
void get_quads(float *a, int n, float *quad, float *x)
Definition
PolynomComplexRoots.h:206
recurse
void recurse(float *a, int n, float *b, int m, float *quad, float *err, int *iter)
Definition
PolynomComplexRoots.h:166
sqrt
RVec< PromoteType< T > > sqrt(const RVec< T > &v)
n
*brief user defined string literal for JSON values *sa std::size_t n
Definition
json.hpp:20362
decoder
PolynomComplexRoots.h
Generated on
for BmnRoot by
1.17.0