package org.freehep.math.minuit; import java.util.ArrayList; import java.util.List; /** * * @version $Id: SimplexBuilder.java 8584 2006-08-10 23:06:37Z duns $ */ class SimplexBuilder implements MinimumBuilder { public FunctionMinimum minimum(MnFcn mfcn, GradientCalculator gc, MinimumSeed seed, MnStrategy strategy, int maxfcn, double minedm) { MnMachinePrecision prec = seed.precision(); MnAlgebraicVector x = seed.parameters().vec().clone(); MnAlgebraicVector step = MnUtils.mul(seed.gradient().gstep(),10.); int n = x.size(); double wg = 1./n; double alpha = 1., beta = 0.5, gamma = 2., rhomin = 4., rhomax = 8.; double rho1 = 1. + alpha; double rho2 = 1. + alpha*gamma; List<Pair<Double,MnAlgebraicVector>> simpl = new ArrayList<Pair<Double,MnAlgebraicVector>>(n+1); simpl.add(new Pair<Double, MnAlgebraicVector>(seed.fval(), x.clone())); int jl = 0, jh = 0; double amin = seed.fval(), aming = seed.fval(); for(int i = 0; i < n; i++) { double dmin = 8.*prec.eps2()*(Math.abs(x.get(i)) + prec.eps2()); if(step.get(i) < dmin) step.set(i,dmin); x.set(i, x.get(i) + step.get(i)); double tmp = mfcn.valueOf(x); if(tmp < amin) { amin = tmp; jl = i+1; } if(tmp > aming) { aming = tmp; jh = i+1; } simpl.add(new Pair<Double, MnAlgebraicVector>(tmp, x.clone())); x.set(i, x.get(i) - step.get(i)); } SimplexParameters simplex = new SimplexParameters(simpl, jh, jl); do { amin = simplex.get(jl).first; jl = simplex.jl(); jh = simplex.jh(); MnAlgebraicVector pbar = new MnAlgebraicVector(n); for(int i = 0; i < n+1; i++) { if(i == jh) continue; pbar = MnUtils.add(pbar,MnUtils.mul(simplex.get(i).second,wg)); } MnAlgebraicVector pstar = MnUtils.sub(MnUtils.mul(pbar,1. + alpha),MnUtils.mul(simplex.get(jh).second,alpha)); double ystar = mfcn.valueOf(pstar); if(ystar > amin) { if(ystar < simplex.get(jh).first) { simplex.update(ystar, pstar); if(jh != simplex.jh()) continue; } MnAlgebraicVector pstst = MnUtils.add(MnUtils.mul(simplex.get(jh).second,beta),MnUtils.mul(pbar,1. - beta)); double ystst = mfcn.valueOf(pstst); if(ystst > simplex.get(jh).first) break; simplex.update(ystst, pstst); continue; } MnAlgebraicVector pstst = MnUtils.add(MnUtils.mul(pstar,gamma),MnUtils.mul(pbar,1. - gamma)); double ystst = mfcn.valueOf(pstst); double y1 = (ystar - simplex.get(jh).first)*rho2; double y2 = (ystst - simplex.get(jh).first)*rho1; double rho = 0.5*(rho2*y1 - rho1*y2)/(y1 - y2); if(rho < rhomin) { if(ystst < simplex.get(jl).first) simplex.update(ystst, pstst); else simplex.update(ystar, pstar); continue; } if(rho > rhomax) rho = rhomax; MnAlgebraicVector prho = MnUtils.add(MnUtils.mul(pbar,rho),MnUtils.mul(simplex.get(jh).second,1. - rho)); double yrho = mfcn.valueOf(prho); if(yrho < simplex.get(jl).first && yrho < ystst) { simplex.update(yrho, prho); continue; } if(ystst < simplex.get(jl).first) { simplex.update(ystst, pstst); continue; } if(yrho > simplex.get(jl).first) { if(ystst < simplex.get(jl).first) simplex.update(ystst, pstst); else simplex.update(ystar, pstar); continue; } if(ystar > simplex.get(jh).first) { pstst = MnUtils.add(MnUtils.mul(simplex.get(jh).second,beta),MnUtils.mul(pbar,1-beta)); ystst = mfcn.valueOf(pstst); if(ystst > simplex.get(jh).first) break; simplex.update(ystst, pstst); } } while(simplex.edm() > minedm && mfcn.numOfCalls() < maxfcn); amin = simplex.get(jl).first; jl = simplex.jl(); jh = simplex.jh(); MnAlgebraicVector pbar = new MnAlgebraicVector(n); for(int i = 0; i < n+1; i++) { if(i == jh) continue; pbar = MnUtils.add(pbar,MnUtils.mul(simplex.get(i).second,wg)); } double ybar = mfcn.valueOf(pbar); if(ybar < amin) simplex.update(ybar, pbar); else { pbar = simplex.get(jl).second; ybar = simplex.get(jl).first; } MnAlgebraicVector dirin = simplex.dirin(); // scale to sigmas on parameters werr^2 = dirin^2 * (up/edm) dirin = MnUtils.mul(dirin,Math.sqrt(mfcn.errorDef()/simplex.edm())); MinimumState st = new MinimumState(new MinimumParameters(pbar, dirin, ybar), simplex.edm(), mfcn.numOfCalls()); List<MinimumState> states = new ArrayList<MinimumState>(1); states.add(st); if(mfcn.numOfCalls() > maxfcn) { System.err.println("Simplex did not converge, #fcn calls exhausted."); return new FunctionMinimum(seed, states, mfcn.errorDef(), new FunctionMinimum.MnReachedCallLimit()); } if(simplex.edm() > minedm) { System.err.println("Simplex did not converge, edm > minedm."); return new FunctionMinimum(seed, states, mfcn.errorDef(), new FunctionMinimum.MnAboveMaxEdm()); } return new FunctionMinimum(seed, states, mfcn.errorDef()); } }