summaryrefslogtreecommitdiff
path: root/src/theory/fp/fp_converter.h
blob: 344dcf926ac24671229331f5c0378a6194f3b39a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
/*********************                                                        */
/*! \file fp_converter.h
 ** \verbatim
 ** Top contributors (to current version):
 **   Martin Brain
 ** This file is part of the CVC4 project.
 ** Copyright (c) 2009-2019 by the authors listed in the file AUTHORS
 ** in the top-level source directory) and their institutional affiliations.
 ** All rights reserved.  See the file COPYING in the top-level source
 ** directory for licensing information.\endverbatim
 **
 ** \brief Converts floating-point nodes to bit-vector expressions.
 **
 ** Uses the symfpu library to convert from floating-point operations to
 ** bit-vectors and propositions allowing the theory to be solved by
 ** 'bit-blasting'.
 **/

#include "cvc4_private.h"

#ifndef CVC4__THEORY__FP__FP_CONVERTER_H
#define CVC4__THEORY__FP__FP_CONVERTER_H

#include "base/check.h"
#include "context/cdhashmap.h"
#include "context/cdlist.h"
#include "expr/node.h"
#include "expr/node_builder.h"
#include "expr/type.h"
#include "theory/valuation.h"
#include "util/bitvector.h"
#include "util/floatingpoint.h"
#include "util/hash.h"

#ifdef CVC4_USE_SYMFPU
#include "symfpu/core/unpackedFloat.h"
#endif

#ifdef CVC4_SYM_SYMBOLIC_EVAL
// This allows debugging of the CVC4 symbolic back-end.
// By enabling this and disabling constant folding in the rewriter,
// SMT files that have operations on constants will be evaluated
// during the encoding step, which means that the expressions
// generated by the symbolic back-end can be debugged with gdb.
#include "theory/rewriter.h"
#endif

namespace CVC4 {
namespace theory {
namespace fp {

typedef PairHashFunction<TypeNode, TypeNode, TypeNodeHashFunction,
                         TypeNodeHashFunction>
    PairTypeNodeHashFunction;

/**
 * This is a symfpu symbolic "back-end".  It allows the library to be used to
 * construct bit-vector expressions that compute floating-point operations.
 * This is effectively the glue between symfpu's notion of "signed bit-vector"
 * and CVC4's node.
 */
namespace symfpuSymbolic {

// Forward declarations of the wrapped types so that traits can be defined early
// and used in the implementations
class symbolicRoundingMode;
class floatingPointTypeInfo;
class symbolicProposition;
template <bool T>
class symbolicBitVector;

// This is the template parameter for symfpu's templates.
class traits
{
 public:
  // The six key types that symfpu uses.
  typedef unsigned bwt;
  typedef symbolicRoundingMode rm;
  typedef floatingPointTypeInfo fpt;
  typedef symbolicProposition prop;
  typedef symbolicBitVector<true> sbv;
  typedef symbolicBitVector<false> ubv;

  // Give concrete instances (wrapped nodes) for each rounding mode.
  static symbolicRoundingMode RNE(void);
  static symbolicRoundingMode RNA(void);
  static symbolicRoundingMode RTP(void);
  static symbolicRoundingMode RTN(void);
  static symbolicRoundingMode RTZ(void);

  // Properties used by symfpu
  static void precondition(const bool b);
  static void postcondition(const bool b);
  static void invariant(const bool b);
  static void precondition(const prop &p);
  static void postcondition(const prop &p);
  static void invariant(const prop &p);
};

// Use the same type names as symfpu.
typedef traits::bwt bwt;

/**
 * Wrap the CVC4::Node types so that we can debug issues with this back-end
 */
class nodeWrapper : public Node
{
 protected:
/* CVC4_SYM_SYMBOLIC_EVAL is for debugging CVC4 symbolic back-end issues.
 * Enable this and disabling constant folding will mean that operations
 * that are input with constant args are 'folded' using the symbolic encoding
 * allowing them to be traced via GDB.
 */
#ifdef CVC4_SYM_SYMBOLIC_EVAL
  nodeWrapper(const Node &n) : Node(theory::Rewriter::rewrite(n)) {}
#else
  nodeWrapper(const Node &n) : Node(n) {}
#endif
};

class symbolicProposition : public nodeWrapper
{
 protected:
  bool checkNodeType(const TNode node);

#ifdef CVC4_USE_SYMFPU
  friend ::symfpu::ite<symbolicProposition, symbolicProposition>;  // For ITE
#endif

