use crate::smt::{EmlConstraint, Interval, IntervalDomain, PropResult};
pub fn interval_prune(constraint: &EmlConstraint, vars: &[Interval]) -> bool {
let bounds: Vec<(f64, f64)> = vars.iter().map(|iv| (iv.lo, iv.hi)).collect();
let n = bounds.len();
let mut domain = IntervalDomain::new(&bounds, n);
domain.propagate(constraint) == PropResult::Conflict
}
pub fn solver_prune(
constraint: &EmlConstraint,
vars: &[Interval],
min_depth: usize,
current_depth: usize,
) -> bool {
if current_depth < min_depth {
return false;
}
let bounds: Vec<(f64, f64)> = vars.iter().map(|iv| (iv.lo, iv.hi)).collect();
let solver = crate::smt::EmlSmtSolver::new(bounds);
match solver.check_sat(constraint) {
Ok(crate::smt::SmtResult::Unsat) => true,
Ok(crate::smt::SmtResult::Sat(_)) | Ok(crate::smt::SmtResult::Unknown) | Err(_) => false,
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::smt::{EmlConstraint, Interval};
use crate::tree::{EmlNode, EmlTree};
use std::sync::Arc;
fn var0_tree() -> EmlTree {
EmlTree::from_node(Arc::new(EmlNode::Var(0)))
}
fn const_neg_one_tree() -> EmlTree {
EmlTree::from_node(Arc::new(EmlNode::Const(-1.0)))
}
#[test]
fn test_interval_prune_conflict() {
let c = EmlConstraint::GeZero(const_neg_one_tree());
let vars = vec![Interval::new(0.0, 3.0)];
assert!(interval_prune(&c, &vars), "Const -1 >= 0 should conflict");
}
#[test]
fn test_interval_prune_feasible() {
let c = EmlConstraint::GeZero(var0_tree());
let vars = vec![Interval::new(0.0, 5.0)];
assert!(
!interval_prune(&c, &vars),
"var0 in [0,5] >= 0 should be feasible"
);
}
#[test]
fn test_solver_prune_depth_gate() {
let c = EmlConstraint::GeZero(const_neg_one_tree());
let vars = vec![Interval::new(0.0, 1.0)];
assert!(
!solver_prune(&c, &vars, 3, 1),
"Below min_depth should not prune"
);
}
#[test]
fn test_solver_prune_unsat() {
let c = EmlConstraint::GeZero(const_neg_one_tree());
let vars = vec![Interval::new(0.0, 1.0)];
assert!(solver_prune(&c, &vars, 0, 0), "Clear UNSAT should prune");
}
#[test]
fn test_solver_prune_sat_not_pruned() {
let c = EmlConstraint::GeZero(var0_tree());
let vars = vec![Interval::new(0.0, 10.0)];
assert!(
!solver_prune(&c, &vars, 0, 0),
"SAT constraint should not prune"
);
}
}