use {
super::{EliminateIF, Eliminator},
crate::{assign::AssignIF, cdb::ClauseDBIF, types::*},
};
#[derive(Clone, Eq, Debug, Ord, PartialEq, PartialOrd)]
enum Subsumable {
None,
By(Lit),
Success,
}
impl Eliminator {
pub fn try_subsume(
&mut self,
asg: &mut impl AssignIF,
cdb: &mut impl ClauseDBIF,
cid: ClauseId,
did: ClauseId,
) -> MaybeInconsistent {
match have_subsuming_lit(cdb, cid, did) {
Subsumable::Success => {
#[cfg(feature = "trace_elimination")]
println!(
"BackSubsC => {} {} subsumed completely by {} {:#}",
did, cdb[did], cid, cdb[cid],
);
debug_assert!(!cdb[did].is_dead());
if !cdb[did].is(FlagClause::LEARNT) {
cdb[cid].turn_off(FlagClause::LEARNT);
}
self.remove_cid_occur(asg, did, &mut cdb[did]);
cdb.remove_clause(did);
self.num_subsumed += 1;
}
Subsumable::By(l) => {
debug_assert!(cid.is_lifted_lit());
#[cfg(feature = "trace_elimination")]
println!("BackSubC subsumes {} from {} and {}", l, cid, did);
strengthen_clause(asg, cdb, self, did, !l)?;
self.enqueue_var(asg, l.vi(), true);
}
Subsumable::None => (),
}
Ok(())
}
}
fn have_subsuming_lit(cdb: &mut impl ClauseDBIF, cid: ClauseId, other: ClauseId) -> Subsumable {
debug_assert!(!other.is_lifted_lit());
if cid.is_lifted_lit() {
let l = Lit::from(cid);
let oh = &cdb[other];
for lo in oh.iter() {
if l == !*lo {
return Subsumable::By(l);
}
}
return Subsumable::None;
}
let ch = &cdb[cid];
debug_assert!(1 < ch.len());
let ob = &cdb[other];
debug_assert!(1 < ob.len());
debug_assert!(ob.contains(ob[0]));
debug_assert!(ob.contains(ob[1]));
'next: for l in ch.iter() {
for lo in ob.iter() {
if *l == *lo {
continue 'next;
}
}
return Subsumable::None;
}
Subsumable::Success
}
fn strengthen_clause(
asg: &mut impl AssignIF,
cdb: &mut impl ClauseDBIF,
elim: &mut Eliminator,
cid: ClauseId,
l: Lit,
) -> MaybeInconsistent {
debug_assert!(!cdb[cid].is_dead());
debug_assert!(1 < cdb[cid].len());
match cdb.transform_by_elimination(cid, l) {
RefClause::Clause(_ci) => {
#[cfg(feature = "trace_elimination")]
println!("cid {} drops literal {}", cid, l);
elim.enqueue_clause(cid, &mut cdb[cid]);
elim.remove_lit_occur(asg, l, cid);
Ok(())
}
RefClause::RegisteredClause(_) => {
elim.remove_cid_occur(asg, cid, &mut cdb[cid]);
cdb.remove_clause(cid);
Ok(())
}
RefClause::UnitClause(l0) => {
cdb.certificate_add_assertion(l0);
elim.remove_cid_occur(asg, cid, &mut cdb[cid]);
cdb.remove_clause(cid);
match asg.assigned(l0) {
None => asg.assign_at_root_level(l0),
Some(true) => Ok(()),
Some(false) => Err(SolverError::RootLevelConflict((l0, asg.reason(l0.vi())))),
}
}
RefClause::Dead | RefClause::EmptyClause => unreachable!("strengthen_clause"),
}
}