CR2RE Pipeline Reference Manual 1.6.2
irplib_polynomial-test.c
1/* $Id: irplib_polynomial-test.c,v 1.37 2013-01-29 08:43:33 jtaylor Exp $
2 *
3 * This file is part of the ESO Common Pipeline Library
4 * Copyright (C) 2001-2004 European Southern Observatory
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02111-1307 USA
19 */
20
21/*
22 * $Author: jtaylor $
23 * $Date: 2013-01-29 08:43:33 $
24 * $Revision: 1.37 $
25 * $Name: not supported by cvs2svn $
26 */
27
28/*-----------------------------------------------------------------------------
29 Includes
30 -----------------------------------------------------------------------------*/
31
32#ifdef HAVE_CONFIG_H
33#include <config.h>
34#endif
35
36#include <irplib_polynomial.h>
37#include <math.h>
38#include <float.h>
39#include <stdint.h>
40
41/*-----------------------------------------------------------------------------
42 Defines
43 -----------------------------------------------------------------------------*/
44
45#define MAXDEGREE 14
46
47#define irplib_polynomial_test_root_all(A, B, C, D, E) \
48 irplib_polynomial_test_root_all_macro(A, B, C, D, E, __LINE__)
49
50/*-----------------------------------------------------------------------------
51 Static functions
52 -----------------------------------------------------------------------------*/
53
54static cpl_error_code irplib_polynomial_multiply_1d_factor(cpl_polynomial *,
55 const cpl_vector *,
56 cpl_size);
57static void irplib_polynomial_solve_1d_all_test(void);
58
59static void irplib_polynomial_test_root_all_macro(const cpl_vector *, cpl_size,
60 double, double, double,
61 unsigned);
62
63/*-----------------------------------------------------------------------------
64 Main
65 -----------------------------------------------------------------------------*/
66int main(void)
67{
68 /* Initialize CPL */
69 cpl_test_init(PACKAGE_BUGREPORT, CPL_MSG_WARNING);
70
71 irplib_polynomial_solve_1d_all_test();
72
73 return cpl_test_end(0);
74}
75
76
77/*----------------------------------------------------------------------------*/
84/*----------------------------------------------------------------------------*/
85static void irplib_polynomial_solve_1d_all_test(void)
86{
87
88 cpl_polynomial * p2d = cpl_polynomial_new(2);
89 cpl_polynomial * p1d = cpl_polynomial_new(1);
90 cpl_vector * xtrue = cpl_vector_new(2);
91 const cpl_size maxdegree = 4; /* Largest robustly handled degree */
92 cpl_size nreal = 0;
93 cpl_size i;
94 cpl_error_code code;
95#if MAXDEGREE > 8
96 double stol, rtol;
97#endif
98
99 code = irplib_polynomial_solve_1d_all(NULL, xtrue, &nreal);
100 cpl_test_eq_error(code, CPL_ERROR_NULL_INPUT);
101
102 code = irplib_polynomial_solve_1d_all(p1d, NULL, &nreal);
103 cpl_test_eq_error(code, CPL_ERROR_NULL_INPUT);
104
105 code = irplib_polynomial_solve_1d_all(p1d, xtrue, NULL);
106 cpl_test_eq_error(code, CPL_ERROR_NULL_INPUT);
107
108 code = irplib_polynomial_solve_1d_all(p2d, xtrue, &nreal);
109 cpl_test_eq_error(code, CPL_ERROR_INVALID_TYPE);
110
111 code = irplib_polynomial_solve_1d_all(p1d, xtrue, &nreal);
112 cpl_test_eq_error(code, CPL_ERROR_DATA_NOT_FOUND);
113
114 /* Create a 1st degree polynomial, x = 0 */
115 i = 1;
116 code = cpl_polynomial_set_coeff(p1d, &i, 1.0);
117 cpl_test_eq_error(code, CPL_ERROR_NONE);
118 code = irplib_polynomial_solve_1d_all(p1d, xtrue, &nreal);
119 cpl_test_eq_error(code, CPL_ERROR_INCOMPATIBLE_INPUT);
120
121 cpl_polynomial_delete(p1d);
122 cpl_polynomial_delete(p2d);
123
124 for (nreal = 1; nreal <= maxdegree; nreal++) {
125 /* A single, zero-valued root with multiplicity equal to degree */
126 double xreal = 0.0;
127
128
129 cpl_vector_set_size(xtrue, nreal);
130
131 (void)cpl_vector_fill(xtrue, xreal);
132
133 irplib_polynomial_test_root_all(xtrue, nreal, CPL_MATH_PI,
134 2.0 * DBL_EPSILON, 2.0 * DBL_EPSILON);
135
136 /* A single, non-zero integer root with multiplicity equal to degree */
137 xreal = 1.0;
138
139 (void)cpl_vector_fill(xtrue, xreal);
140
141 irplib_polynomial_test_root_all(xtrue, nreal, 1.0,
142 2.0 * DBL_EPSILON, 2.0 * DBL_EPSILON);
143
144 /* degree distinct real roots - with rounding */
145 for (i = 0; i < nreal; i++) {
146 (void)cpl_vector_set(xtrue, i, 2.0 * (double)i - CPL_MATH_E);
147 }
148
149 irplib_polynomial_test_root_all(xtrue, nreal, CPL_MATH_PI,
150 20.0 * DBL_EPSILON,
151 550.0 * DBL_EPSILON);
152
153 /* All real, one zero, one positive, rest negative, sum zero */
154 for (i = 0; i < nreal-1; i++) {
155 (void)cpl_vector_set(xtrue, nreal-i-2, (double)(-i));
156 }
157 (void)cpl_vector_set(xtrue, nreal-1, (double)(nreal-1)); /* FIXME: ? */
158
159 irplib_polynomial_test_root_all(xtrue, nreal, CPL_MATH_PI,
160 16.0*DBL_EPSILON, 600.0*DBL_EPSILON);
161
162 if (nreal < 2) continue;
163 /* Two complex, conjugate roots, the rest is real
164 with multiplicity degree-2 */
165
166 (void)cpl_vector_fill(xtrue, 2.0);
167 (void)cpl_vector_set(xtrue, nreal-2, -1.0);
168 (void)cpl_vector_set(xtrue, nreal-1, 1.0);
169
170 irplib_polynomial_test_root_all(xtrue, nreal-2, CPL_MATH_PI,
171 30.0*DBL_EPSILON, 25.0*DBL_EPSILON);
172
173 if (nreal < 3) continue;
174 if (nreal > 4) {
175 /* Two real roots, the smaller with multiplicity degree-1 */
176 (void)cpl_vector_fill(xtrue, 1.0);
177 (void)cpl_vector_set(xtrue, nreal - 1 , 2.0);
178
179 irplib_polynomial_test_root_all(xtrue, nreal, CPL_MATH_PI,
180 DBL_EPSILON, DBL_EPSILON);
181 /* Same with negative roots */
182 (void)cpl_vector_fill(xtrue, -1.0);
183 (void)cpl_vector_set(xtrue, 0 , -2.0);
184
185 irplib_polynomial_test_root_all(xtrue, nreal, CPL_MATH_PI,
186 DBL_EPSILON, DBL_EPSILON);
187 /* Two real roots, the larger with multiplicity degree-1 */
188 (void)cpl_vector_fill(xtrue, 2.0);
189 (void)cpl_vector_set(xtrue, 0, 1.0);
190
191 irplib_polynomial_test_root_all(xtrue, nreal, CPL_MATH_PI,
192 DBL_EPSILON, DBL_EPSILON);
193 }
194
195 if (nreal > 3) continue;
196
197 /* Same with negative roots */
198 (void)cpl_vector_fill(xtrue, -2.0 * FLT_EPSILON);
199 (void)cpl_vector_set(xtrue, 0, -1.0);
200
201 irplib_polynomial_test_root_all(xtrue, nreal, CPL_MATH_PI,
202 DBL_EPSILON, 2.0*DBL_EPSILON);
203
204 /* A more extreme case: Same with negative roots */
205#if defined SIZE_MAX && SIZE_MAX <= 4294967295
206 /* Fails on 32-bit - also w. -0.1 * FLT_EPSILON */
207#else
208 (void)cpl_vector_fill(xtrue, -0.2 * FLT_EPSILON);
209
210 (void)cpl_vector_set(xtrue, 0, -1.0);
211
212 irplib_polynomial_test_root_all(xtrue, nreal, CPL_MATH_PI,
213 FLT_EPSILON, 3.0*DBL_EPSILON);
214#endif
215
216
217 if (nreal != 3) {
218 /* The most extreme case: Same with negative roots */
219 (void)cpl_vector_fill(xtrue, -2.0 * DBL_EPSILON);
220 (void)cpl_vector_set(xtrue, 0, -1.0);
221
222 irplib_polynomial_test_root_all(xtrue, nreal, CPL_MATH_PI,
223 DBL_EPSILON, 2.0*DBL_EPSILON);
224
225
226 (void)cpl_vector_set(xtrue, 0, -1.0);
227 (void)cpl_vector_set(xtrue, 1, -2.0e-4 * FLT_EPSILON);
228 (void)cpl_vector_set(xtrue, 2, 2.0e-4 * FLT_EPSILON);
229
230 irplib_polynomial_test_root_all(xtrue, nreal, CPL_MATH_PI,
231 FLT_EPSILON, 2.0*DBL_EPSILON);
232 }
233
234 /* Two complex conjugate roots, remaining:
235 small, with multiplicity degree-2 */
236 (void)cpl_vector_fill(xtrue, 2.0*DBL_EPSILON);
237 (void)cpl_vector_set(xtrue, nreal - 2 , 3.0);
238 (void)cpl_vector_set(xtrue, nreal - 1 , 2.0);
239
240 irplib_polynomial_test_root_all(xtrue, nreal - 2, CPL_MATH_PI,
241 4.0 * DBL_EPSILON, DBL_EPSILON);
242
243 /* Two complex conjugate roots with small real part, remaining:
244 with multiplicity degree-2 */
245 (void)cpl_vector_fill(xtrue, 3.0);
246 (void)cpl_vector_set(xtrue, nreal - 2 , -1.0);
247 (void)cpl_vector_set(xtrue, nreal - 1 , 2.0);
248
249 irplib_polynomial_test_root_all(xtrue, nreal - 2, CPL_MATH_PI,
250 6.0*DBL_EPSILON, 220.0*DBL_EPSILON);
251
252
253 }
254
255#if MAXDEGREE > 2
256 /* Cover branch fixing cancellation with one negative,
257 one positive near-zero and one positive root. */
258 nreal = 3;
259
260 cpl_vector_set_size(xtrue, nreal);
261
262 /* -2, epsilon, 1.5 */
263 (void)cpl_vector_set(xtrue, 0, -2.0);
264 (void)cpl_vector_set(xtrue, 1, 2.0 * DBL_EPSILON);
265 (void)cpl_vector_set(xtrue, 2, 1.5);
266
267 irplib_polynomial_test_root_all(xtrue, nreal, 1.0,
268 4.0*DBL_EPSILON, 30.0*DBL_EPSILON);
269
270 (void)cpl_vector_set(xtrue, 0, 1.0);
271 (void)cpl_vector_set(xtrue, 1, 2.0);
272 (void)cpl_vector_set(xtrue, 2, 1.0);
273
274 irplib_polynomial_test_root_all(xtrue, nreal-2, 1.0,
275 4.0*DBL_EPSILON, 30.0*DBL_EPSILON);
276
277#if MAXDEGREE > 3
278 nreal = 4;
279
280 cpl_vector_set_size(xtrue, nreal);
281
282 /* Depressed has zero as root */
283 (void)cpl_vector_set(xtrue, 0, -1.0);
284 (void)cpl_vector_set(xtrue, 1, 1.0);
285 (void)cpl_vector_set(xtrue, 2, 2.0);
286 (void)cpl_vector_set(xtrue, 3, 2.0);
287
288 irplib_polynomial_test_root_all(xtrue, nreal, CPL_MATH_PI,
289 2.0 * DBL_EPSILON, 2.0 * DBL_EPSILON);
290
291 /* Depressed has zero as root, and two complex roots*/
292 irplib_polynomial_test_root_all(xtrue, 2, CPL_MATH_PI,
293 2.0 * DBL_EPSILON, 2.0 * DBL_EPSILON);
294
295
296 /* Depressed is biquadratic, with 4 real roots */
297 (void)cpl_vector_set(xtrue, 0, -2.0);
298 (void)cpl_vector_set(xtrue, 1, -1.0);
299 (void)cpl_vector_set(xtrue, 2, 1.0);
300 (void)cpl_vector_set(xtrue, 3, 2.0);
301
302 irplib_polynomial_test_root_all(xtrue, nreal, CPL_MATH_PI,
303 2.0 * DBL_EPSILON, 2.0 * DBL_EPSILON);
304
305 /* Depressed is biquadratic, with 2 real roots */
306 (void)cpl_vector_set(xtrue, 0, -1.0);
307 (void)cpl_vector_set(xtrue, 1, 1.0);
308 (void)cpl_vector_set(xtrue, 2, 0.0);
309 (void)cpl_vector_set(xtrue, 3, 2.0);
310
311 irplib_polynomial_test_root_all(xtrue, 2, CPL_MATH_PI,
312 2.0 * DBL_EPSILON, 2.0 * DBL_EPSILON);
313
314 /* Depressed is biquadratic (the quadratic has real, negative roots),
315 with 0 real roots */
316 (void)cpl_vector_set(xtrue, 0, 1.0);
317 (void)cpl_vector_set(xtrue, 1, 2.0);
318 (void)cpl_vector_set(xtrue, 2, 1.0);
319 (void)cpl_vector_set(xtrue, 3, 3.0);
320
321 irplib_polynomial_test_root_all(xtrue, 0, CPL_MATH_PI,
322 10.0 * DBL_EPSILON, 10.0 * DBL_EPSILON);
323
324 /* roots: 0, 0, ai, -ai */
325 (void)cpl_vector_set(xtrue, 0, 0.0);
326 (void)cpl_vector_set(xtrue, 1, 0.0);
327 (void)cpl_vector_set(xtrue, 2, 0.0);
328 (void)cpl_vector_set(xtrue, 3, 2.0);
329
330 irplib_polynomial_test_root_all(xtrue, 2, CPL_MATH_PI,
331 2.0 * DBL_EPSILON, 2.0 * DBL_EPSILON);
332
333 p1d = cpl_polynomial_new(1);
334
335 i = 0;
336 cpl_polynomial_set_coeff(p1d, &i, -5.0);
337 i = 1;
338 cpl_polynomial_set_coeff(p1d, &i, -1.0);
339 i = 2;
340 cpl_polynomial_set_coeff(p1d, &i, -2.0);
341 i = 4;
342 cpl_polynomial_set_coeff(p1d, &i, 1.0);
343
344 code = irplib_polynomial_solve_1d_all(p1d, xtrue, &nreal);
345 cpl_test_eq_error(code, CPL_ERROR_NONE);
346
347 cpl_msg_info(cpl_func, "Computed roots (%" CPL_SIZE_FORMAT " real): ",
348 nreal);
349 if (cpl_msg_get_level() <= CPL_MSG_INFO)
350 cpl_vector_dump(xtrue, stderr);
351 cpl_msg_info(cpl_func, "Residual: %g -> %g ", cpl_vector_get(xtrue, 0),
352 cpl_polynomial_eval_1d(p1d, cpl_vector_get(xtrue, 0), NULL) );
353 cpl_msg_info(cpl_func, "Residual: %g -> %g ", cpl_vector_get(xtrue, 1),
354 cpl_polynomial_eval_1d(p1d, cpl_vector_get(xtrue, 1), NULL) );
355
356 cpl_polynomial_delete(p1d);
357
358 (void)cpl_vector_set(xtrue, 0, 0.0);
359 (void)cpl_vector_set(xtrue, 1, 2.0);
360 (void)cpl_vector_set(xtrue, 2, 1.0);
361 (void)cpl_vector_set(xtrue, 3, 1.0);
362
363 irplib_polynomial_test_root_all(xtrue, 0, CPL_MATH_PI,
364 2.0 * DBL_EPSILON, 2.0 * DBL_EPSILON);
365
366 (void)cpl_vector_set(xtrue, 0, -1.0);
367 (void)cpl_vector_set(xtrue, 1, 2.0);
368 (void)cpl_vector_set(xtrue, 2, 1.0);
369 (void)cpl_vector_set(xtrue, 3, 3.0);
370
371 irplib_polynomial_test_root_all(xtrue, 0, CPL_MATH_PI,
372 3.0 * DBL_EPSILON, 3.0 * DBL_EPSILON);
373#if MAXDEGREE > 4
374 nreal = 5;
375
376 cpl_vector_set_size(xtrue, nreal);
377
378 /* Depressed has zero as root */
379 (void)cpl_vector_set(xtrue, 0, -1.0);
380 (void)cpl_vector_set(xtrue, 1, 1.0);
381 (void)cpl_vector_set(xtrue, 2, 2.0);
382 (void)cpl_vector_set(xtrue, 3, 3.0);
383 (void)cpl_vector_set(xtrue, 4, 4.0);
384
385 irplib_polynomial_test_root_all(xtrue, nreal, CPL_MATH_PI,
386 48.0 * DBL_EPSILON, 2800.0 * DBL_EPSILON);
387
388 irplib_polynomial_test_root_all(xtrue, nreal-2, CPL_MATH_PI,
389 8.0 * DBL_EPSILON, 4000.0 * DBL_EPSILON);
390
391 irplib_polynomial_test_root_all(xtrue, nreal-4, CPL_MATH_PI,
392 4.0 * DBL_EPSILON, 600.0 * DBL_EPSILON);
393
394 (void)cpl_vector_set(xtrue, 0, -1.0);
395 (void)cpl_vector_set(xtrue, 1, 10.0);
396 (void)cpl_vector_set(xtrue, 2, 1.0);
397 (void)cpl_vector_set(xtrue, 3, 20.0);
398 (void)cpl_vector_set(xtrue, 4, 1.0);
399
400 irplib_polynomial_test_root_all(xtrue, 1, 1.0,
401 DBL_EPSILON, DBL_EPSILON);
402
403 (void)cpl_vector_set(xtrue, 0, 4.0);
404 (void)cpl_vector_set(xtrue, 1, -10.0);
405 (void)cpl_vector_set(xtrue, 2, 4.0);
406 (void)cpl_vector_set(xtrue, 3, 10.0);
407 (void)cpl_vector_set(xtrue, 4, 4.0);
408
409 irplib_polynomial_test_root_all(xtrue, 1, 1.0,
410 DBL_EPSILON, DBL_EPSILON);
411 irplib_polynomial_test_root_all(xtrue, 1, -1.0,
412 DBL_EPSILON, DBL_EPSILON);
413
414#if MAXDEGREE > 5
415 nreal = 6;
416
417 cpl_vector_set_size(xtrue, nreal);
418
419 (void)cpl_vector_set(xtrue, 0, -1.0);
420 (void)cpl_vector_set(xtrue, 1, 1.0);
421 (void)cpl_vector_set(xtrue, 2, 2.0);
422 (void)cpl_vector_set(xtrue, 3, 3.0);
423 (void)cpl_vector_set(xtrue, 4, 4.0);
424 (void)cpl_vector_set(xtrue, 5, 5.0);
425
426 irplib_polynomial_test_root_all(xtrue, nreal, CPL_MATH_PI,
427 240.0 * DBL_EPSILON, 50.0e3 * DBL_EPSILON);
428
429 irplib_polynomial_test_root_all(xtrue, nreal-2, CPL_MATH_PI,
430 10.0 * DBL_EPSILON, 25.0e3 * DBL_EPSILON);
431
432 irplib_polynomial_test_root_all(xtrue, nreal-4, CPL_MATH_PI,
433 12.0 * DBL_EPSILON, 1600.0 * DBL_EPSILON);
434
435 /* These two pairs of double roots are not handled well */
436 (void)cpl_vector_set(xtrue, 0, 1.0);
437 (void)cpl_vector_set(xtrue, 1, 1.0);
438 (void)cpl_vector_set(xtrue, 2, 3.0);
439 (void)cpl_vector_set(xtrue, 3, 3.0);
440 (void)cpl_vector_set(xtrue, 4, 2.0);
441 (void)cpl_vector_set(xtrue, 5, 1.0);
442
443 irplib_polynomial_test_root_all(xtrue, nreal-2, CPL_MATH_PI, 0.07, 0.1);
444
445 /* Single pair of double roots - somewhat better */
446 (void)cpl_vector_set(xtrue, 0, 1.0);
447 (void)cpl_vector_set(xtrue, 1, 1.0);
448 (void)cpl_vector_set(xtrue, 2, 2.0);
449 (void)cpl_vector_set(xtrue, 3, 1.0);
450 (void)cpl_vector_set(xtrue, 4, 3.0);
451 (void)cpl_vector_set(xtrue, 5, 3.0);
452
453 irplib_polynomial_test_root_all(xtrue, nreal-4, CPL_MATH_PI,
454 FLT_EPSILON, 1600.0 * DBL_EPSILON);
455
456 /* These three pairs of double roots are handled only without scaling */
457 (void)cpl_vector_set(xtrue, 0, 0.0);
458 (void)cpl_vector_set(xtrue, 1, 0.0);
459 (void)cpl_vector_set(xtrue, 2, 1.0);
460 (void)cpl_vector_set(xtrue, 3, 1.0);
461 (void)cpl_vector_set(xtrue, 4, 2.0);
462 (void)cpl_vector_set(xtrue, 5, 2.0);
463
464 irplib_polynomial_test_root_all(xtrue, nreal, 1.0,
465 DBL_EPSILON, DBL_EPSILON);
466
467 /* These three pairs of double roots are handled only without scaling */
468 (void)cpl_vector_set(xtrue, 0, 1.0);
469 (void)cpl_vector_set(xtrue, 1, 1.0);
470 (void)cpl_vector_set(xtrue, 2, 2.0);
471 (void)cpl_vector_set(xtrue, 3, 2.0);
472 (void)cpl_vector_set(xtrue, 4, 3.0);
473 (void)cpl_vector_set(xtrue, 5, 3.0);
474
475 irplib_polynomial_test_root_all(xtrue, nreal, 1.0,
476 10.0 * FLT_EPSILON, 1500.0 * DBL_EPSILON);
477
478 /* These three pairs of double roots are easy ... */
479 (void)cpl_vector_set(xtrue, 0, 0.0);
480 (void)cpl_vector_set(xtrue, 1, 0.0);
481 (void)cpl_vector_set(xtrue, 2, 0.0);
482 (void)cpl_vector_set(xtrue, 3, 0.0);
483 (void)cpl_vector_set(xtrue, 4, 1.0);
484 (void)cpl_vector_set(xtrue, 5, 1.0);
485
486 irplib_polynomial_test_root_all(xtrue, nreal, CPL_MATH_PI,
487 DBL_EPSILON, DBL_EPSILON);
488
489 /* A triple-root */
490 (void)cpl_vector_set(xtrue, 0, -1.0);
491 (void)cpl_vector_set(xtrue, 1, 1.0);
492 (void)cpl_vector_set(xtrue, 2, 1.0);
493 (void)cpl_vector_set(xtrue, 3, 1.0);
494 (void)cpl_vector_set(xtrue, 4, 2.0);
495 (void)cpl_vector_set(xtrue, 5, 3.0);
496
497 irplib_polynomial_test_root_all(xtrue, nreal, CPL_MATH_PI,
498 124.0 * FLT_EPSILON, 960e4 * DBL_EPSILON);
499
500#if MAXDEGREE > 6
501 nreal = 7;
502
503 cpl_vector_set_size(xtrue, nreal);
504
505 /* Effectively a triple root */
506 (void)cpl_vector_set(xtrue, 0, 0.0);
507 (void)cpl_vector_set(xtrue, 1, 0.0);
508 (void)cpl_vector_set(xtrue, 2, 0.0);
509 (void)cpl_vector_set(xtrue, 3, 0.0);
510 (void)cpl_vector_set(xtrue, 4, 1.0);
511 (void)cpl_vector_set(xtrue, 5, 1.0);
512 (void)cpl_vector_set(xtrue, 6, 1.0);
513
514 irplib_polynomial_test_root_all(xtrue, nreal, CPL_MATH_PI,
515 DBL_EPSILON, DBL_EPSILON);
516
517#if MAXDEGREE > 7
518 nreal = 8;
519
520 cpl_vector_set_size(xtrue, nreal);
521
522 (void)cpl_vector_set(xtrue, 0, -3.0);
523 (void)cpl_vector_set(xtrue, 1, -2.0);
524 (void)cpl_vector_set(xtrue, 2, -1.0);
525 (void)cpl_vector_set(xtrue, 3, 0.0);
526 (void)cpl_vector_set(xtrue, 4, 1.0);
527 (void)cpl_vector_set(xtrue, 5, 2.0);
528 (void)cpl_vector_set(xtrue, 6, 3.0);
529 (void)cpl_vector_set(xtrue, 7, 4.0);
530
531 irplib_polynomial_test_root_all(xtrue, nreal, CPL_MATH_PI,
532 50.0 * DBL_EPSILON, 350e3 * DBL_EPSILON);
533
534 (void)cpl_vector_set(xtrue, 0, 1.0);
535 (void)cpl_vector_set(xtrue, 1, 2.0);
536 (void)cpl_vector_set(xtrue, 2, 3.0);
537 (void)cpl_vector_set(xtrue, 3, 4.0);
538 (void)cpl_vector_set(xtrue, 4, 5.0);
539 (void)cpl_vector_set(xtrue, 5, 6.0);
540 (void)cpl_vector_set(xtrue, 6, 7.0);
541 (void)cpl_vector_set(xtrue, 7, 8.0);
542
543 irplib_polynomial_test_root_all(xtrue, nreal, CPL_MATH_PI,
544 5e5 * DBL_EPSILON, FLT_EPSILON);
545
546#if MAXDEGREE > 8
547
548 nreal = 0;
549 stol = DBL_EPSILON;
550 rtol = DBL_EPSILON * 1000.0;
551
552 do {
553 nreal++;
554 cpl_vector_set_size(xtrue, nreal);
555
556 for (i = 0; i < nreal; i++) {
557 (void)cpl_vector_set(xtrue, i, (double)i);
558 }
559
560 irplib_polynomial_test_root_all(xtrue, nreal, 1.0,
561 stol, rtol);
562 stol *= 6.0;
563 rtol *= 12.0;
564 } while (nreal < MAXDEGREE);
565
566#endif
567#endif
568#endif
569#endif
570#endif
571#endif
572#endif
573
574 cpl_vector_delete(xtrue);
575
576 return;
577}
578
579/*----------------------------------------------------------------------------*/
590/*----------------------------------------------------------------------------*/
591static
592cpl_error_code irplib_polynomial_multiply_1d_factor(cpl_polynomial * self,
593 const cpl_vector * roots,
594 cpl_size nreal)
595{
596
597 const cpl_size nroots = cpl_vector_get_size(roots);
598 cpl_size i, degree;
599 double prevroot = 0.0; /* Avoid (false) uninit warning */
600
601 cpl_ensure_code(self != NULL, CPL_ERROR_NULL_INPUT);
602 cpl_ensure_code(roots != NULL, CPL_ERROR_NULL_INPUT);
603 cpl_ensure_code(cpl_polynomial_get_dimension(self) == 1,
604 CPL_ERROR_ILLEGAL_INPUT);
605
606 cpl_ensure_code(nreal >= 0, CPL_ERROR_ILLEGAL_INPUT);
607 cpl_ensure_code(nreal <= nroots,
608 CPL_ERROR_ILLEGAL_INPUT);
609 cpl_ensure_code((cpl_vector_get_size(roots) - nreal) % 2 == 0,
610 CPL_ERROR_ILLEGAL_INPUT);
611
612 i = 0;
613 degree = cpl_polynomial_get_degree(self);
614 cpl_ensure_code(degree > 0 || cpl_polynomial_get_coeff(self, &i) != 0.0,
615 CPL_ERROR_DATA_NOT_FOUND);
616
617 for (i = 0; i < nreal; i++) {
618 const double root = cpl_vector_get(roots, i);
619 double prev = 0.0;
620 cpl_size j;
621
622 degree++;
623
624 for (j = degree; j >= 0; j--) {
625 double value = 0.0;
626 double newval;
627
628 if (j > 0) {
629 const cpl_size jj = j - 1;
630 newval = value = cpl_polynomial_get_coeff(self, &jj);
631 } else {
632 newval = 0.0;
633 }
634
635 if (j < degree) {
636 newval -= root * prev;
637 }
638
639 cpl_polynomial_set_coeff(self, &j, newval);
640
641 prev = value;
642
643 }
644
645 if (i > 0)
646 cpl_test_leq(prevroot, root);
647 prevroot = root;
648 }
649
650 /* Multiplication with the complex conjugate root
651 (x-a-ib) (x-a+ib) p(x) = (x-a)^2 p(x) + b^2 p(x) */
652 for (; i < nroots; i += 2) {
653 const double a = cpl_vector_get(roots, i);
654 const double b = cpl_vector_get(roots, i+1);
655 cpl_vector * aroot = cpl_vector_new(2);
656 cpl_polynomial * copy = cpl_polynomial_duplicate(self);
657
658 cpl_vector_fill(aroot, a);
659
660 irplib_polynomial_multiply_1d_factor(self, aroot, 2);
661
662 cpl_test_lt(0.0, fabs(b)); /* Complex root must be complex ... */
663
664 cpl_polynomial_multiply_scalar(copy, copy, b * b);
665
666 cpl_polynomial_add(self, self, copy);
667
668 cpl_vector_delete(aroot);
669 cpl_polynomial_delete(copy);
670
671 }
672 cpl_test_assert(i == nroots);
673
674 for (i = 0; i < nreal; i++) {
675 const double root = cpl_vector_get(roots, i);
676 double d = 0.0;
677 const double resid = cpl_polynomial_eval_1d(self, root, &d);
678 if (resid != 0.0) {
679 cpl_msg_info(cpl_func, "Real, true root %d/%d of %d degree 1D-"
680 "polynomial at %g has non-zero residual: %g "
681 "(gradient=%g)",
682 1+(int)i, (int)nreal, (int)degree, root, resid, d);
683 }
684 }
685
686 return CPL_ERROR_NONE;
687
688}
689
690/*----------------------------------------------------------------------------*/
703/*----------------------------------------------------------------------------*/
704static void
705irplib_polynomial_test_root_all_macro(const cpl_vector * self, cpl_size nreal,
706 double factor, double tolerance,
707 double resitol, unsigned line)
708{
709
710 const cpl_size nfail = cpl_test_get_failed();
711 const cpl_size degree = cpl_vector_get_size(self);
712 cpl_polynomial * p1d = cpl_polynomial_new(1);
713 cpl_vector * roots = cpl_vector_new(degree);
714 double maxerror = 0.0;
715 cpl_size i = 0;
716 cpl_size jreal;
717 cpl_error_code code;
718
719 code = cpl_polynomial_set_coeff(p1d, &i, factor);
720 cpl_test_eq_error(code, CPL_ERROR_NONE);
721
722 code = irplib_polynomial_multiply_1d_factor(p1d, self, nreal);
723 cpl_test_eq_error(code, CPL_ERROR_NONE);
724
725 code = irplib_polynomial_solve_1d_all(p1d, roots, &jreal);
726 cpl_test_eq_error(code, CPL_ERROR_NONE);
727
728 cpl_test_eq(jreal, nreal);
729 if (jreal != nreal) {
730 cpl_vector * jroots = (jreal == 0 && code) ? NULL :
731 cpl_vector_wrap(code ? jreal : CPL_MAX(nreal, jreal),
732 cpl_vector_get_data(roots));
733
734 cpl_msg_info(cpl_func, "1D-polynomial of degree %d:", (int)degree);
735 cpl_polynomial_dump(p1d, stderr);
736 cpl_msg_error(cpl_func, "True roots (%" CPL_SIZE_FORMAT
737 " real): (line=%u)", nreal, line);
738 cpl_vector_dump(self, stderr);
739 cpl_msg_error(cpl_func, "Computed roots (%" CPL_SIZE_FORMAT " real): ",
740 jreal);
741 cpl_vector_dump(jroots, stderr);
742 (void)cpl_vector_unwrap(jroots);
743 } else {
744 if (cpl_msg_get_level() < CPL_MSG_WARNING) {
745 CPL_DIAG_PRAGMA_PUSH_IGN(-Wcast-qual)
746 cpl_bivector * dump =
747 cpl_bivector_wrap_vectors((cpl_vector*)self, roots);
748 CPL_DIAG_PRAGMA_POP;
749
750 cpl_msg_warning(cpl_func, "Comparing %" CPL_SIZE_FORMAT " roots (%"
751 CPL_SIZE_FORMAT " real): (line=%u)",
752 degree, nreal, line);
753 cpl_bivector_dump(dump, stderr);
754 cpl_bivector_unwrap_vectors(dump);
755 }
756
757 for (i = 0; i < jreal; i++) {
758 const double root = cpl_vector_get(roots, i);
759 const double residual = cpl_polynomial_eval_1d(p1d, root, NULL);
760
761 cpl_test_abs(root, cpl_vector_get(self, i), tolerance);
762 if (fabs(root - cpl_vector_get(self, i)) > maxerror)
763 maxerror = fabs(root - cpl_vector_get(self, i));
764
765 cpl_test_abs(residual, 0.0, resitol);
766
767 }
768
769 for (i = nreal; i < degree; i++) {
770 const double root = cpl_vector_get(roots, i);
771
772 cpl_test_abs(root, cpl_vector_get(self, i), tolerance);
773 if (fabs(root - cpl_vector_get(self, i)) > maxerror)
774 maxerror = fabs(root - cpl_vector_get(self, i));
775
776 /* FIXME: Verify residual as well */
777
778 }
779
780 if (cpl_test_get_failed() != nfail) {
781 cpl_msg_error(cpl_func, "Line %u failed test(s) on %d/%d real "
782 "roots:", line, (int)nreal, (int)degree);
783 cpl_vector_dump(self, stderr);
784 } else if (maxerror > 0.0) {
785 cpl_msg_info(cpl_func, "Max-error at degree=%d (line=%u): %g",
786 (int)degree, line, maxerror);
787 }
788 }
789
790 cpl_vector_delete(roots);
791 cpl_polynomial_delete(p1d);
792
793 return;
794}