antecedent_graph/
ancestry.rs1use crate::dag::Dag;
6use crate::error::GraphError;
7use crate::overlay::GraphOverlay;
8use crate::types::DenseNodeId;
9use crate::workspace::{BitSet, GraphWorkspace};
10
11impl Dag {
12 pub fn ancestors_of(&self, nodes: &[DenseNodeId], out: &mut BitSet, ws: &mut GraphWorkspace) {
14 self.ancestors_of_with(nodes, out, ws, None);
15 }
16
17 pub(crate) fn ancestors_of_with(
19 &self,
20 nodes: &[DenseNodeId],
21 out: &mut BitSet,
22 ws: &mut GraphWorkspace,
23 overlay: Option<&GraphOverlay>,
24 ) {
25 let n = self.node_count();
26 out.resize(n);
27 out.clear();
28 ws.prepare(n);
29 for &v in nodes {
30 if v.as_usize() >= n {
31 continue;
32 }
33 if !out.contains(v) {
34 out.insert(v);
35 ws.frontier.push(v);
36 }
37 }
38 while let Some(u) = ws.frontier.pop() {
39 for &p in self.parents(u) {
40 if let Some(ov) = overlay {
41 if !ov.edge_visible(p, u) {
42 continue;
43 }
44 }
45 if !out.contains(p) {
46 out.insert(p);
47 ws.frontier.push(p);
48 }
49 }
50 }
51 }
52
53 pub fn descendants_of(&self, nodes: &[DenseNodeId], out: &mut BitSet, ws: &mut GraphWorkspace) {
55 self.descendants_of_with(nodes, out, ws, None);
56 }
57
58 pub(crate) fn descendants_of_with(
60 &self,
61 nodes: &[DenseNodeId],
62 out: &mut BitSet,
63 ws: &mut GraphWorkspace,
64 overlay: Option<&GraphOverlay>,
65 ) {
66 let n = self.node_count();
67 out.resize(n);
68 out.clear();
69 ws.prepare(n);
70 for &v in nodes {
71 if v.as_usize() >= n {
72 continue;
73 }
74 if !out.contains(v) {
75 out.insert(v);
76 ws.frontier.push(v);
77 }
78 }
79 while let Some(u) = ws.frontier.pop() {
80 for &c in self.children(u) {
81 if let Some(ov) = overlay {
82 if !ov.edge_visible(u, c) {
83 continue;
84 }
85 }
86 if !out.contains(c) {
87 out.insert(c);
88 ws.frontier.push(c);
89 }
90 }
91 }
92 }
93
94 #[must_use]
96 pub fn is_ancestor(&self, anc: DenseNodeId, desc: DenseNodeId) -> bool {
97 self.reaches(anc, desc)
98 }
99
100 pub fn markov_blanket(&self, node: DenseNodeId, out: &mut BitSet) -> Result<(), GraphError> {
107 self.validate_node_pub(node)?;
108 let n = self.node_count();
109 out.resize(n);
110 out.clear();
111 for &p in self.parents(node) {
112 out.insert(p);
113 }
114 for &c in self.children(node) {
115 out.insert(c);
116 for &spouse in self.parents(c) {
117 if spouse != node {
118 out.insert(spouse);
119 }
120 }
121 }
122 Ok(())
123 }
124
125 pub fn markov_blanket_nodes(&self, node: DenseNodeId) -> Result<Vec<DenseNodeId>, GraphError> {
131 let mut bits = BitSet::with_len(self.node_count());
132 self.markov_blanket(node, &mut bits)?;
133 Ok((0..self.node_count())
134 .map(|i| DenseNodeId::from_raw(u32::try_from(i).expect("node fit")))
135 .filter(|&id| bits.contains(id))
136 .collect())
137 }
138
139 pub fn mutilate(&self, intervened: &[DenseNodeId]) -> Result<Dag, GraphError> {
149 for &v in intervened {
150 self.validate_node_pub(v)?;
151 }
152 let overlay = GraphOverlay::do_intervention(self.node_count(), intervened);
153 self.view(&overlay).materialize()
154 }
155
156 pub(crate) fn validate_node_pub(&self, id: DenseNodeId) -> Result<(), GraphError> {
157 if id.as_usize() >= self.node_count() {
158 Err(GraphError::UnknownNode { id: id.raw() })
159 } else {
160 Ok(())
161 }
162 }
163}
164
165#[cfg(test)]
166mod tests {
167 use super::*;
168
169 #[test]
170 fn markov_blanket_includes_parents_children_spouses() {
171 let mut graph = Dag::with_variables(5);
173 let parent_a = DenseNodeId::from_raw(0);
174 let parent_b = DenseNodeId::from_raw(1);
175 let treatment = DenseNodeId::from_raw(2);
176 let outcome = DenseNodeId::from_raw(3);
177 let spouse_c = DenseNodeId::from_raw(4);
178 graph.insert_directed(parent_a, treatment).unwrap();
179 graph.insert_directed(parent_b, treatment).unwrap();
180 graph.insert_directed(treatment, outcome).unwrap();
181 graph.insert_directed(spouse_c, outcome).unwrap();
182
183 let mb = graph.markov_blanket_nodes(treatment).unwrap();
184 assert_eq!(mb, vec![parent_a, parent_b, outcome, spouse_c]);
185 assert!(!mb.contains(&treatment));
186 }
187
188 #[test]
189 fn markov_blanket_of_root_includes_child_and_spouse() {
190 let mut graph = Dag::with_variables(3);
191 let parent_a = DenseNodeId::from_raw(0);
192 let parent_b = DenseNodeId::from_raw(1);
193 let outcome = DenseNodeId::from_raw(2);
194 graph.insert_directed(parent_a, outcome).unwrap();
195 graph.insert_directed(parent_b, outcome).unwrap();
196 assert_eq!(graph.markov_blanket_nodes(outcome).unwrap(), vec![parent_a, parent_b]);
197 assert_eq!(graph.markov_blanket_nodes(parent_a).unwrap(), vec![parent_b, outcome]);
198 }
199}