35 ClassImp(RooChebychev);
39 static inline double fast_fma(
40 const double x,
const double y,
const double z) noexcept
42 #if defined(FP_FAST_FMA) // check if std::fma has fast hardware implementation
43 return std::fma(x, y, z);
44 #else // defined(FP_FAST_FMA)
46 #if defined(__clang__)
47 #pragma STDC FP_CONTRACT ON // hint clang that using an FMA is okay here
48 #endif // defined(__clang__)
50 #endif // defined(FP_FAST_FMA)
54 enum class Kind : int { First = 1, Second = 2 };
61 template <
typename T, Kind KIND>
62 class ChebychevIterator {
70 constexpr ChebychevIterator() =
default;
72 ChebychevIterator(
const ChebychevIterator &) =
default;
74 ChebychevIterator(ChebychevIterator &&) =
default;
76 constexpr ChebychevIterator(
const T &x)
77 : _curr(static_cast<int>(KIND) * x), _twox(2 * x)
81 ChebychevIterator &operator=(
const ChebychevIterator &) =
default;
83 ChebychevIterator &operator=(ChebychevIterator &&) =
default;
86 constexpr
inline T operator*() const noexcept {
return _last; }
88 constexpr
inline T lookahead() const noexcept {
return _curr; }
90 inline ChebychevIterator &operator++() noexcept
93 T newval = _twox*_curr -_last;
99 inline ChebychevIterator operator++(
int) noexcept
101 ChebychevIterator retVal(*
this);
110 RooChebychev::RooChebychev() : _refRangeName(0)
117 RooChebychev::RooChebychev(
const char* name,
const char* title,
118 RooAbsReal& x,
const RooArgList& coefList):
119 RooAbsPdf(name, title),
120 _x(
"x",
"Dependent", this, x),
121 _coefList(
"coefficients",
"List of coefficients",this),
124 for (
const auto coef : coefList) {
125 if (!dynamic_cast<RooAbsReal*>(coef)) {
126 coutE(InputArguments) <<
"RooChebychev::ctor(" << GetName() <<
127 ") ERROR: coefficient " << coef->GetName() <<
128 " is not of type RooAbsReal" << std::endl ;
129 throw std::invalid_argument(
"Wrong input arguments for RooChebychev");
131 _coefList.add(*coef) ;
137 RooChebychev::RooChebychev(
const RooChebychev& other,
const char* name) :
138 RooAbsPdf(other, name),
139 _x(
"x", this, other._x),
140 _coefList(
"coefList",this,other._coefList),
141 _refRangeName(other._refRangeName)
147 void RooChebychev::selectNormalizationRange(
const char* rangeName, Bool_t force)
149 if (rangeName && (force || !_refRangeName)) {
150 _refRangeName = (TNamed*) RooNameReg::instance().constPtr(rangeName) ;
159 Double_t RooChebychev::evaluate()
const
164 const Double_t xmax = _x.max(_refRangeName?_refRangeName->GetName():0);
165 const Double_t xmin = _x.min(_refRangeName?_refRangeName->GetName():0);
167 const Double_t x = (_x - 0.5 * (xmax + xmin)) / (0.5 * (xmax - xmin));
169 using size_type =
typename RooListProxy::Storage_t::size_type;
170 const size_type iend = _coefList.size();
173 ChebychevIterator<double, Kind::First> chit(x);
175 for (size_type i = 0; iend != i; ++i, ++chit) {
176 auto c =
static_cast<const RooAbsReal &
>(_coefList[i]).getVal();
189 void compute(
size_t batchSize,
double xmax,
double xmin,
190 double * __restrict output,
191 const double * __restrict
const xData,
192 const RooListProxy& _coefList)
194 constexpr
size_t block = 128;
195 const size_t nCoef = _coefList.size();
196 double prev[block][2], X[block];
198 for (
size_t i=0; i<batchSize; i+=block) {
199 size_t stop = (i+block >= batchSize) ? batchSize-i : block;
203 for (
size_t j=0; j<stop; j++) {
204 prev[j][0] = output[i+j] = 1.0;
205 prev[j][1] = X[j] = (xData[i+j] -0.5*(xmax + xmin)) / (0.5*(xmax - xmin));
208 for (
size_t k=0; k<nCoef; k++) {
209 const double coef =
static_cast<const RooAbsReal &
>(_coefList[k]).getVal();
210 for (
size_t j=0; j<stop; j++) {
211 output[i+j] += prev[j][1]*coef;
214 const double next = 2*X[j]*prev[j][1] -prev[j][0];
215 prev[j][0] = prev[j][1];
224 RooSpan<double> RooChebychev::evaluateBatch(std::size_t begin, std::size_t batchSize)
const {
225 auto xData = _x.getValBatch(begin, batchSize);
230 batchSize = xData.size();
231 auto output = _batchData.makeWritableBatchUnInit(begin, batchSize);
232 const Double_t xmax = _x.max(_refRangeName?_refRangeName->GetName() :
nullptr);
233 const Double_t xmin = _x.min(_refRangeName?_refRangeName->GetName() :
nullptr);
234 compute(batchSize, xmax, xmin, output.data(), xData.data(), _coefList);
239 Int_t RooChebychev::getAnalyticalIntegral(RooArgSet& allVars, RooArgSet& analVars,
const char* )
const
241 if (matchArgs(allVars, analVars, _x))
return 1;
247 Double_t RooChebychev::analyticalIntegral(Int_t code,
const char* rangeName)
const
249 assert(1 == code); (void)code;
251 const Double_t xmax = _x.max(_refRangeName?_refRangeName->GetName():0);
252 const Double_t xmin = _x.min(_refRangeName?_refRangeName->GetName():0);
253 const Double_t halfrange = .5 * (xmax - xmin), mid = .5 * (xmax + xmin);
255 const Double_t b = (_x.max(rangeName) - mid) / halfrange;
256 const Double_t a = (_x.min(rangeName) - mid) / halfrange;
260 return halfrange * evalAnaInt(a, b);
265 Double_t RooChebychev::evalAnaInt(
const Double_t a,
const Double_t b)
const
272 using size_type =
typename RooListProxy::Storage_t::size_type;
273 const size_type iend = _coefList.size();
277 const double c =
static_cast<const RooAbsReal &
>(_coefList[0]).getVal();
278 sum = fast_fma(0.5 * (b + a) * (b - a), c, sum);
281 ChebychevIterator<double, Kind::First> bit(b), ait(a);
284 for (size_type i = 1; iend != i; ++i) {
286 const double c =
static_cast<const RooAbsReal &
>(_coefList[i]).getVal();
287 const double term2 = (*bit - *ait) / nminus1;
288 ++bit, ++ait, ++nminus1;
289 const double term1 = (bit.lookahead() - ait.lookahead()) / (nminus1 + 1.);
290 const double intTn = 0.5 * (term1 - term2);
291 sum = fast_fma(intTn, c, sum);