use amari_core::Vector;
use amari_network::GeometricNetwork;
fn main() -> Result<(), Box<dyn std::error::Error>> {
println!("🌴 Amari Geometric Network Analysis - Tropical Path Finding");
println!("========================================================\n");
let mut network = GeometricNetwork::<2, 0, 0>::new();
println!("🚗 Building a transportation network...");
let cities = vec![
("New York", 0.0, 0.0),
("Philadelphia", 1.5, -0.8),
("Boston", 2.0, 3.0),
("Washington DC", 0.5, -2.0),
("Baltimore", 1.0, -1.5),
("Pittsburgh", -2.0, -1.0),
("Buffalo", -1.0, 2.5),
("Albany", 1.8, 1.5),
("Hartford", 2.5, 1.0),
("Providence", 3.0, 2.0),
];
let mut city_indices = Vec::new();
for (i, (name, x, y)) in cities.iter().enumerate() {
let node = network.add_node(Vector::from_components(*x, *y, 0.0).mv);
city_indices.push((node, *name));
println!(" 🏙️ {}: City {} at ({:.1}, {:.1})", i, name, x, y);
}
println!("\n🛣️ Adding transportation routes with travel times...");
let routes = vec![
(0, 1, 1.5), (0, 3, 4.5), (0, 7, 2.5), (1, 3, 3.0), (1, 4, 2.0), (2, 7, 3.5), (2, 8, 1.5), (2, 9, 1.0), (3, 4, 0.5), (3, 5, 5.0), (4, 5, 4.5), (5, 6, 3.5), (6, 7, 2.0), (7, 8, 1.8), (8, 9, 1.2), (0, 6, 6.0), (1, 8, 4.0), (4, 7, 3.8), ];
for (from, to, time) in routes {
network.add_edge(from, to, time)?;
let from_name = city_indices[from].1;
let to_name = city_indices[to].1;
println!(" {} → {} ({:.1}h)", from_name, to_name, time);
}
let bidirectional_routes = vec![
(0, 2, 4.0), (1, 5, 5.5), (6, 8, 4.2), ];
for (city1, city2, time) in bidirectional_routes {
network.add_undirected_edge(city1, city2, time)?;
let name1 = city_indices[city1].1;
let name2 = city_indices[city2].1;
println!(" {} ↔ {} ({:.1}h)", name1, name2, time);
}
println!("✅ Created {} routes", network.num_edges());
println!("\n🌴 Converting to tropical network representation...");
let tropical_network = network.to_tropical_network()?;
println!(
"✅ Tropical network created with {} nodes",
tropical_network.size()
);
println!("\nIn tropical algebra:");
println!(" • Addition (⊕) becomes max operation");
println!(" • Multiplication (⊗) becomes addition");
println!(" • This transforms shortest path to tropical matrix operations");
println!("\n🎯 Finding shortest paths using tropical algebra:");
let test_routes = vec![
(0, 2, "New York", "Boston"),
(0, 5, "New York", "Pittsburgh"),
(1, 6, "Philadelphia", "Buffalo"),
(3, 9, "Washington DC", "Providence"),
(5, 9, "Pittsburgh", "Providence"),
];
for (start, end, start_name, end_name) in test_routes {
println!("\n 🗺️ Route: {} → {}", start_name, end_name);
let tropical_result = tropical_network.shortest_path_tropical(start, end)?;
match &tropical_result {
Some((path, distance)) => {
print!(" Path: ");
for (i, &node_idx) in path.iter().enumerate() {
if i > 0 {
print!(" → ");
}
print!("{}", city_indices[node_idx].1);
}
println!();
println!(" Total time: {:.1} hours", distance);
if path.len() > 1 {
println!(" Breakdown:");
for window in path.windows(2) {
let from_idx = window[0];
let to_idx = window[1];
if let Ok(edge_weight) = tropical_network.get_edge(from_idx, to_idx) {
if !edge_weight.is_zero() {
println!(
" {} → {}: {:.1}h",
city_indices[from_idx].1,
city_indices[to_idx].1,
edge_weight.value()
);
}
}
}
}
}
None => {
println!(" ❌ No path found");
}
}
match network.shortest_path(start, end)? {
Some((std_path, std_distance)) => {
let tropical_path = tropical_result
.as_ref()
.map(|(path, _)| path.clone())
.unwrap_or_default();
if std_path != tropical_path {
println!(
" 🔄 Standard algorithm found different path: {:?} ({:.1}h)",
std_path
.iter()
.map(|&i| city_indices[i].1)
.collect::<Vec<_>>(),
std_distance
);
}
}
None => {
println!(" 🔄 Standard algorithm also found no path");
}
}
}
println!("\n📊 Computing all-pairs shortest paths with tropical algebra...");
let all_pairs_tropical = tropical_network.all_pairs_shortest_paths()?;
println!(
"✅ Computed shortest paths between all {} city pairs",
cities.len()
);
println!("\n📋 Travel time matrix (in hours):");
print!(" ");
for (_, name) in &city_indices {
print!("{:>8}", &name[..4.min(name.len())]);
}
println!();
for (i, (_, from_name)) in city_indices.iter().enumerate() {
print!("{:>8}", &from_name[..4.min(from_name.len())]);
#[allow(clippy::needless_range_loop)]
for j in 0..cities.len() {
let distance = all_pairs_tropical[i][j];
if distance.is_zero() {
print!(" ∞ "); } else if i == j {
print!(" 0 "); } else {
print!("{:>8.1}", distance.value());
}
}
println!();
}
println!("\n🔍 Network connectivity analysis:");
let mut reachable_pairs = 0;
let mut total_distance = 0.0;
let mut max_distance = 0.0;
let mut max_distance_pair = (0, 0);
for (i, row) in all_pairs_tropical.iter().enumerate().take(cities.len()) {
for (j, distance) in row.iter().enumerate().take(cities.len()) {
if i != j && !distance.is_zero() {
reachable_pairs += 1;
let dist_value = distance.value();
total_distance += dist_value;
if dist_value > max_distance {
max_distance = dist_value;
max_distance_pair = (i, j);
}
}
}
}
let total_pairs = cities.len() * (cities.len() - 1);
let connectivity = (reachable_pairs as f64 / total_pairs as f64) * 100.0;
let average_distance = if reachable_pairs > 0 {
total_distance / reachable_pairs as f64
} else {
0.0
};
println!(
" • Network connectivity: {:.1}% ({}/{} pairs reachable)",
connectivity, reachable_pairs, total_pairs
);
println!(" • Average travel time: {:.1} hours", average_distance);
println!(
" • Longest route: {} → {} ({:.1} hours)",
city_indices[max_distance_pair.0].1, city_indices[max_distance_pair.1].1, max_distance
);
println!("\n🌟 Computing tropical betweenness centrality...");
let tropical_betweenness = tropical_network.tropical_betweenness()?;
println!("✅ Centrality analysis complete");
let mut centrality_ranking: Vec<(f64, &str)> = tropical_betweenness
.iter()
.enumerate()
.map(|(i, ¢rality)| (centrality, city_indices[i].1))
.collect();
centrality_ranking.sort_by(|a, b| b.0.partial_cmp(&a.0).unwrap());
println!("\n🏆 Cities ranked by tropical betweenness centrality:");
for (i, (centrality, city_name)) in centrality_ranking.iter().enumerate() {
if *centrality > 0.0 {
println!(" {}. {}: {:.4}", i + 1, city_name, centrality);
}
}
println!("\n🎉 Tropical path finding analysis complete!");
println!("This example demonstrated:");
println!(" ✓ Converting geometric networks to tropical representation");
println!(" ✓ Efficient shortest path computation using max-plus algebra");
println!(" ✓ All-pairs shortest path computation");
println!(" ✓ Network connectivity and efficiency analysis");
println!(" ✓ Tropical betweenness centrality calculation");
println!(" ✓ Practical applications in transportation networks");
Ok(())
}