- Timestamp:
- Apr 28, 2005, 11:17:02 PM (21 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
branches/eam-psphot-branch/psLib/src/dataManip/psMinimize.c
r3578 r3788 9 9 * @author GLG, MHPCC 10 10 * 11 * @version $Revision: 1.110 $ $Name: not supported by cvs2svn $12 * @date $Date: 2005-0 3-31 01:02:15$11 * @version $Revision: 1.110.6.1 $ $Name: not supported by cvs2svn $ 12 * @date $Date: 2005-04-29 09:17:02 $ 13 13 * 14 14 * Copyright 2004-2005 Maui High Performance Computing Center, University of Hawaii … … 557 557 } 558 558 559 /****************************************************************************** 560 psMinimizeLMChi2(): This routine will take an procedure which calculates 561 an arbitrary function and it's derivative and minimize the chi-squared match 562 between that function at the specified coords and the specified value at 563 those coords. 564 565 XXX: Do this: 566 After checking that all entries in the paramMask are 1 or 0, when 567 forming the A matrix from alpha, try this: 568 569 A[i][i] = (1 + lambda*paramask[i]) * alpha[i][i]; 570 571 XXX: This is very different from what is specified in the SDR. Must 572 coordinate with IfA on new SDR. 573 574 XXX: Do vector/image recycles. 575 576 XXX: probably yErr will be part of the SDR. 577 578 XXX: This must work for both F32 and F64. F32 is currently implemented. 579 Note: since the LUD routines are only implemented in F64, then we 580 will have to convert all F32 input vectors to F64 regardless. So, 581 the F64 port might be. 582 583 XXX: Must update the covar matrix. 584 *****************************************************************************/ 559 // XXX EAM this is my re-implementation of MinLM 585 560 psBool psMinimizeLMChi2(psMinimization *min, 586 561 psImage *covar, … … 601 576 PS_PTR_CHECK_NULL(func, NULL); 602 577 578 // this function has test and current values for several things 579 // the current best value is in lower case 580 // the next guess value is in upper case 581 582 // allocate internal arrays (current vs Guess) 583 psImage *alpha = psImageAlloc (params->n, params->n, PS_TYPE_F64); 584 psImage *Alpha = psImageAlloc (params->n, params->n, PS_TYPE_F64); 585 psVector *beta = psVectorAlloc (params->n, PS_TYPE_F64); 586 psVector *Beta = psVectorAlloc (params->n, PS_TYPE_F64); 587 psVector *Params = psVectorAlloc (params->n, PS_TYPE_F64); 588 psVector *dy = NULL; 589 psF64 chisq = 0.0; 590 psF64 Chisq = 0.0; 591 psF64 lambda = 0.001; 592 593 // the initial guess on params is provided by the user 594 Params = psVectorCopy (Params, params, PS_TYPE_F32); 595 596 // the user provides the error or NULL. we need to convert 597 // to appropriate weights 598 dy = psVectorAlloc (y->n, PS_TYPE_F32); 599 if (yErr != NULL) { 600 for (int i = 0; i < dy->n; i++) { 601 dy->data.F32[i] = 1.0 / PS_SQR (yErr->data.F32[i]); 602 } 603 } else { 604 for (int i = 0; i < dy->n; i++) { 605 dy->data.F32[i] = 1.0; 606 } 607 } 608 609 // calculate initial alpha and beta, set chisq (min->value) 610 min->value = p_psMinLM_SetABX (alpha, beta, params, x, y, dy, func); 611 # ifndef PS_NO_TRACE 612 // dump some useful info if trace is defined 613 if (psTraceGetLevel (".psLib.dataManip.psMinimizeLMChi2") > 4) { 614 p_psImagePrint (psTraceGetDestination(), alpha, "alpha guess"); 615 p_psVectorPrint (psTraceGetDestination(), beta, "beta guess"); 616 p_psVectorPrint (psTraceGetDestination(), params, "params guess"); 617 } 618 # endif /* PS_NO_TRACE */ 619 620 621 // iterate until the tolerance is reached, or give up 622 while ((min->lastDelta > min->tol) && (min->iter < min->maxIter)) { 623 624 // set a new guess for Alpha, Beta, Params 625 p_psMinLM_GuessABP (Alpha, Beta, Params, alpha, beta, params, lambda); 626 627 # ifndef PS_NO_TRACE 628 // dump some useful info if trace is defined 629 if (psTraceGetLevel (".psLib.dataManip.psMinimizeLMChi2") > 4) { 630 p_psImagePrint (psTraceGetDestination(), Alpha, "alpha guess"); 631 p_psVectorPrint (psTraceGetDestination(), Beta, "beta guess"); 632 p_psVectorPrint (psTraceGetDestination(), Params, "params guess"); 633 } 634 # endif /* PS_NO_TRACE */ 635 636 // calculate Chisq for new guess, update Alpha & Beta 637 Chisq = p_psMinLM_SetABX (Alpha, Beta, Params, x, y, dy, func); 638 psTrace (".psLib.dataManip.psMinimizeLMChi2", 3, "chisq: %f, Chisq %f, delta: %f\n", chisq, Chisq, min->lastDelta); 639 640 // accept new guess (if improvement), or increase lambda 641 if (Chisq < min->value) { 642 min->lastDelta = (min->value - Chisq) / (dy->n - params->n); 643 min->value = Chisq; 644 alpha = psImageCopy (alpha, Alpha, PS_TYPE_F64); 645 beta = psVectorCopy (beta, Beta, PS_TYPE_F64); 646 params = psVectorCopy (params, Params, PS_TYPE_F32); 647 lambda *= 0.1; 648 } else { 649 lambda *= 10.0; 650 } 651 min->iter ++; 652 } 653 psTrace (".psLib.dataManip.psMinimizeLMChi2", 3, "chisq: %f, Chisq %f, delta: %f\n", chisq, Chisq, min->lastDelta); 654 655 // free the internal temporary data 656 psFree (alpha); 657 psFree (Alpha); 658 psFree (beta); 659 psFree (Beta); 660 psFree (Params); 661 psFree (dy); 662 return (true); 663 } 664 665 // XXX EAM: this needs to respect the mask on params 666 // XXX EAM: check not NULL on alpha, beta, params 667 // alpha, beta, params are already allocated 668 psF64 p_psMinLM_SetABX (psImage *alpha, 669 psVector *beta, 670 psVector *params, 671 const psArray *x, 672 const psVector *y, 673 const psVector *dy, 674 psMinimizeLMChi2Func func) 675 { 676 677 psF64 chisq; 678 psF64 delta; 679 psF64 weight; 680 psF64 ymodel; 681 psVector *deriv = psVectorAlloc (params->n, PS_TYPE_F32); 682 683 // zero alpha and beta for summing below 684 for (int j = 0; j < params->n; j++) { 685 for (int k = 0; k < params->n; k++) { 686 alpha->data.F64[j][k] = 0; 687 } 688 beta->data.F64[j] = 0; 689 } 690 chisq = 0.0; 691 692 // calculate chisq, alpha, beta 693 for (int i = 0; i < y->n; i++) { 694 ymodel = func (deriv, params, (psVector *) x->data[i]); 695 696 delta = ymodel - y->data.F32[i]; 697 chisq += PS_SQR (delta) * dy->data.F32[i]; 698 699 for (int j = 0; j < params->n; j++) { 700 weight = deriv->data.F32[j] * dy->data.F32[i]; 701 for (int k = 0; k <= j; k++) { 702 alpha->data.F64[j][k] += weight * deriv->data.F32[k]; 703 } 704 beta->data.F64[j] += weight * delta; 705 } 706 } 707 708 // calculate lower-left half of alpha 709 for (int j = 1; j < params->n; j++) { 710 for (int k = 0; k < j; k++) { 711 alpha->data.F64[k][j] = alpha->data.F64[j][k]; 712 } 713 } 714 psFree (deriv); 715 return (chisq); 716 } 717 718 // XXX EAM : can we use static copies of LUv, LUm, A? 719 psBool p_psMinLM_GuessABP (psImage *Alpha, 720 psVector *Beta, 721 psVector *Params, 722 psImage *alpha, 723 psVector *beta, 724 psVector *params, 725 psF64 lambda) 726 { 727 728 # define USE_LU_DECOMP 1 729 # if (USE_LU_DECOMP) 730 psVector *LUv = NULL; 731 psImage *LUm = NULL; 732 psImage *A = NULL; 733 psF32 det; 734 735 // LU decomposition version 736 psTrace (".pslib.dataManip.psMinLM_GuessABP", 3, "using LUD version"); 737 738 // set new guess values (creates matrix A) 739 A = psImageCopy (NULL, alpha, PS_TYPE_F64); 740 for (int j = 0; j < params->n; j++) { 741 A->data.F64[j][j] = alpha->data.F64[j][j] * (1.0 + lambda); 742 } 743 744 // solve A*beta = Beta (Alpha = 1/A) 745 // these operations do not modify the input values (creates LUm, LUv) 746 LUm = psMatrixLUD (NULL, &LUv, A); 747 Beta = psMatrixLUSolve (Beta, LUm, beta, LUv); 748 Alpha = psMatrixInvert (Alpha, A, &det); 749 750 # else 751 // gauss-jordan version 752 psTrace (".pslib.dataManip.psMinLM_GuessABP", 3, "using Gauss-J version"); 753 754 // set new guess values (creates matrix A) 755 Beta = psVectorCopy (Beta, beta, PS_TYPE_F64); 756 Alpha = psImageCopy (Alpha, alpha, PS_TYPE_F64); 757 for (int j = 0; j < params->n; j++) { 758 Alpha->data.F64[j][j] = alpha->data.F64[j][j] * (1.0 + lambda); 759 } 760 761 psGaussJordan (Alpha, Beta); 762 # endif 763 764 // apply beta to get new params values 765 for (int j = 0; j < params->n; j++) { 766 Params->data.F32[j] = params->data.F32[j] - Beta->data.F64[j]; 767 } 768 769 # if (USE_LU_DECOMP) 770 psFree (A); 771 psFree (LUm); 772 psFree (LUv); 773 # endif 774 775 return true; 776 } 777 778 # define SWAP(X,Y) {double tmp=(X); (X) = (Y); (Y) = tmp;} 779 780 // XXX EAM : temporary gauss-jordan solver based on gene's 781 // version based on the Numerical Recipes version 782 bool psGaussJordan (psImage *a, psVector *b) 783 { 784 785 int *indxc,*indxr,*ipiv; 786 int Nx, icol, irow; 787 int i, j, k, l, ll; 788 float big, dum, pivinv; 789 psF64 *vector; 790 psF64 **matrix; 791 792 Nx = a->numCols; 793 matrix = a->data.F64; 794 vector = b->data.F64; 795 796 indxc = psAlloc (Nx*sizeof(int)); 797 indxr = psAlloc (Nx*sizeof(int)); 798 ipiv = psAlloc (Nx*sizeof(int)); 799 for (j = 0; j < Nx; j++) 800 ipiv[j] = 0; 801 802 irow = icol = 0; 803 big = fabs(matrix[0][0]); 804 805 for (i = 0; i < Nx; i++) { 806 big = 0.0; 807 for (j = 0; j < Nx; j++) { 808 if (!finite(matrix[i][j])) { 809 // XXX EAM: this should use the psError stack 810 fprintf (stderr, "GAUSSJ: NaN\n"); 811 goto fescape; 812 } 813 if (ipiv[j] != 1) { 814 for (k = 0; k < Nx; k++) { 815 if (ipiv[k] == 0) { 816 if (fabs (matrix[j][k]) >= big) { 817 big = fabs (matrix[j][k]); 818 irow = j; 819 icol = k; 820 } 821 } else { 822 if (ipiv[k] > 1) { 823 // XXX EAM: this should use the psError stack 824 fprintf (stderr, "GAUSSJ: Singular Matrix! (1)\n"); 825 goto fescape; 826 } 827 } 828 } 829 } 830 } 831 ipiv[icol]++; 832 if (irow != icol) { 833 for (l = 0; l < Nx; l++) { 834 SWAP (matrix[irow][l], matrix[icol][l]); 835 } 836 SWAP (vector[irow], vector[icol]); 837 } 838 indxr[i] = irow; 839 indxc[i] = icol; 840 if (matrix[icol][icol] == 0.0) { 841 // XXX EAM: this should use the psError stack 842 fprintf (stderr, "GAUSSJ: Singular Matrix! (2)\n"); 843 goto fescape; 844 } 845 pivinv = 1.0 / matrix[icol][icol]; 846 matrix[icol][icol] = 1.0; 847 for (l = 0; l < Nx; l++) { 848 matrix[icol][l] *= pivinv; 849 } 850 vector[icol] *= pivinv; 851 852 for (ll = 0; ll < Nx; ll++) { 853 if (ll != icol) { 854 dum = matrix[ll][icol]; 855 matrix[ll][icol] = 0.0; 856 for (l = 0; l < Nx; l++) 857 matrix[ll][l] -= matrix[icol][l]*dum; 858 vector[ll] -= vector[icol]*dum; 859 } 860 } 861 } 862 863 for (l = Nx - 1; l >= 0; l--) { 864 if (indxr[l] != indxc[l]) 865 for (k = 0; k < Nx; k++) 866 SWAP (matrix[k][indxr[l]], matrix[k][indxc[l]]); 867 } 868 psFree (ipiv); 869 psFree (indxr); 870 psFree (indxc); 871 return (true); 872 873 fescape: 874 psFree (ipiv); 875 psFree (indxr); 876 psFree (indxc); 877 return (false); 878 } 879 880 /****************************************************************************** 881 psMinimizeLMChi2(): This routine will take an procedure which calculates 882 an arbitrary function and it's derivative and minimize the chi-squared match 883 between that function at the specified coords and the specified value at 884 those coords. 885 886 XXX: Do this: 887 After checking that all entries in the paramMask are 1 or 0, when 888 forming the A matrix from alpha, try this: 889 890 A[i][i] = (1 + lambda*paramask[i]) * alpha[i][i]; 891 892 XXX: This is very different from what is specified in the SDR. Must 893 coordinate with IfA on new SDR. 894 895 XXX: Do vector/image recycles. 896 897 XXX: probably yErr will be part of the SDR. 898 899 XXX: This must work for both F32 and F64. F32 is currently implemented. 900 Note: since the LUD routines are only implemented in F64, then we 901 will have to convert all F32 input vectors to F64 regardless. So, 902 the F64 port might be. 903 904 XXX: Must update the covar matrix. 905 *****************************************************************************/ 906 psBool psMinimizeLMChi2Old(psMinimization *min, 907 psImage *covar, 908 psVector *params, 909 const psVector *paramMask, 910 const psArray *x, 911 const psVector *y, 912 const psVector *yErr, 913 psMinimizeLMChi2Func func) 914 { 915 PS_PTR_CHECK_NULL(min, NULL); 916 PS_VECTOR_CHECK_NULL(params, NULL); 917 PS_VECTOR_CHECK_EMPTY(params, NULL); 918 PS_PTR_CHECK_NULL(x, NULL); 919 PS_VECTOR_CHECK_NULL(y, NULL); 920 PS_VECTOR_CHECK_EMPTY(y, NULL); 921 PS_VECTOR_CHECK_SIZE_EQUAL(x, y, NULL); 922 PS_PTR_CHECK_NULL(func, NULL); 923 603 924 if (paramMask != NULL) { 604 925 PS_VECTOR_CHECK_SIZE_EQUAL(params, paramMask, NULL); … … 636 957 psF32 currChi2 = 0.0; 637 958 psF32 newChi2 = 0.0; 638 psF32 lamda = 0.00005; 639 lamda = 0.05; 959 psF32 lamda = 0.00005; // XXX EAM : this starting value is VERY small (lamda is mis-spelt) 960 lamda = 0.05; // XXX EAM : this starting value is quite large (lamda is mis-spelt) 640 961 641 962 psTrace(".psLib.dataManip.psMinimize", 6, … … 661 982 // 662 983 currChi2 = 0.0; 663 currValueVec = func(deriv, params, x); 984 // currValueVec = func(deriv, params, x); 985 986 // XXX EAM: use BinaryOp ? 987 // t1 = BinaryOp (NULL, currValueVec, "-", y); 988 // t1 = BinaryOp (t1, t1, "*", t1); 989 990 // XXX EAM: this ignores yErr 664 991 for (n=0;n<numData;n++) { 665 992 currChi2+= (currValueVec->data.F32[n] - y->data.F32[n]) * … … 670 997 } 671 998 999 // XXX EAM: this is just for tracing 672 1000 for (p=0;p<numParams;p++) { 673 1001 psTrace(".psLib.dataManip.psMinimize", 6, … … 679 1007 // 680 1008 // Mask elements of the derivative for each data point. 681 // 1009 // XXX EAM : is this necessary? probably not... 682 1010 for (p=0;p<numParams;p++) { 683 1011 if ((paramMask != NULL) && (paramMask->data.U8[p] != 0)) { … … 690 1018 // 691 1019 // Calculate the BETA vector. 692 // 1020 // XXX EAM: I think this is wrong 693 1021 for (p=0;p<numParams;p++) { 1022 if ((paramMask != NULL) && (paramMask->data.U8[p] != 0)) { 1023 continue; 1024 } 694 1025 beta->data.F64[p] = 0.0; 695 1026 for (n=0;n<numData;n++) { … … 707 1038 // 708 1039 // Calculate the ALPHA matrix. 709 // 1040 // XXX EAM: also wrong? (missing yErr) 710 1041 for (k=0;k<numParams;k++) { 711 1042 for (l=0;l<numParams;l++) { … … 773 1104 // 774 1105 newChi2 = 0.0; 775 newValueVec = func(deriv, newParams, x);1106 // newValueVec = func(deriv, newParams, x); 776 1107 for (n=0;n<numData;n++) { 777 1108 newChi2+= (newValueVec->data.F32[n] - y->data.F32[n]) * … … 1098 1429 min->value = 0.0; 1099 1430 min->iter = 0; 1100 min->lastDelta = 0.0;1431 min->lastDelta = tol + 1; 1101 1432 1102 1433 return(min);
Note:
See TracChangeset
for help on using the changeset viewer.
