IPP Software Navigation Tools IPP Links Communication Pan-STARRS Links

Changeset 7132


Ignore:
Timestamp:
May 17, 2006, 3:20:51 PM (20 years ago)
Author:
Paul Price
Message:

Cleaning up code in psStats.c and psMathUtils.[ch]

Location:
trunk/psLib/src/math
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/psLib/src/math/psMathUtils.c

    r6305 r7132  
    11/** @file psMathUtils.c
    22 *
    3  *  This file contains standard math rotines.
     3 *  This file contains standard math routines.
    44 *
    5  *  @version $Revision: 1.1 $ $Name: not supported by cvs2svn $
    6  *  @date $Date: 2006-02-02 21:09:07 $
     5 *  @version $Revision: 1.2 $ $Name: not supported by cvs2svn $
     6 *  @date $Date: 2006-05-18 01:20:51 $
    77 *
    88 *  Copyright 2004-2005 Maui High Performance Computing Center, University of Hawaii
     
    4848
    4949/*****************************************************************************
    50 vectorBinDisectTYPE(): This is a macro for a private function which takes as
    51 input an array of data as well as a single value for that data.  The input
    52 vector values are assumed to be non-decreasing (v[i-1] <= v[i] for all i).
    53 This routine does a binary disection of the vector and returns "i" such that
    54 (v[i] <= x <= v[i+1).  If x lies outside the range of v[], then this routine
    55 prints a warning message and returns (-2 or -1).
     50This is a macro covering the various types for the below function.
    5651 *****************************************************************************/
    57 #define FUNC_MACRO_VECTOR_BIN_DISECT(TYPE) \
    58 static psS32 vectorBinDisect##TYPE(ps##TYPE *bins, \
    59                                    psS32 numBins, \
    60                                    ps##TYPE x) \
    61 { \
    62     psS32 min; \
    63     psS32 max; \
    64     psS32 mid; \
     52#define VECTOR_BIN_DISECT_CASE(TYPE) \
     53case PS_TYPE_##TYPE: { \
     54    ps##TYPE *bounds = bins->data.TYPE; \
     55    ps##TYPE value = x->data.TYPE; \
     56    long min; \
     57    long max; \
     58    long mid; \
    6559    psTrace(__func__, 4, "---- %s() begin ----\n", __func__); \
    6660    /* psTrace(__func__, 6, "Determining the bin for: %f\n", x); */\
    67     if (x < bins[0]) { \
     61    if (value < bounds[0]) { \
    6862        psLogMsg(__func__, PS_LOG_WARN, \
    6963                 "vectorBinDisect%s(): ordinate %f is outside vector range (%f - %f).", \
    70                  #TYPE, x, bins[0], bins[numBins-1]); \
     64                 #TYPE, value, bounds[0], bounds[numBins-1]); \
    7165        return(-2); \
    7266    } \
    73     if (x > bins[numBins-1]) { \
     67    if (value > bounds[numBins-1]) { \
    7468        psLogMsg(__func__, PS_LOG_WARN, \
    7569                 "vectorBinDisect%s(): ordinate %f is outside vector range (%f - %f).", \
    76                  #TYPE, x, bins[0], bins[numBins-1]); \
     70                 #TYPE, value, bounds[0], bounds[numBins-1]); \
    7771        return(-1); \
    7872    } \
     
    8276    mid = ((max+1)-min)/2; \
    8377    while (min != max) { \
    84         /*psTrace(__func__, 6, "(min, mid, max) is (%u, %u, %u): (x, bins[mid]) is (%f, %f)\n", min, mid, max, x, bins[mid]); */\
    8578        \
    86         if (x == bins[mid]) { \
    87             /*psTrace(__func__, 6, "%.2f should be in this range (%.2f - %.2f)\n", x, bins[mid], bins[mid+1]); */\
     79        if (value == bounds[mid]) { \
    8880            psTrace(__func__, 4, "---- %s(%d) end (1) ----\n", __func__, mid); \
    8981            return(mid); \
    90         } else if (x < bins[mid]) { \
     82        } else if (value < bounds[mid]) { \
    9183            max = mid-1; \
    9284        } else { \
     
    9587        mid = ((max+1)+min)/2; \
    9688    } \
    97     /*psTrace(__func__, 6, "%.2f should be in this range (%.2f - %.2f)\n", x, bins[min], bins[min+1]);*/ \
    9889    psTrace(__func__, 4, "---- %s(%d) end (2) ----\n", __func__, min); \
    9990    return(min); \
    100 } \
    101 
    102 FUNC_MACRO_VECTOR_BIN_DISECT(S8)
    103 FUNC_MACRO_VECTOR_BIN_DISECT(S16)
    104 FUNC_MACRO_VECTOR_BIN_DISECT(S32)
    105 FUNC_MACRO_VECTOR_BIN_DISECT(S64)
    106 FUNC_MACRO_VECTOR_BIN_DISECT(U8)
    107 FUNC_MACRO_VECTOR_BIN_DISECT(U16)
    108 FUNC_MACRO_VECTOR_BIN_DISECT(U32)
    109 FUNC_MACRO_VECTOR_BIN_DISECT(U64)
    110 FUNC_MACRO_VECTOR_BIN_DISECT(F32)
    111 FUNC_MACRO_VECTOR_BIN_DISECT(F64)
     91}
    11292
    11393/*****************************************************************************
    114 p_psVectorBinDisect(): A wrapper to the above p_psVectorBinDisect().
     94p_psVectorBinDisect(): This function takes as input an array of data as well as a single value for that data.
     95The input vector values are assumed to be non-decreasing (v[i-1] <= v[i] for all i).  This routine does a
     96binary disection of the vector and returns "i" such that (v[i] <= x <= v[i+1).  If x lies outside the range of
     97v[], then this routine prints a warning message and returns (-2 or -1).
    11598  *****************************************************************************/
    11699psS32 p_psVectorBinDisect(
    117     psVector *bins,
    118     psScalar *x)
     100    const psVector *bins,
     101    const psScalar *x)
    119102{
    120103    PS_ASSERT_VECTOR_NON_NULL(bins, -4);
     
    122105    PS_ASSERT_PTR_NON_NULL(x, -6);
    123106    PS_ASSERT_PTR_TYPE_EQUAL(x, bins, -3);
    124     char* strType;
     107    long numBins = bins->n;             // Number of bins
    125108
    126109    switch (x->type.type) {
    127     case PS_TYPE_U8:
    128         return(vectorBinDisectU8(bins->data.U8, bins->n, x->data.U8));
    129     case PS_TYPE_U16:
    130         return(vectorBinDisectU16(bins->data.U16, bins->n, x->data.U16));
    131     case PS_TYPE_U32:
    132         return(vectorBinDisectU32(bins->data.U32, bins->n, x->data.U32));
    133     case PS_TYPE_U64:
    134         return(vectorBinDisectU64(bins->data.U64, bins->n, x->data.U64));
    135     case PS_TYPE_S8:
    136         return(vectorBinDisectS8(bins->data.S8, bins->n, x->data.S8));
    137     case PS_TYPE_S16:
    138         return(vectorBinDisectS16(bins->data.S16, bins->n, x->data.S16));
    139     case PS_TYPE_S32:
    140         return(vectorBinDisectS32(bins->data.S32, bins->n, x->data.S32));
    141     case PS_TYPE_S64:
    142         return(vectorBinDisectS64(bins->data.S64, bins->n, x->data.S64));
    143     case PS_TYPE_F32:
    144         return(vectorBinDisectF32(bins->data.F32, bins->n, x->data.F32));
    145     case PS_TYPE_F64:
    146         return(vectorBinDisectF64(bins->data.F64, bins->n, x->data.F64));
    147     default:
    148         PS_TYPE_NAME(strType, x->type.type);
    149         psError(PS_ERR_BAD_PARAMETER_TYPE, "psLib type %s is not supported.", strType);
    150         return -1;
     110        VECTOR_BIN_DISECT_CASE(S8);
     111        VECTOR_BIN_DISECT_CASE(S16);
     112        VECTOR_BIN_DISECT_CASE(S32);
     113        VECTOR_BIN_DISECT_CASE(S64);
     114        VECTOR_BIN_DISECT_CASE(U8);
     115        VECTOR_BIN_DISECT_CASE(U16);
     116        VECTOR_BIN_DISECT_CASE(U32);
     117        VECTOR_BIN_DISECT_CASE(U64);
     118        VECTOR_BIN_DISECT_CASE(F32);
     119        VECTOR_BIN_DISECT_CASE(F64);
     120    default: {
     121            char* strType;
     122            PS_TYPE_NAME(strType, x->type.type);
     123            psError(PS_ERR_BAD_PARAMETER_TYPE, "psLib type %s is not supported.", strType);
     124            return -1;
     125        }
    151126    }
    152127    return(-3);
     
    154129
    155130
    156 
    157 /*****************************************************************************
    158 fullInterpolateTYPE(): This routine will take as input n-element psVectors
    159 domain and range, and the x value, assumed to lie with the domain vector.  It
    160 produces as output the (order-1)-order LaGrange interpolated value of x.
    161  
    162 XXX: do we error check for non-distinct domain values?
    163  
    164 This routine will only be called inside this file.  So, we do not have to
    165 do PS_ASSERTS.
    166  *****************************************************************************/
    167 #define FUNC_MACRO_FULL_INTERPOLATE(TYPE) \
    168 static psScalar *vectorInterpolate##TYPE( \
    169         psScalar *out, \
    170         psVector *domain, \
    171         psVector *range, \
    172         psS32 order, \
    173         psScalar *x) \
    174 { \
     131/*************************************************************************************************************
     132Helper macro for p_psVectorInterpolate: handles each of the types
     133*************************************************************************************************************/
     134#define VECTOR_INTERPOLATE_CASE(TYPE) \
     135case PS_TYPE_##TYPE: { \
    175136    psTrace(__func__, 4, "---- %s() begin %u-order.) (%d data points) ----\n", __func__, order, order+1); \
    176137    if (x->data.TYPE < domain->data.TYPE[0]) { \
     
    213174    psTrace(__func__, 4, "---- %s(....) end ----\n", __func__); \
    214175    return(out); \
    215 } \
    216 
    217 FUNC_MACRO_FULL_INTERPOLATE(U8)
    218 FUNC_MACRO_FULL_INTERPOLATE(U16)
    219 FUNC_MACRO_FULL_INTERPOLATE(U32)
    220 FUNC_MACRO_FULL_INTERPOLATE(U64)
    221 FUNC_MACRO_FULL_INTERPOLATE(S8)
    222 FUNC_MACRO_FULL_INTERPOLATE(S16)
    223 FUNC_MACRO_FULL_INTERPOLATE(S32)
    224 FUNC_MACRO_FULL_INTERPOLATE(S64)
    225 FUNC_MACRO_FULL_INTERPOLATE(F32)
    226 FUNC_MACRO_FULL_INTERPOLATE(F64)
     176}
    227177
    228178/*****************************************************************************
     
    236186psScalar *p_psVectorInterpolate(
    237187    psScalar *out,
    238     psVector *domain,
    239     psVector *range,
     188    const psVector *domain,
     189    const psVector *range,
    240190    psS32 order,
    241     psScalar *x)
     191    const psScalar *x)
    242192{
    243193    psTrace(__func__, 4, "---- %s() begin ----\n", __func__);
     
    249199    PS_ASSERT_PTR_TYPE_EQUAL(domain, range, NULL);
    250200    PS_ASSERT_PTR_TYPE_EQUAL(domain, x, NULL);
    251     if (out == NULL) {
     201    if (!out) {
    252202        out = psScalarAlloc(0, x->type.type);
    253203    } else {
    254204        PS_ASSERT_PTR_TYPE_EQUAL(domain, out, NULL);
    255205    }
    256     char* strType;
    257206
    258207    switch (x->type.type) {
    259     case PS_TYPE_U8:
    260         return(vectorInterpolateU8(out, domain, range, order, x));
    261     case PS_TYPE_U16:
    262         return(vectorInterpolateU16(out, domain, range, order, x));
    263     case PS_TYPE_U32:
    264         return(vectorInterpolateU32(out, domain, range, order, x));
    265     case PS_TYPE_U64:
    266         return(vectorInterpolateU64(out, domain, range, order, x));
    267     case PS_TYPE_S8:
    268         return(vectorInterpolateS8(out, domain, range, order, x));
    269     case PS_TYPE_S16:
    270         return(vectorInterpolateS16(out, domain, range, order, x));
    271     case PS_TYPE_S32:
    272         return(vectorInterpolateS32(out, domain, range, order, x));
    273     case PS_TYPE_S64:
    274         return(vectorInterpolateS64(out, domain, range, order, x));
    275     case PS_TYPE_F32:
    276         return(vectorInterpolateF32(out, domain, range, order, x));
    277     case PS_TYPE_F64:
    278         return(vectorInterpolateF64(out, domain, range, order, x));
    279     default:
    280         PS_TYPE_NAME(strType, x->type.type);
    281         psError(PS_ERR_BAD_PARAMETER_TYPE, "psLib type %s is not supported.", strType);
    282         return NULL;
     208        VECTOR_INTERPOLATE_CASE(U8);
     209        VECTOR_INTERPOLATE_CASE(U16);
     210        VECTOR_INTERPOLATE_CASE(U32);
     211        VECTOR_INTERPOLATE_CASE(U64);
     212        VECTOR_INTERPOLATE_CASE(S8);
     213        VECTOR_INTERPOLATE_CASE(S16);
     214        VECTOR_INTERPOLATE_CASE(S32);
     215        VECTOR_INTERPOLATE_CASE(S64);
     216        VECTOR_INTERPOLATE_CASE(F32);
     217        VECTOR_INTERPOLATE_CASE(F64);
     218    default: {
     219            char* strType;
     220            PS_TYPE_NAME(strType, x->type.type);
     221            psError(PS_ERR_BAD_PARAMETER_TYPE, "psLib type %s is not supported.", strType);
     222            return NULL;
     223        }
    283224    }
    284225
     
    287228
    288229/*****************************************************************************
    289 These macros and functions define the following functions:
    290  
    291     p_psNormalizeVectorRange(myData, low, high)
    292  
    293 That assumes that the low/high arguments are PS_TYPE_F64; the vector myData
    294 can be of any type.  Arguments low/high will be converted to the appropriate
    295 type and one of the type-specific functions below will be called:
    296  
    297     p_psNormalizeVectorRangeU8(myData, low, high)
    298     p_psNormalizeVectorRangeU16(myData, low, high)
    299     p_psNormalizeVectorRangeU32(myData, low, high)
    300     p_psNormalizeVectorRangeU64(myData, low, high)
    301     p_psNormalizeVectorRangeS8(myData, low, high)
    302     p_psNormalizeVectorRangeS16(myData, low, high)
    303     p_psNormalizeVectorRangeS32(myData, low, high)
    304     p_psNormalizeVectorRangeS64(myData, low, high)
    305     p_psNormalizeVectorRangeF32(myData, low, high)
    306     p_psNormalizeVectorRangeF64(myData, low, high)
     230Helper macro for p_psNormalizeVectorRange: handles each of the types
    307231 *****************************************************************************/
    308 #define PS_FUNC_MACRO_NORMALIZE_VECTOR_RANGE(TYPE) \
    309 static void p_psNormalizeVectorRange##TYPE( \
    310         psVector* myData, \
    311         ps##TYPE outLow, \
    312         ps##TYPE outHigh) \
    313 { \
    314     ps##TYPE min = (ps##TYPE) PS_MAX_##TYPE; \
    315     ps##TYPE max = (ps##TYPE) -PS_MAX_##TYPE; \
    316     psS32 i = 0; \
    317     \
    318     for (i = 0; i < myData->n; i++) { \
     232#define NORMALIZE_VECTOR_RANGE_CASE(TYPE) \
     233case PS_TYPE_##TYPE: { \
     234    ps##TYPE low = outLow; \
     235    ps##TYPE high = outHigh; \
     236    ps##TYPE min = (ps##TYPE)PS_MAX_##TYPE; \
     237    ps##TYPE max = (ps##TYPE)-PS_MAX_##TYPE; \
     238    \
     239    for (long i = 0; i < myData->n; i++) { \
    319240        if (myData->data.TYPE[i] < min) { \
    320241            min = myData->data.TYPE[i]; \
     
    327248    /* Ensure that max!=min before we divide by (max-min) */ \
    328249    if (max != min) { \
    329         for (i = 0; i < myData->n; i++) { \
    330             myData->data.TYPE[i] = (outLow + (myData->data.TYPE[i] - min) * \
    331                                     (outHigh - outLow) / (max - min)); \
     250        for (long i = 0; i < myData->n; i++) { \
     251            myData->data.TYPE[i] = (low + (myData->data.TYPE[i] - min) * \
     252                                    (high - low) / (max - min)); \
    332253        } \
    333254    } else { \
    334255        psLogMsg(__func__, PS_LOG_WARN, "WARNING: (max==min).  Setting all elements to min.\n"); \
    335         for (i = 0; i < myData->n; i++) \
     256        for (long i = 0; i < myData->n; i++) \
    336257        { \
    337258            \
    338             myData->data.TYPE[i] = outLow; \
     259            myData->data.TYPE[i] = low; \
    339260            \
    340261        } \
    341262    } \
     263    break; \
    342264} \
    343265
    344 PS_FUNC_MACRO_NORMALIZE_VECTOR_RANGE(U8)
    345 PS_FUNC_MACRO_NORMALIZE_VECTOR_RANGE(U16)
    346 PS_FUNC_MACRO_NORMALIZE_VECTOR_RANGE(U32)
    347 PS_FUNC_MACRO_NORMALIZE_VECTOR_RANGE(U64)
    348 PS_FUNC_MACRO_NORMALIZE_VECTOR_RANGE(S8)
    349 PS_FUNC_MACRO_NORMALIZE_VECTOR_RANGE(S16)
    350 PS_FUNC_MACRO_NORMALIZE_VECTOR_RANGE(S32)
    351 PS_FUNC_MACRO_NORMALIZE_VECTOR_RANGE(S64)
    352 PS_FUNC_MACRO_NORMALIZE_VECTOR_RANGE(F32)
    353 PS_FUNC_MACRO_NORMALIZE_VECTOR_RANGE(F64)
    354 
    355 psS32 p_psNormalizeVectorRange(psVector* myData,
    356                                psF64 outLow,
    357                                psF64 outHigh)
     266/*************************************************************************************************************
     267p_psNormalizeVectorRange(myData, low, high): this function normalises the vector (myData) to the range
     268low:
     269high.
     270*************************************************************************************************************/
     271bool p_psNormalizeVectorRange(psVector* myData,
     272                              psF64 outLow,
     273                              psF64 outHigh)
    358274{
    359     PS_ASSERT_VECTOR_NON_NULL(myData, -1);
    360     char* strType;
    361 
     275    PS_ASSERT_VECTOR_NON_NULL(myData, false);
    362276    psTrace(__func__, 4, "---- %s() begin ----\n", __func__);
     277
    363278    switch (myData->type.type) {
    364     case PS_TYPE_U8:
    365         p_psNormalizeVectorRangeU8(myData, (psU8) outLow, (psU8) outHigh);
    366         break;
    367     case PS_TYPE_U16:
    368         p_psNormalizeVectorRangeU16(myData, (psU16) outLow, (psU16) outHigh);
    369         break;
    370     case PS_TYPE_U32:
    371         p_psNormalizeVectorRangeU32(myData, (psU32) outLow, (psU32) outHigh);
    372         break;
    373     case PS_TYPE_U64:
    374         p_psNormalizeVectorRangeU64(myData, (psU64) outLow, (psU64) outHigh);
    375         break;
    376     case PS_TYPE_S8:
    377         p_psNormalizeVectorRangeS8(myData, (psS8) outLow, (psS8) outHigh);
    378         break;
    379     case PS_TYPE_S16:
    380         p_psNormalizeVectorRangeS16(myData, (psS16) outLow, (psS16) outHigh);
    381         break;
    382     case PS_TYPE_S32:
    383         p_psNormalizeVectorRangeS32(myData, (psS32) outLow, (psS32) outHigh);
    384         break;
    385     case PS_TYPE_S64:
    386         p_psNormalizeVectorRangeS64(myData, (psS64) outLow, (psS64) outHigh);
    387         break;
    388     case PS_TYPE_F32:
    389         p_psNormalizeVectorRangeF32(myData, (psF32) outLow, (psF32) outHigh);
    390         break;
    391     case PS_TYPE_F64:
    392         p_psNormalizeVectorRangeF64(myData, (psF64) outLow, (psF64) outHigh);
    393         break;
    394     case PS_TYPE_C32:
    395     case PS_TYPE_C64:
    396     default:
    397         PS_TYPE_NAME(strType, myData->type.type);
    398         psError(PS_ERR_BAD_PARAMETER_TYPE, "psLib type %s is not supported.", strType);
    399         break;
     279        NORMALIZE_VECTOR_RANGE_CASE(U8);
     280        NORMALIZE_VECTOR_RANGE_CASE(U16);
     281        NORMALIZE_VECTOR_RANGE_CASE(U32);
     282        NORMALIZE_VECTOR_RANGE_CASE(U64);
     283        NORMALIZE_VECTOR_RANGE_CASE(S8);
     284        NORMALIZE_VECTOR_RANGE_CASE(S16);
     285        NORMALIZE_VECTOR_RANGE_CASE(S32);
     286        NORMALIZE_VECTOR_RANGE_CASE(S64);
     287        NORMALIZE_VECTOR_RANGE_CASE(F32);
     288        NORMALIZE_VECTOR_RANGE_CASE(F64);
     289    default: {
     290            char* strType;
     291            PS_TYPE_NAME(strType, myData->type.type);
     292            psError(PS_ERR_BAD_PARAMETER_TYPE, "psLib type %s is not supported.", strType);
     293            break;
     294        }
    400295    }
    401296    psTrace(__func__, 4, "---- %s() end ----\n", __func__);
    402     return(0);
    403 }
    404 
    405 
     297    return true;
     298}
     299
     300
  • trunk/psLib/src/math/psMathUtils.h

    r6437 r7132  
    77 *  @author GLG, MHPCC
    88 *
    9  *  @version $Revision: 1.2 $ $Name: not supported by cvs2svn $
    10  *  @date $Date: 2006-02-17 00:56:48 $
     9 *  @version $Revision: 1.3 $ $Name: not supported by cvs2svn $
     10 *  @date $Date: 2006-05-18 01:20:51 $
    1111 *
    1212 *  Copyright 2004-2005 Maui High Performance Computing Center, University of Hawaii
     
    3434 */
    3535psS32 p_psVectorBinDisect(
    36     psVector *bins,                    ///< Array of non-decreasing values
    37     psScalar *x                        ///< Target value to find
     36    const psVector *bins,               ///< Array of non-decreasing values
     37    const psScalar *x                   ///< Target value to find
    3838);
    3939
     
    4444 */
    4545psScalar *p_psVectorInterpolate(
    46     psScalar *out,
    47     psVector *domain,                  ///< Domain (x coords) for interpolation
    48     psVector *range,                   ///< Range (y coords) for interpolation
    49     psS32 order,                       ///< Order of interpolation function
    50     psScalar *x                        ///< Location at which to evaluate
     46    psScalar *out,                      ///< Output scalar, or NULL
     47    const psVector *domain,             ///< Domain (x coords) for interpolation
     48    const psVector *range,              ///< Range (y coords) for interpolation
     49    psS32 order,                        ///< Order of interpolation function
     50    const psScalar *x                   ///< Location at which to evaluate
    5151);
    5252
    53 psS32 p_psNormalizeVectorRange(psVector* myData,
    54                                psF64 outLow,
    55                                psF64 outHigh);
     53bool p_psNormalizeVectorRange(psVector* myData,
     54                              psF64 outLow,
     55                              psF64 outHigh);
    5656
    5757/** \} */ // End of MathGroup Functions
  • trunk/psLib/src/math/psStats.c

    r7055 r7132  
    1616 * use ->min and ->max (PS_STAT_USE_RANGE)
    1717 *
    18  *  @version $Revision: 1.171 $ $Name: not supported by cvs2svn $
    19  *  @date $Date: 2006-05-03 23:16:16 $
     18 *  @version $Revision: 1.172 $ $Name: not supported by cvs2svn $
     19 *  @date $Date: 2006-05-18 01:20:50 $
    2020 *
    2121 *  Copyright 2004 Maui High Performance Computing Center, University of Hawaii
     
    2828#include <float.h>
    2929#include <math.h>
     30#include <limits.h>
    3031
    3132/*****************************************************************************/
     
    5051/* DEFINE STATEMENTS                                                         */
    5152/*****************************************************************************/
    52 #define PS_GAUSS_WIDTH 5                // The width of the Gaussian smoothing.
     53#define PS_GAUSS_WIDTH 3                // The width of the Gaussian smoothing.
    5354// This corresponds to N in the ADD.
    5455#define PS_CLIPPED_NUM_ITER_LB 1
     
    6364/* TYPE DEFINITIONS                                                          */
    6465/*****************************************************************************/
    65 psVector* p_psConvertToF32(psVector* in);
     66
     67// None
     68
    6669/*****************************************************************************/
    6770/* GLOBAL VARIABLES                                                          */
     
    154157 *****************************************************************************/
    155158/******************************************************************************
    156 p_psVectorSampleMean(myVector, maskVector, maskVal, stats): calculates the
     159vectorSampleMean(myVector, maskVector, maskVal, stats): calculates the
    157160mean of the input vector.  If there was a problem with the mean calculation,
    158161this routine sets stats->sampleMean to NAN.
    159162 *****************************************************************************/
    160 psS32 p_psVectorSampleMean(const psVector* myVector,
    161                            const psVector* errors,
    162                            const psVector* maskVector,
    163                            psU32 maskVal,
    164                            psStats* stats)
     163static bool vectorSampleMean(const psVector* myVector,
     164                             const psVector* errors,
     165                             const psVector* maskVector,
     166                             psMaskType maskVal,
     167                             psStats* stats)
    165168{
    166169    psTrace(__func__, 4, "---- %s() begin ----\n", __func__);
    167170
    168     psS32 i = 0;                // Loop index variable
    169     psF32 mean = 0.0;           // The mean
    170     psS32 count = 0;            // # of points in this mean
    171 
    172     // If PS_STAT_USE_RANGE is requested, then we enter a slightly different
    173     // loop.
    174     if (errors == NULL) {
     171    psF32 mean = 0.0;                   // The mean
     172    long count = 0;                     // Number of points contributing to this mean
     173
     174    // If PS_STAT_USE_RANGE is requested, then we enter a slightly different loop.
     175    if (!errors) {
    175176        if (stats->options & PS_STAT_USE_RANGE) {
    176             if (maskVector != NULL) {
    177                 for (i = 0; i < myVector->n; i++) {
     177            if (maskVector) {
     178                // No errors, check range, check mask
     179                for (long i = 0; i < myVector->n; i++) {
    178180                    // Check if the data is with the specified range
    179181                    if (!(maskVal & maskVector->data.U8[i]) &&
     
    184186                    }
    185187                }
    186                 if (count != 0) {
    187                     mean /= (psF32)count;
    188                 } else {
    189                     mean = NAN;
    190                 }
    191188
    192189            } else {
    193                 for (i = 0; i < myVector->n; i++) {
     190                // No errors, check range, no mask
     191                for (long i = 0; i < myVector->n; i++) {
    194192                    if ((stats->min <= myVector->data.F32[i]) &&
    195193                            (myVector->data.F32[i] <= stats->max)) {
     
    198196                    }
    199197                }
    200                 if (count != 0) {
    201                     mean /= (psF32)count;
    202                 } else {
    203                     mean = NAN;
    204                 }
    205             }
    206         } else {
    207             if (maskVector != NULL) {
    208                 for (i = 0; i < myVector->n; i++) {
     198            }
     199        } else {
     200            if (maskVector) {
     201                // No errors, no range check, check mask
     202                for (long i = 0; i < myVector->n; i++) {
    209203                    if (!(maskVal & maskVector->data.U8[i])) {
    210204                        mean += myVector->data.F32[i];
     
    212206                    }
    213207                }
    214                 if (count != 0) {
    215                     mean /= (psF32)count;
    216                 } else {
    217                     mean = NAN;
    218                 }
     208
    219209            } else {
    220                 for (i = 0; i < myVector->n; i++) {
     210                // No errors, no range check, no mask
     211                for (long i = 0; i < myVector->n; i++) {
    221212                    mean += myVector->data.F32[i];
    222213                }
    223                 mean /= (psF32)myVector->n;
    224             }
    225         }
     214                count = myVector->n;
     215            }
     216        }
     217
     218        if (count > 0) {
     219            mean /= (psF32)count;
     220        } else {
     221            mean = NAN;
     222        }
     223
    226224    } else {
    227         psF32 errorDivisor = 0.0;
    228         psF32 errorSqr = 0.0;
     225        psF32 sumWeights = 0.0;         // The sum of the weights
    229226        if (stats->options & PS_STAT_USE_RANGE) {
    230227            if (maskVector != NULL) {
    231                 for (i = 0; i < myVector->n; i++) {
     228                for (long i = 0; i < myVector->n; i++) {
    232229                    // Check if the data is with the specified range
    233230                    if (!(maskVal & maskVector->data.U8[i]) &&
    234231                            (stats->min <= myVector->data.F32[i]) &&
    235232                            (myVector->data.F32[i] <= stats->max)) {
    236                         errorSqr = errors->data.F32[i]*errors->data.F32[i];
    237                         mean += myVector->data.F32[i]/errorSqr;
    238                         errorDivisor+= (1.0 / errorSqr);
     233                        float weight = 1.0 / PS_SQR(errors->data.F32[i]);
     234                        mean += myVector->data.F32[i] * weight;
     235                        sumWeights += weight;
    239236                        count++;
    240237                    }
    241238                }
    242                 if (count != 0) {
    243                     mean /= errorDivisor;
    244                 } else {
    245                     mean = NAN;
    246                 }
    247 
    248239            } else {
    249                 for (i = 0; i < myVector->n; i++) {
     240                for (long i = 0; i < myVector->n; i++) {
    250241                    if ((stats->min <= myVector->data.F32[i]) &&
    251242                            (myVector->data.F32[i] <= stats->max)) {
    252                         errorSqr = errors->data.F32[i]*errors->data.F32[i];
    253                         mean += myVector->data.F32[i]/errorSqr;
    254                         errorDivisor+= (1.0 / errorSqr);
     243                        float weight = 1.0 / PS_SQR(errors->data.F32[i]);
     244                        mean += myVector->data.F32[i] * weight;
     245                        sumWeights += weight;
    255246                        count++;
    256247                    }
    257248                }
    258                 if (count != 0) {
    259                     mean /= errorDivisor;
    260                 } else {
    261                     mean = NAN;
    262                 }
    263249            }
    264250        } else {
    265251            if (maskVector != NULL) {
    266                 for (i = 0; i < myVector->n; i++) {
     252                for (long i = 0; i < myVector->n; i++) {
    267253                    if (!(maskVal & maskVector->data.U8[i])) {
    268                         errorSqr = errors->data.F32[i]*errors->data.F32[i];
    269                         mean += myVector->data.F32[i]/errorSqr;
    270                         errorDivisor+= (1.0 / errorSqr);
     254                        float weight = 1.0 / PS_SQR(errors->data.F32[i]);
     255                        mean += myVector->data.F32[i] * weight;
     256                        sumWeights += weight;
    271257                        count++;
    272258                    }
    273259                }
    274                 if (count != 0) {
    275                     mean /= errorDivisor;
    276                 } else {
    277                     mean = NAN;
    278                 }
    279260            } else {
    280                 for (i = 0; i < myVector->n; i++) {
    281                     errorSqr = errors->data.F32[i]*errors->data.F32[i];
    282                     mean += myVector->data.F32[i]/errorSqr;
    283                     errorDivisor+= (1.0 / errorSqr);
    284                 }
    285                 mean /= errorDivisor;
    286             }
     261                for (long i = 0; i < myVector->n; i++) {
     262                    float weight = 1.0 / PS_SQR(errors->data.F32[i]);
     263                    mean += myVector->data.F32[i] * weight;
     264                    sumWeights += weight;
     265                }
     266                count = myVector->n;
     267            }
     268        }
     269
     270        if (count > 0) {
     271            mean /= sumWeights;
     272        } else {
     273            mean = NAN;
    287274        }
    288275    }
     
    290277    stats->sampleMean = mean;
    291278    if (isnan(mean)) {
    292         psTrace(__func__, 4, "---- %s(-1) end ----\n", __func__);
    293         return(-1);
    294     } else {
    295         psTrace(__func__, 4, "---- %s(0) end ----\n", __func__);
    296         return(0);
    297     }
    298 
     279        psTrace(__func__, 4, "---- %s(false) end ----\n", __func__);
     280        return false;
     281    }
     282
     283    psTrace(__func__, 4, "---- %s(true) end ----\n", __func__);
     284    return true;
    299285}
    300286
    301287/******************************************************************************
    302 p_psVectorSampleMax(myVector, maskVector, maskVal, stats): calculates the
    303 max of the input vector.  If there was a problem with the max calculation,
    304 this routine sets stats->max to NAN.
     288vectorMinMax(myVector, maskVector, maskVal, stats): calculates the minimum and maximum of the input vector.
     289If there was a problem with the calculation, this routine sets stats->max and stats->min to NAN.  Return the
     290number of valid values in the vector (those not masked or outside the specified range.
    305291 *****************************************************************************/
    306 psS32 p_psVectorMax(const psVector* myVector,
    307                     const psVector* maskVector,
    308                     psU32 maskVal,
    309                     psStats* stats)
     292static long vectorMinMax(const psVector* myVector,
     293                         const psVector* maskVector,
     294                         psMaskType maskVal,
     295                         psStats* stats
     296                        )
    310297{
    311298    psTrace(__func__, 4, "---- %s() begin ----\n", __func__);
    312     psS32 i = 0;                // Loop index variable
    313     psF32 max = -PS_MAX_F32;    // The calculated maximum
    314     psS32 empty = true;         // Does this vector have valid elements?
     299    psF32 max = -PS_MAX_F32;            // The calculated maximum
     300    psF32 min = PS_MAX_F32;             // The calculated minimum
     301    psF32 *vector = myVector->data.F32; // Dereference the vector
     302    psU8 *mask = NULL;                  // Dereference the mask
     303    if (maskVector) {
     304        mask = maskVector->data.U8;
     305    }
     306    int num = myVector->n;              // Number of values
     307    int numValid = 0;                   // Number of valid values
    315308
    316309    // If PS_STAT_USE_RANGE is requested, then we enter a different loop.
    317310    if (stats->options & PS_STAT_USE_RANGE) {
    318         if (maskVector != NULL) {
    319             for (i = 0; i < myVector->n; i++) {
    320                 if (!(maskVal & maskVector->data.U8[i])) {
    321                     if ((myVector->data.F32[i] > max) &&
    322                             (stats->min <= myVector->data.F32[i]) &&
    323                             (myVector->data.F32[i] <= stats->max)) {
    324                         max = myVector->data.F32[i];
    325                         empty = false;
     311        if (mask) {
     312            // Need to check range and mask
     313            for (long i = 0; i < num; i++) {
     314                if (!(maskVal & mask[i]) && vector[i] >= stats->min && vector[i] <= stats->max) {
     315                    numValid++;
     316                    if (vector[i] > max) {
     317                        max = vector[i];
    326318                    }
    327                 }
    328             }
    329         } else {
    330             for (i = 0; i < myVector->n; i++) {
    331                 if ((myVector->data.F32[i] > max) &&
    332                         (stats->min <= myVector->data.F32[i]) &&
    333                         (myVector->data.F32[i] <= stats->max)) {
    334                     max = myVector->data.F32[i];
    335                     empty = false;
     319                    if (vector[i] < min) {
     320                        min = vector[i];
     321                    }
     322                }
     323            }
     324        } else {
     325            // Need to check range
     326            for (long i = 0; i < num; i++) {
     327                if (vector[i] >= stats->min && vector[i] <= stats->max) {
     328                    numValid++;
     329                    if (vector[i] > max) {
     330                        max = vector[i];
     331                    }
     332                    if (vector[i] < min) {
     333                        min = vector[i];
     334                    }
    336335                }
    337336            }
    338337        }
    339338    } else {
    340         if (maskVector != NULL) {
    341             for (i = 0; i < myVector->n; i++) {
    342                 if (!(maskVal & maskVector->data.U8[i])) {
    343                     if (myVector->data.F32[i] > max) {
    344                         max = myVector->data.F32[i];
    345                         empty = false;
     339        if (mask) {
     340            // Need to check mask
     341            for (long i = 0; i < num; i++) {
     342                if (!(maskVal & mask[i])) {
     343                    numValid++;
     344                    if (vector[i] > max) {
     345                        max = vector[i];
    346346                    }
    347                 }
    348             }
    349         } else {
    350             for (i = 0; i < myVector->n; i++) {
    351                 if (myVector->data.F32[i] > max) {
    352                     max = myVector->data.F32[i];
    353                     empty = false;
    354                 }
    355             }
    356         }
    357     }
    358     if (empty == false) {
     347                    if (vector[i] < min) {
     348                        min = vector[i];
     349                    }
     350                }
     351            }
     352        } else {
     353            // No checks
     354            for (long i = 0; i < num; i++) {
     355                if (vector[i] > max) {
     356                    max = vector[i];
     357                }
     358                if (vector[i] < min) {
     359                    min = vector[i];
     360                }
     361            }
     362            numValid = num;
     363        }
     364    }
     365
     366
     367    if (numValid == 0) {
     368        stats->max = NAN;
     369        stats->min = NAN;
     370    } else {
    359371        stats->max = max;
    360     } else {
    361         stats->max = NAN;
    362         psTrace(__func__, 4, "---- %s(1) end ----\n", __func__);
    363         return(1);
    364     }
    365     psTrace(__func__, 4, "---- %s(0) end ----\n", __func__);
    366     return(0);
     372        stats->min = min;
     373    }
     374    psTrace(__func__, 4, "---- %s(%d) end ----\n", __func__, numValid);
     375    return numValid;
    367376}
    368377
     378#if 0
    369379/******************************************************************************
    370 p_psVectorSampleMin(myVector, maskVector, maskVal, stats): calculates the
    371 minimum of the input vector.  If there was a problem with the min calculation,
    372 this routine sets stats->min to NAN.
    373  *****************************************************************************/
    374 psS32 p_psVectorMin(const psVector* myVector,
    375                     const psVector* maskVector,
    376                     psU32 maskVal,
    377                     psStats* stats)
    378 {
    379     psTrace(__func__, 4, "---- %s() begin ----\n", __func__);
    380     psS32 i = 0;                // Loop index variable
    381     psF32 min = PS_MAX_F32;   // The calculated maximum
    382     psS32 empty = true;         // Does this vector have valid elements?
    383 
    384     if (stats->options & PS_STAT_USE_RANGE) {
    385         if (maskVector != NULL) {
    386             for (i = 0; i < myVector->n; i++) {
    387                 if (!(maskVal & maskVector->data.U8[i])) {
    388                     if ((myVector->data.F32[i] < min) &&
    389                             (stats->min <= myVector->data.F32[i]) &&
    390                             (myVector->data.F32[i] <= stats->max)) {
    391                         min = myVector->data.F32[i];
    392                         empty = false;
    393                     }
    394                 }
    395             }
    396         } else {
    397             for (i = 0; i < myVector->n; i++) {
    398                 if ((myVector->data.F32[i] < min) &&
    399                         (stats->min <= myVector->data.F32[i]) &&
    400                         (myVector->data.F32[i] <= stats->max)) {
    401                     min = myVector->data.F32[i];
    402                     empty = false;
    403                 }
    404             }
    405         }
    406     } else {
    407         if (maskVector != NULL) {
    408             for (i = 0; i < myVector->n; i++) {
    409                 if (!(maskVal & maskVector->data.U8[i])) {
    410                     if (myVector->data.F32[i] < min) {
    411                         min = myVector->data.F32[i];
    412                         empty = false;
    413                     }
    414                 }
    415             }
    416         } else {
    417             for (i = 0; i < myVector->n; i++) {
    418                 if (myVector->data.F32[i] < min) {
    419                     min = myVector->data.F32[i];
    420                     empty = false;
    421                 }
    422             }
    423         }
    424     }
    425 
    426     if (empty == false) {
    427         stats->min = min;
    428     } else {
    429         stats->min = NAN;
    430         psTrace(__func__, 4, "---- %s(1) end ----\n", __func__);
    431         return(1);
    432     }
    433     psTrace(__func__, 4, "---- %s(0) end ----\n", __func__);
    434     return(0);
    435 }
    436 
    437 /******************************************************************************
    438 p_psVectorNValues(myVector, maskVector, maskVal, stats): This routine returns
     380vectorCheckNonEmpty(myVector, maskVector, maskVal, stats): This routine returns
    439381"true" if the inputPsVector has 1 or more valid elements (a valid element is an
    440382unmasked element within the specified min/max range).  Otherwise, return
    441383"false".
    442384 *****************************************************************************/
    443 bool p_psVectorCheckNonEmpty(
    444     const psVector* myVector,
    445     const psVector* maskVector,
    446     psU32 maskVal,
    447     psStats* stats)
     385static bool vectorCheckNonEmpty(const psVector* myVector,
     386                                const psVector* maskVector,
     387                                psMaskType maskVal,
     388                                psStats* stats)
    448389{
    449390    psTrace(__func__, 4, "---- %s() begin ----\n", __func__);
    450     PS_ASSERT_VECTOR_NON_NULL(myVector, -1);
    451     PS_ASSERT_PTR_NON_NULL(stats, -1);
    452     psS32 i = 0;                // Loop index variable
     391    PS_ASSERT_VECTOR_NON_NULL(myVector, false);
     392    PS_ASSERT_PTR_NON_NULL(stats, false);
    453393
    454394    if (stats->options & PS_STAT_USE_RANGE) {
    455         if (maskVector != NULL) {
    456             for (i = 0; i < myVector->n; i++) {
     395        if (maskVector) {
     396            for (long i = 0; i < myVector->n; i++) {
    457397                if (!(maskVal & maskVector->data.U8[i]) &&
    458398                        (stats->min <= myVector->data.F32[i]) &&
    459399                        (myVector->data.F32[i] <= stats->max)) {
    460400                    psTrace(__func__, 4, "---- %s(true) end ----\n", __func__);
    461                     return(true);
    462                 }
    463             }
    464         } else {
    465             for (i = 0; i < myVector->n; i++) {
     401                    return true;
     402                }
     403            }
     404        } else {
     405            for (long i = 0; i < myVector->n; i++) {
    466406                if ((stats->min <= myVector->data.F32[i]) &&
    467407                        (myVector->data.F32[i] <= stats->max)) {
    468408                    psTrace(__func__, 4, "---- %s(true) end ----\n", __func__);
    469                     return(true);
     409                    return true;
    470410                }
    471411            }
     
    473413    } else {
    474414        if (maskVector != NULL) {
    475             for (i = 0; i < myVector->n; i++) {
     415            for (long i = 0; i < myVector->n; i++) {
    476416                if (!(maskVal & maskVector->data.U8[i])) {
    477417                    psTrace(__func__, 4, "---- %s(true) end ----\n", __func__);
    478                     return(true);
     418                    return true;
    479419                }
    480420            }
     
    482422            if (myVector->n > 0) {
    483423                psTrace(__func__, 4, "---- %s(true) end ----\n", __func__);
    484                 return(true);
     424                return true;
    485425            }
    486426        }
     
    489429    return(false);
    490430}
    491 
     431#endif
    492432
    493433/******************************************************************************
    494 p_psVectorNValues(myVector, maskVector, maskVal, stats): calculates the
    495 number of non-masked pixels in the vector that fall within the min/max
    496 range, if specified.
     434vectorSampleMedian(myVector, maskVector, maskVal, stats): calculates the median
     435and quartiles of the input vector.  Returns true on success (including if there
     436were no valid input vector elements).
    497437 *****************************************************************************/
    498 psS32 p_psVectorNValues(const psVector* myVector,
    499                         const psVector* maskVector,
    500                         psU32 maskVal,
    501                         psStats* stats)
     438static bool vectorSampleMedian(const psVector* myVector,
     439                               const psVector* maskVector,
     440                               psMaskType maskVal,
     441                               psStats* stats)
    502442{
    503443    psTrace(__func__, 4, "---- %s() begin ----\n", __func__);
    504     PS_ASSERT_VECTOR_NON_NULL(myVector, -1);
    505     PS_ASSERT_PTR_NON_NULL(stats, -1);
    506     psS32 i = 0;                // Loop index variable
    507     psS32 numData = 0;          // The number of data points
    508 
    509     if (stats->options & PS_STAT_USE_RANGE) {
    510         if (maskVector != NULL) {
    511             for (i = 0; i < myVector->n; i++) {
    512                 if (!(maskVal & maskVector->data.U8[i]) &&
    513                         (stats->min <= myVector->data.F32[i]) &&
    514                         (myVector->data.F32[i] <= stats->max)) {
    515                     numData++;
    516                 }
    517             }
    518         } else {
    519             for (i = 0; i < myVector->n; i++) {
    520                 if ((stats->min <= myVector->data.F32[i]) &&
    521                         (myVector->data.F32[i] <= stats->max)) {
    522                     numData++;
    523                 }
    524             }
    525         }
    526     } else {
    527         if (maskVector != NULL) {
    528             for (i = 0; i < myVector->n; i++) {
    529                 if (!(maskVal & maskVector->data.U8[i])) {
    530                     numData++;
    531                 }
    532             }
    533         } else {
    534             numData = myVector->n;
    535         }
    536     }
    537 
    538     psTrace(__func__, 4, "---- %s(%d) end ----\n", __func__, numData);
    539     return (numData);
    540 }
    541 
    542 /******************************************************************************
    543 p_psVectorSampleMedian(myVector, maskVector, maskVal, stats): calculates the
    544 median of the input vector.  Returns true on success (including if there were
    545 no valid input vector elements).
    546  *****************************************************************************/
    547 bool p_psVectorSampleMedian(const psVector* myVector,
    548                             const psVector* maskVector,
    549                             psU32 maskVal,
    550                             psStats* stats)
    551 {
    552     psTrace(__func__, 4, "---- %s() begin ----\n", __func__);
    553     psVector* unsortedVector = NULL;    // Temporary vector
    554     psVector* sortedVector = NULL;      // Temporary vector
    555     psS32 i = 0;                        // Loop index variable
    556     psS32 count = 0;
    557     psS32 nValues = 0;
    558 
    559     // Determine how many data points fit inside this min/max range
    560     // and are not masked, if the maskVector is not NULL.
    561     nValues = p_psVectorNValues(myVector, maskVector, maskVal, stats);
    562 
    563     if (nValues <= 0) {
    564         psLogMsg(__func__, PS_LOG_WARN, "WARNING: p_psVectorSampleMedian(): no valid elements in input vector.\n");
    565         return(true);
    566         stats->sampleMedian = NAN;
    567     }
    568444
    569445    // Allocate temporary vectors for the data.
    570     unsortedVector = psVectorAlloc(nValues, PS_TYPE_F32);
    571     unsortedVector->n = nValues;
     446    psVector* vector = psVectorAlloc(myVector->n, PS_TYPE_F32); // Vector containing the unmasked values
     447    long count = 0;                     // Number of valid entries
    572448
    573449    // Determine if we must only use data points within a min/max range.
     
    575451        // Store all non-masked data points within the min/max range
    576452        // into the temporary vectors.
    577         count = 0;
    578453        if (maskVector != NULL) {
    579             for (i = 0; i < myVector->n; i++) {
     454            for (long i = 0; i < myVector->n; i++) {
    580455                if (!(maskVal & maskVector->data.U8[i]) &&
    581456                        (stats->min <= myVector->data.F32[i]) &&
    582457                        (myVector->data.F32[i] <= stats->max)) {
    583                     unsortedVector->data.F32[count] = myVector->data.F32[i];
     458                    vector->data.F32[count] = myVector->data.F32[i];
    584459                    count++;
    585460                }
    586461            }
    587462        } else {
    588             for (i = 0; i < myVector->n; i++) {
     463            for (long i = 0; i < myVector->n; i++) {
    589464                if ((stats->min <= myVector->data.F32[i]) &&
    590465                        (myVector->data.F32[i] <= stats->max)) {
    591                     unsortedVector->data.F32[count] = myVector->data.F32[i];
     466                    vector->data.F32[count] = myVector->data.F32[i];
    592467                    count++;
    593468                }
     
    596471    } else {
    597472        // Store all non-masked data points into the temporary vectors.
    598         count = 0;
    599         if (maskVector != NULL) {
    600             for (i = 0; i < myVector->n; i++) {
     473        if (maskVector) {
     474            for (long i = 0; i < myVector->n; i++) {
    601475                if (!(maskVal & maskVector->data.U8[i])) {
    602                     unsortedVector->data.F32[count] = myVector->data.F32[i];
     476                    vector->data.F32[count] = myVector->data.F32[i];
    603477                    count++;
    604478                }
    605479            }
    606480        } else {
    607             for (i = 0; i < myVector->n; i++) {
    608                 unsortedVector->data.F32[i] = myVector->data.F32[i];
    609             }
    610         }
    611     }
    612     // Sort the temporary vectors.
    613     sortedVector = psVectorSort(sortedVector, unsortedVector);
    614     if (sortedVector == NULL) {
     481            vector = psVectorCopy(vector, myVector, PS_TYPE_F32);
     482            count = myVector->n;
     483        }
     484    }
     485    vector->n = count;
     486    if (count == 0) {
     487        psError(PS_ERR_BAD_PARAMETER_SIZE, true, "No valid data in input vector.\n");
     488        psFree(vector);
     489        stats->sampleMedian = NAN;
     490        return false;
     491    }
     492
     493    // Sort the temporary vector.
     494    vector = psVectorSort(vector, vector); // Sort in-place (since it's a copy, it's OK)
     495    if (!vector) {
    615496        psError(PS_ERR_UNEXPECTED_NULL,
    616497                false,
    617498                PS_ERRORTEXT_psStats_STATS_SAMPLE_MEDIAN_SORT_PROBLEM);
    618499        psTrace(__func__, 4, "---- %s(false) end ----\n", __func__);
    619         psFree(unsortedVector);
    620         return(false);
     500        psFree(vector);
     501        return false;
    621502    }
    622503
    623504    // Calculate the median exactly.  Use the average if the number of samples
    624505    // is even.
    625     if (0 == (nValues % 2)) {
    626         stats->sampleMedian = 0.5 * (sortedVector->data.F32[(nValues / 2) - 1] +
    627                                      sortedVector->data.F32[nValues / 2]);
     506    if (count % 2 == 0) {
     507        stats->sampleMedian = 0.5 * (vector->data.F32[(count / 2) - 1] +
     508                                     vector->data.F32[count / 2]);
    628509    } else {
    629         stats->sampleMedian = sortedVector->data.F32[nValues / 2];
    630     }
     510        stats->sampleMedian = vector->data.F32[count / 2];
     511    }
     512
     513    // Calculate the quartile points exactly.
     514    stats->sampleUQ = vector->data.F32[3 * (count / 4)];
     515    stats->sampleLQ = vector->data.F32[count / 4];
    631516
    632517    // Free the temporary data structures.
    633     psFree(unsortedVector);
    634     psFree(sortedVector);
     518    psFree(vector);
    635519
    636520    // Return "true" on success.
    637521    psTrace(__func__, 4, "---- %s(true) end ----\n", __func__);
    638     return(true);
     522    return true;
    639523}
    640524
    641525/******************************************************************************
    642 p_psVectorSmoothHistGaussian(): This routine smoothes the data in the input
     526vectorSmoothHistGaussian(): This routine smoothes the data in the input
    643527robustHistogram with a Gaussian of width sigma.  It returns a psVector of the
    644528smoothed data.
    645529 *****************************************************************************/
    646 psVector *p_psVectorSmoothHistGaussian(
    647     psHistogram *histogram,
    648     psF32 sigma)
     530psVector *vectorSmoothHistGaussian(psHistogram *histogram,
     531                                   psF32 sigma)
    649532{
    650533    psTrace(__func__, 4, "---- %s() begin ----\n", __func__);
     
    657540    }
    658541
    659     psS32 numBins = histogram->nums->n;
    660     psVector *smooth = psVectorAlloc(numBins, PS_TYPE_F32);
     542    long numBins = histogram->nums->n;  // Number of histogram bins
     543    psVector *smooth = psVectorAlloc(numBins, PS_TYPE_F32); // Smoothed version of histogram bins
    661544    smooth->n = smooth->nalloc;
    662     psS32 jMin = 0;
    663     psS32 jMax = 0;
    664 
    665     if (histogram->uniform == false) {
     545    const psVector *bounds = histogram->bounds; // The bounds for the histogram bins
     546
     547    if (!histogram->uniform) {
    666548        //
    667549        // We get here if the histogram is non-uniform.  This code is not tested.
    668550        // However, it is also not used anywhere, yet.
    669551        //
    670         psLogMsg(__func__, PS_LOG_WARN, "WARNING: p_psVectorSmoothHistGaussian() on non-uniform histograms has not been tested or used.\n");
    671 
    672         for (psS32 i = 0; i < numBins; i++) {
     552        psLogMsg(__func__, PS_LOG_WARN, "WARNING: vectorSmoothHistGaussian() on non-uniform histograms has not been tested or used.\n");
     553
     554        for (long i = 0; i < numBins; i++) {
    673555            // Determine the midpoint of bin i.
    674             psS32 iMid = PS_BIN_MIDPOINT(histogram, i);
     556            float iMid = PS_BIN_MIDPOINT(histogram, i);
    675557
    676558            //
     
    678560            // range of data values surrounding iMid.  The range is of size:
    679561            // 2*PS_GAUSS_WIDTH*sigma
     562            long jMin, jMax;
    680563            psF32 x = iMid - (PS_GAUSS_WIDTH * sigma);
    681             jMin = i;
    682             while (jMin > 0) {
    683                 if ((histogram->bounds->data.F32[jMin] <= x) &&
    684                         (histogram->bounds->data.F32[jMin+1] >= x)) {
    685                     break;
    686                 }
    687                 jMin--;
    688             }
    689 
     564            for (jMin = i; jMin > 0 && bounds->data.F32[jMin] > x; jMin--)
     565                ;
    690566            x = iMid + (PS_GAUSS_WIDTH * sigma);
    691             jMax = i;
    692             while (jMax < (histogram->bounds->n - 1)) {
    693                 if ((histogram->bounds->data.F32[jMax] <= x) &&
    694                         (histogram->bounds->data.F32[jMax+1] >= x)) {
    695                     break;
    696                 }
    697                 jMax++;
    698             }
    699 
     567            for (jMax = i; jMax < bounds->n - 1 && bounds->data.F32[jMax + 1] > x; jMax++)
     568                ;
    700569
    701570            //
     
    703572            //
    704573            smooth->data.F32[i] = 0.0;
    705             for (psS32 j = jMin ; j <= jMax ; j++) {
    706                 psS32 jMid = PS_BIN_MIDPOINT(histogram, j);
     574            for (long j = jMin ; j <= jMax ; j++) {
     575                float jMid = PS_BIN_MIDPOINT(histogram, j);
    707576                smooth->data.F32[i] +=
    708577                    histogram->nums->data.F32[j] * psGaussian(jMid, iMid, sigma, true);
     
    713582        // We get here if the histogram is uniform.
    714583        //
    715         for (psS32 i = 0; i < numBins; i++) {
    716             psF32 binSize = histogram->bounds->data.F32[1] - histogram->bounds->data.F32[0];
    717             psS32 gaussWidth = (psS32) ((PS_GAUSS_WIDTH * sigma) / binSize);
     584        for (long i = 0; i < numBins; i++) {
     585            psF32 binSize = bounds->data.F32[1] - bounds->data.F32[0];
     586            psS32 gaussWidth = ((PS_GAUSS_WIDTH * sigma) / binSize);
    718587
    719588            //
     
    723592            // took way too long.
    724593            //
     594            #if 0
     595
    725596            gaussWidth = 10;
     597            #endif
    726598            //
    727599            // We determine the bin numbers (jMin:jMax) corresponding to a
     
    729601            // 2*PS_GAUSS_WIDTH*sigma
    730602            //
    731             psS32 jMin = i - gaussWidth;
    732             if (jMin < 0 ) {
    733                 jMin = 0;
    734             }
    735             psS32 jMax = i + gaussWidth;
    736             if (jMax > (histogram->bounds->n - 1)) {
    737                 jMax = (histogram->bounds->n - 1);
    738             }
     603            psS32 jMin = PS_MAX(i - gaussWidth, 0);
     604            psS32 jMax = PS_MIN(i + gaussWidth, bounds->n - 1);
    739605
    740606            //
     
    742608            //
    743609            smooth->data.F32[i] = 0.0;
    744             psS32 iMid = PS_BIN_MIDPOINT(histogram, i);
    745             for (psS32 j = jMin ; j <= jMax ; j++) {
    746                 psS32 jMid = PS_BIN_MIDPOINT(histogram, j);
     610            float iMid = PS_BIN_MIDPOINT(histogram, i);
     611            for (long j = jMin ; j <= jMax ; j++) {
     612                float jMid = PS_BIN_MIDPOINT(histogram, j);
    747613                smooth->data.F32[i] +=
    748614                    histogram->nums->data.F32[j] * psGaussian(jMid, iMid, sigma, true);
     
    757623    return(smooth);
    758624}
     625
    759626/******************************************************************************
    760 p_psVectorSampleQuartiles(myVector, maskVector, maskVal, statsalculates
    761 the upper and/or lower quartiles of the input vector.
    762 Inputs
    763     myVector
    764     maskVector
    765     maskVal
    766     stats
    767 Returns
    768     NULL
    769  *****************************************************************************/
    770 bool p_psVectorSampleQuartiles(const psVector* myVector,
    771                                const psVector* maskVector,
    772                                psU32 maskVal,
    773                                psStats* stats)
    774 {
    775     psTrace(__func__, 4, "---- %s() begin ----\n", __func__);
    776     psVector* unsortedVector = NULL;
    777     psVector* sortedVector = NULL;
    778     psS32 i = 0;
    779     psS32 count = 0;
    780     psS32 nValues = 0;
    781 
    782     // Determine how many data points fit inside this min/max range
    783     // and are not masked, if the maskVector is not NULL.
    784     nValues = p_psVectorNValues(myVector, maskVector, maskVal, stats);
    785 
    786     // Allocate temporary vectors for the data.
    787     unsortedVector = psVectorAlloc(nValues, PS_TYPE_F32);
    788     unsortedVector->n = unsortedVector->nalloc;
    789 
    790     if (stats->options & PS_STAT_USE_RANGE) {
    791         // Store all non-masked data points within the min/max range
    792         // into the temporary vectors.
    793         count = 0;
    794         if (maskVector != NULL) {
    795             for (i = 0; i < myVector->n; i++) {
    796                 if (!(maskVal & maskVector->data.U8[i]) &&
    797                         (stats->min <= myVector->data.F32[i]) && (myVector->data.F32[i] <= stats->max)) {
    798                     unsortedVector->data.F32[count++] = myVector->data.F32[i];
    799                 }
    800             }
    801         } else {
    802             for (i = 0; i < myVector->n; i++) {
    803                 if ((stats->min <= myVector->data.F32[i]) && (myVector->data.F32[i] <= stats->max)) {
    804                     unsortedVector->data.F32[count++] = myVector->data.F32[i];
    805                 }
    806             }
    807         }
    808     } else {
    809         // Store all non-masked data points into the temporary vectors.
    810         count = 0;
    811         if (maskVector != NULL) {
    812             for (i = 0; i < myVector->n; i++) {
    813                 if (!(maskVal & maskVector->data.U8[i])) {
    814                     unsortedVector->data.F32[count++] = myVector->data.F32[i];
    815                 }
    816             }
    817         } else {
    818             for (i = 0; i < myVector->n; i++) {
    819                 unsortedVector->data.F32[i] = myVector->data.F32[i];
    820             }
    821         }
    822     }
    823 
    824     // Sort the temporary vectors.
    825     sortedVector = psVectorSort(sortedVector, unsortedVector);
    826     if (sortedVector == NULL) {
    827         psError(PS_ERR_UNEXPECTED_NULL,
    828                 false,
    829                 PS_ERRORTEXT_psStats_STATS_SAMPLE_MEDIAN_SORT_PROBLEM);
    830         psTrace(__func__, 4, "---- %s(false) end ----\n", __func__);
    831         return(false);
    832     }
    833 
    834     // Calculate the quartile points exactly.
    835     stats->sampleUQ = sortedVector->data.F32[3 * (nValues / 4)];
    836     stats->sampleLQ = sortedVector->data.F32[nValues / 4];
    837 
    838     // Free the temporary data structures.
    839     psFree(unsortedVector);
    840     psFree(sortedVector);
    841     psTrace(__func__, 4, "---- %s(true) end ----\n", __func__);
    842     return(true);
    843 }
    844 
    845 /******************************************************************************
    846 p_psVectorSampleStdev(myVector, maskVector, maskVal, stats): calculates the
     627vectorSampleStdev(myVector, maskVector, maskVal, stats): calculates the
    847628stdev of the input vector.
    848629Inputs
     
    855636 
    856637 *****************************************************************************/
    857 void p_psVectorSampleStdev(const psVector* myVector,
    858                            const psVector* errors,
    859                            const psVector* maskVector,
    860                            psU32 maskVal,
    861                            psStats* stats)
     638static bool vectorSampleStdev(const psVector* myVector,
     639                              const psVector* errors,
     640                              const psVector* maskVector,
     641                              psMaskType maskVal,
     642                              psStats* stats)
    862643{
    863644    psTrace(__func__, 4, "---- %s() begin ----\n", __func__);
    864     psS32 i = 0;                  // Loop index variable
    865     psS32 countInt = 0;           // # of data points being used
    866     psF32 countFloat = 0.0;     // # of data points being used
    867     psF32 mean = 0.0;           // The mean
    868     psF32 diff = 0.0;           // Used in calculating stdev
    869     psF32 sumSquares = 0.0;     // temporary variable
    870     psF32 sumDiffs = 0.0;       // temporary variable
    871     psF32 errorDivisor = 0.0f;
    872645
    873646    // This procedure requires the mean.  If it has not been already
    874     // calculated, then call p_psVectorSampleMean()
    875     if (0 != isnan(stats->sampleMean)) {
    876         p_psVectorSampleMean(myVector, errors, maskVector, maskVal, stats);
     647    // calculated, then call vectorSampleMean()
     648    if (isnan(stats->sampleMean)) {
     649        vectorSampleMean(myVector, errors, maskVector, maskVal, stats);
    877650    }
    878651    // If the mean is NAN, then generate a warning and set the stdev to NAN.
    879     if (0 != isnan(stats->sampleMean)) {
     652    if (isnan(stats->sampleMean)) {
    880653        stats->sampleStdev = NAN;
    881         psLogMsg(__func__, PS_LOG_WARN, "WARNING: p_psVectorSampleStdev(): p_psVectorSampleMean() reported a NAN mean.\n");
     654        psLogMsg(__func__, PS_LOG_WARN, "WARNING: vectorSampleStdev(): vectorSampleMean() reported a NAN mean.\n");
    882655        psTrace(__func__, 4, "---- %s() end ----\n", __func__);
    883         return;
    884     }
    885 
    886     mean = stats->sampleMean;
     656        return false;
     657    }
     658
     659    // Accumulate the sums
     660    double mean = stats->sampleMean;    // The mean
     661    double sumSquares = 0.0;            // Sum of the squares
     662    double sumDiffs = 0.0;              // Sum of the differences
     663    double errorDivisor = 0.0;          // Division for errors
     664    long count = 0;                     // Number of data points being used
    887665    if (stats->options & PS_STAT_USE_RANGE) {
    888         if (maskVector != NULL) {
    889             for (i = 0; i < myVector->n; i++) {
     666        if (maskVector) {
     667            for (long i = 0; i < myVector->n; i++) {
    890668                if (!(maskVal & maskVector->data.U8[i]) &&
    891669                        (stats->min <= myVector->data.F32[i]) &&
    892670                        (myVector->data.F32[i] <= stats->max)) {
    893                     diff = myVector->data.F32[i] - mean;
    894                     sumSquares += (diff * diff);
     671                    double diff = myVector->data.F32[i] - mean;
     672                    sumSquares += PS_SQR(diff);
    895673                    sumDiffs += diff;
    896                     countInt++;
    897                     if (errors != NULL) {
    898                         errorDivisor+= (1.0 / PS_SQR(errors->data.F32[i]));
     674                    count++;
     675                    if (errors) {
     676                        errorDivisor += 1.0 / PS_SQR(errors->data.F32[i]);
    899677                    }
    900678                }
    901679            }
    902680        } else {
    903             for (i = 0; i < myVector->n; i++) {
     681            for (long i = 0; i < myVector->n; i++) {
    904682                if ((stats->min <= myVector->data.F32[i]) && (myVector->data.F32[i] <= stats->max)) {
    905                     diff = myVector->data.F32[i] - mean;
    906                     sumSquares += (diff * diff);
     683                    double diff = myVector->data.F32[i] - mean;
     684                    sumSquares += PS_SQR(diff);
    907685                    sumDiffs += diff;
    908                     countInt++;
    909                     if (errors != NULL) {
    910                         errorDivisor+= (1.0 / PS_SQR(errors->data.F32[i]));
     686                    count++;
     687                    if (errors) {
     688                        errorDivisor += 1.0 / PS_SQR(errors->data.F32[i]);
    911689                    }
    912690                }
    913691            }
    914             countInt = myVector->n;
     692            count = myVector->n;
    915693        }
    916694    } else {
    917         if (maskVector != NULL) {
    918             for (i = 0; i < myVector->n; i++) {
     695        if (maskVector) {
     696            for (long i = 0; i < myVector->n; i++) {
    919697                if (!(maskVal & maskVector->data.U8[i])) {
    920                     diff = myVector->data.F32[i] - mean;
    921                     sumSquares += (diff * diff);
     698                    double diff = myVector->data.F32[i] - mean;
     699                    sumSquares += PS_SQR(diff);
    922700                    sumDiffs += diff;
    923                     countInt++;
    924                     if (errors != NULL) {
    925                         errorDivisor+= (1.0 / PS_SQR(errors->data.F32[i]));
     701                    count++;
     702                    if (errors) {
     703                        errorDivisor += 1.0 / PS_SQR(errors->data.F32[i]);
    926704                    }
    927705                }
    928706            }
    929707        } else {
    930             for (i = 0; i < myVector->n; i++) {
    931                 diff = myVector->data.F32[i] - mean;
    932                 sumSquares += (diff * diff);
     708            for (long i = 0; i < myVector->n; i++) {
     709                double diff = myVector->data.F32[i] - mean;
     710                sumSquares += PS_SQR(diff);
    933711                sumDiffs += diff;
    934                 countInt++;
    935             }
    936             countInt = myVector->n;
    937             if (errors != NULL) {
    938                 errorDivisor+= (1.0 / PS_SQR(errors->data.F32[i]));
    939             }
    940         }
    941     }
    942 
    943     if (countInt == 0) {
     712                count++;
     713                if (errors) {
     714                    errorDivisor += 1.0 / PS_SQR(errors->data.F32[i]);
     715                }
     716            }
     717            count = myVector->n;
     718        }
     719    }
     720
     721    if (count == 0) {
    944722        stats->sampleStdev = NAN;
    945         psLogMsg(__func__, PS_LOG_WARN, "WARNING: p_psVectorSampleStdev(): no valid psVector elements (%d).  Setting stats->sampleStdev = NAN.\n", countInt);
    946     } else if (countInt == 1) {
     723        psLogMsg(__func__, PS_LOG_WARN, "WARNING: vectorSampleStdev(): no valid psVector elements (%d).  Setting stats->sampleStdev = NAN.\n", count);
     724        return false;
     725    }
     726    if (count == 1) {
    947727        stats->sampleStdev = 0.0;
    948         psLogMsg(__func__, PS_LOG_WARN, "WARNING: p_psVectorSampleStdev(): only one valid psVector elements (%d).  Setting stats->sampleStdev = 0.0.\n", countInt);
    949     } else {
     728        psLogMsg(__func__, PS_LOG_WARN, "WARNING: vectorSampleStdev(): only one valid psVector elements (%d).  Setting stats->sampleStdev = 0.0.\n", count);
     729        return false;
     730    }
     731
     732    if (errors) {
     733        #if 1
    950734        // XXX: The ADD specifies this as the definition of the standard
    951735        // deviation if the errors are known.  Verify this with IfA: none of
    952736        // the data points in the vector are used.  Verify that the masks and
    953737        // data ranges are used correctly.
    954         if (errors != NULL) {
    955             if (0) {
    956                 stats->sampleStdev = (1.0 / sqrtf(errorDivisor));
    957             } else {
    958                 countFloat = (psF32)countInt;
    959                 stats->sampleStdev = sqrtf((sumSquares - (sumDiffs * sumDiffs / countFloat)) / (countFloat - 1));
    960             }
    961         } else {
    962             countFloat = (psF32)countInt;
    963             stats->sampleStdev = sqrtf((sumSquares - (sumDiffs * sumDiffs / countFloat)) / (countFloat - 1));
    964 
    965         }
     738        stats->sampleStdev = (1.0 / sqrtf(errorDivisor));
     739        #else
     740
     741        stats->sampleStdev = sqrt((sumSquares - (sumDiffs * sumDiffs / (float)count)) /
     742                                  (float)(count - 1));
     743        #endif
     744
     745    } else {
     746        stats->sampleStdev = sqrt((sumSquares - (sumDiffs * sumDiffs / (float)count)) /
     747                                  (float)(count - 1));
     748
    966749    }
    967750    psTrace(__func__, 4, "---- %s() end ----\n", __func__);
     751
     752    return true;
    968753}
    969754
    970755/******************************************************************************
    971 p_psVectorClippedStats(myVector, errors, maskVector, maskVal, stats): calculates the
     756vectorClippedStats(myVector, errors, maskVector, maskVal, stats): calculates the
    972757clipped stats (mean or stdev) of the input vector.
    973758 
     
    978763    stats
    979764Returns
    980     0 for success.
    981     -1: error
    982     -2: warning
     765    true for success; false otherwise
    983766 *****************************************************************************/
    984 psS32 p_psVectorClippedStats(const psVector* myVector,
    985                              const psVector* errors,
    986                              const psVector* maskVector,
    987                              psU32 maskVal,
    988                              psStats* stats)
     767static bool vectorClippedStats(const psVector* myVector,
     768                               const psVector* errors,
     769                               psVector* maskVector,
     770                               psMaskType maskVal,
     771                               psStats* stats
     772                              )
    989773{
    990774    psTrace(__func__, 4, "---- %s() begin ----\n", __func__);
    991775    psTrace(__func__, 4, "Trace level is %d\n", psTraceGetLevel(__func__));
    992     psF32 clippedMean = 0.0;
    993     psF32 clippedStdev = 0.0;
    994     psVector* tmpMask = NULL;
    995     static psStats *statsTmp = NULL;
    996     psS32 rc = 0;
    997776
    998777    // Ensure that stats->clipIter is within the proper range.
     
    1008787    // Allocate a psStats structure for calculating the mean, median, and
    1009788    // stdev.
    1010     if (statsTmp == NULL) {
    1011         statsTmp = psStatsAlloc(PS_STAT_SAMPLE_MEAN);
    1012         p_psMemSetPersistent(statsTmp, true);
     789    psStats *statsTmp = psStatsAlloc(PS_STAT_SAMPLE_MEAN | PS_STAT_SAMPLE_STDEV);
     790
     791    // We've already copied the mask vector, so it's safe to simply increment the reference counter.
     792    psVector *tmpMask = NULL;
     793    if (maskVector) {
     794        tmpMask = psMemIncrRefCounter(maskVector);
    1013795    } else {
    1014         // Initialize structure if already allocated
    1015         statsTmp->sampleMean = NAN;
    1016         statsTmp->sampleMedian = NAN;
    1017         statsTmp->sampleStdev = NAN;
    1018         statsTmp->sampleUQ = NAN;
    1019         statsTmp->sampleLQ = NAN;
    1020         statsTmp->robustMedian = NAN;
    1021         statsTmp->robustStdev = NAN;
    1022         statsTmp->robustUQ = NAN;
    1023         statsTmp->robustLQ = NAN;
    1024         statsTmp->robustN50 = -1;
    1025         statsTmp->fittedMean = NAN;
    1026         statsTmp->fittedStdev = NAN;
    1027         statsTmp->fittedNfit = -1;
    1028         statsTmp->clippedMean = NAN;
    1029         statsTmp->clippedStdev = NAN;
    1030         statsTmp->clippedNvalues = -1;
    1031         statsTmp->clipSigma = 3.0;
    1032         statsTmp->clipIter = 3;
    1033         statsTmp->min = NAN;
    1034         statsTmp->max = NAN;
    1035         statsTmp->binsize = NAN;
    1036         statsTmp->nSubsample = 100000;
    1037     }
    1038 
    1039     // We allocate a temporary mask vector since during the iterative
    1040     // steps that follow, we will be masking off additional data points.
    1041     // However, we do no want to modify the original mask vector.
    1042     tmpMask = psVectorAlloc(myVector->n, PS_TYPE_U8);
    1043     tmpMask->n = tmpMask->nalloc;
    1044 
    1045     // If we were called with a mask vector, then initialize the temporary
    1046     // mask vector with those values.  Otherwise, initialize to zero.
    1047     if (maskVector != NULL) {
    1048         for (psS32 i = 0; i < tmpMask->n; i++) {
    1049             tmpMask->data.U8[i] = maskVector->data.U8[i];
    1050         }
    1051     } else {
    1052         for (psS32 i = 0; i < tmpMask->n; i++) {
    1053             tmpMask->data.U8[i] = 0;
    1054         }
     796        tmpMask = psVectorAlloc(myVector->n, PS_TYPE_U8);
     797        tmpMask->n = tmpMask->nalloc;
     798        psVectorInit(tmpMask, 0);
    1055799    }
    1056800
    1057801    // 1. Compute the sample median.
    1058     p_psVectorSampleMedian(myVector, maskVector, maskVal, statsTmp);
     802    vectorSampleMedian(myVector, tmpMask, maskVal, statsTmp);
    1059803    if (isnan(statsTmp->sampleMedian)) {
    1060         psLogMsg(__func__, PS_LOG_WARN, "Call to p_psVectorSampleMedian returned NAN\n");
     804        psLogMsg(__func__, PS_LOG_WARN, "Call to vectorSampleMedian returned NAN\n");
    1061805        stats->clippedMean = NAN;
    1062806        stats->clippedStdev = NAN;
    1063         psTrace(__func__, 4, "---- %s(-2) end ----\n", __func__);
    1064         return(-2);
     807        psTrace(__func__, 4, "---- %s(false) end ----\n", __func__);
     808        psFree(tmpMask);
     809        psFree(statsTmp);
     810        return false;
    1065811    }
    1066812    psTrace(__func__, 6, "The initial sample median is %f\n", statsTmp->sampleMedian);
    1067813
    1068814    // 2. Compute the sample standard deviation.
    1069     p_psVectorSampleStdev(myVector, errors, maskVector, maskVal, statsTmp);
     815    vectorSampleStdev(myVector, errors, tmpMask, maskVal, statsTmp);
    1070816    if (isnan(statsTmp->sampleStdev)) {
    1071         psLogMsg(__func__, PS_LOG_WARN, "Call to p_psVectorSampleStdev returned NAN\n");
     817        psLogMsg(__func__, PS_LOG_WARN, "Call to vectorSampleStdev returned NAN\n");
    1072818        stats->clippedMean = NAN;
    1073819        stats->clippedStdev = NAN;
    1074         psTrace(__func__, 4, "---- %s(-2) end ----\n", __func__);
    1075         return(-2);
     820        psTrace(__func__, 4, "---- %s(false) end ----\n", __func__);
     821        psFree(tmpMask);
     822        psFree(statsTmp);
     823        return false;
    1076824    }
    1077825    psTrace(__func__, 6, "The initial sample stdev is %f\n", statsTmp->sampleStdev);
    1078826
    1079827    // 3. Use the sample median as the first estimator of the mean X.
    1080     clippedMean = statsTmp->sampleMedian;
     828    psF32 clippedMean = statsTmp->sampleMedian;
    1081829
    1082830    // 4. Use the sample stdev as the first estimator of the mean stdev.
    1083     clippedStdev = statsTmp->sampleStdev;
     831    psF32 clippedStdev = statsTmp->sampleStdev;
    1084832
    1085833    // 5. Repeat N (stats->clipIter) times:
    1086     for (psS32 iter = 0; iter < stats->clipIter; iter++) {
     834    long numClipped = LONG_MAX;         // Number of values clipped in this iteration
     835    for (int iter = 0; iter < stats->clipIter && numClipped > 0; iter++) {
     836        numClipped = 0;
    1087837        psTrace(__func__, 6, "------------ Iteration %d ------------\n", iter);
    1088838        // a) Exclude all values x_i for which |x_i - x| > K * stdev
    1089         if (errors != NULL) {
    1090             for (psS32 j = 0; j < myVector->n; j++) {
    1091                 if (fabs(myVector->data.F32[j] - clippedMean) > (stats->clipSigma * errors->data.F32[j])) {
     839        if (errors) {
     840            for (long j = 0; j < myVector->n; j++) {
     841                if (fabsf(myVector->data.F32[j] - clippedMean) > (stats->clipSigma * errors->data.F32[j])) {
    1092842                    tmpMask->data.U8[j] = 0xff;
    1093                 }
    1094             }
    1095         } else {
    1096             for (psS32 j = 0; j < myVector->n; j++) {
    1097                 if (fabs(myVector->data.F32[j] - clippedMean) >
    1098                         (stats->clipSigma * clippedStdev)) {
     843                    psTrace(__func__, 10, "Clipped %d: %f +/- %f\n", j,
     844                            myVector->data.F32[j], errors->data.F32[j]);
     845                    numClipped++;
     846                }
     847            }
     848        } else {
     849            for (long j = 0; j < myVector->n; j++) {
     850                if (fabsf(myVector->data.F32[j] - clippedMean) > (stats->clipSigma * clippedStdev)) {
    1099851                    tmpMask->data.U8[j] = 0xff;
     852                    psTrace(__func__, 10, "Clipped %d: %f\n", j, myVector->data.F32[j]);
     853                    numClipped++;
    1100854                }
    1101855            }
     
    1103857
    1104858        // b) compute new mean and stdev
    1105         p_psVectorSampleMean(myVector, errors, tmpMask, 0xff, statsTmp);
    1106         p_psVectorSampleStdev(myVector, errors, tmpMask, 0xff, statsTmp);
     859        vectorSampleMean(myVector, errors, tmpMask, maskVal, statsTmp);
     860        vectorSampleStdev(myVector, errors, tmpMask, maskVal, statsTmp);
    1107861        psTrace(__func__, 6, "The new sample mean is %f\n", statsTmp->sampleMean);
    1108862        psTrace(__func__, 6, "The new sample stdev is %f\n", statsTmp->sampleStdev);
     
    1113867            // Exit loop.
    1114868            iter = stats->clipIter;
    1115             psError(PS_ERR_UNKNOWN, true, "p_psVectorSampleMean() or p_psVectorSampleStdev() returned a NAN.\n");
     869            psError(PS_ERR_UNKNOWN, true, "vectorSampleMean() or vectorSampleStdev() returned a NAN.\n");
    1116870            psFree(tmpMask);
    1117             return(-1);
     871            return false;
    1118872        } else {
    1119873            clippedMean = statsTmp->sampleMean;
     
    1122876    }
    1123877
    1124     // 7. The last calcuated value of x is the cliped mean.
     878    // 7. The last calcuated value of x is the clipped mean.
    1125879    if (stats->options & PS_STAT_CLIPPED_MEAN) {
    1126880        stats->clippedMean = clippedMean;
    1127881        psTrace(__func__, 6, "The final clipped mean is %f\n", clippedMean);
    1128882    }
    1129     // 8. The last calcuated value of stdev is the cliped stdev.
     883    // 8. The last calcuated value of stdev is the clipped stdev.
    1130884    if (stats->options & PS_STAT_CLIPPED_STDEV) {
    1131885        stats->clippedStdev = clippedStdev;
     
    1134888
    1135889    psFree(tmpMask);
    1136     psTrace(__func__, 4, "---- %s(%d) end ----\n", __func__, rc);
    1137     return(rc);
     890    psFree(statsTmp);
     891    psTrace(__func__, 4, "---- %s(true) end ----\n", __func__);
     892    return true;
    1138893}
    1139894
    1140 static psF32 QuadraticInverse(
    1141     psF32 a,
    1142     psF32 b,
    1143     psF32 c,
    1144     psF32 y,
    1145     psF32 xLo,
    1146     psF32 xHi)
     895static psF32 QuadraticInverse(psF32 a,
     896                              psF32 b,
     897                              psF32 c,
     898                              psF32 y,
     899                              psF32 xLo,
     900                              psF32 xHi
     901                             )
    1147902{
    1148903    psF64 tmp = sqrt((y - c)/a + (b*b)/(4.0 * a * a));
     
    1151906    psF64 x2 = -b/(2.0*a) - tmp;
    1152907
    1153     if (0) {
    1154         psF64 y1 = (a * x1 * x1) + (b * x1) + c;
    1155         psF64 y2 = (a * x2 * x2) + (b * x2) + c;
    1156         printf("QuadraticInverse: %fx^2 + %fx + %f\n", a, b, c);
    1157         printf("QuadraticInverse: y is %f\n", y);
    1158         printf("QuadraticInverse: (x1, x2) is (%f %f)\n", x1, x2);
    1159         printf("QuadraticInverse: (y1, y2) is (%f %f)\n", y1, y2);
    1160     }
    1161 
    1162     if ((xLo <= x1) && (x1 <= xHi)) {
    1163         return(x1);
    1164     } else if ((xLo <= x2) && (x2 <= xHi)) {
    1165         return(x2);
    1166     } else {
    1167         return(0.5 * (xLo + xHi));
    1168     }
     908    #if 0
     909
     910    psF64 y1 = (a * x1 * x1) + (b * x1) + c;
     911    psF64 y2 = (a * x2 * x2) + (b * x2) + c;
     912    printf("QuadraticInverse: %fx^2 + %fx + %f\n", a, b, c);
     913    printf("QuadraticInverse: y is %f\n", y);
     914    printf("QuadraticInverse: (x1, x2) is (%f %f)\n", x1, x2);
     915    printf("QuadraticInverse: (y1, y2) is (%f %f)\n", y1, y2);
     916    #endif
     917
     918    if (xLo <= x1 && x1 <= xHi) {
     919        return x1;
     920    }
     921    if (xLo <= x2 && x2 <= xHi) {
     922        return x2;
     923    }
     924    return 0.5 * (xLo + xHi);
    1169925}
    1170926
     
    1180936 
    1181937*****************************************************************************/
    1182 psF32 fitQuadraticSearchForYThenReturnX(
    1183     psVector *xVec,
    1184     psVector *yVec,
    1185     psS32 binNum,
    1186     psF32 yVal)
     938static psF32 fitQuadraticSearchForYThenReturnX(const psVector *xVec,
     939        psVector *yVec,
     940        psS32 binNum,
     941        psF32 yVal
     942                                              )
    1187943{
    1188944    psTrace(__func__, 4, "---- %s() begin ----\n", __func__);
     
    1235991        if (((y->data.F64[0] < y->data.F64[1]) && !(y->data.F64[1] <= y->data.F64[2])) ||
    1236992                ((y->data.F64[0] > y->data.F64[1]) && !(y->data.F64[1] >= y->data.F64[2]))) {
    1237             psError(PS_ERR_UNKNOWN, true, "This routine must be called with monotonically increasing or decreasing data points.\n");
     993            psError(PS_ERR_UNKNOWN, true,
     994                    "This routine must be called with monotonically increasing or decreasing data points.\n");
    1238995            psFree(x);
    1239996            psFree(y);
    1240997            psTrace(__func__, 5, "---- %s() end ----\n", __func__);
    1241             return(NAN);
     998            return NAN;
    1242999        }
    12431000
     
    12511008            psFree(y);
    12521009            psTrace(__func__, 5, "---- %s(NAN) end ----\n", __func__);
    1253             return(NAN);
     1010            return NAN;
    12541011        }
    12551012        psTrace(__func__, 6, "myPoly->coeff[0] is %f\n", myPoly->coeff[0]);
     
    12621019
    12631020        psTrace(__func__, 6, "We fit the polynomial, now find x such that f(x) equals %f\n", yVal);
    1264         tmpFloat = QuadraticInverse(myPoly->coeff[2], myPoly->coeff[1], myPoly->coeff[0], yVal, x->data.F64[0], x->data.F64[2]);
     1021        tmpFloat = QuadraticInverse(myPoly->coeff[2], myPoly->coeff[1], myPoly->coeff[0], yVal,
     1022                                    x->data.F64[0], x->data.F64[2]);
    12651023        psFree(myPoly);
    12661024
     
    12951053
    12961054    psTrace(__func__, 5, "---- %s(%f) end ----\n", __func__, tmpFloat);
    1297     return(tmpFloat);
     1055    return tmpFloat;
    12981056}
    12991057
     
    13011059NOTE: We assume unnormalized gaussians.
    13021060 *****************************************************************************/
    1303 psF32 psMinimizeLMChi2Gauss1D(
    1304     psVector *deriv,
    1305     const psVector *params,
    1306     const psVector *coords)
     1061static psF32 minimizeLMChi2Gauss1D(psVector *deriv,
     1062                                   const psVector *params,
     1063                                   const psVector *coords
     1064                                  )
    13071065{
    13081066    psTrace(__func__, 4, "---- %s() begin ----\n", __func__);
     
    13181076    psF32 stdev = params->data.F32[1];
    13191077
    1320     if (deriv == NULL) {
    1321         deriv = psVectorAlloc(2, PS_TYPE_F32);
    1322         deriv->n = 2;
    1323     } else {
     1078    psF32 gauss = psGaussian(x, mean, stdev, false);
     1079    if (deriv) {
    13241080        PS_ASSERT_VECTOR_SIZE(deriv, 2, NAN);
    13251081        PS_ASSERT_VECTOR_TYPE(deriv, PS_TYPE_F32, NAN);
    1326     }
    1327 
    1328     psF32 tmp = (x - mean) * psGaussian(x, mean, stdev, false);
    1329     deriv->data.F32[0] = tmp / (stdev * stdev);
    1330     tmp = (x - mean) * (x - mean) * psGaussian(x, mean, stdev, 0);
    1331     deriv->data.F32[1] = tmp / (stdev * stdev * stdev);
     1082        psF32 tmp = (x - mean) * gauss;
     1083        deriv->data.F32[0] = tmp / (stdev * stdev);
     1084        deriv->data.F32[1] = (x - mean) * tmp / (stdev * stdev * stdev);
     1085    }
     1086
    13321087
    13331088    psTrace(__func__, 4, "---- %s() end ----\n", __func__);
    1334     return(psGaussian(x, mean, stdev, false));
     1089    return gauss;
    13351090}
    13361091
    13371092/******************************************************************************
    1338 p_psVectorRobustStats(myVector, maskVector, maskVal, stats): This is the new
     1093vectorRobustStats(myVector, maskVector, maskVal, stats): This is the new
    13391094version of the robust stats routine.
    13401095 
     
    13541109*****************************************************************************/
    13551110#define INITIAL_NUM_BINS 1000.0
    1356 psS32 p_psVectorRobustStats(const psVector* myVector,
    1357                             const psVector* errors,
    1358                             const psVector* maskVector,
    1359                             psU32 maskVal,
    1360                             psStats* stats)
     1111static bool vectorRobustStats(const psVector* myVector,
     1112                              const psVector* errors,
     1113                              psVector* maskVector,
     1114                              psMaskType maskVal,
     1115                              psStats* stats)
    13611116{
    13621117    psTrace(__func__, 4, "---- %s() begin ----\n", __func__);
     
    13641119        PS_VECTOR_PRINT_F32(myVector);
    13651120    }
    1366     psHistogram *robustHistogram = NULL;
    1367     psHistogram *cumulativeRobustHistogram = NULL;
    1368     psS32 numBins = 0;
    1369     psScalar tmpScalar;
     1121
     1122    psScalar tmpScalar;                 // Temporary scalar variable, for p_psVectorBinDisect
    13701123    tmpScalar.type.type = PS_TYPE_F32;
    1371     psS32 totalDataPoints = 0;
    1372     psS32 rc = 0;
    1373     psS32 rcBool = false;
    1374     psVector *tmpMaskVec = psVectorAlloc(myVector->n, PS_TYPE_U8);
    1375     tmpMaskVec->n = tmpMaskVec->nalloc;
    1376     if (maskVector != NULL) {
    1377         for (psS32 i = 0 ; i < myVector->n ; i++) {
    1378             tmpMaskVec->data.U8[i] = maskVector->data.U8[i];
    1379         }
     1124
     1125    // We need a mask for these statistics, so if the one we're given is NULL, make our own.
     1126    psVector *mask = NULL;              // The actual mask we will use
     1127    if (maskVector) {
     1128        mask = psMemIncrRefCounter(maskVector);
    13801129    } else {
    1381         for (psS32 i = 0 ; i < myVector->n ; i++) {
    1382             tmpMaskVec->data.U8[i] = 0;
    1383         }
    1384     }
    1385     psS32 iterate = 1;
    1386     psF32 sigma;
    1387     psStats *tmpStatsMinMax = psStatsAlloc(PS_STAT_MIN | PS_STAT_MAX);
    1388 
    1389     while (iterate > 0) {
    1390         psTrace(__func__, 6, "-------------------- Iterating on Bin size.  Iteration number %d --------------------\n", iterate);
    1391         psF32 binSize = 0.0;
     1130        mask = psVectorAlloc(myVector->n, PS_TYPE_U8);
     1131        mask->n = myVector->n;
     1132        psVectorInit(mask, 0);
     1133    }
     1134
     1135    psStats *statsMinMax = psStatsAlloc(PS_STAT_MIN | PS_STAT_MAX); // Statistics for min and max
     1136    psHistogram *histogram = NULL;      // Histogram of the data
     1137    psHistogram *cumulative = NULL;     // Cumulative histogram of the data
     1138    float min = NAN, max = NAN;         // Mimimum and maximum values
     1139    float sigma = NAN;                  // The robust standard deviation
     1140    long totalDataPoints = 0;           // Total number of (unmasked) data points
     1141
     1142    // Iterate to get the best bin size
     1143    for (int iterate = 1; iterate > 0; iterate++) {
     1144        psTrace(__func__, 6,
     1145                "-------------------- Iterating on Bin size.  Iteration number %d --------------------\n",
     1146                iterate);
     1147
     1148        // Get the minimum and maximum values
     1149        int numValid = vectorMinMax(myVector, mask, maskVal, statsMinMax); // Number of valid values
     1150        min = statsMinMax->min;
     1151        max = statsMinMax->max;
     1152        if (numValid == 0 || isnan(min) || isnan(max)) {
     1153            // Data range calculation failed
     1154            psError(PS_ERR_UNKNOWN, false, "Failed to calculate the min/max of the input vector.\n");
     1155            psFree(statsMinMax);
     1156            psFree(mask);
     1157            psTrace(__func__, 4, "---- %s(false) end  ----\n", __func__);
     1158            return false;
     1159        }
     1160        psTrace(__func__, 6, "Data min/max is (%.2f, %.2f)\n", min, max);
     1161
     1162        // If all data points have the same value, then we set the appropiate members of stats and return.
     1163        if (fabs(max - min) <= FLT_EPSILON) {
     1164            psTrace(__func__, 5, "All data points have the same value: %f.\n", min);
     1165            if (stats->options & PS_STAT_ROBUST_MEDIAN) {
     1166                stats->robustMedian = min;
     1167            }
     1168            if (stats->options & PS_STAT_ROBUST_QUARTILE) {
     1169                stats->robustUQ = min;
     1170                stats->robustLQ = min;
     1171            }
     1172            stats->robustN50 = numValid;
     1173            psFree(statsMinMax);
     1174            psFree(mask);
     1175
     1176            psTrace(__func__, 4, "---- %s(0) end  ----\n", __func__);
     1177            return false;
     1178        }
     1179
     1180        float binSize = 0.0;            // Size of bins for histogram
    13921181        if ((iterate == 1) && (stats->options & PS_STAT_USE_BINSIZE)) {
    13931182            // Set initial bin size to the specified value.
     
    13951184            psTrace(__func__, 6, "Setting initial robust bin size to %.2f\n", binSize);
    13961185        } else {
    1397             // Determine the bin size of the robust histogram.  This is done
    1398             // by computing the total range of data values and dividing by 1000.0.
    1399 
    1400             rc = p_psVectorMin(myVector, tmpMaskVec, 1, tmpStatsMinMax);
    1401             rc|= p_psVectorMax(myVector, tmpMaskVec, 1, tmpStatsMinMax);
    1402             if ((rc != 0) || isnan(tmpStatsMinMax->min) || isnan(tmpStatsMinMax->max)) {
    1403                 psError(PS_ERR_UNKNOWN, false, "Failed to calculate the min/max of the input vector.\n");
    1404                 psFree(tmpStatsMinMax);
    1405                 psFree(tmpMaskVec);
    1406                 psTrace(__func__, 4, "---- %s(1) end  ----\n", __func__);
    1407                 return(1);
    1408             }
    1409             psTrace(__func__, 6, "Data min/max is (%.2f, %.2f)\n", tmpStatsMinMax->min, tmpStatsMinMax->max);
    1410             binSize = (tmpStatsMinMax->max - tmpStatsMinMax->min) / INITIAL_NUM_BINS;
     1186            // Determine the bin size of the robust histogram, using the pre-defined number of bins
     1187            binSize = (max - min) / INITIAL_NUM_BINS;
    14111188        }
    14121189        psTrace(__func__, 6, "Initial robust bin size is %.2f\n", binSize);
    14131190
    1414         //
    1415         // If all data points have the same value, then we set the appropiate
    1416         // members of stats and return.
    1417         //
    1418         if (fabs(tmpStatsMinMax->max - tmpStatsMinMax->min) <= FLT_EPSILON) {
    1419             psTrace(__func__, 5, "All data points have the same value.\n", binSize);
    1420             if (stats->options & PS_STAT_ROBUST_MEDIAN) {
    1421                 stats->robustMedian = tmpStatsMinMax->min;
    1422             }
    1423             if (stats->options & PS_STAT_ROBUST_QUARTILE) {
    1424                 stats->robustUQ = tmpStatsMinMax->min;
    1425                 stats->robustLQ = tmpStatsMinMax->min;
    1426             }
    1427             // XXX: Set these to the number of unmasked data points?
    1428             stats->robustN50 = 0;
    1429             psFree(tmpStatsMinMax);
    1430             psFree(tmpMaskVec);
    1431 
    1432             psTrace(__func__, 4, "---- %s(0) end  ----\n", __func__);
    1433             return(0);
    1434         }
    1435 
    1436         //
    1437         // ADD: Step 0.
    1438         // Construct the histogram with the specified bin size.
    1439         //
    1440         // NOTE: we can not specify the bin size precisely since the argument
    1441         // to psHistogramAlloc() is the number of bins, not the binSize.
    1442         // If we get here, we know that binSize != 0.0.
    1443         //
    1444         numBins = (psS32)((tmpStatsMinMax->max - tmpStatsMinMax->min) / binSize);
     1191        // ADD step 0: Construct the histogram with the specified bin size.  NOTE: we can not specify the bin
     1192        // size precisely since the argument to psHistogramAlloc() is the number of bins, not the binSize.  If
     1193        // we get here, we know that binSize != 0.0.
     1194        long numBins = (max - min) / binSize; // Number of bins
    14451195        psTrace(__func__, 6, "Numbins is %d\n", numBins);
    1446         psTrace(__func__, 6, "Creating a robust histogram from data range (%.2f - %.2f)\n", tmpStatsMinMax->min, tmpStatsMinMax->max);
    1447         robustHistogram = psHistogramAlloc(tmpStatsMinMax->min, tmpStatsMinMax->max, numBins);
    1448         cumulativeRobustHistogram = psHistogramAlloc(tmpStatsMinMax->min, tmpStatsMinMax->max, numBins);
    1449 
    1450         // Populate the histogram array.
    1451         robustHistogram = psVectorHistogram(robustHistogram, myVector, errors, tmpMaskVec, maskVal);
     1196        psTrace(__func__, 6, "Creating a robust histogram from data range (%.2f - %.2f)\n", min, max);
     1197        // Generate the histogram
     1198        histogram = psHistogramAlloc(min, max, numBins);
     1199        histogram = psVectorHistogram(histogram, myVector, errors, mask, maskVal);
    14521200        if (psTraceGetLevel(__func__) >= 8) {
    1453             PS_VECTOR_PRINT_F32(robustHistogram->bounds);
    1454             PS_VECTOR_PRINT_F32(robustHistogram->nums);
    1455         }
    1456         //
    1457         // ADD: Step 1.
    1458         // Construct the cumulative histogram from the specific histogram
    1459         //
    1460         cumulativeRobustHistogram->nums->data.F32[0] = robustHistogram->nums->data.F32[0];
    1461         for (psS32 i = 1 ; i < robustHistogram->nums->n ; i++) {
    1462             cumulativeRobustHistogram->nums->data.F32[i] = cumulativeRobustHistogram->nums->data.F32[i-1] +
    1463                     robustHistogram->nums->data.F32[i];
     1201            PS_VECTOR_PRINT_F32(histogram->bounds);
     1202            PS_VECTOR_PRINT_F32(histogram->nums);
     1203        }
     1204
     1205        // ADD step 1: Convert the specific histogram to a cumulative histogram
     1206        cumulative = psHistogramAlloc(min, max, numBins);
     1207        cumulative->nums->data.F32[0] = histogram->nums->data.F32[0];
     1208        for (long i = 1; i < histogram->nums->n; i++) {
     1209            cumulative->nums->data.F32[i] = cumulative->nums->data.F32[i-1] + histogram->nums->data.F32[i];
    14641210        }
    14651211        if (psTraceGetLevel(__func__) >= 8) {
    1466             PS_VECTOR_PRINT_F32(cumulativeRobustHistogram->bounds);
    1467             PS_VECTOR_PRINT_F32(cumulativeRobustHistogram->nums);
    1468         }
    1469 
    1470         //
    1471         // ADD: Step 2.
    1472         // Find the bin which contains the 50% data point.
    1473         //
    1474         totalDataPoints = cumulativeRobustHistogram->nums->data.F32[numBins - 1];
     1212            PS_VECTOR_PRINT_F32(cumulative->bounds);
     1213            PS_VECTOR_PRINT_F32(cumulative->nums);
     1214        }
     1215
     1216        // ADD step 2: Find the bin which contains the 50% data point.
     1217        totalDataPoints = cumulative->nums->data.F32[numBins - 1];
    14751218        psTrace(__func__, 6, "Total data points is %d\n", totalDataPoints);
    1476         psS32 binMedian;
    1477         if (totalDataPoints/2.0 < cumulativeRobustHistogram->nums->data.F32[0]) {
     1219        long binMedian;
     1220        if (totalDataPoints/2.0 < cumulative->nums->data.F32[0]) {
    14781221            // Special case: the median is in the first bin.  Perhaps we should recode this.
    14791222            // XXX: Must try a special case where the median in in the last bin.
     
    14811224        } else {
    14821225            tmpScalar.data.F32 = totalDataPoints/2.0;
    1483             binMedian = 1 + p_psVectorBinDisect(cumulativeRobustHistogram->nums, &tmpScalar);
     1226            binMedian = 1 + p_psVectorBinDisect(cumulative->nums, &tmpScalar);
    14841227            if (binMedian < 0) {
    1485                 psError(PS_ERR_UNKNOWN, false, "Failed to calculate the 50 precent data point (%d).\n", binMedian);
    1486                 psFree(tmpStatsMinMax);
    1487                 psFree(robustHistogram);
    1488                 psFree(cumulativeRobustHistogram);
    1489                 psFree(tmpMaskVec);
    1490                 psTrace(__func__, 4, "---- %s(1) end  ----\n", __func__);
    1491                 return(1);
    1492             }
    1493         }
    1494         psTrace(__func__, 6, "The median bin is %d (%.2f to %.2f)\n", binMedian, cumulativeRobustHistogram->bounds->data.F32[binMedian], cumulativeRobustHistogram->bounds->data.F32[binMedian+1]);
    1495 
    1496         //
    1497         // ADD: Step 3.
    1498         // Interpolate to the exact 50% position: this is the robust histogram median.
    1499         //
    1500         stats->robustMedian = fitQuadraticSearchForYThenReturnX(
    1501                                   *(psVector* *)&cumulativeRobustHistogram->bounds,
    1502                                   *(psVector* *)&cumulativeRobustHistogram->nums,
    1503                                   binMedian,
    1504                                   totalDataPoints/2.0);
     1228                psError(PS_ERR_UNKNOWN, false,
     1229                        "Failed to calculate the 50 precent data point (%d).\n", binMedian);
     1230                psFree(statsMinMax);
     1231                psFree(histogram);
     1232                psFree(cumulative);
     1233                psFree(mask);
     1234                psTrace(__func__, 4, "---- %s(false) end  ----\n", __func__);
     1235                return false;
     1236            }
     1237        }
     1238        psTrace(__func__, 6, "The median bin is %d (%.2f to %.2f)\n", binMedian,
     1239                cumulative->bounds->data.F32[binMedian], cumulative->bounds->data.F32[binMedian+1]);
     1240
     1241        // ADD step 3: Interpolate to the exact 50% position: this is the robust histogram median.
     1242        stats->robustMedian = fitQuadraticSearchForYThenReturnX(cumulative->bounds, cumulative->nums,
     1243                              binMedian, totalDataPoints/2.0);
    15051244        if (isnan(stats->robustMedian)) {
    1506             psError(PS_ERR_UNKNOWN, false, "Failed to fit a quadratic and calculate the 50-percent position.\n");
    1507             psFree(tmpStatsMinMax);
    1508             psFree(robustHistogram);
    1509             psFree(cumulativeRobustHistogram);
    1510             psFree(tmpMaskVec);
    1511             psTrace(__func__, 4, "---- %s(1) end  ----\n", __func__);
    1512             return(1);
     1245            psError(PS_ERR_UNKNOWN, false,
     1246                    "Failed to fit a quadratic and calculate the 50-percent position.\n");
     1247            psFree(statsMinMax);
     1248            psFree(histogram);
     1249            psFree(cumulative);
     1250            psFree(mask);
     1251            psTrace(__func__, 4, "---- %s(false) end  ----\n", __func__);
     1252            return false;
    15131253        }
    15141254        psTrace(__func__, 6, "Current robust median is %f\n", stats->robustMedian);
    15151255
    1516         //
    1517         // ADD: Step 4.
    1518         // Find the bins which contains the 15.8655% and 84.1345% data points.
    1519         //
    1520         psS32 binLo = 0;
    1521         psS32 binHi = 0;
     1256        // ADD step 4: Find the bins which contains the 15.8655% and 84.1345% data points.
     1257        long binLo = 0;                 // Bin containing the 15.8655% mark
    15221258        tmpScalar.data.F32 = totalDataPoints * 0.158655f;
    1523         if (tmpScalar.data.F32 <= cumulativeRobustHistogram->nums->data.F32[0]) {
    1524             binLo = 0;
    1525         } else {
     1259        if (tmpScalar.data.F32 > cumulative->nums->data.F32[0]) {
    15261260            // NOTE: the (+1) here is because of the way p_psVectorBinDisect is defined.
    1527             binLo = 1 + p_psVectorBinDisect(cumulativeRobustHistogram->nums, &tmpScalar);
    1528             if (binLo > cumulativeRobustHistogram->nums->n-1) {
    1529                 binLo = cumulativeRobustHistogram->nums->n-1;
    1530             }
    1531         }
     1261            binLo = 1 + p_psVectorBinDisect(cumulative->nums, &tmpScalar);
     1262            if (binLo > cumulative->nums->n-1) {
     1263                binLo = cumulative->nums->n-1;
     1264            }
     1265        }
     1266
     1267        long binHi = 0;                 // Bin containing the 84.1345% mark
    15321268        tmpScalar.data.F32 = totalDataPoints * 0.841345f;
    1533         if (tmpScalar.data.F32 <= cumulativeRobustHistogram->nums->data.F32[0]) {
    1534             binHi = 0;
    1535         } else {
     1269        if (tmpScalar.data.F32 > cumulative->nums->data.F32[0]) {
    15361270            // NOTE: the (+1) here is because of the way p_psVectorBinDisect is defined.
    1537             binHi = 1 + p_psVectorBinDisect(cumulativeRobustHistogram->nums, &tmpScalar);
    1538             if (binHi > cumulativeRobustHistogram->nums->n-1) {
    1539                 binHi = cumulativeRobustHistogram->nums->n-1;
    1540             }
    1541         }
    1542         psTrace(__func__, 6, "The 15.8655-percent and 84.1345-percent data point bins are (%d, %d).\n",
     1271            binHi = 1 + p_psVectorBinDisect(cumulative->nums, &tmpScalar);
     1272            if (binHi > cumulative->nums->n-1) {
     1273                binHi = cumulative->nums->n-1;
     1274            }
     1275        }
     1276        psTrace(__func__, 6, "The 15.8655%% and 84.1345%% data point bins are (%d, %d).\n",
    15431277                binLo, binHi);
    1544         psTrace(__func__, 6, "binLo midpoint is %f\n", PS_BIN_MIDPOINT(cumulativeRobustHistogram, binLo));
    1545         psTrace(__func__, 6, "binHi midpoint is %f\n", PS_BIN_MIDPOINT(cumulativeRobustHistogram, binHi));
     1278        psTrace(__func__, 6, "binLo midpoint is %f\n", PS_BIN_MIDPOINT(cumulative, binLo));
     1279        psTrace(__func__, 6, "binHi midpoint is %f\n", PS_BIN_MIDPOINT(cumulative, binHi));
    15461280
    15471281        if ((binLo < 0) || (binHi < 0)) {
    1548             psError(PS_ERR_UNKNOWN, false, "Failed to calculate the 15.8655 and 84.1345 percent data point\n");
    1549             psFree(tmpStatsMinMax);
    1550             psFree(robustHistogram);
    1551             psFree(cumulativeRobustHistogram);
    1552             psFree(tmpMaskVec);
    1553             psTrace(__func__, 4, "---- %s(1) end  ----\n", __func__);
    1554             return(1);
    1555         }
    1556 
    1557         //
    1558         // ADD: Step 4b.
    1559         // Interpolate Sigma to find these two positions exactly: these are the 1sigma positions.
    1560         //
    1561         // XXX: I am overriding the ADD for now.  The following code implements
    1562         // the ADD exactly and is having problems fitting a 2nd-order polynomial
    1563         // to data y-values suchs as (1, 1, 100).  Therefore, I commented out the
    1564         // code and am doing simply linear interpolation.
    1565         //
    1566         psF32 binLoF32;
    1567         psF32 binHiF32;
    1568         if (0) {
    1569             binLoF32 = fitQuadraticSearchForYThenReturnX(
    1570                            *(psVector* *)&cumulativeRobustHistogram->bounds,
    1571                            *(psVector* *)&cumulativeRobustHistogram->nums,
    1572                            binLo,
    1573                            totalDataPoints * 0.158655f);
    1574             binHiF32 = fitQuadraticSearchForYThenReturnX(
    1575                            *(psVector* *)&cumulativeRobustHistogram->bounds,
    1576                            *(psVector* *)&cumulativeRobustHistogram->nums,
    1577                            binHi,
    1578                            totalDataPoints * 0.841345f);
    1579             psTrace(__func__, 6, "The exact 15.8655 and 84.1345 percent data point positions are: (%f, %f)\n",
    1580                     binLoF32, binHiF32);
    1581         }
    1582 
    1583         //
     1282            psError(PS_ERR_UNKNOWN, false, "Failed to calculate the 15.8655%% and 84.1345%% data points.\n");
     1283            psFree(statsMinMax);
     1284            psFree(histogram);
     1285            psFree(cumulative);
     1286            psFree(mask);
     1287            psTrace(__func__, 4, "---- %s(false) end  ----\n", __func__);
     1288            return false;
     1289        }
     1290
     1291        // ADD step 4b: Interpolate Sigma to find these two positions exactly: these are the 1sigma positions.
     1292        #if 0
     1293        // XXX: I am overriding the ADD for now.  The following code implements the ADD exactly and is having
     1294        // problems fitting a 2nd-order polynomial to data y-values suchs as (1, 1, 100).  Therefore, I
     1295        // commented out the code and am doing simply linear interpolation.
     1296
     1297        // Value for the 15.8655% mark
     1298        float binLoF32 = fitQuadraticSearchForYThenReturnX(cumulative->bounds, cumulative->nums, binLo,
     1299                         totalDataPoints * 0.158655f);
     1300        // Value for the 84.1345% mark
     1301        float binHiF32 = fitQuadraticSearchForYThenReturnX(cumulative->bounds, cumulative->nums, binHi,
     1302                         totalDataPoints * 0.841345f);
     1303        psTrace(__func__, 6, "The exact 15.8655%% and 84.1345%% data point positions are: (%f, %f)\n",
     1304                binLoF32, binHiF32);
     1305        #else
    15841306        // This code basically interpolates to find the positions exactly.
    1585         //
    1586         if (1) {
    1587             psTrace(__func__, 6, "binLo is %d.  Nums at that bin and the next are (%.2f, %.2f)\n",
    1588                     binLo, cumulativeRobustHistogram->nums->data.F32[binLo],
    1589                     cumulativeRobustHistogram->nums->data.F32[binLo+1]);
    1590             psTrace(__func__, 6, "binHi is %d.  Nums at that bin and the next are (%.2f, %.2f)\n",
    1591                     binHi, cumulativeRobustHistogram->nums->data.F32[binHi],
    1592                     cumulativeRobustHistogram->nums->data.F32[binHi+1]);
    1593 
    1594             psF32 deltaNums;
    1595             psF32 deltaBounds;
    1596             psF32 prevPixels;
    1597             psF32 percentNums;
    1598             psF32 base;
    1599             deltaBounds = cumulativeRobustHistogram->bounds->data.F32[binLo+1] - cumulativeRobustHistogram->bounds->data.F32[binLo];
    1600             if (binLo == 0) {
    1601                 deltaNums = cumulativeRobustHistogram->nums->data.F32[0];
    1602                 prevPixels = 0;
    1603             } else {
    1604                 deltaNums = cumulativeRobustHistogram->nums->data.F32[binLo] - cumulativeRobustHistogram->nums->data.F32[binLo-1];
    1605                 prevPixels = cumulativeRobustHistogram->nums->data.F32[binLo-1];
    1606             }
    1607             percentNums = (totalDataPoints * 0.158655f) - prevPixels;
    1608             base = cumulativeRobustHistogram->bounds->data.F32[binLo];
    1609             binLoF32 = base + (deltaBounds / deltaNums) * percentNums;
    1610             psTrace(__func__, 6, "(base, deltaBounds, deltaNums, prevPixels, percentNums) is (%.2f %.2f %.2f %.2f %.2f)\n",
    1611                     base, deltaBounds, deltaNums, prevPixels, percentNums);
    1612 
    1613             deltaBounds = cumulativeRobustHistogram->bounds->data.F32[binHi+1] - cumulativeRobustHistogram->bounds->data.F32[binHi];
    1614             if (binHi == 0) {
    1615                 deltaNums = cumulativeRobustHistogram->nums->data.F32[0];
    1616                 prevPixels = 0;
    1617             } else {
    1618                 deltaNums = cumulativeRobustHistogram->nums->data.F32[binHi] - cumulativeRobustHistogram->nums->data.F32[binHi-1];
    1619                 prevPixels = cumulativeRobustHistogram->nums->data.F32[binHi-1];
    1620             }
    1621             percentNums = (totalDataPoints * 0.841345f) - prevPixels;
    1622             base = cumulativeRobustHistogram->bounds->data.F32[binHi];
    1623             binHiF32 = base + (deltaBounds / deltaNums) * percentNums;
    1624             psTrace(__func__, 6, "(base, deltaBounds, deltaNums, prevPixels, percentNums) is (%.2f %.2f %.2f %.2f %.2f)\n",
    1625                     base, deltaBounds, deltaNums, prevPixels, percentNums);
    1626             psTrace(__func__, 6, "The exact 15.8655 and 84.1345 percent data point positions are: (%f, %f)\n", binLoF32, binHiF32);
    1627         }
    1628 
    1629         //
    1630         // ADD: Step 5.
    1631         // Determine SIGMA as 1/2 of the distance between these positions.
    1632         //
     1307        psTrace(__func__, 6, "binLo is %d.  Nums at that bin and the next are (%.2f, %.2f)\n",
     1308                binLo, cumulative->nums->data.F32[binLo], cumulative->nums->data.F32[binLo+1]);
     1309        psTrace(__func__, 6, "binHi is %d.  Nums at that bin and the next are (%.2f, %.2f)\n",
     1310                binHi, cumulative->nums->data.F32[binHi], cumulative->nums->data.F32[binHi+1]);
     1311
     1312        float deltaBounds = cumulative->bounds->data.F32[binLo+1] - cumulative->bounds->data.F32[binLo];
     1313        float deltaNums;
     1314        float prevPixels;
     1315        if (binLo == 0) {
     1316            deltaNums = cumulative->nums->data.F32[0];
     1317            prevPixels = 0;
     1318        } else {
     1319            deltaNums = cumulative->nums->data.F32[binLo] - cumulative->nums->data.F32[binLo-1];
     1320            prevPixels = cumulative->nums->data.F32[binLo-1];
     1321        }
     1322        float percentNums = (totalDataPoints * 0.158655f) - prevPixels;
     1323        float base = cumulative->bounds->data.F32[binLo];
     1324        float binLoF32 = base + (deltaBounds / deltaNums) * percentNums; // Value for the 15.8655% mark
     1325        psTrace(__func__, 6,
     1326                "(base, deltaBounds, deltaNums, prevPixels, percentNums) is (%.2f %.2f %.2f %.2f %.2f)\n",
     1327                base, deltaBounds, deltaNums, prevPixels, percentNums);
     1328
     1329        deltaBounds = cumulative->bounds->data.F32[binHi+1] - cumulative->bounds->data.F32[binHi];
     1330        if (binHi == 0) {
     1331            deltaNums = cumulative->nums->data.F32[0];
     1332            prevPixels = 0;
     1333        } else {
     1334            deltaNums = cumulative->nums->data.F32[binHi] - cumulative->nums->data.F32[binHi-1];
     1335            prevPixels = cumulative->nums->data.F32[binHi-1];
     1336        }
     1337        percentNums = (totalDataPoints * 0.841345f) - prevPixels;
     1338        base = cumulative->bounds->data.F32[binHi];
     1339        float binHiF32 = base + (deltaBounds / deltaNums) * percentNums; // Value for the 84.1345% mark
     1340        psTrace(__func__, 6,
     1341                "(base, deltaBounds, deltaNums, prevPixels, percentNums) is (%.2f %.2f %.2f %.2f %.2f)\n",
     1342                base, deltaBounds, deltaNums, prevPixels, percentNums);
     1343        psTrace(__func__, 6,
     1344                "The exact 15.8655 and 84.1345 percent data point positions are: (%f, %f)\n",
     1345                binLoF32, binHiF32);
     1346        #endif
     1347
     1348        // ADD step 5: Determine SIGMA as 1/2 of the distance between these positions.
    16331349        sigma = (binHiF32 - binLoF32) / 2.0;
    16341350        psTrace(__func__, 6, "The current sigma is %f.\n", sigma);
    16351351        stats->robustStdev = sigma;
    16361352
    1637         //
    1638         // ADD: Step 6.
    1639         // If the measured SIGMA is less than 2 times the bin size, exclude
    1640         // points which are more than 25 bins from the median,
    1641         // recalculate the bin size, and perform the algorithm again.
    1642         //
     1353        // ADD step 6: If the measured SIGMA is less than 2 times the bin size, exclude points which are more
     1354        // than 25 bins from the median, recalculate the bin size, and perform the algorithm again.
    16431355        if (sigma < (2 * binSize)) {
    16441356            psTrace(__func__, 6, "*************: Do another iteration (%f %f).\n", sigma, binSize);
    1645             psS32 maskLo = PS_MAX(0, (binMedian - 25));
    1646             psS32 maskHi = PS_MIN(robustHistogram->bounds->n - 1, (binMedian + 25));
    1647             psF32 medianLo = robustHistogram->bounds->data.F32[maskLo];
    1648             psF32 medianHi = robustHistogram->bounds->data.F32[maskHi];
    1649             psTrace(__func__, 6, "Masking data more than 25 bins from the median (%.2f)\n", stats->robustMedian);
    1650             psTrace(__func__, 6, "The median is at bin number %d.  We mask bins outside the bin range (%d:%d)\n",
     1357            long maskLo = PS_MAX(0, (binMedian - 25)); // Low index for masking region
     1358            long maskHi = PS_MIN(histogram->bounds->n - 1, (binMedian + 25)); // High index for masking
     1359            psF32 medianLo = histogram->bounds->data.F32[maskLo]; // Value at low index
     1360            psF32 medianHi = histogram->bounds->data.F32[maskHi]; // Value at high index
     1361            psTrace(__func__, 6, "Masking data more than 25 bins from the median\n");
     1362            psTrace(__func__, 6,
     1363                    "The median is at bin number %d.  We mask bins outside the bin range (%d:%d)\n",
    16511364                    binMedian, maskLo, maskHi);
    16521365            psTrace(__func__, 6, "Masking data outside (%f %f)\n", medianLo, medianHi);
    1653             for (psS32 i = 0 ; i < myVector->n ; i++) {
     1366            for (long i = 0 ; i < myVector->n ; i++) {
    16541367                if ((myVector->data.F32[i] < medianLo) || (myVector->data.F32[i] > medianHi)) {
    1655                     tmpMaskVec->data.U8[i] = 1;
     1368                    mask->data.U8[i] = 0xff;
    16561369                    psTrace(__func__, 6, "Masking element %d is %f\n", i, myVector->data.F32[i]);
    16571370                }
    16581371            }
    1659             psFree(robustHistogram);
    1660             psFree(cumulativeRobustHistogram);
    1661             iterate++;
    1662         } else {
     1372            // Free the histograms; they will be recreated on the next iteration, with new bounds
     1373            psFree(histogram);
     1374            psFree(cumulative);
     1375        } else {
     1376            // We've got the bin size correct now
    16631377            psTrace(__func__, 6, "*************: No more iteration.  sigma is %f\n", sigma);
    1664             iterate = 0;
    1665         }
    1666     }
    1667 
    1668     //
    1669     // ADD: Step 7.
    1670     // Find the bins which contains the 25% and 75% data points.
    1671     //
    1672     psS32 binLo25 = 0;
    1673     psS32 binHi25 = 0;
     1378            iterate = -1;
     1379        }
     1380    }
     1381    psFree(histogram);
     1382
     1383    // ADD step 7: Find the bins which contains the 25% and 75% data points.
     1384    long binLo25 = 0;                   // Bin containing the 25% value
     1385    long binHi25 = 0;                   // Bin containing the 75% value
    16741386
    16751387    tmpScalar.data.F32 = totalDataPoints * 0.25f;
    1676     if (tmpScalar.data.F32 <= cumulativeRobustHistogram->nums->data.F32[0]) {
     1388    if (tmpScalar.data.F32 <= cumulative->nums->data.F32[0]) {
    16771389        // Special case where its in first bin.  The last bin should be handled automatically.
    16781390        binLo25 = 0;
    16791391    } else {
    1680         binLo25 = 1 + p_psVectorBinDisect(cumulativeRobustHistogram->nums, &tmpScalar);
     1392        binLo25 = 1 + p_psVectorBinDisect(cumulative->nums, &tmpScalar);
    16811393    }
    16821394    tmpScalar.data.F32 = totalDataPoints * 0.75f;
    1683     if (tmpScalar.data.F32 <= cumulativeRobustHistogram->nums->data.F32[0]) {
     1395    if (tmpScalar.data.F32 <= cumulative->nums->data.F32[0]) {
    16841396        // Special case where its in first bin.  The last bin should be handled automatically.
    16851397        binHi25 = 0;
    16861398    } else {
    1687         binHi25 = 1 + p_psVectorBinDisect(cumulativeRobustHistogram->nums, &tmpScalar);
     1399        binHi25 = 1 + p_psVectorBinDisect(cumulative->nums, &tmpScalar);
    16881400    }
    16891401    if ((binLo25 < 0) || (binHi25 < 0)) {
    16901402        psError(PS_ERR_UNKNOWN, false, "Failed to calculate the 25 and 75 percent data points\n");
    1691         psFree(tmpStatsMinMax);
    1692         psFree(robustHistogram);
    1693         psFree(cumulativeRobustHistogram);
    1694         psFree(tmpMaskVec);
     1403        psFree(statsMinMax);
     1404        psFree(cumulative);
     1405        psFree(mask);
     1406        psTrace(__func__, 4, "---- %s(false) end  ----\n", __func__);
     1407        return false;
     1408    }
     1409    psTrace(__func__, 6, "The 25-percent and 75-precent data point bins are (%d, %d).\n", binLo25, binHi25);
     1410
     1411    // ADD step 8: Interpolate to find these two positions exactly: these are the upper and lower quartile
     1412    // positions.
     1413    psF32 binLo25F32 = fitQuadraticSearchForYThenReturnX(cumulative->bounds, cumulative->nums,
     1414                       binLo25, totalDataPoints * 0.25f);
     1415    psF32 binHi25F32 = fitQuadraticSearchForYThenReturnX(cumulative->bounds, cumulative->nums,
     1416                       binHi25, totalDataPoints * 0.75f);
     1417    psFree(cumulative);
     1418
     1419    if (isnan(binLo25F32) || isnan(binHi25F32)) {
     1420        psError(PS_ERR_UNKNOWN, false,
     1421                "could not determine the robustUQ: fitQuadraticSearchForYThenReturnX() returned a NAN.\n");
     1422        psFree(statsMinMax);
     1423        psFree(mask);
    16951424        psTrace(__func__, 4, "---- %s(1) end  ----\n", __func__);
    1696         return(1);
    1697     }
    1698     psTrace(__func__, 6, "The 25-percent and 75-precent data point bins are (%d, %d).\n", binLo25, binHi25);
    1699 
    1700     //
    1701     // ADD: Step 8.
    1702     // Interpolate to find these two positions exactly: these are the upper
    1703     // and lower quartile positions.
    1704     //
    1705     psF32 binLo25F32 = fitQuadraticSearchForYThenReturnX(
    1706                            *(psVector* *)&cumulativeRobustHistogram->bounds,
    1707                            *(psVector* *)&cumulativeRobustHistogram->nums,
    1708                            binLo25,
    1709                            totalDataPoints * 0.25f);
    1710 
    1711     psF32 binHi25F32 = fitQuadraticSearchForYThenReturnX(
    1712                            *(psVector* *)&cumulativeRobustHistogram->bounds,
    1713                            *(psVector* *)&cumulativeRobustHistogram->nums,
    1714                            binHi25,
    1715                            totalDataPoints * 0.75f);
    1716 
    1717     if (isnan(binLo25F32) || isnan(binHi25F32)) {
    1718         psError(PS_ERR_UNKNOWN, false, "could not determine the robustUQ: fitQuadraticSearchForYThenReturnX() returned a NAN.\n");
    1719         psFree(tmpStatsMinMax);
    1720         psFree(robustHistogram);
    1721         psFree(cumulativeRobustHistogram);
    1722         psFree(tmpMaskVec);
    1723         psTrace(__func__, 4, "---- %s(1) end  ----\n", __func__);
    1724         return(1);
     1425        return false;
    17251426    }
    17261427
    17271428    stats->robustLQ = binLo25F32;
    17281429    stats->robustUQ = binHi25F32;
    1729     psTrace(__func__, 6, "The 25 and 75 percent data point exact positions are (%f, %f).\n", binLo25F32, binHi25F32);
    1730     psS32 N50 = 0;
    1731     for (psS32 i = 0 ; i < myVector->n ; i++) {
    1732         // XXX: use maskVal here?
    1733         if ((0 == tmpMaskVec->data.U8[i]) &&
    1734                 (binLo25F32 <= myVector->data.F32[i]) &&
    1735                 (binHi25F32 >= myVector->data.F32[i])) {
     1430    psTrace(__func__, 6, "The 25 and 75 percent data point exact positions are (%f, %f).\n",
     1431            binLo25F32, binHi25F32);
     1432    long N50 = 0;
     1433    for (long i = 0 ; i < myVector->n ; i++) {
     1434        if (!(mask->data.U8[i] & maskVal) &&
     1435                (binLo25F32 <= myVector->data.F32[i]) && (binHi25F32 >= myVector->data.F32[i])) {
    17361436            N50++;
    17371437        }
     
    17401440    psTrace(__func__, 6, "The robustN50 is %d.\n", N50);
    17411441
    1742     // ************************************************************************
    1743     if ((stats->options & PS_STAT_FITTED_MEAN) ||
    1744             (stats->options & PS_STAT_FITTED_STDEV)) {
    1745         //
     1442
     1443    // Fitted statistics
     1444    if (stats->options & PS_STAT_FITTED_MEAN || stats->options & PS_STAT_FITTED_STDEV) {
    17461445        // New algorithm for calculated mean and stdev.
    1747         //
    17481446
    17491447        // XXX: Where is this documented?
    1750         psF32 dN = (psF32) (0.17 * N50);
     1448        psF32 dN = 0.17 * N50;
    17511449        if (dN < 1.0) {
    17521450            dN = 1.0;
     
    17561454        psF32 newBinSize = sigma / dN;
    17571455
    1758         //
    17591456        // Determine the min/max of the vector (which prior outliers masked out)
    1760         //
    1761         rc = p_psVectorMin(myVector, tmpMaskVec, 1 | maskVal, tmpStatsMinMax);
    1762         rc|= p_psVectorMax(myVector, tmpMaskVec, 1 | maskVal, tmpStatsMinMax);
    1763         if ((rc != 0) || isnan(tmpStatsMinMax->min) || isnan(tmpStatsMinMax->max)) {
     1457        int numValid = vectorMinMax(myVector, mask, maskVal, statsMinMax); // Number of values
     1458        min = statsMinMax->min;
     1459        max = statsMinMax->max;
     1460        if (numValid == 0 || isnan(min) || isnan(max)) {
    17641461            psError(PS_ERR_UNKNOWN, false, "Failed to calculate the min/max of the input vector.\n");
    1765             psFree(tmpStatsMinMax);
    1766             psFree(robustHistogram);
    1767             psFree(cumulativeRobustHistogram);
    1768             psFree(tmpMaskVec);
    1769             psTrace(__func__, 4, "---- %s(1) end  ----\n", __func__);
    1770             return(1);
    1771         }
    1772 
    1773         //
     1462            psFree(statsMinMax);
     1463            psFree(mask);
     1464            psTrace(__func__, 4, "---- %s(false) end  ----\n", __func__);
     1465            return false;
     1466        }
     1467
    17741468        // Calculate the number of bins.
    1775         //
    1776         numBins = (psS32)((tmpStatsMinMax->max - tmpStatsMinMax->min) / newBinSize);
    1777         psTrace(__func__, 6, "The new min/max values are (%f, %f).\n", tmpStatsMinMax->min, tmpStatsMinMax->max);
     1469        long numBins = (max - min) / newBinSize;
     1470        psTrace(__func__, 6, "The new min/max values are (%f, %f).\n", min, max);
    17781471        psTrace(__func__, 6, "The new bin size is %f.\n", newBinSize);
    17791472        psTrace(__func__, 6, "The numBins is %d\n", numBins);
    17801473
    1781         psHistogram *newHistogram = psHistogramAlloc(tmpStatsMinMax->min, tmpStatsMinMax->max, numBins);
    1782         newHistogram = psVectorHistogram(newHistogram, myVector, errors, tmpMaskVec, maskVal|1);
     1474        psHistogram *histogram = psHistogramAlloc(min, max, numBins); // A new histogram (without outliers)
     1475        histogram = psVectorHistogram(histogram, myVector, errors, mask, maskVal);
    17831476        if (psTraceGetLevel(__func__) >= 8) {
    1784             PS_VECTOR_PRINT_F32(newHistogram->nums);
    1785         }
    1786 
    1787         //
    1788         // FITTED STATISTICS HERE
    1789         //
    1790         // Smooth the resulting histogram with a Gaussian with sigma_s = 1
    1791         // bin.
    1792         //
    1793         psF32 sigma_s = newBinSize;
    1794 
    1795         psVector *newHistogramSmoothed = p_psVectorSmoothHistGaussian(newHistogram, sigma_s);
     1477            PS_VECTOR_PRINT_F32(histogram->nums);
     1478        }
     1479
     1480        // Smooth the resulting histogram with a Gaussian with sigma_s = 1 bin.
     1481        psVector *smoothed = vectorSmoothHistGaussian(histogram, newBinSize); // Smoothed histogram
    17961482        if (psTraceGetLevel(__func__) >= 8) {
    1797             PS_VECTOR_PRINT_F32(newHistogramSmoothed);
    1798         }
    1799 
    1800         //
    1801         // Find the bin with the peak value in the range 2 sigma of the
    1802         // robust histogram median.
    1803         //
    1804 
    1805         psS32 binMin = 0;
    1806         psS32 binMax = 0;
     1483            PS_VECTOR_PRINT_F32(smoothed);
     1484        }
     1485
     1486        // Find the bin with the peak value in the range 2 sigma of the robust histogram median.
     1487        long binMin = 0;                // Low bin to check
     1488        long binMax = 0;                // High bin to check
    18071489        tmpScalar.data.F32 = stats->robustMedian - (2.0 * sigma);
    1808         if (tmpScalar.data.F32 <= newHistogram->bounds->data.F32[0]) {
     1490        if (tmpScalar.data.F32 <= histogram->bounds->data.F32[0]) {
    18091491            binMin = 0;
    18101492        } else {
    1811             binMin = p_psVectorBinDisect((psVector *) newHistogram->bounds, &tmpScalar);
     1493            binMin = p_psVectorBinDisect(histogram->bounds, &tmpScalar);
    18121494        }
    18131495
    18141496        tmpScalar.data.F32 = stats->robustMedian + (2.0 + sigma);
    1815         if (tmpScalar.data.F32 >= newHistogram->bounds->data.F32[newHistogram->bounds->n-1]) {
    1816             binMax = newHistogram->bounds->n-1;
    1817         } else {
    1818             binMax = p_psVectorBinDisect((psVector *) newHistogram->bounds, &tmpScalar);
     1497        if (tmpScalar.data.F32 >= histogram->bounds->data.F32[histogram->bounds->n-1]) {
     1498            binMax = histogram->bounds->n-1;
     1499        } else {
     1500            binMax = p_psVectorBinDisect(histogram->bounds, &tmpScalar);
    18191501        }
    18201502        if ((binMin < 0) || (binMax < 0)) {
    1821             psError(PS_ERR_UNKNOWN, false, "Failed to calculate the +- 2.0 * sigma bins\n");
    1822             psFree(tmpMaskVec);
    1823             psFree(robustHistogram);
    1824             psFree(cumulativeRobustHistogram);
    1825             psFree(tmpStatsMinMax);
    1826             psTrace(__func__, 4, "---- %s(1) end  ----\n", __func__);
    1827             return(1);
    1828         }
    1829 
    1830         psS32 binNum = binMin;
    1831         psF32 binMaxNums = newHistogramSmoothed->data.F32[binNum];
     1503            psError(PS_ERR_UNKNOWN, false, "Failed to calculate the +/- 2.0 * sigma bins\n");
     1504            psFree(statsMinMax);
     1505            psFree(histogram);
     1506            psFree(mask);
     1507            psTrace(__func__, 4, "---- %s(false) end  ----\n", __func__);
     1508            return false;
     1509        }
     1510
     1511        long binNum = binMin;           // Bin number containing the peak
     1512        psF32 binMaxNums = smoothed->data.F32[binNum]; // The peak value
    18321513        for (psS32 i = binMin+1 ; i <= binMax ; i++) {
    1833             if (newHistogramSmoothed->data.F32[i] > binMaxNums) {
     1514            if (smoothed->data.F32[i] > binMaxNums) {
    18341515                binNum = i;
    1835                 binMaxNums = newHistogramSmoothed->data.F32[i];
     1516                binMaxNums = smoothed->data.F32[i];
    18361517            }
    18371518        }
    18381519        psTrace(__func__, 6, "The peak bin is %d, with %f data.n", binNum, binMaxNums);
    18391520
    1840         //
    1841         // Fit a Gaussian to the bins in the range 20 sigma of the robust
    1842         // histogram median.
    1843         //
     1521        // Fit a Gaussian to the bins in the range 20 sigma of the robust histogram median.
    18441522        tmpScalar.data.F32 = stats->robustMedian - (20.0 * sigma);
    1845         if (tmpScalar.data.F32 < tmpStatsMinMax->min) {
     1523        if (tmpScalar.data.F32 < min) {
    18461524            binMin = 0;
    18471525        } else {
    1848             binMin = p_psVectorBinDisect((psVector *) newHistogram->bounds, &tmpScalar);
    1849             // XXX: check for errors here.
     1526            binMin = p_psVectorBinDisect(histogram->bounds, &tmpScalar);
    18501527        }
    18511528        tmpScalar.data.F32 = stats->robustMedian + (20.0 * sigma);
    1852         if (tmpScalar.data.F32 > tmpStatsMinMax->max) {
    1853             binMax = newHistogramSmoothed->n - 1;
    1854         } else {
    1855             binMax = p_psVectorBinDisect((psVector *) newHistogram->bounds, &tmpScalar);
    1856             // XXX: check for errors here.
    1857         }
    1858         psVector *y = psVectorAlloc((1 + (binMax - binMin)), PS_TYPE_F32);
    1859         psArray *x = psArrayAlloc((1 + (binMax - binMin)));
    1860         psS32 j = 0;
     1529        if (tmpScalar.data.F32 > max) {
     1530            binMax = smoothed->n - 1;
     1531        } else {
     1532            binMax = p_psVectorBinDisect(histogram->bounds, &tmpScalar);
     1533        }
     1534        if (binMin < 0 || binMax < 0) {
     1535            psError(PS_ERR_UNKNOWN, false, "Failed to calculate the +/- 20.0 * sigma bins\n");
     1536            psFree(statsMinMax);
     1537            psFree(histogram);
     1538            psFree(mask);
     1539            psTrace(__func__, 4, "---- %s(false) end  ----\n", __func__);
     1540            return false;
     1541        }
     1542
     1543        // Generate the variables that will be used in the Gaussian fitting
     1544        psVector *y = psVectorAlloc((1 + (binMax - binMin)), PS_TYPE_F32); // Vector of coordinates
     1545        psArray *x = psArrayAlloc((1 + (binMax - binMin))); // Array of ordinates
    18611546        y->n = y->nalloc;
    1862 
    1863         for (psS32 i = binMin ; i <= binMax ; i++) {
    1864             y->data.F32[j] = newHistogramSmoothed->data.F32[i];
    1865             x->data[j] = (psPtr *) psVectorAlloc(1, PS_TYPE_F32);
    1866             x->n++;
    1867             ((psVector *) x->data[j])->data.F32[0] = PS_BIN_MIDPOINT(newHistogram, i);
    1868             ((psVector *) x->data[j])->n++;
    1869             j++;
     1547        x->n = x->nalloc;
     1548        for (long i = binMin, j = 0; i <= binMax ; i++, j++) {
     1549            y->data.F32[j] = smoothed->data.F32[i];
     1550            psVector *ordinate = psVectorAlloc(1, PS_TYPE_F32); // The ordinate value
     1551            ordinate->n = 1;
     1552            ordinate->data.F32[0] = PS_BIN_MIDPOINT(histogram, i);
     1553            x->data[j] = ordinate;
    18701554        }
    18711555        if (psTraceGetLevel(__func__) >= 8) {
     
    18731557            PS_VECTOR_PRINT_F32(y);
    18741558        }
    1875 
    1876         rc = p_psVectorMin(y, NULL, 0, tmpStatsMinMax);
    1877         rc|= p_psVectorMax(y, NULL, 0, tmpStatsMinMax);
    1878         if ((rc != 0) || isnan(tmpStatsMinMax->min) || isnan(tmpStatsMinMax->max)) {
     1559        psFree(smoothed);
     1560        psFree(histogram);
     1561
     1562        numValid = vectorMinMax(y, NULL, 0, statsMinMax); // Number of valid values
     1563        min = statsMinMax->min;
     1564        max = statsMinMax->max;
     1565        if (numValid == 0 || isnan(min) || isnan(max)) {
    18791566            psError(PS_ERR_UNKNOWN, false, "Failed to calculate the min/max of the input vector.\n");
    1880             psFree(tmpMaskVec);
    1881             psFree(robustHistogram);
    1882             psFree(cumulativeRobustHistogram);
    1883             psFree(tmpStatsMinMax);
    1884             psTrace(__func__, 4, "---- %s(1) end  ----\n", __func__);
    1885             return(1);
    1886         }
    1887 
    1888         //
     1567            psFree(mask);
     1568            psFree(histogram);
     1569            psFree(statsMinMax);
     1570            psTrace(__func__, 4, "---- %s(false) end  ----\n", __func__);
     1571            return false;
     1572        }
     1573
    18891574        // Normalize y to [0.0:1.0] (since the psMinimizeLMChi2Gauss1D() functions is [0.0:1.0])
    1890         // XXX: Use the normalize routines for this.
    1891         //
    1892         for (psS32 i = 0 ; i < y->n ; i++) {
    1893             y->data.F32[i]= (y->data.F32[i] - tmpStatsMinMax->min) / (tmpStatsMinMax->max - tmpStatsMinMax->min);
    1894         }
    1895 
    1896         //
    1897         psMinimization *min = psMinimizationAlloc(100, 0.01);
    1898         psVector *params = psVectorAlloc(2, PS_TYPE_F32);
     1575        p_psNormalizeVectorRange(y, 0.0, 1.0);
     1576
     1577        // Fit a Gaussian to the data.
     1578        psMinimization *minimizer = psMinimizationAlloc(100, 0.01); // The minimizer information
     1579        psVector *params = psVectorAlloc(2, PS_TYPE_F32); // Parameters for the Gaussian
    18991580        params->n = params->nalloc;
    1900         // Initial guess for the mean ([0]) and standard dev.
     1581        // Initial guess for the mean (index 0) and standard dev (index 1).
    19011582        params->data.F32[0] = stats->robustMedian;
    19021583        params->data.F32[1] = sigma;
     
    19051586            PS_VECTOR_PRINT_F32(y);
    19061587        }
    1907 
    1908         //
    1909         // Fit a Gaussian to the data.
    1910         //
    1911         rcBool = psMinimizeLMChi2(min, NULL, params, NULL, x, y, NULL, psMinimizeLMChi2Gauss1D);
    1912         if (rcBool != true) {
     1588        if (!psMinimizeLMChi2(minimizer, NULL, params, NULL, x, y, NULL, minimizeLMChi2Gauss1D)) {
    19131589            psError(PS_ERR_UNKNOWN, false, "Failed to fit a gaussian to the robust histogram.\n");
    1914             psFree(tmpStatsMinMax);
    1915             psFree(robustHistogram);
    1916             psFree(cumulativeRobustHistogram);
    1917             psFree(newHistogram);
     1590            psFree(statsMinMax);
    19181591            psFree(x);
    19191592            psFree(y);
    1920             psFree(min);
     1593            psFree(minimizer);
    19211594            psFree(params);
    1922             psFree(tmpMaskVec);
    1923             psTrace(__func__, 4, "---- %s(1) end  ----\n", __func__);
    1924             return(1);
     1595            psFree(mask);
     1596            psTrace(__func__, 4, "---- %s(false) end  ----\n", __func__);
     1597            return false;
    19251598        }
    19261599        if (psTraceGetLevel(__func__) >= 8) {
     
    19281601        }
    19291602
    1930         //
    1931         // The fitted mean mean_r is derived directly from the fitted
    1932         // Gaussian mean.
    1933         //
     1603        // The fitted mean is the Gaussian mean.
    19341604        stats->fittedMean = params->data.F32[0];
    19351605        psTrace(__func__, 6, "The fitted mean is %f.\n", params->data.F32[0]);
    19361606
    1937         //
    1938         // The fitted standard deviation, SIGMA_r is determined by
    1939         // subtracting the smoothing scale in quadrature:
    1940         //     SIGMA_r^2 = SIGMA^2 - sigma_s^2
    1941         //
    1942         stats->fittedStdev = sqrt(PS_SQR(params->data.F32[1]) - PS_SQR(sigma_s));
     1607        // The fitted standard deviation, SIGMA_r is determined by subtracting the smoothing scale in
     1608        // quadrature: SIGMA_r^2 = SIGMA^2 - sigma_s^2
     1609        stats->fittedStdev = sqrt(PS_SQR(params->data.F32[1]) - PS_SQR(newBinSize));
    19431610        psTrace(__func__, 6, "The fitted stdev is %f.\n", stats->fittedStdev);
    19441611
    1945         psFree(newHistogramSmoothed);
    1946         psFree(newHistogram);
     1612        // Clean up after fitting
    19471613        psFree(x);
    19481614        psFree(y);
    1949         psFree(min);
     1615        psFree(minimizer);
    19501616        psFree(params);
    19511617    }
    19521618
    1953     psFree(tmpStatsMinMax);
    1954     psFree(cumulativeRobustHistogram);
    1955     psFree(tmpMaskVec);
    1956     psFree(robustHistogram);
     1619    // Clean up
     1620    psFree(statsMinMax);
     1621    psFree(mask);
    19571622
    19581623    psTrace(__func__, 4, "---- %s(0) end  ----\n", __func__);
    1959     return(0);
     1624    return true;
    19601625}
    19611626
     
    19681633static void histogramFree(psHistogram* myHist);
    19691634
     1635// We keep statsFree so that we can identify statistics pointers from the memblock
    19701636static void statsFree(psStats *newStruct)
    19711637{
     
    20381704    PS_ASSERT_FLOAT_LARGER_THAN_OR_EQUAL(upper, lower, NULL);
    20391705
    2040     psS32 i = 0;                  // Loop index variable
    2041     psHistogram* newHist = NULL;        // The new histogram structure
    2042     psF32 binSize = 0.0;        // The histogram bin size
    2043 
    2044     // Allocate memory for the new histogram structure.  If there are N
    2045     // bins, then there are N+1 bounds to those bins.
    2046     newHist = (psHistogram* ) psAlloc(sizeof(psHistogram));
     1706    // Allocate memory for the new histogram structure.  If there are N bins, then there are N+1 bounds to
     1707    // those bins.
     1708    psHistogram *newHist = (psHistogram* ) psAlloc(sizeof(psHistogram)); // The new histogram structure
    20471709    psMemSetDeallocator(newHist, (psFreeFunc) histogramFree);
    20481710    psVector* newBounds = psVectorAlloc(n + 1, PS_TYPE_F32);
     
    20511713
    20521714    // Calculate the bounds for each bin.
    2053     binSize = (upper - lower) / (psF32)n;
    2054     // XXX: Is the following necessary? It prevents the max data point
    2055     // from being in a non-existant bin.
     1715    psF32 binSize = (upper - lower) / (psF32)n; // The histogram bin size
     1716    // XXX: Is the following necessary? It prevents the max data point from being in a non-existant bin.
    20561717    binSize += FLT_EPSILON;
    2057     for (i = 0; i < n + 1; i++) {
     1718    for (long i = 0; i < n + 1; i++) {
    20581719        newBounds->data.F32[i] = lower + (binSize * (psF32)i);
    20591720    }
     
    20611722    // Allocate the bins, and initialize them to zero.
    20621723    newHist->nums = psVectorAlloc(n, PS_TYPE_F32);
    2063     for (i = 0; i < newHist->nums->nalloc; i++) {
     1724    for (long i = 0; i < newHist->nums->nalloc; i++) {
    20641725        newHist->nums->data.F32[i] = 0.0;
    20651726        newHist->nums->n++;
     
    20721733
    20731734    psTrace(__func__, 3, "---- %s() end  ----\n", __func__);
    2074     return (newHist);
     1735    return newHist;
    20751736}
    20761737
     
    20911752    PS_ASSERT_INT_LARGER_THAN_OR_EQUAL(bounds->n, 2, NULL);
    20921753
    2093     psHistogram* newHist = NULL;        // The new histogram structure
    2094     psS32 i;                      // Loop index variable
    2095 
    20961754    // Allocate memory for the new histogram structure.
    2097     newHist = (psHistogram* ) psAlloc(sizeof(psHistogram));
     1755    psHistogram *newHist = (psHistogram* ) psAlloc(sizeof(psHistogram)); // The new histogram structure
    20981756    psMemSetDeallocator(newHist, (psFreeFunc) histogramFree);
    20991757    psVector* newBounds = psVectorAlloc(bounds->n, PS_TYPE_F32);
    21001758    newHist->bounds = newBounds;
    21011759    newBounds->n = newHist->bounds->nalloc;
    2102     for (i = 0; i < bounds->n; i++) {
     1760    for (long i = 0; i < bounds->n; i++) {
    21031761        newBounds->data.F32[i] = bounds->data.F32[i];
    21041762    }
     
    21071765    // then there are N-1 bins.
    21081766    newHist->nums = psVectorAlloc((bounds->n) - 1, PS_TYPE_F32);
    2109     for (i = 0; i < newHist->nums->nalloc; i++) {
     1767    for (long i = 0; i < newHist->nums->nalloc; i++) {
    21101768        newHist->nums->data.F32[i] = 0.0;
    21111769        newHist->nums->n++;
     
    21401798the data point as a boxcar PDF and update a range of points surrounding the
    21411799histogram bin which contains the point.  The width of that boxcar is defined
    2142 as 2.35 * error.  Inputs:
    2143     binNum: the bin number of the data point in the histogram
    2144     out: the histogram structure
    2145     data: the data point value
    2146     error: the error in that data point
     1800as 2.35 * error.
    21471801 
    21481802XXX: Must test this.
    21491803 *****************************************************************************/
    2150 psS32 UpdateHistogramBins(psS32 binNum,
    2151                           psHistogram* out,
    2152                           psF32 data,
    2153                           psF32 error)
     1804static bool UpdateHistogramBins(long binNum, // Bin number of the data point
     1805                                psHistogram* out, // The histogram to be updated
     1806                                psF32 data, // The data point value
     1807                                psF32 error // The error in the data point
     1808                               )
    21541809{
    21551810    psTrace(__func__, 3, "---- %s() begin  ----\n", __func__);
    2156     PS_ASSERT_PTR_NON_NULL(out, -1);
    2157     PS_ASSERT_PTR_NON_NULL(out->bounds, -1);
    2158     PS_ASSERT_PTR_NON_NULL(out->nums, -1);
    2159     PS_ASSERT_INT_WITHIN_RANGE(binNum, 0, ((out->nums->n)-1), -2);
    2160     PS_ASSERT_FLOAT_LARGER_THAN_OR_EQUAL(error, 0.0, -3);
    2161 
    2162     PS_ASSERT_FLOAT_WITHIN_RANGE(data, out->bounds->data.F32[0], out->bounds->data.F32[(out->bounds->n)-1], -4);
    2163 
    2164     psF32 boxcarWidth = 2.35 * error;
     1811    PS_ASSERT_PTR_NON_NULL(out, false);
     1812    PS_ASSERT_PTR_NON_NULL(out->bounds, false);
     1813    PS_ASSERT_PTR_NON_NULL(out->nums, false);
     1814    PS_ASSERT_INT_WITHIN_RANGE(binNum, 0, ((out->nums->n)-1), false);
     1815    PS_ASSERT_FLOAT_LARGER_THAN_OR_EQUAL(error, 0.0, false);
     1816    PS_ASSERT_FLOAT_WITHIN_RANGE(data, out->bounds->data.F32[0],
     1817                                 out->bounds->data.F32[(out->bounds->n)-1], false);
     1818
     1819    psF32 boxcarWidth = 2.35 * error;   // Width of the boxcar
    21651820    psF32 boxcarCenter = (out->bounds->data.F32[binNum] +
    2166                           out->bounds->data.F32[binNum+1]) / 2.0;
    2167     psF32 boxcarLeft = boxcarCenter - (boxcarWidth / 2.0);
    2168     psF32 boxcarRight = boxcarCenter + (boxcarWidth / 2.0);
    2169     psS32 bin;
    2170     psS32 boxcarLeftBinNum = 0;
    2171     psS32 boxcarRightBinNum = 0;
     1821                          out->bounds->data.F32[binNum+1]) / 2.0; // Centre of the boxcar
     1822    psF32 boxcarLeft = boxcarCenter - (boxcarWidth / 2.0); // Left endpoint of the boxcar for the PDF
     1823    psF32 boxcarRight = boxcarCenter + (boxcarWidth / 2.0); // Right endpoint of the boxcar for the PDF
     1824    psS32 boxcarLeftBinNum = 0;         // Bin number for left endpoint
     1825    psS32 boxcarRightBinNum = 0;        // Bin number for right endpoint
    21721826
    21731827    // Determine the left endpoint of the boxcar for the PDF.
    2174     for (bin=binNum ; bin >= 0 ; bin--) {
     1828    for (long bin = binNum; bin >= 0; bin--) {
    21751829        if (out->nums->data.F32[bin] <= boxcarLeft) {
    21761830            boxcarLeftBinNum = bin;
     
    21801834
    21811835    // Determine the right endpoint of the boxcar for the PDF.
    2182     for (bin=binNum ; bin < out->nums->n ; bin++) {
     1836    for (long bin = binNum; bin < out->nums->n; bin++) {
    21831837        if (out->nums->data.F32[bin] >= boxcarRight) {
    21841838            boxcarRightBinNum = bin;
     
    21871841    }
    21881842
    2189     //
    21901843    // If the boxcar fits entirely inside this bin, then simply add 1.0 to the
    21911844    // bin and return.
    2192     //
    21931845    if (boxcarLeftBinNum == boxcarRightBinNum) {
    2194         out->nums->data.F32[binNum]+= 1.0;
    2195         psTrace(__func__, 3, "---- %s(0) end  ----\n", __func__);
    2196         return(0);
    2197     }
    2198 
    2199     //
    2200     // If we get here, multiple bins must be updated.  We handle the left
    2201     // endpoint, and right endpoint differently.
    2202     //
    2203     out->nums->data.F32[boxcarLeftBinNum]+=
     1846        out->nums->data.F32[binNum] += 1.0;
     1847        psTrace(__func__, 3, "---- %s(true) end  ----\n", __func__);
     1848        return true;
     1849    }
     1850
     1851    // If we get here, multiple bins must be updated.  We handle the left-most endpoint, and right-most
     1852    // endpoints differently.
     1853    out->nums->data.F32[boxcarLeftBinNum] +=
    22041854        (out->bounds->data.F32[boxcarLeftBinNum+1] - boxcarLeft) / boxcarWidth;
    22051855
    2206     //
    22071856    // Loop through the center bins, if any.
    2208     //
    2209     for (bin = boxcarLeftBinNum + 1 ; bin < (boxcarRightBinNum - 1) ; bin++) {
    2210         out->nums->data.F32[bin]+=
     1857    for (long bin = boxcarLeftBinNum + 1; bin < (boxcarRightBinNum - 1); bin++) {
     1858        out->nums->data.F32[bin] +=
    22111859            (out->bounds->data.F32[bin+1] - out->bounds->data.F32[bin]) / boxcarWidth;
    22121860    }
    22131861
    2214     //
    22151862    // Handle the right endpoint differently.
    2216     //
    22171863    out->nums->data.F32[boxcarRightBinNum]+=
    22181864        (boxcarRight - out->bounds->data.F32[boxcarRightBinNum]) / boxcarWidth;
    22191865
    2220     //
    2221     // Return 0 on success.
    2222     //
    2223     psTrace(__func__, 3, "---- %s(0) end  ----\n", __func__);
    2224     return(0);
     1866    psTrace(__func__, 3, "---- %s(true) end  ----\n", __func__);
     1867    return true;
    22251868}
    22261869
     
    22551898    PS_ASSERT_INT_NONNEGATIVE(out->nums->n, NULL);
    22561899    PS_ASSERT_VECTOR_NON_NULL(values, out);
    2257     if (mask != NULL) {
     1900    if (mask) {
    22581901        PS_ASSERT_VECTORS_SIZE_EQUAL(values, mask, NULL);
    22591902        PS_ASSERT_VECTOR_TYPE(mask, PS_TYPE_U8, NULL);
    22601903    }
    2261     if (errors != NULL) {
     1904    if (errors) {
    22621905        PS_ASSERT_VECTORS_SIZE_EQUAL(values, errors, NULL);
    22631906        PS_ASSERT_VECTOR_TYPE(errors, values->type.type, NULL);
    22641907    }
    22651908
    2266     psS32 i = 0;                  // Loop index variable
    2267     psF32 binSize = 0.0;          // Histogram bin size
    2268     psS32 binNum = 0;             // A temporary bin number
    2269     psS32 numBins = 0;            // The total number of bins
     1909    long binNum = 0;                    // A temporary bin number
     1910    long numBins = out->nums->n;        // The total number of bins
    22701911    psScalar tmpScalar;
    22711912    tmpScalar.type.type = PS_TYPE_F32;
    2272     psVector* inF32 = NULL;
    2273     psVector* errorsF32 = NULL;
    2274     psS32 mustFreeVectorIn = 1;
    2275     psS32 mustFreeVectorErrors = 1;
    22761913
    22771914    // Convert input and errors vectors to F32 if necessary.
    2278     inF32 = p_psConvertToF32((psVector *) values);
    2279     if (inF32 == NULL) {
    2280         inF32 = (psVector *) values;
    2281         mustFreeVectorIn = 0;
    2282     }
    2283     errorsF32 = p_psConvertToF32((psVector *) errors);
    2284     if (errorsF32 == NULL) {
    2285         errorsF32 = (psVector *) errors;
    2286         mustFreeVectorErrors = 0;
    2287     }
    2288 
    2289     numBins = out->nums->n;
    2290     for (i = 0; i < inF32->n; i++) {
     1915    psVector* inF32 = NULL;             // F32 version of input vector
     1916    if (values->type.type == PS_TYPE_F32) {
     1917        inF32 = psMemIncrRefCounter((psPtr)values);
     1918    } else {
     1919        values = psVectorCopy(NULL, values, PS_TYPE_F32);
     1920    }
     1921    psVector* errorsF32 = NULL;         // F32 version of errors vector
     1922    if (errors) {
     1923        if (errors->type.type == PS_TYPE_F32) {
     1924            errorsF32 = psMemIncrRefCounter((psPtr)errors);
     1925        } else {
     1926            errorsF32 = psVectorCopy(NULL, errors, PS_TYPE_F32);
     1927        }
     1928    }
     1929
     1930    for (long i = 0; i < inF32->n; i++) {
    22911931        // Check if this pixel is masked, and if so, skip it.
    2292         if ((mask == NULL) || ((mask != NULL) && (!(mask->data.U8[i] & maskVal)))) {
     1932        if (!mask || (mask && (!(mask->data.U8[i] & maskVal)))) {
    22931933            if (inF32->data.F32[i] < out->bounds->data.F32[0]) {
    22941934                // If this pixel is below minimum value, count it, then skip.
     
    23011941                // number is trivial.
    23021942                if (out->uniform == true) {
    2303                     binSize = out->bounds->data.F32[1] - out->bounds->data.F32[0];
    2304                     binNum = (psS32)((inF32->data.F32[i] - out->bounds->data.F32[0]) / binSize);
    2305                     if (errorsF32 != NULL) {
    2306                         psS32 rc = UpdateHistogramBins(binNum, out, inF32->data.F32[i],
    2307                                                        errorsF32->data.F32[i]);
    2308                         if (rc < 0) {
    2309                             psLogMsg(__func__, PS_LOG_WARN, "WARNING: Failed to update the histogram bins with the errors vector.\n");
     1943                    float binSize = out->bounds->data.F32[1] - out->bounds->data.F32[0]; // Histogram bin size
     1944                    binNum = (inF32->data.F32[i] - out->bounds->data.F32[0]) / binSize;
     1945                    if (errorsF32) {
     1946                        if (!UpdateHistogramBins(binNum, out, inF32->data.F32[i], errorsF32->data.F32[i])) {
     1947                            psLogMsg(__func__, PS_LOG_WARN, "WARNING: Failed to update the histogram "
     1948                                     "bins with the errors vector.\n");
    23101949                        }
    23111950                    } else {
     
    23291968                    } else {
    23301969                        if (errorsF32 != NULL) {
    2331                             psS32 rc = UpdateHistogramBins(binNum, out,
    2332                                                            inF32->data.F32[i],
    2333                                                            errors->data.F32[i]);
    2334                             if (rc < 0) {
    2335                                 psLogMsg(__func__, PS_LOG_WARN, "WARNING: Failed to update the histogram bins with the errors vector.\n");
     1970                            if (!UpdateHistogramBins(binNum, out, inF32->data.F32[i], errors->data.F32[i])) {
     1971                                psLogMsg(__func__, PS_LOG_WARN, "WARNING: Failed to update the histogram "
     1972                                         "bins with the errors vector.\n");
    23361973                            }
    23371974                        } else {
    2338                             (out->nums->data.F32[binNum])+= 1.0;
     1975                            out->nums->data.F32[binNum] += 1.0;
    23391976                        }
    23401977                    }
     
    23441981    }
    23451982
    2346     if (mustFreeVectorIn == 1) {
    2347         psFree(inF32);
    2348     }
    2349     if (mustFreeVectorErrors == 1) {
    2350         psFree(errorsF32);
    2351     }
     1983    psFree(inF32);
     1984    psFree(errorsF32);
    23521985
    23531986    psTrace(__func__, 3, "---- %s() end  ----\n", __func__);
    23541987    return (out);
    2355 }
    2356 
    2357 /******************************************************************************
    2358 p_psConvertToF32(in): this is the cheap way to support a variety of vector
    2359 data types: we simply convert the input vector to F32 at the beginning, and
    2360 write all of our functions in F32.  If the vast majority of all vector stat
    2361 operations are F32 (or any other single type), then this is probably the
    2362 best way to go.  Otherwise, when the algorithms stablize, we will then macro
    2363 everything and put type support in the various stat functions.
    2364  
    2365 XXX: Should the default data type be F64?  Since we are buying Opterons...
    2366  
    2367 XXX: Use psLib functions instead.
    2368  *****************************************************************************/
    2369 psVector* p_psConvertToF32(psVector* in)
    2370 {
    2371     psTrace(__func__, 4,"---- %s() begin  ----\n", __func__);
    2372     if (in == NULL) {
    2373         return(NULL);
    2374     }
    2375     psS32 i = 0;
    2376     psVector* tmp = NULL;
    2377 
    2378     if (in->type.type == PS_TYPE_S8) {
    2379         tmp = psVectorAlloc(in->n, PS_TYPE_F32);
    2380         for (i = 0; i < in->n; i++) {
    2381             tmp->data.F32[i] = (psF32)in->data.S8[i];
    2382             tmp->n++;
    2383         }
    2384     } else if (in->type.type == PS_TYPE_S16) {
    2385         tmp = psVectorAlloc(in->n, PS_TYPE_F32);
    2386         for (i = 0; i < in->n; i++) {
    2387             tmp->data.F32[i] = (psF32) in->data.S16[i];
    2388             tmp->n++;
    2389         }
    2390     } else if (in->type.type == PS_TYPE_S32) {
    2391         tmp = psVectorAlloc(in->n, PS_TYPE_F32);
    2392         for (i = 0; i < in->n; i++) {
    2393             tmp->data.F32[i] = (psF32)in->data.S32[i];
    2394             tmp->n++;
    2395         }
    2396     } else if (in->type.type == PS_TYPE_S64) {
    2397         tmp = psVectorAlloc(in->n, PS_TYPE_F32);
    2398         for (i = 0; i < in->n; i++) {
    2399             tmp->data.F32[i] = (psF32)in->data.S64[i];
    2400             tmp->n++;
    2401         }
    2402     } else if (in->type.type == PS_TYPE_U8) {
    2403         tmp = psVectorAlloc(in->n, PS_TYPE_F32);
    2404         for (i = 0; i < in->n; i++) {
    2405             tmp->data.F32[i] = (psF32)in->data.U8[i];
    2406             tmp->n++;
    2407         }
    2408     } else if (in->type.type == PS_TYPE_U16) {
    2409         tmp = psVectorAlloc(in->n, PS_TYPE_F32);
    2410         for (i = 0; i < in->n; i++) {
    2411             tmp->data.F32[i] = (psF32)in->data.U16[i];
    2412             tmp->n++;
    2413         }
    2414     } else if (in->type.type == PS_TYPE_U32) {
    2415         tmp = psVectorAlloc(in->n, PS_TYPE_F32);
    2416         for (i = 0; i < in->n; i++) {
    2417             tmp->data.F32[i] = (psF32)in->data.U32[i];
    2418             tmp->n++;
    2419         }
    2420     } else if (in->type.type == PS_TYPE_U64) {
    2421         tmp = psVectorAlloc(in->n, PS_TYPE_F32);
    2422         for (i = 0; i < in->n; i++) {
    2423             tmp->data.F32[i] = (psF32)in->data.U64[i];
    2424             tmp->n++;
    2425         }
    2426     } else if (in->type.type == PS_TYPE_F64) {
    2427         tmp = psVectorAlloc(in->n, PS_TYPE_F32);
    2428         for (i = 0; i < in->n; i++) {
    2429             tmp->data.F32[i] = (psF32)in->data.F64[i];
    2430             tmp->n++;
    2431         }
    2432     } else if (in->type.type == PS_TYPE_F32) {
    2433         // do nothing
    2434     } else {
    2435         char* strType;
    2436         PS_TYPE_NAME(strType, in->type.type);
    2437         psError(PS_ERR_BAD_PARAMETER_TYPE, true,
    2438                 PS_ERRORTEXT_psStats_VECTOR_TYPE_UNSUPPORTED,
    2439                 strType);
    2440     }
    2441 
    2442     psTrace(__func__, 4,"---- %s() end  ----\n", __func__);
    2443     return (tmp);
    24441988}
    24451989
     
    24692013    PS_ASSERT_PTR_NON_NULL(stats, NULL);
    24702014    PS_ASSERT_VECTOR_NON_NULL(in, NULL);
    2471     if (mask != NULL) {
     2015    if (mask) {
    24722016        PS_ASSERT_VECTORS_SIZE_EQUAL(mask, in, stats);
    24732017        PS_ASSERT_VECTOR_TYPE(mask, PS_TYPE_U8, stats);
    24742018    }
    2475     if (errors != NULL) {
     2019    if (errors) {
    24762020        PS_ASSERT_VECTORS_SIZE_EQUAL(errors, in, stats);
    24772021        PS_ASSERT_VECTOR_TYPE(errors, in->type.type, stats);
    24782022    }
    2479     // XXX: Assert that "in" is F64, F32, U16, or S8
    2480 
    2481     psVector* inF32 = NULL;
    2482     psVector* errorsF32 = NULL;
    2483     psS32 mustFreeVectorIn = 1;
    2484     psS32 mustFreeVectorErrors = 1;
    2485 
    2486     inF32 = p_psConvertToF32((psVector *) in);
    2487     if (inF32 == NULL) {
    2488         //        printf("\n\ninF32 is NULL\n\n");
    2489         //        inF32 = (psVector *) in;
    2490         //        mustFreeVectorIn = 0;
    2491         inF32 = psVectorCopy(inF32, in, PS_TYPE_F32);
    2492         inF32->n = inF32->nalloc;
    2493         mustFreeVectorIn = 1;
    2494     }
    2495     //    else printf("\ninF32 has n=%ld, nalloc=%ld\n", inF32->n, inF32->nalloc);
    2496     errorsF32 = p_psConvertToF32((psVector *) errors);
    2497     if (errorsF32 == NULL) {
    2498         errorsF32 = (psVector *) errors;
    2499         mustFreeVectorErrors = 0;
    2500     }
    2501     //    inF32->n = inF32->nalloc;
    2502     //    errorsF32->n = errorsF32->nalloc;
     2023
     2024    // Convert types, as necessary
     2025    psVector *inF32 = NULL;             // Input vector of values, F32 version
     2026    if (in->type.type == PS_TYPE_F32) {
     2027        inF32 = psMemIncrRefCounter((psPtr)in);
     2028    } else {
     2029        inF32 = psVectorCopy(NULL, in, PS_TYPE_F32);
     2030    }
     2031    psVector *errorsF32 = NULL;         // Input vector of errors, F32 version
     2032    if (errors) {
     2033        if (errors->type.type == PS_TYPE_F32) {
     2034            errorsF32 = psMemIncrRefCounter((psPtr)errors);
     2035        } else {
     2036            errorsF32 = psVectorCopy(NULL, errors, PS_TYPE_F32);
     2037        }
     2038    }
     2039    psVector *maskU8 = NULL;            // Input mask vector, U8 version
     2040    if (mask) {
     2041        // We want a copy of the mask, since we may change values
     2042        maskU8 = psVectorCopy(NULL, mask, PS_TYPE_U8);
     2043    }
     2044
     2045
    25032046    if ((stats->options & PS_STAT_USE_RANGE) && (stats->min >= stats->max)) {
    25042047        PS_ASSERT_FLOAT_LARGER_THAN_OR_EQUAL(stats->max, stats->min, stats);
     
    25112054    // ************************************************************************
    25122055    if (stats->options & PS_STAT_SAMPLE_MEAN) {
    2513         if (0 != p_psVectorSampleMean(inF32, errorsF32, mask, maskVal, stats)) {
    2514             psLogMsg(__func__, PS_LOG_WARN, "WARNING: p_psVectorSampleMean() returned an error.\n");
     2056        if (!vectorSampleMean(inF32, errorsF32, maskU8, maskVal, stats)) {
     2057            psLogMsg(__func__, PS_LOG_WARN, "WARNING: vectorSampleMean() returned an error.\n");
    25152058            stats->sampleMean = NAN;
    25162059        }
     
    25182061
    25192062    // ************************************************************************
    2520     if (stats->options & PS_STAT_SAMPLE_MEDIAN) {
    2521         if (false == p_psVectorSampleMedian(inF32, mask, maskVal, stats)) {
    2522             psLogMsg(__func__, PS_LOG_WARN, "WARNING: p_psVectorSampleMedian() returned an error.\n");
     2063    if (stats->options & (PS_STAT_SAMPLE_MEDIAN | PS_STAT_SAMPLE_QUARTILE)) {
     2064        if (!vectorSampleMedian(inF32, maskU8, maskVal, stats)) {
     2065            psLogMsg(__func__, PS_LOG_WARN, "WARNING: vectorSampleMedian() returned an error.\n");
    25232066            stats->sampleMedian = NAN;
     2067            stats->sampleUQ = NAN;
     2068            stats->sampleLQ = NAN;
    25242069        }
    25252070    }
     
    25272072    // ************************************************************************
    25282073    if (stats->options & PS_STAT_SAMPLE_STDEV) {
    2529         if (0 != p_psVectorSampleMean(inF32, errorsF32, mask, maskVal, stats)) {
    2530             psLogMsg(__func__, PS_LOG_WARN, "WARNING: p_psVectorSampleMean() returned an error.\n");
     2074        if (!vectorSampleMean(inF32, errorsF32, maskU8, maskVal, stats)) {
     2075            psLogMsg(__func__, PS_LOG_WARN, "WARNING: vectorSampleMean() returned an error.\n");
    25312076            stats->sampleMean = NAN;
    25322077        } else {
    2533             p_psVectorSampleStdev(inF32, errorsF32, mask, maskVal, stats);
     2078            vectorSampleStdev(inF32, errorsF32, maskU8, maskVal, stats);
    25342079        }
    25352080    }
    25362081
    25372082    // ************************************************************************
    2538     if (stats->options & PS_STAT_SAMPLE_QUARTILE) {
    2539         if (false == p_psVectorSampleQuartiles(inF32, mask, maskVal, stats)) {
    2540             psLogMsg(__func__, PS_LOG_WARN, "WARNING: p_psVectorSampleQuartiles() returned an error.\n");
    2541             stats->sampleLQ = NAN;
    2542             stats->sampleUQ = NAN;
    2543         }
    2544     }
    2545 
    2546     // ************************************************************************
    2547     if ((stats->options & PS_STAT_ROBUST_MEDIAN) ||
    2548             (stats->options & PS_STAT_ROBUST_STDEV) ||
    2549             (stats->options & PS_STAT_ROBUST_QUARTILE) ||
    2550             (stats->options & PS_STAT_FITTED_MEAN) ||
    2551             (stats->options & PS_STAT_FITTED_STDEV)) {
    2552         if (0 != p_psVectorRobustStats(inF32, errorsF32, mask, maskVal, stats)) {
     2083    if (stats->options & (PS_STAT_ROBUST_MEDIAN | PS_STAT_ROBUST_STDEV | PS_STAT_ROBUST_QUARTILE |
     2084                          PS_STAT_FITTED_MEAN | PS_STAT_FITTED_STDEV)) {
     2085        if (!vectorRobustStats(inF32, errorsF32, maskU8, maskVal, stats)) {
    25532086            psError(PS_ERR_UNKNOWN, false, PS_ERRORTEXT_psStats_STATS_FAILED);
    25542087            psFree(stats);
     2088            psFree(inF32);
     2089            psFree(errorsF32);
    25552090            psTrace(__func__, 3,"---- %s(NULL) end  ----\n", __func__);
    25562091            return(NULL);
     
    25602095    // ************************************************************************
    25612096    if ((stats->options & PS_STAT_CLIPPED_MEAN) || (stats->options & PS_STAT_CLIPPED_STDEV)) {
    2562         psS32 rc = p_psVectorClippedStats(inF32, errorsF32, mask, maskVal, stats);
    2563         if (rc < 0) {
     2097        if (!vectorClippedStats(inF32, errorsF32, maskU8, maskVal, stats)) {
    25642098            psError(PS_ERR_UNKNOWN, false, "Failed to calculate clipped statistics for input psVector.\n");
    25652099            stats->clippedMean = NAN;
     
    25692103
    25702104    // ************************************************************************
    2571     if (stats->options & PS_STAT_MAX) {
    2572         if (0 != p_psVectorMax(inF32, mask, maskVal, stats)) {
    2573             psError(PS_ERR_UNKNOWN, false, "Failed to calculate vector maximum");
    2574             stats->max = NAN;
    2575         }
    2576     }
    2577 
    2578     // ************************************************************************
    2579     if (stats->options & PS_STAT_MIN) {
    2580         if (0 != p_psVectorMin(inF32, mask, maskVal, stats)) {
    2581             psError(PS_ERR_UNKNOWN, false, "Failed to calculate vector minimum");
    2582             stats->min = NAN;
    2583         }
    2584     }
    2585 
    2586     if (mustFreeVectorIn == 1) {
    2587         psFree(inF32);
    2588     }
    2589     if (mustFreeVectorErrors == 1) {
    2590         psFree(errorsF32);
    2591     }
     2105    if (stats->options & (PS_STAT_MAX | PS_STAT_MIN)) {
     2106        if (vectorMinMax(inF32, maskU8, maskVal, stats) == 0) {
     2107            psError(PS_ERR_UNKNOWN, false, "Failed to calculate vector minimum and maximum");
     2108        }
     2109    }
     2110
     2111    psFree(inF32);
     2112    psFree(errorsF32);
     2113    psFree(maskU8);
    25922114    psTrace(__func__, 3,"---- %s() end  ----\n", __func__);
    25932115    return (stats);
Note: See TracChangeset for help on using the changeset viewer.