SuperDex Physics C++ API
Loading...
Searching...
No Matches
vmatrix.h
Go to the documentation of this file.
1/*
2 * Copyright (c) Meta Platforms, Inc. and affiliates.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#pragma once
18
22
23namespace superdex {
24
25// Common SIMD array types.
26
27// NOTE: While most of these are redundant (multiple matrix
28// shapes fallback to the same underlying NdArray type),
29// they are mostly used to convey intention and expected
30// data in the functions using them.
31
32/**
33 Special case for the SIMD representation of a 2x2 matrix.
34 Stores the matrix entries following a flattened row-major
35 layout. That is, in the order (a, c, d, b), corresponding
36 to the matrix:
37 | a c |
38 | d b |
39 */
40
43
44/**
45 SIMD representation of a NxM matrices. Stores the matrix entries in N vectors following the
46 standard-row major layout, with as many padding entries as necessary (ok, only either 0 or 1).
47 */
48
56
64
66
67/**
68 SIMD representation of tensors.
69 */
73
76
77/**
78 Special case for the SIMD representation of a 2x2 symmetric
79 matrix. Stores the matrix entries in the order (a, c, b, ?),
80 corresponding to the symmetric matrix:
81 | a c |
82 | c b |
83 */
86
87/**
88 Special case for the SIMD representation of a 3x3 symmetric
89 matrix. Stores the matrix entries in two vectors, containing
90 the diagonal terms (a, b, c, ?) and the off-diagonal terms
91 (d, e, f, ?). Corresponds to the symmetric matrix:
92 | a d e |
93 | d b f |
94 | e f c |
95 */
98
99// Vec4r full matrix <--> Vec4r sym matrix conversion
100template <typename T>
102 NdArray<Simd<T, 4>, 2> const& m);
103template <typename T>
105template <typename T>
107 NdArray<Simd<T, 4>, 3> const& m);
108template <typename T>
110
111// NdArray <--> Vec4r conversion
112template <typename T>
114template <typename T>
116template <typename T>
118template <typename T>
120template <typename T>
122template <typename T>
124template <typename T>
126template <typename T>
128template <typename T>
129[[nodiscard]] MOCHI_FORCE_INLINE Simd<T, 4> ToSimd(NdArray<T, 2> const& v, T z = T(0), T w = T(0));
130template <typename T>
131[[nodiscard]] MOCHI_FORCE_INLINE Simd<T, 4> ToSimd(NdArray<T, 3> const& v, T w = T(0));
132template <typename T>
134template <typename T>
136template <typename T>
138template <typename T>
140template <typename T>
142template <typename T>
144template <typename T>
146 NdArray<Simd<T, 4>, 3, 3, 3> const& t);
147template <typename T>
149 NdArray<T, 3, 3, 3, 3> const& t);
150template <typename T>
151[[nodiscard]] MOCHI_FORCE_INLINE Simd<T, 4> ToSimdFromSymComponents2x2(T a00, T a01, T a11);
152
153/**************************************************************************************************
154 NdArray conversions for simd <--> scalar
155
156 If the last dimension != 4, then the Simd<T, 4> representation will have padding.
157 The value of the padding could be anything. Don't assume zero.
158*/
159
160// Load a dense (D0 x D1) row-major matrix into an array of Simd<T, 4> for SIMD operations.
161template <size_t D0, size_t D1, typename T>
163
164// Load a dense (D0 x D1) row-major matrix into an array of Simd<T, 4> for SIMD operations.
165// For this overload, the dense matrix is represented as flat Span of (D0 * D1) values.
166template <size_t D0, size_t D1, typename T, typename ConstOrNonConstT>
168
169// Load a dense (D0 x D1) row-major matrix into an array of Simd<T, 4> for SIMD operations.
170// For this overload, the dense matrix is represented as flat pointer.
171template <size_t D0, size_t D1, typename T>
172MOCHI_FORCE_INLINE void LoadMatrix(NdArray<Simd<T, 4>, D0>& out, T const* x);
173
174// Load a dense 4D row-major matrix into a 3D array of Simd<T, 4> for SIMD operations.
175template <size_t D0, size_t D1, size_t D2, size_t D3, typename T>
177 NdArray<Simd<T, 4>, D0, D1, D2>& out,
179
180// Load a dense 4D row-major matrix into a 3D array of Simd<T, 4> for SIMD operations.
181// For this overload, the dense matrix is represented as flat pointer.
182template <size_t D0, size_t D1, size_t D2, size_t D3, typename T>
183MOCHI_FORCE_INLINE void LoadMatrix(NdArray<Simd<T, 4>, D0, D1, D2>& out, T const* x);
184
185// Load a dense (D0 x D1) row-major submatrix using an array of Simd<T, 4> (D1 <= 4, skipping
186// padding if D1 != 4) from a dense (D2 x D3) row-major matrix at the the specified row and column.
187template <size_t D0, size_t D1, size_t D2, size_t D3, typename T>
189LoadSubmatrix(NdArray<Simd<T, 4>, D0>& out, Int2 coords, NdArray<T, D2, D3> const& x);
190
191// Load a dense (D0 x D1) row-major submatrix using an array of Simd<T, 4> (D1 <= 4, skipping
192// padding if D1 != 4) from a dense (D2 x D3) row-major matrix at the the specified row and column.
193template <size_t D0, size_t D1, size_t D2, size_t D3, typename T>
194MOCHI_FORCE_INLINE void LoadSubmatrix(NdArray<Simd<T, 4>, D0>& out, Int2 coords, T const* x);
195
196// Load a dense (D0 x D1) row-major submatrix using an array of Simd<T, 4> (D1 <= 4, skipping
197// padding if D1 != 4) from a dense (D2 x D3) row-major matrix at the the specified row and column.
198template <size_t D0, size_t D1, size_t D2, size_t D3, typename T>
200
201// Store a dense (D0 x D1) row-major matrix using an array of Simd<T, 4> (D1 <= 4, skipping padding
202// if D1 != 4).
203template <size_t D0, size_t D1, typename T>
205
206// Store a dense (D0 x D1) row-major matrix using an array of Simd<T, 4> (D1 <= 4, skipping padding
207// if D1 != 4). For this overload, the result is written to a flat pointer (memory should be
208// allocated).
209template <size_t D0, size_t D1, typename T>
210MOCHI_FORCE_INLINE void StoreMatrix(T* outData, NdArray<Simd<T, 4>, D0> const& x);
211
212// Store a dense (D0 x D1) row-major matrix using an array of Simd<T, 4> (D1 <= 4, skipping padding
213// if D1 != 4). For this overload, the result is written to a flat Span of (D0 * D1) values.
214template <size_t D0, size_t D1, typename T>
216
217// Store a dense 4D row-major matrix using a 3D array of Simd<T, 4>, (D3 <= 4, skipping padding if
218// D3 != 4).
219template <size_t D0, size_t D1, size_t D2, size_t D3, typename T>
222 NdArray<Simd<T, 4>, D0, D1, D2> const& x);
223
224// Store a dense (D0 x D1) row-major submatrix using an array of Simd<T, 4> (D1 <= 4, skipping
225// padding if D1 != 4) in a dense (D2 x D3) row-major matrix at the the specified row and column.
226template <size_t D0, size_t D1, size_t D2, size_t D3, typename T>
228StoreSubmatrix(NdArray<T, D2, D3>& out, Int2 coords, NdArray<Simd<T, 4>, D0> const& x);
229
230// Store a dense (D0 x D1) row-major submatrix using an array of Simd<T, 4> (D1 <= 4, skipping
231// padding if D1 != 4) in a dense (D2 x D3) row-major matrix at the the specified row and column.
232template <size_t D0, size_t D1, size_t D2, size_t D3, typename T>
233MOCHI_FORCE_INLINE void StoreSubmatrix(T* out, Int2 coords, NdArray<Simd<T, 4>, D0> const& x);
234
235// Store a dense (D0 x D1) row-major submatrix using an array of Simd<T, 4> (D1 <= 4, skipping
236// padding if D1 != 4) in a dense (D2 x D3) row-major matrix at the the specified row and column.
237template <size_t D0, size_t D1, size_t D2, size_t D3, typename T>
238MOCHI_FORCE_INLINE void StoreSubmatrix(Span<T> out, Int2 coords, NdArray<Simd<T, 4>, D0> const& x);
239
240#define MOCHI_DETAILS_UNROLL_OP_SCALAR_ARRAY(result, OP, a, b) \
241 if constexpr (D0 <= 4) { \
242 (result)[0] = a OP b[0]; \
243 if constexpr (D0 > 1) { \
244 (result)[1] = a OP b[1]; \
245 } \
246 if constexpr (D0 > 2) { \
247 (result)[2] = a OP b[2]; \
248 } \
249 if constexpr (D0 > 3) { \
250 (result)[3] = a OP b[3]; \
251 } \
252 } else { \
253 for (size_t i = 0; i < D0; ++i) { \
254 (result)[i] = a OP b[i]; \
255 } \
256 }
257
258// NdArray memberwise math operators (+=, -=, *=, /=, +, -, *, /)
259#define MOCHI_DETAILS_NDARRAY_SIMD_MEMBERWISE_OP(OP_EQ, OP) \
260 template <typename T, int N, size_t D0, size_t... DIMS> \
261 MOCHI_FORCE_INLINE constexpr NdArray<Simd<T, N>, D0, DIMS...> operator OP( \
262 NdArray<Simd<T, N>, D0, DIMS...> const& lhs, T rhs) { \
263 return lhs OP Simd<T, N>(rhs); /* NdArray<Simd> OP Simd */ \
264 } \
265 template <typename T, int N, size_t D0, size_t... DIMS> \
266 MOCHI_FORCE_INLINE constexpr NdArray<Simd<T, N>, D0, DIMS...> operator OP( \
267 T lhs, NdArray<Simd<T, N>, D0, DIMS...> const& rhs) { \
268 NdArray<Simd<T, N>, D0, DIMS...> result{}; \
269 MOCHI_DETAILS_UNROLL_OP_SCALAR_ARRAY( \
270 result, OP, (Simd<T, N>{lhs}), rhs); /* Simd OP NdArray<Simd> */ \
271 return result; \
272 }
273
278
279#undef MOCHI_DETAILS_NDARRAY_SIMD_MEMBERWISE_OP
280#undef MOCHI_DETAILS_UNROLL_OP_SCALAR_ARRAY
281
282/**************************************************************************************************
283 NdArray MOCHI_FORCE_INLINEs (Simd specialization)
284*/
285
286template <typename T, size_t D0>
287[[nodiscard]] MOCHI_FORCE_INLINE constexpr bool operator==(
288 NdArray<Simd<T, 4>, D0> const& lhs,
289 NdArray<Simd<T, 4>, D0> const& rhs) {
290 auto isEqual = VEqual(lhs[0], rhs[0]);
291 if constexpr (D0 > 1) {
292 isEqual &= VEqual(lhs[1], rhs[1]);
293 }
294 if constexpr (D0 > 2) {
295 isEqual &= VEqual(lhs[2], rhs[2]);
296 }
297 if constexpr (D0 > 3) {
298 isEqual &= VEqual(lhs[3], rhs[3]);
299 }
300 if constexpr (D0 > 4) {
301 for (size_t i = 4; i < D0; ++i) {
302 isEqual &= VEqual(lhs[i], rhs[i]);
303 }
304 }
305 return AllTrue(isEqual);
306}
307
308template <typename T, size_t D0, size_t... DIMS>
309[[nodiscard]] MOCHI_FORCE_INLINE constexpr bool operator!=(
310 NdArray<Simd<T, 4>, D0, DIMS...> const& lhs,
311 NdArray<Simd<T, 4>, D0, DIMS...> const& rhs) {
312 return !(lhs == rhs);
313}
314
315/**************************************************************************************************
316 NdArray matrices conversions
317*/
318
319template <typename T>
321 NdArray<Simd<T, 4>, 3> result;
322 result[0] = Blend<0, 1, 1, 1>(m[0], Shuffle<3, 0, 1, 3>(m[1]));
323 result[1] = Blend<1, 0, 1, 1>(m[0], Shuffle<0, 3, 2, 3>(m[1]));
324 result[2] = Blend<1, 1, 0, 1>(m[0], Shuffle<1, 2, 3, 3>(m[1]));
325 return result;
326}
327
328template <typename T>
332
333template <typename T>
335 NdArray<Simd<T, 4>, 2> result;
336 result[0] = Blend<0, 1, 1, 1>(m[0], Blend<1, 0, 1, 1>(m[1], m[2]));
337 result[1] = Shuffle<1, 2, 2, 3>(m[0], m[1]);
338 return result;
339}
340
341template <typename T>
345
346template <typename T>
348 alignas(alignof(Simd<T, 4>)) T data[4];
349 Store(data, v);
350 return Real2{(real)data[0], (real)data[1]};
351}
352
353template <typename T>
355 alignas(alignof(Simd<T, 4>)) T data[4];
356 Store(data, v);
357 return Real3{(real)data[0], (real)data[1], (real)data[2]};
358}
359
360template <typename T>
362 alignas(alignof(Simd<T, 4>)) T data[4];
363 Store(data, v);
364 return Real4{(real)data[0], (real)data[1], (real)data[2], (real)data[3]};
365}
366
367template <typename T>
369 alignas(alignof(Simd<T, 4>)) T data[4];
370 Store(data, m);
371 return NdArray<T, 2, 2>{NdArray<T, 2>{data[0], data[1]}, NdArray<T, 2>{data[2], data[3]}};
372}
373
374template <typename T>
376 NdArray<T, 3, 3> result;
377 Store(result[0].data(), m[0]);
378 Store(result[1].data(), m[1]);
379 Store<3>(result[2].data(), m[2]);
380 return result;
381}
382
383template <typename T>
385 NdArray<T, 4, 4> result;
386 Store(result[0].data(), m[0]);
387 Store(result[1].data(), m[1]);
388 Store(result[2].data(), m[2]);
389 Store(result[3].data(), m[3]);
390 return result;
391}
392
393template <typename T>
395 alignas(alignof(Simd<T, 4>)) T data[4];
396 Store(data, m);
397 return NdArray<T, 2, 2>{NdArray<T, 2>{data[0], data[1]}, NdArray<T, 2>{data[1], data[2]}};
398}
399
400template <typename T>
402 alignas(alignof(Simd<T, 4>)) T diag[4];
403 alignas(alignof(Simd<T, 4>)) T offd[4];
404 Store(diag, m[0]);
405 Store(offd, m[1]);
406 return NdArray<T, 3, 3>{
407 NdArray<T, 3>{diag[0], offd[0], offd[1]},
408 NdArray<T, 3>{offd[0], diag[1], offd[2]},
409 NdArray<T, 3>{offd[1], offd[2], diag[2]}};
410}
411
412template <typename T>
414 return {v[0], v[1], z, w};
415}
416
417template <typename T>
419 return {v[0], v[1], v[2], w};
420}
421
422template <typename T>
424 return {v[0], v[1], v[2], v[3]};
425}
426
427template <typename T>
429 return {m[0][0], m[0][1], m[1][0], m[1][1]};
430}
431
432template <typename T>
434 return {ToSimd(m[0]), ToSimd(m[1]), ToSimd(m[2])};
435}
436
437template <typename T>
439 return {ToSimd(m[0]), ToSimd(m[1]), ToSimd(m[2]), ToSimd(m[3])};
440}
441
442template <typename T>
444 // NOTE: For the off-diagonal term, we only consider the upper-right entry (◹).
445 return Simd<T, 4>{m[0][0], m[0][1], m[1][1]};
446}
447
448template <typename T>
450 // NOTE: For the off-diagonal terms, we only consider the upper-right entries (◹).
451 return {Simd<T, 4>(m[0][0], m[1][1], m[2][2]), Simd<T, 4>(m[0][1], m[0][2], m[1][2])};
452}
453
454template <typename T>
456 NdArray<Simd<T, 4>, 3, 3, 3> result;
457 for (int i = 0; i < 3; ++i) {
458 for (int j = 0; j < 3; ++j) {
459 result[i][j] = ToSimdMatrix(t[i][j]);
460 }
461 }
462 return result;
463}
464
465template <typename T>
467 return Simd<T, 4>{a00, a01, a01, a11};
468}
469
470template <typename T>
473 for (int i = 0; i < 3; ++i) {
474 for (int j = 0; j < 3; ++j) {
475 result[i][j] = ToNdArray3x3(t[i][j]);
476 }
477 }
478 return result;
479}
480
481template <typename T>
483 NdArray<Simd<T, 4>, 3, 3> result;
484 for (int i = 0; i < 3; ++i) {
485 result[i] = ToSimdMatrix(t[i]);
486 }
487 return result;
488}
489
490template <typename T>
492 NdArray<T, 3, 3, 3> result;
493 for (int i = 0; i < 3; ++i) {
494 result[i] = ToNdArray3x3(t[i]);
495 }
496 return result;
497}
498
499/**************************************************************************************************
500 NdArray conversions for simd <--> scalar
501*/
502
503template <size_t D0, size_t D1, typename T>
504MOCHI_FORCE_INLINE void LoadMatrix(NdArray<Simd<T, 4>, D0>& out, T const* x) {
505 static_assert(D1 >= 1 && D1 <= 4, "Unsupported size");
506 using V = Simd<T, 4>;
507 if constexpr ((D0 == 4) && (D1 == 3)) {
508 // Special case for 3D tetrahedrons
509 out[0] = Load<V>(x + 0 * D1);
510 out[1] = Load<V>(x + 1 * D1);
511 out[2] = Load<V>(x + 2 * D1);
512 out[3] = Load<int(D1), V>(x + 3 * D1);
513 } else {
514 for (size_t i = 0; i < D0 - 1; ++i) {
515 out[i] = Load<V>(x + i * D1);
516 }
517 out[D0 - 1] = Load<int(D1), V>(x + (D0 - 1) * D1);
518 }
519}
520
521template <size_t D0, size_t D1, typename T, typename ConstOrNonConstT>
523 MOCHI_ASSERT_VERBOSE(x.size() == (D0 * D1), "Span size mismatch");
524 LoadMatrix<D0, D1>(out, x.data());
525}
526
527template <size_t D0, size_t D1, typename T>
529 LoadMatrix<D0, D1>(out, &x[0][0]);
530}
531
532template <size_t D0, size_t D1, size_t D2, size_t D3, typename T>
533MOCHI_FORCE_INLINE void LoadMatrix(NdArray<Simd<T, 4>, D0, D1, D2>& out, T const* x) {
534 static_assert(D3 >= 1 && D3 <= 4, "Unsupported size");
535 using V = Simd<T, 4>;
536 for (size_t i = 0; i < D0; ++i) {
537 for (size_t j = 0; j < D1; ++j) {
538 for (size_t k = 0; k < D2; ++k) {
539 out[i][j][k] = Load<int(D3), V>(x + i * D1 * D2 * D3 + j * D2 * D3 + k * D3);
540 }
541 }
542 }
543}
544
545template <size_t D0, size_t D1, size_t D2, size_t D3, typename T>
547 NdArray<Simd<T, 4>, D0, D1, D2>& out,
549 LoadMatrix<D0, D1, D2, D3>(out, &x[0][0][0][0]);
550}
551
552template <size_t D0, size_t D1, size_t D2, size_t D3, typename T>
553MOCHI_FORCE_INLINE void LoadSubmatrix(NdArray<Simd<T, 4>, D0>& out, Int2 coords, T const* x) {
554 static_assert(D1 >= 1 && D1 <= 4, "Unsupported size");
555 static_assert(D0 <= D2 && D1 <= D3, "Unsupported dimensions");
556 MOCHI_ASSERT_VERBOSE(coords[0] + D0 <= D2, "Size mismatch");
557 MOCHI_ASSERT_VERBOSE(coords[1] + D1 <= D3, "Size mismatch");
558 MOCHI_ASSERT_VERBOSE(coords[0] >= 0 && coords[1] >= 0, "Invalid coordinates");
559 using V = Simd<T, 4>;
560 for (size_t i = 0; i < D0 - 1; ++i) {
561 out[i] = Load<V>(x + (coords[0] + i) * D3 + coords[1]);
562 }
563 out[D0 - 1] = Load<int(D1), V>(x + (coords[0] + D0 - 1) * D3 + coords[1]);
564}
565
566template <size_t D0, size_t D1, size_t D2, size_t D3, typename T, typename ConstOrNonConstT>
569 MOCHI_ASSERT_VERBOSE(x.size() == (D2 * D3), "Span size mismatch");
570 LoadSubmatrix<D0, D1, D2, D3>(out, coords, x.data());
571}
572
573template <size_t D0, size_t D1, size_t D2, size_t D3, typename T>
576 LoadSubmatrix<D0, D1, D2, D3>(out, coords, &x[0][0]);
577}
578
579template <size_t D0, size_t D1, typename T>
581 static_assert(D1 >= 1 && D1 <= 4, "Unsupported size");
582 if constexpr ((D0 == 4) && (D1 == 3)) {
583 // Special case for 3D tetrahedrons
584 Store(out + 0 * D1, x[0]);
585 Store(out + 1 * D1, x[1]);
586 Store(out + 2 * D1, x[2]);
587 Store<int(D1)>(out + 3 * D1, x[3]);
588 } else {
589 for (size_t i = 0; i < D0 - 1; ++i) {
590 Store(out + i * D1, x[i]);
591 }
592 Store<int(D1)>(out + (D0 - 1) * D1, x[D0 - 1]);
593 }
594}
595
596template <size_t D0, size_t D1, typename T>
598 MOCHI_ASSERT_VERBOSE(out.size() == (D0 * D1), "Span size mismatch");
599 StoreMatrix<D0, D1>(out.data(), x);
600}
601
602template <size_t D0, size_t D1, typename T>
604 StoreMatrix<D0, D1>(&out[0][0], x);
605}
606
607template <size_t D0, size_t D1, size_t D2, size_t D3, typename T>
608MOCHI_FORCE_INLINE void StoreMatrix(T* out, NdArray<Simd<T, 4>, D0, D1, D2> const& x) {
609 static_assert(D3 >= 1 && D3 <= 4, "Unsupported size");
610 for (size_t i = 0; i < D0; ++i) {
611 for (size_t j = 0; j < D1; ++j) {
612 for (size_t k = 0; k < D2; ++k) {
613 Store<int(D3)>(out + i * D1 * D2 * D3 + j * D2 * D3 + k * D3, x[i][j][k]);
614 }
615 }
616 }
617}
618
619template <size_t D0, size_t D1, size_t D2, size_t D3, typename T>
622 NdArray<Simd<T, 4>, D0, D1, D2> const& x) {
623 StoreMatrix<D0, D1, D2, D3>(&out[0][0][0][0], x);
624}
625
626template <size_t D0, size_t D1, size_t D2, size_t D3, typename T>
627MOCHI_FORCE_INLINE void StoreSubmatrix(T* out, Int2 coords, NdArray<Simd<T, 4>, D0> const& x) {
628 static_assert(D1 >= 1 && D1 <= 4, "Unsupported size");
629 static_assert(D0 <= D2 && D1 <= D3, "Unsupported dimensions");
630 MOCHI_ASSERT_VERBOSE(coords[0] + D0 <= D2, "Size mismatch");
631 MOCHI_ASSERT_VERBOSE(coords[1] + D1 <= D3, "Size mismatch");
632 MOCHI_ASSERT_VERBOSE(coords[0] >= 0 && coords[1] >= 0, "Invalid coordinates");
633 for (size_t i = 0; i < D0; ++i) {
634 Store<int(D1)>(out + (coords[0] + i) * D3 + coords[1], x[i]);
635 }
636}
637
638template <size_t D0, size_t D1, size_t D2, size_t D3, typename T>
640 MOCHI_ASSERT_VERBOSE(out.size() == (D2 * D3), "Span size mismatch");
641 StoreSubmatrix<D0, D1, D2, D3>(out.data(), coords, x);
642}
643
644template <size_t D0, size_t D1, size_t D2, size_t D3, typename T>
647 StoreSubmatrix<D0, D1, D2, D3>(&out[0][0], coords, x);
648}
649
650/**************************************************************************************************
651 BroadcastEach
652*/
653
654namespace ndarray_details {
655template <class V, size_t D0, size_t... DIMS, size_t... I>
656[[nodiscard]] MOCHI_FORCE_INLINE auto BroadcastEach( // TODO: Make this a lambda with C++20
657 NdArray<typename V::Scalar, D0, DIMS...> const& a,
658 std::index_sequence<I...>) {
659 if constexpr (sizeof...(DIMS) == 0) { // Last dimension is a Simd broadcast
660 return NdArray<V, D0, DIMS...>{Broadcast<V>(a[I])...};
661 } else {
662 return NdArray<V, D0, DIMS...>{BroadcastEach<V>(a[I])...};
663 }
664}
665template <class V, int N, size_t... I>
666[[nodiscard]] MOCHI_FORCE_INLINE auto BroadcastEach( // TODO: Make this a lambda with C++20
667 Simd<typename V::Scalar, N> const& a, std::index_sequence<I...>) {
668 if constexpr (V::kSize == N) {
669 return NdArray<V, (size_t)N>{Broadcast<(int)I>(a)...}; // Broadcast I'th to same Simd size
670 } else {
671 return NdArray<V, (size_t)N>{Broadcast<V>(Get<I>(a))...}; // Broadcast I'th to other Simd size
672 }
673}
674} // namespace ndarray_details
675
676// Broadcast each member of an NdArray to a Simd vector.
677// Example:
678// auto pt = Real3{x, y, z};
679// auto v = Broadcast<Vec4r>(pt); // v = {{x, x, x, x}, {y, y, y, y}, {z, z, z, z}}
680//
681template <class V, size_t D0, size_t... DIMS, MOCHI_CONCEPT(IsSimd<V>)>
682[[nodiscard]] MOCHI_FORCE_INLINE NdArray<V, D0, DIMS...> BroadcastEach(
684 return ndarray_details::BroadcastEach<V>(a, std::make_index_sequence<D0>());
685}
686
687// Broadcast each member a Simd vector to its own Simd vector
688// Example:
689// auto pt = Vec4r{a, b, c, d};
690// auto v = Broadcast<Vec4r>(pt); // v = {{a, a, a, a}, {b, b, b, b}, {c, c, c, c}, {d, d, d, d}}
691//
692template <class V, int N, MOCHI_CONCEPT(IsSimd<V>)>
694 return ndarray_details::BroadcastEach<V>(a, std::make_index_sequence<(size_t)N>());
695}
696
697// Broadcast just the first 3 members of a Simd vector to its own Simd vector
698// Example:
699// auto pt = Vec4r{a, b, c, d};
700// auto v = Broadcast3<Vec4r>(pt); // v = {{a, a, a, a}, {b, b, b, b}, {c, c, c, c}}
701//
702template <class V, int N, MOCHI_CONCEPT(IsSimd<V>&& N >= 3)>
704 if constexpr (V::kSize == N) {
706 } else {
708 }
709}
710
711// Broadcast just the first 3x3 portion of a Simd matrix, each member to its own vector.
712// Example:
713// auto mat = VMatrix4x4{row0, row1, row2, row3};
714// auto vmat = Broadcast3x3<Vec4r>(mat);
715// // vmat = {Broadcast3<Vec4r>(mat[0]), Broadcast3<Vec4r>(mat[1]), Broadcast3<Vec4r>(mat[2])};
716//
717template <class V, size_t D0, int D1, MOCHI_CONCEPT(IsSimd<V>&& D0 >= 3 && D1 >= 3)>
722
723/**************************************************************************************************
724 LoadTransposed / StoreTransposed
725*/
726
727// Load (kTupleCount * 3) values in transposed order (kTupleCount == V::kSize by default).
728// In other words:
729// {{x0, y0, z0}, {x1, y1, z1}, ...} --> {{x0, x1, ...}, {y0, y1, ...}, {z0, z1, ...}}
730template <int kTupleCount = -1, class V, MOCHI_CONCEPT(IsSimd<V>)>
731MOCHI_FORCE_INLINE void LoadTransposed(typename V::Scalar const* ptr, NdArray<V, 3>& out) {
732 auto constexpr kTupleCount_ = (kTupleCount == -1) ? V::kSize : kTupleCount;
733 LoadTransposed<kTupleCount_>(ptr, out[0], out[1], out[2]);
734}
735
736// Store (kTupleCount * 3) values in transposed order (kTupleCount == V::kSize by default).
737// In other words:
738// {{x0, x1, ...}, {y0, y1, ...}, {z0, z1, ...}} --> {{x0, y0, z0}, {x1, y1, z1}, ...}
739template <int kTupleCount = -1, class V, MOCHI_CONCEPT(IsSimd<V>)>
740MOCHI_FORCE_INLINE void StoreTransposed(typename V::Scalar* ptr, NdArray<V, 3> const& src) {
741 auto constexpr kTupleCount_ = (kTupleCount == -1) ? V::kSize : kTupleCount;
743 ptr, src[0], src[1], src[2]); // TODO: Support arbitrary size when C++20 makes that easier
744}
745
746} // namespace superdex
constexpr SizeT size() const
Definition span.h:106
constexpr T * data() const
Definition span.h:118
#define MOCHI_ASSERT_VERBOSE(condition_without_side_effects,...)
Definition debug.h:102
#define MOCHI_CONCEPT(a)
#define MOCHI_FORCE_INLINE
void LoadMatrix(NdArray< Simd< T, 4 >, D0 > &out, NdArray< T, D0, D1 > const &x)
Definition vmatrix.h:528
Simd< T, 2 > Shuffle(Simd< T, 2 > a)
Definition simd_inl.h:270
constexpr bool operator==(NdArray< T, D0, DIMS... > const &lhs, NdArray< T, D0, DIMS... > const &rhs)
Definition nd_array.h:191
NdArray< Simd< T, 4 >, 3, 3, 3 > ToSimdTensor(NdArray< T, 3, 3, 3, 3 > const &t)
Definition vmatrix.h:455
NdArray< Simd< real, 4 >, 2 > VMatrix2x4r
Definition vmatrix.h:51
Simd< T, 4 > ToSimdFromSymComponents2x2(T a00, T a01, T a11)
Definition vmatrix.h:466
NdArray< Simd< real, 4 >, 3, 3 > VTensor3x3x3r
Definition vmatrix.h:71
Simd< T, 4 > ToSimd(NdArray< T, 2 > const &v, T z=T(0), T w=T(0))
Definition vmatrix.h:413
Simd< float, 4 > VSymMatrix2x2f
Definition vmatrix.h:85
void LoadSubmatrix(NdArray< Simd< T, 4 >, D0 > &out, Int2 coords, NdArray< T, D2, D3 > const &x)
Definition vmatrix.h:575
NdArray< Simd< float, 4 >, 3 > VMatrix3x4f
Definition vmatrix.h:61
bool AllTrue(T const &a)
Definition basic_utils.h:60
NdArray< Simd< real, 4 >, 3 > VMatrix3x3r
Definition vmatrix.h:52
V VEqual(V a, V b)
Definition simd_inl.h:700
NdArray< T, 3, 3 > ToNdArray3x3(NdArray< Simd< T, 4 >, 3 > m)
Definition vmatrix.h:375
NdArray< Simd< float, 4 >, 4 > VMatrix4x4f
Definition vmatrix.h:63
Real3 ToReal3(Simd< T, 4 > v)
Definition vmatrix.h:354
NdArray< Simd< float, 4 >, 3 > VMatrix3x3f
Definition vmatrix.h:60
NdArray< V, 3 > Broadcast3(Simd< typename V::Scalar, N > const &a)
Definition vmatrix.h:703
Simd< T, 4 > ToSimdSymMatrix(NdArray< T, 2, 2 > const &m)
Definition vmatrix.h:443
NdArray< Simd< real, 4 >, 4, 3 > VTensor4x3x3r
Definition vmatrix.h:72
Real4 ToReal4(Simd< T, 4 > v)
Definition vmatrix.h:361
Simd< real, 4 > VSymMatrix2x2r
Special case for the SIMD representation of a 2x2 symmetric matrix.
Definition vmatrix.h:84
NdArray< Simd< float, 4 >, 2 > VSymMatrix3x3f
Definition vmatrix.h:97
V Broadcast(typename V::Scalar a)
Definition simd_inl.h:115
NdArray< Simd< real, 4 >, 4 > VMatrix4x4r
Definition vmatrix.h:55
NdArray< Simd< float, 4 >, 3, 3 > VTensor3x3x3f
Definition vmatrix.h:75
Simd< T, N > Blend(Simd< T, N > a, Simd< T, N > b)
Definition simd_inl.h:285
void StoreSubmatrix(NdArray< T, D2, D3 > &out, Int2 coords, NdArray< Simd< T, 4 >, D0 > const &x)
Definition vmatrix.h:646
NdArray< Simd< float, 4 >, 2 > VMatrix2x4f
Definition vmatrix.h:59
NdArray< T, 3, 3 > ToNdArraySym3x3(NdArray< Simd< T, 4 >, 2 > m)
Definition vmatrix.h:401
NdArray< Simd< T, 4 >, 3 > SimdSymToFull(NdArray< Simd< T, 4 >, 2 > const &m)
Definition vmatrix.h:320
NdArray< T, 4, 4 > ToNdArray(NdArray< Simd< T, 4 >, 4 > m)
Definition vmatrix.h:384
NdArray< Simd< real, 4 >, 3 > VMatrix3x4r
Definition vmatrix.h:53
NdArray< T, 2, 2 > ToNdArray2x2(Simd< T, 4 > m)
Definition vmatrix.h:368
NdArray< Simd< double, 4 >, 3 > VMatrix3x3d
Definition vmatrix.h:65
NdArray< Simd< T, 4 >, 2 > SimdFullToSym(NdArray< Simd< T, 4 >, 3 > const &m)
Definition vmatrix.h:334
T Get(Simd< T, N > v)
Definition simd_inl.h:300
NdArray< real, 3 > Real3
Definition nd_array.h:106
NdArray< Simd< real, 4 >, 3, 3, 3 > VTensor3x3x3x3r
SIMD representation of tensors.
Definition vmatrix.h:70
NdArray< real, 4 > Real4
Definition nd_array.h:107
NdArray< Simd< float, 4 >, 3 > VMatrix3x2f
Definition vmatrix.h:57
NdArray< T, 3, 3, 3, 3 > ToNdArrayTensor(NdArray< Simd< T, 4 >, 3, 3, 3 > const &t)
Definition vmatrix.h:471
NdArray< Simd< float, 4 >, 3, 3, 3 > VTensor3x3x3x3f
Definition vmatrix.h:74
Simd< real, 4 > VMatrix2x2r
Special case for the SIMD representation of a 2x2 matrix.
Definition vmatrix.h:41
void LoadTransposed(T const *ptr, Simd< T, N > &out0, Simd< T, N > &out1, Simd< T, N > &out2)
Definition simd_inl.h:207
Simd< float, 4 > VMatrix2x2f
Definition vmatrix.h:42
NdArray< Simd< float, 4 >, 4 > VMatrix4x3f
Definition vmatrix.h:62
NdArray< Simd< real, 4 >, 2 > VSymMatrix3x3r
Special case for the SIMD representation of a 3x3 symmetric matrix.
Definition vmatrix.h:96
void StoreTransposed(T *ptr, Simd< T, N > a, Simd< T, N > b, Simd< T, N > c)
Definition simd_inl.h:245
void Store(T *ptr, Simd< T, N > a)
Definition simd_inl.h:213
NdArray< Simd< real, 4 >, 2 > VMatrix2x3r
Definition vmatrix.h:50
NdArray< int, 2 > Int2
Definition nd_array.h:137
NdArray< Simd< real, 4 >, 4 > VMatrix4x3r
Definition vmatrix.h:54
void StoreMatrix(NdArray< T, D0, D1 > &out, NdArray< Simd< T, 4 >, D0 > const &x)
Definition vmatrix.h:603
constexpr bool operator!=(NdArray< T, D0, DIMS... > const &lhs, NdArray< T, D0, DIMS... > const &rhs)
Definition nd_array.h:227
Real2 ToReal2(Simd< T, 4 > v)
Definition vmatrix.h:347
V Load(typename V::Scalar const *ptr)
Definition simd_inl.h:184
NdArray< V, 3, 3 > Broadcast3x3(NdArray< Simd< typename V::Scalar, D1 >, D0 > const &a)
Definition vmatrix.h:718
NdArray< Simd< real, 4 >, 3 > VMatrix3x2r
SIMD representation of a NxM matrices.
Definition vmatrix.h:49
NdArray< real, 2 > Real2
Definition nd_array.h:105
NdArray< V, D0, DIMS... > BroadcastEach(NdArray< typename V::Scalar, D0, DIMS... > const &a)
Definition vmatrix.h:682
NdArray< Simd< float, 4 >, 2 > VMatrix2x3f
Definition vmatrix.h:58
NdArray< T, 2, 2 > ToNdArraySym2x2(Simd< T, 4 > m)
Definition vmatrix.h:394
Simd< T, 4 > ToSimdMatrix(NdArray< T, 2, 2 > const &m)
Definition vmatrix.h:428
#define MOCHI_DETAILS_NDARRAY_SIMD_MEMBERWISE_OP(OP_EQ, OP)
Definition vmatrix.h:259