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