use std::collections::HashSet;
use petgraph::visit::{EdgeRef, IntoEdgeReferences, IntoNodeIdentifiers, NodeCount, NodeIndexable};
pub trait DirectedGraphAdapter:
IntoNodeIdentifiers + IntoEdgeReferences + NodeIndexable + NodeCount + Copy
{
}
impl<G> DirectedGraphAdapter for G where
G: IntoNodeIdentifiers + IntoEdgeReferences + NodeIndexable + NodeCount + Copy
{
}
#[derive(Clone, Debug)]
pub struct DirectedSnapshot<N> {
ids: Vec<N>,
arc: Vec<Vec<usize>>,
arc_set: Vec<HashSet<usize>>,
und: Vec<Vec<usize>>,
und_set: Vec<HashSet<usize>>,
}
impl<N: Copy> DirectedSnapshot<N> {
#[must_use]
pub fn new<G>(g: G) -> Self
where
G: DirectedGraphAdapter<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 arc_set: Vec<HashSet<usize>> = vec![HashSet::new(); n];
let mut und_set: Vec<HashSet<usize>> = vec![HashSet::new(); n];
for e in g.edge_references() {
let a = compact[g.to_index(e.source())];
let b = compact[g.to_index(e.target())];
if a == b {
continue; }
arc_set[a].insert(b);
und_set[a].insert(b);
und_set[b].insert(a);
}
let sorted = |s: &[HashSet<usize>]| -> Vec<Vec<usize>> {
s.iter()
.map(|set| {
let mut v: Vec<usize> = set.iter().copied().collect();
v.sort_unstable();
v
})
.collect()
};
let arc = sorted(&arc_set);
let und = sorted(&und_set);
DirectedSnapshot {
ids,
arc,
arc_set,
und,
und_set,
}
}
#[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 out_neighbors(&self, i: usize) -> &[usize] {
&self.arc[i]
}
#[inline]
#[must_use]
pub fn has_arc(&self, a: usize, b: usize) -> bool {
self.arc_set[a].contains(&b)
}
#[inline]
#[must_use]
pub fn undirected_neighbors(&self, i: usize) -> &[usize] {
&self.und[i]
}
#[inline]
#[must_use]
pub fn undirected_adjacent(&self, a: usize, b: usize) -> bool {
self.und_set[a].contains(&b)
}
}