use crate::clifford::Metric;
use crate::forms::FiniteOddField;
use crate::scalar::Laurent;
use super::local::{springer_decompose_local, LocalSpringerDecomp};
pub fn springer_decompose_laurent<S: FiniteOddField, const K: usize>(
metric: &Metric<Laurent<S, K>>,
) -> Option<LocalSpringerDecomp> {
springer_decompose_local(metric)
}
#[cfg(test)]
mod tests {
use super::*;
use crate::scalar::{Fp, Fpn, Scalar};
type L5 = Laurent<Fp<5>, 4>; type L9 = Laurent<Fpn<3, 2>, 4>;
fn l5(coeffs: &[i128], val: i128) -> L5 {
Laurent::from_coeffs(coeffs.iter().map(|&n| Fp::<5>::from_int(n)).collect(), val)
}
#[test]
fn two_residue_layers_survive() {
let m = Metric::diagonal(vec![l5(&[1], 0), l5(&[1], 1)]);
let d = springer_decompose_laurent(&m).unwrap();
assert_eq!(d.graded.len(), 2);
assert_eq!(d.graded[0].valuation, 1); assert_eq!(d.graded[1].valuation, 0);
assert_eq!(
d.graded.iter().map(|g| g.dim).sum::<usize>() + d.radical_dim,
2
);
assert_eq!(d.parity_layer(0).len(), 1); assert_eq!(d.parity_layer(1).len(), 1); assert!(d.graded[0].disc_is_square); assert!(d.graded[1].disc_is_square);
}
#[test]
fn residue_square_class_tracks_nonsquares_in_f5() {
let m = Metric::diagonal(vec![l5(&[2], 0), l5(&[2], 1)]);
let d = springer_decompose_laurent(&m).unwrap();
assert!(!d.graded[0].disc_is_square);
assert!(!d.graded[1].disc_is_square);
let m2 = Metric::diagonal(vec![l5(&[2], 0), l5(&[3], 0)]);
let d2 = springer_decompose_laurent(&m2).unwrap();
assert_eq!(d2.graded.len(), 1);
assert_eq!(d2.graded[0].dim, 2);
assert!(d2.graded[0].disc_is_square);
}
#[test]
fn extension_residue_field_f9_square_class() {
let ns = (0..9u128)
.map(|c| Fpn::<3, 2>::from_coeffs(&[c % 3, c / 3]))
.find(|x| !x.is_zero() && !x.is_square())
.expect("F_9 has nonsquares");
let sq = ns.mul(&ns); let m = Metric::diagonal(vec![
Laurent::<Fpn<3, 2>, 4>::from_coeffs(vec![sq], 1),
Laurent::<Fpn<3, 2>, 4>::from_coeffs(vec![ns], 0),
]);
let d = springer_decompose_laurent(&m).unwrap();
assert_eq!(d.graded.len(), 2);
assert_eq!(d.graded[0].valuation, 1); assert!(d.graded[0].disc_is_square, "ns² is a square in F_9");
assert!(!d.graded[1].disc_is_square, "ns is a nonsquare in F_9");
let _ = L9::one(); }
#[test]
fn radical_and_char2_rejection() {
let m = Metric::diagonal(vec![L5::zero(), l5(&[1], 1)]);
let d = springer_decompose_laurent(&m).unwrap();
assert_eq!(d.radical_dim, 1);
assert_eq!(d.graded.len(), 1);
let m2 = Metric::diagonal(vec![Laurent::<Fpn<2, 3>, 4>::one()]);
assert!(springer_decompose_laurent(&m2).is_none());
}
}