Logo ROOT  
Reference Guide
RooMinimizerFcn.cxx
Go to the documentation of this file.
1/*****************************************************************************
2 * Project: RooFit *
3 * Package: RooFitCore *
4 * @(#)root/roofitcore:$Id$
5 * Authors: *
6 * AL, Alfio Lazzaro, INFN Milan, alfio.lazzaro@mi.infn.it *
7 * *
8 * *
9 * Redistribution and use in source and binary forms, *
10 * with or without modification, are permitted according to the terms *
11 * listed in LICENSE (http://roofit.sourceforge.net/license.txt) *
12 *****************************************************************************/
13
14#ifndef __ROOFIT_NOROOMINIMIZER
15
16//////////////////////////////////////////////////////////////////////////////
17//
18// RooMinimizerFcn is am interface class to the ROOT::Math function
19// for minization.
20//
21
22#include <iostream>
23
24#include "RooFit.h"
25#include "RooMinimizerFcn.h"
26
27#include "Riostream.h"
28
29#include "TIterator.h"
30#include "TClass.h"
31
32#include "RooAbsArg.h"
33#include "RooAbsPdf.h"
34#include "RooArgSet.h"
35#include "RooRealVar.h"
36#include "RooAbsRealLValue.h"
37#include "RooMsgService.h"
38
39#include "RooMinimizer.h"
40
41using namespace std;
42
44 bool verbose) :
45 _funct(funct), _context(context),
46 // Reset the *largest* negative log-likelihood value we have seen so far
47 _maxFCN(-1e30), _numBadNLL(0),
48 _printEvalErrors(10), _doEvalErrorWall(kTRUE),
49 _nDim(0), _logfile(0),
50 _verbose(verbose)
51{
52
53 _evalCounter = 0 ;
54
55 // Examine parameter list
57 RooArgList paramList(*paramSet);
58 delete paramSet;
59
60 _floatParamList = (RooArgList*) paramList.selectByAttrib("Constant",kFALSE);
61 if (_floatParamList->getSize()>1) {
63 }
64 _floatParamList->setName("floatParamList");
65
66 _constParamList = (RooArgList*) paramList.selectByAttrib("Constant",kTRUE);
67 if (_constParamList->getSize()>1) {
69 }
70 _constParamList->setName("constParamList");
71
72 // Remove all non-RooRealVar parameters from list (MINUIT cannot handle them)
74 RooAbsArg* arg;
75 while ((arg=(RooAbsArg*)pIter->Next())) {
76 if (!arg->IsA()->InheritsFrom(RooAbsRealLValue::Class())) {
77 oocoutW(_context,Minimization) << "RooMinimizerFcn::RooMinimizerFcn: removing parameter "
78 << arg->GetName()
79 << " from list because it is not of type RooRealVar" << endl;
81 }
82 }
83 delete pIter;
84
86
88
89 // Save snapshot of initial lists
92
93}
94
95
96
98 _evalCounter(other._evalCounter),
99 _funct(other._funct),
100 _context(other._context),
101 _maxFCN(other._maxFCN),
102 _numBadNLL(other._numBadNLL),
103 _printEvalErrors(other._printEvalErrors),
104 _doEvalErrorWall(other._doEvalErrorWall),
105 _nDim(other._nDim),
106 _logfile(other._logfile),
107 _verbose(other._verbose),
108 _floatParamVec(other._floatParamVec)
109{
114}
115
116
118{
119 delete _floatParamList;
120 delete _initFloatParamList;
121 delete _constParamList;
122 delete _initConstParamList;
123}
124
125
127{
128 return new RooMinimizerFcn(*this) ;
129}
130
131
132Bool_t RooMinimizerFcn::Synchronize(std::vector<ROOT::Fit::ParameterSettings>& parameters,
133 Bool_t optConst, Bool_t verbose)
134{
135
136 // Internal function to synchronize TMinimizer with current
137 // information in RooAbsReal function parameters
138
139 Bool_t constValChange(kFALSE) ;
140 Bool_t constStatChange(kFALSE) ;
141
142 Int_t index(0) ;
143
144 // Handle eventual migrations from constParamList -> floatParamList
145 for(index= 0; index < _constParamList->getSize() ; index++) {
146
147 RooRealVar *par= dynamic_cast<RooRealVar*>(_constParamList->at(index)) ;
148 if (!par) continue ;
149
150 RooRealVar *oldpar= dynamic_cast<RooRealVar*>(_initConstParamList->at(index)) ;
151 if (!oldpar) continue ;
152
153 // Test if constness changed
154 if (!par->isConstant()) {
155
156 // Remove from constList, add to floatList
157 _constParamList->remove(*par) ;
158 _floatParamList->add(*par) ;
159 _initFloatParamList->addClone(*oldpar) ;
160 _initConstParamList->remove(*oldpar) ;
161 constStatChange=kTRUE ;
162 _nDim++ ;
163
164 if (verbose) {
165 oocoutI(_context,Minimization) << "RooMinimizerFcn::synchronize: parameter "
166 << par->GetName() << " is now floating." << endl ;
167 }
168 }
169
170 // Test if value changed
171 if (par->getVal()!= oldpar->getVal()) {
172 constValChange=kTRUE ;
173 if (verbose) {
174 oocoutI(_context,Minimization) << "RooMinimizerFcn::synchronize: value of constant parameter "
175 << par->GetName()
176 << " changed from " << oldpar->getVal() << " to "
177 << par->getVal() << endl ;
178 }
179 }
180
181 }
182
183 // Update reference list
185
186 // Synchronize MINUIT with function state
187 // Handle floatParamList
188 for(index= 0; index < _floatParamList->getSize(); index++) {
189 RooRealVar *par= dynamic_cast<RooRealVar*>(_floatParamList->at(index)) ;
190
191 if (!par) continue ;
192
193 Double_t pstep(0) ;
194 Double_t pmin(0) ;
195 Double_t pmax(0) ;
196
197 if(!par->isConstant()) {
198
199 // Verify that floating parameter is indeed of type RooRealVar
200 if (!par->IsA()->InheritsFrom(RooRealVar::Class())) {
201 oocoutW(_context,Minimization) << "RooMinimizerFcn::fit: Error, non-constant parameter "
202 << par->GetName()
203 << " is not of type RooRealVar, skipping" << endl ;
204 _floatParamList->remove(*par);
205 index--;
206 _nDim--;
207 continue ;
208 }
209
210 // Set the limits, if not infinite
211 if (par->hasMin() )
212 pmin = par->getMin();
213 if (par->hasMax() )
214 pmax = par->getMax();
215
216 // Calculate step size
217 pstep = par->getError();
218 if(pstep <= 0) {
219 // Floating parameter without error estitimate
220 if (par->hasMin() && par->hasMax()) {
221 pstep= 0.1*(pmax-pmin);
222
223 // Trim default choice of error if within 2 sigma of limit
224 if (pmax - par->getVal() < 2*pstep) {
225 pstep = (pmax - par->getVal())/2 ;
226 } else if (par->getVal() - pmin < 2*pstep) {
227 pstep = (par->getVal() - pmin )/2 ;
228 }
229
230 // If trimming results in zero error, restore default
231 if (pstep==0) {
232 pstep= 0.1*(pmax-pmin);
233 }
234
235 } else {
236 pstep=1 ;
237 }
238 if(verbose) {
239 oocoutW(_context,Minimization) << "RooMinimizerFcn::synchronize: WARNING: no initial error estimate available for "
240 << par->GetName() << ": using " << pstep << endl;
241 }
242 }
243 } else {
244 pmin = par->getVal() ;
245 pmax = par->getVal() ;
246 }
247
248 // new parameter
249 if (index>=Int_t(parameters.size())) {
250
251 if (par->hasMin() && par->hasMax()) {
252 parameters.push_back(ROOT::Fit::ParameterSettings(par->GetName(),
253 par->getVal(),
254 pstep,
255 pmin,pmax));
256 }
257 else {
258 parameters.push_back(ROOT::Fit::ParameterSettings(par->GetName(),
259 par->getVal(),
260 pstep));
261 if (par->hasMin() )
262 parameters.back().SetLowerLimit(pmin);
263 else if (par->hasMax() )
264 parameters.back().SetUpperLimit(pmax);
265 }
266
267 continue;
268
269 }
270
271 Bool_t oldFixed = parameters[index].IsFixed();
272 Double_t oldVar = parameters[index].Value();
273 Double_t oldVerr = parameters[index].StepSize();
274 Double_t oldVlo = parameters[index].LowerLimit();
275 Double_t oldVhi = parameters[index].UpperLimit();
276
277 if (par->isConstant() && !oldFixed) {
278
279 // Parameter changes floating -> constant : update only value if necessary
280 if (oldVar!=par->getVal()) {
281 parameters[index].SetValue(par->getVal());
282 if (verbose) {
283 oocoutI(_context,Minimization) << "RooMinimizerFcn::synchronize: value of parameter "
284 << par->GetName() << " changed from " << oldVar
285 << " to " << par->getVal() << endl ;
286 }
287 }
288 parameters[index].Fix();
289 constStatChange=kTRUE ;
290 if (verbose) {
291 oocoutI(_context,Minimization) << "RooMinimizerFcn::synchronize: parameter "
292 << par->GetName() << " is now fixed." << endl ;
293 }
294
295 } else if (par->isConstant() && oldFixed) {
296
297 // Parameter changes constant -> constant : update only value if necessary
298 if (oldVar!=par->getVal()) {
299 parameters[index].SetValue(par->getVal());
300 constValChange=kTRUE ;
301
302 if (verbose) {
303 oocoutI(_context,Minimization) << "RooMinimizerFcn::synchronize: value of fixed parameter "
304 << par->GetName() << " changed from " << oldVar
305 << " to " << par->getVal() << endl ;
306 }
307 }
308
309 } else {
310 // Parameter changes constant -> floating
311 if (!par->isConstant() && oldFixed) {
312 parameters[index].Release();
313 constStatChange=kTRUE ;
314
315 if (verbose) {
316 oocoutI(_context,Minimization) << "RooMinimizerFcn::synchronize: parameter "
317 << par->GetName() << " is now floating." << endl ;
318 }
319 }
320
321 // Parameter changes constant -> floating : update all if necessary
322 if (oldVar!=par->getVal() || oldVlo!=pmin || oldVhi != pmax || oldVerr!=pstep) {
323 parameters[index].SetValue(par->getVal());
324 parameters[index].SetStepSize(pstep);
325 if (par->hasMin() && par->hasMax() )
326 parameters[index].SetLimits(pmin,pmax);
327 else if (par->hasMin() )
328 parameters[index].SetLowerLimit(pmin);
329 else if (par->hasMax() )
330 parameters[index].SetUpperLimit(pmax);
331 }
332
333 // Inform user about changes in verbose mode
334 if (verbose) {
335 // if ierr<0, par was moved from the const list and a message was already printed
336
337 if (oldVar!=par->getVal()) {
338 oocoutI(_context,Minimization) << "RooMinimizerFcn::synchronize: value of parameter "
339 << par->GetName() << " changed from " << oldVar << " to "
340 << par->getVal() << endl ;
341 }
342 if (oldVlo!=pmin || oldVhi!=pmax) {
343 oocoutI(_context,Minimization) << "RooMinimizerFcn::synchronize: limits of parameter "
344 << par->GetName() << " changed from [" << oldVlo << "," << oldVhi
345 << "] to [" << pmin << "," << pmax << "]" << endl ;
346 }
347
348 // If oldVerr=0, then parameter was previously fixed
349 if (oldVerr!=pstep && oldVerr!=0) {
350 oocoutI(_context,Minimization) << "RooMinimizerFcn::synchronize: error/step size of parameter "
351 << par->GetName() << " changed from " << oldVerr << " to " << pstep << endl ;
352 }
353 }
354 }
355 }
356
357 if (optConst) {
358 if (constStatChange) {
359
361
362 oocoutI(_context,Minimization) << "RooMinimizerFcn::synchronize: set of constant parameters changed, rerunning const optimizer" << endl ;
364 } else if (constValChange) {
365 oocoutI(_context,Minimization) << "RooMinimizerFcn::synchronize: constant parameter values changed, rerunning const optimizer" << endl ;
367 }
368
370
371 }
372
374
375 return 0 ;
376
377}
378
380{
381 // Access PDF parameter value by ordinal index (needed by MINUIT)
382
383 return ((RooRealVar*)_floatParamList->at(index))->getVal() ;
384}
385
387{
388 // Access PDF parameter error by ordinal index (needed by MINUIT)
389 return ((RooRealVar*)_floatParamList->at(index))->getError() ;
390}
391
392
394{
395 // Modify PDF parameter error by ordinal index (needed by MINUIT)
396
397 ((RooRealVar*)_floatParamList->at(index))->setError(value) ;
398}
399
400
401
403{
404 // Modify PDF parameter error by ordinal index (needed by MINUIT)
405
406 ((RooRealVar*)_floatParamList->at(index))->removeAsymError() ;
407}
408
409
411{
412 // Modify PDF parameter error by ordinal index (needed by MINUIT)
413
414 ((RooRealVar*)_floatParamList->at(index))->setAsymError(loVal,hiVal) ;
415}
416
417
419{
420 // Transfer MINUIT fit results back into RooFit objects
421
422 for (Int_t index= 0; index < _nDim; index++) {
423 Double_t value = results.Value(index);
424 SetPdfParamVal(index, value);
425
426 // Set the parabolic error
427 Double_t err = results.Error(index);
428 SetPdfParamErr(index, err);
429
430 Double_t eminus = results.LowerError(index);
431 Double_t eplus = results.UpperError(index);
432
433 if(eplus > 0 || eminus < 0) {
434 // Store the asymmetric error, if it is available
435 SetPdfParamErr(index, eminus,eplus);
436 } else {
437 // Clear the asymmetric error
438 ClearPdfParamAsymErr(index) ;
439 }
440 }
441
442}
443
444Bool_t RooMinimizerFcn::SetLogFile(const char* inLogfile)
445{
446 // Change the file name for logging of a RooMinimizer of all MINUIT steppings
447 // through the parameter space. If inLogfile is null, the current log file
448 // is closed and logging is stopped.
449
450 if (_logfile) {
451 oocoutI(_context,Minimization) << "RooMinimizerFcn::setLogFile: closing previous log file" << endl ;
452 _logfile->close() ;
453 delete _logfile ;
454 _logfile = 0 ;
455 }
456 _logfile = new ofstream(inLogfile) ;
457 if (!_logfile->good()) {
458 oocoutI(_context,Minimization) << "RooMinimizerFcn::setLogFile: cannot open file " << inLogfile << endl ;
459 _logfile->close() ;
460 delete _logfile ;
461 _logfile= 0;
462 }
463
464 return kFALSE ;
465
466}
467
468
470{
471 // Apply results of given external covariance matrix. i.e. propagate its errors
472 // to all RRV parameter representations and give this matrix instead of the
473 // HESSE matrix at the next save() call
474
475 for (Int_t i=0 ; i<_nDim ; i++) {
476 // Skip fixed parameters
477 if (_floatParamList->at(i)->isConstant()) {
478 continue ;
479 }
480 SetPdfParamErr(i, sqrt(V(i,i))) ;
481 }
482
483}
484
485
486Bool_t RooMinimizerFcn::SetPdfParamVal(const Int_t &index, const Double_t &value) const
487{
488 //RooRealVar* par = (RooRealVar*)_floatParamList->at(index);
489 RooRealVar* par = (RooRealVar*)_floatParamVec[index] ;
490
491 if (par->getVal()!=value) {
492 if (_verbose) cout << par->GetName() << "=" << value << ", " ;
493
494 par->setVal(value);
495 return kTRUE;
496 }
497
498 return kFALSE;
499}
500
501
502
503////////////////////////////////////////////////////////////////////////////////
504
506{
507 _floatParamVec.clear() ;
509 RooAbsArg* arg ;
510 _floatParamVec = std::vector<RooAbsArg*>(_floatParamList->getSize()) ;
511 Int_t i(0) ;
512 while((arg=iter.next())) {
513 _floatParamVec[i++] = arg ;
514 }
515}
516
517
518
519double RooMinimizerFcn::DoEval(const double *x) const
520{
521
522 // Set the parameter values for this iteration
523 for (int index = 0; index < _nDim; index++) {
524 if (_logfile) (*_logfile) << x[index] << " " ;
525 SetPdfParamVal(index,x[index]);
526 }
527
528 // Calculate the function for these parameters
530 double fvalue = _funct->getVal();
532
533 if (RooAbsReal::numEvalErrors()>0 || fvalue > 1e30) {
534
535 if (_printEvalErrors>=0) {
536
537 if (_doEvalErrorWall) {
538 oocoutW(_context,Minimization) << "RooMinimizerFcn: Minimized function has error status." << endl
539 << "Returning maximum FCN so far (" << _maxFCN
540 << ") to force MIGRAD to back out of this region. Error log follows" << endl ;
541 } else {
542 oocoutW(_context,Minimization) << "RooMinimizerFcn: Minimized function has error status but is ignored" << endl ;
543 }
544
546 ooccoutW(_context,Minimization) << "Parameter values: " ;
547 for (const auto par : *_floatParamList) {
548 auto var = static_cast<const RooRealVar*>(par);
549 if (first) { first = kFALSE ; } else ooccoutW(_context,Minimization) << ", " ;
550 ooccoutW(_context,Minimization) << var->GetName() << "=" << var->getVal() ;
551 }
553
556 }
557
558 if (_doEvalErrorWall) {
559 fvalue = _maxFCN+1;
560 }
561
563 _numBadNLL++ ;
564 } else {
565 _maxFCN = std::max(fvalue, _maxFCN);
566 }
567
568 // Optional logging
569 if (_logfile)
570 (*_logfile) << setprecision(15) << fvalue << setprecision(4) << endl;
571 if (_verbose) {
572 cout << "\nprevFCN" << (_funct->isOffsetting()?"-offset":"") << " = " << setprecision(10)
573 << fvalue << setprecision(4) << " " ;
574 cout.flush() ;
575 }
576
577 _evalCounter++ ;
578
579 return fvalue;
580}
581
582#endif
583
void Class()
Definition: Class.C:29
#define oocoutW(o, a)
Definition: RooMsgService.h:47
#define oocoutI(o, a)
Definition: RooMsgService.h:45
#define ooccoutW(o, a)
Definition: RooMsgService.h:55
int Int_t
Definition: RtypesCore.h:43
const Bool_t kFALSE
Definition: RtypesCore.h:90
bool Bool_t
Definition: RtypesCore.h:61
double Double_t
Definition: RtypesCore.h:57
const Bool_t kTRUE
Definition: RtypesCore.h:89
double sqrt(double)
class containg the result of the fit and all the related information (fitted parameter values,...
Definition: FitResult.h:47
double UpperError(unsigned int i) const
upper Minos error. If Minos has not run for parameter i return the parabolic error
Definition: FitResult.cxx:378
double Error(unsigned int i) const
parameter error by index
Definition: FitResult.h:186
double Value(unsigned int i) const
parameter value by index
Definition: FitResult.h:179
double LowerError(unsigned int i) const
lower Minos error. If Minos has not run for parameter i return the parabolic error
Definition: FitResult.cxx:371
Class, describing value, limits and step size of the parameters Provides functionality also to set/re...
Documentation for the abstract class IBaseFunctionMultiDim.
Definition: IFunction.h:62
RooAbsArg is the common abstract base class for objects that represent a value (of arbitrary type) an...
Definition: RooAbsArg.h:73
RooArgSet * getParameters(const RooAbsData *data, Bool_t stripDisconnected=kTRUE) const
Create a list of leaf nodes in the arg tree starting with ourself as top node that don't match any of...
Definition: RooAbsArg.cxx:544
virtual void constOptimizeTestStatistic(ConstOpCode opcode, Bool_t doAlsoTrackingOpt=kTRUE)
Interface function signaling a request to perform constant term optimization.
Definition: RooAbsArg.cxx:1705
@ ValueChange
Definition: RooAbsArg.h:374
@ ConfigChange
Definition: RooAbsArg.h:374
Bool_t isConstant() const
Check if the "Constant" attribute is set.
Definition: RooAbsArg.h:342
Int_t getSize() const
void sort(Bool_t reverse=false)
Sort collection using std::sort and name comparison.
RooAbsCollection * snapshot(Bool_t deepCopy=kTRUE) const
Take a snap shot of current collection contents.
virtual RooAbsArg * addClone(const RooAbsArg &var, Bool_t silent=kFALSE)
Add a clone of the specified argument to list.
RooFIter fwdIterator() const
One-time forward iterator.
virtual Bool_t add(const RooAbsArg &var, Bool_t silent=kFALSE)
Add the specified argument to list.
RooAbsCollection * selectByAttrib(const char *name, Bool_t value) const
Create a subset of the current collection, consisting only of those elements with the specified attri...
void setName(const char *name)
virtual Bool_t remove(const RooAbsArg &var, Bool_t silent=kFALSE, Bool_t matchByNameOnly=kFALSE)
Remove the specified argument from our list.
TIterator * createIterator(Bool_t dir=kIterForward) const
TIterator-style iteration over contained elements.
virtual Double_t getMax(const char *name=0) const
Get maximum of currently defined range.
Bool_t hasMax(const char *name=0) const
Check if variable has an upper bound.
Bool_t hasMin(const char *name=0) const
Check if variable has a lower bound.
virtual Double_t getMin(const char *name=0) const
Get miniminum of currently defined range.
RooAbsReal is the common abstract base class for objects that represent a real value and implements f...
Definition: RooAbsReal.h:60
virtual Bool_t isOffsetting() const
Definition: RooAbsReal.h:343
static void setHideOffset(Bool_t flag)
Definition: RooAbsReal.cxx:116
Double_t getVal(const RooArgSet *normalisationSet=nullptr) const
Evaluate object.
Definition: RooAbsReal.h:90
static Int_t numEvalErrors()
Return the number of logged evaluation errors since the last clearing.
static void setEvalErrorLoggingMode(ErrorLoggingMode m)
Set evaluation error logging mode.
static void printEvalErrors(std::ostream &os=std::cout, Int_t maxPerNode=10000000)
Print all outstanding logged evaluation error on the given ostream.
static void clearEvalErrorLog()
Clear the stack of evaluation error messages.
RooArgList is a container object that can hold multiple RooAbsArg objects.
Definition: RooArgList.h:21
RooAbsArg * at(Int_t idx) const
Return object at given index, or nullptr if index is out of range.
Definition: RooArgList.h:74
RooArgSet is a container object that can hold multiple RooAbsArg objects.
Definition: RooArgSet.h:28
A one-time forward iterator working on RooLinkedList or RooAbsCollection.
RooAbsArg * next()
Return next element or nullptr if at end.
RooArgList * _floatParamList
std::ofstream * _logfile
void SetPdfParamErr(Int_t index, Double_t value)
RooArgList * _initFloatParamList
virtual double DoEval(const double *x) const
virtual ROOT::Math::IBaseFunctionMultiDim * Clone() const
Clone a function.
Bool_t SetLogFile(const char *inLogfile)
void ApplyCovarianceMatrix(TMatrixDSym &V)
Double_t GetPdfParamErr(Int_t index)
Double_t GetPdfParamVal(Int_t index)
Bool_t SetPdfParamVal(const Int_t &index, const Double_t &value) const
std::vector< RooAbsArg * > _floatParamVec
virtual ~RooMinimizerFcn()
RooArgList * _constParamList
Bool_t Synchronize(std::vector< ROOT::Fit::ParameterSettings > &parameters, Bool_t optConst, Bool_t verbose)
void BackProp(const ROOT::Fit::FitResult &results)
RooMinimizerFcn(RooAbsReal *funct, RooMinimizer *context, bool verbose=false)
RooAbsReal * _funct
RooMinimizer * _context
void ClearPdfParamAsymErr(Int_t index)
RooArgList * _initConstParamList
RooMinimizer is a wrapper class around ROOT::Fit:Fitter that provides a seamless interface between th...
Definition: RooMinimizer.h:38
RooRealVar represents a variable that can be changed from the outside.
Definition: RooRealVar.h:35
Double_t getError() const
Definition: RooRealVar.h:62
virtual void setVal(Double_t value)
Set value of variable to 'value'.
Definition: RooRealVar.cxx:225
Iterator abstract base class.
Definition: TIterator.h:30
virtual TObject * Next()=0
virtual const char * GetName() const
Returns name of object.
Definition: TNamed.h:47
virtual Bool_t InheritsFrom(const char *classname) const
Returns kTRUE if object inherits from class "classname".
Definition: TObject.cxx:443
Double_t x[n]
Definition: legend1.C:17
Namespace for new Math classes and functions.
IBaseFunctionMultiDimTempl< double > IBaseFunctionMultiDim
Definition: IFunctionfwd.h:31
tbb::task_arena is an alias of tbb::interface7::task_arena, which doesn't allow to forward declare tb...
Definition: StringConv.hxx:21
@ Minimization
Definition: RooGlobalFunc.h:67
static constexpr double eplus
Definition: first.py:1