use std::time::Instant;
use petgraph::graph::{NodeIndex, UnGraph};
use rand::rngs::StdRng;
use rand::{Rng, SeedableRng};
use graphlet::rim::scalable::fast_graphlet_degree_vectors;
use graphlet::{graphlet_degree_vectors, Registry};
const EXACT_BUDGET_SECS: f64 = 45.0;
fn gnp(n: usize, p: f64, rng: &mut impl Rng) -> UnGraph<(), ()> {
let mut g = UnGraph::with_capacity(n, 0);
for _ in 0..n {
g.add_node(());
}
for i in 0..n {
for j in (i + 1)..n {
if rng.gen_bool(p) {
g.add_edge(NodeIndex::new(i), NodeIndex::new(j), ());
}
}
}
g
}
fn main() {
let mut rng = StdRng::seed_from_u64(0xDECA_5CA1_AB1E_u64);
let reg = Registry::build();
let sweeps: &[(f64, &[usize])] = &[
(0.1, &[20, 40, 60, 80, 100, 150, 200]),
(0.3, &[20, 40, 60, 80, 100, 150]),
];
println!(
"{:>4} {:>5} {:>14} {:>12} {:>10}",
"n", "p", "exact_ms", "fast_ms", "speedup"
);
for &(p, sizes) in sweeps {
let mut exact_retired = false;
for &n in sizes {
let g = gnp(n, p, &mut rng);
let exact_dur = if exact_retired {
None
} else {
let t0 = Instant::now();
let exact = graphlet_degree_vectors(&g, ®);
let d = t0.elapsed();
let fast_check = fast_graphlet_degree_vectors(&g, ®);
assert_eq!(exact.len(), fast_check.len());
for i in 0..exact.len() {
assert_eq!(
exact.row(i),
fast_check.row(i),
"fast/exact GDV mismatch at n={n}, p={p}, node {i}"
);
}
if d.as_secs_f64() > EXACT_BUDGET_SECS {
exact_retired = true;
}
Some(d)
};
let t1 = Instant::now();
let _fast = fast_graphlet_degree_vectors(&g, ®);
let fast_dur = t1.elapsed();
match exact_dur {
Some(ex) => {
let speedup = ex.as_secs_f64() / fast_dur.as_secs_f64().max(1e-12);
println!(
"{:>4} {:>5.2} {:>14.3} {:>12.3} {:>9.1}x",
n,
p,
ex.as_secs_f64() * 1000.0,
fast_dur.as_secs_f64() * 1000.0,
speedup
);
}
None => {
println!(
"{:>4} {:>5.2} {:>14} {:>12.3} {:>10}",
n,
p,
"impractical",
fast_dur.as_secs_f64() * 1000.0,
"-"
);
}
}
}
}
}