use std::collections::VecDeque;
use super::graph_node::GraphNode;
use super::scc_graph_node::SccGraphNode;
use super::strongly_connected_components::ComputeScc;
use crate::ordered_hash_set::OrderedHashSet;
use crate::unordered_hash_set::UnorderedHashSet;
#[cfg(test)]
#[path = "feedback_set_test.rs"]
mod feedback_set_test;
struct FeedbackSetAlgoContext<Node: ComputeScc> {
pending: VecDeque<SccGraphNode<Node>>,
feedback_set: OrderedHashSet<Node::NodeId>,
in_flight: UnorderedHashSet<Node::NodeId>,
visited: UnorderedHashSet<Node::NodeId>,
}
pub fn calc_feedback_set<Node: ComputeScc>(
node: SccGraphNode<Node>,
) -> OrderedHashSet<Node::NodeId> {
let mut ctx = FeedbackSetAlgoContext {
feedback_set: OrderedHashSet::default(),
in_flight: UnorderedHashSet::default(),
pending: VecDeque::new(),
visited: UnorderedHashSet::default(),
};
ctx.pending.push_back(node);
while let Some(node) = ctx.pending.pop_front() {
calc_feedback_set_recursive(node, &mut ctx);
}
ctx.feedback_set
}
fn calc_feedback_set_recursive<Node: ComputeScc>(
node: SccGraphNode<Node>,
ctx: &mut FeedbackSetAlgoContext<Node>,
) {
let cur_node_id = node.get_id();
if !ctx.visited.insert(cur_node_id.clone()) {
return;
};
let neighbors = node.get_neighbors();
let has_self_loop = neighbors.iter().any(|neighbor| neighbor.get_id() == cur_node_id);
let mut remaining_neighbors = neighbors.into_iter();
if has_self_loop {
ctx.feedback_set.insert(cur_node_id.clone());
} else {
ctx.in_flight.insert(cur_node_id.clone());
for neighbor in remaining_neighbors.by_ref() {
let neighbor_id = neighbor.get_id();
if ctx.feedback_set.contains(&neighbor_id) {
continue;
} else if ctx.in_flight.contains(&neighbor_id) {
ctx.feedback_set.insert(neighbor_id);
} else {
calc_feedback_set_recursive(neighbor, ctx);
}
if ctx.feedback_set.contains(&cur_node_id) {
break;
}
}
ctx.in_flight.remove(&cur_node_id);
};
ctx.pending.extend(remaining_neighbors.filter(|node| !ctx.visited.contains(&node.get_id())));
}