logicaffeine_proof/
dimacs.rs1use crate::cdcl::{Lit, Solver};
15
16#[derive(Clone, Debug, PartialEq, Eq)]
18pub struct DimacsCnf {
19 pub num_vars: usize,
20 pub clauses: Vec<Vec<Lit>>,
21}
22
23#[derive(Clone, Debug, PartialEq, Eq)]
25pub enum DimacsError {
26 MissingHeader,
28 MalformedHeader(String),
30 VarOutOfRange { var: i64, num_vars: usize },
32 InvalidToken(String),
34 UnterminatedClause,
36}
37
38impl DimacsCnf {
39 pub fn into_solver(&self) -> Solver {
41 let mut s = Solver::new(self.num_vars);
42 for c in &self.clauses {
43 s.add_clause(c.clone());
44 }
45 s
46 }
47}
48
49pub fn parse(input: &str) -> Result<DimacsCnf, DimacsError> {
51 let mut header: Option<usize> = None;
52 let mut clauses: Vec<Vec<Lit>> = Vec::new();
53 let mut current: Vec<Lit> = Vec::new();
54
55 for line in input.lines() {
56 let line = line.trim();
57 if line.is_empty() || line.starts_with('c') {
58 continue;
59 }
60 if let Some(rest) = line.strip_prefix("p ") {
61 if header.is_some() {
62 return Err(DimacsError::MalformedHeader(line.to_string()));
63 }
64 let mut it = rest.split_whitespace();
65 match (it.next(), it.next(), it.next(), it.next()) {
66 (Some("cnf"), Some(nv), Some(nc), None) => {
67 let num_vars =
68 nv.parse::<usize>().map_err(|_| DimacsError::MalformedHeader(line.to_string()))?;
69 nc.parse::<usize>().map_err(|_| DimacsError::MalformedHeader(line.to_string()))?;
70 header = Some(num_vars);
71 }
72 _ => return Err(DimacsError::MalformedHeader(line.to_string())),
73 }
74 continue;
75 }
76 let num_vars = header.ok_or(DimacsError::MissingHeader)?;
78 for tok in line.split_whitespace() {
79 let n: i64 = tok.parse().map_err(|_| DimacsError::InvalidToken(tok.to_string()))?;
80 if n == 0 {
81 clauses.push(std::mem::take(&mut current));
82 } else {
83 let v = n.unsigned_abs();
84 if v as usize > num_vars {
85 return Err(DimacsError::VarOutOfRange { var: n, num_vars });
86 }
87 current.push(Lit::new((v - 1) as u32, n > 0));
88 }
89 }
90 }
91
92 let num_vars = header.ok_or(DimacsError::MissingHeader)?;
93 if !current.is_empty() {
94 return Err(DimacsError::UnterminatedClause);
95 }
96 Ok(DimacsCnf { num_vars, clauses })
97}
98
99pub fn print(cnf: &DimacsCnf) -> String {
101 let mut out = format!("p cnf {} {}\n", cnf.num_vars, cnf.clauses.len());
102 for clause in &cnf.clauses {
103 for l in clause {
104 let v = (l.var() + 1) as i64;
105 out.push_str(&(if l.is_positive() { v } else { -v }).to_string());
106 out.push(' ');
107 }
108 out.push_str("0\n");
109 }
110 out
111}