#[macro_use]
extern crate criterion;
use criterion::Criterion;
use itertools::Itertools;
use pathfinding::prelude::{
astar, bfs, dfs, dijkstra, fringe, idastar, iddfs, separate_components,
};
use rand::prelude::SliceRandom;
use rand::{Rng, RngCore, SeedableRng};
use rand_xorshift::XorShiftRng;
use std::collections::HashSet;
use std::usize;
#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
struct Pt {
x: u16,
y: u16,
}
impl Pt {
fn new(x: u16, y: u16) -> Pt {
Pt { x, y }
}
#[inline]
fn heuristic(p: &Pt) -> usize {
(128 - p.x - p.y) as usize
}
}
#[inline]
fn successors(pt: &Pt) -> Vec<Pt> {
let mut ret = Vec::with_capacity(4);
if 0 < pt.x {
ret.push(Pt::new(pt.x - 1, pt.y))
}
if pt.x < 64 {
ret.push(Pt::new(pt.x + 1, pt.y))
}
if 0 < pt.y {
ret.push(Pt::new(pt.x, pt.y - 1))
}
if pt.y < 64 {
ret.push(Pt::new(pt.x, pt.y + 1))
}
ret
}
fn corner_to_corner_astar(c: &mut Criterion) {
c.bench_function("corner_to_corner_astar", |b| {
b.iter(|| {
assert_ne!(
astar(
&Pt::new(0, 0),
|n| successors(n).into_iter().map(|n| (n, 1)),
Pt::heuristic,
|n| n.x == 64 && n.y == 64,
),
None
)
})
});
}
fn corner_to_corner_bfs(c: &mut Criterion) {
c.bench_function("corner_to_corner_bfs", |b| {
b.iter(|| {
assert_ne!(
bfs(
&Pt::new(0, 0),
|n| successors(n),
|n| n.x == 64 && n.y == 64,
),
None
)
})
});
}
fn corner_to_corner_dfs(c: &mut Criterion) {
c.bench_function("corner_to_corner_dfs", |b| {
b.iter(|| {
assert_ne!(
dfs(Pt::new(0, 0), |n| successors(n), |n| n.x == 64 && n.y == 64),
None
)
})
});
}
fn corner_to_corner_dijkstra(c: &mut Criterion) {
c.bench_function("corner_to_corner_dijkstra", |b| {
b.iter(|| {
assert_ne!(
dijkstra(
&Pt::new(0, 0),
|n| successors(n).into_iter().map(|n| (n, 1)),
|n| n.x == 64 && n.y == 64,
),
None
)
})
});
}
fn corner_to_corner_fringe(c: &mut Criterion) {
c.bench_function("corner_to_corner_fringe", |b| {
b.iter(|| {
assert_ne!(
fringe(
&Pt::new(0, 0),
|n| successors(n).into_iter().map(|n| (n, 1)),
Pt::heuristic,
|n| n.x == 64 && n.y == 64,
),
None
)
})
});
}
fn corner_to_corner_idastar(c: &mut Criterion) {
c.bench_function("corner_to_corner_idastar", |b| {
b.iter(|| {
assert_ne!(
idastar(
&Pt::new(0, 0),
|n| successors(n).into_iter().map(|n| (n, 1)),
Pt::heuristic,
|n| n.x == 64 && n.y == 64,
),
None
)
})
});
}
fn corner_to_corner_iddfs(c: &mut Criterion) {
c.bench_function("corner_to_corner_iddfs", |b| {
b.iter(|| {
assert_ne!(
iddfs(Pt::new(0, 0), |n| successors(n), |n| n.x == 5 && n.y == 5,),
None
)
})
});
}
fn no_path_astar(c: &mut Criterion) {
c.bench_function("no_path_astar", |b| {
b.iter(|| {
assert_eq!(
astar(
&Pt::new(2, 3),
|n| successors(n).into_iter().map(|n| (n, 1)),
|_| 1,
|_| false,
),
None
)
})
});
}
fn no_path_bfs(c: &mut Criterion) {
c.bench_function("no_path_bfs", |b| {
b.iter(|| assert_eq!(bfs(&Pt::new(2, 3), |n| successors(n), |_| false), None))
});
}
fn no_path_dijkstra(c: &mut Criterion) {
c.bench_function("no_path_dijkstra", |b| {
b.iter(|| {
assert_eq!(
dijkstra(
&Pt::new(2, 3),
|n| successors(n).into_iter().map(|n| (n, 1)),
|_| false,
),
None
)
})
});
}
fn no_path_fringe(c: &mut Criterion) {
c.bench_function("no_path_fringe", |b| {
b.iter(|| {
assert_eq!(
fringe(
&Pt::new(2, 3),
|n| successors(n).into_iter().map(|n| (n, 1)),
|_| 1,
|_| false,
),
None
)
})
});
}
fn bench_separate_components(c: &mut Criterion) {
c.bench_function("separate_components", |b| {
let mut rng = XorShiftRng::from_seed([
3, 42, 93, 129, 1, 85, 72, 42, 84, 23, 95, 212, 253, 10, 4, 2,
]);
let mut seen = HashSet::new();
let mut components = (0..100)
.map(|_| {
let mut component = Vec::new();
for _ in 0..100 {
let node = rng.next_u64();
if !seen.contains(&node) {
seen.insert(node);
component.push(node);
}
}
component.sort();
assert!(
!component.is_empty(),
"component is empty, rng seed needs changing"
);
component
})
.collect_vec();
components.sort_by_key(|c| c[0]);
let mut groups = components
.iter()
.flat_map(|component| {
let mut component = component.clone();
component.shuffle(&mut rng);
let mut subcomponents = Vec::new();
while !component.is_empty() {
let cut = rng.gen_range(0, component.len());
let mut subcomponent = component.drain(cut..).collect_vec();
if !component.is_empty() {
subcomponent.push(component[0]);
}
subcomponents.shuffle(&mut rng);
subcomponents.push(subcomponent);
}
subcomponents
})
.collect_vec();
groups.shuffle(&mut rng);
b.iter(|| separate_components(&groups));
});
}
criterion_group!(
benches,
corner_to_corner_astar,
corner_to_corner_bfs,
corner_to_corner_dfs,
corner_to_corner_dijkstra,
corner_to_corner_fringe,
corner_to_corner_idastar,
corner_to_corner_iddfs,
no_path_astar,
no_path_bfs,
no_path_dijkstra,
no_path_fringe,
bench_separate_components,
);
criterion_main!(benches);