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 "expr/dtype.h" |
19 |
|
#include "expr/dtype_cons.h" |
20 |
|
#include "expr/node_algorithm.h" |
21 |
|
#include "options/quantifiers_options.h" |
22 |
|
#include "theory/arith/arith_msum.h" |
23 |
|
#include "theory/quantifiers/cegqi/ceg_arith_instantiator.h" |
24 |
|
#include "theory/quantifiers/cegqi/ceg_bv_instantiator.h" |
25 |
|
#include "theory/quantifiers/cegqi/ceg_dt_instantiator.h" |
26 |
|
#include "theory/quantifiers/cegqi/inst_strategy_cegqi.h" |
27 |
|
#include "theory/quantifiers/first_order_model.h" |
28 |
|
#include "theory/quantifiers/quantifiers_attributes.h" |
29 |
|
#include "theory/quantifiers/quantifiers_state.h" |
30 |
|
#include "theory/quantifiers/term_database.h" |
31 |
|
#include "theory/quantifiers/term_util.h" |
32 |
|
#include "theory/rewriter.h" |
33 |
|
#include "util/rational.h" |
34 |
|
|
35 |
|
using namespace std; |
36 |
|
using namespace cvc5::kind; |
37 |
|
|
38 |
|
namespace cvc5 { |
39 |
|
namespace theory { |
40 |
|
namespace quantifiers { |
41 |
|
|
42 |
366 |
CegTermType mkStrictCTT(CegTermType c) |
43 |
|
{ |
44 |
366 |
Assert(!isStrictCTT(c)); |
45 |
366 |
if (c == CEG_TT_LOWER) |
46 |
|
{ |
47 |
219 |
return CEG_TT_LOWER_STRICT; |
48 |
|
} |
49 |
147 |
else if (c == CEG_TT_UPPER) |
50 |
|
{ |
51 |
147 |
return CEG_TT_UPPER_STRICT; |
52 |
|
} |
53 |
|
return c; |
54 |
|
} |
55 |
|
|
56 |
3797 |
CegTermType mkNegateCTT(CegTermType c) |
57 |
|
{ |
58 |
3797 |
if (c == CEG_TT_LOWER) |
59 |
|
{ |
60 |
1031 |
return CEG_TT_UPPER; |
61 |
|
} |
62 |
2766 |
else if (c == CEG_TT_UPPER) |
63 |
|
{ |
64 |
2766 |
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 |
366 |
bool isStrictCTT(CegTermType c) |
77 |
|
{ |
78 |
366 |
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 |
18741 |
bool isUpperBoundCTT(CegTermType c) |
85 |
|
{ |
86 |
18741 |
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 |
47 |
void TermProperties::composeProperty(TermProperties& p) |
129 |
|
{ |
130 |
47 |
if (p.d_coeff.isNull()) |
131 |
|
{ |
132 |
|
return; |
133 |
|
} |
134 |
47 |
if (d_coeff.isNull()) |
135 |
|
{ |
136 |
41 |
d_coeff = p.d_coeff; |
137 |
|
} |
138 |
|
else |
139 |
|
{ |
140 |
6 |
NodeManager* nm = NodeManager::currentNM(); |
141 |
12 |
d_coeff = nm->mkConst(Rational(d_coeff.getConst<Rational>() |
142 |
6 |
* p.d_coeff.getConst<Rational>())); |
143 |
|
} |
144 |
|
} |
145 |
|
|
146 |
|
// push the substitution pv_prop.getModifiedTerm(pv) -> n |
147 |
41244 |
void SolvedForm::push_back(Node pv, Node n, TermProperties& pv_prop) |
148 |
|
{ |
149 |
41244 |
d_vars.push_back(pv); |
150 |
41244 |
d_subs.push_back(n); |
151 |
41244 |
d_props.push_back(pv_prop); |
152 |
41244 |
if (pv_prop.isBasic()) |
153 |
|
{ |
154 |
41032 |
return; |
155 |
|
} |
156 |
212 |
d_non_basic.push_back(pv); |
157 |
|
// update theta value |
158 |
424 |
Node new_theta = getTheta(); |
159 |
212 |
if (new_theta.isNull()) |
160 |
|
{ |
161 |
158 |
new_theta = pv_prop.d_coeff; |
162 |
|
} |
163 |
|
else |
164 |
|
{ |
165 |
54 |
Assert(new_theta.getKind() == CONST_RATIONAL); |
166 |
54 |
Assert(pv_prop.d_coeff.getKind() == CONST_RATIONAL); |
167 |
54 |
NodeManager* nm = NodeManager::currentNM(); |
168 |
54 |
new_theta = nm->mkConst(Rational(new_theta.getConst<Rational>() |
169 |
|
* pv_prop.d_coeff.getConst<Rational>())); |
170 |
|
} |
171 |
212 |
d_theta.push_back(new_theta); |
172 |
|
} |
173 |
|
// pop the substitution pv_prop.getModifiedTerm(pv) -> n |
174 |
4388 |
void SolvedForm::pop_back(Node pv, Node n, TermProperties& pv_prop) |
175 |
|
{ |
176 |
4388 |
d_vars.pop_back(); |
177 |
4388 |
d_subs.pop_back(); |
178 |
4388 |
d_props.pop_back(); |
179 |
4388 |
if (pv_prop.isBasic()) |
180 |
|
{ |
181 |
4343 |
return; |
182 |
|
} |
183 |
45 |
d_non_basic.pop_back(); |
184 |
|
// update theta value |
185 |
45 |
d_theta.pop_back(); |
186 |
|
} |
187 |
|
|
188 |
1931 |
CegInstantiator::CegInstantiator(Env& env, |
189 |
|
Node q, |
190 |
|
QuantifiersState& qs, |
191 |
|
TermRegistry& tr, |
192 |
1931 |
InstStrategyCegqi* parent) |
193 |
|
: EnvObj(env), |
194 |
|
d_quant(q), |
195 |
|
d_qstate(qs), |
196 |
|
d_treg(tr), |
197 |
|
d_parent(parent), |
198 |
|
d_is_nested_quant(false), |
199 |
1931 |
d_effort(CEG_INST_EFFORT_NONE) |
200 |
|
{ |
201 |
1931 |
} |
202 |
|
|
203 |
5793 |
CegInstantiator::~CegInstantiator() { |
204 |
5461 |
for (std::pair<Node, Instantiator*> inst : d_instantiator) |
205 |
|
{ |
206 |
3530 |
delete inst.second; |
207 |
|
} |
208 |
2669 |
for (std::pair<TheoryId, InstantiatorPreprocess*> instp : d_tipp) |
209 |
|
{ |
210 |
738 |
delete instp.second; |
211 |
|
} |
212 |
3862 |
} |
213 |
|
|
214 |
3386659 |
void CegInstantiator::computeProgVars( Node n ){ |
215 |
3386659 |
if( d_prog_var.find( n )==d_prog_var.end() ){ |
216 |
64480 |
d_prog_var[n].clear(); |
217 |
64480 |
if (n.getKind() == kind::WITNESS) |
218 |
|
{ |
219 |
544 |
Assert(d_prog_var.find(n[0][0]) == d_prog_var.end()); |
220 |
544 |
d_prog_var[n[0][0]].clear(); |
221 |
|
} |
222 |
64480 |
if (d_vars_set.find(n) != d_vars_set.end()) |
223 |
|
{ |
224 |
3197 |
d_prog_var[n].insert(n); |
225 |
|
} |
226 |
61283 |
else if (!isEligibleForInstantiation(n)) |
227 |
|
{ |
228 |
3078 |
d_inelig.insert(n); |
229 |
3078 |
return; |
230 |
|
} |
231 |
148488 |
for( unsigned i=0; i<n.getNumChildren(); i++ ){ |
232 |
87086 |
computeProgVars( n[i] ); |
233 |
87086 |
if( d_inelig.find( n[i] )!=d_inelig.end() ){ |
234 |
12443 |
d_inelig.insert(n); |
235 |
|
} |
236 |
|
// all variables in child are contained in this |
237 |
87086 |
d_prog_var[n].insert(d_prog_var[n[i]].begin(), d_prog_var[n[i]].end()); |
238 |
|
} |
239 |
|
// selectors applied to program variables are also variables |
240 |
122804 |
if (n.getKind() == APPLY_SELECTOR_TOTAL |
241 |
122804 |
&& d_prog_var[n].find(n[0]) != d_prog_var[n].end()) |
242 |
|
{ |
243 |
60 |
d_prog_var[n].insert(n); |
244 |
|
} |
245 |
61402 |
if (n.getKind() == kind::WITNESS) |
246 |
|
{ |
247 |
544 |
d_prog_var.erase(n[0][0]); |
248 |
|
} |
249 |
|
} |
250 |
|
} |
251 |
|
|
252 |
948656 |
bool CegInstantiator::isEligible( Node n ) { |
253 |
|
//compute d_subs_fv, which program variables are contained in n, and determines if eligible |
254 |
948656 |
computeProgVars( n ); |
255 |
948656 |
return d_inelig.find( n )==d_inelig.end(); |
256 |
|
} |
257 |
|
|
258 |
56096 |
CegHandledStatus CegInstantiator::isCbqiKind(Kind k) |
259 |
|
{ |
260 |
141303 |
if (quantifiers::TermUtil::isBoolConnective(k) || k == PLUS || k == GEQ |
261 |
15078 |
|| k == EQUAL || k == MULT || k == NONLINEAR_MULT || k == DIVISION |
262 |
9239 |
|| k == DIVISION_TOTAL || k == INTS_DIVISION || k == INTS_DIVISION_TOTAL |
263 |
9103 |
|| k == INTS_MODULUS || k == INTS_MODULUS_TOTAL || k == TO_INTEGER |
264 |
65098 |
|| k == IS_INTEGER) |
265 |
|
{ |
266 |
47098 |
return CEG_HANDLED; |
267 |
|
} |
268 |
|
|
269 |
|
// CBQI typically works for satisfaction-complete theories |
270 |
8998 |
TheoryId t = kindToTheoryId(k); |
271 |
8998 |
if (t == THEORY_BV || t == THEORY_FP || t == THEORY_DATATYPES |
272 |
5825 |
|| t == THEORY_BOOL) |
273 |
|
{ |
274 |
3173 |
return CEG_HANDLED; |
275 |
|
} |
276 |
5825 |
return CEG_UNHANDLED; |
277 |
|
} |
278 |
|
|
279 |
7856 |
CegHandledStatus CegInstantiator::isCbqiTerm(Node n) |
280 |
|
{ |
281 |
7856 |
CegHandledStatus ret = CEG_HANDLED; |
282 |
15712 |
std::unordered_set<TNode> visited; |
283 |
15712 |
std::vector<TNode> visit; |
284 |
15712 |
TNode cur; |
285 |
7856 |
visit.push_back(n); |
286 |
103126 |
do |
287 |
|
{ |
288 |
110982 |
cur = visit.back(); |
289 |
110982 |
visit.pop_back(); |
290 |
110982 |
if (visited.find(cur) == visited.end()) |
291 |
|
{ |
292 |
90729 |
visited.insert(cur); |
293 |
90729 |
if (cur.getKind() != BOUND_VARIABLE && TermUtil::hasBoundVarAttr(cur)) |
294 |
|
{ |
295 |
64286 |
if (cur.getKind() == FORALL || cur.getKind() == WITNESS) |
296 |
|
{ |
297 |
8190 |
visit.push_back(cur[1]); |
298 |
|
} |
299 |
|
else |
300 |
|
{ |
301 |
56096 |
CegHandledStatus curr = isCbqiKind(cur.getKind()); |
302 |
56096 |
if (curr < ret) |
303 |
|
{ |
304 |
5825 |
ret = curr; |
305 |
11650 |
Trace("cegqi-debug2") << "Non-cbqi kind : " << cur.getKind() |
306 |
5825 |
<< " in " << n << std::endl; |
307 |
5825 |
if (curr == CEG_UNHANDLED) |
308 |
|
{ |
309 |
5825 |
return CEG_UNHANDLED; |
310 |
|
} |
311 |
|
} |
312 |
157386 |
for (const Node& nc : cur) |
313 |
|
{ |
314 |
107115 |
visit.push_back(nc); |
315 |
|
} |
316 |
|
} |
317 |
|
} |
318 |
|
} |
319 |
105157 |
} while (!visit.empty()); |
320 |
2031 |
return ret; |
321 |
|
} |
322 |
|
|
323 |
25893 |
CegHandledStatus CegInstantiator::isCbqiSort(TypeNode tn) |
324 |
|
{ |
325 |
51786 |
std::map<TypeNode, CegHandledStatus> visited; |
326 |
51786 |
return isCbqiSort(tn, visited); |
327 |
|
} |
328 |
|
|
329 |
31073 |
CegHandledStatus CegInstantiator::isCbqiSort( |
330 |
|
TypeNode tn, std::map<TypeNode, CegHandledStatus>& visited) |
331 |
|
{ |
332 |
31073 |
std::map<TypeNode, CegHandledStatus>::iterator itv = visited.find(tn); |
333 |
31073 |
if (itv != visited.end()) |
334 |
|
{ |
335 |
3011 |
return itv->second; |
336 |
|
} |
337 |
28062 |
CegHandledStatus ret = CEG_UNHANDLED; |
338 |
72625 |
if (tn.isInteger() || tn.isReal() || tn.isBoolean() || tn.isBitVector() |
339 |
42266 |
|| tn.isFloatingPoint()) |
340 |
|
{ |
341 |
13871 |
ret = CEG_HANDLED; |
342 |
|
} |
343 |
14191 |
else if (tn.isDatatype()) |
344 |
|
{ |
345 |
|
// recursive calls to this datatype are handlable |
346 |
2317 |
visited[tn] = CEG_HANDLED; |
347 |
|
// we initialize to handled, we remain handled as long as all subfields |
348 |
|
// of this datatype are not unhandled. |
349 |
2317 |
ret = CEG_HANDLED; |
350 |
2317 |
const DType& dt = tn.getDType(); |
351 |
4799 |
for (unsigned i = 0, ncons = dt.getNumConstructors(); i < ncons; i++) |
352 |
|
{ |
353 |
|
// get the constructor type |
354 |
6486 |
TypeNode consType; |
355 |
4004 |
if (dt.isParametric()) |
356 |
|
{ |
357 |
|
// if parametric, must instantiate the argument types |
358 |
36 |
consType = dt[i].getSpecializedConstructorType(tn); |
359 |
|
} |
360 |
|
else |
361 |
|
{ |
362 |
3968 |
consType = dt[i].getConstructor().getType(); |
363 |
|
} |
364 |
7662 |
for (const TypeNode& crange : consType) |
365 |
|
{ |
366 |
5180 |
CegHandledStatus cret = isCbqiSort(crange, visited); |
367 |
5180 |
if (cret == CEG_UNHANDLED) |
368 |
|
{ |
369 |
3044 |
Trace("cegqi-debug2") |
370 |
1522 |
<< "Non-cbqi sort : " << tn << " due to " << crange << std::endl; |
371 |
1522 |
visited[tn] = CEG_UNHANDLED; |
372 |
1522 |
return CEG_UNHANDLED; |
373 |
|
} |
374 |
3658 |
else if (cret < ret) |
375 |
|
{ |
376 |
|
ret = cret; |
377 |
|
} |
378 |
|
} |
379 |
|
} |
380 |
|
} |
381 |
|
// sets, arrays, functions and others are not supported |
382 |
26540 |
visited[tn] = ret; |
383 |
26540 |
return ret; |
384 |
|
} |
385 |
|
|
386 |
19728 |
CegHandledStatus CegInstantiator::isCbqiQuantPrefix(Node q) |
387 |
|
{ |
388 |
19728 |
CegHandledStatus hmin = CEG_HANDLED_UNCONDITIONAL; |
389 |
33692 |
for (const Node& v : q[0]) |
390 |
|
{ |
391 |
39800 |
TypeNode tn = v.getType(); |
392 |
25836 |
CegHandledStatus handled = isCbqiSort(tn); |
393 |
25836 |
if (handled == CEG_UNHANDLED) |
394 |
|
{ |
395 |
11872 |
return CEG_UNHANDLED; |
396 |
|
} |
397 |
13964 |
else if (handled < hmin) |
398 |
|
{ |
399 |
8175 |
hmin = handled; |
400 |
|
} |
401 |
|
} |
402 |
7856 |
return hmin; |
403 |
|
} |
404 |
|
|
405 |
24527 |
CegHandledStatus CegInstantiator::isCbqiQuant(Node q) |
406 |
|
{ |
407 |
24527 |
Assert(q.getKind() == FORALL); |
408 |
|
// compute attributes |
409 |
49054 |
QAttributes qa; |
410 |
24527 |
QuantAttributes::computeQuantAttributes(q, qa); |
411 |
24527 |
if (qa.d_quant_elim) |
412 |
|
{ |
413 |
96 |
return CEG_HANDLED; |
414 |
|
} |
415 |
24431 |
if (qa.d_sygus) |
416 |
|
{ |
417 |
548 |
return CEG_UNHANDLED; |
418 |
|
} |
419 |
23883 |
Assert(!qa.d_quant_elim_partial); |
420 |
|
// if has an instantiation pattern, don't do it |
421 |
23883 |
if (q.getNumChildren() == 3) |
422 |
|
{ |
423 |
6131 |
for (const Node& pat : q[2]) |
424 |
|
{ |
425 |
5314 |
if (pat.getKind() == INST_PATTERN) |
426 |
|
{ |
427 |
4155 |
return CEG_UNHANDLED; |
428 |
|
} |
429 |
|
} |
430 |
|
} |
431 |
19728 |
CegHandledStatus ret = CEG_HANDLED; |
432 |
|
// if quantifier has a non-handled variable, then do not use cbqi |
433 |
19728 |
CegHandledStatus ncbqiv = CegInstantiator::isCbqiQuantPrefix(q); |
434 |
39456 |
Trace("cegqi-quant-debug") << "isCbqiQuantPrefix returned " << ncbqiv |
435 |
19728 |
<< std::endl; |
436 |
19728 |
if (ncbqiv == CEG_UNHANDLED) |
437 |
|
{ |
438 |
|
// unhandled variable type |
439 |
11872 |
ret = CEG_UNHANDLED; |
440 |
|
} |
441 |
|
else |
442 |
|
{ |
443 |
7856 |
CegHandledStatus cbqit = CegInstantiator::isCbqiTerm(q); |
444 |
7856 |
Trace("cegqi-quant-debug") << "isCbqiTerm returned " << cbqit << std::endl; |
445 |
7856 |
if (cbqit == CEG_UNHANDLED) |
446 |
|
{ |
447 |
5825 |
if (ncbqiv == CEG_HANDLED_UNCONDITIONAL) |
448 |
|
{ |
449 |
|
// all variables are fully handled, this implies this will be handlable |
450 |
|
// regardless of body (e.g. for EPR) |
451 |
|
// so, try but not exclusively |
452 |
|
ret = CEG_PARTIALLY_HANDLED; |
453 |
|
} |
454 |
|
else |
455 |
|
{ |
456 |
|
// cannot be handled |
457 |
5825 |
ret = CEG_UNHANDLED; |
458 |
|
} |
459 |
|
} |
460 |
2031 |
else if (cbqit == CEG_PARTIALLY_HANDLED) |
461 |
|
{ |
462 |
|
ret = CEG_PARTIALLY_HANDLED; |
463 |
|
} |
464 |
|
} |
465 |
19728 |
if (ret == CEG_UNHANDLED && options::cegqiAll()) |
466 |
|
{ |
467 |
|
// try but not exclusively |
468 |
17 |
ret = CEG_PARTIALLY_HANDLED; |
469 |
|
} |
470 |
19728 |
return ret; |
471 |
|
} |
472 |
|
|
473 |
436140 |
bool CegInstantiator::hasVariable( Node n, Node pv ) { |
474 |
436140 |
computeProgVars( n ); |
475 |
436140 |
return d_prog_var[n].find( pv )!=d_prog_var[n].end(); |
476 |
|
} |
477 |
|
|
478 |
41348 |
void CegInstantiator::activateInstantiationVariable(Node v, unsigned index) |
479 |
|
{ |
480 |
41348 |
if( d_instantiator.find( v )==d_instantiator.end() ){ |
481 |
7060 |
TypeNode tn = v.getType(); |
482 |
|
Instantiator * vinst; |
483 |
3530 |
if( tn.isReal() ){ |
484 |
2021 |
vinst = new ArithInstantiator(d_env, tn, d_parent->getVtsTermCache()); |
485 |
1509 |
}else if( tn.isDatatype() ){ |
486 |
54 |
vinst = new DtInstantiator(d_env, tn); |
487 |
1455 |
}else if( tn.isBitVector() ){ |
488 |
1224 |
vinst = new BvInstantiator(d_env, tn, d_parent->getBvInverter()); |
489 |
231 |
}else if( tn.isBoolean() ){ |
490 |
219 |
vinst = new ModelValueInstantiator(d_env, tn); |
491 |
|
}else{ |
492 |
|
//default |
493 |
12 |
vinst = new Instantiator(d_env, tn); |
494 |
|
} |
495 |
3530 |
d_instantiator[v] = vinst; |
496 |
|
} |
497 |
41348 |
d_curr_subs_proc[v].clear(); |
498 |
41348 |
d_curr_index[v] = index; |
499 |
41348 |
d_curr_iphase[v] = CEG_INST_PHASE_NONE; |
500 |
41348 |
} |
501 |
|
|
502 |
4492 |
void CegInstantiator::deactivateInstantiationVariable(Node v) |
503 |
|
{ |
504 |
4492 |
d_curr_subs_proc.erase(v); |
505 |
4492 |
d_curr_index.erase(v); |
506 |
4492 |
d_curr_iphase.erase(v); |
507 |
4492 |
} |
508 |
|
|
509 |
66392 |
bool CegInstantiator::hasTriedInstantiation(Node v) |
510 |
|
{ |
511 |
66392 |
return !d_curr_subs_proc[v].empty(); |
512 |
|
} |
513 |
|
|
514 |
5431 |
void CegInstantiator::registerTheoryIds(TypeNode tn, |
515 |
|
std::map<TypeNode, bool>& visited) |
516 |
|
{ |
517 |
5431 |
if (visited.find(tn) == visited.end()) |
518 |
|
{ |
519 |
5377 |
visited[tn] = true; |
520 |
5377 |
TheoryId tid = Theory::theoryOf(tn); |
521 |
5377 |
registerTheoryId(tid); |
522 |
5377 |
if (tn.isDatatype()) |
523 |
|
{ |
524 |
66 |
const DType& dt = tn.getDType(); |
525 |
170 |
for (unsigned i = 0; i < dt.getNumConstructors(); i++) |
526 |
|
{ |
527 |
222 |
for (unsigned j = 0; j < dt[i].getNumArgs(); j++) |
528 |
|
{ |
529 |
118 |
registerTheoryIds(dt[i].getArgType(j), visited); |
530 |
|
} |
531 |
|
} |
532 |
|
} |
533 |
|
} |
534 |
5431 |
} |
535 |
|
|
536 |
7308 |
void CegInstantiator::registerTheoryId(TheoryId tid) |
537 |
|
{ |
538 |
7308 |
if (std::find(d_tids.begin(), d_tids.end(), tid) == d_tids.end()) |
539 |
|
{ |
540 |
|
// setup any theory-specific preprocessors here |
541 |
3935 |
if (tid == THEORY_BV) |
542 |
|
{ |
543 |
738 |
d_tipp[tid] = new BvInstantiatorPreprocess; |
544 |
|
} |
545 |
3935 |
d_tids.push_back(tid); |
546 |
|
} |
547 |
7308 |
} |
548 |
|
|
549 |
5313 |
void CegInstantiator::registerVariable(Node v) |
550 |
|
{ |
551 |
5313 |
Assert(std::find(d_vars.begin(), d_vars.end(), v) == d_vars.end()); |
552 |
5313 |
d_vars.push_back(v); |
553 |
5313 |
d_vars_set.insert(v); |
554 |
10626 |
TypeNode vtn = v.getType(); |
555 |
10626 |
Trace("cegqi-proc-debug") << "Collect theory ids from type " << vtn << " of " |
556 |
5313 |
<< v << std::endl; |
557 |
|
// collect relevant theories for this variable |
558 |
10626 |
std::map<TypeNode, bool> visited; |
559 |
5313 |
registerTheoryIds(vtn, visited); |
560 |
5313 |
} |
561 |
|
|
562 |
47363 |
bool CegInstantiator::constructInstantiation(SolvedForm& sf, unsigned i) |
563 |
|
{ |
564 |
47363 |
if( i==d_vars.size() ){ |
565 |
|
//solved for all variables, now construct instantiation |
566 |
|
bool needsPostprocess = |
567 |
6015 |
sf.d_vars.size() > d_input_vars.size() || !d_var_order_index.empty(); |
568 |
12030 |
std::vector< Instantiator * > pp_inst; |
569 |
12030 |
std::map< Instantiator *, Node > pp_inst_to_var; |
570 |
47259 |
for( std::map< Node, Instantiator * >::iterator ita = d_active_instantiators.begin(); ita != d_active_instantiators.end(); ++ita ){ |
571 |
123732 |
if (ita->second->needsPostProcessInstantiationForVariable( |
572 |
82488 |
this, sf, ita->first, d_effort)) |
573 |
|
{ |
574 |
253 |
needsPostprocess = true; |
575 |
253 |
pp_inst_to_var[ ita->second ] = ita->first; |
576 |
|
} |
577 |
|
} |
578 |
6015 |
if( needsPostprocess ){ |
579 |
|
//must make copy so that backtracking reverts sf |
580 |
4426 |
SolvedForm sf_tmp = sf; |
581 |
2213 |
bool postProcessSuccess = true; |
582 |
2425 |
for( std::map< Instantiator *, Node >::iterator itp = pp_inst_to_var.begin(); itp != pp_inst_to_var.end(); ++itp ){ |
583 |
759 |
if (!itp->first->postProcessInstantiationForVariable( |
584 |
506 |
this, sf_tmp, itp->second, d_effort)) |
585 |
|
{ |
586 |
41 |
postProcessSuccess = false; |
587 |
41 |
break; |
588 |
|
} |
589 |
|
} |
590 |
2213 |
if( postProcessSuccess ){ |
591 |
2172 |
return doAddInstantiation(sf_tmp.d_vars, sf_tmp.d_subs); |
592 |
|
}else{ |
593 |
41 |
return false; |
594 |
|
} |
595 |
|
}else{ |
596 |
3802 |
return doAddInstantiation(sf.d_vars, sf.d_subs); |
597 |
|
} |
598 |
|
}else{ |
599 |
41348 |
bool is_sv = false; |
600 |
82696 |
Node pv; |
601 |
41348 |
if( d_stack_vars.empty() ){ |
602 |
41288 |
pv = d_vars[i]; |
603 |
|
}else{ |
604 |
60 |
pv = d_stack_vars.back(); |
605 |
60 |
is_sv = true; |
606 |
60 |
d_stack_vars.pop_back(); |
607 |
|
} |
608 |
41348 |
activateInstantiationVariable(pv, i); |
609 |
|
|
610 |
|
//get the instantiator object |
611 |
41348 |
Assert(d_instantiator.find(pv) != d_instantiator.end()); |
612 |
41348 |
Instantiator* vinst = d_instantiator[pv]; |
613 |
41348 |
Assert(vinst != NULL); |
614 |
41348 |
d_active_instantiators[pv] = vinst; |
615 |
41348 |
vinst->reset(this, sf, pv, d_effort); |
616 |
|
// if d_effort is full, we must choose at least one model value |
617 |
41348 |
if ((i + 1) < d_vars.size() || d_effort != CEG_INST_EFFORT_FULL) |
618 |
|
{ |
619 |
|
// First, try to construct an instantiation term for pv based on |
620 |
|
// equality and theory-specific instantiation techniques. |
621 |
40035 |
if (constructInstantiation(sf, vinst, pv)) |
622 |
|
{ |
623 |
26595 |
return true; |
624 |
|
} |
625 |
|
} |
626 |
|
// If the above call fails, resort to using value in model. We do so if: |
627 |
|
// - we have yet to try an instantiation this round (or we are trying |
628 |
|
// multiple instantiations, indicated by options::cegqiMultiInst), |
629 |
|
// - the instantiator uses model values at this effort or |
630 |
|
// if we are solving for a subfield of a datatype (is_sv), and |
631 |
|
// - the instantiator allows model values. |
632 |
44219 |
if ((options().quantifiers.cegqiMultiInst || !hasTriedInstantiation(pv)) |
633 |
26536 |
&& (vinst->useModelValue(this, sf, pv, d_effort) || is_sv) |
634 |
41125 |
&& vinst->allowModelValue(this, sf, pv, d_effort)) |
635 |
|
{ |
636 |
12977 |
Node mv = getModelValue( pv ); |
637 |
12977 |
TermProperties pv_prop_m; |
638 |
11619 |
Trace("cegqi-inst-debug") << "[4] " << i << "...try model value " << mv << std::endl; |
639 |
11619 |
d_curr_iphase[pv] = CEG_INST_PHASE_MVALUE; |
640 |
11619 |
CegInstEffort prev = d_effort; |
641 |
11619 |
if (d_effort < CEG_INST_EFFORT_STANDARD_MV) |
642 |
|
{ |
643 |
|
// update the effort level to indicate we have used a model value |
644 |
2114 |
d_effort = CEG_INST_EFFORT_STANDARD_MV; |
645 |
|
} |
646 |
11619 |
if (constructInstantiationInc(pv, mv, pv_prop_m, sf)) |
647 |
|
{ |
648 |
10261 |
return true; |
649 |
|
} |
650 |
1358 |
d_effort = prev; |
651 |
|
} |
652 |
|
|
653 |
4492 |
Trace("cegqi-inst-debug") << "[No instantiation found for " << pv << "]" << std::endl; |
654 |
4492 |
if (is_sv) |
655 |
|
{ |
656 |
|
d_stack_vars.push_back( pv ); |
657 |
|
} |
658 |
4492 |
d_active_instantiators.erase( pv ); |
659 |
4492 |
deactivateInstantiationVariable(pv); |
660 |
4492 |
return false; |
661 |
|
} |
662 |
|
} |
663 |
|
|
664 |
40035 |
bool CegInstantiator::constructInstantiation(SolvedForm& sf, |
665 |
|
Instantiator* vinst, |
666 |
|
Node pv) |
667 |
|
{ |
668 |
80070 |
TypeNode pvtn = pv.getType(); |
669 |
80070 |
TypeNode pvtnb = pvtn.getBaseType(); |
670 |
80070 |
Node pvr = pv; |
671 |
40035 |
eq::EqualityEngine* ee = d_qstate.getEqualityEngine(); |
672 |
40035 |
if (ee->hasTerm(pv)) |
673 |
|
{ |
674 |
27646 |
pvr = ee->getRepresentative(pv); |
675 |
|
} |
676 |
80070 |
Trace("cegqi-inst-debug") << "[Find instantiation for " << pv |
677 |
40035 |
<< "], rep=" << pvr << ", instantiator is " |
678 |
40035 |
<< vinst->identify() << std::endl; |
679 |
80070 |
Node pv_value; |
680 |
40035 |
if (options().quantifiers.cegqiModel) |
681 |
|
{ |
682 |
40035 |
pv_value = getModelValue(pv); |
683 |
40035 |
Trace("cegqi-bound2") << "...M( " << pv << " ) = " << pv_value << std::endl; |
684 |
|
} |
685 |
|
|
686 |
|
//[1] easy case : pv is in the equivalence class as another term not |
687 |
|
// containing pv |
688 |
40035 |
if (vinst->hasProcessEqualTerm(this, sf, pv, d_effort)) |
689 |
|
{ |
690 |
116 |
Trace("cegqi-inst-debug") |
691 |
58 |
<< "[1] try based on equivalence class." << std::endl; |
692 |
58 |
d_curr_iphase[pv] = CEG_INST_PHASE_EQC; |
693 |
58 |
std::map<Node, std::vector<Node> >::iterator it_eqc = d_curr_eqc.find(pvr); |
694 |
58 |
if (it_eqc != d_curr_eqc.end()) |
695 |
|
{ |
696 |
|
// std::vector< Node > eq_candidates; |
697 |
116 |
Trace("cegqi-inst-debug2") |
698 |
58 |
<< "...eqc has size " << it_eqc->second.size() << std::endl; |
699 |
164 |
for (const Node& n : it_eqc->second) |
700 |
|
{ |
701 |
120 |
if (n != pv) |
702 |
|
{ |
703 |
148 |
Trace("cegqi-inst-debug") |
704 |
74 |
<< "...try based on equal term " << n << std::endl; |
705 |
|
// must be an eligible term |
706 |
74 |
if (isEligible(n)) |
707 |
|
{ |
708 |
94 |
Node ns; |
709 |
|
// coefficient of pv in the equality we solve (null is 1) |
710 |
94 |
TermProperties pv_prop; |
711 |
54 |
bool proc = false; |
712 |
54 |
if (!d_prog_var[n].empty()) |
713 |
|
{ |
714 |
46 |
ns = applySubstitution(pvtn, n, sf, pv_prop, false); |
715 |
46 |
if (!ns.isNull()) |
716 |
|
{ |
717 |
46 |
computeProgVars(ns); |
718 |
|
// substituted version must be new and cannot contain pv |
719 |
46 |
proc = d_prog_var[ns].find(pv) == d_prog_var[ns].end(); |
720 |
|
} |
721 |
|
} |
722 |
|
else |
723 |
|
{ |
724 |
8 |
ns = n; |
725 |
8 |
proc = true; |
726 |
|
} |
727 |
54 |
if (proc) |
728 |
|
{ |
729 |
14 |
if (vinst->processEqualTerm(this, sf, pv, pv_prop, ns, d_effort)) |
730 |
|
{ |
731 |
14 |
return true; |
732 |
|
} |
733 |
|
else if (!options().quantifiers.cegqiMultiInst |
734 |
|
&& hasTriedInstantiation(pv)) |
735 |
|
{ |
736 |
|
return false; |
737 |
|
} |
738 |
|
// Do not consider more than one equal term, |
739 |
|
// this helps non-monotonic strategies that may encounter |
740 |
|
// duplicate instantiations. |
741 |
|
break; |
742 |
|
} |
743 |
|
} |
744 |
|
} |
745 |
|
} |
746 |
44 |
if (vinst->processEqualTerms(this, sf, pv, it_eqc->second, d_effort)) |
747 |
|
{ |
748 |
34 |
return true; |
749 |
|
} |
750 |
20 |
else if (!options().quantifiers.cegqiMultiInst |
751 |
20 |
&& hasTriedInstantiation(pv)) |
752 |
|
{ |
753 |
|
return false; |
754 |
|
} |
755 |
|
} |
756 |
|
else |
757 |
|
{ |
758 |
|
Trace("cegqi-inst-debug2") << "...eqc not found." << std::endl; |
759 |
|
} |
760 |
|
} |
761 |
|
|
762 |
|
//[2] : we can solve an equality for pv |
763 |
|
/// iterate over equivalence classes to find cases where we can solve for |
764 |
|
/// the variable |
765 |
39987 |
if (vinst->hasProcessEquality(this, sf, pv, d_effort)) |
766 |
|
{ |
767 |
55892 |
Trace("cegqi-inst-debug") |
768 |
27946 |
<< "[2] try based on solving equalities." << std::endl; |
769 |
27946 |
d_curr_iphase[pv] = CEG_INST_PHASE_EQUAL; |
770 |
27946 |
std::vector<Node>& cteqc = d_curr_type_eqc[pvtnb]; |
771 |
|
|
772 |
387952 |
for (const Node& r : cteqc) |
773 |
|
{ |
774 |
373230 |
std::map<Node, std::vector<Node> >::iterator it_reqc = d_curr_eqc.find(r); |
775 |
733236 |
std::vector<Node> lhs; |
776 |
733236 |
std::vector<bool> lhs_v; |
777 |
733236 |
std::vector<TermProperties> lhs_prop; |
778 |
373230 |
Assert(it_reqc != d_curr_eqc.end()); |
779 |
1270464 |
for (const Node& n : it_reqc->second) |
780 |
|
{ |
781 |
910458 |
Trace("cegqi-inst-debug2") << "...look at term " << n << std::endl; |
782 |
|
// must be an eligible term |
783 |
910458 |
if (isEligible(n)) |
784 |
|
{ |
785 |
1474676 |
Node ns; |
786 |
1474676 |
TermProperties pv_prop; |
787 |
743950 |
if (!d_prog_var[n].empty()) |
788 |
|
{ |
789 |
686235 |
ns = applySubstitution(pvtn, n, sf, pv_prop); |
790 |
686235 |
if (!ns.isNull()) |
791 |
|
{ |
792 |
686217 |
computeProgVars(ns); |
793 |
|
} |
794 |
|
} |
795 |
|
else |
796 |
|
{ |
797 |
57715 |
ns = n; |
798 |
|
} |
799 |
743950 |
if (!ns.isNull()) |
800 |
|
{ |
801 |
743932 |
bool hasVar = d_prog_var[ns].find(pv) != d_prog_var[ns].end(); |
802 |
1487864 |
Trace("cegqi-inst-debug2") << "... " << ns << " has var " << pv |
803 |
743932 |
<< " : " << hasVar << std::endl; |
804 |
1474640 |
std::vector<TermProperties> term_props; |
805 |
1474640 |
std::vector<Node> terms; |
806 |
743932 |
term_props.push_back(pv_prop); |
807 |
743932 |
terms.push_back(ns); |
808 |
1536079 |
for (unsigned j = 0, size = lhs.size(); j < size; j++) |
809 |
|
{ |
810 |
|
// if this term or the another has pv in it, try to solve for it |
811 |
805371 |
if (hasVar || lhs_v[j]) |
812 |
|
{ |
813 |
92246 |
Trace("cegqi-inst-debug") << "......try based on equality " |
814 |
46123 |
<< lhs[j] << " = " << ns << std::endl; |
815 |
46123 |
term_props.push_back(lhs_prop[j]); |
816 |
46123 |
terms.push_back(lhs[j]); |
817 |
46123 |
if (vinst->processEquality( |
818 |
46123 |
this, sf, pv, term_props, terms, d_effort)) |
819 |
|
{ |
820 |
12442 |
return true; |
821 |
|
} |
822 |
67362 |
else if (!options().quantifiers.cegqiMultiInst |
823 |
67362 |
&& hasTriedInstantiation(pv)) |
824 |
|
{ |
825 |
782 |
return false; |
826 |
|
} |
827 |
32899 |
term_props.pop_back(); |
828 |
32899 |
terms.pop_back(); |
829 |
|
} |
830 |
|
} |
831 |
730708 |
lhs.push_back(ns); |
832 |
730708 |
lhs_v.push_back(hasVar); |
833 |
730708 |
lhs_prop.push_back(pv_prop); |
834 |
|
} |
835 |
|
else |
836 |
|
{ |
837 |
36 |
Trace("cegqi-inst-debug2") |
838 |
18 |
<< "... term " << n << " is ineligible after substitution." |
839 |
18 |
<< std::endl; |
840 |
|
} |
841 |
|
} |
842 |
|
else |
843 |
|
{ |
844 |
333016 |
Trace("cegqi-inst-debug2") |
845 |
166508 |
<< "... term " << n << " is ineligible." << std::endl; |
846 |
|
} |
847 |
|
} |
848 |
|
} |
849 |
|
} |
850 |
|
//[3] directly look at assertions |
851 |
26763 |
if (!vinst->hasProcessAssertion(this, sf, pv, d_effort)) |
852 |
|
{ |
853 |
7196 |
return false; |
854 |
|
} |
855 |
19567 |
Trace("cegqi-inst-debug") << "[3] try based on assertions." << std::endl; |
856 |
19567 |
d_curr_iphase[pv] = CEG_INST_PHASE_ASSERTION; |
857 |
39134 |
std::unordered_set<Node> lits; |
858 |
58701 |
for (unsigned r = 0; r < 2; r++) |
859 |
|
{ |
860 |
39134 |
TheoryId tid = r == 0 ? Theory::theoryOf(pvtn) : THEORY_UF; |
861 |
39134 |
Trace("cegqi-inst-debug2") << " look at assertions of " << tid << std::endl; |
862 |
|
std::map<TheoryId, std::vector<Node> >::iterator ita = |
863 |
39134 |
d_curr_asserts.find(tid); |
864 |
39134 |
if (ita != d_curr_asserts.end()) |
865 |
|
{ |
866 |
486491 |
for (const Node& lit : ita->second) |
867 |
|
{ |
868 |
462331 |
if (lits.find(lit) == lits.end()) |
869 |
|
{ |
870 |
453486 |
lits.insert(lit); |
871 |
906972 |
Node plit; |
872 |
453486 |
if (options().quantifiers.cegqiRepeatLit || !isSolvedAssertion(lit)) |
873 |
|
{ |
874 |
447862 |
plit = vinst->hasProcessAssertion(this, sf, pv, lit, d_effort); |
875 |
|
} |
876 |
453486 |
if (!plit.isNull()) |
877 |
|
{ |
878 |
436257 |
Trace("cegqi-inst-debug2") << " look at " << lit; |
879 |
436257 |
if (plit != lit) |
880 |
|
{ |
881 |
9229 |
Trace("cegqi-inst-debug2") << "...processed to : " << plit; |
882 |
|
} |
883 |
436257 |
Trace("cegqi-inst-debug2") << std::endl; |
884 |
|
// apply substitutions |
885 |
872514 |
Node slit = applySubstitutionToLiteral(plit, sf); |
886 |
436257 |
if (!slit.isNull()) |
887 |
|
{ |
888 |
|
// check if contains pv |
889 |
436140 |
if (hasVariable(slit, pv)) |
890 |
|
{ |
891 |
36280 |
Trace("cegqi-inst-debug") |
892 |
18140 |
<< "...try based on literal " << slit << "," << std::endl; |
893 |
18140 |
Trace("cegqi-inst-debug") << "...from " << lit << std::endl; |
894 |
18140 |
if (vinst->processAssertion(this, sf, pv, slit, lit, d_effort)) |
895 |
|
{ |
896 |
|
return true; |
897 |
|
} |
898 |
36280 |
else if (!options().quantifiers.cegqiMultiInst |
899 |
36280 |
&& hasTriedInstantiation(pv)) |
900 |
|
{ |
901 |
|
return false; |
902 |
|
} |
903 |
|
} |
904 |
|
} |
905 |
|
} |
906 |
|
} |
907 |
|
} |
908 |
|
} |
909 |
|
} |
910 |
19567 |
if (vinst->processAssertions(this, sf, pv, d_effort)) |
911 |
|
{ |
912 |
14105 |
return true; |
913 |
|
} |
914 |
5462 |
return false; |
915 |
|
} |
916 |
|
|
917 |
60 |
void CegInstantiator::pushStackVariable( Node v ) { |
918 |
60 |
d_stack_vars.push_back( v ); |
919 |
60 |
} |
920 |
|
|
921 |
|
void CegInstantiator::popStackVariable() { |
922 |
|
Assert(!d_stack_vars.empty()); |
923 |
|
d_stack_vars.pop_back(); |
924 |
|
} |
925 |
|
|
926 |
41244 |
bool CegInstantiator::constructInstantiationInc(Node pv, |
927 |
|
Node n, |
928 |
|
TermProperties& pv_prop, |
929 |
|
SolvedForm& sf, |
930 |
|
bool revertOnSuccess) |
931 |
|
{ |
932 |
82488 |
Node cnode = pv_prop.getCacheNode(); |
933 |
41244 |
if( d_curr_subs_proc[pv][n].find( cnode )==d_curr_subs_proc[pv][n].end() ){ |
934 |
41244 |
d_curr_subs_proc[pv][n][cnode] = true; |
935 |
41244 |
if( Trace.isOn("cegqi-inst-debug") ){ |
936 |
|
for( unsigned j=0; j<sf.d_subs.size(); j++ ){ |
937 |
|
Trace("cegqi-inst-debug") << " "; |
938 |
|
} |
939 |
|
Trace("cegqi-inst-debug") << sf.d_subs.size() << ": (" << d_curr_iphase[pv] |
940 |
|
<< ") "; |
941 |
|
Node mod_pv = pv_prop.getModifiedTerm( pv ); |
942 |
|
Trace("cegqi-inst-debug") << mod_pv << " -> " << n << std::endl; |
943 |
|
Assert(n.getType().isSubtypeOf(pv.getType())); |
944 |
|
} |
945 |
|
//must ensure variables have been computed for n |
946 |
41244 |
computeProgVars( n ); |
947 |
41244 |
Assert(d_inelig.find(n) == d_inelig.end()); |
948 |
|
|
949 |
|
//substitute into previous substitutions, when applicable |
950 |
82488 |
std::vector< Node > a_var; |
951 |
41244 |
a_var.push_back( pv ); |
952 |
82488 |
std::vector< Node > a_subs; |
953 |
41244 |
a_subs.push_back( n ); |
954 |
82488 |
std::vector< TermProperties > a_prop; |
955 |
41244 |
a_prop.push_back( pv_prop ); |
956 |
82488 |
std::vector< Node > a_non_basic; |
957 |
41244 |
if( !pv_prop.isBasic() ){ |
958 |
212 |
a_non_basic.push_back( pv ); |
959 |
|
} |
960 |
41244 |
bool success = true; |
961 |
82488 |
std::map< int, Node > prev_subs; |
962 |
82488 |
std::map< int, TermProperties > prev_prop; |
963 |
82488 |
std::map< int, Node > prev_sym_subs; |
964 |
82488 |
std::vector< Node > new_non_basic; |
965 |
41244 |
Trace("cegqi-inst-debug2") << "Applying substitutions to previous substitution terms..." << std::endl; |
966 |
835506 |
for( unsigned j=0; j<sf.d_subs.size(); j++ ){ |
967 |
794262 |
Trace("cegqi-inst-debug2") << " Apply for " << sf.d_subs[j] << std::endl; |
968 |
794262 |
Assert(d_prog_var.find(sf.d_subs[j]) != d_prog_var.end()); |
969 |
794262 |
if( d_prog_var[sf.d_subs[j]].find( pv )!=d_prog_var[sf.d_subs[j]].end() ){ |
970 |
31978 |
prev_subs[j] = sf.d_subs[j]; |
971 |
63956 |
TNode tv = pv; |
972 |
63956 |
TNode ts = n; |
973 |
63956 |
TermProperties a_pv_prop; |
974 |
63956 |
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 ); |
975 |
31978 |
if( !new_subs.isNull() ){ |
976 |
31978 |
sf.d_subs[j] = new_subs; |
977 |
|
// the substitution apply to this term resulted in a non-basic substitution relationship |
978 |
31978 |
if( !a_pv_prop.isBasic() ){ |
979 |
|
// we are processing: |
980 |
|
// sf.d_props[j].getModifiedTerm( sf.d_vars[j] ) = sf.d_subs[j] { pv_prop.getModifiedTerm( pv ) -> n } |
981 |
|
|
982 |
|
// based on the above substitution, we have: |
983 |
|
// x = sf.d_subs[j] { pv_prop.getModifiedTerm( pv ) -> n } |
984 |
|
// is equivalent to |
985 |
|
// a_pv_prop.getModifiedTerm( x ) = new_subs |
986 |
|
|
987 |
|
// thus we must compose substitutions: |
988 |
|
// a_pv_prop.getModifiedTerm( sf.d_props[j].getModifiedTerm( sf.d_vars[j] ) ) = new_subs |
989 |
|
|
990 |
47 |
prev_prop[j] = sf.d_props[j]; |
991 |
47 |
bool prev_basic = sf.d_props[j].isBasic(); |
992 |
|
|
993 |
|
// now compose the property |
994 |
47 |
sf.d_props[j].composeProperty( a_pv_prop ); |
995 |
|
|
996 |
|
// if previously was basic, becomes non-basic |
997 |
47 |
if( prev_basic && !sf.d_props[j].isBasic() ){ |
998 |
41 |
Assert(std::find(sf.d_non_basic.begin(), |
999 |
|
sf.d_non_basic.end(), |
1000 |
|
sf.d_vars[j]) |
1001 |
|
== sf.d_non_basic.end()); |
1002 |
41 |
new_non_basic.push_back( sf.d_vars[j] ); |
1003 |
41 |
sf.d_non_basic.push_back( sf.d_vars[j] ); |
1004 |
|
} |
1005 |
|
} |
1006 |
31978 |
if( sf.d_subs[j]!=prev_subs[j] ){ |
1007 |
31974 |
computeProgVars( sf.d_subs[j] ); |
1008 |
31974 |
Assert(d_inelig.find(sf.d_subs[j]) == d_inelig.end()); |
1009 |
|
} |
1010 |
31978 |
Trace("cegqi-inst-debug2") << "Subs " << j << " " << sf.d_subs[j] << std::endl; |
1011 |
|
}else{ |
1012 |
|
Trace("cegqi-inst-debug2") << "...failed to apply substitution to " << sf.d_subs[j] << std::endl; |
1013 |
|
success = false; |
1014 |
|
break; |
1015 |
|
} |
1016 |
|
}else{ |
1017 |
762284 |
Trace("cegqi-inst-debug2") << "Skip " << j << " " << sf.d_subs[j] << std::endl; |
1018 |
|
} |
1019 |
|
} |
1020 |
41244 |
if( success ){ |
1021 |
41244 |
Trace("cegqi-inst-debug2") << "Adding to vectors..." << std::endl; |
1022 |
41244 |
sf.push_back( pv, n, pv_prop ); |
1023 |
41244 |
Trace("cegqi-inst-debug2") << "Recurse..." << std::endl; |
1024 |
41244 |
unsigned i = d_curr_index[pv]; |
1025 |
41244 |
success = constructInstantiation(sf, d_stack_vars.empty() ? i + 1 : i); |
1026 |
41244 |
if (!success || revertOnSuccess) |
1027 |
|
{ |
1028 |
4388 |
Trace("cegqi-inst-debug2") << "Removing from vectors..." << std::endl; |
1029 |
4388 |
sf.pop_back( pv, n, pv_prop ); |
1030 |
|
} |
1031 |
|
} |
1032 |
41244 |
if (success && !revertOnSuccess) |
1033 |
|
{ |
1034 |
36856 |
return true; |
1035 |
|
}else{ |
1036 |
4388 |
Trace("cegqi-inst-debug2") << "Revert substitutions..." << std::endl; |
1037 |
|
//revert substitution information |
1038 |
6249 |
for (std::map<int, Node>::iterator it = prev_subs.begin(); |
1039 |
6249 |
it != prev_subs.end(); |
1040 |
|
++it) |
1041 |
|
{ |
1042 |
1861 |
sf.d_subs[it->first] = it->second; |
1043 |
|
} |
1044 |
4388 |
for (std::map<int, TermProperties>::iterator it = prev_prop.begin(); |
1045 |
4388 |
it != prev_prop.end(); |
1046 |
|
++it) |
1047 |
|
{ |
1048 |
|
sf.d_props[it->first] = it->second; |
1049 |
|
} |
1050 |
4388 |
for( unsigned i=0; i<new_non_basic.size(); i++ ){ |
1051 |
|
sf.d_non_basic.pop_back(); |
1052 |
|
} |
1053 |
4388 |
return success; |
1054 |
|
} |
1055 |
|
}else{ |
1056 |
|
//already tried this substitution |
1057 |
|
return false; |
1058 |
|
} |
1059 |
|
} |
1060 |
|
|
1061 |
5974 |
bool CegInstantiator::doAddInstantiation(std::vector<Node>& vars, |
1062 |
|
std::vector<Node>& subs) |
1063 |
|
{ |
1064 |
5974 |
if (vars.size() > d_input_vars.size() || !d_var_order_index.empty()) |
1065 |
|
{ |
1066 |
2172 |
Trace("cegqi-inst-debug") << "Reconstructing instantiations...." << std::endl; |
1067 |
4344 |
std::map< Node, Node > subs_map; |
1068 |
38647 |
for( unsigned i=0; i<subs.size(); i++ ){ |
1069 |
36475 |
subs_map[vars[i]] = subs[i]; |
1070 |
|
} |
1071 |
2172 |
subs.clear(); |
1072 |
25838 |
for (unsigned i = 0, size = d_input_vars.size(); i < size; ++i) |
1073 |
|
{ |
1074 |
23666 |
std::map<Node, Node>::iterator it = subs_map.find(d_input_vars[i]); |
1075 |
23666 |
Assert(it != subs_map.end()); |
1076 |
47332 |
Node n = it->second; |
1077 |
47332 |
Trace("cegqi-inst-debug") << " " << d_input_vars[i] << " -> " << n |
1078 |
23666 |
<< std::endl; |
1079 |
23666 |
Assert(n.getType().isComparableTo(d_input_vars[i].getType())); |
1080 |
23666 |
subs.push_back( n ); |
1081 |
|
} |
1082 |
|
} |
1083 |
5974 |
if (Trace.isOn("cegqi-inst")) |
1084 |
|
{ |
1085 |
|
Trace("cegqi-inst") << "Ceg Instantiator produced : " << std::endl; |
1086 |
|
for (unsigned i = 0, size = d_input_vars.size(); i < size; ++i) |
1087 |
|
{ |
1088 |
|
Node v = d_input_vars[i]; |
1089 |
|
Trace("cegqi-inst") << i << " (" << d_curr_iphase[v] << ") : " |
1090 |
|
<< v << " -> " << subs[i] << std::endl; |
1091 |
|
Assert(subs[i].getType().isComparableTo(v.getType())); |
1092 |
|
} |
1093 |
|
} |
1094 |
5974 |
Trace("cegqi-inst-debug") << "Do the instantiation...." << std::endl; |
1095 |
5974 |
return d_parent->doAddInstantiation(subs); |
1096 |
|
} |
1097 |
|
|
1098 |
61334 |
bool CegInstantiator::isEligibleForInstantiation(Node n) const |
1099 |
|
{ |
1100 |
61334 |
Kind nk = n.getKind(); |
1101 |
61334 |
if (nk != INST_CONSTANT && nk != SKOLEM && nk != BOOLEAN_TERM_VARIABLE) |
1102 |
|
{ |
1103 |
57402 |
return true; |
1104 |
|
} |
1105 |
3932 |
if (n.getAttribute(VirtualTermSkolemAttribute())) |
1106 |
|
{ |
1107 |
|
// virtual terms are allowed |
1108 |
89 |
return true; |
1109 |
|
} |
1110 |
|
// only legal if current quantified formula contains n |
1111 |
3843 |
return expr::hasSubterm(d_quant, n); |
1112 |
|
} |
1113 |
|
|
1114 |
1155296 |
bool CegInstantiator::canApplyBasicSubstitution( Node n, std::vector< Node >& non_basic ){ |
1115 |
1155296 |
Assert(d_prog_var.find(n) != d_prog_var.end()); |
1116 |
1155296 |
if( !non_basic.empty() ){ |
1117 |
11275 |
for (std::unordered_set<Node>::iterator it = d_prog_var[n].begin(); |
1118 |
11275 |
it != d_prog_var[n].end(); |
1119 |
|
++it) |
1120 |
|
{ |
1121 |
7967 |
if (std::find(non_basic.begin(), non_basic.end(), *it) != non_basic.end()) |
1122 |
|
{ |
1123 |
2081 |
return false; |
1124 |
|
} |
1125 |
|
} |
1126 |
|
} |
1127 |
1153215 |
return true; |
1128 |
|
} |
1129 |
|
|
1130 |
719039 |
Node CegInstantiator::applySubstitution( TypeNode tn, Node n, std::vector< Node >& vars, std::vector< Node >& subs, std::vector< TermProperties >& prop, |
1131 |
|
std::vector< Node >& non_basic, TermProperties& pv_prop, bool try_coeff ) { |
1132 |
719039 |
n = rewrite(n); |
1133 |
719039 |
computeProgVars( n ); |
1134 |
719039 |
bool is_basic = canApplyBasicSubstitution( n, non_basic ); |
1135 |
719039 |
if( Trace.isOn("sygus-si-apply-subs-debug") ){ |
1136 |
|
Trace("sygus-si-apply-subs-debug") << "is_basic = " << is_basic << " " << tn << std::endl; |
1137 |
|
for( unsigned i=0; i<subs.size(); i++ ){ |
1138 |
|
Trace("sygus-si-apply-subs-debug") << " " << vars[i] << " -> " << subs[i] << " types : " << vars[i].getType() << " -> " << subs[i].getType() << std::endl; |
1139 |
|
Assert(subs[i].getType().isSubtypeOf(vars[i].getType())); |
1140 |
|
} |
1141 |
|
} |
1142 |
719039 |
Node nret; |
1143 |
719039 |
if( is_basic ){ |
1144 |
717855 |
nret = n.substitute( vars.begin(), vars.end(), subs.begin(), subs.end() ); |
1145 |
|
}else{ |
1146 |
1184 |
if( !tn.isInteger() ){ |
1147 |
|
//can do basic substitution instead with divisions |
1148 |
1572 |
std::vector< Node > nvars; |
1149 |
1572 |
std::vector< Node > nsubs; |
1150 |
6736 |
for( unsigned i=0; i<vars.size(); i++ ){ |
1151 |
5950 |
if( !prop[i].d_coeff.isNull() ){ |
1152 |
2662 |
Assert(vars[i].getType().isInteger()); |
1153 |
2662 |
Assert(prop[i].d_coeff.isConst()); |
1154 |
5324 |
Node nn = NodeManager::currentNM()->mkNode( MULT, subs[i], NodeManager::currentNM()->mkConst( Rational(1)/prop[i].d_coeff.getConst<Rational>() ) ); |
1155 |
2662 |
nn = NodeManager::currentNM()->mkNode( kind::TO_INTEGER, nn ); |
1156 |
2662 |
nn = rewrite(nn); |
1157 |
2662 |
nsubs.push_back( nn ); |
1158 |
|
}else{ |
1159 |
3288 |
nsubs.push_back( subs[i] ); |
1160 |
|
} |
1161 |
|
} |
1162 |
786 |
nret = n.substitute( vars.begin(), vars.end(), nsubs.begin(), nsubs.end() ); |
1163 |
398 |
}else if( try_coeff ){ |
1164 |
|
//must convert to monomial representation |
1165 |
796 |
std::map< Node, Node > msum; |
1166 |
398 |
if (ArithMSum::getMonomialSum(n, msum)) |
1167 |
|
{ |
1168 |
796 |
std::map< Node, Node > msum_coeff; |
1169 |
796 |
std::map< Node, Node > msum_term; |
1170 |
1767 |
for( std::map< Node, Node >::iterator it = msum.begin(); it != msum.end(); ++it ){ |
1171 |
|
//check if in substitution |
1172 |
1369 |
std::vector< Node >::iterator its = std::find( vars.begin(), vars.end(), it->first ); |
1173 |
1369 |
if( its!=vars.end() ){ |
1174 |
677 |
int index = its-vars.begin(); |
1175 |
677 |
if( prop[index].d_coeff.isNull() ){ |
1176 |
|
//apply substitution |
1177 |
288 |
msum_term[it->first] = subs[index]; |
1178 |
|
}else{ |
1179 |
|
//apply substitution, multiply to ensure no divisibility conflict |
1180 |
389 |
msum_term[it->first] = subs[index]; |
1181 |
|
//relative coefficient |
1182 |
389 |
msum_coeff[it->first] = prop[index].d_coeff; |
1183 |
389 |
if( pv_prop.d_coeff.isNull() ){ |
1184 |
380 |
pv_prop.d_coeff = prop[index].d_coeff; |
1185 |
|
}else{ |
1186 |
9 |
pv_prop.d_coeff = NodeManager::currentNM()->mkNode( MULT, pv_prop.d_coeff, prop[index].d_coeff ); |
1187 |
|
} |
1188 |
|
} |
1189 |
|
}else{ |
1190 |
692 |
msum_term[it->first] = it->first; |
1191 |
|
} |
1192 |
|
} |
1193 |
|
//make sum with normalized coefficient |
1194 |
398 |
if( !pv_prop.d_coeff.isNull() ){ |
1195 |
380 |
pv_prop.d_coeff = rewrite(pv_prop.d_coeff); |
1196 |
380 |
Trace("sygus-si-apply-subs-debug") << "Combined coeff : " << pv_prop.d_coeff << std::endl; |
1197 |
760 |
std::vector< Node > children; |
1198 |
1713 |
for( std::map< Node, Node >::iterator it = msum.begin(); it != msum.end(); ++it ){ |
1199 |
2666 |
Node c_coeff; |
1200 |
1333 |
if( !msum_coeff[it->first].isNull() ){ |
1201 |
778 |
c_coeff = rewrite(NodeManager::currentNM()->mkConst( |
1202 |
389 |
pv_prop.d_coeff.getConst<Rational>() |
1203 |
1167 |
/ msum_coeff[it->first].getConst<Rational>())); |
1204 |
|
}else{ |
1205 |
944 |
c_coeff = pv_prop.d_coeff; |
1206 |
|
} |
1207 |
1333 |
if( !it->second.isNull() ){ |
1208 |
1030 |
c_coeff = NodeManager::currentNM()->mkNode( MULT, c_coeff, it->second ); |
1209 |
|
} |
1210 |
1333 |
Assert(!c_coeff.isNull()); |
1211 |
2666 |
Node c; |
1212 |
1333 |
if( msum_term[it->first].isNull() ){ |
1213 |
74 |
c = c_coeff; |
1214 |
|
}else{ |
1215 |
1259 |
c = NodeManager::currentNM()->mkNode( MULT, c_coeff, msum_term[it->first] ); |
1216 |
|
} |
1217 |
1333 |
children.push_back( c ); |
1218 |
1333 |
Trace("sygus-si-apply-subs-debug") << "Add child : " << c << std::endl; |
1219 |
|
} |
1220 |
760 |
Node nretc = children.size()==1 ? children[0] : NodeManager::currentNM()->mkNode( PLUS, children ); |
1221 |
380 |
nretc = rewrite(nretc); |
1222 |
|
//ensure that nret does not contain vars |
1223 |
380 |
if (!expr::hasSubterm(nretc, vars)) |
1224 |
|
{ |
1225 |
|
//result is ( nret / pv_prop.d_coeff ) |
1226 |
380 |
nret = nretc; |
1227 |
|
}else{ |
1228 |
|
Trace("sygus-si-apply-subs-debug") << "Failed, since result " << nretc << " contains free variable." << std::endl; |
1229 |
|
} |
1230 |
|
}else{ |
1231 |
|
//implies that we have a monomial that has a free variable |
1232 |
18 |
Trace("sygus-si-apply-subs-debug") << "Failed to find coefficient during substitution, implies monomial with free variable." << std::endl; |
1233 |
|
} |
1234 |
|
}else{ |
1235 |
|
Trace("sygus-si-apply-subs-debug") << "Failed to find monomial sum " << n << std::endl; |
1236 |
|
} |
1237 |
|
} |
1238 |
|
} |
1239 |
719039 |
if( n!=nret && !nret.isNull() ){ |
1240 |
359778 |
nret = rewrite(nret); |
1241 |
|
} |
1242 |
719039 |
return nret; |
1243 |
|
} |
1244 |
|
|
1245 |
436257 |
Node CegInstantiator::applySubstitutionToLiteral( Node lit, std::vector< Node >& vars, std::vector< Node >& subs, |
1246 |
|
std::vector< TermProperties >& prop, std::vector< Node >& non_basic ) { |
1247 |
436257 |
computeProgVars( lit ); |
1248 |
436257 |
bool is_basic = canApplyBasicSubstitution( lit, non_basic ); |
1249 |
436257 |
Node lret; |
1250 |
436257 |
if( is_basic ){ |
1251 |
435360 |
lret = lit.substitute( vars.begin(), vars.end(), subs.begin(), subs.end() ); |
1252 |
|
}else{ |
1253 |
1794 |
Node atom = lit.getKind()==NOT ? lit[0] : lit; |
1254 |
897 |
bool pol = lit.getKind()!=NOT; |
1255 |
|
//arithmetic inequalities and disequalities |
1256 |
897 |
if( atom.getKind()==GEQ || ( atom.getKind()==EQUAL && !pol && atom[0].getType().isReal() ) ){ |
1257 |
780 |
NodeManager* nm = NodeManager::currentNM(); |
1258 |
780 |
Assert(atom.getKind() != GEQ || atom[1].isConst()); |
1259 |
1560 |
Node atom_lhs; |
1260 |
1560 |
Node atom_rhs; |
1261 |
780 |
if( atom.getKind()==GEQ ){ |
1262 |
718 |
atom_lhs = atom[0]; |
1263 |
718 |
atom_rhs = atom[1]; |
1264 |
|
}else{ |
1265 |
62 |
atom_lhs = nm->mkNode(MINUS, atom[0], atom[1]); |
1266 |
62 |
atom_lhs = rewrite(atom_lhs); |
1267 |
62 |
atom_rhs = nm->mkConst(Rational(0)); |
1268 |
|
} |
1269 |
|
//must be an eligible term |
1270 |
780 |
if( isEligible( atom_lhs ) ){ |
1271 |
|
//apply substitution to LHS of atom |
1272 |
1560 |
TermProperties atom_lhs_prop; |
1273 |
780 |
atom_lhs = applySubstitution(nm->realType(), |
1274 |
|
atom_lhs, |
1275 |
|
vars, |
1276 |
|
subs, |
1277 |
|
prop, |
1278 |
|
non_basic, |
1279 |
|
atom_lhs_prop); |
1280 |
780 |
if( !atom_lhs.isNull() ){ |
1281 |
780 |
if( !atom_lhs_prop.d_coeff.isNull() ){ |
1282 |
|
atom_rhs = nm->mkNode(MULT, atom_lhs_prop.d_coeff, atom_rhs); |
1283 |
|
atom_rhs = rewrite(atom_rhs); |
1284 |
|
} |
1285 |
780 |
lret = nm->mkNode(atom.getKind(), atom_lhs, atom_rhs); |
1286 |
780 |
if( !pol ){ |
1287 |
423 |
lret = lret.negate(); |
1288 |
|
} |
1289 |
|
} |
1290 |
|
} |
1291 |
|
}else{ |
1292 |
|
// don't know how to apply substitution to literal |
1293 |
|
} |
1294 |
|
} |
1295 |
436257 |
if( lit!=lret && !lret.isNull() ){ |
1296 |
256694 |
lret = rewrite(lret); |
1297 |
|
} |
1298 |
436257 |
return lret; |
1299 |
|
} |
1300 |
|
|
1301 |
4806 |
bool CegInstantiator::check() { |
1302 |
4806 |
processAssertions(); |
1303 |
6419 |
for( unsigned r=0; r<2; r++ ){ |
1304 |
6119 |
d_effort = r == 0 ? CEG_INST_EFFORT_STANDARD : CEG_INST_EFFORT_FULL; |
1305 |
7732 |
SolvedForm sf; |
1306 |
6119 |
d_stack_vars.clear(); |
1307 |
6119 |
d_bound_var_index.clear(); |
1308 |
6119 |
d_solved_asserts.clear(); |
1309 |
|
//try to add an instantiation |
1310 |
6119 |
if (constructInstantiation(sf, 0)) |
1311 |
|
{ |
1312 |
4506 |
return true; |
1313 |
|
} |
1314 |
|
} |
1315 |
300 |
Trace("cegqi-engine") << " WARNING : unable to find CEGQI single invocation instantiation." << std::endl; |
1316 |
300 |
return false; |
1317 |
|
} |
1318 |
|
|
1319 |
4806 |
void CegInstantiator::processAssertions() { |
1320 |
9612 |
Trace("cegqi-proc") << "--- Process assertions, #var = " << d_vars.size() |
1321 |
4806 |
<< std::endl; |
1322 |
4806 |
d_curr_asserts.clear(); |
1323 |
4806 |
d_curr_eqc.clear(); |
1324 |
4806 |
d_curr_type_eqc.clear(); |
1325 |
|
|
1326 |
|
// must use master equality engine to avoid value instantiations |
1327 |
4806 |
eq::EqualityEngine* ee = d_qstate.getEqualityEngine(); |
1328 |
|
|
1329 |
|
//for each variable |
1330 |
42919 |
for( unsigned i=0; i<d_vars.size(); i++ ){ |
1331 |
76226 |
Node pv = d_vars[i]; |
1332 |
76226 |
TypeNode pvtn = pv.getType(); |
1333 |
38113 |
Trace("cegqi-proc-debug") << "Collect theory ids from type " << pvtn << " of " << pv << std::endl; |
1334 |
|
//collect information about eqc |
1335 |
38113 |
if( ee->hasTerm( pv ) ){ |
1336 |
52484 |
Node pvr = ee->getRepresentative( pv ); |
1337 |
26242 |
if( d_curr_eqc.find( pvr )==d_curr_eqc.end() ){ |
1338 |
14511 |
Trace("cegqi-proc") << "Collect equivalence class " << pvr << std::endl; |
1339 |
14511 |
eq::EqClassIterator eqc_i = eq::EqClassIterator( pvr, ee ); |
1340 |
74925 |
while( !eqc_i.isFinished() ){ |
1341 |
30207 |
d_curr_eqc[pvr].push_back( *eqc_i ); |
1342 |
30207 |
++eqc_i; |
1343 |
|
} |
1344 |
|
} |
1345 |
|
} |
1346 |
|
} |
1347 |
|
//collect assertions for relevant theories |
1348 |
4806 |
const LogicInfo& logicInfo = d_qstate.getLogicInfo(); |
1349 |
14968 |
for (TheoryId tid : d_tids) |
1350 |
|
{ |
1351 |
10162 |
if (!logicInfo.isTheoryEnabled(tid)) |
1352 |
|
{ |
1353 |
2077 |
continue; |
1354 |
|
} |
1355 |
16170 |
Trace("cegqi-proc") << "Collect assertions from theory " << tid |
1356 |
8085 |
<< std::endl; |
1357 |
8085 |
d_curr_asserts[tid].clear(); |
1358 |
|
// collect all assertions from theory |
1359 |
358477 |
for (context::CDList<Assertion>::const_iterator |
1360 |
8085 |
it = d_qstate.factsBegin(tid), |
1361 |
8085 |
itEnd = d_qstate.factsEnd(tid); |
1362 |
366562 |
it != itEnd; |
1363 |
|
++it) |
1364 |
|
{ |
1365 |
716954 |
Node lit = (*it).d_assertion; |
1366 |
716954 |
Node atom = lit.getKind() == NOT ? lit[0] : lit; |
1367 |
716954 |
if (d_is_nested_quant |
1368 |
1065231 |
|| std::find(d_ce_atoms.begin(), d_ce_atoms.end(), atom) |
1369 |
1065231 |
!= d_ce_atoms.end()) |
1370 |
|
{ |
1371 |
37344 |
d_curr_asserts[tid].push_back(lit); |
1372 |
37344 |
Trace("cegqi-proc-debug") << "...add : " << lit << std::endl; |
1373 |
|
} |
1374 |
|
else |
1375 |
|
{ |
1376 |
642266 |
Trace("cegqi-proc") |
1377 |
321133 |
<< "...do not consider literal " << tid << " : " << lit |
1378 |
321133 |
<< " since it is not part of CE body." << std::endl; |
1379 |
|
} |
1380 |
|
} |
1381 |
|
} |
1382 |
|
//collect equivalence classes that correspond to relevant theories |
1383 |
4806 |
Trace("cegqi-proc-debug") << "...collect typed equivalence classes" << std::endl; |
1384 |
4806 |
eq::EqClassesIterator eqcs_i = eq::EqClassesIterator( ee ); |
1385 |
786642 |
while( !eqcs_i.isFinished() ){ |
1386 |
781836 |
Node r = *eqcs_i; |
1387 |
781836 |
TypeNode rtn = r.getType(); |
1388 |
390918 |
TheoryId tid = Theory::theoryOf( rtn ); |
1389 |
|
//if we care about the theory of this eqc |
1390 |
390918 |
if( std::find( d_tids.begin(), d_tids.end(), tid )!=d_tids.end() ){ |
1391 |
330593 |
if( rtn.isInteger() || rtn.isReal() ){ |
1392 |
22845 |
rtn = rtn.getBaseType(); |
1393 |
|
} |
1394 |
330593 |
Trace("cegqi-proc-debug") << "...type eqc: " << r << std::endl; |
1395 |
330593 |
d_curr_type_eqc[rtn].push_back( r ); |
1396 |
330593 |
if( d_curr_eqc.find( r )==d_curr_eqc.end() ){ |
1397 |
316082 |
Trace("cegqi-proc") << "Collect equivalence class " << r << std::endl; |
1398 |
316082 |
Trace("cegqi-proc-debug") << " "; |
1399 |
316082 |
eq::EqClassIterator eqc_i = eq::EqClassIterator( r, ee ); |
1400 |
1070882 |
while( !eqc_i.isFinished() ){ |
1401 |
377400 |
Trace("cegqi-proc-debug") << *eqc_i << " "; |
1402 |
377400 |
d_curr_eqc[r].push_back( *eqc_i ); |
1403 |
377400 |
++eqc_i; |
1404 |
|
} |
1405 |
316082 |
Trace("cegqi-proc-debug") << std::endl; |
1406 |
|
} |
1407 |
|
} |
1408 |
390918 |
++eqcs_i; |
1409 |
|
} |
1410 |
|
|
1411 |
|
//remove unecessary assertions |
1412 |
12891 |
for( std::map< TheoryId, std::vector< Node > >::iterator it = d_curr_asserts.begin(); it != d_curr_asserts.end(); ++it ){ |
1413 |
16170 |
std::vector< Node > akeep; |
1414 |
45429 |
for( unsigned i=0; i<it->second.size(); i++ ){ |
1415 |
74688 |
Node n = it->second[i]; |
1416 |
|
//must be an eligible term |
1417 |
37344 |
if( isEligible( n ) ){ |
1418 |
|
//must contain at least one variable |
1419 |
31255 |
if( !d_prog_var[n].empty() ){ |
1420 |
30223 |
Trace("cegqi-proc") << "...literal[" << it->first << "] : " << n << std::endl; |
1421 |
30223 |
akeep.push_back( n ); |
1422 |
|
}else{ |
1423 |
1032 |
Trace("cegqi-proc") << "...remove literal from " << it->first << " : " << n << " since it contains no relevant variables." << std::endl; |
1424 |
|
} |
1425 |
|
}else{ |
1426 |
6089 |
Trace("cegqi-proc") << "...remove literal from " << it->first << " : " << n << " since it contains ineligible terms." << std::endl; |
1427 |
|
} |
1428 |
|
} |
1429 |
8085 |
it->second.clear(); |
1430 |
8085 |
it->second.insert( it->second.end(), akeep.begin(), akeep.end() ); |
1431 |
|
} |
1432 |
|
|
1433 |
|
//remove duplicate terms from eqc |
1434 |
335399 |
for( std::map< Node, std::vector< Node > >::iterator it = d_curr_eqc.begin(); it != d_curr_eqc.end(); ++it ){ |
1435 |
661186 |
std::vector< Node > new_eqc; |
1436 |
738200 |
for( unsigned i=0; i<it->second.size(); i++ ){ |
1437 |
407607 |
if( std::find( new_eqc.begin(), new_eqc.end(), it->second[i] )==new_eqc.end() ){ |
1438 |
407607 |
new_eqc.push_back( it->second[i] ); |
1439 |
|
} |
1440 |
|
} |
1441 |
330593 |
it->second.clear(); |
1442 |
330593 |
it->second.insert( it->second.end(), new_eqc.begin(), new_eqc.end() ); |
1443 |
|
} |
1444 |
4806 |
} |
1445 |
|
|
1446 |
113032 |
Node CegInstantiator::getModelValue( Node n ) { |
1447 |
113032 |
return d_treg.getModel()->getValue(n); |
1448 |
|
} |
1449 |
|
|
1450 |
1162 |
Node CegInstantiator::getBoundVariable(TypeNode tn) |
1451 |
|
{ |
1452 |
1162 |
unsigned index = 0; |
1453 |
|
std::unordered_map<TypeNode, unsigned>::iterator itb = |
1454 |
1162 |
d_bound_var_index.find(tn); |
1455 |
1162 |
if (itb != d_bound_var_index.end()) |
1456 |
|
{ |
1457 |
91 |
index = itb->second; |
1458 |
|
} |
1459 |
1162 |
d_bound_var_index[tn] = index + 1; |
1460 |
2144 |
while (index >= d_bound_var[tn].size()) |
1461 |
|
{ |
1462 |
982 |
std::stringstream ss; |
1463 |
491 |
ss << "x" << index; |
1464 |
982 |
Node x = NodeManager::currentNM()->mkBoundVar(ss.str(), tn); |
1465 |
491 |
d_bound_var[tn].push_back(x); |
1466 |
|
} |
1467 |
1162 |
return d_bound_var[tn][index]; |
1468 |
|
} |
1469 |
|
|
1470 |
455754 |
bool CegInstantiator::isSolvedAssertion(Node n) const |
1471 |
|
{ |
1472 |
455754 |
return d_solved_asserts.find(n) != d_solved_asserts.end(); |
1473 |
|
} |
1474 |
|
|
1475 |
4536 |
void CegInstantiator::markSolved(Node n, bool solved) |
1476 |
|
{ |
1477 |
4536 |
if (solved) |
1478 |
|
{ |
1479 |
2268 |
d_solved_asserts.insert(n); |
1480 |
|
} |
1481 |
2268 |
else if (isSolvedAssertion(n)) |
1482 |
|
{ |
1483 |
2268 |
d_solved_asserts.erase(n); |
1484 |
|
} |
1485 |
4536 |
} |
1486 |
|
|
1487 |
28633 |
void CegInstantiator::collectCeAtoms( Node n, std::map< Node, bool >& visited ) { |
1488 |
28633 |
if( n.getKind()==FORALL ){ |
1489 |
174 |
d_is_nested_quant = true; |
1490 |
28459 |
}else if( visited.find( n )==visited.end() ){ |
1491 |
26435 |
visited[n] = true; |
1492 |
26435 |
if( TermUtil::isBoolConnectiveTerm( n ) ){ |
1493 |
40204 |
for( unsigned i=0; i<n.getNumChildren(); i++ ){ |
1494 |
26563 |
collectCeAtoms( n[i], visited ); |
1495 |
|
} |
1496 |
|
}else{ |
1497 |
12794 |
if( std::find( d_ce_atoms.begin(), d_ce_atoms.end(), n )==d_ce_atoms.end() ){ |
1498 |
12794 |
Trace("cegqi-ce-atoms") << "CE atoms : " << n << std::endl; |
1499 |
12794 |
d_ce_atoms.push_back( n ); |
1500 |
|
} |
1501 |
|
} |
1502 |
|
} |
1503 |
28633 |
} |
1504 |
|
|
1505 |
1931 |
void CegInstantiator::registerCounterexampleLemma(Node lem, |
1506 |
|
std::vector<Node>& ceVars, |
1507 |
|
std::vector<Node>& auxLems) |
1508 |
|
{ |
1509 |
1931 |
Trace("cegqi-reg") << "Register counterexample lemma..." << std::endl; |
1510 |
1931 |
d_input_vars.clear(); |
1511 |
1931 |
d_input_vars.insert(d_input_vars.end(), ceVars.begin(), ceVars.end()); |
1512 |
|
|
1513 |
|
//Assert( d_vars.empty() ); |
1514 |
1931 |
d_vars.clear(); |
1515 |
1931 |
registerTheoryId(THEORY_UF); |
1516 |
5901 |
for (const Node& cv : ceVars) |
1517 |
|
{ |
1518 |
3970 |
Trace("cegqi-reg") << " register input variable : " << cv << std::endl; |
1519 |
3970 |
registerVariable(cv); |
1520 |
|
} |
1521 |
|
|
1522 |
|
// preprocess with all relevant instantiator preprocessors |
1523 |
3862 |
Trace("cegqi-debug") << "Preprocess based on theory-specific methods..." |
1524 |
1931 |
<< std::endl; |
1525 |
3862 |
std::vector<Node> pvars; |
1526 |
1931 |
pvars.insert(pvars.end(), d_vars.begin(), d_vars.end()); |
1527 |
2662 |
for (std::pair<const TheoryId, InstantiatorPreprocess*>& p : d_tipp) |
1528 |
|
{ |
1529 |
731 |
p.second->registerCounterexampleLemma(lem, pvars, auxLems); |
1530 |
|
} |
1531 |
|
// must register variables generated by preprocessors |
1532 |
3862 |
Trace("cegqi-debug") << "Register variables from theory-specific methods " |
1533 |
3862 |
<< d_input_vars.size() << " " << pvars.size() << " ..." |
1534 |
1931 |
<< std::endl; |
1535 |
2211 |
for (unsigned i = d_input_vars.size(), size = pvars.size(); i < size; ++i) |
1536 |
|
{ |
1537 |
560 |
Trace("cegqi-reg") << " register inst preprocess variable : " << pvars[i] |
1538 |
280 |
<< std::endl; |
1539 |
280 |
registerVariable(pvars[i]); |
1540 |
|
} |
1541 |
|
|
1542 |
|
// register variables that were introduced during TheoryEngine preprocessing |
1543 |
3862 |
std::unordered_set<Node> ceSyms; |
1544 |
1931 |
expr::getSymbols(lem, ceSyms); |
1545 |
3862 |
std::unordered_set<Node> qSyms; |
1546 |
1931 |
expr::getSymbols(d_quant, qSyms); |
1547 |
|
// all variables that are in counterexample lemma but not in quantified |
1548 |
|
// formula |
1549 |
12171 |
for (const Node& ces : ceSyms) |
1550 |
|
{ |
1551 |
10240 |
if (qSyms.find(ces) != qSyms.end()) |
1552 |
|
{ |
1553 |
|
// a free symbol of the quantified formula. |
1554 |
12277 |
continue; |
1555 |
|
} |
1556 |
7140 |
if (std::find(d_vars.begin(), d_vars.end(), ces) != d_vars.end()) |
1557 |
|
{ |
1558 |
|
// already processed variable |
1559 |
3924 |
continue; |
1560 |
|
} |
1561 |
|
// must avoid selector symbols, and function skolems introduced by |
1562 |
|
// theory preprocessing |
1563 |
4279 |
TypeNode ct = ces.getType(); |
1564 |
3216 |
if (ct.isBoolean() || ct.isFunctionLike()) |
1565 |
|
{ |
1566 |
|
// Boolean variables, including the counterexample literal, don't matter |
1567 |
|
// since they are always assigned a model value. |
1568 |
2153 |
continue; |
1569 |
|
} |
1570 |
2126 |
Trace("cegqi-reg") << " register theory preprocess variable : " << ces |
1571 |
1063 |
<< std::endl; |
1572 |
|
// register the variable, which was introduced by TheoryEngine's preprocess |
1573 |
|
// method, e.g. an ITE skolem. |
1574 |
1063 |
registerVariable(ces); |
1575 |
|
} |
1576 |
|
|
1577 |
|
// determine variable order: must do Reals before Ints |
1578 |
1931 |
Trace("cegqi-debug") << "Determine variable order..." << std::endl; |
1579 |
1931 |
if (!d_vars.empty()) |
1580 |
|
{ |
1581 |
3862 |
std::map<Node, unsigned> voo; |
1582 |
1931 |
bool doSort = false; |
1583 |
3862 |
std::vector<Node> vars; |
1584 |
3862 |
std::map<TypeNode, std::vector<Node> > tvars; |
1585 |
7244 |
for (unsigned i = 0, size = d_vars.size(); i < size; i++) |
1586 |
|
{ |
1587 |
5313 |
voo[d_vars[i]] = i; |
1588 |
5313 |
d_var_order_index.push_back(0); |
1589 |
10626 |
TypeNode tn = d_vars[i].getType(); |
1590 |
5313 |
if (tn.isInteger()) |
1591 |
|
{ |
1592 |
2910 |
doSort = true; |
1593 |
2910 |
tvars[tn].push_back(d_vars[i]); |
1594 |
|
} |
1595 |
|
else |
1596 |
|
{ |
1597 |
2403 |
vars.push_back(d_vars[i]); |
1598 |
|
} |
1599 |
|
} |
1600 |
1931 |
if (doSort) |
1601 |
|
{ |
1602 |
814 |
Trace("cegqi-debug") << "Sort variables based on ordering." << std::endl; |
1603 |
1628 |
for (std::pair<const TypeNode, std::vector<Node> >& vs : tvars) |
1604 |
|
{ |
1605 |
814 |
vars.insert(vars.end(), vs.second.begin(), vs.second.end()); |
1606 |
|
} |
1607 |
|
|
1608 |
814 |
Trace("cegqi-debug") << "Consider variables in this order : " << std::endl; |
1609 |
4023 |
for (unsigned i = 0; i < vars.size(); i++) |
1610 |
|
{ |
1611 |
3209 |
d_var_order_index[voo[vars[i]]] = i; |
1612 |
6418 |
Trace("cegqi-debug") << " " << vars[i] << " : " << vars[i].getType() |
1613 |
3209 |
<< ", index was : " << voo[vars[i]] << std::endl; |
1614 |
3209 |
d_vars[i] = vars[i]; |
1615 |
|
} |
1616 |
814 |
Trace("cegqi-debug") << std::endl; |
1617 |
|
} |
1618 |
|
else |
1619 |
|
{ |
1620 |
1117 |
d_var_order_index.clear(); |
1621 |
|
} |
1622 |
|
} |
1623 |
|
|
1624 |
|
// collect atoms from all lemmas: we will only solve for literals coming from |
1625 |
|
// the original body |
1626 |
1931 |
d_is_nested_quant = false; |
1627 |
3862 |
std::map< Node, bool > visited; |
1628 |
1931 |
collectCeAtoms(lem, visited); |
1629 |
2070 |
for (const Node& alem : auxLems) |
1630 |
|
{ |
1631 |
139 |
collectCeAtoms(alem, visited); |
1632 |
|
} |
1633 |
1931 |
} |
1634 |
|
|
1635 |
3530 |
Instantiator::Instantiator(Env& env, TypeNode tn) : EnvObj(env), d_type(tn) |
1636 |
|
{ |
1637 |
3530 |
d_closed_enum_type = tn.isClosedEnumerable(); |
1638 |
3530 |
} |
1639 |
|
|
1640 |
14 |
bool Instantiator::processEqualTerm(CegInstantiator* ci, |
1641 |
|
SolvedForm& sf, |
1642 |
|
Node pv, |
1643 |
|
TermProperties& pv_prop, |
1644 |
|
Node n, |
1645 |
|
CegInstEffort effort) |
1646 |
|
{ |
1647 |
14 |
pv_prop.d_type = CEG_TT_EQUAL; |
1648 |
14 |
return ci->constructInstantiationInc(pv, n, pv_prop, sf); |
1649 |
|
} |
1650 |
|
|
1651 |
|
} // namespace quantifiers |
1652 |
|
} // namespace theory |
1653 |
31125 |
} // namespace cvc5 |