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