use crate::sat::assignment::Assignment;
use crate::sat::clause::Clause;
use crate::sat::clause_management::ClauseManagement;
use crate::sat::clause_storage::LiteralStorage;
use crate::sat::cnf::Cnf;
use crate::sat::conflict_analysis::{Analyser, Conflict};
use crate::sat::literal::Literal;
use crate::sat::propagation::Propagator;
use crate::sat::restarter::Restarter;
use crate::sat::solver::{DefaultConfig, SolutionStats, Solutions, Solver, SolverConfig};
use crate::sat::trail::Reason;
use crate::sat::trail::Trail;
use crate::sat::variable_selection::VariableSelection;
use crate::sat::{cnf, variable_selection};
use std::fmt::Debug;
#[derive(Debug, Clone)]
pub struct Cdcl<Config: SolverConfig = DefaultConfig> {
assignment: Config::Assignment,
propagator: Config::Propagator,
pub cnf: Cnf<Config::Literal, Config::LiteralStorage>,
selector: Config::VariableSelector,
decision_level: cnf::DecisionLevel,
trail: Trail<Config::Literal, Config::LiteralStorage>,
restarter: Config::Restarter,
conflict_analysis: Analyser<Config::Literal, Config::LiteralStorage>,
manager: Config::ClauseManager,
}
impl<Config: SolverConfig> Cdcl<Config> {
pub const fn all_assigned(&self) -> bool {
self.trail.len() == self.cnf.num_vars
}
fn should_restart(&mut self) -> bool {
#[allow(clippy::cast_precision_loss)]
let conflict_rate = if !self.trail.is_empty() {
self.restarter.num_restarts() as f64 / self.trail.len() as f64
} else if self.restarter.num_restarts() > 0 {
f64::INFINITY
} else {
0.0
};
self.restarter.should_restart() || conflict_rate > 0.1
}
fn add_propagation(&mut self, lit: Config::Literal, c_ref: usize) {
self.trail
.push(lit, self.decision_level, Reason::Clause(c_ref));
}
pub fn add_clause(&mut self, clause: Clause<Config::Literal, Config::LiteralStorage>) {
if clause.is_empty() || clause.is_tautology() {
return;
}
let c_ref = self.cnf.len();
self.cnf.add_clause(clause);
self.propagator.add_clause(&self.cnf[c_ref], c_ref);
}
}
impl<Config: SolverConfig> Solver<Config> for Cdcl<Config> {
fn new<L: Literal, S: LiteralStorage<L>>(cnf: Cnf<L, S>) -> Self {
let cnf = cnf.convert();
let propagator = Propagator::new(&cnf);
let vars = &cnf.lits;
let selector = Config::VariableSelector::new(cnf.num_vars, vars, &cnf.clauses);
let restarter = Restarter::new();
let conflict_analysis = Analyser::new(cnf.num_vars);
let manager = Config::ClauseManager::new(&cnf.clauses);
Self {
assignment: Assignment::new(cnf.num_vars),
trail: Trail::new(&cnf.clauses, cnf.num_vars),
propagator,
cnf,
selector,
restarter,
decision_level: 0,
conflict_analysis,
manager,
}
}
fn from_parts<L: Literal, S: LiteralStorage<L>>(
cnf: Cnf<L, S>,
assignment: Config::Assignment,
manager: Config::ClauseManager,
propagator: Config::Propagator,
restarter: Config::Restarter,
selector: Config::VariableSelector,
) -> Self {
let cnf = cnf.convert();
let conflict_analysis = Analyser::new(cnf.num_vars);
Self {
trail: Trail::new(&cnf.clauses, cnf.num_vars),
assignment,
propagator,
cnf,
selector,
conflict_analysis,
restarter,
manager,
decision_level: 0,
}
}
fn solve(&mut self) -> Option<Solutions> {
if self.cnf.is_empty() {
return Some(Solutions::default());
}
if self
.propagator
.propagate(&mut self.trail, &mut self.assignment, &mut self.cnf)
.is_some()
{
return None;
}
if self.cnf.iter().any(Clause::is_empty) {
return None;
}
loop {
if let Some(c_ref) = self.propagator.propagate(
&mut self.trail,
&mut self.assignment,
&mut self.cnf,
)
{
self.manager.on_conflict(&mut self.cnf);
let (conflict, to_bump) = self.conflict_analysis.analyse_conflict(
&self.cnf,
&self.trail,
&self.assignment,
c_ref,
);
match conflict {
Conflict::Unit(_) | Conflict::Restart(_) | Conflict::Ground => {
return None;
}
Conflict::Learned(assert_idx, mut clause) => {
clause.swap(0, assert_idx);
let asserting_lit = clause[0];
let bt_level = clause
.iter()
.skip(1)
.map(|lit| self.trail.level(lit.variable()))
.max()
.unwrap_or(0);
clause.calculate_lbd(&self.trail);
clause.is_learnt = true;
clause.bump_activity(1.0);
self.manager
.bump_involved_clause_activities(&mut self.cnf, c_ref);
self.trail.backstep_to(&mut self.assignment, bt_level);
self.decision_level = bt_level;
let new_clause_idx = self.cnf.len();
self.add_clause(clause);
self.add_propagation(asserting_lit, new_clause_idx);
if self.manager.should_clean_db() {
self.manager.clean_clause_db(
&mut self.cnf,
&mut self.trail,
&mut self.propagator,
&mut self.assignment,
);
}
}
}
self.selector.bumps(to_bump);
self.selector.decay(variable_selection::VSIDS_DECAY_FACTOR);
if self.should_restart() {
self.trail.reset();
self.assignment.reset();
self.decision_level = 0;
}
} else {
self.decision_level = self.decision_level.wrapping_add(1);
if self.all_assigned() {
return Some(self.solutions());
}
let lit_option = self.selector.pick(&self.assignment);
if let Some(lit) = lit_option {
self.trail.push(lit, self.decision_level, Reason::Decision);
} else {
return Some(self.solutions());
}
}
}
}
fn solutions(&self) -> Solutions {
self.assignment.get_solutions()
}
fn stats(&self) -> SolutionStats {
SolutionStats {
conflicts: self.conflict_analysis.count,
decisions: self.selector.decisions(),
propagations: self.propagator.num_propagations(),
restarts: self.restarter.num_restarts(),
learnt_clauses: self.cnf.len() - self.cnf.non_learnt_idx,
removed_clauses: self.manager.num_removed(),
}
}
fn debug(&mut self) {
todo!()
}
}