1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
//! `domtree` provides facilities a generic implementation to calculate the dominator tree of
//! a directed graph. The algorithm basically follows the description in
//! "A Simple, Fast Dominance Algorithm" by Keith D. Cooper, Timothy J. Harvey, and Ken Kennedy.
//!
//! To implement the trait for your own graph structure, you need to prepare several fields:
//! ```ignore
//! #[derive(Clone)]
//! struct VecSet<Y>(Vec<Y>);
//!
//! impl<Y: Clone + Default> AssocSet<usize, Y> for VecSet<Y> {
//!     fn get(&self, target: usize) -> Y {
//!         self.0[target].clone()
//!     }
//!
//!     fn set(&mut self, key: usize, val: Y) {
//!         self.0[key] = val;
//!     }
//! }
//!
//! #[derive(Clone, Debug)]
//! struct HashMemberSet<T>(HashSet<T>);
//! impl<T : PartialEq + Eq + Hash> MemberSet<T> for HashMemberSet<T>  {
//!     fn contains(&self, target: T) -> bool {
//!         self.0.contains(&target)
//!     }
//!
//!     fn insert(&mut self, target: T) {
//!         self.0.insert(target);
//!     }
//! }
//!
//! #[derive(Debug)]
//! struct Node {
//!     tag: usize,                                  // node's identifier
//!     dom: Option<usize>,                          // node's immediate dominator
//!     frontiers: UnsafeCell<HashMemberSet<usize>>, // node's dominance frontiers
//!     incoming_edges: Vec<usize>,                  // node's in-edges
//!     outgoing_edges: Vec<usize>                   // node's out-edges
//! }
//!
//! #[derive(Debug)]
//! struct Graph {
//!     nodes: Vec<Node>,
//! }
//! ```
//! Then, one needs to first expose some APIs such that this crate can run DFS on the graph.
//! ```ignore
//! use std::iter::Cloned;
//! use std::slice::Iter;
//! use domtree::dfs::DFSGraph;
//! impl DFSGraph for Graph {
//!     type Identifier = usize;
//!     type Set<Y> = VecSet<Y>  where Y: Clone + Default;
//!     type SuccessorIter<'a> = Cloned<Iter<'a, usize>> where Self: 'a;
//!
//!     fn create_set<Y>(&self) -> Self::Set<Y> where Y: Clone + Default {
//!         let mut data = Vec::new();
//!         data.resize(self.nodes.len(), Default::default());
//!         VecSet(data)
//!     }
//!
//!     fn outgoing_edges<'a>(&'a self, id: Self::Identifier) -> Self::SuccessorIter<'a> {
//!         self.nodes[id].outgoing_edges.iter().cloned()
//!     }
//! }
//! ```
//! After this, one also need to specify how the algorithm can access the fields related to the
//! dominance tree.
//! ```ignore
//! impl DomTree for Graph {
//!     type MutDomIter<'a> = Map<IterMut<'a, Node>, fn(&'a mut Node)->&'a mut Option<usize>> where Self: 'a;
//!     type PredecessorIter<'a> = Cloned<Iter<'a, usize>> where Self: 'a;
//!
//!     fn dom(&self, id: Self::Identifier) -> Option<Self::Identifier> {
//!         self.nodes[id].dom.clone()
//!     }
//!
//!     fn set_dom(&mut self, id: Self::Identifier, target: Option<Self::Identifier>) {
//!         self.nodes[id].dom = target;
//!     }
//!
//!     fn predecessor_iter<'a>(&'a self, id: Self::Identifier) -> Self::PredecessorIter<'a> {
//!         self.nodes[id].incoming_edges.iter().cloned()
//!     }
//!
//!     fn doms_mut<'a>(&'a mut self) -> Self::MutDomIter<'a> {
//!         self.nodes.iter_mut().map(|x|&mut x.dom)
//!     }
//! }
//!
//! impl DominanceFrontier for Graph {
//!     type FrontierSet = HashMemberSet<usize>;
//!     type NodeIter<'a> = Range<usize> where Self: 'a ;
//!
//!     fn frontiers_cell(&self, id: Self::Identifier) -> &UnsafeCell<Self::FrontierSet> {
//!         &self.nodes[id].frontiers
//!     }
//!
//!     fn node_iter<'a>(&'a self) -> Self::NodeIter<'a> {
//!         0..self.nodes.len()
//!     }
//! }
//! ```
//! Then, one can just run populate the dominance tree and the dominance frontiers
//! ```ignore
//! let mut g = random_graph(10000);
//! dump_graph(&g);
//! g.populate_dom(0);
//! g.populate_frontiers();
//! ```
use crate::dfs::DFSGraph;
use crate::set::{AssocSet, MemberSet};
use std::cell::UnsafeCell;

/// DFS related interfaces.
pub mod dfs;
/// Housekeeping data structure interfaces.
pub mod set;

#[cfg(test)]
mod test;

/// An iterator over the dominators of a given node.
pub struct DominatorIter<'a, T: DomTree> {
    tree: &'a T,
    current: T::Identifier,
}

impl<'a, T: DomTree> Iterator for DominatorIter<'a, T> {
    type Item = T::Identifier;
    fn next(&mut self) -> Option<Self::Item> {
        let dom = self.tree.dom(self.current).filter(|x| *x != self.current);
        if let Some(x) = dom {
            self.current = x;
        }
        dom
    }
}