 public:
  symbolicProposition(const Node n);
  symbolicProposition(bool v);
  symbolicProposition(const symbolicProposition &old);

  symbolicProposition operator!(void)const;
  symbolicProposition operator&&(const symbolicProposition &op) const;
  symbolicProposition operator||(const symbolicProposition &op) const;
  symbolicProposition operator==(const symbolicProposition &op) const;
  symbolicProposition operator^(const symbolicProposition &op) const;
};

class symbolicRoundingMode : public nodeWrapper
{
 protected:
  bool checkNodeType(const TNode n);

#ifdef CVC4_USE_SYMFPU
  friend ::symfpu::ite<symbolicProposition, symbolicRoundingMode>;  // For ITE
#endif

 public:
  symbolicRoundingMode(const Node n);
  symbolicRoundingMode(const unsigned v);
  symbolicRoundingMode(const symbolicRoundingMode &old);

  symbolicProposition valid(void) const;
  symbolicProposition operator==(const symbolicRoundingMode &op) const;
};

// Type function for mapping between types
template <bool T>
struct signedToLiteralType;

template <>
struct signedToLiteralType<true>
{
  typedef int literalType;
};
template <>
struct signedToLiteralType<false>
{
  typedef unsigned int literalType;
};

template <bool isSigned>
class symbolicBitVector : public nodeWrapper
{
 protected:
  typedef typename signedToLiteralType<isSigned>::literalType literalType;

  Node boolNodeToBV(Node node) const;
  Node BVToBoolNode(Node node) const;

  Node fromProposition(Node node) const;
  Node toProposition(Node node) const;
  bool checkNodeType(const TNode n);
  friend symbolicBitVector<!isSigned>;  // To allow conversion between the types

#ifdef CVC4_USE_SYMFPU
  friend ::symfpu::ite<symbolicProposition,
                       symbolicBitVector<isSigned> >;  // For ITE
#endif

 public:
  symbolicBitVector(const Node n);
  symbolicBitVector(const bwt w, const unsigned v);
  symbolicBitVector(const symbolicProposition &p);
  symbolicBitVector(const symbolicBitVector<isSigned> &old);
  symbolicBitVector(const BitVector &old);

  bwt getWidth(void) const;

  /*** Constant creation and test ***/
  static symbolicBitVector<isSigned> one(const bwt &w);
  static symbolicBitVector<isSigned> zero(const bwt &w);
  static symbolicBitVector<isSigned> allOnes(const bwt &w);

  symbolicProposition isAllOnes() const;
  symbolicProposition isAllZeros() const;

  static symbolicBitVector<isSigned> maxValue(const bwt &w);
  static symbolicBitVector<isSigned> minValue(const bwt &w);

  /*** Operators ***/
  symbolicBitVector<isSigned> operator<<(
      const symbolicBitVector<isSigned> &op) const;
  symbolicBitVector<isSigned> operator>>(
      const symbolicBitVector<isSigned> &op) const;
  symbolicBitVector<isSigned> operator|(
      const symbolicBitVector<isSigned> &op) const;
  symbolicBitVector<isSigned> operator&(
      const symbolicBitVector<isSigned> &op) const;
  symbolicBitVector<isSigned> operator+(
      const symbolicBitVector<isSigned> &op) const;
  symbolicBitVector<isSigned> operator-(
      const symbolicBitVector<isSigned> &op) const;
  symbolicBitVector<isSigned> operator*(
      const symbolicBitVector<isSigned> &op) const;
  symbolicBitVector<isSigned> operator/(
      const symbolicBitVector<isSigned> &op) const;
  symbolicBitVector<isSigned> operator%(
      const symbolicBitVector<isSigned> &op) const;
  symbolicBitVector<isSigned> operator-(void) const;
  symbolicBitVector<isSigned> operator~(void)const;
  symbolicBitVector<isSigned> increment() const;
  symbolicBitVector<isSigned> decrement() const;
  symbolicBitVector<isSigned> signExtendRightShift(
      const symbolicBitVector<isSigned> &op) const;

  /*** Modular operations ***/
  // This back-end doesn't do any overflow checking so these are the same as
  // other operations
  symbolicBitVector<isSigned> modularLeftShift(
      const symbolicBitVector<isSigned> &op) const;
  symbolicBitVector<isSigned> modularRightShift(
      const symbolicBitVector<isSigned> &op) const;
  symbolicBitVector<isSigned> modularIncrement() const;
  symbolicBitVector<isSigned> modularDecrement() const;
  symbolicBitVector<isSigned> modularAdd(
      const symbolicBitVector<isSigned> &op) const;
  symbolicBitVector<isSigned> modularNegate() const;

