SuperDex Physics C++ API
Loading...
Searching...
No Matches
matrix_utils_inl.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
19#include <mochi_core/utils/matrix_utils.h> // for intellisense
20
21#include <cmath>
22
23namespace superdex {
24
25/**************************************************************************************************
26 Frobenius Norm
27*/
28
29template <typename T, size_t N, size_t M>
31 T accum = T(0);
32 for (int i = 0; i < N; ++i) {
33 accum += Dot(a[i], a[i]);
34 }
35 return accum;
36}
37
38template <typename T, size_t N, size_t M>
40 return Sqrt(NormSqr(a));
41}
42
43template <typename T, size_t D0, int D1, MOCHI_CONCEPT_DEF(D0 >= 3 && D1 >= 3)>
45 return HSum<3>(a[0] * a[0] + a[1] * a[1] + a[2] * a[2]);
46}
47
48template <typename T, size_t D0, int D1, MOCHI_CONCEPT_DEF(D0 >= 3 && D1 >= 3)>
52
53/**************************************************************************************************
54 Matrix-Vector Dot Product
55*/
56
57template <typename T, size_t N, size_t M>
59 NdArray<T, N, M> const& a,
60 NdArray<T, M> const& b) {
61 NdArray<T, N> result = {};
62 for (size_t i = 0; i < result.size(); ++i) {
63 result[i] = Dot(a[i], b);
64 }
65 return result;
66}
67
68template <typename T, size_t N, size_t M>
70 MOCHI_ASSERT_VERBOSE((M == b.size()) && (out.size() == N), "Size mismatch");
71 for (size_t i = 0; i < out.size(); ++i) {
72 out[i] = Dot(b, a[i]);
73 }
74}
75
76template <typename T, size_t N, size_t M>
78 NdArray<T, N> result = {};
79 DotMatVec(a, b, Span<T>(result));
80 return result;
81}
82
83template <typename T>
85 NdArray<T, 3, 3> const& a,
86 NdArray<T, 3> const& b) {
87 return NdArray<T, 3>{
88 a[0][0] * b[0] + a[0][1] * b[1] + a[0][2] * b[2],
89 a[1][0] * b[0] + a[1][1] * b[1] + a[1][2] * b[2],
90 a[2][0] * b[0] + a[2][1] * b[1] + a[2][2] * b[2]};
91}
92
93template <size_t N, typename T, size_t D0>
95 static_assert(D0 >= 3, "Requires a matrix with at least 3 rows");
96 auto const a = VDot<N>(m[0], v);
97 auto const b = VDot<N>(m[1], v);
98 auto const c = VDot<N>(m[2], v);
100}
101
102template <typename T, size_t D0>
106
107template <typename T>
109 auto a = VDot(m[0], v);
110 auto b = VDot(m[1], v);
111 auto c = VDot(m[2], v);
112 auto d = VDot(m[3], v);
113 auto ab = Shuffle<0, 0, 0, 0>(a, b); // ac = (a[0], a[0], b[0], b[0])
114 auto cd = Shuffle<0, 0, 0, 0>(c, d); // bd = (c[0], c[0], d[0], d[0])
115 return Shuffle<0, 2, 0, 2>(ab, cd); // return (a[0], b[0], c[0], d[0])
116}
117
118/**************************************************************************************************
119 Vector-Matrix Dot Product
120*/
121
122template <typename T, size_t N, size_t M>
124 NdArray<T, N> const& a,
125 NdArray<T, N, M> const& b) {
126 if constexpr (N == 3 && M == 3) {
127 return NdArray<T, 3>{
128 a[0] * b[0][0] + a[1] * b[1][0] + a[2] * b[2][0],
129 a[0] * b[0][1] + a[1] * b[1][1] + a[2] * b[2][1],
130 a[0] * b[0][2] + a[1] * b[1][2] + a[2] * b[2][2]};
131 } else {
132 return DotMatVec(Transpose(b), a);
133 }
134}
135
136template <typename T>
138 // |u v| | a b c | = | ua + vd |
139 // | d e f | | ub + ve |
140 // | uc + vf |
141 Simd<T, 4> temp0 = Broadcast<0>(v) * m[0]; // (ua, ub, uc, ?)
142 Simd<T, 4> temp1 = Broadcast<1>(v) * m[1]; // (vd, ve, vf, ?)
143 return temp0 + temp1; // (ua + vd, ub + ve, uc + vf, ?)
144}
145
146template <typename T, size_t D0>
148 static_assert(D0 == 3 || D0 == 4, "Requires a matrix with 3 or 4 rows");
149 return Broadcast<0>(a) * b[0] + Broadcast<1>(a) * b[1] + Broadcast<2>(a) * b[2];
150}
151
152template <typename T>
154 return Broadcast<0>(a) * b[0] + Broadcast<1>(a) * b[1] + Broadcast<2>(a) * b[2] +
155 Broadcast<3>(a) * b[3];
156}
157
158/**************************************************************************************************
159 Matrix-Matrix Dot Product
160*/
161
162template <typename T, size_t N, size_t M, size_t L>
164 NdArray<T, N, M> const& a,
165 NdArray<T, M, L> const& b) {
166 NdArray<T, N, L> result = {};
168 for (int n = 0; n < N; ++n) {
169 result[n] = DotMatVec(bT, a[n]);
170 }
171 return result;
172}
173
174template <typename T>
176 NdArray<Simd<T, 4>, 4> const& a,
177 NdArray<Simd<T, 4>, 4> const& b) {
178 return NdArray<Simd<T, 4>, 4>{
179 DotVecMat4x4(a[0], b), DotVecMat4x4(a[1], b), DotVecMat4x4(a[2], b), DotVecMat4x4(a[3], b)};
180}
181
182template <typename T>
184 NdArray<T, 3, 3> const& a,
185 NdArray<T, 3, 3> const& b) {
186 return {
188 a[0][0] * b[0][0] + a[0][1] * b[1][0] + a[0][2] * b[2][0],
189 a[0][0] * b[0][1] + a[0][1] * b[1][1] + a[0][2] * b[2][1],
190 a[0][0] * b[0][2] + a[0][1] * b[1][2] + a[0][2] * b[2][2]},
192 a[1][0] * b[0][0] + a[1][1] * b[1][0] + a[1][2] * b[2][0],
193 a[1][0] * b[0][1] + a[1][1] * b[1][1] + a[1][2] * b[2][1],
194 a[1][0] * b[0][2] + a[1][1] * b[1][2] + a[1][2] * b[2][2]},
196 a[2][0] * b[0][0] + a[2][1] * b[1][0] + a[2][2] * b[2][0],
197 a[2][0] * b[0][1] + a[2][1] * b[1][1] + a[2][2] * b[2][1],
198 a[2][0] * b[0][2] + a[2][1] * b[1][2] + a[2][2] * b[2][2]}};
199}
200
201template <typename T, size_t D0A, size_t D0B>
203 NdArray<Simd<T, 4>, D0A> const& a,
204 NdArray<Simd<T, 4>, D0B> const& b) {
205 return {DotVecMat3x3(a[0], b), DotVecMat3x3(a[1], b), DotVecMat3x3(a[2], b)};
206}
207
208template <typename T>
210 Simd<T, 4> const a0 = Shuffle<0, 1, 3, 2>(a);
211 Simd<T, 4> const b0 = Shuffle<0, 3, 2, 1>(b);
212 Simd<T, 4> const a1 = Shuffle<1, 0, 2, 3>(a);
213 Simd<T, 4> const b1 = Shuffle<2, 1, 0, 3>(b);
214 return a0 * b0 + a1 * b1;
215}
216
217/**************************************************************************************************
218 Outer Product
219*/
220
221template <typename T>
223 NdArray<T, 2> const& a,
224 NdArray<T, 2> const& b) {
225 return {NdArray<T, 2>{a[0] * b[0], a[0] * b[1]}, NdArray<T, 2>{a[1] * b[0], a[1] * b[1]}};
226}
227
228template <typename T>
230 NdArray<T, 3> const& a,
231 NdArray<T, 2> const& b) {
232 return NdArray<T, 3, 2>{
233 NdArray<T, 2>{a[0] * b[0], a[0] * b[1]},
234 NdArray<T, 2>{a[1] * b[0], a[1] * b[1]},
235 NdArray<T, 2>{a[2] * b[0], a[2] * b[1]}};
236}
237
238template <typename T>
240 NdArray<T, 3> const& a,
241 NdArray<T, 3> const& b) {
242 return {
243 NdArray<T, 3>{a[0] * b[0], a[0] * b[1], a[0] * b[2]},
244 NdArray<T, 3>{a[1] * b[0], a[1] * b[1], a[1] * b[2]},
245 NdArray<T, 3>{a[2] * b[0], a[2] * b[1], a[2] * b[2]}};
246}
247
248// Outer product of 3 component vectors (assumed 4th component unused)
249template <typename T>
251 return NdArray<Simd<T, 4>, 3>{
252 Shuffle<0, 0, 0, 0>(a) * b, // {a[0] * b[0], a[0] * b[1], a[0] * b[2], a[0] * b[3] }
253 Shuffle<1, 1, 1, 1>(a) * b, // {a[1] * b[0], a[1] * b[1], a[1] * b[2], a[1] * b[3] }
254 Shuffle<2, 2, 2, 2>(a) * b, // {a[2] * b[0], a[2] * b[1], a[2] * b[2], a[2] * b[3] }
255 };
256}
257
258template <typename T>
260 Simd<T, 4> const& vec,
261 NdArray<Simd<T, 4>, 3> const& mat) {
262 NdArray<Simd<T, 4>, 3, 3> outProd;
263 outProd[0] = mat * Broadcast<0>(vec);
264 outProd[1] = mat * Broadcast<1>(vec);
265 outProd[2] = mat * Broadcast<2>(vec);
266 return outProd;
267}
268
269// Outer product of a 3x3 matrix and a 3x1 vector returning a 3x3x3 3rd-order tensor
270template <typename T>
272 NdArray<Simd<T, 4>, 3> const& mat,
273 Simd<T, 4> const& vec) {
274 NdArray<Simd<T, 4>, 3, 3> result;
275 for (int i = 0; i < 3; ++i) {
276 result[i] = Outer3(mat[i], vec);
277 }
278 return result;
279}
280
281template <typename T>
283 NdArray<Simd<T, 4>, 3, 3> const& ten,
284 Simd<T, 4> const& vec) {
285 NdArray<Simd<T, 4>, 3, 3, 3> outProd;
286 for (int i = 0; i < 3; ++i) {
287 outProd[i][0] = ten[i] * Broadcast<0>(vec);
288 outProd[i][1] = ten[i] * Broadcast<1>(vec);
289 outProd[i][2] = ten[i] * Broadcast<2>(vec);
290 }
291 return outProd;
292}
293
294template <typename T>
296 Simd<T, 4> const& vec,
297 NdArray<Simd<T, 4>, 3, 3> const& ten) {
298 NdArray<Simd<T, 4>, 3, 3, 3> outProd;
299 for (int i = 0; i < 3; ++i) {
300 outProd[0][i] = ten[i] * Broadcast<0>(vec);
301 outProd[1][i] = ten[i] * Broadcast<1>(vec);
302 outProd[2][i] = ten[i] * Broadcast<2>(vec);
303 }
304 return outProd;
305}
306
307template <typename T>
309 NdArray<Simd<T, 4>, 3> const& mat0,
310 NdArray<Simd<T, 4>, 3> const& mat1) {
311 NdArray<Simd<T, 4>, 3, 3, 3> outProd;
312 for (int i = 0; i < 3; ++i) {
313 outProd[i][0] = mat0 * Broadcast<0>(mat1[i]);
314 outProd[i][1] = mat0 * Broadcast<1>(mat1[i]);
315 outProd[i][2] = mat0 * Broadcast<2>(mat1[i]);
316 }
317 return outProd;
318}
319
320template <typename T>
322 // {Vec4r{a0b0, a1b1, a2b2, *}, Vec4r{a0b1, a0b2, a1b2, *}}
323 return {a * b, Shuffle<0, 0, 1, 3>(a) * Shuffle<1, 2, 2, 3>(b)};
324}
325
326template <typename T>
328 NdArray<Simd<T, 4>, 2, 2> result;
329 for (int i = 0; i < 2; i++) {
330 for (int j = 0; j < 2; j++) {
331 result[i][j] = a[2 * i + j] * b;
332 }
333 }
334 return result;
335}
336
337/**************************************************************************************************
338 Inner Product
339*/
340
341template <typename T>
343 T result = {};
344 for (int i = 0; i < 3; ++i) {
345 result += Dot<3>(A[i], B[i]);
346 }
347 return result;
348}
349
350template <typename T, size_t N, size_t M>
352 T result = T{};
353 for (size_t i = 0; i < N; ++i) {
354 result += Dot(A[i], B[i]);
355 }
356 return result;
357}
358
359template <typename T>
361 return A[0] * B[0] + T{2_r} * A[1] * B[1] + A[2] * B[2];
362}
363
364/**************************************************************************************************
365 Invert
366*/
367
368template <typename T>
370 return Invert(A, Det(A));
371}
372
373template <typename T>
375 MOCHI_ASSERT_VERBOSE(!NearEqual(det, T(0), T(ScalarType<T>(1e-16))), "Non-invertible matrix.");
376 T const invDet = T(1) / det;
377 return {
378 NdArray<T, 2>{A[1][1] * invDet, -A[0][1] * invDet},
379 NdArray<T, 2>{-A[1][0] * invDet, A[0][0] * invDet}};
380}
381
382template <typename T>
384 return Invert(A, Det(A));
385}
386
387template <typename T>
389 MOCHI_ASSERT_VERBOSE(!NearEqual(det, T(0), T(ScalarType<T>(1e-16))), "Non-invertible matrix.");
390 NdArray<T, 3, 3> cofactorTranspose{
392 A[1][1] * A[2][2] - A[1][2] * A[2][1],
393 A[0][2] * A[2][1] - A[0][1] * A[2][2],
394 A[0][1] * A[1][2] - A[0][2] * A[1][1]},
396 A[1][2] * A[2][0] - A[1][0] * A[2][2],
397 A[0][0] * A[2][2] - A[0][2] * A[2][0],
398 A[0][2] * A[1][0] - A[0][0] * A[1][2]},
400 A[1][0] * A[2][1] - A[1][1] * A[2][0],
401 A[0][1] * A[2][0] - A[0][0] * A[2][1],
402 A[0][0] * A[1][1] - A[0][1] * A[1][0]}};
403 return cofactorTranspose / det;
404}
405
406template <typename T>
407inline void PseudoInvert(NdArray<T, 3, 2> const& a, NdArray<T, 2, 3>* outInv, T* outDet) {
408 NdArray<T, 2, 3> const at = Transpose(a);
409 NdArray<T, 3, 3> const coef_1 = Outer(at[0], at[1]) - Outer(at[1], at[0]);
410 T const coef_2 = Dot(DotVecMat(at[0], coef_1), at[1]);
411 (*outInv)[0] = DotMatVec(coef_1, at[1]) / coef_2;
412 (*outInv)[1] = -DotMatVec(coef_1, at[0]) / coef_2;
413 *outDet = Norm(Cross(at[0], at[1]));
414}
415
416template <typename T>
417MOCHI_FORCE_INLINE constexpr T
418Minor4x4(T const m[16], int r0, int r1, int r2, int c0, int c1, int c2) {
419 return m[4 * r0 + c0] * (m[4 * r1 + c1] * m[4 * r2 + c2] - m[4 * r2 + c1] * m[4 * r1 + c2]) -
420 m[4 * r0 + c1] * (m[4 * r1 + c0] * m[4 * r2 + c2] - m[4 * r2 + c0] * m[4 * r1 + c2]) +
421 m[4 * r0 + c2] * (m[4 * r1 + c0] * m[4 * r2 + c1] - m[4 * r2 + c0] * m[4 * r1 + c1]);
422}
423
424template <typename T>
425inline constexpr void Cofactor4x4(T const m[16], T adjOut[16]) {
426 adjOut[0] = Minor4x4(m, 1, 2, 3, 1, 2, 3);
427 adjOut[1] = -Minor4x4(m, 0, 2, 3, 1, 2, 3);
428 adjOut[2] = Minor4x4(m, 0, 1, 3, 1, 2, 3);
429 adjOut[3] = -Minor4x4(m, 0, 1, 2, 1, 2, 3);
430 adjOut[4] = -Minor4x4(m, 1, 2, 3, 0, 2, 3);
431 adjOut[5] = Minor4x4(m, 0, 2, 3, 0, 2, 3);
432 adjOut[6] = -Minor4x4(m, 0, 1, 3, 0, 2, 3);
433 adjOut[7] = Minor4x4(m, 0, 1, 2, 0, 2, 3);
434 adjOut[8] = Minor4x4(m, 1, 2, 3, 0, 1, 3);
435 adjOut[9] = -Minor4x4(m, 0, 2, 3, 0, 1, 3);
436 adjOut[10] = Minor4x4(m, 0, 1, 3, 0, 1, 3);
437 adjOut[11] = -Minor4x4(m, 0, 1, 2, 0, 1, 3);
438 adjOut[12] = -Minor4x4(m, 1, 2, 3, 0, 1, 2);
439 adjOut[13] = Minor4x4(m, 0, 2, 3, 0, 1, 2);
440 adjOut[14] = -Minor4x4(m, 0, 1, 3, 0, 1, 2);
441 adjOut[15] = Minor4x4(m, 0, 1, 2, 0, 1, 2);
442}
443
444template <typename T>
445inline constexpr T Det4x4(T const m[16]) {
446 return m[0] * Minor4x4(m, 1, 2, 3, 1, 2, 3) - m[1] * Minor4x4(m, 1, 2, 3, 0, 2, 3) +
447 m[2] * Minor4x4(m, 1, 2, 3, 0, 1, 3) - m[3] * Minor4x4(m, 1, 2, 3, 0, 1, 2);
448}
449
450template <typename T>
451inline constexpr void InvertRowMajor4x4(T const m[16], T invOut[16]) {
452 Cofactor4x4(m, invOut);
453
454 T det = Det4x4(m);
455
456 MOCHI_ASSERT_VERBOSE(!NearEqual(det, T(0), T(ScalarType<T>(1e-16))), "Non-invertible matrix.");
457
458 T inv_det = T(1) / det;
459 for (int i = 0; i < 16; ++i) {
460 invOut[i] = invOut[i] * inv_det;
461 }
462}
463
464template <typename T>
467 InvertRowMajor4x4(&A[0][0], &out[0][0]);
468 return out;
469}
470
471template <typename T>
473 // This calls the non-SIMD implementation above. Could probably be much faster with a proper SIMD
474 // implementation.
475 NdArray<Simd<T, 4>, 4> out;
476 static_assert(sizeof(NdArray<Simd<T, 4>, 4>) == sizeof(NdArray<T, 4, 4>));
477 InvertRowMajor4x4(reinterpret_cast<T const*>(&A[0]), reinterpret_cast<T*>(&out[0]));
478 return out;
479}
480
481template <typename T>
483 return Invert3x3(mat, VDet3x3(mat));
484}
485
486template <typename T>
488 NdArray<Simd<T, 4>, 3> const& mat,
489 Simd<T, 4> det) {
490 MOCHI_ASSERT_VERBOSE(!NearEqual(Get0(det), T(0), T(1.e-16)), "Non-invertible matrix");
491 return Transpose3x3(Cofactor3x3(mat)) / det;
492}
493
494template <typename T>
496 return Invert3x3(mat, Simd<T, 4>{det});
497}
498
499template <typename T>
503
504// Implementation inspired by:
505// https://lxjk.github.io/2017/09/03/Fast-4x4-Matrix-Inverse-with-SSE-SIMD-Explained.html
506//
507template <typename T>
509 NdArray<Simd<T, 4>, 4> const& mat) {
510#if MOCHI_ASSERT_VERBOSE_ENABLED
511 constexpr T tol = T{10} * kDefaultNearEqualEpsilon<T>;
512
514 (mat[0][3] == 0) && (mat[1][3] == 0) && (mat[2][3] == 0) && (mat[3][3] == 1),
515 "Expected a transformation matrix where the last column is {0, 0, 0, 1}");
516
517 auto n0 = Norm<3>(mat[0]);
518 auto n1 = Norm<3>(mat[1]);
519 auto n2 = Norm<3>(mat[2]);
521 NearZero(Dot<3>(mat[0], mat[1]), tol * n0 * n1) &&
522 NearZero(Dot<3>(mat[1], mat[2]), tol * n1 * n2) &&
523 NearZero(Dot<3>(mat[2], mat[0]), tol * n0 * n2),
524 "Expected a transformation matrix with orthogonal basis vectors");
525
526#endif // MOCHI_ASSERT_VERBOSE_ENABLED
527
528 NdArray<Simd<T, 4>, 4> r;
529
530 // Transpose 3x3. We know m03 = m13 = m23 = 0
531 auto t0 = Shuffle<0, 1, 0, 1>(mat[0], mat[1]); // 00, 01, 10, 11
532 auto t1 = Shuffle<2, 3, 2, 3>(mat[0], mat[1]); // 02, 03, 12, 13
533 r[0] = Shuffle<0, 2, 0, 3>(t0, mat[2]); // 00, 10, 20, 23(=0)
534 r[1] = Shuffle<1, 3, 1, 3>(t0, mat[2]); // 01, 11, 21, 23(=0)
535 r[2] = Shuffle<0, 2, 2, 3>(t1, mat[2]); // 02, 12, 22, 23(=0)
536
537 // Invert scale
538 auto sizeSqr = r[0] * r[0] + r[1] * r[1] + r[2] * r[2];
540 AllTrue<3>(sizeSqr > Sqr(tol)),
541 "Transformation matrix has degenerate scale on at least one axis");
542 auto rSizeSqr = T(1) / ToSimdPoint(sizeSqr);
543 r[0] *= rSizeSqr;
544 r[1] *= rSizeSqr;
545 r[2] *= rSizeSqr;
546
547 // Last row (translation)
548 r[3] = r[0] * Broadcast<0>(mat[3]) + r[1] * Broadcast<1>(mat[3]) + r[2] * Broadcast<2>(mat[3]);
549 r[3] = ToSimdPoint(-r[3]);
550
551 return r;
552}
553
554template <typename T>
556 // This performs 8 SIMD shuffles to transpose the input and another 8 to transpose the result
557 // (thus about 16 cycles slower than InvertTransformationTransposed). This could be improved if we
558 // think it is worth the effort.
560}
561
562/**************************************************************************************************
563 Matrix Builders
564*/
565
566template <size_t N, typename T>
568 NdArray<T, N, N> result = {};
569 for (size_t i = 0; i < result.size(); ++i) {
570 result[i][i] = valueOnDiagonal;
571 }
572 return result;
573}
574
575template <size_t N, typename T>
577 NdArray<T, N, N> result = {};
578 for (size_t i = 0; i < result.size(); ++i) {
579 result[i][i] = diagonalVector[i];
580 }
581 return result;
582}
583
584template <typename T>
585MOCHI_FORCE_INLINE constexpr NdArray<T, 3> Sym2x2Components(T a00, T a01, T a11) {
586 return {a00, a01, a11};
587}
588
589template <typename T>
591 return {m[0][0], T{0.5_r} * (m[0][1] + m[1][0]), m[1][1]};
592}
593
594template <typename T>
595MOCHI_FORCE_INLINE constexpr NdArray<T, 2, 2> SymMatrix2x2(T a00, T a01, T a11) {
596 return {NdArray<T, 2>{a00, a01}, NdArray<T, 2>{a01, a11}};
597}
598
599template <size_t N, typename T>
601 return DiagonalMatrix<N, T>((T)1);
602}
603
604// Return an NxN array with a given array down the diagonal.
605template <size_t N, typename T>
607 static_assert(N >= 1 && N <= 4, "Requires 1-4 rows");
608 using V = Simd<T, 4>;
609 NdArray<V, N> result = {};
610 auto zeros = SimdZero<V>();
611 if constexpr (N >= 1) {
612 result[0] = Blend<0, 1, 1, 1>(diagonalVector, zeros);
613 }
614 if constexpr (N >= 2) {
615 result[1] = Blend<1, 0, 1, 1>(diagonalVector, zeros);
616 }
617 if constexpr (N >= 3) {
618 result[2] = Blend<1, 1, 0, 1>(diagonalVector, zeros);
619 }
620 if constexpr (N == 4) {
621 result[3] = Blend<1, 1, 1, 0>(diagonalVector, zeros);
622 }
623 return result;
624}
625
626template <size_t N, typename T>
628 return VDiagonalMatrix<N>(Simd<T, 4>{valueOnDiagonal});
629}
630
631template <size_t N, typename T>
635
636/**************************************************************************************************
637 Matrix Determinant
638*/
639
640template <typename T>
642 return A[0][0] * A[1][1] - A[0][1] * A[1][0];
643}
644
645template <typename T>
647 return //
648 A[0][0] * (A[1][1] * A[2][2] - A[1][2] * A[2][1]) -
649 A[0][1] * (A[1][0] * A[2][2] - A[1][2] * A[2][0]) +
650 A[0][2] * (A[1][0] * A[2][1] - A[1][1] * A[2][0]);
651}
652
653template <typename T>
655 return Det4x4(&A[0][0]);
656}
657
658template <typename T, size_t N>
660 static_assert(N == 3 || N == 4, "Expected a 3x3 or 4x4 Simd matrix");
661
662 // Equivalent to:
663 //
664 // return
665 // A[0][0] * (A[1][1] * A[2][2] - A[1][2] * A[2][1]) -
666 // A[0][1] * (A[1][0] * A[2][2] - A[1][2] * A[2][0]) +
667 // A[0][2] * (A[1][0] * A[2][1] - A[1][1] * A[2][0]);
668 //
669 auto const a = Shuffle<1, 0, 0, 0>(A[1]);
670 auto const b = Shuffle<2, 2, 1, 0>(A[2]);
671 auto const c = Shuffle<2, 2, 1, 0>(A[1]);
672 auto const d = Shuffle<1, 0, 0, 0>(A[2]);
673 auto const result = A[0] * (a * b - c * d);
674 return Broadcast<0>(result) - Broadcast<1>(result) + Broadcast<2>(result);
675}
676
677// Calculate the determinant of the 3x3 portion of a Vec4r[N]. Ignores the last column.
678template <typename T, size_t N>
680 return Get<0>(VDet3x3(A));
681}
682
683template <typename T>
685 return A[0] * A[3] - A[1] * A[2];
686}
687/**************************************************************************************************
688 Matrix Transpose
689*/
690
691template <typename T, size_t N, size_t M>
693 NdArray<T, M, N> result = {};
694 for (size_t i = 0; i < M; ++i) {
695 for (size_t j = 0; j < N; ++j) {
696 result[i][j] = mat[j][i];
697 }
698 }
699 return result;
700}
701
702template <typename T>
704 // Adapted from _MM_TRANSPOSE4_PS
705 auto const temp0 = Shuffle<0, 1, 0, 1>(m[0], m[1]);
706 auto const temp2 = Shuffle<2, 3, 2, 3>(m[0], m[1]);
707 auto const temp1 = Shuffle<0, 1, 0, 1>(m[2], m[3]);
708 auto const temp3 = Shuffle<2, 3, 2, 3>(m[2], m[3]);
709 return {
710 Shuffle<0, 2, 0, 2>(temp0, temp1),
711 Shuffle<1, 3, 1, 3>(temp0, temp1),
712 Shuffle<0, 2, 0, 2>(temp2, temp3),
713 Shuffle<1, 3, 1, 3>(temp2, temp3),
714 };
715}
716
717template <typename T>
719 // Input is row-major: [a00, a01, a10, a11]
720 // Output is row-major: [a00, a10, a01, a11]
721 return Shuffle<0, 2, 1, 3>(m);
722}
723
724template <typename T, size_t D0>
726 static_assert(D0 == 3 || D0 == 4, "Expected 3x3 or 4x3 matrix");
727 // Transpose the 3x3 portion. Fill the 4th column with m[2][3]
728 auto const temp0 = Shuffle<0, 1, 0, 1>(m[0], m[1]);
729 auto const temp1 = Shuffle<2, 3, 2, 3>(m[0], m[1]);
730 return {
731 Shuffle<0, 2, 0, 3>(temp0, m[2]),
732 Shuffle<1, 3, 1, 3>(temp0, m[2]),
733 Shuffle<0, 2, 2, 3>(temp1, m[2]),
734 };
735}
736
737/**************************************************************************************************
738 Matrix Cofactor
739*/
740
741template <typename T>
743 NdArray<T, 2, 2> cofactor{
744 NdArray<T, 2>{mat[1][1], -mat[1][0]}, NdArray<T, 2>{-mat[0][1], mat[0][0]}};
745 return cofactor;
746}
747
748template <typename T>
749inline constexpr NdArray<T, 3, 3> Cofactor(NdArray<T, 3, 3> const& mat) {
750 NdArray<T, 3, 3> cofactor{
752 mat[1][1] * mat[2][2] - mat[1][2] * mat[2][1],
753 mat[1][2] * mat[2][0] - mat[1][0] * mat[2][2],
754 mat[1][0] * mat[2][1] - mat[1][1] * mat[2][0]},
756 mat[0][2] * mat[2][1] - mat[0][1] * mat[2][2],
757 mat[0][0] * mat[2][2] - mat[0][2] * mat[2][0],
758 mat[0][1] * mat[2][0] - mat[0][0] * mat[2][1]},
760 mat[0][1] * mat[1][2] - mat[0][2] * mat[1][1],
761 mat[0][2] * mat[1][0] - mat[0][0] * mat[1][2],
762 mat[0][0] * mat[1][1] - mat[0][1] * mat[1][0]}};
763 return cofactor;
764}
765
766// Calculate the cofactor matrix from the 3x3 portion of a Vec4r[3].
767// The last column of the result should be ignored.
768template <typename T>
770 // Equivalent to Transpose(Invert(mat, 1_r)), which reduces to:
771 //
772 // return {
773 // NdArray<T, 3>{mat[1][1] * mat[2][2] - mat[1][2] * mat[2][1],
774 // mat[1][2] * mat[2][0] - mat[1][0] * mat[2][2],
775 // mat[1][0] * mat[2][1] - mat[1][1] * mat[2][0]},
776 // NdArray<T, 3>{mat[0][2] * mat[2][1] - mat[0][1] * mat[2][2],
777 // mat[0][0] * mat[2][2] - mat[0][2] * mat[2][0],
778 // mat[0][1] * mat[2][0] - mat[0][0] * mat[2][1]},
779 // NdArray<T, 3>{mat[0][1] * mat[1][2] - mat[0][2] * mat[1][1],
780 // mat[0][2] * mat[1][0] - mat[0][0] * mat[1][2],
781 // mat[0][0] * mat[1][1] - mat[0][1] * mat[1][0]},
782 // };
783
784 // Prepare multiples for row0 of the result
785 auto const a1 = Shuffle<1, 2, 2, 0>(mat[1], mat[1]);
786 auto const b1 = Shuffle<2, 1, 0, 2>(mat[2], mat[2]);
787 auto const a2 = mat[1]; // Shuffle<0, 1, 0, 0>(mat[1], mat[1]);
788 auto const b2 = Shuffle<1, 0, 0, 0>(mat[2], mat[2]);
789
790 // Prepare multiplies for row1 of the result
791 auto const c1 = Shuffle<2, 1, 0, 2>(mat[0], mat[0]);
792 auto const d1 = Shuffle<1, 2, 2, 0>(mat[2], mat[2]);
793 auto const c2 = Shuffle<1, 0, 0, 0>(mat[0], mat[0]);
794 auto const d2 = mat[2]; // Shuffle<0, 1, 0, 0>(mat[2], mat[2]);
795
796 // Prepare multiples for row2 of the result
797 auto const e1 = Shuffle<1, 2, 2, 0>(mat[0], mat[0]);
798 auto const f1 = Shuffle<2, 1, 0, 2>(mat[1], mat[1]);
799 auto const e2 = mat[0]; // Shuffle<0, 1, 0, 0>(mat[0], mat[0]);
800 auto const f2 = Shuffle<1, 0, 0, 0>(mat[1], mat[1]);
801
802 // Multiply cofactors
803 auto const a1b1 = a1 * b1;
804 auto const a2b2 = a2 * b2;
805 auto const c1d1 = c1 * d1;
806 auto const c2d2 = c2 * d2;
807 auto const e1f1 = e1 * f1;
808 auto const e2f2 = e2 * f2;
809
810 // Shuffle results of multiples so they can be subtracted and returned.
811 return {
812 Shuffle<0, 2, 0, 0>(a1b1, a2b2) - Shuffle<1, 3, 1, 0>(a1b1, a2b2),
813 Shuffle<0, 2, 0, 0>(c1d1, c2d2) - Shuffle<1, 3, 1, 0>(c1d1, c2d2),
814 Shuffle<0, 2, 0, 0>(e1f1, e2f2) - Shuffle<1, 3, 1, 0>(e1f1, e2f2),
815 };
816}
817
818// Calculate the cofactor matrix from the symmetric 2x2 SIMD matrix.
819template <typename T>
823
824// Calculate the cofactor matrix from the symmetric 3x3 SIMD matrix.
825template <typename T>
827 // Equivalent to Transpose(Invert(mat, 1_r)), which reduces to:
828 //
829 // |bc - ff, ef - dc, df - be|
830 // | · , ac - ee, de - af|
831 // | · , · , ab - dd|
832 //
833 // diag = (bc - ff, ac - ee, ab - dd)
834 // offd = (ef - dc, df - be, de - af)
835
836 auto diag = Shuffle<1, 0, 0, 3>(mat[0]) * Shuffle<2, 2, 1, 3>(mat[0]) -
837 Shuffle<2, 1, 0, 3>(mat[1] * mat[1]);
838
839 auto offd = Shuffle<1, 0, 0, 3>(mat[1]) * Shuffle<2, 2, 1, 3>(mat[1]) -
840 mat[1] * Shuffle<2, 1, 0, 3>(mat[0]);
841
842 return NdArray<Simd<T, 4>, 2>{diag, offd};
843}
844
845/**************************************************************************************************
846 Matrix Trace (sum of diagonal elements)
847*/
848template <typename T, size_t DimTotal, size_t DimTrace>
850 static_assert(DimTrace <= DimTotal, "Invalid dimensions");
851 static_assert(DimTotal >= 1, "Invalid dimensions");
852 static_assert(DimTrace >= 1, "Invalid dimensions");
853 T trace = T(0);
854 if constexpr (DimTrace >= 1) {
855 trace += mat[0][0];
856 }
857 if constexpr (DimTrace >= 2) {
858 trace += mat[1][1];
859 }
860 if constexpr (DimTrace >= 3) {
861 trace += mat[2][2];
862 }
863 if constexpr (DimTrace >= 4) {
864 trace += mat[3][3];
865 }
866 if constexpr (DimTrace >= 5) {
867 for (int i = 4; i < DimTrace; ++i) {
868 trace += mat[i][i];
869 }
870 }
871 return trace;
872}
873
874template <typename T>
875MOCHI_FORCE_INLINE constexpr T Trace2x2(Simd<T, 4> const& mat) {
876 return mat[0] + mat[3];
877}
878
879template <typename T>
880MOCHI_FORCE_INLINE constexpr T Trace3x3(NdArray<Simd<T, 4>, 3> const& mat) {
881 return Get<0>(mat[0]) + Get<1>(mat[1]) + Get<2>(mat[2]);
882}
883
884/**************************************************************************************************
885 Skew-symmetric matrix
886*/
887
888// Return the 3x3 skew-symmetric matrix [v] of a vector v, s.t. [v] * u = v x u, [v] = -[v]^T
889template <typename T>
891 T const zero{0};
892 return {
893 NdArray<T, 3>{zero, -v[2], v[1]},
894 NdArray<T, 3>{v[2], zero, -v[0]},
895 NdArray<T, 3>{-v[1], v[0], zero}};
896}
897
898// Return the 3x3 skew-symmetric matrix [v] of a vector v, s.t. [v] * u = v x u, [v] = -[v]^T
899template <typename T>
901 Simd<T, 4> v = Set<3>(vector, T(0));
902 return {
906 };
907}
908
909// Return the vector v s.t. skew(v) is the anti-symmetric part of the input matrix
910template <typename T>
912 return T(0.5) *
914 matrix[2][1] - matrix[1][2], matrix[0][2] - matrix[2][0], matrix[1][0] - matrix[0][1]};
915}
916
917// Computes the first derivative of Skew(v)
918template <typename T>
920 using V = Simd<T, 4>;
921 NdArray<V, 3, 3> dskew;
922 dskew[0] = Skew3(SimdBasisVector<0, V>());
923 dskew[1] = Skew3(SimdBasisVector<1, V>());
924 dskew[2] = Skew3(SimdBasisVector<2, V>());
925 return dskew;
926}
927
928/**************************************************************************************************
929 Vector Derivatives
930*/
931
932// Derivative of normalized 3-vector w.r.t. vector
933template <typename T>
935 T const vNorm = Norm<3>(v) + std::numeric_limits<T>::min();
936 Simd<T, 4> const vHat = v / vNorm;
937 return (VEye<3, T>() - Outer3(vHat, vHat)) / vNorm;
938}
939
940template <typename T, size_t N>
942 return DNormalize(v, NormSqr(v));
943}
944
945template <typename T, size_t N>
947 constexpr auto kMin = std::numeric_limits<ScalarType<T>>::min();
948 static_assert(kMin > 0); // Check numeric_limits has been correctly specialized.
949 T const invNorm = T(1) / (Sqrt(sqrNorm) + T(kMin));
950 NdArray<T, N> const n = v * invNorm;
951 NdArray<T, N, N> result{};
952 for (size_t i = 0; i < N; ++i) {
953 for (size_t j = 0; j < N; ++j) {
954 result[i][j] = -n[i] * n[j] * invNorm;
955 }
956 result[i][i] += invNorm;
957 }
958 return result;
959}
960
961/**************************************************************************************************
962 Matrix Row/Column Selection
963*/
964
965// Retrieves the largest row (in the L-2 sense) of the given matrix. Optionally outputs
966// its squared norm.
967template <typename T, size_t D0, size_t D1>
968inline constexpr auto LargestRow(NdArray<T, D0, D1> const& A, T* sqrNorm) {
969 // Compute per-row norms.
970 NdArray<T, D0> sqrNorms = {};
971 for (size_t i = 0; i < D0; ++i) {
972 sqrNorms[i] = NormSqr(A[i]);
973 }
974
975 // Identify row with largest squared L2 norm.
976 auto index = ArgMax(sqrNorms);
977
978 // Store its squared norm if requested.
979 if (sqrNorm != nullptr) {
980 *sqrNorm = sqrNorms[index];
981 }
982
983 // Return largest row.
984 return A[index];
985}
986
987inline auto LargestRowColSym2x2(VSymMatrix2x2r A, Vec4r& outNormSqr) {
988 // Vectors are:
989 // r₁ = (a, c)
990 // r₂ = (c, b)
991
992 // Evaluate squared norms.
993 Vec4r entriesSqr = A * A; // (a², c², b², ?)
994 Vec4r temp0 = Broadcast<1>(entriesSqr); // (c², c², ?, ?)
995 Vec4r normSqr = entriesSqr + temp0; // (|r₁|², ?, |r₂|², ?)
996 real r1NormSqr = Get<0>(normSqr);
997 real r2NormSqr = Get<2>(normSqr);
998
999 // Shuffle values according depending on which row was larger
1000 if (r1NormSqr > r2NormSqr) {
1001 outNormSqr = r1NormSqr;
1002 return Shuffle<0, 1, 3, 3>(A);
1003 } else {
1004 outNormSqr = r2NormSqr;
1005 return Shuffle<1, 2, 3, 3>(A);
1006 }
1007}
1008
1009inline auto LargestRowColSym3x3(VSymMatrix3x3r A, Vec4r& outNormSqr) {
1010 // Vectors are:
1011 // r₁ = (a, d, e)
1012 // r₂ = (d, b, f)
1013 // r₃ = (e, f, c)
1014
1015 // Evaluate squared norms.
1016 Vec4r diagSqr = A[0] * A[0]; // (a², b², c², ?)
1017 Vec4r offdSqr = A[1] * A[1]; // (d², e², f², ?)
1018 Vec4r temp0 = Shuffle<0, 0, 2, 3>(offdSqr); // (d², d², f², ?)
1019 Vec4r temp1 = Shuffle<1, 2, 1, 3>(offdSqr); // (e², f², e², ?)
1020 Vec4r normSqr = diagSqr + temp0 + temp1; // (|r₁|², |r₂|², |r₃|², ?)
1021
1022 // Blend entries according to norms.
1023 real max = HMax<3>(normSqr);
1024 if (max == Get<0>(normSqr)) { // If r1 was the largest row
1025 outNormSqr = Broadcast<0>(normSqr);
1026 return Blend<0, 1, 1, 0>(A[0], Shuffle<0, 0, 1, 0>(A[1]));
1027 } else if (max == Get<1>(normSqr)) { // If r2 was the largest row
1028 outNormSqr = Broadcast<1>(normSqr);
1029 return Blend<1, 0, 1, 0>(A[0], Shuffle<0, 0, 2, 0>(A[1]));
1030 } else { // If r3 was the largest row
1031 outNormSqr = Broadcast<2>(normSqr);
1032 return Blend<1, 1, 0, 0>(A[0], Shuffle<1, 2, 0, 0>(A[1]));
1033 }
1034}
1035
1036} // namespace superdex
static constexpr int size()
Definition nd_array.h:78
constexpr SizeT size() const
Definition span.h:106
#define MOCHI_ASSERT_VERBOSE(condition_without_side_effects,...)
Definition debug.h:102
#define MOCHI_FORCE_INLINE
constexpr NdArray< T, M > DotVecMat(NdArray< T, N > const &a, NdArray< T, N, M > const &b)
T Dot(Simd< T, N > a, Simd< T, N > b)
Definition simd.h:673
Simd< T, 2 > Shuffle(Simd< T, 2 > a)
Definition simd_inl.h:273
constexpr T Trace(NdArray< T, DimTotal, DimTotal > const &mat)
constexpr NdArray< T, N, N > DNormalize(NdArray< T, N > const &v)
constexpr NdArray< T, 2, 2 > SymMatrix2x2(T a00, T a01, T a11)
NdArray< Simd< T, 4 >, 3 > DNormalize3(Simd< T, 4 > const &v)
Simd< T, 4 > Transpose2x2(Simd< T, 4 > const &m)
constexpr NdArray< T, 3 > Sym2x2Components(T a00, T a01, T a11)
T NormSqr(Simd< T, N > a)
Definition simd_inl.h:874
NdArray< Simd< T, 4 >, 3 > Cofactor3x3(NdArray< Simd< T, 4 >, 3 > const &mat)
Simd< T, 4 > DotVecMat4x4(Simd< T, 4 > a, NdArray< Simd< T, 4 >, 4 > const &b)
Simd< T, 4 > Invert2x2(Simd< T, 4 > const &mat, T det)
NdArray< Simd< T, 4 >, 4 > InvertTransformation(NdArray< Simd< T, 4 >, 4 > const &mat)
constexpr Simd< T, 4 > InvSkew3(NdArray< Simd< T, 4 >, 3 > const &matrix)
T HSum(Simd< T, N > a)
Definition simd_inl.h:377
constexpr T kDefaultNearEqualEpsilon
V VDot(V a, V b)
Definition simd_inl.h:851
T Norm(Simd< T, N > a)
Definition simd_inl.h:879
T Det2x2(Simd< T, 4 > const &A)
bool AllTrue(T const &a)
Definition basic_utils.h:60
V SimdBasisVector()
Definition simd_inl.h:151
Simd< T, 4 > DotMatVec3xN(NdArray< Simd< T, 4 >, D0 > const &m, Simd< T, 4 > v)
constexpr auto LargestRow(NdArray< T, D0, D1 > const &A, T *sqrNorm=nullptr)
NdArray< Simd< T, 4 >, 3, 3 > VDSkew3()
constexpr NdArray< T, N > DotMatVec(NdArray< T, N, M > const &a, NdArray< T, M > const &b)
Simd< T, 4 > DotMatVec4x4(NdArray< Simd< T, 4 >, 4 > const &m, Simd< T, 4 > v)
Simd< T, N > Set(Simd< T, N > a, T value)
Definition simd_inl.h:313
NdArray< Simd< T, 4 >, 3 > Transpose3x3(NdArray< Simd< T, 4 >, D0 > const &m)
Simd< real, 4 > Vec4r
Definition simd.h:206
NdArray< Simd< T, 4 >, 2 > CofactorSym3x3(NdArray< Simd< T, 4 >, 2 > const &mat)
V SimdZero()
Definition simd_inl.h:146
T HMax(Simd< T, N > a)
Definition simd_inl.h:395
NdArray< Simd< T, 4 >, 4 > InvertTransformationTransposed(NdArray< Simd< T, 4 >, 4 > const &mat)
Simd< real, 4 > VSymMatrix2x2r
Special case for the SIMD representation of a 2x2 symmetric matrix.
Definition vmatrix.h:84
V Broadcast(typename V::Scalar a)
Definition simd_inl.h:115
constexpr NdArray< T, M, N > Transpose(NdArray< T, N, M > const &mat)
auto LargestRowColSym2x2(VSymMatrix2x2r A, Vec4r &outNormSqr)
Simd< T, N > Blend(Simd< T, N > a, Simd< T, N > b)
Definition simd_inl.h:288
constexpr NdArray< T, N, N > Eye()
TransformRT Invert(TransformRT const &a)
Simd< T, 4 > DotVecMat3x3(Simd< T, 4 > v, NdArray< Simd< T, 4 >, D0 > const &m)
constexpr T Colon(NdArray< T, N, M > const &A, NdArray< T, N, M > const &B)
constexpr T Minor4x4(T const m[16], int r0, int r1, int r2, int c0, int c1, int c2)
Simd< T, 4 > DotVecMat2x3(Simd< T, 4 > v, NdArray< Simd< T, 4 >, 2 > const &m)
constexpr T Sqr(T a)
NdArray< Simd< T, 4 >, 4 > Transpose4x4(NdArray< Simd< T, 4 >, 4 > const &m)
NdArray< Simd< T, 4 >, 2, 2 > Outer2(Simd< T, 4 > const &a, Simd< T, 4 > const &b)
constexpr T Sqrt(T a)
void PseudoInvert(NdArray< T, 3, 2 > const &a, NdArray< T, 2, 3 > *outInv, T *outDet)
NdArray< Simd< T, 4 >, 4 > Dot4x4(NdArray< Simd< T, 4 >, 4 > const &a, NdArray< Simd< T, 4 >, 4 > const &b)
T Colon3x3(NdArray< Simd< T, 4 >, 3 > const &A, NdArray< Simd< T, 4 >, 3 > const &B)
constexpr T Det4x4(T const m[16])
NdArray< Simd< T, 4 >, 2 > OuterSym3(Simd< T, 4 > a, Simd< T, 4 > b)
auto LargestRowColSym3x3(VSymMatrix3x3r A, Vec4r &outNormSqr)
T Get(Simd< T, N > v)
Definition simd_inl.h:303
Simd< T, 4 > DotMatVec3x3(NdArray< Simd< T, 4 >, D0 > const &m, Simd< T, 4 > v)
Simd< T, 4 > Dot2x2(Simd< T, 4 > const &a, Simd< T, 4 > const &b)
constexpr NdArray< T, 3, 3 > Skew(NdArray< T, 3 > const &v)
constexpr NdArray< Simd< T, 4 >, 3 > Skew3(Simd< T, 4 > const &vector)
NdArray< Simd< T, 4 >, 3 > Invert3x3(NdArray< Simd< T, 4 >, 3 > const &mat)
constexpr size_t ArgMax(NdArray< T, N > const &a)
constexpr NdArray< T, 2, 2 > Cofactor(NdArray< T, 2, 2 > const &mat)
T Norm3x3(NdArray< Simd< T, D1 >, D0 > const &a)
T NormSqr3x3(NdArray< Simd< T, D1 >, D0 > const &a)
constexpr void Cofactor4x4(T const m[16], T adjOut[16])
T Get0(Simd< T, N > v)
Definition simd_inl.h:298
Simd< T, 4 > CofactorSym2x2(Simd< T, 4 > const &mat)
constexpr NdArray< T, 2, 2 > Outer(NdArray< T, 2 > const &a, NdArray< T, 2 > const &b)
constexpr T Trace3x3(NdArray< Simd< T, 4 >, 3 > const &mat)
NdArray< Simd< T, 4 >, 3 > Outer3(Simd< T, 4 > a, Simd< T, 4 > b)
constexpr T ColonSym2x2(NdArray< T, 3 > const &A, NdArray< T, 3 > const &B)
constexpr void InvertRowMajor4x4(T const m[16], T invOut[16])
NdArray< Simd< real, 4 >, 2 > VSymMatrix3x3r
Special case for the SIMD representation of a 3x3 symmetric matrix.
Definition vmatrix.h:96
NdArray< Simd< T, 4 >, N > VEye()
constexpr T Det(NdArray< T, 2, 2 > const &A)
bool NearEqual(TransformRT const &a, TransformRT const &b, real epsilon=kDefaultNearEqualEpsilon< real >)
constexpr NdArray< T, N, N > DiagonalMatrix(T valueOnDiagonal)
NdArray< Simd< T, 4 >, N > VDiagonalMatrix(T valueOnDiagonal)
constexpr T Trace2x2(Simd< T, 4 > const &mat)
Simd< T, N > Neg(Simd< T, N > a)
Definition simd_inl.h:338
T Det3x3(NdArray< Simd< T, 4 >, N > const &A)
V ToSimdPoint(V a)
Definition simd_inl.h:174
constexpr auto NearZero(T const &a, T epsilon=kDefaultNearEqualEpsilon< T >)
constexpr NdArray< Simd< T, 4 >, 4 > Invert4x4(NdArray< Simd< T, 4 >, 4 > const &A)
constexpr NdArray< T, 3 > Cross(NdArray< T, 3 > const &a, NdArray< T, 3 > const &b)
Simd< T, 4 > VDet3x3(NdArray< Simd< T, 4 >, N > const &A)
NdArray< Simd< T, 4 >, 3 > Dot3x3(NdArray< Simd< T, 4 >, D0A > const &a, NdArray< Simd< T, 4 >, D0B > const &b)