package hep.aida.ref.fitter;
import hep.aida.IAnalysisFactory;
import hep.aida.IAnnotation;
import hep.aida.IBaseHistogram;
import hep.aida.ICloud;
import hep.aida.IDataPointSet;
import hep.aida.IFitData;
import hep.aida.IFitParameterSettings;
import hep.aida.IFitResult;
import hep.aida.IFunction;
import hep.aida.IFunctionFactory;
import hep.aida.IHistogram;
import hep.aida.IHistogram1D;
import hep.aida.IHistogramFactory;
import hep.aida.IManagedObject;
import hep.aida.IModelFunction;
import hep.aida.IProfile;
import hep.aida.IRangeSet;
import hep.aida.ITree;
import hep.aida.ITupleFactory;
import hep.aida.dev.IDevFitData;
import hep.aida.dev.IDevFitDataIterator;
import hep.aida.dev.IDevFitResult;
import hep.aida.ext.IExtFitter;
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.AidaUtils;
import hep.aida.ref.fitter.fitdata.FitDataCreator;
import hep.aida.ref.function.BaseModelFunction;
import hep.aida.ref.function.FunctionCatalog;
import hep.aida.ref.function.RangeSet;
import hep.aida.ref.histogram.DataPointSet;
import hep.aida.ref.pdf.Dependent;
import hep.aida.ref.pdf.Function;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.Map;
import java.util.StringTokenizer;
import java.util.regex.Pattern;
import org.freehep.util.FreeHEPLookup;
import org.openide.util.Lookup;
/**
* @author The AIDA team @ SLAC.
*
*/
public class Fitter implements IExtFitter {
// The IOptimizer.
private String engineType;
private IOptimizer optimizer = null;
// The IFitMethod.
private String fitMethodType;
private IFitMethod fitMethod = null;
// The IFunction to be minimized.
private IFunction fitFunction;
// IFitParameterSettings
private Hashtable fitParHash = new Hashtable();
private boolean useGradient = true;
private ArrayList constraintList = new ArrayList();
private Hashtable simpleConstraintHash = new Hashtable();
private boolean createClone = true;
/**
* Create a new Fitter specifying the underlying optimizing engine.
* @param fitMethodType The type of fitter.
* @param engineType The type of optimizer to use.
* @throws IllegalArgumentException if the engineType does not exist.
*
*/
public Fitter(String fitMethodType, String engineType, String options) throws IllegalArgumentException {
setFitMethod(fitMethodType);
setEngine(engineType);
Map opt = hep.aida.ref.AidaUtils.parseOptions(options);
String val = (String) opt.get("noClone");
if ( val != null && val.trim().equalsIgnoreCase("true") ) createClone = false;
}
public void setEngine(String engineType) throws IllegalArgumentException {
if (engineType == null || engineType.length() == 0) engineType = "jminuit";
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 void setFitMethod(String fitMethodType) throws IllegalArgumentException {
if (fitMethodType == null || fitMethodType.length() == 0) fitMethodType = "chi2";
// 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);
this.fitMethodType = fitMethodType;
this.fitMethod = tmpFitMethod;
}
public IOptimizer optimizer() {
return optimizer;
}
public String fitMethodName() {
return fitMethodType;
}
public IFitParameterSettings fitParameterSettings(String name) {
if ( fitParHash.containsKey(name) ) return (IFitParameterSettings) fitParHash.get(name);
IFitParameterSettings fitPar = new FitParameterSettings(name);
fitParHash.put(name,fitPar);
return fitPar;
}
public String[] listParameterSettings() {
int size = fitParHash.size();
String[] parNames = new String[size];
Enumeration e = fitParHash.keys();
for (int i = 0; e.hasMoreElements(); i++)
parNames[i] = (String) e.nextElement();
return parNames;
}
public void resetParameterSettings() {
fitParHash.clear();
}
public IFitResult fit( Function f ) {
if ( f.numberOfDependents() != 1 )
throw new IllegalArgumentException("Currently we only fit 1 dimensional functions.");
Dependent x = f.getDependent(0);
if ( ! x.isConnected() )
throw new IllegalArgumentException("Dependent "+x.name()+" is not connected to a data set");
IFitData data = x.data();
return fit( data, f );
}
public IFitResult fit(IFitData d, IFunction originalFunction) {
return fit(d, originalFunction, null);
}
public IFitResult fit(IFitData d, IFunction originalFunction, String range) {
return fit(d, originalFunction, range, null);
}
private void addBounds(IRangeSet rs, int index, double[] lb, double[] ub) {
if ( lb.length == 0 ) throw new RuntimeException("No ranges are set in the FitData. Please report the problem");
for ( int j = 0; j < ub.length; j++ )
rs.include(lb[j],ub[j]);
}
public IFitResult fit(IFitData d, IFunction originalFunction, String range, Object correlationObject) {
String name = "";
if ( originalFunction instanceof IManagedObject ) {
name = ((IManagedObject) originalFunction).name();
} else {
name = originalFunction.title();
}
name += " "+engineName()+" fit";
IFunction fClone = cloneFunction(name,originalFunction);
boolean setRange = false;
if ( originalFunction instanceof IFunction )
setRange = true;
// IModelFunction f = (IModelFunction)originalFunction;
IModelFunction f;
if ( fClone instanceof IModelFunction ) {
f = (IModelFunction)fClone;
} else if (fClone instanceof IFunction) {
f = new BaseModelFunction(name, name, fClone);
} else {
throw new RuntimeException("Fitter for now can only use IModelFunctions and IFunctions. Please report this problem");
}
if ( range != null ) {
Map optionsMap = AidaUtils.parseOptions( range );
range = (String) optionsMap.get("range");
RangeSet usersRange = new RangeSet(range);
IRangeSet rs = d.range(0);
rs.excludeAll();
addBounds(rs, 0, usersRange.lowerBounds(), usersRange.upperBounds());
}
if ( setRange ) {
f.excludeNormalizationAll();
//Set ranges on function.
IRangeSet d_rs = null;
for ( int i = 0; i < d.dimension(); i++ ) {
d_rs = d.range(i);
IRangeSet f_rs = f.normalizationRange(i);
addBounds(f_rs, i, d_rs.lowerBounds(), d_rs.upperBounds());
}
}
//Clear the fit method and set the correlation Object
fitMethod.clear();
fitMethod.setCorrelationObject(correlationObject);
loadFitDataAndFunction(d,f);
long startFit = System.currentTimeMillis();
optimizer.optimize();
long endFit = System.currentTimeMillis();
double fitSeconds = (double)(endFit-startFit)/1000.;
// Set the minimum parameters on the function
String[] parNames = f.parameterNames();
for( int i = 0; i < parNames.length; i++ )
f.setParameter(parNames[i],optimizer.result().parameters()[i]);
double[][] covMatrix = optimizer.result().covarianceMatrix();
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 );
int countI = 0;
for( int i = 0; i < parNames.length; i++ ) {
result.setFitParameterSettings( parNames[i], fitParameterSettings(parNames[i]) );
int countJ = 0;
for( int j = 0; j < parNames.length; j++ ) {
if ( ! optimizer.variableSettings(parNames[i]).isFixed() && ! optimizer.variableSettings(parNames[j]).isFixed() )
result.setCovMatrixElement( i, j , covMatrix[countI][countJ++] );
}
if ( ! optimizer.variableSettings(parNames[i]).isFixed() ) countI++;
}
return (IFitResult)result;
}
public IFitResult fit(IBaseHistogram h, IFunction f) {
return fit( h, f, null);
}
public IFitResult fit(IBaseHistogram h, IFunction f, String range) {
if ( h instanceof IHistogram || h instanceof IProfile )
if ( fitMethod.fitType() == IFitMethod.UNBINNED_FIT ) throw new IllegalArgumentException("Cannot perform unbinned fit on a IHistogram!!");
else if ( h instanceof ICloud )
if ( fitMethod.fitType() == IFitMethod.BINNED_FIT ) throw new IllegalArgumentException("Cannot perform binned fit on a ICloud!!");
IFitData fitData = FitDataCreator.create(h);
return fit( fitData, f, range );
}
private void setDefaultInitialParameters(IFunction f, String model, Object data) {
if ( model.equals("g") ) {
if ( data instanceof IHistogram1D ) {
IHistogram1D h1 = (IHistogram1D) data;
double[] pars = new double[3];
pars[0] = h1.maxBinHeight();
pars[1] = h1.mean();
pars[2] = h1.rms();
f.setParameters(pars);
}
}
}
public IFitResult fit(IBaseHistogram h, String model) {
return fit(h, model, (String)null);
}
public IFitResult fit(IBaseHistogram h, String model, String range) {
IFunction func = FunctionCatalog.getFunctionCatalog().create(model);
setDefaultInitialParameters(func, model, h);
return fit(h,func, range);
}
public IFitResult fit(IBaseHistogram h, String model, double[] initialParameters) {
return fit(h,model, initialParameters, null);
}
public IFitResult fit(IBaseHistogram h, String model, double[] initialParameters, String range) {
IFunction func = FunctionCatalog.getFunctionCatalog().create(model);
if ( initialParameters.length != func.numberOfParameters() ) throw new IllegalArgumentException("Wrong number of parameters "+initialParameters.length+
"! This function requires "+func.numberOfParameters());
func.setParameters(initialParameters);
return fit(h,func, range);
}
public IFitResult fit(IDataPointSet dataPointSet, IFunction f) {
return fit(dataPointSet, f, (String)null);
}
public IFitResult fit(IDataPointSet dataPointSet, IFunction f, String range) {
return fit(dataPointSet, f, range, null);
}
public IFitResult fit(IDataPointSet dataPointSet, IFunction f, double[] initialParameters) {
return fit(dataPointSet, f, initialParameters, null, null);
}
public IFitResult fit(IDataPointSet dataPointSet, IFunction f, String range, Object correlationObject) {
return fit(dataPointSet, f, null, range, correlationObject);
}
public IFitResult fit(IDataPointSet dataPointSet, IFunction f, double[] initialParameters, String range, Object correlationObject) {
if ( fitMethod.fitType() == IFitMethod.UNBINNED_FIT ) throw new IllegalArgumentException("Cannot perform unbinned fit on a IDataPointSet!!");
if ( dataPointSet.dimension() != f.dimension() + 1 ) throw new IllegalArgumentException("Wrong dimension match. DataPointSets can only be fitted if"+
" their dimension is one unit bigger than the one of the function");
if ( initialParameters != null ) {
if ( initialParameters.length != f.numberOfParameters() ) throw new IllegalArgumentException("Wrong number of parameters "+initialParameters.length+
"! This function requires "+f.numberOfParameters());
f.setParameters(initialParameters);
}
IFitData fitData = FitDataCreator.create(dataPointSet);
return fit( fitData, f, range, correlationObject );
}
public IFitResult fit(IDataPointSet dataPointSet, String model) {
return fit(dataPointSet, model, (String)null);
}
public IFitResult fit(IDataPointSet dataPointSet, String model, String range) {
return fit(dataPointSet,model, range, null);
}
public IFitResult fit(IDataPointSet dataPointSet, String model, String range, Object correlationObject) {
IFunction func = FunctionCatalog.getFunctionCatalog().create(model);
setDefaultInitialParameters(func, model, dataPointSet);
return fit(dataPointSet,func, range, correlationObject);
}
public IFitResult fit(IDataPointSet dataPointSet, String model, double[] initialParameters) {
return fit(dataPointSet, model, initialParameters, null, null);
}
public IFitResult fit(IDataPointSet dataPointSet, String model, double[] initialParameters, String range) {
return fit(dataPointSet, model, initialParameters, range, null);
}
public IFitResult fit(IDataPointSet dataPointSet, String model, double[] initialParameters, String range, Object correlationObject) {
IFunction func = FunctionCatalog.getFunctionCatalog().create(model);
return fit(dataPointSet,func, initialParameters, range, correlationObject);
}
public IFitResult fit(IFitData d, String model, double[] initialParameters) {
return fit(d,model,initialParameters,null);
}
public IFitResult fit(IFitData d, String model, double[] initialParameters, String range) {
return fit(d,model,initialParameters, range, null);
}
public IFitResult fit(IFitData d, String model, double[] initialParameters, String range, Object correlationObject) {
IFunction func = FunctionCatalog.getFunctionCatalog().create(model);
if ( initialParameters != null ) {
if ( initialParameters.length != func.numberOfParameters() ) throw new IllegalArgumentException("Wrong number of parameters "+initialParameters.length+
"! This function requires "+func.numberOfParameters());
func.setParameters(initialParameters);
}
return fit(d,func, range, correlationObject);
}
public IFitResult fit(IFitData d, String model) {
return fit(d,model,(String)null);
}
public IFitResult fit(IFitData d, String model, String range) {
return fit(d,model, range, null);
}
public IFitResult fit(IFitData d, String model, String range, Object correlationObject) {
IFunction func = FunctionCatalog.getFunctionCatalog().create(model);
return fit(d,func, range, correlationObject);
}
public void setConstraint(String expression) throws IllegalArgumentException {
if ( ! optimizer.acceptsConstraints() )
throw new UnsupportedOperationException("Optimizer "+engineName()+" does not accept constraints.");
StringTokenizer st = new StringTokenizer(expression,"=");
if ( st.countTokens() != 2 ) throw new IllegalArgumentException("Only constraints of the form \" parName = SomeExpression \" are supported");
String parName = st.nextToken().trim();
if ( ! Pattern.matches("\\w+", parName) ) throw new IllegalArgumentException("Incorrect parameter name "+parName);
String constrExpression = st.nextToken().trim();
if ( Pattern.matches("\\w+",constrExpression) ) {
simpleConstraintHash.put(parName,constrExpression);
} else {
throw new IllegalArgumentException("This type of constraint is not supported yet "+parName+" = "+constrExpression);
}
constraintList.add(expression);
}
public String[] constraints() {
int size = constraintList.size();
String[] constraints = new String[size];
for ( int i = 0; i pmax ) throw new IllegalArgumentException("Incorret parameter limits : "+pmin+" has to be less than "+pmax);
if ( npts < 1 ) throw new IllegalArgumentException("The number of points has to be greater than zero : "+npts);
IFunction fClone = cloneFunction(null, originalFunction);
IModelFunction f;
if ( fClone instanceof IModelFunction ) {
f = (IModelFunction)fClone;
} else {
f = new BaseModelFunction("", "", fClone);
}
loadFitDataAndFunction(d,f);
int index = f.indexOfParameter( parName );
IFitParameterSettings fitParSet = fitParameterSettings(parName);
if ( fitParSet.isFixed() ) throw new IllegalArgumentException("Parameter "+parName+" is fixed");
IDataPointSet dps = new DataPointSet("",parName+" scan",2,npts);
double step = (pmax - pmin)/(npts-1);
double startValue = optimizer.variableSettings(parName).value();
for ( int i = 0; i -1 && ind2 > -1 ) {
varSimpleConstraint1.add( new Integer(ind1) );
varSimpleConstraint2.add( new Integer(ind2) );
}
}
protected boolean isValidSimpleConstraint(String varName1, String varName2 ) {
int ind1 = indexOfVariable( varName1 );
int ind2 = indexOfVariable( varName2 );
if ( ind1 > -1 && ind2 > -1 ) return true;
return false;
}
protected void applySimpleConstraint( double[] x ) {
for ( int i = 0; i < varSimpleConstraint1.size(); i++ ) {
int ind1 = ( (Integer) varSimpleConstraint1.get(i) ).intValue();
int ind2 = ( (Integer) varSimpleConstraint2.get(i) ).intValue();
x[ind1] = x[ind2];
}
}
}
}
Ads help maintain this website.