Lattice Land Core Library
pre_fub.hpp
Go to the documentation of this file.
1 // Copyright 2022 Pierre Talbot
2 
3 #ifndef LALA_CORE_PRE_FUB_HPP
4 #define LALA_CORE_PRE_FUB_HPP
5 
6 #include "../logic/logic.hpp"
7 
8 namespace lala {
9 
10 template <class VT>
11 struct PreFLB;
12 
13 /** `PreFUB` is a pre-abstract universe \f$ \langle \mathbb{F}\setminus\{NaN\}, \leq \rangle \f$ totally ordered by the floating-point arithmetic comparison operator.
14  We work on a subset of floating-point numbers without NaN.
15  It is used to represent (and possibly approximate) constraints of the form \f$ x \leq k \f$ where \f$ k \f$ is a real number.
16 */
17 template<class VT>
18 struct PreFUB {
21  using value_type = VT;
24 
25  constexpr static const bool is_totally_ordered = true;
26  constexpr static const bool preserve_bot = true;
27  constexpr static const bool preserve_top = true;
28  constexpr static const bool preserve_join = true;
29  constexpr static const bool preserve_meet = true;
30  /** Note that -0 and +0 are treated as the same element. */
31  constexpr static const bool injective_concretization = true;
32  constexpr static const bool preserve_concrete_covers = false;
33  constexpr static const bool is_lower_bound = false;
34  constexpr static const bool is_upper_bound = true;
35  constexpr static const char* name = "FUB";
36  constexpr static const bool is_arithmetic = true;
37  CUDA constexpr static value_type zero() { return 0.0; }
38  CUDA constexpr static value_type one() { return 1.0; }
39 
40 private:
41  template<bool diagnose, bool is_tell, class F>
42  CUDA NI static bool interpret(const F& f, value_type& k, IDiagnostics& diagnostics) {
43  if(f.is(F::Z)) {
44  auto z = f.z();
45  // We do not consider the min and max values of integers to be infinities when they are part of the logical formula.
46  if constexpr(is_tell) {
47  k = battery::ru_cast<value_type, decltype(z), false>(z);
48  }
49  else {
50  k = battery::rd_cast<value_type, decltype(z), false>(z);
51  }
52  return true;
53  }
54  else if(f.is(F::R)) {
55  if constexpr(is_tell) {
56  k = battery::ru_cast<value_type>(battery::get<1>(f.r()));
57  }
58  else {
59  k = battery::rd_cast<value_type>(battery::get<0>(f.r()));
60  }
61  return true;
62  }
63  RETURN_INTERPRETATION_ERROR("Only a constant of sort `Int` or `Real` can be interpreted by a floating-point abstract universe.")
64  }
65 
66 public:
67  /** Interpret a constant in the lattice of increasing floating-point numbers `FInc` according to the downset semantics.
68  Interpretations:
69  * Formulas of kind `F::Z` might be over-approximated (if the integer cannot be represented in a floating-point number because it is too large).
70  * Formulas of kind `F::R` might be over-approximated to the upper bound of the interval (if the real number is represented by an interval [lb..ub] where lb != ub).
71  * Other kind of formulas are not supported. */
72  template<bool diagnose, class F>
73  CUDA static bool interpret_tell(const F& f, value_type& k, IDiagnostics& diagnostics) {
74  return interpret<diagnose, true>(f, k, diagnostics);
75  }
76 
77  /** Same as `interpret_tell` but the constant is under-approximated instead. */
78  template<bool diagnose, class F>
79  CUDA static bool interpret_ask(const F& f, value_type& k, IDiagnostics& diagnostics) {
80  return interpret<diagnose, false>(f, k, diagnostics);
81  }
82 
83  /** Verify if the type of a variable, introduced by an existential quantifier, is compatible with the current abstract universe.
84  Interpretations:
85  * Variables of type `Int` are always over-approximated (\f$ \mathbb{Z} \subseteq \gamma(\top) \f$).
86  * Variables of type `Real` are represented exactly (only initially because \f$ \mathbb{R} = \gamma(\top) \f$). */
87  template<bool diagnose, class F, bool dualize = false>
88  CUDA NI static bool interpret_type(const F& f, value_type& k, IDiagnostics& diagnostics) {
89  assert(f.is(F::E));
90  const auto& vname = battery::get<0>(f.exists());
91  const auto& cty = battery::get<1>(f.exists());
92  if(cty.is_int()) {
93  k = dualize ? bot() : top();
94  RETURN_INTERPRETATION_WARNING("Variable `" + vname + "` of sort `Int` is over-approximated in a floating-point abstract universe.");
95  }
96  else if(cty.is_real()) {
97  k = dualize ? bot() : top();
98  return true;
99  }
100  else {
101  RETURN_INTERPRETATION_ERROR("Variable `" + vname + "` can only be of sort `Real`, or be over-approximated if the sort is `Bool` or `Int`.");
102  }
103  }
104 
105  /** Given a floating-point value, create a logical constant representing that value.
106  * The constant is represented by a singleton interval of `double` [v..v].
107  * Note that the lattice order has no influence here.
108  * \pre `v != bot()` and `v != top()`.
109  */
110  template<class F>
111  CUDA static F deinterpret(const value_type& v) {
112  return F::make_real(v, v);
113  }
114 
115  /** The logical predicate symbol corresponding to the order of this pre-universe.
116  We have \f$ a \leq_\mathit{FInc} b \Leftrightarrow a \leq b \f$.
117  \return The logical symbol `LEQ`. */
118  CUDA static constexpr Sig sig_order() { return LEQ; }
119 
120  /** The logical predicate symbol corresponding to the strict order of this pre-universe.
121  We have \f$ a <_\mathit{FInc} b \Leftrightarrow a < b \f$.
122  \return The logical symbol `LT`. */
123  CUDA static constexpr Sig sig_strict_order() { return LT; }
124 
125  /** \f$ \bot \f$ is represented by the floating-point negative infinity value. */
126  CUDA static constexpr value_type bot() {
127  return battery::limits<value_type>::neg_inf();
128  }
129 
130  /** \f$ \top \f$ is represented by the floating-point positive infinity value. */
131  CUDA static constexpr value_type top() {
132  return battery::limits<value_type>::inf();
133  }
134 
135  /** \return \f$ x \sqcup y \f$ defined as \f$ \mathit{max}(x, y) \f$. */
136  CUDA static constexpr value_type join(value_type x, value_type y) { return battery::max(x, y); }
137 
138  /** \return \f$ x \sqcap y \f$ defined as \f$ \mathit{min}(x, y) \f$. */
139  CUDA static constexpr value_type meet(value_type x, value_type y) { return battery::min(x, y); }
140 
141  /** \return \f$ \mathit{true} \f$ if \f$ x \leq_\mathit{FInc} y \f$ where the order \f$ \leq_\mathit{FInc} \f$ is the natural arithmetic ordering, otherwise returns \f$ \mathit{false} \f$. */
142  CUDA static constexpr bool order(value_type x, value_type y) { return x <= y; }
143 
144  /** \return \f$ \mathit{true} \f$ if \f$ x <_\mathit{FInc} y \f$ where the order \f$ <_\mathit{ZInc} \f$ is the natural arithmetic ordering, otherwise returns \f$ \mathit{false} \f$. */
145  CUDA static constexpr bool strict_order(value_type x, value_type y) { return x < y; }
146 
147  /** From a lattice perspective, this function returns an element \f$ y \f$ such that \f$ y \f$ is a cover of \f$ x \f$.
148 
149  \return The next value of \f$ x \f$ in the floating-point increasing chain \f$ -\infty, \ldots, prev(-2.0), -2.0, next(-2.0), \ldots, \infty \f$ is the next representable value of \f$ x \f$ when \f$ x \not\in \{\infty, -\infty\} \f$ and \f$ x \f$ otherwise.
150  Note that \f$ 0 \f$ is considered to be represented by a single value. */
151  CUDA static constexpr value_type next(value_type x) {
152  if(x == bot() || x == top()) {
153  return x;
154  }
155  if(x == value_type{-0.0}) {
156  return battery::nextafter(value_type{+0.0}, top());
157  }
158  return battery::nextafter(x, top());
159  }
160 
161  /** From a lattice perspective, this function returns an element \f$ y \f$ such that \f$ x \f$ is a cover of \f$ y \f$.
162 
163  \return The previous value of \f$ x \f$ in the floating-point increasing chain \f$ -\infty, \ldots, prev(-2.0), -2.0, next(-2.0), \ldots, \infty \f$ is the previous representable value of \f$ x \f$ when \f$ x \not\in \{\infty, -\infty\} \f$ and \f$ x \f$ otherwise.
164  \f$ 0 \f$ is considered to be represented by a single value. */
165  CUDA static constexpr value_type prev(value_type x) {
166  if(x == bot() || x == top()) {
167  return x;
168  }
169  if(x == value_type{+0.0}) {
170  return battery::nextafter(value_type{-0.0}, bot());
171  }
172  return battery::nextafter(x, bot());
173  }
174 
175  CUDA static constexpr value_type project(Sig fun, value_type x) {
176  switch(fun) {
177  case NEG: return -x;
178  default: return top();
179  }
180  }
181 
182  CUDA static constexpr value_type project(Sig fun, value_type x, value_type y) {
183  switch(fun) {
184  case ADD: return battery::add_up(x, y);
185  case SUB: return battery::sub_up(x, y);
186  case MUL: return battery::mul_up(x, y);
187  case DIV: return battery::div_up(x, y);
188  case MIN: return battery::min(x, y);
189  case MAX: return battery::max(x, y);
190  case EQ: return x == y;
191  case NEQ: return x != y;
192  case LEQ: return x <= y;
193  case GEQ: return x >= y;
194  case LT: return x < y;
195  case GT: return x >= y;
196  default: return top();
197  }
198  }
199 };
200 
201 } // namespace lala
202 
203 #endif
Definition: diagnostics.hpp:19
#define RETURN_INTERPRETATION_WARNING(MSG)
Definition: diagnostics.hpp:159
#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
@ 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
@ MIN
Unary arithmetic function symbols.
Definition: ast.hpp:97
@ DIV
Unary arithmetic function symbols.
Definition: ast.hpp:101
@ GT
Arithmetic comparison predicates. When applied to set, it corresponds to the lexicographic ordering o...
Definition: ast.hpp:113
@ MAX
Binary arithmetic function symbols.
Definition: ast.hpp:97
@ LT
Unary arithmetic function symbols.
Definition: ast.hpp:113
@ SUB
Unary arithmetic function symbols.
Definition: ast.hpp:97
@ MUL
Unary arithmetic function symbols.
Definition: ast.hpp:97
@ NEG
Unary arithmetic function symbols.
Definition: ast.hpp:96
Definition: pre_flb.hpp:19
Definition: pre_fub.hpp:18
constexpr static const bool is_arithmetic
Definition: pre_fub.hpp:36
static constexpr CUDA value_type bot()
Definition: pre_fub.hpp:126
constexpr static const bool is_totally_ordered
Definition: pre_fub.hpp:25
static constexpr CUDA value_type top()
Definition: pre_fub.hpp:131
static constexpr CUDA value_type meet(value_type x, value_type y)
Definition: pre_fub.hpp:139
constexpr static const bool preserve_meet
Definition: pre_fub.hpp:29
constexpr static CUDA value_type zero()
Definition: pre_fub.hpp:37
constexpr static const char * name
Definition: pre_fub.hpp:35
VT value_type
Definition: pre_fub.hpp:21
static constexpr CUDA value_type project(Sig fun, value_type x, value_type y)
Definition: pre_fub.hpp:182
static constexpr CUDA Sig sig_order()
Definition: pre_fub.hpp:118
static constexpr CUDA value_type join(value_type x, value_type y)
Definition: pre_fub.hpp:136
static CUDA bool interpret_ask(const F &f, value_type &k, IDiagnostics &diagnostics)
Definition: pre_fub.hpp:79
constexpr static const bool preserve_concrete_covers
Definition: pre_fub.hpp:32
static CUDA F deinterpret(const value_type &v)
Definition: pre_fub.hpp:111
static constexpr CUDA bool strict_order(value_type x, value_type y)
Definition: pre_fub.hpp:145
constexpr static const bool is_lower_bound
Definition: pre_fub.hpp:33
constexpr static const bool preserve_bot
Definition: pre_fub.hpp:26
static constexpr CUDA bool order(value_type x, value_type y)
Definition: pre_fub.hpp:142
constexpr static CUDA value_type one()
Definition: pre_fub.hpp:38
constexpr static const bool preserve_top
Definition: pre_fub.hpp:27
PreFLB< VT > dual_type
Definition: pre_fub.hpp:20
static constexpr CUDA value_type project(Sig fun, value_type x)
Definition: pre_fub.hpp:175
constexpr static const bool preserve_join
Definition: pre_fub.hpp:28
constexpr static const bool injective_concretization
Definition: pre_fub.hpp:31
static constexpr CUDA value_type prev(value_type x)
Definition: pre_fub.hpp:165
static CUDA bool interpret_tell(const F &f, value_type &k, IDiagnostics &diagnostics)
Definition: pre_fub.hpp:73
static constexpr CUDA value_type next(value_type x)
Definition: pre_fub.hpp:151
CUDA static NI bool interpret_type(const F &f, value_type &k, IDiagnostics &diagnostics)
Definition: pre_fub.hpp:88
static constexpr CUDA Sig sig_strict_order()
Definition: pre_fub.hpp:123
constexpr static const bool is_upper_bound
Definition: pre_fub.hpp:34
PreFUB< VT > this_type
Definition: pre_fub.hpp:19