package org.freehep.math.minuit; /** In case that one of the components of the second derivative g2 calculated * by the numerical gradient calculator is negative, a 1dim line search in * the direction of that component is done in order to find a better position * where g2 is again positive. * @version $Id: NegativeG2LineSearch.java 8584 2006-08-10 23:06:37Z duns $ */ abstract class NegativeG2LineSearch { static MinimumState search(MnFcn fcn, MinimumState st, GradientCalculator gc, MnMachinePrecision prec) { boolean negG2 = hasNegativeG2(st.gradient(), prec); if(!negG2) return st; int n = st.parameters().vec().size(); FunctionGradient dgrad = st.gradient(); MinimumParameters pa = st.parameters(); boolean iterate = false; int iter = 0; do { iterate = false; for(int i = 0; i < n; i++) { if(dgrad.g2().get(i) < prec.eps2()) { // do line search if second derivative negative MnAlgebraicVector step = new MnAlgebraicVector(n); step.set(i,dgrad.gstep().get(i)*dgrad.vec().get(i)); if(Math.abs(dgrad.vec().get(i)) > prec.eps2()) step.set(i, step.get(i) * (-1./Math.abs(dgrad.vec().get(i)))); double gdel = step.get(i)*dgrad.vec().get(i); MnParabolaPoint pp = MnLineSearch.search(fcn, pa, step, gdel, prec); step = MnUtils.mul(step,pp.x()); pa = new MinimumParameters(MnUtils.add(pa.vec(),step), pp.y()); dgrad = gc.gradient(pa, dgrad); iterate = true; break; } } } while(iter++ < 2*n && iterate); MnAlgebraicSymMatrix mat = new MnAlgebraicSymMatrix(n); for(int i = 0; i < n; i++) mat.set(i,i, Math.abs(dgrad.g2().get(i)) > prec.eps2() ? 1./dgrad.g2().get(i) : 1.); MinimumError err = new MinimumError(mat, 1.); double edm = new VariableMetricEDMEstimator().estimate(dgrad, err); return new MinimumState(pa, err, dgrad, edm, fcn.numOfCalls()); } static boolean hasNegativeG2(FunctionGradient grad, MnMachinePrecision prec) { for(int i = 0; i < grad.vec().size(); i++) if(grad.g2().get(i) < prec.eps2()) return true; return false; } }