casadi_blazing_2d_boor_eval.hpp
1 //
2 // MIT No Attribution
3 //
4 // Copyright (C) 2010-2023 Joel Andersson, Joris Gillis, Moritz Diehl, KU Leuven.
5 //
6 // Permission is hereby granted, free of charge, to any person obtaining a copy of this
7 // software and associated documentation files (the "Software"), to deal in the Software
8 // without restriction, including without limitation the rights to use, copy, modify,
9 // merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
10 // permit persons to whom the Software is furnished to do so.
11 //
12 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
13 // INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
14 // PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
15 // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
16 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
17 // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
18 //
19 
20 // C-REPLACE "casadi_blazing_boor_init<T1>" "casadi_blazing_boor_init"
21 // C-REPLACE "casadi_blazing_dbasis<T1>" "casadi_blazing_dbasis"
22 // C-REPLACE "casadi_blazing_d2basis<T1>" "casadi_blazing_d2basis"
23 // C-REPLACE "casadi_blazing_tensor_ttv2<T1>" "casadi_blazing_tensor_ttv2"
24 
25 // SYMBOL "blazing_2d_boor_eval"
26 template<typename T1>
27 void casadi_blazing_2d_boor_eval(T1* f, T1* J, T1* H, const T1* all_knots, const T1* all_knots_cache, const casadi_int* offset, const T1* c, const T1* dc, const T1* ddc, const T1* all_x, const casadi_int* lookup_mode, casadi_int* iw, T1* w) { // NOLINT(whitespace/line_length)
28  casadi_int *starts;
29  iw+=2+1;
30  starts = iw;
31 
32  casadi_int stride1 = offset[1]-offset[0]-4;
33 
34  simde__m256d zero = simde_mm256_set1_pd(0.0);
35 
36  // Per-dimension de Boor evaluation
37  simde__m256d d0[2], d1[2], d2[2];
38  const T1* inv2[2] = {0, 0}; const T1* inv3[2] = {0, 0};
39 
40  // Per-dim cache slice: [intercept, slope, inv1[n_k], inv2[n_k], inv3[n_k]],
41  // size 2 + 3*n_k per dim. Accumulate as we advance through dims.
42  const T1* dim_cache0 = all_knots_cache;
43  const T1* dim_cache1 = all_knots_cache
44  ? all_knots_cache + 2 + 3*(offset[1] - offset[0]) : 0;
45  starts[0] = casadi_blazing_boor_init<T1>(all_x[0], all_knots, dim_cache0,
46  offset[0], offset[1], lookup_mode[0], &d0[0], &d1[0], &d2[0], &inv2[0], &inv3[0]);
47  starts[1] = casadi_blazing_boor_init<T1>(all_x[1], all_knots, dim_cache1,
48  offset[1], offset[2], lookup_mode[1], &d0[1], &d1[1], &d2[1], &inv2[1], &inv3[1]);
49 
50  // Load coefficient sub-tensor (same C used for value and all NPC derivatives)
51  simde__m256d C[4];
52  for (int j=0;j<4;++j) {
53  C[j] = simde_mm256_loadu_pd(c+(starts[1]+j)*stride1+starts[0]);
54  }
55 
56  if (f) {
57  f[0] = casadi_blazing_tensor_ttv2<T1>(C, &d0[0], &d0[1]);
58  }
59 
60  if (J || H) {
61  const T1* t0 = all_knots + offset[0] + starts[0];
62  const T1* t1 = all_knots + offset[1] + starts[1];
63 
64  // Effective first-derivative basis: raw for precomputed, summation-by-parts for NPC
65  simde__m256d J0, J1;
66  if (dc) {
67  J0 = d1[0];
68  J1 = d1[1];
69  } else {
70  casadi_blazing_dbasis<T1>(&J0, &d1[0], t0, inv3[0]);
71  casadi_blazing_dbasis<T1>(&J1, &d1[1], t1, inv3[1]);
72  }
73 
74  // First derivatives
75  if (J) {
76  if (dc) {
77  stride1 = offset[1]-offset[0]-4-1;
78  for (int j=0;j<4;++j) {
79  C[j] = simde_mm256_loadu_pd(dc+(starts[1]+j)*stride1+starts[0]-1);
80  }
81  dc += stride1*(offset[2]-offset[1]-4);
82  }
83  J[0] = casadi_blazing_tensor_ttv2<T1>(C, &J0, &d0[1]);
84 
85  if (dc) {
86  stride1 = offset[1]-offset[0]-4;
87  for (int j=0;j<4;++j) {
88  if (j==0) {
89  C[j] = zero;
90  } else {
91  C[j] = simde_mm256_loadu_pd(dc+(starts[1]+j-1)*stride1+starts[0]);
92  }
93  }
94  }
95  J[1] = casadi_blazing_tensor_ttv2<T1>(C, &d0[0], &J1);
96  }
97 
98  // Second derivatives
99  if (H) {
100  // Effective second-derivative basis
101  simde__m256d H0, H1;
102  if (ddc) {
103  H0 = d2[0];
104  H1 = d2[1];
105  } else {
106  casadi_blazing_d2basis<T1>(&H0, &d2[0], t0, inv2[0], inv3[0]);
107  casadi_blazing_d2basis<T1>(&H1, &d2[1], t1, inv2[1], inv3[1]);
108  }
109 
110  // Diagonal
111  if (ddc) {
112  stride1 = offset[1]-offset[0]-4-2;
113  for (int j=0;j<4;++j)
114  C[j] = simde_mm256_loadu_pd(ddc+(starts[1]+j)*stride1+starts[0]-2);
115  ddc += stride1*(offset[2]-offset[1]-4);
116  }
117  H[0] = casadi_blazing_tensor_ttv2<T1>(C, &H0, &d0[1]);
118 
119  if (ddc) {
120  stride1 = offset[1]-offset[0]-4;
121  for (int j=0;j<4;++j) {
122  if (j<=1) {
123  C[j] = zero;
124  } else {
125  C[j] = simde_mm256_loadu_pd(ddc+(starts[1]+j-2)*stride1+starts[0]);
126  }
127  }
128  ddc += stride1*(offset[2]-offset[1]-4-2);
129  }
130  H[3] = casadi_blazing_tensor_ttv2<T1>(C, &d0[0], &H1);
131 
132  // Off-diagonal
133  if (ddc) {
134  stride1 = offset[1]-offset[0]-5;
135  for (int j=0;j<4;++j) {
136  if (j==0) {
137  C[j] = zero;
138  } else {
139  C[j] = simde_mm256_loadu_pd(ddc+(starts[1]+j-1)*stride1+starts[0]-1);
140  }
141  }
142  }
143  H[1] = H[2] = casadi_blazing_tensor_ttv2<T1>(C, &J0, &J1);
144  }
145  }
146 }