mod components;
mod dimacs;
mod literal;
pub(crate) mod show_set;
pub(crate) mod space;
pub(crate) mod weights;
pub(crate) use literal::EquivFold;
pub use literal::{Literal, VarId};
pub use show_set::{ShowMask, ShowSet};
pub use space::{Local, Original, Reduced, Space};
pub use weights::{WeightTable, Weights};
pub(crate) use dimacs::{DimacsHeader, parse_weight, rational_string, write_dimacs};
pub use dimacs::parse_rational_weight;
pub use components::detect_components_in;
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Clause {
pub literals: Vec<Literal>,
}
impl Clause {
pub fn new(literals: Vec<Literal>) -> Self {
debug_assert!(
{
let mut ok = true;
for i in 0..literals.len() {
for j in (i + 1)..literals.len() {
if literals[i].var == literals[j].var {
ok = false;
break;
}
}
if !ok {
break;
}
}
ok
},
"Clause::new: duplicate variable in literals {literals:?}",
);
Clause { literals }
}
}
impl std::ops::Deref for Clause {
type Target = [Literal];
#[inline(always)]
fn deref(&self) -> &[Literal] {
&self.literals
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
#[non_exhaustive]
pub enum Mode {
#[default]
Mc,
Wmc,
Pmc,
Pwmc,
Compile,
}
impl Mode {
const ALL: &'static [Mode] = &[Mode::Mc, Mode::Wmc, Mode::Pmc, Mode::Pwmc, Mode::Compile];
pub fn names() -> impl Iterator<Item = &'static str> {
Mode::ALL.iter().map(|m| m.token())
}
pub(crate) fn parse_track(s: &str) -> Option<Self> {
Mode::parse_mode(s).filter(|m| *m != Mode::Compile)
}
pub fn parse_mode(s: &str) -> Option<Self> {
Mode::ALL.iter().copied().find(|m| m.token() == s)
}
pub fn token(self) -> &'static str {
match self {
Mode::Mc => "mc",
Mode::Wmc => "wmc",
Mode::Pmc => "pmc",
Mode::Pwmc => "pwmc",
Mode::Compile => "compile",
}
}
pub fn is_weighted(self) -> bool {
matches!(self, Mode::Wmc | Mode::Pwmc)
}
pub fn is_projected(self) -> bool {
matches!(self, Mode::Pmc | Mode::Pwmc)
}
}
#[derive(Clone, Debug, Default)]
pub struct CnfMeta {
track: Option<Mode>,
show_vars: Option<ShowSet<Original>>,
pub(crate) weights: Option<WeightTable>,
}
impl CnfMeta {
pub fn from_parts(
num_vars: u32,
track: Option<Mode>,
show_vars: Option<ShowSet<Original>>,
weights: Option<WeightTable>,
) -> Result<Self, crate::error::VitriError> {
if let Some(var) = show_vars
.as_ref()
.and_then(|show| show.iter_vars().find(|var| var.0 >= num_vars))
{
return Err(crate::error::VitriError::input(format!(
"show variable {} exceeds declared variable count {num_vars}",
var.to_dimacs()
)));
}
if let Some(weights) = &weights {
weights.validate_num_vars(num_vars)?;
}
Ok(CnfMeta {
track,
show_vars,
weights,
})
}
pub fn declared_track(&self) -> Option<Mode> {
self.track
}
pub fn mode(&self) -> Mode {
self.track.unwrap_or_default()
}
pub fn declared_show_vars(&self) -> Option<&ShowSet<Original>> {
self.show_vars.as_ref()
}
pub fn declared_weights(&self) -> Option<&WeightTable> {
self.weights.as_ref()
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct CnfFormula {
pub num_vars: u32,
pub clauses: Vec<Clause>,
}
impl CnfFormula {
pub(crate) fn contradiction(num_vars: u32) -> Self {
CnfFormula {
num_vars,
clauses: vec![Clause::new(vec![])],
}
}
pub(crate) fn is_refuted(&self) -> bool {
contains_empty_clause(&self.clauses)
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct UnitPropagation {
pub residual: CnfFormula,
pub forced: Vec<Literal>,
}
pub fn propagate_units(formula: &CnfFormula) -> UnitPropagation {
let (clauses, forced) =
crate::preprocess::unit_propagation::propagate(&formula.clauses, formula.num_vars);
UnitPropagation {
residual: CnfFormula {
num_vars: formula.num_vars,
clauses,
},
forced,
}
}
pub(crate) fn contains_empty_clause(clauses: &[Clause]) -> bool {
clauses.iter().any(|c| c.literals.is_empty())
}
pub(crate) mod occ;
mod union_find;
pub(crate) mod stats;