3#ifndef LALA_CORE_ALGORITHM_HPP
4#define LALA_CORE_ALGORITHM_HPP
11template<
class Allocator,
class ExtendedSig>
16 && (f.
seq(0).is(F::LV) || f.
seq(0).is(F::V))
17 && f.
seq(1).is_constant();
21template<
class Allocator,
class ExtendedSig>
26 && (f.
seq(0).is(F::LV) || f.
seq(0).is(F::V))
31template<
class Allocator,
class ExtendedSig>
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));
40template<
class Allocator>
43 return F::make_binary(F::make_lvar(
UNTYPED, std::move(v)), sig, F::make_z(z), aty, allocator);
46template<
class Allocator>
49 return F::make_binary(F::make_avar(v), sig, F::make_z(z), aty, allocator);
52template <
class Allocator>
55 assert(f.
is(F::S) || f.
is(F::Z) || f.
is(F::R));
59template <
class Allocator>
62 assert(f.
is(F::S) || f.
is(F::Z) || f.
is(F::R));
67 template<
class Allocator,
class ExtendedSig>
68 CUDA NI
const TFormula<Allocator, ExtendedSig>& var_in_impl(
const TFormula<Allocator, ExtendedSig>& f,
bool& found);
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);
82 template<
class Allocator,
class ExtendedSig>
83 CUDA NI
const TFormula<Allocator, ExtendedSig>& var_in_impl(
const TFormula<Allocator, ExtendedSig>& f,
bool& found)
85 using F = TFormula<Allocator, ExtendedSig>;
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;
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()));
106 for(
int i = 0; i < children.size(); ++i) {
113 CUDA NI
int num_qf_vars(
const F& f,
bool type_filter,
AType aty);
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()));
119 for(
int i = 0; i < children.size(); ++i) {
120 total += num_qf_vars(children[i], type_filter, aty);
126 CUDA NI
int num_qf_vars(
const F& f,
bool type_filter,
AType aty) {
130 return f.type() == aty ? 1 : 0;
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);
144template<
typename Allocator,
typename ExtendedSig>
147 return impl::var_in_impl(f, found);
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);
169 return impl::num_qf_vars(f,
false,
UNTYPED);
175 return impl::num_qf_vars(f,
true, aty);
181 for(
int i = 0; i < seq.size(); ++i) {
188 else if(ty != seq[i].type()) {
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) {
204 if(seq[i].is(F::Seq) && seq[i].sig() ==
AND) {
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]));
211 for(
int i = 0; i < other_.size(); ++i) {
212 other.push_back(std::move(other_[i]));
215 else if(seq[i].type() == ty) {
216 fty.push_back(seq[i]);
219 other.push_back(seq[i]);
223 return battery::make_tuple(
224 F::make_nary(
AND, std::move(fty), ty),
225 F::make_nary(
AND, std::move(other), other_ty));
229CUDA NI std::optional<F>
negate(
const F& f);
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()) {
246 return F::make_nary(sig_neg, neg_seq, f.type());
251 assert(f.is_binary() && f.sig() ==
EQ);
252 if(f.seq(0).is(F::B)) {
255 return F::make_binary(b,
EQ, f.seq(1), f.type(), f.seq().get_allocator());
257 else if(f.seq(1).is(F::B)) {
260 return F::make_binary(f.seq(0),
EQ, b, f.type(), f.seq().get_allocator());
262 return F::make_nary(
NEQ, f.seq(), f.type());
266CUDA NI std::optional<F>
negate(
const F& f) {
268 return F::make_false();
270 else if(f.is_false()) {
271 return F::make_true();
273 else if(f.is_variable()) {
274 return F::make_unary(
NOT, f, f.type());
276 else if(f.is(F::Seq)) {
279 case NOT:
return f.seq(0);
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;
293 return F::make_unary(
NOT, f, f.type());
301 return F::make_nary(neg_sig, f.seq(), f.type());
314 default: assert(0);
return sig;
384 case NEQ:
return sig;
397template <
class F,
class Env>
401 f = F::make_lvar(erase_type ?
UNTYPED : f.v().aty(), env.name_of(f.v()));
404 for(
int i = 0; i < f.seq().size(); ++i) {
409 for(
int i = 0; i < f.eseq().size(); ++i) {
419 CUDA
bool is_bz(
const F& f) {
420 return f.is(F::Z) || f.is(F::B);
424 CUDA
bool is_binary_bz(
const typename F::Sequence& seq) {
425 return seq.size() == 2 && is_bz(seq[0]) && is_bz(seq[1]);
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);
437 CUDA F eval_seq(
Sig sig,
const typename F::Sequence& seq,
AType atype) {
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();
445 else if(!seq[i].is_true()) {
446 residual.push_back(seq[i]);
449 if(residual.size() == 0) {
450 return F::make_true();
452 else if(residual.size() == 1) {
456 return F::make_nary(
AND, std::move(residual), atype);
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();
465 else if(!seq[i].is_false()) {
466 residual.push_back(seq[i]);
469 if(residual.size() == 0) {
470 return F::make_false();
472 else if(residual.size() == 1) {
476 return F::make_nary(
OR, std::move(residual), atype);
480 if(is_binary_bz<F>(seq)) {
481 return seq[0].is_false() || seq[1].is_true() ? F::make_true() : F::make_false();
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()) {
497 if(is_binary_bz<F>(seq)) {
498 return (seq[0].is_true() == seq[1].is_true()) ? F::make_true() : F::make_false();
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); }
509 if(seq.size() == 1 && is_bz(seq[0])) {
510 return seq[0].is_true() ? F::make_false() : F::make_true();
512 if(seq.size() == 1 && seq[0].is_unary() && seq[0].sig() ==
NOT) {
513 return seq[0].seq(0);
518 if(is_binary_bz<F>(seq)) {
519 return (seq[0].is_true() != seq[1].is_true()) ? F::make_true() : F::make_false();
524 if(seq.size() == 3 && is_bz(seq[0])) {
525 return seq[0].is_true() ? seq[1] : seq[2];
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();
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())
540 return F::make_binary(seq[0].seq(0),
EQ, seq[0].seq(1).seq(0), atype);
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();
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())
555 return F::make_binary(seq[0].seq(0),
NEQ, seq[0].seq(1).seq(0), atype);
558 if(seq.size() == 2 && seq[0].is_binary() &&
560 seq[0].sig() ==
ADD &&
561 is_bz(seq[0].seq(1)))
563 return F::make_binary(seq[0].seq(0),
NEQ, F::make_z(seq[1].to_z() - seq[0].seq(1).to_z()), atype);
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);
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);
576 if(is_binary_z<F>(seq)) {
577 return seq[0].z() < seq[1].z() ? F::make_true() : F::make_false();
582 if(is_binary_z<F>(seq)) {
583 return seq[0].z() <= seq[1].z() ? F::make_true() : F::make_false();
588 if(is_binary_z<F>(seq)) {
589 return seq[0].z() > seq[1].z() ? F::make_true() : F::make_false();
594 if(is_binary_z<F>(seq)) {
595 return seq[0].z() >= seq[1].z() ? F::make_true() : F::make_false();
600 if(is_binary_z<F>(seq)) {
601 return F::make_z(battery::min(seq[0].z(), seq[1].z()));
606 if(is_binary_z<F>(seq)) {
607 return F::make_z(battery::max(seq[0].z(), seq[1].z()));
612 if(seq.size() == 1 && is_bz(seq[0])) {
613 return F::make_z(-seq[0].to_z());
615 if(seq.size() == 1 && seq[0].is_unary() && seq[0].sig() ==
NEG) {
616 return seq[0].seq(0);
621 if(seq.size() == 1 && is_bz(seq[0])) {
622 return F::make_z(abs(seq[0].to_z()));
627 typename F::Sequence residual;
629 for(
int i = 0; i < seq.size(); ++i) {
631 sum += seq[i].to_z();
634 residual.push_back(seq[i]);
637 if(residual.size() == 0) {
638 return F::make_z(sum);
642 residual.push_back(F::make_z(sum));
644 if(residual.size() == 1) {
648 return F::make_nary(
ADD, std::move(residual), atype);
653 typename F::Sequence residual;
655 for(
int i = 0; i < seq.size(); ++i) {
657 prod *= seq[i].to_z();
660 residual.push_back(seq[i]);
663 if(residual.size() == 0) {
664 return F::make_z(prod);
670 else if(prod == -1 && residual.size() > 0) {
671 residual[0] = F::make_unary(
NEG, std::move(residual[0]), atype);
674 residual.push_back(F::make_z(prod));
676 if(residual.size() == 1) {
680 return F::make_nary(
MUL, std::move(residual), atype);
685 if(is_binary_bz<F>(seq)) {
686 return F::make_z(seq[0].to_z() - seq[1].to_z());
688 else if(seq.size() == 2 && is_bz(seq[1]) && seq[1].to_z() == 0) {
691 else if(seq.size() == 2 && is_bz(seq[0]) && seq[0].to_z() == 0) {
692 return F::make_unary(
NEG, seq[0], atype);
700 if(is_binary_z<F>(seq)) {
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;
709 else if(seq.size() == 2 && is_bz(seq[0]) && seq[0].to_z() == 0) {
712 else if(seq.size() == 2 && is_bz(seq[1]) && seq[1].to_z() == 1) {
718 if(is_binary_z<F>(seq)) {
719 return F::make_z(battery::tmod(seq[0].z(), seq[1].z()));
724 if(is_binary_z<F>(seq)) {
725 return F::make_z(battery::fmod(seq[0].z(), seq[1].z()));
730 if(is_binary_z<F>(seq)) {
731 return F::make_z(battery::cmod(seq[0].z(), seq[1].z()));
736 if(is_binary_z<F>(seq)) {
737 return F::make_z(battery::emod(seq[0].z(), seq[1].z()));
742 if(is_binary_bz<F>(seq)) {
743 return F::make_z(battery::ipow(seq[0].to_z(), seq[1].to_z()));
745 else if(seq.size() == 2 && is_bz(seq[1]) && seq[1].to_z() == 0) {
751 if(seq.size() == 2 && is_bz(seq[0]) && seq[1].is(F::S)) {
752 const auto& set = seq[1].s();
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();
761 return F::make_false();
763 else if(seq.size() == 2 && seq[1].is(F::S) && seq[1].s().size() == 0) {
764 return F::make_false();
769 return F::make_nary(sig, seq, atype);
782 case F::LV:
return f;
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]));
789 return impl::eval_seq<F>(f.sig(), evaluated_seq, f.type());
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]));
797 return F::make_nary(f.esig(), std::move(evaluated_eseq), f.type());
799 default: assert(
false);
return f;
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
@ 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