40 double inner_product(
const LAVector&,
const LAVector&);
42 void VariableMetricBuilder::AddResult( std::vector<MinimumState>& result,
const MinimumState & state)
const {
46 result.push_back(state);
50 if (TraceIter() ) TraceIteration(result.size()-1, result.back() );
52 if (PrintLevel() > 1) {
53 MnPrint::PrintState(std::cout, result.back(),
"VariableMetric: Iteration # ",result.size()-1);
59 FunctionMinimum VariableMetricBuilder::Minimum(
const MnFcn& fcn,
const GradientCalculator& gc,
const MinimumSeed& seed,
const MnStrategy& strategy,
unsigned int maxfcn,
double edmval)
const {
69 int printLevel = PrintLevel();
73 std::cout<<
"VariableMetricBuilder convergence when edm < "<<edmval<<std::endl;
76 if(seed.Parameters().Vec().size() == 0) {
77 return FunctionMinimum(seed, fcn.Up());
82 double edm = seed.State().Edm();
84 FunctionMinimum min(seed, fcn.Up() );
88 MN_INFO_MSG(
"VariableMetricBuilder: initial matrix not pos.def.");
94 std::vector<MinimumState> result;
95 if (StorageLevel() > 0)
103 std::cout <<
"VariableMetric: start iterating until Edm is < " << edmval << std::endl;
104 MnPrint::PrintState(std::cout, seed.State(),
"VariableMetric: Initial state ");
107 AddResult( result, seed.State());
111 int maxfcn_eff = maxfcn;
113 bool iterate =
false;
120 std::cout <<
"start iterating... " << std::endl;
121 if (ipass > 0) std::cout <<
"continue iterating... " << std::endl;
124 min = Minimum(fcn, gc, seed, result, maxfcn_eff, edmval);
127 if ( min.HasReachedCallLimit() ) {
129 MN_INFO_MSG(
"VariableMetricBuilder: FunctionMinimum is invalid, reached the function call limit");
138 MN_INFO_MSG(
"VariableMetricBuilder: FunctionMinimum is invalid after second try");
145 edm = result.back().Edm();
148 if( (strategy.Strategy() == 2) ||
149 (strategy.Strategy() == 1 && min.Error().Dcovar() > 0.05) ) {
152 std::cout<<
"MnMigrad will verify convergence and Error matrix. "<< std::endl;
153 std::cout<<
"dcov is = "<< min.Error().Dcovar() << std::endl;
156 MinimumState st = MnHesse(strategy)(fcn, min.State(), min.Seed().Trafo(),maxfcn);
158 if (printLevel > 1) {
159 MnPrint::PrintState(std::cout, st,
"VariableMetric: After Hessian ");
161 AddResult( result, st);
166 std::cout <<
"edm after Hesse calculation " << edm <<
" requested " << edmval << std::endl;
170 double machineLimit = fabs(seed.Precision().Eps2()*result.back().Fval());
171 if (edm >= machineLimit) {
174 MN_INFO_MSG(
"VariableMetricBuilder: Tolerance is not sufficient, continue the minimization");
175 MN_INFO_VAL2(
"Current Edm is",edm);
176 MN_INFO_VAL2(
"Required Edm is",edmval);
181 MN_INFO_MSG(
"VariableMetricBuilder: Stop the minimization - reached machine accuracy limit");
182 MN_INFO_VAL2(
"Edm is smaller than machine accuracy",machineLimit);
183 MN_INFO_VAL2(
"Current Edm is",edm);
184 MN_INFO_VAL2(
"Required Edm is",edmval);
198 if (ipass == 0) maxfcn_eff = int(maxfcn*1.3);
205 if (edm > 10*edmval) {
206 min.Add( result.back(), FunctionMinimum::MnAboveMaxEdm() );
208 MN_INFO_VAL2(
"VariableMetricBuilder: INVALID function minimum - edm is above tolerance,",edm);
209 MN_INFO_VAL2(
"VariableMetricBuilder: Required tolerance is 10 x edmval ",edmval);
215 if ( min.IsAboveMaxEdm() ) {
216 MN_INFO_MSG(
"VariableMetricBuilder: Edm has been re-computed after Hesse");
217 MN_INFO_VAL2(
"new value is now smaller than the required tolerance,",edm);
220 min.Add( result.back() );
224 std::cout <<
"Obtained function minimum " << min << std::endl;
230 FunctionMinimum VariableMetricBuilder::Minimum(
const MnFcn& fcn,
const GradientCalculator& gc,
const MinimumSeed& seed, std::vector<MinimumState>& result,
unsigned int maxfcn,
double edmval)
const {
240 const MnMachinePrecision& prec = seed.Precision();
244 const MinimumState & initialState = result.back();
246 double edm = initialState.Edm();
250 std::cout <<
"\n\nDEBUG Variable Metric Builder \nInitial State: "
251 <<
" Parameter " << initialState.Vec()
252 <<
" Gradient " << initialState.Gradient().Vec()
253 <<
" Inv Hessian " << initialState.Error().InvHessian()
254 <<
" edm = " << initialState.Edm() << std::endl;
260 edm *= (1. + 3.*initialState.Error().Dcovar());
261 MnLineSearch lsearch;
262 MnAlgebraicVector step(initialState.Gradient().Vec().size());
264 MnAlgebraicVector prevStep(initialState.Gradient().Vec().size());
266 MinimumState s0 = result.back();
267 assert(s0.IsValid() );
273 step = -1.*s0.Error().InvHessian()*s0.Gradient().Vec();
276 std::cout <<
"\n\n---> Iteration - " << result.size()
277 <<
"\nFval = " << s0.Fval() <<
" numOfCall = " << fcn.NumOfCalls()
278 <<
"\nInternal Parameter values " << s0.Vec()
279 <<
" Newton step " << step << std::endl;
283 if ( inner_product(s0.Gradient().Vec(),s0.Gradient().Vec() ) <= 0 ) {
285 std::cout <<
"VariableMetricBuilder: all derivatives are zero - return current status" << std::endl;
291 double gdel = inner_product(step, s0.Gradient().Grad());
294 std::cout <<
" gdel = " << gdel << std::endl;
300 MN_INFO_MSG(
"VariableMetricBuilder: matrix not pos.def, gdel > 0");
305 step = -1.*s0.Error().InvHessian()*s0.Gradient().Vec();
309 gdel = inner_product(step, s0.Gradient().Grad());
314 AddResult(result, s0);
316 return FunctionMinimum(seed, result, fcn.Up());
320 MnParabolaPoint pp = lsearch(fcn, s0.Parameters(), step, gdel, prec);
323 if(fabs(pp.Y() - s0.Fval()) <= fabs(s0.Fval())*prec.Eps() ) {
325 MN_INFO_MSG(
"VariableMetricBuilder: no improvement in line search");
329 if (result.size() <= 1 )
330 AddResult(result, MinimumState(s0.Parameters(), s0.Error(), s0.Gradient(), s0.Edm(), fcn.NumOfCalls()));
333 AddResult(result, MinimumState(pp.Y(), s0.Edm(), fcn.NumOfCalls()));
341 std::cout <<
"Result after line search : \nx = " << pp.X()
342 <<
"\nOld Fval = " << s0.Fval()
343 <<
"\nNew Fval = " << pp.Y()
344 <<
"\nNFcalls = " << fcn.NumOfCalls() << std::endl;
347 MinimumParameters p(s0.Vec() + pp.X()*step, pp.Y());
350 FunctionGradient g = gc(p, s0.Gradient());
353 edm = Estimator().Estimate(g, s0.Error());
358 MN_INFO_MSG(
"VariableMetricBuilder: matrix not pos.def. : edm is < 0. Make pos def...");
362 edm = Estimator().Estimate(g, s0.Error());
365 MN_INFO_MSG(
"VariableMetricBuilder: matrix still not pos.def. : exit iterations ");
367 AddResult(result, s0);
369 return FunctionMinimum(seed, result, fcn.Up());
372 MinimumError e = ErrorUpdator().Update(s0, p, g);
375 std::cout <<
"Updated new point: \n "
376 <<
" Parameter " << p.Vec()
377 <<
" Gradient " << g.Vec()
378 <<
" InvHessian " << e.Matrix()
379 <<
" Hessian " << e.Hessian()
380 <<
" edm = " << edm << std::endl << std::endl;
384 s0 = MinimumState(p, e, g, edm, fcn.NumOfCalls());
385 if (StorageLevel() || result.size() <= 1)
386 AddResult(result, s0);
389 AddResult(result, MinimumState(p.Fval(), edm, fcn.NumOfCalls()));
392 edm *= (1. + 3.*e.Dcovar());
395 std::cout <<
"Dcovar = " << e.Dcovar() <<
"\tCorrected edm = " << edm << std::endl;
400 }
while(edm > edmval && fcn.NumOfCalls() < maxfcn);
403 if ( ! result.back().IsValid() )
407 if(fcn.NumOfCalls() >= maxfcn) {
409 MN_INFO_MSG(
"VariableMetricBuilder: call limit exceeded.");
411 return FunctionMinimum(seed, result, fcn.Up(), FunctionMinimum::MnReachedCallLimit());
415 if(edm < fabs(prec.Eps2()*result.back().Fval())) {
417 MN_INFO_MSG(
"VariableMetricBuilder: machine accuracy limits further improvement.");
419 return FunctionMinimum(seed, result, fcn.Up());
420 }
else if(edm < 10*edmval) {
421 return FunctionMinimum(seed, result, fcn.Up());
424 MN_INFO_MSG(
"VariableMetricBuilder: iterations finish without convergence.");
425 MN_INFO_VAL2(
"VariableMetricBuilder",edm);
426 MN_INFO_VAL2(
" requested",edmval);
428 return FunctionMinimum(seed, result, fcn.Up(), FunctionMinimum::MnAboveMaxEdm());
434 std::cout <<
"Exiting successfully Variable Metric Builder \n"
435 <<
"NFCalls = " << fcn.NumOfCalls()
436 <<
"\nFval = " << result.back().Fval()
437 <<
"\nedm = " << edm <<
" requested = " << edmval << std::endl;
440 return FunctionMinimum(seed, result, fcn.Up());