Logo ROOT  
Reference Guide
 
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules Pages
Loading...
Searching...
No Matches
FitUtil.h
Go to the documentation of this file.
1// @(#)root/mathcore:$Id$
2// Author: L. Moneta Tue Nov 28 10:52:47 2006
3
4/**********************************************************************
5 * *
6 * Copyright (c) 2006 LCG ROOT Math Team, CERN/PH-SFT *
7 * *
8 * *
9 **********************************************************************/
10
11// Header file for class FitUtil
12
13#ifndef ROOT_Fit_FitUtil
14#define ROOT_Fit_FitUtil
15
17#include "Math/IParamFunction.h"
18
19#ifdef R__USE_IMT
21#endif
23
24#include "Fit/BinData.h"
25#include "Fit/UnBinData.h"
27
28#include "Math/Integrator.h"
30
31#include "TError.h"
32#include <vector>
33
34// using parameter cache is not thread safe but needed for normalizing the functions
35#define USE_PARAMCACHE
36
37//#define DEBUG_FITUTIL
38
39#ifdef R__HAS_VECCORE
40namespace vecCore {
41template <class T>
42vecCore::Mask<T> Int2Mask(unsigned i)
43{
44 T x;
45 for (unsigned j = 0; j < vecCore::VectorSize<T>(); j++)
46 vecCore::Set<T>(x, j, j);
47 return vecCore::Mask<T>(x < T(i));
48}
49}
50#endif
51
52namespace ROOT {
53
54 namespace Fit {
55
56/**
57 namespace defining utility free functions using in Fit for evaluating the various fit method
58 functions (chi2, likelihood, etc..) given the data and the model function
59
60 @ingroup FitMain
61*/
62namespace FitUtil {
63
66
67 template <class T>
69
70 template <class T>
72
73 // internal class defining
74 template <class T>
76 public:
77 LikelihoodAux(T logv = {}, T w = {}, T w2 = {}) : logvalue(logv), weight(w), weight2(w2) {}
78
80 {
81 return LikelihoodAux<T>(logvalue + l.logvalue, weight + l.weight, weight2 + l.weight2);
82 }
83
85 {
86 logvalue += l.logvalue;
87 weight += l.weight;
88 weight2 += l.weight2;
89 return *this;
90 }
91
95 };
96
97 template <>
99 public:
100 LikelihoodAux(double logv = 0.0, double w = 0.0, double w2 = 0.0) : logvalue(logv), weight(w), weight2(w2){};
101
103 {
104 return LikelihoodAux<double>(logvalue + l.logvalue, weight + l.weight, weight2 + l.weight2);
105 }
106
108 {
109 logvalue += l.logvalue;
110 weight += l.weight;
111 weight2 += l.weight2;
112 return *this;
113 }
114
115 double logvalue;
116 double weight;
117 double weight2;
118 };
119
120 // internal class to evaluate the function or the integral
121 // and cached internal integration details
122 // if useIntegral is false no allocation is done
123 // and this is a dummy class
124 // class is templated on any parametric functor implementing operator()(x,p) and NDim()
125 // contains a constant pointer to the function
126
127 template <class ParamFunc = ROOT::Math::IParamMultiFunctionTempl<double>>
129
130 public:
131 IntegralEvaluator(const ParamFunc &func, const double *p, bool useIntegral = true,
133 : fDim(0), fParams(nullptr), fFunc(nullptr), fIg1Dim(nullptr), fIgNDim(nullptr), fFunc1Dim(nullptr), fFuncNDim(nullptr)
134 {
135 if (useIntegral) {
136 SetFunction(func, p, igType);
137 }
138 }
139
140 void SetFunction(const ParamFunc &func, const double *p = nullptr,
142 {
143 // set the integrand function and create required wrapper
144 // to perform integral in (x) of a generic f(x,p)
145 fParams = p;
146 fDim = func.NDim();
147 // copy the function object to be able to modify the parameters
148 // fFunc = dynamic_cast<ROOT::Math::IParamMultiFunction *>( func.Clone() );
149 fFunc = &func;
150 assert(fFunc != nullptr);
151 // set parameters in function
152 // fFunc->SetParameters(p);
153 if (fDim == 1) {
154 fFunc1Dim =
156 *this, &IntegralEvaluator::F1);
158 // fIg1Dim->SetFunction( static_cast<const ROOT::Math::IMultiGenFunction & >(*fFunc),false);
159 fIg1Dim->SetFunction(static_cast<const ROOT::Math::IGenFunction &>(*fFunc1Dim));
160 } else if (fDim > 1) {
161 fFuncNDim =
163 const>(*this, &IntegralEvaluator::FN, fDim);
166 } else
167 assert(fDim > 0);
168 }
169
170 void SetParameters(const double *p)
171 {
172 // copy just the pointer
173 fParams = p;
174 }
175
177 {
178 if (fIg1Dim)
179 delete fIg1Dim;
180 if (fIgNDim)
181 delete fIgNDim;
182 if (fFunc1Dim)
183 delete fFunc1Dim;
184 if (fFuncNDim)
185 delete fFuncNDim;
186 // if (fFunc) delete fFunc;
187 }
188
189 // evaluation of integrand function (one-dim)
190 double F1(double x) const
191 {
192 double xx = x;
193 return ExecFunc(fFunc, &xx, fParams);
194 }
195 // evaluation of integrand function (multi-dim)
196 double FN(const double *x) const { return ExecFunc(fFunc, x, fParams); }
197
198 double Integral(const double *x1, const double *x2)
199 {
200 // return unnormalized integral
201 return (fIg1Dim) ? fIg1Dim->Integral(*x1, *x2) : fIgNDim->Integral(x1, x2);
202 }
203
204 double operator()(const double *x1, const double *x2)
205 {
206 // return normalized integral, divided by bin volume (dx1*dx...*dxn)
207 if (fIg1Dim) {
208 double dV = *x2 - *x1;
209 return fIg1Dim->Integral(*x1, *x2) / dV;
210 } else if (fIgNDim) {
211 double dV = 1;
212 for (unsigned int i = 0; i < fDim; ++i)
213 dV *= (x2[i] - x1[i]);
214 return fIgNDim->Integral(x1, x2) / dV;
215 // std::cout << " do integral btw x " << x1[0] << " " << x2[0] << " y " << x1[1] << " "
216 // << x2[1] << " dV = " << dV << " result = " << result << std::endl; return result;
217 } else
218 assert(1.); // should never be here
219 return 0;
220 }
221
222 private:
223 template <class T>
224 inline double ExecFunc(T *f, const double *x, const double *p) const
225 {
226 return (*f)(x, p);
227 }
228
229#ifdef R__HAS_VECCORE
230
231#if __clang_major__ > 16
232#pragma clang diagnostic push
233#pragma clang diagnostic ignored "-Wvla-cxx-extension"
234#endif
235
236 inline double ExecFunc(const IModelFunctionTempl<ROOT::Double_v> *f, const double *x, const double *p) const
237 {
238 // Figure out the size of the SIMD vectors.
239 constexpr static int vecSize = sizeof(ROOT::Double_v) / sizeof(double);
240 double xBuffer[vecSize];
242 for (unsigned int i = 0; i < fDim; ++i) {
243 // The Load() function reads multiple values from the pointed-to
244 // memory into xx. This is why we have to copy the input values from
245 // the x array into a zero-padded buffer to read from. Otherwise,
246 // Load() would access the x array out of bounds.
247 *xBuffer = x[i];
248 for(int j = 1; j < vecSize; ++j) {
249 xBuffer[j] = 0.0;
250 }
251 vecCore::Load<ROOT::Double_v>(xx[i], xBuffer);
252 }
253 auto res = (*f)(xx, p);
254 return vecCore::Get<ROOT::Double_v>(res, 0);
255 }
256
257#if __clang_major__ > 16
258#pragma clang diagnostic pop
259#endif
260
261#endif
262
263 // objects of this class are not meant to be copied / assigned
266
267 unsigned int fDim;
268 const double *fParams;
269 // ROOT::Math::IParamMultiFunction * fFunc; // copy of function in order to be able to change parameters
270 // const ParamFunc * fFunc; // reference to a generic parametric function
271 const ParamFunc *fFunc;
276 };
277
278 /** Chi2 Functions */
279
280 /**
281 evaluate the Chi2 given a model function and the data at the point x.
282 return also nPoints as the effective number of used points in the Chi2 evaluation
283 */
284 double EvaluateChi2(const IModelFunction &func, const BinData &data, const double *p, unsigned int &nPoints,
286
287 /**
288 evaluate the effective Chi2 given a model function and the data at the point x.
289 The effective chi2 uses the errors on the coordinates : W = 1/(sigma_y**2 + ( sigma_x_i * df/dx_i )**2 )
290 return also nPoints as the effective number of used points in the Chi2 evaluation
291 */
292 double EvaluateChi2Effective(const IModelFunction &func, const BinData &data, const double *x, unsigned int &nPoints);
293
294 /**
295 evaluate the Chi2 gradient given a model function and the data at the point p.
296 return also nPoints as the effective number of used points in the Chi2 evaluation
297 */
298 void EvaluateChi2Gradient(const IModelFunction &func, const BinData &data, const double *p, double *grad,
299 unsigned int &nPoints,
301 unsigned nChunks = 0);
302
303 /**
304 evaluate the LogL given a model function and the data at the point x.
305 return also nPoints as the effective number of used points in the LogL evaluation
306 */
307 double EvaluateLogL(const IModelFunction &func, const UnBinData &data, const double *p, int iWeight, bool extended,
308 unsigned int &nPoints, ::ROOT::EExecutionPolicy executionPolicy, unsigned nChunks = 0);
309
310 /**
311 evaluate the LogL gradient given a model function and the data at the point p.
312 return also nPoints as the effective number of used points in the LogL evaluation
313 */
314 void EvaluateLogLGradient(const IModelFunction &func, const UnBinData &data, const double *p, double *grad,
315 unsigned int &nPoints,
317 unsigned nChunks = 0);
318
319 // #ifdef R__HAS_VECCORE
320 // template <class NotCompileIfScalarBackend = std::enable_if<!(std::is_same<double, ROOT::Double_v>::value)>>
321 // void EvaluateLogLGradient(const IModelFunctionTempl<ROOT::Double_v> &, const UnBinData &, const double *, double
322 // *, unsigned int & ) {}
323 // #endif
324
325 /**
326 evaluate the Poisson LogL given a model function and the data at the point p.
327 return also nPoints as the effective number of used points in the LogL evaluation
328 By default is extended, pass extend to false if want to be not extended (MultiNomial)
329 */
330 double EvaluatePoissonLogL(const IModelFunction &func, const BinData &data, const double *p, int iWeight,
332 unsigned nChunks = 0);
333
334 /**
335 evaluate the Poisson LogL given a model function and the data at the point p.
336 return also nPoints as the effective number of used points in the LogL evaluation
337 */
338 void EvaluatePoissonLogLGradient(const IModelFunction &func, const BinData &data, const double *p, double *grad,
339 unsigned int &nPoints,
341 unsigned nChunks = 0);
342
343 // methods required by dedicate minimizer like Fumili
344
345 /**
346 evaluate the residual contribution to the Chi2 given a model function and the BinPoint data
347 and if the pointer g is not null evaluate also the gradient of the residual.
348 If the function provides parameter derivatives they are used otherwise a simple derivative calculation
349 is used
350 */
351 double EvaluateChi2Residual(const IModelFunction &func, const BinData &data, const double *p, unsigned int ipoint,
352 double *g = nullptr, double * h = nullptr, bool hasGrad = false, bool fullHessian = false);
353
354 /**
355 evaluate the pdf contribution to the LogL given a model function and the BinPoint data.
356 If the pointer g is not null evaluate also the gradient of the pdf.
357 If the function provides parameter derivatives they are used otherwise a simple derivative calculation
358 is used
359 */
360 double
361 EvaluatePdf(const IModelFunction &func, const UnBinData &data, const double *p, unsigned int ipoint, double *g = nullptr, double * h = nullptr, bool hasGrad = false, bool fullHessian = false);
362
363
364 /**
365 evaluate the pdf contribution to the Poisson LogL given a model function and the BinPoint data.
366 If the pointer g is not null evaluate also the gradient of the Poisson pdf.
367 If the function provides parameter derivatives they are used otherwise a simple derivative calculation
368 is used
369 */
370 double EvaluatePoissonBinPdf(const IModelFunction & func, const BinData & data, const double * x, unsigned int ipoint, double * g = nullptr, double * h = nullptr, bool hasGrad = false, bool fullHessian = false);
371
372 unsigned setAutomaticChunking(unsigned nEvents);
373
374 template<class T>
375 struct Evaluate {
376#ifdef R__HAS_VECCORE
377 static double EvalChi2(const IModelFunctionTempl<T> &func, const BinData &data, const double *p,
378 unsigned int &nPoints, ::ROOT::EExecutionPolicy executionPolicy, unsigned nChunks = 0)
379 {
380 // evaluate the chi2 given a vectorized function reference , the data and returns the value and also in nPoints
381 // the actual number of used points
382 // normal chi2 using only error on values (from fitting histogram)
383 // optionally the integral of function in the bin is used
384
385 //Info("EvalChi2","Using vectorized implementation %d",(int) data.Opt().fIntegral);
386
387 unsigned int n = data.Size();
388 nPoints = data.Size(); // npoints
389
390 // set parameters of the function to cache integral value
391#ifdef USE_PARAMCACHE
392 (const_cast<IModelFunctionTempl<T> &>(func)).SetParameters(p);
393#endif
394 // do not cache parameter values (it is not thread safe)
395 //func.SetParameters(p);
396
397
398 // get fit option and check case if using integral of bins
399 const DataOptions &fitOpt = data.Opt();
400 if (fitOpt.fBinVolume || fitOpt.fIntegral || fitOpt.fExpErrors)
401 Error("FitUtil::EvaluateChi2", "The vectorized implementation doesn't support Integrals, BinVolume or ExpErrors\n. Aborting operation.");
402
403 (const_cast<IModelFunctionTempl<T> &>(func)).SetParameters(p);
404
405 double maxResValue = std::numeric_limits<double>::max() / n;
406 std::vector<double> ones{1., 1., 1., 1.};
407 auto vecSize = vecCore::VectorSize<T>();
408
409 auto mapFunction = [&](unsigned int i) {
410 // in case of no error in y invError=1 is returned
411 T x1, y, invErrorVec;
412 vecCore::Load<T>(x1, data.GetCoordComponent(i * vecSize, 0));
413 vecCore::Load<T>(y, data.ValuePtr(i * vecSize));
414 const auto invError = data.ErrorPtr(i * vecSize);
415 auto invErrorptr = (invError != nullptr) ? invError : &ones.front();
416 vecCore::Load<T>(invErrorVec, invErrorptr);
417
418 const T *x;
419 std::vector<T> xc;
420 if(data.NDim() > 1) {
421 xc.resize(data.NDim());
422 xc[0] = x1;
423 for (unsigned int j = 1; j < data.NDim(); ++j)
424 vecCore::Load<T>(xc[j], data.GetCoordComponent(i * vecSize, j));
425 x = xc.data();
426 } else {
427 x = &x1;
428 }
429
430 T fval{};
431
432#ifdef USE_PARAMCACHE
433 fval = func(x);
434#else
435 fval = func(x, p);
436#endif
437
438 T tmp = (y - fval) * invErrorVec;
439 T chi2 = tmp * tmp;
440
441
442 // avoid infinity or nan in chi2 values due to wrong function values
443 auto m = vecCore::Mask_v<T>(chi2 > maxResValue);
444
445 vecCore::MaskedAssign<T>(chi2, m, maxResValue);
446
447 return chi2;
448 };
449
450 auto redFunction = [](const std::vector<T> &objs) {
451 return std::accumulate(objs.begin(), objs.end(), T{});
452 };
453
454#ifndef R__USE_IMT
455 (void)nChunks;
456
457 // If IMT is disabled, force the execution policy to the serial case
459 Warning("FitUtil::EvaluateChi2", "Multithread execution policy requires IMT, which is disabled. Changing "
460 "to ::ROOT::EExecutionPolicy::kSequential.");
462 }
463#endif
464
465 T res{};
468 res = pool.MapReduce(mapFunction, ROOT::TSeq<unsigned>(0, data.Size()/vecSize), redFunction);
469#ifdef R__USE_IMT
472 auto chunks = nChunks != 0 ? nChunks : setAutomaticChunking(data.Size() / vecSize);
473 res = pool.MapReduce(mapFunction, ROOT::TSeq<unsigned>(0, data.Size() / vecSize), redFunction, chunks);
474#endif
475 } else {
476 Error("FitUtil::EvaluateChi2", "Execution policy unknown. Available choices:\n ::ROOT::EExecutionPolicy::kSequential (default)\n ::ROOT::EExecutionPolicy::kMultiThread (requires IMT)\n");
477 }
478
479 // Last SIMD vector of elements (if padding needed)
480 if (data.Size() % vecSize != 0)
481 vecCore::MaskedAssign(res, vecCore::Int2Mask<T>(data.Size() % vecSize),
482 res + mapFunction(data.Size() / vecSize));
483
484 return vecCore::ReduceAdd(res);
485 }
486
487 static double EvalLogL(const IModelFunctionTempl<T> &func, const UnBinData &data, const double *const p,
488 int iWeight, bool extended, unsigned int &nPoints,
490 {
491 // evaluate the LogLikelihood
492 unsigned int n = data.Size();
493 nPoints = data.Size(); // npoints
494
495 //unsigned int nRejected = 0;
496 bool normalizeFunc = false;
497
498 // set parameters of the function to cache integral value
499#ifdef USE_PARAMCACHE
500 (const_cast<IModelFunctionTempl<T> &>(func)).SetParameters(p);
501#endif
502
503#ifdef R__USE_IMT
504 // in case parameter needs to be propagated to user function use trick to set parameters by calling one time the function
505 // this will be done in sequential mode and parameters can be set in a thread safe manner
506 if (!normalizeFunc) {
507 if (data.NDim() == 1) {
508 T x;
509 vecCore::Load<T>(x, data.GetCoordComponent(0, 0));
510 func( &x, p);
511 }
512 else {
513 std::vector<T> x(data.NDim());
514 for (unsigned int j = 0; j < data.NDim(); ++j)
515 vecCore::Load<T>(x[j], data.GetCoordComponent(0, j));
516 func( x.data(), p);
517 }
518 }
519#endif
520
521 // this is needed if function must be normalized
522 double norm = 1.0;
523 if (normalizeFunc) {
524 // compute integral of the function
525 std::vector<double> xmin(data.NDim());
526 std::vector<double> xmax(data.NDim());
528 // compute integral in the ranges where is defined
529 if (data.Range().Size() > 0) {
530 norm = 0;
531 for (unsigned int ir = 0; ir < data.Range().Size(); ++ir) {
532 data.Range().GetRange(&xmin[0], &xmax[0], ir);
533 norm += igEval.Integral(xmin.data(), xmax.data());
534 }
535 } else {
536 // use (-inf +inf)
537 data.Range().GetRange(&xmin[0], &xmax[0]);
538 // check if function is zero at +- inf
539 T xmin_v, xmax_v;
540 vecCore::Load<T>(xmin_v, xmin.data());
541 vecCore::Load<T>(xmax_v, xmax.data());
542 if (vecCore::ReduceAdd(func(&xmin_v, p)) != 0 || vecCore::ReduceAdd(func(&xmax_v, p)) != 0) {
543 MATH_ERROR_MSG("FitUtil::EvaluateLogLikelihood", "A range has not been set and the function is not zero at +/- inf");
544 return 0;
545 }
546 norm = igEval.Integral(&xmin[0], &xmax[0]);
547 }
548 }
549
550 // needed to compute effective global weight in case of extended likelihood
551
552 auto vecSize = vecCore::VectorSize<T>();
553 unsigned int numVectors = n / vecSize;
554
555 auto mapFunction = [ &, p](const unsigned i) {
556 T W{};
557 T W2{};
558 T fval{};
559
560 (void)p; /* avoid unused lambda capture warning if PARAMCACHE is disabled */
561
562 T x1;
563 vecCore::Load<T>(x1, data.GetCoordComponent(i * vecSize, 0));
564 const T *x = nullptr;
565 unsigned int ndim = data.NDim();
566 std::vector<T> xc;
567 if (ndim > 1) {
568 xc.resize(ndim);
569 xc[0] = x1;
570 for (unsigned int j = 1; j < ndim; ++j)
571 vecCore::Load<T>(xc[j], data.GetCoordComponent(i * vecSize, j));
572 x = xc.data();
573 } else {
574 x = &x1;
575 }
576
577#ifdef USE_PARAMCACHE
578 fval = func(x);
579#else
580 fval = func(x, p);
581#endif
582
583#ifdef DEBUG_FITUTIL
584 if (i < 5 || (i > numVectors-5) ) {
585 if (ndim == 1) std::cout << i << " x " << x[0] << " fval = " << fval;
586 else std::cout << i << " x " << x[0] << " y " << x[1] << " fval = " << fval;
587 }
588#endif
589
590 if (normalizeFunc) fval = fval * (1 / norm);
591
592 // function EvalLog protects against negative or too small values of fval
594 if (iWeight > 0) {
595 T weight{};
596 if (data.WeightsPtr(i) == nullptr)
597 weight = 1;
598 else
599 vecCore::Load<T>(weight, data.WeightsPtr(i*vecSize));
600 logval *= weight;
601 if (iWeight == 2) {
602 logval *= weight; // use square of weights in likelihood
603 if (!extended) {
604 // needed sum of weights and sum of weight square if likelkihood is extended
605 W = weight;
606 W2 = weight * weight;
607 }
608 }
609 }
610#ifdef DEBUG_FITUTIL
611 if (i < 5 || (i > numVectors-5)) {
612 std::cout << " " << fval << " logfval " << logval << std::endl;
613 }
614#endif
615
616 return LikelihoodAux<T>(logval, W, W2);
617 };
618
619 auto redFunction = [](const std::vector<LikelihoodAux<T>> &objs) {
620 return std::accumulate(objs.begin(), objs.end(), LikelihoodAux<T>(),
621 [](const LikelihoodAux<T> &l1, const LikelihoodAux<T> &l2) {
622 return l1 + l2;
623 });
624 };
625
626#ifndef R__USE_IMT
627 (void)nChunks;
628
629 // If IMT is disabled, force the execution policy to the serial case
631 Warning("FitUtil::EvaluateLogL", "Multithread execution policy requires IMT, which is disabled. Changing "
632 "to ::ROOT::EExecutionPolicy::kSequential.");
634 }
635#endif
636
637 T logl_v{};
638 T sumW_v{};
639 T sumW2_v{};
644#ifdef R__USE_IMT
649#endif
650 } else {
651 Error("FitUtil::EvaluateLogL", "Execution policy unknown. Available choices:\n ::ROOT::EExecutionPolicy::kSequential (default)\n ::ROOT::EExecutionPolicy::kMultiThread (requires IMT)\n");
652 }
653
654 logl_v = resArray.logvalue;
655 sumW_v = resArray.weight;
656 sumW2_v = resArray.weight2;
657
658 // Compute the contribution from the remaining points ( Last padded SIMD vector of elements )
659 unsigned int remainingPoints = n % vecSize;
660 if (remainingPoints > 0) {
662 // Add the contribution from the valid remaining points and store the result in the output variable
663 auto remainingMask = vecCore::Int2Mask<T>(remainingPoints);
664 vecCore::MaskedAssign(logl_v, remainingMask, logl_v + remainingPointsContribution.logvalue);
665 vecCore::MaskedAssign(sumW_v, remainingMask, sumW_v + remainingPointsContribution.weight);
666 vecCore::MaskedAssign(sumW2_v, remainingMask, sumW2_v + remainingPointsContribution.weight2);
667 }
668
669
670 //reduce vector type to double.
671 double logl = vecCore::ReduceAdd(logl_v);
672 double sumW = vecCore::ReduceAdd(sumW_v);
673 double sumW2 = vecCore::ReduceAdd(sumW2_v);
674
675 if (extended) {
676 // add Poisson extended term
677 double extendedTerm = 0; // extended term in likelihood
678 double nuTot = 0;
679 // nuTot is integral of function in the range
680 // if function has been normalized integral has been already computed
681 if (!normalizeFunc) {
683 std::vector<double> xmin(data.NDim());
684 std::vector<double> xmax(data.NDim());
685
686 // compute integral in the ranges where is defined
687 if (data.Range().Size() > 0) {
688 nuTot = 0;
689 for (unsigned int ir = 0; ir < data.Range().Size(); ++ir) {
690 data.Range().GetRange(&xmin[0], &xmax[0], ir);
691 nuTot += igEval.Integral(xmin.data(), xmax.data());
692 }
693 } else {
694 // use (-inf +inf)
695 data.Range().GetRange(&xmin[0], &xmax[0]);
696 // check if function is zero at +- inf
697 T xmin_v, xmax_v;
698 vecCore::Load<T>(xmin_v, xmin.data());
699 vecCore::Load<T>(xmax_v, xmax.data());
700 if (vecCore::ReduceAdd(func(&xmin_v, p)) != 0 || vecCore::ReduceAdd(func(&xmax_v, p)) != 0) {
701 MATH_ERROR_MSG("FitUtil::EvaluateLogLikelihood", "A range has not been set and the function is not zero at +/- inf");
702 return 0;
703 }
704 nuTot = igEval.Integral(&xmin[0], &xmax[0]);
705 }
706
707 // force to be last parameter value
708 //nutot = p[func.NDim()-1];
709 if (iWeight != 2)
710 extendedTerm = - nuTot; // no need to add in this case n log(nu) since is already computed before
711 else {
712 // case use weight square in likelihood : compute total effective weight = sw2/sw
713 // ignore for the moment case when sumW is zero
714 extendedTerm = - (sumW2 / sumW) * nuTot;
715 }
716
717 } else {
718 nuTot = norm;
719 extendedTerm = - nuTot + double(n) * ROOT::Math::Util::EvalLog(nuTot);
720 // in case of weights need to use here sum of weights (to be done)
721 }
722
723 logl += extendedTerm;
724 }
725
726#ifdef DEBUG_FITUTIL
727 std::cout << "Evaluated log L for parameters (";
728 for (unsigned int ip = 0; ip < func.NPar(); ++ip)
729 std::cout << " " << p[ip];
730 std::cout << ") nll = " << -logl << std::endl;
731#endif
732
733 return -logl;
734
735 }
736
737 static double EvalPoissonLogL(const IModelFunctionTempl<T> &func, const BinData &data, const double *p,
738 int iWeight, bool extended, unsigned int,
740 {
741 // evaluate the Poisson Log Likelihood
742 // for binned likelihood fits
743 // this is Sum ( f(x_i) - y_i * log( f (x_i) ) )
744 // add as well constant term for saturated model to make it like a Chi2/2
745 // by default is extended. If extended is false the fit is not extended and
746 // the global poisson term is removed (i.e is a binomial fit)
747 // (remember that in this case one needs to have a function with a fixed normalization
748 // like in a non extended binned fit)
749 //
750 // if use Weight use a weighted dataset
751 // iWeight = 1 ==> logL = Sum( w f(x_i) )
752 // case of iWeight==1 is actually identical to weight==0
753 // iWeight = 2 ==> logL = Sum( w*w * f(x_i) )
754 //
755
756#ifdef USE_PARAMCACHE
757 (const_cast<IModelFunctionTempl<T> &>(func)).SetParameters(p);
758#endif
759 auto vecSize = vecCore::VectorSize<T>();
760 // get fit option and check case of using integral of bins
761 const DataOptions &fitOpt = data.Opt();
762 if (fitOpt.fExpErrors || fitOpt.fIntegral)
763 Error("FitUtil::EvaluateChi2",
764 "The vectorized implementation doesn't support Integrals or BinVolume\n. Aborting operation.");
765 bool useW2 = (iWeight == 2);
766
767 auto mapFunction = [&](unsigned int i) {
768 T y;
769 vecCore::Load<T>(y, data.ValuePtr(i * vecSize));
770 T fval{};
771
772 if (data.NDim() > 1) {
773 std::vector<T> x(data.NDim());
774 for (unsigned int j = 0; j < data.NDim(); ++j)
775 vecCore::Load<T>(x[j], data.GetCoordComponent(i * vecSize, j));
776#ifdef USE_PARAMCACHE
777 fval = func(x.data());
778#else
779 fval = func(x.data(), p);
780#endif
781 // one -dim case
782 } else {
783 T x;
784 vecCore::Load<T>(x, data.GetCoordComponent(i * vecSize, 0));
785#ifdef USE_PARAMCACHE
786 fval = func(&x);
787#else
788 fval = func(&x, p);
789#endif
790 }
791
792 // EvalLog protects against 0 values of fval but don't want to add in the -log sum
793 // negative values of fval
794 vecCore::MaskedAssign<T>(fval, fval < 0.0, 0.0);
795
796 T nloglike{}; // negative loglikelihood
797
798 if (useW2) {
799 // apply weight correction . Effective weight is error^2/ y
800 // and expected events in bins is fval/weight
801 // can apply correction only when y is not zero otherwise weight is undefined
802 // (in case of weighted likelihood I don't care about the constant term due to
803 // the saturated model)
805 T error = 0.0;
806 vecCore::Load<T>(error, data.ErrorPtr(i * vecSize));
807 // for empty bin use the average weight computed from the total data weight
808 auto m = vecCore::Mask_v<T>(y != 0.0);
809 auto weight = vecCore::Blend(m,(error * error) / y, T(data.SumOfError2()/ data.SumOfContent()) );
810 if (extended) {
811 nloglike = weight * ( fval - y);
812 }
813 vecCore::MaskedAssign<T>(nloglike, y != 0, nloglike + weight * y *( ROOT::Math::Util::EvalLog(y) - ROOT::Math::Util::EvalLog(fval)) );
814
815 } else {
816 // standard case no weights or iWeight=1
817 // this is needed for Poisson likelihood (which are extended and not for multinomial)
818 // the formula below include constant term due to likelihood of saturated model (f(x) = y)
819 // (same formula as in Baker-Cousins paper, page 439 except a factor of 2
820 if (extended) nloglike = fval - y;
821
822 vecCore::MaskedAssign<T>(
824 }
825
826 return nloglike;
827 };
828
829#ifdef R__USE_IMT
830 auto redFunction = [](const std::vector<T> &objs) { return std::accumulate(objs.begin(), objs.end(), T{}); };
831#else
832 (void)nChunks;
833
834 // If IMT is disabled, force the execution policy to the serial case
836 Warning("FitUtil::Evaluate<T>::EvalPoissonLogL",
837 "Multithread execution policy requires IMT, which is disabled. Changing "
838 "to ::ROOT::EExecutionPolicy::kSequential.");
840 }
841#endif
842
843 T res{};
845 for (unsigned int i = 0; i < (data.Size() / vecSize); i++) {
846 res += mapFunction(i);
847 }
848#ifdef R__USE_IMT
851 auto chunks = nChunks != 0 ? nChunks : setAutomaticChunking(data.Size() / vecSize);
852 res = pool.MapReduce(mapFunction, ROOT::TSeq<unsigned>(0, data.Size() / vecSize), redFunction, chunks);
853#endif
854 } else {
855 Error(
856 "FitUtil::Evaluate<T>::EvalPoissonLogL",
857 "Execution policy unknown. Available choices:\n ::ROOT::EExecutionPolicy::kSequential (default)\n ::ROOT::EExecutionPolicy::kMultiThread (requires IMT)\n");
858 }
859
860 // Last padded SIMD vector of elements
861 if (data.Size() % vecSize != 0)
862 vecCore::MaskedAssign(res, vecCore::Int2Mask<T>(data.Size() % vecSize),
863 res + mapFunction(data.Size() / vecSize));
864
865 return vecCore::ReduceAdd(res);
866 }
867
868 static double EvalChi2Effective(const IModelFunctionTempl<T> &, const BinData &, const double *, unsigned int &)
869 {
870 Error("FitUtil::Evaluate<T>::EvalChi2Effective", "The vectorized evaluation of the Chi2 with coordinate errors is still not supported");
871 return -1.;
872 }
873
874 // Compute a mask to filter out infinite numbers and NaN values.
875 // The argument rval is updated so infinite numbers and NaN values are replaced by
876 // maximum finite values (preserving the original sign).
877 static vecCore::Mask<T> CheckInfNaNValues(T &rval)
878 {
879 auto mask = rval > -vecCore::NumericLimits<T>::Max() && rval < vecCore::NumericLimits<T>::Max();
880
881 // Case +inf or nan
882 vecCore::MaskedAssign(rval, !mask, +vecCore::NumericLimits<T>::Max());
883
884 // Case -inf
885 vecCore::MaskedAssign(rval, !mask && rval < 0, -vecCore::NumericLimits<T>::Max());
886
887 return mask;
888 }
889
890 static void EvalChi2Gradient(const IModelFunctionTempl<T> &f, const BinData &data, const double *p, double *grad,
891 unsigned int &nPoints,
893 unsigned nChunks = 0)
894 {
895 // evaluate the gradient of the chi2 function
896 // this function is used when the model function knows how to calculate the derivative and we can
897 // avoid that the minimizer re-computes them
898 //
899 // case of chi2 effective (errors on coordinate) is not supported
900
901 if (data.HaveCoordErrors()) {
902 MATH_ERROR_MSG("FitUtil::EvaluateChi2Gradient",
903 "Error on the coordinates are not used in calculating Chi2 gradient");
904 return; // it will assert otherwise later in GetPoint
905 }
906
907 const IGradModelFunctionTempl<T> *fg = dynamic_cast<const IGradModelFunctionTempl<T> *>(&f);
908 assert(fg != nullptr); // must be called by a gradient function
909
910 const IGradModelFunctionTempl<T> &func = *fg;
911
912 const DataOptions &fitOpt = data.Opt();
913 if (fitOpt.fBinVolume || fitOpt.fIntegral || fitOpt.fExpErrors)
914 Error("FitUtil::EvaluateChi2Gradient", "The vectorized implementation doesn't support Integrals,"
915 "BinVolume or ExpErrors\n. Aborting operation.");
916
917 unsigned int npar = func.NPar();
918 auto vecSize = vecCore::VectorSize<T>();
919 unsigned initialNPoints = data.Size();
920 unsigned numVectors = initialNPoints / vecSize;
921
922 // numVectors + 1 because of the padded data (call to mapFunction with i = numVectors after the main loop)
923 std::vector<vecCore::Mask<T>> validPointsMasks(numVectors + 1);
924
925 auto mapFunction = [&](const unsigned int i) {
926 // set all vector values to zero
927 std::vector<T> gradFunc(npar);
928 std::vector<T> pointContributionVec(npar);
929
930 T x1, y, invError;
931
932 vecCore::Load<T>(x1, data.GetCoordComponent(i * vecSize, 0));
933 vecCore::Load<T>(y, data.ValuePtr(i * vecSize));
934 const auto invErrorPtr = data.ErrorPtr(i * vecSize);
935
936 if (invErrorPtr == nullptr)
937 invError = 1;
938 else
939 vecCore::Load<T>(invError, invErrorPtr);
940
941 // TODO: Check error options and invert if needed
942
943 T fval = 0;
944
945 const T *x = nullptr;
946
947 unsigned int ndim = data.NDim();
948 // need to declare vector outside if statement
949 // otherwise pointer will be invalid
950 std::vector<T> xc;
951 if (ndim > 1) {
952 xc.resize(ndim);
953 xc[0] = x1;
954 for (unsigned int j = 1; j < ndim; ++j)
955 vecCore::Load<T>(xc[j], data.GetCoordComponent(i * vecSize, j));
956 x = xc.data();
957 } else {
958 x = &x1;
959 }
960
961 fval = func(x, p);
962 func.ParameterGradient(x, p, &gradFunc[0]);
963
965 if (vecCore::MaskEmpty(validPointsMasks[i])) {
966 // Return a zero contribution to all partial derivatives on behalf of the current points
968 }
969
970 // loop on the parameters
971 for (unsigned int ipar = 0; ipar < npar; ++ipar) {
972 // avoid singularity in the function (infinity and nan ) in the chi2 sum
973 // eventually add possibility of excluding some points (like singularity)
975
976 if (vecCore::MaskEmpty(validPointsMasks[i])) {
977 break; // exit loop on parameters
978 }
979
980 // calculate derivative point contribution (only for valid points)
981 vecCore::MaskedAssign(pointContributionVec[ipar], validPointsMasks[i],
982 -2.0 * (y - fval) * invError * invError * gradFunc[ipar]);
983 }
984
986 };
987
988 // Reduce the set of vectors by summing its equally-indexed components
989 auto redFunction = [&](const std::vector<std::vector<T>> &partialResults) {
990 std::vector<T> result(npar);
991
992 for (auto const &pointContributionVec : partialResults) {
993 for (unsigned int parameterIndex = 0; parameterIndex < npar; parameterIndex++)
995 }
996
997 return result;
998 };
999
1000 std::vector<T> gVec(npar);
1001 std::vector<double> g(npar);
1002
1003#ifndef R__USE_IMT
1004 // to fix compiler warning
1005 (void)nChunks;
1006
1007 // If IMT is disabled, force the execution policy to the serial case
1009 Warning("FitUtil::EvaluateChi2Gradient",
1010 "Multithread execution policy requires IMT, which is disabled. Changing "
1011 "to ::ROOT::EExecutionPolicy::kSequential.");
1013 }
1014#endif
1015
1019 }
1020#ifdef R__USE_IMT
1025 }
1026#endif
1027 else {
1028 Error(
1029 "FitUtil::EvaluateChi2Gradient",
1030 "Execution policy unknown. Available choices:\n 0: Serial (default)\n 1: MultiThread (requires IMT)\n");
1031 }
1032
1033 // Compute the contribution from the remaining points
1034 unsigned int remainingPoints = initialNPoints % vecSize;
1035 if (remainingPoints > 0) {
1037 // Add the contribution from the valid remaining points and store the result in the output variable
1038 auto remainingMask = vecCore::Int2Mask<T>(remainingPoints);
1039 for (unsigned int param = 0; param < npar; param++) {
1040 vecCore::MaskedAssign(gVec[param], remainingMask, gVec[param] + remainingPointsContribution[param]);
1041 }
1042 }
1043 // reduce final gradient result from T to double
1044 for (unsigned int param = 0; param < npar; param++) {
1045 grad[param] = vecCore::ReduceAdd(gVec[param]);
1046 }
1047
1048 // correct the number of points
1050
1051 if (std::any_of(validPointsMasks.begin(), validPointsMasks.end(),
1052 [](vecCore::Mask<T> validPoints) { return !vecCore::MaskFull(validPoints); })) {
1053 unsigned nRejected = 0;
1054
1055 for (const auto &mask : validPointsMasks) {
1056 for (unsigned int i = 0; i < vecSize; i++) {
1057 nRejected += !vecCore::Get(mask, i);
1058 }
1059 }
1060
1063
1064 if (nPoints < npar) {
1065 MATH_ERROR_MSG("FitUtil::EvaluateChi2Gradient",
1066 "Too many points rejected for overflow in gradient calculation");
1067 }
1068 }
1069 }
1070
1071 static double EvalChi2Residual(const IModelFunctionTempl<T> &, const BinData &, const double *, unsigned int, double *, double *, bool, bool)
1072 {
1073 Error("FitUtil::Evaluate<T>::EvalChi2Residual", "The vectorized evaluation of the Chi2 with the ith residual is still not supported");
1074 return -1.;
1075 }
1076
1077 /// evaluate the pdf (Poisson) contribution to the logl (return actually log of pdf)
1078 /// and its gradient
1079 static double EvalPoissonBinPdf(const IModelFunctionTempl<T> &, const BinData &, const double *, unsigned int , double * , double * , bool, bool) {
1080 Error("FitUtil::Evaluate<T>::EvaluatePoissonBinPdf", "The vectorized evaluation of the BinnedLikelihood fit evaluated point by point is still not supported");
1081 return -1.;
1082 }
1083
1084 static double EvalPdf(const IModelFunctionTempl<T> &, const UnBinData &, const double *, unsigned int , double * , double * , bool, bool) {
1085 Error("FitUtil::Evaluate<T>::EvalPdf", "The vectorized evaluation of the LogLikelihood fit evaluated point by point is still not supported");
1086 return -1.;
1087 }
1088
1089 //template <class NotCompileIfScalarBackend = std::enable_if<!(std::is_same<double, ROOT::Double_v>::value)>>
1090 // static double EvalPdf(const IModelFunctionTempl<ROOT::Double_v> &func, const UnBinData &data, const double *p, unsigned int i, double *, double *, bool, bool) {
1091 // // evaluate the pdf contribution to the generic logl function in case of bin data
1092 // // return actually the log of the pdf and its derivatives
1093 // // func.SetParameters(p);
1094 // const auto x = vecCore::FromPtr<ROOT::Double_v>(data.GetCoordComponent(i, 0));
1095 // auto fval = func(&x, p);
1096 // auto logPdf = ROOT::Math::Util::EvalLog(fval);
1097 // return vecCore::Get<ROOT::Double_v>(logPdf, 0);
1098
1099 static void
1100 EvalPoissonLogLGradient(const IModelFunctionTempl<T> &f, const BinData &data, const double *p, double *grad,
1101 unsigned int &,
1103 unsigned nChunks = 0)
1104 {
1105 // evaluate the gradient of the Poisson log likelihood function
1106
1107 const IGradModelFunctionTempl<T> *fg = dynamic_cast<const IGradModelFunctionTempl<T> *>(&f);
1108 assert(fg != nullptr); // must be called by a grad function
1109
1110 const IGradModelFunctionTempl<T> &func = *fg;
1111
1112 (const_cast<IGradModelFunctionTempl<T> &>(func)).SetParameters(p);
1113
1114
1115 const DataOptions &fitOpt = data.Opt();
1116 if (fitOpt.fBinVolume || fitOpt.fIntegral || fitOpt.fExpErrors)
1117 Error("FitUtil::EvaluatePoissonLogLGradient", "The vectorized implementation doesn't support Integrals,"
1118 "BinVolume or ExpErrors\n. Aborting operation.");
1119
1120 unsigned int npar = func.NPar();
1121 auto vecSize = vecCore::VectorSize<T>();
1122 unsigned initialNPoints = data.Size();
1123 unsigned numVectors = initialNPoints / vecSize;
1124
1125 auto mapFunction = [&](const unsigned int i) {
1126 // set all vector values to zero
1127 std::vector<T> gradFunc(npar);
1128 std::vector<T> pointContributionVec(npar);
1129
1130 T x1, y;
1131
1132 vecCore::Load<T>(x1, data.GetCoordComponent(i * vecSize, 0));
1133 vecCore::Load<T>(y, data.ValuePtr(i * vecSize));
1134
1135 T fval = 0;
1136
1137 const T *x = nullptr;
1138
1139 unsigned ndim = data.NDim();
1140 std::vector<T> xc;
1141 if (ndim > 1) {
1142 xc.resize(ndim);
1143 xc[0] = x1;
1144 for (unsigned int j = 1; j < ndim; ++j)
1145 vecCore::Load<T>(xc[j], data.GetCoordComponent(i * vecSize, j));
1146 x = xc.data();
1147 } else {
1148 x = &x1;
1149 }
1150
1151 fval = func(x, p);
1152 func.ParameterGradient(x, p, &gradFunc[0]);
1153
1154 // correct the gradient
1155 for (unsigned int ipar = 0; ipar < npar; ++ipar) {
1156 vecCore::Mask<T> positiveValuesMask = fval > 0;
1157
1158 // df/dp * (1. - y/f )
1159 vecCore::MaskedAssign(pointContributionVec[ipar], positiveValuesMask, gradFunc[ipar] * (1. - y / fval));
1160
1161 vecCore::Mask<T> validNegativeValuesMask = !positiveValuesMask && gradFunc[ipar] != 0;
1162
1163 if (!vecCore::MaskEmpty(validNegativeValuesMask)) {
1164 const T kdmax1 = vecCore::math::Sqrt(vecCore::NumericLimits<T>::Max());
1165 const T kdmax2 = vecCore::NumericLimits<T>::Max() / (4 * initialNPoints);
1166 T gg = kdmax1 * gradFunc[ipar];
1167 pointContributionVec[ipar] = -vecCore::Blend(gg > 0, vecCore::math::Min(gg, kdmax2), vecCore::math::Max(gg, -kdmax2));
1168 }
1169 }
1170
1171#ifdef DEBUG_FITUTIL
1172 {
1174 if (i < 5 || (i > data.Size()-5) ) {
1175 if (data.NDim() > 1) std::cout << i << " x " << x[0] << " y " << x[1];
1176 else std::cout << i << " x " << x[0];
1177 std::cout << " func " << fval << " gradient ";
1178 for (unsigned int ii = 0; ii < npar; ++ii) std::cout << " " << pointContributionVec[ii];
1179 std::cout << "\n";
1180 }
1181 }
1182#endif
1183
1184 return pointContributionVec;
1185 };
1186
1187 // Vertically reduce the set of vectors by summing its equally-indexed components
1188 auto redFunction = [&](const std::vector<std::vector<T>> &partialResults) {
1189 std::vector<T> result(npar);
1190
1191 for (auto const &pointContributionVec : partialResults) {
1192 for (unsigned int parameterIndex = 0; parameterIndex < npar; parameterIndex++)
1194 }
1195
1196 return result;
1197 };
1198
1199 std::vector<T> gVec(npar);
1200
1201#ifndef R__USE_IMT
1202 // to fix compiler warning
1203 (void)nChunks;
1204
1205 // If IMT is disabled, force the execution policy to the serial case
1207 Warning("FitUtil::EvaluatePoissonLogLGradient",
1208 "Multithread execution policy requires IMT, which is disabled. Changing "
1209 "to ::ROOT::EExecutionPolicy::kSequential.");
1211 }
1212#endif
1213
1217 }
1218#ifdef R__USE_IMT
1223 }
1224#endif
1225 else {
1226 Error("FitUtil::EvaluatePoissonLogLGradient", "Execution policy unknown. Available choices:\n "
1227 "::ROOT::EExecutionPolicy::kSequential (default)\n "
1228 "::ROOT::EExecutionPolicy::kMultiThread (requires IMT)\n");
1229 }
1230
1231
1232 // Compute the contribution from the remaining points
1233 unsigned int remainingPoints = initialNPoints % vecSize;
1234 if (remainingPoints > 0) {
1236 // Add the contribution from the valid remaining points and store the result in the output variable
1237 auto remainingMask = vecCore::Int2Mask<T>(remainingPoints);
1238 for (unsigned int param = 0; param < npar; param++) {
1239 vecCore::MaskedAssign(gVec[param], remainingMask, gVec[param] + remainingPointsContribution[param]);
1240 }
1241 }
1242 // reduce final gradient result from T to double
1243 for (unsigned int param = 0; param < npar; param++) {
1244 grad[param] = vecCore::ReduceAdd(gVec[param]);
1245 }
1246
1247#ifdef DEBUG_FITUTIL
1248 std::cout << "***** Final gradient : ";
1249 for (unsigned int ii = 0; ii< npar; ++ii) std::cout << grad[ii] << " ";
1250 std::cout << "\n";
1251#endif
1252
1253 }
1254
1255 static void EvalLogLGradient(const IModelFunctionTempl<T> &f, const UnBinData &data, const double *p,
1256 double *grad, unsigned int &,
1258 unsigned nChunks = 0)
1259 {
1260 // evaluate the gradient of the log likelihood function
1261
1262 const IGradModelFunctionTempl<T> *fg = dynamic_cast<const IGradModelFunctionTempl<T> *>(&f);
1263 assert(fg != nullptr); // must be called by a grad function
1264
1265 const IGradModelFunctionTempl<T> &func = *fg;
1266
1267
1268 unsigned int npar = func.NPar();
1269 auto vecSize = vecCore::VectorSize<T>();
1270 unsigned initialNPoints = data.Size();
1271 unsigned numVectors = initialNPoints / vecSize;
1272
1273#ifdef DEBUG_FITUTIL
1274 std::cout << "\n===> Evaluate Gradient for parameters ";
1275 for (unsigned int ip = 0; ip < npar; ++ip)
1276 std::cout << " " << p[ip];
1277 std::cout << "\n";
1278#endif
1279
1280 (const_cast<IGradModelFunctionTempl<T> &>(func)).SetParameters(p);
1281
1282 const T kdmax1 = vecCore::math::Sqrt(vecCore::NumericLimits<T>::Max());
1283 const T kdmax2 = vecCore::NumericLimits<T>::Max() / (4 * initialNPoints);
1284
1285 auto mapFunction = [&](const unsigned int i) {
1286 std::vector<T> gradFunc(npar);
1287 std::vector<T> pointContributionVec(npar);
1288
1289 T x1;
1290 vecCore::Load<T>(x1, data.GetCoordComponent(i * vecSize, 0));
1291
1292 const T *x = nullptr;
1293
1294 unsigned int ndim = data.NDim();
1295 std::vector<T> xc(ndim);
1296 if (ndim > 1) {
1297 xc.resize(ndim);
1298 xc[0] = x1;
1299 for (unsigned int j = 1; j < ndim; ++j)
1300 vecCore::Load<T>(xc[j], data.GetCoordComponent(i * vecSize, j));
1301 x = xc.data();
1302 } else {
1303 x = &x1;
1304 }
1305
1306
1307 T fval = func(x, p);
1308 func.ParameterGradient(x, p, &gradFunc[0]);
1309
1310#ifdef DEBUG_FITUTIL
1311 if (i < 5 || (i > numVectors-5) ) {
1312 if (ndim > 1) std::cout << i << " x " << x[0] << " y " << x[1] << " gradient " << gradFunc[0] << " " << gradFunc[1] << " " << gradFunc[3] << std::endl;
1313 else std::cout << i << " x " << x[0] << " gradient " << gradFunc[0] << " " << gradFunc[1] << " " << gradFunc[3] << std::endl;
1314 }
1315#endif
1316
1317 vecCore::Mask<T> positiveValues = fval > 0;
1318
1319 for (unsigned int kpar = 0; kpar < npar; ++kpar) {
1320 if (!vecCore::MaskEmpty(positiveValues))
1321 vecCore::MaskedAssign<T>(pointContributionVec[kpar], positiveValues, -1. / fval * gradFunc[kpar]);
1322
1323 vecCore::Mask<T> nonZeroGradientValues = !positiveValues && gradFunc[kpar] != 0;
1324 if (!vecCore::MaskEmpty(nonZeroGradientValues)) {
1325 T gg = kdmax1 * gradFunc[kpar];
1327 vecCore::Blend(nonZeroGradientValues && gg > 0, -vecCore::math::Min(gg, kdmax2),
1328 -vecCore::math::Max(gg, -kdmax2));
1329 }
1330 // if func derivative is zero term is also zero so do not add in g[kpar]
1331 }
1332
1333 return pointContributionVec;
1334 };
1335
1336 // Vertically reduce the set of vectors by summing its equally-indexed components
1337 auto redFunction = [&](const std::vector<std::vector<T>> &pointContributions) {
1338 std::vector<T> result(npar);
1339
1340 for (auto const &pointContributionVec : pointContributions) {
1341 for (unsigned int parameterIndex = 0; parameterIndex < npar; parameterIndex++)
1343 }
1344
1345 return result;
1346 };
1347
1348 std::vector<T> gVec(npar);
1349 std::vector<double> g(npar);
1350
1351#ifndef R__USE_IMT
1352 // to fix compiler warning
1353 (void)nChunks;
1354
1355 // If IMT is disabled, force the execution policy to the serial case
1357 Warning("FitUtil::EvaluateLogLGradient",
1358 "Multithread execution policy requires IMT, which is disabled. Changing "
1359 "to ::ROOT::EExecutionPolicy::kSequential.");
1361 }
1362#endif
1363
1367 }
1368#ifdef R__USE_IMT
1373 }
1374#endif
1375 else {
1376 Error("FitUtil::EvaluateLogLGradient", "Execution policy unknown. Available choices:\n "
1377 "::ROOT::EExecutionPolicy::kSequential (default)\n "
1378 "::ROOT::EExecutionPolicy::kMultiThread (requires IMT)\n");
1379 }
1380
1381 // Compute the contribution from the remaining points
1382 unsigned int remainingPoints = initialNPoints % vecSize;
1383 if (remainingPoints > 0) {
1385 // Add the contribution from the valid remaining points and store the result in the output variable
1386 auto remainingMask = vecCore::Int2Mask<T>(initialNPoints % vecSize);
1387 for (unsigned int param = 0; param < npar; param++) {
1388 vecCore::MaskedAssign(gVec[param], remainingMask, gVec[param] + remainingPointsContribution[param]);
1389 }
1390 }
1391 // reduce final gradient result from T to double
1392 for (unsigned int param = 0; param < npar; param++) {
1393 grad[param] = vecCore::ReduceAdd(gVec[param]);
1394 }
1395
1396#ifdef DEBUG_FITUTIL
1397 std::cout << "Final gradient ";
1398 for (unsigned int param = 0; param < npar; param++) {
1399 std::cout << " " << grad[param];
1400 }
1401 std::cout << "\n";
1402#endif
1403 }
1404 };
1405
1406 template<>
1407 struct Evaluate<double>{
1408#endif
1409
1410 static double EvalChi2(const IModelFunction &func, const BinData &data, const double *p, unsigned int &nPoints,
1412 {
1413 // evaluate the chi2 given a function reference, the data and returns the value and also in nPoints
1414 // the actual number of used points
1415 // normal chi2 using only error on values (from fitting histogram)
1416 // optionally the integral of function in the bin is used
1417
1418
1419 //Info("EvalChi2","Using non-vectorized implementation %d",(int) data.Opt().fIntegral);
1420
1422 }
1423
1424 static double EvalLogL(const IModelFunctionTempl<double> &func, const UnBinData &data, const double *p,
1425 int iWeight, bool extended, unsigned int &nPoints,
1427 {
1429 }
1430
1431 static double EvalPoissonLogL(const IModelFunctionTempl<double> &func, const BinData &data, const double *p,
1432 int iWeight, bool extended, unsigned int &nPoints,
1434 {
1436 }
1437
1438 static double EvalChi2Effective(const IModelFunctionTempl<double> &func, const BinData & data, const double * p, unsigned int &nPoints)
1439 {
1441 }
1442 static void EvalChi2Gradient(const IModelFunctionTempl<double> &func, const BinData &data, const double *p,
1443 double *g, unsigned int &nPoints,
1445 unsigned nChunks = 0)
1446 {
1448 }
1449
1450 static double EvalChi2Residual(const IModelFunctionTempl<double> &func, const BinData & data, const double * p, unsigned int i, double *g, double * h,
1451 bool hasGrad, bool fullHessian)
1452 {
1454 }
1455
1456 /// evaluate the pdf (Poisson) contribution to the logl (return actually log of pdf)
1457 /// and its gradient
1458 static double EvalPoissonBinPdf(const IModelFunctionTempl<double> &func, const BinData & data, const double *p, unsigned int i, double *g, double * h, bool hasGrad, bool fullHessian) {
1460 }
1461
1462 static double EvalPdf(const IModelFunctionTempl<double> &func, const UnBinData & data, const double *p, unsigned int i, double *g, double * h, bool hasGrad, bool fullHessian) {
1463 return FitUtil::EvaluatePdf(func, data, p, i, g, h, hasGrad, fullHessian);
1464 }
1465
1466 static void
1474
1475 static void EvalLogLGradient(const IModelFunctionTempl<double> &func, const UnBinData &data, const double *p,
1476 double *g, unsigned int &nPoints,
1478 unsigned nChunks = 0)
1479 {
1481 }
1482 };
1483
1484} // end namespace FitUtil
1485
1486 } // end namespace Fit
1487
1488} // end namespace ROOT
1489
1490#if defined (R__HAS_VECCORE) && defined(R__HAS_VC)
1491//Fixes alignment for structures of SIMD structures
1493#endif
1494
1495#endif /* ROOT_Fit_FitUtil */
#define MATH_ERROR_MSG(loc, str)
Definition Error.h:83
#define f(i)
Definition RSha256.hxx:104
#define g(i)
Definition RSha256.hxx:105
#define h(i)
Definition RSha256.hxx:106
ROOT::Detail::TRangeCast< T, true > TRangeDynCast
TRangeDynCast is an adapter class that allows the typed iteration through a TCollection.
void Error(const char *location, const char *msgfmt,...)
Use this function in case an error occurred.
Definition TError.cxx:185
void Warning(const char *location, const char *msgfmt,...)
Use this function in warning situations.
Definition TError.cxx:229
winID h TVirtualViewer3D TVirtualGLPainter p
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void data
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 mask
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 x2
Option_t Option_t TPoint TPoint const char x1
float xmin
float xmax
R__EXTERN TVirtualMutex * gROOTMutex
Definition TROOT.h:63
#define R__LOCKGUARD(mutex)
Class describing the binned data sets : vectors of x coordinates, y values and optionally error on y ...
Definition BinData.h:52
double Integral(const double *x1, const double *x2)
Definition FitUtil.h:198
ROOT::Math::IGenFunction * fFunc1Dim
Definition FitUtil.h:274
ROOT::Math::IntegratorMultiDim * fIgNDim
Definition FitUtil.h:273
void SetFunction(const ParamFunc &func, const double *p=nullptr, ROOT::Math::IntegrationOneDim::Type igType=ROOT::Math::IntegrationOneDim::kDEFAULT)
Definition FitUtil.h:140
IntegralEvaluator(const IntegralEvaluator &rhs)=delete
IntegralEvaluator(const ParamFunc &func, const double *p, bool useIntegral=true, ROOT::Math::IntegrationOneDim::Type igType=ROOT::Math::IntegrationOneDim::kDEFAULT)
Definition FitUtil.h:131
IntegralEvaluator & operator=(const IntegralEvaluator &rhs)=delete
double F1(double x) const
Definition FitUtil.h:190
ROOT::Math::IntegratorOneDim * fIg1Dim
Definition FitUtil.h:272
double FN(const double *x) const
Definition FitUtil.h:196
ROOT::Math::IMultiGenFunction * fFuncNDim
Definition FitUtil.h:275
void SetParameters(const double *p)
Definition FitUtil.h:170
double ExecFunc(T *f, const double *x, const double *p) const
Definition FitUtil.h:224
double operator()(const double *x1, const double *x2)
Definition FitUtil.h:204
LikelihoodAux(double logv=0.0, double w=0.0, double w2=0.0)
Definition FitUtil.h:100
LikelihoodAux & operator+=(const LikelihoodAux &l)
Definition FitUtil.h:107
LikelihoodAux operator+(const LikelihoodAux &l) const
Definition FitUtil.h:102
LikelihoodAux operator+(const LikelihoodAux &l) const
Definition FitUtil.h:79
LikelihoodAux(T logv={}, T w={}, T w2={})
Definition FitUtil.h:77
LikelihoodAux & operator+=(const LikelihoodAux &l)
Definition FitUtil.h:84
Class describing the un-binned data sets (just x coordinates values) of any dimensions.
Definition UnBinData.h:46
Documentation for the abstract class IBaseFunctionMultiDim.
Definition IFunction.h:61
Interface (abstract class) for generic functions objects of one-dimension Provides a method to evalua...
Definition IFunction.h:112
Interface (abstract class) for parametric gradient multi-dimensional functions providing in addition ...
User class for performing multidimensional integration.
double Integral(const double *xmin, const double *xmax)
evaluate the integral with the previously given function between xmin[] and xmax[]
void SetFunction(Function &f, unsigned int dim)
set integration function using a generic function implementing the operator()(double *x) The dimensio...
User Class for performing numerical integration of a function in one dimension.
Definition Integrator.h:98
void SetFunction(Function &f)
method to set the a generic integration function
Definition Integrator.h:492
double Integral(Function &f, double a, double b)
evaluate the Integral of a function f over the defined interval (a,b)
Definition Integrator.h:499
Template class to wrap any member function of a class taking a double and returning a double in a 1D ...
const_iterator begin() const
const_iterator end() const
A pseudo container class which is a generator of indices.
Definition TSeq.hxx:67
This class provides a simple interface to execute the same task multiple times in parallel threads,...
Type
enumeration specifying the integration types.
@ kDEFAULT
default type specified in the static options
Double_t y[n]
Definition legend1.C:17
Double_t x[n]
Definition legend1.C:17
const Int_t n
Definition legend1.C:16
TFitResultPtr Fit(FitObject *h1, TF1 *f1, Foption_t &option, const ROOT::Math::MinimizerOptions &moption, const char *goption, ROOT::Fit::DataRange &range)
Definition HFitImpl.cxx:133
ROOT::Math::IParamMultiGradFunction IGradModelFunction
Definition FitUtil.h:65
ROOT::Math::IParamMultiFunction IModelFunction
Definition FitUtil.h:64
double EvaluatePoissonBinPdf(const IModelFunction &func, const BinData &data, const double *x, unsigned int ipoint, double *g=nullptr, double *h=nullptr, bool hasGrad=false, bool fullHessian=false)
evaluate the pdf contribution to the Poisson LogL given a model function and the BinPoint data.
Definition FitUtil.cxx:1297
void EvaluatePoissonLogLGradient(const IModelFunction &func, const BinData &data, const double *p, double *grad, unsigned int &nPoints, ::ROOT::EExecutionPolicy executionPolicy=::ROOT::EExecutionPolicy::kSequential, unsigned nChunks=0)
evaluate the Poisson LogL given a model function and the data at the point p.
double EvaluateChi2Residual(const IModelFunction &func, const BinData &data, const double *p, unsigned int ipoint, double *g=nullptr, double *h=nullptr, bool hasGrad=false, bool fullHessian=false)
evaluate the residual contribution to the Chi2 given a model function and the BinPoint data and if th...
Definition FitUtil.cxx:545
double EvaluatePoissonLogL(const IModelFunction &func, const BinData &data, const double *p, int iWeight, bool extended, unsigned int &nPoints, ::ROOT::EExecutionPolicy executionPolicy, unsigned nChunks=0)
evaluate the Poisson LogL given a model function and the data at the point p.
double EvaluateChi2Effective(const IModelFunction &func, const BinData &data, const double *x, unsigned int &nPoints)
evaluate the effective Chi2 given a model function and the data at the point x.
Definition FitUtil.cxx:424
void EvaluateLogLGradient(const IModelFunction &func, const UnBinData &data, const double *p, double *grad, unsigned int &nPoints, ::ROOT::EExecutionPolicy executionPolicy=::ROOT::EExecutionPolicy::kSequential, unsigned nChunks=0)
evaluate the LogL gradient given a model function and the data at the point p.
double EvaluatePdf(const IModelFunction &func, const UnBinData &data, const double *p, unsigned int ipoint, double *g=nullptr, double *h=nullptr, bool hasGrad=false, bool fullHessian=false)
evaluate the pdf contribution to the LogL given a model function and the BinPoint data.
Definition FitUtil.cxx:891
unsigned setAutomaticChunking(unsigned nEvents)
Definition FitUtil.cxx:1841
double EvaluateLogL(const IModelFunction &func, const UnBinData &data, const double *p, int iWeight, bool extended, unsigned int &nPoints, ::ROOT::EExecutionPolicy executionPolicy, unsigned nChunks=0)
evaluate the LogL given a model function and the data at the point x.
double EvaluateChi2(const IModelFunction &func, const BinData &data, const double *p, unsigned int &nPoints, ::ROOT::EExecutionPolicy executionPolicy, unsigned nChunks=0)
Chi2 Functions.
Definition FitUtil.cxx:226
void EvaluateChi2Gradient(const IModelFunction &func, const BinData &data, const double *p, double *grad, unsigned int &nPoints, ::ROOT::EExecutionPolicy executionPolicy=::ROOT::EExecutionPolicy::kSequential, unsigned nChunks=0)
evaluate the Chi2 gradient given a model function and the data at the point p.
T EvalLog(T x)
safe evaluation of log(x) with a protections against negative or zero argument to the log smooth line...
Definition Util.h:64
tbb::task_arena is an alias of tbb::interface7::task_arena, which doesn't allow to forward declare tb...
Double_t Double_v
Definition Types.h:55
DataOptions : simple structure holding the options on how the data are filled.
Definition DataOptions.h:28
static double EvalLogL(const IModelFunctionTempl< double > &func, const UnBinData &data, const double *p, int iWeight, bool extended, unsigned int &nPoints, ::ROOT::EExecutionPolicy executionPolicy, unsigned nChunks=0)
Definition FitUtil.h:1424
static double EvalChi2Effective(const IModelFunctionTempl< double > &func, const BinData &data, const double *p, unsigned int &nPoints)
Definition FitUtil.h:1438
static void EvalLogLGradient(const IModelFunctionTempl< double > &func, const UnBinData &data, const double *p, double *g, unsigned int &nPoints, ::ROOT::EExecutionPolicy executionPolicy=::ROOT::EExecutionPolicy::kSequential, unsigned nChunks=0)
Definition FitUtil.h:1475
static void EvalChi2Gradient(const IModelFunctionTempl< double > &func, const BinData &data, const double *p, double *g, unsigned int &nPoints, ::ROOT::EExecutionPolicy executionPolicy=::ROOT::EExecutionPolicy::kSequential, unsigned nChunks=0)
Definition FitUtil.h:1442
static double EvalPdf(const IModelFunctionTempl< double > &func, const UnBinData &data, const double *p, unsigned int i, double *g, double *h, bool hasGrad, bool fullHessian)
Definition FitUtil.h:1462
static double EvalChi2(const IModelFunction &func, const BinData &data, const double *p, unsigned int &nPoints, ::ROOT::EExecutionPolicy executionPolicy, unsigned nChunks=0)
Definition FitUtil.h:1410
static double EvalPoissonBinPdf(const IModelFunctionTempl< double > &func, const BinData &data, const double *p, unsigned int i, double *g, double *h, bool hasGrad, bool fullHessian)
evaluate the pdf (Poisson) contribution to the logl (return actually log of pdf) and its gradient
Definition FitUtil.h:1458
static void EvalPoissonLogLGradient(const IModelFunctionTempl< double > &func, const BinData &data, const double *p, double *g, unsigned int &nPoints, ::ROOT::EExecutionPolicy executionPolicy=::ROOT::EExecutionPolicy::kSequential, unsigned nChunks=0)
Definition FitUtil.h:1467
static double EvalPoissonLogL(const IModelFunctionTempl< double > &func, const BinData &data, const double *p, int iWeight, bool extended, unsigned int &nPoints, ::ROOT::EExecutionPolicy executionPolicy, unsigned nChunks=0)
Definition FitUtil.h:1431
static double EvalChi2Residual(const IModelFunctionTempl< double > &func, const BinData &data, const double *p, unsigned int i, double *g, double *h, bool hasGrad, bool fullHessian)
Definition FitUtil.h:1450
TMarker m
Definition textangle.C:8
TLine l
Definition textangle.C:4