ProvSQL C/C++ API
Adding support for provenance and uncertainty management to PostgreSQL databases
Loading...
Searching...
No Matches
dimacs_cnf.cpp
Go to the documentation of this file.
1/**
2 * @file dimacs_cnf.cpp
3 * @brief Implementation of the DIMACS-CNF to BooleanCircuit parser.
4 */
5#include "dimacs_cnf.h"
6#include "Circuit.hpp"
7
8#include <cstdlib>
9#include <map>
10#include <sstream>
11#include <stdexcept>
12#include <string>
13#include <vector>
14
15namespace {
16
17// A MCC weight line: "c p weight <lit> <w> 0". Returns true and fills
18// (lit, w) if @p line is one.
19bool parse_weight_line(const std::string &line, long &lit, double &w)
20{
21 std::istringstream iss(line);
22 std::string c, p, weight;
23 if (!(iss >> c >> p >> weight) || c != "c" || p != "p" || weight != "weight")
24 return false;
25 long zero = 1;
26 if (!(iss >> lit >> w >> zero))
27 return false;
28 return true;
29}
30
31} // namespace
32
33gate_t parse_dimacs_cnf(const std::string &text, BooleanCircuit &c,
34 bool weighted)
35{
36 std::map<long, double> weights; // positive literal -> weight
37 std::vector<int> tokens; // clause literals, 0-terminated, flattened
38 bool saw_header = false;
39
40 std::istringstream in(text);
41 std::string line;
42 while (std::getline(in, line)) {
43 // Trim leading whitespace to classify the line.
44 size_t s = line.find_first_not_of(" \t\r");
45 if (s == std::string::npos)
46 continue;
47 char lead = line[s];
48 if (lead == 'c') {
49 long lit; double w;
50 if (parse_weight_line(line.substr(s), lit, w) && lit > 0)
51 weights[lit] = w;
52 continue; // other comments (incl. "c t wmc", "c p show") ignored
53 }
54 if (lead == 'p') {
55 std::istringstream iss(line.substr(s));
56 std::string p, cnf;
57 iss >> p >> cnf; // "p cnf <nvars> <nclauses>"; counts not needed
58 saw_header = true;
59 continue;
60 }
61 // A clause line: whitespace-separated literals (a clause may span lines,
62 // terminated by 0).
63 std::istringstream iss(line.substr(s));
64 int lit;
65 while (iss >> lit)
66 tokens.push_back(lit);
67 }
68 if (!saw_header)
69 throw std::runtime_error("DIMACS: missing 'p cnf' header");
70
71 // Materialise the circuit. Input / NOT gates are created on first use.
72 std::map<int, gate_t> in_gate; // var -> IN gate
73 std::map<int, gate_t> neg_gate; // var -> NOT gate
74
75 auto literal_gate = [&](int lit) -> gate_t {
76 int v = std::abs(lit);
77 auto it = in_gate.find(v);
78 if (it == in_gate.end()) {
79 double p = 0.5;
80 if (weighted) {
81 auto w = weights.find(v);
82 if (w != weights.end()) p = w->second;
83 }
84 gate_t g = c.setGate("v" + std::to_string(v), BooleanGate::IN, p);
85 it = in_gate.emplace(v, g).first;
86 }
87 if (lit > 0)
88 return it->second;
89 auto n = neg_gate.find(v);
90 if (n == neg_gate.end()) {
91 gate_t ng = c.setGate("n" + std::to_string(v), BooleanGate::NOT);
92 c.addWire(ng, it->second);
93 n = neg_gate.emplace(v, ng).first;
94 }
95 return n->second;
96 };
97
98 gate_t root = c.setGate("root", BooleanGate::AND);
99 unsigned clause_no = 0;
100 gate_t clause = c.setGate("cl0", BooleanGate::OR);
101 bool clause_open = false;
102 for (int lit : tokens) {
103 if (lit == 0) {
104 c.addWire(root, clause);
105 clause = c.setGate("cl" + std::to_string(++clause_no), BooleanGate::OR);
106 clause_open = false;
107 } else {
108 c.addWire(clause, literal_gate(lit));
109 clause_open = true;
110 }
111 }
112 // A trailing clause not terminated by 0 is still honoured.
113 if (clause_open)
114 c.addWire(root, clause);
115
116 return root;
117}
@ NOT
Logical negation of a single child gate.
@ OR
Logical disjunction of child gates.
@ AND
Logical conjunction of child gates.
@ IN
Input (variable) gate representing a base tuple.
gate_t
Strongly-typed gate identifier.
Definition Circuit.h:49
Out-of-line template method implementations for Circuit<gateType>.
Boolean circuit for provenance formula evaluation.
gate_t setGate(BooleanGate type) override
Allocate a new gate with type type and no UUID.
void addWire(gate_t f, gate_t t)
Add a directed wire from gate f (parent) to gate t (child).
Definition Circuit.hpp:81
gate_t parse_dimacs_cnf(const std::string &text, BooleanCircuit &c, bool weighted)
Parse text (a DIMACS CNF) into c and return the root gate.
Parse a DIMACS CNF into a ProvSQL BooleanCircuit.