1 |
|
/****************************************************************************** |
2 |
|
* Top contributors (to current version): |
3 |
|
* Andrew Reynolds, Piotr Trojanek, Mathias Preiner |
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 counterexample-guided quantifier instantiation. |
14 |
|
*/ |
15 |
|
|
16 |
|
#include "theory/quantifiers/cegqi/ceg_instantiator.h" |
17 |
|
|
18 |
|
#include "theory/quantifiers/cegqi/ceg_arith_instantiator.h" |
19 |
|
#include "theory/quantifiers/cegqi/ceg_bv_instantiator.h" |
20 |
|
#include "theory/quantifiers/cegqi/ceg_dt_instantiator.h" |
21 |
|
|
22 |
|
#include "expr/dtype.h" |
23 |
|
#include "expr/dtype_cons.h" |
24 |
|
#include "expr/node_algorithm.h" |
25 |
|
#include "options/quantifiers_options.h" |
26 |
|
#include "theory/arith/arith_msum.h" |
27 |
|
#include "theory/quantifiers/cegqi/inst_strategy_cegqi.h" |
28 |
|
#include "theory/quantifiers/first_order_model.h" |
29 |
|
#include "theory/quantifiers/quantifiers_attributes.h" |
30 |
|
#include "theory/quantifiers/quantifiers_state.h" |
31 |
|
#include "theory/quantifiers/term_database.h" |
32 |
|
#include "theory/quantifiers/term_util.h" |
33 |
|
#include "theory/rewriter.h" |
34 |
|
|
35 |
|
using namespace std; |
36 |
|
using namespace cvc5::kind; |
37 |
|
|
38 |
|
namespace cvc5 { |
39 |
|
namespace theory { |
40 |
|
namespace quantifiers { |
41 |
|
|
42 |
322 |
CegTermType mkStrictCTT(CegTermType c) |
43 |
|
{ |
44 |
322 |
Assert(!isStrictCTT(c)); |
45 |
322 |
if (c == CEG_TT_LOWER) |
46 |
|
{ |
47 |
214 |
return CEG_TT_LOWER_STRICT; |
48 |
|
} |
49 |
108 |
else if (c == CEG_TT_UPPER) |
50 |
|
{ |
51 |
108 |
return CEG_TT_UPPER_STRICT; |
52 |
|
} |
53 |
|
return c; |
54 |
|
} |
55 |
|
|
56 |
3304 |
CegTermType mkNegateCTT(CegTermType c) |
57 |
|
{ |
58 |
3304 |
if (c == CEG_TT_LOWER) |
59 |
|
{ |
60 |
933 |
return CEG_TT_UPPER; |
61 |
|
} |
62 |
2371 |
else if (c == CEG_TT_UPPER) |
63 |
|
{ |
64 |
2371 |
return CEG_TT_LOWER; |
65 |
|
} |
66 |
|
else if (c == CEG_TT_LOWER_STRICT) |
67 |
|
{ |
68 |
|
return CEG_TT_UPPER_STRICT; |
69 |
|
} |
70 |
|
else if (c == CEG_TT_UPPER_STRICT) |
71 |
|
{ |
72 |
|
return CEG_TT_LOWER_STRICT; |
73 |
|
} |
74 |
|
return c; |
75 |
|
} |
76 |
322 |
bool isStrictCTT(CegTermType c) |
77 |
|
{ |
78 |
322 |
return c == CEG_TT_LOWER_STRICT || c == CEG_TT_UPPER_STRICT; |
79 |
|
} |
80 |
|
bool isLowerBoundCTT(CegTermType c) |
81 |
|
{ |
82 |
|
return c == CEG_TT_LOWER || c == CEG_TT_LOWER_STRICT; |
83 |
|
} |
84 |
20563 |
bool isUpperBoundCTT(CegTermType c) |
85 |
|
{ |
86 |
20563 |
return c == CEG_TT_UPPER || c == CEG_TT_UPPER_STRICT; |
87 |
|
} |
88 |
|
|
89 |
|
std::ostream& operator<<(std::ostream& os, CegInstEffort e) |
90 |
|
{ |
91 |
|
switch (e) |
92 |
|
{ |
93 |
|
case CEG_INST_EFFORT_NONE: os << "?"; break; |
94 |
|
case CEG_INST_EFFORT_STANDARD: os << "STANDARD"; break; |
95 |
|
case CEG_INST_EFFORT_STANDARD_MV: os << "STANDARD_MV"; break; |
96 |
|
case CEG_INST_EFFORT_FULL: os << "FULL"; break; |
97 |
|
default: Unreachable(); |
98 |
|
} |
99 |
|
return os; |
100 |
|
} |
101 |
|
|
102 |
|
std::ostream& operator<<(std::ostream& os, CegInstPhase phase) |
103 |
|
{ |
104 |
|
switch (phase) |
105 |
|
{ |
106 |
|
case CEG_INST_PHASE_NONE: os << "?"; break; |
107 |
|
case CEG_INST_PHASE_EQC: os << "eqc"; break; |
108 |
|
case CEG_INST_PHASE_EQUAL: os << "eq"; break; |
109 |
|
case CEG_INST_PHASE_ASSERTION: os << "as"; break; |
110 |
|
case CEG_INST_PHASE_MVALUE: os << "mv"; break; |
111 |
|
default: Unreachable(); |
112 |
|
} |
113 |
|
return os; |
114 |
|
} |
115 |
|
std::ostream& operator<<(std::ostream& os, CegHandledStatus status) |
116 |
|
{ |
117 |
|
switch (status) |
118 |
|
{ |
119 |
|
case CEG_UNHANDLED: os << "unhandled"; break; |
120 |
|
case CEG_PARTIALLY_HANDLED: os << "partially_handled"; break; |
121 |
|
case CEG_HANDLED: os << "handled"; break; |
122 |
|
case CEG_HANDLED_UNCONDITIONAL: os << "handled_unc"; break; |
123 |
|
default: Unreachable(); |
124 |
|
} |
125 |
|
return os; |
126 |
|
} |
127 |
|
|
128 |
46 |
void TermProperties::composeProperty(TermProperties& p) |
129 |
|
{ |
130 |
46 |
if (p.d_coeff.isNull()) |
131 |
|
{ |
132 |
|
return; |
133 |
|
} |
134 |
46 |
if (d_coeff.isNull()) |
135 |
|
{ |
136 |
40 |
d_coeff = p.d_coeff; |
137 |
|
} |
138 |
|
else |
139 |
|
{ |
140 |
6 |
d_coeff = NodeManager::currentNM()->mkNode(MULT, d_coeff, p.d_coeff); |
141 |
6 |
d_coeff = Rewriter::rewrite(d_coeff); |
142 |
|
} |
143 |
|
} |
144 |
|
|
145 |
|
// push the substitution pv_prop.getModifiedTerm(pv) -> n |
146 |
45381 |
void SolvedForm::push_back(Node pv, Node n, TermProperties& pv_prop) |
147 |
|
{ |
148 |
45381 |
d_vars.push_back(pv); |
149 |
45381 |
d_subs.push_back(n); |
150 |
45381 |
d_props.push_back(pv_prop); |
151 |
45381 |
if (pv_prop.isBasic()) |
152 |
|
{ |
153 |
45177 |
return; |
154 |
|
} |
155 |
204 |
d_non_basic.push_back(pv); |
156 |
|
// update theta value |
157 |
408 |
Node new_theta = getTheta(); |
158 |
204 |
if (new_theta.isNull()) |
159 |
|
{ |
160 |
150 |
new_theta = pv_prop.d_coeff; |
161 |
|
} |
162 |
|
else |
163 |
|
{ |
164 |
54 |
new_theta = |
165 |
108 |
NodeManager::currentNM()->mkNode(MULT, new_theta, pv_prop.d_coeff); |
166 |
54 |
new_theta = Rewriter::rewrite(new_theta); |
167 |
|
} |
168 |
204 |
d_theta.push_back(new_theta); |
169 |
|
} |
170 |
|
// pop the substitution pv_prop.getModifiedTerm(pv) -> n |
171 |
9444 |
void SolvedForm::pop_back(Node pv, Node n, TermProperties& pv_prop) |
172 |
|
{ |
173 |
9444 |
d_vars.pop_back(); |
174 |
9444 |
d_subs.pop_back(); |
175 |
9444 |
d_props.pop_back(); |
176 |
9444 |
if (pv_prop.isBasic()) |
177 |
|
{ |
178 |
9399 |
return; |
179 |
|
} |
180 |
45 |
d_non_basic.pop_back(); |
181 |
|
// update theta value |
182 |
45 |
d_theta.pop_back(); |
183 |
|
} |
184 |
|
|
185 |
1623 |
CegInstantiator::CegInstantiator(Node q, |
186 |
|
QuantifiersState& qs, |
187 |
|
TermRegistry& tr, |
188 |
1623 |
InstStrategyCegqi* parent) |
189 |
|
: d_quant(q), |
190 |
|
d_qstate(qs), |
191 |
|
d_treg(tr), |
192 |
|
d_parent(parent), |
193 |
|
d_is_nested_quant(false), |
194 |
1623 |
d_effort(CEG_INST_EFFORT_NONE) |
195 |
|
{ |
196 |
1623 |
} |
197 |
|
|
198 |
4869 |
CegInstantiator::~CegInstantiator() { |
199 |
4681 |
for (std::pair<Node, Instantiator*> inst : d_instantiator) |
200 |
|
{ |
201 |
3058 |
delete inst.second; |
202 |
|
} |
203 |
2340 |
for (std::pair<TheoryId, InstantiatorPreprocess*> instp : d_tipp) |
204 |
|
{ |
205 |
717 |
delete instp.second; |
206 |
|
} |
207 |
3246 |
} |
208 |
|
|
209 |
3334308 |
void CegInstantiator::computeProgVars( Node n ){ |
210 |
3334308 |
if( d_prog_var.find( n )==d_prog_var.end() ){ |
211 |
58787 |
d_prog_var[n].clear(); |
212 |
58787 |
if (n.getKind() == kind::WITNESS) |
213 |
|
{ |
214 |
580 |
Assert(d_prog_var.find(n[0][0]) == d_prog_var.end()); |
215 |
580 |
d_prog_var[n[0][0]].clear(); |
216 |
|
} |
217 |
58787 |
if (d_vars_set.find(n) != d_vars_set.end()) |
218 |
|
{ |
219 |
2755 |
d_prog_var[n].insert(n); |
220 |
|
} |
221 |
56032 |
else if (!isEligibleForInstantiation(n)) |
222 |
|
{ |
223 |
2929 |
d_inelig.insert(n); |
224 |
2929 |
return; |
225 |
|
} |
226 |
135938 |
for( unsigned i=0; i<n.getNumChildren(); i++ ){ |
227 |
80080 |
computeProgVars( n[i] ); |
228 |
80080 |
if( d_inelig.find( n[i] )!=d_inelig.end() ){ |
229 |
11837 |
d_inelig.insert(n); |
230 |
|
} |
231 |
|
// all variables in child are contained in this |
232 |
80080 |
d_prog_var[n].insert(d_prog_var[n[i]].begin(), d_prog_var[n[i]].end()); |
233 |
|
} |
234 |
|
// selectors applied to program variables are also variables |
235 |
111716 |
if (n.getKind() == APPLY_SELECTOR_TOTAL |
236 |
111716 |
&& d_prog_var[n].find(n[0]) != d_prog_var[n].end()) |
237 |
|
{ |
238 |
42 |
d_prog_var[n].insert(n); |
239 |
|
} |
240 |
55858 |
if (n.getKind() == kind::WITNESS) |
241 |
|
{ |
242 |
580 |
d_prog_var.erase(n[0][0]); |
243 |
|
} |
244 |
|
} |
245 |
|
} |
246 |
|
|
247 |
955178 |
bool CegInstantiator::isEligible( Node n ) { |
248 |
|
//compute d_subs_fv, which program variables are contained in n, and determines if eligible |
249 |
955178 |
computeProgVars( n ); |
250 |
955178 |
return d_inelig.find( n )==d_inelig.end(); |
251 |
|
} |
252 |
|
|
253 |
50257 |
CegHandledStatus CegInstantiator::isCbqiKind(Kind k) |
254 |
|
{ |
255 |
126351 |
if (quantifiers::TermUtil::isBoolConnective(k) || k == PLUS || k == GEQ |
256 |
14037 |
|| k == EQUAL || k == MULT || k == NONLINEAR_MULT || k == DIVISION |
257 |
8635 |
|| k == DIVISION_TOTAL || k == INTS_DIVISION || k == INTS_DIVISION_TOTAL |
258 |
8499 |
|| k == INTS_MODULUS || k == INTS_MODULUS_TOTAL || k == TO_INTEGER |
259 |
58655 |
|| k == IS_INTEGER) |
260 |
|
{ |
261 |
41863 |
return CEG_HANDLED; |
262 |
|
} |
263 |
|
|
264 |
|
// CBQI typically works for satisfaction-complete theories |
265 |
8394 |
TheoryId t = kindToTheoryId(k); |
266 |
8394 |
if (t == THEORY_BV || t == THEORY_FP || t == THEORY_DATATYPES |
267 |
5751 |
|| t == THEORY_BOOL) |
268 |
|
{ |
269 |
2643 |
return CEG_HANDLED; |
270 |
|
} |
271 |
5751 |
return CEG_UNHANDLED; |
272 |
|
} |
273 |
|
|
274 |
7424 |
CegHandledStatus CegInstantiator::isCbqiTerm(Node n) |
275 |
|
{ |
276 |
7424 |
CegHandledStatus ret = CEG_HANDLED; |
277 |
14848 |
std::unordered_set<TNode> visited; |
278 |
14848 |
std::vector<TNode> visit; |
279 |
14848 |
TNode cur; |
280 |
7424 |
visit.push_back(n); |
281 |
91430 |
do |
282 |
|
{ |
283 |
98854 |
cur = visit.back(); |
284 |
98854 |
visit.pop_back(); |
285 |
98854 |
if (visited.find(cur) == visited.end()) |
286 |
|
{ |
287 |
81796 |
visited.insert(cur); |
288 |
81796 |
if (cur.getKind() != BOUND_VARIABLE && TermUtil::hasBoundVarAttr(cur)) |
289 |
|
{ |
290 |
57997 |
if (cur.getKind() == FORALL || cur.getKind() == WITNESS) |
291 |
|
{ |
292 |
7740 |
visit.push_back(cur[1]); |
293 |
|
} |
294 |
|
else |
295 |
|
{ |
296 |
50257 |
CegHandledStatus curr = isCbqiKind(cur.getKind()); |
297 |
50257 |
if (curr < ret) |
298 |
|
{ |
299 |
5751 |
ret = curr; |
300 |
11502 |
Trace("cegqi-debug2") << "Non-cbqi kind : " << cur.getKind() |
301 |
5751 |
<< " in " << n << std::endl; |
302 |
5751 |
if (curr == CEG_UNHANDLED) |
303 |
|
{ |
304 |
5751 |
return CEG_UNHANDLED; |
305 |
|
} |
306 |
|
} |
307 |
140155 |
for (const Node& nc : cur) |
308 |
|
{ |
309 |
95649 |
visit.push_back(nc); |
310 |
|
} |
311 |
|
} |
312 |
|
} |
313 |
|
} |
314 |
93103 |
} while (!visit.empty()); |
315 |
1673 |
return ret; |
316 |
|
} |
317 |
|
|
318 |
24410 |
CegHandledStatus CegInstantiator::isCbqiSort(TypeNode tn) |
319 |
|
{ |
320 |
48820 |
std::map<TypeNode, CegHandledStatus> visited; |
321 |
48820 |
return isCbqiSort(tn, visited); |
322 |
|
} |
323 |
|
|
324 |
29281 |
CegHandledStatus CegInstantiator::isCbqiSort( |
325 |
|
TypeNode tn, std::map<TypeNode, CegHandledStatus>& visited) |
326 |
|
{ |
327 |
29281 |
std::map<TypeNode, CegHandledStatus>::iterator itv = visited.find(tn); |
328 |
29281 |
if (itv != visited.end()) |
329 |
|
{ |
330 |
2854 |
return itv->second; |
331 |
|
} |
332 |
26427 |
CegHandledStatus ret = CEG_UNHANDLED; |
333 |
68806 |
if (tn.isInteger() || tn.isReal() || tn.isBoolean() || tn.isBitVector() |
334 |
40176 |
|| tn.isFloatingPoint()) |
335 |
|
{ |
336 |
12691 |
ret = CEG_HANDLED; |
337 |
|
} |
338 |
13736 |
else if (tn.isDatatype()) |
339 |
|
{ |
340 |
|
// recursive calls to this datatype are handlable |
341 |
2167 |
visited[tn] = CEG_HANDLED; |
342 |
|
// we initialize to handled, we remain handled as long as all subfields |
343 |
|
// of this datatype are not unhandled. |
344 |
2167 |
ret = CEG_HANDLED; |
345 |
2167 |
const DType& dt = tn.getDType(); |
346 |
4538 |
for (unsigned i = 0, ncons = dt.getNumConstructors(); i < ncons; i++) |
347 |
|
{ |
348 |
|
// get the constructor type |
349 |
6138 |
TypeNode consType; |
350 |
3767 |
if (dt.isParametric()) |
351 |
|
{ |
352 |
|
// if parametric, must instantiate the argument types |
353 |
36 |
consType = dt[i].getSpecializedConstructorType(tn); |
354 |
|
} |
355 |
|
else |
356 |
|
{ |
357 |
3731 |
consType = dt[i].getConstructor().getType(); |
358 |
|
} |
359 |
7242 |
for (const TypeNode& crange : consType) |
360 |
|
{ |
361 |
4871 |
CegHandledStatus cret = isCbqiSort(crange, visited); |
362 |
4871 |
if (cret == CEG_UNHANDLED) |
363 |
|
{ |
364 |
2792 |
Trace("cegqi-debug2") |
365 |
1396 |
<< "Non-cbqi sort : " << tn << " due to " << crange << std::endl; |
366 |
1396 |
visited[tn] = CEG_UNHANDLED; |
367 |
1396 |
return CEG_UNHANDLED; |
368 |
|
} |
369 |
3475 |
else if (cret < ret) |
370 |
|
{ |
371 |
|
ret = cret; |
372 |
|
} |
373 |
|
} |
374 |
|
} |
375 |
|
} |
376 |
|
// sets, arrays, functions and others are not supported |
377 |
25031 |
visited[tn] = ret; |
378 |
25031 |
return ret; |
379 |
|
} |
380 |
|
|
381 |
18991 |
CegHandledStatus CegInstantiator::isCbqiQuantPrefix(Node q) |
382 |
|
{ |
383 |
18991 |
CegHandledStatus hmin = CEG_HANDLED_UNCONDITIONAL; |
384 |
31792 |
for (const Node& v : q[0]) |
385 |
|
{ |
386 |
37169 |
TypeNode tn = v.getType(); |
387 |
24368 |
CegHandledStatus handled = isCbqiSort(tn); |
388 |
24368 |
if (handled == CEG_UNHANDLED) |
389 |
|
{ |
390 |
11567 |
return CEG_UNHANDLED; |
391 |
|
} |
392 |
12801 |
else if (handled < hmin) |
393 |
|
{ |
394 |
7698 |
hmin = handled; |
395 |
|
} |
396 |
|
} |
397 |
7424 |
return hmin; |
398 |
|
} |
399 |
|
|
400 |
23535 |
CegHandledStatus CegInstantiator::isCbqiQuant(Node q) |
401 |
|
{ |
402 |
23535 |
Assert(q.getKind() == FORALL); |
403 |
|
// compute attributes |
404 |
47070 |
QAttributes qa; |
405 |
23535 |
QuantAttributes::computeQuantAttributes(q, qa); |
406 |
23535 |
if (qa.d_quant_elim) |
407 |
|
{ |
408 |
74 |
return CEG_HANDLED; |
409 |
|
} |
410 |
23461 |
if (qa.d_sygus) |
411 |
|
{ |
412 |
335 |
return CEG_UNHANDLED; |
413 |
|
} |
414 |
23126 |
Assert(!qa.d_quant_elim_partial); |
415 |
|
// if has an instantiation pattern, don't do it |
416 |
23126 |
if (q.getNumChildren() == 3) |
417 |
|
{ |
418 |
5995 |
for (const Node& pat : q[2]) |
419 |
|
{ |
420 |
5234 |
if (pat.getKind() == INST_PATTERN) |
421 |
|
{ |
422 |
4135 |
return CEG_UNHANDLED; |
423 |
|
} |
424 |
|
} |
425 |
|
} |
426 |
18991 |
CegHandledStatus ret = CEG_HANDLED; |
427 |
|
// if quantifier has a non-handled variable, then do not use cbqi |
428 |
18991 |
CegHandledStatus ncbqiv = CegInstantiator::isCbqiQuantPrefix(q); |
429 |
37982 |
Trace("cegqi-quant-debug") << "isCbqiQuantPrefix returned " << ncbqiv |
430 |
18991 |
<< std::endl; |
431 |
18991 |
if (ncbqiv == CEG_UNHANDLED) |
432 |
|
{ |
433 |
|
// unhandled variable type |
434 |
11567 |
ret = CEG_UNHANDLED; |
435 |
|
} |
436 |
|
else |
437 |
|
{ |
438 |
7424 |
CegHandledStatus cbqit = CegInstantiator::isCbqiTerm(q); |
439 |
7424 |
Trace("cegqi-quant-debug") << "isCbqiTerm returned " << cbqit << std::endl; |
440 |
7424 |
if (cbqit == CEG_UNHANDLED) |
441 |
|
{ |
442 |
5751 |
if (ncbqiv == CEG_HANDLED_UNCONDITIONAL) |
443 |
|
{ |
444 |
|
// all variables are fully handled, this implies this will be handlable |
445 |
|
// regardless of body (e.g. for EPR) |
446 |
|
// so, try but not exclusively |
447 |
|
ret = CEG_PARTIALLY_HANDLED; |
448 |
|
} |
449 |
|
else |
450 |
|
{ |
451 |
|
// cannot be handled |
452 |
5751 |
ret = CEG_UNHANDLED; |
453 |
|
} |
454 |
|
} |
455 |
1673 |
else if (cbqit == CEG_PARTIALLY_HANDLED) |
456 |
|
{ |
457 |
|
ret = CEG_PARTIALLY_HANDLED; |
458 |
|
} |
459 |
|
} |
460 |
18991 |
if (ret == CEG_UNHANDLED && options::cegqiAll()) |
461 |
|
{ |
462 |
|
// try but not exclusively |
463 |
17 |
ret = CEG_PARTIALLY_HANDLED; |
464 |
|
} |
465 |
18991 |
return ret; |
466 |
|
} |
467 |
|
|
468 |
426094 |
bool CegInstantiator::hasVariable( Node n, Node pv ) { |
469 |
426094 |
computeProgVars( n ); |
470 |
426094 |
return d_prog_var[n].find( pv )!=d_prog_var[n].end(); |
471 |
|
} |
472 |
|
|
473 |
41369 |
void CegInstantiator::activateInstantiationVariable(Node v, unsigned index) |
474 |
|
{ |
475 |
41369 |
if( d_instantiator.find( v )==d_instantiator.end() ){ |
476 |
6116 |
TypeNode tn = v.getType(); |
477 |
|
Instantiator * vinst; |
478 |
3058 |
if( tn.isReal() ){ |
479 |
1687 |
vinst = new ArithInstantiator(tn, d_parent->getVtsTermCache()); |
480 |
1371 |
}else if( tn.isDatatype() ){ |
481 |
42 |
vinst = new DtInstantiator(tn); |
482 |
1329 |
}else if( tn.isBitVector() ){ |
483 |
1110 |
vinst = new BvInstantiator(tn, d_parent->getBvInverter()); |
484 |
219 |
}else if( tn.isBoolean() ){ |
485 |
207 |
vinst = new ModelValueInstantiator(tn); |
486 |
|
}else{ |
487 |
|
//default |
488 |
12 |
vinst = new Instantiator(tn); |
489 |
|
} |
490 |
3058 |
d_instantiator[v] = vinst; |
491 |
|
} |
492 |
41369 |
d_curr_subs_proc[v].clear(); |
493 |
41369 |
d_curr_index[v] = index; |
494 |
41369 |
d_curr_iphase[v] = CEG_INST_PHASE_NONE; |
495 |
41369 |
} |
496 |
|
|
497 |
5432 |
void CegInstantiator::deactivateInstantiationVariable(Node v) |
498 |
|
{ |
499 |
5432 |
d_curr_subs_proc.erase(v); |
500 |
5432 |
d_curr_index.erase(v); |
501 |
5432 |
d_curr_iphase.erase(v); |
502 |
5432 |
} |
503 |
|
|
504 |
63633 |
bool CegInstantiator::hasTriedInstantiation(Node v) |
505 |
|
{ |
506 |
63633 |
return !d_curr_subs_proc[v].empty(); |
507 |
|
} |
508 |
|
|
509 |
4499 |
void CegInstantiator::registerTheoryIds(TypeNode tn, |
510 |
|
std::map<TypeNode, bool>& visited) |
511 |
|
{ |
512 |
4499 |
if (visited.find(tn) == visited.end()) |
513 |
|
{ |
514 |
4453 |
visited[tn] = true; |
515 |
4453 |
TheoryId tid = Theory::theoryOf(tn); |
516 |
4453 |
registerTheoryId(tid); |
517 |
4453 |
if (tn.isDatatype()) |
518 |
|
{ |
519 |
58 |
const DType& dt = tn.getDType(); |
520 |
150 |
for (unsigned i = 0; i < dt.getNumConstructors(); i++) |
521 |
|
{ |
522 |
194 |
for (unsigned j = 0; j < dt[i].getNumArgs(); j++) |
523 |
|
{ |
524 |
102 |
registerTheoryIds(dt[i].getArgType(j), visited); |
525 |
|
} |
526 |
|
} |
527 |
|
} |
528 |
|
} |
529 |
4499 |
} |
530 |
|
|
531 |
6076 |
void CegInstantiator::registerTheoryId(TheoryId tid) |
532 |
|
{ |
533 |
6076 |
if (std::find(d_tids.begin(), d_tids.end(), tid) == d_tids.end()) |
534 |
|
{ |
535 |
|
// setup any theory-specific preprocessors here |
536 |
3306 |
if (tid == THEORY_BV) |
537 |
|
{ |
538 |
717 |
d_tipp[tid] = new BvInstantiatorPreprocess; |
539 |
|
} |
540 |
3306 |
d_tids.push_back(tid); |
541 |
|
} |
542 |
6076 |
} |
543 |
|
|
544 |
4397 |
void CegInstantiator::registerVariable(Node v) |
545 |
|
{ |
546 |
4397 |
Assert(std::find(d_vars.begin(), d_vars.end(), v) == d_vars.end()); |
547 |
4397 |
d_vars.push_back(v); |
548 |
4397 |
d_vars_set.insert(v); |
549 |
8794 |
TypeNode vtn = v.getType(); |
550 |
8794 |
Trace("cegqi-proc-debug") << "Collect theory ids from type " << vtn << " of " |
551 |
4397 |
<< v << std::endl; |
552 |
|
// collect relevant theories for this variable |
553 |
8794 |
std::map<TypeNode, bool> visited; |
554 |
4397 |
registerTheoryIds(vtn, visited); |
555 |
4397 |
} |
556 |
|
|
557 |
51310 |
bool CegInstantiator::constructInstantiation(SolvedForm& sf, unsigned i) |
558 |
|
{ |
559 |
51310 |
if( i==d_vars.size() ){ |
560 |
|
//solved for all variables, now construct instantiation |
561 |
|
bool needsPostprocess = |
562 |
9941 |
sf.d_vars.size() > d_input_vars.size() || !d_var_order_index.empty(); |
563 |
19882 |
std::vector< Instantiator * > pp_inst; |
564 |
19882 |
std::map< Instantiator *, Node > pp_inst_to_var; |
565 |
62815 |
for( std::map< Node, Instantiator * >::iterator ita = d_active_instantiators.begin(); ita != d_active_instantiators.end(); ++ita ){ |
566 |
158622 |
if (ita->second->needsPostProcessInstantiationForVariable( |
567 |
105748 |
this, sf, ita->first, d_effort)) |
568 |
|
{ |
569 |
244 |
needsPostprocess = true; |
570 |
244 |
pp_inst_to_var[ ita->second ] = ita->first; |
571 |
|
} |
572 |
|
} |
573 |
9941 |
if( needsPostprocess ){ |
574 |
|
//must make copy so that backtracking reverts sf |
575 |
12526 |
SolvedForm sf_tmp = sf; |
576 |
6263 |
bool postProcessSuccess = true; |
577 |
6466 |
for( std::map< Instantiator *, Node >::iterator itp = pp_inst_to_var.begin(); itp != pp_inst_to_var.end(); ++itp ){ |
578 |
732 |
if (!itp->first->postProcessInstantiationForVariable( |
579 |
488 |
this, sf_tmp, itp->second, d_effort)) |
580 |
|
{ |
581 |
41 |
postProcessSuccess = false; |
582 |
41 |
break; |
583 |
|
} |
584 |
|
} |
585 |
6263 |
if( postProcessSuccess ){ |
586 |
6222 |
return doAddInstantiation(sf_tmp.d_vars, sf_tmp.d_subs); |
587 |
|
}else{ |
588 |
41 |
return false; |
589 |
|
} |
590 |
|
}else{ |
591 |
3678 |
return doAddInstantiation(sf.d_vars, sf.d_subs); |
592 |
|
} |
593 |
|
}else{ |
594 |
41369 |
bool is_sv = false; |
595 |
82738 |
Node pv; |
596 |
41369 |
if( d_stack_vars.empty() ){ |
597 |
41327 |
pv = d_vars[i]; |
598 |
|
}else{ |
599 |
42 |
pv = d_stack_vars.back(); |
600 |
42 |
is_sv = true; |
601 |
42 |
d_stack_vars.pop_back(); |
602 |
|
} |
603 |
41369 |
activateInstantiationVariable(pv, i); |
604 |
|
|
605 |
|
//get the instantiator object |
606 |
41369 |
Assert(d_instantiator.find(pv) != d_instantiator.end()); |
607 |
41369 |
Instantiator* vinst = d_instantiator[pv]; |
608 |
41369 |
Assert(vinst != NULL); |
609 |
41369 |
d_active_instantiators[pv] = vinst; |
610 |
41369 |
vinst->reset(this, sf, pv, d_effort); |
611 |
|
// if d_effort is full, we must choose at least one model value |
612 |
41369 |
if ((i + 1) < d_vars.size() || d_effort != CEG_INST_EFFORT_FULL) |
613 |
|
{ |
614 |
|
// First, try to construct an instantiation term for pv based on |
615 |
|
// equality and theory-specific instantiation techniques. |
616 |
40018 |
if (constructInstantiation(sf, vinst, pv)) |
617 |
|
{ |
618 |
26006 |
return true; |
619 |
|
} |
620 |
|
} |
621 |
|
// If the above call fails, resort to using value in model. We do so if: |
622 |
|
// - we have yet to try an instantiation this round (or we are trying |
623 |
|
// multiple instantiations, indicated by options::cegqiMultiInst), |
624 |
|
// - the instantiator uses model values at this effort or |
625 |
|
// if we are solving for a subfield of a datatype (is_sv), and |
626 |
|
// - the instantiator allows model values. |
627 |
45029 |
if ((options::cegqiMultiInst() || !hasTriedInstantiation(pv)) |
628 |
27768 |
&& (vinst->useModelValue(this, sf, pv, d_effort) || is_sv) |
629 |
42046 |
&& vinst->allowModelValue(this, sf, pv, d_effort)) |
630 |
|
{ |
631 |
12709 |
Node mv = getModelValue( pv ); |
632 |
12709 |
TermProperties pv_prop_m; |
633 |
11320 |
Trace("cegqi-inst-debug") << "[4] " << i << "...try model value " << mv << std::endl; |
634 |
11320 |
d_curr_iphase[pv] = CEG_INST_PHASE_MVALUE; |
635 |
11320 |
CegInstEffort prev = d_effort; |
636 |
11320 |
if (d_effort < CEG_INST_EFFORT_STANDARD_MV) |
637 |
|
{ |
638 |
|
// update the effort level to indicate we have used a model value |
639 |
2020 |
d_effort = CEG_INST_EFFORT_STANDARD_MV; |
640 |
|
} |
641 |
11320 |
if (constructInstantiationInc(pv, mv, pv_prop_m, sf)) |
642 |
|
{ |
643 |
9931 |
return true; |
644 |
|
} |
645 |
1389 |
d_effort = prev; |
646 |
|
} |
647 |
|
|
648 |
5432 |
Trace("cegqi-inst-debug") << "[No instantiation found for " << pv << "]" << std::endl; |
649 |
5432 |
if (is_sv) |
650 |
|
{ |
651 |
|
d_stack_vars.push_back( pv ); |
652 |
|
} |
653 |
5432 |
d_active_instantiators.erase( pv ); |
654 |
5432 |
deactivateInstantiationVariable(pv); |
655 |
5432 |
return false; |
656 |
|
} |
657 |
|
} |
658 |
|
|
659 |
40018 |
bool CegInstantiator::constructInstantiation(SolvedForm& sf, |
660 |
|
Instantiator* vinst, |
661 |
|
Node pv) |
662 |
|
{ |
663 |
80036 |
TypeNode pvtn = pv.getType(); |
664 |
80036 |
TypeNode pvtnb = pvtn.getBaseType(); |
665 |
80036 |
Node pvr = pv; |
666 |
40018 |
eq::EqualityEngine* ee = d_qstate.getEqualityEngine(); |
667 |
40018 |
if (ee->hasTerm(pv)) |
668 |
|
{ |
669 |
27686 |
pvr = ee->getRepresentative(pv); |
670 |
|
} |
671 |
80036 |
Trace("cegqi-inst-debug") << "[Find instantiation for " << pv |
672 |
40018 |
<< "], rep=" << pvr << ", instantiator is " |
673 |
40018 |
<< vinst->identify() << std::endl; |
674 |
80036 |
Node pv_value; |
675 |
40018 |
if (options::cegqiModel()) |
676 |
|
{ |
677 |
40018 |
pv_value = getModelValue(pv); |
678 |
40018 |
Trace("cegqi-bound2") << "...M( " << pv << " ) = " << pv_value << std::endl; |
679 |
|
} |
680 |
|
|
681 |
|
//[1] easy case : pv is in the equivalence class as another term not |
682 |
|
// containing pv |
683 |
40018 |
if (vinst->hasProcessEqualTerm(this, sf, pv, d_effort)) |
684 |
|
{ |
685 |
88 |
Trace("cegqi-inst-debug") |
686 |
44 |
<< "[1] try based on equivalence class." << std::endl; |
687 |
44 |
d_curr_iphase[pv] = CEG_INST_PHASE_EQC; |
688 |
44 |
std::map<Node, std::vector<Node> >::iterator it_eqc = d_curr_eqc.find(pvr); |
689 |
44 |
if (it_eqc != d_curr_eqc.end()) |
690 |
|
{ |
691 |
|
// std::vector< Node > eq_candidates; |
692 |
88 |
Trace("cegqi-inst-debug2") |
693 |
44 |
<< "...eqc has size " << it_eqc->second.size() << std::endl; |
694 |
124 |
for (const Node& n : it_eqc->second) |
695 |
|
{ |
696 |
91 |
if (n != pv) |
697 |
|
{ |
698 |
114 |
Trace("cegqi-inst-debug") |
699 |
57 |
<< "...try based on equal term " << n << std::endl; |
700 |
|
// must be an eligible term |
701 |
57 |
if (isEligible(n)) |
702 |
|
{ |
703 |
63 |
Node ns; |
704 |
|
// coefficient of pv in the equality we solve (null is 1) |
705 |
63 |
TermProperties pv_prop; |
706 |
37 |
bool proc = false; |
707 |
37 |
if (!d_prog_var[n].empty()) |
708 |
|
{ |
709 |
29 |
ns = applySubstitution(pvtn, n, sf, pv_prop, false); |
710 |
29 |
if (!ns.isNull()) |
711 |
|
{ |
712 |
29 |
computeProgVars(ns); |
713 |
|
// substituted version must be new and cannot contain pv |
714 |
29 |
proc = d_prog_var[ns].find(pv) == d_prog_var[ns].end(); |
715 |
|
} |
716 |
|
} |
717 |
|
else |
718 |
|
{ |
719 |
8 |
ns = n; |
720 |
8 |
proc = true; |
721 |
|
} |
722 |
37 |
if (proc) |
723 |
|
{ |
724 |
11 |
if (vinst->processEqualTerm(this, sf, pv, pv_prop, ns, d_effort)) |
725 |
|
{ |
726 |
11 |
return true; |
727 |
|
} |
728 |
|
else if (!options::cegqiMultiInst() && hasTriedInstantiation(pv)) |
729 |
|
{ |
730 |
|
return false; |
731 |
|
} |
732 |
|
// Do not consider more than one equal term, |
733 |
|
// this helps non-monotonic strategies that may encounter |
734 |
|
// duplicate instantiations. |
735 |
|
break; |
736 |
|
} |
737 |
|
} |
738 |
|
} |
739 |
|
} |
740 |
33 |
if (vinst->processEqualTerms(this, sf, pv, it_eqc->second, d_effort)) |
741 |
|
{ |
742 |
25 |
return true; |
743 |
|
} |
744 |
8 |
else if (!options::cegqiMultiInst() && hasTriedInstantiation(pv)) |
745 |
|
{ |
746 |
|
return false; |
747 |
|
} |
748 |
|
} |
749 |
|
else |
750 |
|
{ |
751 |
|
Trace("cegqi-inst-debug2") << "...eqc not found." << std::endl; |
752 |
|
} |
753 |
|
} |
754 |
|
|
755 |
|
//[2] : we can solve an equality for pv |
756 |
|
/// iterate over equivalence classes to find cases where we can solve for |
757 |
|
/// the variable |
758 |
39982 |
if (vinst->hasProcessEquality(this, sf, pv, d_effort)) |
759 |
|
{ |
760 |
56634 |
Trace("cegqi-inst-debug") |
761 |
28317 |
<< "[2] try based on solving equalities." << std::endl; |
762 |
28317 |
d_curr_iphase[pv] = CEG_INST_PHASE_EQUAL; |
763 |
28317 |
std::vector<Node>& cteqc = d_curr_type_eqc[pvtnb]; |
764 |
|
|
765 |
397654 |
for (const Node& r : cteqc) |
766 |
|
{ |
767 |
382307 |
std::map<Node, std::vector<Node> >::iterator it_reqc = d_curr_eqc.find(r); |
768 |
751644 |
std::vector<Node> lhs; |
769 |
751644 |
std::vector<bool> lhs_v; |
770 |
751644 |
std::vector<TermProperties> lhs_prop; |
771 |
382307 |
Assert(it_reqc != d_curr_eqc.end()); |
772 |
1287676 |
for (const Node& n : it_reqc->second) |
773 |
|
{ |
774 |
918339 |
Trace("cegqi-inst-debug2") << "...look at term " << n << std::endl; |
775 |
|
// must be an eligible term |
776 |
918339 |
if (isEligible(n)) |
777 |
|
{ |
778 |
1481618 |
Node ns; |
779 |
1481618 |
TermProperties pv_prop; |
780 |
747294 |
if (!d_prog_var[n].empty()) |
781 |
|
{ |
782 |
668349 |
ns = applySubstitution(pvtn, n, sf, pv_prop); |
783 |
668349 |
if (!ns.isNull()) |
784 |
|
{ |
785 |
668331 |
computeProgVars(ns); |
786 |
|
} |
787 |
|
} |
788 |
|
else |
789 |
|
{ |
790 |
78945 |
ns = n; |
791 |
|
} |
792 |
747294 |
if (!ns.isNull()) |
793 |
|
{ |
794 |
747276 |
bool hasVar = d_prog_var[ns].find(pv) != d_prog_var[ns].end(); |
795 |
1494552 |
Trace("cegqi-inst-debug2") << "... " << ns << " has var " << pv |
796 |
747276 |
<< " : " << hasVar << std::endl; |
797 |
1481582 |
std::vector<TermProperties> term_props; |
798 |
1481582 |
std::vector<Node> terms; |
799 |
747276 |
term_props.push_back(pv_prop); |
800 |
747276 |
terms.push_back(ns); |
801 |
1494982 |
for (unsigned j = 0, size = lhs.size(); j < size; j++) |
802 |
|
{ |
803 |
|
// if this term or the another has pv in it, try to solve for it |
804 |
760676 |
if (hasVar || lhs_v[j]) |
805 |
|
{ |
806 |
110524 |
Trace("cegqi-inst-debug") << "......try based on equality " |
807 |
55262 |
<< lhs[j] << " = " << ns << std::endl; |
808 |
55262 |
term_props.push_back(lhs_prop[j]); |
809 |
55262 |
terms.push_back(lhs[j]); |
810 |
55262 |
if (vinst->processEquality( |
811 |
55262 |
this, sf, pv, term_props, terms, d_effort)) |
812 |
|
{ |
813 |
12194 |
return true; |
814 |
|
} |
815 |
43068 |
else if (!options::cegqiMultiInst() && hasTriedInstantiation(pv)) |
816 |
|
{ |
817 |
776 |
return false; |
818 |
|
} |
819 |
42292 |
term_props.pop_back(); |
820 |
42292 |
terms.pop_back(); |
821 |
|
} |
822 |
|
} |
823 |
734306 |
lhs.push_back(ns); |
824 |
734306 |
lhs_v.push_back(hasVar); |
825 |
734306 |
lhs_prop.push_back(pv_prop); |
826 |
|
} |
827 |
|
else |
828 |
|
{ |
829 |
36 |
Trace("cegqi-inst-debug2") |
830 |
18 |
<< "... term " << n << " is ineligible after substitution." |
831 |
18 |
<< std::endl; |
832 |
|
} |
833 |
|
} |
834 |
|
else |
835 |
|
{ |
836 |
342090 |
Trace("cegqi-inst-debug2") |
837 |
171045 |
<< "... term " << n << " is ineligible." << std::endl; |
838 |
|
} |
839 |
|
} |
840 |
|
} |
841 |
|
} |
842 |
|
//[3] directly look at assertions |
843 |
27012 |
if (!vinst->hasProcessAssertion(this, sf, pv, d_effort)) |
844 |
|
{ |
845 |
7224 |
return false; |
846 |
|
} |
847 |
19788 |
Trace("cegqi-inst-debug") << "[3] try based on assertions." << std::endl; |
848 |
19788 |
d_curr_iphase[pv] = CEG_INST_PHASE_ASSERTION; |
849 |
39576 |
std::unordered_set<Node> lits; |
850 |
59364 |
for (unsigned r = 0; r < 2; r++) |
851 |
|
{ |
852 |
39576 |
TheoryId tid = r == 0 ? Theory::theoryOf(pvtn) : THEORY_UF; |
853 |
39576 |
Trace("cegqi-inst-debug2") << " look at assertions of " << tid << std::endl; |
854 |
|
std::map<TheoryId, std::vector<Node> >::iterator ita = |
855 |
39576 |
d_curr_asserts.find(tid); |
856 |
39576 |
if (ita != d_curr_asserts.end()) |
857 |
|
{ |
858 |
474021 |
for (const Node& lit : ita->second) |
859 |
|
{ |
860 |
449415 |
if (lits.find(lit) == lits.end()) |
861 |
|
{ |
862 |
443470 |
lits.insert(lit); |
863 |
886940 |
Node plit; |
864 |
443470 |
if (options::cegqiRepeatLit() || !isSolvedAssertion(lit)) |
865 |
|
{ |
866 |
437804 |
plit = vinst->hasProcessAssertion(this, sf, pv, lit, d_effort); |
867 |
|
} |
868 |
443470 |
if (!plit.isNull()) |
869 |
|
{ |
870 |
426199 |
Trace("cegqi-inst-debug2") << " look at " << lit; |
871 |
426199 |
if (plit != lit) |
872 |
|
{ |
873 |
8793 |
Trace("cegqi-inst-debug2") << "...processed to : " << plit; |
874 |
|
} |
875 |
426199 |
Trace("cegqi-inst-debug2") << std::endl; |
876 |
|
// apply substitutions |
877 |
852398 |
Node slit = applySubstitutionToLiteral(plit, sf); |
878 |
426199 |
if (!slit.isNull()) |
879 |
|
{ |
880 |
|
// check if contains pv |
881 |
426094 |
if (hasVariable(slit, pv)) |
882 |
|
{ |
883 |
37280 |
Trace("cegqi-inst-debug") |
884 |
18640 |
<< "...try based on literal " << slit << "," << std::endl; |
885 |
18640 |
Trace("cegqi-inst-debug") << "...from " << lit << std::endl; |
886 |
18640 |
if (vinst->processAssertion(this, sf, pv, slit, lit, d_effort)) |
887 |
|
{ |
888 |
|
return true; |
889 |
|
} |
890 |
18640 |
else if (!options::cegqiMultiInst() && hasTriedInstantiation(pv)) |
891 |
|
{ |
892 |
|
return false; |
893 |
|
} |
894 |
|
} |
895 |
|
} |
896 |
|
} |
897 |
|
} |
898 |
|
} |
899 |
|
} |
900 |
|
} |
901 |
19788 |
if (vinst->processAssertions(this, sf, pv, d_effort)) |
902 |
|
{ |
903 |
13776 |
return true; |
904 |
|
} |
905 |
6012 |
return false; |
906 |
|
} |
907 |
|
|
908 |
42 |
void CegInstantiator::pushStackVariable( Node v ) { |
909 |
42 |
d_stack_vars.push_back( v ); |
910 |
42 |
} |
911 |
|
|
912 |
|
void CegInstantiator::popStackVariable() { |
913 |
|
Assert(!d_stack_vars.empty()); |
914 |
|
d_stack_vars.pop_back(); |
915 |
|
} |
916 |
|
|
917 |
50170 |
bool CegInstantiator::constructInstantiationInc(Node pv, |
918 |
|
Node n, |
919 |
|
TermProperties& pv_prop, |
920 |
|
SolvedForm& sf, |
921 |
|
bool revertOnSuccess) |
922 |
|
{ |
923 |
100340 |
Node cnode = pv_prop.getCacheNode(); |
924 |
50170 |
if( d_curr_subs_proc[pv][n].find( cnode )==d_curr_subs_proc[pv][n].end() ){ |
925 |
45381 |
d_curr_subs_proc[pv][n][cnode] = true; |
926 |
45381 |
if( Trace.isOn("cegqi-inst-debug") ){ |
927 |
|
for( unsigned j=0; j<sf.d_subs.size(); j++ ){ |
928 |
|
Trace("cegqi-inst-debug") << " "; |
929 |
|
} |
930 |
|
Trace("cegqi-inst-debug") << sf.d_subs.size() << ": (" << d_curr_iphase[pv] |
931 |
|
<< ") "; |
932 |
|
Node mod_pv = pv_prop.getModifiedTerm( pv ); |
933 |
|
Trace("cegqi-inst-debug") << mod_pv << " -> " << n << std::endl; |
934 |
|
Assert(n.getType().isSubtypeOf(pv.getType())); |
935 |
|
} |
936 |
|
//must ensure variables have been computed for n |
937 |
45381 |
computeProgVars( n ); |
938 |
45381 |
Assert(d_inelig.find(n) == d_inelig.end()); |
939 |
|
|
940 |
|
//substitute into previous substitutions, when applicable |
941 |
90762 |
std::vector< Node > a_var; |
942 |
45381 |
a_var.push_back( pv ); |
943 |
90762 |
std::vector< Node > a_subs; |
944 |
45381 |
a_subs.push_back( n ); |
945 |
90762 |
std::vector< TermProperties > a_prop; |
946 |
45381 |
a_prop.push_back( pv_prop ); |
947 |
90762 |
std::vector< Node > a_non_basic; |
948 |
45381 |
if( !pv_prop.isBasic() ){ |
949 |
204 |
a_non_basic.push_back( pv ); |
950 |
|
} |
951 |
45381 |
bool success = true; |
952 |
90762 |
std::map< int, Node > prev_subs; |
953 |
90762 |
std::map< int, TermProperties > prev_prop; |
954 |
90762 |
std::map< int, Node > prev_sym_subs; |
955 |
90762 |
std::vector< Node > new_non_basic; |
956 |
45381 |
Trace("cegqi-inst-debug2") << "Applying substitutions to previous substitution terms..." << std::endl; |
957 |
838624 |
for( unsigned j=0; j<sf.d_subs.size(); j++ ){ |
958 |
793243 |
Trace("cegqi-inst-debug2") << " Apply for " << sf.d_subs[j] << std::endl; |
959 |
793243 |
Assert(d_prog_var.find(sf.d_subs[j]) != d_prog_var.end()); |
960 |
793243 |
if( d_prog_var[sf.d_subs[j]].find( pv )!=d_prog_var[sf.d_subs[j]].end() ){ |
961 |
31967 |
prev_subs[j] = sf.d_subs[j]; |
962 |
63934 |
TNode tv = pv; |
963 |
63934 |
TNode ts = n; |
964 |
63934 |
TermProperties a_pv_prop; |
965 |
63934 |
Node new_subs = applySubstitution( sf.d_vars[j].getType(), sf.d_subs[j], a_var, a_subs, a_prop, a_non_basic, a_pv_prop, true ); |
966 |
31967 |
if( !new_subs.isNull() ){ |
967 |
31967 |
sf.d_subs[j] = new_subs; |
968 |
|
// the substitution apply to this term resulted in a non-basic substitution relationship |
969 |
31967 |
if( !a_pv_prop.isBasic() ){ |
970 |
|
// we are processing: |
971 |
|
// sf.d_props[j].getModifiedTerm( sf.d_vars[j] ) = sf.d_subs[j] { pv_prop.getModifiedTerm( pv ) -> n } |
972 |
|
|
973 |
|
// based on the above substitution, we have: |
974 |
|
// x = sf.d_subs[j] { pv_prop.getModifiedTerm( pv ) -> n } |
975 |
|
// is equivalent to |
976 |
|
// a_pv_prop.getModifiedTerm( x ) = new_subs |
977 |
|
|
978 |
|
// thus we must compose substitutions: |
979 |
|
// a_pv_prop.getModifiedTerm( sf.d_props[j].getModifiedTerm( sf.d_vars[j] ) ) = new_subs |
980 |
|
|
981 |
46 |
prev_prop[j] = sf.d_props[j]; |
982 |
46 |
bool prev_basic = sf.d_props[j].isBasic(); |
983 |
|
|
984 |
|
// now compose the property |
985 |
46 |
sf.d_props[j].composeProperty( a_pv_prop ); |
986 |
|
|
987 |
|
// if previously was basic, becomes non-basic |
988 |
46 |
if( prev_basic && !sf.d_props[j].isBasic() ){ |
989 |
40 |
Assert(std::find(sf.d_non_basic.begin(), |
990 |
|
sf.d_non_basic.end(), |
991 |
|
sf.d_vars[j]) |
992 |
|
== sf.d_non_basic.end()); |
993 |
40 |
new_non_basic.push_back( sf.d_vars[j] ); |
994 |
40 |
sf.d_non_basic.push_back( sf.d_vars[j] ); |
995 |
|
} |
996 |
|
} |
997 |
31967 |
if( sf.d_subs[j]!=prev_subs[j] ){ |
998 |
31965 |
computeProgVars( sf.d_subs[j] ); |
999 |
31965 |
Assert(d_inelig.find(sf.d_subs[j]) == d_inelig.end()); |
1000 |
|
} |
1001 |
31967 |
Trace("cegqi-inst-debug2") << "Subs " << j << " " << sf.d_subs[j] << std::endl; |
1002 |
|
}else{ |
1003 |
|
Trace("cegqi-inst-debug2") << "...failed to apply substitution to " << sf.d_subs[j] << std::endl; |
1004 |
|
success = false; |
1005 |
|
break; |
1006 |
|
} |
1007 |
|
}else{ |
1008 |
761276 |
Trace("cegqi-inst-debug2") << "Skip " << j << " " << sf.d_subs[j] << std::endl; |
1009 |
|
} |
1010 |
|
} |
1011 |
45381 |
if( success ){ |
1012 |
45381 |
Trace("cegqi-inst-debug2") << "Adding to vectors..." << std::endl; |
1013 |
45381 |
sf.push_back( pv, n, pv_prop ); |
1014 |
45381 |
Trace("cegqi-inst-debug2") << "Recurse..." << std::endl; |
1015 |
45381 |
unsigned i = d_curr_index[pv]; |
1016 |
45381 |
success = constructInstantiation(sf, d_stack_vars.empty() ? i + 1 : i); |
1017 |
45381 |
if (!success || revertOnSuccess) |
1018 |
|
{ |
1019 |
9444 |
Trace("cegqi-inst-debug2") << "Removing from vectors..." << std::endl; |
1020 |
9444 |
sf.pop_back( pv, n, pv_prop ); |
1021 |
|
} |
1022 |
|
} |
1023 |
45381 |
if (success && !revertOnSuccess) |
1024 |
|
{ |
1025 |
35937 |
return true; |
1026 |
|
}else{ |
1027 |
9444 |
Trace("cegqi-inst-debug2") << "Revert substitutions..." << std::endl; |
1028 |
|
//revert substitution information |
1029 |
12036 |
for (std::map<int, Node>::iterator it = prev_subs.begin(); |
1030 |
12036 |
it != prev_subs.end(); |
1031 |
|
++it) |
1032 |
|
{ |
1033 |
2592 |
sf.d_subs[it->first] = it->second; |
1034 |
|
} |
1035 |
9444 |
for (std::map<int, TermProperties>::iterator it = prev_prop.begin(); |
1036 |
9444 |
it != prev_prop.end(); |
1037 |
|
++it) |
1038 |
|
{ |
1039 |
|
sf.d_props[it->first] = it->second; |
1040 |
|
} |
1041 |
9444 |
for( unsigned i=0; i<new_non_basic.size(); i++ ){ |
1042 |
|
sf.d_non_basic.pop_back(); |
1043 |
|
} |
1044 |
9444 |
return success; |
1045 |
|
} |
1046 |
|
}else{ |
1047 |
|
//already tried this substitution |
1048 |
4789 |
return false; |
1049 |
|
} |
1050 |
|
} |
1051 |
|
|
1052 |
9900 |
bool CegInstantiator::doAddInstantiation(std::vector<Node>& vars, |
1053 |
|
std::vector<Node>& subs) |
1054 |
|
{ |
1055 |
9900 |
if (vars.size() > d_input_vars.size() || !d_var_order_index.empty()) |
1056 |
|
{ |
1057 |
6222 |
Trace("cegqi-inst-debug") << "Reconstructing instantiations...." << std::endl; |
1058 |
12444 |
std::map< Node, Node > subs_map; |
1059 |
54427 |
for( unsigned i=0; i<subs.size(); i++ ){ |
1060 |
48205 |
subs_map[vars[i]] = subs[i]; |
1061 |
|
} |
1062 |
6222 |
subs.clear(); |
1063 |
33470 |
for (unsigned i = 0, size = d_input_vars.size(); i < size; ++i) |
1064 |
|
{ |
1065 |
27248 |
std::map<Node, Node>::iterator it = subs_map.find(d_input_vars[i]); |
1066 |
27248 |
Assert(it != subs_map.end()); |
1067 |
54496 |
Node n = it->second; |
1068 |
54496 |
Trace("cegqi-inst-debug") << " " << d_input_vars[i] << " -> " << n |
1069 |
27248 |
<< std::endl; |
1070 |
27248 |
Assert(n.getType().isSubtypeOf(d_input_vars[i].getType())); |
1071 |
27248 |
subs.push_back( n ); |
1072 |
|
} |
1073 |
|
} |
1074 |
9900 |
if (Trace.isOn("cegqi-inst")) |
1075 |
|
{ |
1076 |
|
Trace("cegqi-inst") << "Ceg Instantiator produced : " << std::endl; |
1077 |
|
for (unsigned i = 0, size = d_input_vars.size(); i < size; ++i) |
1078 |
|
{ |
1079 |
|
Node v = d_input_vars[i]; |
1080 |
|
Trace("cegqi-inst") << i << " (" << d_curr_iphase[v] << ") : " |
1081 |
|
<< v << " -> " << subs[i] << std::endl; |
1082 |
|
Assert(subs[i].getType().isSubtypeOf(v.getType())); |
1083 |
|
} |
1084 |
|
} |
1085 |
9900 |
Trace("cegqi-inst-debug") << "Do the instantiation...." << std::endl; |
1086 |
9900 |
return d_parent->doAddInstantiation(subs); |
1087 |
|
} |
1088 |
|
|
1089 |
56055 |
bool CegInstantiator::isEligibleForInstantiation(Node n) const |
1090 |
|
{ |
1091 |
56055 |
Kind nk = n.getKind(); |
1092 |
56055 |
if (nk != INST_CONSTANT && nk != SKOLEM && nk != BOOLEAN_TERM_VARIABLE) |
1093 |
|
{ |
1094 |
52486 |
return true; |
1095 |
|
} |
1096 |
3569 |
if (n.getAttribute(VirtualTermSkolemAttribute())) |
1097 |
|
{ |
1098 |
|
// virtual terms are allowed |
1099 |
79 |
return true; |
1100 |
|
} |
1101 |
|
// only legal if current quantified formula contains n |
1102 |
3490 |
return expr::hasSubterm(d_quant, n); |
1103 |
|
} |
1104 |
|
|
1105 |
1127250 |
bool CegInstantiator::canApplyBasicSubstitution( Node n, std::vector< Node >& non_basic ){ |
1106 |
1127250 |
Assert(d_prog_var.find(n) != d_prog_var.end()); |
1107 |
1127250 |
if( !non_basic.empty() ){ |
1108 |
11096 |
for (std::unordered_set<Node>::iterator it = d_prog_var[n].begin(); |
1109 |
11096 |
it != d_prog_var[n].end(); |
1110 |
|
++it) |
1111 |
|
{ |
1112 |
7776 |
if (std::find(non_basic.begin(), non_basic.end(), *it) != non_basic.end()) |
1113 |
|
{ |
1114 |
1899 |
return false; |
1115 |
|
} |
1116 |
|
} |
1117 |
|
} |
1118 |
1125351 |
return true; |
1119 |
|
} |
1120 |
|
|
1121 |
701051 |
Node CegInstantiator::applySubstitution( TypeNode tn, Node n, std::vector< Node >& vars, std::vector< Node >& subs, std::vector< TermProperties >& prop, |
1122 |
|
std::vector< Node >& non_basic, TermProperties& pv_prop, bool try_coeff ) { |
1123 |
701051 |
n = Rewriter::rewrite(n); |
1124 |
701051 |
computeProgVars( n ); |
1125 |
701051 |
bool is_basic = canApplyBasicSubstitution( n, non_basic ); |
1126 |
701051 |
if( Trace.isOn("sygus-si-apply-subs-debug") ){ |
1127 |
|
Trace("sygus-si-apply-subs-debug") << "is_basic = " << is_basic << " " << tn << std::endl; |
1128 |
|
for( unsigned i=0; i<subs.size(); i++ ){ |
1129 |
|
Trace("sygus-si-apply-subs-debug") << " " << vars[i] << " -> " << subs[i] << " types : " << vars[i].getType() << " -> " << subs[i].getType() << std::endl; |
1130 |
|
Assert(subs[i].getType().isSubtypeOf(vars[i].getType())); |
1131 |
|
} |
1132 |
|
} |
1133 |
701051 |
Node nret; |
1134 |
701051 |
if( is_basic ){ |
1135 |
699963 |
nret = n.substitute( vars.begin(), vars.end(), subs.begin(), subs.end() ); |
1136 |
|
}else{ |
1137 |
1088 |
if( !tn.isInteger() ){ |
1138 |
|
//can do basic substitution instead with divisions |
1139 |
1422 |
std::vector< Node > nvars; |
1140 |
1422 |
std::vector< Node > nsubs; |
1141 |
6208 |
for( unsigned i=0; i<vars.size(); i++ ){ |
1142 |
5497 |
if( !prop[i].d_coeff.isNull() ){ |
1143 |
2517 |
Assert(vars[i].getType().isInteger()); |
1144 |
2517 |
Assert(prop[i].d_coeff.isConst()); |
1145 |
5034 |
Node nn = NodeManager::currentNM()->mkNode( MULT, subs[i], NodeManager::currentNM()->mkConst( Rational(1)/prop[i].d_coeff.getConst<Rational>() ) ); |
1146 |
2517 |
nn = NodeManager::currentNM()->mkNode( kind::TO_INTEGER, nn ); |
1147 |
2517 |
nn = Rewriter::rewrite( nn ); |
1148 |
2517 |
nsubs.push_back( nn ); |
1149 |
|
}else{ |
1150 |
2980 |
nsubs.push_back( subs[i] ); |
1151 |
|
} |
1152 |
|
} |
1153 |
711 |
nret = n.substitute( vars.begin(), vars.end(), nsubs.begin(), nsubs.end() ); |
1154 |
377 |
}else if( try_coeff ){ |
1155 |
|
//must convert to monomial representation |
1156 |
754 |
std::map< Node, Node > msum; |
1157 |
377 |
if (ArithMSum::getMonomialSum(n, msum)) |
1158 |
|
{ |
1159 |
754 |
std::map< Node, Node > msum_coeff; |
1160 |
754 |
std::map< Node, Node > msum_term; |
1161 |
1706 |
for( std::map< Node, Node >::iterator it = msum.begin(); it != msum.end(); ++it ){ |
1162 |
|
//check if in substitution |
1163 |
1329 |
std::vector< Node >::iterator its = std::find( vars.begin(), vars.end(), it->first ); |
1164 |
1329 |
if( its!=vars.end() ){ |
1165 |
656 |
int index = its-vars.begin(); |
1166 |
656 |
if( prop[index].d_coeff.isNull() ){ |
1167 |
|
//apply substitution |
1168 |
288 |
msum_term[it->first] = subs[index]; |
1169 |
|
}else{ |
1170 |
|
//apply substitution, multiply to ensure no divisibility conflict |
1171 |
368 |
msum_term[it->first] = subs[index]; |
1172 |
|
//relative coefficient |
1173 |
368 |
msum_coeff[it->first] = prop[index].d_coeff; |
1174 |
368 |
if( pv_prop.d_coeff.isNull() ){ |
1175 |
359 |
pv_prop.d_coeff = prop[index].d_coeff; |
1176 |
|
}else{ |
1177 |
9 |
pv_prop.d_coeff = NodeManager::currentNM()->mkNode( MULT, pv_prop.d_coeff, prop[index].d_coeff ); |
1178 |
|
} |
1179 |
|
} |
1180 |
|
}else{ |
1181 |
673 |
msum_term[it->first] = it->first; |
1182 |
|
} |
1183 |
|
} |
1184 |
|
//make sum with normalized coefficient |
1185 |
377 |
if( !pv_prop.d_coeff.isNull() ){ |
1186 |
359 |
pv_prop.d_coeff = Rewriter::rewrite( pv_prop.d_coeff ); |
1187 |
359 |
Trace("sygus-si-apply-subs-debug") << "Combined coeff : " << pv_prop.d_coeff << std::endl; |
1188 |
718 |
std::vector< Node > children; |
1189 |
1652 |
for( std::map< Node, Node >::iterator it = msum.begin(); it != msum.end(); ++it ){ |
1190 |
2586 |
Node c_coeff; |
1191 |
1293 |
if( !msum_coeff[it->first].isNull() ){ |
1192 |
368 |
c_coeff = Rewriter::rewrite( NodeManager::currentNM()->mkConst( pv_prop.d_coeff.getConst<Rational>() / msum_coeff[it->first].getConst<Rational>() ) ); |
1193 |
|
}else{ |
1194 |
925 |
c_coeff = pv_prop.d_coeff; |
1195 |
|
} |
1196 |
1293 |
if( !it->second.isNull() ){ |
1197 |
1008 |
c_coeff = NodeManager::currentNM()->mkNode( MULT, c_coeff, it->second ); |
1198 |
|
} |
1199 |
1293 |
Assert(!c_coeff.isNull()); |
1200 |
2586 |
Node c; |
1201 |
1293 |
if( msum_term[it->first].isNull() ){ |
1202 |
73 |
c = c_coeff; |
1203 |
|
}else{ |
1204 |
1220 |
c = NodeManager::currentNM()->mkNode( MULT, c_coeff, msum_term[it->first] ); |
1205 |
|
} |
1206 |
1293 |
children.push_back( c ); |
1207 |
1293 |
Trace("sygus-si-apply-subs-debug") << "Add child : " << c << std::endl; |
1208 |
|
} |
1209 |
718 |
Node nretc = children.size()==1 ? children[0] : NodeManager::currentNM()->mkNode( PLUS, children ); |
1210 |
359 |
nretc = Rewriter::rewrite( nretc ); |
1211 |
|
//ensure that nret does not contain vars |
1212 |
359 |
if (!expr::hasSubterm(nretc, vars)) |
1213 |
|
{ |
1214 |
|
//result is ( nret / pv_prop.d_coeff ) |
1215 |
359 |
nret = nretc; |
1216 |
|
}else{ |
1217 |
|
Trace("sygus-si-apply-subs-debug") << "Failed, since result " << nretc << " contains free variable." << std::endl; |
1218 |
|
} |
1219 |
|
}else{ |
1220 |
|
//implies that we have a monomial that has a free variable |
1221 |
18 |
Trace("sygus-si-apply-subs-debug") << "Failed to find coefficient during substitution, implies monomial with free variable." << std::endl; |
1222 |
|
} |
1223 |
|
}else{ |
1224 |
|
Trace("sygus-si-apply-subs-debug") << "Failed to find monomial sum " << n << std::endl; |
1225 |
|
} |
1226 |
|
} |
1227 |
|
} |
1228 |
701051 |
if( n!=nret && !nret.isNull() ){ |
1229 |
348792 |
nret = Rewriter::rewrite( nret ); |
1230 |
|
} |
1231 |
701051 |
return nret; |
1232 |
|
} |
1233 |
|
|
1234 |
426199 |
Node CegInstantiator::applySubstitutionToLiteral( Node lit, std::vector< Node >& vars, std::vector< Node >& subs, |
1235 |
|
std::vector< TermProperties >& prop, std::vector< Node >& non_basic ) { |
1236 |
426199 |
computeProgVars( lit ); |
1237 |
426199 |
bool is_basic = canApplyBasicSubstitution( lit, non_basic ); |
1238 |
426199 |
Node lret; |
1239 |
426199 |
if( is_basic ){ |
1240 |
425388 |
lret = lit.substitute( vars.begin(), vars.end(), subs.begin(), subs.end() ); |
1241 |
|
}else{ |
1242 |
1622 |
Node atom = lit.getKind()==NOT ? lit[0] : lit; |
1243 |
811 |
bool pol = lit.getKind()!=NOT; |
1244 |
|
//arithmetic inequalities and disequalities |
1245 |
811 |
if( atom.getKind()==GEQ || ( atom.getKind()==EQUAL && !pol && atom[0].getType().isReal() ) ){ |
1246 |
706 |
NodeManager* nm = NodeManager::currentNM(); |
1247 |
706 |
Assert(atom.getKind() != GEQ || atom[1].isConst()); |
1248 |
1412 |
Node atom_lhs; |
1249 |
1412 |
Node atom_rhs; |
1250 |
706 |
if( atom.getKind()==GEQ ){ |
1251 |
675 |
atom_lhs = atom[0]; |
1252 |
675 |
atom_rhs = atom[1]; |
1253 |
|
}else{ |
1254 |
31 |
atom_lhs = nm->mkNode(MINUS, atom[0], atom[1]); |
1255 |
31 |
atom_lhs = Rewriter::rewrite( atom_lhs ); |
1256 |
31 |
atom_rhs = nm->mkConst(Rational(0)); |
1257 |
|
} |
1258 |
|
//must be an eligible term |
1259 |
706 |
if( isEligible( atom_lhs ) ){ |
1260 |
|
//apply substitution to LHS of atom |
1261 |
1412 |
TermProperties atom_lhs_prop; |
1262 |
706 |
atom_lhs = applySubstitution(nm->realType(), |
1263 |
|
atom_lhs, |
1264 |
|
vars, |
1265 |
|
subs, |
1266 |
|
prop, |
1267 |
|
non_basic, |
1268 |
|
atom_lhs_prop); |
1269 |
706 |
if( !atom_lhs.isNull() ){ |
1270 |
706 |
if( !atom_lhs_prop.d_coeff.isNull() ){ |
1271 |
|
atom_rhs = nm->mkNode(MULT, atom_lhs_prop.d_coeff, atom_rhs); |
1272 |
|
atom_rhs = Rewriter::rewrite(atom_rhs); |
1273 |
|
} |
1274 |
706 |
lret = nm->mkNode(atom.getKind(), atom_lhs, atom_rhs); |
1275 |
706 |
if( !pol ){ |
1276 |
376 |
lret = lret.negate(); |
1277 |
|
} |
1278 |
|
} |
1279 |
|
} |
1280 |
|
}else{ |
1281 |
|
// don't know how to apply substitution to literal |
1282 |
|
} |
1283 |
|
} |
1284 |
426199 |
if( lit!=lret && !lret.isNull() ){ |
1285 |
251362 |
lret = Rewriter::rewrite( lret ); |
1286 |
|
} |
1287 |
426199 |
return lret; |
1288 |
|
} |
1289 |
|
|
1290 |
4597 |
bool CegInstantiator::check() { |
1291 |
4597 |
processAssertions(); |
1292 |
6229 |
for( unsigned r=0; r<2; r++ ){ |
1293 |
5929 |
d_effort = r == 0 ? CEG_INST_EFFORT_STANDARD : CEG_INST_EFFORT_FULL; |
1294 |
7561 |
SolvedForm sf; |
1295 |
5929 |
d_stack_vars.clear(); |
1296 |
5929 |
d_bound_var_index.clear(); |
1297 |
5929 |
d_solved_asserts.clear(); |
1298 |
|
//try to add an instantiation |
1299 |
5929 |
if (constructInstantiation(sf, 0)) |
1300 |
|
{ |
1301 |
4297 |
return true; |
1302 |
|
} |
1303 |
|
} |
1304 |
300 |
Trace("cegqi-engine") << " WARNING : unable to find CEGQI single invocation instantiation." << std::endl; |
1305 |
300 |
return false; |
1306 |
|
} |
1307 |
|
|
1308 |
4597 |
void CegInstantiator::processAssertions() { |
1309 |
9194 |
Trace("cegqi-proc") << "--- Process assertions, #var = " << d_vars.size() |
1310 |
4597 |
<< std::endl; |
1311 |
4597 |
d_curr_asserts.clear(); |
1312 |
4597 |
d_curr_eqc.clear(); |
1313 |
4597 |
d_curr_type_eqc.clear(); |
1314 |
|
|
1315 |
|
// must use master equality engine to avoid value instantiations |
1316 |
4597 |
eq::EqualityEngine* ee = d_qstate.getEqualityEngine(); |
1317 |
|
|
1318 |
|
//for each variable |
1319 |
41821 |
for( unsigned i=0; i<d_vars.size(); i++ ){ |
1320 |
74448 |
Node pv = d_vars[i]; |
1321 |
74448 |
TypeNode pvtn = pv.getType(); |
1322 |
37224 |
Trace("cegqi-proc-debug") << "Collect theory ids from type " << pvtn << " of " << pv << std::endl; |
1323 |
|
//collect information about eqc |
1324 |
37224 |
if( ee->hasTerm( pv ) ){ |
1325 |
50820 |
Node pvr = ee->getRepresentative( pv ); |
1326 |
25410 |
if( d_curr_eqc.find( pvr )==d_curr_eqc.end() ){ |
1327 |
13654 |
Trace("cegqi-proc") << "Collect equivalence class " << pvr << std::endl; |
1328 |
13654 |
eq::EqClassIterator eqc_i = eq::EqClassIterator( pvr, ee ); |
1329 |
71762 |
while( !eqc_i.isFinished() ){ |
1330 |
29054 |
d_curr_eqc[pvr].push_back( *eqc_i ); |
1331 |
29054 |
++eqc_i; |
1332 |
|
} |
1333 |
|
} |
1334 |
|
} |
1335 |
|
} |
1336 |
|
//collect assertions for relevant theories |
1337 |
4597 |
const LogicInfo& logicInfo = d_qstate.getLogicInfo(); |
1338 |
14321 |
for (TheoryId tid : d_tids) |
1339 |
|
{ |
1340 |
9724 |
if (!logicInfo.isTheoryEnabled(tid)) |
1341 |
|
{ |
1342 |
2075 |
continue; |
1343 |
|
} |
1344 |
15298 |
Trace("cegqi-proc") << "Collect assertions from theory " << tid |
1345 |
7649 |
<< std::endl; |
1346 |
7649 |
d_curr_asserts[tid].clear(); |
1347 |
|
// collect all assertions from theory |
1348 |
367005 |
for (context::CDList<Assertion>::const_iterator |
1349 |
7649 |
it = d_qstate.factsBegin(tid), |
1350 |
7649 |
itEnd = d_qstate.factsEnd(tid); |
1351 |
374654 |
it != itEnd; |
1352 |
|
++it) |
1353 |
|
{ |
1354 |
734010 |
Node lit = (*it).d_assertion; |
1355 |
734010 |
Node atom = lit.getKind() == NOT ? lit[0] : lit; |
1356 |
734010 |
if (d_is_nested_quant |
1357 |
1092509 |
|| std::find(d_ce_atoms.begin(), d_ce_atoms.end(), atom) |
1358 |
1092509 |
!= d_ce_atoms.end()) |
1359 |
|
{ |
1360 |
36076 |
d_curr_asserts[tid].push_back(lit); |
1361 |
36076 |
Trace("cegqi-proc-debug") << "...add : " << lit << std::endl; |
1362 |
|
} |
1363 |
|
else |
1364 |
|
{ |
1365 |
661858 |
Trace("cegqi-proc") |
1366 |
330929 |
<< "...do not consider literal " << tid << " : " << lit |
1367 |
330929 |
<< " since it is not part of CE body." << std::endl; |
1368 |
|
} |
1369 |
|
} |
1370 |
|
} |
1371 |
|
//collect equivalence classes that correspond to relevant theories |
1372 |
4597 |
Trace("cegqi-proc-debug") << "...collect typed equivalence classes" << std::endl; |
1373 |
4597 |
eq::EqClassesIterator eqcs_i = eq::EqClassesIterator( ee ); |
1374 |
780183 |
while( !eqcs_i.isFinished() ){ |
1375 |
775586 |
Node r = *eqcs_i; |
1376 |
775586 |
TypeNode rtn = r.getType(); |
1377 |
387793 |
TheoryId tid = Theory::theoryOf( rtn ); |
1378 |
|
//if we care about the theory of this eqc |
1379 |
387793 |
if( std::find( d_tids.begin(), d_tids.end(), tid )!=d_tids.end() ){ |
1380 |
326851 |
if( rtn.isInteger() || rtn.isReal() ){ |
1381 |
22662 |
rtn = rtn.getBaseType(); |
1382 |
|
} |
1383 |
326851 |
Trace("cegqi-proc-debug") << "...type eqc: " << r << std::endl; |
1384 |
326851 |
d_curr_type_eqc[rtn].push_back( r ); |
1385 |
326851 |
if( d_curr_eqc.find( r )==d_curr_eqc.end() ){ |
1386 |
313197 |
Trace("cegqi-proc") << "Collect equivalence class " << r << std::endl; |
1387 |
313197 |
Trace("cegqi-proc-debug") << " "; |
1388 |
313197 |
eq::EqClassIterator eqc_i = eq::EqClassIterator( r, ee ); |
1389 |
1061225 |
while( !eqc_i.isFinished() ){ |
1390 |
374014 |
Trace("cegqi-proc-debug") << *eqc_i << " "; |
1391 |
374014 |
d_curr_eqc[r].push_back( *eqc_i ); |
1392 |
374014 |
++eqc_i; |
1393 |
|
} |
1394 |
313197 |
Trace("cegqi-proc-debug") << std::endl; |
1395 |
|
} |
1396 |
|
} |
1397 |
387793 |
++eqcs_i; |
1398 |
|
} |
1399 |
|
|
1400 |
|
//remove unecessary assertions |
1401 |
12246 |
for( std::map< TheoryId, std::vector< Node > >::iterator it = d_curr_asserts.begin(); it != d_curr_asserts.end(); ++it ){ |
1402 |
15298 |
std::vector< Node > akeep; |
1403 |
43725 |
for( unsigned i=0; i<it->second.size(); i++ ){ |
1404 |
72152 |
Node n = it->second[i]; |
1405 |
|
//must be an eligible term |
1406 |
36076 |
if( isEligible( n ) ){ |
1407 |
|
//must contain at least one variable |
1408 |
30578 |
if( !d_prog_var[n].empty() ){ |
1409 |
28860 |
Trace("cegqi-proc") << "...literal[" << it->first << "] : " << n << std::endl; |
1410 |
28860 |
akeep.push_back( n ); |
1411 |
|
}else{ |
1412 |
1718 |
Trace("cegqi-proc") << "...remove literal from " << it->first << " : " << n << " since it contains no relevant variables." << std::endl; |
1413 |
|
} |
1414 |
|
}else{ |
1415 |
5498 |
Trace("cegqi-proc") << "...remove literal from " << it->first << " : " << n << " since it contains ineligible terms." << std::endl; |
1416 |
|
} |
1417 |
|
} |
1418 |
7649 |
it->second.clear(); |
1419 |
7649 |
it->second.insert( it->second.end(), akeep.begin(), akeep.end() ); |
1420 |
|
} |
1421 |
|
|
1422 |
|
//remove duplicate terms from eqc |
1423 |
331448 |
for( std::map< Node, std::vector< Node > >::iterator it = d_curr_eqc.begin(); it != d_curr_eqc.end(); ++it ){ |
1424 |
653702 |
std::vector< Node > new_eqc; |
1425 |
729919 |
for( unsigned i=0; i<it->second.size(); i++ ){ |
1426 |
403068 |
if( std::find( new_eqc.begin(), new_eqc.end(), it->second[i] )==new_eqc.end() ){ |
1427 |
403068 |
new_eqc.push_back( it->second[i] ); |
1428 |
|
} |
1429 |
|
} |
1430 |
326851 |
it->second.clear(); |
1431 |
326851 |
it->second.insert( it->second.end(), new_eqc.begin(), new_eqc.end() ); |
1432 |
|
} |
1433 |
4597 |
} |
1434 |
|
|
1435 |
116238 |
Node CegInstantiator::getModelValue( Node n ) { |
1436 |
116238 |
return d_treg.getModel()->getValue(n); |
1437 |
|
} |
1438 |
|
|
1439 |
1215 |
Node CegInstantiator::getBoundVariable(TypeNode tn) |
1440 |
|
{ |
1441 |
1215 |
unsigned index = 0; |
1442 |
|
std::unordered_map<TypeNode, unsigned>::iterator itb = |
1443 |
1215 |
d_bound_var_index.find(tn); |
1444 |
1215 |
if (itb != d_bound_var_index.end()) |
1445 |
|
{ |
1446 |
136 |
index = itb->second; |
1447 |
|
} |
1448 |
1215 |
d_bound_var_index[tn] = index + 1; |
1449 |
2203 |
while (index >= d_bound_var[tn].size()) |
1450 |
|
{ |
1451 |
988 |
std::stringstream ss; |
1452 |
494 |
ss << "x" << index; |
1453 |
988 |
Node x = NodeManager::currentNM()->mkBoundVar(ss.str(), tn); |
1454 |
494 |
d_bound_var[tn].push_back(x); |
1455 |
|
} |
1456 |
1215 |
return d_bound_var[tn][index]; |
1457 |
|
} |
1458 |
|
|
1459 |
445748 |
bool CegInstantiator::isSolvedAssertion(Node n) const |
1460 |
|
{ |
1461 |
445748 |
return d_solved_asserts.find(n) != d_solved_asserts.end(); |
1462 |
|
} |
1463 |
|
|
1464 |
4556 |
void CegInstantiator::markSolved(Node n, bool solved) |
1465 |
|
{ |
1466 |
4556 |
if (solved) |
1467 |
|
{ |
1468 |
2278 |
d_solved_asserts.insert(n); |
1469 |
|
} |
1470 |
2278 |
else if (isSolvedAssertion(n)) |
1471 |
|
{ |
1472 |
2278 |
d_solved_asserts.erase(n); |
1473 |
|
} |
1474 |
4556 |
} |
1475 |
|
|
1476 |
24180 |
void CegInstantiator::collectCeAtoms( Node n, std::map< Node, bool >& visited ) { |
1477 |
24180 |
if( n.getKind()==FORALL ){ |
1478 |
164 |
d_is_nested_quant = true; |
1479 |
24016 |
}else if( visited.find( n )==visited.end() ){ |
1480 |
22190 |
visited[n] = true; |
1481 |
22190 |
if( TermUtil::isBoolConnectiveTerm( n ) ){ |
1482 |
33756 |
for( unsigned i=0; i<n.getNumChildren(); i++ ){ |
1483 |
22454 |
collectCeAtoms( n[i], visited ); |
1484 |
|
} |
1485 |
|
}else{ |
1486 |
10888 |
if( std::find( d_ce_atoms.begin(), d_ce_atoms.end(), n )==d_ce_atoms.end() ){ |
1487 |
10888 |
Trace("cegqi-ce-atoms") << "CE atoms : " << n << std::endl; |
1488 |
10888 |
d_ce_atoms.push_back( n ); |
1489 |
|
} |
1490 |
|
} |
1491 |
|
} |
1492 |
24180 |
} |
1493 |
|
|
1494 |
1623 |
void CegInstantiator::registerCounterexampleLemma(Node lem, |
1495 |
|
std::vector<Node>& ceVars, |
1496 |
|
std::vector<Node>& auxLems) |
1497 |
|
{ |
1498 |
1623 |
Trace("cegqi-reg") << "Register counterexample lemma..." << std::endl; |
1499 |
1623 |
d_input_vars.clear(); |
1500 |
1623 |
d_input_vars.insert(d_input_vars.end(), ceVars.begin(), ceVars.end()); |
1501 |
|
|
1502 |
|
//Assert( d_vars.empty() ); |
1503 |
1623 |
d_vars.clear(); |
1504 |
1623 |
registerTheoryId(THEORY_UF); |
1505 |
4789 |
for (const Node& cv : ceVars) |
1506 |
|
{ |
1507 |
3166 |
Trace("cegqi-reg") << " register input variable : " << cv << std::endl; |
1508 |
3166 |
registerVariable(cv); |
1509 |
|
} |
1510 |
|
|
1511 |
|
// preprocess with all relevant instantiator preprocessors |
1512 |
3246 |
Trace("cegqi-debug") << "Preprocess based on theory-specific methods..." |
1513 |
1623 |
<< std::endl; |
1514 |
3246 |
std::vector<Node> pvars; |
1515 |
1623 |
pvars.insert(pvars.end(), d_vars.begin(), d_vars.end()); |
1516 |
2333 |
for (std::pair<const TheoryId, InstantiatorPreprocess*>& p : d_tipp) |
1517 |
|
{ |
1518 |
710 |
p.second->registerCounterexampleLemma(lem, pvars, auxLems); |
1519 |
|
} |
1520 |
|
// must register variables generated by preprocessors |
1521 |
3246 |
Trace("cegqi-debug") << "Register variables from theory-specific methods " |
1522 |
3246 |
<< d_input_vars.size() << " " << pvars.size() << " ..." |
1523 |
1623 |
<< std::endl; |
1524 |
1831 |
for (unsigned i = d_input_vars.size(), size = pvars.size(); i < size; ++i) |
1525 |
|
{ |
1526 |
416 |
Trace("cegqi-reg") << " register inst preprocess variable : " << pvars[i] |
1527 |
208 |
<< std::endl; |
1528 |
208 |
registerVariable(pvars[i]); |
1529 |
|
} |
1530 |
|
|
1531 |
|
// register variables that were introduced during TheoryEngine preprocessing |
1532 |
3246 |
std::unordered_set<Node> ceSyms; |
1533 |
1623 |
expr::getSymbols(lem, ceSyms); |
1534 |
3246 |
std::unordered_set<Node> qSyms; |
1535 |
1623 |
expr::getSymbols(d_quant, qSyms); |
1536 |
|
// all variables that are in counterexample lemma but not in quantified |
1537 |
|
// formula |
1538 |
10485 |
for (const Node& ces : ceSyms) |
1539 |
|
{ |
1540 |
8862 |
if (qSyms.find(ces) != qSyms.end()) |
1541 |
|
{ |
1542 |
|
// a free symbol of the quantified formula. |
1543 |
10718 |
continue; |
1544 |
|
} |
1545 |
5983 |
if (std::find(d_vars.begin(), d_vars.end(), ces) != d_vars.end()) |
1546 |
|
{ |
1547 |
|
// already processed variable |
1548 |
3130 |
continue; |
1549 |
|
} |
1550 |
|
// must avoid selector symbols, and function skolems introduced by |
1551 |
|
// theory preprocessing |
1552 |
3876 |
TypeNode ct = ces.getType(); |
1553 |
2853 |
if (ct.isBoolean() || ct.isFunctionLike()) |
1554 |
|
{ |
1555 |
|
// Boolean variables, including the counterexample literal, don't matter |
1556 |
|
// since they are always assigned a model value. |
1557 |
1830 |
continue; |
1558 |
|
} |
1559 |
2046 |
Trace("cegqi-reg") << " register theory preprocess variable : " << ces |
1560 |
1023 |
<< std::endl; |
1561 |
|
// register the variable, which was introduced by TheoryEngine's preprocess |
1562 |
|
// method, e.g. an ITE skolem. |
1563 |
1023 |
registerVariable(ces); |
1564 |
|
} |
1565 |
|
|
1566 |
|
// determine variable order: must do Reals before Ints |
1567 |
1623 |
Trace("cegqi-debug") << "Determine variable order..." << std::endl; |
1568 |
1623 |
if (!d_vars.empty()) |
1569 |
|
{ |
1570 |
3246 |
std::map<Node, unsigned> voo; |
1571 |
1623 |
bool doSort = false; |
1572 |
3246 |
std::vector<Node> vars; |
1573 |
3246 |
std::map<TypeNode, std::vector<Node> > tvars; |
1574 |
6020 |
for (unsigned i = 0, size = d_vars.size(); i < size; i++) |
1575 |
|
{ |
1576 |
4397 |
voo[d_vars[i]] = i; |
1577 |
4397 |
d_var_order_index.push_back(0); |
1578 |
8794 |
TypeNode tn = d_vars[i].getType(); |
1579 |
4397 |
if (tn.isInteger()) |
1580 |
|
{ |
1581 |
2169 |
doSort = true; |
1582 |
2169 |
tvars[tn].push_back(d_vars[i]); |
1583 |
|
} |
1584 |
|
else |
1585 |
|
{ |
1586 |
2228 |
vars.push_back(d_vars[i]); |
1587 |
|
} |
1588 |
|
} |
1589 |
1623 |
if (doSort) |
1590 |
|
{ |
1591 |
544 |
Trace("cegqi-debug") << "Sort variables based on ordering." << std::endl; |
1592 |
1088 |
for (std::pair<const TypeNode, std::vector<Node> >& vs : tvars) |
1593 |
|
{ |
1594 |
544 |
vars.insert(vars.end(), vs.second.begin(), vs.second.end()); |
1595 |
|
} |
1596 |
|
|
1597 |
544 |
Trace("cegqi-debug") << "Consider variables in this order : " << std::endl; |
1598 |
2964 |
for (unsigned i = 0; i < vars.size(); i++) |
1599 |
|
{ |
1600 |
2420 |
d_var_order_index[voo[vars[i]]] = i; |
1601 |
4840 |
Trace("cegqi-debug") << " " << vars[i] << " : " << vars[i].getType() |
1602 |
2420 |
<< ", index was : " << voo[vars[i]] << std::endl; |
1603 |
2420 |
d_vars[i] = vars[i]; |
1604 |
|
} |
1605 |
544 |
Trace("cegqi-debug") << std::endl; |
1606 |
|
} |
1607 |
|
else |
1608 |
|
{ |
1609 |
1079 |
d_var_order_index.clear(); |
1610 |
|
} |
1611 |
|
} |
1612 |
|
|
1613 |
|
// collect atoms from all lemmas: we will only solve for literals coming from |
1614 |
|
// the original body |
1615 |
1623 |
d_is_nested_quant = false; |
1616 |
3246 |
std::map< Node, bool > visited; |
1617 |
1623 |
collectCeAtoms(lem, visited); |
1618 |
1726 |
for (const Node& alem : auxLems) |
1619 |
|
{ |
1620 |
103 |
collectCeAtoms(alem, visited); |
1621 |
|
} |
1622 |
1623 |
} |
1623 |
|
|
1624 |
3058 |
Instantiator::Instantiator(TypeNode tn) : d_type(tn) |
1625 |
|
{ |
1626 |
3058 |
d_closed_enum_type = tn.isClosedEnumerable(); |
1627 |
3058 |
} |
1628 |
|
|
1629 |
11 |
bool Instantiator::processEqualTerm(CegInstantiator* ci, |
1630 |
|
SolvedForm& sf, |
1631 |
|
Node pv, |
1632 |
|
TermProperties& pv_prop, |
1633 |
|
Node n, |
1634 |
|
CegInstEffort effort) |
1635 |
|
{ |
1636 |
11 |
pv_prop.d_type = CEG_TT_EQUAL; |
1637 |
11 |
return ci->constructInstantiationInc(pv, n, pv_prop, sf); |
1638 |
|
} |
1639 |
|
|
1640 |
|
} // namespace quantifiers |
1641 |
|
} // namespace theory |
1642 |
29511 |
} // namespace cvc5 |