00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032 #ifdef HAVE_CONFIG_H
00033 #include <config.h>
00034 #endif
00035
00036 #include <irplib_polynomial.h>
00037 #include <math.h>
00038 #include <float.h>
00039 #include <stdint.h>
00040
00041
00042
00043
00044
00045 #define MAXDEGREE 6
00046
00047 #define irplib_polynomial_test_root_all(A, B, C, D, E) \
00048 irplib_polynomial_test_root_all_macro(A, B, C, D, E, __LINE__)
00049
00050
00051
00052
00053
00054 static cpl_error_code irplib_polynomial_multiply_1d_factor(cpl_polynomial *,
00055 const cpl_vector *,
00056 cpl_size);
00057 static void irplib_polynomial_solve_1d_all_test(void);
00058
00059 static void irplib_polynomial_test_root_all_macro(const cpl_vector *, cpl_size,
00060 double, double, double,
00061 unsigned);
00062
00063
00064
00065
00066 int main(void)
00067 {
00068
00069 cpl_test_init(PACKAGE_BUGREPORT, CPL_MSG_WARNING);
00070
00071 irplib_polynomial_solve_1d_all_test();
00072
00073 return cpl_test_end(0);
00074 }
00075
00076
00077
00084
00085 static void irplib_polynomial_solve_1d_all_test(void)
00086 {
00087
00088 cpl_polynomial * p2d = cpl_polynomial_new(2);
00089 cpl_polynomial * p1d = cpl_polynomial_new(1);
00090 cpl_vector * xtrue = cpl_vector_new(2);
00091 const cpl_size maxdegree = 4;
00092 cpl_size nreal = 0;
00093 cpl_size i;
00094
00095 cpl_test_eq(irplib_polynomial_solve_1d_all(NULL, xtrue, &nreal),
00096 CPL_ERROR_NULL_INPUT);
00097 cpl_test_error(CPL_ERROR_NULL_INPUT);
00098
00099 cpl_test_eq(irplib_polynomial_solve_1d_all(p1d, NULL, &nreal),
00100 CPL_ERROR_NULL_INPUT);
00101 cpl_test_error(CPL_ERROR_NULL_INPUT);
00102
00103 cpl_test_eq(irplib_polynomial_solve_1d_all(p1d, xtrue, NULL),
00104 CPL_ERROR_NULL_INPUT);
00105 cpl_test_error(CPL_ERROR_NULL_INPUT);
00106
00107 cpl_test_eq(irplib_polynomial_solve_1d_all(p2d, xtrue, &nreal),
00108 CPL_ERROR_INVALID_TYPE);
00109 cpl_test_error(CPL_ERROR_INVALID_TYPE);
00110
00111 cpl_test_eq(irplib_polynomial_solve_1d_all(p1d, xtrue, &nreal),
00112 CPL_ERROR_DATA_NOT_FOUND);
00113 cpl_test_error(CPL_ERROR_DATA_NOT_FOUND);
00114
00115
00116 i = 1;
00117 cpl_test_eq(cpl_polynomial_set_coeff(p1d, &i, 1.0), CPL_ERROR_NONE);
00118 cpl_test_eq(irplib_polynomial_solve_1d_all(p1d, xtrue, &nreal),
00119 CPL_ERROR_INCOMPATIBLE_INPUT);
00120 cpl_test_error(CPL_ERROR_INCOMPATIBLE_INPUT);
00121
00122 cpl_polynomial_delete(p1d);
00123 cpl_polynomial_delete(p2d);
00124
00125 for (nreal = 1; nreal <= maxdegree; nreal++) {
00126
00127 double xreal = 0.0;
00128
00129
00130 cpl_vector_set_size(xtrue, nreal);
00131
00132 (void)cpl_vector_fill(xtrue, xreal);
00133
00134 irplib_polynomial_test_root_all(xtrue, nreal, CPL_MATH_PI,
00135 2.0 * DBL_EPSILON, 2.0 * DBL_EPSILON);
00136
00137
00138 xreal = 1.0;
00139
00140 (void)cpl_vector_fill(xtrue, xreal);
00141
00142 irplib_polynomial_test_root_all(xtrue, nreal, 1.0,
00143 2.0 * DBL_EPSILON, 2.0 * DBL_EPSILON);
00144
00145
00146 for (i = 0; i < nreal; i++) {
00147 (void)cpl_vector_set(xtrue, i, 2.0 * (double)i - CPL_MATH_E);
00148 }
00149
00150 irplib_polynomial_test_root_all(xtrue, nreal, CPL_MATH_PI,
00151 20.0 * DBL_EPSILON,
00152 300.0 * DBL_EPSILON);
00153
00154
00155 for (i = 0; i < nreal-1; i++) {
00156 (void)cpl_vector_set(xtrue, nreal-i-2, (double)(-i));
00157 }
00158 (void)cpl_vector_set(xtrue, nreal-1, (double)(nreal-1));
00159
00160 irplib_polynomial_test_root_all(xtrue, nreal, CPL_MATH_PI,
00161 16.0*DBL_EPSILON, 600.0*DBL_EPSILON);
00162
00163 if (nreal < 2) continue;
00164
00165
00166
00167 (void)cpl_vector_fill(xtrue, 2.0);
00168 (void)cpl_vector_set(xtrue, nreal-2, -1.0);
00169 (void)cpl_vector_set(xtrue, nreal-1, 1.0);
00170
00171 irplib_polynomial_test_root_all(xtrue, nreal-2, CPL_MATH_PI,
00172 30.0*DBL_EPSILON, 25.0*DBL_EPSILON);
00173
00174 if (nreal < 3) continue;
00175 if (nreal > 4) {
00176
00177 (void)cpl_vector_fill(xtrue, 1.0);
00178 (void)cpl_vector_set(xtrue, nreal - 1 , 2.0);
00179
00180 irplib_polynomial_test_root_all(xtrue, nreal, CPL_MATH_PI,
00181 DBL_EPSILON, DBL_EPSILON);
00182
00183 (void)cpl_vector_fill(xtrue, -1.0);
00184 (void)cpl_vector_set(xtrue, 0 , -2.0);
00185
00186 irplib_polynomial_test_root_all(xtrue, nreal, CPL_MATH_PI,
00187 DBL_EPSILON, DBL_EPSILON);
00188
00189 (void)cpl_vector_fill(xtrue, 2.0);
00190 (void)cpl_vector_set(xtrue, 0, 1.0);
00191
00192 irplib_polynomial_test_root_all(xtrue, nreal, CPL_MATH_PI,
00193 DBL_EPSILON, DBL_EPSILON);
00194 }
00195
00196 if (nreal > 3) continue;
00197
00198
00199 (void)cpl_vector_fill(xtrue, -2.0 * FLT_EPSILON);
00200 (void)cpl_vector_set(xtrue, 0, -1.0);
00201
00202 irplib_polynomial_test_root_all(xtrue, nreal, CPL_MATH_PI,
00203 DBL_EPSILON, 2.0*DBL_EPSILON);
00204
00205
00206 #if defined SIZE_MAX && SIZE_MAX <= 4294967295
00207 (void)cpl_vector_fill(xtrue, -0.1 * FLT_EPSILON);
00208 #else
00209 (void)cpl_vector_fill(xtrue, -0.2 * FLT_EPSILON);
00210 #endif
00211
00212 (void)cpl_vector_set(xtrue, 0, -1.0);
00213
00214 irplib_polynomial_test_root_all(xtrue, nreal, CPL_MATH_PI,
00215 FLT_EPSILON, 3.0*DBL_EPSILON);
00216
00217 if (nreal != 3) {
00218
00219 (void)cpl_vector_fill(xtrue, -2.0 * DBL_EPSILON);
00220 (void)cpl_vector_set(xtrue, 0, -1.0);
00221
00222 irplib_polynomial_test_root_all(xtrue, nreal, CPL_MATH_PI,
00223 DBL_EPSILON, 2.0*DBL_EPSILON);
00224
00225
00226 (void)cpl_vector_set(xtrue, 0, -1.0);
00227 (void)cpl_vector_set(xtrue, 1, -2.0e-4 * FLT_EPSILON);
00228 (void)cpl_vector_set(xtrue, 2, 2.0e-4 * FLT_EPSILON);
00229
00230 irplib_polynomial_test_root_all(xtrue, nreal, CPL_MATH_PI,
00231 FLT_EPSILON, 2.0*DBL_EPSILON);
00232 }
00233
00234
00235
00236 (void)cpl_vector_fill(xtrue, 2.0*DBL_EPSILON);
00237 (void)cpl_vector_set(xtrue, nreal - 2 , 3.0);
00238 (void)cpl_vector_set(xtrue, nreal - 1 , 2.0);
00239
00240 irplib_polynomial_test_root_all(xtrue, nreal - 2, CPL_MATH_PI,
00241 4.0 * DBL_EPSILON, DBL_EPSILON);
00242
00243
00244
00245 (void)cpl_vector_fill(xtrue, 3.0);
00246 (void)cpl_vector_set(xtrue, nreal - 2 , -1.0);
00247 (void)cpl_vector_set(xtrue, nreal - 1 , 2.0);
00248
00249 irplib_polynomial_test_root_all(xtrue, nreal - 2, CPL_MATH_PI,
00250 6.0*DBL_EPSILON, 220.0*DBL_EPSILON);
00251
00252
00253 }
00254
00255 #if MAXDEGREE > 2
00256
00257
00258 nreal = 3;
00259
00260 cpl_vector_set_size(xtrue, nreal);
00261
00262
00263 (void)cpl_vector_set(xtrue, 0, -2.0);
00264 (void)cpl_vector_set(xtrue, 1, 2.0 * DBL_EPSILON);
00265 (void)cpl_vector_set(xtrue, 2, 1.5);
00266
00267 irplib_polynomial_test_root_all(xtrue, nreal, 1.0,
00268 4.0*DBL_EPSILON, 30.0*DBL_EPSILON);
00269
00270 #if MAXDEGREE > 3
00271 nreal = 4;
00272
00273 cpl_vector_set_size(xtrue, nreal);
00274
00275
00276 (void)cpl_vector_set(xtrue, 0, -1.0);
00277 (void)cpl_vector_set(xtrue, 1, 1.0);
00278 (void)cpl_vector_set(xtrue, 2, 2.0);
00279 (void)cpl_vector_set(xtrue, 3, 2.0);
00280
00281 irplib_polynomial_test_root_all(xtrue, nreal, CPL_MATH_PI,
00282 2.0 * DBL_EPSILON, 2.0 * DBL_EPSILON);
00283
00284
00285 irplib_polynomial_test_root_all(xtrue, 2, CPL_MATH_PI,
00286 2.0 * DBL_EPSILON, 2.0 * DBL_EPSILON);
00287
00288
00289
00290 (void)cpl_vector_set(xtrue, 0, -2.0);
00291 (void)cpl_vector_set(xtrue, 1, -1.0);
00292 (void)cpl_vector_set(xtrue, 2, 1.0);
00293 (void)cpl_vector_set(xtrue, 3, 2.0);
00294
00295 irplib_polynomial_test_root_all(xtrue, nreal, CPL_MATH_PI,
00296 2.0 * DBL_EPSILON, 2.0 * DBL_EPSILON);
00297
00298
00299 (void)cpl_vector_set(xtrue, 0, -1.0);
00300 (void)cpl_vector_set(xtrue, 1, 1.0);
00301 (void)cpl_vector_set(xtrue, 2, 0.0);
00302 (void)cpl_vector_set(xtrue, 3, 2.0);
00303
00304 irplib_polynomial_test_root_all(xtrue, 2, CPL_MATH_PI,
00305 2.0 * DBL_EPSILON, 2.0 * DBL_EPSILON);
00306
00307
00308
00309 (void)cpl_vector_set(xtrue, 0, 1.0);
00310 (void)cpl_vector_set(xtrue, 1, 2.0);
00311 (void)cpl_vector_set(xtrue, 2, 1.0);
00312 (void)cpl_vector_set(xtrue, 3, 3.0);
00313
00314 irplib_polynomial_test_root_all(xtrue, 0, CPL_MATH_PI,
00315 10.0 * DBL_EPSILON, 10.0 * DBL_EPSILON);
00316
00317
00318 (void)cpl_vector_set(xtrue, 0, 0.0);
00319 (void)cpl_vector_set(xtrue, 1, 0.0);
00320 (void)cpl_vector_set(xtrue, 2, 0.0);
00321 (void)cpl_vector_set(xtrue, 3, 2.0);
00322
00323 irplib_polynomial_test_root_all(xtrue, 2, CPL_MATH_PI,
00324 2.0 * DBL_EPSILON, 2.0 * DBL_EPSILON);
00325
00326 p1d = cpl_polynomial_new(1);
00327
00328 i = 0;
00329 cpl_polynomial_set_coeff(p1d, &i, -5.0);
00330 i = 1;
00331 cpl_polynomial_set_coeff(p1d, &i, -1.0);
00332 i = 2;
00333 cpl_polynomial_set_coeff(p1d, &i, -2.0);
00334 i = 4;
00335 cpl_polynomial_set_coeff(p1d, &i, 1.0);
00336
00337 cpl_test_eq(irplib_polynomial_solve_1d_all(p1d, xtrue, &nreal),
00338 CPL_ERROR_NONE);
00339
00340 cpl_msg_info(cpl_func, "Computed roots (%" CPL_SIZE_FORMAT " real): ",
00341 nreal);
00342 if (cpl_msg_get_level() <= CPL_MSG_INFO)
00343 cpl_vector_dump(xtrue, stderr);
00344 cpl_msg_info(cpl_func, "Residual: %g -> %g ", cpl_vector_get(xtrue, 0),
00345 cpl_polynomial_eval_1d(p1d, cpl_vector_get(xtrue, 0), NULL) );
00346 cpl_msg_info(cpl_func, "Residual: %g -> %g ", cpl_vector_get(xtrue, 1),
00347 cpl_polynomial_eval_1d(p1d, cpl_vector_get(xtrue, 1), NULL) );
00348
00349 cpl_polynomial_delete(p1d);
00350
00351 (void)cpl_vector_set(xtrue, 0, 0.0);
00352 (void)cpl_vector_set(xtrue, 1, 2.0);
00353 (void)cpl_vector_set(xtrue, 2, 1.0);
00354 (void)cpl_vector_set(xtrue, 3, 1.0);
00355
00356 irplib_polynomial_test_root_all(xtrue, 0, CPL_MATH_PI,
00357 2.0 * DBL_EPSILON, 2.0 * DBL_EPSILON);
00358
00359 (void)cpl_vector_set(xtrue, 0, -1.0);
00360 (void)cpl_vector_set(xtrue, 1, 2.0);
00361 (void)cpl_vector_set(xtrue, 2, 1.0);
00362 (void)cpl_vector_set(xtrue, 3, 3.0);
00363
00364 irplib_polynomial_test_root_all(xtrue, 0, CPL_MATH_PI,
00365 3.0 * DBL_EPSILON, 3.0 * DBL_EPSILON);
00366 #if MAXDEGREE > 4
00367 nreal = 5;
00368
00369 cpl_vector_set_size(xtrue, nreal);
00370
00371
00372 (void)cpl_vector_set(xtrue, 0, -1.0);
00373 (void)cpl_vector_set(xtrue, 1, 1.0);
00374 (void)cpl_vector_set(xtrue, 2, 2.0);
00375 (void)cpl_vector_set(xtrue, 3, 3.0);
00376 (void)cpl_vector_set(xtrue, 4, 4.0);
00377
00378 irplib_polynomial_test_root_all(xtrue, nreal, CPL_MATH_PI,
00379 48.0 * DBL_EPSILON, 2800.0 * DBL_EPSILON);
00380
00381 irplib_polynomial_test_root_all(xtrue, nreal-2, CPL_MATH_PI,
00382 8.0 * DBL_EPSILON, 4000.0 * DBL_EPSILON);
00383
00384 irplib_polynomial_test_root_all(xtrue, nreal-4, CPL_MATH_PI,
00385 4.0 * DBL_EPSILON, 600.0 * DBL_EPSILON);
00386
00387 #if MAXDEGREE > 5
00388 nreal = 6;
00389
00390 cpl_vector_set_size(xtrue, nreal);
00391
00392
00393 (void)cpl_vector_set(xtrue, 0, -1.0);
00394 (void)cpl_vector_set(xtrue, 1, 1.0);
00395 (void)cpl_vector_set(xtrue, 2, 2.0);
00396 (void)cpl_vector_set(xtrue, 3, 3.0);
00397 (void)cpl_vector_set(xtrue, 4, 4.0);
00398 (void)cpl_vector_set(xtrue, 5, 5.0);
00399
00400 irplib_polynomial_test_root_all(xtrue, nreal, CPL_MATH_PI,
00401 240.0 * DBL_EPSILON, 50.0e3 * DBL_EPSILON);
00402
00403 irplib_polynomial_test_root_all(xtrue, nreal-2, CPL_MATH_PI,
00404 8.0 * DBL_EPSILON, 25.0e3 * DBL_EPSILON);
00405
00406 irplib_polynomial_test_root_all(xtrue, nreal-4, CPL_MATH_PI,
00407 12.0 * DBL_EPSILON, 1600.0 * DBL_EPSILON);
00408
00409 #endif
00410 #endif
00411 #endif
00412 #endif
00413
00414 cpl_vector_delete(xtrue);
00415
00416 return;
00417 }
00418
00419
00430
00431 static
00432 cpl_error_code irplib_polynomial_multiply_1d_factor(cpl_polynomial * self,
00433 const cpl_vector * roots,
00434 cpl_size nreal)
00435 {
00436
00437 const cpl_size nroots = cpl_vector_get_size(roots);
00438 cpl_size i, degree;
00439
00440 cpl_ensure_code(self != NULL, CPL_ERROR_NULL_INPUT);
00441 cpl_ensure_code(roots != NULL, CPL_ERROR_NULL_INPUT);
00442 cpl_ensure_code(cpl_polynomial_get_dimension(self) == 1,
00443 CPL_ERROR_ILLEGAL_INPUT);
00444
00445 cpl_ensure_code(nreal >= 0, CPL_ERROR_ILLEGAL_INPUT);
00446 cpl_ensure_code(nreal <= nroots,
00447 CPL_ERROR_ILLEGAL_INPUT);
00448 cpl_ensure_code((cpl_vector_get_size(roots) - nreal) % 2 == 0,
00449 CPL_ERROR_ILLEGAL_INPUT);
00450
00451 i = 0;
00452 degree = cpl_polynomial_get_degree(self);
00453 cpl_ensure_code(degree > 0 || cpl_polynomial_get_coeff(self, &i) != 0.0,
00454 CPL_ERROR_DATA_NOT_FOUND);
00455
00456 for (i = 0; i < nreal; i++) {
00457 const double root = cpl_vector_get(roots, i);
00458 double prev = 0.0;
00459 cpl_size j;
00460
00461 degree++;
00462
00463 for (j = degree; j >= 0; j--) {
00464 double value = 0.0;
00465 double newval;
00466
00467 if (j > 0) {
00468 const cpl_size jj = j - 1;
00469 newval = value = cpl_polynomial_get_coeff(self, &jj);
00470 } else {
00471 newval = 0.0;
00472 }
00473
00474 if (j < degree) {
00475 newval -= root * prev;
00476 }
00477
00478 cpl_polynomial_set_coeff(self, &j, newval);
00479
00480 prev = value;
00481
00482 }
00483 }
00484
00485
00486
00487 for (; i < nroots; i += 2) {
00488 const double a = cpl_vector_get(roots, i);
00489 const double b = cpl_vector_get(roots, i+1);
00490 cpl_vector * aroot = cpl_vector_new(2);
00491 cpl_polynomial * copy = cpl_polynomial_duplicate(self);
00492
00493 cpl_vector_fill(aroot, a);
00494
00495 irplib_polynomial_multiply_1d_factor(self, aroot, 2);
00496
00497 cpl_polynomial_multiply_scalar(copy, copy, b * b);
00498
00499 cpl_polynomial_add(self, self, copy);
00500
00501 cpl_vector_delete(aroot);
00502 cpl_polynomial_delete(copy);
00503
00504 }
00505
00506 return CPL_ERROR_NONE;
00507
00508 }
00509
00510
00523
00524 static void
00525 irplib_polynomial_test_root_all_macro(const cpl_vector * self, cpl_size nreal,
00526 double factor, double tolerance,
00527 double resitol, unsigned line)
00528 {
00529
00530 const cpl_size degree = cpl_vector_get_size(self);
00531 cpl_polynomial * p1d = cpl_polynomial_new(1);
00532 cpl_vector * roots = cpl_vector_new(degree);
00533 cpl_size i = 0;
00534 cpl_size jreal;
00535
00536 cpl_test_eq(cpl_polynomial_set_coeff(p1d, &i, factor), CPL_ERROR_NONE);
00537
00538 cpl_test_eq(irplib_polynomial_multiply_1d_factor(p1d, self, nreal),
00539 CPL_ERROR_NONE);
00540
00541 cpl_test_eq(irplib_polynomial_solve_1d_all(p1d, roots, &jreal),
00542 CPL_ERROR_NONE);
00543
00544 cpl_test_eq(jreal, nreal);
00545 if (jreal != nreal) {
00546 cpl_msg_info(cpl_func, "1D-polynomial:");
00547 cpl_polynomial_dump(p1d, stderr);
00548 cpl_msg_error(cpl_func, "True roots (%" CPL_SIZE_FORMAT
00549 " real): (line=%u)", nreal, line);
00550 cpl_vector_dump(self, stderr);
00551 cpl_msg_error(cpl_func, "Computed roots (%" CPL_SIZE_FORMAT " real): ",
00552 jreal);
00553 cpl_vector_dump(roots, stderr);
00554 } else if (cpl_msg_get_level() < CPL_MSG_WARNING) {
00555 cpl_bivector * dump =
00556 cpl_bivector_wrap_vectors((cpl_vector*)self, roots);
00557
00558 cpl_msg_warning(cpl_func, "Comparing %" CPL_SIZE_FORMAT " roots (%"
00559 CPL_SIZE_FORMAT " real): (line=%u)",
00560 degree, nreal, line);
00561 cpl_bivector_dump(dump, stderr);
00562 cpl_bivector_unwrap_vectors(dump);
00563 }
00564
00565 for (i = 0; i < jreal; i++) {
00566 const double root = cpl_vector_get(roots, i);
00567 const double residual = cpl_polynomial_eval_1d(p1d, root, NULL);
00568
00569 cpl_test_abs(root, cpl_vector_get(self, i), tolerance);
00570
00571 cpl_test_abs(residual, 0.0, resitol);
00572
00573 }
00574
00575 for (i = nreal; i < degree; i++) {
00576 const double root = cpl_vector_get(roots, i);
00577
00578 cpl_test_abs(root, cpl_vector_get(self, i), tolerance);
00579
00580
00581
00582 }
00583
00584 cpl_vector_delete(roots);
00585 cpl_polynomial_delete(p1d);
00586
00587 return;
00588 }