use std::collections::HashSet;
use petgraph::visit::{IntoNeighborsDirected, IntoNodeIdentifiers, NodeCount, NodeIndexable};
use petgraph::Direction;
pub trait GraphAdapter:
IntoNodeIdentifiers + IntoNeighborsDirected + NodeIndexable + NodeCount + Copy
{
}
impl<G> GraphAdapter for G where
G: IntoNodeIdentifiers + IntoNeighborsDirected + NodeIndexable + NodeCount + Copy
{
}
#[derive(Clone, Debug)]
pub struct Snapshot<N> {
ids: Vec<N>,
adj: Vec<Vec<usize>>,
nbr: Vec<HashSet<usize>>,
}
impl<N: Copy> Snapshot<N> {
#[must_use]
pub fn new<G>(g: G) -> Self
where
G: GraphAdapter<NodeId = N>,
{
let bound = g.node_bound();
let mut compact = vec![usize::MAX; bound];
let mut ids: Vec<N> = Vec::new();
for v in g.node_identifiers() {
compact[g.to_index(v)] = ids.len();
ids.push(v);
}
let n = ids.len();
let mut adj = vec![Vec::new(); n];
let mut seen = vec![usize::MAX; n];
for v in g.node_identifiers() {
let vi = compact[g.to_index(v)];
for dir in [Direction::Outgoing, Direction::Incoming] {
for u in g.neighbors_directed(v, dir) {
let ui = compact[g.to_index(u)];
if ui != vi && seen[ui] != vi {
seen[ui] = vi;
adj[vi].push(ui);
}
}
}
}
for row in &mut adj {
row.sort_unstable();
}
let nbr = adj.iter().map(|r| r.iter().copied().collect()).collect();
Snapshot { ids, adj, nbr }
}
#[inline]
#[must_use]
pub fn len(&self) -> usize {
self.ids.len()
}
#[inline]
#[must_use]
pub fn is_empty(&self) -> bool {
self.ids.is_empty()
}
#[inline]
#[must_use]
pub fn id(&self, i: usize) -> N {
self.ids[i]
}
#[inline]
#[must_use]
pub fn neighbors(&self, i: usize) -> &[usize] {
&self.adj[i]
}
#[inline]
#[must_use]
pub fn adjacent(&self, a: usize, b: usize) -> bool {
self.nbr[a].contains(&b)
}
}