oxidd_parser/
dimacs.rs

1//! DIMACS CNF/SAT parser based on the paper
2//! "[Satisfiability Suggested Format][spec]"
3//!
4//! The parsers perform some trivial simplifications on the CNF or the SAT
5//! formula: CNFs with empty clauses become
6//! [`Literal::FALSE`][crate::Literal::FALSE], empty CNFs become
7//! [`Literal::TRUE`][crate::Literal::TRUE]. Likewise, empty disjunctions,
8//! conjunctions, etc., in SAT formulas are replaced by the respective constant.
9//! Equivalence operators are replaced by XOR and negation (since
10//! [`Circuit`s][crate::Circuit] do not support equivalence). Conjunction,
11//! disjunction, and XOR operators with just a single operand are discarded.
12//!
13//! In addition to regular OR clauses, the CNF parser also supports [XOR
14//! clauses][xcnf] (XCNF).
15//!
16//! [spec]: https://www21.in.tum.de/~lammich/2015_SS_Seminar_SAT/resources/dimacs-cnf.pdf
17//! [xcnf]: https://www.msoos.org/xor-clauses/
18
19// spell-checker:ignore multispace
20
21use rustc_hash::FxHashSet;
22
23use nom::bytes::complete::tag;
24use nom::character::complete::{char, line_ending, multispace0, space0, space1, u64};
25use nom::combinator::{consumed, cut, eof, value};
26use nom::error::{context, ContextError, ErrorKind, FromExternalError, ParseError};
27use nom::multi::many0_count;
28use nom::sequence::{preceded, terminated};
29use nom::{Err, IResult};
30
31use crate::util::{
32    self, context_loc, eol, fail, fail_with_contexts, line_span, word, word_span, MAX_CAPACITY,
33};
34use crate::{ParseOptions, Problem, Tree, Var, VarSet};
35
36// spell-checker:ignore SATX,SATEX
37
38#[allow(clippy::upper_case_acronyms)]
39#[derive(Clone, Copy, PartialEq, Eq, Debug)]
40enum Format {
41    CNF,
42    SAT { xor: bool, eq: bool },
43}
44#[rustfmt::skip]
45const SAT: Format = Format::SAT { xor: false, eq: false };
46#[rustfmt::skip]
47const SATX: Format = Format::SAT { xor: true, eq: false };
48#[rustfmt::skip]
49const SATE: Format = Format::SAT { xor: false, eq: false };
50#[rustfmt::skip]
51const SATEX: Format = Format::SAT { xor: true, eq: true };
52
53fn format<'a, E: ParseError<&'a [u8]> + ContextError<&'a [u8]>>(
54    input: &'a [u8],
55) -> IResult<&'a [u8], Format, E> {
56    let inner = |input: &'a [u8]| match input {
57        [b'c', b'n', b'f', r @ ..] => Ok((r, Format::CNF)),
58        [b's', b'a', b't', b'e', b'x', r @ ..] => Ok((r, SATEX)),
59        [b's', b'a', b't', b'e', r @ ..] => Ok((r, SATE)),
60        [b's', b'a', b't', b'x', r @ ..] => Ok((r, SATX)),
61        [b's', b'a', b't', r @ ..] => Ok((r, SAT)),
62        _ => Err(Err::Error(E::from_error_kind(input, ErrorKind::Alt))),
63    };
64
65    context_loc(
66        || word_span(input),
67        "format must be one of 'cnf', 'sat', 'satx', 'sate', or 'satex'",
68        word(inner),
69    )(input)
70}
71
72/// Parses a problem line, i.e., `p cnf <#vars> <#clauses>` or
73/// `p sat[e][x] <#vars>`
74///
75/// Returns the format, number of vars and in case of `cnf` format the number of
76/// clauses together with their spans.
77fn problem_line<'a, E: ParseError<&'a [u8]> + ContextError<&'a [u8]>>(
78    input: &'a [u8],
79) -> IResult<&'a [u8], ((&'a [u8], Format), (&'a [u8], usize), (&'a [u8], usize)), E> {
80    let inner = |input| {
81        let (input, _) = context(
82            "all lines in the preamble must begin with 'c' or 'p'",
83            cut(char('p')),
84        )(input)?;
85        let (input, _) = space1(input)?;
86        let (input, fmt) = consumed(format)(input)?;
87        let (input, _) = space1(input)?;
88        let (input, num_vars) = consumed(u64)(input)?;
89        if num_vars.1 > MAX_CAPACITY {
90            return fail(num_vars.0, "too many variables");
91        }
92        let num_vars = (num_vars.0, num_vars.1 as usize);
93        if fmt.1 == Format::CNF {
94            let msg = "expected the number of clauses (CNF format)";
95            let (input, _) = context(msg, space1)(input)?;
96            let (input, num_clauses) = context_loc(|| word_span(input), msg, consumed(u64))(input)?;
97            if num_clauses.1 > MAX_CAPACITY {
98                return fail(num_clauses.0, "too many clauses");
99            }
100            let num_clauses = (num_clauses.0, num_clauses.1 as usize);
101            let (input, _) = space0(input)?;
102            value((fmt, num_vars, num_clauses), line_ending)(input)
103        } else {
104            let (input, _) = space0(input)?;
105            context(
106                "expected a line break (SAT formats do not take a number of clauses)",
107                value((fmt, num_vars, ([].as_slice(), 0)), line_ending),
108            )(input)
109        }
110    };
111
112    context_loc(
113        || line_span(input),
114        "problem line must have format 'p <format> <#vars> [<#clauses>]'",
115        cut(inner),
116    )(input)
117}
118
119#[derive(Clone, PartialEq, Eq, Debug)]
120struct Preamble {
121    format: Format,
122    vars: VarSet,
123    /// Number of clauses (CNF format, otherwise 0)
124    num_clauses: usize,
125    clause_tree: Option<Tree<usize>>,
126}
127
128/// Parses the preamble, i.e., all `c` and `p` lines at the beginning of the
129/// file
130///
131/// Note: `parse_orders` only instructs the parser to treat comment lines as
132/// order lines. In case a var or a clause order is given, this function ensures
133/// that they are valid. However, if no var order is given, then the returned
134/// var order is empty, and if no clause order is given, then the returned
135/// clause order is empty.
136fn preamble<'a, E>(
137    parse_var_order: bool,
138    parse_clause_tree: bool,
139) -> impl Fn(&'a [u8]) -> IResult<&'a [u8], Preamble, E>
140where
141    E: ParseError<&'a [u8]> + ContextError<&'a [u8]> + FromExternalError<&'a [u8], String>,
142{
143    move |mut input| {
144        // TODO: `parse_clause_tree` currently requires a valid (or empty)
145        // variable order. Is this what we want?
146        if parse_var_order || parse_clause_tree {
147            let mut vars = VarSet {
148                len: 0,
149                order: Vec::new(),
150                order_tree: None,
151                names: Vec::new(),
152            };
153
154            let mut max_var_span = [].as_slice(); // in the name mapping / linear order
155            let mut tree_max_var = ([].as_slice(), 0); // dummy value
156            let mut name_set: FxHashSet<&str> = Default::default();
157
158            // clause order
159            let mut clause_tree = None;
160            let mut clause_order_span = [].as_slice();
161            let mut max_clause = ([].as_slice(), 0); // dummy value
162
163            loop {
164                let next_input = match preceded(char::<_, E>('c'), space1)(input) {
165                    Ok((i, _)) => i,
166                    Err(_) => break,
167                };
168                if let Ok((next_input, _)) = preceded(tag("co"), space1::<_, E>)(next_input) {
169                    if parse_clause_tree {
170                        if clause_tree.is_some() {
171                            return fail(line_span(input), "clause order may only be given once");
172                        }
173                        let t: Tree<usize>;
174                        (input, (clause_order_span, (t, max_clause))) =
175                            terminated(consumed(util::tree(false, false)), eol)(next_input)?;
176                        clause_tree = Some(t);
177                    } else {
178                        input = match memchr::memchr(b'\n', input) {
179                            Some(i) => &input[i + 1..],
180                            None => &input[input.len()..],
181                        };
182                    }
183                } else if let Ok((next_input, _)) = preceded(tag("vo"), space1::<_, E>)(next_input)
184                {
185                    // variable order tree
186                    if vars.order_tree.is_some() {
187                        let msg = "variable order tree may only be given once";
188                        return fail(line_span(input), msg);
189                    }
190                    let t: Tree<Var>;
191                    (input, (t, tree_max_var)) =
192                        terminated(util::tree(true, true), eol)(next_input)?;
193
194                    // The variable order tree takes precedence (and determines the linear order)
195                    vars.order.clear();
196                    vars.order.reserve(tree_max_var.1 + 1);
197                    t.flatten_into(&mut vars.order);
198                    vars.order_tree = Some(t);
199                } else if let Ok((next_input, ((var_span, var), name))) =
200                    util::var_order_record::<E>(next_input)
201                {
202                    // var order line
203                    input = next_input;
204                    if var == 0 {
205                        return fail(var_span, "variable number must be greater than 0");
206                    }
207                    if var > MAX_CAPACITY {
208                        return fail(var_span, "variable number too large");
209                    }
210
211                    let num_vars = var as usize;
212                    let var = num_vars - 1;
213
214                    if num_vars > vars.names.len() {
215                        vars.names.resize(num_vars, None);
216                        vars.order.reserve(num_vars - vars.names.len());
217                        max_var_span = var_span;
218                    } else if vars.names[var].is_some() {
219                        return fail(var_span, "second occurrence of variable in order");
220                    }
221                    // always write Some to mark the variable as present
222                    vars.names[var] = Some(if let Some(name) = name {
223                        let Ok(name) = std::str::from_utf8(name) else {
224                            return fail(name, "invalid UTF-8");
225                        };
226                        if !name_set.insert(name) {
227                            return fail(name.as_bytes(), "second occurrence of variable name");
228                        }
229                        name.to_owned()
230                    } else {
231                        String::new()
232                    });
233                    if vars.order_tree.is_none() {
234                        vars.order.push(var);
235                    }
236                } else {
237                    return fail(
238                        line_span(input),
239                        "expected a variable order record ('c <var> [<name>]'), a variable order tree ('c vo <tree>'), or a clause order tree ('c co <tree>')",
240                    );
241                }
242            }
243
244            if vars.order_tree.is_none() && vars.names.len() != vars.order.len() {
245                return fail_with_contexts([
246                    (input, "expected another variable order line"),
247                    (max_var_span, "note: maximal variable number given here"),
248                ]);
249            }
250
251            let (next_input, (format, num_vars, num_clauses)) = problem_line(input)?;
252            if vars.order_tree.is_none() {
253                if !vars.order.is_empty() && num_vars.1 != vars.order.len() {
254                    return fail_with_contexts([
255                        (num_vars.0, "number of variables does not match"),
256                        (max_var_span, "note: maximal variable number given here"),
257                    ]);
258                }
259            } else {
260                if num_vars.1 != tree_max_var.1 + 1 {
261                    return fail_with_contexts([
262                        (num_vars.0, "number of variables does not match"),
263                        (tree_max_var.0, "note: maximal variable number given here"),
264                    ]);
265                }
266                if vars.names.len() > num_vars.1 {
267                    return fail_with_contexts([
268                        (max_var_span, "name assigned to non-existing variable"),
269                        (num_vars.0, "note: number of variables given here"),
270                    ]);
271                }
272            }
273
274            if clause_tree.is_some() {
275                if format.1 != Format::CNF {
276                    let msg0 = "clause tree only supported for 'cnf' format";
277                    return fail_with_contexts([
278                        (clause_order_span, msg0),
279                        (format.0, "note: format given here"),
280                    ]);
281                }
282                if max_clause.1 != num_clauses.1 - 1 {
283                    return fail_with_contexts([
284                        (num_clauses.0, "number of clauses does not match"),
285                        (max_clause.0, "note: maximal clause number given here"),
286                    ]);
287                }
288            }
289
290            // cleanup: we used `Some(String::new())` to mark unnamed variables as present
291            while let Some(name) = vars.names.last() {
292                if !name.as_ref().is_some_and(String::is_empty) {
293                    break;
294                }
295                vars.names.pop();
296            }
297            for name in &mut vars.names {
298                if name.as_ref().is_some_and(String::is_empty) {
299                    *name = None;
300                }
301            }
302
303            vars.len = num_vars.1;
304            #[cfg(debug_assertions)]
305            vars.check_valid();
306            let preamble = Preamble {
307                format: format.1,
308                vars,
309                num_clauses: num_clauses.1,
310                clause_tree,
311            };
312            Ok((next_input, preamble))
313        } else {
314            let (input, (format, num_vars, num_clauses)) =
315                preceded(many0_count(util::comment), problem_line)(input)?;
316            let preamble = Preamble {
317                format: format.1,
318                vars: VarSet::new(num_vars.1),
319                num_clauses: num_clauses.1,
320                clause_tree: None,
321            };
322            Ok((input, preamble))
323        }
324    }
325}
326
327mod cnf {
328    use nom::branch::alt;
329    use nom::character::complete::{char, multispace0, one_of, u64};
330    use nom::combinator::{consumed, eof, iterator, map, recognize};
331    use nom::error::{context, ContextError, ErrorKind, FromExternalError, ParseError};
332    use nom::sequence::preceded;
333    use nom::{Err, IResult};
334
335    use crate::util::fail;
336    use crate::{Circuit, GateKind, Literal, Problem, Tree};
337
338    use super::Preamble;
339
340    #[derive(Clone, Copy, PartialEq, Eq, Debug)]
341    enum CNFTokenKind {
342        Int(u64),
343        Neg,
344        Xor,
345    }
346
347    #[derive(Clone, PartialEq, Eq, Debug)]
348    struct CNFToken<'a> {
349        span: &'a [u8],
350        kind: CNFTokenKind,
351    }
352
353    fn lex<'a, E: ParseError<&'a [u8]> + ContextError<&'a [u8]>>(
354        input: &'a [u8],
355    ) -> IResult<&'a [u8], CNFToken<'a>, E> {
356        let tok = alt((
357            map(consumed(u64), |(span, n)| CNFToken {
358                span,
359                kind: CNFTokenKind::Int(n),
360            }),
361            map(recognize(char('-')), |span| CNFToken {
362                span,
363                kind: CNFTokenKind::Neg,
364            }),
365            map(recognize(one_of("xX")), |span| CNFToken {
366                span,
367                kind: CNFTokenKind::Xor,
368            }),
369        ));
370
371        preceded(multispace0, tok)(input)
372    }
373
374    fn make_conj_tree(
375        circuit: &mut Circuit,
376        conjuncts: &[Literal],
377        tree: Tree<usize>,
378        stack: &mut Vec<Literal>,
379    ) -> Literal {
380        match tree {
381            Tree::Inner(children) => {
382                let saved_stack_len = stack.len();
383                for child in children {
384                    let l = make_conj_tree(circuit, conjuncts, child, stack);
385                    stack.push(l);
386                }
387                let root = circuit.push_gate(GateKind::And);
388                circuit.push_gate_inputs(stack[saved_stack_len..].iter().copied());
389                stack.truncate(saved_stack_len);
390                root
391            }
392            Tree::Leaf(i) => conjuncts[i],
393        }
394    }
395
396    pub fn parse<'a, E>(
397        preamble: Preamble,
398    ) -> impl FnOnce(&'a [u8]) -> IResult<&'a [u8], Problem, E>
399    where
400        E: ParseError<&'a [u8]> + ContextError<&'a [u8]> + FromExternalError<&'a [u8], String>,
401    {
402        move |input| {
403            let Preamble {
404                vars,
405                num_clauses,
406                clause_tree: clause_order_tree,
407                ..
408            } = preamble;
409            let num_vars = vars.len();
410            let mut circuit = Circuit::new(vars);
411            circuit.push_gate(GateKind::Or);
412
413            let mut neg = false;
414
415            let mut it = iterator(input, lex::<E>);
416            for token in &mut it {
417                match token.kind {
418                    CNFTokenKind::Int(0) => {
419                        circuit.push_gate(GateKind::Or);
420                    }
421                    CNFTokenKind::Int(n) => {
422                        if n > num_vars as u64 {
423                            return fail(token.span, "variables must be in range [1, #vars]");
424                        }
425                        circuit.push_gate_input(Literal::from_input(neg, (n - 1) as usize));
426                        neg = false;
427                    }
428                    CNFTokenKind::Neg if !neg => neg = true,
429                    CNFTokenKind::Neg => return fail(token.span, "expected a variable"),
430                    CNFTokenKind::Xor => {
431                        if let Some(gate) = circuit.last_gate() {
432                            if !gate.inputs.is_empty() {
433                                return fail(token.span, "XOR clauses must be marked as such at the beginning of the clause");
434                            }
435                            circuit.set_last_gate_kind(GateKind::Xor);
436                        }
437                    }
438                }
439            }
440
441            let (input, ()) = it.finish()?;
442            let (input, _) = multispace0(input)?;
443            let (input, _) = context("expected a literal or '0'", eof)(input)?;
444
445            let num_gates = circuit.num_gates();
446            if num_gates != num_clauses {
447                // The last clause may or may not be terminated by 0. In case it is, we called
448                // `push_clause()` once too often.
449                if num_gates == num_clauses + 1 && circuit.last_gate().unwrap().inputs.is_empty() {
450                    circuit.pop_gate();
451                } else {
452                    return Err(Err::Failure(E::from_external_error(
453                        input,
454                        ErrorKind::Fail,
455                        format!("expected {num_clauses} clauses, got {num_gates}"),
456                    )));
457                }
458            }
459            let num_gates = circuit.num_gates(); // may have been decremented above
460
461            let root = if num_gates == 0 {
462                Literal::TRUE
463            } else {
464                let mut is_false = false;
465                let mut conj = Vec::with_capacity(num_gates);
466                let mut gate = 0;
467                circuit.retain_gates(|inputs| {
468                    if is_false {
469                        return false;
470                    }
471                    match inputs {
472                        [] => {
473                            is_false = true;
474                            false
475                        }
476                        [l] => {
477                            conj.push(*l);
478                            false
479                        }
480                        _ => {
481                            conj.push(Literal::from_gate(false, gate));
482                            gate += 1;
483                            true
484                        }
485                    }
486                });
487
488                if is_false {
489                    circuit.clear_gates();
490                    Literal::FALSE
491                } else if let Some(tree) = clause_order_tree {
492                    let mut stack = Vec::with_capacity(num_clauses);
493                    make_conj_tree(&mut circuit, &conj, tree, &mut stack)
494                } else {
495                    let root = circuit.push_gate(GateKind::And);
496                    circuit.push_gate_inputs(conj);
497                    root
498                }
499            };
500
501            Ok((
502                input,
503                Problem {
504                    circuit,
505                    details: crate::ProblemDetails::Root(root),
506                },
507            ))
508        }
509    }
510}
511
512mod sat {
513    use nom::branch::alt;
514    use nom::bytes::complete::tag;
515    use nom::character::complete::{char, multispace0, u64};
516    use nom::combinator::{consumed, map, recognize, value};
517    use nom::error::{ContextError, ErrorKind, ParseError};
518    use nom::Err;
519    use nom::IResult;
520
521    use crate::util::{fail, map_res_fail, word};
522    use crate::{Circuit, GateKind, Literal, Problem, ProblemDetails, Var, VarSet};
523
524    #[derive(Clone, Copy, PartialEq, Eq, Debug)]
525    enum TokenKind {
526        Var(Var),
527        Lpar,
528        Rpar,
529        Neg,
530        And,
531        Or,
532        Xor,
533        Eq,
534    }
535
536    #[derive(Clone, PartialEq, Eq, Debug)]
537    struct Token<'a> {
538        span: &'a [u8],
539        kind: TokenKind,
540    }
541
542    macro_rules! match_tok {
543        ($matcher:expr, $tok:ident) => {
544            map(recognize($matcher), |span| {
545                Some(Token {
546                    span,
547                    kind: TokenKind::$tok,
548                })
549            })
550        };
551    }
552
553    fn lex<'a, E: ParseError<&'a [u8]> + ContextError<&'a [u8]>>(
554        num_vars: usize,
555    ) -> impl Fn(&'a [u8]) -> IResult<&'a [u8], Option<Token<'a>>, E> {
556        move |input| {
557            let (input, _) = multispace0(input)?; // should never fail
558            if input.is_empty() {
559                return Ok((input, None));
560            }
561            alt((
562                map_res_fail(consumed(u64), |(span, n)| {
563                    if n == 0 || n > num_vars as u64 {
564                        Err((span, "variables must be in range [1, #vars]"))
565                    } else {
566                        Ok(Some(Token {
567                            span,
568                            kind: TokenKind::Var(n as usize),
569                        }))
570                    }
571                }),
572                match_tok!(char('('), Lpar),
573                match_tok!(char(')'), Rpar),
574                match_tok!(char('-'), Neg),
575                match_tok!(char('*'), And),
576                match_tok!(char('+'), Or),
577                match_tok!(word(tag("xor")), Xor),
578                match_tok!(char('='), Eq),
579            ))(input)
580        }
581    }
582
583    #[derive(Debug)]
584    enum SatParserErr<'a, E> {
585        E(E),
586        Rpar { input: &'a [u8], span: &'a [u8] },
587    }
588    impl<'a, E: ParseError<&'a [u8]>> ParseError<&'a [u8]> for SatParserErr<'a, E> {
589        fn from_error_kind(input: &'a [u8], kind: ErrorKind) -> Self {
590            Self::E(E::from_error_kind(input, kind))
591        }
592
593        fn append(input: &'a [u8], kind: ErrorKind, other: Self) -> Self {
594            match other {
595                Self::E(other) => Self::E(E::append(input, kind, other)),
596                Self::Rpar { .. } => unreachable!(),
597            }
598        }
599    }
600    impl<'a, E: ContextError<&'a [u8]>> ContextError<&'a [u8]> for SatParserErr<'a, E> {
601        fn add_context(input: &'a [u8], ctx: &'static str, other: Self) -> Self {
602            match other {
603                Self::E(other) => Self::E(E::add_context(input, ctx, other)),
604                Self::Rpar { .. } => other,
605            }
606        }
607    }
608
609    fn expect<'a, E: ParseError<&'a [u8]> + ContextError<&'a [u8]>>(
610        kind: TokenKind,
611        err: &'static str,
612        num_vars: usize,
613    ) -> impl Fn(&'a [u8]) -> IResult<&'a [u8], (), E> {
614        move |input| {
615            let (input, tok) = lex(num_vars)(input)?;
616            match tok {
617                None => fail(input, err),
618                Some(tok) if tok.kind != kind => fail(tok.span, err),
619                _ => Ok((input, ())),
620            }
621        }
622    }
623
624    fn formula<'a, E: ParseError<&'a [u8]> + ContextError<&'a [u8]>>(
625        allow_xor: bool,
626        allow_eq: bool,
627        circuit: &mut Circuit,
628        stack: &mut Vec<Literal>,
629        input: &'a [u8],
630    ) -> IResult<&'a [u8], Literal, SatParserErr<'a, E>> {
631        let num_vars = circuit.inputs().len();
632        let (input, tok) = lex(num_vars)(input)?;
633        let tok = match tok {
634            Some(tok) => tok,
635            None => return fail(input, "expected a formula"),
636        };
637
638        match tok.kind {
639            TokenKind::Var(n) => Ok((input, Literal::from_input(false, n - 1))),
640            TokenKind::Lpar => {
641                let (input, l) = formula(allow_xor, allow_eq, circuit, stack, input)?;
642                value(l, expect(TokenKind::Rpar, "expected ')'", num_vars))(input)
643            }
644            TokenKind::Rpar => Err(Err::Error(SatParserErr::Rpar {
645                input,
646                span: tok.span,
647            })),
648            TokenKind::Neg => {
649                let (input, tok) = lex(num_vars)(input)?;
650                let tok = match tok {
651                    Some(t) => t,
652                    None => return fail(input, "expected a variable or '('"),
653                };
654                match tok.kind {
655                    TokenKind::Var(n) => Ok((input, Literal::from_input(true, n - 1))),
656                    TokenKind::Lpar => {
657                        let (input, l) = formula(allow_xor, allow_eq, circuit, stack, input)?;
658                        value(!l, expect(TokenKind::Rpar, "expected ')'", num_vars))(input)
659                    }
660                    _ => fail(tok.span, "expected a variable or '('"),
661                }
662            }
663            TokenKind::Xor if !allow_xor => fail(
664                tok.span,
665                "'xor' is only allowed in formats 'satx' and 'satex'",
666            ),
667            TokenKind::Eq if !allow_eq => fail(
668                tok.span,
669                "'=' is only allowed in formats 'sate' and 'satex'",
670            ),
671            _ => {
672                let (mut input, ()) = expect(TokenKind::Lpar, "expected '('", num_vars)(input)?;
673
674                let saved_stack_len = stack.len();
675                let input = loop {
676                    match formula(allow_xor, allow_eq, circuit, stack, input) {
677                        Ok((i, sub)) => {
678                            input = i;
679                            stack.push(sub)
680                        }
681                        Err(Err::Error(SatParserErr::Rpar { input, .. })) => break input,
682                        Err(f) => {
683                            stack.truncate(saved_stack_len);
684                            return Err(f);
685                        }
686                    }
687                };
688
689                let children = &stack[saved_stack_len..];
690                let literal = match children {
691                    [] => match tok.kind {
692                        TokenKind::And | TokenKind::Eq => Literal::TRUE,
693                        TokenKind::Or | TokenKind::Xor => Literal::FALSE,
694                        _ => unreachable!(),
695                    },
696                    [l] => *l,
697                    _ => {
698                        let l = circuit.push_gate(match tok.kind {
699                            TokenKind::And => GateKind::And,
700                            TokenKind::Or => GateKind::Or,
701                            _ => GateKind::Xor,
702                        });
703
704                        circuit.push_gate_inputs(children.iter().copied());
705
706                        if tok.kind == TokenKind::Eq && children.len() % 2 == 0 {
707                            !l
708                        } else {
709                            l
710                        }
711                    }
712                };
713                stack.truncate(saved_stack_len);
714
715                Ok((input, literal))
716            }
717        }
718    }
719
720    pub fn parse<'a, E: ParseError<&'a [u8]> + ContextError<&'a [u8]>>(
721        vars: VarSet,
722        allow_xor: bool,
723        allow_eq: bool,
724    ) -> impl FnOnce(&'a [u8]) -> IResult<&'a [u8], Problem, E> {
725        let num_vars = vars.len();
726        let mut circuit = Circuit::new(vars);
727        let mut stack = Vec::with_capacity(2 * num_vars);
728        move |input| match formula(allow_xor, allow_eq, &mut circuit, &mut stack, input) {
729            Ok((input, root)) => Ok((
730                input,
731                Problem {
732                    circuit,
733                    details: ProblemDetails::Root(root),
734                },
735            )),
736            Err(e) => Err(e.map(|e| match e {
737                SatParserErr::E(e) => e,
738                SatParserErr::Rpar { input, span } => E::add_context(
739                    span,
740                    "expected a formula",
741                    E::from_error_kind(input, ErrorKind::Fail),
742                ),
743            })),
744        }
745    }
746}
747
748/// Parse a DIMACS CNF/SAT file
749pub fn parse<'a, E>(options: &ParseOptions) -> impl Fn(&'a [u8]) -> IResult<&'a [u8], Problem, E>
750where
751    E: ParseError<&'a [u8]> + ContextError<&'a [u8]> + FromExternalError<&'a [u8], String>,
752{
753    let parse_var_order = options.var_order;
754    let parse_clause_tree = options.clause_tree;
755    move |input| {
756        let (input, preamble) = preamble(parse_var_order, parse_clause_tree)(input)?;
757        match preamble.format {
758            Format::CNF => cnf::parse(preamble)(input),
759            Format::SAT { xor, eq } => {
760                let (input, res) = sat::parse(preamble.vars, xor, eq)(input)?;
761                let (input, _) = context(
762                    "expected end of file (SAT files may only contain a single formula)",
763                    preceded(multispace0, eof),
764                )(input)?;
765                Ok((input, res))
766            }
767        }
768    }
769}
770
771#[cfg(test)]
772mod tests {
773    use nom::Finish;
774
775    use crate::util::test::*;
776    use crate::{Gate, Literal};
777
778    use super::*;
779
780    #[test]
781    fn example_cnf() {
782        let input = "c Example CNF format file
783c
784p cnf 4 3
7851 3 -4 0
7864 0 2
787-3";
788        let (input, problem) = parse::<()>(&OPTS_NO_ORDER)(input.as_bytes())
789            .finish()
790            .unwrap();
791        assert!(input.is_empty());
792
793        let (circuit, root) = unwrap_problem(problem);
794        let inputs = circuit.inputs();
795        assert_eq!(inputs.len(), 4);
796        assert!(inputs.order().is_none());
797
798        assert_eq!(root, g(2));
799        assert_eq!(circuit.gate(root), Some(Gate::and(&[g(0), v(3), g(1)])));
800        assert_eq!(circuit.gate(g(0)), Some(Gate::or(&[v(0), v(2), !v(3)])));
801        assert_eq!(circuit.gate(g(1)), Some(Gate::or(&[v(1), !v(2)])));
802    }
803
804    #[test]
805    fn example_cnf_0term() {
806        let input = "c Example CNF format file
807c
808p cnf 4 3
8091 3 -4 0
8104 0 2
811-3 0";
812        let (input, problem) = parse::<()>(&OPTS_NO_ORDER)(input.as_bytes())
813            .finish()
814            .unwrap();
815        assert!(input.is_empty());
816
817        let (circuit, root) = unwrap_problem(problem);
818        let inputs = circuit.inputs();
819        assert_eq!(inputs.len(), 4);
820        assert!(inputs.order().is_none());
821
822        assert_eq!(root, g(2));
823        assert_eq!(circuit.gate(root), Some(Gate::and(&[g(0), v(3), g(1)])));
824        assert_eq!(circuit.gate(g(0)), Some(Gate::or(&[v(0), v(2), !v(3)])));
825        assert_eq!(circuit.gate(g(1)), Some(Gate::or(&[v(1), !v(2)])));
826    }
827
828    #[test]
829    fn empty_cnf() {
830        let input = "p cnf 0 0\n";
831        let (input, problem) = parse::<()>(&OPTS_NO_ORDER)(input.as_bytes())
832            .finish()
833            .unwrap();
834        assert!(input.is_empty());
835
836        let (circuit, root) = unwrap_problem(problem);
837        let inputs = circuit.inputs();
838        assert_eq!(inputs.len(), 0);
839
840        assert_eq!(root, Literal::TRUE);
841    }
842
843    #[test]
844    fn example_sat() {
845        let input = "c Sample SAT format
846c
847p sat 4
848(*(+(1 3 -4)
849    +(4)
850    +(2 3)))";
851        let (input, problem) = parse::<()>(&OPTS_NO_ORDER)(input.as_bytes())
852            .finish()
853            .unwrap();
854        assert!(input.is_empty());
855
856        let (circuit, root) = unwrap_problem(problem);
857        let inputs = circuit.inputs();
858        assert_eq!(inputs.len(), 4);
859        assert!(inputs.order().is_none());
860
861        assert_eq!(root, g(2));
862        assert_eq!(circuit.gate(root), Some(Gate::and(&[g(0), v(3), g(1)])));
863        assert_eq!(circuit.gate(g(0)), Some(Gate::or(&[v(0), v(2), !v(3)])));
864        assert_eq!(circuit.gate(g(1)), Some(Gate::or(&[v(1), v(2)])));
865    }
866
867    #[test]
868    fn preamble_satx() {
869        let (input, preamble) = preamble::<()>(false, false)(b"p satx 1337 \n").unwrap();
870        assert!(input.is_empty());
871        assert_eq!(
872            preamble,
873            Preamble {
874                format: SATX,
875                vars: VarSet::new(1337),
876                num_clauses: 0,
877                clause_tree: None
878            }
879        );
880    }
881
882    #[test]
883    fn preamble_sate() {
884        let (input, preamble) = preamble::<()>(false, false)(b"p sate 1\n").unwrap();
885        assert!(input.is_empty());
886        assert_eq!(
887            preamble,
888            Preamble {
889                format: SATE,
890                vars: VarSet::new(1),
891                num_clauses: 0,
892                clause_tree: None
893            }
894        );
895    }
896
897    #[test]
898    fn preamble_satex() {
899        let (input, preamble) = preamble::<()>(false, false)(b"p satex 42 \n").unwrap();
900        assert!(input.is_empty());
901        assert_eq!(
902            preamble,
903            Preamble {
904                format: SATEX,
905                vars: VarSet::new(42),
906                num_clauses: 0,
907                clause_tree: None
908            }
909        );
910    }
911}