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