mod ema;
mod heap;
mod propagate;
#[cfg_attr(feature = "EVSIDS", path = "evsids.rs")]
#[cfg_attr(feature = "LRB_rewarding", path = "learning_rate.rs")]
mod reward;
mod select;
mod stack;
mod trail_saving;
mod var;
pub use self::{propagate::PropagateIF, property::*, select::VarSelectIF, var::VarManipulateIF};
use {
self::{
ema::ProgressASG,
heap::{VarHeapIF, VarIdHeap},
},
crate::{cdb::ClauseDBIF, types::*},
std::{fmt, ops::Range, slice::Iter},
};
#[cfg(feature = "trail_saving")]
pub use self::trail_saving::TrailSavingIF;
#[cfg(any(feature = "best_phases_tracking", feature = "rephase"))]
use std::collections::HashMap;
pub trait AssignIF:
ActivityIF<VarId>
+ Instantiate
+ PropagateIF
+ VarManipulateIF
+ PropertyDereference<property::Tusize, usize>
+ PropertyReference<property::TEma, EmaView>
{
fn root_level(&self) -> DecisionLevel;
fn stack(&self, i: usize) -> Lit;
fn stack_range(&self, r: Range<usize>) -> &[Lit];
fn stack_len(&self) -> usize;
fn len_upto(&self, n: DecisionLevel) -> usize;
fn stack_is_empty(&self) -> bool;
fn stack_iter(&self) -> Iter<'_, Lit>;
fn decision_level(&self) -> DecisionLevel;
fn decision_vi(&self, lv: DecisionLevel) -> VarId;
fn remains(&self) -> bool;
fn assign_ref(&self) -> &[Option<bool>];
fn level_ref(&self) -> &[DecisionLevel];
fn best_assigned(&mut self) -> Option<usize>;
#[cfg(feature = "rephase")]
fn best_phases_invalid(&self) -> bool;
fn extend_model(&mut self, c: &mut impl ClauseDBIF) -> Vec<Option<bool>>;
fn satisfies(&self, c: &[Lit]) -> bool;
}
#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
pub enum AssignReason {
BinaryLink(Lit),
Decision(DecisionLevel),
Implication(ClauseId),
None,
}
impl fmt::Display for AssignReason {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
&AssignReason::BinaryLink(_) => write!(f, "Implied by a binary clause"),
AssignReason::Decision(0) => write!(f, "Asserted"),
AssignReason::Decision(lvl) => write!(f, "Decided at level {lvl}"),
AssignReason::Implication(cid) => write!(f, "Implied by {cid}"),
AssignReason::None => write!(f, "Not assigned"),
}
}
}
#[derive(Clone, Debug)]
pub struct Var {
flags: FlagVar,
reward: f64,
#[cfg(feature = "boundary_check")]
pub propagated_at: usize,
#[cfg(feature = "boundary_check")]
pub timestamp: usize,
#[cfg(feature = "boundary_check")]
pub state: VarState,
}
#[derive(Clone, Debug)]
pub struct AssignStack {
assign: Vec<Option<bool>>,
level: Vec<DecisionLevel>,
reason: Vec<AssignReason>,
trail: Vec<Lit>,
trail_lim: Vec<usize>,
q_head: usize,
root_level: DecisionLevel,
var_order: VarIdHeap, #[cfg(feature = "trail_saving")]
reason_saved: Vec<AssignReason>,
#[cfg(feature = "trail_saving")]
trail_saved: Vec<Lit>,
num_reconflict: usize,
num_repropagation: usize,
best_assign: bool,
build_best_at: usize,
num_best_assign: usize,
num_rephase: usize,
bp_divergence_ema: Ema,
#[cfg(feature = "best_phases_tracking")]
best_phases: HashMap<VarId, (bool, AssignReason)>,
#[cfg(feature = "rephase")]
phase_age: usize,
pub stage_scale: usize,
pub eliminated: Vec<Lit>,
pub num_vars: usize,
pub num_asserted_vars: usize,
pub num_eliminated_vars: usize,
num_decision: usize,
num_propagation: usize,
pub num_conflict: usize,
num_restart: usize,
assign_rate: ProgressASG,
dpc_ema: EmaSU,
ppc_ema: EmaSU,
cpr_ema: EmaSU,
tick: usize,
var: Vec<Var>,
activity_decay: f64,
#[cfg(feature = "EVSIDS")]
activity_decay_default: f64,
activity_anti_decay: f64,
#[cfg(feature = "EVSIDS")]
activity_decay_step: f64,
}
#[cfg(feature = "boundary_check")]
#[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
pub struct Assign {
pub at: usize,
pub pos: Option<usize>,
pub lvl: DecisionLevel,
pub lit: i32,
pub val: Option<bool>,
pub by: AssignReason,
pub state: VarState,
}
#[cfg(feature = "boundary_check")]
pub trait DebugReportIF {
fn report(&self, asg: &AssignStack) -> Vec<Assign>;
}
#[cfg(feature = "boundary_check")]
fn make_lit_report(asg: &AssignStack, lit: &Lit) -> Assign {
let vi = lit.vi();
Assign {
lit: i32::from(lit),
val: asg.assigned(*lit),
pos: asg.trail.iter().position(|l| vi == l.vi()),
lvl: asg.level(vi),
by: asg.reason(vi),
at: asg.var(vi).propagated_at,
state: asg.var[vi].state,
}
}
#[cfg(feature = "boundary_check")]
impl DebugReportIF for Lit {
fn report(&self, asg: &AssignStack) -> Vec<Assign> {
vec![make_lit_report(asg, self)]
}
}
#[cfg(feature = "boundary_check")]
impl DebugReportIF for [Lit] {
fn report(&self, asg: &AssignStack) -> Vec<Assign> {
self.iter()
.map(|l| make_lit_report(asg, l))
.collect::<Vec<_>>()
}
}
#[cfg(feature = "boundary_check")]
impl DebugReportIF for Clause {
fn report(&self, asg: &AssignStack) -> Vec<Assign> {
let mut l = self
.iter()
.map(|l| make_lit_report(asg, l))
.collect::<Vec<_>>();
l.sort();
l
}
}
pub mod property {
use super::AssignStack;
use crate::types::*;
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum Tusize {
NumConflict,
NumDecision,
NumPropagation,
NumRephase,
NumRestart,
NumVar,
NumAssertedVar,
NumEliminatedVar,
NumReconflict,
NumRepropagation,
NumUnassertedVar,
NumUnassignedVar,
NumUnreachableVar,
RootLevel,
}
pub const USIZES: [Tusize; 14] = [
Tusize::NumConflict,
Tusize::NumDecision,
Tusize::NumPropagation,
Tusize::NumRephase,
Tusize::NumRestart,
Tusize::NumVar,
Tusize::NumAssertedVar,
Tusize::NumEliminatedVar,
Tusize::NumReconflict,
Tusize::NumRepropagation,
Tusize::NumUnassertedVar,
Tusize::NumUnassignedVar,
Tusize::NumUnreachableVar,
Tusize::RootLevel,
];
impl PropertyDereference<Tusize, usize> for AssignStack {
#[inline]
fn derefer(&self, k: Tusize) -> usize {
match k {
Tusize::NumConflict => self.num_conflict,
Tusize::NumDecision => self.num_decision,
Tusize::NumPropagation => self.num_propagation,
Tusize::NumRephase => self.num_rephase,
Tusize::NumRestart => self.num_restart,
Tusize::NumVar => self.num_vars,
Tusize::NumAssertedVar => self.num_asserted_vars,
Tusize::NumEliminatedVar => self.num_eliminated_vars,
Tusize::NumReconflict => self.num_reconflict,
Tusize::NumRepropagation => self.num_repropagation,
Tusize::NumUnassertedVar => {
self.num_vars - self.num_asserted_vars - self.num_eliminated_vars
}
Tusize::NumUnassignedVar => {
self.num_vars
- self.num_asserted_vars
- self.num_eliminated_vars
- self.trail.len()
}
Tusize::NumUnreachableVar => self.num_vars - self.num_best_assign,
Tusize::RootLevel => self.root_level as usize,
}
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum Tf64 {
AverageVarActivity,
CurrentWorkingSetSize,
VarDecayRate,
}
pub const F64S: [Tf64; 3] = [
Tf64::AverageVarActivity,
Tf64::CurrentWorkingSetSize,
Tf64::VarDecayRate,
];
impl PropertyDereference<Tf64, f64> for AssignStack {
#[inline]
fn derefer(&self, k: Tf64) -> f64 {
match k {
Tf64::AverageVarActivity => 0.0, Tf64::CurrentWorkingSetSize => 0.0, Tf64::VarDecayRate => self.activity_decay,
}
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum TEma {
AssignRate,
DecisionPerConflict,
PropagationPerConflict,
ConflictPerRestart,
ConflictPerBaseRestart,
BestPhaseDivergenceRate,
}
pub const EMAS: [TEma; 6] = [
TEma::AssignRate,
TEma::DecisionPerConflict,
TEma::PropagationPerConflict,
TEma::ConflictPerRestart,
TEma::ConflictPerBaseRestart,
TEma::BestPhaseDivergenceRate,
];
impl PropertyReference<TEma, EmaView> for AssignStack {
#[inline]
fn refer(&self, k: TEma) -> &EmaView {
match k {
TEma::AssignRate => self.assign_rate.as_view(),
TEma::DecisionPerConflict => self.dpc_ema.as_view(),
TEma::PropagationPerConflict => self.ppc_ema.as_view(),
TEma::ConflictPerRestart => self.cpr_ema.as_view(),
TEma::ConflictPerBaseRestart => self.cpr_ema.as_view(),
TEma::BestPhaseDivergenceRate => self.bp_divergence_ema.as_view(),
}
}
}
}