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 |
|
#include "expr/dtype.h" |
16 |
|
|
17 |
|
#include <sstream> |
18 |
|
|
19 |
|
#include "expr/dtype_cons.h" |
20 |
|
#include "expr/node_algorithm.h" |
21 |
|
#include "expr/skolem_manager.h" |
22 |
|
#include "expr/type_matcher.h" |
23 |
|
#include "util/rational.h" |
24 |
|
|
25 |
|
using namespace cvc5::kind; |
26 |
|
|
27 |
|
namespace cvc5 { |
28 |
|
|
29 |
3594 |
DType::DType(std::string name, bool isCo) |
30 |
|
: d_name(name), |
31 |
|
d_params(), |
32 |
|
d_isCo(isCo), |
33 |
|
d_isTuple(false), |
34 |
|
d_isRecord(false), |
35 |
|
d_constructors(), |
36 |
|
d_resolved(false), |
37 |
|
d_self(), |
38 |
|
d_involvesExt(false), |
39 |
|
d_involvesUt(false), |
40 |
|
d_sygusAllowConst(false), |
41 |
|
d_sygusAllowAll(false), |
42 |
7188 |
d_card(CardinalityUnknown()), |
43 |
|
d_wellFounded(0), |
44 |
10782 |
d_nestedRecursion(0) |
45 |
|
{ |
46 |
3594 |
} |
47 |
|
|
48 |
888 |
DType::DType(std::string name, const std::vector<TypeNode>& params, bool isCo) |
49 |
|
: d_name(name), |
50 |
|
d_params(params), |
51 |
|
d_isCo(isCo), |
52 |
|
d_isTuple(false), |
53 |
|
d_isRecord(false), |
54 |
|
d_constructors(), |
55 |
|
d_resolved(false), |
56 |
|
d_self(), |
57 |
|
d_involvesExt(false), |
58 |
|
d_involvesUt(false), |
59 |
|
d_sygusAllowConst(false), |
60 |
|
d_sygusAllowAll(false), |
61 |
1776 |
d_card(CardinalityUnknown()), |
62 |
|
d_wellFounded(0), |
63 |
2664 |
d_nestedRecursion(0) |
64 |
|
{ |
65 |
888 |
} |
66 |
|
|
67 |
19800 |
DType::~DType() {} |
68 |
|
|
69 |
955322 |
std::string DType::getName() const { return d_name; } |
70 |
8261781 |
size_t DType::getNumConstructors() const { return d_constructors.size(); } |
71 |
|
|
72 |
1554794 |
bool DType::isParametric() const { return d_params.size() > 0; } |
73 |
6640 |
size_t DType::getNumParameters() const { return d_params.size(); } |
74 |
2243 |
TypeNode DType::getParameter(size_t i) const |
75 |
|
{ |
76 |
2243 |
Assert(isParametric()); |
77 |
2243 |
Assert(i < d_params.size()); |
78 |
2243 |
return d_params[i]; |
79 |
|
} |
80 |
|
|
81 |
601 |
std::vector<TypeNode> DType::getParameters() const |
82 |
|
{ |
83 |
601 |
Assert(isParametric()); |
84 |
601 |
return d_params; |
85 |
|
} |
86 |
|
|
87 |
636018 |
bool DType::isCodatatype() const { return d_isCo; } |
88 |
|
|
89 |
1918299 |
bool DType::isSygus() const { return !d_sygusType.isNull(); } |
90 |
|
|
91 |
39965 |
bool DType::isTuple() const { return d_isTuple; } |
92 |
|
|
93 |
8 |
bool DType::isRecord() const { return d_isRecord; } |
94 |
|
|
95 |
800311 |
bool DType::isResolved() const { return d_resolved; } |
96 |
|
|
97 |
2578 |
const DType& DType::datatypeOf(Node item) |
98 |
|
{ |
99 |
5156 |
TypeNode t = item.getType(); |
100 |
2578 |
switch (t.getKind()) |
101 |
|
{ |
102 |
2572 |
case CONSTRUCTOR_TYPE: return t[t.getNumChildren() - 1].getDType(); |
103 |
6 |
case SELECTOR_TYPE: |
104 |
|
case TESTER_TYPE: |
105 |
6 |
case UPDATER_TYPE: return t[0].getDType(); |
106 |
|
default: |
107 |
|
Unhandled() << "arg must be a datatype constructor, selector, or tester"; |
108 |
|
} |
109 |
|
} |
110 |
|
|
111 |
3322334 |
size_t DType::indexOf(Node item) |
112 |
|
{ |
113 |
3322334 |
Assert(item.getType().isConstructor() || item.getType().isTester() |
114 |
|
|| item.getType().isSelector() || item.getType().isUpdater()); |
115 |
3322334 |
return indexOfInternal(item); |
116 |
|
} |
117 |
|
|
118 |
3322334 |
size_t DType::indexOfInternal(Node item) |
119 |
|
{ |
120 |
3322334 |
if (item.getKind() == APPLY_TYPE_ASCRIPTION) |
121 |
|
{ |
122 |
597 |
return indexOf(item[0]); |
123 |
|
} |
124 |
3321737 |
Assert(item.hasAttribute(DTypeIndexAttr())); |
125 |
3321737 |
return item.getAttribute(DTypeIndexAttr()); |
126 |
|
} |
127 |
|
|
128 |
2040 |
size_t DType::cindexOf(Node item) |
129 |
|
{ |
130 |
2040 |
Assert(item.getType().isSelector() || item.getType().isUpdater()); |
131 |
2040 |
return cindexOfInternal(item); |
132 |
|
} |
133 |
2040 |
size_t DType::cindexOfInternal(Node item) |
134 |
|
{ |
135 |
2040 |
if (item.getKind() == APPLY_TYPE_ASCRIPTION) |
136 |
|
{ |
137 |
|
return cindexOf(item[0]); |
138 |
|
} |
139 |
2040 |
Assert(item.hasAttribute(DTypeConsIndexAttr())); |
140 |
2040 |
return item.getAttribute(DTypeConsIndexAttr()); |
141 |
|
} |
142 |
|
|
143 |
4476 |
bool DType::resolve(const std::map<std::string, TypeNode>& resolutions, |
144 |
|
const std::vector<TypeNode>& placeholders, |
145 |
|
const std::vector<TypeNode>& replacements, |
146 |
|
const std::vector<TypeNode>& paramTypes, |
147 |
|
const std::vector<TypeNode>& paramReplacements) |
148 |
|
{ |
149 |
4476 |
Trace("datatypes-init") << "DType::resolve: " << std::endl; |
150 |
4476 |
Assert(!d_resolved); |
151 |
4476 |
Assert(resolutions.find(d_name) != resolutions.end()); |
152 |
4476 |
Assert(placeholders.size() == replacements.size()); |
153 |
4476 |
Assert(paramTypes.size() == paramReplacements.size()); |
154 |
4476 |
Assert(getNumConstructors() > 0); |
155 |
8952 |
TypeNode self = (*resolutions.find(d_name)).second; |
156 |
4476 |
Assert(&self.getDType() == this); |
157 |
4476 |
d_resolved = true; |
158 |
4476 |
size_t index = 0; |
159 |
18336 |
for (std::shared_ptr<DTypeConstructor> ctor : d_constructors) |
160 |
|
{ |
161 |
13860 |
Trace("datatypes-init") << "DType::resolve ctor " << std::endl; |
162 |
13860 |
if (!ctor->resolve(self, |
163 |
|
resolutions, |
164 |
|
placeholders, |
165 |
|
replacements, |
166 |
|
paramTypes, |
167 |
|
paramReplacements, |
168 |
|
index)) |
169 |
|
{ |
170 |
|
return false; |
171 |
|
} |
172 |
13860 |
ctor->d_constructor.setAttribute(DTypeIndexAttr(), index); |
173 |
13860 |
ctor->d_tester.setAttribute(DTypeIndexAttr(), index++); |
174 |
13860 |
Assert(ctor->isResolved()); |
175 |
13860 |
Trace("datatypes-init") << "DType::resolve ctor finished" << std::endl; |
176 |
|
} |
177 |
4476 |
d_self = self; |
178 |
|
|
179 |
4476 |
d_involvesExt = false; |
180 |
4476 |
d_involvesUt = false; |
181 |
18336 |
for (const std::shared_ptr<DTypeConstructor>& ctor : d_constructors) |
182 |
|
{ |
183 |
13860 |
if (ctor->involvesExternalType()) |
184 |
|
{ |
185 |
966 |
d_involvesExt = true; |
186 |
|
} |
187 |
13860 |
if (ctor->involvesUninterpretedType()) |
188 |
|
{ |
189 |
6982 |
d_involvesUt = true; |
190 |
|
} |
191 |
|
} |
192 |
|
|
193 |
4476 |
if (isSygus()) |
194 |
|
{ |
195 |
|
// all datatype constructors should be sygus and have sygus operators whose |
196 |
|
// free variables are subsets of sygus bound var list. |
197 |
3404 |
std::unordered_set<Node> svs; |
198 |
5100 |
for (const Node& sv : d_sygusBvl) |
199 |
|
{ |
200 |
3398 |
svs.insert(sv); |
201 |
|
} |
202 |
11759 |
for (size_t i = 0, ncons = d_constructors.size(); i < ncons; i++) |
203 |
|
{ |
204 |
20114 |
Node sop = d_constructors[i]->getSygusOp(); |
205 |
10057 |
Assert(!sop.isNull()) |
206 |
|
<< "Sygus datatype contains a non-sygus constructor"; |
207 |
20114 |
std::unordered_set<Node> fvs; |
208 |
10057 |
expr::getFreeVariables(sop, fvs); |
209 |
11495 |
for (const Node& v : fvs) |
210 |
|
{ |
211 |
1438 |
if (svs.find(v) == svs.end()) |
212 |
|
{ |
213 |
|
// return false, indicating we should abort, since this datatype is |
214 |
|
// not well formed. |
215 |
|
return false; |
216 |
|
} |
217 |
|
} |
218 |
|
} |
219 |
|
} |
220 |
4476 |
Trace("datatypes-init") << "DType::resolve: finished" << std::endl; |
221 |
4476 |
return true; |
222 |
|
} |
223 |
|
|
224 |
13860 |
void DType::addConstructor(std::shared_ptr<DTypeConstructor> c) |
225 |
|
{ |
226 |
13860 |
Assert(!d_resolved); |
227 |
13860 |
d_constructors.push_back(c); |
228 |
13860 |
} |
229 |
|
|
230 |
10028 |
void DType::addSygusConstructor(Node op, |
231 |
|
const std::string& cname, |
232 |
|
const std::vector<TypeNode>& cargs, |
233 |
|
int weight) |
234 |
|
{ |
235 |
|
// avoid name clashes |
236 |
20056 |
std::stringstream ss; |
237 |
10028 |
ss << getName() << "_" << getNumConstructors() << "_" << cname; |
238 |
20056 |
std::string name = ss.str(); |
239 |
10028 |
unsigned cweight = weight >= 0 ? weight : (cargs.empty() ? 0 : 1); |
240 |
|
std::shared_ptr<DTypeConstructor> c = |
241 |
20056 |
std::make_shared<DTypeConstructor>(name, cweight); |
242 |
10028 |
c->setSygus(op); |
243 |
21307 |
for (size_t j = 0, nargs = cargs.size(); j < nargs; j++) |
244 |
|
{ |
245 |
22558 |
std::stringstream sname; |
246 |
11279 |
sname << name << "_" << j; |
247 |
11279 |
c->addArg(sname.str(), cargs[j]); |
248 |
|
} |
249 |
10028 |
addConstructor(c); |
250 |
10028 |
} |
251 |
|
|
252 |
1702 |
void DType::setSygus(TypeNode st, Node bvl, bool allowConst, bool allowAll) |
253 |
|
{ |
254 |
1702 |
Assert(!d_resolved); |
255 |
|
// We can be in a case where the only rule specified was |
256 |
|
// (Constant T), in which case we have not yet added a constructor. We |
257 |
|
// ensure an arbitrary constant is added in this case. We additionally |
258 |
|
// add a constant if the grammar has only non-nullary constructors, since this |
259 |
|
// ensures the datatype is well-founded (see 3423). |
260 |
|
// Notice we only want to do this for sygus datatypes that are user-provided. |
261 |
|
// At the moment, the condition !allow_all implies the grammar is |
262 |
|
// user-provided and hence may require a default constant. |
263 |
|
// For the SyGuS API, we could consider requiring the user to explicitly add |
264 |
|
// the "any constant" constructor with a call instead of passing a flag. This |
265 |
|
// would make the block of code unnecessary. |
266 |
1702 |
if (allowConst && !allowAll) |
267 |
|
{ |
268 |
|
// if I don't already have a constant (0-ary constructor) |
269 |
35 |
bool hasConstant = false; |
270 |
59 |
for (size_t i = 0, ncons = getNumConstructors(); i < ncons; i++) |
271 |
|
{ |
272 |
30 |
if ((*this)[i].getNumArgs() == 0) |
273 |
|
{ |
274 |
6 |
hasConstant = true; |
275 |
6 |
break; |
276 |
|
} |
277 |
|
} |
278 |
35 |
if (!hasConstant) |
279 |
|
{ |
280 |
|
// add an arbitrary one |
281 |
58 |
Node op = st.mkGroundTerm(); |
282 |
|
// use same naming convention as SygusDatatype |
283 |
58 |
std::stringstream ss; |
284 |
29 |
ss << getName() << "_" << getNumConstructors() << "_" << op; |
285 |
|
// it has zero weight |
286 |
|
std::shared_ptr<DTypeConstructor> c = |
287 |
58 |
std::make_shared<DTypeConstructor>(ss.str(), 0); |
288 |
29 |
c->setSygus(op); |
289 |
29 |
addConstructor(c); |
290 |
|
} |
291 |
|
} |
292 |
|
|
293 |
1702 |
d_sygusType = st; |
294 |
1702 |
d_sygusBvl = bvl; |
295 |
1702 |
d_sygusAllowConst = allowConst || allowAll; |
296 |
1702 |
d_sygusAllowAll = allowAll; |
297 |
1702 |
} |
298 |
|
|
299 |
1770 |
void DType::setTuple() |
300 |
|
{ |
301 |
1770 |
Assert(!d_resolved); |
302 |
1770 |
d_isTuple = true; |
303 |
1770 |
} |
304 |
|
|
305 |
8 |
void DType::setRecord() |
306 |
|
{ |
307 |
8 |
Assert(!d_resolved); |
308 |
8 |
d_isRecord = true; |
309 |
8 |
} |
310 |
|
|
311 |
3090 |
Cardinality DType::getCardinality(TypeNode t) const |
312 |
|
{ |
313 |
3090 |
Trace("datatypes-init") << "DType::getCardinality " << std::endl; |
314 |
3090 |
Assert(isResolved()); |
315 |
3090 |
Assert(t.isDatatype() && t.getDType().getTypeNode() == d_self); |
316 |
6180 |
std::vector<TypeNode> processing; |
317 |
3090 |
computeCardinality(t, processing); |
318 |
6180 |
return d_card; |
319 |
|
} |
320 |
|
|
321 |
22 |
Cardinality DType::getCardinality() const |
322 |
|
{ |
323 |
22 |
Assert(!isParametric()); |
324 |
22 |
return getCardinality(d_self); |
325 |
|
} |
326 |
|
|
327 |
7583 |
Cardinality DType::computeCardinality(TypeNode t, |
328 |
|
std::vector<TypeNode>& processing) const |
329 |
|
{ |
330 |
7583 |
Trace("datatypes-init") << "DType::computeCardinality " << std::endl; |
331 |
7583 |
Assert(isResolved()); |
332 |
22749 |
if (std::find(processing.begin(), processing.end(), d_self) |
333 |
22749 |
!= processing.end()) |
334 |
|
{ |
335 |
292 |
d_card = Cardinality::INTEGERS; |
336 |
292 |
return d_card; |
337 |
|
} |
338 |
7291 |
processing.push_back(d_self); |
339 |
14582 |
Cardinality c = 0; |
340 |
21182 |
for (std::shared_ptr<DTypeConstructor> ctor : d_constructors) |
341 |
|
{ |
342 |
13891 |
c += ctor->computeCardinality(t, processing); |
343 |
|
} |
344 |
7291 |
d_card = c; |
345 |
7291 |
processing.pop_back(); |
346 |
7291 |
return d_card; |
347 |
|
} |
348 |
|
|
349 |
139400 |
bool DType::isRecursiveSingleton(TypeNode t) const |
350 |
|
{ |
351 |
139400 |
Trace("datatypes-init") << "DType::isRecursiveSingleton " << std::endl; |
352 |
139400 |
Assert(isResolved()); |
353 |
139400 |
Assert(t.isDatatype() && t.getDType().getTypeNode() == d_self); |
354 |
139400 |
if (d_cardRecSingleton.find(t) != d_cardRecSingleton.end()) |
355 |
|
{ |
356 |
138291 |
return d_cardRecSingleton[t] == 1; |
357 |
|
} |
358 |
1109 |
if (isCodatatype()) |
359 |
|
{ |
360 |
11 |
Assert(d_cardUAssume[t].empty()); |
361 |
22 |
std::vector<TypeNode> processing; |
362 |
11 |
if (computeCardinalityRecSingleton(t, processing, d_cardUAssume[t])) |
363 |
|
{ |
364 |
1 |
d_cardRecSingleton[t] = 1; |
365 |
1 |
if (Trace.isOn("dt-card")) |
366 |
|
{ |
367 |
|
Trace("dt-card") << "DType " << getName() |
368 |
|
<< " is recursive singleton, dependent upon " |
369 |
|
<< d_cardUAssume[t].size() |
370 |
|
<< " uninterpreted sorts: " << std::endl; |
371 |
|
for (size_t i = 0; i < d_cardUAssume[t].size(); i++) |
372 |
|
{ |
373 |
|
Trace("dt-card") << " " << d_cardUAssume[t][i] << std::endl; |
374 |
|
} |
375 |
|
Trace("dt-card") << std::endl; |
376 |
|
} |
377 |
|
} |
378 |
|
else |
379 |
|
{ |
380 |
10 |
d_cardRecSingleton[t] = -1; |
381 |
|
} |
382 |
|
} |
383 |
|
else |
384 |
|
{ |
385 |
1098 |
d_cardRecSingleton[t] = -1; |
386 |
|
} |
387 |
1109 |
return d_cardRecSingleton[t] == 1; |
388 |
|
} |
389 |
|
|
390 |
|
bool DType::isRecursiveSingleton() const |
391 |
|
{ |
392 |
|
Assert(!isParametric()); |
393 |
|
return isRecursiveSingleton(d_self); |
394 |
|
} |
395 |
|
|
396 |
1 |
unsigned DType::getNumRecursiveSingletonArgTypes(TypeNode t) const |
397 |
|
{ |
398 |
1 |
Assert(d_cardRecSingleton.find(t) != d_cardRecSingleton.end()); |
399 |
1 |
Assert(isRecursiveSingleton(t)); |
400 |
1 |
return d_cardUAssume[t].size(); |
401 |
|
} |
402 |
|
|
403 |
|
unsigned DType::getNumRecursiveSingletonArgTypes() const |
404 |
|
{ |
405 |
|
Assert(!isParametric()); |
406 |
|
return getNumRecursiveSingletonArgTypes(d_self); |
407 |
|
} |
408 |
|
|
409 |
|
TypeNode DType::getRecursiveSingletonArgType(TypeNode t, size_t i) const |
410 |
|
{ |
411 |
|
Assert(d_cardRecSingleton.find(t) != d_cardRecSingleton.end()); |
412 |
|
Assert(isRecursiveSingleton(t)); |
413 |
|
return d_cardUAssume[t][i]; |
414 |
|
} |
415 |
|
|
416 |
|
TypeNode DType::getRecursiveSingletonArgType(size_t i) const |
417 |
|
{ |
418 |
|
Assert(!isParametric()); |
419 |
|
return getRecursiveSingletonArgType(d_self, i); |
420 |
|
} |
421 |
|
|
422 |
14 |
bool DType::computeCardinalityRecSingleton( |
423 |
|
TypeNode t, |
424 |
|
std::vector<TypeNode>& processing, |
425 |
|
std::vector<TypeNode>& u_assume) const |
426 |
|
{ |
427 |
28 |
Trace("datatypes-init") << "DType::computeCardinalityRecSingleton " |
428 |
14 |
<< std::endl; |
429 |
42 |
if (std::find(processing.begin(), processing.end(), d_self) |
430 |
42 |
!= processing.end()) |
431 |
|
{ |
432 |
1 |
return true; |
433 |
|
} |
434 |
13 |
if (d_cardRecSingleton[t] == 0) |
435 |
|
{ |
436 |
|
// if not yet computed |
437 |
13 |
if (d_constructors.size() != 1) |
438 |
|
{ |
439 |
10 |
return false; |
440 |
|
} |
441 |
3 |
bool success = false; |
442 |
3 |
processing.push_back(d_self); |
443 |
4 |
for (size_t i = 0, nargs = d_constructors[0]->getNumArgs(); i < nargs; i++) |
444 |
|
{ |
445 |
4 |
TypeNode tc = d_constructors[0]->getArgType(i); |
446 |
|
// if it is an uninterpreted sort, then we depend on it having cardinality |
447 |
|
// one |
448 |
3 |
if (tc.isSort()) |
449 |
|
{ |
450 |
|
if (std::find(u_assume.begin(), u_assume.end(), tc) == u_assume.end()) |
451 |
|
{ |
452 |
|
u_assume.push_back(tc); |
453 |
|
} |
454 |
|
// if it is a datatype, recurse |
455 |
|
} |
456 |
3 |
else if (tc.isDatatype()) |
457 |
|
{ |
458 |
3 |
const DType& dt = tc.getDType(); |
459 |
3 |
if (!dt.computeCardinalityRecSingleton(t, processing, u_assume)) |
460 |
|
{ |
461 |
2 |
return false; |
462 |
|
} |
463 |
|
else |
464 |
|
{ |
465 |
1 |
success = true; |
466 |
|
} |
467 |
|
// if it is a builtin type, it must have cardinality one |
468 |
|
} |
469 |
|
else if (!tc.getCardinality().isOne()) |
470 |
|
{ |
471 |
|
return false; |
472 |
|
} |
473 |
|
} |
474 |
1 |
processing.pop_back(); |
475 |
1 |
return success; |
476 |
|
} |
477 |
|
else if (d_cardRecSingleton[t] == -1) |
478 |
|
{ |
479 |
|
return false; |
480 |
|
} |
481 |
|
for (size_t i = 0, csize = d_cardUAssume[t].size(); i < csize; i++) |
482 |
|
{ |
483 |
|
if (std::find(u_assume.begin(), u_assume.end(), d_cardUAssume[t][i]) |
484 |
|
== u_assume.end()) |
485 |
|
{ |
486 |
|
u_assume.push_back(d_cardUAssume[t][i]); |
487 |
|
} |
488 |
|
} |
489 |
|
return true; |
490 |
|
} |
491 |
|
|
492 |
126030 |
CardinalityClass DType::getCardinalityClass(TypeNode t) const |
493 |
|
{ |
494 |
126030 |
Trace("datatypes-init") << "DType::isFinite " << std::endl; |
495 |
126030 |
Assert(isResolved()); |
496 |
126030 |
Assert(t.isDatatype() && t.getDType().getTypeNode() == d_self); |
497 |
|
|
498 |
|
// is this already in the cache ? |
499 |
126030 |
std::map<TypeNode, CardinalityClass>::const_iterator it = d_cardClass.find(t); |
500 |
126030 |
if (it != d_cardClass.end()) |
501 |
|
{ |
502 |
124200 |
return it->second; |
503 |
|
} |
504 |
|
// it is the max cardinality class of a constructor, with base case ONE |
505 |
|
// if we have one constructor and FINITE otherwise. |
506 |
1830 |
CardinalityClass c = d_constructors.size() == 1 ? CardinalityClass::ONE |
507 |
1830 |
: CardinalityClass::FINITE; |
508 |
9071 |
for (std::shared_ptr<DTypeConstructor> ctor : d_constructors) |
509 |
|
{ |
510 |
7241 |
CardinalityClass cc = ctor->getCardinalityClass(t); |
511 |
7241 |
c = maxCardinalityClass(c, cc); |
512 |
|
} |
513 |
1830 |
d_cardClass[t] = c; |
514 |
1830 |
return c; |
515 |
|
} |
516 |
14 |
CardinalityClass DType::getCardinalityClass() const |
517 |
|
{ |
518 |
14 |
Assert(isResolved() && !isParametric()); |
519 |
14 |
return getCardinalityClass(d_self); |
520 |
|
} |
521 |
|
|
522 |
22 |
bool DType::isFinite(TypeNode t, bool fmfEnabled) const |
523 |
|
{ |
524 |
22 |
return isCardinalityClassFinite(getCardinalityClass(t), fmfEnabled); |
525 |
|
} |
526 |
|
|
527 |
22 |
bool DType::isFinite(bool fmfEnabled) const |
528 |
|
{ |
529 |
22 |
return isFinite(d_self, fmfEnabled); |
530 |
|
} |
531 |
|
|
532 |
25603 |
bool DType::isWellFounded() const |
533 |
|
{ |
534 |
25603 |
Assert(isResolved()); |
535 |
25603 |
if (d_wellFounded != 0) |
536 |
|
{ |
537 |
|
// already computed |
538 |
23409 |
return d_wellFounded == 1; |
539 |
|
} |
540 |
2194 |
Trace("datatypes-init") << "DType::isWellFounded " << getName() << std::endl; |
541 |
4388 |
std::vector<TypeNode> processing; |
542 |
2194 |
if (!computeWellFounded(processing)) |
543 |
|
{ |
544 |
|
// not well-founded since no ground term can be constructed |
545 |
4 |
Trace("datatypes-init") << "DType::isWellFounded: false for " << getName() |
546 |
2 |
<< " due to no ground terms." << std::endl; |
547 |
2 |
d_wellFounded = -1; |
548 |
2 |
return false; |
549 |
|
} |
550 |
4384 |
Trace("datatypes-init") << "DType::isWellFounded: true for " << getName() |
551 |
2192 |
<< std::endl; |
552 |
2192 |
d_wellFounded = 1; |
553 |
2192 |
return true; |
554 |
|
} |
555 |
|
|
556 |
4537 |
bool DType::computeWellFounded(std::vector<TypeNode>& processing) const |
557 |
|
{ |
558 |
4537 |
Trace("datatypes-init") << "DType::computeWellFounded " << std::endl; |
559 |
4537 |
Assert(isResolved()); |
560 |
13611 |
if (std::find(processing.begin(), processing.end(), d_self) |
561 |
13611 |
!= processing.end()) |
562 |
|
{ |
563 |
762 |
return d_isCo; |
564 |
|
} |
565 |
3775 |
processing.push_back(d_self); |
566 |
4581 |
for (std::shared_ptr<DTypeConstructor> ctor : d_constructors) |
567 |
|
{ |
568 |
4521 |
if (ctor->computeWellFounded(processing)) |
569 |
|
{ |
570 |
3715 |
processing.pop_back(); |
571 |
3715 |
return true; |
572 |
|
} |
573 |
|
else |
574 |
|
{ |
575 |
1612 |
Trace("dt-wf") << "Constructor " << ctor->getName() |
576 |
806 |
<< " is not well-founded." << std::endl; |
577 |
|
} |
578 |
|
} |
579 |
60 |
processing.pop_back(); |
580 |
120 |
Trace("dt-wf") << "DType " << getName() << " is not well-founded." |
581 |
60 |
<< std::endl; |
582 |
60 |
return false; |
583 |
|
} |
584 |
|
|
585 |
105529 |
Node DType::mkGroundTerm(TypeNode t) const |
586 |
|
{ |
587 |
105529 |
Trace("datatypes-init") << "DType::mkGroundTerm of type " << t << std::endl; |
588 |
105529 |
Assert(isResolved()); |
589 |
105529 |
return mkGroundTermInternal(t, false); |
590 |
|
} |
591 |
|
|
592 |
109148 |
Node DType::mkGroundValue(TypeNode t) const |
593 |
|
{ |
594 |
109148 |
Assert(isResolved()); |
595 |
109148 |
Trace("datatypes-init") << "DType::mkGroundValue of type " << t << std::endl; |
596 |
109148 |
Node v = mkGroundTermInternal(t, true); |
597 |
109148 |
return v; |
598 |
|
} |
599 |
|
|
600 |
214677 |
Node DType::mkGroundTermInternal(TypeNode t, bool isValue) const |
601 |
|
{ |
602 |
429354 |
Trace("datatypes-init") << "DType::mkGroundTerm of type " << t |
603 |
214677 |
<< ", isValue = " << isValue << std::endl; |
604 |
|
// is this already in the cache ? |
605 |
214677 |
std::map<TypeNode, Node>& cache = isValue ? d_groundValue : d_groundTerm; |
606 |
214677 |
std::map<TypeNode, Node>::iterator it = cache.find(t); |
607 |
214677 |
if (it != cache.end()) |
608 |
|
{ |
609 |
427128 |
Trace("datatypes-init") |
610 |
213564 |
<< "\nin cache: " << d_self << " => " << it->second << std::endl; |
611 |
213564 |
return it->second; |
612 |
|
} |
613 |
2226 |
std::vector<TypeNode> processing; |
614 |
2226 |
Node groundTerm = computeGroundTerm(t, processing, isValue); |
615 |
1113 |
if (!groundTerm.isNull()) |
616 |
|
{ |
617 |
|
// we found a ground-term-constructing constructor! |
618 |
1103 |
cache[t] = groundTerm; |
619 |
2206 |
Trace("datatypes-init") |
620 |
1103 |
<< "constructed: " << getName() << " => " << groundTerm << std::endl; |
621 |
|
} |
622 |
|
// if ground term is null, we are not well-founded |
623 |
2226 |
Trace("datatypes-init") << "DType::mkGroundTerm for " << t |
624 |
1113 |
<< ", isValue=" << isValue << " returns " |
625 |
1113 |
<< groundTerm << std::endl; |
626 |
1113 |
return groundTerm; |
627 |
|
} |
628 |
|
|
629 |
9710 |
void DType::getAlienSubfieldTypes(std::unordered_set<TypeNode>& types, |
630 |
|
std::map<TypeNode, bool>& processed, |
631 |
|
bool isAlienPos) const |
632 |
|
{ |
633 |
9710 |
std::map<TypeNode, bool>::iterator it = processed.find(d_self); |
634 |
9710 |
if (it != processed.end()) |
635 |
|
{ |
636 |
7367 |
if (it->second || (!isAlienPos && !it->second)) |
637 |
|
{ |
638 |
|
// already processed as an alien subfield type, or already processed |
639 |
|
// as a non-alien subfield type and isAlienPos is false. |
640 |
7349 |
return; |
641 |
|
} |
642 |
|
} |
643 |
2361 |
processed[d_self] = isAlienPos; |
644 |
11376 |
for (std::shared_ptr<DTypeConstructor> ctor : d_constructors) |
645 |
|
{ |
646 |
18660 |
for (unsigned j = 0, nargs = ctor->getNumArgs(); j < nargs; ++j) |
647 |
|
{ |
648 |
19255 |
TypeNode tn = ctor->getArgType(j); |
649 |
9645 |
if (tn.isDatatype()) |
650 |
|
{ |
651 |
|
// special case for datatypes, we must recurse to collect subfield types |
652 |
8272 |
if (!isAlienPos) |
653 |
|
{ |
654 |
|
// since we aren't adding it to types below, we add its alien |
655 |
|
// subfield types here. |
656 |
8242 |
const DType& dt = tn.getDType(); |
657 |
8242 |
dt.getAlienSubfieldTypes(types, processed, false); |
658 |
|
} |
659 |
8272 |
if (tn.isParametricDatatype() && !isAlienPos) |
660 |
|
{ |
661 |
|
// (instantiated) parametric datatypes have an AST structure: |
662 |
|
// (PARAMETRIC_DATATYPE D T1 ... Tn) |
663 |
|
// where D is the uninstantiated datatype type. We should not view D |
664 |
|
// as an alien subfield type of tn. Thus, we need a special case here |
665 |
|
// which ignores the first child, when isAlienPos is false. |
666 |
72 |
for (unsigned i = 1, nchild = tn.getNumChildren(); i < nchild; i++) |
667 |
|
{ |
668 |
37 |
expr::getComponentTypes(tn[i], types); |
669 |
|
} |
670 |
35 |
continue; |
671 |
|
} |
672 |
|
} |
673 |
|
// we are in a case where tn is not a datatype, we add all (alien) |
674 |
|
// component types to types below. |
675 |
9610 |
bool hasTn = types.find(tn) != types.end(); |
676 |
19220 |
Trace("datatypes-init") |
677 |
9610 |
<< "Collect subfield types " << tn << ", hasTn=" << hasTn |
678 |
9610 |
<< ", isAlienPos=" << isAlienPos << std::endl; |
679 |
9610 |
expr::getComponentTypes(tn, types); |
680 |
9610 |
if (!isAlienPos && !hasTn) |
681 |
|
{ |
682 |
|
// the top-level type is added by getComponentTypes, so remove it if it |
683 |
|
// was not already listed in types |
684 |
9537 |
Assert(types.find(tn) != types.end()); |
685 |
9537 |
types.erase(tn); |
686 |
|
} |
687 |
|
} |
688 |
|
} |
689 |
|
// Now, go back and add all alien subfield types from datatypes if |
690 |
|
// not done so already. This is because getComponentTypes does not |
691 |
|
// recurse into subfield types of datatypes. |
692 |
2630 |
for (const TypeNode& sstn : types) |
693 |
|
{ |
694 |
269 |
if (sstn.isDatatype()) |
695 |
|
{ |
696 |
162 |
const DType& dt = sstn.getDType(); |
697 |
162 |
dt.getAlienSubfieldTypes(types, processed, true); |
698 |
|
} |
699 |
|
} |
700 |
|
} |
701 |
|
|
702 |
24664 |
bool DType::hasNestedRecursion() const |
703 |
|
{ |
704 |
24664 |
if (d_nestedRecursion != 0) |
705 |
|
{ |
706 |
23358 |
return d_nestedRecursion == 1; |
707 |
|
} |
708 |
2612 |
Trace("datatypes-init") << "Compute simply recursive for " << getName() |
709 |
1306 |
<< std::endl; |
710 |
|
// get the alien subfield types of this datatype |
711 |
2612 |
std::unordered_set<TypeNode> types; |
712 |
2612 |
std::map<TypeNode, bool> processed; |
713 |
1306 |
getAlienSubfieldTypes(types, processed, false); |
714 |
1306 |
if (Trace.isOn("datatypes-init")) |
715 |
|
{ |
716 |
|
Trace("datatypes-init") << "Alien subfield types: " << std::endl; |
717 |
|
for (const TypeNode& t : types) |
718 |
|
{ |
719 |
|
Trace("datatypes-init") << "- " << t << std::endl; |
720 |
|
} |
721 |
|
} |
722 |
|
// does types contain self? |
723 |
1306 |
if (types.find(d_self) != types.end()) |
724 |
|
{ |
725 |
26 |
Trace("datatypes-init") |
726 |
26 |
<< "DType::hasNestedRecursion: true for " << getName() |
727 |
13 |
<< " due to alien subfield type" << std::endl; |
728 |
|
// has nested recursion since it has itself as an alien subfield type. |
729 |
13 |
d_nestedRecursion = 1; |
730 |
13 |
return true; |
731 |
|
} |
732 |
|
// If it is parametric, this type may match with an alien subfield type (e.g. |
733 |
|
// we may have a field (T Int) for parametric datatype (T x) where x |
734 |
|
// is a type parameter). Thus, we check whether the self type matches any |
735 |
|
// alien subfield type using the TypeMatcher utility. |
736 |
1293 |
if (isParametric()) |
737 |
|
{ |
738 |
52 |
for (const TypeNode& t : types) |
739 |
|
{ |
740 |
54 |
TypeMatcher m(d_self); |
741 |
27 |
Trace("datatypes-init") << " " << t << std::endl; |
742 |
27 |
if (m.doMatching(d_self, t)) |
743 |
|
{ |
744 |
|
Trace("datatypes-init") |
745 |
|
<< "DType::hasNestedRecursion: true for " << getName() |
746 |
|
<< " due to parametric strict component type, " << d_self |
747 |
|
<< " matching " << t << std::endl; |
748 |
|
d_nestedRecursion = 1; |
749 |
|
return true; |
750 |
|
} |
751 |
|
} |
752 |
|
} |
753 |
2586 |
Trace("datatypes-init") << "DType::hasNestedRecursion: false for " |
754 |
1293 |
<< getName() << std::endl; |
755 |
1293 |
d_nestedRecursion = -1; |
756 |
1293 |
return false; |
757 |
|
} |
758 |
|
|
759 |
2553 |
Node getSubtermWithType(Node e, TypeNode t, bool isTop) |
760 |
|
{ |
761 |
2553 |
if (!isTop && e.getType() == t) |
762 |
|
{ |
763 |
2 |
return e; |
764 |
|
} |
765 |
3535 |
for (const Node& ei : e) |
766 |
|
{ |
767 |
1971 |
Node se = getSubtermWithType(ei, t, false); |
768 |
987 |
if (!se.isNull()) |
769 |
|
{ |
770 |
3 |
return se; |
771 |
|
} |
772 |
|
} |
773 |
2548 |
return Node(); |
774 |
|
} |
775 |
|
|
776 |
1652 |
Node DType::computeGroundTerm(TypeNode t, |
777 |
|
std::vector<TypeNode>& processing, |
778 |
|
bool isValue) const |
779 |
|
{ |
780 |
1652 |
if (std::find(processing.begin(), processing.end(), t) != processing.end()) |
781 |
|
{ |
782 |
148 |
Trace("datatypes-init") |
783 |
74 |
<< "...already processing " << t << " " << d_self << std::endl; |
784 |
74 |
return Node(); |
785 |
|
} |
786 |
1578 |
processing.push_back(t); |
787 |
1578 |
std::map<TypeNode, Node>& gtCache = isValue ? d_groundValue : d_groundTerm; |
788 |
1946 |
for (unsigned r = 0; r < 2; r++) |
789 |
|
{ |
790 |
2010 |
for (std::shared_ptr<DTypeConstructor> ctor : d_constructors) |
791 |
|
{ |
792 |
|
// do nullary constructors first |
793 |
2693 |
if ((ctor->getNumArgs() == 0) != (r == 0)) |
794 |
|
{ |
795 |
1051 |
continue; |
796 |
|
} |
797 |
3284 |
Trace("datatypes-init") << "Try constructing for " << ctor->getName() |
798 |
3284 |
<< ", processing = " << processing.size() |
799 |
1642 |
<< ", isValue=" << isValue << std::endl; |
800 |
1718 |
Node e = ctor->computeGroundTerm(t, processing, gtCache, isValue); |
801 |
1642 |
if (!e.isNull()) |
802 |
|
{ |
803 |
|
// must check subterms for the same type to avoid infinite loops in |
804 |
|
// type enumeration |
805 |
3132 |
Node se = getSubtermWithType(e, t, true); |
806 |
1566 |
if (!se.isNull()) |
807 |
|
{ |
808 |
2 |
Trace("datatypes-init") << "Take subterm " << se << std::endl; |
809 |
2 |
e = se; |
810 |
|
} |
811 |
1566 |
processing.pop_back(); |
812 |
1566 |
return e; |
813 |
|
} |
814 |
|
else |
815 |
|
{ |
816 |
76 |
Trace("datatypes-init") << "...failed." << std::endl; |
817 |
|
} |
818 |
|
} |
819 |
|
} |
820 |
12 |
processing.pop_back(); |
821 |
12 |
return Node(); |
822 |
|
} |
823 |
|
|
824 |
269915 |
TypeNode DType::getTypeNode() const |
825 |
|
{ |
826 |
269915 |
Assert(isResolved()); |
827 |
269915 |
Assert(!d_self.isNull()); |
828 |
269915 |
return d_self; |
829 |
|
} |
830 |
|
|
831 |
8 |
TypeNode DType::getTypeNode(const std::vector<TypeNode>& params) const |
832 |
|
{ |
833 |
8 |
Assert(isResolved()); |
834 |
8 |
Assert(!d_self.isNull() && d_self.isParametricDatatype()); |
835 |
8 |
return d_self.instantiateParametricDatatype(params); |
836 |
|
} |
837 |
|
|
838 |
5134589 |
const DTypeConstructor& DType::operator[](size_t index) const |
839 |
|
{ |
840 |
5134589 |
Assert(index < getNumConstructors()); |
841 |
5134589 |
return *d_constructors[index]; |
842 |
|
} |
843 |
|
|
844 |
1319 |
Node DType::getSharedSelector(TypeNode dtt, TypeNode t, size_t index) const |
845 |
|
{ |
846 |
1319 |
Assert(isResolved()); |
847 |
|
std::map<TypeNode, std::map<TypeNode, std::map<unsigned, Node> > >::iterator |
848 |
1319 |
itd = d_sharedSel.find(dtt); |
849 |
1319 |
if (itd != d_sharedSel.end()) |
850 |
|
{ |
851 |
|
std::map<TypeNode, std::map<unsigned, Node> >::iterator its = |
852 |
1045 |
itd->second.find(t); |
853 |
1045 |
if (its != itd->second.end()) |
854 |
|
{ |
855 |
845 |
std::map<unsigned, Node>::iterator it = its->second.find(index); |
856 |
845 |
if (it != its->second.end()) |
857 |
|
{ |
858 |
600 |
return it->second; |
859 |
|
} |
860 |
|
} |
861 |
|
} |
862 |
|
// make the shared selector |
863 |
1438 |
Node s; |
864 |
719 |
NodeManager* nm = NodeManager::currentNM(); |
865 |
1438 |
std::stringstream ss; |
866 |
719 |
ss << "sel_" << index; |
867 |
719 |
SkolemManager* sm = nm->getSkolemManager(); |
868 |
1438 |
TypeNode stype = nm->mkSelectorType(dtt, t); |
869 |
1438 |
Node nindex = nm->mkConst(Rational(index)); |
870 |
719 |
s = sm->mkSkolemFunction(SkolemFunId::SHARED_SELECTOR, |
871 |
|
stype, |
872 |
|
nindex, |
873 |
|
NodeManager::SKOLEM_NO_NOTIFY); |
874 |
719 |
d_sharedSel[dtt][t][index] = s; |
875 |
1438 |
Trace("dt-shared-sel") << "Made " << s << " of type " << dtt << " -> " << t |
876 |
719 |
<< std::endl; |
877 |
719 |
return s; |
878 |
|
} |
879 |
|
|
880 |
622499 |
TypeNode DType::getSygusType() const { return d_sygusType; } |
881 |
|
|
882 |
104830 |
Node DType::getSygusVarList() const { return d_sygusBvl; } |
883 |
|
|
884 |
1292 |
bool DType::getSygusAllowConst() const { return d_sygusAllowConst; } |
885 |
|
|
886 |
1232 |
bool DType::getSygusAllowAll() const { return d_sygusAllowAll; } |
887 |
|
|
888 |
|
bool DType::involvesExternalType() const { return d_involvesExt; } |
889 |
|
|
890 |
2807 |
bool DType::involvesUninterpretedType() const { return d_involvesUt; } |
891 |
|
|
892 |
484 |
const std::vector<std::shared_ptr<DTypeConstructor> >& DType::getConstructors() |
893 |
|
const |
894 |
|
{ |
895 |
484 |
return d_constructors; |
896 |
|
} |
897 |
|
|
898 |
|
std::unordered_set<TypeNode> DType::getSubfieldTypes() const |
899 |
|
{ |
900 |
|
std::unordered_set<TypeNode> subFieldTypes; |
901 |
|
for (std::shared_ptr<DTypeConstructor> ctor : d_constructors) |
902 |
|
{ |
903 |
|
for (size_t i = 0, nargs = ctor->getNumArgs(); i < nargs; i++) |
904 |
|
{ |
905 |
|
subFieldTypes.insert(ctor->getArgType(i)); |
906 |
|
} |
907 |
|
} |
908 |
|
return subFieldTypes; |
909 |
|
} |
910 |
|
|
911 |
20 |
std::ostream& operator<<(std::ostream& os, const DType& dt) |
912 |
|
{ |
913 |
20 |
dt.toStream(os); |
914 |
20 |
return os; |
915 |
|
} |
916 |
|
|
917 |
20 |
void DType::toStream(std::ostream& out) const |
918 |
|
{ |
919 |
20 |
out << "DATATYPE " << getName(); |
920 |
20 |
if (isParametric()) |
921 |
|
{ |
922 |
|
out << '['; |
923 |
|
for (size_t i = 0, nparams = getNumParameters(); i < nparams; ++i) |
924 |
|
{ |
925 |
|
if (i > 0) |
926 |
|
{ |
927 |
|
out << ','; |
928 |
|
} |
929 |
|
out << getParameter(i); |
930 |
|
} |
931 |
|
out << ']'; |
932 |
|
} |
933 |
20 |
out << " = " << std::endl; |
934 |
20 |
bool firstTime = true; |
935 |
58 |
for (std::shared_ptr<DTypeConstructor> ctor : d_constructors) |
936 |
|
{ |
937 |
38 |
if (!firstTime) |
938 |
|
{ |
939 |
20 |
out << " | "; |
940 |
|
} |
941 |
38 |
firstTime = false; |
942 |
38 |
out << *ctor; |
943 |
|
} |
944 |
20 |
out << " END;" << std::endl; |
945 |
20 |
} |
946 |
|
|
947 |
|
DTypeIndexConstant::DTypeIndexConstant(size_t index) : d_index(index) {} |
948 |
|
std::ostream& operator<<(std::ostream& out, const DTypeIndexConstant& dic) |
949 |
|
{ |
950 |
|
return out << "index_" << dic.getIndex(); |
951 |
|
} |
952 |
|
|
953 |
22755 |
} // namespace cvc5 |