use vyre_primitives::graph::knowledge_compile::ddnnf_evaluate_cpu;
#[must_use]
pub fn pass_applies(
nodes: &[(u32, u32, u32)],
node_var: &[u32],
children: &[u32],
var_assignments: &[u32],
topo_order: &[u32],
) -> u32 {
use crate::observability::{bump, knowledge_compile_pass_precondition_calls};
bump(&knowledge_compile_pass_precondition_calls);
let evals = ddnnf_evaluate_cpu(nodes, node_var, children, var_assignments, topo_order);
if topo_order.is_empty() {
return 0;
}
let Some(root) = topo_order.last().copied() else {
return 0;
};
let root = root as usize;
evals[root]
}
#[must_use]
pub fn pass_conflicts(
nodes: &[(u32, u32, u32)],
node_var: &[u32],
children: &[u32],
var_assignments: &[u32],
topo_order: &[u32],
) -> bool {
pass_applies(nodes, node_var, children, var_assignments, topo_order) == 0
}
#[cfg(test)]
mod tests {
use super::*;
use vyre_primitives::graph::knowledge_compile::{AND_NODE, LITERAL_TRUE};
#[test]
fn unconditional_pass_always_applies() {
let nodes = vec![(LITERAL_TRUE, 0u32, 0u32)];
let node_var = vec![0u32];
let children: Vec<u32> = vec![];
let assignments = vec![1u32];
let topo = vec![0u32];
assert_eq!(
pass_applies(&nodes, &node_var, &children, &assignments, &topo),
1
);
assert!(!pass_conflicts(
&nodes,
&node_var,
&children,
&assignments,
&topo
));
}
#[test]
fn unconditional_pass_blocked_by_false_var() {
let nodes = vec![(LITERAL_TRUE, 0u32, 0u32)];
let node_var = vec![0u32];
let children: Vec<u32> = vec![];
let assignments = vec![0u32];
let topo = vec![0u32];
assert_eq!(
pass_applies(&nodes, &node_var, &children, &assignments, &topo),
0
);
assert!(pass_conflicts(
&nodes,
&node_var,
&children,
&assignments,
&topo
));
}
#[test]
fn conjunctive_pass_requires_both() {
let nodes = vec![
(LITERAL_TRUE, 0u32, 0u32), (LITERAL_TRUE, 0u32, 0u32), (AND_NODE, 0u32, 2u32), ];
let node_var = vec![0u32, 1u32, 0u32];
let children = vec![0u32, 1u32];
let topo = vec![0u32, 1u32, 2u32];
let both_true = vec![1u32, 1u32];
assert_eq!(
pass_applies(&nodes, &node_var, &children, &both_true, &topo),
1
);
let one_false = vec![1u32, 0u32];
assert_eq!(
pass_applies(&nodes, &node_var, &children, &one_false, &topo),
0
);
}
#[test]
fn empty_topo_returns_zero() {
let nodes: Vec<(u32, u32, u32)> = vec![];
let node_var: Vec<u32> = vec![];
let children: Vec<u32> = vec![];
let assignments: Vec<u32> = vec![];
let topo: Vec<u32> = vec![];
assert_eq!(
pass_applies(&nodes, &node_var, &children, &assignments, &topo),
0
);
}
}