FTQuant  0.1
RectBivariateSpline.cpp
Go to the documentation of this file.
2 
3 #include <iostream>
4 
5 std::vector<std::vector<std::array<double, 16>>>
7  auto coefs = this->a;
8  return coefs;
9 }
10 
11 int transpose(std::vector<std::vector<double>>& mat) {
12  std::vector<std::vector<double>> new_mat;
13  for (unsigned j = 0; j < mat[0].size(); ++j) {
14  std::vector<double> new_line;
15  for (unsigned i = 0; i < mat.size(); ++i) {
16  new_line.push_back(mat[i][j]);
17  }
18  new_mat.push_back(new_line);
19  }
20  mat = new_mat;
21  return 0;
22 }
23 
24 std::vector<std::vector<double>> diff(const std::vector<double>& x,
25  const std::vector<std::vector<double>>& f,
26  const int dim = 1) {
27  std::vector<std::vector<double>> der;
28  unsigned Ny = f[0].size();
29  unsigned Nx = f.size();
30  double tang;
31  double hi;
32 
33  if (dim == 0) {
34  double px;
35 
36  for (unsigned j = 0; j < Ny; ++j) {
37  std::vector<double> der_;
38  hi = x[1] - x[0];
39  tang = (f[1][j] - f[0][j]) / hi;
40  px = (f[1][j] - f[0][j] + tang * hi) / (2. * hi);
41  der_.push_back(px);
42  for (unsigned i = 1; i < Nx - 1; ++i) {
43  px = (f[i + 1][j] - f[i - 1][j]) / (x[i + 1] - x[i - 1]);
44  der_.push_back(px);
45  }
46  hi = x[Nx - 1] - x[Nx - 2];
47  tang = (f[Nx - 1][j] - f[Nx - 2][j]) / hi;
48  px = (tang * hi + f[Nx - 1][j] - f[Nx - 2][j]) / (2. * hi);
49 
50  der_.push_back(px);
51  der.push_back(der_);
52  }
53  transpose(der);
54  }
55  if (dim == 1) {
56  double py;
57 
58  for (unsigned i = 0; i < Nx; ++i) {
59  std::vector<double> der_;
60 
61  hi = x[1] - x[0];
62  tang = (f[i][1] - f[i][0]) / hi;
63  py = (f[i][1] - f[i][0] + tang * hi) / (2. * hi);
64  der_.push_back(py);
65  for (unsigned j = 1; j < Ny - 1; ++j) {
66  py = (f[i][j + 1] - f[i][j - 1]) / (x[j + 1] - x[j - 1]);
67  der_.push_back(py);
68  }
69  hi = x[Ny - 1] - x[Ny - 2];
70  tang = (f[i][Ny - 1] - f[i][Ny - 2]) / hi;
71  py = (f[i][Ny - 1] - f[i][Ny - 2] + tang * hi) / (2. * hi);
72  der_.push_back(py);
73  der.push_back(der_);
74  }
75  }
76 
77  return der;
78 }
79 
80 std::array<std::vector<std::vector<double>>, 3>
82  const std::vector<double>& x, const std::vector<double>& y,
83  const std::vector<std::vector<double>>& f) {
84  std::array<std::vector<std::vector<double>>, 3> der;
85  der[0] = diff(x, f, 0);
86  der[1] = diff(y, f, 1);
87  der[2] = diff(y, der[0], 1);
88  return der;
89 }
90 
91 void RectBivariateCubicSpline::fit(const std::vector<double>& x,
92  const std::vector<double>& y,
93  const std::vector<std::vector<double>>& f) {
94 
95  auto derivative = this->weighted_finite_derivative(x, y, f);
96  this->x = x;
97  this->y = y;
98  std::vector<std::vector<std::array<double, 16>>> coefs;
99  for (unsigned i = 0; i < x.size() - 1; ++i) {
100  double dx = x[i + 1] - x[i];
101  std::vector<std::array<double, 16>> coef;
102  for (unsigned j = 0; j < y.size() - 1; ++j) {
103  std::array<double, 16> x_;
104  std::array<double, 16> alpha;
105 
106  double dy = y[j + 1] - y[j];
107  double dxdy = dx * dy;
108 
109  x_[0] = f[i][j], x_[1] = f[i + 1][j], x_[2] = f[i][j + 1],
110  x_[3] = f[i + 1][j + 1];
111  x_[4] = derivative[0][i][j] * dx, x_[5] = derivative[0][i + 1][j] * dx,
112  x_[6] = derivative[0][i][j + 1] * dx,
113  x_[7] = derivative[0][i + 1][j + 1] * dx;
114  x_[8] = derivative[1][i][j] * dy, x_[9] = derivative[1][i + 1][j] * dy,
115  x_[10] = derivative[1][i][j + 1] * dy,
116  x_[11] = derivative[1][i + 1][j + 1] * dy;
117  x_[12] = derivative[2][i][j] * dxdy,
118  x_[13] = derivative[2][i + 1][j] * dxdy,
119  x_[14] = derivative[2][i][j + 1] * dxdy,
120  x_[15] = derivative[2][i + 1][j + 1] * dxdy;
121 
122  alpha[0] = x_[0], alpha[1] = x_[4],
123  alpha[2] = 3 * (x_[1] - x_[0]) - 2. * x_[4] - x_[5];
124  alpha[3] = 2. * (x_[0] - x_[1]) + x_[4] + x_[5], alpha[4] = x_[8],
125  alpha[5] = x_[12];
126  alpha[6] = 3. * (x_[9] - x_[8]) - 2. * x_[12] - x_[13],
127  alpha[7] = 2. * (x_[8] - x_[9]) + x_[12] + x_[13];
128  alpha[8] = 3. * (x_[2] - x_[0]) - 2. * x_[8] - x_[10],
129  alpha[9] = 3. * (x_[6] - x_[4]) - 2. * x_[12] - x_[14];
130  alpha[10] = 9. * (x_[0] - x_[1] - x_[2] + x_[3]) +
131  6. * (x_[4] - x_[6] + x_[8] - x_[9]) +
132  3. * (x_[5] - x_[7] + x_[10] - x_[11]) + 4. * x_[12] +
133  2. * (x_[13] + x_[14]) + x_[15];
134  alpha[11] = 6. * (-x_[0] + x_[1] + x_[2] - x_[3]) +
135  3. * (-x_[4] - x_[5] + x_[6] + x_[7]) +
136  4. * (-x_[8] + x_[9]) +
137  2. * (x_[11] - x_[10] - x_[12] - x_[13]) - x_[14] - x_[15];
138  alpha[12] = 2. * (x_[0] - x_[2]) + x_[8] + x_[10],
139  alpha[13] = 2. * (x_[4] - x_[6]) + x_[12] + x_[14];
140  alpha[14] = 6. * (-x_[0] + x_[1] + x_[2] - x_[3]) +
141  4. * (-x_[4] + x_[6]) + 2. * (-x_[5] + x_[7]) +
142  3. * (-x_[8] + x_[9] - x_[10] + x_[11]) +
143  2. * (-x_[12] - x_[14]) - x_[13] - x_[15];
144  alpha[15] = 4. * (x_[0] - x_[1] - x_[2] + x_[3]) +
145  2. * (x_[4] + x_[5] - x_[6] - x_[7] + x_[8] - x_[9] + x_[10] -
146  x_[11]) +
147  x_[12] + x_[13] + x_[14] + x_[15];
148 
149  coef.push_back(alpha);
150  }
151  coefs.push_back(coef);
152  }
153  this->a = coefs;
154  return;
155 }
156 
157 int binsearch(const std::vector<double>& x, const double value) {
158 
159  if (value >= x[x.size() - 1])
160  return x.size() - 1;
161  if (value <= x[0])
162  return -1;
163 
164  int RB = x.size() - 1;
165  int LB = 0;
166  int mid;
167  double d;
168 
169  while (LB <= RB) {
170  mid = (LB + RB) >> 1;
171  d = x[mid];
172  if (value < d && value >= x[mid - 1])
173  return mid - 1;
174  else if (value >= d && value < x[mid + 1])
175  return mid;
176  else if (d < value)
177  LB = mid + 1;
178  else
179  RB = mid - 1;
180  }
181  return 0;
182 }
183 
184 double RectBivariateCubicSpline::eval(double x_, double y_) const {
185  int i0 = binsearch(this->x, x_);
186  int j0 = binsearch(this->y, y_);
187  double x_ev, y_ev;
188  if (x_ <= this->x[0]) {
189  x_ev = this->x[0], i0 = 0;
190  } else if (x_ >= this->x[this->x.size() - 1]) {
191  x_ev = this->x[this->x.size() - 1], i0 = this->x.size() - 2;
192  } else {
193  x_ev = x_;
194  }
195  if (y_ <= this->y[0]) {
196  y_ev = this->y[0], j0 = 0;
197  } else if (y_ >= this->y[this->y.size() - 1]) {
198  y_ev = this->y[this->y.size() - 1], j0 = this->y.size() - 2;
199  } else {
200  y_ev = y_;
201  }
202  auto coef = this->a[i0][j0];
203  double dx = this->x[i0 + 1] - this->x[i0];
204  double dy = this->y[j0 + 1] - this->y[j0];
205  double xbar = (x_ev - this->x[i0]) / dx;
206  double ybar = (y_ev - this->y[j0]) / dy;
207 
208  std::array<double, 4> xi{1., xbar, xbar * xbar, xbar * xbar * xbar};
209  std::array<double, 4> yi{1., ybar, ybar * ybar, ybar * ybar * ybar};
210 
211  double sum = 0;
212  // std::cout<<"i0: "<<i0<<" j0: "<< j0 <<" x_ev: "<<x_ev<<" y_ev: "<<y_ev<<'\n';
213  // std::cout<<"xbar: "<<xbar<<" ybar: "<<ybar<<'\n';
214 
215  for (int j = 0; j < 4; ++j)
216  for (int i = 0; i < 4; ++i)
217  sum += coef[4 * j + i] * xi[i] * yi[j];
218  return sum;
219 }
220 
221 double RectBivariateCubicSpline::derivative_x(double x_, double y_) const {
222  int i0 = binsearch(this->x, x_);
223  int j0 = binsearch(this->y, y_);
224  double x_ev, y_ev;
225  if (x_ <= this->x[0]) {
226  x_ev = this->x[0], i0 = 0;
227  } else if (x_ >= this->x[this->x.size() - 1]) {
228  x_ev = this->x[this->x.size() - 1], i0 = this->x.size() - 2;
229  } else {
230  x_ev = x_;
231  }
232  if (y_ <= this->y[0]) {
233  y_ev = this->y[0], j0 = 0;
234  } else if (y_ >= this->y[this->y.size() - 1]) {
235  y_ev = this->y[this->y.size() - 1], j0 = this->y.size() - 2;
236  } else {
237  y_ev = y_;
238  }
239 
240  auto coef = this->a[i0][j0];
241  double dx = this->x[i0 + 1] - this->x[i0];
242  double dy = this->y[j0 + 1] - this->y[j0];
243  double xbar = (x_ev - this->x[i0]) / dx;
244  double ybar = (y_ev - this->y[j0]) / dy;
245 
246  std::array<double, 4> xi{0., 1. / dx, 2. * xbar / dx, 3. * xbar * xbar / dx};
247  std::array<double, 4> yi{1., ybar, ybar * ybar, ybar * ybar * ybar};
248 
249  double sum = 0;
250 
251  for (int j = 0; j < 4; ++j)
252  for (int i = 1; i < 4; ++i)
253  sum += coef[4 * j + i] * xi[i] * yi[j];
254  return sum;
255 }
256 
257 double RectBivariateCubicSpline::derivative_y(double x_, double y_) const {
258  int i0 = binsearch(this->x, x_);
259  int j0 = binsearch(this->y, y_);
260  double x_ev, y_ev;
261  if (x_ <= this->x[0]) {
262  x_ev = this->x[0], i0 = 0;
263  } else if (x_ >= this->x[this->x.size() - 1]) {
264  x_ev = this->x[this->x.size() - 1], i0 = this->x.size() - 2;
265  } else {
266  x_ev = x_;
267  }
268  if (y_ <= this->y[0]) {
269  y_ev = this->y[0], j0 = 0;
270  } else if (y_ >= this->y[this->y.size() - 1]) {
271  y_ev = this->y[this->y.size() - 1], j0 = this->y.size() - 2;
272  } else {
273  y_ev = y_;
274  }
275 
276  auto coef = this->a[i0][j0];
277  double dx = this->x[i0 + 1] - this->x[i0];
278  double dy = this->y[j0 + 1] - this->y[j0];
279  double xbar = (x_ev - this->x[i0]) / dx;
280  double ybar = (y_ev - this->y[j0]) / dy;
281 
282  std::array<double, 4> xi{1., xbar, xbar * xbar, xbar * xbar * xbar};
283  std::array<double, 4> yi{0., 1. / dy, 2. * ybar / dy, 3. * ybar * ybar / dy};
284 
285  double sum = 0.;
286 
287  for (int j = 1; j < 4; ++j)
288  for (int i = 0; i < 4; ++i)
289  sum += coef[4 * j + i] * xi[i] * yi[j];
290  return sum;
291 }
292 
293 double RectBivariateCubicSpline::derivative_xx(double x_, double y_) const {
294  int i0 = binsearch(this->x, x_);
295  int j0 = binsearch(this->y, y_);
296  double x_ev, y_ev;
297  if (x_ <= this->x[0]) {
298  x_ev = this->x[0], i0 = 0;
299  } else if (x_ >= this->x[this->x.size() - 1]) {
300  x_ev = this->x[this->x.size() - 1], i0 = this->x.size() - 2;
301  } else {
302  x_ev = x_;
303  }
304  if (y_ <= this->y[0]) {
305  y_ev = this->y[0], j0 = 0;
306  } else if (y_ >= this->y[this->y.size() - 1]) {
307  y_ev = this->y[this->y.size() - 1], j0 = this->y.size() - 2;
308  } else {
309  y_ev = y_;
310  }
311 
312  auto coef = this->a[i0][j0];
313  double dx = this->x[i0 + 1] - this->x[i0];
314  double dy = this->y[j0 + 1] - this->y[j0];
315  double xbar = (x_ev - this->x[i0]) / dx;
316  double ybar = (y_ev - this->y[j0]) / dy;
317 
318  std::array<double, 4> xi{0., 0., 2. / (dx * dx), 6. * xbar / (dx * dx)};
319  std::array<double, 4> yi{1., ybar, ybar * ybar, ybar * ybar * ybar};
320 
321  double sum = 0;
322 
323  for (int j = 0; j < 4; ++j)
324  for (int i = 2; i < 4; ++i)
325  sum += coef[4 * j + i] * xi[i] * yi[j];
326  return sum;
327 }
328 
329 double RectBivariateCubicSpline::derivative_yy(double x_, double y_) const {
330  int i0 = binsearch(this->x, x_);
331  int j0 = binsearch(this->y, y_);
332  double x_ev, y_ev;
333  if (x_ <= this->x[0]) {
334  x_ev = this->x[0], i0 = 0;
335  } else if (x_ >= this->x[this->x.size() - 1]) {
336  x_ev = this->x[this->x.size() - 1], i0 = this->x.size() - 2;
337  } else {
338  x_ev = x_;
339  }
340  if (y_ <= this->y[0]) {
341  y_ev = this->y[0], j0 = 0;
342  } else if (y_ >= this->y[this->y.size() - 1]) {
343  y_ev = this->y[this->y.size() - 1], j0 = this->y.size() - 2;
344  } else {
345  y_ev = y_;
346  }
347 
348  auto coef = this->a[i0][j0];
349  double dx = this->x[i0 + 1] - this->x[i0];
350  double dy = this->y[j0 + 1] - this->y[j0];
351  double xbar = (x_ev - this->x[i0]) / dx;
352  double ybar = (y_ev - this->y[j0]) / dy;
353 
354  std::array<double, 4> xi{1., xbar, xbar * xbar, xbar * xbar * xbar};
355  std::array<double, 4> yi{0., 0., 2. / (dy * dy), 6. * ybar / (dy * dy)};
356 
357  double sum = 0;
358 
359  for (int j = 2; j < 4; ++j)
360  for (int i = 0; i < 4; ++i)
361  sum += coef[4 * j + i] * xi[i] * yi[j];
362  return sum;
363 }
364 
365 double RectBivariateCubicSpline::derivative_xy(double x_, double y_) const {
366  int i0 = binsearch(this->x, x_);
367  int j0 = binsearch(this->y, y_);
368  double x_ev, y_ev;
369  if (x_ <= this->x[0]) {
370  x_ev = this->x[0], i0 = 0;
371  } else if (x_ >= this->x[this->x.size() - 1]) {
372  x_ev = this->x[this->x.size() - 1], i0 = this->x.size() - 2;
373  } else {
374  x_ev = x_;
375  }
376  if (y_ <= this->y[0]) {
377  y_ev = this->y[0], j0 = 0;
378  } else if (y_ >= this->y[this->y.size() - 1]) {
379  y_ev = this->y[this->y.size() - 1], j0 = this->y.size() - 2;
380  } else {
381  y_ev = y_;
382  }
383 
384  auto coef = this->a[i0][j0];
385  double dx = this->x[i0 + 1] - this->x[i0];
386  double dy = this->y[j0 + 1] - this->y[j0];
387  double xbar = (x_ev - this->x[i0]) / dx;
388  double ybar = (y_ev - this->y[j0]) / dy;
389 
390  std::array<double, 4> xi{0., 1. / dx, 2. * xbar / dx, 3. * xbar * xbar / dx};
391  std::array<double, 4> yi{0., 1. / dy, 2. * ybar / dy, 3. * ybar * ybar / dy};
392 
393  double sum = 0.;
394 
395  for (int j = 1; j < 4; ++j)
396  for (int i = 1; i < 4; ++i)
397  sum += coef[4 * j + i] * xi[i] * yi[j];
398  return sum;
399 }
400 
402  int dx, int dy) const {
403  if (dx == 1 && dy == 0)
404  return derivative_x(x_, y_);
405  if (dx == 2 && dy == 0)
406  return derivative_xx(x_, y_);
407  if (dx == 0 && dy == 1)
408  return derivative_y(x_, y_);
409  if (dx == 0 && dy == 2)
410  return derivative_yy(x_, y_);
411  if (dx == 1 && dy == 1)
412  return derivative_xy(x_, y_);
413  std::cout << "dx + dy must be less than 2"
414  << "\n";
415  return -1.;
416 }
int transpose(std::vector< std::vector< double >> &mat)
std::vector< std::vector< double > > diff(const std::vector< double > &x, const std::vector< std::vector< double >> &f, const int dim=1)
int binsearch(const std::vector< double > &x, const double value)
void fit(const std::vector< double > &x, const std::vector< double > &y, const std::vector< std::vector< double >> &f)
double derivative_yy(double x_, double y_) const
double derivative_xy(double x_, double y_) const
double derivative_x(double x_, double y_) const
double derivative_y(double x_, double y_) const
double partial_derivative(double x_, double y_, int dx, int dy) const
std::vector< std::vector< std::array< double, 16 > > > get_coefs() const
std::array< std::vector< std::vector< double > >, 3 > weighted_finite_derivative(const std::vector< double > &x, const std::vector< double > &y, const std::vector< std::vector< double >> &f)
double eval(double x_, double y_) const
double derivative_xx(double x_, double y_) const