Logo ROOT   6.18/05
Reference Guide
RooChebychev.cxx
Go to the documentation of this file.
1/*****************************************************************************
2 * Project: RooFit *
3 * Package: RooFitModels *
4 * @(#)root/roofit:$Id$
5 * Authors: *
6 * GR, Gerhard Raven, UC San Diego, Gerhard.Raven@slac.stanford.edu
7 * *
8 * Copyright (c) 2000-2005, Regents of the University of California *
9 * and Stanford University. All rights reserved. *
10 * *
11 * Redistribution and use in source and binary forms, *
12 * with or without modification, are permitted according to the terms *
13 * listed in LICENSE (http://roofit.sourceforge.net/license.txt) *
14 *****************************************************************************/
15
16/** \class RooChebychev
17 \ingroup Roofit
18
19Chebychev polynomial p.d.f. of the first kind.
20
21The coefficient that goes with \f$ T_0(x)=1 \f$ (i.e. the constant polynomial) is
22implicitly assumed to be 1, and the list of coefficients supplied by callers
23starts with the coefficient that goes with \f$ T_1(x)=x \f$ (i.e. the linear term).
24**/
25
26#include <cmath>
27#include <iostream>
28
29#include "RooFit.h"
30
31#include "Riostream.h"
32
33#include "RooChebychev.h"
34#include "RooAbsReal.h"
35#include "RooRealVar.h"
36#include "RooArgList.h"
37#include "RooNameReg.h"
38
39#include "TError.h"
40
42
43namespace { // anonymous namespace to hide implementation details
44/// use fast FMA if available, fall back to normal arithmetic if not
45static inline double fast_fma(
46 const double x, const double y, const double z) noexcept
47{
48#if defined(FP_FAST_FMA) // check if std::fma has fast hardware implementation
49 return std::fma(x, y, z);
50#else // defined(FP_FAST_FMA)
51 // std::fma might be slow, so use a more pedestrian implementation
52#if defined(__clang__)
53#pragma STDC FP_CONTRACT ON // hint clang that using an FMA is okay here
54#endif // defined(__clang__)
55 return (x * y) + z;
56#endif // defined(FP_FAST_FMA)
57}
58
59/// Chebychev polynomials of first or second kind
60enum class Kind : int { First = 1, Second = 2 };
61
62/** @brief ChebychevIterator evaluates increasing orders at given x
63 *
64 * @author Manuel Schiller <Manuel.Schiller@glasgow.ac.uk>
65 * @date 2019-03-24
66 */
67template <typename T, Kind KIND>
68class ChebychevIterator {
69private:
70 T _last = 1;
71 T _curr = 0;
72 T _twox = 0;
73
74public:
75 /// default constructor
76 constexpr ChebychevIterator() = default;
77 /// copy constructor
78 ChebychevIterator(const ChebychevIterator &) = default;
79 /// move constructor
80 ChebychevIterator(ChebychevIterator &&) = default;
81 /// construct from given x in [-1, 1]
82 constexpr ChebychevIterator(const T &x)
83 : _curr(static_cast<int>(KIND) * x), _twox(2 * x)
84 {}
85
86 /// (copy) assignment
87 ChebychevIterator &operator=(const ChebychevIterator &) = default;
88 /// move assignment
89 ChebychevIterator &operator=(ChebychevIterator &&) = default;
90
91 /// get value of Chebychev polynomial at current order
92 constexpr inline T operator*() const noexcept { return _last; }
93 // get value of Chebychev polynomial at (current + 1) order
94 constexpr inline T lookahead() const noexcept { return _curr; }
95 /// move on to next order, return reference to new value
96 inline ChebychevIterator &operator++() noexcept
97 {
98 T newval = fast_fma(_twox, _curr, -_last);
99 _last = _curr;
100 _curr = newval;
101 return *this;
102 }
103 /// move on to next order, return copy of new value
104 inline ChebychevIterator operator++(int) noexcept
105 {
106 ChebychevIterator retVal(*this);
107 operator++();
108 return retVal;
109 }
110};
111} // anonymous namespace
112
113////////////////////////////////////////////////////////////////////////////////
114
115RooChebychev::RooChebychev() : _refRangeName(0)
116{
117}
118
119////////////////////////////////////////////////////////////////////////////////
120/// Constructor
121
122RooChebychev::RooChebychev(const char* name, const char* title,
123 RooAbsReal& x, const RooArgList& coefList):
124 RooAbsPdf(name, title),
125 _x("x", "Dependent", this, x),
126 _coefList("coefficients","List of coefficients",this),
127 _refRangeName(0)
128{
129 TIterator* coefIter = coefList.createIterator() ;
130 RooAbsArg* coef ;
131 while((coef = (RooAbsArg*)coefIter->Next())) {
132 if (!dynamic_cast<RooAbsReal*>(coef)) {
133 std::cerr << "RooChebychev::ctor(" << GetName() <<
134 ") ERROR: coefficient " << coef->GetName() <<
135 " is not of type RooAbsReal" << std::endl ;
136 R__ASSERT(0) ;
137 }
138 _coefList.add(*coef) ;
139 }
140
141 delete coefIter ;
142}
143
144////////////////////////////////////////////////////////////////////////////////
145
146RooChebychev::RooChebychev(const RooChebychev& other, const char* name) :
147 RooAbsPdf(other, name),
148 _x("x", this, other._x),
149 _coefList("coefList",this,other._coefList),
150 _refRangeName(other._refRangeName)
151{
152}
153
154////////////////////////////////////////////////////////////////////////////////
155
156void RooChebychev::selectNormalizationRange(const char* rangeName, Bool_t force)
157{
158 if (rangeName && (force || !_refRangeName)) {
160 }
161 if (!rangeName) {
162 _refRangeName = 0 ;
163 }
164}
165
166////////////////////////////////////////////////////////////////////////////////
167
169{
170 // first bring the range of the variable _x to the normalised range [-1, 1]
171 // calculate sum_k c_k T_k(x) where x is given in the normalised range,
172 // c_0 = 1, and the higher coefficients are given in _coefList
175 // transform to range [-1, +1]
176 const Double_t x = (_x - 0.5 * (xmax + xmin)) / (0.5 * (xmax - xmin));
177 // extract current values of coefficients
178 using size_type = typename RooListProxy::Storage_t::size_type;
179 const size_type iend = _coefList.size();
180 double sum = 1.;
181 if (iend > 0) {
182 ChebychevIterator<double, Kind::First> chit(x);
183 ++chit;
184 for (size_type i = 0; iend != i; ++i, ++chit) {
185 auto c = static_cast<const RooAbsReal &>(_coefList[i]).getVal();
186 sum = fast_fma(*chit, c, sum);
187 }
188 }
189 return sum;
190}
191
192////////////////////////////////////////////////////////////////////////////////
193
194Int_t RooChebychev::getAnalyticalIntegral(RooArgSet& allVars, RooArgSet& analVars, const char* /* rangeName */) const
195{
196 if (matchArgs(allVars, analVars, _x)) return 1;
197 return 0;
198}
199
200////////////////////////////////////////////////////////////////////////////////
201
202Double_t RooChebychev::analyticalIntegral(Int_t code, const char* rangeName) const
203{
204 R__ASSERT(1 == code);
205
208 const Double_t halfrange = .5 * (xmax - xmin), mid = .5 * (xmax + xmin);
209 // the full range of the function is mapped to the normalised [-1, 1] range
210 const Double_t b = (_x.max(rangeName) - mid) / halfrange;
211 const Double_t a = (_x.min(rangeName) - mid) / halfrange;
212
213 // take care to multiply with the right factor to account for the mapping to
214 // normalised range [-1, 1]
215 return halfrange * evalAnaInt(a, b);
216}
217
218////////////////////////////////////////////////////////////////////////////////
219
221{
222 // coefficient for integral(T_0(x)) is 1 (implicit), integrate by hand
223 // T_0(x) and T_1(x), and use for n > 1: integral(T_n(x) dx) =
224 // (T_n+1(x) / (n + 1) - T_n-1(x) / (n - 1)) / 2
225 double sum = b - a; // integrate T_0(x) by hand
226
227 using size_type = typename RooListProxy::Storage_t::size_type;
228 const size_type iend = _coefList.size();
229 if (iend > 0) {
230 {
231 // integrate T_1(x) by hand...
232 const double c = static_cast<const RooAbsReal &>(_coefList[0]).getVal();
233 sum = fast_fma(0.5 * (b + a) * (b - a), c, sum);
234 }
235 if (1 < iend) {
236 ChebychevIterator<double, Kind::First> bit(b), ait(a);
237 ++bit, ++ait;
238 double nminus1 = 1.;
239 for (size_type i = 1; iend != i; ++i) {
240 // integrate using recursion relation
241 const double c = static_cast<const RooAbsReal &>(_coefList[i]).getVal();
242 const double term2 = (*bit - *ait) / nminus1;
243 ++bit, ++ait, ++nminus1;
244 const double term1 = (bit.lookahead() - ait.lookahead()) / (nminus1 + 1.);
245 const double intTn = 0.5 * (term1 - term2);
246 sum = fast_fma(intTn, c, sum);
247 }
248 }
249 }
250 return sum;
251}
#define b(i)
Definition: RSha256.hxx:100
#define c(i)
Definition: RSha256.hxx:101
int Int_t
Definition: RtypesCore.h:41
bool Bool_t
Definition: RtypesCore.h:59
double Double_t
Definition: RtypesCore.h:55
#define ClassImp(name)
Definition: Rtypes.h:365
#define R__ASSERT(e)
Definition: TError.h:96
char name[80]
Definition: TGX11.cxx:109
float xmin
Definition: THbookFile.cxx:93
float xmax
Definition: THbookFile.cxx:93
Binding & operator=(OUT(*fun)(void))
TTime operator*(const TTime &t1, const TTime &t2)
Definition: TTime.h:85
RooAbsArg is the common abstract base class for objects that represent a value (of arbitrary type) an...
Definition: RooAbsArg.h:70
Storage_t::size_type size() const
TIterator * createIterator(Bool_t dir=kIterForward) const R__SUGGEST_ALTERNATIVE("begin()
TIterator-style iteration over contained elements.
RooAbsReal is the common abstract base class for objects that represent a real value and implements f...
Definition: RooAbsReal.h:53
Bool_t matchArgs(const RooArgSet &allDeps, RooArgSet &numDeps, const RooArgProxy &a) const
Utility function for use in getAnalyticalIntegral().
Double_t getVal(const RooArgSet *normalisationSet=nullptr) const
Evaluate object.
Definition: RooAbsReal.h:81
RooArgList is a container object that can hold multiple RooAbsArg objects.
Definition: RooArgList.h:21
RooArgSet is a container object that can hold multiple RooAbsArg objects.
Definition: RooArgSet.h:28
Chebychev polynomial p.d.f.
Definition: RooChebychev.h:25
virtual void selectNormalizationRange(const char *rangeName=0, Bool_t force=kFALSE)
Interface function to force use of a given normalization range to interpret function value.
RooRealProxy _x
Definition: RooChebychev.h:43
Int_t getAnalyticalIntegral(RooArgSet &allVars, RooArgSet &analVars, const char *rangeName=0) const
Interface function getAnalyticalIntergral advertises the analytical integrals that are supported.
TNamed * _refRangeName
Definition: RooChebychev.h:45
RooListProxy _coefList
Definition: RooChebychev.h:44
Double_t evaluate() const
Evaluate this PDF / function / constant. Needs to be overridden by all derived classes.
Double_t evalAnaInt(const Double_t a, const Double_t b) const
Double_t analyticalIntegral(Int_t code, const char *rangeName=0) const
Implements the actual analytical integral(s) advertised by getAnalyticalIntegral.
virtual Bool_t add(const RooAbsArg &var, Bool_t silent=kFALSE)
Reimplementation of standard RooArgList::add()
const TNamed * constPtr(const char *stringPtr)
Return a unique TNamed pointer for given C++ string.
Definition: RooNameReg.cxx:72
static RooNameReg & instance()
Return reference to singleton instance.
Definition: RooNameReg.cxx:52
Double_t min(const char *rname=0) const
Definition: RooRealProxy.h:56
Double_t max(const char *rname=0) const
Definition: RooRealProxy.h:57
Iterator abstract base class.
Definition: TIterator.h:30
virtual TObject * Next()=0
The TNamed class is the base class for all named ROOT classes.
Definition: TNamed.h:29
virtual const char * GetName() const
Returns name of object.
Definition: TNamed.h:47
Double_t y[n]
Definition: legend1.C:17
Double_t x[n]
Definition: legend1.C:17
double T(double x)
Definition: ChebyshevPol.h:34
auto * a
Definition: textangle.C:12
static long int sum(long int i)
Definition: Factory.cxx:2258