Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
MnContours.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/MnContours.h"
11#include "Minuit2/MnMinos.h"
12#include "Minuit2/MnMigrad.h"
15#include "Minuit2/FCNBase.h"
16#include "Minuit2/MnCross.h"
17#include "Minuit2/MinosError.h"
19#include "Minuit2/MnPrint.h"
20
21namespace ROOT {
22
23namespace Minuit2 {
24
25std::vector<std::pair<double, double>> MnContours::
26operator()(unsigned int px, unsigned int py, unsigned int npoints) const
27{
28 // get contour as a pair of (x,y) points passing the parameter index (px, py) and the number of requested points
29 // (>=4)
31 return cont();
32}
33
34ContoursError MnContours::Contour(unsigned int px, unsigned int py, unsigned int npoints) const
35{
36 // calculate the contour passing the parameter index (px, py) and the number of requested points (>=4)
37 // the fcn.UP() has to be set to the required value (see Minuit document on errors)
38 assert(npoints > 3);
39 unsigned int maxcalls = 100 * (npoints + 5) * (fMinimum.UserState().VariableParameters() + 1);
40 unsigned int nfcn = 0;
41
42 MnPrint print("MnContours");
43 print.Debug("MnContours: finding ",npoints," contours points for ",px,py," at level ",fFCN.Up()," from value ",fMinimum.Fval());
44
45 std::vector<std::pair<double, double>> result;
46 result.reserve(npoints);
47 std::vector<MnUserParameterState> states;
48 // double edmmax = 0.5*0.05*fFCN.Up()*1.e-3;
49
50 // double toler = 0.05;
51 double toler = 0.1; // use same defaut value as in Minos
52
53 // get first four points running Minos separately on the two parameters
54 // and then finding the corresponding minimum in the other
55 // P1( exlow, ymin1) where ymin1 is the parameter value (y) at the minimum of f when x is fixed to exlow
56 // P2(xmin1, eylow) where xmin1 is the the parameter value (x) at the minimum of f when y is fixed to eylow
57 // P3(exup, ymin2)
58 // P4(xmin2, eyup)
60
61 double valx = fMinimum.UserState().Value(px);
62 double valy = fMinimum.UserState().Value(py);
63
64 print.Debug("Run Minos to find first 4 contour points. Current minimum is : ",valx,valy);
65
66 MinosError mnex = minos.Minos(px);
67 nfcn += mnex.NFcn();
68 if (!mnex.IsValid()) {
69 print.Error("unable to find first two points");
70 return ContoursError(px, py, result, mnex, mnex, nfcn);
71 }
72 std::pair<double, double> ex = mnex();
73
74 print.Debug("Minos error for p0: ",ex.first,ex.second);
75
76 MinosError mney = minos.Minos(py);
77 nfcn += mney.NFcn();
78 if (!mney.IsValid()) {
79 print.Error("unable to find second two points");
80 return ContoursError(px, py, result, mnex, mney, nfcn);
81 }
82 std::pair<double, double> ey = mney();
83
84 print.Debug("Minos error for p0: ",ey.first,ey.second);
85
86 // if Minos is not at limits we can use migrad to find the other corresponding point coordinate
87 MnMigrad migrad0(fFCN, fMinimum.UserState(), MnStrategy(std::max(0, int(fStrategy.Strategy() - 1))));
88
89// function cross for a single parameter - copy the state
92 // need to copy the state since we modify it when calling function cross
93
94
95 auto findCrossValue = [&](unsigned int ipar, double startValue, double direction, bool & status) {
96 std::vector<unsigned int> vpar(1, ipar);
97 std::vector<double> vmid(1, startValue);
98 std::vector<double> vdir(1, direction);
99 ustate.Fix(ipar);
101 status = crossResult.IsValid();
102 print.Debug("result of findCrossValue for par",ipar,"status: ",status," searching from ",vmid[0],"dir",vdir[0],
103 " -> ",crossResult.Value()," fcn = ",crossResult.State().Fval());
104 return (status) ? vmid[0] + crossResult.Value() * vdir[0] : 0;
105 };
106
107 // function to find the contour points at the border of p1 after the minimization in p2
108 auto findContourPointsAtBorder = [&](unsigned int p1, unsigned int p2, double p1Limit, FunctionMinimum & minp2, bool order) {
109 // we are at the limit in p1
110 ustate.SetValue(p1, p1Limit);
111 ustate.Fix(p1);
112 bool ret1 = false;
113 bool ret2 = false;
114 double deltaFCN = fMinimum.Fval() + fFCN.Up()- minp2.UserState().Fval();
115 double pmid = minp2.UserState().Value(p2); // starting point for search
116 double pdir = minp2.UserState().Error(p2) * deltaFCN/fFCN.Up(); // direction for the search
117 double y1 = findCrossValue(p2, pmid, pdir, ret1);
118 double y2 = findCrossValue(p2, pmid, -pdir, ret2);
119 if (!ret1 && !ret2) {
120 return std::vector<double>();
121 }
122 std::vector<double> yvalues; yvalues.reserve(2);
123 // check if value is
124 if (ret1 && !ret2) {
125 yvalues.push_back(y1);
126 } else if (!ret1 && ret2) {
127 yvalues.push_back(y2);
128 } else {
129 // if points are not the same use both
130 if (std::abs(y1-y2) > 0.0001 * fMinimum.UserState().Error(p2)) {
131 // order them in increasing/decreasing y depending on order flag
132 int orderDir = (order) ? 1 : -1;
133 if (orderDir*(y2-y1) > 0) {
134 yvalues.push_back(y1);
135 yvalues.push_back(y2);
136 } else {
137 yvalues.push_back(y2);
138 yvalues.push_back(y1);
139 }
140 }
141 else
142 yvalues.push_back(y1);
143 }
144 print.Debug("Found contour point at the border: ",ustate.Value(p1)," , ",yvalues[0]);
145 if (yvalues.size() > 1) print.Debug("Found additional point at : ",ustate.Value(p1)," , ",yvalues[1]);
146 return yvalues;
147 };
148
149 // start from minimizing in p1 and fixing p0 to lower Minos value
150 std::vector<double> yvalues_xlo(1);
151 migrad0.Fix(px);
152 migrad0.SetValue(px, valx + ex.first);
154 nfcn += exy_lo.NFcn();
155 if (!exy_lo.IsValid()) {
156 print.Error("unable to find Lower y Value for x Parameter", px);
157 return ContoursError(px, py, result, mnex, mney, nfcn);
158 }
159 yvalues_xlo[0] = exy_lo.UserState().Value(py);
160 print.Debug("Minimum fcn value for px set to ",valx + ex.first," is at py = ",yvalues_xlo[0]," fcn = ",exy_lo.UserState().Fval());
161 if (mnex.AtLowerLimit()) {
162 // use MnCross to find contour point at borders starting from found minimum point. Order is in decreasing y
163 yvalues_xlo = findContourPointsAtBorder(px,py,ustate.Parameter(px).LowerLimit(),exy_lo, false);
164 if (yvalues_xlo.empty()) {
165 print.Error("unable to find corresponding value for ",py,"when Parameter",px,"is at lower limit: ", ustate.Value(px));
166 return ContoursError(px, py, result, mnex, mney, nfcn);
167 }
168 }
169
170 // now minimize in pi and fix p0 to upper Minos value
171 std::vector<double> yvalues_xup(1);
172 migrad0.SetValue(px, valx + ex.second);
173 migrad0.Fix(px);
175 nfcn += exy_up.NFcn();
176 if (!exy_up.IsValid()) {
177 print.Error("unable to find Upper y Value for x Parameter", px);
178 return ContoursError(px, py, result, mnex, mney, nfcn);
179 }
180 yvalues_xup[0] = exy_up.UserState().Value(py);
181 print.Debug("Minimum fcn value for px set to ",valx + ex.second," is at py = ",yvalues_xup[0]," fcn = ",exy_up.UserState().Fval());
182 if (mnex.AtUpperLimit()) {
183 // use MnCross to find contour point at borders starting from found minimum point. Order is in increasing y
184 yvalues_xup = findContourPointsAtBorder(px,py,ustate.Parameter(px).UpperLimit(),exy_up, true);
185 if (yvalues_xup.empty()) {
186 print.Error("unable to find corresponding value for ",py,"when Parameter",px,"is at upper limit: ", ustate.Value(px));
187 return ContoursError(px, py, result, mnex, mney, nfcn);
188 }
189 }
190
191 // now look for x values when y is fixed
192
193 MnMigrad migrad1(fFCN, fMinimum.UserState(), MnStrategy(std::max(0, int(fStrategy.Strategy() - 1))));
194 migrad1.Fix(py);
195 std::vector<double> xvalues_ylo(1);
196 migrad1.SetValue(py, valy + ey.first);
198 nfcn += eyx_lo.NFcn();
199 if (!eyx_lo.IsValid()) {
200 print.Error("unable to find Lower x Value for y Parameter", py);
201 return ContoursError(px, py, result, mnex, mney, nfcn);
202 }
203 xvalues_ylo[0] = eyx_lo.UserState().Value(px);
204 print.Debug("Minimum fcn value for py set to ",valy + ey.first," is at px = ",xvalues_ylo[0]," fcn = ",eyx_lo.UserState().Fval());
205 if (mney.AtLowerLimit()) {
206 // use MnCross to find contour point at borders starting from found minimum point. Order is in increasing x
207 xvalues_ylo = findContourPointsAtBorder(py,px,ustate.Parameter(py).LowerLimit(),eyx_lo, true);
208 if (xvalues_ylo.empty()) {
209 print.Error("unable to find corresponding value for ",px,"when Parameter",py,"is at lower limit: ", ustate.Value(py));
210 return ContoursError(px, py, result, mnex, mney, nfcn);
211 }
212 }
213
214 std::vector<double> xvalues_yup(1);
215 migrad1.Fix(py);
216 migrad1.SetValue(py, valy + ey.second);
218 nfcn += eyx_up.NFcn();
219 if (!eyx_up.IsValid()) {
220 print.Error("unable to find Upper x Value for y Parameter", py);
221 return ContoursError(px, py, result, mnex, mney, nfcn);
222 }
223 xvalues_yup[0] = eyx_up.UserState().Value(px);
224 print.Debug("Minimum fcn value for py set to ",valy + ey.second," is at px = ",xvalues_yup[0]," fcn = ",eyx_up.UserState().Fval());
225 if (mney.AtUpperLimit()) {
226 // use MnCross to find contour point at borders starting from found minimum point. Order is in decreasing x
227 xvalues_yup = findContourPointsAtBorder(py,px,ustate.Parameter(py).UpperLimit(),eyx_up, false);
228 if (xvalues_yup.empty()) {
229 print.Error("unable to find corresponding value for ",px,"when Parameter",py,"is at upper limit: ", ustate.Value(py));
230 return ContoursError(px, py, result, mnex, mney, nfcn);
231 }
232 }
233
234 // add the found point, start from low-x and add the extra points when existing (contour at border)
235 result.emplace_back(valx + ex.first, yvalues_xlo[0]);
236 if (yvalues_xlo.size()==2) result.emplace_back(valx + ex.first, yvalues_xlo[1]);
237 // low y
238 result.emplace_back(xvalues_ylo[0], valy + ey.first);
239 if (xvalues_ylo.size()==2) result.emplace_back(xvalues_ylo[1],valy + ey.first );
240 // up x
241 result.emplace_back(valx + ex.second, yvalues_xup[0]);
242 if (yvalues_xup.size()==2) result.emplace_back(valx + ex.second, yvalues_xup[1]);
243 // up y
244 result.emplace_back(xvalues_yup[0], valy + ey.second);
245 if (xvalues_yup.size()==2) result.emplace_back(xvalues_yup[1],valy + ey.second );
246
247
248 MnUserParameterState upar = fMinimum.UserState();
249
250
251 print.Debug([&](std::ostream &os){
252 os << "List of first " << result.size() << " points found: \n";
253 os << "Parameters : " << upar.Name(px) << "\t" << upar.Name(py) << std::endl;
254 for (auto & p : result) os << p << std::endl;
255 });
256
257 double scalx = 1. / (ex.second - ex.first);
258 double scaly = 1. / (ey.second - ey.first);
259
260 upar.Fix(px);
261 upar.Fix(py);
262
263 std::vector<unsigned int> par(2);
264 par[0] = px;
265 par[1] = py;
266 MnFunctionCross cross(fFCN, upar, fMinimum.Fval(), fStrategy);
267
268 // find the remaining points of the contour
269 unsigned int np0 = result.size();
270 for (unsigned int i = np0; i < npoints; i++) {
271
272 // find the two neighbouring points with largest separation
273 auto idist1 = result.end() - 1;
274 auto idist2 = result.begin();
275 double dx = idist1->first - (idist2)->first;
276 double dy = idist1->second - (idist2)->second;
277 double bigdis = scalx * scalx * dx * dx + scaly * scaly * dy * dy;
278
279 for (auto ipair = result.begin(); ipair != result.end() - 1; ++ipair) {
280 double distx = ipair->first - (ipair + 1)->first;
281 double disty = ipair->second - (ipair + 1)->second;
282 double dist = scalx * scalx * distx * distx + scaly * scaly * disty * disty;
283 // need to treat cases where points are at the border
284 if (distx == 0. && upar.Parameter(px).HasLimits() &&
285 (ipair->first == upar.Parameter(px).LowerLimit() || ipair->first == upar.Parameter(px).UpperLimit() ) )
286 dist = 0;
287 if (disty == 0. && upar.Parameter(py).HasLimits() &&
288 (ipair->second == upar.Parameter(py).LowerLimit() || ipair->second == upar.Parameter(py).UpperLimit() ) )
289 dist = 0;
290
291 if (dist > bigdis) {
292 bigdis = dist;
293 idist1 = ipair;
294 idist2 = ipair + 1;
295 }
296 }
297
298 double a1 = 0.5;
299 double a2 = 0.5;
300 double sca = 1.;
301
302 bool validPoint = false;
303
304 do {
305
306 if (nfcn > maxcalls) {
307 print.Error("maximum number of function calls exhausted");
308 return ContoursError(px, py, result, mnex, mney, nfcn);
309 }
310
311 print.Debug("Find new contour point between points with max sep: (",idist1->first,", ",idist1->second,") and (",
312 idist2->first,", ",idist2->second,") with weights ",a1,a2);
313 // find next point between the found 2 with max separation
314 // start from point situated at the middle (a1,a2=0.5)
315 // and direction
316 double xmidcr = a1 * idist1->first + a2 * (idist2)->first;
317 double ymidcr = a1 * idist1->second + a2 * (idist2)->second;
318 // direction is the perpendicular one
319 double xdir = (idist2)->second - idist1->second;
320 double ydir = idist1->first - (idist2)->first;
321 double scalfac = sca * std::max(std::fabs(xdir * scalx), std::fabs(ydir * scaly));
322 double xdircr = xdir / scalfac;
323 double ydircr = ydir / scalfac;
324 std::vector<double> pmid(2);
325 pmid[0] = xmidcr;
326 pmid[1] = ymidcr;
327 std::vector<double> pdir(2);
328 pdir[0] = xdircr;
329 pdir[1] = ydircr;
330
331 print.Debug("calling MnCross with pmid: ",pmid[0],pmid[1], "and pdir ",pdir[0],pdir[1]);
332 MnCross opt = cross(par, pmid, pdir, toler, maxcalls);
333 nfcn += opt.NFcn();
334 if (!opt.IsValid() || opt.AtLimit()) {
335 // Exclude also case where we are at limits since point is not in that case
336 // on the contour. If we are at limit maybe we should try more?
337 if (a1 < 0.3) {
338 // here when having tried with a1=0.5, a1 = 0.75 and a1=0.25
339 print.Info("Unable to find point on Contour", i + 1, '\n', "found only", i, "points");
340 return ContoursError(px, py, result, mnex, mney, nfcn);
341 } else if (a1 > 0.5) {
342 a1 = 0.25;
343 a2 = 0.75;
344 print.Debug("Unable to find point, try closer to p2 with weight values",a1,a2);
345 } else {
346 a1 = 0.75;
347 a2 = 0.25;
348 print.Debug("Unable to find point, try closer to p1 with weight values",a1,a2);
349 //std::cout<<"*****switch direction"<<std::endl;
350 //sca = -1.;
351 }
352 } else {
353 // a point is found
354 double aopt = opt.Value();
355 int pos = result.size();
356 if (idist2 == result.begin()) {
357 result.emplace_back(xmidcr + (aopt)*xdircr, ymidcr + (aopt)*ydircr);
358 print.Info(result.back());
359 } else {
360 print.Info(*idist2);
361 auto itr = result.insert(idist2, {xmidcr + (aopt)*xdircr, ymidcr + (aopt)*ydircr});
362 pos = std::distance(result.begin(),itr);
363 }
364 print.Info("Found new point - pos: ",pos,result[pos], "fcn = ",opt.State().Fval());
365 validPoint = true;
366 }
367 // loop until a valid point has been found
368 } while (!validPoint);
369 } // end loop on points
370
371 print.Info("Number of contour points =", result.size());
372
373 return ContoursError(px, py, result, mnex, mney, nfcn);
374}
375
376
377} // namespace Minuit2
378
379} // namespace ROOT
ROOT::Detail::TRangeCast< T, true > TRangeDynCast
TRangeDynCast is an adapter class that allows the typed iteration through a TCollection.
winID h TVirtualViewer3D TVirtualGLPainter p
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t result
Option_t Option_t TPoint TPoint const char y2
Option_t Option_t TPoint TPoint const char y1
class holding the full result of the minimization; both internal and external (MnUserParameterState) ...
Class holding the result of Minos (lower and upper values) for a specific parameter.
Definition MinosError.h:25
const FCNBase & fFCN
Definition MnContours.h:64
std::vector< std::pair< double, double > > operator()(unsigned int, unsigned int, unsigned int npoints=20) const
ask for one Contour (points only) from number of points (>=4) and parameter indices
ContoursError Contour(unsigned int, unsigned int, unsigned int npoints=20) const
ask for one Contour ContoursError (MinosErrors + points) from number of points (>=4) and parameter in...
const FunctionMinimum & fMinimum
Definition MnContours.h:65
bool AtLimit() const
Definition MnCross.h:90
const MnUserParameterState & State() const
Definition MnCross.h:88
unsigned int NFcn() const
Definition MnCross.h:93
bool IsValid() const
Definition MnCross.h:89
double Value() const
Definition MnCross.h:87
API class for minimization using Variable Metric technology ("MIGRAD"); allows for user interaction: ...
Definition MnMigrad.h:32
API class for Minos Error analysis (asymmetric errors); minimization has to be done before and Minimu...
Definition MnMinos.h:33
MinosError Minos(unsigned int, unsigned int maxcalls=0, double toler=0.1) const
ask for MinosError (Lower + Upper) can be printed via std::cout
Definition MnMinos.cxx:75
void Debug(const Ts &... args)
Definition MnPrint.h:135
void Error(const Ts &... args)
Definition MnPrint.h:117
void Info(const Ts &... args)
Definition MnPrint.h:129
API class for defining four levels of strategies: low (0), medium (1), high (2), very high (>=3); act...
Definition MnStrategy.h:27
unsigned int Strategy() const
Definition MnStrategy.h:36
class which holds the external user and/or internal Minuit representation of the parameters and error...
Double_t ey[n]
Definition legend1.C:17
Double_t ex[n]
Definition legend1.C:17
tbb::task_arena is an alias of tbb::interface7::task_arena, which doesn't allow to forward declare tb...