Project
Loading...
Searching...
No Matches
MultivariatePolynomialHelper.h
Go to the documentation of this file.
1// Copyright 2019-2020 CERN and copyright holders of ALICE O2.
2// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders.
3// All rights not expressly granted are reserved.
4//
5// This software is distributed under the terms of the GNU General Public
6// License v3 (GPL Version 3), copied verbatim in the file "COPYING".
7//
8// In applying this license CERN does not waive the privileges and immunities
9// granted to it by virtue of its status as an Intergovernmental Organization
10// or submit itself to any jurisdiction.
11
14
15#ifndef ALICEO2_TPC_MULTIVARIATEPOLYNOMIALHELPER
16#define ALICEO2_TPC_MULTIVARIATEPOLYNOMIALHELPER
17
18#include "GPUCommonDef.h"
19
20#if !defined(GPUCA_GPUCODE)
21#include <vector>
22#include <string>
23#include <cassert>
24#if !defined(GPUCA_NO_FMT)
25#include <fmt/format.h>
26#endif
27#endif
28
29class TLinearFitter;
30
31namespace o2::gpu
32{
33
34#if !defined(GPUCA_GPUCODE)
35
38
44 MultivariatePolynomialContainer(const uint32_t dim, const uint32_t degree, const uint32_t nParameters, const float params[/* nParameters*/], const bool interactionOnly) : mDim{dim}, mDegree{degree}, mParams{params, params + nParameters}, mInteractionOnly{interactionOnly} {};
45
48
49 const uint32_t mDim{};
50 const uint32_t mDegree{};
51 const std::vector<float> mParams{};
52 const bool mInteractionOnly{};
53};
54#endif
55
58{
59 public:
63 template <uint32_t Degree, uint32_t Dim>
64 GPUd() static constexpr uint32_t getNParametersAllTerms()
65 {
66 if constexpr (Degree == 0) {
67 return binomialCoeff<Dim - 1, 0>();
68 } else {
69 return binomialCoeff<Dim - 1 + Degree, Degree>() + getNParametersAllTerms<Degree - 1, Dim>();
70 }
71 }
72
76 GPUd() static constexpr uint32_t getNParametersAllTerms(uint32_t degree, uint32_t dim)
77 {
78 if (degree == 0) {
79 return binomialCoeff(dim - 1, 0);
80 } else {
81 return binomialCoeff(dim - 1 + degree, degree) + getNParametersAllTerms(degree - 1, dim);
82 }
83 }
84
86 template <uint32_t Degree, uint32_t Dim>
87 GPUd() static constexpr uint32_t getNParametersInteractionOnly()
88 {
89 if constexpr (Degree == 0) {
90 return binomialCoeff<Dim - 1, 0>();
91 } else {
92 return binomialCoeff<Dim, Degree>() + getNParametersInteractionOnly<Degree - 1, Dim>();
93 }
94 }
95
97 GPUd() static constexpr uint32_t getNParametersInteractionOnly(uint32_t degree, uint32_t dim)
98 {
99 if (degree == 0) {
100 return binomialCoeff(dim - 1, 0);
101 } else {
102 return binomialCoeff(dim, degree) + getNParametersInteractionOnly(degree - 1, dim);
103 }
104 }
105
106 template <uint32_t Degree, uint32_t Dim, bool InteractionOnly>
107 GPUd() static constexpr uint32_t getNParameters()
108 {
109 if constexpr (InteractionOnly) {
110 return getNParametersInteractionOnly<Degree, Dim>();
111 } else {
112 return getNParametersAllTerms<Degree, Dim>();
113 }
114 }
115
116 GPUd() static constexpr uint32_t getNParameters(uint32_t degree, uint32_t dim, bool interactionOnly)
117 {
118 if (interactionOnly) {
119 return getNParametersInteractionOnly(degree, dim);
120 } else {
121 return getNParametersAllTerms(degree, dim);
122 }
123 }
124
125 private:
128 template <uint32_t N>
129 GPUd() static constexpr uint32_t factorial()
130 {
131 if constexpr (N == 0 || N == 1) {
132 return 1;
133 } else {
134 return N * factorial<N - 1>();
135 }
136 }
137
140 GPUd() static constexpr uint32_t factorial(uint32_t n) { return n == 0 || n == 1 ? 1 : n * factorial(n - 1); }
141
144 template <uint32_t N, uint32_t K>
145 GPUd() static constexpr uint32_t binomialCoeff()
146 {
147 return factorial<N>() / (factorial<K>() * factorial<N - K>());
148 }
149
152 GPUd() static constexpr uint32_t binomialCoeff(uint32_t n, uint32_t k)
153 {
154 return factorial(n) / (factorial(k) * factorial(n - k));
155 }
156};
157
163template <uint32_t Dim, uint32_t Degree, bool InteractionOnly>
165{
166 static constexpr uint16_t FMaxdim = 10;
167 static constexpr uint16_t FMaxdegree = 9;
168
169#if !defined(GPUCA_GPUCODE)
170 static_assert(Dim <= MultivariatePolynomialHelper<Dim, Degree, InteractionOnly>::FMaxdim && Degree <= MultivariatePolynomialHelper<Dim, Degree, InteractionOnly>::FMaxdegree, "Max. number of dimensions or degrees exceeded!");
171#endif
172
173 public:
177 GPUd() static constexpr float evalPol(GPUgeneric() const float par[/*number of parameters*/], const float x[/*number of dimensions*/])
178 {
179 return par[0] + loopDegrees<1>(par, x);
180 }
181
183 GPUd() static constexpr uint32_t getDim() { return Dim; }
184
186 GPUd() static constexpr uint32_t getDegree() { return Degree; }
187
189 GPUd() static constexpr bool isInteractionOnly() { return InteractionOnly; }
190
191 private:
193 GPUd() static constexpr uint32_t pow10(const uint32_t n) { return n == 0 ? 1 : 10 * pow10(n - 1); }
194
195 template <uint32_t N>
196 GPUd() static constexpr uint32_t pow10()
197 {
198 if constexpr (N == 0) {
199 return 1;
200 } else {
201 return 10 * pow10<N - 1>();
202 }
203 }
204
206 GPUd() static constexpr uint32_t mod10(const uint32_t a, const uint32_t b) { return (a / b) % 10; }
207
208 template <uint32_t A, uint32_t B>
209 GPUd() static constexpr uint32_t mod10()
210 {
211 return (A / B) % 10;
212 }
213
215 GPUd() static constexpr uint32_t resetIndices(const uint32_t degreePol, const uint32_t pos, const uint32_t leftDigit, const uint32_t iter, const uint32_t refDigit);
216
217 template <uint32_t DegreePol, uint32_t Pos, uint32_t DigitPos>
218 GPUd() static constexpr uint32_t getNewPos();
219
223 template <uint32_t DegreePol, uint32_t Pos>
224 GPUd() static constexpr float prodTerm(const float x[]);
225
227 template <uint32_t DegreePol, uint32_t posNew>
228 static constexpr bool checkInteraction();
229
234 template <uint32_t DegreePol, uint32_t Pos, uint32_t Index>
235 GPUd() static constexpr float sumTerms(GPUgeneric() const float par[], const float x[]);
236
241 template <uint32_t DegreePol>
242 GPUd() static constexpr float loopDegrees(GPUgeneric() const float par[], const float x[]);
243};
244
245#if !defined(GPUCA_GPUCODE) // disable specialized class for GPU, as it should be only used for the fitting!
247template <>
249{
250 public:
254 MultivariatePolynomialHelper(const uint32_t nDim, const uint32_t degree, const bool interactionOnly) : mDim{nDim}, mDegree{degree}, mInteractionOnly{interactionOnly} { assert(mDegree <= FMaxdegree); };
255
258
261
263 void print() const;
264
266 std::string getFormula() const;
267
269 std::string getTLinearFitterFormula() const;
270
272 std::vector<std::string> getTerms() const;
273
275 TLinearFitter getTLinearFitter() const;
276
284 static std::vector<float> fit(TLinearFitter& fitter, std::vector<double>& x, std::vector<double>& y, std::vector<double>& error, const bool clearPoints);
285
292 std::vector<float> fit(std::vector<double>& x, std::vector<double>& y, std::vector<double>& error, const bool clearPoints) const;
293
297 float evalPol(const float par[/*number of parameters*/], const float x[/*number of dimensions*/]) const
298 {
299 return evalPol(par, x, mDegree, mDim, mInteractionOnly);
300 }
301
303 float evalPol(const float par[], const float x[], const uint32_t degree, const uint32_t dim, const bool interactionOnly) const;
304
306 uint32_t getDim() const { return mDim; }
307
309 uint32_t getDegree() const { return mDegree; }
310
312 bool isInteractionOnly() const { return mInteractionOnly; }
313
314 protected:
315 uint32_t mDim{};
316 uint32_t mDegree{};
317 bool mInteractionOnly{};
318
319 private:
320 static constexpr uint16_t FMaxdegree = 9;
321
323 template <class Type>
324 Type combination_with_repetiton(const uint32_t degree, const uint32_t dim, const float par[], int32_t& indexPar, const float x[], const bool interactionOnly) const;
325};
326#endif
327
328//=================================================================================
329//============================ inline implementations =============================
330//=================================================================================
331
332template <uint32_t Dim, uint32_t Degree, bool InteractionOnly>
333GPUd() constexpr uint32_t MultivariatePolynomialHelper<Dim, Degree, InteractionOnly>::resetIndices(const uint32_t degreePol, const uint32_t pos, const uint32_t leftDigit, const uint32_t iter, const uint32_t refDigit)
334{
335 if (iter <= degreePol) {
336 const int32_t powTmp = pow10(leftDigit);
337 const int32_t rightDigit = mod10(pos, powTmp);
338 const int32_t posTmp = pos - (rightDigit - refDigit) * powTmp;
339 return resetIndices(degreePol, posTmp, leftDigit - 1, iter + 1, refDigit);
340 }
341 return pos;
342}
343
344template <uint32_t Dim, uint32_t Degree, bool InteractionOnly>
345template <uint32_t DegreePol, uint32_t Pos, uint32_t DigitPos>
346GPUd() constexpr uint32_t MultivariatePolynomialHelper<Dim, Degree, InteractionOnly>::getNewPos()
347{
348 if constexpr (DegreePol > DigitPos) {
349 // check if digit of current position is at is max position
350 if constexpr (mod10<Pos, pow10<DigitPos>()>() == Dim) {
351 // increase digit of left position
352 constexpr uint32_t LeftDigit = DigitPos + 1;
353 constexpr uint32_t PowLeftDigit = pow10<LeftDigit>();
354 constexpr uint32_t PosTmp = Pos + PowLeftDigit;
355 constexpr uint32_t RefDigit = mod10<PosTmp, PowLeftDigit>();
356
357 // resetting digits to the right if digit exceeds number of dimensions
358 constexpr uint32_t PosReset = resetIndices(DegreePol, PosTmp, LeftDigit - 1, DegreePol - DigitPos, RefDigit);
359
360 // check next digit
361 return getNewPos<DegreePol, PosReset, DigitPos + 1>();
362 } else {
363 return getNewPos<DegreePol, Pos, DigitPos + 1>();
364 }
365 } else {
366 return Pos;
367 }
368}
369
370template <uint32_t Dim, uint32_t Degree, bool InteractionOnly>
371template <uint32_t DegreePol, uint32_t Pos>
372GPUd() constexpr float MultivariatePolynomialHelper<Dim, Degree, InteractionOnly>::prodTerm(const float x[])
373{
374 if constexpr (DegreePol > 0) {
375 // extract index of the dimension which is decoded in the digit
376 const uint32_t index = mod10<Pos, pow10<DegreePol - 1>()>();
377 return x[index] * prodTerm<DegreePol - 1, Pos>(x);
378 }
379 return 1;
380}
381
382template <uint32_t Dim, uint32_t Degree, bool InteractionOnly>
383template <uint32_t DegreePol, uint32_t posNew>
384constexpr bool MultivariatePolynomialHelper<Dim, Degree, InteractionOnly>::checkInteraction()
385{
386 if constexpr (DegreePol > 1) {
387 constexpr bool isInteraction = mod10<posNew, pow10<DegreePol - 1>()>() == mod10<posNew, pow10<DegreePol - 2>()>();
388 if constexpr (isInteraction) {
389 return true;
390 }
391 return checkInteraction<DegreePol - 1, posNew>();
392 }
393 return false;
394}
395
396template <uint32_t Dim, uint32_t Degree, bool InteractionOnly>
397template <uint32_t DegreePol, uint32_t Pos, uint32_t Index>
398GPUd() constexpr float MultivariatePolynomialHelper<Dim, Degree, InteractionOnly>::sumTerms(GPUgeneric() const float par[], const float x[])
399{
400 // checking if the current position is reasonable e.g. if the max dimension is x[4]: for Pos=15 -> x[1]*x[5] the position is set to 22 -> x[2]*x[2]
401 constexpr uint32_t PosNew = getNewPos<DegreePol, Pos, 0>();
402 if constexpr (mod10<PosNew, pow10<DegreePol>()>() != 1) {
403
404 // check if all digits in posNew are unequal: For interaction_only terms with x[Dim]*x[Dim]... etc. can be skipped
405 if constexpr (InteractionOnly && checkInteraction<DegreePol, PosNew>()) {
406 return sumTerms<DegreePol, PosNew + 1, Index>(par, x);
407 } else {
408 // sum up the term for corrent term and set posotion for next combination
409 return par[Index] * prodTerm<DegreePol, PosNew>(x) + sumTerms<DegreePol, PosNew + 1, Index + 1>(par, x);
410 }
411 }
412 return 0;
413}
414
415template <uint32_t Dim, uint32_t Degree, bool InteractionOnly>
416template <uint32_t DegreePol>
417GPUd() constexpr float MultivariatePolynomialHelper<Dim, Degree, InteractionOnly>::loopDegrees(GPUgeneric() const float par[], const float x[])
418{
419 if constexpr (DegreePol <= Degree) {
420 constexpr uint32_t index{getNParameters<DegreePol - 1, Dim, InteractionOnly>()}; // offset of the index for accessing the parameters
421 return sumTerms<DegreePol, 0, index>(par, x) + loopDegrees<DegreePol + 1>(par, x);
422 }
423 return 0;
424}
425
426} // namespace o2::gpu
427
428#endif
#define GPUgeneric()
uint16_t pos
Definition RawData.h:3
Definition A.h:16
Definition B.h:16
MultivariatePolynomialHelper(const uint32_t nDim, const uint32_t degree, const bool interactionOnly)
MultivariatePolynomialHelper()=default
default constructor
static std::vector< float > fit(TLinearFitter &fitter, std::vector< double > &x, std::vector< double > &y, std::vector< double > &error, const bool clearPoints)
std::vector< std::string > getTerms() const
std::vector< float > fit(std::vector< double > &x, std::vector< double > &y, std::vector< double > &error, const bool clearPoints) const
float evalPol(const float par[], const float x[], const uint32_t degree, const uint32_t dim, const bool interactionOnly) const
evalutes the polynomial
float evalPol(const float par[], const float x[]) const
void print() const
printing the formula of the polynomial
GPUd() static const expr uint32_t getDegree()
GPUd() static const expr float evalPol(GPUgeneric() const float par[]
GPUd() static const expr uint32_t getDim()
GPUd() static const expr bool isInteractionOnly()
Helper class for calculating the number of parameters for a multidimensional polynomial.
GPUd() static const expr uint32_t getNParametersAllTerms(uint32_t degree
GPUd() static const expr uint32_t getNParametersAllTerms()
GLdouble n
Definition glcorearb.h:1982
GLint GLenum GLint x
Definition glcorearb.h:403
GLuint index
Definition glcorearb.h:781
GLboolean GLboolean GLboolean b
Definition glcorearb.h:1233
GLenum const GLfloat * params
Definition glcorearb.h:272
GLboolean GLboolean GLboolean GLboolean a
Definition glcorearb.h:1233
Node par(int index)
Parameters.
simple struct to enable writing the MultivariatePolynomial to file
const uint32_t mDim
number of dimensions of the polynomial
const uint32_t mDegree
degree of the polynomials
MultivariatePolynomialContainer()=default
for ROOT I/O
const bool mInteractionOnly
consider only interaction terms
MultivariatePolynomialContainer(const uint32_t dim, const uint32_t degree, const uint32_t nParameters, const float params[], const bool interactionOnly)
const std::vector< float > mParams
parameters of the polynomial