Lattice Land Core Library
Loading...
Searching...
No Matches
ast.hpp
Go to the documentation of this file.
1// Copyright 2021 Pierre Talbot
2
3#ifndef LALA_CORE_AST_HPP
4#define LALA_CORE_AST_HPP
5
6#include "battery/utility.hpp"
7#include "battery/vector.hpp"
8#include "battery/string.hpp"
9#include "battery/tuple.hpp"
10#include "battery/variant.hpp"
11#include "battery/shared_ptr.hpp"
12#include "battery/unique_ptr.hpp"
13#include "sort.hpp"
14#include "thrust/optional.h"
15
16#ifdef _WINDOWS
17# undef DIFFERENCE // Avoid clash with #define in WinUser.h
18# undef IN // Avoid clash with #define in ntdef.h
19#endif
20
21namespace lala {
22
23/** A "logical variable" is just the name of the variable. */
24template<class Allocator>
25using LVar = battery::string<Allocator>;
26
27/** The kind of interpretation operations. */
28enum class IKind {
29 ASK,
30 TELL
31};
32
33/** We call an "abstract variable" the representation of a logical variable in an abstract domain.
34It is a pair of integers `(aty, vid)` where `aty` is the UID of the abstract element and `vid` is an internal identifier of the variable inside the abstract element.
35The mapping between logical variables and abstract variables is maintained in an environment (see `env.hpp`).
36An abstract variable always has a single name (or no name if it is not explicitly represented in the initial formula).
37But a logical variable can be represented by several abstract variables when the variable occurs in different abstract elements. */
38class AVar {
39 int value;
40public:
41 CUDA constexpr AVar(): value(-1) {}
42 constexpr AVar(const AVar&) = default;
43 constexpr AVar(AVar&&) = default;
44 constexpr AVar& operator=(const AVar&) = default;
45 constexpr AVar& operator=(AVar&&) = default;
46 CUDA constexpr bool operator==(const AVar& other) const {
47 return value == other.value;
48 }
49 CUDA constexpr bool operator!=(const AVar& other) const {
50 return value != other.value;
51 }
52
53 CUDA constexpr AVar(AType atype, int var_id): value((var_id << 8) | atype) {
54 assert(atype >= 0);
55 assert(var_id >= 0);
56 assert(atype < (1 << 8));
57 assert(var_id < (1 << 23));
58 }
59 CUDA constexpr AVar(AType atype, size_t var_id): AVar(atype, static_cast<int>(var_id)) {}
60
61 CUDA constexpr bool is_untyped() const {
62 return value == -1;
63 }
64
65 CUDA constexpr int aty() const {
66 return is_untyped() ? -1 : (value & ((1 << 8) - 1));
67 }
68
69 CUDA constexpr int vid() const {
70 return is_untyped() ? -1 : value >> 8;
71 }
72
73 CUDA constexpr void type_as(AType aty) {
74 value = (vid() << 8) | aty;
75 }
76};
77
78/** A first-order signature is a triple \f$ (X, F, P) \f$ where \f$ X \f$ is the set of variables, \f$ F \f$ the set of function symbols and \f$ P \f$ the set of predicates.
79 We represent \f$ X \f$ by strings (see `LVar`), while \f$ F \f$ and \f$ P \f$ are described in the following enumeration `Sig`.
80 For programming conveniency, we suppose that logical connectors are included in the set of predicates and thus are in the signature as well.
81 Finally, function symbols and predicates are at the "same level".
82 Hence a predicate can occur as the argument of a function, which is convenient when modelling, consider for example a cardinality constraint: \f$ ((x > 4) + (y < 4) + (z = 3)) \neq 2 \f$.
83
84 Symbols are sometimes overloaded across different universe of discourse.
85 For instance, `ADD` can be used over integers, reals and even set of integers (pairwise addition).
86
87 Division and modulus are defined as usual over continuous domains such as rational and real numbers.
88 However, it gets more tricky when defined over discrete domains such as integers and floating-point numbers, since there is not a single definition of division and modulus.
89 The various kinds of discrete divisions are explained in (Leijend D. (2003). Division and Modulus for Computer Scientists), and we add four of those definitions to the logical signature.
90 There are several use-cases of modulus and division:
91 * If you write a constraint model, you probably want to use euclidean division and modulus (EDIV, EMOD) as this is the most "mathematical" definition.
92 * If you intend to model the semantics of a programming language, you should use the same kind of division as the one present in your programming language (most likely truncated division).
93 */
94enum Sig {
95 ///@{
96 NEG, ABS, ///< Unary arithmetic function symbols.
97 ADD, SUB, MUL, POW, MIN, MAX, ///< Binary arithmetic function symbols.
98 SQRT, EXP, LN, ///< Square root, natural exponential and natural logarithm function symbols.
99 NROOT, LOG, ///< nth root and logarithm to base (both binary function symbols).
100 SIN, COS, TAN, ASIN, ACOS, ATAN, SINH, COSH, TANH, ASINH, ACOSH, ATANH, ///< Trigonometric unary function symbols.
101 DIV, MOD, ///< Division and modulus over continuous domains (e.g., floating-point numbers and rational).
102 TDIV, TMOD, ///< Truncated division, present in most programming languages, is defined as \f$ a\,\mathbf{tdiv}\,b = \mathit{trunc}(a/b) \f$, i.e., it rounds towards zero. Modulus is defined as \f$ a\,\mathbf{tmod}\,b = a - b * (a\,\mathbf{tdiv}\,b) \f$.
103 FDIV, FMOD, ///< Floor division (Knuth D. (1972). The Art of Computer Programming, Vol 1, Fundamental Algorithms), is defined as \f$ a\,\mathbf{fdiv}\,b = \lfloor a/b \rfloor \f$, i.e., it rounds towards negative infinity. Modulus is defined as \f$ a\,\mathbf{fmod}\,b = a - b * (a\,\mathbf{fdiv}\,b) \f$.
104 CDIV, CMOD, ///< Ceil division is defined as \f$ a\,\mathbf{cdiv}\,b = \lceil a/b \rceil \f$. Modulus is defined as \f$ a\,\mathbf{cmod}\,b = a - b * (a\,\mathbf{cdiv}\,b) \f$.
105 EDIV, EMOD, ///< Euclidean division (Boute T. R. (1992). The Euclidean definition of the functions div and mod). The properties satisfy by this division are: (1) \f$ a\,\mathbf{ediv}\,b \in \mathbb{Z} \f$, (2) \f$ a = b * (a\,\mathbf{ediv}\,b) + (a\,\mathbf{emod}\,b) \f$ and (3) \f$ 0 \leq a\,\mathbf{emod}\,b < |b|\f$. Further, note that Euclidean division satisfies \f$ a\,\mathbf{ediv}\,(-b) = -(a\,\mathbf{ediv}\,b) \f$ and \f$ a\,\mathbf{emod}\,(-b) = a\,\mathbf{emod}\,b \f$.
107 SUBSET, SUBSETEQ, SUPSET, SUPSETEQ, ///< Set inclusion predicates.
108 IN, ///< Set membership predicate.
109 CARD, ///< Cardinality function from set to integer.
110 HULL, ///< Unary function performing the convex hull of a set, e.g., \f$ \mathit{hull}(s) = \{x \;|\; \mathit{min}(s) \leq x \leq \mathit{max}(s) \} \f$.
111 CONVEX, ///< Unary predicate, requiring \f$ s = \mathit{hull}(s) \f$.
112 EQ, NEQ, ///< Equality relations.
113 LEQ, GEQ, LT, GT, ///< Arithmetic comparison predicates. When applied to set, it corresponds to the lexicographic ordering of the sorted set according the underlying natural ordering of the elements in the set.
114 AND, OR, IMPLY, EQUIV, NOT, XOR, ///< Logical connector.
115 ITE, ///< If-then-else
116 MAXIMIZE, ///< Unary "meta-predicate" indicating that its argument must be maximized, according to the increasing ordering of the underlying universe of discourse. This is not a predicate because it is defined on the solutions space of the whole formulas.
117 MINIMIZE ///< Same as MAXIMIZE, but for minimization.
118 ///@}
120
121CUDA NI inline const char* string_of_sig(Sig sig) {
122 switch(sig) {
123 case NEG: return "-";
124 case ABS: return "abs";
125 case ADD: return "+";
126 case SUB: return "-";
127 case MUL: return "*";
128 case DIV: return "/";
129 case TDIV: return "tdiv";
130 case FDIV: return "fdiv";
131 case CDIV: return "cdiv";
132 case EDIV: return "ediv";
133 case MOD: return "%%";
134 case TMOD: return "tmod";
135 case FMOD: return "fmod";
136 case CMOD: return "cmod";
137 case EMOD: return "emod";
138 case POW: return "^";
139 case SQRT: return "sqrt";
140 case EXP: return "exp";
141 case LN: return "ln";
142 case NROOT: return "nroot";
143 case LOG: return "log";
144 case SIN: return "sin";
145 case COS: return "cos";
146 case TAN: return "tan";
147 case ASIN: return "asin";
148 case ACOS: return "acos";
149 case ATAN: return "atan";
150 case SINH: return "sinh";
151 case COSH: return "cosh";
152 case TANH: return "tanh";
153 case ASINH: return "asinh";
154 case ACOSH: return "acosh";
155 case ATANH: return "atanh";
156 case MIN: return "min";
157 case MAX: return "max";
158 case UNION: return "\u222A";
159 case INTERSECTION: return "\u2229";
160 case DIFFERENCE: return "\\";
161 case SYMMETRIC_DIFFERENCE: return "\u2296";
162 case COMPLEMENT: return "complement";
163 case IN: return "\u2208";
164 case SUBSET: return "\u2282";
165 case SUBSETEQ: return "\u2286";
166 case SUPSET: return "\u2283";
167 case SUPSETEQ: return "\u2287";
168 case CARD: return "card";
169 case HULL: return "hull";
170 case CONVEX: return "convex";
171 case EQ: return "=";
172 case NEQ: return "\u2260";
173 case LEQ: return "\u2264";
174 case GEQ: return "\u2265";
175 case LT: return "<";
176 case GT: return ">";
177 case AND: return "\u2227";
178 case OR: return "\u2228";
179 case IMPLY: return "\u21D2";
180 case EQUIV: return "\u21D4";
181 case NOT: return "\u00AC";
182 case XOR: return "\u2295";
183 case ITE: return "ite";
184 case MAXIMIZE: return "maximize";
185 case MINIMIZE: return "minimize";
186 default:
187 assert(false);
188 return "<bug! unknown sig>";
189 }
190 }
191
192 CUDA NI inline constexpr bool is_prefix(Sig sig) {
193 return sig == ABS || sig == SQRT || sig == EXP || sig == LN || sig == NROOT || sig == LOG || sig == SIN || sig == COS || sig == TAN || sig == ASIN || sig == ACOS || sig == ATAN || sig == SINH || sig == COSH || sig == TANH || sig == ASINH || sig == ACOSH || sig == ATANH || sig == MIN || sig == MAX || sig == COMPLEMENT || sig == CARD || sig == HULL || sig == CONVEX || sig == ITE || sig == MAXIMIZE || sig == MINIMIZE;
194 }
195
196 CUDA NI inline constexpr bool is_division(Sig sig) {
197 return sig == DIV || sig == TDIV || sig == EDIV || sig == FDIV || sig == CDIV;
198 }
199
200 CUDA NI inline constexpr bool is_modulo(Sig sig) {
201 return sig == MOD || sig == TMOD || sig == EMOD || sig == FMOD || sig == CMOD;
202 }
203
204 CUDA NI inline constexpr bool is_associative(Sig sig) {
205 return sig == ADD || sig == MUL || sig == AND || sig == OR || sig == EQUIV || sig == XOR
206 || sig == UNION || sig == INTERSECTION || sig == MAX || sig == MIN;
207 }
208}
209
210namespace battery {
211 template<>
212 CUDA NI inline void print(const lala::Sig& sig) {
213 printf("%s", lala::string_of_sig(sig));
214 }
215}
216
217namespace lala {
218
219/** `TFormula` represents the AST of a typed first-order logical formula.
220In our context, the type of a formula is an integer representing the UID of an abstract domain in which the formula should to be interpreted.
221It defaults to the value `UNTYPED` if the formula is not (yet) typed.
222By default, the types of integer and real number are supported.
223The supported symbols can be extended with the template parameter `ExtendedSig`.
224This extended signature can also be used for representing exactly constant such as real numbers using a string.
225The AST of a formula is represented by a variant, where each alternative is described below.
226We represent everything at the same level (term, formula, predicate, variable, constant).
227This is generally convenient when modelling to avoid creating intermediate boolean variables when reifying.
228We can have `x + (x > y \/ y > x + 4) >= 1`.
229
230Differently from first-order logic, the existential quantifier does not have a subformula, i.e., we write \f$ \exists{x:Int} \land \exists{y:Int} \land x < y\f$.
231This semantics comes from "dynamic predicate logic" where a formula is interpreted in a context (here the abstract element).
232(The exact connection of our framework to dynamic predicate logic is not yet perfectly clear.) */
233template<class Allocator, class ExtendedSig = battery::string<Allocator>>
234class TFormula {
235public:
236 using allocator_type = Allocator;
238 using Sequence = battery::vector<this_type, Allocator>;
239 using Existential = battery::tuple<LVar<Allocator>, Sort<Allocator>>;
241 using Formula = battery::variant<
242 logic_bool, ///< Representation of Booleans.
243 logic_int, ///< Representation of integers.
244 logic_real, ///< Approximation of real numbers.
245 LogicSet, ///< Set of Booleans, integers, reals or sets.
246 AVar, ///< Abstract variable
247 LVar<Allocator>, ///< Logical variable
248 Existential, ///< Existential quantifier
249 battery::tuple<Sig, Sequence>, ///< ADD, SUB, ..., EQ, ..., AND, .., NOT
250 battery::tuple<ExtendedSig, Sequence> ///< see above
251 >;
252
253 /** Index of Booleans in the variant type `Formula` (called kind below). */
254 static constexpr size_t B = 0;
255
256 /** Index of integers in the variant type `Formula` (called kind below). */
257 static constexpr size_t Z = B + 1;
258
259 /** Index of real numbers in the variant type `Formula` (called kind below). */
260 static constexpr size_t R = Z + 1;
261
262 /** Index of sets in the variant type `Formula` (called kind below). */
263 static constexpr size_t S = R + 1;
264
265 /** Index of abstract variables in the variant type `Formula` (called kind below). */
266 static constexpr size_t V = S + 1;
267
268 /** Index of logical variables in the variant type `Formula` (called kind below). */
269 static constexpr size_t LV = V + 1;
270
271 /** Index of existential quantifier in the variant type `Formula` (called kind below). */
272 static constexpr size_t E = LV + 1;
273
274 /** Index of n-ary operators in the variant type `Formula` (called kind below). */
275 static constexpr size_t Seq = E + 1;
276
277 /** Index of n-ary operators where the operator is an extended signature in the variant type `Formula` (called kind below). */
278 static constexpr size_t ESeq = Seq + 1;
279
280private:
281 AType type_;
282 Formula formula;
283
284public:
285 /** By default, we initialize the formula to `true`. */
286 CUDA TFormula(): type_(UNTYPED), formula(Formula::template create<B>(true)) {}
287 CUDA TFormula(Formula&& formula): type_(UNTYPED), formula(std::move(formula)) {}
288 CUDA TFormula(AType uid, Formula&& formula): type_(uid), formula(std::move(formula)) {}
289
290 CUDA TFormula(const this_type& other): type_(other.type_), formula(other.formula) {}
291 CUDA TFormula(this_type&& other): type_(other.type_), formula(std::move(other.formula)) {}
292
293 template <class Alloc2, class ExtendedSig2>
294 friend class TFormula;
295
296 template <class Alloc2, class ExtendedSig2>
297 CUDA NI TFormula(const TFormula<Alloc2, ExtendedSig2>& other, const Allocator& allocator = Allocator())
298 : type_(other.type_), formula(Formula::template create<B>(true))
299 {
300 switch(other.formula.index()) {
301 case B: formula = Formula::template create<B>(other.b()); break;
302 case Z: formula = Formula::template create<Z>(other.z()); break;
303 case R: formula = Formula::template create<R>(other.r()); break;
304 case S: formula = Formula::template create<S>(LogicSet(other.s(), allocator));
305 break;
306 case V: formula = Formula::template create<V>(other.v()); break;
307 case LV: formula = Formula::template create<LV>(LVar<Allocator>(other.lv(), allocator)); break;
308 case E: formula = Formula::template create<E>(
309 battery::make_tuple(
310 LVar<Allocator>(battery::get<0>(other.exists()), allocator),
311 battery::get<1>(other.exists())));
312 break;
313 case Seq:
314 formula = Formula::template create<Seq>(
315 battery::make_tuple(
316 other.sig(),
317 Sequence(other.seq(), allocator)));
318 break;
319 case ESeq:
320 formula = Formula::template create<ESeq>(
321 battery::make_tuple(
322 ExtendedSig(other.esig(), allocator),
323 Sequence(other.eseq(), allocator)));
324 break;
325 default: printf("print: formula not handled.\n"); assert(false); break;
326 }
327 }
328
329 CUDA void swap(this_type& other) {
330 ::battery::swap(type_, other.type_);
331 ::battery::swap(formula, other.formula);
332 }
333
334 CUDA this_type& operator=(const this_type& rhs) {
335 this_type(rhs).swap(*this);
336 return *this;
337 }
338
340 this_type(std::move(rhs)).swap(*this);
341 return *this;
342 }
343
344 CUDA Formula& data() { return formula; }
345 CUDA const Formula& data() const { return formula; }
346 CUDA AType type() const { return type_; }
347 CUDA void type_as(AType ty) {
348 type_ = ty;
349 if(is(V)) {
350 v().type_as(ty);
351 }
352 }
353
354 CUDA constexpr bool is_untyped() const {
355 return type() == UNTYPED;
356 }
357
358 CUDA NI thrust::optional<Sort<allocator_type>> sort() const {
359 using sort_t = Sort<allocator_type>;
360 switch(formula.index()) {
361 case B: return sort_t(sort_t::Bool);
362 case Z: return sort_t(sort_t::Int);
363 case R: return sort_t(sort_t::Real);
364 case S: {
365 if(s().empty()) {
366 return {}; // Impossible to get the sort of the empty set.
367 }
368 for(int i = 0; i < s().size(); ++i) {
369 auto subsort = battery::get<0>(s()[i]).sort();
370 if(!subsort.has_value()) {
371 subsort = battery::get<1>(s()[i]).sort();
372 }
373 if(subsort.has_value()) {
374 return sort_t(sort_t::Set, std::move(*subsort) , s().get_allocator());
375 }
376 }
377 break;
378 }
379 case E: return battery::get<1>(exists());
380 }
381 return {};
382 }
383
384 CUDA static this_type make_true() { return TFormula(); }
385 CUDA static this_type make_false() { return TFormula(Formula::template create<B>(false)); }
386
387 CUDA static this_type make_bool(logic_bool b, AType atype = UNTYPED) {
388 return this_type(atype, Formula::template create<B>(b));
389 }
390
391 CUDA static this_type make_z(logic_int i, AType atype = UNTYPED) {
392 return this_type(atype, Formula::template create<Z>(i));
393 }
394
395 /** Create a term representing a real number which is approximated by interval [lb..ub].
396 By default the real number is supposedly over-approximated. */
397 CUDA static this_type make_real(double lb, double ub, AType atype = UNTYPED) {
398 return this_type(atype, Formula::template create<R>(battery::make_tuple(lb, ub)));
399 }
400
401 CUDA static this_type make_real(logic_real r, AType atype = UNTYPED) {
402 return this_type(atype, Formula::template create<R>(r));
403 }
404
405 CUDA static this_type make_set(LogicSet set, AType atype = UNTYPED) {
406 return this_type(atype, Formula::template create<S>(std::move(set)));
407 }
408
409 /** The type of the formula is embedded in `v`. */
410 CUDA static this_type make_avar(AVar v) {
411 return this_type(v.aty(), Formula::template create<V>(v));
412 }
413
414 CUDA static this_type make_avar(AType ty, int vid) {
415 return make_avar(AVar(ty, vid));
416 }
417
418 CUDA static this_type make_lvar(AType ty, LVar<Allocator> lvar) {
419 return this_type(ty, Formula::template create<LV>(std::move(lvar)));
420 }
421
423 return this_type(ty, Formula::template create<E>(battery::make_tuple(std::move(lvar), std::move(ctype))));
424 }
425
426 /** If `flatten` is `true` it will try to merge the children together to avoid nested formula. */
427 CUDA NI static this_type make_nary(Sig sig, Sequence children, AType atype = UNTYPED, bool flatten=true)
428 {
430 for(size_t i = 0; i < children.size(); ++i) {
431 if(flatten && children[i].is(Seq) && children[i].sig() == sig && children[i].type() == atype) {
432 for(size_t j = 0; j < children[i].seq().size(); ++j) {
433 seq.push_back(std::move(children[i].seq(j)));
434 }
435 }
436 else {
437 seq.push_back(std::move(children[i]));
438 }
439 }
440 return this_type(atype, Formula::template create<Seq>(battery::make_tuple(sig, std::move(seq))));
441 }
442
443 CUDA static this_type make_unary(Sig sig, TFormula child, AType atype = UNTYPED, const Allocator& allocator = Allocator()) {
444 return make_nary(sig, Sequence({std::move(child)}, allocator), atype);
445 }
446
447 CUDA static this_type make_binary(TFormula lhs, Sig sig, TFormula rhs, AType atype = UNTYPED, const Allocator& allocator = Allocator(), bool flatten=true) {
448 return make_nary(sig, Sequence({std::move(lhs), std::move(rhs)}, allocator), atype, flatten);
449 }
450
451 CUDA static this_type make_nary(ExtendedSig esig, Sequence children, AType atype = UNTYPED) {
452 return this_type(atype, Formula::template create<ESeq>(battery::make_tuple(std::move(esig), std::move(children))));
453 }
454
455 CUDA size_t index() const {
456 return formula.index();
457 }
458
459 CUDA bool is(size_t kind) const {
460 return formula.index() == kind;
461 }
462
463 CUDA bool is_true() const {
464 return (is(B) && b()) || (is(Z) && z() != 0);
465 }
466
467 CUDA bool is_false() const {
468 return (is(B) && !b()) || (is(Z) && z() == 0);
469 }
470
471 CUDA logic_int to_z() const {
472 assert(is(B) || is(Z));
473 return (is(B) ? (b() ? 1 : 0) : z());
474 }
475
476 CUDA bool is_constant() const {
477 return is(B) || is(Z) || is(R) || is(S);
478 }
479
480 CUDA bool is_variable() const {
481 return is(LV) || is(V);
482 }
483
484 CUDA bool is_unary() const {
485 return is(Seq) && seq().size() == 1;
486 }
487
488 CUDA bool is_binary() const {
489 return is(Seq) && seq().size() == 2;
490 }
491
492 CUDA logic_bool b() const {
493 return battery::get<B>(formula);
494 }
495
496 CUDA logic_int z() const {
497 return battery::get<Z>(formula);
498 }
499
500 CUDA const logic_real& r() const {
501 return battery::get<R>(formula);
502 }
503
504 CUDA const LogicSet& s() const {
505 return battery::get<S>(formula);
506 }
507
508 CUDA AVar v() const {
509 return battery::get<V>(formula);
510 }
511
512 CUDA const LVar<Allocator>& lv() const {
513 return battery::get<LV>(formula);
514 }
515
516 CUDA const Existential& exists() const {
517 return battery::get<E>(formula);
518 }
519
520 CUDA Sig sig() const {
521 return battery::get<0>(battery::get<Seq>(formula));
522 }
523
524 CUDA NI bool is_logical() const {
525 if(is(Seq)) {
526 Sig s = sig();
527 return s == AND || s == OR || s == IMPLY
528 || s == EQUIV || s == NOT || s == XOR || s == ITE;
529 }
530 return false;
531 }
532
533 CUDA const ExtendedSig& esig() const {
534 return battery::get<0>(battery::get<ESeq>(formula));
535 }
536
537 CUDA const Sequence& seq() const {
538 return battery::get<1>(battery::get<Seq>(formula));
539 }
540
541 CUDA const this_type& seq(size_t i) const {
542 return seq()[i];
543 }
544
545 CUDA const Sequence& eseq() const {
546 return battery::get<1>(battery::get<ESeq>(formula));
547 }
548
549 CUDA const this_type& eseq(size_t i) const {
550 return eseq()[i];
551 }
552
553 CUDA logic_bool& b() {
554 return battery::get<B>(formula);
555 }
556
557 CUDA logic_int& z() {
558 return battery::get<Z>(formula);
559 }
560
561 CUDA logic_real& r() {
562 return battery::get<R>(formula);
563 }
564
565 CUDA LogicSet& s() {
566 return battery::get<S>(formula);
567 }
568
569 CUDA AVar& v() {
570 return battery::get<V>(formula);
571 }
572
573 CUDA Sig& sig() {
574 return battery::get<0>(battery::get<Seq>(formula));
575 }
576
577 CUDA ExtendedSig& esig() {
578 return battery::get<0>(battery::get<ESeq>(formula));
579 }
580
581 CUDA Sequence& seq() {
582 return battery::get<1>(battery::get<Seq>(formula));
583 }
584
585 CUDA this_type& seq(size_t i) {
586 return seq()[i];
587 }
588
589 CUDA Sequence& eseq() {
590 return battery::get<1>(battery::get<ESeq>(formula));
591 }
592
593 CUDA this_type& eseq(size_t i) {
594 return eseq()[i];
595 }
596
597 CUDA NI this_type map_sig(Sig sig) const {
598 assert(is(Seq));
599 this_type f = *this;
600 f.sig() = sig;
601 return std::move(f);
602 }
603
604 CUDA NI this_type map_atype(AType aty) const {
605 this_type f = *this;
606 f.type_as(aty);
607 return std::move(f);
608 }
609
610private:
611 template <class Fun>
612 CUDA NI void inplace_map_(Fun fun, const this_type& parent) {
613 switch(formula.index()) {
614 case Seq: {
615 for(int i = 0; i < seq().size(); ++i) {
616 seq(i).inplace_map_(fun, *this);
617 }
618 break;
619 }
620 case ESeq: {
621 for(int i = 0; i < eseq().size(); ++i) {
622 eseq(i).inplace_map_(fun, *this);
623 }
624 break;
625 }
626 default: {
627 fun(*this, parent);
628 break;
629 }
630 }
631 }
632
633public:
634
635 /** In-place map of each leaf of the formula to a new leaf according to `fun`. */
636 template <class Fun>
637 CUDA NI void inplace_map(Fun fun) {
638 return inplace_map_(fun, *this);
639 }
640
641 /** Map of each leaf of the formula to a new leaf according to `fun`. */
642 template <class Fun>
643 CUDA NI this_type map(Fun fun) {
644 this_type copy(*this);
645 copy.inplace_map([&](this_type& f, const this_type& parent){ f = fun(f, parent); });
646 return std::move(copy);
647 }
648
649private:
650 template<size_t n>
651 CUDA NI void print_sequence(bool print_atype, bool top_level = false) const {
652 const auto& op = battery::get<0>(battery::get<n>(formula));
653 const auto& children = battery::get<1>(battery::get<n>(formula));
654 if(children.size() == 0) {
656 return;
657 }
658 if constexpr(n == Seq) {
659 if(children.size() == 1) {
660 if(op == ABS) printf("|");
661 else if(op == CARD) printf("#(");
662 else printf("%s(", string_of_sig(op));
663 children[0].print_impl(print_atype);
664 if(op == ABS) printf("|");
665 else if(op == CARD) printf(")");
666 else printf(")");
667 return;
668 }
669 }
670 bool isprefix = true;
671 if constexpr(n == Seq) {
672 isprefix = is_prefix(op);
673 }
674 if(isprefix) {
676 }
677 printf("(");
678 for(int i = 0; i < children.size(); ++i) {
679 children[i].print_impl(print_atype);
680 if(i < children.size() - 1) {
681 if(!isprefix) {
682 printf(" ");
684 printf(" ");
685 }
686 else {
687 printf(", ");
688 }
689 }
690 if constexpr(n == Seq) {
691 if(op == AND && top_level) {
692 printf("\n");
693 }
694 }
695 }
696 printf(")");
697 }
698
699 CUDA NI void print_impl(bool print_atype = true, bool top_level = false) const {
700 switch(formula.index()) {
701 case B:
702 printf("%s", b() ? "true" : "false");
703 break;
704 case Z:
705 printf("%lld", z());
706 break;
707 case R: {
708 const auto& r_lb = battery::get<0>(r());
709 const auto& r_ub = battery::get<1>(r());
710 if(r_lb == r_ub) {
711 printf("%.50lf", r_lb);
712 }
713 else {
714 printf("[%.50lf..%.50lf]", r_lb, r_ub);
715 }
716 break;
717 }
718 case S:
719 printf("{");
720 for(int i = 0; i < s().size(); ++i) {
721 const auto& lb = battery::get<0>(s()[i]);
722 const auto& ub = battery::get<1>(s()[i]);
723 if(lb == ub) {
724 lb.print(print_atype);
725 }
726 else {
727 printf("[");
728 lb.print(print_atype);
729 printf("..");
730 ub.print(print_atype);
731 printf("]");
732 }
733 if(i < s().size() - 1) {
734 printf(", ");
735 }
736 }
737 printf("}");
738 break;
739 case V:
740 printf("var(%d, %d)", v().vid(), v().aty());
741 break;
742 case LV:
743 lv().print();
744 break;
745 case E: {
746 if(print_atype) { printf("("); }
747 const auto& e = exists();
748 printf("var ");
749 battery::get<0>(e).print();
750 printf(":");
751 battery::get<1>(e).print();
752 if(print_atype) { printf(")"); }
753 break;
754 }
755 case Seq: print_sequence<Seq>(print_atype, top_level); break;
756 case ESeq: print_sequence<ESeq>(print_atype, top_level); break;
757 default: printf("print: formula not handled.\n"); assert(false); break;
758 }
759 if(print_atype) {
760 printf(":%d", type_);
761 }
762 }
763
764public:
765 CUDA void print(bool print_atype = true) const {
766 print_impl(print_atype, true);
767 }
768};
769
770template<typename Allocator, typename ExtendedSig>
772 return lhs.type() == rhs.type() && lhs.data() == rhs.data();
773}
774
775template<typename Allocator, typename ExtendedSig>
776CUDA bool operator!=(const TFormula<Allocator, ExtendedSig>& lhs, const TFormula<Allocator, ExtendedSig>& rhs) {
777 return !(lhs == rhs);
778}
779
780} // namespace lala
781#endif
Definition ast.hpp:38
CUDA constexpr int vid() const
Definition ast.hpp:69
CUDA constexpr int aty() const
Definition ast.hpp:65
CUDA constexpr AVar(AType atype, size_t var_id)
Definition ast.hpp:59
CUDA constexpr void type_as(AType aty)
Definition ast.hpp:73
constexpr AVar(const AVar &)=default
CUDA constexpr bool operator==(const AVar &other) const
Definition ast.hpp:46
constexpr AVar & operator=(const AVar &)=default
CUDA constexpr AVar(AType atype, int var_id)
Definition ast.hpp:53
constexpr AVar & operator=(AVar &&)=default
CUDA constexpr AVar()
Definition ast.hpp:41
CUDA constexpr bool is_untyped() const
Definition ast.hpp:61
constexpr AVar(AVar &&)=default
Definition ast.hpp:234
static constexpr size_t Seq
Definition ast.hpp:275
CUDA const Sequence & eseq() const
Definition ast.hpp:545
CUDA logic_int to_z() const
Definition ast.hpp:471
CUDA NI thrust::optional< Sort< allocator_type > > sort() const
Definition ast.hpp:358
CUDA logic_bool & b()
Definition ast.hpp:553
battery::vector< this_type, Allocator > Sequence
Definition ast.hpp:238
CUDA Sig sig() const
Definition ast.hpp:520
CUDA TFormula(this_type &&other)
Definition ast.hpp:291
friend class TFormula
Definition ast.hpp:294
CUDA TFormula(Formula &&formula)
Definition ast.hpp:287
static CUDA this_type make_exists(AType ty, LVar< Allocator > lvar, Sort< Allocator > ctype)
Definition ast.hpp:422
CUDA const logic_real & r() const
Definition ast.hpp:500
CUDA NI this_type map_sig(Sig sig) const
Definition ast.hpp:597
CUDA bool is_binary() const
Definition ast.hpp:488
CUDA NI void inplace_map(Fun fun)
Definition ast.hpp:637
CUDA NI TFormula(const TFormula< Alloc2, ExtendedSig2 > &other, const Allocator &allocator=Allocator())
Definition ast.hpp:297
CUDA this_type & operator=(this_type &&rhs)
Definition ast.hpp:339
CUDA LogicSet & s()
Definition ast.hpp:565
static CUDA this_type make_set(LogicSet set, AType atype=UNTYPED)
Definition ast.hpp:405
static constexpr size_t R
Definition ast.hpp:260
CUDA AVar & v()
Definition ast.hpp:569
static CUDA this_type make_false()
Definition ast.hpp:385
static CUDA this_type make_true()
Definition ast.hpp:384
TFormula< Allocator, ExtendedSig > this_type
Definition ast.hpp:237
CUDA bool is_true() const
Definition ast.hpp:463
CUDA Formula & data()
Definition ast.hpp:344
static CUDA this_type make_z(logic_int i, AType atype=UNTYPED)
Definition ast.hpp:391
CUDA this_type & eseq(size_t i)
Definition ast.hpp:593
CUDA logic_real & r()
Definition ast.hpp:561
CUDA const Sequence & seq() const
Definition ast.hpp:537
CUDA bool is_false() const
Definition ast.hpp:467
static CUDA this_type make_real(double lb, double ub, AType atype=UNTYPED)
Definition ast.hpp:397
static constexpr size_t S
Definition ast.hpp:263
static CUDA this_type make_unary(Sig sig, TFormula child, AType atype=UNTYPED, const Allocator &allocator=Allocator())
Definition ast.hpp:443
CUDA NI bool is_logical() const
Definition ast.hpp:524
CUDA logic_bool b() const
Definition ast.hpp:492
CUDA bool is_variable() const
Definition ast.hpp:480
CUDA bool is_unary() const
Definition ast.hpp:484
CUDA bool is(size_t kind) const
Definition ast.hpp:459
CUDA const this_type & eseq(size_t i) const
Definition ast.hpp:549
static CUDA this_type make_nary(ExtendedSig esig, Sequence children, AType atype=UNTYPED)
Definition ast.hpp:451
CUDA ExtendedSig & esig()
Definition ast.hpp:577
CUDA this_type & seq(size_t i)
Definition ast.hpp:585
static constexpr size_t V
Definition ast.hpp:266
static CUDA this_type make_bool(logic_bool b, AType atype=UNTYPED)
Definition ast.hpp:387
CUDA bool is_constant() const
Definition ast.hpp:476
CUDA void type_as(AType ty)
Definition ast.hpp:347
CUDA const LVar< Allocator > & lv() const
Definition ast.hpp:512
CUDA Sig & sig()
Definition ast.hpp:573
battery::variant< logic_bool, logic_int, logic_real, LogicSet, AVar, LVar< Allocator >, Existential, battery::tuple< Sig, Sequence >, battery::tuple< ExtendedSig, Sequence > > Formula
Representation of Booleans.
Definition ast.hpp:241
static CUDA this_type make_binary(TFormula lhs, Sig sig, TFormula rhs, AType atype=UNTYPED, const Allocator &allocator=Allocator(), bool flatten=true)
Definition ast.hpp:447
CUDA AType type() const
Definition ast.hpp:346
static constexpr size_t B
Definition ast.hpp:254
CUDA TFormula(const this_type &other)
Definition ast.hpp:290
CUDA void print(bool print_atype=true) const
Definition ast.hpp:765
Allocator allocator_type
Definition ast.hpp:236
CUDA const LogicSet & s() const
Definition ast.hpp:504
CUDA Sequence & eseq()
Definition ast.hpp:589
CUDA constexpr bool is_untyped() const
Definition ast.hpp:354
static CUDA this_type make_real(logic_real r, AType atype=UNTYPED)
Definition ast.hpp:401
CUDA this_type & operator=(const this_type &rhs)
Definition ast.hpp:334
static constexpr size_t ESeq
Definition ast.hpp:278
logic_set< this_type > LogicSet
Definition ast.hpp:240
static CUDA this_type make_lvar(AType ty, LVar< Allocator > lvar)
Definition ast.hpp:418
CUDA Sequence & seq()
Definition ast.hpp:581
CUDA AVar v() const
Definition ast.hpp:508
CUDA NI this_type map_atype(AType aty) const
Definition ast.hpp:604
CUDA TFormula(AType uid, Formula &&formula)
Definition ast.hpp:288
CUDA TFormula()
Definition ast.hpp:286
static CUDA this_type make_avar(AType ty, int vid)
Definition ast.hpp:414
CUDA const this_type & seq(size_t i) const
Definition ast.hpp:541
CUDA void swap(this_type &other)
Definition ast.hpp:329
CUDA logic_int z() const
Definition ast.hpp:496
CUDA const ExtendedSig & esig() const
Definition ast.hpp:533
CUDA NI this_type map(Fun fun)
Definition ast.hpp:643
CUDA const Formula & data() const
Definition ast.hpp:345
CUDA size_t index() const
Definition ast.hpp:455
CUDA const Existential & exists() const
Definition ast.hpp:516
static constexpr size_t E
Definition ast.hpp:272
static constexpr size_t LV
Definition ast.hpp:269
static CUDA this_type make_avar(AVar v)
Definition ast.hpp:410
CUDA static NI this_type make_nary(Sig sig, Sequence children, AType atype=UNTYPED, bool flatten=true)
Definition ast.hpp:427
CUDA logic_int & z()
Definition ast.hpp:557
battery::tuple< LVar< Allocator >, Sort< Allocator > > Existential
Definition ast.hpp:239
static constexpr size_t Z
Definition ast.hpp:257
Definition ast.hpp:210
CUDA NI void print(const lala::Sig &sig)
Definition ast.hpp:212
Definition abstract_deps.hpp:14
battery::vector< battery::tuple< F, F >, typename F::allocator_type > logic_set
Definition sort.hpp:127
int AType
Definition sort.hpp:18
CUDA constexpr bool operator==(const CartesianProduct< As... > &a, const CartesianProduct< Bs... > &b)
Definition cartesian_product.hpp:572
CUDA NI constexpr bool is_associative(Sig sig)
Definition ast.hpp:204
Sig
Definition ast.hpp:94
@ HULL
Unary function performing the convex hull of a set, e.g., .
Definition ast.hpp:110
@ XOR
Logical connector.
Definition ast.hpp:114
@ SIN
Unary arithmetic function symbols.
Definition ast.hpp:100
@ ITE
If-then-else.
Definition ast.hpp:115
@ NEQ
Equality relations.
Definition ast.hpp:112
@ SYMMETRIC_DIFFERENCE
Unary arithmetic function symbols.
Definition ast.hpp:106
@ LEQ
Unary arithmetic function symbols.
Definition ast.hpp:113
@ NOT
Unary arithmetic function symbols.
Definition ast.hpp:114
@ ACOS
Unary arithmetic function symbols.
Definition ast.hpp:100
@ IMPLY
Unary arithmetic function symbols.
Definition ast.hpp:114
@ TANH
Unary arithmetic function symbols.
Definition ast.hpp:100
@ TMOD
Truncated division, present in most programming languages, is defined as , i.e., it rounds towards ze...
Definition ast.hpp:102
@ ATAN
Unary arithmetic function symbols.
Definition ast.hpp:100
@ ASIN
Unary arithmetic function symbols.
Definition ast.hpp:100
@ CARD
Cardinality function from set to integer.
Definition ast.hpp:109
@ SUPSETEQ
Set inclusion predicates.
Definition ast.hpp:107
@ MOD
Division and modulus over continuous domains (e.g., floating-point numbers and rational).
Definition ast.hpp:101
@ DIFFERENCE
Unary arithmetic function symbols.
Definition ast.hpp:106
@ ATANH
Trigonometric unary function symbols.
Definition ast.hpp:100
@ CONVEX
Unary predicate, requiring .
Definition ast.hpp:111
@ UNION
Unary arithmetic function symbols.
Definition ast.hpp:106
@ OR
Unary arithmetic function symbols.
Definition ast.hpp:114
@ EQ
Unary arithmetic function symbols.
Definition ast.hpp:112
@ ACOSH
Unary arithmetic function symbols.
Definition ast.hpp:100
@ NROOT
Unary arithmetic function symbols.
Definition ast.hpp:99
@ GEQ
Unary arithmetic function symbols.
Definition ast.hpp:113
@ ADD
Unary arithmetic function symbols.
Definition ast.hpp:97
@ IN
Set membership predicate.
Definition ast.hpp:108
@ COS
Unary arithmetic function symbols.
Definition ast.hpp:100
@ POW
Unary arithmetic function symbols.
Definition ast.hpp:97
@ MIN
Unary arithmetic function symbols.
Definition ast.hpp:97
@ INTERSECTION
Unary arithmetic function symbols.
Definition ast.hpp:106
@ LN
Square root, natural exponential and natural logarithm function symbols.
Definition ast.hpp:98
@ SINH
Unary arithmetic function symbols.
Definition ast.hpp:100
@ EDIV
Unary arithmetic function symbols.
Definition ast.hpp:105
@ DIV
Unary arithmetic function symbols.
Definition ast.hpp:101
@ GT
Arithmetic comparison predicates. When applied to set, it corresponds to the lexicographic ordering o...
Definition ast.hpp:113
@ FMOD
Floor division (Knuth D. (1972). The Art of Computer Programming, Vol 1, Fundamental Algorithms),...
Definition ast.hpp:103
@ MAX
Binary arithmetic function symbols.
Definition ast.hpp:97
@ SQRT
Unary arithmetic function symbols.
Definition ast.hpp:98
@ LT
Unary arithmetic function symbols.
Definition ast.hpp:113
@ TDIV
Unary arithmetic function symbols.
Definition ast.hpp:102
@ FDIV
Unary arithmetic function symbols.
Definition ast.hpp:103
@ EXP
Unary arithmetic function symbols.
Definition ast.hpp:98
@ COMPLEMENT
Set functions.
Definition ast.hpp:106
@ TAN
Unary arithmetic function symbols.
Definition ast.hpp:100
@ SUBSETEQ
Unary arithmetic function symbols.
Definition ast.hpp:107
@ AND
Unary arithmetic function symbols.
Definition ast.hpp:114
@ MAXIMIZE
Unary "meta-predicate" indicating that its argument must be maximized, according to the increasing or...
Definition ast.hpp:116
@ SUBSET
Unary arithmetic function symbols.
Definition ast.hpp:107
@ MINIMIZE
Same as MAXIMIZE, but for minimization.
Definition ast.hpp:117
@ EQUIV
Unary arithmetic function symbols.
Definition ast.hpp:114
@ ABS
Unary arithmetic function symbols.
Definition ast.hpp:96
@ ASINH
Unary arithmetic function symbols.
Definition ast.hpp:100
@ SUB
Unary arithmetic function symbols.
Definition ast.hpp:97
@ SUPSET
Unary arithmetic function symbols.
Definition ast.hpp:107
@ COSH
Unary arithmetic function symbols.
Definition ast.hpp:100
@ MUL
Unary arithmetic function symbols.
Definition ast.hpp:97
@ CMOD
Ceil division is defined as . Modulus is defined as .
Definition ast.hpp:104
@ LOG
nth root and logarithm to base (both binary function symbols).
Definition ast.hpp:99
@ CDIV
Unary arithmetic function symbols.
Definition ast.hpp:104
@ NEG
Unary arithmetic function symbols.
Definition ast.hpp:96
@ EMOD
Euclidean division (Boute T. R. (1992). The Euclidean definition of the functions div and mod)....
Definition ast.hpp:105
battery::tuple< double, double > logic_real
Definition sort.hpp:119
long long int logic_int
Definition sort.hpp:114
bool logic_bool
Definition sort.hpp:109
battery::string< Allocator > LVar
Definition ast.hpp:25
CUDA NI constexpr bool is_prefix(Sig sig)
Definition ast.hpp:192
CUDA NI const char * string_of_sig(Sig sig)
Definition ast.hpp:121
CUDA NI constexpr bool is_division(Sig sig)
Definition ast.hpp:196
IKind
Definition ast.hpp:28
CUDA NI constexpr bool is_modulo(Sig sig)
Definition ast.hpp:200
#define UNTYPED
Definition sort.hpp:21
Definition sort.hpp:26