27#include "Math/Minimizer1D.h"
59 print.
Debug(
"doing line search along given step and gdel = s^t*g = ", gdel);
61 double overall = 1000.;
62 double undral = -100.;
73 for (
unsigned int i = 0; i < step.
size(); i++) {
76 double ratio = std::fabs(st.
Vec()(i) / step(i));
82 if (std::fabs(slamin) < prec.
Eps())
84 slamin *= prec.
Eps2();
86 double f0 = st.
Fval();
87 double f1 = fcnCaller(st.
Vec() + step);
89 double fvmin = st.
Fval();
96 double toler8 = toler;
97 double slamax = slambg;
111 print.
Trace(
"flast", flast,
"f0", f0,
"flast-f0", flast - f0,
"slam", slam);
119 double denom = 2. * (flast - f0 - gdel * slam) / (slam * slam);
121 print.
Trace(
"denom", denom);
123 slam = -gdel / denom;
128 print.
Trace(
"new slam", slam);
130#ifdef TRY_OPPOSIT_DIR
132 bool slamIsNeg =
false;
137 print.
Trace(
"slam is negative - set to", slamax);
138#ifdef TRY_OPPOSITE_DIR
139 slamNeg = 2 * slam - 1;
141 print.
Trace(
"slam is negative - compare values between", slamNeg,
"and", slamax);
147 print.
Trace(
"slam larger than max value - set to", slamax);
151 print.
Trace(
"slam too small - set to", toler8);
155 print.
Trace(
"slam smaller than", slamin,
"return");
159 return {xvmin, fvmin};
161 if (std::fabs(slam - 1.) < toler8 && p1.
Y() < p0.
Y()) {
165 return {xvmin, fvmin};
167 if (std::fabs(slam - 1.) < toler8)
175 f2 = fcnCaller(st.
Vec() + slam * step);
179#ifdef TRY_OPPOSITE_DIR
182 double f2alt = fcn(st.
Vec() + slamNeg * step);
195 if (std::fabs(p0.
Y() - fvmin) < std::fabs(fvmin) * prec.
Eps()) {
199 toler8 = toler * slam;
200 overall = slam - toler8;
205 }
while (
iterate && niter < maxiter);
206 if (niter >= maxiter) {
208 return {xvmin, fvmin};
211 print.
Trace(
"after initial 2-point iter:",
'\n',
" x0, x1, x2:", p0.
X(), p1.
X(), slam,
'\n',
" f0, f1, f2:", p0.
Y(),
218 slamax = std::max(slamax, alpha * std::fabs(xvmin));
220 print.
Trace(
"Iteration", niter,
'\n',
" x0, x1, x2:", p0.
X(), p1.X(), p2.
X(),
'\n',
" f0, f1, f2:", p0.
Y(),
221 p1.Y(), p2.
Y(),
'\n',
" slamax :", slamax,
'\n',
" p2-p0,p1 :", p2.
Y() - p0.
Y(), p2.
Y() - p1.Y(),
222 '\n',
" a, b, c :", pb.
A(), pb.
B(), pb.
C());
223 if (pb.
A() < prec.
Eps2()) {
224 double slopem = 2. * pb.
A() * xvmin + pb.
B();
226 slam = xvmin + slamax;
228 slam = xvmin - slamax;
229 print.
Trace(
"xvmin", xvmin,
"slopem", slopem,
"slam", slam);
233 if (slam > xvmin + slamax)
234 slam = xvmin + slamax;
235 if (slam < xvmin - slamax)
236 slam = xvmin - slamax;
246 print.
Debug(
"slam", slam,
"undral", undral,
"overall", overall);
251 print.
Trace(
"iterate on f3- slam", niter,
"slam", slam,
"xvmin", xvmin);
254 double toler9 = std::max(toler8, std::fabs(toler8 * slam));
256 if (std::fabs(p0.
X() - slam) < toler9 || std::fabs(p1.X() - slam) < toler9 ||
257 std::fabs(p2.
X() - slam) < toler9) {
261 return {xvmin, fvmin};
267 f3 = fcnCaller(st.
Vec() + slam * step);
268 print.
Trace(
"f3", f3,
"f3-p(2-0).Y()", f3 - p2.
Y(), f3 - p1.Y(), f3 - p0.
Y());
270 if (f3 > p0.
Y() && f3 > p1.Y() && f3 > p2.
Y()) {
271 print.
Trace(
"f3 worse than all three previous");
273 overall = std::min(overall, slam - toler8);
275 undral = std::max(undral, slam + toler8);
276 slam = 0.5 * (slam + xvmin);
277 print.
Trace(
"new slam", slam);
281 }
while (
iterate && niter < maxiter);
282 if (niter >= maxiter) {
284 print.
Debug(
"Exhausted max number of iterations ",maxiter,
" return");
285 return {xvmin, fvmin};
290 if (p0.
Y() > p1.Y() && p0.
Y() > p2.
Y())
292 else if (p1.Y() > p0.
Y() && p1.Y() > p2.
Y())
296 print.
Trace(
"f3", f3,
"fvmin", fvmin,
"xvmin", xvmin);
302 overall = std::min(overall, slam - toler8);
304 undral = std::max(undral, slam + toler8);
308 }
while (niter < maxiter);
310 print.
Debug(
"f1, f2 =", p0.
Y(), p1.
Y(),
'\n',
"x1, x2 =", p0.
X(), p1.
X(),
'\n',
"x, f =", xvmin, fvmin);
311 return {xvmin, fvmin};
323 MnPrint print(
"MnLineSearch::CubicSearch");
325 print.Trace(
"gdel", gdel,
"g2del", g2del,
"step", step);
328 double overall = 100.;
329 double undral = -100.;
335 for (
unsigned int i = 0; i < step.
size(); i++) {
338 double ratio = std::fabs(st.
Vec()(i) / step(i));
344 if (std::fabs(slamin) < prec.
Eps())
346 slamin *= prec.
Eps2();
348 double f0 = st.
Fval();
349 double f1 = fcn(st.
Vec() + step);
350 double fvmin = st.
Fval();
352 print.Debug(
"f0", f0,
"f1",
f1);
358 double toler8 = toler;
359 double slamax = slambg;
375 cubicMatrix(0, 0) = (x0 * x0 * x0 - x1 * x1 * x1) / 3.;
376 cubicMatrix(0, 1) = (x0 * x0 - x1 * x1) / 2.;
377 cubicMatrix(0, 2) = (x0 - x1);
378 cubicMatrix(1, 0) = x0 * x0;
379 cubicMatrix(1, 1) = x0;
380 cubicMatrix(1, 2) = 1;
381 cubicMatrix(2, 0) = 2. * x0;
382 cubicMatrix(2, 1) = 1;
383 cubicMatrix(2, 2) = 0;
390 print.Debug(
"Vec:\n ", bVec);
393 if (!cubicMatrix.
Invert()) {
394 print.Warn(
"Inversion failed - return");
395 return {xvmin, fvmin};
398 cubicCoeff = cubicMatrix * bVec;
399 print.Debug(
"Cubic:\n ", cubicCoeff);
401 double ddd = cubicCoeff(1) * cubicCoeff(1) - 4 * cubicCoeff(0) * cubicCoeff(2);
402 double slam1, slam2 = 0;
404 if (cubicCoeff(0) > 0) {
405 slam1 = (-cubicCoeff(1) - std::sqrt(ddd)) / (2. * cubicCoeff(0));
406 slam2 = (-cubicCoeff(1) + std::sqrt(ddd)) / (2. * cubicCoeff(0));
407 }
else if (cubicCoeff(0) < 0) {
408 slam1 = (-cubicCoeff(1) + std::sqrt(ddd)) / (2. * cubicCoeff(0));
409 slam2 = (-cubicCoeff(1) - std::sqrt(ddd)) / (2. * cubicCoeff(0));
411 slam1 = -gdel / g2del;
415 print.Debug(
"slam1", slam1,
"slam2", slam2);
425 if (std::fabs(slam2) < toler)
426 slam2 = (slam2 >= 0) ? slamax : -slamax;
428 double f2 = fcn(st.
Vec() + slam2 * step);
430 print.Debug(
"try with slam 2", slam2,
"f2", f2);
448 if (std::fabs(slam1) < toler)
449 slam1 = (slam1 >= 0) ? -slamax : slamax;
451 double f3 = fcn(st.
Vec() + slam1 * step);
453 print.Debug(
"try with slam 1", slam1,
"f3", f3);
472 bool iterate2 =
false;
480 print.Debug(
"iter", niter,
"test approx deriv ad second deriv at", slam,
"fp", fp);
483 double h = 0.001 * slam;
484 double fh = fcn(st.
Vec() + (slam +
h) * step);
485 double fl = fcn(st.
Vec() + (slam -
h) * step);
486 double df = (fh - fl) / (2. *
h);
487 double df2 = (fh + fl - 2. * fp) / (
h *
h);
489 print.Debug(
"deriv", df, df2);
492 if (std::fabs(df) < prec.
Eps() && std::fabs(df2) < prec.
Eps()) {
494 slam = (slam >= 0) ? -slamax : slamax;
496 fp = fcn(st.
Vec() + slam * step);
497 }
else if (std::fabs(df2) <= 0) {
514 }
while (niter < maxiter);
516 return {xvmin, fvmin};
523 ProjectedFcn(
const MnFcn &fcn,
const MinimumParameters &pa,
const MnAlgebraicVector &step)
524 : fFcn(fcn), fPar(pa), fStep(step)
531 double DoEval(
double x)
const {
return fFcn(fPar.Vec() +
x * fStep); }
534 const MinimumParameters &fPar;
541 MnPrint print(
"MnLineSearch::BrentSearch");
543 print.Debug(
"gdel", gdel,
"g2del", g2del);
545 print.Debug([&](std::ostream &os) {
546 for (
unsigned int i = 0; i < step.size(); ++i) {
548 os <<
"step(i) " << step(i) <<
'\n';
549 std::cout <<
"par(i) " << st.Vec()(i) <<
'\n';
555 ProjectedFcn func(fcn, st, step);
559 double f0 = st.Fval();
560 double f1 = fcn(st.Vec() + step);
563 double fvmin = st.Fval();
565 print.Debug(
"f0", f0,
"f1",
f1);
576 double undral = -1000;
577 double overall = 1000;
585 ROOT::Math::SMatrix<double, 3> cubicMatrix;
586 ROOT::Math::SVector<double, 3> cubicCoeff;
587 ROOT::Math::SVector<double, 3> bVec;
593 cubicMatrix(0, 0) = (x0 * x0 * x0 - x1 * x1 * x1) / 3.;
594 cubicMatrix(0, 1) = (x0 * x0 - x1 * x1) / 2.;
595 cubicMatrix(0, 2) = (x0 - x1);
596 cubicMatrix(1, 0) = x0 * x0;
597 cubicMatrix(1, 1) = x0;
598 cubicMatrix(1, 2) = 1;
599 cubicMatrix(2, 0) = 2. * x0;
600 cubicMatrix(2, 1) = 1;
601 cubicMatrix(2, 2) = 0;
608 print.Debug(
"Vec:\n ", bVec);
611 if (!cubicMatrix.
Invert()) {
612 print.Warn(
"Inversion failed - return");
613 return {xvmin, fvmin};
616 cubicCoeff = cubicMatrix * bVec;
617 print.Debug(
"Cubic:\n ", cubicCoeff);
619 double ddd = cubicCoeff(1) * cubicCoeff(1) - 4 * cubicCoeff(0) * cubicCoeff(2);
620 double slam1, slam2 = 0;
622 if (cubicCoeff(0) > 0) {
623 slam1 = (-cubicCoeff(1) - std::sqrt(ddd)) / (2. * cubicCoeff(0));
624 slam2 = (-cubicCoeff(1) + std::sqrt(ddd)) / (2. * cubicCoeff(0));
625 }
else if (cubicCoeff(0) < 0) {
626 slam1 = (-cubicCoeff(1) + std::sqrt(ddd)) / (2. * cubicCoeff(0));
627 slam2 = (-cubicCoeff(1) - std::sqrt(ddd)) / (2. * cubicCoeff(0));
629 slam1 = -gdel / g2del;
643 double fs1 = func(slam1);
644 double fs2 = func(slam2);
645 print.Debug(
"slam1", slam1,
"slam2", slam2,
"f(slam1)", fs1,
"f(slam2)", fs2);
663 double a = x0 - astart;
664 double b = x0 + astart;
668 double relTol = 0.05;
675 print.Debug(
"f(0)", func(0.),
"f1", func(1.0),
"f(3)", func(3.0),
"f(5)", func(5.0));
682 double delta = delta0;
684 bool scanmin =
false;
691 print.Debug(
"iter", iter,
"a",
a,
"b",
b,
"x0", x0,
"fa", fa,
"fb", fb,
"f0", f0);
692 if (fa <= f0 || fb <= f0) {
705 if (std::fabs((fa - f2) / (
a - x2)) > toler) {
717 x0 = x0 + dir * delta;
720 if (std::fabs((f0 - fa) / (x0 -
a)) < toler) {
721 delta = 10 * delta0 / (10. * (nreset + 1));
728 print.Info(
"A: Done a reset - scan in opposite direction!");
731 if (x0 < b && x0 >
a)
747 if (std::fabs((fb - f2) / (x2 -
b)) > toler) {
759 x0 = x0 + dir * delta;
762 if (std::fabs((f0 - fb) / (x0 -
b)) < toler) {
763 delta = 10 * delta0 / (10. * (nreset + 1));
770 print.Info(
"B: Done a reset - scan in opposite direction!");
773 if (x0 >
a && x0 <
b)
787 print.Debug(
"new x0", x0,
"f0", f0);
797 }
while (
iterate && iter < maxiter);
799 if (f0 > fa || f0 > fb)
802 return {xvmin, fvmin};
804 print.Info(
"1D minimization using", minType);
806 ROOT::Math::Minimizer1D min(minType);
808 min.SetFunction(func, x0,
a,
b);
809 int ret = min.Minimize(maxiter, absTol, relTol);
811 MnPrint::info(
"result of GSL 1D minimization:",
ret,
"niter", min.Iterations(),
"xmin", min.XMinimum(),
"fmin",
814 return {min.XMinimum(), min.FValMinimum()};
SMatrix: a generic fixed size D1 x D2 Matrix class.
bool Invert()
Invert a square Matrix ( this method changes the current matrix).
SVector: a generic fixed size Vector class.
unsigned int size() const
const MnAlgebraicVector & Vec() const
Wrapper class to FCNBase interface used internally by Minuit.
MnPoint 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.
double Eps() const
eps returns the smallest possible number so that 1.+eps > 1.
double Eps2() const
eps2 returns 2*sqrt(eps)
This class defines a parabola of the form a*x*x + b*x + c.
double B() const
Get the coefficient of the linear term.
double C() const
Get the coefficient of the constant term.
double Min() const
Calculate the x coordinate of the Minimum of the parabola.
double A() const
Get the coefficient of the quadratic term.
double X() const
Get the x (first) coordinate.
double Y() const
Get the y (second) coordinate.
void Debug(const Ts &... args)
void Trace(const Ts &... args)
Type
Enumeration with One Dimensional Minimizer Algorithms.
int iterate(rng_state_t *X)
IBaseFunctionOneDim IGenFunction
LAVector MnAlgebraicVector