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