use std::collections::BTreeSet;
use std::sync::Arc;
use antecedent_core::VariableId;
use crate::{Admg, GraphError};
#[derive(Clone, Debug)]
pub struct SelectionDiagram {
causal_graph: Admg,
selection_targets: Arc<[VariableId]>,
}
impl SelectionDiagram {
pub fn try_new(
causal_graph: Admg,
selection_targets: impl Into<Arc<[VariableId]>>,
) -> Result<Self, GraphError> {
let selection_targets = selection_targets.into();
let mut seen = BTreeSet::new();
for target in selection_targets.iter().copied() {
if target.as_usize() >= causal_graph.node_count() {
return Err(GraphError::UnknownNode { id: target.raw() });
}
if !seen.insert(target.raw()) {
return Err(GraphError::InvalidSelectionDiagram {
message: "selection targets must be unique".into(),
});
}
}
Ok(Self { causal_graph, selection_targets })
}
#[must_use]
pub const fn causal_graph(&self) -> &Admg {
&self.causal_graph
}
#[must_use]
pub fn selection_targets(&self) -> &[VariableId] {
&self.selection_targets
}
#[must_use]
pub fn mechanism_may_differ(&self, variable: VariableId) -> bool {
self.selection_targets.contains(&variable)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn selection_targets_are_not_graph_nodes() {
let graph = Admg::with_variables(3);
let diagram = SelectionDiagram::try_new(graph, [VariableId::from_raw(1)]).unwrap();
assert_eq!(diagram.causal_graph().node_count(), 3);
assert!(diagram.mechanism_may_differ(VariableId::from_raw(1)));
}
}