1 |
|
/****************************************************************************** |
2 |
|
* Top contributors (to current version): |
3 |
|
* Abdalrhman Mohamed, Andrew Reynolds, 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 for reconstruct. |
14 |
|
*/ |
15 |
|
|
16 |
|
#include "theory/quantifiers/sygus/sygus_reconstruct.h" |
17 |
|
|
18 |
|
#include "expr/node_algorithm.h" |
19 |
|
#include "smt/command.h" |
20 |
|
#include "theory/datatypes/sygus_datatype_utils.h" |
21 |
|
#include "theory/rewriter.h" |
22 |
|
|
23 |
|
using namespace cvc5::kind; |
24 |
|
|
25 |
|
namespace cvc5 { |
26 |
|
namespace theory { |
27 |
|
namespace quantifiers { |
28 |
|
|
29 |
1529 |
SygusReconstruct::SygusReconstruct(TermDbSygus* tds, SygusStatistics& s) |
30 |
1529 |
: d_tds(tds), d_stats(s) |
31 |
|
{ |
32 |
1529 |
} |
33 |
|
|
34 |
24 |
Node SygusReconstruct::reconstructSolution(Node sol, |
35 |
|
TypeNode stn, |
36 |
|
int8_t& reconstructed, |
37 |
|
uint64_t enumLimit) |
38 |
|
{ |
39 |
48 |
Trace("sygus-rcons") << "SygusReconstruct::reconstructSolution: " << sol |
40 |
24 |
<< std::endl; |
41 |
24 |
Trace("sygus-rcons") << "- target sygus type is " << stn << std::endl; |
42 |
24 |
Trace("sygus-rcons") << "- enumeration limit is " << enumLimit << std::endl; |
43 |
|
|
44 |
|
// this method may get called multiple times with the same object. We need to |
45 |
|
// reset the state to avoid conflicts |
46 |
24 |
clear(); |
47 |
|
|
48 |
24 |
initialize(stn); |
49 |
|
|
50 |
|
/** a set of builtin terms to reconstruct satisfied for each sygus datatype */ |
51 |
48 |
TypeBuiltinSetMap termsToRecons; |
52 |
|
|
53 |
|
// add the main obligation to the set of obligations |
54 |
|
// paramaters stn and sol constitute the main obligation to satisfy |
55 |
24 |
d_obs.push_back(std::make_unique<RConsObligation>(stn, sol)); |
56 |
24 |
termsToRecons[stn].emplace(sol); |
57 |
24 |
d_stnInfo[stn].setBuiltinToOb(sol, d_obs[0].get()); |
58 |
24 |
RConsObligation* ob0 = d_obs[0].get(); |
59 |
48 |
Node k0 = ob0->getSkolem(); |
60 |
|
|
61 |
|
// We need to add the main obligation to the crd in case it cannot be broken |
62 |
|
// down by matching. By doing so, we can solve the obligation using |
63 |
|
// enumeration and crd (if it is in the grammar) |
64 |
24 |
d_stnInfo[stn].addTerm(sol); |
65 |
|
|
66 |
|
// the set of unique (up to rewriting) patterns/shapes in the grammar used by |
67 |
|
// matching |
68 |
48 |
std::unordered_map<TypeNode, std::vector<Node>> pool; |
69 |
|
|
70 |
24 |
uint64_t count = 0; |
71 |
|
|
72 |
|
// algorithm |
73 |
19682 |
while (d_sol[k0].isNull() && count < enumLimit) |
74 |
|
{ |
75 |
|
// enumeration phase |
76 |
|
// a temporary set of new terms to reconstruct cached for processing in the |
77 |
|
// match phase |
78 |
19658 |
TypeBuiltinSetMap termsToReconsPrime; |
79 |
20416 |
for (const std::pair<const TypeNode, BuiltinSet>& pair : termsToRecons) |
80 |
|
{ |
81 |
|
// enumerate a new term |
82 |
10587 |
Trace("sygus-rcons") << "enum: " << stn << ": "; |
83 |
15139 |
Node sz = d_stnInfo[pair.first].nextEnum(); |
84 |
10587 |
if (sz.isNull()) |
85 |
|
{ |
86 |
5380 |
continue; |
87 |
|
} |
88 |
9759 |
Node builtin = Rewriter::rewrite(datatypes::utils::sygusToBuiltin(sz)); |
89 |
|
// if enumerated term does not contain free variables, then its |
90 |
|
// corresponding obligation can be solved immediately |
91 |
5207 |
if (sz.isConst()) |
92 |
|
{ |
93 |
1310 |
Node rep = d_stnInfo[pair.first].addTerm(builtin); |
94 |
655 |
RConsObligation* ob = d_stnInfo[pair.first].builtinToOb(rep); |
95 |
|
// check if the enumerated term solves an obligation |
96 |
655 |
if (ob == nullptr) |
97 |
|
{ |
98 |
|
// if not, create an "artifical" obligation whose solution would be |
99 |
|
// the enumerated term |
100 |
1252 |
d_obs.push_back( |
101 |
1252 |
std::make_unique<RConsObligation>(pair.first, builtin)); |
102 |
626 |
d_stnInfo[pair.first].setBuiltinToOb(builtin, d_obs.back().get()); |
103 |
626 |
ob = d_obs.back().get(); |
104 |
|
} |
105 |
|
// mark the obligation as solved |
106 |
655 |
markSolved(ob, sz); |
107 |
|
// Since we added the term to the candidate rewrite database, there is |
108 |
|
// no point in adding it to the pool too |
109 |
655 |
continue; |
110 |
|
} |
111 |
|
// if there are no matches (all calls to notify return true)... |
112 |
4552 |
if (d_poolTrie.getMatches(builtin, this)) |
113 |
|
{ |
114 |
|
// then, this is a new term and we should add it to pool |
115 |
472 |
d_poolTrie.addTerm(builtin); |
116 |
472 |
pool[pair.first].push_back(sz); |
117 |
1419 |
for (const Node& t : pair.second) |
118 |
|
{ |
119 |
947 |
RConsObligation* ob = d_stnInfo[pair.first].builtinToOb(t); |
120 |
947 |
if (d_sol[ob->getSkolem()].isNull()) |
121 |
|
{ |
122 |
946 |
Trace("sygus-rcons") << "ob: " << *ob << std::endl; |
123 |
|
// try to match builtin term `t` with the enumerated term sz |
124 |
1892 |
TypeBuiltinSetMap temp = matchNewObs(t, sz); |
125 |
|
// cache the new obligations for processing in the match phase |
126 |
964 |
for (const std::pair<const TypeNode, BuiltinSet>& tempPair : temp) |
127 |
|
{ |
128 |
18 |
termsToReconsPrime[tempPair.first].insert( |
129 |
|
tempPair.second.cbegin(), tempPair.second.cend()); |
130 |
|
} |
131 |
|
} |
132 |
|
} |
133 |
|
} |
134 |
|
} |
135 |
|
// match phase |
136 |
9863 |
while (!termsToReconsPrime.empty()) |
137 |
|
{ |
138 |
|
// a temporary set of new terms to reconstruct cached for later processing |
139 |
34 |
TypeBuiltinSetMap obsDPrime; |
140 |
21 |
for (const std::pair<const TypeNode, BuiltinSet>& pair : |
141 |
17 |
termsToReconsPrime) |
142 |
|
{ |
143 |
52 |
for (const Node& t : pair.second) |
144 |
|
{ |
145 |
31 |
termsToRecons[pair.first].emplace(t); |
146 |
31 |
RConsObligation* ob = d_stnInfo[pair.first].builtinToOb(t); |
147 |
31 |
if (d_sol[ob->getSkolem()].isNull()) |
148 |
|
{ |
149 |
31 |
Trace("sygus-rcons") << "ob: " << *ob << std::endl; |
150 |
305 |
for (const Node& sz : pool[pair.first]) |
151 |
|
{ |
152 |
|
// try to match each newly generated and cached term with patterns |
153 |
|
// in pool |
154 |
548 |
TypeBuiltinSetMap temp = matchNewObs(t, sz); |
155 |
|
// cache the new terms for later processing |
156 |
279 |
for (const std::pair<const TypeNode, BuiltinSet>& tempPair : temp) |
157 |
|
{ |
158 |
5 |
obsDPrime[tempPair.first].insert(tempPair.second.cbegin(), |
159 |
|
tempPair.second.cend()); |
160 |
|
} |
161 |
|
} |
162 |
|
} |
163 |
|
} |
164 |
|
} |
165 |
17 |
termsToReconsPrime = std::move(obsDPrime); |
166 |
|
} |
167 |
|
// remove reconstructed terms from termsToRecons |
168 |
9829 |
removeReconstructedTerms(termsToRecons); |
169 |
9829 |
++count; |
170 |
|
} |
171 |
|
|
172 |
24 |
if (Trace("sygus-rcons").isConnected()) |
173 |
|
{ |
174 |
|
RConsObligation::printCandSols(ob0, d_obs); |
175 |
|
printPool(pool); |
176 |
|
} |
177 |
|
|
178 |
|
// if the main obligation is solved, return the solution |
179 |
24 |
if (!d_sol[k0].isNull()) |
180 |
|
{ |
181 |
24 |
reconstructed = 1; |
182 |
|
// The algorithm mostly works with rewritten terms and may not notice that |
183 |
|
// the original terms contain variables eliminated by the rewriter. For |
184 |
|
// example, rewrite((ite true 0 z)) = 0. In such cases, we replace those |
185 |
|
// variables with ground values. |
186 |
24 |
return d_sol[k0].isConst() ? Node(d_sol[k0]) : mkGround(d_sol[k0]); |
187 |
|
} |
188 |
|
|
189 |
|
// we ran out of elements, return null |
190 |
|
reconstructed = -1; |
191 |
|
Warning() << CommandFailure( |
192 |
|
"Cannot get synth function: reconstruction to syntax failed."); |
193 |
|
return Node::null(); |
194 |
|
} |
195 |
|
|
196 |
1220 |
TypeBuiltinSetMap SygusReconstruct::matchNewObs(Node t, Node sz) |
197 |
|
{ |
198 |
1220 |
TypeBuiltinSetMap termsToReconsPrime; |
199 |
|
|
200 |
|
// substitutions generated by match. Note that we might have already seen (and |
201 |
|
// even solved) obligations corresponsing to those substitutions |
202 |
2440 |
NodePairMap matches; |
203 |
|
// the builtin terms corresponding to sygus variables in the grammar are bound |
204 |
|
// variables. However, we want the `match` method to treat them as ground |
205 |
|
// terms. So, we add redundant substitutions |
206 |
1220 |
matches.insert(d_sygusVars.cbegin(), d_sygusVars.cend()); |
207 |
|
|
208 |
|
// try to match the builtin term with the pattern sz |
209 |
3660 |
if (expr::match( |
210 |
2440 |
Rewriter::rewrite(datatypes::utils::sygusToBuiltin(sz)), t, matches)) |
211 |
|
{ |
212 |
|
// the bound variables z generated by the enumerators are reused across |
213 |
|
// enumerated terms, so we need to replace them with our own skolems |
214 |
80 |
NodePairMap subs; |
215 |
40 |
Trace("sygus-rcons") << "-- ct: " << sz << std::endl; |
216 |
|
// remove redundant substitutions |
217 |
144 |
for (const std::pair<const Node, Node>& pair : d_sygusVars) |
218 |
|
{ |
219 |
104 |
matches.erase(pair.first); |
220 |
|
} |
221 |
|
// for each match |
222 |
113 |
for (const std::pair<const Node, Node>& match : matches) |
223 |
|
{ |
224 |
146 |
TypeNode stn = datatypes::utils::builtinVarToSygus(match.first).getType(); |
225 |
|
RConsObligation* newOb; |
226 |
|
// did we come across an equivalent obligation before? |
227 |
146 |
Node rep = d_stnInfo[stn].addTerm(match.second); |
228 |
73 |
RConsObligation* repOb = d_stnInfo[stn].builtinToOb(rep); |
229 |
73 |
if (repOb != nullptr) |
230 |
|
{ |
231 |
|
// if so, use the original obligation |
232 |
42 |
newOb = repOb; |
233 |
|
// while `match.second` is equivalent to `rep`, it may be easier to |
234 |
|
// reconstruct than `rep`. For example: |
235 |
|
// |
236 |
|
// Grammar: S -> p | q | (not S) | (and S S) | (or S S) |
237 |
|
// rep = (= p q) |
238 |
|
// match.second = (or (and p q) (and (not p) (not q))) |
239 |
|
// |
240 |
|
// In this case, `match.second` is easy to reconstruct by matching |
241 |
|
// because it only uses operators that are already in the grammar. |
242 |
|
// `rep`, on the other hand, cannot be reconstructed by matching and |
243 |
|
// can only be solved by enumeration (currently). |
244 |
|
// |
245 |
|
// At this point, we do not know which one is easier to reconstruct by |
246 |
|
// matching, so we add `match.second` to the set of equivalent builtin |
247 |
|
// terms in `repOb` and match against both terms. |
248 |
126 |
if (repOb->getBuiltins().find(match.second) |
249 |
126 |
== repOb->getBuiltins().cend()) |
250 |
|
{ |
251 |
1 |
repOb->addBuiltin(match.second); |
252 |
1 |
d_stnInfo[stn].setBuiltinToOb(match.second, repOb); |
253 |
1 |
termsToReconsPrime[stn].emplace(match.second); |
254 |
|
} |
255 |
|
} |
256 |
|
else |
257 |
|
{ |
258 |
|
// otherwise, create a new obligation of the corresponding sygus type |
259 |
31 |
d_obs.push_back(std::make_unique<RConsObligation>(stn, match.second)); |
260 |
31 |
d_stnInfo[stn].setBuiltinToOb(match.second, d_obs.back().get()); |
261 |
31 |
newOb = d_obs.back().get(); |
262 |
|
// if the match is a constant and the grammar allows random constants |
263 |
31 |
if (match.second.isConst() && stn.getDType().getSygusAllowConst()) |
264 |
|
{ |
265 |
|
// then immediately solve the obligation |
266 |
1 |
markSolved(newOb, d_tds->getProxyVariable(stn, match.second)); |
267 |
|
} |
268 |
|
else |
269 |
|
{ |
270 |
|
// otherwise, add this match to the list of obligations |
271 |
30 |
termsToReconsPrime[stn].emplace(match.second); |
272 |
|
} |
273 |
|
} |
274 |
73 |
subs.emplace(datatypes::utils::builtinVarToSygus(match.first), |
275 |
146 |
newOb->getSkolem()); |
276 |
|
} |
277 |
|
// replace original free vars in sz with new ones |
278 |
40 |
if (!subs.empty()) |
279 |
|
{ |
280 |
37 |
sz = sz.substitute(subs.cbegin(), subs.cend()); |
281 |
|
} |
282 |
|
// sz is solved if it has no sub-obligations or if all of them are solved |
283 |
40 |
bool isSolved = true; |
284 |
113 |
for (const std::pair<const Node, Node>& match : matches) |
285 |
|
{ |
286 |
146 |
TypeNode stn = datatypes::utils::builtinVarToSygus(match.first).getType(); |
287 |
73 |
RConsObligation* ob = d_stnInfo[stn].builtinToOb(match.second); |
288 |
73 |
if (d_sol[ob->getSkolem()].isNull()) |
289 |
|
{ |
290 |
32 |
isSolved = false; |
291 |
32 |
d_subObs[sz].push_back(ob); |
292 |
|
} |
293 |
|
} |
294 |
|
|
295 |
40 |
RConsObligation* ob = d_stnInfo[sz.getType()].builtinToOb(t); |
296 |
|
|
297 |
40 |
if (isSolved) |
298 |
|
{ |
299 |
|
// As it traverses sz, substitute populates its input cache with TNodes |
300 |
|
// that are not preserved by this module and maybe destroyed after the |
301 |
|
// method call. To avoid referencing those unsafe TNodes throughout this |
302 |
|
// module, we pass a iterators of d_sol instead. |
303 |
40 |
Node s = sz.substitute(d_sol.cbegin(), d_sol.cend()); |
304 |
20 |
markSolved(ob, s); |
305 |
|
} |
306 |
|
else |
307 |
|
{ |
308 |
|
// add sz as a possible solution to ob |
309 |
20 |
ob->addCandidateSolution(sz); |
310 |
20 |
d_parentOb[sz] = ob; |
311 |
20 |
d_subObs[sz].back()->addCandidateSolutionToWatchSet(sz); |
312 |
|
} |
313 |
|
} |
314 |
|
|
315 |
2440 |
return termsToReconsPrime; |
316 |
|
} |
317 |
|
|
318 |
676 |
void SygusReconstruct::markSolved(RConsObligation* ob, Node s) |
319 |
|
{ |
320 |
|
// return if ob is already solved |
321 |
676 |
if (!d_sol[ob->getSkolem()].isNull()) |
322 |
|
{ |
323 |
18 |
return; |
324 |
|
} |
325 |
|
|
326 |
658 |
Trace("sygus-rcons") << "sol: " << s << std::endl; |
327 |
1316 |
Trace("sygus-rcons") << "builtin sol: " << datatypes::utils::sygusToBuiltin(s) |
328 |
658 |
<< std::endl; |
329 |
|
|
330 |
|
// First, mark ob as solved |
331 |
658 |
ob->addCandidateSolution(s); |
332 |
658 |
d_sol[ob->getSkolem()] = s; |
333 |
658 |
d_parentOb[s] = ob; |
334 |
|
|
335 |
1316 |
std::vector<RConsObligation*> stack; |
336 |
658 |
stack.push_back(ob); |
337 |
|
|
338 |
2008 |
while (!stack.empty()) |
339 |
|
{ |
340 |
675 |
RConsObligation* curr = stack.back(); |
341 |
675 |
stack.pop_back(); |
342 |
|
|
343 |
|
// for each partial solution/parent of the now solved obligation `curr` |
344 |
695 |
for (const Node& parent : curr->getWatchSet()) |
345 |
|
{ |
346 |
|
// remove `curr` and (possibly) other solved obligations from its list |
347 |
|
// of children |
348 |
72 |
while (!d_subObs[parent].empty() |
349 |
92 |
&& !d_sol[d_subObs[parent].back()->getSkolem()].isNull()) |
350 |
|
{ |
351 |
26 |
d_subObs[parent].pop_back(); |
352 |
|
} |
353 |
|
|
354 |
|
// if the partial solution does not have any more children... |
355 |
20 |
if (d_subObs[parent].empty()) |
356 |
|
{ |
357 |
|
// then it is completely solved and can be used as a solution of its |
358 |
|
// corresponding obligation |
359 |
|
// pass iterators of d_sol to avoid populating it with unsafe TNodes |
360 |
34 |
Node parentSol = parent.substitute(d_sol.cbegin(), d_sol.cend()); |
361 |
17 |
RConsObligation* parentOb = d_parentOb[parent]; |
362 |
|
// proceed only if parent obligation is not already solved |
363 |
17 |
if (d_sol[parentOb->getSkolem()].isNull()) |
364 |
|
{ |
365 |
17 |
parentOb->addCandidateSolution(parentSol); |
366 |
17 |
d_sol[parentOb->getSkolem()] = parentSol; |
367 |
17 |
d_parentOb[parentSol] = parentOb; |
368 |
|
// repeat the same process for the parent obligation |
369 |
17 |
stack.push_back(parentOb); |
370 |
|
} |
371 |
|
} |
372 |
|
else |
373 |
|
{ |
374 |
|
// if it does have remaining children, add it to the watch list of one |
375 |
|
// of them (picked arbitrarily) |
376 |
3 |
d_subObs[parent].back()->addCandidateSolutionToWatchSet(parent); |
377 |
|
} |
378 |
|
} |
379 |
|
} |
380 |
|
} |
381 |
|
|
382 |
24 |
void SygusReconstruct::initialize(TypeNode stn) |
383 |
|
{ |
384 |
48 |
std::vector<Node> builtinVars; |
385 |
|
|
386 |
|
// Cache the sygus variables introduced by the problem (which we treat as |
387 |
|
// ground terms when calling the `match` method) as opposed to the sygus |
388 |
|
// variables introduced by the enumerators (which we treat as bound |
389 |
|
// variables). |
390 |
71 |
for (Node sv : stn.getDType().getSygusVarList()) |
391 |
|
{ |
392 |
47 |
builtinVars.push_back(datatypes::utils::sygusToBuiltin(sv)); |
393 |
47 |
d_sygusVars.emplace(datatypes::utils::sygusToBuiltin(sv), |
394 |
94 |
datatypes::utils::sygusToBuiltin(sv)); |
395 |
|
} |
396 |
|
|
397 |
48 |
SygusTypeInfo stnInfo; |
398 |
24 |
stnInfo.initialize(d_tds, stn); |
399 |
|
|
400 |
|
// find the non-terminals of the grammar |
401 |
48 |
std::vector<TypeNode> sfTypes; |
402 |
24 |
stnInfo.getSubfieldTypes(sfTypes); |
403 |
|
|
404 |
|
// initialize the enumerators and candidate rewrite databases. Notice here |
405 |
|
// that we treat the sygus variables introduced by the problem as bound |
406 |
|
// variables (needed for making sure that obligations are equal). This is fine |
407 |
|
// as we will never add variables that were introduced by the enumerators to |
408 |
|
// the database. |
409 |
77 |
for (TypeNode tn : sfTypes) |
410 |
|
{ |
411 |
53 |
d_stnInfo[tn].initialize(d_tds, d_stats, tn, builtinVars); |
412 |
|
} |
413 |
24 |
} |
414 |
|
|
415 |
9829 |
void SygusReconstruct::removeReconstructedTerms( |
416 |
|
TypeBuiltinSetMap& termsToRecons) |
417 |
|
{ |
418 |
20423 |
for (std::pair<const TypeNode, BuiltinSet>& pair : termsToRecons) |
419 |
|
{ |
420 |
10594 |
BuiltinSet::iterator it = pair.second.begin(); |
421 |
35896 |
while (it != pair.second.end()) |
422 |
|
{ |
423 |
12651 |
if (d_sol[d_stnInfo[pair.first].builtinToOb(*it)->getSkolem()].isNull()) |
424 |
|
{ |
425 |
12602 |
++it; |
426 |
|
} |
427 |
|
else |
428 |
|
{ |
429 |
49 |
it = pair.second.erase(it); |
430 |
|
} |
431 |
|
} |
432 |
|
} |
433 |
9829 |
} |
434 |
|
|
435 |
6 |
Node SygusReconstruct::mkGround(Node n) const |
436 |
|
{ |
437 |
|
// get the set of bound variables in n |
438 |
12 |
std::unordered_set<TNode> vars; |
439 |
6 |
expr::getVariables(n, vars); |
440 |
|
|
441 |
12 |
std::unordered_map<TNode, TNode> subs; |
442 |
|
|
443 |
|
// generate a ground value for each one of those variables |
444 |
12 |
for (const TNode& var : vars) |
445 |
|
{ |
446 |
6 |
subs.emplace(var, var.getType().mkGroundValue()); |
447 |
|
} |
448 |
|
|
449 |
|
// substitute the variables with ground values |
450 |
12 |
return n.substitute(subs); |
451 |
|
} |
452 |
|
|
453 |
4164 |
bool SygusReconstruct::notify(Node s, |
454 |
|
Node n, |
455 |
|
std::vector<Node>& vars, |
456 |
|
std::vector<Node>& subs) |
457 |
|
{ |
458 |
14076 |
for (size_t i = 0; i < vars.size(); ++i) |
459 |
|
{ |
460 |
|
// We consider sygus variables as ground terms. So, if they are not equal to |
461 |
|
// their substitution, then s is not matchable with n and we try the next |
462 |
|
// term s. Example: If s = (+ z x) and n = (+ z y), then s is not matchable |
463 |
|
// with n and we return true |
464 |
9996 |
if (d_sygusVars.find(vars[i]) != d_sygusVars.cend() && vars[i] != subs[i]) |
465 |
|
{ |
466 |
84 |
return true; |
467 |
|
} |
468 |
|
} |
469 |
|
// Note: false here means that we finally found an s that is matchable with n, |
470 |
|
// so we should not add n to the pool |
471 |
4080 |
return false; |
472 |
|
} |
473 |
|
|
474 |
24 |
void SygusReconstruct::clear() |
475 |
|
{ |
476 |
24 |
d_obs.clear(); |
477 |
24 |
d_stnInfo.clear(); |
478 |
24 |
d_sol.clear(); |
479 |
24 |
d_subObs.clear(); |
480 |
24 |
d_parentOb.clear(); |
481 |
24 |
d_sygusVars.clear(); |
482 |
24 |
d_poolTrie.clear(); |
483 |
24 |
} |
484 |
|
|
485 |
|
void SygusReconstruct::printPool( |
486 |
|
const std::unordered_map<TypeNode, std::vector<Node>>& pool) const |
487 |
|
{ |
488 |
|
Trace("sygus-rcons") << std::endl << "Pool:" << std::endl << '{'; |
489 |
|
|
490 |
|
for (const std::pair<const TypeNode, std::vector<Node>>& pair : pool) |
491 |
|
{ |
492 |
|
Trace("sygus-rcons") << std::endl |
493 |
|
<< " " << pair.first << ':' << std::endl |
494 |
|
<< " [" << std::endl; |
495 |
|
|
496 |
|
for (const Node& sygusTerm : pair.second) |
497 |
|
{ |
498 |
|
Trace("sygus-rcons") << " " |
499 |
|
<< Rewriter::rewrite( |
500 |
|
datatypes::utils::sygusToBuiltin(sygusTerm)) |
501 |
|
.toString() |
502 |
|
<< std::endl; |
503 |
|
} |
504 |
|
|
505 |
|
Trace("sygus-rcons") << " ]" << std::endl; |
506 |
|
} |
507 |
|
|
508 |
|
Trace("sygus-rcons") << '}' << std::endl; |
509 |
|
} |
510 |
|
|
511 |
|
} // namespace quantifiers |
512 |
|
} // namespace theory |
513 |
28191 |
} // namespace cvc5 |