#![cfg(feature = "testing")]
#[macro_use]
mod common;
use common::*;
use diffable::{
coords::Coords,
epsilon_metric::R64,
flat::{KleinBottle, KleinBottleCover, MyopicTorus, MyopicTorusCover, S1, Torus, TorusCover},
group_presentation, test_pseudo_riemannian, test_quotient, test_tangent_bundle,
traits::{Chart, GroupPresentation, InnerProduct, NerveComplex, NerveComplexParameters, Nodes},
};
use proptest::prelude::*;
test_tangent_bundle!(
tangent_bundle_s1_quotient,
R64,
S1<Coords<_, _>>,
arb_s1_quotient(),
arb_vec::<1>(),
arb_scalar()
);
test_quotient!(
quotient_s1,
S1<Coords<_, _>>,
arb_s1_quotient(),
arb_vec1(),
arb_z()
);
test_pseudo_riemannian!(
riemannian_s1,
S1<Coords<_, _>>,
arb_s1_quotient(),
arb_vec1()
);
test_tangent_bundle!(
torus_tangent_bundle,
R64,
Torus<Coords<R64, 1>, Coords<R64, 2>>,
(arb_s1_quotient(), arb_s1_quotient()).prop_map(|(a, b)| Torus::new(a, b)),
arb_vec2(),
arb_scalar()
);
test_pseudo_riemannian!(
riemannian_torus,
Torus<Coords<R64, 1>, Coords<R64, 2>>,
(arb_s1_quotient(), arb_s1_quotient()).prop_map(|(a, b)| Torus::new(a, b)),
arb_vec2()
);
test_tangent_bundle!(
klein_bottle_tangent_bundle,
R64,
KleinBottle<Coords<R64, 1>, Coords<R64, 2>>,
(arb_s1_quotient(), arb_s1_quotient()).prop_map(|(a, b)| KleinBottle::new(a, b)),
arb_vec2(),
arb_scalar()
);
test_pseudo_riemannian!(
riemannian_klein_bottle,
KleinBottle<Coords<R64, 1>, Coords<R64, 2>>,
(arb_s1_quotient(), arb_s1_quotient()).prop_map(|(a, b)| KleinBottle::new(a, b)),
arb_vec2()
);
#[test]
fn klein_bottle_fundamental_group() {
let presentation = KleinBottleCover::<Coords<R64, 1>, Coords<R64, 2>>::fundamental_group();
group_presentation!(
KLEIN_BOTTLE,
n_generators = 2,
relations = [[(0, false), (0, false), (1, false), (1, false)],]
);
assert!(
presentation.check_exactly_equal(&KLEIN_BOTTLE),
"Expected: {:?}\nActual: {:?}",
presentation,
KLEIN_BOTTLE
);
}
#[test]
fn torus_fundamental_group() {
let presentation = TorusCover::<Coords<R64, 1>, Coords<R64, 2>>::fundamental_group();
group_presentation!(
TORUS,
n_generators = 2,
relations = [[(0, false), (1, false), (0, true), (1, true)],]
);
assert!(
presentation.check_exactly_equal(&TORUS),
"Expected: {:?}\nActual: {:?}",
presentation,
TORUS
);
}
#[test]
fn myopic_torus_cover_invariants() {
type T = MyopicTorus<Coords<f64, 1>, Coords<f64, 2>>;
type Cover = MyopicTorusCover<Coords<f64, 1>, Coords<f64, 2>>;
let s = T::s() as f64;
let h = 1.0 / s; let delta_s = 2f64.sqrt() / (2.0 * s); let rho = (2f64.sqrt() + 2.0) / (4.0 * s); let big_r = 2.0 / s;
assert!(
2.0 * rho < big_r,
"2ρ < R: adjacent base points must see each other"
);
assert!(delta_s < rho, "δ_s < ρ: the cover must actually cover");
assert!(h < big_r, "adjacent base points within myopia radius");
let recovered = Cover::covering_radius().unwrap();
assert_eq!(R64(recovered), R64(delta_s));
}
proptest! {
#![proptest_config(ProptestConfig::with_cases(10))]
#[test]
fn myopic_torus_geodesic(
p in (arb_s1_quotient_f64(), arb_s1_quotient_f64()).prop_map(
|(a, b)| Torus::<Coords<f64, 1>, Coords<f64, 2>>::new(a, b)
),
q in (arb_s1_quotient_f64(), arb_s1_quotient_f64()).prop_map(
|(a, b)| Torus::<Coords<f64, 1>, Coords<f64, 2>>::new(a, b)
)) {
type Cover = MyopicTorusCover::<Coords<f64, 1>, Coords<f64, 2>>;
let n = Cover::nodes().len();
for i in 0..n {
let ns: Vec<_> = Cover::get_neighbors(i).collect();
for j in &ns {
assert!(Cover::edge_weight(i, *j).is_some(), "{i}-{j} invisible");
}
}
let expected_distance = p.to_local(&q).unwrap().norm();
let Some(diffable::traits::Geodesic {path: _, length, certificate}) =
Cover::geodesic_path(&p, &q) else {
panic!("no geodesic found")
};
prop_assert!(certificate.is_global(), "not certified as global minimum {certificate:?}");
prop_assert_eq!(R64(length), R64(expected_distance));
}
}