use crate::scalar::tropical::{MinPlus, Tropical};
use crate::scalar::{Laurent, Qp, Qq, Scalar};
pub trait Valued: Scalar {
fn valuation(&self) -> Option<i128>;
fn uniformizer() -> Self;
}
pub fn tropicalize<K: Valued>(x: &K) -> Tropical<MinPlus> {
match x.valuation() {
Some(v) => Tropical::int(v),
None => Tropical::infinity(),
}
}
impl<const P: u128, const K: u128> Valued for Qp<P, K> {
fn valuation(&self) -> Option<i128> {
Qp::valuation(self)
}
fn uniformizer() -> Self {
Qp::from_p_power(1)
}
}
impl<const P: u128, const N: usize, const F: usize> Valued for Qq<P, N, F> {
fn valuation(&self) -> Option<i128> {
Qq::valuation(self)
}
fn uniformizer() -> Self {
Qq::from_p_power(1)
}
}
impl<S: Scalar, const K: usize> Valued for Laurent<S, K> {
fn valuation(&self) -> Option<i128> {
Laurent::valuation(self)
}
fn uniformizer() -> Self {
Laurent::t()
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::scalar::{Fp, Rational};
#[test]
fn uniformizers_have_valuation_one() {
assert_eq!(Qp::<5, 4>::uniformizer().valuation(), Some(1));
assert_eq!(Qq::<3, 4, 2>::uniformizer().valuation(), Some(1));
assert_eq!(Laurent::<Rational, 6>::uniformizer().valuation(), Some(1));
assert_eq!(Laurent::<Fp<7>, 6>::uniformizer().valuation(), Some(1));
}
#[test]
fn zero_valuation_is_none() {
assert_eq!(<Qp<5, 4> as Valued>::valuation(&Qp::zero()), None);
assert_eq!(
<Laurent<Rational, 6> as Valued>::valuation(&Laurent::zero()),
None
);
}
#[test]
fn trait_valuation_matches_inherent() {
let x = Qp::<5, 4>::from_int(50); assert_eq!(<Qp<5, 4> as Valued>::valuation(&x), x.valuation());
assert_eq!(<Qp<5, 4> as Valued>::valuation(&x), Some(2));
}
#[test]
fn tropicalize_is_multiplicative() {
type Q = Qp<5, 8>;
let samples = [
Q::from_int(1),
Q::from_int(5), Q::from_int(50), Q::from_int(7), Q::from_p_power(-1), Q::zero(), ];
for x in &samples {
for y in &samples {
assert_eq!(
tropicalize(&x.mul(y)),
tropicalize(x).mul(&tropicalize(y)),
"τ(xy) ≠ τ(x)⊗τ(y)"
);
}
}
}
#[test]
fn tropicalize_is_subadditive() {
type Q = Qp<5, 8>;
let samples = [
Q::from_int(1),
Q::from_int(5),
Q::from_int(6), Q::from_int(25),
Q::from_int(-1),
Q::zero(),
];
for x in &samples {
for y in &samples {
let s = tropicalize(x).add(&tropicalize(y)); assert_eq!(tropicalize(&x.add(y)).add(&s), s, "subadditivity J.1(ii)");
}
}
}
#[test]
fn tropicalize_equality_off_vanishing_locus() {
type Q = Qp<5, 8>;
let samples = [
Q::from_int(1),
Q::from_int(5),
Q::from_int(25),
Q::from_int(7),
Q::from_p_power(-1),
];
for x in &samples {
for y in &samples {
if tropicalize(x) != tropicalize(y) {
assert_eq!(
tropicalize(&x.add(y)),
tropicalize(x).add(&tropicalize(y)),
"off the vanishing locus the min is strict"
);
}
}
}
}
#[test]
fn tropicalize_is_generic_over_legs() {
assert_eq!(
tropicalize(&Qq::<3, 4, 2>::from_p_power(1)),
Tropical::int(1)
);
assert_eq!(tropicalize(&Laurent::<Fp<7>, 6>::t()), Tropical::int(1));
assert!(tropicalize(&Qp::<5, 4>::zero()).is_infinity());
}
}