Lattice Land Core Library
interpretation.hpp
Go to the documentation of this file.
1 // Copyright 2023 Pierre Talbot
2 
3 #ifndef LALA_CORE_INTERPRETATION_HPP
4 #define LALA_CORE_INTERPRETATION_HPP
5 
6 #include "logic/logic.hpp"
7 #include <optional>
8 
9 /**
10  * This file provides an extended interface to interpret formulas in abstract domains and abstract universes.
11  * It also provides a unified interface for tell and ask interpretation using a template parameter `IKind`.
12 */
13 
14 namespace lala {
15 
16 /** Interpret `true` in the lattice `L`.
17  * \return `true` if `L` preserves the top element w.r.t. the concrete domain or if `true` is interpreted by under-approximation (kind == ASK).
18  */
19 template <class L, IKind kind, bool diagnose = false, class F>
20 CUDA bool ginterpret_true(const F& f, IDiagnostics& diagnostics) {
21  assert(f.is_true());
22  if constexpr(kind == IKind::ASK || L::preserve_top) {
23  return true;
24  }
25  else {
26  const char* name = L::name;
27  RETURN_INTERPRETATION_ERROR("Bottom is not preserved, hence we cannot over-approximate `true` in this abstract domain.");
28  }
29 }
30 
31 /** This function provides an extended and unified interface to ask and tell interpretation of formula in abstract domains.
32  * It provides default interpretation for common formulas such as `true`, `false` and conjunction of formulas whenever `A` satisfies some lattice-theoretic conditions.
33  */
34 template <IKind kind, bool diagnose = false, class A, class F, class Env, class I>
35 CUDA bool ginterpret_in(const A& a, const F& f, Env& env, I& intermediate, IDiagnostics& diagnostics) {
36  const char* name = A::name;
37  if(f.is_true()) {
38  return ginterpret_true<A, kind, diagnose>(f, diagnostics);
39  }
40  else if(f.is_false()) {
41  if constexpr(kind == IKind::TELL || A::preserve_bot) {
42  return a.template interpret<kind, diagnose>(f, env, intermediate, diagnostics); // We don't know how `bot` is represented by this abstract domain, so we just forward the interpretation call.
43  }
44  else {
45  RETURN_INTERPRETATION_ERROR("Bot is not preserved, hence we cannot under-approximate `true` in this abstract domain.");
46  }
47  }
48  else if(f.is(F::Seq) && f.sig() == AND) {
49  if constexpr(kind == IKind::ASK || A::preserve_meet) {
50  for(int i = 0; i < f.seq().size(); ++i) {
51  if(!ginterpret_in<kind, diagnose>(a, f.seq(i), env, intermediate, diagnostics)) {
52  return false;
53  }
54  }
55  return true;
56  }
57  else {
58  RETURN_INTERPRETATION_ERROR("Meet is not preserved, hence we cannot over-approximate conjunctions in this abstract domain.");
59  }
60  }
61  // In the other cases, we cannot provide a default interpretation, so we forward the call to the abstract domain.
62  return a.template interpret<kind, diagnose>(f, env, intermediate, diagnostics);
63 }
64 
65 /** This function provides an extended and unified interface to ask and tell interpretation of formula in abstract universes.
66  * It provides default interpretation for common formulas such as `true`, `false`, conjunction and disjunction of formulas whenever `U` satisfies some lattice-theoretic conditions. */
67 template <IKind kind, bool diagnose = false, class F, class Env, class U>
68 CUDA bool ginterpret_in(const F& f, const Env& env, U& value, IDiagnostics& diagnostics) {
69  const char* name = U::name;
70  if(f.is_true()) {
71  return ginterpret_true<U, kind, diagnose>(f, diagnostics);
72  }
73  else if(f.is_false()) {
74  if constexpr(kind == IKind::TELL || U::preserve_bot) {
75  value.meet_bot();
76  return true;
77  }
78  else {
79  RETURN_INTERPRETATION_ERROR("Bot is not preserved, hence we cannot under-approximate `true` in this abstract universe.");
80  }
81  }
82  else if(f.is(F::Seq)) {
83  if(f.sig() == AND) {
84  if constexpr(kind == IKind::ASK || U::preserve_meet) {
85  for(int i = 0; i < f.seq().size(); ++i) {
86  if(!ginterpret_in<kind, diagnose>(f.seq(i), env, value, diagnostics)) {
87  return false;
88  }
89  }
90  return true;
91  }
92  else {
93  RETURN_INTERPRETATION_ERROR("Meet is not preserved, hence we cannot over-approximate conjunctions in this abstract universe.");
94  }
95  }
96  else if(f.sig() == OR) {
97  if constexpr(kind == IKind::TELL || U::preserve_join) {
98  using U2 = typename U::local_type;
99  U2 join_value = U2::bot();
100  for(int i = 0; i < f.seq().size(); ++i) {
101  U2 x = U2::top();
102  if(!ginterpret_in<kind, diagnose>(f.seq(i), env, x, diagnostics)) {
103  return false;
104  }
105  join_value.join(x);
106  }
107  value.meet(join_value);
108  return true;
109  }
110  else {
111  RETURN_INTERPRETATION_ERROR("Join is not preserved, hence we cannot under-approximate disjunctions in this abstract universe.");
112  }
113  }
114  }
115  // In the other cases, we cannot provide a default interpretation, so we forward the call to the abstract element.
116  return U::template interpret<kind, diagnose>(f, env, value, diagnostics);
117 }
118 
119 /** Top-level version of `ginterpret_in`, we restore `env` and `intermediate` in case of failure. */
120 template <IKind kind, bool diagnose = false, class A, class F, class Env, class I>
121 CUDA bool top_level_ginterpret_in(const A& a, const F& f, Env& env, I& intermediate, IDiagnostics& diagnostics) {
122  auto snap = env.snapshot();
123  I copy = intermediate;
124  if(ginterpret_in<kind, diagnose>(a, f, env, intermediate, diagnostics)) {
125  return true;
126  }
127  else {
128  env.restore(snap);
129  intermediate = std::move(copy);
130  return false;
131  }
132 }
133 
134 template <class A, class Alloc = battery::standard_allocator, class Env>
135 CUDA A make_top(Env& env, Alloc alloc = Alloc{}) {
136  if constexpr(A::is_abstract_universe) {
137  return A::top();
138  }
139  else {
140  return A::top(env, alloc);
141  }
142 }
143 
144 template <bool diagnose = false, class TellAlloc = battery::standard_allocator, class F, class Env, class L>
145 CUDA bool interpret_and_tell(const F& f, Env& env, L& value, IDiagnostics& diagnostics, TellAlloc tell_alloc = TellAlloc{}) {
146  if constexpr(L::is_abstract_universe) {
147  return ginterpret_in<IKind::TELL, diagnose>(f, env, value, diagnostics);
148  }
149  else {
150  typename L::template tell_type<TellAlloc> tell(tell_alloc);
151  if(top_level_ginterpret_in<IKind::TELL, diagnose>(value, f, env, tell, diagnostics)) {
152  value.deduce(tell);
153  return true;
154  }
155  else {
156  return false;
157  }
158  }
159 }
160 
161 template <class A, bool diagnose = false, class F, class Env, class TellAlloc = typename A::allocator_type>
162 CUDA std::optional<A> create_and_interpret_and_tell(const F& f,
163  Env& env, IDiagnostics& diagnostics,
164  typename A::allocator_type alloc = typename A::allocator_type{},
165  TellAlloc tell_alloc = TellAlloc{})
166 {
167  auto snap = env.snapshot();
168  A a{make_top<A>(env, alloc)};
169  if(interpret_and_tell<diagnose>(f, env, a, diagnostics, tell_alloc)) {
170  return {std::move(a)};
171  }
172  else {
173  env.restore(snap);
174  return {};
175  }
176 }
177 
178 }
179 
180 #endif
Definition: diagnostics.hpp:19
#define RETURN_INTERPRETATION_ERROR(MSG)
Definition: diagnostics.hpp:155
Definition: abstract_deps.hpp:14
CUDA A make_top(Env &env, Alloc alloc=Alloc{})
Definition: interpretation.hpp:135
@ OR
Unary arithmetic function symbols.
Definition: ast.hpp:114
@ AND
Unary arithmetic function symbols.
Definition: ast.hpp:114
CUDA bool top_level_ginterpret_in(const A &a, const F &f, Env &env, I &intermediate, IDiagnostics &diagnostics)
Definition: interpretation.hpp:121
CUDA bool ginterpret_true(const F &f, IDiagnostics &diagnostics)
Definition: interpretation.hpp:20
CUDA std::optional< A > create_and_interpret_and_tell(const F &f, Env &env, IDiagnostics &diagnostics, typename A::allocator_type alloc=typename A::allocator_type{}, TellAlloc tell_alloc=TellAlloc{})
Definition: interpretation.hpp:162
CUDA bool interpret_and_tell(const F &f, Env &env, L &value, IDiagnostics &diagnostics, TellAlloc tell_alloc=TellAlloc{})
Definition: interpretation.hpp:145
CUDA bool ginterpret_in(const A &a, const F &f, Env &env, I &intermediate, IDiagnostics &diagnostics)
Definition: interpretation.hpp:35