IPP Software Navigation Tools IPP Links Communication Pan-STARRS Links

Changeset 2197


Ignore:
Timestamp:
Oct 26, 2004, 11:25:59 AM (22 years ago)
Author:
gusciora
Message:

...

Location:
trunk/psLib
Files:
15 edited

Legend:

Unmodified
Added
Removed
  • trunk/psLib/src/astro/psCoord.c

    r2104 r2197  
    1010*  @author George Gusciora, MHPCC
    1111*
    12 *  @version $Revision: 1.25 $ $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 $
    1414*
    1515*  Copyright 2004 Maui High Performance Computing Center, University of Hawaii
     
    5858/*****************************************************************************/
    5959
    60 static float p_psArg(float x, float y);
    61 
    62 /******************************************************************************
    63 XXX: Verify this arc tan function.
    64 XXX: macro
    65 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 
    9360/*****************************************************************************/
    9461/* FUNCTION IMPLEMENTATION - PUBLIC                                          */
     
    292259    if (projection->type == PS_PROJ_TAN) {
    293260        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);
    295262        tmp->r = atan(180.0 / (R * M_PI));
    296263
    297264    } else if (projection->type == PS_PROJ_SIN) {
    298265        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);
    300267        tmp->r = acos((R * M_PI) / 180.0);
    301268
     
    314281        chu2 *= chu2;
    315282        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);
    317284        tmp->r = asin((coord->y * chu * M_PI) / 180.0);
    318285
  • trunk/psLib/src/astronomy/psCoord.c

    r2104 r2197  
    1010*  @author George Gusciora, MHPCC
    1111*
    12 *  @version $Revision: 1.25 $ $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 $
    1414*
    1515*  Copyright 2004 Maui High Performance Computing Center, University of Hawaii
     
    5858/*****************************************************************************/
    5959
    60 static float p_psArg(float x, float y);
    61 
    62 /******************************************************************************
    63 XXX: Verify this arc tan function.
    64 XXX: macro
    65 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 
    9360/*****************************************************************************/
    9461/* FUNCTION IMPLEMENTATION - PUBLIC                                          */
     
    292259    if (projection->type == PS_PROJ_TAN) {
    293260        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);
    295262        tmp->r = atan(180.0 / (R * M_PI));
    296263
    297264    } else if (projection->type == PS_PROJ_SIN) {
    298265        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);
    300267        tmp->r = acos((R * M_PI) / 180.0);
    301268
     
    314281        chu2 *= chu2;
    315282        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);
    317284        tmp->r = asin((coord->y * chu * M_PI) / 180.0);
    318285
  • trunk/psLib/src/dataManip/psConstants.h

    r2136 r2197  
    66 *  @author GLG, MHPCC
    77 *
    8  *  @version $Revision: 1.12 $ $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 $
    1010 *
    1111 *  Copyright 2004 Maui High Performance Computing Center, University of Hawaii
     
    107107} \
    108108
     109/** Preprocessor macro to generate error on a NULL vector */
     110#define PS_CHECK_NULL_VECTOR_RETURN_F0(NAME) \
     111if (NAME == NULL || NAME->data.V == NULL) { \
     112    psError(__func__,"Unallowable operation: %s or its data is NULL.", #NAME); \
     113    return(0.0); \
     114} \
     115
    109116/** Preprocessor macro to generate error on a NULL poniter */
    110117#define PS_CHECK_NULL_PTR_RETURN_NULL(NAME) \
     
    113120    return(NULL); \
    114121}
     122
     123/** Preprocessor macro to generate error on a NULL poniter */
     124#define PS_CHECK_NULL_PTR_RETURN_F0(NAME) \
     125if (NAME == NULL) { \
     126    psError(__func__,"Unallowable operation: %s is NULL.", #NAME); \
     127    return(0.0); \
     128}
     129
    115130/** Preprocessor macro to generate error on a NULL poniter */
    116131#define PS_CHECK_NULL_PTR_RETURN_ZERO(NAME) \
     
    127142} \
    128143
     144/** Preprocessor macro to generate error for zero length vector */
     145#define PS_CHECK_EMPTY_VECTOR_RETURN_F0(NAME) \
     146if (NAME->n < 1) { \
     147    psError(__func__,"Unallowable operation: %s has zero n value.", #NAME); \
     148    return(0.0); \
     149} \
     150
    129151/** Preprocessor macro to generate error on differing size vectors */
    130152#define PS_CHECK_VECTOR_SIZE_EQUAL_RETURN_NULL(VEC1, VEC2) \
     
    132154    psError(__func__,"Vector %s has size %d, Vector %s has size %d.", #VEC1, VEC1->n, #VEC2, VEC2->n); \
    133155    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) \
     160if (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); \
    134163}
    135164
     
    199228
    200229#define PS_MAX(A, B) \
    201 ((A > B) ? A : B) \
     230(((A) > (B)) ? (A) : (B)) \
    202231
    203232#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  
    77 *  polynomials.  It also contains a Gaussian functions.
    88 *
    9  *  @version $Revision: 1.52 $ $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 $
    1111 *
    1212 *  Copyright 2004 Maui High Performance Computing Center, University of Hawaii
  • trunk/psLib/src/dataManip/psMinimize.c

    r2106 r2197  
    99 *  @author GLF, MHPCC
    1010 *
    11  *  @version $Revision: 1.58 $ $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 $
    1313 *
    1414 *  Copyright 2004 Maui High Performance Computing Center, University of Hawaii
     
    636636    psFree(currValueVec);
    637637    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/******************************************************************************
     650psMyMinimizeLMChi2():  This routine will take an procedure which calculates
     651an arbitrary function and it's derivative and minimize the chi-squared match
     652between that function at the specified coords and the specified value at
     653those coords.
     654 
     655XXX: 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 
     661XXX: This is very different from what is specified in the SDR.  Must
     662coordinate with IfA on new SDR.
     663 
     664XXX: Do vector/image recycles.
     665 
     666XXX: probably yErr will be part of the SDR.
     667 
     668XXX: 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 *****************************************************************************/
     673bool 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);
    638895
    639896    if ((min->iter < min->maxIter) ||
  • trunk/psLib/src/dataManip/psMinimize.h

    r1992 r2197  
    88 *  @author GLG, MHPCC
    99 *
    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 $
    1212 *
    1313 *  Copyright 2004 Maui High Performance Computing Center, University of Hawaii
     
    8484
    8585
     86/*
     87   Bug 203:
     88 
     89typedef float (*psMinimizeLMChi2Func)(psVector *deriv, const psVector *params,
     90const psVector *x);
     91 
     92This function takes the current guess for the parameters for which we are
     93trying to get the best values (params), and a single vector (x) of
     94conditions 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 
     105This takes the minimization specs (min), returns the covariance matrix
     106(covar), takes the best guess of initial parameters (params), the parameter
     107mask (paramMask), and takes multiple vectors of conditions in an array (x),
     108the corresponding measured values (y) and errors (yErr) and the function to
     109fit (func).
     110 
     111For example, for GRB afterglows, I have flux as a function of time and
     112frequency.  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
     114errors in "yErr".  Then each of the time-frequency pairs are passed to my model
     115function with the current parameters, and the model function returns the flux
     116for that time-frequency pair, and the derivative with respect to each of the
     117parameters.
     118 
     119This seems reasonable.  The only thing we could change would be to have the
     120function be defined:
     121 
     122typedef psVector* (*psMinimizeLMChi2Func)(psImage *deriv,
     123                                          const psVector *params,
     124                                          const psArray *x);
     125 
     126So it would return the model value for each of the measurements at once, and
     127return for each the derivatives (so that it returns a matrix).
     128 
     129What do you think?
     130 
     131 
     132 
     133I'm not sure I understand how LM chi-squared minimization will work with the
     134following function that you define:
     135 
     136    typedef psVector* (*psMinimizeLMChi2Func)(psImage *deriv,
     137                                              const psVector *params,
     138                                              const psArray *x);
     139 
     140The chi-squared minimization algorithm, as defined in NR, requires that
     141function to be minimized be evaluated at each data point, and that all
     142derivatives, with respect to each parameter, be calculated at each data
     143point.  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
    86161// XXX: What if any of these arguments are NULL?
     162
     163
    87164typedef
    88165float (*psMinimizeLMChi2Func)(psVector *deriv,
     
    98175                      psMinimizeLMChi2Func func);
    99176
     177
     178typedef
     179psVector* (*psMyMinimizeLMChi2Func)(psImage *deriv,
     180                                    const psVector *params,
     181                                    const psArray *x);
     182
     183bool 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
    100192typedef
    101193float (*psMinimizePowellFunc)(const psVector *params,
  • trunk/psLib/src/dataManip/psStats.c

    r2074 r2197  
    99 *  @author GLG, MHPCC
    1010 *
    11  *  @version $Revision: 1.67 $ $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 $
    1313 *
    1414 *  Copyright 2004 Maui High Performance Computing Center, University of Hawaii
     
    4040/*****************************************************************************/
    4141// 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.
    4343#define CLIPPED_NUM_ITER_LB 1
    4444#define CLIPPED_NUM_ITER_UB 10
     
    5757/* TYPE DEFINITIONS                                                          */
    5858/*****************************************************************************/
     59psVector* p_psConvertToF32(psVector* in);
    5960
    6061/*****************************************************************************/
     
    423424    float rangeMax = 0.0;       // Exclude date above this
    424425
    425     // Determine if the number of data points exceed a threshold which will
    426     // cause to generate robust stats, as opposed to exact stats.
    427     // XXX: This code is no longer used.  We now calculate the median exactly
    428     // 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 
    443426    // Determine how many data points fit inside this min/max range
    444427    // and are not masked, IF the maskVector is not NULL>
     
    507490
    508491/******************************************************************************
    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,
     492p_psVectorSmoothHistGaussian(): This routine smoothes the data in the input
     493robustHistogram with a Gaussian of width sigma.
     494 *****************************************************************************/
     495#define GAUSS_WIDTH_OTHER 5.0
     496psVector* p_psVectorSmoothHistGaussian(psHistogram* robustHistogram,
    521497                                       float sigma)
    522498{
    523499    int i = 0;                  // Loop index variable
    524500    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
    563543        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);
    572554}
    573555
     
    913895specified data point.
    914896 *****************************************************************************/
    915 float p_psGaussian(const psVector* restrict myData, const psVector* restrict myParams)
     897float p_psGaussian(const psVector* restrict myData,
     898                   const psVector* restrict myParams)
    916899{
    917900    float x = myData->data.F32[0];
     
    930913calculates the specified partial derivative of the above Gaussian function.
    931914 *****************************************************************************/
    932 float p_psGaussianDeriv(const psVector* restrict myData, const psVector* restrict myParams, int whichParam)
     915float p_psGaussianDeriv(const psVector* restrict myData,
     916                        const psVector* restrict myParams, int whichParam)
    933917{
    934918    float x = myData->data.F32[0];
     
    10361020
    10371021/******************************************************************************
    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.
     1022fitQuadraticSearchForYThenReturnX(*xVec, *yVec, binNum, yVal): This routine
     1023takes psVectors of x/y pairs as input, and fits a quadratic to the 3 points
     1024surrounding element binNum in the vectors (the midpoint between element i
     1025and i+1 is used for x[i]).  It then determines for what value x does that
     1026quadratic f(x) = yVal (the input parameter).
    10421027 
    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*****************************************************************************/
     1030float 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;
    10501038    psVector* x = psVectorAlloc(3, PS_TYPE_F64);
    10511039    psVector* y = psVectorAlloc(3, PS_TYPE_F64);
    10521040    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    */
    10531056    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        }
    10711072        yErr->data.F64[0] = 1.0;
    10721073        yErr->data.F64[1] = 1.0;
    10731074        yErr->data.F64[2] = 1.0;
    10741075
     1076        // Determine the coefficients of the polynomial.
    10751077        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);
    10771081    } 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        }
    10791093    }
    10801094
     
    10831097    psFree(yErr);
    10841098    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]))
    10871104
    10881105/******************************************************************************
     
    11111128*****************************************************************************/
    11121129void 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)
    11141133{
    11151134    psHistogram* robustHistogram = NULL;
     
    11181137    int LQBinNum = -1;          // Bin num for lower quartile
    11191138    int UQBinNum = -1;          // Bin num for upper quartile
     1139    int medianBinNum = -1;
    11201140    int i = 0;                  // Loop index variable
    1121     int maxBinNum = 0;
    1122     float maxBinCount = 0.0;
     1141    int modeBinNum = 0;
     1142    float modeBinCount = 0.0;
    11231143    float dL = 0.0;
    11241144    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;
    11351145    float myMean = 0.0;
    11361146    float myStdev = 0.0;
     
    11391149    float sumSquares = 0.0;
    11401150    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;
    11471152    float sumRobust = 0.0;
    11481153    float sumN50 = 0.0;
    11491154    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);
    11511158
    11521159    // Compute the initial bin size of the robust histogram.  This is done
     
    11881195        p_psVectorMax(myVector, maskVector, maskVal, stats);
    11891196    }
     1197
    11901198    // Create the histogram structure.  NOTE: we can not specify the bin size
    11911199    // precisely since the argument to psHistogramAlloc() is the number of
     
    11981206    psVectorHistogram(robustHistogram, myVector, maskVector, maskVal);
    11991207
    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,
    12031210                            tmpStats->clippedStdev / 4.0f);
    12041211
     
    12081215
    12091216    /**************************************************************************
    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.
    12111222    **************************************************************************/
    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];
    12171225    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    }
    12451244    /**************************************************************************
    12461245    Determine the mode in the range LQ:UQ.
    12471246    **************************************************************************/
    12481247    // Determine the bin with the peak value in the range LQ to UQ.
    1249     maxBinNum = LQBinNum;
    1250     maxBinCount = 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];
    12521251    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
    12611259    dL = (UQBinNum - LQBinNum) / 4;
    1262 
    1263     printf("(LQBinNum, UQBinNum, maxBinNum) is (%d, %d, %d)\n", LQBinNum, UQBinNum, maxBinNum);
    1264 
    12651260    /**************************************************************************
    12661261    Determine the mean/stdev for the bins in the range mode-dL to mode+dL
    12671262    **************************************************************************/
    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 
    12831263    // Calculate the mean of the smoothed robust histogram in the range
    12841264    // mode-dL to mode+dL.  We use the midpoint of each bin as the mean for
    12851265    // that bin (this is a non-exact approximation).
     1266    sumNfit = 0.0;
    12861267    myMean = 0.0;
    1287     for (i = maxBinNum - dL; i <= maxBinNum + dL; i++) {
     1268    for (i = modeBinNum - dL; i <= modeBinNum + dL; i++) {
    12881269        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);
    12911271            countFloat += robustHistogramVector->data.F32[i];
    12921272        }
     1273
     1274        sumNfit += (float)robustHistogram->nums->data.U32[i];
    12931275    }
    12941276    myMean /= countFloat;
     
    12971279    // mode-dL to mode+dL.  We use the midpoint of each bin as the mean for
    12981280    // that bin.
    1299     for (i = maxBinNum - dL; i <= maxBinNum + dL; i++) {
     1281    for (i = modeBinNum - dL; i <= modeBinNum + dL; i++) {
    13001282        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;
    13031284            sumSquares += diff * diff * robustHistogramVector->data.F32[i];
    13041285            sumDiffs += diff * robustHistogramVector->data.F32[i];
     
    13151296
    13161297    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);
    13191299    }
    13201300
     
    13221302        stats->robustStdev = myStdev;
    13231303    }
    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).
    13321309    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.
    13791322    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.
    14491335    stats->robustNfit = sumNfit;
    14501336    stats->robustN50 = sumN50;
    14511337
    1452     psFree(x);
    1453     psFree(y);
    1454     psFree(yErr);
    14551338    psFree(tmpStats);
    14561339    psFree(robustHistogram);
    1457     psFree(myPoly);
    1458     psFree(cumulativeRobustSumsFullRange);
    1459     psFree(cumulativeRobustSumsDlRange);
     1340    psFree(robustHistogramVector);
     1341    psFree(cumulativeRobustSums);
    14601342}
    14611343
     
    14681350    // I am commenting this code out, and replacing it with code which
    14691351    // calculates the mean directly on the robustHistogram.
    1470     //
    1471     // XXX: Replace this with the LaGrange interpolation stuff.
    14721352 
    14731353    domain = psImageAlloc(1, robustHistogramVector->n, PS_TYPE_F32);
     
    14791359    max_pos = -1;
    14801360    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]);
    14831362        data->data.F32[i] = (float) robustHistogramVector->data.F32[i];
    14841363        errors->data.F32[i] = 1.0;
     
    16951574    psScalar tmpScalar;
    16961575    tmpScalar.type.type = PS_TYPE_F32;
     1576    psVector* inF32;
     1577    int mustFreeTmp = 1;
    16971578
    16981579    // NOTE: Verify that this is the correct action.
     
    17061587
    17071588    if (out->nums->type.type != PS_TYPE_U32) {
    1708         psAbort(__func__, "Only data type PS_TYPE_U32 for output.nums member.");
     1589        psAbort(__func__, "Only data type PS_TYPE_U32 for out->nums member.");
    17091590    }
    17101591    // NOTE: Verify that this is the correct action.
     
    17131594    }
    17141595
    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 
    17191596    if (mask != NULL) {
    17201597        if (in->n != mask->n) {
    1721             psAbort(__func__, "Vector data and vector mask are of different sizes.");
     1598            psError(__func__, "Vector data and vector mask are of different sizes.");
    17221599        }
    17231600        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;
    17261609    }
    17271610
     
    17301613
    17311614    numBins = out->nums->n;
    1732     for (i = 0; i < in->n; i++) {
     1615    for (i = 0; i < inF32->n; i++) {
    17331616        // Check if this pixel is masked, and if so, skip it.
    17341617        if ((mask == NULL) || ((mask != NULL) && (!(mask->data.U8[i] & maskVal)))) {
    17351618            // Check if this pixel is below the minimum value, and if so
    17361619            // 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]) {
    17381621                out->minNum++;
    17391622                // Check if this pixel is above the maximum value, and if so
    17401623                // 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]) {
    17421625                out->maxNum++;
    17431626            } else {
     
    17461629                if (out->uniform == true) {
    17471630                    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);
    17491632
    17501633                    // NOTE: This next if-statement really shouldn't be necessary.
     
    17551638                    }
    17561639
    1757                     (out->nums->data.S32[binNum])++;
     1640                    (out->nums->data.U32[binNum])++;
    17581641
    17591642                    // If this is a non-uniform histogram, determining the correct
    17601643                    // bin number requires a bit more work.
    17611644                } 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
    17671649                    } else {
    1768                         (out->nums->data.S32[tmp])++;
     1650                        (out->nums->data.U32[tmp])++;
    17691651                    }
    17701652                }
     
    17721654        }
    17731655    }
     1656
     1657    if (mustFreeTmp == 1) {
     1658        psFree(inF32);
     1659    }
    17741660    return (out);
    17751661}
    17761662
    17771663/******************************************************************************
    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.
     1664p_psConvertToF32(in): this is the cheap way to support a variety of vector
     1665data types: we simply convert the input vector to F32 at the beginning, and
     1666write all of our functions in F32.  If the vast majority of all vector stat
     1667operations are F32 (or any other single type), then this is probably the
     1668best way to go.  Otherwise, when the algorithms stablize, we will then macro
     1669everything and put type support in the various stat functions.
    17851670 
    17861671XXX: Should the default data type be F64?  Since we are buying Athlons...
    17871672 *****************************************************************************/
    1788 psVector* p_psConvertToF32(psStats* stats, psVector* in, psVector* mask, unsigned int maskVal)
     1673psVector* p_psConvertToF32(psVector* in)
    17891674{
    17901675    int i = 0;
     
    18001685        for (i = 0; i < in->n; i++) {
    18011686            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];
    18021692        }
    18031693    } else if (in->type.type == PS_TYPE_F64) {
     
    18391729    int mustFreeTmp = 1;
    18401730
    1841     // NOTE: Verify that this is the correct action.
    18421731    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);
    18501738    if (inF32 == NULL) {
    18511739        inF32 = in;
    18521740        mustFreeTmp = 0;
    18531741    }
    1854     // XXX: Should we abort if (stats->min == stats->max)?
    18551742    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);
    18571745    }
    18581746
  • trunk/psLib/src/math/psConstants.h

    r2136 r2197  
    66 *  @author GLG, MHPCC
    77 *
    8  *  @version $Revision: 1.12 $ $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 $
    1010 *
    1111 *  Copyright 2004 Maui High Performance Computing Center, University of Hawaii
     
    107107} \
    108108
     109/** Preprocessor macro to generate error on a NULL vector */
     110#define PS_CHECK_NULL_VECTOR_RETURN_F0(NAME) \
     111if (NAME == NULL || NAME->data.V == NULL) { \
     112    psError(__func__,"Unallowable operation: %s or its data is NULL.", #NAME); \
     113    return(0.0); \
     114} \
     115
    109116/** Preprocessor macro to generate error on a NULL poniter */
    110117#define PS_CHECK_NULL_PTR_RETURN_NULL(NAME) \
     
    113120    return(NULL); \
    114121}
     122
     123/** Preprocessor macro to generate error on a NULL poniter */
     124#define PS_CHECK_NULL_PTR_RETURN_F0(NAME) \
     125if (NAME == NULL) { \
     126    psError(__func__,"Unallowable operation: %s is NULL.", #NAME); \
     127    return(0.0); \
     128}
     129
    115130/** Preprocessor macro to generate error on a NULL poniter */
    116131#define PS_CHECK_NULL_PTR_RETURN_ZERO(NAME) \
     
    127142} \
    128143
     144/** Preprocessor macro to generate error for zero length vector */
     145#define PS_CHECK_EMPTY_VECTOR_RETURN_F0(NAME) \
     146if (NAME->n < 1) { \
     147    psError(__func__,"Unallowable operation: %s has zero n value.", #NAME); \
     148    return(0.0); \
     149} \
     150
    129151/** Preprocessor macro to generate error on differing size vectors */
    130152#define PS_CHECK_VECTOR_SIZE_EQUAL_RETURN_NULL(VEC1, VEC2) \
     
    132154    psError(__func__,"Vector %s has size %d, Vector %s has size %d.", #VEC1, VEC1->n, #VEC2, VEC2->n); \
    133155    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) \
     160if (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); \
    134163}
    135164
     
    199228
    200229#define PS_MAX(A, B) \
    201 ((A > B) ? A : B) \
     230(((A) > (B)) ? (A) : (B)) \
    202231
    203232#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  
    99 *  @author GLF, MHPCC
    1010 *
    11  *  @version $Revision: 1.58 $ $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 $
    1313 *
    1414 *  Copyright 2004 Maui High Performance Computing Center, University of Hawaii
     
    636636    psFree(currValueVec);
    637637    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/******************************************************************************
     650psMyMinimizeLMChi2():  This routine will take an procedure which calculates
     651an arbitrary function and it's derivative and minimize the chi-squared match
     652between that function at the specified coords and the specified value at
     653those coords.
     654 
     655XXX: 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 
     661XXX: This is very different from what is specified in the SDR.  Must
     662coordinate with IfA on new SDR.
     663 
     664XXX: Do vector/image recycles.
     665 
     666XXX: probably yErr will be part of the SDR.
     667 
     668XXX: 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 *****************************************************************************/
     673bool 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);
    638895
    639896    if ((min->iter < min->maxIter) ||
  • trunk/psLib/src/math/psMinimize.h

    r1992 r2197  
    88 *  @author GLG, MHPCC
    99 *
    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 $
    1212 *
    1313 *  Copyright 2004 Maui High Performance Computing Center, University of Hawaii
     
    8484
    8585
     86/*
     87   Bug 203:
     88 
     89typedef float (*psMinimizeLMChi2Func)(psVector *deriv, const psVector *params,
     90const psVector *x);
     91 
     92This function takes the current guess for the parameters for which we are
     93trying to get the best values (params), and a single vector (x) of
     94conditions 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 
     105This takes the minimization specs (min), returns the covariance matrix
     106(covar), takes the best guess of initial parameters (params), the parameter
     107mask (paramMask), and takes multiple vectors of conditions in an array (x),
     108the corresponding measured values (y) and errors (yErr) and the function to
     109fit (func).
     110 
     111For example, for GRB afterglows, I have flux as a function of time and
     112frequency.  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
     114errors in "yErr".  Then each of the time-frequency pairs are passed to my model
     115function with the current parameters, and the model function returns the flux
     116for that time-frequency pair, and the derivative with respect to each of the
     117parameters.
     118 
     119This seems reasonable.  The only thing we could change would be to have the
     120function be defined:
     121 
     122typedef psVector* (*psMinimizeLMChi2Func)(psImage *deriv,
     123                                          const psVector *params,
     124                                          const psArray *x);
     125 
     126So it would return the model value for each of the measurements at once, and
     127return for each the derivatives (so that it returns a matrix).
     128 
     129What do you think?
     130 
     131 
     132 
     133I'm not sure I understand how LM chi-squared minimization will work with the
     134following function that you define:
     135 
     136    typedef psVector* (*psMinimizeLMChi2Func)(psImage *deriv,
     137                                              const psVector *params,
     138                                              const psArray *x);
     139 
     140The chi-squared minimization algorithm, as defined in NR, requires that
     141function to be minimized be evaluated at each data point, and that all
     142derivatives, with respect to each parameter, be calculated at each data
     143point.  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
    86161// XXX: What if any of these arguments are NULL?
     162
     163
    87164typedef
    88165float (*psMinimizeLMChi2Func)(psVector *deriv,
     
    98175                      psMinimizeLMChi2Func func);
    99176
     177
     178typedef
     179psVector* (*psMyMinimizeLMChi2Func)(psImage *deriv,
     180                                    const psVector *params,
     181                                    const psArray *x);
     182
     183bool 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
    100192typedef
    101193float (*psMinimizePowellFunc)(const psVector *params,
  • trunk/psLib/src/math/psPolynomial.c

    r2106 r2197  
    77 *  polynomials.  It also contains a Gaussian functions.
    88 *
    9  *  @version $Revision: 1.52 $ $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 $
    1111 *
    1212 *  Copyright 2004 Maui High Performance Computing Center, University of Hawaii
  • trunk/psLib/src/math/psSpline.c

    r2106 r2197  
    77 *  polynomials.  It also contains a Gaussian functions.
    88 *
    9  *  @version $Revision: 1.52 $ $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 $
    1111 *
    1212 *  Copyright 2004 Maui High Performance Computing Center, University of Hawaii
  • trunk/psLib/src/math/psStats.c

    r2074 r2197  
    99 *  @author GLG, MHPCC
    1010 *
    11  *  @version $Revision: 1.67 $ $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 $
    1313 *
    1414 *  Copyright 2004 Maui High Performance Computing Center, University of Hawaii
     
    4040/*****************************************************************************/
    4141// 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.
    4343#define CLIPPED_NUM_ITER_LB 1
    4444#define CLIPPED_NUM_ITER_UB 10
     
    5757/* TYPE DEFINITIONS                                                          */
    5858/*****************************************************************************/
     59psVector* p_psConvertToF32(psVector* in);
    5960
    6061/*****************************************************************************/
     
    423424    float rangeMax = 0.0;       // Exclude date above this
    424425
    425     // Determine if the number of data points exceed a threshold which will
    426     // cause to generate robust stats, as opposed to exact stats.
    427     // XXX: This code is no longer used.  We now calculate the median exactly
    428     // 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 
    443426    // Determine how many data points fit inside this min/max range
    444427    // and are not masked, IF the maskVector is not NULL>
     
    507490
    508491/******************************************************************************
    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,
     492p_psVectorSmoothHistGaussian(): This routine smoothes the data in the input
     493robustHistogram with a Gaussian of width sigma.
     494 *****************************************************************************/
     495#define GAUSS_WIDTH_OTHER 5.0
     496psVector* p_psVectorSmoothHistGaussian(psHistogram* robustHistogram,
    521497                                       float sigma)
    522498{
    523499    int i = 0;                  // Loop index variable
    524500    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
    563543        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);
    572554}
    573555
     
    913895specified data point.
    914896 *****************************************************************************/
    915 float p_psGaussian(const psVector* restrict myData, const psVector* restrict myParams)
     897float p_psGaussian(const psVector* restrict myData,
     898                   const psVector* restrict myParams)
    916899{
    917900    float x = myData->data.F32[0];
     
    930913calculates the specified partial derivative of the above Gaussian function.
    931914 *****************************************************************************/
    932 float p_psGaussianDeriv(const psVector* restrict myData, const psVector* restrict myParams, int whichParam)
     915float p_psGaussianDeriv(const psVector* restrict myData,
     916                        const psVector* restrict myParams, int whichParam)
    933917{
    934918    float x = myData->data.F32[0];
     
    10361020
    10371021/******************************************************************************
    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.
     1022fitQuadraticSearchForYThenReturnX(*xVec, *yVec, binNum, yVal): This routine
     1023takes psVectors of x/y pairs as input, and fits a quadratic to the 3 points
     1024surrounding element binNum in the vectors (the midpoint between element i
     1025and i+1 is used for x[i]).  It then determines for what value x does that
     1026quadratic f(x) = yVal (the input parameter).
    10421027 
    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*****************************************************************************/
     1030float 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;
    10501038    psVector* x = psVectorAlloc(3, PS_TYPE_F64);
    10511039    psVector* y = psVectorAlloc(3, PS_TYPE_F64);
    10521040    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    */
    10531056    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        }
    10711072        yErr->data.F64[0] = 1.0;
    10721073        yErr->data.F64[1] = 1.0;
    10731074        yErr->data.F64[2] = 1.0;
    10741075
     1076        // Determine the coefficients of the polynomial.
    10751077        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);
    10771081    } 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        }
    10791093    }
    10801094
     
    10831097    psFree(yErr);
    10841098    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]))
    10871104
    10881105/******************************************************************************
     
    11111128*****************************************************************************/
    11121129void 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)
    11141133{
    11151134    psHistogram* robustHistogram = NULL;
     
    11181137    int LQBinNum = -1;          // Bin num for lower quartile
    11191138    int UQBinNum = -1;          // Bin num for upper quartile
     1139    int medianBinNum = -1;
    11201140    int i = 0;                  // Loop index variable
    1121     int maxBinNum = 0;
    1122     float maxBinCount = 0.0;
     1141    int modeBinNum = 0;
     1142    float modeBinCount = 0.0;
    11231143    float dL = 0.0;
    11241144    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;
    11351145    float myMean = 0.0;
    11361146    float myStdev = 0.0;
     
    11391149    float sumSquares = 0.0;
    11401150    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;
    11471152    float sumRobust = 0.0;
    11481153    float sumN50 = 0.0;
    11491154    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);
    11511158
    11521159    // Compute the initial bin size of the robust histogram.  This is done
     
    11881195        p_psVectorMax(myVector, maskVector, maskVal, stats);
    11891196    }
     1197
    11901198    // Create the histogram structure.  NOTE: we can not specify the bin size
    11911199    // precisely since the argument to psHistogramAlloc() is the number of
     
    11981206    psVectorHistogram(robustHistogram, myVector, maskVector, maskVal);
    11991207
    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,
    12031210                            tmpStats->clippedStdev / 4.0f);
    12041211
     
    12081215
    12091216    /**************************************************************************
    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.
    12111222    **************************************************************************/
    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];
    12171225    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    }
    12451244    /**************************************************************************
    12461245    Determine the mode in the range LQ:UQ.
    12471246    **************************************************************************/
    12481247    // Determine the bin with the peak value in the range LQ to UQ.
    1249     maxBinNum = LQBinNum;
    1250     maxBinCount = 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];
    12521251    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
    12611259    dL = (UQBinNum - LQBinNum) / 4;
    1262 
    1263     printf("(LQBinNum, UQBinNum, maxBinNum) is (%d, %d, %d)\n", LQBinNum, UQBinNum, maxBinNum);
    1264 
    12651260    /**************************************************************************
    12661261    Determine the mean/stdev for the bins in the range mode-dL to mode+dL
    12671262    **************************************************************************/
    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 
    12831263    // Calculate the mean of the smoothed robust histogram in the range
    12841264    // mode-dL to mode+dL.  We use the midpoint of each bin as the mean for
    12851265    // that bin (this is a non-exact approximation).
     1266    sumNfit = 0.0;
    12861267    myMean = 0.0;
    1287     for (i = maxBinNum - dL; i <= maxBinNum + dL; i++) {
     1268    for (i = modeBinNum - dL; i <= modeBinNum + dL; i++) {
    12881269        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);
    12911271            countFloat += robustHistogramVector->data.F32[i];
    12921272        }
     1273
     1274        sumNfit += (float)robustHistogram->nums->data.U32[i];
    12931275    }
    12941276    myMean /= countFloat;
     
    12971279    // mode-dL to mode+dL.  We use the midpoint of each bin as the mean for
    12981280    // that bin.
    1299     for (i = maxBinNum - dL; i <= maxBinNum + dL; i++) {
     1281    for (i = modeBinNum - dL; i <= modeBinNum + dL; i++) {
    13001282        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;
    13031284            sumSquares += diff * diff * robustHistogramVector->data.F32[i];
    13041285            sumDiffs += diff * robustHistogramVector->data.F32[i];
     
    13151296
    13161297    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);
    13191299    }
    13201300
     
    13221302        stats->robustStdev = myStdev;
    13231303    }
    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).
    13321309    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.
    13791322    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.
    14491335    stats->robustNfit = sumNfit;
    14501336    stats->robustN50 = sumN50;
    14511337
    1452     psFree(x);
    1453     psFree(y);
    1454     psFree(yErr);
    14551338    psFree(tmpStats);
    14561339    psFree(robustHistogram);
    1457     psFree(myPoly);
    1458     psFree(cumulativeRobustSumsFullRange);
    1459     psFree(cumulativeRobustSumsDlRange);
     1340    psFree(robustHistogramVector);
     1341    psFree(cumulativeRobustSums);
    14601342}
    14611343
     
    14681350    // I am commenting this code out, and replacing it with code which
    14691351    // calculates the mean directly on the robustHistogram.
    1470     //
    1471     // XXX: Replace this with the LaGrange interpolation stuff.
    14721352 
    14731353    domain = psImageAlloc(1, robustHistogramVector->n, PS_TYPE_F32);
     
    14791359    max_pos = -1;
    14801360    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]);
    14831362        data->data.F32[i] = (float) robustHistogramVector->data.F32[i];
    14841363        errors->data.F32[i] = 1.0;
     
    16951574    psScalar tmpScalar;
    16961575    tmpScalar.type.type = PS_TYPE_F32;
     1576    psVector* inF32;
     1577    int mustFreeTmp = 1;
    16971578
    16981579    // NOTE: Verify that this is the correct action.
     
    17061587
    17071588    if (out->nums->type.type != PS_TYPE_U32) {
    1708         psAbort(__func__, "Only data type PS_TYPE_U32 for output.nums member.");
     1589        psAbort(__func__, "Only data type PS_TYPE_U32 for out->nums member.");
    17091590    }
    17101591    // NOTE: Verify that this is the correct action.
     
    17131594    }
    17141595
    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 
    17191596    if (mask != NULL) {
    17201597        if (in->n != mask->n) {
    1721             psAbort(__func__, "Vector data and vector mask are of different sizes.");
     1598            psError(__func__, "Vector data and vector mask are of different sizes.");
    17221599        }
    17231600        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;
    17261609    }
    17271610
     
    17301613
    17311614    numBins = out->nums->n;
    1732     for (i = 0; i < in->n; i++) {
     1615    for (i = 0; i < inF32->n; i++) {
    17331616        // Check if this pixel is masked, and if so, skip it.
    17341617        if ((mask == NULL) || ((mask != NULL) && (!(mask->data.U8[i] & maskVal)))) {
    17351618            // Check if this pixel is below the minimum value, and if so
    17361619            // 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]) {
    17381621                out->minNum++;
    17391622                // Check if this pixel is above the maximum value, and if so
    17401623                // 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]) {
    17421625                out->maxNum++;
    17431626            } else {
     
    17461629                if (out->uniform == true) {
    17471630                    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);
    17491632
    17501633                    // NOTE: This next if-statement really shouldn't be necessary.
     
    17551638                    }
    17561639
    1757                     (out->nums->data.S32[binNum])++;
     1640                    (out->nums->data.U32[binNum])++;
    17581641
    17591642                    // If this is a non-uniform histogram, determining the correct
    17601643                    // bin number requires a bit more work.
    17611644                } 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
    17671649                    } else {
    1768                         (out->nums->data.S32[tmp])++;
     1650                        (out->nums->data.U32[tmp])++;
    17691651                    }
    17701652                }
     
    17721654        }
    17731655    }
     1656
     1657    if (mustFreeTmp == 1) {
     1658        psFree(inF32);
     1659    }
    17741660    return (out);
    17751661}
    17761662
    17771663/******************************************************************************
    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.
     1664p_psConvertToF32(in): this is the cheap way to support a variety of vector
     1665data types: we simply convert the input vector to F32 at the beginning, and
     1666write all of our functions in F32.  If the vast majority of all vector stat
     1667operations are F32 (or any other single type), then this is probably the
     1668best way to go.  Otherwise, when the algorithms stablize, we will then macro
     1669everything and put type support in the various stat functions.
    17851670 
    17861671XXX: Should the default data type be F64?  Since we are buying Athlons...
    17871672 *****************************************************************************/
    1788 psVector* p_psConvertToF32(psStats* stats, psVector* in, psVector* mask, unsigned int maskVal)
     1673psVector* p_psConvertToF32(psVector* in)
    17891674{
    17901675    int i = 0;
     
    18001685        for (i = 0; i < in->n; i++) {
    18011686            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];
    18021692        }
    18031693    } else if (in->type.type == PS_TYPE_F64) {
     
    18391729    int mustFreeTmp = 1;
    18401730
    1841     // NOTE: Verify that this is the correct action.
    18421731    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);
    18501738    if (inF32 == NULL) {
    18511739        inF32 = in;
    18521740        mustFreeTmp = 0;
    18531741    }
    1854     // XXX: Should we abort if (stats->min == stats->max)?
    18551742    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);
    18571745    }
    18581746
  • trunk/psLib/test/dataManip/tst_psMinimize06.c

    r1992 r2197  
    7474}
    7575
    76 
    77 int main()
     76psVector *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
     104int 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
     167int t02()
    78168{
    79169    int currentId = psMemGetId();
     
    85175    psImage *myCovar;
    86176    psMinimization *min;
    87     psVector *x = psVectorAlloc(N, PS_TYPE_F32);
    88177    psVector *y = psVectorAlloc(N, PS_TYPE_F32);
    89178
    90179    psTraceSetLevel(".psLib", 0);
     180    t02();
    91181    /**************************************************************************
    92182     *************************************************************************/
     
    101191        ((psVector *) (myCoords->data[i]))->data.F32[0] = (float) (i+10);
    102192        ((psVector *) (myCoords->data[i]))->data.F32[1] = (float) (i+3);
    103         x->data.F32[i] = (float) i;
    104193        y->data.F32[i] = (float) i;
    105194    }
     
    131220    psFree(myParamMask);
    132221    psFree(min);
    133     psFree(x);
    134222    psFree(y);
    135223    psFree(myCovar);
     
    142230    return (!testStatus);
    143231}
     232
     233int main()
     234{
     235    t01();
     236    //    t02();
     237}
  • trunk/psLib/test/dataManip/tst_psStats07.c

    r1900 r2197  
    1010#include <math.h>
    1111
    12 #define N 200
     12#define N 90
    1313#define MEAN 32.0
    1414#define STDEV 2.0
    1515#define ERROR_TOLERANCE 0.10
    1616
    17 int main()
     17int t00()
    1818{
    1919    psStats * myStats = NULL;
     
    3232    float realMedianNoMask = MEAN;
    3333    float realModeNoMask = MEAN;
    34     float realStdevNoMask = STDEV * 0.33;
     34    float realStdevNoMask = STDEV * 0.20;
    3535    float realLQNoMask = MEAN - ( 0.6 * STDEV );
    3636    float realUQNoMask = MEAN + ( 0.6 * STDEV );
    3737    int realN50NoMask = N / 4;
    3838    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);
    4841
    4942    /*************************************************************************/
     
    232225                 "PS_STAT_ROBUST_STATS: robust Nfit: no vector mask",
    233226                 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
     255int 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    }
    237301
    238302    /*************************************************************************/
     
    422486    return ( !globalTestStatus );
    423487}
     488
     489int main()
     490{
     491    t00();
     492    t01();
     493}
Note: See TracChangeset for help on using the changeset viewer.