package hep.aida.util.comparison; import hep.aida.ext.IComparisonData; import org.apache.commons.math.distribution.ChiSquaredDistribution; import org.apache.commons.math.distribution.DistributionFactory; /** * * @author The FreeHEP team @ SLAC. * Algorithm taken from http://www.ge.infn.it/geant4/analysis/HEPstatistics/ * */ public class Chi2ComparisonAlgorithm extends AbstractComparisonAlgorithm { private static final String[] names = new String[] {"chiSquared", "chi2"}; private static final int dType = ONLY_BINNED_DATA; private static final int eType = ONLY_SAME_NUMBER_OF_EVENTS; public Chi2ComparisonAlgorithm() { super(dType, eType); } public String[] algorithmNames() { return names; } public double quality(IComparisonData d1, IComparisonData d2) throws RuntimeException { if ( ! canCompare(d1,d2) ) throw new IllegalArgumentException("Invalid data. The "+names[0]+" cannot compare the given datasets. They MUST be binned with the SAME binning."); int n = d1.nPoints(); double chi2 = 0; int nDf = 0; for (int i=0; i < n; i++) { double w1 = d1.weight(i); double w2 = d2.weight(i); double w = w1 + w2; if ( w > 0) { double dw = w1 - w2; chi2 += dw*dw /w; nDf++; } } ChiSquaredDistribution chi2Distribution = DistributionFactory.newInstance().createChiSquareDistribution(nDf); double prob = Double.NaN; try { prob = chi2Distribution.cumulativeProbability(chi2); } catch ( org.apache.commons.math.MathException me) { throw new RuntimeException("Problems evaluating probability ",me); } return prob; } public int nDof(IComparisonData d1, IComparisonData d2) { int n = d1.nPoints(); int nDf = 0; for (int i=0; i < n; i++) { double w1 = d1.weight(i); double w2 = d2.weight(i); double w = w1 + w2; if ( w > 0) nDf++; } return nDf; } public boolean canCompare(IComparisonData d1, IComparisonData d2) { boolean superCanCompare = super.canCompare(d1,d2); if ( ! superCanCompare ) return false; int nPoints = d1.nPoints(); if ( nPoints != d2.nPoints() ) return false; for ( int i = 0; i < nPoints; i++ ) if ( d1.value(i) != d2.value(i) ) return false; return true; } }