use std::{borrow::Borrow, collections::HashSet};
use crate::{
config::{Config, StoppingCriteria},
db::{atom::AtomDB, clause::ClauseDB, literal::LiteralDB, ClauseKey},
misc::log::targets::{self},
structures::{
atom::Atom,
clause::{CClause, Clause},
consequence,
literal::{CLiteral, Literal},
valuation::Valuation,
},
types::err::{self, ResolutionBufferError},
};
use super::{cell::Cell, config::BufferConfig, ResolutionBuffer, ResolutionOk};
impl ResolutionBuffer {
pub fn new(config: &Config) -> Self {
Self {
valueless_count: 0,
clause_length: 0,
asserts: None,
premises: HashSet::default(),
buffer: Vec::default(),
config: BufferConfig::from(config),
callback_premises: None,
}
}
pub fn refresh(&mut self, valuation: &impl Valuation) {
self.valueless_count = 0;
self.clause_length = 0;
self.asserts = None;
self.premises.clear();
match self.buffer.len().cmp(&valuation.atom_count()) {
std::cmp::Ordering::Less => self.buffer = valuation.values().map(Cell::Value).collect(),
std::cmp::Ordering::Equal => unsafe {
for index in 0..self.buffer.len() {
*self.buffer.get_unchecked_mut(index) =
Cell::Value(valuation.value_of_unchecked(index as Atom))
}
},
std::cmp::Ordering::Greater => todo!(),
}
}
pub fn clause_legnth(&self) -> usize {
self.clause_length
}
pub fn to_assertion_clause(&self) -> (CClause, 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,
key: &ClauseKey,
literal_db: &LiteralDB,
clause_db: &mut ClauseDB,
atom_db: &mut AtomDB,
) -> Result<ResolutionOk, err::ResolutionBufferError> {
let base_clause = match unsafe { clause_db.get_unchecked_mut(key) } {
Ok(clause) => clause,
Err(_) => return Err(err::ResolutionBufferError::MissingClause),
};
self.merge_clause(base_clause);
base_clause.increment_proof_count();
clause_db.note_use(*key);
self.premises.insert(*key);
if let Some(literal) = self.asserted_literal() {
return Ok(ResolutionOk::Repeat(*key, literal));
};
if let ClauseKey::Addition(index, _) = key {
clause_db.bump_activity(*index)
};
let the_trail = unsafe { literal_db.top_consequences_unchecked().iter().rev() };
'resolution_loop: for consequence in the_trail {
match consequence.source() {
consequence::Source::BCP(key) => {
let mut key = *key;
let source_clause = match unsafe { clause_db.get_unchecked_mut(&key) } {
Err(_) => {
log::error!(target: targets::RESOLUTION, "Lost resolution clause: {key}");
println!("Missing key");
return Err(err::ResolutionBufferError::LostClause);
}
Ok(clause) => clause,
};
let source_clause_size = source_clause.size();
let resolution_result =
self.resolve_clause(source_clause, consequence.literal());
source_clause.increment_proof_count();
clause_db.note_use(key);
self.premises.insert(key);
if resolution_result.is_err() {
continue 'resolution_loop; }
key = match self.config.subsumption
&& self.clause_length > 2
&& self.clause_length < source_clause_size
{
false => key,
true => {
match key {
ClauseKey::OriginalUnit(_) | ClauseKey::AdditionUnit(_) => {
panic!("! Subsumption called on a unit clause")
}
ClauseKey::OriginalBinary(_) | ClauseKey::AdditionBinary(_) => {
panic!("! Subsumption called on a binary clause");
}
ClauseKey::Original(_) | ClauseKey::Addition(_, _) => unsafe {
let premises = self.take_premises();
let rekey = clause_db.subsume(
key,
consequence.literal(),
atom_db,
premises,
true, )?;
self.premises.insert(rekey);
clause_db.note_use(rekey);
rekey
},
}
}
};
if let ClauseKey::Addition(index, _) = key {
clause_db.bump_activity(index)
};
}
_ => panic!("! The resolution trail contains a literal whose source is not BCP"),
};
if self.valueless_count == 1 {
match self.config.stopping {
StoppingCriteria::FirstUIP => {
break 'resolution_loop;
}
_ => {}
}
}
}
match self.valueless_count {
1 => {
let premises_switch = std::mem::take(&mut self.premises);
self.make_callback_resolution_premises(&premises_switch);
self.premises = premises_switch;
Ok(ResolutionOk::UIP)
}
_ => {
println!("Exhausted");
Err(ResolutionBufferError::Exhausted)
}
}
}
pub fn strengthen_given<'l>(&mut self, literals: impl Iterator<Item = &'l CLiteral>) {
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),
})
}
pub fn take_premises(&mut self) -> HashSet<ClauseKey> {
std::mem::take(&mut self.premises)
}
}
impl ResolutionBuffer {
fn merge_clause(&mut self, clause: &impl Clause) -> Result<(), err::ResolutionBufferError> {
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::ResolutionBufferError::SatisfiedClause);
}
},
Cell::Strengthened => {}
}
}
Ok(())
}
fn resolve_clause(
&mut self,
clause: &impl Clause,
pivot: impl Borrow<CLiteral>,
) -> Result<(), err::ResolutionBufferError> {
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::ResolutionBufferError::LostClause)
}
}
}
unsafe fn set(&mut self, atom: Atom, to: Cell) {
*self.buffer.get_unchecked_mut(atom as usize) = to
}
fn asserted_literal(&self) -> Option<CLiteral> {
if self.valueless_count == 1 {
self.asserts
} else {
None
}
}
}