1 // {{{ MIT License
2
3 // Copyright 2017 Roland Kaminski
4
5 // Permission is hereby granted, free of charge, to any person obtaining a copy
6 // of this software and associated documentation files (the "Software"), to
7 // deal in the Software without restriction, including without limitation the
8 // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
9 // sell copies of the Software, and to permit persons to whom the Software is
10 // furnished to do so, subject to the following conditions:
11
12 // The above copyright notice and this permission notice shall be included in
13 // all copies or substantial portions of the Software.
14
15 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21 // IN THE SOFTWARE.
22
23 // }}}
24
25 #include "gringo/terms.hh"
26 #include "gringo/logger.hh"
27 #include <cstring>
28
29 namespace Gringo {
30
31 // {{{1 TheoryOpDef
32
TheoryOpDef(Location const & loc,String op,unsigned priority,TheoryOperatorType type)33 TheoryOpDef::TheoryOpDef(Location const &loc, String op, unsigned priority, TheoryOperatorType type)
34 : loc_(loc)
35 , op_(op)
36 , priority_(priority)
37 , type_(type) { }
38
39 TheoryOpDef::TheoryOpDef(TheoryOpDef &&) = default;
40
op() const41 String TheoryOpDef::op() const {
42 return op_;
43 }
44
key() const45 TheoryOpDef::Key TheoryOpDef::key() const {
46 return {op_, type_ == TheoryOperatorType::Unary};
47 }
48
49 TheoryOpDef::~TheoryOpDef() noexcept = default;
50
51 TheoryOpDef &TheoryOpDef::operator=(TheoryOpDef &&) = default;
52
loc() const53 Location const &TheoryOpDef::loc() const {
54 return loc_;
55 }
56
print(std::ostream & out) const57 void TheoryOpDef::print(std::ostream &out) const {
58 out << op_ << " :" << priority_ << "," << type_;
59 }
60
priority() const61 unsigned TheoryOpDef::priority() const {
62 return priority_;
63 }
64
type() const65 TheoryOperatorType TheoryOpDef::type() const {
66 return type_;
67 }
68
69 // {{{1 TheoryTermDef
70
TheoryTermDef(Location const & loc,String name)71 TheoryTermDef::TheoryTermDef(Location const &loc, String name)
72 : loc_(loc)
73 , name_(name) { }
74
75 TheoryTermDef::TheoryTermDef(TheoryTermDef &&) = default;
76
addOpDef(TheoryOpDef && def,Logger & log)77 void TheoryTermDef::addOpDef(TheoryOpDef &&def, Logger &log) {
78 auto it = opDefs_.find(def.key());
79 if (it == opDefs_.end()) {
80 opDefs_.push(std::move(def));
81 }
82 else {
83 GRINGO_REPORT(log, Warnings::RuntimeError)
84 << def.loc() << ": error: redefinition of theory operator:" << "\n"
85 << " " << def.op() << "\n"
86 << it->loc() << ": note: operator first defined here\n";
87 }
88 }
89
name() const90 String TheoryTermDef::name() const {
91 return name_;
92 }
93
loc() const94 Location const &TheoryTermDef::loc() const {
95 return loc_;
96 }
97
98 TheoryTermDef::~TheoryTermDef() noexcept = default;
99
100 TheoryTermDef &TheoryTermDef::operator=(TheoryTermDef &&) = default;
101
print(std::ostream & out) const102 void TheoryTermDef::print(std::ostream &out) const {
103 out << name_ << "{";
104 print_comma(out, opDefs_, ",");
105 out << "}";
106 }
107
getPrioAndAssoc(String op) const108 std::pair<unsigned, bool> TheoryTermDef::getPrioAndAssoc(String op) const {
109 auto ret = opDefs_.find(TheoryOpDef::Key{op, false});
110 if (ret != opDefs_.end()) {
111 return {ret->priority(), ret->type() == TheoryOperatorType::BinaryLeft};
112 }
113 else {
114 return {0, true};
115 }
116 }
117
hasOp(String op,bool unary) const118 bool TheoryTermDef::hasOp(String op, bool unary) const {
119 return opDefs_.find(TheoryOpDef::Key{op, unary}) != opDefs_.end();
120 }
121
getPrio(String op,bool unary) const122 unsigned TheoryTermDef::getPrio(String op, bool unary) const {
123 auto ret = opDefs_.find(TheoryOpDef::Key{op, unary});
124 if (ret != opDefs_.end()) {
125 return ret->priority();
126 }
127 else {
128 return 0;
129 }
130 }
131
132 // {{{1 TheoryAtomDef
133
TheoryAtomDef(Location const & loc,String name,unsigned arity,String elemDef,TheoryAtomType type)134 TheoryAtomDef::TheoryAtomDef(Location const &loc, String name, unsigned arity, String elemDef, TheoryAtomType type)
135 : TheoryAtomDef(loc, name, arity, elemDef, type, {}, "") { }
136
TheoryAtomDef(Location const & loc,String name,unsigned arity,String elemDef,TheoryAtomType type,StringVec && ops,String guardDef)137 TheoryAtomDef::TheoryAtomDef(Location const &loc, String name, unsigned arity, String elemDef, TheoryAtomType type, StringVec &&ops, String guardDef)
138 : loc_(loc)
139 , sig_(name, arity, false)
140 , elemDef_(elemDef)
141 , guardDef_(guardDef)
142 , ops_(std::move(ops))
143 , type_(type) { }
144
145 TheoryAtomDef::TheoryAtomDef(TheoryAtomDef &&) = default;
146
sig() const147 Sig TheoryAtomDef::sig() const {
148 return sig_;
149 }
150
hasGuard() const151 bool TheoryAtomDef::hasGuard() const {
152 return !ops_.empty();
153 }
154
type() const155 TheoryAtomType TheoryAtomDef::type() const {
156 return type_;
157 }
158
loc() const159 Location const &TheoryAtomDef::loc() const {
160 return loc_;
161 }
162
ops() const163 StringVec const &TheoryAtomDef::ops() const {
164 return ops_;
165 }
166
elemDef() const167 String TheoryAtomDef::elemDef() const {
168 return elemDef_;
169 }
170
guardDef() const171 String TheoryAtomDef::guardDef() const {
172 assert(hasGuard());
173 return guardDef_;
174 }
175
176 TheoryAtomDef::~TheoryAtomDef() noexcept = default;
177
178 TheoryAtomDef &TheoryAtomDef::operator=(TheoryAtomDef &&) = default;
179
print(std::ostream & out) const180 void TheoryAtomDef::print(std::ostream &out) const {
181 out << "&" << sig_.name() << "/" << sig_.arity() << ":" << elemDef_;
182 if (hasGuard()) {
183 out << ",{";
184 print_comma(out, ops_, ",");
185 out << "}," << guardDef_;
186 }
187 out << "," << type_;
188 }
189
190 // {{{1 TheoryDef
191
TheoryDef(Location const & loc,String name)192 TheoryDef::TheoryDef(Location const &loc, String name)
193 : loc_(loc)
194 , name_(name) { }
195
196 TheoryDef::TheoryDef(TheoryDef &&) = default;
197
name() const198 String TheoryDef::name() const {
199 return name_;
200 }
201
loc() const202 Location const &TheoryDef::loc() const {
203 return loc_;
204 }
205
addAtomDef(TheoryAtomDef && def,Logger & log)206 void TheoryDef::addAtomDef(TheoryAtomDef &&def, Logger &log) {
207 auto it = atomDefs_.find(def.sig());
208 if (it == atomDefs_.end()) {
209 atomDefs_.push(std::move(def));
210 }
211 else {
212 GRINGO_REPORT(log, Warnings::RuntimeError)
213 << def.loc() << ": error: redefinition of theory atom:" << "\n"
214 << " " << def.sig() << "\n"
215 << it->loc() << ": note: atom first defined here\n";
216 }
217 }
218
addTermDef(TheoryTermDef && def,Logger & log)219 void TheoryDef::addTermDef(TheoryTermDef &&def, Logger &log) {
220 auto it = termDefs_.find(def.name());
221 if (it == termDefs_.end()) {
222 termDefs_.push(std::move(def));
223 }
224 else {
225 GRINGO_REPORT(log, Warnings::RuntimeError)
226 << def.loc() << ": error: redefinition of theory term:" << "\n"
227 << " " << def.name() << "\n"
228 << it->loc() << ": note: term first defined term\n";
229 }
230 }
231
232 TheoryDef::~TheoryDef() noexcept = default;
233
234 TheoryDef &TheoryDef::operator=(TheoryDef &&) = default;
235
print(std::ostream & out) const236 void TheoryDef::print(std::ostream &out) const {
237 out << "#theory " << name_ << "{";
238 if (!atomDefs_.empty() || !termDefs_.empty()) {
239 out << "\n";
240 }
241 bool sep = false;
242 for (auto &def : termDefs_) {
243 if (sep) { out << ";\n"; }
244 else { sep = true; }
245 out << " " << def;
246 }
247 for (auto &def : atomDefs_) {
248 if (sep) { out << ";\n"; }
249 else { sep = true; }
250 out << " " << def;
251 }
252 if (sep) {
253 out << "\n";
254 }
255 out << "}.";
256 }
257
getAtomDef(Sig sig) const258 TheoryAtomDef const *TheoryDef::getAtomDef(Sig sig) const {
259 auto ret = atomDefs_.find(sig);
260 return ret != atomDefs_.end() ? &*ret : nullptr;
261 }
262
getTermDef(String name) const263 TheoryTermDef const *TheoryDef::getTermDef(String name) const {
264 auto ret = termDefs_.find(name);
265 return ret != termDefs_.end() ? &*ret : nullptr;
266 }
267
atomDefs() const268 TheoryAtomDefs const &TheoryDef::atomDefs() const {
269 return atomDefs_;
270 }
271
272 // }}}1
273
274 // {{{1 definition of CSPRelTerm
275
276 CSPRelTerm::CSPRelTerm(CSPRelTerm &&) = default;
277 CSPRelTerm &CSPRelTerm::operator=(CSPRelTerm &&) = default;
278
CSPRelTerm(Relation rel,CSPAddTerm && term)279 CSPRelTerm::CSPRelTerm(Relation rel, CSPAddTerm &&term)
280 : rel(rel)
281 , term(std::move(term)) { }
282
collect(VarTermBoundVec & vars) const283 void CSPRelTerm::collect(VarTermBoundVec &vars) const { term.collect(vars); }
collect(VarTermSet & vars) const284 void CSPRelTerm::collect(VarTermSet &vars) const { term.collect(vars); }
replace(Defines & x)285 void CSPRelTerm::replace(Defines &x) { term.replace(x); }
operator ==(CSPRelTerm const & x) const286 bool CSPRelTerm::operator==(CSPRelTerm const &x) const { return rel == x.rel && term == x.term; }
simplify(SimplifyState & state,Logger & log)287 bool CSPRelTerm::simplify(SimplifyState &state, Logger &log) { return term.simplify(state, log); }
rewriteArithmetics(Term::ArithmeticsMap & arith,AuxGen & auxGen)288 void CSPRelTerm::rewriteArithmetics(Term::ArithmeticsMap &arith, AuxGen &auxGen) { term.rewriteArithmetics(arith, auxGen); }
hash() const289 size_t CSPRelTerm::hash() const { return get_value_hash(size_t(rel), term); }
hasPool() const290 bool CSPRelTerm::hasPool() const { return term.hasPool(); }
unpool() const291 std::vector<CSPRelTerm> CSPRelTerm::unpool() const {
292 std::vector<CSPRelTerm> ret;
293 for (auto &x : term.unpool()) { ret.emplace_back(rel, std::move(x)); }
294 return ret;
295 }
~CSPRelTerm()296 CSPRelTerm::~CSPRelTerm() { }
operator <<(std::ostream & out,CSPRelTerm const & x)297 std::ostream &operator<<(std::ostream &out, CSPRelTerm const &x) {
298 out << "$" << x.rel << x.term;
299 return out;
300 }
operator ()(CSPRelTerm const & x) const301 CSPRelTerm clone<CSPRelTerm>::operator()(CSPRelTerm const &x) const {
302 return CSPRelTerm(x.rel, get_clone(x.term));
303 }
304
305 // {{{1 definition of CSPAddTerm
306
307 CSPAddTerm::CSPAddTerm(CSPAddTerm &&) = default;
308 CSPAddTerm &CSPAddTerm::operator=(CSPAddTerm &&) = default;
309
CSPAddTerm(CSPMulTerm && x)310 CSPAddTerm::CSPAddTerm(CSPMulTerm &&x) { terms.emplace_back(std::move(x)); }
CSPAddTerm(Terms && terms)311 CSPAddTerm::CSPAddTerm(Terms &&terms) : terms(std::move(terms)) { }
312
append(CSPMulTerm && x)313 void CSPAddTerm::append(CSPMulTerm &&x) { terms.emplace_back(std::move(x)); }
314
collect(VarTermBoundVec & vars) const315 void CSPAddTerm::collect(VarTermBoundVec &vars) const {
316 for (auto &x : terms) { x.collect(vars); }
317 }
collect(VarTermSet & vars) const318 void CSPAddTerm::collect(VarTermSet &vars) const {
319 for (auto &x : terms) { x.collect(vars); }
320 }
replace(Defines & x)321 void CSPAddTerm::replace(Defines &x) {
322 for (auto &y : terms) { y.replace(x); }
323 }
operator ==(CSPAddTerm const & x) const324 bool CSPAddTerm::operator==(CSPAddTerm const &x) const { return is_value_equal_to(terms, x.terms); }
simplify(SimplifyState & state,Logger & log)325 bool CSPAddTerm::simplify(SimplifyState &state, Logger &log) {
326 for (auto &y : terms) {
327 if (!y.simplify(state, log)) { return false; }
328 }
329 return true;
330 }
rewriteArithmetics(Term::ArithmeticsMap & arith,AuxGen & auxGen)331 void CSPAddTerm::rewriteArithmetics(Term::ArithmeticsMap &arith, AuxGen &auxGen) {
332 for (auto &x : terms) { x.rewriteArithmetics(arith, auxGen); }
333 }
hash() const334 size_t CSPAddTerm::hash() const { return get_value_hash(terms); }
hasPool() const335 bool CSPAddTerm::hasPool() const {
336 for (auto &y : terms) {
337 if (y.hasPool()) { return true; }
338 }
339 return false;
340 }
unpool() const341 std::vector<CSPAddTerm> CSPAddTerm::unpool() const {
342 std::vector<CSPAddTerm> x;
343 auto f = [&](Terms &&args) { x.emplace_back(std::move(args)); };
344 Term::unpool(terms.begin(), terms.end(), std::bind(&CSPMulTerm::unpool, std::placeholders::_1), f);
345 return x;
346 }
toGround(CSPGroundLit & ground,bool invert,Logger & log) const347 void CSPAddTerm::toGround(CSPGroundLit &ground, bool invert, Logger &log) const {
348 bool undefined = false;
349 for (auto &x : terms) {
350 int coe = x.coe->toNum(undefined, log);
351 if (coe != 0) {
352 if (x.var) { std::get<1>(ground).emplace_back(invert ? -coe : coe, x.var->eval(undefined, log)); }
353 else { std::get<2>(ground) = eval(invert ? BinOp::ADD : BinOp::SUB, std::get<2>(ground), coe); }
354 }
355 }
356 assert(!undefined);
357 }
358
checkEval(Logger & log) const359 bool CSPAddTerm::checkEval(Logger &log) const {
360 for (auto &x : terms) {
361 bool undefined = false;
362 x.coe->toNum(undefined, log);
363 if (undefined) { return false; }
364 if (x.var) {
365 x.var->eval(undefined, log);
366 if (undefined) { return false; }
367 }
368 }
369 return true;
370 }
371
~CSPAddTerm()372 CSPAddTerm::~CSPAddTerm() { }
operator <<(std::ostream & out,CSPAddTerm const & x)373 std::ostream &operator<<(std::ostream &out, CSPAddTerm const &x) {
374 print_comma(out, x.terms, "$+");
375 return out;
376 }
operator ()(CSPAddTerm const & x) const377 CSPAddTerm clone<CSPAddTerm>::operator()(CSPAddTerm const &x) const {
378 return CSPAddTerm(get_clone(x.terms));
379 }
380
381 // {{{1 definition of CSPMulTerm
382
383 CSPMulTerm::CSPMulTerm(CSPMulTerm &&) = default;
384 CSPMulTerm &CSPMulTerm::operator=(CSPMulTerm &&) = default;
385
CSPMulTerm(UTerm && var,UTerm && coe)386 CSPMulTerm::CSPMulTerm(UTerm &&var, UTerm &&coe)
387 : var(std::move(var))
388 , coe(std::move(coe)) { }
389
collect(VarTermBoundVec & vars) const390 void CSPMulTerm::collect(VarTermBoundVec &vars) const {
391 if (var) { var->collect(vars, false); }
392 coe->collect(vars, false);
393 }
collect(VarTermSet & vars) const394 void CSPMulTerm::collect(VarTermSet &vars) const {
395 if (var) { var->collect(vars); }
396 coe->collect(vars);
397 }
replace(Defines & x)398 void CSPMulTerm::replace(Defines &x) {
399 if (var) { Term::replace(var, var->replace(x, true)); }
400 Term::replace(coe, coe->replace(x, true));
401 }
operator ==(CSPMulTerm const & x) const402 bool CSPMulTerm::operator==(CSPMulTerm const &x) const {
403 if (var && x.var) { return is_value_equal_to(var, x.var) && is_value_equal_to(coe, x.coe); }
404 else { return !var && !x.var && is_value_equal_to(coe, x.coe); }
405 }
simplify(SimplifyState & state,Logger & log)406 bool CSPMulTerm::simplify(SimplifyState &state, Logger &log) {
407 if (var && var->simplify(state, false, false, log).update(var, false).undefined()) { return false;}
408 return !coe->simplify(state, false, false, log).update(coe, false).undefined();
409 }
rewriteArithmetics(Term::ArithmeticsMap & arith,AuxGen & auxGen)410 void CSPMulTerm::rewriteArithmetics(Term::ArithmeticsMap &arith, AuxGen &auxGen) {
411 if (var) { Term::replace(var, var->rewriteArithmetics(arith, auxGen)); }
412 Term::replace(coe, coe->rewriteArithmetics(arith, auxGen));
413 }
hash() const414 size_t CSPMulTerm::hash() const {
415 if (var) { return get_value_hash(var, coe); }
416 else { return get_value_hash(coe); }
417 }
hasPool() const418 bool CSPMulTerm::hasPool() const {
419 return (var && var->hasPool()) || coe->hasPool();
420 }
unpool() const421 std::vector<CSPMulTerm> CSPMulTerm::unpool() const {
422 std::vector<CSPMulTerm> value;
423 if (var) {
424 auto f = [&](UTerm &&a, UTerm &&b) { value.emplace_back(std::move(a), std::move(b)); };
425 Term::unpool(var, coe, Gringo::unpool, Gringo::unpool, f);
426 }
427 else {
428 for (auto &x : Gringo::unpool(coe)) { value.emplace_back(nullptr, std::move(x)); }
429 }
430 return value;
431 }
~CSPMulTerm()432 CSPMulTerm::~CSPMulTerm() { }
operator <<(std::ostream & out,CSPMulTerm const & x)433 std::ostream &operator<<(std::ostream &out, CSPMulTerm const &x) {
434 out << *x.coe;
435 if (x.var) { out << "$*$" << *x.var; };
436 return out;
437 }
operator ()(CSPMulTerm const & x) const438 CSPMulTerm clone<CSPMulTerm>::operator()(CSPMulTerm const &x) const {
439 return CSPMulTerm(x.var ? get_clone(x.var) : nullptr, get_clone(x.coe));
440 }
441
442 // }}}1
443
444 } // namspace Gringo
445
446