use std::array::from_fn;
use std::fmt;
use std::mem;
use std::ops::{Add, BitXor, Div, Index, IndexMut, Mul, Neg, Sub};
use crate::point::Point3;
use crate::scalar::{
clone_with_abort, reject_definite_zero, require_known_nonzero,
require_known_nonzero_with_abort, with_abort, zero_status, zero_status_with_abort,
};
use crate::vector::{Vector3, Vector4, Vector4GeometricFacts, Vector4HomogeneousKind};
use crate::{
AbortSignal, BlasResult, CheckedBlasResult, ExactRationalKind, ExactRealSetFacts, Problem,
Real, RealKernelExt, RealSign, RealSymbolicDependencyMask, RealZeroOneMinusOneStatus,
ZeroStatus,
};
fn identity_array<const N: usize>() -> [[Real; N]; N] {
from_fn(|row| {
from_fn(|col| {
if row == col {
Real::one()
} else {
Real::zero()
}
})
})
}
fn transpose_array3(matrix: [[Real; 3]; 3]) -> [[Real; 3]; 3] {
let [[m00, m01, m02], [m10, m11, m12], [m20, m21, m22]] = matrix;
[[m00, m10, m20], [m01, m11, m21], [m02, m12, m22]]
}
fn transpose_array3_ref(matrix: &[[Real; 3]; 3]) -> [[Real; 3]; 3] {
[
[
matrix[0][0].clone(),
matrix[1][0].clone(),
matrix[2][0].clone(),
],
[
matrix[0][1].clone(),
matrix[1][1].clone(),
matrix[2][1].clone(),
],
[
matrix[0][2].clone(),
matrix[1][2].clone(),
matrix[2][2].clone(),
],
]
}
fn transpose_array4(matrix: [[Real; 4]; 4]) -> [[Real; 4]; 4] {
let [
[m00, m01, m02, m03],
[m10, m11, m12, m13],
[m20, m21, m22, m23],
[m30, m31, m32, m33],
] = matrix;
[
[m00, m10, m20, m30],
[m01, m11, m21, m31],
[m02, m12, m22, m32],
[m03, m13, m23, m33],
]
}
fn transpose_array4_ref(matrix: &[[Real; 4]; 4]) -> [[Real; 4]; 4] {
[
[
matrix[0][0].clone(),
matrix[1][0].clone(),
matrix[2][0].clone(),
matrix[3][0].clone(),
],
[
matrix[0][1].clone(),
matrix[1][1].clone(),
matrix[2][1].clone(),
matrix[3][1].clone(),
],
[
matrix[0][2].clone(),
matrix[1][2].clone(),
matrix[2][2].clone(),
matrix[3][2].clone(),
],
[
matrix[0][3].clone(),
matrix[1][3].clone(),
matrix[2][3].clone(),
matrix[3][3].clone(),
],
]
}
#[inline]
fn matrix_mask<const N: usize>() -> u16 {
debug_assert!(N * N <= u16::BITS as usize);
if N * N == u16::BITS as usize {
u16::MAX
} else {
(1_u16 << (N * N)) - 1
}
}
#[inline]
fn matrix_entry_bit<const N: usize>(row: usize, column: usize) -> u16 {
1_u16 << (row * N + column)
}
#[inline]
fn matrix_entry_mask_value<const N: usize>(mask: u16, row: usize, column: usize) -> Option<bool> {
if row < N && column < N {
Some((mask & matrix_entry_bit::<N>(row, column)) != 0)
} else {
None
}
}
#[inline]
fn matrix_lane_known_zero_count<const N: usize>(mask: u8) -> u32 {
debug_assert!(N <= u8::BITS as usize);
(mask & ((1_u8 << N) - 1)).count_ones()
}
#[inline]
fn matrix_lane_has_sparse_support<const N: usize>(mask: u8) -> bool {
matrix_lane_known_zero_count::<N>(mask) >= (N as u32).saturating_sub(1)
}
#[inline]
fn matrix_lane_is_known_zero<const N: usize>(mask: u8) -> bool {
matrix_lane_known_zero_count::<N>(mask) == N as u32
}
#[inline]
fn matrix_has_zero_lane<const N: usize>(masks: [u8; N]) -> bool {
masks.into_iter().any(matrix_lane_is_known_zero::<N>)
}
#[inline]
fn matrix_determinant_schedule_hint<const N: usize>(
exact: ExactRealSetFacts,
row_zero_masks: [u8; N],
column_zero_masks: [u8; N],
is_diagonal: bool,
is_upper_triangular: bool,
is_lower_triangular: bool,
) -> MatrixDeterminantScheduleHint {
if matrix_has_zero_lane::<N>(row_zero_masks) || matrix_has_zero_lane::<N>(column_zero_masks) {
return MatrixDeterminantScheduleHint::StructurallyZero;
}
if is_diagonal {
return MatrixDeterminantScheduleHint::Diagonal;
}
if is_upper_triangular || is_lower_triangular {
return MatrixDeterminantScheduleHint::Triangular;
}
if row_zero_masks
.into_iter()
.all(matrix_lane_has_sparse_support::<N>)
|| column_zero_masks
.into_iter()
.all(matrix_lane_has_sparse_support::<N>)
{
return MatrixDeterminantScheduleHint::SparseSupport;
}
if exact.has_shared_denominator_schedule() {
return MatrixDeterminantScheduleHint::SharedDenominator;
}
if exact.has_dyadic_schedule() {
return MatrixDeterminantScheduleHint::Dyadic;
}
if exact.is_nonempty_exact_rational() {
return MatrixDeterminantScheduleHint::ExactRational;
}
MatrixDeterminantScheduleHint::GenericRealFallback
}
#[inline]
fn matrix_zero_masks<const N: usize>(matrix: &[[Real; N]; N]) -> (u16, [u8; N], [u8; N]) {
let mut entry_mask = 0_u16;
let mut row_masks = [0_u8; N];
let mut column_masks = [0_u8; N];
for row in 0..N {
for column in 0..N {
if matrix[row][column].definitely_zero() {
entry_mask |= matrix_entry_bit::<N>(row, column);
row_masks[row] |= 1_u8 << column;
column_masks[column] |= 1_u8 << row;
}
}
}
(entry_mask, row_masks, column_masks)
}
#[inline]
fn matrix_one_mask<const N: usize>(matrix: &[[Real; N]; N]) -> u16 {
let mut mask = 0_u16;
for row in 0..N {
for column in 0..N {
if matrix[row][column].definitely_one() {
mask |= matrix_entry_bit::<N>(row, column);
}
}
}
mask
}
#[inline]
fn matrix_zero_masks_assuming_size<const N: usize, const M: usize>(
matrix: &[[Real; N]; N],
) -> (u16, [u8; M], [u8; M]) {
debug_assert_eq!(N, M);
let mut entry_mask = 0_u16;
let mut row_masks = [0_u8; M];
let mut column_masks = [0_u8; M];
for row in 0..M {
for column in 0..M {
if matrix[row][column].definitely_zero() {
entry_mask |= matrix_entry_bit::<M>(row, column);
row_masks[row] |= 1_u8 << column;
column_masks[column] |= 1_u8 << row;
}
}
}
(entry_mask, row_masks, column_masks)
}
#[inline]
fn matrix_one_mask_assuming_size<const N: usize, const M: usize>(matrix: &[[Real; N]; N]) -> u16 {
debug_assert_eq!(N, M);
let mut mask = 0_u16;
for row in 0..M {
for column in 0..M {
if matrix[row][column].definitely_one() {
mask |= matrix_entry_bit::<M>(row, column);
}
}
}
mask
}
#[inline]
fn matrix_symbolic_dependency_mask<const N: usize>(
matrix: &[[Real; N]; N],
) -> RealSymbolicDependencyMask {
matrix
.iter()
.flat_map(|row| row.iter())
.fold(RealSymbolicDependencyMask::NONE, |mask, value| {
mask.union(value.detailed_facts().symbolic.dependencies)
})
}
#[inline]
fn matrix_symbolic_dependency_mask_assuming_size<const N: usize, const M: usize>(
matrix: &[[Real; N]; N],
) -> RealSymbolicDependencyMask {
debug_assert_eq!(N, M);
let mut mask = RealSymbolicDependencyMask::NONE;
for row in 0..M {
for column in 0..M {
mask = mask.union(matrix[row][column].detailed_facts().symbolic.dependencies);
}
}
mask
}
#[inline]
fn matrix4_signed_permutation_rows(matrix: &[[Real; 4]; 4]) -> Option<[SignedAxis4; 4]> {
let rows = [
matrix4_signed_axis_row(&matrix[0])?,
matrix4_signed_axis_row(&matrix[1])?,
matrix4_signed_axis_row(&matrix[2])?,
matrix4_signed_axis_row(&matrix[3])?,
];
let mut used_columns = 0_u8;
for axis in rows {
let bit = 1_u8 << axis.index();
if used_columns & bit != 0 {
return None;
}
used_columns |= bit;
}
(used_columns == 0b1111).then_some(rows)
}
#[inline]
fn matrix4_signed_permutation_rows_assuming_size<const N: usize>(
matrix: &[[Real; N]; N],
) -> Option<[SignedAxis4; 4]> {
debug_assert_eq!(N, 4);
let rows = [
matrix4_signed_axis_row_refs([&matrix[0][0], &matrix[0][1], &matrix[0][2], &matrix[0][3]])?,
matrix4_signed_axis_row_refs([&matrix[1][0], &matrix[1][1], &matrix[1][2], &matrix[1][3]])?,
matrix4_signed_axis_row_refs([&matrix[2][0], &matrix[2][1], &matrix[2][2], &matrix[2][3]])?,
matrix4_signed_axis_row_refs([&matrix[3][0], &matrix[3][1], &matrix[3][2], &matrix[3][3]])?,
];
let mut used_columns = 0_u8;
for axis in rows {
let bit = 1_u8 << axis.index();
if used_columns & bit != 0 {
return None;
}
used_columns |= bit;
}
(used_columns == 0b1111).then_some(rows)
}
#[inline]
fn matrix3_exact_rational_uniform_scale(matrix: &[[Real; 3]; 3], is_diagonal: bool) -> bool {
if !is_diagonal {
return false;
}
exact_rational_diagonal_entries_equal([&matrix[0][0], &matrix[1][1], &matrix[2][2]])
}
#[inline]
fn matrix4_exact_rational_uniform_scale(matrix: &[[Real; 4]; 4], is_diagonal: bool) -> bool {
if !is_diagonal {
return false;
}
exact_rational_diagonal_entries_equal([
&matrix[0][0],
&matrix[1][1],
&matrix[2][2],
&matrix[3][3],
])
}
#[inline]
fn matrix3_exact_rational_uniform_scale_assuming_size<const N: usize>(
matrix: &[[Real; N]; N],
is_diagonal: bool,
) -> bool {
debug_assert_eq!(N, 3);
if !is_diagonal {
return false;
}
exact_rational_diagonal_entries_equal([&matrix[0][0], &matrix[1][1], &matrix[2][2]])
}
#[inline]
fn matrix4_exact_rational_uniform_scale_assuming_size<const N: usize>(
matrix: &[[Real; N]; N],
is_diagonal: bool,
) -> bool {
debug_assert_eq!(N, 4);
if !is_diagonal {
return false;
}
exact_rational_diagonal_entries_equal([
&matrix[0][0],
&matrix[1][1],
&matrix[2][2],
&matrix[3][3],
])
}
#[inline]
fn exact_rational_diagonal_entries_equal<const N: usize>(entries: [&Real; N]) -> bool {
let Some(first) = entries[0].exact_rational_ref() else {
return false;
};
entries[1..]
.iter()
.all(|entry| entry.exact_rational_ref() == Some(first))
}
#[inline]
fn matrix4_signed_axis_row(row: &[Real; 4]) -> Option<SignedAxis4> {
matrix4_signed_axis_row_refs([&row[0], &row[1], &row[2], &row[3]])
}
#[inline]
fn matrix4_signed_axis_row_refs(row: [&Real; 4]) -> Option<SignedAxis4> {
let mut axis = None;
for (index, value) in row.into_iter().enumerate() {
let status = value.zero_one_or_minus_one();
match status {
RealZeroOneMinusOneStatus::Zero => {}
RealZeroOneMinusOneStatus::One | RealZeroOneMinusOneStatus::MinusOne
if axis.is_none() =>
{
axis = Some(signed_axis4_from_index(
index,
matches!(status, RealZeroOneMinusOneStatus::MinusOne),
)?);
}
_ => return None,
}
}
axis
}
#[inline]
fn signed_axis4_from_index(index: usize, negative: bool) -> Option<SignedAxis4> {
match (index, negative) {
(0, false) => Some(SignedAxis4::PosX),
(0, true) => Some(SignedAxis4::NegX),
(1, false) => Some(SignedAxis4::PosY),
(1, true) => Some(SignedAxis4::NegY),
(2, false) => Some(SignedAxis4::PosZ),
(2, true) => Some(SignedAxis4::NegZ),
(3, false) => Some(SignedAxis4::PosW),
(3, true) => Some(SignedAxis4::NegW),
_ => None,
}
}
#[derive(Clone, Debug, PartialEq)]
pub struct Matrix3(
pub [[Real; 3]; 3],
);
#[derive(Clone, Debug, PartialEq)]
pub struct Matrix4(
pub [[Real; 4]; 4],
);
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum MatrixDeterminantScheduleHint {
StructurallyZero,
Diagonal,
Triangular,
SparseSupport,
SharedDenominator,
Dyadic,
ExactRational,
GenericRealFallback,
}
impl MatrixDeterminantScheduleHint {
pub fn is_shape_driven(self) -> bool {
matches!(
self,
Self::StructurallyZero | Self::Diagonal | Self::Triangular | Self::SparseSupport
)
}
pub fn is_exact_rational_driven(self) -> bool {
matches!(
self,
Self::SharedDenominator | Self::Dyadic | Self::ExactRational
)
}
pub fn requires_generic_real_fallback(self) -> bool {
matches!(self, Self::GenericRealFallback)
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum Matrix3TransformKind {
Identity,
AffineTranslation,
AffineDiagonalLinear,
Affine,
Projective,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum Matrix4TransformKind {
Identity,
SignedPermutation,
AffineTranslation,
AffineDiagonalLinear,
Affine,
Projective,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct Matrix3StructuralFacts {
pub exact: ExactRealSetFacts,
pub symbolic_dependencies: RealSymbolicDependencyMask,
pub zero_mask: u16,
pub one_mask: u16,
pub row_zero_masks: [u8; 3],
pub column_zero_masks: [u8; 3],
pub is_identity: bool,
pub is_diagonal: bool,
pub is_exact_rational_uniform_scale: bool,
pub is_upper_triangular: bool,
pub is_lower_triangular: bool,
pub is_affine: bool,
pub is_affine_translation: bool,
pub transform_kind: Matrix3TransformKind,
}
impl Matrix3StructuralFacts {
pub fn is_zero(self) -> bool {
self.zero_mask == matrix_mask::<3>()
}
pub fn entry_known_zero(self, row: usize, column: usize) -> Option<bool> {
matrix_entry_mask_value::<3>(self.zero_mask, row, column)
}
pub fn entry_known_one(self, row: usize, column: usize) -> Option<bool> {
matrix_entry_mask_value::<3>(self.one_mask, row, column)
}
pub fn row_zero_mask(self, row: usize) -> Option<u8> {
self.row_zero_masks.get(row).copied()
}
pub fn column_zero_mask(self, column: usize) -> Option<u8> {
self.column_zero_masks.get(column).copied()
}
pub fn row_known_zero_count(self, row: usize) -> Option<u32> {
self.row_zero_mask(row)
.map(matrix_lane_known_zero_count::<3>)
}
pub fn column_known_zero_count(self, column: usize) -> Option<u32> {
self.column_zero_mask(column)
.map(matrix_lane_known_zero_count::<3>)
}
pub fn row_is_known_zero(self, row: usize) -> Option<bool> {
self.row_zero_mask(row).map(matrix_lane_is_known_zero::<3>)
}
pub fn column_is_known_zero(self, column: usize) -> Option<bool> {
self.column_zero_mask(column)
.map(matrix_lane_is_known_zero::<3>)
}
pub fn has_known_zero_row(self) -> bool {
self.row_zero_masks
.into_iter()
.any(matrix_lane_is_known_zero::<3>)
}
pub fn has_known_zero_column(self) -> bool {
self.column_zero_masks
.into_iter()
.any(matrix_lane_is_known_zero::<3>)
}
pub fn has_known_zero_lane(self) -> bool {
self.has_known_zero_row() || self.has_known_zero_column()
}
pub fn row_has_sparse_support(self, row: usize) -> Option<bool> {
self.row_zero_mask(row)
.map(matrix_lane_has_sparse_support::<3>)
}
pub fn column_has_sparse_support(self, column: usize) -> Option<bool> {
self.column_zero_mask(column)
.map(matrix_lane_has_sparse_support::<3>)
}
pub fn all_rows_have_sparse_support(self) -> bool {
self.row_zero_masks
.into_iter()
.all(matrix_lane_has_sparse_support::<3>)
}
pub fn all_columns_have_sparse_support(self) -> bool {
self.column_zero_masks
.into_iter()
.all(matrix_lane_has_sparse_support::<3>)
}
pub fn determinant_schedule_hint(self) -> MatrixDeterminantScheduleHint {
matrix_determinant_schedule_hint::<3>(
self.exact,
self.row_zero_masks,
self.column_zero_masks,
self.is_diagonal,
self.is_upper_triangular,
self.is_lower_triangular,
)
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct Matrix4StructuralFacts {
pub exact: ExactRealSetFacts,
pub symbolic_dependencies: RealSymbolicDependencyMask,
pub zero_mask: u16,
pub one_mask: u16,
pub row_zero_masks: [u8; 4],
pub column_zero_masks: [u8; 4],
pub is_identity: bool,
pub is_diagonal: bool,
pub is_exact_rational_uniform_scale: bool,
pub is_upper_triangular: bool,
pub is_lower_triangular: bool,
pub is_affine: bool,
pub is_affine_translation: bool,
pub linear_is_diagonal: bool,
pub direction_linear_is_diagonal: bool,
pub signed_permutation_rows: Option<[SignedAxis4; 4]>,
pub translation_xyz_zero: [bool; 3],
pub transform_kind: Matrix4TransformKind,
}
impl Matrix4StructuralFacts {
pub fn is_zero(self) -> bool {
self.zero_mask == matrix_mask::<4>()
}
pub fn is_signed_permutation(self) -> bool {
self.signed_permutation_rows.is_some()
}
pub fn entry_known_zero(self, row: usize, column: usize) -> Option<bool> {
matrix_entry_mask_value::<4>(self.zero_mask, row, column)
}
pub fn entry_known_one(self, row: usize, column: usize) -> Option<bool> {
matrix_entry_mask_value::<4>(self.one_mask, row, column)
}
pub fn row_zero_mask(self, row: usize) -> Option<u8> {
self.row_zero_masks.get(row).copied()
}
pub fn column_zero_mask(self, column: usize) -> Option<u8> {
self.column_zero_masks.get(column).copied()
}
pub fn row_known_zero_count(self, row: usize) -> Option<u32> {
self.row_zero_mask(row)
.map(matrix_lane_known_zero_count::<4>)
}
pub fn column_known_zero_count(self, column: usize) -> Option<u32> {
self.column_zero_mask(column)
.map(matrix_lane_known_zero_count::<4>)
}
pub fn row_is_known_zero(self, row: usize) -> Option<bool> {
self.row_zero_mask(row).map(matrix_lane_is_known_zero::<4>)
}
pub fn column_is_known_zero(self, column: usize) -> Option<bool> {
self.column_zero_mask(column)
.map(matrix_lane_is_known_zero::<4>)
}
pub fn has_known_zero_row(self) -> bool {
self.row_zero_masks
.into_iter()
.any(matrix_lane_is_known_zero::<4>)
}
pub fn has_known_zero_column(self) -> bool {
self.column_zero_masks
.into_iter()
.any(matrix_lane_is_known_zero::<4>)
}
pub fn has_known_zero_lane(self) -> bool {
self.has_known_zero_row() || self.has_known_zero_column()
}
pub fn row_has_sparse_support(self, row: usize) -> Option<bool> {
self.row_zero_mask(row)
.map(matrix_lane_has_sparse_support::<4>)
}
pub fn column_has_sparse_support(self, column: usize) -> Option<bool> {
self.column_zero_mask(column)
.map(matrix_lane_has_sparse_support::<4>)
}
pub fn all_rows_have_sparse_support(self) -> bool {
self.row_zero_masks
.into_iter()
.all(matrix_lane_has_sparse_support::<4>)
}
pub fn all_columns_have_sparse_support(self) -> bool {
self.column_zero_masks
.into_iter()
.all(matrix_lane_has_sparse_support::<4>)
}
pub fn determinant_schedule_hint(self) -> MatrixDeterminantScheduleHint {
matrix_determinant_schedule_hint::<4>(
self.exact,
self.row_zero_masks,
self.column_zero_masks,
self.is_diagonal,
self.is_upper_triangular,
self.is_lower_triangular,
)
}
}
#[derive(Debug, Clone)]
pub struct PreparedMatrix3<'a> {
right_divisor: PreparedRightDivisor3<'a>,
}
#[derive(Debug, Clone)]
pub struct PreparedMatrix4<'a> {
right_divisor: PreparedRightDivisor4<'a>,
}
#[derive(Debug, Clone)]
pub struct PreparedRightDivisor3<'a> {
divisor: &'a Matrix3,
facts: Matrix3Facts,
right_exact_rational_kind: ExactRationalKind,
is_definitely_dense_for_inverse: bool,
adjugate: Option<[[Real; 3]; 3]>,
determinant: Option<Real>,
reciprocal_determinant: Option<Real>,
inverse: Option<Matrix3>,
}
#[derive(Debug, Clone)]
pub struct PreparedRightDivisor4<'a> {
divisor: &'a Matrix4,
facts: Matrix4Facts,
right_exact_rational_kind: ExactRationalKind,
is_definitely_dense_for_inverse: bool,
factors: Option<([Real; 6], [Real; 6])>,
adjugate: Option<[[Real; 4]; 4]>,
determinant: Option<Real>,
reciprocal_determinant: Option<Real>,
inverse: Option<Matrix4>,
}
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
pub struct MatrixPreparedCacheState {
pub determinant: bool,
pub reciprocal_determinant: bool,
pub minor_factors: bool,
pub adjugate: bool,
pub inverse: bool,
}
impl MatrixPreparedCacheState {
pub const fn is_cold(self) -> bool {
!self.determinant
&& !self.reciprocal_determinant
&& !self.minor_factors
&& !self.adjugate
&& !self.inverse
}
pub const fn is_warm(self) -> bool {
!self.is_cold()
}
pub const fn has_determinant_scale(self) -> bool {
self.determinant && self.reciprocal_determinant
}
pub const fn has_shared_adjugate_path(self) -> bool {
self.adjugate && self.has_determinant_scale()
}
}
#[derive(Clone, Copy, Debug)]
struct Matrix3Facts {
public: Matrix3StructuralFacts,
exact: ExactRealSetFacts,
is_identity: bool,
is_diagonal: bool,
is_upper_triangular: bool,
is_lower_triangular: bool,
linear_is_diagonal: bool,
is_affine: bool,
is_affine_translation: bool,
}
#[inline]
fn combine_exact_rational_kind(
left: ExactRationalKind,
right: ExactRationalKind,
) -> ExactRationalKind {
use ExactRationalKind::{ExactDyadicRational, ExactRational, NonRational};
match (left, right) {
(NonRational, _) | (_, NonRational) => NonRational,
(ExactRational, _) | (_, ExactRational) => ExactRational,
(ExactDyadicRational, ExactDyadicRational) => ExactDyadicRational,
}
}
#[inline]
fn matrix3_exact_rational_kind(matrix: &[[Real; 3]; 3]) -> ExactRationalKind {
let mut kind = ExactRationalKind::ExactDyadicRational;
for row in matrix {
for value in row {
kind = combine_exact_rational_kind(kind, value.exact_rational_kind());
if kind == ExactRationalKind::NonRational {
return kind;
}
}
}
kind
}
fn matrix4_exact_rational_kind(matrix: &[[Real; 4]; 4]) -> ExactRationalKind {
let mut kind = ExactRationalKind::ExactDyadicRational;
for row in matrix {
for value in row {
kind = combine_exact_rational_kind(kind, value.exact_rational_kind());
if kind == ExactRationalKind::NonRational {
return kind;
}
}
}
kind
}
#[inline]
fn matrix_exact_rational_kind<const N: usize>(matrix: &[[Real; N]; N]) -> ExactRationalKind {
let mut kind = ExactRationalKind::ExactDyadicRational;
for row in matrix {
for value in row {
kind = combine_exact_rational_kind(kind, value.exact_rational_kind());
if kind == ExactRationalKind::NonRational {
return kind;
}
}
}
kind
}
impl<'a> PreparedMatrix3<'a> {
pub fn new(matrix: &'a Matrix3) -> Self {
crate::trace_dispatch!("hyperlattice_matrix", "method", "prepared-matrix3-new");
Self {
right_divisor: PreparedRightDivisor3::new(matrix),
}
}
pub fn matrix(&self) -> &Matrix3 {
self.right_divisor.divisor()
}
pub fn structural_facts(&self) -> Matrix3StructuralFacts {
crate::trace_dispatch!(
"hyperlattice_matrix",
"query",
"prepared-matrix3-structural-facts"
);
self.right_divisor.facts.public
}
pub fn exact_facts(&self) -> ExactRealSetFacts {
crate::trace_dispatch!(
"hyperlattice_matrix",
"query",
"prepared-matrix3-exact-facts"
);
self.right_divisor.facts.exact
}
pub fn determinant_schedule_hint(&self) -> MatrixDeterminantScheduleHint {
crate::trace_dispatch!(
"hyperlattice_matrix",
"query",
"prepared-matrix3-determinant-schedule"
);
self.right_divisor.determinant_schedule_hint()
}
pub fn cache_state(&self) -> MatrixPreparedCacheState {
crate::trace_dispatch!(
"hyperlattice_matrix",
"query",
"prepared-matrix3-cache-state"
);
self.right_divisor.cache_state()
}
pub fn determinant(&mut self) -> Real {
crate::trace_dispatch!(
"hyperlattice_matrix",
"method",
"prepared-matrix3-determinant"
);
self.right_divisor.determinant()
}
pub fn right_divisor(&mut self) -> &mut PreparedRightDivisor3<'a> {
&mut self.right_divisor
}
pub fn transform_vec3_handle(&self) -> TransformedMatrix3<'a> {
crate::trace_dispatch!(
"hyperlattice_matrix",
"method",
"prepared-matrix3-transform-handle"
);
TransformedMatrix3::new_with_facts(self.right_divisor.divisor, self.right_divisor.facts)
}
pub fn transform_vector(&self, rhs: &Vector3) -> Vector3 {
crate::trace_dispatch!(
"hyperlattice_matrix",
"method",
"prepared-matrix3-transform-vector"
);
self.transform_vec3_handle().transform_vector(rhs)
}
pub fn transform_vector_batch(&self, rhs: &[Vector3]) -> Vec<Vector3> {
crate::trace_dispatch!(
"hyperlattice_matrix",
"method",
"prepared-matrix3-transform-vector-batch"
);
self.transform_vec3_handle().transform_vector_batch(rhs)
}
pub fn inverse(&mut self) -> BlasResult<Matrix3> {
crate::trace_dispatch!("hyperlattice_matrix", "method", "prepared-matrix3-inverse");
self.right_divisor.inverse()
}
pub fn inverse_checked(&mut self) -> CheckedBlasResult<Matrix3> {
crate::trace_dispatch!(
"hyperlattice_matrix",
"method",
"prepared-matrix3-inverse-checked"
);
self.right_divisor.inverse_checked()
}
pub fn inverse_checked_with_abort(
&mut self,
signal: &AbortSignal,
) -> CheckedBlasResult<Matrix3> {
crate::trace_dispatch!(
"hyperlattice_matrix",
"method",
"prepared-matrix3-inverse-checked-abort"
);
self.right_divisor.inverse_checked_with_abort(signal)
}
pub fn reciprocal(&mut self) -> BlasResult<Matrix3> {
crate::trace_dispatch!(
"hyperlattice_matrix",
"method",
"prepared-matrix3-reciprocal"
);
self.right_divisor.reciprocal()
}
pub fn reciprocal_checked(&mut self) -> CheckedBlasResult<Matrix3> {
crate::trace_dispatch!(
"hyperlattice_matrix",
"method",
"prepared-matrix3-reciprocal-checked"
);
self.right_divisor.reciprocal_checked()
}
pub fn reciprocal_checked_with_abort(
&mut self,
signal: &AbortSignal,
) -> CheckedBlasResult<Matrix3> {
crate::trace_dispatch!(
"hyperlattice_matrix",
"method",
"prepared-matrix3-reciprocal-checked-abort"
);
self.right_divisor.reciprocal_checked_with_abort(signal)
}
pub fn divide_left(&mut self, left: Matrix3) -> BlasResult<Matrix3> {
crate::trace_dispatch!(
"hyperlattice_matrix",
"method",
"prepared-matrix3-divide-left"
);
Ok(Matrix3(self.right_divisor.divide(left.0)?))
}
pub fn divide_left_checked(&mut self, left: Matrix3) -> CheckedBlasResult<Matrix3> {
crate::trace_dispatch!(
"hyperlattice_matrix",
"method",
"prepared-matrix3-divide-left-checked"
);
Ok(Matrix3(self.right_divisor.divide_checked(left.0)?))
}
pub fn divide_left_checked_with_abort(
&mut self,
left: Matrix3,
signal: &AbortSignal,
) -> CheckedBlasResult<Matrix3> {
crate::trace_dispatch!(
"hyperlattice_matrix",
"method",
"prepared-matrix3-divide-left-checked-abort"
);
Ok(Matrix3(
self.right_divisor
.divide_checked_with_abort(left.0, signal)?,
))
}
}
impl<'a> PreparedMatrix4<'a> {
pub fn new(matrix: &'a Matrix4) -> Self {
crate::trace_dispatch!("hyperlattice_matrix", "method", "prepared-matrix4-new");
Self {
right_divisor: PreparedRightDivisor4::new(matrix),
}
}
pub fn matrix(&self) -> &Matrix4 {
self.right_divisor.divisor()
}
pub fn structural_facts(&self) -> Matrix4StructuralFacts {
crate::trace_dispatch!(
"hyperlattice_matrix",
"query",
"prepared-matrix4-structural-facts"
);
self.right_divisor.facts.public
}
pub fn exact_facts(&self) -> ExactRealSetFacts {
crate::trace_dispatch!(
"hyperlattice_matrix",
"query",
"prepared-matrix4-exact-facts"
);
self.right_divisor.facts.exact
}
pub fn determinant_schedule_hint(&self) -> MatrixDeterminantScheduleHint {
crate::trace_dispatch!(
"hyperlattice_matrix",
"query",
"prepared-matrix4-determinant-schedule"
);
self.right_divisor.determinant_schedule_hint()
}
pub fn cache_state(&self) -> MatrixPreparedCacheState {
crate::trace_dispatch!(
"hyperlattice_matrix",
"query",
"prepared-matrix4-cache-state"
);
self.right_divisor.cache_state()
}
pub fn determinant(&mut self) -> Real {
crate::trace_dispatch!(
"hyperlattice_matrix",
"method",
"prepared-matrix4-determinant"
);
self.right_divisor.determinant()
}
pub fn right_divisor(&mut self) -> &mut PreparedRightDivisor4<'a> {
&mut self.right_divisor
}
pub fn transform_vec4_handle(&self) -> TransformedMatrix4<'a> {
crate::trace_dispatch!(
"hyperlattice_matrix",
"method",
"prepared-matrix4-transform-handle"
);
TransformedMatrix4::new_with_facts(self.right_divisor.divisor, self.right_divisor.facts)
}
pub fn transform_vector(&self, rhs: &Vector4) -> Vector4 {
crate::trace_dispatch!(
"hyperlattice_matrix",
"method",
"prepared-matrix4-transform-vector"
);
self.transform_vec4_handle().transform_vector(rhs)
}
pub fn transform_vector_batch(&self, rhs: &[Vector4]) -> Vec<Vector4> {
crate::trace_dispatch!(
"hyperlattice_matrix",
"method",
"prepared-matrix4-transform-vector-batch"
);
self.transform_vec4_handle().transform_vector_batch(rhs)
}
pub fn transform_direction_vector(&self, rhs: &Vector4) -> Vector4 {
crate::trace_dispatch!(
"hyperlattice_matrix",
"method",
"prepared-matrix4-transform-direction-vector"
);
self.transform_vec4_handle().transform_direction_vector(rhs)
}
pub fn transform_direction_batch(&self, rhs: &[Vector4]) -> Vec<Vector4> {
crate::trace_dispatch!(
"hyperlattice_matrix",
"method",
"prepared-matrix4-transform-direction-batch"
);
self.transform_vec4_handle().transform_direction_batch(rhs)
}
pub fn transform_point_vector(&self, rhs: &Vector4) -> Vector4 {
crate::trace_dispatch!(
"hyperlattice_matrix",
"method",
"prepared-matrix4-transform-point-vector"
);
self.transform_vec4_handle().transform_point_vector(rhs)
}
pub fn transform_point_batch(&self, rhs: &[Vector4]) -> Vec<Vector4> {
crate::trace_dispatch!(
"hyperlattice_matrix",
"method",
"prepared-matrix4-transform-point-batch"
);
self.transform_vec4_handle().transform_point_batch(rhs)
}
pub fn inverse(&mut self) -> BlasResult<Matrix4> {
crate::trace_dispatch!("hyperlattice_matrix", "method", "prepared-matrix4-inverse");
self.right_divisor.inverse()
}
pub fn inverse_checked(&mut self) -> CheckedBlasResult<Matrix4> {
crate::trace_dispatch!(
"hyperlattice_matrix",
"method",
"prepared-matrix4-inverse-checked"
);
self.right_divisor.inverse_checked()
}
pub fn inverse_checked_with_abort(
&mut self,
signal: &AbortSignal,
) -> CheckedBlasResult<Matrix4> {
crate::trace_dispatch!(
"hyperlattice_matrix",
"method",
"prepared-matrix4-inverse-checked-abort"
);
self.right_divisor.inverse_checked_with_abort(signal)
}
pub fn reciprocal(&mut self) -> BlasResult<Matrix4> {
crate::trace_dispatch!(
"hyperlattice_matrix",
"method",
"prepared-matrix4-reciprocal"
);
self.right_divisor.reciprocal()
}
pub fn reciprocal_checked(&mut self) -> CheckedBlasResult<Matrix4> {
crate::trace_dispatch!(
"hyperlattice_matrix",
"method",
"prepared-matrix4-reciprocal-checked"
);
self.right_divisor.reciprocal_checked()
}
pub fn reciprocal_checked_with_abort(
&mut self,
signal: &AbortSignal,
) -> CheckedBlasResult<Matrix4> {
crate::trace_dispatch!(
"hyperlattice_matrix",
"method",
"prepared-matrix4-reciprocal-checked-abort"
);
self.right_divisor.reciprocal_checked_with_abort(signal)
}
pub fn divide_left(&mut self, left: Matrix4) -> BlasResult<Matrix4> {
crate::trace_dispatch!(
"hyperlattice_matrix",
"method",
"prepared-matrix4-divide-left"
);
Ok(Matrix4(self.right_divisor.divide(left.0)?))
}
pub fn divide_exact_rational_left(&mut self, left: Matrix4) -> BlasResult<Matrix4> {
crate::trace_dispatch!(
"hyperlattice_matrix",
"method",
"prepared-matrix4-divide-exact-rational-left"
);
Ok(Matrix4(
self.right_divisor.divide_exact_rational_left(left.0)?,
))
}
pub fn divide_left_checked(&mut self, left: Matrix4) -> CheckedBlasResult<Matrix4> {
crate::trace_dispatch!(
"hyperlattice_matrix",
"method",
"prepared-matrix4-divide-left-checked"
);
Ok(Matrix4(self.right_divisor.divide_checked(left.0)?))
}
pub fn divide_left_checked_with_abort(
&mut self,
left: Matrix4,
signal: &AbortSignal,
) -> CheckedBlasResult<Matrix4> {
crate::trace_dispatch!(
"hyperlattice_matrix",
"method",
"prepared-matrix4-divide-left-checked-abort"
);
Ok(Matrix4(
self.right_divisor
.divide_checked_with_abort(left.0, signal)?,
))
}
}
impl<'a> PreparedRightDivisor3<'a> {
pub fn new(divisor: &'a Matrix3) -> Self {
crate::trace_dispatch!(
"hyperlattice_matrix",
"method",
"prepared-right-divisor3-new"
);
let facts = matrix3_facts(&divisor.0);
let right_exact_rational_kind = matrix3_exact_rational_kind(&divisor.0);
Self {
divisor,
facts,
right_exact_rational_kind,
is_definitely_dense_for_inverse: true
&& matrix3_is_definitely_dense_for_inverse(&divisor.0),
adjugate: None,
determinant: None,
reciprocal_determinant: None,
inverse: None,
}
}
pub fn divisor(&self) -> &Matrix3 {
self.divisor
}
pub fn structural_facts(&self) -> Matrix3StructuralFacts {
self.facts.public
}
pub fn determinant_schedule_hint(&self) -> MatrixDeterminantScheduleHint {
self.facts.public.determinant_schedule_hint()
}
pub fn cache_state(&self) -> MatrixPreparedCacheState {
MatrixPreparedCacheState {
determinant: self.determinant.is_some(),
reciprocal_determinant: self.reciprocal_determinant.is_some(),
minor_factors: false,
adjugate: self.adjugate.is_some(),
inverse: self.inverse.is_some(),
}
}
pub fn determinant(&mut self) -> Real {
crate::trace_dispatch!(
"hyperlattice_matrix",
"method",
"prepared-right-divisor3-determinant"
);
if let Some(determinant) = &self.determinant {
crate::trace_dispatch!(
"hyperlattice_matrix",
"method",
"prepared-right-divisor3-determinant-cache-hit"
);
return determinant.clone();
}
let determinant = determinant3(&self.divisor.0);
self.determinant = Some(determinant.clone());
determinant
}
#[inline]
fn can_use_shared_adjugate(&self, left: &[[Real; 3]; 3]) -> bool {
match self.right_exact_rational_kind {
ExactRationalKind::ExactDyadicRational => {
matrix3_exact_rational_kind(left) == ExactRationalKind::ExactDyadicRational
}
ExactRationalKind::ExactRational => {
matches!(
matrix3_exact_rational_kind(left),
ExactRationalKind::ExactDyadicRational | ExactRationalKind::ExactRational
)
}
ExactRationalKind::NonRational => false,
}
}
fn prepare_shared_adjugate(&mut self) -> BlasResult<&[[Real; 3]; 3]> {
if self.adjugate.is_none() {
crate::trace_dispatch!(
"hyperlattice_matrix",
"method",
"prepared-right-divisor3-cache-shared-adjugate"
);
let known_rational = self.right_exact_rational_kind == ExactRationalKind::ExactRational;
let (adjugate, determinant) = if self.is_definitely_dense_for_inverse && known_rational
{
matrix3_adjugate_and_determinant_dense_exact_known_rational(&self.divisor.0)
} else if self.is_definitely_dense_for_inverse {
matrix3_adjugate_and_determinant_dense_exact(&self.divisor.0)
} else {
matrix3_adjugate_and_determinant(&self.divisor.0)
};
let reciprocal_determinant = determinant.inverse_ref()?;
self.adjugate = Some(adjugate);
self.determinant = Some(determinant);
self.reciprocal_determinant = Some(reciprocal_determinant);
}
Ok(self
.adjugate
.as_ref()
.expect("adjugate cache must be present"))
}
fn prepare_shared_adjugate_checked(&mut self) -> CheckedBlasResult<&[[Real; 3]; 3]> {
if self.adjugate.is_none() {
crate::trace_dispatch!(
"hyperlattice_matrix",
"method",
"prepared-right-divisor3-cache-shared-adjugate-checked"
);
let known_rational = self.right_exact_rational_kind == ExactRationalKind::ExactRational;
let (adjugate, determinant) = if self.is_definitely_dense_for_inverse && known_rational
{
matrix3_adjugate_and_determinant_dense_exact_known_rational(&self.divisor.0)
} else if self.is_definitely_dense_for_inverse {
matrix3_adjugate_and_determinant_dense_exact(&self.divisor.0)
} else {
matrix3_adjugate_and_determinant(&self.divisor.0)
};
require_known_nonzero(&determinant)?;
let reciprocal_determinant = determinant.inverse_ref()?;
self.adjugate = Some(adjugate);
self.determinant = Some(determinant);
self.reciprocal_determinant = Some(reciprocal_determinant);
}
Ok(self
.adjugate
.as_ref()
.expect("adjugate cache must be present"))
}
fn prepare_shared_adjugate_checked_with_abort(
&mut self,
signal: &AbortSignal,
) -> CheckedBlasResult<&[[Real; 3]; 3]> {
if self.adjugate.is_none() {
crate::trace_dispatch!(
"hyperlattice_matrix",
"method",
"prepared-right-divisor3-cache-shared-adjugate-checked-abort"
);
let known_rational = self.right_exact_rational_kind == ExactRationalKind::ExactRational;
let (adjugate, determinant) = if self.is_definitely_dense_for_inverse && known_rational
{
matrix3_adjugate_and_determinant_dense_exact_known_rational(&self.divisor.0)
} else if self.is_definitely_dense_for_inverse {
matrix3_adjugate_and_determinant_dense_exact(&self.divisor.0)
} else {
matrix3_adjugate_and_determinant(&self.divisor.0)
};
let determinant = with_abort(determinant, signal);
require_known_nonzero(&determinant)?;
let reciprocal_determinant = determinant.inverse_ref()?;
self.adjugate = Some(adjugate);
self.determinant = Some(determinant);
self.reciprocal_determinant = Some(reciprocal_determinant);
}
Ok(self
.adjugate
.as_ref()
.expect("adjugate cache must be present"))
}
pub fn divide(&mut self, left: [[Real; 3]; 3]) -> BlasResult<[[Real; 3]; 3]> {
crate::trace_dispatch!(
"hyperlattice_matrix",
"method",
"prepared-right-divisor3-divide"
);
right_divide_matrix3_prepared(left, self)
}
pub fn divide_checked(&mut self, left: [[Real; 3]; 3]) -> CheckedBlasResult<[[Real; 3]; 3]> {
crate::trace_dispatch!(
"hyperlattice_matrix",
"method",
"prepared-right-divisor3-divide-checked"
);
right_divide_matrix3_prepared_checked(left, self)
}
pub fn divide_checked_with_abort(
&mut self,
left: [[Real; 3]; 3],
signal: &AbortSignal,
) -> CheckedBlasResult<[[Real; 3]; 3]> {
crate::trace_dispatch!(
"hyperlattice_matrix",
"method",
"prepared-right-divisor3-divide-checked-abort"
);
right_divide_matrix3_prepared_checked_with_abort(left, self, signal)
}
pub fn inverse(&mut self) -> BlasResult<Matrix3> {
crate::trace_dispatch!(
"hyperlattice_matrix",
"method",
"prepared-right-divisor3-inverse"
);
if let Some(inverse) = &self.inverse {
crate::trace_dispatch!(
"hyperlattice_matrix",
"method",
"prepared-right-divisor3-inverse-cache-hit"
);
return Ok(inverse.clone());
}
let _ = self.prepare_shared_adjugate()?;
let inv_det = self
.reciprocal_determinant
.as_ref()
.expect("reciprocal determinant cache should be present");
let adjugate = self
.adjugate
.as_ref()
.expect("adjugate cache should be present")
.clone();
let inverse = Matrix3(scale_matrix3(adjugate, inv_det));
self.inverse = Some(inverse.clone());
Ok(inverse)
}
pub fn inverse_checked(&mut self) -> CheckedBlasResult<Matrix3> {
crate::trace_dispatch!(
"hyperlattice_matrix",
"method",
"prepared-right-divisor3-inverse-checked"
);
let _ = self.prepare_shared_adjugate_checked()?;
if let Some(inverse) = &self.inverse {
crate::trace_dispatch!(
"hyperlattice_matrix",
"method",
"prepared-right-divisor3-inverse-checked-cache-hit"
);
return Ok(inverse.clone());
}
let inv_det = self
.reciprocal_determinant
.as_ref()
.expect("reciprocal determinant cache should be present");
let adjugate = self
.adjugate
.as_ref()
.expect("adjugate cache should be present")
.clone();
let inverse = Matrix3(scale_matrix3(adjugate, inv_det));
self.inverse = Some(inverse.clone());
Ok(inverse)
}
pub fn inverse_checked_with_abort(
&mut self,
signal: &AbortSignal,
) -> CheckedBlasResult<Matrix3> {
crate::trace_dispatch!(
"hyperlattice_matrix",
"method",
"prepared-right-divisor3-inverse-checked-abort"
);
let _ = self.prepare_shared_adjugate_checked_with_abort(signal)?;
if let Some(inverse) = &self.inverse {
crate::trace_dispatch!(
"hyperlattice_matrix",
"method",
"prepared-right-divisor3-inverse-checked-abort-cache-hit"
);
return Ok(inverse.clone());
}
let inv_det = self
.reciprocal_determinant
.as_ref()
.expect("reciprocal determinant cache should be present");
let adjugate = self
.adjugate
.as_ref()
.expect("adjugate cache should be present")
.clone();
let inverse = Matrix3(scale_matrix3(adjugate, inv_det));
self.inverse = Some(inverse.clone());
Ok(inverse)
}
pub fn reciprocal(&mut self) -> BlasResult<Matrix3> {
crate::trace_dispatch!(
"hyperlattice_matrix",
"method",
"prepared-right-divisor3-reciprocal"
);
self.inverse()
}
pub fn reciprocal_checked(&mut self) -> CheckedBlasResult<Matrix3> {
crate::trace_dispatch!(
"hyperlattice_matrix",
"method",
"prepared-right-divisor3-reciprocal-checked"
);
self.inverse_checked()
}
pub fn reciprocal_checked_with_abort(
&mut self,
signal: &AbortSignal,
) -> CheckedBlasResult<Matrix3> {
crate::trace_dispatch!(
"hyperlattice_matrix",
"method",
"prepared-right-divisor3-reciprocal-checked-abort"
);
self.inverse_checked_with_abort(signal)
}
}
impl<'a> PreparedRightDivisor4<'a> {
pub fn new(divisor: &'a Matrix4) -> Self {
crate::trace_dispatch!(
"hyperlattice_matrix",
"method",
"prepared-right-divisor4-new"
);
let facts = matrix4_facts(&divisor.0);
let right_exact_rational_kind = matrix4_exact_rational_kind(&divisor.0);
Self {
divisor,
facts,
right_exact_rational_kind,
is_definitely_dense_for_inverse: true && facts.is_definitely_dense_for_inverse,
factors: None,
adjugate: None,
determinant: None,
reciprocal_determinant: None,
inverse: None,
}
}
pub fn divisor(&self) -> &Matrix4 {
self.divisor
}
pub fn structural_facts(&self) -> Matrix4StructuralFacts {
self.facts.public
}
pub fn determinant_schedule_hint(&self) -> MatrixDeterminantScheduleHint {
self.facts.public.determinant_schedule_hint()
}
pub fn cache_state(&self) -> MatrixPreparedCacheState {
MatrixPreparedCacheState {
determinant: self.determinant.is_some(),
reciprocal_determinant: self.reciprocal_determinant.is_some(),
minor_factors: self.factors.is_some(),
adjugate: self.adjugate.is_some(),
inverse: self.inverse.is_some(),
}
}
pub fn determinant(&mut self) -> Real {
crate::trace_dispatch!(
"hyperlattice_matrix",
"method",
"prepared-right-divisor4-determinant"
);
if let Some(determinant) = &self.determinant {
crate::trace_dispatch!(
"hyperlattice_matrix",
"method",
"prepared-right-divisor4-determinant-cache-hit"
);
return determinant.clone();
}
let dense_exact = self.is_definitely_dense_for_inverse;
let known_rational = self.right_exact_rational_kind != ExactRationalKind::NonRational;
let factors = self.factors.get_or_insert_with(|| {
if dense_exact && known_rational {
matrix4_factors_dense_exact_known_rational(&self.divisor.0)
} else if dense_exact {
matrix4_factors_dense_exact(&self.divisor.0)
} else {
matrix4_factors(&self.divisor.0)
}
});
let determinant = if dense_exact && known_rational {
determinant4_from_factors_known_rational(&factors.0, &factors.1)
} else {
determinant4_from_factors(&factors.0, &factors.1)
};
self.determinant = Some(determinant.clone());
determinant
}
#[inline]
fn can_use_shared_adjugate(&self, left: &[[Real; 4]; 4]) -> bool {
if true && self.right_exact_rational_kind != ExactRationalKind::NonRational {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"prepared-right-divisor4-exact-right-skip-left-kind"
);
return true;
}
match self.right_exact_rational_kind {
ExactRationalKind::ExactDyadicRational => {
let left_kind = matrix4_exact_rational_kind(left);
left_kind == ExactRationalKind::ExactDyadicRational
|| (true && left_kind == ExactRationalKind::ExactRational)
}
ExactRationalKind::ExactRational => {
matches!(
matrix4_exact_rational_kind(left),
ExactRationalKind::ExactDyadicRational | ExactRationalKind::ExactRational
)
}
ExactRationalKind::NonRational => false,
}
}
fn prepare_shared_adjugate(&mut self) -> BlasResult<&[[Real; 4]; 4]> {
if self.adjugate.is_none() {
crate::trace_dispatch!(
"hyperlattice_matrix",
"method",
"prepared-right-divisor4-cache-shared-adjugate"
);
let dense_exact = self.is_definitely_dense_for_inverse;
let known_rational = self.right_exact_rational_kind != ExactRationalKind::NonRational;
let factors = self.factors.get_or_insert_with(|| {
if dense_exact && known_rational {
matrix4_factors_dense_exact_known_rational(&self.divisor.0)
} else if dense_exact {
matrix4_factors_dense_exact(&self.divisor.0)
} else {
matrix4_factors(&self.divisor.0)
}
});
let determinant = if dense_exact && known_rational {
determinant4_from_factors_known_rational(&factors.0, &factors.1)
} else {
determinant4_from_factors(&factors.0, &factors.1)
};
let reciprocal_determinant = determinant.inverse_ref()?;
let adjugate = if dense_exact && known_rational {
matrix4_adjugate_from_factors_dense_exact_known_rational(
&self.divisor.0,
&factors.0,
&factors.1,
)
} else if dense_exact {
matrix4_adjugate_from_factors_dense_exact(&self.divisor.0, &factors.0, &factors.1)
} else {
matrix4_adjugate_from_factors(&self.divisor.0, &factors.0, &factors.1)
};
self.adjugate = Some(adjugate);
self.determinant = Some(determinant);
self.reciprocal_determinant = Some(reciprocal_determinant);
}
Ok(self
.adjugate
.as_ref()
.expect("adjugate cache must be present"))
}
fn prepare_shared_adjugate_checked(&mut self) -> CheckedBlasResult<&[[Real; 4]; 4]> {
if self.adjugate.is_none() {
crate::trace_dispatch!(
"hyperlattice_matrix",
"method",
"prepared-right-divisor4-cache-shared-adjugate-checked"
);
let dense_exact = self.is_definitely_dense_for_inverse;
let known_rational = self.right_exact_rational_kind != ExactRationalKind::NonRational;
let factors = self.factors.get_or_insert_with(|| {
if dense_exact && known_rational {
matrix4_factors_dense_exact_known_rational(&self.divisor.0)
} else if dense_exact {
matrix4_factors_dense_exact(&self.divisor.0)
} else {
matrix4_factors(&self.divisor.0)
}
});
let determinant = if dense_exact && known_rational {
determinant4_from_factors_known_rational(&factors.0, &factors.1)
} else {
determinant4_from_factors(&factors.0, &factors.1)
};
require_known_nonzero(&determinant)?;
let reciprocal_determinant = determinant.inverse_ref()?;
let adjugate = if dense_exact && known_rational {
matrix4_adjugate_from_factors_dense_exact_known_rational(
&self.divisor.0,
&factors.0,
&factors.1,
)
} else if dense_exact {
matrix4_adjugate_from_factors_dense_exact(&self.divisor.0, &factors.0, &factors.1)
} else {
matrix4_adjugate_from_factors(&self.divisor.0, &factors.0, &factors.1)
};
self.adjugate = Some(adjugate);
self.determinant = Some(determinant);
self.reciprocal_determinant = Some(reciprocal_determinant);
}
Ok(self
.adjugate
.as_ref()
.expect("adjugate cache must be present"))
}
fn prepare_shared_adjugate_checked_with_abort(
&mut self,
signal: &AbortSignal,
) -> CheckedBlasResult<&[[Real; 4]; 4]> {
if self.adjugate.is_none() {
crate::trace_dispatch!(
"hyperlattice_matrix",
"method",
"prepared-right-divisor4-cache-shared-adjugate-checked-abort"
);
let dense_exact = self.is_definitely_dense_for_inverse;
let known_rational = self.right_exact_rational_kind != ExactRationalKind::NonRational;
let factors = self.factors.get_or_insert_with(|| {
if dense_exact && known_rational {
matrix4_factors_dense_exact_known_rational(&self.divisor.0)
} else if dense_exact {
matrix4_factors_dense_exact(&self.divisor.0)
} else {
matrix4_factors(&self.divisor.0)
}
});
let determinant = if dense_exact && known_rational {
with_abort(
determinant4_from_factors_known_rational(&factors.0, &factors.1),
signal,
)
} else {
with_abort(determinant4_from_factors(&factors.0, &factors.1), signal)
};
require_known_nonzero(&determinant)?;
let reciprocal_determinant = determinant.inverse_ref()?;
let adjugate = if dense_exact && known_rational {
matrix4_adjugate_from_factors_dense_exact_known_rational(
&self.divisor.0,
&factors.0,
&factors.1,
)
} else if dense_exact {
matrix4_adjugate_from_factors_dense_exact(&self.divisor.0, &factors.0, &factors.1)
} else {
matrix4_adjugate_from_factors(&self.divisor.0, &factors.0, &factors.1)
};
self.adjugate = Some(adjugate);
self.determinant = Some(determinant);
self.reciprocal_determinant = Some(reciprocal_determinant);
}
Ok(self
.adjugate
.as_ref()
.expect("adjugate cache must be present"))
}
pub fn divide(&mut self, left: [[Real; 4]; 4]) -> BlasResult<[[Real; 4]; 4]> {
crate::trace_dispatch!(
"hyperlattice_matrix",
"method",
"prepared-right-divisor4-divide"
);
right_divide_matrix4_prepared(left, self)
}
pub fn divide_exact_rational_left(
&mut self,
left: [[Real; 4]; 4],
) -> BlasResult<[[Real; 4]; 4]> {
crate::trace_dispatch!(
"hyperlattice_matrix",
"method",
"prepared-right-divisor4-divide-exact-rational-left"
);
right_divide_matrix4_prepared_exact_rational_left(left, self)
}
pub fn divide_checked(&mut self, left: [[Real; 4]; 4]) -> CheckedBlasResult<[[Real; 4]; 4]> {
crate::trace_dispatch!(
"hyperlattice_matrix",
"method",
"prepared-right-divisor4-divide-checked"
);
right_divide_matrix4_prepared_checked(left, self)
}
pub fn divide_checked_with_abort(
&mut self,
left: [[Real; 4]; 4],
signal: &AbortSignal,
) -> CheckedBlasResult<[[Real; 4]; 4]> {
crate::trace_dispatch!(
"hyperlattice_matrix",
"method",
"prepared-right-divisor4-divide-checked-abort"
);
right_divide_matrix4_prepared_checked_with_abort(left, self, signal)
}
pub fn inverse(&mut self) -> BlasResult<Matrix4> {
crate::trace_dispatch!(
"hyperlattice_matrix",
"method",
"prepared-right-divisor4-inverse"
);
if let Some(inverse) = &self.inverse {
crate::trace_dispatch!(
"hyperlattice_matrix",
"method",
"prepared-right-divisor4-inverse-cache-hit"
);
return Ok(inverse.clone());
}
let _ = self.prepare_shared_adjugate()?;
let inv_det = self
.reciprocal_determinant
.as_ref()
.expect("reciprocal determinant cache should be present");
let adjugate = self
.adjugate
.as_ref()
.expect("adjugate cache should be present")
.clone();
let inverse = Matrix4(scale_matrix4(adjugate, inv_det));
self.inverse = Some(inverse.clone());
Ok(inverse)
}
pub fn inverse_checked(&mut self) -> CheckedBlasResult<Matrix4> {
crate::trace_dispatch!(
"hyperlattice_matrix",
"method",
"prepared-right-divisor4-inverse-checked"
);
let _ = self.prepare_shared_adjugate_checked()?;
if let Some(inverse) = &self.inverse {
crate::trace_dispatch!(
"hyperlattice_matrix",
"method",
"prepared-right-divisor4-inverse-checked-cache-hit"
);
return Ok(inverse.clone());
}
let inv_det = self
.reciprocal_determinant
.as_ref()
.expect("reciprocal determinant cache should be present");
let adjugate = self
.adjugate
.as_ref()
.expect("adjugate cache should be present")
.clone();
let inverse = Matrix4(scale_matrix4(adjugate, inv_det));
self.inverse = Some(inverse.clone());
Ok(inverse)
}
pub fn inverse_checked_with_abort(
&mut self,
signal: &AbortSignal,
) -> CheckedBlasResult<Matrix4> {
crate::trace_dispatch!(
"hyperlattice_matrix",
"method",
"prepared-right-divisor4-inverse-checked-abort"
);
let _ = self.prepare_shared_adjugate_checked_with_abort(signal)?;
if let Some(inverse) = &self.inverse {
crate::trace_dispatch!(
"hyperlattice_matrix",
"method",
"prepared-right-divisor4-inverse-checked-abort-cache-hit"
);
return Ok(inverse.clone());
}
let inv_det = self
.reciprocal_determinant
.as_ref()
.expect("reciprocal determinant cache should be present");
let adjugate = self
.adjugate
.as_ref()
.expect("adjugate cache should be present")
.clone();
let inverse = Matrix4(scale_matrix4(adjugate, inv_det));
self.inverse = Some(inverse.clone());
Ok(inverse)
}
pub fn reciprocal(&mut self) -> BlasResult<Matrix4> {
crate::trace_dispatch!(
"hyperlattice_matrix",
"method",
"prepared-right-divisor4-reciprocal"
);
self.inverse()
}
pub fn reciprocal_checked(&mut self) -> CheckedBlasResult<Matrix4> {
crate::trace_dispatch!(
"hyperlattice_matrix",
"method",
"prepared-right-divisor4-reciprocal-checked"
);
self.inverse_checked()
}
pub fn reciprocal_checked_with_abort(
&mut self,
signal: &AbortSignal,
) -> CheckedBlasResult<Matrix4> {
crate::trace_dispatch!(
"hyperlattice_matrix",
"method",
"prepared-right-divisor4-reciprocal-checked-abort"
);
self.inverse_checked_with_abort(signal)
}
pub fn powi(&mut self, exponent: i32) -> BlasResult<Matrix4> {
crate::trace_dispatch!(
"hyperlattice_matrix",
"method",
"prepared-right-divisor4-powi"
);
if exponent == -1 {
crate::trace_dispatch!(
"hyperlattice_matrix",
"powi",
"prepared-negative-one-inverse"
);
return self.inverse();
}
let base = if exponent < 0 {
self.inverse()?.0
} else {
self.divisor.0.clone()
};
let power = if self.right_exact_rational_kind != ExactRationalKind::NonRational {
matrix_power4_known_rational(base, exponent.unsigned_abs())
} else {
matrix_power4(base, exponent.unsigned_abs())
};
Ok(Matrix4(power))
}
pub fn powi_checked(&mut self, exponent: i32) -> CheckedBlasResult<Matrix4> {
crate::trace_dispatch!(
"hyperlattice_matrix",
"method",
"prepared-right-divisor4-powi-checked"
);
if exponent == -1 {
crate::trace_dispatch!(
"hyperlattice_matrix",
"powi",
"prepared-negative-one-inverse-checked"
);
return self.inverse_checked();
}
let base = if exponent < 0 {
self.inverse_checked()?.0
} else {
self.divisor.0.clone()
};
let power = if self.right_exact_rational_kind != ExactRationalKind::NonRational {
matrix_power4_known_rational(base, exponent.unsigned_abs())
} else {
matrix_power4(base, exponent.unsigned_abs())
};
Ok(Matrix4(power))
}
pub fn powi_checked_with_abort(
&mut self,
exponent: i32,
signal: &AbortSignal,
) -> CheckedBlasResult<Matrix4> {
crate::trace_dispatch!(
"hyperlattice_matrix",
"method",
"prepared-right-divisor4-powi-checked-abort"
);
if exponent == -1 {
crate::trace_dispatch!(
"hyperlattice_matrix",
"powi",
"prepared-negative-one-inverse-checked-abort"
);
return self.inverse_checked_with_abort(signal);
}
let base = if exponent < 0 {
self.inverse_checked_with_abort(signal)?.0
} else {
self.divisor.0.clone()
};
let power = if self.right_exact_rational_kind != ExactRationalKind::NonRational {
matrix_power4_known_rational(base, exponent.unsigned_abs())
} else {
matrix_power4(base, exponent.unsigned_abs())
};
Ok(Matrix4(power))
}
}
#[derive(Clone, Copy, Debug)]
struct Matrix4Facts {
public: Matrix4StructuralFacts,
exact: ExactRealSetFacts,
is_identity: bool,
is_diagonal: bool,
is_upper_triangular: bool,
is_lower_triangular: bool,
linear_is_diagonal: bool,
direction_linear_is_diagonal: bool,
affine_linear_diagonal_is_definitely_nonzero: bool,
is_definitely_dense_for_inverse: bool,
translation_xyz_zero: [bool; 3],
is_affine: bool,
is_affine_translation: bool,
}
#[inline]
fn matrix3_transform_kind(
is_identity: bool,
is_affine: bool,
is_affine_translation: bool,
linear_is_diagonal: bool,
) -> Matrix3TransformKind {
if is_identity {
Matrix3TransformKind::Identity
} else if is_affine_translation {
Matrix3TransformKind::AffineTranslation
} else if is_affine && linear_is_diagonal {
Matrix3TransformKind::AffineDiagonalLinear
} else if is_affine {
Matrix3TransformKind::Affine
} else {
Matrix3TransformKind::Projective
}
}
#[inline]
fn matrix4_transform_kind(
is_identity: bool,
is_affine: bool,
is_affine_translation: bool,
linear_is_diagonal: bool,
signed_permutation_rows: Option<[SignedAxis4; 4]>,
) -> Matrix4TransformKind {
if is_identity {
Matrix4TransformKind::Identity
} else if signed_permutation_rows.is_some() {
Matrix4TransformKind::SignedPermutation
} else if is_affine_translation {
Matrix4TransformKind::AffineTranslation
} else if is_affine && linear_is_diagonal {
Matrix4TransformKind::AffineDiagonalLinear
} else if is_affine {
Matrix4TransformKind::Affine
} else {
Matrix4TransformKind::Projective
}
}
#[inline]
fn matrix3_facts(matrix: &[[Real; 3]; 3]) -> Matrix3Facts {
let m00_one = matrix[0][0].definitely_one();
let m01_zero = matrix[0][1].definitely_zero();
let m02_zero = matrix[0][2].definitely_zero();
let m10_zero = matrix[1][0].definitely_zero();
let m11_one = matrix[1][1].definitely_one();
let m12_zero = matrix[1][2].definitely_zero();
let m20_zero = matrix[2][0].definitely_zero();
let m21_zero = matrix[2][1].definitely_zero();
let m22_one = matrix[2][2].definitely_one();
let linear_is_diagonal = m01_zero && m10_zero;
let is_diagonal = m01_zero && m02_zero && m10_zero && m12_zero && m20_zero && m21_zero;
let is_identity = is_diagonal && m00_one && m11_one && m22_one;
let is_affine = m20_zero && m21_zero && m22_one;
let is_upper_triangular = m10_zero && m20_zero && m21_zero;
let is_lower_triangular = m01_zero && m02_zero && m12_zero;
let is_affine_translation = is_affine && m00_one && m11_one && linear_is_diagonal;
let exact = crate::kernels::exact_real_set_facts(matrix.iter().flat_map(|row| row.iter()));
let (zero_mask, row_zero_masks, column_zero_masks) = matrix_zero_masks(matrix);
let one_mask = matrix_one_mask(matrix);
let transform_kind = matrix3_transform_kind(
is_identity,
is_affine,
is_affine_translation,
linear_is_diagonal,
);
let public = Matrix3StructuralFacts {
exact,
symbolic_dependencies: matrix_symbolic_dependency_mask(matrix),
zero_mask,
one_mask,
row_zero_masks,
column_zero_masks,
is_identity,
is_diagonal,
is_exact_rational_uniform_scale: matrix3_exact_rational_uniform_scale(matrix, is_diagonal),
is_upper_triangular,
is_lower_triangular,
is_affine,
is_affine_translation,
transform_kind,
};
Matrix3Facts {
public,
exact,
is_identity,
is_diagonal,
is_upper_triangular,
is_lower_triangular,
linear_is_diagonal,
is_affine,
is_affine_translation,
}
}
#[inline]
fn matrix4_facts(matrix: &[[Real; 4]; 4]) -> Matrix4Facts {
let m00_one = matrix[0][0].definitely_one();
let m01_zero = matrix[0][1].definitely_zero();
let m02_zero = matrix[0][2].definitely_zero();
let m03_zero = matrix[0][3].definitely_zero();
let m10_zero = matrix[1][0].definitely_zero();
let m11_one = matrix[1][1].definitely_one();
let m12_zero = matrix[1][2].definitely_zero();
let m13_zero = matrix[1][3].definitely_zero();
let m20_zero = matrix[2][0].definitely_zero();
let m21_zero = matrix[2][1].definitely_zero();
let m22_one = matrix[2][2].definitely_one();
let m23_zero = matrix[2][3].definitely_zero();
let m30_zero = matrix[3][0].definitely_zero();
let m31_zero = matrix[3][1].definitely_zero();
let m32_zero = matrix[3][2].definitely_zero();
let m33_one = matrix[3][3].definitely_one();
let is_definitely_dense_for_inverse = matches!(matrix[1][0].zero_status(), ZeroStatus::NonZero)
&& matches!(matrix[0][1].zero_status(), ZeroStatus::NonZero)
&& matches!(matrix[3][0].zero_status(), ZeroStatus::NonZero);
let linear_is_diagonal = m01_zero && m02_zero && m10_zero && m12_zero && m20_zero && m21_zero;
let direction_linear_is_diagonal = linear_is_diagonal && m30_zero && m31_zero && m32_zero;
let is_diagonal = m01_zero
&& m02_zero
&& m03_zero
&& m10_zero
&& m12_zero
&& m13_zero
&& m20_zero
&& m21_zero
&& m23_zero
&& m30_zero
&& m31_zero
&& m32_zero;
let is_upper_triangular = m10_zero && m20_zero && m30_zero && m21_zero && m31_zero && m32_zero;
let is_lower_triangular = m01_zero && m02_zero && m03_zero && m12_zero && m13_zero && m23_zero;
let is_identity = is_diagonal && m00_one && m11_one && m22_one && m33_one;
let is_affine = m30_zero && m31_zero && m32_zero && m33_one;
let is_affine_translation = is_affine && m00_one && m11_one && m22_one && linear_is_diagonal;
let affine_linear_diagonal_is_definitely_nonzero = if true {
matches!(matrix[0][0].zero_status(), ZeroStatus::NonZero)
&& matches!(matrix[1][1].zero_status(), ZeroStatus::NonZero)
&& matches!(matrix[2][2].zero_status(), ZeroStatus::NonZero)
} else {
false
};
let exact = crate::kernels::exact_real_set_facts(matrix.iter().flat_map(|row| row.iter()));
let (zero_mask, row_zero_masks, column_zero_masks) = matrix_zero_masks(matrix);
let one_mask = matrix_one_mask(matrix);
let translation_xyz_zero = [m03_zero, m13_zero, m23_zero];
let signed_permutation_rows = matrix4_signed_permutation_rows(matrix);
let transform_kind = matrix4_transform_kind(
is_identity,
is_affine,
is_affine_translation,
linear_is_diagonal,
signed_permutation_rows,
);
let public = Matrix4StructuralFacts {
exact,
symbolic_dependencies: matrix_symbolic_dependency_mask(matrix),
zero_mask,
one_mask,
row_zero_masks,
column_zero_masks,
is_identity,
is_diagonal,
is_exact_rational_uniform_scale: matrix4_exact_rational_uniform_scale(matrix, is_diagonal),
is_upper_triangular,
is_lower_triangular,
is_affine,
is_affine_translation,
linear_is_diagonal,
direction_linear_is_diagonal,
signed_permutation_rows,
translation_xyz_zero,
transform_kind,
};
Matrix4Facts {
public,
exact,
is_identity,
is_diagonal,
is_upper_triangular,
is_lower_triangular,
linear_is_diagonal,
direction_linear_is_diagonal,
is_definitely_dense_for_inverse,
translation_xyz_zero,
is_affine,
is_affine_translation,
affine_linear_diagonal_is_definitely_nonzero,
}
}
#[inline]
fn matrix3_facts_assuming_const3<const N: usize>(matrix: &[[Real; N]; N]) -> Matrix3Facts {
debug_assert_eq!(N, 3);
let m00_one = matrix[0][0].definitely_one();
let m01_zero = matrix[0][1].definitely_zero();
let m02_zero = matrix[0][2].definitely_zero();
let m10_zero = matrix[1][0].definitely_zero();
let m11_one = matrix[1][1].definitely_one();
let m12_zero = matrix[1][2].definitely_zero();
let m20_zero = matrix[2][0].definitely_zero();
let m21_zero = matrix[2][1].definitely_zero();
let m22_one = matrix[2][2].definitely_one();
let linear_is_diagonal = m01_zero && m10_zero;
let is_diagonal = m01_zero && m02_zero && m10_zero && m12_zero && m20_zero && m21_zero;
let is_identity = is_diagonal && m00_one && m11_one && m22_one;
let is_affine = m20_zero && m21_zero && m22_one;
let is_upper_triangular = m10_zero && m20_zero && m21_zero;
let is_lower_triangular = m01_zero && m02_zero && m12_zero;
let is_affine_translation = is_affine && m00_one && m11_one && linear_is_diagonal;
let exact = crate::kernels::exact_real_set_facts(
(0..3).flat_map(|row| (0..3).map(move |col| &matrix[row][col])),
);
let (zero_mask, row_zero_masks, column_zero_masks) =
matrix_zero_masks_assuming_size::<N, 3>(matrix);
let one_mask = matrix_one_mask_assuming_size::<N, 3>(matrix);
let transform_kind = matrix3_transform_kind(
is_identity,
is_affine,
is_affine_translation,
linear_is_diagonal,
);
let public = Matrix3StructuralFacts {
exact,
symbolic_dependencies: matrix_symbolic_dependency_mask_assuming_size::<N, 3>(matrix),
zero_mask,
one_mask,
row_zero_masks,
column_zero_masks,
is_identity,
is_diagonal,
is_exact_rational_uniform_scale: matrix3_exact_rational_uniform_scale_assuming_size(
matrix,
is_diagonal,
),
is_upper_triangular,
is_lower_triangular,
is_affine,
is_affine_translation,
transform_kind,
};
Matrix3Facts {
public,
exact,
is_identity,
is_diagonal,
is_upper_triangular,
is_lower_triangular,
linear_is_diagonal,
is_affine,
is_affine_translation,
}
}
#[inline]
fn matrix4_facts_assuming_const4<const N: usize>(matrix: &[[Real; N]; N]) -> Matrix4Facts {
debug_assert_eq!(N, 4);
let m00_one = matrix[0][0].definitely_one();
let m01_zero = matrix[0][1].definitely_zero();
let m02_zero = matrix[0][2].definitely_zero();
let m03_zero = matrix[0][3].definitely_zero();
let m10_zero = matrix[1][0].definitely_zero();
let m11_one = matrix[1][1].definitely_one();
let m12_zero = matrix[1][2].definitely_zero();
let m13_zero = matrix[1][3].definitely_zero();
let m20_zero = matrix[2][0].definitely_zero();
let m21_zero = matrix[2][1].definitely_zero();
let m22_one = matrix[2][2].definitely_one();
let m23_zero = matrix[2][3].definitely_zero();
let m30_zero = matrix[3][0].definitely_zero();
let m31_zero = matrix[3][1].definitely_zero();
let m32_zero = matrix[3][2].definitely_zero();
let m33_one = matrix[3][3].definitely_one();
let is_definitely_dense_for_inverse = matches!(matrix[1][0].zero_status(), ZeroStatus::NonZero)
&& matches!(matrix[0][1].zero_status(), ZeroStatus::NonZero)
&& matches!(matrix[3][0].zero_status(), ZeroStatus::NonZero);
let linear_is_diagonal = m01_zero && m02_zero && m10_zero && m12_zero && m20_zero && m21_zero;
let direction_linear_is_diagonal = linear_is_diagonal && m30_zero && m31_zero && m32_zero;
let is_diagonal = m01_zero
&& m02_zero
&& m03_zero
&& m10_zero
&& m12_zero
&& m13_zero
&& m20_zero
&& m21_zero
&& m23_zero
&& m30_zero
&& m31_zero
&& m32_zero;
let is_upper_triangular = m10_zero && m20_zero && m30_zero && m21_zero && m31_zero && m32_zero;
let is_lower_triangular = m01_zero && m02_zero && m03_zero && m12_zero && m13_zero && m23_zero;
let is_identity = is_diagonal && m00_one && m11_one && m22_one && m33_one;
let is_affine = m30_zero && m31_zero && m32_zero && m33_one;
let is_affine_translation = is_affine && m00_one && m11_one && m22_one && linear_is_diagonal;
let affine_linear_diagonal_is_definitely_nonzero = if true {
matches!(matrix[0][0].zero_status(), ZeroStatus::NonZero)
&& matches!(matrix[1][1].zero_status(), ZeroStatus::NonZero)
&& matches!(matrix[2][2].zero_status(), ZeroStatus::NonZero)
} else {
false
};
let exact = crate::kernels::exact_real_set_facts(
(0..4).flat_map(|row| (0..4).map(move |col| &matrix[row][col])),
);
let (zero_mask, row_zero_masks, column_zero_masks) =
matrix_zero_masks_assuming_size::<N, 4>(matrix);
let one_mask = matrix_one_mask_assuming_size::<N, 4>(matrix);
let translation_xyz_zero = [m03_zero, m13_zero, m23_zero];
let signed_permutation_rows = matrix4_signed_permutation_rows_assuming_size(matrix);
let transform_kind = matrix4_transform_kind(
is_identity,
is_affine,
is_affine_translation,
linear_is_diagonal,
signed_permutation_rows,
);
let public = Matrix4StructuralFacts {
exact,
symbolic_dependencies: matrix_symbolic_dependency_mask_assuming_size::<N, 4>(matrix),
zero_mask,
one_mask,
row_zero_masks,
column_zero_masks,
is_identity,
is_diagonal,
is_exact_rational_uniform_scale: matrix4_exact_rational_uniform_scale_assuming_size(
matrix,
is_diagonal,
),
is_upper_triangular,
is_lower_triangular,
is_affine,
is_affine_translation,
linear_is_diagonal,
direction_linear_is_diagonal,
signed_permutation_rows,
translation_xyz_zero,
transform_kind,
};
Matrix4Facts {
public,
exact,
is_identity,
is_diagonal,
is_upper_triangular,
is_lower_triangular,
linear_is_diagonal,
direction_linear_is_diagonal,
is_definitely_dense_for_inverse,
translation_xyz_zero,
is_affine,
is_affine_translation,
affine_linear_diagonal_is_definitely_nonzero,
}
}
fn map_array2<const N: usize, F>(left: [Real; N], right: [Real; N], mut op: F) -> [Real; N]
where
F: FnMut(Real, Real) -> Real,
{
let mut right = right.into_iter();
left.map(|lhs| op(lhs, right.next().expect("arrays have equal length")))
}
fn map_array_ref<const N: usize, F>(left: [Real; N], right: &[Real; N], mut op: F) -> [Real; N]
where
F: FnMut(Real, &Real) -> Real,
{
let mut right = right.iter();
left.map(|lhs| op(lhs, right.next().expect("arrays have equal length")))
}
fn map_matrix2<const N: usize, F>(
left: [[Real; N]; N],
right: [[Real; N]; N],
mut op: F,
) -> [[Real; N]; N]
where
F: FnMut(Real, Real) -> Real,
{
let mut right = right.into_iter();
left.map(|lhs_row| {
map_array2(
lhs_row,
right.next().expect("matrices have equal row counts"),
&mut op,
)
})
}
fn map_matrix_ref<const N: usize, F>(
left: [[Real; N]; N],
right: &[[Real; N]; N],
mut op: F,
) -> [[Real; N]; N]
where
F: FnMut(Real, &Real) -> Real,
{
let mut right = right.iter();
left.map(|lhs_row| {
map_array_ref(
lhs_row,
right.next().expect("matrices have equal row counts"),
&mut op,
)
})
}
fn map_matrix_left_ref<const N: usize, F>(
left: &[[Real; N]; N],
right: [[Real; N]; N],
mut op: F,
) -> [[Real; N]; N]
where
F: FnMut(&Real, Real) -> Real,
{
let mut left = left.iter();
right.map(|rhs_row| {
let mut left_row = left.next().expect("matrices have equal row counts").iter();
rhs_row.map(|rhs| op(left_row.next().expect("arrays have equal length"), rhs))
})
}
#[inline]
fn matrix_power_with<const N: usize, F>(
base: [[Real; N]; N],
exponent: u32,
mut multiply: F,
) -> [[Real; N]; N]
where
F: FnMut([[Real; N]; N], [[Real; N]; N]) -> [[Real; N]; N],
{
match exponent {
0 => return identity_array(),
1 => return base,
2 => return multiply(base.clone(), base),
3 => {
let square = multiply(base.clone(), base.clone());
return multiply(square, base);
}
4 => {
let square = multiply(base.clone(), base);
return multiply(square.clone(), square);
}
_ => {}
}
let mut exp = exponent;
let mut result = None;
let mut factor = base;
while exp > 0 {
if exp & 1 == 1 {
result = Some(match result {
Some(result) => multiply(result, factor.clone()),
None => factor.clone(),
});
}
exp >>= 1;
if exp > 0 {
factor = multiply(factor.clone(), factor);
}
}
result.expect("positive exponent sets at least one result bit")
}
#[inline]
fn matrix_power3(base: [[Real; 3]; 3], exponent: u32) -> [[Real; 3]; 3] {
crate::trace_dispatch!("hyperlattice_matrix", "helper", "matrix-power3-fixed-mul");
if exponent == 2 {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"matrix-power3-borrowed-square"
);
if true && matrix3_has_dense_multiply_certificate(&base) {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"matrix-power3-dense-certified-square"
);
return multiply_arrays3_dense_ref(&base, &base);
}
return multiply_arrays3_ref(&base, &base);
}
if exponent == 3 {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"matrix-power3-borrowed-cube"
);
if true && matrix3_has_dense_multiply_certificate(&base) {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"matrix-power3-dense-certified-cube"
);
let square = multiply_arrays3_dense_ref(&base, &base);
return multiply_arrays3_rhs_ref_with_exact_dense_certificate(square, &base);
}
let square = multiply_arrays3_ref(&base, &base);
return multiply_arrays3_rhs_ref(square, &base);
}
matrix_power_with(base, exponent, multiply_arrays3)
}
#[inline]
fn matrix_power4(base: [[Real; 4]; 4], exponent: u32) -> [[Real; 4]; 4] {
crate::trace_dispatch!("hyperlattice_matrix", "helper", "matrix-power4-fixed-mul");
if exponent == 2 {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"matrix-power4-borrowed-square"
);
if true && matrix4_has_dense_multiply_certificate(&base) {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"matrix-power4-dense-certified-square"
);
return multiply_arrays4_dense_ref(&base, &base);
}
return multiply_arrays4_ref(&base, &base);
}
if exponent == 3 {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"matrix-power4-borrowed-cube"
);
if true && matrix4_has_dense_multiply_certificate(&base) {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"matrix-power4-dense-certified-cube"
);
let square = multiply_arrays4_dense_ref(&base, &base);
return multiply_arrays4_rhs_ref_with_dense_certificate(square, &base);
}
let square = multiply_arrays4_ref(&base, &base);
return multiply_arrays4_rhs_ref(square, &base);
}
matrix_power_with(base, exponent, multiply_arrays4)
}
#[inline]
fn matrix_power4_known_rational(base: [[Real; 4]; 4], exponent: u32) -> [[Real; 4]; 4] {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"matrix-power4-known-rational"
);
if true {
if exponent == 2 {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"matrix-power4-known-rational-square"
);
return multiply_arrays4_dense_known_rational_ref(&base, &base);
}
if exponent == 3 {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"matrix-power4-known-rational-cube"
);
let square = multiply_arrays4_dense_known_rational_ref(&base, &base);
return multiply_arrays4_dense_known_rational_ref(&square, &base);
}
}
matrix_power4(base, exponent)
}
fn ordinary_pivot<const N: usize>(left: &[[Real; N]; N], col: usize) -> Option<usize> {
let mut unknown = None;
match zero_status(&left[col][col]) {
ZeroStatus::NonZero => return Some(col),
ZeroStatus::Unknown => unknown = Some(col),
ZeroStatus::Zero => {}
}
for (row, values) in left.iter().enumerate().skip(col + 1) {
match zero_status(&values[col]) {
ZeroStatus::NonZero => return Some(row),
ZeroStatus::Unknown if unknown.is_none() => unknown = Some(row),
ZeroStatus::Zero | ZeroStatus::Unknown => {}
}
}
unknown
}
fn checked_pivot<const N: usize, F>(
left: &[[Real; N]; N],
col: usize,
mut classify: F,
) -> CheckedBlasResult<usize>
where
F: FnMut(&Real) -> ZeroStatus,
{
let mut has_unknown = false;
for (row, values) in left.iter().enumerate().skip(col) {
match classify(&values[col]) {
ZeroStatus::NonZero => return Ok(row),
ZeroStatus::Unknown => has_unknown = true,
ZeroStatus::Zero => {}
}
}
if has_unknown {
Err(Problem::UnknownZero)
} else {
Err(Problem::DivideByZero)
}
}
fn scale_entry_in_place(value: &mut Real, factor: &Real) {
let current = mem::replace(value, Real::zero());
*value = current.mul_cached(factor);
}
fn subtract_scaled_entry_in_place(value: &mut Real, pivot: &Real, factor: &Real) {
let current = mem::replace(value, Real::zero());
*value = current - pivot * factor;
}
macro_rules! impl_solve_left_system_fixed {
(
$solve_fn:ident,
$solve_checked_fn:ident,
$solve_abort_fn:ident,
$n:expr
) => {
fn $solve_fn(
coefficients: [[Real; $n]; $n],
rhs: [[Real; $n]; $n],
) -> BlasResult<[[Real; $n]; $n]> {
let mut left = coefficients;
let mut right = rhs;
for col in 0..$n {
let Some(pivot) = ordinary_pivot(&left, col) else {
return Err(Problem::DivideByZero);
};
if pivot != col {
left.swap(col, pivot);
right.swap(col, pivot);
}
let pivot = mem::replace(&mut left[col][col], Real::one());
let inv_pivot = pivot.inverse()?;
for i in 0..$n {
scale_entry_in_place(&mut right[col][i], &inv_pivot);
}
for i in (col + 1)..$n {
scale_entry_in_place(&mut left[col][i], &inv_pivot);
}
let pivot_left = left[col].clone();
let pivot_right = right[col].clone();
for row in 0..$n {
if row == col {
continue;
}
if left[row][col].definitely_zero() {
continue;
}
let factor = mem::replace(&mut left[row][col], Real::zero());
for i in (col + 1)..$n {
subtract_scaled_entry_in_place(&mut left[row][i], &pivot_left[i], &factor);
}
for i in 0..$n {
subtract_scaled_entry_in_place(
&mut right[row][i],
&pivot_right[i],
&factor,
);
}
}
}
Ok(right)
}
fn $solve_checked_fn(
coefficients: [[Real; $n]; $n],
rhs: [[Real; $n]; $n],
) -> CheckedBlasResult<[[Real; $n]; $n]> {
let mut left = coefficients;
let mut right = rhs;
for col in 0..$n {
let pivot = checked_pivot(&left, col, zero_status)?;
if pivot != col {
left.swap(col, pivot);
right.swap(col, pivot);
}
let pivot = mem::replace(&mut left[col][col], Real::one());
let inv_pivot = pivot.inverse()?;
for i in 0..$n {
scale_entry_in_place(&mut right[col][i], &inv_pivot);
}
for i in (col + 1)..$n {
scale_entry_in_place(&mut left[col][i], &inv_pivot);
}
let pivot_left = left[col].clone();
let pivot_right = right[col].clone();
for row in 0..$n {
if row == col {
continue;
}
if left[row][col].definitely_zero() {
continue;
}
let factor = mem::replace(&mut left[row][col], Real::zero());
for i in (col + 1)..$n {
subtract_scaled_entry_in_place(&mut left[row][i], &pivot_left[i], &factor);
}
for i in 0..$n {
subtract_scaled_entry_in_place(
&mut right[row][i],
&pivot_right[i],
&factor,
);
}
}
}
Ok(right)
}
fn $solve_abort_fn(
coefficients: [[Real; $n]; $n],
rhs: [[Real; $n]; $n],
signal: &AbortSignal,
) -> CheckedBlasResult<[[Real; $n]; $n]> {
let mut left = coefficients;
let mut right = rhs;
for col in 0..$n {
let pivot =
checked_pivot(&left, col, |value| zero_status_with_abort(value, signal))?;
if pivot != col {
left.swap(col, pivot);
right.swap(col, pivot);
}
let pivot = mem::replace(&mut left[col][col], Real::one());
let inv_pivot = clone_with_abort(&pivot, signal).inverse()?;
for i in 0..$n {
scale_entry_in_place(&mut right[col][i], &inv_pivot);
}
for i in (col + 1)..$n {
scale_entry_in_place(&mut left[col][i], &inv_pivot);
}
let pivot_left = left[col].clone();
let pivot_right = right[col].clone();
for row in 0..$n {
if row == col {
continue;
}
if left[row][col].definitely_zero() {
continue;
}
let factor = mem::replace(&mut left[row][col], Real::zero());
for i in (col + 1)..$n {
subtract_scaled_entry_in_place(&mut left[row][i], &pivot_left[i], &factor);
}
for i in 0..$n {
subtract_scaled_entry_in_place(
&mut right[row][i],
&pivot_right[i],
&factor,
);
}
}
}
Ok(right)
}
};
}
impl_solve_left_system_fixed!(
solve_left_system3,
solve_left_system3_checked,
solve_left_system3_checked_with_abort,
3
);
impl_solve_left_system_fixed!(
solve_left_system4,
solve_left_system4_checked,
solve_left_system4_checked_with_abort,
4
);
fn prefer_shared_adjugate_right_division<const N: usize>(
left: &[[Real; N]; N],
right: &[[Real; N]; N],
) -> bool {
let right_kind = matrix_exact_rational_kind(right);
if right_kind == ExactRationalKind::NonRational {
return false;
}
if true && N == 4 {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide4-exact-right-skip-left-kind"
);
return true;
}
if true && N == 3 && right_kind == ExactRationalKind::ExactRational {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide3-exact-right-skip-left-kind"
);
return true;
}
let left_kind = matrix_exact_rational_kind(left);
matches!(
combine_exact_rational_kind(left_kind, right_kind),
ExactRationalKind::ExactDyadicRational | ExactRationalKind::ExactRational
)
}
fn prefer_shared_adjugate_right_division_ref3(
left: &[[Real; 3]; 3],
right: &[[Real; 3]; 3],
) -> bool {
let right_kind = matrix3_exact_rational_kind(right);
if right_kind == ExactRationalKind::NonRational {
return false;
}
if true && right_kind == ExactRationalKind::ExactRational {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide3-ref-exact-right-skip-left-kind"
);
return true;
}
let left_kind = matrix3_exact_rational_kind(left);
matches!(
combine_exact_rational_kind(left_kind, right_kind),
ExactRationalKind::ExactDyadicRational | ExactRationalKind::ExactRational
)
}
#[inline]
fn matrix4_direction_linear_is_diagonal(matrix: &[[Real; 4]; 4]) -> bool {
matrix[0][1].definitely_zero()
&& matrix[0][2].definitely_zero()
&& matrix[1][0].definitely_zero()
&& matrix[1][2].definitely_zero()
&& matrix[2][0].definitely_zero()
&& matrix[2][1].definitely_zero()
&& matrix[3][0].definitely_zero()
&& matrix[3][1].definitely_zero()
&& matrix[3][2].definitely_zero()
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
enum Matrix4DirectionLinearKind {
Identity,
Diagonal,
General,
}
#[inline]
fn matrix4_direction_linear_kind(matrix: &[[Real; 4]; 4]) -> Matrix4DirectionLinearKind {
if !matrix4_direction_linear_is_diagonal(matrix) {
return Matrix4DirectionLinearKind::General;
}
if matrix[0][0].definitely_one()
&& matrix[1][1].definitely_one()
&& matrix[2][2].definitely_one()
{
Matrix4DirectionLinearKind::Identity
} else {
Matrix4DirectionLinearKind::Diagonal
}
}
#[inline]
fn matrix4_affine_linear_is_diagonal(matrix: &[[Real; 4]; 4]) -> bool {
matrix[0][1].definitely_zero()
&& matrix[0][2].definitely_zero()
&& matrix[1][0].definitely_zero()
&& matrix[1][2].definitely_zero()
&& matrix[2][0].definitely_zero()
&& matrix[2][1].definitely_zero()
&& matrix[3][0].definitely_zero()
&& matrix[3][1].definitely_zero()
&& matrix[3][2].definitely_zero()
&& matrix[3][3].definitely_one()
}
#[inline]
fn matrix3_is_definitely_dense_for_inverse(matrix: &[[Real; 3]; 3]) -> bool {
matches!(matrix[1][0].zero_status(), ZeroStatus::NonZero)
&& matches!(matrix[0][1].zero_status(), ZeroStatus::NonZero)
&& matches!(matrix[2][0].zero_status(), ZeroStatus::NonZero)
}
#[inline]
fn matrix4_is_definitely_dense_for_inverse(matrix: &[[Real; 4]; 4]) -> bool {
matches!(matrix[1][0].zero_status(), ZeroStatus::NonZero)
&& matches!(matrix[0][1].zero_status(), ZeroStatus::NonZero)
&& matches!(matrix[3][0].zero_status(), ZeroStatus::NonZero)
}
#[inline]
fn matrix3_has_dense_multiply_certificate(matrix: &[[Real; 3]; 3]) -> bool {
matches!(matrix[1][0].zero_status(), ZeroStatus::NonZero)
&& matches!(matrix[0][1].zero_status(), ZeroStatus::NonZero)
&& matches!(matrix[2][0].zero_status(), ZeroStatus::NonZero)
}
#[inline]
fn matrix4_has_dense_multiply_certificate(matrix: &[[Real; 4]; 4]) -> bool {
matches!(matrix[1][0].zero_status(), ZeroStatus::NonZero)
&& matches!(matrix[0][1].zero_status(), ZeroStatus::NonZero)
&& matches!(matrix[3][0].zero_status(), ZeroStatus::NonZero)
}
#[inline]
fn multiply_arrays4_ref_with_dense_certificate(
left: &[[Real; 4]; 4],
right: &[[Real; 4]; 4],
) -> [[Real; 4]; 4] {
if true
&& matrix4_has_dense_multiply_certificate(left)
&& matrix4_has_dense_multiply_certificate(right)
{
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"multiply4-dense-certified-ref"
);
return multiply_arrays4_dense_ref(left, right);
}
multiply_arrays4_ref(left, right)
}
#[inline]
fn multiply_arrays4_rhs_ref_with_dense_certificate(
left: [[Real; 4]; 4],
right: &[[Real; 4]; 4],
) -> [[Real; 4]; 4] {
if true
&& matrix4_has_dense_multiply_certificate(&left)
&& matrix4_has_dense_multiply_certificate(right)
{
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"multiply4-dense-certified-owned-ref"
);
return multiply_arrays4_dense_ref(&left, right);
}
multiply_arrays4_rhs_ref(left, right)
}
#[inline]
fn invert_matrix4_affine_linear_diagonal(matrix: &[[Real; 4]; 4]) -> BlasResult<[[Real; 4]; 4]> {
let inv00 = matrix[0][0].clone().inverse()?;
let inv11 = matrix[1][1].clone().inverse()?;
let inv22 = matrix[2][2].clone().inverse()?;
let inv_tx = Real::zero() - (&matrix[0][3] * &inv00);
let inv_ty = Real::zero() - (&matrix[1][3] * &inv11);
let inv_tz = Real::zero() - (&matrix[2][3] * &inv22);
Ok([
[inv00, Real::zero(), Real::zero(), inv_tx],
[Real::zero(), inv11, Real::zero(), inv_ty],
[Real::zero(), Real::zero(), inv22, inv_tz],
[Real::zero(), Real::zero(), Real::zero(), Real::one()],
])
}
#[inline]
fn invert_matrix4_affine_linear_diagonal_checked(
matrix: &[[Real; 4]; 4],
) -> CheckedBlasResult<[[Real; 4]; 4]> {
require_known_nonzero(&matrix[0][0])?;
require_known_nonzero(&matrix[1][1])?;
require_known_nonzero(&matrix[2][2])?;
invert_matrix4_affine_linear_diagonal(matrix)
}
#[inline]
fn invert_matrix4_affine_linear_diagonal_checked_with_abort(
matrix: &[[Real; 4]; 4],
signal: &AbortSignal,
) -> CheckedBlasResult<[[Real; 4]; 4]> {
require_known_nonzero_with_abort(&matrix[0][0], signal)?;
require_known_nonzero_with_abort(&matrix[1][1], signal)?;
require_known_nonzero_with_abort(&matrix[2][2], signal)?;
invert_matrix4_affine_linear_diagonal(matrix)
}
#[inline]
fn invert_matrix4_affine(
matrix: &[[Real; 4]; 4],
linear_is_diagonal: bool,
is_affine_translation: bool,
) -> BlasResult<[[Real; 4]; 4]> {
if linear_is_diagonal {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"invert-matrix4-affine-linear-diagonal"
);
return invert_matrix4_affine_linear_diagonal(matrix);
}
if is_affine_translation {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"invert-matrix4-affine-translation"
);
return Ok([
[
matrix[0][0].clone(),
matrix[0][1].clone(),
matrix[0][2].clone(),
Real::zero() - &matrix[0][3],
],
[
matrix[1][0].clone(),
matrix[1][1].clone(),
matrix[1][2].clone(),
Real::zero() - &matrix[1][3],
],
[
matrix[2][0].clone(),
matrix[2][1].clone(),
matrix[2][2].clone(),
Real::zero() - &matrix[2][3],
],
[Real::zero(), Real::zero(), Real::zero(), Real::one()],
]);
}
invert_matrix4_affine_without_translation(matrix)
}
#[inline]
fn invert_matrix4_affine_without_translation(
matrix: &[[Real; 4]; 4],
) -> BlasResult<[[Real; 4]; 4]> {
let linear = [
[
matrix[0][0].clone(),
matrix[0][1].clone(),
matrix[0][2].clone(),
],
[
matrix[1][0].clone(),
matrix[1][1].clone(),
matrix[1][2].clone(),
],
[
matrix[2][0].clone(),
matrix[2][1].clone(),
matrix[2][2].clone(),
],
];
let translation = [
matrix[0][3].clone(),
matrix[1][3].clone(),
matrix[2][3].clone(),
];
let inverse_linear = invert_matrix3(linear)?;
let inverse_translation: [Real; 3] = from_fn(|row| {
let shifted = affine_translation_dot3(
[
&inverse_linear[row][0],
&inverse_linear[row][1],
&inverse_linear[row][2],
],
[&translation[0], &translation[1], &translation[2]],
);
Real::zero() - shifted
});
Ok([
[
inverse_linear[0][0].clone(),
inverse_linear[0][1].clone(),
inverse_linear[0][2].clone(),
inverse_translation[0].clone(),
],
[
inverse_linear[1][0].clone(),
inverse_linear[1][1].clone(),
inverse_linear[1][2].clone(),
inverse_translation[1].clone(),
],
[
inverse_linear[2][0].clone(),
inverse_linear[2][1].clone(),
inverse_linear[2][2].clone(),
inverse_translation[2].clone(),
],
[Real::zero(), Real::zero(), Real::zero(), Real::one()],
])
}
#[inline]
fn invert_matrix4_affine_checked(
matrix: &[[Real; 4]; 4],
linear_is_diagonal: bool,
is_affine_translation: bool,
) -> CheckedBlasResult<[[Real; 4]; 4]> {
if linear_is_diagonal {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"invert-matrix4-checked-affine-linear-diagonal"
);
return invert_matrix4_affine_linear_diagonal_checked(matrix);
}
if is_affine_translation {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"invert-matrix4-checked-affine-translation"
);
return Ok([
[
matrix[0][0].clone(),
matrix[0][1].clone(),
matrix[0][2].clone(),
Real::zero() - &matrix[0][3],
],
[
matrix[1][0].clone(),
matrix[1][1].clone(),
matrix[1][2].clone(),
Real::zero() - &matrix[1][3],
],
[
matrix[2][0].clone(),
matrix[2][1].clone(),
matrix[2][2].clone(),
Real::zero() - &matrix[2][3],
],
[Real::zero(), Real::zero(), Real::zero(), Real::one()],
]);
}
invert_matrix4_affine_without_translation_checked(matrix)
}
#[inline]
fn invert_matrix4_affine_without_translation_checked(
matrix: &[[Real; 4]; 4],
) -> CheckedBlasResult<[[Real; 4]; 4]> {
let linear = [
[
matrix[0][0].clone(),
matrix[0][1].clone(),
matrix[0][2].clone(),
],
[
matrix[1][0].clone(),
matrix[1][1].clone(),
matrix[1][2].clone(),
],
[
matrix[2][0].clone(),
matrix[2][1].clone(),
matrix[2][2].clone(),
],
];
let translation = [
matrix[0][3].clone(),
matrix[1][3].clone(),
matrix[2][3].clone(),
];
let inverse_linear = invert_matrix3_checked(linear)?;
let inverse_translation: [Real; 3] = from_fn(|row| {
let shifted = affine_translation_dot3(
[
&inverse_linear[row][0],
&inverse_linear[row][1],
&inverse_linear[row][2],
],
[&translation[0], &translation[1], &translation[2]],
);
Real::zero() - shifted
});
Ok([
[
inverse_linear[0][0].clone(),
inverse_linear[0][1].clone(),
inverse_linear[0][2].clone(),
inverse_translation[0].clone(),
],
[
inverse_linear[1][0].clone(),
inverse_linear[1][1].clone(),
inverse_linear[1][2].clone(),
inverse_translation[1].clone(),
],
[
inverse_linear[2][0].clone(),
inverse_linear[2][1].clone(),
inverse_linear[2][2].clone(),
inverse_translation[2].clone(),
],
[Real::zero(), Real::zero(), Real::zero(), Real::one()],
])
}
#[inline]
fn invert_matrix4_affine_checked_with_abort(
matrix: &[[Real; 4]; 4],
signal: &AbortSignal,
linear_is_diagonal: bool,
is_affine_translation: bool,
) -> CheckedBlasResult<[[Real; 4]; 4]> {
if linear_is_diagonal {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"invert-matrix4-checked-with-abort-affine-linear-diagonal"
);
return invert_matrix4_affine_linear_diagonal_checked_with_abort(matrix, signal);
}
if is_affine_translation {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"invert-matrix4-checked-affine-translation"
);
return Ok([
[
matrix[0][0].clone(),
matrix[0][1].clone(),
matrix[0][2].clone(),
Real::zero() - &matrix[0][3],
],
[
matrix[1][0].clone(),
matrix[1][1].clone(),
matrix[1][2].clone(),
Real::zero() - &matrix[1][3],
],
[
matrix[2][0].clone(),
matrix[2][1].clone(),
matrix[2][2].clone(),
Real::zero() - &matrix[2][3],
],
[Real::zero(), Real::zero(), Real::zero(), Real::one()],
]);
}
invert_matrix4_affine_without_translation_checked_with_abort(matrix, signal)
}
#[inline]
fn invert_matrix4_affine_without_translation_checked_with_abort(
matrix: &[[Real; 4]; 4],
signal: &AbortSignal,
) -> CheckedBlasResult<[[Real; 4]; 4]> {
let linear = [
[
matrix[0][0].clone(),
matrix[0][1].clone(),
matrix[0][2].clone(),
],
[
matrix[1][0].clone(),
matrix[1][1].clone(),
matrix[1][2].clone(),
],
[
matrix[2][0].clone(),
matrix[2][1].clone(),
matrix[2][2].clone(),
],
];
let translation = [
matrix[0][3].clone(),
matrix[1][3].clone(),
matrix[2][3].clone(),
];
let inverse_linear = invert_matrix3_checked_with_abort(linear, signal)?;
let inverse_translation: [Real; 3] = from_fn(|row| {
let shifted = affine_translation_dot3(
[
&inverse_linear[row][0],
&inverse_linear[row][1],
&inverse_linear[row][2],
],
[&translation[0], &translation[1], &translation[2]],
);
Real::zero() - shifted
});
Ok([
[
inverse_linear[0][0].clone(),
inverse_linear[0][1].clone(),
inverse_linear[0][2].clone(),
inverse_translation[0].clone(),
],
[
inverse_linear[1][0].clone(),
inverse_linear[1][1].clone(),
inverse_linear[1][2].clone(),
inverse_translation[1].clone(),
],
[
inverse_linear[2][0].clone(),
inverse_linear[2][1].clone(),
inverse_linear[2][2].clone(),
inverse_translation[2].clone(),
],
[Real::zero(), Real::zero(), Real::zero(), Real::one()],
])
}
#[inline]
fn divide_matrix4_by_affine_linear_diagonal(
left: [[Real; 4]; 4],
right: &[[Real; 4]; 4],
) -> BlasResult<[[Real; 4]; 4]> {
let inv_a00 = right[0][0].clone().inverse()?;
let inv_a11 = right[1][1].clone().inverse()?;
let inv_a22 = right[2][2].clone().inverse()?;
let inv_tx = Real::zero() - (&right[0][3] * &inv_a00);
let inv_ty = Real::zero() - (&right[1][3] * &inv_a11);
let inv_tz = Real::zero() - (&right[2][3] * &inv_a22);
Ok([
[
{
let row = left[0][0].clone();
let row = row * &inv_a00;
row
},
{
let row = left[0][1].clone();
let row = row * &inv_a11;
row
},
{
let row = left[0][2].clone();
let row = row * &inv_a22;
row
},
{
let x = left[0][0].clone();
let y = left[0][1].clone();
let z = left[0][2].clone();
left[0][3].clone() + (&(x * &inv_tx) + &((y * &inv_ty) + &(z * &inv_tz)))
},
],
[
{
let row = left[1][0].clone();
let row = row * &inv_a00;
row
},
{
let row = left[1][1].clone();
let row = row * &inv_a11;
row
},
{
let row = left[1][2].clone();
let row = row * &inv_a22;
row
},
{
let x = left[1][0].clone();
let y = left[1][1].clone();
let z = left[1][2].clone();
left[1][3].clone() + (&(x * &inv_tx) + &((y * &inv_ty) + &(z * &inv_tz)))
},
],
[
{
let row = left[2][0].clone();
let row = row * &inv_a00;
row
},
{
let row = left[2][1].clone();
let row = row * &inv_a11;
row
},
{
let row = left[2][2].clone();
let row = row * &inv_a22;
row
},
{
let x = left[2][0].clone();
let y = left[2][1].clone();
let z = left[2][2].clone();
left[2][3].clone() + (&(x * &inv_tx) + &((y * &inv_ty) + &(z * &inv_tz)))
},
],
[
{
let row = left[3][0].clone();
let row = row * &inv_a00;
row
},
{
let row = left[3][1].clone();
let row = row * &inv_a11;
row
},
{
let row = left[3][2].clone();
let row = row * &inv_a22;
row
},
{
let x = left[3][0].clone();
let y = left[3][1].clone();
let z = left[3][2].clone();
left[3][3].clone() + (&(x * &inv_tx) + &((y * &inv_ty) + &(z * &inv_tz)))
},
],
])
}
#[inline]
fn divide_matrix4_by_affine_linear_diagonal_checked(
left: [[Real; 4]; 4],
right: &[[Real; 4]; 4],
) -> CheckedBlasResult<[[Real; 4]; 4]> {
require_known_nonzero(&right[0][0])?;
require_known_nonzero(&right[1][1])?;
require_known_nonzero(&right[2][2])?;
divide_matrix4_by_affine_linear_diagonal(left, right)
}
#[inline]
fn divide_matrix4_by_affine_linear_diagonal_checked_with_abort(
left: [[Real; 4]; 4],
right: &[[Real; 4]; 4],
signal: &AbortSignal,
) -> CheckedBlasResult<[[Real; 4]; 4]> {
require_known_nonzero_with_abort(&right[0][0], signal)?;
require_known_nonzero_with_abort(&right[1][1], signal)?;
require_known_nonzero_with_abort(&right[2][2], signal)?;
divide_matrix4_by_affine_linear_diagonal(left, right)
}
#[inline]
fn divide_matrix4_by_affine_linear_diagonal_ref(
left: &[[Real; 4]; 4],
right: &[[Real; 4]; 4],
) -> BlasResult<[[Real; 4]; 4]> {
let inv_a00 = right[0][0].clone().inverse()?;
let inv_a11 = right[1][1].clone().inverse()?;
let inv_a22 = right[2][2].clone().inverse()?;
let inv_tx = Real::zero() - (&right[0][3] * &inv_a00);
let inv_ty = Real::zero() - (&right[1][3] * &inv_a11);
let inv_tz = Real::zero() - (&right[2][3] * &inv_a22);
Ok([
[
{
let row = left[0][0].clone();
let row = row * &inv_a00;
row
},
{
let row = left[0][1].clone();
let row = row * &inv_a11;
row
},
{
let row = left[0][2].clone();
let row = row * &inv_a22;
row
},
{
let x = left[0][0].clone();
let y = left[0][1].clone();
let z = left[0][2].clone();
left[0][3].clone() + (&(x * &inv_tx) + &((y * &inv_ty) + &(z * &inv_tz)))
},
],
[
{
let row = left[1][0].clone();
let row = row * &inv_a00;
row
},
{
let row = left[1][1].clone();
let row = row * &inv_a11;
row
},
{
let row = left[1][2].clone();
let row = row * &inv_a22;
row
},
{
let x = left[1][0].clone();
let y = left[1][1].clone();
let z = left[1][2].clone();
left[1][3].clone() + (&(x * &inv_tx) + &((y * &inv_ty) + &(z * &inv_tz)))
},
],
[
{
let row = left[2][0].clone();
let row = row * &inv_a00;
row
},
{
let row = left[2][1].clone();
let row = row * &inv_a11;
row
},
{
let row = left[2][2].clone();
let row = row * &inv_a22;
row
},
{
let x = left[2][0].clone();
let y = left[2][1].clone();
let z = left[2][2].clone();
left[2][3].clone() + (&(x * &inv_tx) + &((y * &inv_ty) + &(z * &inv_tz)))
},
],
[
{
let row = left[3][0].clone();
let row = row * &inv_a00;
row
},
{
let row = left[3][1].clone();
let row = row * &inv_a11;
row
},
{
let row = left[3][2].clone();
let row = row * &inv_a22;
row
},
{
let x = left[3][0].clone();
let y = left[3][1].clone();
let z = left[3][2].clone();
left[3][3].clone() + (&(x * &inv_tx) + &((y * &inv_ty) + &(z * &inv_tz)))
},
],
])
}
fn divide_matrix4_affine_by_affine_linear_diagonal(
left: [[Real; 4]; 4],
right: &[[Real; 4]; 4],
) -> BlasResult<[[Real; 4]; 4]> {
divide_matrix4_by_affine_linear_diagonal(left, right)
}
#[inline]
fn divide_matrix4_affine_by_affine_ref_linear_diagonal(
left: &[[Real; 4]; 4],
right: &[[Real; 4]; 4],
) -> BlasResult<[[Real; 4]; 4]> {
divide_matrix4_by_affine_linear_diagonal_ref(left, right)
}
#[inline]
fn divide_matrix4_affine_by_affine_linear_diagonal_checked(
left: [[Real; 4]; 4],
right: &[[Real; 4]; 4],
) -> CheckedBlasResult<[[Real; 4]; 4]> {
divide_matrix4_by_affine_linear_diagonal_checked(left, right)
}
#[inline]
fn divide_matrix4_affine_by_affine_linear_diagonal_checked_with_abort(
left: [[Real; 4]; 4],
right: &[[Real; 4]; 4],
signal: &AbortSignal,
) -> CheckedBlasResult<[[Real; 4]; 4]> {
divide_matrix4_by_affine_linear_diagonal_checked_with_abort(left, right, signal)
}
#[inline]
fn affine_translation_column_update(row: &[Real; 4], inverse_translation: &[Real; 3]) -> Real {
let matrix_terms = [&row[0], &row[1], &row[2]];
let translation_terms = [
&inverse_translation[0],
&inverse_translation[1],
&inverse_translation[2],
];
row[3].clone() + Real::linear_combination3(matrix_terms, translation_terms)
}
#[inline]
fn affine_translation_column_subtract_update(row: &[Real; 4], translation: [&Real; 3]) -> Real {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"affine-translation-column-subtract"
);
let shifted = affine_translation_dot3([&row[0], &row[1], &row[2]], translation);
row[3].clone() - shifted
}
#[inline]
fn affine_translation_dot3(coefficients: [&Real; 3], values: [&Real; 3]) -> Real {
if true {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"affine-translation-dot3-active-exact"
);
Real::active_linear_combination3(coefficients, values)
} else {
(coefficients[0] * values[0]) + &(coefficients[1] * values[1] + coefficients[2] * values[2])
}
}
#[inline]
fn divide_matrix4_by_affine_no_translation(
left: [[Real; 4]; 4],
right: &[[Real; 4]; 4],
) -> BlasResult<[[Real; 4]; 4]> {
let inverse = invert_matrix4_affine_without_translation(right)?;
Ok(multiply_arrays4(left, inverse))
}
#[inline]
fn divide_matrix4_affine_by_affine_no_translation(
left: [[Real; 4]; 4],
right: &[[Real; 4]; 4],
) -> BlasResult<[[Real; 4]; 4]> {
let left_linear = [
[left[0][0].clone(), left[0][1].clone(), left[0][2].clone()],
[left[1][0].clone(), left[1][1].clone(), left[1][2].clone()],
[left[2][0].clone(), left[2][1].clone(), left[2][2].clone()],
];
let right_linear = [
[
right[0][0].clone(),
right[0][1].clone(),
right[0][2].clone(),
],
[
right[1][0].clone(),
right[1][1].clone(),
right[1][2].clone(),
],
[
right[2][0].clone(),
right[2][1].clone(),
right[2][2].clone(),
],
];
let right_translation = [
right[0][3].clone(),
right[1][3].clone(),
right[2][3].clone(),
];
let right_inverse_linear = invert_matrix3(right_linear)?;
let right_inverse_translation: [Real; 3] = from_fn(|row| {
let shifted = affine_translation_dot3(
[
&right_inverse_linear[row][0],
&right_inverse_linear[row][1],
&right_inverse_linear[row][2],
],
[
&right_translation[0],
&right_translation[1],
&right_translation[2],
],
);
Real::zero() - shifted
});
let linear = multiply_arrays3_affine_linear_with_exact_dense_certificate(
left_linear,
right_inverse_linear,
);
let translation: [Real; 3] = from_fn(|row| {
let shifted = affine_translation_dot3(
[&left[row][0], &left[row][1], &left[row][2]],
[
&right_inverse_translation[0],
&right_inverse_translation[1],
&right_inverse_translation[2],
],
);
left[row][3].clone() + shifted
});
Ok([
[
linear[0][0].clone(),
linear[0][1].clone(),
linear[0][2].clone(),
translation[0].clone(),
],
[
linear[1][0].clone(),
linear[1][1].clone(),
linear[1][2].clone(),
translation[1].clone(),
],
[
linear[2][0].clone(),
linear[2][1].clone(),
linear[2][2].clone(),
translation[2].clone(),
],
[Real::zero(), Real::zero(), Real::zero(), Real::one()],
])
}
#[inline]
fn divide_matrix4_by_affine_translation(
left: [[Real; 4]; 4],
right: &[[Real; 4]; 4],
) -> BlasResult<[[Real; 4]; 4]> {
if true {
let translation = [&right[0][3], &right[1][3], &right[2][3]];
return Ok([
[
left[0][0].clone(),
left[0][1].clone(),
left[0][2].clone(),
affine_translation_column_subtract_update(&left[0], translation),
],
[
left[1][0].clone(),
left[1][1].clone(),
left[1][2].clone(),
affine_translation_column_subtract_update(&left[1], translation),
],
[
left[2][0].clone(),
left[2][1].clone(),
left[2][2].clone(),
affine_translation_column_subtract_update(&left[2], translation),
],
[
left[3][0].clone(),
left[3][1].clone(),
left[3][2].clone(),
affine_translation_column_subtract_update(&left[3], translation),
],
]);
}
let inverse_translation = [
Real::zero() - &right[0][3],
Real::zero() - &right[1][3],
Real::zero() - &right[2][3],
];
Ok([
[
left[0][0].clone(),
left[0][1].clone(),
left[0][2].clone(),
affine_translation_column_update(&left[0], &inverse_translation),
],
[
left[1][0].clone(),
left[1][1].clone(),
left[1][2].clone(),
affine_translation_column_update(&left[1], &inverse_translation),
],
[
left[2][0].clone(),
left[2][1].clone(),
left[2][2].clone(),
affine_translation_column_update(&left[2], &inverse_translation),
],
[
left[3][0].clone(),
left[3][1].clone(),
left[3][2].clone(),
affine_translation_column_update(&left[3], &inverse_translation),
],
])
}
#[inline]
fn multiply_arrays3_affine_linear_with_exact_dense_certificate(
left: [[Real; 3]; 3],
right: [[Real; 3]; 3],
) -> [[Real; 3]; 3] {
if true
&& matrix3_has_dense_multiply_certificate(&left)
&& matrix3_has_dense_multiply_certificate(&right)
{
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"multiply3-affine-linear-dense-certified-exact"
);
return multiply_arrays3_dense_ref(&left, &right);
}
multiply_arrays3(left, right)
}
#[inline]
fn divide_matrix4_affine_by_affine_translation(
left: [[Real; 4]; 4],
right: &[[Real; 4]; 4],
) -> BlasResult<[[Real; 4]; 4]> {
if true {
let translation = [&right[0][3], &right[1][3], &right[2][3]];
return Ok([
[
left[0][0].clone(),
left[0][1].clone(),
left[0][2].clone(),
affine_translation_column_subtract_update(&left[0], translation),
],
[
left[1][0].clone(),
left[1][1].clone(),
left[1][2].clone(),
affine_translation_column_subtract_update(&left[1], translation),
],
[
left[2][0].clone(),
left[2][1].clone(),
left[2][2].clone(),
affine_translation_column_subtract_update(&left[2], translation),
],
[Real::zero(), Real::zero(), Real::zero(), Real::one()],
]);
}
let inverse_translation = [
Real::zero() - &right[0][3],
Real::zero() - &right[1][3],
Real::zero() - &right[2][3],
];
Ok([
[
left[0][0].clone(),
left[0][1].clone(),
left[0][2].clone(),
affine_translation_column_update(&left[0], &inverse_translation),
],
[
left[1][0].clone(),
left[1][1].clone(),
left[1][2].clone(),
affine_translation_column_update(&left[1], &inverse_translation),
],
[
left[2][0].clone(),
left[2][1].clone(),
left[2][2].clone(),
affine_translation_column_update(&left[2], &inverse_translation),
],
[Real::zero(), Real::zero(), Real::zero(), Real::one()],
])
}
#[inline]
fn divide_matrix4_by_affine_checked(
left: [[Real; 4]; 4],
right: &[[Real; 4]; 4],
) -> CheckedBlasResult<[[Real; 4]; 4]> {
divide_matrix4_by_affine_no_translation_checked(left, right)
}
#[inline]
fn divide_matrix4_by_affine_checked_assumed_affine_translation(
left: [[Real; 4]; 4],
right: &[[Real; 4]; 4],
) -> CheckedBlasResult<[[Real; 4]; 4]> {
divide_matrix4_by_affine_checked_assuming_affine_translation(left, right)
}
#[inline]
fn divide_matrix4_by_affine_checked_assuming_affine_translation(
left: [[Real; 4]; 4],
right: &[[Real; 4]; 4],
) -> CheckedBlasResult<[[Real; 4]; 4]> {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide4-checked-by-affine-translation"
);
Ok(divide_matrix4_by_affine_translation(left, right)?)
}
#[inline]
fn divide_matrix4_by_affine_no_translation_checked(
left: [[Real; 4]; 4],
right: &[[Real; 4]; 4],
) -> CheckedBlasResult<[[Real; 4]; 4]> {
let inverse = invert_matrix4_affine_without_translation_checked(right)?;
Ok(multiply_arrays4(left, inverse))
}
#[inline]
fn divide_matrix4_affine_by_affine_checked(
left: [[Real; 4]; 4],
right: &[[Real; 4]; 4],
) -> CheckedBlasResult<[[Real; 4]; 4]> {
divide_matrix4_affine_by_affine_no_translation_checked(left, right)
}
#[inline]
fn divide_matrix4_affine_by_affine_checked_assumed_affine_translation(
left: [[Real; 4]; 4],
right: &[[Real; 4]; 4],
) -> CheckedBlasResult<[[Real; 4]; 4]> {
divide_matrix4_affine_by_affine_checked_assuming_affine_translation(left, right)
}
fn divide_matrix4_affine_by_affine_checked_assuming_affine_translation(
left: [[Real; 4]; 4],
right: &[[Real; 4]; 4],
) -> CheckedBlasResult<[[Real; 4]; 4]> {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide4-checked-affine-by-affine-translation"
);
Ok(divide_matrix4_affine_by_affine_translation(left, right)?)
}
#[inline]
fn divide_matrix4_affine_by_affine_no_translation_checked(
left: [[Real; 4]; 4],
right: &[[Real; 4]; 4],
) -> CheckedBlasResult<[[Real; 4]; 4]> {
let left_linear = [
[left[0][0].clone(), left[0][1].clone(), left[0][2].clone()],
[left[1][0].clone(), left[1][1].clone(), left[1][2].clone()],
[left[2][0].clone(), left[2][1].clone(), left[2][2].clone()],
];
let right_linear = [
[
right[0][0].clone(),
right[0][1].clone(),
right[0][2].clone(),
],
[
right[1][0].clone(),
right[1][1].clone(),
right[1][2].clone(),
],
[
right[2][0].clone(),
right[2][1].clone(),
right[2][2].clone(),
],
];
let right_translation = [
right[0][3].clone(),
right[1][3].clone(),
right[2][3].clone(),
];
let right_inverse_linear = invert_matrix3_checked(right_linear)?;
let right_inverse_translation: [Real; 3] = from_fn(|row| {
let shifted = affine_translation_dot3(
[
&right_inverse_linear[row][0],
&right_inverse_linear[row][1],
&right_inverse_linear[row][2],
],
[
&right_translation[0],
&right_translation[1],
&right_translation[2],
],
);
Real::zero() - shifted
});
let linear = multiply_arrays3_affine_linear_with_exact_dense_certificate(
left_linear,
right_inverse_linear,
);
let translation: [Real; 3] = from_fn(|row| {
let shifted = affine_translation_dot3(
[&left[row][0], &left[row][1], &left[row][2]],
[
&right_inverse_translation[0],
&right_inverse_translation[1],
&right_inverse_translation[2],
],
);
left[row][3].clone() + shifted
});
Ok([
[
linear[0][0].clone(),
linear[0][1].clone(),
linear[0][2].clone(),
translation[0].clone(),
],
[
linear[1][0].clone(),
linear[1][1].clone(),
linear[1][2].clone(),
translation[1].clone(),
],
[
linear[2][0].clone(),
linear[2][1].clone(),
linear[2][2].clone(),
translation[2].clone(),
],
[Real::zero(), Real::zero(), Real::zero(), Real::one()],
])
}
#[inline]
fn divide_matrix4_by_affine_checked_with_abort(
left: [[Real; 4]; 4],
right: &[[Real; 4]; 4],
signal: &AbortSignal,
) -> CheckedBlasResult<[[Real; 4]; 4]> {
divide_matrix4_by_affine_no_translation_checked_with_abort(left, right, signal)
}
#[inline]
fn divide_matrix4_by_affine_checked_with_abort_assumed_affine_translation(
left: [[Real; 4]; 4],
right: &[[Real; 4]; 4],
signal: &AbortSignal,
) -> CheckedBlasResult<[[Real; 4]; 4]> {
divide_matrix4_by_affine_checked_with_abort_assuming_affine_translation(left, right, signal)
}
#[inline]
fn divide_matrix4_by_affine_checked_with_abort_assuming_affine_translation(
left: [[Real; 4]; 4],
right: &[[Real; 4]; 4],
_signal: &AbortSignal,
) -> CheckedBlasResult<[[Real; 4]; 4]> {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide4-checked-abort-by-affine-translation"
);
Ok(divide_matrix4_by_affine_translation(left, right)?)
}
#[inline]
fn divide_matrix4_by_affine_no_translation_checked_with_abort(
left: [[Real; 4]; 4],
right: &[[Real; 4]; 4],
signal: &AbortSignal,
) -> CheckedBlasResult<[[Real; 4]; 4]> {
let inverse = invert_matrix4_affine_without_translation_checked_with_abort(right, signal)?;
Ok(multiply_arrays4(left, inverse))
}
#[inline]
fn divide_matrix4_affine_by_affine_checked_with_abort(
left: [[Real; 4]; 4],
right: &[[Real; 4]; 4],
signal: &AbortSignal,
) -> CheckedBlasResult<[[Real; 4]; 4]> {
divide_matrix4_affine_by_affine_no_translation_checked_with_abort(left, right, signal)
}
#[inline]
fn divide_matrix4_affine_by_affine_checked_with_abort_assumed_affine_translation(
left: [[Real; 4]; 4],
right: &[[Real; 4]; 4],
signal: &AbortSignal,
) -> CheckedBlasResult<[[Real; 4]; 4]> {
divide_matrix4_affine_by_affine_checked_with_abort_assuming_affine_translation(
left, right, signal,
)
}
#[inline]
fn divide_matrix4_affine_by_affine_checked_with_abort_assuming_affine_translation(
left: [[Real; 4]; 4],
right: &[[Real; 4]; 4],
_signal: &AbortSignal,
) -> CheckedBlasResult<[[Real; 4]; 4]> {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide4-checked-abort-affine-by-affine-translation"
);
Ok(divide_matrix4_affine_by_affine_translation(left, right)?)
}
#[inline]
fn divide_matrix4_affine_by_affine_no_translation_checked_with_abort(
left: [[Real; 4]; 4],
right: &[[Real; 4]; 4],
signal: &AbortSignal,
) -> CheckedBlasResult<[[Real; 4]; 4]> {
let left_linear = [
[left[0][0].clone(), left[0][1].clone(), left[0][2].clone()],
[left[1][0].clone(), left[1][1].clone(), left[1][2].clone()],
[left[2][0].clone(), left[2][1].clone(), left[2][2].clone()],
];
let right_linear = [
[
right[0][0].clone(),
right[0][1].clone(),
right[0][2].clone(),
],
[
right[1][0].clone(),
right[1][1].clone(),
right[1][2].clone(),
],
[
right[2][0].clone(),
right[2][1].clone(),
right[2][2].clone(),
],
];
let right_translation = [
right[0][3].clone(),
right[1][3].clone(),
right[2][3].clone(),
];
let right_inverse_linear = invert_matrix3_checked_with_abort(right_linear, signal)?;
let right_inverse_translation: [Real; 3] = from_fn(|row| {
let shifted = affine_translation_dot3(
[
&right_inverse_linear[row][0],
&right_inverse_linear[row][1],
&right_inverse_linear[row][2],
],
[
&right_translation[0],
&right_translation[1],
&right_translation[2],
],
);
Real::zero() - shifted
});
let linear = multiply_arrays3_affine_linear_with_exact_dense_certificate(
left_linear,
right_inverse_linear,
);
let translation: [Real; 3] = from_fn(|row| {
let shifted = affine_translation_dot3(
[&left[row][0], &left[row][1], &left[row][2]],
[
&right_inverse_translation[0],
&right_inverse_translation[1],
&right_inverse_translation[2],
],
);
left[row][3].clone() + shifted
});
Ok([
[
linear[0][0].clone(),
linear[0][1].clone(),
linear[0][2].clone(),
translation[0].clone(),
],
[
linear[1][0].clone(),
linear[1][1].clone(),
linear[1][2].clone(),
translation[1].clone(),
],
[
linear[2][0].clone(),
linear[2][1].clone(),
linear[2][2].clone(),
translation[2].clone(),
],
[Real::zero(), Real::zero(), Real::zero(), Real::one()],
])
}
fn divide_matrix4_by_affine_ref_assumed_affine_translation(
left: &[[Real; 4]; 4],
right: &[[Real; 4]; 4],
) -> BlasResult<[[Real; 4]; 4]> {
divide_matrix4_by_affine_ref_translation(left, right)
}
fn divide_matrix4_by_affine_ref_translation(
left: &[[Real; 4]; 4],
right: &[[Real; 4]; 4],
) -> BlasResult<[[Real; 4]; 4]> {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide4-ref-by-affine-translation"
);
let inverse_translation = [
Real::zero() - &right[0][3],
Real::zero() - &right[1][3],
Real::zero() - &right[2][3],
];
Ok([
[
left[0][0].clone(),
left[0][1].clone(),
left[0][2].clone(),
affine_translation_column_update(&left[0], &inverse_translation),
],
[
left[1][0].clone(),
left[1][1].clone(),
left[1][2].clone(),
affine_translation_column_update(&left[1], &inverse_translation),
],
[
left[2][0].clone(),
left[2][1].clone(),
left[2][2].clone(),
affine_translation_column_update(&left[2], &inverse_translation),
],
[
left[3][0].clone(),
left[3][1].clone(),
left[3][2].clone(),
affine_translation_column_update(&left[3], &inverse_translation),
],
])
}
#[inline]
fn divide_matrix4_by_affine_ref_no_translation(
left: &[[Real; 4]; 4],
right: &[[Real; 4]; 4],
) -> BlasResult<[[Real; 4]; 4]> {
let inverse = invert_matrix4_affine_without_translation(right)?;
Ok(multiply_arrays4_ref(left, &inverse))
}
#[inline]
fn divide_matrix4_affine_by_affine_ref_no_translation(
left: &[[Real; 4]; 4],
right: &[[Real; 4]; 4],
) -> BlasResult<[[Real; 4]; 4]> {
let left_linear = [
[left[0][0].clone(), left[0][1].clone(), left[0][2].clone()],
[left[1][0].clone(), left[1][1].clone(), left[1][2].clone()],
[left[2][0].clone(), left[2][1].clone(), left[2][2].clone()],
];
let right_linear = [
[
right[0][0].clone(),
right[0][1].clone(),
right[0][2].clone(),
],
[
right[1][0].clone(),
right[1][1].clone(),
right[1][2].clone(),
],
[
right[2][0].clone(),
right[2][1].clone(),
right[2][2].clone(),
],
];
let right_translation = [
right[0][3].clone(),
right[1][3].clone(),
right[2][3].clone(),
];
let right_inverse_linear = invert_matrix3(right_linear)?;
let right_inverse_translation: [Real; 3] = from_fn(|row| {
let shifted = affine_translation_dot3(
[
&right_inverse_linear[row][0],
&right_inverse_linear[row][1],
&right_inverse_linear[row][2],
],
[
&right_translation[0],
&right_translation[1],
&right_translation[2],
],
);
Real::zero() - shifted
});
let linear = multiply_arrays3_affine_linear_with_exact_dense_certificate(
left_linear,
right_inverse_linear,
);
let translation: [Real; 3] = from_fn(|row| {
let shifted = affine_translation_dot3(
[&left[row][0], &left[row][1], &left[row][2]],
[
&right_inverse_translation[0],
&right_inverse_translation[1],
&right_inverse_translation[2],
],
);
left[row][3].clone() + shifted
});
Ok([
[
linear[0][0].clone(),
linear[0][1].clone(),
linear[0][2].clone(),
translation[0].clone(),
],
[
linear[1][0].clone(),
linear[1][1].clone(),
linear[1][2].clone(),
translation[1].clone(),
],
[
linear[2][0].clone(),
linear[2][1].clone(),
linear[2][2].clone(),
translation[2].clone(),
],
[Real::zero(), Real::zero(), Real::zero(), Real::one()],
])
}
#[inline]
fn divide_matrix4_affine_by_affine_ref_translation(
left: &[[Real; 4]; 4],
right: &[[Real; 4]; 4],
) -> BlasResult<[[Real; 4]; 4]> {
let inverse_translation = [
Real::zero() - &right[0][3],
Real::zero() - &right[1][3],
Real::zero() - &right[2][3],
];
Ok([
[
left[0][0].clone(),
left[0][1].clone(),
left[0][2].clone(),
affine_translation_column_update(&left[0], &inverse_translation),
],
[
left[1][0].clone(),
left[1][1].clone(),
left[1][2].clone(),
affine_translation_column_update(&left[1], &inverse_translation),
],
[
left[2][0].clone(),
left[2][1].clone(),
left[2][2].clone(),
affine_translation_column_update(&left[2], &inverse_translation),
],
[Real::zero(), Real::zero(), Real::zero(), Real::one()],
])
}
fn invert_matrix3_by_diagonal(matrix: &[[Real; 3]; 3]) -> BlasResult<[[Real; 3]; 3]> {
if matrix[0][0] == matrix[1][1] && matrix[0][0] == matrix[2][2] {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"invert-matrix3-diagonal-uniform-scale"
);
let inv = matrix[0][0].clone().inverse()?;
return Ok([
[inv.clone(), Real::zero(), Real::zero()],
[Real::zero(), inv.clone(), Real::zero()],
[Real::zero(), Real::zero(), inv],
]);
}
let inv00 = matrix[0][0].clone().inverse()?;
let inv11 = matrix[1][1].clone().inverse()?;
let inv22 = matrix[2][2].clone().inverse()?;
if true {
Ok([
[inv00, Real::zero(), Real::zero()],
[Real::zero(), inv11, Real::zero()],
[Real::zero(), Real::zero(), inv22],
])
} else {
Ok(from_fn(|row| {
from_fn(|col| {
if row == 0 && col == 0 {
inv00.clone()
} else if row == 1 && col == 1 {
inv11.clone()
} else if row == 2 && col == 2 {
inv22.clone()
} else {
Real::zero()
}
})
}))
}
}
#[inline]
fn invert_matrix3_by_diagonal_checked(
matrix: &[[Real; 3]; 3],
) -> CheckedBlasResult<[[Real; 3]; 3]> {
require_known_nonzero(&matrix[0][0])?;
require_known_nonzero(&matrix[1][1])?;
require_known_nonzero(&matrix[2][2])?;
invert_matrix3_by_diagonal(matrix)
}
#[inline]
fn invert_matrix3_by_diagonal_checked_with_abort(
matrix: &[[Real; 3]; 3],
signal: &AbortSignal,
) -> CheckedBlasResult<[[Real; 3]; 3]> {
require_known_nonzero_with_abort(&matrix[0][0], signal)?;
require_known_nonzero_with_abort(&matrix[1][1], signal)?;
require_known_nonzero_with_abort(&matrix[2][2], signal)?;
invert_matrix3_by_diagonal(matrix)
}
#[inline]
fn invert_matrix3_upper_triangular(matrix: &[[Real; 3]; 3]) -> BlasResult<[[Real; 3]; 3]> {
let inv_a00 = matrix[0][0].clone().inverse()?;
let inv_a11 = matrix[1][1].clone().inverse()?;
let inv_a22 = matrix[2][2].clone().inverse()?;
let inv_a01 = scale_by_shared_factor(Real::zero() - &matrix[0][1], &inv_a11);
let inv_a01 = scale_by_shared_factor(inv_a01, &inv_a00);
let inv_a12 = scale_by_shared_factor(Real::zero() - &matrix[1][2], &inv_a11);
let inv_a12 = scale_by_shared_factor(inv_a12, &inv_a22);
let inv_a02 = Real::zero() - ((&matrix[0][1] * &inv_a12) + (&matrix[0][2] * &inv_a22));
let inv_a02 = scale_by_shared_factor(inv_a02, &inv_a00);
Ok([
[inv_a00, inv_a01, inv_a02],
[Real::zero(), inv_a11, inv_a12],
[Real::zero(), Real::zero(), inv_a22],
])
}
#[inline]
fn invert_matrix3_upper_triangular_checked(
matrix: &[[Real; 3]; 3],
) -> CheckedBlasResult<[[Real; 3]; 3]> {
require_known_nonzero(&matrix[0][0])?;
require_known_nonzero(&matrix[1][1])?;
require_known_nonzero(&matrix[2][2])?;
invert_matrix3_upper_triangular(matrix)
}
#[inline]
fn invert_matrix3_upper_triangular_checked_with_abort(
matrix: &[[Real; 3]; 3],
signal: &AbortSignal,
) -> CheckedBlasResult<[[Real; 3]; 3]> {
require_known_nonzero_with_abort(&matrix[0][0], signal)?;
require_known_nonzero_with_abort(&matrix[1][1], signal)?;
require_known_nonzero_with_abort(&matrix[2][2], signal)?;
invert_matrix3_upper_triangular(matrix)
}
#[inline]
fn invert_matrix3_lower_triangular(matrix: &[[Real; 3]; 3]) -> BlasResult<[[Real; 3]; 3]> {
let inv_a00 = matrix[0][0].clone().inverse()?;
let inv_a11 = matrix[1][1].clone().inverse()?;
let inv_a22 = matrix[2][2].clone().inverse()?;
let inv_a10 = scale_by_shared_factor(Real::zero() - &matrix[1][0], &inv_a00);
let inv_a10 = scale_by_shared_factor(inv_a10, &inv_a11);
let inv_a20 = Real::zero() - ((&matrix[2][0] * &inv_a00) + (&matrix[2][1] * &inv_a10));
let inv_a20 = scale_by_shared_factor(inv_a20, &inv_a22);
let inv_a21 = scale_by_shared_factor(Real::zero() - &matrix[2][1], &inv_a11);
let inv_a21 = scale_by_shared_factor(inv_a21, &inv_a22);
Ok([
[inv_a00, Real::zero(), Real::zero()],
[inv_a10, inv_a11, Real::zero()],
[inv_a20, inv_a21, inv_a22],
])
}
#[inline]
fn invert_matrix3_lower_triangular_checked(
matrix: &[[Real; 3]; 3],
) -> CheckedBlasResult<[[Real; 3]; 3]> {
require_known_nonzero(&matrix[0][0])?;
require_known_nonzero(&matrix[1][1])?;
require_known_nonzero(&matrix[2][2])?;
invert_matrix3_lower_triangular(matrix)
}
#[inline]
fn invert_matrix3_lower_triangular_checked_with_abort(
matrix: &[[Real; 3]; 3],
signal: &AbortSignal,
) -> CheckedBlasResult<[[Real; 3]; 3]> {
require_known_nonzero_with_abort(&matrix[0][0], signal)?;
require_known_nonzero_with_abort(&matrix[1][1], signal)?;
require_known_nonzero_with_abort(&matrix[2][2], signal)?;
invert_matrix3_lower_triangular(matrix)
}
#[inline]
fn invert_matrix3_affine(
matrix: &[[Real; 3]; 3],
linear_is_diagonal: bool,
) -> BlasResult<[[Real; 3]; 3]> {
if linear_is_diagonal {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"invert-matrix3-affine-linear-diagonal"
);
return invert_matrix3_affine_linear_diagonal(matrix);
}
let a = matrix[0][0].clone();
let b = matrix[0][1].clone();
let c = matrix[1][0].clone();
let d = matrix[1][1].clone();
let tx = matrix[0][2].clone();
let ty = matrix[1][2].clone();
let det = (&a * &d) - (&b * &c);
let inv_det = det.clone().inverse()?;
let inv_a00 = scale_by_shared_factor(d, &inv_det);
let inv_a01 = scale_by_shared_factor(Real::zero() - &b, &inv_det);
let inv_a10 = scale_by_shared_factor(Real::zero() - &c, &inv_det);
let inv_a11 = scale_by_shared_factor(a, &inv_det);
let inv_tx = Real::zero() - ((&inv_a00 * &tx) + (&inv_a01 * &ty));
let inv_ty = Real::zero() - ((&inv_a10 * &tx) + (&inv_a11 * &ty));
Ok([
[inv_a00, inv_a01, inv_tx],
[inv_a10, inv_a11, inv_ty],
[Real::zero(), Real::zero(), Real::one()],
])
}
#[inline]
fn invert_matrix3_affine_linear_diagonal(matrix: &[[Real; 3]; 3]) -> BlasResult<[[Real; 3]; 3]> {
let inv_a00 = matrix[0][0].clone().inverse()?;
let inv_a11 = matrix[1][1].clone().inverse()?;
let inv_tx = Real::zero() - (matrix[0][2].clone() * &inv_a00);
let inv_ty = Real::zero() - (matrix[1][2].clone() * &inv_a11);
Ok([
[inv_a00, Real::zero(), inv_tx],
[Real::zero(), inv_a11, inv_ty],
[Real::zero(), Real::zero(), Real::one()],
])
}
#[inline]
fn invert_matrix3_affine_linear_diagonal_checked(
matrix: &[[Real; 3]; 3],
) -> CheckedBlasResult<[[Real; 3]; 3]> {
require_known_nonzero(&matrix[0][0])?;
require_known_nonzero(&matrix[1][1])?;
let inv_a00 = matrix[0][0].clone().inverse()?;
let inv_a11 = matrix[1][1].clone().inverse()?;
let inv_tx = Real::zero() - (matrix[0][2].clone() * &inv_a00);
let inv_ty = Real::zero() - (matrix[1][2].clone() * &inv_a11);
Ok([
[inv_a00, Real::zero(), inv_tx],
[Real::zero(), inv_a11, inv_ty],
[Real::zero(), Real::zero(), Real::one()],
])
}
#[inline]
fn invert_matrix3_affine_linear_diagonal_checked_with_abort(
matrix: &[[Real; 3]; 3],
signal: &AbortSignal,
) -> CheckedBlasResult<[[Real; 3]; 3]> {
let a00 = with_abort(matrix[0][0].clone(), signal);
let a11 = with_abort(matrix[1][1].clone(), signal);
let inv_a00 = a00;
let inv_a11 = a11;
require_known_nonzero_with_abort(&inv_a00, signal)?;
require_known_nonzero_with_abort(&inv_a11, signal)?;
let inv_a00 = inv_a00.inverse()?;
let inv_a11 = inv_a11.inverse()?;
let inv_tx = Real::zero() - (matrix[0][2].clone() * &inv_a00);
let inv_ty = Real::zero() - (matrix[1][2].clone() * &inv_a11);
Ok([
[inv_a00, Real::zero(), inv_tx],
[Real::zero(), inv_a11, inv_ty],
[Real::zero(), Real::zero(), Real::one()],
])
}
#[inline]
fn divide_matrix3_by_affine_linear_diagonal(
left: [[Real; 3]; 3],
right: &[[Real; 3]; 3],
) -> BlasResult<[[Real; 3]; 3]> {
let inv_a00 = right[0][0].clone().inverse()?;
let inv_a11 = right[1][1].clone().inverse()?;
let inv_tx = Real::zero() - (&right[0][2] * &inv_a00);
let inv_ty = Real::zero() - (&right[1][2] * &inv_a11);
Ok([
[
{
let row = left[0][0].clone();
let row = row * &inv_a00;
row
},
{
let row = left[0][1].clone();
let row = row * &inv_a11;
row
},
{
let x = left[0][0].clone();
let y = left[0][1].clone();
left[0][2].clone() + &(x * &inv_tx) + &(y * &inv_ty)
},
],
[
{
let row = left[1][0].clone();
let row = row * &inv_a00;
row
},
{
let row = left[1][1].clone();
let row = row * &inv_a11;
row
},
{
let x = left[1][0].clone();
let y = left[1][1].clone();
left[1][2].clone() + &(x * &inv_tx) + &(y * &inv_ty)
},
],
[
{
let row = left[2][0].clone();
let row = row * &inv_a00;
row
},
{
let row = left[2][1].clone();
let row = row * &inv_a11;
row
},
{
let x = left[2][0].clone();
let y = left[2][1].clone();
left[2][2].clone() + &(x * &inv_tx) + &(y * &inv_ty)
},
],
])
}
#[inline]
fn divide_matrix3_by_affine_linear_diagonal_checked(
left: [[Real; 3]; 3],
right: &[[Real; 3]; 3],
) -> CheckedBlasResult<[[Real; 3]; 3]> {
require_known_nonzero(&right[0][0])?;
require_known_nonzero(&right[1][1])?;
divide_matrix3_by_affine_linear_diagonal(left, right)
}
#[inline]
fn divide_matrix3_by_affine_linear_diagonal_checked_with_abort(
left: [[Real; 3]; 3],
right: &[[Real; 3]; 3],
signal: &AbortSignal,
) -> CheckedBlasResult<[[Real; 3]; 3]> {
require_known_nonzero_with_abort(&right[0][0], signal)?;
require_known_nonzero_with_abort(&right[1][1], signal)?;
divide_matrix3_by_affine_linear_diagonal(left, right)
}
#[inline]
fn divide_matrix3_by_affine_ref_linear_diagonal(
left: &[[Real; 3]; 3],
right: &[[Real; 3]; 3],
) -> BlasResult<[[Real; 3]; 3]> {
let inv_a00 = right[0][0].clone().inverse()?;
let inv_a11 = right[1][1].clone().inverse()?;
let inv_tx = Real::zero() - (&right[0][2] * &inv_a00);
let inv_ty = Real::zero() - (&right[1][2] * &inv_a11);
Ok([
[
{
let row = left[0][0].clone();
let row = row * &inv_a00;
row
},
{
let row = left[0][1].clone();
let row = row * &inv_a11;
row
},
{
let x = left[0][0].clone();
let y = left[0][1].clone();
left[0][2].clone() + &(x * &inv_tx) + &(y * &inv_ty)
},
],
[
{
let row = left[1][0].clone();
let row = row * &inv_a00;
row
},
{
let row = left[1][1].clone();
let row = row * &inv_a11;
row
},
{
let x = left[1][0].clone();
let y = left[1][1].clone();
left[1][2].clone() + &(x * &inv_tx) + &(y * &inv_ty)
},
],
[
{
let row = left[2][0].clone();
let row = row * &inv_a00;
row
},
{
let row = left[2][1].clone();
let row = row * &inv_a11;
row
},
{
let x = left[2][0].clone();
let y = left[2][1].clone();
left[2][2].clone() + &(x * &inv_tx) + &(y * &inv_ty)
},
],
])
}
#[inline]
fn divide_matrix3_affine_by_affine_linear_diagonal(
left: [[Real; 3]; 3],
right: &[[Real; 3]; 3],
) -> BlasResult<[[Real; 3]; 3]> {
divide_matrix3_by_affine_linear_diagonal(left, right)
}
#[inline]
fn divide_matrix3_affine_by_affine_ref_linear_diagonal(
left: &[[Real; 3]; 3],
right: &[[Real; 3]; 3],
) -> BlasResult<[[Real; 3]; 3]> {
divide_matrix3_by_affine_ref_linear_diagonal(left, right)
}
#[inline]
fn divide_matrix3_affine_by_affine_linear_diagonal_checked(
left: [[Real; 3]; 3],
right: &[[Real; 3]; 3],
) -> CheckedBlasResult<[[Real; 3]; 3]> {
divide_matrix3_by_affine_linear_diagonal_checked(left, right)
}
#[inline]
fn divide_matrix3_affine_by_affine_linear_diagonal_checked_with_abort(
left: [[Real; 3]; 3],
right: &[[Real; 3]; 3],
signal: &AbortSignal,
) -> CheckedBlasResult<[[Real; 3]; 3]> {
divide_matrix3_by_affine_linear_diagonal_checked_with_abort(left, right, signal)
}
#[inline]
fn invert_matrix3_affine_checked(
matrix: &[[Real; 3]; 3],
linear_is_diagonal: bool,
) -> CheckedBlasResult<[[Real; 3]; 3]> {
if linear_is_diagonal {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"invert-matrix3-checked-affine-linear-diagonal"
);
return invert_matrix3_affine_linear_diagonal_checked(matrix);
}
let a = matrix[0][0].clone();
let b = matrix[0][1].clone();
let c = matrix[1][0].clone();
let d = matrix[1][1].clone();
let tx = matrix[0][2].clone();
let ty = matrix[1][2].clone();
let det = (&a * &d) - (&b * &c);
require_known_nonzero(&det)?;
let inv_det = det.inverse()?;
let inv_a00 = scale_by_shared_factor(d, &inv_det);
let inv_a01 = scale_by_shared_factor(Real::zero() - &b, &inv_det);
let inv_a10 = scale_by_shared_factor(Real::zero() - &c, &inv_det);
let inv_a11 = scale_by_shared_factor(a, &inv_det);
let inv_tx = Real::zero() - ((&inv_a00 * &tx) + (&inv_a01 * &ty));
let inv_ty = Real::zero() - ((&inv_a10 * &tx) + (&inv_a11 * &ty));
Ok([
[inv_a00, inv_a01, inv_tx],
[inv_a10, inv_a11, inv_ty],
[Real::zero(), Real::zero(), Real::one()],
])
}
#[inline]
fn invert_matrix3_affine_checked_with_abort(
matrix: &[[Real; 3]; 3],
signal: &AbortSignal,
linear_is_diagonal: bool,
) -> CheckedBlasResult<[[Real; 3]; 3]> {
if linear_is_diagonal {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"invert-matrix3-checked-with-abort-affine-linear-diagonal"
);
return invert_matrix3_affine_linear_diagonal_checked_with_abort(matrix, signal);
}
let a = matrix[0][0].clone();
let b = matrix[0][1].clone();
let c = matrix[1][0].clone();
let d = matrix[1][1].clone();
let tx = matrix[0][2].clone();
let ty = matrix[1][2].clone();
let det = with_abort((&a * &d) - (&b * &c), signal);
require_known_nonzero(&det)?;
let inv_det = det.inverse()?;
let inv_a00 = scale_by_shared_factor(d, &inv_det);
let inv_a01 = scale_by_shared_factor(Real::zero() - &b, &inv_det);
let inv_a10 = scale_by_shared_factor(Real::zero() - &c, &inv_det);
let inv_a11 = scale_by_shared_factor(a, &inv_det);
let inv_tx = Real::zero() - ((&inv_a00 * &tx) + (&inv_a01 * &ty));
let inv_ty = Real::zero() - ((&inv_a10 * &tx) + (&inv_a11 * &ty));
Ok([
[inv_a00, inv_a01, inv_tx],
[inv_a10, inv_a11, inv_ty],
[Real::zero(), Real::zero(), Real::one()],
])
}
#[inline]
fn invert_matrix4_by_diagonal(matrix: &[[Real; 4]; 4]) -> BlasResult<[[Real; 4]; 4]> {
if matrix[0][0] == matrix[1][1] && matrix[0][0] == matrix[2][2] && matrix[0][0] == matrix[3][3]
{
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"invert-matrix4-diagonal-uniform-scale"
);
let inv = matrix[0][0].clone().inverse()?;
return Ok([
[inv.clone(), Real::zero(), Real::zero(), Real::zero()],
[Real::zero(), inv.clone(), Real::zero(), Real::zero()],
[Real::zero(), Real::zero(), inv.clone(), Real::zero()],
[Real::zero(), Real::zero(), Real::zero(), inv],
]);
}
let inv00 = matrix[0][0].clone().inverse()?;
let inv11 = matrix[1][1].clone().inverse()?;
let inv22 = matrix[2][2].clone().inverse()?;
let inv33 = matrix[3][3].clone().inverse()?;
if true {
Ok([
[inv00, Real::zero(), Real::zero(), Real::zero()],
[Real::zero(), inv11, Real::zero(), Real::zero()],
[Real::zero(), Real::zero(), inv22, Real::zero()],
[Real::zero(), Real::zero(), Real::zero(), inv33],
])
} else {
Ok(from_fn(|row| {
from_fn(|col| {
if row == 0 && col == 0 {
inv00.clone()
} else if row == 1 && col == 1 {
inv11.clone()
} else if row == 2 && col == 2 {
inv22.clone()
} else if row == 3 && col == 3 {
inv33.clone()
} else {
Real::zero()
}
})
}))
}
}
#[inline]
fn invert_matrix4_by_upper_triangular(matrix: &[[Real; 4]; 4]) -> BlasResult<[[Real; 4]; 4]> {
let inv_a00 = matrix[0][0].clone().inverse()?;
let inv_a11 = matrix[1][1].clone().inverse()?;
let inv_a22 = matrix[2][2].clone().inverse()?;
let inv_a33 = matrix[3][3].clone().inverse()?;
let inv_diagonal = [inv_a00, inv_a11, inv_a22, inv_a33];
let mut result = [
[Real::zero(), Real::zero(), Real::zero(), Real::zero()],
[Real::zero(), Real::zero(), Real::zero(), Real::zero()],
[Real::zero(), Real::zero(), Real::zero(), Real::zero()],
[Real::zero(), Real::zero(), Real::zero(), Real::zero()],
];
for row in 0..4 {
for col in row..4 {
let mut value = if row == col {
Real::one()
} else {
Real::zero()
};
for k in row..col {
value = value - (&result[row][k] * &matrix[k][col]);
}
result[row][col] = value.mul_cached(&inv_diagonal[col]);
}
}
Ok(result)
}
#[inline]
fn invert_matrix4_by_lower_triangular(matrix: &[[Real; 4]; 4]) -> BlasResult<[[Real; 4]; 4]> {
let inv_a00 = matrix[0][0].clone().inverse()?;
let inv_a11 = matrix[1][1].clone().inverse()?;
let inv_a22 = matrix[2][2].clone().inverse()?;
let inv_a33 = matrix[3][3].clone().inverse()?;
let inv_diagonal = [inv_a00, inv_a11, inv_a22, inv_a33];
let mut result = [
[Real::zero(), Real::zero(), Real::zero(), Real::zero()],
[Real::zero(), Real::zero(), Real::zero(), Real::zero()],
[Real::zero(), Real::zero(), Real::zero(), Real::zero()],
[Real::zero(), Real::zero(), Real::zero(), Real::zero()],
];
for row in 0..4 {
for col in (0..=row).rev() {
let mut value = if row == col {
Real::one()
} else {
Real::zero()
};
for k in (col + 1)..=row {
value = value - (&result[row][k] * &matrix[k][col]);
}
result[row][col] = value.mul_cached(&inv_diagonal[col]);
}
}
Ok(result)
}
#[inline]
fn invert_matrix4_by_upper_triangular_checked(
matrix: &[[Real; 4]; 4],
) -> CheckedBlasResult<[[Real; 4]; 4]> {
require_known_nonzero(&matrix[0][0])?;
require_known_nonzero(&matrix[1][1])?;
require_known_nonzero(&matrix[2][2])?;
require_known_nonzero(&matrix[3][3])?;
invert_matrix4_by_upper_triangular(matrix)
}
#[inline]
fn invert_matrix4_by_lower_triangular_checked(
matrix: &[[Real; 4]; 4],
) -> CheckedBlasResult<[[Real; 4]; 4]> {
require_known_nonzero(&matrix[0][0])?;
require_known_nonzero(&matrix[1][1])?;
require_known_nonzero(&matrix[2][2])?;
require_known_nonzero(&matrix[3][3])?;
invert_matrix4_by_lower_triangular(matrix)
}
#[inline]
fn invert_matrix4_by_upper_triangular_checked_with_abort(
matrix: &[[Real; 4]; 4],
signal: &AbortSignal,
) -> CheckedBlasResult<[[Real; 4]; 4]> {
require_known_nonzero_with_abort(&matrix[0][0], signal)?;
require_known_nonzero_with_abort(&matrix[1][1], signal)?;
require_known_nonzero_with_abort(&matrix[2][2], signal)?;
require_known_nonzero_with_abort(&matrix[3][3], signal)?;
invert_matrix4_by_upper_triangular(matrix)
}
#[inline]
fn invert_matrix4_by_lower_triangular_checked_with_abort(
matrix: &[[Real; 4]; 4],
signal: &AbortSignal,
) -> CheckedBlasResult<[[Real; 4]; 4]> {
require_known_nonzero_with_abort(&matrix[0][0], signal)?;
require_known_nonzero_with_abort(&matrix[1][1], signal)?;
require_known_nonzero_with_abort(&matrix[2][2], signal)?;
require_known_nonzero_with_abort(&matrix[3][3], signal)?;
invert_matrix4_by_lower_triangular(matrix)
}
#[inline]
fn invert_matrix4_by_diagonal_checked(
matrix: &[[Real; 4]; 4],
) -> CheckedBlasResult<[[Real; 4]; 4]> {
require_known_nonzero(&matrix[0][0])?;
require_known_nonzero(&matrix[1][1])?;
require_known_nonzero(&matrix[2][2])?;
require_known_nonzero(&matrix[3][3])?;
invert_matrix4_by_diagonal(matrix)
}
#[inline]
fn invert_matrix4_by_diagonal_checked_with_abort(
matrix: &[[Real; 4]; 4],
signal: &AbortSignal,
) -> CheckedBlasResult<[[Real; 4]; 4]> {
require_known_nonzero_with_abort(&matrix[0][0], signal)?;
require_known_nonzero_with_abort(&matrix[1][1], signal)?;
require_known_nonzero_with_abort(&matrix[2][2], signal)?;
require_known_nonzero_with_abort(&matrix[3][3], signal)?;
invert_matrix4_by_diagonal(matrix)
}
#[inline]
fn multiply_matrix3_by_left_diagonal(
left: &[[Real; 3]; 3],
right: &[[Real; 3]; 3],
) -> [[Real; 3]; 3] {
let inv00 = left[0][0].clone();
let inv11 = left[1][1].clone();
let inv22 = left[2][2].clone();
let [[r00, r01, r02], [r10, r11, r12], [r20, r21, r22]] = right.clone();
[
[
r00.mul_cached(&inv00),
r01.mul_cached(&inv00),
r02.mul_cached(&inv00),
],
[
r10.mul_cached(&inv11),
r11.mul_cached(&inv11),
r12.mul_cached(&inv11),
],
[
r20.mul_cached(&inv22),
r21.mul_cached(&inv22),
r22.mul_cached(&inv22),
],
]
}
#[inline]
fn multiply_matrix3_by_right_diagonal(
left: &[[Real; 3]; 3],
right: &[[Real; 3]; 3],
) -> [[Real; 3]; 3] {
let inv00 = right[0][0].clone();
let inv11 = right[1][1].clone();
let inv22 = right[2][2].clone();
let [[l00, l01, l02], [l10, l11, l12], [l20, l21, l22]] = left.clone();
[
[
l00.mul_cached(&inv00),
l01.mul_cached(&inv11),
l02.mul_cached(&inv22),
],
[
l10.mul_cached(&inv00),
l11.mul_cached(&inv11),
l12.mul_cached(&inv22),
],
[
l20.mul_cached(&inv00),
l21.mul_cached(&inv11),
l22.mul_cached(&inv22),
],
]
}
#[inline]
fn multiply_matrix4_by_left_diagonal(
left: &[[Real; 4]; 4],
right: &[[Real; 4]; 4],
) -> [[Real; 4]; 4] {
let inv00 = left[0][0].clone();
let inv11 = left[1][1].clone();
let inv22 = left[2][2].clone();
let inv33 = left[3][3].clone();
let [
[r00, r01, r02, r03],
[r10, r11, r12, r13],
[r20, r21, r22, r23],
[r30, r31, r32, r33],
] = right.clone();
[
[
r00.mul_cached(&inv00),
r01.mul_cached(&inv00),
r02.mul_cached(&inv00),
r03.mul_cached(&inv00),
],
[
r10.mul_cached(&inv11),
r11.mul_cached(&inv11),
r12.mul_cached(&inv11),
r13.mul_cached(&inv11),
],
[
r20.mul_cached(&inv22),
r21.mul_cached(&inv22),
r22.mul_cached(&inv22),
r23.mul_cached(&inv22),
],
[
r30.mul_cached(&inv33),
r31.mul_cached(&inv33),
r32.mul_cached(&inv33),
r33.mul_cached(&inv33),
],
]
}
#[inline]
fn multiply_matrix4_by_right_diagonal(
left: &[[Real; 4]; 4],
right: &[[Real; 4]; 4],
) -> [[Real; 4]; 4] {
let inv00 = right[0][0].clone();
let inv11 = right[1][1].clone();
let inv22 = right[2][2].clone();
let inv33 = right[3][3].clone();
let [
[l00, l01, l02, l03],
[l10, l11, l12, l13],
[l20, l21, l22, l23],
[l30, l31, l32, l33],
] = left.clone();
[
[
l00.mul_cached(&inv00),
l01.mul_cached(&inv11),
l02.mul_cached(&inv22),
l03.mul_cached(&inv33),
],
[
l10.mul_cached(&inv00),
l11.mul_cached(&inv11),
l12.mul_cached(&inv22),
l13.mul_cached(&inv33),
],
[
l20.mul_cached(&inv00),
l21.mul_cached(&inv11),
l22.mul_cached(&inv22),
l23.mul_cached(&inv33),
],
[
l30.mul_cached(&inv00),
l31.mul_cached(&inv11),
l32.mul_cached(&inv22),
l33.mul_cached(&inv33),
],
]
}
#[inline]
fn divide_matrix3_by_diagonal(
left: [[Real; 3]; 3],
right: &[[Real; 3]; 3],
) -> BlasResult<[[Real; 3]; 3]> {
let inv00 = right[0][0].clone().inverse()?;
let inv11 = right[1][1].clone().inverse()?;
let inv22 = right[2][2].clone().inverse()?;
let mut result = left;
for row in &mut result {
row[0] = row[0].clone().mul_cached(&inv00);
row[1] = row[1].clone().mul_cached(&inv11);
row[2] = row[2].clone().mul_cached(&inv22);
}
Ok(result)
}
#[inline]
fn divide_matrix3_by_upper_triangular(
mut left: [[Real; 3]; 3],
right: &[[Real; 3]; 3],
) -> BlasResult<[[Real; 3]; 3]> {
let inv_a00 = right[0][0].clone().inverse()?;
let inv_a11 = right[1][1].clone().inverse()?;
let inv_a22 = right[2][2].clone().inverse()?;
if true {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"divide3-upper-triangular-fused-exact"
);
let one = Real::one();
for row in &mut left {
let x0 = row[0].clone().mul_cached(&inv_a00);
let x1 = (row[1].clone() - (&x0 * &right[0][1])).mul_cached(&inv_a11);
let x2 = Real::active_signed_product_sum2(
[true, false, false],
[[&row[2], &one], [&x0, &right[0][2]], [&x1, &right[1][2]]],
)
.mul_cached(&inv_a22);
*row = [x0, x1, x2];
}
return Ok(left);
}
let row0_0 = left[0][0].clone().mul_cached(&inv_a00);
let row0_1 = (left[0][1].clone() - (row0_0.clone() * &right[0][1])).mul_cached(&inv_a11);
let row0_2 =
(left[0][2].clone() - (row0_0.clone() * &right[0][2]) - (row0_1.clone() * &right[1][2]))
.mul_cached(&inv_a22);
let row1_0 = left[1][0].clone().mul_cached(&inv_a00);
let row1_1 = (left[1][1].clone() - (row1_0.clone() * &right[0][1])).mul_cached(&inv_a11);
let row1_2 =
(left[1][2].clone() - (row1_0.clone() * &right[0][2]) - (row1_1.clone() * &right[1][2]))
.mul_cached(&inv_a22);
let row2_0 = left[2][0].clone().mul_cached(&inv_a00);
let row2_1 = (left[2][1].clone() - (row2_0.clone() * &right[0][1])).mul_cached(&inv_a11);
let row2_2 =
(left[2][2].clone() - (row2_0.clone() * &right[0][2]) - (row2_1.clone() * &right[1][2]))
.mul_cached(&inv_a22);
left[0] = [row0_0, row0_1, row0_2];
left[1] = [row1_0, row1_1, row1_2];
left[2] = [row2_0, row2_1, row2_2];
Ok(left)
}
#[inline]
fn divide_matrix3_affine_upper_row(
row: &[Real; 3],
right: &[[Real; 3]; 3],
inv_a00: &Real,
inv_a11: &Real,
one: &Real,
) -> [Real; 3] {
let x0 = row[0].clone().mul_cached(inv_a00);
let x1 = (row[1].clone() - (&x0 * &right[0][1])).mul_cached(inv_a11);
let x2 = mul_sub_add(&row[2], one, &x0, &right[0][2], &x1, &right[1][2]);
[x0, x1, x2]
}
#[inline]
fn divide_matrix3_by_affine_upper_triangular(
left: [[Real; 3]; 3],
right: &[[Real; 3]; 3],
) -> BlasResult<[[Real; 3]; 3]> {
let inv_a00 = right[0][0].clone().inverse()?;
let inv_a11 = right[1][1].clone().inverse()?;
if true {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"divide3-affine-upper-triangular-fused-exact"
);
}
let one = Real::one();
Ok([
divide_matrix3_affine_upper_row(&left[0], right, &inv_a00, &inv_a11, &one),
divide_matrix3_affine_upper_row(&left[1], right, &inv_a00, &inv_a11, &one),
divide_matrix3_affine_upper_row(&left[2], right, &inv_a00, &inv_a11, &one),
])
}
#[inline]
fn divide_matrix3_affine_by_affine_upper_triangular(
left: [[Real; 3]; 3],
right: &[[Real; 3]; 3],
) -> BlasResult<[[Real; 3]; 3]> {
let inv_a00 = right[0][0].clone().inverse()?;
let inv_a11 = right[1][1].clone().inverse()?;
if true {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"divide3-affine-left-affine-upper-triangular-fused-exact"
);
}
let one = Real::one();
Ok([
divide_matrix3_affine_upper_row(&left[0], right, &inv_a00, &inv_a11, &one),
divide_matrix3_affine_upper_row(&left[1], right, &inv_a00, &inv_a11, &one),
[Real::zero(), Real::zero(), one],
])
}
#[inline]
fn divide_matrix3_by_affine_upper_triangular_checked(
left: [[Real; 3]; 3],
right: &[[Real; 3]; 3],
) -> CheckedBlasResult<[[Real; 3]; 3]> {
require_known_nonzero(&right[0][0])?;
require_known_nonzero(&right[1][1])?;
divide_matrix3_by_affine_upper_triangular(left, right)
}
#[inline]
fn divide_matrix3_affine_by_affine_upper_triangular_checked(
left: [[Real; 3]; 3],
right: &[[Real; 3]; 3],
) -> CheckedBlasResult<[[Real; 3]; 3]> {
require_known_nonzero(&right[0][0])?;
require_known_nonzero(&right[1][1])?;
divide_matrix3_affine_by_affine_upper_triangular(left, right)
}
#[inline]
fn divide_matrix3_by_affine_upper_triangular_checked_with_abort(
left: [[Real; 3]; 3],
right: &[[Real; 3]; 3],
signal: &AbortSignal,
) -> CheckedBlasResult<[[Real; 3]; 3]> {
require_known_nonzero_with_abort(&right[0][0], signal)?;
require_known_nonzero_with_abort(&right[1][1], signal)?;
divide_matrix3_by_affine_upper_triangular(left, right)
}
#[inline]
fn divide_matrix3_affine_by_affine_upper_triangular_checked_with_abort(
left: [[Real; 3]; 3],
right: &[[Real; 3]; 3],
signal: &AbortSignal,
) -> CheckedBlasResult<[[Real; 3]; 3]> {
require_known_nonzero_with_abort(&right[0][0], signal)?;
require_known_nonzero_with_abort(&right[1][1], signal)?;
divide_matrix3_affine_by_affine_upper_triangular(left, right)
}
#[inline]
fn divide_matrix3_by_upper_triangular_checked(
left: [[Real; 3]; 3],
right: &[[Real; 3]; 3],
) -> CheckedBlasResult<[[Real; 3]; 3]> {
require_known_nonzero(&right[0][0])?;
require_known_nonzero(&right[1][1])?;
require_known_nonzero(&right[2][2])?;
divide_matrix3_by_upper_triangular(left, right)
}
#[inline]
fn divide_matrix3_by_upper_triangular_checked_with_abort(
left: [[Real; 3]; 3],
right: &[[Real; 3]; 3],
signal: &AbortSignal,
) -> CheckedBlasResult<[[Real; 3]; 3]> {
require_known_nonzero_with_abort(&right[0][0], signal)?;
require_known_nonzero_with_abort(&right[1][1], signal)?;
require_known_nonzero_with_abort(&right[2][2], signal)?;
divide_matrix3_by_upper_triangular(left, right)
}
#[inline]
fn divide_matrix3_by_lower_triangular(
mut left: [[Real; 3]; 3],
right: &[[Real; 3]; 3],
) -> BlasResult<[[Real; 3]; 3]> {
let inv_a00 = right[0][0].clone().inverse()?;
let inv_a11 = right[1][1].clone().inverse()?;
let inv_a22 = right[2][2].clone().inverse()?;
if true {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"divide3-lower-triangular-fused-exact"
);
let one = Real::one();
for row in &mut left {
let x2 = row[2].clone().mul_cached(&inv_a22);
let x1 = (row[1].clone() - (&x2 * &right[2][1])).mul_cached(&inv_a11);
let x0 = Real::active_signed_product_sum2(
[true, false, false],
[[&row[0], &one], [&x1, &right[1][0]], [&x2, &right[2][0]]],
)
.mul_cached(&inv_a00);
*row = [x0, x1, x2];
}
return Ok(left);
}
let row0_2 = left[0][2].clone().mul_cached(&inv_a22);
let row0_1 = (left[0][1].clone() - (row0_2.clone() * &right[2][1])).mul_cached(&inv_a11);
let row0_0 =
(left[0][0].clone() - (row0_1.clone() * &right[1][0]) - (row0_2.clone() * &right[2][0]))
.mul_cached(&inv_a00);
let row1_2 = left[1][2].clone().mul_cached(&inv_a22);
let row1_1 = (left[1][1].clone() - (row1_2.clone() * &right[2][1])).mul_cached(&inv_a11);
let row1_0 =
(left[1][0].clone() - (row1_1.clone() * &right[1][0]) - (row1_2.clone() * &right[2][0]))
.mul_cached(&inv_a00);
let row2_2 = left[2][2].clone().mul_cached(&inv_a22);
let row2_1 = (left[2][1].clone() - (row2_2.clone() * &right[2][1])).mul_cached(&inv_a11);
let row2_0 =
(left[2][0].clone() - (row2_1.clone() * &right[1][0]) - (row2_2.clone() * &right[2][0]))
.mul_cached(&inv_a00);
left[0] = [row0_0, row0_1, row0_2];
left[1] = [row1_0, row1_1, row1_2];
left[2] = [row2_0, row2_1, row2_2];
Ok(left)
}
#[inline]
fn divide_matrix3_by_lower_triangular_checked(
left: [[Real; 3]; 3],
right: &[[Real; 3]; 3],
) -> CheckedBlasResult<[[Real; 3]; 3]> {
require_known_nonzero(&right[0][0])?;
require_known_nonzero(&right[1][1])?;
require_known_nonzero(&right[2][2])?;
divide_matrix3_by_lower_triangular(left, right)
}
#[inline]
fn divide_matrix3_by_lower_triangular_checked_with_abort(
left: [[Real; 3]; 3],
right: &[[Real; 3]; 3],
signal: &AbortSignal,
) -> CheckedBlasResult<[[Real; 3]; 3]> {
require_known_nonzero_with_abort(&right[0][0], signal)?;
require_known_nonzero_with_abort(&right[1][1], signal)?;
require_known_nonzero_with_abort(&right[2][2], signal)?;
divide_matrix3_by_lower_triangular(left, right)
}
#[inline]
fn affine_inverse_translation2(linear: &[[Real; 2]; 2], tx: &Real, ty: &Real) -> [Real; 2] {
[
Real::zero() - &mul_add(&linear[0][0], tx, &linear[0][1], ty),
Real::zero() - &mul_add(&linear[1][0], tx, &linear[1][1], ty),
]
}
#[inline]
fn affine_linear_dot2(left_a: &Real, right_a: &Real, left_b: &Real, right_b: &Real) -> Real {
mul_add(left_a, right_a, left_b, right_b)
}
#[inline]
fn affine_translation_column_update_from_inverse2(
row: &[Real; 3],
translation: &[Real; 2],
) -> Real {
row[2].clone() + mul_add(&row[0], &translation[0], &row[1], &translation[1])
}
#[inline]
fn affine_translation_column_subtract_update2(row: &[Real; 3], translation: [&Real; 2]) -> Real {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"affine-translation-column-subtract2"
);
let shifted = mul_add(&row[0], translation[0], &row[1], translation[1]);
row[2].clone() - shifted
}
#[inline]
fn divide_matrix3_by_affine_translation(
left: [[Real; 3]; 3],
right: &[[Real; 3]; 3],
) -> BlasResult<[[Real; 3]; 3]> {
let translation = [&right[0][2], &right[1][2]];
Ok([
[
left[0][0].clone(),
left[0][1].clone(),
affine_translation_column_subtract_update2(&left[0], translation),
],
[
left[1][0].clone(),
left[1][1].clone(),
affine_translation_column_subtract_update2(&left[1], translation),
],
[
left[2][0].clone(),
left[2][1].clone(),
affine_translation_column_subtract_update2(&left[2], translation),
],
])
}
#[inline]
fn divide_matrix3_affine_by_affine_translation(
left: [[Real; 3]; 3],
right: &[[Real; 3]; 3],
) -> BlasResult<[[Real; 3]; 3]> {
let translation = [&right[0][2], &right[1][2]];
Ok([
[
left[0][0].clone(),
left[0][1].clone(),
affine_translation_column_subtract_update2(&left[0], translation),
],
[
left[1][0].clone(),
left[1][1].clone(),
affine_translation_column_subtract_update2(&left[1], translation),
],
[Real::zero(), Real::zero(), Real::one()],
])
}
#[inline]
fn divide_matrix3_by_affine_ref_translation(
left: &[[Real; 3]; 3],
right: &[[Real; 3]; 3],
) -> BlasResult<[[Real; 3]; 3]> {
let translation = [&right[0][2], &right[1][2]];
Ok([
[
left[0][0].clone(),
left[0][1].clone(),
affine_translation_column_subtract_update2(&left[0], translation),
],
[
left[1][0].clone(),
left[1][1].clone(),
affine_translation_column_subtract_update2(&left[1], translation),
],
[
left[2][0].clone(),
left[2][1].clone(),
affine_translation_column_subtract_update2(&left[2], translation),
],
])
}
#[inline]
fn divide_matrix3_affine_by_affine_ref_translation(
left: &[[Real; 3]; 3],
right: &[[Real; 3]; 3],
) -> BlasResult<[[Real; 3]; 3]> {
let translation = [&right[0][2], &right[1][2]];
Ok([
[
left[0][0].clone(),
left[0][1].clone(),
affine_translation_column_subtract_update2(&left[0], translation),
],
[
left[1][0].clone(),
left[1][1].clone(),
affine_translation_column_subtract_update2(&left[1], translation),
],
[Real::zero(), Real::zero(), Real::one()],
])
}
#[inline]
fn divide_matrix3_by_affine_ref_no_translation(
left: &[[Real; 3]; 3],
right: &[[Real; 3]; 3],
) -> BlasResult<[[Real; 3]; 3]> {
let a = right[0][0].clone();
let b = right[0][1].clone();
let c = right[1][0].clone();
let d = right[1][1].clone();
let tx = right[0][2].clone();
let ty = right[1][2].clone();
let right_det = (&a * &d) - (&b * &c);
let right_inv_det = right_det.inverse()?;
let right_inverse_linear = [
[
scale_by_shared_factor(d, &right_inv_det),
scale_by_shared_factor(Real::zero() - &b, &right_inv_det),
],
[
scale_by_shared_factor(Real::zero() - &c, &right_inv_det),
scale_by_shared_factor(a, &right_inv_det),
],
];
let right_inverse_translation = affine_inverse_translation2(&right_inverse_linear, &tx, &ty);
Ok([
[
affine_linear_dot2(
&left[0][0],
&right_inverse_linear[0][0],
&left[0][1],
&right_inverse_linear[1][0],
),
affine_linear_dot2(
&left[0][0],
&right_inverse_linear[0][1],
&left[0][1],
&right_inverse_linear[1][1],
),
affine_translation_column_update_from_inverse2(&left[0], &right_inverse_translation),
],
[
affine_linear_dot2(
&left[1][0],
&right_inverse_linear[0][0],
&left[1][1],
&right_inverse_linear[1][0],
),
affine_linear_dot2(
&left[1][0],
&right_inverse_linear[0][1],
&left[1][1],
&right_inverse_linear[1][1],
),
affine_translation_column_update_from_inverse2(&left[1], &right_inverse_translation),
],
[
affine_linear_dot2(
&left[2][0],
&right_inverse_linear[0][0],
&left[2][1],
&right_inverse_linear[1][0],
),
affine_linear_dot2(
&left[2][0],
&right_inverse_linear[0][1],
&left[2][1],
&right_inverse_linear[1][1],
),
affine_translation_column_update_from_inverse2(&left[2], &right_inverse_translation),
],
])
}
#[inline]
fn divide_matrix3_affine_by_affine_ref_no_translation(
left: &[[Real; 3]; 3],
right: &[[Real; 3]; 3],
) -> BlasResult<[[Real; 3]; 3]> {
let a = right[0][0].clone();
let b = right[0][1].clone();
let c = right[1][0].clone();
let d = right[1][1].clone();
let tx = right[0][2].clone();
let ty = right[1][2].clone();
let right_det = (&a * &d) - (&b * &c);
let right_inv_det = right_det.inverse()?;
let right_inverse_linear = [
[
scale_by_shared_factor(d, &right_inv_det),
scale_by_shared_factor(Real::zero() - &b, &right_inv_det),
],
[
scale_by_shared_factor(Real::zero() - &c, &right_inv_det),
scale_by_shared_factor(a, &right_inv_det),
],
];
let right_inverse_translation = affine_inverse_translation2(&right_inverse_linear, &tx, &ty);
Ok([
[
affine_linear_dot2(
&left[0][0],
&right_inverse_linear[0][0],
&left[0][1],
&right_inverse_linear[1][0],
),
affine_linear_dot2(
&left[0][0],
&right_inverse_linear[0][1],
&left[0][1],
&right_inverse_linear[1][1],
),
affine_translation_column_update_from_inverse2(&left[0], &right_inverse_translation),
],
[
affine_linear_dot2(
&left[1][0],
&right_inverse_linear[0][0],
&left[1][1],
&right_inverse_linear[1][0],
),
affine_linear_dot2(
&left[1][0],
&right_inverse_linear[0][1],
&left[1][1],
&right_inverse_linear[1][1],
),
affine_translation_column_update_from_inverse2(&left[1], &right_inverse_translation),
],
[Real::zero(), Real::zero(), Real::one()],
])
}
#[inline]
fn divide_matrix3_by_affine(
left: [[Real; 3]; 3],
right: &[[Real; 3]; 3],
) -> BlasResult<[[Real; 3]; 3]> {
let a = right[0][0].clone();
let b = right[0][1].clone();
let c = right[1][0].clone();
let d = right[1][1].clone();
let tx = right[0][2].clone();
let ty = right[1][2].clone();
let right_det = (&a * &d) - (&b * &c);
let right_inv_det = right_det.inverse()?;
let right_inverse_linear = [
[
scale_by_shared_factor(d, &right_inv_det),
scale_by_shared_factor(Real::zero() - &b, &right_inv_det),
],
[
scale_by_shared_factor(Real::zero() - &c, &right_inv_det),
scale_by_shared_factor(a, &right_inv_det),
],
];
let right_inverse_translation = affine_inverse_translation2(&right_inverse_linear, &tx, &ty);
Ok([
[
affine_linear_dot2(
&left[0][0],
&right_inverse_linear[0][0],
&left[0][1],
&right_inverse_linear[1][0],
),
affine_linear_dot2(
&left[0][0],
&right_inverse_linear[0][1],
&left[0][1],
&right_inverse_linear[1][1],
),
affine_translation_column_update_from_inverse2(&left[0], &right_inverse_translation),
],
[
affine_linear_dot2(
&left[1][0],
&right_inverse_linear[0][0],
&left[1][1],
&right_inverse_linear[1][0],
),
affine_linear_dot2(
&left[1][0],
&right_inverse_linear[0][1],
&left[1][1],
&right_inverse_linear[1][1],
),
affine_translation_column_update_from_inverse2(&left[1], &right_inverse_translation),
],
[
affine_linear_dot2(
&left[2][0],
&right_inverse_linear[0][0],
&left[2][1],
&right_inverse_linear[1][0],
),
affine_linear_dot2(
&left[2][0],
&right_inverse_linear[0][1],
&left[2][1],
&right_inverse_linear[1][1],
),
affine_translation_column_update_from_inverse2(&left[2], &right_inverse_translation),
],
])
}
#[inline]
fn divide_matrix3_affine_by_affine(
left: [[Real; 3]; 3],
right: &[[Real; 3]; 3],
) -> BlasResult<[[Real; 3]; 3]> {
let a = right[0][0].clone();
let b = right[0][1].clone();
let c = right[1][0].clone();
let d = right[1][1].clone();
let tx = right[0][2].clone();
let ty = right[1][2].clone();
let right_det = (&a * &d) - (&b * &c);
let right_inv_det = right_det.inverse()?;
let right_inverse_linear = [
[
scale_by_shared_factor(d, &right_inv_det),
scale_by_shared_factor(Real::zero() - &b, &right_inv_det),
],
[
scale_by_shared_factor(Real::zero() - &c, &right_inv_det),
scale_by_shared_factor(a, &right_inv_det),
],
];
let right_inverse_translation = affine_inverse_translation2(&right_inverse_linear, &tx, &ty);
Ok([
[
affine_linear_dot2(
&left[0][0],
&right_inverse_linear[0][0],
&left[0][1],
&right_inverse_linear[1][0],
),
affine_linear_dot2(
&left[0][0],
&right_inverse_linear[0][1],
&left[0][1],
&right_inverse_linear[1][1],
),
affine_translation_column_update_from_inverse2(&left[0], &right_inverse_translation),
],
[
affine_linear_dot2(
&left[1][0],
&right_inverse_linear[0][0],
&left[1][1],
&right_inverse_linear[1][0],
),
affine_linear_dot2(
&left[1][0],
&right_inverse_linear[0][1],
&left[1][1],
&right_inverse_linear[1][1],
),
affine_translation_column_update_from_inverse2(&left[1], &right_inverse_translation),
],
[Real::zero(), Real::zero(), Real::one()],
])
}
#[inline]
fn divide_matrix3_by_diagonal_checked(
left: [[Real; 3]; 3],
right: &[[Real; 3]; 3],
) -> CheckedBlasResult<[[Real; 3]; 3]> {
require_known_nonzero(&right[0][0])?;
require_known_nonzero(&right[1][1])?;
require_known_nonzero(&right[2][2])?;
divide_matrix3_by_diagonal(left, right)
}
#[inline]
fn divide_matrix3_by_diagonal_checked_with_abort(
left: [[Real; 3]; 3],
right: &[[Real; 3]; 3],
signal: &AbortSignal,
) -> CheckedBlasResult<[[Real; 3]; 3]> {
require_known_nonzero_with_abort(&right[0][0], signal)?;
require_known_nonzero_with_abort(&right[1][1], signal)?;
require_known_nonzero_with_abort(&right[2][2], signal)?;
divide_matrix3_by_diagonal(left, right)
}
#[inline]
fn divide_matrix3_by_affine_checked(
left: [[Real; 3]; 3],
right: &[[Real; 3]; 3],
) -> CheckedBlasResult<[[Real; 3]; 3]> {
let a = right[0][0].clone();
let b = right[0][1].clone();
let c = right[1][0].clone();
let d = right[1][1].clone();
let tx = right[0][2].clone();
let ty = right[1][2].clone();
let right_det = (&a * &d) - (&b * &c);
require_known_nonzero(&right_det)?;
let right_inv_det = right_det.inverse()?;
let right_inverse_linear = [
[
scale_by_shared_factor(d, &right_inv_det),
scale_by_shared_factor(Real::zero() - &b, &right_inv_det),
],
[
scale_by_shared_factor(Real::zero() - &c, &right_inv_det),
scale_by_shared_factor(a, &right_inv_det),
],
];
let right_inverse_translation = affine_inverse_translation2(&right_inverse_linear, &tx, &ty);
Ok([
[
affine_linear_dot2(
&left[0][0],
&right_inverse_linear[0][0],
&left[0][1],
&right_inverse_linear[1][0],
),
affine_linear_dot2(
&left[0][0],
&right_inverse_linear[0][1],
&left[0][1],
&right_inverse_linear[1][1],
),
affine_translation_column_update_from_inverse2(&left[0], &right_inverse_translation),
],
[
affine_linear_dot2(
&left[1][0],
&right_inverse_linear[0][0],
&left[1][1],
&right_inverse_linear[1][0],
),
affine_linear_dot2(
&left[1][0],
&right_inverse_linear[0][1],
&left[1][1],
&right_inverse_linear[1][1],
),
affine_translation_column_update_from_inverse2(&left[1], &right_inverse_translation),
],
[
affine_linear_dot2(
&left[2][0],
&right_inverse_linear[0][0],
&left[2][1],
&right_inverse_linear[1][0],
),
affine_linear_dot2(
&left[2][0],
&right_inverse_linear[0][1],
&left[2][1],
&right_inverse_linear[1][1],
),
affine_translation_column_update_from_inverse2(&left[2], &right_inverse_translation),
],
])
}
#[inline]
fn divide_matrix3_by_affine_checked_with_abort(
left: [[Real; 3]; 3],
right: &[[Real; 3]; 3],
signal: &AbortSignal,
) -> CheckedBlasResult<[[Real; 3]; 3]> {
let a = right[0][0].clone();
let b = right[0][1].clone();
let c = right[1][0].clone();
let d = right[1][1].clone();
let tx = right[0][2].clone();
let ty = right[1][2].clone();
let right_det = with_abort((&a * &d) - (&b * &c), signal);
require_known_nonzero(&right_det)?;
let right_inv_det = right_det.inverse()?;
let right_inverse_linear = [
[
scale_by_shared_factor(d, &right_inv_det),
scale_by_shared_factor(Real::zero() - &b, &right_inv_det),
],
[
scale_by_shared_factor(Real::zero() - &c, &right_inv_det),
scale_by_shared_factor(a, &right_inv_det),
],
];
let right_inverse_translation = affine_inverse_translation2(&right_inverse_linear, &tx, &ty);
Ok([
[
affine_linear_dot2(
&left[0][0],
&right_inverse_linear[0][0],
&left[0][1],
&right_inverse_linear[1][0],
),
affine_linear_dot2(
&left[0][0],
&right_inverse_linear[0][1],
&left[0][1],
&right_inverse_linear[1][1],
),
affine_translation_column_update_from_inverse2(&left[0], &right_inverse_translation),
],
[
affine_linear_dot2(
&left[1][0],
&right_inverse_linear[0][0],
&left[1][1],
&right_inverse_linear[1][0],
),
affine_linear_dot2(
&left[1][0],
&right_inverse_linear[0][1],
&left[1][1],
&right_inverse_linear[1][1],
),
affine_translation_column_update_from_inverse2(&left[1], &right_inverse_translation),
],
[
affine_linear_dot2(
&left[2][0],
&right_inverse_linear[0][0],
&left[2][1],
&right_inverse_linear[1][0],
),
affine_linear_dot2(
&left[2][0],
&right_inverse_linear[0][1],
&left[2][1],
&right_inverse_linear[1][1],
),
affine_translation_column_update_from_inverse2(&left[2], &right_inverse_translation),
],
])
}
#[inline]
fn divide_matrix3_affine_by_affine_checked(
left: [[Real; 3]; 3],
right: &[[Real; 3]; 3],
) -> CheckedBlasResult<[[Real; 3]; 3]> {
let a = right[0][0].clone();
let b = right[0][1].clone();
let c = right[1][0].clone();
let d = right[1][1].clone();
let tx = right[0][2].clone();
let ty = right[1][2].clone();
let right_det = (&a * &d) - (&b * &c);
require_known_nonzero(&right_det)?;
let right_inv_det = right_det.inverse()?;
let right_inverse_linear = [
[
scale_by_shared_factor(d, &right_inv_det),
scale_by_shared_factor(Real::zero() - &b, &right_inv_det),
],
[
scale_by_shared_factor(Real::zero() - &c, &right_inv_det),
scale_by_shared_factor(a, &right_inv_det),
],
];
let right_inverse_translation = affine_inverse_translation2(&right_inverse_linear, &tx, &ty);
Ok([
[
affine_linear_dot2(
&left[0][0],
&right_inverse_linear[0][0],
&left[0][1],
&right_inverse_linear[1][0],
),
affine_linear_dot2(
&left[0][0],
&right_inverse_linear[0][1],
&left[0][1],
&right_inverse_linear[1][1],
),
affine_translation_column_update_from_inverse2(&left[0], &right_inverse_translation),
],
[
affine_linear_dot2(
&left[1][0],
&right_inverse_linear[0][0],
&left[1][1],
&right_inverse_linear[1][0],
),
affine_linear_dot2(
&left[1][0],
&right_inverse_linear[0][1],
&left[1][1],
&right_inverse_linear[1][1],
),
affine_translation_column_update_from_inverse2(&left[1], &right_inverse_translation),
],
[Real::zero(), Real::zero(), Real::one()],
])
}
#[inline]
fn divide_matrix3_affine_by_affine_checked_with_abort(
left: [[Real; 3]; 3],
right: &[[Real; 3]; 3],
signal: &AbortSignal,
) -> CheckedBlasResult<[[Real; 3]; 3]> {
let a = right[0][0].clone();
let b = right[0][1].clone();
let c = right[1][0].clone();
let d = right[1][1].clone();
let tx = right[0][2].clone();
let ty = right[1][2].clone();
let right_det = with_abort((&a * &d) - (&b * &c), signal);
require_known_nonzero(&right_det)?;
let right_inv_det = right_det.inverse()?;
let right_inverse_linear = [
[
scale_by_shared_factor(d, &right_inv_det),
scale_by_shared_factor(Real::zero() - &b, &right_inv_det),
],
[
scale_by_shared_factor(Real::zero() - &c, &right_inv_det),
scale_by_shared_factor(a, &right_inv_det),
],
];
let right_inverse_translation = affine_inverse_translation2(&right_inverse_linear, &tx, &ty);
Ok([
[
affine_linear_dot2(
&left[0][0],
&right_inverse_linear[0][0],
&left[0][1],
&right_inverse_linear[1][0],
),
affine_linear_dot2(
&left[0][0],
&right_inverse_linear[0][1],
&left[0][1],
&right_inverse_linear[1][1],
),
affine_translation_column_update_from_inverse2(&left[0], &right_inverse_translation),
],
[
affine_linear_dot2(
&left[1][0],
&right_inverse_linear[0][0],
&left[1][1],
&right_inverse_linear[1][0],
),
affine_linear_dot2(
&left[1][0],
&right_inverse_linear[0][1],
&left[1][1],
&right_inverse_linear[1][1],
),
affine_translation_column_update_from_inverse2(&left[1], &right_inverse_translation),
],
[Real::zero(), Real::zero(), Real::one()],
])
}
#[inline]
fn divide_matrix4_by_diagonal(
left: [[Real; 4]; 4],
right: &[[Real; 4]; 4],
) -> BlasResult<[[Real; 4]; 4]> {
let inv00 = right[0][0].clone().inverse()?;
let inv11 = right[1][1].clone().inverse()?;
let inv22 = right[2][2].clone().inverse()?;
let inv33 = right[3][3].clone().inverse()?;
let mut result = left;
for row in &mut result {
row[0] = row[0].clone().mul_cached(&inv00);
row[1] = row[1].clone().mul_cached(&inv11);
row[2] = row[2].clone().mul_cached(&inv22);
row[3] = row[3].clone().mul_cached(&inv33);
}
Ok(result)
}
#[inline]
fn divide_matrix4_by_diagonal_checked(
left: [[Real; 4]; 4],
right: &[[Real; 4]; 4],
) -> CheckedBlasResult<[[Real; 4]; 4]> {
require_known_nonzero(&right[0][0])?;
require_known_nonzero(&right[1][1])?;
require_known_nonzero(&right[2][2])?;
require_known_nonzero(&right[3][3])?;
divide_matrix4_by_diagonal(left, right)
}
#[inline]
fn divide_matrix4_by_diagonal_checked_with_abort(
left: [[Real; 4]; 4],
right: &[[Real; 4]; 4],
signal: &AbortSignal,
) -> CheckedBlasResult<[[Real; 4]; 4]> {
require_known_nonzero_with_abort(&right[0][0], signal)?;
require_known_nonzero_with_abort(&right[1][1], signal)?;
require_known_nonzero_with_abort(&right[2][2], signal)?;
require_known_nonzero_with_abort(&right[3][3], signal)?;
divide_matrix4_by_diagonal(left, right)
}
#[inline]
fn divide_matrix4_by_upper_triangular(
mut left: [[Real; 4]; 4],
right: &[[Real; 4]; 4],
) -> BlasResult<[[Real; 4]; 4]> {
let inv_a00 = right[0][0].clone().inverse()?;
let inv_a11 = right[1][1].clone().inverse()?;
let inv_a22 = right[2][2].clone().inverse()?;
let inv_a33 = right[3][3].clone().inverse()?;
if true {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"divide4-upper-triangular-fused-exact"
);
let one = Real::one();
for row in &mut left {
let x0 = row[0].clone().mul_cached(&inv_a00);
let x1 = (row[1].clone() - (&x0 * &right[0][1])).mul_cached(&inv_a11);
let x2 = Real::active_signed_product_sum2(
[true, false, false],
[[&row[2], &one], [&x0, &right[0][2]], [&x1, &right[1][2]]],
)
.mul_cached(&inv_a22);
let x3 = Real::active_signed_product_sum2(
[true, false, false, false],
[
[&row[3], &one],
[&x0, &right[0][3]],
[&x1, &right[1][3]],
[&x2, &right[2][3]],
],
)
.mul_cached(&inv_a33);
*row = [x0, x1, x2, x3];
}
return Ok(left);
}
let inv_diagonal = [inv_a00, inv_a11, inv_a22, inv_a33];
for row in 0..4 {
for col in 0..4 {
let mut value = left[row][col].clone();
for k in 0..col {
value = value - (&left[row][k] * &right[k][col]);
}
left[row][col] = value.mul_cached(&inv_diagonal[col]);
}
}
Ok(left)
}
#[inline]
fn divide_matrix4_affine_upper_row(
row: &[Real; 4],
right: &[[Real; 4]; 4],
inv_a00: &Real,
inv_a11: &Real,
inv_a22: &Real,
one: &Real,
) -> [Real; 4] {
let x0 = row[0].clone().mul_cached(inv_a00);
let x1 = (row[1].clone() - (&x0 * &right[0][1])).mul_cached(inv_a11);
let x2 = if true {
Real::active_signed_product_sum2(
[true, false, false],
[[&row[2], one], [&x0, &right[0][2]], [&x1, &right[1][2]]],
)
.mul_cached(inv_a22)
} else {
(row[2].clone() - (&x0 * &right[0][2]) - (&x1 * &right[1][2])).mul_cached(inv_a22)
};
let x3 = if true {
Real::active_signed_product_sum2(
[true, false, false, false],
[
[&row[3], one],
[&x0, &right[0][3]],
[&x1, &right[1][3]],
[&x2, &right[2][3]],
],
)
} else {
row[3].clone() - (&x0 * &right[0][3]) - (&x1 * &right[1][3]) - (&x2 * &right[2][3])
};
[x0, x1, x2, x3]
}
#[inline]
fn divide_matrix4_by_affine_upper_triangular(
left: [[Real; 4]; 4],
right: &[[Real; 4]; 4],
) -> BlasResult<[[Real; 4]; 4]> {
let inv_a00 = right[0][0].clone().inverse()?;
let inv_a11 = right[1][1].clone().inverse()?;
let inv_a22 = right[2][2].clone().inverse()?;
if true {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"divide4-affine-upper-triangular-fused-exact"
);
}
let one = Real::one();
Ok([
divide_matrix4_affine_upper_row(&left[0], right, &inv_a00, &inv_a11, &inv_a22, &one),
divide_matrix4_affine_upper_row(&left[1], right, &inv_a00, &inv_a11, &inv_a22, &one),
divide_matrix4_affine_upper_row(&left[2], right, &inv_a00, &inv_a11, &inv_a22, &one),
divide_matrix4_affine_upper_row(&left[3], right, &inv_a00, &inv_a11, &inv_a22, &one),
])
}
#[inline]
fn divide_matrix4_affine_by_affine_upper_triangular(
left: [[Real; 4]; 4],
right: &[[Real; 4]; 4],
) -> BlasResult<[[Real; 4]; 4]> {
let inv_a00 = right[0][0].clone().inverse()?;
let inv_a11 = right[1][1].clone().inverse()?;
let inv_a22 = right[2][2].clone().inverse()?;
if true {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"divide4-affine-left-affine-upper-triangular-fused-exact"
);
}
let one = Real::one();
Ok([
divide_matrix4_affine_upper_row(&left[0], right, &inv_a00, &inv_a11, &inv_a22, &one),
divide_matrix4_affine_upper_row(&left[1], right, &inv_a00, &inv_a11, &inv_a22, &one),
divide_matrix4_affine_upper_row(&left[2], right, &inv_a00, &inv_a11, &inv_a22, &one),
[Real::zero(), Real::zero(), Real::zero(), one],
])
}
#[inline]
fn divide_matrix4_by_affine_upper_triangular_checked(
left: [[Real; 4]; 4],
right: &[[Real; 4]; 4],
) -> CheckedBlasResult<[[Real; 4]; 4]> {
require_known_nonzero(&right[0][0])?;
require_known_nonzero(&right[1][1])?;
require_known_nonzero(&right[2][2])?;
divide_matrix4_by_affine_upper_triangular(left, right)
}
#[inline]
fn divide_matrix4_affine_by_affine_upper_triangular_checked(
left: [[Real; 4]; 4],
right: &[[Real; 4]; 4],
) -> CheckedBlasResult<[[Real; 4]; 4]> {
require_known_nonzero(&right[0][0])?;
require_known_nonzero(&right[1][1])?;
require_known_nonzero(&right[2][2])?;
divide_matrix4_affine_by_affine_upper_triangular(left, right)
}
#[inline]
fn divide_matrix4_by_affine_upper_triangular_checked_with_abort(
left: [[Real; 4]; 4],
right: &[[Real; 4]; 4],
signal: &AbortSignal,
) -> CheckedBlasResult<[[Real; 4]; 4]> {
require_known_nonzero_with_abort(&right[0][0], signal)?;
require_known_nonzero_with_abort(&right[1][1], signal)?;
require_known_nonzero_with_abort(&right[2][2], signal)?;
divide_matrix4_by_affine_upper_triangular(left, right)
}
#[inline]
fn divide_matrix4_affine_by_affine_upper_triangular_checked_with_abort(
left: [[Real; 4]; 4],
right: &[[Real; 4]; 4],
signal: &AbortSignal,
) -> CheckedBlasResult<[[Real; 4]; 4]> {
require_known_nonzero_with_abort(&right[0][0], signal)?;
require_known_nonzero_with_abort(&right[1][1], signal)?;
require_known_nonzero_with_abort(&right[2][2], signal)?;
divide_matrix4_affine_by_affine_upper_triangular(left, right)
}
#[inline]
fn divide_matrix4_by_upper_triangular_checked(
left: [[Real; 4]; 4],
right: &[[Real; 4]; 4],
) -> CheckedBlasResult<[[Real; 4]; 4]> {
require_known_nonzero(&right[0][0])?;
require_known_nonzero(&right[1][1])?;
require_known_nonzero(&right[2][2])?;
require_known_nonzero(&right[3][3])?;
divide_matrix4_by_upper_triangular(left, right)
}
#[inline]
fn divide_matrix4_by_upper_triangular_checked_with_abort(
left: [[Real; 4]; 4],
right: &[[Real; 4]; 4],
signal: &AbortSignal,
) -> CheckedBlasResult<[[Real; 4]; 4]> {
require_known_nonzero_with_abort(&right[0][0], signal)?;
require_known_nonzero_with_abort(&right[1][1], signal)?;
require_known_nonzero_with_abort(&right[2][2], signal)?;
require_known_nonzero_with_abort(&right[3][3], signal)?;
divide_matrix4_by_upper_triangular(left, right)
}
#[inline]
fn divide_matrix4_by_lower_triangular(
mut left: [[Real; 4]; 4],
right: &[[Real; 4]; 4],
) -> BlasResult<[[Real; 4]; 4]> {
let inv_a00 = right[0][0].clone().inverse()?;
let inv_a11 = right[1][1].clone().inverse()?;
let inv_a22 = right[2][2].clone().inverse()?;
let inv_a33 = right[3][3].clone().inverse()?;
if true {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"divide4-lower-triangular-fused-exact"
);
let one = Real::one();
for row in &mut left {
let x3 = row[3].clone().mul_cached(&inv_a33);
let x2 = (row[2].clone() - (&x3 * &right[3][2])).mul_cached(&inv_a22);
let x1 = Real::active_signed_product_sum2(
[true, false, false],
[[&row[1], &one], [&x2, &right[2][1]], [&x3, &right[3][1]]],
)
.mul_cached(&inv_a11);
let x0 = Real::active_signed_product_sum2(
[true, false, false, false],
[
[&row[0], &one],
[&x1, &right[1][0]],
[&x2, &right[2][0]],
[&x3, &right[3][0]],
],
)
.mul_cached(&inv_a00);
*row = [x0, x1, x2, x3];
}
return Ok(left);
}
let inv_diagonal = [inv_a00, inv_a11, inv_a22, inv_a33];
for row in 0..4 {
for col in (0..4).rev() {
let mut value = left[row][col].clone();
for k in (col + 1)..4 {
value = value - (&left[row][k] * &right[k][col]);
}
left[row][col] = value.mul_cached(&inv_diagonal[col]);
}
}
Ok(left)
}
#[inline]
fn divide_matrix4_by_lower_triangular_checked(
left: [[Real; 4]; 4],
right: &[[Real; 4]; 4],
) -> CheckedBlasResult<[[Real; 4]; 4]> {
require_known_nonzero(&right[0][0])?;
require_known_nonzero(&right[1][1])?;
require_known_nonzero(&right[2][2])?;
require_known_nonzero(&right[3][3])?;
divide_matrix4_by_lower_triangular(left, right)
}
#[inline]
fn divide_matrix4_by_lower_triangular_checked_with_abort(
left: [[Real; 4]; 4],
right: &[[Real; 4]; 4],
signal: &AbortSignal,
) -> CheckedBlasResult<[[Real; 4]; 4]> {
require_known_nonzero_with_abort(&right[0][0], signal)?;
require_known_nonzero_with_abort(&right[1][1], signal)?;
require_known_nonzero_with_abort(&right[2][2], signal)?;
require_known_nonzero_with_abort(&right[3][3], signal)?;
divide_matrix4_by_lower_triangular(left, right)
}
fn right_divide_matrix3(left: [[Real; 3]; 3], right: [[Real; 3]; 3]) -> BlasResult<[[Real; 3]; 3]> {
let right_facts = matrix3_facts(&right);
if right_facts.is_identity {
crate::trace_dispatch!("hyperlattice_matrix", "helper", "right-divide3-identity");
return Ok(left);
}
if right_facts.is_diagonal {
crate::trace_dispatch!("hyperlattice_matrix", "helper", "right-divide3-diagonal");
return divide_matrix3_by_diagonal(left, &right);
}
if right_facts.is_affine_translation {
let left_facts = matrix3_facts(&left);
if left_facts.is_affine {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide3-affine-left-affine-translation"
);
return divide_matrix3_affine_by_affine_translation(left, &right);
}
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide3-affine-by-translation"
);
return divide_matrix3_by_affine_translation(left, &right);
}
if right_facts.is_affine && right_facts.is_upper_triangular {
let left_facts = matrix3_facts(&left);
if left_facts.is_affine {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide3-affine-left-affine-upper-triangular"
);
return divide_matrix3_affine_by_affine_upper_triangular(left, &right);
}
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide3-affine-upper-triangular"
);
return divide_matrix3_by_affine_upper_triangular(left, &right);
}
if right_facts.is_upper_triangular {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide3-upper-triangular"
);
return divide_matrix3_by_upper_triangular(left, &right);
}
if right_facts.is_lower_triangular {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide3-lower-triangular"
);
return divide_matrix3_by_lower_triangular(left, &right);
}
if right_facts.is_affine {
let left_facts = matrix3_facts(&left);
let left_is_affine = left_facts.is_affine;
let right_linear_is_diagonal = right_facts.linear_is_diagonal;
let right_is_affine_translation = right_facts.is_affine_translation;
crate::trace_dispatch!("hyperlattice_matrix", "helper", "right-divide3-affine");
if left_is_affine {
if right_is_affine_translation {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide3-affine-left-affine-translation"
);
return divide_matrix3_affine_by_affine_translation(left, &right);
}
if right_linear_is_diagonal {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide3-affine-left-affine-linear-diagonal"
);
return divide_matrix3_affine_by_affine_linear_diagonal(left, &right);
}
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide3-affine-left-affine"
);
return divide_matrix3_affine_by_affine(left, &right);
}
if right_is_affine_translation {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide3-affine-by-translation"
);
return divide_matrix3_by_affine_translation(left, &right);
}
if right_linear_is_diagonal {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide3-affine-linear-diagonal"
);
return divide_matrix3_by_affine_linear_diagonal(left, &right);
}
return divide_matrix3_by_affine(left, &right);
}
if !prefer_shared_adjugate_right_division(&left, &right) {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide3-gauss-jordan"
);
return Ok(transpose_array3(solve_left_system3(
transpose_array3(right),
transpose_array3(left),
)?));
}
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide3-shared-adjugate"
);
let (adjugate, det) = matrix3_adjugate_and_determinant(&right);
let inv_det = det.inverse()?;
Ok(scale_matrix3(
multiply_arrays3_with_exact_dense_certificate(left, adjugate),
&inv_det,
))
}
fn right_divide_matrix3_ref(
left: &[[Real; 3]; 3],
right: &[[Real; 3]; 3],
) -> BlasResult<[[Real; 3]; 3]> {
let right_facts = matrix3_facts(right);
if right_facts.is_identity {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide3-ref-identity"
);
return Ok(left.clone());
}
if right_facts.is_diagonal {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide3-ref-diagonal"
);
return divide_matrix3_by_diagonal(left.clone(), right);
}
if right_facts.is_affine_translation {
let left_facts = matrix3_facts(left);
if left_facts.is_affine {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide3-ref-affine-left-affine-translation"
);
return divide_matrix3_affine_by_affine_ref_translation(left, right);
}
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide3-ref-affine-by-translation"
);
return divide_matrix3_by_affine_ref_translation(left, right);
}
if right_facts.is_affine && right_facts.is_upper_triangular {
let left_facts = matrix3_facts(left);
if left_facts.is_affine {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide3-ref-affine-left-affine-upper-triangular"
);
return divide_matrix3_affine_by_affine_upper_triangular(left.clone(), right);
}
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide3-ref-affine-upper-triangular"
);
return divide_matrix3_by_affine_upper_triangular(left.clone(), right);
}
if right_facts.is_upper_triangular {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide3-ref-upper-triangular"
);
return divide_matrix3_by_upper_triangular(left.clone(), right);
}
if right_facts.is_lower_triangular {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide3-ref-lower-triangular"
);
return divide_matrix3_by_lower_triangular(left.clone(), right);
}
if right_facts.is_affine {
let left_facts = matrix3_facts(left);
let left_is_affine = left_facts.is_affine;
let right_linear_is_diagonal = right_facts.linear_is_diagonal;
let right_is_affine_translation = right_facts.is_affine_translation;
crate::trace_dispatch!("hyperlattice_matrix", "helper", "right-divide3-ref-affine");
if left_is_affine {
if right_is_affine_translation {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide3-ref-affine-left-affine-translation"
);
return divide_matrix3_affine_by_affine_ref_translation(left, right);
}
if right_linear_is_diagonal {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide3-ref-affine-left-affine-linear-diagonal"
);
return divide_matrix3_affine_by_affine_ref_linear_diagonal(left, right);
}
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide3-ref-affine-left-affine"
);
return divide_matrix3_affine_by_affine_ref_no_translation(left, right);
}
if right_is_affine_translation {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide3-ref-affine-by-translation"
);
return divide_matrix3_by_affine_ref_translation(left, right);
}
if right_linear_is_diagonal {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide3-ref-affine-linear-diagonal"
);
return divide_matrix3_by_affine_ref_linear_diagonal(left, right);
}
return divide_matrix3_by_affine_ref_no_translation(left, right);
}
if !prefer_shared_adjugate_right_division_ref3(left, right) {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide3-ref-gauss-jordan"
);
return Ok(transpose_array3(solve_left_system3(
transpose_array3_ref(right),
transpose_array3_ref(left),
)?));
}
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide3-ref-shared-adjugate"
);
let (adjugate, det) = matrix3_adjugate_and_determinant(right);
let inv_det = det.inverse()?;
Ok(scale_matrix3(
multiply_arrays3_ref_with_exact_dense_certificate(left, &adjugate),
&inv_det,
))
}
fn right_divide_matrix3_checked(
left: [[Real; 3]; 3],
right: [[Real; 3]; 3],
) -> CheckedBlasResult<[[Real; 3]; 3]> {
let right_facts = matrix3_facts(&right);
if right_facts.is_identity {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide3-checked-identity"
);
return Ok(left);
}
if right_facts.is_diagonal {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide3-checked-diagonal"
);
return divide_matrix3_by_diagonal_checked(left, &right);
}
if right_facts.is_affine_translation {
let left_facts = matrix3_facts(&left);
if left_facts.is_affine {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide3-checked-affine-left-affine-translation"
);
return divide_matrix3_affine_by_affine_translation(left, &right);
}
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide3-checked-affine-by-translation"
);
return divide_matrix3_by_affine_translation(left, &right);
}
if right_facts.is_affine && right_facts.is_upper_triangular {
let left_facts = matrix3_facts(&left);
if left_facts.is_affine {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide3-checked-affine-left-affine-upper-triangular"
);
return divide_matrix3_affine_by_affine_upper_triangular_checked(left, &right);
}
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide3-checked-affine-upper-triangular"
);
return divide_matrix3_by_affine_upper_triangular_checked(left, &right);
}
if right_facts.is_upper_triangular {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide3-checked-upper-triangular"
);
return divide_matrix3_by_upper_triangular_checked(left, &right);
}
if right_facts.is_lower_triangular {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide3-checked-lower-triangular"
);
return divide_matrix3_by_lower_triangular_checked(left, &right);
}
if right_facts.is_affine {
let left_facts = matrix3_facts(&left);
let left_is_affine = left_facts.is_affine;
let right_linear_is_diagonal = right_facts.linear_is_diagonal;
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide3-checked-affine"
);
if left_is_affine {
if right_linear_is_diagonal {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide3-checked-affine-left-affine-linear-diagonal"
);
return divide_matrix3_affine_by_affine_linear_diagonal_checked(left, &right);
}
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide3-checked-affine-left-affine"
);
return divide_matrix3_affine_by_affine_checked(left, &right);
}
if right_linear_is_diagonal {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide3-checked-affine-linear-diagonal"
);
return divide_matrix3_by_affine_linear_diagonal_checked(left, &right);
}
return divide_matrix3_by_affine_checked(left, &right);
}
if !prefer_shared_adjugate_right_division(&left, &right) {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide3-checked-gauss-jordan"
);
return Ok(transpose_array3(solve_left_system3_checked(
transpose_array3(right),
transpose_array3(left),
)?));
}
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide3-checked-shared-adjugate"
);
let (adjugate, det) = matrix3_adjugate_and_determinant(&right);
require_known_nonzero(&det)?;
let inv_det = det.inverse()?;
Ok(scale_matrix3(
multiply_arrays3_with_exact_dense_certificate(left, adjugate),
&inv_det,
))
}
fn right_divide_matrix3_checked_with_abort(
left: [[Real; 3]; 3],
right: [[Real; 3]; 3],
signal: &AbortSignal,
) -> CheckedBlasResult<[[Real; 3]; 3]> {
let right_facts = matrix3_facts(&right);
if right_facts.is_identity {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide3-checked-abort-identity"
);
return Ok(left);
}
if right_facts.is_diagonal {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide3-checked-abort-diagonal"
);
return divide_matrix3_by_diagonal_checked_with_abort(left, &right, signal);
}
if right_facts.is_affine_translation {
let left_facts = matrix3_facts(&left);
if left_facts.is_affine {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide3-checked-abort-affine-left-affine-translation"
);
return divide_matrix3_affine_by_affine_translation(left, &right);
}
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide3-checked-abort-affine-by-translation"
);
return divide_matrix3_by_affine_translation(left, &right);
}
if right_facts.is_affine && right_facts.is_upper_triangular {
let left_facts = matrix3_facts(&left);
if left_facts.is_affine {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide3-checked-abort-affine-left-affine-upper-triangular"
);
return divide_matrix3_affine_by_affine_upper_triangular_checked_with_abort(
left, &right, signal,
);
}
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide3-checked-abort-affine-upper-triangular"
);
return divide_matrix3_by_affine_upper_triangular_checked_with_abort(left, &right, signal);
}
if right_facts.is_upper_triangular {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide3-checked-abort-upper-triangular"
);
return divide_matrix3_by_upper_triangular_checked_with_abort(left, &right, signal);
}
if right_facts.is_lower_triangular {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide3-checked-abort-lower-triangular"
);
return divide_matrix3_by_lower_triangular_checked_with_abort(left, &right, signal);
}
if right_facts.is_affine {
let left_facts = matrix3_facts(&left);
let left_is_affine = left_facts.is_affine;
let right_linear_is_diagonal = right_facts.linear_is_diagonal;
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide3-checked-abort-affine"
);
if left_is_affine {
if right_linear_is_diagonal {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide3-checked-abort-affine-left-affine-linear-diagonal"
);
return divide_matrix3_affine_by_affine_linear_diagonal_checked_with_abort(
left, &right, signal,
);
}
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide3-checked-abort-affine-left-affine"
);
return divide_matrix3_affine_by_affine_checked_with_abort(left, &right, signal);
}
if right_linear_is_diagonal {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide3-checked-abort-affine-linear-diagonal"
);
return divide_matrix3_by_affine_linear_diagonal_checked_with_abort(
left, &right, signal,
);
}
return divide_matrix3_by_affine_checked_with_abort(left, &right, signal);
}
if !prefer_shared_adjugate_right_division(&left, &right) {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide3-checked-abort-gauss-jordan"
);
return Ok(transpose_array3(solve_left_system3_checked_with_abort(
transpose_array3(right),
transpose_array3(left),
signal,
)?));
}
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide3-checked-abort-shared-adjugate"
);
let (adjugate, det) = matrix3_adjugate_and_determinant(&right);
let det = with_abort(det, signal);
require_known_nonzero(&det)?;
let inv_det = det.inverse()?;
Ok(scale_matrix3(
multiply_arrays3_with_exact_dense_certificate(left, adjugate),
&inv_det,
))
}
fn right_divide_matrix3_prepared(
left: [[Real; 3]; 3],
prepared: &mut PreparedRightDivisor3,
) -> BlasResult<[[Real; 3]; 3]> {
let right_facts = prepared.facts;
if right_facts.is_identity {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide3-prepared-identity"
);
return Ok(left);
}
if right_facts.is_diagonal {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide3-prepared-diagonal"
);
return divide_matrix3_by_diagonal(left, &prepared.divisor.0);
}
if right_facts.is_affine_translation {
let left_facts = matrix3_facts(&left);
if left_facts.is_affine {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide3-prepared-affine-left-affine-translation"
);
return divide_matrix3_affine_by_affine_translation(left, &prepared.divisor.0);
}
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide3-prepared-affine-by-translation"
);
return divide_matrix3_by_affine_translation(left, &prepared.divisor.0);
}
if right_facts.is_affine && right_facts.is_upper_triangular {
let left_facts = matrix3_facts(&left);
if left_facts.is_affine {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide3-prepared-affine-left-affine-upper-triangular"
);
return divide_matrix3_affine_by_affine_upper_triangular(left, &prepared.divisor.0);
}
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide3-prepared-affine-upper-triangular"
);
return divide_matrix3_by_affine_upper_triangular(left, &prepared.divisor.0);
}
if right_facts.is_upper_triangular {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide3-prepared-upper-triangular"
);
return divide_matrix3_by_upper_triangular(left, &prepared.divisor.0);
}
if right_facts.is_lower_triangular {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide3-prepared-lower-triangular"
);
return divide_matrix3_by_lower_triangular(left, &prepared.divisor.0);
}
if right_facts.is_affine {
let left_facts = matrix3_facts(&left);
let left_is_affine = left_facts.is_affine;
let right_linear_is_diagonal = right_facts.linear_is_diagonal;
let right_is_affine_translation = right_facts.is_affine_translation;
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide3-prepared-affine"
);
if left_is_affine {
if right_is_affine_translation {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide3-prepared-affine-left-affine-translation"
);
return divide_matrix3_affine_by_affine_translation(left, &prepared.divisor.0);
}
if right_linear_is_diagonal {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide3-prepared-affine-left-affine-linear-diagonal"
);
return divide_matrix3_affine_by_affine_linear_diagonal(left, &prepared.divisor.0);
}
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide3-prepared-affine-left-affine"
);
return divide_matrix3_affine_by_affine(left, &prepared.divisor.0);
}
if right_is_affine_translation {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide3-prepared-affine-by-translation"
);
return divide_matrix3_by_affine_translation(left, &prepared.divisor.0);
}
if right_linear_is_diagonal {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide3-prepared-affine-linear-diagonal"
);
return divide_matrix3_by_affine_linear_diagonal(left, &prepared.divisor.0);
}
return divide_matrix3_by_affine(left, &prepared.divisor.0);
}
if !prepared.can_use_shared_adjugate(&left) {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide3-prepared-gauss-jordan"
);
return Ok(transpose_array3(solve_left_system3(
transpose_array3_ref(&prepared.divisor.0),
transpose_array3(left),
)?));
}
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide3-prepared-shared-adjugate"
);
let _ = prepared.prepare_shared_adjugate()?;
let inv_det = prepared
.reciprocal_determinant
.as_ref()
.expect("reciprocal determinant cache should be present");
let adjugate = prepared
.adjugate
.as_ref()
.expect("adjugate cache should be present");
Ok(scale_matrix3(
multiply_arrays3_rhs_ref_with_exact_dense_certificate(left, adjugate),
inv_det,
))
}
fn right_divide_matrix3_prepared_checked(
left: [[Real; 3]; 3],
prepared: &mut PreparedRightDivisor3,
) -> CheckedBlasResult<[[Real; 3]; 3]> {
let right_facts = prepared.facts;
if right_facts.is_identity {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide3-prepared-checked-identity"
);
return Ok(left);
}
if right_facts.is_diagonal {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide3-prepared-checked-diagonal"
);
return divide_matrix3_by_diagonal_checked(left, &prepared.divisor.0);
}
if right_facts.is_affine_translation {
let left_facts = matrix3_facts(&left);
if left_facts.is_affine {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide3-prepared-checked-affine-left-affine-translation"
);
return divide_matrix3_affine_by_affine_translation(left, &prepared.divisor.0);
}
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide3-prepared-checked-affine-by-translation"
);
return divide_matrix3_by_affine_translation(left, &prepared.divisor.0);
}
if right_facts.is_affine && right_facts.is_upper_triangular {
let left_facts = matrix3_facts(&left);
if left_facts.is_affine {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide3-prepared-checked-affine-left-affine-upper-triangular"
);
return divide_matrix3_affine_by_affine_upper_triangular_checked(
left,
&prepared.divisor.0,
);
}
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide3-prepared-checked-affine-upper-triangular"
);
return divide_matrix3_by_affine_upper_triangular_checked(left, &prepared.divisor.0);
}
if right_facts.is_upper_triangular {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide3-prepared-checked-upper-triangular"
);
return divide_matrix3_by_upper_triangular_checked(left, &prepared.divisor.0);
}
if right_facts.is_lower_triangular {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide3-prepared-checked-lower-triangular"
);
return divide_matrix3_by_lower_triangular_checked(left, &prepared.divisor.0);
}
if right_facts.is_affine {
let left_facts = matrix3_facts(&left);
let left_is_affine = left_facts.is_affine;
let right_linear_is_diagonal = right_facts.linear_is_diagonal;
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide3-prepared-checked-affine"
);
if left_is_affine {
if right_linear_is_diagonal {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide3-prepared-checked-affine-left-affine-linear-diagonal"
);
return divide_matrix3_affine_by_affine_linear_diagonal_checked(
left,
&prepared.divisor.0,
);
}
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide3-prepared-checked-affine-left-affine"
);
return divide_matrix3_affine_by_affine_checked(left, &prepared.divisor.0);
}
if right_linear_is_diagonal {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide3-prepared-checked-affine-linear-diagonal"
);
return divide_matrix3_by_affine_linear_diagonal_checked(left, &prepared.divisor.0);
}
return divide_matrix3_by_affine_checked(left, &prepared.divisor.0);
}
if !prepared.can_use_shared_adjugate(&left) {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide3-prepared-checked-gauss-jordan"
);
return Ok(transpose_array3(solve_left_system3_checked(
transpose_array3_ref(&prepared.divisor.0),
transpose_array3(left),
)?));
}
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide3-prepared-checked-shared-adjugate"
);
let _ = prepared.prepare_shared_adjugate_checked()?;
let inv_det = prepared
.reciprocal_determinant
.as_ref()
.expect("reciprocal determinant cache should be present");
let adjugate = prepared
.adjugate
.as_ref()
.expect("adjugate cache should be present");
Ok(scale_matrix3(
multiply_arrays3_rhs_ref_with_exact_dense_certificate(left, adjugate),
inv_det,
))
}
fn right_divide_matrix3_prepared_checked_with_abort(
left: [[Real; 3]; 3],
prepared: &mut PreparedRightDivisor3,
signal: &AbortSignal,
) -> CheckedBlasResult<[[Real; 3]; 3]> {
let right_facts = prepared.facts;
if right_facts.is_identity {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide3-prepared-checked-abort-identity"
);
return Ok(left);
}
if right_facts.is_diagonal {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide3-prepared-checked-abort-diagonal"
);
return divide_matrix3_by_diagonal_checked_with_abort(left, &prepared.divisor.0, signal);
}
if right_facts.is_affine_translation {
let left_facts = matrix3_facts(&left);
if left_facts.is_affine {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide3-prepared-checked-abort-affine-left-affine-translation"
);
return divide_matrix3_affine_by_affine_translation(left, &prepared.divisor.0);
}
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide3-prepared-checked-abort-affine-by-translation"
);
return divide_matrix3_by_affine_translation(left, &prepared.divisor.0);
}
if true && right_facts.is_affine && right_facts.is_upper_triangular {
let left_facts = matrix3_facts(&left);
if left_facts.is_affine {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide3-prepared-checked-abort-affine-left-affine-upper-triangular"
);
return divide_matrix3_affine_by_affine_upper_triangular_checked_with_abort(
left,
&prepared.divisor.0,
signal,
);
}
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide3-prepared-checked-abort-affine-upper-triangular"
);
return divide_matrix3_by_affine_upper_triangular_checked_with_abort(
left,
&prepared.divisor.0,
signal,
);
}
if right_facts.is_upper_triangular {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide3-prepared-checked-abort-upper-triangular"
);
return divide_matrix3_by_upper_triangular_checked_with_abort(
left,
&prepared.divisor.0,
signal,
);
}
if right_facts.is_lower_triangular {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide3-prepared-checked-abort-lower-triangular"
);
return divide_matrix3_by_lower_triangular_checked_with_abort(
left,
&prepared.divisor.0,
signal,
);
}
if right_facts.is_affine {
let left_facts = matrix3_facts(&left);
let left_is_affine = left_facts.is_affine;
let right_linear_is_diagonal = right_facts.linear_is_diagonal;
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide3-prepared-checked-abort-affine"
);
if left_is_affine {
if right_linear_is_diagonal {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide3-prepared-checked-abort-affine-left-affine-linear-diagonal"
);
return divide_matrix3_affine_by_affine_linear_diagonal_checked_with_abort(
left,
&prepared.divisor.0,
signal,
);
}
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide3-prepared-checked-abort-affine-left-affine"
);
return divide_matrix3_affine_by_affine_checked_with_abort(
left,
&prepared.divisor.0,
signal,
);
}
if right_linear_is_diagonal {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide3-prepared-checked-abort-affine-linear-diagonal"
);
return divide_matrix3_by_affine_linear_diagonal_checked_with_abort(
left,
&prepared.divisor.0,
signal,
);
}
return divide_matrix3_by_affine_checked_with_abort(left, &prepared.divisor.0, signal);
}
if !prepared.can_use_shared_adjugate(&left) {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide3-prepared-checked-abort-gauss-jordan"
);
return Ok(transpose_array3(solve_left_system3_checked_with_abort(
transpose_array3_ref(&prepared.divisor.0),
transpose_array3(left),
signal,
)?));
}
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide3-prepared-checked-abort-shared-adjugate"
);
let _ = prepared.prepare_shared_adjugate_checked_with_abort(signal)?;
let inv_det = prepared
.reciprocal_determinant
.as_ref()
.expect("reciprocal determinant cache should be present");
let adjugate = prepared
.adjugate
.as_ref()
.expect("adjugate cache should be present");
Ok(scale_matrix3(
multiply_arrays3_rhs_ref_with_exact_dense_certificate(left, adjugate),
inv_det,
))
}
fn right_divide_matrix4(left: [[Real; 4]; 4], right: [[Real; 4]; 4]) -> BlasResult<[[Real; 4]; 4]> {
if can_use_dense_exact_shared_adjugate4(&right) {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide4-dense-exact-shared-adjugate"
);
return right_divide_matrix4_dense_exact_shared(&left, &right);
}
let right_facts = matrix4_facts(&right);
if right_facts.is_identity {
crate::trace_dispatch!("hyperlattice_matrix", "helper", "right-divide4-identity");
return Ok(left);
}
if right_facts.is_diagonal {
crate::trace_dispatch!("hyperlattice_matrix", "helper", "right-divide4-diagonal");
return divide_matrix4_by_diagonal(left, &right);
}
if right_facts.is_affine_translation {
let left_facts = matrix4_facts(&left);
if left_facts.is_affine {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide4-affine-left-affine-translation"
);
return divide_matrix4_affine_by_affine_translation(left, &right);
}
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide4-affine-by-translation"
);
return divide_matrix4_by_affine_translation(left, &right);
}
if true && right_facts.is_affine && right_facts.is_upper_triangular {
let left_facts = matrix4_facts(&left);
if left_facts.is_affine {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide4-affine-left-affine-upper-triangular"
);
return divide_matrix4_affine_by_affine_upper_triangular(left, &right);
}
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide4-affine-upper-triangular"
);
return divide_matrix4_by_affine_upper_triangular(left, &right);
}
if right_facts.is_upper_triangular {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide4-upper-triangular"
);
return divide_matrix4_by_upper_triangular(left, &right);
}
if right_facts.is_lower_triangular {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide4-lower-triangular"
);
return divide_matrix4_by_lower_triangular(left, &right);
}
if right_facts.is_affine {
let left_facts = matrix4_facts(&left);
let left_is_affine = left_facts.is_affine;
let right_linear_is_diagonal = right_facts.linear_is_diagonal;
let right_is_affine_translation = right_facts.is_affine_translation;
crate::trace_dispatch!("hyperlattice_matrix", "helper", "right-divide4-affine");
if left_is_affine {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide4-affine-left-affine"
);
if right_is_affine_translation {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide4-affine-left-affine-translation"
);
return divide_matrix4_affine_by_affine_translation(left, &right);
}
if right_linear_is_diagonal {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide4-affine-left-affine-linear-diagonal"
);
return divide_matrix4_affine_by_affine_linear_diagonal(left, &right);
}
return divide_matrix4_affine_by_affine_no_translation(left, &right);
}
if right_is_affine_translation {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide4-affine-by-translation"
);
return divide_matrix4_by_affine_translation(left, &right);
}
if right_linear_is_diagonal {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide4-affine-linear-diagonal"
);
if right_facts.affine_linear_diagonal_is_definitely_nonzero {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide4-affine-linear-diagonal-known-nonzero"
);
return divide_matrix4_by_affine_linear_diagonal(left, &right);
}
return divide_matrix4_by_affine_linear_diagonal_checked(left, &right);
}
return divide_matrix4_by_affine_no_translation(left, &right);
}
if !prefer_shared_adjugate_right_division(&left, &right) {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide4-gauss-jordan"
);
return Ok(transpose_array4(solve_left_system4(
transpose_array4(right),
transpose_array4(left),
)?));
}
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide4-shared-adjugate"
);
let dense_exact = true && right_facts.is_definitely_dense_for_inverse;
let (s, c) = if dense_exact {
matrix4_factors_dense_exact(&right)
} else {
matrix4_factors(&right)
};
let det = determinant4_from_factors(&s, &c);
let inv_det = det.inverse()?;
let adjugate = if dense_exact {
matrix4_adjugate_from_factors_dense_exact(&right, &s, &c)
} else {
matrix4_adjugate_from_factors(&right, &s, &c)
};
Ok(scale_matrix4(
multiply_arrays4_ref_with_dense_certificate(&left, &adjugate),
&inv_det,
))
}
#[inline]
fn can_use_dense_exact_shared_adjugate4(right: &[[Real; 4]; 4]) -> bool {
true && matrix4_is_definitely_dense_for_inverse(right)
&& matrix4_exact_rational_kind(right) != ExactRationalKind::NonRational
}
#[inline]
fn right_divide_matrix4_dense_exact_shared(
left: &[[Real; 4]; 4],
right: &[[Real; 4]; 4],
) -> BlasResult<[[Real; 4]; 4]> {
let (s, c) = matrix4_factors_dense_exact_known_rational(right);
let det = determinant4_from_factors_known_rational(&s, &c);
let inv_det = det.inverse()?;
let adjugate = matrix4_adjugate_from_factors_dense_exact_known_rational(right, &s, &c);
let product = if matrix4_exact_rational_kind(left) != ExactRationalKind::NonRational {
multiply_arrays4_dense_known_rational_ref(left, &adjugate)
} else {
multiply_arrays4_ref_with_dense_certificate(left, &adjugate)
};
Ok(scale_matrix4(product, &inv_det))
}
#[inline]
fn right_divide_matrix4_dense_exact_shared_checked(
left: &[[Real; 4]; 4],
right: &[[Real; 4]; 4],
) -> CheckedBlasResult<[[Real; 4]; 4]> {
let (s, c) = matrix4_factors_dense_exact_known_rational(right);
let det = determinant4_from_factors_known_rational(&s, &c);
require_known_nonzero(&det)?;
let inv_det = det.inverse()?;
let adjugate = matrix4_adjugate_from_factors_dense_exact_known_rational(right, &s, &c);
let product = if matrix4_exact_rational_kind(left) != ExactRationalKind::NonRational {
multiply_arrays4_dense_known_rational_ref(left, &adjugate)
} else {
multiply_arrays4_ref_with_dense_certificate(left, &adjugate)
};
Ok(scale_matrix4(product, &inv_det))
}
#[inline]
fn right_divide_matrix4_dense_exact_shared_checked_with_abort(
left: &[[Real; 4]; 4],
right: &[[Real; 4]; 4],
signal: &AbortSignal,
) -> CheckedBlasResult<[[Real; 4]; 4]> {
let (s, c) = matrix4_factors_dense_exact_known_rational(right);
let det = with_abort(determinant4_from_factors_known_rational(&s, &c), signal);
require_known_nonzero(&det)?;
let inv_det = det.inverse()?;
let adjugate = matrix4_adjugate_from_factors_dense_exact_known_rational(right, &s, &c);
let product = if matrix4_exact_rational_kind(left) != ExactRationalKind::NonRational {
multiply_arrays4_dense_known_rational_ref(left, &adjugate)
} else {
multiply_arrays4_ref_with_dense_certificate(left, &adjugate)
};
Ok(scale_matrix4(product, &inv_det))
}
fn right_divide_matrix4_prepared(
left: [[Real; 4]; 4],
prepared: &mut PreparedRightDivisor4,
) -> BlasResult<[[Real; 4]; 4]> {
let right_facts = prepared.facts;
if right_facts.is_identity {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide4-prepared-identity"
);
return Ok(left);
}
if right_facts.is_diagonal {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide4-prepared-diagonal"
);
return divide_matrix4_by_diagonal(left, &prepared.divisor.0);
}
if right_facts.is_affine_translation {
let left_facts = matrix4_facts(&left);
if left_facts.is_affine {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide4-prepared-affine-left-affine-translation"
);
return divide_matrix4_affine_by_affine_translation(left, &prepared.divisor.0);
}
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide4-prepared-affine-by-translation"
);
return divide_matrix4_by_affine_translation(left, &prepared.divisor.0);
}
if true && right_facts.is_affine && right_facts.is_upper_triangular {
let left_facts = matrix4_facts(&left);
if left_facts.is_affine {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide4-prepared-affine-left-affine-upper-triangular"
);
return divide_matrix4_affine_by_affine_upper_triangular(left, &prepared.divisor.0);
}
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide4-prepared-affine-upper-triangular"
);
return divide_matrix4_by_affine_upper_triangular(left, &prepared.divisor.0);
}
if right_facts.is_upper_triangular {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide4-prepared-upper-triangular"
);
return divide_matrix4_by_upper_triangular(left, &prepared.divisor.0);
}
if right_facts.is_lower_triangular {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide4-prepared-lower-triangular"
);
return divide_matrix4_by_lower_triangular(left, &prepared.divisor.0);
}
if right_facts.is_affine {
let left_facts = matrix4_facts(&left);
let left_is_affine = left_facts.is_affine;
let right_linear_is_diagonal = right_facts.linear_is_diagonal;
let right_is_affine_translation = right_facts.is_affine_translation;
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide4-prepared-affine"
);
if left_is_affine {
if right_is_affine_translation {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide4-prepared-affine-left-affine-translation"
);
return divide_matrix4_affine_by_affine_translation(left, &prepared.divisor.0);
}
if right_linear_is_diagonal {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide4-prepared-affine-left-affine-linear-diagonal"
);
return divide_matrix4_affine_by_affine_linear_diagonal(left, &prepared.divisor.0);
}
return divide_matrix4_affine_by_affine_no_translation(left, &prepared.divisor.0);
}
if right_is_affine_translation {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide4-prepared-affine-by-translation"
);
return divide_matrix4_by_affine_translation(left, &prepared.divisor.0);
}
if right_linear_is_diagonal {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide4-prepared-affine-linear-diagonal"
);
if right_facts.affine_linear_diagonal_is_definitely_nonzero {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide4-prepared-affine-linear-diagonal-known-nonzero"
);
return divide_matrix4_by_affine_linear_diagonal(left, &prepared.divisor.0);
}
return divide_matrix4_by_affine_linear_diagonal_checked(left, &prepared.divisor.0);
}
return divide_matrix4_by_affine_no_translation(left, &prepared.divisor.0);
}
if !prepared.can_use_shared_adjugate(&left) {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide4-prepared-gauss-jordan"
);
return Ok(transpose_array4(solve_left_system4(
transpose_array4_ref(&prepared.divisor.0),
transpose_array4(left),
)?));
}
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide4-prepared-shared-adjugate"
);
let _ = prepared.prepare_shared_adjugate()?;
let inv_det = prepared
.reciprocal_determinant
.as_ref()
.expect("reciprocal determinant cache should be present");
let adjugate = prepared
.adjugate
.as_ref()
.expect("adjugate cache should be present");
let product = if prepared.right_exact_rational_kind != ExactRationalKind::NonRational
&& matrix4_exact_rational_kind(&left) != ExactRationalKind::NonRational
{
multiply_arrays4_dense_known_rational_ref(&left, adjugate)
} else {
multiply_arrays4_rhs_ref_with_dense_certificate(left, adjugate)
};
Ok(scale_matrix4(product, inv_det))
}
fn right_divide_matrix4_prepared_exact_rational_left(
left: [[Real; 4]; 4],
prepared: &mut PreparedRightDivisor4,
) -> BlasResult<[[Real; 4]; 4]> {
if true && prepared.right_exact_rational_kind != ExactRationalKind::NonRational {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide4-prepared-certified-left-exact-shared-adjugate"
);
let _ = prepared.prepare_shared_adjugate()?;
let inv_det = prepared
.reciprocal_determinant
.as_ref()
.expect("reciprocal determinant cache should be present");
let adjugate = prepared
.adjugate
.as_ref()
.expect("adjugate cache should be present");
let product = multiply_arrays4_dense_known_rational_ref(&left, adjugate);
return Ok(scale_matrix4(product, inv_det));
}
right_divide_matrix4_prepared(left, prepared)
}
fn right_divide_matrix4_prepared_checked(
left: [[Real; 4]; 4],
prepared: &mut PreparedRightDivisor4,
) -> CheckedBlasResult<[[Real; 4]; 4]> {
let right_facts = prepared.facts;
if right_facts.is_identity {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide4-prepared-checked-identity"
);
return Ok(left);
}
if right_facts.is_diagonal {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide4-prepared-checked-diagonal"
);
return divide_matrix4_by_diagonal_checked(left, &prepared.divisor.0);
}
if right_facts.is_affine_translation {
let left_facts = matrix4_facts(&left);
if left_facts.is_affine {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide4-prepared-checked-affine-left-affine-translation"
);
return divide_matrix4_affine_by_affine_checked_assumed_affine_translation(
left,
&prepared.divisor.0,
);
}
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide4-prepared-checked-affine-by-translation"
);
return divide_matrix4_by_affine_checked_assumed_affine_translation(
left,
&prepared.divisor.0,
);
}
if true && right_facts.is_affine && right_facts.is_upper_triangular {
let left_facts = matrix4_facts(&left);
if left_facts.is_affine {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide4-prepared-checked-affine-left-affine-upper-triangular"
);
return divide_matrix4_affine_by_affine_upper_triangular_checked(
left,
&prepared.divisor.0,
);
}
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide4-prepared-checked-affine-upper-triangular"
);
return divide_matrix4_by_affine_upper_triangular_checked(left, &prepared.divisor.0);
}
if right_facts.is_upper_triangular {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide4-prepared-checked-upper-triangular"
);
return divide_matrix4_by_upper_triangular_checked(left, &prepared.divisor.0);
}
if right_facts.is_lower_triangular {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide4-prepared-checked-lower-triangular"
);
return divide_matrix4_by_lower_triangular_checked(left, &prepared.divisor.0);
}
if right_facts.is_affine {
let left_facts = matrix4_facts(&left);
let left_is_affine = left_facts.is_affine;
let right_linear_is_diagonal = right_facts.linear_is_diagonal;
let right_is_affine_translation = right_facts.is_affine_translation;
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide4-prepared-checked-affine"
);
if left_is_affine {
if right_is_affine_translation {
return divide_matrix4_affine_by_affine_checked_assumed_affine_translation(
left,
&prepared.divisor.0,
);
}
if right_linear_is_diagonal {
if right_facts.affine_linear_diagonal_is_definitely_nonzero {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide4-prepared-checked-affine-left-affine-linear-diagonal-known-nonzero"
);
return divide_matrix4_affine_by_affine_linear_diagonal(
left,
&prepared.divisor.0,
);
}
return divide_matrix4_affine_by_affine_linear_diagonal_checked(
left,
&prepared.divisor.0,
);
}
return divide_matrix4_affine_by_affine_checked(left, &prepared.divisor.0);
}
if right_is_affine_translation {
return divide_matrix4_by_affine_checked_assumed_affine_translation(
left,
&prepared.divisor.0,
);
}
if right_linear_is_diagonal {
if right_facts.affine_linear_diagonal_is_definitely_nonzero {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide4-prepared-checked-affine-linear-diagonal-known-nonzero"
);
return divide_matrix4_by_affine_linear_diagonal(left, &prepared.divisor.0);
}
return divide_matrix4_by_affine_linear_diagonal_checked(left, &prepared.divisor.0);
}
return divide_matrix4_by_affine_checked(left, &prepared.divisor.0);
}
if !prepared.can_use_shared_adjugate(&left) {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide4-prepared-checked-gauss-jordan"
);
return Ok(transpose_array4(solve_left_system4_checked(
transpose_array4_ref(&prepared.divisor.0),
transpose_array4(left),
)?));
}
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide4-prepared-checked-shared-adjugate"
);
let _ = prepared.prepare_shared_adjugate_checked()?;
let inv_det = prepared
.reciprocal_determinant
.as_ref()
.expect("reciprocal determinant cache should be present");
let adjugate = prepared
.adjugate
.as_ref()
.expect("adjugate cache should be present");
let product = if prepared.right_exact_rational_kind != ExactRationalKind::NonRational
&& matrix4_exact_rational_kind(&left) != ExactRationalKind::NonRational
{
multiply_arrays4_dense_known_rational_ref(&left, adjugate)
} else {
multiply_arrays4_rhs_ref_with_dense_certificate(left, adjugate)
};
Ok(scale_matrix4(product, inv_det))
}
fn right_divide_matrix4_prepared_checked_with_abort(
left: [[Real; 4]; 4],
prepared: &mut PreparedRightDivisor4,
signal: &AbortSignal,
) -> CheckedBlasResult<[[Real; 4]; 4]> {
let right_facts = prepared.facts;
if right_facts.is_identity {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide4-prepared-checked-abort-identity"
);
return Ok(left);
}
if right_facts.is_diagonal {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide4-prepared-checked-abort-diagonal"
);
return divide_matrix4_by_diagonal_checked_with_abort(left, &prepared.divisor.0, signal);
}
if right_facts.is_affine_translation {
let left_facts = matrix4_facts(&left);
if left_facts.is_affine {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide4-prepared-checked-abort-affine-left-affine-translation"
);
return divide_matrix4_affine_by_affine_checked_with_abort_assumed_affine_translation(
left,
&prepared.divisor.0,
signal,
);
}
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide4-prepared-checked-abort-affine-by-translation"
);
return divide_matrix4_by_affine_checked_with_abort_assumed_affine_translation(
left,
&prepared.divisor.0,
signal,
);
}
if true && right_facts.is_affine && right_facts.is_upper_triangular {
let left_facts = matrix4_facts(&left);
if left_facts.is_affine {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide4-prepared-checked-abort-affine-left-affine-upper-triangular"
);
return divide_matrix4_affine_by_affine_upper_triangular_checked_with_abort(
left,
&prepared.divisor.0,
signal,
);
}
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide4-prepared-checked-abort-affine-upper-triangular"
);
return divide_matrix4_by_affine_upper_triangular_checked_with_abort(
left,
&prepared.divisor.0,
signal,
);
}
if right_facts.is_upper_triangular {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide4-prepared-checked-abort-upper-triangular"
);
return divide_matrix4_by_upper_triangular_checked_with_abort(
left,
&prepared.divisor.0,
signal,
);
}
if right_facts.is_lower_triangular {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide4-prepared-checked-abort-lower-triangular"
);
return divide_matrix4_by_lower_triangular_checked_with_abort(
left,
&prepared.divisor.0,
signal,
);
}
if right_facts.is_affine {
let left_facts = matrix4_facts(&left);
let left_is_affine = left_facts.is_affine;
let right_linear_is_diagonal = right_facts.linear_is_diagonal;
let right_is_affine_translation = right_facts.is_affine_translation;
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide4-prepared-checked-abort-affine"
);
if left_is_affine {
if right_is_affine_translation {
return divide_matrix4_affine_by_affine_checked_with_abort_assumed_affine_translation(
left,
&prepared.divisor.0,
signal,
);
}
if right_linear_is_diagonal {
if right_facts.affine_linear_diagonal_is_definitely_nonzero {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide4-prepared-checked-abort-affine-left-affine-linear-diagonal-known-nonzero"
);
return divide_matrix4_affine_by_affine_linear_diagonal(
left,
&prepared.divisor.0,
);
}
return divide_matrix4_affine_by_affine_linear_diagonal_checked_with_abort(
left,
&prepared.divisor.0,
signal,
);
}
return divide_matrix4_affine_by_affine_checked_with_abort(
left,
&prepared.divisor.0,
signal,
);
}
if right_is_affine_translation {
return divide_matrix4_by_affine_checked_with_abort_assumed_affine_translation(
left,
&prepared.divisor.0,
signal,
);
}
if right_linear_is_diagonal {
if right_facts.affine_linear_diagonal_is_definitely_nonzero {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide4-prepared-checked-abort-affine-linear-diagonal-known-nonzero"
);
return divide_matrix4_by_affine_linear_diagonal(left, &prepared.divisor.0);
}
return divide_matrix4_by_affine_linear_diagonal_checked_with_abort(
left,
&prepared.divisor.0,
signal,
);
}
return divide_matrix4_by_affine_checked_with_abort(left, &prepared.divisor.0, signal);
}
if !prepared.can_use_shared_adjugate(&left) {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide4-prepared-checked-abort-gauss-jordan"
);
return Ok(transpose_array4(solve_left_system4_checked_with_abort(
transpose_array4_ref(&prepared.divisor.0),
transpose_array4(left),
signal,
)?));
}
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide4-prepared-checked-abort-shared-adjugate"
);
let _ = prepared.prepare_shared_adjugate_checked_with_abort(signal)?;
let inv_det = prepared
.reciprocal_determinant
.as_ref()
.expect("reciprocal determinant cache should be present");
let adjugate = prepared
.adjugate
.as_ref()
.expect("adjugate cache should be present");
let product = if prepared.right_exact_rational_kind != ExactRationalKind::NonRational
&& matrix4_exact_rational_kind(&left) != ExactRationalKind::NonRational
{
multiply_arrays4_dense_known_rational_ref(&left, adjugate)
} else {
multiply_arrays4_rhs_ref_with_dense_certificate(left, adjugate)
};
Ok(scale_matrix4(product, inv_det))
}
fn right_divide_matrix4_ref(
left: &[[Real; 4]; 4],
right: &[[Real; 4]; 4],
) -> BlasResult<[[Real; 4]; 4]> {
if can_use_dense_exact_shared_adjugate4(right) {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide4-ref-dense-exact-shared-adjugate"
);
return right_divide_matrix4_dense_exact_shared(left, right);
}
let right_facts = matrix4_facts(right);
if right_facts.is_identity {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide4-ref-identity"
);
return Ok(left.clone());
}
if right_facts.is_diagonal {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide4-ref-diagonal"
);
return divide_matrix4_by_diagonal(left.clone(), right);
}
if true && right_facts.is_affine && right_facts.is_upper_triangular {
let left_facts = matrix4_facts(left);
if left_facts.is_affine {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide4-ref-affine-left-affine-upper-triangular"
);
return divide_matrix4_affine_by_affine_upper_triangular(left.clone(), right);
}
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide4-ref-affine-upper-triangular"
);
return divide_matrix4_by_affine_upper_triangular(left.clone(), right);
}
if right_facts.is_upper_triangular {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide4-ref-upper-triangular"
);
return divide_matrix4_by_upper_triangular(left.clone(), right);
}
if right_facts.is_lower_triangular {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide4-ref-lower-triangular"
);
return divide_matrix4_by_lower_triangular(left.clone(), right);
}
if right_facts.is_affine {
let left_facts = matrix4_facts(left);
let left_is_affine = left_facts.is_affine;
let right_linear_is_diagonal = right_facts.linear_is_diagonal;
let right_is_affine_translation = right_facts.is_affine_translation;
crate::trace_dispatch!("hyperlattice_matrix", "helper", "right-divide4-ref-affine");
if left_is_affine {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide4-ref-affine-left-affine"
);
if right_is_affine_translation {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide4-ref-affine-by-affine-translation"
);
return divide_matrix4_affine_by_affine_ref_translation(left, right);
}
if right_linear_is_diagonal {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide4-ref-affine-left-affine-linear-diagonal"
);
return divide_matrix4_affine_by_affine_ref_linear_diagonal(left, right);
}
return divide_matrix4_affine_by_affine_ref_no_translation(left, right);
}
if right_is_affine_translation {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide4-ref-by-affine-translation"
);
return divide_matrix4_by_affine_ref_assumed_affine_translation(left, right);
}
if right_linear_is_diagonal {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide4-ref-affine-linear-diagonal"
);
return divide_matrix4_by_affine_linear_diagonal_ref(left, right);
}
return divide_matrix4_by_affine_ref_no_translation(left, right);
}
if !prefer_shared_adjugate_right_division(left, right) {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide4-ref-gauss-jordan"
);
return Ok(transpose_array4(solve_left_system4(
transpose_array4_ref(right),
transpose_array4_ref(left),
)?));
}
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide4-ref-shared-adjugate"
);
let dense_exact = true && right_facts.is_definitely_dense_for_inverse;
let (s, c) = if dense_exact {
matrix4_factors_dense_exact(right)
} else {
matrix4_factors(right)
};
let det = determinant4_from_factors(&s, &c);
let inv_det = det.inverse()?;
let adjugate = if dense_exact {
matrix4_adjugate_from_factors_dense_exact(right, &s, &c)
} else {
matrix4_adjugate_from_factors(right, &s, &c)
};
Ok(scale_matrix4(
multiply_arrays4_ref_with_dense_certificate(left, &adjugate),
&inv_det,
))
}
fn right_divide_matrix4_checked(
left: [[Real; 4]; 4],
right: [[Real; 4]; 4],
) -> CheckedBlasResult<[[Real; 4]; 4]> {
if can_use_dense_exact_shared_adjugate4(&right) {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide4-checked-dense-exact-shared-adjugate"
);
return right_divide_matrix4_dense_exact_shared_checked(&left, &right);
}
let right_facts = matrix4_facts(&right);
if right_facts.is_identity {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide4-checked-identity"
);
return Ok(left);
}
if right_facts.is_diagonal {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide4-checked-diagonal"
);
return divide_matrix4_by_diagonal_checked(left, &right);
}
if right_facts.is_affine_translation {
let left_facts = matrix4_facts(&left);
if left_facts.is_affine {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide4-checked-affine-left-affine-translation"
);
return divide_matrix4_affine_by_affine_checked_assumed_affine_translation(
left, &right,
);
}
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide4-checked-affine-by-translation"
);
return divide_matrix4_by_affine_checked_assumed_affine_translation(left, &right);
}
if true && right_facts.is_affine && right_facts.is_upper_triangular {
let left_facts = matrix4_facts(&left);
if left_facts.is_affine {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide4-checked-affine-left-affine-upper-triangular"
);
return divide_matrix4_affine_by_affine_upper_triangular_checked(left, &right);
}
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide4-checked-affine-upper-triangular"
);
return divide_matrix4_by_affine_upper_triangular_checked(left, &right);
}
if right_facts.is_upper_triangular {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide4-checked-upper-triangular"
);
return divide_matrix4_by_upper_triangular_checked(left, &right);
}
if right_facts.is_lower_triangular {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide4-checked-lower-triangular"
);
return divide_matrix4_by_lower_triangular_checked(left, &right);
}
if right_facts.is_affine {
let left_facts = matrix4_facts(&left);
let left_is_affine = left_facts.is_affine;
let right_linear_is_diagonal = right_facts.linear_is_diagonal;
let right_is_affine_translation = right_facts.is_affine_translation;
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide4-checked-affine"
);
if left_is_affine {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide4-checked-affine-left-affine"
);
if right_is_affine_translation {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide4-checked-affine-by-affine-translation"
);
return divide_matrix4_affine_by_affine_checked_assumed_affine_translation(
left, &right,
);
}
if right_linear_is_diagonal {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide4-checked-affine-left-affine-linear-diagonal"
);
if right_facts.affine_linear_diagonal_is_definitely_nonzero {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide4-checked-affine-left-affine-linear-diagonal-known-nonzero"
);
return divide_matrix4_affine_by_affine_linear_diagonal(left, &right);
}
return divide_matrix4_affine_by_affine_linear_diagonal_checked(left, &right);
}
return divide_matrix4_affine_by_affine_checked(left, &right);
}
if right_is_affine_translation {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide4-checked-by-affine-translation"
);
return divide_matrix4_by_affine_checked_assumed_affine_translation(left, &right);
}
if right_linear_is_diagonal {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide4-checked-affine-linear-diagonal"
);
if right_facts.affine_linear_diagonal_is_definitely_nonzero {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide4-checked-affine-linear-diagonal-known-nonzero"
);
return divide_matrix4_by_affine_linear_diagonal(left, &right);
}
return divide_matrix4_by_affine_linear_diagonal_checked(left, &right);
}
return divide_matrix4_by_affine_checked(left, &right);
}
if !prefer_shared_adjugate_right_division(&left, &right) {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide4-checked-gauss-jordan"
);
return Ok(transpose_array4(solve_left_system4_checked(
transpose_array4(right),
transpose_array4(left),
)?));
}
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide4-checked-shared-adjugate"
);
let dense_exact = true && right_facts.is_definitely_dense_for_inverse;
let (s, c) = if dense_exact {
matrix4_factors_dense_exact(&right)
} else {
matrix4_factors(&right)
};
let det = determinant4_from_factors(&s, &c);
require_known_nonzero(&det)?;
let inv_det = det.inverse()?;
let adjugate = if dense_exact {
matrix4_adjugate_from_factors_dense_exact(&right, &s, &c)
} else {
matrix4_adjugate_from_factors(&right, &s, &c)
};
Ok(scale_matrix4(
multiply_arrays4_ref_with_dense_certificate(&left, &adjugate),
&inv_det,
))
}
fn right_divide_matrix4_checked_with_abort(
left: [[Real; 4]; 4],
right: [[Real; 4]; 4],
signal: &AbortSignal,
) -> CheckedBlasResult<[[Real; 4]; 4]> {
if can_use_dense_exact_shared_adjugate4(&right) {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide4-checked-abort-dense-exact-shared-adjugate"
);
return right_divide_matrix4_dense_exact_shared_checked_with_abort(&left, &right, signal);
}
let right_facts = matrix4_facts(&right);
if right_facts.is_identity {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide4-checked-abort-identity"
);
return Ok(left);
}
if right_facts.is_diagonal {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide4-checked-abort-diagonal"
);
return divide_matrix4_by_diagonal_checked_with_abort(left, &right, signal);
}
if right_facts.is_affine_translation {
let left_facts = matrix4_facts(&left);
if left_facts.is_affine {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide4-checked-abort-affine-left-affine-translation"
);
return divide_matrix4_affine_by_affine_checked_with_abort_assumed_affine_translation(
left, &right, signal,
);
}
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide4-checked-abort-affine-by-translation"
);
return divide_matrix4_by_affine_checked_with_abort_assumed_affine_translation(
left, &right, signal,
);
}
if true && right_facts.is_affine && right_facts.is_upper_triangular {
let left_facts = matrix4_facts(&left);
if left_facts.is_affine {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide4-checked-abort-affine-left-affine-upper-triangular"
);
return divide_matrix4_affine_by_affine_upper_triangular_checked_with_abort(
left, &right, signal,
);
}
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide4-checked-abort-affine-upper-triangular"
);
return divide_matrix4_by_affine_upper_triangular_checked_with_abort(left, &right, signal);
}
if right_facts.is_upper_triangular {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide4-checked-abort-upper-triangular"
);
return divide_matrix4_by_upper_triangular_checked_with_abort(left, &right, signal);
}
if right_facts.is_lower_triangular {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide4-checked-abort-lower-triangular"
);
return divide_matrix4_by_lower_triangular_checked_with_abort(left, &right, signal);
}
if right_facts.is_affine {
let left_facts = matrix4_facts(&left);
let left_is_affine = left_facts.is_affine;
let right_linear_is_diagonal = right_facts.linear_is_diagonal;
let right_is_affine_translation = right_facts.is_affine_translation;
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide4-checked-abort-affine"
);
if left_is_affine {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide4-checked-abort-affine-left-affine"
);
if right_is_affine_translation {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide4-checked-abort-affine-by-affine-translation"
);
return divide_matrix4_affine_by_affine_checked_with_abort_assumed_affine_translation(
left,
&right,
signal,
);
}
if right_linear_is_diagonal {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide4-checked-abort-affine-left-affine-linear-diagonal"
);
if right_facts.affine_linear_diagonal_is_definitely_nonzero {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide4-checked-abort-affine-left-affine-linear-diagonal-known-nonzero"
);
return divide_matrix4_affine_by_affine_linear_diagonal(left, &right);
}
return divide_matrix4_affine_by_affine_linear_diagonal_checked_with_abort(
left, &right, signal,
);
}
return divide_matrix4_affine_by_affine_checked_with_abort(left, &right, signal);
}
if right_is_affine_translation {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide4-checked-abort-by-affine-translation"
);
return divide_matrix4_by_affine_checked_with_abort_assumed_affine_translation(
left, &right, signal,
);
}
if right_linear_is_diagonal {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide4-checked-abort-affine-linear-diagonal"
);
if right_facts.affine_linear_diagonal_is_definitely_nonzero {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide4-checked-abort-affine-linear-diagonal-known-nonzero"
);
return divide_matrix4_by_affine_linear_diagonal(left, &right);
}
return divide_matrix4_by_affine_linear_diagonal_checked_with_abort(
left, &right, signal,
);
}
return divide_matrix4_by_affine_checked_with_abort(left, &right, signal);
}
if !prefer_shared_adjugate_right_division(&left, &right) {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide4-checked-abort-gauss-jordan"
);
return Ok(transpose_array4(solve_left_system4_checked_with_abort(
transpose_array4(right),
transpose_array4(left),
signal,
)?));
}
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide4-checked-abort-shared-adjugate"
);
let dense_exact = true && right_facts.is_definitely_dense_for_inverse;
let (s, c) = if dense_exact {
matrix4_factors_dense_exact(&right)
} else {
matrix4_factors(&right)
};
let det = determinant4_from_factors(&s, &c);
let det = with_abort(det, signal);
require_known_nonzero(&det)?;
let inv_det = det.inverse()?;
let adjugate = if dense_exact {
matrix4_adjugate_from_factors_dense_exact(&right, &s, &c)
} else {
matrix4_adjugate_from_factors(&right, &s, &c)
};
Ok(scale_matrix4(
multiply_arrays4_ref_with_dense_certificate(&left, &adjugate),
&inv_det,
))
}
#[inline]
fn multiply_arrays3_borrowed(left: &[[Real; 3]; 3], right: &[[Real; 3]; 3]) -> [[Real; 3]; 3] {
let left_nonzero = [
[
!left[0][0].definitely_zero(),
!left[0][1].definitely_zero(),
!left[0][2].definitely_zero(),
],
[
!left[1][0].definitely_zero(),
!left[1][1].definitely_zero(),
!left[1][2].definitely_zero(),
],
[
!left[2][0].definitely_zero(),
!left[2][1].definitely_zero(),
!left[2][2].definitely_zero(),
],
];
let right_nonzero = [
[
!right[0][0].definitely_zero(),
!right[0][1].definitely_zero(),
!right[0][2].definitely_zero(),
],
[
!right[1][0].definitely_zero(),
!right[1][1].definitely_zero(),
!right[1][2].definitely_zero(),
],
[
!right[2][0].definitely_zero(),
!right[2][1].definitely_zero(),
!right[2][2].definitely_zero(),
],
];
let left_all_nonzero = left_nonzero[0][0]
&& left_nonzero[0][1]
&& left_nonzero[0][2]
&& left_nonzero[1][0]
&& left_nonzero[1][1]
&& left_nonzero[1][2]
&& left_nonzero[2][0]
&& left_nonzero[2][1]
&& left_nonzero[2][2];
let right_all_nonzero = right_nonzero[0][0]
&& right_nonzero[0][1]
&& right_nonzero[0][2]
&& right_nonzero[1][0]
&& right_nonzero[1][1]
&& right_nonzero[1][2]
&& right_nonzero[2][0]
&& right_nonzero[2][1]
&& right_nonzero[2][2];
if left_all_nonzero && right_all_nonzero {
crate::trace_dispatch!("hyperlattice_matrix", "helper", "multiply3-borrowed-dense");
let cell = |row: usize, col: usize| {
Real::dot3(
[&left[row][0], &left[row][1], &left[row][2]],
[&right[0][col], &right[1][col], &right[2][col]],
)
};
return [
[cell(0, 0), cell(0, 1), cell(0, 2)],
[cell(1, 0), cell(1, 1), cell(1, 2)],
[cell(2, 0), cell(2, 1), cell(2, 2)],
];
}
crate::trace_dispatch!("hyperlattice_matrix", "helper", "multiply3-borrowed-sparse");
let cell = |row: usize, col: usize| {
let l0 = &left[row][0];
let l1 = &left[row][1];
let l2 = &left[row][2];
let r0 = &right[0][col];
let r1 = &right[1][col];
let r2 = &right[2][col];
let p0 = left_nonzero[row][0] && right_nonzero[0][col];
let p1 = left_nonzero[row][1] && right_nonzero[1][col];
let p2 = left_nonzero[row][2] && right_nonzero[2][col];
let nonzero_count = usize::from(p0) + usize::from(p1) + usize::from(p2);
match nonzero_count {
0 => Real::zero(),
1 => {
if p0 {
l0 * r0
} else if p1 {
l1 * r1
} else {
l2 * r2
}
}
2 => {
if !p0 {
Real::active_signed_product_sum2([true, true], [[l1, r1], [l2, r2]])
} else if !p1 {
Real::active_signed_product_sum2([true, true], [[l0, r0], [l2, r2]])
} else {
Real::active_signed_product_sum2([true, true], [[l0, r0], [l1, r1]])
}
}
_ => Real::dot3([l0, l1, l2], [r0, r1, r2]),
}
};
[
[cell(0, 0), cell(0, 1), cell(0, 2)],
[cell(1, 0), cell(1, 1), cell(1, 2)],
[cell(2, 0), cell(2, 1), cell(2, 2)],
]
}
#[inline]
fn multiply_arrays3_dense_ref(left: &[[Real; 3]; 3], right: &[[Real; 3]; 3]) -> [[Real; 3]; 3] {
crate::trace_dispatch!("hyperlattice_matrix", "helper", "multiply3-dense-ref");
let cell = |row: usize, col: usize| {
Real::dot3(
[&left[row][0], &left[row][1], &left[row][2]],
[&right[0][col], &right[1][col], &right[2][col]],
)
};
[
[cell(0, 0), cell(0, 1), cell(0, 2)],
[cell(1, 0), cell(1, 1), cell(1, 2)],
[cell(2, 0), cell(2, 1), cell(2, 2)],
]
}
#[inline]
fn multiply_arrays3_with_exact_dense_certificate(
left: [[Real; 3]; 3],
right: [[Real; 3]; 3],
) -> [[Real; 3]; 3] {
if true
&& matrix3_has_dense_multiply_certificate(&left)
&& matrix3_has_dense_multiply_certificate(&right)
{
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"multiply3-owned-owned-dense-certified-exact"
);
return multiply_arrays3_dense_ref(&left, &right);
}
multiply_arrays3(left, right)
}
#[inline]
fn multiply_arrays3_rhs_ref_with_exact_dense_certificate(
left: [[Real; 3]; 3],
right: &[[Real; 3]; 3],
) -> [[Real; 3]; 3] {
if true
&& matrix3_has_dense_multiply_certificate(&left)
&& matrix3_has_dense_multiply_certificate(right)
{
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"multiply3-owned-ref-dense-certified-exact"
);
return multiply_arrays3_dense_ref(&left, right);
}
multiply_arrays3_rhs_ref(left, right)
}
#[inline]
fn multiply_arrays3_ref_with_exact_dense_certificate(
left: &[[Real; 3]; 3],
right: &[[Real; 3]; 3],
) -> [[Real; 3]; 3] {
if true
&& matrix3_has_dense_multiply_certificate(left)
&& matrix3_has_dense_multiply_certificate(right)
{
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"multiply3-ref-ref-dense-certified-exact"
);
return multiply_arrays3_dense_ref(left, right);
}
multiply_arrays3_ref(left, right)
}
#[inline]
fn multiply_arrays4_borrowed(left: &[[Real; 4]; 4], right: &[[Real; 4]; 4]) -> [[Real; 4]; 4] {
let left_nonzero = [
[
!left[0][0].definitely_zero(),
!left[0][1].definitely_zero(),
!left[0][2].definitely_zero(),
!left[0][3].definitely_zero(),
],
[
!left[1][0].definitely_zero(),
!left[1][1].definitely_zero(),
!left[1][2].definitely_zero(),
!left[1][3].definitely_zero(),
],
[
!left[2][0].definitely_zero(),
!left[2][1].definitely_zero(),
!left[2][2].definitely_zero(),
!left[2][3].definitely_zero(),
],
[
!left[3][0].definitely_zero(),
!left[3][1].definitely_zero(),
!left[3][2].definitely_zero(),
!left[3][3].definitely_zero(),
],
];
let right_nonzero = [
[
!right[0][0].definitely_zero(),
!right[0][1].definitely_zero(),
!right[0][2].definitely_zero(),
!right[0][3].definitely_zero(),
],
[
!right[1][0].definitely_zero(),
!right[1][1].definitely_zero(),
!right[1][2].definitely_zero(),
!right[1][3].definitely_zero(),
],
[
!right[2][0].definitely_zero(),
!right[2][1].definitely_zero(),
!right[2][2].definitely_zero(),
!right[2][3].definitely_zero(),
],
[
!right[3][0].definitely_zero(),
!right[3][1].definitely_zero(),
!right[3][2].definitely_zero(),
!right[3][3].definitely_zero(),
],
];
let left_all_nonzero = left_nonzero[0][0]
&& left_nonzero[0][1]
&& left_nonzero[0][2]
&& left_nonzero[0][3]
&& left_nonzero[1][0]
&& left_nonzero[1][1]
&& left_nonzero[1][2]
&& left_nonzero[1][3]
&& left_nonzero[2][0]
&& left_nonzero[2][1]
&& left_nonzero[2][2]
&& left_nonzero[2][3]
&& left_nonzero[3][0]
&& left_nonzero[3][1]
&& left_nonzero[3][2]
&& left_nonzero[3][3];
let right_all_nonzero = right_nonzero[0][0]
&& right_nonzero[0][1]
&& right_nonzero[0][2]
&& right_nonzero[0][3]
&& right_nonzero[1][0]
&& right_nonzero[1][1]
&& right_nonzero[1][2]
&& right_nonzero[1][3]
&& right_nonzero[2][0]
&& right_nonzero[2][1]
&& right_nonzero[2][2]
&& right_nonzero[2][3]
&& right_nonzero[3][0]
&& right_nonzero[3][1]
&& right_nonzero[3][2]
&& right_nonzero[3][3];
if left_all_nonzero && right_all_nonzero {
crate::trace_dispatch!("hyperlattice_matrix", "helper", "multiply4-borrowed-dense");
let cell = |row: usize, col: usize| {
let l0 = &left[row][0];
let l1 = &left[row][1];
let l2 = &left[row][2];
let l3 = &left[row][3];
let r0 = &right[0][col];
let r1 = &right[1][col];
let r2 = &right[2][col];
let r3 = &right[3][col];
if true {
Real::active_signed_product_sum2(
[true, true, true, true],
[[l0, r0], [l1, r1], [l2, r2], [l3, r3]],
)
} else {
Real::dot4([l0, l1, l2, l3], [r0, r1, r2, r3])
}
};
return [
[cell(0, 0), cell(0, 1), cell(0, 2), cell(0, 3)],
[cell(1, 0), cell(1, 1), cell(1, 2), cell(1, 3)],
[cell(2, 0), cell(2, 1), cell(2, 2), cell(2, 3)],
[cell(3, 0), cell(3, 1), cell(3, 2), cell(3, 3)],
];
}
crate::trace_dispatch!("hyperlattice_matrix", "helper", "multiply4-borrowed-sparse");
let cell = |row: usize, col: usize| {
let l0 = &left[row][0];
let l1 = &left[row][1];
let l2 = &left[row][2];
let l3 = &left[row][3];
let r0 = &right[0][col];
let r1 = &right[1][col];
let r2 = &right[2][col];
let r3 = &right[3][col];
let left_row = left_nonzero[row];
let p0 = left_row[0] && right_nonzero[0][col];
let p1 = left_row[1] && right_nonzero[1][col];
let p2 = left_row[2] && right_nonzero[2][col];
let p3 = left_row[3] && right_nonzero[3][col];
let nonzero_count = usize::from(p0) + usize::from(p1) + usize::from(p2) + usize::from(p3);
match nonzero_count {
0 => Real::zero(),
1 => {
if p0 {
l0 * r0
} else if p1 {
l1 * r1
} else if p2 {
l2 * r2
} else {
l3 * r3
}
}
2 => {
if p0 {
if p1 {
Real::active_signed_product_sum2([true, true], [[l0, r0], [l1, r1]])
} else if p2 {
Real::active_signed_product_sum2([true, true], [[l0, r0], [l2, r2]])
} else {
Real::active_signed_product_sum2([true, true], [[l0, r0], [l3, r3]])
}
} else if p1 {
if p2 {
Real::active_signed_product_sum2([true, true], [[l1, r1], [l2, r2]])
} else {
Real::active_signed_product_sum2([true, true], [[l1, r1], [l3, r3]])
}
} else if p2 {
Real::active_signed_product_sum2([true, true], [[l2, r2], [l3, r3]])
} else {
unreachable!("matrix multiply sparse branch expects exactly two active terms")
}
}
3 => {
if !p0 {
Real::active_signed_product_sum2(
[true, true, true],
[[l1, r1], [l2, r2], [l3, r3]],
)
} else if !p1 {
Real::active_signed_product_sum2(
[true, true, true],
[[l0, r0], [l2, r2], [l3, r3]],
)
} else if !p2 {
Real::active_signed_product_sum2(
[true, true, true],
[[l0, r0], [l1, r1], [l3, r3]],
)
} else {
Real::active_signed_product_sum2(
[true, true, true],
[[l0, r0], [l1, r1], [l2, r2]],
)
}
}
_ if true => Real::active_signed_product_sum2(
[true, true, true, true],
[[l0, r0], [l1, r1], [l2, r2], [l3, r3]],
),
_ => Real::dot4([l0, l1, l2, l3], [r0, r1, r2, r3]),
}
};
[
[cell(0, 0), cell(0, 1), cell(0, 2), cell(0, 3)],
[cell(1, 0), cell(1, 1), cell(1, 2), cell(1, 3)],
[cell(2, 0), cell(2, 1), cell(2, 2), cell(2, 3)],
[cell(3, 0), cell(3, 1), cell(3, 2), cell(3, 3)],
]
}
#[inline]
fn multiply_arrays4_dense_ref(left: &[[Real; 4]; 4], right: &[[Real; 4]; 4]) -> [[Real; 4]; 4] {
crate::trace_dispatch!("hyperlattice_matrix", "helper", "multiply4-dense-ref");
let cell = |row: usize, col: usize| {
let l0 = &left[row][0];
let l1 = &left[row][1];
let l2 = &left[row][2];
let l3 = &left[row][3];
let r0 = &right[0][col];
let r1 = &right[1][col];
let r2 = &right[2][col];
let r3 = &right[3][col];
if true {
Real::active_signed_product_sum2(
[true, true, true, true],
[[l0, r0], [l1, r1], [l2, r2], [l3, r3]],
)
} else {
Real::dot4([l0, l1, l2, l3], [r0, r1, r2, r3])
}
};
[
[cell(0, 0), cell(0, 1), cell(0, 2), cell(0, 3)],
[cell(1, 0), cell(1, 1), cell(1, 2), cell(1, 3)],
[cell(2, 0), cell(2, 1), cell(2, 2), cell(2, 3)],
[cell(3, 0), cell(3, 1), cell(3, 2), cell(3, 3)],
]
}
#[inline]
fn multiply_arrays4_dense_known_rational_ref(
left: &[[Real; 4]; 4],
right: &[[Real; 4]; 4],
) -> [[Real; 4]; 4] {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"multiply4-dense-known-rational-ref"
);
let cell = |row: usize, col: usize| {
let l0 = &left[row][0];
let l1 = &left[row][1];
let l2 = &left[row][2];
let l3 = &left[row][3];
let r0 = &right[0][col];
let r1 = &right[1][col];
let r2 = &right[2][col];
let r3 = &right[3][col];
Real::active_signed_product_sum2_known_exact_rational(
[true, true, true, true],
[[l0, r0], [l1, r1], [l2, r2], [l3, r3]],
)
};
[
[cell(0, 0), cell(0, 1), cell(0, 2), cell(0, 3)],
[cell(1, 0), cell(1, 1), cell(1, 2), cell(1, 3)],
[cell(2, 0), cell(2, 1), cell(2, 2), cell(2, 3)],
[cell(3, 0), cell(3, 1), cell(3, 2), cell(3, 3)],
]
}
#[inline]
fn multiply_arrays3(left: [[Real; 3]; 3], right: [[Real; 3]; 3]) -> [[Real; 3]; 3] {
let left_facts = matrix3_facts(&left);
let right_facts = matrix3_facts(&right);
if left_facts.is_identity {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"multiply3-owned-owned-identity-left"
);
return right;
}
if right_facts.is_identity {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"multiply3-owned-owned-identity-right"
);
return left;
}
if left_facts.is_diagonal {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"multiply3-owned-owned-diagonal-left"
);
return multiply_matrix3_by_left_diagonal(&left, &right);
}
if right_facts.is_diagonal {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"multiply3-owned-owned-diagonal-right"
);
return multiply_matrix3_by_right_diagonal(&left, &right);
}
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"multiply3-owned-owned-specialized"
);
multiply_arrays3_borrowed(&left, &right)
}
#[inline]
fn multiply_arrays4(left: [[Real; 4]; 4], right: [[Real; 4]; 4]) -> [[Real; 4]; 4] {
let left_facts = matrix4_facts(&left);
let right_facts = matrix4_facts(&right);
if left_facts.is_identity {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"multiply4-owned-owned-identity-left"
);
return right;
}
if right_facts.is_identity {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"multiply4-owned-owned-identity-right"
);
return left;
}
if left_facts.is_diagonal {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"multiply4-owned-owned-diagonal-left"
);
return multiply_matrix4_by_left_diagonal(&left, &right);
}
if right_facts.is_diagonal {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"multiply4-owned-owned-diagonal-right"
);
return multiply_matrix4_by_right_diagonal(&left, &right);
}
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"multiply4-owned-owned-specialized"
);
multiply_arrays4_borrowed(&left, &right)
}
#[inline]
fn multiply_arrays3_rhs_ref(left: [[Real; 3]; 3], right: &[[Real; 3]; 3]) -> [[Real; 3]; 3] {
let left_facts = matrix3_facts(&left);
let right_facts = matrix3_facts(right);
if left_facts.is_identity {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"multiply3-owned-ref-identity-left"
);
return right.clone();
}
if right_facts.is_identity {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"multiply3-owned-ref-identity-right"
);
return left;
}
if left_facts.is_diagonal {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"multiply3-owned-ref-diagonal-left"
);
return multiply_matrix3_by_left_diagonal(&left, right);
}
if right_facts.is_diagonal {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"multiply3-owned-ref-diagonal-right"
);
return multiply_matrix3_by_right_diagonal(&left, right);
}
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"multiply3-owned-ref-specialized"
);
multiply_arrays3_borrowed(&left, right)
}
#[inline]
fn multiply_arrays4_rhs_ref(left: [[Real; 4]; 4], right: &[[Real; 4]; 4]) -> [[Real; 4]; 4] {
let left_facts = matrix4_facts(&left);
let right_facts = matrix4_facts(right);
if left_facts.is_identity {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"multiply4-owned-ref-identity-left"
);
return right.clone();
}
if right_facts.is_identity {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"multiply4-owned-ref-identity-right"
);
return left;
}
if left_facts.is_diagonal {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"multiply4-owned-ref-diagonal-left"
);
return multiply_matrix4_by_left_diagonal(&left, right);
}
if right_facts.is_diagonal {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"multiply4-owned-ref-diagonal-right"
);
return multiply_matrix4_by_right_diagonal(&left, right);
}
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"multiply4-owned-ref-specialized"
);
multiply_arrays4_borrowed(&left, right)
}
#[inline]
fn multiply_arrays3_ref(left: &[[Real; 3]; 3], right: &[[Real; 3]; 3]) -> [[Real; 3]; 3] {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"multiply3-ref-ref-specialized"
);
let left_facts = matrix3_facts(left);
let right_facts = matrix3_facts(right);
if left_facts.is_identity {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"multiply3-ref-ref-identity-left"
);
return right.clone();
}
if right_facts.is_identity {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"multiply3-ref-ref-identity-right"
);
return left.clone();
}
if left_facts.is_diagonal {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"multiply3-ref-ref-diagonal-left"
);
return multiply_matrix3_by_left_diagonal(left, right);
}
if right_facts.is_diagonal {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"multiply3-ref-ref-diagonal-right"
);
return multiply_matrix3_by_right_diagonal(left, right);
}
multiply_arrays3_borrowed(left, right)
}
#[inline]
fn multiply_arrays4_ref(left: &[[Real; 4]; 4], right: &[[Real; 4]; 4]) -> [[Real; 4]; 4] {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"multiply4-ref-ref-specialized"
);
let left_facts = matrix4_facts(left);
let right_facts = matrix4_facts(right);
if left_facts.is_identity {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"multiply4-ref-ref-identity-left"
);
return right.clone();
}
if right_facts.is_identity {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"multiply4-ref-ref-identity-right"
);
return left.clone();
}
if left_facts.is_diagonal {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"multiply4-ref-ref-diagonal-left"
);
return multiply_matrix4_by_left_diagonal(left, right);
}
if right_facts.is_diagonal {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"multiply4-ref-ref-diagonal-right"
);
return multiply_matrix4_by_right_diagonal(left, right);
}
multiply_arrays4_borrowed(left, right)
}
fn transform_vector_rhs_ref<const N: usize>(left: &[[Real; N]; N], right: &[Real; N]) -> [Real; N] {
if N == 4 {
let left_facts = matrix4_facts_assuming_const4(left);
if left_facts.is_identity {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"transform-vector4-identity"
);
return right.clone();
}
if left_facts.is_diagonal {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"transform-vector4-diagonal"
);
return from_fn(|row| right[row].clone().mul_cached(&left[row][row]));
}
match right[3].zero_one_or_minus_one() {
RealZeroOneMinusOneStatus::Zero => {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"transform-vector-direction"
);
if left_facts.direction_linear_is_diagonal {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"transform-vector-direction-diagonal"
);
return from_fn(|row| {
if row == 3 {
Real::zero()
} else {
right[row].clone().mul_cached(&left[row][row])
}
});
}
let vector_terms = [&right[0], &right[1], &right[2]];
return from_fn(|row| {
let matrix_terms = [&left[row][0], &left[row][1], &left[row][2]];
Real::linear_combination3(matrix_terms, vector_terms)
});
}
RealZeroOneMinusOneStatus::One => {
crate::trace_dispatch!("hyperlattice_matrix", "helper", "transform-vector-point");
if left_facts.is_affine && left_facts.linear_is_diagonal {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"transform-vector-point-affine-linear-diagonal"
);
return from_fn(|row| {
if row == 3 {
Real::one()
} else {
right[row].clone().mul_cached(&left[row][row]) + &left[row][3]
}
});
}
let translation_is_zero: [bool; N] = from_fn(|row| {
if row < 3 {
left_facts.translation_xyz_zero[row]
} else {
left[row][3].definitely_zero()
}
});
let vector_terms = [&right[0], &right[1], &right[2]];
return from_fn(|row| {
let matrix_terms = [&left[row][0], &left[row][1], &left[row][2]];
let mapped = Real::linear_combination3(matrix_terms, vector_terms);
if translation_is_zero[row] {
mapped
} else {
mapped + &left[row][3]
}
});
}
RealZeroOneMinusOneStatus::MinusOne | RealZeroOneMinusOneStatus::NeitherOrUnknown => {}
}
let translation_is_zero: [bool; N] = from_fn(|row| {
if row < 3 {
left_facts.translation_xyz_zero[row]
} else {
left[row][3].definitely_zero()
}
});
let vector_terms = [&right[0], &right[1], &right[2]];
crate::trace_dispatch!("hyperlattice_matrix", "helper", "transform-vector-full");
from_fn(|row| {
if translation_is_zero[row] {
let matrix_terms = [&left[row][0], &left[row][1], &left[row][2]];
Real::linear_combination3(matrix_terms, vector_terms)
} else {
let matrix_terms = [&left[row][0], &left[row][1], &left[row][2], &left[row][3]];
let vector_terms = [&right[0], &right[1], &right[2], &right[3]];
Real::linear_combination4(matrix_terms, vector_terms)
}
})
} else {
let left_facts = matrix3_facts_assuming_const3(left);
if left_facts.is_identity {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"transform-vector3-identity"
);
return right.clone();
}
if left_facts.is_diagonal {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"transform-vector3-diagonal"
);
return from_fn(|row| right[row].clone().mul_cached(&left[row][row]));
}
let vector_terms = [&right[0], &right[1], &right[2]];
from_fn(|row| {
let matrix_terms = [&left[row][0], &left[row][1], &left[row][2]];
Real::linear_combination3(matrix_terms, vector_terms)
})
}
}
#[inline]
fn transform_vector3_rhs_ref_cached(left: &[[Real; 3]; 3], right: &[Real; 3]) -> [Real; 3] {
let matrix_facts = matrix3_facts(left);
if matrix_facts.is_identity {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"transform-vector3-identity"
);
return right.clone();
}
if matrix_facts.is_diagonal {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"transform-vector3-diagonal"
);
return from_fn(|row| right[row].clone().mul_cached(&left[row][row]));
}
crate::trace_dispatch!("hyperlattice_matrix", "helper", "transform-vector3-dense");
transform_vector3_rhs_dense_ref(left, right)
}
#[inline]
fn transform_vector3_rhs_dense_ref(left: &[[Real; 3]; 3], right: &[Real; 3]) -> [Real; 3] {
let vector_terms = [&right[0], &right[1], &right[2]];
from_fn(|row| {
let matrix_terms = [&left[row][0], &left[row][1], &left[row][2]];
Real::linear_combination3(matrix_terms, vector_terms)
})
}
#[inline]
fn transform_vector3_rhs_dense_active_ref(left: &[[Real; 3]; 3], right: &[Real; 3]) -> [Real; 3] {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"transform-vector3-dense-active"
);
let vector_terms = [&right[0], &right[1], &right[2]];
from_fn(|row| {
let matrix_terms = [&left[row][0], &left[row][1], &left[row][2]];
Real::active_linear_combination3(matrix_terms, vector_terms)
})
}
#[inline]
fn transform_vector4_rhs_ref_cached_with_matrix_facts(
left: &[[Real; 4]; 4],
right: &[Real; 4],
translation_is_zero: &[bool; 4],
matrix_facts: Matrix4Facts,
) -> [Real; 4] {
if matrix_facts.is_identity {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"transform-vector4-identity"
);
return right.clone();
}
if matrix_facts.is_diagonal {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"transform-vector4-diagonal"
);
return from_fn(|row| right[row].clone().mul_cached(&left[row][row]));
}
let vector_terms = [&right[0], &right[1], &right[2]];
match right[3].zero_one_or_minus_one() {
RealZeroOneMinusOneStatus::Zero => {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"transform-vector4-direction"
);
return transform_vector4_rhs_direction_ref_cached(
left,
right,
matrix_facts.direction_linear_is_diagonal,
);
}
RealZeroOneMinusOneStatus::One => {
crate::trace_dispatch!("hyperlattice_matrix", "helper", "transform-vector4-point");
return transform_vector4_rhs_point_ref_cached(left, right, translation_is_zero);
}
RealZeroOneMinusOneStatus::MinusOne | RealZeroOneMinusOneStatus::NeitherOrUnknown => {}
}
crate::trace_dispatch!("hyperlattice_matrix", "helper", "transform-vector4-full");
from_fn(|row| {
if translation_is_zero[row] {
let matrix_terms = [&left[row][0], &left[row][1], &left[row][2]];
Real::linear_combination3(matrix_terms, vector_terms)
} else {
let matrix_terms = [&left[row][0], &left[row][1], &left[row][2], &left[row][3]];
let vector_terms = [&right[0], &right[1], &right[2], &right[3]];
Real::linear_combination4(matrix_terms, vector_terms)
}
})
}
#[inline]
fn transform_vector4_rhs_ref_with_facts(
left: &[[Real; 4]; 4],
right: &[Real; 4],
translation_is_zero: &[bool; 4],
all_translation_zero: bool,
all_translation_nonzero: bool,
direction_is_diagonal: bool,
matrix_facts: Option<Matrix4Facts>,
facts: Vector4GeometricFacts,
) -> [Real; 4] {
match facts.homogeneous {
Vector4HomogeneousKind::Direction => {
transform_vector4_rhs_direction_ref_cached(left, right, direction_is_diagonal)
}
Vector4HomogeneousKind::Point => {
if all_translation_zero {
transform_vector4_rhs_full_no_translation_ref_cached(left, right)
} else if all_translation_nonzero {
transform_vector4_rhs_point_all_nonzero_ref_cached(left, right)
} else {
transform_vector4_rhs_point_ref_cached(left, right, translation_is_zero)
}
}
Vector4HomogeneousKind::Unknown => {
let matrix_facts = matrix_facts.unwrap_or_else(|| matrix4_facts(left));
transform_vector4_rhs_ref_cached_with_matrix_facts(
left,
right,
translation_is_zero,
matrix_facts,
)
}
}
}
#[inline]
fn transform_vector4_rhs_direction_ref_cached(
left: &[[Real; 4]; 4],
right: &[Real; 4],
direction_is_diagonal: bool,
) -> [Real; 4] {
if direction_is_diagonal {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"transform-vector4-direction-diagonal-facts"
);
return [
right[0].clone().mul_cached(&left[0][0]),
right[1].clone().mul_cached(&left[1][1]),
right[2].clone().mul_cached(&left[2][2]),
Real::zero(),
];
}
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"transform-vector4-batch-direction"
);
let vector_terms = [&right[0], &right[1], &right[2]];
from_fn(|row| {
let matrix_terms = [&left[row][0], &left[row][1], &left[row][2]];
Real::linear_combination3(matrix_terms, vector_terms)
})
}
fn transform_vector4_direction_batch_assumed_ref(
left: &[[Real; 4]; 4],
rhs: &[Vector4],
direction_is_diagonal: bool,
) -> Vec<Vector4> {
let mut transformed = Vec::with_capacity(rhs.len());
if direction_is_diagonal {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"transform-vector4-direction-batch-diagonal-assumed"
);
for vector in rhs {
transformed.push(Vector4([
vector.0[0].clone().mul_cached(&left[0][0]),
vector.0[1].clone().mul_cached(&left[1][1]),
vector.0[2].clone().mul_cached(&left[2][2]),
Real::zero(),
]));
}
return transformed;
}
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"transform-vector4-direction-batch-linear-assumed"
);
for vector in rhs {
let vector_terms = [&vector.0[0], &vector.0[1], &vector.0[2]];
transformed.push(Vector4(from_fn(|row| {
let matrix_terms = [&left[row][0], &left[row][1], &left[row][2]];
Real::linear_combination3(matrix_terms, vector_terms)
})));
}
transformed
}
#[inline]
fn transform_vector4_rhs_point_affine_linear_diagonal_ref_cached(
left: &[[Real; 4]; 4],
right: &[Real; 4],
) -> [Real; 4] {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"transform-vector4-point-affine-linear-diagonal"
);
[
right[0].clone().mul_cached(&left[0][0]) + &left[0][3],
right[1].clone().mul_cached(&left[1][1]) + &left[1][3],
right[2].clone().mul_cached(&left[2][2]) + &left[2][3],
right[3].clone(),
]
}
#[inline]
fn transform_vector4_rhs_point_with_scaled_w_ref_cached(
left: &[[Real; 4]; 4],
right: &[Real; 4],
translation_is_zero: &[bool; 4],
all_translation_zero: bool,
all_translation_nonzero: bool,
w_scale_is_one: bool,
w_scale: &Real,
) -> [Real; 4] {
let vector_terms = [&right[0], &right[1], &right[2]];
if all_translation_zero {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"transform-vector4-point-scaled-w-full-no-translation"
);
return from_fn(|row| {
let matrix_terms = [&left[row][0], &left[row][1], &left[row][2]];
Real::linear_combination3(matrix_terms, vector_terms)
});
}
if all_translation_nonzero {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"transform-vector4-point-scaled-w-full-nonzero"
);
let translation: [Real; 4] = if w_scale_is_one {
from_fn(|row| left[row][3].clone())
} else {
from_fn(|row| left[row][3].clone().mul_cached(w_scale))
};
if true {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"transform-vector4-point-scaled-w-full-nonzero-active"
);
return from_fn(|row| {
let matrix_terms = [&left[row][0], &left[row][1], &left[row][2]];
Real::active_linear_combination3(matrix_terms, vector_terms) + &translation[row]
});
}
return from_fn(|row| {
let matrix_terms = [&left[row][0], &left[row][1], &left[row][2]];
Real::linear_combination3(matrix_terms, vector_terms) + &translation[row]
});
}
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"transform-vector4-point-scaled-w-partial"
);
from_fn(|row| {
let matrix_terms = [&left[row][0], &left[row][1], &left[row][2]];
let mapped = Real::linear_combination3(matrix_terms, vector_terms);
if translation_is_zero[row] {
mapped
} else {
if w_scale_is_one {
mapped + &left[row][3]
} else {
mapped + &left[row][3].clone().mul_cached(w_scale)
}
}
})
}
#[inline]
fn transform_vector4_rhs_point_ref_cached(
left: &[[Real; 4]; 4],
right: &[Real; 4],
translation_is_zero: &[bool; 4],
) -> [Real; 4] {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"transform-vector4-batch-point"
);
let vector_terms = [&right[0], &right[1], &right[2]];
from_fn(|row| {
let matrix_terms = [&left[row][0], &left[row][1], &left[row][2]];
let mapped = Real::linear_combination3(matrix_terms, vector_terms);
if translation_is_zero[row] {
mapped
} else {
mapped + &left[row][3]
}
})
}
#[inline]
fn transform_vector4_rhs_point_all_nonzero_ref_cached(
left: &[[Real; 4]; 4],
right: &[Real; 4],
) -> [Real; 4] {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"transform-vector4-point-all-nonzero"
);
let vector_terms = [&right[0], &right[1], &right[2]];
from_fn(|row| {
let matrix_terms = [&left[row][0], &left[row][1], &left[row][2]];
Real::linear_combination3(matrix_terms, vector_terms) + &left[row][3]
})
}
#[inline]
fn transform_vector4_rhs_full_no_translation_ref_cached(
left: &[[Real; 4]; 4],
right: &[Real; 4],
) -> [Real; 4] {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"transform-vector4-batch-full-no-translation"
);
let vector_terms = [&right[0], &right[1], &right[2]];
from_fn(|row| {
let matrix_terms = [&left[row][0], &left[row][1], &left[row][2]];
Real::linear_combination3(matrix_terms, vector_terms)
})
}
#[derive(Clone, Copy, Debug)]
pub struct TransformedMatrix3<'a> {
matrix: &'a Matrix3,
facts: Matrix3Facts,
}
impl<'a> TransformedMatrix3<'a> {
fn new(matrix: &'a Matrix3) -> Self {
let facts = matrix3_facts(&matrix.0);
Self::new_with_facts(matrix, facts)
}
fn new_with_facts(matrix: &'a Matrix3, facts: Matrix3Facts) -> Self {
Self { matrix, facts }
}
pub fn transform_vector(&self, rhs: &Vector3) -> Vector3 {
if self.facts.is_identity {
crate::trace_dispatch!(
"hyperlattice_matrix",
"method",
"transform-vector3-identity"
);
return rhs.clone();
}
if self.facts.is_diagonal {
crate::trace_dispatch!(
"hyperlattice_matrix",
"method",
"transform-vector3-diagonal"
);
return Vector3(from_fn(|row| {
rhs.0[row].clone().mul_cached(&self.matrix.0[row][row])
}));
}
crate::trace_dispatch!("hyperlattice_matrix", "helper", "transform-vector3-dense");
Vector3(transform_vector3_rhs_dense_ref(&self.matrix.0, &rhs.0))
}
pub fn vector(&self, rhs: &'a Vector3) -> TransformedVector3<'a> {
TransformedVector3 {
matrix: self.matrix,
facts: self.facts,
vector: rhs,
}
}
pub fn transform_vector_batch(&self, rhs: &[Vector3]) -> Vec<Vector3> {
if self.facts.is_identity {
crate::trace_dispatch!(
"hyperlattice_matrix",
"method",
"transform-vector3-batch-identity"
);
return rhs.to_vec();
}
if self.facts.is_diagonal {
crate::trace_dispatch!(
"hyperlattice_matrix",
"method",
"transform-vector3-batch-diagonal"
);
return rhs
.iter()
.map(|vector| {
Vector3(from_fn(|row| {
vector.0[row].clone().mul_cached(&self.matrix.0[row][row])
}))
})
.collect();
}
let mut transformed = Vec::with_capacity(rhs.len());
for vector in rhs {
transformed.push(self.transform_vector(vector));
}
transformed
}
}
#[derive(Clone, Copy, Debug)]
pub struct TransformedMatrix4<'a> {
matrix: &'a Matrix4,
facts: Matrix4Facts,
translation_is_zero: [bool; 4],
all_translation_zero: bool,
all_translation_nonzero: bool,
direction_is_diagonal: bool,
}
impl<'a> TransformedMatrix4<'a> {
#[inline]
fn transform_vector_with_facts(
&self,
rhs: &Vector4,
vector_facts: Vector4GeometricFacts,
) -> Vector4 {
if self.facts.is_identity {
crate::trace_dispatch!(
"hyperlattice_matrix",
"method",
"transform-vector4-identity"
);
return rhs.clone();
}
if self.facts.is_diagonal {
crate::trace_dispatch!(
"hyperlattice_matrix",
"method",
"transform-vector4-diagonal"
);
if matches!(vector_facts.homogeneous, Vector4HomogeneousKind::Direction) {
return Vector4([
rhs.0[0].clone().mul_cached(&self.matrix.0[0][0]),
rhs.0[1].clone().mul_cached(&self.matrix.0[1][1]),
rhs.0[2].clone().mul_cached(&self.matrix.0[2][2]),
Real::zero(),
]);
}
if matches!(vector_facts.homogeneous, Vector4HomogeneousKind::Point)
&& self.facts.is_affine
{
return Vector4(
transform_vector4_rhs_point_affine_linear_diagonal_ref_cached(
&self.matrix.0,
&rhs.0,
),
);
}
return Vector4(from_fn(|row| {
rhs.0[row].clone().mul_cached(&self.matrix.0[row][row])
}));
}
if matches!(vector_facts.homogeneous, Vector4HomogeneousKind::Point)
&& self.facts.is_affine
&& self.facts.linear_is_diagonal
{
return Vector4(
transform_vector4_rhs_point_affine_linear_diagonal_ref_cached(
&self.matrix.0,
&rhs.0,
),
);
}
Vector4(transform_vector4_rhs_ref_with_facts(
&self.matrix.0,
&rhs.0,
&self.translation_is_zero,
self.all_translation_zero,
self.all_translation_nonzero,
self.direction_is_diagonal,
Some(self.facts),
vector_facts,
))
}
fn new(matrix: &'a Matrix4) -> Self {
let facts = matrix4_facts(&matrix.0);
Self::new_with_facts(matrix, facts)
}
fn new_with_facts(matrix: &'a Matrix4, facts: Matrix4Facts) -> Self {
let translation_is_zero = [
facts.translation_xyz_zero[0],
facts.translation_xyz_zero[1],
facts.translation_xyz_zero[2],
matrix[3][3].definitely_zero(),
];
let all_translation_zero = translation_is_zero.iter().all(|value| *value);
let all_translation_nonzero = translation_is_zero.iter().all(|value| !*value);
let direction_is_diagonal = facts.direction_linear_is_diagonal;
Self {
matrix,
facts,
translation_is_zero,
all_translation_zero,
all_translation_nonzero,
direction_is_diagonal,
}
}
pub fn transform_vector(&self, rhs: &Vector4) -> Vector4 {
self.transform_vector_with_facts(rhs, rhs.geometric_facts())
}
#[inline]
pub fn transform_direction_vector(&self, rhs: &Vector4) -> Vector4 {
self.transform_vector_with_facts(
rhs,
Vector4GeometricFacts {
homogeneous: Vector4HomogeneousKind::Direction,
},
)
}
#[inline]
pub fn transform_point_vector(&self, rhs: &Vector4) -> Vector4 {
if self.facts.is_identity {
crate::trace_dispatch!(
"hyperlattice_matrix",
"method",
"transform-vector4-point-identity"
);
return rhs.clone();
}
if self.facts.is_affine && self.facts.linear_is_diagonal {
return Vector4(
transform_vector4_rhs_point_affine_linear_diagonal_ref_cached(
&self.matrix.0,
&rhs.0,
),
);
}
self.transform_vector_with_facts(
rhs,
Vector4GeometricFacts {
homogeneous: Vector4HomogeneousKind::Point,
},
)
}
pub fn vector(&self, rhs: &'a Vector4) -> TransformedVector4<'a> {
TransformedVector4 {
matrix: self.matrix,
facts: self.facts,
translation_is_zero: self.translation_is_zero,
all_translation_zero: self.all_translation_zero,
all_translation_nonzero: self.all_translation_nonzero,
direction_is_diagonal: self.direction_is_diagonal,
vector_facts: None,
vector: rhs,
}
}
pub fn transform_vector_batch(&self, rhs: &[Vector4]) -> Vec<Vector4> {
if self.facts.is_identity {
crate::trace_dispatch!(
"hyperlattice_matrix",
"method",
"transform-vector4-batch-identity"
);
return rhs.to_vec();
}
if self.facts.is_diagonal {
let mut transformed = Vec::with_capacity(rhs.len());
if let Some(first) = rhs.first() {
match first.0[3].zero_one_or_minus_one() {
RealZeroOneMinusOneStatus::Zero => {
if rhs
.iter()
.skip(1)
.all(|vector| vector.0[3].definitely_zero())
{
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"transform-vector4-batch-diagonal-direction"
);
for vector in rhs {
transformed.push(Vector4([
vector.0[0].clone().mul_cached(&self.matrix.0[0][0]),
vector.0[1].clone().mul_cached(&self.matrix.0[1][1]),
vector.0[2].clone().mul_cached(&self.matrix.0[2][2]),
Real::zero(),
]));
}
return transformed;
}
}
RealZeroOneMinusOneStatus::One
if self.facts.is_affine
&& rhs
.iter()
.skip(1)
.all(|vector| vector.0[3].definitely_one()) =>
{
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"transform-vector4-batch-diagonal-point"
);
for vector in rhs {
transformed.push(Vector4([
vector.0[0].clone().mul_cached(&self.matrix.0[0][0]),
vector.0[1].clone().mul_cached(&self.matrix.0[1][1]),
vector.0[2].clone().mul_cached(&self.matrix.0[2][2]),
Real::one(),
]));
}
return transformed;
}
RealZeroOneMinusOneStatus::MinusOne
| RealZeroOneMinusOneStatus::One
| RealZeroOneMinusOneStatus::NeitherOrUnknown => {}
}
}
for vector in rhs {
transformed.push(Vector4(from_fn(|row| {
vector.0[row].clone().mul_cached(&self.matrix.0[row][row])
})));
}
return transformed;
}
let mut transformed = Vec::with_capacity(rhs.len());
let mut has_direction = false;
let mut has_point = false;
let mut has_unknown = false;
for vector in rhs {
match vector.geometric_facts().homogeneous {
Vector4HomogeneousKind::Direction => has_direction = true,
Vector4HomogeneousKind::Point => has_point = true,
Vector4HomogeneousKind::Unknown => has_unknown = true,
}
if (has_direction && has_point)
|| (has_direction && has_unknown)
|| (has_point && has_unknown)
{
break;
}
}
if has_direction && !has_point && !has_unknown {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"transform-vector4-batch-direction"
);
if self.direction_is_diagonal {
for vector in rhs {
transformed.push(Vector4([
vector.0[0].clone().mul_cached(&self.matrix.0[0][0]),
vector.0[1].clone().mul_cached(&self.matrix.0[1][1]),
vector.0[2].clone().mul_cached(&self.matrix.0[2][2]),
Real::zero(),
]));
}
} else {
for vector in rhs {
transformed.push(Vector4(transform_vector4_rhs_direction_ref_cached(
&self.matrix.0,
&vector.0,
self.direction_is_diagonal,
)));
}
}
return transformed;
}
if has_point && !has_direction && !has_unknown {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"transform-vector4-batch-point"
);
if self.facts.is_affine && self.facts.linear_is_diagonal {
for vector in rhs {
transformed.push(Vector4(
transform_vector4_rhs_point_affine_linear_diagonal_ref_cached(
&self.matrix.0,
&vector.0,
),
));
}
} else if self.all_translation_nonzero {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"transform-vector4-batch-point-all-nonzero"
);
for vector in rhs {
transformed.push(Vector4(transform_vector4_rhs_point_all_nonzero_ref_cached(
&self.matrix.0,
&vector.0,
)));
}
} else if self.all_translation_zero {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"transform-vector4-batch-full-no-translation"
);
for vector in rhs {
transformed.push(Vector4(
transform_vector4_rhs_full_no_translation_ref_cached(
&self.matrix.0,
&vector.0,
),
));
}
} else {
for vector in rhs {
transformed.push(Vector4(transform_vector4_rhs_point_ref_cached(
&self.matrix.0,
&vector.0,
&self.translation_is_zero,
)));
}
}
return transformed;
}
if has_unknown && !has_direction && !has_point {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"transform-vector4-batch-unknown"
);
for vector in rhs {
transformed.push(Vector4(transform_vector4_rhs_ref_cached_with_matrix_facts(
&self.matrix.0,
&vector.0,
&self.translation_is_zero,
self.facts,
)));
}
return transformed;
}
let mut vector_facts = Vec::with_capacity(rhs.len());
for vector in rhs {
vector_facts.push(vector.geometric_facts());
}
if has_direction && has_point && !has_unknown {
crate::trace_dispatch!(
"hyperlattice_matrix",
"method",
"transform-vector4-batch-mixed"
);
for (vector, facts) in rhs.iter().zip(vector_facts.iter()) {
transformed.push(self.transform_vector_with_facts(vector, *facts));
}
return transformed;
}
if has_unknown && (has_direction || has_point) {
crate::trace_dispatch!(
"hyperlattice_matrix",
"method",
"transform-vector4-batch-mixed"
);
for (vector, facts) in rhs.iter().zip(vector_facts.iter()) {
transformed.push(self.transform_vector_with_facts(vector, *facts));
}
return transformed;
}
for (vector, facts) in rhs.iter().zip(vector_facts.iter()) {
transformed.push(self.transform_vector_with_facts(vector, *facts));
}
transformed
}
pub fn transform_direction_batch(&self, rhs: &[Vector4]) -> Vec<Vector4> {
crate::trace_dispatch!(
"hyperlattice_matrix",
"method",
"transform-vector4-direction-batch-assumed"
);
if self.facts.is_identity {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"transform-vector4-direction-batch-identity-assumed"
);
return rhs.to_vec();
}
transform_vector4_direction_batch_assumed_ref(
&self.matrix.0,
rhs,
self.direction_is_diagonal,
)
}
pub fn transform_point_batch(&self, rhs: &[Vector4]) -> Vec<Vector4> {
crate::trace_dispatch!(
"hyperlattice_matrix",
"method",
"transform-vector4-point-batch-assumed"
);
if self.facts.is_identity {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"transform-vector4-point-batch-identity-assumed"
);
return rhs.to_vec();
}
let mut transformed = Vec::with_capacity(rhs.len());
if self.facts.is_affine && self.facts.linear_is_diagonal {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"transform-vector4-point-batch-affine-linear-diagonal-assumed"
);
for vector in rhs {
transformed.push(Vector4([
vector.0[0].clone().mul_cached(&self.matrix.0[0][0]) + &self.matrix.0[0][3],
vector.0[1].clone().mul_cached(&self.matrix.0[1][1]) + &self.matrix.0[1][3],
vector.0[2].clone().mul_cached(&self.matrix.0[2][2]) + &self.matrix.0[2][3],
Real::one(),
]));
}
return transformed;
}
if self.all_translation_nonzero {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"transform-vector4-point-batch-all-nonzero-assumed"
);
for vector in rhs {
transformed.push(Vector4(transform_vector4_rhs_point_all_nonzero_ref_cached(
&self.matrix.0,
&vector.0,
)));
}
return transformed;
}
if self.all_translation_zero {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"transform-vector4-point-batch-no-translation-assumed"
);
for vector in rhs {
transformed.push(Vector4(
transform_vector4_rhs_full_no_translation_ref_cached(&self.matrix.0, &vector.0),
));
}
return transformed;
}
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"transform-vector4-point-batch-partial-translation-assumed"
);
for vector in rhs {
transformed.push(Vector4(transform_vector4_rhs_point_ref_cached(
&self.matrix.0,
&vector.0,
&self.translation_is_zero,
)));
}
transformed
}
}
#[derive(Clone, Copy, Debug)]
pub struct TransformedVector3<'a> {
matrix: &'a Matrix3,
facts: Matrix3Facts,
vector: &'a Vector3,
}
impl<'a> TransformedVector3<'a> {
#[inline]
pub fn materialize(self) -> Vector3 {
if self.facts.is_identity {
crate::trace_dispatch!(
"hyperlattice_matrix",
"method",
"materialize-vector3-identity"
);
return self.vector.clone();
}
if self.facts.is_diagonal {
crate::trace_dispatch!(
"hyperlattice_matrix",
"method",
"materialize-vector3-diagonal"
);
return Vector3(from_fn(|row| {
self.vector.0[row]
.clone()
.mul_cached(&self.matrix.0[row][row])
}));
}
crate::trace_dispatch!("hyperlattice_matrix", "helper", "transform-vector3-dense");
Vector3(transform_vector3_rhs_dense_ref(
&self.matrix.0,
&self.vector.0,
))
}
}
#[derive(Clone, Copy, Debug)]
pub struct TransformedVector4<'a> {
matrix: &'a Matrix4,
facts: Matrix4Facts,
translation_is_zero: [bool; 4],
all_translation_zero: bool,
all_translation_nonzero: bool,
direction_is_diagonal: bool,
vector_facts: Option<Vector4GeometricFacts>,
vector: &'a Vector4,
}
impl<'a> TransformedVector4<'a> {
#[inline]
pub fn materialize(self) -> Vector4 {
if self.facts.is_identity {
crate::trace_dispatch!(
"hyperlattice_matrix",
"method",
"materialize-vector4-identity"
);
return self.vector.clone();
}
let vector_facts = self
.vector_facts
.unwrap_or_else(|| self.vector.geometric_facts());
if self.facts.is_diagonal {
crate::trace_dispatch!(
"hyperlattice_matrix",
"method",
"materialize-vector4-diagonal"
);
if matches!(vector_facts.homogeneous, Vector4HomogeneousKind::Direction) {
return Vector4([
self.vector.0[0].clone().mul_cached(&self.matrix.0[0][0]),
self.vector.0[1].clone().mul_cached(&self.matrix.0[1][1]),
self.vector.0[2].clone().mul_cached(&self.matrix.0[2][2]),
Real::zero(),
]);
}
if matches!(vector_facts.homogeneous, Vector4HomogeneousKind::Point)
&& self.facts.is_affine
{
return Vector4(
transform_vector4_rhs_point_affine_linear_diagonal_ref_cached(
&self.matrix.0,
&self.vector.0,
),
);
}
return Vector4(from_fn(|row| {
self.vector.0[row]
.clone()
.mul_cached(&self.matrix.0[row][row])
}));
}
if matches!(vector_facts.homogeneous, Vector4HomogeneousKind::Point)
&& self.facts.is_affine
&& self.facts.linear_is_diagonal
{
return Vector4(
transform_vector4_rhs_point_affine_linear_diagonal_ref_cached(
&self.matrix.0,
&self.vector.0,
),
);
}
Vector4(transform_vector4_rhs_ref_with_facts(
&self.matrix.0,
&self.vector.0,
&self.translation_is_zero,
self.all_translation_zero,
self.all_translation_nonzero,
self.direction_is_diagonal,
Some(self.facts),
vector_facts,
))
}
}
#[inline]
fn scale_by_shared_factor(value: Real, factor: &Real) -> Real {
if true {
value.mul_cached(factor)
} else {
value * factor.clone()
}
}
fn scale_matrix3(matrix: [[Real; 3]; 3], factor: &Real) -> [[Real; 3]; 3] {
let [[m00, m01, m02], [m10, m11, m12], [m20, m21, m22]] = matrix;
[
[
scale_by_shared_factor(m00, factor),
scale_by_shared_factor(m01, factor),
scale_by_shared_factor(m02, factor),
],
[
scale_by_shared_factor(m10, factor),
scale_by_shared_factor(m11, factor),
scale_by_shared_factor(m12, factor),
],
[
scale_by_shared_factor(m20, factor),
scale_by_shared_factor(m21, factor),
scale_by_shared_factor(m22, factor),
],
]
}
fn scale_matrix4(matrix: [[Real; 4]; 4], factor: &Real) -> [[Real; 4]; 4] {
let [
[m00, m01, m02, m03],
[m10, m11, m12, m13],
[m20, m21, m22, m23],
[m30, m31, m32, m33],
] = matrix;
[
[
scale_by_shared_factor(m00, factor),
scale_by_shared_factor(m01, factor),
scale_by_shared_factor(m02, factor),
scale_by_shared_factor(m03, factor),
],
[
scale_by_shared_factor(m10, factor),
scale_by_shared_factor(m11, factor),
scale_by_shared_factor(m12, factor),
scale_by_shared_factor(m13, factor),
],
[
scale_by_shared_factor(m20, factor),
scale_by_shared_factor(m21, factor),
scale_by_shared_factor(m22, factor),
scale_by_shared_factor(m23, factor),
],
[
scale_by_shared_factor(m30, factor),
scale_by_shared_factor(m31, factor),
scale_by_shared_factor(m32, factor),
scale_by_shared_factor(m33, factor),
],
]
}
#[inline]
fn mul_sub(left_a: &Real, right_a: &Real, left_b: &Real, right_b: &Real) -> Real {
if true {
let first_zero = left_a.definitely_zero() || right_a.definitely_zero();
let second_zero = left_b.definitely_zero() || right_b.definitely_zero();
if first_zero || second_zero {
crate::trace_dispatch!("hyperlattice_matrix", "helper", "mul-sub-pruned");
if first_zero && second_zero {
return Real::zero();
}
if first_zero {
return -(left_b * right_b);
}
return left_a * right_a;
}
Real::active_signed_product_sum2([true, false], [[left_a, right_a], [left_b, right_b]])
} else {
left_a * right_a - left_b * right_b
}
}
#[inline]
fn mul_sub_dense_exact(left_a: &Real, right_a: &Real, left_b: &Real, right_b: &Real) -> Real {
crate::trace_dispatch!("hyperlattice_matrix", "helper", "mul-sub-dense-exact");
Real::active_signed_product_sum2([true, false], [[left_a, right_a], [left_b, right_b]])
}
#[inline]
fn mul_sub_dense_exact_known_rational(
left_a: &Real,
right_a: &Real,
left_b: &Real,
right_b: &Real,
) -> Real {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"mul-sub-dense-exact-known-rational"
);
Real::active_signed_product_sum2_known_exact_rational(
[true, false],
[[left_a, right_a], [left_b, right_b]],
)
}
fn mul_add(left_a: &Real, right_a: &Real, left_b: &Real, right_b: &Real) -> Real {
if true {
let first_zero = left_a.definitely_zero() || right_a.definitely_zero();
let second_zero = left_b.definitely_zero() || right_b.definitely_zero();
if first_zero || second_zero {
crate::trace_dispatch!("hyperlattice_matrix", "helper", "mul-add-pruned");
if first_zero && second_zero {
return Real::zero();
}
if first_zero {
return left_b * right_b;
}
return left_a * right_a;
}
Real::active_signed_product_sum2([true, true], [[left_a, right_a], [left_b, right_b]])
} else {
left_a * right_a + left_b * right_b
}
}
#[inline]
fn mul_add_sub(
left_a: &Real,
right_a: &Real,
left_b: &Real,
right_b: &Real,
left_c: &Real,
right_c: &Real,
) -> Real {
if true {
let first_zero = left_a.definitely_zero() || right_a.definitely_zero();
let second_zero = left_b.definitely_zero() || right_b.definitely_zero();
let third_zero = left_c.definitely_zero() || right_c.definitely_zero();
let nonzero_count = (!first_zero) as u8 + (!second_zero) as u8 + (!third_zero) as u8;
if nonzero_count <= 2 {
crate::trace_dispatch!("hyperlattice_matrix", "helper", "mul-add-sub-pruned");
return match nonzero_count {
0 => Real::zero(),
1 => {
if !first_zero {
left_a * right_a
} else if !second_zero {
left_b * right_b
} else {
-(left_c * right_c)
}
}
2 => {
if first_zero {
Real::active_signed_product_sum2(
[true, false],
[[left_b, right_b], [left_c, right_c]],
)
} else if second_zero {
Real::active_signed_product_sum2(
[true, false],
[[left_a, right_a], [left_c, right_c]],
)
} else {
Real::active_signed_product_sum2(
[true, true],
[[left_a, right_a], [left_b, right_b]],
)
}
}
_ => unreachable!(),
};
}
Real::active_signed_product_sum2(
[true, true, false],
[[left_a, right_a], [left_b, right_b], [left_c, right_c]],
)
} else {
mul_add(left_a, right_a, left_b, right_b) - left_c * right_c
}
}
#[inline]
fn mul_add_sub_dense_exact(
left_a: &Real,
right_a: &Real,
left_b: &Real,
right_b: &Real,
left_c: &Real,
right_c: &Real,
) -> Real {
crate::trace_dispatch!("hyperlattice_matrix", "helper", "mul-add-sub-dense-exact");
Real::active_signed_product_sum2(
[true, true, false],
[[left_a, right_a], [left_b, right_b], [left_c, right_c]],
)
}
#[inline]
fn mul_add_sub_dense_exact_known_rational(
left_a: &Real,
right_a: &Real,
left_b: &Real,
right_b: &Real,
left_c: &Real,
right_c: &Real,
) -> Real {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"mul-add-sub-dense-exact-known-rational"
);
Real::active_signed_product_sum2_known_exact_rational(
[true, true, false],
[[left_a, right_a], [left_b, right_b], [left_c, right_c]],
)
}
fn mul_sub_add(
left_a: &Real,
right_a: &Real,
left_b: &Real,
right_b: &Real,
left_c: &Real,
right_c: &Real,
) -> Real {
if true {
let first_zero = left_a.definitely_zero() || right_a.definitely_zero();
let second_zero = left_b.definitely_zero() || right_b.definitely_zero();
let third_zero = left_c.definitely_zero() || right_c.definitely_zero();
let nonzero_count = (!first_zero) as u8 + (!second_zero) as u8 + (!third_zero) as u8;
if nonzero_count <= 2 {
crate::trace_dispatch!("hyperlattice_matrix", "helper", "mul-sub-add-pruned");
return match nonzero_count {
0 => Real::zero(),
1 => {
if !first_zero {
left_a * right_a
} else if !second_zero {
-(left_b * right_b)
} else {
-(left_c * right_c)
}
}
2 => {
if first_zero {
Real::active_signed_product_sum2(
[false, false],
[[left_b, right_b], [left_c, right_c]],
)
} else if second_zero {
Real::active_signed_product_sum2(
[true, false],
[[left_a, right_a], [left_c, right_c]],
)
} else {
Real::active_signed_product_sum2(
[true, false],
[[left_a, right_a], [left_b, right_b]],
)
}
}
_ => unreachable!(),
};
}
Real::active_signed_product_sum2(
[true, false, false],
[[left_a, right_a], [left_b, right_b], [left_c, right_c]],
)
} else {
left_a * right_a - mul_add(left_b, right_b, left_c, right_c)
}
}
#[inline]
fn mul_sub_add_dense_exact(
left_a: &Real,
right_a: &Real,
left_b: &Real,
right_b: &Real,
left_c: &Real,
right_c: &Real,
) -> Real {
crate::trace_dispatch!("hyperlattice_matrix", "helper", "mul-sub-add-dense-exact");
Real::active_signed_product_sum2(
[true, false, false],
[[left_a, right_a], [left_b, right_b], [left_c, right_c]],
)
}
#[inline]
fn mul_sub_add_dense_exact_known_rational(
left_a: &Real,
right_a: &Real,
left_b: &Real,
right_b: &Real,
left_c: &Real,
right_c: &Real,
) -> Real {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"mul-sub-add-dense-exact-known-rational"
);
Real::active_signed_product_sum2_known_exact_rational(
[true, false, false],
[[left_a, right_a], [left_b, right_b], [left_c, right_c]],
)
}
#[inline]
fn determinant3(m: &[[Real; 3]; 3]) -> Real {
crate::trace_dispatch!("hyperlattice_matrix", "helper", "determinant3");
let c00 = mul_sub(&m[1][1], &m[2][2], &m[1][2], &m[2][1]);
let c10 = mul_sub(&m[1][2], &m[2][0], &m[1][0], &m[2][2]);
let c20 = mul_sub(&m[1][0], &m[2][1], &m[1][1], &m[2][0]);
Real::dot3([&m[0][0], &m[0][1], &m[0][2]], [&c00, &c10, &c20])
}
#[inline]
fn matrix3_adjugate_and_determinant(matrix: &[[Real; 3]; 3]) -> ([[Real; 3]; 3], Real) {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"matrix3-adjugate-and-determinant"
);
let m = &matrix;
let c00 = mul_sub(&m[1][1], &m[2][2], &m[1][2], &m[2][1]);
let c01 = mul_sub(&m[0][2], &m[2][1], &m[0][1], &m[2][2]);
let c02 = mul_sub(&m[0][1], &m[1][2], &m[0][2], &m[1][1]);
let c10 = mul_sub(&m[1][2], &m[2][0], &m[1][0], &m[2][2]);
let c11 = mul_sub(&m[0][0], &m[2][2], &m[0][2], &m[2][0]);
let c12 = mul_sub(&m[0][2], &m[1][0], &m[0][0], &m[1][2]);
let c20 = mul_sub(&m[1][0], &m[2][1], &m[1][1], &m[2][0]);
let c21 = mul_sub(&m[0][1], &m[2][0], &m[0][0], &m[2][1]);
let c22 = mul_sub(&m[0][0], &m[1][1], &m[0][1], &m[1][0]);
let det = Real::dot3([&m[0][0], &m[0][1], &m[0][2]], [&c00, &c10, &c20]);
([[c00, c01, c02], [c10, c11, c12], [c20, c21, c22]], det)
}
#[inline(never)]
fn matrix3_adjugate_and_determinant_dense_exact(matrix: &[[Real; 3]; 3]) -> ([[Real; 3]; 3], Real) {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"matrix3-adjugate-and-determinant-dense-exact"
);
let m = &matrix;
let c00 = mul_sub_dense_exact(&m[1][1], &m[2][2], &m[1][2], &m[2][1]);
let c01 = mul_sub_dense_exact(&m[0][2], &m[2][1], &m[0][1], &m[2][2]);
let c02 = mul_sub_dense_exact(&m[0][1], &m[1][2], &m[0][2], &m[1][1]);
let c10 = mul_sub_dense_exact(&m[1][2], &m[2][0], &m[1][0], &m[2][2]);
let c11 = mul_sub_dense_exact(&m[0][0], &m[2][2], &m[0][2], &m[2][0]);
let c12 = mul_sub_dense_exact(&m[0][2], &m[1][0], &m[0][0], &m[1][2]);
let c20 = mul_sub_dense_exact(&m[1][0], &m[2][1], &m[1][1], &m[2][0]);
let c21 = mul_sub_dense_exact(&m[0][1], &m[2][0], &m[0][0], &m[2][1]);
let c22 = mul_sub_dense_exact(&m[0][0], &m[1][1], &m[0][1], &m[1][0]);
let det = Real::active_linear_combination3([&m[0][0], &m[0][1], &m[0][2]], [&c00, &c10, &c20]);
([[c00, c01, c02], [c10, c11, c12], [c20, c21, c22]], det)
}
#[inline(never)]
fn matrix3_adjugate_and_determinant_dense_exact_known_rational(
matrix: &[[Real; 3]; 3],
) -> ([[Real; 3]; 3], Real) {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"matrix3-adjugate-and-determinant-dense-exact-known-rational"
);
let m = &matrix;
let c00 = mul_sub_dense_exact_known_rational(&m[1][1], &m[2][2], &m[1][2], &m[2][1]);
let c01 = mul_sub_dense_exact_known_rational(&m[0][2], &m[2][1], &m[0][1], &m[2][2]);
let c02 = mul_sub_dense_exact_known_rational(&m[0][1], &m[1][2], &m[0][2], &m[1][1]);
let c10 = mul_sub_dense_exact_known_rational(&m[1][2], &m[2][0], &m[1][0], &m[2][2]);
let c11 = mul_sub_dense_exact_known_rational(&m[0][0], &m[2][2], &m[0][2], &m[2][0]);
let c12 = mul_sub_dense_exact_known_rational(&m[0][2], &m[1][0], &m[0][0], &m[1][2]);
let c20 = mul_sub_dense_exact_known_rational(&m[1][0], &m[2][1], &m[1][1], &m[2][0]);
let c21 = mul_sub_dense_exact_known_rational(&m[0][1], &m[2][0], &m[0][0], &m[2][1]);
let c22 = mul_sub_dense_exact_known_rational(&m[0][0], &m[1][1], &m[0][1], &m[1][0]);
let det = Real::active_signed_product_sum2_known_exact_rational(
[true, true, true],
[[&m[0][0], &c00], [&m[0][1], &c10], [&m[0][2], &c20]],
);
([[c00, c01, c02], [c10, c11, c12], [c20, c21, c22]], det)
}
#[inline]
fn matrix3_scaled_adjugate(matrix: &[[Real; 3]; 3]) -> BlasResult<[[Real; 3]; 3]> {
crate::trace_dispatch!("hyperlattice_matrix", "helper", "matrix3-scaled-adjugate");
let m = &matrix;
let c00 = mul_sub(&m[1][1], &m[2][2], &m[1][2], &m[2][1]);
let c01 = mul_sub(&m[0][2], &m[2][1], &m[0][1], &m[2][2]);
let c02 = mul_sub(&m[0][1], &m[1][2], &m[0][2], &m[1][1]);
let c10 = mul_sub(&m[1][2], &m[2][0], &m[1][0], &m[2][2]);
let c11 = mul_sub(&m[0][0], &m[2][2], &m[0][2], &m[2][0]);
let c12 = mul_sub(&m[0][2], &m[1][0], &m[0][0], &m[1][2]);
let c20 = mul_sub(&m[1][0], &m[2][1], &m[1][1], &m[2][0]);
let c21 = mul_sub(&m[0][1], &m[2][0], &m[0][0], &m[2][1]);
let c22 = mul_sub(&m[0][0], &m[1][1], &m[0][1], &m[1][0]);
let det = Real::dot3([&m[0][0], &m[0][1], &m[0][2]], [&c00, &c10, &c20]);
let inv_det = det.inverse()?;
Ok([
[
scale_by_shared_factor(c00, &inv_det),
scale_by_shared_factor(c01, &inv_det),
scale_by_shared_factor(c02, &inv_det),
],
[
scale_by_shared_factor(c10, &inv_det),
scale_by_shared_factor(c11, &inv_det),
scale_by_shared_factor(c12, &inv_det),
],
[
scale_by_shared_factor(c20, &inv_det),
scale_by_shared_factor(c21, &inv_det),
scale_by_shared_factor(c22, &inv_det),
],
])
}
#[inline(never)]
fn matrix3_scaled_adjugate_dense_exact(matrix: &[[Real; 3]; 3]) -> BlasResult<[[Real; 3]; 3]> {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"matrix3-scaled-adjugate-dense-exact"
);
let m = &matrix;
let c00 = mul_sub_dense_exact(&m[1][1], &m[2][2], &m[1][2], &m[2][1]);
let c01 = mul_sub_dense_exact(&m[0][2], &m[2][1], &m[0][1], &m[2][2]);
let c02 = mul_sub_dense_exact(&m[0][1], &m[1][2], &m[0][2], &m[1][1]);
let c10 = mul_sub_dense_exact(&m[1][2], &m[2][0], &m[1][0], &m[2][2]);
let c11 = mul_sub_dense_exact(&m[0][0], &m[2][2], &m[0][2], &m[2][0]);
let c12 = mul_sub_dense_exact(&m[0][2], &m[1][0], &m[0][0], &m[1][2]);
let c20 = mul_sub_dense_exact(&m[1][0], &m[2][1], &m[1][1], &m[2][0]);
let c21 = mul_sub_dense_exact(&m[0][1], &m[2][0], &m[0][0], &m[2][1]);
let c22 = mul_sub_dense_exact(&m[0][0], &m[1][1], &m[0][1], &m[1][0]);
let det = Real::active_linear_combination3([&m[0][0], &m[0][1], &m[0][2]], [&c00, &c10, &c20]);
let inv_det = det.inverse()?;
Ok([
[
scale_by_shared_factor(c00, &inv_det),
scale_by_shared_factor(c01, &inv_det),
scale_by_shared_factor(c02, &inv_det),
],
[
scale_by_shared_factor(c10, &inv_det),
scale_by_shared_factor(c11, &inv_det),
scale_by_shared_factor(c12, &inv_det),
],
[
scale_by_shared_factor(c20, &inv_det),
scale_by_shared_factor(c21, &inv_det),
scale_by_shared_factor(c22, &inv_det),
],
])
}
#[inline]
fn invert_matrix3(matrix: [[Real; 3]; 3]) -> BlasResult<[[Real; 3]; 3]> {
crate::trace_dispatch!("hyperlattice_matrix", "helper", "invert-matrix3");
if matrix3_is_definitely_dense_for_inverse(&matrix) {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"invert-matrix3-dense-cofactor"
);
if true {
return matrix3_scaled_adjugate_dense_exact(&matrix);
}
return matrix3_scaled_adjugate(&matrix);
}
let facts = matrix3_facts(&matrix);
if facts.is_identity {
crate::trace_dispatch!("hyperlattice_matrix", "helper", "invert-matrix3-identity");
return Ok(matrix);
}
if facts.is_diagonal {
crate::trace_dispatch!("hyperlattice_matrix", "helper", "invert-matrix3-diagonal");
return invert_matrix3_by_diagonal(&matrix);
}
if facts.is_upper_triangular {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"invert-matrix3-upper-triangular"
);
return invert_matrix3_upper_triangular(&matrix);
}
if facts.is_lower_triangular {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"invert-matrix3-lower-triangular"
);
return invert_matrix3_lower_triangular(&matrix);
}
if facts.is_affine {
crate::trace_dispatch!("hyperlattice_matrix", "helper", "invert-matrix3-affine");
return invert_matrix3_affine(&matrix, facts.linear_is_diagonal);
}
matrix3_scaled_adjugate(&matrix)
}
#[inline]
fn invert_matrix3_checked(matrix: [[Real; 3]; 3]) -> CheckedBlasResult<[[Real; 3]; 3]> {
crate::trace_dispatch!("hyperlattice_matrix", "helper", "invert-matrix3-checked");
if matrix3_is_definitely_dense_for_inverse(&matrix) {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"invert-matrix3-checked-dense-cofactor"
);
let (adjugate, det) = if true {
matrix3_adjugate_and_determinant_dense_exact(&matrix)
} else {
matrix3_adjugate_and_determinant(&matrix)
};
require_known_nonzero(&det)?;
let inv_det = det.inverse()?;
return Ok(scale_matrix3(adjugate, &inv_det));
}
let facts = matrix3_facts(&matrix);
if facts.is_identity {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"invert-matrix3-checked-identity"
);
return Ok(matrix);
}
if facts.is_diagonal {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"invert-matrix3-checked-diagonal"
);
return invert_matrix3_by_diagonal_checked(&matrix);
}
if facts.is_upper_triangular {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"invert-matrix3-checked-upper-triangular"
);
return invert_matrix3_upper_triangular_checked(&matrix);
}
if facts.is_lower_triangular {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"invert-matrix3-checked-lower-triangular"
);
return invert_matrix3_lower_triangular_checked(&matrix);
}
if facts.is_affine {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"invert-matrix3-checked-affine"
);
return invert_matrix3_affine_checked(&matrix, facts.linear_is_diagonal);
}
let (adjugate, det) = matrix3_adjugate_and_determinant(&matrix);
require_known_nonzero(&det)?;
let inv_det = det.inverse()?;
Ok(scale_matrix3(adjugate, &inv_det))
}
#[inline]
fn invert_matrix3_checked_with_abort(
matrix: [[Real; 3]; 3],
signal: &AbortSignal,
) -> CheckedBlasResult<[[Real; 3]; 3]> {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"invert-matrix3-checked-with-abort"
);
if matrix3_is_definitely_dense_for_inverse(&matrix) {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"invert-matrix3-checked-with-abort-dense-cofactor"
);
let (adjugate, det) = if true {
matrix3_adjugate_and_determinant_dense_exact(&matrix)
} else {
matrix3_adjugate_and_determinant(&matrix)
};
let det = with_abort(det, signal);
require_known_nonzero(&det)?;
let inv_det = det.inverse()?;
return Ok(scale_matrix3(adjugate, &inv_det));
}
let facts = matrix3_facts(&matrix);
if facts.is_identity {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"invert-matrix3-checked-with-abort-identity"
);
return Ok(matrix);
}
if facts.is_diagonal {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"invert-matrix3-checked-with-abort-diagonal"
);
return invert_matrix3_by_diagonal_checked_with_abort(&matrix, signal);
}
if facts.is_upper_triangular {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"invert-matrix3-checked-with-abort-upper-triangular"
);
return invert_matrix3_upper_triangular_checked_with_abort(&matrix, signal);
}
if facts.is_lower_triangular {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"invert-matrix3-checked-with-abort-lower-triangular"
);
return invert_matrix3_lower_triangular_checked_with_abort(&matrix, signal);
}
if facts.is_affine {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"invert-matrix3-checked-with-abort-affine"
);
return invert_matrix3_affine_checked_with_abort(&matrix, signal, facts.linear_is_diagonal);
}
let (adjugate, det) = matrix3_adjugate_and_determinant(&matrix);
let det = with_abort(det, signal);
require_known_nonzero(&det)?;
let inv_det = det.inverse()?;
Ok(scale_matrix3(adjugate, &inv_det))
}
#[inline]
fn matrix4_factors(m: &[[Real; 4]; 4]) -> ([Real; 6], [Real; 6]) {
crate::trace_dispatch!("hyperlattice_matrix", "helper", "matrix4-factors");
let s = [
mul_sub(&m[0][0], &m[1][1], &m[1][0], &m[0][1]),
mul_sub(&m[0][0], &m[1][2], &m[1][0], &m[0][2]),
mul_sub(&m[0][0], &m[1][3], &m[1][0], &m[0][3]),
mul_sub(&m[0][1], &m[1][2], &m[1][1], &m[0][2]),
mul_sub(&m[0][1], &m[1][3], &m[1][1], &m[0][3]),
mul_sub(&m[0][2], &m[1][3], &m[1][2], &m[0][3]),
];
let c = [
mul_sub(&m[2][0], &m[3][1], &m[3][0], &m[2][1]),
mul_sub(&m[2][0], &m[3][2], &m[3][0], &m[2][2]),
mul_sub(&m[2][0], &m[3][3], &m[3][0], &m[2][3]),
mul_sub(&m[2][1], &m[3][2], &m[3][1], &m[2][2]),
mul_sub(&m[2][1], &m[3][3], &m[3][1], &m[2][3]),
mul_sub(&m[2][2], &m[3][3], &m[3][2], &m[2][3]),
];
(s, c)
}
#[inline(never)]
fn matrix4_factors_dense_exact(m: &[[Real; 4]; 4]) -> ([Real; 6], [Real; 6]) {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"matrix4-factors-dense-exact"
);
let s = [
mul_sub_dense_exact(&m[0][0], &m[1][1], &m[1][0], &m[0][1]),
mul_sub_dense_exact(&m[0][0], &m[1][2], &m[1][0], &m[0][2]),
mul_sub_dense_exact(&m[0][0], &m[1][3], &m[1][0], &m[0][3]),
mul_sub_dense_exact(&m[0][1], &m[1][2], &m[1][1], &m[0][2]),
mul_sub_dense_exact(&m[0][1], &m[1][3], &m[1][1], &m[0][3]),
mul_sub_dense_exact(&m[0][2], &m[1][3], &m[1][2], &m[0][3]),
];
let c = [
mul_sub_dense_exact(&m[2][0], &m[3][1], &m[3][0], &m[2][1]),
mul_sub_dense_exact(&m[2][0], &m[3][2], &m[3][0], &m[2][2]),
mul_sub_dense_exact(&m[2][0], &m[3][3], &m[3][0], &m[2][3]),
mul_sub_dense_exact(&m[2][1], &m[3][2], &m[3][1], &m[2][2]),
mul_sub_dense_exact(&m[2][1], &m[3][3], &m[3][1], &m[2][3]),
mul_sub_dense_exact(&m[2][2], &m[3][3], &m[3][2], &m[2][3]),
];
(s, c)
}
#[inline(never)]
fn matrix4_factors_dense_exact_known_rational(m: &[[Real; 4]; 4]) -> ([Real; 6], [Real; 6]) {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"matrix4-factors-dense-exact-known-rational"
);
let s = [
mul_sub_dense_exact_known_rational(&m[0][0], &m[1][1], &m[1][0], &m[0][1]),
mul_sub_dense_exact_known_rational(&m[0][0], &m[1][2], &m[1][0], &m[0][2]),
mul_sub_dense_exact_known_rational(&m[0][0], &m[1][3], &m[1][0], &m[0][3]),
mul_sub_dense_exact_known_rational(&m[0][1], &m[1][2], &m[1][1], &m[0][2]),
mul_sub_dense_exact_known_rational(&m[0][1], &m[1][3], &m[1][1], &m[0][3]),
mul_sub_dense_exact_known_rational(&m[0][2], &m[1][3], &m[1][2], &m[0][3]),
];
let c = [
mul_sub_dense_exact_known_rational(&m[2][0], &m[3][1], &m[3][0], &m[2][1]),
mul_sub_dense_exact_known_rational(&m[2][0], &m[3][2], &m[3][0], &m[2][2]),
mul_sub_dense_exact_known_rational(&m[2][0], &m[3][3], &m[3][0], &m[2][3]),
mul_sub_dense_exact_known_rational(&m[2][1], &m[3][2], &m[3][1], &m[2][2]),
mul_sub_dense_exact_known_rational(&m[2][1], &m[3][3], &m[3][1], &m[2][3]),
mul_sub_dense_exact_known_rational(&m[2][2], &m[3][3], &m[3][2], &m[2][3]),
];
(s, c)
}
fn determinant4_from_factors(s: &[Real; 6], c: &[Real; 6]) -> Real {
crate::trace_dispatch!("hyperlattice_matrix", "helper", "determinant4-from-factors");
Real::signed_product_sum2(
[true, false, true, true, false, true],
[
[&s[0], &c[5]],
[&s[1], &c[4]],
[&s[2], &c[3]],
[&s[3], &c[2]],
[&s[4], &c[1]],
[&s[5], &c[0]],
],
)
}
fn determinant4_from_factors_known_rational(s: &[Real; 6], c: &[Real; 6]) -> Real {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"determinant4-from-factors-known-rational"
);
Real::active_signed_product_sum2_known_exact_rational(
[true, false, true, true, false, true],
[
[&s[0], &c[5]],
[&s[1], &c[4]],
[&s[2], &c[3]],
[&s[3], &c[2]],
[&s[4], &c[1]],
[&s[5], &c[0]],
],
)
}
#[inline]
fn determinant4(m: &[[Real; 4]; 4]) -> Real {
crate::trace_dispatch!("hyperlattice_matrix", "helper", "determinant4");
let (s, c) = matrix4_factors(m);
determinant4_from_factors(&s, &c)
}
#[inline]
fn matrix4_scaled_adjugate_from_factors(
m: &[[Real; 4]; 4],
s: &[Real; 6],
c: &[Real; 6],
inv_det: &Real,
) -> [[Real; 4]; 4] {
[
[
scale_by_shared_factor(
mul_add_sub(&m[1][1], &c[5], &m[1][3], &c[3], &m[1][2], &c[4]),
inv_det,
),
scale_by_shared_factor(
mul_sub_add(&m[0][2], &c[4], &m[0][1], &c[5], &m[0][3], &c[3]),
inv_det,
),
scale_by_shared_factor(
mul_add_sub(&m[3][1], &s[5], &m[3][3], &s[3], &m[3][2], &s[4]),
inv_det,
),
scale_by_shared_factor(
mul_sub_add(&m[2][2], &s[4], &m[2][1], &s[5], &m[2][3], &s[3]),
inv_det,
),
],
[
scale_by_shared_factor(
mul_sub_add(&m[1][2], &c[2], &m[1][0], &c[5], &m[1][3], &c[1]),
inv_det,
),
scale_by_shared_factor(
mul_add_sub(&m[0][0], &c[5], &m[0][3], &c[1], &m[0][2], &c[2]),
inv_det,
),
scale_by_shared_factor(
mul_sub_add(&m[3][2], &s[2], &m[3][0], &s[5], &m[3][3], &s[1]),
inv_det,
),
scale_by_shared_factor(
mul_add_sub(&m[2][0], &s[5], &m[2][3], &s[1], &m[2][2], &s[2]),
inv_det,
),
],
[
scale_by_shared_factor(
mul_add_sub(&m[1][0], &c[4], &m[1][3], &c[0], &m[1][1], &c[2]),
inv_det,
),
scale_by_shared_factor(
mul_sub_add(&m[0][1], &c[2], &m[0][0], &c[4], &m[0][3], &c[0]),
inv_det,
),
scale_by_shared_factor(
mul_add_sub(&m[3][0], &s[4], &m[3][3], &s[0], &m[3][1], &s[2]),
inv_det,
),
scale_by_shared_factor(
mul_sub_add(&m[2][1], &s[2], &m[2][0], &s[4], &m[2][3], &s[0]),
inv_det,
),
],
[
scale_by_shared_factor(
mul_sub_add(&m[1][1], &c[1], &m[1][0], &c[3], &m[1][2], &c[0]),
inv_det,
),
scale_by_shared_factor(
mul_add_sub(&m[0][0], &c[3], &m[0][2], &c[0], &m[0][1], &c[1]),
inv_det,
),
scale_by_shared_factor(
mul_sub_add(&m[3][1], &s[1], &m[3][0], &s[3], &m[3][2], &s[0]),
inv_det,
),
scale_by_shared_factor(
mul_add_sub(&m[2][0], &s[3], &m[2][2], &s[0], &m[2][1], &s[1]),
inv_det,
),
],
]
}
#[inline(never)]
fn matrix4_scaled_adjugate_from_factors_dense_exact(
m: &[[Real; 4]; 4],
s: &[Real; 6],
c: &[Real; 6],
inv_det: &Real,
) -> [[Real; 4]; 4] {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"matrix4-scaled-adjugate-dense-exact"
);
[
[
scale_by_shared_factor(
mul_add_sub_dense_exact(&m[1][1], &c[5], &m[1][3], &c[3], &m[1][2], &c[4]),
inv_det,
),
scale_by_shared_factor(
mul_sub_add_dense_exact(&m[0][2], &c[4], &m[0][1], &c[5], &m[0][3], &c[3]),
inv_det,
),
scale_by_shared_factor(
mul_add_sub_dense_exact(&m[3][1], &s[5], &m[3][3], &s[3], &m[3][2], &s[4]),
inv_det,
),
scale_by_shared_factor(
mul_sub_add_dense_exact(&m[2][2], &s[4], &m[2][1], &s[5], &m[2][3], &s[3]),
inv_det,
),
],
[
scale_by_shared_factor(
mul_sub_add_dense_exact(&m[1][2], &c[2], &m[1][0], &c[5], &m[1][3], &c[1]),
inv_det,
),
scale_by_shared_factor(
mul_add_sub_dense_exact(&m[0][0], &c[5], &m[0][3], &c[1], &m[0][2], &c[2]),
inv_det,
),
scale_by_shared_factor(
mul_sub_add_dense_exact(&m[3][2], &s[2], &m[3][0], &s[5], &m[3][3], &s[1]),
inv_det,
),
scale_by_shared_factor(
mul_add_sub_dense_exact(&m[2][0], &s[5], &m[2][3], &s[1], &m[2][2], &s[2]),
inv_det,
),
],
[
scale_by_shared_factor(
mul_add_sub_dense_exact(&m[1][0], &c[4], &m[1][3], &c[0], &m[1][1], &c[2]),
inv_det,
),
scale_by_shared_factor(
mul_sub_add_dense_exact(&m[0][1], &c[2], &m[0][0], &c[4], &m[0][3], &c[0]),
inv_det,
),
scale_by_shared_factor(
mul_add_sub_dense_exact(&m[3][0], &s[4], &m[3][3], &s[0], &m[3][1], &s[2]),
inv_det,
),
scale_by_shared_factor(
mul_sub_add_dense_exact(&m[2][1], &s[2], &m[2][0], &s[4], &m[2][3], &s[0]),
inv_det,
),
],
[
scale_by_shared_factor(
mul_sub_add_dense_exact(&m[1][1], &c[1], &m[1][0], &c[3], &m[1][2], &c[0]),
inv_det,
),
scale_by_shared_factor(
mul_add_sub_dense_exact(&m[0][0], &c[3], &m[0][2], &c[0], &m[0][1], &c[1]),
inv_det,
),
scale_by_shared_factor(
mul_sub_add_dense_exact(&m[3][1], &s[1], &m[3][0], &s[3], &m[3][2], &s[0]),
inv_det,
),
scale_by_shared_factor(
mul_add_sub_dense_exact(&m[2][0], &s[3], &m[2][2], &s[0], &m[2][1], &s[1]),
inv_det,
),
],
]
}
#[inline]
fn invert_matrix4(matrix: [[Real; 4]; 4]) -> BlasResult<[[Real; 4]; 4]> {
if matrix4_is_definitely_dense_for_inverse(&matrix) {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"invert-matrix4-dense-cofactor"
);
let (s, c) = if true {
matrix4_factors_dense_exact(&matrix)
} else {
matrix4_factors(&matrix)
};
let det = determinant4_from_factors(&s, &c);
let inv_det = det.inverse()?;
if true {
return Ok(matrix4_scaled_adjugate_from_factors_dense_exact(
&matrix, &s, &c, &inv_det,
));
}
return Ok(matrix4_scaled_adjugate_from_factors(
&matrix, &s, &c, &inv_det,
));
}
let facts = matrix4_facts(&matrix);
if facts.is_identity {
crate::trace_dispatch!("hyperlattice_matrix", "helper", "invert-matrix4-identity");
return Ok(matrix);
}
if facts.is_diagonal {
crate::trace_dispatch!("hyperlattice_matrix", "helper", "invert-matrix4-diagonal");
return invert_matrix4_by_diagonal(&matrix);
}
if facts.is_upper_triangular {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"invert-matrix4-upper-triangular"
);
return invert_matrix4_by_upper_triangular(&matrix);
}
if facts.is_lower_triangular {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"invert-matrix4-lower-triangular"
);
return invert_matrix4_by_lower_triangular(&matrix);
}
if facts.is_affine {
crate::trace_dispatch!("hyperlattice_matrix", "helper", "invert-matrix4-affine");
return invert_matrix4_affine(
&matrix,
facts.linear_is_diagonal,
facts.is_affine_translation,
);
}
let (s, c) = matrix4_factors(&matrix);
let det = determinant4_from_factors(&s, &c);
let inv_det = det.inverse()?;
Ok(matrix4_scaled_adjugate_from_factors(
&matrix, &s, &c, &inv_det,
))
}
#[inline]
fn invert_matrix4_checked(matrix: [[Real; 4]; 4]) -> CheckedBlasResult<[[Real; 4]; 4]> {
if matrix4_is_definitely_dense_for_inverse(&matrix) {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"invert-matrix4-checked-dense-cofactor"
);
let (s, c) = if true {
matrix4_factors_dense_exact(&matrix)
} else {
matrix4_factors(&matrix)
};
let det = determinant4_from_factors(&s, &c);
require_known_nonzero(&det)?;
let inv_det = det.inverse()?;
if true {
return Ok(matrix4_scaled_adjugate_from_factors_dense_exact(
&matrix, &s, &c, &inv_det,
));
}
return Ok(matrix4_scaled_adjugate_from_factors(
&matrix, &s, &c, &inv_det,
));
}
let facts = matrix4_facts(&matrix);
if facts.is_identity {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"invert-matrix4-checked-identity"
);
return Ok(matrix);
}
if facts.is_diagonal {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"invert-matrix4-checked-diagonal"
);
return invert_matrix4_by_diagonal_checked(&matrix);
}
if facts.is_upper_triangular {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"invert-matrix4-checked-upper-triangular"
);
return invert_matrix4_by_upper_triangular_checked(&matrix);
}
if facts.is_lower_triangular {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"invert-matrix4-checked-lower-triangular"
);
return invert_matrix4_by_lower_triangular_checked(&matrix);
}
if facts.is_affine {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"invert-matrix4-checked-affine"
);
return invert_matrix4_affine_checked(
&matrix,
facts.linear_is_diagonal,
facts.is_affine_translation,
);
}
let (s, c) = matrix4_factors(&matrix);
let det = determinant4_from_factors(&s, &c);
require_known_nonzero(&det)?;
let inv_det = det.inverse()?;
Ok(matrix4_scaled_adjugate_from_factors(
&matrix, &s, &c, &inv_det,
))
}
#[inline]
fn invert_matrix4_checked_with_abort(
matrix: [[Real; 4]; 4],
signal: &AbortSignal,
) -> CheckedBlasResult<[[Real; 4]; 4]> {
if matrix4_is_definitely_dense_for_inverse(&matrix) {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"invert-matrix4-checked-with-abort-dense-cofactor"
);
let (s, c) = if true {
matrix4_factors_dense_exact(&matrix)
} else {
matrix4_factors(&matrix)
};
let det = determinant4_from_factors(&s, &c);
let det = with_abort(det, signal);
require_known_nonzero(&det)?;
let inv_det = det.inverse()?;
if true {
return Ok(matrix4_scaled_adjugate_from_factors_dense_exact(
&matrix, &s, &c, &inv_det,
));
}
return Ok(matrix4_scaled_adjugate_from_factors(
&matrix, &s, &c, &inv_det,
));
}
let facts = matrix4_facts(&matrix);
if facts.is_identity {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"invert-matrix4-checked-with-abort-identity"
);
return Ok(matrix);
}
if facts.is_diagonal {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"invert-matrix4-checked-with-abort-diagonal"
);
return invert_matrix4_by_diagonal_checked_with_abort(&matrix, signal);
}
if facts.is_upper_triangular {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"invert-matrix4-checked-with-abort-upper-triangular"
);
return invert_matrix4_by_upper_triangular_checked_with_abort(&matrix, signal);
}
if facts.is_lower_triangular {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"invert-matrix4-checked-with-abort-lower-triangular"
);
return invert_matrix4_by_lower_triangular_checked_with_abort(&matrix, signal);
}
if facts.is_affine {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"invert-matrix4-checked-with-abort-affine"
);
return invert_matrix4_affine_checked_with_abort(
&matrix,
signal,
facts.linear_is_diagonal,
facts.is_affine_translation,
);
}
let (s, c) = matrix4_factors(&matrix);
let det = determinant4_from_factors(&s, &c);
let det = with_abort(det, signal);
require_known_nonzero(&det)?;
let inv_det = det.inverse()?;
Ok(matrix4_scaled_adjugate_from_factors(
&matrix, &s, &c, &inv_det,
))
}
#[inline]
fn matrix4_adjugate_from_factors(
m: &[[Real; 4]; 4],
s: &[Real; 6],
c: &[Real; 6],
) -> [[Real; 4]; 4] {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"matrix4-unscaled-adjugate-from-factors"
);
[
[
mul_add_sub(&m[1][1], &c[5], &m[1][3], &c[3], &m[1][2], &c[4]),
mul_sub_add(&m[0][2], &c[4], &m[0][1], &c[5], &m[0][3], &c[3]),
mul_add_sub(&m[3][1], &s[5], &m[3][3], &s[3], &m[3][2], &s[4]),
mul_sub_add(&m[2][2], &s[4], &m[2][1], &s[5], &m[2][3], &s[3]),
],
[
mul_sub_add(&m[1][2], &c[2], &m[1][0], &c[5], &m[1][3], &c[1]),
mul_add_sub(&m[0][0], &c[5], &m[0][3], &c[1], &m[0][2], &c[2]),
mul_sub_add(&m[3][2], &s[2], &m[3][0], &s[5], &m[3][3], &s[1]),
mul_add_sub(&m[2][0], &s[5], &m[2][3], &s[1], &m[2][2], &s[2]),
],
[
mul_add_sub(&m[1][0], &c[4], &m[1][3], &c[0], &m[1][1], &c[2]),
mul_sub_add(&m[0][1], &c[2], &m[0][0], &c[4], &m[0][3], &c[0]),
mul_add_sub(&m[3][0], &s[4], &m[3][3], &s[0], &m[3][1], &s[2]),
mul_sub_add(&m[2][1], &s[2], &m[2][0], &s[4], &m[2][3], &s[0]),
],
[
mul_sub_add(&m[1][1], &c[1], &m[1][0], &c[3], &m[1][2], &c[0]),
mul_add_sub(&m[0][0], &c[3], &m[0][2], &c[0], &m[0][1], &c[1]),
mul_sub_add(&m[3][1], &s[1], &m[3][0], &s[3], &m[3][2], &s[0]),
mul_add_sub(&m[2][0], &s[3], &m[2][2], &s[0], &m[2][1], &s[1]),
],
]
}
#[inline(never)]
fn matrix4_adjugate_from_factors_dense_exact(
m: &[[Real; 4]; 4],
s: &[Real; 6],
c: &[Real; 6],
) -> [[Real; 4]; 4] {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"matrix4-unscaled-adjugate-dense-exact"
);
[
[
mul_add_sub_dense_exact(&m[1][1], &c[5], &m[1][3], &c[3], &m[1][2], &c[4]),
mul_sub_add_dense_exact(&m[0][2], &c[4], &m[0][1], &c[5], &m[0][3], &c[3]),
mul_add_sub_dense_exact(&m[3][1], &s[5], &m[3][3], &s[3], &m[3][2], &s[4]),
mul_sub_add_dense_exact(&m[2][2], &s[4], &m[2][1], &s[5], &m[2][3], &s[3]),
],
[
mul_sub_add_dense_exact(&m[1][2], &c[2], &m[1][0], &c[5], &m[1][3], &c[1]),
mul_add_sub_dense_exact(&m[0][0], &c[5], &m[0][3], &c[1], &m[0][2], &c[2]),
mul_sub_add_dense_exact(&m[3][2], &s[2], &m[3][0], &s[5], &m[3][3], &s[1]),
mul_add_sub_dense_exact(&m[2][0], &s[5], &m[2][3], &s[1], &m[2][2], &s[2]),
],
[
mul_add_sub_dense_exact(&m[1][0], &c[4], &m[1][3], &c[0], &m[1][1], &c[2]),
mul_sub_add_dense_exact(&m[0][1], &c[2], &m[0][0], &c[4], &m[0][3], &c[0]),
mul_add_sub_dense_exact(&m[3][0], &s[4], &m[3][3], &s[0], &m[3][1], &s[2]),
mul_sub_add_dense_exact(&m[2][1], &s[2], &m[2][0], &s[4], &m[2][3], &s[0]),
],
[
mul_sub_add_dense_exact(&m[1][1], &c[1], &m[1][0], &c[3], &m[1][2], &c[0]),
mul_add_sub_dense_exact(&m[0][0], &c[3], &m[0][2], &c[0], &m[0][1], &c[1]),
mul_sub_add_dense_exact(&m[3][1], &s[1], &m[3][0], &s[3], &m[3][2], &s[0]),
mul_add_sub_dense_exact(&m[2][0], &s[3], &m[2][2], &s[0], &m[2][1], &s[1]),
],
]
}
#[inline(never)]
fn matrix4_adjugate_from_factors_dense_exact_known_rational(
m: &[[Real; 4]; 4],
s: &[Real; 6],
c: &[Real; 6],
) -> [[Real; 4]; 4] {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"matrix4-unscaled-adjugate-dense-exact-known-rational"
);
[
[
mul_add_sub_dense_exact_known_rational(
&m[1][1], &c[5], &m[1][3], &c[3], &m[1][2], &c[4],
),
mul_sub_add_dense_exact_known_rational(
&m[0][2], &c[4], &m[0][1], &c[5], &m[0][3], &c[3],
),
mul_add_sub_dense_exact_known_rational(
&m[3][1], &s[5], &m[3][3], &s[3], &m[3][2], &s[4],
),
mul_sub_add_dense_exact_known_rational(
&m[2][2], &s[4], &m[2][1], &s[5], &m[2][3], &s[3],
),
],
[
mul_sub_add_dense_exact_known_rational(
&m[1][2], &c[2], &m[1][0], &c[5], &m[1][3], &c[1],
),
mul_add_sub_dense_exact_known_rational(
&m[0][0], &c[5], &m[0][3], &c[1], &m[0][2], &c[2],
),
mul_sub_add_dense_exact_known_rational(
&m[3][2], &s[2], &m[3][0], &s[5], &m[3][3], &s[1],
),
mul_add_sub_dense_exact_known_rational(
&m[2][0], &s[5], &m[2][3], &s[1], &m[2][2], &s[2],
),
],
[
mul_add_sub_dense_exact_known_rational(
&m[1][0], &c[4], &m[1][3], &c[0], &m[1][1], &c[2],
),
mul_sub_add_dense_exact_known_rational(
&m[0][1], &c[2], &m[0][0], &c[4], &m[0][3], &c[0],
),
mul_add_sub_dense_exact_known_rational(
&m[3][0], &s[4], &m[3][3], &s[0], &m[3][1], &s[2],
),
mul_sub_add_dense_exact_known_rational(
&m[2][1], &s[2], &m[2][0], &s[4], &m[2][3], &s[0],
),
],
[
mul_sub_add_dense_exact_known_rational(
&m[1][1], &c[1], &m[1][0], &c[3], &m[1][2], &c[0],
),
mul_add_sub_dense_exact_known_rational(
&m[0][0], &c[3], &m[0][2], &c[0], &m[0][1], &c[1],
),
mul_sub_add_dense_exact_known_rational(
&m[3][1], &s[1], &m[3][0], &s[3], &m[3][2], &s[0],
),
mul_add_sub_dense_exact_known_rational(
&m[2][0], &s[3], &m[2][2], &s[0], &m[2][1], &s[1],
),
],
]
}
macro_rules! impl_matrix {
(
$name:ident,
$vector:ident,
$n:expr,
$div_fn:ident,
$div_ref_fn:ident,
$power_fn:ident,
$mul_owned_fn:ident,
$mul_rhs_ref_fn:ident,
$mul_ref_fn:ident,
$div_checked_fn:ident,
$div_checked_abort_fn:ident
) => {
impl $name {
pub fn new(values: [[Real; $n]; $n]) -> Self {
crate::trace_dispatch!("hyperlattice_matrix", "constructor", "new");
Self(values)
}
pub fn zero() -> Self {
crate::trace_dispatch!("hyperlattice_matrix", "constructor", "zero");
Self(from_fn(|_| from_fn(|_| Real::zero())))
}
pub fn identity() -> Self {
crate::trace_dispatch!("hyperlattice_matrix", "constructor", "identity");
Self(from_fn(|row| {
from_fn(|col| {
if row == col {
Real::one()
} else {
Real::zero()
}
})
}))
}
pub fn transpose(&self) -> Self {
crate::trace_dispatch!("hyperlattice_matrix", "method", "transpose");
Self(from_fn(|row| from_fn(|col| self.0[col][row].clone())))
}
pub fn reciprocal(self) -> BlasResult<Self> {
crate::trace_dispatch!("hyperlattice_matrix", "method", "reciprocal");
self.inverse()
}
pub fn reciprocal_checked(self) -> CheckedBlasResult<Self> {
crate::trace_dispatch!("hyperlattice_matrix", "method", "reciprocal-checked");
self.inverse_checked()
}
pub fn powi(self, exponent: i32) -> BlasResult<Self> {
crate::trace_dispatch!("hyperlattice_matrix", "method", "powi");
if exponent == -1 {
crate::trace_dispatch!("hyperlattice_matrix", "powi", "negative-one-inverse");
return self.inverse();
}
let base = if exponent < 0 {
self.inverse()?.0
} else {
self.0
};
Ok(Self($power_fn(base, exponent.unsigned_abs())))
}
pub fn powi_checked(self, exponent: i32) -> CheckedBlasResult<Self> {
crate::trace_dispatch!("hyperlattice_matrix", "method", "powi-checked");
if exponent == -1 {
crate::trace_dispatch!(
"hyperlattice_matrix",
"powi",
"negative-one-inverse-checked"
);
return self.inverse_checked();
}
let base = if exponent < 0 {
self.inverse_checked()?.0
} else {
self.0
};
Ok(Self($power_fn(base, exponent.unsigned_abs())))
}
pub fn powi_checked_with_abort(
self,
exponent: i32,
signal: &AbortSignal,
) -> CheckedBlasResult<Self> {
crate::trace_dispatch!("hyperlattice_matrix", "method", "powi-checked-with-abort");
if exponent == -1 {
crate::trace_dispatch!(
"hyperlattice_matrix",
"powi",
"negative-one-inverse-checked-with-abort"
);
return self.inverse_checked_with_abort(signal);
}
let base = if exponent < 0 {
self.inverse_checked_with_abort(signal)?.0
} else {
self.0
};
Ok(Self($power_fn(base, exponent.unsigned_abs())))
}
pub fn div_scalar_checked(self, rhs: Real) -> CheckedBlasResult<Self> {
crate::trace_dispatch!("hyperlattice_matrix", "method", "div-scalar-checked");
require_known_nonzero(&rhs)?;
let inv_rhs = rhs.inverse()?;
if true {
Ok(Self(
self.0
.map(|row| row.map(|value| value.mul_cached(&inv_rhs))),
))
} else {
let mut values = self.0;
for row in &mut values {
for value in row {
*value = value.clone().mul_cached(&inv_rhs);
}
}
Ok(Self(values))
}
}
pub fn div_scalar_checked_with_abort(
self,
rhs: Real,
signal: &AbortSignal,
) -> CheckedBlasResult<Self> {
crate::trace_dispatch!(
"hyperlattice_matrix",
"method",
"div-scalar-checked-with-abort"
);
let rhs = with_abort(rhs, signal);
require_known_nonzero(&rhs)?;
let inv_rhs = rhs.inverse()?;
if true {
Ok(Self(
self.0
.map(|row| row.map(|value| value.mul_cached(&inv_rhs))),
))
} else {
let mut values = self.0;
for row in &mut values {
for value in row {
*value = value.clone().mul_cached(&inv_rhs);
}
}
Ok(Self(values))
}
}
pub fn div_matrix_checked(self, rhs: Self) -> CheckedBlasResult<Self> {
crate::trace_dispatch!("hyperlattice_matrix", "method", "div-matrix-checked");
Ok(Self($div_checked_fn(self.0, rhs.0)?))
}
pub fn div_matrix_checked_with_abort(
self,
rhs: Self,
signal: &AbortSignal,
) -> CheckedBlasResult<Self> {
crate::trace_dispatch!(
"hyperlattice_matrix",
"method",
"div-matrix-checked-with-abort"
);
Ok(Self($div_checked_abort_fn(self.0, rhs.0, signal)?))
}
}
impl Index<usize> for $name {
type Output = [Real; $n];
fn index(&self, index: usize) -> &Self::Output {
&self.0[index]
}
}
impl IndexMut<usize> for $name {
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
&mut self.0[index]
}
}
impl fmt::Display for $name {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("[")?;
for row in 0..$n {
if row > 0 {
f.write_str(", ")?;
}
f.write_str("[")?;
for col in 0..$n {
if col > 0 {
f.write_str(", ")?;
}
if f.alternate() {
write!(f, "{:#}", self.0[row][col])?;
} else {
write!(f, "{}", self.0[row][col])?;
}
}
f.write_str("]")?;
}
f.write_str("]")
}
}
impl Add for $name {
type Output = Self;
fn add(self, rhs: Self) -> Self::Output {
crate::trace_dispatch!("hyperlattice_matrix", "op", "add-owned-owned");
if true {
Self(map_matrix2(self.0, rhs.0, |lhs, rhs| lhs + rhs))
} else {
Self(from_fn(|row| {
from_fn(|col| self.0[row][col].clone() + rhs.0[row][col].clone())
}))
}
}
}
impl Add<&$name> for $name {
type Output = Self;
fn add(self, rhs: &$name) -> Self::Output {
crate::trace_dispatch!("hyperlattice_matrix", "op", "add-owned-ref");
Self(map_matrix_ref(self.0, &rhs.0, Real::add_cached))
}
}
impl Add<$name> for &$name {
type Output = $name;
fn add(self, rhs: $name) -> Self::Output {
crate::trace_dispatch!("hyperlattice_matrix", "op", "add-ref-owned");
$name(map_matrix_left_ref(&self.0, rhs.0, |lhs, rhs| lhs + rhs))
}
}
impl Add<&$name> for &$name {
type Output = $name;
fn add(self, rhs: &$name) -> Self::Output {
crate::trace_dispatch!("hyperlattice_matrix", "op", "add-ref-ref");
$name(from_fn(|row| {
from_fn(|col| &self.0[row][col] + &rhs.0[row][col])
}))
}
}
impl Add<Real> for $name {
type Output = Self;
fn add(self, rhs: Real) -> Self::Output {
crate::trace_dispatch!("hyperlattice_matrix", "op", "add-scalar-owned");
let rhs = &rhs;
if true {
Self(self.0.map(|row| row.map(|value| value.add_cached(rhs))))
} else {
let mut values = self.0;
for row in &mut values {
for value in row {
*value = value.clone().add_cached(rhs);
}
}
Self(values)
}
}
}
impl Add<&Real> for $name {
type Output = Self;
fn add(self, rhs: &Real) -> Self::Output {
crate::trace_dispatch!("hyperlattice_matrix", "op", "add-scalar-ref");
Self(self.0.map(|row| row.map(|value| value.add_cached(rhs))))
}
}
impl Sub for $name {
type Output = Self;
fn sub(self, rhs: Self) -> Self::Output {
crate::trace_dispatch!("hyperlattice_matrix", "op", "sub-owned-owned");
if true {
Self(map_matrix2(self.0, rhs.0, |lhs, rhs| lhs - rhs))
} else {
Self(from_fn(|row| {
from_fn(|col| self.0[row][col].clone() - rhs.0[row][col].clone())
}))
}
}
}
impl Sub<&$name> for $name {
type Output = Self;
fn sub(self, rhs: &$name) -> Self::Output {
crate::trace_dispatch!("hyperlattice_matrix", "op", "sub-owned-ref");
Self(map_matrix_ref(self.0, &rhs.0, Real::sub_cached))
}
}
impl Sub<$name> for &$name {
type Output = $name;
fn sub(self, rhs: $name) -> Self::Output {
crate::trace_dispatch!("hyperlattice_matrix", "op", "sub-ref-owned");
$name(map_matrix_left_ref(&self.0, rhs.0, |lhs, rhs| lhs - rhs))
}
}
impl Sub<&$name> for &$name {
type Output = $name;
fn sub(self, rhs: &$name) -> Self::Output {
crate::trace_dispatch!("hyperlattice_matrix", "op", "sub-ref-ref");
$name(from_fn(|row| {
from_fn(|col| &self.0[row][col] - &rhs.0[row][col])
}))
}
}
impl Sub<Real> for $name {
type Output = Self;
fn sub(self, rhs: Real) -> Self::Output {
crate::trace_dispatch!("hyperlattice_matrix", "op", "sub-scalar-owned");
let rhs = -rhs;
let rhs = &rhs;
if true {
Self(self.0.map(|row| row.map(|value| value.add_cached(rhs))))
} else {
let mut values = self.0;
for row in &mut values {
for value in row {
*value = value.clone().add_cached(rhs);
}
}
Self(values)
}
}
}
impl Sub<&Real> for $name {
type Output = Self;
fn sub(self, rhs: &Real) -> Self::Output {
crate::trace_dispatch!("hyperlattice_matrix", "op", "sub-scalar-ref");
let rhs = -rhs.clone();
Self(self.0.map(|row| row.map(|value| value.add_cached(&rhs))))
}
}
impl Neg for $name {
type Output = Self;
fn neg(self) -> Self::Output {
crate::trace_dispatch!("hyperlattice_matrix", "op", "neg-owned");
if true {
Self(self.0.map(|row| row.map(|value| -value)))
} else {
Self(from_fn(|row| from_fn(|col| -self.0[row][col].clone())))
}
}
}
impl Neg for &$name {
type Output = $name;
fn neg(self) -> Self::Output {
crate::trace_dispatch!("hyperlattice_matrix", "op", "neg-ref");
$name(from_fn(|row| from_fn(|col| -self.0[row][col].clone())))
}
}
impl Mul<Real> for $name {
type Output = Self;
fn mul(self, rhs: Real) -> Self::Output {
crate::trace_dispatch!("hyperlattice_matrix", "op", "mul-scalar-owned");
let rhs = &rhs;
if true {
Self(self.0.map(|row| row.map(|value| value.mul_cached(rhs))))
} else {
let mut values = self.0;
for row in &mut values {
for value in row {
*value = value.clone().mul_cached(rhs);
}
}
Self(values)
}
}
}
impl Mul<&Real> for $name {
type Output = Self;
fn mul(self, rhs: &Real) -> Self::Output {
crate::trace_dispatch!("hyperlattice_matrix", "op", "mul-scalar-ref");
Self(self.0.map(|row| row.map(|value| value.mul_cached(rhs))))
}
}
impl Div<Real> for $name {
type Output = BlasResult<Self>;
fn div(self, rhs: Real) -> Self::Output {
crate::trace_dispatch!("hyperlattice_matrix", "op", "div-scalar-owned");
reject_definite_zero(&rhs)?;
let inv_rhs = rhs.inverse()?;
if true && $n == 3 {
Ok(Self(self.0.map(|row| row.map(|value| &value * &inv_rhs))))
} else if true {
Ok(Self(
self.0
.map(|row| row.map(|value| value.mul_cached(&inv_rhs))),
))
} else {
let mut values = self.0;
for row in &mut values {
for value in row {
*value = value.clone().mul_cached(&inv_rhs);
}
}
Ok(Self(values))
}
}
}
impl Div<&Real> for $name {
type Output = BlasResult<Self>;
fn div(self, rhs: &Real) -> Self::Output {
crate::trace_dispatch!("hyperlattice_matrix", "op", "div-scalar-ref");
reject_definite_zero(rhs)?;
let inv_rhs = rhs.inverse_ref()?;
if true && $n == 3 {
Ok(Self(self.0.map(|row| row.map(|value| &value * &inv_rhs))))
} else if true {
Ok(Self(
self.0
.map(|row| row.map(|value| value.mul_cached(&inv_rhs))),
))
} else {
let mut values = self.0;
for row in &mut values {
for value in row {
*value = value.clone().mul_cached(&inv_rhs);
}
}
Ok(Self(values))
}
}
}
impl Mul for $name {
type Output = Self;
fn mul(self, rhs: Self) -> Self::Output {
crate::trace_dispatch!("hyperlattice_matrix", "op", "mul-owned-owned");
Self($mul_owned_fn(self.0, rhs.0))
}
}
impl Mul<&$name> for $name {
type Output = Self;
fn mul(self, rhs: &$name) -> Self::Output {
crate::trace_dispatch!("hyperlattice_matrix", "op", "mul-owned-ref");
Self($mul_rhs_ref_fn(self.0, &rhs.0))
}
}
impl Mul<$name> for &$name {
type Output = $name;
fn mul(self, rhs: $name) -> Self::Output {
crate::trace_dispatch!("hyperlattice_matrix", "op", "mul-ref-owned");
$name($mul_ref_fn(&self.0, &rhs.0))
}
}
impl Mul<&$name> for &$name {
type Output = $name;
fn mul(self, rhs: &$name) -> Self::Output {
crate::trace_dispatch!("hyperlattice_matrix", "op", "mul-ref-ref");
$name($mul_ref_fn(&self.0, &rhs.0))
}
}
impl Div for $name {
type Output = BlasResult<Self>;
fn div(self, rhs: Self) -> Self::Output {
crate::trace_dispatch!("hyperlattice_matrix", "op", "div-owned-owned");
Ok(Self($div_fn(self.0, rhs.0)?))
}
}
impl Div<&$name> for $name {
type Output = BlasResult<Self>;
fn div(self, rhs: &$name) -> Self::Output {
crate::trace_dispatch!("hyperlattice_matrix", "op", "div-owned-ref");
self / rhs.clone()
}
}
impl Div<$name> for &$name {
type Output = BlasResult<$name>;
fn div(self, rhs: $name) -> Self::Output {
crate::trace_dispatch!("hyperlattice_matrix", "op", "div-ref-owned");
self.clone() / rhs
}
}
impl Div<&$name> for &$name {
type Output = BlasResult<$name>;
fn div(self, rhs: &$name) -> Self::Output {
crate::trace_dispatch!("hyperlattice_matrix", "op", "div-ref-ref");
Ok($name($div_ref_fn(&self.0, &rhs.0)?))
}
}
impl Mul<$vector> for $name {
type Output = $vector;
fn mul(self, rhs: $vector) -> Self::Output {
crate::trace_dispatch!("hyperlattice_matrix", "op", "transform-vector-owned-owned");
$vector(transform_vector_rhs_ref(&self.0, &rhs.0))
}
}
impl Mul<&$vector> for $name {
type Output = $vector;
fn mul(self, rhs: &$vector) -> Self::Output {
crate::trace_dispatch!("hyperlattice_matrix", "op", "transform-vector-owned-ref");
$vector(transform_vector_rhs_ref(&self.0, &rhs.0))
}
}
impl Mul<$vector> for &$name {
type Output = $vector;
fn mul(self, rhs: $vector) -> Self::Output {
crate::trace_dispatch!("hyperlattice_matrix", "op", "transform-vector-ref-owned");
$vector(transform_vector_rhs_ref(&self.0, &rhs.0))
}
}
impl Mul<&$vector> for &$name {
type Output = $vector;
fn mul(self, rhs: &$vector) -> Self::Output {
crate::trace_dispatch!("hyperlattice_matrix", "op", "transform-vector-ref-ref");
$vector(transform_vector_rhs_ref(&self.0, &rhs.0))
}
}
impl BitXor<i32> for $name {
type Output = BlasResult<Self>;
fn bitxor(self, rhs: i32) -> Self::Output {
crate::trace_dispatch!("hyperlattice_matrix", "op", "bitxor-powi");
self.powi(rhs)
}
}
};
}
impl_matrix!(
Matrix3,
Vector3,
3,
right_divide_matrix3,
right_divide_matrix3_ref,
matrix_power3,
multiply_arrays3,
multiply_arrays3_rhs_ref,
multiply_arrays3_ref,
right_divide_matrix3_checked,
right_divide_matrix3_checked_with_abort
);
impl_matrix!(
Matrix4,
Vector4,
4,
right_divide_matrix4,
right_divide_matrix4_ref,
matrix_power4,
multiply_arrays4,
multiply_arrays4_rhs_ref,
multiply_arrays4_ref,
right_divide_matrix4_checked,
right_divide_matrix4_checked_with_abort
);
impl Matrix3 {
pub fn exact_facts(&self) -> ExactRealSetFacts {
crate::trace_dispatch!("hyperlattice_matrix", "query", "matrix3-exact-facts");
matrix3_facts(&self.0).exact
}
pub fn structural_facts(&self) -> Matrix3StructuralFacts {
crate::trace_dispatch!("hyperlattice_matrix", "query", "matrix3-structural-facts");
matrix3_facts(&self.0).public
}
pub fn prepare(&self) -> PreparedMatrix3<'_> {
PreparedMatrix3::new(self)
}
pub fn diagonal(diagonal: [Real; 3]) -> Self {
crate::trace_dispatch!("hyperlattice_matrix", "constructor", "diagonal3");
let [d0, d1, d2] = diagonal;
Self([
[d0, Real::zero(), Real::zero()],
[Real::zero(), d1, Real::zero()],
[Real::zero(), Real::zero(), d2],
])
}
pub fn diagonal_inverse(diagonal: [Real; 3]) -> BlasResult<Self> {
crate::trace_dispatch!("hyperlattice_matrix", "constructor", "diagonal3-inverse");
let [d0, d1, d2] = diagonal;
Ok(Self::diagonal([
d0.inverse()?,
d1.inverse()?,
d2.inverse()?,
]))
}
pub fn div_diagonal(self, diagonal: [Real; 3]) -> BlasResult<Self> {
crate::trace_dispatch!("hyperlattice_matrix", "method", "div-diagonal3");
let [[a00, a01, a02], [a10, a11, a12], [a20, a21, a22]] = self.0;
let [d0, d1, d2] = diagonal;
let inv0 = d0.inverse()?;
let inv1 = d1.inverse()?;
let inv2 = d2.inverse()?;
Ok(Self([
[
a00.mul_cached(&inv0),
a01.mul_cached(&inv1),
a02.mul_cached(&inv2),
],
[
a10.mul_cached(&inv0),
a11.mul_cached(&inv1),
a12.mul_cached(&inv2),
],
[
a20.mul_cached(&inv0),
a21.mul_cached(&inv1),
a22.mul_cached(&inv2),
],
]))
}
pub fn upper_triangular_inverse(self) -> BlasResult<Self> {
crate::trace_dispatch!("hyperlattice_matrix", "method", "upper-triangular3-inverse");
Ok(Self(invert_matrix3_upper_triangular(&self.0)?))
}
pub fn upper_triangular_inverse_checked(self) -> CheckedBlasResult<Self> {
crate::trace_dispatch!(
"hyperlattice_matrix",
"method",
"upper-triangular3-inverse-checked"
);
Ok(Self(invert_matrix3_upper_triangular_checked(&self.0)?))
}
pub fn upper_triangular_inverse_checked_with_abort(
self,
signal: &AbortSignal,
) -> CheckedBlasResult<Self> {
crate::trace_dispatch!(
"hyperlattice_matrix",
"method",
"upper-triangular3-inverse-checked-with-abort"
);
Ok(Self(invert_matrix3_upper_triangular_checked_with_abort(
&self.0, signal,
)?))
}
pub fn lower_triangular_inverse(self) -> BlasResult<Self> {
crate::trace_dispatch!("hyperlattice_matrix", "method", "lower-triangular3-inverse");
Ok(Self(invert_matrix3_lower_triangular(&self.0)?))
}
pub fn lower_triangular_inverse_checked(self) -> CheckedBlasResult<Self> {
crate::trace_dispatch!(
"hyperlattice_matrix",
"method",
"lower-triangular3-inverse-checked"
);
Ok(Self(invert_matrix3_lower_triangular_checked(&self.0)?))
}
pub fn lower_triangular_inverse_checked_with_abort(
self,
signal: &AbortSignal,
) -> CheckedBlasResult<Self> {
crate::trace_dispatch!(
"hyperlattice_matrix",
"method",
"lower-triangular3-inverse-checked-with-abort"
);
Ok(Self(invert_matrix3_lower_triangular_checked_with_abort(
&self.0, signal,
)?))
}
pub fn div_upper_triangular(self, divisor: Self) -> BlasResult<Self> {
crate::trace_dispatch!("hyperlattice_matrix", "method", "div-upper-triangular3");
Ok(Self(divide_matrix3_by_upper_triangular(
self.0, &divisor.0,
)?))
}
pub fn div_upper_triangular_checked(self, divisor: Self) -> CheckedBlasResult<Self> {
crate::trace_dispatch!(
"hyperlattice_matrix",
"method",
"div-upper-triangular3-checked"
);
Ok(Self(divide_matrix3_by_upper_triangular_checked(
self.0, &divisor.0,
)?))
}
pub fn div_upper_triangular_checked_with_abort(
self,
divisor: Self,
signal: &AbortSignal,
) -> CheckedBlasResult<Self> {
crate::trace_dispatch!(
"hyperlattice_matrix",
"method",
"div-upper-triangular3-checked-with-abort"
);
Ok(Self(divide_matrix3_by_upper_triangular_checked_with_abort(
self.0, &divisor.0, signal,
)?))
}
pub fn div_lower_triangular(self, divisor: Self) -> BlasResult<Self> {
crate::trace_dispatch!("hyperlattice_matrix", "method", "div-lower-triangular3");
Ok(Self(divide_matrix3_by_lower_triangular(
self.0, &divisor.0,
)?))
}
pub fn div_lower_triangular_checked(self, divisor: Self) -> CheckedBlasResult<Self> {
crate::trace_dispatch!(
"hyperlattice_matrix",
"method",
"div-lower-triangular3-checked"
);
Ok(Self(divide_matrix3_by_lower_triangular_checked(
self.0, &divisor.0,
)?))
}
pub fn div_lower_triangular_checked_with_abort(
self,
divisor: Self,
signal: &AbortSignal,
) -> CheckedBlasResult<Self> {
crate::trace_dispatch!(
"hyperlattice_matrix",
"method",
"div-lower-triangular3-checked-with-abort"
);
Ok(Self(divide_matrix3_by_lower_triangular_checked_with_abort(
self.0, &divisor.0, signal,
)?))
}
pub fn div_diagonal_vector(&self, diagonal: [Real; 3], rhs: &Vector3) -> BlasResult<Vector3> {
crate::trace_dispatch!("hyperlattice_matrix", "method", "div-diagonal3-vector");
let [d0, d1, d2] = diagonal;
let (inv0, inv1, inv2) = if d0 == d1 && d0 == d2 {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"div-diagonal3-vector-uniform-scale"
);
let inv = d0.inverse()?;
(inv.clone(), inv.clone(), inv)
} else {
(d0.inverse()?, d1.inverse()?, d2.inverse()?)
};
let rhs_div = [
rhs.0[0].clone().mul_cached(&inv0),
rhs.0[1].clone().mul_cached(&inv1),
rhs.0[2].clone().mul_cached(&inv2),
];
let mapped = if true {
transform_vector3_rhs_dense_active_ref(&self.0, &rhs_div)
} else {
transform_vector3_rhs_ref_cached(&self.0, &rhs_div)
};
Ok(Vector3(mapped))
}
pub fn prepare_right_divisor(&self) -> PreparedRightDivisor3<'_> {
PreparedRightDivisor3::new(self)
}
pub fn div_matrix_with_prepared(
self,
divisor: &mut PreparedRightDivisor3<'_>,
) -> BlasResult<Self> {
crate::trace_dispatch!("hyperlattice_matrix", "method", "div-matrix-with-prepared");
Ok(Self(divisor.divide(self.0)?))
}
pub fn div_matrix_checked_with_prepared(
self,
divisor: &mut PreparedRightDivisor3<'_>,
) -> CheckedBlasResult<Self> {
crate::trace_dispatch!(
"hyperlattice_matrix",
"method",
"div-matrix-checked-with-prepared"
);
Ok(Self(divisor.divide_checked(self.0)?))
}
pub fn div_matrix_checked_with_prepared_with_abort(
self,
divisor: &mut PreparedRightDivisor3<'_>,
signal: &AbortSignal,
) -> CheckedBlasResult<Self> {
crate::trace_dispatch!(
"hyperlattice_matrix",
"method",
"div-matrix-checked-with-prepared-with-abort"
);
Ok(Self(divisor.divide_checked_with_abort(self.0, signal)?))
}
pub fn uniform_scale(scale: Real) -> Self {
crate::trace_dispatch!("hyperlattice_matrix", "constructor", "uniform-scale3");
Self([
[scale.clone(), Real::zero(), Real::zero()],
[Real::zero(), scale.clone(), Real::zero()],
[Real::zero(), Real::zero(), scale],
])
}
pub fn uniform_scale_inverse(scale: Real) -> BlasResult<Self> {
crate::trace_dispatch!(
"hyperlattice_matrix",
"constructor",
"uniform-scale3-inverse"
);
let inv = scale.inverse()?;
Ok(Self::uniform_scale(inv))
}
pub fn transform_vec3_batch(&self, rhs: &[Vector3]) -> Vec<Vector3> {
crate::trace_dispatch!(
"hyperlattice_matrix",
"method",
"transform-vector-vec3-batch"
);
self.transform_vec3_handle().transform_vector_batch(rhs)
}
pub fn transform_vec3_handle(&self) -> TransformedMatrix3<'_> {
TransformedMatrix3::new(self)
}
pub fn transform_vec3_with<'a>(&'a self, rhs: &'a Vector3) -> TransformedVector3<'a> {
self.transform_vec3_handle().vector(rhs)
}
pub fn inverse(self) -> BlasResult<Self> {
crate::trace_dispatch!("hyperlattice_matrix", "method", "matrix3-inverse");
Ok(Self(invert_matrix3(self.0)?))
}
pub fn inverse_checked(self) -> CheckedBlasResult<Self> {
crate::trace_dispatch!("hyperlattice_matrix", "method", "matrix3-inverse-checked");
Ok(Self(invert_matrix3_checked(self.0)?))
}
pub fn inverse_checked_with_abort(self, signal: &AbortSignal) -> CheckedBlasResult<Self> {
crate::trace_dispatch!(
"hyperlattice_matrix",
"method",
"matrix3-inverse-checked-with-abort"
);
Ok(Self(invert_matrix3_checked_with_abort(self.0, signal)?))
}
pub fn determinant(&self) -> Real {
crate::trace_dispatch!("hyperlattice_matrix", "method", "matrix3-determinant");
determinant3(&self.0)
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum SignedAxis4 {
PosX,
NegX,
PosY,
NegY,
PosZ,
NegZ,
PosW,
NegW,
}
impl SignedAxis4 {
#[inline]
fn index(self) -> usize {
match self {
Self::PosX | Self::NegX => 0,
Self::PosY | Self::NegY => 1,
Self::PosZ | Self::NegZ => 2,
Self::PosW | Self::NegW => 3,
}
}
#[inline]
fn is_negative(self) -> bool {
matches!(self, Self::NegX | Self::NegY | Self::NegZ | Self::NegW)
}
}
#[inline]
fn signed_axis4_scalar(axis: SignedAxis4) -> Real {
if axis.is_negative() {
-Real::one()
} else {
Real::one()
}
}
#[inline]
fn signed_axis4_apply(value: Real, axis: SignedAxis4) -> Real {
if axis.is_negative() { -value } else { value }
}
impl Matrix4 {
pub fn from_row_major(values: [Real; 16]) -> Self {
let [
m00,
m01,
m02,
m03,
m10,
m11,
m12,
m13,
m20,
m21,
m22,
m23,
m30,
m31,
m32,
m33,
] = values;
Self::new([
[m00, m01, m02, m03],
[m10, m11, m12, m13],
[m20, m21, m22, m23],
[m30, m31, m32, m33],
])
}
pub fn from_row_slice(values: &[Real]) -> Option<Self> {
if values.len() != 16 {
return None;
}
let values = std::array::from_fn(|index| values[index].clone());
Some(Self::from_row_major(values))
}
pub fn exact_facts(&self) -> ExactRealSetFacts {
crate::trace_dispatch!("hyperlattice_matrix", "query", "matrix4-exact-facts");
matrix4_facts(&self.0).exact
}
pub fn structural_facts(&self) -> Matrix4StructuralFacts {
crate::trace_dispatch!("hyperlattice_matrix", "query", "matrix4-structural-facts");
matrix4_facts(&self.0).public
}
pub fn prepare(&self) -> PreparedMatrix4<'_> {
PreparedMatrix4::new(self)
}
pub fn affine_translation(translation: [Real; 3]) -> Self {
crate::trace_dispatch!("hyperlattice_matrix", "constructor", "affine-translation");
let [tx, ty, tz] = translation;
Self([
[Real::one(), Real::zero(), Real::zero(), tx],
[Real::zero(), Real::one(), Real::zero(), ty],
[Real::zero(), Real::zero(), Real::one(), tz],
[Real::zero(), Real::zero(), Real::zero(), Real::one()],
])
}
pub fn affine_nonuniform_scale(scale: [Real; 3]) -> Self {
let [sx, sy, sz] = scale;
Self([
[sx, Real::zero(), Real::zero(), Real::zero()],
[Real::zero(), sy, Real::zero(), Real::zero()],
[Real::zero(), Real::zero(), sz, Real::zero()],
[Real::zero(), Real::zero(), Real::zero(), Real::one()],
])
}
pub fn rotation_x(angle: Real) -> Self {
let sin = angle.clone().sin();
let cos = angle.cos();
Self::from_row_major([
Real::one(),
Real::zero(),
Real::zero(),
Real::zero(),
Real::zero(),
cos.clone(),
-sin.clone(),
Real::zero(),
Real::zero(),
sin,
cos,
Real::zero(),
Real::zero(),
Real::zero(),
Real::zero(),
Real::one(),
])
}
pub fn rotation_y(angle: Real) -> Self {
let sin = angle.clone().sin();
let cos = angle.cos();
Self::from_row_major([
cos.clone(),
Real::zero(),
sin.clone(),
Real::zero(),
Real::zero(),
Real::one(),
Real::zero(),
Real::zero(),
-sin,
Real::zero(),
cos,
Real::zero(),
Real::zero(),
Real::zero(),
Real::zero(),
Real::one(),
])
}
pub fn rotation_z(angle: Real) -> Self {
let sin = angle.clone().sin();
let cos = angle.cos();
Self::from_row_major([
cos.clone(),
-sin.clone(),
Real::zero(),
Real::zero(),
sin,
cos,
Real::zero(),
Real::zero(),
Real::zero(),
Real::zero(),
Real::one(),
Real::zero(),
Real::zero(),
Real::zero(),
Real::zero(),
Real::one(),
])
}
pub fn rotation_axis_angle(axis: &Vector3, angle: Real) -> CheckedBlasResult<Self> {
let axis = axis.normalize_checked()?;
let sin = angle.clone().sin();
let cos = angle.cos();
let one_minus_cos = Real::one() - cos.clone();
let [x, y, z] = axis.0;
let zero = Real::zero();
let one = Real::one();
Ok(Self::from_row_major([
cos.clone() + x.clone() * x.clone() * one_minus_cos.clone(),
x.clone() * y.clone() * one_minus_cos.clone() - z.clone() * sin.clone(),
x.clone() * z.clone() * one_minus_cos.clone() + y.clone() * sin.clone(),
zero.clone(),
y.clone() * x.clone() * one_minus_cos.clone() + z.clone() * sin.clone(),
cos.clone() + y.clone() * y.clone() * one_minus_cos.clone(),
y.clone() * z.clone() * one_minus_cos.clone() - x.clone() * sin.clone(),
zero.clone(),
z.clone() * x.clone() * one_minus_cos.clone() - y.clone() * sin.clone(),
z.clone() * y.clone() * one_minus_cos.clone() + x.clone() * sin,
cos + z.clone() * z * one_minus_cos,
zero.clone(),
zero.clone(),
zero.clone(),
zero,
one,
]))
}
pub fn rotation_between_vectors(from: &Vector3, to: &Vector3) -> CheckedBlasResult<Self> {
let from = from.normalize_checked()?;
let to = to.normalize_checked()?;
let dot = from.dot(&to);
match (dot.clone() - Real::one()).refine_sign_until(128) {
Some(RealSign::Zero) => return Ok(Self::identity()),
_ => {}
}
let (axis, angle) = match (dot + Real::one()).refine_sign_until(128) {
Some(RealSign::Zero) => {
let threshold = (Real::from(9_u8) / Real::from(10_u8))?;
let seed = if matches!(
(from.0[0].clone().abs() - threshold).refine_sign_until(128),
Some(RealSign::Negative)
) {
Vector3::x()
} else {
Vector3::y()
};
(from.unit_cross_checked(&seed)?, Real::pi())
}
_ => (from.unit_cross_checked(&to)?, from.angle_to(&to)?),
};
Self::rotation_axis_angle(&axis, angle)
}
pub fn affine_translation_inverse(translation: [Real; 3]) -> Self {
crate::trace_dispatch!(
"hyperlattice_matrix",
"constructor",
"affine-translation-inverse"
);
let [tx, ty, tz] = translation;
Self::affine_translation([-tx, -ty, -tz])
}
pub fn div_affine_translation(self, translation: [Real; 3]) -> Self {
crate::trace_dispatch!("hyperlattice_matrix", "method", "div-affine-translation4");
let [row0, row1, row2, row3] = self.0;
let [tx, ty, tz] = translation;
let terms = [&tx, &ty, &tz];
let t0 = affine_translation_column_subtract_update(&row0, terms);
let t1 = affine_translation_column_subtract_update(&row1, terms);
let t2 = affine_translation_column_subtract_update(&row2, terms);
let t3 = affine_translation_column_subtract_update(&row3, terms);
let [a00, a01, a02, _] = row0;
let [a10, a11, a12, _] = row1;
let [a20, a21, a22, _] = row2;
let [a30, a31, a32, _] = row3;
Self([
[a00, a01, a02, t0],
[a10, a11, a12, t1],
[a20, a21, a22, t2],
[a30, a31, a32, t3],
])
}
pub fn affine_orthonormal(linear: [[Real; 3]; 3], translation: [Real; 3]) -> Self {
crate::trace_dispatch!("hyperlattice_matrix", "constructor", "affine-orthonormal");
let [[r00, r01, r02], [r10, r11, r12], [r20, r21, r22]] = linear;
let [tx, ty, tz] = translation;
Self([
[r00, r01, r02, tx],
[r10, r11, r12, ty],
[r20, r21, r22, tz],
[Real::zero(), Real::zero(), Real::zero(), Real::one()],
])
}
pub fn affine_orthonormal_inverse(linear: [[Real; 3]; 3], translation: [Real; 3]) -> Self {
crate::trace_dispatch!(
"hyperlattice_matrix",
"constructor",
"affine-orthonormal-inverse"
);
let [[r00, r01, r02], [r10, r11, r12], [r20, r21, r22]] = linear;
let [tx, ty, tz] = translation;
let it0 = Real::zero() - affine_translation_dot3([&r00, &r10, &r20], [&tx, &ty, &tz]);
let it1 = Real::zero() - affine_translation_dot3([&r01, &r11, &r21], [&tx, &ty, &tz]);
let it2 = Real::zero() - affine_translation_dot3([&r02, &r12, &r22], [&tx, &ty, &tz]);
Self([
[r00, r10, r20, it0],
[r01, r11, r21, it1],
[r02, r12, r22, it2],
[Real::zero(), Real::zero(), Real::zero(), Real::one()],
])
}
pub fn div_affine_orthonormal(self, linear: [[Real; 3]; 3], translation: [Real; 3]) -> Self {
crate::trace_dispatch!("hyperlattice_matrix", "method", "div-affine-orthonormal4");
let [[r00, r01, r02], [r10, r11, r12], [r20, r21, r22]] = linear;
let [tx, ty, tz] = translation;
let it0 = Real::zero() - affine_translation_dot3([&r00, &r10, &r20], [&tx, &ty, &tz]);
let it1 = Real::zero() - affine_translation_dot3([&r01, &r11, &r21], [&tx, &ty, &tz]);
let it2 = Real::zero() - affine_translation_dot3([&r02, &r12, &r22], [&tx, &ty, &tz]);
let inv_translation = [&it0, &it1, &it2];
let result = self.0.map(|row| {
let [a0, a1, a2, a3] = row;
let c0 = Real::active_linear_combination3([&a0, &a1, &a2], [&r00, &r01, &r02]);
let c1 = Real::active_linear_combination3([&a0, &a1, &a2], [&r10, &r11, &r12]);
let c2 = Real::active_linear_combination3([&a0, &a1, &a2], [&r20, &r21, &r22]);
let c3 = affine_translation_dot3([&a0, &a1, &a2], inv_translation) + a3;
[c0, c1, c2, c3]
});
Self(result)
}
pub fn signed_permutation(rows: [SignedAxis4; 4]) -> Self {
crate::trace_dispatch!("hyperlattice_matrix", "constructor", "signed-permutation4");
let [r0, r1, r2, r3] = rows;
let mut matrix = [
[Real::zero(), Real::zero(), Real::zero(), Real::zero()],
[Real::zero(), Real::zero(), Real::zero(), Real::zero()],
[Real::zero(), Real::zero(), Real::zero(), Real::zero()],
[Real::zero(), Real::zero(), Real::zero(), Real::zero()],
];
matrix[0][r0.index()] = signed_axis4_scalar(r0);
matrix[1][r1.index()] = signed_axis4_scalar(r1);
matrix[2][r2.index()] = signed_axis4_scalar(r2);
matrix[3][r3.index()] = signed_axis4_scalar(r3);
Self(matrix)
}
pub fn signed_permutation_inverse(rows: [SignedAxis4; 4]) -> Self {
crate::trace_dispatch!(
"hyperlattice_matrix",
"constructor",
"signed-permutation4-inverse"
);
let [r0, r1, r2, r3] = rows;
let mut matrix = [
[Real::zero(), Real::zero(), Real::zero(), Real::zero()],
[Real::zero(), Real::zero(), Real::zero(), Real::zero()],
[Real::zero(), Real::zero(), Real::zero(), Real::zero()],
[Real::zero(), Real::zero(), Real::zero(), Real::zero()],
];
matrix[r0.index()][0] = signed_axis4_scalar(r0);
matrix[r1.index()][1] = signed_axis4_scalar(r1);
matrix[r2.index()][2] = signed_axis4_scalar(r2);
matrix[r3.index()][3] = signed_axis4_scalar(r3);
Self(matrix)
}
pub fn div_signed_permutation(self, rows: [SignedAxis4; 4]) -> Self {
crate::trace_dispatch!("hyperlattice_matrix", "method", "div-signed-permutation4");
let [r0, r1, r2, r3] = rows;
Self(self.0.map(|row| {
[
signed_axis4_apply(row[r0.index()].clone(), r0),
signed_axis4_apply(row[r1.index()].clone(), r1),
signed_axis4_apply(row[r2.index()].clone(), r2),
signed_axis4_apply(row[r3.index()].clone(), r3),
]
}))
}
pub fn transform_signed_permutation_vector(rows: [SignedAxis4; 4], rhs: &Vector4) -> Vector4 {
crate::trace_dispatch!(
"hyperlattice_matrix",
"method",
"transform-signed-permutation4-vector"
);
let [r0, r1, r2, r3] = rows;
Vector4([
signed_axis4_apply(rhs.0[r0.index()].clone(), r0),
signed_axis4_apply(rhs.0[r1.index()].clone(), r1),
signed_axis4_apply(rhs.0[r2.index()].clone(), r2),
signed_axis4_apply(rhs.0[r3.index()].clone(), r3),
])
}
pub fn transform_signed_permutation_batch(
rows: [SignedAxis4; 4],
rhs: &[Vector4],
) -> Vec<Vector4> {
crate::trace_dispatch!(
"hyperlattice_matrix",
"method",
"transform-signed-permutation4-batch"
);
let [r0, r1, r2, r3] = rows;
rhs.iter()
.map(|vector| {
Vector4([
signed_axis4_apply(vector.0[r0.index()].clone(), r0),
signed_axis4_apply(vector.0[r1.index()].clone(), r1),
signed_axis4_apply(vector.0[r2.index()].clone(), r2),
signed_axis4_apply(vector.0[r3.index()].clone(), r3),
])
})
.collect()
}
pub fn diagonal(diagonal: [Real; 4]) -> Self {
crate::trace_dispatch!("hyperlattice_matrix", "constructor", "diagonal");
let [d0, d1, d2, d3] = diagonal;
Self([
[d0, Real::zero(), Real::zero(), Real::zero()],
[Real::zero(), d1, Real::zero(), Real::zero()],
[Real::zero(), Real::zero(), d2, Real::zero()],
[Real::zero(), Real::zero(), Real::zero(), d3],
])
}
pub fn diagonal_inverse(diagonal: [Real; 4]) -> BlasResult<Self> {
crate::trace_dispatch!("hyperlattice_matrix", "constructor", "diagonal-inverse");
let [d0, d1, d2, d3] = diagonal;
Ok(Self::diagonal([
d0.inverse()?,
d1.inverse()?,
d2.inverse()?,
d3.inverse()?,
]))
}
pub fn div_diagonal(self, diagonal: [Real; 4]) -> BlasResult<Self> {
crate::trace_dispatch!("hyperlattice_matrix", "method", "div-diagonal");
let [
[a00, a01, a02, a03],
[a10, a11, a12, a13],
[a20, a21, a22, a23],
[a30, a31, a32, a33],
] = self.0;
let [d0, d1, d2, d3] = diagonal;
let inv0 = d0.inverse()?;
let inv1 = d1.inverse()?;
let inv2 = d2.inverse()?;
let inv3 = d3.inverse()?;
Ok(Self([
[
a00.mul_cached(&inv0),
a01.mul_cached(&inv1),
a02.mul_cached(&inv2),
a03.mul_cached(&inv3),
],
[
a10.mul_cached(&inv0),
a11.mul_cached(&inv1),
a12.mul_cached(&inv2),
a13.mul_cached(&inv3),
],
[
a20.mul_cached(&inv0),
a21.mul_cached(&inv1),
a22.mul_cached(&inv2),
a23.mul_cached(&inv3),
],
[
a30.mul_cached(&inv0),
a31.mul_cached(&inv1),
a32.mul_cached(&inv2),
a33.mul_cached(&inv3),
],
]))
}
pub fn upper_triangular_inverse(self) -> BlasResult<Self> {
crate::trace_dispatch!("hyperlattice_matrix", "method", "upper-triangular4-inverse");
Ok(Self(invert_matrix4_by_upper_triangular(&self.0)?))
}
pub fn upper_triangular_inverse_checked(self) -> CheckedBlasResult<Self> {
crate::trace_dispatch!(
"hyperlattice_matrix",
"method",
"upper-triangular4-inverse-checked"
);
Ok(Self(invert_matrix4_by_upper_triangular_checked(&self.0)?))
}
pub fn upper_triangular_inverse_checked_with_abort(
self,
signal: &AbortSignal,
) -> CheckedBlasResult<Self> {
crate::trace_dispatch!(
"hyperlattice_matrix",
"method",
"upper-triangular4-inverse-checked-with-abort"
);
Ok(Self(invert_matrix4_by_upper_triangular_checked_with_abort(
&self.0, signal,
)?))
}
pub fn lower_triangular_inverse(self) -> BlasResult<Self> {
crate::trace_dispatch!("hyperlattice_matrix", "method", "lower-triangular4-inverse");
Ok(Self(invert_matrix4_by_lower_triangular(&self.0)?))
}
pub fn lower_triangular_inverse_checked(self) -> CheckedBlasResult<Self> {
crate::trace_dispatch!(
"hyperlattice_matrix",
"method",
"lower-triangular4-inverse-checked"
);
Ok(Self(invert_matrix4_by_lower_triangular_checked(&self.0)?))
}
pub fn lower_triangular_inverse_checked_with_abort(
self,
signal: &AbortSignal,
) -> CheckedBlasResult<Self> {
crate::trace_dispatch!(
"hyperlattice_matrix",
"method",
"lower-triangular4-inverse-checked-with-abort"
);
Ok(Self(invert_matrix4_by_lower_triangular_checked_with_abort(
&self.0, signal,
)?))
}
pub fn div_upper_triangular(self, divisor: Self) -> BlasResult<Self> {
crate::trace_dispatch!("hyperlattice_matrix", "method", "div-upper-triangular4");
Ok(Self(divide_matrix4_by_upper_triangular(
self.0, &divisor.0,
)?))
}
pub fn div_upper_triangular_checked(self, divisor: Self) -> CheckedBlasResult<Self> {
crate::trace_dispatch!(
"hyperlattice_matrix",
"method",
"div-upper-triangular4-checked"
);
Ok(Self(divide_matrix4_by_upper_triangular_checked(
self.0, &divisor.0,
)?))
}
pub fn div_upper_triangular_checked_with_abort(
self,
divisor: Self,
signal: &AbortSignal,
) -> CheckedBlasResult<Self> {
crate::trace_dispatch!(
"hyperlattice_matrix",
"method",
"div-upper-triangular4-checked-with-abort"
);
Ok(Self(divide_matrix4_by_upper_triangular_checked_with_abort(
self.0, &divisor.0, signal,
)?))
}
pub fn div_lower_triangular(self, divisor: Self) -> BlasResult<Self> {
crate::trace_dispatch!("hyperlattice_matrix", "method", "div-lower-triangular4");
Ok(Self(divide_matrix4_by_lower_triangular(
self.0, &divisor.0,
)?))
}
pub fn div_lower_triangular_checked(self, divisor: Self) -> CheckedBlasResult<Self> {
crate::trace_dispatch!(
"hyperlattice_matrix",
"method",
"div-lower-triangular4-checked"
);
Ok(Self(divide_matrix4_by_lower_triangular_checked(
self.0, &divisor.0,
)?))
}
pub fn div_lower_triangular_checked_with_abort(
self,
divisor: Self,
signal: &AbortSignal,
) -> CheckedBlasResult<Self> {
crate::trace_dispatch!(
"hyperlattice_matrix",
"method",
"div-lower-triangular4-checked-with-abort"
);
Ok(Self(divide_matrix4_by_lower_triangular_checked_with_abort(
self.0, &divisor.0, signal,
)?))
}
pub fn div_diagonal_vector(&self, diagonal: [Real; 4], rhs: &Vector4) -> BlasResult<Vector4> {
crate::trace_dispatch!("hyperlattice_matrix", "method", "div-diagonal4-vector");
let [d0, d1, d2, d3] = diagonal;
let vector_facts = rhs.geometric_facts();
if matches!(vector_facts.homogeneous, Vector4HomogeneousKind::Direction) {
let (inv0, inv1, inv2) = if d0 == d1 && d0 == d2 {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"div-diagonal4-vector-direction-uniform-scale"
);
let inv = d0.inverse()?;
(inv.clone(), inv.clone(), inv)
} else {
(d0.inverse()?, d1.inverse()?, d2.inverse()?)
};
let rhs_div = [
rhs.0[0].clone().mul_cached(&inv0),
rhs.0[1].clone().mul_cached(&inv1),
rhs.0[2].clone().mul_cached(&inv2),
Real::zero(),
];
return Ok(Vector4(transform_vector4_rhs_direction_ref_cached(
&self.0,
&rhs_div,
matrix4_direction_linear_is_diagonal(&self.0),
)));
}
let linear_uniform_scale = d0 == d1 && d0 == d2;
let (inv0, inv1, inv2) = if linear_uniform_scale {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"div-diagonal4-vector-linear-uniform-scale"
);
let inv = d0.inverse()?;
(inv.clone(), inv.clone(), inv)
} else {
(d0.inverse()?, d1.inverse()?, d2.inverse()?)
};
let inv3_is_one = d3.definitely_one();
let inv3 = if inv3_is_one {
Real::one()
} else {
d3.inverse()?
};
let rhs_div_3_scale = if inv3_is_one {
rhs.0[3].clone()
} else if rhs.0[3].definitely_one() {
inv3.clone()
} else {
rhs.0[3].clone().mul_cached(&inv3)
};
let rhs_div_x = rhs.0[0].clone().mul_cached(&inv0);
let rhs_div_y = rhs.0[1].clone().mul_cached(&inv1);
let rhs_div_z = rhs.0[2].clone().mul_cached(&inv2);
match vector_facts.homogeneous {
Vector4HomogeneousKind::Point => {
let translation_is_zero = [
self.0[0][3].definitely_zero(),
self.0[1][3].definitely_zero(),
self.0[2][3].definitely_zero(),
self.0[3][3].definitely_zero(),
];
let all_translation_zero = translation_is_zero.iter().all(|value| *value);
let all_translation_nonzero = translation_is_zero.iter().all(|value| !*value);
let rhs_div = [rhs_div_x, rhs_div_y, rhs_div_z, rhs_div_3_scale];
return Ok(Vector4(
transform_vector4_rhs_point_with_scaled_w_ref_cached(
&self.0,
&rhs_div,
&translation_is_zero,
all_translation_zero,
all_translation_nonzero,
inv3_is_one,
&inv3,
),
));
}
Vector4HomogeneousKind::Direction => {
let rhs_div = [rhs_div_x, rhs_div_y, rhs_div_z, Real::zero()];
let direction_is_diagonal = matrix4_direction_linear_is_diagonal(&self.0);
return Ok(Vector4(transform_vector4_rhs_direction_ref_cached(
&self.0,
&rhs_div,
direction_is_diagonal,
)));
}
Vector4HomogeneousKind::Unknown => {
let matrix_facts = matrix4_facts(&self.0);
let translation_is_zero = [
matrix_facts.translation_xyz_zero[0],
matrix_facts.translation_xyz_zero[1],
matrix_facts.translation_xyz_zero[2],
self.0[3][3].definitely_zero(),
];
let all_translation_zero = translation_is_zero.iter().all(|value| *value);
let all_translation_nonzero = translation_is_zero.iter().all(|value| !*value);
let rhs_div = [rhs_div_x, rhs_div_y, rhs_div_z, rhs_div_3_scale];
return Ok(Vector4(transform_vector4_rhs_ref_with_facts(
&self.0,
&rhs_div,
&translation_is_zero,
all_translation_zero,
all_translation_nonzero,
matrix_facts.direction_linear_is_diagonal,
Some(matrix_facts),
vector_facts,
)));
}
};
}
#[inline]
pub fn div_diagonal_direction_vector(
&self,
diagonal: [Real; 4],
rhs: &Vector4,
) -> BlasResult<Vector4> {
crate::trace_dispatch!(
"hyperlattice_matrix",
"method",
"div-diagonal4-vector-direction-only"
);
let [d0, d1, d2, _d3] = diagonal;
let inv0 = d0.inverse()?;
let inv1 = d1.inverse()?;
let inv2 = d2.inverse()?;
let rhs_div = [
rhs.0[0].clone().mul_cached(&inv0),
rhs.0[1].clone().mul_cached(&inv1),
rhs.0[2].clone().mul_cached(&inv2),
Real::zero(),
];
Ok(Vector4(transform_vector4_rhs_direction_ref_cached(
&self.0,
&rhs_div,
matrix4_direction_linear_is_diagonal(&self.0),
)))
}
pub fn prepare_right_divisor(&self) -> PreparedRightDivisor4<'_> {
PreparedRightDivisor4::new(self)
}
pub fn div_matrix_with_prepared(
self,
divisor: &mut PreparedRightDivisor4<'_>,
) -> BlasResult<Self> {
crate::trace_dispatch!("hyperlattice_matrix", "method", "div-matrix-with-prepared");
Ok(Self(divisor.divide(self.0)?))
}
pub fn div_exact_rational_matrix_with_prepared(
self,
divisor: &mut PreparedRightDivisor4<'_>,
) -> BlasResult<Self> {
crate::trace_dispatch!(
"hyperlattice_matrix",
"method",
"div-exact-rational-matrix-with-prepared"
);
Ok(Self(divisor.divide_exact_rational_left(self.0)?))
}
pub fn div_matrix_checked_with_prepared(
self,
divisor: &mut PreparedRightDivisor4<'_>,
) -> CheckedBlasResult<Self> {
crate::trace_dispatch!(
"hyperlattice_matrix",
"method",
"div-matrix-checked-with-prepared"
);
Ok(Self(divisor.divide_checked(self.0)?))
}
pub fn div_matrix_checked_with_prepared_with_abort(
self,
divisor: &mut PreparedRightDivisor4<'_>,
signal: &AbortSignal,
) -> CheckedBlasResult<Self> {
crate::trace_dispatch!(
"hyperlattice_matrix",
"method",
"div-matrix-checked-with-prepared-with-abort"
);
Ok(Self(divisor.divide_checked_with_abort(self.0, signal)?))
}
pub fn uniform_scale(scale: Real) -> Self {
crate::trace_dispatch!("hyperlattice_matrix", "constructor", "uniform-scale");
Self([
[scale.clone(), Real::zero(), Real::zero(), Real::zero()],
[Real::zero(), scale.clone(), Real::zero(), Real::zero()],
[Real::zero(), Real::zero(), scale.clone(), Real::zero()],
[Real::zero(), Real::zero(), Real::zero(), scale],
])
}
pub fn uniform_scale_inverse(scale: Real) -> BlasResult<Self> {
crate::trace_dispatch!(
"hyperlattice_matrix",
"constructor",
"uniform-scale-inverse"
);
let inv = scale.inverse()?;
Ok(Self::uniform_scale(inv))
}
pub fn transform_vec4_handle(&self) -> TransformedMatrix4<'_> {
TransformedMatrix4::new(self)
}
pub fn transform_vec4_with<'a>(&'a self, rhs: &'a Vector4) -> TransformedVector4<'a> {
self.transform_vec4_handle().vector(rhs)
}
pub fn transform_vec4_point(&self, rhs: &Vector4) -> Vector4 {
if matrix4_affine_linear_is_diagonal(&self.0) {
return Vector4(
transform_vector4_rhs_point_affine_linear_diagonal_ref_cached(&self.0, &rhs.0),
);
}
let facts = matrix4_facts(&self.0);
TransformedMatrix4::new_with_facts(self, facts).transform_point_vector(rhs)
}
pub fn transform_point3(&self, point: &Point3) -> BlasResult<Point3> {
let transformed = self.transform_vec4_point(&Vector4::new([
point.x.clone(),
point.y.clone(),
point.z.clone(),
Real::one(),
]));
let [x, y, z, w] = transformed.0;
if w.definitely_one() {
return Ok(Point3::new(x, y, z));
}
let inv_w = w.inverse()?;
Ok(Point3::new(
x.mul_cached(&inv_w),
y.mul_cached(&inv_w),
z.mul_cached(&inv_w),
))
}
pub fn transform_direction3(&self, direction: &Vector3) -> Vector3 {
let transformed = self.transform_vec4_direction(&Vector4::new([
direction.0[0].clone(),
direction.0[1].clone(),
direction.0[2].clone(),
Real::zero(),
]));
let [x, y, z, _w] = transformed.0;
Vector3::new([x, y, z])
}
pub fn transform_vec4_direction(&self, rhs: &Vector4) -> Vector4 {
if true {
match matrix4_direction_linear_kind(&self.0) {
Matrix4DirectionLinearKind::Identity => {
crate::trace_dispatch!(
"hyperlattice_matrix",
"method",
"transform-vector-vec4-direction-linear-identity"
);
return rhs.clone();
}
Matrix4DirectionLinearKind::Diagonal => {
return Vector4(transform_vector4_rhs_direction_ref_cached(
&self.0, &rhs.0, true,
));
}
Matrix4DirectionLinearKind::General => {
return Vector4(transform_vector4_rhs_direction_ref_cached(
&self.0, &rhs.0, false,
));
}
}
}
Vector4(transform_vector4_rhs_direction_ref_cached(
&self.0,
&rhs.0,
matrix4_direction_linear_is_diagonal(&self.0),
))
}
pub fn transform_vec4_direction_batch(&self, rhs: &[Vector4]) -> Vec<Vector4> {
crate::trace_dispatch!(
"hyperlattice_matrix",
"method",
"transform-vector-vec4-direction-batch"
);
transform_vector4_direction_batch_assumed_ref(
&self.0,
rhs,
matrix4_direction_linear_is_diagonal(&self.0),
)
}
pub fn transform_vec4_point_batch(&self, rhs: &[Vector4]) -> Vec<Vector4> {
crate::trace_dispatch!(
"hyperlattice_matrix",
"method",
"transform-vector-vec4-point-batch"
);
self.transform_vec4_handle().transform_point_batch(rhs)
}
pub fn transform_vec4_batch(&self, rhs: &[Vector4]) -> Vec<Vector4> {
crate::trace_dispatch!(
"hyperlattice_matrix",
"method",
"transform-vector-vec4-batch"
);
self.transform_vec4_handle().transform_vector_batch(rhs)
}
pub fn inverse(self) -> BlasResult<Self> {
crate::trace_dispatch!("hyperlattice_matrix", "method", "matrix4-inverse");
Ok(Self(invert_matrix4(self.0)?))
}
pub fn inverse_checked(self) -> CheckedBlasResult<Self> {
crate::trace_dispatch!("hyperlattice_matrix", "method", "matrix4-inverse-checked");
Ok(Self(invert_matrix4_checked(self.0)?))
}
pub fn inverse_checked_with_abort(self, signal: &AbortSignal) -> CheckedBlasResult<Self> {
crate::trace_dispatch!(
"hyperlattice_matrix",
"method",
"matrix4-inverse-checked-with-abort"
);
Ok(Self(invert_matrix4_checked_with_abort(self.0, signal)?))
}
pub fn determinant(&self) -> Real {
crate::trace_dispatch!("hyperlattice_matrix", "method", "matrix4-determinant");
determinant4(&self.0)
}
}