mod build;
mod conflict;
pub mod restart;
mod search;
mod stage;
mod validate;
pub use self::{
build::SatSolverIF,
restart::{RestartIF, RestartManager},
search::SolveIF,
stage::StageManager,
validate::ValidateIF,
};
use crate::{assign::AssignStack, cdb::ClauseDB, state::*, types::*};
#[derive(Debug, Eq, PartialEq)]
pub enum Certificate {
SAT(Vec<i32>),
UNSAT,
}
pub type SolverResult = Result<Certificate, SolverError>;
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum SolverEvent {
Assert(VarId),
Conflict,
Eliminate(VarId),
Instantiate,
NewVar,
Reinitialize,
Restart,
Stage(usize),
#[cfg(feature = "clause_vivification")]
Vivify(bool),
}
#[derive(Clone, Debug, Default)]
pub struct Solver {
pub asg: AssignStack,
pub cdb: ClauseDB,
pub state: State,
}
impl<V: AsRef<[i32]>> TryFrom<Vec<V>> for Certificate {
type Error = SolverError;
fn try_from(vec: Vec<V>) -> SolverResult {
Solver::try_from((Config::default(), vec.as_ref())).map_or_else(
|e: SolverResult| match e {
Ok(cert) => Ok(cert),
Err(SolverError::EmptyClause) => Ok(Certificate::UNSAT),
Err(e) => Err(e),
},
|mut solver| solver.solve(),
)
}
}
#[cfg(feature = "incremental_solver")]
pub struct SolverIter<'a> {
solver: &'a mut Solver,
refute: Option<Vec<i32>>,
}
#[cfg(feature = "incremental_solver")]
impl Solver {
pub fn iter(&mut self) -> SolverIter {
SolverIter {
solver: self,
refute: None,
}
}
}
#[cfg(feature = "incremental_solver")]
impl<'a> Iterator for SolverIter<'a> {
type Item = Vec<i32>;
fn next(&mut self) -> Option<Self::Item> {
if let Some(ref v) = self.refute {
debug_assert!(1 < v.len());
match self.solver.add_clause(v) {
Err(SolverError::Inconsistent) => return None,
Err(SolverError::EmptyClause) => return None,
Err(e) => panic!("s UNKNOWN: {:?} by adding {:?}", e, v),
Ok(_) => self.solver.reset(),
}
self.refute = None;
}
match self.solver.solve() {
Ok(Certificate::SAT(ans)) => {
let rft: Vec<i32> = ans.iter().map(|i| -i).collect::<Vec<i32>>();
self.refute = Some(rft);
Some(ans)
}
Ok(Certificate::UNSAT) => None,
e => panic!("s UNKNOWN: {:?}", e),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::assign;
#[cfg_attr(not(feature = "no_IO"), test)]
fn test_solver() {
let config = Config::from("cnfs/sample.cnf");
if let Ok(s) = Solver::build(&config) {
assert_eq!(s.asg.derefer(assign::property::Tusize::NumVar), 250);
assert_eq!(
s.asg.derefer(assign::property::Tusize::NumUnassertedVar),
250
);
} else {
panic!("failed to build a solver for cnfs/sample.cnf");
}
}
macro_rules! run {
($vec: expr) => {
println!(
"{:>46} =| {:?}",
format!("{:?}", $vec),
match Solver::try_from((Config::default(), $vec.as_ref())).map(|mut s| s.solve()) {
Err(e) => e,
Ok(Ok(u @ Certificate::UNSAT)) => Ok(u),
Ok(s) => s,
}
);
};
}
macro_rules! sat {
($vec: expr, $should_be: pat) => {
println!("{:>46} =| ", format!("{:?}", $vec));
let result = Certificate::try_from($vec);
println!("{:?}", result);
assert!(matches!(result, $should_be));
};
($vec: expr) => {
println!(
"{:>46} =| {:?}",
format!("{:?}", $vec),
Certificate::try_from($vec)
);
};
}
#[test]
fn test_on_memory_solving() {
let mut v: Vec<Vec<i32>> = Vec::new();
run!(v);
v.push(Vec::new());
run!(v);
run!(vec![vec![1]]);
run!(vec![vec![1], vec![-1]]);
run!(vec![vec![1, 2], vec![-1, 3], vec![1, -3], vec![-1, 2]]);
run!(vec![
vec![1, 2],
vec![-1, 3],
vec![1, -3],
vec![-1, -2],
vec![-2, -3]
]);
run!(vec![
vec![1, 2],
vec![-1, 3],
vec![-1, -3],
vec![-1, -2],
vec![1, -2]
]);
let (v1, v2, v3, v4, v5) = (vec![1, 2], vec![-1, 3], vec![1, -3], vec![-1, 2], vec![-3]);
run!(vec![&v1, &v2, &v3, &v4, &v5]); run!([&v1, &v2, &v3, &v4, &v5]);
let v0: Vec<Vec<i32>> = vec![];
sat!(v0, Ok(Certificate::SAT(_)));
let v1: Vec<Vec<i32>> = vec![vec![]];
sat!(v1, Ok(Certificate::UNSAT));
sat!(vec![vec![1i32]], Ok(Certificate::SAT(_)));
sat!(vec![vec![1i32], vec![-1]], Ok(Certificate::UNSAT));
sat!(vec![vec![1i32, 2], vec![-1, 3], vec![1, -3], vec![-1, 2]]);
sat!(vec![
vec![1i32, 2],
vec![-1, 3],
vec![1, -3],
vec![-1, -2],
vec![-2, -3]
]);
sat!(vec![
vec![1i32, 2],
vec![-1, 3],
vec![-1, -3],
vec![-1, -2],
vec![1, -2]
]);
let (v1, v2, v3, v4, v5) = (
vec![1i32, 2],
vec![-1i32, 3],
vec![1i32, -3],
vec![-1i32, 2],
vec![-3i32],
);
sat!(vec![&v1, &v2, &v3, &v4, &v5]); }
#[cfg(feature = "incremental_solver")]
#[test]
fn test_solver_iter() {
let mut slv = Solver::instantiate(
&Config::default(),
&CNFDescription {
num_of_variables: 8,
..CNFDescription::default()
},
);
assert_eq!(slv.iter().count(), 256);
}
#[cfg(feature = "incremental_solver")]
#[test]
fn test_add_var_on_incremental_solver() {
let mut slv = Solver::instantiate(
&Config::default(),
&CNFDescription {
num_of_variables: 4,
..CNFDescription::default()
},
);
assert!(slv.add_clause(vec![-1, -2]).is_ok());
assert!(slv.add_clause(vec![-3, -4]).is_ok());
assert!(slv.add_assignment(-2).is_ok());
let a = slv.add_var() as i32;
assert!(slv.add_clause(vec![1, 3, 4, -a]).is_ok());
assert!(slv.add_clause(vec![1, -3, -4, -a]).is_ok());
assert!(slv.add_clause(vec![-1, 3, -4, -a]).is_ok());
assert!(slv.add_clause(vec![-1, -3, 4, -a]).is_ok());
assert!(slv.add_clause(vec![-1, -3, -4, a]).is_ok());
assert!(slv.add_clause(vec![-1, 3, 4, a]).is_ok());
assert!(slv.add_clause(vec![1, -3, 4, a]).is_ok());
assert!(slv.add_clause(vec![1, 3, -4, a]).is_ok());
let b = slv.add_var() as i32;
assert!(slv.add_clause(vec![1, 3, -b]).is_ok());
assert!(slv.add_clause(vec![1, 4, -b]).is_ok());
assert!(slv.add_clause(vec![3, 4, -b]).is_ok());
assert!(slv.add_clause(vec![-1, -3, b]).is_ok());
assert!(slv.add_clause(vec![-1, -4, b]).is_ok());
assert!(slv.add_clause(vec![-3, -4, b]).is_ok());
assert!(slv.add_clause(vec![-1, -b]).is_ok());
assert!(slv.add_clause(vec![-a, -b]).is_ok());
assert_eq!(slv.iter().count(), 4);
}
#[cfg(feature = "incremental_solver")]
#[test]
fn test_add_var_and_add_assignment() {
let mut slv = Solver::instantiate(
&Config::default(),
&CNFDescription {
num_of_variables: 3 as usize,
..CNFDescription::default()
},
);
slv.add_var();
assert!(slv.add_clause(vec![-1, 4]).is_ok());
slv.add_var();
assert!(slv.add_clause(vec![-2, 5]).is_ok());
slv.add_var();
assert!(slv.add_clause(vec![-1, -2, 6]).is_ok());
slv.add_var();
assert!(slv.add_clause(vec![-5, 7]).is_ok());
slv.add_var();
assert!(slv.add_clause(vec![-6, 8]).is_ok());
slv.add_var();
assert!(slv.add_clause(vec![-4, 9]).is_ok());
slv.add_var();
assert!(slv.add_clause(vec![-3, 10]).is_ok());
slv.add_var();
assert!(slv.add_clause(vec![-5, -3, 11]).is_ok());
assert!(slv.add_clause(vec![-6, -3, 11]).is_ok());
slv.add_var();
assert!(slv.add_clause(vec![-4, -3, 12]).is_ok());
assert!(slv.add_assignment(-11).is_ok());
assert!(slv.solve().is_ok());
}
}