UVES Pipeline Reference Manual  5.3.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 
40 /*-----------------------------------------------------------------------------
41  Defines
42  -----------------------------------------------------------------------------*/
43 
44 #define MAXDEGREE 6
45 
46 #define irplib_polynomial_test_root_all(A, B, C, D, E) \
47  irplib_polynomial_test_root_all_macro(A, B, C, D, E, __LINE__)
48 
49 /*-----------------------------------------------------------------------------
50  Static functions
51  -----------------------------------------------------------------------------*/
52 
53 static cpl_error_code irplib_polynomial_multiply_1d_factor(cpl_polynomial *,
54  const cpl_vector *,
55  cpl_size);
56 static void irplib_polynomial_solve_1d_all_test(void);
57 
58 static void irplib_polynomial_test_root_all_macro(const cpl_vector *, cpl_size,
59  double, double, double,
60  unsigned);
61 
62 /*-----------------------------------------------------------------------------
63  Main
64  -----------------------------------------------------------------------------*/
65 int main(void)
66 {
67  /* Initialize CPL */
68  cpl_test_init(PACKAGE_BUGREPORT, CPL_MSG_WARNING);
69 
70  irplib_polynomial_solve_1d_all_test();
71 
72  return cpl_test_end(0);
73 }
74 
75 
76 /*----------------------------------------------------------------------------*/
83 /*----------------------------------------------------------------------------*/
84 static void irplib_polynomial_solve_1d_all_test(void)
85 {
86 
87  cpl_polynomial * p2d = cpl_polynomial_new(2);
88  cpl_polynomial * p1d = cpl_polynomial_new(1);
89  cpl_vector * xtrue = cpl_vector_new(2);
90  const cpl_size maxdegree = 4; /* Largest robustly handled degree */
91  cpl_size nreal = 0;
92  cpl_size i;
93 
94  cpl_test_eq(irplib_polynomial_solve_1d_all(NULL, xtrue, &nreal),
95  CPL_ERROR_NULL_INPUT);
96  cpl_test_error(CPL_ERROR_NULL_INPUT);
97 
98  cpl_test_eq(irplib_polynomial_solve_1d_all(p1d, NULL, &nreal),
99  CPL_ERROR_NULL_INPUT);
100  cpl_test_error(CPL_ERROR_NULL_INPUT);
101 
102  cpl_test_eq(irplib_polynomial_solve_1d_all(p1d, xtrue, NULL),
103  CPL_ERROR_NULL_INPUT);
104  cpl_test_error(CPL_ERROR_NULL_INPUT);
105 
106  cpl_test_eq(irplib_polynomial_solve_1d_all(p2d, xtrue, &nreal),
107  CPL_ERROR_INVALID_TYPE);
108  cpl_test_error(CPL_ERROR_INVALID_TYPE);
109 
110  cpl_test_eq(irplib_polynomial_solve_1d_all(p1d, xtrue, &nreal),
111  CPL_ERROR_DATA_NOT_FOUND);
112  cpl_test_error(CPL_ERROR_DATA_NOT_FOUND);
113 
114  /* Create a 1st degree polynomial, x = 0 */
115  i = 1;
116  cpl_test_eq(cpl_polynomial_set_coeff(p1d, &i, 1.0), CPL_ERROR_NONE);
117  cpl_test_eq(irplib_polynomial_solve_1d_all(p1d, xtrue, &nreal),
118  CPL_ERROR_INCOMPATIBLE_INPUT);
119  cpl_test_error(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  300.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  (void)cpl_vector_fill(xtrue, -0.2 * FLT_EPSILON);
206  (void)cpl_vector_set(xtrue, 0, -1.0);
207 
208  irplib_polynomial_test_root_all(xtrue, nreal, CPL_MATH_PI,
209  FLT_EPSILON, 3.0*DBL_EPSILON);
210 
211  if (nreal != 3) {
212  /* The most extreme case: Same with negative roots */
213  (void)cpl_vector_fill(xtrue, -2.0 * DBL_EPSILON);
214  (void)cpl_vector_set(xtrue, 0, -1.0);
215 
216  irplib_polynomial_test_root_all(xtrue, nreal, CPL_MATH_PI,
217  DBL_EPSILON, 2.0*DBL_EPSILON);
218 
219 
220  (void)cpl_vector_set(xtrue, 0, -1.0);
221  (void)cpl_vector_set(xtrue, 1, -2.0e-4 * FLT_EPSILON);
222  (void)cpl_vector_set(xtrue, 2, 2.0e-4 * FLT_EPSILON);
223 
224  irplib_polynomial_test_root_all(xtrue, nreal, CPL_MATH_PI,
225  FLT_EPSILON, 2.0*DBL_EPSILON);
226  }
227 
228  /* Two complex conjugate roots, remaining:
229  small, with multiplicity degree-2 */
230  (void)cpl_vector_fill(xtrue, 2.0*DBL_EPSILON);
231  (void)cpl_vector_set(xtrue, nreal - 2 , 3.0);
232  (void)cpl_vector_set(xtrue, nreal - 1 , 2.0);
233 
234  irplib_polynomial_test_root_all(xtrue, nreal - 2, CPL_MATH_PI,
235  4.0 * DBL_EPSILON, DBL_EPSILON);
236 
237  /* Two complex conjugate roots with small real part, remaining:
238  with multiplicity degree-2 */
239  (void)cpl_vector_fill(xtrue, 3.0);
240  (void)cpl_vector_set(xtrue, nreal - 2 , -1.0);
241  (void)cpl_vector_set(xtrue, nreal - 1 , 2.0);
242 
243  irplib_polynomial_test_root_all(xtrue, nreal - 2, CPL_MATH_PI,
244  6.0*DBL_EPSILON, 220.0*DBL_EPSILON);
245 
246 
247  }
248 
249 #if MAXDEGREE > 2
250  /* Cover branch fixing cancellation with one negative,
251  one positive near-zero and one positive root. */
252  nreal = 3;
253 
254  cpl_vector_set_size(xtrue, nreal);
255 
256  /* -2, epsilon, 1.5 */
257  (void)cpl_vector_set(xtrue, 0, -2.0);
258  (void)cpl_vector_set(xtrue, 1, 2.0 * DBL_EPSILON);
259  (void)cpl_vector_set(xtrue, 2, 1.5);
260 
261  irplib_polynomial_test_root_all(xtrue, nreal, 1.0,
262  4.0*DBL_EPSILON, 30.0*DBL_EPSILON);
263 
264 #if MAXDEGREE > 3
265  nreal = 4;
266 
267  cpl_vector_set_size(xtrue, nreal);
268 
269  /* Depressed has zero as root */
270  (void)cpl_vector_set(xtrue, 0, -1.0);
271  (void)cpl_vector_set(xtrue, 1, 1.0);
272  (void)cpl_vector_set(xtrue, 2, 2.0);
273  (void)cpl_vector_set(xtrue, 3, 2.0);
274 
275  irplib_polynomial_test_root_all(xtrue, nreal, CPL_MATH_PI,
276  2.0 * DBL_EPSILON, 2.0 * DBL_EPSILON);
277 
278  /* Depressed has zero as root, and two complex roots*/
279  irplib_polynomial_test_root_all(xtrue, 2, CPL_MATH_PI,
280  2.0 * DBL_EPSILON, 2.0 * DBL_EPSILON);
281 
282 
283  /* Depressed is biquadratic, with 4 real roots */
284  (void)cpl_vector_set(xtrue, 0, -2.0);
285  (void)cpl_vector_set(xtrue, 1, -1.0);
286  (void)cpl_vector_set(xtrue, 2, 1.0);
287  (void)cpl_vector_set(xtrue, 3, 2.0);
288 
289  irplib_polynomial_test_root_all(xtrue, nreal, CPL_MATH_PI,
290  2.0 * DBL_EPSILON, 2.0 * DBL_EPSILON);
291 
292  /* Depressed is biquadratic, with 2 real roots */
293  (void)cpl_vector_set(xtrue, 0, -1.0);
294  (void)cpl_vector_set(xtrue, 1, 1.0);
295  (void)cpl_vector_set(xtrue, 2, 0.0);
296  (void)cpl_vector_set(xtrue, 3, 2.0);
297 
298  irplib_polynomial_test_root_all(xtrue, 2, CPL_MATH_PI,
299  2.0 * DBL_EPSILON, 2.0 * DBL_EPSILON);
300 
301  /* Depressed is biquadratic (the quadratic has real, negative roots),
302  with 0 real roots */
303  (void)cpl_vector_set(xtrue, 0, 1.0);
304  (void)cpl_vector_set(xtrue, 1, 2.0);
305  (void)cpl_vector_set(xtrue, 2, 1.0);
306  (void)cpl_vector_set(xtrue, 3, 3.0);
307 
308  irplib_polynomial_test_root_all(xtrue, 0, CPL_MATH_PI,
309  10.0 * DBL_EPSILON, 10.0 * DBL_EPSILON);
310 
311  /* roots: 0, 0, ai, -ai */
312  (void)cpl_vector_set(xtrue, 0, 0.0);
313  (void)cpl_vector_set(xtrue, 1, 0.0);
314  (void)cpl_vector_set(xtrue, 2, 0.0);
315  (void)cpl_vector_set(xtrue, 3, 2.0);
316 
317  irplib_polynomial_test_root_all(xtrue, 2, CPL_MATH_PI,
318  2.0 * DBL_EPSILON, 2.0 * DBL_EPSILON);
319 
320  p1d = cpl_polynomial_new(1);
321 
322  i = 0;
323  cpl_polynomial_set_coeff(p1d, &i, -5.0);
324  i = 1;
325  cpl_polynomial_set_coeff(p1d, &i, -1.0);
326  i = 2;
327  cpl_polynomial_set_coeff(p1d, &i, -2.0);
328  i = 4;
329  cpl_polynomial_set_coeff(p1d, &i, 1.0);
330 
331  cpl_test_eq(irplib_polynomial_solve_1d_all(p1d, xtrue, &nreal),
332  CPL_ERROR_NONE);
333 
334  cpl_msg_info(cpl_func, "Computed roots (%" CPL_SIZE_FORMAT " real): ",
335  nreal);
336  if (cpl_msg_get_level() <= CPL_MSG_INFO)
337  cpl_vector_dump(xtrue, stderr);
338  cpl_msg_info(cpl_func, "Residual: %g -> %g ", cpl_vector_get(xtrue, 0),
339  cpl_polynomial_eval_1d(p1d, cpl_vector_get(xtrue, 0), NULL) );
340  cpl_msg_info(cpl_func, "Residual: %g -> %g ", cpl_vector_get(xtrue, 1),
341  cpl_polynomial_eval_1d(p1d, cpl_vector_get(xtrue, 1), NULL) );
342 
343  cpl_polynomial_delete(p1d);
344 
345  (void)cpl_vector_set(xtrue, 0, 0.0);
346  (void)cpl_vector_set(xtrue, 1, 2.0);
347  (void)cpl_vector_set(xtrue, 2, 1.0);
348  (void)cpl_vector_set(xtrue, 3, 1.0);
349 
350  irplib_polynomial_test_root_all(xtrue, 0, CPL_MATH_PI,
351  2.0 * DBL_EPSILON, 2.0 * DBL_EPSILON);
352 
353  (void)cpl_vector_set(xtrue, 0, -1.0);
354  (void)cpl_vector_set(xtrue, 1, 2.0);
355  (void)cpl_vector_set(xtrue, 2, 1.0);
356  (void)cpl_vector_set(xtrue, 3, 3.0);
357 
358  irplib_polynomial_test_root_all(xtrue, 0, CPL_MATH_PI,
359  3.0 * DBL_EPSILON, 3.0 * DBL_EPSILON);
360 #if MAXDEGREE > 4
361  nreal = 5;
362 
363  cpl_vector_set_size(xtrue, nreal);
364 
365  /* Depressed has zero as root */
366  (void)cpl_vector_set(xtrue, 0, -1.0);
367  (void)cpl_vector_set(xtrue, 1, 1.0);
368  (void)cpl_vector_set(xtrue, 2, 2.0);
369  (void)cpl_vector_set(xtrue, 3, 3.0);
370  (void)cpl_vector_set(xtrue, 4, 4.0);
371 
372  irplib_polynomial_test_root_all(xtrue, nreal, CPL_MATH_PI,
373  48.0 * DBL_EPSILON, 2800.0 * DBL_EPSILON);
374 
375  irplib_polynomial_test_root_all(xtrue, nreal-2, CPL_MATH_PI,
376  8.0 * DBL_EPSILON, 4000.0 * DBL_EPSILON);
377 
378  irplib_polynomial_test_root_all(xtrue, nreal-4, CPL_MATH_PI,
379  4.0 * DBL_EPSILON, 600.0 * DBL_EPSILON);
380 
381 #if MAXDEGREE > 5
382  nreal = 6;
383 
384  cpl_vector_set_size(xtrue, nreal);
385 
386  /* Depressed has zero as root */
387  (void)cpl_vector_set(xtrue, 0, -1.0);
388  (void)cpl_vector_set(xtrue, 1, 1.0);
389  (void)cpl_vector_set(xtrue, 2, 2.0);
390  (void)cpl_vector_set(xtrue, 3, 3.0);
391  (void)cpl_vector_set(xtrue, 4, 4.0);
392  (void)cpl_vector_set(xtrue, 5, 5.0);
393 
394  irplib_polynomial_test_root_all(xtrue, nreal, CPL_MATH_PI,
395  240.0 * DBL_EPSILON, 50.0e3 * DBL_EPSILON);
396 
397  irplib_polynomial_test_root_all(xtrue, nreal-2, CPL_MATH_PI,
398  8.0 * DBL_EPSILON, 25.0e3 * DBL_EPSILON);
399 
400  irplib_polynomial_test_root_all(xtrue, nreal-4, CPL_MATH_PI,
401  12.0 * DBL_EPSILON, 1600.0 * DBL_EPSILON);
402 
403 #endif
404 #endif
405 #endif
406 #endif
407 
408  cpl_vector_delete(xtrue);
409 
410  return;
411 }
412 
413 /*----------------------------------------------------------------------------*/
424 /*----------------------------------------------------------------------------*/
425 static
426 cpl_error_code irplib_polynomial_multiply_1d_factor(cpl_polynomial * self,
427  const cpl_vector * roots,
428  cpl_size nreal)
429 {
430 
431  const cpl_size nroots = cpl_vector_get_size(roots);
432  cpl_size i, degree;
433 
434  cpl_ensure_code(self != NULL, CPL_ERROR_NULL_INPUT);
435  cpl_ensure_code(roots != NULL, CPL_ERROR_NULL_INPUT);
436  cpl_ensure_code(cpl_polynomial_get_dimension(self) == 1,
437  CPL_ERROR_ILLEGAL_INPUT);
438 
439  cpl_ensure_code(nreal >= 0, CPL_ERROR_ILLEGAL_INPUT);
440  cpl_ensure_code(nreal <= nroots,
441  CPL_ERROR_ILLEGAL_INPUT);
442  cpl_ensure_code((cpl_vector_get_size(roots) - nreal) % 2 == 0,
443  CPL_ERROR_ILLEGAL_INPUT);
444 
445  i = 0;
446  degree = cpl_polynomial_get_degree(self);
447  cpl_ensure_code(degree > 0 || cpl_polynomial_get_coeff(self, &i) != 0.0,
448  CPL_ERROR_DATA_NOT_FOUND);
449 
450  for (i = 0; i < nreal; i++) {
451  const double root = cpl_vector_get(roots, i);
452  double prev = 0.0;
453  cpl_size j;
454 
455  degree++;
456 
457  for (j = degree; j >= 0; j--) {
458  double value = 0.0;
459  double newval;
460 
461  if (j > 0) {
462  const cpl_size jj = j - 1;
463  newval = value = cpl_polynomial_get_coeff(self, &jj);
464  } else {
465  newval = 0.0;
466  }
467 
468  if (j < degree) {
469  newval -= root * prev;
470  }
471 
472  cpl_polynomial_set_coeff(self, &j, newval);
473 
474  prev = value;
475 
476  }
477  }
478 
479  /* Multiplication with the complex conjugate root
480  (x-a-ib) (x-a+ib) p(x) = (x-a)^2 p(x) + b^2 p(x) */
481  for (; i < nroots; i += 2) {
482  const double a = cpl_vector_get(roots, i);
483  const double b = cpl_vector_get(roots, i+1);
484  cpl_vector * aroot = cpl_vector_new(2);
485  cpl_polynomial * copy = cpl_polynomial_duplicate(self);
486 
487  cpl_vector_fill(aroot, a);
488 
489  irplib_polynomial_multiply_1d_factor(self, aroot, 2);
490 
491  cpl_polynomial_multiply_scalar(copy, copy, b * b);
492 
493  cpl_polynomial_add(self, self, copy);
494 
495  cpl_vector_delete(aroot);
496  cpl_polynomial_delete(copy);
497 
498  }
499 
500  return CPL_ERROR_NONE;
501 
502 }
503 
504 /*----------------------------------------------------------------------------*/
517 /*----------------------------------------------------------------------------*/
518 static void
519 irplib_polynomial_test_root_all_macro(const cpl_vector * self, cpl_size nreal,
520  double factor, double tolerance,
521  double resitol, unsigned line)
522 {
523 
524  const cpl_size degree = cpl_vector_get_size(self);
525  cpl_polynomial * p1d = cpl_polynomial_new(1);
526  cpl_vector * roots = cpl_vector_new(degree);
527  cpl_size i = 0;
528  cpl_size jreal;
529 
530  cpl_test_eq(cpl_polynomial_set_coeff(p1d, &i, factor), CPL_ERROR_NONE);
531 
532  cpl_test_eq(irplib_polynomial_multiply_1d_factor(p1d, self, nreal),
533  CPL_ERROR_NONE);
534 
535  cpl_test_eq(irplib_polynomial_solve_1d_all(p1d, roots, &jreal),
536  CPL_ERROR_NONE);
537 
538  cpl_test_eq(jreal, nreal);
539  if (jreal != nreal) {
540  cpl_msg_info(cpl_func, "1D-polynomial:");
541  cpl_polynomial_dump(p1d, stderr);
542  cpl_msg_error(cpl_func, "True roots (%" CPL_SIZE_FORMAT
543  " real): (line=%u)", nreal, line);
544  cpl_vector_dump(self, stderr);
545  cpl_msg_error(cpl_func, "Computed roots (%" CPL_SIZE_FORMAT " real): ",
546  jreal);
547  cpl_vector_dump(roots, stderr);
548  } else if (cpl_msg_get_level() < CPL_MSG_WARNING) {
549  cpl_bivector * dump =
550  cpl_bivector_wrap_vectors((cpl_vector*)self, roots);
551 
552  cpl_msg_warning(cpl_func, "Comparing %" CPL_SIZE_FORMAT " roots (%"
553  CPL_SIZE_FORMAT " real): (line=%u)",
554  degree, nreal, line);
555  cpl_bivector_dump(dump, stderr);
556  cpl_bivector_unwrap_vectors(dump);
557  }
558 
559  for (i = 0; i < jreal; i++) {
560  const double root = cpl_vector_get(roots, i);
561  const double residual = cpl_polynomial_eval_1d(p1d, root, NULL);
562 
563  cpl_test_abs(root, cpl_vector_get(self, i), tolerance);
564 
565  cpl_test_abs(residual, 0.0, resitol);
566 
567  }
568 
569  for (i = nreal; i < degree; i++) {
570  const double root = cpl_vector_get(roots, i);
571 
572  cpl_test_abs(root, cpl_vector_get(self, i), tolerance);
573 
574  /* FIXME: Verify residual as well */
575 
576  }
577 
578  cpl_vector_delete(roots);
579  cpl_polynomial_delete(p1d);
580 
581  return;
582 }