use super::*;
use crate::{
EntityRef, EntitySet, PrimaryMap, SecondaryMap, non_max::NonMaxU32,
packed_option::PackedOption, prelude::*,
};
use alloc::collections::BTreeSet;
use core::{
cmp,
fmt::{self, Debug},
hash::Hash,
iter,
ops::Range,
};
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Scc(u32);
crate::entity_impl!(Scc);
pub struct StronglyConnectedComponents<Node>
where
Node: EntityRef,
{
components: PrimaryMap<Scc, Range<u32>>,
component_nodes: Vec<Node>,
}
impl<Node> Debug for StronglyConnectedComponents<Node>
where
Node: EntityRef + Debug,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
struct Map<'a, Node: EntityRef + Debug>(&'a StronglyConnectedComponents<Node>);
impl<'a, Node> Debug for Map<'a, Node>
where
Node: EntityRef + Debug,
{
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> fmt::Result {
f.debug_map().entries(self.0.iter()).finish()
}
}
f.debug_struct("StronglyConnectedComponents")
.field("components", &Map(self))
.finish()
}
}
impl<Node> StronglyConnectedComponents<Node>
where
Node: EntityRef + Debug,
{
pub fn new<G>(graph: G) -> Self
where
G: Graph<Node>,
{
let nodes = graph.nodes();
let mut component_nodes = vec![];
let mut components = PrimaryMap::<Scc, Range<u32>>::new();
let mut index = NonMaxU32::default();
let (min, max) = nodes.size_hint();
let capacity = max.unwrap_or_else(|| 2 * min);
let mut indices = SecondaryMap::<Node, Option<NonMaxU32>>::with_capacity(capacity);
let mut lowlinks = SecondaryMap::<Node, Option<NonMaxU32>>::with_capacity(capacity);
let mut stack = vec![];
let mut on_stack = EntitySet::<Node>::new();
let mut dfs = Dfs::new(nodes);
while let Some(event) = dfs.next(
&graph,
|node| indices[node].is_some(),
) {
match event {
DfsEvent::Pre(node) => {
debug_assert!(indices[node].is_none());
debug_assert!(lowlinks[node].is_none());
indices[node] = Some(index);
lowlinks[node] = Some(index);
index = NonMaxU32::new(index.get() + 1).unwrap();
stack.push(node);
let is_newly_on_stack = on_stack.insert(node);
debug_assert!(is_newly_on_stack);
}
DfsEvent::AfterEdge(node, succ) => {
debug_assert!(indices[node].is_some());
debug_assert!(lowlinks[node].is_some());
debug_assert!(lowlinks[node] <= indices[node]);
debug_assert!(indices[succ].is_some());
debug_assert!(lowlinks[succ].is_some());
debug_assert!(lowlinks[succ] <= indices[succ]);
if on_stack.contains(succ) {
lowlinks[node] =
Some(cmp::min(lowlinks[node].unwrap(), lowlinks[succ].unwrap()));
}
}
DfsEvent::Post(node) => {
debug_assert!(indices[node].is_some());
debug_assert!(lowlinks[node].is_some());
if indices[node] == lowlinks[node] {
let mut done = false;
components.push(extend_with_range(
&mut component_nodes,
iter::from_fn(|| {
if done {
return None;
}
let v = stack.pop().unwrap();
let was_on_stack = on_stack.remove(v);
debug_assert!(was_on_stack);
if v == node {
done = true;
}
Some(v)
}),
));
}
}
}
}
Self {
components,
component_nodes,
}
}
pub fn len(&self) -> usize {
self.components.len()
}
fn node_range(&self, range: Range<u32>) -> &[Node] {
let start = usize::try_from(range.start).unwrap();
let end = usize::try_from(range.end).unwrap();
&self.component_nodes[start..end]
}
pub fn iter(&self) -> impl ExactSizeIterator<Item = (Scc, &[Node])> + '_ {
self.components
.iter()
.map(|(component, range)| (component, self.node_range(range.clone())))
}
pub fn keys(&self) -> impl ExactSizeIterator<Item = Scc> {
self.components.keys()
}
#[cfg(test)]
pub fn values(&self) -> impl ExactSizeIterator<Item = &[Node]> + '_ {
self.components
.values()
.map(|range| self.node_range(range.clone()))
}
pub fn nodes(&self, component: Scc) -> &[Node] {
let range = self.components[component].clone();
self.node_range(range)
}
pub fn evaporation<G>(&self, graph: G) -> Evaporation
where
G: Graph<Node>,
{
log::trace!("Creating the evaporation of {self:#?}");
let node_to_component: SecondaryMap<Node, PackedOption<Scc>> = self
.iter()
.flat_map(|(c, nodes)| {
nodes
.iter()
.copied()
.map(move |node| (node, PackedOption::from(Some(c))))
})
.collect();
let mut reverse_edge_set = BTreeSet::<(Scc, Scc)>::new();
for (from_component, nodes) in self.iter() {
for node in nodes {
for succ in graph.successors(*node) {
let to_component = node_to_component[succ].unwrap();
if to_component == from_component {
continue;
}
reverse_edge_set.insert((to_component, from_component));
}
}
}
let mut reverse_edges =
SecondaryMap::<Scc, Range<u32>>::with_capacity(self.components.len());
let mut reverse_edge_elems = Vec::with_capacity(reverse_edge_set.len());
for (to_node, from_node) in reverse_edge_set {
let range = extend_with_range(&mut reverse_edge_elems, Some(from_node));
if reverse_edges[to_node] == Range::default() {
reverse_edges[to_node] = range;
} else {
debug_assert_eq!(reverse_edges[to_node].end, range.start);
reverse_edges[to_node].end = range.end;
}
}
let result = Evaporation {
reverse_edges,
reverse_edge_elems,
};
log::trace!(" -> {result:#?}");
result
}
}
pub struct Evaporation {
reverse_edges: SecondaryMap<Scc, Range<u32>>,
reverse_edge_elems: Vec<Scc>,
}
impl Debug for Evaporation {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
struct Map<'a>(&'a Evaporation);
impl<'a> Debug for Map<'a> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_map()
.entries(
self.0
.reverse_edges
.keys()
.map(|k| (k, self.0.reverse_edges(k))),
)
.finish()
}
}
f.debug_struct("Evaporation")
.field("reverse_edges", &Map(self))
.finish()
}
}
impl Evaporation {
pub fn reverse_edges(&self, component: Scc) -> &[Scc] {
let Range { start, end } = self.reverse_edges[component].clone();
let start = usize::try_from(start).unwrap();
let end = usize::try_from(end).unwrap();
&self.reverse_edge_elems[start..end]
}
}
#[cfg(test)]
mod tests {
use super::*;
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Node(u32);
crate::entity_impl!(Node);
#[derive(Debug)]
struct Graph {
edges: SecondaryMap<Node, Vec<Node>>,
}
impl Default for Graph {
fn default() -> Self {
let _ = env_logger::try_init();
Self {
edges: Default::default(),
}
}
}
impl Graph {
fn define(&mut self, node: u32, edges: impl IntoIterator<Item = u32>) -> &mut Self {
assert!(self.edges[Node::from_u32(node)].is_empty());
self.edges[Node::from_u32(node)].extend(edges.into_iter().map(|v| Node::from_u32(v)));
self
}
}
impl super::Graph<Node> for Graph {
type NodesIter<'a>
= cranelift_entity::Keys<Node>
where
Self: 'a;
fn nodes(&self) -> Self::NodesIter<'_> {
self.edges.keys()
}
type SuccessorsIter<'a>
= core::iter::Copied<core::slice::Iter<'a, Node>>
where
Self: 'a;
fn successors(&self, node: Node) -> Self::SuccessorsIter<'_> {
self.edges[node].iter().copied()
}
}
fn components(graph: &Graph) -> Vec<Vec<u32>> {
let components = StronglyConnectedComponents::new(graph);
components
.values()
.map(|vs| vs.iter().map(|v| v.as_u32()).collect::<Vec<_>>())
.collect()
}
#[test]
fn test_empty() {
let graph = Graph::default();
assert!(components(&graph).is_empty());
}
#[test]
fn test_single_node() {
let mut graph = Graph::default();
graph.define(0, []);
assert_eq!(components(&graph), vec![vec![0]]);
}
#[test]
fn test_single_node_cycle() {
let mut graph = Graph::default();
graph.define(0, [0]);
assert_eq!(components(&graph), vec![vec![0]]);
}
#[test]
fn test_disconnected_nodes() {
let mut graph = Graph::default();
graph.define(0, []);
graph.define(1, []);
assert_eq!(components(&graph), vec![vec![1], vec![0]]);
}
#[test]
fn test_chained_nodes() {
let mut graph = Graph::default();
graph.define(0, []);
graph.define(1, [0]);
graph.define(2, [1]);
graph.define(3, [2]);
assert_eq!(components(&graph), vec![vec![0], vec![1], vec![2], vec![3]]);
}
#[test]
fn test_simple_multi_node_cycle() {
let mut graph = Graph::default();
graph.define(0, [3]);
graph.define(1, [0]);
graph.define(2, [1]);
graph.define(3, [2]);
assert_eq!(components(&graph), vec![vec![0, 1, 2, 3]]);
}
#[test]
fn test_complicated_multi_node_cycle() {
let mut graph = Graph::default();
graph.define(0, [3]);
graph.define(1, [0]);
graph.define(2, [1, 4]);
graph.define(3, [2]);
graph.define(4, [3]);
assert_eq!(components(&graph), vec![vec![0, 1, 2, 3, 4]]);
}
#[test]
fn test_disconnected_cycles() {
let mut graph = Graph::default();
graph.define(0, [2]);
graph.define(1, [3]);
graph.define(2, [0]);
graph.define(3, [1]);
assert_eq!(components(&graph), vec![vec![1, 3], vec![0, 2]]);
}
#[test]
fn test_chain_of_cycles() {
let mut graph = Graph::default();
graph.define(0, [0, 1]);
graph.define(1, [2, 3]);
graph.define(2, [1]);
graph.define(3, [5]);
graph.define(4, [3]);
graph.define(5, [4]);
assert_eq!(components(&graph), vec![vec![3, 4, 5], vec![1, 2], vec![0]]);
}
#[test]
fn test_multiple_edges_to_same_component() {
let mut graph = Graph::default();
graph.define(0, [2]);
graph.define(1, [3]);
graph.define(2, [0, 4]);
graph.define(3, [1, 4]);
graph.define(4, [5]);
graph.define(5, [4]);
assert_eq!(components(&graph), vec![vec![4, 5], vec![1, 3], vec![0, 2]]);
}
#[test]
fn test_duplicate_edges() {
let mut graph = Graph::default();
graph.define(0, [2]);
graph.define(1, [3]);
graph.define(2, [0, 3, 3]);
graph.define(3, [1]);
assert_eq!(components(&graph), vec![vec![1, 3], vec![0, 2]]);
}
}