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 <optional>
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 CUDA NI inline constexpr bool is_arithmetic_comparison(Sig sig) {
210 return sig == LEQ || sig == GEQ || sig == EQ || sig == NEQ || sig == GT || sig == LT;
211 }
212
213 CUDA NI inline constexpr bool is_logical(Sig sig) {
214 return sig == AND || sig == OR || sig == IMPLY || sig == EQUIV || sig == NOT || sig == XOR;
215 }
216
217 CUDA NI inline constexpr bool is_predicate(Sig sig) {
218 return sig == IN || sig == SUBSET || sig == SUBSETEQ || sig == SUPSET || sig == SUPSETEQ ||
219 sig == EQ || sig == NEQ || sig == LEQ || sig == GEQ || sig == LT || sig == GT;
220 }
221}
222
223namespace battery {
224 template<>
225 CUDA NI inline void print(const lala::Sig& sig) {
226 printf("%s", lala::string_of_sig(sig));
227 }
228}
229
230namespace lala {
231
232/** `TFormula` represents the AST of a typed first-order logical formula.
233In 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.
234It defaults to the value `UNTYPED` if the formula is not (yet) typed.
235By default, the types of integer and real number are supported.
236The supported symbols can be extended with the template parameter `ExtendedSig`.
237This extended signature can also be used for representing exactly constant such as real numbers using a string.
238The AST of a formula is represented by a variant, where each alternative is described below.
239We represent everything at the same level (term, formula, predicate, variable, constant).
240This is generally convenient when modelling to avoid creating intermediate boolean variables when reifying.
241We can have `x + (x > y \/ y > x + 4) >= 1`.
242
243Differently 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$.
244This semantics comes from "dynamic predicate logic" where a formula is interpreted in a context (here the abstract element).
245(The exact connection of our framework to dynamic predicate logic is not yet perfectly clear.) */
246template<class Allocator, class ExtendedSig = battery::string<Allocator>>
247class TFormula {
248public:
249 using allocator_type = Allocator;
251 using Sequence = battery::vector<this_type, Allocator>;
252 using Existential = battery::tuple<LVar<Allocator>, Sort<Allocator>>;
254 using Formula = battery::variant<
255 logic_bool, ///< Representation of Booleans.
256 logic_int, ///< Representation of integers.
257 logic_real, ///< Approximation of real numbers.
258 LogicSet, ///< Set of Booleans, integers, reals or sets.
259 AVar, ///< Abstract variable
260 LVar<Allocator>, ///< Logical variable
261 Existential, ///< Existential quantifier
262 battery::tuple<Sig, Sequence>, ///< ADD, SUB, ..., EQ, ..., AND, .., NOT
263 battery::tuple<ExtendedSig, Sequence> ///< see above
264 >;
265
266 /** Index of Booleans in the variant type `Formula` (called kind below). */
267 static constexpr size_t B = 0;
268
269 /** Index of integers in the variant type `Formula` (called kind below). */
270 static constexpr size_t Z = B + 1;
271
272 /** Index of real numbers in the variant type `Formula` (called kind below). */
273 static constexpr size_t R = Z + 1;
274
275 /** Index of sets in the variant type `Formula` (called kind below). */
276 static constexpr size_t S = R + 1;
277
278 /** Index of abstract variables in the variant type `Formula` (called kind below). */
279 static constexpr size_t V = S + 1;
280
281 /** Index of logical variables in the variant type `Formula` (called kind below). */
282 static constexpr size_t LV = V + 1;
283
284 /** Index of existential quantifier in the variant type `Formula` (called kind below). */
285 static constexpr size_t E = LV + 1;
286
287 /** Index of n-ary operators in the variant type `Formula` (called kind below). */
288 static constexpr size_t Seq = E + 1;
289
290 /** Index of n-ary operators where the operator is an extended signature in the variant type `Formula` (called kind below). */
291 static constexpr size_t ESeq = Seq + 1;
292
293private:
294 AType type_;
295 Formula formula;
296
297public:
298 /** By default, we initialize the formula to `true`. */
299 CUDA TFormula(): type_(UNTYPED), formula(Formula::template create<B>(true)) {}
300 CUDA TFormula(Formula&& formula): type_(UNTYPED), formula(std::move(formula)) {}
301 CUDA TFormula(AType uid, Formula&& formula): type_(uid), formula(std::move(formula)) {}
302
303 CUDA TFormula(const this_type& other): type_(other.type_), formula(other.formula) {}
304 CUDA TFormula(this_type&& other): type_(other.type_), formula(std::move(other.formula)) {}
305
306 template <class Alloc2, class ExtendedSig2>
307 friend class TFormula;
308
309 template <class Alloc2, class ExtendedSig2>
310 CUDA NI TFormula(const TFormula<Alloc2, ExtendedSig2>& other, const Allocator& allocator = Allocator())
311 : type_(other.type_), formula(Formula::template create<B>(true))
312 {
313 switch(other.formula.index()) {
314 case B: formula = Formula::template create<B>(other.b()); break;
315 case Z: formula = Formula::template create<Z>(other.z()); break;
316 case R: formula = Formula::template create<R>(other.r()); break;
317 case S: formula = Formula::template create<S>(LogicSet(other.s(), allocator));
318 break;
319 case V: formula = Formula::template create<V>(other.v()); break;
320 case LV: formula = Formula::template create<LV>(LVar<Allocator>(other.lv(), allocator)); break;
321 case E: formula = Formula::template create<E>(
322 battery::make_tuple(
323 LVar<Allocator>(battery::get<0>(other.exists()), allocator),
324 battery::get<1>(other.exists())));
325 break;
326 case Seq:
327 formula = Formula::template create<Seq>(
328 battery::make_tuple(
329 other.sig(),
330 Sequence(other.seq(), allocator)));
331 break;
332 case ESeq:
333 formula = Formula::template create<ESeq>(
334 battery::make_tuple(
335 ExtendedSig(other.esig(), allocator),
336 Sequence(other.eseq(), allocator)));
337 break;
338 default: printf("print: formula not handled.\n"); assert(false); break;
339 }
340 }
341
342 CUDA void swap(this_type& other) {
343 ::battery::swap(type_, other.type_);
344 ::battery::swap(formula, other.formula);
345 }
346
347 CUDA this_type& operator=(const this_type& rhs) {
348 this_type(rhs).swap(*this);
349 return *this;
350 }
351
353 this_type(std::move(rhs)).swap(*this);
354 return *this;
355 }
356
357 CUDA Formula& data() { return formula; }
358 CUDA const Formula& data() const { return formula; }
359 CUDA AType type() const { return type_; }
360 CUDA void type_as(AType ty) {
361 type_ = ty;
362 if(is(V)) {
363 v().type_as(ty);
364 }
365 }
366
367 CUDA constexpr bool is_untyped() const {
368 return type() == UNTYPED;
369 }
370
371 CUDA NI std::optional<Sort<allocator_type>> sort() const {
372 using sort_t = Sort<allocator_type>;
373 switch(formula.index()) {
374 case B: return sort_t(sort_t::Bool);
375 case Z: return sort_t(sort_t::Int);
376 case R: return sort_t(sort_t::Real);
377 case S: {
378 if(s().empty()) {
379 return {}; // Impossible to get the sort of the empty set.
380 }
381 for(int i = 0; i < s().size(); ++i) {
382 auto subsort = battery::get<0>(s()[i]).sort();
383 if(!subsort.has_value()) {
384 subsort = battery::get<1>(s()[i]).sort();
385 }
386 if(subsort.has_value()) {
387 return sort_t(sort_t::Set, std::move(*subsort) , s().get_allocator());
388 }
389 }
390 break;
391 }
392 case E: return battery::get<1>(exists());
393 }
394 return {};
395 }
396
397 CUDA static this_type make_true() { return TFormula(); }
398 CUDA static this_type make_false() { return TFormula(Formula::template create<B>(false)); }
399
400 CUDA static this_type make_bool(logic_bool b, AType atype = UNTYPED) {
401 return this_type(atype, Formula::template create<B>(b));
402 }
403
404 CUDA static this_type make_z(logic_int i, AType atype = UNTYPED) {
405 return this_type(atype, Formula::template create<Z>(i));
406 }
407
408 /** Create a term representing a real number which is approximated by interval [lb..ub].
409 By default the real number is supposedly over-approximated. */
410 CUDA static this_type make_real(double lb, double ub, AType atype = UNTYPED) {
411 return this_type(atype, Formula::template create<R>(battery::make_tuple(lb, ub)));
412 }
413
414 CUDA static this_type make_real(logic_real r, AType atype = UNTYPED) {
415 return this_type(atype, Formula::template create<R>(r));
416 }
417
418 CUDA static this_type make_set(LogicSet set, AType atype = UNTYPED) {
419 return this_type(atype, Formula::template create<S>(std::move(set)));
420 }
421
422 /** The type of the formula is embedded in `v`. */
423 CUDA static this_type make_avar(AVar v) {
424 return this_type(v.aty(), Formula::template create<V>(v));
425 }
426
427 CUDA static this_type make_avar(AType ty, int vid) {
428 return make_avar(AVar(ty, vid));
429 }
430
431 CUDA static this_type make_lvar(AType ty, LVar<Allocator> lvar) {
432 return this_type(ty, Formula::template create<LV>(std::move(lvar)));
433 }
434
436 return this_type(ty, Formula::template create<E>(battery::make_tuple(std::move(lvar), std::move(ctype))));
437 }
438
439 /** If `flatten` is `true` it will try to merge the children together to avoid nested formula. */
440 CUDA NI static this_type make_nary(Sig sig, Sequence children, AType atype = UNTYPED, bool flatten=true)
441 {
442 if(is_associative(sig) && flatten) {
443 Sequence seq{children.get_allocator()};
444 for(size_t i = 0; i < children.size(); ++i) {
445 if(children[i].is(Seq) && children[i].sig() == sig && children[i].type() == atype) {
446 for(size_t j = 0; j < children[i].seq().size(); ++j) {
447 seq.push_back(std::move(children[i].seq(j)));
448 }
449 }
450 else {
451 seq.push_back(std::move(children[i]));
452 }
453 }
454 return this_type(atype, Formula::template create<Seq>(battery::make_tuple(sig, std::move(seq))));
455 }
456 else {
457 return this_type(atype, Formula::template create<Seq>(battery::make_tuple(sig, std::move(children))));
458 }
459 /** The following code leads to bugs (accap_a4 segfaults, wordpress7_500 gives wrong answers).
460 * I don't know why, but it seems that the simplification is not always correct, perhaps in reified context?
461 * Or perhaps it is a question of atype? */
462 // if(seq.size() == 0) {
463 // if(sig == AND) return make_true();
464 // if(sig == OR) return make_false();
465 // }
466 // if(seq.size() == 1 && (sig == AND || sig == OR)) {
467 // return std::move(seq[0]);
468 // }
469 }
470
471 CUDA static this_type make_unary(Sig sig, TFormula child, AType atype = UNTYPED, const Allocator& allocator = Allocator()) {
472 return make_nary(sig, Sequence({std::move(child)}, allocator), atype);
473 }
474
475 CUDA static this_type make_binary(TFormula lhs, Sig sig, TFormula rhs, AType atype = UNTYPED, const Allocator& allocator = Allocator(), bool flatten=true) {
476 return make_nary(sig, Sequence({std::move(lhs), std::move(rhs)}, allocator), atype, flatten);
477 }
478
479 CUDA static this_type make_nary(ExtendedSig esig, Sequence children, AType atype = UNTYPED) {
480 return this_type(atype, Formula::template create<ESeq>(battery::make_tuple(std::move(esig), std::move(children))));
481 }
482
483 CUDA size_t index() const {
484 return formula.index();
485 }
486
487 CUDA bool is(size_t kind) const {
488 return formula.index() == kind;
489 }
490
491 CUDA bool is_true() const {
492 return (is(B) && b()) || (is(Z) && z() != 0);
493 }
494
495 CUDA bool is_false() const {
496 return (is(B) && !b()) || (is(Z) && z() == 0);
497 }
498
499 CUDA logic_int to_z() const {
500 assert(is(B) || is(Z));
501 return (is(B) ? (b() ? 1 : 0) : z());
502 }
503
504 CUDA bool is_constant() const {
505 return is(B) || is(Z) || is(R) || is(S);
506 }
507
508 CUDA bool is_variable() const {
509 return is(LV) || is(V);
510 }
511
512 CUDA bool is_unary() const {
513 return is(Seq) && seq().size() == 1;
514 }
515
516 CUDA bool is_binary() const {
517 return is(Seq) && seq().size() == 2;
518 }
519
520 CUDA logic_bool b() const {
521 return battery::get<B>(formula);
522 }
523
524 CUDA logic_int z() const {
525 return battery::get<Z>(formula);
526 }
527
528 CUDA const logic_real& r() const {
529 return battery::get<R>(formula);
530 }
531
532 CUDA const LogicSet& s() const {
533 return battery::get<S>(formula);
534 }
535
536 CUDA AVar v() const {
537 return battery::get<V>(formula);
538 }
539
540 CUDA const LVar<Allocator>& lv() const {
541 return battery::get<LV>(formula);
542 }
543
544 CUDA const Existential& exists() const {
545 return battery::get<E>(formula);
546 }
547
548 CUDA Sig sig() const {
549 return battery::get<0>(battery::get<Seq>(formula));
550 }
551
552 CUDA NI bool is_logical() const {
553 if(is(Seq)) {
554 return ::lala::is_logical(sig());
555 }
556 return false;
557 }
558
559 CUDA NI bool is_predicate() const {
560 if(is(Seq)) {
561 return ::lala::is_predicate(sig());
562 }
563 return false;
564 }
565
566 CUDA NI bool is_comparison() const {
567 if(is(Seq)) {
568 Sig s = sig();
570 }
571 return false;
572 }
573
574 CUDA const ExtendedSig& esig() const {
575 return battery::get<0>(battery::get<ESeq>(formula));
576 }
577
578 CUDA const Sequence& seq() const {
579 return battery::get<1>(battery::get<Seq>(formula));
580 }
581
582 CUDA const this_type& seq(size_t i) const {
583 return seq()[i];
584 }
585
586 CUDA const Sequence& eseq() const {
587 return battery::get<1>(battery::get<ESeq>(formula));
588 }
589
590 CUDA const this_type& eseq(size_t i) const {
591 return eseq()[i];
592 }
593
594 CUDA logic_bool& b() {
595 return battery::get<B>(formula);
596 }
597
598 CUDA logic_int& z() {
599 return battery::get<Z>(formula);
600 }
601
602 CUDA logic_real& r() {
603 return battery::get<R>(formula);
604 }
605
606 CUDA LogicSet& s() {
607 return battery::get<S>(formula);
608 }
609
610 CUDA AVar& v() {
611 return battery::get<V>(formula);
612 }
613
614 CUDA Sig& sig() {
615 return battery::get<0>(battery::get<Seq>(formula));
616 }
617
618 CUDA ExtendedSig& esig() {
619 return battery::get<0>(battery::get<ESeq>(formula));
620 }
621
622 CUDA Sequence& seq() {
623 return battery::get<1>(battery::get<Seq>(formula));
624 }
625
626 CUDA this_type& seq(size_t i) {
627 return seq()[i];
628 }
629
630 CUDA Sequence& eseq() {
631 return battery::get<1>(battery::get<ESeq>(formula));
632 }
633
634 CUDA this_type& eseq(size_t i) {
635 return eseq()[i];
636 }
637
638 CUDA NI this_type map_sig(Sig sig) const {
639 assert(is(Seq));
640 this_type f = *this;
641 f.sig() = sig;
642 return std::move(f);
643 }
644
645 CUDA NI this_type map_atype(AType aty) const {
646 this_type f = *this;
647 f.type_as(aty);
648 return std::move(f);
649 }
650
651private:
652 template <class Fun>
653 CUDA NI void inplace_map_(Fun fun, const this_type& parent) {
654 switch(formula.index()) {
655 case Seq: {
656 for(int i = 0; i < seq().size(); ++i) {
657 seq(i).inplace_map_(fun, *this);
658 }
659 break;
660 }
661 case ESeq: {
662 for(int i = 0; i < eseq().size(); ++i) {
663 eseq(i).inplace_map_(fun, *this);
664 }
665 break;
666 }
667 default: {
668 fun(*this, parent);
669 break;
670 }
671 }
672 }
673
674public:
675
676 /** In-place map of each leaf of the formula to a new leaf according to `fun`. */
677 template <class Fun>
678 CUDA NI void inplace_map(Fun fun) {
679 return inplace_map_(fun, *this);
680 }
681
682 /** Map of each leaf of the formula to a new leaf according to `fun`. */
683 template <class Fun>
684 CUDA NI this_type map(Fun fun) {
685 this_type copy(*this);
686 copy.inplace_map([&](this_type& f, const this_type& parent){ f = fun(f, parent); });
687 return std::move(copy);
688 }
689
690private:
691 template<size_t n>
692 CUDA NI void print_sequence(bool print_atype, bool top_level = false) const {
693 const auto& op = battery::get<0>(battery::get<n>(formula));
694 const auto& children = battery::get<1>(battery::get<n>(formula));
695 if(children.size() == 0) {
697 return;
698 }
699 if constexpr(n == Seq) {
700 if(children.size() == 1) {
701 if(op == ABS) printf("|");
702 else if(op == CARD) printf("#(");
703 else printf("%s(", string_of_sig(op));
704 children[0].print_impl(print_atype);
705 if(op == ABS) printf("|");
706 else if(op == CARD) printf(")");
707 else printf(")");
708 return;
709 }
710 }
711 bool isprefix = true;
712 if constexpr(n == Seq) {
713 isprefix = is_prefix(op);
714 }
715 if(isprefix) {
717 }
718 printf("(");
719 for(int i = 0; i < children.size(); ++i) {
720 children[i].print_impl(print_atype);
721 if(i < children.size() - 1) {
722 if(!isprefix) {
723 printf(" ");
725 printf(" ");
726 }
727 else {
728 printf(", ");
729 }
730 }
731 if constexpr(n == Seq) {
732 if(op == AND && top_level) {
733 printf("\n");
734 }
735 }
736 }
737 printf(")");
738 }
739
740 CUDA NI void print_impl(bool print_atype = true, bool top_level = false) const {
741 switch(formula.index()) {
742 case B:
743 printf("%s", b() ? "true" : "false");
744 break;
745 case Z:
746 printf("%lld", z());
747 break;
748 case R: {
749 const auto& r_lb = battery::get<0>(r());
750 const auto& r_ub = battery::get<1>(r());
751 if(r_lb == r_ub) {
752 printf("%.50lf", r_lb);
753 }
754 else {
755 printf("[%.50lf..%.50lf]", r_lb, r_ub);
756 }
757 break;
758 }
759 case S:
760 printf("{");
761 for(int i = 0; i < s().size(); ++i) {
762 const auto& lb = battery::get<0>(s()[i]);
763 const auto& ub = battery::get<1>(s()[i]);
764 if(lb == ub) {
765 lb.print(print_atype);
766 }
767 else {
768 printf("[");
769 lb.print(print_atype);
770 printf("..");
771 ub.print(print_atype);
772 printf("]");
773 }
774 if(i < s().size() - 1) {
775 printf(", ");
776 }
777 }
778 printf("}");
779 break;
780 case V:
781 printf("var(%d, %d)", v().vid(), v().aty());
782 break;
783 case LV:
784 lv().print();
785 break;
786 case E: {
787 if(print_atype) { printf("("); }
788 const auto& e = exists();
789 printf("var ");
790 battery::get<0>(e).print();
791 printf(":");
792 battery::get<1>(e).print();
793 if(print_atype) { printf(")"); }
794 break;
795 }
796 case Seq: print_sequence<Seq>(print_atype, top_level); break;
797 case ESeq: print_sequence<ESeq>(print_atype, top_level); break;
798 default: printf("print: formula not handled.\n"); assert(false); break;
799 }
800 if(print_atype) {
801 printf(":%d", type_);
802 }
803 }
804
805public:
806 CUDA void print(bool print_atype = true) const {
807 print_impl(print_atype, true);
808 }
809};
810
811template<typename Allocator, typename ExtendedSig>
813 return lhs.type() == rhs.type() && lhs.data() == rhs.data();
814}
815
816template<typename Allocator, typename ExtendedSig>
817CUDA bool operator!=(const TFormula<Allocator, ExtendedSig>& lhs, const TFormula<Allocator, ExtendedSig>& rhs) {
818 return !(lhs == rhs);
819}
820
821} // namespace lala
822#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 b.hpp:10
Definition ast.hpp:247
static constexpr size_t Seq
Definition ast.hpp:288
CUDA const Sequence & eseq() const
Definition ast.hpp:586
CUDA logic_int to_z() const
Definition ast.hpp:499
CUDA logic_bool & b()
Definition ast.hpp:594
battery::vector< this_type, Allocator > Sequence
Definition ast.hpp:251
CUDA Sig sig() const
Definition ast.hpp:548
CUDA TFormula(this_type &&other)
Definition ast.hpp:304
friend class TFormula
Definition ast.hpp:307
CUDA TFormula(Formula &&formula)
Definition ast.hpp:300
static CUDA this_type make_exists(AType ty, LVar< Allocator > lvar, Sort< Allocator > ctype)
Definition ast.hpp:435
CUDA const logic_real & r() const
Definition ast.hpp:528
CUDA NI this_type map_sig(Sig sig) const
Definition ast.hpp:638
CUDA bool is_binary() const
Definition ast.hpp:516
CUDA NI void inplace_map(Fun fun)
Definition ast.hpp:678
CUDA NI TFormula(const TFormula< Alloc2, ExtendedSig2 > &other, const Allocator &allocator=Allocator())
Definition ast.hpp:310
CUDA this_type & operator=(this_type &&rhs)
Definition ast.hpp:352
CUDA LogicSet & s()
Definition ast.hpp:606
static CUDA this_type make_set(LogicSet set, AType atype=UNTYPED)
Definition ast.hpp:418
static constexpr size_t R
Definition ast.hpp:273
CUDA AVar & v()
Definition ast.hpp:610
static CUDA this_type make_false()
Definition ast.hpp:398
static CUDA this_type make_true()
Definition ast.hpp:397
TFormula< Allocator, ExtendedSig > this_type
Definition ast.hpp:250
CUDA bool is_true() const
Definition ast.hpp:491
CUDA Formula & data()
Definition ast.hpp:357
static CUDA this_type make_z(logic_int i, AType atype=UNTYPED)
Definition ast.hpp:404
CUDA this_type & eseq(size_t i)
Definition ast.hpp:634
CUDA logic_real & r()
Definition ast.hpp:602
CUDA const Sequence & seq() const
Definition ast.hpp:578
CUDA NI std::optional< Sort< allocator_type > > sort() const
Definition ast.hpp:371
CUDA bool is_false() const
Definition ast.hpp:495
static CUDA this_type make_real(double lb, double ub, AType atype=UNTYPED)
Definition ast.hpp:410
static constexpr size_t S
Definition ast.hpp:276
static CUDA this_type make_unary(Sig sig, TFormula child, AType atype=UNTYPED, const Allocator &allocator=Allocator())
Definition ast.hpp:471
CUDA NI bool is_logical() const
Definition ast.hpp:552
CUDA logic_bool b() const
Definition ast.hpp:520
CUDA bool is_variable() const
Definition ast.hpp:508
CUDA bool is_unary() const
Definition ast.hpp:512
CUDA bool is(size_t kind) const
Definition ast.hpp:487
CUDA const this_type & eseq(size_t i) const
Definition ast.hpp:590
static CUDA this_type make_nary(ExtendedSig esig, Sequence children, AType atype=UNTYPED)
Definition ast.hpp:479
CUDA ExtendedSig & esig()
Definition ast.hpp:618
CUDA this_type & seq(size_t i)
Definition ast.hpp:626
static constexpr size_t V
Definition ast.hpp:279
static CUDA this_type make_bool(logic_bool b, AType atype=UNTYPED)
Definition ast.hpp:400
CUDA bool is_constant() const
Definition ast.hpp:504
CUDA void type_as(AType ty)
Definition ast.hpp:360
CUDA const LVar< Allocator > & lv() const
Definition ast.hpp:540
CUDA Sig & sig()
Definition ast.hpp:614
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:254
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:475
CUDA AType type() const
Definition ast.hpp:359
static constexpr size_t B
Definition ast.hpp:267
CUDA TFormula(const this_type &other)
Definition ast.hpp:303
CUDA void print(bool print_atype=true) const
Definition ast.hpp:806
Allocator allocator_type
Definition ast.hpp:249
CUDA const LogicSet & s() const
Definition ast.hpp:532
CUDA Sequence & eseq()
Definition ast.hpp:630
CUDA constexpr bool is_untyped() const
Definition ast.hpp:367
static CUDA this_type make_real(logic_real r, AType atype=UNTYPED)
Definition ast.hpp:414
CUDA this_type & operator=(const this_type &rhs)
Definition ast.hpp:347
static constexpr size_t ESeq
Definition ast.hpp:291
logic_set< this_type > LogicSet
Definition ast.hpp:253
static CUDA this_type make_lvar(AType ty, LVar< Allocator > lvar)
Definition ast.hpp:431
CUDA Sequence & seq()
Definition ast.hpp:622
CUDA AVar v() const
Definition ast.hpp:536
CUDA NI this_type map_atype(AType aty) const
Definition ast.hpp:645
CUDA NI bool is_comparison() const
Definition ast.hpp:566
CUDA TFormula(AType uid, Formula &&formula)
Definition ast.hpp:301
CUDA TFormula()
Definition ast.hpp:299
CUDA NI bool is_predicate() const
Definition ast.hpp:559
static CUDA this_type make_avar(AType ty, int vid)
Definition ast.hpp:427
CUDA const this_type & seq(size_t i) const
Definition ast.hpp:582
CUDA void swap(this_type &other)
Definition ast.hpp:342
CUDA logic_int z() const
Definition ast.hpp:524
CUDA const ExtendedSig & esig() const
Definition ast.hpp:574
CUDA NI this_type map(Fun fun)
Definition ast.hpp:684
CUDA const Formula & data() const
Definition ast.hpp:358
CUDA size_t index() const
Definition ast.hpp:483
CUDA const Existential & exists() const
Definition ast.hpp:544
static constexpr size_t E
Definition ast.hpp:285
static constexpr size_t LV
Definition ast.hpp:282
static CUDA this_type make_avar(AVar v)
Definition ast.hpp:423
CUDA static NI this_type make_nary(Sig sig, Sequence children, AType atype=UNTYPED, bool flatten=true)
Definition ast.hpp:440
CUDA logic_int & z()
Definition ast.hpp:598
battery::tuple< LVar< Allocator >, Sort< Allocator > > Existential
Definition ast.hpp:252
static constexpr size_t Z
Definition ast.hpp:270
Definition ast.hpp:223
CUDA NI void print(const lala::Sig &sig)
Definition ast.hpp:225
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:504
CUDA NI bool is_arithmetic_comparison(const F &f)
Definition algorithm.hpp:338
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 constexpr bool is_predicate(Sig sig)
Definition ast.hpp:217
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_logical(Sig sig)
Definition ast.hpp:213
CUDA NI constexpr bool is_modulo(Sig sig)
Definition ast.hpp:200
#define UNTYPED
Definition sort.hpp:21
Definition sort.hpp:26