use std::marker::PhantomData;
use super::coerced::{CoerceTransformation, EquivalentTransportedMF};
use super::modular_def::{ModularError, ModularForm, ModularTransformationGroup};
use crate::arithmetic_utils::Field;
#[allow(dead_code)]
pub struct ProductModularForm<
R: Field,
F1,
F2,
const TWICE_WEIGHT_1: usize,
const TWICE_WEIGHT_2: usize,
const TWICE_WEIGHT_SUM: usize,
> {
pub first: F1,
pub second: F2,
r: PhantomData<R>,
}
impl<
R: Field,
F1: ModularForm<TWICE_WEIGHT_1, R>,
F2: ModularForm<TWICE_WEIGHT_2, R>,
const TWICE_WEIGHT_1: usize,
const TWICE_WEIGHT_2: usize,
const TWICE_WEIGHT_SUM: usize,
> ProductModularForm<R, F1, F2, TWICE_WEIGHT_1, TWICE_WEIGHT_2, TWICE_WEIGHT_SUM>
{
const WEIGHT_CHECK: () = assert!(
TWICE_WEIGHT_SUM == TWICE_WEIGHT_1 + TWICE_WEIGHT_2,
"TWICE_WEIGHT_SUM must equal TWICE_WEIGHT_1 + TWICE_WEIGHT_2 for ProductModularForm"
);
#[must_use = "The factors are now inside the product"]
#[allow(dead_code)]
pub fn new(first: F1, second: F2) -> Self {
let () = Self::WEIGHT_CHECK;
Self {
first,
second,
r: PhantomData,
}
}
}
#[allow(dead_code)]
pub struct CombinedTransformationGroup<G1, G2> {
pub first: G1,
pub second: G2,
}
impl<R: Field, G1: ModularTransformationGroup<R>, G2: ModularTransformationGroup<R>>
ModularTransformationGroup<R> for CombinedTransformationGroup<G1, G2>
{
fn new(raw_matrix: [[R; 2]; 2]) -> Result<Self, ModularError> {
let [[a, b], [c, d]] = raw_matrix;
let first = G1::new([[a.clone(), b.clone()], [c.clone(), d.clone()]])?;
let second = G2::new([[a, b], [c, d]])?;
Ok(Self { first, second })
}
fn transform_q(&self, q: &R) -> R {
self.first.transform_q(q)
}
fn multiplier_system(&self, tau: &R) -> R {
self.first.multiplier_system(tau) * self.second.multiplier_system(tau)
}
fn raw_a(&self) -> R {
self.first.raw_a()
}
fn raw_b(&self) -> R {
self.first.raw_b()
}
fn raw_c(&self) -> R {
self.first.raw_c()
}
fn raw_d(&self) -> R {
self.first.raw_d()
}
fn is_trivial_multiplier_system() -> bool {
G1::is_trivial_multiplier_system() && G2::is_trivial_multiplier_system()
}
}
impl<
R: Field,
F1: ModularForm<TWICE_WEIGHT_1, R>,
F2: ModularForm<TWICE_WEIGHT_2, R>,
const TWICE_WEIGHT_1: usize,
const TWICE_WEIGHT_2: usize,
const TWICE_WEIGHT_SUM: usize,
> ModularForm<TWICE_WEIGHT_SUM, R>
for ProductModularForm<R, F1, F2, TWICE_WEIGHT_1, TWICE_WEIGHT_2, TWICE_WEIGHT_SUM>
{
type TransformationGroup =
CombinedTransformationGroup<F1::TransformationGroup, F2::TransformationGroup>;
fn extract_coeffs(&self, which_coeff: usize) -> Result<R, ModularError> {
let mut to_return = R::zero();
for k in 0..=which_coeff {
let a_k = self.first.extract_coeffs(k)?;
let b_rest = self.second.extract_coeffs(which_coeff - k)?;
to_return += a_k * b_rest;
}
Ok(to_return)
}
fn evaluate_at(&self, q: &R) -> Result<R, ModularError> {
Ok(self.first.evaluate_at(q)? * self.second.evaluate_at(q)?)
}
}
pub fn square_modular_form<
R: Field,
const TWICE_WEIGHT: usize,
const FOUR_WEIGHT: usize,
T: ModularForm<TWICE_WEIGHT, R> + Clone,
>(
t: T,
) -> ProductModularForm<R, T, T, TWICE_WEIGHT, TWICE_WEIGHT, FOUR_WEIGHT> {
ProductModularForm::new(t.clone(), t)
}
pub fn cube_modular_form<
R: Field,
const TWICE_WEIGHT: usize,
const FOUR_WEIGHT: usize,
const SIX_WEIGHT: usize,
T: ModularForm<TWICE_WEIGHT, R> + Clone,
>(
t: T,
) -> impl ModularForm<SIX_WEIGHT, R> {
ProductModularForm::new(
t.clone(),
ProductModularForm::<R, T, T, TWICE_WEIGHT, TWICE_WEIGHT, FOUR_WEIGHT>::new(t.clone(), t),
)
}
pub fn square_modular_form_trivial<
R: Field,
const TWICE_WEIGHT: usize,
const FOUR_WEIGHT: usize,
T: ModularForm<TWICE_WEIGHT, R> + Clone,
>(
t: T,
) -> impl ModularForm<FOUR_WEIGHT, R, TransformationGroup = T::TransformationGroup> {
assert!(
T::TransformationGroup::is_trivial_multiplier_system(),
"square_modular_form_trivial requires T::TransformationGroup to have a trivial multiplier system"
);
let coercion = CoerceTransformation::FORCED(
PhantomData,
PhantomData,
PhantomData::<T::TransformationGroup>,
);
EquivalentTransportedMF::coerce(square_modular_form(t), coercion)
}
pub fn cube_modular_form_trivial<
R: Field,
const TWICE_WEIGHT: usize,
const FOUR_WEIGHT: usize,
const SIX_WEIGHT: usize,
T: ModularForm<TWICE_WEIGHT, R> + Clone,
>(
t: T,
) -> impl ModularForm<SIX_WEIGHT, R, TransformationGroup = T::TransformationGroup> {
assert!(
T::TransformationGroup::is_trivial_multiplier_system(),
"cube_modular_form_trivial requires T::TransformationGroup to have a trivial multiplier system"
);
let product = ProductModularForm::new(
t.clone(),
ProductModularForm::<R, T, T, TWICE_WEIGHT, TWICE_WEIGHT, FOUR_WEIGHT>::new(t.clone(), t),
);
let coercion = CoerceTransformation::FORCED(
PhantomData,
PhantomData,
PhantomData::<T::TransformationGroup>,
);
EquivalentTransportedMF::coerce(product, coercion)
}