Lattice Land Core Library
nbitset.hpp
Go to the documentation of this file.
1 // Copyright 2024 Pierre Talbot
2 
3 #ifndef LALA_CORE_NBITSET_HPP
4 #define LALA_CORE_NBITSET_HPP
5 
6 #include "arith_bound.hpp"
7 #include "battery/bitset.hpp"
8 
9 namespace lala {
10 
11 /** This class represents a set of integer values with a fixed-size bitset.
12  * In order to have well-defined arithmetic operations preserving bottom and top elements, the first and last bits (written L and R below) of the bitset are reserved.
13  * The meaning of L is to include all negative integers and the meaning of R is to include all integers greater than the size of the bitset.
14  * Given a bitset \f$ Lb_0b_1...b_nR \f$ of size n + 3, the concretization function is given as follows:
15  * \f$ \gamma(Lb_0b_1...b_nR) = \{ i \in \mathbb{Z} \mid 0 \leq i \leq n \land b_i = 1 \} \cup \{ i \in \mathbb{Z} \;|\; i < 0 \land L = 1 \} \cup \{ i \in \mathbb{Z} \;|\; i > n \land R = 1 \} \f$
16  */
17 template <size_t N, class Mem, class T = unsigned long long>
18 class NBitset
19 {
20 public:
21  using memory_type = Mem;
22  using bitset_type = battery::bitset<N, Mem, T>;
24  template <class M> using this_type2 = NBitset<N, M, T>;
26 
27  using LB = local::ZLB;
28  using UB = local::ZUB;
29  using value_type = typename LB::value_type;
30 
31  template <size_t N2, class Mem2, class T2>
32  friend class NBitset;
33 
34  constexpr static const bool is_abstract_universe = true;
35  constexpr static const bool sequential = Mem::sequential;
36  constexpr static const bool is_totally_ordered = false;
37  constexpr static const bool preserve_bot = true;
38  constexpr static const bool preserve_top = true;
39  constexpr static const bool preserve_join = true;
40  constexpr static const bool preserve_meet = true;
41  constexpr static const bool injective_concretization = true;
42  constexpr static const bool preserve_concrete_covers = false;
43  constexpr static const bool complemented = true;
44  constexpr static const bool is_arithmetic = true;
45  constexpr static const char* name = "NBitset";
46 
47 private:
48  bitset_type bits;
49 
50  struct bot_constructor_tag {};
51  CUDA constexpr NBitset(bot_constructor_tag) {}
52 
53 public:
54  /** Initialize to top (all bits at `1`). */
55  CUDA constexpr NBitset() {
56  bits.set();
57  }
58 
59  CUDA constexpr static this_type from_set(const battery::vector<int>& values) {
60  this_type b(bot());
61  for(int i = 0; i < values.size(); ++i) {
62  b.bits.set(battery::min(static_cast<int>(N)-1, battery::max(values[i]+1,0)), true);
63  }
64  return b;
65  }
66 
67  CUDA constexpr NBitset(const this_type& other): NBitset(other.bits) {}
68  constexpr NBitset(this_type&&) = default;
69 
70  /** Given a value \f$ x \in U \f$ where \f$ U \f$ is the universe of discourse, we initialize a singleton bitset \f$ 0_0..1_{x+1}...0_n \f$. */
71  CUDA constexpr NBitset(value_type x) {
72  bits.set(battery::min(static_cast<int>(N)-1, battery::max(0, x+1)));
73  }
74 
75  CUDA constexpr NBitset(value_type lb, value_type ub): bits(
76  battery::min(static_cast<int>(N)-1, battery::max(lb+1,0)),
77  battery::min(static_cast<int>(N)-1, battery::max(ub+1, 0)))
78  {}
79 
80  template<class M>
81  CUDA constexpr NBitset(const this_type2<M>& other): bits(other.bits) {}
82 
83  template<class M>
84  CUDA constexpr NBitset(this_type2<M>&& other): bits(std::move(other.bits)) {}
85 
86  template<class M>
87  CUDA constexpr NBitset(const battery::bitset<N, M, T>& bits): bits(bits) {}
88 
89  /** The assignment operator can only be used in a sequential context.
90  * It is monotone but not extensive. */
91  template <class M>
92  CUDA constexpr this_type& operator=(const this_type2<M>& other) {
93  bits = other.bits;
94  return *this;
95  }
96 
97  CUDA constexpr this_type& operator=(const this_type& other) {
98  bits = other.bits;
99  return *this;
100  }
101 
102  /** Pre-interpreted formula `x == 0`. */
103  CUDA constexpr static local_type eq_zero() { return local_type(0); }
104  /** Pre-interpreted formula `x == 1`. */
105  CUDA constexpr static local_type eq_one() { return local_type(1); }
106 
107  CUDA constexpr static local_type bot() { return NBitset(bot_constructor_tag{}); }
108  CUDA constexpr static local_type top() { return NBitset(); }
109  CUDA constexpr local::B is_top() const { return bits.all(); }
110  CUDA constexpr local::B is_bot() const { return bits.none(); }
111  CUDA constexpr const bitset_type& value() const { return bits; }
112 
113 private:
114  template<bool diagnose, class F, class Env, class M>
115  CUDA NI static bool interpret_existential(const F& f, const Env& env, this_type2<M>& k, IDiagnostics& diagnostics) {
116  const auto& sort = battery::get<1>(f.exists());
117  if(sort.is_int()) {
118  return true;
119  }
120  else if(sort.is_bool()) {
121  k.meet(local_type(0,1));
122  return true;
123  }
124  else {
125  const auto& vname = battery::get<0>(f.exists());
126  RETURN_INTERPRETATION_ERROR(("NBitset only supports variables of type `Int` or `Bool`, but `" + vname + "` has another sort."));
127  }
128  }
129 
130  template<bool diagnose, bool negated, class F, class M>
131  CUDA NI static bool interpret_tell_set(const F& f, const F& k, this_type2<M>& tell, IDiagnostics& diagnostics) {
132  using sort_type = Sort<typename F::allocator_type>;
133  std::optional<sort_type> sort = f.seq(1).sort();
134  if(sort.has_value() &&
135  (sort.value() == sort_type(sort_type::Set, sort_type(sort_type::Int))
136  || sort.value() == sort_type(sort_type::Set, sort_type(sort_type::Bool))))
137  {
138  const auto& set = f.seq(1).s();
139  local_type join_s(bot_constructor_tag{});
140  bool over_appx = false;
141  for(int i = 0; i < set.size(); ++i) {
142  int l = battery::get<0>(set[i]).to_z();
143  int u = battery::get<1>(set[i]).to_z();
144  join_s.join(local_type(l, u));
145  if(l < 0 || u >= join_s.bits.size() - 2) {
146  over_appx = true;
147  }
148  }
149  if constexpr(negated) {
150  join_s = join_s.complement();
151  // In any case it must be set to true: if no element is below zero, then some elements in the negation are; and if some elements are below zero it's not all of them.
152  join_s.bits.set(0, true);
153  join_s.bits.set(join_s.bits.size()-1, true);
154  }
155  tell.meet(join_s);
156  if(over_appx) {
157  RETURN_INTERPRETATION_WARNING("Constraint `x in S` is over-approximated because some elements of `S` fall outside the bitset.");
158  }
159  return true;
160  }
161  else {
162  RETURN_INTERPRETATION_ERROR("NBitset only supports membership (`x in S`) where `S` is a set of integers.");
163  }
164  }
165 
166  template<bool diagnose, class F, class M>
167  CUDA NI static bool interpret_tell_x_op_k(const F& f, logic_int k, Sig sig, this_type2<M>& tell, IDiagnostics& diagnostics) {
168  if(sig == LT) {
169  return interpret_tell_x_op_k<diagnose>(f, k-1, LEQ, tell, diagnostics);
170  }
171  else if(sig == GT) {
172  return interpret_tell_x_op_k<diagnose>(f, k+1, GEQ, tell, diagnostics);
173  }
174  else if(k < 0 || k >= tell.bits.size() - 2) {
175  if((k == -1 && sig == LEQ) || (k == tell.bits.size() - 2 && sig == GEQ)) {
176  // this is fine because x <= -1 and x >= n-2 can be represented exactly.
177  }
178  else {
179  INTERPRETATION_WARNING("Constraint `x <op> k` is over-approximated because `k` is not representable in the bitset. Note that for a bitset of size `n`, the only values representable exactly are in the interval `[0, n-3]` because two bits are used to represent all negative values and all values exceeding the size of the bitset.");
180  // If it is NEQ, we can't give a better approximation than top.
181  if(sig == NEQ) {
182  return true;
183  }
184  }
185  }
186  switch(sig) {
187  case EQ: tell.meet(local_type(k, k)); break;
188  case NEQ: tell.meet(local_type(k, k).complement()); break;
189  case LEQ: tell.meet(local_type(-1, k)); break;
190  case GEQ: tell.meet(local_type(k, tell.bits.size())); break;
191  default: RETURN_INTERPRETATION_ERROR("This symbol is not supported.");
192  }
193  return true;
194  }
195 
196  template<bool diagnose, bool negated, class F, class Env, class M>
197  CUDA NI static bool interpret_binary(const F& f, const Env& env, this_type2<M>& tell, IDiagnostics& diagnostics) {
198  if(f.sig() == IN) {
199  return interpret_tell_set<diagnose, negated>(f, f.seq(1), tell, diagnostics);
200  }
201  else if(f.seq(1).is(F::Z) || f.seq(1).is(F::B)) {
202  return interpret_tell_x_op_k<diagnose>(f, f.seq(1).to_z(), f.sig(), tell, diagnostics);
203  }
204  else {
205  RETURN_INTERPRETATION_ERROR("Only integer and Boolean constants are supported in NBitset.");
206  }
207  }
208 
209 public:
210  /** Support the following language where all constants `k` are integer or Boolean values:
211  * * `var x:Z`
212  * * `var x:B`
213  * * `x <op> k` where `k` is an integer constant and `<op>` in {==, !=, <, <=, >, >=}.
214  * * `x in S` where `S` is a set of integers.
215  * It can be over-approximated if the element `k` falls out of the bitset. */
216  template<bool diagnose = false, class F, class Env, class M>
217  CUDA NI static bool interpret_tell(const F& f, const Env& env, this_type2<M>& tell, IDiagnostics& diagnostics) {
218  using sort_type = Sort<typename F::allocator_type>;
219  if(f.is(F::E)) {
220  return interpret_existential<diagnose>(f, env, tell, diagnostics);
221  }
222  else if(f.is_unary() && f.sig() == NOT && f.seq(0).is_binary()) {
223  return interpret_binary<diagnose, true>(f.seq(0), env, tell, diagnostics);
224  }
225  else if(f.is_binary() && f.seq(0).is_variable() && f.seq(1).is_constant()) {
226  return interpret_binary<diagnose, false>(f, env, tell, diagnostics);
227  }
228  else {
229  RETURN_INTERPRETATION_ERROR("Only binary formulas of the form `x <sig> k` where if x is a variable and k is a constant are supported. We also supports existential quantifier and membership in a set of integers (x in S).");
230  }
231  }
232 
233  /** Support the same language than the "tell language" without existential. */
234  template<bool diagnose = false, class F, class Env, class M>
235  CUDA NI static bool interpret_ask(const F& f, const Env& env, this_type2<M>& k, IDiagnostics& diagnostics) {
237  auto nf = negate(f);
238  if(!nf.has_value()) {
239  RETURN_INTERPRETATION_ERROR("Could not negate the formula in order to interpret_ask it.");
240  }
241  if(f.is(F::E)) {
242  RETURN_INTERPRETATION_ERROR("Existential quantification is not supported in ask interpretation.");
243  }
244  if(interpret_tell<diagnose>(nf.value(), env, b, diagnostics)) {
245  k.meet(b.complement());
246  return true;
247  }
248  else {
249  return false;
250  }
251  }
252 
253  template<IKind kind, bool diagnose = false, class F, class Env, class M>
254  CUDA NI static bool interpret(const F& f, const Env& env, this_type2<M>& k, IDiagnostics& diagnostics) {
255  if constexpr(kind == IKind::ASK) {
256  return interpret_ask<diagnose>(f, env, k, diagnostics);
257  }
258  else {
259  return interpret_tell<diagnose>(f, env, k, diagnostics);
260  }
261  }
262 
263  CUDA constexpr LB lb() const {
264  value_type l = bits.countr_zero();
265  return l == 0 ? LB::top() :
266  (l == bits.size() ? LB::bot() : LB::geq_k(l-1));
267  }
268 
269  CUDA constexpr UB ub() const {
270  value_type r = bits.countl_zero();
271  return r == 0 ? UB::top() :
272  (r == bits.size() ? UB::bot() : UB::leq_k(bits.size() - r - 2));
273  }
274 
275  CUDA constexpr local_type complement() const {
276  local_type c(bits);
277  c.bits.flip();
278  return c;
279  }
280 
281  CUDA constexpr void join_top() {
282  bits.set();
283  }
284 
285  template<class A>
286  CUDA constexpr bool join_lb(const A& lb) {
287  return join(local_type(lb.value(), bits.size()));
288  }
289 
290  template<class A>
291  CUDA constexpr bool join_ub(const A& ub) {
292  return join(local_type(-1, ub.value()));
293  }
294 
295  template<class M>
296  CUDA constexpr bool join(const this_type2<M>& other) {
297  if(!other.bits.is_subset_of(bits)) {
298  bits |= other.bits;
299  return true;
300  }
301  return false;
302  }
303 
304  CUDA constexpr void meet_bot() {
305  bits.reset();
306  }
307 
308  template<class A>
309  CUDA constexpr bool meet_lb(const A& lb) {
310  return meet(local_type(lb.value(), bits.size()));
311  }
312 
313  template<class A>
314  CUDA constexpr bool meet_ub(const A& ub) {
315  return meet(local_type(-1, ub.value()));
316  }
317 
318  template<class M>
319  CUDA constexpr bool meet(const this_type2<M>& other) {
320  if(!bits.is_subset_of(other.bits)) {
321  bits &= other.bits;
322  return true;
323  }
324  return false;
325  }
326 
327  template <class M>
328  CUDA constexpr bool extract(this_type2<M>& ua) const {
329  ua.bits = bits;
330  return true;
331  }
332 
333  template<class Env, class Allocator = typename Env::allocator_type>
334  CUDA TFormula<Allocator> deinterpret(AVar x, const Env& env, const Allocator& allocator = Allocator()) const {
335  using F = TFormula<Allocator>;
336  if(is_bot()) {
337  return F::make_false();
338  }
339  else if(is_top()) {
340  return F::make_true();
341  }
342  else {
343  typename F::Sequence seq{allocator};
344  if(bits.test(0)) {
345  seq.push_back(F::make_binary(F::make_avar(x), LEQ, F::make_z(-1), UNTYPED, allocator));
346  }
347  if(bits.test(bits.size()-1)) {
348  seq.push_back(F::make_binary(F::make_avar(x), GEQ, F::make_z(bits.size()-2), UNTYPED, allocator));
349  }
350  logic_set<F> logical_set(allocator);
351  for(int i = 1; i < bits.size()-1; ++i) {
352  if(bits.test(i)) {
353  int l = i - 1;
354  for(i = i + 1; i < bits.size()-1 && bits.test(i); ++i) {}
355  int u = i - 2;
356  logical_set.push_back(battery::make_tuple(F::make_z(l), F::make_z(u)));
357  }
358  }
359  if(logical_set.size() > 0) {
360  seq.push_back(F::make_binary(F::make_avar(x), IN, F::make_set(std::move(logical_set)), UNTYPED, allocator));
361  }
362  if(seq.size() == 1) {
363  return std::move(seq[0]);
364  }
365  else {
366  return F::make_nary(OR, std::move(seq));
367  }
368  }
369  }
370 
371  /** Deinterpret the current value to a logical constant.
372  * The lower bound is deinterpreted, and it is up to the user to check that interval is a singleton.
373  */
374  template<class F>
375  CUDA NI F deinterpret() const {
376  return lb().template deinterpret<F>();
377  }
378 
379  CUDA NI void print() const {
380  printf("{");
381  bool comma_needed = false;
382  if(bits.test(0)) {
383  printf(".., -1");
384  comma_needed = true;
385  }
386  for(int i = 1; i < bits.size() - 1; ++i) {
387  if(bits.test(i)) {
388  if(comma_needed) { printf(", "); }
389  printf("%d", i-1);
390  comma_needed = true;
391  }
392  }
393  if(bits.test(bits.size()-1)) {
394  if(comma_needed) { printf(", "); }
395  printf("%d, ..", static_cast<int>(bits.size())-2);
396  }
397  printf("}");
398  }
399 
400  CUDA NI constexpr static bool is_trivial_fun(Sig sig) {
401  switch(sig) {
402  case ABS:
403  case NEG: return false;
404  default: return true;
405  }
406  }
407 
408 public:
409  CUDA constexpr void neg(const local_type& x) {
410  // if `x` represents all negative numbers, then the negation is all positive numbers.
411  if(x.bits.test(0)) {
412  if(x.bits.count() == 1) {
413  bits.set(0, false);
414  }
415  }
416  else if(x.bits.count() == 0) {
417  meet_bot();
418  }
419  else {
420  meet(local_type(-1));
421  }
422  }
423 
424  CUDA constexpr void abs(const local_type& x) {
425  // If the first bit is set, it means all negative numbers are represented, so it only constrains the current value to be positive. Otherwise, we just take the meet with `x`.
426  if(x.bits.test(0)) {
427  bits.set(0, false);
428  }
429  else {
430  meet(x);
431  }
432  }
433 
434  CUDA constexpr void project(Sig fun, const local_type& x) {
435  switch(fun) {
436  case NEG: neg(x); break;
437  case ABS: abs(x); break;
438  }
439  }
440 
441  CUDA constexpr void additive_inverse(const local_type& x) {
442  printf("%% additive_inverse is unsupported\n");
443  int* ptr = nullptr;
444  ptr[1] = 193;
445  }
446 
447  CUDA constexpr void project(Sig fun, const local_type& x, const local_type& y) {
448  printf("%% binary functions %s are unsupported\n", string_of_sig(fun));
449  int* ptr = nullptr;
450  ptr[1] = 193;
451  }
452 
453  CUDA constexpr local_type width() const {
454  if(bits.test(0) || bits.test(bits.size() - 1)) { return top(); }
455  else { return local_type(bits.count()); }
456  }
457 
458  /** \return The median value of the bitset. */
459  CUDA constexpr local_type median() const {
460  if(is_bot()) { return local_type::bot(); }
461  int total = bits.count();
462  int current = 0;
463  for(int i = 0; i < bits.size(); ++i) {
464  if(bits.test(i)) {
465  ++current;
466  if(current == total/2 || total == 1) {
467  return local_type(i-1);
468  }
469  }
470  }
471  return local_type::bot();
472  }
473 };
474 
475 // Lattice operations
476 
477 template<size_t N, class M1, class M2, class T>
479 {
481 }
482 
483 template<size_t N, class M1, class M2, class T>
485 {
487 }
488 
489 template<size_t N, class M1, class M2, class T>
490 CUDA constexpr bool operator<=(const NBitset<N, M1, T>& a, const NBitset<N, M2, T>& b)
491 {
492  return a.value().is_subset_of(b.value());
493 }
494 
495 template<size_t N, class M1, class M2, class T>
496 CUDA constexpr bool operator<(const NBitset<N, M1, T>& a, const NBitset<N, M2, T>& b)
497 {
498  return a.value().is_proper_subset_of(b.value());
499 }
500 
501 template<size_t N, class M1, class M2, class T>
502 CUDA constexpr bool operator>=(const NBitset<N, M1, T>& a, const NBitset<N, M2, T>& b)
503 {
504  return b <= a;
505 }
506 
507 template<size_t N, class M1, class M2, class T>
508 CUDA constexpr bool operator>(const NBitset<N, M1, T>& a, const NBitset<N, M2, T>& b)
509 {
510  return b < a;
511 }
512 
513 template<size_t N, class M1, class M2, class T>
514 CUDA constexpr bool operator==(const NBitset<N, M1, T>& a, const NBitset<N, M2, T>& b)
515 {
516  return a.value() == b.value();
517 }
518 
519 template<size_t N, class M1, class M2, class T>
520 CUDA constexpr bool operator!=(const NBitset<N, M1, T>& a, const NBitset<N, M2, T>& b)
521 {
522  return a.value() != b.value();
523 }
524 
525 template<size_t N, class M, class T>
526 std::ostream& operator<<(std::ostream &s, const NBitset<N, M, T> &a) {
527  s << "{";
528  bool comma_needed = false;
529  if(a.value().test(0)) {
530  s << ".., -1";
531  comma_needed = true;
532  }
533  for(int i = 1; i < a.value().size() - 1; ++i) {
534  if(a.value().test(i)) {
535  if(comma_needed) { s << ", "; }
536  s << (i-1);
537  comma_needed = true;
538  }
539  }
540  if(a.value().test(a.value().size()-1)) {
541  if(comma_needed) { s << ", "; }
542  s << a.value().size()-2 << ", ..";
543  }
544  s << "}";
545  return s;
546 }
547 
548 } // end namespace lala
549 
550 #endif
Definition: ast.hpp:38
Definition: arith_bound.hpp:118
static constexpr CUDA local_type top()
Definition: arith_bound.hpp:185
static constexpr CUDA this_type geq_k(value_type k)
Definition: arith_bound.hpp:156
static constexpr CUDA this_type leq_k(value_type k)
Definition: arith_bound.hpp:166
constexpr CUDA value_type value() const
Definition: arith_bound.hpp:206
static constexpr CUDA local_type bot()
Definition: arith_bound.hpp:182
typename pre_universe::value_type value_type
Definition: arith_bound.hpp:122
Definition: b.hpp:10
Definition: diagnostics.hpp:19
Definition: nbitset.hpp:19
CUDA static NI bool interpret(const F &f, const Env &env, this_type2< M > &k, IDiagnostics &diagnostics)
Definition: nbitset.hpp:254
constexpr static const bool injective_concretization
Definition: nbitset.hpp:41
constexpr static CUDA this_type from_set(const battery::vector< int > &values)
Definition: nbitset.hpp:59
constexpr CUDA LB lb() const
Definition: nbitset.hpp:263
constexpr static const bool preserve_join
Definition: nbitset.hpp:39
constexpr CUDA bool join(const this_type2< M > &other)
Definition: nbitset.hpp:296
battery::bitset< N, Mem, T > bitset_type
Definition: nbitset.hpp:22
constexpr static const char * name
Definition: nbitset.hpp:45
CUDA static NI bool interpret_tell(const F &f, const Env &env, this_type2< M > &tell, IDiagnostics &diagnostics)
Definition: nbitset.hpp:217
constexpr CUDA NBitset(value_type lb, value_type ub)
Definition: nbitset.hpp:75
friend class NBitset
Definition: nbitset.hpp:32
constexpr CUDA bool meet(const this_type2< M > &other)
Definition: nbitset.hpp:319
constexpr CUDA NBitset(this_type2< M > &&other)
Definition: nbitset.hpp:84
constexpr CUDA void additive_inverse(const local_type &x)
Definition: nbitset.hpp:441
constexpr CUDA NBitset(value_type x)
Definition: nbitset.hpp:71
constexpr static CUDA local_type bot()
Definition: nbitset.hpp:107
constexpr static const bool sequential
Definition: nbitset.hpp:35
constexpr CUDA NBitset()
Definition: nbitset.hpp:55
constexpr CUDA local_type median() const
Definition: nbitset.hpp:459
constexpr CUDA local_type complement() const
Definition: nbitset.hpp:275
constexpr CUDA bool join_lb(const A &lb)
Definition: nbitset.hpp:286
constexpr CUDA const bitset_type & value() const
Definition: nbitset.hpp:111
constexpr static CUDA local_type eq_zero()
Definition: nbitset.hpp:103
constexpr CUDA void abs(const local_type &x)
Definition: nbitset.hpp:424
constexpr CUDA NBitset(const this_type &other)
Definition: nbitset.hpp:67
constexpr CUDA UB ub() const
Definition: nbitset.hpp:269
constexpr static CUDA local_type top()
Definition: nbitset.hpp:108
constexpr static CUDA local_type eq_one()
Definition: nbitset.hpp:105
constexpr static const bool preserve_meet
Definition: nbitset.hpp:40
constexpr static const bool is_totally_ordered
Definition: nbitset.hpp:36
constexpr CUDA bool join_ub(const A &ub)
Definition: nbitset.hpp:291
constexpr NBitset(this_type &&)=default
constexpr CUDA void project(Sig fun, const local_type &x)
Definition: nbitset.hpp:434
constexpr static const bool preserve_bot
Definition: nbitset.hpp:37
CUDA NI void print() const
Definition: nbitset.hpp:379
CUDA NI F deinterpret() const
Definition: nbitset.hpp:375
constexpr static const bool preserve_top
Definition: nbitset.hpp:38
CUDA static NI bool interpret_ask(const F &f, const Env &env, this_type2< M > &k, IDiagnostics &diagnostics)
Definition: nbitset.hpp:235
constexpr static const bool complemented
Definition: nbitset.hpp:43
constexpr static const bool preserve_concrete_covers
Definition: nbitset.hpp:42
constexpr CUDA bool meet_lb(const A &lb)
Definition: nbitset.hpp:309
constexpr static const bool is_abstract_universe
Definition: nbitset.hpp:34
constexpr static const bool is_arithmetic
Definition: nbitset.hpp:44
Mem memory_type
Definition: nbitset.hpp:21
constexpr CUDA void join_top()
Definition: nbitset.hpp:281
constexpr CUDA this_type & operator=(const this_type &other)
Definition: nbitset.hpp:97
constexpr CUDA NBitset(const battery::bitset< N, M, T > &bits)
Definition: nbitset.hpp:87
constexpr CUDA local_type width() const
Definition: nbitset.hpp:453
this_type2< battery::local_memory > local_type
Definition: nbitset.hpp:25
constexpr CUDA local::B is_top() const
Definition: nbitset.hpp:109
CUDA TFormula< Allocator > deinterpret(AVar x, const Env &env, const Allocator &allocator=Allocator()) const
Definition: nbitset.hpp:334
constexpr CUDA bool meet_ub(const A &ub)
Definition: nbitset.hpp:314
typename LB::value_type value_type
Definition: nbitset.hpp:29
CUDA constexpr static NI bool is_trivial_fun(Sig sig)
Definition: nbitset.hpp:400
constexpr CUDA this_type & operator=(const this_type2< M > &other)
Definition: nbitset.hpp:92
constexpr CUDA void neg(const local_type &x)
Definition: nbitset.hpp:409
constexpr CUDA void project(Sig fun, const local_type &x, const local_type &y)
Definition: nbitset.hpp:447
constexpr CUDA void meet_bot()
Definition: nbitset.hpp:304
constexpr CUDA NBitset(const this_type2< M > &other)
Definition: nbitset.hpp:81
constexpr CUDA bool extract(this_type2< M > &ua) const
Definition: nbitset.hpp:328
constexpr CUDA local::B is_bot() const
Definition: nbitset.hpp:110
Definition: ast.hpp:247
#define INTERPRETATION_WARNING(MSG)
Definition: diagnostics.hpp:150
#define RETURN_INTERPRETATION_WARNING(MSG)
Definition: diagnostics.hpp:159
#define RETURN_INTERPRETATION_ERROR(MSG)
Definition: diagnostics.hpp:155
Definition: ast.hpp:223
::lala::ZLB< int, battery::local_memory > ZLB
Definition: arith_bound.hpp:68
::lala::B<::battery::local_memory > B
Definition: b.hpp:12
::lala::ZUB< int, battery::local_memory > ZUB
Definition: arith_bound.hpp:69
Definition: abstract_deps.hpp:14
CUDA NI const char * string_of_sig(Sig sig)
Definition: ast.hpp:121
constexpr CUDA bool operator==(const CartesianProduct< As... > &a, const CartesianProduct< Bs... > &b)
Definition: cartesian_product.hpp:504
long long int logic_int
Definition: sort.hpp:114
Sig
Definition: ast.hpp:94
@ 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
@ 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
@ IN
Set membership predicate.
Definition: ast.hpp:108
@ GT
Arithmetic comparison predicates. When applied to set, it corresponds to the lexicographic ordering o...
Definition: ast.hpp:113
@ LT
Unary arithmetic function symbols.
Definition: ast.hpp:113
@ ABS
Unary arithmetic function symbols.
Definition: ast.hpp:96
@ NEG
Unary arithmetic function symbols.
Definition: ast.hpp:96
constexpr CUDA auto fjoin(const CartesianProduct< As... > &a, const CartesianProduct< Bs... > &b)
Definition: cartesian_product.hpp:464
battery::vector< battery::tuple< F, F >, typename F::allocator_type > logic_set
Definition: sort.hpp:127
CUDA NI std::optional< F > negate(const F &f)
Definition: algorithm.hpp:284
std::ostream & operator<<(std::ostream &s, const CartesianProduct< A, As... > &cp)
Definition: cartesian_product.hpp:531
constexpr CUDA bool operator<(const CartesianProduct< As... > &a, const CartesianProduct< Bs... > &b)
Definition: cartesian_product.hpp:485
constexpr CUDA auto fmeet(const CartesianProduct< As... > &a, const CartesianProduct< Bs... > &b)
Definition: cartesian_product.hpp:471
constexpr CUDA bool operator>(const CartesianProduct< As... > &a, const CartesianProduct< Bs... > &b)
Definition: cartesian_product.hpp:498
#define UNTYPED
Definition: sort.hpp:21
Definition: sort.hpp:26