smt_scope/analysis/graph/
hide.rs

1use petgraph::{
2    graph::{DiGraph, EdgeReference, NodeIndex},
3    visit::{Bfs, EdgeFiltered, EdgeRef, Reversed, ReversedEdgeReference, Walker},
4};
5
6use super::{
7    raw::{EdgeKind, IndexesInstGraph, Node, NodeState, RawInstGraph, RawIx},
8    InstGraph, RawNodeIndex,
9};
10
11type PathToRoot<'a, T> = EdgeFiltered<Reversed<&'a DiGraph<Node, EdgeKind, RawIx>>, T>;
12type PathToLeaf<'a, T> = EdgeFiltered<&'a DiGraph<Node, EdgeKind, RawIx>, T>;
13
14impl RawInstGraph {
15    pub fn reset_visibility_to(&mut self, hidden: bool) -> bool {
16        let state = if hidden {
17            NodeState::Hidden
18        } else {
19            NodeState::Visible
20        };
21        let mut modified = false;
22        for node in self.graph.node_weights_mut().filter(|n| !n.disabled()) {
23            modified |= self.stats.set_state(node, state);
24        }
25        modified
26    }
27    pub fn can_set_visibility(&self, node: &Node, hidden: bool) -> bool {
28        !node.disabled() && node.hidden() != hidden
29    }
30    pub fn set_visibility<I: IndexesInstGraph>(&mut self, node: I, hidden: bool) -> bool {
31        let node = node.index(self);
32        let node = &mut self.graph[node.0];
33        if node.disabled() {
34            return false;
35        }
36        self.stats.set_state(
37            node,
38            if hidden {
39                NodeState::Hidden
40            } else {
41                NodeState::Visible
42            },
43        )
44    }
45
46    pub fn keep_first_n(
47        &mut self,
48        nodes: impl Iterator<Item = RawNodeIndex>,
49        mut n: usize,
50    ) -> bool {
51        let mut modified = false;
52        for node in nodes {
53            if n == 0 {
54                modified |= self.set_visibility(node, true);
55            } else if self[node].visible() {
56                n -= 1;
57            }
58        }
59        modified
60    }
61
62    /// When predicate `p` evaluates to true the visibility of the corresponding
63    /// node is set to `hidden`. Use this when hiding nodes and the predicate is
64    /// expensive as it avoids calling the predicate a lot more than
65    /// `set_visibility_all`.
66    pub fn set_visibility_when(
67        &mut self,
68        hidden: bool,
69        mut p: impl FnMut(&Self, RawNodeIndex, &Node) -> bool,
70    ) -> bool {
71        let mut modified = false;
72        for node in self.graph.node_indices().map(RawNodeIndex) {
73            let n = &self[node];
74            if !self.can_set_visibility(n, hidden) {
75                continue;
76            }
77            if p(self, node, n) {
78                modified |= self.set_visibility(node, hidden);
79            }
80        }
81        modified
82    }
83    /// When predicate `p` evaluates to `Some` the visibility of the corresponding
84    /// node is set to `hidden` (`true`) or `visible` (`false`).
85    pub fn set_visibility_all(
86        &mut self,
87        mut p: impl FnMut(&Self, RawNodeIndex, &Node) -> Option<bool>,
88    ) -> bool {
89        let mut modified = false;
90        for node in self.graph.node_indices().map(RawNodeIndex) {
91            let n = &self[node];
92            if n.disabled() {
93                continue;
94            }
95            if let Some(hidden) = p(self, node, n) {
96                modified |= self.set_visibility(node, hidden);
97            }
98        }
99        modified
100    }
101
102    pub fn set_visibility_many<I: IndexesInstGraph>(
103        &mut self,
104        hidden: bool,
105        nodes: impl Iterator<Item = I>,
106    ) -> bool {
107        let mut modified = false;
108        for node in nodes {
109            let node = node.index(self);
110            modified |= self.set_visibility(node, hidden);
111        }
112        modified
113    }
114
115    fn filter_path(
116        &self,
117        edge: impl EdgeRef<NodeId = NodeIndex<RawIx>>,
118        f: impl Fn(&Node) -> u16,
119    ) -> bool {
120        let from = &self.graph[edge.source()];
121        let to = &self.graph[edge.target()];
122        if from.disabled() {
123            f(from) == f(to)
124        } else {
125            f(from) == f(to).saturating_add(1)
126        }
127    }
128    /// A graph with edges that aren't part of any `longest/shortest` path to a
129    /// root filtered out. The edges are also reversed, so the graph can be
130    /// walked from any node to find the longest/shortest path to a root.
131    pub fn path_to_root_graph(
132        &self,
133        longest: bool,
134    ) -> PathToRoot<'_, impl Fn(ReversedEdgeReference<EdgeReference<EdgeKind, RawIx>>) -> bool + '_>
135    {
136        let f = move |depth: &Node| {
137            if longest {
138                depth.fwd_depth.max
139            } else {
140                depth.fwd_depth.min
141            }
142        };
143        let filter = move |edge: ReversedEdgeReference<EdgeReference<EdgeKind, RawIx>>| {
144            self.filter_path(edge, f)
145        };
146        EdgeFiltered::from_fn(self.rev(), filter)
147    }
148    /// A graph with edges that aren't part of any `longest/shortest` path to a
149    /// leaf filtered out. The graph can be walked from any node to find the
150    /// longest/shortest path to a leaf.
151    pub fn path_to_leaf_graph(
152        &self,
153        longest: bool,
154    ) -> PathToLeaf<'_, impl Fn(EdgeReference<EdgeKind, RawIx>) -> bool + '_> {
155        let f = move |depth: &Node| {
156            if longest {
157                depth.bwd_depth.max
158            } else {
159                depth.bwd_depth.min
160            }
161        };
162        let filter = move |edge: EdgeReference<EdgeKind, RawIx>| self.filter_path(edge, f);
163        EdgeFiltered::from_fn(&self.graph, filter)
164    }
165
166    pub fn show_longest_path_through(&mut self, node: RawNodeIndex) -> (bool, Vec<RawNodeIndex>) {
167        let mut path: Vec<_> = {
168            let to_root = self.path_to_root_graph(true);
169            Bfs::new(&to_root, node.0)
170                .iter(&to_root)
171                .map(RawNodeIndex)
172                .collect()
173        };
174        path.reverse();
175        {
176            let to_leaf = self.path_to_leaf_graph(true);
177            let to_leaf = Bfs::new(&to_leaf, node.0).iter(&to_leaf).skip(1);
178            path.extend(to_leaf.map(RawNodeIndex));
179        };
180        path.retain(|&n| !self[n].disabled());
181        let modified = self.set_visibility_many(false, path.iter().copied());
182        (modified, path)
183    }
184}
185
186impl InstGraph {
187    pub fn keep_first_n_cost(&mut self, n: usize) -> bool {
188        let (top_cost, other) = self.analysis.first_n_cost(&self.raw, n);
189        let cost = top_cost.iter().chain(other).copied();
190        let cost = cost.chain(self.subgraphs.singletons());
191        self.raw.keep_first_n(cost, n)
192    }
193    pub fn keep_first_n_children(&mut self, n: usize) -> bool {
194        let (top_children, other) = self.analysis.first_n_children(&self.raw, n);
195        let children = top_children.iter().chain(other).copied();
196        let children = children.chain(self.subgraphs.singletons());
197        self.raw.keep_first_n(children, n)
198    }
199    pub fn keep_first_n_fwd_depth_min(&mut self, n: usize) -> bool {
200        let (top_fwd_depth_min, other) = self.analysis.first_n_fwd_depth_min(&self.raw, n);
201        let fwd_depth_min = top_fwd_depth_min.iter().chain(other).copied();
202        let fwd_depth_min = fwd_depth_min.chain(self.subgraphs.singletons());
203        self.raw.keep_first_n(fwd_depth_min, n)
204    }
205}