use std::{borrow::Borrow, rc::Rc};
use crate::{
config::{Config, StoppingCriteria},
db::{atom::AtomDB, clause::ClauseDB, literal::LiteralDB, ClauseKey},
dispatch::{
library::delta::{
self,
Resolution::{self},
},
macros::{self},
Dispatch,
},
misc::log::targets::{self},
structures::{
atom::Atom,
clause::{vClause, Clause},
literal::{self, abLiteral, Literal},
valuation::Valuation,
},
types::err::{self},
};
pub enum Ok {
FirstUIP,
Exhausted,
UnitClause,
Missed(ClauseKey, abLiteral),
}
#[derive(Clone, Copy)]
pub enum Cell {
Value(Option<bool>),
None(abLiteral),
Conflict(abLiteral),
Strengthened,
Pivot,
}
pub struct ResolutionBuffer {
valueless_count: usize,
clause_length: usize,
asserts: Option<abLiteral>,
buffer: Vec<Cell>,
dispatcher: Option<Rc<dyn Fn(Dispatch)>>,
config: BufferConfig,
}
pub struct BufferConfig {
subsumption: bool,
stopping: StoppingCriteria,
}
impl ResolutionBuffer {
pub fn clause_legnth(&self) -> usize {
self.clause_length
}
pub fn from_valuation(
valuation: &impl Valuation,
dispatcher: Option<Rc<dyn Fn(Dispatch)>>,
config: &Config,
) -> Self {
let valuation_copy = valuation.values().map(Cell::Value).collect();
ResolutionBuffer {
valueless_count: 0,
clause_length: 0,
asserts: None,
buffer: valuation_copy,
dispatcher,
config: BufferConfig {
subsumption: config.switch.subsumption,
stopping: config.stopping_criteria,
},
}
}
pub fn to_assertion_clause(self) -> (vClause, Option<usize>) {
let mut the_clause = vec![];
let mut conflict_index = None;
for item in &self.buffer {
match item {
Cell::Strengthened | Cell::Value(_) | Cell::Pivot => {}
Cell::Conflict(literal) => the_clause.push(*literal),
Cell::None(literal) => {
if self.valueless_count == 1 {
conflict_index = Some(the_clause.size())
}
the_clause.push(*literal)
}
}
}
(the_clause, conflict_index)
}
pub fn clear_atom_value(&mut self, atom: Atom) {
unsafe { self.set(atom, Cell::Value(None)) }
}
pub fn resolve_through_current_level(
&mut self,
conflict: &ClauseKey,
literal_db: &LiteralDB,
clause_db: &mut ClauseDB,
atom_db: &mut AtomDB,
) -> Result<Ok, err::ResolutionBuffer> {
let base_clause = match unsafe { clause_db.get_unchecked(conflict) } {
Ok(c) => c,
Err(_) => return Err(err::ResolutionBuffer::MissingClause),
};
self.merge_clause(base_clause);
if let Some(asserted_literal) = self.asserted_literal() {
return Ok(Ok::Missed(*conflict, asserted_literal));
};
macros::send_resolution_delta!(self, delta::Resolution::Begin);
macros::send_resolution_delta!(self, delta::Resolution::Used(*conflict));
if let ClauseKey::Addition(index, _) = conflict {
clause_db.bump_activity(*index)
};
'resolution_loop: for (source, literal) in
literal_db.last_consequences_unchecked().iter().rev()
{
match source {
literal::Source::BCP(the_key) => {
let source_clause = match unsafe { clause_db.get_unchecked(the_key) } {
Err(_) => {
log::error!(target: targets::RESOLUTION, "Lost resolution clause {the_key}");
return Err(err::ResolutionBuffer::LostClause);
}
Ok(clause) => clause,
};
let resolution_result = self.resolve_clause(source_clause, literal);
if resolution_result.is_err() {
continue 'resolution_loop;
}
if self.config.subsumption && self.clause_length < source_clause.size() {
match self.clause_length {
0 => {}
1 => {
macros::send_resolution_delta!(self, Resolution::Used(*the_key));
macros::send_resolution_delta!(self, delta::Resolution::End);
return Ok(Ok::UnitClause);
}
_ => match the_key {
ClauseKey::Unit(_) => {
panic!("!")
}
ClauseKey::Binary(_) => {
todo!("a formula is found which triggers this…");
}
ClauseKey::Original(_) | ClauseKey::Addition(_, _) => unsafe {
let k = clause_db.subsume(*the_key, literal, atom_db)?;
macros::send_resolution_delta!(self, delta::Resolution::End);
macros::send_resolution_delta!(self, delta::Resolution::Begin);
macros::send_resolution_delta!(
self,
delta::Resolution::Used(k)
);
},
},
}
} else {
macros::send_resolution_delta!(self, delta::Resolution::Used(*the_key));
}
if let ClauseKey::Addition(index, _) = the_key {
clause_db.bump_activity(*index)
};
}
_ => panic!("unexpected"),
};
if self.valueless_count == 1 {
match self.config.stopping {
StoppingCriteria::FirstUIP => {
macros::send_resolution_delta!(self, delta::Resolution::End);
return Ok(Ok::FirstUIP);
}
StoppingCriteria::None => {}
};
}
}
macros::send_resolution_delta!(self, delta::Resolution::End);
Ok(Ok::Exhausted)
}
pub fn strengthen_given<'l>(&mut self, literals: impl Iterator<Item = &'l abLiteral>) {
for literal in literals {
match unsafe { *self.buffer.get_unchecked(literal.atom() as usize) } {
Cell::None(_) | Cell::Conflict(_) => {
if let Some(length_minus_one) = self.clause_length.checked_sub(1) {
self.clause_length = length_minus_one;
}
unsafe { self.set(literal.atom(), Cell::Strengthened) }
}
_ => {}
}
}
}
pub fn atoms_used(&self) -> impl Iterator<Item = Atom> + '_ {
self.buffer
.iter()
.enumerate()
.filter_map(|(index, cell)| match cell {
Cell::Value(_) => None,
_ => Some(index as Atom),
})
}
}
impl ResolutionBuffer {
fn merge_clause(&mut self, clause: &impl Clause) -> Result<(), err::ResolutionBuffer> {
for literal in clause.literals() {
match unsafe { self.buffer.get_unchecked(literal.atom() as usize) } {
Cell::Conflict(_) | Cell::None(_) | Cell::Pivot => {}
Cell::Value(maybe) => match maybe {
None => {
self.clause_length += 1;
self.valueless_count += 1;
unsafe { self.set(literal.atom(), Cell::None(*literal)) };
if self.asserts.is_none() {
self.asserts = Some(*literal);
}
}
Some(value) if *value != literal.polarity() => {
self.clause_length += 1;
unsafe { self.set(literal.atom(), Cell::Conflict(*literal)) };
}
Some(_) => {
log::error!(target: targets::RESOLUTION, "Satisfied clause");
return Err(err::ResolutionBuffer::SatisfiedClause);
}
},
Cell::Strengthened => {}
}
}
Ok(())
}
fn resolve_clause(
&mut self,
clause: &impl Clause,
pivot: impl Borrow<abLiteral>,
) -> Result<(), err::ResolutionBuffer> {
let pivot = pivot.borrow();
let contents = unsafe { *self.buffer.get_unchecked(pivot.atom() as usize) };
match contents {
Cell::None(literal) if pivot == &literal.negate() => {
self.merge_clause(clause)?;
self.clause_length -= 1;
unsafe { self.set(pivot.atom(), Cell::Pivot) };
self.valueless_count -= 1;
Ok(())
}
Cell::Conflict(literal) if pivot == &literal.negate() => {
self.merge_clause(clause)?;
self.clause_length -= 1;
unsafe { self.set(pivot.atom(), Cell::Pivot) };
Ok(())
}
_ => {
Err(err::ResolutionBuffer::LostClause)
}
}
}
unsafe fn set(&mut self, atom: Atom, to: Cell) {
*self.buffer.get_unchecked_mut(atom as usize) = to
}
fn asserted_literal(&self) -> Option<abLiteral> {
if self.valueless_count == 1 {
self.asserts
} else {
None
}
}
}