use super::{local_is_isotropic_char2, Char2QuadForm};
use crate::forms::function_field_char2::char2_monic_irreducible_factors;
use crate::forms::{FiniteChar2Field, FunctionFieldPlace};
use crate::scalar::{Poly, RationalFunction, Scalar};
fn ff_is_square<S: FiniteChar2Field>(f: &RationalFunction<S>) -> bool {
if f.is_zero() {
return true;
}
let prod = f.num().mul(f.den());
prod.coeffs()
.iter()
.enumerate()
.all(|(i, c)| i & 1 == 0 || c.is_zero())
}
pub fn global_is_pe<S: FiniteChar2Field>(f: &RationalFunction<S>) -> bool {
use super::asnf::local_is_pe;
if f.is_zero() {
return true;
}
if !local_is_pe(f, &FunctionFieldPlace::Infinite) {
return false;
}
char2_monic_irreducible_factors(f.den())
.into_iter()
.all(|p| local_is_pe(f, &FunctionFieldPlace::Finite(p)))
}
pub fn artin_schreier_form_places<S: FiniteChar2Field>(
form: &Char2QuadForm<S>,
) -> Vec<FunctionFieldPlace<S>> {
let mut primes: Vec<Poly<S>> = Vec::new();
let mut push = |g: &Poly<S>| {
for p in char2_monic_irreducible_factors(g) {
if !primes.contains(&p) {
primes.push(p);
}
}
};
for (a, b) in &form.blocks {
push(a.num());
push(a.den());
push(b.num());
push(b.den());
}
for c in &form.singular {
push(c.num());
push(c.den());
}
let mut places = vec![FunctionFieldPlace::Infinite];
places.extend(primes.into_iter().map(FunctionFieldPlace::Finite));
places
}
pub fn is_isotropic_global_char2<S: FiniteChar2Field>(form: &Char2QuadForm<S>) -> Option<bool> {
if form.singular.iter().any(|c| c.is_zero()) {
return Some(true);
}
if form.blocks.iter().any(|(a, b)| a.is_zero() || b.is_zero()) {
return Some(true);
}
let nb = form.blocks.len();
let ns = form.singular.len();
let rank = 2 * nb + ns;
if rank == 0 {
return Some(false); }
if rank >= 5 {
return Some(true); }
if ns >= 3 {
return Some(true); }
if ns == 2 {
if nb >= 1 {
return Some(true);
}
let prod = form.singular[0].mul(&form.singular[1]);
return Some(ff_is_square(&prod)); }
match (nb, ns) {
(0, 1) => Some(false), (1, 0) => {
let (a, b) = &form.blocks[0];
Some(global_is_pe(&a.mul(b)))
}
_ => {
let mut all_iso = true;
for place in artin_schreier_form_places(form) {
match local_is_isotropic_char2(form, &place) {
Some(true) => {}
Some(false) => return Some(false),
None => all_iso = false,
}
}
all_iso.then_some(true)
}
}
}