use std::cmp::max;
use std::collections::VecDeque;
use rustc_hash::FxHashSet;
use crate::bubbles::finder::SuperbubbleFinder;
use crate::graphs::{AlignableRefGraph, NodeIndexType};
#[derive(Copy, Clone)]
enum BubbleNode<N> {
None,
Entrance(N),
Exit(N)
}
impl<N> BubbleNode<N> {
#[inline]
pub fn is_entrance(&self) -> bool {
matches!(self, BubbleNode::Entrance(_))
}
#[inline]
pub fn is_exit(&self) -> bool {
matches!(self, BubbleNode::Exit(_))
}
}
#[derive(Clone)]
pub struct BubbleIndex<N> {
bubble_entrance: Vec<BubbleNode<N>>,
bubble_exit: Vec<BubbleNode<N>>,
node_bubble_map: Vec<Vec<NodeBubbleMap<N>>>,
dist_to_end: Vec<(usize, usize)>
}
impl<N> BubbleIndex<N>
where
N: NodeIndexType,
{
pub fn new<G>(graph: &G) -> Self
where G: AlignableRefGraph<NodeIndex=N>
{
let finder = SuperbubbleFinder::new(graph);
let mut bubble_entrances = vec![BubbleNode::None; graph.node_count_with_start_and_end()];
let mut bubble_exits = vec![BubbleNode::None; graph.node_count_with_start_and_end()];
for (entrance, exit) in finder.iter() {
bubble_entrances[entrance.index()] = BubbleNode::Entrance(exit);
bubble_exits[exit.index()] = BubbleNode::Exit(entrance);
}
let mut node_bubble_map = vec![Vec::default(); graph.node_count_with_start_and_end()];
let mut dists_to_end = vec![(0, 0); graph.node_count_with_start_and_end()];
let end_node_bubblestack = if bubble_exits[graph.end_node().index()].is_exit() {
vec![(0usize, graph.end_node())]
} else {
Vec::default()
};
let mut queue: VecDeque<_> = vec![
(graph.end_node(), 0usize, end_node_bubblestack)
].into();
let mut visited = FxHashSet::default();
visited.insert(graph.end_node());
while !queue.is_empty() {
let (curr, dist_from_end, bubble_stack) = queue.pop_front().unwrap();
for (bubble_dist_from_end, bubble_exit) in bubble_stack.iter() {
node_bubble_map[curr.index()].push(NodeBubbleMap {
bubble_exit: *bubble_exit,
min_dist_to_exit: dist_from_end - *bubble_dist_from_end,
max_dist_to_exit: 0 })
}
dists_to_end[curr.index()].0 = dist_from_end;
for pred in graph.predecessors(curr) {
if !visited.contains(&pred) {
let new_dist_from_end = dist_from_end + 1;
let mut new_bubble_stack = bubble_stack.clone();
if bubble_entrances[pred.index()].is_entrance() {
let (bubble_dist_from_start, bubble_exit) = new_bubble_stack.pop().unwrap();
node_bubble_map[pred.index()].push(NodeBubbleMap {
bubble_exit,
min_dist_to_exit: new_dist_from_end - bubble_dist_from_start,
max_dist_to_exit: 0 });
}
if bubble_exits[pred.index()].is_exit() {
new_bubble_stack.push((new_dist_from_end, pred));
}
visited.insert(pred);
queue.push_back((pred, new_dist_from_end, new_bubble_stack));
}
}
}
for n in finder.inv_rev_postorder().iter().rev() {
let mut max_dist_to_end = 0;
for succ in graph.successors(*n) {
max_dist_to_end = max(max_dist_to_end, dists_to_end[succ.index()].1 + 1);
}
dists_to_end[n.index()].1 = max_dist_to_end;
for bubble in node_bubble_map[n.index()].iter_mut() {
bubble.max_dist_to_exit = max_dist_to_end - dists_to_end[bubble.bubble_exit.index()].1;
}
}
Self {
bubble_entrance: bubble_entrances,
bubble_exit: bubble_exits,
node_bubble_map,
dist_to_end: dists_to_end
}
}
#[inline]
pub fn is_entrance(&self, node: N) -> bool {
self.bubble_entrance[node.index()].is_entrance()
}
#[inline]
pub fn is_exit(&self, node: N) -> bool {
self.bubble_exit[node.index()].is_exit()
}
#[inline]
pub fn get_node_bubbles(&self, node: N) -> &[NodeBubbleMap<N>] {
&self.node_bubble_map[node.index()]
}
#[inline]
pub fn node_is_part_of_bubble(&self, node: N) -> bool {
!self.node_bubble_map[node.index()].is_empty()
}
#[inline]
pub fn num_bubbles(&self) -> usize {
self.bubble_entrance.iter()
.filter(|v| v.is_entrance())
.count()
}
#[inline]
pub fn get_min_dist_to_end(&self, node: N) -> usize {
self.dist_to_end[node.index()].0
}
#[inline]
pub fn get_max_dist_to_end(&self, node: N) -> usize {
self.dist_to_end[node.index()].1
}
#[inline]
pub fn get_dist_to_end(&self) -> &[(usize, usize)] {
&self.dist_to_end
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct NodeBubbleMap<N> {
pub bubble_exit: N,
pub min_dist_to_exit: usize,
pub max_dist_to_exit: usize
}
impl<N> NodeBubbleMap<N>
where
N: NodeIndexType,
{
pub fn new(bubble_exit: N, min_dist_to_exit: usize, max_dist_to_exit: usize) -> Self {
NodeBubbleMap {
bubble_exit,
min_dist_to_exit,
max_dist_to_exit
}
}
}