1 |
|
/****************************************************************************** |
2 |
|
* Top contributors (to current version): |
3 |
|
* Andrew Reynolds, Mathias Preiner, Aina Niemetz |
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 |
|
* Implementation of sygus_enumerator. |
14 |
|
*/ |
15 |
|
|
16 |
|
#include "theory/quantifiers/sygus/sygus_enumerator.h" |
17 |
|
|
18 |
|
#include "expr/dtype_cons.h" |
19 |
|
#include "expr/node_algorithm.h" |
20 |
|
#include "options/datatypes_options.h" |
21 |
|
#include "options/quantifiers_options.h" |
22 |
|
#include "smt/logic_exception.h" |
23 |
|
#include "theory/datatypes/sygus_datatype_utils.h" |
24 |
|
#include "theory/datatypes/theory_datatypes_utils.h" |
25 |
|
#include "theory/quantifiers/sygus/synth_engine.h" |
26 |
|
#include "theory/quantifiers/sygus/type_node_id_trie.h" |
27 |
|
#include "theory/rewriter.h" |
28 |
|
|
29 |
|
using namespace cvc5::kind; |
30 |
|
|
31 |
|
namespace cvc5 { |
32 |
|
namespace theory { |
33 |
|
namespace quantifiers { |
34 |
|
|
35 |
166 |
SygusEnumerator::SygusEnumerator(TermDbSygus* tds, |
36 |
|
SygusEnumeratorCallback* sec, |
37 |
|
SygusStatistics* s, |
38 |
|
bool enumShapes, |
39 |
166 |
bool enumAnyConstHoles) |
40 |
|
: d_tds(tds), |
41 |
|
d_sec(sec), |
42 |
|
d_stats(s), |
43 |
|
d_enumShapes(enumShapes), |
44 |
|
d_enumAnyConstHoles(enumAnyConstHoles), |
45 |
|
d_tlEnum(nullptr), |
46 |
166 |
d_abortSize(-1) |
47 |
|
{ |
48 |
166 |
} |
49 |
|
|
50 |
166 |
void SygusEnumerator::initialize(Node e) |
51 |
|
{ |
52 |
166 |
Trace("sygus-enum") << "SygusEnumerator::initialize " << e << std::endl; |
53 |
166 |
d_enum = e; |
54 |
|
// allocate the default callback |
55 |
166 |
if (d_sec == nullptr && options::sygusSymBreakDynamic()) |
56 |
|
{ |
57 |
53 |
d_secd.reset(new SygusEnumeratorCallbackDefault(e, d_stats)); |
58 |
53 |
d_sec = d_secd.get(); |
59 |
|
} |
60 |
166 |
d_etype = d_enum.getType(); |
61 |
166 |
Assert(d_etype.isDatatype()); |
62 |
166 |
Assert(d_etype.getDType().isSygus()); |
63 |
166 |
d_tlEnum = getMasterEnumForType(d_etype); |
64 |
166 |
d_abortSize = options::sygusAbortSize(); |
65 |
|
|
66 |
|
// if we don't have a term database, we don't register symmetry breaking |
67 |
|
// lemmas |
68 |
166 |
if (d_tds == nullptr) |
69 |
|
{ |
70 |
|
return; |
71 |
|
} |
72 |
|
// Get the statically registered symmetry breaking clauses for e, see if they |
73 |
|
// can be used for speeding up the enumeration. |
74 |
166 |
NodeManager* nm = NodeManager::currentNM(); |
75 |
332 |
std::vector<Node> sbl; |
76 |
166 |
d_tds->getSymBreakLemmas(e, sbl); |
77 |
332 |
Node ag = d_tds->getActiveGuardForEnumerator(e); |
78 |
332 |
Node truen = nm->mkConst(true); |
79 |
|
// use TNode for substitute below |
80 |
332 |
TNode agt = ag; |
81 |
332 |
TNode truent = truen; |
82 |
166 |
Assert(d_tcache.find(d_etype) != d_tcache.end()); |
83 |
166 |
const DType& dt = d_etype.getDType(); |
84 |
236 |
for (const Node& lem : sbl) |
85 |
|
{ |
86 |
70 |
if (!d_tds->isSymBreakLemmaTemplate(lem)) |
87 |
|
{ |
88 |
|
// substitute its active guard by true and rewrite |
89 |
72 |
Node slem = lem.substitute(agt, truent); |
90 |
36 |
slem = Rewriter::rewrite(slem); |
91 |
|
// break into conjuncts |
92 |
72 |
std::vector<Node> sblc; |
93 |
36 |
if (slem.getKind() == AND) |
94 |
|
{ |
95 |
9 |
for (const Node& slemc : slem) |
96 |
|
{ |
97 |
6 |
sblc.push_back(slemc); |
98 |
|
} |
99 |
|
} |
100 |
|
else |
101 |
|
{ |
102 |
33 |
sblc.push_back(slem); |
103 |
|
} |
104 |
75 |
for (const Node& sblemma : sblc) |
105 |
|
{ |
106 |
78 |
Trace("sygus-enum") |
107 |
39 |
<< " symmetry breaking lemma : " << sblemma << std::endl; |
108 |
|
// if its a negation of a unit top-level tester, then this specifies |
109 |
|
// that we should not enumerate terms whose top symbol is that |
110 |
|
// constructor |
111 |
39 |
if (sblemma.getKind() == NOT) |
112 |
|
{ |
113 |
74 |
Node a; |
114 |
37 |
int tst = datatypes::utils::isTester(sblemma[0], a); |
115 |
37 |
if (tst >= 0) |
116 |
|
{ |
117 |
37 |
if (a == e) |
118 |
|
{ |
119 |
74 |
Node cons = dt[tst].getConstructor(); |
120 |
74 |
Trace("sygus-enum") << " ...unit exclude constructor #" << tst |
121 |
37 |
<< ", constructor " << cons << std::endl; |
122 |
37 |
d_sbExcTlCons.insert(cons); |
123 |
|
} |
124 |
|
} |
125 |
|
} |
126 |
|
// other symmetry breaking lemmas such as disjunctions are not used |
127 |
|
} |
128 |
|
} |
129 |
|
} |
130 |
|
} |
131 |
|
|
132 |
113 |
void SygusEnumerator::addValue(Node v) |
133 |
|
{ |
134 |
|
// do nothing |
135 |
113 |
} |
136 |
|
|
137 |
46363 |
bool SygusEnumerator::increment() { return d_tlEnum->increment(); } |
138 |
45816 |
Node SygusEnumerator::getCurrent() |
139 |
|
{ |
140 |
45816 |
if (d_abortSize >= 0) |
141 |
|
{ |
142 |
4237 |
int cs = static_cast<int>(d_tlEnum->getCurrentSize()); |
143 |
4237 |
if (cs > d_abortSize) |
144 |
|
{ |
145 |
18 |
std::stringstream ss; |
146 |
9 |
ss << "Maximum term size (" << options::sygusAbortSize() |
147 |
9 |
<< ") for enumerative SyGuS exceeded."; |
148 |
9 |
throw LogicException(ss.str()); |
149 |
|
} |
150 |
|
} |
151 |
45807 |
Node ret = d_tlEnum->getCurrent(); |
152 |
45807 |
if (!ret.isNull() && !d_sbExcTlCons.empty()) |
153 |
|
{ |
154 |
433 |
Assert(ret.hasOperator()); |
155 |
|
// might be excluded by an externally provided symmetry breaking clause |
156 |
433 |
if (d_sbExcTlCons.find(ret.getOperator()) != d_sbExcTlCons.end()) |
157 |
|
{ |
158 |
48 |
Trace("sygus-enum-exc") |
159 |
48 |
<< "Exclude (external) : " << datatypes::utils::sygusToBuiltin(ret) |
160 |
24 |
<< std::endl; |
161 |
24 |
ret = Node::null(); |
162 |
|
} |
163 |
|
} |
164 |
45807 |
if (Trace.isOn("sygus-enum")) |
165 |
|
{ |
166 |
|
Trace("sygus-enum") << "Enumerate : "; |
167 |
|
TermDbSygus::toStreamSygus("sygus-enum", ret); |
168 |
|
Trace("sygus-enum") << std::endl; |
169 |
|
} |
170 |
45807 |
return ret; |
171 |
|
} |
172 |
|
|
173 |
294 |
bool SygusEnumerator::isEnumShapes() const { return d_enumShapes; } |
174 |
|
|
175 |
310 |
SygusEnumerator::TermCache::TermCache() |
176 |
|
: d_sec(nullptr), |
177 |
|
d_isSygusType(false), |
178 |
|
d_numConClasses(0), |
179 |
|
d_sizeEnum(0), |
180 |
310 |
d_isComplete(false) |
181 |
|
{ |
182 |
310 |
} |
183 |
|
|
184 |
310 |
void SygusEnumerator::TermCache::initialize(SygusStatistics* s, |
185 |
|
Node e, |
186 |
|
TypeNode tn, |
187 |
|
SygusEnumeratorCallback* sec) |
188 |
|
{ |
189 |
310 |
Trace("sygus-enum-debug") << "Init term cache " << tn << "..." << std::endl; |
190 |
310 |
d_stats = s; |
191 |
310 |
d_enum = e; |
192 |
310 |
d_tn = tn; |
193 |
310 |
d_sec = sec; |
194 |
310 |
d_sizeStartIndex[0] = 0; |
195 |
310 |
d_isSygusType = false; |
196 |
|
|
197 |
|
// compute static information about tn |
198 |
310 |
if (!d_tn.isDatatype()) |
199 |
|
{ |
200 |
|
// not a datatype, finish |
201 |
32 |
return; |
202 |
|
} |
203 |
294 |
const DType& dt = tn.getDType(); |
204 |
294 |
if (!dt.isSygus()) |
205 |
|
{ |
206 |
|
// not a sygus datatype, finish |
207 |
|
return; |
208 |
|
} |
209 |
|
|
210 |
294 |
d_isSygusType = true; |
211 |
|
|
212 |
|
// get argument types for all constructors |
213 |
588 |
std::map<unsigned, std::vector<TypeNode>> argTypes; |
214 |
|
// map weights to constructors |
215 |
588 |
std::map<unsigned, std::vector<unsigned>> weightsToIndices; |
216 |
|
|
217 |
|
// constructor class 0 is reserved for nullary operators with 0 weight |
218 |
|
// this is an optimization so that we always skip them for sizes >= 1 |
219 |
294 |
ConstructorClass& ccZero = d_cclass[0]; |
220 |
294 |
ccZero.d_weight = 0; |
221 |
294 |
d_numConClasses = 1; |
222 |
|
// we must indicate that we should process zero weight constructor classes |
223 |
294 |
weightsToIndices[0].clear(); |
224 |
1797 |
for (unsigned i = 0, ncons = dt.getNumConstructors(); i < ncons; i++) |
225 |
|
{ |
226 |
|
// record weight information |
227 |
1503 |
unsigned w = dt[i].getWeight(); |
228 |
3006 |
Trace("sygus-enum-debug") << "Weight " << dt[i].getSygusOp() << ": " << w |
229 |
1503 |
<< std::endl; |
230 |
1503 |
weightsToIndices[w].push_back(i); |
231 |
|
// record type information |
232 |
3107 |
for (unsigned j = 0, nargs = dt[i].getNumArgs(); j < nargs; j++) |
233 |
|
{ |
234 |
3208 |
TypeNode type = dt[i].getArgType(j); |
235 |
1604 |
argTypes[i].push_back(type); |
236 |
|
} |
237 |
|
} |
238 |
294 |
NodeManager* nm = NodeManager::currentNM(); |
239 |
818 |
for (std::pair<const unsigned, std::vector<unsigned>>& wp : weightsToIndices) |
240 |
|
{ |
241 |
524 |
unsigned w = wp.first; |
242 |
|
|
243 |
|
// assign constructors to constructor classes |
244 |
1048 |
TypeNodeIdTrie tnit; |
245 |
1048 |
std::map<Node, unsigned> nToC; |
246 |
2027 |
for (unsigned i : wp.second) |
247 |
|
{ |
248 |
1503 |
if (argTypes[i].empty() && w == 0) |
249 |
|
{ |
250 |
628 |
ccZero.d_cons.push_back(i); |
251 |
|
} |
252 |
|
else |
253 |
|
{ |
254 |
|
// we merge those whose argument types are the same |
255 |
|
// We could, but choose not to, order these types, which would lead to |
256 |
|
// more aggressive merging of constructor classes. On the negative side, |
257 |
|
// this adds another level of indirection to remember which argument |
258 |
|
// positions the argument types occur in, for each constructor. |
259 |
1750 |
Node n = nm->mkConst(Rational(i)); |
260 |
875 |
nToC[n] = i; |
261 |
875 |
tnit.add(n, argTypes[i]); |
262 |
|
} |
263 |
|
} |
264 |
1048 |
std::map<Node, unsigned> assign; |
265 |
524 |
tnit.assignIds(assign, d_numConClasses); |
266 |
1399 |
for (std::pair<const Node, unsigned>& cp : assign) |
267 |
|
{ |
268 |
|
// determine which constructor class this goes into using tnit |
269 |
875 |
unsigned cclassi = cp.second; |
270 |
875 |
unsigned i = nToC[cp.first]; |
271 |
1750 |
Trace("sygus-enum-debug") << "Constructor class for " |
272 |
1750 |
<< dt[i].getSygusOp() << " is " << cclassi |
273 |
875 |
<< std::endl; |
274 |
|
// initialize the constructor class |
275 |
875 |
if (d_cclass.find(cclassi) == d_cclass.end()) |
276 |
|
{ |
277 |
512 |
d_cclass[cclassi].d_weight = w; |
278 |
2048 |
d_cclass[cclassi].d_types.insert(d_cclass[cclassi].d_types.end(), |
279 |
512 |
argTypes[i].begin(), |
280 |
2048 |
argTypes[i].end()); |
281 |
|
} |
282 |
|
// add to constructor class |
283 |
875 |
d_cclass[cclassi].d_cons.push_back(i); |
284 |
|
} |
285 |
1048 |
Trace("sygus-enum-debug") << "#cons classes for weight <= " << w << " : " |
286 |
524 |
<< d_numConClasses << std::endl; |
287 |
524 |
d_weightToCcIndex[w] = d_numConClasses; |
288 |
|
} |
289 |
294 |
Trace("sygus-enum-debug") << "...finish" << std::endl; |
290 |
|
} |
291 |
|
|
292 |
56253 |
unsigned SygusEnumerator::TermCache::getLastConstructorClassIndexForWeight( |
293 |
|
unsigned w) const |
294 |
|
{ |
295 |
56253 |
std::map<unsigned, unsigned>::const_iterator it = d_weightToCcIndex.find(w); |
296 |
56253 |
if (it == d_weightToCcIndex.end()) |
297 |
|
{ |
298 |
47545 |
return d_numConClasses; |
299 |
|
} |
300 |
8708 |
return it->second; |
301 |
|
} |
302 |
92 |
unsigned SygusEnumerator::TermCache::getNumConstructorClasses() const |
303 |
|
{ |
304 |
92 |
return d_numConClasses; |
305 |
|
} |
306 |
868 |
void SygusEnumerator::TermCache::getConstructorClass( |
307 |
|
unsigned i, std::vector<unsigned>& cclass) const |
308 |
|
{ |
309 |
868 |
std::map<unsigned, ConstructorClass>::const_iterator it = d_cclass.find(i); |
310 |
868 |
Assert(it != d_cclass.end()); |
311 |
868 |
cclass.insert( |
312 |
1736 |
cclass.end(), it->second.d_cons.begin(), it->second.d_cons.end()); |
313 |
868 |
} |
314 |
831 |
void SygusEnumerator::TermCache::getTypesForConstructorClass( |
315 |
|
unsigned i, std::vector<TypeNode>& types) const |
316 |
|
{ |
317 |
831 |
std::map<unsigned, ConstructorClass>::const_iterator it = d_cclass.find(i); |
318 |
831 |
Assert(it != d_cclass.end()); |
319 |
831 |
types.insert( |
320 |
1662 |
types.end(), it->second.d_types.begin(), it->second.d_types.end()); |
321 |
831 |
} |
322 |
|
|
323 |
831 |
unsigned SygusEnumerator::TermCache::getWeightForConstructorClass( |
324 |
|
unsigned i) const |
325 |
|
{ |
326 |
831 |
std::map<unsigned, ConstructorClass>::const_iterator it = d_cclass.find(i); |
327 |
831 |
Assert(it != d_cclass.end()); |
328 |
831 |
return it->second.d_weight; |
329 |
|
} |
330 |
|
|
331 |
55392 |
bool SygusEnumerator::TermCache::addTerm(Node n) |
332 |
|
{ |
333 |
55392 |
if (!d_isSygusType) |
334 |
|
{ |
335 |
|
// non-sygus terms generated by TermEnumMasterInterp/TermEnumMasterFv |
336 |
|
// enumeration are unique by construction |
337 |
222 |
Trace("sygus-enum-terms") << "tc(" << d_tn << "): term (builtin): " << n |
338 |
111 |
<< std::endl; |
339 |
111 |
d_terms.push_back(n); |
340 |
111 |
return true; |
341 |
|
} |
342 |
55281 |
Assert(!n.isNull()); |
343 |
55281 |
if (d_sec != nullptr) |
344 |
|
{ |
345 |
55281 |
if (!d_sec->addTerm(n, d_bterms)) |
346 |
|
{ |
347 |
62868 |
Trace("sygus-enum-exc") |
348 |
62868 |
<< "Exclude: " << datatypes::utils::sygusToBuiltin(n) |
349 |
31434 |
<< " due to callback" << std::endl; |
350 |
31434 |
return false; |
351 |
|
} |
352 |
|
} |
353 |
23847 |
if (d_stats != nullptr) |
354 |
|
{ |
355 |
23847 |
++(d_stats->d_enumTerms); |
356 |
|
} |
357 |
23847 |
d_terms.push_back(n); |
358 |
23847 |
return true; |
359 |
|
} |
360 |
424 |
void SygusEnumerator::TermCache::pushEnumSizeIndex() |
361 |
|
{ |
362 |
424 |
d_sizeEnum++; |
363 |
424 |
d_sizeStartIndex[d_sizeEnum] = d_terms.size(); |
364 |
848 |
Trace("sygus-enum-debug") << "tc(" << d_tn << "): size " << d_sizeEnum |
365 |
848 |
<< " terms start at index " << d_terms.size() |
366 |
424 |
<< std::endl; |
367 |
424 |
} |
368 |
40498 |
unsigned SygusEnumerator::TermCache::getEnumSize() const { return d_sizeEnum; } |
369 |
35086 |
unsigned SygusEnumerator::TermCache::getIndexForSize(unsigned s) const |
370 |
|
{ |
371 |
35086 |
Assert(s <= d_sizeEnum); |
372 |
35086 |
std::map<unsigned, unsigned>::const_iterator it = d_sizeStartIndex.find(s); |
373 |
35086 |
Assert(it != d_sizeStartIndex.end()); |
374 |
35086 |
return it->second; |
375 |
|
} |
376 |
217056 |
Node SygusEnumerator::TermCache::getTerm(unsigned index) const |
377 |
|
{ |
378 |
217056 |
Assert(index < d_terms.size()); |
379 |
217056 |
return d_terms[index]; |
380 |
|
} |
381 |
|
|
382 |
54463 |
unsigned SygusEnumerator::TermCache::getNumTerms() const |
383 |
|
{ |
384 |
54463 |
return d_terms.size(); |
385 |
|
} |
386 |
|
|
387 |
57048 |
bool SygusEnumerator::TermCache::isComplete() const { return d_isComplete; } |
388 |
43 |
void SygusEnumerator::TermCache::setComplete() { d_isComplete = true; } |
389 |
216394 |
unsigned SygusEnumerator::TermEnum::getCurrentSize() { return d_currSize; } |
390 |
3607 |
SygusEnumerator::TermEnum::TermEnum() : d_se(nullptr), d_currSize(0) {} |
391 |
3297 |
SygusEnumerator::TermEnumSlave::TermEnumSlave() |
392 |
|
: TermEnum(), |
393 |
|
d_sizeLim(0), |
394 |
|
d_index(0), |
395 |
|
d_indexNextEnd(0), |
396 |
|
d_hasIndexNextEnd(false), |
397 |
3297 |
d_master(nullptr) |
398 |
|
{ |
399 |
3297 |
} |
400 |
|
|
401 |
3297 |
bool SygusEnumerator::TermEnumSlave::initialize(SygusEnumerator* se, |
402 |
|
TypeNode tn, |
403 |
|
unsigned sizeMin, |
404 |
|
unsigned sizeMax) |
405 |
|
{ |
406 |
3297 |
d_se = se; |
407 |
3297 |
d_tn = tn; |
408 |
3297 |
d_sizeLim = sizeMax; |
409 |
6594 |
Trace("sygus-enum-debug2") << "slave(" << d_tn |
410 |
3297 |
<< "): init, min/max=" << sizeMin << "/" << sizeMax |
411 |
3297 |
<< "...\n"; |
412 |
|
|
413 |
|
// must have pointer to the master |
414 |
3297 |
d_master = d_se->getMasterEnumForType(d_tn); |
415 |
|
|
416 |
3297 |
SygusEnumerator::TermCache& tc = d_se->d_tcache[d_tn]; |
417 |
|
// if the size is exact, we start at the limit |
418 |
3297 |
d_currSize = sizeMin; |
419 |
|
// initialize the index |
420 |
3303 |
while (d_currSize > tc.getEnumSize()) |
421 |
|
{ |
422 |
76 |
Trace("sygus-enum-debug2") << "slave(" << d_tn |
423 |
38 |
<< "): init force increment master...\n"; |
424 |
|
// increment the master until we have enough terms |
425 |
38 |
if (!d_master->increment()) |
426 |
|
{ |
427 |
70 |
Trace("sygus-enum-debug2") << "slave(" << d_tn |
428 |
35 |
<< "): ...fail init force master\n"; |
429 |
35 |
return false; |
430 |
|
} |
431 |
6 |
Trace("sygus-enum-debug2") << "slave(" << d_tn |
432 |
3 |
<< "): ...success init force master\n"; |
433 |
|
} |
434 |
3262 |
d_index = tc.getIndexForSize(d_currSize); |
435 |
3262 |
Trace("sygus-enum-debug2") << "slave(" << d_tn << "): validate indices...\n"; |
436 |
|
// initialize the next end index (marks where size increments) |
437 |
3262 |
validateIndexNextEnd(); |
438 |
6524 |
Trace("sygus-enum-debug2") |
439 |
3262 |
<< "slave(" << d_tn << "): validate init end: " << d_hasIndexNextEnd |
440 |
3262 |
<< " " << d_indexNextEnd << " " << d_index << " " << d_currSize << "\n"; |
441 |
|
// ensure that indexNextEnd is valid (it must be greater than d_index) |
442 |
3262 |
bool ret = validateIndex(); |
443 |
6524 |
Trace("sygus-enum-debug2") |
444 |
6524 |
<< "slave(" << d_tn << "): ..." << (ret ? "success" : "fail") |
445 |
3262 |
<< " init, now: " << d_hasIndexNextEnd << " " << d_indexNextEnd << " " |
446 |
3262 |
<< d_index << " " << d_currSize << "\n"; |
447 |
3262 |
return ret; |
448 |
|
} |
449 |
|
|
450 |
108528 |
Node SygusEnumerator::TermEnumSlave::getCurrent() |
451 |
|
{ |
452 |
108528 |
SygusEnumerator::TermCache& tc = d_se->d_tcache[d_tn]; |
453 |
217056 |
Node curr = tc.getTerm(d_index); |
454 |
217056 |
Trace("sygus-enum-debug2") |
455 |
108528 |
<< "slave(" << d_tn |
456 |
217056 |
<< "): current : " << datatypes::utils::sygusToBuiltin(curr) |
457 |
217056 |
<< ", sizes = " << datatypes::utils::getSygusTermSize(curr) << " " |
458 |
108528 |
<< getCurrentSize() << std::endl; |
459 |
217056 |
Trace("sygus-enum-debug2") << "slave(" << d_tn |
460 |
108528 |
<< "): indices : " << d_hasIndexNextEnd << " " |
461 |
108528 |
<< d_indexNextEnd << " " << d_index << std::endl; |
462 |
|
// lookup in the cache |
463 |
217056 |
return tc.getTerm(d_index); |
464 |
|
} |
465 |
|
|
466 |
30976 |
bool SygusEnumerator::TermEnumSlave::increment() |
467 |
|
{ |
468 |
|
// increment index |
469 |
30976 |
d_index++; |
470 |
|
// ensure that index is valid |
471 |
30976 |
return validateIndex(); |
472 |
|
} |
473 |
|
|
474 |
34238 |
bool SygusEnumerator::TermEnumSlave::validateIndex() |
475 |
|
{ |
476 |
34238 |
Trace("sygus-enum-debug2") << "slave(" << d_tn << ") : validate index...\n"; |
477 |
34238 |
SygusEnumerator::TermCache& tc = d_se->d_tcache[d_tn]; |
478 |
|
// ensure that index is in the range |
479 |
53816 |
while (d_index >= tc.getNumTerms()) |
480 |
|
{ |
481 |
10335 |
Assert(d_index == tc.getNumTerms()); |
482 |
10335 |
Trace("sygus-enum-debug2") << "slave(" << d_tn << ") : force master...\n"; |
483 |
|
// if the size of the master is larger than the size limit, then |
484 |
|
// there is no use continuing, since there are no more terms that this |
485 |
|
// slave enumerator can return. |
486 |
10335 |
if (d_master->getCurrentSize() > d_sizeLim) |
487 |
|
{ |
488 |
444 |
return false; |
489 |
|
} |
490 |
|
// must push the master index |
491 |
9891 |
if (!d_master->increment()) |
492 |
|
{ |
493 |
204 |
Trace("sygus-enum-debug2") << "slave(" << d_tn |
494 |
102 |
<< ") : ...fail force master\n"; |
495 |
102 |
return false; |
496 |
|
} |
497 |
19578 |
Trace("sygus-enum-debug2") << "slave(" << d_tn |
498 |
9789 |
<< ") : ...success force master\n"; |
499 |
|
} |
500 |
|
// always validate the next index end here |
501 |
33692 |
validateIndexNextEnd(); |
502 |
67384 |
Trace("sygus-enum-debug2") << "slave(" << d_tn |
503 |
33692 |
<< ") : validate index end...\n"; |
504 |
|
// if we are at the beginning of the next size, increment current size |
505 |
34142 |
while (d_hasIndexNextEnd && d_index == d_indexNextEnd) |
506 |
|
{ |
507 |
2640 |
d_currSize++; |
508 |
5280 |
Trace("sygus-enum-debug2") << "slave(" << d_tn << ") : size++ (" |
509 |
2640 |
<< d_currSize << "/" << d_sizeLim << ")\n"; |
510 |
|
// if we've hit the size limit, return false |
511 |
2640 |
if (d_currSize > d_sizeLim) |
512 |
|
{ |
513 |
2415 |
Trace("sygus-enum-debug2") << "slave(" << d_tn << ") : fail size\n"; |
514 |
2415 |
return false; |
515 |
|
} |
516 |
225 |
validateIndexNextEnd(); |
517 |
|
} |
518 |
31277 |
Trace("sygus-enum-debug2") << "slave(" << d_tn << ") : finished\n"; |
519 |
31277 |
return true; |
520 |
|
} |
521 |
|
|
522 |
37179 |
void SygusEnumerator::TermEnumSlave::validateIndexNextEnd() |
523 |
|
{ |
524 |
37179 |
SygusEnumerator::TermCache& tc = d_se->d_tcache[d_tn]; |
525 |
|
// update the next end index |
526 |
37179 |
d_hasIndexNextEnd = d_currSize < tc.getEnumSize(); |
527 |
37179 |
if (d_hasIndexNextEnd) |
528 |
|
{ |
529 |
31824 |
d_indexNextEnd = tc.getIndexForSize(d_currSize + 1); |
530 |
|
} |
531 |
37179 |
} |
532 |
|
|
533 |
310 |
void SygusEnumerator::initializeTermCache(TypeNode tn) |
534 |
|
{ |
535 |
|
// initialize the term cache |
536 |
310 |
d_tcache[tn].initialize(d_stats, d_enum, tn, d_sec); |
537 |
310 |
} |
538 |
|
|
539 |
3463 |
SygusEnumerator::TermEnum* SygusEnumerator::getMasterEnumForType(TypeNode tn) |
540 |
|
{ |
541 |
3463 |
if (tn.isDatatype() && tn.getDType().isSygus()) |
542 |
|
{ |
543 |
3436 |
std::map<TypeNode, TermEnumMaster>::iterator it = d_masterEnum.find(tn); |
544 |
3436 |
if (it != d_masterEnum.end()) |
545 |
|
{ |
546 |
3142 |
return &it->second; |
547 |
|
} |
548 |
294 |
initializeTermCache(tn); |
549 |
|
// initialize the master enumerator |
550 |
294 |
bool ret = d_masterEnum[tn].initialize(this, tn); |
551 |
294 |
AlwaysAssert(ret); |
552 |
294 |
return &d_masterEnum[tn]; |
553 |
|
} |
554 |
27 |
if (d_enumAnyConstHoles) |
555 |
|
{ |
556 |
5 |
std::map<TypeNode, TermEnumMasterFv>::iterator it = d_masterEnumFv.find(tn); |
557 |
5 |
if (it != d_masterEnumFv.end()) |
558 |
|
{ |
559 |
|
return &it->second; |
560 |
|
} |
561 |
5 |
initializeTermCache(tn); |
562 |
|
// initialize the master enumerator |
563 |
5 |
bool ret = d_masterEnumFv[tn].initialize(this, tn); |
564 |
5 |
AlwaysAssert(ret); |
565 |
5 |
return &d_masterEnumFv[tn]; |
566 |
|
} |
567 |
|
std::map<TypeNode, std::unique_ptr<TermEnumMasterInterp>>::iterator it = |
568 |
22 |
d_masterEnumInt.find(tn); |
569 |
22 |
if (it != d_masterEnumInt.end()) |
570 |
|
{ |
571 |
11 |
return it->second.get(); |
572 |
|
} |
573 |
11 |
initializeTermCache(tn); |
574 |
|
// create the master enumerator |
575 |
11 |
d_masterEnumInt[tn].reset(new TermEnumMasterInterp(tn)); |
576 |
|
// initialize the master enumerator |
577 |
11 |
TermEnumMasterInterp* temi = d_masterEnumInt[tn].get(); |
578 |
11 |
bool ret = temi->initialize(this, tn); |
579 |
11 |
AlwaysAssert(ret); |
580 |
11 |
return temi; |
581 |
|
} |
582 |
|
|
583 |
294 |
SygusEnumerator::TermEnumMaster::TermEnumMaster() |
584 |
|
: TermEnum(), |
585 |
|
d_enumShapes(false), |
586 |
|
d_enumShapesInit(false), |
587 |
|
d_isIncrementing(false), |
588 |
|
d_currTermSet(false), |
589 |
|
d_consClassNum(0), |
590 |
|
d_ccWeight(0), |
591 |
|
d_consNum(0), |
592 |
|
d_currChildSize(0), |
593 |
294 |
d_childrenValid(0) |
594 |
|
{ |
595 |
294 |
} |
596 |
|
|
597 |
294 |
bool SygusEnumerator::TermEnumMaster::initialize(SygusEnumerator* se, |
598 |
|
TypeNode tn) |
599 |
|
{ |
600 |
294 |
Trace("sygus-enum-debug") << "master(" << tn << "): init...\n"; |
601 |
294 |
d_tds = se->d_tds; |
602 |
294 |
d_se = se; |
603 |
294 |
d_tn = tn; |
604 |
|
|
605 |
294 |
d_currSize = 0; |
606 |
|
// we will start with constructor class zero |
607 |
294 |
d_consClassNum = 0; |
608 |
294 |
d_currChildSize = 0; |
609 |
294 |
d_ccCons.clear(); |
610 |
294 |
d_enumShapes = se->isEnumShapes(); |
611 |
294 |
d_enumShapesInit = false; |
612 |
294 |
d_isIncrementing = false; |
613 |
294 |
d_currTermSet = false; |
614 |
294 |
bool ret = increment(); |
615 |
588 |
Trace("sygus-enum-debug") << "master(" << tn |
616 |
294 |
<< "): finish init, ret = " << ret << "\n"; |
617 |
294 |
return ret; |
618 |
|
} |
619 |
|
|
620 |
101022 |
Node SygusEnumerator::TermEnumMaster::getCurrent() |
621 |
|
{ |
622 |
101022 |
if (d_currTermSet) |
623 |
|
{ |
624 |
45807 |
return d_currTerm; |
625 |
|
} |
626 |
55215 |
d_currTermSet = true; |
627 |
|
// construct based on the children |
628 |
110430 |
std::vector<Node> children; |
629 |
55215 |
const DType& dt = d_tn.getDType(); |
630 |
55215 |
Assert(d_consNum > 0 && d_consNum <= d_ccCons.size()); |
631 |
|
// get the current constructor number |
632 |
55215 |
unsigned cnum = d_ccCons[d_consNum - 1]; |
633 |
55215 |
children.push_back(dt[cnum].getConstructor()); |
634 |
|
// add the current of each child to children |
635 |
163743 |
for (unsigned i = 0, nargs = dt[cnum].getNumArgs(); i < nargs; i++) |
636 |
|
{ |
637 |
108528 |
Assert(d_children.find(i) != d_children.end()); |
638 |
217056 |
Node cc = d_children[i].getCurrent(); |
639 |
108528 |
if (cc.isNull()) |
640 |
|
{ |
641 |
|
d_currTerm = cc; |
642 |
|
return cc; |
643 |
|
} |
644 |
108528 |
children.push_back(cc); |
645 |
|
} |
646 |
55215 |
if (d_enumShapes) |
647 |
|
{ |
648 |
|
// ensure all variables are unique |
649 |
10977 |
childrenToShape(children); |
650 |
|
} |
651 |
55215 |
d_currTerm = NodeManager::currentNM()->mkNode(APPLY_CONSTRUCTOR, children); |
652 |
55215 |
return d_currTerm; |
653 |
|
} |
654 |
|
|
655 |
56479 |
bool SygusEnumerator::TermEnumMaster::increment() |
656 |
|
{ |
657 |
|
// Am I already incrementing? If so, fail. |
658 |
|
// This is to break infinite loops for slave enumerators who request an |
659 |
|
// increment() from the master enumerator of their type that is also their |
660 |
|
// parent. This ensures we do not loop on a grammar like: |
661 |
|
// A -> -( A ) | B+B |
662 |
|
// B -> x | y |
663 |
|
// where we require the first term enumerated to be over B+B. |
664 |
|
// Set that we are incrementing |
665 |
56479 |
if (d_isIncrementing) |
666 |
|
{ |
667 |
|
return false; |
668 |
|
} |
669 |
112958 |
Trace("sygus-enum-summary") << "SygusEnumerator::TermEnumMaster: increment " |
670 |
56479 |
<< d_tn << "..." << std::endl; |
671 |
56479 |
d_isIncrementing = true; |
672 |
56479 |
bool ret = incrementInternal(); |
673 |
56479 |
d_isIncrementing = false; |
674 |
112958 |
Trace("sygus-enum-summary") |
675 |
56479 |
<< "SygusEnumerator::TermEnumMaster: finished increment " << d_tn |
676 |
56479 |
<< std::endl; |
677 |
56479 |
return ret; |
678 |
|
} |
679 |
|
|
680 |
57005 |
bool SygusEnumerator::TermEnumMaster::incrementInternal() |
681 |
|
{ |
682 |
57005 |
SygusEnumerator::TermCache& tc = d_se->d_tcache[d_tn]; |
683 |
57005 |
if (tc.isComplete()) |
684 |
|
{ |
685 |
752 |
return false; |
686 |
|
} |
687 |
112506 |
Trace("sygus-enum-debug2") << "master(" << d_tn |
688 |
56253 |
<< "): get last constructor class..." << std::endl; |
689 |
|
// the maximum index of a constructor class to consider |
690 |
56253 |
unsigned ncc = tc.getLastConstructorClassIndexForWeight(d_currSize); |
691 |
112506 |
Trace("sygus-enum-debug2") << "Last constructor class " << d_currSize << ": " |
692 |
56253 |
<< ncc << std::endl; |
693 |
|
// If we are enumerating shapes, the first enumerated term is a free variable. |
694 |
56253 |
if (d_enumShapes && !d_enumShapesInit) |
695 |
|
{ |
696 |
66 |
Assert(d_tds != nullptr); |
697 |
132 |
Node fv = d_tds->getFreeVar(d_tn, 0); |
698 |
66 |
d_enumShapesInit = true; |
699 |
66 |
d_currTermSet = true; |
700 |
66 |
d_currTerm = fv; |
701 |
|
// must add to term cache |
702 |
66 |
tc.addTerm(fv); |
703 |
66 |
return true; |
704 |
|
} |
705 |
|
|
706 |
|
// have we initialized the current constructor class? |
707 |
57923 |
while (d_ccCons.empty() && d_consClassNum < ncc) |
708 |
|
{ |
709 |
868 |
Assert(d_ccTypes.empty()); |
710 |
1736 |
Trace("sygus-enum-debug2") << "master(" << d_tn |
711 |
868 |
<< "): try constructor class " << d_consClassNum |
712 |
868 |
<< std::endl; |
713 |
|
// get the list of constructors in the constructor class |
714 |
868 |
tc.getConstructorClass(d_consClassNum, d_ccCons); |
715 |
|
// if there are any... |
716 |
868 |
if (!d_ccCons.empty()) |
717 |
|
{ |
718 |
|
// successfully initialized the constructor class |
719 |
796 |
d_consNum = 0; |
720 |
|
// we will populate the children |
721 |
796 |
Assert(d_children.empty()); |
722 |
796 |
Assert(d_ccTypes.empty()); |
723 |
796 |
tc.getTypesForConstructorClass(d_consClassNum, d_ccTypes); |
724 |
796 |
d_ccWeight = tc.getWeightForConstructorClass(d_consClassNum); |
725 |
796 |
d_childrenValid = 0; |
726 |
|
// initialize the children into their initial state |
727 |
796 |
if (!initializeChildren()) |
728 |
|
{ |
729 |
|
// didn't work (due to size), we will try the next class |
730 |
104 |
d_ccCons.clear(); |
731 |
104 |
d_ccTypes.clear(); |
732 |
208 |
Trace("sygus-enum-debug2") << "master(" << d_tn |
733 |
104 |
<< "): failed due to init size\n"; |
734 |
|
} |
735 |
|
} |
736 |
|
else |
737 |
|
{ |
738 |
|
// No constructors in constructor class. This can happen for class 0 if a |
739 |
|
// type has no nullary constructors with weight 0. |
740 |
144 |
Trace("sygus-enum-debug2") << "master(" << d_tn |
741 |
72 |
<< "): failed due to no cons\n"; |
742 |
|
} |
743 |
|
// increment the next constructor class we will try |
744 |
868 |
d_consClassNum++; |
745 |
|
} |
746 |
|
|
747 |
|
// have we run out of constructor classes for this size? |
748 |
56187 |
if (d_ccCons.empty()) |
749 |
|
{ |
750 |
|
// check whether we should terminate, which notice always treats |
751 |
|
// uninterpreted sorts as infinite, since we do not put bounds on them |
752 |
|
// in our enumeration. |
753 |
446 |
if (isCardinalityClassFinite(d_tn.getCardinalityClass(), false)) |
754 |
|
{ |
755 |
92 |
if (ncc == tc.getNumConstructorClasses()) |
756 |
|
{ |
757 |
67 |
bool doTerminate = true; |
758 |
78 |
for (unsigned i = 1; i < ncc; i++) |
759 |
|
{ |
760 |
|
// The maximum size of terms from a constructor class can be |
761 |
|
// determined if all of its argument types are finished enumerating. |
762 |
|
// If this maximum size is less than or equal to d_currSize for |
763 |
|
// each constructor class, we are done. |
764 |
35 |
unsigned sum = tc.getWeightForConstructorClass(i); |
765 |
46 |
std::vector<TypeNode> cctns; |
766 |
35 |
tc.getTypesForConstructorClass(i, cctns); |
767 |
54 |
for (unsigned j = 0, ntypes = cctns.size(); j < ntypes; j++) |
768 |
|
{ |
769 |
62 |
TypeNode tnc = cctns[j]; |
770 |
43 |
SygusEnumerator::TermCache& tcc = d_se->d_tcache[tnc]; |
771 |
43 |
if (!tcc.isComplete()) |
772 |
|
{ |
773 |
|
// maximum size of this constructor class cannot be determined |
774 |
24 |
doTerminate = false; |
775 |
24 |
break; |
776 |
|
} |
777 |
|
else |
778 |
|
{ |
779 |
19 |
sum += tcc.getEnumSize(); |
780 |
19 |
if (sum > d_currSize) |
781 |
|
{ |
782 |
|
// maximum size of this constructor class is greater than size |
783 |
|
doTerminate = false; |
784 |
|
break; |
785 |
|
} |
786 |
|
} |
787 |
|
} |
788 |
35 |
if (!doTerminate) |
789 |
|
{ |
790 |
24 |
break; |
791 |
|
} |
792 |
|
} |
793 |
67 |
if (doTerminate) |
794 |
|
{ |
795 |
86 |
Trace("sygus-engine") << "master(" << d_tn << "): complete at size " |
796 |
43 |
<< d_currSize << std::endl; |
797 |
43 |
tc.setComplete(); |
798 |
43 |
return false; |
799 |
|
} |
800 |
|
} |
801 |
|
} |
802 |
|
|
803 |
|
// increment the size bound |
804 |
403 |
d_currSize++; |
805 |
806 |
Trace("sygus-enum-debug2") << "master(" << d_tn |
806 |
403 |
<< "): size++ : " << d_currSize << "\n"; |
807 |
403 |
if (Trace.isOn("sygus-engine")) |
808 |
|
{ |
809 |
|
// am i the master enumerator? if so, print |
810 |
|
if (d_se->d_tlEnum == this) |
811 |
|
{ |
812 |
|
Trace("sygus-engine") << "SygusEnumerator::size = " << d_currSize |
813 |
|
<< std::endl; |
814 |
|
} |
815 |
|
} |
816 |
|
|
817 |
|
// push the bound |
818 |
403 |
tc.pushEnumSizeIndex(); |
819 |
|
|
820 |
|
// restart with constructor class one (skip nullary constructors) |
821 |
403 |
d_consClassNum = 1; |
822 |
|
|
823 |
|
// We break for a round: return the null term when we cross a size |
824 |
|
// boundary. This ensures that the necessary breaks are taken, e.g. |
825 |
|
// in slave enumerators who may instead want to abandon this call to |
826 |
|
// increment master when the size of the master makes their increment |
827 |
|
// infeasible. |
828 |
403 |
d_currTermSet = true; |
829 |
403 |
d_currTerm = Node::null(); |
830 |
403 |
return true; |
831 |
|
} |
832 |
|
|
833 |
55741 |
bool incSuccess = false; |
834 |
28640 |
do |
835 |
|
{ |
836 |
167710 |
Trace("sygus-enum-debug2") << "master(" << d_tn << "): check return " |
837 |
167710 |
<< d_childrenValid << "/" << d_ccTypes.size() |
838 |
83855 |
<< std::endl; |
839 |
|
// the children should be initialized by here |
840 |
83855 |
Assert(d_childrenValid == d_ccTypes.size()); |
841 |
|
|
842 |
|
// do we have more constructors for the given children? |
843 |
83855 |
if (d_consNum < d_ccCons.size()) |
844 |
|
{ |
845 |
110430 |
Trace("sygus-enum-debug2") << "master(" << d_tn << "): try constructor " |
846 |
55215 |
<< d_consNum << std::endl; |
847 |
|
// increment constructor index |
848 |
|
// we will build for the current constructor and the given children |
849 |
55215 |
d_consNum++; |
850 |
55215 |
d_currTermSet = false; |
851 |
55215 |
d_currTerm = Node::null(); |
852 |
110430 |
Node c = getCurrent(); |
853 |
55215 |
if (!c.isNull()) |
854 |
|
{ |
855 |
55215 |
if (!tc.addTerm(c)) |
856 |
|
{ |
857 |
|
// the term was not unique based on rewriting |
858 |
62868 |
Trace("sygus-enum-debug2") << "master(" << d_tn |
859 |
31434 |
<< "): failed addTerm\n"; |
860 |
|
// we will return null (d_currTermSet is true at this point) |
861 |
31434 |
Assert(d_currTermSet); |
862 |
31434 |
d_currTerm = Node::null(); |
863 |
|
} |
864 |
|
} |
865 |
55215 |
return true; |
866 |
|
} |
867 |
|
|
868 |
|
// finished constructors for this set of children, must increment children |
869 |
|
|
870 |
|
// reset the constructor number |
871 |
28640 |
d_consNum = 0; |
872 |
|
|
873 |
|
// try incrementing the last child until we find one that works |
874 |
28640 |
incSuccess = false; |
875 |
90592 |
while (!incSuccess && d_childrenValid > 0) |
876 |
|
{ |
877 |
61952 |
Trace("sygus-enum-debug2") << "master(" << d_tn << "): try incrementing " |
878 |
30976 |
<< d_childrenValid << std::endl; |
879 |
30976 |
unsigned i = d_childrenValid - 1; |
880 |
30976 |
Assert(d_children[i].getCurrentSize() <= d_currChildSize); |
881 |
|
// track the size |
882 |
30976 |
d_currChildSize -= d_children[i].getCurrentSize(); |
883 |
30976 |
if (d_children[i].increment()) |
884 |
|
{ |
885 |
56238 |
Trace("sygus-enum-debug2") << "master(" << d_tn |
886 |
28119 |
<< "): increment success...\n"; |
887 |
28119 |
d_currChildSize += d_children[i].getCurrentSize(); |
888 |
|
// must see if we can initialize the remaining children here |
889 |
|
// if not, there is no use continuing. |
890 |
28119 |
if (initializeChildren()) |
891 |
|
{ |
892 |
56228 |
Trace("sygus-enum-debug2") |
893 |
28114 |
<< "master(" << d_tn << "): success init children\n"; |
894 |
28114 |
Assert(d_currChildSize + d_ccWeight <= d_currSize); |
895 |
28114 |
incSuccess = true; |
896 |
|
} |
897 |
|
else |
898 |
|
{ |
899 |
|
// failed to initialize the remaining children (likely due to a |
900 |
|
// child having a non-zero minimum size bound). |
901 |
10 |
Trace("sygus-enum-debug2") |
902 |
5 |
<< "master(" << d_tn << "): fail init children\n"; |
903 |
5 |
d_currChildSize -= d_children[i].getCurrentSize(); |
904 |
|
} |
905 |
|
} |
906 |
30976 |
if (!incSuccess) |
907 |
|
{ |
908 |
5724 |
Trace("sygus-enum-debug2") << "master(" << d_tn |
909 |
2862 |
<< "): fail, backtrack...\n"; |
910 |
|
// current child is out of values |
911 |
2862 |
d_children.erase(i); |
912 |
2862 |
d_childrenValid--; |
913 |
|
} |
914 |
|
} |
915 |
|
} while (incSuccess); |
916 |
1052 |
Trace("sygus-enum-debug2") << "master(" << d_tn |
917 |
526 |
<< "): failed increment children\n"; |
918 |
|
// restart with the next constructor class |
919 |
526 |
d_ccCons.clear(); |
920 |
526 |
d_ccTypes.clear(); |
921 |
526 |
return incrementInternal(); |
922 |
|
} |
923 |
|
|
924 |
28915 |
bool SygusEnumerator::TermEnumMaster::initializeChildren() |
925 |
|
{ |
926 |
57830 |
Trace("sygus-enum-debug2") |
927 |
28915 |
<< "master(" << d_tn << "): init children, start = " << d_childrenValid |
928 |
57830 |
<< ", #types=" << d_ccTypes.size() << ", sizes=" << d_currChildSize << "/" |
929 |
28915 |
<< d_currSize << std::endl; |
930 |
28915 |
unsigned currChildren = d_childrenValid; |
931 |
28915 |
unsigned sizeMin = 0; |
932 |
|
// while we need to initialize the current child |
933 |
35351 |
while (d_childrenValid < d_ccTypes.size()) |
934 |
|
{ |
935 |
3327 |
if (!initializeChild(d_childrenValid, sizeMin)) |
936 |
|
{ |
937 |
169 |
if (d_childrenValid == currChildren) |
938 |
|
{ |
939 |
|
// we are back to the child we started with, we terminate now. |
940 |
218 |
Trace("sygus-enum-debug2") << "master(" << d_tn |
941 |
109 |
<< "): init children : failed, finished" |
942 |
109 |
<< std::endl; |
943 |
109 |
return false; |
944 |
|
} |
945 |
120 |
Trace("sygus-enum-debug2") << "master(" << d_tn |
946 |
60 |
<< "): init children : failed" << std::endl; |
947 |
|
// we failed in this size configuration |
948 |
|
// reinitialize with the next size up |
949 |
60 |
unsigned currSize = d_children[d_childrenValid - 1].getCurrentSize(); |
950 |
60 |
d_currChildSize -= currSize; |
951 |
60 |
sizeMin = currSize + 1; |
952 |
60 |
d_children.erase(d_childrenValid - 1); |
953 |
60 |
d_childrenValid--; |
954 |
|
} |
955 |
|
else |
956 |
|
{ |
957 |
3158 |
sizeMin = 0; |
958 |
3158 |
d_childrenValid++; |
959 |
|
} |
960 |
|
} |
961 |
57612 |
Trace("sygus-enum-debug2") << "master(" << d_tn |
962 |
28806 |
<< "): init children : success" << std::endl; |
963 |
|
// initialized all children |
964 |
28806 |
return true; |
965 |
|
} |
966 |
|
|
967 |
3327 |
bool SygusEnumerator::TermEnumMaster::initializeChild(unsigned i, |
968 |
|
unsigned sizeMin) |
969 |
|
{ |
970 |
3327 |
Assert(d_ccWeight <= d_currSize); |
971 |
3327 |
Assert(d_currChildSize + d_ccWeight <= d_currSize); |
972 |
3327 |
unsigned sizeMax = (d_currSize - d_ccWeight) - d_currChildSize; |
973 |
6654 |
Trace("sygus-enum-debug2") << "master(" << d_tn << "): initializeChild " << i |
974 |
3327 |
<< " (" << d_currSize << ", " << d_ccWeight << ", " |
975 |
3327 |
<< d_currChildSize << ")\n"; |
976 |
3327 |
if (sizeMin > sizeMax) |
977 |
|
{ |
978 |
60 |
Trace("sygus-enum-debug2") << "master(" << d_tn << "): failed due to size " |
979 |
30 |
<< sizeMin << "/" << sizeMax << "\n"; |
980 |
30 |
return false; |
981 |
|
} |
982 |
|
// initialize the child to enumerate exactly the terms that sum to size |
983 |
3297 |
sizeMin = (i + 1 == d_ccTypes.size()) ? sizeMax : sizeMin; |
984 |
3297 |
TermEnumSlave& te = d_children[i]; |
985 |
3297 |
bool init = te.initialize(d_se, d_ccTypes[i], sizeMin, sizeMax); |
986 |
3297 |
if (!init) |
987 |
|
{ |
988 |
|
// failed to initialize |
989 |
139 |
d_children.erase(i); |
990 |
278 |
Trace("sygus-enum-debug2") << "master(" << d_tn |
991 |
139 |
<< "): failed due to child init\n"; |
992 |
139 |
return false; |
993 |
|
} |
994 |
3158 |
unsigned teSize = te.getCurrentSize(); |
995 |
|
// fail if the initial children size does not fit d_currSize-d_ccWeight |
996 |
3158 |
if (teSize + d_currChildSize + d_ccWeight > d_currSize) |
997 |
|
{ |
998 |
|
d_children.erase(i); |
999 |
|
Trace("sygus-enum-debug2") << "master(" << d_tn |
1000 |
|
<< "): failed due to child size\n"; |
1001 |
|
return false; |
1002 |
|
} |
1003 |
3158 |
d_currChildSize += teSize; |
1004 |
6316 |
Trace("sygus-enum-debug2") << "master(" << d_tn |
1005 |
3158 |
<< "): success initializeChild " << i << "\n"; |
1006 |
3158 |
return true; |
1007 |
|
} |
1008 |
|
|
1009 |
10977 |
void SygusEnumerator::TermEnumMaster::childrenToShape( |
1010 |
|
std::vector<Node>& children) |
1011 |
|
{ |
1012 |
10977 |
if (children.size() <= 2) |
1013 |
|
{ |
1014 |
|
// don't need to convert constants and unary applications |
1015 |
961 |
return; |
1016 |
|
} |
1017 |
20032 |
std::map<TypeNode, int> vcounter; |
1018 |
|
// Buffered child, so that we only compute vcounter if there are more than |
1019 |
|
// one children with free variables, since otherwise there is no change. |
1020 |
|
// For example, if we are given { C, (+ x1 x2), 1 }, we buffer child (+ x1 x2) |
1021 |
|
// noting that it has free variables. We proceed with processing the remaining |
1022 |
|
// children, and note that no other child contains free variables, and hence |
1023 |
|
// no change is necessary (since by construction, all children have the |
1024 |
|
// property of having unique variable subterms). On the other hand if the |
1025 |
|
// last child above was x1, then this would trigger us to convert (+ x1 x2) |
1026 |
|
// while computing vcounter, and subsequently update x1 to x3 to obtain |
1027 |
|
// { C, (+ x1 x2), x3 }. |
1028 |
|
// Have we set the buffer child index |
1029 |
10016 |
bool bufferChildSet = false; |
1030 |
|
// Have we processed the buffer child index |
1031 |
10016 |
bool bufferChildProcessed = false; |
1032 |
|
// The buffer child index |
1033 |
10016 |
size_t bufferChild = 0; |
1034 |
32121 |
for (size_t i = 1, nchildren = children.size(); i < nchildren; i++) |
1035 |
|
{ |
1036 |
22105 |
if (!expr::hasBoundVar(children[i])) |
1037 |
|
{ |
1038 |
|
// don't need to care about expressions with no bound variables |
1039 |
10145 |
continue; |
1040 |
|
} |
1041 |
20815 |
else if (!bufferChildSet) |
1042 |
|
{ |
1043 |
8855 |
bufferChild = i; |
1044 |
8855 |
bufferChildSet = true; |
1045 |
8855 |
continue; |
1046 |
|
} |
1047 |
3105 |
else if (!bufferChildProcessed) |
1048 |
|
{ |
1049 |
|
// process the buffer child |
1050 |
2910 |
children[bufferChild] = convertShape(children[bufferChild], vcounter); |
1051 |
2910 |
bufferChildProcessed = true; |
1052 |
|
} |
1053 |
3105 |
children[i] = convertShape(children[i], vcounter); |
1054 |
|
} |
1055 |
|
} |
1056 |
|
|
1057 |
6015 |
Node SygusEnumerator::TermEnumMaster::convertShape( |
1058 |
|
Node n, std::map<TypeNode, int>& vcounter) |
1059 |
|
{ |
1060 |
6015 |
Assert(d_tds != nullptr); |
1061 |
6015 |
NodeManager* nm = NodeManager::currentNM(); |
1062 |
12030 |
std::unordered_map<TNode, Node> visited; |
1063 |
6015 |
std::unordered_map<TNode, Node>::iterator it; |
1064 |
12030 |
std::vector<TNode> visit; |
1065 |
12030 |
TNode cur; |
1066 |
6015 |
visit.push_back(n); |
1067 |
15853 |
do |
1068 |
|
{ |
1069 |
21868 |
cur = visit.back(); |
1070 |
21868 |
visit.pop_back(); |
1071 |
21868 |
it = visited.find(cur); |
1072 |
|
|
1073 |
21868 |
if (it == visited.end()) |
1074 |
|
{ |
1075 |
16491 |
if (cur.isVar()) |
1076 |
|
{ |
1077 |
|
// do the conversion |
1078 |
8136 |
visited[cur] = d_tds->getFreeVarInc(cur.getType(), vcounter); |
1079 |
|
} |
1080 |
8355 |
else if (!expr::hasBoundVar(cur)) |
1081 |
|
{ |
1082 |
|
// no bound variables, no change |
1083 |
3028 |
visited[cur] = cur; |
1084 |
|
} |
1085 |
|
else |
1086 |
|
{ |
1087 |
5327 |
visited[cur] = Node::null(); |
1088 |
5327 |
visit.push_back(cur); |
1089 |
5327 |
visit.insert(visit.end(), cur.begin(), cur.end()); |
1090 |
|
} |
1091 |
|
} |
1092 |
5377 |
else if (it->second.isNull()) |
1093 |
|
{ |
1094 |
10654 |
Node ret = cur; |
1095 |
5327 |
bool childChanged = false; |
1096 |
10654 |
std::vector<Node> children; |
1097 |
5327 |
if (cur.getMetaKind() == metakind::PARAMETERIZED) |
1098 |
|
{ |
1099 |
5327 |
children.push_back(cur.getOperator()); |
1100 |
|
} |
1101 |
15853 |
for (const Node& cn : cur) |
1102 |
|
{ |
1103 |
10526 |
it = visited.find(cn); |
1104 |
10526 |
Assert(it != visited.end()); |
1105 |
10526 |
Assert(!it->second.isNull()); |
1106 |
10526 |
childChanged = childChanged || cn != it->second; |
1107 |
10526 |
children.push_back(it->second); |
1108 |
|
} |
1109 |
5327 |
if (childChanged) |
1110 |
|
{ |
1111 |
3721 |
ret = nm->mkNode(cur.getKind(), children); |
1112 |
|
} |
1113 |
5327 |
visited[cur] = ret; |
1114 |
|
} |
1115 |
21868 |
} while (!visit.empty()); |
1116 |
6015 |
Assert(visited.find(n) != visited.end()); |
1117 |
6015 |
Assert(!visited.find(n)->second.isNull()); |
1118 |
12030 |
return visited[n]; |
1119 |
|
} |
1120 |
|
|
1121 |
11 |
SygusEnumerator::TermEnumMasterInterp::TermEnumMasterInterp(TypeNode tn) |
1122 |
11 |
: TermEnum(), d_te(tn), d_currNumConsts(0), d_nextIndexEnd(0) |
1123 |
|
{ |
1124 |
11 |
} |
1125 |
|
|
1126 |
11 |
bool SygusEnumerator::TermEnumMasterInterp::initialize(SygusEnumerator* se, |
1127 |
|
TypeNode tn) |
1128 |
|
{ |
1129 |
11 |
d_se = se; |
1130 |
11 |
d_tn = tn; |
1131 |
11 |
d_currSize = 0; |
1132 |
11 |
d_currNumConsts = 1; |
1133 |
11 |
d_nextIndexEnd = 1; |
1134 |
11 |
return true; |
1135 |
|
} |
1136 |
|
|
1137 |
101 |
Node SygusEnumerator::TermEnumMasterInterp::getCurrent() { return *d_te; } |
1138 |
102 |
bool SygusEnumerator::TermEnumMasterInterp::increment() |
1139 |
|
{ |
1140 |
102 |
if (d_te.isFinished()) |
1141 |
|
{ |
1142 |
1 |
return false; |
1143 |
|
} |
1144 |
101 |
SygusEnumerator::TermCache& tc = d_se->d_tcache[d_tn]; |
1145 |
202 |
Node curr = getCurrent(); |
1146 |
101 |
tc.addTerm(curr); |
1147 |
101 |
if (tc.getNumTerms() == d_nextIndexEnd) |
1148 |
|
{ |
1149 |
16 |
tc.pushEnumSizeIndex(); |
1150 |
16 |
d_currSize++; |
1151 |
16 |
d_currNumConsts = d_currNumConsts * options::sygusActiveGenEnumConsts(); |
1152 |
16 |
d_nextIndexEnd = d_nextIndexEnd + d_currNumConsts; |
1153 |
|
} |
1154 |
101 |
++d_te; |
1155 |
101 |
return !d_te.isFinished(); |
1156 |
|
} |
1157 |
5 |
SygusEnumerator::TermEnumMasterFv::TermEnumMasterFv() : TermEnum() {} |
1158 |
5 |
bool SygusEnumerator::TermEnumMasterFv::initialize(SygusEnumerator* se, |
1159 |
|
TypeNode tn) |
1160 |
|
{ |
1161 |
5 |
d_se = se; |
1162 |
5 |
d_tn = tn; |
1163 |
5 |
d_currSize = 0; |
1164 |
10 |
Node ret = getCurrent(); |
1165 |
5 |
AlwaysAssert(!ret.isNull()); |
1166 |
5 |
SygusEnumerator::TermCache& tc = d_se->d_tcache[d_tn]; |
1167 |
5 |
tc.addTerm(ret); |
1168 |
10 |
return true; |
1169 |
|
} |
1170 |
|
|
1171 |
10 |
Node SygusEnumerator::TermEnumMasterFv::getCurrent() |
1172 |
|
{ |
1173 |
10 |
Assert(d_se->d_tds != nullptr); |
1174 |
10 |
Node ret = d_se->d_tds->getFreeVar(d_tn, d_currSize); |
1175 |
20 |
Trace("sygus-enum-debug2") << "master_fv(" << d_tn << "): mk " << ret |
1176 |
10 |
<< std::endl; |
1177 |
10 |
return ret; |
1178 |
|
} |
1179 |
|
|
1180 |
5 |
bool SygusEnumerator::TermEnumMasterFv::increment() |
1181 |
|
{ |
1182 |
5 |
SygusEnumerator::TermCache& tc = d_se->d_tcache[d_tn]; |
1183 |
|
// size increments at a constant rate |
1184 |
5 |
d_currSize++; |
1185 |
5 |
tc.pushEnumSizeIndex(); |
1186 |
10 |
Node curr = getCurrent(); |
1187 |
10 |
Trace("sygus-enum-debug2") << "master_fv(" << d_tn << "): increment, add " |
1188 |
5 |
<< curr << std::endl; |
1189 |
5 |
bool ret = tc.addTerm(curr); |
1190 |
5 |
AlwaysAssert(ret); |
1191 |
10 |
return true; |
1192 |
|
} |
1193 |
|
|
1194 |
|
} // namespace quantifiers |
1195 |
|
} // namespace theory |
1196 |
29505 |
} // namespace cvc5 |