package hep.aida.ref.pdf;
import hep.aida.IFitData;
import hep.aida.IFunction;
import hep.aida.dev.IDevFitData;
import hep.aida.dev.IDevFitDataIterator;
import hep.aida.ext.IFitMethod;
import hep.aida.ext.IOptimizer;
import hep.aida.ext.IOptimizerConfiguration;
import hep.aida.ext.IOptimizerFactory;
import hep.aida.ext.IVariableSettings;
import hep.aida.ref.fitter.fitdata.FitDataCreator;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import org.freehep.util.FreeHEPLookup;
import org.openide.util.Lookup;
/**
* Another implementation of IFitter.
*
* @author The FreeHEP team @ SLAC.
*
*/
public class PdfFitter {
// The IOptimizer.
private String engineType;
private IOptimizer optimizer = null;
// The IFitMethod.
private String fitMethodType;
private IFitMethod fitMethod = null;
// Internal configuration
private boolean useGradient = true;
public PdfFitter(String fitMethodType, String engineType) throws IllegalArgumentException {
setFitMethod(fitMethodType);
setEngine(engineType);
}
public void setEngine(String engineType) throws IllegalArgumentException {
if (engineType == null || engineType.length() == 0) engineType = "uncmin";
String enType = engineType.toLowerCase();
IOptimizerFactory tmpOptimizerFactory = null;
Lookup.Template template = new Lookup.Template(IOptimizerFactory.class);
Lookup.Result result = FreeHEPLookup.instance().lookup(template);
Collection c = result.allInstances();
for (Iterator i = c.iterator(); i.hasNext(); ) {
IOptimizerFactory of = (IOptimizerFactory)i.next();
String[] names = of.optimizerFactoryNames();
if ( names == null || names.length == 0 )
throw new IllegalArgumentException("IOptimizerFactory with illegal names!");
for ( int j = 0; j < names.length; j++ ) {
if ( enType.equals( names[j].toLowerCase() ) ) {
tmpOptimizerFactory = of;
break;
}
}
}
if (tmpOptimizerFactory == null) throw new IllegalArgumentException("Cannot create IOptimizer of type: "+engineType);
this.engineType = engineType;
this.optimizer = tmpOptimizerFactory.create(engineType);
}
public String engineName() {
return engineType;
}
public static IFitMethod getFitMethod(String fitMethodType) throws IllegalArgumentException {
// Check the lookup table to look for the fitMethod of the given type.
String fitMet = fitMethodType.toLowerCase();
IFitMethod tmpFitMethod = null;
Lookup.Template template = new Lookup.Template(IFitMethod.class);
Lookup.Result result = FreeHEPLookup.instance().lookup(template);
Collection c = result.allInstances();
for (Iterator i = c.iterator(); i.hasNext(); ) {
IFitMethod fm = (IFitMethod)i.next();
String[] names = fm.fitMethodNames();
if ( names == null || names.length == 0 )
throw new IllegalArgumentException("IFitMethod with illegal names!");
for ( int j = 0; j < names.length; j++ ) {
if ( fitMet.equals( names[j].toLowerCase() ) ) {
tmpFitMethod = fm;
break;
}
}
}
if (tmpFitMethod == null) throw new IllegalArgumentException("Unknown IFitMethod type: "+fitMethodType);
return tmpFitMethod;
}
public void setFitMethod(String fitMethodType) throws IllegalArgumentException {
if (fitMethodType == null || fitMethodType.length() == 0) fitMethodType = "chi2";
this.fitMethodType = fitMethodType;
this.fitMethod = getFitMethod(fitMethodType);
}
public String fitMethodName() {
return fitMethodType;
}
public void fit(Object[] objs, Function[] functions) {
IFitData[] data = new IFitData[objs.length];
for ( int i = 0; i < data.length; i++ )
data[i] = FitDataCreator.create(objs[i]);
fit( data, functions);
}
public void fit(IFitData[] data, Function[] functions) {
int nData = data.length;
if ( nData != functions.length )
throw new IllegalArgumentException("Inconsistent number of data sets ("+nData+") and functions ("+functions.length+").");
int fitType = fitMethod.fitType();
for ( int i = 0; i < nData; i++ ) {
if ( fitType != ( (IDevFitData) data[i] ).fitType() ) throw new IllegalArgumentException("This FitData is incompatible with the selected fit method");
if ( data[i].dimension() != functions[i].numberOfDependents() ) throw new IllegalArgumentException("Dimension mismatch!! Function's dimension "+functions[i].numberOfDependents()+" FitData's dimension "+data[i].dimension());
}
// For simultaneous fits the normalization parameter of the functions have to have different names.
// The name is changed before the fit and changed back after the fit.
if ( nData > 1 )
for ( int i = 0; i < nData; i++ )
functions[i].getNormalizationParameter().setName("norm_"+i);
fitMethod.clear();
optimizer.reset();
setErrorDefinition();
boolean normalizeFunction = fitType == IFitMethod.UNBINNED_FIT;
for ( int i = 0; i < nData; i++ )
functions[i].normalize(normalizeFunction);
InternalObjectiveFunction objectiveFunction = new InternalObjectiveFunction(data, functions, fitMethod);
for( int i = 0; i < objectiveFunction.dimension(); i++ ) {
Parameter p = objectiveFunction.getVariable(i);
IVariableSettings varSet = optimizer.variableSettings(p.name());
varSet.setValue( p.value() );
varSet.setFixed( p.isFixed() );
double stepSize = p.stepSize();
if ( Double.isNaN( stepSize ) ) {
stepSize = 0.1*Math.abs(p.value());
if ( stepSize < 1 ) stepSize = 1;
}
varSet.setStepSize( stepSize );
if ( p.useBounds() )
varSet.setBounds( p.lowerBound(), p.upperBound() );
}
optimizer.setFunction(objectiveFunction);
optimizer.configuration().setUseFunctionGradient(objectiveFunction.providesGradient() && useFunctionGradient());
optimizer.configuration().setMaxIterations(500);
// optimizer.configuration().setPrintLevel(-2);
optimizer.optimize();
// Change back the name of the normalization parameter.
if ( nData > 1 )
for ( int i = 0; i < nData; i++ )
functions[i].getNormalizationParameter().setName("norm");
}
public void fit(Object obj, Function function) {
IFitData data = FitDataCreator.create(obj);
fit( data, function);
}
public void fit(IFitData data, Function function) {
fit( new IFitData[] {data}, new Function[] { function } );
/*
int status = optimizer.result().optimizationStatus();
int dataEntries = ((FitFunction) fitFunction).dataEntries();
int freePars = ((FitFunction) fitFunction).nFreePars();
int nDoF = dataEntries - freePars;
double funcVal = fitFunction.value(f.parameters());
IDevFitResult result = new FitResult(fitFunction.dimension(), fitSeconds);
result.setConstraints( constraints() );
result.setDataDescription( d.dataDescription() );
result.setEngineName( engineName() );
result.setFitMethodName( fitMethodName() );
result.setFitStatus( status );
result.setFittedFunction( f ); // FIX ME! Replace with clone.
result.setIsValid( true ); ////??????
result.setNdf( nDoF );
if ( fitMethod.fitType() == IFitMethod.UNBINNED_FIT )
result.setQuality( funcVal/nDoF/Math.sqrt(2.) );
else
result.setQuality( funcVal/nDoF );
*/
}
public boolean useFunctionGradient() {
return useGradient;
}
public void setUseFunctionGradient(boolean useGradient) {
this.useGradient = useGradient;
}
private void setErrorDefinition() {
if ( fitMethod.fitType() == IFitMethod.BINNED_FIT )
optimizer.configuration().setErrorDefinition(IOptimizerConfiguration.CHI2_FIT_ERROR);
else
optimizer.configuration().setErrorDefinition(IOptimizerConfiguration.LOGL_FIT_ERROR);
}
}