Logo ROOT  
Reference Guide
 
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules Pages
Loading...
Searching...
No Matches
MnLineSearch.cxx
Go to the documentation of this file.
1// @(#)root/minuit2:$Id$
2// Authors: M. Winkler, F. James, L. Moneta, A. Zsenei 2003-2005
3
4/**********************************************************************
5 * *
6 * Copyright (c) 2005 LCG ROOT Math team, CERN/PH-SFT *
7 * *
8 **********************************************************************/
9
11#include "Minuit2/MnFcn.h"
14#include "Minuit2/MnParabola.h"
17#include "Minuit2/MnPrint.h"
18
19#include <algorithm>
20#include <cmath>
21
22#ifdef USE_OTHER_LS
23
24#include "Math/SMatrix.h"
25#include "Math/SVector.h"
26
27#include "Math/IFunction.h"
28#include "Math/Minimizer1D.h"
29
30#endif
31
32namespace ROOT {
33
34namespace Minuit2 {
35
36/** Perform a line search from position defined by the vector st
37 along the direction step, where the length of vector step
38 gives the expected position of Minimum.
39 fcn is Value of function at the starting position ,
40 gdel (if non-zero) is df/dx along step at st.
41 Return a parabola point containing Minimum x position and y (function Value)
42 - add a flag to control the debug
43*/
44
46 double gdel, const MnMachinePrecision &prec) const
47{
48
49 //*-*-*-*-*-*-*-*-*-*Perform a line search from position st along step *-*-*-*-*-*-*-*
50 //*-* =========================================
51 //*-* SLAMBG and ALPHA control the maximum individual steps allowed.
52 //*-* The first step is always =1. The max length of second step is SLAMBG.
53 //*-* The max size of subsequent steps is the maximum previous successful
54 //*-* step multiplied by ALPHA + the size of most recent successful step,
55 //*-* but cannot be smaller than SLAMBG.
56 //*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
57
58 MnPrint print("MnLineSearch");
59
60 print.Debug("doing line search along given step and gdel = s^t*g = ", gdel);
61
62 double overall = 1000.;
63 double undral = -100.;
64 double toler = 0.05;
65 double slamin = 0.;
66 double slambg = 5.;
67 double alpha = 2.;
68 int maxiter = 12;
69 // start as in Fortran from 1 and count all the time we evaluate the function
70 int niter = 1;
71
72 for (unsigned int i = 0; i < step.size(); i++) {
73 if (step(i) == 0)
74 continue;
75 double ratio = std::fabs(st.Vec()(i) / step(i));
76 if (slamin == 0)
77 slamin = ratio;
78 if (ratio < slamin)
79 slamin = ratio;
80 }
81 if (std::fabs(slamin) < prec.Eps())
82 slamin = prec.Eps();
83 slamin *= prec.Eps2();
84
85 double f0 = st.Fval();
86 double f1 = fcn(st.Vec() + step);
87 niter++;
88 double fvmin = st.Fval();
89 double xvmin = 0.;
90
91 if (f1 < f0) {
92 fvmin = f1;
93 xvmin = 1.;
94 }
95 double toler8 = toler;
96 double slamax = slambg;
97 double flast = f1;
98 double slam = 1.;
99
100 bool iterate = false;
101 MnParabolaPoint p0(0., f0);
103 double f2 = 0.;
104 // quadratic interpolation using the two points p0,p1 and the slope at p0
105 do {
106 // cut toler8 as function goes up
107 iterate = false;
108 // MnParabola pb = MnParabolaFactory()(p0, gdel, p1);
109
110 print.Trace("flast", flast, "f0", f0, "flast-f0", flast - f0, "slam", slam);
111 // double df = flast-f0;
112 // if(std::fabs(df) < prec.Eps2()) {
113 // if(flast-f0 < 0.) df = -prec.Eps2();
114 // else df = prec.Eps2();
115 // }
116 // std::cout<<"df= "<<df<<std::endl;
117 // double denom = 2.*(df-gdel*slam)/(slam*slam);
118 double denom = 2. * (flast - f0 - gdel * slam) / (slam * slam);
119
120 print.Trace("denom", denom);
121 if (denom != 0) {
122 slam = -gdel / denom;
123 } else {
124 denom = -0.1 * gdel;
125 slam = 1.;
126 }
127 print.Trace("new slam", slam);
128
129#ifdef TRY_OPPOSIT_DIR
130 // if is less than zero indicates maximum position. Use then slamax or x = x0 - 2slam + 1
131 bool slamIsNeg = false;
132 double slamNeg = 0;
133#endif
134
135 if (slam < 0.) {
136 print.Trace("slam is negative - set to", slamax);
137#ifdef TRY_OPPOSITE_DIR
138 slamNeg = 2 * slam - 1;
139 slamIsNeg = true;
140 print.Trace("slam is negative - compare values between", slamNeg, "and", slamax);
141#endif
142 slam = slamax;
143 }
144 if (slam > slamax) {
145 slam = slamax;
146 print.Trace("slam larger than max value - set to", slamax);
147 }
148
149 if (slam < toler8) {
150 print.Trace("slam too small - set to", toler8);
151 slam = toler8;
152 }
153 if (slam < slamin) {
154 print.Trace("slam smaller than", slamin, "return");
155 // std::cout<<"f1, f2= "<<p0.Y()<<", "<<p1.Y()<<std::endl;
156 // std::cout<<"x1, x2= "<<p0.X()<<", "<<p1.X()<<std::endl;
157 // std::cout<<"x, f= "<<xvmin<<", "<<fvmin<<std::endl;
158 return MnParabolaPoint(xvmin, fvmin);
159 }
160 if (std::fabs(slam - 1.) < toler8 && p1.Y() < p0.Y()) {
161 // std::cout<<"f1, f2= "<<p0.Y()<<", "<<p1.Y()<<std::endl;
162 // std::cout<<"x1, x2= "<<p0.X()<<", "<<p1.X()<<std::endl;
163 // std::cout<<"x, f= "<<xvmin<<", "<<fvmin<<std::endl;
164 return MnParabolaPoint(xvmin, fvmin);
165 }
166 if (std::fabs(slam - 1.) < toler8)
167 slam = 1. + toler8;
168
169 // if(std::fabs(gdel) < prec.Eps2() && std::fabs(denom) < prec.Eps2())
170 // slam = 1000.;
171 // MnAlgebraicVector tmp = step;
172 // tmp *= slam;
173 // f2 = fcn(st.Vec()+tmp);
174 f2 = fcn(st.Vec() + slam * step);
175
176 niter++; // do as in Minuit (count all func evalu)
177
178#ifdef TRY_OPPOSITE_DIR
179 if (slamIsNeg) {
180 // try alternative in the opposite direction
181 double f2alt = fcn(st.Vec() + slamNeg * step);
182 if (f2alt < f2) {
183 slam = slamNeg;
184 f2 = f2alt;
185 undral += slam;
186 }
187 }
188#endif
189 if (f2 < fvmin) {
190 fvmin = f2;
191 xvmin = slam;
192 }
193 // LM : correct a bug using precision
194 if (std::fabs(p0.Y() - fvmin) < std::fabs(fvmin) * prec.Eps()) {
195 // if(p0.Y()-prec.Eps() < fvmin && fvmin < p0.Y()+prec.Eps()) {
196 iterate = true;
197 flast = f2;
198 toler8 = toler * slam;
199 overall = slam - toler8;
200 slamax = overall;
202 // niter++;
203 }
204 } while (iterate && niter < maxiter);
205 if (niter >= maxiter) {
206 // exhausted max number of iterations
207 return MnParabolaPoint(xvmin, fvmin);
208 }
209
210 print.Trace("after initial 2-point iter:", '\n', " x0, x1, x2:", p0.X(), p1.X(), slam, '\n', " f0, f1, f2:", p0.Y(),
211 p1.Y(), f2);
212
214
215 // do now the quadratic interpolation with 3 points
216 do {
217 slamax = std::max(slamax, alpha * std::fabs(xvmin));
219 print.Trace("Iteration", niter, '\n', " x0, x1, x2:", p0.X(), p1.X(), p2.X(), '\n', " f0, f1, f2:", p0.Y(),
220 p1.Y(), p2.Y(), '\n', " slamax :", slamax, '\n', " p2-p0,p1 :", p2.Y() - p0.Y(), p2.Y() - p1.Y(),
221 '\n', " a, b, c :", pb.A(), pb.B(), pb.C());
222 if (pb.A() < prec.Eps2()) {
223 double slopem = 2. * pb.A() * xvmin + pb.B();
224 if (slopem < 0.)
225 slam = xvmin + slamax;
226 else
227 slam = xvmin - slamax;
228 print.Trace("xvmin", xvmin, "slopem", slopem, "slam", slam);
229 } else {
230 slam = pb.Min();
231 // std::cout<<"pb.Min() slam= "<<slam<<std::endl;
232 if (slam > xvmin + slamax)
233 slam = xvmin + slamax;
234 if (slam < xvmin - slamax)
235 slam = xvmin - slamax;
236 }
237 if (slam > 0.) {
238 if (slam > overall)
239 slam = overall;
240 } else {
241 if (slam < undral)
242 slam = undral;
243 }
244
245 print.Debug("slam", slam, "undral", undral, "overall", overall);
246
247 double f3 = 0.;
248 do {
249
250 print.Trace("iterate on f3- slam", niter, "slam", slam, "xvmin", xvmin);
251
252 iterate = false;
253 double toler9 = std::max(toler8, std::fabs(toler8 * slam));
254 // min. of parabola at one point
255 if (std::fabs(p0.X() - slam) < toler9 || std::fabs(p1.X() - slam) < toler9 ||
256 std::fabs(p2.X() - slam) < toler9) {
257 // std::cout<<"f1, f2, f3= "<<p0.Y()<<", "<<p1.Y()<<", "<<p2.Y()<<std::endl;
258 // std::cout<<"x1, x2, x3= "<<p0.X()<<", "<<p1.X()<<", "<<p2.X()<<std::endl;
259 // std::cout<<"x, f= "<<xvmin<<", "<<fvmin<<std::endl;
260 return MnParabolaPoint(xvmin, fvmin);
261 }
262
263 // take the step
264 // MnAlgebraicVector tmp = step;
265 // tmp *= slam;
266 f3 = fcn(st.Vec() + slam * step);
267 print.Trace("f3", f3, "f3-p(2-0).Y()", f3 - p2.Y(), f3 - p1.Y(), f3 - p0.Y());
268 // if latest point worse than all three previous, cut step
269 if (f3 > p0.Y() && f3 > p1.Y() && f3 > p2.Y()) {
270 print.Trace("f3 worse than all three previous");
271 if (slam > xvmin)
272 overall = std::min(overall, slam - toler8);
273 if (slam < xvmin)
274 undral = std::max(undral, slam + toler8);
275 slam = 0.5 * (slam + xvmin);
276 print.Trace("new slam", slam);
277 iterate = true;
278 niter++;
279 }
280 } while (iterate && niter < maxiter);
281 if (niter >= maxiter) {
282 // exhausted max number of iterations
283 print.Debug("Exhausted max number of iterations ",maxiter," return");
284 return MnParabolaPoint(xvmin, fvmin);
285 }
286
287 // find worst previous point out of three and replace
289 if (p0.Y() > p1.Y() && p0.Y() > p2.Y())
290 p0 = p3;
291 else if (p1.Y() > p0.Y() && p1.Y() > p2.Y())
292 p1 = p3;
293 else
294 p2 = p3;
295 print.Trace("f3", f3, "fvmin", fvmin, "xvmin", xvmin);
296 if (f3 < fvmin) {
297 fvmin = f3;
298 xvmin = slam;
299 } else {
300 if (slam > xvmin)
301 overall = std::min(overall, slam - toler8);
302 if (slam < xvmin)
303 undral = std::max(undral, slam + toler8);
304 }
305
306 niter++;
307 } while (niter < maxiter);
308
309 print.Debug("f1, f2 =", p0.Y(), p1.Y(), '\n', "x1, x2 =", p0.X(), p1.X(), '\n', "x, f =", xvmin, fvmin);
310 return MnParabolaPoint(xvmin, fvmin);
311}
312
313#ifdef USE_OTHER_LS
314
315/** Perform a line search using a cubic interpolation using x0, x1 , df/dx(x0) and d2/dx(x0) (second derivative)
316 This is used at the beginning when the second derivative is known to be negative
317*/
318
319MnParabolaPoint MnLineSearch::CubicSearch(const MnFcn &fcn, const MinimumParameters &st, const MnAlgebraicVector &step,
320 double gdel, double g2del, const MnMachinePrecision &prec) const
321{
322 MnPrint print("MnLineSearch::CubicSearch");
323
324 print.Trace("gdel", gdel, "g2del", g2del, "step", step);
325
326 // change of large values
327 double overall = 100.;
328 double undral = -100.;
329 double toler = 0.05;
330 double slamin = 0.;
331 double slambg = 5.;
332 double alpha = 2.;
333
334 for (unsigned int i = 0; i < step.size(); i++) {
335 if (step(i) == 0)
336 continue;
337 double ratio = std::fabs(st.Vec()(i) / step(i));
338 if (slamin == 0)
339 slamin = ratio;
340 if (ratio < slamin)
341 slamin = ratio;
342 }
343 if (std::fabs(slamin) < prec.Eps())
344 slamin = prec.Eps();
345 slamin *= prec.Eps2();
346
347 double f0 = st.Fval();
348 double f1 = fcn(st.Vec() + step);
349 double fvmin = st.Fval();
350 double xvmin = 0.;
351 print.Debug("f0", f0, "f1", f1);
352
353 if (f1 < f0) {
354 fvmin = f1;
355 xvmin = 1.;
356 }
357 double toler8 = toler;
358 double slamax = slambg;
359 double flast = f1;
360 double slam = 1.;
361
362 // MnParabolaPoint p0(0., f0);
363 // MnParabolaPoint p1(slam, flast);
364
366 ROOT::Math::SVector<double, 3> cubicCoeff; // cubic coefficients to be found
367 ROOT::Math::SVector<double, 3> bVec; // cubic coefficients to be found
368 double x0 = 0;
369
370 // cubic interpolation using the two points p0,p1 and the slope at p0 and the second derivative at p0
371
372 // cut toler8 as function goes up
373 double x1 = slam;
374 cubicMatrix(0, 0) = (x0 * x0 * x0 - x1 * x1 * x1) / 3.;
375 cubicMatrix(0, 1) = (x0 * x0 - x1 * x1) / 2.;
376 cubicMatrix(0, 2) = (x0 - x1);
377 cubicMatrix(1, 0) = x0 * x0;
378 cubicMatrix(1, 1) = x0;
379 cubicMatrix(1, 2) = 1;
380 cubicMatrix(2, 0) = 2. * x0;
381 cubicMatrix(2, 1) = 1;
382 cubicMatrix(2, 2) = 0;
383
384 bVec(0) = f0 - f1;
385 bVec(1) = gdel;
386 bVec(2) = g2del;
387
388 // if (debug) std::cout << "Matrix:\n " << cubicMatrix << std::endl;
389 print.Debug("Vec:\n ", bVec);
390
391 // find the minimum need to invert the matrix
392 if (!cubicMatrix.Invert()) {
393 print.Warn("Inversion failed - return");
394 return MnParabolaPoint(xvmin, fvmin);
395 }
396
398 print.Debug("Cubic:\n ", cubicCoeff);
399
400 double ddd = cubicCoeff(1) * cubicCoeff(1) - 4 * cubicCoeff(0) * cubicCoeff(2); // b**2 - 4ac
401 double slam1, slam2 = 0;
402 // slam1 should be minimum and slam2 the maximum
403 if (cubicCoeff(0) > 0) {
404 slam1 = (-cubicCoeff(1) - std::sqrt(ddd)) / (2. * cubicCoeff(0));
405 slam2 = (-cubicCoeff(1) + std::sqrt(ddd)) / (2. * cubicCoeff(0));
406 } else if (cubicCoeff(0) < 0) {
407 slam1 = (-cubicCoeff(1) + std::sqrt(ddd)) / (2. * cubicCoeff(0));
408 slam2 = (-cubicCoeff(1) - std::sqrt(ddd)) / (2. * cubicCoeff(0));
409 } else { // case == 0 (-b/c)
410 slam1 = -gdel / g2del;
411 slam2 = slam1;
412 }
413
414 print.Debug("slam1", slam1, "slam2", slam2);
415
416 // this should be the minimum otherwise inversion failed and I should do something else
417
418 if (slam2 < undral)
419 slam2 = undral;
420 if (slam2 > overall)
421 slam2 = overall;
422
423 // I am stack somewhere - take a large step
424 if (std::fabs(slam2) < toler)
425 slam2 = (slam2 >= 0) ? slamax : -slamax;
426
427 double f2 = fcn(st.Vec() + slam2 * step);
428
429 print.Debug("try with slam 2", slam2, "f2", f2);
430
431 double fp;
432 // use this as new minimum
433 // bool noImpr = false;
434 if (f2 < fvmin) {
435 slam = slam2;
436 xvmin = slam;
437 fvmin = f2;
438 fp = fvmin;
439 } else {
440 // try with slam2 if it is better
441
442 if (slam1 < undral)
443 slam1 = undral;
444 if (slam1 > overall)
445 slam1 = overall;
446
447 if (std::fabs(slam1) < toler)
448 slam1 = (slam1 >= 0) ? -slamax : slamax;
449
450 double f3 = fcn(st.Vec() + slam1 * step);
451
452 print.Debug("try with slam 1", slam1, "f3", f3);
453
454 if (f3 < fvmin) {
455 slam = slam1;
456 fp = fvmin;
457 xvmin = slam;
458 fvmin = f3;
459 } else {
460 // case both f2 and f3 did not produce a better result
461 if (f2 < f3) {
462 slam = slam1;
463 fp = f2;
464 } else {
465 slam = slam2;
466 fp = f3;
467 }
468 }
469 }
470
471 bool iterate2 = false;
472 int niter = 0;
473
474 int maxiter = 10;
475
476 do {
477 iterate2 = false;
478
479 print.Debug("iter", niter, "test approx deriv ad second deriv at", slam, "fp", fp);
480
481 // estimate grad and second derivative at new point taking a step of 10-3
482 double h = 0.001 * slam;
483 double fh = fcn(st.Vec() + (slam + h) * step);
484 double fl = fcn(st.Vec() + (slam - h) * step);
485 double df = (fh - fl) / (2. * h);
486 double df2 = (fh + fl - 2. * fp) / (h * h);
487
488 print.Debug("deriv", df, df2);
489
490 // if I am in a point of still negative derivative
491 if (std::fabs(df) < prec.Eps() && std::fabs(df2) < prec.Eps()) {
492 // try in opposite direction with an opposite value
493 slam = (slam >= 0) ? -slamax : slamax;
494 slamax *= 10;
495 fp = fcn(st.Vec() + slam * step);
496 } else if (std::fabs(df2) <= 0) { // gradient is significative different than zero then redo a cubic interpolation
497 // from new point
498
499 return MnParabolaPoint(slam, fp); // should redo a cubic interpol. ??
500 // niter ++;
501 // if (niter > maxiter) break;
502
503 // MinimumParameters pa = MinimumParameters(st.Vec() + stepNew, fp);
504 // gdel = stepNew(i)
505 // MnParabolaPoint pp = CubicSearch(fcn, st, stepNew, df, df2
506
507 }
508
509 else
510 return MnParabolaPoint(slam, fp);
511
512 niter++;
513 } while (niter < maxiter);
514
515 return MnParabolaPoint(xvmin, fvmin);
516}
517
518// class describing Fcn function in one dimension
520
521public:
522 ProjectedFcn(const MnFcn &fcn, const MinimumParameters &pa, const MnAlgebraicVector &step)
523 : fFcn(fcn), fPar(pa), fStep(step)
524 {
525 }
526
527 ROOT::Math::IGenFunction *Clone() const { return new ProjectedFcn(*this); }
528
529private:
530 double DoEval(double x) const { return fFcn(fPar.Vec() + x * fStep); }
531
532 const MnFcn &fFcn;
533 const MinimumParameters &fPar;
534 const MnAlgebraicVector &fStep;
535};
536
537MnParabolaPoint MnLineSearch::BrentSearch(const MnFcn &fcn, const MinimumParameters &st, const MnAlgebraicVector &step,
538 double gdel, double g2del, const MnMachinePrecision &prec) const
539{
540 MnPrint print("MnLineSearch::BrentSearch");
541
542 print.Debug("gdel", gdel, "g2del", g2del);
543
544 print.Debug([&](std::ostream &os) {
545 for (unsigned int i = 0; i < step.size(); ++i) {
546 if (step(i) != 0) {
547 os << "step(i) " << step(i) << '\n';
548 std::cout << "par(i) " << st.Vec()(i) << '\n';
549 break;
550 }
551 }
552 });
553
554 ProjectedFcn func(fcn, st, step);
555
556 // do first a cubic interpolation
557
558 double f0 = st.Fval();
559 double f1 = fcn(st.Vec() + step);
560 f0 = func(0.0);
561 f1 = func(1.);
562 double fvmin = st.Fval();
563 double xvmin = 0.;
564 print.Debug("f0", f0, "f1", f1);
565
566 if (f1 < f0) {
567 fvmin = f1;
568 xvmin = 1.;
569 }
570 // double toler8 = toler;
571 // double slamax = slambg;
572 // double flast = f1;
573 double slam = 1.;
574
575 double undral = -1000;
576 double overall = 1000;
577
578 double x0 = 0;
579
580// MnParabolaPoint p0(0., f0);
581// MnParabolaPoint p1(slam, flast);
582#ifdef USE_CUBIC
583
585 ROOT::Math::SVector<double, 3> cubicCoeff; // cubic coefficients to be found
586 ROOT::Math::SVector<double, 3> bVec; // cubic coefficients to be found
587
588 // cubic interpolation using the two points p0,p1 and the slope at p0 and the second derivative at p0
589
590 // cut toler8 as function goes up
591 double x1 = slam;
592 cubicMatrix(0, 0) = (x0 * x0 * x0 - x1 * x1 * x1) / 3.;
593 cubicMatrix(0, 1) = (x0 * x0 - x1 * x1) / 2.;
594 cubicMatrix(0, 2) = (x0 - x1);
595 cubicMatrix(1, 0) = x0 * x0;
596 cubicMatrix(1, 1) = x0;
597 cubicMatrix(1, 2) = 1;
598 cubicMatrix(2, 0) = 2. * x0;
599 cubicMatrix(2, 1) = 1;
600 cubicMatrix(2, 2) = 0;
601
602 bVec(0) = f0 - f1;
603 bVec(1) = gdel;
604 bVec(2) = g2del;
605
606 // if (debug) std::cout << "Matrix:\n " << cubicMatrix << std::endl;
607 print.Debug("Vec:\n ", bVec);
608
609 // find the minimum need to invert the matrix
610 if (!cubicMatrix.Invert()) {
611 print.Warn("Inversion failed - return");
612 return MnParabolaPoint(xvmin, fvmin);
613 }
614
616 print.Debug("Cubic:\n ", cubicCoeff);
617
618 double ddd = cubicCoeff(1) * cubicCoeff(1) - 4 * cubicCoeff(0) * cubicCoeff(2); // b**2 - 4ac
619 double slam1, slam2 = 0;
620 // slam1 should be minimum and slam2 the maximum
621 if (cubicCoeff(0) > 0) {
622 slam1 = (-cubicCoeff(1) - std::sqrt(ddd)) / (2. * cubicCoeff(0));
623 slam2 = (-cubicCoeff(1) + std::sqrt(ddd)) / (2. * cubicCoeff(0));
624 } else if (cubicCoeff(0) < 0) {
625 slam1 = (-cubicCoeff(1) + std::sqrt(ddd)) / (2. * cubicCoeff(0));
626 slam2 = (-cubicCoeff(1) - std::sqrt(ddd)) / (2. * cubicCoeff(0));
627 } else { // case == 0 (-b/c)
628 slam1 = -gdel / g2del;
629 slam2 = slam1;
630 }
631
632 if (slam1 < undral)
633 slam1 = undral;
634 if (slam1 > overall)
635 slam1 = overall;
636
637 if (slam2 < undral)
638 slam2 = undral;
639 if (slam2 > overall)
640 slam2 = overall;
641
642 double fs1 = func(slam1);
643 double fs2 = func(slam2);
644 print.Debug("slam1", slam1, "slam2", slam2, "f(slam1)", fs1, "f(slam2)", fs2);
645
646 if (fs1 < fs2) {
647 x0 = slam1;
648 f0 = fs1;
649 } else {
650 x0 = slam2;
651 f0 = fs2;
652 }
653
654#else
655 x0 = xvmin;
656 f0 = fvmin;
657#endif
658
659 double astart = 100;
660
661 // do a Brent search in a large interval
662 double a = x0 - astart;
663 double b = x0 + astart;
664 // double x0 = 1;
665 int maxiter = 20;
666 double absTol = 0.5;
667 double relTol = 0.05;
668
669 ROOT::Math::Minim1D::Type minType = ROOT::Math::Minim1D::BRENT;
670
671 bool iterate = false;
672 int iter = 0;
673
674 print.Debug("f(0)", func(0.), "f1", func(1.0), "f(3)", func(3.0), "f(5)", func(5.0));
675
676 double fa = func(a);
677 double fb = func(b);
678 // double f0 = func(x0);
679 double toler = 0.01;
680 double delta0 = 5;
681 double delta = delta0;
682 bool enlarge = true;
683 bool scanmin = false;
684 double x2, f2 = 0;
685 double dir = 1;
686 int nreset = 0;
687
688 do {
689
690 print.Debug("iter", iter, "a", a, "b", b, "x0", x0, "fa", fa, "fb", fb, "f0", f0);
691 if (fa <= f0 || fb <= f0) {
692 scanmin = false;
693 if (fa < fb) {
694 if (fa < fvmin) {
695 fvmin = fa;
696 xvmin = a;
697 }
698 // double f2 = fa;
699 // double x2 = a;
700 if (enlarge) {
701 x2 = a - 1000; // move lower
702 f2 = func(x2);
703 }
704 if (std::fabs((fa - f2) / (a - x2)) > toler) { // significant change in f continue to enlarge interval
705 x0 = a;
706 f0 = fa;
707 a = x2;
708 fa = f2;
709 enlarge = true;
710 } else {
711 // move direction of [a
712 // values change a little, start from central point try with x0 = x0 - delta
713 if (nreset == 0)
714 dir = -1;
715 enlarge = false;
716 x0 = x0 + dir * delta;
717 f0 = func(x0);
718 // if reached limit try opposite direction , direction b]
719 if (std::fabs((f0 - fa) / (x0 - a)) < toler) {
720 delta = 10 * delta0 / (10. * (nreset + 1)); // decrease the delta if still not change observed
721 a = x0;
722 fa = f0;
723 x0 = delta;
724 f0 = func(x0);
725 dir *= -1;
726 nreset++;
727 print.Info("A: Done a reset - scan in opposite direction!");
728 }
729 delta *= 2; // double delta at next iteration
730 if (x0 < b && x0 > a)
731 scanmin = true;
732 else {
733 x0 = 0;
734 f0 = st.Fval();
735 }
736 }
737 } else { // fb < fa
738 if (fb < fvmin) {
739 fvmin = fb;
740 xvmin = b;
741 }
742 if (enlarge) {
743 x2 = b + 1000; // move upper
744 f2 = func(x2);
745 }
746 if (std::fabs((fb - f2) / (x2 - b)) > toler) { // significant change in f continue to enlarge interval
747 f0 = fb;
748 x0 = b;
749 b = x2; //
750 fb = f2;
751 enlarge = true;
752 } else {
753 // here move direction b
754 // values change a little, try with x0 = fa + delta
755 if (nreset == 0)
756 dir = 1;
757 enlarge = false;
758 x0 = x0 + dir * delta;
759 f0 = func(x0);
760 // if reached limit try other side
761 if (std::fabs((f0 - fb) / (x0 - b)) < toler) {
762 delta = 10 * delta0 / (10. * (nreset + 1)); // decrease the delta if still not change observed
763 b = x0;
764 fb = f0;
765 x0 = -delta;
766 f0 = func(x0);
767 dir *= -1;
768 nreset++;
769 print.Info("B: Done a reset - scan in opposite direction!");
770 }
771 delta *= 2; // double delta at next iteration
772 if (x0 > a && x0 < b)
773 scanmin = true;
774 else {
775 x0 = 0;
776 f0 = st.Fval();
777 }
778 }
779 }
780
781 if (f0 < fvmin) {
782 x0 = xvmin;
783 fvmin = f0;
784 }
785
786 print.Debug("new x0", x0, "f0", f0);
787
788 // use golden section
790
791 } else { // x0 is a min of [a,b]
792 iterate = false;
793 }
794
795 iter++;
796 } while (iterate && iter < maxiter);
797
798 if (f0 > fa || f0 > fb)
799 // skip minim 1d try Minuit LS
800 // return (*this) (fcn, st, step, gdel, prec, debug);
801 return MnParabolaPoint(xvmin, fvmin);
802
803 print.Info("1D minimization using", minType);
804
805 ROOT::Math::Minimizer1D min(minType);
806
807 min.SetFunction(func, x0, a, b);
808 int ret = min.Minimize(maxiter, absTol, relTol);
809
810 MnPrint::info("result of GSL 1D minimization:", ret, "niter", min.Iterations(), "xmin", min.XMinimum(), "fmin",
811 min.FValMinimum());
812
813 return MnParabolaPoint(min.XMinimum(), min.FValMinimum());
814}
815
816#endif
817
818} // namespace Minuit2
819
820} // namespace ROOT
#define b(i)
Definition RSha256.hxx:100
#define a(i)
Definition RSha256.hxx:99
#define h(i)
Definition RSha256.hxx:106
ROOT::Detail::TRangeCast< T, true > TRangeDynCast
TRangeDynCast is an adapter class that allows the typed iteration through a TCollection.
Option_t Option_t TPoint TPoint const char x2
Option_t Option_t TPoint TPoint const char x1
Interface (abstract class) for generic functions objects of one-dimension Provides a method to evalua...
Definition IFunction.h:114
SMatrix: a generic fixed size D1 x D2 Matrix class.
Definition SMatrix.h:101
SVector: a generic fixed size Vector class.
Definition SVector.h:75
unsigned int size() const
Definition MnMatrix.h:1032
Wrapper class to FCNBase interface used internally by Minuit.
Definition MnFcn.h:30
MnParabolaPoint operator()(const MnFcn &, const MinimumParameters &, const MnAlgebraicVector &, double, const MnMachinePrecision &) const
Perform a line search from position defined by the vector st along the direction step,...
Sets the relative floating point (double) arithmetic precision.
This class defines a parabola of the form a*x*x + b*x + c.
Definition MnParabola.h:30
void Debug(const Ts &... args)
Definition MnPrint.h:135
void Trace(const Ts &... args)
Definition MnPrint.h:141
Type
Enumeration with One Dimensional Minimizer Algorithms.
Double_t x[n]
Definition legend1.C:17
TF1 * f1
Definition legend1.C:11
int iterate(rng_state_t *X)
Definition mixmax.icc:34
LAVector MnAlgebraicVector
Definition MnMatrixfwd.h:22
tbb::task_arena is an alias of tbb::interface7::task_arena, which doesn't allow to forward declare tb...