1 |
|
/****************************************************************************** |
2 |
|
* Top contributors (to current version): |
3 |
|
* Martin Brain, Mathias Preiner, Aina Niemetz |
4 |
|
* |
5 |
|
* This file is part of the cvc5 project. |
6 |
|
* |
7 |
|
* Copyright (c) 2009-2021 by the authors listed in the file AUTHORS |
8 |
|
* in the top-level source directory and their institutional affiliations. |
9 |
|
* All rights reserved. See the file COPYING in the top-level source |
10 |
|
* directory for licensing information. |
11 |
|
* **************************************************************************** |
12 |
|
* |
13 |
|
* Converts floating-point nodes to bit-vector expressions. |
14 |
|
* |
15 |
|
* Uses the symfpu library to convert from floating-point operations to |
16 |
|
* bit-vectors and propositions allowing the theory to be solved by |
17 |
|
* 'bit-blasting'. |
18 |
|
* |
19 |
|
* !!! This header is not to be included in any other headers !!! |
20 |
|
*/ |
21 |
|
|
22 |
|
#include "cvc5_private.h" |
23 |
|
|
24 |
|
#ifndef CVC5__THEORY__FP__FP_CONVERTER_H |
25 |
|
#define CVC5__THEORY__FP__FP_CONVERTER_H |
26 |
|
|
27 |
|
#include "context/cdhashmap.h" |
28 |
|
#include "context/cdlist.h" |
29 |
|
#include "expr/node.h" |
30 |
|
#include "expr/type_node.h" |
31 |
|
#include "theory/valuation.h" |
32 |
|
#include "util/bitvector.h" |
33 |
|
#include "util/floatingpoint_size.h" |
34 |
|
#include "util/hash.h" |
35 |
|
|
36 |
|
#ifdef CVC5_USE_SYMFPU |
37 |
|
#include "symfpu/core/unpackedFloat.h" |
38 |
|
#endif |
39 |
|
|
40 |
|
#ifdef CVC5_SYM_SYMBOLIC_EVAL |
41 |
|
// This allows debugging of the cvc5 symbolic back-end. |
42 |
|
// By enabling this and disabling constant folding in the rewriter, |
43 |
|
// SMT files that have operations on constants will be evaluated |
44 |
|
// during the encoding step, which means that the expressions |
45 |
|
// generated by the symbolic back-end can be debugged with gdb. |
46 |
|
#include "theory/rewriter.h" |
47 |
|
#endif |
48 |
|
|
49 |
|
namespace cvc5 { |
50 |
|
namespace theory { |
51 |
|
namespace fp { |
52 |
|
|
53 |
|
/** |
54 |
|
* This is a symfpu symbolic "back-end". It allows the library to be used to |
55 |
|
* construct bit-vector expressions that compute floating-point operations. |
56 |
|
* This is effectively the glue between symfpu's notion of "signed bit-vector" |
57 |
|
* and cvc5's node. |
58 |
|
*/ |
59 |
|
namespace symfpuSymbolic { |
60 |
|
|
61 |
|
// Forward declarations of the wrapped types so that traits can be defined early |
62 |
|
// and used in the implementations |
63 |
|
class symbolicRoundingMode; |
64 |
|
class floatingPointTypeInfo; |
65 |
|
class symbolicProposition; |
66 |
|
template <bool T> |
67 |
|
class symbolicBitVector; |
68 |
|
|
69 |
|
// This is the template parameter for symfpu's templates. |
70 |
|
class traits |
71 |
|
{ |
72 |
|
public: |
73 |
|
// The six key types that symfpu uses. |
74 |
|
typedef unsigned bwt; |
75 |
|
typedef symbolicRoundingMode rm; |
76 |
|
typedef floatingPointTypeInfo fpt; |
77 |
|
typedef symbolicProposition prop; |
78 |
|
typedef symbolicBitVector<true> sbv; |
79 |
|
typedef symbolicBitVector<false> ubv; |
80 |
|
|
81 |
|
// Give concrete instances (wrapped nodes) for each rounding mode. |
82 |
|
static symbolicRoundingMode RNE(void); |
83 |
|
static symbolicRoundingMode RNA(void); |
84 |
|
static symbolicRoundingMode RTP(void); |
85 |
|
static symbolicRoundingMode RTN(void); |
86 |
|
static symbolicRoundingMode RTZ(void); |
87 |
|
|
88 |
|
// Properties used by symfpu |
89 |
|
static void precondition(const bool b); |
90 |
|
static void postcondition(const bool b); |
91 |
|
static void invariant(const bool b); |
92 |
|
static void precondition(const prop &p); |
93 |
|
static void postcondition(const prop &p); |
94 |
|
static void invariant(const prop &p); |
95 |
|
}; |
96 |
|
|
97 |
|
// Use the same type names as symfpu. |
98 |
|
typedef traits::bwt bwt; |
99 |
|
|
100 |
|
/** |
101 |
|
* Wrap the cvc5::Node types so that we can debug issues with this back-end |
102 |
|
*/ |
103 |
1473010 |
class nodeWrapper : public Node |
104 |
|
{ |
105 |
|
protected: |
106 |
|
/* CVC5_SYM_SYMBOLIC_EVAL is for debugging cvc5 symbolic back-end issues. |
107 |
|
* Enable this and disabling constant folding will mean that operations |
108 |
|
* that are input with constant args are 'folded' using the symbolic encoding |
109 |
|
* allowing them to be traced via GDB. |
110 |
|
*/ |
111 |
|
#ifdef CVC5_SYM_SYMBOLIC_EVAL |
112 |
|
nodeWrapper(const Node &n) : Node(theory::Rewriter::rewrite(n)) {} |
113 |
|
#else |
114 |
1415874 |
nodeWrapper(const Node &n) : Node(n) {} |
115 |
|
#endif |
116 |
|
}; |
117 |
|
|
118 |
532985 |
class symbolicProposition : public nodeWrapper |
119 |
|
{ |
120 |
|
protected: |
121 |
|
bool checkNodeType(const TNode node); |
122 |
|
|
123 |
|
#ifdef CVC5_USE_SYMFPU |
124 |
|
friend ::symfpu::ite<symbolicProposition, symbolicProposition>; // For ITE |
125 |
|
#endif |
126 |
|
|
127 |
|
public: |
128 |
|
symbolicProposition(const Node n); |
129 |
|
symbolicProposition(bool v); |
130 |
|
symbolicProposition(const symbolicProposition &old); |
131 |
|
|
132 |
|
symbolicProposition operator!(void)const; |
133 |
|
symbolicProposition operator&&(const symbolicProposition &op) const; |
134 |
|
symbolicProposition operator||(const symbolicProposition &op) const; |
135 |
|
symbolicProposition operator==(const symbolicProposition &op) const; |
136 |
|
symbolicProposition operator^(const symbolicProposition &op) const; |
137 |
|
}; |
138 |
|
|
139 |
1847 |
class symbolicRoundingMode : public nodeWrapper |
140 |
|
{ |
141 |
|
protected: |
142 |
|
bool checkNodeType(const TNode n); |
143 |
|
|
144 |
|
#ifdef CVC5_USE_SYMFPU |
145 |
|
friend ::symfpu::ite<symbolicProposition, symbolicRoundingMode>; // For ITE |
146 |
|
#endif |
147 |
|
|
148 |
|
public: |
149 |
|
symbolicRoundingMode(const Node n); |
150 |
|
symbolicRoundingMode(const unsigned v); |
151 |
|
symbolicRoundingMode(const symbolicRoundingMode &old); |
152 |
|
|
153 |
|
symbolicProposition valid(void) const; |
154 |
|
symbolicProposition operator==(const symbolicRoundingMode &op) const; |
155 |
|
}; |
156 |
|
|
157 |
|
// Type function for mapping between types |
158 |
|
template <bool T> |
159 |
|
struct signedToLiteralType; |
160 |
|
|
161 |
|
template <> |
162 |
|
struct signedToLiteralType<true> |
163 |
|
{ |
164 |
|
typedef int literalType; |
165 |
|
}; |
166 |
|
template <> |
167 |
|
struct signedToLiteralType<false> |
168 |
|
{ |
169 |
|
typedef unsigned int literalType; |
170 |
|
}; |
171 |
|
|
172 |
|
template <bool isSigned> |
173 |
911330 |
class symbolicBitVector : public nodeWrapper |
174 |
|
{ |
175 |
|
protected: |
176 |
|
typedef typename signedToLiteralType<isSigned>::literalType literalType; |
177 |
|
|
178 |
|
Node boolNodeToBV(Node node) const; |
179 |
|
Node BVToBoolNode(Node node) const; |
180 |
|
|
181 |
|
Node fromProposition(Node node) const; |
182 |
|
Node toProposition(Node node) const; |
183 |
|
bool checkNodeType(const TNode n); |
184 |
|
friend symbolicBitVector<!isSigned>; // To allow conversion between the types |
185 |
|
|
186 |
|
#ifdef CVC5_USE_SYMFPU |
187 |
|
friend ::symfpu::ite<symbolicProposition, |
188 |
|
symbolicBitVector<isSigned> >; // For ITE |
189 |
|
#endif |
190 |
|
|
191 |
|
public: |
192 |
|
symbolicBitVector(const Node n); |
193 |
|
symbolicBitVector(const bwt w, const unsigned v); |
194 |
|
symbolicBitVector(const symbolicProposition &p); |
195 |
|
symbolicBitVector(const symbolicBitVector<isSigned> &old); |
196 |
|
symbolicBitVector(const BitVector &old); |
197 |
|
|
198 |
|
bwt getWidth(void) const; |
199 |
|
|
200 |
|
/*** Constant creation and test ***/ |
201 |
|
static symbolicBitVector<isSigned> one(const bwt &w); |
202 |
|
static symbolicBitVector<isSigned> zero(const bwt &w); |
203 |
|
static symbolicBitVector<isSigned> allOnes(const bwt &w); |
204 |
|
|
205 |
|
symbolicProposition isAllOnes() const; |
206 |
|
symbolicProposition isAllZeros() const; |
207 |
|
|
208 |
|
static symbolicBitVector<isSigned> maxValue(const bwt &w); |
209 |
|
static symbolicBitVector<isSigned> minValue(const bwt &w); |
210 |
|
|
211 |
|
/*** Operators ***/ |
212 |
|
symbolicBitVector<isSigned> operator<<( |
213 |
|
const symbolicBitVector<isSigned> &op) const; |
214 |
|
symbolicBitVector<isSigned> operator>>( |
215 |
|
const symbolicBitVector<isSigned> &op) const; |
216 |
|
symbolicBitVector<isSigned> operator|( |
217 |
|
const symbolicBitVector<isSigned> &op) const; |
218 |
|
symbolicBitVector<isSigned> operator&( |
219 |
|
const symbolicBitVector<isSigned> &op) const; |
220 |
|
symbolicBitVector<isSigned> operator+( |
221 |
|
const symbolicBitVector<isSigned> &op) const; |
222 |
|
symbolicBitVector<isSigned> operator-( |
223 |
|
const symbolicBitVector<isSigned> &op) const; |
224 |
|
symbolicBitVector<isSigned> operator*( |
225 |
|
const symbolicBitVector<isSigned> &op) const; |
226 |
|
symbolicBitVector<isSigned> operator/( |
227 |
|
const symbolicBitVector<isSigned> &op) const; |
228 |
|
symbolicBitVector<isSigned> operator%( |
229 |
|
const symbolicBitVector<isSigned> &op) const; |
230 |
|
symbolicBitVector<isSigned> operator-(void) const; |
231 |
|
symbolicBitVector<isSigned> operator~(void)const; |
232 |
|
symbolicBitVector<isSigned> increment() const; |
233 |
|
symbolicBitVector<isSigned> decrement() const; |
234 |
|
symbolicBitVector<isSigned> signExtendRightShift( |
235 |
|
const symbolicBitVector<isSigned> &op) const; |
236 |
|
|
237 |
|
/*** Modular operations ***/ |
238 |
|
// This back-end doesn't do any overflow checking so these are the same as |
239 |
|
// other operations |
240 |
|
symbolicBitVector<isSigned> modularLeftShift( |
241 |
|
const symbolicBitVector<isSigned> &op) const; |
242 |
|
symbolicBitVector<isSigned> modularRightShift( |
243 |
|
const symbolicBitVector<isSigned> &op) const; |
244 |
|
symbolicBitVector<isSigned> modularIncrement() const; |
245 |
|
symbolicBitVector<isSigned> modularDecrement() const; |
246 |
|
symbolicBitVector<isSigned> modularAdd( |
247 |
|
const symbolicBitVector<isSigned> &op) const; |
248 |
|
symbolicBitVector<isSigned> modularNegate() const; |
249 |
|
|
250 |
|
/*** Comparisons ***/ |
251 |
|
symbolicProposition operator==(const symbolicBitVector<isSigned> &op) const; |
252 |
|
symbolicProposition operator<=(const symbolicBitVector<isSigned> &op) const; |
253 |
|
symbolicProposition operator>=(const symbolicBitVector<isSigned> &op) const; |
254 |
|
symbolicProposition operator<(const symbolicBitVector<isSigned> &op) const; |
255 |
|
symbolicProposition operator>(const symbolicBitVector<isSigned> &op) const; |
256 |
|
|
257 |
|
/*** Type conversion ***/ |
258 |
|
// cvc5 nodes make no distinction between signed and unsigned, thus these are |
259 |
|
// trivial |
260 |
|
symbolicBitVector<true> toSigned(void) const; |
261 |
|
symbolicBitVector<false> toUnsigned(void) const; |
262 |
|
|
263 |
|
/*** Bit hacks ***/ |
264 |
|
symbolicBitVector<isSigned> extend(bwt extension) const; |
265 |
|
symbolicBitVector<isSigned> contract(bwt reduction) const; |
266 |
|
symbolicBitVector<isSigned> resize(bwt newSize) const; |
267 |
|
symbolicBitVector<isSigned> matchWidth( |
268 |
|
const symbolicBitVector<isSigned> &op) const; |
269 |
|
symbolicBitVector<isSigned> append( |
270 |
|
const symbolicBitVector<isSigned> &op) const; |
271 |
|
|
272 |
|
// Inclusive of end points, thus if the same, extracts just one bit |
273 |
|
symbolicBitVector<isSigned> extract(bwt upper, bwt lower) const; |
274 |
|
}; |
275 |
|
|
276 |
|
// Use the same type information as the literal back-end but add an interface to |
277 |
|
// TypeNodes for convenience. |
278 |
|
class floatingPointTypeInfo : public FloatingPointSize |
279 |
|
{ |
280 |
|
public: |
281 |
|
floatingPointTypeInfo(const TypeNode t); |
282 |
|
floatingPointTypeInfo(unsigned exp, unsigned sig); |
283 |
|
floatingPointTypeInfo(const floatingPointTypeInfo &old); |
284 |
|
|
285 |
|
TypeNode getTypeNode(void) const; |
286 |
|
}; |
287 |
|
} |
288 |
|
|
289 |
|
/** |
290 |
|
* This class uses SymFPU to convert an expression containing floating-point |
291 |
|
* kinds and operations into a logically equivalent form with bit-vector |
292 |
|
* operations replacing the floating-point ones. It also has a getValue method |
293 |
|
* to produce an expression which will reconstruct the value of the |
294 |
|
* floating-point terms from a valuation. |
295 |
|
* |
296 |
|
* Internally it caches all of the unpacked floats so that unnecessary packing |
297 |
|
* and unpacking operations are avoided and to make best use of structural |
298 |
|
* sharing. |
299 |
|
*/ |
300 |
|
class FpConverter |
301 |
|
{ |
302 |
|
public: |
303 |
|
/** Constructor. */ |
304 |
|
FpConverter(context::UserContext*); |
305 |
|
/** Destructor. */ |
306 |
|
~FpConverter(); |
307 |
|
|
308 |
|
/** Adds a node to the conversion, returns the converted node */ |
309 |
|
Node convert(TNode); |
310 |
|
|
311 |
|
/** Gives the node representing the value of a given variable */ |
312 |
|
Node getValue(Valuation&, TNode); |
313 |
|
|
314 |
|
context::CDList<Node> d_additionalAssertions; |
315 |
|
|
316 |
|
protected: |
317 |
|
#ifdef CVC5_USE_SYMFPU |
318 |
|
typedef symfpuSymbolic::traits traits; |
319 |
|
typedef ::symfpu::unpackedFloat<symfpuSymbolic::traits> uf; |
320 |
|
typedef symfpuSymbolic::traits::rm rm; |
321 |
|
typedef symfpuSymbolic::traits::fpt fpt; |
322 |
|
typedef symfpuSymbolic::traits::prop prop; |
323 |
|
typedef symfpuSymbolic::traits::ubv ubv; |
324 |
|
typedef symfpuSymbolic::traits::sbv sbv; |
325 |
|
|
326 |
|
typedef context::CDHashMap<Node, uf> fpMap; |
327 |
|
typedef context::CDHashMap<Node, rm> rmMap; |
328 |
|
typedef context::CDHashMap<Node, prop> boolMap; |
329 |
|
typedef context::CDHashMap<Node, ubv> ubvMap; |
330 |
|
typedef context::CDHashMap<Node, sbv> sbvMap; |
331 |
|
|
332 |
|
fpMap d_fpMap; |
333 |
|
rmMap d_rmMap; |
334 |
|
boolMap d_boolMap; |
335 |
|
ubvMap d_ubvMap; |
336 |
|
sbvMap d_sbvMap; |
337 |
|
|
338 |
|
/* These functions take a symfpu object and convert it to a node. |
339 |
|
* These should ensure that constant folding it will give a |
340 |
|
* constant of the right type. |
341 |
|
*/ |
342 |
|
|
343 |
|
Node ufToNode(const fpt &, const uf &) const; |
344 |
|
Node rmToNode(const rm &) const; |
345 |
|
Node propToNode(const prop &) const; |
346 |
|
Node ubvToNode(const ubv &) const; |
347 |
|
Node sbvToNode(const sbv &) const; |
348 |
|
|
349 |
|
/* Creates the relevant components for a variable */ |
350 |
|
uf buildComponents(TNode current); |
351 |
|
#endif |
352 |
|
}; |
353 |
|
|
354 |
|
} // namespace fp |
355 |
|
} // namespace theory |
356 |
|
} // namespace cvc5 |
357 |
|
|
358 |
|
#endif /* CVC5__THEORY__FP__THEORY_FP_H */ |