Changeset 1199 for trunk/psLib/src/math/psMinimize.c
- Timestamp:
- Jul 8, 2004, 10:50:46 AM (22 years ago)
- File:
-
- 1 edited
-
trunk/psLib/src/math/psMinimize.c (modified) (12 diffs)
Legend:
- Unmodified
- Added
- Removed
-
trunk/psLib/src/math/psMinimize.c
r1192 r1199 1 /** @file psMinimize.c 2 * \brief basic minimization functions 3 * @ingroup Math 4 * 5 * This file will contain functions to minimize an arbitrary function at 6 * a data point, fit an arbitrary function to a set of data points, and 7 * fit a 1-D polynomial to a set of data points. 8 * 9 * @author George Gusciora, MHPCC 10 * 11 * @version $Revision: 1.22 $ $Name: not supported by cvs2svn $ 12 * @date $Date: 2004-07-08 20:50:46 $ 13 * 14 * Copyright 2004 Maui High Performance Computing Center, University of Hawaii 15 */ 16 /*****************************************************************************/ 17 /* INCLUDE FILES */ 18 /*****************************************************************************/ 1 19 #include <stdlib.h> 2 20 #include <stdio.h> … … 23 41 #include "psMinimize.h" 24 42 #include "psMatrix.h" 25 #include "float.h" 26 #include <math.h> 27 43 /*****************************************************************************/ 44 /* DEFINE STATEMENTS */ 45 /*****************************************************************************/ 28 46 #define MAX_LMM_ITERATIONS 100 29 47 #define MAX_MINIMIZE_ITERATIONS 100 48 49 /** Preprocessor macro to generate error on a NULL 1DPolynomial */ 50 #define PS_CHECK_NULL_1DPOLY(NAME) \ 51 if (NAME == NULL || NAME->coeff == NULL) { \ 52 psError(__func__,"Invalid operation: %s or its data is NULL.", #NAME); \ 53 } 54 55 /** Preprocessor macro to generate error on a NULL vector */ 56 #define PS_CHECK_NULL_VECTOR(NAME) \ 57 if (NAME == NULL || NAME->data.V == NULL) { \ 58 psError(__func__,"Invalid operation: %s or its data is NULL.", #NAME); \ 59 } 60 61 /** Preprocessor macro to generate error for zero length vector */ 62 #define PS_CHECK_EMPTY_VECTOR(NAME) \ 63 if (NAME->n < 1) { \ 64 psError(__func__,"Invalid operation: %s has zero n value.", #NAME); \ 65 } 66 67 /** Preprocessor macro to generate error on differing size vectors */ 68 #define PS_CHECK_VECTOR_SIZE_EQUAL(VEC1, VEC2) \ 69 if (VEC1->n != VEC2->n) { \ 70 psError(__func__,"Vector %s has size %d, Vector %s has size %d.", #VEC1, VEC1->n, #VEC2, VEC2->n); \ 71 } 72 73 /** Preprocessor macro to generate error on a NULL image */ 74 #define PS_CHECK_NULL_IMAGE(NAME) \ 75 if (NAME == NULL || NAME->data.V == NULL) { \ 76 psError(__func__,"Invalid operation: %s or its data is NULL.", #NAME); \ 77 } 78 79 /** Preprocessor macro to generate error for zero length rows or columns */ 80 #define PS_CHECK_EMPTY_IMAGE(NAME) \ 81 if (NAME->numCols < 1 || NAME->numRows < 1) { \ 82 psError(__func__,"Invalid operation: %s has zero rows or columns (%dx%d).", #NAME, \ 83 NAME->numCols, NAME->numRows); \ 84 } 85 86 87 /*****************************************************************************/ 88 /* TYPE DEFINITIONS */ 89 /*****************************************************************************/ 30 90 typedef struct 31 91 { … … 53 113 psMinimizeData; 54 114 55 56 /****************************************************************************** 57 p_psMinFunc(*params, *funcData): We use the GSL-supplied function 115 /*****************************************************************************/ 116 /* GLOBAL VARIABLES */ 117 /*****************************************************************************/ 118 119 // None 120 121 /*****************************************************************************/ 122 /* FILE STATIC VARIABLES */ 123 /*****************************************************************************/ 124 125 // None 126 127 /*****************************************************************************/ 128 /* FUNCTION IMPLEMENTATION - LOCAL */ 129 /*****************************************************************************/ 130 131 /****************************************************************************** 132 p_psMinFunc(*params, *funcData): We use the GSL procedure 58 133 gsl_multimin_fdfminimizer_iterate() to minimize an arbitary function supplied 59 by the user. The GSL function requires the user-supplied function to be in 60 a different format than the psLib format. The purpose of this procedure is 61 to serve as a GSL-format wrapper for the psLib user-supplied function which 62 is to be minimized. 63 *params: The parameters of the function to be minimized. These will be 134 by the user. That GSL procedure requires the function to be minimized to be 135 in a different format than the psLib format. The purpose of this procedure 136 is to serve as a GSL-format wrapper for the user-supplied procedure which is 137 to be minimized. 138 139 params: The parameters of the function to be minimized. These will be 64 140 varied by GSL in order to minimize the function. 65 *funcData: a psLib struct which contains the data point to be minimized, 66 the function and derivative function pointers, an initial guess at 67 the parameters, an option parameter mask, etc. 141 142 funcData: a private psLib struct which contains the data point to be 143 minimized, the function and derivative function pointers, an initial 144 guess at the parameters, an option parameter mask, etc. 68 145 *****************************************************************************/ 69 146 double p_psMinFunc(const gsl_vector *params, … … 109 186 110 187 /****************************************************************************** 111 p_psMinFuncDeriv(*params, *funcData): We use the GSL-supplied function 112 gsl_multimin_fdfminimizer_iterate() to minimize an arbitary function supplied 113 by the user. The GSL function requires the user-supplied function to be in 114 a different format than the psLib format. The purpose of this procedure is 115 to serve as a GSL-format wrapper for the psLib user-supplied function which 116 is to be minimized. 117 *params: The parameters of the function to be minimized. These will be 188 p_psMinFuncDeriv(*params, *funcData): a GSL-like wrapper for the 189 user-supplied procedure which calculates the derviative of the function to be 190 minimized. 191 192 params: The parameters of the function to be minimized. These will be 118 193 varied by GSL in order to minimize the function. 119 *funcData: a psLib struct which contains the data point to be minimized, 120 the function and derivative function pointers, an initial guess at 121 the parameters, an option parameter mask, etc. 122 *df: we calculate the derivative of the function w.r.t. to each parameter 194 195 funcData: a private psLib struct which contains the data point to be 196 minimized, the function and derivative function pointers, an initial 197 guess at the parameters, an option parameter mask, etc. 198 199 df: we calculate the derivative of the function w.r.t. to each parameter 123 200 in "params" and return those derivatives in this psVector. 124 201 *****************************************************************************/ … … 180 257 } 181 258 182 183 /******************************************************************************184 psMinimize(initialGuess, myFunction, myFunctionDeriv, coord, paramMask):185 186 This routine must minimize an arbitrary function; it must determine the set187 of parameters of that function such that the188 *****************************************************************************/189 psVector *190 psMinimize(psVector *restrict initialGuess,191 float (*myFunction)(const psVector *restrict, const psVector *restrict),192 float (*myFunctionDeriv)(const psVector *restrict, const psVector *restrict, int),193 const psVector *restrict coord,194 const psVector *restrict paramMask)195 {196 int status;197 int i = 0;198 int j = 0;199 int iter = 0;200 gsl_multimin_function_fdf f;201 const gsl_multimin_fdfminimizer_type *T;202 gsl_multimin_fdfminimizer *s;203 psMinimizeData inputData;204 gsl_vector *x;205 206 inputData.initialGuess = initialGuess;207 inputData.coord = coord;208 inputData.paramMask = paramMask;209 inputData.evalModel = myFunction;210 inputData.d_evalModel = myFunctionDeriv;211 inputData.paramCount = 0;212 213 // If the user supplied a parameter mask, then count the number of214 // non-masked elements. This will be used later in allocating a vector215 // for the parameters.216 if (paramMask != NULL) {217 for (i=0;i<paramMask->n;i++) {218 if (paramMask->data.U8[i] != 0) {219 inputData.paramCount++;220 }221 }222 } else {223 inputData.paramCount= initialGuess->n;224 }225 226 // The initial guess at the parameters for the function are written into227 // the vector inputParameterList. If the paramMask is not NULL, then228 // masked parameters are masked out.229 x = gsl_vector_alloc(inputData.paramCount);230 if (paramMask != NULL) {231 j = 0;232 for (i=0;i<initialGuess->n;i++) {233 if (paramMask->data.U8[i] == 0) {234 gsl_vector_set(x, j++, initialGuess->data.F32[i]);235 }236 }237 } else {238 for (i=0;i<initialGuess->n;i++) {239 gsl_vector_set(x, i, initialGuess->data.F32[i]);240 }241 }242 f.f = &p_psMinFunc;243 f.df = &p_psMinFuncDeriv;244 f.fdf = &p_psMinFuncFuncDeriv;245 f.n = inputData.paramCount;246 f.params = &inputData;247 248 T = gsl_multimin_fdfminimizer_conjugate_fr;249 s = gsl_multimin_fdfminimizer_alloc(T, inputData.paramCount);250 gsl_multimin_fdfminimizer_set(s, &f, x, 0.01, 1e-4);251 do {252 iter++;253 status = gsl_multimin_fdfminimizer_iterate(s);254 255 if (status)256 break;257 258 status = gsl_multimin_test_gradient(s->gradient, 1e-3);259 260 if (status == GSL_SUCCESS)261 printf ("Minimum found at:\n");262 263 } while (status == GSL_CONTINUE && iter < MAX_MINIMIZE_ITERATIONS);264 265 // In the above steps we had removed the masked elements from the266 // the solver. This next code blocks puts those masked elements267 // into the solution.268 if (paramMask != NULL) {269 j = 0;270 for (i=0;i<initialGuess->n;i++) {271 if (paramMask->data.U8[i] == 0) {272 initialGuess->data.F32[i] = gsl_vector_get(s->x, j++);273 } else {274 initialGuess->data.F32[i] = initialGuess->data.F32[i];275 }276 }277 } else {278 for (i=0;i<initialGuess->n;i++) {279 initialGuess->data.F32[i] = gsl_vector_get(s->x, i);280 }281 }282 return(initialGuess);283 }284 285 286 287 288 289 259 // The first argument to evalModel() and d_evalModel() specifies the data 290 260 // point. It must have the same size as the second dimension of *domain. … … 293 263 294 264 /****************************************************************************** 295 p_psMinChi2Func(*x, *funcData, *outdata): We use the GSL-supplied function 296 gsl_multifit_fdfsolver_iterate() to determine the function parameters that 297 best fit the supllied set of data points. That GSL function requires the 298 user-supplied function to be in a different format than the psLib format. 299 The purpose of this procedure is to serve as a GSL-format wrapper for the 300 psLib user-supplied function which is to be minimized. 301 x: These are the parameters which are to be varied by GSL in order to 302 minimized chi2 over the data set. 265 p_psMinChi2Func(*x, *funcData, *outdata): We use the GSL procedure 266 gsl_multifit_fdfsolver_iterate() to fit an arbitrary function, supplied by 267 the user, to a set of data points. That GSL procedure requires the function 268 to be fit to be in a different format than the psLib format. The purpose of 269 this procedure is to serve as a GSL-format wrapper for the user-supplied 270 procedure which is to be fit to the data. 271 272 params: These are the parameters which are to be varied by GSL in order 273 to minimize chi2 over the data set. 274 303 275 funcData: this data structure contains the input values over which the 304 function will be evaluated, the expected value of the function at 305 those points, the amount of error tolerable at those points, a mask 306 vector which specifies which parameters to the function are to be 307 constant, and an initial guess at the parameters. 276 function will be evaluated, the expected value of the function at 277 those points, the amount of error tolerable at those points, a mask 278 vector which specifies which parameters to the function are to be 279 constant, and an initial guess at the parameters. 280 308 281 outData: The function is evaluated at each point, then subtract the 309 expected value and divide by the error.282 expected value and divide by the error. 310 283 *****************************************************************************/ 311 284 int p_psMinChi2Func(const gsl_vector *params, … … 366 339 } 367 340 341 /****************************************************************************** 342 p_psMinChi2FuncDeriv(*x, *funcData, *outdata): a GSL-like wrapper for the 343 user-supplied procedure which calculates the derviative of the function to be 344 minimized. 345 params: These are the parameters which are to be varied by GSL in order 346 to minimize chi2 over the data set. 347 348 funcData: this data structure contains the input values over which the 349 function will be evaluated, the expected value of the function at 350 those points, the amount of error tolerable at those points, a mask 351 vector which specifies which parameters to the function are to be 352 constant, and an initial guess at the parameters. 353 354 J: The derivative is evaluated at each point and w.r.t. each parameter 355 and returned in this data structure. 356 *****************************************************************************/ 368 357 int p_psMinChi2FuncDeriv(const gsl_vector *params, 369 358 void *funcData, … … 433 422 return GSL_SUCCESS; 434 423 } 424 425 426 /****************************************************************************** 427 p_psBuildSums1D(x, polyOrder, sums): this routine calculates the powers of 428 input parameter "x" between 0 and input parameter polyOrder. The result is 429 returned as a psVector sums. 430 *****************************************************************************/ 431 void p_psBuildSums1D(double x, 432 int polyOrder, 433 psVector *sums) 434 { 435 int i = 0; 436 double xSum = 0.0; 437 438 xSum = 1.0; 439 for(i=0;i<=polyOrder;i++) { 440 sums->data.F64[i] = xSum; 441 xSum*= x; 442 } 443 } 444 445 446 /****************************************************************************** 447 p_psBuildSums1D(x): this routine returns a psVector with "x" elements. The 448 values of the vector will be scaled uniformly between -1.0 and 1.0. 449 *****************************************************************************/ 450 psVector *psBuildImageScalingFactors(int x) 451 452 { 453 int i = 0; // loop index variable. 454 psVector *imageScalingFactors = NULL; 455 456 457 imageScalingFactors = psVectorAlloc(x, PS_TYPE_F32); 458 459 for (i=0;i<x;i++) { 460 imageScalingFactors->data.F32[i] = (((float) 2*i) / ((float) x)) - 1.0; 461 } 462 463 return(imageScalingFactors); 464 } 465 466 /****************************************************************************** 467 CURRENTLY NOT IN USE. 468 469 p_psPolyOrderCheck(A, N, *indx, *B, polyOrder,*flag) This routine checks if 470 all polyOrder-th terms in the polyOrder-th order sky background polynomial 471 defined by the coefficients in the array B[] are consistent with zero. If 472 true, then *flag is set to 1. Otherwise, *flag is set to 0. The matrix 473 inversion code in the middle of this procedure draws from Numerical Recipes 474 in C page 48. 475 Input: 476 A This is the LUD decomposition of the original matrix A. 477 N The size of the matrix (plus 1, actually, since offset 1). 478 indx misc Numerical Recipes data structure. 479 B The coefficients of the sky polynomial. 480 polyOrder The degree of the sky polynomial. 481 Output: 482 *flag Set this to 1 if we must recalculate the coefficients. 483 *****************************************************************************/ 484 void p_psPolyOrderCheck(float **A, 485 int N, 486 int *indx, 487 float *B, 488 int polyOrder, 489 int *flag) 490 { 491 float **y = NULL; // This 2-D matrix will hold A^-1 492 float *col = NULL; // misc NumerRecipes data structure 493 float *error=NULL; // will hold the sqrt() of the 494 // diagonal of y[][]. 495 int i=0; // loop-index variable 496 int j=0; // loop-index variable 497 int numPolyTerms = 0; // The number of terms in the 498 // polynomial. 499 int lastTerm = 0; // The index location of the first 500 // n-th order term in array B[]. 501 int firstTerm = 0; // Index location of last such term. 502 503 // Allocate the necessary data structures for this procedure... 504 error = (float *) psAlloc((N + 1) * sizeof(float)); 505 col = (float *) psAlloc((N + 1) * sizeof(float)); 506 y = (float **) psAlloc((N + 1) * sizeof(float *)); 507 for(i=1;i<=N;i++) { 508 y[i] = (float *) psAlloc((N + 1) * sizeof(float)); 509 } 510 511 // Invert the matrix A and put the result in y[][]. This code is taken 512 // from Numerical Recipes in C page 48. 513 for(j=1;j<=N;j++) { 514 for(i=1;i<=N;i++) { 515 col[i] = 0.0; 516 } 517 col[j] = 1.0; 518 // NOTE: substitue the LUD rotine 519 // lubksb(A, N, indx, col); 520 for(i=1;i<=N;i++) { 521 y[i][j] = col[i]; 522 } 523 } 524 525 // Determine where the first n-th order (in this comment, n equals 526 // polyOrder) polynomial term is stored in the matrix B[], and also were 527 // the last n-order term is stored. Then we loop over all the n-order 528 // terms and check if they are consistent with zero. 529 530 numPolyTerms = (((polyOrder+1) * (polyOrder + 2)) / 2); 531 lastTerm = numPolyTerms + 1; 532 firstTerm = lastTerm - polyOrder; 533 *flag = 1; 534 for (i=firstTerm; i<=lastTerm; i++) { 535 #ifdef DARWIN 536 error[i] = (float)sqrt(y[i][i]); 537 #else 538 539 error[i] = sqrtf(y[i][i]); 540 #endif 541 542 if (!((B[i] <= (2.0f * error[i])) && 543 ((-2.0f * error[i]) <= B[i]))) { 544 *flag = 0; 545 } 546 } 547 548 // Free all memory allocated in this routine. 549 psFree(error); 550 psFree(col); 551 for(j=1;j<=N;j++) { 552 psFree(y[j]); 553 } 554 psFree(y); 555 } 556 557 558 559 560 /*****************************************************************************/ 561 /* FUNCTION IMPLEMENTATION - PUBLIC */ 562 /*****************************************************************************/ 563 564 565 566 /****************************************************************************** 567 psMinimize(initialGuess, myFunction, myFunctionDeriv, coord, paramMask): 568 569 This routine must minimize an arbitrary function; it determines the set of 570 parameters of that function such that the. 571 *****************************************************************************/ 572 psVector * 573 psMinimize(psVector *restrict initialGuess, 574 float (*myFunction)(const psVector *restrict, const psVector *restrict), 575 float (*myFunctionDeriv)(const psVector *restrict, const psVector *restrict, int), 576 const psVector *restrict coord, 577 const psVector *restrict paramMask) 578 { 579 int status; 580 int i = 0; 581 int j = 0; 582 int iter = 0; 583 gsl_multimin_function_fdf f; 584 const gsl_multimin_fdfminimizer_type *T; 585 gsl_multimin_fdfminimizer *s; 586 psMinimizeData inputData; 587 gsl_vector *x; 588 589 PS_CHECK_NULL_VECTOR(initialGuess); 590 PS_CHECK_EMPTY_VECTOR(initialGuess); 591 PS_CHECK_NULL_VECTOR(coord); 592 PS_CHECK_EMPTY_VECTOR(coord); 593 if (paramMask != NULL) { 594 PS_CHECK_NULL_VECTOR(paramMask); 595 PS_CHECK_EMPTY_VECTOR(paramMask); 596 PS_CHECK_VECTOR_SIZE_EQUAL(initialGuess, paramMask); 597 } 598 599 inputData.initialGuess = initialGuess; 600 inputData.coord = coord; 601 inputData.paramMask = paramMask; 602 inputData.evalModel = myFunction; 603 inputData.d_evalModel = myFunctionDeriv; 604 inputData.paramCount = 0; 605 606 // If the user supplied a parameter mask, then count the number of 607 // non-masked elements. This will be used later in allocating a vector 608 // for the parameters. 609 if (paramMask != NULL) { 610 for (i=0;i<paramMask->n;i++) { 611 if (paramMask->data.U8[i] != 0) { 612 inputData.paramCount++; 613 } 614 } 615 } else { 616 inputData.paramCount= initialGuess->n; 617 } 618 619 // The initial guess at the parameters for the function are written into 620 // the vector inputParameterList. If the paramMask is not NULL, then 621 // masked parameters are masked out. 622 x = gsl_vector_alloc(inputData.paramCount); 623 if (paramMask != NULL) { 624 j = 0; 625 for (i=0;i<initialGuess->n;i++) { 626 if (paramMask->data.U8[i] == 0) { 627 gsl_vector_set(x, j++, initialGuess->data.F32[i]); 628 } 629 } 630 } else { 631 for (i=0;i<initialGuess->n;i++) { 632 gsl_vector_set(x, i, initialGuess->data.F32[i]); 633 } 634 } 635 f.f = &p_psMinFunc; 636 f.df = &p_psMinFuncDeriv; 637 f.fdf = &p_psMinFuncFuncDeriv; 638 f.n = inputData.paramCount; 639 f.params = &inputData; 640 641 T = gsl_multimin_fdfminimizer_conjugate_fr; 642 s = gsl_multimin_fdfminimizer_alloc(T, inputData.paramCount); 643 gsl_multimin_fdfminimizer_set(s, &f, x, 0.01, 1e-4); 644 do { 645 iter++; 646 status = gsl_multimin_fdfminimizer_iterate(s); 647 648 if (status) 649 break; 650 651 status = gsl_multimin_test_gradient(s->gradient, 1e-3); 652 653 if (status == GSL_SUCCESS) 654 printf ("Minimum found at:\n"); 655 656 } while (status == GSL_CONTINUE && iter < MAX_MINIMIZE_ITERATIONS); 657 658 // In the above steps we had removed the masked elements from the 659 // the solver. This next code blocks puts those masked elements 660 // into the solution. 661 if (paramMask != NULL) { 662 j = 0; 663 for (i=0;i<initialGuess->n;i++) { 664 if (paramMask->data.U8[i] == 0) { 665 initialGuess->data.F32[i] = gsl_vector_get(s->x, j++); 666 } else { 667 initialGuess->data.F32[i] = initialGuess->data.F32[i]; 668 } 669 } 670 } else { 671 for (i=0;i<initialGuess->n;i++) { 672 initialGuess->data.F32[i] = gsl_vector_get(s->x, i); 673 } 674 } 675 return(initialGuess); 676 } 677 678 679 680 681 435 682 436 683 /****************************************************************************** … … 454 701 gsl_multifit_function_fdf f; // GSL structure that contains the 455 702 // functions/derivative to be solved. 456 double *xInit = NULL; // The initial guess at the parameters703 double *xInit = NULL; // The initial guess at the parameters 457 704 // with masked parameters removed. 458 705 const gsl_multifit_fdfsolver_type *T; … … 463 710 psMinChi2Data inputData; 464 711 float chiSqOld = 0.0; 712 713 PS_CHECK_NULL_IMAGE(domain); 714 PS_CHECK_EMPTY_IMAGE(domain); 715 PS_CHECK_NULL_VECTOR(data); 716 PS_CHECK_EMPTY_VECTOR(data); 717 PS_CHECK_NULL_VECTOR(errors); 718 PS_CHECK_EMPTY_VECTOR(errors); 719 PS_CHECK_NULL_VECTOR(initialGuess); 720 PS_CHECK_EMPTY_VECTOR(initialGuess); 721 PS_CHECK_VECTOR_SIZE_EQUAL(data, errors); 722 if (domain->numRows != data->n) { 723 psAbort(__func__,"Number of data points and data values not equal."); 724 } 725 if (paramMask != NULL) { 726 PS_CHECK_NULL_VECTOR(paramMask); 727 PS_CHECK_EMPTY_VECTOR(paramMask); 728 PS_CHECK_VECTOR_SIZE_EQUAL(initialGuess, paramMask); 729 } 465 730 466 731 inputData.n = numData; … … 589 854 590 855 /****************************************************************************** 591 p_psBuildSums1D(x, polyOrder, sums): this routine calculates the powers of592 input parameter "x" between 0 and input parameter polyOrder. The result is593 returned as a psVector sums.594 *****************************************************************************/595 void p_psBuildSums1D(double x,596 int polyOrder,597 psVector *sums)598 {599 int i = 0;600 double xSum = 0.0;601 602 xSum = 1.0;603 for(i=0;i<=polyOrder;i++) {604 sums->data.F64[i] = xSum;605 xSum*= x;606 }607 }608 609 610 /******************************************************************************611 p_psBuildSums1D(x): this routine returns a psVector with "x" elements. The612 values of the vector will be scaled uniformly between -1.0 and 1.0.613 *****************************************************************************/614 psVector *psBuildImageScalingFactors(int x)615 616 {617 int i = 0; // loop index variable.618 psVector *imageScalingFactors = NULL;619 620 621 imageScalingFactors = psVectorAlloc(x, PS_TYPE_F32);622 623 for (i=0;i<x;i++) {624 imageScalingFactors->data.F32[i] = (((float) 2*i) / ((float) x)) - 1.0;625 }626 627 return(imageScalingFactors);628 }629 630 /** @brief This routine checks if all polyOrder-th terms in the polyOrder-th631 * order sky background polynomial defined by the coefficients in the array B[]632 * are consistent with zero. If true, then *flag is set to 1. Otherwise,633 * *flag is set to 0. The matrix inversion code in the middle of this634 * procedure draws from Numerical Recipes in C page 48.635 *636 * Input:637 * <ul>638 * <li> A This is the LUD decomposition of the original matrix A.639 * <li> N The size of the matrix (plus 1, actually, since offset 1).640 * <li> indx misc Numerical Recipes data structure.641 * <li> B The coefficients of the sky polynomial.642 * <li> polyOrder The degree of the sky polynomial.643 * </ul>644 * Output:645 * <ul>646 * <li> *flag Set this to 1 if we must recalculate the coefficients.647 * </ul>648 *649 * @return error status (PsError) indicating error information, or NULL on650 * success.651 */652 653 654 655 void polyOrderCheck(float **A,656 int N,657 int *indx,658 float *B,659 int polyOrder,660 int *flag)661 {662 float **y = NULL; // This 2-D matrix will hold A^-1663 float *col = NULL; // misc NumerRecipes data structure664 float *error=NULL; // will hold the sqrt() of the665 // diagonal of y[][].666 int i=0; // loop-index variable667 int j=0; // loop-index variable668 int numPolyTerms = 0; // The number of terms in the669 // polynomial.670 int lastTerm = 0; // The index location of the first671 // n-th order term in array B[].672 int firstTerm = 0; // Index location of last such term.673 674 // Allocate the necessary data structures for this procedure...675 error = (float *) psAlloc((N + 1) * sizeof(float));676 col = (float *) psAlloc((N + 1) * sizeof(float));677 y = (float **) psAlloc((N + 1) * sizeof(float *));678 for(i=1;i<=N;i++) {679 y[i] = (float *) psAlloc((N + 1) * sizeof(float));680 }681 682 // Invert the matrix A and put the result in y[][]. This code is taken683 // from Numerical Recipes in C page 48.684 for(j=1;j<=N;j++) {685 for(i=1;i<=N;i++) {686 col[i] = 0.0;687 }688 col[j] = 1.0;689 // NOTE: substitue the LUD rotine690 // lubksb(A, N, indx, col);691 for(i=1;i<=N;i++) {692 y[i][j] = col[i];693 }694 }695 696 // Determine where the first n-th order (in this comment, n equals697 // polyOrder) polynomial term is stored in the matrix B[], and also were698 // the last n-order term is stored. Then we loop over all the n-order699 // terms and check if they are consistent with zero.700 701 numPolyTerms = (((polyOrder+1) * (polyOrder + 2)) / 2);702 lastTerm = numPolyTerms + 1;703 firstTerm = lastTerm - polyOrder;704 *flag = 1;705 for (i=firstTerm; i<=lastTerm; i++) {706 #ifdef DARWIN707 error[i] = (float)sqrt(y[i][i]);708 #else709 710 error[i] = sqrtf(y[i][i]);711 #endif712 713 if (!((B[i] <= (2.0f * error[i])) &&714 ((-2.0f * error[i]) <= B[i]))) {715 *flag = 0;716 }717 }718 719 // Free all memory allocated in this routine.720 psFree(error);721 psFree(col);722 for(j=1;j<=N;j++) {723 psFree(y[j]);724 }725 psFree(y);726 }727 728 /******************************************************************************729 856 This routine must fit a polynomial of degree myPoly to the data points 730 857 (x, y) and return the coefficients of that polynomial, as well as the 731 858 error for each data poiny (yErr). 859 860 NOTE: yErr is currently ignored. 732 861 *****************************************************************************/ 733 862 psPolynomial1D * … … 749 878 psVector *xSums = NULL; 750 879 751 if (x->n != y->n) { 752 psAbort(__func__, "x and y arguments have different sizes.\n"); 753 } 754 if (x->n != yErr->n) { 755 psAbort(__func__, "y and yErr arguments have different sizes.\n"); 756 } 880 PS_CHECK_NULL_1DPOLY(myPoly); 881 PS_CHECK_NULL_VECTOR(x); 882 PS_CHECK_EMPTY_VECTOR(x); 883 PS_CHECK_NULL_VECTOR(y); 884 PS_CHECK_EMPTY_VECTOR(y); 885 PS_CHECK_NULL_VECTOR(yErr); 886 PS_CHECK_EMPTY_VECTOR(yErr); 887 PS_CHECK_VECTOR_SIZE_EQUAL(x, y); 888 PS_CHECK_VECTOR_SIZE_EQUAL(y, yErr); 757 889 758 890 A = psImageAlloc(polyOrder, polyOrder, PS_TYPE_F64);
Note:
See TracChangeset
for help on using the changeset viewer.
