use deep_causality_topology::MixedGraph;
use std::collections::{BTreeMap, BTreeSet};
pub fn has_new_unshielded_collider_at<N>(
graph: &MixedGraph<N>,
node: usize,
baseline_parents: &BTreeSet<usize>,
) -> bool {
let parents = graph.parents(node);
for i in 0..parents.len() {
for j in (i + 1)..parents.len() {
let (a, b) = (parents[i], parents[j]);
let shielded = graph.is_adjacent(a, b);
let in_baseline = baseline_parents.contains(&a) && baseline_parents.contains(&b);
if !(shielded || in_baseline) {
return true;
}
}
}
false
}
pub fn has_new_unshielded_collider_any<N>(
graph: &MixedGraph<N>,
targets: &[usize],
baseline: &BTreeMap<usize, BTreeSet<usize>>,
) -> bool {
let empty = BTreeSet::new();
targets.iter().any(|&node| {
has_new_unshielded_collider_at(graph, node, baseline.get(&node).unwrap_or(&empty))
})
}
pub fn is_valid_configuration<N>(
graph: &mut MixedGraph<N>,
targets: &[usize],
baseline: &BTreeMap<usize, BTreeSet<usize>>,
) -> bool {
graph.meek_complete();
if graph.has_cycle() {
return false;
}
!has_new_unshielded_collider_any(graph, targets, baseline)
}
pub fn baseline_parents<N>(
graph: &MixedGraph<N>,
targets: &[usize],
) -> BTreeMap<usize, BTreeSet<usize>> {
targets
.iter()
.map(|&node| (node, graph.parents(node).into_iter().collect()))
.collect()
}