use super::errors::InfinityAlgebraError;
use crate::arithmetic_utils::Ring;
use crate::infinity_algebra::graded_module::GradedModule;
use crate::infinity_algebra::operation_tree::OperationTree;
use crate::infinity_algebra::tensor_power::TensorPower;
pub trait AInfinityAlgebra<Coeffs: Ring>
where
Self: GradedModule<Coeffs>,
{
fn m_n_one_term_owned<const N: usize>(inputs: [Self; N]) -> Self;
fn m_n_one_term<const N: usize>(inputs: [&Self; N]) -> Self;
#[must_use = "Avoid trying to compute the higher coherences which are definitively 0"]
fn max_nonzero_arity() -> Option<usize> {
None
}
fn m_n_slice(inputs: &[Self]) -> Result<Self, InfinityAlgebraError> {
let n = inputs.len();
if let Some(bound) = Self::max_nonzero_arity()
&& n > bound
{
return Ok(Self::zero(inputs[0].ctx()));
}
match n {
0 => Err(InfinityAlgebraError::CurvedAlgebra),
1 => {
let inputs_const: [&Self; 1] = <&[Self; 1]>::try_from(inputs)
.expect("length checked by match arm")
.each_ref();
Ok(Self::m_n_one_term(inputs_const))
}
2 => {
let inputs_const: [&Self; 2] = <&[Self; 2]>::try_from(inputs)
.expect("length checked by match arm")
.each_ref();
Ok(Self::m_n_one_term(inputs_const))
}
3 => {
let inputs_const: [&Self; 3] = <&[Self; 3]>::try_from(inputs)
.expect("length checked by match arm")
.each_ref();
Ok(Self::m_n_one_term(inputs_const))
}
4 => {
let inputs_const: [&Self; 4] = <&[Self; 4]>::try_from(inputs)
.expect("length checked by match arm")
.each_ref();
Ok(Self::m_n_one_term(inputs_const))
}
5 => {
let inputs_const: [&Self; 5] = <&[Self; 5]>::try_from(inputs)
.expect("length checked by match arm")
.each_ref();
Ok(Self::m_n_one_term(inputs_const))
}
6 => {
let inputs_const: [&Self; 6] = <&[Self; 6]>::try_from(inputs)
.expect("length checked by match arm")
.each_ref();
Ok(Self::m_n_one_term(inputs_const))
}
7 => {
let inputs_const: [&Self; 7] = <&[Self; 7]>::try_from(inputs)
.expect("length checked by match arm")
.each_ref();
Ok(Self::m_n_one_term(inputs_const))
}
8 => {
let inputs_const: [&Self; 8] = <&[Self; 8]>::try_from(inputs)
.expect("length checked by match arm")
.each_ref();
Ok(Self::m_n_one_term(inputs_const))
}
_ => Err(InfinityAlgebraError::ArityTooLarge(n)),
}
}
#[must_use = "returns the algebra element resulting from the linear combination; discarding it loses the computed value"]
fn m_n<const N: usize>(ctx: Self::Ctx, tensor: TensorPower<Self, Coeffs, N>) -> Self {
let mut result = Self::zero(ctx);
for (pure_tensor, coeff) in tensor.into_summands() {
result += Self::m_n_one_term_owned(pure_tensor) * coeff;
}
result
}
fn evaluate<const N: usize>(
ctx: Self::Ctx,
tree: &OperationTree,
combination: TensorPower<Self, Coeffs, N>,
) -> Result<Self, InfinityAlgebraError>
where
Self: Clone,
{
assert_eq!(
tree.num_leaves(),
N,
"tree has {} leaves but combination is in A^⊗{}",
tree.num_leaves(),
N,
);
let mut result = Self::zero(ctx);
for (pure_tensor, coeff) in combination.into_summands() {
result += tree.eval_refs_a::<Self, Coeffs>(&pure_tensor)? * coeff;
}
Ok(result)
}
}
impl OperationTree {
pub(crate) fn eval_refs_a<A, Coeffs>(&self, inputs: &[A]) -> Result<A, InfinityAlgebraError>
where
A: AInfinityAlgebra<Coeffs> + Clone,
Coeffs: Ring,
{
match self {
Self::Leaf {
absoulte_position: range,
} => Ok(inputs[*range].clone()),
Self::Node { children, .. } => {
let mut child_outputs: Vec<A> = Vec::with_capacity(children.len());
for child in children {
child_outputs.push(child.eval_refs_a(inputs)?);
}
A::m_n_slice(&child_outputs)
}
}
}
}