use infogeom::FisherRaoSimplex;
use ndarray::array;
use skel::Manifold;
fn main() {
let m = FisherRaoSimplex::default();
let p = array![0.7, 0.2, 0.1];
let q = array![0.1, 0.2, 0.7];
let v = m.log_map(&p.view(), &q.view());
println!("p = {p}");
println!("q = {q}");
println!("log_p(q) = {v:.6}");
let q_recovered = m.exp_map(&p.view(), &v.view());
let err: f64 = q
.iter()
.zip(q_recovered.iter())
.map(|(a, b)| (a - b).abs())
.sum();
println!("exp_p(log_p(q)) = {q_recovered:.6}");
println!("round-trip L1 error: {err:.2e}");
let d_rao =
infogeom::rao_distance_categorical(p.as_slice().unwrap(), q.as_slice().unwrap(), 1e-12)
.unwrap();
println!("\nFisher-Rao distance: {d_rao:.6} rad");
println!("\ngeodesic interpolation:");
for &t in &[0.25, 0.5, 0.75] {
let vt = v.mapv(|vi| vi * t);
let pt = m.exp_map(&p.view(), &vt.view());
println!(" t={t:.2}: {pt:.4}");
}
let tv = m.parallel_transport(&p.view(), &q.view(), &v.view());
println!("\nparallel transport of v from T_p to T_q:");
println!(" v at p: {v:.6}");
println!(" Pv at q: {tv:.6}");
let norm_at_p: f64 = p
.iter()
.zip(v.iter())
.map(|(&pi, &vi)| vi * vi / (4.0 * pi))
.sum::<f64>()
.sqrt();
let norm_at_q: f64 = q
.iter()
.zip(tv.iter())
.map(|(&qi, &tvi)| tvi * tvi / (4.0 * qi))
.sum::<f64>()
.sqrt();
println!(" Fisher norm at p: {norm_at_p:.6}");
println!(" Fisher norm at q: {norm_at_q:.6}");
println!(" norm preserved: {}", (norm_at_p - norm_at_q).abs() < 1e-6);
}