Lattice Land Core Library
Loading...
Searching...
No Matches
pre_zinc.hpp
Go to the documentation of this file.
1// Copyright 2022 Pierre Talbot
2
3#ifndef LALA_CORE_PRE_ZINC_HPP
4#define LALA_CORE_PRE_ZINC_HPP
5
6#include "../logic/logic.hpp"
7
8namespace lala {
9
10template<class VT>
11struct PreZDec;
12
13/** `PreZInc` is a pre-abstract universe \f$ \langle \{-\infty, \ldots, -2, -1, 0, 1, 2, \ldots, \infty\}, \leq \rangle \f$ totally ordered by the natural arithmetic comparison operator.
14 It is used to represent constraints of the form \f$ x \geq k \f$ where \f$ k \f$ is an integer.
15*/
16template<class VT>
17struct PreZInc {
20 using value_type = VT;
22
23 static_assert(std::is_integral_v<value_type>, "PreZInc only works over integer types.");
24
25 constexpr static const bool is_totally_ordered = true;
26
27 /** `true` if \f$ \gamma(\bot) = \bot^\flat \f$. */
28 constexpr static const bool preserve_bot = true;
29
30 /** `true` if \f$ \gamma(\top) = \top^\flat \f$. */
31 constexpr static const bool preserve_top = true;
32
33 /** `true` if \f$ \gamma(a \sqcup b) = \gamma(a) \cap \gamma(b) \f$ .*/
34 constexpr static const bool preserve_join = true;
35
36 /** `true` if \f$ \gamma(a \sqcap b) = \gamma(a) \cup \gamma(b) \f$ .*/
37 constexpr static const bool preserve_meet = true;
38
39 /** The concretization is injective when each abstract element maps to a distinct concrete element.
40 This is important for the correctness of `prev` and `next` because we suppose \f$ \gamma(x) != \gamma(\mathit{next}(x)) \f$ when \f$ x \neq \bot \land x \neq \top \f$. */
41 constexpr static const bool injective_concretization = true;
42
43 /** `true` if concrete covers are preserved by the concretization function, i.e., \f$ \gamma(\mathit{next}(x)) \f$ is a cover of \f$ \gamma(x) \f$, and dually for \f$ \mathit{prev}(x) \f$.
44 * \remark `preserve_concrete_covers` implies `injective_concretization`.
45 */
46 constexpr static const bool preserve_concrete_covers = true;
47
48 /** `true` if for all element \f$ x \in A \f$, there exists a unique element \f$ \lnot x \in A \f$ such that \f$ x \sqcup \lnot x = \top \f$ and \f$ x \sqcap \lnot x = \bot \f$. */
49 constexpr static const bool complemented = false;
50
51 /** `true` if the natural order of the universe of discourse coincides with the lattice order of this pre-universe, `false` if it is reversed. */
52 constexpr static const bool increasing = true;
53
54 constexpr static const char* name = "ZInc";
55
56 constexpr static const bool is_arithmetic = true;
57 CUDA constexpr static value_type zero() { return 0; }
58 CUDA constexpr static value_type one() { return 1; }
59
60private:
61 template<bool diagnose, bool is_tell, class F>
62 CUDA NI static bool interpret(const F& f, value_type& k, IDiagnostics& diagnostics) {
63 if(f.is(F::Z)) {
64 auto z = f.z();
65 if(z == bot() || z == top()) {
66 RETURN_INTERPRETATION_ERROR("Constant of sort `Int` with the minimal or maximal representable value of the underlying integer type. We use those values to model negative and positive infinities. Example: Suppose we use a byte type, `x >= 256` is interpreted as `x >= INF` which is always false and thus is different from the intended constraint.");
67 }
68 k = z;
69 return true;
70 }
71 else if(f.is(F::R)) {
72 if constexpr(is_tell) {
73 k = battery::ru_cast<value_type>(battery::get<0>(f.r()));
74 }
75 else {
76 k = battery::ru_cast<value_type>(battery::get<1>(f.r()));
77 }
78 return true;
79 }
80 else if(f.is(F::B)) {
81 k = f.b() ? one() : zero();
82 return true;
83 }
84 RETURN_INTERPRETATION_ERROR("Only constant of sorts `Int` and `Real` can be interpreted by an integer abstract universe.");
85 }
86
87public:
88 /** Interpret a constant in the lattice of increasing integers according to the upset semantics (see universe.hpp for explanation).
89 Overflows are not verified (issue #1).
90 Interpretations:
91 * Formulas of kind `F::Z` are interpreted exactly: \f$ [\![ x:\mathbb{Z} \geq k:\mathbb{Z} ]\!] = k \f$.
92 * Formulas of kind `F::R` are over-approximated: \f$ [\![ x:\mathbb{Z} \geq [l..u]:\mathbb{R} ]\!] = \lceil l \rceil \f$.
93 Note that all elements in \f$ [l..\lceil l \rceil[\f$ do not belong to \f$ \mathbb{Z} \f$, so they can be safely ignored.
94 Examples:
95 * \f$ [\![x >= [2.5..2.5]:R ]\!] = 3 \f$.
96 * \f$ [\![x >= [2.9..3.1]:R ]\!] = 3 \f$.
97 */
98 template<bool diagnose, class F>
99 CUDA static bool interpret_tell(const F& f, value_type& tell, IDiagnostics& diagnostics) {
100 return interpret<diagnose, true>(f, tell, diagnostics);
101 }
102
103 /** Similar to `interpret_tell` but the formula is under-approximated, in particular: \f$ [\![ x:\mathbb{Z} \geq [l..u]:\mathbb{R} ]\!] = \lceil u \rceil \f$. */
104 template<bool diagnose, class F>
105 CUDA static bool interpret_ask(const F& f, value_type& ask, IDiagnostics& diagnostics) {
106 return interpret<diagnose, false>(f, ask, diagnostics);
107 }
108
109 /** Verify if the type of a variable, introduced by an existential quantifier, is compatible with the current abstract universe.
110 Variables of type `Int` are interpreted exactly (\f$ \mathbb{Z} = \gamma(\bot) \f$).
111 Note that we assume there is no overflow, that might be taken into account the future. */
112 template<bool diagnose, class F>
113 CUDA NI static bool interpret_type(const F& f, value_type& k, IDiagnostics& diagnostics) {
114 assert(f.is(F::E));
115 const auto& sort = battery::get<1>(f.exists());
116 if(sort.is_int()) {
117 k = bot();
118 return true;
119 }
120 else {
121 const auto& vname = battery::get<0>(f.exists());
122 RETURN_INTERPRETATION_ERROR("The type of `" + vname + "` can only be `Int`.")
123 }
124 }
125
126 /** Given an Integer value, create a logical constant representing that value.
127 * Note that the lattice order has no influence here.
128 * \pre `v != bot()` and `v != top()`.
129 */
130 template<class F>
131 CUDA static F deinterpret(const value_type& v) {
132 return F::make_z(v);
133 }
134
135 /** The logical predicate symbol corresponding to the order of this pre-universe.
136 We have \f$ a \leq_\mathit{ZInc} b \Leftrightarrow a \leq b \f$.
137 \return The logical symbol `LEQ`. */
138 CUDA static constexpr Sig sig_order() { return LEQ; }
139
140 /** The logical predicate symbol corresponding to the strict order of this pre-universe.
141 We have \f$ a <_\mathit{ZInc} b \Leftrightarrow a < b \f$.
142 \return The logical symbol `LT`. */
143 CUDA static constexpr Sig sig_strict_order() { return LT; }
144
145 /** \f$ \bot \f$ is represented by the minimal representable value of the underlying value type. */
146 CUDA static constexpr value_type bot() {
147 return battery::limits<value_type>::bot();
148 }
149
150 /** \f$ \top \f$ is represented by the maximal representable value of the underlying value type. */
151 CUDA static constexpr value_type top() {
152 return battery::limits<value_type>::top();
153 }
154
155 /** \return \f$ x \sqcup y \f$ defined as \f$ \mathit{max}(x, y) \f$. */
156 CUDA static constexpr value_type join(value_type x, value_type y) { return battery::max(x, y); }
157
158 /** \return \f$ x \sqcap y \f$ defined as \f$ \mathit{min}(x, y) \f$. */
159 CUDA static constexpr value_type meet(value_type x, value_type y) { return battery::min(x, y); }
160
161 /** \return \f$ \mathit{true} \f$ if \f$ x \leq_\mathit{ZInc} y \f$ where the order \f$ \leq_\mathit{ZInc} \f$ is the natural arithmetic ordering, otherwise returns \f$ \mathit{false} \f$. */
162 CUDA static constexpr bool order(value_type x, value_type y) { return x <= y; }
163
164 /** \return \f$ \mathit{true} \f$ if \f$ x <_\mathit{ZInc} y \f$ where the order \f$ <_\mathit{ZInc} \f$ is the natural arithmetic ordering, otherwise returns \f$ \mathit{false} \f$. */
165 CUDA static constexpr bool strict_order(value_type x, value_type y) { return x < y; }
166
167 /** From a lattice perspective, `next: ZInc -> ZInc` returns an element `next(x)` such that `x` is covered by `next(x)`.
168 \param x The element covering the returned element.
169 \return The next value of `x` in the discrete increasing chain `bot, ..., -2, -1, 0, 1, ..., top`.
170 \remark The next value of `bot` is `bot` and the next value of `top` is `top`.
171 \remark There is no element \f$ x \neq \top \f$ such that \f$ \mathit{next}(x) = \top \f$, but it can occur in case of overflow which is not checked. */
172 CUDA static constexpr value_type next(value_type x) {
173 return x + (x != top() && x != bot());
174 }
175
176 /** From a lattice perspective, `prev: ZInc -> ZInc` returns an element `prev(x)` such that `x` covers `prev(x)`.
177 \param x The element covered by the returned element.
178 \return The previous value of `x` in the discrete increasing chain `bot, ..., -2, -1, 0, 1, ..., top`.
179 \remark The previous value of `bot` is `bot` and the previous value of `top` is `top`.
180 \remark There is no element \f$ x \neq \bot \f$ such that \f$ \mathit{prev}(x) = \bot \f$, but it can occur in case of overflow which is not checked. */
181 CUDA static constexpr value_type prev(value_type x)
182 {
183 return x - (x != top() && x != bot());
184 }
185
186 CUDA NI static constexpr bool is_supported_fun(Sig sig) {
187 switch(sig) {
188 case NEG:
189 case ABS:
190 case ADD:
191 case SUB:
192 case MUL:
193 case TDIV:
194 case TMOD:
195 case FDIV:
196 case FMOD:
197 case CDIV:
198 case CMOD:
199 case EDIV:
200 case EMOD:
201 case POW:
202 case MIN:
203 case MAX:
204 case EQ:
205 case NEQ:
206 case LEQ:
207 case GEQ:
208 case LT:
209 case GT: return true;
210 default: return false;
211 }
212 }
213
214 /** `fun: value_type -> ZInc` is an abstract function on `ZInc` over-approximating the function denoted by `sig` on the concrete domain.
215 * \tparam sig The signature of the function to over-approximate, can be either `NEG` or `ABS`.
216 * \param x The argument of the function, which is a constant value in the underlying universe of discourse.
217 * \note Since `x` is a constant, we do not check for equality with `bot()` or `top()`.
218 */
219 template<Sig sig>
220 CUDA static constexpr value_type fun(value_type x) {
221 static_assert(sig == NEG || sig == ABS, "Unsupported unary function.");
222 switch(sig) {
223 case NEG: return -x;
224 case ABS: return abs(x);
225 default: assert(0); return x;
226 }
227 }
228
229 /** `fun: value_type X value_type -> ZInc` is similar to its unary version but with an arity of 2. */
230 template<Sig sig>
231 CUDA NI static constexpr value_type fun(value_type x, value_type y) {
232 static_assert(
233 sig == ADD || sig == SUB || sig == MUL || sig == TDIV || sig == TMOD || sig == FDIV || sig == FMOD || sig == CDIV || sig == CMOD || sig == EDIV || sig == EMOD || sig == POW || sig == MIN || sig == MAX || sig == EQ || sig == NEQ || sig == LEQ || sig == GEQ || sig == LT || sig == GT,
234 "Unsupported binary function.");
235 switch(sig) {
236 case ADD: return x + y;
237 case SUB: return x - y;
238 case MUL: return x * y;
239 // Truncated division and modulus, by default in C++.
240 case TDIV: return x / y;
241 case TMOD: return x % y;
242 // Floor division and modulus, see (Leijen D. (2003). Division and Modulus for Computer Scientists).
243 case FDIV: return battery::fdiv(x, y);
244 case FMOD: return battery::fmod(x, y);
245 // Ceil division and modulus.
246 case CDIV: return battery::cdiv(x, y);
247 case CMOD: return battery::cmod(x, y);
248 // Euclidean division and modulus, see (Leijen D. (2003). Division and Modulus for Computer Scientists).
249 case EDIV: return battery::ediv(x, y);
250 case EMOD: return battery::emod(x, y);
251 case POW: return battery::ipow(x, y);
252 case MIN: return battery::min(x, y);
253 case MAX: return battery::max(x, y);
254 case EQ: return x == y;
255 case NEQ: return x != y;
256 case LEQ: return x <= y;
257 case GEQ: return x >= y;
258 case LT: return x < y;
259 case GT: return x >= y;
260 default: assert(0); return x;
261 }
262 }
263};
264
265} // namespace lala
266
267#endif
Definition diagnostics.hpp:19
#define RETURN_INTERPRETATION_ERROR(MSG)
Definition diagnostics.hpp:155
Definition abstract_deps.hpp:14
Sig
Definition ast.hpp:94
@ NEQ
Equality relations.
Definition ast.hpp:112
@ LEQ
Unary arithmetic function symbols.
Definition ast.hpp:113
@ TMOD
Truncated division, present in most programming languages, is defined as , i.e., it rounds towards ze...
Definition ast.hpp:102
@ 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
@ 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
@ ABS
Unary arithmetic function symbols.
Definition ast.hpp:96
@ SUB
Unary arithmetic function symbols.
Definition ast.hpp:97
@ 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
Definition pre_zdec.hpp:18
Definition pre_zinc.hpp:17
VT value_type
Definition pre_zinc.hpp:20
CUDA static constexpr value_type one()
Definition pre_zinc.hpp:58
static constexpr const bool preserve_join
Definition pre_zinc.hpp:34
static constexpr const bool preserve_concrete_covers
Definition pre_zinc.hpp:46
static constexpr const bool increasing
Definition pre_zinc.hpp:52
static CUDA constexpr bool order(value_type x, value_type y)
Definition pre_zinc.hpp:162
static constexpr const bool is_arithmetic
Definition pre_zinc.hpp:56
static CUDA constexpr Sig sig_order()
Definition pre_zinc.hpp:138
static constexpr const char * name
Definition pre_zinc.hpp:54
static CUDA bool interpret_tell(const F &f, value_type &tell, IDiagnostics &diagnostics)
Definition pre_zinc.hpp:99
CUDA static constexpr value_type zero()
Definition pre_zinc.hpp:57
static constexpr const bool preserve_meet
Definition pre_zinc.hpp:37
PreZInc< VT > this_type
Definition pre_zinc.hpp:18
CUDA static NI constexpr bool is_supported_fun(Sig sig)
Definition pre_zinc.hpp:186
static CUDA bool interpret_ask(const F &f, value_type &ask, IDiagnostics &diagnostics)
Definition pre_zinc.hpp:105
static constexpr const bool preserve_top
Definition pre_zinc.hpp:31
static CUDA constexpr value_type top()
Definition pre_zinc.hpp:151
static CUDA constexpr Sig sig_strict_order()
Definition pre_zinc.hpp:143
static CUDA constexpr value_type fun(value_type x)
Definition pre_zinc.hpp:220
CUDA static NI bool interpret_type(const F &f, value_type &k, IDiagnostics &diagnostics)
Definition pre_zinc.hpp:113
static constexpr const bool complemented
Definition pre_zinc.hpp:49
static CUDA constexpr value_type bot()
Definition pre_zinc.hpp:146
static constexpr const bool injective_concretization
Definition pre_zinc.hpp:41
static constexpr const bool preserve_bot
Definition pre_zinc.hpp:28
static CUDA constexpr value_type prev(value_type x)
Definition pre_zinc.hpp:181
static CUDA constexpr value_type next(value_type x)
Definition pre_zinc.hpp:172
CUDA static NI constexpr value_type fun(value_type x, value_type y)
Definition pre_zinc.hpp:231
static constexpr const bool is_totally_ordered
Definition pre_zinc.hpp:25
static CUDA constexpr value_type join(value_type x, value_type y)
Definition pre_zinc.hpp:156
static CUDA F deinterpret(const value_type &v)
Definition pre_zinc.hpp:131
static CUDA constexpr value_type meet(value_type x, value_type y)
Definition pre_zinc.hpp:159
static CUDA constexpr bool strict_order(value_type x, value_type y)
Definition pre_zinc.hpp:165