#![allow(dead_code)]
use std::ffi::{c_char, c_int};
use super::ffi::{fmpz, slong};
#[repr(C)]
#[derive(Clone, Copy)]
pub struct MagStruct {
_payload: [u64; 2],
}
#[repr(C)]
#[derive(Clone, Copy)]
pub struct ArfStruct {
_payload: [u64; 4],
}
#[repr(C)]
#[derive(Clone, Copy)]
pub struct ArbStruct {
pub mid: ArfStruct,
pub rad: MagStruct,
}
#[repr(C)]
#[derive(Clone, Copy)]
pub struct AcbStruct {
pub real: ArbStruct,
pub imag: ArbStruct,
}
const _: () = assert!(std::mem::size_of::<MagStruct>() == 16);
const _: () = assert!(std::mem::size_of::<ArfStruct>() == 32);
const _: () = assert!(std::mem::size_of::<ArbStruct>() == 48);
const _: () = assert!(std::mem::size_of::<AcbStruct>() == 96);
const _: () = assert!(std::mem::align_of::<AcbStruct>() == 8);
impl ArbStruct {
pub const fn zeroed() -> Self {
ArbStruct {
mid: ArfStruct { _payload: [0; 4] },
rad: MagStruct { _payload: [0; 2] },
}
}
}
impl AcbStruct {
pub const fn zeroed() -> Self {
AcbStruct {
real: ArbStruct::zeroed(),
imag: ArbStruct::zeroed(),
}
}
}
impl ArfStruct {
pub const fn zeroed() -> Self {
ArfStruct { _payload: [0; 4] }
}
}
impl MagStruct {
pub const fn zeroed() -> Self {
MagStruct { _payload: [0; 2] }
}
}
#[repr(C, align(8))]
pub struct AcbMatBuf(pub [u8; 64]);
#[repr(C, align(8))]
pub struct ArbMatBuf(pub [u8; 64]);
#[repr(C, align(8))]
pub struct FmpzMatBuf(pub [u8; 64]);
impl AcbMatBuf {
pub const fn sentinel() -> Self {
AcbMatBuf([0xAA; 64])
}
}
impl ArbMatBuf {
pub const fn sentinel() -> Self {
ArbMatBuf([0xAA; 64])
}
}
impl FmpzMatBuf {
pub const fn sentinel() -> Self {
FmpzMatBuf([0xAA; 64])
}
}
pub const ARF_RND_DOWN: c_int = 0;
pub const ARF_RND_UP: c_int = 1;
pub const ARF_RND_FLOOR: c_int = 2;
pub const ARF_RND_CEIL: c_int = 3;
pub const ARF_RND_NEAR: c_int = 4;
pub const ARB_STR_MORE: u64 = 1;
pub const ARB_STR_NO_RADIUS: u64 = 2;
#[link(name = "flint")]
extern "C" {
pub fn arf_init(x: *mut ArfStruct);
pub fn arf_clear(x: *mut ArfStruct);
pub fn arf_set_d(x: *mut ArfStruct, v: f64);
pub fn arf_get_d(x: *const ArfStruct, rnd: c_int) -> f64;
pub fn arf_set_mag(y: *mut ArfStruct, x: *const MagStruct);
pub fn arf_get_fmpz_2exp(man: *mut fmpz, exp: *mut fmpz, x: *const ArfStruct);
pub fn arf_set_fmpz_2exp(x: *mut ArfStruct, man: *const fmpz, exp: *const fmpz);
pub fn mag_init(x: *mut MagStruct);
pub fn mag_clear(x: *mut MagStruct);
pub fn mag_set_d(z: *mut MagStruct, x: f64);
pub fn mag_get_d(z: *const MagStruct) -> f64;
pub fn mag_zero(z: *mut MagStruct);
pub fn mag_is_inf(x: *const MagStruct) -> c_int;
pub fn arb_init(x: *mut ArbStruct);
pub fn arb_clear(x: *mut ArbStruct);
pub fn arb_zero(x: *mut ArbStruct);
pub fn arb_one(x: *mut ArbStruct);
pub fn arb_indeterminate(x: *mut ArbStruct);
pub fn arb_set(y: *mut ArbStruct, x: *const ArbStruct);
pub fn arb_set_d(y: *mut ArbStruct, x: f64);
pub fn arb_set_si(y: *mut ArbStruct, x: slong);
pub fn arb_set_ui(y: *mut ArbStruct, x: u64);
pub fn arb_set_fmpz_2exp(x: *mut ArbStruct, y: *const fmpz, exp: *const fmpz);
pub fn arb_set_round(z: *mut ArbStruct, x: *const ArbStruct, prec: slong);
pub fn arb_neg(y: *mut ArbStruct, x: *const ArbStruct);
pub fn arb_abs(y: *mut ArbStruct, x: *const ArbStruct);
pub fn arb_add(z: *mut ArbStruct, x: *const ArbStruct, y: *const ArbStruct, prec: slong);
pub fn arb_sub(z: *mut ArbStruct, x: *const ArbStruct, y: *const ArbStruct, prec: slong);
pub fn arb_mul(z: *mut ArbStruct, x: *const ArbStruct, y: *const ArbStruct, prec: slong);
pub fn arb_div(z: *mut ArbStruct, x: *const ArbStruct, y: *const ArbStruct, prec: slong);
pub fn arb_sqrt(z: *mut ArbStruct, x: *const ArbStruct, prec: slong);
pub fn arb_pow(z: *mut ArbStruct, x: *const ArbStruct, y: *const ArbStruct, prec: slong);
pub fn arb_exp(z: *mut ArbStruct, x: *const ArbStruct, prec: slong);
pub fn arb_log(z: *mut ArbStruct, x: *const ArbStruct, prec: slong);
pub fn arb_gamma(z: *mut ArbStruct, x: *const ArbStruct, prec: slong);
pub fn arb_const_pi(z: *mut ArbStruct, prec: slong);
pub fn arb_mul_2exp_si(y: *mut ArbStruct, x: *const ArbStruct, e: slong);
pub fn arb_add_error_arf(x: *mut ArbStruct, err: *const ArfStruct);
pub fn arb_get_mid_arb(z: *mut ArbStruct, x: *const ArbStruct);
pub fn arb_get_rad_arb(z: *mut ArbStruct, x: *const ArbStruct);
pub fn arb_get_mag(z: *mut MagStruct, x: *const ArbStruct);
pub fn arb_get_lbound_arf(u: *mut ArfStruct, x: *const ArbStruct, prec: slong);
pub fn arb_get_ubound_arf(u: *mut ArfStruct, x: *const ArbStruct, prec: slong);
pub fn arb_rel_accuracy_bits(x: *const ArbStruct) -> slong;
pub fn arb_is_finite(x: *const ArbStruct) -> c_int;
pub fn arb_is_exact(x: *const ArbStruct) -> c_int;
pub fn arb_is_positive(x: *const ArbStruct) -> c_int;
pub fn arb_contains_zero(x: *const ArbStruct) -> c_int;
pub fn arb_contains(x: *const ArbStruct, y: *const ArbStruct) -> c_int;
pub fn arb_overlaps(x: *const ArbStruct, y: *const ArbStruct) -> c_int;
pub fn arb_equal(x: *const ArbStruct, y: *const ArbStruct) -> c_int;
pub fn arb_get_str(x: *const ArbStruct, n: slong, flags: u64) -> *mut c_char;
pub fn acb_init(x: *mut AcbStruct);
pub fn acb_clear(x: *mut AcbStruct);
pub fn acb_zero(x: *mut AcbStruct);
pub fn acb_one(x: *mut AcbStruct);
pub fn acb_onei(x: *mut AcbStruct);
pub fn acb_indeterminate(x: *mut AcbStruct);
pub fn acb_set(z: *mut AcbStruct, x: *const AcbStruct);
pub fn acb_set_d_d(z: *mut AcbStruct, re: f64, im: f64);
pub fn acb_set_arb_arb(z: *mut AcbStruct, re: *const ArbStruct, im: *const ArbStruct);
pub fn acb_set_round(z: *mut AcbStruct, x: *const AcbStruct, prec: slong);
pub fn acb_get_real(re: *mut ArbStruct, z: *const AcbStruct);
pub fn acb_get_imag(im: *mut ArbStruct, z: *const AcbStruct);
pub fn acb_neg(z: *mut AcbStruct, x: *const AcbStruct);
pub fn acb_conj(z: *mut AcbStruct, x: *const AcbStruct);
pub fn acb_add(z: *mut AcbStruct, x: *const AcbStruct, y: *const AcbStruct, prec: slong);
pub fn acb_sub(z: *mut AcbStruct, x: *const AcbStruct, y: *const AcbStruct, prec: slong);
pub fn acb_mul(z: *mut AcbStruct, x: *const AcbStruct, y: *const AcbStruct, prec: slong);
pub fn acb_div(z: *mut AcbStruct, x: *const AcbStruct, y: *const AcbStruct, prec: slong);
pub fn acb_sqrt(z: *mut AcbStruct, x: *const AcbStruct, prec: slong);
pub fn acb_exp(z: *mut AcbStruct, x: *const AcbStruct, prec: slong);
pub fn acb_log(z: *mut AcbStruct, x: *const AcbStruct, prec: slong);
pub fn acb_pow(z: *mut AcbStruct, x: *const AcbStruct, y: *const AcbStruct, prec: slong);
pub fn acb_abs(u: *mut ArbStruct, z: *const AcbStruct, prec: slong);
pub fn acb_const_pi(x: *mut AcbStruct, prec: slong);
pub fn acb_mul_2exp_si(z: *mut AcbStruct, x: *const AcbStruct, e: slong);
pub fn acb_rel_accuracy_bits(x: *const AcbStruct) -> slong;
pub fn acb_is_finite(x: *const AcbStruct) -> c_int;
pub fn acb_contains(x: *const AcbStruct, y: *const AcbStruct) -> c_int;
pub fn acb_contains_zero(x: *const AcbStruct) -> c_int;
pub fn acb_overlaps(x: *const AcbStruct, y: *const AcbStruct) -> c_int;
pub fn acb_equal(x: *const AcbStruct, y: *const AcbStruct) -> c_int;
pub fn _arb_vec_init(n: slong) -> *mut ArbStruct;
pub fn _arb_vec_clear(v: *mut ArbStruct, n: slong);
pub fn _acb_vec_init(n: slong) -> *mut AcbStruct;
pub fn _acb_vec_clear(v: *mut AcbStruct, n: slong);
pub fn arb_mat_init(mat: *mut ArbMatBuf, r: slong, c: slong);
pub fn arb_mat_clear(mat: *mut ArbMatBuf);
pub fn arb_mat_entry_ptr(mat: *mut ArbMatBuf, i: slong, j: slong) -> *mut ArbStruct;
pub fn arb_mat_cho(l: *mut ArbMatBuf, a: *const ArbMatBuf, prec: slong) -> c_int;
pub fn acb_mat_init(mat: *mut AcbMatBuf, r: slong, c: slong);
pub fn acb_mat_clear(mat: *mut AcbMatBuf);
pub fn acb_mat_entry_ptr(mat: *mut AcbMatBuf, i: slong, j: slong) -> *mut AcbStruct;
pub fn acb_mat_get_imag(im: *mut ArbMatBuf, mat: *const AcbMatBuf);
pub fn acb_modular_eta(z: *mut AcbStruct, tau: *const AcbStruct, prec: slong);
pub fn acb_modular_j(z: *mut AcbStruct, tau: *const AcbStruct, prec: slong);
pub fn acb_modular_lambda(r: *mut AcbStruct, tau: *const AcbStruct, prec: slong);
pub fn acb_modular_delta(r: *mut AcbStruct, tau: *const AcbStruct, prec: slong);
pub fn acb_modular_eisenstein(
r: *mut AcbStruct,
tau: *const AcbStruct,
len: slong,
prec: slong,
);
pub fn acb_modular_theta(
theta1: *mut AcbStruct,
theta2: *mut AcbStruct,
theta3: *mut AcbStruct,
theta4: *mut AcbStruct,
z: *const AcbStruct,
tau: *const AcbStruct,
prec: slong,
);
pub fn acb_elliptic_p(
r: *mut AcbStruct,
z: *const AcbStruct,
tau: *const AcbStruct,
prec: slong,
);
pub fn acb_elliptic_p_prime(
r: *mut AcbStruct,
z: *const AcbStruct,
tau: *const AcbStruct,
prec: slong,
);
pub fn acb_elliptic_zeta(
r: *mut AcbStruct,
z: *const AcbStruct,
tau: *const AcbStruct,
prec: slong,
);
pub fn acb_elliptic_sigma(
r: *mut AcbStruct,
z: *const AcbStruct,
tau: *const AcbStruct,
prec: slong,
);
pub fn acb_elliptic_invariants(
g2: *mut AcbStruct,
g3: *mut AcbStruct,
tau: *const AcbStruct,
prec: slong,
);
pub fn acb_elliptic_roots(
e1: *mut AcbStruct,
e2: *mut AcbStruct,
e3: *mut AcbStruct,
tau: *const AcbStruct,
prec: slong,
);
}
#[cfg(flint_acb_theta)]
#[link(name = "flint")]
extern "C" {
pub fn acb_theta_all(
th: *mut AcbStruct,
z: *const AcbStruct,
tau: *const AcbMatBuf,
sqr: c_int,
prec: slong,
);
pub fn acb_theta_one(
th: *mut AcbStruct,
z: *const AcbStruct,
tau: *const AcbMatBuf,
ab: u64,
prec: slong,
);
pub fn acb_theta_char_dot(a: u64, b: u64, g: slong) -> slong;
pub fn acb_siegel_reduce(mat: *mut FmpzMatBuf, tau: *const AcbMatBuf, prec: slong);
pub fn acb_siegel_is_reduced(tau: *const AcbMatBuf, tol_exp: slong, prec: slong) -> c_int;
pub fn acb_siegel_transform(
w: *mut AcbMatBuf,
mat: *const FmpzMatBuf,
tau: *const AcbMatBuf,
prec: slong,
);
pub fn sp2gz_is_correct(mat: *const FmpzMatBuf) -> c_int;
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct AbiMismatch {
pub detail: String,
}
static ABI_OK: std::sync::OnceLock<Result<(), AbiMismatch>> = std::sync::OnceLock::new();
pub fn abi_self_check() -> Result<(), AbiMismatch> {
ABI_OK.get_or_init(run_abi_self_check).clone()
}
fn run_abi_self_check() -> Result<(), AbiMismatch> {
let acb_size = std::mem::size_of::<AcbStruct>();
let arb_size = std::mem::size_of::<ArbStruct>();
unsafe {
let mut m = AcbMatBuf::sentinel();
acb_mat_init(&mut m, 1, 2);
let e00 = acb_mat_entry_ptr(&mut m, 0, 0) as usize;
let e01 = acb_mat_entry_ptr(&mut m, 0, 1) as usize;
let tail_ok = m.0[32..].iter().all(|&b| b == 0xAA);
acb_mat_clear(&mut m);
let measured = e01.wrapping_sub(e00);
if measured != acb_size {
return Err(AbiMismatch {
detail: format!(
"FLINT's acb_struct is {measured} bytes, this build assumes {acb_size}"
),
});
}
if !tail_ok {
return Err(AbiMismatch {
detail: "acb_mat_init wrote past the 32 bytes acb_mat_struct is assumed to \
occupy; the opaque buffer in flint::arb needs enlarging"
.to_string(),
});
}
let mut r = ArbMatBuf::sentinel();
arb_mat_init(&mut r, 1, 2);
let f00 = arb_mat_entry_ptr(&mut r, 0, 0) as usize;
let f01 = arb_mat_entry_ptr(&mut r, 0, 1) as usize;
let tail_ok = r.0[32..].iter().all(|&b| b == 0xAA);
arb_mat_clear(&mut r);
let measured = f01.wrapping_sub(f00);
if measured != arb_size {
return Err(AbiMismatch {
detail: format!(
"FLINT's arb_struct is {measured} bytes, this build assumes {arb_size}"
),
});
}
if !tail_ok {
return Err(AbiMismatch {
detail: "arb_mat_init wrote past the 32 bytes arb_mat_struct is assumed to \
occupy; the opaque buffer in flint::arb needs enlarging"
.to_string(),
});
}
let mut x = ArbStruct::zeroed();
arb_init(&mut x);
arb_set_d(&mut x, 1.5);
let mid = arf_get_d(&x.mid, ARF_RND_NEAR);
let rad = mag_get_d(&x.rad);
arb_clear(&mut x);
if mid != 1.5 || rad != 0.0 {
return Err(AbiMismatch {
detail: format!(
"arb_struct field offsets disagree with FLINT: read mid={mid}, rad={rad} \
from a ball set to exactly 1.5"
),
});
}
let mut z = AcbStruct::zeroed();
acb_init(&mut z);
acb_set_d_d(&mut z, 2.25, -3.5);
let re = arf_get_d(&z.real.mid, ARF_RND_NEAR);
let im = arf_get_d(&z.imag.mid, ARF_RND_NEAR);
acb_clear(&mut z);
if re != 2.25 || im != -3.5 {
return Err(AbiMismatch {
detail: format!(
"acb_struct field offsets disagree with FLINT: read re={re}, im={im} \
from 2.25 - 3.5i"
),
});
}
}
Ok(())
}