1 |
|
/****************************************************************************** |
2 |
|
* Top contributors (to current version): |
3 |
|
* Morgan Deters, Andrew Reynolds, Christopher L. Conway |
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 manager for Nodes. |
14 |
|
*/ |
15 |
|
|
16 |
|
#include "cvc5_private.h" |
17 |
|
|
18 |
|
/* circular dependency; force node.h first */ |
19 |
|
//#include "expr/attribute.h" |
20 |
|
#include "expr/node.h" |
21 |
|
#include "expr/type_node.h" |
22 |
|
|
23 |
|
#ifndef CVC5__NODE_MANAGER_H |
24 |
|
#define CVC5__NODE_MANAGER_H |
25 |
|
|
26 |
|
#include <string> |
27 |
|
#include <unordered_set> |
28 |
|
#include <vector> |
29 |
|
|
30 |
|
#include "base/check.h" |
31 |
|
#include "expr/kind.h" |
32 |
|
#include "expr/metakind.h" |
33 |
|
#include "expr/node_value.h" |
34 |
|
#include "util/floatingpoint_size.h" |
35 |
|
|
36 |
|
namespace cvc5 { |
37 |
|
|
38 |
|
using Record = std::vector<std::pair<std::string, TypeNode>>; |
39 |
|
|
40 |
|
namespace api { |
41 |
|
class Solver; |
42 |
|
} |
43 |
|
|
44 |
|
class ResourceManager; |
45 |
|
class SkolemManager; |
46 |
|
class BoundVarManager; |
47 |
|
|
48 |
|
class DType; |
49 |
|
|
50 |
|
namespace expr { |
51 |
|
namespace attr { |
52 |
|
class AttributeUniqueId; |
53 |
|
class AttributeManager; |
54 |
|
} // namespace attr |
55 |
|
|
56 |
|
class TypeChecker; |
57 |
|
} // namespace expr |
58 |
|
|
59 |
|
/** |
60 |
|
* An interface that an interested party can implement and then subscribe |
61 |
|
* to NodeManager events via NodeManager::subscribeEvents(this). |
62 |
|
*/ |
63 |
23111 |
class NodeManagerListener { |
64 |
|
public: |
65 |
20467 |
virtual ~NodeManagerListener() {} |
66 |
2815 |
virtual void nmNotifyNewSort(TypeNode tn, uint32_t flags) {} |
67 |
6 |
virtual void nmNotifyNewSortConstructor(TypeNode tn, uint32_t flags) {} |
68 |
629 |
virtual void nmNotifyInstantiateSortConstructor(TypeNode ctor, TypeNode sort, |
69 |
629 |
uint32_t flags) {} |
70 |
1209 |
virtual void nmNotifyNewDatatypes(const std::vector<TypeNode>& datatypes, |
71 |
|
uint32_t flags) |
72 |
|
{ |
73 |
1209 |
} |
74 |
|
virtual void nmNotifyNewVar(TNode n) {} |
75 |
|
virtual void nmNotifyNewSkolem(TNode n, const std::string& comment, |
76 |
|
uint32_t flags) {} |
77 |
|
/** |
78 |
|
* Notify a listener of a Node that's being GCed. If this function stores a |
79 |
|
* reference |
80 |
|
* to the Node somewhere, very bad things will happen. |
81 |
|
*/ |
82 |
10957771 |
virtual void nmNotifyDeleteNode(TNode n) {} |
83 |
|
}; /* class NodeManagerListener */ |
84 |
|
|
85 |
|
class NodeManager |
86 |
|
{ |
87 |
|
friend class api::Solver; |
88 |
|
friend class expr::NodeValue; |
89 |
|
friend class expr::TypeChecker; |
90 |
|
friend class SkolemManager; |
91 |
|
|
92 |
|
friend class NodeBuilder; |
93 |
|
friend class NodeManagerScope; |
94 |
|
|
95 |
|
public: |
96 |
|
/** |
97 |
|
* Return true if given kind is n-ary. The test is based on n-ary kinds |
98 |
|
* having their maximal arity as the maximal possible number of children |
99 |
|
* of a node. |
100 |
|
*/ |
101 |
|
static bool isNAryKind(Kind k); |
102 |
|
|
103 |
|
private: |
104 |
|
/** Predicate for use with STL algorithms */ |
105 |
|
struct NodeValueReferenceCountNonZero { |
106 |
32040050 |
bool operator()(expr::NodeValue* nv) { return nv->d_rc > 0; } |
107 |
|
}; |
108 |
|
|
109 |
|
typedef std::unordered_set<expr::NodeValue*, |
110 |
|
expr::NodeValuePoolHashFunction, |
111 |
|
expr::NodeValuePoolEq> NodeValuePool; |
112 |
|
typedef std::unordered_set<expr::NodeValue*, |
113 |
|
expr::NodeValueIDHashFunction, |
114 |
|
expr::NodeValueIDEquality> NodeValueIDSet; |
115 |
|
|
116 |
|
static thread_local NodeManager* s_current; |
117 |
|
|
118 |
|
/** The skolem manager */ |
119 |
|
std::unique_ptr<SkolemManager> d_skManager; |
120 |
|
/** The bound variable manager */ |
121 |
|
std::unique_ptr<BoundVarManager> d_bvManager; |
122 |
|
|
123 |
|
NodeValuePool d_nodeValuePool; |
124 |
|
|
125 |
|
size_t next_id; |
126 |
|
|
127 |
|
expr::attr::AttributeManager* d_attrManager; |
128 |
|
|
129 |
|
/** |
130 |
|
* The node value we're currently freeing. This unique node value |
131 |
|
* is permitted to have outstanding TNodes to it (in "soft" |
132 |
|
* contexts, like as a key in attribute tables), even though |
133 |
|
* normally it's an error to have a TNode to a node value with a |
134 |
|
* reference count of 0. Being "under deletion" also enables |
135 |
|
* assertions that inc() is not called on it. |
136 |
|
*/ |
137 |
|
expr::NodeValue* d_nodeUnderDeletion; |
138 |
|
|
139 |
|
/** |
140 |
|
* True iff we are in reclaimZombies(). This avoids unnecessary |
141 |
|
* recursion; a NodeValue being deleted might zombify other |
142 |
|
* NodeValues, but these shouldn't trigger a (recursive) call to |
143 |
|
* reclaimZombies(). |
144 |
|
*/ |
145 |
|
bool d_inReclaimZombies; |
146 |
|
|
147 |
|
/** |
148 |
|
* The set of zombie nodes. We may want to revisit this design, as |
149 |
|
* we might like to delete nodes in least-recently-used order. But |
150 |
|
* we also need to avoid processing a zombie twice. |
151 |
|
*/ |
152 |
|
NodeValueIDSet d_zombies; |
153 |
|
|
154 |
|
/** |
155 |
|
* NodeValues with maxed out reference counts. These live as long as the |
156 |
|
* NodeManager. They have a custom deallocation procedure at the very end. |
157 |
|
*/ |
158 |
|
std::vector<expr::NodeValue*> d_maxedOut; |
159 |
|
|
160 |
|
/** |
161 |
|
* A set of operator singletons (w.r.t. to this NodeManager |
162 |
|
* instance) for operators. Conceptually, Nodes with kind, say, |
163 |
|
* PLUS, are APPLYs of a PLUS operator to arguments. This array |
164 |
|
* holds the set of operators for these things. A PLUS operator is |
165 |
|
* a Node with kind "BUILTIN", and if you call |
166 |
|
* plusOperator->getConst<cvc5::Kind>(), you get kind::PLUS back. |
167 |
|
*/ |
168 |
|
Node d_operators[kind::LAST_KIND]; |
169 |
|
|
170 |
|
/** unique vars per (Kind,Type) */ |
171 |
|
std::map< Kind, std::map< TypeNode, Node > > d_unique_vars; |
172 |
|
|
173 |
|
/** |
174 |
|
* A list of subscribers for NodeManager events. |
175 |
|
*/ |
176 |
|
std::vector<NodeManagerListener*> d_listeners; |
177 |
|
|
178 |
|
/** A list of datatypes owned by this node manager */ |
179 |
|
std::vector<std::unique_ptr<DType> > d_dtypes; |
180 |
|
|
181 |
|
/** |
182 |
|
* A map of tuple and record types to their corresponding datatype. |
183 |
|
*/ |
184 |
20377 |
class TupleTypeCache { |
185 |
|
public: |
186 |
|
std::map< TypeNode, TupleTypeCache > d_children; |
187 |
|
TypeNode d_data; |
188 |
|
TypeNode getTupleType( NodeManager * nm, std::vector< TypeNode >& types, unsigned index = 0 ); |
189 |
|
}; |
190 |
18891 |
class RecTypeCache { |
191 |
|
public: |
192 |
|
std::map< TypeNode, std::map< std::string, RecTypeCache > > d_children; |
193 |
|
TypeNode d_data; |
194 |
|
TypeNode getRecordType( NodeManager * nm, const Record& rec, unsigned index = 0 ); |
195 |
|
}; |
196 |
|
TupleTypeCache d_tt_cache; |
197 |
|
RecTypeCache d_rt_cache; |
198 |
|
|
199 |
|
/** |
200 |
|
* Keep a count of all abstract values produced by this NodeManager. |
201 |
|
* Abstract values have a type attribute, so if multiple SmtEngines |
202 |
|
* are attached to this NodeManager, we don't want their abstract |
203 |
|
* values to overlap. |
204 |
|
*/ |
205 |
|
unsigned d_abstractValueCount; |
206 |
|
|
207 |
|
/** |
208 |
|
* A counter used to produce unique skolem names. |
209 |
|
* |
210 |
|
* Note that it is NOT incremented when skolems are created using |
211 |
|
* SKOLEM_EXACT_NAME, so it is NOT a count of the skolems produced |
212 |
|
* by this node manager. |
213 |
|
*/ |
214 |
|
unsigned d_skolemCounter; |
215 |
|
|
216 |
|
/** |
217 |
|
* Look up a NodeValue in the pool associated to this NodeManager. |
218 |
|
* The NodeValue argument need not be a "completely-constructed" |
219 |
|
* NodeValue. In particular, "non-inlined" constants are permitted |
220 |
|
* (see below). |
221 |
|
* |
222 |
|
* For non-CONSTANT metakinds, nv's d_kind and d_nchildren should be |
223 |
|
* correctly set, and d_children[0..n-1] should be valid (extant) |
224 |
|
* NodeValues for lookup. |
225 |
|
* |
226 |
|
* For CONSTANT metakinds, nv's d_kind should be set correctly. |
227 |
|
* Normally a CONSTANT would have d_nchildren == 0 and the constant |
228 |
|
* value inlined in the d_children space. However, here we permit |
229 |
|
* "non-inlined" NodeValues to avoid unnecessary copying. For |
230 |
|
* these, d_nchildren == 1, and d_nchildren is a pointer to the |
231 |
|
* constant value. |
232 |
|
* |
233 |
|
* The point of this complex design is to permit efficient lookups |
234 |
|
* (without fully constructing a NodeValue). In the case that the |
235 |
|
* argument is not fully constructed, and this function returns |
236 |
|
* NULL, the caller should fully construct an equivalent one before |
237 |
|
* calling poolInsert(). NON-FULLY-CONSTRUCTED NODEVALUES are not |
238 |
|
* permitted in the pool! |
239 |
|
*/ |
240 |
|
inline expr::NodeValue* poolLookup(expr::NodeValue* nv) const; |
241 |
|
|
242 |
|
/** |
243 |
|
* Insert a NodeValue into the NodeManager's pool. |
244 |
|
* |
245 |
|
* It is an error to insert a NodeValue already in the pool. |
246 |
|
* Enquire first with poolLookup(). |
247 |
|
*/ |
248 |
|
inline void poolInsert(expr::NodeValue* nv); |
249 |
|
|
250 |
|
/** |
251 |
|
* Remove a NodeValue from the NodeManager's pool. |
252 |
|
* |
253 |
|
* It is an error to request the removal of a NodeValue from the |
254 |
|
* pool that is not in the pool. |
255 |
|
*/ |
256 |
|
inline void poolRemove(expr::NodeValue* nv); |
257 |
|
|
258 |
|
/** |
259 |
|
* Determine if nv is currently being deleted by the NodeManager. |
260 |
|
*/ |
261 |
17512363140 |
inline bool isCurrentlyDeleting(const expr::NodeValue* nv) const { |
262 |
17512363140 |
return d_nodeUnderDeletion == nv; |
263 |
|
} |
264 |
|
|
265 |
|
/** |
266 |
|
* Register a NodeValue as a zombie. |
267 |
|
*/ |
268 |
49471373 |
inline void markForDeletion(expr::NodeValue* nv) { |
269 |
49471373 |
Assert(nv->d_rc == 0); |
270 |
|
|
271 |
|
// if d_reclaiming is set, make sure we don't call |
272 |
|
// reclaimZombies(), because it's already running. |
273 |
49471373 |
if(Debug.isOn("gc")) { |
274 |
|
Debug("gc") << "zombifying node value " << nv |
275 |
|
<< " [" << nv->d_id << "]: "; |
276 |
|
nv->printAst(Debug("gc")); |
277 |
|
Debug("gc") << (d_inReclaimZombies ? " [CURRENTLY-RECLAIMING]" : "") |
278 |
|
<< std::endl; |
279 |
|
} |
280 |
|
|
281 |
|
// `d_zombies` uses the node id to hash and compare nodes. If `d_zombies` |
282 |
|
// already contains a node value with the same id as `nv`, but the pointers |
283 |
|
// are different, then the wrong `NodeManager` was in scope for one of the |
284 |
|
// two nodes when it reached refcount zero. |
285 |
49471373 |
Assert(d_zombies.find(nv) == d_zombies.end() || *d_zombies.find(nv) == nv); |
286 |
|
|
287 |
49471373 |
d_zombies.insert(nv); |
288 |
|
|
289 |
49471373 |
if(safeToReclaimZombies()) { |
290 |
32583219 |
if(d_zombies.size() > 5000) { |
291 |
2819 |
reclaimZombies(); |
292 |
|
} |
293 |
|
} |
294 |
49471373 |
} |
295 |
|
|
296 |
|
/** |
297 |
|
* Register a NodeValue as having a maxed out reference count. This NodeValue |
298 |
|
* will live as long as its containing NodeManager. |
299 |
|
*/ |
300 |
7 |
inline void markRefCountMaxedOut(expr::NodeValue* nv) { |
301 |
7 |
Assert(nv->HasMaximizedReferenceCount()); |
302 |
7 |
if(Debug.isOn("gc")) { |
303 |
|
Debug("gc") << "marking node value " << nv |
304 |
|
<< " [" << nv->d_id << "]: as maxed out" << std::endl; |
305 |
|
} |
306 |
7 |
d_maxedOut.push_back(nv); |
307 |
7 |
} |
308 |
|
|
309 |
|
/** |
310 |
|
* Reclaim all zombies. |
311 |
|
*/ |
312 |
|
void reclaimZombies(); |
313 |
|
|
314 |
|
/** |
315 |
|
* It is safe to collect zombies. |
316 |
|
*/ |
317 |
|
bool safeToReclaimZombies() const; |
318 |
|
|
319 |
|
/** |
320 |
|
* Returns a reverse topological sort of a list of NodeValues. The NodeValues |
321 |
|
* must be valid and have ids. The NodeValues are not modified (including ref |
322 |
|
* counts). |
323 |
|
*/ |
324 |
|
static std::vector<expr::NodeValue*> TopologicalSort( |
325 |
|
const std::vector<expr::NodeValue*>& roots); |
326 |
|
|
327 |
|
/** |
328 |
|
* This template gives a mechanism to stack-allocate a NodeValue |
329 |
|
* with enough space for N children (where N is a compile-time |
330 |
|
* constant). You use it like this: |
331 |
|
* |
332 |
|
* NVStorage<4> nvStorage; |
333 |
|
* NodeValue& nvStack = reinterpret_cast<NodeValue&>(nvStorage); |
334 |
|
* |
335 |
|
* ...and then you can use nvStack as a NodeValue that you know has |
336 |
|
* room for 4 children. |
337 |
|
*/ |
338 |
|
template <size_t N> |
339 |
250933426 |
struct NVStorage { |
340 |
|
expr::NodeValue nv; |
341 |
|
expr::NodeValue* child[N]; |
342 |
|
};/* struct NodeManager::NVStorage<N> */ |
343 |
|
|
344 |
|
// undefined private copy constructor (disallow copy) |
345 |
|
NodeManager(const NodeManager&) = delete; |
346 |
|
|
347 |
|
NodeManager& operator=(const NodeManager&) = delete; |
348 |
|
|
349 |
|
void init(); |
350 |
|
|
351 |
|
/** |
352 |
|
* Create a variable with the given name and type. NOTE that no |
353 |
|
* lookup is done on the name. If you mkVar("a", type) and then |
354 |
|
* mkVar("a", type) again, you have two variables. The NodeManager |
355 |
|
* version of this is private to avoid internal uses of mkVar() from |
356 |
|
* within cvc5. Such uses should employ SkolemManager::mkSkolem() instead. |
357 |
|
*/ |
358 |
|
Node mkVar(const std::string& name, const TypeNode& type); |
359 |
|
|
360 |
|
/** Create a variable with the given type. */ |
361 |
|
Node mkVar(const TypeNode& type); |
362 |
|
|
363 |
|
/** |
364 |
|
* Create a skolem constant with the given name, type, and comment. For |
365 |
|
* details, see SkolemManager::mkDummySkolem, which calls this method. |
366 |
|
* |
367 |
|
* This method is intentionally private. To create skolems, one should |
368 |
|
* call a method from SkolemManager for allocating a skolem in a standard |
369 |
|
* way, or otherwise use SkolemManager::mkDummySkolem. |
370 |
|
*/ |
371 |
|
Node mkSkolem(const std::string& prefix, |
372 |
|
const TypeNode& type, |
373 |
|
const std::string& comment = "", |
374 |
|
int flags = SKOLEM_DEFAULT); |
375 |
|
|
376 |
|
public: |
377 |
|
explicit NodeManager(); |
378 |
|
~NodeManager(); |
379 |
|
|
380 |
|
/** The node manager in the current public-facing cvc5 library context */ |
381 |
80839376099 |
static NodeManager* currentNM() { return s_current; } |
382 |
|
/** Get this node manager's skolem manager */ |
383 |
229872 |
SkolemManager* getSkolemManager() { return d_skManager.get(); } |
384 |
|
/** Get this node manager's bound variable manager */ |
385 |
760440 |
BoundVarManager* getBoundVarManager() { return d_bvManager.get(); } |
386 |
|
|
387 |
|
/** Subscribe to NodeManager events */ |
388 |
20907 |
void subscribeEvents(NodeManagerListener* listener) { |
389 |
20907 |
Assert(std::find(d_listeners.begin(), d_listeners.end(), listener) |
390 |
|
== d_listeners.end()) |
391 |
|
<< "listener already subscribed"; |
392 |
20907 |
d_listeners.push_back(listener); |
393 |
20907 |
} |
394 |
|
|
395 |
|
/** Unsubscribe from NodeManager events */ |
396 |
18263 |
void unsubscribeEvents(NodeManagerListener* listener) { |
397 |
18263 |
std::vector<NodeManagerListener*>::iterator elt = std::find(d_listeners.begin(), d_listeners.end(), listener); |
398 |
18263 |
Assert(elt != d_listeners.end()) << "listener not subscribed"; |
399 |
18263 |
d_listeners.erase(elt); |
400 |
18263 |
} |
401 |
|
|
402 |
|
/** |
403 |
|
* Return the datatype at the given index owned by this class. Type nodes are |
404 |
|
* associated with datatypes through the DatatypeIndexConstant class. The |
405 |
|
* argument index is intended to be a value taken from that class. |
406 |
|
* |
407 |
|
* Type nodes must access their DTypes through a level of indirection to |
408 |
|
* prevent cycles in the Node AST (as DTypes themselves contain Nodes), which |
409 |
|
* would lead to memory leaks. Thus TypeNode are given a DatatypeIndexConstant |
410 |
|
* which is used as an index to retrieve the DType via this call. |
411 |
|
*/ |
412 |
|
const DType& getDTypeForIndex(size_t index) const; |
413 |
|
|
414 |
|
/** Get a Kind from an operator expression */ |
415 |
|
static inline Kind operatorToKind(TNode n); |
416 |
|
|
417 |
|
/** Get corresponding application kind for function |
418 |
|
* |
419 |
|
* Different functional nodes are applied differently, according to their |
420 |
|
* type. For example, uninterpreted functions (of FUNCTION_TYPE) are applied |
421 |
|
* via APPLY_UF, while constructors (of CONSTRUCTOR_TYPE) via |
422 |
|
* APPLY_CONSTRUCTOR. This method provides the correct application according |
423 |
|
* to which functional type fun has. |
424 |
|
* |
425 |
|
* @param fun The functional node |
426 |
|
* @return the correct application kind for fun. If fun's type is not function |
427 |
|
* like (see TypeNode::isFunctionLike), then UNDEFINED_KIND is returned. |
428 |
|
*/ |
429 |
|
static Kind getKindForFunction(TNode fun); |
430 |
|
|
431 |
|
// general expression-builders |
432 |
|
// |
433 |
|
/** Create a node with no child. */ |
434 |
|
Node mkNode(Kind kind); |
435 |
|
|
436 |
|
/** Create a node with one child. */ |
437 |
|
Node mkNode(Kind kind, TNode child1); |
438 |
|
|
439 |
|
/** Create a node with two children. */ |
440 |
|
Node mkNode(Kind kind, TNode child1, TNode child2); |
441 |
|
|
442 |
|
/** Create a node with three children. */ |
443 |
|
Node mkNode(Kind kind, TNode child1, TNode child2, TNode child3); |
444 |
|
|
445 |
|
/** Create a node with an arbitrary number of children. */ |
446 |
|
template <bool ref_count> |
447 |
|
Node mkNode(Kind kind, const std::vector<NodeTemplate<ref_count> >& children); |
448 |
|
|
449 |
|
/** Create a node using an initializer list. |
450 |
|
* |
451 |
|
* This function serves two purposes: |
452 |
|
* - We can avoid creating a temporary vector in some cases, e.g., when we |
453 |
|
* want to create a node with a fixed, large number of children |
454 |
|
* - It makes sure that calls to `mkNode` that braced-init-lists work as |
455 |
|
* expected, e.g., mkNode(REGEXP_EMPTY, {}) will call this overload instead |
456 |
|
* of creating a node with a null node as a child. |
457 |
|
*/ |
458 |
|
Node mkNode(Kind kind, std::initializer_list<TNode> children); |
459 |
|
|
460 |
|
/** |
461 |
|
* Create an AND node with arbitrary number of children. This returns the |
462 |
|
* true node if children is empty, or the single node in children if |
463 |
|
* it contains only one node. |
464 |
|
* |
465 |
|
* We define construction of AND as a special case here since it is widely |
466 |
|
* used for e.g. constructing explanations. |
467 |
|
*/ |
468 |
|
template <bool ref_count> |
469 |
|
Node mkAnd(const std::vector<NodeTemplate<ref_count> >& children); |
470 |
|
|
471 |
|
/** |
472 |
|
* Create an OR node with arbitrary number of children. This returns the |
473 |
|
* false node if children is empty, or the single node in children if |
474 |
|
* it contains only one node. |
475 |
|
* |
476 |
|
* We define construction of OR as a special case here since it is widely |
477 |
|
* used for e.g. constructing explanations or lemmas. |
478 |
|
*/ |
479 |
|
template <bool ref_count> |
480 |
|
Node mkOr(const std::vector<NodeTemplate<ref_count> >& children); |
481 |
|
|
482 |
|
/** Create a node (with no children) by operator. */ |
483 |
|
Node mkNode(TNode opNode); |
484 |
|
|
485 |
|
/** Create a node with one child by operator. */ |
486 |
|
Node mkNode(TNode opNode, TNode child1); |
487 |
|
|
488 |
|
/** Create a node with two children by operator. */ |
489 |
|
Node mkNode(TNode opNode, TNode child1, TNode child2); |
490 |
|
|
491 |
|
/** Create a node with three children by operator. */ |
492 |
|
Node mkNode(TNode opNode, TNode child1, TNode child2, TNode child3); |
493 |
|
|
494 |
|
/** Create a node by applying an operator to the children. */ |
495 |
|
template <bool ref_count> |
496 |
|
Node mkNode(TNode opNode, const std::vector<NodeTemplate<ref_count> >& children); |
497 |
|
|
498 |
|
/** |
499 |
|
* Create a node by applying an operator to an arbitrary number of children. |
500 |
|
* |
501 |
|
* Analoguous to `mkNode(Kind, std::initializer_list<TNode>)`. |
502 |
|
*/ |
503 |
|
Node mkNode(TNode opNode, std::initializer_list<TNode> children); |
504 |
|
|
505 |
|
Node mkBoundVar(const std::string& name, const TypeNode& type); |
506 |
|
|
507 |
|
Node mkBoundVar(const TypeNode& type); |
508 |
|
|
509 |
|
/** get the canonical bound variable list for function type tn */ |
510 |
|
Node getBoundVarListForFunctionType( TypeNode tn ); |
511 |
|
|
512 |
|
/** |
513 |
|
* Create an Node by applying an associative operator to the children. |
514 |
|
* If <code>children.size()</code> is greater than the max arity for |
515 |
|
* <code>kind</code>, then the expression will be broken up into |
516 |
|
* suitably-sized chunks, taking advantage of the associativity of |
517 |
|
* <code>kind</code>. For example, if kind <code>FOO</code> has max arity |
518 |
|
* 2, then calling <code>mkAssociative(FOO,a,b,c)</code> will return |
519 |
|
* <code>(FOO (FOO a b) c)</code> or <code>(FOO a (FOO b c))</code>. |
520 |
|
* The order of the arguments will be preserved in a left-to-right |
521 |
|
* traversal of the resulting tree. |
522 |
|
*/ |
523 |
|
Node mkAssociative(Kind kind, const std::vector<Node>& children); |
524 |
|
|
525 |
|
/** |
526 |
|
* Create an Node by applying an binary left-associative operator to the |
527 |
|
* children. For example, mkLeftAssociative( f, { a, b, c } ) returns |
528 |
|
* f( f( a, b ), c ). |
529 |
|
*/ |
530 |
|
Node mkLeftAssociative(Kind kind, const std::vector<Node>& children); |
531 |
|
/** |
532 |
|
* Create an Node by applying an binary right-associative operator to the |
533 |
|
* children. For example, mkRightAssociative( f, { a, b, c } ) returns |
534 |
|
* f( a, f( b, c ) ). |
535 |
|
*/ |
536 |
|
Node mkRightAssociative(Kind kind, const std::vector<Node>& children); |
537 |
|
|
538 |
|
/** make chain |
539 |
|
* |
540 |
|
* Given a kind k and arguments t_1, ..., t_n, this returns the |
541 |
|
* conjunction of: |
542 |
|
* (k t_1 t_2) .... (k t_{n-1} t_n) |
543 |
|
* It is expected that k is a kind denoting a predicate, and args is a list |
544 |
|
* of terms of size >= 2 such that the terms above are well-typed. |
545 |
|
*/ |
546 |
|
Node mkChain(Kind kind, const std::vector<Node>& children); |
547 |
|
|
548 |
|
/** |
549 |
|
* Optional flags used to control behavior of NodeManager::mkSkolem(). |
550 |
|
* They should be composed with a bitwise OR (e.g., |
551 |
|
* "SKOLEM_NO_NOTIFY | SKOLEM_EXACT_NAME"). Of course, SKOLEM_DEFAULT |
552 |
|
* cannot be composed in such a manner. |
553 |
|
*/ |
554 |
|
enum SkolemFlags |
555 |
|
{ |
556 |
|
SKOLEM_DEFAULT = 0, /**< default behavior */ |
557 |
|
SKOLEM_NO_NOTIFY = 1, /**< do not notify subscribers */ |
558 |
|
SKOLEM_EXACT_NAME = 2, /**< do not make the name unique by adding the id */ |
559 |
|
SKOLEM_IS_GLOBAL = 4, /**< global vars appear in models even after a pop */ |
560 |
|
SKOLEM_BOOL_TERM_VAR = 8 /**< vars requiring kind BOOLEAN_TERM_VARIABLE */ |
561 |
|
}; /* enum SkolemFlags */ |
562 |
|
|
563 |
|
/** Create a instantiation constant with the given type. */ |
564 |
|
Node mkInstConstant(const TypeNode& type); |
565 |
|
|
566 |
|
/** Create a boolean term variable. */ |
567 |
|
Node mkBooleanTermVariable(); |
568 |
|
|
569 |
|
/** Make a new abstract value with the given type. */ |
570 |
|
Node mkAbstractValue(const TypeNode& type); |
571 |
|
|
572 |
|
/** make unique (per Type,Kind) variable. */ |
573 |
|
Node mkNullaryOperator(const TypeNode& type, Kind k); |
574 |
|
|
575 |
|
/** |
576 |
|
* Create a singleton set from the given element n. |
577 |
|
* @param t the element type of the returned set. |
578 |
|
* Note that the type of n needs to be a subtype of t. |
579 |
|
* @param n the single element in the singleton. |
580 |
|
* @return a singleton set constructed from the element n. |
581 |
|
*/ |
582 |
|
Node mkSingleton(const TypeNode& t, const TNode n); |
583 |
|
|
584 |
|
/** |
585 |
|
* Create a bag from the given element n along with its multiplicity m. |
586 |
|
* @param t the element type of the returned bag. |
587 |
|
* Note that the type of n needs to be a subtype of t. |
588 |
|
* @param n the element that is used to to construct the bag |
589 |
|
* @param m the multiplicity of the element n |
590 |
|
* @return a bag that contains m occurrences of n. |
591 |
|
*/ |
592 |
|
Node mkBag(const TypeNode& t, const TNode n, const TNode m); |
593 |
|
|
594 |
|
/** |
595 |
|
* Create a constant of type T. It will have the appropriate |
596 |
|
* CONST_* kind defined for T. |
597 |
|
*/ |
598 |
|
template <class T> |
599 |
|
Node mkConst(const T&); |
600 |
|
|
601 |
|
template <class T> |
602 |
|
TypeNode mkTypeConst(const T&); |
603 |
|
|
604 |
|
template <class NodeClass, class T> |
605 |
|
NodeClass mkConstInternal(const T&); |
606 |
|
|
607 |
|
/** Create a node with children. */ |
608 |
|
TypeNode mkTypeNode(Kind kind, TypeNode child1); |
609 |
|
TypeNode mkTypeNode(Kind kind, TypeNode child1, TypeNode child2); |
610 |
|
TypeNode mkTypeNode(Kind kind, TypeNode child1, TypeNode child2, |
611 |
|
TypeNode child3); |
612 |
|
TypeNode mkTypeNode(Kind kind, const std::vector<TypeNode>& children); |
613 |
|
|
614 |
|
/** |
615 |
|
* Determine whether Nodes of a particular Kind have operators. |
616 |
|
* @returns true if Nodes of Kind k have operators. |
617 |
|
*/ |
618 |
|
static inline bool hasOperator(Kind k); |
619 |
|
|
620 |
|
/** |
621 |
|
* Get the (singleton) operator of an OPERATOR-kinded kind. The |
622 |
|
* returned node n will have kind BUILTIN, and calling |
623 |
|
* n.getConst<cvc5::Kind>() will yield k. |
624 |
|
*/ |
625 |
5910091 |
inline TNode operatorOf(Kind k) { |
626 |
5910091 |
AssertArgument( kind::metaKindOf(k) == kind::metakind::OPERATOR, k, |
627 |
|
"Kind is not an OPERATOR-kinded kind " |
628 |
|
"in NodeManager::operatorOf()" ); |
629 |
5910091 |
return d_operators[k]; |
630 |
|
} |
631 |
|
|
632 |
|
/** |
633 |
|
* Retrieve an attribute for a node. |
634 |
|
* |
635 |
|
* @param nv the node value |
636 |
|
* @param attr an instance of the attribute kind to retrieve. |
637 |
|
* @returns the attribute, if set, or a default-constructed |
638 |
|
* <code>AttrKind::value_type</code> if not. |
639 |
|
*/ |
640 |
|
template <class AttrKind> |
641 |
|
inline typename AttrKind::value_type getAttribute(expr::NodeValue* nv, |
642 |
|
const AttrKind& attr) const; |
643 |
|
|
644 |
|
/** |
645 |
|
* Check whether an attribute is set for a node. |
646 |
|
* |
647 |
|
* @param nv the node value |
648 |
|
* @param attr an instance of the attribute kind to check |
649 |
|
* @returns <code>true</code> iff <code>attr</code> is set for |
650 |
|
* <code>nv</code>. |
651 |
|
*/ |
652 |
|
template <class AttrKind> |
653 |
|
inline bool hasAttribute(expr::NodeValue* nv, |
654 |
|
const AttrKind& attr) const; |
655 |
|
|
656 |
|
/** |
657 |
|
* Check whether an attribute is set for a node, and, if so, |
658 |
|
* retrieve it. |
659 |
|
* |
660 |
|
* @param nv the node value |
661 |
|
* @param attr an instance of the attribute kind to check |
662 |
|
* @param value a reference to an object of the attribute's value type. |
663 |
|
* <code>value</code> will be set to the value of the attribute, if it is |
664 |
|
* set for <code>nv</code>; otherwise, it will be set to the default |
665 |
|
* value of the attribute. |
666 |
|
* @returns <code>true</code> iff <code>attr</code> is set for |
667 |
|
* <code>nv</code>. |
668 |
|
*/ |
669 |
|
template <class AttrKind> |
670 |
|
inline bool getAttribute(expr::NodeValue* nv, |
671 |
|
const AttrKind& attr, |
672 |
|
typename AttrKind::value_type& value) const; |
673 |
|
|
674 |
|
/** |
675 |
|
* Set an attribute for a node. If the node doesn't have the |
676 |
|
* attribute, this function assigns one. If the node has one, this |
677 |
|
* overwrites it. |
678 |
|
* |
679 |
|
* @param nv the node value |
680 |
|
* @param attr an instance of the attribute kind to set |
681 |
|
* @param value the value of <code>attr</code> for <code>nv</code> |
682 |
|
*/ |
683 |
|
template <class AttrKind> |
684 |
|
inline void setAttribute(expr::NodeValue* nv, |
685 |
|
const AttrKind& attr, |
686 |
|
const typename AttrKind::value_type& value); |
687 |
|
|
688 |
|
/** |
689 |
|
* Retrieve an attribute for a TNode. |
690 |
|
* |
691 |
|
* @param n the node |
692 |
|
* @param attr an instance of the attribute kind to retrieve. |
693 |
|
* @returns the attribute, if set, or a default-constructed |
694 |
|
* <code>AttrKind::value_type</code> if not. |
695 |
|
*/ |
696 |
|
template <class AttrKind> |
697 |
|
inline typename AttrKind::value_type |
698 |
|
getAttribute(TNode n, const AttrKind& attr) const; |
699 |
|
|
700 |
|
/** |
701 |
|
* Check whether an attribute is set for a TNode. |
702 |
|
* |
703 |
|
* @param n the node |
704 |
|
* @param attr an instance of the attribute kind to check |
705 |
|
* @returns <code>true</code> iff <code>attr</code> is set for <code>n</code>. |
706 |
|
*/ |
707 |
|
template <class AttrKind> |
708 |
|
inline bool hasAttribute(TNode n, |
709 |
|
const AttrKind& attr) const; |
710 |
|
|
711 |
|
/** |
712 |
|
* Check whether an attribute is set for a TNode and, if so, retieve |
713 |
|
* it. |
714 |
|
* |
715 |
|
* @param n the node |
716 |
|
* @param attr an instance of the attribute kind to check |
717 |
|
* @param value a reference to an object of the attribute's value type. |
718 |
|
* <code>value</code> will be set to the value of the attribute, if it is |
719 |
|
* set for <code>nv</code>; otherwise, it will be set to the default value of |
720 |
|
* the attribute. |
721 |
|
* @returns <code>true</code> iff <code>attr</code> is set for <code>n</code>. |
722 |
|
*/ |
723 |
|
template <class AttrKind> |
724 |
|
inline bool getAttribute(TNode n, |
725 |
|
const AttrKind& attr, |
726 |
|
typename AttrKind::value_type& value) const; |
727 |
|
|
728 |
|
/** |
729 |
|
* Set an attribute for a node. If the node doesn't have the |
730 |
|
* attribute, this function assigns one. If the node has one, this |
731 |
|
* overwrites it. |
732 |
|
* |
733 |
|
* @param n the node |
734 |
|
* @param attr an instance of the attribute kind to set |
735 |
|
* @param value the value of <code>attr</code> for <code>n</code> |
736 |
|
*/ |
737 |
|
template <class AttrKind> |
738 |
|
inline void setAttribute(TNode n, |
739 |
|
const AttrKind& attr, |
740 |
|
const typename AttrKind::value_type& value); |
741 |
|
|
742 |
|
/** |
743 |
|
* Retrieve an attribute for a TypeNode. |
744 |
|
* |
745 |
|
* @param n the type node |
746 |
|
* @param attr an instance of the attribute kind to retrieve. |
747 |
|
* @returns the attribute, if set, or a default-constructed |
748 |
|
* <code>AttrKind::value_type</code> if not. |
749 |
|
*/ |
750 |
|
template <class AttrKind> |
751 |
|
inline typename AttrKind::value_type |
752 |
|
getAttribute(TypeNode n, const AttrKind& attr) const; |
753 |
|
|
754 |
|
/** |
755 |
|
* Check whether an attribute is set for a TypeNode. |
756 |
|
* |
757 |
|
* @param n the type node |
758 |
|
* @param attr an instance of the attribute kind to check |
759 |
|
* @returns <code>true</code> iff <code>attr</code> is set for <code>n</code>. |
760 |
|
*/ |
761 |
|
template <class AttrKind> |
762 |
|
inline bool hasAttribute(TypeNode n, |
763 |
|
const AttrKind& attr) const; |
764 |
|
|
765 |
|
/** |
766 |
|
* Check whether an attribute is set for a TypeNode and, if so, retieve |
767 |
|
* it. |
768 |
|
* |
769 |
|
* @param n the type node |
770 |
|
* @param attr an instance of the attribute kind to check |
771 |
|
* @param value a reference to an object of the attribute's value type. |
772 |
|
* <code>value</code> will be set to the value of the attribute, if it is |
773 |
|
* set for <code>nv</code>; otherwise, it will be set to the default value of |
774 |
|
* the attribute. |
775 |
|
* @returns <code>true</code> iff <code>attr</code> is set for <code>n</code>. |
776 |
|
*/ |
777 |
|
template <class AttrKind> |
778 |
|
inline bool getAttribute(TypeNode n, |
779 |
|
const AttrKind& attr, |
780 |
|
typename AttrKind::value_type& value) const; |
781 |
|
|
782 |
|
/** |
783 |
|
* Set an attribute for a type node. If the node doesn't have the |
784 |
|
* attribute, this function assigns one. If the type node has one, |
785 |
|
* this overwrites it. |
786 |
|
* |
787 |
|
* @param n the type node |
788 |
|
* @param attr an instance of the attribute kind to set |
789 |
|
* @param value the value of <code>attr</code> for <code>n</code> |
790 |
|
*/ |
791 |
|
template <class AttrKind> |
792 |
|
inline void setAttribute(TypeNode n, |
793 |
|
const AttrKind& attr, |
794 |
|
const typename AttrKind::value_type& value); |
795 |
|
|
796 |
|
/** Get the (singleton) type for Booleans. */ |
797 |
|
TypeNode booleanType(); |
798 |
|
|
799 |
|
/** Get the (singleton) type for integers. */ |
800 |
|
TypeNode integerType(); |
801 |
|
|
802 |
|
/** Get the (singleton) type for reals. */ |
803 |
|
TypeNode realType(); |
804 |
|
|
805 |
|
/** Get the (singleton) type for strings. */ |
806 |
|
TypeNode stringType(); |
807 |
|
|
808 |
|
/** Get the (singleton) type for RegExp. */ |
809 |
|
TypeNode regExpType(); |
810 |
|
|
811 |
|
/** Get the (singleton) type for rounding modes. */ |
812 |
|
TypeNode roundingModeType(); |
813 |
|
|
814 |
|
/** Get the bound var list type. */ |
815 |
|
TypeNode boundVarListType(); |
816 |
|
|
817 |
|
/** Get the instantiation pattern type. */ |
818 |
|
TypeNode instPatternType(); |
819 |
|
|
820 |
|
/** Get the instantiation pattern type. */ |
821 |
|
TypeNode instPatternListType(); |
822 |
|
|
823 |
|
/** |
824 |
|
* Get the (singleton) type for builtin operators (that is, the type |
825 |
|
* of the Node returned from Node::getOperator() when the operator |
826 |
|
* is built-in, like EQUAL). */ |
827 |
|
TypeNode builtinOperatorType(); |
828 |
|
|
829 |
|
/** |
830 |
|
* Make a function type from domain to range. |
831 |
|
* |
832 |
|
* @param domain the domain type |
833 |
|
* @param range the range type |
834 |
|
* @returns the functional type domain -> range |
835 |
|
*/ |
836 |
|
TypeNode mkFunctionType(const TypeNode& domain, |
837 |
|
const TypeNode& range); |
838 |
|
|
839 |
|
/** |
840 |
|
* Make a function type with input types from |
841 |
|
* argTypes. <code>argTypes</code> must have at least one element. |
842 |
|
* |
843 |
|
* @param argTypes the domain is a tuple (argTypes[0], ..., argTypes[n]) |
844 |
|
* @param range the range type |
845 |
|
* @returns the functional type (argTypes[0], ..., argTypes[n]) -> range |
846 |
|
*/ |
847 |
|
TypeNode mkFunctionType(const std::vector<TypeNode>& argTypes, |
848 |
|
const TypeNode& range); |
849 |
|
|
850 |
|
/** |
851 |
|
* Make a function type with input types from |
852 |
|
* <code>sorts[0..sorts.size()-2]</code> and result type |
853 |
|
* <code>sorts[sorts.size()-1]</code>. <code>sorts</code> must have |
854 |
|
* at least 2 elements. |
855 |
|
* |
856 |
|
* @param sorts The argument and range sort of the function type, where the |
857 |
|
* range type is the last in this vector. |
858 |
|
* @return the function type |
859 |
|
*/ |
860 |
|
TypeNode mkFunctionType(const std::vector<TypeNode>& sorts); |
861 |
|
|
862 |
|
/** |
863 |
|
* Make a predicate type with input types from |
864 |
|
* <code>sorts</code>. The result with be a function type with range |
865 |
|
* <code>BOOLEAN</code>. <code>sorts</code> must have at least one |
866 |
|
* element. |
867 |
|
*/ |
868 |
|
TypeNode mkPredicateType(const std::vector<TypeNode>& sorts); |
869 |
|
|
870 |
|
/** |
871 |
|
* Make a tuple type with types from |
872 |
|
* <code>types</code>. <code>types</code> must have at least one |
873 |
|
* element. |
874 |
|
* |
875 |
|
* @param types a vector of types |
876 |
|
* @returns the tuple type (types[0], ..., types[n]) |
877 |
|
*/ |
878 |
|
TypeNode mkTupleType(const std::vector<TypeNode>& types); |
879 |
|
|
880 |
|
/** |
881 |
|
* Make a record type with the description from rec. |
882 |
|
* |
883 |
|
* @param rec a description of the record |
884 |
|
* @returns the record type |
885 |
|
*/ |
886 |
|
TypeNode mkRecordType(const Record& rec); |
887 |
|
|
888 |
|
/** |
889 |
|
* @returns the symbolic expression type |
890 |
|
*/ |
891 |
|
TypeNode sExprType(); |
892 |
|
|
893 |
|
/** Make the type of floating-point with <code>exp</code> bit exponent and |
894 |
|
<code>sig</code> bit significand */ |
895 |
|
TypeNode mkFloatingPointType(unsigned exp, unsigned sig); |
896 |
|
TypeNode mkFloatingPointType(FloatingPointSize fs); |
897 |
|
|
898 |
|
/** Make the type of bitvectors of size <code>size</code> */ |
899 |
|
TypeNode mkBitVectorType(unsigned size); |
900 |
|
|
901 |
|
/** Make the type of arrays with the given parameterization */ |
902 |
|
inline TypeNode mkArrayType(TypeNode indexType, TypeNode constituentType); |
903 |
|
|
904 |
|
/** Make the type of set with the given parameterization */ |
905 |
|
inline TypeNode mkSetType(TypeNode elementType); |
906 |
|
|
907 |
|
/** Make the type of bags with the given parameterization */ |
908 |
|
TypeNode mkBagType(TypeNode elementType); |
909 |
|
|
910 |
|
/** Make the type of sequences with the given parameterization */ |
911 |
|
TypeNode mkSequenceType(TypeNode elementType); |
912 |
|
|
913 |
|
/** Bits for use in mkDatatypeType() flags. |
914 |
|
* |
915 |
|
* DATATYPE_FLAG_PLACEHOLDER indicates that the type should not be printed |
916 |
|
* out as a definition, for example, in models or during dumping. |
917 |
|
*/ |
918 |
|
enum |
919 |
|
{ |
920 |
|
DATATYPE_FLAG_NONE = 0, |
921 |
|
DATATYPE_FLAG_PLACEHOLDER = 1 |
922 |
|
}; /* enum */ |
923 |
|
|
924 |
|
/** Make a type representing the given datatype. */ |
925 |
|
TypeNode mkDatatypeType(DType& datatype, uint32_t flags = DATATYPE_FLAG_NONE); |
926 |
|
|
927 |
|
/** |
928 |
|
* Make a set of types representing the given datatypes, which may be |
929 |
|
* mutually recursive. |
930 |
|
*/ |
931 |
|
std::vector<TypeNode> mkMutualDatatypeTypes( |
932 |
|
const std::vector<DType>& datatypes, uint32_t flags = DATATYPE_FLAG_NONE); |
933 |
|
|
934 |
|
/** |
935 |
|
* Make a set of types representing the given datatypes, which may |
936 |
|
* be mutually recursive. unresolvedTypes is a set of SortTypes |
937 |
|
* that were used as placeholders in the Datatypes for the Datatypes |
938 |
|
* of the same name. This is just a more complicated version of the |
939 |
|
* above mkMutualDatatypeTypes() function, but is required to handle |
940 |
|
* complex types. |
941 |
|
* |
942 |
|
* For example, unresolvedTypes might contain the single sort "list" |
943 |
|
* (with that name reported from SortType::getName()). The |
944 |
|
* datatypes list might have the single datatype |
945 |
|
* |
946 |
|
* DATATYPE |
947 |
|
* list = cons(car:ARRAY INT OF list, cdr:list) | nil; |
948 |
|
* END; |
949 |
|
* |
950 |
|
* To represent the Type of the array, the user had to create a |
951 |
|
* placeholder type (an uninterpreted sort) to stand for "list" in |
952 |
|
* the type of "car". It is this placeholder sort that should be |
953 |
|
* passed in unresolvedTypes. If the datatype was of the simpler |
954 |
|
* form: |
955 |
|
* |
956 |
|
* DATATYPE |
957 |
|
* list = cons(car:list, cdr:list) | nil; |
958 |
|
* END; |
959 |
|
* |
960 |
|
* then no complicated Type needs to be created, and the above, |
961 |
|
* simpler form of mkMutualDatatypeTypes() is enough. |
962 |
|
*/ |
963 |
|
std::vector<TypeNode> mkMutualDatatypeTypes( |
964 |
|
const std::vector<DType>& datatypes, |
965 |
|
const std::set<TypeNode>& unresolvedTypes, |
966 |
|
uint32_t flags = DATATYPE_FLAG_NONE); |
967 |
|
|
968 |
|
/** |
969 |
|
* Make a type representing a constructor with the given argument (subfield) |
970 |
|
* types and return type range. |
971 |
|
*/ |
972 |
|
TypeNode mkConstructorType(const std::vector<TypeNode>& args, TypeNode range); |
973 |
|
|
974 |
|
/** Make a type representing a selector with the given parameterization */ |
975 |
|
TypeNode mkSelectorType(TypeNode domain, TypeNode range); |
976 |
|
|
977 |
|
/** Make a type representing a tester with given parameterization */ |
978 |
|
TypeNode mkTesterType(TypeNode domain); |
979 |
|
|
980 |
|
/** Make a type representing an updater with the given parameterization */ |
981 |
|
TypeNode mkDatatypeUpdateType(TypeNode domain, TypeNode range); |
982 |
|
|
983 |
|
/** Bits for use in mkSort() flags. */ |
984 |
|
enum |
985 |
|
{ |
986 |
|
SORT_FLAG_NONE = 0, |
987 |
|
SORT_FLAG_PLACEHOLDER = 1 |
988 |
|
}; /* enum */ |
989 |
|
|
990 |
|
/** Make a new (anonymous) sort of arity 0. */ |
991 |
|
TypeNode mkSort(uint32_t flags = SORT_FLAG_NONE); |
992 |
|
|
993 |
|
/** Make a new sort with the given name of arity 0. */ |
994 |
|
TypeNode mkSort(const std::string& name, uint32_t flags = SORT_FLAG_NONE); |
995 |
|
|
996 |
|
/** Make a new sort by parameterizing the given sort constructor. */ |
997 |
|
TypeNode mkSort(TypeNode constructor, |
998 |
|
const std::vector<TypeNode>& children, |
999 |
|
uint32_t flags = SORT_FLAG_NONE); |
1000 |
|
|
1001 |
|
/** Make a new sort with the given name and arity. */ |
1002 |
|
TypeNode mkSortConstructor(const std::string& name, |
1003 |
|
size_t arity, |
1004 |
|
uint32_t flags = SORT_FLAG_NONE); |
1005 |
|
|
1006 |
|
/** |
1007 |
|
* Get the type for the given node and optionally do type checking. |
1008 |
|
* |
1009 |
|
* Initial type computation will be near-constant time if |
1010 |
|
* type checking is not requested. Results are memoized, so that |
1011 |
|
* subsequent calls to getType() without type checking will be |
1012 |
|
* constant time. |
1013 |
|
* |
1014 |
|
* Initial type checking is linear in the size of the expression. |
1015 |
|
* Again, the results are memoized, so that subsequent calls to |
1016 |
|
* getType(), with or without type checking, will be constant |
1017 |
|
* time. |
1018 |
|
* |
1019 |
|
* NOTE: A TypeCheckingException can be thrown even when type |
1020 |
|
* checking is not requested. getType() will always return a |
1021 |
|
* valid and correct type and, thus, an exception will be thrown |
1022 |
|
* when no valid or correct type can be computed (e.g., if the |
1023 |
|
* arguments to a bit-vector operation aren't bit-vectors). When |
1024 |
|
* type checking is not requested, getType() will do the minimum |
1025 |
|
* amount of checking required to return a valid result. |
1026 |
|
* |
1027 |
|
* @param n the Node for which we want a type |
1028 |
|
* @param check whether we should check the type as we compute it |
1029 |
|
* (default: false) |
1030 |
|
*/ |
1031 |
|
TypeNode getType(TNode n, bool check = false); |
1032 |
|
|
1033 |
|
/** Reclaim zombies while there are more than k nodes in the pool (if possible).*/ |
1034 |
|
void reclaimZombiesUntil(uint32_t k); |
1035 |
|
|
1036 |
|
/** Reclaims all zombies (if possible).*/ |
1037 |
|
void reclaimAllZombies(); |
1038 |
|
|
1039 |
|
/** Size of the node pool. */ |
1040 |
|
size_t poolSize() const; |
1041 |
|
|
1042 |
|
/** Deletes a list of attributes from the NM's AttributeManager.*/ |
1043 |
|
void deleteAttributes(const std::vector< const expr::attr::AttributeUniqueId* >& ids); |
1044 |
|
|
1045 |
|
/** |
1046 |
|
* This function gives developers a hook into the NodeManager. |
1047 |
|
* This can be changed in node_manager.cpp without recompiling most of cvc5. |
1048 |
|
* |
1049 |
|
* debugHook is a debugging only function, and should not be present in |
1050 |
|
* any published code! |
1051 |
|
*/ |
1052 |
|
void debugHook(int debugFlag); |
1053 |
|
}; /* class NodeManager */ |
1054 |
|
|
1055 |
|
/** |
1056 |
|
* This class changes the "current" thread-global |
1057 |
|
* <code>NodeManager</code> when it is created and reinstates the |
1058 |
|
* previous thread-global <code>NodeManager</code> when it is |
1059 |
|
* destroyed, effectively maintaining a set of nested |
1060 |
|
* <code>NodeManager</code> scopes. This is especially useful on |
1061 |
|
* public-interface calls into the cvc5 library, where cvc5's notion |
1062 |
|
* of the "current" <code>NodeManager</code> should be set to match |
1063 |
|
* the calling context. See, for example, the implementations of |
1064 |
|
* public calls in the <code>SmtEngine</code> class. |
1065 |
|
* |
1066 |
|
* The client must be careful to create and destroy |
1067 |
|
* <code>NodeManagerScope</code> objects in a well-nested manner (such |
1068 |
|
* as on the stack). You may create a <code>NodeManagerScope</code> |
1069 |
|
* with <code>new</code> and destroy it with <code>delete</code>, or |
1070 |
|
* place it as a data member of an object that is, but if the scope of |
1071 |
|
* these <code>new</code>/<code>delete</code> pairs isn't properly |
1072 |
|
* maintained, the incorrect "current" <code>NodeManager</code> |
1073 |
|
* pointer may be restored after a delete. |
1074 |
|
*/ |
1075 |
|
class NodeManagerScope { |
1076 |
|
/** The old NodeManager, to be restored on destruction. */ |
1077 |
|
NodeManager* d_oldNodeManager; |
1078 |
|
public: |
1079 |
1073086555 |
NodeManagerScope(NodeManager* nm) : d_oldNodeManager(NodeManager::s_current) |
1080 |
|
{ |
1081 |
1073086555 |
NodeManager::s_current = nm; |
1082 |
1073086555 |
Debug("current") << "node manager scope: " << NodeManager::s_current << "\n"; |
1083 |
1073086555 |
} |
1084 |
|
|
1085 |
2146162588 |
~NodeManagerScope() { |
1086 |
1073081294 |
NodeManager::s_current = d_oldNodeManager; |
1087 |
2146162588 |
Debug("current") << "node manager scope: " |
1088 |
1073081294 |
<< "returning to " << NodeManager::s_current << "\n"; |
1089 |
1073081294 |
} |
1090 |
|
};/* class NodeManagerScope */ |
1091 |
|
|
1092 |
10433 |
inline TypeNode NodeManager::mkArrayType(TypeNode indexType, |
1093 |
|
TypeNode constituentType) { |
1094 |
10433 |
CheckArgument(!indexType.isNull(), indexType, |
1095 |
|
"unexpected NULL index type"); |
1096 |
10433 |
CheckArgument(!constituentType.isNull(), constituentType, |
1097 |
|
"unexpected NULL constituent type"); |
1098 |
20866 |
Debug("arrays") << "making array type " << indexType << " " |
1099 |
10433 |
<< constituentType << std::endl; |
1100 |
10433 |
return mkTypeNode(kind::ARRAY_TYPE, indexType, constituentType); |
1101 |
|
} |
1102 |
|
|
1103 |
13054 |
inline TypeNode NodeManager::mkSetType(TypeNode elementType) { |
1104 |
13054 |
CheckArgument(!elementType.isNull(), elementType, |
1105 |
|
"unexpected NULL element type"); |
1106 |
13054 |
Debug("sets") << "making sets type " << elementType << std::endl; |
1107 |
13054 |
return mkTypeNode(kind::SET_TYPE, elementType); |
1108 |
|
} |
1109 |
|
|
1110 |
477465999 |
inline expr::NodeValue* NodeManager::poolLookup(expr::NodeValue* nv) const { |
1111 |
477465999 |
NodeValuePool::const_iterator find = d_nodeValuePool.find(nv); |
1112 |
477465999 |
if(find == d_nodeValuePool.end()) { |
1113 |
30990429 |
return NULL; |
1114 |
|
} else { |
1115 |
446475570 |
return *find; |
1116 |
|
} |
1117 |
|
} |
1118 |
|
|
1119 |
31001073 |
inline void NodeManager::poolInsert(expr::NodeValue* nv) { |
1120 |
31001073 |
Assert(d_nodeValuePool.find(nv) == d_nodeValuePool.end()) |
1121 |
|
<< "NodeValue already in the pool!"; |
1122 |
31001073 |
d_nodeValuePool.insert(nv);// FIXME multithreading |
1123 |
31001073 |
} |
1124 |
|
|
1125 |
30274450 |
inline void NodeManager::poolRemove(expr::NodeValue* nv) { |
1126 |
30274450 |
Assert(d_nodeValuePool.find(nv) != d_nodeValuePool.end()) |
1127 |
|
<< "NodeValue is not in the pool!"; |
1128 |
|
|
1129 |
30274450 |
d_nodeValuePool.erase(nv);// FIXME multithreading |
1130 |
30274450 |
} |
1131 |
|
|
1132 |
|
} // namespace cvc5 |
1133 |
|
|
1134 |
|
#define CVC5__NODE_MANAGER_NEEDS_CONSTANT_MAP |
1135 |
|
#include "expr/metakind.h" |
1136 |
|
#undef CVC5__NODE_MANAGER_NEEDS_CONSTANT_MAP |
1137 |
|
|
1138 |
|
#include "expr/node_builder.h" |
1139 |
|
|
1140 |
|
namespace cvc5 { |
1141 |
|
|
1142 |
|
// general expression-builders |
1143 |
|
|
1144 |
18059123 |
inline bool NodeManager::hasOperator(Kind k) { |
1145 |
18059123 |
switch(kind::MetaKind mk = kind::metaKindOf(k)) { |
1146 |
|
|
1147 |
1884746 |
case kind::metakind::INVALID: |
1148 |
|
case kind::metakind::VARIABLE: |
1149 |
|
case kind::metakind::NULLARY_OPERATOR: |
1150 |
1884746 |
return false; |
1151 |
|
|
1152 |
14198029 |
case kind::metakind::OPERATOR: |
1153 |
|
case kind::metakind::PARAMETERIZED: |
1154 |
14198029 |
return true; |
1155 |
|
|
1156 |
1976348 |
case kind::metakind::CONSTANT: |
1157 |
1976348 |
return false; |
1158 |
|
|
1159 |
|
default: Unhandled() << mk; |
1160 |
|
} |
1161 |
|
} |
1162 |
|
|
1163 |
586622 |
inline Kind NodeManager::operatorToKind(TNode n) { |
1164 |
586622 |
return kind::operatorToKind(n.d_nv); |
1165 |
|
} |
1166 |
|
|
1167 |
10268 |
inline Node NodeManager::mkNode(Kind kind) |
1168 |
|
{ |
1169 |
20536 |
NodeBuilder nb(this, kind); |
1170 |
20536 |
return nb.constructNode(); |
1171 |
|
} |
1172 |
|
|
1173 |
40611455 |
inline Node NodeManager::mkNode(Kind kind, TNode child1) { |
1174 |
81222910 |
NodeBuilder nb(this, kind); |
1175 |
40611455 |
nb << child1; |
1176 |
81222898 |
return nb.constructNode(); |
1177 |
|
} |
1178 |
|
|
1179 |
124356585 |
inline Node NodeManager::mkNode(Kind kind, TNode child1, TNode child2) { |
1180 |
248713170 |
NodeBuilder nb(this, kind); |
1181 |
124356585 |
nb << child1 << child2; |
1182 |
248712792 |
return nb.constructNode(); |
1183 |
|
} |
1184 |
|
|
1185 |
1047304 |
inline Node NodeManager::mkNode(Kind kind, TNode child1, TNode child2, |
1186 |
|
TNode child3) { |
1187 |
2094608 |
NodeBuilder nb(this, kind); |
1188 |
1047304 |
nb << child1 << child2 << child3; |
1189 |
2094576 |
return nb.constructNode(); |
1190 |
|
} |
1191 |
|
|
1192 |
|
// N-ary version |
1193 |
|
template <bool ref_count> |
1194 |
15590810 |
inline Node NodeManager::mkNode(Kind kind, |
1195 |
|
const std::vector<NodeTemplate<ref_count> >& |
1196 |
|
children) { |
1197 |
31181620 |
NodeBuilder nb(this, kind); |
1198 |
15590810 |
nb.append(children); |
1199 |
31181591 |
return nb.constructNode(); |
1200 |
|
} |
1201 |
|
|
1202 |
|
template <bool ref_count> |
1203 |
671866 |
Node NodeManager::mkAnd(const std::vector<NodeTemplate<ref_count> >& children) |
1204 |
|
{ |
1205 |
671866 |
if (children.empty()) |
1206 |
|
{ |
1207 |
58571 |
return mkConst(true); |
1208 |
|
} |
1209 |
613295 |
else if (children.size() == 1) |
1210 |
|
{ |
1211 |
398618 |
return children[0]; |
1212 |
|
} |
1213 |
214677 |
return mkNode(kind::AND, children); |
1214 |
|
} |
1215 |
|
|
1216 |
|
template <bool ref_count> |
1217 |
1090772 |
Node NodeManager::mkOr(const std::vector<NodeTemplate<ref_count> >& children) |
1218 |
|
{ |
1219 |
1090772 |
if (children.empty()) |
1220 |
|
{ |
1221 |
1970 |
return mkConst(false); |
1222 |
|
} |
1223 |
1088802 |
else if (children.size() == 1) |
1224 |
|
{ |
1225 |
134222 |
return children[0]; |
1226 |
|
} |
1227 |
954580 |
return mkNode(kind::OR, children); |
1228 |
|
} |
1229 |
|
|
1230 |
|
// for operators |
1231 |
|
inline Node NodeManager::mkNode(TNode opNode) { |
1232 |
|
NodeBuilder nb(this, operatorToKind(opNode)); |
1233 |
|
if(opNode.getKind() != kind::BUILTIN) { |
1234 |
|
nb << opNode; |
1235 |
|
} |
1236 |
|
return nb.constructNode(); |
1237 |
|
} |
1238 |
|
|
1239 |
367592 |
inline Node NodeManager::mkNode(TNode opNode, TNode child1) { |
1240 |
735184 |
NodeBuilder nb(this, operatorToKind(opNode)); |
1241 |
367592 |
if(opNode.getKind() != kind::BUILTIN) { |
1242 |
367592 |
nb << opNode; |
1243 |
|
} |
1244 |
367592 |
nb << child1; |
1245 |
735184 |
return nb.constructNode(); |
1246 |
|
} |
1247 |
|
|
1248 |
64 |
inline Node NodeManager::mkNode(TNode opNode, TNode child1, TNode child2) { |
1249 |
128 |
NodeBuilder nb(this, operatorToKind(opNode)); |
1250 |
64 |
if(opNode.getKind() != kind::BUILTIN) { |
1251 |
64 |
nb << opNode; |
1252 |
|
} |
1253 |
64 |
nb << child1 << child2; |
1254 |
128 |
return nb.constructNode(); |
1255 |
|
} |
1256 |
|
|
1257 |
4 |
inline Node NodeManager::mkNode(TNode opNode, TNode child1, TNode child2, |
1258 |
|
TNode child3) { |
1259 |
8 |
NodeBuilder nb(this, operatorToKind(opNode)); |
1260 |
4 |
if(opNode.getKind() != kind::BUILTIN) { |
1261 |
4 |
nb << opNode; |
1262 |
|
} |
1263 |
4 |
nb << child1 << child2 << child3; |
1264 |
8 |
return nb.constructNode(); |
1265 |
|
} |
1266 |
|
|
1267 |
|
// N-ary version for operators |
1268 |
|
template <bool ref_count> |
1269 |
45695 |
inline Node NodeManager::mkNode(TNode opNode, |
1270 |
|
const std::vector<NodeTemplate<ref_count> >& |
1271 |
|
children) { |
1272 |
91390 |
NodeBuilder nb(this, operatorToKind(opNode)); |
1273 |
45695 |
if(opNode.getKind() != kind::BUILTIN) { |
1274 |
866 |
nb << opNode; |
1275 |
|
} |
1276 |
45695 |
nb.append(children); |
1277 |
91390 |
return nb.constructNode(); |
1278 |
|
} |
1279 |
|
|
1280 |
30045 |
inline TypeNode NodeManager::mkTypeNode(Kind kind, TypeNode child1) { |
1281 |
30045 |
return (NodeBuilder(this, kind) << child1).constructTypeNode(); |
1282 |
|
} |
1283 |
|
|
1284 |
43779 |
inline TypeNode NodeManager::mkTypeNode(Kind kind, TypeNode child1, |
1285 |
|
TypeNode child2) { |
1286 |
43779 |
return (NodeBuilder(this, kind) << child1 << child2).constructTypeNode(); |
1287 |
|
} |
1288 |
|
|
1289 |
|
inline TypeNode NodeManager::mkTypeNode(Kind kind, TypeNode child1, |
1290 |
|
TypeNode child2, TypeNode child3) { |
1291 |
|
return (NodeBuilder(this, kind) << child1 << child2 << child3) |
1292 |
|
.constructTypeNode(); |
1293 |
|
} |
1294 |
|
|
1295 |
|
// N-ary version for types |
1296 |
72806 |
inline TypeNode NodeManager::mkTypeNode(Kind kind, |
1297 |
|
const std::vector<TypeNode>& children) { |
1298 |
72806 |
return NodeBuilder(this, kind).append(children).constructTypeNode(); |
1299 |
|
} |
1300 |
|
|
1301 |
|
template <class T> |
1302 |
218739763 |
Node NodeManager::mkConst(const T& val) { |
1303 |
218739763 |
return mkConstInternal<Node, T>(val); |
1304 |
|
} |
1305 |
|
|
1306 |
|
template <class T> |
1307 |
32193663 |
TypeNode NodeManager::mkTypeConst(const T& val) { |
1308 |
32193663 |
return mkConstInternal<TypeNode, T>(val); |
1309 |
|
} |
1310 |
|
|
1311 |
|
template <class NodeClass, class T> |
1312 |
250933426 |
NodeClass NodeManager::mkConstInternal(const T& val) { |
1313 |
|
// This method indirectly calls `NodeValue::inc()`, which relies on having |
1314 |
|
// the correct `NodeManager` in scope. |
1315 |
501866852 |
NodeManagerScope nms(this); |
1316 |
|
|
1317 |
|
// typedef typename kind::metakind::constantMap<T>::OwningTheory theory_t; |
1318 |
250933426 |
NVStorage<1> nvStorage; |
1319 |
250933426 |
expr::NodeValue& nvStack = reinterpret_cast<expr::NodeValue&>(nvStorage); |
1320 |
|
|
1321 |
250933426 |
nvStack.d_id = 0; |
1322 |
250933426 |
nvStack.d_kind = kind::metakind::ConstantMap<T>::kind; |
1323 |
250933426 |
nvStack.d_rc = 0; |
1324 |
250933426 |
nvStack.d_nchildren = 1; |
1325 |
|
|
1326 |
|
#if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) |
1327 |
|
#pragma GCC diagnostic push |
1328 |
|
#pragma GCC diagnostic ignored "-Warray-bounds" |
1329 |
|
#endif |
1330 |
|
|
1331 |
250933426 |
nvStack.d_children[0] = |
1332 |
|
const_cast<expr::NodeValue*>(reinterpret_cast<const expr::NodeValue*>(&val)); |
1333 |
250933426 |
expr::NodeValue* nv = poolLookup(&nvStack); |
1334 |
|
|
1335 |
|
#if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) |
1336 |
|
#pragma GCC diagnostic pop |
1337 |
|
#endif |
1338 |
|
|
1339 |
250933426 |
if(nv != NULL) { |
1340 |
247447969 |
return NodeClass(nv); |
1341 |
|
} |
1342 |
|
|
1343 |
3485457 |
nv = (expr::NodeValue*) |
1344 |
3485457 |
std::malloc(sizeof(expr::NodeValue) + sizeof(T)); |
1345 |
3485457 |
if(nv == NULL) { |
1346 |
|
throw std::bad_alloc(); |
1347 |
|
} |
1348 |
|
|
1349 |
3485457 |
nv->d_nchildren = 0; |
1350 |
3485457 |
nv->d_kind = kind::metakind::ConstantMap<T>::kind; |
1351 |
3485457 |
nv->d_id = next_id++;// FIXME multithreading |
1352 |
3485457 |
nv->d_rc = 0; |
1353 |
|
|
1354 |
|
//OwningTheory::mkConst(val); |
1355 |
3485457 |
new (&nv->d_children) T(val); |
1356 |
|
|
1357 |
3485457 |
poolInsert(nv); |
1358 |
3485457 |
if(Debug.isOn("gc")) { |
1359 |
|
Debug("gc") << "creating node value " << nv |
1360 |
|
<< " [" << nv->d_id << "]: "; |
1361 |
|
nv->printAst(Debug("gc")); |
1362 |
|
Debug("gc") << std::endl; |
1363 |
|
} |
1364 |
|
|
1365 |
3485457 |
return NodeClass(nv); |
1366 |
|
} |
1367 |
|
|
1368 |
|
} // namespace cvc5 |
1369 |
|
|
1370 |
|
#endif /* CVC5__NODE_MANAGER_H */ |