- Timestamp:
- May 31, 2013, 6:19:08 AM (13 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
branches/eam_branches/ipp-20130509/psLib/src/math/psMinimizeLMM.c
r29542 r35615 360 360 } 361 361 362 363 362 /****************************************************************************** 364 363 psMinimizeLMChi2(): This routine will take an procedure which calculates an … … 580 579 } 581 580 581 /****************************************************************************** 582 psMinimizeLMChi2(): This routine takes a function-pointer (func) which calculates an arbitrary 583 function and it's derivatives and minimizes the chi-squared match between that function at the 584 specified points and the specified value at those points. 585 586 The original version of this function used a convergence criterion based on the change in 587 chisq. this has problems since it depends on the choice of points used to measure the fit. 588 (consider a gaussian on a background : it 100 pixels are used -- and some or most contribute to 589 the chisq -- and the delta-chisq is 10%, then the same change in model fit will yield a 590 delta-chisq of 1% if 1000 pixels are used (all but the 100 measuring the background)). 591 592 This implementation uses changes to the parameters and stops if they are no longer significant. 593 594 This requires F32 input data; all internal calls use F32. 595 *****************************************************************************/ 596 bool psMinimizeLMChi2_Alt( 597 psMinimization *min, 598 psImage *covar, 599 psVector *params, 600 psMinConstraint *constraint, 601 const psArray *x, 602 const psVector *y, 603 const psVector *yWt, 604 psMinimizeLMChi2Func func) 605 { 606 psTrace("psLib.math", 3, "---- begin ----\n"); 607 PS_ASSERT_PTR_NON_NULL(min, false); 608 PS_ASSERT_VECTOR_NON_NULL(params, false); 609 PS_ASSERT_VECTOR_NON_EMPTY(params, false); 610 PS_ASSERT_VECTOR_TYPE(params, PS_TYPE_F32, false); 611 psVector *paramMask = NULL; 612 if (constraint != NULL) { 613 paramMask = constraint->paramMask; 614 if (paramMask != NULL) { 615 PS_ASSERT_VECTOR_TYPE(paramMask, PS_TYPE_VECTOR_MASK, false); 616 PS_ASSERT_VECTORS_SIZE_EQUAL(params, paramMask, false); 617 } 618 } 619 PS_ASSERT_PTR_NON_NULL(x, false); 620 for (psS32 i = 0 ; i < x->n ; i++) { 621 psVector *coord = (psVector *) (x->data[i]); 622 PS_ASSERT_VECTOR_NON_NULL(coord, false); 623 PS_ASSERT_VECTOR_TYPE(coord, PS_TYPE_F32, false); 624 } 625 PS_ASSERT_VECTOR_NON_NULL(y, false); 626 PS_ASSERT_VECTOR_NON_EMPTY(y, false); 627 PS_ASSERT_VECTOR_TYPE(y, PS_TYPE_F32, false); 628 PS_ASSERT_VECTORS_SIZE_EQUAL(x, y, false); 629 if (yWt != NULL) { 630 PS_ASSERT_VECTOR_TYPE(yWt, PS_TYPE_F32, false); 631 PS_ASSERT_VECTORS_SIZE_EQUAL(y, yWt, false); 632 } 633 PS_ASSERT_PTR_NON_NULL(func, false); 634 635 psMinimizeLMLimitFunc checkLimits = NULL; 636 if (constraint) { 637 checkLimits = constraint->checkLimits; 638 } 639 640 // this function has test and current values for several things 641 // the current best value is in lower case 642 // the next guess value is in upper case 643 644 // allocate internal arrays (current vs Guess) 645 psImage *Alpha = NULL; 646 psVector *Beta = NULL; 647 648 // Alpha & Beta only contain elements to represent the unmasked parameters 649 if (!psMinLM_AllocAB (&Alpha, &Beta, params, paramMask)) { 650 psAbort ("programming error: no unmasked parameters to be fit\n"); 651 } 652 653 psImage *alpha = psImageAlloc(Alpha->numCols, Alpha->numRows, PS_TYPE_F32); 654 psVector *beta = psVectorAlloc(Beta->n, PS_TYPE_F32); 655 psVector *Params = psVectorAlloc(params->n, PS_TYPE_F32); 656 657 psVector *dy = NULL; 658 psF32 Chisq = 0.0; 659 psF32 lambda = 0.001; 660 psF32 dLinear = 0.0; 661 662 // the user provides the error or NULL. we need to convert 663 // to appropriate weights 664 if (yWt != NULL) { 665 dy = (psVector *) yWt; 666 } else { 667 dy = psVectorAlloc(y->n, PS_TYPE_F32); 668 psVectorInit(dy, 1.0); 669 } 670 671 // number of degrees of freedom for this fit 672 int nDOF = dy->n - params->n; 673 674 // calculate initial alpha and beta, set chisq (min->value) 675 min->value = psMinLM_SetABX(alpha, beta, params, paramMask, x, y, dy, func); 676 if (isnan(min->value)) { 677 min->iter = min->maxIter; 678 psFree(alpha); 679 psFree(Alpha); 680 psFree(beta); 681 psFree(Beta); 682 psFree(Params); 683 return(false); 684 } 685 // dump some useful info if trace is defined 686 if (psTraceGetLevel("psLib.math") >= 6) { 687 p_psImagePrint(psTraceGetDestination(), alpha, "alpha guess (0)"); 688 p_psVectorPrint(psTraceGetDestination(), beta, "beta guess (0)"); 689 } 690 if (psTraceGetLevel("psLib.math") >= 5) { 691 p_psVectorPrint(psTraceGetDestination(), params, "params guess (0)"); 692 } 693 694 // iterate until: (a) nIter = min->iter or (b) (chisq / ndof) < maxChisq and deltaChisq < minTol (but don't stop unless Chisq is finite) 695 bool done = (min->iter >= min->maxIter); 696 while (!done) { 697 psTrace("psLib.math", 5, "Iteration number %d. (max iterations is %d).\n", min->iter, min->maxIter); 698 psTrace("psLib.math", 5, "Last delta is %f. stop if < %f, accept if < %f\n", min->lastDelta, min->minTol, min->maxTol); 699 700 // set a new guess for Alpha, Beta, Params 701 if (!psMinLM_GuessABP(Alpha, Beta, Params, alpha, beta, params, paramMask, checkLimits, lambda, &dLinear)) { 702 min->iter ++; 703 if (min->iter >= min->maxIter) break; 704 lambda *= 10.0; 705 continue; 706 } 707 708 // dump some useful info if trace is defined 709 if (psTraceGetLevel("psLib.math") >= 6) { 710 p_psImagePrint(psTraceGetDestination(), Alpha, "Alpha guess (1)"); 711 p_psVectorPrint(psTraceGetDestination(), Beta, "Beta guess (1)"); 712 p_psVectorPrint(psTraceGetDestination(), beta, "beta current (1)"); 713 } 714 if (psTraceGetLevel("psLib.math") >= 5) { 715 p_psVectorPrint(psTraceGetDestination(), Params, "params guess (1)"); 716 } 717 718 // calculate Chisq for new guess, update Alpha & Beta 719 Chisq = psMinLM_SetABX(Alpha, Beta, Params, paramMask, x, y, dy, func); 720 if (isnan(Chisq)) { 721 min->iter ++; 722 if (min->iter >= min->maxIter) break; 723 lambda *= 10.0; 724 continue; 725 } 726 727 // convergence criterion: 728 // compare the delta (min->value - Chisq) with the 729 // expected delta from the linear model (dLinear) 730 // accept new guess if it is an improvement (rho > 0), or else increase lambda 731 psF32 rho = (min->value - Chisq) / dLinear; 732 733 psTrace("psLib.math", 5, "last chisq: %f, new chisq %f, delta: %f, dLinear: %f, rho: %f, lambda: %f, nDOF: %d\n", min->value, Chisq, min->lastDelta, dLinear, rho, lambda, nDOF); 734 735 psTrace("psLib.math.dLinear", 5, "last chisq: %f, new chisq %f, delta: %f, dLinear: %f, rho: %f, lambda: %f\n", min->value, Chisq, min->lastDelta, dLinear, rho, lambda); 736 737 // dump some useful info if trace is defined 738 if (psTraceGetLevel("psLib.math") >= 6) { 739 p_psImagePrint(psTraceGetDestination(), Alpha, "alpha guess (2)"); 740 p_psVectorPrint(psTraceGetDestination(), Beta, "beta guess (2)"); 741 } 742 743 // change in chisq/nDOF since last minimum 744 min->lastDelta = (min->value - Chisq) / nDOF; 745 746 /* rho is positive if the new chisq is smaller; allow for some insignificant change (slight negative rho) */ 747 if (rho >= -1e-6) { 748 min->value = Chisq; 749 alpha = psImageCopy(alpha, Alpha, PS_TYPE_F32); 750 beta = psVectorCopy(beta, Beta, PS_TYPE_F32); 751 params = psVectorCopy(params, Params, PS_TYPE_F32); 752 lambda *= 0.25; 753 } else { 754 lambda *= 10.0; 755 } 756 min->iter++; 757 758 // ending conditions: 759 // 1) hard limit : too many iterations 760 done = (min->iter >= min->maxIter); 761 762 // 2) require chisqDOF < maxChisqDOF (if maxChisqDOF is not NAN) 763 float chisqDOF = Chisq / nDOF; 764 if (isfinite(min->maxChisqDOF) && (chisqDOF > min->maxChisqDOF)) { 765 continue; 766 } 767 768 // 3) require deltaChi > 1e-6 769 if (min->lastDelta < 1e-5) { 770 continue; 771 } 772 773 // 4) require rParDelta < \eta * rParSigma 774 // rParDelta : radius of parameter change; 775 // rParSigma : radius of parameter error 776 777 // note that alpha & beta only represent unmasked parameters 778 779 // R(Par_sigma) = \sum (alpha[i][i]) 780 float rParSigma = 0.0; 781 for (int j = 0; j < beta->n; j++) { 782 rParSigma += Alpha->data.F32[j][j]; 783 } 784 rParSigma = sqrt(rParSigma); 785 786 // note that beta or Beta is the actual parameter change for this pass : 787 // new param = old param - beta. I need to be sure I'm using the new 788 // or the old one and also the one before or after the matrix eqn Ax = B is solved. 789 float rParDelta = 0.0; 790 for (int j = 0; j < beta->n; j++) { 791 rParDelta += PS_SQR(lastBeta->data.F32[j] - Beta->data.F32[j]); 792 } 793 rParDelta = sqrt(rParDelta); 794 795 psTrace("psLib.math", 5, "rParDelta : %f, rParSigma: %f, Niter: %d\n", rParDelta, rParSigma, min->iter); 796 } 797 psTrace("psLib.math", 5, "chisq: %f, last delta: %f, Niter: %d\n", min->value, min->lastDelta, min->iter); 798 799 // construct & return the covariance matrix (if requested) 800 if (covar != NULL) { 801 if (!psMinLM_GuessABP(Alpha, Beta, Params, alpha, beta, params, paramMask, NULL, 0.0, NULL)) { 802 psTrace ("psLib.math", 5, "failure to calculate covariance matrix\n"); 803 } 804 // set covar values which are not masked 805 psImageInit (covar, 0.0); 806 for (int j = 0, J = 0; j < params->n; j++) { 807 if (paramMask && (paramMask->data.PS_TYPE_VECTOR_MASK_DATA[j])) { 808 covar->data.F32[j][j] = 1.0; 809 continue; 810 } 811 for (int k = 0, K = 0; k < params->n; k++) { 812 if (paramMask && (paramMask->data.PS_TYPE_VECTOR_MASK_DATA[k])) continue; 813 covar->data.F32[j][k] = Alpha->data.F32[J][K]; 814 K++; 815 } 816 J++; 817 } 818 } 819 820 // free the internal temporary data 821 psFree(alpha); 822 psFree(Alpha); 823 psFree(beta); 824 psFree(Beta); 825 psFree(Params); 826 if (yWt == NULL) { 827 psFree(dy); 828 } 829 830 // if the last improvement was at least as good as maxTol, accept the fit: 831 if (min->lastDelta <= min->maxTol) { 832 psTrace("psLib.math", 6, "---- end (true) ----\n"); 833 return(true); 834 } 835 psTrace("psLib.math", 6, "---- end (false) ----\n"); 836 return(false); 837 } 838 582 839 bool psMinLM_AllocAB (psImage **Alpha, psVector **Beta, const psVector *params, const psVector *paramMask) { 583 840
Note:
See TracChangeset
for help on using the changeset viewer.
