1 |
|
/****************************************************************************** |
2 |
|
* Top contributors (to current version): |
3 |
|
* Mathias Preiner, 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 |
|
* SyGuS instantiator class. |
14 |
|
*/ |
15 |
|
|
16 |
|
#include "theory/quantifiers/sygus_inst.h" |
17 |
|
|
18 |
|
#include <sstream> |
19 |
|
#include <unordered_set> |
20 |
|
|
21 |
|
#include "expr/node_algorithm.h" |
22 |
|
#include "expr/skolem_manager.h" |
23 |
|
#include "options/quantifiers_options.h" |
24 |
|
#include "theory/bv/theory_bv_utils.h" |
25 |
|
#include "theory/datatypes/sygus_datatype_utils.h" |
26 |
|
#include "theory/quantifiers/first_order_model.h" |
27 |
|
#include "theory/quantifiers/sygus/sygus_enumerator.h" |
28 |
|
#include "theory/quantifiers/sygus/sygus_grammar_cons.h" |
29 |
|
#include "theory/quantifiers/sygus/synth_engine.h" |
30 |
|
#include "theory/quantifiers/term_util.h" |
31 |
|
#include "theory/rewriter.h" |
32 |
|
|
33 |
|
namespace cvc5 { |
34 |
|
namespace theory { |
35 |
|
namespace quantifiers { |
36 |
|
|
37 |
|
namespace { |
38 |
|
|
39 |
|
/** |
40 |
|
* Collect maximal ground terms with type tn in node n. |
41 |
|
* |
42 |
|
* @param n: Node to traverse. |
43 |
|
* @param tn: Collects only terms with type tn. |
44 |
|
* @param terms: Collected terms. |
45 |
|
* @param cache: Caches visited nodes. |
46 |
|
* @param skip_quant: Do not traverse quantified formulas (skip quantifiers). |
47 |
|
*/ |
48 |
59 |
void getMaxGroundTerms(TNode n, |
49 |
|
TypeNode tn, |
50 |
|
std::unordered_set<Node>& terms, |
51 |
|
std::unordered_set<TNode>& cache, |
52 |
|
bool skip_quant = false) |
53 |
|
{ |
54 |
118 |
if (options::sygusInstTermSel() != options::SygusInstTermSelMode::MAX |
55 |
59 |
&& options::sygusInstTermSel() != options::SygusInstTermSelMode::BOTH) |
56 |
|
{ |
57 |
59 |
return; |
58 |
|
} |
59 |
|
|
60 |
|
Trace("sygus-inst-term") << "Find maximal terms with type " << tn |
61 |
|
<< " in: " << n << std::endl; |
62 |
|
|
63 |
|
Node cur; |
64 |
|
std::vector<TNode> visit; |
65 |
|
|
66 |
|
visit.push_back(n); |
67 |
|
do |
68 |
|
{ |
69 |
|
cur = visit.back(); |
70 |
|
visit.pop_back(); |
71 |
|
|
72 |
|
if (cache.find(cur) != cache.end()) |
73 |
|
{ |
74 |
|
continue; |
75 |
|
} |
76 |
|
cache.insert(cur); |
77 |
|
|
78 |
|
if (expr::hasBoundVar(cur) || cur.getType() != tn) |
79 |
|
{ |
80 |
|
if (!skip_quant || cur.getKind() != kind::FORALL) |
81 |
|
{ |
82 |
|
visit.insert(visit.end(), cur.begin(), cur.end()); |
83 |
|
} |
84 |
|
} |
85 |
|
else |
86 |
|
{ |
87 |
|
terms.insert(cur); |
88 |
|
Trace("sygus-inst-term") << " found: " << cur << std::endl; |
89 |
|
} |
90 |
|
} while (!visit.empty()); |
91 |
|
} |
92 |
|
|
93 |
|
/* |
94 |
|
* Collect minimal ground terms with type tn in node n. |
95 |
|
* |
96 |
|
* @param n: Node to traverse. |
97 |
|
* @param tn: Collects only terms with type tn. |
98 |
|
* @param terms: Collected terms. |
99 |
|
* @param cache: Caches visited nodes and flags indicating whether a minimal |
100 |
|
* term was already found in a subterm. |
101 |
|
* @param skip_quant: Do not traverse quantified formulas (skip quantifiers). |
102 |
|
*/ |
103 |
59 |
void getMinGroundTerms(TNode n, |
104 |
|
TypeNode tn, |
105 |
|
std::unordered_set<Node>& terms, |
106 |
|
std::unordered_map<TNode, std::pair<bool, bool>>& cache, |
107 |
|
bool skip_quant = false) |
108 |
|
{ |
109 |
118 |
if (options::sygusInstTermSel() != options::SygusInstTermSelMode::MIN |
110 |
59 |
&& options::sygusInstTermSel() != options::SygusInstTermSelMode::BOTH) |
111 |
|
{ |
112 |
|
return; |
113 |
|
} |
114 |
|
|
115 |
118 |
Trace("sygus-inst-term") << "Find minimal terms with type " << tn |
116 |
59 |
<< " in: " << n << std::endl; |
117 |
|
|
118 |
118 |
Node cur; |
119 |
118 |
std::vector<TNode> visit; |
120 |
|
|
121 |
59 |
visit.push_back(n); |
122 |
81474 |
do |
123 |
|
{ |
124 |
81533 |
cur = visit.back(); |
125 |
81533 |
visit.pop_back(); |
126 |
|
|
127 |
81533 |
auto it = cache.find(cur); |
128 |
81533 |
if (it == cache.end()) |
129 |
|
{ |
130 |
11710 |
cache.emplace(cur, std::make_pair(false, false)); |
131 |
5855 |
if (!skip_quant || cur.getKind() != kind::FORALL) |
132 |
|
{ |
133 |
5855 |
visit.push_back(cur); |
134 |
5855 |
visit.insert(visit.end(), cur.begin(), cur.end()); |
135 |
|
} |
136 |
|
} |
137 |
|
/* up-traversal */ |
138 |
75678 |
else if (!it->second.first) |
139 |
|
{ |
140 |
5855 |
bool found_min_term = false; |
141 |
|
|
142 |
|
/* Check if we found a minimal term in one of the children. */ |
143 |
25718 |
for (const Node& c : cur) |
144 |
|
{ |
145 |
23914 |
found_min_term |= cache[c].second; |
146 |
23914 |
if (found_min_term) break; |
147 |
|
} |
148 |
|
|
149 |
|
/* If we haven't found a minimal term yet, add this term if it has the |
150 |
|
* right type. */ |
151 |
5855 |
if (cur.getType() == tn && !expr::hasBoundVar(cur) && !found_min_term) |
152 |
|
{ |
153 |
229 |
terms.insert(cur); |
154 |
229 |
found_min_term = true; |
155 |
229 |
Trace("sygus-inst-term") << " found: " << cur << std::endl; |
156 |
|
} |
157 |
|
|
158 |
5855 |
it->second.first = true; |
159 |
5855 |
it->second.second = found_min_term; |
160 |
|
} |
161 |
81533 |
} while (!visit.empty()); |
162 |
|
} |
163 |
|
|
164 |
|
/* |
165 |
|
* Add special values for a given type. |
166 |
|
* |
167 |
|
* @param tn: The type node. |
168 |
|
* @param extra_cons: A map of TypeNode to constants, which are added in |
169 |
|
* addition to the default grammar. |
170 |
|
*/ |
171 |
143 |
void addSpecialValues(const TypeNode& tn, |
172 |
|
std::map<TypeNode, std::unordered_set<Node>>& extra_cons) |
173 |
|
{ |
174 |
143 |
if (tn.isBitVector()) |
175 |
|
{ |
176 |
6 |
uint32_t size = tn.getBitVectorSize(); |
177 |
6 |
extra_cons[tn].insert(bv::utils::mkOnes(size)); |
178 |
6 |
extra_cons[tn].insert(bv::utils::mkMinSigned(size)); |
179 |
6 |
extra_cons[tn].insert(bv::utils::mkMaxSigned(size)); |
180 |
|
} |
181 |
143 |
} |
182 |
|
|
183 |
|
} // namespace |
184 |
|
|
185 |
61 |
SygusInst::SygusInst(QuantifiersState& qs, |
186 |
|
QuantifiersInferenceManager& qim, |
187 |
|
QuantifiersRegistry& qr, |
188 |
61 |
TermRegistry& tr) |
189 |
|
: QuantifiersModule(qs, qim, qr, tr), |
190 |
61 |
d_ce_lemma_added(qs.getUserContext()), |
191 |
61 |
d_global_terms(qs.getUserContext()), |
192 |
183 |
d_notified_assertions(qs.getUserContext()) |
193 |
|
{ |
194 |
61 |
} |
195 |
|
|
196 |
675 |
bool SygusInst::needsCheck(Theory::Effort e) |
197 |
|
{ |
198 |
675 |
return e >= Theory::EFFORT_LAST_CALL; |
199 |
|
} |
200 |
|
|
201 |
189 |
QuantifiersModule::QEffort SygusInst::needsModel(Theory::Effort e) |
202 |
|
{ |
203 |
189 |
return QEFFORT_STANDARD; |
204 |
|
} |
205 |
|
|
206 |
189 |
void SygusInst::reset_round(Theory::Effort e) |
207 |
|
{ |
208 |
189 |
d_active_quant.clear(); |
209 |
189 |
d_inactive_quant.clear(); |
210 |
|
|
211 |
189 |
FirstOrderModel* model = d_treg.getModel(); |
212 |
189 |
uint32_t nasserted = model->getNumAssertedQuantifiers(); |
213 |
|
|
214 |
408 |
for (uint32_t i = 0; i < nasserted; ++i) |
215 |
|
{ |
216 |
438 |
Node q = model->getAssertedQuantifier(i); |
217 |
|
|
218 |
219 |
if (model->isQuantifierActive(q)) |
219 |
|
{ |
220 |
162 |
d_active_quant.insert(q); |
221 |
324 |
Node lit = getCeLiteral(q); |
222 |
|
|
223 |
|
bool value; |
224 |
162 |
if (d_qstate.getValuation().hasSatValue(lit, value)) |
225 |
|
{ |
226 |
162 |
if (!value) |
227 |
|
{ |
228 |
6 |
if (!d_qstate.getValuation().isDecision(lit)) |
229 |
|
{ |
230 |
6 |
model->setQuantifierActive(q, false); |
231 |
6 |
d_active_quant.erase(q); |
232 |
6 |
d_inactive_quant.insert(q); |
233 |
6 |
Trace("sygus-inst") << "Set inactive: " << q << std::endl; |
234 |
|
} |
235 |
|
} |
236 |
|
} |
237 |
|
} |
238 |
|
} |
239 |
189 |
} |
240 |
|
|
241 |
416 |
void SygusInst::check(Theory::Effort e, QEffort quant_e) |
242 |
|
{ |
243 |
416 |
Trace("sygus-inst") << "Check " << e << ", " << quant_e << std::endl; |
244 |
|
|
245 |
416 |
if (quant_e != QEFFORT_STANDARD) return; |
246 |
|
|
247 |
189 |
FirstOrderModel* model = d_treg.getModel(); |
248 |
189 |
Instantiate* inst = d_qim.getInstantiate(); |
249 |
189 |
TermDbSygus* db = d_treg.getTermDatabaseSygus(); |
250 |
378 |
SygusExplain syexplain(db); |
251 |
189 |
NodeManager* nm = NodeManager::currentNM(); |
252 |
189 |
options::SygusInstMode mode = options::sygusInstMode(); |
253 |
|
|
254 |
345 |
for (const Node& q : d_active_quant) |
255 |
|
{ |
256 |
156 |
const std::vector<Node>& inst_constants = d_inst_constants.at(q); |
257 |
156 |
const std::vector<Node>& dt_evals = d_var_eval.at(q); |
258 |
156 |
Assert(inst_constants.size() == dt_evals.size()); |
259 |
156 |
Assert(inst_constants.size() == q[0].getNumChildren()); |
260 |
|
|
261 |
312 |
std::vector<Node> terms, values, eval_unfold_lemmas; |
262 |
909 |
for (size_t i = 0, size = q[0].getNumChildren(); i < size; ++i) |
263 |
|
{ |
264 |
1506 |
Node dt_var = inst_constants[i]; |
265 |
1506 |
Node dt_eval = dt_evals[i]; |
266 |
1506 |
Node value = model->getValue(dt_var); |
267 |
1506 |
Node t = datatypes::utils::sygusToBuiltin(value); |
268 |
753 |
terms.push_back(t); |
269 |
753 |
values.push_back(value); |
270 |
|
|
271 |
1506 |
std::vector<Node> exp; |
272 |
753 |
syexplain.getExplanationForEquality(dt_var, value, exp); |
273 |
1506 |
Node lem; |
274 |
753 |
if (exp.empty()) |
275 |
|
{ |
276 |
|
lem = dt_eval.eqNode(t); |
277 |
|
} |
278 |
|
else |
279 |
|
{ |
280 |
2259 |
lem = nm->mkNode(kind::IMPLIES, |
281 |
1506 |
exp.size() == 1 ? exp[0] : nm->mkNode(kind::AND, exp), |
282 |
1506 |
dt_eval.eqNode(t)); |
283 |
|
} |
284 |
753 |
eval_unfold_lemmas.push_back(lem); |
285 |
|
} |
286 |
|
|
287 |
156 |
if (mode == options::SygusInstMode::PRIORITY_INST) |
288 |
|
{ |
289 |
312 |
if (!inst->addInstantiation(q, |
290 |
|
terms, |
291 |
|
InferenceId::QUANTIFIERS_INST_SYQI, |
292 |
312 |
nm->mkNode(kind::SEXPR, values))) |
293 |
|
{ |
294 |
89 |
sendEvalUnfoldLemmas(eval_unfold_lemmas); |
295 |
|
} |
296 |
|
} |
297 |
|
else if (mode == options::SygusInstMode::PRIORITY_EVAL) |
298 |
|
{ |
299 |
|
if (!sendEvalUnfoldLemmas(eval_unfold_lemmas)) |
300 |
|
{ |
301 |
|
inst->addInstantiation(q, |
302 |
|
terms, |
303 |
|
InferenceId::QUANTIFIERS_INST_SYQI, |
304 |
|
nm->mkNode(kind::SEXPR, values)); |
305 |
|
} |
306 |
|
} |
307 |
|
else |
308 |
|
{ |
309 |
|
Assert(mode == options::SygusInstMode::INTERLEAVE); |
310 |
|
inst->addInstantiation(q, |
311 |
|
terms, |
312 |
|
InferenceId::QUANTIFIERS_INST_SYQI, |
313 |
|
nm->mkNode(kind::SEXPR, values)); |
314 |
|
sendEvalUnfoldLemmas(eval_unfold_lemmas); |
315 |
|
} |
316 |
|
} |
317 |
|
} |
318 |
|
|
319 |
89 |
bool SygusInst::sendEvalUnfoldLemmas(const std::vector<Node>& lemmas) |
320 |
|
{ |
321 |
89 |
bool added_lemma = false; |
322 |
517 |
for (const Node& lem : lemmas) |
323 |
|
{ |
324 |
428 |
Trace("sygus-inst") << "Evaluation unfolding: " << lem << std::endl; |
325 |
428 |
added_lemma |= |
326 |
856 |
d_qim.addPendingLemma(lem, InferenceId::QUANTIFIERS_SYQI_EVAL_UNFOLD); |
327 |
|
} |
328 |
89 |
return added_lemma; |
329 |
|
} |
330 |
|
|
331 |
1 |
bool SygusInst::checkCompleteFor(Node q) |
332 |
|
{ |
333 |
1 |
return d_inactive_quant.find(q) != d_inactive_quant.end(); |
334 |
|
} |
335 |
|
|
336 |
53 |
void SygusInst::registerQuantifier(Node q) |
337 |
|
{ |
338 |
53 |
Assert(d_ce_lemmas.find(q) == d_ce_lemmas.end()); |
339 |
|
|
340 |
53 |
Trace("sygus-inst") << "Register " << q << std::endl; |
341 |
|
|
342 |
106 |
std::map<TypeNode, std::unordered_set<Node>> extra_cons; |
343 |
106 |
std::map<TypeNode, std::unordered_set<Node>> exclude_cons; |
344 |
106 |
std::map<TypeNode, std::unordered_set<Node>> include_cons; |
345 |
106 |
std::unordered_set<Node> term_irrelevant; |
346 |
|
|
347 |
|
/* Collect relevant local ground terms for each variable type. */ |
348 |
106 |
if (options::sygusInstScope() == options::SygusInstScope::IN |
349 |
53 |
|| options::sygusInstScope() == options::SygusInstScope::BOTH) |
350 |
|
{ |
351 |
106 |
std::unordered_map<TypeNode, std::unordered_set<Node>> relevant_terms; |
352 |
196 |
for (const Node& var : q[0]) |
353 |
|
{ |
354 |
286 |
TypeNode tn = var.getType(); |
355 |
|
|
356 |
|
/* Collect relevant ground terms for type tn. */ |
357 |
143 |
if (relevant_terms.find(tn) == relevant_terms.end()) |
358 |
|
{ |
359 |
118 |
std::unordered_set<Node> terms; |
360 |
118 |
std::unordered_set<TNode> cache_max; |
361 |
118 |
std::unordered_map<TNode, std::pair<bool, bool>> cache_min; |
362 |
|
|
363 |
59 |
getMinGroundTerms(q, tn, terms, cache_min); |
364 |
59 |
getMaxGroundTerms(q, tn, terms, cache_max); |
365 |
59 |
relevant_terms.emplace(tn, terms); |
366 |
|
} |
367 |
|
|
368 |
|
/* Add relevant ground terms to grammar. */ |
369 |
143 |
auto& terms = relevant_terms[tn]; |
370 |
714 |
for (const auto& t : terms) |
371 |
|
{ |
372 |
1142 |
TypeNode ttn = t.getType(); |
373 |
571 |
extra_cons[ttn].insert(t); |
374 |
571 |
Trace("sygus-inst") << "Adding (local) extra cons: " << t << std::endl; |
375 |
|
} |
376 |
|
} |
377 |
|
} |
378 |
|
|
379 |
|
/* Collect relevant global ground terms for each variable type. */ |
380 |
106 |
if (options::sygusInstScope() == options::SygusInstScope::OUT |
381 |
53 |
|| options::sygusInstScope() == options::SygusInstScope::BOTH) |
382 |
|
{ |
383 |
|
for (const Node& var : q[0]) |
384 |
|
{ |
385 |
|
TypeNode tn = var.getType(); |
386 |
|
|
387 |
|
/* Collect relevant ground terms for type tn. */ |
388 |
|
if (d_global_terms.find(tn) == d_global_terms.end()) |
389 |
|
{ |
390 |
|
std::unordered_set<Node> terms; |
391 |
|
std::unordered_set<TNode> cache_max; |
392 |
|
std::unordered_map<TNode, std::pair<bool, bool>> cache_min; |
393 |
|
|
394 |
|
for (const Node& a : d_notified_assertions) |
395 |
|
{ |
396 |
|
getMinGroundTerms(a, tn, terms, cache_min, true); |
397 |
|
getMaxGroundTerms(a, tn, terms, cache_max, true); |
398 |
|
} |
399 |
|
d_global_terms.insert(tn, terms); |
400 |
|
} |
401 |
|
|
402 |
|
/* Add relevant ground terms to grammar. */ |
403 |
|
auto it = d_global_terms.find(tn); |
404 |
|
if (it != d_global_terms.end()) |
405 |
|
{ |
406 |
|
for (const auto& t : (*it).second) |
407 |
|
{ |
408 |
|
TypeNode ttn = t.getType(); |
409 |
|
extra_cons[ttn].insert(t); |
410 |
|
Trace("sygus-inst") |
411 |
|
<< "Adding (global) extra cons: " << t << std::endl; |
412 |
|
} |
413 |
|
} |
414 |
|
} |
415 |
|
} |
416 |
|
|
417 |
|
/* Construct grammar for each bound variable of 'q'. */ |
418 |
53 |
Trace("sygus-inst") << "Process variables of " << q << std::endl; |
419 |
106 |
std::vector<TypeNode> types; |
420 |
196 |
for (const Node& var : q[0]) |
421 |
|
{ |
422 |
143 |
addSpecialValues(var.getType(), extra_cons); |
423 |
286 |
TypeNode tn = CegGrammarConstructor::mkSygusDefaultType(var.getType(), |
424 |
286 |
Node(), |
425 |
286 |
var.toString(), |
426 |
|
extra_cons, |
427 |
|
exclude_cons, |
428 |
|
include_cons, |
429 |
286 |
term_irrelevant); |
430 |
143 |
types.push_back(tn); |
431 |
|
|
432 |
286 |
Trace("sygus-inst") << "Construct (default) datatype for " << var |
433 |
143 |
<< std::endl |
434 |
143 |
<< tn << std::endl; |
435 |
|
} |
436 |
|
|
437 |
53 |
registerCeLemma(q, types); |
438 |
53 |
} |
439 |
|
|
440 |
|
/* Construct grammars for all bound variables of quantifier 'q'. Currently, |
441 |
|
* we use the default grammar of the variable's type. |
442 |
|
*/ |
443 |
53 |
void SygusInst::preRegisterQuantifier(Node q) |
444 |
|
{ |
445 |
53 |
Trace("sygus-inst") << "preRegister " << q << std::endl; |
446 |
53 |
addCeLemma(q); |
447 |
53 |
} |
448 |
|
|
449 |
65 |
void SygusInst::ppNotifyAssertions(const std::vector<Node>& assertions) |
450 |
|
{ |
451 |
233 |
for (const Node& a : assertions) |
452 |
|
{ |
453 |
168 |
d_notified_assertions.insert(a); |
454 |
|
} |
455 |
65 |
} |
456 |
|
|
457 |
|
/*****************************************************************************/ |
458 |
|
/* private methods */ |
459 |
|
/*****************************************************************************/ |
460 |
|
|
461 |
215 |
Node SygusInst::getCeLiteral(Node q) |
462 |
|
{ |
463 |
215 |
auto it = d_ce_lits.find(q); |
464 |
215 |
if (it != d_ce_lits.end()) |
465 |
|
{ |
466 |
162 |
return it->second; |
467 |
|
} |
468 |
|
|
469 |
53 |
NodeManager* nm = NodeManager::currentNM(); |
470 |
53 |
SkolemManager* sm = nm->getSkolemManager(); |
471 |
106 |
Node sk = sm->mkDummySkolem("CeLiteral", nm->booleanType()); |
472 |
106 |
Node lit = d_qstate.getValuation().ensureLiteral(sk); |
473 |
53 |
d_ce_lits[q] = lit; |
474 |
53 |
return lit; |
475 |
|
} |
476 |
|
|
477 |
53 |
void SygusInst::registerCeLemma(Node q, std::vector<TypeNode>& types) |
478 |
|
{ |
479 |
53 |
Assert(q[0].getNumChildren() == types.size()); |
480 |
53 |
Assert(d_ce_lemmas.find(q) == d_ce_lemmas.end()); |
481 |
53 |
Assert(d_inst_constants.find(q) == d_inst_constants.end()); |
482 |
53 |
Assert(d_var_eval.find(q) == d_var_eval.end()); |
483 |
|
|
484 |
53 |
Trace("sygus-inst") << "Register CE Lemma for " << q << std::endl; |
485 |
|
|
486 |
|
/* Generate counterexample lemma for 'q'. */ |
487 |
53 |
NodeManager* nm = NodeManager::currentNM(); |
488 |
53 |
TermDbSygus* db = d_treg.getTermDatabaseSygus(); |
489 |
|
|
490 |
|
/* For each variable x_i of \forall x_i . P[x_i], create a fresh datatype |
491 |
|
* instantiation constant ic_i with type types[i] and wrap each ic_i in |
492 |
|
* DT_SYGUS_EVAL(ic_i), which will be used to instantiate x_i. */ |
493 |
106 |
std::vector<Node> evals; |
494 |
106 |
std::vector<Node> inst_constants; |
495 |
196 |
for (size_t i = 0, size = types.size(); i < size; ++i) |
496 |
|
{ |
497 |
286 |
TypeNode tn = types[i]; |
498 |
286 |
TNode var = q[0][i]; |
499 |
|
|
500 |
|
/* Create the instantiation constant and set attribute accordingly. */ |
501 |
286 |
Node ic = nm->mkInstConstant(tn); |
502 |
|
InstConstantAttribute ica; |
503 |
143 |
ic.setAttribute(ica, q); |
504 |
143 |
Trace("sygus-inst") << "Create " << ic << " for " << var << std::endl; |
505 |
|
|
506 |
143 |
db->registerEnumerator(ic, ic, nullptr, ROLE_ENUM_MULTI_SOLUTION); |
507 |
|
|
508 |
286 |
std::vector<Node> args = {ic}; |
509 |
286 |
Node svl = tn.getDType().getSygusVarList(); |
510 |
143 |
if (!svl.isNull()) |
511 |
|
{ |
512 |
|
args.insert(args.end(), svl.begin(), svl.end()); |
513 |
|
} |
514 |
286 |
Node eval = nm->mkNode(kind::DT_SYGUS_EVAL, args); |
515 |
|
|
516 |
143 |
inst_constants.push_back(ic); |
517 |
143 |
evals.push_back(eval); |
518 |
|
} |
519 |
|
|
520 |
53 |
d_inst_constants.emplace(q, inst_constants); |
521 |
53 |
d_var_eval.emplace(q, evals); |
522 |
|
|
523 |
106 |
Node lit = getCeLiteral(q); |
524 |
53 |
d_qim.addPendingPhaseRequirement(lit, true); |
525 |
|
|
526 |
|
/* The decision strategy for quantified formula 'q' ensures that its |
527 |
|
* counterexample literal is decided on first. It is user-context dependent. |
528 |
|
*/ |
529 |
53 |
Assert(d_dstrat.find(q) == d_dstrat.end()); |
530 |
|
DecisionStrategy* ds = new DecisionStrategySingleton( |
531 |
53 |
"CeLiteral", lit, d_qstate.getSatContext(), d_qstate.getValuation()); |
532 |
|
|
533 |
53 |
d_dstrat[q].reset(ds); |
534 |
53 |
d_qim.getDecisionManager()->registerStrategy( |
535 |
|
DecisionManager::STRAT_QUANT_CEGQI_FEASIBLE, ds); |
536 |
|
|
537 |
|
/* Add counterexample lemma (lit => ~P[x_i/eval_i]) */ |
538 |
|
Node body = |
539 |
106 |
q[1].substitute(q[0].begin(), q[0].end(), evals.begin(), evals.end()); |
540 |
106 |
Node lem = nm->mkNode(kind::OR, lit.negate(), body.negate()); |
541 |
53 |
lem = Rewriter::rewrite(lem); |
542 |
|
|
543 |
53 |
d_ce_lemmas.emplace(std::make_pair(q, lem)); |
544 |
53 |
Trace("sygus-inst") << "Register CE Lemma: " << lem << std::endl; |
545 |
53 |
} |
546 |
|
|
547 |
53 |
void SygusInst::addCeLemma(Node q) |
548 |
|
{ |
549 |
53 |
Assert(d_ce_lemmas.find(q) != d_ce_lemmas.end()); |
550 |
|
|
551 |
|
/* Already added in previous contexts. */ |
552 |
53 |
if (d_ce_lemma_added.find(q) != d_ce_lemma_added.end()) return; |
553 |
|
|
554 |
106 |
Node lem = d_ce_lemmas[q]; |
555 |
53 |
d_qim.addPendingLemma(lem, InferenceId::QUANTIFIERS_SYQI_CEX); |
556 |
53 |
d_ce_lemma_added.insert(q); |
557 |
53 |
Trace("sygus-inst") << "Add CE Lemma: " << lem << std::endl; |
558 |
|
} |
559 |
|
|
560 |
|
} // namespace quantifiers |
561 |
|
} // namespace theory |
562 |
29502 |
} // namespace cvc5 |