use super::ball::ComplexBall;
use super::error::ThetaError;
use super::{backend, evaluate_at, EllipticFn, ModularFn, Precision};
fn require_upper_half_plane(function: &'static str, tau: &ComplexBall) -> Result<(), ThetaError> {
if backend::imag_is_certainly_positive(tau)? {
Ok(())
} else {
Err(ThetaError::NotInUpperHalfPlane { function })
}
}
fn modular(
function: &'static str,
which: ModularFn,
tau: &ComplexBall,
precision: Precision,
) -> Result<ComplexBall, ThetaError> {
require_upper_half_plane(function, tau)?;
evaluate_at(function, precision, |bits| {
backend::modular_scalar(which, tau, bits)
})
}
pub fn dedekind_eta(tau: &ComplexBall, precision: Precision) -> Result<ComplexBall, ThetaError> {
modular("eta", ModularFn::Eta, tau, precision)
}
pub fn j_invariant(tau: &ComplexBall, precision: Precision) -> Result<ComplexBall, ThetaError> {
modular("j", ModularFn::JInvariant, tau, precision)
}
pub fn modular_lambda(tau: &ComplexBall, precision: Precision) -> Result<ComplexBall, ThetaError> {
modular("lambda", ModularFn::Lambda, tau, precision)
}
pub fn modular_discriminant(
tau: &ComplexBall,
precision: Precision,
) -> Result<ComplexBall, ThetaError> {
modular("Delta", ModularFn::Delta, tau, precision)
}
pub fn eisenstein_series(
tau: &ComplexBall,
count: usize,
precision: Precision,
) -> Result<Vec<ComplexBall>, ThetaError> {
if count == 0 {
return Ok(Vec::new());
}
require_upper_half_plane("Eisenstein series", tau)?;
evaluate_at("Eisenstein series", precision, |bits| {
backend::eisenstein(tau, count, bits)
})
}
pub fn jacobi_theta(
z: &ComplexBall,
tau: &ComplexBall,
precision: Precision,
) -> Result<[ComplexBall; 4], ThetaError> {
require_upper_half_plane("Jacobi theta", tau)?;
evaluate_at("Jacobi theta", precision, |bits| {
backend::jacobi_theta(z, tau, bits)
})
}
pub fn jacobi_theta_null(
tau: &ComplexBall,
precision: Precision,
) -> Result<[ComplexBall; 4], ThetaError> {
let zero = ComplexBall::exact_i64(0, 0, tau.precision());
jacobi_theta(&zero, tau, precision)
}
fn elliptic(
function: &'static str,
which: EllipticFn,
z: &ComplexBall,
tau: &ComplexBall,
precision: Precision,
) -> Result<ComplexBall, ThetaError> {
require_upper_half_plane(function, tau)?;
evaluate_at(function, precision, |bits| {
backend::elliptic_fn(which, z, tau, bits)
})
}
pub fn weierstrass_p(
z: &ComplexBall,
tau: &ComplexBall,
precision: Precision,
) -> Result<ComplexBall, ThetaError> {
elliptic("weierstrass_p", EllipticFn::P, z, tau, precision)
}
pub fn weierstrass_p_prime(
z: &ComplexBall,
tau: &ComplexBall,
precision: Precision,
) -> Result<ComplexBall, ThetaError> {
elliptic("weierstrass_p_prime", EllipticFn::PPrime, z, tau, precision)
}
pub fn weierstrass_zeta(
z: &ComplexBall,
tau: &ComplexBall,
precision: Precision,
) -> Result<ComplexBall, ThetaError> {
elliptic("weierstrass_zeta", EllipticFn::Zeta, z, tau, precision)
}
pub fn weierstrass_sigma(
z: &ComplexBall,
tau: &ComplexBall,
precision: Precision,
) -> Result<ComplexBall, ThetaError> {
elliptic("weierstrass_sigma", EllipticFn::Sigma, z, tau, precision)
}
pub fn weierstrass_invariants(
tau: &ComplexBall,
precision: Precision,
) -> Result<(ComplexBall, ComplexBall), ThetaError> {
require_upper_half_plane("weierstrass_invariants", tau)?;
evaluate_at("weierstrass_invariants", precision, |bits| {
backend::elliptic_invariants(tau, bits)
})
}
pub fn weierstrass_roots(
tau: &ComplexBall,
precision: Precision,
) -> Result<[ComplexBall; 3], ThetaError> {
require_upper_half_plane("weierstrass_roots", tau)?;
evaluate_at("weierstrass_roots", precision, |bits| {
backend::elliptic_roots(tau, bits)
})
}