Lattice Land Core Library
Loading...
Searching...
No Matches
algorithm.hpp
Go to the documentation of this file.
1// Copyright 2022 Pierre Talbot
2
3#ifndef LALA_CORE_ALGORITHM_HPP
4#define LALA_CORE_ALGORITHM_HPP
5
6#include "ast.hpp"
7
8namespace lala {
9
10/** \return `true` if the formula `f` has the shape `variable <sig> constant`. */
11template<class Allocator, class ExtendedSig>
14 return f.is(F::Seq)
15 && f.sig() == sig
16 && (f.seq(0).is(F::LV) || f.seq(0).is(F::V))
17 && f.seq(1).is_constant();
18}
19
20/** \return `true` if the formula `f` has the shape `variable op integer constant`, e.g., `x < 4`. */
21template<class Allocator, class ExtendedSig>
22CUDA NI bool is_v_op_z(const TFormula<Allocator, ExtendedSig>& f, Sig sig) {
24 return f.is(F::Seq)
25 && f.sig() == sig
26 && (f.seq(0).is(F::LV) || f.seq(0).is(F::V))
27 && f.seq(1).is(F::Z);
28}
29
30/** \return `true` if the formula `f` has the shape `variable = variable` or `variable <=> variable`. */
31template<class Allocator, class ExtendedSig>
34 return f.is(F::Seq)
35 && (f.sig() == EQ || f.sig() == EQUIV)
36 && (f.seq(0).is(F::LV) || f.seq(0).is(F::V))
37 && (f.seq(1).is(F::LV) || f.seq(1).is(F::V));
38}
39
40template<class Allocator>
41CUDA NI TFormula<Allocator> make_v_op_z(LVar<Allocator> v, Sig sig, logic_int z, AType aty = UNTYPED, const Allocator& allocator = Allocator()) {
42 using F = TFormula<Allocator>;
43 return F::make_binary(F::make_lvar(UNTYPED, std::move(v)), sig, F::make_z(z), aty, allocator);
44}
45
46template<class Allocator>
47CUDA NI TFormula<Allocator> make_v_op_z(AVar v, Sig sig, logic_int z, AType aty = UNTYPED, const Allocator& allocator = Allocator()) {
48 using F = TFormula<Allocator>;
49 return F::make_binary(F::make_avar(v), sig, F::make_z(z), aty, allocator);
50}
51
52template <class Allocator>
54 using F = TFormula<Allocator>;
55 assert(f.is(F::S) || f.is(F::Z) || f.is(F::R));
56 return f.is(F::S) ? SUPSETEQ : GEQ;
57}
58
59template <class Allocator>
61 using F = TFormula<Allocator>;
62 assert(f.is(F::S) || f.is(F::Z) || f.is(F::R));
63 return f.is(F::S) ? SUBSETEQ : LEQ;
64}
65
66namespace impl {
67 template<class Allocator, class ExtendedSig>
68 CUDA NI const TFormula<Allocator, ExtendedSig>& var_in_impl(const TFormula<Allocator, ExtendedSig>& f, bool& found);
69
70 template<size_t n, class Allocator, class ExtendedSig>
71 CUDA NI const TFormula<Allocator, ExtendedSig>& find_var_in_seq(const TFormula<Allocator, ExtendedSig>& f, bool& found) {
72 const auto& children = battery::get<1>(battery::get<n>(f.data()));
73 for(int i = 0; i < children.size(); ++i) {
74 const auto& subformula = var_in_impl(children[i], found);
75 if(found) {
76 return subformula;
77 }
78 }
79 return f;
80 }
81
82 template<class Allocator, class ExtendedSig>
83 CUDA NI const TFormula<Allocator, ExtendedSig>& var_in_impl(const TFormula<Allocator, ExtendedSig>& f, bool& found)
84 {
85 using F = TFormula<Allocator, ExtendedSig>;
86 switch(f.index()) {
87 case F::Z:
88 case F::R:
89 case F::S:
90 return f;
91 case F::V:
92 case F::E:
93 case F::LV:
94 found = true;
95 return f;
96 case F::Seq: return find_var_in_seq<F::Seq>(f, found);
97 case F::ESeq: return find_var_in_seq<F::ESeq>(f, found);
98 default: printf("var_in: formula not handled.\n"); assert(false); return f;
99 }
100 }
101
102 template<size_t n, class F>
103 CUDA NI int num_vars_in_seq(const F& f) {
104 const auto& children = battery::get<1>(battery::get<n>(f.data()));
105 int total = 0;
106 for(int i = 0; i < children.size(); ++i) {
107 total += num_vars(children[i]);
108 }
109 return total;
110 }
111
112 template<class F>
113 CUDA NI int num_qf_vars(const F& f, bool type_filter, AType aty);
114
115 template<size_t n, class F>
116 CUDA NI int num_qf_vars_in_seq(const F& f, bool type_filter, AType aty) {
117 const auto& children = battery::get<1>(battery::get<n>(f.data()));
118 int total = 0;
119 for(int i = 0; i < children.size(); ++i) {
120 total += num_qf_vars(children[i], type_filter, aty);
121 }
122 return total;
123 }
124
125 template<class F>
126 CUDA NI int num_qf_vars(const F& f, bool type_filter, AType aty) {
127 switch(f.index()) {
128 case F::E:
129 if(type_filter) {
130 return f.type() == aty ? 1 : 0;
131 }
132 else {
133 return 1;
134 }
135 case F::Seq: return impl::num_qf_vars_in_seq<F::Seq>(f, type_filter, aty);
136 case F::ESeq: return impl::num_qf_vars_in_seq<F::ESeq>(f, type_filter, aty);
137 default: return 0;
138 }
139 }
140}
141
142/** \return The first variable occurring in the formula, or any other subformula if the formula does not contain a variable.
143 It returns either a logical variable, an abstract variable or a quantifier. */
144template<typename Allocator, typename ExtendedSig>
146 bool found = false;
147 return impl::var_in_impl(f, found);
148}
149
150/** \return The number of variables occurring in the formula `F` including existential quantifier, logical variables and abstract variables.
151 * Each occurrence of a variable is added up (duplicates are counted). */
152template<class F>
153CUDA NI int num_vars(const F& f)
154{
155 switch(f.index()) {
156 case F::V:
157 case F::E:
158 case F::LV:
159 return 1;
160 case F::Seq: return impl::num_vars_in_seq<F::Seq>(f);
161 case F::ESeq: return impl::num_vars_in_seq<F::ESeq>(f);
162 default: return 0;
163 }
164}
165
166/** \return The number of existential quantifiers. */
167template<class F>
168CUDA int num_quantified_vars(const F& f) {
169 return impl::num_qf_vars(f, false, UNTYPED);
170}
171
172/** \return The number of variables occurring in an existential quantifier that have type `aty`. */
173template<class F>
174CUDA int num_quantified_vars(const F& f, AType aty) {
175 return impl::num_qf_vars(f, true, aty);
176}
177
178template<class F>
179CUDA NI AType type_of_conjunction(const typename F::Sequence& seq) {
180 AType ty = UNTYPED;
181 for(int i = 0; i < seq.size(); ++i) {
182 if(seq[i].type() == UNTYPED) {
183 return UNTYPED;
184 }
185 else if(ty == UNTYPED) {
186 ty = seq[i].type();
187 }
188 else if(ty != seq[i].type()) {
189 return UNTYPED;
190 }
191 }
192 return ty;
193}
194
195/** Given a conjunctive formula `f` of the form \f$ c_1 \land ... \land c_n \f$, it returns a pair \f$ \langle c_i \land .. \land c_j, c_k \land ... \land c_l \rangle \f$ such that the first component contains all formulas with the type `ty`, and the second component, all other formulas. */
196template<class F>
197CUDA NI battery::tuple<F,F> extract_ty(const F& f, AType ty) {
198 assert(f.is(F::Seq));
199 const auto& seq = f.seq();
200 typename F::Sequence fty;
201 typename F::Sequence other;
202 for(int i = 0; i < seq.size(); ++i) {
203 // In case of nested conjunction.
204 if(seq[i].is(F::Seq) && seq[i].sig() == AND) {
205 auto r = extract_ty(seq[i], ty);
206 auto& fty_ = battery::get<0>(r).seq();
207 auto& other_ = battery::get<1>(r).seq();
208 for(int i = 0; i < fty_.size(); ++i) {
209 fty.push_back(std::move(fty_[i]));
210 }
211 for(int i = 0; i < other_.size(); ++i) {
212 other.push_back(std::move(other_[i]));
213 }
214 }
215 else if(seq[i].type() == ty) {
216 fty.push_back(seq[i]);
217 }
218 else {
219 other.push_back(seq[i]);
220 }
221 }
222 AType other_ty = type_of_conjunction<F>(other);
223 return battery::make_tuple(
224 F::make_nary(AND, std::move(fty), ty),
225 F::make_nary(AND, std::move(other), other_ty));
226}
227
228template <class F>
229CUDA NI std::optional<F> negate(const F& f);
230
231/** not(f1 \/ ... \/ fn) --> not(f1) /\ ... /\ not(fn)
232 not(f1 /\ ... /\ fn) --> not(f1) \/ ... \/ not(fn) */
233template <class F>
234CUDA NI std::optional<F> de_morgan_law(Sig sig_neg, const F& f) {
235 auto seq = f.seq();
236 typename F::Sequence neg_seq(seq.size());
237 for(int i = 0; i < f.seq().size(); ++i) {
238 auto neg_i = negate(seq[i]);
239 if(neg_i.has_value()) {
240 neg_seq[i] = *neg_i;
241 }
242 else {
243 return {};
244 }
245 }
246 return F::make_nary(sig_neg, neg_seq, f.type());
247}
248
249template <class F>
250CUDA NI std::optional<F> negate_eq(const F& f) {
251 assert(f.is_binary() && f.sig() == EQ);
252 if(f.seq(0).is(F::B)) {
253 auto b = f.seq(0);
254 b.b() = !b.b();
255 return F::make_binary(b, EQ, f.seq(1), f.type(), f.seq().get_allocator());
256 }
257 else if(f.seq(1).is(F::B)) {
258 auto b = f.seq(1);
259 b.b() = !b.b();
260 return F::make_binary(f.seq(0), EQ, b, f.type(), f.seq().get_allocator());
261 }
262 return F::make_nary(NEQ, f.seq(), f.type());
263}
264
265template <class F>
266CUDA NI std::optional<F> negate(const F& f) {
267 if(f.is_true()) {
268 return F::make_false();
269 }
270 else if(f.is_false()) {
271 return F::make_true();
272 }
273 else if(f.is_variable()) {
274 return F::make_unary(NOT, f, f.type());
275 }
276 else if(f.is(F::Seq)) {
277 Sig neg_sig;
278 switch(f.sig()) {
279 case NOT: return f.seq(0);
280 case EQ: return negate_eq(f);
281 // Total order predicates can be reversed.
282 case LEQ: neg_sig = GT; break;
283 case GEQ: neg_sig = LT; break;
284 case NEQ: neg_sig = EQ; break;
285 case LT: neg_sig = GEQ; break;
286 case GT: neg_sig = LEQ; break;
287 // Partial order predicates cannot simply be reversed.
288 case SUBSET:
289 case SUBSETEQ:
290 case SUPSET:
291 case SUPSETEQ:
292 case IN:
293 return F::make_unary(NOT, f, f.type());
294 case AND:
295 return de_morgan_law(OR, f);
296 case OR:
297 return de_morgan_law(AND, f);
298 default:
299 return {};
300 }
301 return F::make_nary(neg_sig, f.seq(), f.type());
302 }
303 return {};
304}
305
307 switch(sig) {
308 case EQ: return NEQ;
309 case NEQ: return EQ;
310 case LEQ: return GT;
311 case GEQ: return LT;
312 case LT: return GEQ;
313 case GT: return LEQ;
314 default: assert(0); return sig;
315 }
316}
317
318/** True for the operators <=, <, >, >=, =, != */
319template <class F>
320CUDA NI bool is_arithmetic_comparison(const F& f) {
321 if(f.is(F::Seq)) {
322 switch(f.sig()) {
323 case LEQ:
324 case GEQ:
325 case LT:
326 case GT:
327 case EQ:
328 case NEQ:
329 return true;
330 default: break;
331 }
332 }
333 return false;
334}
335
336/** True for the operators =, !=, subset, subseteq, supset, supseteq */
337template <class F>
338CUDA NI bool is_set_comparison(const F& f) {
339 if(f.is(F::Seq)) {
340 switch(f.sig()) {
341 case EQ:
342 case NEQ:
343 case SUBSET:
344 case SUBSETEQ:
345 case SUPSET:
346 case SUPSETEQ:
347 return true;
348 default: break;
349 }
350 }
351 return false;
352}
353
354/** True for the operators <=, <, >, >=, =, !=, subset, subseteq, supset, supseteq */
355template <class F>
356CUDA NI bool is_comparison(const F& f) {
357 if(f.is(F::Seq)) {
358 switch(f.sig()) {
359 case LEQ:
360 case GEQ:
361 case LT:
362 case GT:
363 case EQ:
364 case NEQ:
365 case SUBSET:
366 case SUBSETEQ:
367 case SUPSET:
368 case SUPSETEQ:
369 return true;
370 default: break;
371 }
372 }
373 return false;
374}
375
376/** Returns the converse of a comparison operator (see `is_comparison`). */
377CUDA NI inline Sig converse_comparison(Sig sig) {
378 switch(sig) {
379 case LEQ: return GEQ;
380 case GEQ: return LEQ;
381 case GT: return LT;
382 case LT: return GT;
383 case EQ: return sig;
384 case NEQ: return sig;
385 case SUBSET: return SUPSET;
386 case SUBSETEQ: return SUPSETEQ;
387 case SUPSET: return SUBSET;
388 case SUPSETEQ: return SUBSETEQ;
389 default:
390 assert(false); // converse not supported for all operators.
391 break;
392 }
393 return sig;
394}
395
396/** Given a formula `f`, we transform all occurrences of `AVar` into logical variables. */
397template <class F, class Env>
398CUDA NI void map_avar_to_lvar(F& f, const Env& env, bool erase_type = false) {
399 switch(f.index()) {
400 case F::V:
401 f = F::make_lvar(erase_type ? UNTYPED : f.v().aty(), env.name_of(f.v()));
402 break;
403 case F::Seq:
404 for(int i = 0; i < f.seq().size(); ++i) {
405 map_avar_to_lvar(f.seq(i), env, erase_type);
406 }
407 break;
408 case F::ESeq:
409 for(int i = 0; i < f.eseq().size(); ++i) {
410 map_avar_to_lvar(f.eseq(i), env, erase_type);
411 }
412 break;
413 default: break;
414 }
415}
416
417namespace impl {
418 template <class F>
419 CUDA bool is_bz(const F& f) {
420 return f.is(F::Z) || f.is(F::B);
421 }
422
423 template <class F>
424 CUDA bool is_binary_bz(const typename F::Sequence& seq) {
425 return seq.size() == 2 && is_bz(seq[0]) && is_bz(seq[1]);
426 }
427
428 template <class F>
429 CUDA bool is_binary_z(const typename F::Sequence& seq) {
430 return seq.size() == 2 && seq[0].is(F::Z) && seq[1].is(F::Z);
431 }
432
433 /** Evaluate the function or predicate `sig` on the sequence of constants `seq`.
434 * It only works on Boolean and integers constants for now.
435 */
436 template <class F>
437 CUDA F eval_seq(Sig sig, const typename F::Sequence& seq, AType atype) {
438 switch(sig) {
439 case AND: {
440 typename F::Sequence residual;
441 for(int i = 0; i < seq.size(); ++i) {
442 if(seq[i].is_false()) {
443 return F::make_false();
444 }
445 else if(!seq[i].is_true()) {
446 residual.push_back(seq[i]);
447 }
448 }
449 if(residual.size() == 0) {
450 return F::make_true();
451 }
452 else if(residual.size() == 1) {
453 return residual[0];
454 }
455 else {
456 return F::make_nary(AND, std::move(residual), atype);
457 }
458 }
459 case OR: {
460 typename F::Sequence residual;
461 for(int i = 0; i < seq.size(); ++i) {
462 if(seq[i].is_true()) {
463 return F::make_true();
464 }
465 else if(!seq[i].is_false()) {
466 residual.push_back(seq[i]);
467 }
468 }
469 if(residual.size() == 0) {
470 return F::make_false();
471 }
472 else if(residual.size() == 1) {
473 return residual[0];
474 }
475 else {
476 return F::make_nary(OR, std::move(residual), atype);
477 }
478 }
479 case IMPLY: {
480 if(is_binary_bz<F>(seq)) {
481 return seq[0].is_false() || seq[1].is_true() ? F::make_true() : F::make_false();
482 }
483 else if(seq.size() == 2) {
484 if(seq[0].is_true()) { return seq[1]; }
485 else if(seq[0].is_false()) { return F::make_true(); }
486 else if(seq[1].is_true()) { return F::make_true(); }
487 else if(seq[1].is_false()) {
488 auto r = negate(seq[0]);
489 if(r.has_value()) {
490 return r.value();
491 }
492 }
493 }
494 break;
495 }
496 case EQUIV: {
497 if(is_binary_bz<F>(seq)) {
498 return (seq[0].is_true() == seq[1].is_true()) ? F::make_true() : F::make_false();
499 }
500 else if(seq.size() == 2) {
501 if(seq[0].is_true()) { return seq[1]; }
502 else if(seq[0].is_false()) { return F::make_unary(NOT, seq[1], atype); }
503 else if(seq[1].is_true()) { return seq[0]; }
504 else if(seq[1].is_false()) { return F::make_unary(NOT, seq[0], atype); }
505 }
506 break;
507 }
508 case NOT: {
509 if(seq.size() == 1 && is_bz(seq[0])) {
510 return seq[0].is_true() ? F::make_false() : F::make_true();
511 }
512 if(seq.size() == 1 && seq[0].is_unary() && seq[0].sig() == NOT) {
513 return seq[0].seq(0);
514 }
515 break;
516 }
517 case XOR: {
518 if(is_binary_bz<F>(seq)) {
519 return (seq[0].is_true() != seq[1].is_true()) ? F::make_true() : F::make_false();
520 }
521 break;
522 }
523 case ITE: {
524 if(seq.size() == 3 && is_bz(seq[0])) {
525 return seq[0].is_true() ? seq[1] : seq[2];
526 }
527 break;
528 }
529 case EQ: {
530 if(seq.size() == 2 && seq[0].is_constant() && seq[1].is_constant()) {
531 return seq[0] == seq[1] ? F::make_true() : F::make_false();
532 }
533 // We detect a common pattern for equalities: x + (-y) == 0
534 if(seq.size() == 2 && seq[0].is_binary() &&
535 seq[1].is(F::Z) && seq[1].z() == 0 &&
536 seq[0].sig() == ADD &&
537 seq[0].seq(1).is_unary() && seq[0].seq(1).sig() == NEG && seq[0].seq(1).seq(0).is_variable() &&
538 seq[0].seq(0).is_variable())
539 {
540 return F::make_binary(seq[0].seq(0), EQ, seq[0].seq(1).seq(0), atype);
541 }
542 break;
543 }
544 case NEQ: {
545 if(seq.size() == 2 && seq[0].is_constant() && seq[1].is_constant()) {
546 return seq[0] != seq[1] ? F::make_true() : F::make_false();
547 }
548 // We detect a common pattern for disequalities: x + (-y) != 0
549 if(seq.size() == 2 && seq[0].is_binary() &&
550 seq[1].is(F::Z) && seq[1].z() == 0 &&
551 seq[0].sig() == ADD &&
552 seq[0].seq(1).is_unary() && seq[0].seq(1).sig() == NEG && seq[0].seq(1).seq(0).is_variable() &&
553 seq[0].seq(0).is_variable())
554 {
555 return F::make_binary(seq[0].seq(0), NEQ, seq[0].seq(1).seq(0), atype);
556 }
557 // Detect `x + k != k2` where `k` and `k2` are constants. It should be generalized.
558 if(seq.size() == 2 && seq[0].is_binary() &&
559 is_bz(seq[1]) &&
560 seq[0].sig() == ADD &&
561 is_bz(seq[0].seq(1)))
562 {
563 return F::make_binary(seq[0].seq(0), NEQ, F::make_z(seq[1].to_z() - seq[0].seq(1).to_z()), atype);
564 }
565 // k != -x --> -k != x
566 if(seq.size() == 2 && is_bz(seq[0]) && seq[1].is_unary() && seq[1].sig() == NEG && seq[1].seq(0).is_variable()) {
567 return F::make_binary(F::make_z(-seq[0].to_z()), NEQ, seq[1].seq(0), atype);
568 }
569 // -x != k --> x != -k
570 if(seq.size() == 2 && is_bz(seq[1]) && seq[0].is_unary() && seq[0].sig() == NEG && seq[0].seq(0).is_variable()) {
571 return F::make_binary(seq[0].seq(0), NEQ, F::make_z(-seq[1].to_z()), atype);
572 }
573 break;
574 }
575 case LT: {
576 if(is_binary_z<F>(seq)) {
577 return seq[0].z() < seq[1].z() ? F::make_true() : F::make_false();
578 }
579 break;
580 }
581 case LEQ: {
582 if(is_binary_z<F>(seq)) {
583 return seq[0].z() <= seq[1].z() ? F::make_true() : F::make_false();
584 }
585 break;
586 }
587 case GT: {
588 if(is_binary_z<F>(seq)) {
589 return seq[0].z() > seq[1].z() ? F::make_true() : F::make_false();
590 }
591 break;
592 }
593 case GEQ: {
594 if(is_binary_z<F>(seq)) {
595 return seq[0].z() >= seq[1].z() ? F::make_true() : F::make_false();
596 }
597 break;
598 }
599 case MIN: {
600 if(is_binary_z<F>(seq)) {
601 return F::make_z(battery::min(seq[0].z(), seq[1].z()));
602 }
603 break;
604 }
605 case MAX: {
606 if(is_binary_z<F>(seq)) {
607 return F::make_z(battery::max(seq[0].z(), seq[1].z()));
608 }
609 break;
610 }
611 case NEG: {
612 if(seq.size() == 1 && is_bz(seq[0])) {
613 return F::make_z(-seq[0].to_z());
614 }
615 if(seq.size() == 1 && seq[0].is_unary() && seq[0].sig() == NEG) {
616 return seq[0].seq(0);
617 }
618 break;
619 }
620 case ABS: {
621 if(seq.size() == 1 && is_bz(seq[0])) {
622 return F::make_z(abs(seq[0].to_z()));
623 }
624 break;
625 }
626 case ADD: {
627 typename F::Sequence residual;
628 logic_int sum = 0;
629 for(int i = 0; i < seq.size(); ++i) {
630 if(is_bz(seq[i])) {
631 sum += seq[i].to_z();
632 }
633 else {
634 residual.push_back(seq[i]);
635 }
636 }
637 if(residual.size() == 0) {
638 return F::make_z(sum);
639 }
640 else {
641 if(sum != 0) {
642 residual.push_back(F::make_z(sum));
643 }
644 if(residual.size() == 1) {
645 return residual[0];
646 }
647 else {
648 return F::make_nary(ADD, std::move(residual), atype);
649 }
650 }
651 }
652 case MUL: {
653 typename F::Sequence residual;
654 logic_int prod = 1;
655 for(int i = 0; i < seq.size(); ++i) {
656 if(is_bz(seq[i])) {
657 prod *= seq[i].to_z();
658 }
659 else {
660 residual.push_back(seq[i]);
661 }
662 }
663 if(residual.size() == 0) {
664 return F::make_z(prod);
665 }
666 else {
667 if(prod == 0) {
668 return F::make_z(0);
669 }
670 else if(prod == -1 && residual.size() > 0) {
671 residual[0] = F::make_unary(NEG, std::move(residual[0]), atype);
672 }
673 else if(prod != 1) {
674 residual.push_back(F::make_z(prod));
675 }
676 if(residual.size() == 1) {
677 return residual[0];
678 }
679 else {
680 return F::make_nary(MUL, std::move(residual), atype);
681 }
682 }
683 }
684 case SUB: {
685 if(is_binary_bz<F>(seq)) {
686 return F::make_z(seq[0].to_z() - seq[1].to_z());
687 }
688 else if(seq.size() == 2 && is_bz(seq[1]) && seq[1].to_z() == 0) {
689 return seq[0];
690 }
691 else if(seq.size() == 2 && is_bz(seq[0]) && seq[0].to_z() == 0) {
692 return F::make_unary(NEG, seq[0], atype);
693 }
694 break;
695 }
696 case TDIV:
697 case FDIV:
698 case CDIV:
699 case EDIV: {
700 if(is_binary_z<F>(seq)) {
701 switch(sig) {
702 case TDIV: return F::make_z(battery::tdiv(seq[0].z(), seq[1].z()));
703 case FDIV: return F::make_z(battery::fdiv(seq[0].z(), seq[1].z()));
704 case CDIV: return F::make_z(battery::cdiv(seq[0].z(), seq[1].z()));
705 case EDIV: return F::make_z(battery::ediv(seq[0].z(), seq[1].z()));
706 default: assert(0); break;
707 }
708 }
709 else if(seq.size() == 2 && is_bz(seq[0]) && seq[0].to_z() == 0) {
710 return F::make_z(0);
711 }
712 else if(seq.size() == 2 && is_bz(seq[1]) && seq[1].to_z() == 1) {
713 return seq[0];
714 }
715 break;
716 }
717 case TMOD: {
718 if(is_binary_z<F>(seq)) {
719 return F::make_z(battery::tmod(seq[0].z(), seq[1].z()));
720 }
721 break;
722 }
723 case FMOD: {
724 if(is_binary_z<F>(seq)) {
725 return F::make_z(battery::fmod(seq[0].z(), seq[1].z()));
726 }
727 break;
728 }
729 case CMOD: {
730 if(is_binary_z<F>(seq)) {
731 return F::make_z(battery::cmod(seq[0].z(), seq[1].z()));
732 }
733 break;
734 }
735 case EMOD: {
736 if(is_binary_z<F>(seq)) {
737 return F::make_z(battery::emod(seq[0].z(), seq[1].z()));
738 }
739 break;
740 }
741 case POW: {
742 if(is_binary_bz<F>(seq)) {
743 return F::make_z(battery::ipow(seq[0].to_z(), seq[1].to_z()));
744 }
745 else if(seq.size() == 2 && is_bz(seq[1]) && seq[1].to_z() == 0) {
746 return F::make_z(1);
747 }
748 break;
749 }
750 case IN: {
751 if(seq.size() == 2 && is_bz(seq[0]) && seq[1].is(F::S)) {
752 const auto& set = seq[1].s();
753 logic_int left = seq[0].to_z();
754 for(int i = 0; i < set.size(); ++i) {
755 const auto& lb = battery::get<0>(set[i]);
756 const auto& ub = battery::get<1>(set[i]);
757 if(is_bz(lb) && is_bz(ub) && left >= lb.to_z() && left <= ub.to_z()) {
758 return F::make_true();
759 }
760 }
761 return F::make_false();
762 }
763 else if(seq.size() == 2 && seq[1].is(F::S) && seq[1].s().size() == 0) {
764 return F::make_false();
765 }
766 break;
767 }
768 }
769 return F::make_nary(sig, seq, atype);
770 }
771}
772
773template <class F>
774CUDA NI F eval(const F& f) {
775 switch(f.index()) {
776 case F::Z: return f;
777 case F::R: return f;
778 case F::S: return f;
779 case F::B: return f;
780 case F::V: return f;
781 case F::E: return f;
782 case F::LV: return f;
783 case F::Seq: {
784 const auto& seq = f.seq();
785 typename F::Sequence evaluated_seq;
786 for(int i = 0; i < seq.size(); ++i) {
787 evaluated_seq.push_back(eval(seq[i]));
788 }
789 return impl::eval_seq<F>(f.sig(), evaluated_seq, f.type());
790 }
791 case F::ESeq: {
792 auto eseq = f.eseq();
793 typename F::Sequence evaluated_eseq;
794 for(int i = 0; i < eseq.size(); ++i) {
795 evaluated_eseq.push_back(eval(eseq[i]));
796 }
797 return F::make_nary(f.esig(), std::move(evaluated_eseq), f.type());
798 }
799 default: assert(false); return f;
800 }
801}
802
803}
804
805#endif
Definition ast.hpp:38
Definition ast.hpp:234
CUDA Sig sig() const
Definition ast.hpp:535
CUDA const Sequence & seq() const
Definition ast.hpp:552
CUDA bool is(size_t kind) const
Definition ast.hpp:474
Definition abstract_deps.hpp:14
CUDA NI std::optional< F > negate_eq(const F &f)
Definition algorithm.hpp:250
CUDA NI bool is_v_op_constant(const TFormula< Allocator, ExtendedSig > &f, Sig sig)
Definition algorithm.hpp:12
CUDA NI void map_avar_to_lvar(F &f, const Env &env, bool erase_type=false)
Definition algorithm.hpp:398
int AType
Definition sort.hpp:18
CUDA NI std::optional< F > de_morgan_law(Sig sig_neg, const F &f)
Definition algorithm.hpp:234
CUDA NI Sig converse_comparison(Sig sig)
Definition algorithm.hpp:377
CUDA NI bool is_arithmetic_comparison(const F &f)
Definition algorithm.hpp:320
Sig
Definition ast.hpp:94
@ XOR
Logical connector.
Definition ast.hpp:114
@ ITE
If-then-else.
Definition ast.hpp:115
@ NEQ
Equality relations.
Definition ast.hpp:112
@ LEQ
Unary arithmetic function symbols.
Definition ast.hpp:113
@ NOT
Unary arithmetic function symbols.
Definition ast.hpp:114
@ IMPLY
Unary arithmetic function symbols.
Definition ast.hpp:114
@ TMOD
Truncated division, present in most programming languages, is defined as , i.e., it rounds towards ze...
Definition ast.hpp:102
@ SUPSETEQ
Set inclusion predicates.
Definition ast.hpp:107
@ OR
Unary arithmetic function symbols.
Definition ast.hpp:114
@ EQ
Unary arithmetic function symbols.
Definition ast.hpp:112
@ 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
@ POW
Unary arithmetic function symbols.
Definition ast.hpp:97
@ MIN
Unary arithmetic function symbols.
Definition ast.hpp:97
@ EDIV
Unary arithmetic function symbols.
Definition ast.hpp:105
@ 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
@ 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
@ SUBSETEQ
Unary arithmetic function symbols.
Definition ast.hpp:107
@ AND
Unary arithmetic function symbols.
Definition ast.hpp:114
@ SUBSET
Unary arithmetic function symbols.
Definition ast.hpp:107
@ EQUIV
Unary arithmetic function symbols.
Definition ast.hpp:114
@ ABS
Unary arithmetic function symbols.
Definition ast.hpp:96
@ SUB
Unary arithmetic function symbols.
Definition ast.hpp:97
@ SUPSET
Unary arithmetic function symbols.
Definition ast.hpp:107
@ MUL
Unary arithmetic function symbols.
Definition ast.hpp:97
@ CMOD
Ceil division is defined as . Modulus is defined as .
Definition ast.hpp:104
@ 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
CUDA NI std::optional< F > negate(const F &f)
Definition algorithm.hpp:266
long long int logic_int
Definition sort.hpp:114
CUDA NI bool is_var_equality(const TFormula< Allocator, ExtendedSig > &f)
Definition algorithm.hpp:32
CUDA NI TFormula< Allocator > make_v_op_z(LVar< Allocator > v, Sig sig, logic_int z, AType aty=UNTYPED, const Allocator &allocator=Allocator())
Definition algorithm.hpp:41
CUDA int num_quantified_vars(const F &f)
Definition algorithm.hpp:168
CUDA NI battery::tuple< F, F > extract_ty(const F &f, AType ty)
Definition algorithm.hpp:197
CUDA NI bool is_v_op_z(const TFormula< Allocator, ExtendedSig > &f, Sig sig)
Definition algorithm.hpp:22
battery::string< Allocator > LVar
Definition ast.hpp:25
CUDA NI AType type_of_conjunction(const typename F::Sequence &seq)
Definition algorithm.hpp:179
CUDA Sig leq_of_constant(const TFormula< Allocator > &f)
Definition algorithm.hpp:60
CUDA NI bool is_comparison(const F &f)
Definition algorithm.hpp:356
CUDA Sig geq_of_constant(const TFormula< Allocator > &f)
Definition algorithm.hpp:53
CUDA NI int num_vars(const F &f)
Definition algorithm.hpp:153
CUDA Sig negate_arithmetic_comparison(Sig sig)
Definition algorithm.hpp:306
CUDA const TFormula< Allocator, ExtendedSig > & var_in(const TFormula< Allocator, ExtendedSig > &f)
Definition algorithm.hpp:145
CUDA NI F eval(const F &f)
Definition algorithm.hpp:774
CUDA NI bool is_set_comparison(const F &f)
Definition algorithm.hpp:338
#define UNTYPED
Definition sort.hpp:21