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