IPP Software Navigation Tools IPP Links Communication Pan-STARRS Links

Changeset 36345


Ignore:
Timestamp:
Dec 4, 2013, 2:11:09 PM (13 years ago)
Author:
bills
Message:

Integrate updated psStats code from the trunk

Location:
branches/eam_branches/ipp-20130904/psLib/src/math
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • branches/eam_branches/ipp-20130904/psLib/src/math/psMinimizePolyFit.c

    r36291 r36345  
    715715        sigma  = (sorted->data.F64[3 * sorted->n / 4] - sorted->data.F64[sorted->n / 4]);
    716716        psFree(sorted);
     717
     718        if ((!isfinite(median))||
     719            (!isfinite(sigma))) {
     720          median = 0.0;
     721          sigma = 1.0;
     722        }
     723        if ((median == 0.0)&&(sigma == 1.0)) {
     724          scale = false;
     725        }
    717726        // I can't see a way to not clobber x if it's already F64, so make a copy.x
    718727        z64 = psVectorCopy(NULL,x64,PS_TYPE_F64);
     
    726735       
    727736        result = VectorFitPolynomial1DOrd(poly, mask, maskValue, f64, fErr64, z64);
     737        psFree(z64); // Done with this.
    728738      }
    729739      else {
     
    736746     
    737747      if (scale) {
    738         psFree(z64); // Done with this.
    739 
    740748        // Undo scaling in the polynomial values.
    741749        psF64 *Zcoeff = psAlloc((1 + poly->nX) * sizeof(psF64));
     
    757765#if (CZW)
    758766            printf("        %d %d %f %f %f %f => %f\n",
    759                    i,j,Zcoeff[j],pow(1.0 / sigma,j) * pow(-1,j - i),pow(median,j - i),1.0 * psBinomialCoeff(j,i),
     767                   i,j,Zcoeff[j],
     768                   pow(1.0 / sigma,j) * pow(-1,j - i),
     769                   pow(median,j - i),
     770                   1.0 * psBinomialCoeff(j,i),
    760771                   Zcoeff[j] * pow(1.0 / sigma,j) * pow(-1,j  -i) * pow(median,j - i) * 1.0 * psBinomialCoeff(j,i)
    761772                   );
  • branches/eam_branches/ipp-20130904/psLib/src/math/psStats.c

    r36262 r36345  
    140140}
    141141
     142// Debug information
     143#define CZW 0
    142144
    143145/*****************************************************************************/
     
    172174*****************************************************************************/
    173175
    174 static psF32 fitQuadraticSearchForYThenReturnBin(const psVector *xVec, psVector *yVec, psS32 binNum, psF32 yVal);
     176// static psF32 fitQuadraticSearchForYThenReturnBin(const psVector *xVec, psVector *yVec, psS32 binNum, psF32 yVal);
     177static psF32 fitLinearSearchForYThenReturnBin(const psVector *xVec, psVector *yVec, psS32 binNum, psF32 yVal);
    175178
    176179/******************************************************************************
     
    229232        }
    230233        count++;
     234
    231235    }
    232236    if (errors) {
     
    793797        } else {
    794798            // Determine the bin size of the robust histogram, using the pre-defined number of bins
    795             binSize = (max - min) / INITIAL_NUM_BINS;
     799            binSize = (max - min) / INITIAL_NUM_BINS;
    796800        }
    797801        psTrace(TRACE, 6, "Initial robust bin size is %.2f\n", binSize);
     
    876880        cumulative = psHistogramAlloc(min, max, numBins);
    877881        cumulative->nums->data.F32[0] = histogram->nums->data.F32[0];
    878         for (long i = 1; i < histogram->nums->n; i++) {
    879             cumulative->nums->data.F32[i] = cumulative->nums->data.F32[i-1] + histogram->nums->data.F32[i];
    880             cumulative->bounds->data.F32[i-1] = histogram->bounds->data.F32[i];
    881         }
     882        cumulative->bounds->data.F32[0] = histogram->bounds->data.F32[1];
     883
     884        // Correctly fill the cumulative distribution with monotonically increasing values (skip zero valued bins).
     885        long Nc = 1;  // track the current bin of cumulative
     886        // the boundaries for the current cumulative bin are from upper end of the last valid histogram bin to the
     887        // upper end of the current histogram bin
     888        for (long i = 1; i < histogram->nums->n - 1; i++) {
     889            if (histogram->nums->data.F32[i] == 0.0) continue;
     890            cumulative->nums->data.F32[Nc] = cumulative->nums->data.F32[Nc - 1] + histogram->nums->data.F32[i];
     891            cumulative->bounds->data.F32[Nc] = histogram->bounds->data.F32[i+1];
     892            Nc ++;
     893        }
     894        long Nlast = Nc - 1;  // last valid cumulative bin
     895        for (long i = Nc; i < histogram->nums->n; i++) { // Ensure the unused entries are filled.
     896            cumulative->nums->data.F32[i] = cumulative->nums->data.F32[Nlast];
     897            cumulative->bounds->data.F32[i] = cumulative->bounds->data.F32[i-1] + 1.0;
     898        }
     899       
    882900        if (psTraceGetLevel("psLib.math") >= 8) {
    883901            PS_VECTOR_PRINT_F32(cumulative->bounds);
     
    895913
    896914        // ADD step 3: Interpolate to the exact 50% position in bin units
    897         stats->robustMedian = fitQuadraticSearchForYThenReturnBin(cumulative->bounds, cumulative->nums, binMedian, totalDataPoints/2.0);
    898         // float robustBin = fitQuadraticSearchForYThenReturnXusingValues(cumulative->bounds, cumulative->nums, binMedian, totalDataPoints/2.0);
     915        // stats->robustMedian = fitQuadraticSearchForYThenReturnBin(cumulative->bounds, cumulative->nums, binMedian, totalDataPoints/2.0);
     916        // float robustBin = fitQuadraticSearchForYThenReturnXusingValues(cumulative->bounds, cumulative->nums, binMedian, totalDataPoints/2.0);
    899917        // fprintf (stderr, "robustBin : %f vs %f\n", robustBin, stats->robustMedian);
     918        // There's no reason to do a quadratic fit near the 50% bin, as it's approximately linear there.
     919        // Instead, do a 5-point linear fit.
     920        stats->robustMedian = fitLinearSearchForYThenReturnBin(cumulative->bounds, cumulative->nums, binMedian, totalDataPoints/2.0);
    900921
    901922        // convert bin to bin value: this is the robust histogram median.
     
    912933        PS_BIN_FOR_VALUE(binL2, cumulative->nums, totalDataPoints * 0.308538f, 0);
    913934        PS_BIN_FOR_VALUE(binH2, cumulative->nums, totalDataPoints * 0.691462f, 0);
    914         PS_BIN_FOR_VALUE(binL4, cumulative->nums, totalDataPoints * 0.022481f, 0);
    915         PS_BIN_FOR_VALUE(binH4, cumulative->nums, totalDataPoints * 0.977519f, 0);
    916 
     935        PS_BIN_FOR_VALUE(binL4, cumulative->nums, totalDataPoints * 0.022750f, 0);
     936        PS_BIN_FOR_VALUE(binH4, cumulative->nums, totalDataPoints * 0.977250f, 0);
     937       
     938       
    917939        psTrace(TRACE, 6, "The 15.8655%% and 84.1345%% data point bins are (%ld, %ld).\n",
    918940                binLo, binHi);
     
    926948            goto escape;
    927949        }
    928 
     950   
    929951        // ADD step 4b: Interpolate Sigma (linearly) to find these two positions exactly: these are the 1sigma
    930952        // positions.
     
    938960        // (extrapolation should not be needed and will result in errors)
    939961        float binLoF32, binHiF32, binL2F32, binH2F32, binL4F32, binH4F32;
     962#if (0)
    940963        PS_BIN_INTERPOLATE (binLoF32, cumulative->nums, cumulative->bounds, binLo,
    941964                            totalDataPoints * 0.158655f);
     
    947970                            totalDataPoints * 0.691462f);
    948971        PS_BIN_INTERPOLATE (binL4F32, cumulative->nums, cumulative->bounds, binL4,
    949                             totalDataPoints * 0.022481f);
     972                            totalDataPoints * 0.022750f);
    950973        PS_BIN_INTERPOLATE (binH4F32, cumulative->nums, cumulative->bounds, binH4,
    951                             totalDataPoints * 0.977519f);
    952 
     974                            totalDataPoints * 0.977250f);
     975#else
     976        binLoF32 = fitLinearSearchForYThenReturnBin(cumulative->bounds, cumulative->nums, binLo, totalDataPoints * 0.158655);
     977        binHiF32 = fitLinearSearchForYThenReturnBin(cumulative->bounds, cumulative->nums, binHi, totalDataPoints * 0.841345);         
     978        binL2F32 = fitLinearSearchForYThenReturnBin(cumulative->bounds, cumulative->nums, binL2, totalDataPoints * 0.308538);
     979        binH2F32 = fitLinearSearchForYThenReturnBin(cumulative->bounds, cumulative->nums, binH2, totalDataPoints * 0.691462);         
     980        binL4F32 = fitLinearSearchForYThenReturnBin(cumulative->bounds, cumulative->nums, binL4, totalDataPoints * 0.022750);
     981        binH4F32 = fitLinearSearchForYThenReturnBin(cumulative->bounds, cumulative->nums, binH4, totalDataPoints * 0.977250);
     982#endif 
    953983        // report +/- 1 sigma points
    954984        psTrace(TRACE, 5,
     
    959989                binL2F32, binH2F32);
    960990        psTrace(TRACE, 5,
    961                 "The exact 02.22481 and 97.7519 percent data point positions are: (%f, %f)\n",
     991                "The exact 02.2275 and 97.7250 percent data point positions are: (%f, %f)\n",
    962992                binL4F32, binH4F32);
    963993
     994        // If some of the fits failed, attempt to fix this
     995        if (!isfinite(binLoF32) && isfinite(binHiF32)) { binLoF32 = -1.0 * binHiF32; }
     996        if (!isfinite(binHiF32) && isfinite(binLoF32)) { binHiF32 = -1.0 * binLoF32; }
     997        if (!isfinite(binL2F32) && isfinite(binH2F32)) { binL2F32 = -1.0 * binH2F32; }
     998        if (!isfinite(binH2F32) && isfinite(binL2F32)) { binH2F32 = -1.0 * binL2F32; }
     999        if (!isfinite(binL4F32) && isfinite(binH4F32)) { binL4F32 = -1.0 * binH4F32; }
     1000        if (!isfinite(binH4F32) && isfinite(binL4F32)) { binH4F32 = -1.0 * binL4F32; }
     1001       
    9641002        // ADD step 5: Determine SIGMA as the distance between binL2 and binH2 (+/- 0.5 sigma)
     1003
     1004
    9651005        float sigma1 = (binH2F32 - binL2F32);
    9661006        float sigma2 = (binHiF32 - binLoF32) / 2.0;
    9671007        float sigma4 = (binH4F32 - binL4F32) / 4.0;
    9681008
     1009        // Fix again?
     1010        if (!isfinite(sigma1) && isfinite(sigma2) && isfinite(sigma4)) { sigma1 = (sigma2 + sigma4) / 2.0; }
     1011        if (!isfinite(sigma2) && isfinite(sigma1) && isfinite(sigma4)) { sigma2 = (sigma1 + sigma4) / 2.0; }
     1012        if (!isfinite(sigma4) && isfinite(sigma2) && isfinite(sigma1)) { sigma4 = (sigma2 + sigma1) / 2.0; }
     1013       
    9691014        // take the smallest of the three: if we have a clump with wide outliers, sigma2 and
    9701015        // sigma4 will be biased high; if we have a bi-modal distribution, sigma1 and sigma2
    9711016        // will be biased high.
    972         sigma = PS_MIN (sigma1, PS_MIN (sigma2, sigma4));
     1017        //        sigma = PS_MIN (sigma1, PS_MIN (sigma2, sigma4));
     1018        // CZW: Instead, take the median.  Taking the MIN forces a bias on unbiased data.
     1019        //      It seems like occasionally getting the wrong answer on a complex distribution
     1020        //      is more acceptable than always getting the wrong answer for simple ones.
     1021
     1022       
     1023        sigma = PS_MAX( PS_MIN(sigma1,sigma2),
     1024                        PS_MIN( PS_MAX(sigma1,sigma2),
     1025                                sigma4));
    9731026
    9741027        psTrace(TRACE, 6, "The 1x sigma is %f.\n", sigma1);
     
    9771030
    9781031        psTrace(TRACE, 6, "The current sigma is %f.\n", sigma);
    979         stats->robustStdev = sigma;
     1032        //        stats->robustStdev = sigma;
     1033        stats->robustStdev = sigma;
     1034
     1035#if (CZW && 0)
     1036        // Skewness check: Find least biased sample for each pair.
     1037        sigma1 = 2.0 * PS_MIN(binH2F32 - stats->robustMedian,
     1038                              stats->robustMedian - binL2F32);
     1039        sigma2 = 1.0 * PS_MIN(binHiF32 - stats->robustMedian,
     1040                              stats->robustMedian - binLoF32);
     1041        sigma4 = 0.5 * PS_MIN(binH4F32 - stats->robustMedian,
     1042                              stats->robustMedian - binL4F32);
     1043        // Kurtosis check: Take median sample as the solution.
     1044        stats->robustStdev = PS_MAX( PS_MIN(sigma1,sigma2),
     1045                                     PS_MIN( PS_MAX(sigma1,sigma2),
     1046                                             sigma4));
     1047#endif
     1048
     1049       
     1050#if (CZW)
     1051        //      printf("CZW: bad sigma?: %f %f  %f %f  %f %f  %f %f %f  %f\n",
     1052        //             binH2F32,binL2F32,binHiF32,binLoF32,binH4F32,binL4F32,
     1053        //             sigma1,sigma2,sigma4,sigma);
     1054       
     1055        printf("CZW Robust (%d): median %f sigma %f delta: %f \n\t %f %f %f %f %f %f %f \n\t %f %f %f %f %f %f %f\n",
     1056               iterate,
     1057               stats->robustMedian,stats->robustStdev,
     1058               fabs(cumulative->bounds->data.F32[binMedian] - cumulative->bounds->data.F32[binMedian + 1]),
     1059               
     1060               cumulative->bounds->data.F32[binMedian-3],cumulative->bounds->data.F32[binMedian-2],
     1061               cumulative->bounds->data.F32[binMedian-1],
     1062               cumulative->bounds->data.F32[binMedian],
     1063               cumulative->bounds->data.F32[binMedian+1],
     1064               cumulative->bounds->data.F32[binMedian+2],cumulative->bounds->data.F32[binMedian+3],
     1065               
     1066               cumulative->nums->data.F32[binMedian-3],cumulative->nums->data.F32[binMedian-2],
     1067               cumulative->nums->data.F32[binMedian-1],
     1068               cumulative->nums->data.F32[binMedian],
     1069               cumulative->nums->data.F32[binMedian+1],
     1070               cumulative->nums->data.F32[binMedian+2],cumulative->nums->data.F32[binMedian+3]);
     1071        //      PS_VECTOR_PRINT_F32(histogram->bounds);
     1072        //      PS_VECTOR_PRINT_F32(histogram->nums);
     1073        //      PS_VECTOR_PRINT_F32(cumulative->bounds);
     1074        //      PS_VECTOR_PRINT_F32(cumulative->nums);
     1075#endif
    9801076
    9811077        // ADD step 6: If the measured SIGMA is less than 2 times the bin size, exclude points which are more
     
    9831079        if (sigma < (3.0 * binSize)) {
    9841080            psTrace(TRACE, 6, "*************: Do another iteration (%f %f).\n", sigma, binSize);
    985             long maskLo = PS_MAX(0, (binMedian - 25)); // Low index for masking region
    986             long maskHi = PS_MIN(histogram->bounds->n - 1, (binMedian + 25)); // High index for masking
    987             psF32 medianLo = histogram->bounds->data.F32[maskLo]; // Value at low index
    988             psF32 medianHi = histogram->bounds->data.F32[maskHi]; // Value at high index
     1081
     1082            // these limits are supposed to be 25 x the raw bin size, NOT 25 of the cumulative histogram bins
     1083            psF32 medianLo = stats->robustMedian - 25*binSize;
     1084            psF32 medianHi = stats->robustMedian + 25*binSize;
     1085
     1086            // long maskLo = PS_MAX(0, (binMedian - 25)); // Low index for masking region
     1087            // long maskHi = PS_MIN(cumulative->bounds->n - 1, (binMedian + 25)); // High index for masking
     1088            // psF32 medianLo = cumulative->bounds->data.F32[maskLo]; // Value at low index
     1089            // psF32 medianHi = cumulative->bounds->data.F32[maskHi]; // Value at high index
    9891090            psTrace(TRACE, 6, "Masking data more than 25 bins from the median\n");
    990             psTrace(TRACE, 6,
    991                     "The median is at bin number %ld.  We mask bins outside the bin range (%ld:%ld)\n",
    992                     binMedian, maskLo, maskHi);
     1091            // psTrace(TRACE, 6, "The median is at bin number %ld.  We mask bins outside the bin range (%ld:%ld)\n", binMedian, maskLo, maskHi);
    9931092            psTrace(TRACE, 6, "Masking data outside (%f %f)\n", medianLo, medianHi);
     1093            int Nmasked = 0;
    9941094            for (long i = 0 ; i < myVector->n ; i++) {
    9951095                if ((myVector->data.F32[i] < medianLo) || (myVector->data.F32[i] > medianHi)) {
    996                     // XXXX is this correct?  is MASK_MARK safe?
     1096                    if (mask->data.PS_TYPE_VECTOR_MASK_DATA[i] & MASK_MARK) continue;
    9971097                    mask->data.PS_TYPE_VECTOR_MASK_DATA[i] |= MASK_MARK;
    9981098                    psTrace(TRACE, 6, "Masking element %ld is %f\n", i, myVector->data.F32[i]);
     1099                    Nmasked ++;
    9991100                }
    10001101            }
     1102
     1103            if (Nmasked == 0) {
     1104                // no significant change to the sigma & binsize -- we are done here
     1105                iterate = -1;
     1106                continue;
     1107            }
    10011108
    10021109            // Free the histograms; they will be recreated on the next iteration, with new bounds
     
    10301137        }
    10311138    }
    1032 
     1139   
    10331140    // XXX test lines while studying algorithm errors
    10341141    // fprintf (stderr, "robust stats test %7.1f +/- %7.1f : %4ld %4ld %4ld %4ld %4ld  : %f %f %f\n",
     
    10401147    PS_BIN_FOR_VALUE (binLo25, cumulative->nums, totalDataPoints * 0.25f, 0);
    10411148    PS_BIN_FOR_VALUE (binHi25, cumulative->nums, totalDataPoints * 0.75f, 0);
    1042     psTrace(TRACE, 6, "The 25-percent and 75-precent data point bins are (%ld, %ld).\n", binLo25, binHi25);
     1149    psTrace(TRACE, 6, "The 25-percent and 75-percent data point bins are (%ld, %ld).\n", binLo25, binHi25);
    10431150
    10441151    // ADD step 8: Interpolate to find these two positions exactly: these are the upper and lower quartile
    10451152    // positions.
    1046     psF32 binLo25F32 = fitQuadraticSearchForYThenReturnBin(cumulative->bounds, cumulative->nums, binLo25, totalDataPoints * 0.25f);
    1047     psF32 binHi25F32 = fitQuadraticSearchForYThenReturnBin(cumulative->bounds, cumulative->nums, binHi25, totalDataPoints * 0.75f);
     1153    psF32 binLo25F32 = fitLinearSearchForYThenReturnBin(cumulative->bounds, cumulative->nums, binLo25, totalDataPoints * 0.25f);
     1154    psF32 binHi25F32 = fitLinearSearchForYThenReturnBin(cumulative->bounds, cumulative->nums, binHi25, totalDataPoints * 0.75f);
    10481155    if (isnan(binLo25F32) || isnan(binHi25F32)) {
    1049         COUNT_WARNING(10, 100, "could not determine the robustUQ: fitQuadraticSearchForYThenReturnBin() returned a NAN.\n");
     1156        COUNT_WARNING(10, 100, "could not determine the robustUQ or LQ: fitLinearSearchForYThenReturnBin() returned a NAN.\n");
    10501157        goto escape;
    10511158    }
     
    11001207 * "vectorFittedStats_v4" all versions of fitted stats now resolve to this function (only v4
    11011208 * has really been used) vectorFittedStats requires guess for fittedMean and fittedStdev
    1102  * robustN50 should also be set gaussian fit is performed using 2D polynomial to ln(y) this
     1209 * robustN50 should also be set gaussian fit is performed using 1D polynomial to ln(y) this
    11031210 * version follows the upper portion of the distribution until it passes 0.5*peak
    11041211 ********************/
     
    11351242        return true;
    11361243    }
    1137 
     1244    if (myVector->n < 1) { printf("There are no elements in this vector.\n"); abort(); }
    11381245    float guessStdev = stats->robustStdev;  // pass the guess sigma
    11391246    float guessMean = stats->robustMedian;  // pass the guess mean
     
    11551262            // set roughly so that the lowest bins have about 2 cnts
    11561263            // Nsmallest ~ N50 / (4*dN))
    1157             psF32 dN = PS_MAX (1, PS_MIN (4, stats->robustN50 / 8));
    1158             binSize = guessStdev / dN;
     1264          //            psF32 dN = PS_MAX (1, PS_MIN (4, stats->robustN50 / 8));
     1265
     1266          // CZW 2013-11-20: We know that the histogram is going to be basically Gaussian.
     1267          // Furthermore, we only use the inner +/- 2 sigma parts.  Therefore, define the
     1268          // binsize such that the bin at 2 sigma contains ~50 points (S/N ~ 7).  robustN50
     1269          // contains half the total points, so 2 * robustN50 / 50 is the fraction of all
     1270          // points in the 2 sigma bin.  Dance the erf() relations around, and it looks like
     1271          // there's a factor of about 1/20 to include.  Keep the PS_MAX to ensure we never bin
     1272          // wider than 1 sigma when the number of points is small.
     1273          psF32 dN = PS_MAX(1, (stats->robustN50 / 500.0));
     1274          binSize = guessStdev / dN;
    11591275        }
    11601276
     
    11821298        // XXX can we calculate the binMin, binMax **before** building this histogram?
    11831299        // if the range is too absurd, adjust numBins & binSize
    1184         long numBins = PS_MAX (50, PS_MIN (10000, (max - min) / binSize));
    1185         binSize = (max - min) / (float) numBins;
     1300        // We no longer want to reset the binSize here, as it can cause odd things.  Better to select
     1301        // a number of bins, and then set the min/max values to put those bins sanely around the mean.
     1302        //        long numBins = PS_MAX (50, PS_MIN (10000, (max - min) / binSize));
     1303        //        binSize = (max - min) / (float) numBins;
    11861304        psTrace(TRACE, 6, "The new min/max values are (%f, %f).\n", min, max);
    11871305        psTrace(TRACE, 6, "The new bin size is %f.\n", binSize);
    1188         psTrace(TRACE, 6, "The numBins is %ld\n", numBins);
    1189 
     1306        //        psTrace(TRACE, 6, "The numBins is %ld\n", numBins);
     1307
     1308
     1309#define FITTED_CLIPPING_NUM 5.0
     1310        if (min < guessMean - FITTED_CLIPPING_NUM * guessStdev) {
     1311          min = guessMean - FITTED_CLIPPING_NUM * guessStdev;
     1312        }
     1313        if (max > guessMean + FITTED_CLIPPING_NUM * guessStdev) {
     1314          max = guessMean + FITTED_CLIPPING_NUM * guessStdev;
     1315        }
     1316        long numBins = PS_MAX (50, PS_MIN (10000, (max - min) / binSize));
     1317        if (CZW) { printf("I've clipped: %f %f => %f %f ; %f %ld\n",guessMean,guessStdev,min,max,binSize,stats->robustN50); }
    11901318        psHistogram *histogram = psHistogramAlloc(min, max, numBins); // A new histogram (without outliers)
    11911319        if (!psVectorHistogram(histogram, myVector, errors, mask, maskVal)) {
     
    12221350        PS_BIN_FOR_VALUE (binMin, histogram->bounds, guessMean - minFitSigma*guessStdev, 0);
    12231351        PS_BIN_FOR_VALUE (binMax, histogram->bounds, guessMean + maxFitSigma*guessStdev, 0);
     1352
    12241353        if (binMin == binMax) {
    12251354            COUNT_WARNING(10, 100, "Failed to calculate the min/max of the input vector.\n");
     
    12381367            }
    12391368            psTrace (TRACE, 6, "(%f = %.0f) ", histogram->bounds->data.F32[i], histogram->nums->data.F32[i]);
     1369            if (CZW) { printf("CENTERED_HISTOGRAM: %f %f\n",
     1370                              PS_BIN_MIDPOINT(histogram,i),
     1371                              histogram->nums->data.F32[i]); }
    12401372        }
    12411373        psTrace (TRACE, 6, "\n");
    12421374
     1375        if (CZW) { printf("Bin selection done: %ld %f %f %ld %f %f %ld %f %f\n",
     1376                          binMin,PS_BIN_MIDPOINT(histogram,binMin),histogram->nums->data.F32[binMin],
     1377                          binMax,PS_BIN_MIDPOINT(histogram,binMax),histogram->nums->data.F32[binMax],
     1378                          binPeak,PS_BIN_MIDPOINT(histogram,binPeak),histogram->nums->data.F32[binPeak]);
     1379        }
     1380       
    12431381        // assume a reasonably well-defined gaussian-like population; run from peak out until val < 0.25*peak
    12441382        psTrace(TRACE, 6, "The clipped numBins is %ld\n", binMax - binMin);
     
    12481386        psTrace(TRACE, 6, "The clipped peak value is %f\n", histogram->nums->data.F32[binPeak]);
    12491387
     1388       
    12501389        float lowfitMean = NAN;
    12511390        float lowfitStdev = NAN;
     
    12851424            }
    12861425            y->n = x->n = j;
    1287 
     1426           
    12881427            // fit 2nd order polynomial to ln(y) = -(x-xo)^2/2sigma^2
    12891428            // XXX this fit may fail with an error for an ill-conditioned matrix (bad data)
     
    12911430            psPolynomial1D *poly = psPolynomial1DAlloc(PS_POLYNOMIAL_ORD, 2);
    12921431            bool status = psVectorFitPolynomial1D (poly, NULL, 0, y, NULL, x);
     1432#if (CZW && 1)
     1433            printf("CZW: LowfitPoly: %f %f %f\n",poly->coeff[0],poly->coeff[1],poly->coeff[2]);
     1434            for (long i = 0; i < x->n; i++) {
     1435              printf("CZW: Lowfit: %d %ld %f %f %f\n",
     1436                     status,i,x->data.F32[i],y->data.F32[i],
     1437                     poly->coeff[0] + poly->coeff[1] * x->data.F32[i] +
     1438                     poly->coeff[2] * pow(x->data.F32[i],2));
     1439            }
     1440#endif
    12931441            psFree(x);
    12941442            psFree(y);
     
    13051453            if (poly->coeff[2] >= 0.0) {
    13061454                COUNT_WARNING(10, 100, "Failed parabolic fit: %f + %f x + %f x^2\n", poly->coeff[0], poly->coeff[1], poly->coeff[2]);
     1455
    13071456                psFree(poly);
    13081457                psFree(histogram);
     
    13571506                }
    13581507            }
     1508
    13591509            psTrace(TRACE, 6, "Lower bound for symmetric range: %f (%ld)\n",
    13601510                    PS_BIN_MIDPOINT(histogram, binS), binS);
     
    13781528            psPolynomial1D *poly = psPolynomial1DAlloc(PS_POLYNOMIAL_ORD, 2);
    13791529            bool status = psVectorFitPolynomial1D (poly, NULL, 0, y, NULL, x);
     1530#if (CZW && 1)
     1531            printf("CZW: FullfitPoly: %f %f %f\n",poly->coeff[0],poly->coeff[1],poly->coeff[2]);
     1532            for (long i = 0; i < x->n; i++) {
     1533              printf("CZW: Fullfit: %d %ld %f %f %f\n",
     1534                     status,i,x->data.F32[i],y->data.F32[i],
     1535                     poly->coeff[0] + poly->coeff[1] * x->data.F32[i] +
     1536                     poly->coeff[2] * pow(x->data.F32[i],2));
     1537            }
     1538#endif
    13801539            psFree(x);
    13811540            psFree(y);
     
    13931552            fullfitStdev = sqrt(-0.5/poly->coeff[2]);
    13941553            fullfitMean = poly->coeff[1]*PS_SQR(fullfitStdev);
     1554
    13951555#ifndef PS_NO_TRACE
    13961556            psTrace(TRACE, 6, "Parabolic Symmetric fit results: %f + %f x + %f x^2\n", poly->coeff[0], poly->coeff[1], poly->coeff[2]);
     
    14151575            }
    14161576
     1577           
    14171578            psFree (poly);
    14181579        }
     
    14371598            done = true;
    14381599        }
     1600
     1601       
     1602#if (CZW && 1)
     1603        printf("CZW IN FITTED: iter   %d %f \n"
     1604               "               low    %f %f \n"
     1605               "               full   %f %f \n"
     1606               "               robust %f %f \n"
     1607               "               final  %f %f\n",
     1608               iteration,minValueSym,
     1609               lowfitMean,lowfitStdev,
     1610               fullfitMean,fullfitStdev,
     1611               stats->robustMedian,stats->robustStdev,
     1612               guessMean,guessStdev);
     1613#endif
    14391614
    14401615        // Clean up after fitting
     
    19652140// other private functions used above
    19662141
     2142# if (0)
    19672143static psF32 QuadraticInverse(psF32 a,
    19682144                              psF32 b,
     
    19862162    return 0.5 * (xLo + xHi);
    19872163}
     2164
     2165static psF32 LinearInverse(psF32 a,
     2166                           psF32 b,
     2167                           psF32 y,
     2168                           psF32 xLo,
     2169                           psF32 xHi
     2170    )
     2171{
     2172    psF64 x = (y - b) / a;
     2173
     2174    if (xLo <= x && x <= xHi) {
     2175        return x;
     2176    }
     2177    return 0.5 * (xLo + xHi);
     2178}
     2179# endif
    19882180
    19892181# if (0)
     
    22422434    return tmpFloat;
    22432435}
    2244 # endif
    22452436
    22462437/******************************************************************************
     
    22762467    PS_ASSERT_INT_WITHIN_RANGE(binNum, 0, (int)(yVec->n - 1), NAN);
    22772468
    2278     psVector *x = psVectorAlloc(3, PS_TYPE_F64);
    2279     psVector *y = psVectorAlloc(3, PS_TYPE_F64);
     2469    //    psVector *x = psVectorAlloc(3, PS_TYPE_F64);
     2470    //    psVector *y = psVectorAlloc(3, PS_TYPE_F64);
     2471    psVector *x = psVectorAlloc(5, PS_TYPE_F64);
     2472    psVector *y = psVectorAlloc(5, PS_TYPE_F64);
    22802473    psF32 tmpFloat = 0.0f;
    22812474
    2282     if ((binNum >= 1) && (binNum <= (yVec->n - 2)) && (binNum <= (xVec->n - 2))) {
     2475    //    if ((binNum >= 1) && (binNum <= (yVec->n - 2)) && (binNum <= (xVec->n - 2))) {
     2476    if ((binNum >= 2) && (binNum <= (yVec->n - 3)) && (binNum <= (xVec->n - 3))) {
    22832477        // The general case.  We have all three points.
    2284         x->data.F64[0] = binNum - 1;
    2285         x->data.F64[1] = binNum;
    2286         x->data.F64[2] = binNum + 1;
    2287         y->data.F64[0] = yVec->data.F32[binNum - 1];
    2288         y->data.F64[1] = yVec->data.F32[binNum];
    2289         y->data.F64[2] = yVec->data.F32[binNum + 1];
     2478      //        x->data.F64[0] = binNum - 1;
     2479      //        x->data.F64[1] = binNum;
     2480      //        x->data.F64[2] = binNum + 1;
     2481      x->data.F64[0] = xVec->data.F32[binNum - 2];
     2482      x->data.F64[1] = xVec->data.F32[binNum - 1];
     2483      x->data.F64[2] = xVec->data.F32[binNum + 0];
     2484      x->data.F64[3] = xVec->data.F32[binNum + 1];
     2485      x->data.F64[4] = xVec->data.F32[binNum + 2];
     2486        y->data.F64[0] = yVec->data.F32[binNum - 2];
     2487        y->data.F64[1] = yVec->data.F32[binNum - 1];
     2488        y->data.F64[2] = yVec->data.F32[binNum + 0];
     2489        y->data.F64[3] = yVec->data.F32[binNum + 1];
     2490        y->data.F64[4] = yVec->data.F32[binNum + 2];
    22902491        psTrace(TRACE, 6, "x vec (orig) is (%f %f %f %f)\n", xVec->data.F32[binNum - 1], xVec->data.F32[binNum], xVec->data.F32[binNum+1], xVec->data.F32[binNum+2]);
    22912492        psTrace(TRACE, 6, "x data is (%f %f %f)\n", x->data.F64[0], x->data.F64[1], x->data.F64[2]);
    22922493        psTrace(TRACE, 6, "y data is (%f %f %f)\n", y->data.F64[0], y->data.F64[1], y->data.F64[2]);
    22932494
     2495
    22942496        // Ensure that the y value lies within range of the y values.
    2295         if (! (((y->data.F64[0] <= yVal) && (yVal <= y->data.F64[2])) ||
    2296                ((y->data.F64[2] <= yVal) && (yVal <= y->data.F64[0]))) ) {
     2497        if (! (((y->data.F64[0] <= yVal) && (yVal <= y->data.F64[4])) ||
     2498               ((y->data.F64[4] <= yVal) && (yVal <= y->data.F64[0]))) ) {
    22972499            psError(PS_ERR_BAD_PARAMETER_VALUE, true,
    22982500                    _("Specified yVal, %g, is not within y-range, %g to %g."),
     
    23312533
    23322534        psTrace(TRACE, 6, "We fit the polynomial, now find x such that f(x) equals %f\n", yVal);
    2333         float binValue = QuadraticInverse(myPoly->coeff[2], myPoly->coeff[1], myPoly->coeff[0], yVal, x->data.F64[0], x->data.F64[2]);
     2535        float binValue = QuadraticInverse(myPoly->coeff[2], myPoly->coeff[1], myPoly->coeff[0], yVal, x->data.F64[0], x->data.F64[4]);
    23342536        psFree(myPoly);
    23352537
     
    23412543            return(NAN);
    23422544        }
    2343 
     2545       
    23442546        // I believe that mathematically the fitted bin position must be between binNum - 1 and binNum + 1
    2345         assert (binValue >= binNum - 1);
    2346         assert (binValue <= binNum + 1);
    2347 
    2348         int fitBin = binValue;
    2349         float dX = xVec->data.F32[fitBin+1] - xVec->data.F32[fitBin];
    2350         float dY = binValue - fitBin;
    2351         tmpFloat = xVec->data.F32[fitBin] + dY * dX;
     2547        //      assert (binValue >= binNum - 1);
     2548        //      assert (binValue <= binNum + 1);
     2549
     2550        //      int fitBin = binValue;
     2551        //        float dX = xVec->data.F32[fitBin+1] - xVec->data.F32[fitBin];
     2552        //        float dY = binValue - fitBin;
     2553        //        tmpFloat = xVec->data.F32[fitBin] + dY * dX;
     2554        tmpFloat = binValue;
     2555       
    23522556    } else {
    23532557        // These are special cases where the bin is at the beginning or end of the vector.
     
    23812585    return tmpFloat;
    23822586}
     2587# endif
     2588
     2589
     2590/******************************************************************************
     2591fitQuadraticSearchForYThenReturnXusingValues(*xVec, *yVec, binNum, yVal): A general routine
     2592which fits a quadratic to three points and returns the x bin value corresponding to the input
     2593y-value.  This routine takes psVectors of x/y pairs as input, and fits a quadratic to the 3
     2594points surrounding element binNum in the vectors.  This version uses the values of x[i] for the
     2595x coordinates (not the midpoints).  This is appropriate for a cumulative histogram.  It then
     2596determines for what value x does that quadratic f(x) = yVal (the input parameter).
     2597
     2598XXX this function is used a fair amount in an inner loop: the polynomial fitting and evaluation
     2599could easily be done with statically allocated doubles, skipping the psLib versions of
     2600polynomial fitting, etc.
     2601
     2602*****************************************************************************/
     2603static psF32 fitLinearSearchForYThenReturnBin(const psVector *xVec,
     2604                                              psVector *yVec,
     2605                                              psS32 binNum,
     2606                                              psF32 yVal
     2607    )
     2608{
     2609
     2610# if (1)
     2611# define HALF_SIZE 2
     2612  double Sx = 0.0;
     2613
     2614  double Sy = 0.0;
     2615  double Sxx = 0.0;
     2616  double Sxy = 0.0;
     2617  double deltaY = 0.0;
     2618  int N = 0;
     2619
     2620  for (int u = binNum - HALF_SIZE; u <= binNum + HALF_SIZE; u++) {
     2621    if ((u >= 0)&&(u < yVec->n)) {
     2622      if (u+1 < xVec->n) {
     2623        Sx += yVec->data.F32[u];
     2624        Sxx += PS_SQR(yVec->data.F32[u]);
     2625
     2626        deltaY = xVec->data.F32[u];
     2627        //deltaY = 0.5 * (xVec->data.F32[u] + xVec->data.F32[u+1]);
     2628        Sy += deltaY;
     2629        Sxy += yVec->data.F32[u] * deltaY;
     2630        N += 1;
     2631      }
     2632    }
     2633  }
     2634  double Det = N * Sxx - Sx * Sx;
     2635  if (Det == 0.0) return NAN;
     2636  if (N == 0) return NAN;
     2637
     2638  double C0 = (Sy*Sxx - Sx*Sxy) / Det;
     2639  double C1 = (Sxy*N - Sx*Sy) / Det;
     2640 
     2641  double value = C0 + yVal*C1;
     2642  return value;
     2643 
     2644 
     2645# else
     2646    psTrace(TRACE, 5, "binNum, yVal is (%d, %f)\n", binNum, yVal);
     2647    if (psTraceGetLevel("psLib.math") >= 8) {
     2648        PS_VECTOR_PRINT_F32(xVec);
     2649        PS_VECTOR_PRINT_F32(yVec);
     2650    }
     2651
     2652    PS_ASSERT_VECTOR_NON_NULL(xVec, NAN);
     2653    PS_ASSERT_VECTOR_NON_NULL(yVec, NAN);
     2654    PS_ASSERT_VECTOR_TYPE(xVec, PS_TYPE_F32, NAN);
     2655    PS_ASSERT_VECTOR_TYPE(yVec, PS_TYPE_F32, NAN);
     2656    PS_ASSERT_INT_WITHIN_RANGE(binNum, 0, (int)(xVec->n - 1), NAN);
     2657    PS_ASSERT_INT_WITHIN_RANGE(binNum, 0, (int)(yVec->n - 1), NAN);
     2658
     2659    //    psVector *x = psVectorAlloc(3, PS_TYPE_F64);
     2660    //    psVector *y = psVectorAlloc(3, PS_TYPE_F64);
     2661    psVector *x = psVectorAlloc(5, PS_TYPE_F64);
     2662    psVector *y = psVectorAlloc(5, PS_TYPE_F64);
     2663    psF32 tmpFloat = 0.0f;
     2664
     2665    if ((binNum >= 2) && (binNum <= (yVec->n - 3)) && (binNum <= (xVec->n - 3))) {
     2666        x->data.F64[0] = xVec->data.F32[binNum - 2];
     2667        x->data.F64[1] = xVec->data.F32[binNum - 1];
     2668        x->data.F64[2] = xVec->data.F32[binNum + 0];
     2669        x->data.F64[3] = xVec->data.F32[binNum + 1];
     2670        x->data.F64[4] = xVec->data.F32[binNum + 2];
     2671
     2672        y->data.F64[0] = yVec->data.F32[binNum - 2];
     2673        y->data.F64[1] = yVec->data.F32[binNum - 1];
     2674        y->data.F64[2] = yVec->data.F32[binNum + 0];
     2675        y->data.F64[3] = yVec->data.F32[binNum + 1];
     2676        y->data.F64[4] = yVec->data.F32[binNum + 2];
     2677        psTrace(TRACE, 6, "x vec (orig) is (%f %f %f %f)\n", xVec->data.F32[binNum - 1], xVec->data.F32[binNum], xVec->data.F32[binNum+1], xVec->data.F32[binNum+2]);
     2678        psTrace(TRACE, 6, "x data is (%f %f %f)\n", x->data.F64[0], x->data.F64[1], x->data.F64[2]);
     2679        psTrace(TRACE, 6, "y data is (%f %f %f)\n", y->data.F64[0], y->data.F64[1], y->data.F64[2]);
     2680
     2681        // Ensure that the y value lies within range of the y values.
     2682        if (! (((y->data.F64[0] <= yVal) && (yVal <= y->data.F64[4])) ||
     2683               ((y->data.F64[4] <= yVal) && (yVal <= y->data.F64[0]))) ) {
     2684            psError(PS_ERR_BAD_PARAMETER_VALUE, true,
     2685                    _("Specified yVal, %g, is not within y-range, %g to %g."),
     2686                    (psF64)yVal, y->data.F64[0], y->data.F64[2]);
     2687            return NAN;
     2688        }
     2689
     2690        // Ensure that the y values are monotonic.
     2691        if (((y->data.F64[0] < y->data.F64[1]) && !(y->data.F64[1] <= y->data.F64[2])) ||
     2692            ((y->data.F64[0] > y->data.F64[1]) && !(y->data.F64[1] >= y->data.F64[2]))) {
     2693            psError(PS_ERR_UNKNOWN, true,
     2694                    "This routine must be called with monotonically increasing or decreasing data points.\n");
     2695            psFree(x);
     2696            psFree(y);
     2697            return NAN;
     2698        }
     2699
     2700        // Determine the coefficients of the polynomial.
     2701        psPolynomial1D *myPoly = psPolynomial1DAlloc(PS_POLYNOMIAL_ORD, 1);
     2702        if (!psVectorFitPolynomial1D(myPoly, NULL, 0, y, NULL, x)) {
     2703            psError(PS_ERR_UNEXPECTED_NULL, false,
     2704                    _("Failed to fit a 1-dimensional polynomial to the three specified data points.  "
     2705                      "Returning NAN."));
     2706            psFree(x);
     2707            psFree(y);
     2708            return NAN;
     2709        }
     2710
     2711        psTrace(TRACE, 6, "myPoly->coeff[0] is %f\n", myPoly->coeff[0]);
     2712        psTrace(TRACE, 6, "myPoly->coeff[1] is %f\n", myPoly->coeff[1]);
     2713        psTrace(TRACE, 6, "Fitted y vec is (%f %f)\n",
     2714                (psF32) psPolynomial1DEval(myPoly, (psF64) x->data.F64[0]),
     2715                (psF32) psPolynomial1DEval(myPoly, (psF64) x->data.F64[1]));
     2716
     2717        psTrace(TRACE, 6, "We fit the polynomial, now find x such that f(x) equals %f\n", yVal);
     2718        float binValue = LinearInverse(myPoly->coeff[1], myPoly->coeff[0], yVal, x->data.F64[0], x->data.F64[4]);
     2719        psFree(myPoly);
     2720
     2721        if (isnan(binValue)) {
     2722            psError(PS_ERR_UNEXPECTED_NULL,
     2723                    false, _("Failed to determine the median of the fitted polynomial.  Returning NAN."));
     2724            psFree(x);
     2725            psFree(y);
     2726            return(NAN);
     2727        }
     2728       
     2729        // I believe that mathematically the fitted bin position must be between binNum - 1 and binNum + 1
     2730        //      assert (binValue >= binNum - 1);
     2731        //      assert (binValue <= binNum + 1);
     2732
     2733        //      int fitBin = binValue;
     2734        //        float dX = xVec->data.F32[fitBin+1] - xVec->data.F32[fitBin];
     2735        //        float dY = binValue - fitBin;
     2736        //        tmpFloat = xVec->data.F32[fitBin] + dY * dX;
     2737        tmpFloat = binValue;
     2738               
     2739       
     2740    } else {
     2741        // These are special cases where the bin is at the beginning or end of the vector.
     2742        if (binNum == 0) {
     2743            // We have two points only at the beginning of the vectors x and y.
     2744            // X = (dX/dY)(Y - Yo) + Xo
     2745            float dX = xVec->data.F32[1] - xVec->data.F32[0];
     2746            float dY = yVec->data.F32[1] - yVec->data.F32[0];
     2747            if (dY == 0.0) {
     2748                tmpFloat = xVec->data.F32[0];
     2749            } else {
     2750                tmpFloat = (yVal - yVec->data.F32[0]) * (dX / dY) + xVec->data.F32[0];
     2751            }
     2752        } else if (binNum == (xVec->n - 1)) {
     2753            // We have two points only at the end of the vectors x and y.
     2754            // X = (dX/dY)(Y - Yo) + Xo
     2755            float dX = xVec->data.F32[binNum] - xVec->data.F32[binNum-1];
     2756            float dY = yVec->data.F32[binNum] - yVec->data.F32[binNum-1];
     2757            if (dY == 0.0) {
     2758                tmpFloat = xVec->data.F32[binNum-1];
     2759            } else {
     2760                tmpFloat = (yVal - yVec->data.F32[binNum-1]) * (dX / dY) + xVec->data.F32[binNum-1];
     2761            }
     2762        }
     2763    }
     2764
     2765    psTrace(TRACE, 6, "FIT: return %f\n", tmpFloat);
     2766    psFree(x);
     2767    psFree(y);
     2768
     2769    return tmpFloat;
     2770# endif
     2771}
Note: See TracChangeset for help on using the changeset viewer.