use hyperreal::Real;
pub type ExactRealSetFacts = hyperreal::RealExactSetFacts;
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub(crate) enum ExactRationalKind {
NonRational,
ExactRational,
ExactDyadicRational,
}
pub(crate) fn exact_real_set_facts<'a, I>(values: I) -> ExactRealSetFacts
where
I: IntoIterator<Item = &'a Real>,
{
Real::exact_set_facts(values)
}
pub(crate) trait RealKernelExt: Sized {
fn mul_cached(self, factor: &Self) -> Self;
fn add_cached(self, rhs: &Self) -> Self;
fn sub_cached(self, rhs: &Self) -> Self;
fn exact_rational_kind(&self) -> ExactRationalKind;
fn dot3(left: [&Self; 3], right: [&Self; 3]) -> Self;
fn dot4(left: [&Self; 4], right: [&Self; 4]) -> Self;
fn dot3_same(values: [&Self; 3]) -> Self;
fn dot4_same(values: [&Self; 4]) -> Self;
fn linear_combination3(coefficients: [&Self; 3], values: [&Self; 3]) -> Self;
fn active_linear_combination3(coefficients: [&Self; 3], values: [&Self; 3]) -> Self;
fn linear_combination4(coefficients: [&Self; 4], values: [&Self; 4]) -> Self;
fn signed_product_sum2<const TERMS: usize>(
positive_terms: [bool; TERMS],
terms: [[&Self; 2]; TERMS],
) -> Self;
fn active_signed_product_sum2<const TERMS: usize>(
positive_terms: [bool; TERMS],
terms: [[&Self; 2]; TERMS],
) -> Self;
fn active_signed_product_sum2_known_exact_rational<const TERMS: usize>(
positive_terms: [bool; TERMS],
terms: [[&Self; 2]; TERMS],
) -> Self;
}
impl RealKernelExt for Real {
#[inline]
fn mul_cached(self, factor: &Self) -> Self {
crate::trace_dispatch!("hyperlattice", "real_kernel", "mul-cached");
&self * factor
}
#[inline]
fn add_cached(self, rhs: &Self) -> Self {
crate::trace_dispatch!("hyperlattice", "real_kernel", "add-cached");
&self + rhs
}
#[inline]
fn sub_cached(self, rhs: &Self) -> Self {
crate::trace_dispatch!("hyperlattice", "real_kernel", "sub-cached");
&self - rhs
}
#[inline]
fn exact_rational_kind(&self) -> ExactRationalKind {
match self.exact_rational_ref() {
Some(rational) if rational.is_dyadic() => ExactRationalKind::ExactDyadicRational,
Some(_) => ExactRationalKind::ExactRational,
None => ExactRationalKind::NonRational,
}
}
#[inline]
fn dot3(left: [&Self; 3], right: [&Self; 3]) -> Self {
Real::dot3_refs(left, right)
}
#[inline]
fn dot4(left: [&Self; 4], right: [&Self; 4]) -> Self {
Real::dot4_refs(left, right)
}
#[inline]
fn dot3_same(values: [&Self; 3]) -> Self {
Real::dot3_refs(values, values)
}
#[inline]
fn dot4_same(values: [&Self; 4]) -> Self {
Real::dot4_refs(values, values)
}
#[inline]
fn linear_combination3(coefficients: [&Self; 3], values: [&Self; 3]) -> Self {
Real::linear_combination3_refs(coefficients, values)
}
#[inline]
fn active_linear_combination3(coefficients: [&Self; 3], values: [&Self; 3]) -> Self {
Real::active_linear_combination3_refs(coefficients, values)
}
#[inline]
fn linear_combination4(coefficients: [&Self; 4], values: [&Self; 4]) -> Self {
Real::linear_combination4_refs(coefficients, values)
}
#[inline]
fn signed_product_sum2<const TERMS: usize>(
positive_terms: [bool; TERMS],
terms: [[&Self; 2]; TERMS],
) -> Self {
let mut first_term: Option<([&Self; 2], bool)> = None;
let mut second_term: Option<([&Self; 2], bool)> = None;
let mut nonzero_count = 0usize;
for i in 0..TERMS {
if terms[i][0].definitely_zero() || terms[i][1].definitely_zero() {
continue;
}
let term = (terms[i], positive_terms[i]);
nonzero_count += 1;
if nonzero_count == 1 {
first_term = Some(term);
} else if nonzero_count == 2 {
second_term = Some(term);
}
}
match nonzero_count {
0 => return Real::zero(),
1 => {
let (term, positive) = first_term.expect("single non-zero term tracked");
let product = term[0] * term[1];
return if positive { product } else { -product };
}
2 => {
let (left, left_positive) = first_term.expect("first non-zero term tracked");
let (right, right_positive) = second_term.expect("second non-zero term tracked");
return Real::active_signed_product_sum2(
[left_positive, right_positive],
[left, right],
);
}
_ => {}
}
Real::active_signed_product_sum2(positive_terms, terms)
}
#[inline]
fn active_signed_product_sum2<const TERMS: usize>(
positive_terms: [bool; TERMS],
terms: [[&Self; 2]; TERMS],
) -> Self {
if let Some(sum) = Real::exact_rational_signed_product_sum(positive_terms, terms) {
crate::trace_dispatch!(
"hyperlattice",
"real_kernel",
"signed-product-sum-exact-rational"
);
return sum;
}
crate::trace_dispatch!("hyperlattice", "real_kernel", "signed-product-sum-generic");
let mut total: Option<Real> = None;
for i in 0..TERMS {
let product = terms[i][0] * terms[i][1];
total = Some(match total.take() {
Some(total) if positive_terms[i] => total + product,
Some(total) => total - product,
None if positive_terms[i] => product,
None => -product,
});
}
total.unwrap_or_else(Real::zero)
}
#[inline]
fn active_signed_product_sum2_known_exact_rational<const TERMS: usize>(
positive_terms: [bool; TERMS],
terms: [[&Self; 2]; TERMS],
) -> Self {
Real::exact_rational_signed_product_sum_known_exact(positive_terms, terms)
}
}