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 KuiperComparisonAlgorithm extends AbstractComparisonAlgorithm {
private static final double ACCURACY = 0.001;
private static final double CONVERGENCE = 1.e-8;
private static final String[] names = new String[] {"Kuiper"};
private static final int dType = ONLY_UNBINNED_DATA;
private static final int eType = ANY_NUMBER_OF_EVENTS;
public KuiperComparisonAlgorithm() {
super(dType, eType);
}
public String[] algorithmNames() {
return names;
}
public double quality(IComparisonData d1, IComparisonData d2) {
if ( d1.type() != IComparisonData.UNBINNED_DATA || d2.type() != IComparisonData.UNBINNED_DATA )
throw new IllegalArgumentException("The "+algorithmNames()[0]+" comparison can only be applyed to unbinned data.");
double[] cumulatived1 = getCumulativeArray(d1);
double[] cumulatived2 = getCumulativeArray(d2);
double dPlus=0;
double dMinus=0;
double data1=0.,data2=0.;
double cumulative1=0.,cumulative2=0.;
int j1=0,j2=0;
int nPoints1 = d1.nPoints();
int nPoints2 = d2.nPoints();
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 = cumulatived1[j1];
advance1 = true;
}
if(data2 <= data1){
cumulative2 = cumulatived2[j2];
advance2 = true;
}
double delta = (cumulative2 - cumulative1);
if( delta > dPlus) dPlus = delta;
if( -1*delta > dMinus) dMinus = -1*delta;
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;
}
double distance = dPlus + dMinus;
double entries1 = entries(d1);
double entries2 = entries(d2);
double eventProduct = entries1*entries2;
double eventSum = entries1+entries2;
double rootEvt = Math.sqrt(eventProduct/eventSum);
double arg = (rootEvt + 0.155 + 0.24/rootEvt) * distance;
double arg2 = -2.*arg*arg;
double factor = 2.;
double factor2 = 0.;
double product = 0.;
double term = 0;
double soFar = 0;
double sum = 0;
double argument = 0;
for ( int i = 1; i < 100; i++ ) {
argument = arg2 * i * i;
term = factor * Math.exp( argument );
factor2 = -2 * arg2 * i * i -1;
product = factor2 * term;
sum += product;
if ( Math.abs(term) <= soFar * ACCURACY ||
Math.abs(term) <= sum * CONVERGENCE ) return sum;
soFar = Math.abs(term);
}
return 1.;
}
}