use super::FiniteOddField;
use crate::clifford::Metric;
use crate::forms::{as_diagonal, WittClassG};
use std::fmt;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct OddCharInvariants {
pub p: u128,
pub field_order: u128,
pub dim: usize,
pub radical_dim: usize,
pub disc_is_square: bool,
pub hasse: i128,
}
impl OddCharInvariants {
pub fn display(&self) -> String {
self.to_string()
}
}
impl fmt::Display for OddCharInvariants {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let d = if self.disc_is_square { "□" } else { "✶" };
let field = format!("F_{}", self.field_order);
let rad = if self.radical_dim > 0 {
format!(" ⊗̂ Λ({}^{})", field, self.radical_dim)
} else {
String::new()
};
write!(
f,
"{}: dim {} disc {} hasse {:+}{}",
field, self.dim, d, self.hasse, rad
)
}
}
pub fn hasse_invariant_finite_odd<F: FiniteOddField>(metric: &Metric<F>) -> Option<i128> {
F::ensure_supported()?;
as_diagonal(metric)?;
Some(1)
}
pub fn discriminant_finite_odd<F: FiniteOddField>(metric: &Metric<F>) -> Option<F> {
F::ensure_supported()?;
let metric = as_diagonal(metric)?;
let mut d = F::one();
for x in &metric.q {
if !x.is_zero() {
d = d.mul(x);
}
}
Some(d)
}
pub fn classify_finite_odd<F: FiniteOddField>(metric: &Metric<F>) -> Option<OddCharInvariants> {
F::ensure_supported()?;
let metric = as_diagonal(metric)?;
let dim = metric.q.iter().filter(|x| !x.is_zero()).count();
let radical_dim = metric.q.len() - dim;
let disc = discriminant_finite_odd(&metric)?;
Some(OddCharInvariants {
p: F::characteristic_prime(),
field_order: F::field_order(),
dim,
radical_dim,
disc_is_square: F::is_square_value(disc),
hasse: hasse_invariant_finite_odd(&metric)?,
})
}
pub fn finite_odd_witt<F: FiniteOddField>(metric: &Metric<F>) -> Option<WittClassG> {
F::ensure_supported()?;
let metric = as_diagonal(metric)?;
let mut det = F::one();
let mut m = 0usize;
for x in &metric.q {
if !x.is_zero() {
det = det.mul(x);
m += 1;
}
}
let signed = if (m * (m.wrapping_sub(1)) / 2) & 1 == 1 {
det.neg()
} else {
det
};
let kappa = if F::is_square_value(F::from_int(-1)) {
0
} else {
1
};
Some(WittClassG::OddChar {
field_order: F::field_order(),
kappa,
e0: (m & 1) as u128,
sclass: if F::is_square_value(signed) { 0 } else { 1 },
})
}