/// Interfaces related to Dominance Tree construction.
pub trait DomTree: DFSGraph + Sized {
    /// [`Self::MutDomIter`] is used in [`Self::doms_mut`] to get an iterator
    /// over all nodes and return the mutable references to their immediate dominator identifiers.
    type MutDomIter<'a>: Iterator<Item = &'a mut Option<Self::Identifier>>
    where
        Self: 'a;
    /// [`Self::PredecessorIter`] is similiar to [`DFSGraph::SuccessorIter`], but it returns
    /// incoming edges instead.
    type PredecessorIter<'a>: Iterator<Item = Self::Identifier>
    where
        Self: 'a;

    /// Returns the identifier of the immediate dominator of the given node.
    fn dom(&self, id: Self::Identifier) -> Option<Self::Identifier>;
    /// Updates the immediate dominator identifier of the given node.
    fn set_dom(&mut self, id: Self::Identifier, target: Option<Self::Identifier>);
    /// Returns an iterator over the incoming edges of the given node.
    fn predecessor_iter<'a>(&'a self, id: Self::Identifier) -> Self::PredecessorIter<'a>;
    /// Returns an iterator over all nodes which yields the mutable references to their immediate
    /// dominator identifiers.
    fn doms_mut<'a>(&'a mut self) -> Self::MutDomIter<'a>;
    /// Returns an iterator over all the **strict** dominators of a node.
    fn dom_iter(&self, id: Self::Identifier) -> DominatorIter<Self> {
        DominatorIter {
            tree: self,
            current: id,
        }
    }
    /// Calculate all the immediate dominator for all nodes. This will form the dominator tree.
    fn populate_dom(&mut self, root: Self::Identifier) {
        // two-pointer algorithm to trace LCA.
        fn intersect<D: DomTree>(
            tree: &D,
            order_map: &D::Set<usize>,
            mut x: D::Identifier,
            mut y: D::Identifier,
        ) -> D::Identifier {
            unsafe {
                while x != y {
                    while order_map.get(x) < order_map.get(y) {
                        // safe because we are processing in reverse post order.
                        x = tree.dom(x).unwrap_unchecked();
                    }
                    while order_map.get(y) < order_map.get(x) {
                        // safe because we are processing in reverse post order.
                        y = tree.dom(y).unwrap_unchecked();
                    }
                }
            }
            return x;
        }
        // initialize all immediate dominators to None.
        self.doms_mut().for_each(|x| *x = None);
        // set root to be its own immediate dominator.
        self.set_dom(root, Some(root));

        // establish post oder using DFS.
        let post_order = self.post_order_sequence(root);
        let mut post_order_map = self.create_set();
        for (i, k) in post_order.iter().cloned().enumerate() {
            post_order_map.set(k, i);
        }

        // Iterate until the fixed point is reached.
        let mut changed = true;
        while changed {
            changed = false;
            for (order, i) in post_order.iter().cloned().enumerate().rev() {
                if i == root {
                    continue;
                }
                let dom = unsafe {
                    self.predecessor_iter(i)
                        .filter(|x| post_order_map.get(*x) > order)
                        .next()
                        // safe because we are processing in reverse post order.
                        .unwrap_unchecked()
                };
                let dom = self
                    .predecessor_iter(i)
                    .filter(|x| *x != dom && self.dom(*x).is_some())
                    .fold(dom, |dom, x| intersect(self, &post_order_map, x, dom));

                if self.dom(i).map(|x| x != dom).unwrap_or(true) {
                    self.set_dom(i, Some(dom));
                    changed = true;
                }
            }
        }
    }
}

/// Interfaces related to dominance frontier calculation
pub trait DominanceFrontier: DomTree {
    /// [`Self::FrontierSet`] is used to maintain the dominance frontier.
    /// Each node should hold a separate [`Self::FrontierSet`].
    type FrontierSet: MemberSet<Self::Identifier>;
    /// [`Self::NodeIter`] is an iterator over all nodes of the graph.
    type NodeIter<'a>: Iterator<Item = Self::Identifier>
    where
        Self: 'a;
    /// Due to mutable reference limitations, the trait expects [`Self::FrontierSet`] to
    /// be wrapped in a [`UnsafeCell`] to allow iterated update. This method is used to
    /// access the [`UnsafeCell`].
    fn frontiers_cell(&self, id: Self::Identifier) -> &UnsafeCell<Self::FrontierSet>;
    /// A helper function that is auto derived for user to access the dominance frontiers of
    /// the given node.
    fn frontiers(&self, id: Self::Identifier) -> &Self::FrontierSet {
        unsafe { &*self.frontiers_cell(id).get() }
    }
    /// Gets an iterator over all nodes of the graph.
    fn node_iter<'a>(&'a self) -> Self::NodeIter<'a>;

    /// Calculate the dominance frontiers of all nodes. The immediate dominators must be
    /// calculated before calling this function. Otherwise, it will not crash but the answers can get
    /// wrong.
    fn populate_frontiers(&mut self) {
        for i in self.node_iter() {
            for mut p in self.predecessor_iter(i) {
                if let Some(dom) = self.dom(i) {
                    while p != dom {
                        unsafe {
                            (*self.frontiers_cell(p).get()).insert(i);
                        }
                        if let Some(pdom) = self.dom(p) {
                            p = pdom;
                        } else {
                            break;
                        }
                    }
                }
            }
        }
    }
}