1 |
|
/****************************************************************************** |
2 |
|
* Top contributors (to current version): |
3 |
|
* Andrew Reynolds, Morgan Deters, Tim King |
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 |
|
* A class representing a datatype definition. |
14 |
|
*/ |
15 |
|
|
16 |
|
#include "cvc5_private.h" |
17 |
|
|
18 |
|
#ifndef CVC5__EXPR__DTYPE_H |
19 |
|
#define CVC5__EXPR__DTYPE_H |
20 |
|
|
21 |
|
#include <map> |
22 |
|
#include <string> |
23 |
|
#include <vector> |
24 |
|
#include "expr/attribute.h" |
25 |
|
#include "expr/node.h" |
26 |
|
#include "expr/type_node.h" |
27 |
|
|
28 |
|
namespace cvc5 { |
29 |
|
|
30 |
|
// ----------------------- datatype attributes |
31 |
|
/** |
32 |
|
* Attribute for the index of an expression within a datatype, which is either: |
33 |
|
* (1) If the expression is a constructor, then its index refers to its |
34 |
|
* placement in the constructor list of the datatype that owns it, (2) If the |
35 |
|
* expression is a selector, then its index refers to its placement in the |
36 |
|
* argument list of the constructor that owns it. |
37 |
|
*/ |
38 |
|
struct DTypeIndexTag |
39 |
|
{ |
40 |
|
}; |
41 |
|
typedef expr::Attribute<DTypeIndexTag, size_t> DTypeIndexAttr; |
42 |
|
/** |
43 |
|
* Attribute for the constructor index of a selector. This indicates the index |
44 |
|
* (DTypeIndexAttr) of the constructor that owns this selector. |
45 |
|
*/ |
46 |
|
struct DTypeConsIndexTag |
47 |
|
{ |
48 |
|
}; |
49 |
|
typedef expr::Attribute<DTypeConsIndexTag, size_t> DTypeConsIndexAttr; |
50 |
|
// ----------------------- end datatype attributes |
51 |
|
|
52 |
|
class DTypeConstructor; |
53 |
|
|
54 |
|
/** |
55 |
|
* The Node-level representation of an inductive datatype, which currently |
56 |
|
* resides within the Expr-level Datatype class (expr/datatype.h). |
57 |
|
* |
58 |
|
* Notice that this class is a specification for a datatype, and is not |
59 |
|
* itself a type. The type that this specification corresponds to can be |
60 |
|
* retrieved (after resolution as described in the following) via getTypeNode. |
61 |
|
* |
62 |
|
* This is far more complicated than it first seems. Consider this |
63 |
|
* datatype definition: |
64 |
|
* |
65 |
|
* DATATYPE nat = |
66 |
|
* succ(pred: nat) |
67 |
|
* | zero |
68 |
|
* END; |
69 |
|
* |
70 |
|
* You cannot define "nat" until you have a Type for it, but you |
71 |
|
* cannot have a Type for it until you fill in the type of the "pred" |
72 |
|
* selector, which needs the Type. So we have a chicken-and-egg |
73 |
|
* problem. It's even more complicated when we have mutual recursion |
74 |
|
* between datatypes, since the CVC presentation language does not |
75 |
|
* require forward-declarations. Here, we define trees of lists that |
76 |
|
* contain trees of lists (etc): |
77 |
|
* |
78 |
|
* DATATYPE |
79 |
|
* tree = node(left: tree, right: tree) | leaf(list), |
80 |
|
* list = cons(car: tree, cdr: list) | nil |
81 |
|
* END; |
82 |
|
* |
83 |
|
* We build DType objects to describe "tree" and "list", and their constructors |
84 |
|
* and constructor arguments, but leave any unknown types (including |
85 |
|
* self-references) in an "unresolved" state. After parsing the whole DATATYPE |
86 |
|
* block, we create a TypeNode through ExprManager::mkMutualDatatypeTypes(). |
87 |
|
* The ExprManager creates a Type for each, but before "releasing" this type |
88 |
|
* into the wild, it does a round of in-place "resolution" on each DType by |
89 |
|
* calling DType::resolve() with a map of string -> TypeNode to |
90 |
|
* allow the datatype to construct the necessary testers and selectors. |
91 |
|
* |
92 |
|
* An additional point to make is that we want to ease the burden on |
93 |
|
* both the parser AND the users of the cvc5 API, so this class takes |
94 |
|
* on the task of generating its own selectors and testers, for |
95 |
|
* instance. That means that, after reifying the DType with the |
96 |
|
* NodeManager, the parser needs to go through the (now-resolved) |
97 |
|
* DType and request the constructor, selector, and tester terms. |
98 |
|
* See src/parser/parser.cpp for how this is done. For API usage |
99 |
|
* ideas, see test/unit/util/datatype_black.h. |
100 |
|
* |
101 |
|
* DTypes may also be defined parametrically, such as this example: |
102 |
|
* |
103 |
|
* DATATYPE |
104 |
|
* list[T] = cons(car : T, cdr : list[T]) | null, |
105 |
|
* tree = node(children : list[tree]) | leaf |
106 |
|
* END; |
107 |
|
* |
108 |
|
* Here, the definition of the parametric datatype list, where T is a type |
109 |
|
* variable. In other words, this defines a family of types list[C] where C is |
110 |
|
* any concrete type. DTypes can be parameterized over multiple type variables |
111 |
|
* using the syntax sym[ T1, ..., Tn ] = ..., |
112 |
|
* |
113 |
|
*/ |
114 |
19589 |
class DType |
115 |
|
{ |
116 |
|
friend class DTypeConstructor; |
117 |
|
friend class NodeManager; // for access to resolve() |
118 |
|
|
119 |
|
public: |
120 |
|
/** |
121 |
|
* Get the datatype of a constructor, selector, or tester operator. |
122 |
|
*/ |
123 |
|
static const DType& datatypeOf(Node item); |
124 |
|
|
125 |
|
/** |
126 |
|
* Get the index of a constructor or tester in its datatype, or the |
127 |
|
* index of a selector in its constructor. (Zero is always the |
128 |
|
* first index.) |
129 |
|
*/ |
130 |
|
static size_t indexOf(Node item); |
131 |
|
|
132 |
|
/** |
133 |
|
* Get the index of constructor corresponding to selector. (Zero is |
134 |
|
* always the first index.) |
135 |
|
*/ |
136 |
|
static size_t cindexOf(Node item); |
137 |
|
|
138 |
|
/** |
139 |
|
* Same as above, but without checks. These methods should be used by |
140 |
|
* internal (Node-level) code. |
141 |
|
*/ |
142 |
|
static size_t indexOfInternal(Node item); |
143 |
|
static size_t cindexOfInternal(Node item); |
144 |
|
|
145 |
|
/** Create a new DType of the given name. */ |
146 |
|
DType(std::string name, bool isCo = false); |
147 |
|
|
148 |
|
/** |
149 |
|
* Create a new DType of the given name, with the given |
150 |
|
* parameterization. |
151 |
|
*/ |
152 |
|
DType(std::string name, |
153 |
|
const std::vector<TypeNode>& params, |
154 |
|
bool isCo = false); |
155 |
|
|
156 |
|
~DType(); |
157 |
|
|
158 |
|
/** Add a constructor to this DType. |
159 |
|
* |
160 |
|
* Notice that constructor names need not |
161 |
|
* be unique; they are for convenience and pretty-printing only. |
162 |
|
*/ |
163 |
|
void addConstructor(std::shared_ptr<DTypeConstructor> c); |
164 |
|
/** add sygus constructor |
165 |
|
* |
166 |
|
* This adds a sygus constructor to this datatype, where |
167 |
|
* this datatype should be currently unresolved. Note this method is |
168 |
|
* syntactic sugar for adding a normal constructor and setting it to be a |
169 |
|
* sygus constructor, and following a naming convention that avoids |
170 |
|
* constructors with the same name. |
171 |
|
* |
172 |
|
* @param op : the builtin operator, constant, or variable that this |
173 |
|
* constructor encodes |
174 |
|
* @param cname the name of the constructor (for printing only) |
175 |
|
* @param cargs the arguments of the constructor. |
176 |
|
* It should be the case that cargs are sygus datatypes that |
177 |
|
* encode the arguments of op. For example, a sygus constructor |
178 |
|
* with op = PLUS should be such that cargs.size()>=2 and |
179 |
|
* the sygus type of cargs[i] is Real/Int for each i. |
180 |
|
* @param weight denotes the value added by the constructor when computing the |
181 |
|
* size of datatype terms. Passing a value < 0 denotes the default weight for |
182 |
|
* the constructor, which is 0 for nullary constructors and 1 for non-nullary |
183 |
|
* constructors. |
184 |
|
*/ |
185 |
|
void addSygusConstructor(Node op, |
186 |
|
const std::string& cname, |
187 |
|
const std::vector<TypeNode>& cargs, |
188 |
|
int weight = -1); |
189 |
|
|
190 |
|
/** set sygus |
191 |
|
* |
192 |
|
* This marks this datatype as a sygus datatype. |
193 |
|
* A sygus datatype is one that represents terms of type st |
194 |
|
* via a deep embedding described in Section 4 of |
195 |
|
* Reynolds et al. CAV 2015. We say that this sygus datatype |
196 |
|
* "encodes" its sygus type st in the following. |
197 |
|
* |
198 |
|
* st : the type this datatype encodes (this can be Int, Bool, etc.), |
199 |
|
* bvl : the list of arguments for the synth-fun |
200 |
|
* allow_const : whether all constants are (implicitly) allowed by the |
201 |
|
* datatype |
202 |
|
* allow_all : whether all terms are (implicitly) allowed by the datatype |
203 |
|
* |
204 |
|
* Notice that allow_const/allow_all do not reflect the constructors |
205 |
|
* for this datatype, and instead are used solely for relaxing constraints |
206 |
|
* when doing solution reconstruction (Figure 5 of Reynolds et al. |
207 |
|
* CAV 2015). |
208 |
|
*/ |
209 |
|
void setSygus(TypeNode st, Node bvl, bool allowConst, bool allowAll); |
210 |
|
|
211 |
|
/** set that this datatype is a tuple */ |
212 |
|
void setTuple(); |
213 |
|
|
214 |
|
/** set that this datatype is a record */ |
215 |
|
void setRecord(); |
216 |
|
|
217 |
|
/** Get the name of this DType. */ |
218 |
|
std::string getName() const; |
219 |
|
|
220 |
|
/** Get the number of constructors (so far) for this DType. */ |
221 |
|
size_t getNumConstructors() const; |
222 |
|
|
223 |
|
/** Is this datatype parametric? */ |
224 |
|
bool isParametric() const; |
225 |
|
|
226 |
|
/** Get the number of type parameters */ |
227 |
|
size_t getNumParameters() const; |
228 |
|
|
229 |
|
/** Get parameter */ |
230 |
|
TypeNode getParameter(size_t i) const; |
231 |
|
|
232 |
|
/** Get parameters */ |
233 |
|
std::vector<TypeNode> getParameters() const; |
234 |
|
|
235 |
|
/** is this a co-datatype? */ |
236 |
|
bool isCodatatype() const; |
237 |
|
|
238 |
|
/** is this a sygus datatype? */ |
239 |
|
bool isSygus() const; |
240 |
|
|
241 |
|
/** is this a tuple datatype? */ |
242 |
|
bool isTuple() const; |
243 |
|
|
244 |
|
/** is this a record datatype? */ |
245 |
|
bool isRecord() const; |
246 |
|
|
247 |
|
/** |
248 |
|
* Return the cardinality of this datatype. |
249 |
|
* The DType must be resolved. |
250 |
|
* |
251 |
|
* The version of this method that takes type t is required |
252 |
|
* for parametric datatypes, where t is an instantiated |
253 |
|
* parametric datatype type whose datatype is this class. |
254 |
|
*/ |
255 |
|
Cardinality getCardinality(TypeNode t) const; |
256 |
|
Cardinality getCardinality() const; |
257 |
|
|
258 |
|
/** |
259 |
|
* Return the cardinality class of the datatype. The |
260 |
|
* DType must be resolved or an assertion is violated. |
261 |
|
* |
262 |
|
* The version of this method that takes type t is required |
263 |
|
* for parametric datatypes, where t is an instantiated |
264 |
|
* parametric datatype type whose datatype is this class. |
265 |
|
*/ |
266 |
|
CardinalityClass getCardinalityClass(TypeNode t) const; |
267 |
|
CardinalityClass getCardinalityClass() const; |
268 |
|
|
269 |
|
/** |
270 |
|
* Return true iff this DType has finite cardinality. If the |
271 |
|
* datatype is not well-founded, this method returns false. The |
272 |
|
* DType must be resolved or an assertion is violated. |
273 |
|
* |
274 |
|
* The version of this method that takes type t is required |
275 |
|
* for parametric datatypes, where t is an instantiated |
276 |
|
* parametric datatype type whose datatype is this class. |
277 |
|
* |
278 |
|
* @param t The (instantiated) datatype type we are computing finiteness for |
279 |
|
* @param fmfEnabled Whether finite model finding is enabled |
280 |
|
* @return true if finite model finding is enabled |
281 |
|
*/ |
282 |
|
bool isFinite(TypeNode t, bool fmfEnabled=false) const; |
283 |
|
bool isFinite(bool fmfEnabled=false) const; |
284 |
|
|
285 |
|
/** is well-founded |
286 |
|
* |
287 |
|
* Return true iff this datatype is well-founded (there exist finite |
288 |
|
* values of this type). This datatype must be resolved or an assertion is |
289 |
|
* violated. |
290 |
|
*/ |
291 |
|
bool isWellFounded() const; |
292 |
|
/** |
293 |
|
* Does this datatype have nested recursion? This is true if this datatype |
294 |
|
* definition contains itself as an alien subfield type, or a variant |
295 |
|
* of itself as an alien subfield type (if this datatype is parametric). |
296 |
|
* For details see getAlienSubfieldTypes below. |
297 |
|
* |
298 |
|
* Notice that a type having no nested recursion may have a subfield type that |
299 |
|
* has nested recursion. |
300 |
|
*/ |
301 |
|
bool hasNestedRecursion() const; |
302 |
|
|
303 |
|
/** is recursive singleton |
304 |
|
* |
305 |
|
* Return true iff this datatype is a recursive singleton |
306 |
|
* (a recursive singleton is a recursive datatype with only |
307 |
|
* one infinite value). For details, see Reynolds et al. CADE 2015. |
308 |
|
* |
309 |
|
* The versions of these methods that takes type t is required |
310 |
|
* for parametric datatypes, where t is an instantiated |
311 |
|
* parametric datatype type whose datatype is this class. |
312 |
|
*/ |
313 |
|
bool isRecursiveSingleton(TypeNode t) const; |
314 |
|
bool isRecursiveSingleton() const; |
315 |
|
|
316 |
|
/** recursive single arguments |
317 |
|
* |
318 |
|
* Get recursive singleton argument types (uninterpreted sorts that the |
319 |
|
* cardinality of this datatype is dependent upon). For example, for : |
320 |
|
* stream := cons( head1 : U1, head2 : U2, tail : stream ) |
321 |
|
* Then, the recursive singleton argument types of stream are { U1, U2 }, |
322 |
|
* since if U1 and U2 have cardinality one, then stream has cardinality |
323 |
|
* one as well. |
324 |
|
* |
325 |
|
* The versions of these methods that takes Type t is required |
326 |
|
* for parametric datatypes, where t is an instantiated |
327 |
|
* parametric datatype type whose datatype is this class. |
328 |
|
*/ |
329 |
|
unsigned getNumRecursiveSingletonArgTypes(TypeNode t) const; |
330 |
|
TypeNode getRecursiveSingletonArgType(TypeNode t, size_t i) const; |
331 |
|
unsigned getNumRecursiveSingletonArgTypes() const; |
332 |
|
TypeNode getRecursiveSingletonArgType(size_t i) const; |
333 |
|
|
334 |
|
/** |
335 |
|
* Construct and return a ground term of this DType. The |
336 |
|
* DType must be both resolved and well-founded, or else an |
337 |
|
* exception is thrown. |
338 |
|
* |
339 |
|
* This method takes a type t, which is a datatype type whose |
340 |
|
* datatype is this class, which may be an instantiated datatype |
341 |
|
* type if this datatype is parametric. |
342 |
|
*/ |
343 |
|
Node mkGroundTerm(TypeNode t) const; |
344 |
|
/** Make ground value |
345 |
|
* |
346 |
|
* Same as above, but constructs a constant value instead of a ground term. |
347 |
|
* These two notions typically coincide. However, for uninterpreted sorts, |
348 |
|
* they do not: mkGroundTerm returns a fresh variable whereas mkValue returns |
349 |
|
* an uninterpreted constant. The motivation for mkGroundTerm is that |
350 |
|
* unintepreted constants should never appear in lemmas. The motivation for |
351 |
|
* mkGroundValue is for things like type enumeration and model construction. |
352 |
|
*/ |
353 |
|
Node mkGroundValue(TypeNode t) const; |
354 |
|
|
355 |
|
/** |
356 |
|
* Get the TypeNode associated to this DType. Can only be |
357 |
|
* called post-resolution. |
358 |
|
*/ |
359 |
|
TypeNode getTypeNode() const; |
360 |
|
|
361 |
|
/** |
362 |
|
* Get the TypeNode associated to this (parameterized) DType. Can only be |
363 |
|
* called post-resolution. |
364 |
|
*/ |
365 |
|
TypeNode getTypeNode(const std::vector<TypeNode>& params) const; |
366 |
|
|
367 |
|
/** Return true iff this DType has already been resolved. */ |
368 |
|
bool isResolved() const; |
369 |
|
|
370 |
|
/** Get the ith DTypeConstructor. */ |
371 |
|
const DTypeConstructor& operator[](size_t index) const; |
372 |
|
|
373 |
|
/** get sygus type |
374 |
|
* This gets the built-in type associated with |
375 |
|
* this sygus datatype, i.e. the type of the |
376 |
|
* term that this sygus datatype encodes. |
377 |
|
*/ |
378 |
|
TypeNode getSygusType() const; |
379 |
|
|
380 |
|
/** get sygus var list |
381 |
|
* This gets the variable list of the function |
382 |
|
* to synthesize using this sygus datatype. |
383 |
|
* For example, if we are synthesizing a binary |
384 |
|
* function f where solutions are of the form: |
385 |
|
* f = (lambda (xy) t[x,y]) |
386 |
|
* In this case, this method returns the |
387 |
|
* bound variable list containing x and y. |
388 |
|
*/ |
389 |
|
Node getSygusVarList() const; |
390 |
|
/** get sygus allow constants |
391 |
|
* |
392 |
|
* Does this sygus datatype allow constants? |
393 |
|
* Notice that this is not a property of the |
394 |
|
* constructors of this datatype. Instead, it is |
395 |
|
* an auxiliary flag (provided in the call |
396 |
|
* to setSygus). |
397 |
|
*/ |
398 |
|
bool getSygusAllowConst() const; |
399 |
|
/** get sygus allow all |
400 |
|
* |
401 |
|
* Does this sygus datatype allow all terms? |
402 |
|
* Notice that this is not a property of the |
403 |
|
* constructors of this datatype. Instead, it is |
404 |
|
* an auxiliary flag (provided in the call |
405 |
|
* to setSygus). |
406 |
|
*/ |
407 |
|
bool getSygusAllowAll() const; |
408 |
|
|
409 |
|
/** involves external type |
410 |
|
* Get whether this datatype has a subfield |
411 |
|
* in any constructor that is not a datatype type. |
412 |
|
*/ |
413 |
|
bool involvesExternalType() const; |
414 |
|
/** involves uninterpreted type |
415 |
|
* Get whether this datatype has a subfield |
416 |
|
* in any constructor that is an uninterpreted type. |
417 |
|
*/ |
418 |
|
bool involvesUninterpretedType() const; |
419 |
|
|
420 |
|
/** |
421 |
|
* Get the list of constructors. |
422 |
|
*/ |
423 |
|
const std::vector<std::shared_ptr<DTypeConstructor> >& getConstructors() |
424 |
|
const; |
425 |
|
|
426 |
|
/** prints this datatype to stream */ |
427 |
|
void toStream(std::ostream& out) const; |
428 |
|
|
429 |
|
private: |
430 |
|
/** |
431 |
|
* DTypes refer to themselves, recursively, and we have a |
432 |
|
* chicken-and-egg problem. The TypeNode around the DType |
433 |
|
* cannot exist until the DType is finalized, and the DType |
434 |
|
* cannot refer to the TypeNode representing itself until it |
435 |
|
* exists. resolve() is called by the NodeManager when a type is |
436 |
|
* ultimately requested of the DType specification (that is, when |
437 |
|
* NodeManager::mkTypeNode() or NodeManager::mkMutualTypeNodes() |
438 |
|
* is called). Has the effect of freezing the object, too; that is, |
439 |
|
* addConstructor() will fail after a call to resolve(). |
440 |
|
* |
441 |
|
* The basic goal of resolution is to assign constructors, selectors, |
442 |
|
* and testers. To do this, any UnresolvedType/SelfType references |
443 |
|
* must be cleared up. This is the purpose of the "resolutions" map; |
444 |
|
* it includes any mutually-recursive datatypes that are currently |
445 |
|
* under resolution. The four vectors come in two pairs (so, really |
446 |
|
* they are two maps). placeholders->replacements give type variables |
447 |
|
* that should be resolved in the case of parametric datatypes. |
448 |
|
* |
449 |
|
* @param em the NodeManager at play |
450 |
|
* @param resolutions a map of strings to TypeNodes currently under |
451 |
|
* resolution |
452 |
|
* @param placeholders the types in these DTypes under resolution that must |
453 |
|
* be replaced |
454 |
|
* @param replacements the corresponding replacements |
455 |
|
* @param paramTypes the sort constructors in these DTypes under resolution |
456 |
|
* that must be replaced |
457 |
|
* @param paramReplacements the corresponding (parametric) TypeNodes |
458 |
|
*/ |
459 |
|
bool resolve(const std::map<std::string, TypeNode>& resolutions, |
460 |
|
const std::vector<TypeNode>& placeholders, |
461 |
|
const std::vector<TypeNode>& replacements, |
462 |
|
const std::vector<TypeNode>& paramTypes, |
463 |
|
const std::vector<TypeNode>& paramReplacements); |
464 |
|
|
465 |
|
/** compute the cardinality of this datatype */ |
466 |
|
Cardinality computeCardinality(TypeNode t, |
467 |
|
std::vector<TypeNode>& processing) const; |
468 |
|
/** compute whether this datatype is a recursive singleton */ |
469 |
|
bool computeCardinalityRecSingleton(TypeNode t, |
470 |
|
std::vector<TypeNode>& processing, |
471 |
|
std::vector<TypeNode>& u_assume) const; |
472 |
|
/** compute whether this datatype is well-founded */ |
473 |
|
bool computeWellFounded(std::vector<TypeNode>& processing) const; |
474 |
|
/** compute ground term |
475 |
|
* |
476 |
|
* This method checks if there is a term of this datatype whose type is t |
477 |
|
* that is finitely constructable. As needed, it traverses its subfield types. |
478 |
|
* |
479 |
|
* The argument processing is the set of datatype types we are currently |
480 |
|
* traversing. |
481 |
|
* |
482 |
|
* The argument isValue is whether we are constructing a constant value. If |
483 |
|
* this flag is false, we are constructing a canonical ground term that is |
484 |
|
* not necessarily constant. |
485 |
|
*/ |
486 |
|
Node computeGroundTerm(TypeNode t, |
487 |
|
std::vector<TypeNode>& processing, |
488 |
|
bool isValue) const; |
489 |
|
/** Get the shared selector |
490 |
|
* |
491 |
|
* This returns the index^th (constructor-agnostic) |
492 |
|
* selector for type t. The type dtt is the datatype |
493 |
|
* type whose datatype is this class, where this may |
494 |
|
* be an instantiated parametric datatype. |
495 |
|
* |
496 |
|
* In the terminology of "DTypes with Shared Selectors", |
497 |
|
* this returns the term sel_{dtt}^{t,index}. |
498 |
|
*/ |
499 |
|
Node getSharedSelector(TypeNode dtt, TypeNode t, size_t index) const; |
500 |
|
/** |
501 |
|
* Helper for mkGroundTerm and mkGroundValue above. |
502 |
|
*/ |
503 |
|
Node mkGroundTermInternal(TypeNode t, bool isValue) const; |
504 |
|
/** |
505 |
|
* This method is used to get alien subfield types of this datatype. |
506 |
|
* |
507 |
|
* A subfield type T of a datatype type D is a type such that a value of |
508 |
|
* type T may appear as a subterm of a value of type D. |
509 |
|
* |
510 |
|
* An *alien* subfield type T of a datatype type D is a type such that a |
511 |
|
* value v of type T may appear as a subterm of a value of D, and moreover |
512 |
|
* v occurs as a strict subterm of a non-datatype term in that value. |
513 |
|
* |
514 |
|
* For example, the alien subfield types of T in: |
515 |
|
* T -> Emp | Container(s : (Set List)) |
516 |
|
* List -> nil | cons( head : Int, tail: List) |
517 |
|
* are { List, Int }. Notice that Int is an alien subfield type since it |
518 |
|
* appears as a subfield type of List, and List is an alien subfield type |
519 |
|
* of T. In other words, Int is an alien subfield type due to the above |
520 |
|
* definition due to the term (Container (singleton (cons 0 nil))), where |
521 |
|
* 0 occurs as a subterm of (singleton (cons 0 nil)). The non-strict |
522 |
|
* subfield types of T in this example are { (Set List) }. |
523 |
|
* |
524 |
|
* For example, the alien subfield types of T in: |
525 |
|
* T -> Emp | Container(s : List) |
526 |
|
* List -> nil | cons( head : (Set T), tail: List) |
527 |
|
* are { T, List, (Set T) }. Notice that T is an alien subfield type of itself |
528 |
|
* since List is a subfield type of T and T is an alien subfield type of List. |
529 |
|
* Furthermore, List and (Set T) are also alien subfield types of T since |
530 |
|
* List is a subfield type of T and T is an alien subfield type of itself. |
531 |
|
* |
532 |
|
* For example, the alien subfield types of T in: |
533 |
|
* T -> Emp | Container(s : (Array Int T)) |
534 |
|
* are { T, Int }, where we assume that values of (Array U1 U2) are |
535 |
|
* constructed from values of U1 and U2, for all types U1, U2. The non-strict |
536 |
|
* subfield types of T in this example are { (Array Int T) }. |
537 |
|
* |
538 |
|
* @param types The set of types to append the alien subfield types to, |
539 |
|
* @param processed The datatypes (cached using d_self) we have processed. If |
540 |
|
* the range of this map is true, we have processed the datatype with |
541 |
|
* isAlienPos = true. |
542 |
|
* @param isAlienPos Whether we are in an alien subfield type position. This |
543 |
|
* flag is true if we have traversed beneath a non-datatype type constructor. |
544 |
|
*/ |
545 |
|
void getAlienSubfieldTypes(std::unordered_set<TypeNode>& types, |
546 |
|
std::map<TypeNode, bool>& processed, |
547 |
|
bool isAlienPos) const; |
548 |
|
/** name of this datatype */ |
549 |
|
std::string d_name; |
550 |
|
/** the type parameters of this datatype (if this is a parametric datatype) |
551 |
|
*/ |
552 |
|
std::vector<TypeNode> d_params; |
553 |
|
/** whether the datatype is a codatatype. */ |
554 |
|
bool d_isCo; |
555 |
|
/** whether the datatype is a tuple */ |
556 |
|
bool d_isTuple; |
557 |
|
/** whether the datatype is a record */ |
558 |
|
bool d_isRecord; |
559 |
|
/** the constructors of this datatype */ |
560 |
|
std::vector<std::shared_ptr<DTypeConstructor> > d_constructors; |
561 |
|
/** whether this datatype has been resolved */ |
562 |
|
bool d_resolved; |
563 |
|
/** self type */ |
564 |
|
mutable TypeNode d_self; |
565 |
|
/** cache for involves external type */ |
566 |
|
bool d_involvesExt; |
567 |
|
/** cache for involves uninterpreted type */ |
568 |
|
bool d_involvesUt; |
569 |
|
/** the builtin type that this sygus type encodes */ |
570 |
|
TypeNode d_sygusType; |
571 |
|
/** the variable list for the sygus function to synthesize */ |
572 |
|
Node d_sygusBvl; |
573 |
|
/** whether all constants are allowed as solutions */ |
574 |
|
bool d_sygusAllowConst; |
575 |
|
/** whether all terms are allowed as solutions */ |
576 |
|
bool d_sygusAllowAll; |
577 |
|
|
578 |
|
/** the cardinality of this datatype |
579 |
|
* "mutable" because computing the cardinality can be expensive, |
580 |
|
* and so it's computed just once, on demand---this is the cache |
581 |
|
*/ |
582 |
|
mutable Cardinality d_card; |
583 |
|
|
584 |
|
/** is this type a recursive singleton type? |
585 |
|
* The range of this map stores |
586 |
|
* 0 if the field has not been computed, |
587 |
|
* 1 if this datatype is a recursive singleton type, |
588 |
|
* -1 if this datatype is not a recursive singleton type. |
589 |
|
* For definition of (co)recursive singleton, see |
590 |
|
* Section 2 of Reynolds et al. CADE 2015. |
591 |
|
*/ |
592 |
|
mutable std::map<TypeNode, int> d_cardRecSingleton; |
593 |
|
/** if d_cardRecSingleton is true, |
594 |
|
* This datatype has infinite cardinality if at least one of the |
595 |
|
* following uninterpreted sorts having cardinality > 1. |
596 |
|
*/ |
597 |
|
mutable std::map<TypeNode, std::vector<TypeNode> > d_cardUAssume; |
598 |
|
/** |
599 |
|
* Cache of whether this datatype is well-founded, where 0 means we have |
600 |
|
* not computed this information, 1 means it is well-founded, -1 means it is |
601 |
|
* not. |
602 |
|
*/ |
603 |
|
mutable int d_wellFounded; |
604 |
|
/** |
605 |
|
* Cache of whether this datatype has nested recursion, where 0 means we have |
606 |
|
* not computed this information, 1 means it has nested recursion, -1 means it |
607 |
|
* does not. |
608 |
|
*/ |
609 |
|
mutable int d_nestedRecursion; |
610 |
|
/** cache of ground term for this datatype */ |
611 |
|
mutable std::map<TypeNode, Node> d_groundTerm; |
612 |
|
/** cache of ground values for this datatype */ |
613 |
|
mutable std::map<TypeNode, Node> d_groundValue; |
614 |
|
/** cache of shared selectors for this datatype */ |
615 |
|
mutable std::map<TypeNode, std::map<TypeNode, std::map<unsigned, Node> > > |
616 |
|
d_sharedSel; |
617 |
|
/** A cache for getCardinalityClass. */ |
618 |
|
mutable std::map<TypeNode, CardinalityClass> d_cardClass; |
619 |
|
}; /* class DType */ |
620 |
|
|
621 |
|
/** |
622 |
|
* A hash function for DTypes. Needed to store them in hash sets |
623 |
|
* and hash maps. |
624 |
|
*/ |
625 |
|
struct DTypeHashFunction |
626 |
|
{ |
627 |
|
size_t operator()(const DType& dt) const |
628 |
|
{ |
629 |
|
return std::hash<std::string>()(dt.getName()); |
630 |
|
} |
631 |
|
size_t operator()(const DType* dt) const |
632 |
|
{ |
633 |
|
return std::hash<std::string>()(dt->getName()); |
634 |
|
} |
635 |
|
}; /* struct DTypeHashFunction */ |
636 |
|
|
637 |
|
/* stores an index to DType residing in NodeManager */ |
638 |
|
class DTypeIndexConstant |
639 |
|
{ |
640 |
|
public: |
641 |
|
DTypeIndexConstant(size_t index); |
642 |
|
|
643 |
|
size_t getIndex() const { return d_index; } |
644 |
|
bool operator==(const DTypeIndexConstant& uc) const |
645 |
|
{ |
646 |
|
return d_index == uc.d_index; |
647 |
|
} |
648 |
|
bool operator!=(const DTypeIndexConstant& uc) const { return !(*this == uc); } |
649 |
|
bool operator<(const DTypeIndexConstant& uc) const |
650 |
|
{ |
651 |
|
return d_index < uc.d_index; |
652 |
|
} |
653 |
|
bool operator<=(const DTypeIndexConstant& uc) const |
654 |
|
{ |
655 |
|
return d_index <= uc.d_index; |
656 |
|
} |
657 |
|
bool operator>(const DTypeIndexConstant& uc) const { return !(*this <= uc); } |
658 |
|
bool operator>=(const DTypeIndexConstant& uc) const { return !(*this < uc); } |
659 |
|
|
660 |
|
private: |
661 |
|
const size_t d_index; |
662 |
|
}; /* class DTypeIndexConstant */ |
663 |
|
|
664 |
|
std::ostream& operator<<(std::ostream& out, const DTypeIndexConstant& dic); |
665 |
|
|
666 |
|
struct DTypeIndexConstantHashFunction |
667 |
|
{ |
668 |
|
size_t operator()(const DTypeIndexConstant& dic) const |
669 |
|
{ |
670 |
|
return IntegerHashFunction()(dic.getIndex()); |
671 |
|
} |
672 |
|
}; /* struct DTypeIndexConstantHashFunction */ |
673 |
|
|
674 |
|
std::ostream& operator<<(std::ostream& os, const DType& dt); |
675 |
|
|
676 |
|
} // namespace cvc5 |
677 |
|
|
678 |
|
#endif |