1 |
|
/****************************************************************************** |
2 |
|
* Top contributors (to current version): |
3 |
|
* Andrew Reynolds, Haniel Barbosa, Abdalrhman Mohamed |
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_repair_const. |
14 |
|
*/ |
15 |
|
|
16 |
|
#include "theory/quantifiers/sygus/sygus_repair_const.h" |
17 |
|
|
18 |
|
#include "expr/dtype_cons.h" |
19 |
|
#include "expr/node_algorithm.h" |
20 |
|
#include "expr/skolem_manager.h" |
21 |
|
#include "options/base_options.h" |
22 |
|
#include "options/quantifiers_options.h" |
23 |
|
#include "printer/printer.h" |
24 |
|
#include "smt/smt_engine.h" |
25 |
|
#include "smt/smt_engine_scope.h" |
26 |
|
#include "smt/smt_statistics_registry.h" |
27 |
|
#include "theory/datatypes/theory_datatypes_utils.h" |
28 |
|
#include "theory/logic_info.h" |
29 |
|
#include "theory/quantifiers/cegqi/ceg_instantiator.h" |
30 |
|
#include "theory/quantifiers/sygus/sygus_grammar_norm.h" |
31 |
|
#include "theory/quantifiers/sygus/term_database_sygus.h" |
32 |
|
#include "theory/smt_engine_subsolver.h" |
33 |
|
|
34 |
|
using namespace cvc5::kind; |
35 |
|
|
36 |
|
namespace cvc5 { |
37 |
|
namespace theory { |
38 |
|
namespace quantifiers { |
39 |
|
|
40 |
1151 |
SygusRepairConst::SygusRepairConst(TermDbSygus* tds) |
41 |
1151 |
: d_tds(tds), d_allow_constant_grammar(false) |
42 |
|
{ |
43 |
1151 |
} |
44 |
|
|
45 |
8 |
void SygusRepairConst::initialize(Node base_inst, |
46 |
|
const std::vector<Node>& candidates) |
47 |
|
{ |
48 |
8 |
Trace("sygus-repair-const") << "SygusRepairConst::initialize" << std::endl; |
49 |
8 |
Trace("sygus-repair-const") << " conjecture : " << base_inst << std::endl; |
50 |
8 |
d_base_inst = base_inst; |
51 |
|
|
52 |
|
// compute whether there are "allow all constant" types in the variables of q |
53 |
16 |
std::map<TypeNode, bool> tprocessed; |
54 |
16 |
for (const Node& v : candidates) |
55 |
|
{ |
56 |
16 |
TypeNode tn = v.getType(); |
57 |
|
// do the type traversal of the sygus type |
58 |
8 |
registerSygusType(tn, tprocessed); |
59 |
|
} |
60 |
16 |
Trace("sygus-repair-const") |
61 |
8 |
<< " allow constants : " << d_allow_constant_grammar << std::endl; |
62 |
8 |
} |
63 |
|
|
64 |
|
// recursion depth bounded by number of types in grammar (small) |
65 |
105 |
void SygusRepairConst::registerSygusType(TypeNode tn, |
66 |
|
std::map<TypeNode, bool>& tprocessed) |
67 |
|
{ |
68 |
105 |
if (tprocessed.find(tn) == tprocessed.end()) |
69 |
|
{ |
70 |
30 |
tprocessed[tn] = true; |
71 |
30 |
if (!tn.isDatatype()) |
72 |
|
{ |
73 |
|
// may have recursed to a non-datatype, e.g. in the case that we have |
74 |
|
// "any constant" constructors |
75 |
10 |
return; |
76 |
|
} |
77 |
20 |
const DType& dt = tn.getDType(); |
78 |
20 |
if (!dt.isSygus()) |
79 |
|
{ |
80 |
|
// may have recursed to a non-sygus-datatype |
81 |
|
return; |
82 |
|
} |
83 |
|
// check if this datatype allows all constants |
84 |
20 |
if (dt.getSygusAllowConst()) |
85 |
|
{ |
86 |
16 |
d_allow_constant_grammar = true; |
87 |
|
} |
88 |
107 |
for (unsigned i = 0, ncons = dt.getNumConstructors(); i < ncons; i++) |
89 |
|
{ |
90 |
87 |
const DTypeConstructor& dtc = dt[i]; |
91 |
|
// recurse on all subfields |
92 |
184 |
for (unsigned j = 0, nargs = dtc.getNumArgs(); j < nargs; j++) |
93 |
|
{ |
94 |
194 |
TypeNode tnc = d_tds->getArgType(dtc, j); |
95 |
97 |
registerSygusType(tnc, tprocessed); |
96 |
|
} |
97 |
|
} |
98 |
|
} |
99 |
|
} |
100 |
|
|
101 |
135 |
bool SygusRepairConst::isActive() const |
102 |
|
{ |
103 |
135 |
return !d_base_inst.isNull() && d_allow_constant_grammar; |
104 |
|
} |
105 |
|
|
106 |
70 |
bool SygusRepairConst::repairSolution(const std::vector<Node>& candidates, |
107 |
|
const std::vector<Node>& candidate_values, |
108 |
|
std::vector<Node>& repair_cv, |
109 |
|
bool useConstantsAsHoles) |
110 |
|
{ |
111 |
140 |
return repairSolution(d_base_inst, |
112 |
|
candidates, |
113 |
|
candidate_values, |
114 |
|
repair_cv, |
115 |
140 |
useConstantsAsHoles); |
116 |
|
} |
117 |
|
|
118 |
135 |
bool SygusRepairConst::repairSolution(Node sygusBody, |
119 |
|
const std::vector<Node>& candidates, |
120 |
|
const std::vector<Node>& candidate_values, |
121 |
|
std::vector<Node>& repair_cv, |
122 |
|
bool useConstantsAsHoles) |
123 |
|
{ |
124 |
135 |
Assert(candidates.size() == candidate_values.size()); |
125 |
|
|
126 |
|
// if no grammar type allows constants, no repair is possible |
127 |
135 |
if (!isActive()) |
128 |
|
{ |
129 |
|
return false; |
130 |
|
} |
131 |
135 |
if (Trace.isOn("sygus-repair-const")) |
132 |
|
{ |
133 |
|
Trace("sygus-repair-const") << "Repair candidate solutions..." << std::endl; |
134 |
|
for (unsigned i = 0, size = candidates.size(); i < size; i++) |
135 |
|
{ |
136 |
|
std::stringstream ss; |
137 |
|
TermDbSygus::toStreamSygus(ss, candidate_values[i]); |
138 |
|
Trace("sygus-repair-const") |
139 |
|
<< " " << candidates[i] << " -> " << ss.str() << std::endl; |
140 |
|
} |
141 |
|
Trace("sygus-repair-const") |
142 |
|
<< "Getting candidate skeletons : " << std::endl; |
143 |
|
} |
144 |
270 |
std::vector<Node> candidate_skeletons; |
145 |
270 |
std::map<TypeNode, int> free_var_count; |
146 |
270 |
std::vector<Node> sk_vars; |
147 |
270 |
std::map<Node, Node> sk_vars_to_subs; |
148 |
270 |
for (unsigned i = 0, size = candidates.size(); i < size; i++) |
149 |
|
{ |
150 |
270 |
Node cv = candidate_values[i]; |
151 |
|
Node skeleton = getSkeleton( |
152 |
270 |
cv, free_var_count, sk_vars, sk_vars_to_subs, useConstantsAsHoles); |
153 |
135 |
if (Trace.isOn("sygus-repair-const")) |
154 |
|
{ |
155 |
|
std::stringstream ss; |
156 |
|
TermDbSygus::toStreamSygus(ss, cv); |
157 |
|
Trace("sygus-repair-const") |
158 |
|
<< "Solution #" << i << " : " << ss.str() << std::endl; |
159 |
|
if (skeleton == cv) |
160 |
|
{ |
161 |
|
Trace("sygus-repair-const") << "...solution unchanged" << std::endl; |
162 |
|
} |
163 |
|
else |
164 |
|
{ |
165 |
|
std::stringstream sss; |
166 |
|
TermDbSygus::toStreamSygus(sss, skeleton); |
167 |
|
Trace("sygus-repair-const") |
168 |
|
<< "...inferred skeleton : " << sss.str() << std::endl; |
169 |
|
} |
170 |
|
} |
171 |
135 |
candidate_skeletons.push_back(skeleton); |
172 |
|
} |
173 |
|
|
174 |
135 |
if (sk_vars.empty()) |
175 |
|
{ |
176 |
|
Trace("sygus-repair-const") << "...no solutions repaired." << std::endl; |
177 |
|
return false; |
178 |
|
} |
179 |
|
|
180 |
135 |
Trace("sygus-repair-const") << "Get first-order query..." << std::endl; |
181 |
|
Node fo_body = |
182 |
270 |
getFoQuery(sygusBody, candidates, candidate_skeletons, sk_vars); |
183 |
|
|
184 |
135 |
Trace("sygus-repair-const-debug") << "...got : " << fo_body << std::endl; |
185 |
|
|
186 |
135 |
if (d_queries.find(fo_body) != d_queries.end()) |
187 |
|
{ |
188 |
18 |
Trace("sygus-repair-const") << "...duplicate query." << std::endl; |
189 |
18 |
return false; |
190 |
|
} |
191 |
117 |
d_queries.insert(fo_body); |
192 |
|
|
193 |
|
// check whether it is not in the current logic, e.g. non-linear arithmetic. |
194 |
|
// if so, undo replacements until it is in the current logic. |
195 |
234 |
LogicInfo logic = smt::currentSmtEngine()->getLogicInfo(); |
196 |
117 |
if (logic.isTheoryEnabled(THEORY_ARITH) && logic.isLinear()) |
197 |
|
{ |
198 |
75 |
fo_body = fitToLogic(sygusBody, |
199 |
|
logic, |
200 |
|
fo_body, |
201 |
|
candidates, |
202 |
|
candidate_skeletons, |
203 |
|
sk_vars, |
204 |
|
sk_vars_to_subs); |
205 |
150 |
Trace("sygus-repair-const-debug") |
206 |
75 |
<< "...after fit-to-logic : " << fo_body << std::endl; |
207 |
|
} |
208 |
117 |
Assert(!expr::hasFreeVar(fo_body)); |
209 |
|
|
210 |
117 |
if (fo_body.isNull() || sk_vars.empty()) |
211 |
|
{ |
212 |
6 |
Trace("sygus-repair-const") |
213 |
3 |
<< "...all skeleton variables lead to bad logic." << std::endl; |
214 |
3 |
return false; |
215 |
|
} |
216 |
|
|
217 |
114 |
Trace("sygus-repair-const") << "Make satisfiabily query..." << std::endl; |
218 |
114 |
if (fo_body.getKind() == FORALL) |
219 |
|
{ |
220 |
|
// must be a CBQI quantifier |
221 |
53 |
CegHandledStatus hstatus = CegInstantiator::isCbqiQuant(fo_body); |
222 |
53 |
if (hstatus < CEG_HANDLED) |
223 |
|
{ |
224 |
|
// abort if less than fully handled |
225 |
|
Trace("sygus-repair-const") << "...first-order query is not handlable by " |
226 |
|
"counterexample-guided instantiation." |
227 |
|
<< std::endl; |
228 |
|
return false; |
229 |
|
} |
230 |
|
} |
231 |
|
|
232 |
114 |
Trace("sygus-engine") << "Repairing previous solution..." << std::endl; |
233 |
|
// make the satisfiability query |
234 |
228 |
std::unique_ptr<SmtEngine> repcChecker; |
235 |
|
// initialize the subsolver using the standard method |
236 |
228 |
initializeSubsolver( |
237 |
|
repcChecker, |
238 |
|
nullptr, |
239 |
114 |
Options::current().quantifiers.sygusRepairConstTimeoutWasSetByUser, |
240 |
|
options::sygusRepairConstTimeout()); |
241 |
|
// renable options disabled by sygus |
242 |
114 |
repcChecker->setOption("miniscope-quant", "true"); |
243 |
114 |
repcChecker->setOption("miniscope-quant-fv", "true"); |
244 |
114 |
repcChecker->setOption("quant-split", "true"); |
245 |
114 |
repcChecker->assertFormula(fo_body); |
246 |
|
// check satisfiability |
247 |
228 |
Result r = repcChecker->checkSat(); |
248 |
114 |
Trace("sygus-repair-const") << "...got : " << r << std::endl; |
249 |
342 |
if (r.asSatisfiabilityResult().isSat() == Result::UNSAT |
250 |
342 |
|| r.asSatisfiabilityResult().isUnknown()) |
251 |
|
{ |
252 |
100 |
Trace("sygus-engine") << "...failed" << std::endl; |
253 |
100 |
return false; |
254 |
|
} |
255 |
28 |
std::vector<Node> sk_sygus_m; |
256 |
35 |
for (const Node& v : sk_vars) |
257 |
|
{ |
258 |
21 |
Assert(d_sk_to_fo.find(v) != d_sk_to_fo.end()); |
259 |
42 |
Node fov = d_sk_to_fo[v]; |
260 |
42 |
Node fov_m = repcChecker->getValue(fov); |
261 |
21 |
Trace("sygus-repair-const") << " " << fov << " = " << fov_m << std::endl; |
262 |
|
// convert to sygus |
263 |
42 |
Node fov_m_to_sygus = d_tds->getProxyVariable(v.getType(), fov_m); |
264 |
21 |
sk_sygus_m.push_back(fov_m_to_sygus); |
265 |
|
} |
266 |
28 |
std::stringstream ss; |
267 |
|
// convert back to sygus |
268 |
28 |
for (unsigned i = 0, size = candidates.size(); i < size; i++) |
269 |
|
{ |
270 |
28 |
Node csk = candidate_skeletons[i]; |
271 |
|
Node scsk = csk.substitute( |
272 |
28 |
sk_vars.begin(), sk_vars.end(), sk_sygus_m.begin(), sk_sygus_m.end()); |
273 |
14 |
repair_cv.push_back(scsk); |
274 |
14 |
if (Trace.isOn("sygus-repair-const") || Trace.isOn("sygus-engine")) |
275 |
|
{ |
276 |
|
std::stringstream sss; |
277 |
|
TermDbSygus::toStreamSygus(sss, repair_cv[i]); |
278 |
|
ss << " * " << candidates[i] << " -> " << sss.str() << std::endl; |
279 |
|
} |
280 |
|
} |
281 |
14 |
Trace("sygus-engine") << "...success:" << std::endl; |
282 |
14 |
Trace("sygus-engine") << ss.str(); |
283 |
28 |
Trace("sygus-repair-const") |
284 |
14 |
<< "Repaired constants in solution : " << std::endl; |
285 |
14 |
Trace("sygus-repair-const") << ss.str(); |
286 |
14 |
return true; |
287 |
|
} |
288 |
|
|
289 |
110 |
bool SygusRepairConst::mustRepair(Node n) |
290 |
|
{ |
291 |
220 |
std::unordered_set<TNode> visited; |
292 |
220 |
std::vector<TNode> visit; |
293 |
220 |
TNode cur; |
294 |
110 |
visit.push_back(n); |
295 |
195 |
do |
296 |
|
{ |
297 |
305 |
cur = visit.back(); |
298 |
305 |
visit.pop_back(); |
299 |
305 |
if (visited.find(cur) == visited.end()) |
300 |
|
{ |
301 |
284 |
visited.insert(cur); |
302 |
284 |
Assert(cur.getKind() == APPLY_CONSTRUCTOR); |
303 |
284 |
if (isRepairable(cur, false)) |
304 |
|
{ |
305 |
70 |
return true; |
306 |
|
} |
307 |
521 |
for (const Node& cn : cur) |
308 |
|
{ |
309 |
307 |
visit.push_back(cn); |
310 |
|
} |
311 |
|
} |
312 |
235 |
} while (!visit.empty()); |
313 |
|
|
314 |
40 |
return false; |
315 |
|
} |
316 |
|
|
317 |
1070 |
bool SygusRepairConst::isRepairable(Node n, bool useConstantsAsHoles) |
318 |
|
{ |
319 |
1070 |
if (n.getKind() != APPLY_CONSTRUCTOR) |
320 |
|
{ |
321 |
158 |
return false; |
322 |
|
} |
323 |
1824 |
TypeNode tn = n.getType(); |
324 |
912 |
Assert(tn.isDatatype()); |
325 |
912 |
const DType& dt = tn.getDType(); |
326 |
912 |
if (!dt.isSygus()) |
327 |
|
{ |
328 |
|
return false; |
329 |
|
} |
330 |
1824 |
Node op = n.getOperator(); |
331 |
912 |
unsigned cindex = datatypes::utils::indexOf(op); |
332 |
1824 |
Node sygusOp = dt[cindex].getSygusOp(); |
333 |
912 |
if (sygusOp.getAttribute(SygusAnyConstAttribute())) |
334 |
|
{ |
335 |
|
// if it represents "any constant" then it is repairable |
336 |
261 |
return true; |
337 |
|
} |
338 |
651 |
if (dt[cindex].getNumArgs() > 0) |
339 |
|
{ |
340 |
302 |
return false; |
341 |
|
} |
342 |
349 |
if (useConstantsAsHoles && dt.getSygusAllowConst()) |
343 |
|
{ |
344 |
|
if (sygusOp.isConst()) |
345 |
|
{ |
346 |
|
// if a constant, it is repairable |
347 |
|
return true; |
348 |
|
} |
349 |
|
} |
350 |
349 |
return false; |
351 |
|
} |
352 |
|
|
353 |
135 |
Node SygusRepairConst::getSkeleton(Node n, |
354 |
|
std::map<TypeNode, int>& free_var_count, |
355 |
|
std::vector<Node>& sk_vars, |
356 |
|
std::map<Node, Node>& sk_vars_to_subs, |
357 |
|
bool useConstantsAsHoles) |
358 |
|
{ |
359 |
135 |
if (isRepairable(n, useConstantsAsHoles)) |
360 |
|
{ |
361 |
4 |
Node sk_var = d_tds->getFreeVarInc(n.getType(), free_var_count); |
362 |
2 |
sk_vars.push_back(sk_var); |
363 |
2 |
sk_vars_to_subs[sk_var] = n; |
364 |
4 |
Trace("sygus-repair-const-debug") |
365 |
2 |
<< "Var to subs : " << sk_var << " -> " << n << std::endl; |
366 |
2 |
return sk_var; |
367 |
|
} |
368 |
133 |
NodeManager* nm = NodeManager::currentNM(); |
369 |
|
// get the most general candidate skeleton of n |
370 |
266 |
std::unordered_map<TNode, Node> visited; |
371 |
133 |
std::unordered_map<TNode, Node>::iterator it; |
372 |
266 |
std::vector<TNode> visit; |
373 |
266 |
TNode cur; |
374 |
133 |
visit.push_back(n); |
375 |
1360 |
do |
376 |
|
{ |
377 |
1493 |
cur = visit.back(); |
378 |
1493 |
visit.pop_back(); |
379 |
1493 |
it = visited.find(cur); |
380 |
|
|
381 |
1493 |
if (it == visited.end()) |
382 |
|
{ |
383 |
709 |
visited[cur] = Node::null(); |
384 |
709 |
visit.push_back(cur); |
385 |
1360 |
for (const Node& cn : cur) |
386 |
|
{ |
387 |
651 |
visit.push_back(cn); |
388 |
|
} |
389 |
|
} |
390 |
784 |
else if (it->second.isNull()) |
391 |
|
{ |
392 |
1418 |
Node ret = cur; |
393 |
709 |
bool childChanged = false; |
394 |
1418 |
std::vector<Node> children; |
395 |
709 |
if (cur.getMetaKind() == kind::metakind::PARAMETERIZED) |
396 |
|
{ |
397 |
551 |
children.push_back(cur.getOperator()); |
398 |
|
} |
399 |
1360 |
for (const Node& cn : cur) |
400 |
|
{ |
401 |
1302 |
Node child; |
402 |
|
// if it is repairable |
403 |
651 |
if (isRepairable(cn, useConstantsAsHoles)) |
404 |
|
{ |
405 |
|
// replace it by the next free variable |
406 |
189 |
child = d_tds->getFreeVarInc(cn.getType(), free_var_count); |
407 |
189 |
sk_vars.push_back(child); |
408 |
189 |
sk_vars_to_subs[child] = cn; |
409 |
378 |
Trace("sygus-repair-const-debug") |
410 |
189 |
<< "Var to subs : " << child << " -> " << cn << std::endl; |
411 |
|
} |
412 |
|
else |
413 |
|
{ |
414 |
462 |
it = visited.find(cn); |
415 |
462 |
Assert(it != visited.end()); |
416 |
462 |
Assert(!it->second.isNull()); |
417 |
462 |
child = it->second; |
418 |
|
} |
419 |
651 |
childChanged = childChanged || cn != child; |
420 |
651 |
children.push_back(child); |
421 |
|
} |
422 |
709 |
if (childChanged) |
423 |
|
{ |
424 |
172 |
ret = nm->mkNode(cur.getKind(), children); |
425 |
|
} |
426 |
709 |
visited[cur] = ret; |
427 |
|
} |
428 |
1493 |
} while (!visit.empty()); |
429 |
133 |
Assert(visited.find(n) != visited.end()); |
430 |
133 |
Assert(!visited.find(n)->second.isNull()); |
431 |
133 |
return visited[n]; |
432 |
|
} |
433 |
|
|
434 |
138 |
Node SygusRepairConst::getFoQuery(Node body, |
435 |
|
const std::vector<Node>& candidates, |
436 |
|
const std::vector<Node>& candidate_skeletons, |
437 |
|
const std::vector<Node>& sk_vars) |
438 |
|
{ |
439 |
138 |
NodeManager* nm = NodeManager::currentNM(); |
440 |
138 |
SkolemManager* sm = nm->getSkolemManager(); |
441 |
138 |
Trace("sygus-repair-const") << " Substitute skeletons..." << std::endl; |
442 |
138 |
body = body.substitute(candidates.begin(), |
443 |
|
candidates.end(), |
444 |
|
candidate_skeletons.begin(), |
445 |
|
candidate_skeletons.end()); |
446 |
138 |
Trace("sygus-repair-const-debug") << " ...got : " << body << std::endl; |
447 |
|
|
448 |
138 |
Trace("sygus-repair-const") << " Unfold the specification..." << std::endl; |
449 |
138 |
body = d_tds->evaluateWithUnfolding(body); |
450 |
138 |
Trace("sygus-repair-const-debug") << " ...got : " << body << std::endl; |
451 |
|
|
452 |
138 |
Trace("sygus-repair-const") << " Introduce first-order vars..." << std::endl; |
453 |
333 |
for (const Node& v : sk_vars) |
454 |
|
{ |
455 |
195 |
std::map<Node, Node>::iterator itf = d_sk_to_fo.find(v); |
456 |
195 |
if (itf == d_sk_to_fo.end()) |
457 |
|
{ |
458 |
32 |
TypeNode builtinType = d_tds->sygusToBuiltinType(v.getType()); |
459 |
32 |
Node sk_fov = sm->mkDummySkolem("k", builtinType); |
460 |
16 |
d_sk_to_fo[v] = sk_fov; |
461 |
16 |
d_fo_to_sk[sk_fov] = v; |
462 |
32 |
Trace("sygus-repair-const-debug") |
463 |
16 |
<< "Map " << v << " -> " << sk_fov << std::endl; |
464 |
|
} |
465 |
|
} |
466 |
|
// now, we must replace all terms of the form eval( z_i, t1...tn ) with |
467 |
|
// a fresh first-order variable w_i, where z_i is a variable introduced in |
468 |
|
// the skeleton inference step (z_i is a variable in sk_vars). |
469 |
276 |
std::unordered_map<TNode, Node> visited; |
470 |
138 |
std::unordered_map<TNode, Node>::iterator it; |
471 |
276 |
std::vector<TNode> visit; |
472 |
276 |
TNode cur; |
473 |
138 |
visit.push_back(body); |
474 |
10583 |
do |
475 |
|
{ |
476 |
10721 |
cur = visit.back(); |
477 |
10721 |
visit.pop_back(); |
478 |
10721 |
it = visited.find(cur); |
479 |
|
|
480 |
10721 |
if (it == visited.end()) |
481 |
|
{ |
482 |
4883 |
visited[cur] = Node::null(); |
483 |
4883 |
if (cur.getKind() == DT_SYGUS_EVAL) |
484 |
|
{ |
485 |
1762 |
Node v = cur[0]; |
486 |
881 |
if (std::find(sk_vars.begin(), sk_vars.end(), v) != sk_vars.end()) |
487 |
|
{ |
488 |
881 |
std::map<Node, Node>::iterator itf = d_sk_to_fo.find(v); |
489 |
881 |
Assert(itf != d_sk_to_fo.end()); |
490 |
881 |
visited[cur] = itf->second; |
491 |
|
} |
492 |
|
} |
493 |
4883 |
if (visited[cur].isNull()) |
494 |
|
{ |
495 |
4002 |
visit.push_back(cur); |
496 |
10583 |
for (const Node& cn : cur) |
497 |
|
{ |
498 |
6581 |
visit.push_back(cn); |
499 |
|
} |
500 |
|
} |
501 |
|
} |
502 |
5838 |
else if (it->second.isNull()) |
503 |
|
{ |
504 |
8004 |
Node ret = cur; |
505 |
4002 |
bool childChanged = false; |
506 |
8004 |
std::vector<Node> children; |
507 |
4002 |
if (cur.getMetaKind() == kind::metakind::PARAMETERIZED) |
508 |
|
{ |
509 |
160 |
children.push_back(cur.getOperator()); |
510 |
|
} |
511 |
10583 |
for (const Node& cn : cur) |
512 |
|
{ |
513 |
6581 |
it = visited.find(cn); |
514 |
6581 |
Assert(it != visited.end()); |
515 |
6581 |
Assert(!it->second.isNull()); |
516 |
6581 |
childChanged = childChanged || cn != it->second; |
517 |
6581 |
children.push_back(it->second); |
518 |
|
} |
519 |
4002 |
if (childChanged) |
520 |
|
{ |
521 |
1794 |
ret = nm->mkNode(cur.getKind(), children); |
522 |
|
} |
523 |
4002 |
visited[cur] = ret; |
524 |
|
} |
525 |
10721 |
} while (!visit.empty()); |
526 |
138 |
Assert(visited.find(body) != visited.end()); |
527 |
138 |
Assert(!visited.find(body)->second.isNull()); |
528 |
138 |
Node fo_body = visited[body]; |
529 |
138 |
Trace("sygus-repair-const-debug") << " ...got : " << fo_body << std::endl; |
530 |
276 |
return fo_body; |
531 |
|
} |
532 |
|
|
533 |
75 |
Node SygusRepairConst::fitToLogic(Node body, |
534 |
|
LogicInfo& logic, |
535 |
|
Node n, |
536 |
|
const std::vector<Node>& candidates, |
537 |
|
std::vector<Node>& candidate_skeletons, |
538 |
|
std::vector<Node>& sk_vars, |
539 |
|
std::map<Node, Node>& sk_vars_to_subs) |
540 |
|
{ |
541 |
150 |
std::vector<Node> rm_var; |
542 |
150 |
Node exc_var; |
543 |
81 |
while (getFitToLogicExcludeVar(logic, n, exc_var)) |
544 |
|
{ |
545 |
75 |
if (exc_var.isNull()) |
546 |
|
{ |
547 |
72 |
return n; |
548 |
|
} |
549 |
6 |
Trace("sygus-repair-const") << "...exclude " << exc_var |
550 |
3 |
<< " due to logic restrictions." << std::endl; |
551 |
6 |
TNode tvar = exc_var; |
552 |
3 |
Assert(sk_vars_to_subs.find(exc_var) != sk_vars_to_subs.end()); |
553 |
6 |
TNode tsubs = sk_vars_to_subs[exc_var]; |
554 |
|
// revert the substitution |
555 |
6 |
for (unsigned i = 0, size = candidate_skeletons.size(); i < size; i++) |
556 |
|
{ |
557 |
3 |
candidate_skeletons[i] = candidate_skeletons[i].substitute(tvar, tsubs); |
558 |
|
} |
559 |
|
// remove the variable |
560 |
3 |
sk_vars_to_subs.erase(exc_var); |
561 |
|
std::vector<Node>::iterator it = |
562 |
3 |
std::find(sk_vars.begin(), sk_vars.end(), exc_var); |
563 |
3 |
Assert(it != sk_vars.end()); |
564 |
3 |
sk_vars.erase(it); |
565 |
|
// reconstruct the query |
566 |
3 |
n = getFoQuery(body, candidates, candidate_skeletons, sk_vars); |
567 |
|
// reset the exclusion variable |
568 |
3 |
exc_var = Node::null(); |
569 |
|
} |
570 |
3 |
return Node::null(); |
571 |
|
} |
572 |
|
|
573 |
78 |
bool SygusRepairConst::getFitToLogicExcludeVar(LogicInfo& logic, |
574 |
|
Node n, |
575 |
|
Node& exvar) |
576 |
|
{ |
577 |
78 |
bool restrictLA = logic.isTheoryEnabled(THEORY_ARITH) && logic.isLinear(); |
578 |
|
|
579 |
|
// should have at least one restriction |
580 |
78 |
Assert(restrictLA); |
581 |
|
|
582 |
156 |
std::unordered_set<TNode> visited; |
583 |
78 |
std::unordered_set<TNode>::iterator it; |
584 |
156 |
std::vector<TNode> visit; |
585 |
156 |
TNode cur; |
586 |
78 |
visit.push_back(n); |
587 |
3381 |
do |
588 |
|
{ |
589 |
3459 |
cur = visit.back(); |
590 |
3459 |
visit.pop_back(); |
591 |
3459 |
it = visited.find(cur); |
592 |
|
|
593 |
3459 |
if (it == visited.end()) |
594 |
|
{ |
595 |
2246 |
visited.insert(cur); |
596 |
2246 |
Kind ck = cur.getKind(); |
597 |
4492 |
bool isArithDivKind = (ck == DIVISION_TOTAL || ck == INTS_DIVISION_TOTAL |
598 |
4492 |
|| ck == INTS_MODULUS_TOTAL); |
599 |
2246 |
Assert(ck != DIVISION && ck != INTS_DIVISION && ck != INTS_MODULUS); |
600 |
2246 |
if (restrictLA && (ck == NONLINEAR_MULT || isArithDivKind)) |
601 |
|
{ |
602 |
15 |
for (unsigned j = 0, size = cur.getNumChildren(); j < size; j++) |
603 |
|
{ |
604 |
21 |
Node ccur = cur[j]; |
605 |
12 |
std::map<Node, Node>::iterator itf = d_fo_to_sk.find(ccur); |
606 |
12 |
if (itf != d_fo_to_sk.end()) |
607 |
|
{ |
608 |
3 |
if (ck == NONLINEAR_MULT || (isArithDivKind && j == 1)) |
609 |
|
{ |
610 |
3 |
exvar = itf->second; |
611 |
3 |
return true; |
612 |
|
} |
613 |
|
} |
614 |
|
} |
615 |
3 |
return false; |
616 |
|
} |
617 |
5684 |
for (const Node& ccur : cur) |
618 |
|
{ |
619 |
3444 |
visit.push_back(ccur); |
620 |
|
} |
621 |
|
} |
622 |
3453 |
} while (!visit.empty()); |
623 |
|
|
624 |
72 |
return true; |
625 |
|
} |
626 |
|
|
627 |
|
} // namespace quantifiers |
628 |
|
} // namespace theory |
629 |
29340 |
} // namespace cvc5 |