package hep.aida.util;

import hep.aida.IAnalysisFactory;
import hep.aida.ICloud1D;
import hep.aida.IHistogram1D;

/**
 *
 * @author The FreeHEP team @ SLAC.
 * @version $Id: HistUtils.java 13360 2007-10-02 23:13:06Z serbo $
 */
public class HistUtils {
    
    /**
     * Test the distribution of h1 and h2 using the Kolmogorov algorithm.
     * The result is between 0 and 1; 1 is for identical histograms.
     *
     */
    
    public static double kolmogorovTest( ICloud1D c1, ICloud1D c2) {
        return kolmogorovTest(c1, c2, 50);
    }
    
    public static double kolmogorovTest( ICloud1D c1, ICloud1D c2, int nBins) {
        double result = 0;
        if (!c1.isConverted() && !c2.isConverted()) {
        double[] bins1 = null;
        double[] bins2 = null;
            double xMin = c1.lowerEdge();
            double xMax = c1.upperEdge();
            if (c2.lowerEdge() < xMin) xMin = c2.lowerEdge();
            if (c2.upperEdge() > xMax) xMax = c2.upperEdge();
            bins1 = getBins(c1, nBins, xMin, xMax);
            bins2 = getBins(c1, nBins, xMin, xMax);
            result = kolmogorovTest(bins1, bins2);
        } else if (c1.isConverted() && !c2.isConverted()) {
            IHistogram1D h1 = c1.histogram();
            IHistogram1D h2 = IAnalysisFactory.create().createHistogramFactory(null).createHistogram1D(c2.title(), h1.axis().bins(), h1.axis().lowerEdge(), h1.axis().upperEdge());
            result = kolmogorovTest(h1, h2);
        } else if (!c1.isConverted() && c2.isConverted()) {
            IHistogram1D h2 = c2.histogram();
            IHistogram1D h1 = IAnalysisFactory.create().createHistogramFactory(null).createHistogram1D(c1.title(), h2.axis().bins(), h2.axis().lowerEdge(), h2.axis().upperEdge());
            result = kolmogorovTest(h1, h2);
        } else if (c1.isConverted() && c2.isConverted()) {
            result = kolmogorovTest(c1.histogram(), c2.histogram());
        }
        return result;
    }
               
    // Use for unconverted ICloud1D only
    private static double[] getBins(ICloud1D c, int nBins, double xMin, double xMax) {
        if ( c.isConverted() )
            throw new IllegalArgumentException("ICloud1D must be not converted!");
        
        double[] bins = new double[nBins];
        double x = 0;
        double binWidth = (xMax - xMin)/nBins;
        for (int i=0; i= xMin && x< xMax) {
                int index = (int) Math.floor((x - xMin)/binWidth);
                bins[index] += c.weight(i);
            }
        }
        return bins;
    }
    
    public static double kolmogorovTest( IHistogram1D h1, IHistogram1D h2 ) {
               
        if ( h1 == null || h2 == null )
            throw new IllegalArgumentException("Null Histogram!");
        
        if ( ! h1.axis().equals( h2.axis() ) )
            throw new IllegalArgumentException("The two histograms must have the same binning!");
        
        int nBins = h1.axis().bins();
        
        double[] bins1 = new double[nBins];
        double[] bins2 = new double[nBins];
        
        for ( int i = 0; i < nBins; i++ ) {
            bins1[i] = h1.binHeight(i);
            bins2[i] = h2.binHeight(i);
        }
        return kolmogorovTest(bins1, bins2);        
    }
    
    /**
     * Test the distribution of h1 and h2 using the Kolmogorov algorithm.
     * The result is between 0 and 1; 1 is for identical histograms.
     *
     */
    public static double kolmogorovTest( double[] bins1, double[] bins2 ) {
        
        if ( bins1.length != bins2.length )
            throw new IllegalArgumentException("The two histograms must have the same number of bins!");
        
        int nBins = bins1.length;
        
        double sumOfHeights1 = 0;
        double sumOfHeights2 = 0;
        
        for ( int i = 0; i < nBins; i++ ) {
            sumOfHeights1 += bins1[i];
            sumOfHeights2 += bins2[i];
        }
        
        if ( sumOfHeights1 == 0 || sumOfHeights2 == 0 )
            throw new IllegalArgumentException("The histograms cannot have zero integral!");
        
        double norm1 = 1./sumOfHeights1;
        double norm2 = 1./sumOfHeights2;
        
        // Find largest difference for Kolmogorov Test
        double diff = 0, normSum1 = 0, normSum2 = 0;
        
        for ( int i = 0; i < nBins; i++ ) {
            normSum1 += norm1*bins1[i];
            normSum2 += norm2*bins2[i];
            double tmpDiff = Math.abs( normSum1 - normSum2 );
            if ( tmpDiff > diff ) diff = tmpDiff;
        }
        
        double prob = diff*Math.sqrt(sumOfHeights1*sumOfHeights2/(sumOfHeights1+sumOfHeights2));
        double p = 0;
        if ( prob < 0.2 ) return 1;
        if ( prob > 1 ) {
            // jf2[j] = -2* j**2
            double[] fj2 = {-2. , -8. , -18. , -32. , -50.};
            double s = -2;
            double p2 = prob*prob;
            for ( int i = 0; i < 5; i++ ) {
                s *= -1;
                double c = fj2[i] *p2;
                if (c < -100) return p;
                p += s*Math.exp(c);
            }
            return p;
        }
        
        double[] cons = { -1.233700550136 , -11.10330496 , -30.84251376};
        double sqr2pi = Math.sqrt( 2*Math.PI );
        
        double zinv = 1./prob;
        double a = sqr2pi*zinv;
        double zinv2 = zinv*zinv;
        
        double arg;
        for ( int i =0; i < 3; i++) {
            arg = cons[i]*zinv2;
            if (arg < -30) continue;
            p += Math.exp(arg);
        }
        p = 1 - a*p;
        return p;
        
    }    
}
 

Ads help maintain this website.