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
00040
00041
00042
00043
00044 #define MAXDEGREE 0
00045
00046
00047
00048
00049
00050 static cpl_error_code irplib_polynomial_multiply_1d_factor(cpl_polynomial *,
00051 const cpl_vector *,
00052 int);
00053 static void irplib_polynomial_solve_1d_all_test(void);
00054
00055 static void irplib_polynomial_test_root_all(const cpl_vector *, int, double,
00056 double, double);
00057
00058 static cpl_error_code irplib_polynomial_add(cpl_polynomial *,
00059 const cpl_polynomial *,
00060 const cpl_polynomial *);
00061
00062 static cpl_error_code irplib_polynomial_multiply_scalar(cpl_polynomial *,
00063 double);
00064
00065
00066
00067
00068 int main(void)
00069 {
00070
00071 cpl_test_init(PACKAGE_BUGREPORT, CPL_MSG_WARNING);
00072
00073 irplib_polynomial_solve_1d_all_test();
00074
00075 return cpl_test_end(0);
00076 }
00077
00078
00079
00086
00087 static void irplib_polynomial_solve_1d_all_test(void)
00088 {
00089
00090 cpl_polynomial * p2d = cpl_polynomial_new(2);
00091 cpl_polynomial * p1d = cpl_polynomial_new(1);
00092 cpl_vector * xtrue = cpl_vector_new(2);
00093 const int maxdegree = MAXDEGREE;
00094 int nreal = 0;
00095 int i;
00096
00097 cpl_test_eq(irplib_polynomial_solve_1d_all(NULL, xtrue, &nreal),
00098 CPL_ERROR_NULL_INPUT);
00099 cpl_test_error(CPL_ERROR_NULL_INPUT);
00100
00101 cpl_test_eq(irplib_polynomial_solve_1d_all(p1d, NULL, &nreal),
00102 CPL_ERROR_NULL_INPUT);
00103 cpl_test_error(CPL_ERROR_NULL_INPUT);
00104
00105 cpl_test_eq(irplib_polynomial_solve_1d_all(p1d, xtrue, NULL),
00106 CPL_ERROR_NULL_INPUT);
00107 cpl_test_error(CPL_ERROR_NULL_INPUT);
00108
00109 cpl_test_eq(irplib_polynomial_solve_1d_all(p2d, xtrue, &nreal),
00110 CPL_ERROR_INVALID_TYPE);
00111 cpl_test_error(CPL_ERROR_INVALID_TYPE);
00112
00113 cpl_test_eq(irplib_polynomial_solve_1d_all(p1d, xtrue, &nreal),
00114 CPL_ERROR_DATA_NOT_FOUND);
00115 cpl_test_error(CPL_ERROR_DATA_NOT_FOUND);
00116
00117
00118 i = 1;
00119 cpl_test_eq(cpl_polynomial_set_coeff(p1d, &i, 1.0), CPL_ERROR_NONE);
00120 cpl_test_eq(irplib_polynomial_solve_1d_all(p1d, xtrue, &nreal),
00121 CPL_ERROR_INCOMPATIBLE_INPUT);
00122 cpl_test_error(CPL_ERROR_INCOMPATIBLE_INPUT);
00123
00124 cpl_polynomial_delete(p1d);
00125 cpl_polynomial_delete(p2d);
00126
00127 for (nreal = 1; nreal <= maxdegree; nreal++) {
00128
00129 double xreal = 0.0;
00130
00131
00132 cpl_vector_set_size(xtrue, nreal);
00133
00134 (void)cpl_vector_fill(xtrue, xreal);
00135
00136 irplib_polynomial_test_root_all(xtrue, nreal, CPL_MATH_PI,
00137 2.0 * DBL_EPSILON, 2.0 * DBL_EPSILON);
00138
00139
00140 xreal = 1.0;
00141
00142 (void)cpl_vector_fill(xtrue, xreal);
00143
00144 irplib_polynomial_test_root_all(xtrue, nreal, 1.0,
00145 2.0 * DBL_EPSILON, 2.0 * DBL_EPSILON);
00146
00147
00148 for (i = 0; i < nreal; i++) {
00149 (void)cpl_vector_set(xtrue, i, 2.0 * (double)i - CPL_MATH_E);
00150 }
00151
00152 irplib_polynomial_test_root_all(xtrue, nreal, CPL_MATH_PI,
00153 20.0 * DBL_EPSILON,
00154 230.0 * DBL_EPSILON);
00155
00156
00157 for (i = 0; i < nreal-1; i++) {
00158 (void)cpl_vector_set(xtrue, nreal-i-2, (double)(-i));
00159 }
00160 (void)cpl_vector_set(xtrue, nreal-1, (double)(nreal-1));
00161
00162 irplib_polynomial_test_root_all(xtrue, nreal, CPL_MATH_PI,
00163 16.0*DBL_EPSILON, 127.0*DBL_EPSILON);
00164
00165 if (nreal < 2) continue;
00166
00167
00168
00169 (void)cpl_vector_fill(xtrue, 2.0);
00170 (void)cpl_vector_set(xtrue, nreal-2, -1.0);
00171 (void)cpl_vector_set(xtrue, nreal-1, 1.0);
00172
00173 irplib_polynomial_test_root_all(xtrue, nreal-2, CPL_MATH_PI,
00174 30.0*DBL_EPSILON, 25.0*DBL_EPSILON);
00175
00176 if (nreal < 3) continue;
00177
00178 (void)cpl_vector_fill(xtrue, 1.0);
00179 (void)cpl_vector_set(xtrue, nreal - 1 , 2.0);
00180
00181 irplib_polynomial_test_root_all(xtrue, nreal, CPL_MATH_PI,
00182 DBL_EPSILON, DBL_EPSILON);
00183
00184
00185 (void)cpl_vector_fill(xtrue, -1.0);
00186 (void)cpl_vector_set(xtrue, 0 , -2.0);
00187
00188 irplib_polynomial_test_root_all(xtrue, nreal, CPL_MATH_PI,
00189 DBL_EPSILON, DBL_EPSILON);
00190
00191
00192 (void)cpl_vector_fill(xtrue, 2.0);
00193 (void)cpl_vector_set(xtrue, 0, 1.0);
00194
00195 irplib_polynomial_test_root_all(xtrue, nreal, CPL_MATH_PI,
00196 DBL_EPSILON, DBL_EPSILON);
00197
00198 if (nreal > 3) continue;
00199
00200
00201 (void)cpl_vector_fill(xtrue, -2.0 * FLT_EPSILON);
00202 (void)cpl_vector_set(xtrue, 0, -1.0);
00203
00204 irplib_polynomial_test_root_all(xtrue, nreal, CPL_MATH_PI,
00205 DBL_EPSILON, 2.0*DBL_EPSILON);
00206
00207
00208 (void)cpl_vector_fill(xtrue, -2.0e-4 * FLT_EPSILON);
00209 (void)cpl_vector_set(xtrue, 0, -1.0);
00210
00211 irplib_polynomial_test_root_all(xtrue, nreal, CPL_MATH_PI,
00212 FLT_EPSILON, 2.0*DBL_EPSILON);
00213
00214
00215 (void)cpl_vector_fill(xtrue, -2.0 * DBL_EPSILON);
00216 (void)cpl_vector_set(xtrue, 0, -1.0);
00217
00218 irplib_polynomial_test_root_all(xtrue, nreal, CPL_MATH_PI,
00219 DBL_EPSILON, 2.0*DBL_EPSILON);
00220
00221
00222 (void)cpl_vector_set(xtrue, 0, -1.0);
00223 (void)cpl_vector_set(xtrue, 1, -2.0e-4 * FLT_EPSILON);
00224 (void)cpl_vector_set(xtrue, 2, 2.0e-4 * FLT_EPSILON);
00225
00226 irplib_polynomial_test_root_all(xtrue, nreal, CPL_MATH_PI,
00227 FLT_EPSILON, 2.0*DBL_EPSILON);
00228
00229
00230
00231 (void)cpl_vector_fill(xtrue, 2.0*DBL_EPSILON);
00232 (void)cpl_vector_set(xtrue, nreal - 2 , 3.0);
00233 (void)cpl_vector_set(xtrue, nreal - 1 , 2.0);
00234
00235 irplib_polynomial_test_root_all(xtrue, nreal - 2, CPL_MATH_PI,
00236 4.0 * DBL_EPSILON, DBL_EPSILON);
00237
00238
00239
00240 (void)cpl_vector_fill(xtrue, 3.0);
00241 (void)cpl_vector_set(xtrue, nreal - 2 , -1.0);
00242 (void)cpl_vector_set(xtrue, nreal - 1 , 2.0);
00243
00244 irplib_polynomial_test_root_all(xtrue, nreal - 2, CPL_MATH_PI,
00245 6.0*DBL_EPSILON, 220.0*DBL_EPSILON);
00246
00247
00248 }
00249
00250 #if MAXDEGREE > 2
00251
00252
00253 nreal = 3;
00254
00255 cpl_vector_set_size(xtrue, nreal);
00256
00257
00258 (void)cpl_vector_set(xtrue, 0, -2.0);
00259 (void)cpl_vector_set(xtrue, 1, 2.0 * DBL_EPSILON);
00260 (void)cpl_vector_set(xtrue, 2, 1.5);
00261
00262 irplib_polynomial_test_root_all(xtrue, nreal, 1.0,
00263 4.0*DBL_EPSILON, 30.0*DBL_EPSILON);
00264
00265 #endif
00266
00267 #if MAXDEGREE > 3
00268 nreal = 4;
00269
00270 cpl_vector_set_size(xtrue, nreal);
00271
00272
00273 (void)cpl_vector_set(xtrue, 0, -1.0);
00274 (void)cpl_vector_set(xtrue, 1, 1.0);
00275 (void)cpl_vector_set(xtrue, 2, 2.0);
00276 (void)cpl_vector_set(xtrue, 3, 2.0);
00277
00278 irplib_polynomial_test_root_all(xtrue, nreal, CPL_MATH_PI,
00279 2.0 * DBL_EPSILON, 2.0 * DBL_EPSILON);
00280
00281
00282 irplib_polynomial_test_root_all(xtrue, 2, CPL_MATH_PI,
00283 2.0 * DBL_EPSILON, 2.0 * DBL_EPSILON);
00284
00285
00286
00287 (void)cpl_vector_set(xtrue, 0, -2.0);
00288 (void)cpl_vector_set(xtrue, 1, -1.0);
00289 (void)cpl_vector_set(xtrue, 2, 1.0);
00290 (void)cpl_vector_set(xtrue, 3, 2.0);
00291
00292 irplib_polynomial_test_root_all(xtrue, nreal, CPL_MATH_PI,
00293 2.0 * DBL_EPSILON, 2.0 * DBL_EPSILON);
00294
00295
00296 (void)cpl_vector_set(xtrue, 0, -1.0);
00297 (void)cpl_vector_set(xtrue, 1, 1.0);
00298 (void)cpl_vector_set(xtrue, 2, 0.0);
00299 (void)cpl_vector_set(xtrue, 3, 2.0);
00300
00301 irplib_polynomial_test_root_all(xtrue, 2, CPL_MATH_PI,
00302 2.0 * DBL_EPSILON, 2.0 * DBL_EPSILON);
00303
00304
00305
00306 (void)cpl_vector_set(xtrue, 0, 1.0);
00307 (void)cpl_vector_set(xtrue, 1, 2.0);
00308 (void)cpl_vector_set(xtrue, 2, 1.0);
00309 (void)cpl_vector_set(xtrue, 3, 3.0);
00310
00311 irplib_polynomial_test_root_all(xtrue, 0, CPL_MATH_PI,
00312 2.0 * DBL_EPSILON, 2.0 * DBL_EPSILON);
00313
00314
00315 (void)cpl_vector_set(xtrue, 0, 0.0);
00316 (void)cpl_vector_set(xtrue, 1, 0.0);
00317 (void)cpl_vector_set(xtrue, 2, 0.0);
00318 (void)cpl_vector_set(xtrue, 3, 2.0);
00319
00320 irplib_polynomial_test_root_all(xtrue, 2, CPL_MATH_PI,
00321 2.0 * DBL_EPSILON, 2.0 * DBL_EPSILON);
00322
00323 #if 1
00324 p1d = cpl_polynomial_new(1);
00325
00326 i = 0;
00327 cpl_polynomial_set_coeff(p1d, &i, -5.0);
00328 i = 1;
00329 cpl_polynomial_set_coeff(p1d, &i, -1.0);
00330 i = 2;
00331 cpl_polynomial_set_coeff(p1d, &i, -2.0);
00332 i = 4;
00333 cpl_polynomial_set_coeff(p1d, &i, 1.0);
00334
00335 cpl_test_eq(irplib_polynomial_solve_1d_all(p1d, xtrue, &nreal),
00336 CPL_ERROR_NONE);
00337
00338 cpl_msg_info(cpl_func, "Computed roots (%d real): ", nreal);
00339 if (cpl_msg_get_level() <= CPL_MSG_INFO)
00340 cpl_vector_dump(xtrue, stderr);
00341 cpl_msg_info(cpl_func, "Residual: %g -> %g ", cpl_vector_get(xtrue, 0),
00342 cpl_polynomial_eval_1d(p1d, cpl_vector_get(xtrue, 0), NULL) );
00343 cpl_msg_info(cpl_func, "Residual: %g -> %g ", cpl_vector_get(xtrue, 1),
00344 cpl_polynomial_eval_1d(p1d, cpl_vector_get(xtrue, 1), NULL) );
00345
00346 cpl_polynomial_delete(p1d);
00347 #endif
00348
00349 (void)cpl_vector_set(xtrue, 0, 0.0);
00350 (void)cpl_vector_set(xtrue, 1, 2.0);
00351 (void)cpl_vector_set(xtrue, 2, 1.0);
00352 (void)cpl_vector_set(xtrue, 3, 1.0);
00353
00354 irplib_polynomial_test_root_all(xtrue, 0, CPL_MATH_PI,
00355 2.0 * DBL_EPSILON, 2.0 * DBL_EPSILON);
00356
00357 (void)cpl_vector_set(xtrue, 0, -1.0);
00358 (void)cpl_vector_set(xtrue, 1, 2.0);
00359 (void)cpl_vector_set(xtrue, 2, 1.0);
00360 (void)cpl_vector_set(xtrue, 3, 3.0);
00361
00362 irplib_polynomial_test_root_all(xtrue, 0, CPL_MATH_PI,
00363 3.0 * DBL_EPSILON, 3.0 * DBL_EPSILON);
00364 #endif
00365
00366 cpl_vector_delete(xtrue);
00367
00368 return;
00369 }
00370
00371
00382
00383 static
00384 cpl_error_code irplib_polynomial_multiply_1d_factor(cpl_polynomial * self,
00385 const cpl_vector * roots,
00386 int nreal)
00387 {
00388
00389 int i, degree;
00390 const int nroots = cpl_vector_get_size(roots);
00391
00392 cpl_ensure_code(self != NULL, CPL_ERROR_NULL_INPUT);
00393 cpl_ensure_code(roots != NULL, CPL_ERROR_NULL_INPUT);
00394 cpl_ensure_code(cpl_polynomial_get_dimension(self) == 1,
00395 CPL_ERROR_ILLEGAL_INPUT);
00396
00397 cpl_ensure_code(nreal >= 0, CPL_ERROR_ILLEGAL_INPUT);
00398 cpl_ensure_code(nreal <= nroots,
00399 CPL_ERROR_ILLEGAL_INPUT);
00400 cpl_ensure_code((cpl_vector_get_size(roots) - nreal) % 2 == 0,
00401 CPL_ERROR_ILLEGAL_INPUT);
00402
00403 i = 0;
00404 degree = cpl_polynomial_get_degree(self);
00405 cpl_ensure_code(degree > 0 || cpl_polynomial_get_coeff(self, &i) != 0.0,
00406 CPL_ERROR_DATA_NOT_FOUND);
00407
00408 for (i = 0; i < nreal; i++) {
00409 const double root = cpl_vector_get(roots, i);
00410 double prev = 0.0;
00411 int j;
00412
00413 degree++;
00414
00415 for (j = degree; j >= 0; j--) {
00416 double value = 0.0;
00417 double newval;
00418
00419 if (j > 0) {
00420 const int jj = j - 1;
00421 newval = value = cpl_polynomial_get_coeff(self, &jj);
00422 } else {
00423 newval = 0.0;
00424 }
00425
00426 if (j < degree) {
00427 newval -= root * prev;
00428 }
00429
00430 cpl_polynomial_set_coeff(self, &j, newval);
00431
00432 prev = value;
00433
00434 }
00435 }
00436
00437
00438
00439 for (; i < nroots; i += 2) {
00440 const double a = cpl_vector_get(roots, i);
00441 const double b = cpl_vector_get(roots, i+1);
00442 cpl_vector * aroot = cpl_vector_new(2);
00443 cpl_polynomial * copy = cpl_polynomial_duplicate(self);
00444
00445 cpl_vector_fill(aroot, a);
00446
00447 irplib_polynomial_multiply_1d_factor(self, aroot, 2);
00448
00449 irplib_polynomial_multiply_scalar(copy, b * b);
00450
00451 irplib_polynomial_add(self, self, copy);
00452
00453 cpl_vector_delete(aroot);
00454 cpl_polynomial_delete(copy);
00455
00456 }
00457
00458 return CPL_ERROR_NONE;
00459
00460 }
00461
00462
00463
00478
00479 static cpl_error_code irplib_polynomial_add(cpl_polynomial * self,
00480 const cpl_polynomial * first,
00481 const cpl_polynomial * second)
00482 {
00483
00484 int degree0;
00485 int degree1;
00486 int degree2;
00487
00488 cpl_ensure_code(self != NULL, CPL_ERROR_NULL_INPUT);
00489 cpl_ensure_code(first != NULL, CPL_ERROR_NULL_INPUT);
00490 cpl_ensure_code(second != NULL, CPL_ERROR_NULL_INPUT);
00491
00492 cpl_ensure_code(cpl_polynomial_get_dimension(self) ==
00493 cpl_polynomial_get_dimension(first),
00494 CPL_ERROR_INCOMPATIBLE_INPUT);
00495 cpl_ensure_code(cpl_polynomial_get_dimension(self) ==
00496 cpl_polynomial_get_dimension(second),
00497 CPL_ERROR_INCOMPATIBLE_INPUT);
00498
00499 cpl_ensure_code(cpl_polynomial_get_dimension(self) == 1,
00500 CPL_ERROR_UNSUPPORTED_MODE);
00501
00502 degree0 = cpl_polynomial_get_degree(self);
00503 degree1 = cpl_polynomial_get_degree(first);
00504 degree2 = cpl_polynomial_get_degree(second);
00505
00506 if (degree1 > degree2) {
00507 for (; degree0 > degree1; degree0--) {
00508 cpl_polynomial_set_coeff(self, °ree0, 0.0);
00509 }
00510 for (; degree0 > degree2; degree0--) {
00511 const double val1 = cpl_polynomial_get_coeff(first, °ree0);
00512 cpl_polynomial_set_coeff(self, °ree0, val1);
00513 }
00514 } else {
00515 for (; degree0 > degree2; degree0--) {
00516 cpl_polynomial_set_coeff(self, °ree0, 0.0);
00517 }
00518 for (; degree0 > degree1; degree0--) {
00519 const double val2 = cpl_polynomial_get_coeff(second, °ree0);
00520 cpl_polynomial_set_coeff(self, °ree0, val2);
00521 }
00522 }
00523
00524 for (; degree0 >=0; degree0--) {
00525 const double val1 = cpl_polynomial_get_coeff(first, °ree0);
00526 const double val2 = cpl_polynomial_get_coeff(second, °ree0);
00527 cpl_polynomial_set_coeff(self, °ree0, val1 + val2);
00528 }
00529
00530 return CPL_ERROR_NONE;
00531 }
00532
00533
00545
00546 static cpl_error_code irplib_polynomial_multiply_scalar(cpl_polynomial * self,
00547 double factor)
00548 {
00549
00550 int degree0;
00551
00552 cpl_ensure_code(self != NULL, CPL_ERROR_NULL_INPUT);
00553
00554 cpl_ensure_code(cpl_polynomial_get_dimension(self) == 1,
00555 CPL_ERROR_UNSUPPORTED_MODE);
00556
00557 degree0 = cpl_polynomial_get_degree(self);
00558
00559 for (; degree0 >=0; degree0--) {
00560 const double val = cpl_polynomial_get_coeff(self, °ree0);
00561 cpl_polynomial_set_coeff(self, °ree0, factor * val);
00562 }
00563
00564 return CPL_ERROR_NONE;
00565 }
00566
00567
00580
00581 static void irplib_polynomial_test_root_all(const cpl_vector * self, int nreal,
00582 double factor, double tolerance,
00583 double resitol)
00584 {
00585
00586 const int degree = cpl_vector_get_size(self);
00587 cpl_polynomial * p1d = cpl_polynomial_new(1);
00588 cpl_vector * roots = cpl_vector_new(degree);
00589 int i = 0;
00590 int jreal;
00591
00592 cpl_test_eq(cpl_polynomial_set_coeff(p1d, &i, factor), CPL_ERROR_NONE);
00593
00594 cpl_test_eq(irplib_polynomial_multiply_1d_factor(p1d, self, nreal),
00595 CPL_ERROR_NONE);
00596
00597 cpl_test_eq(irplib_polynomial_solve_1d_all(p1d, roots, &jreal),
00598 CPL_ERROR_NONE);
00599
00600 cpl_test_eq(jreal, nreal);
00601 if (jreal != nreal) {
00602 cpl_msg_error(cpl_func, "True roots (%d real): ", nreal);
00603 cpl_vector_dump(self, stderr);
00604 cpl_msg_error(cpl_func, "Computed roots (%d real): ", jreal);
00605 cpl_vector_dump(roots, stderr);
00606 } else if (cpl_msg_get_level() < CPL_MSG_WARNING) {
00607 cpl_bivector * dump =
00608 cpl_bivector_wrap_vectors((cpl_vector*)self, roots);
00609
00610 cpl_msg_warning(cpl_func, "Comparing %d roots (%d real): ", degree,
00611 nreal);
00612 cpl_bivector_dump(dump, stderr);
00613 cpl_bivector_unwrap_vectors(dump);
00614 }
00615
00616 for (i = 0; i < jreal; i++) {
00617 const double root = cpl_vector_get(roots, i);
00618 const double residual = cpl_polynomial_eval_1d(p1d, root, NULL);
00619
00620 cpl_test_abs(root, cpl_vector_get(self, i), tolerance);
00621
00622 cpl_test_abs(residual, 0.0, resitol);
00623
00624 }
00625
00626 for (i = nreal; i < degree; i++) {
00627 const double root = cpl_vector_get(roots, i);
00628
00629 cpl_test_abs(root, cpl_vector_get(self, i), tolerance);
00630
00631
00632 }
00633
00634 cpl_vector_delete(roots);
00635 cpl_polynomial_delete(p1d);
00636
00637 return;
00638 }