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;
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() {
ctx.calc_feedback_set_recursive(node);
}
ctx.feedback_set
}
struct FeedbackSetAlgoContext<Node: ComputeScc> {
pending: VecDeque<SccGraphNode<Node>>,
feedback_set: OrderedHashSet<Node::NodeId>,
in_flight: UnorderedHashSet<Node::NodeId>,
visited: UnorderedHashSet<Node::NodeId>,
}
impl<Node: ComputeScc> FeedbackSetAlgoContext<Node> {
fn calc_feedback_set_recursive(&mut self, node: SccGraphNode<Node>) {
let cur_node_id = node.get_id();
if !self.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 {
self.feedback_set.insert(cur_node_id.clone());
} else {
self.in_flight.insert(cur_node_id.clone());
for neighbor in remaining_neighbors.by_ref() {
let neighbor_id = neighbor.get_id();
if self.feedback_set.contains(&neighbor_id) {
continue;
} else if self.in_flight.contains(&neighbor_id) {
self.feedback_set.insert(neighbor_id);
} else {
self.calc_feedback_set_recursive(neighbor);
}
if self.feedback_set.contains(&cur_node_id) {
break;
}
}
self.in_flight.remove(&cur_node_id);
};
self.pending
.extend(remaining_neighbors.filter(|node| !self.visited.contains(&node.get_id())));
}
}