MINT2
RooCubicSplineKnot.h
Go to the documentation of this file.
1 #ifndef ROO_CUBICSPLINEKNOT
2 #define ROO_CUBICSPLINEKNOT
3 #include <cassert>
4 #include <vector>
5 #include "RooArgList.h"
6 template <typename> class TVectorT;
8 class TH1;
9 
10 // CINT doesn't like it if we encapsulate this in RooCubicSplineKnot ;-(
11 
13 public:
14 
16  public:
17  BoundaryConditions( bool leftSecondDerivative = true , bool rightSecondDerivative = true
18  , double valueLeft=0, double valueRight=0 )
19  { secondDerivative[0] = leftSecondDerivative ; secondDerivative[1] = rightSecondDerivative;
20  value[0] = valueLeft; value[1] = valueRight;
21  }
23  double value[2];
24  };
25 
26  RooCubicSplineKnot(const double *array, int nEntries ) : _u( array, array+nEntries) {}
27  template <typename Iter> RooCubicSplineKnot(Iter begin, Iter end) : _u(begin,end) {}
28  RooCubicSplineKnot(const std::vector<double>& knots ) // needed to easily interface with python...
29  : _u(knots) {}
30 
31  double u(int i) const {
32  assert(size());
33  assert(i>-3);
34  assert(i<size()+3);
35  return _u[std::min(std::max(0,i),size()-1)]; }
36  int size() const { return _u.size(); }
37  double evaluate(double _u, const RooArgList& b) const;
38  double analyticalIntegral(const RooArgList& b) const;
39 
40  void computeCoefficients(std::vector<double>& y, BoundaryConditions bc = BoundaryConditions() ) const ;
41  void smooth(std::vector<double>& y, const std::vector<double>& dy, double lambda) const;
42 
43  const std::vector<double>& knots() const { return _u; }
44 
45  class S_jk {
46  public:
47  S_jk() : t(0.), d(0.), s(0.), o(0.125) {}
48  S_jk(double a, double b, double c) : t(a*b*c), d(0.5*(a*b+a*c+b*c) ), s( 0.25*(a+b+c) ), o(0.125) { }
49  S_jk(const S_jk& other, double offset=0) : t(other.t), d(other.d), s(other.s), o(other.o) {
50  if (!offset) return;
51  t+=offset*(-2*d+offset*(4*s-offset*o*8));
52  d+=offset*(-8*s+3*offset*o*8)/2;
53  s-=offset*3*o*8/4;
54  }
55  S_jk& operator*=(double z) { t*=z; d*=z; s*=z; o*=z; return *this; }
56  S_jk& operator/=(double z) { t/=z; d/=z; s/=z; o/=z; return *this; }
57  S_jk& operator-() { t=-t; d=-d; s=-s; o=-o; return *this; }
58  S_jk& operator+=(const S_jk& other) { t+=other.t; d+=other.d; s+=other.s; o+=other.o; return *this; }
59  S_jk& operator-=(const S_jk& other) { t-=other.t; d-=other.d; s-=other.s; o-=other.o; return *this; }
60 
61  S_jk operator*(double z) const { return S_jk(*this)*=z; }
62  S_jk operator/(double z) const { return S_jk(*this)/=z; }
63  S_jk operator+(const S_jk& other) const { return S_jk(*this)+=other; }
64  S_jk operator-(const S_jk& other) const { return S_jk(*this)-=other; }
65 
66 
67  double operator()(int j, int k) const {
68  if (j>k) std::swap(j,k);
69  assert(0<=j&&j<4);
70  assert(0<=k&&k<4-j); // note: for 4-j<=k<4 could return 0... but better not to invoke with those..
71  switch(3*j+k) {
72  case 0: return -t; // (0,0)
73  case 1: return d; // (0,1),(1,0)
74  case 2: return -s; // (0,2),(2,0)
75  case 3: return o; // (0,3),(3,0)
76  case 4: return -2*s; // (1,1)
77  case 5: return 3*o; // (1,2),(2,1)
78  }
79  assert(1==0);
80  return 0;
81  }
82  private:
83  double t,d,s,o;
84  };
85  // S matrix for i-th interval
86  RooCubicSplineKnot::S_jk S_jk_sum(int i, const RooArgList& b) const ;
87 
88  class S2_jk {
89  public:
90  S2_jk() : t0(0.), t1(0.), t2(0.), t3(0.), t4(0.), t5(0.), t6(1./64.) {}
91  S2_jk(double a1, double b1, double c1, double a2, double b2, double c2) :
92  t0(a1*b1*c1*a2*b2*c2),
93  t1(1./2.*((a1*b1*c1)*(a2*b2+a2*c2+b2*c2)+(a2*b2*c2)*(a1*b1+a1*c1+b1*c1))),
94  t2(1./4.*((a1*b1*c1)*(a2+b2+c2)+(a2*b2*c2)*(a1+b1+c1)+(a1*b1+a1*c1+b1*c1)*(a2*b2+a2*c2+b2*c2))),
95  t3(1./8.*((a1*b1*c1)+(a2*b2*c2)+(a1+b1+c1)*(a2*b2+a2*c2+b2*c2)+(a2+b2+c2)*(a1*b1+a1*c1+b1*c1))),
96  t4(1./16.*((a1*b1+a1*c1+b1*c1)+(a2*b2+a2*c2+b2*c2)+(a1+b1+c1)*(a2+b2+c2))),
97  t5(1./32.*((a1+b1+c1)+(a2+b2+c2))),
98  t6(1./64.)
99  { }
100  S2_jk(const S2_jk& other, double offset=0) : t0(other.t0), t1(other.t1), t2(other.t2), t3(other.t3), t4(other.t4), t5(other.t5), t6(other.t6) {
101  if (!offset) return;
102  t0+=offset*(-2*t1+offset*(4*t2+offset*(-8*t3+offset*(16*t4+offset*(-32*t5+offset*64*t6)))));
103  t1+=offset*(-8*t2+offset*(3*8*t3+offset*(-4*16*t4+offset*(5*32*t5-6*offset*64*t6))))/2;
104  t2+=offset*(-3*8*t3+offset*(6*16*t4+offset*(-10*32*t5+15*offset*64*t6)))/4;
105  t3+=offset*(-4*16*t4+offset*(10*32*t5-20*offset*64*t6))/8;
106  t4+=offset*(-5*32*t5+15*offset*64*t6)/16;
107  t5-=offset*6*64*t6/32;
108  }
109  S2_jk& operator*=(double z) { t0*=z; t1*=z; t2*=z; t3*=z; t4*=z; t5*=z; t6*=z; return *this; }
110  S2_jk& operator/=(double z) { t0/=z; t1/=z; t2/=z; t3/=z; t4/=z; t5/=z; t6/=z; return *this; }
111  S2_jk operator-() { t0=-t0; t1=-t1; t2=-t2; t3=-t3; t4=-t4; t5=-t5; t6=-t6; return *this; }
112  S2_jk& operator+=(const S2_jk& other) { t0+=other.t0; t1+=other.t1; t2+=other.t2; t3+=other.t3; t4+=other.t4; t5+=other.t5; t6+=other.t6; return *this; }
113  S2_jk& operator-=(const S2_jk& other) { t0-=other.t0; t1-=other.t1; t2-=other.t2; t3-=other.t3; t4-=other.t4; t5-=other.t5; t6-=other.t6; return *this; }
114 
115  S2_jk operator*(double z) const { return S2_jk(*this)*=z; }
116  S2_jk operator/(double z) const { return S2_jk(*this)/=z; }
117  S2_jk operator+(const S2_jk& other) const { return S2_jk(*this)+=other; }
118  S2_jk operator-(const S2_jk& other) const { return S2_jk(*this)-=other; }
119 
120 
121  double operator()(int j, int k) const {
122  if (j>k) std::swap(j,k);
123  assert(0<=j&&j<7);
124  assert(0<=k&&k<7-j);
125  switch(6*j+k) {
126  case 0: return t0; // (0,0)
127  case 1: return -t1; // (0,1),(1,0)
128  case 2: return t2; // (0,2),(2,0)
129  case 3: return -t3; // (0,3),(3,0)
130  case 4: return t4; // (0,4),(4,0)
131  case 5: return -t5; // (0,5),(5,0)
132  case 6: return t6; // (0,6),(6,0)
133  case 7: return 2*t2; // (1,1)
134  case 8: return -3*t3; // (1,2),(2,1)
135  case 9: return 4*t4; // (1,3),(3,1)
136  case 10:return -5*t5; // (1,4),(4,1)
137  case 11:return 6*t6; // (1,5),(5,1)
138  case 14:return 6*t4; // (2,2)
139  case 15:return -10*t5; // (2,3),(3,2)
140  case 16:return 15*t6; // (2,4),(4,2)
141  case 21:return 20*t6; // (3,3)
142  }
143  assert(1==0);
144  return 0;
145  }
146  private:
147  double t0,t1,t2,t3,t4,t5,t6;
148  };
149  // S matrix for product of 2 splines for i-th interval
150  RooCubicSplineKnot::S2_jk S2_jk_sum(int i, const RooArgList& b1, const RooArgList& b2) const ;
151 
152 
153  class S_edge {
154  public:
155  S_edge(double a, double b) : alpha(0.5*a), beta(b) {}
156  S_edge(const S_edge& other, double offset=0);
157  double operator()(int j, int k) const {
158  assert(j==0||j==1);
159  assert(0<=(j+k) && (j+k)<2);
160  return ( j+k==0 ) ? beta : alpha ;
161  }
162  private:
163  double alpha,beta;
164  };
165 
166  RooCubicSplineKnot::S_edge S_jk_edge(bool left, const RooArgList& b) const;
167 
168  class S2_edge {
169  public:
170  S2_edge(double a1, double b1, double a2, double b2) :
171  t0(b1*b2),
172  t1(1./2.*(a1*b2+a2*b1)),
173  t2(1./4.*a1*a2)
174  {}
175  S2_edge(const S2_edge& other, double offset=0): t0(other.t0), t1(other.t1), t2(other.t2) {
176  if (!offset) return;
177  t0+=offset*(2*t1+offset*4*t2);
178  t1+=offset*8*t2/2.;
179  // t2=t2;
180  }
181  double operator()(int j, int k) const {
182  if (j>k) std::swap(j,k);
183  assert(0<=j&&j<3);
184  assert(0<=k&&k<3-j);
185  switch(2*j+k) {
186  case 0: return t0; // (0,0)
187  case 1: return t1; // (0,1),(1,0)
188  case 2: return t2; // (0,2),(2,0)
189  case 3: return 2*t2; // (1,1)
190  }
191  assert(1==0);
192  return 0;
193  }
194  private:
195  double t0,t1,t2;
196  };
197 
198  RooCubicSplineKnot::S2_edge S2_jk_edge(bool left, const RooArgList& b1, const RooArgList& b2) const;
199 
200  // return integrals over the i-th bin of the j-th basis spline . exp(-gamma x)
201  // as matrix_ij
202  double expIntegral(const TH1* hist, double gamma, TVectorD& coefficients, TMatrixD& covarianceMatrix) const;
203 
204 
205 private:
206 
207  int index(double u_) const;
208 
209  // Basic Splines
210  double A(double u_,int i) const{ return -cub(d(u_,i+1))/P(i); }
211  double B(double u_,int i) const{ return sqr(d(u_,i+1))*d(u_,i-2)/P(i) + d(u_,i-1)*d(u_,i+2)*d(u_,i+1)/Q(i) + d(u_,i )*sqr(d(u_,i+2))/R(i); }
212  double C(double u_,int i) const{ return -sqr(d(u_,i-1))*d(u_,i+1)/Q(i) - d(u_,i )*d(u_,i+2)*d(u_,i-1)/R(i) - d(u_,i+3)*sqr(d(u_,i ))/S(i); }
213  double D(double u_,int i) const{ return cub(d(u_,i ))/S(i); }
214 
215  // Parameters of Linear System
216  double ma(int i, bool bc[]) const { // subdiagonal
217 
218  return (i!=size()-1) ? A(u(i),i)
219  : (bc[1] ) ? double(6)/(h(i,i-2)*h(i-1))
220  : double(0) ;
221  }
222 
223  double mc(int i, bool bc[]) const { // superdiagonal
224  return (i!=0) ? C(u(i),i)
225  : bc[0] ? double(6)/(h(2,0)*h(0))
226  : double(0);
227  }
228 
229  double mb(int i, bool bc[]) const { // diagonal
230  if (i!=0 && i!=size()-1) return B(u(i),i);
231 
232  if (i==0) {
233  return bc[0] ? -(double(6)/h(i)+double(6)/h(i+2,i))/h(i)
234  : double(3)/h(i);
235  } else {
236  return bc[1] ? -(double(6)/h(i-1)+double(6)/h(i,i-2))/h(i-1)
237  : - double(3)/h(i-1);
238  }
239  }
240 
241 
242 
243  // Normalisation
244  double P(int i) const { if (_PQRS.empty()) fillPQRS(); assert(4*i <int(_PQRS.size())); return _PQRS[4*i ]; }
245  double Q(int i) const { if (_PQRS.empty()) fillPQRS(); assert(4*i+1<int(_PQRS.size())); return _PQRS[4*i+1]; }
246  double R(int i) const { if (_PQRS.empty()) fillPQRS(); assert(4*i+2<int(_PQRS.size())); return _PQRS[4*i+2]; }
247  double S(int i) const { if (_PQRS.empty()) fillPQRS(); assert(4*i+3<int(_PQRS.size())); return _PQRS[4*i+3]; }
248 
249  void fillPQRS() const;
250 
251  static double sqr(double x) { return x*x; }
252  static double cub(double x) { return x*sqr(x); }
253  static double qua(double x) { return sqr(sqr(x)); }
254  double d(double u_, int j) const { return u_-u(j); }
255  double d(double u_, int i, int j, int k) const { return d(u_,i)*d(u_,j)*d(u_,k); }
256  double h(int i, int j) const { return u(i)-u(j); }
257  double h(int i) const { return h(i+1,i); }
258  double r(int i) const { return double(3)/h(i); }
259  double f(int i) const { return -r(i-1)-r(i); }
260  double p(int i) const { return 2*h(i-1)+h(i); }
261 
262  std::vector<double> _u;
263  mutable std::vector<double> _PQRS;
264  mutable std::vector<double> _IABCD;
265  mutable std::vector<RooCubicSplineKnot::S_jk> _S_jk;
266  mutable std::vector<RooCubicSplineKnot::S2_jk> _S2_jk;
267  //ClassDef(RooCubicSplineKnot, 1);
268 };
269 
270 #endif
RooCubicSplineKnot::S_jk S_jk_sum(int i, const RooArgList &b) const
S_jk operator/(double z) const
double mb(int i, bool bc[]) const
double S(int i) const
RooCubicSplineKnot::S2_jk S2_jk_sum(int i, const RooArgList &b1, const RooArgList &b2) const
std::vector< RooCubicSplineKnot::S_jk > _S_jk
double operator()(int j, int k) const
S2_edge(const S2_edge &other, double offset=0)
double D(double u_, int i) const
double C(double u_, int i) const
double B(double u_, int i) const
RooCubicSplineKnot::S2_edge S2_jk_edge(bool left, const RooArgList &b1, const RooArgList &b2) const
RooCubicSplineKnot(const double *array, int nEntries)
S_jk & operator *=(double z)
S2_jk & operator-=(const S2_jk &other)
double h(int i) const
BoundaryConditions(bool leftSecondDerivative=true, bool rightSecondDerivative=true, double valueLeft=0, double valueRight=0)
S2_jk operator+(const S2_jk &other) const
static double cub(double x)
double operator()(int j, int k) const
std::vector< double > _PQRS
double Q(int i) const
double d(double u_, int i, int j, int k) const
RooCubicSplineKnot(const std::vector< double > &knots)
int index(double u_) const
S_jk operator+(const S_jk &other) const
S_jk operator *(double z) const
double f(int i) const
RooCubicSplineKnot::S_edge S_jk_edge(bool left, const RooArgList &b) const
S_jk operator-(const S_jk &other) const
double h(int i, int j) const
S2_jk(const S2_jk &other, double offset=0)
static double qua(double x)
static double sqr(double x)
void smooth(std::vector< double > &y, const std::vector< double > &dy, double lambda) const
double mc(int i, bool bc[]) const
S2_jk operator-(const S2_jk &other) const
double R(int i) const
double analyticalIntegral(const RooArgList &b) const
double d(double u_, int j) const
double u(int i) const
S2_jk operator *(double z) const
std::vector< RooCubicSplineKnot::S2_jk > _S2_jk
S2_jk operator/(double z) const
double expIntegral(const TH1 *hist, double gamma, TVectorD &coefficients, TMatrixD &covarianceMatrix) const
S2_jk & operator+=(const S2_jk &other)
S_jk & operator+=(const S_jk &other)
void computeCoefficients(std::vector< double > &y, BoundaryConditions bc=BoundaryConditions()) const
double operator()(int j, int k) const
TVectorT< Double_t > TVectorD
S_jk(const S_jk &other, double offset=0)
const std::vector< double > & knots() const
double evaluate(double _u, const RooArgList &b) const
std::vector< double > _u
double P(int i) const
RooCubicSplineKnot(Iter begin, Iter end)
double r(int i) const
S_jk & operator-=(const S_jk &other)
S_jk(double a, double b, double c)
double lambda(double x, double y, double z)
Definition: lambda.h:8
double operator()(int j, int k) const
S2_jk(double a1, double b1, double c1, double a2, double b2, double c2)
S2_edge(double a1, double b1, double a2, double b2)
double p(int i) const
std::vector< double > _IABCD
double A(double u_, int i) const
double ma(int i, bool bc[]) const