blob: 1a7fd428f10b9c4b85a41102bef55c47d5e4afcd [file] [log] [blame] [edit]
//! Checker tests, that require a Solver instance, so they cannot be unit tests of the
//! varisat-checker crate.
use anyhow::Error;
use proptest::prelude::*;
use varisat::{
checker::{Checker, ProofTranscriptProcessor, ProofTranscriptStep},
dimacs::write_dimacs,
CnfFormula, ExtendFormula, Lit, ProofFormat, Solver, Var,
};
use varisat_formula::test::{conditional_pigeon_hole, sgen_unsat_formula};
proptest! {
#[test]
fn checked_unsat_via_dimacs(formula in sgen_unsat_formula(1..7usize)) {
let mut dimacs = vec![];
let mut proof = vec![];
let mut solver = Solver::new();
write_dimacs(&mut dimacs, &formula).unwrap();
solver.write_proof(&mut proof, ProofFormat::Varisat);
solver.add_dimacs_cnf(&mut &dimacs[..]).unwrap();
prop_assert_eq!(solver.solve().ok(), Some(false));
solver.close_proof().map_err(|e| TestCaseError::fail(e.to_string()))?;
drop(solver);
let mut checker = Checker::new();
checker.add_dimacs_cnf(&mut &dimacs[..]).unwrap();
checker.check_proof(&mut &proof[..]).unwrap();
}
#[test]
fn sgen_checked_unsat_incremental_clauses(formula in sgen_unsat_formula(1..7usize)) {
let mut proof = vec![];
let mut solver = Solver::new();
solver.write_proof(&mut proof, ProofFormat::Varisat);
let mut expected_models = 0;
// Add all clauses incrementally so they are recorded in the proof
solver.solve().unwrap();
expected_models += 1;
let mut last_state = Some(true);
for clause in formula.iter() {
solver.add_clause(clause);
let state = solver.solve().ok();
if state != last_state {
prop_assert_eq!(state, Some(false));
prop_assert_eq!(last_state, Some(true));
last_state = state;
}
if state == Some(true) {
expected_models += 1;
}
}
prop_assert_eq!(last_state, Some(false));
drop(solver);
#[derive(Default)]
struct FoundModels {
counter: usize,
unsat: bool,
}
impl ProofTranscriptProcessor for FoundModels {
fn process_step(
&mut self,
step: &ProofTranscriptStep,
) -> Result<(), Error> {
if let ProofTranscriptStep::Model { .. } = step {
self.counter += 1;
} else if let ProofTranscriptStep::Unsat = step {
self.unsat = true;
}
Ok(())
}
}
let mut found_models = FoundModels::default();
let mut checker = Checker::new();
checker.add_transcript(&mut found_models);
checker.check_proof(&mut &proof[..]).unwrap();
prop_assert_eq!(found_models.counter, expected_models);
prop_assert!(found_models.unsat);
}
#[test]
fn pigeon_hole_checked_unsat_assumption_core(
(enable_row, columns, formula) in conditional_pigeon_hole(1..5usize, 1..5usize),
) {
let mut proof = vec![];
let mut solver = Solver::new();
solver.write_proof(&mut proof, ProofFormat::Varisat);
let mut expected_sat = 0;
let mut expected_unsat = 0;
solver.solve().unwrap();
expected_sat += 1;
solver.add_formula(&formula);
prop_assert_eq!(solver.solve().ok(), Some(true));
expected_sat += 1;
let mut assumptions = enable_row;
assumptions.push(Lit::positive(Var::from_index(formula.var_count() + 10)));
solver.assume(&assumptions);
prop_assert_eq!(solver.solve().ok(), Some(false));
expected_unsat += 1;
let mut candidates = solver.failed_core().unwrap().to_owned();
let mut core: Vec<Lit> = vec![];
while !candidates.is_empty() {
solver.assume(&candidates[0..candidates.len() - 1]);
match solver.solve() {
Err(_) => unreachable!(),
Ok(true) => {
expected_sat += 1;
let skipped = *candidates.last().unwrap();
core.push(skipped);
let single_clause = CnfFormula::from(Some([skipped]));
solver.add_formula(&single_clause);
},
Ok(false) => {
expected_unsat += 1;
candidates = solver.failed_core().unwrap().to_owned();
}
}
}
prop_assert_eq!(core.len(), columns + 1);
drop(solver);
#[derive(Default)]
struct CountResults {
sat: usize,
unsat: usize,
}
impl ProofTranscriptProcessor for CountResults {
fn process_step(
&mut self,
step: &ProofTranscriptStep,
) -> Result<(), Error> {
match step {
ProofTranscriptStep::Model { .. } => {
self.sat += 1;
}
ProofTranscriptStep::Unsat
| ProofTranscriptStep::FailedAssumptions { .. } => {
self.unsat += 1;
}
_ => (),
}
Ok(())
}
}
let mut count_results = CountResults::default();
let mut checker = Checker::new();
checker.add_transcript(&mut count_results);
checker.check_proof(&mut &proof[..]).unwrap();
prop_assert_eq!(count_results.sat, expected_sat);
prop_assert_eq!(count_results.unsat, expected_unsat);
}
}