  /*** Comparisons ***/
  symbolicProposition operator==(const symbolicBitVector<isSigned> &op) const;
  symbolicProposition operator<=(const symbolicBitVector<isSigned> &op) const;
  symbolicProposition operator>=(const symbolicBitVector<isSigned> &op) const;
  symbolicProposition operator<(const symbolicBitVector<isSigned> &op) const;
  symbolicProposition operator>(const symbolicBitVector<isSigned> &op) const;

  /*** Type conversion ***/
  // CVC4 nodes make no distinction between signed and unsigned, thus these are
  // trivial
  symbolicBitVector<true> toSigned(void) const;
  symbolicBitVector<false> toUnsigned(void) const;

  /*** Bit hacks ***/
  symbolicBitVector<isSigned> extend(bwt extension) const;
  symbolicBitVector<isSigned> contract(bwt reduction) const;
  symbolicBitVector<isSigned> resize(bwt newSize) const;
  symbolicBitVector<isSigned> matchWidth(
      const symbolicBitVector<isSigned> &op) const;
  symbolicBitVector<isSigned> append(
      const symbolicBitVector<isSigned> &op) const;

  // Inclusive of end points, thus if the same, extracts just one bit
  symbolicBitVector<isSigned> extract(bwt upper, bwt lower) const;
};

// Use the same type information as the literal back-end but add an interface to
// TypeNodes for convenience.
class floatingPointTypeInfo : public FloatingPointSize
{
 public:
  floatingPointTypeInfo(const TypeNode t);
  floatingPointTypeInfo(unsigned exp, unsigned sig);
  floatingPointTypeInfo(const floatingPointTypeInfo &old);

  TypeNode getTypeNode(void) const;
};
}

/**
 * This class uses SymFPU to convert an expression containing floating-point
 * kinds and operations into a logically equivalent form with bit-vector
 * operations replacing the floating-point ones.  It also has a getValue method
 * to produce an expression which will reconstruct the value of the
 * floating-point terms from a valuation.
 *
 * Internally it caches all of the unpacked floats so that unnecessary packing
 * and unpacking operations are avoided and to make best use of structural
 * sharing.
 */
class FpConverter
{
 protected:
#ifdef CVC4_USE_SYMFPU
  typedef symfpuSymbolic::traits traits;
  typedef ::symfpu::unpackedFloat<symfpuSymbolic::traits> uf;
  typedef symfpuSymbolic::traits::rm rm;
  typedef symfpuSymbolic::traits::fpt fpt;
  typedef symfpuSymbolic::traits::prop prop;
  typedef symfpuSymbolic::traits::ubv ubv;
  typedef symfpuSymbolic::traits::sbv sbv;

  typedef context::CDHashMap<Node, uf, NodeHashFunction> fpMap;
  typedef context::CDHashMap<Node, rm, NodeHashFunction> rmMap;
  typedef context::CDHashMap<Node, prop, NodeHashFunction> boolMap;
  typedef context::CDHashMap<Node, ubv, NodeHashFunction> ubvMap;
  typedef context::CDHashMap<Node, sbv, NodeHashFunction> sbvMap;

  fpMap d_fpMap;
  rmMap d_rmMap;
  boolMap d_boolMap;
  ubvMap d_ubvMap;
  sbvMap d_sbvMap;

  /* These functions take a symfpu object and convert it to a node.
   * These should ensure that constant folding it will give a
   * constant of the right type.
   */

  Node ufToNode(const fpt &, const uf &) const;
  Node rmToNode(const rm &) const;
  Node propToNode(const prop &) const;
  Node ubvToNode(const ubv &) const;
  Node sbvToNode(const sbv &) const;

  /* Creates the relevant components for a variable */
  uf buildComponents(TNode current);
#endif

 public:
  context::CDList<Node> d_additionalAssertions;

  FpConverter(context::UserContext *);

  /** Adds a node to the conversion, returns the converted node */
  Node convert(TNode);

  /** Gives the node representing the value of a given variable */
  Node getValue(Valuation &, TNode);
};

}  // namespace fp
}  // namespace theory
}  // namespace CVC4

#endif /* CVC4__THEORY__FP__THEORY_FP_H */
generated by cgit on debian on lair
contact matthew@masot.net with questions or feedback