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
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 std::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 {
429 if(is_associative(sig) && flatten) {
430 Sequence seq{children.get_allocator()};
431 for(size_t i = 0; i < children.size(); ++i) {
432 if(children[i].is(Seq) && children[i].sig() == sig && children[i].type() == atype) {
433 for(size_t j = 0; j < children[i].seq().size(); ++j) {
434 seq.push_back(std::move(children[i].seq(j)));
435 }
436 }
437 else {
438 seq.push_back(std::move(children[i]));
439 }
440 }
441 return this_type(atype, Formula::template create<Seq>(battery::make_tuple(sig, std::move(seq))));
442 }
443 else {
444 return this_type(atype, Formula::template create<Seq>(battery::make_tuple(sig, std::move(children))));
445 }
446 /** The following code leads to bugs (accap_a4 segfaults, wordpress7_500 gives wrong answers).
447 * I don't know why, but it seems that the simplification is not always correct, perhaps in reified context?
448 * Or perhaps it is a question of atype? */
449 // if(seq.size() == 0) {
450 // if(sig == AND) return make_true();
451 // if(sig == OR) return make_false();
452 // }
453 // if(seq.size() == 1 && (sig == AND || sig == OR)) {
454 // return std::move(seq[0]);
455 // }
456 }
457
458 CUDA static this_type make_unary(Sig sig, TFormula child, AType atype = UNTYPED, const Allocator& allocator = Allocator()) {
459 return make_nary(sig, Sequence({std::move(child)}, allocator), atype);
460 }
461
462 CUDA static this_type make_binary(TFormula lhs, Sig sig, TFormula rhs, AType atype = UNTYPED, const Allocator& allocator = Allocator(), bool flatten=true) {
463 return make_nary(sig, Sequence({std::move(lhs), std::move(rhs)}, allocator), atype, flatten);
464 }
465
466 CUDA static this_type make_nary(ExtendedSig esig, Sequence children, AType atype = UNTYPED) {
467 return this_type(atype, Formula::template create<ESeq>(battery::make_tuple(std::move(esig), std::move(children))));
468 }
469
470 CUDA size_t index() const {
471 return formula.index();
472 }
473
474 CUDA bool is(size_t kind) const {
475 return formula.index() == kind;
476 }
477
478 CUDA bool is_true() const {
479 return (is(B) && b()) || (is(Z) && z() != 0);
480 }
481
482 CUDA bool is_false() const {
483 return (is(B) && !b()) || (is(Z) && z() == 0);
484 }
485
486 CUDA logic_int to_z() const {
487 assert(is(B) || is(Z));
488 return (is(B) ? (b() ? 1 : 0) : z());
489 }
490
491 CUDA bool is_constant() const {
492 return is(B) || is(Z) || is(R) || is(S);
493 }
494
495 CUDA bool is_variable() const {
496 return is(LV) || is(V);
497 }
498
499 CUDA bool is_unary() const {
500 return is(Seq) && seq().size() == 1;
501 }
502
503 CUDA bool is_binary() const {
504 return is(Seq) && seq().size() == 2;
505 }
506
507 CUDA logic_bool b() const {
508 return battery::get<B>(formula);
509 }
510
511 CUDA logic_int z() const {
512 return battery::get<Z>(formula);
513 }
514
515 CUDA const logic_real& r() const {
516 return battery::get<R>(formula);
517 }
518
519 CUDA const LogicSet& s() const {
520 return battery::get<S>(formula);
521 }
522
523 CUDA AVar v() const {
524 return battery::get<V>(formula);
525 }
526
527 CUDA const LVar<Allocator>& lv() const {
528 return battery::get<LV>(formula);
529 }
530
531 CUDA const Existential& exists() const {
532 return battery::get<E>(formula);
533 }
534
535 CUDA Sig sig() const {
536 return battery::get<0>(battery::get<Seq>(formula));
537 }
538
539 CUDA NI bool is_logical() const {
540 if(is(Seq)) {
541 Sig s = sig();
542 return s == AND || s == OR || s == IMPLY
543 || s == EQUIV || s == NOT || s == XOR || s == ITE;
544 }
545 return false;
546 }
547
548 CUDA const ExtendedSig& esig() const {
549 return battery::get<0>(battery::get<ESeq>(formula));
550 }
551
552 CUDA const Sequence& seq() const {
553 return battery::get<1>(battery::get<Seq>(formula));
554 }
555
556 CUDA const this_type& seq(size_t i) const {
557 return seq()[i];
558 }
559
560 CUDA const Sequence& eseq() const {
561 return battery::get<1>(battery::get<ESeq>(formula));
562 }
563
564 CUDA const this_type& eseq(size_t i) const {
565 return eseq()[i];
566 }
567
568 CUDA logic_bool& b() {
569 return battery::get<B>(formula);
570 }
571
572 CUDA logic_int& z() {
573 return battery::get<Z>(formula);
574 }
575
576 CUDA logic_real& r() {
577 return battery::get<R>(formula);
578 }
579
580 CUDA LogicSet& s() {
581 return battery::get<S>(formula);
582 }
583
584 CUDA AVar& v() {
585 return battery::get<V>(formula);
586 }
587
588 CUDA Sig& sig() {
589 return battery::get<0>(battery::get<Seq>(formula));
590 }
591
592 CUDA ExtendedSig& esig() {
593 return battery::get<0>(battery::get<ESeq>(formula));
594 }
595
596 CUDA Sequence& seq() {
597 return battery::get<1>(battery::get<Seq>(formula));
598 }
599
600 CUDA this_type& seq(size_t i) {
601 return seq()[i];
602 }
603
604 CUDA Sequence& eseq() {
605 return battery::get<1>(battery::get<ESeq>(formula));
606 }
607
608 CUDA this_type& eseq(size_t i) {
609 return eseq()[i];
610 }
611
612 CUDA NI this_type map_sig(Sig sig) const {
613 assert(is(Seq));
614 this_type f = *this;
615 f.sig() = sig;
616 return std::move(f);
617 }
618
619 CUDA NI this_type map_atype(AType aty) const {
620 this_type f = *this;
621 f.type_as(aty);
622 return std::move(f);
623 }
624
625private:
626 template <class Fun>
627 CUDA NI void inplace_map_(Fun fun, const this_type& parent) {
628 switch(formula.index()) {
629 case Seq: {
630 for(int i = 0; i < seq().size(); ++i) {
631 seq(i).inplace_map_(fun, *this);
632 }
633 break;
634 }
635 case ESeq: {
636 for(int i = 0; i < eseq().size(); ++i) {
637 eseq(i).inplace_map_(fun, *this);
638 }
639 break;
640 }
641 default: {
642 fun(*this, parent);
643 break;
644 }
645 }
646 }
647
648public:
649
650 /** In-place map of each leaf of the formula to a new leaf according to `fun`. */
651 template <class Fun>
652 CUDA NI void inplace_map(Fun fun) {
653 return inplace_map_(fun, *this);
654 }
655
656 /** Map of each leaf of the formula to a new leaf according to `fun`. */
657 template <class Fun>
658 CUDA NI this_type map(Fun fun) {
659 this_type copy(*this);
660 copy.inplace_map([&](this_type& f, const this_type& parent){ f = fun(f, parent); });
661 return std::move(copy);
662 }
663
664private:
665 template<size_t n>
666 CUDA NI void print_sequence(bool print_atype, bool top_level = false) const {
667 const auto& op = battery::get<0>(battery::get<n>(formula));
668 const auto& children = battery::get<1>(battery::get<n>(formula));
669 if(children.size() == 0) {
671 return;
672 }
673 if constexpr(n == Seq) {
674 if(children.size() == 1) {
675 if(op == ABS) printf("|");
676 else if(op == CARD) printf("#(");
677 else printf("%s(", string_of_sig(op));
678 children[0].print_impl(print_atype);
679 if(op == ABS) printf("|");
680 else if(op == CARD) printf(")");
681 else printf(")");
682 return;
683 }
684 }
685 bool isprefix = true;
686 if constexpr(n == Seq) {
687 isprefix = is_prefix(op);
688 }
689 if(isprefix) {
691 }
692 printf("(");
693 for(int i = 0; i < children.size(); ++i) {
694 children[i].print_impl(print_atype);
695 if(i < children.size() - 1) {
696 if(!isprefix) {
697 printf(" ");
699 printf(" ");
700 }
701 else {
702 printf(", ");
703 }
704 }
705 if constexpr(n == Seq) {
706 if(op == AND && top_level) {
707 printf("\n");
708 }
709 }
710 }
711 printf(")");
712 }
713
714 CUDA NI void print_impl(bool print_atype = true, bool top_level = false) const {
715 switch(formula.index()) {
716 case B:
717 printf("%s", b() ? "true" : "false");
718 break;
719 case Z:
720 printf("%lld", z());
721 break;
722 case R: {
723 const auto& r_lb = battery::get<0>(r());
724 const auto& r_ub = battery::get<1>(r());
725 if(r_lb == r_ub) {
726 printf("%.50lf", r_lb);
727 }
728 else {
729 printf("[%.50lf..%.50lf]", r_lb, r_ub);
730 }
731 break;
732 }
733 case S:
734 printf("{");
735 for(int i = 0; i < s().size(); ++i) {
736 const auto& lb = battery::get<0>(s()[i]);
737 const auto& ub = battery::get<1>(s()[i]);
738 if(lb == ub) {
739 lb.print(print_atype);
740 }
741 else {
742 printf("[");
743 lb.print(print_atype);
744 printf("..");
745 ub.print(print_atype);
746 printf("]");
747 }
748 if(i < s().size() - 1) {
749 printf(", ");
750 }
751 }
752 printf("}");
753 break;
754 case V:
755 printf("var(%d, %d)", v().vid(), v().aty());
756 break;
757 case LV:
758 lv().print();
759 break;
760 case E: {
761 if(print_atype) { printf("("); }
762 const auto& e = exists();
763 printf("var ");
764 battery::get<0>(e).print();
765 printf(":");
766 battery::get<1>(e).print();
767 if(print_atype) { printf(")"); }
768 break;
769 }
770 case Seq: print_sequence<Seq>(print_atype, top_level); break;
771 case ESeq: print_sequence<ESeq>(print_atype, top_level); break;
772 default: printf("print: formula not handled.\n"); assert(false); break;
773 }
774 if(print_atype) {
775 printf(":%d", type_);
776 }
777 }
778
779public:
780 CUDA void print(bool print_atype = true) const {
781 print_impl(print_atype, true);
782 }
783};
784
785template<typename Allocator, typename ExtendedSig>
787 return lhs.type() == rhs.type() && lhs.data() == rhs.data();
788}
789
790template<typename Allocator, typename ExtendedSig>
791CUDA bool operator!=(const TFormula<Allocator, ExtendedSig>& lhs, const TFormula<Allocator, ExtendedSig>& rhs) {
792 return !(lhs == rhs);
793}
794
795} // namespace lala
796#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:234
static constexpr size_t Seq
Definition ast.hpp:275
CUDA const Sequence & eseq() const
Definition ast.hpp:560
CUDA logic_int to_z() const
Definition ast.hpp:486
CUDA logic_bool & b()
Definition ast.hpp:568
battery::vector< this_type, Allocator > Sequence
Definition ast.hpp:238
CUDA Sig sig() const
Definition ast.hpp:535
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:515
CUDA NI this_type map_sig(Sig sig) const
Definition ast.hpp:612
CUDA bool is_binary() const
Definition ast.hpp:503
CUDA NI void inplace_map(Fun fun)
Definition ast.hpp:652
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:580
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:584
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:478
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:608
CUDA logic_real & r()
Definition ast.hpp:576
CUDA const Sequence & seq() const
Definition ast.hpp:552
CUDA NI std::optional< Sort< allocator_type > > sort() const
Definition ast.hpp:358
CUDA bool is_false() const
Definition ast.hpp:482
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:458
CUDA NI bool is_logical() const
Definition ast.hpp:539
CUDA logic_bool b() const
Definition ast.hpp:507
CUDA bool is_variable() const
Definition ast.hpp:495
CUDA bool is_unary() const
Definition ast.hpp:499
CUDA bool is(size_t kind) const
Definition ast.hpp:474
CUDA const this_type & eseq(size_t i) const
Definition ast.hpp:564
static CUDA this_type make_nary(ExtendedSig esig, Sequence children, AType atype=UNTYPED)
Definition ast.hpp:466
CUDA ExtendedSig & esig()
Definition ast.hpp:592
CUDA this_type & seq(size_t i)
Definition ast.hpp:600
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:491
CUDA void type_as(AType ty)
Definition ast.hpp:347
CUDA const LVar< Allocator > & lv() const
Definition ast.hpp:527
CUDA Sig & sig()
Definition ast.hpp:588
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:462
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:780
Allocator allocator_type
Definition ast.hpp:236
CUDA const LogicSet & s() const
Definition ast.hpp:519
CUDA Sequence & eseq()
Definition ast.hpp:604
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:596
CUDA AVar v() const
Definition ast.hpp:523
CUDA NI this_type map_atype(AType aty) const
Definition ast.hpp:619
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:556
CUDA void swap(this_type &other)
Definition ast.hpp:329
CUDA logic_int z() const
Definition ast.hpp:511
CUDA const ExtendedSig & esig() const
Definition ast.hpp:548
CUDA NI this_type map(Fun fun)
Definition ast.hpp:658
CUDA const Formula & data() const
Definition ast.hpp:345
CUDA size_t index() const
Definition ast.hpp:470
CUDA const Existential & exists() const
Definition ast.hpp:531
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:572
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:503
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