use {
crate::{
FilterVertices,
Order,
OutNeighbors,
Tarjan,
Vertices,
},
std::collections::BTreeSet,
};
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Johnson75<'a, D> {
a: &'a D,
b: Vec<BTreeSet<usize>>,
blocked: BTreeSet<usize>,
stack: Vec<usize>,
}
impl<'a, D> Johnson75<'a, D> {
#[must_use]
pub fn new(a: &'a D) -> Self
where
D: Order,
{
Self {
a,
b: vec![BTreeSet::new(); a.order()],
blocked: BTreeSet::new(),
stack: Vec::new(),
}
}
#[must_use]
fn is_blocked(&self, u: usize) -> bool {
self.blocked.contains(&u)
}
fn unblock(&mut self, u: usize) {
if self.is_blocked(u) {
let _ = self.blocked.remove(&u);
let b_ptr = self.b.as_mut_ptr();
while let Some(v) = unsafe { (*b_ptr.add(u)).pop_first() } {
self.unblock(v);
}
}
}
#[must_use]
fn circuit(
&mut self,
v: usize,
s: usize,
scc: &D,
result: &mut Vec<Vec<usize>>,
) -> bool
where
D: OutNeighbors,
{
self.stack.push(v);
let mut f = false;
let _ = self.blocked.insert(v);
for w in scc.out_neighbors(v) {
if w == s {
result.push(self.stack.clone());
f = true;
} else if !self.is_blocked(w) && self.circuit(w, s, scc, result) {
f = true;
}
}
if f {
self.unblock(v);
} else {
let b_ptr = self.b.as_mut_ptr();
for w in scc.out_neighbors(v) {
let _ = unsafe { (*b_ptr.add(w)).insert(v) };
}
}
let _ = self.stack.pop();
f
}
#[must_use]
pub fn circuits(&mut self) -> Vec<Vec<usize>>
where
D: FilterVertices + Order + OutNeighbors + Vertices,
{
let mut result = Vec::new();
for s in self.a.vertices() {
let subgraph = self.a.filter_vertices(|u| u >= s);
let mut tarjan = Tarjan::new(&subgraph);
let components = tarjan.components();
if let Some(min_scc) =
components.iter().min_by_key(|scc| scc.iter().min())
{
let component =
self.a.filter_vertices(|u| min_scc.contains(&u));
if component.order() > 0 {
let &start = min_scc.iter().min().unwrap();
let b_ptr = self.b.as_mut_ptr();
for vertex in component.vertices() {
let _ = self.blocked.remove(&vertex);
unsafe {
if let Some(b_set) = b_ptr.add(vertex).as_mut() {
b_set.clear();
}
};
}
let _ =
self.circuit(start, start, &component, &mut result);
}
}
}
result
}
}
#[cfg(test)]
mod tests {
use {
super::*,
crate::{
AdjacencyMap,
Biclique,
Circuit,
Cycle,
},
};
#[test]
fn biclique_2_2() {
let digraph = AdjacencyMap::biclique(2, 2);
assert!(Johnson75::new(&digraph).circuits().eq(&[
vec![0, 2],
vec![0, 2, 1, 3],
vec![0, 3],
vec![0, 3, 1, 2],
vec![1, 2],
vec![1, 3]
]));
}
#[test]
fn biclique_2_3() {
let digraph = AdjacencyMap::biclique(2, 3);
assert!(Johnson75::new(&digraph).circuits().eq(&[
vec![0, 2],
vec![0, 2, 1, 3],
vec![0, 2, 1, 4],
vec![0, 3],
vec![0, 3, 1, 2],
vec![0, 3, 1, 4],
vec![0, 4],
vec![0, 4, 1, 2],
vec![0, 4, 1, 3],
vec![1, 2],
vec![1, 3],
vec![1, 4]
]));
}
#[test]
fn circuit_3() {
let digraph = AdjacencyMap::circuit(3);
assert!(Johnson75::new(&digraph).circuits().eq(&[vec![0, 1, 2]]));
}
#[test]
fn circuit_4() {
let digraph = AdjacencyMap::circuit(4);
assert!(Johnson75::new(&digraph).circuits().eq(&[vec![0, 1, 2, 3]]));
}
#[test]
fn circuit_5() {
let digraph = AdjacencyMap::circuit(5);
assert!(
Johnson75::new(&digraph)
.circuits()
.eq(&[vec![0, 1, 2, 3, 4]])
);
}
#[test]
fn cycle_3() {
let digraph = AdjacencyMap::cycle(3);
assert!(Johnson75::new(&digraph).circuits().eq(&[
vec![0, 1],
vec![0, 1, 2],
vec![0, 2],
vec![0, 2, 1],
vec![1, 2]
]));
}
#[test]
fn cycle_4() {
let digraph = AdjacencyMap::cycle(4);
assert!(Johnson75::new(&digraph).circuits().eq(&[
vec![0, 1],
vec![0, 1, 2, 3],
vec![0, 3],
vec![0, 3, 2, 1],
vec![1, 2],
vec![2, 3]
]));
}
#[test]
fn cycle_5() {
let digraph = AdjacencyMap::cycle(5);
assert!(Johnson75::new(&digraph).circuits().eq(&[
vec![0, 1],
vec![0, 1, 2, 3, 4],
vec![0, 4],
vec![0, 4, 3, 2, 1],
vec![1, 2],
vec![2, 3],
vec![3, 4]
]));
}
}