package org.freehep.math.minuit;
import java.util.List;
import java.util.ArrayList;
/**
*
* @version $Id: VariableMetricBuilder.java 8584 2006-08-10 23:06:37Z duns $
*/
class VariableMetricBuilder implements MinimumBuilder
{
VariableMetricBuilder()
{
theEstimator = new VariableMetricEDMEstimator();
theErrorUpdator = new DavidonErrorUpdator();
}
public FunctionMinimum minimum(MnFcn fcn, GradientCalculator gc, MinimumSeed seed, MnStrategy strategy, int maxfcn, double edmval)
{
FunctionMinimum min = minimum(fcn, gc, seed, maxfcn, edmval);
if( (strategy.strategy() == 2) || (strategy.strategy() == 1 && min.error().dcovar() > 0.05) )
{
MinimumState st = new MnHesse(strategy).calculate(fcn, min.state(), min.seed().trafo(),0);
min.add(st);
}
if(!min.isValid()) System.err.println("FunctionMinimum is invalid.");
return min;
}
FunctionMinimum minimum(MnFcn fcn, GradientCalculator gc, MinimumSeed seed, int maxfcn, double edmval)
{
edmval *= 0.0001;
if(seed.parameters().vec().size() == 0)
{
return new FunctionMinimum(seed, fcn.errorDef());
}
MnMachinePrecision prec = seed.precision();
List<MinimumState> result = new ArrayList<MinimumState>(8);
double edm = seed.state().edm();
if(edm < 0.)
{
System.err.println("VariableMetricBuilder: initial matrix not pos.def.");
if (seed.error().isPosDef()) throw new RuntimeException("Something is wrong!");
return new FunctionMinimum(seed, fcn.errorDef());
}
result.add(seed.state());
// iterate until edm is small enough or max # of iterations reached
edm *= (1. + 3.*seed.error().dcovar());
MnAlgebraicVector step = new MnAlgebraicVector(seed.gradient().vec().size());
do
{
MinimumState s0 = result.get(result.size()-1);
step = MnUtils.mul(MnUtils.mul(s0.error().invHessian(),s0.gradient().vec()),-1);
double gdel = MnUtils.innerProduct(step, s0.gradient().grad());
if(gdel > 0.)
{
System.err.println("VariableMetricBuilder: matrix not pos.def.");
System.err.println("gdel > 0: "+gdel);
s0 = MnPosDef.test(s0, prec);
step = MnUtils.mul(MnUtils.mul(s0.error().invHessian(),s0.gradient().vec()),-1);
gdel = MnUtils.innerProduct(step, s0.gradient().grad());
System.err.println("gdel: "+gdel);
if(gdel > 0.)
{
result.add(s0);
return new FunctionMinimum(seed, result, fcn.errorDef());
}
}
MnParabolaPoint pp = MnLineSearch.search(fcn, s0.parameters(), step, gdel, prec);
if(Math.abs(pp.y() - s0.fval()) < prec.eps())
{
System.err.println("VariableMetricBuilder: no improvement");
break; //no improvement
}
MinimumParameters p = new MinimumParameters(MnUtils.add(s0.vec(), MnUtils.mul(step,pp.x())), pp.y());
FunctionGradient g = gc.gradient(p, s0.gradient());
edm = estimator().estimate(g, s0.error());
if(edm < 0.)
{
System.err.println("VariableMetricBuilder: matrix not pos.def.");
System.err.println("edm < 0");
s0 = MnPosDef.test(s0, prec);
edm = estimator().estimate(g, s0.error());
if(edm < 0.)
{
result.add(s0);
return new FunctionMinimum(seed, result, fcn.errorDef());
}
}
MinimumError e = errorUpdator().update(s0, p, g);
result.add(new MinimumState(p, e, g, edm, fcn.numOfCalls()));
// result[0] = MinimumState(p, e, g, edm, fcn.numOfCalls());
edm *= (1. + 3.*e.dcovar());
} while(edm > edmval && fcn.numOfCalls() < maxfcn);
if(fcn.numOfCalls() >= maxfcn)
{
System.err.println("VariableMetricBuilder: call limit exceeded.");
return new FunctionMinimum(seed, result, fcn.errorDef(), new FunctionMinimum.MnReachedCallLimit());
}
if(edm > edmval)
{
if(edm < Math.abs(prec.eps2()*result.get(result.size()-1).fval()))
{
System.err.println("VariableMetricBuilder: machine accuracy limits further improvement.");
return new FunctionMinimum(seed, result, fcn.errorDef());
}
else if(edm < 10.*edmval)
{
return new FunctionMinimum(seed, result, fcn.errorDef());
}
else
{
System.err.println("VariableMetricBuilder: finishes without convergence.");
System.err.println("VariableMetricBuilder: edm= "+edm+" requested: "+edmval);
return new FunctionMinimum(seed, result, fcn.errorDef(), new FunctionMinimum.MnAboveMaxEdm());
}
}
return new FunctionMinimum(seed, result, fcn.errorDef());
}
VariableMetricEDMEstimator estimator()
{
return theEstimator;
}
DavidonErrorUpdator errorUpdator()
{
return theErrorUpdator;
}
private VariableMetricEDMEstimator theEstimator;
private DavidonErrorUpdator theErrorUpdator;
}