Changeset 2197
- Timestamp:
- Oct 26, 2004, 11:25:59 AM (22 years ago)
- Location:
- trunk/psLib
- Files:
-
- 15 edited
-
src/astro/psCoord.c (modified) (4 diffs)
-
src/astronomy/psCoord.c (modified) (4 diffs)
-
src/dataManip/psConstants.h (modified) (6 diffs)
-
src/dataManip/psFunctions.c (modified) (1 diff)
-
src/dataManip/psMinimize.c (modified) (2 diffs)
-
src/dataManip/psMinimize.h (modified) (3 diffs)
-
src/dataManip/psStats.c (modified) (29 diffs)
-
src/math/psConstants.h (modified) (6 diffs)
-
src/math/psMinimize.c (modified) (2 diffs)
-
src/math/psMinimize.h (modified) (3 diffs)
-
src/math/psPolynomial.c (modified) (1 diff)
-
src/math/psSpline.c (modified) (1 diff)
-
src/math/psStats.c (modified) (29 diffs)
-
test/dataManip/tst_psMinimize06.c (modified) (5 diffs)
-
test/dataManip/tst_psStats07.c (modified) (4 diffs)
Legend:
- Unmodified
- Added
- Removed
-
trunk/psLib/src/astro/psCoord.c
r2104 r2197 10 10 * @author George Gusciora, MHPCC 11 11 * 12 * @version $Revision: 1.2 5$ $Name: not supported by cvs2svn $13 * @date $Date: 2004-10- 14 01:17:50$12 * @version $Revision: 1.26 $ $Name: not supported by cvs2svn $ 13 * @date $Date: 2004-10-26 21:24:42 $ 14 14 * 15 15 * Copyright 2004 Maui High Performance Computing Center, University of Hawaii … … 58 58 /*****************************************************************************/ 59 59 60 static float p_psArg(float x, float y);61 62 /******************************************************************************63 XXX: Verify this arc tan function.64 XXX: macro65 XXX: I don't think this arg() is correct.66 *****************************************************************************/67 68 float p_psArg(float x,69 float y)70 {71 if (y!= 0.0) {72 return(atan(y/x));73 } else {74 return(0.5 * M_PI);75 }76 return (0.0);77 /*78 if (x > 0) {79 return (atan(y / x));80 } else if ((x == 0) && (y == 0)) {81 return (0.5 * M_PI);82 } else if ((x == 0) && (y == 0)) {83 return (-0.5 * M_PI);84 } else if ((x == 0) && (y == 0)) {85 return (M_PI + atan(y / x));86 } else if ((x == 0) && (y == 0)) {87 return (-M_PI + atan(y / x));88 }89 psAbort(__func__, "Unacceptable range for (p_psArg(%f, %f).\n", x, y);90 */91 }92 93 60 /*****************************************************************************/ 94 61 /* FUNCTION IMPLEMENTATION - PUBLIC */ … … 292 259 if (projection->type == PS_PROJ_TAN) { 293 260 R = sqrt((coord->x * coord->x) + (coord->y * coord->y)); 294 tmp->d = p_psArg(-coord->y, coord->x);261 tmp->d = atan2(-coord->y, coord->x); 295 262 tmp->r = atan(180.0 / (R * M_PI)); 296 263 297 264 } else if (projection->type == PS_PROJ_SIN) { 298 265 R = sqrt((coord->x * coord->x) + (coord->y * coord->y)); 299 tmp->d = p_psArg(-coord->y, coord->x);266 tmp->d = atan2(-coord->y, coord->x); 300 267 tmp->r = acos((R * M_PI) / 180.0); 301 268 … … 314 281 chu2 *= chu2; 315 282 chu = sqrt(1.0 - chu1 - chu2); 316 tmp->d = 2.0 * p_psArg((2.0 * chu * chu) - 1.0, (coord->x * chu * M_PI) / 360.0);283 tmp->d = 2.0 * atan2((2.0 * chu * chu) - 1.0, (coord->x * chu * M_PI) / 360.0); 317 284 tmp->r = asin((coord->y * chu * M_PI) / 180.0); 318 285 -
trunk/psLib/src/astronomy/psCoord.c
r2104 r2197 10 10 * @author George Gusciora, MHPCC 11 11 * 12 * @version $Revision: 1.2 5$ $Name: not supported by cvs2svn $13 * @date $Date: 2004-10- 14 01:17:50$12 * @version $Revision: 1.26 $ $Name: not supported by cvs2svn $ 13 * @date $Date: 2004-10-26 21:24:42 $ 14 14 * 15 15 * Copyright 2004 Maui High Performance Computing Center, University of Hawaii … … 58 58 /*****************************************************************************/ 59 59 60 static float p_psArg(float x, float y);61 62 /******************************************************************************63 XXX: Verify this arc tan function.64 XXX: macro65 XXX: I don't think this arg() is correct.66 *****************************************************************************/67 68 float p_psArg(float x,69 float y)70 {71 if (y!= 0.0) {72 return(atan(y/x));73 } else {74 return(0.5 * M_PI);75 }76 return (0.0);77 /*78 if (x > 0) {79 return (atan(y / x));80 } else if ((x == 0) && (y == 0)) {81 return (0.5 * M_PI);82 } else if ((x == 0) && (y == 0)) {83 return (-0.5 * M_PI);84 } else if ((x == 0) && (y == 0)) {85 return (M_PI + atan(y / x));86 } else if ((x == 0) && (y == 0)) {87 return (-M_PI + atan(y / x));88 }89 psAbort(__func__, "Unacceptable range for (p_psArg(%f, %f).\n", x, y);90 */91 }92 93 60 /*****************************************************************************/ 94 61 /* FUNCTION IMPLEMENTATION - PUBLIC */ … … 292 259 if (projection->type == PS_PROJ_TAN) { 293 260 R = sqrt((coord->x * coord->x) + (coord->y * coord->y)); 294 tmp->d = p_psArg(-coord->y, coord->x);261 tmp->d = atan2(-coord->y, coord->x); 295 262 tmp->r = atan(180.0 / (R * M_PI)); 296 263 297 264 } else if (projection->type == PS_PROJ_SIN) { 298 265 R = sqrt((coord->x * coord->x) + (coord->y * coord->y)); 299 tmp->d = p_psArg(-coord->y, coord->x);266 tmp->d = atan2(-coord->y, coord->x); 300 267 tmp->r = acos((R * M_PI) / 180.0); 301 268 … … 314 281 chu2 *= chu2; 315 282 chu = sqrt(1.0 - chu1 - chu2); 316 tmp->d = 2.0 * p_psArg((2.0 * chu * chu) - 1.0, (coord->x * chu * M_PI) / 360.0);283 tmp->d = 2.0 * atan2((2.0 * chu * chu) - 1.0, (coord->x * chu * M_PI) / 360.0); 317 284 tmp->r = asin((coord->y * chu * M_PI) / 180.0); 318 285 -
trunk/psLib/src/dataManip/psConstants.h
r2136 r2197 6 6 * @author GLG, MHPCC 7 7 * 8 * @version $Revision: 1.1 2$ $Name: not supported by cvs2svn $9 * @date $Date: 2004-10- 14 23:43:12 $8 * @version $Revision: 1.13 $ $Name: not supported by cvs2svn $ 9 * @date $Date: 2004-10-26 21:24:42 $ 10 10 * 11 11 * Copyright 2004 Maui High Performance Computing Center, University of Hawaii … … 107 107 } \ 108 108 109 /** Preprocessor macro to generate error on a NULL vector */ 110 #define PS_CHECK_NULL_VECTOR_RETURN_F0(NAME) \ 111 if (NAME == NULL || NAME->data.V == NULL) { \ 112 psError(__func__,"Unallowable operation: %s or its data is NULL.", #NAME); \ 113 return(0.0); \ 114 } \ 115 109 116 /** Preprocessor macro to generate error on a NULL poniter */ 110 117 #define PS_CHECK_NULL_PTR_RETURN_NULL(NAME) \ … … 113 120 return(NULL); \ 114 121 } 122 123 /** Preprocessor macro to generate error on a NULL poniter */ 124 #define PS_CHECK_NULL_PTR_RETURN_F0(NAME) \ 125 if (NAME == NULL) { \ 126 psError(__func__,"Unallowable operation: %s is NULL.", #NAME); \ 127 return(0.0); \ 128 } 129 115 130 /** Preprocessor macro to generate error on a NULL poniter */ 116 131 #define PS_CHECK_NULL_PTR_RETURN_ZERO(NAME) \ … … 127 142 } \ 128 143 144 /** Preprocessor macro to generate error for zero length vector */ 145 #define PS_CHECK_EMPTY_VECTOR_RETURN_F0(NAME) \ 146 if (NAME->n < 1) { \ 147 psError(__func__,"Unallowable operation: %s has zero n value.", #NAME); \ 148 return(0.0); \ 149 } \ 150 129 151 /** Preprocessor macro to generate error on differing size vectors */ 130 152 #define PS_CHECK_VECTOR_SIZE_EQUAL_RETURN_NULL(VEC1, VEC2) \ … … 132 154 psError(__func__,"Vector %s has size %d, Vector %s has size %d.", #VEC1, VEC1->n, #VEC2, VEC2->n); \ 133 155 return(NULL); \ 156 } 157 158 /** Preprocessor macro to generate error on differing size vectors */ 159 #define PS_CHECK_VECTOR_SIZE_EQUAL_RETURN_F0(VEC1, VEC2) \ 160 if (VEC1->n != VEC2->n) { \ 161 psError(__func__,"Vector %s has size %d, Vector %s has size %d.", #VEC1, VEC1->n, #VEC2, VEC2->n); \ 162 return(0.0); \ 134 163 } 135 164 … … 199 228 200 229 #define PS_MAX(A, B) \ 201 (( A > B) ? A : B) \230 (((A) > (B)) ? (A) : (B)) \ 202 231 203 232 #define PS_MIN(A, B) \ 204 (( A < B) ? A : B) \205 233 (((A) < (B)) ? (A) : (B)) \ 234 -
trunk/psLib/src/dataManip/psFunctions.c
r2106 r2197 7 7 * polynomials. It also contains a Gaussian functions. 8 8 * 9 * @version $Revision: 1.5 2$ $Name: not supported by cvs2svn $10 * @date $Date: 2004-10- 14 01:44:48$9 * @version $Revision: 1.53 $ $Name: not supported by cvs2svn $ 10 * @date $Date: 2004-10-26 21:24:42 $ 11 11 * 12 12 * Copyright 2004 Maui High Performance Computing Center, University of Hawaii -
trunk/psLib/src/dataManip/psMinimize.c
r2106 r2197 9 9 * @author GLF, MHPCC 10 10 * 11 * @version $Revision: 1.5 8$ $Name: not supported by cvs2svn $12 * @date $Date: 2004-10- 14 01:44:48$11 * @version $Revision: 1.59 $ $Name: not supported by cvs2svn $ 12 * @date $Date: 2004-10-26 21:24:42 $ 13 13 * 14 14 * Copyright 2004 Maui High Performance Computing Center, University of Hawaii … … 636 636 psFree(currValueVec); 637 637 psFree(newValueVec); 638 639 if ((min->iter < min->maxIter) || 640 (min->lastDelta <= min->tol)) { 641 return(true); 642 } 643 644 psTrace(".psLib.dataManip.psMinimizeLMChi2", 4, 645 "---- psMinimizeLMChi2() end (false) ----\n"); 646 return(false); 647 } 648 649 /****************************************************************************** 650 psMyMinimizeLMChi2(): This routine will take an procedure which calculates 651 an arbitrary function and it's derivative and minimize the chi-squared match 652 between that function at the specified coords and the specified value at 653 those coords. 654 655 XXX: Do this: 656 After checking that all entries in the paramMask are 1 or 0, when 657 forming the A matrix from alpha, try this: 658 659 A[i][i] = (1 + lambda*paramask[i]) * alpha[i][i]; 660 661 XXX: This is very different from what is specified in the SDR. Must 662 coordinate with IfA on new SDR. 663 664 XXX: Do vector/image recycles. 665 666 XXX: probably yErr will be part of the SDR. 667 668 XXX: This must work for both F32 and F64. F32 is currently implemented. 669 Note: since the LUD routines are only implemented in F64, then we 670 will have to convert all F32 input vectors to F64 regardless. So, 671 the F64 port might be. 672 *****************************************************************************/ 673 bool psMyMinimizeLMChi2(psMinimization *min, 674 psImage *covar, 675 psVector *params, 676 const psVector *paramMask, 677 const psArray *x, 678 const psVector *y, 679 const psVector *yErr, 680 psMyMinimizeLMChi2Func func) 681 { 682 PS_CHECK_NULL_PTR_RETURN_NULL(min); 683 PS_CHECK_NULL_VECTOR_RETURN_NULL(params); 684 PS_CHECK_EMPTY_VECTOR_RETURN_NULL(params); 685 PS_CHECK_NULL_PTR_RETURN_NULL(x); 686 PS_CHECK_NULL_VECTOR_RETURN_NULL(y); 687 PS_CHECK_EMPTY_VECTOR_RETURN_NULL(y); 688 PS_CHECK_VECTOR_SIZE_EQUAL_RETURN_NULL(x, y); 689 if (paramMask != NULL) { 690 PS_CHECK_VECTOR_SIZE_EQUAL_RETURN_NULL(params, paramMask); 691 } 692 if (yErr != NULL) { 693 PS_CHECK_VECTOR_SIZE_EQUAL_RETURN_NULL(y, yErr); 694 } 695 696 psTrace(".psLib.dataManip.psMinimizeLMChi2", 4, 697 "---- psMinimizeLMChi2() begin ----\n"); 698 int numData = y->n; 699 int numParams = params->n; 700 int i; 701 int j; 702 int k; 703 int l; 704 int n; 705 int p; 706 psVector *beta = psVectorAlloc(numParams, PS_TYPE_F64); 707 psVector *perm = psVectorAlloc(numParams, PS_TYPE_F64); 708 709 psVector *paramDeltasF64 = psVectorAlloc(numParams, PS_TYPE_F64); 710 psVector *origParams = psVectorAlloc(numParams, PS_TYPE_F32); 711 psVector *newParams = psVectorAlloc(numParams, PS_TYPE_F32); 712 713 psImage *alpha = psImageAlloc(numParams, numParams, PS_TYPE_F32); 714 psImage *A = psImageAlloc(numParams, numParams, PS_TYPE_F64); 715 psImage *aOut = psImageAlloc(numParams, numParams, PS_TYPE_F64); 716 717 // psVector **deriv = (psVector **) psAlloc(numData * sizeof(psVector *)); 718 // for (i=0;i<numData;i++) { 719 // deriv[i] = psVectorAlloc(numParams, PS_TYPE_F32); 720 // } 721 psImage *deriv = psImageAlloc(numParams, numData, PS_TYPE_F32); 722 723 psVector *currValueVec; 724 psVector *newValueVec; 725 726 float currChi2 = 0.0; 727 float newChi2 = 0.0; 728 float lamda = 0.00005; 729 730 psTrace(".psLib.dataManip.psMinimizeLMChi2", 6, 731 "min->maxIter is %d\n", min->maxIter); 732 psTrace(".psLib.dataManip.psMinimizeLMChi2", 6, 733 "min->tol is %f\n", min->tol); 734 735 for (p=0;p<numParams;p++) { 736 origParams->data.F32[p] = params->data.F32[p]; 737 } 738 739 min->lastDelta = HUGE; 740 min->iter = 0; 741 742 while ((min->lastDelta > min->tol) && (min->iter < min->maxIter)) { 743 psTrace(".psLib.dataManip.psMinimizeLMChi2", 4, 744 "------------------------------------------------------\n"); 745 psTrace(".psLib.dataManip.psMinimizeLMChi2", 4, 746 "Iteration %d. Delta is %f\n", min->iter, min->lastDelta); 747 748 // 749 // Calculate the current values and chi-squared of the function. 750 // 751 currChi2 = 0.0; 752 currValueVec = func(deriv, params, x); 753 for (n=0;n<numData;n++) { 754 currChi2+= (currValueVec->data.F32[n] * currValueVec->data.F32[n]); 755 } 756 757 for (p=0;p<numParams;p++) { 758 psTrace(".psLib.dataManip.psMinimizeLMChi2", 6, 759 "params->data.F32[%d] is %f.\n", p, params->data.F32[p]); 760 } 761 psTrace(".psLib.dataManip.psMinimizeLMChi2", 6, 762 "Current chi-squared is (%f)\n", currChi2); 763 764 // 765 // Mask elements of the derivative for each data point. 766 // 767 for (p=0;p<numParams;p++) { 768 if ((paramMask != NULL) && (paramMask->data.U8[p] != 0)) { 769 for (n=0;n<numData;n++) { 770 deriv->data.F32[n][p] = 0.0; 771 } 772 } 773 } 774 775 // 776 // Calculate the BETA vector. 777 // 778 for (p=0;p<numParams;p++) { 779 beta->data.F64[p] = 0.0; 780 for (n=0;n<numData;n++) { 781 (beta->data.F64[p])+= 782 (y->data.F32[n] - currValueVec->data.F32[n]) * 783 deriv->data.F32[n][p]; 784 } 785 // XXX: multiple by -1 here? 786 (beta->data.F64[p])*= -1.0; 787 psTrace(".psLib.dataManip.psMinimizeLMChi2", 6, 788 "beta->data.F64[%d] is %f.\n", p, beta->data.F64[p]); 789 } 790 psFree(currValueVec); 791 792 // 793 // Calculate the ALPHA matrix. 794 // 795 for (k=0;k<numParams;k++) { 796 for (l=0;l<numParams;l++) { 797 alpha->data.F32[k][l] = 0.0; 798 for (n=0;n<numData;n++) { 799 alpha->data.F32[k][l]+= deriv->data.F32[n][k] * 800 deriv->data.F32[n][l]; 801 } 802 } 803 } 804 805 // 806 // Calculate the matrix A. 807 // 808 for (j=0;j<numParams;j++) { 809 for (k=0;k<numParams;k++) { 810 if (j == k) { 811 A->data.F64[j][k] = 812 (double) ((1.0 + lamda) * alpha->data.F32[j][k]); 813 } else { 814 A->data.F64[j][k] = (double) alpha->data.F32[j][k]; 815 } 816 } 817 } 818 for (j=0;j<numParams;j++) { 819 psTrace(".psLib.dataManip.psMinimizeLMChi2", 6, "Matrix A[][]:\n"); 820 for (k=0;k<numParams;k++) { 821 psTrace(".psLib.dataManip.psMinimizeLMChi2", 6, "%f ", A->data.F64[j][k]); 822 } 823 psTrace(".psLib.dataManip.psMinimizeLMChi2", 6, "Matrix A[][]:\n"); 824 } 825 826 // 827 // Solve A * alpha = Beta 828 // 829 aOut = psMatrixLUD(aOut, perm, A); 830 paramDeltasF64 = psMatrixLUSolve(paramDeltasF64, aOut, beta, perm); 831 832 // 833 // Mask any masked parameters. 834 // 835 for (i=0;i<numParams;i++) { 836 psTrace(".psLib.dataManip.psMinimizeLMChi2", 6, 837 "paramDeltasF64->data.F64[%d] is %f.\n", i, paramDeltasF64->data.F64[i]); 838 if ((paramMask != NULL) && (paramMask->data.U8[i] != 0)) { 839 newParams->data.F32[i] = origParams->data.F32[i]; 840 } else { 841 newParams->data.F32[i] = params->data.F32[i] - 842 (float) paramDeltasF64->data.F64[i]; 843 } 844 } 845 846 psTrace(".psLib.dataManip.psMinimizeLMChi2", 6, 847 "Calling func() with new parameters:\n"); 848 for (i=0;i<numParams;i++) { 849 psTrace(".psLib.dataManip.psMinimizeLMChi2", 6, 850 "newParams->data.F32[%d] is %f.\n", i, newParams->data.F32[i]); 851 } 852 853 854 // 855 // Calculate new function values. 856 // 857 newChi2 = 0.0; 858 newValueVec = func(deriv, newParams, x); 859 for (n=0;n<numData;n++) { 860 newChi2+= (newValueVec->data.F32[n] * newValueVec->data.F32[n]); 861 } 862 psFree(newValueVec); 863 864 psTrace(".psLib.dataManip.psMinimizeLMChi2", 4, 865 "old/new chi-squareds are (%f, %f)\n", currChi2, newChi2); 866 867 // 868 // If the new chi-squared is lower, then keep it. 869 // 870 if (currChi2 > newChi2) { 871 min->lastDelta = currChi2 - newChi2; 872 min->value = newChi2; 873 874 // We already masked params. 875 for (i=0;i<numParams;i++) { 876 params->data.F32[i] = (float) newParams->data.F32[i]; 877 } 878 lamda*= 0.1; 879 } else { 880 lamda*= 10.0; 881 } 882 psTrace(".psLib.dataManip.psMinimizeLMChi2", 4, 883 "lamda is %f\n", lamda); 884 min->iter++; 885 } 886 psFree(beta); 887 psFree(perm); 888 psFree(paramDeltasF64); 889 psFree(origParams); 890 psFree(newParams); 891 psFree(alpha); 892 psFree(A); 893 psFree(aOut); 894 psFree(deriv); 638 895 639 896 if ((min->iter < min->maxIter) || -
trunk/psLib/src/dataManip/psMinimize.h
r1992 r2197 8 8 * @author GLG, MHPCC 9 9 * 10 * @version $Revision: 1. 29$ $Name: not supported by cvs2svn $11 * @date $Date: 2004-10- 06 23:38:49$10 * @version $Revision: 1.30 $ $Name: not supported by cvs2svn $ 11 * @date $Date: 2004-10-26 21:24:43 $ 12 12 * 13 13 * Copyright 2004 Maui High Performance Computing Center, University of Hawaii … … 84 84 85 85 86 /* 87 Bug 203: 88 89 typedef float (*psMinimizeLMChi2Func)(psVector *deriv, const psVector *params, 90 const psVector *x); 91 92 This function takes the current guess for the parameters for which we are 93 trying to get the best values (params), and a single vector (x) of 94 conditions from the array of x values fed into the minimiser. 95 96 bool psMinimizeLMChi2(psMinimization *min, 97 psImage *covar, 98 psVector *params, 99 const psVector *paramMask, 100 const psArray *x, 101 const psVector *y, 102 const psVector *yErr, 103 psMinimizeLMChi2Func func); 104 105 This takes the minimization specs (min), returns the covariance matrix 106 (covar), takes the best guess of initial parameters (params), the parameter 107 mask (paramMask), and takes multiple vectors of conditions in an array (x), 108 the corresponding measured values (y) and errors (yErr) and the function to 109 fit (func). 110 111 For example, for GRB afterglows, I have flux as a function of time and 112 frequency. So I stuff into the "psArray *x" all my time and frequency values 113 (so a whole heap of vectors of size 2), I have the measured values in "y" and 114 errors in "yErr". Then each of the time-frequency pairs are passed to my model 115 function with the current parameters, and the model function returns the flux 116 for that time-frequency pair, and the derivative with respect to each of the 117 parameters. 118 119 This seems reasonable. The only thing we could change would be to have the 120 function be defined: 121 122 typedef psVector* (*psMinimizeLMChi2Func)(psImage *deriv, 123 const psVector *params, 124 const psArray *x); 125 126 So it would return the model value for each of the measurements at once, and 127 return for each the derivatives (so that it returns a matrix). 128 129 What do you think? 130 131 132 133 I'm not sure I understand how LM chi-squared minimization will work with the 134 following function that you define: 135 136 typedef psVector* (*psMinimizeLMChi2Func)(psImage *deriv, 137 const psVector *params, 138 const psArray *x); 139 140 The chi-squared minimization algorithm, as defined in NR, requires that 141 function to be minimized be evaluated at each data point, and that all 142 derivatives, with respect to each parameter, be calculated at each data 143 point. In the above, can I assume that 144 145 x is an array of psVectors, with each vector corresponding to a single 146 data point. 147 148 The returned value has the same length as x. It contains the value of 149 the function at each data point in x. 150 151 deriv: an n-by-p matrix where "n" is the number of data points, and "p" 152 is the number of parameters. The [i][j] element of this matrix 153 holds the derivative of the function at the i-th data point with 154 respect to the j-th parameter. 155 156 157 158 */ 159 160 86 161 // XXX: What if any of these arguments are NULL? 162 163 87 164 typedef 88 165 float (*psMinimizeLMChi2Func)(psVector *deriv, … … 98 175 psMinimizeLMChi2Func func); 99 176 177 178 typedef 179 psVector* (*psMyMinimizeLMChi2Func)(psImage *deriv, 180 const psVector *params, 181 const psArray *x); 182 183 bool psMyMinimizeLMChi2(psMinimization *min, 184 psImage *covar, 185 psVector *params, 186 const psVector *paramMask, 187 const psArray *x, 188 const psVector *y, 189 const psVector *yErr, 190 psMyMinimizeLMChi2Func func); 191 100 192 typedef 101 193 float (*psMinimizePowellFunc)(const psVector *params, -
trunk/psLib/src/dataManip/psStats.c
r2074 r2197 9 9 * @author GLG, MHPCC 10 10 * 11 * @version $Revision: 1.6 7$ $Name: not supported by cvs2svn $12 * @date $Date: 2004-10- 13 02:40:13 $11 * @version $Revision: 1.68 $ $Name: not supported by cvs2svn $ 12 * @date $Date: 2004-10-26 21:24:43 $ 13 13 * 14 14 * Copyright 2004 Maui High Performance Computing Center, University of Hawaii … … 40 40 /*****************************************************************************/ 41 41 // will use robust statistical methods. 42 #define GAUSS_WIDTH 20// The width of the Gaussian or boxcar smoothing.42 #define GAUSS_WIDTH 5 // The width of the Gaussian or boxcar smoothing. 43 43 #define CLIPPED_NUM_ITER_LB 1 44 44 #define CLIPPED_NUM_ITER_UB 10 … … 57 57 /* TYPE DEFINITIONS */ 58 58 /*****************************************************************************/ 59 psVector* p_psConvertToF32(psVector* in); 59 60 60 61 /*****************************************************************************/ … … 423 424 float rangeMax = 0.0; // Exclude date above this 424 425 425 // Determine if the number of data points exceed a threshold which will426 // cause to generate robust stats, as opposed to exact stats.427 // XXX: This code is no longer used. We now calculate the median exactly428 // regardless of the vector size.429 /*430 * // Calculate the robust quartiles. stats2 = psStatsAlloc(PS_STAT_ROBUST_MEDIAN);431 * p_psVectorRobustStats(myVector, maskVector, maskVal, stats2);432 *433 * // Store the robust quartiles into the sample quartile members. stats->sampleMedian =434 * stats2->robustMedian;435 *436 * // Free temporary data buffers. psFree(stats2);437 *438 * // Set the PS_STAT_ROBUST_FOR_SAMPLE bit in the stats structure. stats->options = stats->options |439 * PS_STAT_ROBUST_FOR_SAMPLE;440 *441 * return; } */442 443 426 // Determine how many data points fit inside this min/max range 444 427 // and are not masked, IF the maskVector is not NULL> … … 507 490 508 491 /****************************************************************************** 509 This routine smoothes the data in the input robustHistogram with a 510 Gaussian of width sigma. 511 512 XXX: Must consult with IfA on the proper values for the Gaussian 513 smoothing. Currently, the Gaussian coefficients are such that only 514 the center coefficient is non-zero. This is because "e" is being 515 raised to a very large negative number for all points except the 516 center point. 517 518 XXX: use a static variable for gaussianCoefs[] and compute them once. 519 *****************************************************************************/ 520 psVector* p_psVectorsmoothHistGaussian(psHistogram* robustHistogram, 492 p_psVectorSmoothHistGaussian(): This routine smoothes the data in the input 493 robustHistogram with a Gaussian of width sigma. 494 *****************************************************************************/ 495 #define GAUSS_WIDTH_OTHER 5.0 496 psVector* p_psVectorSmoothHistGaussian(psHistogram* robustHistogram, 521 497 float sigma) 522 498 { 523 499 int i = 0; // Loop index variable 524 500 int j = 0; // Loop index variable 525 float denom = 0.0; // Temporary variable 526 float expo = 0.0; // Temporary variable 527 float gaussianCoefs[1 + (2 * GAUSS_WIDTH)]; // The Gaussian Coefficients 528 psVector* smooth = psVectorAlloc(robustHistogram->nums->n, PS_TYPE_F32); 529 530 for (i = 0; i < (1 + (2 * GAUSS_WIDTH)); i++) { 531 if (fabs(sigma) >= FLT_EPSILON) { 532 // If sigma does not equal zero, then we use Gaussian smoothing. 533 #ifdef DARWIN 534 denom = (float)sqrt(2.0 * M_PI * sigma * sigma); 535 #else 536 537 denom = sqrtf(2.0 * M_PI * sigma * sigma); 538 #endif 539 540 expo = -(float)((i - GAUSS_WIDTH) * (i - GAUSS_WIDTH)); 541 expo /= (2.0 * sigma * sigma); 542 gaussianCoefs[i] = exp(expo / denom); 543 544 //printf("p_psVectorsmoothHistGaussian(): gaussianCoefs[%d] is %f\n", i, gaussianCoefs[i]); 545 // NOTE: Gaussian smoothing just isn't working with low sigma 546 // values. The problem is that the Gaussian coefficients are 547 // all zero, except for the middle coefficient, which is exactly 548 // one. Therefore, I'm using boxcar smoothing. 549 gaussianCoefs[i] = 1.0 / (1.0 + (2.0 * (float)GAUSS_WIDTH)); 550 // printf("gaussianCoefs[%d] is %f\n", i, gaussianCoefs[i]); 551 } else { 552 /* If sigma equals zero (all pixels have the same value) the above code will divide by zero. 553 * Therefore, we don't need to smooth the data. */ 554 for (i = 0; i < robustHistogram->nums->n; i++) { 555 smooth->data.F32[i] = (float)robustHistogram->nums->data.S32[i]; 556 } 557 return (smooth); 558 } 559 } 560 561 // Perform the actual smoothing. 562 for (i = 0; i < robustHistogram->nums->n; i++) { 501 float iMid; 502 float jMid; 503 int numBins = robustHistogram->nums->n; 504 int numBounds = robustHistogram->bounds->n; 505 psVector* smooth = psVectorAlloc(numBins, PS_TYPE_F32); 506 int jMin = 0; 507 int jMax = 0; 508 float firstBound = robustHistogram->bounds->data.F32[0]; 509 float lastBound = robustHistogram->bounds->data.F32[numBounds-1]; 510 psScalar x; 511 512 x.type.type = PS_TYPE_F32; 513 for (i = 0; i < numBins; i++) { 514 iMid = (robustHistogram->bounds->data.F32[i] + 515 robustHistogram->bounds->data.F32[i+1]) / 2.0; 516 517 // YYY: The p_psVectorBinDisect() routine does much of the work of 518 // the following conditionals, however, it also reports a warning 519 // message. I don't want the warning message so I reproduce the 520 // conditionals here. Maybe p_psVectorBinDisect() should not produce 521 // warnings? 522 523 x.data.F32 = iMid - (GAUSS_WIDTH * sigma); 524 if ((x.data.F32 >= firstBound) && (x.data.F32 <= lastBound)) { 525 jMin = p_psVectorBinDisect(robustHistogram->bounds, &x); 526 } else if (x.data.F32 <= firstBound) { 527 jMin = 0; 528 } else if (x.data.F32 >= lastBound) { 529 jMin = robustHistogram->bounds->n - 1; 530 531 } 532 533 x.data.F32 = iMid + (GAUSS_WIDTH * sigma); 534 if ((x.data.F32 >= firstBound) && (x.data.F32 <= lastBound)) { 535 jMax = p_psVectorBinDisect(robustHistogram->bounds, &x); 536 } else if (x.data.F32 <= firstBound) { 537 jMax = 0; 538 } else if (x.data.F32 >= lastBound) { 539 jMax = robustHistogram->bounds->n - 1; 540 541 } 542 563 543 smooth->data.F32[i] = 0.0; 564 for (j = -GAUSS_WIDTH; j <= +GAUSS_WIDTH; j++) { 565 if (((j + i) >= 0) && ((j + i) < smooth->n)) { 566 smooth->data.F32[i] += (gaussianCoefs[j + GAUSS_WIDTH] * 567 (float)robustHistogram->nums->data.S32[j + i]); 568 } 569 } 570 } 571 return (smooth); 544 for (j = jMin ; j <= jMax ; j++) { 545 jMid = (robustHistogram->bounds->data.F32[j] + 546 robustHistogram->bounds->data.F32[j+1]) / 2.0; 547 smooth->data.F32[i] += 548 ((float) robustHistogram->nums->data.U32[j]) * 549 psGaussian(jMid, iMid, sigma, true); 550 } 551 } 552 553 return(smooth); 572 554 } 573 555 … … 913 895 specified data point. 914 896 *****************************************************************************/ 915 float p_psGaussian(const psVector* restrict myData, const psVector* restrict myParams) 897 float p_psGaussian(const psVector* restrict myData, 898 const psVector* restrict myParams) 916 899 { 917 900 float x = myData->data.F32[0]; … … 930 913 calculates the specified partial derivative of the above Gaussian function. 931 914 *****************************************************************************/ 932 float p_psGaussianDeriv(const psVector* restrict myData, const psVector* restrict myParams, int whichParam) 915 float p_psGaussianDeriv(const psVector* restrict myData, 916 const psVector* restrict myParams, int whichParam) 933 917 { 934 918 float x = myData->data.F32[0]; … … 1036 1020 1037 1021 /****************************************************************************** 1038 p_psFitQuadratic(robustHistogram. cumulativeSums, binNum, fitFloat): given 1039 the specified histogram, with the specified pre-calculated cumulativeSums, 1040 this routine fits a quadratic f(x) to the 3 bins surrounding bin "binNum", 1041 and then finds the point x such that f(x) == fitFloat. 1022 fitQuadraticSearchForYThenReturnX(*xVec, *yVec, binNum, yVal): This routine 1023 takes psVectors of x/y pairs as input, and fits a quadratic to the 3 points 1024 surrounding element binNum in the vectors (the midpoint between element i 1025 and i+1 is used for x[i]). It then determines for what value x does that 1026 quadratic f(x) = yVal (the input parameter). 1042 1027 1043 XXX: This function is currently not being used. 1044 *****************************************************************************/ 1045 float p_psFitQuadratic(psHistogram* histogram, 1046 psVector* cumulativeSums, 1047 int binNum, 1048 float fitFloat) 1049 { 1028 // XXX: Use static variables. 1029 *****************************************************************************/ 1030 float fitQuadraticSearchForYThenReturnX(psVector *xVec, 1031 psVector *yVec, 1032 int binNum, 1033 float yVal) 1034 { 1035 // static psVector* x = NULL; 1036 // static psVector* y = NULL; 1037 // static psVector* yErr = NULL; 1050 1038 psVector* x = psVectorAlloc(3, PS_TYPE_F64); 1051 1039 psVector* y = psVectorAlloc(3, PS_TYPE_F64); 1052 1040 psVector* yErr = psVectorAlloc(3, PS_TYPE_F64); 1041 1042 /* 1043 if (x == NULL) { 1044 x = psVectorAlloc(3, PS_TYPE_F64); 1045 p_psMemSetPersistent(x, true); 1046 } 1047 if (y == NULL) { 1048 y = psVectorAlloc(3, PS_TYPE_F64); 1049 p_psMemSetPersistent(y, true); 1050 } 1051 if (yErr == NULL) { 1052 yErr = psVectorAlloc(3, PS_TYPE_F64); 1053 p_psMemSetPersistent(yErr, true); 1054 } 1055 */ 1053 1056 psPolynomial1D* myPoly = psPolynomial1DAlloc(2, PS_POLYNOMIAL_ORD); 1054 1055 if ((binNum > 0) && (binNum < (histogram->nums->n + 1))) { 1056 x->data.F64[0] = (double)0.5 * 1057 (histogram->bounds->data.F32[binNum - 1] + histogram->bounds->data.F32[binNum]); 1058 x->data.F64[1] = (double)0.5 * 1059 (histogram->bounds->data.F32[binNum] + histogram->bounds->data.F32[binNum + 1]); 1060 x->data.F64[2] = (double)0.5 * 1061 (histogram->bounds->data.F32[binNum + 1] + histogram->bounds->data.F32[binNum + 2]); 1062 1063 y->data.F64[0] = cumulativeSums->data.F32[binNum - 1]; 1064 y->data.F64[1] = cumulativeSums->data.F32[binNum]; 1065 y->data.F64[2] = cumulativeSums->data.F32[binNum + 1]; 1066 1067 if (!((y->data.F64[0] <= fitFloat) && (fitFloat <= y->data.F64[2]))) { 1068 psAbort(__func__, "p_psVectorRobustStats(0): midpoint not within y-range\n"); 1069 } 1070 1057 float tmpFloat; 1058 1059 if ((binNum > 0) && (binNum < (yVec->n - 2))) { 1060 x->data.F64[0] = (double) (0.5 * (xVec->data.F32[binNum - 1] + xVec->data.F32[binNum])); 1061 x->data.F64[1] = (double) (0.5 * (xVec->data.F32[binNum] + xVec->data.F32[binNum+1])); 1062 x->data.F64[2] = (double) (0.5 * (xVec->data.F32[binNum+1] + xVec->data.F32[binNum+2])); 1063 y->data.F64[0] = yVec->data.F32[binNum - 1]; 1064 y->data.F64[1] = yVec->data.F32[binNum]; 1065 y->data.F64[2] = yVec->data.F32[binNum + 1]; 1066 1067 // Ensure that yVal is within the range of the bins we are using. 1068 if (!((y->data.F64[0] <= yVal) && (yVal <= y->data.F64[2]))) { 1069 printf("((%f), %f, %f)\n", yVal, y->data.F64[0], y->data.F64[2]); 1070 psError(__func__, "yVal not within y-range\n"); 1071 } 1071 1072 yErr->data.F64[0] = 1.0; 1072 1073 yErr->data.F64[1] = 1.0; 1073 1074 yErr->data.F64[2] = 1.0; 1074 1075 1076 // Determine the coefficients of the polynomial. 1075 1077 myPoly = psVectorFitPolynomial1D(myPoly, x, y, yErr); 1076 return (p_ps1DPolyMedian(myPoly, x->data.F64[0], x->data.F64[2], fitFloat)); 1078 // Call p_ps1DPolyMedian(), which does a binary search on the 1079 // polynomial, looking for the value x such that f(x) = yVal 1080 tmpFloat = p_ps1DPolyMedian(myPoly, x->data.F64[0], x->data.F64[2], yVal); 1077 1081 } else { 1078 return (0.5 * (histogram->bounds->data.F32[binNum + 1] + histogram->bounds->data.F32[binNum])); 1082 if (binNum == 0) { 1083 tmpFloat = 0.5 * (xVec->data.F32[binNum] + 1084 xVec->data.F32[binNum + 1]); 1085 } else if (binNum == (xVec->n - 1)) { 1086 // XXX: Is this right? 1087 tmpFloat = xVec->data.F32[binNum]; 1088 } else if (binNum == (xVec->n - 2)) { 1089 // XXX: Is this right? 1090 tmpFloat = 0.5 * (xVec->data.F32[binNum] + 1091 xVec->data.F32[binNum + 1]); 1092 } 1079 1093 } 1080 1094 … … 1083 1097 psFree(yErr); 1084 1098 psFree(myPoly); 1085 return (0.0); 1086 } 1099 return(tmpFloat); 1100 } 1101 1102 #define PS_BIN_MIDPOINT(HISTOGRAM, BIN_NUM) \ 1103 (0.5 * (HISTOGRAM->bounds->data.F32[(BIN_NUM)] + HISTOGRAM->bounds->data.F32[(BIN_NUM)+1])) 1087 1104 1088 1105 /****************************************************************************** … … 1111 1128 *****************************************************************************/ 1112 1129 void p_psVectorRobustStats(const psVector* restrict myVector, 1113 const psVector* restrict maskVector, unsigned int maskVal, psStats* stats) 1130 const psVector* restrict maskVector, 1131 unsigned int maskVal, 1132 psStats* stats) 1114 1133 { 1115 1134 psHistogram* robustHistogram = NULL; … … 1118 1137 int LQBinNum = -1; // Bin num for lower quartile 1119 1138 int UQBinNum = -1; // Bin num for upper quartile 1139 int medianBinNum = -1; 1120 1140 int i = 0; // Loop index variable 1121 int m axBinNum = 0;1122 float m axBinCount = 0.0;1141 int modeBinNum = 0; 1142 float modeBinCount = 0.0; 1123 1143 float dL = 0.0; 1124 1144 int numBins = 0; 1125 psStats* tmpStats = psStatsAlloc(PS_STAT_CLIPPED_STDEV | PS_STAT_CLIPPED_MEAN);1126 1127 // psImage* domain;1128 // psVector* errors;1129 // psVector* data;1130 // psVector* initialGuess;1131 // psVector* theParams;1132 // float chiSq=0.0;1133 // float max = -HUGE;1134 // float max_pos;1135 1145 float myMean = 0.0; 1136 1146 float myStdev = 0.0; … … 1139 1149 float sumSquares = 0.0; 1140 1150 float sumDiffs = 0.0; 1141 psVector* x = psVectorAlloc(3, PS_TYPE_F64); 1142 psVector* y = psVectorAlloc(3, PS_TYPE_F64); 1143 psVector* yErr = psVectorAlloc(3, PS_TYPE_F64); 1144 psPolynomial1D* myPoly = psPolynomial1DAlloc(2, PS_POLYNOMIAL_ORD); 1145 psVector* cumulativeRobustSumsFullRange = NULL; 1146 psVector* cumulativeRobustSumsDlRange = NULL; 1151 psVector* cumulativeRobustSums = NULL; 1147 1152 float sumRobust = 0.0; 1148 1153 float sumN50 = 0.0; 1149 1154 float sumNfit = 0.0; 1150 float cumulativeMedian = 0.0; 1155 psScalar tmpScalar; 1156 tmpScalar.type.type = PS_TYPE_F32; 1157 psStats* tmpStats = psStatsAlloc(PS_STAT_CLIPPED_STDEV | PS_STAT_CLIPPED_MEAN); 1151 1158 1152 1159 // Compute the initial bin size of the robust histogram. This is done … … 1188 1195 p_psVectorMax(myVector, maskVector, maskVal, stats); 1189 1196 } 1197 1190 1198 // Create the histogram structure. NOTE: we can not specify the bin size 1191 1199 // precisely since the argument to psHistogramAlloc() is the number of … … 1198 1206 psVectorHistogram(robustHistogram, myVector, maskVector, maskVal); 1199 1207 1200 // Smooth the histogram. 1201 // XXX: is that the right stdev? 1202 robustHistogramVector = p_psVectorsmoothHistGaussian(robustHistogram, 1208 // Smooth the histogram, Gaussian-style. 1209 robustHistogramVector = p_psVectorSmoothHistGaussian(robustHistogram, 1203 1210 tmpStats->clippedStdev / 4.0f); 1204 1211 … … 1208 1215 1209 1216 /************************************************************************** 1210 Determine the lower/upper quartiles. 1217 Determine the median/lower/upper quartile bin numbers. 1218 1219 We define a vector called "cumulativeRobustSums" where the value at 1220 index position i is equal to the sum of bins 0:i. This will be used in 1221 determining the median and lower/upper quartiles. 1211 1222 **************************************************************************/ 1212 // We define a vector called "cumulativeRobustSums..." where the value at 1213 // index position i is equal to the sum of bins 0:i. This will be used 1214 // now and later in determining the lower/upper quartiles. 1215 cumulativeRobustSumsFullRange = psVectorAlloc(robustHistogramVector->n, PS_TYPE_F32); 1216 cumulativeRobustSumsFullRange->data.F32[0] = robustHistogramVector->data.F32[0]; 1223 cumulativeRobustSums = psVectorAlloc(robustHistogramVector->n, PS_TYPE_F32); 1224 cumulativeRobustSums->data.F32[0] = robustHistogramVector->data.F32[0]; 1217 1225 for (i = 1; i < robustHistogramVector->n; i++) { 1218 cumulativeRobustSumsFullRange->data.F32[i] = 1219 cumulativeRobustSumsFullRange->data.F32[i - 1] + robustHistogramVector->data.F32[i]; 1220 } 1221 sumRobust = cumulativeRobustSumsFullRange->data.F32[robustHistogramVector->n - 1]; 1222 1223 // Determine the bin number containing the lower quartile point. 1224 LQBinNum = -1; 1225 for (i = 0; i < cumulativeRobustSumsFullRange->n; i++) { 1226 if (cumulativeRobustSumsFullRange->data.F32[i] >= (sumRobust / 4.0)) { 1227 LQBinNum = i; 1228 break; 1229 } 1230 } 1231 1232 // Determine the bin number containing the upper quartile point. 1233 UQBinNum = -1; 1234 for (i = cumulativeRobustSumsFullRange->n - 1; i >= 0; i--) { 1235 if (cumulativeRobustSumsFullRange->data.F32[i] <= (3.0 * sumRobust / 4.0)) { 1236 UQBinNum = i; 1237 break; 1238 } 1239 } 1240 1241 if ((LQBinNum == -1) || (UQBinNum == -1)) { 1242 psAbort(__func__, "Could not determine the robust lower/upper quartiles."); 1243 } 1244 1226 cumulativeRobustSums->data.F32[i] = cumulativeRobustSums->data.F32[i - 1] + 1227 robustHistogramVector->data.F32[i]; 1228 } 1229 sumRobust = cumulativeRobustSums->data.F32[robustHistogramVector->n - 1]; 1230 1231 tmpScalar.data.F32 = sumRobust / 4.0; 1232 LQBinNum = p_psVectorBinDisect(cumulativeRobustSums, &tmpScalar); 1233 tmpScalar.data.F32 = 3.0 * sumRobust / 4.0; 1234 UQBinNum = p_psVectorBinDisect(cumulativeRobustSums, &tmpScalar); 1235 tmpScalar.data.F32 = sumRobust / 2.0; 1236 medianBinNum = p_psVectorBinDisect(cumulativeRobustSums, &tmpScalar); 1237 1238 if ((LQBinNum < 0) || (UQBinNum < 0)) { 1239 psError(__func__, "Could not determine the robust lower/upper quartile bin numbers."); 1240 } 1241 if (medianBinNum < 0) { 1242 psError(__func__, "Could not determine the robust lower/upper quartile bin numbers."); 1243 } 1245 1244 /************************************************************************** 1246 1245 Determine the mode in the range LQ:UQ. 1247 1246 **************************************************************************/ 1248 1247 // Determine the bin with the peak value in the range LQ to UQ. 1249 m axBinNum = LQBinNum;1250 m axBinCount = robustHistogramVector->data.F32[LQBinNum];1251 sumN50 = (float)robustHistogram->nums->data. S32[LQBinNum];1248 modeBinNum = LQBinNum; 1249 modeBinCount = robustHistogramVector->data.F32[LQBinNum]; 1250 sumN50 = (float)robustHistogram->nums->data.U32[LQBinNum]; 1252 1251 for (i = LQBinNum + 1; i <= UQBinNum; i++) { 1253 if (robustHistogramVector->data.F32[i] > maxBinCount) { 1254 maxBinNum = i; 1255 maxBinCount = robustHistogramVector->data.F32[i]; 1256 } 1257 sumN50 += (float)robustHistogram->nums->data.S32[i]; 1258 } 1259 1260 // XXX: is dL defined as the value at the LQ/UQ, or the bin number? 1252 if (robustHistogramVector->data.F32[i] > modeBinCount) { 1253 modeBinNum = i; 1254 modeBinCount = robustHistogramVector->data.F32[i]; 1255 } 1256 sumN50 += (float)robustHistogram->nums->data.U32[i]; 1257 } 1258 1261 1259 dL = (UQBinNum - LQBinNum) / 4; 1262 1263 printf("(LQBinNum, UQBinNum, maxBinNum) is (%d, %d, %d)\n", LQBinNum, UQBinNum, maxBinNum);1264 1265 1260 /************************************************************************** 1266 1261 Determine the mean/stdev for the bins in the range mode-dL to mode+dL 1267 1262 **************************************************************************/ 1268 cumulativeRobustSumsDlRange = psVectorAlloc(robustHistogramVector->n, PS_TYPE_F32);1269 for (i = 0; i < robustHistogramVector->n; i++) {1270 cumulativeRobustSumsDlRange->data.F32[i] = 0.0;1271 }1272 sumNfit = 0.0;1273 cumulativeMedian = 0.0;1274 for (i = maxBinNum - dL; i <= maxBinNum + dL; i++) {1275 if ((0 <= i) && (i < robustHistogramVector->n)) {1276 cumulativeRobustSumsDlRange->data.F32[i] =1277 cumulativeRobustSumsDlRange->data.F32[i - 1] + robustHistogramVector->data.F32[i];1278 cumulativeMedian += robustHistogramVector->data.F32[i];1279 sumNfit += (float)robustHistogram->nums->data.S32[i];1280 }1281 }1282 1283 1263 // Calculate the mean of the smoothed robust histogram in the range 1284 1264 // mode-dL to mode+dL. We use the midpoint of each bin as the mean for 1285 1265 // that bin (this is a non-exact approximation). 1266 sumNfit = 0.0; 1286 1267 myMean = 0.0; 1287 for (i = m axBinNum - dL; i <= maxBinNum + dL; i++) {1268 for (i = modeBinNum - dL; i <= modeBinNum + dL; i++) { 1288 1269 if ((0 <= i) && (i < robustHistogramVector->n)) { 1289 myMean += (robustHistogramVector->data.F32[i]) * 0.5 * 1290 (robustHistogram->bounds->data.F32[i + 1] + robustHistogram->bounds->data.F32[i]); 1270 myMean += (robustHistogramVector->data.F32[i]) * PS_BIN_MIDPOINT(robustHistogram, i); 1291 1271 countFloat += robustHistogramVector->data.F32[i]; 1292 1272 } 1273 1274 sumNfit += (float)robustHistogram->nums->data.U32[i]; 1293 1275 } 1294 1276 myMean /= countFloat; … … 1297 1279 // mode-dL to mode+dL. We use the midpoint of each bin as the mean for 1298 1280 // that bin. 1299 for (i = m axBinNum - dL; i <= maxBinNum + dL; i++) {1281 for (i = modeBinNum - dL; i <= modeBinNum + dL; i++) { 1300 1282 if ((0 <= i) && (i < robustHistogramVector->n)) { 1301 diff = (0.5 * (robustHistogram->bounds->data.F32[i + 1] + 1302 robustHistogram->bounds->data.F32[i])) - myMean; 1283 diff = PS_BIN_MIDPOINT(robustHistogram, i) - myMean; 1303 1284 sumSquares += diff * diff * robustHistogramVector->data.F32[i]; 1304 1285 sumDiffs += diff * robustHistogramVector->data.F32[i]; … … 1315 1296 1316 1297 if (stats->options & PS_STAT_ROBUST_MODE) { 1317 stats->robustMode = 0.5 * 1318 (robustHistogram->bounds->data.F32[maxBinNum] + robustHistogram->bounds->data.F32[maxBinNum + 1]); 1298 stats->robustMode = PS_BIN_MIDPOINT(robustHistogram, modeBinNum); 1319 1299 } 1320 1300 … … 1322 1302 stats->robustStdev = myStdev; 1323 1303 } 1324 // To determine the median (and later, the lower/upper quartile), we fit 1325 // a quadratic to the three bins surrounding the bin containing the median. 1326 // The quadratic y=f(x) with x being the midpoint of each bin, and y being 1327 // the cumulative number of data points in all bins up to, and including, 1328 // this bin. We then solve the quadratic for 1329 1330 // XXX: Create a "p_psQuadraticFitAndSolveForX() function. 1331 1304 1305 // To determine the median, we fit a quadratic y=f(x) to the three bins 1306 // surrounding the bin containing the median (x is the midpoint of each 1307 // bin and y is the value of each bin). Then we figure out what value 1308 // of x corresponds to f(x) being the median (half of all points). 1332 1309 if (stats->options & PS_STAT_ROBUST_MEDIAN) { 1333 if ((maxBinNum > 0) && (maxBinNum < (robustHistogram->nums->n - 1))) { 1334 x->data.F64[0] = (double)0.5 * 1335 (robustHistogram->bounds->data.F32[maxBinNum - 1] + 1336 robustHistogram->bounds->data.F32[maxBinNum]); 1337 x->data.F64[1] = (double)0.5 * 1338 (robustHistogram->bounds->data.F32[maxBinNum] + 1339 robustHistogram->bounds->data.F32[maxBinNum + 1]); 1340 x->data.F64[2] = (double)0.5 * 1341 (robustHistogram->bounds->data.F32[maxBinNum + 1] + 1342 robustHistogram->bounds->data.F32[maxBinNum + 2]); 1343 1344 y->data.F64[0] = cumulativeRobustSumsDlRange->data.F32[maxBinNum - 1]; 1345 y->data.F64[1] = cumulativeRobustSumsDlRange->data.F32[maxBinNum]; 1346 y->data.F64[2] = cumulativeRobustSumsDlRange->data.F32[maxBinNum + 1]; 1347 1348 // Ensure that cumulativeMedian/2 is actually within the range of the bins 1349 // we are using. 1350 cumulativeMedian *= 0.5; 1351 if (!((y->data.F64[0] <= cumulativeMedian) && (cumulativeMedian <= y->data.F64[2]))) { 1352 printf("((%f), %f, %f)\n", cumulativeMedian, y->data.F64[0], y->data.F64[2]); 1353 psAbort(__func__, "p_psVectorRobustStats(1): midpoint not within y-range\n"); 1354 } 1355 // XXX: yErr is not currently used by psVectorFitPolynomial1D(). We 1356 // may have to set this meaningfully later. 1357 yErr->data.F64[0] = 1.0; 1358 yErr->data.F64[1] = 1.0; 1359 yErr->data.F64[2] = 1.0; 1360 1361 // Determine the coefficients of the polynomial. 1362 myPoly = psVectorFitPolynomial1D(myPoly, x, y, yErr); 1363 // Call p_ps1DPolyMedian(), which does a binary search on the 1364 // polynomial, looking for the value x such that 1365 // f(x) = cumulativeMedian. 1366 stats->robustMedian = p_ps1DPolyMedian(myPoly, x->data.F64[0], x->data.F64[2], cumulativeMedian); 1367 } else { 1368 // If the mode is the first/last histogram bin, then simply use 1369 // the midpoint of that bin. 1370 stats->robustMedian = 0.5 * (robustHistogram->bounds->data.F32[maxBinNum + 1] + 1371 robustHistogram->bounds->data.F32[maxBinNum]); 1372 } 1373 } 1374 // The lower/upper quartile calculations are very similar to the median 1375 // calculations. We fit a quadratic to the array containing the 1376 // cumulative data points in each bin, then search for x such that 1377 // f(x) equals the lower/upper quartile exactly. 1378 // 1310 // Take a psVector. Fit a polynomial y = f(x) to the 3 data elements 1311 // surrounding medianBinNum, then find the x-value corresponding y = sumRobust/2.0. 1312 stats->robustMedian = fitQuadraticSearchForYThenReturnX(robustHistogram->bounds, 1313 cumulativeRobustSums, 1314 medianBinNum, 1315 sumRobust/2.0); 1316 } 1317 1318 // To determine the quartiles, we fit a quadratic y=f(x) to the three bins 1319 // surrounding the bin containing LQ/UQ (x is the midpoint of each 1320 // bin and y is the value of each bin). Then we figure out what value 1321 // of x corresponds to f(x) being the LQ/UQ. 1379 1322 if (stats->options & PS_STAT_ROBUST_QUARTILE) { 1380 countFloat = cumulativeRobustSumsFullRange->data.F32[robustHistogramVector->n - 1]; 1381 1382 if ((LQBinNum > 0) && (LQBinNum < (robustHistogram->nums->n - 1))) { 1383 x->data.F64[0] = (double)0.5 * 1384 (robustHistogram->bounds->data.F32[LQBinNum - 1] + 1385 robustHistogram->bounds->data.F32[LQBinNum]); 1386 x->data.F64[1] = (double)0.5 * 1387 (robustHistogram->bounds->data.F32[LQBinNum] + 1388 robustHistogram->bounds->data.F32[LQBinNum + 1]); 1389 x->data.F64[2] = (double)0.5 * 1390 (robustHistogram->bounds->data.F32[LQBinNum + 1] + 1391 robustHistogram->bounds->data.F32[LQBinNum + 2]); 1392 1393 y->data.F64[0] = cumulativeRobustSumsFullRange->data.F32[LQBinNum - 1]; 1394 y->data.F64[1] = cumulativeRobustSumsFullRange->data.F32[LQBinNum]; 1395 y->data.F64[2] = cumulativeRobustSumsFullRange->data.F32[LQBinNum + 1]; 1396 1397 if (!((y->data.F64[0] <= (countFloat / 4.0)) && ((countFloat / 4.0) <= y->data.F64[2]))) { 1398 psAbort(__func__, "p_psVectorRobustStats(2): midpoint not within y-range\n"); 1399 } 1400 1401 yErr->data.F64[0] = 1.0; 1402 yErr->data.F64[1] = 1.0; 1403 yErr->data.F64[2] = 1.0; 1404 1405 myPoly = psVectorFitPolynomial1D(myPoly, x, y, yErr); 1406 stats->robustLQ = p_ps1DPolyMedian(myPoly, x->data.F64[0], x->data.F64[2], countFloat / 4.0); 1407 1408 } else { 1409 // If the LQ is the first/last histogram bin, then simply use 1410 // the midpoint of that bin. 1411 stats->robustLQ = 0.5 * (robustHistogram->bounds->data.F32[LQBinNum + 1] + 1412 robustHistogram->bounds->data.F32[LQBinNum]); 1413 } 1414 1415 if ((UQBinNum > 0) && (UQBinNum < (robustHistogram->nums->n - 1))) { 1416 x->data.F64[0] = (double)0.5 * 1417 (robustHistogram->bounds->data.F32[UQBinNum - 1] + 1418 robustHistogram->bounds->data.F32[UQBinNum]); 1419 x->data.F64[1] = (double)0.5 * 1420 (robustHistogram->bounds->data.F32[UQBinNum] + 1421 robustHistogram->bounds->data.F32[UQBinNum + 1]); 1422 x->data.F64[2] = (double)0.5 * 1423 (robustHistogram->bounds->data.F32[UQBinNum + 1] + 1424 robustHistogram->bounds->data.F32[UQBinNum + 2]); 1425 1426 y->data.F64[0] = cumulativeRobustSumsFullRange->data.F32[UQBinNum - 1]; 1427 y->data.F64[1] = cumulativeRobustSumsFullRange->data.F32[UQBinNum]; 1428 y->data.F64[2] = cumulativeRobustSumsFullRange->data.F32[UQBinNum + 1]; 1429 1430 if (!((y->data.F64[0] <= (3.0 * countFloat / 4.0)) && 1431 ((3.0 * countFloat / 4.0) <= y->data.F64[2]))) { 1432 psAbort(__func__, "p_psVectorRobustStats(3): midpoint not within y-range\n"); 1433 } 1434 1435 yErr->data.F64[0] = 1.0; 1436 yErr->data.F64[1] = 1.0; 1437 yErr->data.F64[2] = 1.0; 1438 1439 myPoly = psVectorFitPolynomial1D(myPoly, x, y, yErr); 1440 stats->robustUQ = p_ps1DPolyMedian(myPoly, 1441 x->data.F64[0], x->data.F64[2], 3.0 * countFloat / 4.0); 1442 } else { 1443 // If the UQ is the first/last histogram bin, then simply use 1444 // the midpoint of that bin. 1445 stats->robustUQ = 0.5 * (robustHistogram->bounds->data.F32[UQBinNum + 1] + 1446 robustHistogram->bounds->data.F32[UQBinNum]); 1447 } 1448 } 1323 countFloat = cumulativeRobustSums->data.F32[robustHistogramVector->n - 1]; 1324 1325 stats->robustLQ = fitQuadraticSearchForYThenReturnX(robustHistogram->bounds, 1326 cumulativeRobustSums, 1327 LQBinNum, 1328 countFloat/4.0); 1329 stats->robustUQ = fitQuadraticSearchForYThenReturnX(robustHistogram->bounds, 1330 cumulativeRobustSums, 1331 UQBinNum, 1332 3.0 * countFloat/4.0); 1333 } 1334 // XXX: I think sumNfit == sumN50 here. 1449 1335 stats->robustNfit = sumNfit; 1450 1336 stats->robustN50 = sumN50; 1451 1337 1452 psFree(x);1453 psFree(y);1454 psFree(yErr);1455 1338 psFree(tmpStats); 1456 1339 psFree(robustHistogram); 1457 psFree(myPoly); 1458 psFree(cumulativeRobustSumsFullRange); 1459 psFree(cumulativeRobustSumsDlRange); 1340 psFree(robustHistogramVector); 1341 psFree(cumulativeRobustSums); 1460 1342 } 1461 1343 … … 1468 1350 // I am commenting this code out, and replacing it with code which 1469 1351 // calculates the mean directly on the robustHistogram. 1470 //1471 // XXX: Replace this with the LaGrange interpolation stuff.1472 1352 1473 1353 domain = psImageAlloc(1, robustHistogramVector->n, PS_TYPE_F32); … … 1479 1359 max_pos = -1; 1480 1360 for (i=0;i<robustHistogramVector->n;i++) { 1481 domain->data.F32[i][0] = 0.5 * (robustHistogram->bounds->data.F32[i+1] + 1482 robustHistogram->bounds->data.F32[i]); 1361 domain->data.F32[i][0] = PS_BIN_MIDPOINT(robustHistogram, i);bounds->data.F32[modeBinNum + 1]); 1483 1362 data->data.F32[i] = (float) robustHistogramVector->data.F32[i]; 1484 1363 errors->data.F32[i] = 1.0; … … 1695 1574 psScalar tmpScalar; 1696 1575 tmpScalar.type.type = PS_TYPE_F32; 1576 psVector* inF32; 1577 int mustFreeTmp = 1; 1697 1578 1698 1579 // NOTE: Verify that this is the correct action. … … 1706 1587 1707 1588 if (out->nums->type.type != PS_TYPE_U32) { 1708 psAbort(__func__, "Only data type PS_TYPE_U32 for out put.nums member.");1589 psAbort(__func__, "Only data type PS_TYPE_U32 for out->nums member."); 1709 1590 } 1710 1591 // NOTE: Verify that this is the correct action. … … 1713 1594 } 1714 1595 1715 if (in->type.type != PS_TYPE_F32) {1716 psAbort(__func__, "Only data type PS_TYPE_F32 is currently supported (0x%x).", in->type.type);1717 }1718 1719 1596 if (mask != NULL) { 1720 1597 if (in->n != mask->n) { 1721 ps Abort(__func__, "Vector data and vector mask are of different sizes.");1598 psError(__func__, "Vector data and vector mask are of different sizes."); 1722 1599 } 1723 1600 if (mask->type.type != PS_TYPE_U8) { 1724 psAbort(__func__, "Vector mask must be type PS_TYPE_U8"); 1725 } 1601 psError(__func__, "Vector mask must be type PS_TYPE_U8"); 1602 } 1603 } 1604 1605 inF32 = p_psConvertToF32((psVector *) in); 1606 if (inF32 == NULL) { 1607 inF32 = (psVector *) in; 1608 mustFreeTmp = 0; 1726 1609 } 1727 1610 … … 1730 1613 1731 1614 numBins = out->nums->n; 1732 for (i = 0; i < in ->n; i++) {1615 for (i = 0; i < inF32->n; i++) { 1733 1616 // Check if this pixel is masked, and if so, skip it. 1734 1617 if ((mask == NULL) || ((mask != NULL) && (!(mask->data.U8[i] & maskVal)))) { 1735 1618 // Check if this pixel is below the minimum value, and if so 1736 1619 // count it, then skip it. 1737 if (in ->data.F32[i] < out->bounds->data.F32[0]) {1620 if (inF32->data.F32[i] < out->bounds->data.F32[0]) { 1738 1621 out->minNum++; 1739 1622 // Check if this pixel is above the maximum value, and if so 1740 1623 // count it, then skip it. 1741 } else if (in ->data.F32[i] > out->bounds->data.F32[numBins]) {1624 } else if (inF32->data.F32[i] > out->bounds->data.F32[numBins]) { 1742 1625 out->maxNum++; 1743 1626 } else { … … 1746 1629 if (out->uniform == true) { 1747 1630 binSize = out->bounds->data.F32[1] - out->bounds->data.F32[0]; 1748 binNum = (int)((in ->data.F32[i] - out->bounds->data.F32[0]) / binSize);1631 binNum = (int)((inF32->data.F32[i] - out->bounds->data.F32[0]) / binSize); 1749 1632 1750 1633 // NOTE: This next if-statement really shouldn't be necessary. … … 1755 1638 } 1756 1639 1757 (out->nums->data. S32[binNum])++;1640 (out->nums->data.U32[binNum])++; 1758 1641 1759 1642 // If this is a non-uniform histogram, determining the correct 1760 1643 // bin number requires a bit more work. 1761 1644 } else { 1762 tmpScalar.data.F32 = in->data.F32[i]; 1763 tmp = p_psVectorBinDisect(out->bounds, 1764 &tmpScalar); 1765 if (tmp == -1) { 1766 // XXX: Generate warning message 1645 tmpScalar.data.F32 = inF32->data.F32[i]; 1646 tmp = p_psVectorBinDisect(out->bounds, &tmpScalar); 1647 if (tmp < 0) { 1648 // XXX: Generate warning message 1767 1649 } else { 1768 (out->nums->data. S32[tmp])++;1650 (out->nums->data.U32[tmp])++; 1769 1651 } 1770 1652 } … … 1772 1654 } 1773 1655 } 1656 1657 if (mustFreeTmp == 1) { 1658 psFree(inF32); 1659 } 1774 1660 return (out); 1775 1661 } 1776 1662 1777 1663 /****************************************************************************** 1778 p_psConvertToF32(myVector, maskVector, maskVal, stats): this is the cheap 1779 way to support a variety of vector data types: we simply convert the input 1780 vector to F32 at the beginning, and write all of our functions in F32. If 1781 the vast majority of all vector stat operations are F32 (or any other single 1782 type), then this is probably the best way to go. Otherwise, when the 1783 algorithms stablize, we will then macro everything and put type support in 1784 the various stat functions. 1664 p_psConvertToF32(in): this is the cheap way to support a variety of vector 1665 data types: we simply convert the input vector to F32 at the beginning, and 1666 write all of our functions in F32. If the vast majority of all vector stat 1667 operations are F32 (or any other single type), then this is probably the 1668 best way to go. Otherwise, when the algorithms stablize, we will then macro 1669 everything and put type support in the various stat functions. 1785 1670 1786 1671 XXX: Should the default data type be F64? Since we are buying Athlons... 1787 1672 *****************************************************************************/ 1788 psVector* p_psConvertToF32(ps Stats* stats, psVector* in, psVector* mask, unsigned int maskVal)1673 psVector* p_psConvertToF32(psVector* in) 1789 1674 { 1790 1675 int i = 0; … … 1800 1685 for (i = 0; i < in->n; i++) { 1801 1686 tmp->data.F32[i] = (float)in->data.U16[i]; 1687 } 1688 } else if (in->type.type == PS_TYPE_U8) { 1689 tmp = psVectorAlloc(in->n, PS_TYPE_F32); 1690 for (i = 0; i < in->n; i++) { 1691 tmp->data.F32[i] = (float)in->data.U8[i]; 1802 1692 } 1803 1693 } else if (in->type.type == PS_TYPE_F64) { … … 1839 1729 int mustFreeTmp = 1; 1840 1730 1841 // NOTE: Verify that this is the correct action.1842 1731 if (in == NULL) { 1843 return (stats); 1844 } 1845 if (stats == NULL) { 1846 return (NULL); 1847 } 1848 1849 inF32 = p_psConvertToF32(stats, in, mask, maskVal); 1732 psError(__func__, "in is NULL\n"); 1733 return(stats); 1734 } 1735 PS_CHECK_NULL_PTR_RETURN_NULL(stats); 1736 1737 inF32 = p_psConvertToF32((psVector *) in); 1850 1738 if (inF32 == NULL) { 1851 1739 inF32 = in; 1852 1740 mustFreeTmp = 0; 1853 1741 } 1854 // XXX: Should we abort if (stats->min == stats->max)?1855 1742 if ((stats->options & PS_STAT_USE_RANGE) && (stats->min >= stats->max)) { 1856 psAbort(__func__, "psVectorStats() called with range: %f to %f\n", stats->min, stats->max); 1743 psError(__func__, "psVectorStats() called with range: %f to %f\n", stats->min, stats->max); 1744 return(stats); 1857 1745 } 1858 1746 -
trunk/psLib/src/math/psConstants.h
r2136 r2197 6 6 * @author GLG, MHPCC 7 7 * 8 * @version $Revision: 1.1 2$ $Name: not supported by cvs2svn $9 * @date $Date: 2004-10- 14 23:43:12 $8 * @version $Revision: 1.13 $ $Name: not supported by cvs2svn $ 9 * @date $Date: 2004-10-26 21:24:42 $ 10 10 * 11 11 * Copyright 2004 Maui High Performance Computing Center, University of Hawaii … … 107 107 } \ 108 108 109 /** Preprocessor macro to generate error on a NULL vector */ 110 #define PS_CHECK_NULL_VECTOR_RETURN_F0(NAME) \ 111 if (NAME == NULL || NAME->data.V == NULL) { \ 112 psError(__func__,"Unallowable operation: %s or its data is NULL.", #NAME); \ 113 return(0.0); \ 114 } \ 115 109 116 /** Preprocessor macro to generate error on a NULL poniter */ 110 117 #define PS_CHECK_NULL_PTR_RETURN_NULL(NAME) \ … … 113 120 return(NULL); \ 114 121 } 122 123 /** Preprocessor macro to generate error on a NULL poniter */ 124 #define PS_CHECK_NULL_PTR_RETURN_F0(NAME) \ 125 if (NAME == NULL) { \ 126 psError(__func__,"Unallowable operation: %s is NULL.", #NAME); \ 127 return(0.0); \ 128 } 129 115 130 /** Preprocessor macro to generate error on a NULL poniter */ 116 131 #define PS_CHECK_NULL_PTR_RETURN_ZERO(NAME) \ … … 127 142 } \ 128 143 144 /** Preprocessor macro to generate error for zero length vector */ 145 #define PS_CHECK_EMPTY_VECTOR_RETURN_F0(NAME) \ 146 if (NAME->n < 1) { \ 147 psError(__func__,"Unallowable operation: %s has zero n value.", #NAME); \ 148 return(0.0); \ 149 } \ 150 129 151 /** Preprocessor macro to generate error on differing size vectors */ 130 152 #define PS_CHECK_VECTOR_SIZE_EQUAL_RETURN_NULL(VEC1, VEC2) \ … … 132 154 psError(__func__,"Vector %s has size %d, Vector %s has size %d.", #VEC1, VEC1->n, #VEC2, VEC2->n); \ 133 155 return(NULL); \ 156 } 157 158 /** Preprocessor macro to generate error on differing size vectors */ 159 #define PS_CHECK_VECTOR_SIZE_EQUAL_RETURN_F0(VEC1, VEC2) \ 160 if (VEC1->n != VEC2->n) { \ 161 psError(__func__,"Vector %s has size %d, Vector %s has size %d.", #VEC1, VEC1->n, #VEC2, VEC2->n); \ 162 return(0.0); \ 134 163 } 135 164 … … 199 228 200 229 #define PS_MAX(A, B) \ 201 (( A > B) ? A : B) \230 (((A) > (B)) ? (A) : (B)) \ 202 231 203 232 #define PS_MIN(A, B) \ 204 (( A < B) ? A : B) \205 233 (((A) < (B)) ? (A) : (B)) \ 234 -
trunk/psLib/src/math/psMinimize.c
r2106 r2197 9 9 * @author GLF, MHPCC 10 10 * 11 * @version $Revision: 1.5 8$ $Name: not supported by cvs2svn $12 * @date $Date: 2004-10- 14 01:44:48$11 * @version $Revision: 1.59 $ $Name: not supported by cvs2svn $ 12 * @date $Date: 2004-10-26 21:24:42 $ 13 13 * 14 14 * Copyright 2004 Maui High Performance Computing Center, University of Hawaii … … 636 636 psFree(currValueVec); 637 637 psFree(newValueVec); 638 639 if ((min->iter < min->maxIter) || 640 (min->lastDelta <= min->tol)) { 641 return(true); 642 } 643 644 psTrace(".psLib.dataManip.psMinimizeLMChi2", 4, 645 "---- psMinimizeLMChi2() end (false) ----\n"); 646 return(false); 647 } 648 649 /****************************************************************************** 650 psMyMinimizeLMChi2(): This routine will take an procedure which calculates 651 an arbitrary function and it's derivative and minimize the chi-squared match 652 between that function at the specified coords and the specified value at 653 those coords. 654 655 XXX: Do this: 656 After checking that all entries in the paramMask are 1 or 0, when 657 forming the A matrix from alpha, try this: 658 659 A[i][i] = (1 + lambda*paramask[i]) * alpha[i][i]; 660 661 XXX: This is very different from what is specified in the SDR. Must 662 coordinate with IfA on new SDR. 663 664 XXX: Do vector/image recycles. 665 666 XXX: probably yErr will be part of the SDR. 667 668 XXX: This must work for both F32 and F64. F32 is currently implemented. 669 Note: since the LUD routines are only implemented in F64, then we 670 will have to convert all F32 input vectors to F64 regardless. So, 671 the F64 port might be. 672 *****************************************************************************/ 673 bool psMyMinimizeLMChi2(psMinimization *min, 674 psImage *covar, 675 psVector *params, 676 const psVector *paramMask, 677 const psArray *x, 678 const psVector *y, 679 const psVector *yErr, 680 psMyMinimizeLMChi2Func func) 681 { 682 PS_CHECK_NULL_PTR_RETURN_NULL(min); 683 PS_CHECK_NULL_VECTOR_RETURN_NULL(params); 684 PS_CHECK_EMPTY_VECTOR_RETURN_NULL(params); 685 PS_CHECK_NULL_PTR_RETURN_NULL(x); 686 PS_CHECK_NULL_VECTOR_RETURN_NULL(y); 687 PS_CHECK_EMPTY_VECTOR_RETURN_NULL(y); 688 PS_CHECK_VECTOR_SIZE_EQUAL_RETURN_NULL(x, y); 689 if (paramMask != NULL) { 690 PS_CHECK_VECTOR_SIZE_EQUAL_RETURN_NULL(params, paramMask); 691 } 692 if (yErr != NULL) { 693 PS_CHECK_VECTOR_SIZE_EQUAL_RETURN_NULL(y, yErr); 694 } 695 696 psTrace(".psLib.dataManip.psMinimizeLMChi2", 4, 697 "---- psMinimizeLMChi2() begin ----\n"); 698 int numData = y->n; 699 int numParams = params->n; 700 int i; 701 int j; 702 int k; 703 int l; 704 int n; 705 int p; 706 psVector *beta = psVectorAlloc(numParams, PS_TYPE_F64); 707 psVector *perm = psVectorAlloc(numParams, PS_TYPE_F64); 708 709 psVector *paramDeltasF64 = psVectorAlloc(numParams, PS_TYPE_F64); 710 psVector *origParams = psVectorAlloc(numParams, PS_TYPE_F32); 711 psVector *newParams = psVectorAlloc(numParams, PS_TYPE_F32); 712 713 psImage *alpha = psImageAlloc(numParams, numParams, PS_TYPE_F32); 714 psImage *A = psImageAlloc(numParams, numParams, PS_TYPE_F64); 715 psImage *aOut = psImageAlloc(numParams, numParams, PS_TYPE_F64); 716 717 // psVector **deriv = (psVector **) psAlloc(numData * sizeof(psVector *)); 718 // for (i=0;i<numData;i++) { 719 // deriv[i] = psVectorAlloc(numParams, PS_TYPE_F32); 720 // } 721 psImage *deriv = psImageAlloc(numParams, numData, PS_TYPE_F32); 722 723 psVector *currValueVec; 724 psVector *newValueVec; 725 726 float currChi2 = 0.0; 727 float newChi2 = 0.0; 728 float lamda = 0.00005; 729 730 psTrace(".psLib.dataManip.psMinimizeLMChi2", 6, 731 "min->maxIter is %d\n", min->maxIter); 732 psTrace(".psLib.dataManip.psMinimizeLMChi2", 6, 733 "min->tol is %f\n", min->tol); 734 735 for (p=0;p<numParams;p++) { 736 origParams->data.F32[p] = params->data.F32[p]; 737 } 738 739 min->lastDelta = HUGE; 740 min->iter = 0; 741 742 while ((min->lastDelta > min->tol) && (min->iter < min->maxIter)) { 743 psTrace(".psLib.dataManip.psMinimizeLMChi2", 4, 744 "------------------------------------------------------\n"); 745 psTrace(".psLib.dataManip.psMinimizeLMChi2", 4, 746 "Iteration %d. Delta is %f\n", min->iter, min->lastDelta); 747 748 // 749 // Calculate the current values and chi-squared of the function. 750 // 751 currChi2 = 0.0; 752 currValueVec = func(deriv, params, x); 753 for (n=0;n<numData;n++) { 754 currChi2+= (currValueVec->data.F32[n] * currValueVec->data.F32[n]); 755 } 756 757 for (p=0;p<numParams;p++) { 758 psTrace(".psLib.dataManip.psMinimizeLMChi2", 6, 759 "params->data.F32[%d] is %f.\n", p, params->data.F32[p]); 760 } 761 psTrace(".psLib.dataManip.psMinimizeLMChi2", 6, 762 "Current chi-squared is (%f)\n", currChi2); 763 764 // 765 // Mask elements of the derivative for each data point. 766 // 767 for (p=0;p<numParams;p++) { 768 if ((paramMask != NULL) && (paramMask->data.U8[p] != 0)) { 769 for (n=0;n<numData;n++) { 770 deriv->data.F32[n][p] = 0.0; 771 } 772 } 773 } 774 775 // 776 // Calculate the BETA vector. 777 // 778 for (p=0;p<numParams;p++) { 779 beta->data.F64[p] = 0.0; 780 for (n=0;n<numData;n++) { 781 (beta->data.F64[p])+= 782 (y->data.F32[n] - currValueVec->data.F32[n]) * 783 deriv->data.F32[n][p]; 784 } 785 // XXX: multiple by -1 here? 786 (beta->data.F64[p])*= -1.0; 787 psTrace(".psLib.dataManip.psMinimizeLMChi2", 6, 788 "beta->data.F64[%d] is %f.\n", p, beta->data.F64[p]); 789 } 790 psFree(currValueVec); 791 792 // 793 // Calculate the ALPHA matrix. 794 // 795 for (k=0;k<numParams;k++) { 796 for (l=0;l<numParams;l++) { 797 alpha->data.F32[k][l] = 0.0; 798 for (n=0;n<numData;n++) { 799 alpha->data.F32[k][l]+= deriv->data.F32[n][k] * 800 deriv->data.F32[n][l]; 801 } 802 } 803 } 804 805 // 806 // Calculate the matrix A. 807 // 808 for (j=0;j<numParams;j++) { 809 for (k=0;k<numParams;k++) { 810 if (j == k) { 811 A->data.F64[j][k] = 812 (double) ((1.0 + lamda) * alpha->data.F32[j][k]); 813 } else { 814 A->data.F64[j][k] = (double) alpha->data.F32[j][k]; 815 } 816 } 817 } 818 for (j=0;j<numParams;j++) { 819 psTrace(".psLib.dataManip.psMinimizeLMChi2", 6, "Matrix A[][]:\n"); 820 for (k=0;k<numParams;k++) { 821 psTrace(".psLib.dataManip.psMinimizeLMChi2", 6, "%f ", A->data.F64[j][k]); 822 } 823 psTrace(".psLib.dataManip.psMinimizeLMChi2", 6, "Matrix A[][]:\n"); 824 } 825 826 // 827 // Solve A * alpha = Beta 828 // 829 aOut = psMatrixLUD(aOut, perm, A); 830 paramDeltasF64 = psMatrixLUSolve(paramDeltasF64, aOut, beta, perm); 831 832 // 833 // Mask any masked parameters. 834 // 835 for (i=0;i<numParams;i++) { 836 psTrace(".psLib.dataManip.psMinimizeLMChi2", 6, 837 "paramDeltasF64->data.F64[%d] is %f.\n", i, paramDeltasF64->data.F64[i]); 838 if ((paramMask != NULL) && (paramMask->data.U8[i] != 0)) { 839 newParams->data.F32[i] = origParams->data.F32[i]; 840 } else { 841 newParams->data.F32[i] = params->data.F32[i] - 842 (float) paramDeltasF64->data.F64[i]; 843 } 844 } 845 846 psTrace(".psLib.dataManip.psMinimizeLMChi2", 6, 847 "Calling func() with new parameters:\n"); 848 for (i=0;i<numParams;i++) { 849 psTrace(".psLib.dataManip.psMinimizeLMChi2", 6, 850 "newParams->data.F32[%d] is %f.\n", i, newParams->data.F32[i]); 851 } 852 853 854 // 855 // Calculate new function values. 856 // 857 newChi2 = 0.0; 858 newValueVec = func(deriv, newParams, x); 859 for (n=0;n<numData;n++) { 860 newChi2+= (newValueVec->data.F32[n] * newValueVec->data.F32[n]); 861 } 862 psFree(newValueVec); 863 864 psTrace(".psLib.dataManip.psMinimizeLMChi2", 4, 865 "old/new chi-squareds are (%f, %f)\n", currChi2, newChi2); 866 867 // 868 // If the new chi-squared is lower, then keep it. 869 // 870 if (currChi2 > newChi2) { 871 min->lastDelta = currChi2 - newChi2; 872 min->value = newChi2; 873 874 // We already masked params. 875 for (i=0;i<numParams;i++) { 876 params->data.F32[i] = (float) newParams->data.F32[i]; 877 } 878 lamda*= 0.1; 879 } else { 880 lamda*= 10.0; 881 } 882 psTrace(".psLib.dataManip.psMinimizeLMChi2", 4, 883 "lamda is %f\n", lamda); 884 min->iter++; 885 } 886 psFree(beta); 887 psFree(perm); 888 psFree(paramDeltasF64); 889 psFree(origParams); 890 psFree(newParams); 891 psFree(alpha); 892 psFree(A); 893 psFree(aOut); 894 psFree(deriv); 638 895 639 896 if ((min->iter < min->maxIter) || -
trunk/psLib/src/math/psMinimize.h
r1992 r2197 8 8 * @author GLG, MHPCC 9 9 * 10 * @version $Revision: 1. 29$ $Name: not supported by cvs2svn $11 * @date $Date: 2004-10- 06 23:38:49$10 * @version $Revision: 1.30 $ $Name: not supported by cvs2svn $ 11 * @date $Date: 2004-10-26 21:24:43 $ 12 12 * 13 13 * Copyright 2004 Maui High Performance Computing Center, University of Hawaii … … 84 84 85 85 86 /* 87 Bug 203: 88 89 typedef float (*psMinimizeLMChi2Func)(psVector *deriv, const psVector *params, 90 const psVector *x); 91 92 This function takes the current guess for the parameters for which we are 93 trying to get the best values (params), and a single vector (x) of 94 conditions from the array of x values fed into the minimiser. 95 96 bool psMinimizeLMChi2(psMinimization *min, 97 psImage *covar, 98 psVector *params, 99 const psVector *paramMask, 100 const psArray *x, 101 const psVector *y, 102 const psVector *yErr, 103 psMinimizeLMChi2Func func); 104 105 This takes the minimization specs (min), returns the covariance matrix 106 (covar), takes the best guess of initial parameters (params), the parameter 107 mask (paramMask), and takes multiple vectors of conditions in an array (x), 108 the corresponding measured values (y) and errors (yErr) and the function to 109 fit (func). 110 111 For example, for GRB afterglows, I have flux as a function of time and 112 frequency. So I stuff into the "psArray *x" all my time and frequency values 113 (so a whole heap of vectors of size 2), I have the measured values in "y" and 114 errors in "yErr". Then each of the time-frequency pairs are passed to my model 115 function with the current parameters, and the model function returns the flux 116 for that time-frequency pair, and the derivative with respect to each of the 117 parameters. 118 119 This seems reasonable. The only thing we could change would be to have the 120 function be defined: 121 122 typedef psVector* (*psMinimizeLMChi2Func)(psImage *deriv, 123 const psVector *params, 124 const psArray *x); 125 126 So it would return the model value for each of the measurements at once, and 127 return for each the derivatives (so that it returns a matrix). 128 129 What do you think? 130 131 132 133 I'm not sure I understand how LM chi-squared minimization will work with the 134 following function that you define: 135 136 typedef psVector* (*psMinimizeLMChi2Func)(psImage *deriv, 137 const psVector *params, 138 const psArray *x); 139 140 The chi-squared minimization algorithm, as defined in NR, requires that 141 function to be minimized be evaluated at each data point, and that all 142 derivatives, with respect to each parameter, be calculated at each data 143 point. In the above, can I assume that 144 145 x is an array of psVectors, with each vector corresponding to a single 146 data point. 147 148 The returned value has the same length as x. It contains the value of 149 the function at each data point in x. 150 151 deriv: an n-by-p matrix where "n" is the number of data points, and "p" 152 is the number of parameters. The [i][j] element of this matrix 153 holds the derivative of the function at the i-th data point with 154 respect to the j-th parameter. 155 156 157 158 */ 159 160 86 161 // XXX: What if any of these arguments are NULL? 162 163 87 164 typedef 88 165 float (*psMinimizeLMChi2Func)(psVector *deriv, … … 98 175 psMinimizeLMChi2Func func); 99 176 177 178 typedef 179 psVector* (*psMyMinimizeLMChi2Func)(psImage *deriv, 180 const psVector *params, 181 const psArray *x); 182 183 bool psMyMinimizeLMChi2(psMinimization *min, 184 psImage *covar, 185 psVector *params, 186 const psVector *paramMask, 187 const psArray *x, 188 const psVector *y, 189 const psVector *yErr, 190 psMyMinimizeLMChi2Func func); 191 100 192 typedef 101 193 float (*psMinimizePowellFunc)(const psVector *params, -
trunk/psLib/src/math/psPolynomial.c
r2106 r2197 7 7 * polynomials. It also contains a Gaussian functions. 8 8 * 9 * @version $Revision: 1.5 2$ $Name: not supported by cvs2svn $10 * @date $Date: 2004-10- 14 01:44:48$9 * @version $Revision: 1.53 $ $Name: not supported by cvs2svn $ 10 * @date $Date: 2004-10-26 21:24:42 $ 11 11 * 12 12 * Copyright 2004 Maui High Performance Computing Center, University of Hawaii -
trunk/psLib/src/math/psSpline.c
r2106 r2197 7 7 * polynomials. It also contains a Gaussian functions. 8 8 * 9 * @version $Revision: 1.5 2$ $Name: not supported by cvs2svn $10 * @date $Date: 2004-10- 14 01:44:48$9 * @version $Revision: 1.53 $ $Name: not supported by cvs2svn $ 10 * @date $Date: 2004-10-26 21:24:42 $ 11 11 * 12 12 * Copyright 2004 Maui High Performance Computing Center, University of Hawaii -
trunk/psLib/src/math/psStats.c
r2074 r2197 9 9 * @author GLG, MHPCC 10 10 * 11 * @version $Revision: 1.6 7$ $Name: not supported by cvs2svn $12 * @date $Date: 2004-10- 13 02:40:13 $11 * @version $Revision: 1.68 $ $Name: not supported by cvs2svn $ 12 * @date $Date: 2004-10-26 21:24:43 $ 13 13 * 14 14 * Copyright 2004 Maui High Performance Computing Center, University of Hawaii … … 40 40 /*****************************************************************************/ 41 41 // will use robust statistical methods. 42 #define GAUSS_WIDTH 20// The width of the Gaussian or boxcar smoothing.42 #define GAUSS_WIDTH 5 // The width of the Gaussian or boxcar smoothing. 43 43 #define CLIPPED_NUM_ITER_LB 1 44 44 #define CLIPPED_NUM_ITER_UB 10 … … 57 57 /* TYPE DEFINITIONS */ 58 58 /*****************************************************************************/ 59 psVector* p_psConvertToF32(psVector* in); 59 60 60 61 /*****************************************************************************/ … … 423 424 float rangeMax = 0.0; // Exclude date above this 424 425 425 // Determine if the number of data points exceed a threshold which will426 // cause to generate robust stats, as opposed to exact stats.427 // XXX: This code is no longer used. We now calculate the median exactly428 // regardless of the vector size.429 /*430 * // Calculate the robust quartiles. stats2 = psStatsAlloc(PS_STAT_ROBUST_MEDIAN);431 * p_psVectorRobustStats(myVector, maskVector, maskVal, stats2);432 *433 * // Store the robust quartiles into the sample quartile members. stats->sampleMedian =434 * stats2->robustMedian;435 *436 * // Free temporary data buffers. psFree(stats2);437 *438 * // Set the PS_STAT_ROBUST_FOR_SAMPLE bit in the stats structure. stats->options = stats->options |439 * PS_STAT_ROBUST_FOR_SAMPLE;440 *441 * return; } */442 443 426 // Determine how many data points fit inside this min/max range 444 427 // and are not masked, IF the maskVector is not NULL> … … 507 490 508 491 /****************************************************************************** 509 This routine smoothes the data in the input robustHistogram with a 510 Gaussian of width sigma. 511 512 XXX: Must consult with IfA on the proper values for the Gaussian 513 smoothing. Currently, the Gaussian coefficients are such that only 514 the center coefficient is non-zero. This is because "e" is being 515 raised to a very large negative number for all points except the 516 center point. 517 518 XXX: use a static variable for gaussianCoefs[] and compute them once. 519 *****************************************************************************/ 520 psVector* p_psVectorsmoothHistGaussian(psHistogram* robustHistogram, 492 p_psVectorSmoothHistGaussian(): This routine smoothes the data in the input 493 robustHistogram with a Gaussian of width sigma. 494 *****************************************************************************/ 495 #define GAUSS_WIDTH_OTHER 5.0 496 psVector* p_psVectorSmoothHistGaussian(psHistogram* robustHistogram, 521 497 float sigma) 522 498 { 523 499 int i = 0; // Loop index variable 524 500 int j = 0; // Loop index variable 525 float denom = 0.0; // Temporary variable 526 float expo = 0.0; // Temporary variable 527 float gaussianCoefs[1 + (2 * GAUSS_WIDTH)]; // The Gaussian Coefficients 528 psVector* smooth = psVectorAlloc(robustHistogram->nums->n, PS_TYPE_F32); 529 530 for (i = 0; i < (1 + (2 * GAUSS_WIDTH)); i++) { 531 if (fabs(sigma) >= FLT_EPSILON) { 532 // If sigma does not equal zero, then we use Gaussian smoothing. 533 #ifdef DARWIN 534 denom = (float)sqrt(2.0 * M_PI * sigma * sigma); 535 #else 536 537 denom = sqrtf(2.0 * M_PI * sigma * sigma); 538 #endif 539 540 expo = -(float)((i - GAUSS_WIDTH) * (i - GAUSS_WIDTH)); 541 expo /= (2.0 * sigma * sigma); 542 gaussianCoefs[i] = exp(expo / denom); 543 544 //printf("p_psVectorsmoothHistGaussian(): gaussianCoefs[%d] is %f\n", i, gaussianCoefs[i]); 545 // NOTE: Gaussian smoothing just isn't working with low sigma 546 // values. The problem is that the Gaussian coefficients are 547 // all zero, except for the middle coefficient, which is exactly 548 // one. Therefore, I'm using boxcar smoothing. 549 gaussianCoefs[i] = 1.0 / (1.0 + (2.0 * (float)GAUSS_WIDTH)); 550 // printf("gaussianCoefs[%d] is %f\n", i, gaussianCoefs[i]); 551 } else { 552 /* If sigma equals zero (all pixels have the same value) the above code will divide by zero. 553 * Therefore, we don't need to smooth the data. */ 554 for (i = 0; i < robustHistogram->nums->n; i++) { 555 smooth->data.F32[i] = (float)robustHistogram->nums->data.S32[i]; 556 } 557 return (smooth); 558 } 559 } 560 561 // Perform the actual smoothing. 562 for (i = 0; i < robustHistogram->nums->n; i++) { 501 float iMid; 502 float jMid; 503 int numBins = robustHistogram->nums->n; 504 int numBounds = robustHistogram->bounds->n; 505 psVector* smooth = psVectorAlloc(numBins, PS_TYPE_F32); 506 int jMin = 0; 507 int jMax = 0; 508 float firstBound = robustHistogram->bounds->data.F32[0]; 509 float lastBound = robustHistogram->bounds->data.F32[numBounds-1]; 510 psScalar x; 511 512 x.type.type = PS_TYPE_F32; 513 for (i = 0; i < numBins; i++) { 514 iMid = (robustHistogram->bounds->data.F32[i] + 515 robustHistogram->bounds->data.F32[i+1]) / 2.0; 516 517 // YYY: The p_psVectorBinDisect() routine does much of the work of 518 // the following conditionals, however, it also reports a warning 519 // message. I don't want the warning message so I reproduce the 520 // conditionals here. Maybe p_psVectorBinDisect() should not produce 521 // warnings? 522 523 x.data.F32 = iMid - (GAUSS_WIDTH * sigma); 524 if ((x.data.F32 >= firstBound) && (x.data.F32 <= lastBound)) { 525 jMin = p_psVectorBinDisect(robustHistogram->bounds, &x); 526 } else if (x.data.F32 <= firstBound) { 527 jMin = 0; 528 } else if (x.data.F32 >= lastBound) { 529 jMin = robustHistogram->bounds->n - 1; 530 531 } 532 533 x.data.F32 = iMid + (GAUSS_WIDTH * sigma); 534 if ((x.data.F32 >= firstBound) && (x.data.F32 <= lastBound)) { 535 jMax = p_psVectorBinDisect(robustHistogram->bounds, &x); 536 } else if (x.data.F32 <= firstBound) { 537 jMax = 0; 538 } else if (x.data.F32 >= lastBound) { 539 jMax = robustHistogram->bounds->n - 1; 540 541 } 542 563 543 smooth->data.F32[i] = 0.0; 564 for (j = -GAUSS_WIDTH; j <= +GAUSS_WIDTH; j++) { 565 if (((j + i) >= 0) && ((j + i) < smooth->n)) { 566 smooth->data.F32[i] += (gaussianCoefs[j + GAUSS_WIDTH] * 567 (float)robustHistogram->nums->data.S32[j + i]); 568 } 569 } 570 } 571 return (smooth); 544 for (j = jMin ; j <= jMax ; j++) { 545 jMid = (robustHistogram->bounds->data.F32[j] + 546 robustHistogram->bounds->data.F32[j+1]) / 2.0; 547 smooth->data.F32[i] += 548 ((float) robustHistogram->nums->data.U32[j]) * 549 psGaussian(jMid, iMid, sigma, true); 550 } 551 } 552 553 return(smooth); 572 554 } 573 555 … … 913 895 specified data point. 914 896 *****************************************************************************/ 915 float p_psGaussian(const psVector* restrict myData, const psVector* restrict myParams) 897 float p_psGaussian(const psVector* restrict myData, 898 const psVector* restrict myParams) 916 899 { 917 900 float x = myData->data.F32[0]; … … 930 913 calculates the specified partial derivative of the above Gaussian function. 931 914 *****************************************************************************/ 932 float p_psGaussianDeriv(const psVector* restrict myData, const psVector* restrict myParams, int whichParam) 915 float p_psGaussianDeriv(const psVector* restrict myData, 916 const psVector* restrict myParams, int whichParam) 933 917 { 934 918 float x = myData->data.F32[0]; … … 1036 1020 1037 1021 /****************************************************************************** 1038 p_psFitQuadratic(robustHistogram. cumulativeSums, binNum, fitFloat): given 1039 the specified histogram, with the specified pre-calculated cumulativeSums, 1040 this routine fits a quadratic f(x) to the 3 bins surrounding bin "binNum", 1041 and then finds the point x such that f(x) == fitFloat. 1022 fitQuadraticSearchForYThenReturnX(*xVec, *yVec, binNum, yVal): This routine 1023 takes psVectors of x/y pairs as input, and fits a quadratic to the 3 points 1024 surrounding element binNum in the vectors (the midpoint between element i 1025 and i+1 is used for x[i]). It then determines for what value x does that 1026 quadratic f(x) = yVal (the input parameter). 1042 1027 1043 XXX: This function is currently not being used. 1044 *****************************************************************************/ 1045 float p_psFitQuadratic(psHistogram* histogram, 1046 psVector* cumulativeSums, 1047 int binNum, 1048 float fitFloat) 1049 { 1028 // XXX: Use static variables. 1029 *****************************************************************************/ 1030 float fitQuadraticSearchForYThenReturnX(psVector *xVec, 1031 psVector *yVec, 1032 int binNum, 1033 float yVal) 1034 { 1035 // static psVector* x = NULL; 1036 // static psVector* y = NULL; 1037 // static psVector* yErr = NULL; 1050 1038 psVector* x = psVectorAlloc(3, PS_TYPE_F64); 1051 1039 psVector* y = psVectorAlloc(3, PS_TYPE_F64); 1052 1040 psVector* yErr = psVectorAlloc(3, PS_TYPE_F64); 1041 1042 /* 1043 if (x == NULL) { 1044 x = psVectorAlloc(3, PS_TYPE_F64); 1045 p_psMemSetPersistent(x, true); 1046 } 1047 if (y == NULL) { 1048 y = psVectorAlloc(3, PS_TYPE_F64); 1049 p_psMemSetPersistent(y, true); 1050 } 1051 if (yErr == NULL) { 1052 yErr = psVectorAlloc(3, PS_TYPE_F64); 1053 p_psMemSetPersistent(yErr, true); 1054 } 1055 */ 1053 1056 psPolynomial1D* myPoly = psPolynomial1DAlloc(2, PS_POLYNOMIAL_ORD); 1054 1055 if ((binNum > 0) && (binNum < (histogram->nums->n + 1))) { 1056 x->data.F64[0] = (double)0.5 * 1057 (histogram->bounds->data.F32[binNum - 1] + histogram->bounds->data.F32[binNum]); 1058 x->data.F64[1] = (double)0.5 * 1059 (histogram->bounds->data.F32[binNum] + histogram->bounds->data.F32[binNum + 1]); 1060 x->data.F64[2] = (double)0.5 * 1061 (histogram->bounds->data.F32[binNum + 1] + histogram->bounds->data.F32[binNum + 2]); 1062 1063 y->data.F64[0] = cumulativeSums->data.F32[binNum - 1]; 1064 y->data.F64[1] = cumulativeSums->data.F32[binNum]; 1065 y->data.F64[2] = cumulativeSums->data.F32[binNum + 1]; 1066 1067 if (!((y->data.F64[0] <= fitFloat) && (fitFloat <= y->data.F64[2]))) { 1068 psAbort(__func__, "p_psVectorRobustStats(0): midpoint not within y-range\n"); 1069 } 1070 1057 float tmpFloat; 1058 1059 if ((binNum > 0) && (binNum < (yVec->n - 2))) { 1060 x->data.F64[0] = (double) (0.5 * (xVec->data.F32[binNum - 1] + xVec->data.F32[binNum])); 1061 x->data.F64[1] = (double) (0.5 * (xVec->data.F32[binNum] + xVec->data.F32[binNum+1])); 1062 x->data.F64[2] = (double) (0.5 * (xVec->data.F32[binNum+1] + xVec->data.F32[binNum+2])); 1063 y->data.F64[0] = yVec->data.F32[binNum - 1]; 1064 y->data.F64[1] = yVec->data.F32[binNum]; 1065 y->data.F64[2] = yVec->data.F32[binNum + 1]; 1066 1067 // Ensure that yVal is within the range of the bins we are using. 1068 if (!((y->data.F64[0] <= yVal) && (yVal <= y->data.F64[2]))) { 1069 printf("((%f), %f, %f)\n", yVal, y->data.F64[0], y->data.F64[2]); 1070 psError(__func__, "yVal not within y-range\n"); 1071 } 1071 1072 yErr->data.F64[0] = 1.0; 1072 1073 yErr->data.F64[1] = 1.0; 1073 1074 yErr->data.F64[2] = 1.0; 1074 1075 1076 // Determine the coefficients of the polynomial. 1075 1077 myPoly = psVectorFitPolynomial1D(myPoly, x, y, yErr); 1076 return (p_ps1DPolyMedian(myPoly, x->data.F64[0], x->data.F64[2], fitFloat)); 1078 // Call p_ps1DPolyMedian(), which does a binary search on the 1079 // polynomial, looking for the value x such that f(x) = yVal 1080 tmpFloat = p_ps1DPolyMedian(myPoly, x->data.F64[0], x->data.F64[2], yVal); 1077 1081 } else { 1078 return (0.5 * (histogram->bounds->data.F32[binNum + 1] + histogram->bounds->data.F32[binNum])); 1082 if (binNum == 0) { 1083 tmpFloat = 0.5 * (xVec->data.F32[binNum] + 1084 xVec->data.F32[binNum + 1]); 1085 } else if (binNum == (xVec->n - 1)) { 1086 // XXX: Is this right? 1087 tmpFloat = xVec->data.F32[binNum]; 1088 } else if (binNum == (xVec->n - 2)) { 1089 // XXX: Is this right? 1090 tmpFloat = 0.5 * (xVec->data.F32[binNum] + 1091 xVec->data.F32[binNum + 1]); 1092 } 1079 1093 } 1080 1094 … … 1083 1097 psFree(yErr); 1084 1098 psFree(myPoly); 1085 return (0.0); 1086 } 1099 return(tmpFloat); 1100 } 1101 1102 #define PS_BIN_MIDPOINT(HISTOGRAM, BIN_NUM) \ 1103 (0.5 * (HISTOGRAM->bounds->data.F32[(BIN_NUM)] + HISTOGRAM->bounds->data.F32[(BIN_NUM)+1])) 1087 1104 1088 1105 /****************************************************************************** … … 1111 1128 *****************************************************************************/ 1112 1129 void p_psVectorRobustStats(const psVector* restrict myVector, 1113 const psVector* restrict maskVector, unsigned int maskVal, psStats* stats) 1130 const psVector* restrict maskVector, 1131 unsigned int maskVal, 1132 psStats* stats) 1114 1133 { 1115 1134 psHistogram* robustHistogram = NULL; … … 1118 1137 int LQBinNum = -1; // Bin num for lower quartile 1119 1138 int UQBinNum = -1; // Bin num for upper quartile 1139 int medianBinNum = -1; 1120 1140 int i = 0; // Loop index variable 1121 int m axBinNum = 0;1122 float m axBinCount = 0.0;1141 int modeBinNum = 0; 1142 float modeBinCount = 0.0; 1123 1143 float dL = 0.0; 1124 1144 int numBins = 0; 1125 psStats* tmpStats = psStatsAlloc(PS_STAT_CLIPPED_STDEV | PS_STAT_CLIPPED_MEAN);1126 1127 // psImage* domain;1128 // psVector* errors;1129 // psVector* data;1130 // psVector* initialGuess;1131 // psVector* theParams;1132 // float chiSq=0.0;1133 // float max = -HUGE;1134 // float max_pos;1135 1145 float myMean = 0.0; 1136 1146 float myStdev = 0.0; … … 1139 1149 float sumSquares = 0.0; 1140 1150 float sumDiffs = 0.0; 1141 psVector* x = psVectorAlloc(3, PS_TYPE_F64); 1142 psVector* y = psVectorAlloc(3, PS_TYPE_F64); 1143 psVector* yErr = psVectorAlloc(3, PS_TYPE_F64); 1144 psPolynomial1D* myPoly = psPolynomial1DAlloc(2, PS_POLYNOMIAL_ORD); 1145 psVector* cumulativeRobustSumsFullRange = NULL; 1146 psVector* cumulativeRobustSumsDlRange = NULL; 1151 psVector* cumulativeRobustSums = NULL; 1147 1152 float sumRobust = 0.0; 1148 1153 float sumN50 = 0.0; 1149 1154 float sumNfit = 0.0; 1150 float cumulativeMedian = 0.0; 1155 psScalar tmpScalar; 1156 tmpScalar.type.type = PS_TYPE_F32; 1157 psStats* tmpStats = psStatsAlloc(PS_STAT_CLIPPED_STDEV | PS_STAT_CLIPPED_MEAN); 1151 1158 1152 1159 // Compute the initial bin size of the robust histogram. This is done … … 1188 1195 p_psVectorMax(myVector, maskVector, maskVal, stats); 1189 1196 } 1197 1190 1198 // Create the histogram structure. NOTE: we can not specify the bin size 1191 1199 // precisely since the argument to psHistogramAlloc() is the number of … … 1198 1206 psVectorHistogram(robustHistogram, myVector, maskVector, maskVal); 1199 1207 1200 // Smooth the histogram. 1201 // XXX: is that the right stdev? 1202 robustHistogramVector = p_psVectorsmoothHistGaussian(robustHistogram, 1208 // Smooth the histogram, Gaussian-style. 1209 robustHistogramVector = p_psVectorSmoothHistGaussian(robustHistogram, 1203 1210 tmpStats->clippedStdev / 4.0f); 1204 1211 … … 1208 1215 1209 1216 /************************************************************************** 1210 Determine the lower/upper quartiles. 1217 Determine the median/lower/upper quartile bin numbers. 1218 1219 We define a vector called "cumulativeRobustSums" where the value at 1220 index position i is equal to the sum of bins 0:i. This will be used in 1221 determining the median and lower/upper quartiles. 1211 1222 **************************************************************************/ 1212 // We define a vector called "cumulativeRobustSums..." where the value at 1213 // index position i is equal to the sum of bins 0:i. This will be used 1214 // now and later in determining the lower/upper quartiles. 1215 cumulativeRobustSumsFullRange = psVectorAlloc(robustHistogramVector->n, PS_TYPE_F32); 1216 cumulativeRobustSumsFullRange->data.F32[0] = robustHistogramVector->data.F32[0]; 1223 cumulativeRobustSums = psVectorAlloc(robustHistogramVector->n, PS_TYPE_F32); 1224 cumulativeRobustSums->data.F32[0] = robustHistogramVector->data.F32[0]; 1217 1225 for (i = 1; i < robustHistogramVector->n; i++) { 1218 cumulativeRobustSumsFullRange->data.F32[i] = 1219 cumulativeRobustSumsFullRange->data.F32[i - 1] + robustHistogramVector->data.F32[i]; 1220 } 1221 sumRobust = cumulativeRobustSumsFullRange->data.F32[robustHistogramVector->n - 1]; 1222 1223 // Determine the bin number containing the lower quartile point. 1224 LQBinNum = -1; 1225 for (i = 0; i < cumulativeRobustSumsFullRange->n; i++) { 1226 if (cumulativeRobustSumsFullRange->data.F32[i] >= (sumRobust / 4.0)) { 1227 LQBinNum = i; 1228 break; 1229 } 1230 } 1231 1232 // Determine the bin number containing the upper quartile point. 1233 UQBinNum = -1; 1234 for (i = cumulativeRobustSumsFullRange->n - 1; i >= 0; i--) { 1235 if (cumulativeRobustSumsFullRange->data.F32[i] <= (3.0 * sumRobust / 4.0)) { 1236 UQBinNum = i; 1237 break; 1238 } 1239 } 1240 1241 if ((LQBinNum == -1) || (UQBinNum == -1)) { 1242 psAbort(__func__, "Could not determine the robust lower/upper quartiles."); 1243 } 1244 1226 cumulativeRobustSums->data.F32[i] = cumulativeRobustSums->data.F32[i - 1] + 1227 robustHistogramVector->data.F32[i]; 1228 } 1229 sumRobust = cumulativeRobustSums->data.F32[robustHistogramVector->n - 1]; 1230 1231 tmpScalar.data.F32 = sumRobust / 4.0; 1232 LQBinNum = p_psVectorBinDisect(cumulativeRobustSums, &tmpScalar); 1233 tmpScalar.data.F32 = 3.0 * sumRobust / 4.0; 1234 UQBinNum = p_psVectorBinDisect(cumulativeRobustSums, &tmpScalar); 1235 tmpScalar.data.F32 = sumRobust / 2.0; 1236 medianBinNum = p_psVectorBinDisect(cumulativeRobustSums, &tmpScalar); 1237 1238 if ((LQBinNum < 0) || (UQBinNum < 0)) { 1239 psError(__func__, "Could not determine the robust lower/upper quartile bin numbers."); 1240 } 1241 if (medianBinNum < 0) { 1242 psError(__func__, "Could not determine the robust lower/upper quartile bin numbers."); 1243 } 1245 1244 /************************************************************************** 1246 1245 Determine the mode in the range LQ:UQ. 1247 1246 **************************************************************************/ 1248 1247 // Determine the bin with the peak value in the range LQ to UQ. 1249 m axBinNum = LQBinNum;1250 m axBinCount = robustHistogramVector->data.F32[LQBinNum];1251 sumN50 = (float)robustHistogram->nums->data. S32[LQBinNum];1248 modeBinNum = LQBinNum; 1249 modeBinCount = robustHistogramVector->data.F32[LQBinNum]; 1250 sumN50 = (float)robustHistogram->nums->data.U32[LQBinNum]; 1252 1251 for (i = LQBinNum + 1; i <= UQBinNum; i++) { 1253 if (robustHistogramVector->data.F32[i] > maxBinCount) { 1254 maxBinNum = i; 1255 maxBinCount = robustHistogramVector->data.F32[i]; 1256 } 1257 sumN50 += (float)robustHistogram->nums->data.S32[i]; 1258 } 1259 1260 // XXX: is dL defined as the value at the LQ/UQ, or the bin number? 1252 if (robustHistogramVector->data.F32[i] > modeBinCount) { 1253 modeBinNum = i; 1254 modeBinCount = robustHistogramVector->data.F32[i]; 1255 } 1256 sumN50 += (float)robustHistogram->nums->data.U32[i]; 1257 } 1258 1261 1259 dL = (UQBinNum - LQBinNum) / 4; 1262 1263 printf("(LQBinNum, UQBinNum, maxBinNum) is (%d, %d, %d)\n", LQBinNum, UQBinNum, maxBinNum);1264 1265 1260 /************************************************************************** 1266 1261 Determine the mean/stdev for the bins in the range mode-dL to mode+dL 1267 1262 **************************************************************************/ 1268 cumulativeRobustSumsDlRange = psVectorAlloc(robustHistogramVector->n, PS_TYPE_F32);1269 for (i = 0; i < robustHistogramVector->n; i++) {1270 cumulativeRobustSumsDlRange->data.F32[i] = 0.0;1271 }1272 sumNfit = 0.0;1273 cumulativeMedian = 0.0;1274 for (i = maxBinNum - dL; i <= maxBinNum + dL; i++) {1275 if ((0 <= i) && (i < robustHistogramVector->n)) {1276 cumulativeRobustSumsDlRange->data.F32[i] =1277 cumulativeRobustSumsDlRange->data.F32[i - 1] + robustHistogramVector->data.F32[i];1278 cumulativeMedian += robustHistogramVector->data.F32[i];1279 sumNfit += (float)robustHistogram->nums->data.S32[i];1280 }1281 }1282 1283 1263 // Calculate the mean of the smoothed robust histogram in the range 1284 1264 // mode-dL to mode+dL. We use the midpoint of each bin as the mean for 1285 1265 // that bin (this is a non-exact approximation). 1266 sumNfit = 0.0; 1286 1267 myMean = 0.0; 1287 for (i = m axBinNum - dL; i <= maxBinNum + dL; i++) {1268 for (i = modeBinNum - dL; i <= modeBinNum + dL; i++) { 1288 1269 if ((0 <= i) && (i < robustHistogramVector->n)) { 1289 myMean += (robustHistogramVector->data.F32[i]) * 0.5 * 1290 (robustHistogram->bounds->data.F32[i + 1] + robustHistogram->bounds->data.F32[i]); 1270 myMean += (robustHistogramVector->data.F32[i]) * PS_BIN_MIDPOINT(robustHistogram, i); 1291 1271 countFloat += robustHistogramVector->data.F32[i]; 1292 1272 } 1273 1274 sumNfit += (float)robustHistogram->nums->data.U32[i]; 1293 1275 } 1294 1276 myMean /= countFloat; … … 1297 1279 // mode-dL to mode+dL. We use the midpoint of each bin as the mean for 1298 1280 // that bin. 1299 for (i = m axBinNum - dL; i <= maxBinNum + dL; i++) {1281 for (i = modeBinNum - dL; i <= modeBinNum + dL; i++) { 1300 1282 if ((0 <= i) && (i < robustHistogramVector->n)) { 1301 diff = (0.5 * (robustHistogram->bounds->data.F32[i + 1] + 1302 robustHistogram->bounds->data.F32[i])) - myMean; 1283 diff = PS_BIN_MIDPOINT(robustHistogram, i) - myMean; 1303 1284 sumSquares += diff * diff * robustHistogramVector->data.F32[i]; 1304 1285 sumDiffs += diff * robustHistogramVector->data.F32[i]; … … 1315 1296 1316 1297 if (stats->options & PS_STAT_ROBUST_MODE) { 1317 stats->robustMode = 0.5 * 1318 (robustHistogram->bounds->data.F32[maxBinNum] + robustHistogram->bounds->data.F32[maxBinNum + 1]); 1298 stats->robustMode = PS_BIN_MIDPOINT(robustHistogram, modeBinNum); 1319 1299 } 1320 1300 … … 1322 1302 stats->robustStdev = myStdev; 1323 1303 } 1324 // To determine the median (and later, the lower/upper quartile), we fit 1325 // a quadratic to the three bins surrounding the bin containing the median. 1326 // The quadratic y=f(x) with x being the midpoint of each bin, and y being 1327 // the cumulative number of data points in all bins up to, and including, 1328 // this bin. We then solve the quadratic for 1329 1330 // XXX: Create a "p_psQuadraticFitAndSolveForX() function. 1331 1304 1305 // To determine the median, we fit a quadratic y=f(x) to the three bins 1306 // surrounding the bin containing the median (x is the midpoint of each 1307 // bin and y is the value of each bin). Then we figure out what value 1308 // of x corresponds to f(x) being the median (half of all points). 1332 1309 if (stats->options & PS_STAT_ROBUST_MEDIAN) { 1333 if ((maxBinNum > 0) && (maxBinNum < (robustHistogram->nums->n - 1))) { 1334 x->data.F64[0] = (double)0.5 * 1335 (robustHistogram->bounds->data.F32[maxBinNum - 1] + 1336 robustHistogram->bounds->data.F32[maxBinNum]); 1337 x->data.F64[1] = (double)0.5 * 1338 (robustHistogram->bounds->data.F32[maxBinNum] + 1339 robustHistogram->bounds->data.F32[maxBinNum + 1]); 1340 x->data.F64[2] = (double)0.5 * 1341 (robustHistogram->bounds->data.F32[maxBinNum + 1] + 1342 robustHistogram->bounds->data.F32[maxBinNum + 2]); 1343 1344 y->data.F64[0] = cumulativeRobustSumsDlRange->data.F32[maxBinNum - 1]; 1345 y->data.F64[1] = cumulativeRobustSumsDlRange->data.F32[maxBinNum]; 1346 y->data.F64[2] = cumulativeRobustSumsDlRange->data.F32[maxBinNum + 1]; 1347 1348 // Ensure that cumulativeMedian/2 is actually within the range of the bins 1349 // we are using. 1350 cumulativeMedian *= 0.5; 1351 if (!((y->data.F64[0] <= cumulativeMedian) && (cumulativeMedian <= y->data.F64[2]))) { 1352 printf("((%f), %f, %f)\n", cumulativeMedian, y->data.F64[0], y->data.F64[2]); 1353 psAbort(__func__, "p_psVectorRobustStats(1): midpoint not within y-range\n"); 1354 } 1355 // XXX: yErr is not currently used by psVectorFitPolynomial1D(). We 1356 // may have to set this meaningfully later. 1357 yErr->data.F64[0] = 1.0; 1358 yErr->data.F64[1] = 1.0; 1359 yErr->data.F64[2] = 1.0; 1360 1361 // Determine the coefficients of the polynomial. 1362 myPoly = psVectorFitPolynomial1D(myPoly, x, y, yErr); 1363 // Call p_ps1DPolyMedian(), which does a binary search on the 1364 // polynomial, looking for the value x such that 1365 // f(x) = cumulativeMedian. 1366 stats->robustMedian = p_ps1DPolyMedian(myPoly, x->data.F64[0], x->data.F64[2], cumulativeMedian); 1367 } else { 1368 // If the mode is the first/last histogram bin, then simply use 1369 // the midpoint of that bin. 1370 stats->robustMedian = 0.5 * (robustHistogram->bounds->data.F32[maxBinNum + 1] + 1371 robustHistogram->bounds->data.F32[maxBinNum]); 1372 } 1373 } 1374 // The lower/upper quartile calculations are very similar to the median 1375 // calculations. We fit a quadratic to the array containing the 1376 // cumulative data points in each bin, then search for x such that 1377 // f(x) equals the lower/upper quartile exactly. 1378 // 1310 // Take a psVector. Fit a polynomial y = f(x) to the 3 data elements 1311 // surrounding medianBinNum, then find the x-value corresponding y = sumRobust/2.0. 1312 stats->robustMedian = fitQuadraticSearchForYThenReturnX(robustHistogram->bounds, 1313 cumulativeRobustSums, 1314 medianBinNum, 1315 sumRobust/2.0); 1316 } 1317 1318 // To determine the quartiles, we fit a quadratic y=f(x) to the three bins 1319 // surrounding the bin containing LQ/UQ (x is the midpoint of each 1320 // bin and y is the value of each bin). Then we figure out what value 1321 // of x corresponds to f(x) being the LQ/UQ. 1379 1322 if (stats->options & PS_STAT_ROBUST_QUARTILE) { 1380 countFloat = cumulativeRobustSumsFullRange->data.F32[robustHistogramVector->n - 1]; 1381 1382 if ((LQBinNum > 0) && (LQBinNum < (robustHistogram->nums->n - 1))) { 1383 x->data.F64[0] = (double)0.5 * 1384 (robustHistogram->bounds->data.F32[LQBinNum - 1] + 1385 robustHistogram->bounds->data.F32[LQBinNum]); 1386 x->data.F64[1] = (double)0.5 * 1387 (robustHistogram->bounds->data.F32[LQBinNum] + 1388 robustHistogram->bounds->data.F32[LQBinNum + 1]); 1389 x->data.F64[2] = (double)0.5 * 1390 (robustHistogram->bounds->data.F32[LQBinNum + 1] + 1391 robustHistogram->bounds->data.F32[LQBinNum + 2]); 1392 1393 y->data.F64[0] = cumulativeRobustSumsFullRange->data.F32[LQBinNum - 1]; 1394 y->data.F64[1] = cumulativeRobustSumsFullRange->data.F32[LQBinNum]; 1395 y->data.F64[2] = cumulativeRobustSumsFullRange->data.F32[LQBinNum + 1]; 1396 1397 if (!((y->data.F64[0] <= (countFloat / 4.0)) && ((countFloat / 4.0) <= y->data.F64[2]))) { 1398 psAbort(__func__, "p_psVectorRobustStats(2): midpoint not within y-range\n"); 1399 } 1400 1401 yErr->data.F64[0] = 1.0; 1402 yErr->data.F64[1] = 1.0; 1403 yErr->data.F64[2] = 1.0; 1404 1405 myPoly = psVectorFitPolynomial1D(myPoly, x, y, yErr); 1406 stats->robustLQ = p_ps1DPolyMedian(myPoly, x->data.F64[0], x->data.F64[2], countFloat / 4.0); 1407 1408 } else { 1409 // If the LQ is the first/last histogram bin, then simply use 1410 // the midpoint of that bin. 1411 stats->robustLQ = 0.5 * (robustHistogram->bounds->data.F32[LQBinNum + 1] + 1412 robustHistogram->bounds->data.F32[LQBinNum]); 1413 } 1414 1415 if ((UQBinNum > 0) && (UQBinNum < (robustHistogram->nums->n - 1))) { 1416 x->data.F64[0] = (double)0.5 * 1417 (robustHistogram->bounds->data.F32[UQBinNum - 1] + 1418 robustHistogram->bounds->data.F32[UQBinNum]); 1419 x->data.F64[1] = (double)0.5 * 1420 (robustHistogram->bounds->data.F32[UQBinNum] + 1421 robustHistogram->bounds->data.F32[UQBinNum + 1]); 1422 x->data.F64[2] = (double)0.5 * 1423 (robustHistogram->bounds->data.F32[UQBinNum + 1] + 1424 robustHistogram->bounds->data.F32[UQBinNum + 2]); 1425 1426 y->data.F64[0] = cumulativeRobustSumsFullRange->data.F32[UQBinNum - 1]; 1427 y->data.F64[1] = cumulativeRobustSumsFullRange->data.F32[UQBinNum]; 1428 y->data.F64[2] = cumulativeRobustSumsFullRange->data.F32[UQBinNum + 1]; 1429 1430 if (!((y->data.F64[0] <= (3.0 * countFloat / 4.0)) && 1431 ((3.0 * countFloat / 4.0) <= y->data.F64[2]))) { 1432 psAbort(__func__, "p_psVectorRobustStats(3): midpoint not within y-range\n"); 1433 } 1434 1435 yErr->data.F64[0] = 1.0; 1436 yErr->data.F64[1] = 1.0; 1437 yErr->data.F64[2] = 1.0; 1438 1439 myPoly = psVectorFitPolynomial1D(myPoly, x, y, yErr); 1440 stats->robustUQ = p_ps1DPolyMedian(myPoly, 1441 x->data.F64[0], x->data.F64[2], 3.0 * countFloat / 4.0); 1442 } else { 1443 // If the UQ is the first/last histogram bin, then simply use 1444 // the midpoint of that bin. 1445 stats->robustUQ = 0.5 * (robustHistogram->bounds->data.F32[UQBinNum + 1] + 1446 robustHistogram->bounds->data.F32[UQBinNum]); 1447 } 1448 } 1323 countFloat = cumulativeRobustSums->data.F32[robustHistogramVector->n - 1]; 1324 1325 stats->robustLQ = fitQuadraticSearchForYThenReturnX(robustHistogram->bounds, 1326 cumulativeRobustSums, 1327 LQBinNum, 1328 countFloat/4.0); 1329 stats->robustUQ = fitQuadraticSearchForYThenReturnX(robustHistogram->bounds, 1330 cumulativeRobustSums, 1331 UQBinNum, 1332 3.0 * countFloat/4.0); 1333 } 1334 // XXX: I think sumNfit == sumN50 here. 1449 1335 stats->robustNfit = sumNfit; 1450 1336 stats->robustN50 = sumN50; 1451 1337 1452 psFree(x);1453 psFree(y);1454 psFree(yErr);1455 1338 psFree(tmpStats); 1456 1339 psFree(robustHistogram); 1457 psFree(myPoly); 1458 psFree(cumulativeRobustSumsFullRange); 1459 psFree(cumulativeRobustSumsDlRange); 1340 psFree(robustHistogramVector); 1341 psFree(cumulativeRobustSums); 1460 1342 } 1461 1343 … … 1468 1350 // I am commenting this code out, and replacing it with code which 1469 1351 // calculates the mean directly on the robustHistogram. 1470 //1471 // XXX: Replace this with the LaGrange interpolation stuff.1472 1352 1473 1353 domain = psImageAlloc(1, robustHistogramVector->n, PS_TYPE_F32); … … 1479 1359 max_pos = -1; 1480 1360 for (i=0;i<robustHistogramVector->n;i++) { 1481 domain->data.F32[i][0] = 0.5 * (robustHistogram->bounds->data.F32[i+1] + 1482 robustHistogram->bounds->data.F32[i]); 1361 domain->data.F32[i][0] = PS_BIN_MIDPOINT(robustHistogram, i);bounds->data.F32[modeBinNum + 1]); 1483 1362 data->data.F32[i] = (float) robustHistogramVector->data.F32[i]; 1484 1363 errors->data.F32[i] = 1.0; … … 1695 1574 psScalar tmpScalar; 1696 1575 tmpScalar.type.type = PS_TYPE_F32; 1576 psVector* inF32; 1577 int mustFreeTmp = 1; 1697 1578 1698 1579 // NOTE: Verify that this is the correct action. … … 1706 1587 1707 1588 if (out->nums->type.type != PS_TYPE_U32) { 1708 psAbort(__func__, "Only data type PS_TYPE_U32 for out put.nums member.");1589 psAbort(__func__, "Only data type PS_TYPE_U32 for out->nums member."); 1709 1590 } 1710 1591 // NOTE: Verify that this is the correct action. … … 1713 1594 } 1714 1595 1715 if (in->type.type != PS_TYPE_F32) {1716 psAbort(__func__, "Only data type PS_TYPE_F32 is currently supported (0x%x).", in->type.type);1717 }1718 1719 1596 if (mask != NULL) { 1720 1597 if (in->n != mask->n) { 1721 ps Abort(__func__, "Vector data and vector mask are of different sizes.");1598 psError(__func__, "Vector data and vector mask are of different sizes."); 1722 1599 } 1723 1600 if (mask->type.type != PS_TYPE_U8) { 1724 psAbort(__func__, "Vector mask must be type PS_TYPE_U8"); 1725 } 1601 psError(__func__, "Vector mask must be type PS_TYPE_U8"); 1602 } 1603 } 1604 1605 inF32 = p_psConvertToF32((psVector *) in); 1606 if (inF32 == NULL) { 1607 inF32 = (psVector *) in; 1608 mustFreeTmp = 0; 1726 1609 } 1727 1610 … … 1730 1613 1731 1614 numBins = out->nums->n; 1732 for (i = 0; i < in ->n; i++) {1615 for (i = 0; i < inF32->n; i++) { 1733 1616 // Check if this pixel is masked, and if so, skip it. 1734 1617 if ((mask == NULL) || ((mask != NULL) && (!(mask->data.U8[i] & maskVal)))) { 1735 1618 // Check if this pixel is below the minimum value, and if so 1736 1619 // count it, then skip it. 1737 if (in ->data.F32[i] < out->bounds->data.F32[0]) {1620 if (inF32->data.F32[i] < out->bounds->data.F32[0]) { 1738 1621 out->minNum++; 1739 1622 // Check if this pixel is above the maximum value, and if so 1740 1623 // count it, then skip it. 1741 } else if (in ->data.F32[i] > out->bounds->data.F32[numBins]) {1624 } else if (inF32->data.F32[i] > out->bounds->data.F32[numBins]) { 1742 1625 out->maxNum++; 1743 1626 } else { … … 1746 1629 if (out->uniform == true) { 1747 1630 binSize = out->bounds->data.F32[1] - out->bounds->data.F32[0]; 1748 binNum = (int)((in ->data.F32[i] - out->bounds->data.F32[0]) / binSize);1631 binNum = (int)((inF32->data.F32[i] - out->bounds->data.F32[0]) / binSize); 1749 1632 1750 1633 // NOTE: This next if-statement really shouldn't be necessary. … … 1755 1638 } 1756 1639 1757 (out->nums->data. S32[binNum])++;1640 (out->nums->data.U32[binNum])++; 1758 1641 1759 1642 // If this is a non-uniform histogram, determining the correct 1760 1643 // bin number requires a bit more work. 1761 1644 } else { 1762 tmpScalar.data.F32 = in->data.F32[i]; 1763 tmp = p_psVectorBinDisect(out->bounds, 1764 &tmpScalar); 1765 if (tmp == -1) { 1766 // XXX: Generate warning message 1645 tmpScalar.data.F32 = inF32->data.F32[i]; 1646 tmp = p_psVectorBinDisect(out->bounds, &tmpScalar); 1647 if (tmp < 0) { 1648 // XXX: Generate warning message 1767 1649 } else { 1768 (out->nums->data. S32[tmp])++;1650 (out->nums->data.U32[tmp])++; 1769 1651 } 1770 1652 } … … 1772 1654 } 1773 1655 } 1656 1657 if (mustFreeTmp == 1) { 1658 psFree(inF32); 1659 } 1774 1660 return (out); 1775 1661 } 1776 1662 1777 1663 /****************************************************************************** 1778 p_psConvertToF32(myVector, maskVector, maskVal, stats): this is the cheap 1779 way to support a variety of vector data types: we simply convert the input 1780 vector to F32 at the beginning, and write all of our functions in F32. If 1781 the vast majority of all vector stat operations are F32 (or any other single 1782 type), then this is probably the best way to go. Otherwise, when the 1783 algorithms stablize, we will then macro everything and put type support in 1784 the various stat functions. 1664 p_psConvertToF32(in): this is the cheap way to support a variety of vector 1665 data types: we simply convert the input vector to F32 at the beginning, and 1666 write all of our functions in F32. If the vast majority of all vector stat 1667 operations are F32 (or any other single type), then this is probably the 1668 best way to go. Otherwise, when the algorithms stablize, we will then macro 1669 everything and put type support in the various stat functions. 1785 1670 1786 1671 XXX: Should the default data type be F64? Since we are buying Athlons... 1787 1672 *****************************************************************************/ 1788 psVector* p_psConvertToF32(ps Stats* stats, psVector* in, psVector* mask, unsigned int maskVal)1673 psVector* p_psConvertToF32(psVector* in) 1789 1674 { 1790 1675 int i = 0; … … 1800 1685 for (i = 0; i < in->n; i++) { 1801 1686 tmp->data.F32[i] = (float)in->data.U16[i]; 1687 } 1688 } else if (in->type.type == PS_TYPE_U8) { 1689 tmp = psVectorAlloc(in->n, PS_TYPE_F32); 1690 for (i = 0; i < in->n; i++) { 1691 tmp->data.F32[i] = (float)in->data.U8[i]; 1802 1692 } 1803 1693 } else if (in->type.type == PS_TYPE_F64) { … … 1839 1729 int mustFreeTmp = 1; 1840 1730 1841 // NOTE: Verify that this is the correct action.1842 1731 if (in == NULL) { 1843 return (stats); 1844 } 1845 if (stats == NULL) { 1846 return (NULL); 1847 } 1848 1849 inF32 = p_psConvertToF32(stats, in, mask, maskVal); 1732 psError(__func__, "in is NULL\n"); 1733 return(stats); 1734 } 1735 PS_CHECK_NULL_PTR_RETURN_NULL(stats); 1736 1737 inF32 = p_psConvertToF32((psVector *) in); 1850 1738 if (inF32 == NULL) { 1851 1739 inF32 = in; 1852 1740 mustFreeTmp = 0; 1853 1741 } 1854 // XXX: Should we abort if (stats->min == stats->max)?1855 1742 if ((stats->options & PS_STAT_USE_RANGE) && (stats->min >= stats->max)) { 1856 psAbort(__func__, "psVectorStats() called with range: %f to %f\n", stats->min, stats->max); 1743 psError(__func__, "psVectorStats() called with range: %f to %f\n", stats->min, stats->max); 1744 return(stats); 1857 1745 } 1858 1746 -
trunk/psLib/test/dataManip/tst_psMinimize06.c
r1992 r2197 74 74 } 75 75 76 77 int main() 76 psVector *myFunc2(psImage *myDeriv, 77 psVector *myParams, 78 psArray *myCoords) 79 { 80 psVector *sum = psVectorAlloc(myCoords->n, PS_TYPE_F32); 81 int i; 82 int j; 83 84 85 if (myDeriv == NULL) { 86 myDeriv = psImageAlloc(myParams->n, myCoords->n, PS_TYPE_F32); 87 psError(__func__, "myDeriv is NULL.\n"); 88 } 89 90 for (i=0;i<N;i++) { 91 sum->data.F32[i] = MIN_VALUE; 92 for (j=0;j<NUM_PARAMS;j++) { 93 sum->data.F32[i]+= (myParams->data.F32[j] - expectedParm[j]) * 94 (myParams->data.F32[j] - expectedParm[j]); 95 96 myDeriv->data.F32[i][j] = (2.0 * myParams->data.F32[j]) - 97 (2.0 * expectedParm[j]); 98 } 99 } 100 101 return(sum); 102 } 103 104 int t01() 105 { 106 int currentId = psMemGetId(); 107 int memLeaks = 0; 108 int i = 0; 109 psArray *myCoords; 110 psVector *myParams; 111 psImage *myCovar; 112 psMinimization *min; 113 psVector *y; 114 115 psTraceSetLevel(".psLib", 0); 116 /************************************************************************** 117 *************************************************************************/ 118 min = psMinimizationAlloc(NUM_ITERATIONS, ERR_TOL); 119 myCovar = psImageAlloc(NUM_PARAMS, NUM_PARAMS, PS_TYPE_F32); 120 myParams = psVectorAlloc(NUM_PARAMS, PS_TYPE_F32); 121 myCoords = psArrayAlloc(N); 122 y = psVectorAlloc(N, PS_TYPE_F32); 123 124 for (i=0;i<N;i++) { 125 myCoords->data[i] = (psPTR *) psVectorAlloc(2, PS_TYPE_F32); 126 ((psVector *) (myCoords->data[i]))->data.F32[0] = (float) (i+10); 127 ((psVector *) (myCoords->data[i]))->data.F32[1] = (float) (i+3); 128 y->data.F32[i] = (float) i; 129 } 130 for (i=0;i<NUM_PARAMS;i++) { 131 expectedParm[i] = 2.42 + (float) (2 * i); 132 myParams->data.F32[i] = (float) i; 133 myParams->data.F32[i] = expectedParm[i] * 1.3; 134 myParams->data.F32[i] = (float) (5 + i); 135 myParams->data.F32[i] = 0.0; 136 } 137 138 psMyMinimizeLMChi2(min, 139 myCovar, 140 myParams, 141 NULL, 142 myCoords, 143 y, 144 NULL, 145 (psMyMinimizeLMChi2Func) myFunc2); 146 147 printf("\nThe chi-squared is %f\n", min->value); 148 for (i=0;i<NUM_PARAMS;i++) { 149 printf("Parameter %d at the minimum is %f (expected: %f)\n", i, 150 myParams->data.F32[i], expectedParm[i]); 151 } 152 153 psFree(min); 154 psFree(myCovar); 155 psFree(myParams); 156 psFree(myCoords); 157 psFree(y); 158 159 psMemCheckCorruption(1); 160 memLeaks = psMemCheckLeaks(currentId,NULL,NULL); 161 if (0 != memLeaks) { 162 psAbort(__func__,"Memory Leaks! (%d leaks)", memLeaks); 163 } 164 return (!testStatus); 165 } 166 167 int t02() 78 168 { 79 169 int currentId = psMemGetId(); … … 85 175 psImage *myCovar; 86 176 psMinimization *min; 87 psVector *x = psVectorAlloc(N, PS_TYPE_F32);88 177 psVector *y = psVectorAlloc(N, PS_TYPE_F32); 89 178 90 179 psTraceSetLevel(".psLib", 0); 180 t02(); 91 181 /************************************************************************** 92 182 *************************************************************************/ … … 101 191 ((psVector *) (myCoords->data[i]))->data.F32[0] = (float) (i+10); 102 192 ((psVector *) (myCoords->data[i]))->data.F32[1] = (float) (i+3); 103 x->data.F32[i] = (float) i;104 193 y->data.F32[i] = (float) i; 105 194 } … … 131 220 psFree(myParamMask); 132 221 psFree(min); 133 psFree(x);134 222 psFree(y); 135 223 psFree(myCovar); … … 142 230 return (!testStatus); 143 231 } 232 233 int main() 234 { 235 t01(); 236 // t02(); 237 } -
trunk/psLib/test/dataManip/tst_psStats07.c
r1900 r2197 10 10 #include <math.h> 11 11 12 #define N 20012 #define N 90 13 13 #define MEAN 32.0 14 14 #define STDEV 2.0 15 15 #define ERROR_TOLERANCE 0.10 16 16 17 int main()17 int t00() 18 18 { 19 19 psStats * myStats = NULL; … … 32 32 float realMedianNoMask = MEAN; 33 33 float realModeNoMask = MEAN; 34 float realStdevNoMask = STDEV * 0. 33;34 float realStdevNoMask = STDEV * 0.20; 35 35 float realLQNoMask = MEAN - ( 0.6 * STDEV ); 36 36 float realUQNoMask = MEAN + ( 0.6 * STDEV ); 37 37 int realN50NoMask = N / 4; 38 38 int realNfitNoMask = N / 4; 39 float realMeanWithMask = MEAN; 40 float realMedianWithMask = MEAN; 41 float realModeWithMask = MEAN; 42 float realStdevWithMask = STDEV; 43 float realLQWithMask = MEAN; 44 float realUQWithMask = MEAN; 45 int realN50WithMask = N / 4; 46 int realNfitWithMask = N / 4; 47 39 40 psTraceSetLevel(".psLib.dataManip.psStats", 10); 48 41 49 42 /*************************************************************************/ … … 232 225 "PS_STAT_ROBUST_STATS: robust Nfit: no vector mask", 233 226 testStatus ); 234 235 236 return ( 0 ); 227 return(testStatus); 228 229 /*************************************************************************/ 230 /* Deallocate data structures */ 231 /*************************************************************************/ 232 printPositiveTestHeader( stdout, 233 "psStats functions", 234 "psStats(): deallocating memory" ); 235 236 psFree( myStats ); 237 psFree( myVector ); 238 psFree( maskVector ); 239 240 psMemCheckCorruption( 1 ); 241 memLeaks = psMemCheckLeaks(currentId,NULL,stderr); 242 if ( 0 != memLeaks ) { 243 psAbort( __func__, "Memory Leaks! (%d leaks)", memLeaks ); 244 } 245 246 printFooter( stdout, 247 "psVector functions", 248 "psStats(): deallocating memory", 249 testStatus ); 250 251 return ( !globalTestStatus ); 252 } 253 254 255 int t01() 256 { 257 psStats * myStats = NULL; 258 int testStatus = true; 259 int globalTestStatus = true; 260 int i = 0; 261 psVector *myVector = NULL; 262 psVector *maskVector = NULL; 263 // NOTE: These values were calculated by running the function on the data. 264 // A: They must be changed if we adjust the number of data points. 265 // B: We don't really know that they are correct. 266 int count = 0; 267 int currentId = psMemGetId(); 268 int memLeaks = 0; 269 float realMeanWithMask = MEAN; 270 float realMedianWithMask = MEAN; 271 float realModeWithMask = MEAN; 272 float realStdevWithMask = STDEV * 0.20; 273 float realLQWithMask = MEAN; 274 float realUQWithMask = MEAN; 275 int realN50WithMask = N / 4; 276 int realNfitWithMask = N / 4; 277 278 psTraceSetLevel(".psLib.dataManip.psStats", 10); 279 280 /*************************************************************************/ 281 /* Allocate and initialize data structures */ 282 /*************************************************************************/ 283 myStats = psStatsAlloc( PS_STAT_ROBUST_MEAN | 284 PS_STAT_ROBUST_MEDIAN | 285 PS_STAT_ROBUST_MODE | 286 PS_STAT_ROBUST_STDEV | 287 PS_STAT_ROBUST_QUARTILE ); 288 289 maskVector = psVectorAlloc( N, PS_TYPE_U8 ); 290 maskVector->n = N; 291 myVector = psGaussianDev( MEAN, STDEV, N ); 292 // Set the mask vector and calculate the expected maximum. 293 for ( i = 0;i < N;i++ ) { 294 if ( i < ( N / 2 ) ) { 295 maskVector->data.U8[ i ] = 0; 296 count++; 297 } else { 298 maskVector->data.U8[ i ] = 1; 299 } 300 } 237 301 238 302 /*************************************************************************/ … … 422 486 return ( !globalTestStatus ); 423 487 } 488 489 int main() 490 { 491 t00(); 492 t01(); 493 }
Note:
See TracChangeset
for help on using the changeset viewer.
