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 GPUd() static constexpr uint32_t getNParametersAllTerms(const uint32_t degree, const uint32_t dim) { return (degree == 0) ? binomialCoeff(dim - 1, 0) : binomialCoeff(dim - 1 + degree, degree) + getNParametersAllTerms(degree - 1, dim); }
64
66 GPUd() static constexpr uint32_t getNParametersInteractionOnly(const uint32_t degree, const uint32_t dim) { return (degree == 0) ? binomialCoeff(dim - 1, 0) : binomialCoeff(dim, degree) + getNParametersInteractionOnly(degree - 1, dim); }
67
68 GPUd() static constexpr uint32_t getNParameters(const uint32_t degree, const uint32_t dim, const bool interactionOnly)
69 {
70 if (interactionOnly) {
71 return getNParametersInteractionOnly(degree, dim);
72 } else {
73 return getNParametersAllTerms(degree, dim);
74 }
75 }
76
77 private:
80 GPUd() static constexpr uint32_t factorial(const uint32_t n) { return (n == 0) || (n == 1) ? 1 : n * factorial(n - 1); }
81
84 GPUd() static constexpr uint32_t binomialCoeff(const uint32_t n, const uint32_t k) { return factorial(n) / (factorial(k) * factorial(n - k)); }
85};
86
92template <uint32_t Dim, uint32_t Degree, bool InteractionOnly>
94{
95 static constexpr uint16_t FMaxdim = 10;
96 static constexpr uint16_t FMaxdegree = 9;
97
98#if !defined(GPUCA_GPUCODE)
99 static_assert(Dim <= MultivariatePolynomialHelper<Dim, Degree, InteractionOnly>::FMaxdim && Degree <= MultivariatePolynomialHelper<Dim, Degree, InteractionOnly>::FMaxdegree, "Max. number of dimensions or degrees exceeded!");
100#endif
101
102 public:
106 GPUd() static constexpr float evalPol(GPUgeneric() const float par[/*number of parameters*/], const float x[/*number of dimensions*/]) { return par[0] + loopDegrees<1>(par, x); }
107
109 GPUd() static constexpr uint32_t getDim() { return Dim; }
110
112 GPUd() static constexpr uint32_t getDegree() { return Degree; }
113
115 GPUd() static constexpr bool isInteractionOnly() { return InteractionOnly; }
116
117 private:
119 GPUd() static constexpr uint32_t pow10(const uint32_t n) { return n == 0 ? 1 : 10 * pow10(n - 1); }
120
122 GPUd() static constexpr uint32_t mod10(const uint32_t a, const uint32_t b) { return (a / b) % 10; }
123
125 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);
126
127 GPUd() static constexpr uint32_t getNewPos(const uint32_t degreePol, const uint32_t pos, const uint32_t digitPos);
128
132 template <uint32_t DegreePol>
133 GPUd() static constexpr float prodTerm(const float x[], const uint32_t pos);
134
136 template <uint32_t DegreePol, uint32_t posNew>
137 static constexpr bool checkInteraction();
138
143 template <uint32_t DegreePol, uint32_t Pos, uint32_t Index>
144 GPUd() static constexpr float sumTerms(GPUgeneric() const float par[], const float x[]);
145
150 template <uint32_t DegreePol>
151 GPUd() static constexpr float loopDegrees(GPUgeneric() const float par[], const float x[]);
152};
153
154#if !defined(GPUCA_GPUCODE) // disable specialized class for GPU, as it should be only used for the fitting!
156template <>
158{
159 public:
163 MultivariatePolynomialHelper(const uint32_t nDim, const uint32_t degree, const bool interactionOnly) : mDim{nDim}, mDegree{degree}, mInteractionOnly{interactionOnly} { assert(mDegree <= FMaxdegree); };
164
167
170
172 void print() const;
173
175 std::string getFormula() const;
176
178 std::string getTLinearFitterFormula() const;
179
181 std::vector<std::string> getTerms() const;
182
184 TLinearFitter getTLinearFitter() const;
185
193 static std::vector<float> fit(TLinearFitter& fitter, std::vector<double>& x, std::vector<double>& y, std::vector<double>& error, const bool clearPoints);
194
201 std::vector<float> fit(std::vector<double>& x, std::vector<double>& y, std::vector<double>& error, const bool clearPoints) const;
202
206 float evalPol(const float par[/*number of parameters*/], const float x[/*number of dimensions*/]) const { return evalPol(par, x, mDegree, mDim, mInteractionOnly); }
207
209 float evalPol(const float par[], const float x[], const uint32_t degree, const uint32_t dim, const bool interactionOnly) const;
210
212 uint32_t getDim() const { return mDim; }
213
215 uint32_t getDegree() const { return mDegree; }
216
218 bool isInteractionOnly() const { return mInteractionOnly; }
219
220 protected:
221 uint32_t mDim{};
222 uint32_t mDegree{};
223 bool mInteractionOnly{};
224
225 private:
226 static constexpr uint16_t FMaxdegree = 9;
227
229 template <class Type>
230 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;
231};
232#endif
233
234//=================================================================================
235//============================ inline implementations =============================
236//=================================================================================
237
238template <uint32_t Dim, uint32_t Degree, bool InteractionOnly>
239GPUd() 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)
240{
241 if (iter <= degreePol) {
242 const int32_t powTmp = pow10(leftDigit);
243 const int32_t rightDigit = mod10(pos, powTmp);
244 const int32_t posTmp = pos - (rightDigit - refDigit) * powTmp;
245 return resetIndices(degreePol, posTmp, leftDigit - 1, iter + 1, refDigit);
246 }
247 return pos;
248}
249
250template <uint32_t Dim, uint32_t Degree, bool InteractionOnly>
251GPUd() constexpr uint32_t MultivariatePolynomialHelper<Dim, Degree, InteractionOnly>::getNewPos(const uint32_t degreePol, const uint32_t pos, const uint32_t digitPos)
252{
253 if (degreePol > digitPos) {
254 // check if digit of current position is at is max position
255 if (mod10(pos, pow10(digitPos)) == Dim) {
256 // increase digit of left position
257 const uint32_t leftDigit = digitPos + 1;
258 const uint32_t posTmp = pos + pow10(leftDigit);
259 const uint32_t refDigit = mod10(posTmp, pow10(digitPos + 1));
260
261 // resetting digits to the right if digit exceeds number of dimensions
262 const uint32_t posReset = resetIndices(degreePol, posTmp, leftDigit - 1, degreePol - digitPos, refDigit);
263
264 // check next digit
265 return getNewPos(degreePol, posReset, digitPos + 1);
266 }
267 return getNewPos(degreePol, pos, digitPos + 1);
268 }
269 return pos;
270}
271
272template <uint32_t Dim, uint32_t Degree, bool InteractionOnly>
273template <uint32_t DegreePol>
274GPUd() constexpr float MultivariatePolynomialHelper<Dim, Degree, InteractionOnly>::prodTerm(const float x[], const uint32_t pos)
275{
276 if constexpr (DegreePol > 0) {
277 // extract index of the dimension which is decoded in the digit
278 const uint32_t index = mod10(pos, pow10(DegreePol - 1));
279 return x[index] * prodTerm<DegreePol - 1>(x, pos);
280 }
281 return 1;
282}
283
284template <uint32_t Dim, uint32_t Degree, bool InteractionOnly>
285template <uint32_t DegreePol, uint32_t posNew>
286constexpr bool MultivariatePolynomialHelper<Dim, Degree, InteractionOnly>::checkInteraction()
287{
288 if constexpr (DegreePol > 1) {
289 constexpr bool isInteraction = mod10(posNew, pow10(DegreePol - 1)) == mod10(posNew, pow10(DegreePol - 2));
290 if constexpr (isInteraction) {
291 return true;
292 }
293 return checkInteraction<DegreePol - 1, posNew>();
294 }
295 return false;
296}
297
298template <uint32_t Dim, uint32_t Degree, bool InteractionOnly>
299template <uint32_t DegreePol, uint32_t Pos, uint32_t Index>
300GPUd() constexpr float MultivariatePolynomialHelper<Dim, Degree, InteractionOnly>::sumTerms(GPUgeneric() const float par[], const float x[])
301{
302 // 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]
303 constexpr uint32_t posNew = getNewPos(DegreePol, Pos, 0);
304 if constexpr (mod10(posNew, pow10(DegreePol)) != 1) {
305
306 // check if all digits in posNew are unequal: For interaction_only terms with x[Dim]*x[Dim]... etc. can be skipped
307 if constexpr (InteractionOnly && checkInteraction<DegreePol, posNew>()) {
308 return sumTerms<DegreePol, posNew + 1, Index>(par, x);
309 }
310
311 // sum up the term for corrent term and set posotion for next combination
312 return par[Index] * prodTerm<DegreePol>(x, posNew) + sumTerms<DegreePol, posNew + 1, Index + 1>(par, x);
313 }
314 return 0;
315}
316
317template <uint32_t Dim, uint32_t Degree, bool InteractionOnly>
318template <uint32_t DegreePol>
319GPUd() constexpr float MultivariatePolynomialHelper<Dim, Degree, InteractionOnly>::loopDegrees(GPUgeneric() const float par[], const float x[])
320{
321 if constexpr (DegreePol <= Degree) {
322 constexpr uint32_t index{getNParameters(DegreePol - 1, Dim, InteractionOnly)}; // offset of the index for accessing the parameters
323 return sumTerms<DegreePol, 0, index>(par, x) + loopDegrees<DegreePol + 1>(par, x);
324 }
325 return 0;
326}
327
328} // namespace o2::gpu
329
330#endif
#define GPUgeneric()
uint16_t pos
Definition RawData.h:3
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 getNParametersInteractionOnly(const uint32_t degree
GPUd() static const expr uint32_t getNParameters(const uint32_t degree
GPUd() static const expr uint32_t getNParametersAllTerms(const uint32_t degree
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
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