51 casadi_int casadi_blazing_low(T1 x,
const T1* grid, casadi_int ng,
52 casadi_int lookup_mode,
const T1* grid_inv) {
53 switch (lookup_mode) {
64 T1 intercept = grid_inv[0];
65 T1 slope = grid_inv[1];
66 ret = (casadi_int) (x * slope + intercept);
70 T1 dg = grid[ng-1] - g0;
71 ret = (casadi_int) ((x - g0) * (ng-1) / dg);
74 if (ret > ng-2) ret = ng-2;
94 if (grid[lo + len] < x) lo += len + 1;
98 if (lo > ng - 2) lo = ng - 2;
106 casadi_int n = ng - 2;
107 if (n <= 0)
return 0;
108 simde__m256d xv = simde_mm256_set1_pd(
static_cast<T1
>(x));
110 for (; i + 4 <= n; i += 4) {
111 simde__m256d gv = simde_mm256_loadu_pd((
const T1*)(grid + i + 1));
112 simde__m256d cmp = simde_mm256_cmp_pd(xv, gv, SIMDE_CMP_LT_OQ);
113 int m = simde_mm256_movemask_pd(cmp);
115 if (m)
return i + ((m & 1) ? 0 : (m & 2) ? 1 : (m & 4) ? 2 : 3);
118 if (x < grid[i+1])
return i;
128 template<
typename T1>
129 void casadi_blazing_printvec(
const simde__m256d* e) {
131 simde_mm256_storeu_pd(elements, *e);
132 printf(
"mm256d: <%.4f %.4f %.4f %.4f>\n", elements[0], elements[1], elements[2], elements[3]);
136 template<
typename T1>
137 void casadi_blazing_de_boor(T1 x,
const T1* knots,
const T1* inv1,
const T1* inv2,
const T1* inv3, simde__m256d* boor_d0, simde__m256d* boor_d1, simde__m256d* boor_d2,
const simde__m256d* boor_d3) {
138 simde__m256d x_ = simde_mm256_set1_pd(x);
139 simde__m256d zero = simde_mm256_set1_pd(0.0);
140 simde__m256d mask_end = simde_mm256_set_pd(0.0, -1.0, -1.0, -1.0);
144 simde__m256d boor_d3i_1 = simde_mm256_permute4x64_pd(*boor_d3, SIMDE_MM_SHUFFLE(3, 3, 2, 1));
145 boor_d3i_1 = simde_mm256_blendv_pd(zero, boor_d3i_1, mask_end);
147 simde__m256d knotsi = simde_mm256_loadu_pd(knots);
148 simde__m256d knotsi_2 = simde_mm256_loadu_pd(knots+2);
149 simde__m256d knotsi_3 = simde_mm256_loadu_pd(knots+3);
150 simde__m256d knotsi_4 = simde_mm256_loadu_pd(knots+4);
155 r = simde_mm256_mul_pd(simde_mm256_sub_pd(x_, knotsi), simde_mm256_loadu_pd(inv1));
156 *boor_d2 = simde_mm256_mul_pd(r, *boor_d3);
157 r = simde_mm256_mul_pd(simde_mm256_sub_pd(knotsi_2, x_), simde_mm256_loadu_pd(inv1 + 1));
158 *boor_d2 = simde_mm256_fmadd_pd(r, boor_d3i_1, *boor_d2);
161 simde__m256d boor_d2i_1 = simde_mm256_permute4x64_pd(*boor_d2, SIMDE_MM_SHUFFLE(3, 3, 2, 1));
162 boor_d2i_1 = simde_mm256_blendv_pd(zero, boor_d2i_1, mask_end);
165 r = simde_mm256_mul_pd(simde_mm256_sub_pd(x_, knotsi), simde_mm256_loadu_pd(inv2));
166 *boor_d1 = simde_mm256_mul_pd(r, *boor_d2);
167 r = simde_mm256_mul_pd(simde_mm256_sub_pd(knotsi_3, x_), simde_mm256_loadu_pd(inv2 + 1));
168 *boor_d1 = simde_mm256_fmadd_pd(r, boor_d2i_1, *boor_d1);
171 simde__m256d boor_d1i_1 = simde_mm256_permute4x64_pd(*boor_d1, SIMDE_MM_SHUFFLE(3, 3, 2, 1));
172 boor_d1i_1 = simde_mm256_blendv_pd(zero, boor_d1i_1, mask_end);
175 r = simde_mm256_mul_pd(simde_mm256_sub_pd(x_, knotsi), simde_mm256_loadu_pd(inv3));
176 *boor_d0 = simde_mm256_mul_pd(r, *boor_d1);
177 r = simde_mm256_mul_pd(simde_mm256_sub_pd(knotsi_4, x_), simde_mm256_loadu_pd(inv3 + 1));
178 *boor_d0 = simde_mm256_fmadd_pd(r, boor_d1i_1, *boor_d0);
181 simde__m256d knotsi_1 = simde_mm256_loadu_pd(knots+1);
182 simde__m256d bottom, bottom_mask;
184 bottom = simde_mm256_sub_pd(knotsi_1, knotsi);
185 bottom_mask = simde_mm256_cmp_pd(bottom, zero, SIMDE_CMP_EQ_OQ);
186 r = simde_mm256_div_pd(simde_mm256_sub_pd(x_, knotsi), bottom);
187 r = simde_mm256_blendv_pd(r, zero, bottom_mask);
188 *boor_d2 = simde_mm256_mul_pd(r, *boor_d3);
189 *boor_d2 = simde_mm256_blendv_pd(*boor_d2, zero, bottom_mask);
191 bottom = simde_mm256_sub_pd(knotsi_2, knotsi_1);
192 bottom_mask = simde_mm256_cmp_pd(bottom, zero, SIMDE_CMP_EQ_OQ);
193 r = simde_mm256_div_pd(simde_mm256_sub_pd(knotsi_2, x_), bottom);
194 r = simde_mm256_blendv_pd(r, zero, bottom_mask);
195 *boor_d2 = simde_mm256_fmadd_pd(r, boor_d3i_1, *boor_d2);
197 simde__m256d boor_d2i_1 = simde_mm256_permute4x64_pd(*boor_d2, SIMDE_MM_SHUFFLE(3, 3, 2, 1));
198 boor_d2i_1 = simde_mm256_blendv_pd(zero, boor_d2i_1, mask_end);
200 bottom = simde_mm256_sub_pd(knotsi_2, knotsi);
201 bottom_mask = simde_mm256_cmp_pd(bottom, zero, SIMDE_CMP_EQ_OQ);
202 r = simde_mm256_div_pd(simde_mm256_sub_pd(x_, knotsi), bottom);
203 r = simde_mm256_blendv_pd(r, zero, bottom_mask);
204 *boor_d1 = simde_mm256_mul_pd(r, *boor_d2);
205 *boor_d1 = simde_mm256_blendv_pd(*boor_d1, zero, bottom_mask);
207 bottom = simde_mm256_sub_pd(knotsi_3, knotsi_1);
208 bottom_mask = simde_mm256_cmp_pd(bottom, zero, SIMDE_CMP_EQ_OQ);
209 r = simde_mm256_div_pd(simde_mm256_sub_pd(knotsi_3, x_), bottom);
210 r = simde_mm256_blendv_pd(r, zero, bottom_mask);
211 *boor_d1 = simde_mm256_fmadd_pd(r, boor_d2i_1, *boor_d1);
213 simde__m256d boor_d1i_1 = simde_mm256_permute4x64_pd(*boor_d1, SIMDE_MM_SHUFFLE(3, 3, 2, 1));
214 boor_d1i_1 = simde_mm256_blendv_pd(zero, boor_d1i_1, mask_end);
216 bottom = simde_mm256_sub_pd(knotsi_3, knotsi);
217 bottom_mask = simde_mm256_cmp_pd(bottom, zero, SIMDE_CMP_EQ_OQ);
218 r = simde_mm256_div_pd(simde_mm256_sub_pd(x_, knotsi), bottom);
219 r = simde_mm256_blendv_pd(r, zero, bottom_mask);
220 *boor_d0 = simde_mm256_mul_pd(r, *boor_d1);
221 *boor_d0 = simde_mm256_blendv_pd(*boor_d0, zero, bottom_mask);
223 bottom = simde_mm256_sub_pd(knotsi_4, knotsi_1);
224 bottom_mask = simde_mm256_cmp_pd(bottom, zero, SIMDE_CMP_EQ_OQ);
225 r = simde_mm256_div_pd(simde_mm256_sub_pd(knotsi_4, x_), bottom);
226 r = simde_mm256_blendv_pd(r, zero, bottom_mask);
227 *boor_d0 = simde_mm256_fmadd_pd(r, boor_d1i_1, *boor_d0);
251 template<
typename T1>
252 void casadi_blazing_boor_der(simde__m256d* out,
const simde__m256d* boor,
253 const simde__m256d* scale) {
254 simde__m256d sb = simde_mm256_mul_pd(*boor, *scale);
255 simde__m256d shifted = simde_mm256_permute4x64_pd(sb, SIMDE_MM_SHUFFLE(2, 1, 0, 0));
256 shifted = simde_mm256_blend_pd(simde_mm256_setzero_pd(), shifted, 0xE);
257 *out = simde_mm256_sub_pd(shifted, sb);
263 template<
typename T1>
264 void casadi_blazing_shift_left(simde__m256d* out,
const simde__m256d* v) {
265 simde__m256d shifted = simde_mm256_permute4x64_pd(*v, SIMDE_MM_SHUFFLE(3, 3, 2, 1));
266 *out = simde_mm256_blend_pd(shifted, simde_mm256_setzero_pd(), 0x8);
273 template<
typename T1>
274 void casadi_blazing_knot_scale(simde__m256d* out,
const simde__m256d* degree,
275 const simde__m256d* t_hi,
const simde__m256d* t_lo) {
276 simde__m256d zero = simde_mm256_setzero_pd();
277 simde__m256d denom = simde_mm256_sub_pd(*t_hi, *t_lo);
278 simde__m256d denom_mask = simde_mm256_cmp_pd(denom, zero, SIMDE_CMP_EQ_OQ);
279 simde__m256d scale = simde_mm256_div_pd(*degree, denom);
280 *out = simde_mm256_blendv_pd(scale, zero, denom_mask);
299 template<
typename T1>
300 casadi_int casadi_blazing_boor_init(
301 T1 x,
const T1* all_knots,
const T1* dim_cache,
302 casadi_int knot_offset, casadi_int knot_offset_next,
303 casadi_int lookup_mode,
304 simde__m256d* d0, simde__m256d* d1, simde__m256d* d2,
305 const T1** inv2_out,
const T1** inv3_out) {
306 casadi_int degree = 3;
307 const T1* knots = all_knots + knot_offset;
308 casadi_int n_knots = knot_offset_next - knot_offset;
309 casadi_int n_b = n_knots - degree - 1;
311 const T1* grid_inv = dim_cache;
312 casadi_int L = casadi_blazing_low<T1>(x, knots + degree,
314 lookup_mode, grid_inv);
315 casadi_int start = L;
316 if (start > n_b - degree - 1) start = n_b - degree - 1;
318 simde__m256d d3 = simde_mm256_setzero_pd();
319 if (x >= knots[0] && x <= knots[n_knots-1]) {
321 d3 = simde_mm256_set1_pd(1.0);
322 }
else if (x == knots[n_knots-1]) {
323 d3 = simde_mm256_set_pd(1.0, 0.0, 0.0, 0.0);
324 }
else if (knots[L+degree] == x) {
325 d3 = simde_mm256_set_pd(0.0, 1.0, 0.0, 0.0);
327 d3 = simde_mm256_set_pd(1.0, 0.0, 0.0, 0.0);
330 const T1 *inv1 = 0, *inv2 = 0, *inv3 = 0;
333 const T1* inv_base = dim_cache + 2;
334 inv1 = inv_base + start;
335 inv2 = inv_base + n_knots + start;
336 inv3 = inv_base + 2*n_knots + start;
337 if (inv2_out) *inv2_out = inv_base + n_knots + start + 1;
338 if (inv3_out) *inv3_out = inv_base + 2*n_knots + start + 1;
340 if (inv2_out) *inv2_out = 0;
341 if (inv3_out) *inv3_out = 0;
343 casadi_blazing_de_boor(x, knots + start, inv1, inv2, inv3, d0, d1, d2, &d3);
351 template<
typename T1>
352 void casadi_blazing_dbasis(simde__m256d* out,
const simde__m256d* boor_d1,
353 const T1* t,
const T1* inv3) {
354 simde__m256d three = simde_mm256_set1_pd(3.0);
355 simde__m256d s1, t_hi, t_lo, shifted;
357 s1 = simde_mm256_mul_pd(three, simde_mm256_loadu_pd(inv3));
359 t_hi = simde_mm256_loadu_pd(t + 4);
360 t_lo = simde_mm256_loadu_pd(t + 1);
361 casadi_blazing_knot_scale<T1>(&s1, &three, &t_hi, &t_lo);
363 casadi_blazing_shift_left<T1>(&shifted, boor_d1);
364 casadi_blazing_boor_der<T1>(out, &shifted, &s1);
372 template<
typename T1>
373 void casadi_blazing_d2basis(simde__m256d* out,
const simde__m256d* boor_d2,
374 const T1* t,
const T1* inv2,
const T1* inv3) {
375 simde__m256d three = simde_mm256_set1_pd(3.0);
376 simde__m256d two = simde_mm256_set1_pd(2.0);
377 simde__m256d s1, s2, t_hi, t_lo, shifted, inner;
379 s1 = simde_mm256_mul_pd(three, simde_mm256_loadu_pd(inv3));
380 s2 = simde_mm256_mul_pd(two, simde_mm256_loadu_pd(inv2));
382 t_lo = simde_mm256_loadu_pd(t + 1);
383 t_hi = simde_mm256_loadu_pd(t + 4);
384 casadi_blazing_knot_scale<T1>(&s1, &three, &t_hi, &t_lo);
385 t_hi = simde_mm256_loadu_pd(t + 3);
386 casadi_blazing_knot_scale<T1>(&s2, &two, &t_hi, &t_lo);
388 casadi_blazing_shift_left<T1>(&shifted, boor_d2);
389 casadi_blazing_boor_der<T1>(&inner, &shifted, &s2);
390 casadi_blazing_shift_left<T1>(&shifted, &inner);
391 casadi_blazing_boor_der<T1>(out, &shifted, &s1);
398 template<
typename T1>
399 T1 casadi_blazing_hsum(
const simde__m256d* r) {
400 simde__m128d r0 = simde_mm256_castpd256_pd128(*r);
401 simde__m128d r1 = simde_mm256_extractf128_pd(*r, 1);
402 r0 = simde_mm_add_pd(r0, r1);
403 return simde_mm_cvtsd_f64(simde_mm_add_sd(r0, simde_mm_unpackhi_pd(r0, r0)));
414 template<
typename T1>
415 T1 casadi_blazing_tensor_ttv2(
const simde__m256d C[4],
416 const simde__m256d* a,
const simde__m256d* b) {
419 simde__m256d ab0 = simde_mm256_mul_pd(*a,
420 simde_mm256_permute4x64_pd(*b, SIMDE_MM_SHUFFLE(0, 0, 0, 0)));
421 simde__m256d ab1 = simde_mm256_mul_pd(*a,
422 simde_mm256_permute4x64_pd(*b, SIMDE_MM_SHUFFLE(1, 1, 1, 1)));
423 simde__m256d ab2 = simde_mm256_mul_pd(*a,
424 simde_mm256_permute4x64_pd(*b, SIMDE_MM_SHUFFLE(2, 2, 2, 2)));
425 simde__m256d ab3 = simde_mm256_mul_pd(*a,
426 simde_mm256_permute4x64_pd(*b, SIMDE_MM_SHUFFLE(3, 3, 3, 3)));
428 r = simde_mm256_mul_pd(ab0, C[0]);
429 r = simde_mm256_fmadd_pd(ab1, C[1], r);
430 r = simde_mm256_fmadd_pd(ab2, C[2], r);
431 r = simde_mm256_fmadd_pd(ab3, C[3], r);
433 return casadi_blazing_hsum<T1>(&r);
444 template<
typename T1>
445 T1 casadi_blazing_tensor_ttv3(
const simde__m256d C[16],
446 const simde__m256d* a,
const simde__m256d* b,
const simde__m256d* c) {
447 simde__m256d ab[4], cab[4], r;
450 simde__m256d b0 = simde_mm256_permute4x64_pd(*b, SIMDE_MM_SHUFFLE(0, 0, 0, 0));
451 simde__m256d b1 = simde_mm256_permute4x64_pd(*b, SIMDE_MM_SHUFFLE(1, 1, 1, 1));
452 simde__m256d b2 = simde_mm256_permute4x64_pd(*b, SIMDE_MM_SHUFFLE(2, 2, 2, 2));
453 simde__m256d b3 = simde_mm256_permute4x64_pd(*b, SIMDE_MM_SHUFFLE(3, 3, 3, 3));
454 ab[0] = simde_mm256_mul_pd(*a, b0);
455 ab[1] = simde_mm256_mul_pd(*a, b1);
456 ab[2] = simde_mm256_mul_pd(*a, b2);
457 ab[3] = simde_mm256_mul_pd(*a, b3);
459 for (i = 0; i < 4; ++i) {
460 cab[i] = simde_mm256_mul_pd(ab[0], C[4*i+0]);
461 cab[i] = simde_mm256_fmadd_pd(ab[1], C[4*i+1], cab[i]);
462 cab[i] = simde_mm256_fmadd_pd(ab[2], C[4*i+2], cab[i]);
463 cab[i] = simde_mm256_fmadd_pd(ab[3], C[4*i+3], cab[i]);
466 r = simde_mm256_mul_pd(cab[0],
467 simde_mm256_permute4x64_pd(*c, SIMDE_MM_SHUFFLE(0, 0, 0, 0)));
468 r = simde_mm256_fmadd_pd(cab[1],
469 simde_mm256_permute4x64_pd(*c, SIMDE_MM_SHUFFLE(1, 1, 1, 1)), r);
470 r = simde_mm256_fmadd_pd(cab[2],
471 simde_mm256_permute4x64_pd(*c, SIMDE_MM_SHUFFLE(2, 2, 2, 2)), r);
472 r = simde_mm256_fmadd_pd(cab[3],
473 simde_mm256_permute4x64_pd(*c, SIMDE_MM_SHUFFLE(3, 3, 3, 3)), r);
475 return casadi_blazing_hsum<T1>(&r);
488 template<
typename T1>
489 T1 casadi_blazing_tensor_ttv4(
const T1* coeffs,
490 casadi_int s1, casadi_int s2, casadi_int s3,
491 const simde__m256d* a,
const simde__m256d* b,
const simde__m256d* c,
492 const simde__m256d* d) {
496 simde__m256d dbr[4] = {
497 simde_mm256_permute4x64_pd(*d, SIMDE_MM_SHUFFLE(0, 0, 0, 0)),
498 simde_mm256_permute4x64_pd(*d, SIMDE_MM_SHUFFLE(1, 1, 1, 1)),
499 simde_mm256_permute4x64_pd(*d, SIMDE_MM_SHUFFLE(2, 2, 2, 2)),
500 simde_mm256_permute4x64_pd(*d, SIMDE_MM_SHUFFLE(3, 3, 3, 3))
505 for (
int idx = 0; idx < 16; ++idx) C[idx] = simde_mm256_setzero_pd();
506 for (l = 0; l < 4; ++l) {
507 const T1* base = coeffs + s3*l;
508 simde__m256d dl = dbr[l];
509 for (j = 0; j < 4; ++j) {
510 for (k = 0; k < 4; ++k) {
511 C[j+4*k] = simde_mm256_fmadd_pd(
512 simde_mm256_loadu_pd(base + s1*j + s2*k), dl, C[j+4*k]);
517 return casadi_blazing_tensor_ttv3<T1>(C, a, b, c);
530 template<
typename T1>
531 T1 casadi_blazing_tensor_ttv5(
const T1* coeffs,
532 casadi_int s1, casadi_int s2, casadi_int s3, casadi_int s4,
533 const simde__m256d* a,
const simde__m256d* b,
const simde__m256d* c,
534 const simde__m256d* d,
const simde__m256d* e) {
539 simde__m256d dbr[4] = {
540 simde_mm256_permute4x64_pd(*d, SIMDE_MM_SHUFFLE(0, 0, 0, 0)),
541 simde_mm256_permute4x64_pd(*d, SIMDE_MM_SHUFFLE(1, 1, 1, 1)),
542 simde_mm256_permute4x64_pd(*d, SIMDE_MM_SHUFFLE(2, 2, 2, 2)),
543 simde_mm256_permute4x64_pd(*d, SIMDE_MM_SHUFFLE(3, 3, 3, 3))
545 simde__m256d ebr[4] = {
546 simde_mm256_permute4x64_pd(*e, SIMDE_MM_SHUFFLE(0, 0, 0, 0)),
547 simde_mm256_permute4x64_pd(*e, SIMDE_MM_SHUFFLE(1, 1, 1, 1)),
548 simde_mm256_permute4x64_pd(*e, SIMDE_MM_SHUFFLE(2, 2, 2, 2)),
549 simde_mm256_permute4x64_pd(*e, SIMDE_MM_SHUFFLE(3, 3, 3, 3))
552 for (l = 0; l < 4; ++l) {
553 for (m = 0; m < 4; ++m) {
554 de[l+4*m] = simde_mm256_mul_pd(dbr[l], ebr[m]);
560 for (
int idx = 0; idx < 16; ++idx) C[idx] = simde_mm256_setzero_pd();
561 for (l = 0; l < 4; ++l) {
562 for (m = 0; m < 4; ++m) {
563 const T1* base = coeffs + s3*l + s4*m;
564 simde__m256d delm = de[l+4*m];
565 for (j = 0; j < 4; ++j) {
566 for (k = 0; k < 4; ++k) {
567 C[j+4*k] = simde_mm256_fmadd_pd(
568 simde_mm256_loadu_pd(base + s1*j + s2*k),
575 return casadi_blazing_tensor_ttv3<T1>(C, a, b, c);