diff --git a/ext/crates/algebra/Cargo.toml b/ext/crates/algebra/Cargo.toml index f1bec82ad..d31506be7 100644 --- a/ext/crates/algebra/Cargo.toml +++ b/ext/crates/algebra/Cargo.toml @@ -26,6 +26,7 @@ nom = { version = "7.0.0", default-features = false, features = ["alloc"] } rustc-hash = "1.1.0" serde = { version = "1.0.0", features = ["derive"] } serde_json = "1.0.0" +enum_dispatch = "0.3.13" [dev-dependencies] bencher = "0.1.5" diff --git a/ext/crates/algebra/src/algebra/adem_algebra.rs b/ext/crates/algebra/src/algebra/adem_algebra.rs index bad7c8bcc..0712e6d3c 100644 --- a/ext/crates/algebra/src/algebra/adem_algebra.rs +++ b/ext/crates/algebra/src/algebra/adem_algebra.rs @@ -20,23 +20,6 @@ use crate::algebra::{ Algebra, Bialgebra, GeneratedAlgebra, UnstableAlgebra, }; -/// An algebra that can be viewed as an Adem algebra. -/// -/// This is here so that the Python bindings can use modules defined for AdemAlgebraT -/// with their version of [`SteenrodAlgebra`]. -/// -/// In order for things to work `AdemAlgebraT` cannot implement [`Algebra`]. -/// Otherwise, the algebra enum for our bindings will see an implementation clash. -pub trait AdemAlgebraT: Send + Sync + Algebra { - fn adem_algebra(&self) -> &AdemAlgebra; -} - -impl AdemAlgebraT for AdemAlgebra { - fn adem_algebra(&self) -> &AdemAlgebra { - self - } -} - /// An Adem basis element for the Steenrod algebra. /// /// To encode an element diff --git a/ext/crates/algebra/src/algebra/algebra_trait.rs b/ext/crates/algebra/src/algebra/algebra_trait.rs index 4baf4df34..5d8f8f882 100644 --- a/ext/crates/algebra/src/algebra/algebra_trait.rs +++ b/ext/crates/algebra/src/algebra/algebra_trait.rs @@ -1,3 +1,4 @@ +use enum_dispatch::enum_dispatch; #[cfg(doc)] use fp::vector::FpVector; use fp::{ @@ -19,6 +20,7 @@ use itertools::Itertools; /// this function before performing other operations at that degree. /// /// Algebras may have a distinguished set of generators; see [`GeneratedAlgebra`]. +#[enum_dispatch] pub trait Algebra: std::fmt::Display + Send + Sync + 'static { /// A name for the algebra to use in serialization operations. This defaults to "" for algebras /// that don't care about this problem. @@ -189,6 +191,7 @@ pub trait Algebra: std::fmt::Display + Send + Sync + 'static { } } +#[enum_dispatch] pub trait UnstableAlgebra: Algebra { fn dimension_unstable(&self, degree: i32, excess: i32) -> usize; @@ -476,6 +479,7 @@ impl MuAlgebra for A { /// An [`Algebra`] equipped with a distinguished presentation. /// /// These data can be used to specify finite modules as the actions of the distinguished generators. +#[enum_dispatch] pub trait GeneratedAlgebra: Algebra { /// Return generators in `degree`. /// @@ -528,64 +532,3 @@ pub trait GeneratedAlgebra: Algebra { /// arbitrary degree. fn generating_relations(&self, degree: i32) -> Vec>; } - -#[macro_export] -macro_rules! dispatch_algebra { - ($struct:ty, $dispatch_macro:ident) => { - impl Algebra for $struct { - $dispatch_macro! { - fn prefix(&self) -> &str; - fn magic(&self) -> u32; - fn prime(&self) -> ValidPrime; - fn compute_basis(&self, degree: i32); - fn dimension(&self, degree: i32) -> usize; - fn multiply_basis_elements( - &self, - result: FpSliceMut, - coeff: u32, - r_degree: i32, - r_idx: usize, - s_degree: i32, - s_idx: usize, - ); - - fn multiply_basis_element_by_element( - &self, - result: FpSliceMut, - coeff: u32, - r_degree: i32, - r_idx: usize, - s_degree: i32, - s: FpSlice, - ); - - fn multiply_element_by_basis_element( - &self, - result: FpSliceMut, - coeff: u32, - r_degree: i32, - r: FpSlice, - s_degree: i32, - s_idx: usize, - ); - - fn multiply_element_by_element( - &self, - result: FpSliceMut, - coeff: u32, - r_degree: i32, - r: FpSlice, - s_degree: i32, - s: FpSlice, - ); - - fn default_filtration_one_products(&self) -> Vec<(String, i32, usize)>; - - fn basis_element_to_string(&self, degree: i32, idx: usize) -> String; - fn basis_element_from_string(&self, elt: &str) -> Option<(i32, usize)>; - - fn element_to_string(&self, degree: i32, element: FpSlice) -> String; - } - } - }; -} diff --git a/ext/crates/algebra/src/algebra/bialgebra_trait.rs b/ext/crates/algebra/src/algebra/bialgebra_trait.rs index 62048668e..0b0d4bc45 100644 --- a/ext/crates/algebra/src/algebra/bialgebra_trait.rs +++ b/ext/crates/algebra/src/algebra/bialgebra_trait.rs @@ -2,6 +2,7 @@ use crate::algebra::Algebra; /// An [`Algebra`] equipped with a coproduct operation that makes it into a /// bialgebra. +#[enum_dispatch::enum_dispatch] pub trait Bialgebra: Algebra { /// Computes a coproduct $\Delta(x)$, expressed as /// diff --git a/ext/crates/algebra/src/algebra/milnor_algebra.rs b/ext/crates/algebra/src/algebra/milnor_algebra.rs index b36a77f06..10ef7f555 100644 --- a/ext/crates/algebra/src/algebra/milnor_algebra.rs +++ b/ext/crates/algebra/src/algebra/milnor_algebra.rs @@ -11,19 +11,6 @@ use serde::{Deserialize, Serialize}; use crate::algebra::{combinatorics, Algebra, Bialgebra, GeneratedAlgebra, UnstableAlgebra}; -// This is here so that the Python bindings can use modules defined for AdemAlgebraT with their own algebra enum. -// In order for things to work AdemAlgebraT cannot implement Algebra. -// Otherwise, the algebra enum for our bindings will see an implementation clash. -pub trait MilnorAlgebraT: Send + Sync + Algebra { - fn milnor_algebra(&self) -> &MilnorAlgebra; -} - -impl MilnorAlgebraT for MilnorAlgebra { - fn milnor_algebra(&self) -> &MilnorAlgebra { - self - } -} - fn q_part_default() -> u32 { !0 } diff --git a/ext/crates/algebra/src/algebra/mod.rs b/ext/crates/algebra/src/algebra/mod.rs index 1d13352c0..67baed2b0 100644 --- a/ext/crates/algebra/src/algebra/mod.rs +++ b/ext/crates/algebra/src/algebra/mod.rs @@ -2,7 +2,7 @@ //! representations of the Steenrod algebra. pub mod adem_algebra; -pub use adem_algebra::{AdemAlgebra, AdemAlgebraT}; +pub use adem_algebra::AdemAlgebra; mod algebra_trait; pub use algebra_trait::{Algebra, GeneratedAlgebra, MuAlgebra, UnstableAlgebra}; @@ -16,14 +16,9 @@ pub mod field; pub use field::Field; pub mod milnor_algebra; -pub use milnor_algebra::{MilnorAlgebra, MilnorAlgebraT}; - -mod polynomial_algebra; -pub use polynomial_algebra::{ - PolynomialAlgebra, PolynomialAlgebraMonomial, PolynomialAlgebraTableEntry, -}; +pub use milnor_algebra::MilnorAlgebra; mod steenrod_algebra; -pub use steenrod_algebra::{AlgebraType, SteenrodAlgebra, SteenrodAlgebraBorrow, SteenrodAlgebraT}; +pub use steenrod_algebra::{AlgebraType, SteenrodAlgebra}; pub mod pair_algebra; diff --git a/ext/crates/algebra/src/algebra/pair_algebra.rs b/ext/crates/algebra/src/algebra/pair_algebra.rs index e9b80ccaa..a9038a71c 100644 --- a/ext/crates/algebra/src/algebra/pair_algebra.rs +++ b/ext/crates/algebra/src/algebra/pair_algebra.rs @@ -20,6 +20,7 @@ type HashMap = hashbrown::HashMap fmt::Result { - write!( - f, - "UAM(degree={}, valid={}, poly={}, ext={})", - self.degree, self.valid, self.poly, self.ext - )?; - Ok(()) - } -} - -impl PolynomialAlgebraMonomial { - pub fn new(p: ValidPrime) -> Self { - Self { - degree: 0xFEDCBA9, // Looks invalid to me! - poly: FpVector::new(p, 0), - ext: FpVector::new(ValidPrime::new(2), 0), - valid: true, - } - } -} - -#[derive(Default)] -pub struct PolynomialAlgebraTableEntry { - pub index_to_monomial: Vec, // degree -> index -> AdemBasisElement - pub monomial_to_index: HashMap, // degree -> AdemBasisElement -> index -} - -impl PolynomialAlgebraTableEntry { - pub fn new() -> Self { - Self::default() - } -} - -impl std::hash::Hash for PolynomialAlgebraMonomial { - fn hash(&self, state: &mut H) { - self.poly.hash(state); - self.ext.hash(state); - } -} - -pub trait PolynomialAlgebra: std::fmt::Display + Sized + Send + Sync + 'static { - fn prime(&self) -> ValidPrime; - - fn polynomial_monomials(&self) -> &TruncatedPolynomialMonomialBasis; - fn exterior_monomials(&self) -> &TruncatedPolynomialMonomialBasis; - - fn min_degree(&self) -> i32 { - 0 - } - - fn polynomial_generators_in_degree(&self, degree: i32) -> usize; - fn exterior_generators_in_degree(&self, degree: i32) -> usize; - fn repr_poly_generator(&self, degree: i32, _index: usize) -> (String, u32); - fn repr_ext_generator(&self, degree: i32, _index: usize) -> String; - - fn basis_table(&self) -> &OnceVec; - - fn frobenius_on_generator(&self, degree: i32, index: usize) -> Option; - fn compute_generating_set(&self, degree: i32); - - fn compute_basis_step(&self, degree: i32) { - assert!(degree as usize == self.basis_table().len()); - let num_poly_gens = self.polynomial_generators_in_degree(degree); - let num_ext_gens = self.exterior_generators_in_degree(degree); - let poly_parts = self.polynomial_monomials(); - let ext_parts = self.exterior_monomials(); - if degree > 0 { - poly_parts.add_gens_and_calculate_parts(degree, num_poly_gens); - ext_parts.add_gens_and_calculate_parts(degree, num_ext_gens); - } - let mut table = PolynomialAlgebraTableEntry::new(); - for poly_deg in 0..=degree { - let ext_deg = degree - poly_deg; - for p in poly_parts.parts(poly_deg) { - for e in ext_parts.parts(ext_deg) { - let index = table.index_to_monomial.len(); - let mut m = PolynomialAlgebraMonomial { - degree, - poly: p.clone(), - ext: e.clone(), - valid: true, - }; - self.set_monomial_degree(&mut m, degree); - table.monomial_to_index.insert(m.clone(), index); - table.index_to_monomial.push(m); - } - } - } - self.basis_table().push(table); - } - - fn monomial_to_index(&self, monomial: &PolynomialAlgebraMonomial) -> usize { - self.basis_table()[monomial.degree as usize] - .monomial_to_index - .get(monomial) - .copied() - .unwrap_or_else(|| panic!("Didn't find monomial: {monomial}")) - } - - fn index_to_monomial(&self, degree: i32, index: usize) -> &PolynomialAlgebraMonomial { - &self.basis_table()[degree as usize].index_to_monomial[index] - } - - fn frobenius_monomial(&self, target: &mut FpVector, source: &FpVector) { - let p = self.prime().as_i32(); - for (i, c) in source.iter_nonzero() { - let (gen_degree, gen_index) = self.polynomial_monomials().internal_idx_to_gen_deg(i); - let frob = self.frobenius_on_generator(gen_degree, gen_index); - if let Some(e) = frob { - let out_idx = self - .polynomial_monomials() - .gen_deg_idx_to_internal_idx(p * gen_degree, e); - target.add_basis_element(out_idx, c); - } - } - } - - fn multiply_monomials( - &self, - target: &mut PolynomialAlgebraMonomial, - source: &PolynomialAlgebraMonomial, - ) -> Option { - let minus_one = self.prime() - 1; - self.set_monomial_degree(target, target.degree + source.degree); - let mut temp_source_ext = source.ext.clone(); - temp_source_ext.set_scratch_vector_size(target.ext.len()); - // If we made sign_rule handle vectors of different lengths, we could avoid cloning ext here. - let coeff = if target.ext.sign_rule(&temp_source_ext) { - minus_one - } else { - 1 - }; - target.ext.add_truncate(&temp_source_ext, 1)?; - - let mut carry_vec = [FpVector::new(self.prime(), target.poly.len())]; - let mut source_vec = source.poly.clone(); - source_vec.set_scratch_vector_size(target.poly.len()); - let mut carry_q = true; - while carry_q { - carry_q = target.poly.add_carry(&source_vec, 1, &mut carry_vec); - if carry_q { - source_vec.set_to_zero(); - self.frobenius_monomial(&mut source_vec, &carry_vec[0]); - carry_vec[0].set_to_zero(); - } - } - Some(coeff) - } - - fn multiply_polynomials( - &self, - target: &mut FpVector, - coeff: u32, - left_degree: i32, - left: &FpVector, - right_degree: i32, - right: &FpVector, - ) { - let p = self.prime(); - target.set_scratch_vector_size(self.dimension(left_degree + right_degree)); - for (left_idx, left_entry) in left.iter_nonzero() { - for (right_idx, right_entry) in right.iter_nonzero() { - let mut target_mono = self.index_to_monomial(left_degree, left_idx).clone(); - let source_mono = self.index_to_monomial(right_degree, right_idx); - let nonzero_result = self.multiply_monomials(&mut target_mono, source_mono); - if let Some(c) = nonzero_result { - let idx = self.monomial_to_index(&target_mono); - target.add_basis_element(idx, (left_entry * right_entry * c * coeff) % p); - } - } - } - } - - fn multiply_polynomial_by_monomial( - &self, - target: &mut FpVector, - coeff: u32, - left_degree: i32, - left: &FpVector, - right_mono: &PolynomialAlgebraMonomial, - ) { - let p = self.prime(); - target.extend_len(self.dimension(left_degree + right_mono.degree)); - for (left_idx, left_entry) in left.iter_nonzero() { - let mut target_mono = self.index_to_monomial(left_degree, left_idx).clone(); // Could reduce cloning a bit but probably best not to worry. - let nonzero_result = self.multiply_monomials(&mut target_mono, right_mono); - if let Some(c) = nonzero_result { - let idx = self.monomial_to_index(&target_mono); - target.add_basis_element(idx, (left_entry * c * coeff) % p); - } - } - } - - // At p=2 this is redundant but at odd primes one must worry about signs. - fn multiply_monomial_by_polynomial( - &self, - target: &mut FpVector, - coeff: u32, - left_mono: &PolynomialAlgebraMonomial, - right_degree: i32, - right: &FpVector, - ) { - let p = self.prime(); - target.extend_len(self.dimension(right_degree + left_mono.degree)); - for (right_idx, right_entry) in right.iter_nonzero() { - let mut target_mono = left_mono.clone(); // Could reduce cloning a bit but probably best not to worry. - let right_mono = self.index_to_monomial(right_degree, right_idx); - let nonzero_result = self.multiply_monomials(&mut target_mono, right_mono); - if let Some(c) = nonzero_result { - let idx = self.monomial_to_index(&target_mono); - target.add_basis_element(idx, (right_entry * c * coeff) % p); - } - } - } - - fn set_monomial_degree(&self, mono: &mut PolynomialAlgebraMonomial, degree: i32) { - mono.degree = degree; - mono.ext.set_scratch_vector_size( - self.exterior_monomials() - .generators_up_to_degree(mono.degree), - ); - mono.poly.set_scratch_vector_size( - self.polynomial_monomials() - .generators_up_to_degree(mono.degree), - ); - } - - fn max_computed_degree(&self) -> i32 { - self.basis_table().len() as i32 - 1 - } -} - -impl Algebra for A { - fn prime(&self) -> ValidPrime { - self.prime() - } - - fn compute_basis(&self, degree: i32) { - self.compute_generating_set(degree); - for i in self.max_computed_degree() + 1..=degree { - self.compute_basis_step(i); - } - } - - fn dimension(&self, degree: i32) -> usize { - if degree < 0 { - 0 - } else { - self.basis_table()[degree as usize].index_to_monomial.len() - } - } - - fn basis_element_to_string(&self, degree: i32, index: usize) -> String { - let mono = self.index_to_monomial(degree, index); - let mut exp_map = HashMap::default(); - for (i, e) in mono.poly.iter_nonzero() { - let (gen_deg, gen_idx) = self.polynomial_monomials().internal_idx_to_gen_deg(i); - let (var, var_exp) = self.repr_poly_generator(gen_deg, gen_idx); - let entry = exp_map.entry(var).or_insert((0, gen_deg / var_exp as i32)); - entry.0 += (e * var_exp) as i32; - } - let result = exp_map - .iter() - .sorted_by_key(|(_, &(_, gen_deg))| gen_deg) - .map(|(var, &(var_exp, gen_deg))| { - let pow = if var_exp > 1 { - format!("^{{{var_exp}}}") - } else { - "".to_string() - }; - let s = format!("{var}{pow}"); - (s, gen_deg) - }) - .merge_by( - mono.ext.iter_nonzero().map(|(i, _)| { - let (gen_deg, gen_idx) = self.exterior_monomials().internal_idx_to_gen_deg(i); - let var = self.repr_ext_generator(gen_deg, gen_idx); - (var, gen_deg) - }), - |x, y| x.1 < y.1, - ) - .map(|(v, _gen_deg)| v) - .join(" "); - if result.is_empty() { - "1".to_string() - } else { - result - } - } - - fn basis_element_from_string(&self, _elt: &str) -> Option<(i32, usize)> { - todo!() - } - - fn multiply_basis_elements( - &self, - mut result: FpSliceMut, - coeff: u32, - left_degree: i32, - left_idx: usize, - right_degree: i32, - right_idx: usize, - ) { - if coeff == 0 { - return; - } - let mut target = self.index_to_monomial(left_degree, left_idx).clone(); - let source = self.index_to_monomial(right_degree, right_idx); - if self.multiply_monomials(&mut target, source).is_some() { - let idx = self.monomial_to_index(&target); - result.add_basis_element(idx, coeff); - } - } -} diff --git a/ext/crates/algebra/src/algebra/steenrod_algebra.rs b/ext/crates/algebra/src/algebra/steenrod_algebra.rs index 547370e3d..0d8b4dac5 100644 --- a/ext/crates/algebra/src/algebra/steenrod_algebra.rs +++ b/ext/crates/algebra/src/algebra/steenrod_algebra.rs @@ -9,20 +9,10 @@ use serde::Deserialize; use serde_json::Value; use crate::{ - algebra::{ - AdemAlgebra, AdemAlgebraT, Algebra, Bialgebra, GeneratedAlgebra, MilnorAlgebra, - MilnorAlgebraT, - }, - dispatch_algebra, + algebra::{AdemAlgebra, Algebra, Bialgebra, GeneratedAlgebra, MilnorAlgebra, UnstableAlgebra}, + pair_algebra::PairAlgebra, }; -// This is here so that the Python bindings can use modules defined aor SteenrodAlgebraT with their own algebra enum. -// In order for things to work SteenrodAlgebraT cannot implement Algebra. -// Otherwise, the algebra enum for our bindings will see an implementation clash. -pub trait SteenrodAlgebraT: Send + Sync + Algebra { - fn steenrod_algebra(&self) -> SteenrodAlgebraBorrow<'_>; -} - #[derive(Copy, Clone, Debug, Eq, PartialEq)] pub enum AlgebraType { Adem, @@ -62,12 +52,10 @@ impl std::str::FromStr for AlgebraType { } } -pub enum SteenrodAlgebraBorrow<'a> { - BorrowAdem(&'a AdemAlgebra), - BorrowMilnor(&'a MilnorAlgebra), -} - #[allow(clippy::large_enum_variant)] +// `PairAlgebra` is not included in the dispatch list because it has associated types, +// which are incompatible with `enum_dispatch`. See pair_algebra.rs for more details. +#[enum_dispatch::enum_dispatch(Algebra, Bialgebra, GeneratedAlgebra, UnstableAlgebra)] pub enum SteenrodAlgebra { AdemAlgebra(AdemAlgebra), MilnorAlgebra(MilnorAlgebra), @@ -82,33 +70,6 @@ impl std::fmt::Display for SteenrodAlgebra { } } -impl SteenrodAlgebraT for SteenrodAlgebra { - fn steenrod_algebra(&self) -> SteenrodAlgebraBorrow<'_> { - match self { - Self::AdemAlgebra(a) => SteenrodAlgebraBorrow::BorrowAdem(a), - Self::MilnorAlgebra(a) => SteenrodAlgebraBorrow::BorrowMilnor(a), - } - } -} - -impl AdemAlgebraT for A { - fn adem_algebra(&self) -> &AdemAlgebra { - match self.steenrod_algebra() { - SteenrodAlgebraBorrow::BorrowAdem(a) => a, - SteenrodAlgebraBorrow::BorrowMilnor(_) => panic!(), - } - } -} - -impl MilnorAlgebraT for A { - fn milnor_algebra(&self) -> &MilnorAlgebra { - match self.steenrod_algebra() { - SteenrodAlgebraBorrow::BorrowAdem(_) => panic!(), - SteenrodAlgebraBorrow::BorrowMilnor(a) => a, - } - } -} - impl<'a> TryInto<&'a AdemAlgebra> for &'a SteenrodAlgebra { type Error = anyhow::Error; @@ -135,22 +96,6 @@ impl<'a> TryInto<&'a MilnorAlgebra> for &'a SteenrodAlgebra { } } -impl Bialgebra for SteenrodAlgebra { - fn decompose(&self, op_deg: i32, op_idx: usize) -> Vec<(i32, usize)> { - match self { - Self::AdemAlgebra(a) => a.decompose(op_deg, op_idx), - Self::MilnorAlgebra(a) => a.decompose(op_deg, op_idx), - } - } - - fn coproduct(&self, op_deg: i32, op_idx: usize) -> Vec<(i32, usize, i32, usize)> { - match self { - Self::AdemAlgebra(a) => a.coproduct(op_deg, op_idx), - Self::MilnorAlgebra(a) => a.coproduct(op_deg, op_idx), - } - } -} - #[derive(Deserialize, Debug)] struct AlgebraSpec { p: ValidPrime, @@ -199,26 +144,7 @@ macro_rules! dispatch_steenrod { }; } -dispatch_algebra!(SteenrodAlgebra, dispatch_steenrod); - -/// An algebra with a specified list of generators and generating relations. This data can be used -/// to specify modules by specifying the actions of the generators. -impl GeneratedAlgebra for SteenrodAlgebra { - dispatch_steenrod! { - fn generators(&self, degree: i32) -> Vec; - fn generator_to_string(&self, degree: i32, idx: usize) -> String; - - fn decompose_basis_element( - &self, - degree: i32, - idx: usize, - ) -> Vec<(u32, (i32, usize), (i32, usize))>; - - fn generating_relations(&self, degree: i32) -> Vec>; - } -} - -impl crate::pair_algebra::PairAlgebra for AdemAlgebra { +impl PairAlgebra for AdemAlgebra { type Element = crate::pair_algebra::MilnorPairElement; fn element_is_zero(_elt: &Self::Element) -> bool { @@ -278,7 +204,7 @@ impl crate::pair_algebra::PairAlgebra for AdemAlgebra { } } -impl crate::pair_algebra::PairAlgebra for SteenrodAlgebra { +impl PairAlgebra for SteenrodAlgebra { type Element = crate::pair_algebra::MilnorPairElement; dispatch_steenrod! { @@ -299,13 +225,3 @@ impl crate::pair_algebra::PairAlgebra for SteenrodAlgebra { MilnorAlgebra::finalize_element(elt); } } - -impl crate::UnstableAlgebra for SteenrodAlgebra { - dispatch_steenrod! { - fn dimension_unstable(&self, degree: i32, excess: i32) -> usize; - fn multiply_basis_elements_unstable(&self, result: FpSliceMut, coeff: u32, r_degree: i32, r_index: usize, s_degree: i32, s_index: usize, excess: i32); - fn multiply_basis_element_by_element_unstable(&self, result: FpSliceMut, coeff: u32, r_degree: i32, r_idx: usize, s_degree: i32, s: FpSlice, excess: i32); - fn multiply_element_by_basis_element_unstable(&self, result: FpSliceMut, coeff: u32, r_degree: i32, r: FpSlice, s_degree: i32, s_idx: usize, excess: i32); - fn multiply_element_by_element_unstable(&self, result: FpSliceMut, coeff: u32, r_degree: i32, r: FpSlice, s_degree: i32, s: FpSlice, excess: i32); - } -}