use oxiz_sat::{Lit, Solver, SolverResult};
#[test]
fn test_xor_step_by_step() {
let mut sat = Solver::new();
let x = sat.new_var(); let a = sat.new_var(); let b = sat.new_var();
println!("Vars: x={}, a={}, b={}", x.index(), a.index(), b.index());
sat.add_clause([Lit::neg(x), Lit::neg(a), Lit::neg(b)]);
sat.add_clause([Lit::neg(x), Lit::pos(a), Lit::pos(b)]);
sat.add_clause([Lit::pos(x), Lit::neg(a), Lit::pos(b)]);
sat.add_clause([Lit::pos(x), Lit::pos(a), Lit::neg(b)]);
println!("\n=== Test: x=true, a=false should be SAT with b=true ===");
sat.add_clause([Lit::pos(x)]); sat.add_clause([Lit::neg(a)]);
let result = sat.solve();
println!("Result: {:?}", result);
if result == SolverResult::Sat {
let model = sat.model();
let xv = model[x.index()].is_true();
let av = model[a.index()].is_true();
let bv = model[b.index()].is_true();
println!("x={}, a={}, b={}", xv, av, bv);
let expected_x = av ^ bv;
println!(
"Verify: {} XOR {} = {}, x={}, match={}",
av,
bv,
expected_x,
xv,
expected_x == xv
);
assert!(xv, "x should be true");
assert!(!av, "a should be false");
assert!(bv, "b should be true (false XOR true = true)");
} else {
panic!("Should be SAT!");
}
}
#[test]
fn test_incremental_unit_clauses() {
let mut sat = Solver::new();
let x = sat.new_var();
let a = sat.new_var();
let b = sat.new_var();
sat.add_clause([Lit::neg(x), Lit::neg(a), Lit::neg(b)]);
sat.add_clause([Lit::neg(x), Lit::pos(a), Lit::pos(b)]);
sat.add_clause([Lit::pos(x), Lit::neg(a), Lit::pos(b)]);
sat.add_clause([Lit::pos(x), Lit::pos(a), Lit::neg(b)]);
println!("\n=== First solve (unconstrained) ===");
let r1 = sat.solve();
println!("Result: {:?}", r1);
assert_eq!(r1, SolverResult::Sat);
println!("\n=== Adding x=true ===");
sat.add_clause([Lit::pos(x)]);
let r2 = sat.solve();
println!("Result: {:?}", r2);
assert_eq!(r2, SolverResult::Sat);
if r2 == SolverResult::Sat {
let model = sat.model();
let xv = model[x.index()].is_true();
let av = model[a.index()].is_true();
let bv = model[b.index()].is_true();
println!("x={}, a={}, b={}", xv, av, bv);
assert!(xv, "x should be true");
assert!(av ^ bv, "Exactly one of a, b must be true when x=true");
}
println!("\n=== Adding a=false ===");
sat.add_clause([Lit::neg(a)]);
let r3 = sat.solve();
println!("Result: {:?}", r3);
assert_eq!(
r3,
SolverResult::Sat,
"Should be SAT with x=true, a=false, b=true"
);
if r3 == SolverResult::Sat {
let model = sat.model();
let xv = model[x.index()].is_true();
let av = model[a.index()].is_true();
let bv = model[b.index()].is_true();
println!("x={}, a={}, b={}", xv, av, bv);
assert!(xv, "x should be true");
assert!(!av, "a should be false");
assert!(bv, "b should be true (x=true, a=false => b=true)");
}
}
#[test]
fn test_verify_clauses() {
let mut sat = Solver::new();
let x = sat.new_var();
let a = sat.new_var();
let b = sat.new_var();
let clauses = vec![
vec![Lit::neg(x), Lit::neg(a), Lit::neg(b)], vec![Lit::neg(x), Lit::pos(a), Lit::pos(b)], vec![Lit::pos(x), Lit::neg(a), Lit::pos(b)], vec![Lit::pos(x), Lit::pos(a), Lit::neg(b)], ];
for c in &clauses {
sat.add_clause(c.iter().copied());
}
sat.add_clause([Lit::pos(x)]); sat.add_clause([Lit::neg(a)]);
let result = sat.solve();
println!("Result: {:?}", result);
if result == SolverResult::Sat {
let model = sat.model();
let lit_val = |l: Lit| -> bool {
let val = model[l.var().index()].is_true();
if l.is_pos() { val } else { !val }
};
println!("\nVerifying all clauses:");
for (i, clause) in clauses.iter().enumerate() {
let satisfied = clause.iter().any(|&l| lit_val(l));
let lits_str: Vec<String> = clause
.iter()
.map(|&l| {
let name = match l.var().index() {
0 => "x",
1 => "a",
2 => "b",
_ => "?",
};
if l.is_pos() {
name.to_string()
} else {
format!("~{}", name)
}
})
.collect();
println!(
" Clause {}: {:?} = {}",
i,
lits_str,
if satisfied { "SAT" } else { "VIOLATED!" }
);
assert!(satisfied, "Clause {} should be satisfied", i);
}
println!(" Unit x=true: {}", lit_val(Lit::pos(x)));
println!(" Unit a=false: {}", lit_val(Lit::neg(a)));
}
}