use traj_dist_rs::distance::{
batch::{DistanceAlgorithm, Metric, cdist, pdist},
distance_type::DistanceType,
};
fn main() {
println!("============================================================");
println!("Batch Computation Examples");
println!("============================================================");
let num_trajectories = 10;
let trajectories: Vec<Vec<[f64; 2]>> = (0..num_trajectories)
.map(|_| {
(0..20)
.map(|_| [rand::random::<f64>() * 10.0, rand::random::<f64>() * 10.0])
.collect()
})
.collect();
println!(
"\nCreated {} trajectories with 20 points each",
num_trajectories
);
println!("\n1. pdist - Pairwise Distance Matrix (Compressed)");
println!("{}", "-".repeat(60));
let metric = Metric::new(DistanceAlgorithm::SSPD, DistanceType::Euclidean);
match pdist(&trajectories, &metric, false, true) {
Ok(compressed_distances) => {
println!(
" Number of pairwise distances: {}",
compressed_distances.len()
);
println!(
" Expected: {}",
num_trajectories * (num_trajectories - 1) / 2
);
println!(" First 5 distances:");
for (i, &dist) in compressed_distances.iter().take(5).enumerate() {
println!(" [{}]: {:.6}", i, dist);
}
let min_dist = compressed_distances
.iter()
.cloned()
.fold(f64::INFINITY, f64::min);
let max_dist = compressed_distances
.iter()
.cloned()
.fold(f64::NEG_INFINITY, f64::max);
println!(" Min distance: {:.6}", min_dist);
println!(" Max distance: {:.6}", max_dist);
}
Err(e) => {
println!(" Error: {}", e);
}
}
println!("\n2. pdist with Different Algorithms");
println!("{}", "-".repeat(60));
let algorithms = vec![
(DistanceAlgorithm::SSPD, "SSPD"),
(DistanceAlgorithm::DTW, "DTW"),
(DistanceAlgorithm::Hausdorff, "Hausdorff"),
(DistanceAlgorithm::LCSS { eps: 0.1 }, "LCSS"),
(DistanceAlgorithm::EDR { eps: 0.1 }, "EDR"),
(DistanceAlgorithm::ERP { g: [0.0, 0.0] }, "ERP"),
(DistanceAlgorithm::Frechet, "Frechet"),
(DistanceAlgorithm::DiscretFrechet, "Discret Frechet"),
(DistanceAlgorithm::EDwP, "EDwP"),
];
for (algorithm, name) in algorithms {
let metric = Metric::new(algorithm, DistanceType::Euclidean);
match pdist(&trajectories, &metric, false, true) {
Ok(distances) => {
let mean = distances.iter().sum::<f64>() / distances.len() as f64;
println!(
" {:20}: {} distances, mean={:.6}",
name,
distances.len(),
mean
);
}
Err(e) => {
println!(" {:20}: Error - {}", name, e);
}
}
}
println!("\n3. cdist - Full Distance Matrix");
println!("{}", "-".repeat(60));
let traj_set_a: Vec<_> = trajectories.iter().take(5).cloned().collect();
let traj_set_b: Vec<_> = trajectories.iter().skip(5).cloned().collect();
let metric = Metric::new(DistanceAlgorithm::SSPD, DistanceType::Euclidean);
match cdist(&traj_set_a, &traj_set_b, &metric, false, true) {
Ok(distance_matrix) => {
let rows = traj_set_a.len();
let cols = traj_set_b.len();
println!(" Distance matrix shape: {}x{}", rows, cols);
println!(" Expected: {}x{}", rows, cols);
println!(" Full matrix:");
for row in 0..rows {
print!(" [");
for col in 0..cols {
let idx = row * cols + col;
if col > 0 {
print!(", ");
}
print!("{:.6}", distance_matrix[idx]);
}
println!("]");
}
}
Err(e) => {
println!(" Error: {}", e);
}
}
println!("\n4. cdist with Spherical Distance");
println!("{}", "-".repeat(60));
let geo_trajectories = vec![
vec![
[40.7128, -74.0060],
[40.7306, -73.9352],
[40.6413, -73.7781],
], vec![
[34.0522, -118.2437],
[34.0522, -118.2437],
[33.9425, -118.4081],
], vec![[51.5074, -0.1278], [51.4700, -0.4543], [51.5055, -0.2799]], ];
let metric = Metric::new(DistanceAlgorithm::SSPD, DistanceType::Spherical);
match cdist(&geo_trajectories, &geo_trajectories, &metric, false, true) {
Ok(distance_matrix) => {
let rows = geo_trajectories.len();
let cols = geo_trajectories.len();
println!(" Distance matrix (Haversine, in kilometers):");
for row in 0..rows {
print!(" [");
for col in 0..cols {
let idx = row * cols + col;
if col > 0 {
print!(", ");
}
print!("{:.3}", distance_matrix[idx] / 1000.0); }
println!("]");
}
}
Err(e) => {
println!(" Error: {}", e);
}
}
println!("\n5. pdist with Parallel Processing");
println!("{}", "-".repeat(60));
let metric = Metric::new(DistanceAlgorithm::SSPD, DistanceType::Euclidean);
match pdist(&trajectories, &metric, false, true) {
Ok(distances) => {
println!(" Sequential: {} distances computed", distances.len());
}
Err(e) => {
println!(" Sequential error: {}", e);
}
}
match pdist(&trajectories, &metric, true, true) {
Ok(distances) => {
println!(" Parallel: {} distances computed", distances.len());
}
Err(e) => {
println!(" Parallel error: {}", e);
}
}
println!("\n6. cdist with Parallel Processing");
println!("{}", "-".repeat(60));
let metric = Metric::new(DistanceAlgorithm::DTW, DistanceType::Euclidean);
match cdist(&traj_set_a, &traj_set_b, &metric, false, true) {
Ok(_matrix) => {
let rows = traj_set_a.len();
let cols = traj_set_b.len();
println!(" Sequential: {}x{} matrix computed", rows, cols);
}
Err(e) => {
println!(" Sequential error: {}", e);
}
}
match cdist(&traj_set_a, &traj_set_b, &metric, true, true) {
Ok(_matrix) => {
let rows = traj_set_a.len();
let cols = traj_set_b.len();
println!(" Parallel: {}x{} matrix computed", rows, cols);
}
Err(e) => {
println!(" Parallel error: {}", e);
}
}
println!("\n============================================================");
println!("All batch computations completed successfully!");
println!("============================================================");
}