MINT2
RooCubicSplineKnot.cpp
Go to the documentation of this file.
1 #include <iostream>
2 #include <string>
3 
4 #include "TMath.h"
5 #include "TVectorD.h"
6 #include "TH1.h"
7 #include "RooAbsReal.h"
8 
10 
11 using namespace std;
13 
14  Double_t get(const RooArgList& b,int i) { return ((RooAbsReal&)b[i]).getVal() ; }
15  Double_t get(const RooArgList& b,int i,int k) { return RooCubicSplineKnot_aux::get(b,i+k); }
16 
17  template <typename T> typename T::const_reference get(const T& t, int i, int j) { return t[4*i+j]; }
18  template <typename T> typename T::const_reference get2(const T& t, int i, int j) { return t[10*i+j];}
19  template <typename T> void push_back(T& t, const typename T::value_type& a,
20  const typename T::value_type& b,
21  const typename T::value_type& c,
22  const typename T::value_type& d) { t.push_back(a); t.push_back(b); t.push_back(c); t.push_back(d) ; }
23 
24 }
25 
26 void RooCubicSplineKnot::smooth(std::vector<double>& y, const std::vector<double>& dy, double lambda) const {
27 // implementation as described in D.S.G. Pollock, Smoothing Splines"
28 // see http://r.789695.n4.nabble.com/file/n905996/SPLINES.PDF
29  using namespace std;
30  int n = y.size();
31  vector<double> uu(n-2),vv(n-3),ww(n-4), q(n-2);
32  assert( dy.size()==y.size());
33  assert( size()==n);
34  // lambda = 0 : no smoothing ; lambda -> 1: straight line (the ultimate smooth curve)
35  if (lambda<0|| !(lambda<1)) {
36  throw std::string("RooCubicSplineKnot::smooth: smoothing parameter must be in range [0,1)");
37  }
38  double mu =2*lambda/(3*(1-lambda));
39  for (int i=0;i<n-2;++i) {
40  q[i] = r(i)*(y[i]-y[i+1])-r(i+1)*(y[i+1]-y[i+2]);
41  uu[i] = p(i+1)+mu*(sqr(r(i)*dy[i])+sqr(f(i+1)*dy[i+1])+sqr(r(i+1)*dy[i+2]) );
42  if (i>n-4) continue;
43  vv[i] = h(i+1)+mu*(f(i+1)*r(i+1)*sqr(dy[i+1]) + f(i+1)*r(i+2)*sqr(dy[i+2]));
44  if (i>n-5) continue ;
45  ww[i] = mu*r(i+1)*r(i+2)*sqr(dy[i+2]);
46  }
47 
48  // Solve A b = q with A(i,i)=uu(i), A(i+1,i)=A(i,i+1) = vv(i), A(i+2,i),A(i,i+2)=ww(i)
49  // start with factorization: A -> L D LT
50  vv[0] /= uu[0]; ww[0] /= uu[0];
51  uu[1] -= uu[0]*sqr(vv[0]);
52  vv[1] -= uu[0]*vv[0]*ww[0];
53  vv[1] /= uu[1]; ww[1] /= uu[1];
54  for (int i=2;i<n-4;++i) {
55  uu[i] -= uu[i-1]*sqr(vv[i-1])+uu[i-2]*sqr(ww[i-2]);
56  vv[i] -= uu[i-1]*vv[i-1]*ww[i-1]; vv[i] /= uu[i];
57  ww[i] /= uu[i];
58  }
59  uu[n-4] -= uu[n-5]*sqr(vv[n-5])+uu[n-6]*sqr(ww[n-6]);
60  vv[n-4] -= uu[n-5]*vv[n-5]*ww[n-5]; vv[n-4] /= uu[n-4];
61  uu[n-3] -= uu[n-4]*sqr(vv[n-4])+uu[n-5]*sqr(ww[n-5]);
62 
63  // forward substitution (i.e. solve L ( D LT b ) = q for D LT b -> q
64  q[1] -= vv[0 ]*q[0 ];
65  for (int i=2;i<n-2;++i) q[i] -= vv[i-1]*q[i-1]+ww[i-2]*q[i-2];
66  // rescale (i.e. solve D (LT b ) = q for LT b
67  for (int i=0;i<n-2;++i) { q[i] /= uu[i] ; }
68  // backward substitution (i.e. solve LT b = q for b -> q )
69  q[n-4] -= vv[n-4]*q[n-3];
70  for (int i=n-5;i>=0;--i) q[i ] -= vv[i ]*q[i+1]+ww[i]*q[i+2];
71  // solve for y...
72  int i=0;
73  y[i] -=mu*sqr(dy[i])*(r(i)*q[i] ); ++i;
74  y[i] -=mu*sqr(dy[i])*(r(i)*q[i]+f(i)*q[i-1] ); ++i;
75  for (;i<n-2;++i) y[i]-=mu*sqr(dy[i])*(r(i)*q[i]+f(i)*q[i-1]+r(i-1)*q[i-2]);
76  y[i] -=mu*sqr(dy[i])*( f(i)*q[i-1]+r(i-1)*q[i-2]); ++i;
77  y[i] -=mu*sqr(dy[i])*( r(i-1)*q[i-2]);
78 
79 }
80 
81 // on input, y contains the values at the knot locations
82 // on output, it contains the b-spline coefficients
83 // Note: one element will be pre-pended, and one post-pended !!
84 void RooCubicSplineKnot::computeCoefficients(std::vector<double>& y, BoundaryConditions bc) const
85 {
86  // see http://en.wikipedia.org/wiki/Spline_interpolation
87  // for the derivation of the linear system...
88  // see http://en.wikipedia.org/wiki/Tridiagonal_matrix_algorithm
89  // for the O(N) algorithm to solve the relevant linear system...
90  int n = size();
91  assert(int(y.size())==size());
92 
93  // Weights of first and last spline are fully determined by values at knots
94  double bf = y.front();
95  double bb = y.back();
96 
97  // Set boundary conditions for linear system
98  y.front() = bc.value[0] - bf * ( bc.secondDerivative[0] ? ( double(6) / sqr(h(0)) ) : ( -double(3) / h(0) ) );
99  y.back() = bc.value[1] - bb * ( bc.secondDerivative[1] ? ( double(6) / sqr(h(n-2))) : ( double(3) / h(n-2) ) );
100 
101  // Solve linear system
102  std::vector<double> c; c.reserve(n);
103  c.push_back( mc(0, bc.secondDerivative) / mb(0, bc.secondDerivative) );
104  y[0] /= mb(0, bc.secondDerivative);
105  // TODO: rewrite the special cases i==1 and i==n-1 (move latter out of loop)
106  // so we can avoid 'if' statements in the loop body...
107  for (int i = 1; i < n; ++i) {
108  double m = double(1) / ( mb(i, bc.secondDerivative ) - ma(i, bc.secondDerivative) * c.back() );
109  c.push_back( mc(i,bc.secondDerivative) * m );
110  y[i] -= ma(i, bc.secondDerivative) * y[i - 1];
111  y[i] *= m;
112  }
113  for (int i = n-1 ; i-- > 0; ) y[i] -= c[i] * y[i + 1];
114  y.push_back(bb); y.insert(y.begin(),bf); // ouch... expensive!
115 }
116 
117 
118 
119 
121  assert(_PQRS.empty());
122  // P,Q,R,S only depend on the knot vector, so build at construction, and cache them...
123  _PQRS.reserve(4*size());
124  for (int i=0;i<size();++i) {
125  _PQRS.push_back( h(i+1,i-2)*h(i+1,i-1)*h(i+1,i) );
126  _PQRS.push_back( h(i+1,i-1)*h(i+2,i-1)*h(i+1,i) );
127  _PQRS.push_back( h(i+2,i )*h(i+2,i-1)*h(i+1,i) );
128  _PQRS.push_back( h(i+2,i )*h(i+3,i )*h(i+1,i) );
129  }
130 
131 }
132 
133 double RooCubicSplineKnot::evaluate(double x, const RooArgList& b) const {
135  int i = index(x); // location in knot vector: index of last knot less than x...
136  assert(-1<=i && i<=size());
137  // we're a 'natural' spline. If beyond first/last knot, Extrapolate using the derivative at the first (last) knot
138  if (i==-1 ) { ++i; return get(b,i,0) - d(x,i)*r(i )*(get(b,i,0)-get(b,i,1)); }
139  if (i==size()) { --i; return get(b,i,2) + d(x,i)*r(i-1)*(get(b,i,2)-get(b,i,1)); }
140  assert( u(i) <= x && x<= u(i+1) );
141  return get(b,i,0)*A(x,i) // TODO: substitute A,B,C,D 'in situ'
142  + get(b,i,1)*B(x,i)
143  + get(b,i,2)*C(x,i)
144  + get(b,i,3)*D(x,i);
145 }
146 
147 double RooCubicSplineKnot::analyticalIntegral(const RooArgList& b) const {
150  if (_IABCD.empty()) {
151  // the integrals of A,B,C,D from u(i) to u(i+1) only depend on the knot vector...
152  // so we create them 'on demand' and cache the result
153  _IABCD.reserve(4*size());
154  for (int j=0;j<size();++j) {
155  push_back(_IABCD, qua(h(j,j+1))/(4*P(j))
156  , - cub(h(j,j+1))*(3*u(j)-4*u(j-2)+u(j+1))/(12*P(j))
157  - sqr(h(j,j+1))*(3*sqr(u(j))-2*u(j-1)*u(j+1)+sqr(u(j+1))+u(j)*(-4*u(j-1)+2*u(j+1)-4*u(j+2)) +6*u(j-1)*u(j+2)-2*u(j+1)*u(j+2) )/(12*Q(j))
158  + sqr(h(j,j+1))*(3*sqr(u(j+1))+sqr(u(j ))+2*u(j)*u(j+1)-8*u(j+1)*u(j+2)-4*u(j )*u(j+2)+6*sqr(u(j+2)))/(12*R(j))
159  , sqr(h(j,j+1))*(3*sqr(u(j ))+sqr(u(j+1))+2*u(j+1)*u(j)-8*u(j )*u(j-1)-4*u(j-1)*u(j+1)+6*sqr(u(j-1)))/(12*Q(j))
160  - sqr(h(j,j+1))*(3*sqr(u(j+1))+sqr(u(j))-4*u(j-1)*u(j+1)+6*u(j-1)*u(j+2)-4*u(j+1)*u(j+2)-2*u(j)*(u(j-1)-u(j+1)+u(j+2)))/(12*R(j))
161  + cub(h(j,j+1))*(3*u(j+1)-4*u(j+3)+u(j))/(12*S(j))
162  , qua(h(j,j+1))/(4*S(j)) );
163  }
164  }
165  // FIXME: this assumes the integration range goes from first knot to last knot...
166  assert(b.getSize()-2==size());
167  double norm(0);
168  for (int i=0; i < size()-1; ++i) for (int k=0;k<4;++k) {
169  norm += get(b,i,k)*RooCubicSplineKnot_aux::get(_IABCD,i,k) ;
170  }
171  return norm;
172 }
173 
174 // location in knot vector: index of last knot less than x... except when beyond interval+ last +1 if to right, -1 if to left
175 int RooCubicSplineKnot::index(double u) const
176 {
177  if (u>_u.back()) return size();
178  std::vector<double>::const_iterator i = --std::upper_bound(_u.begin(),_u.end()-1,u);
179  return std::distance(_u.begin(),i);
180 }
181 
182 // S matrix for i-th interval
184 {
185  if (_S_jk.empty()) {
186  _S_jk.reserve(size()*4);
187  for(int j=0;j<size();++j) {
188  // This 'table' should be compatible with the definitions of A,B,C, and D...
189  _S_jk.push_back( -RooCubicSplineKnot::S_jk(u(j+1),u(j+1),u(j+1))/P(j) ); // A
190  _S_jk.push_back( RooCubicSplineKnot::S_jk(u(j-2),u(j+1),u(j+1))/P(j)
191  +RooCubicSplineKnot::S_jk(u(j-1),u(j+1),u(j+2))/Q(j)
192  +RooCubicSplineKnot::S_jk(u(j ),u(j+2),u(j+2))/R(j) ); // B
193  _S_jk.push_back( -RooCubicSplineKnot::S_jk(u(j-1),u(j-1),u(j+1))/Q(j)
194  -RooCubicSplineKnot::S_jk(u(j-1),u(j ),u(j+2))/R(j)
195  -RooCubicSplineKnot::S_jk(u(j ),u(j ),u(j+3))/S(j) ); // C
196  _S_jk.push_back( RooCubicSplineKnot::S_jk(u(j ),u(j ),u(j ))/S(j) ); // D
197  }
198  }
200  return get(_S_jk,i,0)*get(b,i,0)
201  + get(_S_jk,i,1)*get(b,i,1)
202  + get(_S_jk,i,2)*get(b,i,2)
203  + get(_S_jk,i,3)*get(b,i,3);
204 }
205 
206 // S matrix for product of 2 splines for i-th interval
207 RooCubicSplineKnot::S2_jk RooCubicSplineKnot::S2_jk_sum(int i, const RooArgList& b1, const RooArgList& b2) const
208 {
209  if (_S2_jk.empty()) {
210  _S2_jk.reserve(size()*10);
211  for(int j=0;j<size();++j) {
212  // This 'table' should be compatible with the definitions of A,B,C, and D...
213  _S2_jk.push_back( RooCubicSplineKnot::S2_jk(u(j+1),u(j+1),u(j+1),u(j+1),u(j+1),u(j+1)) / (P(j)*P(j)) ); // (A * A)
214 
215  _S2_jk.push_back( RooCubicSplineKnot::S2_jk(u(j-2),u(j+1),u(j+1),u(j-2),u(j+1),u(j+1)) / (P(j)*P(j))
216  +RooCubicSplineKnot::S2_jk(u(j-1),u(j+1),u(j+2),u(j-1),u(j+1),u(j+2)) / (Q(j)*Q(j))
217  +RooCubicSplineKnot::S2_jk(u(j ),u(j+2),u(j+2),u(j ),u(j+2),u(j+2)) / (R(j)*R(j))
218  +RooCubicSplineKnot::S2_jk(u(j-2),u(j+1),u(j+1),u(j-1),u(j+1),u(j+2)) / (P(j)*Q(j)) * 2.
219  +RooCubicSplineKnot::S2_jk(u(j-2),u(j+1),u(j+1),u(j ),u(j+2),u(j+2)) / (P(j)*R(j)) * 2.
220  +RooCubicSplineKnot::S2_jk(u(j-1),u(j+1),u(j+2),u(j ),u(j+2),u(j+2)) / (Q(j)*R(j)) * 2. ); // (B * B)
221 
222  _S2_jk.push_back( RooCubicSplineKnot::S2_jk(u(j-1),u(j-1),u(j+1),u(j-1),u(j-1),u(j+1)) / (Q(j)*Q(j))
223  +RooCubicSplineKnot::S2_jk(u(j-1),u(j ),u(j+2),u(j-1),u(j ),u(j+2)) / (R(j)*R(j))
224  +RooCubicSplineKnot::S2_jk(u(j ),u(j ),u(j+3),u(j ),u(j ),u(j+3)) / (S(j)*S(j))
225  +RooCubicSplineKnot::S2_jk(u(j-1),u(j-1),u(j+1),u(j-1),u(j ),u(j+2)) / (Q(j)*R(j)) * 2.
226  +RooCubicSplineKnot::S2_jk(u(j-1),u(j-1),u(j+1),u(j ),u(j ),u(j+3)) / (Q(j)*S(j)) * 2.
227  +RooCubicSplineKnot::S2_jk(u(j-1),u(j ),u(j+2),u(j ),u(j ),u(j+3)) / (R(j)*S(j)) * 2. ); // (C * C)
228 
229  _S2_jk.push_back( RooCubicSplineKnot::S2_jk(u(j ),u(j ),u(j ),u(j ),u(j ),u(j )) / (S(j)*S(j)) ); // (D * D)
230 
231 
232  _S2_jk.push_back( -RooCubicSplineKnot::S2_jk(u(j+1),u(j+1),u(j+1),u(j-2),u(j+1),u(j+1)) / (P(j)*P(j))
233  -RooCubicSplineKnot::S2_jk(u(j+1),u(j+1),u(j+1),u(j-1),u(j+1),u(j+2)) / (P(j)*Q(j))
234  -RooCubicSplineKnot::S2_jk(u(j+1),u(j+1),u(j+1),u(j ),u(j+2),u(j+2)) / (P(j)*R(j)) ); // (A * B)
235 
236  _S2_jk.push_back( RooCubicSplineKnot::S2_jk(u(j+1),u(j+1),u(j+1),u(j-1),u(j-1),u(j+1)) / (P(j)*Q(j))
237  +RooCubicSplineKnot::S2_jk(u(j+1),u(j+1),u(j+1),u(j-1),u(j ),u(j+2)) / (P(j)*R(j))
238  +RooCubicSplineKnot::S2_jk(u(j+1),u(j+1),u(j+1),u(j ),u(j ),u(j+3)) / (P(j)*S(j)) ); // (A * C)
239 
240  _S2_jk.push_back( -RooCubicSplineKnot::S2_jk(u(j+1),u(j+1),u(j+1),u(j ),u(j ),u(j )) / (P(j)*S(j)) ); // (A * D)
241 
242 
243  _S2_jk.push_back( -RooCubicSplineKnot::S2_jk(u(j-2),u(j+1),u(j+1),u(j-1),u(j-1),u(j+1)) / (P(j)*Q(j))
244  -RooCubicSplineKnot::S2_jk(u(j-2),u(j+1),u(j+1),u(j-1),u(j ),u(j+2)) / (P(j)*R(j))
245  -RooCubicSplineKnot::S2_jk(u(j-2),u(j+1),u(j+1),u(j ),u(j ),u(j+3)) / (P(j)*S(j))
246  -RooCubicSplineKnot::S2_jk(u(j-1),u(j+1),u(j+2),u(j-1),u(j-1),u(j+1)) / (Q(j)*Q(j))
247  -RooCubicSplineKnot::S2_jk(u(j-1),u(j+1),u(j+2),u(j-1),u(j ),u(j+2)) / (Q(j)*R(j))
248  -RooCubicSplineKnot::S2_jk(u(j-1),u(j+1),u(j+2),u(j ),u(j ),u(j+3)) / (Q(j)*S(j))
249  -RooCubicSplineKnot::S2_jk(u(j ),u(j+2),u(j+2),u(j-1),u(j-1),u(j+1)) / (R(j)*Q(j))
250  -RooCubicSplineKnot::S2_jk(u(j ),u(j+2),u(j+2),u(j-1),u(j ),u(j+2)) / (R(j)*R(j))
251  -RooCubicSplineKnot::S2_jk(u(j ),u(j+2),u(j+2),u(j ),u(j ),u(j+3)) / (R(j)*S(j)) ); // (B * C)
252 
253  _S2_jk.push_back( RooCubicSplineKnot::S2_jk(u(j-2),u(j+1),u(j+1),u(j ),u(j ),u(j )) / (P(j)*S(j))
254  +RooCubicSplineKnot::S2_jk(u(j-1),u(j+1),u(j+2),u(j ),u(j ),u(j )) / (Q(j)*S(j))
255  +RooCubicSplineKnot::S2_jk(u(j ),u(j+2),u(j+2),u(j ),u(j ),u(j )) / (R(j)*S(j)) ); // (B * D)
256 
257  _S2_jk.push_back( -RooCubicSplineKnot::S2_jk(u(j-1),u(j-1),u(j+1),u(j ),u(j ),u(j )) / (Q(j)*S(j))
258  -RooCubicSplineKnot::S2_jk(u(j-1),u(j ),u(j+2),u(j ),u(j ),u(j )) / (R(j)*S(j))
259  -RooCubicSplineKnot::S2_jk(u(j ),u(j ),u(j+3),u(j ),u(j ),u(j )) / (S(j)*S(j)) ); // (C * D)
260  }
261  }
264  return get2(_S2_jk,i,0)*get(b1,i,0)*get(b2,i,0)
265  + get2(_S2_jk,i,1)*get(b1,i,1)*get(b2,i,1)
266  + get2(_S2_jk,i,2)*get(b1,i,2)*get(b2,i,2)
267  + get2(_S2_jk,i,3)*get(b1,i,3)*get(b2,i,3)
268  + get2(_S2_jk,i,4)*(get(b1,i,0)*get(b2,i,1)+get(b1,i,1)*get(b2,i,0))
269  + get2(_S2_jk,i,5)*(get(b1,i,0)*get(b2,i,2)+get(b1,i,2)*get(b2,i,0))
270  + get2(_S2_jk,i,6)*(get(b1,i,0)*get(b2,i,3)+get(b1,i,3)*get(b2,i,0))
271  + get2(_S2_jk,i,7)*(get(b1,i,1)*get(b2,i,2)+get(b1,i,2)*get(b2,i,1))
272  + get2(_S2_jk,i,8)*(get(b1,i,1)*get(b2,i,3)+get(b1,i,3)*get(b2,i,1))
273  + get2(_S2_jk,i,9)*(get(b1,i,2)*get(b2,i,3)+get(b1,i,3)*get(b2,i,2));
274 }
275 
276 RooCubicSplineKnot::S_edge::S_edge(const S_edge& other, double offset) :
277  alpha(other.alpha), beta(other.beta + offset * other.alpha * 2)
278  {}
279 
280 // S matrix for natural extrapolation beyond the first/last knot...
281 RooCubicSplineKnot::S_edge RooCubicSplineKnot::S_jk_edge(bool left, const RooArgList& b) const {
283  if (left) {
284  // efficiency = return evaluate(u(0),b) - d(x,0)*r(0)*(get(b,0,0)-get(b,0,1));
285  double alpha = -r(0)*(get(b,0,0)-get(b,0,1));
286  double beta = evaluate(u(0),b)-alpha*u(0);
287  return S_edge( alpha, beta );
288  } else {
289  int i = size()-1;
290  double alpha = r(i-1)*(get(b,i,2)-get(b,i,1));
291  double beta = evaluate(u(i),b)-alpha*u(i);
292  return S_edge(alpha,beta);
293  }
294 }
295 
296 // S matrix for natural extrapolation of spline product beyond the first/last knot...
297 RooCubicSplineKnot::S2_edge RooCubicSplineKnot::S2_jk_edge(bool left, const RooArgList& b1, const RooArgList& b2) const {
299  if (left) {
300  double alpha1 = -r(0)*(get(b1,0,0)-get(b1,0,1));
301  double beta1 = evaluate(u(0),b1)-alpha1*u(0);
302  double alpha2 = -r(0)*(get(b2,0,0)-get(b2,0,1));
303  double beta2 = evaluate(u(0),b2)-alpha2*u(0);
304  return S2_edge(alpha1,beta1,alpha2,beta2);
305  } else {
306  int i = size()-1;
307  double alpha1 = r(i-1)*(get(b1,i,2)-get(b1,i,1));
308  double beta1 = evaluate(u(i),b1)-alpha1*u(i);
309  double alpha2 = r(i-1)*(get(b2,i,2)-get(b2,i,1));
310  double beta2 = evaluate(u(i),b2)-alpha2*u(i);
311  return S2_edge(alpha1,beta1,alpha2,beta2);
312  }
313 }
314 
315 namespace {
316  // integral from lo to hi of (x-a)(x-b)(x-c)Exp[-gamma x]
317  double eI(double lo, double hi, double a, double b, double c, double gamma) {
318  assert(hi>=lo);
319  assert(0<=lo);
320  a*=gamma;b*=gamma;c*=gamma;
321  lo*=gamma;hi*=gamma;
322  double result = -a*b*c *(TMath::Gamma(1,hi) - TMath::Gamma(1,lo))*TMath::Gamma(1)
323  + (b*c+a*c+a*b)*(TMath::Gamma(2,hi) - TMath::Gamma(2,lo))*TMath::Gamma(2)
324  - (a+b+c) *(TMath::Gamma(3,hi) - TMath::Gamma(3,lo))*TMath::Gamma(3)
325  + (TMath::Gamma(4,hi) - TMath::Gamma(4,lo))*TMath::Gamma(4);
326 
327  return result / TMath::Power(gamma,4);
328  }
329  // integral from lo to hi of (x-a)(x-b)(x-c)
330  double fI(double lo, double hi, double a, double b, double c, double ) {
331  assert(hi>=lo);
332  assert(0<=lo);
333  double result = -a*b*c *( hi - lo )
334  + (b*c+a*c+a*b)*( hi*hi - lo*lo ) / 2.
335  - (a+b+c) *( hi*hi*hi - lo*lo*lo )/ 3.
336  + ( hi*hi*hi*hi - lo*lo*lo*lo) / 4. ;
337 
338  return result ;
339  }
340 
341 #if 0
342  // integral from lo to hi of [ c + slope * (x - offset) ] Exp[-Gamma x ]
343  // = [ c-slope*offset + slope*x ] Exp[-Gamma x ]
344  double eIn(double lo, double hi, double c, double slope, double offset, double gamma) {
345  assert(hi>=lo);
346  assert(0<=lo);
347  double a = c - slope*offset;
348  double b = slope; // ( a + b x ) Exp[ -Gamma x ]
349  // (1/Gamma) ( a Gamma b y ) Exp[ -y ]
350 
351 
352 
353  return result / TMath::Power(gamma,4);
354  }
355 
356 #endif
357 }
358 
359 #include "TMatrixD.h"
360 #include "TVectorD.h"
361 #include "TDecompBK.h"
362 
363 // return integrals from lo to hi of basis spline . exp(-gamma x), for each basis spline...
364 // FIXME: # of splines != # of knots... so cannot return as TGraphErrors...
365 
366 // return the chisquared , input hist + gamma, out : coefficients, errors
367 double RooCubicSplineKnot::expIntegral(const TH1* hist, double gamma, TVectorD& coefficients, TMatrixD& covarianceMatrix) const {
368  assert(hist!=0);
369  int nknots = size();
370  int nsplines = nknots+2;
371  int nbins = hist->GetNbinsX();
372  TMatrixD matrix(nsplines,nbins); for (int i=0;i<nsplines;++i) for (int j=0;j<nbins;++j) { matrix(i,j)=0; }
373  TVectorD Y(nbins), DY(nbins);
374 
375  for (int i=0;i<nbins ;++i) {
376  Y(i) = hist->GetBinContent(1+i);
377  DY(i) = hist->GetBinError(1+i);
378 
379 
380  Y(i) /= DY(i)*DY(i);
381 
382  double lo = hist->GetBinLowEdge(1+i);
383  double hi = lo + hist->GetBinWidth(1+i);
384 
385  double Norm = (exp(-gamma*lo)-exp(-gamma*hi))/gamma;
386 
387  // go for flat parent distribution;
388  // Norm = hi-lo;
389 
390 #if 0
391  // compute contributions beyond the first and last knot...
392  if (lo < _u.front()) {
393  // b-spline 0: 1 - d(x,0)*r(0) // d(x,0) = x - u(0)
394  // b-spline 1: + d(x,0)*r(0)
395  matrix(0, 0) += eIn( lo,hi, 1., -r(0), u(0) )/Norm;
396  matrix(1, 0) += eIn( lo,hi, 0., +r(0), u(0) )/Norm;
397 
398  }
399  if (hi > _u.back()) {
400  // c + alpha * (x - x0)
401  matrix(nknots , nbins-1) += eIn( lo, hi, 0., -r(nknots-2), u(nknots-1) )/Norm;
402  matrix(nknots+1, nbins-1) += eIn( lo, hi, 1., +r(nknots-2), u(nknots-1) )/Norm;
403 
404  }
405 #else
406  // assume nothing beyond spline interval
407  assert( lo >= _u.front() && hi <= _u.back() );
408 #endif
409 
410  // this bit is by construction fully contained between the first and last knot
411  for (int j=0;j<nknots-1;++j) {
412  double l = std::max(lo,u(j));
413  double h = std::min(hi,u(j+1));
414  if (l>=h) continue;
415  // in the knot interval [ u(j), u(j+1) ], the splines j..j+3 contribute...
416  matrix(j ,i) += (-eI(l,h, u(j+1),u(j+1),u(j+1), gamma)/P(j) ) / Norm;
417  matrix(j+1,i) += ( eI(l,h, u(j-2),u(j+1),u(j+1), gamma)/P(j)
418  +eI(l,h, u(j-1),u(j+1),u(j+2), gamma)/Q(j)
419  +eI(l,h, u(j ),u(j+2),u(j+2), gamma)/R(j) ) / Norm;
420  matrix(j+2,i) += (-eI(l,h, u(j-1),u(j-1),u(j+1), gamma)/Q(j)
421  -eI(l,h, u(j-1),u(j ),u(j+2), gamma)/R(j)
422  -eI(l,h, u(j ),u(j ),u(j+3), gamma)/S(j) ) / Norm;
423  matrix(j+3,i) += ( eI(l,h, u(j ),u(j ),u(j ), gamma)/S(j) ) / Norm;
424  }
425 
426  }
427 
428  TMatrixDSym D(nsplines);
429  for (int i=0;i<nsplines;++i) for (int j=0;j<=i;++j) {
430  D(i,j) = 0;
431  for (int k=0;k<nbins;++k) D(i,j) += matrix(i,k)*matrix(j,k)/(DY(k)*DY(k));
432  if (i!=j) D(j,i) = D(i,j);
433  }
434  TDecompBK solver(D);
435 
436  Y *= matrix;
437  TVectorD YY = Y;
438 
439  bool ok;
440  coefficients.ResizeTo(nsplines);
441  coefficients = solver.Solve(Y,ok);
442  if (!ok) {
443  std::cout << "WARNING: bad linear system solution... " << std::endl;
444  return -1;
445  }
446 
447  D.Invert();
448  covarianceMatrix.ResizeTo(D);
449  covarianceMatrix = D;
450 
451  double chisq = 0;
452  for (int i=0;i<nbins;++i) {
453  double y = hist->GetBinContent(1+i);
454  double dy = hist->GetBinError(1+i);
455  double f = 0; for (int j=0;j<nsplines;++j) f+=matrix(j,i)*coefficients(j);
456  double c = sqr( (y-f)/dy );
457  // double lo = hist->GetBinLowEdge(1+i);
458  // double hi = lo + hist->GetBinWidth(1+i);
459  // std::cout << " bin " << i << " [ " << lo << " , " << hi << " ] y = " << y << " dy = " << dy << " f = " << f << " chi^2 = " << c << std::endl;
460  chisq+=c;
461  }
462 
463  return chisq;
464  // silence compiler warning about fI being unused
465  (void) fI;
466 }
RooCubicSplineKnot::S_jk S_jk_sum(int i, const RooArgList &b) const
double S(int i) const
RooCubicSplineKnot::S2_jk S2_jk_sum(int i, const RooArgList &b1, const RooArgList &b2) const
double D(double u_, int i) const
RooCubicSplineKnot::S2_edge S2_jk_edge(bool left, const RooArgList &b1, const RooArgList &b2) const
double Q(int i) const
int index(double u_) const
double f(int i) const
RooCubicSplineKnot::S_edge S_jk_edge(bool left, const RooArgList &b) const
double h(int i, int j) const
static double sqr(double x)
void smooth(std::vector< double > &y, const std::vector< double > &dy, double lambda) const
double R(int i) const
double analyticalIntegral(const RooArgList &b) const
double u(int i) const
double expIntegral(const TH1 *hist, double gamma, TVectorD &coefficients, TMatrixD &covarianceMatrix) const
static const double m
void computeCoefficients(std::vector< double > &y, BoundaryConditions bc=BoundaryConditions()) const
double evaluate(double _u, const RooArgList &b) const
std::vector< double > _u
double P(int i) const
double r(int i) const
double lambda(double x, double y, double z)
Definition: lambda.h:8
void push_back(T &t, const typename T::value_type &a, const typename T::value_type &b, const typename T::value_type &c, const typename T::value_type &d)
Double_t get(const RooArgList &b, int i)
T::const_reference get(const T &t, int i, int j)
Double_t Q(double M, double m1, double m2)
T::const_reference get2(const T &t, int i, int j)