1use std::array::from_fn;
11use std::fmt;
12use std::mem;
13use std::ops::{Add, BitXor, Div, Index, IndexMut, Mul, Neg, Sub};
14
15use crate::point::Point3;
16use crate::scalar::{
17 clone_with_abort, reject_definite_zero, require_known_nonzero,
18 require_known_nonzero_with_abort, with_abort, zero_status, zero_status_with_abort,
19};
20use crate::vector::{Vector3, Vector4, Vector4GeometricFacts, Vector4HomogeneousKind};
21use crate::{
22 AbortSignal, BlasResult, CheckedBlasResult, ExactRationalKind, ExactRealSetFacts, Problem,
23 Real, RealKernelExt, RealSign, RealSymbolicDependencyMask, RealZeroOneMinusOneStatus,
24 ZeroStatus,
25};
26
27fn identity_array<const N: usize>() -> [[Real; N]; N] {
28 from_fn(|row| {
29 from_fn(|col| {
30 if row == col {
31 Real::one()
32 } else {
33 Real::zero()
34 }
35 })
36 })
37}
38
39fn transpose_array3(matrix: [[Real; 3]; 3]) -> [[Real; 3]; 3] {
40 let [[m00, m01, m02], [m10, m11, m12], [m20, m21, m22]] = matrix;
47 [[m00, m10, m20], [m01, m11, m21], [m02, m12, m22]]
48}
49
50fn transpose_array3_ref(matrix: &[[Real; 3]; 3]) -> [[Real; 3]; 3] {
51 [
52 [
53 matrix[0][0].clone(),
54 matrix[1][0].clone(),
55 matrix[2][0].clone(),
56 ],
57 [
58 matrix[0][1].clone(),
59 matrix[1][1].clone(),
60 matrix[2][1].clone(),
61 ],
62 [
63 matrix[0][2].clone(),
64 matrix[1][2].clone(),
65 matrix[2][2].clone(),
66 ],
67 ]
68}
69
70fn transpose_array4(matrix: [[Real; 4]; 4]) -> [[Real; 4]; 4] {
71 let [
76 [m00, m01, m02, m03],
77 [m10, m11, m12, m13],
78 [m20, m21, m22, m23],
79 [m30, m31, m32, m33],
80 ] = matrix;
81 [
82 [m00, m10, m20, m30],
83 [m01, m11, m21, m31],
84 [m02, m12, m22, m32],
85 [m03, m13, m23, m33],
86 ]
87}
88
89fn transpose_array4_ref(matrix: &[[Real; 4]; 4]) -> [[Real; 4]; 4] {
90 [
93 [
94 matrix[0][0].clone(),
95 matrix[1][0].clone(),
96 matrix[2][0].clone(),
97 matrix[3][0].clone(),
98 ],
99 [
100 matrix[0][1].clone(),
101 matrix[1][1].clone(),
102 matrix[2][1].clone(),
103 matrix[3][1].clone(),
104 ],
105 [
106 matrix[0][2].clone(),
107 matrix[1][2].clone(),
108 matrix[2][2].clone(),
109 matrix[3][2].clone(),
110 ],
111 [
112 matrix[0][3].clone(),
113 matrix[1][3].clone(),
114 matrix[2][3].clone(),
115 matrix[3][3].clone(),
116 ],
117 ]
118}
119
120#[inline]
121fn matrix_mask<const N: usize>() -> u16 {
122 debug_assert!(N * N <= u16::BITS as usize);
123 if N * N == u16::BITS as usize {
124 u16::MAX
125 } else {
126 (1_u16 << (N * N)) - 1
127 }
128}
129
130#[inline]
131fn matrix_entry_bit<const N: usize>(row: usize, column: usize) -> u16 {
132 1_u16 << (row * N + column)
133}
134
135#[inline]
136fn matrix_entry_mask_value<const N: usize>(mask: u16, row: usize, column: usize) -> Option<bool> {
137 if row < N && column < N {
138 Some((mask & matrix_entry_bit::<N>(row, column)) != 0)
139 } else {
140 None
141 }
142}
143
144#[inline]
145fn matrix_lane_known_zero_count<const N: usize>(mask: u8) -> u32 {
146 debug_assert!(N <= u8::BITS as usize);
147 (mask & ((1_u8 << N) - 1)).count_ones()
148}
149
150#[inline]
151fn matrix_lane_has_sparse_support<const N: usize>(mask: u8) -> bool {
152 matrix_lane_known_zero_count::<N>(mask) >= (N as u32).saturating_sub(1)
153}
154
155#[inline]
156fn matrix_lane_is_known_zero<const N: usize>(mask: u8) -> bool {
157 matrix_lane_known_zero_count::<N>(mask) == N as u32
158}
159
160#[inline]
161fn matrix_has_zero_lane<const N: usize>(masks: [u8; N]) -> bool {
162 masks.into_iter().any(matrix_lane_is_known_zero::<N>)
163}
164
165#[inline]
166fn matrix_determinant_schedule_hint<const N: usize>(
167 exact: ExactRealSetFacts,
168 row_zero_masks: [u8; N],
169 column_zero_masks: [u8; N],
170 is_diagonal: bool,
171 is_upper_triangular: bool,
172 is_lower_triangular: bool,
173) -> MatrixDeterminantScheduleHint {
174 if matrix_has_zero_lane::<N>(row_zero_masks) || matrix_has_zero_lane::<N>(column_zero_masks) {
175 return MatrixDeterminantScheduleHint::StructurallyZero;
176 }
177 if is_diagonal {
178 return MatrixDeterminantScheduleHint::Diagonal;
179 }
180 if is_upper_triangular || is_lower_triangular {
181 return MatrixDeterminantScheduleHint::Triangular;
182 }
183 if row_zero_masks
184 .into_iter()
185 .all(matrix_lane_has_sparse_support::<N>)
186 || column_zero_masks
187 .into_iter()
188 .all(matrix_lane_has_sparse_support::<N>)
189 {
190 return MatrixDeterminantScheduleHint::SparseSupport;
191 }
192 if exact.has_shared_denominator_schedule() {
193 return MatrixDeterminantScheduleHint::SharedDenominator;
194 }
195 if exact.has_dyadic_schedule() {
196 return MatrixDeterminantScheduleHint::Dyadic;
197 }
198 if exact.is_nonempty_exact_rational() {
199 return MatrixDeterminantScheduleHint::ExactRational;
200 }
201 MatrixDeterminantScheduleHint::GenericRealFallback
202}
203
204#[inline]
205fn matrix_zero_masks<const N: usize>(matrix: &[[Real; N]; N]) -> (u16, [u8; N], [u8; N]) {
206 let mut entry_mask = 0_u16;
207 let mut row_masks = [0_u8; N];
208 let mut column_masks = [0_u8; N];
209 for row in 0..N {
210 for column in 0..N {
211 if matrix[row][column].definitely_zero() {
212 entry_mask |= matrix_entry_bit::<N>(row, column);
213 row_masks[row] |= 1_u8 << column;
214 column_masks[column] |= 1_u8 << row;
215 }
216 }
217 }
218 (entry_mask, row_masks, column_masks)
219}
220
221#[inline]
222fn matrix_one_mask<const N: usize>(matrix: &[[Real; N]; N]) -> u16 {
223 let mut mask = 0_u16;
224 for row in 0..N {
225 for column in 0..N {
226 if matrix[row][column].definitely_one() {
227 mask |= matrix_entry_bit::<N>(row, column);
228 }
229 }
230 }
231 mask
232}
233
234#[inline]
235fn matrix_zero_masks_assuming_size<const N: usize, const M: usize>(
236 matrix: &[[Real; N]; N],
237) -> (u16, [u8; M], [u8; M]) {
238 debug_assert_eq!(N, M);
239 let mut entry_mask = 0_u16;
240 let mut row_masks = [0_u8; M];
241 let mut column_masks = [0_u8; M];
242 for row in 0..M {
243 for column in 0..M {
244 if matrix[row][column].definitely_zero() {
245 entry_mask |= matrix_entry_bit::<M>(row, column);
246 row_masks[row] |= 1_u8 << column;
247 column_masks[column] |= 1_u8 << row;
248 }
249 }
250 }
251 (entry_mask, row_masks, column_masks)
252}
253
254#[inline]
255fn matrix_one_mask_assuming_size<const N: usize, const M: usize>(matrix: &[[Real; N]; N]) -> u16 {
256 debug_assert_eq!(N, M);
257 let mut mask = 0_u16;
258 for row in 0..M {
259 for column in 0..M {
260 if matrix[row][column].definitely_one() {
261 mask |= matrix_entry_bit::<M>(row, column);
262 }
263 }
264 }
265 mask
266}
267
268#[inline]
269fn matrix_symbolic_dependency_mask<const N: usize>(
270 matrix: &[[Real; N]; N],
271) -> RealSymbolicDependencyMask {
272 matrix
273 .iter()
274 .flat_map(|row| row.iter())
275 .fold(RealSymbolicDependencyMask::NONE, |mask, value| {
276 mask.union(value.detailed_facts().symbolic.dependencies)
277 })
278}
279
280#[inline]
281fn matrix_symbolic_dependency_mask_assuming_size<const N: usize, const M: usize>(
282 matrix: &[[Real; N]; N],
283) -> RealSymbolicDependencyMask {
284 debug_assert_eq!(N, M);
285 let mut mask = RealSymbolicDependencyMask::NONE;
286 for row in 0..M {
287 for column in 0..M {
288 mask = mask.union(matrix[row][column].detailed_facts().symbolic.dependencies);
289 }
290 }
291 mask
292}
293
294#[inline]
295fn matrix4_signed_permutation_rows(matrix: &[[Real; 4]; 4]) -> Option<[SignedAxis4; 4]> {
296 let rows = [
306 matrix4_signed_axis_row(&matrix[0])?,
307 matrix4_signed_axis_row(&matrix[1])?,
308 matrix4_signed_axis_row(&matrix[2])?,
309 matrix4_signed_axis_row(&matrix[3])?,
310 ];
311 let mut used_columns = 0_u8;
312 for axis in rows {
313 let bit = 1_u8 << axis.index();
314 if used_columns & bit != 0 {
315 return None;
316 }
317 used_columns |= bit;
318 }
319 (used_columns == 0b1111).then_some(rows)
320}
321
322#[inline]
323fn matrix4_signed_permutation_rows_assuming_size<const N: usize>(
324 matrix: &[[Real; N]; N],
325) -> Option<[SignedAxis4; 4]> {
326 debug_assert_eq!(N, 4);
327 let rows = [
328 matrix4_signed_axis_row_refs([&matrix[0][0], &matrix[0][1], &matrix[0][2], &matrix[0][3]])?,
329 matrix4_signed_axis_row_refs([&matrix[1][0], &matrix[1][1], &matrix[1][2], &matrix[1][3]])?,
330 matrix4_signed_axis_row_refs([&matrix[2][0], &matrix[2][1], &matrix[2][2], &matrix[2][3]])?,
331 matrix4_signed_axis_row_refs([&matrix[3][0], &matrix[3][1], &matrix[3][2], &matrix[3][3]])?,
332 ];
333 let mut used_columns = 0_u8;
334 for axis in rows {
335 let bit = 1_u8 << axis.index();
336 if used_columns & bit != 0 {
337 return None;
338 }
339 used_columns |= bit;
340 }
341 (used_columns == 0b1111).then_some(rows)
342}
343
344#[inline]
345fn matrix3_exact_rational_uniform_scale(matrix: &[[Real; 3]; 3], is_diagonal: bool) -> bool {
346 if !is_diagonal {
347 return false;
348 }
349 exact_rational_diagonal_entries_equal([&matrix[0][0], &matrix[1][1], &matrix[2][2]])
350}
351
352#[inline]
353fn matrix4_exact_rational_uniform_scale(matrix: &[[Real; 4]; 4], is_diagonal: bool) -> bool {
354 if !is_diagonal {
355 return false;
356 }
357 exact_rational_diagonal_entries_equal([
358 &matrix[0][0],
359 &matrix[1][1],
360 &matrix[2][2],
361 &matrix[3][3],
362 ])
363}
364
365#[inline]
366fn matrix3_exact_rational_uniform_scale_assuming_size<const N: usize>(
367 matrix: &[[Real; N]; N],
368 is_diagonal: bool,
369) -> bool {
370 debug_assert_eq!(N, 3);
371 if !is_diagonal {
372 return false;
373 }
374 exact_rational_diagonal_entries_equal([&matrix[0][0], &matrix[1][1], &matrix[2][2]])
375}
376
377#[inline]
378fn matrix4_exact_rational_uniform_scale_assuming_size<const N: usize>(
379 matrix: &[[Real; N]; N],
380 is_diagonal: bool,
381) -> bool {
382 debug_assert_eq!(N, 4);
383 if !is_diagonal {
384 return false;
385 }
386 exact_rational_diagonal_entries_equal([
387 &matrix[0][0],
388 &matrix[1][1],
389 &matrix[2][2],
390 &matrix[3][3],
391 ])
392}
393
394#[inline]
395fn exact_rational_diagonal_entries_equal<const N: usize>(entries: [&Real; N]) -> bool {
396 let Some(first) = entries[0].exact_rational_ref() else {
404 return false;
405 };
406 entries[1..]
407 .iter()
408 .all(|entry| entry.exact_rational_ref() == Some(first))
409}
410
411#[inline]
412fn matrix4_signed_axis_row(row: &[Real; 4]) -> Option<SignedAxis4> {
413 matrix4_signed_axis_row_refs([&row[0], &row[1], &row[2], &row[3]])
414}
415
416#[inline]
417fn matrix4_signed_axis_row_refs(row: [&Real; 4]) -> Option<SignedAxis4> {
418 let mut axis = None;
419 for (index, value) in row.into_iter().enumerate() {
420 let status = value.zero_one_or_minus_one();
421 match status {
422 RealZeroOneMinusOneStatus::Zero => {}
423 RealZeroOneMinusOneStatus::One | RealZeroOneMinusOneStatus::MinusOne
424 if axis.is_none() =>
425 {
426 axis = Some(signed_axis4_from_index(
427 index,
428 matches!(status, RealZeroOneMinusOneStatus::MinusOne),
429 )?);
430 }
431 _ => return None,
432 }
433 }
434 axis
435}
436
437#[inline]
438fn signed_axis4_from_index(index: usize, negative: bool) -> Option<SignedAxis4> {
439 match (index, negative) {
440 (0, false) => Some(SignedAxis4::PosX),
441 (0, true) => Some(SignedAxis4::NegX),
442 (1, false) => Some(SignedAxis4::PosY),
443 (1, true) => Some(SignedAxis4::NegY),
444 (2, false) => Some(SignedAxis4::PosZ),
445 (2, true) => Some(SignedAxis4::NegZ),
446 (3, false) => Some(SignedAxis4::PosW),
447 (3, true) => Some(SignedAxis4::NegW),
448 _ => None,
449 }
450}
451
452#[derive(Clone, Debug, PartialEq)]
454pub struct Matrix3(
455 pub [[Real; 3]; 3],
457);
458
459#[derive(Clone, Debug, PartialEq)]
461pub struct Matrix4(
462 pub [[Real; 4]; 4],
464);
465
466#[derive(Clone, Copy, Debug, Eq, PartialEq)]
481pub enum MatrixDeterminantScheduleHint {
482 StructurallyZero,
485 Diagonal,
487 Triangular,
489 SparseSupport,
491 SharedDenominator,
493 Dyadic,
495 ExactRational,
497 GenericRealFallback,
499}
500
501impl MatrixDeterminantScheduleHint {
502 pub fn is_shape_driven(self) -> bool {
510 matches!(
511 self,
512 Self::StructurallyZero | Self::Diagonal | Self::Triangular | Self::SparseSupport
513 )
514 }
515
516 pub fn is_exact_rational_driven(self) -> bool {
525 matches!(
526 self,
527 Self::SharedDenominator | Self::Dyadic | Self::ExactRational
528 )
529 }
530
531 pub fn requires_generic_real_fallback(self) -> bool {
533 matches!(self, Self::GenericRealFallback)
534 }
535}
536
537#[derive(Clone, Copy, Debug, Eq, PartialEq)]
546pub enum Matrix3TransformKind {
547 Identity,
549 AffineTranslation,
551 AffineDiagonalLinear,
553 Affine,
555 Projective,
557}
558
559#[derive(Clone, Copy, Debug, Eq, PartialEq)]
566pub enum Matrix4TransformKind {
567 Identity,
569 SignedPermutation,
571 AffineTranslation,
573 AffineDiagonalLinear,
575 Affine,
577 Projective,
579}
580
581#[derive(Clone, Copy, Debug, Eq, PartialEq)]
593pub struct Matrix3StructuralFacts {
594 pub exact: ExactRealSetFacts,
596 pub symbolic_dependencies: RealSymbolicDependencyMask,
606 pub zero_mask: u16,
608 pub one_mask: u16,
610 pub row_zero_masks: [u8; 3],
612 pub column_zero_masks: [u8; 3],
614 pub is_identity: bool,
616 pub is_diagonal: bool,
618 pub is_exact_rational_uniform_scale: bool,
623 pub is_upper_triangular: bool,
625 pub is_lower_triangular: bool,
627 pub is_affine: bool,
629 pub is_affine_translation: bool,
631 pub transform_kind: Matrix3TransformKind,
633}
634
635impl Matrix3StructuralFacts {
636 pub fn is_zero(self) -> bool {
638 self.zero_mask == matrix_mask::<3>()
639 }
640
641 pub fn entry_known_zero(self, row: usize, column: usize) -> Option<bool> {
649 matrix_entry_mask_value::<3>(self.zero_mask, row, column)
650 }
651
652 pub fn entry_known_one(self, row: usize, column: usize) -> Option<bool> {
654 matrix_entry_mask_value::<3>(self.one_mask, row, column)
655 }
656
657 pub fn row_zero_mask(self, row: usize) -> Option<u8> {
659 self.row_zero_masks.get(row).copied()
660 }
661
662 pub fn column_zero_mask(self, column: usize) -> Option<u8> {
664 self.column_zero_masks.get(column).copied()
665 }
666
667 pub fn row_known_zero_count(self, row: usize) -> Option<u32> {
669 self.row_zero_mask(row)
670 .map(matrix_lane_known_zero_count::<3>)
671 }
672
673 pub fn column_known_zero_count(self, column: usize) -> Option<u32> {
675 self.column_zero_mask(column)
676 .map(matrix_lane_known_zero_count::<3>)
677 }
678
679 pub fn row_is_known_zero(self, row: usize) -> Option<bool> {
686 self.row_zero_mask(row).map(matrix_lane_is_known_zero::<3>)
687 }
688
689 pub fn column_is_known_zero(self, column: usize) -> Option<bool> {
691 self.column_zero_mask(column)
692 .map(matrix_lane_is_known_zero::<3>)
693 }
694
695 pub fn has_known_zero_row(self) -> bool {
697 self.row_zero_masks
698 .into_iter()
699 .any(matrix_lane_is_known_zero::<3>)
700 }
701
702 pub fn has_known_zero_column(self) -> bool {
704 self.column_zero_masks
705 .into_iter()
706 .any(matrix_lane_is_known_zero::<3>)
707 }
708
709 pub fn has_known_zero_lane(self) -> bool {
711 self.has_known_zero_row() || self.has_known_zero_column()
712 }
713
714 pub fn row_has_sparse_support(self, row: usize) -> Option<bool> {
720 self.row_zero_mask(row)
721 .map(matrix_lane_has_sparse_support::<3>)
722 }
723
724 pub fn column_has_sparse_support(self, column: usize) -> Option<bool> {
726 self.column_zero_mask(column)
727 .map(matrix_lane_has_sparse_support::<3>)
728 }
729
730 pub fn all_rows_have_sparse_support(self) -> bool {
732 self.row_zero_masks
733 .into_iter()
734 .all(matrix_lane_has_sparse_support::<3>)
735 }
736
737 pub fn all_columns_have_sparse_support(self) -> bool {
739 self.column_zero_masks
740 .into_iter()
741 .all(matrix_lane_has_sparse_support::<3>)
742 }
743
744 pub fn determinant_schedule_hint(self) -> MatrixDeterminantScheduleHint {
750 matrix_determinant_schedule_hint::<3>(
751 self.exact,
752 self.row_zero_masks,
753 self.column_zero_masks,
754 self.is_diagonal,
755 self.is_upper_triangular,
756 self.is_lower_triangular,
757 )
758 }
759}
760
761#[derive(Clone, Copy, Debug, Eq, PartialEq)]
767pub struct Matrix4StructuralFacts {
768 pub exact: ExactRealSetFacts,
770 pub symbolic_dependencies: RealSymbolicDependencyMask,
777 pub zero_mask: u16,
779 pub one_mask: u16,
781 pub row_zero_masks: [u8; 4],
783 pub column_zero_masks: [u8; 4],
785 pub is_identity: bool,
787 pub is_diagonal: bool,
789 pub is_exact_rational_uniform_scale: bool,
796 pub is_upper_triangular: bool,
798 pub is_lower_triangular: bool,
800 pub is_affine: bool,
802 pub is_affine_translation: bool,
804 pub linear_is_diagonal: bool,
806 pub direction_linear_is_diagonal: bool,
808 pub signed_permutation_rows: Option<[SignedAxis4; 4]>,
815 pub translation_xyz_zero: [bool; 3],
817 pub transform_kind: Matrix4TransformKind,
819}
820
821impl Matrix4StructuralFacts {
822 pub fn is_zero(self) -> bool {
824 self.zero_mask == matrix_mask::<4>()
825 }
826
827 pub fn is_signed_permutation(self) -> bool {
829 self.signed_permutation_rows.is_some()
830 }
831
832 pub fn entry_known_zero(self, row: usize, column: usize) -> Option<bool> {
838 matrix_entry_mask_value::<4>(self.zero_mask, row, column)
839 }
840
841 pub fn entry_known_one(self, row: usize, column: usize) -> Option<bool> {
843 matrix_entry_mask_value::<4>(self.one_mask, row, column)
844 }
845
846 pub fn row_zero_mask(self, row: usize) -> Option<u8> {
848 self.row_zero_masks.get(row).copied()
849 }
850
851 pub fn column_zero_mask(self, column: usize) -> Option<u8> {
853 self.column_zero_masks.get(column).copied()
854 }
855
856 pub fn row_known_zero_count(self, row: usize) -> Option<u32> {
858 self.row_zero_mask(row)
859 .map(matrix_lane_known_zero_count::<4>)
860 }
861
862 pub fn column_known_zero_count(self, column: usize) -> Option<u32> {
864 self.column_zero_mask(column)
865 .map(matrix_lane_known_zero_count::<4>)
866 }
867
868 pub fn row_is_known_zero(self, row: usize) -> Option<bool> {
874 self.row_zero_mask(row).map(matrix_lane_is_known_zero::<4>)
875 }
876
877 pub fn column_is_known_zero(self, column: usize) -> Option<bool> {
879 self.column_zero_mask(column)
880 .map(matrix_lane_is_known_zero::<4>)
881 }
882
883 pub fn has_known_zero_row(self) -> bool {
885 self.row_zero_masks
886 .into_iter()
887 .any(matrix_lane_is_known_zero::<4>)
888 }
889
890 pub fn has_known_zero_column(self) -> bool {
892 self.column_zero_masks
893 .into_iter()
894 .any(matrix_lane_is_known_zero::<4>)
895 }
896
897 pub fn has_known_zero_lane(self) -> bool {
899 self.has_known_zero_row() || self.has_known_zero_column()
900 }
901
902 pub fn row_has_sparse_support(self, row: usize) -> Option<bool> {
909 self.row_zero_mask(row)
910 .map(matrix_lane_has_sparse_support::<4>)
911 }
912
913 pub fn column_has_sparse_support(self, column: usize) -> Option<bool> {
915 self.column_zero_mask(column)
916 .map(matrix_lane_has_sparse_support::<4>)
917 }
918
919 pub fn all_rows_have_sparse_support(self) -> bool {
921 self.row_zero_masks
922 .into_iter()
923 .all(matrix_lane_has_sparse_support::<4>)
924 }
925
926 pub fn all_columns_have_sparse_support(self) -> bool {
928 self.column_zero_masks
929 .into_iter()
930 .all(matrix_lane_has_sparse_support::<4>)
931 }
932
933 pub fn determinant_schedule_hint(self) -> MatrixDeterminantScheduleHint {
940 matrix_determinant_schedule_hint::<4>(
941 self.exact,
942 self.row_zero_masks,
943 self.column_zero_masks,
944 self.is_diagonal,
945 self.is_upper_triangular,
946 self.is_lower_triangular,
947 )
948 }
949}
950
951#[derive(Debug, Clone)]
962pub struct PreparedMatrix3<'a> {
963 right_divisor: PreparedRightDivisor3<'a>,
964}
965
966#[derive(Debug, Clone)]
973pub struct PreparedMatrix4<'a> {
974 right_divisor: PreparedRightDivisor4<'a>,
975}
976
977#[derive(Debug, Clone)]
987pub struct PreparedRightDivisor3<'a> {
988 divisor: &'a Matrix3,
989 facts: Matrix3Facts,
990 right_exact_rational_kind: ExactRationalKind,
991 is_definitely_dense_for_inverse: bool,
992 adjugate: Option<[[Real; 3]; 3]>,
993 determinant: Option<Real>,
994 reciprocal_determinant: Option<Real>,
995 inverse: Option<Matrix3>,
996}
997
998#[derive(Debug, Clone)]
1006pub struct PreparedRightDivisor4<'a> {
1007 divisor: &'a Matrix4,
1008 facts: Matrix4Facts,
1009 right_exact_rational_kind: ExactRationalKind,
1010 is_definitely_dense_for_inverse: bool,
1011 factors: Option<([Real; 6], [Real; 6])>,
1012 adjugate: Option<[[Real; 4]; 4]>,
1013 determinant: Option<Real>,
1014 reciprocal_determinant: Option<Real>,
1015 inverse: Option<Matrix4>,
1016}
1017
1018#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
1029pub struct MatrixPreparedCacheState {
1030 pub determinant: bool,
1032 pub reciprocal_determinant: bool,
1034 pub minor_factors: bool,
1039 pub adjugate: bool,
1041 pub inverse: bool,
1043}
1044
1045impl MatrixPreparedCacheState {
1046 pub const fn is_cold(self) -> bool {
1048 !self.determinant
1049 && !self.reciprocal_determinant
1050 && !self.minor_factors
1051 && !self.adjugate
1052 && !self.inverse
1053 }
1054
1055 pub const fn is_warm(self) -> bool {
1057 !self.is_cold()
1058 }
1059
1060 pub const fn has_determinant_scale(self) -> bool {
1062 self.determinant && self.reciprocal_determinant
1063 }
1064
1065 pub const fn has_shared_adjugate_path(self) -> bool {
1067 self.adjugate && self.has_determinant_scale()
1068 }
1069}
1070
1071#[derive(Clone, Copy, Debug)]
1072struct Matrix3Facts {
1073 public: Matrix3StructuralFacts,
1074 exact: ExactRealSetFacts,
1075 is_identity: bool,
1076 is_diagonal: bool,
1077 is_upper_triangular: bool,
1081 is_lower_triangular: bool,
1082 linear_is_diagonal: bool,
1088 is_affine: bool,
1089 is_affine_translation: bool,
1090}
1091
1092#[inline]
1093fn combine_exact_rational_kind(
1094 left: ExactRationalKind,
1095 right: ExactRationalKind,
1096) -> ExactRationalKind {
1097 use ExactRationalKind::{ExactDyadicRational, ExactRational, NonRational};
1098 match (left, right) {
1099 (NonRational, _) | (_, NonRational) => NonRational,
1100 (ExactRational, _) | (_, ExactRational) => ExactRational,
1101 (ExactDyadicRational, ExactDyadicRational) => ExactDyadicRational,
1102 }
1103}
1104
1105#[inline]
1106fn matrix3_exact_rational_kind(matrix: &[[Real; 3]; 3]) -> ExactRationalKind {
1107 let mut kind = ExactRationalKind::ExactDyadicRational;
1108 for row in matrix {
1109 for value in row {
1110 kind = combine_exact_rational_kind(kind, value.exact_rational_kind());
1111 if kind == ExactRationalKind::NonRational {
1112 return kind;
1113 }
1114 }
1115 }
1116 kind
1117}
1118
1119fn matrix4_exact_rational_kind(matrix: &[[Real; 4]; 4]) -> ExactRationalKind {
1120 let mut kind = ExactRationalKind::ExactDyadicRational;
1121 for row in matrix {
1122 for value in row {
1123 kind = combine_exact_rational_kind(kind, value.exact_rational_kind());
1124 if kind == ExactRationalKind::NonRational {
1125 return kind;
1126 }
1127 }
1128 }
1129 kind
1130}
1131
1132#[inline]
1133fn matrix_exact_rational_kind<const N: usize>(matrix: &[[Real; N]; N]) -> ExactRationalKind {
1134 let mut kind = ExactRationalKind::ExactDyadicRational;
1135 for row in matrix {
1136 for value in row {
1137 kind = combine_exact_rational_kind(kind, value.exact_rational_kind());
1138 if kind == ExactRationalKind::NonRational {
1139 return kind;
1140 }
1141 }
1142 }
1143 kind
1144}
1145
1146impl<'a> PreparedMatrix3<'a> {
1147 pub fn new(matrix: &'a Matrix3) -> Self {
1149 crate::trace_dispatch!("hyperlattice_matrix", "method", "prepared-matrix3-new");
1150 Self {
1151 right_divisor: PreparedRightDivisor3::new(matrix),
1152 }
1153 }
1154
1155 pub fn matrix(&self) -> &Matrix3 {
1157 self.right_divisor.divisor()
1158 }
1159
1160 pub fn structural_facts(&self) -> Matrix3StructuralFacts {
1167 crate::trace_dispatch!(
1168 "hyperlattice_matrix",
1169 "query",
1170 "prepared-matrix3-structural-facts"
1171 );
1172 self.right_divisor.facts.public
1173 }
1174
1175 pub fn exact_facts(&self) -> ExactRealSetFacts {
1177 crate::trace_dispatch!(
1178 "hyperlattice_matrix",
1179 "query",
1180 "prepared-matrix3-exact-facts"
1181 );
1182 self.right_divisor.facts.exact
1183 }
1184
1185 pub fn determinant_schedule_hint(&self) -> MatrixDeterminantScheduleHint {
1187 crate::trace_dispatch!(
1188 "hyperlattice_matrix",
1189 "query",
1190 "prepared-matrix3-determinant-schedule"
1191 );
1192 self.right_divisor.determinant_schedule_hint()
1193 }
1194
1195 pub fn cache_state(&self) -> MatrixPreparedCacheState {
1198 crate::trace_dispatch!(
1199 "hyperlattice_matrix",
1200 "query",
1201 "prepared-matrix3-cache-state"
1202 );
1203 self.right_divisor.cache_state()
1204 }
1205
1206 pub fn determinant(&mut self) -> Real {
1215 crate::trace_dispatch!(
1216 "hyperlattice_matrix",
1217 "method",
1218 "prepared-matrix3-determinant"
1219 );
1220 self.right_divisor.determinant()
1221 }
1222
1223 pub fn right_divisor(&mut self) -> &mut PreparedRightDivisor3<'a> {
1229 &mut self.right_divisor
1230 }
1231
1232 pub fn transform_vec3_handle(&self) -> TransformedMatrix3<'a> {
1244 crate::trace_dispatch!(
1245 "hyperlattice_matrix",
1246 "method",
1247 "prepared-matrix3-transform-handle"
1248 );
1249 TransformedMatrix3::new_with_facts(self.right_divisor.divisor, self.right_divisor.facts)
1250 }
1251
1252 pub fn transform_vector(&self, rhs: &Vector3) -> Vector3 {
1254 crate::trace_dispatch!(
1255 "hyperlattice_matrix",
1256 "method",
1257 "prepared-matrix3-transform-vector"
1258 );
1259 self.transform_vec3_handle().transform_vector(rhs)
1260 }
1261
1262 pub fn transform_vector_batch(&self, rhs: &[Vector3]) -> Vec<Vector3> {
1264 crate::trace_dispatch!(
1265 "hyperlattice_matrix",
1266 "method",
1267 "prepared-matrix3-transform-vector-batch"
1268 );
1269 self.transform_vec3_handle().transform_vector_batch(rhs)
1270 }
1271
1272 pub fn inverse(&mut self) -> BlasResult<Matrix3> {
1274 crate::trace_dispatch!("hyperlattice_matrix", "method", "prepared-matrix3-inverse");
1275 self.right_divisor.inverse()
1276 }
1277
1278 pub fn inverse_checked(&mut self) -> CheckedBlasResult<Matrix3> {
1280 crate::trace_dispatch!(
1281 "hyperlattice_matrix",
1282 "method",
1283 "prepared-matrix3-inverse-checked"
1284 );
1285 self.right_divisor.inverse_checked()
1286 }
1287
1288 pub fn inverse_checked_with_abort(
1290 &mut self,
1291 signal: &AbortSignal,
1292 ) -> CheckedBlasResult<Matrix3> {
1293 crate::trace_dispatch!(
1294 "hyperlattice_matrix",
1295 "method",
1296 "prepared-matrix3-inverse-checked-abort"
1297 );
1298 self.right_divisor.inverse_checked_with_abort(signal)
1299 }
1300
1301 pub fn reciprocal(&mut self) -> BlasResult<Matrix3> {
1303 crate::trace_dispatch!(
1304 "hyperlattice_matrix",
1305 "method",
1306 "prepared-matrix3-reciprocal"
1307 );
1308 self.right_divisor.reciprocal()
1309 }
1310
1311 pub fn reciprocal_checked(&mut self) -> CheckedBlasResult<Matrix3> {
1313 crate::trace_dispatch!(
1314 "hyperlattice_matrix",
1315 "method",
1316 "prepared-matrix3-reciprocal-checked"
1317 );
1318 self.right_divisor.reciprocal_checked()
1319 }
1320
1321 pub fn reciprocal_checked_with_abort(
1323 &mut self,
1324 signal: &AbortSignal,
1325 ) -> CheckedBlasResult<Matrix3> {
1326 crate::trace_dispatch!(
1327 "hyperlattice_matrix",
1328 "method",
1329 "prepared-matrix3-reciprocal-checked-abort"
1330 );
1331 self.right_divisor.reciprocal_checked_with_abort(signal)
1332 }
1333
1334 pub fn divide_left(&mut self, left: Matrix3) -> BlasResult<Matrix3> {
1336 crate::trace_dispatch!(
1337 "hyperlattice_matrix",
1338 "method",
1339 "prepared-matrix3-divide-left"
1340 );
1341 Ok(Matrix3(self.right_divisor.divide(left.0)?))
1342 }
1343
1344 pub fn divide_left_checked(&mut self, left: Matrix3) -> CheckedBlasResult<Matrix3> {
1346 crate::trace_dispatch!(
1347 "hyperlattice_matrix",
1348 "method",
1349 "prepared-matrix3-divide-left-checked"
1350 );
1351 Ok(Matrix3(self.right_divisor.divide_checked(left.0)?))
1352 }
1353
1354 pub fn divide_left_checked_with_abort(
1356 &mut self,
1357 left: Matrix3,
1358 signal: &AbortSignal,
1359 ) -> CheckedBlasResult<Matrix3> {
1360 crate::trace_dispatch!(
1361 "hyperlattice_matrix",
1362 "method",
1363 "prepared-matrix3-divide-left-checked-abort"
1364 );
1365 Ok(Matrix3(
1366 self.right_divisor
1367 .divide_checked_with_abort(left.0, signal)?,
1368 ))
1369 }
1370}
1371
1372impl<'a> PreparedMatrix4<'a> {
1373 pub fn new(matrix: &'a Matrix4) -> Self {
1375 crate::trace_dispatch!("hyperlattice_matrix", "method", "prepared-matrix4-new");
1376 Self {
1377 right_divisor: PreparedRightDivisor4::new(matrix),
1378 }
1379 }
1380
1381 pub fn matrix(&self) -> &Matrix4 {
1383 self.right_divisor.divisor()
1384 }
1385
1386 pub fn structural_facts(&self) -> Matrix4StructuralFacts {
1393 crate::trace_dispatch!(
1394 "hyperlattice_matrix",
1395 "query",
1396 "prepared-matrix4-structural-facts"
1397 );
1398 self.right_divisor.facts.public
1399 }
1400
1401 pub fn exact_facts(&self) -> ExactRealSetFacts {
1403 crate::trace_dispatch!(
1404 "hyperlattice_matrix",
1405 "query",
1406 "prepared-matrix4-exact-facts"
1407 );
1408 self.right_divisor.facts.exact
1409 }
1410
1411 pub fn determinant_schedule_hint(&self) -> MatrixDeterminantScheduleHint {
1413 crate::trace_dispatch!(
1414 "hyperlattice_matrix",
1415 "query",
1416 "prepared-matrix4-determinant-schedule"
1417 );
1418 self.right_divisor.determinant_schedule_hint()
1419 }
1420
1421 pub fn cache_state(&self) -> MatrixPreparedCacheState {
1424 crate::trace_dispatch!(
1425 "hyperlattice_matrix",
1426 "query",
1427 "prepared-matrix4-cache-state"
1428 );
1429 self.right_divisor.cache_state()
1430 }
1431
1432 pub fn determinant(&mut self) -> Real {
1439 crate::trace_dispatch!(
1440 "hyperlattice_matrix",
1441 "method",
1442 "prepared-matrix4-determinant"
1443 );
1444 self.right_divisor.determinant()
1445 }
1446
1447 pub fn right_divisor(&mut self) -> &mut PreparedRightDivisor4<'a> {
1449 &mut self.right_divisor
1450 }
1451
1452 pub fn transform_vec4_handle(&self) -> TransformedMatrix4<'a> {
1463 crate::trace_dispatch!(
1464 "hyperlattice_matrix",
1465 "method",
1466 "prepared-matrix4-transform-handle"
1467 );
1468 TransformedMatrix4::new_with_facts(self.right_divisor.divisor, self.right_divisor.facts)
1469 }
1470
1471 pub fn transform_vector(&self, rhs: &Vector4) -> Vector4 {
1473 crate::trace_dispatch!(
1474 "hyperlattice_matrix",
1475 "method",
1476 "prepared-matrix4-transform-vector"
1477 );
1478 self.transform_vec4_handle().transform_vector(rhs)
1479 }
1480
1481 pub fn transform_vector_batch(&self, rhs: &[Vector4]) -> Vec<Vector4> {
1484 crate::trace_dispatch!(
1485 "hyperlattice_matrix",
1486 "method",
1487 "prepared-matrix4-transform-vector-batch"
1488 );
1489 self.transform_vec4_handle().transform_vector_batch(rhs)
1490 }
1491
1492 pub fn transform_direction_vector(&self, rhs: &Vector4) -> Vector4 {
1495 crate::trace_dispatch!(
1496 "hyperlattice_matrix",
1497 "method",
1498 "prepared-matrix4-transform-direction-vector"
1499 );
1500 self.transform_vec4_handle().transform_direction_vector(rhs)
1501 }
1502
1503 pub fn transform_direction_batch(&self, rhs: &[Vector4]) -> Vec<Vector4> {
1506 crate::trace_dispatch!(
1507 "hyperlattice_matrix",
1508 "method",
1509 "prepared-matrix4-transform-direction-batch"
1510 );
1511 self.transform_vec4_handle().transform_direction_batch(rhs)
1512 }
1513
1514 pub fn transform_point_vector(&self, rhs: &Vector4) -> Vector4 {
1517 crate::trace_dispatch!(
1518 "hyperlattice_matrix",
1519 "method",
1520 "prepared-matrix4-transform-point-vector"
1521 );
1522 self.transform_vec4_handle().transform_point_vector(rhs)
1523 }
1524
1525 pub fn transform_point_batch(&self, rhs: &[Vector4]) -> Vec<Vector4> {
1528 crate::trace_dispatch!(
1529 "hyperlattice_matrix",
1530 "method",
1531 "prepared-matrix4-transform-point-batch"
1532 );
1533 self.transform_vec4_handle().transform_point_batch(rhs)
1534 }
1535
1536 pub fn inverse(&mut self) -> BlasResult<Matrix4> {
1538 crate::trace_dispatch!("hyperlattice_matrix", "method", "prepared-matrix4-inverse");
1539 self.right_divisor.inverse()
1540 }
1541
1542 pub fn inverse_checked(&mut self) -> CheckedBlasResult<Matrix4> {
1544 crate::trace_dispatch!(
1545 "hyperlattice_matrix",
1546 "method",
1547 "prepared-matrix4-inverse-checked"
1548 );
1549 self.right_divisor.inverse_checked()
1550 }
1551
1552 pub fn inverse_checked_with_abort(
1554 &mut self,
1555 signal: &AbortSignal,
1556 ) -> CheckedBlasResult<Matrix4> {
1557 crate::trace_dispatch!(
1558 "hyperlattice_matrix",
1559 "method",
1560 "prepared-matrix4-inverse-checked-abort"
1561 );
1562 self.right_divisor.inverse_checked_with_abort(signal)
1563 }
1564
1565 pub fn reciprocal(&mut self) -> BlasResult<Matrix4> {
1567 crate::trace_dispatch!(
1568 "hyperlattice_matrix",
1569 "method",
1570 "prepared-matrix4-reciprocal"
1571 );
1572 self.right_divisor.reciprocal()
1573 }
1574
1575 pub fn reciprocal_checked(&mut self) -> CheckedBlasResult<Matrix4> {
1577 crate::trace_dispatch!(
1578 "hyperlattice_matrix",
1579 "method",
1580 "prepared-matrix4-reciprocal-checked"
1581 );
1582 self.right_divisor.reciprocal_checked()
1583 }
1584
1585 pub fn reciprocal_checked_with_abort(
1587 &mut self,
1588 signal: &AbortSignal,
1589 ) -> CheckedBlasResult<Matrix4> {
1590 crate::trace_dispatch!(
1591 "hyperlattice_matrix",
1592 "method",
1593 "prepared-matrix4-reciprocal-checked-abort"
1594 );
1595 self.right_divisor.reciprocal_checked_with_abort(signal)
1596 }
1597
1598 pub fn divide_left(&mut self, left: Matrix4) -> BlasResult<Matrix4> {
1600 crate::trace_dispatch!(
1601 "hyperlattice_matrix",
1602 "method",
1603 "prepared-matrix4-divide-left"
1604 );
1605 Ok(Matrix4(self.right_divisor.divide(left.0)?))
1606 }
1607
1608 pub fn divide_exact_rational_left(&mut self, left: Matrix4) -> BlasResult<Matrix4> {
1614 crate::trace_dispatch!(
1615 "hyperlattice_matrix",
1616 "method",
1617 "prepared-matrix4-divide-exact-rational-left"
1618 );
1619 Ok(Matrix4(
1620 self.right_divisor.divide_exact_rational_left(left.0)?,
1621 ))
1622 }
1623
1624 pub fn divide_left_checked(&mut self, left: Matrix4) -> CheckedBlasResult<Matrix4> {
1626 crate::trace_dispatch!(
1627 "hyperlattice_matrix",
1628 "method",
1629 "prepared-matrix4-divide-left-checked"
1630 );
1631 Ok(Matrix4(self.right_divisor.divide_checked(left.0)?))
1632 }
1633
1634 pub fn divide_left_checked_with_abort(
1636 &mut self,
1637 left: Matrix4,
1638 signal: &AbortSignal,
1639 ) -> CheckedBlasResult<Matrix4> {
1640 crate::trace_dispatch!(
1641 "hyperlattice_matrix",
1642 "method",
1643 "prepared-matrix4-divide-left-checked-abort"
1644 );
1645 Ok(Matrix4(
1646 self.right_divisor
1647 .divide_checked_with_abort(left.0, signal)?,
1648 ))
1649 }
1650}
1651
1652impl<'a> PreparedRightDivisor3<'a> {
1653 pub fn new(divisor: &'a Matrix3) -> Self {
1655 crate::trace_dispatch!(
1656 "hyperlattice_matrix",
1657 "method",
1658 "prepared-right-divisor3-new"
1659 );
1660 let facts = matrix3_facts(&divisor.0);
1661 let right_exact_rational_kind = matrix3_exact_rational_kind(&divisor.0);
1662 Self {
1663 divisor,
1664 facts,
1665 right_exact_rational_kind,
1666 is_definitely_dense_for_inverse: true
1667 && matrix3_is_definitely_dense_for_inverse(&divisor.0),
1668 adjugate: None,
1669 determinant: None,
1670 reciprocal_determinant: None,
1671 inverse: None,
1672 }
1673 }
1674
1675 pub fn divisor(&self) -> &Matrix3 {
1680 self.divisor
1681 }
1682
1683 pub fn structural_facts(&self) -> Matrix3StructuralFacts {
1685 self.facts.public
1686 }
1687
1688 pub fn determinant_schedule_hint(&self) -> MatrixDeterminantScheduleHint {
1695 self.facts.public.determinant_schedule_hint()
1696 }
1697
1698 pub fn cache_state(&self) -> MatrixPreparedCacheState {
1704 MatrixPreparedCacheState {
1705 determinant: self.determinant.is_some(),
1706 reciprocal_determinant: self.reciprocal_determinant.is_some(),
1707 minor_factors: false,
1708 adjugate: self.adjugate.is_some(),
1709 inverse: self.inverse.is_some(),
1710 }
1711 }
1712
1713 pub fn determinant(&mut self) -> Real {
1721 crate::trace_dispatch!(
1722 "hyperlattice_matrix",
1723 "method",
1724 "prepared-right-divisor3-determinant"
1725 );
1726 if let Some(determinant) = &self.determinant {
1727 crate::trace_dispatch!(
1728 "hyperlattice_matrix",
1729 "method",
1730 "prepared-right-divisor3-determinant-cache-hit"
1731 );
1732 return determinant.clone();
1733 }
1734 let determinant = determinant3(&self.divisor.0);
1735 self.determinant = Some(determinant.clone());
1736 determinant
1737 }
1738
1739 #[inline]
1740 fn can_use_shared_adjugate(&self, left: &[[Real; 3]; 3]) -> bool {
1741 match self.right_exact_rational_kind {
1742 ExactRationalKind::ExactDyadicRational => {
1743 matrix3_exact_rational_kind(left) == ExactRationalKind::ExactDyadicRational
1744 }
1745 ExactRationalKind::ExactRational => {
1746 matches!(
1747 matrix3_exact_rational_kind(left),
1748 ExactRationalKind::ExactDyadicRational | ExactRationalKind::ExactRational
1749 )
1750 }
1751 ExactRationalKind::NonRational => false,
1752 }
1753 }
1754
1755 fn prepare_shared_adjugate(&mut self) -> BlasResult<&[[Real; 3]; 3]> {
1756 if self.adjugate.is_none() {
1757 crate::trace_dispatch!(
1758 "hyperlattice_matrix",
1759 "method",
1760 "prepared-right-divisor3-cache-shared-adjugate"
1761 );
1762 let known_rational = self.right_exact_rational_kind == ExactRationalKind::ExactRational;
1763 let (adjugate, determinant) = if self.is_definitely_dense_for_inverse && known_rational
1764 {
1765 matrix3_adjugate_and_determinant_dense_exact_known_rational(&self.divisor.0)
1766 } else if self.is_definitely_dense_for_inverse {
1767 matrix3_adjugate_and_determinant_dense_exact(&self.divisor.0)
1768 } else {
1769 matrix3_adjugate_and_determinant(&self.divisor.0)
1770 };
1771 let reciprocal_determinant = determinant.inverse_ref()?;
1772 self.adjugate = Some(adjugate);
1773 self.determinant = Some(determinant);
1774 self.reciprocal_determinant = Some(reciprocal_determinant);
1775 }
1776 Ok(self
1777 .adjugate
1778 .as_ref()
1779 .expect("adjugate cache must be present"))
1780 }
1781
1782 fn prepare_shared_adjugate_checked(&mut self) -> CheckedBlasResult<&[[Real; 3]; 3]> {
1783 if self.adjugate.is_none() {
1784 crate::trace_dispatch!(
1785 "hyperlattice_matrix",
1786 "method",
1787 "prepared-right-divisor3-cache-shared-adjugate-checked"
1788 );
1789 let known_rational = self.right_exact_rational_kind == ExactRationalKind::ExactRational;
1790 let (adjugate, determinant) = if self.is_definitely_dense_for_inverse && known_rational
1791 {
1792 matrix3_adjugate_and_determinant_dense_exact_known_rational(&self.divisor.0)
1793 } else if self.is_definitely_dense_for_inverse {
1794 matrix3_adjugate_and_determinant_dense_exact(&self.divisor.0)
1795 } else {
1796 matrix3_adjugate_and_determinant(&self.divisor.0)
1797 };
1798 require_known_nonzero(&determinant)?;
1799 let reciprocal_determinant = determinant.inverse_ref()?;
1800 self.adjugate = Some(adjugate);
1801 self.determinant = Some(determinant);
1802 self.reciprocal_determinant = Some(reciprocal_determinant);
1803 }
1804 Ok(self
1805 .adjugate
1806 .as_ref()
1807 .expect("adjugate cache must be present"))
1808 }
1809
1810 fn prepare_shared_adjugate_checked_with_abort(
1811 &mut self,
1812 signal: &AbortSignal,
1813 ) -> CheckedBlasResult<&[[Real; 3]; 3]> {
1814 if self.adjugate.is_none() {
1815 crate::trace_dispatch!(
1816 "hyperlattice_matrix",
1817 "method",
1818 "prepared-right-divisor3-cache-shared-adjugate-checked-abort"
1819 );
1820 let known_rational = self.right_exact_rational_kind == ExactRationalKind::ExactRational;
1821 let (adjugate, determinant) = if self.is_definitely_dense_for_inverse && known_rational
1822 {
1823 matrix3_adjugate_and_determinant_dense_exact_known_rational(&self.divisor.0)
1824 } else if self.is_definitely_dense_for_inverse {
1825 matrix3_adjugate_and_determinant_dense_exact(&self.divisor.0)
1826 } else {
1827 matrix3_adjugate_and_determinant(&self.divisor.0)
1828 };
1829 let determinant = with_abort(determinant, signal);
1830 require_known_nonzero(&determinant)?;
1831 let reciprocal_determinant = determinant.inverse_ref()?;
1832 self.adjugate = Some(adjugate);
1833 self.determinant = Some(determinant);
1838 self.reciprocal_determinant = Some(reciprocal_determinant);
1839 }
1840 Ok(self
1841 .adjugate
1842 .as_ref()
1843 .expect("adjugate cache must be present"))
1844 }
1845
1846 pub fn divide(&mut self, left: [[Real; 3]; 3]) -> BlasResult<[[Real; 3]; 3]> {
1854 crate::trace_dispatch!(
1855 "hyperlattice_matrix",
1856 "method",
1857 "prepared-right-divisor3-divide"
1858 );
1859 right_divide_matrix3_prepared(left, self)
1860 }
1861
1862 pub fn divide_checked(&mut self, left: [[Real; 3]; 3]) -> CheckedBlasResult<[[Real; 3]; 3]> {
1868 crate::trace_dispatch!(
1869 "hyperlattice_matrix",
1870 "method",
1871 "prepared-right-divisor3-divide-checked"
1872 );
1873 right_divide_matrix3_prepared_checked(left, self)
1874 }
1875
1876 pub fn divide_checked_with_abort(
1882 &mut self,
1883 left: [[Real; 3]; 3],
1884 signal: &AbortSignal,
1885 ) -> CheckedBlasResult<[[Real; 3]; 3]> {
1886 crate::trace_dispatch!(
1887 "hyperlattice_matrix",
1888 "method",
1889 "prepared-right-divisor3-divide-checked-abort"
1890 );
1891 right_divide_matrix3_prepared_checked_with_abort(left, self, signal)
1892 }
1893
1894 pub fn inverse(&mut self) -> BlasResult<Matrix3> {
1897 crate::trace_dispatch!(
1898 "hyperlattice_matrix",
1899 "method",
1900 "prepared-right-divisor3-inverse"
1901 );
1902 if let Some(inverse) = &self.inverse {
1903 crate::trace_dispatch!(
1904 "hyperlattice_matrix",
1905 "method",
1906 "prepared-right-divisor3-inverse-cache-hit"
1907 );
1908 return Ok(inverse.clone());
1909 }
1910 let _ = self.prepare_shared_adjugate()?;
1911 let inv_det = self
1912 .reciprocal_determinant
1913 .as_ref()
1914 .expect("reciprocal determinant cache should be present");
1915 let adjugate = self
1916 .adjugate
1917 .as_ref()
1918 .expect("adjugate cache should be present")
1919 .clone();
1920 let inverse = Matrix3(scale_matrix3(adjugate, inv_det));
1921 self.inverse = Some(inverse.clone());
1922 Ok(inverse)
1923 }
1924
1925 pub fn inverse_checked(&mut self) -> CheckedBlasResult<Matrix3> {
1927 crate::trace_dispatch!(
1928 "hyperlattice_matrix",
1929 "method",
1930 "prepared-right-divisor3-inverse-checked"
1931 );
1932 let _ = self.prepare_shared_adjugate_checked()?;
1933 if let Some(inverse) = &self.inverse {
1934 crate::trace_dispatch!(
1935 "hyperlattice_matrix",
1936 "method",
1937 "prepared-right-divisor3-inverse-checked-cache-hit"
1938 );
1939 return Ok(inverse.clone());
1940 }
1941 let inv_det = self
1942 .reciprocal_determinant
1943 .as_ref()
1944 .expect("reciprocal determinant cache should be present");
1945 let adjugate = self
1946 .adjugate
1947 .as_ref()
1948 .expect("adjugate cache should be present")
1949 .clone();
1950 let inverse = Matrix3(scale_matrix3(adjugate, inv_det));
1951 self.inverse = Some(inverse.clone());
1952 Ok(inverse)
1953 }
1954
1955 pub fn inverse_checked_with_abort(
1957 &mut self,
1958 signal: &AbortSignal,
1959 ) -> CheckedBlasResult<Matrix3> {
1960 crate::trace_dispatch!(
1961 "hyperlattice_matrix",
1962 "method",
1963 "prepared-right-divisor3-inverse-checked-abort"
1964 );
1965 let _ = self.prepare_shared_adjugate_checked_with_abort(signal)?;
1966 if let Some(inverse) = &self.inverse {
1967 crate::trace_dispatch!(
1968 "hyperlattice_matrix",
1969 "method",
1970 "prepared-right-divisor3-inverse-checked-abort-cache-hit"
1971 );
1972 return Ok(inverse.clone());
1973 }
1974 let inv_det = self
1975 .reciprocal_determinant
1976 .as_ref()
1977 .expect("reciprocal determinant cache should be present");
1978 let adjugate = self
1979 .adjugate
1980 .as_ref()
1981 .expect("adjugate cache should be present")
1982 .clone();
1983 let inverse = Matrix3(scale_matrix3(adjugate, inv_det));
1984 self.inverse = Some(inverse.clone());
1985 Ok(inverse)
1986 }
1987
1988 pub fn reciprocal(&mut self) -> BlasResult<Matrix3> {
1990 crate::trace_dispatch!(
1991 "hyperlattice_matrix",
1992 "method",
1993 "prepared-right-divisor3-reciprocal"
1994 );
1995 self.inverse()
1996 }
1997
1998 pub fn reciprocal_checked(&mut self) -> CheckedBlasResult<Matrix3> {
2000 crate::trace_dispatch!(
2001 "hyperlattice_matrix",
2002 "method",
2003 "prepared-right-divisor3-reciprocal-checked"
2004 );
2005 self.inverse_checked()
2006 }
2007
2008 pub fn reciprocal_checked_with_abort(
2010 &mut self,
2011 signal: &AbortSignal,
2012 ) -> CheckedBlasResult<Matrix3> {
2013 crate::trace_dispatch!(
2014 "hyperlattice_matrix",
2015 "method",
2016 "prepared-right-divisor3-reciprocal-checked-abort"
2017 );
2018 self.inverse_checked_with_abort(signal)
2019 }
2020}
2021
2022impl<'a> PreparedRightDivisor4<'a> {
2023 pub fn new(divisor: &'a Matrix4) -> Self {
2025 crate::trace_dispatch!(
2026 "hyperlattice_matrix",
2027 "method",
2028 "prepared-right-divisor4-new"
2029 );
2030 let facts = matrix4_facts(&divisor.0);
2031 let right_exact_rational_kind = matrix4_exact_rational_kind(&divisor.0);
2032 Self {
2033 divisor,
2034 facts,
2035 right_exact_rational_kind,
2036 is_definitely_dense_for_inverse: true && facts.is_definitely_dense_for_inverse,
2037 factors: None,
2038 adjugate: None,
2039 determinant: None,
2040 reciprocal_determinant: None,
2041 inverse: None,
2042 }
2043 }
2044
2045 pub fn divisor(&self) -> &Matrix4 {
2050 self.divisor
2051 }
2052
2053 pub fn structural_facts(&self) -> Matrix4StructuralFacts {
2055 self.facts.public
2056 }
2057
2058 pub fn determinant_schedule_hint(&self) -> MatrixDeterminantScheduleHint {
2063 self.facts.public.determinant_schedule_hint()
2064 }
2065
2066 pub fn cache_state(&self) -> MatrixPreparedCacheState {
2073 MatrixPreparedCacheState {
2074 determinant: self.determinant.is_some(),
2075 reciprocal_determinant: self.reciprocal_determinant.is_some(),
2076 minor_factors: self.factors.is_some(),
2077 adjugate: self.adjugate.is_some(),
2078 inverse: self.inverse.is_some(),
2079 }
2080 }
2081
2082 pub fn determinant(&mut self) -> Real {
2091 crate::trace_dispatch!(
2092 "hyperlattice_matrix",
2093 "method",
2094 "prepared-right-divisor4-determinant"
2095 );
2096 if let Some(determinant) = &self.determinant {
2097 crate::trace_dispatch!(
2098 "hyperlattice_matrix",
2099 "method",
2100 "prepared-right-divisor4-determinant-cache-hit"
2101 );
2102 return determinant.clone();
2103 }
2104 let dense_exact = self.is_definitely_dense_for_inverse;
2105 let known_rational = self.right_exact_rational_kind != ExactRationalKind::NonRational;
2106 let factors = self.factors.get_or_insert_with(|| {
2107 if dense_exact && known_rational {
2108 matrix4_factors_dense_exact_known_rational(&self.divisor.0)
2109 } else if dense_exact {
2110 matrix4_factors_dense_exact(&self.divisor.0)
2111 } else {
2112 matrix4_factors(&self.divisor.0)
2113 }
2114 });
2115 let determinant = if dense_exact && known_rational {
2116 determinant4_from_factors_known_rational(&factors.0, &factors.1)
2117 } else {
2118 determinant4_from_factors(&factors.0, &factors.1)
2119 };
2120 self.determinant = Some(determinant.clone());
2121 determinant
2122 }
2123
2124 #[inline]
2125 fn can_use_shared_adjugate(&self, left: &[[Real; 4]; 4]) -> bool {
2126 if true && self.right_exact_rational_kind != ExactRationalKind::NonRational {
2127 crate::trace_dispatch!(
2128 "hyperlattice_matrix",
2129 "helper",
2130 "prepared-right-divisor4-exact-right-skip-left-kind"
2131 );
2132 return true;
2133 }
2134 match self.right_exact_rational_kind {
2135 ExactRationalKind::ExactDyadicRational => {
2136 let left_kind = matrix4_exact_rational_kind(left);
2137 left_kind == ExactRationalKind::ExactDyadicRational
2138 || (true && left_kind == ExactRationalKind::ExactRational)
2139 }
2140 ExactRationalKind::ExactRational => {
2141 matches!(
2142 matrix4_exact_rational_kind(left),
2143 ExactRationalKind::ExactDyadicRational | ExactRationalKind::ExactRational
2144 )
2145 }
2146 ExactRationalKind::NonRational => false,
2147 }
2148 }
2149
2150 fn prepare_shared_adjugate(&mut self) -> BlasResult<&[[Real; 4]; 4]> {
2151 if self.adjugate.is_none() {
2152 crate::trace_dispatch!(
2153 "hyperlattice_matrix",
2154 "method",
2155 "prepared-right-divisor4-cache-shared-adjugate"
2156 );
2157 let dense_exact = self.is_definitely_dense_for_inverse;
2158 let known_rational = self.right_exact_rational_kind != ExactRationalKind::NonRational;
2159 let factors = self.factors.get_or_insert_with(|| {
2160 if dense_exact && known_rational {
2166 matrix4_factors_dense_exact_known_rational(&self.divisor.0)
2167 } else if dense_exact {
2168 matrix4_factors_dense_exact(&self.divisor.0)
2169 } else {
2170 matrix4_factors(&self.divisor.0)
2171 }
2172 });
2173 let determinant = if dense_exact && known_rational {
2174 determinant4_from_factors_known_rational(&factors.0, &factors.1)
2175 } else {
2176 determinant4_from_factors(&factors.0, &factors.1)
2177 };
2178 let reciprocal_determinant = determinant.inverse_ref()?;
2179 let adjugate = if dense_exact && known_rational {
2180 matrix4_adjugate_from_factors_dense_exact_known_rational(
2181 &self.divisor.0,
2182 &factors.0,
2183 &factors.1,
2184 )
2185 } else if dense_exact {
2186 matrix4_adjugate_from_factors_dense_exact(&self.divisor.0, &factors.0, &factors.1)
2187 } else {
2188 matrix4_adjugate_from_factors(&self.divisor.0, &factors.0, &factors.1)
2189 };
2190 self.adjugate = Some(adjugate);
2191 self.determinant = Some(determinant);
2192 self.reciprocal_determinant = Some(reciprocal_determinant);
2193 }
2194 Ok(self
2195 .adjugate
2196 .as_ref()
2197 .expect("adjugate cache must be present"))
2198 }
2199
2200 fn prepare_shared_adjugate_checked(&mut self) -> CheckedBlasResult<&[[Real; 4]; 4]> {
2201 if self.adjugate.is_none() {
2202 crate::trace_dispatch!(
2203 "hyperlattice_matrix",
2204 "method",
2205 "prepared-right-divisor4-cache-shared-adjugate-checked"
2206 );
2207 let dense_exact = self.is_definitely_dense_for_inverse;
2208 let known_rational = self.right_exact_rational_kind != ExactRationalKind::NonRational;
2209 let factors = self.factors.get_or_insert_with(|| {
2210 if dense_exact && known_rational {
2216 matrix4_factors_dense_exact_known_rational(&self.divisor.0)
2217 } else if dense_exact {
2218 matrix4_factors_dense_exact(&self.divisor.0)
2219 } else {
2220 matrix4_factors(&self.divisor.0)
2221 }
2222 });
2223 let determinant = if dense_exact && known_rational {
2224 determinant4_from_factors_known_rational(&factors.0, &factors.1)
2225 } else {
2226 determinant4_from_factors(&factors.0, &factors.1)
2227 };
2228 require_known_nonzero(&determinant)?;
2229 let reciprocal_determinant = determinant.inverse_ref()?;
2230 let adjugate = if dense_exact && known_rational {
2231 matrix4_adjugate_from_factors_dense_exact_known_rational(
2232 &self.divisor.0,
2233 &factors.0,
2234 &factors.1,
2235 )
2236 } else if dense_exact {
2237 matrix4_adjugate_from_factors_dense_exact(&self.divisor.0, &factors.0, &factors.1)
2238 } else {
2239 matrix4_adjugate_from_factors(&self.divisor.0, &factors.0, &factors.1)
2240 };
2241 self.adjugate = Some(adjugate);
2242 self.determinant = Some(determinant);
2243 self.reciprocal_determinant = Some(reciprocal_determinant);
2244 }
2245 Ok(self
2246 .adjugate
2247 .as_ref()
2248 .expect("adjugate cache must be present"))
2249 }
2250
2251 fn prepare_shared_adjugate_checked_with_abort(
2252 &mut self,
2253 signal: &AbortSignal,
2254 ) -> CheckedBlasResult<&[[Real; 4]; 4]> {
2255 if self.adjugate.is_none() {
2256 crate::trace_dispatch!(
2257 "hyperlattice_matrix",
2258 "method",
2259 "prepared-right-divisor4-cache-shared-adjugate-checked-abort"
2260 );
2261 let dense_exact = self.is_definitely_dense_for_inverse;
2262 let known_rational = self.right_exact_rational_kind != ExactRationalKind::NonRational;
2263 let factors = self.factors.get_or_insert_with(|| {
2264 if dense_exact && known_rational {
2268 matrix4_factors_dense_exact_known_rational(&self.divisor.0)
2269 } else if dense_exact {
2270 matrix4_factors_dense_exact(&self.divisor.0)
2271 } else {
2272 matrix4_factors(&self.divisor.0)
2273 }
2274 });
2275 let determinant = if dense_exact && known_rational {
2276 with_abort(
2277 determinant4_from_factors_known_rational(&factors.0, &factors.1),
2278 signal,
2279 )
2280 } else {
2281 with_abort(determinant4_from_factors(&factors.0, &factors.1), signal)
2282 };
2283 require_known_nonzero(&determinant)?;
2284 let reciprocal_determinant = determinant.inverse_ref()?;
2285 let adjugate = if dense_exact && known_rational {
2286 matrix4_adjugate_from_factors_dense_exact_known_rational(
2287 &self.divisor.0,
2288 &factors.0,
2289 &factors.1,
2290 )
2291 } else if dense_exact {
2292 matrix4_adjugate_from_factors_dense_exact(&self.divisor.0, &factors.0, &factors.1)
2293 } else {
2294 matrix4_adjugate_from_factors(&self.divisor.0, &factors.0, &factors.1)
2295 };
2296 self.adjugate = Some(adjugate);
2297 self.determinant = Some(determinant);
2298 self.reciprocal_determinant = Some(reciprocal_determinant);
2299 }
2300 Ok(self
2301 .adjugate
2302 .as_ref()
2303 .expect("adjugate cache must be present"))
2304 }
2305
2306 pub fn divide(&mut self, left: [[Real; 4]; 4]) -> BlasResult<[[Real; 4]; 4]> {
2314 crate::trace_dispatch!(
2315 "hyperlattice_matrix",
2316 "method",
2317 "prepared-right-divisor4-divide"
2318 );
2319 right_divide_matrix4_prepared(left, self)
2320 }
2321
2322 pub fn divide_exact_rational_left(
2330 &mut self,
2331 left: [[Real; 4]; 4],
2332 ) -> BlasResult<[[Real; 4]; 4]> {
2333 crate::trace_dispatch!(
2334 "hyperlattice_matrix",
2335 "method",
2336 "prepared-right-divisor4-divide-exact-rational-left"
2337 );
2338 right_divide_matrix4_prepared_exact_rational_left(left, self)
2339 }
2340
2341 pub fn divide_checked(&mut self, left: [[Real; 4]; 4]) -> CheckedBlasResult<[[Real; 4]; 4]> {
2347 crate::trace_dispatch!(
2348 "hyperlattice_matrix",
2349 "method",
2350 "prepared-right-divisor4-divide-checked"
2351 );
2352 right_divide_matrix4_prepared_checked(left, self)
2353 }
2354
2355 pub fn divide_checked_with_abort(
2361 &mut self,
2362 left: [[Real; 4]; 4],
2363 signal: &AbortSignal,
2364 ) -> CheckedBlasResult<[[Real; 4]; 4]> {
2365 crate::trace_dispatch!(
2366 "hyperlattice_matrix",
2367 "method",
2368 "prepared-right-divisor4-divide-checked-abort"
2369 );
2370 right_divide_matrix4_prepared_checked_with_abort(left, self, signal)
2371 }
2372
2373 pub fn inverse(&mut self) -> BlasResult<Matrix4> {
2379 crate::trace_dispatch!(
2380 "hyperlattice_matrix",
2381 "method",
2382 "prepared-right-divisor4-inverse"
2383 );
2384 if let Some(inverse) = &self.inverse {
2385 crate::trace_dispatch!(
2386 "hyperlattice_matrix",
2387 "method",
2388 "prepared-right-divisor4-inverse-cache-hit"
2389 );
2390 return Ok(inverse.clone());
2391 }
2392 let _ = self.prepare_shared_adjugate()?;
2393 let inv_det = self
2394 .reciprocal_determinant
2395 .as_ref()
2396 .expect("reciprocal determinant cache should be present");
2397 let adjugate = self
2398 .adjugate
2399 .as_ref()
2400 .expect("adjugate cache should be present")
2401 .clone();
2402 let inverse = Matrix4(scale_matrix4(adjugate, inv_det));
2403 self.inverse = Some(inverse.clone());
2404 Ok(inverse)
2405 }
2406
2407 pub fn inverse_checked(&mut self) -> CheckedBlasResult<Matrix4> {
2409 crate::trace_dispatch!(
2410 "hyperlattice_matrix",
2411 "method",
2412 "prepared-right-divisor4-inverse-checked"
2413 );
2414 let _ = self.prepare_shared_adjugate_checked()?;
2415 if let Some(inverse) = &self.inverse {
2416 crate::trace_dispatch!(
2417 "hyperlattice_matrix",
2418 "method",
2419 "prepared-right-divisor4-inverse-checked-cache-hit"
2420 );
2421 return Ok(inverse.clone());
2422 }
2423 let inv_det = self
2424 .reciprocal_determinant
2425 .as_ref()
2426 .expect("reciprocal determinant cache should be present");
2427 let adjugate = self
2428 .adjugate
2429 .as_ref()
2430 .expect("adjugate cache should be present")
2431 .clone();
2432 let inverse = Matrix4(scale_matrix4(adjugate, inv_det));
2433 self.inverse = Some(inverse.clone());
2434 Ok(inverse)
2435 }
2436
2437 pub fn inverse_checked_with_abort(
2439 &mut self,
2440 signal: &AbortSignal,
2441 ) -> CheckedBlasResult<Matrix4> {
2442 crate::trace_dispatch!(
2443 "hyperlattice_matrix",
2444 "method",
2445 "prepared-right-divisor4-inverse-checked-abort"
2446 );
2447 let _ = self.prepare_shared_adjugate_checked_with_abort(signal)?;
2448 if let Some(inverse) = &self.inverse {
2449 crate::trace_dispatch!(
2450 "hyperlattice_matrix",
2451 "method",
2452 "prepared-right-divisor4-inverse-checked-abort-cache-hit"
2453 );
2454 return Ok(inverse.clone());
2455 }
2456 let inv_det = self
2457 .reciprocal_determinant
2458 .as_ref()
2459 .expect("reciprocal determinant cache should be present");
2460 let adjugate = self
2461 .adjugate
2462 .as_ref()
2463 .expect("adjugate cache should be present")
2464 .clone();
2465 let inverse = Matrix4(scale_matrix4(adjugate, inv_det));
2466 self.inverse = Some(inverse.clone());
2467 Ok(inverse)
2468 }
2469
2470 pub fn reciprocal(&mut self) -> BlasResult<Matrix4> {
2477 crate::trace_dispatch!(
2478 "hyperlattice_matrix",
2479 "method",
2480 "prepared-right-divisor4-reciprocal"
2481 );
2482 self.inverse()
2483 }
2484
2485 pub fn reciprocal_checked(&mut self) -> CheckedBlasResult<Matrix4> {
2487 crate::trace_dispatch!(
2488 "hyperlattice_matrix",
2489 "method",
2490 "prepared-right-divisor4-reciprocal-checked"
2491 );
2492 self.inverse_checked()
2493 }
2494
2495 pub fn reciprocal_checked_with_abort(
2497 &mut self,
2498 signal: &AbortSignal,
2499 ) -> CheckedBlasResult<Matrix4> {
2500 crate::trace_dispatch!(
2501 "hyperlattice_matrix",
2502 "method",
2503 "prepared-right-divisor4-reciprocal-checked-abort"
2504 );
2505 self.inverse_checked_with_abort(signal)
2506 }
2507
2508 pub fn powi(&mut self, exponent: i32) -> BlasResult<Matrix4> {
2514 crate::trace_dispatch!(
2515 "hyperlattice_matrix",
2516 "method",
2517 "prepared-right-divisor4-powi"
2518 );
2519 if exponent == -1 {
2520 crate::trace_dispatch!(
2521 "hyperlattice_matrix",
2522 "powi",
2523 "prepared-negative-one-inverse"
2524 );
2525 return self.inverse();
2526 }
2527 let base = if exponent < 0 {
2528 self.inverse()?.0
2529 } else {
2530 self.divisor.0.clone()
2531 };
2532 let power = if self.right_exact_rational_kind != ExactRationalKind::NonRational {
2533 matrix_power4_known_rational(base, exponent.unsigned_abs())
2534 } else {
2535 matrix_power4(base, exponent.unsigned_abs())
2536 };
2537 Ok(Matrix4(power))
2538 }
2539
2540 pub fn powi_checked(&mut self, exponent: i32) -> CheckedBlasResult<Matrix4> {
2542 crate::trace_dispatch!(
2543 "hyperlattice_matrix",
2544 "method",
2545 "prepared-right-divisor4-powi-checked"
2546 );
2547 if exponent == -1 {
2548 crate::trace_dispatch!(
2549 "hyperlattice_matrix",
2550 "powi",
2551 "prepared-negative-one-inverse-checked"
2552 );
2553 return self.inverse_checked();
2554 }
2555 let base = if exponent < 0 {
2556 self.inverse_checked()?.0
2557 } else {
2558 self.divisor.0.clone()
2559 };
2560 let power = if self.right_exact_rational_kind != ExactRationalKind::NonRational {
2561 matrix_power4_known_rational(base, exponent.unsigned_abs())
2562 } else {
2563 matrix_power4(base, exponent.unsigned_abs())
2564 };
2565 Ok(Matrix4(power))
2566 }
2567
2568 pub fn powi_checked_with_abort(
2570 &mut self,
2571 exponent: i32,
2572 signal: &AbortSignal,
2573 ) -> CheckedBlasResult<Matrix4> {
2574 crate::trace_dispatch!(
2575 "hyperlattice_matrix",
2576 "method",
2577 "prepared-right-divisor4-powi-checked-abort"
2578 );
2579 if exponent == -1 {
2580 crate::trace_dispatch!(
2581 "hyperlattice_matrix",
2582 "powi",
2583 "prepared-negative-one-inverse-checked-abort"
2584 );
2585 return self.inverse_checked_with_abort(signal);
2586 }
2587 let base = if exponent < 0 {
2588 self.inverse_checked_with_abort(signal)?.0
2589 } else {
2590 self.divisor.0.clone()
2591 };
2592 let power = if self.right_exact_rational_kind != ExactRationalKind::NonRational {
2593 matrix_power4_known_rational(base, exponent.unsigned_abs())
2594 } else {
2595 matrix_power4(base, exponent.unsigned_abs())
2596 };
2597 Ok(Matrix4(power))
2598 }
2599}
2600
2601#[derive(Clone, Copy, Debug)]
2602struct Matrix4Facts {
2603 public: Matrix4StructuralFacts,
2604 exact: ExactRealSetFacts,
2605 is_identity: bool,
2606 is_diagonal: bool,
2607 is_upper_triangular: bool,
2608 is_lower_triangular: bool,
2609 linear_is_diagonal: bool,
2615 direction_linear_is_diagonal: bool,
2620 affine_linear_diagonal_is_definitely_nonzero: bool,
2624 is_definitely_dense_for_inverse: bool,
2625 translation_xyz_zero: [bool; 3],
2633 is_affine: bool,
2634 is_affine_translation: bool,
2635}
2636
2637#[inline]
2638fn matrix3_transform_kind(
2639 is_identity: bool,
2640 is_affine: bool,
2641 is_affine_translation: bool,
2642 linear_is_diagonal: bool,
2643) -> Matrix3TransformKind {
2644 if is_identity {
2645 Matrix3TransformKind::Identity
2646 } else if is_affine_translation {
2647 Matrix3TransformKind::AffineTranslation
2648 } else if is_affine && linear_is_diagonal {
2649 Matrix3TransformKind::AffineDiagonalLinear
2650 } else if is_affine {
2651 Matrix3TransformKind::Affine
2652 } else {
2653 Matrix3TransformKind::Projective
2654 }
2655}
2656
2657#[inline]
2658fn matrix4_transform_kind(
2659 is_identity: bool,
2660 is_affine: bool,
2661 is_affine_translation: bool,
2662 linear_is_diagonal: bool,
2663 signed_permutation_rows: Option<[SignedAxis4; 4]>,
2664) -> Matrix4TransformKind {
2665 if is_identity {
2666 Matrix4TransformKind::Identity
2667 } else if signed_permutation_rows.is_some() {
2668 Matrix4TransformKind::SignedPermutation
2669 } else if is_affine_translation {
2670 Matrix4TransformKind::AffineTranslation
2671 } else if is_affine && linear_is_diagonal {
2672 Matrix4TransformKind::AffineDiagonalLinear
2673 } else if is_affine {
2674 Matrix4TransformKind::Affine
2675 } else {
2676 Matrix4TransformKind::Projective
2677 }
2678}
2679
2680#[inline]
2681fn matrix3_facts(matrix: &[[Real; 3]; 3]) -> Matrix3Facts {
2682 let m00_one = matrix[0][0].definitely_one();
2687 let m01_zero = matrix[0][1].definitely_zero();
2688 let m02_zero = matrix[0][2].definitely_zero();
2689 let m10_zero = matrix[1][0].definitely_zero();
2690 let m11_one = matrix[1][1].definitely_one();
2691 let m12_zero = matrix[1][2].definitely_zero();
2692 let m20_zero = matrix[2][0].definitely_zero();
2693 let m21_zero = matrix[2][1].definitely_zero();
2694 let m22_one = matrix[2][2].definitely_one();
2695
2696 let linear_is_diagonal = m01_zero && m10_zero;
2697 let is_diagonal = m01_zero && m02_zero && m10_zero && m12_zero && m20_zero && m21_zero;
2698 let is_identity = is_diagonal && m00_one && m11_one && m22_one;
2699 let is_affine = m20_zero && m21_zero && m22_one;
2700 let is_upper_triangular = m10_zero && m20_zero && m21_zero;
2707 let is_lower_triangular = m01_zero && m02_zero && m12_zero;
2708 let is_affine_translation = is_affine && m00_one && m11_one && linear_is_diagonal;
2713 let exact = crate::kernels::exact_real_set_facts(matrix.iter().flat_map(|row| row.iter()));
2714 let (zero_mask, row_zero_masks, column_zero_masks) = matrix_zero_masks(matrix);
2715 let one_mask = matrix_one_mask(matrix);
2716 let transform_kind = matrix3_transform_kind(
2717 is_identity,
2718 is_affine,
2719 is_affine_translation,
2720 linear_is_diagonal,
2721 );
2722 let public = Matrix3StructuralFacts {
2723 exact,
2724 symbolic_dependencies: matrix_symbolic_dependency_mask(matrix),
2725 zero_mask,
2726 one_mask,
2727 row_zero_masks,
2728 column_zero_masks,
2729 is_identity,
2730 is_diagonal,
2731 is_exact_rational_uniform_scale: matrix3_exact_rational_uniform_scale(matrix, is_diagonal),
2732 is_upper_triangular,
2733 is_lower_triangular,
2734 is_affine,
2735 is_affine_translation,
2736 transform_kind,
2737 };
2738
2739 Matrix3Facts {
2740 public,
2741 exact,
2748 is_identity,
2749 is_diagonal,
2750 is_upper_triangular,
2751 is_lower_triangular,
2752 linear_is_diagonal,
2753 is_affine,
2754 is_affine_translation,
2755 }
2756}
2757
2758#[inline]
2759fn matrix4_facts(matrix: &[[Real; 4]; 4]) -> Matrix4Facts {
2760 let m00_one = matrix[0][0].definitely_one();
2764 let m01_zero = matrix[0][1].definitely_zero();
2765 let m02_zero = matrix[0][2].definitely_zero();
2766 let m03_zero = matrix[0][3].definitely_zero();
2767 let m10_zero = matrix[1][0].definitely_zero();
2768 let m11_one = matrix[1][1].definitely_one();
2769 let m12_zero = matrix[1][2].definitely_zero();
2770 let m13_zero = matrix[1][3].definitely_zero();
2771 let m20_zero = matrix[2][0].definitely_zero();
2772 let m21_zero = matrix[2][1].definitely_zero();
2773 let m22_one = matrix[2][2].definitely_one();
2774 let m23_zero = matrix[2][3].definitely_zero();
2775 let m30_zero = matrix[3][0].definitely_zero();
2776 let m31_zero = matrix[3][1].definitely_zero();
2777 let m32_zero = matrix[3][2].definitely_zero();
2778 let m33_one = matrix[3][3].definitely_one();
2779 let is_definitely_dense_for_inverse = matches!(matrix[1][0].zero_status(), ZeroStatus::NonZero)
2780 && matches!(matrix[0][1].zero_status(), ZeroStatus::NonZero)
2781 && matches!(matrix[3][0].zero_status(), ZeroStatus::NonZero);
2782
2783 let linear_is_diagonal = m01_zero && m02_zero && m10_zero && m12_zero && m20_zero && m21_zero;
2784 let direction_linear_is_diagonal = linear_is_diagonal && m30_zero && m31_zero && m32_zero;
2785 let is_diagonal = m01_zero
2786 && m02_zero
2787 && m03_zero
2788 && m10_zero
2789 && m12_zero
2790 && m13_zero
2791 && m20_zero
2792 && m21_zero
2793 && m23_zero
2794 && m30_zero
2795 && m31_zero
2796 && m32_zero;
2797 let is_upper_triangular = m10_zero && m20_zero && m30_zero && m21_zero && m31_zero && m32_zero;
2804 let is_lower_triangular = m01_zero && m02_zero && m03_zero && m12_zero && m13_zero && m23_zero;
2805 let is_identity = is_diagonal && m00_one && m11_one && m22_one && m33_one;
2806 let is_affine = m30_zero && m31_zero && m32_zero && m33_one;
2807 let is_affine_translation = is_affine && m00_one && m11_one && m22_one && linear_is_diagonal;
2808 let affine_linear_diagonal_is_definitely_nonzero = if true {
2809 matches!(matrix[0][0].zero_status(), ZeroStatus::NonZero)
2810 && matches!(matrix[1][1].zero_status(), ZeroStatus::NonZero)
2811 && matches!(matrix[2][2].zero_status(), ZeroStatus::NonZero)
2812 } else {
2813 false
2814 };
2815 let exact = crate::kernels::exact_real_set_facts(matrix.iter().flat_map(|row| row.iter()));
2816 let (zero_mask, row_zero_masks, column_zero_masks) = matrix_zero_masks(matrix);
2817 let one_mask = matrix_one_mask(matrix);
2818 let translation_xyz_zero = [m03_zero, m13_zero, m23_zero];
2819 let signed_permutation_rows = matrix4_signed_permutation_rows(matrix);
2820 let transform_kind = matrix4_transform_kind(
2821 is_identity,
2822 is_affine,
2823 is_affine_translation,
2824 linear_is_diagonal,
2825 signed_permutation_rows,
2826 );
2827 let public = Matrix4StructuralFacts {
2828 exact,
2829 symbolic_dependencies: matrix_symbolic_dependency_mask(matrix),
2830 zero_mask,
2831 one_mask,
2832 row_zero_masks,
2833 column_zero_masks,
2834 is_identity,
2835 is_diagonal,
2836 is_exact_rational_uniform_scale: matrix4_exact_rational_uniform_scale(matrix, is_diagonal),
2837 is_upper_triangular,
2838 is_lower_triangular,
2839 is_affine,
2840 is_affine_translation,
2841 linear_is_diagonal,
2842 direction_linear_is_diagonal,
2843 signed_permutation_rows,
2844 translation_xyz_zero,
2845 transform_kind,
2846 };
2847
2848 Matrix4Facts {
2849 public,
2850 exact,
2854 is_identity,
2855 is_diagonal,
2856 is_upper_triangular,
2857 is_lower_triangular,
2858 linear_is_diagonal,
2859 direction_linear_is_diagonal,
2860 is_definitely_dense_for_inverse,
2861 translation_xyz_zero,
2862 is_affine,
2863 is_affine_translation,
2864 affine_linear_diagonal_is_definitely_nonzero,
2865 }
2866}
2867
2868#[inline]
2869fn matrix3_facts_assuming_const3<const N: usize>(matrix: &[[Real; N]; N]) -> Matrix3Facts {
2870 debug_assert_eq!(N, 3);
2875 let m00_one = matrix[0][0].definitely_one();
2876 let m01_zero = matrix[0][1].definitely_zero();
2877 let m02_zero = matrix[0][2].definitely_zero();
2878 let m10_zero = matrix[1][0].definitely_zero();
2879 let m11_one = matrix[1][1].definitely_one();
2880 let m12_zero = matrix[1][2].definitely_zero();
2881 let m20_zero = matrix[2][0].definitely_zero();
2882 let m21_zero = matrix[2][1].definitely_zero();
2883 let m22_one = matrix[2][2].definitely_one();
2884
2885 let linear_is_diagonal = m01_zero && m10_zero;
2886 let is_diagonal = m01_zero && m02_zero && m10_zero && m12_zero && m20_zero && m21_zero;
2887 let is_identity = is_diagonal && m00_one && m11_one && m22_one;
2888 let is_affine = m20_zero && m21_zero && m22_one;
2889 let is_upper_triangular = m10_zero && m20_zero && m21_zero;
2890 let is_lower_triangular = m01_zero && m02_zero && m12_zero;
2891 let is_affine_translation = is_affine && m00_one && m11_one && linear_is_diagonal;
2892 let exact = crate::kernels::exact_real_set_facts(
2893 (0..3).flat_map(|row| (0..3).map(move |col| &matrix[row][col])),
2894 );
2895 let (zero_mask, row_zero_masks, column_zero_masks) =
2896 matrix_zero_masks_assuming_size::<N, 3>(matrix);
2897 let one_mask = matrix_one_mask_assuming_size::<N, 3>(matrix);
2898 let transform_kind = matrix3_transform_kind(
2899 is_identity,
2900 is_affine,
2901 is_affine_translation,
2902 linear_is_diagonal,
2903 );
2904 let public = Matrix3StructuralFacts {
2905 exact,
2906 symbolic_dependencies: matrix_symbolic_dependency_mask_assuming_size::<N, 3>(matrix),
2907 zero_mask,
2908 one_mask,
2909 row_zero_masks,
2910 column_zero_masks,
2911 is_identity,
2912 is_diagonal,
2913 is_exact_rational_uniform_scale: matrix3_exact_rational_uniform_scale_assuming_size(
2914 matrix,
2915 is_diagonal,
2916 ),
2917 is_upper_triangular,
2918 is_lower_triangular,
2919 is_affine,
2920 is_affine_translation,
2921 transform_kind,
2922 };
2923
2924 Matrix3Facts {
2925 public,
2926 exact,
2927 is_identity,
2928 is_diagonal,
2929 is_upper_triangular,
2930 is_lower_triangular,
2931 linear_is_diagonal,
2932 is_affine,
2933 is_affine_translation,
2934 }
2935}
2936
2937#[inline]
2938fn matrix4_facts_assuming_const4<const N: usize>(matrix: &[[Real; N]; N]) -> Matrix4Facts {
2939 debug_assert_eq!(N, 4);
2943 let m00_one = matrix[0][0].definitely_one();
2944 let m01_zero = matrix[0][1].definitely_zero();
2945 let m02_zero = matrix[0][2].definitely_zero();
2946 let m03_zero = matrix[0][3].definitely_zero();
2947 let m10_zero = matrix[1][0].definitely_zero();
2948 let m11_one = matrix[1][1].definitely_one();
2949 let m12_zero = matrix[1][2].definitely_zero();
2950 let m13_zero = matrix[1][3].definitely_zero();
2951 let m20_zero = matrix[2][0].definitely_zero();
2952 let m21_zero = matrix[2][1].definitely_zero();
2953 let m22_one = matrix[2][2].definitely_one();
2954 let m23_zero = matrix[2][3].definitely_zero();
2955 let m30_zero = matrix[3][0].definitely_zero();
2956 let m31_zero = matrix[3][1].definitely_zero();
2957 let m32_zero = matrix[3][2].definitely_zero();
2958 let m33_one = matrix[3][3].definitely_one();
2959 let is_definitely_dense_for_inverse = matches!(matrix[1][0].zero_status(), ZeroStatus::NonZero)
2960 && matches!(matrix[0][1].zero_status(), ZeroStatus::NonZero)
2961 && matches!(matrix[3][0].zero_status(), ZeroStatus::NonZero);
2962
2963 let linear_is_diagonal = m01_zero && m02_zero && m10_zero && m12_zero && m20_zero && m21_zero;
2964 let direction_linear_is_diagonal = linear_is_diagonal && m30_zero && m31_zero && m32_zero;
2965 let is_diagonal = m01_zero
2966 && m02_zero
2967 && m03_zero
2968 && m10_zero
2969 && m12_zero
2970 && m13_zero
2971 && m20_zero
2972 && m21_zero
2973 && m23_zero
2974 && m30_zero
2975 && m31_zero
2976 && m32_zero;
2977 let is_upper_triangular = m10_zero && m20_zero && m30_zero && m21_zero && m31_zero && m32_zero;
2978 let is_lower_triangular = m01_zero && m02_zero && m03_zero && m12_zero && m13_zero && m23_zero;
2979 let is_identity = is_diagonal && m00_one && m11_one && m22_one && m33_one;
2980 let is_affine = m30_zero && m31_zero && m32_zero && m33_one;
2981 let is_affine_translation = is_affine && m00_one && m11_one && m22_one && linear_is_diagonal;
2982 let affine_linear_diagonal_is_definitely_nonzero = if true {
2983 matches!(matrix[0][0].zero_status(), ZeroStatus::NonZero)
2984 && matches!(matrix[1][1].zero_status(), ZeroStatus::NonZero)
2985 && matches!(matrix[2][2].zero_status(), ZeroStatus::NonZero)
2986 } else {
2987 false
2988 };
2989 let exact = crate::kernels::exact_real_set_facts(
2990 (0..4).flat_map(|row| (0..4).map(move |col| &matrix[row][col])),
2991 );
2992 let (zero_mask, row_zero_masks, column_zero_masks) =
2993 matrix_zero_masks_assuming_size::<N, 4>(matrix);
2994 let one_mask = matrix_one_mask_assuming_size::<N, 4>(matrix);
2995 let translation_xyz_zero = [m03_zero, m13_zero, m23_zero];
2996 let signed_permutation_rows = matrix4_signed_permutation_rows_assuming_size(matrix);
2997 let transform_kind = matrix4_transform_kind(
2998 is_identity,
2999 is_affine,
3000 is_affine_translation,
3001 linear_is_diagonal,
3002 signed_permutation_rows,
3003 );
3004 let public = Matrix4StructuralFacts {
3005 exact,
3006 symbolic_dependencies: matrix_symbolic_dependency_mask_assuming_size::<N, 4>(matrix),
3007 zero_mask,
3008 one_mask,
3009 row_zero_masks,
3010 column_zero_masks,
3011 is_identity,
3012 is_diagonal,
3013 is_exact_rational_uniform_scale: matrix4_exact_rational_uniform_scale_assuming_size(
3014 matrix,
3015 is_diagonal,
3016 ),
3017 is_upper_triangular,
3018 is_lower_triangular,
3019 is_affine,
3020 is_affine_translation,
3021 linear_is_diagonal,
3022 direction_linear_is_diagonal,
3023 signed_permutation_rows,
3024 translation_xyz_zero,
3025 transform_kind,
3026 };
3027
3028 Matrix4Facts {
3029 public,
3030 exact,
3031 is_identity,
3032 is_diagonal,
3033 is_upper_triangular,
3034 is_lower_triangular,
3035 linear_is_diagonal,
3036 direction_linear_is_diagonal,
3037 is_definitely_dense_for_inverse,
3038 translation_xyz_zero,
3039 is_affine,
3040 is_affine_translation,
3041 affine_linear_diagonal_is_definitely_nonzero,
3042 }
3043}
3044
3045fn map_array2<const N: usize, F>(left: [Real; N], right: [Real; N], mut op: F) -> [Real; N]
3046where
3047 F: FnMut(Real, Real) -> Real,
3048{
3049 let mut right = right.into_iter();
3050 left.map(|lhs| op(lhs, right.next().expect("arrays have equal length")))
3051}
3052
3053fn map_array_ref<const N: usize, F>(left: [Real; N], right: &[Real; N], mut op: F) -> [Real; N]
3054where
3055 F: FnMut(Real, &Real) -> Real,
3056{
3057 let mut right = right.iter();
3058 left.map(|lhs| op(lhs, right.next().expect("arrays have equal length")))
3059}
3060
3061fn map_matrix2<const N: usize, F>(
3062 left: [[Real; N]; N],
3063 right: [[Real; N]; N],
3064 mut op: F,
3065) -> [[Real; N]; N]
3066where
3067 F: FnMut(Real, Real) -> Real,
3068{
3069 let mut right = right.into_iter();
3070 left.map(|lhs_row| {
3071 map_array2(
3072 lhs_row,
3073 right.next().expect("matrices have equal row counts"),
3074 &mut op,
3075 )
3076 })
3077}
3078
3079fn map_matrix_ref<const N: usize, F>(
3080 left: [[Real; N]; N],
3081 right: &[[Real; N]; N],
3082 mut op: F,
3083) -> [[Real; N]; N]
3084where
3085 F: FnMut(Real, &Real) -> Real,
3086{
3087 let mut right = right.iter();
3088 left.map(|lhs_row| {
3089 map_array_ref(
3090 lhs_row,
3091 right.next().expect("matrices have equal row counts"),
3092 &mut op,
3093 )
3094 })
3095}
3096
3097fn map_matrix_left_ref<const N: usize, F>(
3098 left: &[[Real; N]; N],
3099 right: [[Real; N]; N],
3100 mut op: F,
3101) -> [[Real; N]; N]
3102where
3103 F: FnMut(&Real, Real) -> Real,
3104{
3105 let mut left = left.iter();
3106 right.map(|rhs_row| {
3107 let mut left_row = left.next().expect("matrices have equal row counts").iter();
3108 rhs_row.map(|rhs| op(left_row.next().expect("arrays have equal length"), rhs))
3109 })
3110}
3111
3112#[inline]
3113fn matrix_power_with<const N: usize, F>(
3114 base: [[Real; N]; N],
3115 exponent: u32,
3116 mut multiply: F,
3117) -> [[Real; N]; N]
3118where
3119 F: FnMut([[Real; N]; N], [[Real; N]; N]) -> [[Real; N]; N],
3120{
3121 match exponent {
3141 0 => return identity_array(),
3142 1 => return base,
3143 2 => return multiply(base.clone(), base),
3146 3 => {
3147 let square = multiply(base.clone(), base.clone());
3148 return multiply(square, base);
3149 }
3150 4 => {
3151 let square = multiply(base.clone(), base);
3152 return multiply(square.clone(), square);
3153 }
3154 _ => {}
3155 }
3156
3157 let mut exp = exponent;
3158 let mut result = None;
3159 let mut factor = base;
3160
3161 while exp > 0 {
3162 if exp & 1 == 1 {
3163 result = Some(match result {
3164 Some(result) => multiply(result, factor.clone()),
3165 None => factor.clone(),
3166 });
3167 }
3168 exp >>= 1;
3169 if exp > 0 {
3170 factor = multiply(factor.clone(), factor);
3171 }
3172 }
3173
3174 result.expect("positive exponent sets at least one result bit")
3175}
3176
3177#[inline]
3178fn matrix_power3(base: [[Real; 3]; 3], exponent: u32) -> [[Real; 3]; 3] {
3179 crate::trace_dispatch!("hyperlattice_matrix", "helper", "matrix-power3-fixed-mul");
3180 if exponent == 2 {
3184 crate::trace_dispatch!(
3185 "hyperlattice_matrix",
3186 "helper",
3187 "matrix-power3-borrowed-square"
3188 );
3189 if true && matrix3_has_dense_multiply_certificate(&base) {
3190 crate::trace_dispatch!(
3191 "hyperlattice_matrix",
3192 "helper",
3193 "matrix-power3-dense-certified-square"
3194 );
3195 return multiply_arrays3_dense_ref(&base, &base);
3196 }
3197 return multiply_arrays3_ref(&base, &base);
3198 }
3199 if exponent == 3 {
3200 crate::trace_dispatch!(
3201 "hyperlattice_matrix",
3202 "helper",
3203 "matrix-power3-borrowed-cube"
3204 );
3205 if true && matrix3_has_dense_multiply_certificate(&base) {
3206 crate::trace_dispatch!(
3207 "hyperlattice_matrix",
3208 "helper",
3209 "matrix-power3-dense-certified-cube"
3210 );
3211 let square = multiply_arrays3_dense_ref(&base, &base);
3212 return multiply_arrays3_rhs_ref_with_exact_dense_certificate(square, &base);
3213 }
3214 let square = multiply_arrays3_ref(&base, &base);
3215 return multiply_arrays3_rhs_ref(square, &base);
3216 }
3217 matrix_power_with(base, exponent, multiply_arrays3)
3218}
3219
3220#[inline]
3221fn matrix_power4(base: [[Real; 4]; 4], exponent: u32) -> [[Real; 4]; 4] {
3222 crate::trace_dispatch!("hyperlattice_matrix", "helper", "matrix-power4-fixed-mul");
3223 if exponent == 2 {
3227 crate::trace_dispatch!(
3228 "hyperlattice_matrix",
3229 "helper",
3230 "matrix-power4-borrowed-square"
3231 );
3232 if true && matrix4_has_dense_multiply_certificate(&base) {
3233 crate::trace_dispatch!(
3234 "hyperlattice_matrix",
3235 "helper",
3236 "matrix-power4-dense-certified-square"
3237 );
3238 return multiply_arrays4_dense_ref(&base, &base);
3239 }
3240 return multiply_arrays4_ref(&base, &base);
3241 }
3242 if exponent == 3 {
3243 crate::trace_dispatch!(
3244 "hyperlattice_matrix",
3245 "helper",
3246 "matrix-power4-borrowed-cube"
3247 );
3248 if true && matrix4_has_dense_multiply_certificate(&base) {
3249 crate::trace_dispatch!(
3250 "hyperlattice_matrix",
3251 "helper",
3252 "matrix-power4-dense-certified-cube"
3253 );
3254 let square = multiply_arrays4_dense_ref(&base, &base);
3255 return multiply_arrays4_rhs_ref_with_dense_certificate(square, &base);
3256 }
3257 let square = multiply_arrays4_ref(&base, &base);
3258 return multiply_arrays4_rhs_ref(square, &base);
3259 }
3260 matrix_power_with(base, exponent, multiply_arrays4)
3261}
3262
3263#[inline]
3264fn matrix_power4_known_rational(base: [[Real; 4]; 4], exponent: u32) -> [[Real; 4]; 4] {
3265 crate::trace_dispatch!(
3266 "hyperlattice_matrix",
3267 "helper",
3268 "matrix-power4-known-rational"
3269 );
3270 if true {
3271 if exponent == 2 {
3272 crate::trace_dispatch!(
3273 "hyperlattice_matrix",
3274 "helper",
3275 "matrix-power4-known-rational-square"
3276 );
3277 return multiply_arrays4_dense_known_rational_ref(&base, &base);
3278 }
3279 if exponent == 3 {
3280 crate::trace_dispatch!(
3281 "hyperlattice_matrix",
3282 "helper",
3283 "matrix-power4-known-rational-cube"
3284 );
3285 let square = multiply_arrays4_dense_known_rational_ref(&base, &base);
3286 return multiply_arrays4_dense_known_rational_ref(&square, &base);
3287 }
3288 }
3289 matrix_power4(base, exponent)
3290}
3291
3292fn ordinary_pivot<const N: usize>(left: &[[Real; N]; N], col: usize) -> Option<usize> {
3293 let mut unknown = None;
3294 match zero_status(&left[col][col]) {
3295 ZeroStatus::NonZero => return Some(col),
3296 ZeroStatus::Unknown => unknown = Some(col),
3297 ZeroStatus::Zero => {}
3298 }
3299
3300 for (row, values) in left.iter().enumerate().skip(col + 1) {
3301 match zero_status(&values[col]) {
3302 ZeroStatus::NonZero => return Some(row),
3303 ZeroStatus::Unknown if unknown.is_none() => unknown = Some(row),
3304 ZeroStatus::Zero | ZeroStatus::Unknown => {}
3305 }
3306 }
3307
3308 unknown
3309}
3310
3311fn checked_pivot<const N: usize, F>(
3312 left: &[[Real; N]; N],
3313 col: usize,
3314 mut classify: F,
3315) -> CheckedBlasResult<usize>
3316where
3317 F: FnMut(&Real) -> ZeroStatus,
3318{
3319 let mut has_unknown = false;
3320 for (row, values) in left.iter().enumerate().skip(col) {
3321 match classify(&values[col]) {
3322 ZeroStatus::NonZero => return Ok(row),
3323 ZeroStatus::Unknown => has_unknown = true,
3324 ZeroStatus::Zero => {}
3325 }
3326 }
3327
3328 if has_unknown {
3329 Err(Problem::UnknownZero)
3330 } else {
3331 Err(Problem::DivideByZero)
3332 }
3333}
3334
3335fn scale_entry_in_place(value: &mut Real, factor: &Real) {
3336 let current = mem::replace(value, Real::zero());
3337 *value = current.mul_cached(factor);
3338}
3339
3340fn subtract_scaled_entry_in_place(value: &mut Real, pivot: &Real, factor: &Real) {
3341 let current = mem::replace(value, Real::zero());
3342 *value = current - pivot * factor;
3345}
3346
3347macro_rules! impl_solve_left_system_fixed {
3348 (
3349 $solve_fn:ident,
3350 $solve_checked_fn:ident,
3351 $solve_abort_fn:ident,
3352 $n:expr
3353 ) => {
3354 fn $solve_fn(
3355 coefficients: [[Real; $n]; $n],
3356 rhs: [[Real; $n]; $n],
3357 ) -> BlasResult<[[Real; $n]; $n]> {
3358 let mut left = coefficients;
3359 let mut right = rhs;
3360
3361 for col in 0..$n {
3362 let Some(pivot) = ordinary_pivot(&left, col) else {
3363 return Err(Problem::DivideByZero);
3364 };
3365 if pivot != col {
3366 left.swap(col, pivot);
3367 right.swap(col, pivot);
3368 }
3369
3370 let pivot = mem::replace(&mut left[col][col], Real::one());
3377 let inv_pivot = pivot.inverse()?;
3378 for i in 0..$n {
3379 scale_entry_in_place(&mut right[col][i], &inv_pivot);
3380 }
3381 for i in (col + 1)..$n {
3382 scale_entry_in_place(&mut left[col][i], &inv_pivot);
3383 }
3384 let pivot_left = left[col].clone();
3385 let pivot_right = right[col].clone();
3386
3387 for row in 0..$n {
3388 if row == col {
3389 continue;
3390 }
3391 if left[row][col].definitely_zero() {
3394 continue;
3395 }
3396 let factor = mem::replace(&mut left[row][col], Real::zero());
3397 for i in (col + 1)..$n {
3398 subtract_scaled_entry_in_place(&mut left[row][i], &pivot_left[i], &factor);
3399 }
3400 for i in 0..$n {
3401 subtract_scaled_entry_in_place(
3402 &mut right[row][i],
3403 &pivot_right[i],
3404 &factor,
3405 );
3406 }
3407 }
3408 }
3409
3410 Ok(right)
3411 }
3412
3413 fn $solve_checked_fn(
3414 coefficients: [[Real; $n]; $n],
3415 rhs: [[Real; $n]; $n],
3416 ) -> CheckedBlasResult<[[Real; $n]; $n]> {
3417 let mut left = coefficients;
3418 let mut right = rhs;
3419
3420 for col in 0..$n {
3421 let pivot = checked_pivot(&left, col, zero_status)?;
3422 if pivot != col {
3423 left.swap(col, pivot);
3424 right.swap(col, pivot);
3425 }
3426
3427 let pivot = mem::replace(&mut left[col][col], Real::one());
3432 let inv_pivot = pivot.inverse()?;
3433 for i in 0..$n {
3434 scale_entry_in_place(&mut right[col][i], &inv_pivot);
3435 }
3436 for i in (col + 1)..$n {
3437 scale_entry_in_place(&mut left[col][i], &inv_pivot);
3438 }
3439 let pivot_left = left[col].clone();
3440 let pivot_right = right[col].clone();
3441
3442 for row in 0..$n {
3443 if row == col {
3444 continue;
3445 }
3446 if left[row][col].definitely_zero() {
3448 continue;
3449 }
3450 let factor = mem::replace(&mut left[row][col], Real::zero());
3451 for i in (col + 1)..$n {
3452 subtract_scaled_entry_in_place(&mut left[row][i], &pivot_left[i], &factor);
3453 }
3454 for i in 0..$n {
3455 subtract_scaled_entry_in_place(
3456 &mut right[row][i],
3457 &pivot_right[i],
3458 &factor,
3459 );
3460 }
3461 }
3462 }
3463
3464 Ok(right)
3465 }
3466
3467 fn $solve_abort_fn(
3468 coefficients: [[Real; $n]; $n],
3469 rhs: [[Real; $n]; $n],
3470 signal: &AbortSignal,
3471 ) -> CheckedBlasResult<[[Real; $n]; $n]> {
3472 let mut left = coefficients;
3473 let mut right = rhs;
3474
3475 for col in 0..$n {
3476 let pivot =
3477 checked_pivot(&left, col, |value| zero_status_with_abort(value, signal))?;
3478 if pivot != col {
3479 left.swap(col, pivot);
3480 right.swap(col, pivot);
3481 }
3482
3483 let pivot = mem::replace(&mut left[col][col], Real::one());
3484 let inv_pivot = clone_with_abort(&pivot, signal).inverse()?;
3485 for i in 0..$n {
3486 scale_entry_in_place(&mut right[col][i], &inv_pivot);
3487 }
3488 for i in (col + 1)..$n {
3489 scale_entry_in_place(&mut left[col][i], &inv_pivot);
3490 }
3491 let pivot_left = left[col].clone();
3492 let pivot_right = right[col].clone();
3493
3494 for row in 0..$n {
3495 if row == col {
3496 continue;
3497 }
3498 if left[row][col].definitely_zero() {
3502 continue;
3503 }
3504 let factor = mem::replace(&mut left[row][col], Real::zero());
3505 for i in (col + 1)..$n {
3506 subtract_scaled_entry_in_place(&mut left[row][i], &pivot_left[i], &factor);
3507 }
3508 for i in 0..$n {
3509 subtract_scaled_entry_in_place(
3510 &mut right[row][i],
3511 &pivot_right[i],
3512 &factor,
3513 );
3514 }
3515 }
3516 }
3517
3518 Ok(right)
3519 }
3520 };
3521}
3522
3523impl_solve_left_system_fixed!(
3524 solve_left_system3,
3525 solve_left_system3_checked,
3526 solve_left_system3_checked_with_abort,
3527 3
3528);
3529impl_solve_left_system_fixed!(
3530 solve_left_system4,
3531 solve_left_system4_checked,
3532 solve_left_system4_checked_with_abort,
3533 4
3534);
3535
3536fn prefer_shared_adjugate_right_division<const N: usize>(
3537 left: &[[Real; N]; N],
3538 right: &[[Real; N]; N],
3539) -> bool {
3540 let right_kind = matrix_exact_rational_kind(right);
3554 if right_kind == ExactRationalKind::NonRational {
3555 return false;
3556 }
3557 if true && N == 4 {
3558 crate::trace_dispatch!(
3559 "hyperlattice_matrix",
3560 "helper",
3561 "right-divide4-exact-right-skip-left-kind"
3562 );
3563 return true;
3564 }
3565 if true && N == 3 && right_kind == ExactRationalKind::ExactRational {
3566 crate::trace_dispatch!(
3567 "hyperlattice_matrix",
3568 "helper",
3569 "right-divide3-exact-right-skip-left-kind"
3570 );
3571 return true;
3572 }
3573 let left_kind = matrix_exact_rational_kind(left);
3574 matches!(
3575 combine_exact_rational_kind(left_kind, right_kind),
3576 ExactRationalKind::ExactDyadicRational | ExactRationalKind::ExactRational
3577 )
3578}
3579
3580fn prefer_shared_adjugate_right_division_ref3(
3581 left: &[[Real; 3]; 3],
3582 right: &[[Real; 3]; 3],
3583) -> bool {
3584 let right_kind = matrix3_exact_rational_kind(right);
3585 if right_kind == ExactRationalKind::NonRational {
3586 return false;
3587 }
3588 if true && right_kind == ExactRationalKind::ExactRational {
3589 crate::trace_dispatch!(
3590 "hyperlattice_matrix",
3591 "helper",
3592 "right-divide3-ref-exact-right-skip-left-kind"
3593 );
3594 return true;
3595 }
3596 let left_kind = matrix3_exact_rational_kind(left);
3597 matches!(
3598 combine_exact_rational_kind(left_kind, right_kind),
3599 ExactRationalKind::ExactDyadicRational | ExactRationalKind::ExactRational
3600 )
3601}
3602
3603#[inline]
3604fn matrix4_direction_linear_is_diagonal(matrix: &[[Real; 4]; 4]) -> bool {
3605 matrix[0][1].definitely_zero()
3612 && matrix[0][2].definitely_zero()
3613 && matrix[1][0].definitely_zero()
3614 && matrix[1][2].definitely_zero()
3615 && matrix[2][0].definitely_zero()
3616 && matrix[2][1].definitely_zero()
3617 && matrix[3][0].definitely_zero()
3618 && matrix[3][1].definitely_zero()
3619 && matrix[3][2].definitely_zero()
3620}
3621
3622#[derive(Clone, Copy, Debug, Eq, PartialEq)]
3623enum Matrix4DirectionLinearKind {
3624 Identity,
3625 Diagonal,
3626 General,
3627}
3628
3629#[inline]
3630fn matrix4_direction_linear_kind(matrix: &[[Real; 4]; 4]) -> Matrix4DirectionLinearKind {
3631 if !matrix4_direction_linear_is_diagonal(matrix) {
3637 return Matrix4DirectionLinearKind::General;
3638 }
3639 if matrix[0][0].definitely_one()
3640 && matrix[1][1].definitely_one()
3641 && matrix[2][2].definitely_one()
3642 {
3643 Matrix4DirectionLinearKind::Identity
3644 } else {
3645 Matrix4DirectionLinearKind::Diagonal
3646 }
3647}
3648
3649#[inline]
3650fn matrix4_affine_linear_is_diagonal(matrix: &[[Real; 4]; 4]) -> bool {
3651 matrix[0][1].definitely_zero()
3658 && matrix[0][2].definitely_zero()
3659 && matrix[1][0].definitely_zero()
3660 && matrix[1][2].definitely_zero()
3661 && matrix[2][0].definitely_zero()
3662 && matrix[2][1].definitely_zero()
3663 && matrix[3][0].definitely_zero()
3664 && matrix[3][1].definitely_zero()
3665 && matrix[3][2].definitely_zero()
3666 && matrix[3][3].definitely_one()
3667}
3668
3669#[inline]
3670fn matrix3_is_definitely_dense_for_inverse(matrix: &[[Real; 3]; 3]) -> bool {
3671 matches!(matrix[1][0].zero_status(), ZeroStatus::NonZero)
3681 && matches!(matrix[0][1].zero_status(), ZeroStatus::NonZero)
3682 && matches!(matrix[2][0].zero_status(), ZeroStatus::NonZero)
3683}
3684
3685#[inline]
3686fn matrix4_is_definitely_dense_for_inverse(matrix: &[[Real; 4]; 4]) -> bool {
3687 matches!(matrix[1][0].zero_status(), ZeroStatus::NonZero)
3695 && matches!(matrix[0][1].zero_status(), ZeroStatus::NonZero)
3696 && matches!(matrix[3][0].zero_status(), ZeroStatus::NonZero)
3697}
3698
3699#[inline]
3700fn matrix3_has_dense_multiply_certificate(matrix: &[[Real; 3]; 3]) -> bool {
3701 matches!(matrix[1][0].zero_status(), ZeroStatus::NonZero)
3707 && matches!(matrix[0][1].zero_status(), ZeroStatus::NonZero)
3708 && matches!(matrix[2][0].zero_status(), ZeroStatus::NonZero)
3709}
3710
3711#[inline]
3712fn matrix4_has_dense_multiply_certificate(matrix: &[[Real; 4]; 4]) -> bool {
3713 matches!(matrix[1][0].zero_status(), ZeroStatus::NonZero)
3718 && matches!(matrix[0][1].zero_status(), ZeroStatus::NonZero)
3719 && matches!(matrix[3][0].zero_status(), ZeroStatus::NonZero)
3720}
3721
3722#[inline]
3723fn multiply_arrays4_ref_with_dense_certificate(
3724 left: &[[Real; 4]; 4],
3725 right: &[[Real; 4]; 4],
3726) -> [[Real; 4]; 4] {
3727 if true
3728 && matrix4_has_dense_multiply_certificate(left)
3729 && matrix4_has_dense_multiply_certificate(right)
3730 {
3731 crate::trace_dispatch!(
3732 "hyperlattice_matrix",
3733 "helper",
3734 "multiply4-dense-certified-ref"
3735 );
3736 return multiply_arrays4_dense_ref(left, right);
3737 }
3738 multiply_arrays4_ref(left, right)
3739}
3740
3741#[inline]
3742fn multiply_arrays4_rhs_ref_with_dense_certificate(
3743 left: [[Real; 4]; 4],
3744 right: &[[Real; 4]; 4],
3745) -> [[Real; 4]; 4] {
3746 if true
3747 && matrix4_has_dense_multiply_certificate(&left)
3748 && matrix4_has_dense_multiply_certificate(right)
3749 {
3750 crate::trace_dispatch!(
3751 "hyperlattice_matrix",
3752 "helper",
3753 "multiply4-dense-certified-owned-ref"
3754 );
3755 return multiply_arrays4_dense_ref(&left, right);
3756 }
3757 multiply_arrays4_rhs_ref(left, right)
3758}
3759
3760#[inline]
3761fn invert_matrix4_affine_linear_diagonal(matrix: &[[Real; 4]; 4]) -> BlasResult<[[Real; 4]; 4]> {
3762 let inv00 = matrix[0][0].clone().inverse()?;
3770 let inv11 = matrix[1][1].clone().inverse()?;
3771 let inv22 = matrix[2][2].clone().inverse()?;
3772 let inv_tx = Real::zero() - (&matrix[0][3] * &inv00);
3773 let inv_ty = Real::zero() - (&matrix[1][3] * &inv11);
3774 let inv_tz = Real::zero() - (&matrix[2][3] * &inv22);
3775
3776 Ok([
3777 [inv00, Real::zero(), Real::zero(), inv_tx],
3778 [Real::zero(), inv11, Real::zero(), inv_ty],
3779 [Real::zero(), Real::zero(), inv22, inv_tz],
3780 [Real::zero(), Real::zero(), Real::zero(), Real::one()],
3781 ])
3782}
3783
3784#[inline]
3785fn invert_matrix4_affine_linear_diagonal_checked(
3786 matrix: &[[Real; 4]; 4],
3787) -> CheckedBlasResult<[[Real; 4]; 4]> {
3788 require_known_nonzero(&matrix[0][0])?;
3789 require_known_nonzero(&matrix[1][1])?;
3790 require_known_nonzero(&matrix[2][2])?;
3791 invert_matrix4_affine_linear_diagonal(matrix)
3792}
3793
3794#[inline]
3795fn invert_matrix4_affine_linear_diagonal_checked_with_abort(
3796 matrix: &[[Real; 4]; 4],
3797 signal: &AbortSignal,
3798) -> CheckedBlasResult<[[Real; 4]; 4]> {
3799 require_known_nonzero_with_abort(&matrix[0][0], signal)?;
3800 require_known_nonzero_with_abort(&matrix[1][1], signal)?;
3801 require_known_nonzero_with_abort(&matrix[2][2], signal)?;
3802 invert_matrix4_affine_linear_diagonal(matrix)
3803}
3804
3805#[inline]
3806fn invert_matrix4_affine(
3807 matrix: &[[Real; 4]; 4],
3808 linear_is_diagonal: bool,
3809 is_affine_translation: bool,
3810) -> BlasResult<[[Real; 4]; 4]> {
3811 if linear_is_diagonal {
3815 crate::trace_dispatch!(
3816 "hyperlattice_matrix",
3817 "helper",
3818 "invert-matrix4-affine-linear-diagonal"
3819 );
3820 return invert_matrix4_affine_linear_diagonal(matrix);
3821 }
3822 if is_affine_translation {
3823 crate::trace_dispatch!(
3824 "hyperlattice_matrix",
3825 "helper",
3826 "invert-matrix4-affine-translation"
3827 );
3828 return Ok([
3829 [
3830 matrix[0][0].clone(),
3831 matrix[0][1].clone(),
3832 matrix[0][2].clone(),
3833 Real::zero() - &matrix[0][3],
3834 ],
3835 [
3836 matrix[1][0].clone(),
3837 matrix[1][1].clone(),
3838 matrix[1][2].clone(),
3839 Real::zero() - &matrix[1][3],
3840 ],
3841 [
3842 matrix[2][0].clone(),
3843 matrix[2][1].clone(),
3844 matrix[2][2].clone(),
3845 Real::zero() - &matrix[2][3],
3846 ],
3847 [Real::zero(), Real::zero(), Real::zero(), Real::one()],
3848 ]);
3849 }
3850 invert_matrix4_affine_without_translation(matrix)
3851}
3852
3853#[inline]
3854fn invert_matrix4_affine_without_translation(
3855 matrix: &[[Real; 4]; 4],
3856) -> BlasResult<[[Real; 4]; 4]> {
3857 let linear = [
3863 [
3864 matrix[0][0].clone(),
3865 matrix[0][1].clone(),
3866 matrix[0][2].clone(),
3867 ],
3868 [
3869 matrix[1][0].clone(),
3870 matrix[1][1].clone(),
3871 matrix[1][2].clone(),
3872 ],
3873 [
3874 matrix[2][0].clone(),
3875 matrix[2][1].clone(),
3876 matrix[2][2].clone(),
3877 ],
3878 ];
3879 let translation = [
3880 matrix[0][3].clone(),
3881 matrix[1][3].clone(),
3882 matrix[2][3].clone(),
3883 ];
3884 let inverse_linear = invert_matrix3(linear)?;
3885
3886 let inverse_translation: [Real; 3] = from_fn(|row| {
3887 let shifted = affine_translation_dot3(
3888 [
3889 &inverse_linear[row][0],
3890 &inverse_linear[row][1],
3891 &inverse_linear[row][2],
3892 ],
3893 [&translation[0], &translation[1], &translation[2]],
3894 );
3895 Real::zero() - shifted
3896 });
3897
3898 Ok([
3899 [
3900 inverse_linear[0][0].clone(),
3901 inverse_linear[0][1].clone(),
3902 inverse_linear[0][2].clone(),
3903 inverse_translation[0].clone(),
3904 ],
3905 [
3906 inverse_linear[1][0].clone(),
3907 inverse_linear[1][1].clone(),
3908 inverse_linear[1][2].clone(),
3909 inverse_translation[1].clone(),
3910 ],
3911 [
3912 inverse_linear[2][0].clone(),
3913 inverse_linear[2][1].clone(),
3914 inverse_linear[2][2].clone(),
3915 inverse_translation[2].clone(),
3916 ],
3917 [Real::zero(), Real::zero(), Real::zero(), Real::one()],
3918 ])
3919}
3920
3921#[inline]
3922fn invert_matrix4_affine_checked(
3923 matrix: &[[Real; 4]; 4],
3924 linear_is_diagonal: bool,
3925 is_affine_translation: bool,
3926) -> CheckedBlasResult<[[Real; 4]; 4]> {
3927 if linear_is_diagonal {
3928 crate::trace_dispatch!(
3929 "hyperlattice_matrix",
3930 "helper",
3931 "invert-matrix4-checked-affine-linear-diagonal"
3932 );
3933 return invert_matrix4_affine_linear_diagonal_checked(matrix);
3934 }
3935 if is_affine_translation {
3936 crate::trace_dispatch!(
3937 "hyperlattice_matrix",
3938 "helper",
3939 "invert-matrix4-checked-affine-translation"
3940 );
3941 return Ok([
3942 [
3943 matrix[0][0].clone(),
3944 matrix[0][1].clone(),
3945 matrix[0][2].clone(),
3946 Real::zero() - &matrix[0][3],
3947 ],
3948 [
3949 matrix[1][0].clone(),
3950 matrix[1][1].clone(),
3951 matrix[1][2].clone(),
3952 Real::zero() - &matrix[1][3],
3953 ],
3954 [
3955 matrix[2][0].clone(),
3956 matrix[2][1].clone(),
3957 matrix[2][2].clone(),
3958 Real::zero() - &matrix[2][3],
3959 ],
3960 [Real::zero(), Real::zero(), Real::zero(), Real::one()],
3961 ]);
3962 }
3963 invert_matrix4_affine_without_translation_checked(matrix)
3964}
3965
3966#[inline]
3967fn invert_matrix4_affine_without_translation_checked(
3968 matrix: &[[Real; 4]; 4],
3969) -> CheckedBlasResult<[[Real; 4]; 4]> {
3970 let linear = [
3978 [
3979 matrix[0][0].clone(),
3980 matrix[0][1].clone(),
3981 matrix[0][2].clone(),
3982 ],
3983 [
3984 matrix[1][0].clone(),
3985 matrix[1][1].clone(),
3986 matrix[1][2].clone(),
3987 ],
3988 [
3989 matrix[2][0].clone(),
3990 matrix[2][1].clone(),
3991 matrix[2][2].clone(),
3992 ],
3993 ];
3994 let translation = [
3995 matrix[0][3].clone(),
3996 matrix[1][3].clone(),
3997 matrix[2][3].clone(),
3998 ];
3999 let inverse_linear = invert_matrix3_checked(linear)?;
4000
4001 let inverse_translation: [Real; 3] = from_fn(|row| {
4002 let shifted = affine_translation_dot3(
4003 [
4004 &inverse_linear[row][0],
4005 &inverse_linear[row][1],
4006 &inverse_linear[row][2],
4007 ],
4008 [&translation[0], &translation[1], &translation[2]],
4009 );
4010 Real::zero() - shifted
4011 });
4012
4013 Ok([
4014 [
4015 inverse_linear[0][0].clone(),
4016 inverse_linear[0][1].clone(),
4017 inverse_linear[0][2].clone(),
4018 inverse_translation[0].clone(),
4019 ],
4020 [
4021 inverse_linear[1][0].clone(),
4022 inverse_linear[1][1].clone(),
4023 inverse_linear[1][2].clone(),
4024 inverse_translation[1].clone(),
4025 ],
4026 [
4027 inverse_linear[2][0].clone(),
4028 inverse_linear[2][1].clone(),
4029 inverse_linear[2][2].clone(),
4030 inverse_translation[2].clone(),
4031 ],
4032 [Real::zero(), Real::zero(), Real::zero(), Real::one()],
4033 ])
4034}
4035
4036#[inline]
4037fn invert_matrix4_affine_checked_with_abort(
4038 matrix: &[[Real; 4]; 4],
4039 signal: &AbortSignal,
4040 linear_is_diagonal: bool,
4041 is_affine_translation: bool,
4042) -> CheckedBlasResult<[[Real; 4]; 4]> {
4043 if linear_is_diagonal {
4044 crate::trace_dispatch!(
4045 "hyperlattice_matrix",
4046 "helper",
4047 "invert-matrix4-checked-with-abort-affine-linear-diagonal"
4048 );
4049 return invert_matrix4_affine_linear_diagonal_checked_with_abort(matrix, signal);
4050 }
4051 if is_affine_translation {
4052 crate::trace_dispatch!(
4053 "hyperlattice_matrix",
4054 "helper",
4055 "invert-matrix4-checked-affine-translation"
4056 );
4057 return Ok([
4058 [
4059 matrix[0][0].clone(),
4060 matrix[0][1].clone(),
4061 matrix[0][2].clone(),
4062 Real::zero() - &matrix[0][3],
4063 ],
4064 [
4065 matrix[1][0].clone(),
4066 matrix[1][1].clone(),
4067 matrix[1][2].clone(),
4068 Real::zero() - &matrix[1][3],
4069 ],
4070 [
4071 matrix[2][0].clone(),
4072 matrix[2][1].clone(),
4073 matrix[2][2].clone(),
4074 Real::zero() - &matrix[2][3],
4075 ],
4076 [Real::zero(), Real::zero(), Real::zero(), Real::one()],
4077 ]);
4078 }
4079 invert_matrix4_affine_without_translation_checked_with_abort(matrix, signal)
4080}
4081
4082#[inline]
4083fn invert_matrix4_affine_without_translation_checked_with_abort(
4084 matrix: &[[Real; 4]; 4],
4085 signal: &AbortSignal,
4086) -> CheckedBlasResult<[[Real; 4]; 4]> {
4087 let linear = [
4095 [
4096 matrix[0][0].clone(),
4097 matrix[0][1].clone(),
4098 matrix[0][2].clone(),
4099 ],
4100 [
4101 matrix[1][0].clone(),
4102 matrix[1][1].clone(),
4103 matrix[1][2].clone(),
4104 ],
4105 [
4106 matrix[2][0].clone(),
4107 matrix[2][1].clone(),
4108 matrix[2][2].clone(),
4109 ],
4110 ];
4111 let translation = [
4112 matrix[0][3].clone(),
4113 matrix[1][3].clone(),
4114 matrix[2][3].clone(),
4115 ];
4116 let inverse_linear = invert_matrix3_checked_with_abort(linear, signal)?;
4117
4118 let inverse_translation: [Real; 3] = from_fn(|row| {
4119 let shifted = affine_translation_dot3(
4120 [
4121 &inverse_linear[row][0],
4122 &inverse_linear[row][1],
4123 &inverse_linear[row][2],
4124 ],
4125 [&translation[0], &translation[1], &translation[2]],
4126 );
4127 Real::zero() - shifted
4128 });
4129
4130 Ok([
4131 [
4132 inverse_linear[0][0].clone(),
4133 inverse_linear[0][1].clone(),
4134 inverse_linear[0][2].clone(),
4135 inverse_translation[0].clone(),
4136 ],
4137 [
4138 inverse_linear[1][0].clone(),
4139 inverse_linear[1][1].clone(),
4140 inverse_linear[1][2].clone(),
4141 inverse_translation[1].clone(),
4142 ],
4143 [
4144 inverse_linear[2][0].clone(),
4145 inverse_linear[2][1].clone(),
4146 inverse_linear[2][2].clone(),
4147 inverse_translation[2].clone(),
4148 ],
4149 [Real::zero(), Real::zero(), Real::zero(), Real::one()],
4150 ])
4151}
4152
4153#[inline]
4154fn divide_matrix4_by_affine_linear_diagonal(
4155 left: [[Real; 4]; 4],
4156 right: &[[Real; 4]; 4],
4157) -> BlasResult<[[Real; 4]; 4]> {
4158 let inv_a00 = right[0][0].clone().inverse()?;
4163 let inv_a11 = right[1][1].clone().inverse()?;
4164 let inv_a22 = right[2][2].clone().inverse()?;
4165 let inv_tx = Real::zero() - (&right[0][3] * &inv_a00);
4166 let inv_ty = Real::zero() - (&right[1][3] * &inv_a11);
4167 let inv_tz = Real::zero() - (&right[2][3] * &inv_a22);
4168 Ok([
4169 [
4170 {
4171 let row = left[0][0].clone();
4172 let row = row * &inv_a00;
4173 row
4174 },
4175 {
4176 let row = left[0][1].clone();
4177 let row = row * &inv_a11;
4178 row
4179 },
4180 {
4181 let row = left[0][2].clone();
4182 let row = row * &inv_a22;
4183 row
4184 },
4185 {
4186 let x = left[0][0].clone();
4187 let y = left[0][1].clone();
4188 let z = left[0][2].clone();
4189 left[0][3].clone() + (&(x * &inv_tx) + &((y * &inv_ty) + &(z * &inv_tz)))
4190 },
4191 ],
4192 [
4193 {
4194 let row = left[1][0].clone();
4195 let row = row * &inv_a00;
4196 row
4197 },
4198 {
4199 let row = left[1][1].clone();
4200 let row = row * &inv_a11;
4201 row
4202 },
4203 {
4204 let row = left[1][2].clone();
4205 let row = row * &inv_a22;
4206 row
4207 },
4208 {
4209 let x = left[1][0].clone();
4210 let y = left[1][1].clone();
4211 let z = left[1][2].clone();
4212 left[1][3].clone() + (&(x * &inv_tx) + &((y * &inv_ty) + &(z * &inv_tz)))
4213 },
4214 ],
4215 [
4216 {
4217 let row = left[2][0].clone();
4218 let row = row * &inv_a00;
4219 row
4220 },
4221 {
4222 let row = left[2][1].clone();
4223 let row = row * &inv_a11;
4224 row
4225 },
4226 {
4227 let row = left[2][2].clone();
4228 let row = row * &inv_a22;
4229 row
4230 },
4231 {
4232 let x = left[2][0].clone();
4233 let y = left[2][1].clone();
4234 let z = left[2][2].clone();
4235 left[2][3].clone() + (&(x * &inv_tx) + &((y * &inv_ty) + &(z * &inv_tz)))
4236 },
4237 ],
4238 [
4239 {
4240 let row = left[3][0].clone();
4241 let row = row * &inv_a00;
4242 row
4243 },
4244 {
4245 let row = left[3][1].clone();
4246 let row = row * &inv_a11;
4247 row
4248 },
4249 {
4250 let row = left[3][2].clone();
4251 let row = row * &inv_a22;
4252 row
4253 },
4254 {
4255 let x = left[3][0].clone();
4256 let y = left[3][1].clone();
4257 let z = left[3][2].clone();
4258 left[3][3].clone() + (&(x * &inv_tx) + &((y * &inv_ty) + &(z * &inv_tz)))
4259 },
4260 ],
4261 ])
4262}
4263
4264#[inline]
4265fn divide_matrix4_by_affine_linear_diagonal_checked(
4266 left: [[Real; 4]; 4],
4267 right: &[[Real; 4]; 4],
4268) -> CheckedBlasResult<[[Real; 4]; 4]> {
4269 require_known_nonzero(&right[0][0])?;
4270 require_known_nonzero(&right[1][1])?;
4271 require_known_nonzero(&right[2][2])?;
4272 divide_matrix4_by_affine_linear_diagonal(left, right)
4273}
4274
4275#[inline]
4276fn divide_matrix4_by_affine_linear_diagonal_checked_with_abort(
4277 left: [[Real; 4]; 4],
4278 right: &[[Real; 4]; 4],
4279 signal: &AbortSignal,
4280) -> CheckedBlasResult<[[Real; 4]; 4]> {
4281 require_known_nonzero_with_abort(&right[0][0], signal)?;
4282 require_known_nonzero_with_abort(&right[1][1], signal)?;
4283 require_known_nonzero_with_abort(&right[2][2], signal)?;
4284 divide_matrix4_by_affine_linear_diagonal(left, right)
4285}
4286
4287#[inline]
4288fn divide_matrix4_by_affine_linear_diagonal_ref(
4289 left: &[[Real; 4]; 4],
4290 right: &[[Real; 4]; 4],
4291) -> BlasResult<[[Real; 4]; 4]> {
4292 let inv_a00 = right[0][0].clone().inverse()?;
4293 let inv_a11 = right[1][1].clone().inverse()?;
4294 let inv_a22 = right[2][2].clone().inverse()?;
4295 let inv_tx = Real::zero() - (&right[0][3] * &inv_a00);
4296 let inv_ty = Real::zero() - (&right[1][3] * &inv_a11);
4297 let inv_tz = Real::zero() - (&right[2][3] * &inv_a22);
4298 Ok([
4299 [
4300 {
4301 let row = left[0][0].clone();
4302 let row = row * &inv_a00;
4303 row
4304 },
4305 {
4306 let row = left[0][1].clone();
4307 let row = row * &inv_a11;
4308 row
4309 },
4310 {
4311 let row = left[0][2].clone();
4312 let row = row * &inv_a22;
4313 row
4314 },
4315 {
4316 let x = left[0][0].clone();
4317 let y = left[0][1].clone();
4318 let z = left[0][2].clone();
4319 left[0][3].clone() + (&(x * &inv_tx) + &((y * &inv_ty) + &(z * &inv_tz)))
4320 },
4321 ],
4322 [
4323 {
4324 let row = left[1][0].clone();
4325 let row = row * &inv_a00;
4326 row
4327 },
4328 {
4329 let row = left[1][1].clone();
4330 let row = row * &inv_a11;
4331 row
4332 },
4333 {
4334 let row = left[1][2].clone();
4335 let row = row * &inv_a22;
4336 row
4337 },
4338 {
4339 let x = left[1][0].clone();
4340 let y = left[1][1].clone();
4341 let z = left[1][2].clone();
4342 left[1][3].clone() + (&(x * &inv_tx) + &((y * &inv_ty) + &(z * &inv_tz)))
4343 },
4344 ],
4345 [
4346 {
4347 let row = left[2][0].clone();
4348 let row = row * &inv_a00;
4349 row
4350 },
4351 {
4352 let row = left[2][1].clone();
4353 let row = row * &inv_a11;
4354 row
4355 },
4356 {
4357 let row = left[2][2].clone();
4358 let row = row * &inv_a22;
4359 row
4360 },
4361 {
4362 let x = left[2][0].clone();
4363 let y = left[2][1].clone();
4364 let z = left[2][2].clone();
4365 left[2][3].clone() + (&(x * &inv_tx) + &((y * &inv_ty) + &(z * &inv_tz)))
4366 },
4367 ],
4368 [
4369 {
4370 let row = left[3][0].clone();
4371 let row = row * &inv_a00;
4372 row
4373 },
4374 {
4375 let row = left[3][1].clone();
4376 let row = row * &inv_a11;
4377 row
4378 },
4379 {
4380 let row = left[3][2].clone();
4381 let row = row * &inv_a22;
4382 row
4383 },
4384 {
4385 let x = left[3][0].clone();
4386 let y = left[3][1].clone();
4387 let z = left[3][2].clone();
4388 left[3][3].clone() + (&(x * &inv_tx) + &((y * &inv_ty) + &(z * &inv_tz)))
4389 },
4390 ],
4391 ])
4392}
4393
4394fn divide_matrix4_affine_by_affine_linear_diagonal(
4395 left: [[Real; 4]; 4],
4396 right: &[[Real; 4]; 4],
4397) -> BlasResult<[[Real; 4]; 4]> {
4398 divide_matrix4_by_affine_linear_diagonal(left, right)
4401}
4402
4403#[inline]
4404fn divide_matrix4_affine_by_affine_ref_linear_diagonal(
4405 left: &[[Real; 4]; 4],
4406 right: &[[Real; 4]; 4],
4407) -> BlasResult<[[Real; 4]; 4]> {
4408 divide_matrix4_by_affine_linear_diagonal_ref(left, right)
4409}
4410
4411#[inline]
4412fn divide_matrix4_affine_by_affine_linear_diagonal_checked(
4413 left: [[Real; 4]; 4],
4414 right: &[[Real; 4]; 4],
4415) -> CheckedBlasResult<[[Real; 4]; 4]> {
4416 divide_matrix4_by_affine_linear_diagonal_checked(left, right)
4417}
4418
4419#[inline]
4420fn divide_matrix4_affine_by_affine_linear_diagonal_checked_with_abort(
4421 left: [[Real; 4]; 4],
4422 right: &[[Real; 4]; 4],
4423 signal: &AbortSignal,
4424) -> CheckedBlasResult<[[Real; 4]; 4]> {
4425 divide_matrix4_by_affine_linear_diagonal_checked_with_abort(left, right, signal)
4426}
4427
4428#[inline]
4429fn affine_translation_column_update(row: &[Real; 4], inverse_translation: &[Real; 3]) -> Real {
4430 let matrix_terms = [&row[0], &row[1], &row[2]];
4438 let translation_terms = [
4439 &inverse_translation[0],
4440 &inverse_translation[1],
4441 &inverse_translation[2],
4442 ];
4443 row[3].clone() + Real::linear_combination3(matrix_terms, translation_terms)
4444}
4445
4446#[inline]
4447fn affine_translation_column_subtract_update(row: &[Real; 4], translation: [&Real; 3]) -> Real {
4448 crate::trace_dispatch!(
4449 "hyperlattice_matrix",
4450 "helper",
4451 "affine-translation-column-subtract"
4452 );
4453 let shifted = affine_translation_dot3([&row[0], &row[1], &row[2]], translation);
4454 row[3].clone() - shifted
4455}
4456
4457#[inline]
4458fn affine_translation_dot3(coefficients: [&Real; 3], values: [&Real; 3]) -> Real {
4459 if true {
4460 crate::trace_dispatch!(
4461 "hyperlattice_matrix",
4462 "helper",
4463 "affine-translation-dot3-active-exact"
4464 );
4465 Real::active_linear_combination3(coefficients, values)
4466 } else {
4467 (coefficients[0] * values[0]) + &(coefficients[1] * values[1] + coefficients[2] * values[2])
4468 }
4469}
4470
4471#[inline]
4472fn divide_matrix4_by_affine_no_translation(
4473 left: [[Real; 4]; 4],
4474 right: &[[Real; 4]; 4],
4475) -> BlasResult<[[Real; 4]; 4]> {
4476 let inverse = invert_matrix4_affine_without_translation(right)?;
4477 Ok(multiply_arrays4(left, inverse))
4478}
4479
4480#[inline]
4481fn divide_matrix4_affine_by_affine_no_translation(
4482 left: [[Real; 4]; 4],
4483 right: &[[Real; 4]; 4],
4484) -> BlasResult<[[Real; 4]; 4]> {
4485 let left_linear = [
4491 [left[0][0].clone(), left[0][1].clone(), left[0][2].clone()],
4492 [left[1][0].clone(), left[1][1].clone(), left[1][2].clone()],
4493 [left[2][0].clone(), left[2][1].clone(), left[2][2].clone()],
4494 ];
4495 let right_linear = [
4496 [
4497 right[0][0].clone(),
4498 right[0][1].clone(),
4499 right[0][2].clone(),
4500 ],
4501 [
4502 right[1][0].clone(),
4503 right[1][1].clone(),
4504 right[1][2].clone(),
4505 ],
4506 [
4507 right[2][0].clone(),
4508 right[2][1].clone(),
4509 right[2][2].clone(),
4510 ],
4511 ];
4512 let right_translation = [
4513 right[0][3].clone(),
4514 right[1][3].clone(),
4515 right[2][3].clone(),
4516 ];
4517 let right_inverse_linear = invert_matrix3(right_linear)?;
4518 let right_inverse_translation: [Real; 3] = from_fn(|row| {
4519 let shifted = affine_translation_dot3(
4520 [
4521 &right_inverse_linear[row][0],
4522 &right_inverse_linear[row][1],
4523 &right_inverse_linear[row][2],
4524 ],
4525 [
4526 &right_translation[0],
4527 &right_translation[1],
4528 &right_translation[2],
4529 ],
4530 );
4531 Real::zero() - shifted
4532 });
4533 let linear = multiply_arrays3_affine_linear_with_exact_dense_certificate(
4534 left_linear,
4535 right_inverse_linear,
4536 );
4537 let translation: [Real; 3] = from_fn(|row| {
4538 let shifted = affine_translation_dot3(
4539 [&left[row][0], &left[row][1], &left[row][2]],
4540 [
4541 &right_inverse_translation[0],
4542 &right_inverse_translation[1],
4543 &right_inverse_translation[2],
4544 ],
4545 );
4546 left[row][3].clone() + shifted
4547 });
4548 Ok([
4549 [
4550 linear[0][0].clone(),
4551 linear[0][1].clone(),
4552 linear[0][2].clone(),
4553 translation[0].clone(),
4554 ],
4555 [
4556 linear[1][0].clone(),
4557 linear[1][1].clone(),
4558 linear[1][2].clone(),
4559 translation[1].clone(),
4560 ],
4561 [
4562 linear[2][0].clone(),
4563 linear[2][1].clone(),
4564 linear[2][2].clone(),
4565 translation[2].clone(),
4566 ],
4567 [Real::zero(), Real::zero(), Real::zero(), Real::one()],
4568 ])
4569}
4570
4571#[inline]
4572fn divide_matrix4_by_affine_translation(
4573 left: [[Real; 4]; 4],
4574 right: &[[Real; 4]; 4],
4575) -> BlasResult<[[Real; 4]; 4]> {
4576 if true {
4579 let translation = [&right[0][3], &right[1][3], &right[2][3]];
4580 return Ok([
4581 [
4582 left[0][0].clone(),
4583 left[0][1].clone(),
4584 left[0][2].clone(),
4585 affine_translation_column_subtract_update(&left[0], translation),
4586 ],
4587 [
4588 left[1][0].clone(),
4589 left[1][1].clone(),
4590 left[1][2].clone(),
4591 affine_translation_column_subtract_update(&left[1], translation),
4592 ],
4593 [
4594 left[2][0].clone(),
4595 left[2][1].clone(),
4596 left[2][2].clone(),
4597 affine_translation_column_subtract_update(&left[2], translation),
4598 ],
4599 [
4600 left[3][0].clone(),
4601 left[3][1].clone(),
4602 left[3][2].clone(),
4603 affine_translation_column_subtract_update(&left[3], translation),
4604 ],
4605 ]);
4606 }
4607
4608 let inverse_translation = [
4609 Real::zero() - &right[0][3],
4610 Real::zero() - &right[1][3],
4611 Real::zero() - &right[2][3],
4612 ];
4613 Ok([
4614 [
4615 left[0][0].clone(),
4616 left[0][1].clone(),
4617 left[0][2].clone(),
4618 affine_translation_column_update(&left[0], &inverse_translation),
4619 ],
4620 [
4621 left[1][0].clone(),
4622 left[1][1].clone(),
4623 left[1][2].clone(),
4624 affine_translation_column_update(&left[1], &inverse_translation),
4625 ],
4626 [
4627 left[2][0].clone(),
4628 left[2][1].clone(),
4629 left[2][2].clone(),
4630 affine_translation_column_update(&left[2], &inverse_translation),
4631 ],
4632 [
4633 left[3][0].clone(),
4634 left[3][1].clone(),
4635 left[3][2].clone(),
4636 affine_translation_column_update(&left[3], &inverse_translation),
4637 ],
4638 ])
4639}
4640
4641#[inline]
4642fn multiply_arrays3_affine_linear_with_exact_dense_certificate(
4643 left: [[Real; 3]; 3],
4644 right: [[Real; 3]; 3],
4645) -> [[Real; 3]; 3] {
4646 if true
4647 && matrix3_has_dense_multiply_certificate(&left)
4648 && matrix3_has_dense_multiply_certificate(&right)
4649 {
4650 crate::trace_dispatch!(
4651 "hyperlattice_matrix",
4652 "helper",
4653 "multiply3-affine-linear-dense-certified-exact"
4654 );
4655 return multiply_arrays3_dense_ref(&left, &right);
4656 }
4657 multiply_arrays3(left, right)
4658}
4659
4660#[inline]
4661fn divide_matrix4_affine_by_affine_translation(
4662 left: [[Real; 4]; 4],
4663 right: &[[Real; 4]; 4],
4664) -> BlasResult<[[Real; 4]; 4]> {
4665 if true {
4667 let translation = [&right[0][3], &right[1][3], &right[2][3]];
4668 return Ok([
4669 [
4670 left[0][0].clone(),
4671 left[0][1].clone(),
4672 left[0][2].clone(),
4673 affine_translation_column_subtract_update(&left[0], translation),
4674 ],
4675 [
4676 left[1][0].clone(),
4677 left[1][1].clone(),
4678 left[1][2].clone(),
4679 affine_translation_column_subtract_update(&left[1], translation),
4680 ],
4681 [
4682 left[2][0].clone(),
4683 left[2][1].clone(),
4684 left[2][2].clone(),
4685 affine_translation_column_subtract_update(&left[2], translation),
4686 ],
4687 [Real::zero(), Real::zero(), Real::zero(), Real::one()],
4688 ]);
4689 }
4690
4691 let inverse_translation = [
4692 Real::zero() - &right[0][3],
4693 Real::zero() - &right[1][3],
4694 Real::zero() - &right[2][3],
4695 ];
4696 Ok([
4697 [
4698 left[0][0].clone(),
4699 left[0][1].clone(),
4700 left[0][2].clone(),
4701 affine_translation_column_update(&left[0], &inverse_translation),
4702 ],
4703 [
4704 left[1][0].clone(),
4705 left[1][1].clone(),
4706 left[1][2].clone(),
4707 affine_translation_column_update(&left[1], &inverse_translation),
4708 ],
4709 [
4710 left[2][0].clone(),
4711 left[2][1].clone(),
4712 left[2][2].clone(),
4713 affine_translation_column_update(&left[2], &inverse_translation),
4714 ],
4715 [Real::zero(), Real::zero(), Real::zero(), Real::one()],
4716 ])
4717}
4718
4719#[inline]
4720fn divide_matrix4_by_affine_checked(
4721 left: [[Real; 4]; 4],
4722 right: &[[Real; 4]; 4],
4723) -> CheckedBlasResult<[[Real; 4]; 4]> {
4724 divide_matrix4_by_affine_no_translation_checked(left, right)
4725}
4726
4727#[inline]
4728fn divide_matrix4_by_affine_checked_assumed_affine_translation(
4729 left: [[Real; 4]; 4],
4730 right: &[[Real; 4]; 4],
4731) -> CheckedBlasResult<[[Real; 4]; 4]> {
4732 divide_matrix4_by_affine_checked_assuming_affine_translation(left, right)
4734}
4735
4736#[inline]
4737fn divide_matrix4_by_affine_checked_assuming_affine_translation(
4738 left: [[Real; 4]; 4],
4739 right: &[[Real; 4]; 4],
4740) -> CheckedBlasResult<[[Real; 4]; 4]> {
4741 crate::trace_dispatch!(
4744 "hyperlattice_matrix",
4745 "helper",
4746 "right-divide4-checked-by-affine-translation"
4747 );
4748 Ok(divide_matrix4_by_affine_translation(left, right)?)
4749}
4750
4751#[inline]
4752fn divide_matrix4_by_affine_no_translation_checked(
4753 left: [[Real; 4]; 4],
4754 right: &[[Real; 4]; 4],
4755) -> CheckedBlasResult<[[Real; 4]; 4]> {
4756 let inverse = invert_matrix4_affine_without_translation_checked(right)?;
4757 Ok(multiply_arrays4(left, inverse))
4758}
4759
4760#[inline]
4761fn divide_matrix4_affine_by_affine_checked(
4762 left: [[Real; 4]; 4],
4763 right: &[[Real; 4]; 4],
4764) -> CheckedBlasResult<[[Real; 4]; 4]> {
4765 divide_matrix4_affine_by_affine_no_translation_checked(left, right)
4766}
4767
4768#[inline]
4769fn divide_matrix4_affine_by_affine_checked_assumed_affine_translation(
4770 left: [[Real; 4]; 4],
4771 right: &[[Real; 4]; 4],
4772) -> CheckedBlasResult<[[Real; 4]; 4]> {
4773 divide_matrix4_affine_by_affine_checked_assuming_affine_translation(left, right)
4775}
4776
4777fn divide_matrix4_affine_by_affine_checked_assuming_affine_translation(
4778 left: [[Real; 4]; 4],
4779 right: &[[Real; 4]; 4],
4780) -> CheckedBlasResult<[[Real; 4]; 4]> {
4781 crate::trace_dispatch!(
4784 "hyperlattice_matrix",
4785 "helper",
4786 "right-divide4-checked-affine-by-affine-translation"
4787 );
4788 Ok(divide_matrix4_affine_by_affine_translation(left, right)?)
4789}
4790
4791#[inline]
4792fn divide_matrix4_affine_by_affine_no_translation_checked(
4793 left: [[Real; 4]; 4],
4794 right: &[[Real; 4]; 4],
4795) -> CheckedBlasResult<[[Real; 4]; 4]> {
4796 let left_linear = [
4797 [left[0][0].clone(), left[0][1].clone(), left[0][2].clone()],
4798 [left[1][0].clone(), left[1][1].clone(), left[1][2].clone()],
4799 [left[2][0].clone(), left[2][1].clone(), left[2][2].clone()],
4800 ];
4801 let right_linear = [
4802 [
4803 right[0][0].clone(),
4804 right[0][1].clone(),
4805 right[0][2].clone(),
4806 ],
4807 [
4808 right[1][0].clone(),
4809 right[1][1].clone(),
4810 right[1][2].clone(),
4811 ],
4812 [
4813 right[2][0].clone(),
4814 right[2][1].clone(),
4815 right[2][2].clone(),
4816 ],
4817 ];
4818 let right_translation = [
4819 right[0][3].clone(),
4820 right[1][3].clone(),
4821 right[2][3].clone(),
4822 ];
4823 let right_inverse_linear = invert_matrix3_checked(right_linear)?;
4824 let right_inverse_translation: [Real; 3] = from_fn(|row| {
4825 let shifted = affine_translation_dot3(
4826 [
4827 &right_inverse_linear[row][0],
4828 &right_inverse_linear[row][1],
4829 &right_inverse_linear[row][2],
4830 ],
4831 [
4832 &right_translation[0],
4833 &right_translation[1],
4834 &right_translation[2],
4835 ],
4836 );
4837 Real::zero() - shifted
4838 });
4839 let linear = multiply_arrays3_affine_linear_with_exact_dense_certificate(
4840 left_linear,
4841 right_inverse_linear,
4842 );
4843 let translation: [Real; 3] = from_fn(|row| {
4844 let shifted = affine_translation_dot3(
4845 [&left[row][0], &left[row][1], &left[row][2]],
4846 [
4847 &right_inverse_translation[0],
4848 &right_inverse_translation[1],
4849 &right_inverse_translation[2],
4850 ],
4851 );
4852 left[row][3].clone() + shifted
4853 });
4854 Ok([
4855 [
4856 linear[0][0].clone(),
4857 linear[0][1].clone(),
4858 linear[0][2].clone(),
4859 translation[0].clone(),
4860 ],
4861 [
4862 linear[1][0].clone(),
4863 linear[1][1].clone(),
4864 linear[1][2].clone(),
4865 translation[1].clone(),
4866 ],
4867 [
4868 linear[2][0].clone(),
4869 linear[2][1].clone(),
4870 linear[2][2].clone(),
4871 translation[2].clone(),
4872 ],
4873 [Real::zero(), Real::zero(), Real::zero(), Real::one()],
4874 ])
4875}
4876
4877#[inline]
4878fn divide_matrix4_by_affine_checked_with_abort(
4879 left: [[Real; 4]; 4],
4880 right: &[[Real; 4]; 4],
4881 signal: &AbortSignal,
4882) -> CheckedBlasResult<[[Real; 4]; 4]> {
4883 divide_matrix4_by_affine_no_translation_checked_with_abort(left, right, signal)
4884}
4885
4886#[inline]
4887fn divide_matrix4_by_affine_checked_with_abort_assumed_affine_translation(
4888 left: [[Real; 4]; 4],
4889 right: &[[Real; 4]; 4],
4890 signal: &AbortSignal,
4891) -> CheckedBlasResult<[[Real; 4]; 4]> {
4892 divide_matrix4_by_affine_checked_with_abort_assuming_affine_translation(left, right, signal)
4894}
4895
4896#[inline]
4897fn divide_matrix4_by_affine_checked_with_abort_assuming_affine_translation(
4898 left: [[Real; 4]; 4],
4899 right: &[[Real; 4]; 4],
4900 _signal: &AbortSignal,
4901) -> CheckedBlasResult<[[Real; 4]; 4]> {
4902 crate::trace_dispatch!(
4905 "hyperlattice_matrix",
4906 "helper",
4907 "right-divide4-checked-abort-by-affine-translation"
4908 );
4909 Ok(divide_matrix4_by_affine_translation(left, right)?)
4910}
4911
4912#[inline]
4913fn divide_matrix4_by_affine_no_translation_checked_with_abort(
4914 left: [[Real; 4]; 4],
4915 right: &[[Real; 4]; 4],
4916 signal: &AbortSignal,
4917) -> CheckedBlasResult<[[Real; 4]; 4]> {
4918 let inverse = invert_matrix4_affine_without_translation_checked_with_abort(right, signal)?;
4919 Ok(multiply_arrays4(left, inverse))
4920}
4921
4922#[inline]
4923fn divide_matrix4_affine_by_affine_checked_with_abort(
4924 left: [[Real; 4]; 4],
4925 right: &[[Real; 4]; 4],
4926 signal: &AbortSignal,
4927) -> CheckedBlasResult<[[Real; 4]; 4]> {
4928 divide_matrix4_affine_by_affine_no_translation_checked_with_abort(left, right, signal)
4929}
4930
4931#[inline]
4932fn divide_matrix4_affine_by_affine_checked_with_abort_assumed_affine_translation(
4933 left: [[Real; 4]; 4],
4934 right: &[[Real; 4]; 4],
4935 signal: &AbortSignal,
4936) -> CheckedBlasResult<[[Real; 4]; 4]> {
4937 divide_matrix4_affine_by_affine_checked_with_abort_assuming_affine_translation(
4939 left, right, signal,
4940 )
4941}
4942
4943#[inline]
4944fn divide_matrix4_affine_by_affine_checked_with_abort_assuming_affine_translation(
4945 left: [[Real; 4]; 4],
4946 right: &[[Real; 4]; 4],
4947 _signal: &AbortSignal,
4948) -> CheckedBlasResult<[[Real; 4]; 4]> {
4949 crate::trace_dispatch!(
4952 "hyperlattice_matrix",
4953 "helper",
4954 "right-divide4-checked-abort-affine-by-affine-translation"
4955 );
4956 Ok(divide_matrix4_affine_by_affine_translation(left, right)?)
4957}
4958
4959#[inline]
4960fn divide_matrix4_affine_by_affine_no_translation_checked_with_abort(
4961 left: [[Real; 4]; 4],
4962 right: &[[Real; 4]; 4],
4963 signal: &AbortSignal,
4964) -> CheckedBlasResult<[[Real; 4]; 4]> {
4965 let left_linear = [
4966 [left[0][0].clone(), left[0][1].clone(), left[0][2].clone()],
4967 [left[1][0].clone(), left[1][1].clone(), left[1][2].clone()],
4968 [left[2][0].clone(), left[2][1].clone(), left[2][2].clone()],
4969 ];
4970 let right_linear = [
4971 [
4972 right[0][0].clone(),
4973 right[0][1].clone(),
4974 right[0][2].clone(),
4975 ],
4976 [
4977 right[1][0].clone(),
4978 right[1][1].clone(),
4979 right[1][2].clone(),
4980 ],
4981 [
4982 right[2][0].clone(),
4983 right[2][1].clone(),
4984 right[2][2].clone(),
4985 ],
4986 ];
4987 let right_translation = [
4988 right[0][3].clone(),
4989 right[1][3].clone(),
4990 right[2][3].clone(),
4991 ];
4992 let right_inverse_linear = invert_matrix3_checked_with_abort(right_linear, signal)?;
4993 let right_inverse_translation: [Real; 3] = from_fn(|row| {
4994 let shifted = affine_translation_dot3(
4995 [
4996 &right_inverse_linear[row][0],
4997 &right_inverse_linear[row][1],
4998 &right_inverse_linear[row][2],
4999 ],
5000 [
5001 &right_translation[0],
5002 &right_translation[1],
5003 &right_translation[2],
5004 ],
5005 );
5006 Real::zero() - shifted
5007 });
5008 let linear = multiply_arrays3_affine_linear_with_exact_dense_certificate(
5009 left_linear,
5010 right_inverse_linear,
5011 );
5012 let translation: [Real; 3] = from_fn(|row| {
5013 let shifted = affine_translation_dot3(
5014 [&left[row][0], &left[row][1], &left[row][2]],
5015 [
5016 &right_inverse_translation[0],
5017 &right_inverse_translation[1],
5018 &right_inverse_translation[2],
5019 ],
5020 );
5021 left[row][3].clone() + shifted
5022 });
5023 Ok([
5024 [
5025 linear[0][0].clone(),
5026 linear[0][1].clone(),
5027 linear[0][2].clone(),
5028 translation[0].clone(),
5029 ],
5030 [
5031 linear[1][0].clone(),
5032 linear[1][1].clone(),
5033 linear[1][2].clone(),
5034 translation[1].clone(),
5035 ],
5036 [
5037 linear[2][0].clone(),
5038 linear[2][1].clone(),
5039 linear[2][2].clone(),
5040 translation[2].clone(),
5041 ],
5042 [Real::zero(), Real::zero(), Real::zero(), Real::one()],
5043 ])
5044}
5045
5046fn divide_matrix4_by_affine_ref_assumed_affine_translation(
5047 left: &[[Real; 4]; 4],
5048 right: &[[Real; 4]; 4],
5049) -> BlasResult<[[Real; 4]; 4]> {
5050 divide_matrix4_by_affine_ref_translation(left, right)
5052}
5053
5054fn divide_matrix4_by_affine_ref_translation(
5055 left: &[[Real; 4]; 4],
5056 right: &[[Real; 4]; 4],
5057) -> BlasResult<[[Real; 4]; 4]> {
5058 crate::trace_dispatch!(
5063 "hyperlattice_matrix",
5064 "helper",
5065 "right-divide4-ref-by-affine-translation"
5066 );
5067 let inverse_translation = [
5068 Real::zero() - &right[0][3],
5069 Real::zero() - &right[1][3],
5070 Real::zero() - &right[2][3],
5071 ];
5072 Ok([
5073 [
5074 left[0][0].clone(),
5075 left[0][1].clone(),
5076 left[0][2].clone(),
5077 affine_translation_column_update(&left[0], &inverse_translation),
5078 ],
5079 [
5080 left[1][0].clone(),
5081 left[1][1].clone(),
5082 left[1][2].clone(),
5083 affine_translation_column_update(&left[1], &inverse_translation),
5084 ],
5085 [
5086 left[2][0].clone(),
5087 left[2][1].clone(),
5088 left[2][2].clone(),
5089 affine_translation_column_update(&left[2], &inverse_translation),
5090 ],
5091 [
5092 left[3][0].clone(),
5093 left[3][1].clone(),
5094 left[3][2].clone(),
5095 affine_translation_column_update(&left[3], &inverse_translation),
5096 ],
5097 ])
5098}
5099
5100#[inline]
5101fn divide_matrix4_by_affine_ref_no_translation(
5102 left: &[[Real; 4]; 4],
5103 right: &[[Real; 4]; 4],
5104) -> BlasResult<[[Real; 4]; 4]> {
5105 let inverse = invert_matrix4_affine_without_translation(right)?;
5106 Ok(multiply_arrays4_ref(left, &inverse))
5107}
5108
5109#[inline]
5110fn divide_matrix4_affine_by_affine_ref_no_translation(
5111 left: &[[Real; 4]; 4],
5112 right: &[[Real; 4]; 4],
5113) -> BlasResult<[[Real; 4]; 4]> {
5114 let left_linear = [
5118 [left[0][0].clone(), left[0][1].clone(), left[0][2].clone()],
5119 [left[1][0].clone(), left[1][1].clone(), left[1][2].clone()],
5120 [left[2][0].clone(), left[2][1].clone(), left[2][2].clone()],
5121 ];
5122 let right_linear = [
5123 [
5124 right[0][0].clone(),
5125 right[0][1].clone(),
5126 right[0][2].clone(),
5127 ],
5128 [
5129 right[1][0].clone(),
5130 right[1][1].clone(),
5131 right[1][2].clone(),
5132 ],
5133 [
5134 right[2][0].clone(),
5135 right[2][1].clone(),
5136 right[2][2].clone(),
5137 ],
5138 ];
5139 let right_translation = [
5140 right[0][3].clone(),
5141 right[1][3].clone(),
5142 right[2][3].clone(),
5143 ];
5144 let right_inverse_linear = invert_matrix3(right_linear)?;
5145 let right_inverse_translation: [Real; 3] = from_fn(|row| {
5146 let shifted = affine_translation_dot3(
5147 [
5148 &right_inverse_linear[row][0],
5149 &right_inverse_linear[row][1],
5150 &right_inverse_linear[row][2],
5151 ],
5152 [
5153 &right_translation[0],
5154 &right_translation[1],
5155 &right_translation[2],
5156 ],
5157 );
5158 Real::zero() - shifted
5159 });
5160 let linear = multiply_arrays3_affine_linear_with_exact_dense_certificate(
5161 left_linear,
5162 right_inverse_linear,
5163 );
5164 let translation: [Real; 3] = from_fn(|row| {
5165 let shifted = affine_translation_dot3(
5166 [&left[row][0], &left[row][1], &left[row][2]],
5167 [
5168 &right_inverse_translation[0],
5169 &right_inverse_translation[1],
5170 &right_inverse_translation[2],
5171 ],
5172 );
5173 left[row][3].clone() + shifted
5174 });
5175 Ok([
5176 [
5177 linear[0][0].clone(),
5178 linear[0][1].clone(),
5179 linear[0][2].clone(),
5180 translation[0].clone(),
5181 ],
5182 [
5183 linear[1][0].clone(),
5184 linear[1][1].clone(),
5185 linear[1][2].clone(),
5186 translation[1].clone(),
5187 ],
5188 [
5189 linear[2][0].clone(),
5190 linear[2][1].clone(),
5191 linear[2][2].clone(),
5192 translation[2].clone(),
5193 ],
5194 [Real::zero(), Real::zero(), Real::zero(), Real::one()],
5195 ])
5196}
5197
5198#[inline]
5199fn divide_matrix4_affine_by_affine_ref_translation(
5200 left: &[[Real; 4]; 4],
5201 right: &[[Real; 4]; 4],
5202) -> BlasResult<[[Real; 4]; 4]> {
5203 let inverse_translation = [
5206 Real::zero() - &right[0][3],
5207 Real::zero() - &right[1][3],
5208 Real::zero() - &right[2][3],
5209 ];
5210 Ok([
5211 [
5212 left[0][0].clone(),
5213 left[0][1].clone(),
5214 left[0][2].clone(),
5215 affine_translation_column_update(&left[0], &inverse_translation),
5216 ],
5217 [
5218 left[1][0].clone(),
5219 left[1][1].clone(),
5220 left[1][2].clone(),
5221 affine_translation_column_update(&left[1], &inverse_translation),
5222 ],
5223 [
5224 left[2][0].clone(),
5225 left[2][1].clone(),
5226 left[2][2].clone(),
5227 affine_translation_column_update(&left[2], &inverse_translation),
5228 ],
5229 [Real::zero(), Real::zero(), Real::zero(), Real::one()],
5230 ])
5231}
5232
5233fn invert_matrix3_by_diagonal(matrix: &[[Real; 3]; 3]) -> BlasResult<[[Real; 3]; 3]> {
5234 if matrix[0][0] == matrix[1][1] && matrix[0][0] == matrix[2][2] {
5238 crate::trace_dispatch!(
5239 "hyperlattice_matrix",
5240 "helper",
5241 "invert-matrix3-diagonal-uniform-scale"
5242 );
5243 let inv = matrix[0][0].clone().inverse()?;
5244 return Ok([
5245 [inv.clone(), Real::zero(), Real::zero()],
5246 [Real::zero(), inv.clone(), Real::zero()],
5247 [Real::zero(), Real::zero(), inv],
5248 ]);
5249 }
5250 let inv00 = matrix[0][0].clone().inverse()?;
5251 let inv11 = matrix[1][1].clone().inverse()?;
5252 let inv22 = matrix[2][2].clone().inverse()?;
5253 if true {
5254 Ok([
5261 [inv00, Real::zero(), Real::zero()],
5262 [Real::zero(), inv11, Real::zero()],
5263 [Real::zero(), Real::zero(), inv22],
5264 ])
5265 } else {
5266 Ok(from_fn(|row| {
5267 from_fn(|col| {
5268 if row == 0 && col == 0 {
5269 inv00.clone()
5270 } else if row == 1 && col == 1 {
5271 inv11.clone()
5272 } else if row == 2 && col == 2 {
5273 inv22.clone()
5274 } else {
5275 Real::zero()
5276 }
5277 })
5278 }))
5279 }
5280}
5281
5282#[inline]
5283fn invert_matrix3_by_diagonal_checked(
5284 matrix: &[[Real; 3]; 3],
5285) -> CheckedBlasResult<[[Real; 3]; 3]> {
5286 require_known_nonzero(&matrix[0][0])?;
5287 require_known_nonzero(&matrix[1][1])?;
5288 require_known_nonzero(&matrix[2][2])?;
5289 invert_matrix3_by_diagonal(matrix)
5290}
5291
5292#[inline]
5293fn invert_matrix3_by_diagonal_checked_with_abort(
5294 matrix: &[[Real; 3]; 3],
5295 signal: &AbortSignal,
5296) -> CheckedBlasResult<[[Real; 3]; 3]> {
5297 require_known_nonzero_with_abort(&matrix[0][0], signal)?;
5298 require_known_nonzero_with_abort(&matrix[1][1], signal)?;
5299 require_known_nonzero_with_abort(&matrix[2][2], signal)?;
5300 invert_matrix3_by_diagonal(matrix)
5301}
5302
5303#[inline]
5304fn invert_matrix3_upper_triangular(matrix: &[[Real; 3]; 3]) -> BlasResult<[[Real; 3]; 3]> {
5305 let inv_a00 = matrix[0][0].clone().inverse()?;
5310 let inv_a11 = matrix[1][1].clone().inverse()?;
5311 let inv_a22 = matrix[2][2].clone().inverse()?;
5312
5313 let inv_a01 = scale_by_shared_factor(Real::zero() - &matrix[0][1], &inv_a11);
5314 let inv_a01 = scale_by_shared_factor(inv_a01, &inv_a00);
5315 let inv_a12 = scale_by_shared_factor(Real::zero() - &matrix[1][2], &inv_a11);
5316 let inv_a12 = scale_by_shared_factor(inv_a12, &inv_a22);
5317 let inv_a02 = Real::zero() - ((&matrix[0][1] * &inv_a12) + (&matrix[0][2] * &inv_a22));
5318 let inv_a02 = scale_by_shared_factor(inv_a02, &inv_a00);
5319
5320 Ok([
5321 [inv_a00, inv_a01, inv_a02],
5322 [Real::zero(), inv_a11, inv_a12],
5323 [Real::zero(), Real::zero(), inv_a22],
5324 ])
5325}
5326
5327#[inline]
5328fn invert_matrix3_upper_triangular_checked(
5329 matrix: &[[Real; 3]; 3],
5330) -> CheckedBlasResult<[[Real; 3]; 3]> {
5331 require_known_nonzero(&matrix[0][0])?;
5332 require_known_nonzero(&matrix[1][1])?;
5333 require_known_nonzero(&matrix[2][2])?;
5334 invert_matrix3_upper_triangular(matrix)
5335}
5336
5337#[inline]
5338fn invert_matrix3_upper_triangular_checked_with_abort(
5339 matrix: &[[Real; 3]; 3],
5340 signal: &AbortSignal,
5341) -> CheckedBlasResult<[[Real; 3]; 3]> {
5342 require_known_nonzero_with_abort(&matrix[0][0], signal)?;
5343 require_known_nonzero_with_abort(&matrix[1][1], signal)?;
5344 require_known_nonzero_with_abort(&matrix[2][2], signal)?;
5345 invert_matrix3_upper_triangular(matrix)
5346}
5347
5348#[inline]
5349fn invert_matrix3_lower_triangular(matrix: &[[Real; 3]; 3]) -> BlasResult<[[Real; 3]; 3]> {
5350 let inv_a00 = matrix[0][0].clone().inverse()?;
5354 let inv_a11 = matrix[1][1].clone().inverse()?;
5355 let inv_a22 = matrix[2][2].clone().inverse()?;
5356
5357 let inv_a10 = scale_by_shared_factor(Real::zero() - &matrix[1][0], &inv_a00);
5358 let inv_a10 = scale_by_shared_factor(inv_a10, &inv_a11);
5359 let inv_a20 = Real::zero() - ((&matrix[2][0] * &inv_a00) + (&matrix[2][1] * &inv_a10));
5360 let inv_a20 = scale_by_shared_factor(inv_a20, &inv_a22);
5361 let inv_a21 = scale_by_shared_factor(Real::zero() - &matrix[2][1], &inv_a11);
5362 let inv_a21 = scale_by_shared_factor(inv_a21, &inv_a22);
5363
5364 Ok([
5365 [inv_a00, Real::zero(), Real::zero()],
5366 [inv_a10, inv_a11, Real::zero()],
5367 [inv_a20, inv_a21, inv_a22],
5368 ])
5369}
5370
5371#[inline]
5372fn invert_matrix3_lower_triangular_checked(
5373 matrix: &[[Real; 3]; 3],
5374) -> CheckedBlasResult<[[Real; 3]; 3]> {
5375 require_known_nonzero(&matrix[0][0])?;
5376 require_known_nonzero(&matrix[1][1])?;
5377 require_known_nonzero(&matrix[2][2])?;
5378 invert_matrix3_lower_triangular(matrix)
5379}
5380
5381#[inline]
5382fn invert_matrix3_lower_triangular_checked_with_abort(
5383 matrix: &[[Real; 3]; 3],
5384 signal: &AbortSignal,
5385) -> CheckedBlasResult<[[Real; 3]; 3]> {
5386 require_known_nonzero_with_abort(&matrix[0][0], signal)?;
5387 require_known_nonzero_with_abort(&matrix[1][1], signal)?;
5388 require_known_nonzero_with_abort(&matrix[2][2], signal)?;
5389 invert_matrix3_lower_triangular(matrix)
5390}
5391
5392#[inline]
5393fn invert_matrix3_affine(
5394 matrix: &[[Real; 3]; 3],
5395 linear_is_diagonal: bool,
5396) -> BlasResult<[[Real; 3]; 3]> {
5397 if linear_is_diagonal {
5406 crate::trace_dispatch!(
5407 "hyperlattice_matrix",
5408 "helper",
5409 "invert-matrix3-affine-linear-diagonal"
5410 );
5411 return invert_matrix3_affine_linear_diagonal(matrix);
5412 }
5413
5414 let a = matrix[0][0].clone();
5415 let b = matrix[0][1].clone();
5416 let c = matrix[1][0].clone();
5417 let d = matrix[1][1].clone();
5418 let tx = matrix[0][2].clone();
5419 let ty = matrix[1][2].clone();
5420
5421 let det = (&a * &d) - (&b * &c);
5422 let inv_det = det.clone().inverse()?;
5423 let inv_a00 = scale_by_shared_factor(d, &inv_det);
5424 let inv_a01 = scale_by_shared_factor(Real::zero() - &b, &inv_det);
5425 let inv_a10 = scale_by_shared_factor(Real::zero() - &c, &inv_det);
5426 let inv_a11 = scale_by_shared_factor(a, &inv_det);
5427 let inv_tx = Real::zero() - ((&inv_a00 * &tx) + (&inv_a01 * &ty));
5428 let inv_ty = Real::zero() - ((&inv_a10 * &tx) + (&inv_a11 * &ty));
5429
5430 Ok([
5431 [inv_a00, inv_a01, inv_tx],
5432 [inv_a10, inv_a11, inv_ty],
5433 [Real::zero(), Real::zero(), Real::one()],
5434 ])
5435}
5436
5437#[inline]
5438fn invert_matrix3_affine_linear_diagonal(matrix: &[[Real; 3]; 3]) -> BlasResult<[[Real; 3]; 3]> {
5439 let inv_a00 = matrix[0][0].clone().inverse()?;
5444 let inv_a11 = matrix[1][1].clone().inverse()?;
5445 let inv_tx = Real::zero() - (matrix[0][2].clone() * &inv_a00);
5446 let inv_ty = Real::zero() - (matrix[1][2].clone() * &inv_a11);
5447
5448 Ok([
5449 [inv_a00, Real::zero(), inv_tx],
5450 [Real::zero(), inv_a11, inv_ty],
5451 [Real::zero(), Real::zero(), Real::one()],
5452 ])
5453}
5454
5455#[inline]
5456fn invert_matrix3_affine_linear_diagonal_checked(
5457 matrix: &[[Real; 3]; 3],
5458) -> CheckedBlasResult<[[Real; 3]; 3]> {
5459 require_known_nonzero(&matrix[0][0])?;
5460 require_known_nonzero(&matrix[1][1])?;
5461
5462 let inv_a00 = matrix[0][0].clone().inverse()?;
5463 let inv_a11 = matrix[1][1].clone().inverse()?;
5464 let inv_tx = Real::zero() - (matrix[0][2].clone() * &inv_a00);
5465 let inv_ty = Real::zero() - (matrix[1][2].clone() * &inv_a11);
5466
5467 Ok([
5468 [inv_a00, Real::zero(), inv_tx],
5469 [Real::zero(), inv_a11, inv_ty],
5470 [Real::zero(), Real::zero(), Real::one()],
5471 ])
5472}
5473
5474#[inline]
5475fn invert_matrix3_affine_linear_diagonal_checked_with_abort(
5476 matrix: &[[Real; 3]; 3],
5477 signal: &AbortSignal,
5478) -> CheckedBlasResult<[[Real; 3]; 3]> {
5479 let a00 = with_abort(matrix[0][0].clone(), signal);
5480 let a11 = with_abort(matrix[1][1].clone(), signal);
5481 let inv_a00 = a00;
5482 let inv_a11 = a11;
5483 require_known_nonzero_with_abort(&inv_a00, signal)?;
5484 require_known_nonzero_with_abort(&inv_a11, signal)?;
5485 let inv_a00 = inv_a00.inverse()?;
5486 let inv_a11 = inv_a11.inverse()?;
5487 let inv_tx = Real::zero() - (matrix[0][2].clone() * &inv_a00);
5488 let inv_ty = Real::zero() - (matrix[1][2].clone() * &inv_a11);
5489
5490 Ok([
5491 [inv_a00, Real::zero(), inv_tx],
5492 [Real::zero(), inv_a11, inv_ty],
5493 [Real::zero(), Real::zero(), Real::one()],
5494 ])
5495}
5496
5497#[inline]
5498fn divide_matrix3_by_affine_linear_diagonal(
5499 left: [[Real; 3]; 3],
5500 right: &[[Real; 3]; 3],
5501) -> BlasResult<[[Real; 3]; 3]> {
5502 let inv_a00 = right[0][0].clone().inverse()?;
5509 let inv_a11 = right[1][1].clone().inverse()?;
5510 let inv_tx = Real::zero() - (&right[0][2] * &inv_a00);
5511 let inv_ty = Real::zero() - (&right[1][2] * &inv_a11);
5512
5513 Ok([
5514 [
5515 {
5516 let row = left[0][0].clone();
5517 let row = row * &inv_a00;
5518 row
5519 },
5520 {
5521 let row = left[0][1].clone();
5522 let row = row * &inv_a11;
5523 row
5524 },
5525 {
5526 let x = left[0][0].clone();
5527 let y = left[0][1].clone();
5528 left[0][2].clone() + &(x * &inv_tx) + &(y * &inv_ty)
5529 },
5530 ],
5531 [
5532 {
5533 let row = left[1][0].clone();
5534 let row = row * &inv_a00;
5535 row
5536 },
5537 {
5538 let row = left[1][1].clone();
5539 let row = row * &inv_a11;
5540 row
5541 },
5542 {
5543 let x = left[1][0].clone();
5544 let y = left[1][1].clone();
5545 left[1][2].clone() + &(x * &inv_tx) + &(y * &inv_ty)
5546 },
5547 ],
5548 [
5549 {
5550 let row = left[2][0].clone();
5551 let row = row * &inv_a00;
5552 row
5553 },
5554 {
5555 let row = left[2][1].clone();
5556 let row = row * &inv_a11;
5557 row
5558 },
5559 {
5560 let x = left[2][0].clone();
5561 let y = left[2][1].clone();
5562 left[2][2].clone() + &(x * &inv_tx) + &(y * &inv_ty)
5563 },
5564 ],
5565 ])
5566}
5567
5568#[inline]
5569fn divide_matrix3_by_affine_linear_diagonal_checked(
5570 left: [[Real; 3]; 3],
5571 right: &[[Real; 3]; 3],
5572) -> CheckedBlasResult<[[Real; 3]; 3]> {
5573 require_known_nonzero(&right[0][0])?;
5574 require_known_nonzero(&right[1][1])?;
5575 divide_matrix3_by_affine_linear_diagonal(left, right)
5576}
5577
5578#[inline]
5579fn divide_matrix3_by_affine_linear_diagonal_checked_with_abort(
5580 left: [[Real; 3]; 3],
5581 right: &[[Real; 3]; 3],
5582 signal: &AbortSignal,
5583) -> CheckedBlasResult<[[Real; 3]; 3]> {
5584 require_known_nonzero_with_abort(&right[0][0], signal)?;
5585 require_known_nonzero_with_abort(&right[1][1], signal)?;
5586 divide_matrix3_by_affine_linear_diagonal(left, right)
5587}
5588
5589#[inline]
5590fn divide_matrix3_by_affine_ref_linear_diagonal(
5591 left: &[[Real; 3]; 3],
5592 right: &[[Real; 3]; 3],
5593) -> BlasResult<[[Real; 3]; 3]> {
5594 let inv_a00 = right[0][0].clone().inverse()?;
5595 let inv_a11 = right[1][1].clone().inverse()?;
5596 let inv_tx = Real::zero() - (&right[0][2] * &inv_a00);
5597 let inv_ty = Real::zero() - (&right[1][2] * &inv_a11);
5598
5599 Ok([
5600 [
5601 {
5602 let row = left[0][0].clone();
5603 let row = row * &inv_a00;
5604 row
5605 },
5606 {
5607 let row = left[0][1].clone();
5608 let row = row * &inv_a11;
5609 row
5610 },
5611 {
5612 let x = left[0][0].clone();
5613 let y = left[0][1].clone();
5614 left[0][2].clone() + &(x * &inv_tx) + &(y * &inv_ty)
5615 },
5616 ],
5617 [
5618 {
5619 let row = left[1][0].clone();
5620 let row = row * &inv_a00;
5621 row
5622 },
5623 {
5624 let row = left[1][1].clone();
5625 let row = row * &inv_a11;
5626 row
5627 },
5628 {
5629 let x = left[1][0].clone();
5630 let y = left[1][1].clone();
5631 left[1][2].clone() + &(x * &inv_tx) + &(y * &inv_ty)
5632 },
5633 ],
5634 [
5635 {
5636 let row = left[2][0].clone();
5637 let row = row * &inv_a00;
5638 row
5639 },
5640 {
5641 let row = left[2][1].clone();
5642 let row = row * &inv_a11;
5643 row
5644 },
5645 {
5646 let x = left[2][0].clone();
5647 let y = left[2][1].clone();
5648 left[2][2].clone() + &(x * &inv_tx) + &(y * &inv_ty)
5649 },
5650 ],
5651 ])
5652}
5653
5654#[inline]
5655fn divide_matrix3_affine_by_affine_linear_diagonal(
5656 left: [[Real; 3]; 3],
5657 right: &[[Real; 3]; 3],
5658) -> BlasResult<[[Real; 3]; 3]> {
5659 divide_matrix3_by_affine_linear_diagonal(left, right)
5660}
5661
5662#[inline]
5663fn divide_matrix3_affine_by_affine_ref_linear_diagonal(
5664 left: &[[Real; 3]; 3],
5665 right: &[[Real; 3]; 3],
5666) -> BlasResult<[[Real; 3]; 3]> {
5667 divide_matrix3_by_affine_ref_linear_diagonal(left, right)
5668}
5669
5670#[inline]
5671fn divide_matrix3_affine_by_affine_linear_diagonal_checked(
5672 left: [[Real; 3]; 3],
5673 right: &[[Real; 3]; 3],
5674) -> CheckedBlasResult<[[Real; 3]; 3]> {
5675 divide_matrix3_by_affine_linear_diagonal_checked(left, right)
5676}
5677
5678#[inline]
5679fn divide_matrix3_affine_by_affine_linear_diagonal_checked_with_abort(
5680 left: [[Real; 3]; 3],
5681 right: &[[Real; 3]; 3],
5682 signal: &AbortSignal,
5683) -> CheckedBlasResult<[[Real; 3]; 3]> {
5684 divide_matrix3_by_affine_linear_diagonal_checked_with_abort(left, right, signal)
5685}
5686
5687#[inline]
5688fn invert_matrix3_affine_checked(
5689 matrix: &[[Real; 3]; 3],
5690 linear_is_diagonal: bool,
5691) -> CheckedBlasResult<[[Real; 3]; 3]> {
5692 if linear_is_diagonal {
5693 crate::trace_dispatch!(
5694 "hyperlattice_matrix",
5695 "helper",
5696 "invert-matrix3-checked-affine-linear-diagonal"
5697 );
5698 return invert_matrix3_affine_linear_diagonal_checked(matrix);
5699 }
5700
5701 let a = matrix[0][0].clone();
5702 let b = matrix[0][1].clone();
5703 let c = matrix[1][0].clone();
5704 let d = matrix[1][1].clone();
5705 let tx = matrix[0][2].clone();
5706 let ty = matrix[1][2].clone();
5707
5708 let det = (&a * &d) - (&b * &c);
5709 require_known_nonzero(&det)?;
5710 let inv_det = det.inverse()?;
5711 let inv_a00 = scale_by_shared_factor(d, &inv_det);
5712 let inv_a01 = scale_by_shared_factor(Real::zero() - &b, &inv_det);
5713 let inv_a10 = scale_by_shared_factor(Real::zero() - &c, &inv_det);
5714 let inv_a11 = scale_by_shared_factor(a, &inv_det);
5715 let inv_tx = Real::zero() - ((&inv_a00 * &tx) + (&inv_a01 * &ty));
5716 let inv_ty = Real::zero() - ((&inv_a10 * &tx) + (&inv_a11 * &ty));
5717
5718 Ok([
5719 [inv_a00, inv_a01, inv_tx],
5720 [inv_a10, inv_a11, inv_ty],
5721 [Real::zero(), Real::zero(), Real::one()],
5722 ])
5723}
5724
5725#[inline]
5726fn invert_matrix3_affine_checked_with_abort(
5727 matrix: &[[Real; 3]; 3],
5728 signal: &AbortSignal,
5729 linear_is_diagonal: bool,
5730) -> CheckedBlasResult<[[Real; 3]; 3]> {
5731 if linear_is_diagonal {
5732 crate::trace_dispatch!(
5733 "hyperlattice_matrix",
5734 "helper",
5735 "invert-matrix3-checked-with-abort-affine-linear-diagonal"
5736 );
5737 return invert_matrix3_affine_linear_diagonal_checked_with_abort(matrix, signal);
5738 }
5739
5740 let a = matrix[0][0].clone();
5741 let b = matrix[0][1].clone();
5742 let c = matrix[1][0].clone();
5743 let d = matrix[1][1].clone();
5744 let tx = matrix[0][2].clone();
5745 let ty = matrix[1][2].clone();
5746
5747 let det = with_abort((&a * &d) - (&b * &c), signal);
5748 require_known_nonzero(&det)?;
5749 let inv_det = det.inverse()?;
5750 let inv_a00 = scale_by_shared_factor(d, &inv_det);
5751 let inv_a01 = scale_by_shared_factor(Real::zero() - &b, &inv_det);
5752 let inv_a10 = scale_by_shared_factor(Real::zero() - &c, &inv_det);
5753 let inv_a11 = scale_by_shared_factor(a, &inv_det);
5754 let inv_tx = Real::zero() - ((&inv_a00 * &tx) + (&inv_a01 * &ty));
5755 let inv_ty = Real::zero() - ((&inv_a10 * &tx) + (&inv_a11 * &ty));
5756
5757 Ok([
5758 [inv_a00, inv_a01, inv_tx],
5759 [inv_a10, inv_a11, inv_ty],
5760 [Real::zero(), Real::zero(), Real::one()],
5761 ])
5762}
5763
5764#[inline]
5765fn invert_matrix4_by_diagonal(matrix: &[[Real; 4]; 4]) -> BlasResult<[[Real; 4]; 4]> {
5766 if matrix[0][0] == matrix[1][1] && matrix[0][0] == matrix[2][2] && matrix[0][0] == matrix[3][3]
5769 {
5770 crate::trace_dispatch!(
5771 "hyperlattice_matrix",
5772 "helper",
5773 "invert-matrix4-diagonal-uniform-scale"
5774 );
5775 let inv = matrix[0][0].clone().inverse()?;
5776 return Ok([
5777 [inv.clone(), Real::zero(), Real::zero(), Real::zero()],
5778 [Real::zero(), inv.clone(), Real::zero(), Real::zero()],
5779 [Real::zero(), Real::zero(), inv.clone(), Real::zero()],
5780 [Real::zero(), Real::zero(), Real::zero(), inv],
5781 ]);
5782 }
5783 let inv00 = matrix[0][0].clone().inverse()?;
5784 let inv11 = matrix[1][1].clone().inverse()?;
5785 let inv22 = matrix[2][2].clone().inverse()?;
5786 let inv33 = matrix[3][3].clone().inverse()?;
5787 if true {
5788 Ok([
5796 [inv00, Real::zero(), Real::zero(), Real::zero()],
5797 [Real::zero(), inv11, Real::zero(), Real::zero()],
5798 [Real::zero(), Real::zero(), inv22, Real::zero()],
5799 [Real::zero(), Real::zero(), Real::zero(), inv33],
5800 ])
5801 } else {
5802 Ok(from_fn(|row| {
5803 from_fn(|col| {
5804 if row == 0 && col == 0 {
5805 inv00.clone()
5806 } else if row == 1 && col == 1 {
5807 inv11.clone()
5808 } else if row == 2 && col == 2 {
5809 inv22.clone()
5810 } else if row == 3 && col == 3 {
5811 inv33.clone()
5812 } else {
5813 Real::zero()
5814 }
5815 })
5816 }))
5817 }
5818}
5819
5820#[inline]
5821fn invert_matrix4_by_upper_triangular(matrix: &[[Real; 4]; 4]) -> BlasResult<[[Real; 4]; 4]> {
5822 let inv_a00 = matrix[0][0].clone().inverse()?;
5829 let inv_a11 = matrix[1][1].clone().inverse()?;
5830 let inv_a22 = matrix[2][2].clone().inverse()?;
5831 let inv_a33 = matrix[3][3].clone().inverse()?;
5832 let inv_diagonal = [inv_a00, inv_a11, inv_a22, inv_a33];
5833 let mut result = [
5834 [Real::zero(), Real::zero(), Real::zero(), Real::zero()],
5835 [Real::zero(), Real::zero(), Real::zero(), Real::zero()],
5836 [Real::zero(), Real::zero(), Real::zero(), Real::zero()],
5837 [Real::zero(), Real::zero(), Real::zero(), Real::zero()],
5838 ];
5839
5840 for row in 0..4 {
5841 for col in row..4 {
5842 let mut value = if row == col {
5843 Real::one()
5844 } else {
5845 Real::zero()
5846 };
5847 for k in row..col {
5848 value = value - (&result[row][k] * &matrix[k][col]);
5849 }
5850 result[row][col] = value.mul_cached(&inv_diagonal[col]);
5851 }
5852 }
5853 Ok(result)
5854}
5855
5856#[inline]
5857fn invert_matrix4_by_lower_triangular(matrix: &[[Real; 4]; 4]) -> BlasResult<[[Real; 4]; 4]> {
5858 let inv_a00 = matrix[0][0].clone().inverse()?;
5864 let inv_a11 = matrix[1][1].clone().inverse()?;
5865 let inv_a22 = matrix[2][2].clone().inverse()?;
5866 let inv_a33 = matrix[3][3].clone().inverse()?;
5867 let inv_diagonal = [inv_a00, inv_a11, inv_a22, inv_a33];
5868 let mut result = [
5869 [Real::zero(), Real::zero(), Real::zero(), Real::zero()],
5870 [Real::zero(), Real::zero(), Real::zero(), Real::zero()],
5871 [Real::zero(), Real::zero(), Real::zero(), Real::zero()],
5872 [Real::zero(), Real::zero(), Real::zero(), Real::zero()],
5873 ];
5874
5875 for row in 0..4 {
5876 for col in (0..=row).rev() {
5877 let mut value = if row == col {
5878 Real::one()
5879 } else {
5880 Real::zero()
5881 };
5882 for k in (col + 1)..=row {
5883 value = value - (&result[row][k] * &matrix[k][col]);
5884 }
5885 result[row][col] = value.mul_cached(&inv_diagonal[col]);
5886 }
5887 }
5888 Ok(result)
5889}
5890
5891#[inline]
5892fn invert_matrix4_by_upper_triangular_checked(
5893 matrix: &[[Real; 4]; 4],
5894) -> CheckedBlasResult<[[Real; 4]; 4]> {
5895 require_known_nonzero(&matrix[0][0])?;
5896 require_known_nonzero(&matrix[1][1])?;
5897 require_known_nonzero(&matrix[2][2])?;
5898 require_known_nonzero(&matrix[3][3])?;
5899 invert_matrix4_by_upper_triangular(matrix)
5900}
5901
5902#[inline]
5903fn invert_matrix4_by_lower_triangular_checked(
5904 matrix: &[[Real; 4]; 4],
5905) -> CheckedBlasResult<[[Real; 4]; 4]> {
5906 require_known_nonzero(&matrix[0][0])?;
5907 require_known_nonzero(&matrix[1][1])?;
5908 require_known_nonzero(&matrix[2][2])?;
5909 require_known_nonzero(&matrix[3][3])?;
5910 invert_matrix4_by_lower_triangular(matrix)
5911}
5912
5913#[inline]
5914fn invert_matrix4_by_upper_triangular_checked_with_abort(
5915 matrix: &[[Real; 4]; 4],
5916 signal: &AbortSignal,
5917) -> CheckedBlasResult<[[Real; 4]; 4]> {
5918 require_known_nonzero_with_abort(&matrix[0][0], signal)?;
5919 require_known_nonzero_with_abort(&matrix[1][1], signal)?;
5920 require_known_nonzero_with_abort(&matrix[2][2], signal)?;
5921 require_known_nonzero_with_abort(&matrix[3][3], signal)?;
5922 invert_matrix4_by_upper_triangular(matrix)
5923}
5924
5925#[inline]
5926fn invert_matrix4_by_lower_triangular_checked_with_abort(
5927 matrix: &[[Real; 4]; 4],
5928 signal: &AbortSignal,
5929) -> CheckedBlasResult<[[Real; 4]; 4]> {
5930 require_known_nonzero_with_abort(&matrix[0][0], signal)?;
5931 require_known_nonzero_with_abort(&matrix[1][1], signal)?;
5932 require_known_nonzero_with_abort(&matrix[2][2], signal)?;
5933 require_known_nonzero_with_abort(&matrix[3][3], signal)?;
5934 invert_matrix4_by_lower_triangular(matrix)
5935}
5936
5937#[inline]
5938fn invert_matrix4_by_diagonal_checked(
5939 matrix: &[[Real; 4]; 4],
5940) -> CheckedBlasResult<[[Real; 4]; 4]> {
5941 require_known_nonzero(&matrix[0][0])?;
5942 require_known_nonzero(&matrix[1][1])?;
5943 require_known_nonzero(&matrix[2][2])?;
5944 require_known_nonzero(&matrix[3][3])?;
5945 invert_matrix4_by_diagonal(matrix)
5946}
5947
5948#[inline]
5949fn invert_matrix4_by_diagonal_checked_with_abort(
5950 matrix: &[[Real; 4]; 4],
5951 signal: &AbortSignal,
5952) -> CheckedBlasResult<[[Real; 4]; 4]> {
5953 require_known_nonzero_with_abort(&matrix[0][0], signal)?;
5954 require_known_nonzero_with_abort(&matrix[1][1], signal)?;
5955 require_known_nonzero_with_abort(&matrix[2][2], signal)?;
5956 require_known_nonzero_with_abort(&matrix[3][3], signal)?;
5957 invert_matrix4_by_diagonal(matrix)
5958}
5959
5960#[inline]
5961fn multiply_matrix3_by_left_diagonal(
5962 left: &[[Real; 3]; 3],
5963 right: &[[Real; 3]; 3],
5964) -> [[Real; 3]; 3] {
5965 let inv00 = left[0][0].clone();
5969 let inv11 = left[1][1].clone();
5970 let inv22 = left[2][2].clone();
5971 let [[r00, r01, r02], [r10, r11, r12], [r20, r21, r22]] = right.clone();
5972
5973 [
5974 [
5975 r00.mul_cached(&inv00),
5976 r01.mul_cached(&inv00),
5977 r02.mul_cached(&inv00),
5978 ],
5979 [
5980 r10.mul_cached(&inv11),
5981 r11.mul_cached(&inv11),
5982 r12.mul_cached(&inv11),
5983 ],
5984 [
5985 r20.mul_cached(&inv22),
5986 r21.mul_cached(&inv22),
5987 r22.mul_cached(&inv22),
5988 ],
5989 ]
5990}
5991
5992#[inline]
5993fn multiply_matrix3_by_right_diagonal(
5994 left: &[[Real; 3]; 3],
5995 right: &[[Real; 3]; 3],
5996) -> [[Real; 3]; 3] {
5997 let inv00 = right[0][0].clone();
6000 let inv11 = right[1][1].clone();
6001 let inv22 = right[2][2].clone();
6002 let [[l00, l01, l02], [l10, l11, l12], [l20, l21, l22]] = left.clone();
6003
6004 [
6005 [
6006 l00.mul_cached(&inv00),
6007 l01.mul_cached(&inv11),
6008 l02.mul_cached(&inv22),
6009 ],
6010 [
6011 l10.mul_cached(&inv00),
6012 l11.mul_cached(&inv11),
6013 l12.mul_cached(&inv22),
6014 ],
6015 [
6016 l20.mul_cached(&inv00),
6017 l21.mul_cached(&inv11),
6018 l22.mul_cached(&inv22),
6019 ],
6020 ]
6021}
6022
6023#[inline]
6024fn multiply_matrix4_by_left_diagonal(
6025 left: &[[Real; 4]; 4],
6026 right: &[[Real; 4]; 4],
6027) -> [[Real; 4]; 4] {
6028 let inv00 = left[0][0].clone();
6030 let inv11 = left[1][1].clone();
6031 let inv22 = left[2][2].clone();
6032 let inv33 = left[3][3].clone();
6033 let [
6034 [r00, r01, r02, r03],
6035 [r10, r11, r12, r13],
6036 [r20, r21, r22, r23],
6037 [r30, r31, r32, r33],
6038 ] = right.clone();
6039
6040 [
6041 [
6042 r00.mul_cached(&inv00),
6043 r01.mul_cached(&inv00),
6044 r02.mul_cached(&inv00),
6045 r03.mul_cached(&inv00),
6046 ],
6047 [
6048 r10.mul_cached(&inv11),
6049 r11.mul_cached(&inv11),
6050 r12.mul_cached(&inv11),
6051 r13.mul_cached(&inv11),
6052 ],
6053 [
6054 r20.mul_cached(&inv22),
6055 r21.mul_cached(&inv22),
6056 r22.mul_cached(&inv22),
6057 r23.mul_cached(&inv22),
6058 ],
6059 [
6060 r30.mul_cached(&inv33),
6061 r31.mul_cached(&inv33),
6062 r32.mul_cached(&inv33),
6063 r33.mul_cached(&inv33),
6064 ],
6065 ]
6066}
6067
6068#[inline]
6069fn multiply_matrix4_by_right_diagonal(
6070 left: &[[Real; 4]; 4],
6071 right: &[[Real; 4]; 4],
6072) -> [[Real; 4]; 4] {
6073 let inv00 = right[0][0].clone();
6076 let inv11 = right[1][1].clone();
6077 let inv22 = right[2][2].clone();
6078 let inv33 = right[3][3].clone();
6079 let [
6080 [l00, l01, l02, l03],
6081 [l10, l11, l12, l13],
6082 [l20, l21, l22, l23],
6083 [l30, l31, l32, l33],
6084 ] = left.clone();
6085
6086 [
6087 [
6088 l00.mul_cached(&inv00),
6089 l01.mul_cached(&inv11),
6090 l02.mul_cached(&inv22),
6091 l03.mul_cached(&inv33),
6092 ],
6093 [
6094 l10.mul_cached(&inv00),
6095 l11.mul_cached(&inv11),
6096 l12.mul_cached(&inv22),
6097 l13.mul_cached(&inv33),
6098 ],
6099 [
6100 l20.mul_cached(&inv00),
6101 l21.mul_cached(&inv11),
6102 l22.mul_cached(&inv22),
6103 l23.mul_cached(&inv33),
6104 ],
6105 [
6106 l30.mul_cached(&inv00),
6107 l31.mul_cached(&inv11),
6108 l32.mul_cached(&inv22),
6109 l33.mul_cached(&inv33),
6110 ],
6111 ]
6112}
6113
6114#[inline]
6115fn divide_matrix3_by_diagonal(
6116 left: [[Real; 3]; 3],
6117 right: &[[Real; 3]; 3],
6118) -> BlasResult<[[Real; 3]; 3]> {
6119 let inv00 = right[0][0].clone().inverse()?;
6120 let inv11 = right[1][1].clone().inverse()?;
6121 let inv22 = right[2][2].clone().inverse()?;
6122 let mut result = left;
6123 for row in &mut result {
6124 row[0] = row[0].clone().mul_cached(&inv00);
6125 row[1] = row[1].clone().mul_cached(&inv11);
6126 row[2] = row[2].clone().mul_cached(&inv22);
6127 }
6128 Ok(result)
6129}
6130
6131#[inline]
6132fn divide_matrix3_by_upper_triangular(
6133 mut left: [[Real; 3]; 3],
6134 right: &[[Real; 3]; 3],
6135) -> BlasResult<[[Real; 3]; 3]> {
6136 let inv_a00 = right[0][0].clone().inverse()?;
6141 let inv_a11 = right[1][1].clone().inverse()?;
6142 let inv_a22 = right[2][2].clone().inverse()?;
6143 if true {
6144 crate::trace_dispatch!(
6145 "hyperlattice_matrix",
6146 "helper",
6147 "divide3-upper-triangular-fused-exact"
6148 );
6149 let one = Real::one();
6150 for row in &mut left {
6151 let x0 = row[0].clone().mul_cached(&inv_a00);
6152 let x1 = (row[1].clone() - (&x0 * &right[0][1])).mul_cached(&inv_a11);
6153 let x2 = Real::active_signed_product_sum2(
6154 [true, false, false],
6155 [[&row[2], &one], [&x0, &right[0][2]], [&x1, &right[1][2]]],
6156 )
6157 .mul_cached(&inv_a22);
6158 *row = [x0, x1, x2];
6159 }
6160 return Ok(left);
6161 }
6162
6163 let row0_0 = left[0][0].clone().mul_cached(&inv_a00);
6164 let row0_1 = (left[0][1].clone() - (row0_0.clone() * &right[0][1])).mul_cached(&inv_a11);
6165 let row0_2 =
6166 (left[0][2].clone() - (row0_0.clone() * &right[0][2]) - (row0_1.clone() * &right[1][2]))
6167 .mul_cached(&inv_a22);
6168
6169 let row1_0 = left[1][0].clone().mul_cached(&inv_a00);
6170 let row1_1 = (left[1][1].clone() - (row1_0.clone() * &right[0][1])).mul_cached(&inv_a11);
6171 let row1_2 =
6172 (left[1][2].clone() - (row1_0.clone() * &right[0][2]) - (row1_1.clone() * &right[1][2]))
6173 .mul_cached(&inv_a22);
6174
6175 let row2_0 = left[2][0].clone().mul_cached(&inv_a00);
6176 let row2_1 = (left[2][1].clone() - (row2_0.clone() * &right[0][1])).mul_cached(&inv_a11);
6177 let row2_2 =
6178 (left[2][2].clone() - (row2_0.clone() * &right[0][2]) - (row2_1.clone() * &right[1][2]))
6179 .mul_cached(&inv_a22);
6180
6181 left[0] = [row0_0, row0_1, row0_2];
6182 left[1] = [row1_0, row1_1, row1_2];
6183 left[2] = [row2_0, row2_1, row2_2];
6184 Ok(left)
6185}
6186
6187#[inline]
6188fn divide_matrix3_affine_upper_row(
6189 row: &[Real; 3],
6190 right: &[[Real; 3]; 3],
6191 inv_a00: &Real,
6192 inv_a11: &Real,
6193 one: &Real,
6194) -> [Real; 3] {
6195 let x0 = row[0].clone().mul_cached(inv_a00);
6196 let x1 = (row[1].clone() - (&x0 * &right[0][1])).mul_cached(inv_a11);
6197 let x2 = mul_sub_add(&row[2], one, &x0, &right[0][2], &x1, &right[1][2]);
6198 [x0, x1, x2]
6199}
6200
6201#[inline]
6202fn divide_matrix3_by_affine_upper_triangular(
6203 left: [[Real; 3]; 3],
6204 right: &[[Real; 3]; 3],
6205) -> BlasResult<[[Real; 3]; 3]> {
6206 let inv_a00 = right[0][0].clone().inverse()?;
6211 let inv_a11 = right[1][1].clone().inverse()?;
6212 if true {
6213 crate::trace_dispatch!(
6214 "hyperlattice_matrix",
6215 "helper",
6216 "divide3-affine-upper-triangular-fused-exact"
6217 );
6218 }
6219 let one = Real::one();
6220 Ok([
6221 divide_matrix3_affine_upper_row(&left[0], right, &inv_a00, &inv_a11, &one),
6222 divide_matrix3_affine_upper_row(&left[1], right, &inv_a00, &inv_a11, &one),
6223 divide_matrix3_affine_upper_row(&left[2], right, &inv_a00, &inv_a11, &one),
6224 ])
6225}
6226
6227#[inline]
6228fn divide_matrix3_affine_by_affine_upper_triangular(
6229 left: [[Real; 3]; 3],
6230 right: &[[Real; 3]; 3],
6231) -> BlasResult<[[Real; 3]; 3]> {
6232 let inv_a00 = right[0][0].clone().inverse()?;
6233 let inv_a11 = right[1][1].clone().inverse()?;
6234 if true {
6235 crate::trace_dispatch!(
6236 "hyperlattice_matrix",
6237 "helper",
6238 "divide3-affine-left-affine-upper-triangular-fused-exact"
6239 );
6240 }
6241 let one = Real::one();
6242 Ok([
6243 divide_matrix3_affine_upper_row(&left[0], right, &inv_a00, &inv_a11, &one),
6244 divide_matrix3_affine_upper_row(&left[1], right, &inv_a00, &inv_a11, &one),
6245 [Real::zero(), Real::zero(), one],
6246 ])
6247}
6248
6249#[inline]
6250fn divide_matrix3_by_affine_upper_triangular_checked(
6251 left: [[Real; 3]; 3],
6252 right: &[[Real; 3]; 3],
6253) -> CheckedBlasResult<[[Real; 3]; 3]> {
6254 require_known_nonzero(&right[0][0])?;
6255 require_known_nonzero(&right[1][1])?;
6256 divide_matrix3_by_affine_upper_triangular(left, right)
6257}
6258
6259#[inline]
6260fn divide_matrix3_affine_by_affine_upper_triangular_checked(
6261 left: [[Real; 3]; 3],
6262 right: &[[Real; 3]; 3],
6263) -> CheckedBlasResult<[[Real; 3]; 3]> {
6264 require_known_nonzero(&right[0][0])?;
6265 require_known_nonzero(&right[1][1])?;
6266 divide_matrix3_affine_by_affine_upper_triangular(left, right)
6267}
6268
6269#[inline]
6270fn divide_matrix3_by_affine_upper_triangular_checked_with_abort(
6271 left: [[Real; 3]; 3],
6272 right: &[[Real; 3]; 3],
6273 signal: &AbortSignal,
6274) -> CheckedBlasResult<[[Real; 3]; 3]> {
6275 require_known_nonzero_with_abort(&right[0][0], signal)?;
6276 require_known_nonzero_with_abort(&right[1][1], signal)?;
6277 divide_matrix3_by_affine_upper_triangular(left, right)
6278}
6279
6280#[inline]
6281fn divide_matrix3_affine_by_affine_upper_triangular_checked_with_abort(
6282 left: [[Real; 3]; 3],
6283 right: &[[Real; 3]; 3],
6284 signal: &AbortSignal,
6285) -> CheckedBlasResult<[[Real; 3]; 3]> {
6286 require_known_nonzero_with_abort(&right[0][0], signal)?;
6287 require_known_nonzero_with_abort(&right[1][1], signal)?;
6288 divide_matrix3_affine_by_affine_upper_triangular(left, right)
6289}
6290
6291#[inline]
6292fn divide_matrix3_by_upper_triangular_checked(
6293 left: [[Real; 3]; 3],
6294 right: &[[Real; 3]; 3],
6295) -> CheckedBlasResult<[[Real; 3]; 3]> {
6296 require_known_nonzero(&right[0][0])?;
6297 require_known_nonzero(&right[1][1])?;
6298 require_known_nonzero(&right[2][2])?;
6299 divide_matrix3_by_upper_triangular(left, right)
6300}
6301
6302#[inline]
6303fn divide_matrix3_by_upper_triangular_checked_with_abort(
6304 left: [[Real; 3]; 3],
6305 right: &[[Real; 3]; 3],
6306 signal: &AbortSignal,
6307) -> CheckedBlasResult<[[Real; 3]; 3]> {
6308 require_known_nonzero_with_abort(&right[0][0], signal)?;
6309 require_known_nonzero_with_abort(&right[1][1], signal)?;
6310 require_known_nonzero_with_abort(&right[2][2], signal)?;
6311 divide_matrix3_by_upper_triangular(left, right)
6312}
6313
6314#[inline]
6315fn divide_matrix3_by_lower_triangular(
6316 mut left: [[Real; 3]; 3],
6317 right: &[[Real; 3]; 3],
6318) -> BlasResult<[[Real; 3]; 3]> {
6319 let inv_a00 = right[0][0].clone().inverse()?;
6323 let inv_a11 = right[1][1].clone().inverse()?;
6324 let inv_a22 = right[2][2].clone().inverse()?;
6325 if true {
6326 crate::trace_dispatch!(
6327 "hyperlattice_matrix",
6328 "helper",
6329 "divide3-lower-triangular-fused-exact"
6330 );
6331 let one = Real::one();
6332 for row in &mut left {
6333 let x2 = row[2].clone().mul_cached(&inv_a22);
6334 let x1 = (row[1].clone() - (&x2 * &right[2][1])).mul_cached(&inv_a11);
6335 let x0 = Real::active_signed_product_sum2(
6336 [true, false, false],
6337 [[&row[0], &one], [&x1, &right[1][0]], [&x2, &right[2][0]]],
6338 )
6339 .mul_cached(&inv_a00);
6340 *row = [x0, x1, x2];
6341 }
6342 return Ok(left);
6343 }
6344
6345 let row0_2 = left[0][2].clone().mul_cached(&inv_a22);
6346 let row0_1 = (left[0][1].clone() - (row0_2.clone() * &right[2][1])).mul_cached(&inv_a11);
6347 let row0_0 =
6348 (left[0][0].clone() - (row0_1.clone() * &right[1][0]) - (row0_2.clone() * &right[2][0]))
6349 .mul_cached(&inv_a00);
6350
6351 let row1_2 = left[1][2].clone().mul_cached(&inv_a22);
6352 let row1_1 = (left[1][1].clone() - (row1_2.clone() * &right[2][1])).mul_cached(&inv_a11);
6353 let row1_0 =
6354 (left[1][0].clone() - (row1_1.clone() * &right[1][0]) - (row1_2.clone() * &right[2][0]))
6355 .mul_cached(&inv_a00);
6356
6357 let row2_2 = left[2][2].clone().mul_cached(&inv_a22);
6358 let row2_1 = (left[2][1].clone() - (row2_2.clone() * &right[2][1])).mul_cached(&inv_a11);
6359 let row2_0 =
6360 (left[2][0].clone() - (row2_1.clone() * &right[1][0]) - (row2_2.clone() * &right[2][0]))
6361 .mul_cached(&inv_a00);
6362
6363 left[0] = [row0_0, row0_1, row0_2];
6364 left[1] = [row1_0, row1_1, row1_2];
6365 left[2] = [row2_0, row2_1, row2_2];
6366 Ok(left)
6367}
6368
6369#[inline]
6370fn divide_matrix3_by_lower_triangular_checked(
6371 left: [[Real; 3]; 3],
6372 right: &[[Real; 3]; 3],
6373) -> CheckedBlasResult<[[Real; 3]; 3]> {
6374 require_known_nonzero(&right[0][0])?;
6375 require_known_nonzero(&right[1][1])?;
6376 require_known_nonzero(&right[2][2])?;
6377 divide_matrix3_by_lower_triangular(left, right)
6378}
6379
6380#[inline]
6381fn divide_matrix3_by_lower_triangular_checked_with_abort(
6382 left: [[Real; 3]; 3],
6383 right: &[[Real; 3]; 3],
6384 signal: &AbortSignal,
6385) -> CheckedBlasResult<[[Real; 3]; 3]> {
6386 require_known_nonzero_with_abort(&right[0][0], signal)?;
6387 require_known_nonzero_with_abort(&right[1][1], signal)?;
6388 require_known_nonzero_with_abort(&right[2][2], signal)?;
6389 divide_matrix3_by_lower_triangular(left, right)
6390}
6391
6392#[inline]
6393fn affine_inverse_translation2(linear: &[[Real; 2]; 2], tx: &Real, ty: &Real) -> [Real; 2] {
6394 [
6395 Real::zero() - &mul_add(&linear[0][0], tx, &linear[0][1], ty),
6396 Real::zero() - &mul_add(&linear[1][0], tx, &linear[1][1], ty),
6397 ]
6398}
6399
6400#[inline]
6401fn affine_linear_dot2(left_a: &Real, right_a: &Real, left_b: &Real, right_b: &Real) -> Real {
6402 mul_add(left_a, right_a, left_b, right_b)
6403}
6404
6405#[inline]
6406fn affine_translation_column_update_from_inverse2(
6407 row: &[Real; 3],
6408 translation: &[Real; 2],
6409) -> Real {
6410 row[2].clone() + mul_add(&row[0], &translation[0], &row[1], &translation[1])
6411}
6412
6413#[inline]
6414fn affine_translation_column_subtract_update2(row: &[Real; 3], translation: [&Real; 2]) -> Real {
6415 crate::trace_dispatch!(
6416 "hyperlattice_matrix",
6417 "helper",
6418 "affine-translation-column-subtract2"
6419 );
6420 let shifted = mul_add(&row[0], translation[0], &row[1], translation[1]);
6421 row[2].clone() - shifted
6422}
6423
6424#[inline]
6425fn divide_matrix3_by_affine_translation(
6426 left: [[Real; 3]; 3],
6427 right: &[[Real; 3]; 3],
6428) -> BlasResult<[[Real; 3]; 3]> {
6429 let translation = [&right[0][2], &right[1][2]];
6431 Ok([
6432 [
6433 left[0][0].clone(),
6434 left[0][1].clone(),
6435 affine_translation_column_subtract_update2(&left[0], translation),
6436 ],
6437 [
6438 left[1][0].clone(),
6439 left[1][1].clone(),
6440 affine_translation_column_subtract_update2(&left[1], translation),
6441 ],
6442 [
6443 left[2][0].clone(),
6444 left[2][1].clone(),
6445 affine_translation_column_subtract_update2(&left[2], translation),
6446 ],
6447 ])
6448}
6449
6450#[inline]
6451fn divide_matrix3_affine_by_affine_translation(
6452 left: [[Real; 3]; 3],
6453 right: &[[Real; 3]; 3],
6454) -> BlasResult<[[Real; 3]; 3]> {
6455 let translation = [&right[0][2], &right[1][2]];
6457 Ok([
6458 [
6459 left[0][0].clone(),
6460 left[0][1].clone(),
6461 affine_translation_column_subtract_update2(&left[0], translation),
6462 ],
6463 [
6464 left[1][0].clone(),
6465 left[1][1].clone(),
6466 affine_translation_column_subtract_update2(&left[1], translation),
6467 ],
6468 [Real::zero(), Real::zero(), Real::one()],
6469 ])
6470}
6471
6472#[inline]
6473fn divide_matrix3_by_affine_ref_translation(
6474 left: &[[Real; 3]; 3],
6475 right: &[[Real; 3]; 3],
6476) -> BlasResult<[[Real; 3]; 3]> {
6477 let translation = [&right[0][2], &right[1][2]];
6481 Ok([
6482 [
6483 left[0][0].clone(),
6484 left[0][1].clone(),
6485 affine_translation_column_subtract_update2(&left[0], translation),
6486 ],
6487 [
6488 left[1][0].clone(),
6489 left[1][1].clone(),
6490 affine_translation_column_subtract_update2(&left[1], translation),
6491 ],
6492 [
6493 left[2][0].clone(),
6494 left[2][1].clone(),
6495 affine_translation_column_subtract_update2(&left[2], translation),
6496 ],
6497 ])
6498}
6499
6500#[inline]
6501fn divide_matrix3_affine_by_affine_ref_translation(
6502 left: &[[Real; 3]; 3],
6503 right: &[[Real; 3]; 3],
6504) -> BlasResult<[[Real; 3]; 3]> {
6505 let translation = [&right[0][2], &right[1][2]];
6509 Ok([
6510 [
6511 left[0][0].clone(),
6512 left[0][1].clone(),
6513 affine_translation_column_subtract_update2(&left[0], translation),
6514 ],
6515 [
6516 left[1][0].clone(),
6517 left[1][1].clone(),
6518 affine_translation_column_subtract_update2(&left[1], translation),
6519 ],
6520 [Real::zero(), Real::zero(), Real::one()],
6521 ])
6522}
6523
6524#[inline]
6525fn divide_matrix3_by_affine_ref_no_translation(
6526 left: &[[Real; 3]; 3],
6527 right: &[[Real; 3]; 3],
6528) -> BlasResult<[[Real; 3]; 3]> {
6529 let a = right[0][0].clone();
6533 let b = right[0][1].clone();
6534 let c = right[1][0].clone();
6535 let d = right[1][1].clone();
6536 let tx = right[0][2].clone();
6537 let ty = right[1][2].clone();
6538
6539 let right_det = (&a * &d) - (&b * &c);
6540 let right_inv_det = right_det.inverse()?;
6541 let right_inverse_linear = [
6542 [
6543 scale_by_shared_factor(d, &right_inv_det),
6544 scale_by_shared_factor(Real::zero() - &b, &right_inv_det),
6545 ],
6546 [
6547 scale_by_shared_factor(Real::zero() - &c, &right_inv_det),
6548 scale_by_shared_factor(a, &right_inv_det),
6549 ],
6550 ];
6551 let right_inverse_translation = affine_inverse_translation2(&right_inverse_linear, &tx, &ty);
6552
6553 Ok([
6554 [
6555 affine_linear_dot2(
6556 &left[0][0],
6557 &right_inverse_linear[0][0],
6558 &left[0][1],
6559 &right_inverse_linear[1][0],
6560 ),
6561 affine_linear_dot2(
6562 &left[0][0],
6563 &right_inverse_linear[0][1],
6564 &left[0][1],
6565 &right_inverse_linear[1][1],
6566 ),
6567 affine_translation_column_update_from_inverse2(&left[0], &right_inverse_translation),
6568 ],
6569 [
6570 affine_linear_dot2(
6571 &left[1][0],
6572 &right_inverse_linear[0][0],
6573 &left[1][1],
6574 &right_inverse_linear[1][0],
6575 ),
6576 affine_linear_dot2(
6577 &left[1][0],
6578 &right_inverse_linear[0][1],
6579 &left[1][1],
6580 &right_inverse_linear[1][1],
6581 ),
6582 affine_translation_column_update_from_inverse2(&left[1], &right_inverse_translation),
6583 ],
6584 [
6585 affine_linear_dot2(
6586 &left[2][0],
6587 &right_inverse_linear[0][0],
6588 &left[2][1],
6589 &right_inverse_linear[1][0],
6590 ),
6591 affine_linear_dot2(
6592 &left[2][0],
6593 &right_inverse_linear[0][1],
6594 &left[2][1],
6595 &right_inverse_linear[1][1],
6596 ),
6597 affine_translation_column_update_from_inverse2(&left[2], &right_inverse_translation),
6598 ],
6599 ])
6600}
6601
6602#[inline]
6603fn divide_matrix3_affine_by_affine_ref_no_translation(
6604 left: &[[Real; 3]; 3],
6605 right: &[[Real; 3]; 3],
6606) -> BlasResult<[[Real; 3]; 3]> {
6607 let a = right[0][0].clone();
6610 let b = right[0][1].clone();
6611 let c = right[1][0].clone();
6612 let d = right[1][1].clone();
6613 let tx = right[0][2].clone();
6614 let ty = right[1][2].clone();
6615
6616 let right_det = (&a * &d) - (&b * &c);
6617 let right_inv_det = right_det.inverse()?;
6618 let right_inverse_linear = [
6619 [
6620 scale_by_shared_factor(d, &right_inv_det),
6621 scale_by_shared_factor(Real::zero() - &b, &right_inv_det),
6622 ],
6623 [
6624 scale_by_shared_factor(Real::zero() - &c, &right_inv_det),
6625 scale_by_shared_factor(a, &right_inv_det),
6626 ],
6627 ];
6628 let right_inverse_translation = affine_inverse_translation2(&right_inverse_linear, &tx, &ty);
6629
6630 Ok([
6631 [
6632 affine_linear_dot2(
6633 &left[0][0],
6634 &right_inverse_linear[0][0],
6635 &left[0][1],
6636 &right_inverse_linear[1][0],
6637 ),
6638 affine_linear_dot2(
6639 &left[0][0],
6640 &right_inverse_linear[0][1],
6641 &left[0][1],
6642 &right_inverse_linear[1][1],
6643 ),
6644 affine_translation_column_update_from_inverse2(&left[0], &right_inverse_translation),
6645 ],
6646 [
6647 affine_linear_dot2(
6648 &left[1][0],
6649 &right_inverse_linear[0][0],
6650 &left[1][1],
6651 &right_inverse_linear[1][0],
6652 ),
6653 affine_linear_dot2(
6654 &left[1][0],
6655 &right_inverse_linear[0][1],
6656 &left[1][1],
6657 &right_inverse_linear[1][1],
6658 ),
6659 affine_translation_column_update_from_inverse2(&left[1], &right_inverse_translation),
6660 ],
6661 [Real::zero(), Real::zero(), Real::one()],
6662 ])
6663}
6664
6665#[inline]
6666fn divide_matrix3_by_affine(
6667 left: [[Real; 3]; 3],
6668 right: &[[Real; 3]; 3],
6669) -> BlasResult<[[Real; 3]; 3]> {
6670 let a = right[0][0].clone();
6671 let b = right[0][1].clone();
6672 let c = right[1][0].clone();
6673 let d = right[1][1].clone();
6674 let tx = right[0][2].clone();
6675 let ty = right[1][2].clone();
6676
6677 let right_det = (&a * &d) - (&b * &c);
6678 let right_inv_det = right_det.inverse()?;
6679 let right_inverse_linear = [
6680 [
6681 scale_by_shared_factor(d, &right_inv_det),
6682 scale_by_shared_factor(Real::zero() - &b, &right_inv_det),
6683 ],
6684 [
6685 scale_by_shared_factor(Real::zero() - &c, &right_inv_det),
6686 scale_by_shared_factor(a, &right_inv_det),
6687 ],
6688 ];
6689 let right_inverse_translation = affine_inverse_translation2(&right_inverse_linear, &tx, &ty);
6690
6691 Ok([
6692 [
6693 affine_linear_dot2(
6694 &left[0][0],
6695 &right_inverse_linear[0][0],
6696 &left[0][1],
6697 &right_inverse_linear[1][0],
6698 ),
6699 affine_linear_dot2(
6700 &left[0][0],
6701 &right_inverse_linear[0][1],
6702 &left[0][1],
6703 &right_inverse_linear[1][1],
6704 ),
6705 affine_translation_column_update_from_inverse2(&left[0], &right_inverse_translation),
6706 ],
6707 [
6708 affine_linear_dot2(
6709 &left[1][0],
6710 &right_inverse_linear[0][0],
6711 &left[1][1],
6712 &right_inverse_linear[1][0],
6713 ),
6714 affine_linear_dot2(
6715 &left[1][0],
6716 &right_inverse_linear[0][1],
6717 &left[1][1],
6718 &right_inverse_linear[1][1],
6719 ),
6720 affine_translation_column_update_from_inverse2(&left[1], &right_inverse_translation),
6721 ],
6722 [
6723 affine_linear_dot2(
6724 &left[2][0],
6725 &right_inverse_linear[0][0],
6726 &left[2][1],
6727 &right_inverse_linear[1][0],
6728 ),
6729 affine_linear_dot2(
6730 &left[2][0],
6731 &right_inverse_linear[0][1],
6732 &left[2][1],
6733 &right_inverse_linear[1][1],
6734 ),
6735 affine_translation_column_update_from_inverse2(&left[2], &right_inverse_translation),
6736 ],
6737 ])
6738}
6739
6740#[inline]
6741fn divide_matrix3_affine_by_affine(
6742 left: [[Real; 3]; 3],
6743 right: &[[Real; 3]; 3],
6744) -> BlasResult<[[Real; 3]; 3]> {
6745 let a = right[0][0].clone();
6746 let b = right[0][1].clone();
6747 let c = right[1][0].clone();
6748 let d = right[1][1].clone();
6749 let tx = right[0][2].clone();
6750 let ty = right[1][2].clone();
6751
6752 let right_det = (&a * &d) - (&b * &c);
6753 let right_inv_det = right_det.inverse()?;
6754 let right_inverse_linear = [
6755 [
6756 scale_by_shared_factor(d, &right_inv_det),
6757 scale_by_shared_factor(Real::zero() - &b, &right_inv_det),
6758 ],
6759 [
6760 scale_by_shared_factor(Real::zero() - &c, &right_inv_det),
6761 scale_by_shared_factor(a, &right_inv_det),
6762 ],
6763 ];
6764 let right_inverse_translation = affine_inverse_translation2(&right_inverse_linear, &tx, &ty);
6765
6766 Ok([
6767 [
6768 affine_linear_dot2(
6769 &left[0][0],
6770 &right_inverse_linear[0][0],
6771 &left[0][1],
6772 &right_inverse_linear[1][0],
6773 ),
6774 affine_linear_dot2(
6775 &left[0][0],
6776 &right_inverse_linear[0][1],
6777 &left[0][1],
6778 &right_inverse_linear[1][1],
6779 ),
6780 affine_translation_column_update_from_inverse2(&left[0], &right_inverse_translation),
6781 ],
6782 [
6783 affine_linear_dot2(
6784 &left[1][0],
6785 &right_inverse_linear[0][0],
6786 &left[1][1],
6787 &right_inverse_linear[1][0],
6788 ),
6789 affine_linear_dot2(
6790 &left[1][0],
6791 &right_inverse_linear[0][1],
6792 &left[1][1],
6793 &right_inverse_linear[1][1],
6794 ),
6795 affine_translation_column_update_from_inverse2(&left[1], &right_inverse_translation),
6796 ],
6797 [Real::zero(), Real::zero(), Real::one()],
6798 ])
6799}
6800
6801#[inline]
6802fn divide_matrix3_by_diagonal_checked(
6803 left: [[Real; 3]; 3],
6804 right: &[[Real; 3]; 3],
6805) -> CheckedBlasResult<[[Real; 3]; 3]> {
6806 require_known_nonzero(&right[0][0])?;
6807 require_known_nonzero(&right[1][1])?;
6808 require_known_nonzero(&right[2][2])?;
6809 divide_matrix3_by_diagonal(left, right)
6810}
6811
6812#[inline]
6813fn divide_matrix3_by_diagonal_checked_with_abort(
6814 left: [[Real; 3]; 3],
6815 right: &[[Real; 3]; 3],
6816 signal: &AbortSignal,
6817) -> CheckedBlasResult<[[Real; 3]; 3]> {
6818 require_known_nonzero_with_abort(&right[0][0], signal)?;
6819 require_known_nonzero_with_abort(&right[1][1], signal)?;
6820 require_known_nonzero_with_abort(&right[2][2], signal)?;
6821 divide_matrix3_by_diagonal(left, right)
6822}
6823
6824#[inline]
6825fn divide_matrix3_by_affine_checked(
6826 left: [[Real; 3]; 3],
6827 right: &[[Real; 3]; 3],
6828) -> CheckedBlasResult<[[Real; 3]; 3]> {
6829 let a = right[0][0].clone();
6830 let b = right[0][1].clone();
6831 let c = right[1][0].clone();
6832 let d = right[1][1].clone();
6833 let tx = right[0][2].clone();
6834 let ty = right[1][2].clone();
6835 let right_det = (&a * &d) - (&b * &c);
6836 require_known_nonzero(&right_det)?;
6837 let right_inv_det = right_det.inverse()?;
6838 let right_inverse_linear = [
6839 [
6840 scale_by_shared_factor(d, &right_inv_det),
6841 scale_by_shared_factor(Real::zero() - &b, &right_inv_det),
6842 ],
6843 [
6844 scale_by_shared_factor(Real::zero() - &c, &right_inv_det),
6845 scale_by_shared_factor(a, &right_inv_det),
6846 ],
6847 ];
6848 let right_inverse_translation = affine_inverse_translation2(&right_inverse_linear, &tx, &ty);
6849
6850 Ok([
6851 [
6852 affine_linear_dot2(
6853 &left[0][0],
6854 &right_inverse_linear[0][0],
6855 &left[0][1],
6856 &right_inverse_linear[1][0],
6857 ),
6858 affine_linear_dot2(
6859 &left[0][0],
6860 &right_inverse_linear[0][1],
6861 &left[0][1],
6862 &right_inverse_linear[1][1],
6863 ),
6864 affine_translation_column_update_from_inverse2(&left[0], &right_inverse_translation),
6865 ],
6866 [
6867 affine_linear_dot2(
6868 &left[1][0],
6869 &right_inverse_linear[0][0],
6870 &left[1][1],
6871 &right_inverse_linear[1][0],
6872 ),
6873 affine_linear_dot2(
6874 &left[1][0],
6875 &right_inverse_linear[0][1],
6876 &left[1][1],
6877 &right_inverse_linear[1][1],
6878 ),
6879 affine_translation_column_update_from_inverse2(&left[1], &right_inverse_translation),
6880 ],
6881 [
6882 affine_linear_dot2(
6883 &left[2][0],
6884 &right_inverse_linear[0][0],
6885 &left[2][1],
6886 &right_inverse_linear[1][0],
6887 ),
6888 affine_linear_dot2(
6889 &left[2][0],
6890 &right_inverse_linear[0][1],
6891 &left[2][1],
6892 &right_inverse_linear[1][1],
6893 ),
6894 affine_translation_column_update_from_inverse2(&left[2], &right_inverse_translation),
6895 ],
6896 ])
6897}
6898
6899#[inline]
6900fn divide_matrix3_by_affine_checked_with_abort(
6901 left: [[Real; 3]; 3],
6902 right: &[[Real; 3]; 3],
6903 signal: &AbortSignal,
6904) -> CheckedBlasResult<[[Real; 3]; 3]> {
6905 let a = right[0][0].clone();
6906 let b = right[0][1].clone();
6907 let c = right[1][0].clone();
6908 let d = right[1][1].clone();
6909 let tx = right[0][2].clone();
6910 let ty = right[1][2].clone();
6911 let right_det = with_abort((&a * &d) - (&b * &c), signal);
6912 require_known_nonzero(&right_det)?;
6913 let right_inv_det = right_det.inverse()?;
6914 let right_inverse_linear = [
6915 [
6916 scale_by_shared_factor(d, &right_inv_det),
6917 scale_by_shared_factor(Real::zero() - &b, &right_inv_det),
6918 ],
6919 [
6920 scale_by_shared_factor(Real::zero() - &c, &right_inv_det),
6921 scale_by_shared_factor(a, &right_inv_det),
6922 ],
6923 ];
6924 let right_inverse_translation = affine_inverse_translation2(&right_inverse_linear, &tx, &ty);
6925
6926 Ok([
6927 [
6928 affine_linear_dot2(
6929 &left[0][0],
6930 &right_inverse_linear[0][0],
6931 &left[0][1],
6932 &right_inverse_linear[1][0],
6933 ),
6934 affine_linear_dot2(
6935 &left[0][0],
6936 &right_inverse_linear[0][1],
6937 &left[0][1],
6938 &right_inverse_linear[1][1],
6939 ),
6940 affine_translation_column_update_from_inverse2(&left[0], &right_inverse_translation),
6941 ],
6942 [
6943 affine_linear_dot2(
6944 &left[1][0],
6945 &right_inverse_linear[0][0],
6946 &left[1][1],
6947 &right_inverse_linear[1][0],
6948 ),
6949 affine_linear_dot2(
6950 &left[1][0],
6951 &right_inverse_linear[0][1],
6952 &left[1][1],
6953 &right_inverse_linear[1][1],
6954 ),
6955 affine_translation_column_update_from_inverse2(&left[1], &right_inverse_translation),
6956 ],
6957 [
6958 affine_linear_dot2(
6959 &left[2][0],
6960 &right_inverse_linear[0][0],
6961 &left[2][1],
6962 &right_inverse_linear[1][0],
6963 ),
6964 affine_linear_dot2(
6965 &left[2][0],
6966 &right_inverse_linear[0][1],
6967 &left[2][1],
6968 &right_inverse_linear[1][1],
6969 ),
6970 affine_translation_column_update_from_inverse2(&left[2], &right_inverse_translation),
6971 ],
6972 ])
6973}
6974
6975#[inline]
6976fn divide_matrix3_affine_by_affine_checked(
6977 left: [[Real; 3]; 3],
6978 right: &[[Real; 3]; 3],
6979) -> CheckedBlasResult<[[Real; 3]; 3]> {
6980 let a = right[0][0].clone();
6981 let b = right[0][1].clone();
6982 let c = right[1][0].clone();
6983 let d = right[1][1].clone();
6984 let tx = right[0][2].clone();
6985 let ty = right[1][2].clone();
6986 let right_det = (&a * &d) - (&b * &c);
6987 require_known_nonzero(&right_det)?;
6988 let right_inv_det = right_det.inverse()?;
6989 let right_inverse_linear = [
6990 [
6991 scale_by_shared_factor(d, &right_inv_det),
6992 scale_by_shared_factor(Real::zero() - &b, &right_inv_det),
6993 ],
6994 [
6995 scale_by_shared_factor(Real::zero() - &c, &right_inv_det),
6996 scale_by_shared_factor(a, &right_inv_det),
6997 ],
6998 ];
6999 let right_inverse_translation = affine_inverse_translation2(&right_inverse_linear, &tx, &ty);
7000
7001 Ok([
7002 [
7003 affine_linear_dot2(
7004 &left[0][0],
7005 &right_inverse_linear[0][0],
7006 &left[0][1],
7007 &right_inverse_linear[1][0],
7008 ),
7009 affine_linear_dot2(
7010 &left[0][0],
7011 &right_inverse_linear[0][1],
7012 &left[0][1],
7013 &right_inverse_linear[1][1],
7014 ),
7015 affine_translation_column_update_from_inverse2(&left[0], &right_inverse_translation),
7016 ],
7017 [
7018 affine_linear_dot2(
7019 &left[1][0],
7020 &right_inverse_linear[0][0],
7021 &left[1][1],
7022 &right_inverse_linear[1][0],
7023 ),
7024 affine_linear_dot2(
7025 &left[1][0],
7026 &right_inverse_linear[0][1],
7027 &left[1][1],
7028 &right_inverse_linear[1][1],
7029 ),
7030 affine_translation_column_update_from_inverse2(&left[1], &right_inverse_translation),
7031 ],
7032 [Real::zero(), Real::zero(), Real::one()],
7033 ])
7034}
7035
7036#[inline]
7037fn divide_matrix3_affine_by_affine_checked_with_abort(
7038 left: [[Real; 3]; 3],
7039 right: &[[Real; 3]; 3],
7040 signal: &AbortSignal,
7041) -> CheckedBlasResult<[[Real; 3]; 3]> {
7042 let a = right[0][0].clone();
7043 let b = right[0][1].clone();
7044 let c = right[1][0].clone();
7045 let d = right[1][1].clone();
7046 let tx = right[0][2].clone();
7047 let ty = right[1][2].clone();
7048 let right_det = with_abort((&a * &d) - (&b * &c), signal);
7049 require_known_nonzero(&right_det)?;
7050 let right_inv_det = right_det.inverse()?;
7051 let right_inverse_linear = [
7052 [
7053 scale_by_shared_factor(d, &right_inv_det),
7054 scale_by_shared_factor(Real::zero() - &b, &right_inv_det),
7055 ],
7056 [
7057 scale_by_shared_factor(Real::zero() - &c, &right_inv_det),
7058 scale_by_shared_factor(a, &right_inv_det),
7059 ],
7060 ];
7061 let right_inverse_translation = affine_inverse_translation2(&right_inverse_linear, &tx, &ty);
7062
7063 Ok([
7064 [
7065 affine_linear_dot2(
7066 &left[0][0],
7067 &right_inverse_linear[0][0],
7068 &left[0][1],
7069 &right_inverse_linear[1][0],
7070 ),
7071 affine_linear_dot2(
7072 &left[0][0],
7073 &right_inverse_linear[0][1],
7074 &left[0][1],
7075 &right_inverse_linear[1][1],
7076 ),
7077 affine_translation_column_update_from_inverse2(&left[0], &right_inverse_translation),
7078 ],
7079 [
7080 affine_linear_dot2(
7081 &left[1][0],
7082 &right_inverse_linear[0][0],
7083 &left[1][1],
7084 &right_inverse_linear[1][0],
7085 ),
7086 affine_linear_dot2(
7087 &left[1][0],
7088 &right_inverse_linear[0][1],
7089 &left[1][1],
7090 &right_inverse_linear[1][1],
7091 ),
7092 affine_translation_column_update_from_inverse2(&left[1], &right_inverse_translation),
7093 ],
7094 [Real::zero(), Real::zero(), Real::one()],
7095 ])
7096}
7097
7098#[inline]
7099fn divide_matrix4_by_diagonal(
7100 left: [[Real; 4]; 4],
7101 right: &[[Real; 4]; 4],
7102) -> BlasResult<[[Real; 4]; 4]> {
7103 let inv00 = right[0][0].clone().inverse()?;
7104 let inv11 = right[1][1].clone().inverse()?;
7105 let inv22 = right[2][2].clone().inverse()?;
7106 let inv33 = right[3][3].clone().inverse()?;
7107 let mut result = left;
7108 for row in &mut result {
7109 row[0] = row[0].clone().mul_cached(&inv00);
7110 row[1] = row[1].clone().mul_cached(&inv11);
7111 row[2] = row[2].clone().mul_cached(&inv22);
7112 row[3] = row[3].clone().mul_cached(&inv33);
7113 }
7114 Ok(result)
7115}
7116
7117#[inline]
7118fn divide_matrix4_by_diagonal_checked(
7119 left: [[Real; 4]; 4],
7120 right: &[[Real; 4]; 4],
7121) -> CheckedBlasResult<[[Real; 4]; 4]> {
7122 require_known_nonzero(&right[0][0])?;
7123 require_known_nonzero(&right[1][1])?;
7124 require_known_nonzero(&right[2][2])?;
7125 require_known_nonzero(&right[3][3])?;
7126 divide_matrix4_by_diagonal(left, right)
7127}
7128
7129#[inline]
7130fn divide_matrix4_by_diagonal_checked_with_abort(
7131 left: [[Real; 4]; 4],
7132 right: &[[Real; 4]; 4],
7133 signal: &AbortSignal,
7134) -> CheckedBlasResult<[[Real; 4]; 4]> {
7135 require_known_nonzero_with_abort(&right[0][0], signal)?;
7136 require_known_nonzero_with_abort(&right[1][1], signal)?;
7137 require_known_nonzero_with_abort(&right[2][2], signal)?;
7138 require_known_nonzero_with_abort(&right[3][3], signal)?;
7139 divide_matrix4_by_diagonal(left, right)
7140}
7141
7142#[inline]
7143fn divide_matrix4_by_upper_triangular(
7144 mut left: [[Real; 4]; 4],
7145 right: &[[Real; 4]; 4],
7146) -> BlasResult<[[Real; 4]; 4]> {
7147 let inv_a00 = right[0][0].clone().inverse()?;
7154 let inv_a11 = right[1][1].clone().inverse()?;
7155 let inv_a22 = right[2][2].clone().inverse()?;
7156 let inv_a33 = right[3][3].clone().inverse()?;
7157 if true {
7158 crate::trace_dispatch!(
7159 "hyperlattice_matrix",
7160 "helper",
7161 "divide4-upper-triangular-fused-exact"
7162 );
7163 let one = Real::one();
7168 for row in &mut left {
7169 let x0 = row[0].clone().mul_cached(&inv_a00);
7170 let x1 = (row[1].clone() - (&x0 * &right[0][1])).mul_cached(&inv_a11);
7171 let x2 = Real::active_signed_product_sum2(
7172 [true, false, false],
7173 [[&row[2], &one], [&x0, &right[0][2]], [&x1, &right[1][2]]],
7174 )
7175 .mul_cached(&inv_a22);
7176 let x3 = Real::active_signed_product_sum2(
7177 [true, false, false, false],
7178 [
7179 [&row[3], &one],
7180 [&x0, &right[0][3]],
7181 [&x1, &right[1][3]],
7182 [&x2, &right[2][3]],
7183 ],
7184 )
7185 .mul_cached(&inv_a33);
7186 *row = [x0, x1, x2, x3];
7187 }
7188 return Ok(left);
7189 }
7190 let inv_diagonal = [inv_a00, inv_a11, inv_a22, inv_a33];
7191
7192 for row in 0..4 {
7193 for col in 0..4 {
7194 let mut value = left[row][col].clone();
7195 for k in 0..col {
7196 value = value - (&left[row][k] * &right[k][col]);
7197 }
7198 left[row][col] = value.mul_cached(&inv_diagonal[col]);
7199 }
7200 }
7201 Ok(left)
7202}
7203
7204#[inline]
7205fn divide_matrix4_affine_upper_row(
7206 row: &[Real; 4],
7207 right: &[[Real; 4]; 4],
7208 inv_a00: &Real,
7209 inv_a11: &Real,
7210 inv_a22: &Real,
7211 one: &Real,
7212) -> [Real; 4] {
7213 let x0 = row[0].clone().mul_cached(inv_a00);
7214 let x1 = (row[1].clone() - (&x0 * &right[0][1])).mul_cached(inv_a11);
7215 let x2 = if true {
7216 Real::active_signed_product_sum2(
7217 [true, false, false],
7218 [[&row[2], one], [&x0, &right[0][2]], [&x1, &right[1][2]]],
7219 )
7220 .mul_cached(inv_a22)
7221 } else {
7222 (row[2].clone() - (&x0 * &right[0][2]) - (&x1 * &right[1][2])).mul_cached(inv_a22)
7223 };
7224 let x3 = if true {
7225 Real::active_signed_product_sum2(
7226 [true, false, false, false],
7227 [
7228 [&row[3], one],
7229 [&x0, &right[0][3]],
7230 [&x1, &right[1][3]],
7231 [&x2, &right[2][3]],
7232 ],
7233 )
7234 } else {
7235 row[3].clone() - (&x0 * &right[0][3]) - (&x1 * &right[1][3]) - (&x2 * &right[2][3])
7236 };
7237 [x0, x1, x2, x3]
7238}
7239
7240#[inline]
7241fn divide_matrix4_by_affine_upper_triangular(
7242 left: [[Real; 4]; 4],
7243 right: &[[Real; 4]; 4],
7244) -> BlasResult<[[Real; 4]; 4]> {
7245 let inv_a00 = right[0][0].clone().inverse()?;
7249 let inv_a11 = right[1][1].clone().inverse()?;
7250 let inv_a22 = right[2][2].clone().inverse()?;
7251 if true {
7252 crate::trace_dispatch!(
7253 "hyperlattice_matrix",
7254 "helper",
7255 "divide4-affine-upper-triangular-fused-exact"
7256 );
7257 }
7258 let one = Real::one();
7259 Ok([
7260 divide_matrix4_affine_upper_row(&left[0], right, &inv_a00, &inv_a11, &inv_a22, &one),
7261 divide_matrix4_affine_upper_row(&left[1], right, &inv_a00, &inv_a11, &inv_a22, &one),
7262 divide_matrix4_affine_upper_row(&left[2], right, &inv_a00, &inv_a11, &inv_a22, &one),
7263 divide_matrix4_affine_upper_row(&left[3], right, &inv_a00, &inv_a11, &inv_a22, &one),
7264 ])
7265}
7266
7267#[inline]
7268fn divide_matrix4_affine_by_affine_upper_triangular(
7269 left: [[Real; 4]; 4],
7270 right: &[[Real; 4]; 4],
7271) -> BlasResult<[[Real; 4]; 4]> {
7272 let inv_a00 = right[0][0].clone().inverse()?;
7273 let inv_a11 = right[1][1].clone().inverse()?;
7274 let inv_a22 = right[2][2].clone().inverse()?;
7275 if true {
7276 crate::trace_dispatch!(
7277 "hyperlattice_matrix",
7278 "helper",
7279 "divide4-affine-left-affine-upper-triangular-fused-exact"
7280 );
7281 }
7282 let one = Real::one();
7283 Ok([
7284 divide_matrix4_affine_upper_row(&left[0], right, &inv_a00, &inv_a11, &inv_a22, &one),
7285 divide_matrix4_affine_upper_row(&left[1], right, &inv_a00, &inv_a11, &inv_a22, &one),
7286 divide_matrix4_affine_upper_row(&left[2], right, &inv_a00, &inv_a11, &inv_a22, &one),
7287 [Real::zero(), Real::zero(), Real::zero(), one],
7288 ])
7289}
7290
7291#[inline]
7292fn divide_matrix4_by_affine_upper_triangular_checked(
7293 left: [[Real; 4]; 4],
7294 right: &[[Real; 4]; 4],
7295) -> CheckedBlasResult<[[Real; 4]; 4]> {
7296 require_known_nonzero(&right[0][0])?;
7297 require_known_nonzero(&right[1][1])?;
7298 require_known_nonzero(&right[2][2])?;
7299 divide_matrix4_by_affine_upper_triangular(left, right)
7300}
7301
7302#[inline]
7303fn divide_matrix4_affine_by_affine_upper_triangular_checked(
7304 left: [[Real; 4]; 4],
7305 right: &[[Real; 4]; 4],
7306) -> CheckedBlasResult<[[Real; 4]; 4]> {
7307 require_known_nonzero(&right[0][0])?;
7308 require_known_nonzero(&right[1][1])?;
7309 require_known_nonzero(&right[2][2])?;
7310 divide_matrix4_affine_by_affine_upper_triangular(left, right)
7311}
7312
7313#[inline]
7314fn divide_matrix4_by_affine_upper_triangular_checked_with_abort(
7315 left: [[Real; 4]; 4],
7316 right: &[[Real; 4]; 4],
7317 signal: &AbortSignal,
7318) -> CheckedBlasResult<[[Real; 4]; 4]> {
7319 require_known_nonzero_with_abort(&right[0][0], signal)?;
7320 require_known_nonzero_with_abort(&right[1][1], signal)?;
7321 require_known_nonzero_with_abort(&right[2][2], signal)?;
7322 divide_matrix4_by_affine_upper_triangular(left, right)
7323}
7324
7325#[inline]
7326fn divide_matrix4_affine_by_affine_upper_triangular_checked_with_abort(
7327 left: [[Real; 4]; 4],
7328 right: &[[Real; 4]; 4],
7329 signal: &AbortSignal,
7330) -> CheckedBlasResult<[[Real; 4]; 4]> {
7331 require_known_nonzero_with_abort(&right[0][0], signal)?;
7332 require_known_nonzero_with_abort(&right[1][1], signal)?;
7333 require_known_nonzero_with_abort(&right[2][2], signal)?;
7334 divide_matrix4_affine_by_affine_upper_triangular(left, right)
7335}
7336
7337#[inline]
7338fn divide_matrix4_by_upper_triangular_checked(
7339 left: [[Real; 4]; 4],
7340 right: &[[Real; 4]; 4],
7341) -> CheckedBlasResult<[[Real; 4]; 4]> {
7342 require_known_nonzero(&right[0][0])?;
7343 require_known_nonzero(&right[1][1])?;
7344 require_known_nonzero(&right[2][2])?;
7345 require_known_nonzero(&right[3][3])?;
7346 divide_matrix4_by_upper_triangular(left, right)
7347}
7348
7349#[inline]
7350fn divide_matrix4_by_upper_triangular_checked_with_abort(
7351 left: [[Real; 4]; 4],
7352 right: &[[Real; 4]; 4],
7353 signal: &AbortSignal,
7354) -> CheckedBlasResult<[[Real; 4]; 4]> {
7355 require_known_nonzero_with_abort(&right[0][0], signal)?;
7356 require_known_nonzero_with_abort(&right[1][1], signal)?;
7357 require_known_nonzero_with_abort(&right[2][2], signal)?;
7358 require_known_nonzero_with_abort(&right[3][3], signal)?;
7359 divide_matrix4_by_upper_triangular(left, right)
7360}
7361
7362#[inline]
7363fn divide_matrix4_by_lower_triangular(
7364 mut left: [[Real; 4]; 4],
7365 right: &[[Real; 4]; 4],
7366) -> BlasResult<[[Real; 4]; 4]> {
7367 let inv_a00 = right[0][0].clone().inverse()?;
7372 let inv_a11 = right[1][1].clone().inverse()?;
7373 let inv_a22 = right[2][2].clone().inverse()?;
7374 let inv_a33 = right[3][3].clone().inverse()?;
7375 if true {
7376 crate::trace_dispatch!(
7377 "hyperlattice_matrix",
7378 "helper",
7379 "divide4-lower-triangular-fused-exact"
7380 );
7381 let one = Real::one();
7382 for row in &mut left {
7383 let x3 = row[3].clone().mul_cached(&inv_a33);
7384 let x2 = (row[2].clone() - (&x3 * &right[3][2])).mul_cached(&inv_a22);
7385 let x1 = Real::active_signed_product_sum2(
7386 [true, false, false],
7387 [[&row[1], &one], [&x2, &right[2][1]], [&x3, &right[3][1]]],
7388 )
7389 .mul_cached(&inv_a11);
7390 let x0 = Real::active_signed_product_sum2(
7391 [true, false, false, false],
7392 [
7393 [&row[0], &one],
7394 [&x1, &right[1][0]],
7395 [&x2, &right[2][0]],
7396 [&x3, &right[3][0]],
7397 ],
7398 )
7399 .mul_cached(&inv_a00);
7400 *row = [x0, x1, x2, x3];
7401 }
7402 return Ok(left);
7403 }
7404 let inv_diagonal = [inv_a00, inv_a11, inv_a22, inv_a33];
7405
7406 for row in 0..4 {
7407 for col in (0..4).rev() {
7408 let mut value = left[row][col].clone();
7409 for k in (col + 1)..4 {
7410 value = value - (&left[row][k] * &right[k][col]);
7411 }
7412 left[row][col] = value.mul_cached(&inv_diagonal[col]);
7413 }
7414 }
7415 Ok(left)
7416}
7417
7418#[inline]
7419fn divide_matrix4_by_lower_triangular_checked(
7420 left: [[Real; 4]; 4],
7421 right: &[[Real; 4]; 4],
7422) -> CheckedBlasResult<[[Real; 4]; 4]> {
7423 require_known_nonzero(&right[0][0])?;
7424 require_known_nonzero(&right[1][1])?;
7425 require_known_nonzero(&right[2][2])?;
7426 require_known_nonzero(&right[3][3])?;
7427 divide_matrix4_by_lower_triangular(left, right)
7428}
7429
7430#[inline]
7431fn divide_matrix4_by_lower_triangular_checked_with_abort(
7432 left: [[Real; 4]; 4],
7433 right: &[[Real; 4]; 4],
7434 signal: &AbortSignal,
7435) -> CheckedBlasResult<[[Real; 4]; 4]> {
7436 require_known_nonzero_with_abort(&right[0][0], signal)?;
7437 require_known_nonzero_with_abort(&right[1][1], signal)?;
7438 require_known_nonzero_with_abort(&right[2][2], signal)?;
7439 require_known_nonzero_with_abort(&right[3][3], signal)?;
7440 divide_matrix4_by_lower_triangular(left, right)
7441}
7442
7443fn right_divide_matrix3(left: [[Real; 3]; 3], right: [[Real; 3]; 3]) -> BlasResult<[[Real; 3]; 3]> {
7444 let right_facts = matrix3_facts(&right);
7445
7446 if right_facts.is_identity {
7447 crate::trace_dispatch!("hyperlattice_matrix", "helper", "right-divide3-identity");
7448 return Ok(left);
7449 }
7450 if right_facts.is_diagonal {
7451 crate::trace_dispatch!("hyperlattice_matrix", "helper", "right-divide3-diagonal");
7452 return divide_matrix3_by_diagonal(left, &right);
7453 }
7454 if right_facts.is_affine_translation {
7455 let left_facts = matrix3_facts(&left);
7456 if left_facts.is_affine {
7457 crate::trace_dispatch!(
7458 "hyperlattice_matrix",
7459 "helper",
7460 "right-divide3-affine-left-affine-translation"
7461 );
7462 return divide_matrix3_affine_by_affine_translation(left, &right);
7463 }
7464 crate::trace_dispatch!(
7465 "hyperlattice_matrix",
7466 "helper",
7467 "right-divide3-affine-by-translation"
7468 );
7469 return divide_matrix3_by_affine_translation(left, &right);
7470 }
7471 if right_facts.is_affine && right_facts.is_upper_triangular {
7472 let left_facts = matrix3_facts(&left);
7473 if left_facts.is_affine {
7474 crate::trace_dispatch!(
7475 "hyperlattice_matrix",
7476 "helper",
7477 "right-divide3-affine-left-affine-upper-triangular"
7478 );
7479 return divide_matrix3_affine_by_affine_upper_triangular(left, &right);
7480 }
7481 crate::trace_dispatch!(
7482 "hyperlattice_matrix",
7483 "helper",
7484 "right-divide3-affine-upper-triangular"
7485 );
7486 return divide_matrix3_by_affine_upper_triangular(left, &right);
7487 }
7488 if right_facts.is_upper_triangular {
7489 crate::trace_dispatch!(
7490 "hyperlattice_matrix",
7491 "helper",
7492 "right-divide3-upper-triangular"
7493 );
7494 return divide_matrix3_by_upper_triangular(left, &right);
7498 }
7499 if right_facts.is_lower_triangular {
7500 crate::trace_dispatch!(
7501 "hyperlattice_matrix",
7502 "helper",
7503 "right-divide3-lower-triangular"
7504 );
7505 return divide_matrix3_by_lower_triangular(left, &right);
7506 }
7507 if right_facts.is_affine {
7508 let left_facts = matrix3_facts(&left);
7515 let left_is_affine = left_facts.is_affine;
7516 let right_linear_is_diagonal = right_facts.linear_is_diagonal;
7517 let right_is_affine_translation = right_facts.is_affine_translation;
7518 crate::trace_dispatch!("hyperlattice_matrix", "helper", "right-divide3-affine");
7519 if left_is_affine {
7522 if right_is_affine_translation {
7523 crate::trace_dispatch!(
7524 "hyperlattice_matrix",
7525 "helper",
7526 "right-divide3-affine-left-affine-translation"
7527 );
7528 return divide_matrix3_affine_by_affine_translation(left, &right);
7529 }
7530 if right_linear_is_diagonal {
7531 crate::trace_dispatch!(
7532 "hyperlattice_matrix",
7533 "helper",
7534 "right-divide3-affine-left-affine-linear-diagonal"
7535 );
7536 return divide_matrix3_affine_by_affine_linear_diagonal(left, &right);
7537 }
7538 crate::trace_dispatch!(
7539 "hyperlattice_matrix",
7540 "helper",
7541 "right-divide3-affine-left-affine"
7542 );
7543 return divide_matrix3_affine_by_affine(left, &right);
7544 }
7545 if right_is_affine_translation {
7546 crate::trace_dispatch!(
7547 "hyperlattice_matrix",
7548 "helper",
7549 "right-divide3-affine-by-translation"
7550 );
7551 return divide_matrix3_by_affine_translation(left, &right);
7552 }
7553 if right_linear_is_diagonal {
7554 crate::trace_dispatch!(
7555 "hyperlattice_matrix",
7556 "helper",
7557 "right-divide3-affine-linear-diagonal"
7558 );
7559 return divide_matrix3_by_affine_linear_diagonal(left, &right);
7560 }
7561 return divide_matrix3_by_affine(left, &right);
7562 }
7563 if !prefer_shared_adjugate_right_division(&left, &right) {
7564 crate::trace_dispatch!(
7565 "hyperlattice_matrix",
7566 "helper",
7567 "right-divide3-gauss-jordan"
7568 );
7569 return Ok(transpose_array3(solve_left_system3(
7570 transpose_array3(right),
7571 transpose_array3(left),
7572 )?));
7573 }
7574
7575 crate::trace_dispatch!(
7576 "hyperlattice_matrix",
7577 "helper",
7578 "right-divide3-shared-adjugate"
7579 );
7580 let (adjugate, det) = matrix3_adjugate_and_determinant(&right);
7587 let inv_det = det.inverse()?;
7588 Ok(scale_matrix3(
7589 multiply_arrays3_with_exact_dense_certificate(left, adjugate),
7590 &inv_det,
7591 ))
7592}
7593
7594fn right_divide_matrix3_ref(
7595 left: &[[Real; 3]; 3],
7596 right: &[[Real; 3]; 3],
7597) -> BlasResult<[[Real; 3]; 3]> {
7598 let right_facts = matrix3_facts(right);
7599
7600 if right_facts.is_identity {
7601 crate::trace_dispatch!(
7602 "hyperlattice_matrix",
7603 "helper",
7604 "right-divide3-ref-identity"
7605 );
7606 return Ok(left.clone());
7607 }
7608 if right_facts.is_diagonal {
7609 crate::trace_dispatch!(
7610 "hyperlattice_matrix",
7611 "helper",
7612 "right-divide3-ref-diagonal"
7613 );
7614 return divide_matrix3_by_diagonal(left.clone(), right);
7615 }
7616 if right_facts.is_affine_translation {
7617 let left_facts = matrix3_facts(left);
7618 if left_facts.is_affine {
7619 crate::trace_dispatch!(
7620 "hyperlattice_matrix",
7621 "helper",
7622 "right-divide3-ref-affine-left-affine-translation"
7623 );
7624 return divide_matrix3_affine_by_affine_ref_translation(left, right);
7625 }
7626 crate::trace_dispatch!(
7627 "hyperlattice_matrix",
7628 "helper",
7629 "right-divide3-ref-affine-by-translation"
7630 );
7631 return divide_matrix3_by_affine_ref_translation(left, right);
7632 }
7633 if right_facts.is_affine && right_facts.is_upper_triangular {
7634 let left_facts = matrix3_facts(left);
7635 if left_facts.is_affine {
7636 crate::trace_dispatch!(
7637 "hyperlattice_matrix",
7638 "helper",
7639 "right-divide3-ref-affine-left-affine-upper-triangular"
7640 );
7641 return divide_matrix3_affine_by_affine_upper_triangular(left.clone(), right);
7642 }
7643 crate::trace_dispatch!(
7644 "hyperlattice_matrix",
7645 "helper",
7646 "right-divide3-ref-affine-upper-triangular"
7647 );
7648 return divide_matrix3_by_affine_upper_triangular(left.clone(), right);
7649 }
7650 if right_facts.is_upper_triangular {
7651 crate::trace_dispatch!(
7652 "hyperlattice_matrix",
7653 "helper",
7654 "right-divide3-ref-upper-triangular"
7655 );
7656 return divide_matrix3_by_upper_triangular(left.clone(), right);
7657 }
7658 if right_facts.is_lower_triangular {
7659 crate::trace_dispatch!(
7660 "hyperlattice_matrix",
7661 "helper",
7662 "right-divide3-ref-lower-triangular"
7663 );
7664 return divide_matrix3_by_lower_triangular(left.clone(), right);
7665 }
7666 if right_facts.is_affine {
7667 let left_facts = matrix3_facts(left);
7670 let left_is_affine = left_facts.is_affine;
7671 let right_linear_is_diagonal = right_facts.linear_is_diagonal;
7672 let right_is_affine_translation = right_facts.is_affine_translation;
7673 crate::trace_dispatch!("hyperlattice_matrix", "helper", "right-divide3-ref-affine");
7674 if left_is_affine {
7677 if right_is_affine_translation {
7678 crate::trace_dispatch!(
7679 "hyperlattice_matrix",
7680 "helper",
7681 "right-divide3-ref-affine-left-affine-translation"
7682 );
7683 return divide_matrix3_affine_by_affine_ref_translation(left, right);
7684 }
7685 if right_linear_is_diagonal {
7686 crate::trace_dispatch!(
7687 "hyperlattice_matrix",
7688 "helper",
7689 "right-divide3-ref-affine-left-affine-linear-diagonal"
7690 );
7691 return divide_matrix3_affine_by_affine_ref_linear_diagonal(left, right);
7692 }
7693 crate::trace_dispatch!(
7694 "hyperlattice_matrix",
7695 "helper",
7696 "right-divide3-ref-affine-left-affine"
7697 );
7698 return divide_matrix3_affine_by_affine_ref_no_translation(left, right);
7699 }
7700 if right_is_affine_translation {
7701 crate::trace_dispatch!(
7702 "hyperlattice_matrix",
7703 "helper",
7704 "right-divide3-ref-affine-by-translation"
7705 );
7706 return divide_matrix3_by_affine_ref_translation(left, right);
7707 }
7708 if right_linear_is_diagonal {
7709 crate::trace_dispatch!(
7710 "hyperlattice_matrix",
7711 "helper",
7712 "right-divide3-ref-affine-linear-diagonal"
7713 );
7714 return divide_matrix3_by_affine_ref_linear_diagonal(left, right);
7715 }
7716 return divide_matrix3_by_affine_ref_no_translation(left, right);
7717 }
7718 if !prefer_shared_adjugate_right_division_ref3(left, right) {
7719 crate::trace_dispatch!(
7720 "hyperlattice_matrix",
7721 "helper",
7722 "right-divide3-ref-gauss-jordan"
7723 );
7724 return Ok(transpose_array3(solve_left_system3(
7728 transpose_array3_ref(right),
7729 transpose_array3_ref(left),
7730 )?));
7731 }
7732
7733 crate::trace_dispatch!(
7734 "hyperlattice_matrix",
7735 "helper",
7736 "right-divide3-ref-shared-adjugate"
7737 );
7738 let (adjugate, det) = matrix3_adjugate_and_determinant(right);
7743 let inv_det = det.inverse()?;
7744 Ok(scale_matrix3(
7745 multiply_arrays3_ref_with_exact_dense_certificate(left, &adjugate),
7746 &inv_det,
7747 ))
7748}
7749
7750fn right_divide_matrix3_checked(
7751 left: [[Real; 3]; 3],
7752 right: [[Real; 3]; 3],
7753) -> CheckedBlasResult<[[Real; 3]; 3]> {
7754 let right_facts = matrix3_facts(&right);
7755
7756 if right_facts.is_identity {
7757 crate::trace_dispatch!(
7758 "hyperlattice_matrix",
7759 "helper",
7760 "right-divide3-checked-identity"
7761 );
7762 return Ok(left);
7763 }
7764 if right_facts.is_diagonal {
7765 crate::trace_dispatch!(
7766 "hyperlattice_matrix",
7767 "helper",
7768 "right-divide3-checked-diagonal"
7769 );
7770 return divide_matrix3_by_diagonal_checked(left, &right);
7771 }
7772 if right_facts.is_affine_translation {
7773 let left_facts = matrix3_facts(&left);
7774 if left_facts.is_affine {
7775 crate::trace_dispatch!(
7776 "hyperlattice_matrix",
7777 "helper",
7778 "right-divide3-checked-affine-left-affine-translation"
7779 );
7780 return divide_matrix3_affine_by_affine_translation(left, &right);
7781 }
7782 crate::trace_dispatch!(
7783 "hyperlattice_matrix",
7784 "helper",
7785 "right-divide3-checked-affine-by-translation"
7786 );
7787 return divide_matrix3_by_affine_translation(left, &right);
7788 }
7789 if right_facts.is_affine && right_facts.is_upper_triangular {
7790 let left_facts = matrix3_facts(&left);
7791 if left_facts.is_affine {
7792 crate::trace_dispatch!(
7793 "hyperlattice_matrix",
7794 "helper",
7795 "right-divide3-checked-affine-left-affine-upper-triangular"
7796 );
7797 return divide_matrix3_affine_by_affine_upper_triangular_checked(left, &right);
7798 }
7799 crate::trace_dispatch!(
7800 "hyperlattice_matrix",
7801 "helper",
7802 "right-divide3-checked-affine-upper-triangular"
7803 );
7804 return divide_matrix3_by_affine_upper_triangular_checked(left, &right);
7805 }
7806 if right_facts.is_upper_triangular {
7807 crate::trace_dispatch!(
7808 "hyperlattice_matrix",
7809 "helper",
7810 "right-divide3-checked-upper-triangular"
7811 );
7812 return divide_matrix3_by_upper_triangular_checked(left, &right);
7813 }
7814 if right_facts.is_lower_triangular {
7815 crate::trace_dispatch!(
7816 "hyperlattice_matrix",
7817 "helper",
7818 "right-divide3-checked-lower-triangular"
7819 );
7820 return divide_matrix3_by_lower_triangular_checked(left, &right);
7821 }
7822 if right_facts.is_affine {
7823 let left_facts = matrix3_facts(&left);
7828 let left_is_affine = left_facts.is_affine;
7829 let right_linear_is_diagonal = right_facts.linear_is_diagonal;
7830 crate::trace_dispatch!(
7831 "hyperlattice_matrix",
7832 "helper",
7833 "right-divide3-checked-affine"
7834 );
7835 if left_is_affine {
7839 if right_linear_is_diagonal {
7840 crate::trace_dispatch!(
7841 "hyperlattice_matrix",
7842 "helper",
7843 "right-divide3-checked-affine-left-affine-linear-diagonal"
7844 );
7845 return divide_matrix3_affine_by_affine_linear_diagonal_checked(left, &right);
7846 }
7847 crate::trace_dispatch!(
7848 "hyperlattice_matrix",
7849 "helper",
7850 "right-divide3-checked-affine-left-affine"
7851 );
7852 return divide_matrix3_affine_by_affine_checked(left, &right);
7853 }
7854 if right_linear_is_diagonal {
7855 crate::trace_dispatch!(
7856 "hyperlattice_matrix",
7857 "helper",
7858 "right-divide3-checked-affine-linear-diagonal"
7859 );
7860 return divide_matrix3_by_affine_linear_diagonal_checked(left, &right);
7861 }
7862 return divide_matrix3_by_affine_checked(left, &right);
7863 }
7864 if !prefer_shared_adjugate_right_division(&left, &right) {
7865 crate::trace_dispatch!(
7866 "hyperlattice_matrix",
7867 "helper",
7868 "right-divide3-checked-gauss-jordan"
7869 );
7870 return Ok(transpose_array3(solve_left_system3_checked(
7871 transpose_array3(right),
7872 transpose_array3(left),
7873 )?));
7874 }
7875
7876 crate::trace_dispatch!(
7877 "hyperlattice_matrix",
7878 "helper",
7879 "right-divide3-checked-shared-adjugate"
7880 );
7881 let (adjugate, det) = matrix3_adjugate_and_determinant(&right);
7882 require_known_nonzero(&det)?;
7883 let inv_det = det.inverse()?;
7884 Ok(scale_matrix3(
7885 multiply_arrays3_with_exact_dense_certificate(left, adjugate),
7886 &inv_det,
7887 ))
7888}
7889
7890fn right_divide_matrix3_checked_with_abort(
7891 left: [[Real; 3]; 3],
7892 right: [[Real; 3]; 3],
7893 signal: &AbortSignal,
7894) -> CheckedBlasResult<[[Real; 3]; 3]> {
7895 let right_facts = matrix3_facts(&right);
7896
7897 if right_facts.is_identity {
7898 crate::trace_dispatch!(
7899 "hyperlattice_matrix",
7900 "helper",
7901 "right-divide3-checked-abort-identity"
7902 );
7903 return Ok(left);
7904 }
7905 if right_facts.is_diagonal {
7906 crate::trace_dispatch!(
7907 "hyperlattice_matrix",
7908 "helper",
7909 "right-divide3-checked-abort-diagonal"
7910 );
7911 return divide_matrix3_by_diagonal_checked_with_abort(left, &right, signal);
7912 }
7913 if right_facts.is_affine_translation {
7914 let left_facts = matrix3_facts(&left);
7915 if left_facts.is_affine {
7916 crate::trace_dispatch!(
7917 "hyperlattice_matrix",
7918 "helper",
7919 "right-divide3-checked-abort-affine-left-affine-translation"
7920 );
7921 return divide_matrix3_affine_by_affine_translation(left, &right);
7922 }
7923 crate::trace_dispatch!(
7924 "hyperlattice_matrix",
7925 "helper",
7926 "right-divide3-checked-abort-affine-by-translation"
7927 );
7928 return divide_matrix3_by_affine_translation(left, &right);
7929 }
7930 if right_facts.is_affine && right_facts.is_upper_triangular {
7931 let left_facts = matrix3_facts(&left);
7932 if left_facts.is_affine {
7933 crate::trace_dispatch!(
7934 "hyperlattice_matrix",
7935 "helper",
7936 "right-divide3-checked-abort-affine-left-affine-upper-triangular"
7937 );
7938 return divide_matrix3_affine_by_affine_upper_triangular_checked_with_abort(
7939 left, &right, signal,
7940 );
7941 }
7942 crate::trace_dispatch!(
7943 "hyperlattice_matrix",
7944 "helper",
7945 "right-divide3-checked-abort-affine-upper-triangular"
7946 );
7947 return divide_matrix3_by_affine_upper_triangular_checked_with_abort(left, &right, signal);
7948 }
7949 if right_facts.is_upper_triangular {
7950 crate::trace_dispatch!(
7951 "hyperlattice_matrix",
7952 "helper",
7953 "right-divide3-checked-abort-upper-triangular"
7954 );
7955 return divide_matrix3_by_upper_triangular_checked_with_abort(left, &right, signal);
7956 }
7957 if right_facts.is_lower_triangular {
7958 crate::trace_dispatch!(
7959 "hyperlattice_matrix",
7960 "helper",
7961 "right-divide3-checked-abort-lower-triangular"
7962 );
7963 return divide_matrix3_by_lower_triangular_checked_with_abort(left, &right, signal);
7964 }
7965 if right_facts.is_affine {
7966 let left_facts = matrix3_facts(&left);
7969 let left_is_affine = left_facts.is_affine;
7970 let right_linear_is_diagonal = right_facts.linear_is_diagonal;
7971 crate::trace_dispatch!(
7972 "hyperlattice_matrix",
7973 "helper",
7974 "right-divide3-checked-abort-affine"
7975 );
7976 if left_is_affine {
7979 if right_linear_is_diagonal {
7980 crate::trace_dispatch!(
7981 "hyperlattice_matrix",
7982 "helper",
7983 "right-divide3-checked-abort-affine-left-affine-linear-diagonal"
7984 );
7985 return divide_matrix3_affine_by_affine_linear_diagonal_checked_with_abort(
7986 left, &right, signal,
7987 );
7988 }
7989 crate::trace_dispatch!(
7990 "hyperlattice_matrix",
7991 "helper",
7992 "right-divide3-checked-abort-affine-left-affine"
7993 );
7994 return divide_matrix3_affine_by_affine_checked_with_abort(left, &right, signal);
7995 }
7996 if right_linear_is_diagonal {
7997 crate::trace_dispatch!(
7998 "hyperlattice_matrix",
7999 "helper",
8000 "right-divide3-checked-abort-affine-linear-diagonal"
8001 );
8002 return divide_matrix3_by_affine_linear_diagonal_checked_with_abort(
8003 left, &right, signal,
8004 );
8005 }
8006 return divide_matrix3_by_affine_checked_with_abort(left, &right, signal);
8007 }
8008 if !prefer_shared_adjugate_right_division(&left, &right) {
8009 crate::trace_dispatch!(
8010 "hyperlattice_matrix",
8011 "helper",
8012 "right-divide3-checked-abort-gauss-jordan"
8013 );
8014 return Ok(transpose_array3(solve_left_system3_checked_with_abort(
8015 transpose_array3(right),
8016 transpose_array3(left),
8017 signal,
8018 )?));
8019 }
8020
8021 crate::trace_dispatch!(
8022 "hyperlattice_matrix",
8023 "helper",
8024 "right-divide3-checked-abort-shared-adjugate"
8025 );
8026 let (adjugate, det) = matrix3_adjugate_and_determinant(&right);
8027 let det = with_abort(det, signal);
8028 require_known_nonzero(&det)?;
8029 let inv_det = det.inverse()?;
8030 Ok(scale_matrix3(
8031 multiply_arrays3_with_exact_dense_certificate(left, adjugate),
8032 &inv_det,
8033 ))
8034}
8035
8036fn right_divide_matrix3_prepared(
8037 left: [[Real; 3]; 3],
8038 prepared: &mut PreparedRightDivisor3,
8039) -> BlasResult<[[Real; 3]; 3]> {
8040 let right_facts = prepared.facts;
8041
8042 if right_facts.is_identity {
8043 crate::trace_dispatch!(
8044 "hyperlattice_matrix",
8045 "helper",
8046 "right-divide3-prepared-identity"
8047 );
8048 return Ok(left);
8049 }
8050 if right_facts.is_diagonal {
8051 crate::trace_dispatch!(
8052 "hyperlattice_matrix",
8053 "helper",
8054 "right-divide3-prepared-diagonal"
8055 );
8056 return divide_matrix3_by_diagonal(left, &prepared.divisor.0);
8057 }
8058 if right_facts.is_affine_translation {
8059 let left_facts = matrix3_facts(&left);
8060 if left_facts.is_affine {
8061 crate::trace_dispatch!(
8062 "hyperlattice_matrix",
8063 "helper",
8064 "right-divide3-prepared-affine-left-affine-translation"
8065 );
8066 return divide_matrix3_affine_by_affine_translation(left, &prepared.divisor.0);
8067 }
8068 crate::trace_dispatch!(
8069 "hyperlattice_matrix",
8070 "helper",
8071 "right-divide3-prepared-affine-by-translation"
8072 );
8073 return divide_matrix3_by_affine_translation(left, &prepared.divisor.0);
8074 }
8075 if right_facts.is_affine && right_facts.is_upper_triangular {
8076 let left_facts = matrix3_facts(&left);
8077 if left_facts.is_affine {
8078 crate::trace_dispatch!(
8079 "hyperlattice_matrix",
8080 "helper",
8081 "right-divide3-prepared-affine-left-affine-upper-triangular"
8082 );
8083 return divide_matrix3_affine_by_affine_upper_triangular(left, &prepared.divisor.0);
8084 }
8085 crate::trace_dispatch!(
8086 "hyperlattice_matrix",
8087 "helper",
8088 "right-divide3-prepared-affine-upper-triangular"
8089 );
8090 return divide_matrix3_by_affine_upper_triangular(left, &prepared.divisor.0);
8091 }
8092 if right_facts.is_upper_triangular {
8093 crate::trace_dispatch!(
8094 "hyperlattice_matrix",
8095 "helper",
8096 "right-divide3-prepared-upper-triangular"
8097 );
8098 return divide_matrix3_by_upper_triangular(left, &prepared.divisor.0);
8099 }
8100 if right_facts.is_lower_triangular {
8101 crate::trace_dispatch!(
8102 "hyperlattice_matrix",
8103 "helper",
8104 "right-divide3-prepared-lower-triangular"
8105 );
8106 return divide_matrix3_by_lower_triangular(left, &prepared.divisor.0);
8107 }
8108 if right_facts.is_affine {
8109 let left_facts = matrix3_facts(&left);
8112 let left_is_affine = left_facts.is_affine;
8113 let right_linear_is_diagonal = right_facts.linear_is_diagonal;
8114 let right_is_affine_translation = right_facts.is_affine_translation;
8115 crate::trace_dispatch!(
8116 "hyperlattice_matrix",
8117 "helper",
8118 "right-divide3-prepared-affine"
8119 );
8120 if left_is_affine {
8121 if right_is_affine_translation {
8122 crate::trace_dispatch!(
8123 "hyperlattice_matrix",
8124 "helper",
8125 "right-divide3-prepared-affine-left-affine-translation"
8126 );
8127 return divide_matrix3_affine_by_affine_translation(left, &prepared.divisor.0);
8128 }
8129 if right_linear_is_diagonal {
8130 crate::trace_dispatch!(
8131 "hyperlattice_matrix",
8132 "helper",
8133 "right-divide3-prepared-affine-left-affine-linear-diagonal"
8134 );
8135 return divide_matrix3_affine_by_affine_linear_diagonal(left, &prepared.divisor.0);
8136 }
8137 crate::trace_dispatch!(
8138 "hyperlattice_matrix",
8139 "helper",
8140 "right-divide3-prepared-affine-left-affine"
8141 );
8142 return divide_matrix3_affine_by_affine(left, &prepared.divisor.0);
8143 }
8144 if right_is_affine_translation {
8145 crate::trace_dispatch!(
8146 "hyperlattice_matrix",
8147 "helper",
8148 "right-divide3-prepared-affine-by-translation"
8149 );
8150 return divide_matrix3_by_affine_translation(left, &prepared.divisor.0);
8151 }
8152 if right_linear_is_diagonal {
8153 crate::trace_dispatch!(
8154 "hyperlattice_matrix",
8155 "helper",
8156 "right-divide3-prepared-affine-linear-diagonal"
8157 );
8158 return divide_matrix3_by_affine_linear_diagonal(left, &prepared.divisor.0);
8159 }
8160 return divide_matrix3_by_affine(left, &prepared.divisor.0);
8161 }
8162 if !prepared.can_use_shared_adjugate(&left) {
8163 crate::trace_dispatch!(
8164 "hyperlattice_matrix",
8165 "helper",
8166 "right-divide3-prepared-gauss-jordan"
8167 );
8168 return Ok(transpose_array3(solve_left_system3(
8169 transpose_array3_ref(&prepared.divisor.0),
8170 transpose_array3(left),
8171 )?));
8172 }
8173
8174 crate::trace_dispatch!(
8179 "hyperlattice_matrix",
8180 "helper",
8181 "right-divide3-prepared-shared-adjugate"
8182 );
8183 let _ = prepared.prepare_shared_adjugate()?;
8184 let inv_det = prepared
8185 .reciprocal_determinant
8186 .as_ref()
8187 .expect("reciprocal determinant cache should be present");
8188 let adjugate = prepared
8189 .adjugate
8190 .as_ref()
8191 .expect("adjugate cache should be present");
8192 Ok(scale_matrix3(
8193 multiply_arrays3_rhs_ref_with_exact_dense_certificate(left, adjugate),
8194 inv_det,
8195 ))
8196}
8197
8198fn right_divide_matrix3_prepared_checked(
8199 left: [[Real; 3]; 3],
8200 prepared: &mut PreparedRightDivisor3,
8201) -> CheckedBlasResult<[[Real; 3]; 3]> {
8202 let right_facts = prepared.facts;
8203
8204 if right_facts.is_identity {
8205 crate::trace_dispatch!(
8206 "hyperlattice_matrix",
8207 "helper",
8208 "right-divide3-prepared-checked-identity"
8209 );
8210 return Ok(left);
8211 }
8212 if right_facts.is_diagonal {
8213 crate::trace_dispatch!(
8214 "hyperlattice_matrix",
8215 "helper",
8216 "right-divide3-prepared-checked-diagonal"
8217 );
8218 return divide_matrix3_by_diagonal_checked(left, &prepared.divisor.0);
8219 }
8220 if right_facts.is_affine_translation {
8221 let left_facts = matrix3_facts(&left);
8222 if left_facts.is_affine {
8223 crate::trace_dispatch!(
8224 "hyperlattice_matrix",
8225 "helper",
8226 "right-divide3-prepared-checked-affine-left-affine-translation"
8227 );
8228 return divide_matrix3_affine_by_affine_translation(left, &prepared.divisor.0);
8229 }
8230 crate::trace_dispatch!(
8231 "hyperlattice_matrix",
8232 "helper",
8233 "right-divide3-prepared-checked-affine-by-translation"
8234 );
8235 return divide_matrix3_by_affine_translation(left, &prepared.divisor.0);
8236 }
8237 if right_facts.is_affine && right_facts.is_upper_triangular {
8238 let left_facts = matrix3_facts(&left);
8239 if left_facts.is_affine {
8240 crate::trace_dispatch!(
8241 "hyperlattice_matrix",
8242 "helper",
8243 "right-divide3-prepared-checked-affine-left-affine-upper-triangular"
8244 );
8245 return divide_matrix3_affine_by_affine_upper_triangular_checked(
8246 left,
8247 &prepared.divisor.0,
8248 );
8249 }
8250 crate::trace_dispatch!(
8251 "hyperlattice_matrix",
8252 "helper",
8253 "right-divide3-prepared-checked-affine-upper-triangular"
8254 );
8255 return divide_matrix3_by_affine_upper_triangular_checked(left, &prepared.divisor.0);
8256 }
8257 if right_facts.is_upper_triangular {
8258 crate::trace_dispatch!(
8259 "hyperlattice_matrix",
8260 "helper",
8261 "right-divide3-prepared-checked-upper-triangular"
8262 );
8263 return divide_matrix3_by_upper_triangular_checked(left, &prepared.divisor.0);
8264 }
8265 if right_facts.is_lower_triangular {
8266 crate::trace_dispatch!(
8267 "hyperlattice_matrix",
8268 "helper",
8269 "right-divide3-prepared-checked-lower-triangular"
8270 );
8271 return divide_matrix3_by_lower_triangular_checked(left, &prepared.divisor.0);
8272 }
8273 if right_facts.is_affine {
8274 let left_facts = matrix3_facts(&left);
8277 let left_is_affine = left_facts.is_affine;
8278 let right_linear_is_diagonal = right_facts.linear_is_diagonal;
8279 crate::trace_dispatch!(
8280 "hyperlattice_matrix",
8281 "helper",
8282 "right-divide3-prepared-checked-affine"
8283 );
8284 if left_is_affine {
8285 if right_linear_is_diagonal {
8286 crate::trace_dispatch!(
8287 "hyperlattice_matrix",
8288 "helper",
8289 "right-divide3-prepared-checked-affine-left-affine-linear-diagonal"
8290 );
8291 return divide_matrix3_affine_by_affine_linear_diagonal_checked(
8292 left,
8293 &prepared.divisor.0,
8294 );
8295 }
8296 crate::trace_dispatch!(
8297 "hyperlattice_matrix",
8298 "helper",
8299 "right-divide3-prepared-checked-affine-left-affine"
8300 );
8301 return divide_matrix3_affine_by_affine_checked(left, &prepared.divisor.0);
8302 }
8303 if right_linear_is_diagonal {
8304 crate::trace_dispatch!(
8305 "hyperlattice_matrix",
8306 "helper",
8307 "right-divide3-prepared-checked-affine-linear-diagonal"
8308 );
8309 return divide_matrix3_by_affine_linear_diagonal_checked(left, &prepared.divisor.0);
8310 }
8311 return divide_matrix3_by_affine_checked(left, &prepared.divisor.0);
8312 }
8313 if !prepared.can_use_shared_adjugate(&left) {
8314 crate::trace_dispatch!(
8315 "hyperlattice_matrix",
8316 "helper",
8317 "right-divide3-prepared-checked-gauss-jordan"
8318 );
8319 return Ok(transpose_array3(solve_left_system3_checked(
8320 transpose_array3_ref(&prepared.divisor.0),
8321 transpose_array3(left),
8322 )?));
8323 }
8324
8325 crate::trace_dispatch!(
8326 "hyperlattice_matrix",
8327 "helper",
8328 "right-divide3-prepared-checked-shared-adjugate"
8329 );
8330 let _ = prepared.prepare_shared_adjugate_checked()?;
8331 let inv_det = prepared
8332 .reciprocal_determinant
8333 .as_ref()
8334 .expect("reciprocal determinant cache should be present");
8335 let adjugate = prepared
8336 .adjugate
8337 .as_ref()
8338 .expect("adjugate cache should be present");
8339 Ok(scale_matrix3(
8340 multiply_arrays3_rhs_ref_with_exact_dense_certificate(left, adjugate),
8341 inv_det,
8342 ))
8343}
8344
8345fn right_divide_matrix3_prepared_checked_with_abort(
8346 left: [[Real; 3]; 3],
8347 prepared: &mut PreparedRightDivisor3,
8348 signal: &AbortSignal,
8349) -> CheckedBlasResult<[[Real; 3]; 3]> {
8350 let right_facts = prepared.facts;
8351
8352 if right_facts.is_identity {
8353 crate::trace_dispatch!(
8354 "hyperlattice_matrix",
8355 "helper",
8356 "right-divide3-prepared-checked-abort-identity"
8357 );
8358 return Ok(left);
8359 }
8360 if right_facts.is_diagonal {
8361 crate::trace_dispatch!(
8362 "hyperlattice_matrix",
8363 "helper",
8364 "right-divide3-prepared-checked-abort-diagonal"
8365 );
8366 return divide_matrix3_by_diagonal_checked_with_abort(left, &prepared.divisor.0, signal);
8367 }
8368 if right_facts.is_affine_translation {
8369 let left_facts = matrix3_facts(&left);
8370 if left_facts.is_affine {
8371 crate::trace_dispatch!(
8372 "hyperlattice_matrix",
8373 "helper",
8374 "right-divide3-prepared-checked-abort-affine-left-affine-translation"
8375 );
8376 return divide_matrix3_affine_by_affine_translation(left, &prepared.divisor.0);
8377 }
8378 crate::trace_dispatch!(
8379 "hyperlattice_matrix",
8380 "helper",
8381 "right-divide3-prepared-checked-abort-affine-by-translation"
8382 );
8383 return divide_matrix3_by_affine_translation(left, &prepared.divisor.0);
8384 }
8385 if true && right_facts.is_affine && right_facts.is_upper_triangular {
8386 let left_facts = matrix3_facts(&left);
8387 if left_facts.is_affine {
8388 crate::trace_dispatch!(
8389 "hyperlattice_matrix",
8390 "helper",
8391 "right-divide3-prepared-checked-abort-affine-left-affine-upper-triangular"
8392 );
8393 return divide_matrix3_affine_by_affine_upper_triangular_checked_with_abort(
8394 left,
8395 &prepared.divisor.0,
8396 signal,
8397 );
8398 }
8399 crate::trace_dispatch!(
8400 "hyperlattice_matrix",
8401 "helper",
8402 "right-divide3-prepared-checked-abort-affine-upper-triangular"
8403 );
8404 return divide_matrix3_by_affine_upper_triangular_checked_with_abort(
8405 left,
8406 &prepared.divisor.0,
8407 signal,
8408 );
8409 }
8410 if right_facts.is_upper_triangular {
8411 crate::trace_dispatch!(
8412 "hyperlattice_matrix",
8413 "helper",
8414 "right-divide3-prepared-checked-abort-upper-triangular"
8415 );
8416 return divide_matrix3_by_upper_triangular_checked_with_abort(
8417 left,
8418 &prepared.divisor.0,
8419 signal,
8420 );
8421 }
8422 if right_facts.is_lower_triangular {
8423 crate::trace_dispatch!(
8424 "hyperlattice_matrix",
8425 "helper",
8426 "right-divide3-prepared-checked-abort-lower-triangular"
8427 );
8428 return divide_matrix3_by_lower_triangular_checked_with_abort(
8429 left,
8430 &prepared.divisor.0,
8431 signal,
8432 );
8433 }
8434 if right_facts.is_affine {
8435 let left_facts = matrix3_facts(&left);
8439 let left_is_affine = left_facts.is_affine;
8440 let right_linear_is_diagonal = right_facts.linear_is_diagonal;
8441 crate::trace_dispatch!(
8442 "hyperlattice_matrix",
8443 "helper",
8444 "right-divide3-prepared-checked-abort-affine"
8445 );
8446 if left_is_affine {
8447 if right_linear_is_diagonal {
8448 crate::trace_dispatch!(
8449 "hyperlattice_matrix",
8450 "helper",
8451 "right-divide3-prepared-checked-abort-affine-left-affine-linear-diagonal"
8452 );
8453 return divide_matrix3_affine_by_affine_linear_diagonal_checked_with_abort(
8454 left,
8455 &prepared.divisor.0,
8456 signal,
8457 );
8458 }
8459 crate::trace_dispatch!(
8460 "hyperlattice_matrix",
8461 "helper",
8462 "right-divide3-prepared-checked-abort-affine-left-affine"
8463 );
8464 return divide_matrix3_affine_by_affine_checked_with_abort(
8465 left,
8466 &prepared.divisor.0,
8467 signal,
8468 );
8469 }
8470 if right_linear_is_diagonal {
8471 crate::trace_dispatch!(
8472 "hyperlattice_matrix",
8473 "helper",
8474 "right-divide3-prepared-checked-abort-affine-linear-diagonal"
8475 );
8476 return divide_matrix3_by_affine_linear_diagonal_checked_with_abort(
8477 left,
8478 &prepared.divisor.0,
8479 signal,
8480 );
8481 }
8482 return divide_matrix3_by_affine_checked_with_abort(left, &prepared.divisor.0, signal);
8483 }
8484 if !prepared.can_use_shared_adjugate(&left) {
8485 crate::trace_dispatch!(
8486 "hyperlattice_matrix",
8487 "helper",
8488 "right-divide3-prepared-checked-abort-gauss-jordan"
8489 );
8490 return Ok(transpose_array3(solve_left_system3_checked_with_abort(
8491 transpose_array3_ref(&prepared.divisor.0),
8492 transpose_array3(left),
8493 signal,
8494 )?));
8495 }
8496
8497 crate::trace_dispatch!(
8498 "hyperlattice_matrix",
8499 "helper",
8500 "right-divide3-prepared-checked-abort-shared-adjugate"
8501 );
8502 let _ = prepared.prepare_shared_adjugate_checked_with_abort(signal)?;
8503 let inv_det = prepared
8504 .reciprocal_determinant
8505 .as_ref()
8506 .expect("reciprocal determinant cache should be present");
8507 let adjugate = prepared
8508 .adjugate
8509 .as_ref()
8510 .expect("adjugate cache should be present");
8511 Ok(scale_matrix3(
8512 multiply_arrays3_rhs_ref_with_exact_dense_certificate(left, adjugate),
8513 inv_det,
8514 ))
8515}
8516
8517fn right_divide_matrix4(left: [[Real; 4]; 4], right: [[Real; 4]; 4]) -> BlasResult<[[Real; 4]; 4]> {
8518 if can_use_dense_exact_shared_adjugate4(&right) {
8519 crate::trace_dispatch!(
8520 "hyperlattice_matrix",
8521 "helper",
8522 "right-divide4-dense-exact-shared-adjugate"
8523 );
8524 return right_divide_matrix4_dense_exact_shared(&left, &right);
8525 }
8526 let right_facts = matrix4_facts(&right);
8527 if right_facts.is_identity {
8528 crate::trace_dispatch!("hyperlattice_matrix", "helper", "right-divide4-identity");
8529 return Ok(left);
8530 }
8531 if right_facts.is_diagonal {
8532 crate::trace_dispatch!("hyperlattice_matrix", "helper", "right-divide4-diagonal");
8533 return divide_matrix4_by_diagonal(left, &right);
8534 }
8535 if right_facts.is_affine_translation {
8536 let left_facts = matrix4_facts(&left);
8537 if left_facts.is_affine {
8538 crate::trace_dispatch!(
8539 "hyperlattice_matrix",
8540 "helper",
8541 "right-divide4-affine-left-affine-translation"
8542 );
8543 return divide_matrix4_affine_by_affine_translation(left, &right);
8544 }
8545 crate::trace_dispatch!(
8546 "hyperlattice_matrix",
8547 "helper",
8548 "right-divide4-affine-by-translation"
8549 );
8550 return divide_matrix4_by_affine_translation(left, &right);
8551 }
8552 if true && right_facts.is_affine && right_facts.is_upper_triangular {
8553 let left_facts = matrix4_facts(&left);
8554 if left_facts.is_affine {
8555 crate::trace_dispatch!(
8556 "hyperlattice_matrix",
8557 "helper",
8558 "right-divide4-affine-left-affine-upper-triangular"
8559 );
8560 return divide_matrix4_affine_by_affine_upper_triangular(left, &right);
8561 }
8562 crate::trace_dispatch!(
8563 "hyperlattice_matrix",
8564 "helper",
8565 "right-divide4-affine-upper-triangular"
8566 );
8567 return divide_matrix4_by_affine_upper_triangular(left, &right);
8568 }
8569 if right_facts.is_upper_triangular {
8570 crate::trace_dispatch!(
8576 "hyperlattice_matrix",
8577 "helper",
8578 "right-divide4-upper-triangular"
8579 );
8580 return divide_matrix4_by_upper_triangular(left, &right);
8581 }
8582 if right_facts.is_lower_triangular {
8583 crate::trace_dispatch!(
8586 "hyperlattice_matrix",
8587 "helper",
8588 "right-divide4-lower-triangular"
8589 );
8590 return divide_matrix4_by_lower_triangular(left, &right);
8591 }
8592 if right_facts.is_affine {
8593 let left_facts = matrix4_facts(&left);
8598 let left_is_affine = left_facts.is_affine;
8599 let right_linear_is_diagonal = right_facts.linear_is_diagonal;
8600 let right_is_affine_translation = right_facts.is_affine_translation;
8601 crate::trace_dispatch!("hyperlattice_matrix", "helper", "right-divide4-affine");
8602 if left_is_affine {
8607 crate::trace_dispatch!(
8608 "hyperlattice_matrix",
8609 "helper",
8610 "right-divide4-affine-left-affine"
8611 );
8612 if right_is_affine_translation {
8613 crate::trace_dispatch!(
8614 "hyperlattice_matrix",
8615 "helper",
8616 "right-divide4-affine-left-affine-translation"
8617 );
8618 return divide_matrix4_affine_by_affine_translation(left, &right);
8619 }
8620 if right_linear_is_diagonal {
8621 crate::trace_dispatch!(
8622 "hyperlattice_matrix",
8623 "helper",
8624 "right-divide4-affine-left-affine-linear-diagonal"
8625 );
8626 return divide_matrix4_affine_by_affine_linear_diagonal(left, &right);
8627 }
8628 return divide_matrix4_affine_by_affine_no_translation(left, &right);
8629 }
8630 if right_is_affine_translation {
8631 crate::trace_dispatch!(
8632 "hyperlattice_matrix",
8633 "helper",
8634 "right-divide4-affine-by-translation"
8635 );
8636 return divide_matrix4_by_affine_translation(left, &right);
8637 }
8638 if right_linear_is_diagonal {
8639 crate::trace_dispatch!(
8640 "hyperlattice_matrix",
8641 "helper",
8642 "right-divide4-affine-linear-diagonal"
8643 );
8644 if right_facts.affine_linear_diagonal_is_definitely_nonzero {
8645 crate::trace_dispatch!(
8646 "hyperlattice_matrix",
8647 "helper",
8648 "right-divide4-affine-linear-diagonal-known-nonzero"
8649 );
8650 return divide_matrix4_by_affine_linear_diagonal(left, &right);
8651 }
8652 return divide_matrix4_by_affine_linear_diagonal_checked(left, &right);
8653 }
8654 return divide_matrix4_by_affine_no_translation(left, &right);
8655 }
8656 if !prefer_shared_adjugate_right_division(&left, &right) {
8657 crate::trace_dispatch!(
8658 "hyperlattice_matrix",
8659 "helper",
8660 "right-divide4-gauss-jordan"
8661 );
8662 return Ok(transpose_array4(solve_left_system4(
8663 transpose_array4(right),
8664 transpose_array4(left),
8665 )?));
8666 }
8667
8668 crate::trace_dispatch!(
8669 "hyperlattice_matrix",
8670 "helper",
8671 "right-divide4-shared-adjugate"
8672 );
8673 let dense_exact = true && right_facts.is_definitely_dense_for_inverse;
8674 let (s, c) = if dense_exact {
8675 matrix4_factors_dense_exact(&right)
8676 } else {
8677 matrix4_factors(&right)
8678 };
8679 let det = determinant4_from_factors(&s, &c);
8680 let inv_det = det.inverse()?;
8681 let adjugate = if dense_exact {
8682 matrix4_adjugate_from_factors_dense_exact(&right, &s, &c)
8683 } else {
8684 matrix4_adjugate_from_factors(&right, &s, &c)
8685 };
8686 Ok(scale_matrix4(
8687 multiply_arrays4_ref_with_dense_certificate(&left, &adjugate),
8688 &inv_det,
8689 ))
8690}
8691
8692#[inline]
8693fn can_use_dense_exact_shared_adjugate4(right: &[[Real; 4]; 4]) -> bool {
8694 true && matrix4_is_definitely_dense_for_inverse(right)
8695 && matrix4_exact_rational_kind(right) != ExactRationalKind::NonRational
8696}
8697
8698#[inline]
8699fn right_divide_matrix4_dense_exact_shared(
8700 left: &[[Real; 4]; 4],
8701 right: &[[Real; 4]; 4],
8702) -> BlasResult<[[Real; 4]; 4]> {
8703 let (s, c) = matrix4_factors_dense_exact_known_rational(right);
8704 let det = determinant4_from_factors_known_rational(&s, &c);
8705 let inv_det = det.inverse()?;
8706 let adjugate = matrix4_adjugate_from_factors_dense_exact_known_rational(right, &s, &c);
8707 let product = if matrix4_exact_rational_kind(left) != ExactRationalKind::NonRational {
8708 multiply_arrays4_dense_known_rational_ref(left, &adjugate)
8709 } else {
8710 multiply_arrays4_ref_with_dense_certificate(left, &adjugate)
8711 };
8712 Ok(scale_matrix4(product, &inv_det))
8713}
8714
8715#[inline]
8716fn right_divide_matrix4_dense_exact_shared_checked(
8717 left: &[[Real; 4]; 4],
8718 right: &[[Real; 4]; 4],
8719) -> CheckedBlasResult<[[Real; 4]; 4]> {
8720 let (s, c) = matrix4_factors_dense_exact_known_rational(right);
8721 let det = determinant4_from_factors_known_rational(&s, &c);
8722 require_known_nonzero(&det)?;
8723 let inv_det = det.inverse()?;
8724 let adjugate = matrix4_adjugate_from_factors_dense_exact_known_rational(right, &s, &c);
8725 let product = if matrix4_exact_rational_kind(left) != ExactRationalKind::NonRational {
8726 multiply_arrays4_dense_known_rational_ref(left, &adjugate)
8727 } else {
8728 multiply_arrays4_ref_with_dense_certificate(left, &adjugate)
8729 };
8730 Ok(scale_matrix4(product, &inv_det))
8731}
8732
8733#[inline]
8734fn right_divide_matrix4_dense_exact_shared_checked_with_abort(
8735 left: &[[Real; 4]; 4],
8736 right: &[[Real; 4]; 4],
8737 signal: &AbortSignal,
8738) -> CheckedBlasResult<[[Real; 4]; 4]> {
8739 let (s, c) = matrix4_factors_dense_exact_known_rational(right);
8740 let det = with_abort(determinant4_from_factors_known_rational(&s, &c), signal);
8741 require_known_nonzero(&det)?;
8742 let inv_det = det.inverse()?;
8743 let adjugate = matrix4_adjugate_from_factors_dense_exact_known_rational(right, &s, &c);
8744 let product = if matrix4_exact_rational_kind(left) != ExactRationalKind::NonRational {
8745 multiply_arrays4_dense_known_rational_ref(left, &adjugate)
8746 } else {
8747 multiply_arrays4_ref_with_dense_certificate(left, &adjugate)
8748 };
8749 Ok(scale_matrix4(product, &inv_det))
8750}
8751
8752fn right_divide_matrix4_prepared(
8753 left: [[Real; 4]; 4],
8754 prepared: &mut PreparedRightDivisor4,
8755) -> BlasResult<[[Real; 4]; 4]> {
8756 let right_facts = prepared.facts;
8757
8758 if right_facts.is_identity {
8759 crate::trace_dispatch!(
8760 "hyperlattice_matrix",
8761 "helper",
8762 "right-divide4-prepared-identity"
8763 );
8764 return Ok(left);
8765 }
8766 if right_facts.is_diagonal {
8767 crate::trace_dispatch!(
8768 "hyperlattice_matrix",
8769 "helper",
8770 "right-divide4-prepared-diagonal"
8771 );
8772 return divide_matrix4_by_diagonal(left, &prepared.divisor.0);
8773 }
8774 if right_facts.is_affine_translation {
8775 let left_facts = matrix4_facts(&left);
8776 if left_facts.is_affine {
8777 crate::trace_dispatch!(
8778 "hyperlattice_matrix",
8779 "helper",
8780 "right-divide4-prepared-affine-left-affine-translation"
8781 );
8782 return divide_matrix4_affine_by_affine_translation(left, &prepared.divisor.0);
8783 }
8784 crate::trace_dispatch!(
8785 "hyperlattice_matrix",
8786 "helper",
8787 "right-divide4-prepared-affine-by-translation"
8788 );
8789 return divide_matrix4_by_affine_translation(left, &prepared.divisor.0);
8790 }
8791 if true && right_facts.is_affine && right_facts.is_upper_triangular {
8792 let left_facts = matrix4_facts(&left);
8793 if left_facts.is_affine {
8794 crate::trace_dispatch!(
8795 "hyperlattice_matrix",
8796 "helper",
8797 "right-divide4-prepared-affine-left-affine-upper-triangular"
8798 );
8799 return divide_matrix4_affine_by_affine_upper_triangular(left, &prepared.divisor.0);
8800 }
8801 crate::trace_dispatch!(
8802 "hyperlattice_matrix",
8803 "helper",
8804 "right-divide4-prepared-affine-upper-triangular"
8805 );
8806 return divide_matrix4_by_affine_upper_triangular(left, &prepared.divisor.0);
8807 }
8808 if right_facts.is_upper_triangular {
8809 crate::trace_dispatch!(
8810 "hyperlattice_matrix",
8811 "helper",
8812 "right-divide4-prepared-upper-triangular"
8813 );
8814 return divide_matrix4_by_upper_triangular(left, &prepared.divisor.0);
8815 }
8816 if right_facts.is_lower_triangular {
8817 crate::trace_dispatch!(
8818 "hyperlattice_matrix",
8819 "helper",
8820 "right-divide4-prepared-lower-triangular"
8821 );
8822 return divide_matrix4_by_lower_triangular(left, &prepared.divisor.0);
8823 }
8824 if right_facts.is_affine {
8825 let left_facts = matrix4_facts(&left);
8828 let left_is_affine = left_facts.is_affine;
8829 let right_linear_is_diagonal = right_facts.linear_is_diagonal;
8830 let right_is_affine_translation = right_facts.is_affine_translation;
8831 crate::trace_dispatch!(
8832 "hyperlattice_matrix",
8833 "helper",
8834 "right-divide4-prepared-affine"
8835 );
8836 if left_is_affine {
8837 if right_is_affine_translation {
8838 crate::trace_dispatch!(
8839 "hyperlattice_matrix",
8840 "helper",
8841 "right-divide4-prepared-affine-left-affine-translation"
8842 );
8843 return divide_matrix4_affine_by_affine_translation(left, &prepared.divisor.0);
8844 }
8845 if right_linear_is_diagonal {
8846 crate::trace_dispatch!(
8847 "hyperlattice_matrix",
8848 "helper",
8849 "right-divide4-prepared-affine-left-affine-linear-diagonal"
8850 );
8851 return divide_matrix4_affine_by_affine_linear_diagonal(left, &prepared.divisor.0);
8852 }
8853 return divide_matrix4_affine_by_affine_no_translation(left, &prepared.divisor.0);
8854 }
8855 if right_is_affine_translation {
8856 crate::trace_dispatch!(
8857 "hyperlattice_matrix",
8858 "helper",
8859 "right-divide4-prepared-affine-by-translation"
8860 );
8861 return divide_matrix4_by_affine_translation(left, &prepared.divisor.0);
8862 }
8863 if right_linear_is_diagonal {
8864 crate::trace_dispatch!(
8865 "hyperlattice_matrix",
8866 "helper",
8867 "right-divide4-prepared-affine-linear-diagonal"
8868 );
8869 if right_facts.affine_linear_diagonal_is_definitely_nonzero {
8870 crate::trace_dispatch!(
8871 "hyperlattice_matrix",
8872 "helper",
8873 "right-divide4-prepared-affine-linear-diagonal-known-nonzero"
8874 );
8875 return divide_matrix4_by_affine_linear_diagonal(left, &prepared.divisor.0);
8876 }
8877 return divide_matrix4_by_affine_linear_diagonal_checked(left, &prepared.divisor.0);
8878 }
8879 return divide_matrix4_by_affine_no_translation(left, &prepared.divisor.0);
8880 }
8881 if !prepared.can_use_shared_adjugate(&left) {
8882 crate::trace_dispatch!(
8883 "hyperlattice_matrix",
8884 "helper",
8885 "right-divide4-prepared-gauss-jordan"
8886 );
8887 return Ok(transpose_array4(solve_left_system4(
8888 transpose_array4_ref(&prepared.divisor.0),
8889 transpose_array4(left),
8890 )?));
8891 }
8892
8893 crate::trace_dispatch!(
8898 "hyperlattice_matrix",
8899 "helper",
8900 "right-divide4-prepared-shared-adjugate"
8901 );
8902 let _ = prepared.prepare_shared_adjugate()?;
8903 let inv_det = prepared
8904 .reciprocal_determinant
8905 .as_ref()
8906 .expect("reciprocal determinant cache should be present");
8907 let adjugate = prepared
8908 .adjugate
8909 .as_ref()
8910 .expect("adjugate cache should be present");
8911 let product = if prepared.right_exact_rational_kind != ExactRationalKind::NonRational
8912 && matrix4_exact_rational_kind(&left) != ExactRationalKind::NonRational
8913 {
8914 multiply_arrays4_dense_known_rational_ref(&left, adjugate)
8915 } else {
8916 multiply_arrays4_rhs_ref_with_dense_certificate(left, adjugate)
8917 };
8918 Ok(scale_matrix4(product, inv_det))
8919}
8920
8921fn right_divide_matrix4_prepared_exact_rational_left(
8922 left: [[Real; 4]; 4],
8923 prepared: &mut PreparedRightDivisor4,
8924) -> BlasResult<[[Real; 4]; 4]> {
8925 if true && prepared.right_exact_rational_kind != ExactRationalKind::NonRational {
8926 crate::trace_dispatch!(
8927 "hyperlattice_matrix",
8928 "helper",
8929 "right-divide4-prepared-certified-left-exact-shared-adjugate"
8930 );
8931 let _ = prepared.prepare_shared_adjugate()?;
8932 let inv_det = prepared
8933 .reciprocal_determinant
8934 .as_ref()
8935 .expect("reciprocal determinant cache should be present");
8936 let adjugate = prepared
8937 .adjugate
8938 .as_ref()
8939 .expect("adjugate cache should be present");
8940 let product = multiply_arrays4_dense_known_rational_ref(&left, adjugate);
8941 return Ok(scale_matrix4(product, inv_det));
8942 }
8943
8944 right_divide_matrix4_prepared(left, prepared)
8945}
8946
8947fn right_divide_matrix4_prepared_checked(
8948 left: [[Real; 4]; 4],
8949 prepared: &mut PreparedRightDivisor4,
8950) -> CheckedBlasResult<[[Real; 4]; 4]> {
8951 let right_facts = prepared.facts;
8952
8953 if right_facts.is_identity {
8954 crate::trace_dispatch!(
8955 "hyperlattice_matrix",
8956 "helper",
8957 "right-divide4-prepared-checked-identity"
8958 );
8959 return Ok(left);
8960 }
8961 if right_facts.is_diagonal {
8962 crate::trace_dispatch!(
8963 "hyperlattice_matrix",
8964 "helper",
8965 "right-divide4-prepared-checked-diagonal"
8966 );
8967 return divide_matrix4_by_diagonal_checked(left, &prepared.divisor.0);
8968 }
8969 if right_facts.is_affine_translation {
8970 let left_facts = matrix4_facts(&left);
8971 if left_facts.is_affine {
8972 crate::trace_dispatch!(
8973 "hyperlattice_matrix",
8974 "helper",
8975 "right-divide4-prepared-checked-affine-left-affine-translation"
8976 );
8977 return divide_matrix4_affine_by_affine_checked_assumed_affine_translation(
8978 left,
8979 &prepared.divisor.0,
8980 );
8981 }
8982 crate::trace_dispatch!(
8983 "hyperlattice_matrix",
8984 "helper",
8985 "right-divide4-prepared-checked-affine-by-translation"
8986 );
8987 return divide_matrix4_by_affine_checked_assumed_affine_translation(
8988 left,
8989 &prepared.divisor.0,
8990 );
8991 }
8992 if true && right_facts.is_affine && right_facts.is_upper_triangular {
8993 let left_facts = matrix4_facts(&left);
8994 if left_facts.is_affine {
8995 crate::trace_dispatch!(
8996 "hyperlattice_matrix",
8997 "helper",
8998 "right-divide4-prepared-checked-affine-left-affine-upper-triangular"
8999 );
9000 return divide_matrix4_affine_by_affine_upper_triangular_checked(
9001 left,
9002 &prepared.divisor.0,
9003 );
9004 }
9005 crate::trace_dispatch!(
9006 "hyperlattice_matrix",
9007 "helper",
9008 "right-divide4-prepared-checked-affine-upper-triangular"
9009 );
9010 return divide_matrix4_by_affine_upper_triangular_checked(left, &prepared.divisor.0);
9011 }
9012 if right_facts.is_upper_triangular {
9013 crate::trace_dispatch!(
9014 "hyperlattice_matrix",
9015 "helper",
9016 "right-divide4-prepared-checked-upper-triangular"
9017 );
9018 return divide_matrix4_by_upper_triangular_checked(left, &prepared.divisor.0);
9019 }
9020 if right_facts.is_lower_triangular {
9021 crate::trace_dispatch!(
9022 "hyperlattice_matrix",
9023 "helper",
9024 "right-divide4-prepared-checked-lower-triangular"
9025 );
9026 return divide_matrix4_by_lower_triangular_checked(left, &prepared.divisor.0);
9027 }
9028 if right_facts.is_affine {
9029 let left_facts = matrix4_facts(&left);
9032 let left_is_affine = left_facts.is_affine;
9033 let right_linear_is_diagonal = right_facts.linear_is_diagonal;
9034 let right_is_affine_translation = right_facts.is_affine_translation;
9035 crate::trace_dispatch!(
9036 "hyperlattice_matrix",
9037 "helper",
9038 "right-divide4-prepared-checked-affine"
9039 );
9040 if left_is_affine {
9041 if right_is_affine_translation {
9042 return divide_matrix4_affine_by_affine_checked_assumed_affine_translation(
9043 left,
9044 &prepared.divisor.0,
9045 );
9046 }
9047 if right_linear_is_diagonal {
9048 if right_facts.affine_linear_diagonal_is_definitely_nonzero {
9049 crate::trace_dispatch!(
9050 "hyperlattice_matrix",
9051 "helper",
9052 "right-divide4-prepared-checked-affine-left-affine-linear-diagonal-known-nonzero"
9053 );
9054 return divide_matrix4_affine_by_affine_linear_diagonal(
9055 left,
9056 &prepared.divisor.0,
9057 );
9058 }
9059 return divide_matrix4_affine_by_affine_linear_diagonal_checked(
9060 left,
9061 &prepared.divisor.0,
9062 );
9063 }
9064 return divide_matrix4_affine_by_affine_checked(left, &prepared.divisor.0);
9065 }
9066 if right_is_affine_translation {
9067 return divide_matrix4_by_affine_checked_assumed_affine_translation(
9068 left,
9069 &prepared.divisor.0,
9070 );
9071 }
9072 if right_linear_is_diagonal {
9073 if right_facts.affine_linear_diagonal_is_definitely_nonzero {
9074 crate::trace_dispatch!(
9075 "hyperlattice_matrix",
9076 "helper",
9077 "right-divide4-prepared-checked-affine-linear-diagonal-known-nonzero"
9078 );
9079 return divide_matrix4_by_affine_linear_diagonal(left, &prepared.divisor.0);
9080 }
9081 return divide_matrix4_by_affine_linear_diagonal_checked(left, &prepared.divisor.0);
9082 }
9083 return divide_matrix4_by_affine_checked(left, &prepared.divisor.0);
9084 }
9085 if !prepared.can_use_shared_adjugate(&left) {
9086 crate::trace_dispatch!(
9087 "hyperlattice_matrix",
9088 "helper",
9089 "right-divide4-prepared-checked-gauss-jordan"
9090 );
9091 return Ok(transpose_array4(solve_left_system4_checked(
9092 transpose_array4_ref(&prepared.divisor.0),
9093 transpose_array4(left),
9094 )?));
9095 }
9096
9097 crate::trace_dispatch!(
9098 "hyperlattice_matrix",
9099 "helper",
9100 "right-divide4-prepared-checked-shared-adjugate"
9101 );
9102 let _ = prepared.prepare_shared_adjugate_checked()?;
9103 let inv_det = prepared
9104 .reciprocal_determinant
9105 .as_ref()
9106 .expect("reciprocal determinant cache should be present");
9107 let adjugate = prepared
9108 .adjugate
9109 .as_ref()
9110 .expect("adjugate cache should be present");
9111 let product = if prepared.right_exact_rational_kind != ExactRationalKind::NonRational
9112 && matrix4_exact_rational_kind(&left) != ExactRationalKind::NonRational
9113 {
9114 multiply_arrays4_dense_known_rational_ref(&left, adjugate)
9115 } else {
9116 multiply_arrays4_rhs_ref_with_dense_certificate(left, adjugate)
9117 };
9118 Ok(scale_matrix4(product, inv_det))
9119}
9120
9121fn right_divide_matrix4_prepared_checked_with_abort(
9122 left: [[Real; 4]; 4],
9123 prepared: &mut PreparedRightDivisor4,
9124 signal: &AbortSignal,
9125) -> CheckedBlasResult<[[Real; 4]; 4]> {
9126 let right_facts = prepared.facts;
9127
9128 if right_facts.is_identity {
9129 crate::trace_dispatch!(
9130 "hyperlattice_matrix",
9131 "helper",
9132 "right-divide4-prepared-checked-abort-identity"
9133 );
9134 return Ok(left);
9135 }
9136 if right_facts.is_diagonal {
9137 crate::trace_dispatch!(
9138 "hyperlattice_matrix",
9139 "helper",
9140 "right-divide4-prepared-checked-abort-diagonal"
9141 );
9142 return divide_matrix4_by_diagonal_checked_with_abort(left, &prepared.divisor.0, signal);
9143 }
9144 if right_facts.is_affine_translation {
9145 let left_facts = matrix4_facts(&left);
9146 if left_facts.is_affine {
9147 crate::trace_dispatch!(
9148 "hyperlattice_matrix",
9149 "helper",
9150 "right-divide4-prepared-checked-abort-affine-left-affine-translation"
9151 );
9152 return divide_matrix4_affine_by_affine_checked_with_abort_assumed_affine_translation(
9153 left,
9154 &prepared.divisor.0,
9155 signal,
9156 );
9157 }
9158 crate::trace_dispatch!(
9159 "hyperlattice_matrix",
9160 "helper",
9161 "right-divide4-prepared-checked-abort-affine-by-translation"
9162 );
9163 return divide_matrix4_by_affine_checked_with_abort_assumed_affine_translation(
9164 left,
9165 &prepared.divisor.0,
9166 signal,
9167 );
9168 }
9169 if true && right_facts.is_affine && right_facts.is_upper_triangular {
9170 let left_facts = matrix4_facts(&left);
9171 if left_facts.is_affine {
9172 crate::trace_dispatch!(
9173 "hyperlattice_matrix",
9174 "helper",
9175 "right-divide4-prepared-checked-abort-affine-left-affine-upper-triangular"
9176 );
9177 return divide_matrix4_affine_by_affine_upper_triangular_checked_with_abort(
9178 left,
9179 &prepared.divisor.0,
9180 signal,
9181 );
9182 }
9183 crate::trace_dispatch!(
9184 "hyperlattice_matrix",
9185 "helper",
9186 "right-divide4-prepared-checked-abort-affine-upper-triangular"
9187 );
9188 return divide_matrix4_by_affine_upper_triangular_checked_with_abort(
9189 left,
9190 &prepared.divisor.0,
9191 signal,
9192 );
9193 }
9194 if right_facts.is_upper_triangular {
9195 crate::trace_dispatch!(
9196 "hyperlattice_matrix",
9197 "helper",
9198 "right-divide4-prepared-checked-abort-upper-triangular"
9199 );
9200 return divide_matrix4_by_upper_triangular_checked_with_abort(
9201 left,
9202 &prepared.divisor.0,
9203 signal,
9204 );
9205 }
9206 if right_facts.is_lower_triangular {
9207 crate::trace_dispatch!(
9208 "hyperlattice_matrix",
9209 "helper",
9210 "right-divide4-prepared-checked-abort-lower-triangular"
9211 );
9212 return divide_matrix4_by_lower_triangular_checked_with_abort(
9213 left,
9214 &prepared.divisor.0,
9215 signal,
9216 );
9217 }
9218 if right_facts.is_affine {
9219 let left_facts = matrix4_facts(&left);
9222 let left_is_affine = left_facts.is_affine;
9223 let right_linear_is_diagonal = right_facts.linear_is_diagonal;
9224 let right_is_affine_translation = right_facts.is_affine_translation;
9225 crate::trace_dispatch!(
9226 "hyperlattice_matrix",
9227 "helper",
9228 "right-divide4-prepared-checked-abort-affine"
9229 );
9230 if left_is_affine {
9231 if right_is_affine_translation {
9232 return divide_matrix4_affine_by_affine_checked_with_abort_assumed_affine_translation(
9233 left,
9234 &prepared.divisor.0,
9235 signal,
9236 );
9237 }
9238 if right_linear_is_diagonal {
9239 if right_facts.affine_linear_diagonal_is_definitely_nonzero {
9240 crate::trace_dispatch!(
9241 "hyperlattice_matrix",
9242 "helper",
9243 "right-divide4-prepared-checked-abort-affine-left-affine-linear-diagonal-known-nonzero"
9244 );
9245 return divide_matrix4_affine_by_affine_linear_diagonal(
9246 left,
9247 &prepared.divisor.0,
9248 );
9249 }
9250 return divide_matrix4_affine_by_affine_linear_diagonal_checked_with_abort(
9251 left,
9252 &prepared.divisor.0,
9253 signal,
9254 );
9255 }
9256 return divide_matrix4_affine_by_affine_checked_with_abort(
9257 left,
9258 &prepared.divisor.0,
9259 signal,
9260 );
9261 }
9262 if right_is_affine_translation {
9263 return divide_matrix4_by_affine_checked_with_abort_assumed_affine_translation(
9264 left,
9265 &prepared.divisor.0,
9266 signal,
9267 );
9268 }
9269 if right_linear_is_diagonal {
9270 if right_facts.affine_linear_diagonal_is_definitely_nonzero {
9271 crate::trace_dispatch!(
9272 "hyperlattice_matrix",
9273 "helper",
9274 "right-divide4-prepared-checked-abort-affine-linear-diagonal-known-nonzero"
9275 );
9276 return divide_matrix4_by_affine_linear_diagonal(left, &prepared.divisor.0);
9277 }
9278 return divide_matrix4_by_affine_linear_diagonal_checked_with_abort(
9279 left,
9280 &prepared.divisor.0,
9281 signal,
9282 );
9283 }
9284 return divide_matrix4_by_affine_checked_with_abort(left, &prepared.divisor.0, signal);
9285 }
9286 if !prepared.can_use_shared_adjugate(&left) {
9287 crate::trace_dispatch!(
9288 "hyperlattice_matrix",
9289 "helper",
9290 "right-divide4-prepared-checked-abort-gauss-jordan"
9291 );
9292 return Ok(transpose_array4(solve_left_system4_checked_with_abort(
9293 transpose_array4_ref(&prepared.divisor.0),
9294 transpose_array4(left),
9295 signal,
9296 )?));
9297 }
9298
9299 crate::trace_dispatch!(
9300 "hyperlattice_matrix",
9301 "helper",
9302 "right-divide4-prepared-checked-abort-shared-adjugate"
9303 );
9304 let _ = prepared.prepare_shared_adjugate_checked_with_abort(signal)?;
9305 let inv_det = prepared
9306 .reciprocal_determinant
9307 .as_ref()
9308 .expect("reciprocal determinant cache should be present");
9309 let adjugate = prepared
9310 .adjugate
9311 .as_ref()
9312 .expect("adjugate cache should be present");
9313 let product = if prepared.right_exact_rational_kind != ExactRationalKind::NonRational
9314 && matrix4_exact_rational_kind(&left) != ExactRationalKind::NonRational
9315 {
9316 multiply_arrays4_dense_known_rational_ref(&left, adjugate)
9317 } else {
9318 multiply_arrays4_rhs_ref_with_dense_certificate(left, adjugate)
9319 };
9320 Ok(scale_matrix4(product, inv_det))
9321}
9322
9323fn right_divide_matrix4_ref(
9324 left: &[[Real; 4]; 4],
9325 right: &[[Real; 4]; 4],
9326) -> BlasResult<[[Real; 4]; 4]> {
9327 if can_use_dense_exact_shared_adjugate4(right) {
9328 crate::trace_dispatch!(
9329 "hyperlattice_matrix",
9330 "helper",
9331 "right-divide4-ref-dense-exact-shared-adjugate"
9332 );
9333 return right_divide_matrix4_dense_exact_shared(left, right);
9334 }
9335 let right_facts = matrix4_facts(right);
9336 if right_facts.is_identity {
9337 crate::trace_dispatch!(
9338 "hyperlattice_matrix",
9339 "helper",
9340 "right-divide4-ref-identity"
9341 );
9342 return Ok(left.clone());
9343 }
9344 if right_facts.is_diagonal {
9345 crate::trace_dispatch!(
9346 "hyperlattice_matrix",
9347 "helper",
9348 "right-divide4-ref-diagonal"
9349 );
9350 return divide_matrix4_by_diagonal(left.clone(), right);
9351 }
9352 if true && right_facts.is_affine && right_facts.is_upper_triangular {
9353 let left_facts = matrix4_facts(left);
9354 if left_facts.is_affine {
9355 crate::trace_dispatch!(
9356 "hyperlattice_matrix",
9357 "helper",
9358 "right-divide4-ref-affine-left-affine-upper-triangular"
9359 );
9360 return divide_matrix4_affine_by_affine_upper_triangular(left.clone(), right);
9361 }
9362 crate::trace_dispatch!(
9363 "hyperlattice_matrix",
9364 "helper",
9365 "right-divide4-ref-affine-upper-triangular"
9366 );
9367 return divide_matrix4_by_affine_upper_triangular(left.clone(), right);
9368 }
9369 if right_facts.is_upper_triangular {
9370 crate::trace_dispatch!(
9371 "hyperlattice_matrix",
9372 "helper",
9373 "right-divide4-ref-upper-triangular"
9374 );
9375 return divide_matrix4_by_upper_triangular(left.clone(), right);
9376 }
9377 if right_facts.is_lower_triangular {
9378 crate::trace_dispatch!(
9379 "hyperlattice_matrix",
9380 "helper",
9381 "right-divide4-ref-lower-triangular"
9382 );
9383 return divide_matrix4_by_lower_triangular(left.clone(), right);
9384 }
9385 if right_facts.is_affine {
9386 let left_facts = matrix4_facts(left);
9391 let left_is_affine = left_facts.is_affine;
9392 let right_linear_is_diagonal = right_facts.linear_is_diagonal;
9393 let right_is_affine_translation = right_facts.is_affine_translation;
9394 crate::trace_dispatch!("hyperlattice_matrix", "helper", "right-divide4-ref-affine");
9395 if left_is_affine {
9396 crate::trace_dispatch!(
9397 "hyperlattice_matrix",
9398 "helper",
9399 "right-divide4-ref-affine-left-affine"
9400 );
9401 if right_is_affine_translation {
9402 crate::trace_dispatch!(
9403 "hyperlattice_matrix",
9404 "helper",
9405 "right-divide4-ref-affine-by-affine-translation"
9406 );
9407 return divide_matrix4_affine_by_affine_ref_translation(left, right);
9408 }
9409 if right_linear_is_diagonal {
9410 crate::trace_dispatch!(
9411 "hyperlattice_matrix",
9412 "helper",
9413 "right-divide4-ref-affine-left-affine-linear-diagonal"
9414 );
9415 return divide_matrix4_affine_by_affine_ref_linear_diagonal(left, right);
9416 }
9417 return divide_matrix4_affine_by_affine_ref_no_translation(left, right);
9418 }
9419 if right_is_affine_translation {
9420 crate::trace_dispatch!(
9421 "hyperlattice_matrix",
9422 "helper",
9423 "right-divide4-ref-by-affine-translation"
9424 );
9425 return divide_matrix4_by_affine_ref_assumed_affine_translation(left, right);
9426 }
9427 if right_linear_is_diagonal {
9428 crate::trace_dispatch!(
9429 "hyperlattice_matrix",
9430 "helper",
9431 "right-divide4-ref-affine-linear-diagonal"
9432 );
9433 return divide_matrix4_by_affine_linear_diagonal_ref(left, right);
9434 }
9435 return divide_matrix4_by_affine_ref_no_translation(left, right);
9436 }
9437 if !prefer_shared_adjugate_right_division(left, right) {
9438 crate::trace_dispatch!(
9439 "hyperlattice_matrix",
9440 "helper",
9441 "right-divide4-ref-gauss-jordan"
9442 );
9443 return Ok(transpose_array4(solve_left_system4(
9446 transpose_array4_ref(right),
9447 transpose_array4_ref(left),
9448 )?));
9449 }
9450
9451 crate::trace_dispatch!(
9452 "hyperlattice_matrix",
9453 "helper",
9454 "right-divide4-ref-shared-adjugate"
9455 );
9456 let dense_exact = true && right_facts.is_definitely_dense_for_inverse;
9461 let (s, c) = if dense_exact {
9462 matrix4_factors_dense_exact(right)
9463 } else {
9464 matrix4_factors(right)
9465 };
9466 let det = determinant4_from_factors(&s, &c);
9467 let inv_det = det.inverse()?;
9468 let adjugate = if dense_exact {
9469 matrix4_adjugate_from_factors_dense_exact(right, &s, &c)
9470 } else {
9471 matrix4_adjugate_from_factors(right, &s, &c)
9472 };
9473 Ok(scale_matrix4(
9474 multiply_arrays4_ref_with_dense_certificate(left, &adjugate),
9475 &inv_det,
9476 ))
9477}
9478
9479fn right_divide_matrix4_checked(
9480 left: [[Real; 4]; 4],
9481 right: [[Real; 4]; 4],
9482) -> CheckedBlasResult<[[Real; 4]; 4]> {
9483 if can_use_dense_exact_shared_adjugate4(&right) {
9484 crate::trace_dispatch!(
9485 "hyperlattice_matrix",
9486 "helper",
9487 "right-divide4-checked-dense-exact-shared-adjugate"
9488 );
9489 return right_divide_matrix4_dense_exact_shared_checked(&left, &right);
9490 }
9491 let right_facts = matrix4_facts(&right);
9492 if right_facts.is_identity {
9493 crate::trace_dispatch!(
9494 "hyperlattice_matrix",
9495 "helper",
9496 "right-divide4-checked-identity"
9497 );
9498 return Ok(left);
9499 }
9500 if right_facts.is_diagonal {
9501 crate::trace_dispatch!(
9502 "hyperlattice_matrix",
9503 "helper",
9504 "right-divide4-checked-diagonal"
9505 );
9506 return divide_matrix4_by_diagonal_checked(left, &right);
9507 }
9508 if right_facts.is_affine_translation {
9509 let left_facts = matrix4_facts(&left);
9510 if left_facts.is_affine {
9511 crate::trace_dispatch!(
9512 "hyperlattice_matrix",
9513 "helper",
9514 "right-divide4-checked-affine-left-affine-translation"
9515 );
9516 return divide_matrix4_affine_by_affine_checked_assumed_affine_translation(
9517 left, &right,
9518 );
9519 }
9520 crate::trace_dispatch!(
9521 "hyperlattice_matrix",
9522 "helper",
9523 "right-divide4-checked-affine-by-translation"
9524 );
9525 return divide_matrix4_by_affine_checked_assumed_affine_translation(left, &right);
9526 }
9527 if true && right_facts.is_affine && right_facts.is_upper_triangular {
9528 let left_facts = matrix4_facts(&left);
9529 if left_facts.is_affine {
9530 crate::trace_dispatch!(
9531 "hyperlattice_matrix",
9532 "helper",
9533 "right-divide4-checked-affine-left-affine-upper-triangular"
9534 );
9535 return divide_matrix4_affine_by_affine_upper_triangular_checked(left, &right);
9536 }
9537 crate::trace_dispatch!(
9538 "hyperlattice_matrix",
9539 "helper",
9540 "right-divide4-checked-affine-upper-triangular"
9541 );
9542 return divide_matrix4_by_affine_upper_triangular_checked(left, &right);
9543 }
9544 if right_facts.is_upper_triangular {
9545 crate::trace_dispatch!(
9546 "hyperlattice_matrix",
9547 "helper",
9548 "right-divide4-checked-upper-triangular"
9549 );
9550 return divide_matrix4_by_upper_triangular_checked(left, &right);
9551 }
9552 if right_facts.is_lower_triangular {
9553 crate::trace_dispatch!(
9554 "hyperlattice_matrix",
9555 "helper",
9556 "right-divide4-checked-lower-triangular"
9557 );
9558 return divide_matrix4_by_lower_triangular_checked(left, &right);
9559 }
9560 if right_facts.is_affine {
9561 let left_facts = matrix4_facts(&left);
9566 let left_is_affine = left_facts.is_affine;
9567 let right_linear_is_diagonal = right_facts.linear_is_diagonal;
9568 let right_is_affine_translation = right_facts.is_affine_translation;
9569 crate::trace_dispatch!(
9570 "hyperlattice_matrix",
9571 "helper",
9572 "right-divide4-checked-affine"
9573 );
9574 if left_is_affine {
9575 crate::trace_dispatch!(
9576 "hyperlattice_matrix",
9577 "helper",
9578 "right-divide4-checked-affine-left-affine"
9579 );
9580 if right_is_affine_translation {
9581 crate::trace_dispatch!(
9582 "hyperlattice_matrix",
9583 "helper",
9584 "right-divide4-checked-affine-by-affine-translation"
9585 );
9586 return divide_matrix4_affine_by_affine_checked_assumed_affine_translation(
9587 left, &right,
9588 );
9589 }
9590 if right_linear_is_diagonal {
9591 crate::trace_dispatch!(
9592 "hyperlattice_matrix",
9593 "helper",
9594 "right-divide4-checked-affine-left-affine-linear-diagonal"
9595 );
9596 if right_facts.affine_linear_diagonal_is_definitely_nonzero {
9597 crate::trace_dispatch!(
9598 "hyperlattice_matrix",
9599 "helper",
9600 "right-divide4-checked-affine-left-affine-linear-diagonal-known-nonzero"
9601 );
9602 return divide_matrix4_affine_by_affine_linear_diagonal(left, &right);
9603 }
9604 return divide_matrix4_affine_by_affine_linear_diagonal_checked(left, &right);
9605 }
9606 return divide_matrix4_affine_by_affine_checked(left, &right);
9607 }
9608 if right_is_affine_translation {
9609 crate::trace_dispatch!(
9610 "hyperlattice_matrix",
9611 "helper",
9612 "right-divide4-checked-by-affine-translation"
9613 );
9614 return divide_matrix4_by_affine_checked_assumed_affine_translation(left, &right);
9615 }
9616 if right_linear_is_diagonal {
9617 crate::trace_dispatch!(
9618 "hyperlattice_matrix",
9619 "helper",
9620 "right-divide4-checked-affine-linear-diagonal"
9621 );
9622 if right_facts.affine_linear_diagonal_is_definitely_nonzero {
9623 crate::trace_dispatch!(
9624 "hyperlattice_matrix",
9625 "helper",
9626 "right-divide4-checked-affine-linear-diagonal-known-nonzero"
9627 );
9628 return divide_matrix4_by_affine_linear_diagonal(left, &right);
9629 }
9630 return divide_matrix4_by_affine_linear_diagonal_checked(left, &right);
9631 }
9632 return divide_matrix4_by_affine_checked(left, &right);
9633 }
9634 if !prefer_shared_adjugate_right_division(&left, &right) {
9635 crate::trace_dispatch!(
9636 "hyperlattice_matrix",
9637 "helper",
9638 "right-divide4-checked-gauss-jordan"
9639 );
9640 return Ok(transpose_array4(solve_left_system4_checked(
9641 transpose_array4(right),
9642 transpose_array4(left),
9643 )?));
9644 }
9645
9646 crate::trace_dispatch!(
9647 "hyperlattice_matrix",
9648 "helper",
9649 "right-divide4-checked-shared-adjugate"
9650 );
9651 let dense_exact = true && right_facts.is_definitely_dense_for_inverse;
9652 let (s, c) = if dense_exact {
9653 matrix4_factors_dense_exact(&right)
9654 } else {
9655 matrix4_factors(&right)
9656 };
9657 let det = determinant4_from_factors(&s, &c);
9658 require_known_nonzero(&det)?;
9659 let inv_det = det.inverse()?;
9660 let adjugate = if dense_exact {
9661 matrix4_adjugate_from_factors_dense_exact(&right, &s, &c)
9662 } else {
9663 matrix4_adjugate_from_factors(&right, &s, &c)
9664 };
9665 Ok(scale_matrix4(
9666 multiply_arrays4_ref_with_dense_certificate(&left, &adjugate),
9667 &inv_det,
9668 ))
9669}
9670
9671fn right_divide_matrix4_checked_with_abort(
9672 left: [[Real; 4]; 4],
9673 right: [[Real; 4]; 4],
9674 signal: &AbortSignal,
9675) -> CheckedBlasResult<[[Real; 4]; 4]> {
9676 if can_use_dense_exact_shared_adjugate4(&right) {
9677 crate::trace_dispatch!(
9678 "hyperlattice_matrix",
9679 "helper",
9680 "right-divide4-checked-abort-dense-exact-shared-adjugate"
9681 );
9682 return right_divide_matrix4_dense_exact_shared_checked_with_abort(&left, &right, signal);
9683 }
9684 let right_facts = matrix4_facts(&right);
9685 if right_facts.is_identity {
9686 crate::trace_dispatch!(
9687 "hyperlattice_matrix",
9688 "helper",
9689 "right-divide4-checked-abort-identity"
9690 );
9691 return Ok(left);
9692 }
9693 if right_facts.is_diagonal {
9694 crate::trace_dispatch!(
9695 "hyperlattice_matrix",
9696 "helper",
9697 "right-divide4-checked-abort-diagonal"
9698 );
9699 return divide_matrix4_by_diagonal_checked_with_abort(left, &right, signal);
9700 }
9701 if right_facts.is_affine_translation {
9702 let left_facts = matrix4_facts(&left);
9703 if left_facts.is_affine {
9704 crate::trace_dispatch!(
9705 "hyperlattice_matrix",
9706 "helper",
9707 "right-divide4-checked-abort-affine-left-affine-translation"
9708 );
9709 return divide_matrix4_affine_by_affine_checked_with_abort_assumed_affine_translation(
9710 left, &right, signal,
9711 );
9712 }
9713 crate::trace_dispatch!(
9714 "hyperlattice_matrix",
9715 "helper",
9716 "right-divide4-checked-abort-affine-by-translation"
9717 );
9718 return divide_matrix4_by_affine_checked_with_abort_assumed_affine_translation(
9719 left, &right, signal,
9720 );
9721 }
9722 if true && right_facts.is_affine && right_facts.is_upper_triangular {
9723 let left_facts = matrix4_facts(&left);
9724 if left_facts.is_affine {
9725 crate::trace_dispatch!(
9726 "hyperlattice_matrix",
9727 "helper",
9728 "right-divide4-checked-abort-affine-left-affine-upper-triangular"
9729 );
9730 return divide_matrix4_affine_by_affine_upper_triangular_checked_with_abort(
9731 left, &right, signal,
9732 );
9733 }
9734 crate::trace_dispatch!(
9735 "hyperlattice_matrix",
9736 "helper",
9737 "right-divide4-checked-abort-affine-upper-triangular"
9738 );
9739 return divide_matrix4_by_affine_upper_triangular_checked_with_abort(left, &right, signal);
9740 }
9741 if right_facts.is_upper_triangular {
9742 crate::trace_dispatch!(
9743 "hyperlattice_matrix",
9744 "helper",
9745 "right-divide4-checked-abort-upper-triangular"
9746 );
9747 return divide_matrix4_by_upper_triangular_checked_with_abort(left, &right, signal);
9748 }
9749 if right_facts.is_lower_triangular {
9750 crate::trace_dispatch!(
9751 "hyperlattice_matrix",
9752 "helper",
9753 "right-divide4-checked-abort-lower-triangular"
9754 );
9755 return divide_matrix4_by_lower_triangular_checked_with_abort(left, &right, signal);
9756 }
9757 if right_facts.is_affine {
9758 let left_facts = matrix4_facts(&left);
9762 let left_is_affine = left_facts.is_affine;
9763 let right_linear_is_diagonal = right_facts.linear_is_diagonal;
9764 let right_is_affine_translation = right_facts.is_affine_translation;
9765 crate::trace_dispatch!(
9766 "hyperlattice_matrix",
9767 "helper",
9768 "right-divide4-checked-abort-affine"
9769 );
9770 if left_is_affine {
9771 crate::trace_dispatch!(
9772 "hyperlattice_matrix",
9773 "helper",
9774 "right-divide4-checked-abort-affine-left-affine"
9775 );
9776 if right_is_affine_translation {
9777 crate::trace_dispatch!(
9778 "hyperlattice_matrix",
9779 "helper",
9780 "right-divide4-checked-abort-affine-by-affine-translation"
9781 );
9782 return divide_matrix4_affine_by_affine_checked_with_abort_assumed_affine_translation(
9783 left,
9784 &right,
9785 signal,
9786 );
9787 }
9788 if right_linear_is_diagonal {
9789 crate::trace_dispatch!(
9790 "hyperlattice_matrix",
9791 "helper",
9792 "right-divide4-checked-abort-affine-left-affine-linear-diagonal"
9793 );
9794 if right_facts.affine_linear_diagonal_is_definitely_nonzero {
9795 crate::trace_dispatch!(
9796 "hyperlattice_matrix",
9797 "helper",
9798 "right-divide4-checked-abort-affine-left-affine-linear-diagonal-known-nonzero"
9799 );
9800 return divide_matrix4_affine_by_affine_linear_diagonal(left, &right);
9801 }
9802 return divide_matrix4_affine_by_affine_linear_diagonal_checked_with_abort(
9803 left, &right, signal,
9804 );
9805 }
9806 return divide_matrix4_affine_by_affine_checked_with_abort(left, &right, signal);
9807 }
9808 if right_is_affine_translation {
9809 crate::trace_dispatch!(
9810 "hyperlattice_matrix",
9811 "helper",
9812 "right-divide4-checked-abort-by-affine-translation"
9813 );
9814 return divide_matrix4_by_affine_checked_with_abort_assumed_affine_translation(
9815 left, &right, signal,
9816 );
9817 }
9818 if right_linear_is_diagonal {
9819 crate::trace_dispatch!(
9820 "hyperlattice_matrix",
9821 "helper",
9822 "right-divide4-checked-abort-affine-linear-diagonal"
9823 );
9824 if right_facts.affine_linear_diagonal_is_definitely_nonzero {
9825 crate::trace_dispatch!(
9826 "hyperlattice_matrix",
9827 "helper",
9828 "right-divide4-checked-abort-affine-linear-diagonal-known-nonzero"
9829 );
9830 return divide_matrix4_by_affine_linear_diagonal(left, &right);
9831 }
9832 return divide_matrix4_by_affine_linear_diagonal_checked_with_abort(
9833 left, &right, signal,
9834 );
9835 }
9836 return divide_matrix4_by_affine_checked_with_abort(left, &right, signal);
9837 }
9838 if !prefer_shared_adjugate_right_division(&left, &right) {
9839 crate::trace_dispatch!(
9840 "hyperlattice_matrix",
9841 "helper",
9842 "right-divide4-checked-abort-gauss-jordan"
9843 );
9844 return Ok(transpose_array4(solve_left_system4_checked_with_abort(
9845 transpose_array4(right),
9846 transpose_array4(left),
9847 signal,
9848 )?));
9849 }
9850
9851 crate::trace_dispatch!(
9852 "hyperlattice_matrix",
9853 "helper",
9854 "right-divide4-checked-abort-shared-adjugate"
9855 );
9856 let dense_exact = true && right_facts.is_definitely_dense_for_inverse;
9857 let (s, c) = if dense_exact {
9858 matrix4_factors_dense_exact(&right)
9859 } else {
9860 matrix4_factors(&right)
9861 };
9862 let det = determinant4_from_factors(&s, &c);
9863 let det = with_abort(det, signal);
9864 require_known_nonzero(&det)?;
9865 let inv_det = det.inverse()?;
9866 let adjugate = if dense_exact {
9867 matrix4_adjugate_from_factors_dense_exact(&right, &s, &c)
9868 } else {
9869 matrix4_adjugate_from_factors(&right, &s, &c)
9870 };
9871 Ok(scale_matrix4(
9872 multiply_arrays4_ref_with_dense_certificate(&left, &adjugate),
9873 &inv_det,
9874 ))
9875}
9876
9877#[inline]
9878fn multiply_arrays3_borrowed(left: &[[Real; 3]; 3], right: &[[Real; 3]; 3]) -> [[Real; 3]; 3] {
9879 let left_nonzero = [
9880 [
9881 !left[0][0].definitely_zero(),
9882 !left[0][1].definitely_zero(),
9883 !left[0][2].definitely_zero(),
9884 ],
9885 [
9886 !left[1][0].definitely_zero(),
9887 !left[1][1].definitely_zero(),
9888 !left[1][2].definitely_zero(),
9889 ],
9890 [
9891 !left[2][0].definitely_zero(),
9892 !left[2][1].definitely_zero(),
9893 !left[2][2].definitely_zero(),
9894 ],
9895 ];
9896 let right_nonzero = [
9897 [
9898 !right[0][0].definitely_zero(),
9899 !right[0][1].definitely_zero(),
9900 !right[0][2].definitely_zero(),
9901 ],
9902 [
9903 !right[1][0].definitely_zero(),
9904 !right[1][1].definitely_zero(),
9905 !right[1][2].definitely_zero(),
9906 ],
9907 [
9908 !right[2][0].definitely_zero(),
9909 !right[2][1].definitely_zero(),
9910 !right[2][2].definitely_zero(),
9911 ],
9912 ];
9913
9914 let left_all_nonzero = left_nonzero[0][0]
9915 && left_nonzero[0][1]
9916 && left_nonzero[0][2]
9917 && left_nonzero[1][0]
9918 && left_nonzero[1][1]
9919 && left_nonzero[1][2]
9920 && left_nonzero[2][0]
9921 && left_nonzero[2][1]
9922 && left_nonzero[2][2];
9923 let right_all_nonzero = right_nonzero[0][0]
9924 && right_nonzero[0][1]
9925 && right_nonzero[0][2]
9926 && right_nonzero[1][0]
9927 && right_nonzero[1][1]
9928 && right_nonzero[1][2]
9929 && right_nonzero[2][0]
9930 && right_nonzero[2][1]
9931 && right_nonzero[2][2];
9932
9933 if left_all_nonzero && right_all_nonzero {
9934 crate::trace_dispatch!("hyperlattice_matrix", "helper", "multiply3-borrowed-dense");
9935
9936 let cell = |row: usize, col: usize| {
9937 Real::dot3(
9938 [&left[row][0], &left[row][1], &left[row][2]],
9939 [&right[0][col], &right[1][col], &right[2][col]],
9940 )
9941 };
9942
9943 return [
9944 [cell(0, 0), cell(0, 1), cell(0, 2)],
9945 [cell(1, 0), cell(1, 1), cell(1, 2)],
9946 [cell(2, 0), cell(2, 1), cell(2, 2)],
9947 ];
9948 }
9949
9950 crate::trace_dispatch!("hyperlattice_matrix", "helper", "multiply3-borrowed-sparse");
9951
9952 let cell = |row: usize, col: usize| {
9953 let l0 = &left[row][0];
9954 let l1 = &left[row][1];
9955 let l2 = &left[row][2];
9956 let r0 = &right[0][col];
9957 let r1 = &right[1][col];
9958 let r2 = &right[2][col];
9959 let p0 = left_nonzero[row][0] && right_nonzero[0][col];
9960 let p1 = left_nonzero[row][1] && right_nonzero[1][col];
9961 let p2 = left_nonzero[row][2] && right_nonzero[2][col];
9962 let nonzero_count = usize::from(p0) + usize::from(p1) + usize::from(p2);
9963
9964 match nonzero_count {
9965 0 => Real::zero(),
9966 1 => {
9967 if p0 {
9968 l0 * r0
9969 } else if p1 {
9970 l1 * r1
9971 } else {
9972 l2 * r2
9973 }
9974 }
9975 2 => {
9976 if !p0 {
9977 Real::active_signed_product_sum2([true, true], [[l1, r1], [l2, r2]])
9978 } else if !p1 {
9979 Real::active_signed_product_sum2([true, true], [[l0, r0], [l2, r2]])
9980 } else {
9981 Real::active_signed_product_sum2([true, true], [[l0, r0], [l1, r1]])
9982 }
9983 }
9984 _ => Real::dot3([l0, l1, l2], [r0, r1, r2]),
9985 }
9986 };
9987
9988 [
9989 [cell(0, 0), cell(0, 1), cell(0, 2)],
9990 [cell(1, 0), cell(1, 1), cell(1, 2)],
9991 [cell(2, 0), cell(2, 1), cell(2, 2)],
9992 ]
9993}
9994
9995#[inline]
9996fn multiply_arrays3_dense_ref(left: &[[Real; 3]; 3], right: &[[Real; 3]; 3]) -> [[Real; 3]; 3] {
9997 crate::trace_dispatch!("hyperlattice_matrix", "helper", "multiply3-dense-ref");
9998 let cell = |row: usize, col: usize| {
9999 Real::dot3(
10000 [&left[row][0], &left[row][1], &left[row][2]],
10001 [&right[0][col], &right[1][col], &right[2][col]],
10002 )
10003 };
10004
10005 [
10006 [cell(0, 0), cell(0, 1), cell(0, 2)],
10007 [cell(1, 0), cell(1, 1), cell(1, 2)],
10008 [cell(2, 0), cell(2, 1), cell(2, 2)],
10009 ]
10010}
10011
10012#[inline]
10013fn multiply_arrays3_with_exact_dense_certificate(
10014 left: [[Real; 3]; 3],
10015 right: [[Real; 3]; 3],
10016) -> [[Real; 3]; 3] {
10017 if true
10018 && matrix3_has_dense_multiply_certificate(&left)
10019 && matrix3_has_dense_multiply_certificate(&right)
10020 {
10021 crate::trace_dispatch!(
10022 "hyperlattice_matrix",
10023 "helper",
10024 "multiply3-owned-owned-dense-certified-exact"
10025 );
10026 return multiply_arrays3_dense_ref(&left, &right);
10027 }
10028 multiply_arrays3(left, right)
10029}
10030
10031#[inline]
10032fn multiply_arrays3_rhs_ref_with_exact_dense_certificate(
10033 left: [[Real; 3]; 3],
10034 right: &[[Real; 3]; 3],
10035) -> [[Real; 3]; 3] {
10036 if true
10037 && matrix3_has_dense_multiply_certificate(&left)
10038 && matrix3_has_dense_multiply_certificate(right)
10039 {
10040 crate::trace_dispatch!(
10041 "hyperlattice_matrix",
10042 "helper",
10043 "multiply3-owned-ref-dense-certified-exact"
10044 );
10045 return multiply_arrays3_dense_ref(&left, right);
10046 }
10047 multiply_arrays3_rhs_ref(left, right)
10048}
10049
10050#[inline]
10051fn multiply_arrays3_ref_with_exact_dense_certificate(
10052 left: &[[Real; 3]; 3],
10053 right: &[[Real; 3]; 3],
10054) -> [[Real; 3]; 3] {
10055 if true
10056 && matrix3_has_dense_multiply_certificate(left)
10057 && matrix3_has_dense_multiply_certificate(right)
10058 {
10059 crate::trace_dispatch!(
10060 "hyperlattice_matrix",
10061 "helper",
10062 "multiply3-ref-ref-dense-certified-exact"
10063 );
10064 return multiply_arrays3_dense_ref(left, right);
10065 }
10066 multiply_arrays3_ref(left, right)
10067}
10068
10069#[inline]
10070fn multiply_arrays4_borrowed(left: &[[Real; 4]; 4], right: &[[Real; 4]; 4]) -> [[Real; 4]; 4] {
10071 let left_nonzero = [
10072 [
10073 !left[0][0].definitely_zero(),
10074 !left[0][1].definitely_zero(),
10075 !left[0][2].definitely_zero(),
10076 !left[0][3].definitely_zero(),
10077 ],
10078 [
10079 !left[1][0].definitely_zero(),
10080 !left[1][1].definitely_zero(),
10081 !left[1][2].definitely_zero(),
10082 !left[1][3].definitely_zero(),
10083 ],
10084 [
10085 !left[2][0].definitely_zero(),
10086 !left[2][1].definitely_zero(),
10087 !left[2][2].definitely_zero(),
10088 !left[2][3].definitely_zero(),
10089 ],
10090 [
10091 !left[3][0].definitely_zero(),
10092 !left[3][1].definitely_zero(),
10093 !left[3][2].definitely_zero(),
10094 !left[3][3].definitely_zero(),
10095 ],
10096 ];
10097 let right_nonzero = [
10098 [
10099 !right[0][0].definitely_zero(),
10100 !right[0][1].definitely_zero(),
10101 !right[0][2].definitely_zero(),
10102 !right[0][3].definitely_zero(),
10103 ],
10104 [
10105 !right[1][0].definitely_zero(),
10106 !right[1][1].definitely_zero(),
10107 !right[1][2].definitely_zero(),
10108 !right[1][3].definitely_zero(),
10109 ],
10110 [
10111 !right[2][0].definitely_zero(),
10112 !right[2][1].definitely_zero(),
10113 !right[2][2].definitely_zero(),
10114 !right[2][3].definitely_zero(),
10115 ],
10116 [
10117 !right[3][0].definitely_zero(),
10118 !right[3][1].definitely_zero(),
10119 !right[3][2].definitely_zero(),
10120 !right[3][3].definitely_zero(),
10121 ],
10122 ];
10123
10124 let left_all_nonzero = left_nonzero[0][0]
10125 && left_nonzero[0][1]
10126 && left_nonzero[0][2]
10127 && left_nonzero[0][3]
10128 && left_nonzero[1][0]
10129 && left_nonzero[1][1]
10130 && left_nonzero[1][2]
10131 && left_nonzero[1][3]
10132 && left_nonzero[2][0]
10133 && left_nonzero[2][1]
10134 && left_nonzero[2][2]
10135 && left_nonzero[2][3]
10136 && left_nonzero[3][0]
10137 && left_nonzero[3][1]
10138 && left_nonzero[3][2]
10139 && left_nonzero[3][3];
10140 let right_all_nonzero = right_nonzero[0][0]
10141 && right_nonzero[0][1]
10142 && right_nonzero[0][2]
10143 && right_nonzero[0][3]
10144 && right_nonzero[1][0]
10145 && right_nonzero[1][1]
10146 && right_nonzero[1][2]
10147 && right_nonzero[1][3]
10148 && right_nonzero[2][0]
10149 && right_nonzero[2][1]
10150 && right_nonzero[2][2]
10151 && right_nonzero[2][3]
10152 && right_nonzero[3][0]
10153 && right_nonzero[3][1]
10154 && right_nonzero[3][2]
10155 && right_nonzero[3][3];
10156
10157 if left_all_nonzero && right_all_nonzero {
10158 crate::trace_dispatch!("hyperlattice_matrix", "helper", "multiply4-borrowed-dense");
10159 let cell = |row: usize, col: usize| {
10160 let l0 = &left[row][0];
10161 let l1 = &left[row][1];
10162 let l2 = &left[row][2];
10163 let l3 = &left[row][3];
10164 let r0 = &right[0][col];
10165 let r1 = &right[1][col];
10166 let r2 = &right[2][col];
10167 let r3 = &right[3][col];
10168 if true {
10169 Real::active_signed_product_sum2(
10170 [true, true, true, true],
10171 [[l0, r0], [l1, r1], [l2, r2], [l3, r3]],
10172 )
10173 } else {
10174 Real::dot4([l0, l1, l2, l3], [r0, r1, r2, r3])
10175 }
10176 };
10177
10178 return [
10179 [cell(0, 0), cell(0, 1), cell(0, 2), cell(0, 3)],
10180 [cell(1, 0), cell(1, 1), cell(1, 2), cell(1, 3)],
10181 [cell(2, 0), cell(2, 1), cell(2, 2), cell(2, 3)],
10182 [cell(3, 0), cell(3, 1), cell(3, 2), cell(3, 3)],
10183 ];
10184 }
10185
10186 crate::trace_dispatch!("hyperlattice_matrix", "helper", "multiply4-borrowed-sparse");
10187
10188 let cell = |row: usize, col: usize| {
10189 let l0 = &left[row][0];
10190 let l1 = &left[row][1];
10191 let l2 = &left[row][2];
10192 let l3 = &left[row][3];
10193 let r0 = &right[0][col];
10194 let r1 = &right[1][col];
10195 let r2 = &right[2][col];
10196 let r3 = &right[3][col];
10197
10198 let left_row = left_nonzero[row];
10199 let p0 = left_row[0] && right_nonzero[0][col];
10200 let p1 = left_row[1] && right_nonzero[1][col];
10201 let p2 = left_row[2] && right_nonzero[2][col];
10202 let p3 = left_row[3] && right_nonzero[3][col];
10203 let nonzero_count = usize::from(p0) + usize::from(p1) + usize::from(p2) + usize::from(p3);
10204
10205 match nonzero_count {
10206 0 => Real::zero(),
10207 1 => {
10208 if p0 {
10209 l0 * r0
10210 } else if p1 {
10211 l1 * r1
10212 } else if p2 {
10213 l2 * r2
10214 } else {
10215 l3 * r3
10216 }
10217 }
10218 2 => {
10219 if p0 {
10220 if p1 {
10221 Real::active_signed_product_sum2([true, true], [[l0, r0], [l1, r1]])
10229 } else if p2 {
10230 Real::active_signed_product_sum2([true, true], [[l0, r0], [l2, r2]])
10231 } else {
10232 Real::active_signed_product_sum2([true, true], [[l0, r0], [l3, r3]])
10233 }
10234 } else if p1 {
10235 if p2 {
10236 Real::active_signed_product_sum2([true, true], [[l1, r1], [l2, r2]])
10237 } else {
10238 Real::active_signed_product_sum2([true, true], [[l1, r1], [l3, r3]])
10239 }
10240 } else if p2 {
10241 Real::active_signed_product_sum2([true, true], [[l2, r2], [l3, r3]])
10242 } else {
10243 unreachable!("matrix multiply sparse branch expects exactly two active terms")
10244 }
10245 }
10246 3 => {
10247 if !p0 {
10248 Real::active_signed_product_sum2(
10249 [true, true, true],
10250 [[l1, r1], [l2, r2], [l3, r3]],
10251 )
10252 } else if !p1 {
10253 Real::active_signed_product_sum2(
10254 [true, true, true],
10255 [[l0, r0], [l2, r2], [l3, r3]],
10256 )
10257 } else if !p2 {
10258 Real::active_signed_product_sum2(
10259 [true, true, true],
10260 [[l0, r0], [l1, r1], [l3, r3]],
10261 )
10262 } else {
10263 Real::active_signed_product_sum2(
10264 [true, true, true],
10265 [[l0, r0], [l1, r1], [l2, r2]],
10266 )
10267 }
10268 }
10269 _ if true => Real::active_signed_product_sum2(
10270 [true, true, true, true],
10271 [[l0, r0], [l1, r1], [l2, r2], [l3, r3]],
10272 ),
10273 _ => Real::dot4([l0, l1, l2, l3], [r0, r1, r2, r3]),
10274 }
10275 };
10276
10277 [
10278 [cell(0, 0), cell(0, 1), cell(0, 2), cell(0, 3)],
10279 [cell(1, 0), cell(1, 1), cell(1, 2), cell(1, 3)],
10280 [cell(2, 0), cell(2, 1), cell(2, 2), cell(2, 3)],
10281 [cell(3, 0), cell(3, 1), cell(3, 2), cell(3, 3)],
10282 ]
10283}
10284
10285#[inline]
10286fn multiply_arrays4_dense_ref(left: &[[Real; 4]; 4], right: &[[Real; 4]; 4]) -> [[Real; 4]; 4] {
10287 crate::trace_dispatch!("hyperlattice_matrix", "helper", "multiply4-dense-ref");
10288 let cell = |row: usize, col: usize| {
10289 let l0 = &left[row][0];
10290 let l1 = &left[row][1];
10291 let l2 = &left[row][2];
10292 let l3 = &left[row][3];
10293 let r0 = &right[0][col];
10294 let r1 = &right[1][col];
10295 let r2 = &right[2][col];
10296 let r3 = &right[3][col];
10297 if true {
10298 Real::active_signed_product_sum2(
10299 [true, true, true, true],
10300 [[l0, r0], [l1, r1], [l2, r2], [l3, r3]],
10301 )
10302 } else {
10303 Real::dot4([l0, l1, l2, l3], [r0, r1, r2, r3])
10304 }
10305 };
10306
10307 [
10308 [cell(0, 0), cell(0, 1), cell(0, 2), cell(0, 3)],
10309 [cell(1, 0), cell(1, 1), cell(1, 2), cell(1, 3)],
10310 [cell(2, 0), cell(2, 1), cell(2, 2), cell(2, 3)],
10311 [cell(3, 0), cell(3, 1), cell(3, 2), cell(3, 3)],
10312 ]
10313}
10314
10315#[inline]
10316fn multiply_arrays4_dense_known_rational_ref(
10317 left: &[[Real; 4]; 4],
10318 right: &[[Real; 4]; 4],
10319) -> [[Real; 4]; 4] {
10320 crate::trace_dispatch!(
10321 "hyperlattice_matrix",
10322 "helper",
10323 "multiply4-dense-known-rational-ref"
10324 );
10325 let cell = |row: usize, col: usize| {
10326 let l0 = &left[row][0];
10327 let l1 = &left[row][1];
10328 let l2 = &left[row][2];
10329 let l3 = &left[row][3];
10330 let r0 = &right[0][col];
10331 let r1 = &right[1][col];
10332 let r2 = &right[2][col];
10333 let r3 = &right[3][col];
10334 Real::active_signed_product_sum2_known_exact_rational(
10335 [true, true, true, true],
10336 [[l0, r0], [l1, r1], [l2, r2], [l3, r3]],
10337 )
10338 };
10339
10340 [
10341 [cell(0, 0), cell(0, 1), cell(0, 2), cell(0, 3)],
10342 [cell(1, 0), cell(1, 1), cell(1, 2), cell(1, 3)],
10343 [cell(2, 0), cell(2, 1), cell(2, 2), cell(2, 3)],
10344 [cell(3, 0), cell(3, 1), cell(3, 2), cell(3, 3)],
10345 ]
10346}
10347
10348#[inline]
10349fn multiply_arrays3(left: [[Real; 3]; 3], right: [[Real; 3]; 3]) -> [[Real; 3]; 3] {
10350 let left_facts = matrix3_facts(&left);
10355 let right_facts = matrix3_facts(&right);
10356 if left_facts.is_identity {
10357 crate::trace_dispatch!(
10358 "hyperlattice_matrix",
10359 "helper",
10360 "multiply3-owned-owned-identity-left"
10361 );
10362 return right;
10363 }
10364 if right_facts.is_identity {
10365 crate::trace_dispatch!(
10366 "hyperlattice_matrix",
10367 "helper",
10368 "multiply3-owned-owned-identity-right"
10369 );
10370 return left;
10371 }
10372 if left_facts.is_diagonal {
10373 crate::trace_dispatch!(
10374 "hyperlattice_matrix",
10375 "helper",
10376 "multiply3-owned-owned-diagonal-left"
10377 );
10378 return multiply_matrix3_by_left_diagonal(&left, &right);
10379 }
10380 if right_facts.is_diagonal {
10381 crate::trace_dispatch!(
10382 "hyperlattice_matrix",
10383 "helper",
10384 "multiply3-owned-owned-diagonal-right"
10385 );
10386 return multiply_matrix3_by_right_diagonal(&left, &right);
10387 }
10388
10389 crate::trace_dispatch!(
10390 "hyperlattice_matrix",
10391 "helper",
10392 "multiply3-owned-owned-specialized"
10393 );
10394 multiply_arrays3_borrowed(&left, &right)
10395}
10396
10397#[inline]
10398fn multiply_arrays4(left: [[Real; 4]; 4], right: [[Real; 4]; 4]) -> [[Real; 4]; 4] {
10399 let left_facts = matrix4_facts(&left);
10400 let right_facts = matrix4_facts(&right);
10401 if left_facts.is_identity {
10402 crate::trace_dispatch!(
10403 "hyperlattice_matrix",
10404 "helper",
10405 "multiply4-owned-owned-identity-left"
10406 );
10407 return right;
10408 }
10409 if right_facts.is_identity {
10410 crate::trace_dispatch!(
10411 "hyperlattice_matrix",
10412 "helper",
10413 "multiply4-owned-owned-identity-right"
10414 );
10415 return left;
10416 }
10417 if left_facts.is_diagonal {
10418 crate::trace_dispatch!(
10419 "hyperlattice_matrix",
10420 "helper",
10421 "multiply4-owned-owned-diagonal-left"
10422 );
10423 return multiply_matrix4_by_left_diagonal(&left, &right);
10424 }
10425 if right_facts.is_diagonal {
10426 crate::trace_dispatch!(
10427 "hyperlattice_matrix",
10428 "helper",
10429 "multiply4-owned-owned-diagonal-right"
10430 );
10431 return multiply_matrix4_by_right_diagonal(&left, &right);
10432 }
10433
10434 crate::trace_dispatch!(
10435 "hyperlattice_matrix",
10436 "helper",
10437 "multiply4-owned-owned-specialized"
10438 );
10439 multiply_arrays4_borrowed(&left, &right)
10440}
10441
10442#[inline]
10443fn multiply_arrays3_rhs_ref(left: [[Real; 3]; 3], right: &[[Real; 3]; 3]) -> [[Real; 3]; 3] {
10444 let left_facts = matrix3_facts(&left);
10445 let right_facts = matrix3_facts(right);
10446 if left_facts.is_identity {
10447 crate::trace_dispatch!(
10448 "hyperlattice_matrix",
10449 "helper",
10450 "multiply3-owned-ref-identity-left"
10451 );
10452 return right.clone();
10453 }
10454 if right_facts.is_identity {
10455 crate::trace_dispatch!(
10456 "hyperlattice_matrix",
10457 "helper",
10458 "multiply3-owned-ref-identity-right"
10459 );
10460 return left;
10461 }
10462 if left_facts.is_diagonal {
10463 crate::trace_dispatch!(
10464 "hyperlattice_matrix",
10465 "helper",
10466 "multiply3-owned-ref-diagonal-left"
10467 );
10468 return multiply_matrix3_by_left_diagonal(&left, right);
10469 }
10470 if right_facts.is_diagonal {
10471 crate::trace_dispatch!(
10472 "hyperlattice_matrix",
10473 "helper",
10474 "multiply3-owned-ref-diagonal-right"
10475 );
10476 return multiply_matrix3_by_right_diagonal(&left, right);
10477 }
10478
10479 crate::trace_dispatch!(
10480 "hyperlattice_matrix",
10481 "helper",
10482 "multiply3-owned-ref-specialized"
10483 );
10484 multiply_arrays3_borrowed(&left, right)
10485}
10486
10487#[inline]
10488fn multiply_arrays4_rhs_ref(left: [[Real; 4]; 4], right: &[[Real; 4]; 4]) -> [[Real; 4]; 4] {
10489 let left_facts = matrix4_facts(&left);
10490 let right_facts = matrix4_facts(right);
10491 if left_facts.is_identity {
10492 crate::trace_dispatch!(
10493 "hyperlattice_matrix",
10494 "helper",
10495 "multiply4-owned-ref-identity-left"
10496 );
10497 return right.clone();
10498 }
10499 if right_facts.is_identity {
10500 crate::trace_dispatch!(
10501 "hyperlattice_matrix",
10502 "helper",
10503 "multiply4-owned-ref-identity-right"
10504 );
10505 return left;
10506 }
10507 if left_facts.is_diagonal {
10508 crate::trace_dispatch!(
10509 "hyperlattice_matrix",
10510 "helper",
10511 "multiply4-owned-ref-diagonal-left"
10512 );
10513 return multiply_matrix4_by_left_diagonal(&left, right);
10514 }
10515 if right_facts.is_diagonal {
10516 crate::trace_dispatch!(
10517 "hyperlattice_matrix",
10518 "helper",
10519 "multiply4-owned-ref-diagonal-right"
10520 );
10521 return multiply_matrix4_by_right_diagonal(&left, right);
10522 }
10523
10524 crate::trace_dispatch!(
10525 "hyperlattice_matrix",
10526 "helper",
10527 "multiply4-owned-ref-specialized"
10528 );
10529 multiply_arrays4_borrowed(&left, right)
10530}
10531
10532#[inline]
10533fn multiply_arrays3_ref(left: &[[Real; 3]; 3], right: &[[Real; 3]; 3]) -> [[Real; 3]; 3] {
10534 crate::trace_dispatch!(
10539 "hyperlattice_matrix",
10540 "helper",
10541 "multiply3-ref-ref-specialized"
10542 );
10543
10544 let left_facts = matrix3_facts(left);
10545 let right_facts = matrix3_facts(right);
10546 if left_facts.is_identity {
10547 crate::trace_dispatch!(
10548 "hyperlattice_matrix",
10549 "helper",
10550 "multiply3-ref-ref-identity-left"
10551 );
10552 return right.clone();
10553 }
10554 if right_facts.is_identity {
10555 crate::trace_dispatch!(
10556 "hyperlattice_matrix",
10557 "helper",
10558 "multiply3-ref-ref-identity-right"
10559 );
10560 return left.clone();
10561 }
10562 if left_facts.is_diagonal {
10563 crate::trace_dispatch!(
10564 "hyperlattice_matrix",
10565 "helper",
10566 "multiply3-ref-ref-diagonal-left"
10567 );
10568 return multiply_matrix3_by_left_diagonal(left, right);
10569 }
10570 if right_facts.is_diagonal {
10571 crate::trace_dispatch!(
10572 "hyperlattice_matrix",
10573 "helper",
10574 "multiply3-ref-ref-diagonal-right"
10575 );
10576 return multiply_matrix3_by_right_diagonal(left, right);
10577 }
10578
10579 multiply_arrays3_borrowed(left, right)
10580}
10581
10582#[inline]
10583fn multiply_arrays4_ref(left: &[[Real; 4]; 4], right: &[[Real; 4]; 4]) -> [[Real; 4]; 4] {
10584 crate::trace_dispatch!(
10589 "hyperlattice_matrix",
10590 "helper",
10591 "multiply4-ref-ref-specialized"
10592 );
10593
10594 let left_facts = matrix4_facts(left);
10595 let right_facts = matrix4_facts(right);
10596 if left_facts.is_identity {
10597 crate::trace_dispatch!(
10598 "hyperlattice_matrix",
10599 "helper",
10600 "multiply4-ref-ref-identity-left"
10601 );
10602 return right.clone();
10603 }
10604 if right_facts.is_identity {
10605 crate::trace_dispatch!(
10606 "hyperlattice_matrix",
10607 "helper",
10608 "multiply4-ref-ref-identity-right"
10609 );
10610 return left.clone();
10611 }
10612 if left_facts.is_diagonal {
10613 crate::trace_dispatch!(
10614 "hyperlattice_matrix",
10615 "helper",
10616 "multiply4-ref-ref-diagonal-left"
10617 );
10618 return multiply_matrix4_by_left_diagonal(left, right);
10619 }
10620 if right_facts.is_diagonal {
10621 crate::trace_dispatch!(
10622 "hyperlattice_matrix",
10623 "helper",
10624 "multiply4-ref-ref-diagonal-right"
10625 );
10626 return multiply_matrix4_by_right_diagonal(left, right);
10627 }
10628
10629 multiply_arrays4_borrowed(left, right)
10630}
10631
10632fn transform_vector_rhs_ref<const N: usize>(left: &[[Real; N]; N], right: &[Real; N]) -> [Real; N] {
10633 if N == 4 {
10634 let left_facts = matrix4_facts_assuming_const4(left);
10640 if left_facts.is_identity {
10641 crate::trace_dispatch!(
10642 "hyperlattice_matrix",
10643 "helper",
10644 "transform-vector4-identity"
10645 );
10646 return right.clone();
10647 }
10648
10649 if left_facts.is_diagonal {
10650 crate::trace_dispatch!(
10651 "hyperlattice_matrix",
10652 "helper",
10653 "transform-vector4-diagonal"
10654 );
10655 return from_fn(|row| right[row].clone().mul_cached(&left[row][row]));
10656 }
10657
10658 match right[3].zero_one_or_minus_one() {
10665 RealZeroOneMinusOneStatus::Zero => {
10666 crate::trace_dispatch!(
10667 "hyperlattice_matrix",
10668 "helper",
10669 "transform-vector-direction"
10670 );
10671 if left_facts.direction_linear_is_diagonal {
10672 crate::trace_dispatch!(
10673 "hyperlattice_matrix",
10674 "helper",
10675 "transform-vector-direction-diagonal"
10676 );
10677 return from_fn(|row| {
10678 if row == 3 {
10679 Real::zero()
10680 } else {
10681 right[row].clone().mul_cached(&left[row][row])
10682 }
10683 });
10684 }
10685 let vector_terms = [&right[0], &right[1], &right[2]];
10686 return from_fn(|row| {
10687 let matrix_terms = [&left[row][0], &left[row][1], &left[row][2]];
10688 Real::linear_combination3(matrix_terms, vector_terms)
10689 });
10690 }
10691 RealZeroOneMinusOneStatus::One => {
10692 crate::trace_dispatch!("hyperlattice_matrix", "helper", "transform-vector-point");
10693 if left_facts.is_affine && left_facts.linear_is_diagonal {
10694 crate::trace_dispatch!(
10695 "hyperlattice_matrix",
10696 "helper",
10697 "transform-vector-point-affine-linear-diagonal"
10698 );
10699 return from_fn(|row| {
10700 if row == 3 {
10701 Real::one()
10702 } else {
10703 right[row].clone().mul_cached(&left[row][row]) + &left[row][3]
10704 }
10705 });
10706 }
10707 let translation_is_zero: [bool; N] = from_fn(|row| {
10712 if row < 3 {
10713 left_facts.translation_xyz_zero[row]
10714 } else {
10715 left[row][3].definitely_zero()
10716 }
10717 });
10718 let vector_terms = [&right[0], &right[1], &right[2]];
10719 return from_fn(|row| {
10720 let matrix_terms = [&left[row][0], &left[row][1], &left[row][2]];
10721 let mapped = Real::linear_combination3(matrix_terms, vector_terms);
10725 if translation_is_zero[row] {
10726 mapped
10727 } else {
10728 mapped + &left[row][3]
10729 }
10730 });
10731 }
10732 RealZeroOneMinusOneStatus::MinusOne | RealZeroOneMinusOneStatus::NeitherOrUnknown => {}
10733 }
10734
10735 let translation_is_zero: [bool; N] = from_fn(|row| {
10738 if row < 3 {
10739 left_facts.translation_xyz_zero[row]
10740 } else {
10741 left[row][3].definitely_zero()
10742 }
10743 });
10744 let vector_terms = [&right[0], &right[1], &right[2]];
10745 crate::trace_dispatch!("hyperlattice_matrix", "helper", "transform-vector-full");
10746 from_fn(|row| {
10747 if translation_is_zero[row] {
10748 let matrix_terms = [&left[row][0], &left[row][1], &left[row][2]];
10749 Real::linear_combination3(matrix_terms, vector_terms)
10750 } else {
10751 let matrix_terms = [&left[row][0], &left[row][1], &left[row][2], &left[row][3]];
10752 let vector_terms = [&right[0], &right[1], &right[2], &right[3]];
10753 Real::linear_combination4(matrix_terms, vector_terms)
10757 }
10758 })
10759 } else {
10760 let left_facts = matrix3_facts_assuming_const3(left);
10767 if left_facts.is_identity {
10768 crate::trace_dispatch!(
10769 "hyperlattice_matrix",
10770 "helper",
10771 "transform-vector3-identity"
10772 );
10773 return right.clone();
10774 }
10775
10776 if left_facts.is_diagonal {
10777 crate::trace_dispatch!(
10778 "hyperlattice_matrix",
10779 "helper",
10780 "transform-vector3-diagonal"
10781 );
10782 return from_fn(|row| right[row].clone().mul_cached(&left[row][row]));
10783 }
10784
10785 let vector_terms = [&right[0], &right[1], &right[2]];
10786 from_fn(|row| {
10787 let matrix_terms = [&left[row][0], &left[row][1], &left[row][2]];
10788 Real::linear_combination3(matrix_terms, vector_terms)
10791 })
10792 }
10793}
10794
10795#[inline]
10796fn transform_vector3_rhs_ref_cached(left: &[[Real; 3]; 3], right: &[Real; 3]) -> [Real; 3] {
10797 let matrix_facts = matrix3_facts(left);
10807 if matrix_facts.is_identity {
10808 crate::trace_dispatch!(
10809 "hyperlattice_matrix",
10810 "helper",
10811 "transform-vector3-identity"
10812 );
10813 return right.clone();
10814 }
10815
10816 if matrix_facts.is_diagonal {
10817 crate::trace_dispatch!(
10818 "hyperlattice_matrix",
10819 "helper",
10820 "transform-vector3-diagonal"
10821 );
10822 return from_fn(|row| right[row].clone().mul_cached(&left[row][row]));
10823 }
10824
10825 crate::trace_dispatch!("hyperlattice_matrix", "helper", "transform-vector3-dense");
10826 transform_vector3_rhs_dense_ref(left, right)
10827}
10828
10829#[inline]
10830fn transform_vector3_rhs_dense_ref(left: &[[Real; 3]; 3], right: &[Real; 3]) -> [Real; 3] {
10831 let vector_terms = [&right[0], &right[1], &right[2]];
10832 from_fn(|row| {
10833 let matrix_terms = [&left[row][0], &left[row][1], &left[row][2]];
10834 Real::linear_combination3(matrix_terms, vector_terms)
10835 })
10836}
10837
10838#[inline]
10839fn transform_vector3_rhs_dense_active_ref(left: &[[Real; 3]; 3], right: &[Real; 3]) -> [Real; 3] {
10840 crate::trace_dispatch!(
10841 "hyperlattice_matrix",
10842 "helper",
10843 "transform-vector3-dense-active"
10844 );
10845 let vector_terms = [&right[0], &right[1], &right[2]];
10846 from_fn(|row| {
10847 let matrix_terms = [&left[row][0], &left[row][1], &left[row][2]];
10848 Real::active_linear_combination3(matrix_terms, vector_terms)
10849 })
10850}
10851
10852#[inline]
10853fn transform_vector4_rhs_ref_cached_with_matrix_facts(
10854 left: &[[Real; 4]; 4],
10855 right: &[Real; 4],
10856 translation_is_zero: &[bool; 4],
10857 matrix_facts: Matrix4Facts,
10858) -> [Real; 4] {
10859 if matrix_facts.is_identity {
10860 crate::trace_dispatch!(
10861 "hyperlattice_matrix",
10862 "helper",
10863 "transform-vector4-identity"
10864 );
10865 return right.clone();
10866 }
10867
10868 if matrix_facts.is_diagonal {
10869 crate::trace_dispatch!(
10870 "hyperlattice_matrix",
10871 "helper",
10872 "transform-vector4-diagonal"
10873 );
10874 return from_fn(|row| right[row].clone().mul_cached(&left[row][row]));
10875 }
10876
10877 let vector_terms = [&right[0], &right[1], &right[2]];
10883 match right[3].zero_one_or_minus_one() {
10884 RealZeroOneMinusOneStatus::Zero => {
10885 crate::trace_dispatch!(
10887 "hyperlattice_matrix",
10888 "helper",
10889 "transform-vector4-direction"
10890 );
10891 return transform_vector4_rhs_direction_ref_cached(
10892 left,
10893 right,
10894 matrix_facts.direction_linear_is_diagonal,
10895 );
10896 }
10897 RealZeroOneMinusOneStatus::One => {
10898 crate::trace_dispatch!("hyperlattice_matrix", "helper", "transform-vector4-point");
10901 return transform_vector4_rhs_point_ref_cached(left, right, translation_is_zero);
10902 }
10903 RealZeroOneMinusOneStatus::MinusOne | RealZeroOneMinusOneStatus::NeitherOrUnknown => {}
10904 }
10905
10906 crate::trace_dispatch!("hyperlattice_matrix", "helper", "transform-vector4-full");
10907 from_fn(|row| {
10908 if translation_is_zero[row] {
10909 let matrix_terms = [&left[row][0], &left[row][1], &left[row][2]];
10910 Real::linear_combination3(matrix_terms, vector_terms)
10911 } else {
10912 let matrix_terms = [&left[row][0], &left[row][1], &left[row][2], &left[row][3]];
10913 let vector_terms = [&right[0], &right[1], &right[2], &right[3]];
10914 Real::linear_combination4(matrix_terms, vector_terms)
10918 }
10919 })
10920}
10921
10922#[inline]
10923fn transform_vector4_rhs_ref_with_facts(
10924 left: &[[Real; 4]; 4],
10925 right: &[Real; 4],
10926 translation_is_zero: &[bool; 4],
10927 all_translation_zero: bool,
10928 all_translation_nonzero: bool,
10929 direction_is_diagonal: bool,
10930 matrix_facts: Option<Matrix4Facts>,
10931 facts: Vector4GeometricFacts,
10932) -> [Real; 4] {
10933 match facts.homogeneous {
10938 Vector4HomogeneousKind::Direction => {
10939 transform_vector4_rhs_direction_ref_cached(left, right, direction_is_diagonal)
10942 }
10943 Vector4HomogeneousKind::Point => {
10944 if all_translation_zero {
10945 transform_vector4_rhs_full_no_translation_ref_cached(left, right)
10946 } else if all_translation_nonzero {
10947 transform_vector4_rhs_point_all_nonzero_ref_cached(left, right)
10948 } else {
10949 transform_vector4_rhs_point_ref_cached(left, right, translation_is_zero)
10950 }
10951 }
10952 Vector4HomogeneousKind::Unknown => {
10953 let matrix_facts = matrix_facts.unwrap_or_else(|| matrix4_facts(left));
10954 transform_vector4_rhs_ref_cached_with_matrix_facts(
10955 left,
10956 right,
10957 translation_is_zero,
10958 matrix_facts,
10959 )
10960 }
10961 }
10962}
10963
10964#[inline]
10965fn transform_vector4_rhs_direction_ref_cached(
10966 left: &[[Real; 4]; 4],
10967 right: &[Real; 4],
10968 direction_is_diagonal: bool,
10969) -> [Real; 4] {
10970 if direction_is_diagonal {
10971 crate::trace_dispatch!(
10972 "hyperlattice_matrix",
10973 "helper",
10974 "transform-vector4-direction-diagonal-facts"
10975 );
10976 return [
10977 right[0].clone().mul_cached(&left[0][0]),
10978 right[1].clone().mul_cached(&left[1][1]),
10979 right[2].clone().mul_cached(&left[2][2]),
10980 Real::zero(),
10981 ];
10982 }
10983
10984 crate::trace_dispatch!(
10988 "hyperlattice_matrix",
10989 "helper",
10990 "transform-vector4-batch-direction"
10991 );
10992 let vector_terms = [&right[0], &right[1], &right[2]];
10993 from_fn(|row| {
10994 let matrix_terms = [&left[row][0], &left[row][1], &left[row][2]];
10995 Real::linear_combination3(matrix_terms, vector_terms)
10996 })
10997}
10998
10999fn transform_vector4_direction_batch_assumed_ref(
11000 left: &[[Real; 4]; 4],
11001 rhs: &[Vector4],
11002 direction_is_diagonal: bool,
11003) -> Vec<Vector4> {
11004 let mut transformed = Vec::with_capacity(rhs.len());
11005 if direction_is_diagonal {
11006 crate::trace_dispatch!(
11007 "hyperlattice_matrix",
11008 "helper",
11009 "transform-vector4-direction-batch-diagonal-assumed"
11010 );
11011 for vector in rhs {
11012 transformed.push(Vector4([
11013 vector.0[0].clone().mul_cached(&left[0][0]),
11014 vector.0[1].clone().mul_cached(&left[1][1]),
11015 vector.0[2].clone().mul_cached(&left[2][2]),
11016 Real::zero(),
11017 ]));
11018 }
11019 return transformed;
11020 }
11021
11022 crate::trace_dispatch!(
11023 "hyperlattice_matrix",
11024 "helper",
11025 "transform-vector4-direction-batch-linear-assumed"
11026 );
11027 for vector in rhs {
11028 let vector_terms = [&vector.0[0], &vector.0[1], &vector.0[2]];
11035 transformed.push(Vector4(from_fn(|row| {
11036 let matrix_terms = [&left[row][0], &left[row][1], &left[row][2]];
11037 Real::linear_combination3(matrix_terms, vector_terms)
11038 })));
11039 }
11040 transformed
11041}
11042
11043#[inline]
11044fn transform_vector4_rhs_point_affine_linear_diagonal_ref_cached(
11045 left: &[[Real; 4]; 4],
11046 right: &[Real; 4],
11047) -> [Real; 4] {
11048 crate::trace_dispatch!(
11055 "hyperlattice_matrix",
11056 "helper",
11057 "transform-vector4-point-affine-linear-diagonal"
11058 );
11059 [
11060 right[0].clone().mul_cached(&left[0][0]) + &left[0][3],
11061 right[1].clone().mul_cached(&left[1][1]) + &left[1][3],
11062 right[2].clone().mul_cached(&left[2][2]) + &left[2][3],
11063 right[3].clone(),
11071 ]
11072}
11073
11074#[inline]
11075fn transform_vector4_rhs_point_with_scaled_w_ref_cached(
11076 left: &[[Real; 4]; 4],
11077 right: &[Real; 4],
11078 translation_is_zero: &[bool; 4],
11079 all_translation_zero: bool,
11080 all_translation_nonzero: bool,
11081 w_scale_is_one: bool,
11082 w_scale: &Real,
11083) -> [Real; 4] {
11084 let vector_terms = [&right[0], &right[1], &right[2]];
11091 if all_translation_zero {
11095 crate::trace_dispatch!(
11096 "hyperlattice_matrix",
11097 "helper",
11098 "transform-vector4-point-scaled-w-full-no-translation"
11099 );
11100 return from_fn(|row| {
11101 let matrix_terms = [&left[row][0], &left[row][1], &left[row][2]];
11102 Real::linear_combination3(matrix_terms, vector_terms)
11103 });
11104 }
11105
11106 if all_translation_nonzero {
11107 crate::trace_dispatch!(
11111 "hyperlattice_matrix",
11112 "helper",
11113 "transform-vector4-point-scaled-w-full-nonzero"
11114 );
11115 let translation: [Real; 4] = if w_scale_is_one {
11116 from_fn(|row| left[row][3].clone())
11117 } else {
11118 from_fn(|row| left[row][3].clone().mul_cached(w_scale))
11119 };
11120 if true {
11121 crate::trace_dispatch!(
11122 "hyperlattice_matrix",
11123 "helper",
11124 "transform-vector4-point-scaled-w-full-nonzero-active"
11125 );
11126 return from_fn(|row| {
11127 let matrix_terms = [&left[row][0], &left[row][1], &left[row][2]];
11128 Real::active_linear_combination3(matrix_terms, vector_terms) + &translation[row]
11129 });
11130 }
11131 return from_fn(|row| {
11132 let matrix_terms = [&left[row][0], &left[row][1], &left[row][2]];
11133 Real::linear_combination3(matrix_terms, vector_terms) + &translation[row]
11134 });
11135 }
11136
11137 crate::trace_dispatch!(
11140 "hyperlattice_matrix",
11141 "helper",
11142 "transform-vector4-point-scaled-w-partial"
11143 );
11144 from_fn(|row| {
11145 let matrix_terms = [&left[row][0], &left[row][1], &left[row][2]];
11146 let mapped = Real::linear_combination3(matrix_terms, vector_terms);
11147 if translation_is_zero[row] {
11148 mapped
11149 } else {
11150 if w_scale_is_one {
11151 mapped + &left[row][3]
11152 } else {
11153 mapped + &left[row][3].clone().mul_cached(w_scale)
11154 }
11155 }
11156 })
11157}
11158
11159#[inline]
11160fn transform_vector4_rhs_point_ref_cached(
11161 left: &[[Real; 4]; 4],
11162 right: &[Real; 4],
11163 translation_is_zero: &[bool; 4],
11164) -> [Real; 4] {
11165 crate::trace_dispatch!(
11172 "hyperlattice_matrix",
11173 "helper",
11174 "transform-vector4-batch-point"
11175 );
11176 let vector_terms = [&right[0], &right[1], &right[2]];
11177 from_fn(|row| {
11178 let matrix_terms = [&left[row][0], &left[row][1], &left[row][2]];
11179 let mapped = Real::linear_combination3(matrix_terms, vector_terms);
11180 if translation_is_zero[row] {
11181 mapped
11182 } else {
11183 mapped + &left[row][3]
11184 }
11185 })
11186}
11187
11188#[inline]
11189fn transform_vector4_rhs_point_all_nonzero_ref_cached(
11190 left: &[[Real; 4]; 4],
11191 right: &[Real; 4],
11192) -> [Real; 4] {
11193 crate::trace_dispatch!(
11196 "hyperlattice_matrix",
11197 "helper",
11198 "transform-vector4-point-all-nonzero"
11199 );
11200 let vector_terms = [&right[0], &right[1], &right[2]];
11201 from_fn(|row| {
11202 let matrix_terms = [&left[row][0], &left[row][1], &left[row][2]];
11203 Real::linear_combination3(matrix_terms, vector_terms) + &left[row][3]
11204 })
11205}
11206
11207#[inline]
11208fn transform_vector4_rhs_full_no_translation_ref_cached(
11209 left: &[[Real; 4]; 4],
11210 right: &[Real; 4],
11211) -> [Real; 4] {
11212 crate::trace_dispatch!(
11213 "hyperlattice_matrix",
11214 "helper",
11215 "transform-vector4-batch-full-no-translation"
11216 );
11217 let vector_terms = [&right[0], &right[1], &right[2]];
11218 from_fn(|row| {
11219 let matrix_terms = [&left[row][0], &left[row][1], &left[row][2]];
11220 Real::linear_combination3(matrix_terms, vector_terms)
11221 })
11222}
11223
11224#[derive(Clone, Copy, Debug)]
11225pub struct TransformedMatrix3<'a> {
11226 matrix: &'a Matrix3,
11227 facts: Matrix3Facts,
11228}
11229
11230impl<'a> TransformedMatrix3<'a> {
11231 fn new(matrix: &'a Matrix3) -> Self {
11232 let facts = matrix3_facts(&matrix.0);
11233 Self::new_with_facts(matrix, facts)
11234 }
11235
11236 fn new_with_facts(matrix: &'a Matrix3, facts: Matrix3Facts) -> Self {
11237 Self { matrix, facts }
11238 }
11239
11240 pub fn transform_vector(&self, rhs: &Vector3) -> Vector3 {
11241 if self.facts.is_identity {
11242 crate::trace_dispatch!(
11243 "hyperlattice_matrix",
11244 "method",
11245 "transform-vector3-identity"
11246 );
11247 return rhs.clone();
11248 }
11249 if self.facts.is_diagonal {
11250 crate::trace_dispatch!(
11251 "hyperlattice_matrix",
11252 "method",
11253 "transform-vector3-diagonal"
11254 );
11255 return Vector3(from_fn(|row| {
11256 rhs.0[row].clone().mul_cached(&self.matrix.0[row][row])
11257 }));
11258 }
11259 crate::trace_dispatch!("hyperlattice_matrix", "helper", "transform-vector3-dense");
11260 Vector3(transform_vector3_rhs_dense_ref(&self.matrix.0, &rhs.0))
11261 }
11262
11263 pub fn vector(&self, rhs: &'a Vector3) -> TransformedVector3<'a> {
11264 TransformedVector3 {
11265 matrix: self.matrix,
11266 facts: self.facts,
11267 vector: rhs,
11268 }
11269 }
11270
11271 pub fn transform_vector_batch(&self, rhs: &[Vector3]) -> Vec<Vector3> {
11272 if self.facts.is_identity {
11273 crate::trace_dispatch!(
11274 "hyperlattice_matrix",
11275 "method",
11276 "transform-vector3-batch-identity"
11277 );
11278 return rhs.to_vec();
11279 }
11280 if self.facts.is_diagonal {
11281 crate::trace_dispatch!(
11282 "hyperlattice_matrix",
11283 "method",
11284 "transform-vector3-batch-diagonal"
11285 );
11286 return rhs
11287 .iter()
11288 .map(|vector| {
11289 Vector3(from_fn(|row| {
11290 vector.0[row].clone().mul_cached(&self.matrix.0[row][row])
11291 }))
11292 })
11293 .collect();
11294 }
11295 let mut transformed = Vec::with_capacity(rhs.len());
11296 for vector in rhs {
11297 transformed.push(self.transform_vector(vector));
11298 }
11299 transformed
11300 }
11301}
11302
11303#[derive(Clone, Copy, Debug)]
11304pub struct TransformedMatrix4<'a> {
11305 matrix: &'a Matrix4,
11306 facts: Matrix4Facts,
11307 translation_is_zero: [bool; 4],
11308 all_translation_zero: bool,
11309 all_translation_nonzero: bool,
11310 direction_is_diagonal: bool,
11311}
11312
11313impl<'a> TransformedMatrix4<'a> {
11314 #[inline]
11315 fn transform_vector_with_facts(
11316 &self,
11317 rhs: &Vector4,
11318 vector_facts: Vector4GeometricFacts,
11319 ) -> Vector4 {
11320 if self.facts.is_identity {
11321 crate::trace_dispatch!(
11322 "hyperlattice_matrix",
11323 "method",
11324 "transform-vector4-identity"
11325 );
11326 return rhs.clone();
11327 }
11328 if self.facts.is_diagonal {
11329 crate::trace_dispatch!(
11330 "hyperlattice_matrix",
11331 "method",
11332 "transform-vector4-diagonal"
11333 );
11334 if matches!(vector_facts.homogeneous, Vector4HomogeneousKind::Direction) {
11335 return Vector4([
11336 rhs.0[0].clone().mul_cached(&self.matrix.0[0][0]),
11337 rhs.0[1].clone().mul_cached(&self.matrix.0[1][1]),
11338 rhs.0[2].clone().mul_cached(&self.matrix.0[2][2]),
11339 Real::zero(),
11340 ]);
11341 }
11342 if matches!(vector_facts.homogeneous, Vector4HomogeneousKind::Point)
11343 && self.facts.is_affine
11344 {
11345 return Vector4(
11353 transform_vector4_rhs_point_affine_linear_diagonal_ref_cached(
11354 &self.matrix.0,
11355 &rhs.0,
11356 ),
11357 );
11358 }
11359 return Vector4(from_fn(|row| {
11360 rhs.0[row].clone().mul_cached(&self.matrix.0[row][row])
11361 }));
11362 }
11363 if matches!(vector_facts.homogeneous, Vector4HomogeneousKind::Point)
11364 && self.facts.is_affine
11365 && self.facts.linear_is_diagonal
11366 {
11367 return Vector4(
11368 transform_vector4_rhs_point_affine_linear_diagonal_ref_cached(
11369 &self.matrix.0,
11370 &rhs.0,
11371 ),
11372 );
11373 }
11374
11375 Vector4(transform_vector4_rhs_ref_with_facts(
11376 &self.matrix.0,
11377 &rhs.0,
11378 &self.translation_is_zero,
11379 self.all_translation_zero,
11380 self.all_translation_nonzero,
11381 self.direction_is_diagonal,
11382 Some(self.facts),
11383 vector_facts,
11384 ))
11385 }
11386
11387 fn new(matrix: &'a Matrix4) -> Self {
11388 let facts = matrix4_facts(&matrix.0);
11389 Self::new_with_facts(matrix, facts)
11390 }
11391
11392 fn new_with_facts(matrix: &'a Matrix4, facts: Matrix4Facts) -> Self {
11393 let translation_is_zero = [
11401 facts.translation_xyz_zero[0],
11402 facts.translation_xyz_zero[1],
11403 facts.translation_xyz_zero[2],
11404 matrix[3][3].definitely_zero(),
11405 ];
11406 let all_translation_zero = translation_is_zero.iter().all(|value| *value);
11407 let all_translation_nonzero = translation_is_zero.iter().all(|value| !*value);
11408 let direction_is_diagonal = facts.direction_linear_is_diagonal;
11414 Self {
11415 matrix,
11416 facts,
11417 translation_is_zero,
11418 all_translation_zero,
11419 all_translation_nonzero,
11420 direction_is_diagonal,
11421 }
11422 }
11423
11424 pub fn transform_vector(&self, rhs: &Vector4) -> Vector4 {
11425 self.transform_vector_with_facts(rhs, rhs.geometric_facts())
11426 }
11427
11428 #[inline]
11429 pub fn transform_direction_vector(&self, rhs: &Vector4) -> Vector4 {
11430 self.transform_vector_with_facts(
11431 rhs,
11432 Vector4GeometricFacts {
11433 homogeneous: Vector4HomogeneousKind::Direction,
11434 },
11435 )
11436 }
11437
11438 #[inline]
11439 pub fn transform_point_vector(&self, rhs: &Vector4) -> Vector4 {
11440 if self.facts.is_identity {
11441 crate::trace_dispatch!(
11442 "hyperlattice_matrix",
11443 "method",
11444 "transform-vector4-point-identity"
11445 );
11446 return rhs.clone();
11454 }
11455 if self.facts.is_affine && self.facts.linear_is_diagonal {
11456 return Vector4(
11457 transform_vector4_rhs_point_affine_linear_diagonal_ref_cached(
11458 &self.matrix.0,
11459 &rhs.0,
11460 ),
11461 );
11462 }
11463 self.transform_vector_with_facts(
11464 rhs,
11465 Vector4GeometricFacts {
11466 homogeneous: Vector4HomogeneousKind::Point,
11467 },
11468 )
11469 }
11470
11471 pub fn vector(&self, rhs: &'a Vector4) -> TransformedVector4<'a> {
11472 TransformedVector4 {
11473 matrix: self.matrix,
11474 facts: self.facts,
11475 translation_is_zero: self.translation_is_zero,
11476 all_translation_zero: self.all_translation_zero,
11477 all_translation_nonzero: self.all_translation_nonzero,
11478 direction_is_diagonal: self.direction_is_diagonal,
11479 vector_facts: None,
11487 vector: rhs,
11488 }
11489 }
11490
11491 pub fn transform_vector_batch(&self, rhs: &[Vector4]) -> Vec<Vector4> {
11492 if self.facts.is_identity {
11493 crate::trace_dispatch!(
11494 "hyperlattice_matrix",
11495 "method",
11496 "transform-vector4-batch-identity"
11497 );
11498 return rhs.to_vec();
11499 }
11500 if self.facts.is_diagonal {
11501 let mut transformed = Vec::with_capacity(rhs.len());
11502 if let Some(first) = rhs.first() {
11503 match first.0[3].zero_one_or_minus_one() {
11504 RealZeroOneMinusOneStatus::Zero => {
11505 if rhs
11506 .iter()
11507 .skip(1)
11508 .all(|vector| vector.0[3].definitely_zero())
11509 {
11510 crate::trace_dispatch!(
11511 "hyperlattice_matrix",
11512 "helper",
11513 "transform-vector4-batch-diagonal-direction"
11514 );
11515 for vector in rhs {
11522 transformed.push(Vector4([
11523 vector.0[0].clone().mul_cached(&self.matrix.0[0][0]),
11524 vector.0[1].clone().mul_cached(&self.matrix.0[1][1]),
11525 vector.0[2].clone().mul_cached(&self.matrix.0[2][2]),
11526 Real::zero(),
11527 ]));
11528 }
11529 return transformed;
11530 }
11531 }
11532 RealZeroOneMinusOneStatus::One
11533 if self.facts.is_affine
11534 && rhs
11535 .iter()
11536 .skip(1)
11537 .all(|vector| vector.0[3].definitely_one()) =>
11538 {
11539 crate::trace_dispatch!(
11540 "hyperlattice_matrix",
11541 "helper",
11542 "transform-vector4-batch-diagonal-point"
11543 );
11544 for vector in rhs {
11550 transformed.push(Vector4([
11551 vector.0[0].clone().mul_cached(&self.matrix.0[0][0]),
11552 vector.0[1].clone().mul_cached(&self.matrix.0[1][1]),
11553 vector.0[2].clone().mul_cached(&self.matrix.0[2][2]),
11554 Real::one(),
11555 ]));
11556 }
11557 return transformed;
11558 }
11559 RealZeroOneMinusOneStatus::MinusOne
11560 | RealZeroOneMinusOneStatus::One
11561 | RealZeroOneMinusOneStatus::NeitherOrUnknown => {}
11562 }
11563 }
11564 for vector in rhs {
11565 transformed.push(Vector4(from_fn(|row| {
11566 vector.0[row].clone().mul_cached(&self.matrix.0[row][row])
11567 })));
11568 }
11569 return transformed;
11570 }
11571 let mut transformed = Vec::with_capacity(rhs.len());
11572
11573 let mut has_direction = false;
11577 let mut has_point = false;
11578 let mut has_unknown = false;
11579 for vector in rhs {
11580 match vector.geometric_facts().homogeneous {
11581 Vector4HomogeneousKind::Direction => has_direction = true,
11582 Vector4HomogeneousKind::Point => has_point = true,
11583 Vector4HomogeneousKind::Unknown => has_unknown = true,
11584 }
11585
11586 if (has_direction && has_point)
11589 || (has_direction && has_unknown)
11590 || (has_point && has_unknown)
11591 {
11592 break;
11593 }
11594 }
11595
11596 if has_direction && !has_point && !has_unknown {
11599 crate::trace_dispatch!(
11600 "hyperlattice_matrix",
11601 "helper",
11602 "transform-vector4-batch-direction"
11603 );
11604 if self.direction_is_diagonal {
11605 for vector in rhs {
11606 transformed.push(Vector4([
11607 vector.0[0].clone().mul_cached(&self.matrix.0[0][0]),
11608 vector.0[1].clone().mul_cached(&self.matrix.0[1][1]),
11609 vector.0[2].clone().mul_cached(&self.matrix.0[2][2]),
11610 Real::zero(),
11611 ]));
11612 }
11613 } else {
11614 for vector in rhs {
11615 transformed.push(Vector4(transform_vector4_rhs_direction_ref_cached(
11616 &self.matrix.0,
11617 &vector.0,
11618 self.direction_is_diagonal,
11619 )));
11620 }
11621 }
11622 return transformed;
11623 }
11624
11625 if has_point && !has_direction && !has_unknown {
11626 crate::trace_dispatch!(
11627 "hyperlattice_matrix",
11628 "helper",
11629 "transform-vector4-batch-point"
11630 );
11631 if self.facts.is_affine && self.facts.linear_is_diagonal {
11632 for vector in rhs {
11633 transformed.push(Vector4(
11634 transform_vector4_rhs_point_affine_linear_diagonal_ref_cached(
11635 &self.matrix.0,
11636 &vector.0,
11637 ),
11638 ));
11639 }
11640 } else if self.all_translation_nonzero {
11641 crate::trace_dispatch!(
11642 "hyperlattice_matrix",
11643 "helper",
11644 "transform-vector4-batch-point-all-nonzero"
11645 );
11646 for vector in rhs {
11647 transformed.push(Vector4(transform_vector4_rhs_point_all_nonzero_ref_cached(
11648 &self.matrix.0,
11649 &vector.0,
11650 )));
11651 }
11652 } else if self.all_translation_zero {
11653 crate::trace_dispatch!(
11654 "hyperlattice_matrix",
11655 "helper",
11656 "transform-vector4-batch-full-no-translation"
11657 );
11658 for vector in rhs {
11659 transformed.push(Vector4(
11660 transform_vector4_rhs_full_no_translation_ref_cached(
11661 &self.matrix.0,
11662 &vector.0,
11663 ),
11664 ));
11665 }
11666 } else {
11667 for vector in rhs {
11668 transformed.push(Vector4(transform_vector4_rhs_point_ref_cached(
11669 &self.matrix.0,
11670 &vector.0,
11671 &self.translation_is_zero,
11672 )));
11673 }
11674 }
11675 return transformed;
11676 }
11677
11678 if has_unknown && !has_direction && !has_point {
11679 crate::trace_dispatch!(
11682 "hyperlattice_matrix",
11683 "helper",
11684 "transform-vector4-batch-unknown"
11685 );
11686 for vector in rhs {
11687 transformed.push(Vector4(transform_vector4_rhs_ref_cached_with_matrix_facts(
11688 &self.matrix.0,
11689 &vector.0,
11690 &self.translation_is_zero,
11691 self.facts,
11692 )));
11693 }
11694 return transformed;
11695 }
11696
11697 let mut vector_facts = Vec::with_capacity(rhs.len());
11700 for vector in rhs {
11701 vector_facts.push(vector.geometric_facts());
11702 }
11703
11704 if has_direction && has_point && !has_unknown {
11705 crate::trace_dispatch!(
11706 "hyperlattice_matrix",
11707 "method",
11708 "transform-vector4-batch-mixed"
11709 );
11710 for (vector, facts) in rhs.iter().zip(vector_facts.iter()) {
11711 transformed.push(self.transform_vector_with_facts(vector, *facts));
11712 }
11713 return transformed;
11714 }
11715
11716 if has_unknown && (has_direction || has_point) {
11717 crate::trace_dispatch!(
11720 "hyperlattice_matrix",
11721 "method",
11722 "transform-vector4-batch-mixed"
11723 );
11724 for (vector, facts) in rhs.iter().zip(vector_facts.iter()) {
11725 transformed.push(self.transform_vector_with_facts(vector, *facts));
11726 }
11727 return transformed;
11728 }
11729
11730 for (vector, facts) in rhs.iter().zip(vector_facts.iter()) {
11733 transformed.push(self.transform_vector_with_facts(vector, *facts));
11734 }
11735 transformed
11736 }
11737
11738 pub fn transform_direction_batch(&self, rhs: &[Vector4]) -> Vec<Vector4> {
11748 crate::trace_dispatch!(
11749 "hyperlattice_matrix",
11750 "method",
11751 "transform-vector4-direction-batch-assumed"
11752 );
11753 if self.facts.is_identity {
11754 crate::trace_dispatch!(
11755 "hyperlattice_matrix",
11756 "helper",
11757 "transform-vector4-direction-batch-identity-assumed"
11758 );
11759 return rhs.to_vec();
11767 }
11768 transform_vector4_direction_batch_assumed_ref(
11769 &self.matrix.0,
11770 rhs,
11771 self.direction_is_diagonal,
11772 )
11773 }
11774
11775 pub fn transform_point_batch(&self, rhs: &[Vector4]) -> Vec<Vector4> {
11783 crate::trace_dispatch!(
11784 "hyperlattice_matrix",
11785 "method",
11786 "transform-vector4-point-batch-assumed"
11787 );
11788 if self.facts.is_identity {
11789 crate::trace_dispatch!(
11790 "hyperlattice_matrix",
11791 "helper",
11792 "transform-vector4-point-batch-identity-assumed"
11793 );
11794 return rhs.to_vec();
11800 }
11801 let mut transformed = Vec::with_capacity(rhs.len());
11802 if self.facts.is_affine && self.facts.linear_is_diagonal {
11803 crate::trace_dispatch!(
11804 "hyperlattice_matrix",
11805 "helper",
11806 "transform-vector4-point-batch-affine-linear-diagonal-assumed"
11807 );
11808 for vector in rhs {
11815 transformed.push(Vector4([
11816 vector.0[0].clone().mul_cached(&self.matrix.0[0][0]) + &self.matrix.0[0][3],
11817 vector.0[1].clone().mul_cached(&self.matrix.0[1][1]) + &self.matrix.0[1][3],
11818 vector.0[2].clone().mul_cached(&self.matrix.0[2][2]) + &self.matrix.0[2][3],
11819 Real::one(),
11824 ]));
11825 }
11826 return transformed;
11827 }
11828
11829 if self.all_translation_nonzero {
11830 crate::trace_dispatch!(
11831 "hyperlattice_matrix",
11832 "helper",
11833 "transform-vector4-point-batch-all-nonzero-assumed"
11834 );
11835 for vector in rhs {
11836 transformed.push(Vector4(transform_vector4_rhs_point_all_nonzero_ref_cached(
11837 &self.matrix.0,
11838 &vector.0,
11839 )));
11840 }
11841 return transformed;
11842 }
11843
11844 if self.all_translation_zero {
11845 crate::trace_dispatch!(
11846 "hyperlattice_matrix",
11847 "helper",
11848 "transform-vector4-point-batch-no-translation-assumed"
11849 );
11850 for vector in rhs {
11851 transformed.push(Vector4(
11852 transform_vector4_rhs_full_no_translation_ref_cached(&self.matrix.0, &vector.0),
11853 ));
11854 }
11855 return transformed;
11856 }
11857
11858 crate::trace_dispatch!(
11859 "hyperlattice_matrix",
11860 "helper",
11861 "transform-vector4-point-batch-partial-translation-assumed"
11862 );
11863 for vector in rhs {
11864 transformed.push(Vector4(transform_vector4_rhs_point_ref_cached(
11865 &self.matrix.0,
11866 &vector.0,
11867 &self.translation_is_zero,
11868 )));
11869 }
11870 transformed
11871 }
11872}
11873
11874#[derive(Clone, Copy, Debug)]
11875pub struct TransformedVector3<'a> {
11876 matrix: &'a Matrix3,
11877 facts: Matrix3Facts,
11878 vector: &'a Vector3,
11879}
11880
11881impl<'a> TransformedVector3<'a> {
11882 #[inline]
11883 pub fn materialize(self) -> Vector3 {
11884 if self.facts.is_identity {
11885 crate::trace_dispatch!(
11886 "hyperlattice_matrix",
11887 "method",
11888 "materialize-vector3-identity"
11889 );
11890 return self.vector.clone();
11891 }
11892 if self.facts.is_diagonal {
11893 crate::trace_dispatch!(
11894 "hyperlattice_matrix",
11895 "method",
11896 "materialize-vector3-diagonal"
11897 );
11898 return Vector3(from_fn(|row| {
11899 self.vector.0[row]
11900 .clone()
11901 .mul_cached(&self.matrix.0[row][row])
11902 }));
11903 }
11904 crate::trace_dispatch!("hyperlattice_matrix", "helper", "transform-vector3-dense");
11905 Vector3(transform_vector3_rhs_dense_ref(
11906 &self.matrix.0,
11907 &self.vector.0,
11908 ))
11909 }
11910}
11911
11912#[derive(Clone, Copy, Debug)]
11913pub struct TransformedVector4<'a> {
11914 matrix: &'a Matrix4,
11915 facts: Matrix4Facts,
11916 translation_is_zero: [bool; 4],
11917 all_translation_zero: bool,
11918 all_translation_nonzero: bool,
11919 direction_is_diagonal: bool,
11920 vector_facts: Option<Vector4GeometricFacts>,
11921 vector: &'a Vector4,
11922}
11923
11924impl<'a> TransformedVector4<'a> {
11925 #[inline]
11926 pub fn materialize(self) -> Vector4 {
11927 if self.facts.is_identity {
11928 crate::trace_dispatch!(
11929 "hyperlattice_matrix",
11930 "method",
11931 "materialize-vector4-identity"
11932 );
11933 return self.vector.clone();
11934 }
11935 let vector_facts = self
11936 .vector_facts
11937 .unwrap_or_else(|| self.vector.geometric_facts());
11938 if self.facts.is_diagonal {
11939 crate::trace_dispatch!(
11940 "hyperlattice_matrix",
11941 "method",
11942 "materialize-vector4-diagonal"
11943 );
11944 if matches!(vector_facts.homogeneous, Vector4HomogeneousKind::Direction) {
11945 return Vector4([
11946 self.vector.0[0].clone().mul_cached(&self.matrix.0[0][0]),
11947 self.vector.0[1].clone().mul_cached(&self.matrix.0[1][1]),
11948 self.vector.0[2].clone().mul_cached(&self.matrix.0[2][2]),
11949 Real::zero(),
11950 ]);
11951 }
11952 if matches!(vector_facts.homogeneous, Vector4HomogeneousKind::Point)
11953 && self.facts.is_affine
11954 {
11955 return Vector4(
11961 transform_vector4_rhs_point_affine_linear_diagonal_ref_cached(
11962 &self.matrix.0,
11963 &self.vector.0,
11964 ),
11965 );
11966 }
11967 return Vector4(from_fn(|row| {
11968 self.vector.0[row]
11969 .clone()
11970 .mul_cached(&self.matrix.0[row][row])
11971 }));
11972 }
11973 if matches!(vector_facts.homogeneous, Vector4HomogeneousKind::Point)
11974 && self.facts.is_affine
11975 && self.facts.linear_is_diagonal
11976 {
11977 return Vector4(
11978 transform_vector4_rhs_point_affine_linear_diagonal_ref_cached(
11979 &self.matrix.0,
11980 &self.vector.0,
11981 ),
11982 );
11983 }
11984 Vector4(transform_vector4_rhs_ref_with_facts(
11985 &self.matrix.0,
11986 &self.vector.0,
11987 &self.translation_is_zero,
11988 self.all_translation_zero,
11989 self.all_translation_nonzero,
11990 self.direction_is_diagonal,
11991 Some(self.facts),
11992 vector_facts,
11993 ))
11994 }
11995}
11996
11997#[inline]
11998fn scale_by_shared_factor(value: Real, factor: &Real) -> Real {
11999 if true {
12005 value.mul_cached(factor)
12006 } else {
12007 value * factor.clone()
12008 }
12009}
12010
12011fn scale_matrix3(matrix: [[Real; 3]; 3], factor: &Real) -> [[Real; 3]; 3] {
12012 let [[m00, m01, m02], [m10, m11, m12], [m20, m21, m22]] = matrix;
12020 [
12021 [
12022 scale_by_shared_factor(m00, factor),
12023 scale_by_shared_factor(m01, factor),
12024 scale_by_shared_factor(m02, factor),
12025 ],
12026 [
12027 scale_by_shared_factor(m10, factor),
12028 scale_by_shared_factor(m11, factor),
12029 scale_by_shared_factor(m12, factor),
12030 ],
12031 [
12032 scale_by_shared_factor(m20, factor),
12033 scale_by_shared_factor(m21, factor),
12034 scale_by_shared_factor(m22, factor),
12035 ],
12036 ]
12037}
12038
12039fn scale_matrix4(matrix: [[Real; 4]; 4], factor: &Real) -> [[Real; 4]; 4] {
12040 let [
12044 [m00, m01, m02, m03],
12045 [m10, m11, m12, m13],
12046 [m20, m21, m22, m23],
12047 [m30, m31, m32, m33],
12048 ] = matrix;
12049 [
12050 [
12051 scale_by_shared_factor(m00, factor),
12052 scale_by_shared_factor(m01, factor),
12053 scale_by_shared_factor(m02, factor),
12054 scale_by_shared_factor(m03, factor),
12055 ],
12056 [
12057 scale_by_shared_factor(m10, factor),
12058 scale_by_shared_factor(m11, factor),
12059 scale_by_shared_factor(m12, factor),
12060 scale_by_shared_factor(m13, factor),
12061 ],
12062 [
12063 scale_by_shared_factor(m20, factor),
12064 scale_by_shared_factor(m21, factor),
12065 scale_by_shared_factor(m22, factor),
12066 scale_by_shared_factor(m23, factor),
12067 ],
12068 [
12069 scale_by_shared_factor(m30, factor),
12070 scale_by_shared_factor(m31, factor),
12071 scale_by_shared_factor(m32, factor),
12072 scale_by_shared_factor(m33, factor),
12073 ],
12074 ]
12075}
12076
12077#[inline]
12078fn mul_sub(left_a: &Real, right_a: &Real, left_b: &Real, right_b: &Real) -> Real {
12079 if true {
12080 let first_zero = left_a.definitely_zero() || right_a.definitely_zero();
12087 let second_zero = left_b.definitely_zero() || right_b.definitely_zero();
12088
12089 if first_zero || second_zero {
12090 crate::trace_dispatch!("hyperlattice_matrix", "helper", "mul-sub-pruned");
12091 if first_zero && second_zero {
12092 return Real::zero();
12093 }
12094 if first_zero {
12095 return -(left_b * right_b);
12096 }
12097 return left_a * right_a;
12098 }
12099 Real::active_signed_product_sum2([true, false], [[left_a, right_a], [left_b, right_b]])
12100 } else {
12101 left_a * right_a - left_b * right_b
12102 }
12103}
12104
12105#[inline]
12106fn mul_sub_dense_exact(left_a: &Real, right_a: &Real, left_b: &Real, right_b: &Real) -> Real {
12107 crate::trace_dispatch!("hyperlattice_matrix", "helper", "mul-sub-dense-exact");
12108 Real::active_signed_product_sum2([true, false], [[left_a, right_a], [left_b, right_b]])
12109}
12110
12111#[inline]
12112fn mul_sub_dense_exact_known_rational(
12113 left_a: &Real,
12114 right_a: &Real,
12115 left_b: &Real,
12116 right_b: &Real,
12117) -> Real {
12118 crate::trace_dispatch!(
12119 "hyperlattice_matrix",
12120 "helper",
12121 "mul-sub-dense-exact-known-rational"
12122 );
12123 Real::active_signed_product_sum2_known_exact_rational(
12124 [true, false],
12125 [[left_a, right_a], [left_b, right_b]],
12126 )
12127}
12128
12129fn mul_add(left_a: &Real, right_a: &Real, left_b: &Real, right_b: &Real) -> Real {
12130 if true {
12131 let first_zero = left_a.definitely_zero() || right_a.definitely_zero();
12138 let second_zero = left_b.definitely_zero() || right_b.definitely_zero();
12139
12140 if first_zero || second_zero {
12141 crate::trace_dispatch!("hyperlattice_matrix", "helper", "mul-add-pruned");
12142 if first_zero && second_zero {
12143 return Real::zero();
12144 }
12145 if first_zero {
12146 return left_b * right_b;
12147 }
12148 return left_a * right_a;
12149 }
12150 Real::active_signed_product_sum2([true, true], [[left_a, right_a], [left_b, right_b]])
12151 } else {
12152 left_a * right_a + left_b * right_b
12153 }
12154}
12155
12156#[inline]
12157fn mul_add_sub(
12158 left_a: &Real,
12159 right_a: &Real,
12160 left_b: &Real,
12161 right_b: &Real,
12162 left_c: &Real,
12163 right_c: &Real,
12164) -> Real {
12165 if true {
12166 let first_zero = left_a.definitely_zero() || right_a.definitely_zero();
12172 let second_zero = left_b.definitely_zero() || right_b.definitely_zero();
12173 let third_zero = left_c.definitely_zero() || right_c.definitely_zero();
12174 let nonzero_count = (!first_zero) as u8 + (!second_zero) as u8 + (!third_zero) as u8;
12175
12176 if nonzero_count <= 2 {
12177 crate::trace_dispatch!("hyperlattice_matrix", "helper", "mul-add-sub-pruned");
12178 return match nonzero_count {
12179 0 => Real::zero(),
12180 1 => {
12181 if !first_zero {
12182 left_a * right_a
12183 } else if !second_zero {
12184 left_b * right_b
12185 } else {
12186 -(left_c * right_c)
12187 }
12188 }
12189 2 => {
12190 if first_zero {
12191 Real::active_signed_product_sum2(
12192 [true, false],
12193 [[left_b, right_b], [left_c, right_c]],
12194 )
12195 } else if second_zero {
12196 Real::active_signed_product_sum2(
12197 [true, false],
12198 [[left_a, right_a], [left_c, right_c]],
12199 )
12200 } else {
12201 Real::active_signed_product_sum2(
12202 [true, true],
12203 [[left_a, right_a], [left_b, right_b]],
12204 )
12205 }
12206 }
12207 _ => unreachable!(),
12208 };
12209 }
12210 Real::active_signed_product_sum2(
12211 [true, true, false],
12212 [[left_a, right_a], [left_b, right_b], [left_c, right_c]],
12213 )
12214 } else {
12215 mul_add(left_a, right_a, left_b, right_b) - left_c * right_c
12216 }
12217}
12218
12219#[inline]
12220fn mul_add_sub_dense_exact(
12221 left_a: &Real,
12222 right_a: &Real,
12223 left_b: &Real,
12224 right_b: &Real,
12225 left_c: &Real,
12226 right_c: &Real,
12227) -> Real {
12228 crate::trace_dispatch!("hyperlattice_matrix", "helper", "mul-add-sub-dense-exact");
12229 Real::active_signed_product_sum2(
12230 [true, true, false],
12231 [[left_a, right_a], [left_b, right_b], [left_c, right_c]],
12232 )
12233}
12234
12235#[inline]
12236fn mul_add_sub_dense_exact_known_rational(
12237 left_a: &Real,
12238 right_a: &Real,
12239 left_b: &Real,
12240 right_b: &Real,
12241 left_c: &Real,
12242 right_c: &Real,
12243) -> Real {
12244 crate::trace_dispatch!(
12245 "hyperlattice_matrix",
12246 "helper",
12247 "mul-add-sub-dense-exact-known-rational"
12248 );
12249 Real::active_signed_product_sum2_known_exact_rational(
12250 [true, true, false],
12251 [[left_a, right_a], [left_b, right_b], [left_c, right_c]],
12252 )
12253}
12254
12255fn mul_sub_add(
12256 left_a: &Real,
12257 right_a: &Real,
12258 left_b: &Real,
12259 right_b: &Real,
12260 left_c: &Real,
12261 right_c: &Real,
12262) -> Real {
12263 if true {
12264 let first_zero = left_a.definitely_zero() || right_a.definitely_zero();
12269 let second_zero = left_b.definitely_zero() || right_b.definitely_zero();
12270 let third_zero = left_c.definitely_zero() || right_c.definitely_zero();
12271 let nonzero_count = (!first_zero) as u8 + (!second_zero) as u8 + (!third_zero) as u8;
12272
12273 if nonzero_count <= 2 {
12274 crate::trace_dispatch!("hyperlattice_matrix", "helper", "mul-sub-add-pruned");
12275 return match nonzero_count {
12276 0 => Real::zero(),
12277 1 => {
12278 if !first_zero {
12279 left_a * right_a
12280 } else if !second_zero {
12281 -(left_b * right_b)
12282 } else {
12283 -(left_c * right_c)
12284 }
12285 }
12286 2 => {
12287 if first_zero {
12288 Real::active_signed_product_sum2(
12289 [false, false],
12290 [[left_b, right_b], [left_c, right_c]],
12291 )
12292 } else if second_zero {
12293 Real::active_signed_product_sum2(
12294 [true, false],
12295 [[left_a, right_a], [left_c, right_c]],
12296 )
12297 } else {
12298 Real::active_signed_product_sum2(
12299 [true, false],
12300 [[left_a, right_a], [left_b, right_b]],
12301 )
12302 }
12303 }
12304 _ => unreachable!(),
12305 };
12306 }
12307 Real::active_signed_product_sum2(
12308 [true, false, false],
12309 [[left_a, right_a], [left_b, right_b], [left_c, right_c]],
12310 )
12311 } else {
12312 left_a * right_a - mul_add(left_b, right_b, left_c, right_c)
12313 }
12314}
12315
12316#[inline]
12317fn mul_sub_add_dense_exact(
12318 left_a: &Real,
12319 right_a: &Real,
12320 left_b: &Real,
12321 right_b: &Real,
12322 left_c: &Real,
12323 right_c: &Real,
12324) -> Real {
12325 crate::trace_dispatch!("hyperlattice_matrix", "helper", "mul-sub-add-dense-exact");
12326 Real::active_signed_product_sum2(
12327 [true, false, false],
12328 [[left_a, right_a], [left_b, right_b], [left_c, right_c]],
12329 )
12330}
12331
12332#[inline]
12333fn mul_sub_add_dense_exact_known_rational(
12334 left_a: &Real,
12335 right_a: &Real,
12336 left_b: &Real,
12337 right_b: &Real,
12338 left_c: &Real,
12339 right_c: &Real,
12340) -> Real {
12341 crate::trace_dispatch!(
12342 "hyperlattice_matrix",
12343 "helper",
12344 "mul-sub-add-dense-exact-known-rational"
12345 );
12346 Real::active_signed_product_sum2_known_exact_rational(
12347 [true, false, false],
12348 [[left_a, right_a], [left_b, right_b], [left_c, right_c]],
12349 )
12350}
12351
12352#[inline]
12353fn determinant3(m: &[[Real; 3]; 3]) -> Real {
12354 crate::trace_dispatch!("hyperlattice_matrix", "helper", "determinant3");
12355 let c00 = mul_sub(&m[1][1], &m[2][2], &m[1][2], &m[2][1]);
12365 let c10 = mul_sub(&m[1][2], &m[2][0], &m[1][0], &m[2][2]);
12366 let c20 = mul_sub(&m[1][0], &m[2][1], &m[1][1], &m[2][0]);
12367 Real::dot3([&m[0][0], &m[0][1], &m[0][2]], [&c00, &c10, &c20])
12368}
12369
12370#[inline]
12371fn matrix3_adjugate_and_determinant(matrix: &[[Real; 3]; 3]) -> ([[Real; 3]; 3], Real) {
12372 crate::trace_dispatch!(
12373 "hyperlattice_matrix",
12374 "helper",
12375 "matrix3-adjugate-and-determinant"
12376 );
12377 let m = &matrix;
12378 let c00 = mul_sub(&m[1][1], &m[2][2], &m[1][2], &m[2][1]);
12379 let c01 = mul_sub(&m[0][2], &m[2][1], &m[0][1], &m[2][2]);
12380 let c02 = mul_sub(&m[0][1], &m[1][2], &m[0][2], &m[1][1]);
12381 let c10 = mul_sub(&m[1][2], &m[2][0], &m[1][0], &m[2][2]);
12382 let c11 = mul_sub(&m[0][0], &m[2][2], &m[0][2], &m[2][0]);
12383 let c12 = mul_sub(&m[0][2], &m[1][0], &m[0][0], &m[1][2]);
12384 let c20 = mul_sub(&m[1][0], &m[2][1], &m[1][1], &m[2][0]);
12385 let c21 = mul_sub(&m[0][1], &m[2][0], &m[0][0], &m[2][1]);
12386 let c22 = mul_sub(&m[0][0], &m[1][1], &m[0][1], &m[1][0]);
12387 let det = Real::dot3([&m[0][0], &m[0][1], &m[0][2]], [&c00, &c10, &c20]);
12388 ([[c00, c01, c02], [c10, c11, c12], [c20, c21, c22]], det)
12389}
12390
12391#[inline(never)]
12392fn matrix3_adjugate_and_determinant_dense_exact(matrix: &[[Real; 3]; 3]) -> ([[Real; 3]; 3], Real) {
12393 crate::trace_dispatch!(
12394 "hyperlattice_matrix",
12395 "helper",
12396 "matrix3-adjugate-and-determinant-dense-exact"
12397 );
12398 let m = &matrix;
12399 let c00 = mul_sub_dense_exact(&m[1][1], &m[2][2], &m[1][2], &m[2][1]);
12400 let c01 = mul_sub_dense_exact(&m[0][2], &m[2][1], &m[0][1], &m[2][2]);
12401 let c02 = mul_sub_dense_exact(&m[0][1], &m[1][2], &m[0][2], &m[1][1]);
12402 let c10 = mul_sub_dense_exact(&m[1][2], &m[2][0], &m[1][0], &m[2][2]);
12403 let c11 = mul_sub_dense_exact(&m[0][0], &m[2][2], &m[0][2], &m[2][0]);
12404 let c12 = mul_sub_dense_exact(&m[0][2], &m[1][0], &m[0][0], &m[1][2]);
12405 let c20 = mul_sub_dense_exact(&m[1][0], &m[2][1], &m[1][1], &m[2][0]);
12406 let c21 = mul_sub_dense_exact(&m[0][1], &m[2][0], &m[0][0], &m[2][1]);
12407 let c22 = mul_sub_dense_exact(&m[0][0], &m[1][1], &m[0][1], &m[1][0]);
12408 let det = Real::active_linear_combination3([&m[0][0], &m[0][1], &m[0][2]], [&c00, &c10, &c20]);
12409 ([[c00, c01, c02], [c10, c11, c12], [c20, c21, c22]], det)
12410}
12411
12412#[inline(never)]
12413fn matrix3_adjugate_and_determinant_dense_exact_known_rational(
12414 matrix: &[[Real; 3]; 3],
12415) -> ([[Real; 3]; 3], Real) {
12416 crate::trace_dispatch!(
12417 "hyperlattice_matrix",
12418 "helper",
12419 "matrix3-adjugate-and-determinant-dense-exact-known-rational"
12420 );
12421 let m = &matrix;
12422 let c00 = mul_sub_dense_exact_known_rational(&m[1][1], &m[2][2], &m[1][2], &m[2][1]);
12423 let c01 = mul_sub_dense_exact_known_rational(&m[0][2], &m[2][1], &m[0][1], &m[2][2]);
12424 let c02 = mul_sub_dense_exact_known_rational(&m[0][1], &m[1][2], &m[0][2], &m[1][1]);
12425 let c10 = mul_sub_dense_exact_known_rational(&m[1][2], &m[2][0], &m[1][0], &m[2][2]);
12426 let c11 = mul_sub_dense_exact_known_rational(&m[0][0], &m[2][2], &m[0][2], &m[2][0]);
12427 let c12 = mul_sub_dense_exact_known_rational(&m[0][2], &m[1][0], &m[0][0], &m[1][2]);
12428 let c20 = mul_sub_dense_exact_known_rational(&m[1][0], &m[2][1], &m[1][1], &m[2][0]);
12429 let c21 = mul_sub_dense_exact_known_rational(&m[0][1], &m[2][0], &m[0][0], &m[2][1]);
12430 let c22 = mul_sub_dense_exact_known_rational(&m[0][0], &m[1][1], &m[0][1], &m[1][0]);
12431 let det = Real::active_signed_product_sum2_known_exact_rational(
12432 [true, true, true],
12433 [[&m[0][0], &c00], [&m[0][1], &c10], [&m[0][2], &c20]],
12434 );
12435 ([[c00, c01, c02], [c10, c11, c12], [c20, c21, c22]], det)
12436}
12437
12438#[inline]
12439fn matrix3_scaled_adjugate(matrix: &[[Real; 3]; 3]) -> BlasResult<[[Real; 3]; 3]> {
12440 crate::trace_dispatch!("hyperlattice_matrix", "helper", "matrix3-scaled-adjugate");
12441 let m = &matrix;
12442 let c00 = mul_sub(&m[1][1], &m[2][2], &m[1][2], &m[2][1]);
12443 let c01 = mul_sub(&m[0][2], &m[2][1], &m[0][1], &m[2][2]);
12444 let c02 = mul_sub(&m[0][1], &m[1][2], &m[0][2], &m[1][1]);
12445 let c10 = mul_sub(&m[1][2], &m[2][0], &m[1][0], &m[2][2]);
12446 let c11 = mul_sub(&m[0][0], &m[2][2], &m[0][2], &m[2][0]);
12447 let c12 = mul_sub(&m[0][2], &m[1][0], &m[0][0], &m[1][2]);
12448 let c20 = mul_sub(&m[1][0], &m[2][1], &m[1][1], &m[2][0]);
12449 let c21 = mul_sub(&m[0][1], &m[2][0], &m[0][0], &m[2][1]);
12450 let c22 = mul_sub(&m[0][0], &m[1][1], &m[0][1], &m[1][0]);
12451 let det = Real::dot3([&m[0][0], &m[0][1], &m[0][2]], [&c00, &c10, &c20]);
12452 let inv_det = det.inverse()?;
12453 Ok([
12460 [
12461 scale_by_shared_factor(c00, &inv_det),
12462 scale_by_shared_factor(c01, &inv_det),
12463 scale_by_shared_factor(c02, &inv_det),
12464 ],
12465 [
12466 scale_by_shared_factor(c10, &inv_det),
12467 scale_by_shared_factor(c11, &inv_det),
12468 scale_by_shared_factor(c12, &inv_det),
12469 ],
12470 [
12471 scale_by_shared_factor(c20, &inv_det),
12472 scale_by_shared_factor(c21, &inv_det),
12473 scale_by_shared_factor(c22, &inv_det),
12474 ],
12475 ])
12476}
12477
12478#[inline(never)]
12479fn matrix3_scaled_adjugate_dense_exact(matrix: &[[Real; 3]; 3]) -> BlasResult<[[Real; 3]; 3]> {
12480 crate::trace_dispatch!(
12481 "hyperlattice_matrix",
12482 "helper",
12483 "matrix3-scaled-adjugate-dense-exact"
12484 );
12485 let m = &matrix;
12486 let c00 = mul_sub_dense_exact(&m[1][1], &m[2][2], &m[1][2], &m[2][1]);
12487 let c01 = mul_sub_dense_exact(&m[0][2], &m[2][1], &m[0][1], &m[2][2]);
12488 let c02 = mul_sub_dense_exact(&m[0][1], &m[1][2], &m[0][2], &m[1][1]);
12489 let c10 = mul_sub_dense_exact(&m[1][2], &m[2][0], &m[1][0], &m[2][2]);
12490 let c11 = mul_sub_dense_exact(&m[0][0], &m[2][2], &m[0][2], &m[2][0]);
12491 let c12 = mul_sub_dense_exact(&m[0][2], &m[1][0], &m[0][0], &m[1][2]);
12492 let c20 = mul_sub_dense_exact(&m[1][0], &m[2][1], &m[1][1], &m[2][0]);
12493 let c21 = mul_sub_dense_exact(&m[0][1], &m[2][0], &m[0][0], &m[2][1]);
12494 let c22 = mul_sub_dense_exact(&m[0][0], &m[1][1], &m[0][1], &m[1][0]);
12495 let det = Real::active_linear_combination3([&m[0][0], &m[0][1], &m[0][2]], [&c00, &c10, &c20]);
12496 let inv_det = det.inverse()?;
12497 Ok([
12498 [
12499 scale_by_shared_factor(c00, &inv_det),
12500 scale_by_shared_factor(c01, &inv_det),
12501 scale_by_shared_factor(c02, &inv_det),
12502 ],
12503 [
12504 scale_by_shared_factor(c10, &inv_det),
12505 scale_by_shared_factor(c11, &inv_det),
12506 scale_by_shared_factor(c12, &inv_det),
12507 ],
12508 [
12509 scale_by_shared_factor(c20, &inv_det),
12510 scale_by_shared_factor(c21, &inv_det),
12511 scale_by_shared_factor(c22, &inv_det),
12512 ],
12513 ])
12514}
12515
12516#[inline]
12517fn invert_matrix3(matrix: [[Real; 3]; 3]) -> BlasResult<[[Real; 3]; 3]> {
12518 crate::trace_dispatch!("hyperlattice_matrix", "helper", "invert-matrix3");
12519 if matrix3_is_definitely_dense_for_inverse(&matrix) {
12520 crate::trace_dispatch!(
12521 "hyperlattice_matrix",
12522 "helper",
12523 "invert-matrix3-dense-cofactor"
12524 );
12525 if true {
12526 return matrix3_scaled_adjugate_dense_exact(&matrix);
12527 }
12528 return matrix3_scaled_adjugate(&matrix);
12529 }
12530 let facts = matrix3_facts(&matrix);
12531 if facts.is_identity {
12532 crate::trace_dispatch!("hyperlattice_matrix", "helper", "invert-matrix3-identity");
12533 return Ok(matrix);
12534 }
12535 if facts.is_diagonal {
12536 crate::trace_dispatch!("hyperlattice_matrix", "helper", "invert-matrix3-diagonal");
12537 return invert_matrix3_by_diagonal(&matrix);
12538 }
12539 if facts.is_upper_triangular {
12540 crate::trace_dispatch!(
12544 "hyperlattice_matrix",
12545 "helper",
12546 "invert-matrix3-upper-triangular"
12547 );
12548 return invert_matrix3_upper_triangular(&matrix);
12549 }
12550 if facts.is_lower_triangular {
12551 crate::trace_dispatch!(
12552 "hyperlattice_matrix",
12553 "helper",
12554 "invert-matrix3-lower-triangular"
12555 );
12556 return invert_matrix3_lower_triangular(&matrix);
12557 }
12558 if facts.is_affine {
12559 crate::trace_dispatch!("hyperlattice_matrix", "helper", "invert-matrix3-affine");
12560 return invert_matrix3_affine(&matrix, facts.linear_is_diagonal);
12561 }
12562 matrix3_scaled_adjugate(&matrix)
12566}
12567
12568#[inline]
12569fn invert_matrix3_checked(matrix: [[Real; 3]; 3]) -> CheckedBlasResult<[[Real; 3]; 3]> {
12570 crate::trace_dispatch!("hyperlattice_matrix", "helper", "invert-matrix3-checked");
12571 if matrix3_is_definitely_dense_for_inverse(&matrix) {
12572 crate::trace_dispatch!(
12573 "hyperlattice_matrix",
12574 "helper",
12575 "invert-matrix3-checked-dense-cofactor"
12576 );
12577 let (adjugate, det) = if true {
12578 matrix3_adjugate_and_determinant_dense_exact(&matrix)
12579 } else {
12580 matrix3_adjugate_and_determinant(&matrix)
12581 };
12582 require_known_nonzero(&det)?;
12583 let inv_det = det.inverse()?;
12584 return Ok(scale_matrix3(adjugate, &inv_det));
12585 }
12586 let facts = matrix3_facts(&matrix);
12587 if facts.is_identity {
12588 crate::trace_dispatch!(
12589 "hyperlattice_matrix",
12590 "helper",
12591 "invert-matrix3-checked-identity"
12592 );
12593 return Ok(matrix);
12594 }
12595 if facts.is_diagonal {
12596 crate::trace_dispatch!(
12597 "hyperlattice_matrix",
12598 "helper",
12599 "invert-matrix3-checked-diagonal"
12600 );
12601 return invert_matrix3_by_diagonal_checked(&matrix);
12602 }
12603 if facts.is_upper_triangular {
12604 crate::trace_dispatch!(
12607 "hyperlattice_matrix",
12608 "helper",
12609 "invert-matrix3-checked-upper-triangular"
12610 );
12611 return invert_matrix3_upper_triangular_checked(&matrix);
12612 }
12613 if facts.is_lower_triangular {
12614 crate::trace_dispatch!(
12615 "hyperlattice_matrix",
12616 "helper",
12617 "invert-matrix3-checked-lower-triangular"
12618 );
12619 return invert_matrix3_lower_triangular_checked(&matrix);
12620 }
12621 if facts.is_affine {
12622 crate::trace_dispatch!(
12623 "hyperlattice_matrix",
12624 "helper",
12625 "invert-matrix3-checked-affine"
12626 );
12627 return invert_matrix3_affine_checked(&matrix, facts.linear_is_diagonal);
12628 }
12629 let (adjugate, det) = matrix3_adjugate_and_determinant(&matrix);
12630 require_known_nonzero(&det)?;
12631 let inv_det = det.inverse()?;
12632 Ok(scale_matrix3(adjugate, &inv_det))
12633}
12634
12635#[inline]
12636fn invert_matrix3_checked_with_abort(
12637 matrix: [[Real; 3]; 3],
12638 signal: &AbortSignal,
12639) -> CheckedBlasResult<[[Real; 3]; 3]> {
12640 crate::trace_dispatch!(
12641 "hyperlattice_matrix",
12642 "helper",
12643 "invert-matrix3-checked-with-abort"
12644 );
12645 if matrix3_is_definitely_dense_for_inverse(&matrix) {
12646 crate::trace_dispatch!(
12647 "hyperlattice_matrix",
12648 "helper",
12649 "invert-matrix3-checked-with-abort-dense-cofactor"
12650 );
12651 let (adjugate, det) = if true {
12652 matrix3_adjugate_and_determinant_dense_exact(&matrix)
12653 } else {
12654 matrix3_adjugate_and_determinant(&matrix)
12655 };
12656 let det = with_abort(det, signal);
12657 require_known_nonzero(&det)?;
12658 let inv_det = det.inverse()?;
12659 return Ok(scale_matrix3(adjugate, &inv_det));
12660 }
12661 let facts = matrix3_facts(&matrix);
12662 if facts.is_identity {
12663 crate::trace_dispatch!(
12664 "hyperlattice_matrix",
12665 "helper",
12666 "invert-matrix3-checked-with-abort-identity"
12667 );
12668 return Ok(matrix);
12669 }
12670 if facts.is_diagonal {
12671 crate::trace_dispatch!(
12672 "hyperlattice_matrix",
12673 "helper",
12674 "invert-matrix3-checked-with-abort-diagonal"
12675 );
12676 return invert_matrix3_by_diagonal_checked_with_abort(&matrix, signal);
12677 }
12678 if facts.is_upper_triangular {
12679 crate::trace_dispatch!(
12680 "hyperlattice_matrix",
12681 "helper",
12682 "invert-matrix3-checked-with-abort-upper-triangular"
12683 );
12684 return invert_matrix3_upper_triangular_checked_with_abort(&matrix, signal);
12685 }
12686 if facts.is_lower_triangular {
12687 crate::trace_dispatch!(
12688 "hyperlattice_matrix",
12689 "helper",
12690 "invert-matrix3-checked-with-abort-lower-triangular"
12691 );
12692 return invert_matrix3_lower_triangular_checked_with_abort(&matrix, signal);
12693 }
12694 if facts.is_affine {
12695 crate::trace_dispatch!(
12696 "hyperlattice_matrix",
12697 "helper",
12698 "invert-matrix3-checked-with-abort-affine"
12699 );
12700 return invert_matrix3_affine_checked_with_abort(&matrix, signal, facts.linear_is_diagonal);
12701 }
12702 let (adjugate, det) = matrix3_adjugate_and_determinant(&matrix);
12703 let det = with_abort(det, signal);
12704 require_known_nonzero(&det)?;
12705 let inv_det = det.inverse()?;
12706 Ok(scale_matrix3(adjugate, &inv_det))
12707}
12708
12709#[inline]
12710fn matrix4_factors(m: &[[Real; 4]; 4]) -> ([Real; 6], [Real; 6]) {
12711 crate::trace_dispatch!("hyperlattice_matrix", "helper", "matrix4-factors");
12712 let s = [
12718 mul_sub(&m[0][0], &m[1][1], &m[1][0], &m[0][1]),
12719 mul_sub(&m[0][0], &m[1][2], &m[1][0], &m[0][2]),
12720 mul_sub(&m[0][0], &m[1][3], &m[1][0], &m[0][3]),
12721 mul_sub(&m[0][1], &m[1][2], &m[1][1], &m[0][2]),
12722 mul_sub(&m[0][1], &m[1][3], &m[1][1], &m[0][3]),
12723 mul_sub(&m[0][2], &m[1][3], &m[1][2], &m[0][3]),
12724 ];
12725 let c = [
12726 mul_sub(&m[2][0], &m[3][1], &m[3][0], &m[2][1]),
12727 mul_sub(&m[2][0], &m[3][2], &m[3][0], &m[2][2]),
12728 mul_sub(&m[2][0], &m[3][3], &m[3][0], &m[2][3]),
12729 mul_sub(&m[2][1], &m[3][2], &m[3][1], &m[2][2]),
12730 mul_sub(&m[2][1], &m[3][3], &m[3][1], &m[2][3]),
12731 mul_sub(&m[2][2], &m[3][3], &m[3][2], &m[2][3]),
12732 ];
12733 (s, c)
12734}
12735
12736#[inline(never)]
12737fn matrix4_factors_dense_exact(m: &[[Real; 4]; 4]) -> ([Real; 6], [Real; 6]) {
12738 crate::trace_dispatch!(
12739 "hyperlattice_matrix",
12740 "helper",
12741 "matrix4-factors-dense-exact"
12742 );
12743 let s = [
12744 mul_sub_dense_exact(&m[0][0], &m[1][1], &m[1][0], &m[0][1]),
12745 mul_sub_dense_exact(&m[0][0], &m[1][2], &m[1][0], &m[0][2]),
12746 mul_sub_dense_exact(&m[0][0], &m[1][3], &m[1][0], &m[0][3]),
12747 mul_sub_dense_exact(&m[0][1], &m[1][2], &m[1][1], &m[0][2]),
12748 mul_sub_dense_exact(&m[0][1], &m[1][3], &m[1][1], &m[0][3]),
12749 mul_sub_dense_exact(&m[0][2], &m[1][3], &m[1][2], &m[0][3]),
12750 ];
12751 let c = [
12752 mul_sub_dense_exact(&m[2][0], &m[3][1], &m[3][0], &m[2][1]),
12753 mul_sub_dense_exact(&m[2][0], &m[3][2], &m[3][0], &m[2][2]),
12754 mul_sub_dense_exact(&m[2][0], &m[3][3], &m[3][0], &m[2][3]),
12755 mul_sub_dense_exact(&m[2][1], &m[3][2], &m[3][1], &m[2][2]),
12756 mul_sub_dense_exact(&m[2][1], &m[3][3], &m[3][1], &m[2][3]),
12757 mul_sub_dense_exact(&m[2][2], &m[3][3], &m[3][2], &m[2][3]),
12758 ];
12759 (s, c)
12760}
12761
12762#[inline(never)]
12763fn matrix4_factors_dense_exact_known_rational(m: &[[Real; 4]; 4]) -> ([Real; 6], [Real; 6]) {
12764 crate::trace_dispatch!(
12765 "hyperlattice_matrix",
12766 "helper",
12767 "matrix4-factors-dense-exact-known-rational"
12768 );
12769 let s = [
12770 mul_sub_dense_exact_known_rational(&m[0][0], &m[1][1], &m[1][0], &m[0][1]),
12771 mul_sub_dense_exact_known_rational(&m[0][0], &m[1][2], &m[1][0], &m[0][2]),
12772 mul_sub_dense_exact_known_rational(&m[0][0], &m[1][3], &m[1][0], &m[0][3]),
12773 mul_sub_dense_exact_known_rational(&m[0][1], &m[1][2], &m[1][1], &m[0][2]),
12774 mul_sub_dense_exact_known_rational(&m[0][1], &m[1][3], &m[1][1], &m[0][3]),
12775 mul_sub_dense_exact_known_rational(&m[0][2], &m[1][3], &m[1][2], &m[0][3]),
12776 ];
12777 let c = [
12778 mul_sub_dense_exact_known_rational(&m[2][0], &m[3][1], &m[3][0], &m[2][1]),
12779 mul_sub_dense_exact_known_rational(&m[2][0], &m[3][2], &m[3][0], &m[2][2]),
12780 mul_sub_dense_exact_known_rational(&m[2][0], &m[3][3], &m[3][0], &m[2][3]),
12781 mul_sub_dense_exact_known_rational(&m[2][1], &m[3][2], &m[3][1], &m[2][2]),
12782 mul_sub_dense_exact_known_rational(&m[2][1], &m[3][3], &m[3][1], &m[2][3]),
12783 mul_sub_dense_exact_known_rational(&m[2][2], &m[3][3], &m[3][2], &m[2][3]),
12784 ];
12785 (s, c)
12786}
12787
12788fn determinant4_from_factors(s: &[Real; 6], c: &[Real; 6]) -> Real {
12789 crate::trace_dispatch!("hyperlattice_matrix", "helper", "determinant4-from-factors");
12790 Real::signed_product_sum2(
12796 [true, false, true, true, false, true],
12797 [
12798 [&s[0], &c[5]],
12799 [&s[1], &c[4]],
12800 [&s[2], &c[3]],
12801 [&s[3], &c[2]],
12802 [&s[4], &c[1]],
12803 [&s[5], &c[0]],
12804 ],
12805 )
12806}
12807
12808fn determinant4_from_factors_known_rational(s: &[Real; 6], c: &[Real; 6]) -> Real {
12809 crate::trace_dispatch!(
12810 "hyperlattice_matrix",
12811 "helper",
12812 "determinant4-from-factors-known-rational"
12813 );
12814 Real::active_signed_product_sum2_known_exact_rational(
12815 [true, false, true, true, false, true],
12816 [
12817 [&s[0], &c[5]],
12818 [&s[1], &c[4]],
12819 [&s[2], &c[3]],
12820 [&s[3], &c[2]],
12821 [&s[4], &c[1]],
12822 [&s[5], &c[0]],
12823 ],
12824 )
12825}
12826
12827#[inline]
12828fn determinant4(m: &[[Real; 4]; 4]) -> Real {
12829 crate::trace_dispatch!("hyperlattice_matrix", "helper", "determinant4");
12830 let (s, c) = matrix4_factors(m);
12837 determinant4_from_factors(&s, &c)
12838}
12839
12840#[inline]
12841fn matrix4_scaled_adjugate_from_factors(
12842 m: &[[Real; 4]; 4],
12843 s: &[Real; 6],
12844 c: &[Real; 6],
12845 inv_det: &Real,
12846) -> [[Real; 4]; 4] {
12847 [
12848 [
12849 scale_by_shared_factor(
12850 mul_add_sub(&m[1][1], &c[5], &m[1][3], &c[3], &m[1][2], &c[4]),
12851 inv_det,
12852 ),
12853 scale_by_shared_factor(
12854 mul_sub_add(&m[0][2], &c[4], &m[0][1], &c[5], &m[0][3], &c[3]),
12855 inv_det,
12856 ),
12857 scale_by_shared_factor(
12858 mul_add_sub(&m[3][1], &s[5], &m[3][3], &s[3], &m[3][2], &s[4]),
12859 inv_det,
12860 ),
12861 scale_by_shared_factor(
12862 mul_sub_add(&m[2][2], &s[4], &m[2][1], &s[5], &m[2][3], &s[3]),
12863 inv_det,
12864 ),
12865 ],
12866 [
12867 scale_by_shared_factor(
12868 mul_sub_add(&m[1][2], &c[2], &m[1][0], &c[5], &m[1][3], &c[1]),
12869 inv_det,
12870 ),
12871 scale_by_shared_factor(
12872 mul_add_sub(&m[0][0], &c[5], &m[0][3], &c[1], &m[0][2], &c[2]),
12873 inv_det,
12874 ),
12875 scale_by_shared_factor(
12876 mul_sub_add(&m[3][2], &s[2], &m[3][0], &s[5], &m[3][3], &s[1]),
12877 inv_det,
12878 ),
12879 scale_by_shared_factor(
12880 mul_add_sub(&m[2][0], &s[5], &m[2][3], &s[1], &m[2][2], &s[2]),
12881 inv_det,
12882 ),
12883 ],
12884 [
12885 scale_by_shared_factor(
12886 mul_add_sub(&m[1][0], &c[4], &m[1][3], &c[0], &m[1][1], &c[2]),
12887 inv_det,
12888 ),
12889 scale_by_shared_factor(
12890 mul_sub_add(&m[0][1], &c[2], &m[0][0], &c[4], &m[0][3], &c[0]),
12891 inv_det,
12892 ),
12893 scale_by_shared_factor(
12894 mul_add_sub(&m[3][0], &s[4], &m[3][3], &s[0], &m[3][1], &s[2]),
12895 inv_det,
12896 ),
12897 scale_by_shared_factor(
12898 mul_sub_add(&m[2][1], &s[2], &m[2][0], &s[4], &m[2][3], &s[0]),
12899 inv_det,
12900 ),
12901 ],
12902 [
12903 scale_by_shared_factor(
12904 mul_sub_add(&m[1][1], &c[1], &m[1][0], &c[3], &m[1][2], &c[0]),
12905 inv_det,
12906 ),
12907 scale_by_shared_factor(
12908 mul_add_sub(&m[0][0], &c[3], &m[0][2], &c[0], &m[0][1], &c[1]),
12909 inv_det,
12910 ),
12911 scale_by_shared_factor(
12912 mul_sub_add(&m[3][1], &s[1], &m[3][0], &s[3], &m[3][2], &s[0]),
12913 inv_det,
12914 ),
12915 scale_by_shared_factor(
12916 mul_add_sub(&m[2][0], &s[3], &m[2][2], &s[0], &m[2][1], &s[1]),
12917 inv_det,
12918 ),
12919 ],
12920 ]
12921}
12922
12923#[inline(never)]
12924fn matrix4_scaled_adjugate_from_factors_dense_exact(
12925 m: &[[Real; 4]; 4],
12926 s: &[Real; 6],
12927 c: &[Real; 6],
12928 inv_det: &Real,
12929) -> [[Real; 4]; 4] {
12930 crate::trace_dispatch!(
12931 "hyperlattice_matrix",
12932 "helper",
12933 "matrix4-scaled-adjugate-dense-exact"
12934 );
12935 [
12936 [
12937 scale_by_shared_factor(
12938 mul_add_sub_dense_exact(&m[1][1], &c[5], &m[1][3], &c[3], &m[1][2], &c[4]),
12939 inv_det,
12940 ),
12941 scale_by_shared_factor(
12942 mul_sub_add_dense_exact(&m[0][2], &c[4], &m[0][1], &c[5], &m[0][3], &c[3]),
12943 inv_det,
12944 ),
12945 scale_by_shared_factor(
12946 mul_add_sub_dense_exact(&m[3][1], &s[5], &m[3][3], &s[3], &m[3][2], &s[4]),
12947 inv_det,
12948 ),
12949 scale_by_shared_factor(
12950 mul_sub_add_dense_exact(&m[2][2], &s[4], &m[2][1], &s[5], &m[2][3], &s[3]),
12951 inv_det,
12952 ),
12953 ],
12954 [
12955 scale_by_shared_factor(
12956 mul_sub_add_dense_exact(&m[1][2], &c[2], &m[1][0], &c[5], &m[1][3], &c[1]),
12957 inv_det,
12958 ),
12959 scale_by_shared_factor(
12960 mul_add_sub_dense_exact(&m[0][0], &c[5], &m[0][3], &c[1], &m[0][2], &c[2]),
12961 inv_det,
12962 ),
12963 scale_by_shared_factor(
12964 mul_sub_add_dense_exact(&m[3][2], &s[2], &m[3][0], &s[5], &m[3][3], &s[1]),
12965 inv_det,
12966 ),
12967 scale_by_shared_factor(
12968 mul_add_sub_dense_exact(&m[2][0], &s[5], &m[2][3], &s[1], &m[2][2], &s[2]),
12969 inv_det,
12970 ),
12971 ],
12972 [
12973 scale_by_shared_factor(
12974 mul_add_sub_dense_exact(&m[1][0], &c[4], &m[1][3], &c[0], &m[1][1], &c[2]),
12975 inv_det,
12976 ),
12977 scale_by_shared_factor(
12978 mul_sub_add_dense_exact(&m[0][1], &c[2], &m[0][0], &c[4], &m[0][3], &c[0]),
12979 inv_det,
12980 ),
12981 scale_by_shared_factor(
12982 mul_add_sub_dense_exact(&m[3][0], &s[4], &m[3][3], &s[0], &m[3][1], &s[2]),
12983 inv_det,
12984 ),
12985 scale_by_shared_factor(
12986 mul_sub_add_dense_exact(&m[2][1], &s[2], &m[2][0], &s[4], &m[2][3], &s[0]),
12987 inv_det,
12988 ),
12989 ],
12990 [
12991 scale_by_shared_factor(
12992 mul_sub_add_dense_exact(&m[1][1], &c[1], &m[1][0], &c[3], &m[1][2], &c[0]),
12993 inv_det,
12994 ),
12995 scale_by_shared_factor(
12996 mul_add_sub_dense_exact(&m[0][0], &c[3], &m[0][2], &c[0], &m[0][1], &c[1]),
12997 inv_det,
12998 ),
12999 scale_by_shared_factor(
13000 mul_sub_add_dense_exact(&m[3][1], &s[1], &m[3][0], &s[3], &m[3][2], &s[0]),
13001 inv_det,
13002 ),
13003 scale_by_shared_factor(
13004 mul_add_sub_dense_exact(&m[2][0], &s[3], &m[2][2], &s[0], &m[2][1], &s[1]),
13005 inv_det,
13006 ),
13007 ],
13008 ]
13009}
13010
13011#[inline]
13012fn invert_matrix4(matrix: [[Real; 4]; 4]) -> BlasResult<[[Real; 4]; 4]> {
13013 if matrix4_is_definitely_dense_for_inverse(&matrix) {
13014 crate::trace_dispatch!(
13015 "hyperlattice_matrix",
13016 "helper",
13017 "invert-matrix4-dense-cofactor"
13018 );
13019 let (s, c) = if true {
13020 matrix4_factors_dense_exact(&matrix)
13021 } else {
13022 matrix4_factors(&matrix)
13023 };
13024 let det = determinant4_from_factors(&s, &c);
13025 let inv_det = det.inverse()?;
13026 if true {
13027 return Ok(matrix4_scaled_adjugate_from_factors_dense_exact(
13028 &matrix, &s, &c, &inv_det,
13029 ));
13030 }
13031 return Ok(matrix4_scaled_adjugate_from_factors(
13032 &matrix, &s, &c, &inv_det,
13033 ));
13034 }
13035 let facts = matrix4_facts(&matrix);
13036 if facts.is_identity {
13037 crate::trace_dispatch!("hyperlattice_matrix", "helper", "invert-matrix4-identity");
13038 return Ok(matrix);
13039 }
13040 if facts.is_diagonal {
13041 crate::trace_dispatch!("hyperlattice_matrix", "helper", "invert-matrix4-diagonal");
13042 return invert_matrix4_by_diagonal(&matrix);
13043 }
13044 if facts.is_upper_triangular {
13045 crate::trace_dispatch!(
13046 "hyperlattice_matrix",
13047 "helper",
13048 "invert-matrix4-upper-triangular"
13049 );
13050 return invert_matrix4_by_upper_triangular(&matrix);
13051 }
13052 if facts.is_lower_triangular {
13053 crate::trace_dispatch!(
13054 "hyperlattice_matrix",
13055 "helper",
13056 "invert-matrix4-lower-triangular"
13057 );
13058 return invert_matrix4_by_lower_triangular(&matrix);
13059 }
13060 if facts.is_affine {
13061 crate::trace_dispatch!("hyperlattice_matrix", "helper", "invert-matrix4-affine");
13062 return invert_matrix4_affine(
13063 &matrix,
13064 facts.linear_is_diagonal,
13065 facts.is_affine_translation,
13066 );
13067 }
13068 let (s, c) = matrix4_factors(&matrix);
13073 let det = determinant4_from_factors(&s, &c);
13074 let inv_det = det.inverse()?;
13075 Ok(matrix4_scaled_adjugate_from_factors(
13076 &matrix, &s, &c, &inv_det,
13077 ))
13078}
13079
13080#[inline]
13081fn invert_matrix4_checked(matrix: [[Real; 4]; 4]) -> CheckedBlasResult<[[Real; 4]; 4]> {
13082 if matrix4_is_definitely_dense_for_inverse(&matrix) {
13083 crate::trace_dispatch!(
13084 "hyperlattice_matrix",
13085 "helper",
13086 "invert-matrix4-checked-dense-cofactor"
13087 );
13088 let (s, c) = if true {
13089 matrix4_factors_dense_exact(&matrix)
13090 } else {
13091 matrix4_factors(&matrix)
13092 };
13093 let det = determinant4_from_factors(&s, &c);
13094 require_known_nonzero(&det)?;
13095 let inv_det = det.inverse()?;
13096 if true {
13097 return Ok(matrix4_scaled_adjugate_from_factors_dense_exact(
13098 &matrix, &s, &c, &inv_det,
13099 ));
13100 }
13101 return Ok(matrix4_scaled_adjugate_from_factors(
13102 &matrix, &s, &c, &inv_det,
13103 ));
13104 }
13105 let facts = matrix4_facts(&matrix);
13106 if facts.is_identity {
13107 crate::trace_dispatch!(
13108 "hyperlattice_matrix",
13109 "helper",
13110 "invert-matrix4-checked-identity"
13111 );
13112 return Ok(matrix);
13113 }
13114 if facts.is_diagonal {
13115 crate::trace_dispatch!(
13116 "hyperlattice_matrix",
13117 "helper",
13118 "invert-matrix4-checked-diagonal"
13119 );
13120 return invert_matrix4_by_diagonal_checked(&matrix);
13121 }
13122 if facts.is_upper_triangular {
13123 crate::trace_dispatch!(
13124 "hyperlattice_matrix",
13125 "helper",
13126 "invert-matrix4-checked-upper-triangular"
13127 );
13128 return invert_matrix4_by_upper_triangular_checked(&matrix);
13129 }
13130 if facts.is_lower_triangular {
13131 crate::trace_dispatch!(
13132 "hyperlattice_matrix",
13133 "helper",
13134 "invert-matrix4-checked-lower-triangular"
13135 );
13136 return invert_matrix4_by_lower_triangular_checked(&matrix);
13137 }
13138 if facts.is_affine {
13139 crate::trace_dispatch!(
13140 "hyperlattice_matrix",
13141 "helper",
13142 "invert-matrix4-checked-affine"
13143 );
13144 return invert_matrix4_affine_checked(
13145 &matrix,
13146 facts.linear_is_diagonal,
13147 facts.is_affine_translation,
13148 );
13149 }
13150 let (s, c) = matrix4_factors(&matrix);
13151 let det = determinant4_from_factors(&s, &c);
13152 require_known_nonzero(&det)?;
13153 let inv_det = det.inverse()?;
13154 Ok(matrix4_scaled_adjugate_from_factors(
13155 &matrix, &s, &c, &inv_det,
13156 ))
13157}
13158
13159#[inline]
13160fn invert_matrix4_checked_with_abort(
13161 matrix: [[Real; 4]; 4],
13162 signal: &AbortSignal,
13163) -> CheckedBlasResult<[[Real; 4]; 4]> {
13164 if matrix4_is_definitely_dense_for_inverse(&matrix) {
13165 crate::trace_dispatch!(
13166 "hyperlattice_matrix",
13167 "helper",
13168 "invert-matrix4-checked-with-abort-dense-cofactor"
13169 );
13170 let (s, c) = if true {
13171 matrix4_factors_dense_exact(&matrix)
13172 } else {
13173 matrix4_factors(&matrix)
13174 };
13175 let det = determinant4_from_factors(&s, &c);
13176 let det = with_abort(det, signal);
13177 require_known_nonzero(&det)?;
13178 let inv_det = det.inverse()?;
13179 if true {
13180 return Ok(matrix4_scaled_adjugate_from_factors_dense_exact(
13181 &matrix, &s, &c, &inv_det,
13182 ));
13183 }
13184 return Ok(matrix4_scaled_adjugate_from_factors(
13185 &matrix, &s, &c, &inv_det,
13186 ));
13187 }
13188 let facts = matrix4_facts(&matrix);
13189 if facts.is_identity {
13190 crate::trace_dispatch!(
13191 "hyperlattice_matrix",
13192 "helper",
13193 "invert-matrix4-checked-with-abort-identity"
13194 );
13195 return Ok(matrix);
13196 }
13197 if facts.is_diagonal {
13198 crate::trace_dispatch!(
13199 "hyperlattice_matrix",
13200 "helper",
13201 "invert-matrix4-checked-with-abort-diagonal"
13202 );
13203 return invert_matrix4_by_diagonal_checked_with_abort(&matrix, signal);
13204 }
13205 if facts.is_upper_triangular {
13206 crate::trace_dispatch!(
13207 "hyperlattice_matrix",
13208 "helper",
13209 "invert-matrix4-checked-with-abort-upper-triangular"
13210 );
13211 return invert_matrix4_by_upper_triangular_checked_with_abort(&matrix, signal);
13212 }
13213 if facts.is_lower_triangular {
13214 crate::trace_dispatch!(
13215 "hyperlattice_matrix",
13216 "helper",
13217 "invert-matrix4-checked-with-abort-lower-triangular"
13218 );
13219 return invert_matrix4_by_lower_triangular_checked_with_abort(&matrix, signal);
13220 }
13221 if facts.is_affine {
13222 crate::trace_dispatch!(
13223 "hyperlattice_matrix",
13224 "helper",
13225 "invert-matrix4-checked-with-abort-affine"
13226 );
13227 return invert_matrix4_affine_checked_with_abort(
13228 &matrix,
13229 signal,
13230 facts.linear_is_diagonal,
13231 facts.is_affine_translation,
13232 );
13233 }
13234 let (s, c) = matrix4_factors(&matrix);
13235 let det = determinant4_from_factors(&s, &c);
13236 let det = with_abort(det, signal);
13237 require_known_nonzero(&det)?;
13238 let inv_det = det.inverse()?;
13239 Ok(matrix4_scaled_adjugate_from_factors(
13240 &matrix, &s, &c, &inv_det,
13241 ))
13242}
13243
13244#[inline]
13245fn matrix4_adjugate_from_factors(
13246 m: &[[Real; 4]; 4],
13247 s: &[Real; 6],
13248 c: &[Real; 6],
13249) -> [[Real; 4]; 4] {
13250 crate::trace_dispatch!(
13251 "hyperlattice_matrix",
13252 "helper",
13253 "matrix4-unscaled-adjugate-from-factors"
13254 );
13255 [
13262 [
13263 mul_add_sub(&m[1][1], &c[5], &m[1][3], &c[3], &m[1][2], &c[4]),
13264 mul_sub_add(&m[0][2], &c[4], &m[0][1], &c[5], &m[0][3], &c[3]),
13265 mul_add_sub(&m[3][1], &s[5], &m[3][3], &s[3], &m[3][2], &s[4]),
13266 mul_sub_add(&m[2][2], &s[4], &m[2][1], &s[5], &m[2][3], &s[3]),
13267 ],
13268 [
13269 mul_sub_add(&m[1][2], &c[2], &m[1][0], &c[5], &m[1][3], &c[1]),
13270 mul_add_sub(&m[0][0], &c[5], &m[0][3], &c[1], &m[0][2], &c[2]),
13271 mul_sub_add(&m[3][2], &s[2], &m[3][0], &s[5], &m[3][3], &s[1]),
13272 mul_add_sub(&m[2][0], &s[5], &m[2][3], &s[1], &m[2][2], &s[2]),
13273 ],
13274 [
13275 mul_add_sub(&m[1][0], &c[4], &m[1][3], &c[0], &m[1][1], &c[2]),
13276 mul_sub_add(&m[0][1], &c[2], &m[0][0], &c[4], &m[0][3], &c[0]),
13277 mul_add_sub(&m[3][0], &s[4], &m[3][3], &s[0], &m[3][1], &s[2]),
13278 mul_sub_add(&m[2][1], &s[2], &m[2][0], &s[4], &m[2][3], &s[0]),
13279 ],
13280 [
13281 mul_sub_add(&m[1][1], &c[1], &m[1][0], &c[3], &m[1][2], &c[0]),
13282 mul_add_sub(&m[0][0], &c[3], &m[0][2], &c[0], &m[0][1], &c[1]),
13283 mul_sub_add(&m[3][1], &s[1], &m[3][0], &s[3], &m[3][2], &s[0]),
13284 mul_add_sub(&m[2][0], &s[3], &m[2][2], &s[0], &m[2][1], &s[1]),
13285 ],
13286 ]
13287}
13288
13289#[inline(never)]
13290fn matrix4_adjugate_from_factors_dense_exact(
13291 m: &[[Real; 4]; 4],
13292 s: &[Real; 6],
13293 c: &[Real; 6],
13294) -> [[Real; 4]; 4] {
13295 crate::trace_dispatch!(
13296 "hyperlattice_matrix",
13297 "helper",
13298 "matrix4-unscaled-adjugate-dense-exact"
13299 );
13300 [
13301 [
13302 mul_add_sub_dense_exact(&m[1][1], &c[5], &m[1][3], &c[3], &m[1][2], &c[4]),
13303 mul_sub_add_dense_exact(&m[0][2], &c[4], &m[0][1], &c[5], &m[0][3], &c[3]),
13304 mul_add_sub_dense_exact(&m[3][1], &s[5], &m[3][3], &s[3], &m[3][2], &s[4]),
13305 mul_sub_add_dense_exact(&m[2][2], &s[4], &m[2][1], &s[5], &m[2][3], &s[3]),
13306 ],
13307 [
13308 mul_sub_add_dense_exact(&m[1][2], &c[2], &m[1][0], &c[5], &m[1][3], &c[1]),
13309 mul_add_sub_dense_exact(&m[0][0], &c[5], &m[0][3], &c[1], &m[0][2], &c[2]),
13310 mul_sub_add_dense_exact(&m[3][2], &s[2], &m[3][0], &s[5], &m[3][3], &s[1]),
13311 mul_add_sub_dense_exact(&m[2][0], &s[5], &m[2][3], &s[1], &m[2][2], &s[2]),
13312 ],
13313 [
13314 mul_add_sub_dense_exact(&m[1][0], &c[4], &m[1][3], &c[0], &m[1][1], &c[2]),
13315 mul_sub_add_dense_exact(&m[0][1], &c[2], &m[0][0], &c[4], &m[0][3], &c[0]),
13316 mul_add_sub_dense_exact(&m[3][0], &s[4], &m[3][3], &s[0], &m[3][1], &s[2]),
13317 mul_sub_add_dense_exact(&m[2][1], &s[2], &m[2][0], &s[4], &m[2][3], &s[0]),
13318 ],
13319 [
13320 mul_sub_add_dense_exact(&m[1][1], &c[1], &m[1][0], &c[3], &m[1][2], &c[0]),
13321 mul_add_sub_dense_exact(&m[0][0], &c[3], &m[0][2], &c[0], &m[0][1], &c[1]),
13322 mul_sub_add_dense_exact(&m[3][1], &s[1], &m[3][0], &s[3], &m[3][2], &s[0]),
13323 mul_add_sub_dense_exact(&m[2][0], &s[3], &m[2][2], &s[0], &m[2][1], &s[1]),
13324 ],
13325 ]
13326}
13327
13328#[inline(never)]
13329fn matrix4_adjugate_from_factors_dense_exact_known_rational(
13330 m: &[[Real; 4]; 4],
13331 s: &[Real; 6],
13332 c: &[Real; 6],
13333) -> [[Real; 4]; 4] {
13334 crate::trace_dispatch!(
13335 "hyperlattice_matrix",
13336 "helper",
13337 "matrix4-unscaled-adjugate-dense-exact-known-rational"
13338 );
13339 [
13340 [
13341 mul_add_sub_dense_exact_known_rational(
13342 &m[1][1], &c[5], &m[1][3], &c[3], &m[1][2], &c[4],
13343 ),
13344 mul_sub_add_dense_exact_known_rational(
13345 &m[0][2], &c[4], &m[0][1], &c[5], &m[0][3], &c[3],
13346 ),
13347 mul_add_sub_dense_exact_known_rational(
13348 &m[3][1], &s[5], &m[3][3], &s[3], &m[3][2], &s[4],
13349 ),
13350 mul_sub_add_dense_exact_known_rational(
13351 &m[2][2], &s[4], &m[2][1], &s[5], &m[2][3], &s[3],
13352 ),
13353 ],
13354 [
13355 mul_sub_add_dense_exact_known_rational(
13356 &m[1][2], &c[2], &m[1][0], &c[5], &m[1][3], &c[1],
13357 ),
13358 mul_add_sub_dense_exact_known_rational(
13359 &m[0][0], &c[5], &m[0][3], &c[1], &m[0][2], &c[2],
13360 ),
13361 mul_sub_add_dense_exact_known_rational(
13362 &m[3][2], &s[2], &m[3][0], &s[5], &m[3][3], &s[1],
13363 ),
13364 mul_add_sub_dense_exact_known_rational(
13365 &m[2][0], &s[5], &m[2][3], &s[1], &m[2][2], &s[2],
13366 ),
13367 ],
13368 [
13369 mul_add_sub_dense_exact_known_rational(
13370 &m[1][0], &c[4], &m[1][3], &c[0], &m[1][1], &c[2],
13371 ),
13372 mul_sub_add_dense_exact_known_rational(
13373 &m[0][1], &c[2], &m[0][0], &c[4], &m[0][3], &c[0],
13374 ),
13375 mul_add_sub_dense_exact_known_rational(
13376 &m[3][0], &s[4], &m[3][3], &s[0], &m[3][1], &s[2],
13377 ),
13378 mul_sub_add_dense_exact_known_rational(
13379 &m[2][1], &s[2], &m[2][0], &s[4], &m[2][3], &s[0],
13380 ),
13381 ],
13382 [
13383 mul_sub_add_dense_exact_known_rational(
13384 &m[1][1], &c[1], &m[1][0], &c[3], &m[1][2], &c[0],
13385 ),
13386 mul_add_sub_dense_exact_known_rational(
13387 &m[0][0], &c[3], &m[0][2], &c[0], &m[0][1], &c[1],
13388 ),
13389 mul_sub_add_dense_exact_known_rational(
13390 &m[3][1], &s[1], &m[3][0], &s[3], &m[3][2], &s[0],
13391 ),
13392 mul_add_sub_dense_exact_known_rational(
13393 &m[2][0], &s[3], &m[2][2], &s[0], &m[2][1], &s[1],
13394 ),
13395 ],
13396 ]
13397}
13398
13399macro_rules! impl_matrix {
13400 (
13401 $name:ident,
13402 $vector:ident,
13403 $n:expr,
13404 $div_fn:ident,
13405 $div_ref_fn:ident,
13406 $power_fn:ident,
13407 $mul_owned_fn:ident,
13408 $mul_rhs_ref_fn:ident,
13409 $mul_ref_fn:ident,
13410 $div_checked_fn:ident,
13411 $div_checked_abort_fn:ident
13412 ) => {
13413 impl $name {
13414 pub fn new(values: [[Real; $n]; $n]) -> Self {
13416 crate::trace_dispatch!("hyperlattice_matrix", "constructor", "new");
13417 Self(values)
13418 }
13419
13420 pub fn zero() -> Self {
13422 crate::trace_dispatch!("hyperlattice_matrix", "constructor", "zero");
13423 Self(from_fn(|_| from_fn(|_| Real::zero())))
13424 }
13425
13426 pub fn identity() -> Self {
13428 crate::trace_dispatch!("hyperlattice_matrix", "constructor", "identity");
13429 Self(from_fn(|row| {
13430 from_fn(|col| {
13431 if row == col {
13432 Real::one()
13433 } else {
13434 Real::zero()
13435 }
13436 })
13437 }))
13438 }
13439
13440 pub fn transpose(&self) -> Self {
13442 crate::trace_dispatch!("hyperlattice_matrix", "method", "transpose");
13443 Self(from_fn(|row| from_fn(|col| self.0[col][row].clone())))
13444 }
13445
13446 pub fn reciprocal(self) -> BlasResult<Self> {
13450 crate::trace_dispatch!("hyperlattice_matrix", "method", "reciprocal");
13451 self.inverse()
13452 }
13453
13454 pub fn reciprocal_checked(self) -> CheckedBlasResult<Self> {
13458 crate::trace_dispatch!("hyperlattice_matrix", "method", "reciprocal-checked");
13459 self.inverse_checked()
13460 }
13461
13462 pub fn powi(self, exponent: i32) -> BlasResult<Self> {
13466 crate::trace_dispatch!("hyperlattice_matrix", "method", "powi");
13467 if exponent == -1 {
13468 crate::trace_dispatch!("hyperlattice_matrix", "powi", "negative-one-inverse");
13469 return self.inverse();
13470 }
13471 let base = if exponent < 0 {
13479 self.inverse()?.0
13480 } else {
13481 self.0
13482 };
13483 Ok(Self($power_fn(base, exponent.unsigned_abs())))
13484 }
13485
13486 pub fn powi_checked(self, exponent: i32) -> CheckedBlasResult<Self> {
13488 crate::trace_dispatch!("hyperlattice_matrix", "method", "powi-checked");
13489 if exponent == -1 {
13490 crate::trace_dispatch!(
13491 "hyperlattice_matrix",
13492 "powi",
13493 "negative-one-inverse-checked"
13494 );
13495 return self.inverse_checked();
13496 }
13497 let base = if exponent < 0 {
13498 self.inverse_checked()?.0
13499 } else {
13500 self.0
13501 };
13502 Ok(Self($power_fn(base, exponent.unsigned_abs())))
13503 }
13504
13505 pub fn powi_checked_with_abort(
13507 self,
13508 exponent: i32,
13509 signal: &AbortSignal,
13510 ) -> CheckedBlasResult<Self> {
13511 crate::trace_dispatch!("hyperlattice_matrix", "method", "powi-checked-with-abort");
13512 if exponent == -1 {
13513 crate::trace_dispatch!(
13514 "hyperlattice_matrix",
13515 "powi",
13516 "negative-one-inverse-checked-with-abort"
13517 );
13518 return self.inverse_checked_with_abort(signal);
13519 }
13520 let base = if exponent < 0 {
13521 self.inverse_checked_with_abort(signal)?.0
13522 } else {
13523 self.0
13524 };
13525 Ok(Self($power_fn(base, exponent.unsigned_abs())))
13526 }
13527
13528 pub fn div_scalar_checked(self, rhs: Real) -> CheckedBlasResult<Self> {
13530 crate::trace_dispatch!("hyperlattice_matrix", "method", "div-scalar-checked");
13531 require_known_nonzero(&rhs)?;
13532 let inv_rhs = rhs.inverse()?;
13533 if true {
13534 Ok(Self(
13535 self.0
13536 .map(|row| row.map(|value| value.mul_cached(&inv_rhs))),
13537 ))
13538 } else {
13539 let mut values = self.0;
13540 for row in &mut values {
13541 for value in row {
13542 *value = value.clone().mul_cached(&inv_rhs);
13543 }
13544 }
13545 Ok(Self(values))
13546 }
13547 }
13548
13549 pub fn div_scalar_checked_with_abort(
13551 self,
13552 rhs: Real,
13553 signal: &AbortSignal,
13554 ) -> CheckedBlasResult<Self> {
13555 crate::trace_dispatch!(
13556 "hyperlattice_matrix",
13557 "method",
13558 "div-scalar-checked-with-abort"
13559 );
13560 let rhs = with_abort(rhs, signal);
13561 require_known_nonzero(&rhs)?;
13562 let inv_rhs = rhs.inverse()?;
13563 if true {
13564 Ok(Self(
13565 self.0
13566 .map(|row| row.map(|value| value.mul_cached(&inv_rhs))),
13567 ))
13568 } else {
13569 let mut values = self.0;
13570 for row in &mut values {
13571 for value in row {
13572 *value = value.clone().mul_cached(&inv_rhs);
13573 }
13574 }
13575 Ok(Self(values))
13576 }
13577 }
13578
13579 pub fn div_matrix_checked(self, rhs: Self) -> CheckedBlasResult<Self> {
13581 crate::trace_dispatch!("hyperlattice_matrix", "method", "div-matrix-checked");
13582 Ok(Self($div_checked_fn(self.0, rhs.0)?))
13583 }
13584
13585 pub fn div_matrix_checked_with_abort(
13587 self,
13588 rhs: Self,
13589 signal: &AbortSignal,
13590 ) -> CheckedBlasResult<Self> {
13591 crate::trace_dispatch!(
13592 "hyperlattice_matrix",
13593 "method",
13594 "div-matrix-checked-with-abort"
13595 );
13596 Ok(Self($div_checked_abort_fn(self.0, rhs.0, signal)?))
13597 }
13598 }
13599
13600 impl Index<usize> for $name {
13601 type Output = [Real; $n];
13602
13603 fn index(&self, index: usize) -> &Self::Output {
13604 &self.0[index]
13605 }
13606 }
13607
13608 impl IndexMut<usize> for $name {
13609 fn index_mut(&mut self, index: usize) -> &mut Self::Output {
13610 &mut self.0[index]
13611 }
13612 }
13613
13614 impl fmt::Display for $name {
13615 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
13616 f.write_str("[")?;
13617 for row in 0..$n {
13618 if row > 0 {
13619 f.write_str(", ")?;
13620 }
13621 f.write_str("[")?;
13622 for col in 0..$n {
13623 if col > 0 {
13624 f.write_str(", ")?;
13625 }
13626 if f.alternate() {
13627 write!(f, "{:#}", self.0[row][col])?;
13628 } else {
13629 write!(f, "{}", self.0[row][col])?;
13630 }
13631 }
13632 f.write_str("]")?;
13633 }
13634 f.write_str("]")
13635 }
13636 }
13637
13638 impl Add for $name {
13639 type Output = Self;
13640
13641 fn add(self, rhs: Self) -> Self::Output {
13642 crate::trace_dispatch!("hyperlattice_matrix", "op", "add-owned-owned");
13643 if true {
13644 Self(map_matrix2(self.0, rhs.0, |lhs, rhs| lhs + rhs))
13645 } else {
13646 Self(from_fn(|row| {
13647 from_fn(|col| self.0[row][col].clone() + rhs.0[row][col].clone())
13648 }))
13649 }
13650 }
13651 }
13652
13653 impl Add<&$name> for $name {
13654 type Output = Self;
13655
13656 fn add(self, rhs: &$name) -> Self::Output {
13657 crate::trace_dispatch!("hyperlattice_matrix", "op", "add-owned-ref");
13658 Self(map_matrix_ref(self.0, &rhs.0, Real::add_cached))
13659 }
13660 }
13661
13662 impl Add<$name> for &$name {
13663 type Output = $name;
13664
13665 fn add(self, rhs: $name) -> Self::Output {
13666 crate::trace_dispatch!("hyperlattice_matrix", "op", "add-ref-owned");
13667 $name(map_matrix_left_ref(&self.0, rhs.0, |lhs, rhs| lhs + rhs))
13668 }
13669 }
13670
13671 impl Add<&$name> for &$name {
13672 type Output = $name;
13673
13674 fn add(self, rhs: &$name) -> Self::Output {
13675 crate::trace_dispatch!("hyperlattice_matrix", "op", "add-ref-ref");
13676 $name(from_fn(|row| {
13677 from_fn(|col| &self.0[row][col] + &rhs.0[row][col])
13678 }))
13679 }
13680 }
13681
13682 impl Add<Real> for $name {
13683 type Output = Self;
13684
13685 fn add(self, rhs: Real) -> Self::Output {
13686 crate::trace_dispatch!("hyperlattice_matrix", "op", "add-scalar-owned");
13687 let rhs = &rhs;
13688 if true {
13689 Self(self.0.map(|row| row.map(|value| value.add_cached(rhs))))
13690 } else {
13691 let mut values = self.0;
13692 for row in &mut values {
13693 for value in row {
13694 *value = value.clone().add_cached(rhs);
13695 }
13696 }
13697 Self(values)
13698 }
13699 }
13700 }
13701
13702 impl Add<&Real> for $name {
13703 type Output = Self;
13704
13705 fn add(self, rhs: &Real) -> Self::Output {
13706 crate::trace_dispatch!("hyperlattice_matrix", "op", "add-scalar-ref");
13707 Self(self.0.map(|row| row.map(|value| value.add_cached(rhs))))
13708 }
13709 }
13710
13711 impl Sub for $name {
13712 type Output = Self;
13713
13714 fn sub(self, rhs: Self) -> Self::Output {
13715 crate::trace_dispatch!("hyperlattice_matrix", "op", "sub-owned-owned");
13716 if true {
13717 Self(map_matrix2(self.0, rhs.0, |lhs, rhs| lhs - rhs))
13718 } else {
13719 Self(from_fn(|row| {
13720 from_fn(|col| self.0[row][col].clone() - rhs.0[row][col].clone())
13721 }))
13722 }
13723 }
13724 }
13725
13726 impl Sub<&$name> for $name {
13727 type Output = Self;
13728
13729 fn sub(self, rhs: &$name) -> Self::Output {
13730 crate::trace_dispatch!("hyperlattice_matrix", "op", "sub-owned-ref");
13731 Self(map_matrix_ref(self.0, &rhs.0, Real::sub_cached))
13732 }
13733 }
13734
13735 impl Sub<$name> for &$name {
13736 type Output = $name;
13737
13738 fn sub(self, rhs: $name) -> Self::Output {
13739 crate::trace_dispatch!("hyperlattice_matrix", "op", "sub-ref-owned");
13740 $name(map_matrix_left_ref(&self.0, rhs.0, |lhs, rhs| lhs - rhs))
13741 }
13742 }
13743
13744 impl Sub<&$name> for &$name {
13745 type Output = $name;
13746
13747 fn sub(self, rhs: &$name) -> Self::Output {
13748 crate::trace_dispatch!("hyperlattice_matrix", "op", "sub-ref-ref");
13749 $name(from_fn(|row| {
13750 from_fn(|col| &self.0[row][col] - &rhs.0[row][col])
13751 }))
13752 }
13753 }
13754
13755 impl Sub<Real> for $name {
13756 type Output = Self;
13757
13758 fn sub(self, rhs: Real) -> Self::Output {
13759 crate::trace_dispatch!("hyperlattice_matrix", "op", "sub-scalar-owned");
13760 let rhs = -rhs;
13761 let rhs = &rhs;
13762 if true {
13763 Self(self.0.map(|row| row.map(|value| value.add_cached(rhs))))
13764 } else {
13765 let mut values = self.0;
13766 for row in &mut values {
13767 for value in row {
13768 *value = value.clone().add_cached(rhs);
13769 }
13770 }
13771 Self(values)
13772 }
13773 }
13774 }
13775
13776 impl Sub<&Real> for $name {
13777 type Output = Self;
13778
13779 fn sub(self, rhs: &Real) -> Self::Output {
13780 crate::trace_dispatch!("hyperlattice_matrix", "op", "sub-scalar-ref");
13781 let rhs = -rhs.clone();
13782 Self(self.0.map(|row| row.map(|value| value.add_cached(&rhs))))
13783 }
13784 }
13785
13786 impl Neg for $name {
13787 type Output = Self;
13788
13789 fn neg(self) -> Self::Output {
13790 crate::trace_dispatch!("hyperlattice_matrix", "op", "neg-owned");
13791 if true {
13792 Self(self.0.map(|row| row.map(|value| -value)))
13793 } else {
13794 Self(from_fn(|row| from_fn(|col| -self.0[row][col].clone())))
13795 }
13796 }
13797 }
13798
13799 impl Neg for &$name {
13800 type Output = $name;
13801
13802 fn neg(self) -> Self::Output {
13803 crate::trace_dispatch!("hyperlattice_matrix", "op", "neg-ref");
13804 $name(from_fn(|row| from_fn(|col| -self.0[row][col].clone())))
13805 }
13806 }
13807
13808 impl Mul<Real> for $name {
13809 type Output = Self;
13810
13811 fn mul(self, rhs: Real) -> Self::Output {
13812 crate::trace_dispatch!("hyperlattice_matrix", "op", "mul-scalar-owned");
13813 let rhs = &rhs;
13814 if true {
13815 Self(self.0.map(|row| row.map(|value| value.mul_cached(rhs))))
13816 } else {
13817 let mut values = self.0;
13818 for row in &mut values {
13819 for value in row {
13820 *value = value.clone().mul_cached(rhs);
13821 }
13822 }
13823 Self(values)
13824 }
13825 }
13826 }
13827
13828 impl Mul<&Real> for $name {
13829 type Output = Self;
13830
13831 fn mul(self, rhs: &Real) -> Self::Output {
13832 crate::trace_dispatch!("hyperlattice_matrix", "op", "mul-scalar-ref");
13833 Self(self.0.map(|row| row.map(|value| value.mul_cached(rhs))))
13834 }
13835 }
13836
13837 impl Div<Real> for $name {
13838 type Output = BlasResult<Self>;
13839
13840 fn div(self, rhs: Real) -> Self::Output {
13841 crate::trace_dispatch!("hyperlattice_matrix", "op", "div-scalar-owned");
13842 reject_definite_zero(&rhs)?;
13843 let inv_rhs = rhs.inverse()?;
13844 if true && $n == 3 {
13845 Ok(Self(self.0.map(|row| row.map(|value| &value * &inv_rhs))))
13846 } else if true {
13847 Ok(Self(
13848 self.0
13849 .map(|row| row.map(|value| value.mul_cached(&inv_rhs))),
13850 ))
13851 } else {
13852 let mut values = self.0;
13853 for row in &mut values {
13854 for value in row {
13855 *value = value.clone().mul_cached(&inv_rhs);
13856 }
13857 }
13858 Ok(Self(values))
13859 }
13860 }
13861 }
13862
13863 impl Div<&Real> for $name {
13864 type Output = BlasResult<Self>;
13865
13866 fn div(self, rhs: &Real) -> Self::Output {
13867 crate::trace_dispatch!("hyperlattice_matrix", "op", "div-scalar-ref");
13868 reject_definite_zero(rhs)?;
13869 let inv_rhs = rhs.inverse_ref()?;
13870 if true && $n == 3 {
13871 Ok(Self(self.0.map(|row| row.map(|value| &value * &inv_rhs))))
13872 } else if true {
13873 Ok(Self(
13874 self.0
13875 .map(|row| row.map(|value| value.mul_cached(&inv_rhs))),
13876 ))
13877 } else {
13878 let mut values = self.0;
13879 for row in &mut values {
13880 for value in row {
13881 *value = value.clone().mul_cached(&inv_rhs);
13882 }
13883 }
13884 Ok(Self(values))
13885 }
13886 }
13887 }
13888
13889 impl Mul for $name {
13890 type Output = Self;
13891
13892 fn mul(self, rhs: Self) -> Self::Output {
13893 crate::trace_dispatch!("hyperlattice_matrix", "op", "mul-owned-owned");
13894 Self($mul_owned_fn(self.0, rhs.0))
13895 }
13896 }
13897
13898 impl Mul<&$name> for $name {
13899 type Output = Self;
13900
13901 fn mul(self, rhs: &$name) -> Self::Output {
13902 crate::trace_dispatch!("hyperlattice_matrix", "op", "mul-owned-ref");
13903 Self($mul_rhs_ref_fn(self.0, &rhs.0))
13904 }
13905 }
13906
13907 impl Mul<$name> for &$name {
13908 type Output = $name;
13909
13910 fn mul(self, rhs: $name) -> Self::Output {
13911 crate::trace_dispatch!("hyperlattice_matrix", "op", "mul-ref-owned");
13912 $name($mul_ref_fn(&self.0, &rhs.0))
13913 }
13914 }
13915
13916 impl Mul<&$name> for &$name {
13917 type Output = $name;
13918
13919 fn mul(self, rhs: &$name) -> Self::Output {
13920 crate::trace_dispatch!("hyperlattice_matrix", "op", "mul-ref-ref");
13921 $name($mul_ref_fn(&self.0, &rhs.0))
13922 }
13923 }
13924
13925 impl Div for $name {
13926 type Output = BlasResult<Self>;
13927
13928 fn div(self, rhs: Self) -> Self::Output {
13929 crate::trace_dispatch!("hyperlattice_matrix", "op", "div-owned-owned");
13930 Ok(Self($div_fn(self.0, rhs.0)?))
13931 }
13932 }
13933
13934 impl Div<&$name> for $name {
13935 type Output = BlasResult<Self>;
13936
13937 fn div(self, rhs: &$name) -> Self::Output {
13938 crate::trace_dispatch!("hyperlattice_matrix", "op", "div-owned-ref");
13939 self / rhs.clone()
13940 }
13941 }
13942
13943 impl Div<$name> for &$name {
13944 type Output = BlasResult<$name>;
13945
13946 fn div(self, rhs: $name) -> Self::Output {
13947 crate::trace_dispatch!("hyperlattice_matrix", "op", "div-ref-owned");
13948 self.clone() / rhs
13949 }
13950 }
13951
13952 impl Div<&$name> for &$name {
13953 type Output = BlasResult<$name>;
13954
13955 fn div(self, rhs: &$name) -> Self::Output {
13956 crate::trace_dispatch!("hyperlattice_matrix", "op", "div-ref-ref");
13957 Ok($name($div_ref_fn(&self.0, &rhs.0)?))
13958 }
13959 }
13960
13961 impl Mul<$vector> for $name {
13962 type Output = $vector;
13963
13964 fn mul(self, rhs: $vector) -> Self::Output {
13965 crate::trace_dispatch!("hyperlattice_matrix", "op", "transform-vector-owned-owned");
13966 $vector(transform_vector_rhs_ref(&self.0, &rhs.0))
13967 }
13968 }
13969
13970 impl Mul<&$vector> for $name {
13971 type Output = $vector;
13972
13973 fn mul(self, rhs: &$vector) -> Self::Output {
13974 crate::trace_dispatch!("hyperlattice_matrix", "op", "transform-vector-owned-ref");
13975 $vector(transform_vector_rhs_ref(&self.0, &rhs.0))
13976 }
13977 }
13978
13979 impl Mul<$vector> for &$name {
13980 type Output = $vector;
13981
13982 fn mul(self, rhs: $vector) -> Self::Output {
13983 crate::trace_dispatch!("hyperlattice_matrix", "op", "transform-vector-ref-owned");
13984 $vector(transform_vector_rhs_ref(&self.0, &rhs.0))
13985 }
13986 }
13987
13988 impl Mul<&$vector> for &$name {
13989 type Output = $vector;
13990
13991 fn mul(self, rhs: &$vector) -> Self::Output {
13992 crate::trace_dispatch!("hyperlattice_matrix", "op", "transform-vector-ref-ref");
13993 $vector(transform_vector_rhs_ref(&self.0, &rhs.0))
13994 }
13995 }
13996
13997 impl BitXor<i32> for $name {
13998 type Output = BlasResult<Self>;
13999
14000 fn bitxor(self, rhs: i32) -> Self::Output {
14001 crate::trace_dispatch!("hyperlattice_matrix", "op", "bitxor-powi");
14002 self.powi(rhs)
14003 }
14004 }
14005 };
14006}
14007
14008impl_matrix!(
14009 Matrix3,
14010 Vector3,
14011 3,
14012 right_divide_matrix3,
14013 right_divide_matrix3_ref,
14014 matrix_power3,
14015 multiply_arrays3,
14016 multiply_arrays3_rhs_ref,
14017 multiply_arrays3_ref,
14018 right_divide_matrix3_checked,
14019 right_divide_matrix3_checked_with_abort
14020);
14021impl_matrix!(
14022 Matrix4,
14023 Vector4,
14024 4,
14025 right_divide_matrix4,
14026 right_divide_matrix4_ref,
14027 matrix_power4,
14028 multiply_arrays4,
14029 multiply_arrays4_rhs_ref,
14030 multiply_arrays4_ref,
14031 right_divide_matrix4_checked,
14032 right_divide_matrix4_checked_with_abort
14033);
14034
14035impl Matrix3 {
14036 pub fn exact_facts(&self) -> ExactRealSetFacts {
14046 crate::trace_dispatch!("hyperlattice_matrix", "query", "matrix3-exact-facts");
14047 matrix3_facts(&self.0).exact
14048 }
14049
14050 pub fn structural_facts(&self) -> Matrix3StructuralFacts {
14059 crate::trace_dispatch!("hyperlattice_matrix", "query", "matrix3-structural-facts");
14060 matrix3_facts(&self.0).public
14061 }
14062
14063 pub fn prepare(&self) -> PreparedMatrix3<'_> {
14072 PreparedMatrix3::new(self)
14073 }
14074
14075 pub fn diagonal(diagonal: [Real; 3]) -> Self {
14077 crate::trace_dispatch!("hyperlattice_matrix", "constructor", "diagonal3");
14078 let [d0, d1, d2] = diagonal;
14079 Self([
14080 [d0, Real::zero(), Real::zero()],
14081 [Real::zero(), d1, Real::zero()],
14082 [Real::zero(), Real::zero(), d2],
14083 ])
14084 }
14085
14086 pub fn diagonal_inverse(diagonal: [Real; 3]) -> BlasResult<Self> {
14097 crate::trace_dispatch!("hyperlattice_matrix", "constructor", "diagonal3-inverse");
14098 let [d0, d1, d2] = diagonal;
14099 Ok(Self::diagonal([
14100 d0.inverse()?,
14101 d1.inverse()?,
14102 d2.inverse()?,
14103 ]))
14104 }
14105
14106 pub fn div_diagonal(self, diagonal: [Real; 3]) -> BlasResult<Self> {
14118 crate::trace_dispatch!("hyperlattice_matrix", "method", "div-diagonal3");
14119 let [[a00, a01, a02], [a10, a11, a12], [a20, a21, a22]] = self.0;
14120 let [d0, d1, d2] = diagonal;
14121 let inv0 = d0.inverse()?;
14122 let inv1 = d1.inverse()?;
14123 let inv2 = d2.inverse()?;
14124 Ok(Self([
14125 [
14126 a00.mul_cached(&inv0),
14127 a01.mul_cached(&inv1),
14128 a02.mul_cached(&inv2),
14129 ],
14130 [
14131 a10.mul_cached(&inv0),
14132 a11.mul_cached(&inv1),
14133 a12.mul_cached(&inv2),
14134 ],
14135 [
14136 a20.mul_cached(&inv0),
14137 a21.mul_cached(&inv1),
14138 a22.mul_cached(&inv2),
14139 ],
14140 ]))
14141 }
14142
14143 pub fn upper_triangular_inverse(self) -> BlasResult<Self> {
14149 crate::trace_dispatch!("hyperlattice_matrix", "method", "upper-triangular3-inverse");
14150 Ok(Self(invert_matrix3_upper_triangular(&self.0)?))
14151 }
14152
14153 pub fn upper_triangular_inverse_checked(self) -> CheckedBlasResult<Self> {
14155 crate::trace_dispatch!(
14156 "hyperlattice_matrix",
14157 "method",
14158 "upper-triangular3-inverse-checked"
14159 );
14160 Ok(Self(invert_matrix3_upper_triangular_checked(&self.0)?))
14161 }
14162
14163 pub fn upper_triangular_inverse_checked_with_abort(
14165 self,
14166 signal: &AbortSignal,
14167 ) -> CheckedBlasResult<Self> {
14168 crate::trace_dispatch!(
14169 "hyperlattice_matrix",
14170 "method",
14171 "upper-triangular3-inverse-checked-with-abort"
14172 );
14173 Ok(Self(invert_matrix3_upper_triangular_checked_with_abort(
14174 &self.0, signal,
14175 )?))
14176 }
14177
14178 pub fn lower_triangular_inverse(self) -> BlasResult<Self> {
14180 crate::trace_dispatch!("hyperlattice_matrix", "method", "lower-triangular3-inverse");
14181 Ok(Self(invert_matrix3_lower_triangular(&self.0)?))
14182 }
14183
14184 pub fn lower_triangular_inverse_checked(self) -> CheckedBlasResult<Self> {
14186 crate::trace_dispatch!(
14187 "hyperlattice_matrix",
14188 "method",
14189 "lower-triangular3-inverse-checked"
14190 );
14191 Ok(Self(invert_matrix3_lower_triangular_checked(&self.0)?))
14192 }
14193
14194 pub fn lower_triangular_inverse_checked_with_abort(
14196 self,
14197 signal: &AbortSignal,
14198 ) -> CheckedBlasResult<Self> {
14199 crate::trace_dispatch!(
14200 "hyperlattice_matrix",
14201 "method",
14202 "lower-triangular3-inverse-checked-with-abort"
14203 );
14204 Ok(Self(invert_matrix3_lower_triangular_checked_with_abort(
14205 &self.0, signal,
14206 )?))
14207 }
14208
14209 pub fn div_upper_triangular(self, divisor: Self) -> BlasResult<Self> {
14211 crate::trace_dispatch!("hyperlattice_matrix", "method", "div-upper-triangular3");
14212 Ok(Self(divide_matrix3_by_upper_triangular(
14213 self.0, &divisor.0,
14214 )?))
14215 }
14216
14217 pub fn div_upper_triangular_checked(self, divisor: Self) -> CheckedBlasResult<Self> {
14219 crate::trace_dispatch!(
14220 "hyperlattice_matrix",
14221 "method",
14222 "div-upper-triangular3-checked"
14223 );
14224 Ok(Self(divide_matrix3_by_upper_triangular_checked(
14225 self.0, &divisor.0,
14226 )?))
14227 }
14228
14229 pub fn div_upper_triangular_checked_with_abort(
14231 self,
14232 divisor: Self,
14233 signal: &AbortSignal,
14234 ) -> CheckedBlasResult<Self> {
14235 crate::trace_dispatch!(
14236 "hyperlattice_matrix",
14237 "method",
14238 "div-upper-triangular3-checked-with-abort"
14239 );
14240 Ok(Self(divide_matrix3_by_upper_triangular_checked_with_abort(
14241 self.0, &divisor.0, signal,
14242 )?))
14243 }
14244
14245 pub fn div_lower_triangular(self, divisor: Self) -> BlasResult<Self> {
14247 crate::trace_dispatch!("hyperlattice_matrix", "method", "div-lower-triangular3");
14248 Ok(Self(divide_matrix3_by_lower_triangular(
14249 self.0, &divisor.0,
14250 )?))
14251 }
14252
14253 pub fn div_lower_triangular_checked(self, divisor: Self) -> CheckedBlasResult<Self> {
14255 crate::trace_dispatch!(
14256 "hyperlattice_matrix",
14257 "method",
14258 "div-lower-triangular3-checked"
14259 );
14260 Ok(Self(divide_matrix3_by_lower_triangular_checked(
14261 self.0, &divisor.0,
14262 )?))
14263 }
14264
14265 pub fn div_lower_triangular_checked_with_abort(
14267 self,
14268 divisor: Self,
14269 signal: &AbortSignal,
14270 ) -> CheckedBlasResult<Self> {
14271 crate::trace_dispatch!(
14272 "hyperlattice_matrix",
14273 "method",
14274 "div-lower-triangular3-checked-with-abort"
14275 );
14276 Ok(Self(divide_matrix3_by_lower_triangular_checked_with_abort(
14277 self.0, &divisor.0, signal,
14278 )?))
14279 }
14280
14281 pub fn div_diagonal_vector(&self, diagonal: [Real; 3], rhs: &Vector3) -> BlasResult<Vector3> {
14293 crate::trace_dispatch!("hyperlattice_matrix", "method", "div-diagonal3-vector");
14294 let [d0, d1, d2] = diagonal;
14295 let (inv0, inv1, inv2) = if d0 == d1 && d0 == d2 {
14296 crate::trace_dispatch!(
14297 "hyperlattice_matrix",
14298 "helper",
14299 "div-diagonal3-vector-uniform-scale"
14300 );
14301 let inv = d0.inverse()?;
14302 (inv.clone(), inv.clone(), inv)
14303 } else {
14304 (d0.inverse()?, d1.inverse()?, d2.inverse()?)
14305 };
14306
14307 let rhs_div = [
14308 rhs.0[0].clone().mul_cached(&inv0),
14309 rhs.0[1].clone().mul_cached(&inv1),
14310 rhs.0[2].clone().mul_cached(&inv2),
14311 ];
14312 let mapped = if true {
14313 transform_vector3_rhs_dense_active_ref(&self.0, &rhs_div)
14314 } else {
14315 transform_vector3_rhs_ref_cached(&self.0, &rhs_div)
14316 };
14317 Ok(Vector3(mapped))
14318 }
14319
14320 pub fn prepare_right_divisor(&self) -> PreparedRightDivisor3<'_> {
14328 PreparedRightDivisor3::new(self)
14329 }
14330
14331 pub fn div_matrix_with_prepared(
14337 self,
14338 divisor: &mut PreparedRightDivisor3<'_>,
14339 ) -> BlasResult<Self> {
14340 crate::trace_dispatch!("hyperlattice_matrix", "method", "div-matrix-with-prepared");
14341 Ok(Self(divisor.divide(self.0)?))
14342 }
14343
14344 pub fn div_matrix_checked_with_prepared(
14349 self,
14350 divisor: &mut PreparedRightDivisor3<'_>,
14351 ) -> CheckedBlasResult<Self> {
14352 crate::trace_dispatch!(
14353 "hyperlattice_matrix",
14354 "method",
14355 "div-matrix-checked-with-prepared"
14356 );
14357 Ok(Self(divisor.divide_checked(self.0)?))
14358 }
14359
14360 pub fn div_matrix_checked_with_prepared_with_abort(
14362 self,
14363 divisor: &mut PreparedRightDivisor3<'_>,
14364 signal: &AbortSignal,
14365 ) -> CheckedBlasResult<Self> {
14366 crate::trace_dispatch!(
14367 "hyperlattice_matrix",
14368 "method",
14369 "div-matrix-checked-with-prepared-with-abort"
14370 );
14371 Ok(Self(divisor.divide_checked_with_abort(self.0, signal)?))
14372 }
14373
14374 pub fn uniform_scale(scale: Real) -> Self {
14376 crate::trace_dispatch!("hyperlattice_matrix", "constructor", "uniform-scale3");
14377 Self([
14378 [scale.clone(), Real::zero(), Real::zero()],
14379 [Real::zero(), scale.clone(), Real::zero()],
14380 [Real::zero(), Real::zero(), scale],
14381 ])
14382 }
14383
14384 pub fn uniform_scale_inverse(scale: Real) -> BlasResult<Self> {
14395 crate::trace_dispatch!(
14396 "hyperlattice_matrix",
14397 "constructor",
14398 "uniform-scale3-inverse"
14399 );
14400 let inv = scale.inverse()?;
14401 Ok(Self::uniform_scale(inv))
14402 }
14403
14404 pub fn transform_vec3_batch(&self, rhs: &[Vector3]) -> Vec<Vector3> {
14413 crate::trace_dispatch!(
14414 "hyperlattice_matrix",
14415 "method",
14416 "transform-vector-vec3-batch"
14417 );
14418 self.transform_vec3_handle().transform_vector_batch(rhs)
14419 }
14420
14421 pub fn transform_vec3_handle(&self) -> TransformedMatrix3<'_> {
14428 TransformedMatrix3::new(self)
14429 }
14430
14431 pub fn transform_vec3_with<'a>(&'a self, rhs: &'a Vector3) -> TransformedVector3<'a> {
14436 self.transform_vec3_handle().vector(rhs)
14437 }
14438
14439 pub fn inverse(self) -> BlasResult<Self> {
14444 crate::trace_dispatch!("hyperlattice_matrix", "method", "matrix3-inverse");
14445 Ok(Self(invert_matrix3(self.0)?))
14446 }
14447
14448 pub fn inverse_checked(self) -> CheckedBlasResult<Self> {
14450 crate::trace_dispatch!("hyperlattice_matrix", "method", "matrix3-inverse-checked");
14451 Ok(Self(invert_matrix3_checked(self.0)?))
14452 }
14453
14454 pub fn inverse_checked_with_abort(self, signal: &AbortSignal) -> CheckedBlasResult<Self> {
14456 crate::trace_dispatch!(
14457 "hyperlattice_matrix",
14458 "method",
14459 "matrix3-inverse-checked-with-abort"
14460 );
14461 Ok(Self(invert_matrix3_checked_with_abort(self.0, signal)?))
14462 }
14463
14464 pub fn determinant(&self) -> Real {
14466 crate::trace_dispatch!("hyperlattice_matrix", "method", "matrix3-determinant");
14467 determinant3(&self.0)
14468 }
14469}
14470
14471#[derive(Clone, Copy, Debug, Eq, PartialEq)]
14473pub enum SignedAxis4 {
14474 PosX,
14476 NegX,
14478 PosY,
14480 NegY,
14482 PosZ,
14484 NegZ,
14486 PosW,
14488 NegW,
14490}
14491
14492impl SignedAxis4 {
14493 #[inline]
14494 fn index(self) -> usize {
14495 match self {
14496 Self::PosX | Self::NegX => 0,
14497 Self::PosY | Self::NegY => 1,
14498 Self::PosZ | Self::NegZ => 2,
14499 Self::PosW | Self::NegW => 3,
14500 }
14501 }
14502
14503 #[inline]
14504 fn is_negative(self) -> bool {
14505 matches!(self, Self::NegX | Self::NegY | Self::NegZ | Self::NegW)
14506 }
14507}
14508
14509#[inline]
14510fn signed_axis4_scalar(axis: SignedAxis4) -> Real {
14511 if axis.is_negative() {
14512 -Real::one()
14513 } else {
14514 Real::one()
14515 }
14516}
14517
14518#[inline]
14519fn signed_axis4_apply(value: Real, axis: SignedAxis4) -> Real {
14520 if axis.is_negative() { -value } else { value }
14521}
14522
14523impl Matrix4 {
14524 pub fn from_row_major(values: [Real; 16]) -> Self {
14526 let [
14527 m00,
14528 m01,
14529 m02,
14530 m03,
14531 m10,
14532 m11,
14533 m12,
14534 m13,
14535 m20,
14536 m21,
14537 m22,
14538 m23,
14539 m30,
14540 m31,
14541 m32,
14542 m33,
14543 ] = values;
14544 Self::new([
14545 [m00, m01, m02, m03],
14546 [m10, m11, m12, m13],
14547 [m20, m21, m22, m23],
14548 [m30, m31, m32, m33],
14549 ])
14550 }
14551
14552 pub fn from_row_slice(values: &[Real]) -> Option<Self> {
14554 if values.len() != 16 {
14555 return None;
14556 }
14557 let values = std::array::from_fn(|index| values[index].clone());
14558 Some(Self::from_row_major(values))
14559 }
14560
14561 pub fn exact_facts(&self) -> ExactRealSetFacts {
14568 crate::trace_dispatch!("hyperlattice_matrix", "query", "matrix4-exact-facts");
14569 matrix4_facts(&self.0).exact
14570 }
14571
14572 pub fn structural_facts(&self) -> Matrix4StructuralFacts {
14578 crate::trace_dispatch!("hyperlattice_matrix", "query", "matrix4-structural-facts");
14579 matrix4_facts(&self.0).public
14580 }
14581
14582 pub fn prepare(&self) -> PreparedMatrix4<'_> {
14590 PreparedMatrix4::new(self)
14591 }
14592
14593 pub fn affine_translation(translation: [Real; 3]) -> Self {
14595 crate::trace_dispatch!("hyperlattice_matrix", "constructor", "affine-translation");
14596 let [tx, ty, tz] = translation;
14597 Self([
14598 [Real::one(), Real::zero(), Real::zero(), tx],
14599 [Real::zero(), Real::one(), Real::zero(), ty],
14600 [Real::zero(), Real::zero(), Real::one(), tz],
14601 [Real::zero(), Real::zero(), Real::zero(), Real::one()],
14602 ])
14603 }
14604
14605 pub fn affine_nonuniform_scale(scale: [Real; 3]) -> Self {
14607 let [sx, sy, sz] = scale;
14608 Self([
14609 [sx, Real::zero(), Real::zero(), Real::zero()],
14610 [Real::zero(), sy, Real::zero(), Real::zero()],
14611 [Real::zero(), Real::zero(), sz, Real::zero()],
14612 [Real::zero(), Real::zero(), Real::zero(), Real::one()],
14613 ])
14614 }
14615
14616 pub fn rotation_x(angle: Real) -> Self {
14618 let sin = angle.clone().sin();
14619 let cos = angle.cos();
14620 Self::from_row_major([
14621 Real::one(),
14622 Real::zero(),
14623 Real::zero(),
14624 Real::zero(),
14625 Real::zero(),
14626 cos.clone(),
14627 -sin.clone(),
14628 Real::zero(),
14629 Real::zero(),
14630 sin,
14631 cos,
14632 Real::zero(),
14633 Real::zero(),
14634 Real::zero(),
14635 Real::zero(),
14636 Real::one(),
14637 ])
14638 }
14639
14640 pub fn rotation_y(angle: Real) -> Self {
14642 let sin = angle.clone().sin();
14643 let cos = angle.cos();
14644 Self::from_row_major([
14645 cos.clone(),
14646 Real::zero(),
14647 sin.clone(),
14648 Real::zero(),
14649 Real::zero(),
14650 Real::one(),
14651 Real::zero(),
14652 Real::zero(),
14653 -sin,
14654 Real::zero(),
14655 cos,
14656 Real::zero(),
14657 Real::zero(),
14658 Real::zero(),
14659 Real::zero(),
14660 Real::one(),
14661 ])
14662 }
14663
14664 pub fn rotation_z(angle: Real) -> Self {
14666 let sin = angle.clone().sin();
14667 let cos = angle.cos();
14668 Self::from_row_major([
14669 cos.clone(),
14670 -sin.clone(),
14671 Real::zero(),
14672 Real::zero(),
14673 sin,
14674 cos,
14675 Real::zero(),
14676 Real::zero(),
14677 Real::zero(),
14678 Real::zero(),
14679 Real::one(),
14680 Real::zero(),
14681 Real::zero(),
14682 Real::zero(),
14683 Real::zero(),
14684 Real::one(),
14685 ])
14686 }
14687
14688 pub fn rotation_axis_angle(axis: &Vector3, angle: Real) -> CheckedBlasResult<Self> {
14690 let axis = axis.normalize_checked()?;
14691 let sin = angle.clone().sin();
14692 let cos = angle.cos();
14693 let one_minus_cos = Real::one() - cos.clone();
14694 let [x, y, z] = axis.0;
14695 let zero = Real::zero();
14696 let one = Real::one();
14697 Ok(Self::from_row_major([
14698 cos.clone() + x.clone() * x.clone() * one_minus_cos.clone(),
14699 x.clone() * y.clone() * one_minus_cos.clone() - z.clone() * sin.clone(),
14700 x.clone() * z.clone() * one_minus_cos.clone() + y.clone() * sin.clone(),
14701 zero.clone(),
14702 y.clone() * x.clone() * one_minus_cos.clone() + z.clone() * sin.clone(),
14703 cos.clone() + y.clone() * y.clone() * one_minus_cos.clone(),
14704 y.clone() * z.clone() * one_minus_cos.clone() - x.clone() * sin.clone(),
14705 zero.clone(),
14706 z.clone() * x.clone() * one_minus_cos.clone() - y.clone() * sin.clone(),
14707 z.clone() * y.clone() * one_minus_cos.clone() + x.clone() * sin,
14708 cos + z.clone() * z * one_minus_cos,
14709 zero.clone(),
14710 zero.clone(),
14711 zero.clone(),
14712 zero,
14713 one,
14714 ]))
14715 }
14716
14717 pub fn rotation_between_vectors(from: &Vector3, to: &Vector3) -> CheckedBlasResult<Self> {
14719 let from = from.normalize_checked()?;
14720 let to = to.normalize_checked()?;
14721 let dot = from.dot(&to);
14722
14723 match (dot.clone() - Real::one()).refine_sign_until(128) {
14724 Some(RealSign::Zero) => return Ok(Self::identity()),
14725 _ => {}
14726 }
14727
14728 let (axis, angle) = match (dot + Real::one()).refine_sign_until(128) {
14729 Some(RealSign::Zero) => {
14730 let threshold = (Real::from(9_u8) / Real::from(10_u8))?;
14731 let seed = if matches!(
14732 (from.0[0].clone().abs() - threshold).refine_sign_until(128),
14733 Some(RealSign::Negative)
14734 ) {
14735 Vector3::x()
14736 } else {
14737 Vector3::y()
14738 };
14739 (from.unit_cross_checked(&seed)?, Real::pi())
14740 }
14741 _ => (from.unit_cross_checked(&to)?, from.angle_to(&to)?),
14742 };
14743
14744 Self::rotation_axis_angle(&axis, angle)
14745 }
14746
14747 pub fn affine_translation_inverse(translation: [Real; 3]) -> Self {
14753 crate::trace_dispatch!(
14754 "hyperlattice_matrix",
14755 "constructor",
14756 "affine-translation-inverse"
14757 );
14758 let [tx, ty, tz] = translation;
14759 Self::affine_translation([-tx, -ty, -tz])
14760 }
14761
14762 pub fn div_affine_translation(self, translation: [Real; 3]) -> Self {
14769 crate::trace_dispatch!("hyperlattice_matrix", "method", "div-affine-translation4");
14770 let [row0, row1, row2, row3] = self.0;
14771 let [tx, ty, tz] = translation;
14772 let terms = [&tx, &ty, &tz];
14773 let t0 = affine_translation_column_subtract_update(&row0, terms);
14774 let t1 = affine_translation_column_subtract_update(&row1, terms);
14775 let t2 = affine_translation_column_subtract_update(&row2, terms);
14776 let t3 = affine_translation_column_subtract_update(&row3, terms);
14777 let [a00, a01, a02, _] = row0;
14778 let [a10, a11, a12, _] = row1;
14779 let [a20, a21, a22, _] = row2;
14780 let [a30, a31, a32, _] = row3;
14781 Self([
14782 [a00, a01, a02, t0],
14783 [a10, a11, a12, t1],
14784 [a20, a21, a22, t2],
14785 [a30, a31, a32, t3],
14786 ])
14787 }
14788
14789 pub fn affine_orthonormal(linear: [[Real; 3]; 3], translation: [Real; 3]) -> Self {
14795 crate::trace_dispatch!("hyperlattice_matrix", "constructor", "affine-orthonormal");
14796 let [[r00, r01, r02], [r10, r11, r12], [r20, r21, r22]] = linear;
14797 let [tx, ty, tz] = translation;
14798 Self([
14799 [r00, r01, r02, tx],
14800 [r10, r11, r12, ty],
14801 [r20, r21, r22, tz],
14802 [Real::zero(), Real::zero(), Real::zero(), Real::one()],
14803 ])
14804 }
14805
14806 pub fn affine_orthonormal_inverse(linear: [[Real; 3]; 3], translation: [Real; 3]) -> Self {
14812 crate::trace_dispatch!(
14813 "hyperlattice_matrix",
14814 "constructor",
14815 "affine-orthonormal-inverse"
14816 );
14817 let [[r00, r01, r02], [r10, r11, r12], [r20, r21, r22]] = linear;
14818 let [tx, ty, tz] = translation;
14819 let it0 = Real::zero() - affine_translation_dot3([&r00, &r10, &r20], [&tx, &ty, &tz]);
14820 let it1 = Real::zero() - affine_translation_dot3([&r01, &r11, &r21], [&tx, &ty, &tz]);
14821 let it2 = Real::zero() - affine_translation_dot3([&r02, &r12, &r22], [&tx, &ty, &tz]);
14822 Self([
14823 [r00, r10, r20, it0],
14824 [r01, r11, r21, it1],
14825 [r02, r12, r22, it2],
14826 [Real::zero(), Real::zero(), Real::zero(), Real::one()],
14827 ])
14828 }
14829
14830 pub fn div_affine_orthonormal(self, linear: [[Real; 3]; 3], translation: [Real; 3]) -> Self {
14832 crate::trace_dispatch!("hyperlattice_matrix", "method", "div-affine-orthonormal4");
14833 let [[r00, r01, r02], [r10, r11, r12], [r20, r21, r22]] = linear;
14834 let [tx, ty, tz] = translation;
14835 let it0 = Real::zero() - affine_translation_dot3([&r00, &r10, &r20], [&tx, &ty, &tz]);
14836 let it1 = Real::zero() - affine_translation_dot3([&r01, &r11, &r21], [&tx, &ty, &tz]);
14837 let it2 = Real::zero() - affine_translation_dot3([&r02, &r12, &r22], [&tx, &ty, &tz]);
14838 let inv_translation = [&it0, &it1, &it2];
14839 let result = self.0.map(|row| {
14840 let [a0, a1, a2, a3] = row;
14841 let c0 = Real::active_linear_combination3([&a0, &a1, &a2], [&r00, &r01, &r02]);
14842 let c1 = Real::active_linear_combination3([&a0, &a1, &a2], [&r10, &r11, &r12]);
14843 let c2 = Real::active_linear_combination3([&a0, &a1, &a2], [&r20, &r21, &r22]);
14844 let c3 = affine_translation_dot3([&a0, &a1, &a2], inv_translation) + a3;
14845 [c0, c1, c2, c3]
14846 });
14847 Self(result)
14848 }
14849
14850 pub fn signed_permutation(rows: [SignedAxis4; 4]) -> Self {
14856 crate::trace_dispatch!("hyperlattice_matrix", "constructor", "signed-permutation4");
14857 let [r0, r1, r2, r3] = rows;
14858 let mut matrix = [
14859 [Real::zero(), Real::zero(), Real::zero(), Real::zero()],
14860 [Real::zero(), Real::zero(), Real::zero(), Real::zero()],
14861 [Real::zero(), Real::zero(), Real::zero(), Real::zero()],
14862 [Real::zero(), Real::zero(), Real::zero(), Real::zero()],
14863 ];
14864 matrix[0][r0.index()] = signed_axis4_scalar(r0);
14865 matrix[1][r1.index()] = signed_axis4_scalar(r1);
14866 matrix[2][r2.index()] = signed_axis4_scalar(r2);
14867 matrix[3][r3.index()] = signed_axis4_scalar(r3);
14868 Self(matrix)
14869 }
14870
14871 pub fn signed_permutation_inverse(rows: [SignedAxis4; 4]) -> Self {
14873 crate::trace_dispatch!(
14874 "hyperlattice_matrix",
14875 "constructor",
14876 "signed-permutation4-inverse"
14877 );
14878 let [r0, r1, r2, r3] = rows;
14879 let mut matrix = [
14880 [Real::zero(), Real::zero(), Real::zero(), Real::zero()],
14881 [Real::zero(), Real::zero(), Real::zero(), Real::zero()],
14882 [Real::zero(), Real::zero(), Real::zero(), Real::zero()],
14883 [Real::zero(), Real::zero(), Real::zero(), Real::zero()],
14884 ];
14885 matrix[r0.index()][0] = signed_axis4_scalar(r0);
14886 matrix[r1.index()][1] = signed_axis4_scalar(r1);
14887 matrix[r2.index()][2] = signed_axis4_scalar(r2);
14888 matrix[r3.index()][3] = signed_axis4_scalar(r3);
14889 Self(matrix)
14890 }
14891
14892 pub fn div_signed_permutation(self, rows: [SignedAxis4; 4]) -> Self {
14894 crate::trace_dispatch!("hyperlattice_matrix", "method", "div-signed-permutation4");
14895 let [r0, r1, r2, r3] = rows;
14896 Self(self.0.map(|row| {
14897 [
14898 signed_axis4_apply(row[r0.index()].clone(), r0),
14899 signed_axis4_apply(row[r1.index()].clone(), r1),
14900 signed_axis4_apply(row[r2.index()].clone(), r2),
14901 signed_axis4_apply(row[r3.index()].clone(), r3),
14902 ]
14903 }))
14904 }
14905
14906 pub fn transform_signed_permutation_vector(rows: [SignedAxis4; 4], rhs: &Vector4) -> Vector4 {
14908 crate::trace_dispatch!(
14909 "hyperlattice_matrix",
14910 "method",
14911 "transform-signed-permutation4-vector"
14912 );
14913 let [r0, r1, r2, r3] = rows;
14914 Vector4([
14915 signed_axis4_apply(rhs.0[r0.index()].clone(), r0),
14916 signed_axis4_apply(rhs.0[r1.index()].clone(), r1),
14917 signed_axis4_apply(rhs.0[r2.index()].clone(), r2),
14918 signed_axis4_apply(rhs.0[r3.index()].clone(), r3),
14919 ])
14920 }
14921
14922 pub fn transform_signed_permutation_batch(
14924 rows: [SignedAxis4; 4],
14925 rhs: &[Vector4],
14926 ) -> Vec<Vector4> {
14927 crate::trace_dispatch!(
14928 "hyperlattice_matrix",
14929 "method",
14930 "transform-signed-permutation4-batch"
14931 );
14932 let [r0, r1, r2, r3] = rows;
14933 rhs.iter()
14934 .map(|vector| {
14935 Vector4([
14936 signed_axis4_apply(vector.0[r0.index()].clone(), r0),
14937 signed_axis4_apply(vector.0[r1.index()].clone(), r1),
14938 signed_axis4_apply(vector.0[r2.index()].clone(), r2),
14939 signed_axis4_apply(vector.0[r3.index()].clone(), r3),
14940 ])
14941 })
14942 .collect()
14943 }
14944
14945 pub fn diagonal(diagonal: [Real; 4]) -> Self {
14947 crate::trace_dispatch!("hyperlattice_matrix", "constructor", "diagonal");
14948 let [d0, d1, d2, d3] = diagonal;
14949 Self([
14950 [d0, Real::zero(), Real::zero(), Real::zero()],
14951 [Real::zero(), d1, Real::zero(), Real::zero()],
14952 [Real::zero(), Real::zero(), d2, Real::zero()],
14953 [Real::zero(), Real::zero(), Real::zero(), d3],
14954 ])
14955 }
14956
14957 pub fn diagonal_inverse(diagonal: [Real; 4]) -> BlasResult<Self> {
14969 crate::trace_dispatch!("hyperlattice_matrix", "constructor", "diagonal-inverse");
14970 let [d0, d1, d2, d3] = diagonal;
14971 Ok(Self::diagonal([
14972 d0.inverse()?,
14973 d1.inverse()?,
14974 d2.inverse()?,
14975 d3.inverse()?,
14976 ]))
14977 }
14978
14979 pub fn div_diagonal(self, diagonal: [Real; 4]) -> BlasResult<Self> {
14992 crate::trace_dispatch!("hyperlattice_matrix", "method", "div-diagonal");
14993 let [
14994 [a00, a01, a02, a03],
14995 [a10, a11, a12, a13],
14996 [a20, a21, a22, a23],
14997 [a30, a31, a32, a33],
14998 ] = self.0;
14999 let [d0, d1, d2, d3] = diagonal;
15000 let inv0 = d0.inverse()?;
15001 let inv1 = d1.inverse()?;
15002 let inv2 = d2.inverse()?;
15003 let inv3 = d3.inverse()?;
15004 Ok(Self([
15005 [
15006 a00.mul_cached(&inv0),
15007 a01.mul_cached(&inv1),
15008 a02.mul_cached(&inv2),
15009 a03.mul_cached(&inv3),
15010 ],
15011 [
15012 a10.mul_cached(&inv0),
15013 a11.mul_cached(&inv1),
15014 a12.mul_cached(&inv2),
15015 a13.mul_cached(&inv3),
15016 ],
15017 [
15018 a20.mul_cached(&inv0),
15019 a21.mul_cached(&inv1),
15020 a22.mul_cached(&inv2),
15021 a23.mul_cached(&inv3),
15022 ],
15023 [
15024 a30.mul_cached(&inv0),
15025 a31.mul_cached(&inv1),
15026 a32.mul_cached(&inv2),
15027 a33.mul_cached(&inv3),
15028 ],
15029 ]))
15030 }
15031
15032 pub fn upper_triangular_inverse(self) -> BlasResult<Self> {
15034 crate::trace_dispatch!("hyperlattice_matrix", "method", "upper-triangular4-inverse");
15035 Ok(Self(invert_matrix4_by_upper_triangular(&self.0)?))
15036 }
15037
15038 pub fn upper_triangular_inverse_checked(self) -> CheckedBlasResult<Self> {
15040 crate::trace_dispatch!(
15041 "hyperlattice_matrix",
15042 "method",
15043 "upper-triangular4-inverse-checked"
15044 );
15045 Ok(Self(invert_matrix4_by_upper_triangular_checked(&self.0)?))
15046 }
15047
15048 pub fn upper_triangular_inverse_checked_with_abort(
15050 self,
15051 signal: &AbortSignal,
15052 ) -> CheckedBlasResult<Self> {
15053 crate::trace_dispatch!(
15054 "hyperlattice_matrix",
15055 "method",
15056 "upper-triangular4-inverse-checked-with-abort"
15057 );
15058 Ok(Self(invert_matrix4_by_upper_triangular_checked_with_abort(
15059 &self.0, signal,
15060 )?))
15061 }
15062
15063 pub fn lower_triangular_inverse(self) -> BlasResult<Self> {
15065 crate::trace_dispatch!("hyperlattice_matrix", "method", "lower-triangular4-inverse");
15066 Ok(Self(invert_matrix4_by_lower_triangular(&self.0)?))
15067 }
15068
15069 pub fn lower_triangular_inverse_checked(self) -> CheckedBlasResult<Self> {
15071 crate::trace_dispatch!(
15072 "hyperlattice_matrix",
15073 "method",
15074 "lower-triangular4-inverse-checked"
15075 );
15076 Ok(Self(invert_matrix4_by_lower_triangular_checked(&self.0)?))
15077 }
15078
15079 pub fn lower_triangular_inverse_checked_with_abort(
15081 self,
15082 signal: &AbortSignal,
15083 ) -> CheckedBlasResult<Self> {
15084 crate::trace_dispatch!(
15085 "hyperlattice_matrix",
15086 "method",
15087 "lower-triangular4-inverse-checked-with-abort"
15088 );
15089 Ok(Self(invert_matrix4_by_lower_triangular_checked_with_abort(
15090 &self.0, signal,
15091 )?))
15092 }
15093
15094 pub fn div_upper_triangular(self, divisor: Self) -> BlasResult<Self> {
15096 crate::trace_dispatch!("hyperlattice_matrix", "method", "div-upper-triangular4");
15097 Ok(Self(divide_matrix4_by_upper_triangular(
15098 self.0, &divisor.0,
15099 )?))
15100 }
15101
15102 pub fn div_upper_triangular_checked(self, divisor: Self) -> CheckedBlasResult<Self> {
15104 crate::trace_dispatch!(
15105 "hyperlattice_matrix",
15106 "method",
15107 "div-upper-triangular4-checked"
15108 );
15109 Ok(Self(divide_matrix4_by_upper_triangular_checked(
15110 self.0, &divisor.0,
15111 )?))
15112 }
15113
15114 pub fn div_upper_triangular_checked_with_abort(
15116 self,
15117 divisor: Self,
15118 signal: &AbortSignal,
15119 ) -> CheckedBlasResult<Self> {
15120 crate::trace_dispatch!(
15121 "hyperlattice_matrix",
15122 "method",
15123 "div-upper-triangular4-checked-with-abort"
15124 );
15125 Ok(Self(divide_matrix4_by_upper_triangular_checked_with_abort(
15126 self.0, &divisor.0, signal,
15127 )?))
15128 }
15129
15130 pub fn div_lower_triangular(self, divisor: Self) -> BlasResult<Self> {
15132 crate::trace_dispatch!("hyperlattice_matrix", "method", "div-lower-triangular4");
15133 Ok(Self(divide_matrix4_by_lower_triangular(
15134 self.0, &divisor.0,
15135 )?))
15136 }
15137
15138 pub fn div_lower_triangular_checked(self, divisor: Self) -> CheckedBlasResult<Self> {
15140 crate::trace_dispatch!(
15141 "hyperlattice_matrix",
15142 "method",
15143 "div-lower-triangular4-checked"
15144 );
15145 Ok(Self(divide_matrix4_by_lower_triangular_checked(
15146 self.0, &divisor.0,
15147 )?))
15148 }
15149
15150 pub fn div_lower_triangular_checked_with_abort(
15152 self,
15153 divisor: Self,
15154 signal: &AbortSignal,
15155 ) -> CheckedBlasResult<Self> {
15156 crate::trace_dispatch!(
15157 "hyperlattice_matrix",
15158 "method",
15159 "div-lower-triangular4-checked-with-abort"
15160 );
15161 Ok(Self(divide_matrix4_by_lower_triangular_checked_with_abort(
15162 self.0, &divisor.0, signal,
15163 )?))
15164 }
15165
15166 pub fn div_diagonal_vector(&self, diagonal: [Real; 4], rhs: &Vector4) -> BlasResult<Vector4> {
15182 crate::trace_dispatch!("hyperlattice_matrix", "method", "div-diagonal4-vector");
15183 let [d0, d1, d2, d3] = diagonal;
15184 let vector_facts = rhs.geometric_facts();
15185 if matches!(vector_facts.homogeneous, Vector4HomogeneousKind::Direction) {
15186 let (inv0, inv1, inv2) = if d0 == d1 && d0 == d2 {
15192 crate::trace_dispatch!(
15193 "hyperlattice_matrix",
15194 "helper",
15195 "div-diagonal4-vector-direction-uniform-scale"
15196 );
15197 let inv = d0.inverse()?;
15198 (inv.clone(), inv.clone(), inv)
15199 } else {
15200 (d0.inverse()?, d1.inverse()?, d2.inverse()?)
15201 };
15202 let rhs_div = [
15203 rhs.0[0].clone().mul_cached(&inv0),
15204 rhs.0[1].clone().mul_cached(&inv1),
15205 rhs.0[2].clone().mul_cached(&inv2),
15206 Real::zero(),
15207 ];
15208 return Ok(Vector4(transform_vector4_rhs_direction_ref_cached(
15209 &self.0,
15210 &rhs_div,
15211 matrix4_direction_linear_is_diagonal(&self.0),
15212 )));
15213 }
15214
15215 let linear_uniform_scale = d0 == d1 && d0 == d2;
15216 let (inv0, inv1, inv2) = if linear_uniform_scale {
15217 crate::trace_dispatch!(
15218 "hyperlattice_matrix",
15219 "helper",
15220 "div-diagonal4-vector-linear-uniform-scale"
15221 );
15222 let inv = d0.inverse()?;
15223 (inv.clone(), inv.clone(), inv)
15224 } else {
15225 (d0.inverse()?, d1.inverse()?, d2.inverse()?)
15226 };
15227 let inv3_is_one = d3.definitely_one();
15232 let inv3 = if inv3_is_one {
15233 Real::one()
15234 } else {
15235 d3.inverse()?
15236 };
15237 let rhs_div_3_scale = if inv3_is_one {
15238 rhs.0[3].clone()
15239 } else if rhs.0[3].definitely_one() {
15240 inv3.clone()
15241 } else {
15242 rhs.0[3].clone().mul_cached(&inv3)
15243 };
15244
15245 let rhs_div_x = rhs.0[0].clone().mul_cached(&inv0);
15246 let rhs_div_y = rhs.0[1].clone().mul_cached(&inv1);
15247 let rhs_div_z = rhs.0[2].clone().mul_cached(&inv2);
15248
15249 match vector_facts.homogeneous {
15250 Vector4HomogeneousKind::Point => {
15251 let translation_is_zero = [
15252 self.0[0][3].definitely_zero(),
15253 self.0[1][3].definitely_zero(),
15254 self.0[2][3].definitely_zero(),
15255 self.0[3][3].definitely_zero(),
15256 ];
15257 let all_translation_zero = translation_is_zero.iter().all(|value| *value);
15258 let all_translation_nonzero = translation_is_zero.iter().all(|value| !*value);
15259 let rhs_div = [rhs_div_x, rhs_div_y, rhs_div_z, rhs_div_3_scale];
15267 return Ok(Vector4(
15268 transform_vector4_rhs_point_with_scaled_w_ref_cached(
15269 &self.0,
15270 &rhs_div,
15271 &translation_is_zero,
15272 all_translation_zero,
15273 all_translation_nonzero,
15274 inv3_is_one,
15275 &inv3,
15276 ),
15277 ));
15278 }
15279 Vector4HomogeneousKind::Direction => {
15280 let rhs_div = [rhs_div_x, rhs_div_y, rhs_div_z, Real::zero()];
15281 let direction_is_diagonal = matrix4_direction_linear_is_diagonal(&self.0);
15282 return Ok(Vector4(transform_vector4_rhs_direction_ref_cached(
15283 &self.0,
15284 &rhs_div,
15285 direction_is_diagonal,
15286 )));
15287 }
15288 Vector4HomogeneousKind::Unknown => {
15289 let matrix_facts = matrix4_facts(&self.0);
15290 let translation_is_zero = [
15291 matrix_facts.translation_xyz_zero[0],
15292 matrix_facts.translation_xyz_zero[1],
15293 matrix_facts.translation_xyz_zero[2],
15294 self.0[3][3].definitely_zero(),
15295 ];
15296 let all_translation_zero = translation_is_zero.iter().all(|value| *value);
15297 let all_translation_nonzero = translation_is_zero.iter().all(|value| !*value);
15298 let rhs_div = [rhs_div_x, rhs_div_y, rhs_div_z, rhs_div_3_scale];
15299 return Ok(Vector4(transform_vector4_rhs_ref_with_facts(
15300 &self.0,
15301 &rhs_div,
15302 &translation_is_zero,
15303 all_translation_zero,
15304 all_translation_nonzero,
15305 matrix_facts.direction_linear_is_diagonal,
15306 Some(matrix_facts),
15307 vector_facts,
15308 )));
15309 }
15310 };
15311 }
15312
15313 #[inline]
15323 pub fn div_diagonal_direction_vector(
15324 &self,
15325 diagonal: [Real; 4],
15326 rhs: &Vector4,
15327 ) -> BlasResult<Vector4> {
15328 crate::trace_dispatch!(
15329 "hyperlattice_matrix",
15330 "method",
15331 "div-diagonal4-vector-direction-only"
15332 );
15333 let [d0, d1, d2, _d3] = diagonal;
15334 let inv0 = d0.inverse()?;
15335 let inv1 = d1.inverse()?;
15336 let inv2 = d2.inverse()?;
15337 let rhs_div = [
15338 rhs.0[0].clone().mul_cached(&inv0),
15339 rhs.0[1].clone().mul_cached(&inv1),
15340 rhs.0[2].clone().mul_cached(&inv2),
15341 Real::zero(),
15342 ];
15343 Ok(Vector4(transform_vector4_rhs_direction_ref_cached(
15344 &self.0,
15345 &rhs_div,
15346 matrix4_direction_linear_is_diagonal(&self.0),
15347 )))
15348 }
15349
15350 pub fn prepare_right_divisor(&self) -> PreparedRightDivisor4<'_> {
15358 PreparedRightDivisor4::new(self)
15359 }
15360
15361 pub fn div_matrix_with_prepared(
15367 self,
15368 divisor: &mut PreparedRightDivisor4<'_>,
15369 ) -> BlasResult<Self> {
15370 crate::trace_dispatch!("hyperlattice_matrix", "method", "div-matrix-with-prepared");
15371 Ok(Self(divisor.divide(self.0)?))
15372 }
15373
15374 pub fn div_exact_rational_matrix_with_prepared(
15381 self,
15382 divisor: &mut PreparedRightDivisor4<'_>,
15383 ) -> BlasResult<Self> {
15384 crate::trace_dispatch!(
15385 "hyperlattice_matrix",
15386 "method",
15387 "div-exact-rational-matrix-with-prepared"
15388 );
15389 Ok(Self(divisor.divide_exact_rational_left(self.0)?))
15390 }
15391
15392 pub fn div_matrix_checked_with_prepared(
15397 self,
15398 divisor: &mut PreparedRightDivisor4<'_>,
15399 ) -> CheckedBlasResult<Self> {
15400 crate::trace_dispatch!(
15401 "hyperlattice_matrix",
15402 "method",
15403 "div-matrix-checked-with-prepared"
15404 );
15405 Ok(Self(divisor.divide_checked(self.0)?))
15406 }
15407
15408 pub fn div_matrix_checked_with_prepared_with_abort(
15410 self,
15411 divisor: &mut PreparedRightDivisor4<'_>,
15412 signal: &AbortSignal,
15413 ) -> CheckedBlasResult<Self> {
15414 crate::trace_dispatch!(
15415 "hyperlattice_matrix",
15416 "method",
15417 "div-matrix-checked-with-prepared-with-abort"
15418 );
15419 Ok(Self(divisor.divide_checked_with_abort(self.0, signal)?))
15420 }
15421
15422 pub fn uniform_scale(scale: Real) -> Self {
15424 crate::trace_dispatch!("hyperlattice_matrix", "constructor", "uniform-scale");
15425 Self([
15426 [scale.clone(), Real::zero(), Real::zero(), Real::zero()],
15427 [Real::zero(), scale.clone(), Real::zero(), Real::zero()],
15428 [Real::zero(), Real::zero(), scale.clone(), Real::zero()],
15429 [Real::zero(), Real::zero(), Real::zero(), scale],
15430 ])
15431 }
15432
15433 pub fn uniform_scale_inverse(scale: Real) -> BlasResult<Self> {
15445 crate::trace_dispatch!(
15446 "hyperlattice_matrix",
15447 "constructor",
15448 "uniform-scale-inverse"
15449 );
15450 let inv = scale.inverse()?;
15451 Ok(Self::uniform_scale(inv))
15452 }
15453
15454 pub fn transform_vec4_handle(&self) -> TransformedMatrix4<'_> {
15462 TransformedMatrix4::new(self)
15463 }
15464
15465 pub fn transform_vec4_with<'a>(&'a self, rhs: &'a Vector4) -> TransformedVector4<'a> {
15470 self.transform_vec4_handle().vector(rhs)
15471 }
15472
15473 pub fn transform_vec4_point(&self, rhs: &Vector4) -> Vector4 {
15477 if matrix4_affine_linear_is_diagonal(&self.0) {
15478 return Vector4(
15479 transform_vector4_rhs_point_affine_linear_diagonal_ref_cached(&self.0, &rhs.0),
15480 );
15481 }
15482 let facts = matrix4_facts(&self.0);
15483 TransformedMatrix4::new_with_facts(self, facts).transform_point_vector(rhs)
15489 }
15490
15491 pub fn transform_point3(&self, point: &Point3) -> BlasResult<Point3> {
15493 let transformed = self.transform_vec4_point(&Vector4::new([
15494 point.x.clone(),
15495 point.y.clone(),
15496 point.z.clone(),
15497 Real::one(),
15498 ]));
15499 let [x, y, z, w] = transformed.0;
15500 if w.definitely_one() {
15501 return Ok(Point3::new(x, y, z));
15502 }
15503 let inv_w = w.inverse()?;
15504 Ok(Point3::new(
15505 x.mul_cached(&inv_w),
15506 y.mul_cached(&inv_w),
15507 z.mul_cached(&inv_w),
15508 ))
15509 }
15510
15511 pub fn transform_direction3(&self, direction: &Vector3) -> Vector3 {
15513 let transformed = self.transform_vec4_direction(&Vector4::new([
15514 direction.0[0].clone(),
15515 direction.0[1].clone(),
15516 direction.0[2].clone(),
15517 Real::zero(),
15518 ]));
15519 let [x, y, z, _w] = transformed.0;
15520 Vector3::new([x, y, z])
15521 }
15522
15523 pub fn transform_vec4_direction(&self, rhs: &Vector4) -> Vector4 {
15526 if true {
15527 match matrix4_direction_linear_kind(&self.0) {
15528 Matrix4DirectionLinearKind::Identity => {
15529 crate::trace_dispatch!(
15530 "hyperlattice_matrix",
15531 "method",
15532 "transform-vector-vec4-direction-linear-identity"
15533 );
15534 return rhs.clone();
15535 }
15536 Matrix4DirectionLinearKind::Diagonal => {
15537 return Vector4(transform_vector4_rhs_direction_ref_cached(
15538 &self.0, &rhs.0, true,
15539 ));
15540 }
15541 Matrix4DirectionLinearKind::General => {
15542 return Vector4(transform_vector4_rhs_direction_ref_cached(
15543 &self.0, &rhs.0, false,
15544 ));
15545 }
15546 }
15547 }
15548 Vector4(transform_vector4_rhs_direction_ref_cached(
15549 &self.0,
15550 &rhs.0,
15551 matrix4_direction_linear_is_diagonal(&self.0),
15552 ))
15553 }
15554
15555 pub fn transform_vec4_direction_batch(&self, rhs: &[Vector4]) -> Vec<Vector4> {
15561 crate::trace_dispatch!(
15562 "hyperlattice_matrix",
15563 "method",
15564 "transform-vector-vec4-direction-batch"
15565 );
15566 transform_vector4_direction_batch_assumed_ref(
15575 &self.0,
15576 rhs,
15577 matrix4_direction_linear_is_diagonal(&self.0),
15578 )
15579 }
15580
15581 pub fn transform_vec4_point_batch(&self, rhs: &[Vector4]) -> Vec<Vector4> {
15587 crate::trace_dispatch!(
15588 "hyperlattice_matrix",
15589 "method",
15590 "transform-vector-vec4-point-batch"
15591 );
15592 self.transform_vec4_handle().transform_point_batch(rhs)
15598 }
15599
15600 pub fn transform_vec4_batch(&self, rhs: &[Vector4]) -> Vec<Vector4> {
15609 crate::trace_dispatch!(
15610 "hyperlattice_matrix",
15611 "method",
15612 "transform-vector-vec4-batch"
15613 );
15614 self.transform_vec4_handle().transform_vector_batch(rhs)
15615 }
15616
15617 pub fn inverse(self) -> BlasResult<Self> {
15622 crate::trace_dispatch!("hyperlattice_matrix", "method", "matrix4-inverse");
15623 Ok(Self(invert_matrix4(self.0)?))
15624 }
15625
15626 pub fn inverse_checked(self) -> CheckedBlasResult<Self> {
15628 crate::trace_dispatch!("hyperlattice_matrix", "method", "matrix4-inverse-checked");
15629 Ok(Self(invert_matrix4_checked(self.0)?))
15630 }
15631
15632 pub fn inverse_checked_with_abort(self, signal: &AbortSignal) -> CheckedBlasResult<Self> {
15634 crate::trace_dispatch!(
15635 "hyperlattice_matrix",
15636 "method",
15637 "matrix4-inverse-checked-with-abort"
15638 );
15639 Ok(Self(invert_matrix4_checked_with_abort(self.0, signal)?))
15640 }
15641
15642 pub fn determinant(&self) -> Real {
15644 crate::trace_dispatch!("hyperlattice_matrix", "method", "matrix4-determinant");
15645 determinant4(&self.0)
15646 }
15647}