package hep.aida.util.comparison; import hep.aida.ext.IComparisonData; /** * * @author The FreeHEP team @ SLAC. * Algorithm taken from http://www.ge.infn.it/geant4/analysis/HEPstatistics/ * */ public class FiszCramerVonMisesComparisonAlgorithm extends AbstractComparisonAlgorithm { private static final double[] rejectionValues = new double[] {0.1, 0.05, 0.01, 0.001}; private static final double[] criticalValues = new double[] {0.347, 0.461, 0.743, 1.168}; private static final String[] names = new String[] {"FiszCramerVonMises","FCVM"}; private static final int dType = ANY_DATA; private static final int eType = ANY_NUMBER_OF_EVENTS; public FiszCramerVonMisesComparisonAlgorithm() { super(dType, eType); } public String[] algorithmNames() { return names; } public double quality(IComparisonData d1, IComparisonData d2) { if ( d1.type() != d2.type() ) throw new IllegalArgumentException("Incompatible data. One is binned and the other unbinned. Cannot compare."); double[] cumulativeWeights1 = getCumulativeArray(d1); double[] cumulativeWeights2 = getCumulativeArray(d2); int nPoints1 = d1.nPoints(); int nPoints2 = d2.nPoints(); int j1=0, j2=0; double data1 = 0., data2 = 0.; double cumulative1 = 0., cumulative2 = 0.; double t=0.; double sumOfWeightsSquared1 = 0; for ( int i = 0; i < nPoints1; i++ ) sumOfWeightsSquared1 += Math.pow(d1.entries(i),2); double sumOfWeightsSquared2 = 0; for ( int i = 0; i < nPoints2; i++ ) sumOfWeightsSquared2 += Math.pow(d2.entries(i),2); boolean advance1, advance2; boolean flag1 = true, flag2 = true; while(true){ advance1 = false; advance2 = false; data1 = d1.value(j1); data2 = d2.value(j2); if( data1 <= data2 ){ cumulative1 = cumulativeWeights1[j1]; advance1 = true; } if( data2 <= data1){ cumulative2 = cumulativeWeights2[j2]; advance2 = true; } t += ( cumulative2 - cumulative1) * ( cumulative2 - cumulative1); if ( j1 == nPoints1 -1 ) flag1 = false; if ( j2 == nPoints2 -1 ) flag2 = false; if ( advance1 ) { if ( flag1 ) j1++; } else if ( ! flag2 ) if ( flag1 ) j1++; if ( advance2 ) { if ( flag2 ) j2++; } else if ( ! flag1 ) if ( flag2 ) j2++; if ( (!flag1) && (!flag2) ) break; } // Multiply by two for binned data. if ( d1.type() == IComparisonData.BINNED_DATA ) t *= 2; double entries1 = (double)entries(d1); double entries2 = (double)entries(d2); double entriesProduct = entries1 * entries2; double totalentriesSquared = ( entries1 + entries2 ) * ( entries1 + entries2 ); double r = (entriesProduct / totalentriesSquared); double s1 = sumOfWeightsSquared1; double s2 = sumOfWeightsSquared2; double s = s1+s2; double e = entries1+entries2; double val = t * r * s / e; return val; } public void setRejectionLevel() { super.setRejectionLevel(); double aL = rejectionLevel(); boolean found = false; for ( int i = 0; i < rejectionValues.length; i++ ) if ( aL == rejectionValues[i]) { found = true; break; } if ( ! found ) { String levels = ""; for ( int i = 0; i < rejectionValues.length; i++ ) levels += rejectionValues[i]+" "; System.out.println("Algorithm "+algorithmNames()[0]+" can currently support ONLY the following rejection levels: "+levels); } } public double matchUpperBound() { double aL = rejectionLevel(); for ( int i = 0; i < rejectionValues.length; i++ ) if ( aL == rejectionValues[i]) return criticalValues[i]; return criticalValues[1]; } public double matchLowerBound() { return 0; } }