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 AndersonDarlingComparisonAlgorithm extends AbstractComparisonAlgorithm {
private static final String[] names = new String[] {"AndersonDarling","AD"};
private static final int dType = ANY_DATA;
private static final int eType = ANY_NUMBER_OF_EVENTS;
private static final double[] rejectionValues = new double[] {0.1, 0.05, 0.01, 0.001};
private static final double[] criticalValues = new double[] {1.933, 2.492, 3.857, 4.356};
public AndersonDarlingComparisonAlgorithm() {
super(dType, eType);
}
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 matchLowerBound() {
return 0;
}
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 quality(IComparisonData d1, IComparisonData d2) {
if ( d1.type() != d2.type() )
throw new IllegalArgumentException("Incompatible data sets: one is binned the other is unbinned. Cannot perform test");
int nPoints1 = d1.nPoints();
int nPoints2 = d2.nPoints();
// Calculate the sum of weights
double sumOfWeights1=0.,sumOfWeights2=0.;
for(int i=0; i<nPoints1; i++)
sumOfWeights1 += d1.entries(i);
for(int i=0; i<nPoints2; i++)
sumOfWeights2 += d2.entries(i);
// The total sum of weights:
int entries1 = entries(d1);
int entries2 = entries(d2);
double totalEntries = entries1 + entries2;
double totalEntriesSquared= totalEntries*totalEntries;
double equivalentEntries = (totalEntries -1)/totalEntriesSquared;
double dt1=0., dt1_2=0., dt1_add1=0., dt1_add2=0.;
double dt2=0., dt2_2=0., dt2_add2=0., dt2_add1=0.;
double A2=0.;
double data1=0.,data2=0;
double add1=0.,add2=0;
double ratio1=0.,ratio2=0;
double den=0.;
int j1=0,j2=0;
double sum1=0., sum2=0., sumH=0.;
double frequencies1=0.,frequencies2=0., frequenciesL1=0., frequenciesL2=0.;
double frequenciesTot1=0., frequenciesTot2=0., H=0., h=0.;
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 ){
frequencies1 = d1.entries(j1);
sum1 += frequencies1;
frequenciesTot1 = ( (frequencies1 / 2) + sum1 - frequencies1 );
advance1 = true;
frequencies2=0;
frequenciesTot2 = sum2;
}
else if (data1 == data2) {
frequencies1 = d1.entries(j1);
frequencies2 = d2.entries(j2);
sum1 += frequencies1;
sum2 += frequencies2;
frequenciesTot1 = (frequencies1 / 2 + sum1 - frequencies1);
frequenciesTot2 = (frequencies2 / 2 + sum2 - frequencies2);
advance1 = true;
advance2 = true;
}
else {
frequencies2 = d2.entries(j2);
sum2 += frequencies2;
frequenciesTot2 = (frequencies2 / 2 + sum2 - frequencies2);
advance2 = true;
frequencies1=0;
frequenciesTot1 = sum1;
}
h = frequencies1 + frequencies2;
sumH += frequencies1 + frequencies2;
H = ( h / 2 ) + sumH - h;
if (H != 0 && H != 1){
dt1_add1 = ( sumOfWeights1 + sumOfWeights2 ) * frequenciesTot1;
dt1_add2 = ( sumOfWeights1 * H );
dt1 = dt1_add1 - dt1_add2;
dt1_2 = dt1 * dt1;
dt2_add1 = ( sumOfWeights1 + sumOfWeights2 ) * frequenciesTot2;
dt2_add2 = ( sumOfWeights2 * H );
dt2 = dt2_add1 - dt2_add2;
dt2_2 = dt2 * dt2;
den = ( H * ( sumOfWeights1 + sumOfWeights2 - H ) - ( (sumOfWeights1 + sumOfWeights2) * h / 4));
if ( den != 0 ) {
ratio1 += h * dt1_2 / den;
ratio2 += h * dt2_2 / den;
}
}
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;
}
add1 = ratio1 / sumOfWeights1;
add2 = ratio2 / sumOfWeights2;
A2 = equivalentEntries * ( add1 + add2);
return A2;
}
public String[] algorithmNames() {
return names;
}
}