1 |
|
/****************************************************************************** |
2 |
|
* Top contributors (to current version): |
3 |
|
* Andrew Reynolds, Tim King, Andres Noetzli |
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 |
|
* Implements conflict-based instantiation (Reynolds et al FMCAD 2014). |
14 |
|
*/ |
15 |
|
|
16 |
|
#include "theory/quantifiers/quant_conflict_find.h" |
17 |
|
|
18 |
|
#include "base/configuration.h" |
19 |
|
#include "expr/node_algorithm.h" |
20 |
|
#include "options/quantifiers_options.h" |
21 |
|
#include "options/theory_options.h" |
22 |
|
#include "options/uf_options.h" |
23 |
|
#include "smt/smt_statistics_registry.h" |
24 |
|
#include "theory/quantifiers/ematching/trigger_term_info.h" |
25 |
|
#include "theory/quantifiers/first_order_model.h" |
26 |
|
#include "theory/quantifiers/instantiate.h" |
27 |
|
#include "theory/quantifiers/quant_util.h" |
28 |
|
#include "theory/quantifiers/term_database.h" |
29 |
|
#include "theory/quantifiers/term_util.h" |
30 |
|
#include "theory/rewriter.h" |
31 |
|
|
32 |
|
using namespace cvc5::kind; |
33 |
|
using namespace std; |
34 |
|
|
35 |
|
namespace cvc5 { |
36 |
|
namespace theory { |
37 |
|
namespace quantifiers { |
38 |
|
|
39 |
21994 |
QuantInfo::QuantInfo() |
40 |
21994 |
: d_unassigned_nvar(0), d_una_index(0), d_parent(nullptr), d_mg(nullptr) |
41 |
|
{ |
42 |
21994 |
} |
43 |
|
|
44 |
43988 |
QuantInfo::~QuantInfo() { |
45 |
21994 |
delete d_mg; |
46 |
103107 |
for(std::map< int, MatchGen * >::iterator i = d_var_mg.begin(), |
47 |
21994 |
iend=d_var_mg.end(); i != iend; ++i) { |
48 |
81113 |
MatchGen* currentMatchGenerator = (*i).second; |
49 |
81113 |
delete currentMatchGenerator; |
50 |
|
} |
51 |
21994 |
d_var_mg.clear(); |
52 |
21994 |
} |
53 |
|
|
54 |
188309 |
QuantifiersInferenceManager& QuantInfo::getInferenceManager() |
55 |
|
{ |
56 |
188309 |
Assert(d_parent != nullptr); |
57 |
188309 |
return d_parent->getInferenceManager(); |
58 |
|
} |
59 |
|
|
60 |
21994 |
void QuantInfo::initialize( QuantConflictFind * p, Node q, Node qn ) { |
61 |
21994 |
d_parent = p; |
62 |
21994 |
d_q = q; |
63 |
21994 |
d_extra_var.clear(); |
64 |
74044 |
for( unsigned i=0; i<q[0].getNumChildren(); i++ ){ |
65 |
52050 |
d_match.push_back( TNode::null() ); |
66 |
52050 |
d_match_term.push_back( TNode::null() ); |
67 |
|
} |
68 |
|
|
69 |
|
//register the variables |
70 |
74044 |
for( unsigned i=0; i<q[0].getNumChildren(); i++ ){ |
71 |
52050 |
d_var_num[q[0][i]] = i; |
72 |
52050 |
d_vars.push_back( q[0][i] ); |
73 |
52050 |
d_var_types.push_back( q[0][i].getType() ); |
74 |
|
} |
75 |
|
|
76 |
21994 |
registerNode( qn, true, true ); |
77 |
|
|
78 |
|
|
79 |
21994 |
Trace("qcf-qregister") << "- Make match gen structure..." << std::endl; |
80 |
21994 |
d_mg = new MatchGen( this, qn ); |
81 |
|
|
82 |
21994 |
if( d_mg->isValid() ){ |
83 |
|
/* |
84 |
|
for( unsigned j=0; j<q[0].getNumChildren(); j++ ){ |
85 |
|
if( d_inMatchConstraint.find( q[0][j] )==d_inMatchConstraint.end() ){ |
86 |
|
Trace("qcf-invalid") << "QCF invalid : variable " << q[0][j] << " does not exist in a matching constraint." << std::endl; |
87 |
|
d_mg->setInvalid(); |
88 |
|
break; |
89 |
|
} |
90 |
|
} |
91 |
|
*/ |
92 |
103888 |
for( unsigned j=q[0].getNumChildren(); j<d_vars.size(); j++ ){ |
93 |
86406 |
if( d_vars[j].getKind()!=BOUND_VARIABLE ){ |
94 |
81113 |
d_var_mg[j] = NULL; |
95 |
81113 |
bool is_tsym = false; |
96 |
81113 |
if( !MatchGen::isHandledUfTerm( d_vars[j] ) && d_vars[j].getKind()!=ITE ){ |
97 |
898 |
is_tsym = true; |
98 |
898 |
d_tsym_vars.push_back( j ); |
99 |
|
} |
100 |
81113 |
if( !is_tsym || options::qcfTConstraint() ){ |
101 |
80594 |
d_var_mg[j] = new MatchGen( this, d_vars[j], true ); |
102 |
|
} |
103 |
81113 |
if( !d_var_mg[j] || !d_var_mg[j]->isValid() ){ |
104 |
1678 |
Trace("qcf-invalid") << "QCF invalid : cannot match for " << d_vars[j] << std::endl; |
105 |
1678 |
d_mg->setInvalid(); |
106 |
1678 |
break; |
107 |
|
}else{ |
108 |
158870 |
std::vector< int > bvars; |
109 |
79435 |
d_var_mg[j]->determineVariableOrder( this, bvars ); |
110 |
|
} |
111 |
|
} |
112 |
|
} |
113 |
19160 |
if( d_mg->isValid() ){ |
114 |
34964 |
std::vector< int > bvars; |
115 |
17482 |
d_mg->determineVariableOrder( this, bvars ); |
116 |
|
} |
117 |
|
}else{ |
118 |
2834 |
Trace("qcf-invalid") << "QCF invalid : body of formula cannot be processed." << std::endl; |
119 |
|
} |
120 |
21994 |
Trace("qcf-qregister-summary") << "QCF register : " << ( d_mg->isValid() ? "VALID " : "INVALID" ) << " : " << q << std::endl; |
121 |
|
|
122 |
39476 |
if( d_mg->isValid() && options::qcfEagerCheckRd() ){ |
123 |
|
//optimization : record variable argument positions for terms that must be matched |
124 |
34964 |
std::vector< TNode > vars; |
125 |
|
//TODO: revisit this, makes QCF faster, but misses conflicts due to caring about paths that may not be relevant (starExec jobs 14136/14137) |
126 |
34964 |
if( options::qcfSkipRd() ){ |
127 |
|
for( unsigned j=q[0].getNumChildren(); j<d_vars.size(); j++ ){ |
128 |
|
vars.push_back( d_vars[j] ); |
129 |
|
} |
130 |
|
}else{ |
131 |
|
//get all variables that are always relevant |
132 |
34964 |
std::map< TNode, bool > visited; |
133 |
17482 |
getPropagateVars( p, vars, q[1], false, visited ); |
134 |
|
} |
135 |
99421 |
for( unsigned j=0; j<vars.size(); j++ ){ |
136 |
163878 |
Node v = vars[j]; |
137 |
163878 |
TNode f = p->getTermDatabase()->getMatchOperator( v ); |
138 |
81939 |
if( !f.isNull() ){ |
139 |
49737 |
Trace("qcf-opt") << "Record variable argument positions in " << v << ", op=" << f << "..." << std::endl; |
140 |
161630 |
for( unsigned k=0; k<v.getNumChildren(); k++ ){ |
141 |
223786 |
Node n = v[k]; |
142 |
111893 |
std::map< TNode, int >::iterator itv = d_var_num.find( n ); |
143 |
111893 |
if( itv!=d_var_num.end() ){ |
144 |
97973 |
Trace("qcf-opt") << " arg " << k << " is var #" << itv->second << std::endl; |
145 |
97973 |
if( std::find( d_var_rel_dom[itv->second][f].begin(), d_var_rel_dom[itv->second][f].end(), k )==d_var_rel_dom[itv->second][f].end() ){ |
146 |
92502 |
d_var_rel_dom[itv->second][f].push_back( k ); |
147 |
|
} |
148 |
|
} |
149 |
|
} |
150 |
|
} |
151 |
|
} |
152 |
|
} |
153 |
21994 |
} |
154 |
|
|
155 |
210527 |
void QuantInfo::getPropagateVars( QuantConflictFind * p, std::vector< TNode >& vars, TNode n, bool pol, std::map< TNode, bool >& visited ){ |
156 |
210527 |
std::map< TNode, bool >::iterator itv = visited.find( n ); |
157 |
210527 |
if( itv==visited.end() ){ |
158 |
153411 |
visited[n] = true; |
159 |
153411 |
bool rec = true; |
160 |
153411 |
bool newPol = pol; |
161 |
153411 |
if( d_var_num.find( n )!=d_var_num.end() ){ |
162 |
81939 |
Assert(std::find(vars.begin(), vars.end(), n) == vars.end()); |
163 |
81939 |
vars.push_back( n ); |
164 |
163878 |
TNode f = p->getTermDatabase()->getMatchOperator( n ); |
165 |
81939 |
if( !f.isNull() ){ |
166 |
49737 |
if( std::find( p->d_func_rel_dom[f].begin(), p->d_func_rel_dom[f].end(), d_q )==p->d_func_rel_dom[f].end() ){ |
167 |
38268 |
p->d_func_rel_dom[f].push_back( d_q ); |
168 |
|
} |
169 |
|
} |
170 |
71472 |
}else if( MatchGen::isHandledBoolConnective( n ) ){ |
171 |
28459 |
Assert(n.getKind() != IMPLIES); |
172 |
28459 |
QuantPhaseReq::getEntailPolarity( n, 0, true, pol, rec, newPol ); |
173 |
|
} |
174 |
153411 |
Trace("qcf-opt-debug") << "getPropagateVars " << n << ", pol = " << pol << ", rec = " << rec << std::endl; |
175 |
153411 |
if( rec ){ |
176 |
340270 |
for( unsigned i=0; i<n.getNumChildren(); i++ ){ |
177 |
193045 |
getPropagateVars( p, vars, n[i], pol, visited ); |
178 |
|
} |
179 |
|
} |
180 |
|
} |
181 |
210527 |
} |
182 |
|
|
183 |
2628735 |
bool QuantInfo::isBaseMatchComplete() { |
184 |
2628735 |
return d_vars_set.size()==(d_q[0].getNumChildren()+d_extra_var.size()); |
185 |
|
} |
186 |
|
|
187 |
114444 |
void QuantInfo::registerNode( Node n, bool hasPol, bool pol, bool beneathQuant ) { |
188 |
114444 |
Trace("qcf-qregister-debug2") << "Register : " << n << std::endl; |
189 |
114444 |
if( n.getKind()==FORALL ){ |
190 |
4319 |
registerNode( n[1], hasPol, pol, true ); |
191 |
|
}else{ |
192 |
110125 |
if( !MatchGen::isHandledBoolConnective( n ) ){ |
193 |
60860 |
if (expr::hasBoundVar(n)) |
194 |
|
{ |
195 |
|
// literals |
196 |
60658 |
if (n.getKind() == EQUAL) |
197 |
|
{ |
198 |
102354 |
for (unsigned i = 0; i < n.getNumChildren(); i++) |
199 |
|
{ |
200 |
68236 |
flatten(n[i], beneathQuant); |
201 |
|
} |
202 |
|
} |
203 |
26540 |
else if (MatchGen::isHandledUfTerm(n)) |
204 |
|
{ |
205 |
18635 |
flatten(n, beneathQuant); |
206 |
|
} |
207 |
7905 |
else if (n.getKind() == ITE) |
208 |
|
{ |
209 |
4107 |
for (unsigned i = 1; i <= 2; i++) |
210 |
|
{ |
211 |
2738 |
flatten(n[i], beneathQuant); |
212 |
|
} |
213 |
1369 |
registerNode(n[0], false, pol, beneathQuant); |
214 |
|
} |
215 |
6536 |
else if (options::qcfTConstraint()) |
216 |
|
{ |
217 |
|
// a theory-specific predicate |
218 |
1014 |
for (unsigned i = 0; i < n.getNumChildren(); i++) |
219 |
|
{ |
220 |
676 |
flatten(n[i], beneathQuant); |
221 |
|
} |
222 |
|
} |
223 |
|
} |
224 |
|
}else{ |
225 |
134658 |
for( unsigned i=0; i<n.getNumChildren(); i++ ){ |
226 |
|
bool newHasPol; |
227 |
|
bool newPol; |
228 |
85393 |
QuantPhaseReq::getPolarity( n, i, hasPol, pol, newHasPol, newPol ); |
229 |
|
//QcfNode * qcfc = new QcfNode( d_c ); |
230 |
|
//qcfc->d_parent = qcf; |
231 |
|
//qcf->d_child[i] = qcfc; |
232 |
85393 |
registerNode( n[i], newHasPol, newPol, beneathQuant ); |
233 |
|
} |
234 |
|
} |
235 |
|
} |
236 |
114444 |
} |
237 |
|
|
238 |
289784 |
void QuantInfo::flatten( Node n, bool beneathQuant ) { |
239 |
289784 |
Trace("qcf-qregister-debug2") << "Flatten : " << n << std::endl; |
240 |
289784 |
if (expr::hasBoundVar(n)) |
241 |
|
{ |
242 |
243481 |
if( n.getKind()==BOUND_VARIABLE ){ |
243 |
126527 |
d_inMatchConstraint[n] = true; |
244 |
|
} |
245 |
243481 |
if( d_var_num.find( n )==d_var_num.end() ){ |
246 |
104150 |
Trace("qcf-qregister-debug2") << "Add FLATTEN VAR : " << n << std::endl; |
247 |
104150 |
d_var_num[n] = d_vars.size(); |
248 |
104150 |
d_vars.push_back( n ); |
249 |
104150 |
d_var_types.push_back( n.getType() ); |
250 |
104150 |
d_match.push_back( TNode::null() ); |
251 |
104150 |
d_match_term.push_back( TNode::null() ); |
252 |
104150 |
if( n.getKind()==ITE ){ |
253 |
1369 |
registerNode( n, false, false ); |
254 |
102781 |
}else if( n.getKind()==BOUND_VARIABLE ){ |
255 |
6199 |
d_extra_var.push_back( n ); |
256 |
|
}else{ |
257 |
296081 |
for( unsigned i=0; i<n.getNumChildren(); i++ ){ |
258 |
199499 |
flatten( n[i], beneathQuant ); |
259 |
|
} |
260 |
|
} |
261 |
|
}else{ |
262 |
139331 |
Trace("qcf-qregister-debug2") << "...already processed" << std::endl; |
263 |
|
} |
264 |
|
}else{ |
265 |
46303 |
Trace("qcf-qregister-debug2") << "...is ground." << std::endl; |
266 |
|
} |
267 |
289784 |
} |
268 |
|
|
269 |
|
|
270 |
132302 |
bool QuantInfo::reset_round( QuantConflictFind * p ) { |
271 |
1019348 |
for( unsigned i=0; i<d_match.size(); i++ ){ |
272 |
887046 |
d_match[i] = TNode::null(); |
273 |
887046 |
d_match_term[i] = TNode::null(); |
274 |
|
} |
275 |
132302 |
d_vars_set.clear(); |
276 |
132302 |
d_curr_var_deq.clear(); |
277 |
132302 |
d_tconstraints.clear(); |
278 |
|
|
279 |
132302 |
d_mg->reset_round( p ); |
280 |
676243 |
for( std::map< int, MatchGen * >::iterator it = d_var_mg.begin(); it != d_var_mg.end(); ++it ){ |
281 |
543941 |
if (!it->second->reset_round(p)) |
282 |
|
{ |
283 |
|
return false; |
284 |
|
} |
285 |
|
} |
286 |
|
//now, reset for matching |
287 |
132302 |
d_mg->reset( p, false, this ); |
288 |
132302 |
return true; |
289 |
|
} |
290 |
|
|
291 |
7141368 |
int QuantInfo::getCurrentRepVar( int v ) { |
292 |
7141368 |
if( v!=-1 && !d_match[v].isNull() ){ |
293 |
4026352 |
int vn = getVarNum( d_match[v] ); |
294 |
4026352 |
if( vn!=-1 ){ |
295 |
|
//int vr = getCurrentRepVar( vn ); |
296 |
|
//d_match[v] = d_vars[vr]; |
297 |
|
//return vr; |
298 |
30356 |
return getCurrentRepVar( vn ); |
299 |
|
} |
300 |
|
} |
301 |
7111012 |
return v; |
302 |
|
} |
303 |
|
|
304 |
3117653 |
TNode QuantInfo::getCurrentValue( TNode n ) { |
305 |
3117653 |
int v = getVarNum( n ); |
306 |
3117653 |
if( v==-1 ){ |
307 |
1649978 |
return n; |
308 |
|
}else{ |
309 |
1467675 |
if( d_match[v].isNull() ){ |
310 |
1358112 |
return n; |
311 |
|
}else{ |
312 |
109563 |
Assert(getVarNum(d_match[v]) != v); |
313 |
109563 |
return getCurrentValue( d_match[v] ); |
314 |
|
} |
315 |
|
} |
316 |
|
} |
317 |
|
|
318 |
4 |
TNode QuantInfo::getCurrentExpValue( TNode n ) { |
319 |
4 |
int v = getVarNum( n ); |
320 |
4 |
if( v==-1 ){ |
321 |
|
return n; |
322 |
|
}else{ |
323 |
4 |
if( d_match[v].isNull() ){ |
324 |
|
return n; |
325 |
|
}else{ |
326 |
4 |
Assert(getVarNum(d_match[v]) != v); |
327 |
4 |
if( d_match_term[v].isNull() ){ |
328 |
4 |
return getCurrentValue( d_match[v] ); |
329 |
|
}else{ |
330 |
|
return d_match_term[v]; |
331 |
|
} |
332 |
|
} |
333 |
|
} |
334 |
|
} |
335 |
|
|
336 |
7298515 |
bool QuantInfo::getCurrentCanBeEqual( QuantConflictFind * p, int v, TNode n, bool chDiseq ) { |
337 |
|
//check disequalities |
338 |
7298515 |
std::map< int, std::map< TNode, int > >::iterator itd = d_curr_var_deq.find( v ); |
339 |
7298515 |
if( itd!=d_curr_var_deq.end() ){ |
340 |
8223752 |
for( std::map< TNode, int >::iterator it = itd->second.begin(); it != itd->second.end(); ++it ){ |
341 |
2622793 |
Node cv = getCurrentValue( it->first ); |
342 |
1354006 |
Debug("qcf-ccbe") << "compare " << cv << " " << n << std::endl; |
343 |
1354006 |
if( cv==n ){ |
344 |
69231 |
return false; |
345 |
1284775 |
}else if( chDiseq && !isVar( n ) && !isVar( cv ) ){ |
346 |
|
//they must actually be disequal if we are looking for conflicts |
347 |
35099 |
if( !p->areDisequal( n, cv ) ){ |
348 |
|
//TODO : check for entailed disequal |
349 |
|
|
350 |
15988 |
return false; |
351 |
|
} |
352 |
|
} |
353 |
|
} |
354 |
|
} |
355 |
7213296 |
return true; |
356 |
|
} |
357 |
|
|
358 |
|
int QuantInfo::addConstraint( QuantConflictFind * p, int v, TNode n, bool polarity ) { |
359 |
|
v = getCurrentRepVar( v ); |
360 |
|
int vn = getVarNum( n ); |
361 |
|
vn = vn==-1 ? -1 : getCurrentRepVar( vn ); |
362 |
|
n = getCurrentValue( n ); |
363 |
|
return addConstraint( p, v, n, vn, polarity, false ); |
364 |
|
} |
365 |
|
|
366 |
720233 |
int QuantInfo::addConstraint( QuantConflictFind * p, int v, TNode n, int vn, bool polarity, bool doRemove ) { |
367 |
|
//for handling equalities between variables, and disequalities involving variables |
368 |
720233 |
Debug("qcf-match-debug") << "- " << (doRemove ? "un" : "" ) << "constrain : " << v << " -> " << n << " (cv=" << getCurrentValue( n ) << ")"; |
369 |
720233 |
Debug("qcf-match-debug") << ", (vn=" << vn << "), polarity = " << polarity << std::endl; |
370 |
720233 |
Assert(doRemove || n == getCurrentValue(n)); |
371 |
720233 |
Assert(doRemove || v == getCurrentRepVar(v)); |
372 |
720233 |
Assert(doRemove || vn == getCurrentRepVar(getVarNum(n))); |
373 |
720233 |
if( polarity ){ |
374 |
496960 |
if( vn!=v ){ |
375 |
496960 |
if( doRemove ){ |
376 |
247613 |
if( vn!=-1 ){ |
377 |
|
//if set to this in the opposite direction, clean up opposite instead |
378 |
|
// std::map< int, TNode >::iterator itmn = d_match.find( vn ); |
379 |
19555 |
if( d_match[vn]==d_vars[v] ){ |
380 |
|
return addConstraint( p, vn, d_vars[v], v, true, true ); |
381 |
|
}else{ |
382 |
|
//unsetting variables equal |
383 |
19555 |
std::map< int, std::map< TNode, int > >::iterator itd = d_curr_var_deq.find( vn ); |
384 |
19555 |
if( itd!=d_curr_var_deq.end() ){ |
385 |
|
//remove disequalities owned by this |
386 |
22554 |
std::vector< TNode > remDeq; |
387 |
11437 |
for( std::map< TNode, int >::iterator it = itd->second.begin(); it != itd->second.end(); ++it ){ |
388 |
160 |
if( it->second==v ){ |
389 |
160 |
remDeq.push_back( it->first ); |
390 |
|
} |
391 |
|
} |
392 |
11437 |
for( unsigned i=0; i<remDeq.size(); i++ ){ |
393 |
160 |
d_curr_var_deq[vn].erase( remDeq[i] ); |
394 |
|
} |
395 |
|
} |
396 |
|
} |
397 |
|
} |
398 |
247613 |
unsetMatch( p, v ); |
399 |
247613 |
return 1; |
400 |
|
}else{ |
401 |
|
//std::map< int, TNode >::iterator itm = d_match.find( v ); |
402 |
249347 |
bool isGroundRep = false; |
403 |
249347 |
bool isGround = false; |
404 |
249347 |
if( vn!=-1 ){ |
405 |
19777 |
Debug("qcf-match-debug") << " ...Variable bound to variable" << std::endl; |
406 |
|
//std::map< int, TNode >::iterator itmn = d_match.find( vn ); |
407 |
19777 |
if( d_match[v].isNull() ){ |
408 |
|
//setting variables equal |
409 |
19777 |
bool alreadySet = false; |
410 |
19777 |
if( !d_match[vn].isNull() ){ |
411 |
|
alreadySet = true; |
412 |
|
Assert(!isVar(d_match[vn])); |
413 |
|
} |
414 |
|
|
415 |
|
//copy or check disequalities |
416 |
19777 |
std::map< int, std::map< TNode, int > >::iterator itd = d_curr_var_deq.find( v ); |
417 |
19777 |
if( itd!=d_curr_var_deq.end() ){ |
418 |
13452 |
for( std::map< TNode, int >::iterator it = itd->second.begin(); it != itd->second.end(); ++it ){ |
419 |
320 |
Node dv = getCurrentValue( it->first ); |
420 |
160 |
if( !alreadySet ){ |
421 |
160 |
if( d_curr_var_deq[vn].find( dv )==d_curr_var_deq[vn].end() ){ |
422 |
160 |
d_curr_var_deq[vn][dv] = v; |
423 |
|
} |
424 |
|
}else{ |
425 |
|
if( !p->areMatchDisequal( d_match[vn], dv ) ){ |
426 |
|
Debug("qcf-match-debug") << " -> fail, conflicting disequality" << std::endl; |
427 |
|
return -1; |
428 |
|
} |
429 |
|
} |
430 |
|
} |
431 |
|
} |
432 |
19777 |
if( alreadySet ){ |
433 |
|
n = getCurrentValue( n ); |
434 |
|
} |
435 |
|
}else{ |
436 |
|
if( d_match[vn].isNull() ){ |
437 |
|
Debug("qcf-match-debug") << " ...Reverse direction" << std::endl; |
438 |
|
//set the opposite direction |
439 |
|
return addConstraint( p, vn, d_vars[v], v, true, false ); |
440 |
|
}else{ |
441 |
|
Debug("qcf-match-debug") << " -> Both variables bound, compare" << std::endl; |
442 |
|
//are they currently equal |
443 |
|
return p->areMatchEqual( d_match[v], d_match[vn] ) ? 0 : -1; |
444 |
|
} |
445 |
|
} |
446 |
|
}else{ |
447 |
229570 |
Debug("qcf-match-debug") << " ...Variable bound to ground" << std::endl; |
448 |
229570 |
if( d_match[v].isNull() ){ |
449 |
|
//isGroundRep = true; ?? |
450 |
229570 |
isGround = true; |
451 |
|
}else{ |
452 |
|
//compare ground values |
453 |
|
Debug("qcf-match-debug") << " -> Ground value, compare " << d_match[v] << " "<< n << std::endl; |
454 |
|
return p->areMatchEqual( d_match[v], n ) ? 0 : -1; |
455 |
|
} |
456 |
|
} |
457 |
249347 |
if( setMatch( p, v, n, isGroundRep, isGround ) ){ |
458 |
249327 |
Debug("qcf-match-debug") << " -> success" << std::endl; |
459 |
249327 |
return 1; |
460 |
|
}else{ |
461 |
20 |
Debug("qcf-match-debug") << " -> fail, conflicting disequality" << std::endl; |
462 |
20 |
return -1; |
463 |
|
} |
464 |
|
} |
465 |
|
}else{ |
466 |
|
Debug("qcf-match-debug") << " -> redundant, variable identity" << std::endl; |
467 |
|
return 0; |
468 |
|
} |
469 |
|
}else{ |
470 |
223273 |
if( vn==v ){ |
471 |
|
Debug("qcf-match-debug") << " -> fail, variable identity" << std::endl; |
472 |
|
return -1; |
473 |
|
}else{ |
474 |
223273 |
if( doRemove ){ |
475 |
111321 |
Assert(d_curr_var_deq[v].find(n) != d_curr_var_deq[v].end()); |
476 |
111321 |
d_curr_var_deq[v].erase( n ); |
477 |
111321 |
return 1; |
478 |
|
}else{ |
479 |
111952 |
if( d_curr_var_deq[v].find( n )==d_curr_var_deq[v].end() ){ |
480 |
|
//check if it respects equality |
481 |
|
//std::map< int, TNode >::iterator itm = d_match.find( v ); |
482 |
111832 |
if( !d_match[v].isNull() ){ |
483 |
|
TNode nv = getCurrentValue( n ); |
484 |
|
if( !p->areMatchDisequal( nv, d_match[v] ) ){ |
485 |
|
Debug("qcf-match-debug") << " -> fail, conflicting disequality" << std::endl; |
486 |
|
return -1; |
487 |
|
} |
488 |
|
} |
489 |
111832 |
d_curr_var_deq[v][n] = v; |
490 |
111832 |
Debug("qcf-match-debug") << " -> success" << std::endl; |
491 |
111832 |
return 1; |
492 |
|
}else{ |
493 |
120 |
Debug("qcf-match-debug") << " -> redundant disequality" << std::endl; |
494 |
120 |
return 0; |
495 |
|
} |
496 |
|
} |
497 |
|
} |
498 |
|
} |
499 |
|
} |
500 |
|
|
501 |
88 |
bool QuantInfo::isConstrainedVar( int v ) { |
502 |
88 |
if( d_curr_var_deq.find( v )!=d_curr_var_deq.end() && !d_curr_var_deq[v].empty() ){ |
503 |
|
return true; |
504 |
|
}else{ |
505 |
176 |
Node vv = getVar( v ); |
506 |
|
//for( std::map< int, TNode >::iterator it = d_match.begin(); it != d_match.end(); ++it ){ |
507 |
1200 |
for( unsigned i=0; i<d_match.size(); i++ ){ |
508 |
1112 |
if( d_match[i]==vv ){ |
509 |
|
return true; |
510 |
|
} |
511 |
|
} |
512 |
616 |
for( std::map< int, std::map< TNode, int > >::iterator it = d_curr_var_deq.begin(); it != d_curr_var_deq.end(); ++it ){ |
513 |
592 |
for( std::map< TNode, int >::iterator it2 = it->second.begin(); it2 != it->second.end(); ++it2 ){ |
514 |
64 |
if( it2->first==vv ){ |
515 |
|
return true; |
516 |
|
} |
517 |
|
} |
518 |
|
} |
519 |
88 |
return false; |
520 |
|
} |
521 |
|
} |
522 |
|
|
523 |
4565660 |
bool QuantInfo::setMatch( QuantConflictFind * p, int v, TNode n, bool isGroundRep, bool isGround ) { |
524 |
4565660 |
if( getCurrentCanBeEqual( p, v, n ) ){ |
525 |
4519589 |
if( isGroundRep ){ |
526 |
|
//fail if n does not exist in the relevant domain of each of the argument positions |
527 |
4268824 |
std::map< int, std::map< TNode, std::vector< unsigned > > >::iterator it = d_var_rel_dom.find( v ); |
528 |
4268824 |
if( it!=d_var_rel_dom.end() ){ |
529 |
3343415 |
for( std::map< TNode, std::vector< unsigned > >::iterator it2 = it->second.begin(); it2 != it->second.end(); ++it2 ){ |
530 |
4031028 |
for( unsigned j=0; j<it2->second.size(); j++ ){ |
531 |
2162772 |
Debug("qcf-match-debug2") << n << " in relevant domain " << it2->first << "." << it2->second[j] << "?" << std::endl; |
532 |
2162772 |
if( !p->getTermDatabase()->inRelevantDomain( it2->first, it2->second[j], n ) ){ |
533 |
220429 |
Debug("qcf-match-debug") << " -> fail, since " << n << " is not in relevant domain of " << it2->first << "." << it2->second[j] << std::endl; |
534 |
220429 |
return false; |
535 |
|
} |
536 |
|
} |
537 |
|
} |
538 |
|
} |
539 |
|
} |
540 |
4299160 |
Debug("qcf-match-debug") << "-- bind : " << v << " -> " << n << ", checked " << d_curr_var_deq[v].size() << " disequalities" << std::endl; |
541 |
4299160 |
if( isGround ){ |
542 |
4279383 |
if( d_vars[v].getKind()==BOUND_VARIABLE ){ |
543 |
1821883 |
d_vars_set[v] = true; |
544 |
1821883 |
Debug("qcf-match-debug") << "---- now bound " << d_vars_set.size() << " / " << d_q[0].getNumChildren() << " base variables." << std::endl; |
545 |
|
} |
546 |
|
} |
547 |
4299160 |
d_match[v] = n; |
548 |
4299160 |
return true; |
549 |
|
}else{ |
550 |
46071 |
return false; |
551 |
|
} |
552 |
|
} |
553 |
|
|
554 |
2762289 |
void QuantInfo::unsetMatch( QuantConflictFind * p, int v ) { |
555 |
2762289 |
Debug("qcf-match-debug") << "-- unbind : " << v << std::endl; |
556 |
2762289 |
if( d_vars[v].getKind()==BOUND_VARIABLE && d_vars_set.find( v )!=d_vars_set.end() ){ |
557 |
1033754 |
d_vars_set.erase( v ); |
558 |
|
} |
559 |
2762289 |
d_match[ v ] = TNode::null(); |
560 |
2762289 |
} |
561 |
|
|
562 |
496739 |
bool QuantInfo::isMatchSpurious( QuantConflictFind * p ) { |
563 |
3999589 |
for( int i=0; i<getNumVars(); i++ ){ |
564 |
|
//std::map< int, TNode >::iterator it = d_match.find( i ); |
565 |
3541998 |
if( !d_match[i].isNull() ){ |
566 |
2732855 |
if (!getCurrentCanBeEqual(p, i, d_match[i], p->atConflictEffort())) { |
567 |
39148 |
return true; |
568 |
|
} |
569 |
|
} |
570 |
|
} |
571 |
457591 |
return false; |
572 |
|
} |
573 |
|
|
574 |
457405 |
bool QuantInfo::isTConstraintSpurious(QuantConflictFind* p, |
575 |
|
std::vector<Node>& terms) |
576 |
|
{ |
577 |
1871560 |
if( options::qcfEagerTest() ){ |
578 |
|
//check whether the instantiation evaluates as expected |
579 |
457405 |
if (p->atConflictEffort()) { |
580 |
269096 |
Trace("qcf-instance-check") << "Possible conflict instance for " << d_q << " : " << std::endl; |
581 |
269964 |
std::map< TNode, TNode > subs; |
582 |
1058560 |
for( unsigned i=0; i<terms.size(); i++ ){ |
583 |
789464 |
Trace("qcf-instance-check") << " " << terms[i] << std::endl; |
584 |
789464 |
subs[d_q[0][i]] = terms[i]; |
585 |
|
} |
586 |
269096 |
TermDb* tdb = p->getTermDatabase(); |
587 |
269100 |
for( unsigned i=0; i<d_extra_var.size(); i++ ){ |
588 |
8 |
Node n = getCurrentExpValue( d_extra_var[i] ); |
589 |
4 |
Trace("qcf-instance-check") << " " << d_extra_var[i] << " -> " << n << std::endl; |
590 |
4 |
subs[d_extra_var[i]] = n; |
591 |
|
} |
592 |
269096 |
if (!tdb->isEntailed(d_q[1], subs, false, false)) |
593 |
|
{ |
594 |
268228 |
Trace("qcf-instance-check") << "...not entailed to be false." << std::endl; |
595 |
268228 |
return true; |
596 |
|
} |
597 |
|
}else{ |
598 |
|
Node inst = |
599 |
189565 |
getInferenceManager().getInstantiate()->getInstantiation(d_q, terms); |
600 |
188309 |
inst = Rewriter::rewrite(inst); |
601 |
|
Node inst_eval = p->getTermDatabase()->evaluateTerm( |
602 |
189565 |
inst, options::qcfTConstraint(), true); |
603 |
188309 |
if( Trace.isOn("qcf-instance-check") ){ |
604 |
|
Trace("qcf-instance-check") << "Possible propagating instance for " << d_q << " : " << std::endl; |
605 |
|
for( unsigned i=0; i<terms.size(); i++ ){ |
606 |
|
Trace("qcf-instance-check") << " " << terms[i] << std::endl; |
607 |
|
} |
608 |
|
Trace("qcf-instance-check") << "...evaluates to " << inst_eval << std::endl; |
609 |
|
} |
610 |
376618 |
if (inst_eval.isNull() |
611 |
188309 |
|| (inst_eval.isConst() && inst_eval.getConst<bool>())) |
612 |
|
{ |
613 |
187053 |
Trace("qcf-instance-check") << "...spurious." << std::endl; |
614 |
187053 |
return true; |
615 |
|
}else{ |
616 |
1256 |
if (Configuration::isDebugBuild()) |
617 |
|
{ |
618 |
1256 |
if (!p->isPropagatingInstance(inst_eval)) |
619 |
|
{ |
620 |
|
// Notice that this can happen in cases where: |
621 |
|
// (1) x = -1*y is rewritten to y = -1*x, and |
622 |
|
// (2) -1*y is a term in the master equality engine but -1*x is not. |
623 |
|
// In other words, we determined that x = -1*y is a relevant |
624 |
|
// equality to propagate since it involves two known terms, but |
625 |
|
// after rewriting, the equality y = -1*x involves an unknown term |
626 |
|
// -1*x. In this case, the equality is still relevant to propagate, |
627 |
|
// despite the above function not being precise enough to realize |
628 |
|
// it. We output a warning in debug for this. See #2993. |
629 |
|
Trace("qcf-instance-check") |
630 |
|
<< "WARNING: not propagating." << std::endl; |
631 |
|
} |
632 |
|
} |
633 |
1256 |
Trace("qcf-instance-check") << "...not spurious." << std::endl; |
634 |
|
} |
635 |
|
} |
636 |
|
} |
637 |
2124 |
if( !d_tconstraints.empty() ){ |
638 |
|
//check constraints |
639 |
28 |
for( std::map< Node, bool >::iterator it = d_tconstraints.begin(); it != d_tconstraints.end(); ++it ){ |
640 |
|
//apply substitution to the tconstraint |
641 |
16 |
Node cons = p->getQuantifiersRegistry().substituteBoundVariables( |
642 |
32 |
it->first, d_q, terms); |
643 |
16 |
cons = it->second ? cons : cons.negate(); |
644 |
16 |
if (!entailmentTest(p, cons, p->atConflictEffort())) { |
645 |
|
return true; |
646 |
|
} |
647 |
|
} |
648 |
|
} |
649 |
|
// spurious if quantifiers engine is in conflict |
650 |
2124 |
return p->d_qstate.isInConflict(); |
651 |
|
} |
652 |
|
|
653 |
16 |
bool QuantInfo::entailmentTest( QuantConflictFind * p, Node lit, bool chEnt ) { |
654 |
16 |
Trace("qcf-tconstraint-debug") << "Check : " << lit << std::endl; |
655 |
32 |
Node rew = Rewriter::rewrite( lit ); |
656 |
16 |
if (rew.isConst()) |
657 |
|
{ |
658 |
8 |
Trace("qcf-tconstraint-debug") << "...constraint " << lit << " rewrites to " |
659 |
4 |
<< rew << "." << std::endl; |
660 |
4 |
return rew.getConst<bool>(); |
661 |
|
} |
662 |
|
// if checking for conflicts, we must be sure that the (negation of) |
663 |
|
// constraint is (not) entailed |
664 |
12 |
if (!chEnt) |
665 |
|
{ |
666 |
12 |
rew = Rewriter::rewrite(rew.negate()); |
667 |
|
} |
668 |
|
// check if it is entailed |
669 |
24 |
Trace("qcf-tconstraint-debug") |
670 |
12 |
<< "Check entailment of " << rew << "..." << std::endl; |
671 |
12 |
std::pair<bool, Node> et = p->getState().getValuation().entailmentCheck( |
672 |
24 |
options::TheoryOfMode::THEORY_OF_TYPE_BASED, rew); |
673 |
12 |
++(p->d_statistics.d_entailment_checks); |
674 |
24 |
Trace("qcf-tconstraint-debug") |
675 |
12 |
<< "ET result : " << et.first << " " << et.second << std::endl; |
676 |
12 |
if (!et.first) |
677 |
|
{ |
678 |
24 |
Trace("qcf-tconstraint-debug") |
679 |
12 |
<< "...cannot show entailment of " << rew << "." << std::endl; |
680 |
12 |
return !chEnt; |
681 |
|
} |
682 |
|
return chEnt; |
683 |
|
} |
684 |
|
|
685 |
457535 |
bool QuantInfo::completeMatch( QuantConflictFind * p, std::vector< int >& assigned, bool doContinue ) { |
686 |
|
//assign values for variables that were unassigned (usually not necessary, but handles corner cases) |
687 |
457535 |
bool doFail = false; |
688 |
457535 |
bool success = true; |
689 |
457535 |
if( doContinue ){ |
690 |
|
doFail = true; |
691 |
|
success = false; |
692 |
|
}else{ |
693 |
457535 |
if( isBaseMatchComplete() && options::qcfEagerTest() ){ |
694 |
457344 |
return true; |
695 |
|
} |
696 |
|
//solve for interpreted symbol matches |
697 |
|
// this breaks the invariant that all introduced constraints are over existing terms |
698 |
199 |
for( int i=(int)(d_tsym_vars.size()-1); i>=0; i-- ){ |
699 |
8 |
int index = d_tsym_vars[i]; |
700 |
16 |
TNode v = getCurrentValue( d_vars[index] ); |
701 |
8 |
int slv_v = -1; |
702 |
8 |
if( v==d_vars[index] ){ |
703 |
8 |
slv_v = index; |
704 |
|
} |
705 |
8 |
Trace("qcf-tconstraint-debug") << "Solve " << d_vars[index] << " = " << v << " " << d_vars[index].getKind() << std::endl; |
706 |
8 |
if( d_vars[index].getKind()==PLUS || d_vars[index].getKind()==MULT ){ |
707 |
8 |
Kind k = d_vars[index].getKind(); |
708 |
16 |
std::vector< TNode > children; |
709 |
24 |
for( unsigned j=0; j<d_vars[index].getNumChildren(); j++ ){ |
710 |
16 |
int vn = getVarNum( d_vars[index][j] ); |
711 |
16 |
if( vn!=-1 ){ |
712 |
24 |
TNode vv = getCurrentValue( d_vars[index][j] ); |
713 |
12 |
if( vv==d_vars[index][j] ){ |
714 |
|
//we will assign this |
715 |
8 |
if( slv_v==-1 ){ |
716 |
|
Trace("qcf-tconstraint-debug") << "...will solve for var #" << vn << std::endl; |
717 |
|
slv_v = vn; |
718 |
|
if (!p->atConflictEffort()) { |
719 |
|
break; |
720 |
|
} |
721 |
|
}else{ |
722 |
16 |
Node z = p->getZero( k ); |
723 |
8 |
if( !z.isNull() ){ |
724 |
4 |
Trace("qcf-tconstraint-debug") << "...set " << d_vars[vn] << " = " << z << std::endl; |
725 |
4 |
assigned.push_back( vn ); |
726 |
4 |
if( !setMatch( p, vn, z, false, true ) ){ |
727 |
|
success = false; |
728 |
|
break; |
729 |
|
} |
730 |
|
} |
731 |
|
} |
732 |
|
}else{ |
733 |
4 |
Trace("qcf-tconstraint-debug") << "...sum value " << vv << std::endl; |
734 |
4 |
children.push_back( vv ); |
735 |
|
} |
736 |
|
}else{ |
737 |
4 |
Trace("qcf-tconstraint-debug") << "...sum " << d_vars[index][j] << std::endl; |
738 |
4 |
children.push_back( d_vars[index][j] ); |
739 |
|
} |
740 |
|
} |
741 |
8 |
if( success ){ |
742 |
8 |
if( slv_v!=-1 ){ |
743 |
16 |
Node lhs; |
744 |
8 |
if( children.empty() ){ |
745 |
|
lhs = p->getZero( k ); |
746 |
8 |
}else if( children.size()==1 ){ |
747 |
8 |
lhs = children[0]; |
748 |
|
}else{ |
749 |
|
lhs = NodeManager::currentNM()->mkNode( k, children ); |
750 |
|
} |
751 |
16 |
Node sum; |
752 |
8 |
if( v==d_vars[index] ){ |
753 |
8 |
sum = lhs; |
754 |
|
}else{ |
755 |
|
if (p->atConflictEffort()) { |
756 |
|
Kind kn = k; |
757 |
|
if( d_vars[index].getKind()==PLUS ){ |
758 |
|
kn = MINUS; |
759 |
|
} |
760 |
|
if( kn!=k ){ |
761 |
|
sum = NodeManager::currentNM()->mkNode( kn, v, lhs ); |
762 |
|
} |
763 |
|
} |
764 |
|
} |
765 |
8 |
if( !sum.isNull() ){ |
766 |
8 |
assigned.push_back( slv_v ); |
767 |
8 |
Trace("qcf-tconstraint-debug") << "...set " << d_vars[slv_v] << " = " << sum << std::endl; |
768 |
8 |
if( !setMatch( p, slv_v, sum, false, true ) ){ |
769 |
|
success = false; |
770 |
|
} |
771 |
8 |
p->d_tempCache.push_back( sum ); |
772 |
|
} |
773 |
|
}else{ |
774 |
|
//must show that constraint is met |
775 |
|
Node sum = NodeManager::currentNM()->mkNode( k, children ); |
776 |
|
Node eq = sum.eqNode( v ); |
777 |
|
if( !entailmentTest( p, eq ) ){ |
778 |
|
success = false; |
779 |
|
} |
780 |
|
p->d_tempCache.push_back( sum ); |
781 |
|
} |
782 |
|
} |
783 |
|
} |
784 |
|
|
785 |
8 |
if( !success ){ |
786 |
|
break; |
787 |
|
} |
788 |
|
} |
789 |
191 |
if( success ){ |
790 |
|
//check what is left to assign |
791 |
191 |
d_unassigned.clear(); |
792 |
191 |
d_unassigned_tn.clear(); |
793 |
382 |
std::vector< int > unassigned[2]; |
794 |
382 |
std::vector< TypeNode > unassigned_tn[2]; |
795 |
587 |
for( int i=0; i<getNumVars(); i++ ){ |
796 |
396 |
if( d_match[i].isNull() ){ |
797 |
318 |
int rindex = d_var_mg.find( i )==d_var_mg.end() ? 1 : 0; |
798 |
318 |
unassigned[rindex].push_back( i ); |
799 |
318 |
unassigned_tn[rindex].push_back( getVar( i ).getType() ); |
800 |
318 |
assigned.push_back( i ); |
801 |
|
} |
802 |
|
} |
803 |
191 |
d_unassigned_nvar = unassigned[0].size(); |
804 |
573 |
for( unsigned i=0; i<2; i++ ){ |
805 |
382 |
d_unassigned.insert( d_unassigned.end(), unassigned[i].begin(), unassigned[i].end() ); |
806 |
382 |
d_unassigned_tn.insert( d_unassigned_tn.end(), unassigned_tn[i].begin(), unassigned_tn[i].end() ); |
807 |
|
} |
808 |
191 |
d_una_eqc_count.clear(); |
809 |
191 |
d_una_index = 0; |
810 |
|
} |
811 |
|
} |
812 |
|
|
813 |
191 |
if( !d_unassigned.empty() && ( success || doContinue ) ){ |
814 |
186 |
Trace("qcf-check") << "Assign to unassigned (" << d_unassigned.size() << ")..." << std::endl; |
815 |
184 |
do { |
816 |
370 |
if( doFail ){ |
817 |
184 |
Trace("qcf-check-unassign") << "Failure, try again..." << std::endl; |
818 |
|
} |
819 |
370 |
bool invalidMatch = false; |
820 |
2822 |
while( ( d_una_index>=0 && (int)d_una_index<(int)d_unassigned.size() ) || invalidMatch || doFail ){ |
821 |
1226 |
invalidMatch = false; |
822 |
1226 |
if( !doFail && d_una_index==(int)d_una_eqc_count.size() ){ |
823 |
|
//check if it has now been assigned |
824 |
324 |
if( d_una_index<d_unassigned_nvar ){ |
825 |
44 |
if( !isConstrainedVar( d_unassigned[d_una_index] ) ){ |
826 |
44 |
d_una_eqc_count.push_back( -1 ); |
827 |
|
}else{ |
828 |
|
d_var_mg[ d_unassigned[d_una_index] ]->reset( p, true, this ); |
829 |
|
d_una_eqc_count.push_back( 0 ); |
830 |
|
} |
831 |
|
}else{ |
832 |
280 |
d_una_eqc_count.push_back( 0 ); |
833 |
|
} |
834 |
|
}else{ |
835 |
902 |
bool failed = false; |
836 |
902 |
if( !doFail ){ |
837 |
718 |
if( d_una_index<d_unassigned_nvar ){ |
838 |
44 |
if( !isConstrainedVar( d_unassigned[d_una_index] ) ){ |
839 |
44 |
Trace("qcf-check-unassign") << "Succeeded, variable unconstrained at " << d_una_index << std::endl; |
840 |
44 |
d_una_index++; |
841 |
|
}else if( d_var_mg[d_unassigned[d_una_index]]->getNextMatch( p, this ) ){ |
842 |
|
Trace("qcf-check-unassign") << "Succeeded match with mg at " << d_una_index << std::endl; |
843 |
|
d_una_index++; |
844 |
|
}else{ |
845 |
|
failed = true; |
846 |
|
Trace("qcf-check-unassign") << "Failed match with mg at " << d_una_index << std::endl; |
847 |
|
} |
848 |
|
}else{ |
849 |
674 |
Assert(doFail || d_una_index == (int)d_una_eqc_count.size() - 1); |
850 |
674 |
if( d_una_eqc_count[d_una_index]<(int)p->d_eqcs[d_unassigned_tn[d_una_index]].size() ){ |
851 |
471 |
int currIndex = d_una_eqc_count[d_una_index]; |
852 |
471 |
d_una_eqc_count[d_una_index]++; |
853 |
471 |
Trace("qcf-check-unassign") << d_unassigned[d_una_index] << "->" << p->d_eqcs[d_unassigned_tn[d_una_index]][currIndex] << std::endl; |
854 |
471 |
if( setMatch( p, d_unassigned[d_una_index], p->d_eqcs[d_unassigned_tn[d_una_index]][currIndex], true, true ) ){ |
855 |
334 |
d_match_term[d_unassigned[d_una_index]] = TNode::null(); |
856 |
334 |
Trace("qcf-check-unassign") << "Succeeded match " << d_una_index << std::endl; |
857 |
334 |
d_una_index++; |
858 |
|
}else{ |
859 |
137 |
Trace("qcf-check-unassign") << "Failed match " << d_una_index << std::endl; |
860 |
137 |
invalidMatch = true; |
861 |
|
} |
862 |
|
}else{ |
863 |
203 |
failed = true; |
864 |
203 |
Trace("qcf-check-unassign") << "No more matches " << d_una_index << std::endl; |
865 |
|
} |
866 |
|
} |
867 |
|
} |
868 |
902 |
if( doFail || failed ){ |
869 |
|
do{ |
870 |
387 |
if( !doFail ){ |
871 |
203 |
d_una_eqc_count.pop_back(); |
872 |
|
}else{ |
873 |
184 |
doFail = false; |
874 |
|
} |
875 |
387 |
d_una_index--; |
876 |
387 |
}while( d_una_index>=0 && d_una_eqc_count[d_una_index]==-1 ); |
877 |
|
} |
878 |
|
} |
879 |
|
} |
880 |
370 |
success = d_una_index>=0; |
881 |
370 |
if( success ){ |
882 |
240 |
doFail = true; |
883 |
240 |
Trace("qcf-check-unassign") << " Try: " << std::endl; |
884 |
680 |
for( unsigned i=0; i<d_unassigned.size(); i++ ){ |
885 |
440 |
int ui = d_unassigned[i]; |
886 |
440 |
if( !d_match[ui].isNull() ){ |
887 |
396 |
Trace("qcf-check-unassign") << " Assigned #" << ui << " : " << d_vars[ui] << " -> " << d_match[ui] << std::endl; |
888 |
|
} |
889 |
|
} |
890 |
|
} |
891 |
370 |
}while( success && isMatchSpurious( p ) ); |
892 |
186 |
Trace("qcf-check") << "done assigning." << std::endl; |
893 |
|
} |
894 |
191 |
if( success ){ |
895 |
182 |
for( unsigned i=0; i<d_unassigned.size(); i++ ){ |
896 |
121 |
int ui = d_unassigned[i]; |
897 |
121 |
if( !d_match[ui].isNull() ){ |
898 |
77 |
Trace("qcf-check") << " Assigned #" << ui << " : " << d_vars[ui] << " -> " << d_match[ui] << std::endl; |
899 |
|
} |
900 |
|
} |
901 |
61 |
return true; |
902 |
|
}else{ |
903 |
130 |
revertMatch( p, assigned ); |
904 |
130 |
assigned.clear(); |
905 |
130 |
return false; |
906 |
|
} |
907 |
|
} |
908 |
|
|
909 |
457405 |
void QuantInfo::getMatch( std::vector< Node >& terms ){ |
910 |
1780014 |
for( unsigned i=0; i<d_q[0].getNumChildren(); i++ ){ |
911 |
|
//Node cv = qi->getCurrentValue( qi->d_match[i] ); |
912 |
1322609 |
int repVar = getCurrentRepVar( i ); |
913 |
2645218 |
Node cv; |
914 |
|
//std::map< int, TNode >::iterator itmt = qi->d_match_term.find( repVar ); |
915 |
1322609 |
if( !d_match_term[repVar].isNull() ){ |
916 |
1315860 |
cv = d_match_term[repVar]; |
917 |
|
}else{ |
918 |
6749 |
cv = d_match[repVar]; |
919 |
|
} |
920 |
1322609 |
Debug("qcf-check-inst") << "INST : " << i << " -> " << cv << ", from " << d_match[i] << std::endl; |
921 |
1322609 |
terms.push_back( cv ); |
922 |
|
} |
923 |
457405 |
} |
924 |
|
|
925 |
456571 |
void QuantInfo::revertMatch( QuantConflictFind * p, std::vector< int >& assigned ) { |
926 |
456857 |
for( unsigned i=0; i<assigned.size(); i++ ){ |
927 |
286 |
unsetMatch( p, assigned[i] ); |
928 |
|
} |
929 |
456571 |
} |
930 |
|
|
931 |
|
void QuantInfo::debugPrintMatch( const char * c ) { |
932 |
|
for( int i=0; i<getNumVars(); i++ ){ |
933 |
|
Trace(c) << " " << d_vars[i] << " -> "; |
934 |
|
if( !d_match[i].isNull() ){ |
935 |
|
Trace(c) << d_match[i]; |
936 |
|
}else{ |
937 |
|
Trace(c) << "(unassigned) "; |
938 |
|
} |
939 |
|
if( !d_curr_var_deq[i].empty() ){ |
940 |
|
Trace(c) << ", DEQ{ "; |
941 |
|
for( std::map< TNode, int >::iterator it = d_curr_var_deq[i].begin(); it != d_curr_var_deq[i].end(); ++it ){ |
942 |
|
Trace(c) << it->first << " "; |
943 |
|
} |
944 |
|
Trace(c) << "}"; |
945 |
|
} |
946 |
|
if( !d_match_term[i].isNull() && d_match_term[i]!=d_match[i] ){ |
947 |
|
Trace(c) << ", EXP : " << d_match_term[i]; |
948 |
|
} |
949 |
|
Trace(c) << std::endl; |
950 |
|
} |
951 |
|
if( !d_tconstraints.empty() ){ |
952 |
|
Trace(c) << "ADDITIONAL CONSTRAINTS : " << std::endl; |
953 |
|
for( std::map< Node, bool >::iterator it = d_tconstraints.begin(); it != d_tconstraints.end(); ++it ){ |
954 |
|
Trace(c) << " " << it->first << " -> " << it->second << std::endl; |
955 |
|
} |
956 |
|
} |
957 |
|
} |
958 |
|
|
959 |
|
MatchGen::MatchGen() |
960 |
|
: d_matched_basis(), |
961 |
|
d_binding(), |
962 |
|
d_tgt(), |
963 |
|
d_tgt_orig(), |
964 |
|
d_wasSet(), |
965 |
|
d_n(), |
966 |
|
d_type( typ_invalid ), |
967 |
|
d_type_not() |
968 |
|
{ |
969 |
|
d_qni_size = 0; |
970 |
|
d_child_counter = -1; |
971 |
|
d_use_children = true; |
972 |
|
} |
973 |
|
|
974 |
|
|
975 |
158386 |
MatchGen::MatchGen( QuantInfo * qi, Node n, bool isVar ) |
976 |
|
: d_matched_basis(), |
977 |
|
d_binding(), |
978 |
|
d_tgt(), |
979 |
|
d_tgt_orig(), |
980 |
|
d_wasSet(), |
981 |
|
d_n(), |
982 |
|
d_type(), |
983 |
158386 |
d_type_not() |
984 |
|
{ |
985 |
|
//initialize temporary |
986 |
158386 |
d_child_counter = -1; |
987 |
158386 |
d_use_children = true; |
988 |
|
|
989 |
158386 |
Trace("qcf-qregister-debug") << "Make match gen for " << n << ", isVar = " << isVar << std::endl; |
990 |
316772 |
std::vector< Node > qni_apps; |
991 |
158386 |
d_qni_size = 0; |
992 |
158386 |
if( isVar ){ |
993 |
80594 |
Assert(qi->d_var_num.find(n) != qi->d_var_num.end()); |
994 |
|
// rare case where we have a free variable in an operator, we are invalid |
995 |
161188 |
if (n.getKind() == ITE |
996 |
162347 |
|| (options::ufHo() && n.getKind() == APPLY_UF |
997 |
92401 |
&& expr::hasFreeVar(n.getOperator()))) |
998 |
|
{ |
999 |
1159 |
d_type = typ_invalid; |
1000 |
|
}else{ |
1001 |
79435 |
d_type = isHandledUfTerm( n ) ? typ_var : typ_tsym; |
1002 |
79435 |
d_qni_var_num[0] = qi->getVarNum( n ); |
1003 |
79435 |
d_qni_size++; |
1004 |
79435 |
d_type_not = false; |
1005 |
79435 |
d_n = n; |
1006 |
|
//Node f = getMatchOperator( n ); |
1007 |
247695 |
for( unsigned j=0; j<d_n.getNumChildren(); j++ ){ |
1008 |
336520 |
Node nn = d_n[j]; |
1009 |
168260 |
Trace("qcf-qregister-debug") << " " << d_qni_size; |
1010 |
168260 |
if( qi->isVar( nn ) ){ |
1011 |
146274 |
int v = qi->d_var_num[nn]; |
1012 |
146274 |
Trace("qcf-qregister-debug") << " is var #" << v << std::endl; |
1013 |
146274 |
d_qni_var_num[d_qni_size] = v; |
1014 |
|
//qi->addFuncParent( v, f, j ); |
1015 |
|
}else{ |
1016 |
21986 |
Trace("qcf-qregister-debug") << " is gterm " << nn << std::endl; |
1017 |
21986 |
d_qni_gterm[d_qni_size] = nn; |
1018 |
|
} |
1019 |
168260 |
d_qni_size++; |
1020 |
|
} |
1021 |
|
} |
1022 |
|
}else{ |
1023 |
77792 |
if (expr::hasBoundVar(n)) |
1024 |
|
{ |
1025 |
77618 |
d_type_not = false; |
1026 |
77618 |
d_n = n; |
1027 |
77618 |
if( d_n.getKind()==NOT ){ |
1028 |
24462 |
d_n = d_n[0]; |
1029 |
24462 |
d_type_not = !d_type_not; |
1030 |
|
} |
1031 |
|
|
1032 |
77618 |
if( isHandledBoolConnective( d_n ) ){ |
1033 |
|
//non-literals |
1034 |
25473 |
d_type = typ_formula; |
1035 |
81694 |
for( unsigned i=0; i<d_n.getNumChildren(); i++ ){ |
1036 |
60020 |
if( d_n.getKind()!=FORALL || i==1 ){ |
1037 |
55798 |
d_children.push_back( MatchGen( qi, d_n[i], false ) ); |
1038 |
55798 |
if( !d_children[d_children.size()-1].isValid() ){ |
1039 |
3799 |
setInvalid(); |
1040 |
3799 |
break; |
1041 |
|
} |
1042 |
|
} |
1043 |
|
} |
1044 |
|
}else{ |
1045 |
52145 |
d_type = typ_invalid; |
1046 |
|
//literals |
1047 |
52145 |
if( isHandledUfTerm( d_n ) ){ |
1048 |
17710 |
Assert(qi->isVar(d_n)); |
1049 |
17710 |
d_type = typ_pred; |
1050 |
34435 |
}else if( d_n.getKind()==BOUND_VARIABLE ){ |
1051 |
161 |
Assert(d_n.getType().isBoolean()); |
1052 |
161 |
d_type = typ_bool_var; |
1053 |
34274 |
}else if( d_n.getKind()==EQUAL || options::qcfTConstraint() ){ |
1054 |
94320 |
for (unsigned i = 0; i < d_n.getNumChildren(); i++) |
1055 |
|
{ |
1056 |
62880 |
if (expr::hasBoundVar(d_n[i])) |
1057 |
|
{ |
1058 |
46325 |
if (!qi->isVar(d_n[i])) |
1059 |
|
{ |
1060 |
|
Trace("qcf-qregister-debug") |
1061 |
|
<< "ERROR : not var " << d_n[i] << std::endl; |
1062 |
|
} |
1063 |
46325 |
Assert(qi->isVar(d_n[i])); |
1064 |
46325 |
if (d_n.getKind() != EQUAL && qi->isVar(d_n[i])) |
1065 |
|
{ |
1066 |
338 |
d_qni_var_num[i + 1] = qi->d_var_num[d_n[i]]; |
1067 |
|
} |
1068 |
|
} |
1069 |
|
else |
1070 |
|
{ |
1071 |
16555 |
d_qni_gterm[i] = d_n[i]; |
1072 |
|
} |
1073 |
|
} |
1074 |
31440 |
d_type = d_n.getKind() == EQUAL ? typ_eq : typ_tconstraint; |
1075 |
31440 |
Trace("qcf-tconstraint") << "T-Constraint : " << d_n << std::endl; |
1076 |
|
} |
1077 |
|
} |
1078 |
|
}else{ |
1079 |
|
//we will just evaluate |
1080 |
174 |
d_n = n; |
1081 |
174 |
d_type = typ_ground; |
1082 |
|
} |
1083 |
|
} |
1084 |
158386 |
Trace("qcf-qregister-debug") << "Done make match gen " << n << ", type = "; |
1085 |
158386 |
debugPrintType( "qcf-qregister-debug", d_type, true ); |
1086 |
158386 |
Trace("qcf-qregister-debug") << std::endl; |
1087 |
|
//Assert( d_children.size()==d_children_order.size() ); |
1088 |
|
|
1089 |
158386 |
} |
1090 |
|
|
1091 |
471668 |
void MatchGen::collectBoundVar( QuantInfo * qi, Node n, std::vector< int >& cbvars, std::map< Node, bool >& visited, bool& hasNested ) { |
1092 |
471668 |
if( visited.find( n )==visited.end() ){ |
1093 |
404582 |
visited[n] = true; |
1094 |
404582 |
if( n.getKind()==FORALL ){ |
1095 |
3501 |
hasNested = true; |
1096 |
|
} |
1097 |
404582 |
int v = qi->getVarNum( n ); |
1098 |
404582 |
if( v!=-1 && std::find( cbvars.begin(), cbvars.end(), v )==cbvars.end() ){ |
1099 |
260100 |
cbvars.push_back( v ); |
1100 |
|
} |
1101 |
831657 |
for( unsigned i=0; i<n.getNumChildren(); i++ ){ |
1102 |
427075 |
collectBoundVar( qi, n[i], cbvars, visited, hasNested ); |
1103 |
|
} |
1104 |
|
} |
1105 |
471668 |
} |
1106 |
|
|
1107 |
141510 |
void MatchGen::determineVariableOrder( QuantInfo * qi, std::vector< int >& bvars ) { |
1108 |
141510 |
Trace("qcf-qregister-debug") << "Determine variable order " << d_n << ", #bvars = " << bvars.size() << std::endl; |
1109 |
141510 |
bool isComm = d_type==typ_formula && ( d_n.getKind()==OR || d_n.getKind()==AND || d_n.getKind()==EQUAL ); |
1110 |
141510 |
if( isComm ){ |
1111 |
31944 |
std::map< int, std::vector< int > > c_to_vars; |
1112 |
31944 |
std::map< int, std::vector< int > > vars_to_c; |
1113 |
31944 |
std::map< int, int > vb_count; |
1114 |
31944 |
std::map< int, int > vu_count; |
1115 |
31944 |
std::map< int, bool > has_nested; |
1116 |
31944 |
std::vector< bool > assigned; |
1117 |
15972 |
Trace("qcf-qregister-debug") << "Calculate bound variables..." << std::endl; |
1118 |
56518 |
for( unsigned i=0; i<d_children.size(); i++ ){ |
1119 |
81092 |
std::map< Node, bool > visited; |
1120 |
40546 |
has_nested[i] = false; |
1121 |
40546 |
collectBoundVar( qi, d_children[i].d_n, c_to_vars[i], visited, has_nested[i] ); |
1122 |
40546 |
assigned.push_back( false ); |
1123 |
40546 |
vb_count[i] = 0; |
1124 |
40546 |
vu_count[i] = 0; |
1125 |
247605 |
for( unsigned j=0; j<c_to_vars[i].size(); j++ ){ |
1126 |
207059 |
int v = c_to_vars[i][j]; |
1127 |
207059 |
vars_to_c[v].push_back( i ); |
1128 |
207059 |
if( std::find( bvars.begin(), bvars.end(), v )==bvars.end() ){ |
1129 |
188867 |
vu_count[i]++; |
1130 |
|
}else{ |
1131 |
18192 |
vb_count[i]++; |
1132 |
|
} |
1133 |
|
} |
1134 |
|
} |
1135 |
|
//children that bind no unbound variable, then the most number of bound, unbound variables go first |
1136 |
15972 |
Trace("qcf-qregister-vo") << "Variable order for " << d_n << " : " << std::endl; |
1137 |
24574 |
do { |
1138 |
40546 |
int min_score0 = -1; |
1139 |
40546 |
int min_score = -1; |
1140 |
40546 |
int min_score_index = -1; |
1141 |
749140 |
for( unsigned i=0; i<d_children.size(); i++ ){ |
1142 |
708594 |
if( !assigned[i] ){ |
1143 |
374570 |
Trace("qcf-qregister-debug2") << "Child " << i << " has b/ub : " << vb_count[i] << "/" << vu_count[i] << std::endl; |
1144 |
374570 |
int score0 = 0;//has_nested[i] ? 0 : 1; |
1145 |
|
int score; |
1146 |
749140 |
if( !options::qcfVoExp() ){ |
1147 |
374570 |
score = vu_count[i]; |
1148 |
|
}else{ |
1149 |
|
score = vu_count[i]==0 ? 0 : ( 1 + qi->d_vars.size()*( qi->d_vars.size() - vb_count[i] ) + ( qi->d_vars.size() - vu_count[i] ) ); |
1150 |
|
} |
1151 |
374570 |
if( min_score==-1 || score0<min_score0 || ( score0==min_score0 && score<min_score ) ){ |
1152 |
68720 |
min_score0 = score0; |
1153 |
68720 |
min_score = score; |
1154 |
68720 |
min_score_index = i; |
1155 |
|
} |
1156 |
|
} |
1157 |
|
} |
1158 |
40546 |
Trace("qcf-qregister-vo") << " " << d_children_order.size()+1 << ": " << d_children[min_score_index].d_n << " : "; |
1159 |
40546 |
Trace("qcf-qregister-vo") << vu_count[min_score_index] << " " << vb_count[min_score_index] << " " << has_nested[min_score_index] << std::endl; |
1160 |
40546 |
Trace("qcf-qregister-debug") << "...assign child " << min_score_index << std::endl; |
1161 |
40546 |
Trace("qcf-qregister-debug") << "...score : " << min_score << std::endl; |
1162 |
40546 |
Assert(min_score_index != -1); |
1163 |
|
//add to children order |
1164 |
40546 |
d_children_order.push_back( min_score_index ); |
1165 |
40546 |
assigned[min_score_index] = true; |
1166 |
|
//determine order internal to children |
1167 |
40546 |
d_children[min_score_index].determineVariableOrder( qi, bvars ); |
1168 |
40546 |
Trace("qcf-qregister-debug") << "...bind variables" << std::endl; |
1169 |
|
//now, make it a bound variable |
1170 |
40546 |
if( vu_count[min_score_index]>0 ){ |
1171 |
227710 |
for( unsigned i=0; i<c_to_vars[min_score_index].size(); i++ ){ |
1172 |
189637 |
int v = c_to_vars[min_score_index][i]; |
1173 |
189637 |
if( std::find( bvars.begin(), bvars.end(), v )==bvars.end() ){ |
1174 |
241862 |
for( unsigned j=0; j<vars_to_c[v].size(); j++ ){ |
1175 |
157993 |
int vc = vars_to_c[v][j]; |
1176 |
157993 |
vu_count[vc]--; |
1177 |
157993 |
vb_count[vc]++; |
1178 |
|
} |
1179 |
83869 |
bvars.push_back( v ); |
1180 |
|
} |
1181 |
|
} |
1182 |
|
} |
1183 |
40546 |
Trace("qcf-qregister-debug") << "...done assign child " << min_score_index << std::endl; |
1184 |
40546 |
}while( d_children_order.size()!=d_children.size() ); |
1185 |
15972 |
Trace("qcf-qregister-debug") << "Done assign variable ordering for " << d_n << std::endl; |
1186 |
|
}else{ |
1187 |
129585 |
for( unsigned i=0; i<d_children.size(); i++ ){ |
1188 |
4047 |
d_children_order.push_back( i ); |
1189 |
4047 |
d_children[i].determineVariableOrder( qi, bvars ); |
1190 |
|
//now add to bvars |
1191 |
8094 |
std::map< Node, bool > visited; |
1192 |
8094 |
std::vector< int > cvars; |
1193 |
4047 |
bool has_nested = false; |
1194 |
4047 |
collectBoundVar( qi, d_children[i].d_n, cvars, visited, has_nested ); |
1195 |
57088 |
for( unsigned j=0; j<cvars.size(); j++ ){ |
1196 |
53041 |
if( std::find( bvars.begin(), bvars.end(), cvars[j] )==bvars.end() ){ |
1197 |
6087 |
bvars.push_back( cvars[j] ); |
1198 |
|
} |
1199 |
|
} |
1200 |
|
} |
1201 |
|
} |
1202 |
141510 |
} |
1203 |
|
|
1204 |
1071538 |
bool MatchGen::reset_round(QuantConflictFind* p) |
1205 |
|
{ |
1206 |
1071538 |
d_wasSet = false; |
1207 |
1466833 |
for( unsigned i=0; i<d_children.size(); i++ ){ |
1208 |
395295 |
if (!d_children[i].reset_round(p)) |
1209 |
|
{ |
1210 |
|
return false; |
1211 |
|
} |
1212 |
|
} |
1213 |
1071538 |
if( d_type==typ_ground ){ |
1214 |
|
// int e = p->evaluate( d_n ); |
1215 |
|
// if( e==1 ){ |
1216 |
|
// d_ground_eval[0] = p->d_true; |
1217 |
|
//}else if( e==-1 ){ |
1218 |
|
// d_ground_eval[0] = p->d_false; |
1219 |
|
//} |
1220 |
|
// modified |
1221 |
3054 |
TermDb* tdb = p->getTermDatabase(); |
1222 |
3054 |
QuantifiersState& qs = p->getState(); |
1223 |
9162 |
for (unsigned i = 0; i < 2; i++) |
1224 |
|
{ |
1225 |
6108 |
if (tdb->isEntailed(d_n, i == 0)) |
1226 |
|
{ |
1227 |
672 |
d_ground_eval[0] = i==0 ? p->d_true : p->d_false; |
1228 |
|
} |
1229 |
6108 |
if (qs.isInConflict()) |
1230 |
|
{ |
1231 |
|
return false; |
1232 |
|
} |
1233 |
|
} |
1234 |
1068484 |
}else if( d_type==typ_eq ){ |
1235 |
191646 |
TermDb* tdb = p->getTermDatabase(); |
1236 |
191646 |
QuantifiersState& qs = p->getState(); |
1237 |
574938 |
for (unsigned i = 0, size = d_n.getNumChildren(); i < size; i++) |
1238 |
|
{ |
1239 |
383292 |
if (!expr::hasBoundVar(d_n[i])) |
1240 |
|
{ |
1241 |
208834 |
TNode t = tdb->getEntailedTerm(d_n[i]); |
1242 |
104417 |
if (qs.isInConflict()) |
1243 |
|
{ |
1244 |
|
return false; |
1245 |
|
} |
1246 |
104417 |
if (t.isNull()) |
1247 |
|
{ |
1248 |
8297 |
d_ground_eval[i] = d_n[i]; |
1249 |
|
} |
1250 |
|
else |
1251 |
|
{ |
1252 |
96120 |
d_ground_eval[i] = t; |
1253 |
|
} |
1254 |
|
} |
1255 |
|
} |
1256 |
|
} |
1257 |
1071538 |
d_qni_bound_cons.clear(); |
1258 |
1071538 |
d_qni_bound_cons_var.clear(); |
1259 |
1071538 |
d_qni_bound.clear(); |
1260 |
1071538 |
return true; |
1261 |
|
} |
1262 |
|
|
1263 |
2172422 |
void MatchGen::reset( QuantConflictFind * p, bool tgt, QuantInfo * qi ) { |
1264 |
2172422 |
d_tgt = d_type_not ? !tgt : tgt; |
1265 |
2172422 |
Debug("qcf-match") << " Reset for : " << d_n << ", type : "; |
1266 |
2172422 |
debugPrintType( "qcf-match", d_type ); |
1267 |
2172422 |
Debug("qcf-match") << ", tgt = " << d_tgt << ", children = " << d_children.size() << " " << d_children_order.size() << std::endl; |
1268 |
2172422 |
d_qn.clear(); |
1269 |
2172422 |
d_qni.clear(); |
1270 |
2172422 |
d_qni_bound.clear(); |
1271 |
2172422 |
d_child_counter = -1; |
1272 |
2172422 |
d_use_children = true; |
1273 |
2172422 |
d_tgt_orig = d_tgt; |
1274 |
|
|
1275 |
|
//set up processing matches |
1276 |
2172422 |
if( d_type==typ_invalid ){ |
1277 |
|
d_use_children = false; |
1278 |
2172422 |
}else if( d_type==typ_ground ){ |
1279 |
1222 |
d_use_children = false; |
1280 |
1222 |
if( d_ground_eval[0]==( d_tgt ? p->d_true : p->d_false ) ){ |
1281 |
|
d_child_counter = 0; |
1282 |
|
} |
1283 |
2171200 |
}else if( qi->isBaseMatchComplete() && options::qcfEagerTest() ){ |
1284 |
499406 |
d_use_children = false; |
1285 |
499406 |
d_child_counter = 0; |
1286 |
1671794 |
}else if( d_type==typ_bool_var ){ |
1287 |
|
//get current value of the variable |
1288 |
2852 |
TNode n = qi->getCurrentValue( d_n ); |
1289 |
1426 |
int vn = qi->getCurrentRepVar( qi->getVarNum( n ) ); |
1290 |
1426 |
if( vn==-1 ){ |
1291 |
|
//evaluate the value, see if it is compatible |
1292 |
|
//int e = p->evaluate( n ); |
1293 |
|
//if( ( e==1 && d_tgt ) || ( e==0 && !d_tgt ) ){ |
1294 |
|
// d_child_counter = 0; |
1295 |
|
//} |
1296 |
|
//modified |
1297 |
|
if( p->getTermDatabase()->isEntailed( n, d_tgt ) ){ |
1298 |
|
d_child_counter = 0; |
1299 |
|
} |
1300 |
|
}else{ |
1301 |
|
//unassigned, set match to true/false |
1302 |
1426 |
d_qni_bound[0] = vn; |
1303 |
1426 |
qi->setMatch( p, vn, d_tgt ? p->d_true : p->d_false, false, true ); |
1304 |
1426 |
d_child_counter = 0; |
1305 |
|
} |
1306 |
1426 |
if( d_child_counter==0 ){ |
1307 |
1426 |
d_qn.push_back( NULL ); |
1308 |
|
} |
1309 |
1670368 |
}else if( d_type==typ_var ){ |
1310 |
1149102 |
Assert(isHandledUfTerm(d_n)); |
1311 |
2298204 |
TNode f = getMatchOperator( p, d_n ); |
1312 |
1149102 |
Debug("qcf-match-debug") << " reset: Var will match operators of " << f << std::endl; |
1313 |
1149102 |
TNodeTrie* qni = p->getTermDatabase()->getTermArgTrie(Node::null(), f); |
1314 |
1149102 |
if (qni == nullptr || qni->empty()) |
1315 |
|
{ |
1316 |
|
//inform irrelevant quantifiers |
1317 |
230037 |
p->setIrrelevantFunction( f ); |
1318 |
|
} |
1319 |
|
else |
1320 |
|
{ |
1321 |
919065 |
d_qn.push_back(qni); |
1322 |
|
} |
1323 |
1149102 |
d_matched_basis = false; |
1324 |
521266 |
}else if( d_type==typ_tsym || d_type==typ_tconstraint ){ |
1325 |
3248 |
for( std::map< int, int >::iterator it = d_qni_var_num.begin(); it != d_qni_var_num.end(); ++it ){ |
1326 |
1938 |
int repVar = qi->getCurrentRepVar( it->second ); |
1327 |
1938 |
if( qi->d_match[repVar].isNull() ){ |
1328 |
1872 |
Debug("qcf-match-debug") << "Force matching on child #" << it->first << ", which is var #" << repVar << std::endl; |
1329 |
1872 |
d_qni_bound[it->first] = repVar; |
1330 |
|
} |
1331 |
|
} |
1332 |
1310 |
d_qn.push_back( NULL ); |
1333 |
519956 |
}else if( d_type==typ_pred || d_type==typ_eq ){ |
1334 |
|
//add initial constraint |
1335 |
723346 |
Node nn[2]; |
1336 |
|
int vn[2]; |
1337 |
361673 |
if( d_type==typ_pred ){ |
1338 |
152404 |
nn[0] = qi->getCurrentValue( d_n ); |
1339 |
152404 |
vn[0] = qi->getCurrentRepVar( qi->getVarNum( nn[0] ) ); |
1340 |
152404 |
nn[1] = d_tgt ? p->d_true : p->d_false; |
1341 |
152404 |
vn[1] = -1; |
1342 |
152404 |
d_tgt = true; |
1343 |
|
}else{ |
1344 |
627807 |
for( unsigned i=0; i<2; i++ ){ |
1345 |
837076 |
TNode nc; |
1346 |
418538 |
std::map<int, TNode>::iterator it = d_qni_gterm.find(i); |
1347 |
418538 |
if (it != d_qni_gterm.end()) |
1348 |
|
{ |
1349 |
135119 |
nc = it->second; |
1350 |
|
}else{ |
1351 |
283419 |
nc = d_n[i]; |
1352 |
|
} |
1353 |
418538 |
nn[i] = qi->getCurrentValue( nc ); |
1354 |
418538 |
vn[i] = qi->getCurrentRepVar( qi->getVarNum( nn[i] ) ); |
1355 |
|
} |
1356 |
|
} |
1357 |
|
bool success; |
1358 |
361673 |
if( vn[0]==-1 && vn[1]==-1 ){ |
1359 |
|
//Trace("qcf-explain") << " reset : " << d_n << " check ground values " << nn[0] << " " << nn[1] << " (tgt=" << d_tgt << ")" << std::endl; |
1360 |
374 |
Debug("qcf-match-debug") << " reset: check ground values " << nn[0] << " " << nn[1] << " (" << d_tgt << ")" << std::endl; |
1361 |
|
//just compare values |
1362 |
748 |
if( d_tgt ){ |
1363 |
332 |
success = p->areMatchEqual( nn[0], nn[1] ); |
1364 |
|
}else{ |
1365 |
42 |
if (p->atConflictEffort()) { |
1366 |
27 |
success = p->areDisequal( nn[0], nn[1] ); |
1367 |
|
}else{ |
1368 |
15 |
success = p->areMatchDisequal( nn[0], nn[1] ); |
1369 |
|
} |
1370 |
|
} |
1371 |
|
}else{ |
1372 |
|
//otherwise, add a constraint to a variable TODO: this may be over-eager at effort > conflict, since equality may be a propagation |
1373 |
361299 |
if( vn[1]!=-1 && vn[0]==-1 ){ |
1374 |
|
//swap |
1375 |
173334 |
Node t = nn[1]; |
1376 |
86667 |
nn[1] = nn[0]; |
1377 |
86667 |
nn[0] = t; |
1378 |
86667 |
vn[0] = vn[1]; |
1379 |
86667 |
vn[1] = -1; |
1380 |
|
} |
1381 |
361299 |
Debug("qcf-match-debug") << " reset: add constraint " << vn[0] << " -> " << nn[1] << " (vn=" << vn[1] << ")" << std::endl; |
1382 |
|
//add some constraint |
1383 |
361299 |
int addc = qi->addConstraint( p, vn[0], nn[1], vn[1], d_tgt, false ); |
1384 |
361299 |
success = addc!=-1; |
1385 |
|
//if successful and non-redundant, store that we need to cleanup this |
1386 |
361299 |
if( addc==1 ){ |
1387 |
|
//Trace("qcf-explain") << " reset: " << d_n << " add constraint " << vn[0] << " -> " << nn[1] << " (vn=" << vn[1] << ")" << ", d_tgt = " << d_tgt << std::endl; |
1388 |
1083477 |
for( unsigned i=0; i<2; i++ ){ |
1389 |
722318 |
if( vn[i]!=-1 && std::find( d_qni_bound_except.begin(), d_qni_bound_except.end(), i )==d_qni_bound_except.end() ){ |
1390 |
430382 |
d_qni_bound[vn[i]] = vn[i]; |
1391 |
|
} |
1392 |
|
} |
1393 |
361159 |
d_qni_bound_cons[vn[0]] = nn[1]; |
1394 |
361159 |
d_qni_bound_cons_var[vn[0]] = vn[1]; |
1395 |
|
} |
1396 |
|
} |
1397 |
|
//if successful, we will bind values to variables |
1398 |
361673 |
if( success ){ |
1399 |
361300 |
d_qn.push_back( NULL ); |
1400 |
361673 |
} |
1401 |
|
}else{ |
1402 |
158283 |
if( d_children.empty() ){ |
1403 |
|
//add dummy |
1404 |
|
d_qn.push_back( NULL ); |
1405 |
|
}else{ |
1406 |
158283 |
if( d_tgt && d_n.getKind()==FORALL ){ |
1407 |
|
//fail |
1408 |
129732 |
} else if (d_n.getKind() == FORALL && p->atConflictEffort() && |
1409 |
6730 |
!options::qcfNestedConflict()) { |
1410 |
|
//fail |
1411 |
|
}else{ |
1412 |
|
//reset the first child to d_tgt |
1413 |
123002 |
d_child_counter = 0; |
1414 |
123002 |
getChild( d_child_counter )->reset( p, d_tgt, qi ); |
1415 |
|
} |
1416 |
|
} |
1417 |
|
} |
1418 |
2172422 |
d_binding = false; |
1419 |
2172422 |
d_wasSet = true; |
1420 |
2172422 |
Debug("qcf-match") << " reset: Finished reset for " << d_n << ", success = " << ( !d_qn.empty() || d_child_counter!=-1 ) << std::endl; |
1421 |
2172422 |
} |
1422 |
|
|
1423 |
4923133 |
bool MatchGen::getNextMatch( QuantConflictFind * p, QuantInfo * qi ) { |
1424 |
4923133 |
Debug("qcf-match") << " Get next match for : " << d_n << ", type = "; |
1425 |
4923133 |
debugPrintType( "qcf-match", d_type ); |
1426 |
4923133 |
Debug("qcf-match") << ", children = " << d_children.size() << ", binding = " << d_binding << std::endl; |
1427 |
4923133 |
if( !d_use_children ){ |
1428 |
999466 |
if( d_child_counter==0 ){ |
1429 |
499406 |
d_child_counter = -1; |
1430 |
499406 |
return true; |
1431 |
|
}else{ |
1432 |
500060 |
d_wasSet = false; |
1433 |
500060 |
return false; |
1434 |
|
} |
1435 |
3923667 |
}else if( d_type==typ_var || d_type==typ_eq || d_type==typ_pred || d_type==typ_bool_var || d_type==typ_tconstraint || d_type==typ_tsym ){ |
1436 |
3201078 |
bool success = false; |
1437 |
3201078 |
bool terminate = false; |
1438 |
1832018 |
do { |
1439 |
5033096 |
bool doReset = false; |
1440 |
5033096 |
bool doFail = false; |
1441 |
5033096 |
if( !d_binding ){ |
1442 |
3352623 |
if( doMatching( p, qi ) ){ |
1443 |
1844108 |
Debug("qcf-match-debug") << " - Matching succeeded" << std::endl; |
1444 |
1844108 |
d_binding = true; |
1445 |
1844108 |
d_binding_it = d_qni_bound.begin(); |
1446 |
1844108 |
doReset = true; |
1447 |
|
//for tconstraint, add constraint |
1448 |
1844108 |
if( d_type==typ_tconstraint ){ |
1449 |
883 |
std::map< Node, bool >::iterator it = qi->d_tconstraints.find( d_n ); |
1450 |
883 |
if( it==qi->d_tconstraints.end() ){ |
1451 |
883 |
qi->d_tconstraints[d_n] = d_tgt; |
1452 |
|
//store that we added this constraint |
1453 |
883 |
d_qni_bound_cons[0] = d_n; |
1454 |
|
}else if( d_tgt!=it->second ){ |
1455 |
|
success = false; |
1456 |
|
terminate = true; |
1457 |
|
} |
1458 |
|
} |
1459 |
|
}else{ |
1460 |
1508515 |
Debug("qcf-match-debug") << " - Matching failed" << std::endl; |
1461 |
1508515 |
success = false; |
1462 |
1508515 |
terminate = true; |
1463 |
|
} |
1464 |
|
}else{ |
1465 |
1680473 |
doFail = true; |
1466 |
|
} |
1467 |
5033096 |
if( d_binding ){ |
1468 |
|
//also need to create match for each variable we bound |
1469 |
3524581 |
success = true; |
1470 |
3524581 |
Debug("qcf-match-debug") << " Produce matches for bound variables by " << d_n << ", type = "; |
1471 |
3524581 |
debugPrintType( "qcf-match-debug", d_type ); |
1472 |
3524581 |
Debug("qcf-match-debug") << "..." << std::endl; |
1473 |
|
|
1474 |
15489853 |
while( ( success && d_binding_it!=d_qni_bound.end() ) || doFail ){ |
1475 |
5982636 |
QuantInfo::VarMgMap::const_iterator itm; |
1476 |
5982636 |
if( !doFail ){ |
1477 |
4302163 |
Debug("qcf-match-debug") << " check variable " << d_binding_it->second << std::endl; |
1478 |
4302163 |
itm = qi->var_mg_find( d_binding_it->second ); |
1479 |
|
} |
1480 |
5982636 |
if( doFail || ( d_binding_it->first!=0 && itm != qi->var_mg_end() ) ){ |
1481 |
4380128 |
Debug("qcf-match-debug") << " we had bound variable " << d_binding_it->second << ", reset = " << doReset << std::endl; |
1482 |
4380128 |
if( doReset ){ |
1483 |
1427072 |
itm->second->reset( p, true, qi ); |
1484 |
|
} |
1485 |
4380128 |
if( doFail || !itm->second->getNextMatch( p, qi ) ){ |
1486 |
1598327 |
do { |
1487 |
4702928 |
if( d_binding_it==d_qni_bound.begin() ){ |
1488 |
1832018 |
Debug("qcf-match-debug") << " failed." << std::endl; |
1489 |
1832018 |
success = false; |
1490 |
|
}else{ |
1491 |
2870910 |
--d_binding_it; |
1492 |
2870910 |
Debug("qcf-match-debug") << " decrement..." << std::endl; |
1493 |
|
} |
1494 |
9172165 |
}while( success && |
1495 |
5169523 |
( d_binding_it->first==0 || |
1496 |
2298613 |
(!qi->containsVarMg(d_binding_it->second)))); |
1497 |
3104601 |
doReset = false; |
1498 |
3104601 |
doFail = false; |
1499 |
|
}else{ |
1500 |
1275527 |
Debug("qcf-match-debug") << " increment..." << std::endl; |
1501 |
1275527 |
++d_binding_it; |
1502 |
1275527 |
doReset = true; |
1503 |
|
} |
1504 |
|
}else{ |
1505 |
1602508 |
Debug("qcf-match-debug") << " skip..." << d_binding_it->second << std::endl; |
1506 |
1602508 |
++d_binding_it; |
1507 |
1602508 |
doReset = true; |
1508 |
|
} |
1509 |
|
} |
1510 |
3524581 |
if( !success ){ |
1511 |
1832018 |
d_binding = false; |
1512 |
|
}else{ |
1513 |
1692563 |
terminate = true; |
1514 |
1692563 |
if( d_binding_it==d_qni_bound.begin() ){ |
1515 |
7172 |
d_binding = false; |
1516 |
|
} |
1517 |
|
} |
1518 |
|
} |
1519 |
5033096 |
}while( !terminate ); |
1520 |
|
//if not successful, clean up the variables you bound |
1521 |
3201078 |
if( !success ){ |
1522 |
1508515 |
if( d_type==typ_eq || d_type==typ_pred ){ |
1523 |
|
//clean up the constraints you added |
1524 |
718374 |
for( std::map< int, TNode >::iterator it = d_qni_bound_cons.begin(); it != d_qni_bound_cons.end(); ++it ){ |
1525 |
358934 |
if( !it->second.isNull() ){ |
1526 |
358934 |
Debug("qcf-match") << " Clean up bound var " << it->first << (d_tgt ? "!" : "") << " = " << it->second << std::endl; |
1527 |
358934 |
std::map< int, int >::iterator itb = d_qni_bound_cons_var.find( it->first ); |
1528 |
358934 |
int vn = itb!=d_qni_bound_cons_var.end() ? itb->second : -1; |
1529 |
|
//Trace("qcf-explain") << " cleanup: " << d_n << " remove constraint " << it->first << " -> " << it->second << " (vn=" << vn << ")" << ", d_tgt = " << d_tgt << std::endl; |
1530 |
358934 |
qi->addConstraint( p, it->first, it->second, vn, d_tgt, true ); |
1531 |
|
} |
1532 |
|
} |
1533 |
359440 |
d_qni_bound_cons.clear(); |
1534 |
359440 |
d_qni_bound_cons_var.clear(); |
1535 |
359440 |
d_qni_bound.clear(); |
1536 |
|
}else{ |
1537 |
|
//clean up the matches you set |
1538 |
1849638 |
for( std::map< int, int >::iterator it = d_qni_bound.begin(); it != d_qni_bound.end(); ++it ){ |
1539 |
700563 |
Debug("qcf-match") << " Clean up bound var " << it->second << std::endl; |
1540 |
700563 |
Assert(it->second < qi->getNumVars()); |
1541 |
700563 |
qi->unsetMatch( p, it->second ); |
1542 |
700563 |
qi->d_match_term[ it->second ] = TNode::null(); |
1543 |
|
} |
1544 |
1149075 |
d_qni_bound.clear(); |
1545 |
|
} |
1546 |
1508515 |
if( d_type==typ_tconstraint ){ |
1547 |
|
//remove constraint if applicable |
1548 |
875 |
if( d_qni_bound_cons.find( 0 )!=d_qni_bound_cons.end() ){ |
1549 |
875 |
qi->d_tconstraints.erase( d_n ); |
1550 |
875 |
d_qni_bound_cons.clear(); |
1551 |
|
} |
1552 |
|
} |
1553 |
|
} |
1554 |
3201078 |
Debug("qcf-match") << " ...finished matching for " << d_n << ", success = " << success << std::endl; |
1555 |
3201078 |
d_wasSet = success; |
1556 |
3201078 |
return success; |
1557 |
|
} |
1558 |
722589 |
else if (d_type == typ_formula) |
1559 |
|
{ |
1560 |
722589 |
bool success = false; |
1561 |
722589 |
if( d_child_counter<0 ){ |
1562 |
35281 |
if( d_child_counter<-1 ){ |
1563 |
|
success = true; |
1564 |
|
d_child_counter = -1; |
1565 |
|
} |
1566 |
|
}else{ |
1567 |
3530988 |
while( !success && d_child_counter>=0 ){ |
1568 |
|
//transition system based on d_child_counter |
1569 |
1421840 |
if( d_n.getKind()==OR || d_n.getKind()==AND ){ |
1570 |
823291 |
if( (d_n.getKind()==AND)==d_tgt ){ |
1571 |
|
//all children must match simultaneously |
1572 |
761239 |
if( getChild( d_child_counter )->getNextMatch( p, qi ) ){ |
1573 |
460555 |
if( d_child_counter<(int)(getNumChildren()-1) ){ |
1574 |
246138 |
d_child_counter++; |
1575 |
246138 |
Debug("qcf-match-debug") << " Reset child " << d_child_counter << " of " << d_n << std::endl; |
1576 |
246138 |
getChild( d_child_counter )->reset( p, d_tgt, qi ); |
1577 |
|
}else{ |
1578 |
214417 |
success = true; |
1579 |
|
} |
1580 |
|
}else{ |
1581 |
|
//if( std::find( d_independent.begin(), d_independent.end(), d_child_counter )!=d_independent.end() ){ |
1582 |
|
// d_child_counter--; |
1583 |
|
//}else{ |
1584 |
300684 |
d_child_counter--; |
1585 |
|
//} |
1586 |
|
} |
1587 |
|
}else{ |
1588 |
|
//one child must match |
1589 |
62052 |
if( !getChild( d_child_counter )->getNextMatch( p, qi ) ){ |
1590 |
34121 |
if( d_child_counter<(int)(getNumChildren()-1) ){ |
1591 |
18835 |
d_child_counter++; |
1592 |
18835 |
Debug("qcf-match-debug") << " Reset child " << d_child_counter << " of " << d_n << ", one match" << std::endl; |
1593 |
18835 |
getChild( d_child_counter )->reset( p, d_tgt, qi ); |
1594 |
|
}else{ |
1595 |
15286 |
d_child_counter = -1; |
1596 |
|
} |
1597 |
|
}else{ |
1598 |
27931 |
success = true; |
1599 |
|
} |
1600 |
|
} |
1601 |
598549 |
}else if( d_n.getKind()==EQUAL ){ |
1602 |
|
//construct match based on both children |
1603 |
557674 |
if( d_child_counter%2==0 ){ |
1604 |
246071 |
if( getChild( 0 )->getNextMatch( p, qi ) ){ |
1605 |
156862 |
d_child_counter++; |
1606 |
156862 |
getChild( 1 )->reset( p, d_child_counter==1, qi ); |
1607 |
|
}else{ |
1608 |
89209 |
if( d_child_counter==0 ){ |
1609 |
44672 |
d_child_counter = 2; |
1610 |
44672 |
getChild( 0 )->reset( p, !d_tgt, qi ); |
1611 |
|
}else{ |
1612 |
44537 |
d_child_counter = -1; |
1613 |
|
} |
1614 |
|
} |
1615 |
|
} |
1616 |
557674 |
if( d_child_counter>=0 && d_child_counter%2==1 ){ |
1617 |
468465 |
if( getChild( 1 )->getNextMatch( p, qi ) ){ |
1618 |
311841 |
success = true; |
1619 |
|
}else{ |
1620 |
156624 |
d_child_counter--; |
1621 |
|
} |
1622 |
|
} |
1623 |
40875 |
}else if( d_n.getKind()==ITE ){ |
1624 |
37499 |
if( d_child_counter%2==0 ){ |
1625 |
26831 |
int index1 = d_child_counter==4 ? 1 : 0; |
1626 |
26831 |
if( getChild( index1 )->getNextMatch( p, qi ) ){ |
1627 |
16939 |
d_child_counter++; |
1628 |
16939 |
getChild( d_child_counter==5 ? 2 : (d_tgt==(d_child_counter==1) ? 1 : 2) )->reset( p, d_tgt, qi ); |
1629 |
|
}else{ |
1630 |
9892 |
if (d_child_counter == 4) |
1631 |
|
{ |
1632 |
3292 |
d_child_counter = -1; |
1633 |
|
}else{ |
1634 |
6600 |
d_child_counter +=2; |
1635 |
6600 |
getChild( d_child_counter==2 ? 0 : 1 )->reset( p, d_child_counter==2 ? !d_tgt : d_tgt, qi ); |
1636 |
|
} |
1637 |
|
} |
1638 |
|
} |
1639 |
37499 |
if( d_child_counter>=0 && d_child_counter%2==1 ){ |
1640 |
27607 |
int index2 = d_child_counter==5 ? 2 : (d_tgt==(d_child_counter==1) ? 1 : 2); |
1641 |
27607 |
if( getChild( index2 )->getNextMatch( p, qi ) ){ |
1642 |
10730 |
success = true; |
1643 |
|
}else{ |
1644 |
16877 |
d_child_counter--; |
1645 |
|
} |
1646 |
|
} |
1647 |
3376 |
}else if( d_n.getKind()==FORALL ){ |
1648 |
3376 |
if( getChild( d_child_counter )->getNextMatch( p, qi ) ){ |
1649 |
384 |
success = true; |
1650 |
|
}else{ |
1651 |
2992 |
d_child_counter = -1; |
1652 |
|
} |
1653 |
|
} |
1654 |
|
} |
1655 |
687308 |
d_wasSet = success; |
1656 |
687308 |
Debug("qcf-match") << " ...finished construct match for " << d_n << ", success = " << success << std::endl; |
1657 |
687308 |
return success; |
1658 |
|
} |
1659 |
|
} |
1660 |
35281 |
Debug("qcf-match") << " ...already finished for " << d_n << std::endl; |
1661 |
35281 |
return false; |
1662 |
|
} |
1663 |
|
|
1664 |
3352623 |
bool MatchGen::doMatching( QuantConflictFind * p, QuantInfo * qi ) { |
1665 |
3352623 |
if( !d_qn.empty() ){ |
1666 |
2760418 |
if( d_qn[0]==NULL ){ |
1667 |
364036 |
d_qn.clear(); |
1668 |
364036 |
return true; |
1669 |
|
}else{ |
1670 |
2396382 |
Assert(d_type == typ_var); |
1671 |
2396382 |
Assert(d_qni_size > 0); |
1672 |
|
bool invalidMatch; |
1673 |
8063456 |
do { |
1674 |
10459838 |
invalidMatch = false; |
1675 |
10459838 |
Debug("qcf-match-debug") << " Do matching " << d_n << " " << d_qn.size() << " " << d_qni.size() << std::endl; |
1676 |
10459838 |
if( d_qn.size()==d_qni.size()+1 ) { |
1677 |
4823017 |
int index = (int)d_qni.size(); |
1678 |
|
//initialize |
1679 |
9646034 |
TNode val; |
1680 |
4823017 |
std::map< int, int >::iterator itv = d_qni_var_num.find( index ); |
1681 |
4823017 |
if( itv!=d_qni_var_num.end() ){ |
1682 |
|
//get the representative variable this variable is equal to |
1683 |
4491499 |
int repVar = qi->getCurrentRepVar( itv->second ); |
1684 |
4491499 |
Debug("qcf-match-debug") << " Match " << index << " is a variable " << itv->second << ", which is repVar " << repVar << std::endl; |
1685 |
|
//get the value the rep variable |
1686 |
|
//std::map< int, TNode >::iterator itm = qi->d_match.find( repVar ); |
1687 |
4491499 |
if( !qi->d_match[repVar].isNull() ){ |
1688 |
2673321 |
val = qi->d_match[repVar]; |
1689 |
2673321 |
Debug("qcf-match-debug") << " Variable is already bound to " << val << std::endl; |
1690 |
|
}else{ |
1691 |
|
//binding a variable |
1692 |
1818178 |
d_qni_bound[index] = repVar; |
1693 |
|
std::map<TNode, TNodeTrie>::iterator it = |
1694 |
1818178 |
d_qn[index]->d_data.begin(); |
1695 |
1818178 |
if( it != d_qn[index]->d_data.end() ) { |
1696 |
1818178 |
d_qni.push_back( it ); |
1697 |
|
//set the match |
1698 |
1818178 |
if( it->first.getType().isComparableTo( qi->d_var_types[repVar] ) && qi->setMatch( p, d_qni_bound[index], it->first, true, true ) ){ |
1699 |
1652482 |
Debug("qcf-match-debug") << " Binding variable" << std::endl; |
1700 |
1652482 |
if( d_qn.size()<d_qni_size ){ |
1701 |
667891 |
d_qn.push_back( &it->second ); |
1702 |
|
} |
1703 |
|
}else{ |
1704 |
165696 |
Debug("qcf-match") << " Binding variable, currently fail." << std::endl; |
1705 |
165696 |
invalidMatch = true; |
1706 |
|
} |
1707 |
|
}else{ |
1708 |
|
Debug("qcf-match-debug") << " Binding variable, fail, no more variables to bind" << std::endl; |
1709 |
|
d_qn.pop_back(); |
1710 |
|
} |
1711 |
|
} |
1712 |
|
}else{ |
1713 |
331518 |
Debug("qcf-match-debug") << " Match " << index << " is ground term" << std::endl; |
1714 |
331518 |
Assert(d_qni_gterm.find(index) != d_qni_gterm.end()); |
1715 |
331518 |
val = d_qni_gterm[index]; |
1716 |
331518 |
Assert(!val.isNull()); |
1717 |
|
} |
1718 |
4823017 |
if( !val.isNull() ){ |
1719 |
6009678 |
Node valr = p->getRepresentative(val); |
1720 |
|
//constrained by val |
1721 |
|
std::map<TNode, TNodeTrie>::iterator it = |
1722 |
3004839 |
d_qn[index]->d_data.find(valr); |
1723 |
3004839 |
if( it!=d_qn[index]->d_data.end() ){ |
1724 |
1335963 |
Debug("qcf-match-debug") << " Match" << std::endl; |
1725 |
1335963 |
d_qni.push_back( it ); |
1726 |
1335963 |
if( d_qn.size()<d_qni_size ){ |
1727 |
1125163 |
d_qn.push_back( &it->second ); |
1728 |
|
} |
1729 |
|
}else{ |
1730 |
1668876 |
Debug("qcf-match-debug") << " Failed to match" << std::endl; |
1731 |
1668876 |
d_qn.pop_back(); |
1732 |
|
} |
1733 |
|
} |
1734 |
|
}else{ |
1735 |
5636821 |
Assert(d_qn.size() == d_qni.size()); |
1736 |
5636821 |
int index = d_qni.size()-1; |
1737 |
|
//increment if binding this variable |
1738 |
5636821 |
bool success = false; |
1739 |
5636821 |
std::map< int, int >::iterator itb = d_qni_bound.find( index ); |
1740 |
5636821 |
if( itb!=d_qni_bound.end() ){ |
1741 |
4310053 |
d_qni[index]++; |
1742 |
4310053 |
if( d_qni[index]!=d_qn[index]->d_data.end() ){ |
1743 |
2496226 |
success = true; |
1744 |
2496226 |
if( qi->setMatch( p, itb->second, d_qni[index]->first, true, true ) ){ |
1745 |
2395579 |
Debug("qcf-match-debug") << " Bind next variable" << std::endl; |
1746 |
2395579 |
if( d_qn.size()<d_qni_size ){ |
1747 |
2110898 |
d_qn.push_back( &d_qni[index]->second ); |
1748 |
|
} |
1749 |
|
}else{ |
1750 |
100647 |
Debug("qcf-match-debug") << " Bind next variable, currently fail" << std::endl; |
1751 |
100647 |
invalidMatch = true; |
1752 |
|
} |
1753 |
|
}else{ |
1754 |
1813827 |
qi->unsetMatch( p, itb->second ); |
1755 |
1813827 |
qi->d_match_term[ itb->second ] = TNode::null(); |
1756 |
1813827 |
Debug("qcf-match-debug") << " Bind next variable, no more variables to bind" << std::endl; |
1757 |
|
} |
1758 |
|
}else{ |
1759 |
|
//TODO : if it equal to something else, also try that |
1760 |
|
} |
1761 |
|
//if not incrementing, move to next |
1762 |
5636821 |
if( !success ){ |
1763 |
3140595 |
d_qn.pop_back(); |
1764 |
3140595 |
d_qni.pop_back(); |
1765 |
|
} |
1766 |
|
} |
1767 |
10459838 |
}while( ( !d_qn.empty() && d_qni.size()!=d_qni_size ) || invalidMatch ); |
1768 |
2396382 |
if( d_qni.size()==d_qni_size ){ |
1769 |
|
//Assert( !d_qni[d_qni.size()-1]->second.d_data.empty() ); |
1770 |
|
//Debug("qcf-match-debug") << " We matched " << d_qni[d_qni.size()-1]->second.d_children.begin()->first << std::endl; |
1771 |
1480072 |
Assert(!d_qni[d_qni.size() - 1]->second.d_data.empty()); |
1772 |
2960144 |
TNode t = d_qni[d_qni.size()-1]->second.d_data.begin()->first; |
1773 |
1480072 |
Debug("qcf-match-debug") << " " << d_n << " matched " << t << std::endl; |
1774 |
1480072 |
qi->d_match_term[d_qni_var_num[0]] = t; |
1775 |
|
//set the match terms |
1776 |
4392376 |
for( std::map< int, int >::iterator it = d_qni_bound.begin(); it != d_qni_bound.end(); ++it ){ |
1777 |
2912304 |
Debug("qcf-match-debug") << " position " << it->first << " bounded " << it->second << " / " << qi->d_q[0].getNumChildren() << std::endl; |
1778 |
|
//if( it->second<(int)qi->d_q[0].getNumChildren() ){ //if it is an actual variable, we are interested in knowing the actual term |
1779 |
2912304 |
if( it->first>0 ){ |
1780 |
2387182 |
Assert(!qi->d_match[it->second].isNull()); |
1781 |
2387182 |
Assert(p->areEqual(t[it->first - 1], qi->d_match[it->second])); |
1782 |
2387182 |
qi->d_match_term[it->second] = t[it->first-1]; |
1783 |
|
} |
1784 |
|
//} |
1785 |
|
} |
1786 |
|
} |
1787 |
|
} |
1788 |
|
} |
1789 |
2988587 |
return !d_qn.empty(); |
1790 |
|
} |
1791 |
|
|
1792 |
10778522 |
void MatchGen::debugPrintType( const char * c, short typ, bool isTrace ) { |
1793 |
10778522 |
if( isTrace ){ |
1794 |
158386 |
switch( typ ){ |
1795 |
7792 |
case typ_invalid: Trace(c) << "invalid";break; |
1796 |
174 |
case typ_ground: Trace(c) << "ground";break; |
1797 |
31102 |
case typ_eq: Trace(c) << "eq";break; |
1798 |
17710 |
case typ_pred: Trace(c) << "pred";break; |
1799 |
21674 |
case typ_formula: Trace(c) << "formula";break; |
1800 |
79056 |
case typ_var: Trace(c) << "var";break; |
1801 |
161 |
case typ_bool_var: Trace(c) << "bool_var";break; |
1802 |
|
} |
1803 |
|
}else{ |
1804 |
10620136 |
switch( typ ){ |
1805 |
|
case typ_invalid: Debug(c) << "invalid";break; |
1806 |
2444 |
case typ_ground: Debug(c) << "ground";break; |
1807 |
1359257 |
case typ_eq: Debug(c) << "eq";break; |
1808 |
1670878 |
case typ_pred: Debug(c) << "pred";break; |
1809 |
980581 |
case typ_formula: Debug(c) << "formula";break; |
1810 |
6593893 |
case typ_var: Debug(c) << "var";break; |
1811 |
7130 |
case typ_bool_var: Debug(c) << "bool_var";break; |
1812 |
|
} |
1813 |
|
} |
1814 |
10778522 |
} |
1815 |
|
|
1816 |
5477 |
void MatchGen::setInvalid() { |
1817 |
5477 |
d_type = typ_invalid; |
1818 |
5477 |
d_children.clear(); |
1819 |
5477 |
} |
1820 |
|
|
1821 |
259215 |
bool MatchGen::isHandledBoolConnective( TNode n ) { |
1822 |
259215 |
return TermUtil::isBoolConnectiveTerm( n ) && n.getKind()!=SEP_STAR; |
1823 |
|
} |
1824 |
|
|
1825 |
2537437 |
bool MatchGen::isHandledUfTerm( TNode n ) { |
1826 |
|
//return n.getKind()==APPLY_UF || n.getKind()==STORE || n.getKind()==SELECT || |
1827 |
|
// n.getKind()==APPLY_CONSTRUCTOR || n.getKind()==APPLY_SELECTOR_TOTAL || n.getKind()==APPLY_TESTER; |
1828 |
|
//TODO : treat APPLY_TESTER as a T-constraint instead of matching (currently leads to overabundance of instantiations) |
1829 |
|
//return inst::Trigger::isAtomicTriggerKind( n.getKind() ) && ( !options::qcfTConstraint() || n.getKind()!=APPLY_TESTER ); |
1830 |
2537437 |
return inst::TriggerTermInfo::isAtomicTriggerKind(n.getKind()); |
1831 |
|
} |
1832 |
|
|
1833 |
1149102 |
Node MatchGen::getMatchOperator( QuantConflictFind * p, Node n ) { |
1834 |
1149102 |
if( isHandledUfTerm( n ) ){ |
1835 |
1149102 |
return p->getTermDatabase()->getMatchOperator( n ); |
1836 |
|
}else{ |
1837 |
|
return Node::null(); |
1838 |
|
} |
1839 |
|
} |
1840 |
|
|
1841 |
|
bool MatchGen::isHandled( TNode n ) { |
1842 |
|
if (n.getKind() != BOUND_VARIABLE && expr::hasBoundVar(n)) |
1843 |
|
{ |
1844 |
|
if( !isHandledBoolConnective( n ) && !isHandledUfTerm( n ) && n.getKind()!=EQUAL && n.getKind()!=ITE ){ |
1845 |
|
return false; |
1846 |
|
} |
1847 |
|
for( unsigned i=0; i<n.getNumChildren(); i++ ){ |
1848 |
|
if( !isHandled( n[i] ) ){ |
1849 |
|
return false; |
1850 |
|
} |
1851 |
|
} |
1852 |
|
} |
1853 |
|
return true; |
1854 |
|
} |
1855 |
|
|
1856 |
4478 |
QuantConflictFind::QuantConflictFind(QuantifiersState& qs, |
1857 |
|
QuantifiersInferenceManager& qim, |
1858 |
|
QuantifiersRegistry& qr, |
1859 |
4478 |
TermRegistry& tr) |
1860 |
|
: QuantifiersModule(qs, qim, qr, tr), |
1861 |
|
d_conflict(qs.getSatContext(), false), |
1862 |
|
d_true(NodeManager::currentNM()->mkConst<bool>(true)), |
1863 |
|
d_false(NodeManager::currentNM()->mkConst<bool>(false)), |
1864 |
4478 |
d_effort(EFFORT_INVALID) |
1865 |
|
{ |
1866 |
4478 |
} |
1867 |
|
|
1868 |
|
//-------------------------------------------------- registration |
1869 |
|
|
1870 |
23683 |
void QuantConflictFind::registerQuantifier( Node q ) { |
1871 |
23683 |
if (d_qreg.hasOwnership(q, this)) |
1872 |
|
{ |
1873 |
21994 |
d_quants.push_back( q ); |
1874 |
21994 |
d_quant_id[q] = d_quants.size(); |
1875 |
21994 |
if( Trace.isOn("qcf-qregister") ){ |
1876 |
|
Trace("qcf-qregister") << "Register "; |
1877 |
|
debugPrintQuant( "qcf-qregister", q ); |
1878 |
|
Trace("qcf-qregister") << " : " << q << std::endl; |
1879 |
|
} |
1880 |
|
//make QcfNode structure |
1881 |
21994 |
Trace("qcf-qregister") << "- Get relevant equality/disequality pairs, calculate flattening..." << std::endl; |
1882 |
21994 |
d_qinfo[q].initialize( this, q, q[1] ); |
1883 |
|
|
1884 |
|
//debug print |
1885 |
21994 |
if( Trace.isOn("qcf-qregister") ){ |
1886 |
|
Trace("qcf-qregister") << "- Flattened structure is :" << std::endl; |
1887 |
|
Trace("qcf-qregister") << " "; |
1888 |
|
debugPrintQuantBody( "qcf-qregister", q, q[1] ); |
1889 |
|
Trace("qcf-qregister") << std::endl; |
1890 |
|
if( d_qinfo[q].d_vars.size()>q[0].getNumChildren() ){ |
1891 |
|
Trace("qcf-qregister") << " with additional constraints : " << std::endl; |
1892 |
|
for( unsigned j=q[0].getNumChildren(); j<d_qinfo[q].d_vars.size(); j++ ){ |
1893 |
|
Trace("qcf-qregister") << " ?x" << j << " = "; |
1894 |
|
debugPrintQuantBody( "qcf-qregister", q, d_qinfo[q].d_vars[j], false ); |
1895 |
|
Trace("qcf-qregister") << std::endl; |
1896 |
|
} |
1897 |
|
} |
1898 |
|
Trace("qcf-qregister") << "Done registering quantifier." << std::endl; |
1899 |
|
} |
1900 |
|
} |
1901 |
23683 |
} |
1902 |
|
|
1903 |
332 |
bool QuantConflictFind::areMatchEqual( TNode n1, TNode n2 ) { |
1904 |
|
//if( d_effort==QuantConflictFind::effort_mc ){ |
1905 |
|
// return n1==n2 || !areDisequal( n1, n2 ); |
1906 |
|
//}else{ |
1907 |
332 |
return n1==n2; |
1908 |
|
//} |
1909 |
|
} |
1910 |
|
|
1911 |
15 |
bool QuantConflictFind::areMatchDisequal( TNode n1, TNode n2 ) { |
1912 |
|
// if( d_effort==QuantConflictFind::Effort::Conflict ){ |
1913 |
|
// return areDisequal( n1, n2 ); |
1914 |
|
//}else{ |
1915 |
15 |
return n1!=n2; |
1916 |
|
//} |
1917 |
|
} |
1918 |
|
|
1919 |
|
//-------------------------------------------------- check function |
1920 |
|
|
1921 |
73531 |
bool QuantConflictFind::needsCheck( Theory::Effort level ) { |
1922 |
73531 |
bool performCheck = false; |
1923 |
73531 |
if( options::quantConflictFind() && !d_conflict ){ |
1924 |
73527 |
if( level==Theory::EFFORT_LAST_CALL ){ |
1925 |
77544 |
performCheck = options::qcfWhenMode() == options::QcfWhenMode::LAST_CALL; |
1926 |
69510 |
}else if( level==Theory::EFFORT_FULL ){ |
1927 |
13581 |
performCheck = options::qcfWhenMode() == options::QcfWhenMode::DEFAULT; |
1928 |
55929 |
}else if( level==Theory::EFFORT_STANDARD ){ |
1929 |
55929 |
performCheck = options::qcfWhenMode() == options::QcfWhenMode::STD; |
1930 |
|
} |
1931 |
|
} |
1932 |
73531 |
return performCheck; |
1933 |
|
} |
1934 |
|
|
1935 |
17600 |
void QuantConflictFind::reset_round( Theory::Effort level ) { |
1936 |
17600 |
Trace("qcf-check") << "QuantConflictFind::reset_round" << std::endl; |
1937 |
17600 |
Trace("qcf-check") << "Compute relevant equivalence classes..." << std::endl; |
1938 |
17600 |
d_eqcs.clear(); |
1939 |
|
|
1940 |
17600 |
eq::EqClassesIterator eqcs_i = eq::EqClassesIterator(getEqualityEngine()); |
1941 |
17600 |
TermDb* tdb = getTermDatabase(); |
1942 |
2251684 |
while (!eqcs_i.isFinished()) |
1943 |
|
{ |
1944 |
2234084 |
Node r = (*eqcs_i); |
1945 |
1117042 |
if (tdb->hasTermCurrent(r)) |
1946 |
|
{ |
1947 |
2234084 |
TypeNode rtn = r.getType(); |
1948 |
1117042 |
if (!options::cegqi() || !TermUtil::hasInstConstAttr(r)) |
1949 |
|
{ |
1950 |
1061377 |
d_eqcs[rtn].push_back(r); |
1951 |
|
} |
1952 |
|
} |
1953 |
1117042 |
++eqcs_i; |
1954 |
|
} |
1955 |
17600 |
} |
1956 |
|
|
1957 |
230037 |
void QuantConflictFind::setIrrelevantFunction( TNode f ) { |
1958 |
230037 |
if( d_irr_func.find( f )==d_irr_func.end() ){ |
1959 |
20703 |
d_irr_func[f] = true; |
1960 |
20703 |
std::map< TNode, std::vector< Node > >::iterator it = d_func_rel_dom.find( f ); |
1961 |
20703 |
if( it != d_func_rel_dom.end()){ |
1962 |
81210 |
for( unsigned j=0; j<it->second.size(); j++ ){ |
1963 |
65430 |
d_irr_quant[it->second[j]] = true; |
1964 |
|
} |
1965 |
|
} |
1966 |
|
} |
1967 |
230037 |
} |
1968 |
|
|
1969 |
|
namespace { |
1970 |
|
|
1971 |
|
// Returns the beginning of a range of efforts. The range can be iterated |
1972 |
|
// through as unsigned using operator++. |
1973 |
13581 |
inline QuantConflictFind::Effort QcfEffortStart() { |
1974 |
13581 |
return QuantConflictFind::EFFORT_CONFLICT; |
1975 |
|
} |
1976 |
|
|
1977 |
|
// Returns the beginning of a range of efforts. The value returned is included |
1978 |
|
// in the range. |
1979 |
13581 |
inline QuantConflictFind::Effort QcfEffortEnd() { |
1980 |
13581 |
return options::qcfMode() == options::QcfMode::PROP_EQ |
1981 |
13581 |
? QuantConflictFind::EFFORT_PROP_EQ |
1982 |
13581 |
: QuantConflictFind::EFFORT_CONFLICT; |
1983 |
|
} |
1984 |
|
|
1985 |
|
} // namespace |
1986 |
|
|
1987 |
|
/** check */ |
1988 |
49423 |
void QuantConflictFind::check(Theory::Effort level, QEffort quant_e) |
1989 |
|
{ |
1990 |
63004 |
CodeTimer codeTimer(d_qstate.getStats().d_qcf_time); |
1991 |
49423 |
if (quant_e != QEFFORT_CONFLICT) |
1992 |
|
{ |
1993 |
35842 |
return; |
1994 |
|
} |
1995 |
13581 |
Trace("qcf-check") << "QCF : check : " << level << std::endl; |
1996 |
13581 |
if (d_conflict) |
1997 |
|
{ |
1998 |
|
Trace("qcf-check2") << "QCF : finished check : already in conflict." |
1999 |
|
<< std::endl; |
2000 |
|
if (level >= Theory::EFFORT_FULL) |
2001 |
|
{ |
2002 |
|
Trace("qcf-warn") << "ALREADY IN CONFLICT? " << level << std::endl; |
2003 |
|
} |
2004 |
|
return; |
2005 |
|
} |
2006 |
13581 |
unsigned addedLemmas = 0; |
2007 |
13581 |
++(d_statistics.d_inst_rounds); |
2008 |
13581 |
double clSet = 0; |
2009 |
13581 |
int prevEt = 0; |
2010 |
13581 |
if (Trace.isOn("qcf-engine")) |
2011 |
|
{ |
2012 |
|
prevEt = d_statistics.d_entailment_checks.get(); |
2013 |
|
clSet = double(clock()) / double(CLOCKS_PER_SEC); |
2014 |
|
Trace("qcf-engine") << "---Conflict Find Engine Round, effort = " << level |
2015 |
|
<< "---" << std::endl; |
2016 |
|
} |
2017 |
|
|
2018 |
|
// reset the round-specific information |
2019 |
13581 |
d_irr_func.clear(); |
2020 |
13581 |
d_irr_quant.clear(); |
2021 |
|
|
2022 |
13581 |
if (Trace.isOn("qcf-debug")) |
2023 |
|
{ |
2024 |
|
Trace("qcf-debug") << std::endl; |
2025 |
|
debugPrint("qcf-debug"); |
2026 |
|
Trace("qcf-debug") << std::endl; |
2027 |
|
} |
2028 |
13581 |
bool isConflict = false; |
2029 |
13581 |
FirstOrderModel* fm = d_treg.getModel(); |
2030 |
13581 |
unsigned nquant = fm->getNumAssertedQuantifiers(); |
2031 |
|
// for each effort level (find conflict, find propagating) |
2032 |
38598 |
for (unsigned e = QcfEffortStart(), end = QcfEffortEnd(); e <= end; ++e) |
2033 |
|
{ |
2034 |
|
// set the effort (data member for convienence of access) |
2035 |
26298 |
d_effort = static_cast<Effort>(e); |
2036 |
52596 |
Trace("qcf-check") << "Checking quantified formulas at effort " << e |
2037 |
26298 |
<< "..." << std::endl; |
2038 |
|
// for each quantified formula |
2039 |
352406 |
for (unsigned i = 0; i < nquant; i++) |
2040 |
|
{ |
2041 |
653080 |
Node q = fm->getAssertedQuantifier(i, true); |
2042 |
980916 |
if (d_qreg.hasOwnership(q, this) |
2043 |
624450 |
&& d_irr_quant.find(q) == d_irr_quant.end() |
2044 |
1202611 |
&& fm->isQuantifierActive(q)) |
2045 |
|
{ |
2046 |
|
// check this quantified formula |
2047 |
221667 |
checkQuantifiedFormula(q, isConflict, addedLemmas); |
2048 |
221667 |
if (d_conflict || d_qstate.isInConflict()) |
2049 |
|
{ |
2050 |
864 |
break; |
2051 |
|
} |
2052 |
|
} |
2053 |
|
} |
2054 |
|
// We are done if we added a lemma, or discovered a conflict in another |
2055 |
|
// way. An example of the latter case is when two disequal congruent terms |
2056 |
|
// are discovered during term indexing. |
2057 |
26298 |
if (addedLemmas > 0 || d_qstate.isInConflict()) |
2058 |
|
{ |
2059 |
1281 |
break; |
2060 |
|
} |
2061 |
|
} |
2062 |
13581 |
if (isConflict) |
2063 |
|
{ |
2064 |
|
d_conflict.set(true); |
2065 |
|
} |
2066 |
13581 |
if (Trace.isOn("qcf-engine")) |
2067 |
|
{ |
2068 |
|
double clSet2 = double(clock()) / double(CLOCKS_PER_SEC); |
2069 |
|
Trace("qcf-engine") << "Finished conflict find engine, time = " |
2070 |
|
<< (clSet2 - clSet); |
2071 |
|
if (addedLemmas > 0) |
2072 |
|
{ |
2073 |
|
Trace("qcf-engine") << ", effort = " |
2074 |
|
<< (d_effort == EFFORT_CONFLICT |
2075 |
|
? "conflict" |
2076 |
|
: (d_effort == EFFORT_PROP_EQ ? "prop_eq" |
2077 |
|
: "mc")); |
2078 |
|
Trace("qcf-engine") << ", addedLemmas = " << addedLemmas; |
2079 |
|
} |
2080 |
|
Trace("qcf-engine") << std::endl; |
2081 |
|
int currEt = d_statistics.d_entailment_checks.get(); |
2082 |
|
if (currEt != prevEt) |
2083 |
|
{ |
2084 |
|
Trace("qcf-engine") << " Entailment checks = " << (currEt - prevEt) |
2085 |
|
<< std::endl; |
2086 |
|
} |
2087 |
|
} |
2088 |
13581 |
Trace("qcf-check2") << "QCF : finished check : " << level << std::endl; |
2089 |
|
} |
2090 |
|
|
2091 |
221667 |
void QuantConflictFind::checkQuantifiedFormula(Node q, |
2092 |
|
bool& isConflict, |
2093 |
|
unsigned& addedLemmas) |
2094 |
|
{ |
2095 |
221667 |
QuantInfo* qi = &d_qinfo[q]; |
2096 |
221667 |
Assert(d_qinfo.find(q) != d_qinfo.end()); |
2097 |
221667 |
if (!qi->matchGeneratorIsValid()) |
2098 |
|
{ |
2099 |
|
// quantified formula is not properly set up for matching |
2100 |
89365 |
return; |
2101 |
|
} |
2102 |
132302 |
if (Trace.isOn("qcf-check")) |
2103 |
|
{ |
2104 |
|
Trace("qcf-check") << "Check quantified formula "; |
2105 |
|
debugPrintQuant("qcf-check", q); |
2106 |
|
Trace("qcf-check") << " : " << q << "..." << std::endl; |
2107 |
|
} |
2108 |
|
|
2109 |
132302 |
Trace("qcf-check-debug") << "Reset round..." << std::endl; |
2110 |
132302 |
if (!qi->reset_round(this)) |
2111 |
|
{ |
2112 |
|
// it is typically the case that another conflict (e.g. in the term |
2113 |
|
// database) was discovered if we fail here. |
2114 |
|
return; |
2115 |
|
} |
2116 |
|
// try to make a matches making the body false or propagating |
2117 |
132302 |
Trace("qcf-check-debug") << "Get next match..." << std::endl; |
2118 |
132302 |
Instantiate* qinst = d_qim.getInstantiate(); |
2119 |
1123372 |
while (qi->getNextMatch(this)) |
2120 |
|
{ |
2121 |
496503 |
if (d_qstate.isInConflict()) |
2122 |
|
{ |
2123 |
4 |
Trace("qcf-check") << " ... Quantifiers engine discovered conflict, "; |
2124 |
8 |
Trace("qcf-check") << "probably related to disequal congruent terms in " |
2125 |
4 |
"master equality engine" |
2126 |
4 |
<< std::endl; |
2127 |
972 |
return; |
2128 |
|
} |
2129 |
496499 |
if (Trace.isOn("qcf-inst")) |
2130 |
|
{ |
2131 |
|
Trace("qcf-inst") << "*** Produced match at effort " << d_effort << " : " |
2132 |
|
<< std::endl; |
2133 |
|
qi->debugPrintMatch("qcf-inst"); |
2134 |
|
Trace("qcf-inst") << std::endl; |
2135 |
|
} |
2136 |
|
// check whether internal match constraints are satisfied |
2137 |
535463 |
if (qi->isMatchSpurious(this)) |
2138 |
|
{ |
2139 |
77928 |
Trace("qcf-inst") << " ... Spurious (match is inconsistent)" |
2140 |
38964 |
<< std::endl; |
2141 |
78058 |
continue; |
2142 |
|
} |
2143 |
|
// check whether match can be completed |
2144 |
913976 |
std::vector<int> assigned; |
2145 |
457665 |
if (!qi->completeMatch(this, assigned)) |
2146 |
|
{ |
2147 |
260 |
Trace("qcf-inst") << " ... Spurious (cannot assign unassigned vars)" |
2148 |
130 |
<< std::endl; |
2149 |
130 |
continue; |
2150 |
|
} |
2151 |
|
// check whether the match is spurious according to (T-)entailment checks |
2152 |
913846 |
std::vector<Node> terms; |
2153 |
457405 |
qi->getMatch(terms); |
2154 |
457405 |
bool tcs = qi->isTConstraintSpurious(this, terms); |
2155 |
457405 |
if (tcs) |
2156 |
|
{ |
2157 |
910562 |
Trace("qcf-inst") << " ... Spurious (match is T-inconsistent)" |
2158 |
455281 |
<< std::endl; |
2159 |
|
} |
2160 |
|
else |
2161 |
|
{ |
2162 |
|
// otherwise, we have a conflict/propagating instance |
2163 |
|
// for debugging |
2164 |
2124 |
if (Debug.isOn("qcf-check-inst")) |
2165 |
|
{ |
2166 |
|
Node inst = qinst->getInstantiation(q, terms); |
2167 |
|
Debug("qcf-check-inst") |
2168 |
|
<< "Check instantiation " << inst << "..." << std::endl; |
2169 |
|
Assert(!getTermDatabase()->isEntailed(inst, true)); |
2170 |
|
Assert(getTermDatabase()->isEntailed(inst, false) |
2171 |
|
|| d_effort > EFFORT_CONFLICT); |
2172 |
|
} |
2173 |
|
// Process the lemma: either add an instantiation or specific lemmas |
2174 |
|
// constructed during the isTConstraintSpurious call, or both. |
2175 |
4248 |
InferenceId id = (d_effort == EFFORT_CONFLICT |
2176 |
2124 |
? InferenceId::QUANTIFIERS_INST_CBQI_CONFLICT |
2177 |
|
: InferenceId::QUANTIFIERS_INST_CBQI_PROP); |
2178 |
2124 |
if (!qinst->addInstantiation(q, terms, id)) |
2179 |
|
{ |
2180 |
106 |
Trace("qcf-inst") << " ... Failed to add instantiation" << std::endl; |
2181 |
|
// This should only happen if the algorithm generates the same |
2182 |
|
// propagating instance twice this round. In this case, return |
2183 |
|
// to avoid exponential behavior. |
2184 |
106 |
return; |
2185 |
|
} |
2186 |
2018 |
Trace("qcf-check") << " ... Added instantiation" << std::endl; |
2187 |
2018 |
if (Trace.isOn("qcf-inst")) |
2188 |
|
{ |
2189 |
|
Trace("qcf-inst") << "*** Was from effort " << d_effort << " : " |
2190 |
|
<< std::endl; |
2191 |
|
qi->debugPrintMatch("qcf-inst"); |
2192 |
|
Trace("qcf-inst") << std::endl; |
2193 |
|
} |
2194 |
2018 |
++addedLemmas; |
2195 |
2018 |
if (d_effort == EFFORT_CONFLICT) |
2196 |
|
{ |
2197 |
|
// mark relevant: this ensures that quantified formula q is |
2198 |
|
// checked first on the next round. This is an optimization to |
2199 |
|
// ensure that quantified formulas that are more likely to have |
2200 |
|
// conflicting instances are checked earlier. |
2201 |
858 |
d_treg.getModel()->markRelevant(q); |
2202 |
1716 |
if (options::qcfAllConflict()) |
2203 |
|
{ |
2204 |
|
isConflict = true; |
2205 |
|
} |
2206 |
|
else |
2207 |
|
{ |
2208 |
858 |
d_conflict.set(true); |
2209 |
|
} |
2210 |
858 |
return; |
2211 |
|
} |
2212 |
1160 |
else if (d_effort == EFFORT_PROP_EQ) |
2213 |
|
{ |
2214 |
1160 |
d_treg.getModel()->markRelevant(q); |
2215 |
|
} |
2216 |
|
} |
2217 |
|
// clean up assigned |
2218 |
456441 |
qi->revertMatch(this, assigned); |
2219 |
456441 |
d_tempCache.clear(); |
2220 |
|
} |
2221 |
131334 |
Trace("qcf-check") << "Done, conflict = " << d_conflict << std::endl; |
2222 |
|
} |
2223 |
|
|
2224 |
|
//-------------------------------------------------- debugging |
2225 |
|
|
2226 |
|
void QuantConflictFind::debugPrint( const char * c ) { |
2227 |
|
//print the equivalance classes |
2228 |
|
Trace(c) << "----------EQ classes" << std::endl; |
2229 |
|
eq::EqClassesIterator eqcs_i = eq::EqClassesIterator( getEqualityEngine() ); |
2230 |
|
while( !eqcs_i.isFinished() ){ |
2231 |
|
Node n = (*eqcs_i); |
2232 |
|
//if( !n.getType().isInteger() ){ |
2233 |
|
Trace(c) << " - " << n << " : {"; |
2234 |
|
eq::EqClassIterator eqc_i = eq::EqClassIterator( n, getEqualityEngine() ); |
2235 |
|
bool pr = false; |
2236 |
|
while( !eqc_i.isFinished() ){ |
2237 |
|
Node nn = (*eqc_i); |
2238 |
|
if( nn.getKind()!=EQUAL && nn!=n ){ |
2239 |
|
Trace(c) << (pr ? "," : "" ) << " " << nn; |
2240 |
|
pr = true; |
2241 |
|
} |
2242 |
|
++eqc_i; |
2243 |
|
} |
2244 |
|
Trace(c) << (pr ? " " : "" ) << "}" << std::endl; |
2245 |
|
++eqcs_i; |
2246 |
|
} |
2247 |
|
} |
2248 |
|
|
2249 |
|
void QuantConflictFind::debugPrintQuant( const char * c, Node q ) { |
2250 |
|
Trace(c) << "Q" << d_quant_id[q]; |
2251 |
|
} |
2252 |
|
|
2253 |
|
void QuantConflictFind::debugPrintQuantBody( const char * c, Node q, Node n, bool doVarNum ) { |
2254 |
|
if( n.getNumChildren()==0 ){ |
2255 |
|
Trace(c) << n; |
2256 |
|
}else if( doVarNum && d_qinfo[q].d_var_num.find( n )!=d_qinfo[q].d_var_num.end() ){ |
2257 |
|
Trace(c) << "?x" << d_qinfo[q].d_var_num[n]; |
2258 |
|
}else{ |
2259 |
|
Trace(c) << "("; |
2260 |
|
if( n.getKind()==APPLY_UF ){ |
2261 |
|
Trace(c) << n.getOperator(); |
2262 |
|
}else{ |
2263 |
|
Trace(c) << n.getKind(); |
2264 |
|
} |
2265 |
|
for( unsigned i=0; i<n.getNumChildren(); i++ ){ |
2266 |
|
Trace(c) << " "; |
2267 |
|
debugPrintQuantBody( c, q, n[i] ); |
2268 |
|
} |
2269 |
|
Trace(c) << ")"; |
2270 |
|
} |
2271 |
|
} |
2272 |
|
|
2273 |
4478 |
QuantConflictFind::Statistics::Statistics() |
2274 |
|
: d_inst_rounds( |
2275 |
8956 |
smtStatisticsRegistry().registerInt("QuantConflictFind::Inst_Rounds")), |
2276 |
4478 |
d_entailment_checks(smtStatisticsRegistry().registerInt( |
2277 |
8956 |
"QuantConflictFind::Entailment_Checks")) |
2278 |
|
{ |
2279 |
4478 |
} |
2280 |
|
|
2281 |
8 |
TNode QuantConflictFind::getZero( Kind k ) { |
2282 |
8 |
std::map< Kind, Node >::iterator it = d_zero.find( k ); |
2283 |
8 |
if( it==d_zero.end() ){ |
2284 |
16 |
Node nn; |
2285 |
8 |
if( k==PLUS ){ |
2286 |
4 |
nn = NodeManager::currentNM()->mkConst( Rational(0) ); |
2287 |
|
} |
2288 |
8 |
d_zero[k] = nn; |
2289 |
8 |
return nn; |
2290 |
|
}else{ |
2291 |
|
return it->second; |
2292 |
|
} |
2293 |
|
} |
2294 |
|
|
2295 |
|
std::ostream& operator<<(std::ostream& os, const QuantConflictFind::Effort& e) { |
2296 |
|
switch (e) { |
2297 |
|
case QuantConflictFind::EFFORT_INVALID: |
2298 |
|
os << "Invalid"; |
2299 |
|
break; |
2300 |
|
case QuantConflictFind::EFFORT_CONFLICT: |
2301 |
|
os << "Conflict"; |
2302 |
|
break; |
2303 |
|
case QuantConflictFind::EFFORT_PROP_EQ: |
2304 |
|
os << "PropEq"; |
2305 |
|
break; |
2306 |
|
} |
2307 |
|
return os; |
2308 |
|
} |
2309 |
|
|
2310 |
1256 |
bool QuantConflictFind::isPropagatingInstance(Node n) const |
2311 |
|
{ |
2312 |
2512 |
std::unordered_set<TNode> visited; |
2313 |
2512 |
std::vector<TNode> visit; |
2314 |
2512 |
TNode cur; |
2315 |
1256 |
visit.push_back(n); |
2316 |
2673 |
do |
2317 |
|
{ |
2318 |
3929 |
cur = visit.back(); |
2319 |
3929 |
visit.pop_back(); |
2320 |
3929 |
if (visited.find(cur) == visited.end()) |
2321 |
|
{ |
2322 |
3887 |
visited.insert(cur); |
2323 |
3887 |
Kind ck = cur.getKind(); |
2324 |
3887 |
if (ck == FORALL) |
2325 |
|
{ |
2326 |
|
// do nothing |
2327 |
|
} |
2328 |
3791 |
else if (TermUtil::isBoolConnective(ck)) |
2329 |
|
{ |
2330 |
4028 |
for (TNode cc : cur) |
2331 |
|
{ |
2332 |
2673 |
visit.push_back(cc); |
2333 |
|
} |
2334 |
|
} |
2335 |
2436 |
else if (!getEqualityEngine()->hasTerm(cur)) |
2336 |
|
{ |
2337 |
|
Trace("qcf-instance-check-debug") |
2338 |
|
<< "...not propagating instance because of " << cur << " " << ck |
2339 |
|
<< std::endl; |
2340 |
|
return false; |
2341 |
|
} |
2342 |
|
} |
2343 |
3929 |
} while (!visit.empty()); |
2344 |
1256 |
return true; |
2345 |
|
} |
2346 |
|
|
2347 |
|
} // namespace quantifiers |
2348 |
|
} // namespace theory |
2349 |
1929174 |
} // namespace cvc5 |