use crate::sat;
use alloc::vec;
use alloc::vec::Vec;
use elenchus_compiler::{AtomId, Compiled, Fact, Lit, Rule, Value};
pub(crate) fn clause_lit(l: &Lit) -> sat::SatLit {
sat::SatLit::new(l.atom, l.negated)
}
pub(crate) fn fact_lit(f: &Fact) -> sat::SatLit {
match f.value {
Value::True => sat::SatLit::positive(f.atom),
Value::False => sat::SatLit::negative(f.atom),
}
}
pub(crate) fn rule_consequent_clause(r: &Rule, cons: &Lit) -> Vec<sat::SatLit> {
let mut lits: Vec<sat::SatLit> = r.antecedent.iter().map(clause_lit).collect();
lits.push(sat::SatLit::new(cons.atom, !cons.negated));
lits
}
pub(crate) fn build_cnf(c: &Compiled) -> (sat::Cnf, Vec<sat::Var>) {
let mut cnf = sat::Cnf::new(c.atoms.len());
let mut constrained = vec![false; c.atoms.len()];
let add_constraining =
|cnf: &mut sat::Cnf, constrained: &mut [bool], lits: Vec<sat::SatLit>| {
for l in &lits {
constrained[l.var() as usize] = true;
}
cnf.add_clause(lits);
};
for clause in &c.clauses {
add_constraining(
&mut cnf,
&mut constrained,
clause.lits.iter().map(clause_lit).collect(),
);
}
for r in &c.rules {
for cons in &r.consequent {
add_constraining(&mut cnf, &mut constrained, rule_consequent_clause(r, cons));
}
}
for f in &c.facts {
cnf.add_clause(vec![fact_lit(f)]);
}
let project = (0..c.atoms.len() as AtomId)
.filter(|&a| constrained[a as usize])
.collect();
(cnf, project)
}