use std::borrow::Borrow;
use crate::{
context::GenericContext,
db::{
atom::watch_db::{self, WatchTag},
consequence_q::{self},
},
dispatch::{
library::delta::{self, Delta},
macros::{self},
Dispatch,
},
misc::log::targets::{self},
structures::{
clause::ClauseKind,
literal::{self, abLiteral, Literal},
},
types::err::{self},
};
impl<R: rand::Rng + std::default::Default> GenericContext<R> {
pub unsafe fn bcp(&mut self, literal: impl Borrow<abLiteral>) -> Result<(), err::BCP> {
let literal = literal.borrow();
{
let binary_list = &mut *self.atom_db.get_watch_list_unchecked(
literal.atom(),
ClauseKind::Binary,
!literal.polarity(),
);
for element in binary_list {
let WatchTag::Binary(check, clause_key) = element else {
log::error!(target: targets::PROPAGATION, "Long clause found in binary watch list.");
return Err(err::BCP::CorruptWatch);
};
match self.atom_db.value_of(check.atom()) {
None => match self.q_literal(*check) {
Ok(consequence_q::Ok::Qd) => {
macros::send_bcp_delta!(self, Instance, *check, *clause_key);
self.record_literal(check, literal::Source::BCP(*clause_key));
}
Err(_key) => {
return Err(err::BCP::Conflict(*clause_key));
}
},
Some(value) if check.polarity() != value => {
log::trace!(target: targets::PROPAGATION, "Consequence of {clause_key} and {literal} is contradiction.");
macros::send_bcp_delta!(self, Conflict, *literal, *clause_key);
return Err(err::BCP::Conflict(*clause_key));
}
Some(_) => {
log::trace!(target: targets::PROPAGATION, "Missed implication of {clause_key} {literal}.");
}
}
}
}
{
let long_list = &mut *self.atom_db.get_watch_list_unchecked(
literal.atom(),
ClauseKind::Long,
!literal.polarity(),
);
let mut index = 0;
let mut length = long_list.len();
'long_loop: while index < length {
let WatchTag::Clause(clause_key) = long_list.get_unchecked(index) else {
log::error!(target: targets::PROPAGATION, "Binary clause found in long watch list.");
return Err(err::BCP::CorruptWatch);
};
let db_clause = match self.clause_db.get_mut(clause_key) {
Ok(stored_clause) => stored_clause,
Err(_) => {
long_list.swap_remove(index);
length -= 1;
continue 'long_loop;
}
};
match db_clause.update_watch(literal.atom(), &mut self.atom_db) {
Ok(watch_db::WatchStatus::Witness) | Ok(watch_db::WatchStatus::None) => {
long_list.swap_remove(index);
length -= 1;
continue 'long_loop;
}
Ok(watch_db::WatchStatus::Conflict) => {
log::error!(target: targets::PROPAGATION, "Conflict from updating watch during propagation.");
return Err(err::BCP::CorruptWatch);
}
Err(()) => {
let the_watch = *db_clause.get_unchecked(0);
let watch_value = self.atom_db.value_of(the_watch.atom());
match watch_value {
Some(value) if the_watch.polarity() != value => {
self.clause_db.note_use(*clause_key);
macros::send_bcp_delta!(self, Conflict, *literal, *clause_key);
return Err(err::BCP::Conflict(*clause_key));
}
None => {
self.clause_db.note_use(*clause_key);
match self.q_literal(the_watch) {
Ok(consequence_q::Ok::Qd) => {}
Err(_) => return Err(err::BCP::Conflict(*clause_key)),
};
macros::send_bcp_delta!(self, Instance, the_watch, *clause_key);
self.record_literal(the_watch, literal::Source::BCP(*clause_key));
}
Some(_) => {}
}
}
}
index += 1;
continue 'long_loop;
}
}
Ok(())
}
}