#[cfg(feature = "cadical")]
pub mod cadical;
pub mod multisolver;
use std::collections::HashSet;
use std::fmt::{Display, Formatter};
use std::vec::IntoIter;
pub trait SolverState {
fn is_sat(&self) -> bool;
fn is_unsat(&self) -> bool;
fn is_unknown(&self) -> bool;
}
pub trait AddConstraints<C> {
fn insert(&mut self, constraints: &C);
}
impl<T, C> AddConstraints<C> for [T]
where
T: AddConstraints<C>,
{
fn insert(&mut self, constraints: &C) {
for t in self {
t.insert(constraints);
}
}
}
pub trait SatSolver: AddConstraints<Clause> + AddConstraints<Formula> {
type Status: SolverState;
fn new() -> Self;
fn solve(&mut self) -> Self::Status;
fn val(&mut self, lit: i32) -> bool;
fn load_model(&mut self) -> Model;
fn block_model(&mut self);
}
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub struct Clause(pub Vec<i32>);
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub struct Formula(pub Vec<Clause>);
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub struct Model(pub Vec<bool>);
impl Display for Clause {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
f.write_str("[")?;
for i in 0..self.0.len() {
write!(f, "{}", self.0[i])?;
if i < self.0.len() - 1 {
f.write_str(", ")?;
}
}
f.write_str("]")
}
}
impl Display for Formula {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
f.write_str("[")?;
for i in 0..self.0.len() {
write!(f, "{}", self.0[i])?;
if i < self.0.len() - 1 {
f.write_str(";\n")?;
}
}
f.write_str("]")
}
}
impl Clause {
pub fn empty() -> Self {
Self::new(vec![])
}
pub fn new(lits: Vec<i32>) -> Self {
Clause(lits)
}
pub fn single(lit: i32) -> Self {
Self::new(vec![lit])
}
pub fn lits(&self) -> &[i32] {
&self.0
}
fn filter_by_model<'a, 'b>(&'a self, model: &'b Model) -> impl Iterator<Item = &'a i32> + 'a
where
'b: 'a,
{
self.0.iter().filter(|&i| {
let idx = (i.abs() - 1) as usize;
if *i < 0 { !model.0[idx] } else { model.0[idx] }
})
}
pub fn evaluate(&self, model: &Model) -> bool {
self.filter_by_model(model).any(|_| true)
}
pub fn find_true_vars(&self, model: &Model) -> Vec<i32> {
self.filter_by_model(model).copied().collect()
}
pub fn filter_true_vars(&self, model: &Model, set: &HashSet<i32>) -> Vec<i32> {
self.filter_by_model(model)
.filter(|&i| !set.contains(i))
.copied()
.collect()
}
pub fn filter_vars(&self, model: &Model) -> Clause {
Clause(self.find_true_vars(model))
}
pub fn iter(&self) -> impl Iterator<Item = &i32> {
self.0.iter()
}
pub fn concat(&self, clause: &Clause) -> Self {
let mut c = self.clone();
c.concat_mut(clause);
c
}
pub fn concat_mut(&mut self, clause: &Clause) -> &mut Self {
self.0.extend(&clause.0);
self
}
pub fn add(&mut self, lit: i32) -> &mut Self {
self.0.push(lit);
self
}
}
impl IntoIterator for Clause {
type Item = i32;
type IntoIter = IntoIter<i32>;
fn into_iter(self) -> Self::IntoIter {
self.0.into_iter()
}
}
impl Formula {
pub fn empty() -> Formula {
Formula(vec![])
}
pub fn new(clauses: Vec<Clause>) -> Formula {
Formula(clauses)
}
pub fn add(&mut self, clause: Clause) {
self.0.push(clause);
}
pub fn filter_clauses(&self, model: &Model) -> Formula {
Formula(self.0.iter().map(|c| c.filter_vars(model)).collect())
}
fn find_implicant_helper(self) -> HashSet<i32> {
let mut vset = HashSet::new();
let mut clauses: Vec<_> = self.0;
loop {
let begin_sz = vset.len();
let mut kept_clauses = vec![];
for clause in clauses.into_iter() {
if clause.0.iter().any(|&i| vset.contains(&i)) {
continue;
}
if clause.0.len() == 1 {
vset.insert(clause.0[0]);
} else {
kept_clauses.push(clause);
}
}
clauses = kept_clauses;
if clauses.is_empty() {
break;
}
if begin_sz == vset.len() {
let c = clauses.pop().unwrap();
vset.insert(c.0[0]);
}
}
vset
}
pub fn find_implicant(&self, model: &Model) -> HashSet<i32> {
self.filter_clauses(model).find_implicant_helper()
}
pub fn iter(&self) -> impl Iterator<Item = &Clause> {
self.0.iter()
}
pub fn concat(&self, clause: &Clause) -> Self {
let mut f = self.clone();
f.concat_mut(clause);
f
}
pub fn concat_mut(&mut self, clause: &Clause) -> &mut Self {
for c in self.0.iter_mut() {
c.concat_mut(clause);
}
self
}
pub fn distribute(&self, formula: &Formula) -> Self {
Formula::new(formula.iter().flat_map(|c| self.concat(c)).collect())
}
pub fn distribute_mut(&mut self, formula: &Formula) -> &mut Self {
self.0 = self.distribute(formula).0;
self
}
}
impl IntoIterator for Formula {
type Item = Clause;
type IntoIter = IntoIter<Clause>;
fn into_iter(self) -> Self::IntoIter {
self.0.into_iter()
}
}
impl Model {
pub fn get_model<F>(vn: usize, f: F) -> Model
where
F: FnMut(usize) -> bool,
{
Model((1..vn + 1).map(f).collect())
}
pub fn negate(&self) -> Clause {
Clause(
self.0
.iter()
.enumerate()
.map(|(idx, v)| {
if *v {
-(idx as i32 + 1)
} else {
idx as i32 + 1
}
})
.collect(),
)
}
}