mutable
A Database System for Research and Fast Prototyping
Loading...
Searching...
No Matches
CNF.cpp
Go to the documentation of this file.
1#include <mutable/IR/CNF.hpp>
2
5#include <mutable/util/fn.hpp>
7
8
9using namespace m;
10using namespace m::ast;
11using namespace m::cnf;
12
13
14/*======================================================================================================================
15 * CNF Operations
16 *====================================================================================================================*/
17
18bool cnf::Clause::operator<=(const Clause &other) const
19{
20 for (auto pred : *this) {
21 if (not contains(other, pred))
22 return false;
23 }
24 return true;
25}
26
27bool CNF::operator<=(const CNF &other) const
28{
29 for (auto clause : *this) {
30 if (not contains(other, clause))
31 return false;
32 }
33 return true;
34}
35
37{
38 cnf::Clause res;
39 res.reserve(lhs.size() + rhs.size());
40 res.insert(res.end(), lhs.begin(), lhs.end());
41 res.insert(res.end(), rhs.begin(), rhs.end());
42 return res;
43}
44
46{
47 CNF res;
48 res.push_back(lhs);
49 res.push_back(rhs);
50 return res;
51}
52
53CNF cnf::operator&&(const CNF &lhs, const CNF &rhs)
54{
55 CNF res;
56 res.reserve(lhs.size() + rhs.size());
57 res.insert(res.end(), lhs.begin(), lhs.end());
58 res.insert(res.end(), rhs.begin(), rhs.end());
59 return res;
60}
61
62CNF cnf::operator||(const CNF &lhs, const CNF &rhs)
63{
64 CNF res;
65 if (lhs.size() == 0)
66 return rhs;
67 else if (rhs.size() == 0)
68 return lhs;
69
70 res.reserve(lhs.size() * rhs.size());
71 for (auto &clause_left : lhs) {
72 for (auto &clause_right : rhs)
73 res.push_back(clause_left or clause_right);
74 }
75 return res;
76}
77
79{
80 CNF res;
81 for (auto &p : clause)
82 res.emplace_back(Clause({not p}));
83 return res;
84}
85
87{
88 CNF res;
89 for (auto &clause : cnf)
90 res = res or not clause;
91 return res;
92}
93
94
95/*======================================================================================================================
96 * Print/Dump
97 *====================================================================================================================*/
98
99void Predicate::to_sql(std::ostream &out) const
100{
101 if (negative())
102 out << "NOT (" << expr() << ')';
103 else
104 out << expr();
105}
106
107void cnf::Clause::to_sql(std::ostream &out) const
108{
109 switch (size()) {
110 case 0:
111 out << "TRUE";
112 return;
113
114 case 1:
115 out << *begin();
116 return;
117
118 default:
119 for (auto it = begin(); it != end(); ++it) {
120 if (it != begin()) out << " OR ";
121 out << '(' << *it << ')';
122 }
123 return;
124 }
125}
126
127void CNF::to_sql(std::ostream &out) const
128{
129 switch (size()) {
130 case 0:
131 out << "TRUE";
132 return;
133
134 case 1:
135 out << *begin();
136 return;
137
138 default:
139 for (auto it = begin(); it != end(); ++it) {
140 if (it != begin()) out << " AND ";
141 out << *it;
142 }
143 return;
144 }
145}
146
148std::ostream & cnf::operator<<(std::ostream &out, const Predicate &pred)
149{
150 if (pred.negative())
151 out << '-';
152 ast::ASTPrinter print(out);
153 print.expand_nested_queries(false);
154 print(*pred);
155 return out;
156}
157
158std::ostream & cnf::operator<<(std::ostream &out, const cnf::Clause &clause)
159{
160 for (auto it = clause.begin(); it != clause.end(); ++it) {
161 if (it != clause.begin()) out << " v ";
162 out << *it;
163 }
164 return out;
165}
166
167std::ostream & cnf::operator<<(std::ostream &out, const CNF &cnf)
168{
169 if (cnf.empty())
170 out << "TRUE";
171 else if (cnf.size() == 1)
172 out << cnf[0];
173 else {
174 for (auto it = cnf.begin(); it != cnf.end(); ++it) {
175 if (it != cnf.begin()) out << " ^ ";
176 out << '(' << *it << ')';
177 }
178 }
179 return out;
180}
181
182void Predicate::dump(std::ostream &out) const
183{
184 out << *this << std::endl;
185}
186void Predicate::dump() const { dump(std::cerr); }
187
188void cnf::Clause::dump(std::ostream &out) const
189{
190 out << *this << std::endl;
191}
192void cnf::Clause::dump() const { dump(std::cerr); }
193
194void CNF::dump(std::ostream &out) const
195{
196 out << *this << std::endl;
197}
198void CNF::dump() const { dump(std::cerr); }
200
201
202/*======================================================================================================================
203 * CNF Generator
204 *====================================================================================================================*/
205
208{
209 private:
210 bool is_negative_ = false;
212
213 public:
215
216 CNF get() const { return result_; }
217
218 using ConstASTExprVisitor::operator();
219 void operator()(Const<ErrorExpr> &e);
220 void operator()(Const<Designator> &e);
221 void operator()(Const<Constant> &e);
222 void operator()(Const<FnApplicationExpr> &e);
223 void operator()(Const<UnaryExpr> &e);
224 void operator()(Const<BinaryExpr> &e);
225 void operator()(Const<QueryExpr> &e);
226};
227
228void CNFGenerator::operator()(Const<ErrorExpr> &e)
229{
230 result_ = CNF({cnf::Clause({Predicate::Create(&e, is_negative_)})});
231}
232
233void CNFGenerator::operator()(Const<Designator> &e)
234{
235 result_ = CNF({cnf::Clause({Predicate::Create(&e, is_negative_)})});
236}
237
238void CNFGenerator::operator()(Const<Constant> &e)
239{
240 result_ = CNF({cnf::Clause({Predicate::Create(&e, is_negative_)})});
241}
242
243void CNFGenerator::operator()(Const<FnApplicationExpr> &e)
244{
245 result_ = CNF({cnf::Clause({Predicate::Create(&e, is_negative_)})});
246}
247
248void CNFGenerator::operator()(Const<UnaryExpr> &e)
249{
250 switch (e.op().type) {
251 case TK_Not:
252 is_negative_ = not is_negative_;
253 (*this)(*e.expr);
254 is_negative_ = not is_negative_;
255 break;
256
257 default:
258 result_ = CNF({cnf::Clause({Predicate::Create(&e, is_negative_)})});
259 break;
260
261 }
262}
263
264void CNFGenerator::operator()(Const<BinaryExpr> &e)
265{
266 if (e.lhs->type()->is_boolean() and e.rhs->type()->is_boolean()) {
267 /* This is an expression in predicate logic. Convert to CNF. */
268 (*this)(*e.lhs);
269 auto cnf_lhs = result_;
270 (*this)(*e.rhs);
271 auto cnf_rhs = result_;
272
273 if ((not is_negative_ and e.op() == TK_And) or (is_negative_ and e.op() == TK_Or)) {
274 result_ = cnf_lhs and cnf_rhs;
275 } else if ((not is_negative_ and e.op() == TK_Or) or (is_negative_ and e.op() == TK_And)) {
276 result_ = cnf_lhs or cnf_rhs;
277 } else if (e.op() == TK_EQUAL or e.op() == TK_BANG_EQUAL) {
278 /* A ↔ B ⇔ (A → B) ^ (B → A) ⇔ (¬A v B) ^ (¬B v A) */
279 auto equiv = ((not cnf_lhs) or cnf_rhs) and ((not cnf_rhs) or cnf_lhs);
280 if ((not is_negative_ and e.op() == TK_BANG_EQUAL) or (is_negative_ and e.op() == TK_EQUAL))
281 result_ = not equiv; // A ↮ B ⇔ ¬(A ↔ B)
282 else
283 result_ = equiv;
284 } else {
285 M_unreachable("unsupported boolean expression");
286 }
287 } else {
288 /* This expression is a literal. */
289 result_ = CNF({cnf::Clause({Predicate::Create(&e, is_negative_)})});
290 }
291}
292
293void CNFGenerator::operator()(Const<QueryExpr> &e)
294{
295 result_ = CNF({cnf::Clause({Predicate::Create(&e, is_negative_)})});
296}
297
299{
300 CNFGenerator G;
301 G(e);
302 return G.get();
303}
#define M_unreachable(MSG)
Definition: macro.hpp:146
CNF M_EXPORT operator&&(const Clause &lhs, const Clause &rhs)
Returns the logical and of two cnf::Clauses, i.e. a CNF with the two cnf::Clauses lhs and rhs.
Definition: CNF.cpp:45
CNF M_EXPORT operator!(const Clause &clause)
Returns the logical negation of a cnf::Clause.
Definition: CNF.cpp:78
Clause M_EXPORT operator||(const Clause &lhs, const Clause &rhs)
Returns the logical or of two cnf::Clauses, i.e. the disjunction of the Predicates of lhs and rhs.
Definition: CNF.cpp:36
CNF M_EXPORT to_CNF(const ast::Expr &e)
Converts the Boolean Expr e to a CNF.
Definition: CNF.cpp:298
‍mutable namespace
Definition: Backend.hpp:10
bool M_EXPORT contains(const H &haystack, const N &needle)
Checks whether haystack contains needle.
Definition: fn.hpp:383
and
Definition: enum_ops.hpp:12
Helper class to convert Expr and Clause to cnf::CNF.
Definition: CNF.cpp:208
CNF result_
Definition: CNF.cpp:211
CNF get() const
Definition: CNF.cpp:216
void operator()(Const< ErrorExpr > &e)
Definition: CNF.cpp:228
CNFGenerator()
Definition: CNF.cpp:214
Pretty-prints the AST in SQL.
Definition: ASTPrinter.hpp:10
An expression.
Definition: AST.hpp:39
A CNF represents a conjunction of cnf::Clauses.
Definition: CNF.hpp:134
void dump() const
Definition: CNF.cpp:198
bool operator<=(const CNF &other) const
Definition: CNF.cpp:27
void to_sql(std::ostream &out) const
Print as SQL expression.
Definition: CNF.cpp:127
A cnf::Clause represents a disjunction of Predicates.
Definition: CNF.hpp:87
void to_sql(std::ostream &out) const
Print as SQL expression.
Definition: CNF.cpp:107
void dump() const
Definition: CNF.cpp:192
bool operator<=(const Clause &other) const
Definition: CNF.cpp:18
A Predicate contains a Expr of Boolean type in either positive or negative form.
Definition: CNF.hpp:16
static Predicate Create(const ast::Expr *e, bool is_negative)
Creates a Predicate from e.
Definition: CNF.hpp:28
void to_sql(std::ostream &out) const
Print as SQL expression.
Definition: CNF.cpp:99
ast::Expr & expr()
Returns the Expr within this Predicate.
Definition: CNF.hpp:34
void dump() const
Definition: CNF.cpp:186
bool negative() const
Returns true iff this Predicate is negative.
Definition: CNF.hpp:31