use std::array::from_fn;
use std::fmt;
use std::mem;
use std::ops::{Add, BitXor, Div, Index, IndexMut, Mul, Neg, Sub};
use crate::backend::BackendScalar;
use crate::require_known_nonzero_with_abort;
use crate::scalar::{
ZeroStatus, clone_with_abort, reject_definite_zero, require_known_nonzero, with_abort,
zero_status, zero_status_with_abort,
};
use crate::vector::{Vector3, Vector4, Vector4GeometricFacts, Vector4HomogeneousKind};
use crate::{AbortSignal, Backend, BlasResult, CheckedBlasResult, DefaultBackend, Problem, Scalar};
fn identity_array<B: Backend, const N: usize>() -> [[Scalar<B>; N]; N] {
from_fn(|row| {
from_fn(|col| {
if row == col {
Scalar::one()
} else {
Scalar::zero()
}
})
})
}
fn transpose_array3<B: Backend>(matrix: [[Scalar<B>; 3]; 3]) -> [[Scalar<B>; 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<B: Backend>(matrix: &[[Scalar<B>; 3]; 3]) -> [[Scalar<B>; 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<B: Backend>(matrix: [[Scalar<B>; 4]; 4]) -> [[Scalar<B>; 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<B: Backend>(matrix: &[[Scalar<B>; 4]; 4]) -> [[Scalar<B>; 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(),
],
]
}
#[derive(Clone, Debug, PartialEq)]
pub struct Matrix3<B: Backend = DefaultBackend>(
pub [[Scalar<B>; 3]; 3],
);
#[derive(Clone, Debug, PartialEq)]
pub struct Matrix4<B: Backend = DefaultBackend>(
pub [[Scalar<B>; 4]; 4],
);
#[derive(Debug, Clone)]
pub struct PreparedRightDivisor3<'a, B: Backend = DefaultBackend> {
divisor: &'a Matrix3<B>,
facts: Matrix3Facts,
right_is_exact_dyadic: bool,
right_is_exact_rational: bool,
adjugate: Option<[[Scalar<B>; 3]; 3]>,
determinant: Option<Scalar<B>>,
reciprocal_determinant: Option<Scalar<B>>,
}
#[derive(Debug, Clone)]
pub struct PreparedRightDivisor4<'a, B: Backend = DefaultBackend> {
divisor: &'a Matrix4<B>,
facts: Matrix4Facts,
right_is_exact_dyadic: bool,
right_is_exact_rational: bool,
is_definitely_dense_for_inverse: bool,
factors: Option<([Scalar<B>; 6], [Scalar<B>; 6])>,
adjugate: Option<[[Scalar<B>; 4]; 4]>,
determinant: Option<Scalar<B>>,
reciprocal_determinant: Option<Scalar<B>>,
}
#[derive(Clone, Copy, Debug)]
struct Matrix3Facts {
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,
}
fn matrix3_all_exact_dyadic_rational<B: Backend>(matrix: &[[Scalar<B>; 3]; 3]) -> bool {
matrix
.iter()
.all(|row| row.iter().all(|value| value.is_exact_dyadic_rational()))
}
fn matrix4_all_exact_dyadic_rational<B: Backend>(matrix: &[[Scalar<B>; 4]; 4]) -> bool {
matrix
.iter()
.all(|row| row.iter().all(|value| value.is_exact_dyadic_rational()))
}
fn matrix3_all_exact_rational<B: Backend>(matrix: &[[Scalar<B>; 3]; 3]) -> bool {
matrix
.iter()
.all(|row| row.iter().all(|value| value.is_exact_rational()))
}
fn matrix4_all_exact_rational<B: Backend>(matrix: &[[Scalar<B>; 4]; 4]) -> bool {
matrix
.iter()
.all(|row| row.iter().all(|value| value.is_exact_rational()))
}
#[inline(never)]
fn matrix4_all_exact_rational_slow<B: Backend>(matrix: &[[Scalar<B>; 4]; 4]) -> bool {
matrix4_all_exact_rational(matrix)
}
impl<'a, B: Backend> PreparedRightDivisor3<'a, B> {
pub fn new(divisor: &'a Matrix3<B>) -> Self {
crate::trace_dispatch!(
"hyperlattice_matrix",
"method",
"prepared-right-divisor3-new"
);
let facts = matrix3_facts(&divisor.0);
let right_is_exact_dyadic = matrix3_all_exact_dyadic_rational(&divisor.0);
let right_is_exact_rational =
right_is_exact_dyadic || matrix3_all_exact_rational(&divisor.0);
Self {
divisor,
facts,
right_is_exact_dyadic,
right_is_exact_rational,
adjugate: None,
determinant: None,
reciprocal_determinant: None,
}
}
pub fn divisor(&self) -> &Matrix3<B> {
self.divisor
}
#[inline]
fn can_use_shared_adjugate(&self, left: &[[Scalar<B>; 3]; 3]) -> bool {
if self.right_is_exact_dyadic {
return matrix3_all_exact_dyadic_rational(left);
}
if !self.right_is_exact_rational {
return false;
}
matrix3_all_exact_rational(left)
}
fn prepare_shared_adjugate(&mut self) -> BlasResult<&[[Scalar<B>; 3]; 3]> {
if self.adjugate.is_none() {
crate::trace_dispatch!(
"hyperlattice_matrix",
"method",
"prepared-right-divisor3-cache-shared-adjugate"
);
let (adjugate, determinant) = 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<&[[Scalar<B>; 3]; 3]> {
if self.adjugate.is_none() {
crate::trace_dispatch!(
"hyperlattice_matrix",
"method",
"prepared-right-divisor3-cache-shared-adjugate-checked"
);
let (adjugate, determinant) = 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<&[[Scalar<B>; 3]; 3]> {
if self.adjugate.is_none() {
crate::trace_dispatch!(
"hyperlattice_matrix",
"method",
"prepared-right-divisor3-cache-shared-adjugate-checked-abort"
);
let (adjugate, determinant) = 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: [[Scalar<B>; 3]; 3]) -> BlasResult<[[Scalar<B>; 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: [[Scalar<B>; 3]; 3],
) -> CheckedBlasResult<[[Scalar<B>; 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: [[Scalar<B>; 3]; 3],
signal: &AbortSignal,
) -> CheckedBlasResult<[[Scalar<B>; 3]; 3]> {
crate::trace_dispatch!(
"hyperlattice_matrix",
"method",
"prepared-right-divisor3-divide-checked-abort"
);
right_divide_matrix3_prepared_checked_with_abort(left, self, signal)
}
}
impl<'a, B: Backend> PreparedRightDivisor4<'a, B> {
pub fn new(divisor: &'a Matrix4<B>) -> Self {
crate::trace_dispatch!(
"hyperlattice_matrix",
"method",
"prepared-right-divisor4-new"
);
let facts = matrix4_facts(&divisor.0);
let right_is_exact_dyadic = matrix4_all_exact_dyadic_rational(&divisor.0);
let right_is_exact_rational =
right_is_exact_dyadic || matrix4_all_exact_rational(&divisor.0);
Self {
divisor,
facts,
right_is_exact_dyadic,
right_is_exact_rational,
is_definitely_dense_for_inverse: B::FUSE_SIGNED_PRODUCT_SUM
&& facts.is_definitely_dense_for_inverse,
factors: None,
adjugate: None,
determinant: None,
reciprocal_determinant: None,
}
}
pub fn divisor(&self) -> &Matrix4<B> {
self.divisor
}
#[inline]
fn can_use_shared_adjugate(&self, left: &[[Scalar<B>; 4]; 4]) -> bool {
if self.right_is_exact_dyadic {
if matrix4_all_exact_dyadic_rational(left) {
return true;
}
return B::FUSE_SIGNED_PRODUCT_SUM && matrix4_all_exact_rational_slow(left);
}
if !self.right_is_exact_rational {
return false;
}
matrix4_all_exact_rational(left)
}
fn prepare_shared_adjugate(&mut self) -> BlasResult<&[[Scalar<B>; 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 factors = self.factors.get_or_insert_with(|| {
if dense_exact {
matrix4_factors_dense_exact(&self.divisor.0)
} else {
matrix4_factors(&self.divisor.0)
}
});
let determinant = determinant4_from_factors(&factors.0, &factors.1);
let reciprocal_determinant = determinant.inverse_ref()?;
let adjugate = 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<&[[Scalar<B>; 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 factors = self.factors.get_or_insert_with(|| {
if dense_exact {
matrix4_factors_dense_exact(&self.divisor.0)
} else {
matrix4_factors(&self.divisor.0)
}
});
let determinant = determinant4_from_factors(&factors.0, &factors.1);
require_known_nonzero(&determinant)?;
let reciprocal_determinant = determinant.inverse_ref()?;
let adjugate = 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<&[[Scalar<B>; 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 factors = self.factors.get_or_insert_with(|| {
if dense_exact {
matrix4_factors_dense_exact(&self.divisor.0)
} else {
matrix4_factors(&self.divisor.0)
}
});
let determinant = 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 {
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: [[Scalar<B>; 4]; 4]) -> BlasResult<[[Scalar<B>; 4]; 4]> {
crate::trace_dispatch!(
"hyperlattice_matrix",
"method",
"prepared-right-divisor4-divide"
);
right_divide_matrix4_prepared(left, self)
}
pub fn divide_checked(
&mut self,
left: [[Scalar<B>; 4]; 4],
) -> CheckedBlasResult<[[Scalar<B>; 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: [[Scalar<B>; 4]; 4],
signal: &AbortSignal,
) -> CheckedBlasResult<[[Scalar<B>; 4]; 4]> {
crate::trace_dispatch!(
"hyperlattice_matrix",
"method",
"prepared-right-divisor4-divide-checked-abort"
);
right_divide_matrix4_prepared_checked_with_abort(left, self, signal)
}
}
#[derive(Clone, Copy, Debug)]
struct Matrix4Facts {
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_facts<B: Backend>(matrix: &[[Scalar<B>; 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;
Matrix3Facts {
is_identity,
is_diagonal,
is_upper_triangular,
is_lower_triangular,
linear_is_diagonal,
is_affine,
is_affine_translation,
}
}
#[inline]
fn matrix4_facts<B: Backend>(matrix: &[[Scalar<B>; 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 B::FUSE_SIGNED_PRODUCT_SUM {
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
};
Matrix4Facts {
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: [m03_zero, m13_zero, m23_zero],
is_affine,
is_affine_translation,
affine_linear_diagonal_is_definitely_nonzero,
}
}
#[inline]
fn matrix3_facts_assuming_const3<B: Backend, const N: usize>(
matrix: &[[Scalar<B>; 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;
Matrix3Facts {
is_identity,
is_diagonal,
is_upper_triangular,
is_lower_triangular,
linear_is_diagonal,
is_affine,
is_affine_translation,
}
}
#[inline]
fn matrix4_facts_assuming_const4<B: Backend, const N: usize>(
matrix: &[[Scalar<B>; 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 B::FUSE_SIGNED_PRODUCT_SUM {
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
};
Matrix4Facts {
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: [m03_zero, m13_zero, m23_zero],
is_affine,
is_affine_translation,
affine_linear_diagonal_is_definitely_nonzero,
}
}
fn map_array2<B: Backend, const N: usize, F>(
left: [Scalar<B>; N],
right: [Scalar<B>; N],
mut op: F,
) -> [Scalar<B>; N]
where
F: FnMut(Scalar<B>, Scalar<B>) -> Scalar<B>,
{
let mut right = right.into_iter();
left.map(|lhs| op(lhs, right.next().expect("arrays have equal length")))
}
fn map_array_ref<B: Backend, const N: usize, F>(
left: [Scalar<B>; N],
right: &[Scalar<B>; N],
mut op: F,
) -> [Scalar<B>; N]
where
F: FnMut(Scalar<B>, &Scalar<B>) -> Scalar<B>,
{
let mut right = right.iter();
left.map(|lhs| op(lhs, right.next().expect("arrays have equal length")))
}
fn map_matrix2<B: Backend, const N: usize, F>(
left: [[Scalar<B>; N]; N],
right: [[Scalar<B>; N]; N],
mut op: F,
) -> [[Scalar<B>; N]; N]
where
F: FnMut(Scalar<B>, Scalar<B>) -> Scalar<B>,
{
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<B: Backend, const N: usize, F>(
left: [[Scalar<B>; N]; N],
right: &[[Scalar<B>; N]; N],
mut op: F,
) -> [[Scalar<B>; N]; N]
where
F: FnMut(Scalar<B>, &Scalar<B>) -> Scalar<B>,
{
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<B: Backend, const N: usize, F>(
left: &[[Scalar<B>; N]; N],
right: [[Scalar<B>; N]; N],
mut op: F,
) -> [[Scalar<B>; N]; N]
where
F: FnMut(&Scalar<B>, Scalar<B>) -> Scalar<B>,
{
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<B: Backend, const N: usize, F>(
base: [[Scalar<B>; N]; N],
exponent: u32,
mut multiply: F,
) -> [[Scalar<B>; N]; N]
where
F: FnMut([[Scalar<B>; N]; N], [[Scalar<B>; N]; N]) -> [[Scalar<B>; 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<B: Backend>(base: [[Scalar<B>; 3]; 3], exponent: u32) -> [[Scalar<B>; 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 B::FUSE_SIGNED_PRODUCT_SUM && 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 B::FUSE_SIGNED_PRODUCT_SUM && 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::<B>)
}
#[inline]
fn matrix_power4<B: Backend>(base: [[Scalar<B>; 4]; 4], exponent: u32) -> [[Scalar<B>; 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 B::FUSE_SIGNED_PRODUCT_SUM && 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 B::FUSE_SIGNED_PRODUCT_SUM && 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::<B>)
}
fn ordinary_pivot<B: Backend, const N: usize>(
left: &[[Scalar<B>; 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<B: Backend, const N: usize, F>(
left: &[[Scalar<B>; N]; N],
col: usize,
mut classify: F,
) -> CheckedBlasResult<usize>
where
F: FnMut(&Scalar<B>) -> 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<B: Backend>(value: &mut Scalar<B>, factor: &Scalar<B>) {
let current = mem::replace(value, Scalar::zero());
*value = current.mul_cached(factor);
}
fn subtract_scaled_entry_in_place<B: Backend>(
value: &mut Scalar<B>,
pivot: &Scalar<B>,
factor: &Scalar<B>,
) {
let current = mem::replace(value, Scalar::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<B: Backend>(
coefficients: [[Scalar<B>; $n]; $n],
rhs: [[Scalar<B>; $n]; $n],
) -> BlasResult<[[Scalar<B>; $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], Scalar::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], Scalar::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<B: Backend>(
coefficients: [[Scalar<B>; $n]; $n],
rhs: [[Scalar<B>; $n]; $n],
) -> CheckedBlasResult<[[Scalar<B>; $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], Scalar::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], Scalar::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<B: Backend>(
coefficients: [[Scalar<B>; $n]; $n],
rhs: [[Scalar<B>; $n]; $n],
signal: &AbortSignal,
) -> CheckedBlasResult<[[Scalar<B>; $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], Scalar::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], Scalar::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<B: Backend, const N: usize>(
left: &[[Scalar<B>; N]; N],
right: &[[Scalar<B>; N]; N],
) -> bool {
if right
.iter()
.flat_map(|row| row.iter())
.chain(left.iter().flat_map(|row| row.iter()))
.all(Scalar::is_exact_dyadic_rational)
{
return true;
}
prefer_shared_adjugate_exact_rational_right_division(left, right)
}
#[inline(never)]
fn prefer_shared_adjugate_exact_rational_right_division<B: Backend, const N: usize>(
left: &[[Scalar<B>; N]; N],
right: &[[Scalar<B>; N]; N],
) -> bool {
right
.iter()
.flat_map(|row| row.iter())
.chain(left.iter().flat_map(|row| row.iter()))
.all(Scalar::is_exact_rational)
}
#[inline]
fn matrix4_direction_linear_is_diagonal<B: Backend>(matrix: &[[Scalar<B>; 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()
}
#[inline]
fn matrix4_affine_linear_is_diagonal<B: Backend>(matrix: &[[Scalar<B>; 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<B: Backend>(matrix: &[[Scalar<B>; 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<B: Backend>(matrix: &[[Scalar<B>; 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<B: Backend>(matrix: &[[Scalar<B>; 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<B: Backend>(matrix: &[[Scalar<B>; 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<B: Backend>(
left: &[[Scalar<B>; 4]; 4],
right: &[[Scalar<B>; 4]; 4],
) -> [[Scalar<B>; 4]; 4] {
if B::FUSE_SIGNED_PRODUCT_SUM
&& 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<B: Backend>(
left: [[Scalar<B>; 4]; 4],
right: &[[Scalar<B>; 4]; 4],
) -> [[Scalar<B>; 4]; 4] {
if B::FUSE_SIGNED_PRODUCT_SUM
&& 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<B: Backend>(
matrix: &[[Scalar<B>; 4]; 4],
) -> BlasResult<[[Scalar<B>; 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 = Scalar::zero() - (&matrix[0][3] * &inv00);
let inv_ty = Scalar::zero() - (&matrix[1][3] * &inv11);
let inv_tz = Scalar::zero() - (&matrix[2][3] * &inv22);
Ok([
[inv00, Scalar::zero(), Scalar::zero(), inv_tx],
[Scalar::zero(), inv11, Scalar::zero(), inv_ty],
[Scalar::zero(), Scalar::zero(), inv22, inv_tz],
[
Scalar::zero(),
Scalar::zero(),
Scalar::zero(),
Scalar::one(),
],
])
}
#[inline]
fn invert_matrix4_affine_linear_diagonal_checked<B: Backend>(
matrix: &[[Scalar<B>; 4]; 4],
) -> CheckedBlasResult<[[Scalar<B>; 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<B: Backend>(
matrix: &[[Scalar<B>; 4]; 4],
signal: &AbortSignal,
) -> CheckedBlasResult<[[Scalar<B>; 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<B: Backend>(
matrix: &[[Scalar<B>; 4]; 4],
linear_is_diagonal: bool,
is_affine_translation: bool,
) -> BlasResult<[[Scalar<B>; 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(),
Scalar::zero() - &matrix[0][3],
],
[
matrix[1][0].clone(),
matrix[1][1].clone(),
matrix[1][2].clone(),
Scalar::zero() - &matrix[1][3],
],
[
matrix[2][0].clone(),
matrix[2][1].clone(),
matrix[2][2].clone(),
Scalar::zero() - &matrix[2][3],
],
[
Scalar::zero(),
Scalar::zero(),
Scalar::zero(),
Scalar::one(),
],
]);
}
invert_matrix4_affine_without_translation(matrix)
}
#[inline]
fn invert_matrix4_affine_without_translation<B: Backend>(
matrix: &[[Scalar<B>; 4]; 4],
) -> BlasResult<[[Scalar<B>; 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: [Scalar<B>; 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]],
);
Scalar::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(),
],
[
Scalar::zero(),
Scalar::zero(),
Scalar::zero(),
Scalar::one(),
],
])
}
#[inline]
fn invert_matrix4_affine_checked<B: Backend>(
matrix: &[[Scalar<B>; 4]; 4],
linear_is_diagonal: bool,
is_affine_translation: bool,
) -> CheckedBlasResult<[[Scalar<B>; 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(),
Scalar::zero() - &matrix[0][3],
],
[
matrix[1][0].clone(),
matrix[1][1].clone(),
matrix[1][2].clone(),
Scalar::zero() - &matrix[1][3],
],
[
matrix[2][0].clone(),
matrix[2][1].clone(),
matrix[2][2].clone(),
Scalar::zero() - &matrix[2][3],
],
[
Scalar::zero(),
Scalar::zero(),
Scalar::zero(),
Scalar::one(),
],
]);
}
invert_matrix4_affine_without_translation_checked(matrix)
}
#[inline]
fn invert_matrix4_affine_without_translation_checked<B: Backend>(
matrix: &[[Scalar<B>; 4]; 4],
) -> CheckedBlasResult<[[Scalar<B>; 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: [Scalar<B>; 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]],
);
Scalar::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(),
],
[
Scalar::zero(),
Scalar::zero(),
Scalar::zero(),
Scalar::one(),
],
])
}
#[inline]
fn invert_matrix4_affine_checked_with_abort<B: Backend>(
matrix: &[[Scalar<B>; 4]; 4],
signal: &AbortSignal,
linear_is_diagonal: bool,
is_affine_translation: bool,
) -> CheckedBlasResult<[[Scalar<B>; 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(),
Scalar::zero() - &matrix[0][3],
],
[
matrix[1][0].clone(),
matrix[1][1].clone(),
matrix[1][2].clone(),
Scalar::zero() - &matrix[1][3],
],
[
matrix[2][0].clone(),
matrix[2][1].clone(),
matrix[2][2].clone(),
Scalar::zero() - &matrix[2][3],
],
[
Scalar::zero(),
Scalar::zero(),
Scalar::zero(),
Scalar::one(),
],
]);
}
invert_matrix4_affine_without_translation_checked_with_abort(matrix, signal)
}
#[inline]
fn invert_matrix4_affine_without_translation_checked_with_abort<B: Backend>(
matrix: &[[Scalar<B>; 4]; 4],
signal: &AbortSignal,
) -> CheckedBlasResult<[[Scalar<B>; 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: [Scalar<B>; 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]],
);
Scalar::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(),
],
[
Scalar::zero(),
Scalar::zero(),
Scalar::zero(),
Scalar::one(),
],
])
}
#[inline]
fn divide_matrix4_by_affine_linear_diagonal<B: Backend>(
left: [[Scalar<B>; 4]; 4],
right: &[[Scalar<B>; 4]; 4],
) -> BlasResult<[[Scalar<B>; 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 = Scalar::zero() - (&right[0][3] * &inv_a00);
let inv_ty = Scalar::zero() - (&right[1][3] * &inv_a11);
let inv_tz = Scalar::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<B: Backend>(
left: [[Scalar<B>; 4]; 4],
right: &[[Scalar<B>; 4]; 4],
) -> CheckedBlasResult<[[Scalar<B>; 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<B: Backend>(
left: [[Scalar<B>; 4]; 4],
right: &[[Scalar<B>; 4]; 4],
signal: &AbortSignal,
) -> CheckedBlasResult<[[Scalar<B>; 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<B: Backend>(
left: &[[Scalar<B>; 4]; 4],
right: &[[Scalar<B>; 4]; 4],
) -> BlasResult<[[Scalar<B>; 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 = Scalar::zero() - (&right[0][3] * &inv_a00);
let inv_ty = Scalar::zero() - (&right[1][3] * &inv_a11);
let inv_tz = Scalar::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<B: Backend>(
left: [[Scalar<B>; 4]; 4],
right: &[[Scalar<B>; 4]; 4],
) -> BlasResult<[[Scalar<B>; 4]; 4]> {
divide_matrix4_by_affine_linear_diagonal(left, right)
}
#[inline]
fn divide_matrix4_affine_by_affine_ref_linear_diagonal<B: Backend>(
left: &[[Scalar<B>; 4]; 4],
right: &[[Scalar<B>; 4]; 4],
) -> BlasResult<[[Scalar<B>; 4]; 4]> {
divide_matrix4_by_affine_linear_diagonal_ref(left, right)
}
#[inline]
fn divide_matrix4_affine_by_affine_linear_diagonal_checked<B: Backend>(
left: [[Scalar<B>; 4]; 4],
right: &[[Scalar<B>; 4]; 4],
) -> CheckedBlasResult<[[Scalar<B>; 4]; 4]> {
divide_matrix4_by_affine_linear_diagonal_checked(left, right)
}
#[inline]
fn divide_matrix4_affine_by_affine_linear_diagonal_checked_with_abort<B: Backend>(
left: [[Scalar<B>; 4]; 4],
right: &[[Scalar<B>; 4]; 4],
signal: &AbortSignal,
) -> CheckedBlasResult<[[Scalar<B>; 4]; 4]> {
divide_matrix4_by_affine_linear_diagonal_checked_with_abort(left, right, signal)
}
#[inline]
fn affine_translation_column_update<B: Backend>(
row: &[Scalar<B>; 4],
inverse_translation: &[Scalar<B>; 3],
) -> Scalar<B> {
let matrix_terms = [&row[0], &row[1], &row[2]];
let translation_terms = [
&inverse_translation[0],
&inverse_translation[1],
&inverse_translation[2],
];
row[3].clone() + Scalar::linear_combination3(matrix_terms, translation_terms)
}
#[inline]
fn affine_translation_column_subtract_update<B: Backend>(
row: &[Scalar<B>; 4],
translation: [&Scalar<B>; 3],
) -> Scalar<B> {
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<B: Backend>(
coefficients: [&Scalar<B>; 3],
values: [&Scalar<B>; 3],
) -> Scalar<B> {
if B::FUSE_SIGNED_PRODUCT_SUM {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"affine-translation-dot3-active-exact"
);
Scalar::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<B: Backend>(
left: [[Scalar<B>; 4]; 4],
right: &[[Scalar<B>; 4]; 4],
) -> BlasResult<[[Scalar<B>; 4]; 4]> {
let inverse = invert_matrix4_affine_without_translation(right)?;
Ok(multiply_arrays4(left, inverse))
}
#[inline]
fn divide_matrix4_affine_by_affine_no_translation<B: Backend>(
left: [[Scalar<B>; 4]; 4],
right: &[[Scalar<B>; 4]; 4],
) -> BlasResult<[[Scalar<B>; 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: [Scalar<B>; 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],
],
);
Scalar::zero() - shifted
});
let linear = multiply_arrays3_affine_linear_with_exact_dense_certificate(
left_linear,
right_inverse_linear,
);
let translation: [Scalar<B>; 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(),
],
[
Scalar::zero(),
Scalar::zero(),
Scalar::zero(),
Scalar::one(),
],
])
}
#[inline]
fn divide_matrix4_by_affine_translation<B: Backend>(
left: [[Scalar<B>; 4]; 4],
right: &[[Scalar<B>; 4]; 4],
) -> BlasResult<[[Scalar<B>; 4]; 4]> {
if B::FUSE_SIGNED_PRODUCT_SUM {
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 = [
Scalar::zero() - &right[0][3],
Scalar::zero() - &right[1][3],
Scalar::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<B: Backend>(
left: [[Scalar<B>; 3]; 3],
right: [[Scalar<B>; 3]; 3],
) -> [[Scalar<B>; 3]; 3] {
if B::FUSE_SIGNED_PRODUCT_SUM
&& 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<B: Backend>(
left: [[Scalar<B>; 4]; 4],
right: &[[Scalar<B>; 4]; 4],
) -> BlasResult<[[Scalar<B>; 4]; 4]> {
if B::FUSE_SIGNED_PRODUCT_SUM {
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),
],
[
Scalar::zero(),
Scalar::zero(),
Scalar::zero(),
Scalar::one(),
],
]);
}
let inverse_translation = [
Scalar::zero() - &right[0][3],
Scalar::zero() - &right[1][3],
Scalar::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),
],
[
Scalar::zero(),
Scalar::zero(),
Scalar::zero(),
Scalar::one(),
],
])
}
#[inline]
fn divide_matrix4_by_affine_checked<B: Backend>(
left: [[Scalar<B>; 4]; 4],
right: &[[Scalar<B>; 4]; 4],
) -> CheckedBlasResult<[[Scalar<B>; 4]; 4]> {
divide_matrix4_by_affine_no_translation_checked(left, right)
}
#[inline]
fn divide_matrix4_by_affine_checked_assumed_affine_translation<B: Backend>(
left: [[Scalar<B>; 4]; 4],
right: &[[Scalar<B>; 4]; 4],
) -> CheckedBlasResult<[[Scalar<B>; 4]; 4]> {
divide_matrix4_by_affine_checked_assuming_affine_translation(left, right)
}
#[inline]
fn divide_matrix4_by_affine_checked_assuming_affine_translation<B: Backend>(
left: [[Scalar<B>; 4]; 4],
right: &[[Scalar<B>; 4]; 4],
) -> CheckedBlasResult<[[Scalar<B>; 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<B: Backend>(
left: [[Scalar<B>; 4]; 4],
right: &[[Scalar<B>; 4]; 4],
) -> CheckedBlasResult<[[Scalar<B>; 4]; 4]> {
let inverse = invert_matrix4_affine_without_translation_checked(right)?;
Ok(multiply_arrays4(left, inverse))
}
#[inline]
fn divide_matrix4_affine_by_affine_checked<B: Backend>(
left: [[Scalar<B>; 4]; 4],
right: &[[Scalar<B>; 4]; 4],
) -> CheckedBlasResult<[[Scalar<B>; 4]; 4]> {
divide_matrix4_affine_by_affine_no_translation_checked(left, right)
}
#[inline]
fn divide_matrix4_affine_by_affine_checked_assumed_affine_translation<B: Backend>(
left: [[Scalar<B>; 4]; 4],
right: &[[Scalar<B>; 4]; 4],
) -> CheckedBlasResult<[[Scalar<B>; 4]; 4]> {
divide_matrix4_affine_by_affine_checked_assuming_affine_translation(left, right)
}
fn divide_matrix4_affine_by_affine_checked_assuming_affine_translation<B: Backend>(
left: [[Scalar<B>; 4]; 4],
right: &[[Scalar<B>; 4]; 4],
) -> CheckedBlasResult<[[Scalar<B>; 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<B: Backend>(
left: [[Scalar<B>; 4]; 4],
right: &[[Scalar<B>; 4]; 4],
) -> CheckedBlasResult<[[Scalar<B>; 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: [Scalar<B>; 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],
],
);
Scalar::zero() - shifted
});
let linear = multiply_arrays3_affine_linear_with_exact_dense_certificate(
left_linear,
right_inverse_linear,
);
let translation: [Scalar<B>; 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(),
],
[
Scalar::zero(),
Scalar::zero(),
Scalar::zero(),
Scalar::one(),
],
])
}
#[inline]
fn divide_matrix4_by_affine_checked_with_abort<B: Backend>(
left: [[Scalar<B>; 4]; 4],
right: &[[Scalar<B>; 4]; 4],
signal: &AbortSignal,
) -> CheckedBlasResult<[[Scalar<B>; 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<B: Backend>(
left: [[Scalar<B>; 4]; 4],
right: &[[Scalar<B>; 4]; 4],
signal: &AbortSignal,
) -> CheckedBlasResult<[[Scalar<B>; 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<B: Backend>(
left: [[Scalar<B>; 4]; 4],
right: &[[Scalar<B>; 4]; 4],
_signal: &AbortSignal,
) -> CheckedBlasResult<[[Scalar<B>; 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<B: Backend>(
left: [[Scalar<B>; 4]; 4],
right: &[[Scalar<B>; 4]; 4],
signal: &AbortSignal,
) -> CheckedBlasResult<[[Scalar<B>; 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<B: Backend>(
left: [[Scalar<B>; 4]; 4],
right: &[[Scalar<B>; 4]; 4],
signal: &AbortSignal,
) -> CheckedBlasResult<[[Scalar<B>; 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<B: Backend>(
left: [[Scalar<B>; 4]; 4],
right: &[[Scalar<B>; 4]; 4],
signal: &AbortSignal,
) -> CheckedBlasResult<[[Scalar<B>; 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<B: Backend>(
left: [[Scalar<B>; 4]; 4],
right: &[[Scalar<B>; 4]; 4],
_signal: &AbortSignal,
) -> CheckedBlasResult<[[Scalar<B>; 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<B: Backend>(
left: [[Scalar<B>; 4]; 4],
right: &[[Scalar<B>; 4]; 4],
signal: &AbortSignal,
) -> CheckedBlasResult<[[Scalar<B>; 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: [Scalar<B>; 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],
],
);
Scalar::zero() - shifted
});
let linear = multiply_arrays3_affine_linear_with_exact_dense_certificate(
left_linear,
right_inverse_linear,
);
let translation: [Scalar<B>; 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(),
],
[
Scalar::zero(),
Scalar::zero(),
Scalar::zero(),
Scalar::one(),
],
])
}
fn divide_matrix4_by_affine_ref_assumed_affine_translation<B: Backend>(
left: &[[Scalar<B>; 4]; 4],
right: &[[Scalar<B>; 4]; 4],
) -> BlasResult<[[Scalar<B>; 4]; 4]> {
divide_matrix4_by_affine_ref_translation(left, right)
}
fn divide_matrix4_by_affine_ref_translation<B: Backend>(
left: &[[Scalar<B>; 4]; 4],
right: &[[Scalar<B>; 4]; 4],
) -> BlasResult<[[Scalar<B>; 4]; 4]> {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"right-divide4-ref-by-affine-translation"
);
let inverse_translation = [
Scalar::zero() - &right[0][3],
Scalar::zero() - &right[1][3],
Scalar::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<B: Backend>(
left: &[[Scalar<B>; 4]; 4],
right: &[[Scalar<B>; 4]; 4],
) -> BlasResult<[[Scalar<B>; 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<B: Backend>(
left: &[[Scalar<B>; 4]; 4],
right: &[[Scalar<B>; 4]; 4],
) -> BlasResult<[[Scalar<B>; 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: [Scalar<B>; 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],
],
);
Scalar::zero() - shifted
});
let linear = multiply_arrays3_affine_linear_with_exact_dense_certificate(
left_linear,
right_inverse_linear,
);
let translation: [Scalar<B>; 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(),
],
[
Scalar::zero(),
Scalar::zero(),
Scalar::zero(),
Scalar::one(),
],
])
}
#[inline]
fn divide_matrix4_affine_by_affine_ref_translation<B: Backend>(
left: &[[Scalar<B>; 4]; 4],
right: &[[Scalar<B>; 4]; 4],
) -> BlasResult<[[Scalar<B>; 4]; 4]> {
let inverse_translation = [
Scalar::zero() - &right[0][3],
Scalar::zero() - &right[1][3],
Scalar::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),
],
[
Scalar::zero(),
Scalar::zero(),
Scalar::zero(),
Scalar::one(),
],
])
}
fn invert_matrix3_by_diagonal<B: Backend>(
matrix: &[[Scalar<B>; 3]; 3],
) -> BlasResult<[[Scalar<B>; 3]; 3]> {
let inv00 = matrix[0][0].clone().inverse()?;
let inv11 = matrix[1][1].clone().inverse()?;
let inv22 = matrix[2][2].clone().inverse()?;
if B::MOVE_ELEMENTWISE {
Ok([
[inv00, Scalar::zero(), Scalar::zero()],
[Scalar::zero(), inv11, Scalar::zero()],
[Scalar::zero(), Scalar::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 {
Scalar::zero()
}
})
}))
}
}
#[inline]
fn invert_matrix3_by_diagonal_checked<B: Backend>(
matrix: &[[Scalar<B>; 3]; 3],
) -> CheckedBlasResult<[[Scalar<B>; 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<B: Backend>(
matrix: &[[Scalar<B>; 3]; 3],
signal: &AbortSignal,
) -> CheckedBlasResult<[[Scalar<B>; 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<B: Backend>(
matrix: &[[Scalar<B>; 3]; 3],
) -> BlasResult<[[Scalar<B>; 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(Scalar::zero() - &matrix[0][1], &inv_a11);
let inv_a01 = scale_by_shared_factor(inv_a01, &inv_a00);
let inv_a12 = scale_by_shared_factor(Scalar::zero() - &matrix[1][2], &inv_a11);
let inv_a12 = scale_by_shared_factor(inv_a12, &inv_a22);
let inv_a02 = Scalar::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],
[Scalar::zero(), inv_a11, inv_a12],
[Scalar::zero(), Scalar::zero(), inv_a22],
])
}
#[inline]
fn invert_matrix3_upper_triangular_checked<B: Backend>(
matrix: &[[Scalar<B>; 3]; 3],
) -> CheckedBlasResult<[[Scalar<B>; 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<B: Backend>(
matrix: &[[Scalar<B>; 3]; 3],
signal: &AbortSignal,
) -> CheckedBlasResult<[[Scalar<B>; 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<B: Backend>(
matrix: &[[Scalar<B>; 3]; 3],
) -> BlasResult<[[Scalar<B>; 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(Scalar::zero() - &matrix[1][0], &inv_a00);
let inv_a10 = scale_by_shared_factor(inv_a10, &inv_a11);
let inv_a20 = Scalar::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(Scalar::zero() - &matrix[2][1], &inv_a11);
let inv_a21 = scale_by_shared_factor(inv_a21, &inv_a22);
Ok([
[inv_a00, Scalar::zero(), Scalar::zero()],
[inv_a10, inv_a11, Scalar::zero()],
[inv_a20, inv_a21, inv_a22],
])
}
#[inline]
fn invert_matrix3_lower_triangular_checked<B: Backend>(
matrix: &[[Scalar<B>; 3]; 3],
) -> CheckedBlasResult<[[Scalar<B>; 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<B: Backend>(
matrix: &[[Scalar<B>; 3]; 3],
signal: &AbortSignal,
) -> CheckedBlasResult<[[Scalar<B>; 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<B: Backend>(
matrix: &[[Scalar<B>; 3]; 3],
linear_is_diagonal: bool,
) -> BlasResult<[[Scalar<B>; 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(Scalar::zero() - &b, &inv_det);
let inv_a10 = scale_by_shared_factor(Scalar::zero() - &c, &inv_det);
let inv_a11 = scale_by_shared_factor(a, &inv_det);
let inv_tx = Scalar::zero() - ((&inv_a00 * &tx) + (&inv_a01 * &ty));
let inv_ty = Scalar::zero() - ((&inv_a10 * &tx) + (&inv_a11 * &ty));
Ok([
[inv_a00, inv_a01, inv_tx],
[inv_a10, inv_a11, inv_ty],
[Scalar::zero(), Scalar::zero(), Scalar::one()],
])
}
#[inline]
fn invert_matrix3_affine_linear_diagonal<B: Backend>(
matrix: &[[Scalar<B>; 3]; 3],
) -> BlasResult<[[Scalar<B>; 3]; 3]> {
let inv_a00 = matrix[0][0].clone().inverse()?;
let inv_a11 = matrix[1][1].clone().inverse()?;
let inv_tx = Scalar::zero() - (matrix[0][2].clone() * &inv_a00);
let inv_ty = Scalar::zero() - (matrix[1][2].clone() * &inv_a11);
Ok([
[inv_a00, Scalar::zero(), inv_tx],
[Scalar::zero(), inv_a11, inv_ty],
[Scalar::zero(), Scalar::zero(), Scalar::one()],
])
}
#[inline]
fn invert_matrix3_affine_linear_diagonal_checked<B: Backend>(
matrix: &[[Scalar<B>; 3]; 3],
) -> CheckedBlasResult<[[Scalar<B>; 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 = Scalar::zero() - (matrix[0][2].clone() * &inv_a00);
let inv_ty = Scalar::zero() - (matrix[1][2].clone() * &inv_a11);
Ok([
[inv_a00, Scalar::zero(), inv_tx],
[Scalar::zero(), inv_a11, inv_ty],
[Scalar::zero(), Scalar::zero(), Scalar::one()],
])
}
#[inline]
fn invert_matrix3_affine_linear_diagonal_checked_with_abort<B: Backend>(
matrix: &[[Scalar<B>; 3]; 3],
signal: &AbortSignal,
) -> CheckedBlasResult<[[Scalar<B>; 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 = Scalar::zero() - (matrix[0][2].clone() * &inv_a00);
let inv_ty = Scalar::zero() - (matrix[1][2].clone() * &inv_a11);
Ok([
[inv_a00, Scalar::zero(), inv_tx],
[Scalar::zero(), inv_a11, inv_ty],
[Scalar::zero(), Scalar::zero(), Scalar::one()],
])
}
#[inline]
fn divide_matrix3_by_affine_linear_diagonal<B: Backend>(
left: [[Scalar<B>; 3]; 3],
right: &[[Scalar<B>; 3]; 3],
) -> BlasResult<[[Scalar<B>; 3]; 3]> {
let inv_a00 = right[0][0].clone().inverse()?;
let inv_a11 = right[1][1].clone().inverse()?;
let inv_tx = Scalar::zero() - (&right[0][2] * &inv_a00);
let inv_ty = Scalar::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<B: Backend>(
left: [[Scalar<B>; 3]; 3],
right: &[[Scalar<B>; 3]; 3],
) -> CheckedBlasResult<[[Scalar<B>; 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<B: Backend>(
left: [[Scalar<B>; 3]; 3],
right: &[[Scalar<B>; 3]; 3],
signal: &AbortSignal,
) -> CheckedBlasResult<[[Scalar<B>; 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<B: Backend>(
left: &[[Scalar<B>; 3]; 3],
right: &[[Scalar<B>; 3]; 3],
) -> BlasResult<[[Scalar<B>; 3]; 3]> {
let inv_a00 = right[0][0].clone().inverse()?;
let inv_a11 = right[1][1].clone().inverse()?;
let inv_tx = Scalar::zero() - (&right[0][2] * &inv_a00);
let inv_ty = Scalar::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<B: Backend>(
left: [[Scalar<B>; 3]; 3],
right: &[[Scalar<B>; 3]; 3],
) -> BlasResult<[[Scalar<B>; 3]; 3]> {
divide_matrix3_by_affine_linear_diagonal(left, right)
}
#[inline]
fn divide_matrix3_affine_by_affine_ref_linear_diagonal<B: Backend>(
left: &[[Scalar<B>; 3]; 3],
right: &[[Scalar<B>; 3]; 3],
) -> BlasResult<[[Scalar<B>; 3]; 3]> {
divide_matrix3_by_affine_ref_linear_diagonal(left, right)
}
#[inline]
fn divide_matrix3_affine_by_affine_linear_diagonal_checked<B: Backend>(
left: [[Scalar<B>; 3]; 3],
right: &[[Scalar<B>; 3]; 3],
) -> CheckedBlasResult<[[Scalar<B>; 3]; 3]> {
divide_matrix3_by_affine_linear_diagonal_checked(left, right)
}
#[inline]
fn divide_matrix3_affine_by_affine_linear_diagonal_checked_with_abort<B: Backend>(
left: [[Scalar<B>; 3]; 3],
right: &[[Scalar<B>; 3]; 3],
signal: &AbortSignal,
) -> CheckedBlasResult<[[Scalar<B>; 3]; 3]> {
divide_matrix3_by_affine_linear_diagonal_checked_with_abort(left, right, signal)
}
#[inline]
fn invert_matrix3_affine_checked<B: Backend>(
matrix: &[[Scalar<B>; 3]; 3],
linear_is_diagonal: bool,
) -> CheckedBlasResult<[[Scalar<B>; 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(Scalar::zero() - &b, &inv_det);
let inv_a10 = scale_by_shared_factor(Scalar::zero() - &c, &inv_det);
let inv_a11 = scale_by_shared_factor(a, &inv_det);
let inv_tx = Scalar::zero() - ((&inv_a00 * &tx) + (&inv_a01 * &ty));
let inv_ty = Scalar::zero() - ((&inv_a10 * &tx) + (&inv_a11 * &ty));
Ok([
[inv_a00, inv_a01, inv_tx],
[inv_a10, inv_a11, inv_ty],
[Scalar::zero(), Scalar::zero(), Scalar::one()],
])
}
#[inline]
fn invert_matrix3_affine_checked_with_abort<B: Backend>(
matrix: &[[Scalar<B>; 3]; 3],
signal: &AbortSignal,
linear_is_diagonal: bool,
) -> CheckedBlasResult<[[Scalar<B>; 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(Scalar::zero() - &b, &inv_det);
let inv_a10 = scale_by_shared_factor(Scalar::zero() - &c, &inv_det);
let inv_a11 = scale_by_shared_factor(a, &inv_det);
let inv_tx = Scalar::zero() - ((&inv_a00 * &tx) + (&inv_a01 * &ty));
let inv_ty = Scalar::zero() - ((&inv_a10 * &tx) + (&inv_a11 * &ty));
Ok([
[inv_a00, inv_a01, inv_tx],
[inv_a10, inv_a11, inv_ty],
[Scalar::zero(), Scalar::zero(), Scalar::one()],
])
}
#[inline]
fn invert_matrix4_by_diagonal<B: Backend>(
matrix: &[[Scalar<B>; 4]; 4],
) -> BlasResult<[[Scalar<B>; 4]; 4]> {
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 B::MOVE_ELEMENTWISE {
Ok([
[inv00, Scalar::zero(), Scalar::zero(), Scalar::zero()],
[Scalar::zero(), inv11, Scalar::zero(), Scalar::zero()],
[Scalar::zero(), Scalar::zero(), inv22, Scalar::zero()],
[Scalar::zero(), Scalar::zero(), Scalar::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 {
Scalar::zero()
}
})
}))
}
}
#[inline]
fn invert_matrix4_by_upper_triangular<B: Backend>(
matrix: &[[Scalar<B>; 4]; 4],
) -> BlasResult<[[Scalar<B>; 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 = [
[
Scalar::zero(),
Scalar::zero(),
Scalar::zero(),
Scalar::zero(),
],
[
Scalar::zero(),
Scalar::zero(),
Scalar::zero(),
Scalar::zero(),
],
[
Scalar::zero(),
Scalar::zero(),
Scalar::zero(),
Scalar::zero(),
],
[
Scalar::zero(),
Scalar::zero(),
Scalar::zero(),
Scalar::zero(),
],
];
for row in 0..4 {
for col in row..4 {
let mut value = if row == col {
Scalar::one()
} else {
Scalar::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<B: Backend>(
matrix: &[[Scalar<B>; 4]; 4],
) -> BlasResult<[[Scalar<B>; 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 = [
[
Scalar::zero(),
Scalar::zero(),
Scalar::zero(),
Scalar::zero(),
],
[
Scalar::zero(),
Scalar::zero(),
Scalar::zero(),
Scalar::zero(),
],
[
Scalar::zero(),
Scalar::zero(),
Scalar::zero(),
Scalar::zero(),
],
[
Scalar::zero(),
Scalar::zero(),
Scalar::zero(),
Scalar::zero(),
],
];
for row in 0..4 {
for col in (0..=row).rev() {
let mut value = if row == col {
Scalar::one()
} else {
Scalar::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<B: Backend>(
matrix: &[[Scalar<B>; 4]; 4],
) -> CheckedBlasResult<[[Scalar<B>; 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<B: Backend>(
matrix: &[[Scalar<B>; 4]; 4],
) -> CheckedBlasResult<[[Scalar<B>; 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<B: Backend>(
matrix: &[[Scalar<B>; 4]; 4],
signal: &AbortSignal,
) -> CheckedBlasResult<[[Scalar<B>; 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<B: Backend>(
matrix: &[[Scalar<B>; 4]; 4],
signal: &AbortSignal,
) -> CheckedBlasResult<[[Scalar<B>; 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<B: Backend>(
matrix: &[[Scalar<B>; 4]; 4],
) -> CheckedBlasResult<[[Scalar<B>; 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<B: Backend>(
matrix: &[[Scalar<B>; 4]; 4],
signal: &AbortSignal,
) -> CheckedBlasResult<[[Scalar<B>; 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<B: Backend>(
left: &[[Scalar<B>; 3]; 3],
right: &[[Scalar<B>; 3]; 3],
) -> [[Scalar<B>; 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<B: Backend>(
left: &[[Scalar<B>; 3]; 3],
right: &[[Scalar<B>; 3]; 3],
) -> [[Scalar<B>; 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<B: Backend>(
left: &[[Scalar<B>; 4]; 4],
right: &[[Scalar<B>; 4]; 4],
) -> [[Scalar<B>; 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<B: Backend>(
left: &[[Scalar<B>; 4]; 4],
right: &[[Scalar<B>; 4]; 4],
) -> [[Scalar<B>; 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<B: Backend>(
left: [[Scalar<B>; 3]; 3],
right: &[[Scalar<B>; 3]; 3],
) -> BlasResult<[[Scalar<B>; 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<B: Backend>(
mut left: [[Scalar<B>; 3]; 3],
right: &[[Scalar<B>; 3]; 3],
) -> BlasResult<[[Scalar<B>; 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 B::FUSE_SIGNED_PRODUCT_SUM {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"divide3-upper-triangular-fused-exact"
);
let one = Scalar::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 = Scalar::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<B: Backend>(
row: &[Scalar<B>; 3],
right: &[[Scalar<B>; 3]; 3],
inv_a00: &Scalar<B>,
inv_a11: &Scalar<B>,
one: &Scalar<B>,
) -> [Scalar<B>; 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<B: Backend>(
left: [[Scalar<B>; 3]; 3],
right: &[[Scalar<B>; 3]; 3],
) -> BlasResult<[[Scalar<B>; 3]; 3]> {
let inv_a00 = right[0][0].clone().inverse()?;
let inv_a11 = right[1][1].clone().inverse()?;
if B::FUSE_SIGNED_PRODUCT_SUM {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"divide3-affine-upper-triangular-fused-exact"
);
}
let one = Scalar::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<B: Backend>(
left: [[Scalar<B>; 3]; 3],
right: &[[Scalar<B>; 3]; 3],
) -> BlasResult<[[Scalar<B>; 3]; 3]> {
let inv_a00 = right[0][0].clone().inverse()?;
let inv_a11 = right[1][1].clone().inverse()?;
if B::FUSE_SIGNED_PRODUCT_SUM {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"divide3-affine-left-affine-upper-triangular-fused-exact"
);
}
let one = Scalar::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),
[Scalar::zero(), Scalar::zero(), one],
])
}
#[inline]
fn divide_matrix3_by_affine_upper_triangular_checked<B: Backend>(
left: [[Scalar<B>; 3]; 3],
right: &[[Scalar<B>; 3]; 3],
) -> CheckedBlasResult<[[Scalar<B>; 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<B: Backend>(
left: [[Scalar<B>; 3]; 3],
right: &[[Scalar<B>; 3]; 3],
) -> CheckedBlasResult<[[Scalar<B>; 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<B: Backend>(
left: [[Scalar<B>; 3]; 3],
right: &[[Scalar<B>; 3]; 3],
signal: &AbortSignal,
) -> CheckedBlasResult<[[Scalar<B>; 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<B: Backend>(
left: [[Scalar<B>; 3]; 3],
right: &[[Scalar<B>; 3]; 3],
signal: &AbortSignal,
) -> CheckedBlasResult<[[Scalar<B>; 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<B: Backend>(
left: [[Scalar<B>; 3]; 3],
right: &[[Scalar<B>; 3]; 3],
) -> CheckedBlasResult<[[Scalar<B>; 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<B: Backend>(
left: [[Scalar<B>; 3]; 3],
right: &[[Scalar<B>; 3]; 3],
signal: &AbortSignal,
) -> CheckedBlasResult<[[Scalar<B>; 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<B: Backend>(
mut left: [[Scalar<B>; 3]; 3],
right: &[[Scalar<B>; 3]; 3],
) -> BlasResult<[[Scalar<B>; 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 B::FUSE_SIGNED_PRODUCT_SUM {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"divide3-lower-triangular-fused-exact"
);
let one = Scalar::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 = Scalar::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<B: Backend>(
left: [[Scalar<B>; 3]; 3],
right: &[[Scalar<B>; 3]; 3],
) -> CheckedBlasResult<[[Scalar<B>; 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<B: Backend>(
left: [[Scalar<B>; 3]; 3],
right: &[[Scalar<B>; 3]; 3],
signal: &AbortSignal,
) -> CheckedBlasResult<[[Scalar<B>; 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<B: Backend>(
linear: &[[Scalar<B>; 2]; 2],
tx: &Scalar<B>,
ty: &Scalar<B>,
) -> [Scalar<B>; 2] {
[
Scalar::zero() - &mul_add(&linear[0][0], tx, &linear[0][1], ty),
Scalar::zero() - &mul_add(&linear[1][0], tx, &linear[1][1], ty),
]
}
#[inline]
fn affine_linear_dot2<B: Backend>(
left_a: &Scalar<B>,
right_a: &Scalar<B>,
left_b: &Scalar<B>,
right_b: &Scalar<B>,
) -> Scalar<B> {
mul_add(left_a, right_a, left_b, right_b)
}
#[inline]
fn affine_translation_column_update_from_inverse2<B: Backend>(
row: &[Scalar<B>; 3],
translation: &[Scalar<B>; 2],
) -> Scalar<B> {
row[2].clone() + mul_add(&row[0], &translation[0], &row[1], &translation[1])
}
#[inline]
fn affine_translation_column_subtract_update2<B: Backend>(
row: &[Scalar<B>; 3],
translation: [&Scalar<B>; 2],
) -> Scalar<B> {
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<B: Backend>(
left: [[Scalar<B>; 3]; 3],
right: &[[Scalar<B>; 3]; 3],
) -> BlasResult<[[Scalar<B>; 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<B: Backend>(
left: [[Scalar<B>; 3]; 3],
right: &[[Scalar<B>; 3]; 3],
) -> BlasResult<[[Scalar<B>; 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),
],
[Scalar::zero(), Scalar::zero(), Scalar::one()],
])
}
#[inline]
fn divide_matrix3_by_affine_ref_translation<B: Backend>(
left: &[[Scalar<B>; 3]; 3],
right: &[[Scalar<B>; 3]; 3],
) -> BlasResult<[[Scalar<B>; 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<B: Backend>(
left: &[[Scalar<B>; 3]; 3],
right: &[[Scalar<B>; 3]; 3],
) -> BlasResult<[[Scalar<B>; 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),
],
[Scalar::zero(), Scalar::zero(), Scalar::one()],
])
}
#[inline]
fn divide_matrix3_by_affine_ref_no_translation<B: Backend>(
left: &[[Scalar<B>; 3]; 3],
right: &[[Scalar<B>; 3]; 3],
) -> BlasResult<[[Scalar<B>; 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(Scalar::zero() - &b, &right_inv_det),
],
[
scale_by_shared_factor(Scalar::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<B: Backend>(
left: &[[Scalar<B>; 3]; 3],
right: &[[Scalar<B>; 3]; 3],
) -> BlasResult<[[Scalar<B>; 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(Scalar::zero() - &b, &right_inv_det),
],
[
scale_by_shared_factor(Scalar::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),
],
[Scalar::zero(), Scalar::zero(), Scalar::one()],
])
}
#[inline]
fn divide_matrix3_by_affine<B: Backend>(
left: [[Scalar<B>; 3]; 3],
right: &[[Scalar<B>; 3]; 3],
) -> BlasResult<[[Scalar<B>; 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(Scalar::zero() - &b, &right_inv_det),
],
[
scale_by_shared_factor(Scalar::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<B: Backend>(
left: [[Scalar<B>; 3]; 3],
right: &[[Scalar<B>; 3]; 3],
) -> BlasResult<[[Scalar<B>; 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(Scalar::zero() - &b, &right_inv_det),
],
[
scale_by_shared_factor(Scalar::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),
],
[Scalar::zero(), Scalar::zero(), Scalar::one()],
])
}
#[inline]
fn divide_matrix3_by_diagonal_checked<B: Backend>(
left: [[Scalar<B>; 3]; 3],
right: &[[Scalar<B>; 3]; 3],
) -> CheckedBlasResult<[[Scalar<B>; 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<B: Backend>(
left: [[Scalar<B>; 3]; 3],
right: &[[Scalar<B>; 3]; 3],
signal: &AbortSignal,
) -> CheckedBlasResult<[[Scalar<B>; 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<B: Backend>(
left: [[Scalar<B>; 3]; 3],
right: &[[Scalar<B>; 3]; 3],
) -> CheckedBlasResult<[[Scalar<B>; 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(Scalar::zero() - &b, &right_inv_det),
],
[
scale_by_shared_factor(Scalar::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<B: Backend>(
left: [[Scalar<B>; 3]; 3],
right: &[[Scalar<B>; 3]; 3],
signal: &AbortSignal,
) -> CheckedBlasResult<[[Scalar<B>; 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(Scalar::zero() - &b, &right_inv_det),
],
[
scale_by_shared_factor(Scalar::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<B: Backend>(
left: [[Scalar<B>; 3]; 3],
right: &[[Scalar<B>; 3]; 3],
) -> CheckedBlasResult<[[Scalar<B>; 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(Scalar::zero() - &b, &right_inv_det),
],
[
scale_by_shared_factor(Scalar::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),
],
[Scalar::zero(), Scalar::zero(), Scalar::one()],
])
}
#[inline]
fn divide_matrix3_affine_by_affine_checked_with_abort<B: Backend>(
left: [[Scalar<B>; 3]; 3],
right: &[[Scalar<B>; 3]; 3],
signal: &AbortSignal,
) -> CheckedBlasResult<[[Scalar<B>; 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(Scalar::zero() - &b, &right_inv_det),
],
[
scale_by_shared_factor(Scalar::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),
],
[Scalar::zero(), Scalar::zero(), Scalar::one()],
])
}
#[inline]
fn divide_matrix4_by_diagonal<B: Backend>(
left: [[Scalar<B>; 4]; 4],
right: &[[Scalar<B>; 4]; 4],
) -> BlasResult<[[Scalar<B>; 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<B: Backend>(
left: [[Scalar<B>; 4]; 4],
right: &[[Scalar<B>; 4]; 4],
) -> CheckedBlasResult<[[Scalar<B>; 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<B: Backend>(
left: [[Scalar<B>; 4]; 4],
right: &[[Scalar<B>; 4]; 4],
signal: &AbortSignal,
) -> CheckedBlasResult<[[Scalar<B>; 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<B: Backend>(
mut left: [[Scalar<B>; 4]; 4],
right: &[[Scalar<B>; 4]; 4],
) -> BlasResult<[[Scalar<B>; 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 B::FUSE_SIGNED_PRODUCT_SUM {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"divide4-upper-triangular-fused-exact"
);
let one = Scalar::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 = Scalar::active_signed_product_sum2(
[true, false, false],
[[&row[2], &one], [&x0, &right[0][2]], [&x1, &right[1][2]]],
)
.mul_cached(&inv_a22);
let x3 = Scalar::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<B: Backend>(
row: &[Scalar<B>; 4],
right: &[[Scalar<B>; 4]; 4],
inv_a00: &Scalar<B>,
inv_a11: &Scalar<B>,
inv_a22: &Scalar<B>,
one: &Scalar<B>,
) -> [Scalar<B>; 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 B::FUSE_SIGNED_PRODUCT_SUM {
Scalar::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 B::FUSE_SIGNED_PRODUCT_SUM {
Scalar::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<B: Backend>(
left: [[Scalar<B>; 4]; 4],
right: &[[Scalar<B>; 4]; 4],
) -> BlasResult<[[Scalar<B>; 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 B::FUSE_SIGNED_PRODUCT_SUM {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"divide4-affine-upper-triangular-fused-exact"
);
}
let one = Scalar::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<B: Backend>(
left: [[Scalar<B>; 4]; 4],
right: &[[Scalar<B>; 4]; 4],
) -> BlasResult<[[Scalar<B>; 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 B::FUSE_SIGNED_PRODUCT_SUM {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"divide4-affine-left-affine-upper-triangular-fused-exact"
);
}
let one = Scalar::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),
[Scalar::zero(), Scalar::zero(), Scalar::zero(), one],
])
}
#[inline]
fn divide_matrix4_by_affine_upper_triangular_checked<B: Backend>(
left: [[Scalar<B>; 4]; 4],
right: &[[Scalar<B>; 4]; 4],
) -> CheckedBlasResult<[[Scalar<B>; 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<B: Backend>(
left: [[Scalar<B>; 4]; 4],
right: &[[Scalar<B>; 4]; 4],
) -> CheckedBlasResult<[[Scalar<B>; 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<B: Backend>(
left: [[Scalar<B>; 4]; 4],
right: &[[Scalar<B>; 4]; 4],
signal: &AbortSignal,
) -> CheckedBlasResult<[[Scalar<B>; 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<B: Backend>(
left: [[Scalar<B>; 4]; 4],
right: &[[Scalar<B>; 4]; 4],
signal: &AbortSignal,
) -> CheckedBlasResult<[[Scalar<B>; 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<B: Backend>(
left: [[Scalar<B>; 4]; 4],
right: &[[Scalar<B>; 4]; 4],
) -> CheckedBlasResult<[[Scalar<B>; 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<B: Backend>(
left: [[Scalar<B>; 4]; 4],
right: &[[Scalar<B>; 4]; 4],
signal: &AbortSignal,
) -> CheckedBlasResult<[[Scalar<B>; 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<B: Backend>(
mut left: [[Scalar<B>; 4]; 4],
right: &[[Scalar<B>; 4]; 4],
) -> BlasResult<[[Scalar<B>; 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 B::FUSE_SIGNED_PRODUCT_SUM {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"divide4-lower-triangular-fused-exact"
);
let one = Scalar::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 = Scalar::active_signed_product_sum2(
[true, false, false],
[[&row[1], &one], [&x2, &right[2][1]], [&x3, &right[3][1]]],
)
.mul_cached(&inv_a11);
let x0 = Scalar::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<B: Backend>(
left: [[Scalar<B>; 4]; 4],
right: &[[Scalar<B>; 4]; 4],
) -> CheckedBlasResult<[[Scalar<B>; 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<B: Backend>(
left: [[Scalar<B>; 4]; 4],
right: &[[Scalar<B>; 4]; 4],
signal: &AbortSignal,
) -> CheckedBlasResult<[[Scalar<B>; 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<B: Backend>(
left: [[Scalar<B>; 3]; 3],
right: [[Scalar<B>; 3]; 3],
) -> BlasResult<[[Scalar<B>; 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<B: Backend>(
left: &[[Scalar<B>; 3]; 3],
right: &[[Scalar<B>; 3]; 3],
) -> BlasResult<[[Scalar<B>; 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(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<B: Backend>(
left: [[Scalar<B>; 3]; 3],
right: [[Scalar<B>; 3]; 3],
) -> CheckedBlasResult<[[Scalar<B>; 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<B: Backend>(
left: [[Scalar<B>; 3]; 3],
right: [[Scalar<B>; 3]; 3],
signal: &AbortSignal,
) -> CheckedBlasResult<[[Scalar<B>; 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<B: Backend>(
left: [[Scalar<B>; 3]; 3],
prepared: &mut PreparedRightDivisor3<B>,
) -> BlasResult<[[Scalar<B>; 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<B: Backend>(
left: [[Scalar<B>; 3]; 3],
prepared: &mut PreparedRightDivisor3<B>,
) -> CheckedBlasResult<[[Scalar<B>; 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<B: Backend>(
left: [[Scalar<B>; 3]; 3],
prepared: &mut PreparedRightDivisor3<B>,
signal: &AbortSignal,
) -> CheckedBlasResult<[[Scalar<B>; 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 B::FUSE_SIGNED_PRODUCT_SUM && 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<B: Backend>(
left: [[Scalar<B>; 4]; 4],
right: [[Scalar<B>; 4]; 4],
) -> BlasResult<[[Scalar<B>; 4]; 4]> {
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 B::FUSE_SIGNED_PRODUCT_SUM && 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 = B::FUSE_SIGNED_PRODUCT_SUM && 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_prepared<B: Backend>(
left: [[Scalar<B>; 4]; 4],
prepared: &mut PreparedRightDivisor4<B>,
) -> BlasResult<[[Scalar<B>; 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 B::FUSE_SIGNED_PRODUCT_SUM && 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");
Ok(scale_matrix4(
multiply_arrays4_rhs_ref_with_dense_certificate(left, adjugate),
inv_det,
))
}
fn right_divide_matrix4_prepared_checked<B: Backend>(
left: [[Scalar<B>; 4]; 4],
prepared: &mut PreparedRightDivisor4<B>,
) -> CheckedBlasResult<[[Scalar<B>; 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 B::FUSE_SIGNED_PRODUCT_SUM && 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");
Ok(scale_matrix4(
multiply_arrays4_rhs_ref_with_dense_certificate(left, adjugate),
inv_det,
))
}
fn right_divide_matrix4_prepared_checked_with_abort<B: Backend>(
left: [[Scalar<B>; 4]; 4],
prepared: &mut PreparedRightDivisor4<B>,
signal: &AbortSignal,
) -> CheckedBlasResult<[[Scalar<B>; 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 B::FUSE_SIGNED_PRODUCT_SUM && 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");
Ok(scale_matrix4(
multiply_arrays4_rhs_ref_with_dense_certificate(left, adjugate),
inv_det,
))
}
fn right_divide_matrix4_ref<B: Backend>(
left: &[[Scalar<B>; 4]; 4],
right: &[[Scalar<B>; 4]; 4],
) -> BlasResult<[[Scalar<B>; 4]; 4]> {
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 B::FUSE_SIGNED_PRODUCT_SUM && 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 = B::FUSE_SIGNED_PRODUCT_SUM && 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<B: Backend>(
left: [[Scalar<B>; 4]; 4],
right: [[Scalar<B>; 4]; 4],
) -> CheckedBlasResult<[[Scalar<B>; 4]; 4]> {
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 B::FUSE_SIGNED_PRODUCT_SUM && 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 = B::FUSE_SIGNED_PRODUCT_SUM && 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<B: Backend>(
left: [[Scalar<B>; 4]; 4],
right: [[Scalar<B>; 4]; 4],
signal: &AbortSignal,
) -> CheckedBlasResult<[[Scalar<B>; 4]; 4]> {
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 B::FUSE_SIGNED_PRODUCT_SUM && 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 = B::FUSE_SIGNED_PRODUCT_SUM && 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<B: Backend>(
left: &[[Scalar<B>; 3]; 3],
right: &[[Scalar<B>; 3]; 3],
) -> [[Scalar<B>; 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| {
Scalar(B::Repr::dot3(
[&left[row][0].0, &left[row][1].0, &left[row][2].0],
[&right[0][col].0, &right[1][col].0, &right[2][col].0],
))
};
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 => Scalar::zero(),
1 => {
if p0 {
l0 * r0
} else if p1 {
l1 * r1
} else {
l2 * r2
}
}
2 => {
if !p0 {
Scalar::active_signed_product_sum2([true, true], [[l1, r1], [l2, r2]])
} else if !p1 {
Scalar::active_signed_product_sum2([true, true], [[l0, r0], [l2, r2]])
} else {
Scalar::active_signed_product_sum2([true, true], [[l0, r0], [l1, r1]])
}
}
_ => Scalar(B::Repr::dot3([&l0.0, &l1.0, &l2.0], [&r0.0, &r1.0, &r2.0])),
}
};
[
[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<B: Backend>(
left: &[[Scalar<B>; 3]; 3],
right: &[[Scalar<B>; 3]; 3],
) -> [[Scalar<B>; 3]; 3] {
crate::trace_dispatch!("hyperlattice_matrix", "helper", "multiply3-dense-ref");
let cell = |row: usize, col: usize| {
Scalar(B::Repr::dot3(
[&left[row][0].0, &left[row][1].0, &left[row][2].0],
[&right[0][col].0, &right[1][col].0, &right[2][col].0],
))
};
[
[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<B: Backend>(
left: [[Scalar<B>; 3]; 3],
right: [[Scalar<B>; 3]; 3],
) -> [[Scalar<B>; 3]; 3] {
if B::FUSE_SIGNED_PRODUCT_SUM
&& 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<B: Backend>(
left: [[Scalar<B>; 3]; 3],
right: &[[Scalar<B>; 3]; 3],
) -> [[Scalar<B>; 3]; 3] {
if B::FUSE_SIGNED_PRODUCT_SUM
&& 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<B: Backend>(
left: &[[Scalar<B>; 3]; 3],
right: &[[Scalar<B>; 3]; 3],
) -> [[Scalar<B>; 3]; 3] {
if B::FUSE_SIGNED_PRODUCT_SUM
&& 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<B: Backend>(
left: &[[Scalar<B>; 4]; 4],
right: &[[Scalar<B>; 4]; 4],
) -> [[Scalar<B>; 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 B::FUSE_SIGNED_PRODUCT_SUM {
Scalar(B::Repr::active_dot4(
[&l0.0, &l1.0, &l2.0, &l3.0],
[&r0.0, &r1.0, &r2.0, &r3.0],
))
} else {
Scalar(B::Repr::dot4(
[&l0.0, &l1.0, &l2.0, &l3.0],
[&r0.0, &r1.0, &r2.0, &r3.0],
))
}
};
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 => Scalar::zero(),
1 => {
if p0 {
l0 * r0
} else if p1 {
l1 * r1
} else if p2 {
l2 * r2
} else {
l3 * r3
}
}
2 => {
if p0 {
if p1 {
Scalar::active_signed_product_sum2([true, true], [[l0, r0], [l1, r1]])
} else if p2 {
Scalar::active_signed_product_sum2([true, true], [[l0, r0], [l2, r2]])
} else {
Scalar::active_signed_product_sum2([true, true], [[l0, r0], [l3, r3]])
}
} else if p1 {
if p2 {
Scalar::active_signed_product_sum2([true, true], [[l1, r1], [l2, r2]])
} else {
Scalar::active_signed_product_sum2([true, true], [[l1, r1], [l3, r3]])
}
} else if p2 {
Scalar::active_signed_product_sum2([true, true], [[l2, r2], [l3, r3]])
} else {
unreachable!("matrix multiply sparse branch expects exactly two active terms")
}
}
3 => {
if !p0 {
Scalar::active_signed_product_sum2(
[true, true, true],
[[l1, r1], [l2, r2], [l3, r3]],
)
} else if !p1 {
Scalar::active_signed_product_sum2(
[true, true, true],
[[l0, r0], [l2, r2], [l3, r3]],
)
} else if !p2 {
Scalar::active_signed_product_sum2(
[true, true, true],
[[l0, r0], [l1, r1], [l3, r3]],
)
} else {
Scalar::active_signed_product_sum2(
[true, true, true],
[[l0, r0], [l1, r1], [l2, r2]],
)
}
}
_ if B::FUSE_SIGNED_PRODUCT_SUM => Scalar(B::Repr::active_dot4(
[&l0.0, &l1.0, &l2.0, &l3.0],
[&r0.0, &r1.0, &r2.0, &r3.0],
)),
_ => Scalar(B::Repr::dot4(
[&l0.0, &l1.0, &l2.0, &l3.0],
[&r0.0, &r1.0, &r2.0, &r3.0],
)),
}
};
[
[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<B: Backend>(
left: &[[Scalar<B>; 4]; 4],
right: &[[Scalar<B>; 4]; 4],
) -> [[Scalar<B>; 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 B::FUSE_SIGNED_PRODUCT_SUM {
Scalar(B::Repr::active_dot4(
[&l0.0, &l1.0, &l2.0, &l3.0],
[&r0.0, &r1.0, &r2.0, &r3.0],
))
} else {
Scalar(B::Repr::dot4(
[&l0.0, &l1.0, &l2.0, &l3.0],
[&r0.0, &r1.0, &r2.0, &r3.0],
))
}
};
[
[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<B: Backend>(
left: [[Scalar<B>; 3]; 3],
right: [[Scalar<B>; 3]; 3],
) -> [[Scalar<B>; 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<B: Backend>(
left: [[Scalar<B>; 4]; 4],
right: [[Scalar<B>; 4]; 4],
) -> [[Scalar<B>; 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<B: Backend>(
left: [[Scalar<B>; 3]; 3],
right: &[[Scalar<B>; 3]; 3],
) -> [[Scalar<B>; 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<B: Backend>(
left: [[Scalar<B>; 4]; 4],
right: &[[Scalar<B>; 4]; 4],
) -> [[Scalar<B>; 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<B: Backend>(
left: &[[Scalar<B>; 3]; 3],
right: &[[Scalar<B>; 3]; 3],
) -> [[Scalar<B>; 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<B: Backend>(
left: &[[Scalar<B>; 4]; 4],
right: &[[Scalar<B>; 4]; 4],
) -> [[Scalar<B>; 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<B: Backend, const N: usize>(
left: &[[Scalar<B>; N]; N],
right: &[Scalar<B>; N],
) -> [Scalar<B>; 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_or_one() {
Some(false) => {
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 {
Scalar::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]];
Scalar::linear_combination3(matrix_terms, vector_terms)
});
}
Some(true) => {
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 {
Scalar::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 = Scalar::linear_combination3(matrix_terms, vector_terms);
if translation_is_zero[row] {
mapped
} else {
mapped + &left[row][3]
}
});
}
None => {}
}
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]];
Scalar::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]];
Scalar::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]];
Scalar::linear_combination3(matrix_terms, vector_terms)
})
}
}
#[inline]
fn transform_vector3_rhs_ref_cached<B: Backend>(
left: &[[Scalar<B>; 3]; 3],
right: &[Scalar<B>; 3],
) -> [Scalar<B>; 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<B: Backend>(
left: &[[Scalar<B>; 3]; 3],
right: &[Scalar<B>; 3],
) -> [Scalar<B>; 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]];
Scalar::linear_combination3(matrix_terms, vector_terms)
})
}
#[inline]
fn transform_vector3_rhs_dense_active_ref<B: Backend>(
left: &[[Scalar<B>; 3]; 3],
right: &[Scalar<B>; 3],
) -> [Scalar<B>; 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]];
Scalar::active_linear_combination3(matrix_terms, vector_terms)
})
}
#[inline]
fn transform_vector4_rhs_ref_cached_with_matrix_facts<B: Backend>(
left: &[[Scalar<B>; 4]; 4],
right: &[Scalar<B>; 4],
translation_is_zero: &[bool; 4],
matrix_facts: Matrix4Facts,
) -> [Scalar<B>; 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_or_one() {
Some(false) => {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"transform-vector4-direction"
);
return transform_vector4_rhs_direction_ref_cached(
left,
right,
matrix_facts.direction_linear_is_diagonal,
);
}
Some(true) => {
crate::trace_dispatch!("hyperlattice_matrix", "helper", "transform-vector4-point");
return transform_vector4_rhs_point_ref_cached(left, right, translation_is_zero);
}
None => {}
}
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]];
Scalar::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]];
Scalar::linear_combination4(matrix_terms, vector_terms)
}
})
}
#[inline]
fn transform_vector4_rhs_ref_with_facts<B: Backend>(
left: &[[Scalar<B>; 4]; 4],
right: &[Scalar<B>; 4],
translation_is_zero: &[bool; 4],
all_translation_zero: bool,
all_translation_nonzero: bool,
direction_is_diagonal: bool,
matrix_facts: Option<Matrix4Facts>,
facts: Vector4GeometricFacts,
) -> [Scalar<B>; 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<B: Backend>(
left: &[[Scalar<B>; 4]; 4],
right: &[Scalar<B>; 4],
direction_is_diagonal: bool,
) -> [Scalar<B>; 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]),
Scalar::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]];
Scalar::linear_combination3(matrix_terms, vector_terms)
})
}
fn transform_vector4_direction_batch_assumed_ref<B: Backend>(
left: &[[Scalar<B>; 4]; 4],
rhs: &[Vector4<B>],
direction_is_diagonal: bool,
) -> Vec<Vector4<B>> {
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]),
Scalar::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]];
Scalar::linear_combination3(matrix_terms, vector_terms)
})));
}
transformed
}
#[inline]
fn transform_vector4_rhs_point_affine_linear_diagonal_ref_cached<B: Backend>(
left: &[[Scalar<B>; 4]; 4],
right: &[Scalar<B>; 4],
) -> [Scalar<B>; 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<B: Backend>(
left: &[[Scalar<B>; 4]; 4],
right: &[Scalar<B>; 4],
translation_is_zero: &[bool; 4],
all_translation_zero: bool,
all_translation_nonzero: bool,
w_scale_is_one: bool,
w_scale: &Scalar<B>,
) -> [Scalar<B>; 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]];
Scalar::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: [Scalar<B>; 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 B::FUSE_SIGNED_PRODUCT_SUM {
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]];
Scalar::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]];
Scalar::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 = Scalar::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<B: Backend>(
left: &[[Scalar<B>; 4]; 4],
right: &[Scalar<B>; 4],
translation_is_zero: &[bool; 4],
) -> [Scalar<B>; 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 = Scalar::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<B: Backend>(
left: &[[Scalar<B>; 4]; 4],
right: &[Scalar<B>; 4],
) -> [Scalar<B>; 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]];
Scalar::linear_combination3(matrix_terms, vector_terms) + &left[row][3]
})
}
#[inline]
fn transform_vector4_rhs_full_no_translation_ref_cached<B: Backend>(
left: &[[Scalar<B>; 4]; 4],
right: &[Scalar<B>; 4],
) -> [Scalar<B>; 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]];
Scalar::linear_combination3(matrix_terms, vector_terms)
})
}
#[derive(Clone, Copy, Debug)]
pub struct TransformedMatrix3<'a, B: Backend = DefaultBackend> {
matrix: &'a Matrix3<B>,
facts: Matrix3Facts,
}
impl<'a, B: Backend> TransformedMatrix3<'a, B> {
fn new(matrix: &'a Matrix3<B>) -> Self {
let facts = matrix3_facts(&matrix.0);
Self { matrix, facts }
}
pub fn transform_vector(&self, rhs: &Vector3<B>) -> Vector3<B> {
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<B>) -> TransformedVector3<'a, B> {
TransformedVector3 {
matrix: self.matrix,
facts: self.facts,
vector: rhs,
}
}
pub fn transform_vector_batch(&self, rhs: &[Vector3<B>]) -> Vec<Vector3<B>> {
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, B: Backend = DefaultBackend> {
matrix: &'a Matrix4<B>,
facts: Matrix4Facts,
translation_is_zero: [bool; 4],
all_translation_zero: bool,
all_translation_nonzero: bool,
direction_is_diagonal: bool,
}
impl<'a, B: Backend> TransformedMatrix4<'a, B> {
#[inline]
fn transform_vector_with_facts(
&self,
rhs: &Vector4<B>,
vector_facts: Vector4GeometricFacts,
) -> Vector4<B> {
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]),
Scalar::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<B>) -> Self {
let facts = matrix4_facts(&matrix.0);
Self::new_with_facts(matrix, facts)
}
fn new_with_facts(matrix: &'a Matrix4<B>, 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<B>) -> Vector4<B> {
self.transform_vector_with_facts(rhs, rhs.geometric_facts())
}
#[inline]
pub fn transform_direction_vector(&self, rhs: &Vector4<B>) -> Vector4<B> {
self.transform_vector_with_facts(
rhs,
Vector4GeometricFacts {
homogeneous: Vector4HomogeneousKind::Direction,
},
)
}
#[inline]
pub fn transform_point_vector(&self, rhs: &Vector4<B>) -> Vector4<B> {
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<B>) -> TransformedVector4<'a, B> {
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<B>]) -> Vec<Vector4<B>> {
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_or_one() {
Some(false) => {
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]),
Scalar::zero(),
]));
}
return transformed;
}
}
Some(true)
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]),
Scalar::one(),
]));
}
return transformed;
}
_ => {}
}
}
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]),
Scalar::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<B>]) -> Vec<Vector4<B>> {
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<B>]) -> Vec<Vector4<B>> {
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],
Scalar::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, B: Backend = DefaultBackend> {
matrix: &'a Matrix3<B>,
facts: Matrix3Facts,
vector: &'a Vector3<B>,
}
impl<'a, B: Backend> TransformedVector3<'a, B> {
#[inline]
pub fn materialize(self) -> Vector3<B> {
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, B: Backend = DefaultBackend> {
matrix: &'a Matrix4<B>,
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<B>,
}
impl<'a, B: Backend> TransformedVector4<'a, B> {
#[inline]
pub fn materialize(self) -> Vector4<B> {
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]),
Scalar::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<B: Backend>(value: Scalar<B>, factor: &Scalar<B>) -> Scalar<B> {
if B::BORROW_SHARED_SCALE_FACTOR {
value.mul_cached(factor)
} else {
value * factor.clone()
}
}
fn scale_matrix3<B: Backend>(
matrix: [[Scalar<B>; 3]; 3],
factor: &Scalar<B>,
) -> [[Scalar<B>; 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<B: Backend>(
matrix: [[Scalar<B>; 4]; 4],
factor: &Scalar<B>,
) -> [[Scalar<B>; 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<B: Backend>(
left_a: &Scalar<B>,
right_a: &Scalar<B>,
left_b: &Scalar<B>,
right_b: &Scalar<B>,
) -> Scalar<B> {
if B::FUSE_SIGNED_PRODUCT_SUM {
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 Scalar::zero();
}
if first_zero {
return -(left_b * right_b);
}
return left_a * right_a;
}
Scalar::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<B: Backend>(
left_a: &Scalar<B>,
right_a: &Scalar<B>,
left_b: &Scalar<B>,
right_b: &Scalar<B>,
) -> Scalar<B> {
crate::trace_dispatch!("hyperlattice_matrix", "helper", "mul-sub-dense-exact");
Scalar::active_signed_product_sum2([true, false], [[left_a, right_a], [left_b, right_b]])
}
fn mul_add<B: Backend>(
left_a: &Scalar<B>,
right_a: &Scalar<B>,
left_b: &Scalar<B>,
right_b: &Scalar<B>,
) -> Scalar<B> {
if B::FUSE_SIGNED_PRODUCT_SUM {
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 Scalar::zero();
}
if first_zero {
return left_b * right_b;
}
return left_a * right_a;
}
Scalar::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<B: Backend>(
left_a: &Scalar<B>,
right_a: &Scalar<B>,
left_b: &Scalar<B>,
right_b: &Scalar<B>,
left_c: &Scalar<B>,
right_c: &Scalar<B>,
) -> Scalar<B> {
if B::FUSE_SIGNED_PRODUCT_SUM {
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 => Scalar::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 {
Scalar::active_signed_product_sum2(
[true, false],
[[left_b, right_b], [left_c, right_c]],
)
} else if second_zero {
Scalar::active_signed_product_sum2(
[true, false],
[[left_a, right_a], [left_c, right_c]],
)
} else {
Scalar::active_signed_product_sum2(
[true, true],
[[left_a, right_a], [left_b, right_b]],
)
}
}
_ => unreachable!(),
};
}
Scalar::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<B: Backend>(
left_a: &Scalar<B>,
right_a: &Scalar<B>,
left_b: &Scalar<B>,
right_b: &Scalar<B>,
left_c: &Scalar<B>,
right_c: &Scalar<B>,
) -> Scalar<B> {
crate::trace_dispatch!("hyperlattice_matrix", "helper", "mul-add-sub-dense-exact");
Scalar::active_signed_product_sum2(
[true, true, false],
[[left_a, right_a], [left_b, right_b], [left_c, right_c]],
)
}
fn mul_sub_add<B: Backend>(
left_a: &Scalar<B>,
right_a: &Scalar<B>,
left_b: &Scalar<B>,
right_b: &Scalar<B>,
left_c: &Scalar<B>,
right_c: &Scalar<B>,
) -> Scalar<B> {
if B::FUSE_SIGNED_PRODUCT_SUM {
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 => Scalar::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 {
Scalar::active_signed_product_sum2(
[false, false],
[[left_b, right_b], [left_c, right_c]],
)
} else if second_zero {
Scalar::active_signed_product_sum2(
[true, false],
[[left_a, right_a], [left_c, right_c]],
)
} else {
Scalar::active_signed_product_sum2(
[true, false],
[[left_a, right_a], [left_b, right_b]],
)
}
}
_ => unreachable!(),
};
}
Scalar::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<B: Backend>(
left_a: &Scalar<B>,
right_a: &Scalar<B>,
left_b: &Scalar<B>,
right_b: &Scalar<B>,
left_c: &Scalar<B>,
right_c: &Scalar<B>,
) -> Scalar<B> {
crate::trace_dispatch!("hyperlattice_matrix", "helper", "mul-sub-add-dense-exact");
Scalar::active_signed_product_sum2(
[true, false, false],
[[left_a, right_a], [left_b, right_b], [left_c, right_c]],
)
}
#[inline]
fn determinant3<B: Backend>(m: &[[Scalar<B>; 3]; 3]) -> Scalar<B> {
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]);
Scalar::dot3([&m[0][0], &m[0][1], &m[0][2]], [&c00, &c10, &c20])
}
#[inline]
fn matrix3_adjugate_and_determinant<B: Backend>(
matrix: &[[Scalar<B>; 3]; 3],
) -> ([[Scalar<B>; 3]; 3], Scalar<B>) {
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 = Scalar::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<B: Backend>(
matrix: &[[Scalar<B>; 3]; 3],
) -> ([[Scalar<B>; 3]; 3], Scalar<B>) {
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 =
Scalar::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]
fn matrix3_scaled_adjugate<B: Backend>(
matrix: &[[Scalar<B>; 3]; 3],
) -> BlasResult<[[Scalar<B>; 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 = Scalar::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<B: Backend>(
matrix: &[[Scalar<B>; 3]; 3],
) -> BlasResult<[[Scalar<B>; 3]; 3]> {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"matrix3-scaled-adjugate-dense-exact"
);
let (adjugate, det) = matrix3_adjugate_and_determinant_dense_exact(matrix);
let inv_det = det.inverse()?;
Ok(scale_matrix3(adjugate, &inv_det))
}
#[inline]
fn invert_matrix3<B: Backend>(matrix: [[Scalar<B>; 3]; 3]) -> BlasResult<[[Scalar<B>; 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 B::FUSE_SIGNED_PRODUCT_SUM {
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<B: Backend>(
matrix: [[Scalar<B>; 3]; 3],
) -> CheckedBlasResult<[[Scalar<B>; 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 B::FUSE_SIGNED_PRODUCT_SUM {
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<B: Backend>(
matrix: [[Scalar<B>; 3]; 3],
signal: &AbortSignal,
) -> CheckedBlasResult<[[Scalar<B>; 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 B::FUSE_SIGNED_PRODUCT_SUM {
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<B: Backend>(m: &[[Scalar<B>; 4]; 4]) -> ([Scalar<B>; 6], [Scalar<B>; 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<B: Backend>(
m: &[[Scalar<B>; 4]; 4],
) -> ([Scalar<B>; 6], [Scalar<B>; 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)
}
fn determinant4_from_factors<B: Backend>(s: &[Scalar<B>; 6], c: &[Scalar<B>; 6]) -> Scalar<B> {
crate::trace_dispatch!("hyperlattice_matrix", "helper", "determinant4-from-factors");
if B::FUSE_SIGNED_PRODUCT_SUM {
Scalar::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]],
],
)
} else {
let positive = Scalar::dot3([&s[0], &s[2], &s[3]], [&c[5], &c[3], &c[2]]) + &s[5] * &c[0];
let negative = &s[1] * &c[4] + &s[4] * &c[1];
positive - negative
}
}
#[inline]
fn determinant4<B: Backend>(m: &[[Scalar<B>; 4]; 4]) -> Scalar<B> {
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<B: Backend>(
m: &[[Scalar<B>; 4]; 4],
s: &[Scalar<B>; 6],
c: &[Scalar<B>; 6],
inv_det: &Scalar<B>,
) -> [[Scalar<B>; 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<B: Backend>(
m: &[[Scalar<B>; 4]; 4],
s: &[Scalar<B>; 6],
c: &[Scalar<B>; 6],
inv_det: &Scalar<B>,
) -> [[Scalar<B>; 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<B: Backend>(matrix: [[Scalar<B>; 4]; 4]) -> BlasResult<[[Scalar<B>; 4]; 4]> {
if matrix4_is_definitely_dense_for_inverse(&matrix) {
crate::trace_dispatch!(
"hyperlattice_matrix",
"helper",
"invert-matrix4-dense-cofactor"
);
let (s, c) = if B::FUSE_SIGNED_PRODUCT_SUM {
matrix4_factors_dense_exact(&matrix)
} else {
matrix4_factors(&matrix)
};
let det = determinant4_from_factors(&s, &c);
let inv_det = det.inverse()?;
if B::FUSE_SIGNED_PRODUCT_SUM {
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<B: Backend>(
matrix: [[Scalar<B>; 4]; 4],
) -> CheckedBlasResult<[[Scalar<B>; 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 B::FUSE_SIGNED_PRODUCT_SUM {
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 B::FUSE_SIGNED_PRODUCT_SUM {
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<B: Backend>(
matrix: [[Scalar<B>; 4]; 4],
signal: &AbortSignal,
) -> CheckedBlasResult<[[Scalar<B>; 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 B::FUSE_SIGNED_PRODUCT_SUM {
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 B::FUSE_SIGNED_PRODUCT_SUM {
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<B: Backend>(
m: &[[Scalar<B>; 4]; 4],
s: &[Scalar<B>; 6],
c: &[Scalar<B>; 6],
) -> [[Scalar<B>; 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<B: Backend>(
m: &[[Scalar<B>; 4]; 4],
s: &[Scalar<B>; 6],
c: &[Scalar<B>; 6],
) -> [[Scalar<B>; 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]),
],
]
}
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<B: Backend> $name<B> {
pub fn new(values: [[Scalar<B>; $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(|_| Scalar::zero())))
}
pub fn identity() -> Self {
crate::trace_dispatch!("hyperlattice_matrix", "constructor", "identity");
Self(from_fn(|row| {
from_fn(|col| {
if row == col {
Scalar::one()
} else {
Scalar::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");
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");
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");
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: Scalar<B>) -> CheckedBlasResult<Self> {
crate::trace_dispatch!("hyperlattice_matrix", "method", "div-scalar-checked");
require_known_nonzero(&rhs)?;
let inv_rhs = rhs.inverse()?;
if B::MOVE_ELEMENTWISE {
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: Scalar<B>,
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 B::MOVE_ELEMENTWISE {
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<B: Backend> Index<usize> for $name<B> {
type Output = [Scalar<B>; $n];
fn index(&self, index: usize) -> &Self::Output {
&self.0[index]
}
}
impl<B: Backend> IndexMut<usize> for $name<B> {
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
&mut self.0[index]
}
}
impl<B: Backend> fmt::Display for $name<B> {
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<B: Backend> Add for $name<B> {
type Output = Self;
fn add(self, rhs: Self) -> Self::Output {
crate::trace_dispatch!("hyperlattice_matrix", "op", "add-owned-owned");
if B::MOVE_ELEMENTWISE {
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<B: Backend> Add<&$name<B>> for $name<B> {
type Output = Self;
fn add(self, rhs: &$name<B>) -> Self::Output {
crate::trace_dispatch!("hyperlattice_matrix", "op", "add-owned-ref");
Self(map_matrix_ref(self.0, &rhs.0, Scalar::add_cached))
}
}
impl<B: Backend> Add<$name<B>> for &$name<B> {
type Output = $name<B>;
fn add(self, rhs: $name<B>) -> 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<B: Backend> Add<&$name<B>> for &$name<B> {
type Output = $name<B>;
fn add(self, rhs: &$name<B>) -> 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<B: Backend> Add<Scalar<B>> for $name<B> {
type Output = Self;
fn add(self, rhs: Scalar<B>) -> Self::Output {
crate::trace_dispatch!("hyperlattice_matrix", "op", "add-scalar-owned");
let rhs = &rhs;
if B::MOVE_ELEMENTWISE {
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<B: Backend> Add<&Scalar<B>> for $name<B> {
type Output = Self;
fn add(self, rhs: &Scalar<B>) -> Self::Output {
crate::trace_dispatch!("hyperlattice_matrix", "op", "add-scalar-ref");
Self(self.0.map(|row| row.map(|value| value.add_cached(rhs))))
}
}
impl<B: Backend> Sub for $name<B> {
type Output = Self;
fn sub(self, rhs: Self) -> Self::Output {
crate::trace_dispatch!("hyperlattice_matrix", "op", "sub-owned-owned");
if B::MOVE_ELEMENTWISE {
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<B: Backend> Sub<&$name<B>> for $name<B> {
type Output = Self;
fn sub(self, rhs: &$name<B>) -> Self::Output {
crate::trace_dispatch!("hyperlattice_matrix", "op", "sub-owned-ref");
Self(map_matrix_ref(self.0, &rhs.0, Scalar::sub_cached))
}
}
impl<B: Backend> Sub<$name<B>> for &$name<B> {
type Output = $name<B>;
fn sub(self, rhs: $name<B>) -> 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<B: Backend> Sub<&$name<B>> for &$name<B> {
type Output = $name<B>;
fn sub(self, rhs: &$name<B>) -> 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<B: Backend> Sub<Scalar<B>> for $name<B> {
type Output = Self;
fn sub(self, rhs: Scalar<B>) -> Self::Output {
crate::trace_dispatch!("hyperlattice_matrix", "op", "sub-scalar-owned");
let rhs = &rhs;
if B::MOVE_ELEMENTWISE {
Self(self.0.map(|row| row.map(|value| value.sub_cached(rhs))))
} else {
let mut values = self.0;
for row in &mut values {
for value in row {
*value = value.clone().sub_cached(rhs);
}
}
Self(values)
}
}
}
impl<B: Backend> Sub<&Scalar<B>> for $name<B> {
type Output = Self;
fn sub(self, rhs: &Scalar<B>) -> Self::Output {
crate::trace_dispatch!("hyperlattice_matrix", "op", "sub-scalar-ref");
Self(self.0.map(|row| row.map(|value| value.sub_cached(rhs))))
}
}
impl<B: Backend> Neg for $name<B> {
type Output = Self;
fn neg(self) -> Self::Output {
crate::trace_dispatch!("hyperlattice_matrix", "op", "neg-owned");
if B::MOVE_ELEMENTWISE {
Self(self.0.map(|row| row.map(|value| -value)))
} else {
Self(from_fn(|row| from_fn(|col| -self.0[row][col].clone())))
}
}
}
impl<B: Backend> Neg for &$name<B> {
type Output = $name<B>;
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<B: Backend> Mul<Scalar<B>> for $name<B> {
type Output = Self;
fn mul(self, rhs: Scalar<B>) -> Self::Output {
crate::trace_dispatch!("hyperlattice_matrix", "op", "mul-scalar-owned");
let rhs = &rhs;
if B::MOVE_ELEMENTWISE {
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<B: Backend> Mul<&Scalar<B>> for $name<B> {
type Output = Self;
fn mul(self, rhs: &Scalar<B>) -> Self::Output {
crate::trace_dispatch!("hyperlattice_matrix", "op", "mul-scalar-ref");
Self(self.0.map(|row| row.map(|value| value.mul_cached(rhs))))
}
}
impl<B: Backend> Div<Scalar<B>> for $name<B> {
type Output = BlasResult<Self>;
fn div(self, rhs: Scalar<B>) -> Self::Output {
crate::trace_dispatch!("hyperlattice_matrix", "op", "div-scalar-owned");
reject_definite_zero(&rhs)?;
let inv_rhs = rhs.inverse()?;
if B::MOVE_ELEMENTWISE {
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<B: Backend> Div<&Scalar<B>> for $name<B> {
type Output = BlasResult<Self>;
fn div(self, rhs: &Scalar<B>) -> Self::Output {
crate::trace_dispatch!("hyperlattice_matrix", "op", "div-scalar-ref");
reject_definite_zero(rhs)?;
let inv_rhs = rhs.inverse_ref()?;
if B::MOVE_ELEMENTWISE {
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<B: Backend> Mul for $name<B> {
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<B: Backend> Mul<&$name<B>> for $name<B> {
type Output = Self;
fn mul(self, rhs: &$name<B>) -> Self::Output {
crate::trace_dispatch!("hyperlattice_matrix", "op", "mul-owned-ref");
Self($mul_rhs_ref_fn(self.0, &rhs.0))
}
}
impl<B: Backend> Mul<$name<B>> for &$name<B> {
type Output = $name<B>;
fn mul(self, rhs: $name<B>) -> Self::Output {
crate::trace_dispatch!("hyperlattice_matrix", "op", "mul-ref-owned");
$name($mul_ref_fn(&self.0, &rhs.0))
}
}
impl<B: Backend> Mul<&$name<B>> for &$name<B> {
type Output = $name<B>;
fn mul(self, rhs: &$name<B>) -> Self::Output {
crate::trace_dispatch!("hyperlattice_matrix", "op", "mul-ref-ref");
$name($mul_ref_fn(&self.0, &rhs.0))
}
}
impl<B: Backend> Div for $name<B> {
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<B: Backend> Div<&$name<B>> for $name<B> {
type Output = BlasResult<Self>;
fn div(self, rhs: &$name<B>) -> Self::Output {
crate::trace_dispatch!("hyperlattice_matrix", "op", "div-owned-ref");
self / rhs.clone()
}
}
impl<B: Backend> Div<$name<B>> for &$name<B> {
type Output = BlasResult<$name<B>>;
fn div(self, rhs: $name<B>) -> Self::Output {
crate::trace_dispatch!("hyperlattice_matrix", "op", "div-ref-owned");
self.clone() / rhs
}
}
impl<B: Backend> Div<&$name<B>> for &$name<B> {
type Output = BlasResult<$name<B>>;
fn div(self, rhs: &$name<B>) -> Self::Output {
crate::trace_dispatch!("hyperlattice_matrix", "op", "div-ref-ref");
Ok($name($div_ref_fn(&self.0, &rhs.0)?))
}
}
impl<B: Backend> Mul<$vector<B>> for $name<B> {
type Output = $vector<B>;
fn mul(self, rhs: $vector<B>) -> Self::Output {
crate::trace_dispatch!("hyperlattice_matrix", "op", "transform-vector-owned-owned");
$vector(transform_vector_rhs_ref(&self.0, &rhs.0))
}
}
impl<B: Backend> Mul<&$vector<B>> for $name<B> {
type Output = $vector<B>;
fn mul(self, rhs: &$vector<B>) -> Self::Output {
crate::trace_dispatch!("hyperlattice_matrix", "op", "transform-vector-owned-ref");
$vector(transform_vector_rhs_ref(&self.0, &rhs.0))
}
}
impl<B: Backend> Mul<$vector<B>> for &$name<B> {
type Output = $vector<B>;
fn mul(self, rhs: $vector<B>) -> Self::Output {
crate::trace_dispatch!("hyperlattice_matrix", "op", "transform-vector-ref-owned");
$vector(transform_vector_rhs_ref(&self.0, &rhs.0))
}
}
impl<B: Backend> Mul<&$vector<B>> for &$name<B> {
type Output = $vector<B>;
fn mul(self, rhs: &$vector<B>) -> Self::Output {
crate::trace_dispatch!("hyperlattice_matrix", "op", "transform-vector-ref-ref");
$vector(transform_vector_rhs_ref(&self.0, &rhs.0))
}
}
impl<B: Backend> BitXor<i32> for $name<B> {
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<B: Backend> Matrix3<B> {
pub fn diagonal(diagonal: [Scalar<B>; 3]) -> Self {
crate::trace_dispatch!("hyperlattice_matrix", "constructor", "diagonal3");
let [d0, d1, d2] = diagonal;
Self([
[d0, Scalar::zero(), Scalar::zero()],
[Scalar::zero(), d1, Scalar::zero()],
[Scalar::zero(), Scalar::zero(), d2],
])
}
pub fn diagonal_inverse(diagonal: [Scalar<B>; 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: [Scalar<B>; 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: [Scalar<B>; 3],
rhs: &Vector3<B>,
) -> BlasResult<Vector3<B>> {
crate::trace_dispatch!("hyperlattice_matrix", "method", "div-diagonal3-vector");
let [d0, d1, d2] = 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),
];
let mapped = if B::FUSE_SIGNED_PRODUCT_SUM {
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<'_, B> {
PreparedRightDivisor3::new(self)
}
pub fn div_matrix_with_prepared(
self,
divisor: &mut PreparedRightDivisor3<'_, B>,
) -> 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<'_, B>,
) -> 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<'_, B>,
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: Scalar<B>) -> Self {
crate::trace_dispatch!("hyperlattice_matrix", "constructor", "uniform-scale3");
Self([
[scale.clone(), Scalar::zero(), Scalar::zero()],
[Scalar::zero(), scale.clone(), Scalar::zero()],
[Scalar::zero(), Scalar::zero(), scale],
])
}
pub fn uniform_scale_inverse(scale: Scalar<B>) -> 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<B>]) -> Vec<Vector3<B>> {
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<'_, B> {
TransformedMatrix3::new(self)
}
pub fn transform_vec3_with<'a>(&'a self, rhs: &'a Vector3<B>) -> TransformedVector3<'a, B> {
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) -> Scalar<B> {
crate::trace_dispatch!("hyperlattice_matrix", "method", "matrix3-determinant");
determinant3(&self.0)
}
}
impl<B: Backend> Matrix4<B> {
pub fn diagonal(diagonal: [Scalar<B>; 4]) -> Self {
crate::trace_dispatch!("hyperlattice_matrix", "constructor", "diagonal");
let [d0, d1, d2, d3] = diagonal;
Self([
[d0, Scalar::zero(), Scalar::zero(), Scalar::zero()],
[Scalar::zero(), d1, Scalar::zero(), Scalar::zero()],
[Scalar::zero(), Scalar::zero(), d2, Scalar::zero()],
[Scalar::zero(), Scalar::zero(), Scalar::zero(), d3],
])
}
pub fn diagonal_inverse(diagonal: [Scalar<B>; 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: [Scalar<B>; 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: [Scalar<B>; 4],
rhs: &Vector4<B>,
) -> BlasResult<Vector4<B>> {
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 = 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),
Scalar::zero(),
];
return Ok(Vector4(transform_vector4_rhs_direction_ref_cached(
&self.0,
&rhs_div,
matrix4_direction_linear_is_diagonal(&self.0),
)));
}
let inv0 = d0.inverse()?;
let inv1 = d1.inverse()?;
let inv2 = d2.inverse()?;
let inv3_is_one = d3.definitely_one();
let inv3 = if inv3_is_one {
Scalar::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, Scalar::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: [Scalar<B>; 4],
rhs: &Vector4<B>,
) -> BlasResult<Vector4<B>> {
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),
Scalar::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<'_, B> {
PreparedRightDivisor4::new(self)
}
pub fn div_matrix_with_prepared(
self,
divisor: &mut PreparedRightDivisor4<'_, B>,
) -> 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 PreparedRightDivisor4<'_, B>,
) -> 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<'_, B>,
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: Scalar<B>) -> Self {
crate::trace_dispatch!("hyperlattice_matrix", "constructor", "uniform-scale");
Self([
[
scale.clone(),
Scalar::zero(),
Scalar::zero(),
Scalar::zero(),
],
[
Scalar::zero(),
scale.clone(),
Scalar::zero(),
Scalar::zero(),
],
[
Scalar::zero(),
Scalar::zero(),
scale.clone(),
Scalar::zero(),
],
[Scalar::zero(), Scalar::zero(), Scalar::zero(), scale],
])
}
pub fn uniform_scale_inverse(scale: Scalar<B>) -> 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<'_, B> {
TransformedMatrix4::new(self)
}
pub fn transform_vec4_with<'a>(&'a self, rhs: &'a Vector4<B>) -> TransformedVector4<'a, B> {
self.transform_vec4_handle().vector(rhs)
}
pub fn transform_vec4_point(&self, rhs: &Vector4<B>) -> Vector4<B> {
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_vec4_direction(&self, rhs: &Vector4<B>) -> Vector4<B> {
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<B>]) -> Vec<Vector4<B>> {
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<B>]) -> Vec<Vector4<B>> {
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<B>]) -> Vec<Vector4<B>> {
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) -> Scalar<B> {
crate::trace_dispatch!("hyperlattice_matrix", "method", "matrix4-determinant");
determinant4(&self.0)
}
}