mod core;
mod geometry;
pub use core::IntegralForm;
pub use geometry::AUTO_NODE_BUDGET;
pub(crate) use geometry::{checked_factorial, checked_pow2};
#[cfg(test)]
use geometry::SHORT_VECTOR_EXACT_ENUM_LIMIT;
#[cfg(test)]
mod tests {
use super::*;
use crate::scalar::Scalar;
fn a_n(n: usize) -> IntegralForm {
let mut g = vec![vec![0i128; n]; n];
for i in 0..n {
g[i][i] = 2;
if i + 1 < n {
g[i][i + 1] = -1;
g[i + 1][i] = -1;
}
}
IntegralForm::new(g).unwrap()
}
fn d4() -> IntegralForm {
IntegralForm::new(vec![
vec![2, -1, 0, 0],
vec![-1, 2, -1, -1],
vec![0, -1, 2, 0],
vec![0, -1, 0, 2],
])
.unwrap()
}
fn e8() -> IntegralForm {
IntegralForm::new(vec![
vec![2, -1, 0, 0, 0, 0, 0, 0],
vec![-1, 2, -1, 0, 0, 0, 0, 0],
vec![0, -1, 2, -1, 0, 0, 0, 0],
vec![0, 0, -1, 2, -1, 0, 0, 0],
vec![0, 0, 0, -1, 2, -1, 0, -1],
vec![0, 0, 0, 0, -1, 2, -1, 0],
vec![0, 0, 0, 0, 0, -1, 2, 0],
vec![0, 0, 0, 0, -1, 0, 0, 2],
])
.unwrap()
}
fn permute_basis(l: &IntegralForm, perm: &[usize]) -> IntegralForm {
let n = l.dim();
assert_eq!(perm.len(), n);
let mut g = vec![vec![0i128; n]; n];
for i in 0..n {
for j in 0..n {
g[i][j] = l.gram()[perm[i]][perm[j]];
}
}
IntegralForm::new(g).unwrap()
}
#[test]
fn rejects_non_symmetric() {
assert!(IntegralForm::new(vec![vec![1, 2], vec![3, 4]]).is_none());
assert!(IntegralForm::new(vec![vec![1, 2, 3], vec![2, 4]]).is_none());
assert!(IntegralForm::new(vec![vec![2, -1], vec![-1, 2]]).is_some());
}
#[test]
fn determinants_and_evenness() {
assert_eq!(a_n(2).determinant(), 3);
assert_eq!(a_n(3).determinant(), 4);
assert_eq!(d4().determinant(), 4);
assert_eq!(e8().determinant(), 1);
assert!(e8().is_unimodular());
assert!(e8().is_even());
assert!(a_n(2).is_even());
let z3 = IntegralForm::diagonal(&[1, 1, 1]);
assert_eq!(z3.determinant(), 1);
assert!(z3.is_unimodular());
assert!(!z3.is_even());
}
#[test]
fn invariant_factors_track_discriminant_group() {
assert_eq!(a_n(2).invariant_factors(), vec![1, 3]); assert_eq!(d4().invariant_factors(), vec![1, 1, 2, 2]); assert_eq!(e8().invariant_factors(), vec![1, 1, 1, 1, 1, 1, 1, 1]);
let prod: i128 = d4().invariant_factors().iter().product();
assert_eq!(prod, d4().determinant().abs());
}
#[test]
fn levels_match_known_values() {
assert_eq!(IntegralForm::diagonal(&[2]).level(), Some(4)); assert_eq!(a_n(2).level(), Some(3)); assert_eq!(e8().level(), Some(1)); assert_eq!(IntegralForm::diagonal(&[1]).level(), Some(2));
}
#[test]
fn signature_handles_indefinite_and_skew_bases() {
assert_eq!(IntegralForm::diagonal(&[1, 1, -1]).signature(), (2, 1));
let hyp = IntegralForm::new(vec![vec![0, 1], vec![1, 0]]).unwrap();
assert_eq!(hyp.signature(), (1, 1));
assert_eq!(
IntegralForm::new(vec![vec![0, 0], vec![0, 0]])
.unwrap()
.signature(),
(0, 0)
);
}
#[test]
fn lattice_clifford_metrics_preserve_q_and_polar_data() {
use crate::scalar::{Nimber, Rational};
let a2 = a_n(2);
let rat = a2.clifford_metric();
assert_eq!(rat.q, vec![Rational::from_int(2), Rational::from_int(2)]);
assert_eq!(rat.b[&(0, 1)], Rational::from_int(-2));
let f2 = a2.clifford_metric_f2().unwrap();
assert_eq!(f2.q, vec![Nimber(1), Nimber(1)]);
assert_eq!(f2.b[&(0, 1)], Nimber(1));
assert!(IntegralForm::diagonal(&[1]).clifford_metric_f2().is_none());
}
#[test]
fn minimum_and_kissing_numbers() {
assert_eq!(a_n(2).minimum(), Some(2));
assert_eq!(a_n(2).kissing_number(), Some(6)); assert_eq!(a_n(3).kissing_number(), Some(12)); assert_eq!(d4().minimum(), Some(2));
assert_eq!(d4().kissing_number(), Some(24)); assert_eq!(e8().minimum(), Some(2));
assert_eq!(e8().kissing_number(), Some(240));
let z2 = IntegralForm::diagonal(&[1, 1]);
assert_eq!(z2.minimum(), Some(1));
assert_eq!(z2.kissing_number(), Some(4));
}
#[test]
fn short_vectors_return_original_coordinates_after_basis_reduction() {
let g = IntegralForm::new(vec![vec![1, 10], vec![10, 101]]).unwrap();
let mut exact = g
.short_vectors_exact_bounded(1, SHORT_VECTOR_EXACT_ENUM_LIMIT)
.expect("small rational ellipsoid box is enumerated exactly");
exact.sort();
let mut vecs = g.short_vectors(1).unwrap();
vecs.sort();
assert_eq!(exact, vecs);
assert_eq!(
vecs,
vec![vec![-10, 1], vec![-1, 0], vec![1, 0], vec![10, -1]]
);
assert!(vecs.iter().all(|v| g.norm(v) == 1));
}
#[test]
fn short_vectors_are_indefinite_safe() {
let hyp = IntegralForm::new(vec![vec![0, 1], vec![1, 0]]).unwrap();
assert!(!hyp.is_positive_definite());
assert_eq!(hyp.short_vectors(4), None);
assert_eq!(hyp.minimum(), None);
assert_eq!(hyp.automorphism_group_order(), None);
}
#[test]
fn automorphism_orders_match_known() {
assert_eq!(
IntegralForm::diagonal(&[1, 1]).automorphism_group_order(),
Some(8)
);
assert_eq!(
IntegralForm::diagonal(&[1, 1, 1]).automorphism_group_order(),
Some(48)
);
assert_eq!(a_n(2).automorphism_group_order(), Some(12));
assert_eq!(a_n(3).automorphism_group_order(), Some(48));
assert_eq!(d4().automorphism_group_order(), Some(1152));
assert_eq!(e8().automorphism_group_order_bounded(1), Some(696_729_600));
}
#[test]
fn automorphism_budget_cutoff_reports_none() {
let d4_permuted = permute_basis(&d4(), &[2, 0, 1, 3]);
assert_eq!(d4_permuted.automorphism_group_order_bounded(1), Some(1152));
let generic = IntegralForm::new(vec![vec![2, 1], vec![1, 3]]).unwrap();
assert_eq!(generic.automorphism_group_order_bounded(0), None);
}
#[test]
fn direct_sum_is_block_diagonal() {
let sum = a_n(2).direct_sum(&IntegralForm::diagonal(&[1]));
assert_eq!(sum.dim(), 3);
assert_eq!(sum.determinant(), 3); let e8e8 = e8().direct_sum(&e8());
assert_eq!(e8e8.dim(), 16);
assert_eq!(e8e8.determinant(), 1);
assert!(e8e8.is_even());
for i in 0..8 {
for j in 8..16 {
assert_eq!(e8e8.gram()[i][j], 0);
}
}
}
#[test]
fn ldl_returns_none_on_indefinite_gram() {
let hyp = IntegralForm::new(vec![vec![0, 1], vec![1, 0]]).unwrap();
assert!(hyp.ldl().is_none());
assert!(a_n(2).ldl().is_some());
let (d, _) = a_n(2).ldl().unwrap();
assert!(d.iter().all(|&di| di > 0.0));
}
}