use crate::{
db::{
atom::{
watch_db::{WatchStatus, WatchTag},
AtomDB,
},
keys::ClauseKey,
},
structures::{
atom::Atom,
literal::{CLiteral, Literal},
valuation::{vValuation, Valuation},
},
};
use super::dbClause;
impl dbClause {
pub unsafe fn get_watch_a(&self) -> &CLiteral {
self.get_unchecked(0)
}
pub unsafe fn get_watch_b(&self) -> &CLiteral {
self.get_unchecked(self.watch_ptr)
}
pub fn initialise_watches(&mut self, atom_db: &mut AtomDB, valuation: Option<&vValuation>) {
let mut watch_a_set = false;
for (index, literal) in self.clause.iter().enumerate() {
let index_value = match valuation {
Some(v) => unsafe { v.value_of_unchecked(literal.atom()) },
None => unsafe { atom_db.valuation().value_of_unchecked(literal.atom()) },
};
match index_value {
None => {
self.note_watch(literal.atom(), literal.polarity(), atom_db);
self.clause.swap(0, index);
watch_a_set = true;
break;
}
Some(value) if value == literal.polarity() => {
self.note_watch(literal.atom(), literal.polarity(), atom_db);
self.clause.swap(0, index);
watch_a_set = true;
break;
}
Some(_) => {}
}
}
if !watch_a_set {
let zero_literal = unsafe { self.clause.get_unchecked(0) };
self.note_watch(zero_literal.atom(), zero_literal.polarity(), atom_db);
}
let mut watch_b_set = false;
self.watch_ptr = 1;
let mut decision_level_b = unsafe {
let literal = self.clause.get_unchecked(self.watch_ptr);
let maybe_decision_level = atom_db.atom_decision_level_unchecked(literal.atom());
maybe_decision_level.unwrap_or(0)
};
for index in 1..self.clause.len() {
let literal = unsafe { self.clause.get_unchecked(index) };
let atom_value = match valuation {
Some(v) => unsafe { v.value_of_unchecked(literal.atom()) },
None => unsafe { atom_db.valuation().value_of_unchecked(literal.atom()) },
};
match atom_value {
None => {
self.watch_ptr = index;
self.note_watch(literal.atom(), literal.polarity(), atom_db);
watch_b_set = true;
break;
}
Some(value) if value == literal.polarity() => {
self.watch_ptr = index;
self.note_watch(literal.atom(), literal.polarity(), atom_db);
watch_b_set = true;
break;
}
Some(_) => {
let decision_level = unsafe {
atom_db
.atom_decision_level_unchecked(literal.atom())
.unwrap_unchecked()
};
if decision_level > decision_level_b {
self.watch_ptr = index;
decision_level_b = decision_level;
}
}
}
}
if !watch_b_set {
let ptr_literal = unsafe { self.clause.get_unchecked(self.watch_ptr) };
self.note_watch(ptr_literal.atom(), ptr_literal.polarity(), atom_db);
}
}
pub fn note_watch(&self, atom: Atom, value: bool, atom_db: &mut AtomDB) {
match self.key {
ClauseKey::OriginalUnit(_) | ClauseKey::AdditionUnit(_) => {
panic!("! Attempt to note watches on a unit clause")
}
ClauseKey::OriginalBinary(_) | ClauseKey::AdditionBinary(_) => unsafe {
let check_literal = if self.clause.get_unchecked(0).atom() == atom {
*self.clause.get_unchecked(1)
} else {
*self.clause.get_unchecked(0)
};
atom_db.watch_unchecked(atom, value, WatchTag::Binary(check_literal, *self.key()));
},
ClauseKey::Original(_) | ClauseKey::Addition(_, _) => unsafe {
atom_db.watch_unchecked(atom, value, WatchTag::Long(*self.key()));
},
}
}
#[inline(always)]
#[allow(clippy::result_unit_err)]
pub unsafe fn update_watch(
&mut self,
atom: Atom,
atom_db: &mut AtomDB,
) -> Result<WatchStatus, ()> {
if self.clause.get_unchecked(0).atom() == atom {
self.clause.swap(0, self.watch_ptr)
}
let watch_ptr_cache = self.watch_ptr;
let clause_length = self.clause.len();
loop {
self.watch_ptr += 1;
if self.watch_ptr == clause_length {
self.watch_ptr = 1 }
if self.watch_ptr == watch_ptr_cache {
break Err(());
}
let literal = unsafe { self.clause.get_unchecked(self.watch_ptr) };
match atom_db.value_of(literal.atom()) {
None => {
self.note_watch(literal.atom(), literal.polarity(), atom_db);
break Ok(WatchStatus::None);
}
Some(value) if value == literal.polarity() => {
self.note_watch(literal.atom(), literal.polarity(), atom_db);
break Ok(WatchStatus::Witness);
}
Some(_) => {}
}
}
}
}