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