use std::array::from_fn;
use std::fmt;
use std::ops::{Add, Div, Index, IndexMut, Mul, Neg, Sub};
use std::sync::atomic::Ordering;
use crate::scalar::{clone_with_abort, reject_definite_zero, require_known_nonzero, with_abort};
use crate::{
AbortSignal, BlasResult, CheckedBlasResult, ExactRealSetFacts, Problem, Real, RealKernelExt,
RealSymbolicDependencyMask, RealZeroOneMinusOneStatus, ZeroStatus,
};
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum Axis2 {
X,
Y,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum SignedAxis2 {
PosX,
NegX,
PosY,
NegY,
}
impl SignedAxis2 {
pub const fn axis(self) -> Axis2 {
match self {
Self::PosX | Self::NegX => Axis2::X,
Self::PosY | Self::NegY => Axis2::Y,
}
}
pub const fn is_negative(self) -> bool {
matches!(self, Self::NegX | Self::NegY)
}
pub fn sign_real(self) -> Real {
if self.is_negative() {
-Real::one()
} else {
Real::one()
}
}
}
impl Axis2 {
pub const fn index(self) -> usize {
match self {
Self::X => 0,
Self::Y => 1,
}
}
pub const fn bit(self) -> u8 {
1 << self.index()
}
}
#[derive(Clone, Copy, Debug)]
pub struct VectorSharedScaleView<'a, const N: usize> {
components: [&'a Real; N],
pub exact: ExactRealSetFacts,
pub known_zero_mask: u128,
pub known_nonzero_mask: u128,
pub unknown_zero_mask: u128,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct VectorSharedScaleFacts<const N: usize> {
pub exact: ExactRealSetFacts,
pub known_zero_mask: u128,
pub known_nonzero_mask: u128,
pub unknown_zero_mask: u128,
}
impl<const N: usize> VectorSharedScaleFacts<N> {
pub fn is_known_zero(self) -> bool {
self.known_zero_mask == vector_mask::<N>()
}
pub fn is_known_dense(self) -> bool {
self.known_nonzero_mask == vector_mask::<N>()
}
pub fn known_zero_count(self) -> u32 {
self.known_zero_mask.count_ones()
}
pub fn known_nonzero_count(self) -> u32 {
self.known_nonzero_mask.count_ones()
}
pub fn unknown_zero_count(self) -> u32 {
self.unknown_zero_mask.count_ones()
}
pub fn has_dyadic_schedule(self) -> bool {
self.exact.has_dyadic_schedule()
}
pub fn has_shared_denominator_schedule(self) -> bool {
self.exact.has_shared_denominator_schedule()
}
pub fn has_integer_grid_schedule(self) -> bool {
self.exact.has_integer_grid_schedule()
}
pub fn has_signed_unit_schedule(self) -> bool {
self.exact.has_signed_unit_schedule()
}
}
impl<'a, const N: usize> VectorSharedScaleView<'a, N> {
pub fn from_components(components: [&'a Real; N]) -> Option<Self> {
crate::trace_dispatch!(
"hyperlattice_vector",
"query",
"shared-scale-view-from-components"
);
let exact = crate::kernels::exact_real_set_facts(components.iter().copied());
if !exact.has_shared_denominator_schedule() {
return None;
}
let facts = vector_shared_scale_facts(exact, components);
Some(Self {
components,
exact,
known_zero_mask: facts.known_zero_mask,
known_nonzero_mask: facts.known_nonzero_mask,
unknown_zero_mask: facts.unknown_zero_mask,
})
}
pub fn components(self) -> [&'a Real; N] {
self.components
}
pub const fn len(self) -> usize {
N
}
pub const fn is_empty(self) -> bool {
N == 0
}
pub fn facts(self) -> VectorSharedScaleFacts<N> {
VectorSharedScaleFacts {
exact: self.exact,
known_zero_mask: self.known_zero_mask,
known_nonzero_mask: self.known_nonzero_mask,
unknown_zero_mask: self.unknown_zero_mask,
}
}
pub fn is_known_zero(self) -> bool {
self.facts().is_known_zero()
}
pub fn is_known_dense(self) -> bool {
self.facts().is_known_dense()
}
pub fn known_zero_count(self) -> u32 {
self.facts().known_zero_count()
}
pub fn known_nonzero_count(self) -> u32 {
self.facts().known_nonzero_count()
}
pub fn unknown_zero_count(self) -> u32 {
self.facts().unknown_zero_count()
}
pub fn dot(self, rhs: Self) -> Real {
crate::trace_dispatch!(
"hyperlattice_vector",
"method",
"shared-scale-view-dot-known-exact"
);
Real::exact_rational_signed_product_sum_known_exact(
[true; N],
from_fn(|index| [self.components[index], rhs.components[index]]),
)
}
pub fn squared_norm(self) -> Real {
self.dot(self)
}
}
impl<'a> VectorSharedScaleView<'a, 2> {
pub fn wedge(self, rhs: Self) -> Real {
crate::trace_dispatch!(
"hyperlattice_vector",
"method",
"shared-scale-view-wedge-known-exact"
);
Real::exact_rational_signed_product_sum_known_exact(
[true, false],
[
[self.components[0], rhs.components[1]],
[self.components[1], rhs.components[0]],
],
)
}
}
impl<'a> VectorSharedScaleView<'a, 3> {
pub fn cross(self, rhs: Self) -> Vector3 {
crate::trace_dispatch!(
"hyperlattice_vector",
"method",
"shared-scale-view-cross-known-exact"
);
let determinant = |a: &Real, b: &Real, c: &Real, d: &Real| {
Real::exact_rational_signed_product_sum_known_exact([true, false], [[a, b], [c, d]])
};
Vector3::new([
determinant(
self.components[1],
rhs.components[2],
self.components[2],
rhs.components[1],
),
determinant(
self.components[2],
rhs.components[0],
self.components[0],
rhs.components[2],
),
determinant(
self.components[0],
rhs.components[1],
self.components[1],
rhs.components[0],
),
])
}
}
#[derive(Clone, Debug, PartialEq)]
pub struct SharedScaleVec<const N: usize> {
components: [Real; N],
pub exact: ExactRealSetFacts,
pub facts: VectorSharedScaleFacts<N>,
}
impl<const N: usize> SharedScaleVec<N> {
pub fn from_components(components: [Real; N]) -> Option<Self> {
crate::trace_dispatch!(
"hyperlattice_vector",
"constructor",
"shared-scale-vec-from-components"
);
let exact = crate::kernels::exact_real_set_facts(components.iter());
if !exact.has_shared_denominator_schedule() {
return None;
}
let refs = from_fn(|index| &components[index]);
let facts = vector_shared_scale_facts(exact, refs);
Some(Self {
components,
exact,
facts,
})
}
pub fn components(&self) -> &[Real; N] {
&self.components
}
pub fn into_components(self) -> [Real; N] {
self.components
}
pub fn as_view(&self) -> VectorSharedScaleView<'_, N> {
VectorSharedScaleView {
components: from_fn(|index| &self.components[index]),
exact: self.facts.exact,
known_zero_mask: self.facts.known_zero_mask,
known_nonzero_mask: self.facts.known_nonzero_mask,
unknown_zero_mask: self.facts.unknown_zero_mask,
}
}
pub const fn len(&self) -> usize {
N
}
pub const fn is_empty(&self) -> bool {
N == 0
}
pub fn facts(&self) -> VectorSharedScaleFacts<N> {
self.facts
}
pub fn known_zero_count(&self) -> u32 {
self.facts.known_zero_count()
}
pub fn known_nonzero_count(&self) -> u32 {
self.facts.known_nonzero_count()
}
pub fn unknown_zero_count(&self) -> u32 {
self.facts.unknown_zero_count()
}
pub fn dot(&self, rhs: &Self) -> Real {
self.as_view().dot(rhs.as_view())
}
pub fn squared_norm(&self) -> Real {
self.as_view().squared_norm()
}
}
impl SharedScaleVec<2> {
pub fn wedge(&self, rhs: &Self) -> Real {
self.as_view().wedge(rhs.as_view())
}
}
impl SharedScaleVec<3> {
pub fn cross(&self, rhs: &Self) -> Vector3 {
self.as_view().cross(rhs.as_view())
}
}
#[inline]
fn vector_mask<const N: usize>() -> u128 {
debug_assert!(N <= u128::BITS as usize);
if N == u128::BITS as usize {
u128::MAX
} else {
(1_u128 << N) - 1
}
}
#[inline]
fn vector_zero_status_masks<const N: usize>(components: [&Real; N]) -> (u128, u128, u128) {
let mut known_zero_mask = 0_u128;
let mut known_nonzero_mask = 0_u128;
let mut unknown_zero_mask = 0_u128;
for (index, component) in components.into_iter().enumerate() {
let bit = 1_u128 << index;
match component.zero_status() {
ZeroStatus::Zero => known_zero_mask |= bit,
ZeroStatus::NonZero => known_nonzero_mask |= bit,
ZeroStatus::Unknown => unknown_zero_mask |= bit,
}
}
(known_zero_mask, known_nonzero_mask, unknown_zero_mask)
}
#[inline]
fn vector_shared_scale_facts<const N: usize>(
exact: ExactRealSetFacts,
components: [&Real; N],
) -> VectorSharedScaleFacts<N> {
let (known_zero_mask, known_nonzero_mask, unknown_zero_mask) =
vector_zero_status_masks(components);
VectorSharedScaleFacts {
exact,
known_zero_mask,
known_nonzero_mask,
unknown_zero_mask,
}
}
#[inline]
fn vector_one_mask<const N: usize>(components: [&Real; N]) -> u128 {
let mut mask = 0_u128;
for (index, component) in components.into_iter().enumerate() {
if component.definitely_one() {
mask |= 1_u128 << index;
}
}
mask
}
#[inline]
fn single_bit_index(mask: u128) -> Option<usize> {
if mask.count_ones() == 1 {
Some(mask.trailing_zeros() as usize)
} else {
None
}
}
#[inline]
fn signed_axis2_from_components(values: &[Real; 2]) -> Option<SignedAxis2> {
match (
values[0].zero_one_or_minus_one(),
values[1].zero_one_or_minus_one(),
) {
(RealZeroOneMinusOneStatus::One, RealZeroOneMinusOneStatus::Zero) => {
Some(SignedAxis2::PosX)
}
(RealZeroOneMinusOneStatus::MinusOne, RealZeroOneMinusOneStatus::Zero) => {
Some(SignedAxis2::NegX)
}
(RealZeroOneMinusOneStatus::Zero, RealZeroOneMinusOneStatus::One) => {
Some(SignedAxis2::PosY)
}
(RealZeroOneMinusOneStatus::Zero, RealZeroOneMinusOneStatus::MinusOne) => {
Some(SignedAxis2::NegY)
}
_ => None,
}
}
fn vector_symbolic_dependency_mask<const N: usize>(
values: [&Real; N],
) -> RealSymbolicDependencyMask {
values
.into_iter()
.fold(RealSymbolicDependencyMask::NONE, |mask, value| {
mask.union(value.detailed_facts().symbolic.dependencies)
})
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct Vector2Facts {
pub component_zero: [ZeroStatus; 2],
pub exact: ExactRealSetFacts,
pub symbolic_dependencies: RealSymbolicDependencyMask,
pub known_axis: Option<Axis2>,
pub known_signed_axis: Option<SignedAxis2>,
pub known_zero: bool,
}
impl Vector2Facts {
pub fn component_zero(self, axis: Axis2) -> ZeroStatus {
self.component_zero[axis.index()]
}
pub fn known_zero_mask(self) -> u8 {
let mut mask = 0;
if matches!(self.component_zero[0], ZeroStatus::Zero) {
mask |= Axis2::X.bit();
}
if matches!(self.component_zero[1], ZeroStatus::Zero) {
mask |= Axis2::Y.bit();
}
mask
}
pub fn known_nonzero_mask(self) -> u8 {
let mut mask = 0;
if matches!(self.component_zero[0], ZeroStatus::NonZero) {
mask |= Axis2::X.bit();
}
if matches!(self.component_zero[1], ZeroStatus::NonZero) {
mask |= Axis2::Y.bit();
}
mask
}
pub fn unknown_zero_mask(self) -> u8 {
let mut mask = 0;
if matches!(self.component_zero[0], ZeroStatus::Unknown) {
mask |= Axis2::X.bit();
}
if matches!(self.component_zero[1], ZeroStatus::Unknown) {
mask |= Axis2::Y.bit();
}
mask
}
pub fn has_unknown_zero(self) -> bool {
self.unknown_zero_mask() != 0
}
pub fn known_zero_count(self) -> u32 {
self.known_zero_mask().count_ones()
}
pub fn known_nonzero_count(self) -> u32 {
self.known_nonzero_mask().count_ones()
}
pub fn unknown_zero_count(self) -> u32 {
self.unknown_zero_mask().count_ones()
}
pub fn squared_norm_zero_status(self) -> ZeroStatus {
squared_norm_zero_status_from_counts(self.known_nonzero_count(), self.unknown_zero_count())
}
pub fn is_signed_unit_axis(self) -> bool {
self.known_signed_axis.is_some()
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct Vector3Facts {
pub component_zero: [ZeroStatus; 3],
pub exact: ExactRealSetFacts,
pub symbolic_dependencies: RealSymbolicDependencyMask,
pub known_zero_mask: u8,
pub known_nonzero_mask: u8,
pub unknown_zero_mask: u8,
pub one_mask: u8,
pub known_axis_index: Option<usize>,
pub known_zero: bool,
}
impl Vector3Facts {
pub fn known_zero_count(self) -> u32 {
self.known_zero_mask.count_ones()
}
pub fn known_nonzero_count(self) -> u32 {
self.known_nonzero_mask.count_ones()
}
pub fn unknown_zero_count(self) -> u32 {
self.unknown_zero_mask.count_ones()
}
pub fn squared_norm_zero_status(self) -> ZeroStatus {
squared_norm_zero_status_from_counts(self.known_nonzero_count(), self.unknown_zero_count())
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct Vector4Facts {
pub component_zero: [ZeroStatus; 4],
pub exact: ExactRealSetFacts,
pub symbolic_dependencies: RealSymbolicDependencyMask,
pub known_zero_mask: u8,
pub known_nonzero_mask: u8,
pub unknown_zero_mask: u8,
pub one_mask: u8,
pub known_axis_index: Option<usize>,
pub known_zero: bool,
pub homogeneous: Vector4HomogeneousKind,
}
impl Vector4Facts {
pub fn known_zero_count(self) -> u32 {
self.known_zero_mask.count_ones()
}
pub fn known_nonzero_count(self) -> u32 {
self.known_nonzero_mask.count_ones()
}
pub fn unknown_zero_count(self) -> u32 {
self.unknown_zero_mask.count_ones()
}
pub fn squared_norm_zero_status(self) -> ZeroStatus {
squared_norm_zero_status_from_counts(self.known_nonzero_count(), self.unknown_zero_count())
}
}
#[derive(Clone, Debug, PartialEq)]
pub struct Vector2(
pub [Real; 2],
);
#[derive(Clone, Debug, PartialEq)]
pub struct Vector3(
pub [Real; 3],
);
#[derive(Clone, Debug, PartialEq)]
pub struct Vector4(
pub [Real; 4],
);
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum Vector4HomogeneousKind {
Direction,
Point,
Unknown,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub(crate) struct Vector4GeometricFacts {
pub(crate) homogeneous: Vector4HomogeneousKind,
}
#[inline]
fn vector4_geometric_facts(values: &[Real; 4]) -> Vector4GeometricFacts {
let homogeneous = match values[3].zero_one_or_minus_one() {
RealZeroOneMinusOneStatus::Zero => Vector4HomogeneousKind::Direction,
RealZeroOneMinusOneStatus::One => Vector4HomogeneousKind::Point,
RealZeroOneMinusOneStatus::MinusOne | RealZeroOneMinusOneStatus::NeitherOrUnknown => {
Vector4HomogeneousKind::Unknown
}
};
Vector4GeometricFacts { homogeneous }
}
#[inline(always)]
fn squared_norm_zero_status_from_counts(known_nonzero: u32, unknown_zero: u32) -> ZeroStatus {
if known_nonzero > 0 {
ZeroStatus::NonZero
} else if unknown_zero > 0 {
ZeroStatus::Unknown
} else {
ZeroStatus::Zero
}
}
#[inline(always)]
fn require_known_nonzero_status(status: ZeroStatus) -> CheckedBlasResult<()> {
match status {
ZeroStatus::Zero => {
crate::trace_dispatch!("hyperlattice_vector", "norm-facts", "checked-zero-rejected");
Err(Problem::DivideByZero)
}
ZeroStatus::NonZero => {
crate::trace_dispatch!("hyperlattice_vector", "norm-facts", "checked-nonzero");
Ok(())
}
ZeroStatus::Unknown => {
crate::trace_dispatch!(
"hyperlattice_vector",
"norm-facts",
"checked-unknown-rejected"
);
Err(Problem::UnknownZero)
}
}
}
trait VectorSelfDot {
fn self_dot(values: &Self) -> Real;
}
impl VectorSelfDot for [Real; 2] {
#[inline]
fn self_dot(values: &Self) -> Real {
Real::signed_product_sum2(
[true, true],
[[&values[0], &values[0]], [&values[1], &values[1]]],
)
}
}
impl VectorSelfDot for [Real; 3] {
#[inline]
fn self_dot(values: &Self) -> Real {
Real::dot3_same([&values[0], &values[1], &values[2]])
}
}
impl VectorSelfDot for [Real; 4] {
#[inline]
fn self_dot(values: &Self) -> Real {
Real::dot4_same([&values[0], &values[1], &values[2], &values[3]])
}
}
fn map_array2<const N: usize, F>(left: [Real; N], right: [Real; N], mut op: F) -> [Real; N]
where
F: FnMut(Real, Real) -> Real,
{
let mut right = right.into_iter();
left.map(|lhs| op(lhs, right.next().expect("arrays have equal length")))
}
fn map_array_ref<const N: usize, F>(left: [Real; N], right: &[Real; N], mut op: F) -> [Real; N]
where
F: FnMut(Real, &Real) -> Real,
{
let mut right = right.iter();
left.map(|lhs| op(lhs, right.next().expect("arrays have equal length")))
}
macro_rules! impl_vector {
($name:ident, $n:expr) => {
impl $name {
pub fn new(values: [Real; $n]) -> Self {
crate::trace_dispatch!("hyperlattice_vector", "constructor", "new");
Self(values)
}
pub fn try_from_f64_array(values: [f64; $n]) -> BlasResult<Self> {
crate::trace_dispatch!("hyperlattice_vector", "constructor", "from-f64-array");
Ok(Self(
values
.map(Real::try_from)
.into_iter()
.collect::<Result<Vec<_>, _>>()?
.try_into()
.expect("mapped array length is fixed"),
))
}
pub fn try_from_f32_array(values: [f32; $n]) -> BlasResult<Self> {
crate::trace_dispatch!("hyperlattice_vector", "constructor", "from-f32-array");
Ok(Self(
values
.map(Real::try_from)
.into_iter()
.collect::<Result<Vec<_>, _>>()?
.try_into()
.expect("mapped array length is fixed"),
))
}
pub fn to_f64_array_lossy(&self) -> Option<[f64; $n]> {
crate::trace_dispatch!("hyperlattice_vector", "export", "to-f64-array-lossy");
let mut out = [0.0_f64; $n];
for i in 0..$n {
out[i] = self.0[i].to_f64_lossy().filter(|value| value.is_finite())?;
}
Some(out)
}
pub fn to_f32_array_lossy(&self) -> Option<[f32; $n]> {
crate::trace_dispatch!("hyperlattice_vector", "export", "to-f32-array-lossy");
let mut out = [0.0_f32; $n];
for i in 0..$n {
out[i] = self.0[i].to_f32_lossy().filter(|value| value.is_finite())?;
}
Some(out)
}
pub fn zero() -> Self {
crate::trace_dispatch!("hyperlattice_vector", "constructor", "zero");
Self(from_fn(|_| Real::zero()))
}
pub fn zeros() -> Self {
Self::zero()
}
pub fn magnitude(&self) -> BlasResult<Real> {
crate::trace_dispatch!("hyperlattice_vector", "method", "magnitude");
self.magnitude_squared_fast().sqrt()
}
pub fn norm(&self) -> Real {
self.magnitude()
.expect("hyperlattice vector norm should be defined for exact coordinates")
}
pub fn norm_squared(&self) -> Real {
self.magnitude_squared_fast()
}
pub fn magnitude_with_abort(&self, signal: &AbortSignal) -> BlasResult<Real> {
crate::trace_dispatch!("hyperlattice_vector", "method", "magnitude-with-abort");
with_abort(self.dot_with_abort(self, signal), signal).sqrt()
}
#[inline]
fn magnitude_squared_fast(&self) -> Real {
<[Real; $n] as VectorSelfDot>::self_dot(&self.0)
}
pub fn normalize(&self) -> BlasResult<Self> {
crate::trace_dispatch!("hyperlattice_vector", "method", "normalize");
let mag = self.magnitude()?;
let inv_mag = mag.inverse()?;
Ok(Self(from_fn(|i| &self.0[i] * &inv_mag)))
}
pub fn normalize_checked(&self) -> CheckedBlasResult<Self> {
crate::trace_dispatch!("hyperlattice_vector", "method", "normalize-checked");
let norm_status = self.structural_facts().squared_norm_zero_status();
require_known_nonzero_status(norm_status)?;
let mag_squared = self.magnitude_squared_fast();
let mag = mag_squared.sqrt()?;
let inv_mag = mag.inverse()?;
Ok(Self(from_fn(|i| &self.0[i] * &inv_mag)))
}
pub fn normalize_checked_with_abort(
&self,
signal: &AbortSignal,
) -> CheckedBlasResult<Self> {
crate::trace_dispatch!(
"hyperlattice_vector",
"method",
"normalize-checked-with-abort"
);
let norm_status = self.structural_facts().squared_norm_zero_status();
require_known_nonzero_status(norm_status)?;
let mag_squared = with_abort(self.dot_with_abort(self, signal), signal);
let mag = mag_squared.sqrt()?;
let inv_mag = mag.inverse()?;
Ok(Self(from_fn(|i| &self.0[i] * &inv_mag)))
}
pub fn lerp(&self, to: &Self, t: &Real) -> Self {
crate::trace_dispatch!("hyperlattice_vector", "method", "lerp");
self.clone() + ((to - self) * t)
}
pub fn step(&self, direction: &Self, distance: &Real) -> Self {
crate::trace_dispatch!("hyperlattice_vector", "method", "step");
self.clone() + direction.clone() * distance
}
pub fn mean(values: &[Self]) -> Option<Self> {
crate::trace_dispatch!("hyperlattice_vector", "method", "mean");
if values.is_empty() {
return None;
}
let sum = values
.iter()
.cloned()
.fold(Self::zero(), |acc, value| acc + value);
let count = Real::from(u64::try_from(values.len()).ok()?);
(sum / count).ok()
}
pub fn weighted_sum(values: &[Self], weights: &[Real]) -> Option<Self> {
crate::trace_dispatch!("hyperlattice_vector", "method", "weighted-sum");
if values.len() != weights.len() || values.is_empty() {
return None;
}
Some(
values
.iter()
.cloned()
.zip(weights.iter())
.fold(Self::zero(), |acc, (value, weight)| acc + value * weight),
)
}
pub fn div_scalar_checked(self, rhs: Real) -> CheckedBlasResult<Self> {
crate::trace_dispatch!("hyperlattice_vector", "method", "div-scalar-checked");
require_known_nonzero(&rhs)?;
let inv_rhs = rhs.inverse()?;
if true && $n == 3 {
Ok(Self(self.0.map(|value| &value * &inv_rhs)))
} else if true {
Ok(Self(self.0.map(|value| value.mul_cached(&inv_rhs))))
} else {
let mut values = self.0;
for value in &mut values {
*value = value.clone().mul_cached(&inv_rhs);
}
Ok(Self(values))
}
}
pub fn div_scalar_checked_with_abort(
self,
rhs: Real,
signal: &AbortSignal,
) -> CheckedBlasResult<Self> {
crate::trace_dispatch!(
"hyperlattice_vector",
"method",
"div-scalar-checked-with-abort"
);
let rhs = with_abort(rhs, signal);
require_known_nonzero(&rhs)?;
let inv_rhs = rhs.inverse()?;
if true && $n == 3 {
Ok(Self(self.0.map(|value| &value * &inv_rhs)))
} else if true {
Ok(Self(self.0.map(|value| value.mul_cached(&inv_rhs))))
} else {
let mut values = self.0;
for value in &mut values {
*value = value.clone().mul_cached(&inv_rhs);
}
Ok(Self(values))
}
}
}
impl Index<usize> for $name {
type Output = Real;
fn index(&self, index: usize) -> &Self::Output {
&self.0[index]
}
}
impl IndexMut<usize> for $name {
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
&mut self.0[index]
}
}
impl fmt::Display for $name {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("[")?;
for i in 0..$n {
if i > 0 {
f.write_str(", ")?;
}
if f.alternate() {
write!(f, "{:#}", self.0[i])?;
} else {
write!(f, "{}", self.0[i])?;
}
}
f.write_str("]")
}
}
impl Add for $name {
type Output = Self;
fn add(self, rhs: Self) -> Self::Output {
crate::trace_dispatch!("hyperlattice_vector", "op", "add-owned-owned");
if true {
Self(map_array2(self.0, rhs.0, |lhs, rhs| lhs + rhs))
} else {
Self(from_fn(|i| self.0[i].clone() + rhs.0[i].clone()))
}
}
}
impl Add<&$name> for $name {
type Output = Self;
fn add(self, rhs: &$name) -> Self::Output {
crate::trace_dispatch!("hyperlattice_vector", "op", "add-owned-ref");
Self(map_array_ref(self.0, &rhs.0, Real::add_cached))
}
}
impl Add<$name> for &$name {
type Output = $name;
fn add(self, rhs: $name) -> Self::Output {
crate::trace_dispatch!("hyperlattice_vector", "op", "add-ref-owned");
let mut left = self.0.iter();
$name(
rhs.0
.map(|rhs| left.next().expect("vectors have equal length") + rhs),
)
}
}
impl Add<&$name> for &$name {
type Output = $name;
fn add(self, rhs: &$name) -> Self::Output {
crate::trace_dispatch!("hyperlattice_vector", "op", "add-ref-ref");
$name(from_fn(|i| &self.0[i] + &rhs.0[i]))
}
}
impl Add<Real> for $name {
type Output = Self;
fn add(self, rhs: Real) -> Self::Output {
crate::trace_dispatch!("hyperlattice_vector", "op", "add-scalar-owned");
let rhs = &rhs;
if true {
Self(self.0.map(|value| value.add_cached(rhs)))
} else {
let mut values = self.0;
for value in &mut values {
*value = value.clone().add_cached(rhs);
}
Self(values)
}
}
}
impl Add<&Real> for $name {
type Output = Self;
fn add(self, rhs: &Real) -> Self::Output {
crate::trace_dispatch!("hyperlattice_vector", "op", "add-scalar-ref");
Self(self.0.map(|value| value.add_cached(rhs)))
}
}
impl Sub for $name {
type Output = Self;
fn sub(self, rhs: Self) -> Self::Output {
crate::trace_dispatch!("hyperlattice_vector", "op", "sub-owned-owned");
if true {
Self(map_array2(self.0, rhs.0, |lhs, rhs| lhs - rhs))
} else {
Self(from_fn(|i| self.0[i].clone() - rhs.0[i].clone()))
}
}
}
impl Sub<&$name> for $name {
type Output = Self;
fn sub(self, rhs: &$name) -> Self::Output {
crate::trace_dispatch!("hyperlattice_vector", "op", "sub-owned-ref");
Self(map_array_ref(self.0, &rhs.0, Real::sub_cached))
}
}
impl Sub<$name> for &$name {
type Output = $name;
fn sub(self, rhs: $name) -> Self::Output {
crate::trace_dispatch!("hyperlattice_vector", "op", "sub-ref-owned");
let mut left = self.0.iter();
$name(
rhs.0
.map(|rhs| left.next().expect("vectors have equal length") - rhs),
)
}
}
impl Sub<&$name> for &$name {
type Output = $name;
fn sub(self, rhs: &$name) -> Self::Output {
crate::trace_dispatch!("hyperlattice_vector", "op", "sub-ref-ref");
$name(from_fn(|i| &self.0[i] - &rhs.0[i]))
}
}
impl Sub<Real> for $name {
type Output = Self;
fn sub(self, rhs: Real) -> Self::Output {
crate::trace_dispatch!("hyperlattice_vector", "op", "sub-scalar-owned");
let rhs = -rhs;
let rhs = &rhs;
if true {
Self(self.0.map(|value| value.add_cached(rhs)))
} else {
let mut values = self.0;
for value in &mut values {
*value = value.clone().add_cached(rhs);
}
Self(values)
}
}
}
impl Sub<&Real> for $name {
type Output = Self;
fn sub(self, rhs: &Real) -> Self::Output {
crate::trace_dispatch!("hyperlattice_vector", "op", "sub-scalar-ref");
let rhs = -rhs.clone();
Self(self.0.map(|value| value.add_cached(&rhs)))
}
}
impl Neg for $name {
type Output = Self;
fn neg(self) -> Self::Output {
crate::trace_dispatch!("hyperlattice_vector", "op", "neg-owned");
if true {
Self(self.0.map(|value| -value))
} else {
Self(from_fn(|i| -self.0[i].clone()))
}
}
}
impl Neg for &$name {
type Output = $name;
fn neg(self) -> Self::Output {
crate::trace_dispatch!("hyperlattice_vector", "op", "neg-ref");
$name(from_fn(|i| -self.0[i].clone()))
}
}
impl Mul<Real> for $name {
type Output = Self;
fn mul(self, rhs: Real) -> Self::Output {
crate::trace_dispatch!("hyperlattice_vector", "op", "mul-scalar-owned");
let rhs = &rhs;
if true {
Self(self.0.map(|value| value.mul_cached(rhs)))
} else {
let mut values = self.0;
for value in &mut values {
*value = value.clone().mul_cached(rhs);
}
Self(values)
}
}
}
impl Mul<&Real> for $name {
type Output = Self;
fn mul(self, rhs: &Real) -> Self::Output {
crate::trace_dispatch!("hyperlattice_vector", "op", "mul-scalar-ref");
Self(self.0.map(|value| value.mul_cached(rhs)))
}
}
impl Div<Real> for $name {
type Output = BlasResult<Self>;
fn div(self, rhs: Real) -> Self::Output {
crate::trace_dispatch!("hyperlattice_vector", "op", "div-scalar-owned");
reject_definite_zero(&rhs)?;
let inv_rhs = rhs.inverse()?;
if true && $n == 3 {
Ok(Self(self.0.map(|value| &value * &inv_rhs)))
} else if true {
Ok(Self(self.0.map(|value| value.mul_cached(&inv_rhs))))
} else {
let mut values = self.0;
for value in &mut values {
*value = value.clone().mul_cached(&inv_rhs);
}
Ok(Self(values))
}
}
}
impl Div<&Real> for $name {
type Output = BlasResult<Self>;
fn div(self, rhs: &Real) -> Self::Output {
crate::trace_dispatch!("hyperlattice_vector", "op", "div-scalar-ref");
reject_definite_zero(rhs)?;
let inv_rhs = rhs.inverse_ref()?;
if true && $n == 3 {
Ok(Self(self.0.map(|value| &value * &inv_rhs)))
} else if true {
Ok(Self(self.0.map(|value| value.mul_cached(&inv_rhs))))
} else {
let mut values = self.0;
for value in &mut values {
*value = value.clone().mul_cached(&inv_rhs);
}
Ok(Self(values))
}
}
}
};
}
impl Vector2 {
pub fn from_xy(x: Real, y: Real) -> Self {
Self::new([x, y])
}
pub fn x() -> Self {
Self::new([Real::one(), Real::zero()])
}
pub fn y() -> Self {
Self::new([Real::zero(), Real::one()])
}
}
impl Vector3 {
pub fn from_xyz(x: Real, y: Real, z: Real) -> Self {
Self::new([x, y, z])
}
pub fn x() -> Self {
Self::new([Real::one(), Real::zero(), Real::zero()])
}
pub fn y() -> Self {
Self::new([Real::zero(), Real::one(), Real::zero()])
}
pub fn z() -> Self {
Self::new([Real::zero(), Real::zero(), Real::one()])
}
}
impl Vector4 {
pub fn from_xyzw(x: Real, y: Real, z: Real, w: Real) -> Self {
Self::new([x, y, z, w])
}
}
impl_vector!(Vector2, 2);
impl_vector!(Vector3, 3);
impl_vector!(Vector4, 4);
impl Vector4 {
#[inline]
pub(crate) fn geometric_facts(&self) -> Vector4GeometricFacts {
vector4_geometric_facts(&self.0)
}
}
impl Vector2 {
pub fn into_shared_scale(self) -> Option<SharedScaleVec<2>> {
SharedScaleVec::from_components(self.0)
}
pub fn shared_scale_view(&self) -> Option<VectorSharedScaleView<'_, 2>> {
crate::trace_dispatch!("hyperlattice_vector", "query", "vector2-shared-scale-view");
VectorSharedScaleView::from_components([&self.0[0], &self.0[1]])
}
pub fn structural_facts(&self) -> Vector2Facts {
crate::trace_dispatch!("hyperlattice_vector", "query", "vector2-structural-facts");
let component_zero = [self.0[0].zero_status(), self.0[1].zero_status()];
let known_zero = matches!(component_zero, [ZeroStatus::Zero, ZeroStatus::Zero]);
let known_axis = match component_zero {
[ZeroStatus::NonZero, ZeroStatus::Zero] => Some(Axis2::X),
[ZeroStatus::Zero, ZeroStatus::NonZero] => Some(Axis2::Y),
_ => None,
};
Vector2Facts {
component_zero,
exact: crate::kernels::exact_real_set_facts(self.0.iter()),
symbolic_dependencies: vector_symbolic_dependency_mask([&self.0[0], &self.0[1]]),
known_axis,
known_signed_axis: signed_axis2_from_components(&self.0),
known_zero,
}
}
pub fn dot(&self, rhs: &Self) -> Real {
crate::trace_dispatch!("hyperlattice_vector", "method", "dot2");
crate::dot2([&self.0[0], &self.0[1]], [&rhs.0[0], &rhs.0[1]])
}
pub fn dot_with_abort(&self, rhs: &Self, signal: &AbortSignal) -> Real {
crate::trace_dispatch!("hyperlattice_vector", "method", "dot2-with-abort");
if !signal.load(Ordering::Relaxed) {
crate::trace_dispatch!("hyperlattice_vector", "abort", "dot2-inactive-signal");
return self.dot(rhs);
}
let has0 = !self.0[0].definitely_zero() && !rhs.0[0].definitely_zero();
let has1 = !self.0[1].definitely_zero() && !rhs.0[1].definitely_zero();
if !has0 && !has1 {
crate::trace_dispatch!("hyperlattice_vector", "abort", "dot2-sparse-all-zero");
return Real::zero();
}
let product = |lhs: &Real, rhs: &Real, signal: &AbortSignal| {
clone_with_abort(lhs, signal) * clone_with_abort(rhs, signal)
};
if has0 && has1 {
crate::trace_dispatch!("hyperlattice_vector", "abort", "dot2-sparse-two-nonzero");
let lhs0 = clone_with_abort(&self.0[0], signal);
let rhs0 = clone_with_abort(&rhs.0[0], signal);
let lhs1 = clone_with_abort(&self.0[1], signal);
let rhs1 = clone_with_abort(&rhs.0[1], signal);
return Real::active_signed_product_sum2(
[true, true],
[[&lhs0, &rhs0], [&lhs1, &rhs1]],
);
}
crate::trace_dispatch!("hyperlattice_vector", "abort", "dot2-sparse-single");
if has0 {
product(&self.0[0], &rhs.0[0], signal)
} else {
product(&self.0[1], &rhs.0[1], signal)
}
}
pub fn wedge(&self, rhs: &Self) -> Real {
crate::trace_dispatch!("hyperlattice_vector", "method", "wedge2");
crate::wedge2([&self.0[0], &self.0[1]], [&rhs.0[0], &rhs.0[1]])
}
pub fn squared_distance(&self, rhs: &Self) -> Real {
crate::trace_dispatch!("hyperlattice_vector", "method", "squared-distance2");
crate::squared_distance2([&self.0[0], &self.0[1]], [&rhs.0[0], &rhs.0[1]])
}
}
impl Vector3 {
pub fn into_shared_scale(self) -> Option<SharedScaleVec<3>> {
SharedScaleVec::from_components(self.0)
}
pub fn shared_scale_view(&self) -> Option<VectorSharedScaleView<'_, 3>> {
crate::trace_dispatch!("hyperlattice_vector", "query", "vector3-shared-scale-view");
VectorSharedScaleView::from_components([&self.0[0], &self.0[1], &self.0[2]])
}
pub fn structural_facts(&self) -> Vector3Facts {
crate::trace_dispatch!("hyperlattice_vector", "query", "vector3-structural-facts");
let component_zero = [
self.0[0].zero_status(),
self.0[1].zero_status(),
self.0[2].zero_status(),
];
let (known_zero_mask, known_nonzero_mask, unknown_zero_mask) =
vector_zero_status_masks([&self.0[0], &self.0[1], &self.0[2]]);
Vector3Facts {
component_zero,
exact: crate::kernels::exact_real_set_facts(self.0.iter()),
symbolic_dependencies: vector_symbolic_dependency_mask([
&self.0[0], &self.0[1], &self.0[2],
]),
known_zero_mask: known_zero_mask as u8,
known_nonzero_mask: known_nonzero_mask as u8,
unknown_zero_mask: unknown_zero_mask as u8,
one_mask: vector_one_mask([&self.0[0], &self.0[1], &self.0[2]]) as u8,
known_axis_index: if known_zero_mask.count_ones() == 2
&& known_nonzero_mask.count_ones() == 1
&& unknown_zero_mask == 0
{
single_bit_index(known_nonzero_mask)
} else {
None
},
known_zero: known_zero_mask == vector_mask::<3>(),
}
}
pub fn exact_facts(&self) -> ExactRealSetFacts {
crate::trace_dispatch!("hyperlattice_vector", "query", "vector3-exact-facts");
crate::kernels::exact_real_set_facts(self.0.iter())
}
pub fn cross(&self, rhs: &Self) -> Self {
crate::trace_dispatch!("hyperlattice_vector", "method", "cross3");
Self::new([
Real::signed_product_sum2(
[true, false],
[[&self.0[1], &rhs.0[2]], [&self.0[2], &rhs.0[1]]],
),
Real::signed_product_sum2(
[true, false],
[[&self.0[2], &rhs.0[0]], [&self.0[0], &rhs.0[2]]],
),
Real::signed_product_sum2(
[true, false],
[[&self.0[0], &rhs.0[1]], [&self.0[1], &rhs.0[0]]],
),
])
}
pub fn unit_cross_checked(&self, rhs: &Self) -> CheckedBlasResult<Self> {
crate::trace_dispatch!("hyperlattice_vector", "method", "unit-cross-checked");
self.cross(rhs).normalize_checked()
}
pub fn orthonormal_basis_checked(&self) -> CheckedBlasResult<(Self, Self)> {
crate::trace_dispatch!("hyperlattice_vector", "method", "orthonormal-basis-checked");
let axis = self.normalize_checked()?;
for seed in unit_axes3() {
if let Ok(first) = seed.cross(&axis).normalize_checked() {
let second = axis.cross(&first).normalize_checked()?;
return Ok((first, second));
}
}
Err(Problem::UnknownZero)
}
pub fn angle_to(&self, rhs: &Self) -> CheckedBlasResult<Real> {
crate::trace_dispatch!("hyperlattice_vector", "method", "angle-to");
let lhs = self.normalize_checked()?;
let rhs = rhs.normalize_checked()?;
crate::acos(lhs.dot(&rhs))
}
pub fn dot(&self, rhs: &Self) -> Real {
crate::trace_dispatch!("hyperlattice_vector", "method", "dot3");
Real::dot3(
[&self.0[0], &self.0[1], &self.0[2]],
[&rhs.0[0], &rhs.0[1], &rhs.0[2]],
)
}
pub fn squared_distance(&self, rhs: &Self) -> Real {
crate::trace_dispatch!("hyperlattice_vector", "method", "squared-distance3");
let delta = self - rhs;
delta.dot(&delta)
}
pub fn dot_with_abort(&self, rhs: &Self, signal: &AbortSignal) -> Real {
crate::trace_dispatch!("hyperlattice_vector", "method", "dot3-with-abort");
if !signal.load(Ordering::Relaxed) {
crate::trace_dispatch!("hyperlattice_vector", "abort", "dot3-inactive-signal");
return self.dot(rhs);
}
let has0 = !self.0[0].definitely_zero() && !rhs.0[0].definitely_zero();
let has1 = !self.0[1].definitely_zero() && !rhs.0[1].definitely_zero();
let has2 = !self.0[2].definitely_zero() && !rhs.0[2].definitely_zero();
if !has0 && !has1 && !has2 {
crate::trace_dispatch!("hyperlattice_vector", "abort", "dot3-sparse-all-zero");
return Real::zero();
}
let product = |lhs: &Real, rhs: &Real, signal: &AbortSignal| {
clone_with_abort(lhs, signal) * clone_with_abort(rhs, signal)
};
let product_sum2 =
|lhs0: &Real, rhs0: &Real, lhs1: &Real, rhs1: &Real, signal: &AbortSignal| {
let lhs0 = clone_with_abort(lhs0, signal);
let rhs0 = clone_with_abort(rhs0, signal);
let lhs1 = clone_with_abort(lhs1, signal);
let rhs1 = clone_with_abort(rhs1, signal);
Real::active_signed_product_sum2([true, true], [[&lhs0, &rhs0], [&lhs1, &rhs1]])
};
let product_sum3 = |lhs0: &Real,
rhs0: &Real,
lhs1: &Real,
rhs1: &Real,
lhs2: &Real,
rhs2: &Real,
signal: &AbortSignal| {
let lhs0 = clone_with_abort(lhs0, signal);
let rhs0 = clone_with_abort(rhs0, signal);
let lhs1 = clone_with_abort(lhs1, signal);
let rhs1 = clone_with_abort(rhs1, signal);
let lhs2 = clone_with_abort(lhs2, signal);
let rhs2 = clone_with_abort(rhs2, signal);
Real::active_signed_product_sum2(
[true, true, true],
[[&lhs0, &rhs0], [&lhs1, &rhs1], [&lhs2, &rhs2]],
)
};
if has0 as u8 + has1 as u8 + has2 as u8 == 1 {
crate::trace_dispatch!("hyperlattice_vector", "abort", "dot3-sparse-single");
return if has0 {
product(&self.0[0], &rhs.0[0], signal)
} else if has1 {
product(&self.0[1], &rhs.0[1], signal)
} else {
product(&self.0[2], &rhs.0[2], signal)
};
}
if has0 as u8 + has1 as u8 + has2 as u8 == 2 {
crate::trace_dispatch!("hyperlattice_vector", "abort", "dot3-sparse-two");
return if has0 && has1 {
product_sum2(&self.0[0], &rhs.0[0], &self.0[1], &rhs.0[1], signal)
} else if has0 && has2 {
product_sum2(&self.0[0], &rhs.0[0], &self.0[2], &rhs.0[2], signal)
} else {
product_sum2(&self.0[1], &rhs.0[1], &self.0[2], &rhs.0[2], signal)
};
}
crate::trace_dispatch!("hyperlattice_vector", "abort", "dot3-sparse-three-nonzero");
product_sum3(
&self.0[0], &rhs.0[0], &self.0[1], &rhs.0[1], &self.0[2], &rhs.0[2], signal,
)
}
}
fn unit_axes3() -> [Vector3; 3] {
[
Vector3::new([Real::one(), Real::zero(), Real::zero()]),
Vector3::new([Real::zero(), Real::one(), Real::zero()]),
Vector3::new([Real::zero(), Real::zero(), Real::one()]),
]
}
impl Vector4 {
pub fn into_shared_scale(self) -> Option<SharedScaleVec<4>> {
SharedScaleVec::from_components(self.0)
}
pub fn shared_scale_view(&self) -> Option<VectorSharedScaleView<'_, 4>> {
crate::trace_dispatch!("hyperlattice_vector", "query", "vector4-shared-scale-view");
VectorSharedScaleView::from_components([&self.0[0], &self.0[1], &self.0[2], &self.0[3]])
}
pub fn structural_facts(&self) -> Vector4Facts {
crate::trace_dispatch!("hyperlattice_vector", "query", "vector4-structural-facts");
let component_zero = [
self.0[0].zero_status(),
self.0[1].zero_status(),
self.0[2].zero_status(),
self.0[3].zero_status(),
];
let (known_zero_mask, known_nonzero_mask, unknown_zero_mask) =
vector_zero_status_masks([&self.0[0], &self.0[1], &self.0[2], &self.0[3]]);
Vector4Facts {
component_zero,
exact: crate::kernels::exact_real_set_facts(self.0.iter()),
symbolic_dependencies: vector_symbolic_dependency_mask([
&self.0[0], &self.0[1], &self.0[2], &self.0[3],
]),
known_zero_mask: known_zero_mask as u8,
known_nonzero_mask: known_nonzero_mask as u8,
unknown_zero_mask: unknown_zero_mask as u8,
one_mask: vector_one_mask([&self.0[0], &self.0[1], &self.0[2], &self.0[3]]) as u8,
known_axis_index: if known_zero_mask.count_ones() == 3
&& known_nonzero_mask.count_ones() == 1
&& unknown_zero_mask == 0
{
single_bit_index(known_nonzero_mask)
} else {
None
},
known_zero: known_zero_mask == vector_mask::<4>(),
homogeneous: self.geometric_facts().homogeneous,
}
}
pub fn exact_facts(&self) -> ExactRealSetFacts {
crate::trace_dispatch!("hyperlattice_vector", "query", "vector4-exact-facts");
crate::kernels::exact_real_set_facts(self.0.iter())
}
pub fn dot(&self, rhs: &Self) -> Real {
crate::trace_dispatch!("hyperlattice_vector", "method", "dot4");
Real::dot4(
[&self.0[0], &self.0[1], &self.0[2], &self.0[3]],
[&rhs.0[0], &rhs.0[1], &rhs.0[2], &rhs.0[3]],
)
}
pub fn dot_with_abort(&self, rhs: &Self, signal: &AbortSignal) -> Real {
crate::trace_dispatch!("hyperlattice_vector", "method", "dot4-with-abort");
if !signal.load(Ordering::Relaxed) {
crate::trace_dispatch!("hyperlattice_vector", "abort", "dot4-inactive-signal");
return self.dot(rhs);
}
let has0 = !self.0[0].definitely_zero() && !rhs.0[0].definitely_zero();
let has1 = !self.0[1].definitely_zero() && !rhs.0[1].definitely_zero();
let has2 = !self.0[2].definitely_zero() && !rhs.0[2].definitely_zero();
let has3 = !self.0[3].definitely_zero() && !rhs.0[3].definitely_zero();
let nonzero = has0 as u8 + has1 as u8 + has2 as u8 + has3 as u8;
if nonzero == 0 {
crate::trace_dispatch!("hyperlattice_vector", "abort", "dot4-sparse-all-zero");
return Real::zero();
}
let product = |lhs: &Real, rhs: &Real, signal: &AbortSignal| {
clone_with_abort(lhs, signal) * clone_with_abort(rhs, signal)
};
let product_sum2 =
|lhs0: &Real, rhs0: &Real, lhs1: &Real, rhs1: &Real, signal: &AbortSignal| {
let lhs0 = clone_with_abort(lhs0, signal);
let rhs0 = clone_with_abort(rhs0, signal);
let lhs1 = clone_with_abort(lhs1, signal);
let rhs1 = clone_with_abort(rhs1, signal);
Real::active_signed_product_sum2([true, true], [[&lhs0, &rhs0], [&lhs1, &rhs1]])
};
let product_sum3 = |lhs0: &Real,
rhs0: &Real,
lhs1: &Real,
rhs1: &Real,
lhs2: &Real,
rhs2: &Real,
signal: &AbortSignal| {
let lhs0 = clone_with_abort(lhs0, signal);
let rhs0 = clone_with_abort(rhs0, signal);
let lhs1 = clone_with_abort(lhs1, signal);
let rhs1 = clone_with_abort(rhs1, signal);
let lhs2 = clone_with_abort(lhs2, signal);
let rhs2 = clone_with_abort(rhs2, signal);
Real::active_signed_product_sum2(
[true, true, true],
[[&lhs0, &rhs0], [&lhs1, &rhs1], [&lhs2, &rhs2]],
)
};
let product_sum4 = |lhs0: &Real,
rhs0: &Real,
lhs1: &Real,
rhs1: &Real,
lhs2: &Real,
rhs2: &Real,
lhs3: &Real,
rhs3: &Real,
signal: &AbortSignal| {
let lhs0 = clone_with_abort(lhs0, signal);
let rhs0 = clone_with_abort(rhs0, signal);
let lhs1 = clone_with_abort(lhs1, signal);
let rhs1 = clone_with_abort(rhs1, signal);
let lhs2 = clone_with_abort(lhs2, signal);
let rhs2 = clone_with_abort(rhs2, signal);
let lhs3 = clone_with_abort(lhs3, signal);
let rhs3 = clone_with_abort(rhs3, signal);
Real::active_signed_product_sum2(
[true, true, true, true],
[
[&lhs0, &rhs0],
[&lhs1, &rhs1],
[&lhs2, &rhs2],
[&lhs3, &rhs3],
],
)
};
if nonzero == 1 {
crate::trace_dispatch!("hyperlattice_vector", "abort", "dot4-sparse-single");
return if has0 {
product(&self.0[0], &rhs.0[0], signal)
} else if has1 {
product(&self.0[1], &rhs.0[1], signal)
} else if has2 {
product(&self.0[2], &rhs.0[2], signal)
} else {
product(&self.0[3], &rhs.0[3], signal)
};
}
if nonzero == 2 {
crate::trace_dispatch!("hyperlattice_vector", "abort", "dot4-sparse-two");
return if has0 && has1 {
product_sum2(&self.0[0], &rhs.0[0], &self.0[1], &rhs.0[1], signal)
} else if has0 && has2 {
product_sum2(&self.0[0], &rhs.0[0], &self.0[2], &rhs.0[2], signal)
} else if has0 && has3 {
product_sum2(&self.0[0], &rhs.0[0], &self.0[3], &rhs.0[3], signal)
} else if has1 && has2 {
product_sum2(&self.0[1], &rhs.0[1], &self.0[2], &rhs.0[2], signal)
} else if has1 && has3 {
product_sum2(&self.0[1], &rhs.0[1], &self.0[3], &rhs.0[3], signal)
} else {
product_sum2(&self.0[2], &rhs.0[2], &self.0[3], &rhs.0[3], signal)
};
}
if nonzero == 3 {
crate::trace_dispatch!("hyperlattice_vector", "abort", "dot4-sparse-three");
return if !has0 {
product_sum3(
&self.0[1], &rhs.0[1], &self.0[2], &rhs.0[2], &self.0[3], &rhs.0[3], signal,
)
} else if !has1 {
product_sum3(
&self.0[0], &rhs.0[0], &self.0[2], &rhs.0[2], &self.0[3], &rhs.0[3], signal,
)
} else if !has2 {
product_sum3(
&self.0[0], &rhs.0[0], &self.0[1], &rhs.0[1], &self.0[3], &rhs.0[3], signal,
)
} else {
product_sum3(
&self.0[0], &rhs.0[0], &self.0[1], &rhs.0[1], &self.0[2], &rhs.0[2], signal,
)
};
}
crate::trace_dispatch!("hyperlattice_vector", "abort", "dot4-sparse-four");
product_sum4(
&self.0[0], &rhs.0[0], &self.0[1], &rhs.0[1], &self.0[2], &rhs.0[2], &self.0[3],
&rhs.0[3], signal,
)
}
}