package org.freehep.math.minuit; /** * * @version $Id: MnLineSearch.java 8584 2006-08-10 23:06:37Z duns $ */ abstract class MnLineSearch { static MnParabolaPoint search(MnFcn fcn, MinimumParameters st, MnAlgebraicVector step, double gdel, MnMachinePrecision prec) { double overal = 1000.; double undral = -100.; double toler = 0.05; double slamin = 0.; double slambg = 5.; double alpha = 2.; int maxiter = 12; int niter = 0; for(int i = 0; i < step.size(); i++) { if(Math.abs(step.get(i)) < prec.eps()) continue; double ratio = Math.abs(st.vec().get(i)/step.get(i)); if(Math.abs(slamin) < prec.eps()) slamin = ratio; if(ratio < slamin) slamin = ratio; } if(Math.abs(slamin) < prec.eps()) slamin = prec.eps(); slamin *= prec.eps2(); double F0 = st.fval(); double F1 = fcn.valueOf(MnUtils.add(st.vec(),step)); double fvmin = st.fval(); double xvmin = 0.; if(F1 < F0) { fvmin = F1; xvmin = 1.; } double toler8 = toler; double slamax = slambg; double flast = F1; double slam = 1.; boolean iterate = false; MnParabolaPoint p0 = new MnParabolaPoint(0., F0); MnParabolaPoint p1 = new MnParabolaPoint(slam, flast); double F2 = 0.; do { // cut toler8 as function goes up iterate = false; MnParabola pb = MnParabolaFactory.create(p0, gdel, p1); double denom = 2.*(flast-F0-gdel*slam)/(slam*slam); if(Math.abs(denom) < prec.eps()) { denom = -0.1*gdel; slam = 1.; } if(Math.abs(denom) > prec.eps()) slam = -gdel/denom; if(slam < 0.) slam = slamax; if(slam > slamax) slam = slamax; if(slam < toler8) slam = toler8; if(slam < slamin) { return new MnParabolaPoint(xvmin, fvmin); } if(Math.abs(slam - 1.) < toler8 && p1.y() < p0.y()) { return new MnParabolaPoint(xvmin, fvmin); } if(Math.abs(slam - 1.) < toler8) slam = 1. + toler8; F2 = fcn.valueOf(MnUtils.add(st.vec(),MnUtils.mul(step,slam))); if(F2 < fvmin) { fvmin = F2; xvmin = slam; } if(p0.y()-prec.eps() < fvmin && fvmin < p0.y()+prec.eps()) { iterate = true; flast = F2; toler8 = toler*slam; overal = slam - toler8; slamax = overal; p1 = new MnParabolaPoint(slam, flast); niter++; } } while(iterate && niter < maxiter); if(niter >= maxiter) { // exhausted max number of iterations return new MnParabolaPoint(xvmin, fvmin); } MnParabolaPoint p2 = new MnParabolaPoint(slam, F2); do { slamax = Math.max(slamax, alpha*Math.abs(xvmin)); MnParabola pb = MnParabolaFactory.create(p0, p1, p2); if(pb.a() < prec.eps2()) { double slopem = 2.*pb.a()*xvmin + pb.b(); if(slopem < 0.) slam = xvmin + slamax; else slam = xvmin - slamax; } else { slam = pb.min(); if(slam > xvmin + slamax) slam = xvmin + slamax; if(slam < xvmin - slamax) slam = xvmin - slamax; } if(slam > 0.) { if(slam > overal) slam = overal; } else { if(slam < undral) slam = undral; } double F3 = 0.; do { iterate = false; double toler9 = Math.max(toler8, Math.abs(toler8*slam)); // min. of parabola at one point if( Math.abs(p0.x() - slam) < toler9 || Math.abs(p1.x() - slam) < toler9 || Math.abs(p2.x() - slam) < toler9) { return new MnParabolaPoint(xvmin, fvmin); } F3 = fcn.valueOf(MnUtils.add(st.vec(),MnUtils.mul(step,slam))); // if latest point worse than all three previous, cut step if(F3 > p0.y() && F3 > p1.y() && F3 > p2.y()) { if(slam > xvmin) overal = Math.min(overal, slam-toler8); if(slam < xvmin) undral = Math.max(undral, slam+toler8); slam = 0.5*(slam + xvmin); iterate = true; niter++; } } while(iterate && niter < maxiter); if(niter >= maxiter) { // exhausted max number of iterations return new MnParabolaPoint(xvmin, fvmin); } // find worst previous point out of three and replace MnParabolaPoint p3 = new MnParabolaPoint(slam, F3); if(p0.y() > p1.y() && p0.y() > p2.y()) p0 = p3; else if(p1.y() > p0.y() && p1.y() > p2.y()) p1 = p3; else p2 = p3; if(F3 < fvmin) { fvmin = F3; xvmin = slam; } else { if(slam > xvmin) overal = Math.min(overal, slam-toler8); if(slam < xvmin) undral = Math.max(undral, slam+toler8); } niter++; } while(niter < maxiter); return new MnParabolaPoint(xvmin, fvmin); } }