package hep.aida.ref.optimizer.jminuit;
import hep.aida.ext.IOptimizerConfiguration;
import hep.aida.ext.IOptimizerResult;
import hep.aida.ext.IVariableSettings;
import hep.aida.ref.optimizer.AbstractOptimizer;
import hep.aida.ref.optimizer.OptimizerResult;
import java.util.List;
import java.util.ArrayList;
import org.freehep.math.minuit.FCNBase;
import org.freehep.math.minuit.FunctionMinimum;
import org.freehep.math.minuit.MnMigrad;
import org.freehep.math.minuit.MnUserParameters;
import org.freehep.math.minuit.MnUserCovariance;
import org.freehep.math.minuit.MnContours;
import org.freehep.math.minuit.Point;
/**
*
* JMinuit implementation of IOptimizer
* @author The AIDA team @SLAC.
*
*/
class JMinuitOptimizer extends AbstractOptimizer
{
private FunctionMinimum min;
private FCNBase fcn;
private MnUserParameters upar;
private MnMigrad migrad;
private ArrayList pars;
JMinuitOptimizer()
{
result = new OptimizerResult();
this.setConfiguration(new JMinuitConfiguration());
}
public void optimize()
{
pars = new ArrayList();
// Load the function in Minuit. This will load all the variables.
if ( function == null ) throw new IllegalArgumentException("Cannot optimize!! The function was not set correctly!");
String[] variableNames = function.variableNames();
if ( variableNames == null || variableNames.length == 0 ) throw new IllegalArgumentException("Cannot optimize!! There are no variable parameters in this function!");
upar = new MnUserParameters();
for ( int i = 0; i<variableNames.length; i++ )
{
String varName = variableNames[i];
IVariableSettings varSet = variableSettings(varName);
double value = varSet.value();
if ( Double.isNaN(value) ) throw new IllegalArgumentException("No initial value set for variable "+varName);
if ( varSet.isBound() )
upar.add( varName, value, varSet.stepSize(), varSet.lowerBound(), varSet.upperBound() );
else
upar.add( varName, value, varSet.stepSize());
if ( varSet.isFixed() ) upar.fix(varName);
else pars.add(varName);
}
if (upar.variableParameters() == 0) throw new IllegalArgumentException("Cannot optimize!! There are no free variable registered in Minuit!");
fcn = FunctionWrapper.create(function);
migrad = new MnMigrad(fcn,upar); // FixMe: Use other minimizers
migrad.setErrorDef(((JMinuitConfiguration)configuration).errorDef()); // FixMe: Need to set other parameters here
migrad.setUseAnalyticalDerivatives(configuration.useFunctionGradient());
// migrad.setCheckAnalyticalDerivatives(false);
min = migrad.minimize();
if ( configuration().printLevel() <= IOptimizerConfiguration.NORMAL_OUTPUT )
System.out.println(min.toString());
double[] parameterVals = new double[variableNames.length];
for ( int i = 0; i < parameterVals.length; i++ )
parameterVals[i] = min.userParameters().value(i);
result.setParameters(parameterVals);
result.setOptimizationStatus(min.isValid() ? IOptimizerResult.CONVERGED : IOptimizerResult.NOT_CONVERGED);
double[][] cov;
if (min.isValid())
{
for ( int i = 0; i<variableNames.length; i++ )
{
String varName = variableNames[i];
IVariableSettings varSet = variableSettings(varName);
if ( ! varSet.isFixed() )
{
varSet.setValue(min.userParameters().value(varName));
double err = min.userParameters().error(varName);
if ( ! Double.isNaN(err) )
varSet.setStepSize(min.userParameters().error(varName));
}
}
MnUserCovariance mat = min.userCovariance();
if ( configuration().printLevel() <= IOptimizerConfiguration.NORMAL_OUTPUT )
System.out.println(mat.toString());
cov = new double[mat.nrow()][mat.nrow()];
for (int i=0; i<mat.nrow(); i++)
{
for (int j=0; j<mat.nrow(); j++)
{
cov[i][j] = mat.get(i,j);
}
}
}
else {
cov = new double[pars.size()][pars.size()];
}
result.setCovarianceMatrix( cov );
}
public boolean acceptsConstraints() {
return true;
}
public boolean canCalculateContours() {
return true;
}
public double[][] calculateContour(String par1, String par2, int npts, double nSigmas) {
//Optimizing is not necessary if we find a way to pass FunctionMinimum to the contour.
optimize();
MnContours contour = new MnContours(fcn, min);
int px = -1;
int py = -1;
if ( pars.contains(par1) )
px = pars.indexOf(par1);
else
throw new IllegalArgumentException("Parameter "+par1+" was not part of the fit.");
if ( pars.contains(par2) )
py = pars.indexOf(par2);
else
throw new IllegalArgumentException("Parameter "+par2+" was not part of the fit.");
List points = contour.points(px, py, nSigmas, npts);
double[][] result = new double[2][npts];
for ( int i = 0; i < points.size(); i++ ) {
Point p = (Point) points.get(i);
result[0][i] = p.first;
result[1][i] = p.second;
}
return result;
}
public void reset() {
migrad = null;
}
}