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