Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
SimplexBuilder.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
12#include "Minuit2/MnFcn.h"
13#include "Minuit2/MinimumSeed.h"
16#include "Minuit2/MnPrint.h"
17
18namespace ROOT {
19
20namespace Minuit2 {
21
22class GradientCalculator;
23class MnStrategy;
25 const MnStrategy &, unsigned int maxfcn, double minedm) const
26{
27 // find the minimum using the Simplex method of Nelder and Mead (does not use function gradient)
28 // method to find initial simplex is slightly different than in the original Fortran
29 // Minuit since has not been proofed that one to be better
30
31 // synchronize print levels
32 MnPrint print("SimplexBuilder", PrintLevel());
33
34 print.Debug("Running with maxfcn", maxfcn, "minedm", minedm);
35
36 const MnMachinePrecision &prec = seed.Precision();
38 MnAlgebraicVector step = 10. * seed.Gradient().Gstep();
39
40 const unsigned int n = x.size();
41
42 // If there are no parameters, we just return a minimum state
43 if (n == 0) {
45 mfcn.NumOfCalls());
46 return FunctionMinimum(seed, {st}, mfcn.Up());
47 }
48
49 const double wg = 1. / double(n);
50 const double alpha = 1.;
51 const double beta = 0.5;
52 const double gamma = 2.;
53 const double rhomin = 4.;
54 const double rhomax = 8.;
55 const double rho1 = 1. + alpha;
56 // double rho2 = rho1 + alpha*gamma;
57 // change proposed by david sachs (fnal)
58 const double rho2 = 1. + alpha * gamma;
59
60 std::vector<std::pair<double, MnAlgebraicVector>> simpl;
61 simpl.reserve(n + 1);
62 simpl.emplace_back(seed.Fval(), x);
63
64 unsigned int jl = 0;
65 unsigned int jh = 0;
66 double amin = seed.Fval();
67 double aming = seed.Fval();
68
69 for (unsigned int i = 0; i < n; i++) {
70 double dmin = 8. * prec.Eps2() * (std::abs(x(i)) + prec.Eps2());
71 if (step(i) < dmin)
72 step(i) = dmin;
73 x(i) += step(i);
74 double tmp = mfcn(x);
75 if (tmp < amin) {
76 amin = tmp;
77 jl = i + 1;
78 }
79 if (tmp > aming) {
80 aming = tmp;
81 jh = i + 1;
82 }
83 simpl.emplace_back(tmp, x);
84 x(i) -= step(i);
85 }
86 SimplexParameters simplex(simpl, jh, jl);
87
88 print.Debug([&](std::ostream &os) {
89 os << "Initial parameters - min " << jl << " " << amin << " max " << jh << " " << aming << '\n';
90 for (unsigned int i = 0; i < simplex.Simplex().size(); ++i)
91 os << " i = " << i << " x = " << simplex(i).second << " fval(x) = " << simplex(i).first << '\n';
92 });
93
94 double edmPrev = simplex.Edm();
95 int niterations = 0;
96
97 do {
98 jl = simplex.Jl();
99 jh = simplex.Jh();
100 amin = simplex(jl).first;
101 edmPrev = simplex.Edm();
102
103 print.Debug("iteration: edm =", simplex.Edm(), '\n', "--> Min Param is", jl, "pmin", simplex(jl).second,
104 "f(pmin)", amin, '\n', "--> Max param is", jh, simplex(jh).first);
105
106 // std::cout << "ALL SIMPLEX PARAMETERS: "<< std::endl;
107 // for (unsigned int i = 0; i < simplex.Simplex().size(); ++i)
108 // std::cout << " i = " << i << " x = " << simplex(i).second << " fval(x) = " << simplex(i).first <<
109 // std::endl;
110
111 // trace the iterations (need to create a MinimumState although errors and gradient are not existing)
112 if (TraceIter())
113 TraceIteration(niterations, MinimumState(MinimumParameters(simplex(jl).second, simplex(jl).first),
114 simplex.Edm(), mfcn.NumOfCalls()));
115 print.Info(MnPrint::Oneline(simplex(jl).first, simplex.Edm(), mfcn.NumOfCalls(), niterations));
116 niterations++;
117
118 MnAlgebraicVector pbar(n);
119 for (unsigned int i = 0; i < n + 1; i++) {
120 if (i == jh)
121 continue;
122 pbar += (wg * simplex(i).second);
123 }
124
125 MnAlgebraicVector pstar = (1. + alpha) * pbar - alpha * simplex(jh).second;
126 const double ystar = mfcn(pstar);
127
128 print.Debug("pbar", pbar, "pstar", pstar, "f(pstar)", ystar);
129
130 if (ystar > amin) {
131 if (ystar < simplex(jh).first) {
132 simplex.Update(ystar, pstar);
133 if (jh != simplex.Jh())
134 continue;
135 }
136 MnAlgebraicVector pstst = beta * simplex(jh).second + (1. - beta) * pbar;
137 double ystst = mfcn(pstst);
138
139 print.Debug("Reduced simplex pstst", pstst, "f(pstst)", ystst);
140
141 if (ystst > simplex(jh).first)
142 break;
143 simplex.Update(ystst, pstst);
144 continue;
145 }
146
147 MnAlgebraicVector pstst = gamma * pstar + (1. - gamma) * pbar;
148 double ystst = mfcn(pstst);
149
150 print.Debug("pstst", pstst, "f(pstst)", ystst);
151
152 const double y1 = (ystar - simplex(jh).first) * rho2;
153 const double y2 = (ystst - simplex(jh).first) * rho1;
154 double rho = 0.5 * (rho2 * y1 - rho1 * y2) / (y1 - y2);
155 if (rho < rhomin) {
156 if (ystst < simplex(jl).first)
157 simplex.Update(ystst, pstst);
158 else
159 simplex.Update(ystar, pstar);
160 continue;
161 }
162 if (rho > rhomax)
163 rho = rhomax;
164 MnAlgebraicVector prho = rho * pbar + (1. - rho) * simplex(jh).second;
165 double yrho = mfcn(prho);
166
167 print.Debug("prho", prho, "f(prho)", yrho);
168
169 if (yrho < simplex(jl).first && yrho < ystst) {
170 simplex.Update(yrho, prho);
171 continue;
172 }
173 if (ystst < simplex(jl).first) {
174 simplex.Update(ystst, pstst);
175 continue;
176 }
177 if (yrho > simplex(jl).first) {
178 if (ystst < simplex(jl).first)
179 simplex.Update(ystst, pstst);
180 else
181 simplex.Update(ystar, pstar);
182 continue;
183 }
184 if (ystar > simplex(jh).first) {
185 pstst = beta * simplex(jh).second + (1. - beta) * pbar;
186 ystst = mfcn(pstst);
187 if (ystst > simplex(jh).first)
188 break;
189 simplex.Update(ystst, pstst);
190 }
191
192 print.Debug("End loop : Edm", simplex.Edm(), "pstst", pstst, "f(pstst)", ystst);
193
194 } while ((simplex.Edm() > minedm || edmPrev > minedm) && mfcn.NumOfCalls() < maxfcn);
195
196 jl = simplex.Jl();
197 jh = simplex.Jh();
198 amin = simplex(jl).first;
199
200 MnAlgebraicVector pbar(n);
201 for (unsigned int i = 0; i < n + 1; i++) {
202 if (i == jh)
203 continue;
204 pbar += (wg * simplex(i).second);
205 }
206 double ybar = mfcn(pbar);
207 if (ybar < amin)
208 simplex.Update(ybar, pbar);
209 else {
210 pbar = simplex(jl).second;
211 ybar = simplex(jl).first;
212 }
213
214 MnAlgebraicVector dirin = simplex.Dirin();
215 // Scale to sigmas on parameters werr^2 = dirin^2 * (up/edm)
216 dirin *= std::sqrt(mfcn.Up() / simplex.Edm());
217
218 print.Debug("End simplex edm =", simplex.Edm(), "pbar =", pbar, "f(p) =", ybar);
219
220 MinimumState st(MinimumParameters(pbar, dirin, ybar), simplex.Edm(), mfcn.NumOfCalls());
221
222 print.Info("Final iteration", MnPrint::Oneline(st));
223
224 if (TraceIter())
225 TraceIteration(niterations, st);
226
227 if (mfcn.NumOfCalls() > maxfcn) {
228 print.Warn("Simplex did not converge, #fcn calls exhausted");
229
230 return FunctionMinimum(seed, {st}, mfcn.Up(), FunctionMinimum::MnReachedCallLimit);
231 }
232 if (simplex.Edm() > minedm) {
233 print.Warn("Simplex did not converge, edm > minedm");
234
235 return FunctionMinimum(seed, {st}, mfcn.Up(), FunctionMinimum::MnAboveMaxEdm);
236 }
237
238 return FunctionMinimum(seed, {st}, mfcn.Up());
239}
240
241} // namespace Minuit2
242
243} // namespace ROOT
size_t size(const MatrixT &matrix)
retrieve the size of a square matrix
Option_t Option_t TPoint TPoint const char y2
Option_t Option_t TPoint TPoint const char y1
const MnAlgebraicVector & Gstep() const
class holding the full result of the minimization; both internal and external (MnUserParameterState) ...
interface class for gradient calculators
unsigned int size() const
Definition LAVector.h:231
void TraceIteration(int iter, const MinimumState &state) const
const MnAlgebraicVector & Vec() const
const FunctionGradient & Gradient() const
Definition MinimumSeed.h:31
const MinimumParameters & Parameters() const
Definition MinimumSeed.h:29
const MnMachinePrecision & Precision() const
Definition MinimumSeed.h:33
MinimumState keeps the information (position, Gradient, 2nd deriv, etc) after one minimization step (...
Wrapper class to FCNBase interface used internally by Minuit.
Definition MnFcn.h:30
double Up() const
Definition MnFcn.cxx:39
unsigned int NumOfCalls() const
Definition MnFcn.h:39
Sets the relative floating point (double) arithmetic precision.
double Eps2() const
eps2 returns 2*sqrt(eps)
void Debug(const Ts &... args)
Definition MnPrint.h:147
void Info(const Ts &... args)
Definition MnPrint.h:141
void Warn(const Ts &... args)
Definition MnPrint.h:135
API class for defining four levels of strategies: low (0), medium (1), high (2), very high (>=3); act...
Definition MnStrategy.h:27
FunctionMinimum Minimum(const MnFcn &, const GradientCalculator &, const MinimumSeed &, const MnStrategy &, unsigned int, double) const override
class describing the simplex set of points (f(x), x ) which evolve during the minimization iteration ...
MnAlgebraicVector Dirin() const
void Update(double, const MnAlgebraicVector &)
const std::vector< std::pair< double, MnAlgebraicVector > > & Simplex() const
Double_t x[n]
Definition legend1.C:17
const Int_t n
Definition legend1.C:16
This file contains a specialised ROOT message handler to test for diagnostic in unit tests.
Definition first.py:1