Lattice Land Core Library
Loading...
Searching...
No Matches
flat_universe.hpp
Go to the documentation of this file.
1// Copyright 2023 Pierre Talbot
2
3#ifndef LALA_CORE_FLAT_UNIVERSE_HPP
4#define LALA_CORE_FLAT_UNIVERSE_HPP
5
6#include "primitive_upset.hpp"
7
8namespace lala {
9
10template<class PreUniverse, class Mem>
11class FlatUniverse;
12
13/** Lattice of flat integers. */
14template<class VT, class Mem>
16
17/** Lattice of flat floating-point numbers. */
18template<class VT, class Mem>
20
21/** Aliases for lattice allocated on the stack (as local variable) and accessed by only one thread.
22 * To make things simpler, the underlying type is also chosen (when required). */
27
28template<class PreUniverse, class Mem>
30{
31 using U = PreUniverse;
32public:
33 using pre_universe = PreUniverse;
34 using value_type = typename pre_universe::value_type;
35 using memory_type = Mem;
37 template <class M> using this_type2 = FlatUniverse<pre_universe, M>;
39
40 static_assert(pre_universe::increasing);
41 static_assert(pre_universe::preserve_bot && pre_universe::preserve_top,
42 "The Flat lattice construction reuse the bottom and top elements of the pre-universe.\
43 Therefore, it must preserve bottom and top.");
44
45 constexpr static const bool is_abstract_universe = true;
46 constexpr static const bool sequential = Mem::sequential;
47 constexpr static const bool is_totally_ordered = false;
48 constexpr static const bool preserve_bot = true;
49 constexpr static const bool preserve_top = true;
50 constexpr static const bool preserve_join = true;
51 constexpr static const bool preserve_meet = false;
52 constexpr static const bool injective_concretization = pre_universe::injective_concretization;
53 constexpr static const bool preserve_concrete_covers = true;
54 constexpr static const bool complemented = false;
55 constexpr static const char* name = "Flat";
56 constexpr static const bool is_arithmetic = pre_universe::is_arithmetic;
57
58 /** A pre-interpreted formula `x = value` ready to use.
59 * This is mainly for optimization purpose to avoid calling `interpret` each time we need it. */
60 CUDA static constexpr local_type eq_k(value_type k) {
61 return local_type(k);
62 }
63
64private:
65 using atomic_type = memory_type::template atomic_type<value_type>;
66 atomic_type val;
67
68public:
69 /** Similar to \f$[\![\mathit{true}]\!]\f$. */
70 CUDA static constexpr local_type bot() {
71 return local_type();
72 }
73
74 /** Similar to \f$[\![\mathit{false}]\!]\f$. */
75 CUDA static constexpr local_type top() {
76 return local_type(U::top());
77 }
78 /** Initialize to the bottom of the flat lattice. */
79 CUDA constexpr FlatUniverse(): val(U::bot()) {}
80 /** Similar to \f$[\![x = k]\!]\f$ for any name `x` where \f$ = \f$ is the equality. */
81 CUDA constexpr FlatUniverse(value_type k): val(k) {}
82 CUDA constexpr FlatUniverse(const this_type& other): FlatUniverse(other.value()) {}
83 CUDA constexpr FlatUniverse(this_type&& other): val(std::move(other.val)) {}
84
85 template <class M>
86 CUDA constexpr FlatUniverse(const this_type2<M>& other): FlatUniverse(other.value()) {}
87
88 template <class M>
89 CUDA constexpr FlatUniverse(const PrimitiveUpset<pre_universe, M>& other)
90 : FlatUniverse(other.value()) {}
91
92 template <class M>
95
96 /** The assignment operator can only be used in a sequential context.
97 * It is monotone but not extensive. */
98 template <class M>
99 CUDA constexpr this_type& operator=(const this_type2<M>& other) {
100 if constexpr(sequential) {
101 memory_type::store(val, other.value());
102 return *this;
103 }
104 else {
105 static_assert(sequential, "The operator= in `FlatUniverse` can only be used when the underlying memory is `sequential`.");
106 }
107 }
108
109 CUDA constexpr this_type& operator=(const this_type& other) {
110 if constexpr(sequential) {
111 memory_type::store(val, other.value());
112 return *this;
113 }
114 else {
115 static_assert(sequential, "The operator= in `FlatUniverse` can only be used when the underlying memory is `sequential`.");
116 }
117 }
118
119 CUDA constexpr value_type value() const { return memory_type::load(val); }
120
121 CUDA constexpr operator value_type() const { return value(); }
122
123 /** `true` whenever \f$ a = \top \f$, `false` otherwise. */
124 CUDA constexpr local::BInc is_top() const {
125 return value() == U::top();
126 }
127
128 /** `true` whenever \f$ a = \bot \f$, `false` otherwise. */
129 CUDA constexpr local::BDec is_bot() const {
130 return value() == U::bot();
131 }
132
133 CUDA constexpr this_type& tell_top() {
134 memory_type::store(val, U::top());
135 return *this;
136 }
137
138 template<class M1, class M2>
139 CUDA constexpr this_type& tell(const this_type2<M1>& other, BInc<M2>& has_changed) {
140 if(other.is_bot() || *this == other || is_top()) {
141 return *this;
142 }
143 has_changed.tell_top();
144 if(is_bot()) {
145 memory_type::store(val, other.value());
146 return *this;
147 }
148 else {
149 return tell_top();
150 }
151 }
152
153 template<class M1>
154 CUDA constexpr this_type& tell(const this_type2<M1>& other) {
155 if(other.is_bot() || *this == other || is_top()) {
156 return *this;
157 }
158 if(is_bot()) {
159 memory_type::store(val, other.value());
160 return *this;
161 }
162 else {
163 return tell_top();
164 }
165 }
166
167 CUDA constexpr this_type& dtell_bot() {
168 memory_type::store(val, U::bot());
169 return *this;
170 }
171
172 template<class M1, class M2>
173 CUDA constexpr this_type& dtell(const this_type2<M1>& other, BInc<M2>& has_changed) {
174 if(is_bot() || *this == other || other.is_top()) {
175 return *this;
176 }
177 has_changed.tell_top();
178 if(is_top()) {
179 memory_type::store(val, other.value());
180 return *this;
181 }
182 else {
183 return dtell_bot();
184 }
185 }
186
187 template<class M1>
188 CUDA constexpr this_type& dtell(const this_type2<M1>& other) {
189 if(is_bot() || *this == other || other.is_top()) {
190 return *this;
191 }
192 if(is_top()) {
193 memory_type::store(val, other.value());
194 return *this;
195 }
196 else {
197 return dtell_bot();
198 }
199 }
200
201 /** \return \f$ x = k \f$ where `x` is a variable's name and `k` the current value.
202 `true` is returned whenever \f$ a = \bot \f$, and `false` is returned whenever \f$ a = \top \f$.
203 We always return an exact approximation, hence for any formula \f$ \llbracket \varphi \rrbracket = a \f$, we must have \f$ a = \llbracket \rrbracket a \llbracket \rrbracket \f$ where \f$ \rrbracket a \llbracket \f$ is the deinterpretation function. */
204 template<class Env>
205 CUDA NI TFormula<typename Env::allocator_type> deinterpret(AVar avar, const Env& env) const {
207 if(is_top()) {
208 return F::make_false();
209 }
210 else if(is_bot()) {
211 return F::make_true();
212 }
213 return F::make_binary(
214 F::make_avar(avar),
215 EQ,
216 deinterpret<F>(),
217 UNTYPED, env.get_allocator());
218 }
219
220 /** Deinterpret the current value to a logical constant. */
221 template<class F>
222 CUDA NI F deinterpret() const {
223 return pre_universe::template deinterpret<F>(value());
224 }
225
226 /** Under-approximates the current element \f$ a \f$ w.r.t. \f$ \rrbracket a \llbracket \f$ into `ua`.
227 * For this abstract universe, it always returns `true` since the current element \f$ a \f$ is an exact representation of \f$ \rrbracket a \llbracket \f$. */
228 CUDA constexpr bool extract(local_type& ua) const {
229 ua.val = value();
230 return true;
231 }
232
233 /** Print the current element. */
234 CUDA NI void print() const {
235 if(is_bot()) {
236 printf("\u22A5");
237 }
238 else if(is_top()) {
239 printf("\u22A4");
240 }
241 else {
243 }
244 }
245
246public:
247 /** Expects a predicate of the form `x = k` or `k = x`, where `x` is any variable's name, and `k` a constant.
248 Existential formula \f$ \exists{x:T} \f$ can also be interpreted (only to bottom). */
249 template<bool diagnose = false, class F, class Env, class M2>
250 CUDA NI static bool interpret_tell(const F& f, const Env& env, this_type2<M2>& tell, IDiagnostics& diagnostics) {
251 if(f.is(F::E)) {
252 value_type k;
253 bool res = pre_universe::template interpret_type<diagnose>(f, k, diagnostics);
254 if(res) {
255 tell.tell(local_type(k));
256 }
257 return res;
258 }
259 else {
260 if(f.is_binary() && f.sig() == EQ) {
261 int idx_constant = f.seq(0).is_constant() ? 0 : (f.seq(1).is_constant() ? 1 : 100);
262 int idx_variable = f.seq(0).is_variable() ? 0 : (f.seq(1).is_variable() ? 1 : 100);
263 if(idx_constant + idx_variable == 1) {
264 const auto& k = f.seq(idx_constant);
265 const auto& x = f.seq(idx_variable);
266 value_type t;
267 if(pre_universe::template interpret_tell<diagnose>(k, t, diagnostics)) {
268 value_type a;
269 if(pre_universe::template interpret_ask<diagnose>(k, a, diagnostics)) {
270 if(a == t) {
271 tell.tell(local_type(t));
272 return true;
273 }
274 else {
275 RETURN_INTERPRETATION_ERROR("The constant has no exact interpretation which is required in this abstract universe.");
276 }
277 }
278 }
279 return false;
280 }
281 }
283 "Tell interpretation only supports existential quantifier and binary formulas of the form `t1 = t2` where t1 is a constant and t2 is a variable (or conversely).");
284 }
285 }
286
287 /** Same as `interpret_tell` without the support for existential quantifier. */
288 template<bool diagnose = false, class F, class Env, class M2>
289 CUDA NI static bool interpret_ask(const F& f, const Env& env, this_type2<M2>& ask, IDiagnostics& diagnostics) {
290 if(f.is(F::E)) {
291 RETURN_INTERPRETATION_ERROR("Ask interpretation only supports binary formulas of the form `t1 = t2` where t1 is a constant and t2 is a variable (or conversely).")
292 }
293 return interpret_tell<diagnose>(f, env, ask, diagnostics);
294 }
295
296 template<IKind kind, bool diagnose = false, class F, class Env, class M2>
297 CUDA NI static bool interpret(const F& f, const Env& env, this_type2<M2>& value, IDiagnostics& diagnostics) {
298 if constexpr(kind == IKind::ASK) {
299 return interpret_ask<diagnose>(f, env, value, diagnostics);
300 }
301 else {
302 return interpret_tell<diagnose>(f, env, value, diagnostics);
303 }
304 }
305
306 CUDA static constexpr bool is_supported_fun(Sig sig) {
307 return pre_universe::is_supported_fun(sig);
308 }
309
310public:
311 /** Unary function over `value_type`. */
312 template<Sig sig, class M1>
313 CUDA static constexpr local_type fun(const this_type2<M1>& u) {
314 static_assert(is_supported_fun(sig));
315 auto a = u.value();
316 if(U::top() == a) {
317 return local_type::top();
318 }
319 else if(U::bot() == a) {
320 return local_type::bot();
321 }
322 return pre_universe::template fun<sig>(a);
323 }
324
325 /** Binary functions over `value_type`. */
326 template<Sig sig, class M1, class M2>
327 CUDA static constexpr local_type fun(const this_type2<M1>& l, const this_type2<M2>& k) {
328 static_assert(is_supported_fun(sig));
329 auto a = l.value();
330 auto b = k.value();
331 if(U::top() == a || U::top() == b) {
332 return local_type::top();
333 }
334 else if(U::bot() == a || U::bot() == b) {
335 return local_type::bot();
336 }
337 if constexpr(is_division(sig) && is_arithmetic) {
338 if(b == pre_universe::zero()) {
339 return local_type::top();
340 }
341 }
342 return pre_universe::template fun<sig>(a, b);
343 }
344
345 template<class Pre2, class Mem2>
346 friend class FlatUniverse;
347};
348
349// Lattice operators
350
351template<class Pre, class M1, class M2>
353 if(a == b) {
354 return a;
355 }
356 else if(a.is_bot() || b.is_top()) {
357 return b;
358 }
359 else if(b.is_bot() || a.is_top()) {
360 return a;
361 }
362 else {
364 }
365}
366
367template<class Pre, class M1, class M2>
369 if(a == b) {
370 return a;
371 }
372 else if(a.is_bot() || b.is_top()) {
373 return a;
374 }
375 else if(b.is_bot() || a.is_top()) {
376 return b;
377 }
378 else {
380 }
381}
382
383template<class Pre, class M1, class M2>
384CUDA constexpr bool operator<=(const FlatUniverse<Pre, M1>& a, const FlatUniverse<Pre, M2>& b) {
385 return a.is_bot() || b.is_top() || a == b;
386}
387
388template<class Pre, class M1, class M2>
389CUDA constexpr bool operator<(const FlatUniverse<Pre, M1>& a, const FlatUniverse<Pre, M2>& b) {
390 return (a.is_bot() || b.is_top()) && a != b;
391}
392
393template<class Pre, class M1, class M2>
394CUDA constexpr bool operator>=(const FlatUniverse<Pre, M1>& a, const FlatUniverse<Pre, M2>& b) {
395 return b <= a;
396}
397
398template<class Pre, class M1, class M2>
399CUDA constexpr bool operator>(const FlatUniverse<Pre, M1>& a, const FlatUniverse<Pre, M2>& b) {
400 return b < a;
401}
402
403template<class Pre, class M1, class M2>
404CUDA constexpr bool operator==(const FlatUniverse<Pre, M1>& a, const FlatUniverse<Pre, M2>& b) {
405 return a.value() == b.value();
406}
407
408template<class Pre, class M1, class M2>
409CUDA constexpr bool operator!=(const FlatUniverse<Pre, M1>& a, const FlatUniverse<Pre, M2>& b) {
410 return a.value() != b.value();
411}
412
413template<class Pre, class M>
414std::ostream& operator<<(std::ostream &s, const FlatUniverse<Pre, M> &a) {
415 if(a.is_bot()) {
416 s << "\u22A5";
417 }
418 else if(a.is_top()) {
419 s << "\u22A4";
420 }
421 else {
422 s << a.value();
423 }
424 return s;
425}
426
427} // namespace lala
428
429#endif
Definition ast.hpp:38
Definition flat_universe.hpp:30
CUDA constexpr FlatUniverse(const PrimitiveUpset< typename pre_universe::dual_type, M > &other)
Definition flat_universe.hpp:93
typename pre_universe::value_type value_type
Definition flat_universe.hpp:34
CUDA constexpr FlatUniverse(const this_type2< M > &other)
Definition flat_universe.hpp:86
static CUDA constexpr bool is_supported_fun(Sig sig)
Definition flat_universe.hpp:306
static constexpr const char * name
Definition flat_universe.hpp:55
CUDA NI F deinterpret() const
Definition flat_universe.hpp:222
static constexpr const bool is_arithmetic
Definition flat_universe.hpp:56
CUDA constexpr local::BDec is_bot() const
Definition flat_universe.hpp:129
CUDA static NI bool interpret(const F &f, const Env &env, this_type2< M2 > &value, IDiagnostics &diagnostics)
Definition flat_universe.hpp:297
static constexpr const bool injective_concretization
Definition flat_universe.hpp:52
static constexpr const bool is_abstract_universe
Definition flat_universe.hpp:45
Mem memory_type
Definition flat_universe.hpp:35
CUDA constexpr FlatUniverse(this_type &&other)
Definition flat_universe.hpp:83
CUDA constexpr this_type & dtell_bot()
Definition flat_universe.hpp:167
static constexpr const bool complemented
Definition flat_universe.hpp:54
CUDA constexpr local::BInc is_top() const
Definition flat_universe.hpp:124
CUDA NI void print() const
Definition flat_universe.hpp:234
CUDA constexpr value_type value() const
Definition flat_universe.hpp:119
CUDA constexpr this_type & dtell(const this_type2< M1 > &other, BInc< M2 > &has_changed)
Definition flat_universe.hpp:173
CUDA static NI bool interpret_ask(const F &f, const Env &env, this_type2< M2 > &ask, IDiagnostics &diagnostics)
Definition flat_universe.hpp:289
static CUDA constexpr local_type bot()
Definition flat_universe.hpp:70
static constexpr const bool preserve_join
Definition flat_universe.hpp:50
CUDA constexpr this_type & tell_top()
Definition flat_universe.hpp:133
this_type2< battery::local_memory > local_type
Definition flat_universe.hpp:38
CUDA constexpr FlatUniverse()
Definition flat_universe.hpp:79
static constexpr const bool sequential
Definition flat_universe.hpp:46
CUDA NI TFormula< typename Env::allocator_type > deinterpret(AVar avar, const Env &env) const
Definition flat_universe.hpp:205
CUDA constexpr this_type & operator=(const this_type &other)
Definition flat_universe.hpp:109
static CUDA constexpr local_type fun(const this_type2< M1 > &l, const this_type2< M2 > &k)
Definition flat_universe.hpp:327
static CUDA constexpr local_type top()
Definition flat_universe.hpp:75
static CUDA constexpr local_type fun(const this_type2< M1 > &u)
Definition flat_universe.hpp:313
static constexpr const bool preserve_concrete_covers
Definition flat_universe.hpp:53
CUDA constexpr this_type & tell(const this_type2< M1 > &other, BInc< M2 > &has_changed)
Definition flat_universe.hpp:139
static constexpr const bool preserve_meet
Definition flat_universe.hpp:51
static CUDA constexpr local_type eq_k(value_type k)
Definition flat_universe.hpp:60
CUDA constexpr this_type & operator=(const this_type2< M > &other)
Definition flat_universe.hpp:99
static constexpr const bool is_totally_ordered
Definition flat_universe.hpp:47
static constexpr const bool preserve_bot
Definition flat_universe.hpp:48
CUDA constexpr FlatUniverse(const this_type &other)
Definition flat_universe.hpp:82
CUDA constexpr this_type & tell(const this_type2< M1 > &other)
Definition flat_universe.hpp:154
CUDA constexpr bool extract(local_type &ua) const
Definition flat_universe.hpp:228
CUDA constexpr FlatUniverse(value_type k)
Definition flat_universe.hpp:81
CUDA constexpr this_type & dtell(const this_type2< M1 > &other)
Definition flat_universe.hpp:188
CUDA static NI bool interpret_tell(const F &f, const Env &env, this_type2< M2 > &tell, IDiagnostics &diagnostics)
Definition flat_universe.hpp:250
static constexpr const bool preserve_top
Definition flat_universe.hpp:49
CUDA constexpr FlatUniverse(const PrimitiveUpset< pre_universe, M > &other)
Definition flat_universe.hpp:89
PreUniverse pre_universe
Definition flat_universe.hpp:33
Definition diagnostics.hpp:19
Definition primitive_upset.hpp:118
CUDA constexpr this_type & tell_top()
Definition primitive_upset.hpp:233
Definition ast.hpp:234
#define RETURN_INTERPRETATION_ERROR(MSG)
Definition diagnostics.hpp:155
Definition ast.hpp:210
CUDA NI void print(const lala::Sig &sig)
Definition ast.hpp:212
Definition abstract_deps.hpp:14
std::ostream & operator<<(std::ostream &s, const CartesianProduct< A, As... > &cp)
Definition cartesian_product.hpp:597
CUDA constexpr LDual dual(const L &x)
Definition primitive_upset.hpp:110
CUDA constexpr bool operator==(const CartesianProduct< As... > &a, const CartesianProduct< Bs... > &b)
Definition cartesian_product.hpp:572
Sig
Definition ast.hpp:94
@ EQ
Unary arithmetic function symbols.
Definition ast.hpp:112
CUDA constexpr auto join(const CartesianProduct< As... > &a, const CartesianProduct< Bs... > &b)
Definition cartesian_product.hpp:534
CUDA constexpr auto meet(const CartesianProduct< As... > &a, const CartesianProduct< Bs... > &b)
Definition cartesian_product.hpp:541
CUDA constexpr bool operator<(const CartesianProduct< As... > &a, const CartesianProduct< Bs... > &b)
Definition cartesian_product.hpp:554
CUDA NI constexpr bool is_division(Sig sig)
Definition ast.hpp:196
CUDA constexpr bool operator>(const CartesianProduct< As... > &a, const CartesianProduct< Bs... > &b)
Definition cartesian_product.hpp:566
#define UNTYPED
Definition sort.hpp:21