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 |
|
#include "util/rational.h" |
32 |
|
|
33 |
|
using namespace cvc5::kind; |
34 |
|
using namespace std; |
35 |
|
|
36 |
|
namespace cvc5 { |
37 |
|
namespace theory { |
38 |
|
namespace quantifiers { |
39 |
|
|
40 |
8633 |
QuantInfo::QuantInfo() |
41 |
8633 |
: d_unassigned_nvar(0), d_una_index(0), d_parent(nullptr), d_mg(nullptr) |
42 |
|
{ |
43 |
8633 |
} |
44 |
|
|
45 |
17266 |
QuantInfo::~QuantInfo() { |
46 |
8633 |
delete d_mg; |
47 |
40026 |
for(std::map< int, MatchGen * >::iterator i = d_var_mg.begin(), |
48 |
8633 |
iend=d_var_mg.end(); i != iend; ++i) { |
49 |
31393 |
MatchGen* currentMatchGenerator = (*i).second; |
50 |
31393 |
delete currentMatchGenerator; |
51 |
|
} |
52 |
8633 |
d_var_mg.clear(); |
53 |
8633 |
} |
54 |
|
|
55 |
31408 |
QuantifiersInferenceManager& QuantInfo::getInferenceManager() |
56 |
|
{ |
57 |
31408 |
Assert(d_parent != nullptr); |
58 |
31408 |
return d_parent->getInferenceManager(); |
59 |
|
} |
60 |
|
|
61 |
8633 |
void QuantInfo::initialize( QuantConflictFind * p, Node q, Node qn ) { |
62 |
8633 |
d_parent = p; |
63 |
8633 |
d_q = q; |
64 |
8633 |
d_extra_var.clear(); |
65 |
28405 |
for( unsigned i=0; i<q[0].getNumChildren(); i++ ){ |
66 |
19772 |
d_match.push_back( TNode::null() ); |
67 |
19772 |
d_match_term.push_back( TNode::null() ); |
68 |
|
} |
69 |
|
|
70 |
|
//register the variables |
71 |
28405 |
for( unsigned i=0; i<q[0].getNumChildren(); i++ ){ |
72 |
19772 |
d_var_num[q[0][i]] = i; |
73 |
19772 |
d_vars.push_back( q[0][i] ); |
74 |
19772 |
d_var_types.push_back( q[0][i].getType() ); |
75 |
|
} |
76 |
|
|
77 |
8633 |
registerNode( qn, true, true ); |
78 |
|
|
79 |
|
|
80 |
8633 |
Trace("qcf-qregister") << "- Make match gen structure..." << std::endl; |
81 |
8633 |
d_mg = new MatchGen( this, qn ); |
82 |
|
|
83 |
8633 |
if( d_mg->isValid() ){ |
84 |
|
/* |
85 |
|
for( unsigned j=0; j<q[0].getNumChildren(); j++ ){ |
86 |
|
if( d_inMatchConstraint.find( q[0][j] )==d_inMatchConstraint.end() ){ |
87 |
|
Trace("qcf-invalid") << "QCF invalid : variable " << q[0][j] << " does not exist in a matching constraint." << std::endl; |
88 |
|
d_mg->setInvalid(); |
89 |
|
break; |
90 |
|
} |
91 |
|
} |
92 |
|
*/ |
93 |
40435 |
for( unsigned j=q[0].getNumChildren(); j<d_vars.size(); j++ ){ |
94 |
33834 |
if( d_vars[j].getKind()!=BOUND_VARIABLE ){ |
95 |
31393 |
d_var_mg[j] = NULL; |
96 |
31393 |
bool is_tsym = false; |
97 |
31393 |
if( !MatchGen::isHandledUfTerm( d_vars[j] ) && d_vars[j].getKind()!=ITE ){ |
98 |
291 |
is_tsym = true; |
99 |
291 |
d_tsym_vars.push_back( j ); |
100 |
|
} |
101 |
31393 |
if( !is_tsym || options::qcfTConstraint() ){ |
102 |
31226 |
d_var_mg[j] = new MatchGen( this, d_vars[j], true ); |
103 |
|
} |
104 |
31393 |
if( !d_var_mg[j] || !d_var_mg[j]->isValid() ){ |
105 |
726 |
Trace("qcf-invalid") << "QCF invalid : cannot match for " << d_vars[j] << std::endl; |
106 |
726 |
d_mg->setInvalid(); |
107 |
726 |
break; |
108 |
|
}else{ |
109 |
61334 |
std::vector< int > bvars; |
110 |
30667 |
d_var_mg[j]->determineVariableOrder( this, bvars ); |
111 |
|
} |
112 |
|
} |
113 |
|
} |
114 |
7327 |
if( d_mg->isValid() ){ |
115 |
13202 |
std::vector< int > bvars; |
116 |
6601 |
d_mg->determineVariableOrder( this, bvars ); |
117 |
|
} |
118 |
|
}else{ |
119 |
1306 |
Trace("qcf-invalid") << "QCF invalid : body of formula cannot be processed." << std::endl; |
120 |
|
} |
121 |
8633 |
Trace("qcf-qregister-summary") << "QCF register : " << ( d_mg->isValid() ? "VALID " : "INVALID" ) << " : " << q << std::endl; |
122 |
|
|
123 |
8633 |
if( d_mg->isValid() && options::qcfEagerCheckRd() ){ |
124 |
|
//optimization : record variable argument positions for terms that must be matched |
125 |
13202 |
std::vector< TNode > vars; |
126 |
|
//TODO: revisit this, makes QCF faster, but misses conflicts due to caring about paths that may not be relevant (starExec jobs 14136/14137) |
127 |
6601 |
if( options::qcfSkipRd() ){ |
128 |
|
for( unsigned j=q[0].getNumChildren(); j<d_vars.size(); j++ ){ |
129 |
|
vars.push_back( d_vars[j] ); |
130 |
|
} |
131 |
|
}else{ |
132 |
|
//get all variables that are always relevant |
133 |
13202 |
std::map< TNode, bool > visited; |
134 |
6601 |
getPropagateVars( p, vars, q[1], false, visited ); |
135 |
|
} |
136 |
37164 |
for( unsigned j=0; j<vars.size(); j++ ){ |
137 |
61126 |
Node v = vars[j]; |
138 |
61126 |
TNode f = p->getTermDatabase()->getMatchOperator( v ); |
139 |
30563 |
if( !f.isNull() ){ |
140 |
18610 |
Trace("qcf-opt") << "Record variable argument positions in " << v << ", op=" << f << "..." << std::endl; |
141 |
58936 |
for( unsigned k=0; k<v.getNumChildren(); k++ ){ |
142 |
80652 |
Node n = v[k]; |
143 |
40326 |
std::map< TNode, int >::iterator itv = d_var_num.find( n ); |
144 |
40326 |
if( itv!=d_var_num.end() ){ |
145 |
34735 |
Trace("qcf-opt") << " arg " << k << " is var #" << itv->second << std::endl; |
146 |
34735 |
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() ){ |
147 |
32723 |
d_var_rel_dom[itv->second][f].push_back( k ); |
148 |
|
} |
149 |
|
} |
150 |
|
} |
151 |
|
} |
152 |
|
} |
153 |
|
} |
154 |
8633 |
} |
155 |
|
|
156 |
76789 |
void QuantInfo::getPropagateVars( QuantConflictFind * p, std::vector< TNode >& vars, TNode n, bool pol, std::map< TNode, bool >& visited ){ |
157 |
76789 |
std::map< TNode, bool >::iterator itv = visited.find( n ); |
158 |
76789 |
if( itv==visited.end() ){ |
159 |
57809 |
visited[n] = true; |
160 |
57809 |
bool rec = true; |
161 |
57809 |
bool newPol = pol; |
162 |
57809 |
if( d_var_num.find( n )!=d_var_num.end() ){ |
163 |
30563 |
Assert(std::find(vars.begin(), vars.end(), n) == vars.end()); |
164 |
30563 |
vars.push_back( n ); |
165 |
61126 |
TNode f = p->getTermDatabase()->getMatchOperator( n ); |
166 |
30563 |
if( !f.isNull() ){ |
167 |
18610 |
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() ){ |
168 |
14388 |
p->d_func_rel_dom[f].push_back( d_q ); |
169 |
|
} |
170 |
|
} |
171 |
27246 |
}else if( MatchGen::isHandledBoolConnective( n ) ){ |
172 |
10929 |
Assert(n.getKind() != IMPLIES); |
173 |
10929 |
QuantPhaseReq::getEntailPolarity( n, 0, true, pol, rec, newPol ); |
174 |
|
} |
175 |
57809 |
Trace("qcf-opt-debug") << "getPropagateVars " << n << ", pol = " << pol << ", rec = " << rec << std::endl; |
176 |
57809 |
if( rec ){ |
177 |
125503 |
for( unsigned i=0; i<n.getNumChildren(); i++ ){ |
178 |
70188 |
getPropagateVars( p, vars, n[i], pol, visited ); |
179 |
|
} |
180 |
|
} |
181 |
|
} |
182 |
76789 |
} |
183 |
|
|
184 |
646101 |
bool QuantInfo::isBaseMatchComplete() { |
185 |
646101 |
return d_vars_set.size()==(d_q[0].getNumChildren()+d_extra_var.size()); |
186 |
|
} |
187 |
|
|
188 |
46014 |
void QuantInfo::registerNode( Node n, bool hasPol, bool pol, bool beneathQuant ) { |
189 |
46014 |
Trace("qcf-qregister-debug2") << "Register : " << n << std::endl; |
190 |
46014 |
if( n.getKind()==FORALL ){ |
191 |
2064 |
registerNode( n[1], hasPol, pol, true ); |
192 |
|
}else{ |
193 |
43950 |
if( !MatchGen::isHandledBoolConnective( n ) ){ |
194 |
24104 |
if (expr::hasBoundVar(n)) |
195 |
|
{ |
196 |
|
// literals |
197 |
24047 |
if (n.getKind() == EQUAL) |
198 |
|
{ |
199 |
36966 |
for (unsigned i = 0; i < n.getNumChildren(); i++) |
200 |
|
{ |
201 |
24644 |
flatten(n[i], beneathQuant); |
202 |
|
} |
203 |
|
} |
204 |
11725 |
else if (MatchGen::isHandledUfTerm(n)) |
205 |
|
{ |
206 |
7695 |
flatten(n, beneathQuant); |
207 |
|
} |
208 |
4030 |
else if (n.getKind() == ITE) |
209 |
|
{ |
210 |
2073 |
for (unsigned i = 1; i <= 2; i++) |
211 |
|
{ |
212 |
1382 |
flatten(n[i], beneathQuant); |
213 |
|
} |
214 |
691 |
registerNode(n[0], false, pol, beneathQuant); |
215 |
|
} |
216 |
3339 |
else if (options::qcfTConstraint()) |
217 |
|
{ |
218 |
|
// a theory-specific predicate |
219 |
330 |
for (unsigned i = 0; i < n.getNumChildren(); i++) |
220 |
|
{ |
221 |
220 |
flatten(n[i], beneathQuant); |
222 |
|
} |
223 |
|
} |
224 |
|
} |
225 |
|
}else{ |
226 |
53781 |
for( unsigned i=0; i<n.getNumChildren(); i++ ){ |
227 |
|
bool newHasPol; |
228 |
|
bool newPol; |
229 |
33935 |
QuantPhaseReq::getPolarity( n, i, hasPol, pol, newHasPol, newPol ); |
230 |
|
//QcfNode * qcfc = new QcfNode( d_c ); |
231 |
|
//qcfc->d_parent = qcf; |
232 |
|
//qcf->d_child[i] = qcfc; |
233 |
33935 |
registerNode( n[i], newHasPol, newPol, beneathQuant ); |
234 |
|
} |
235 |
|
} |
236 |
|
} |
237 |
46014 |
} |
238 |
|
|
239 |
110397 |
void QuantInfo::flatten( Node n, bool beneathQuant ) { |
240 |
110397 |
Trace("qcf-qregister-debug2") << "Flatten : " << n << std::endl; |
241 |
110397 |
if (expr::hasBoundVar(n)) |
242 |
|
{ |
243 |
92040 |
if( n.getKind()==BOUND_VARIABLE ){ |
244 |
47218 |
d_inMatchConstraint[n] = true; |
245 |
|
} |
246 |
92040 |
if( d_var_num.find( n )==d_var_num.end() ){ |
247 |
41047 |
Trace("qcf-qregister-debug2") << "Add FLATTEN VAR : " << n << std::endl; |
248 |
41047 |
d_var_num[n] = d_vars.size(); |
249 |
41047 |
d_vars.push_back( n ); |
250 |
41047 |
d_var_types.push_back( n.getType() ); |
251 |
41047 |
d_match.push_back( TNode::null() ); |
252 |
41047 |
d_match_term.push_back( TNode::null() ); |
253 |
41047 |
if( n.getKind()==ITE ){ |
254 |
691 |
registerNode( n, false, false ); |
255 |
40356 |
}else if( n.getKind()==BOUND_VARIABLE ){ |
256 |
2768 |
d_extra_var.push_back( n ); |
257 |
|
}else{ |
258 |
114044 |
for( unsigned i=0; i<n.getNumChildren(); i++ ){ |
259 |
76456 |
flatten( n[i], beneathQuant ); |
260 |
|
} |
261 |
|
} |
262 |
|
}else{ |
263 |
50993 |
Trace("qcf-qregister-debug2") << "...already processed" << std::endl; |
264 |
|
} |
265 |
|
}else{ |
266 |
18357 |
Trace("qcf-qregister-debug2") << "...is ground." << std::endl; |
267 |
|
} |
268 |
110397 |
} |
269 |
|
|
270 |
|
|
271 |
50507 |
bool QuantInfo::reset_round( QuantConflictFind * p ) { |
272 |
375893 |
for( unsigned i=0; i<d_match.size(); i++ ){ |
273 |
325386 |
d_match[i] = TNode::null(); |
274 |
325386 |
d_match_term[i] = TNode::null(); |
275 |
|
} |
276 |
50507 |
d_vars_set.clear(); |
277 |
50507 |
d_curr_var_deq.clear(); |
278 |
50507 |
d_tconstraints.clear(); |
279 |
|
|
280 |
50507 |
d_mg->reset_round( p ); |
281 |
245173 |
for( std::map< int, MatchGen * >::iterator it = d_var_mg.begin(); it != d_var_mg.end(); ++it ){ |
282 |
194666 |
if (!it->second->reset_round(p)) |
283 |
|
{ |
284 |
|
return false; |
285 |
|
} |
286 |
|
} |
287 |
|
//now, reset for matching |
288 |
50507 |
d_mg->reset( p, false, this ); |
289 |
50507 |
return true; |
290 |
|
} |
291 |
|
|
292 |
2052360 |
int QuantInfo::getCurrentRepVar( int v ) { |
293 |
2052360 |
if( v!=-1 && !d_match[v].isNull() ){ |
294 |
1060059 |
int vn = getVarNum( d_match[v] ); |
295 |
1060059 |
if( vn!=-1 ){ |
296 |
|
//int vr = getCurrentRepVar( vn ); |
297 |
|
//d_match[v] = d_vars[vr]; |
298 |
|
//return vr; |
299 |
9833 |
return getCurrentRepVar( vn ); |
300 |
|
} |
301 |
|
} |
302 |
2042527 |
return v; |
303 |
|
} |
304 |
|
|
305 |
1098328 |
TNode QuantInfo::getCurrentValue( TNode n ) { |
306 |
1098328 |
int v = getVarNum( n ); |
307 |
1098328 |
if( v==-1 ){ |
308 |
608368 |
return n; |
309 |
|
}else{ |
310 |
489960 |
if( d_match[v].isNull() ){ |
311 |
456935 |
return n; |
312 |
|
}else{ |
313 |
33025 |
Assert(getVarNum(d_match[v]) != v); |
314 |
33025 |
return getCurrentValue( d_match[v] ); |
315 |
|
} |
316 |
|
} |
317 |
|
} |
318 |
|
|
319 |
1 |
TNode QuantInfo::getCurrentExpValue( TNode n ) { |
320 |
1 |
int v = getVarNum( n ); |
321 |
1 |
if( v==-1 ){ |
322 |
|
return n; |
323 |
|
}else{ |
324 |
1 |
if( d_match[v].isNull() ){ |
325 |
|
return n; |
326 |
|
}else{ |
327 |
1 |
Assert(getVarNum(d_match[v]) != v); |
328 |
1 |
if( d_match_term[v].isNull() ){ |
329 |
1 |
return getCurrentValue( d_match[v] ); |
330 |
|
}else{ |
331 |
|
return d_match_term[v]; |
332 |
|
} |
333 |
|
} |
334 |
|
} |
335 |
|
} |
336 |
|
|
337 |
1640181 |
bool QuantInfo::getCurrentCanBeEqual( QuantConflictFind * p, int v, TNode n, bool chDiseq ) { |
338 |
|
//check disequalities |
339 |
1640181 |
std::map< int, std::map< TNode, int > >::iterator itd = d_curr_var_deq.find( v ); |
340 |
1640181 |
if( itd!=d_curr_var_deq.end() ){ |
341 |
1931991 |
for( std::map< TNode, int >::iterator it = itd->second.begin(); it != itd->second.end(); ++it ){ |
342 |
867301 |
Node cv = getCurrentValue( it->first ); |
343 |
451208 |
Debug("qcf-ccbe") << "compare " << cv << " " << n << std::endl; |
344 |
451208 |
if( cv==n ){ |
345 |
24916 |
return false; |
346 |
426292 |
}else if( chDiseq && !isVar( n ) && !isVar( cv ) ){ |
347 |
|
//they must actually be disequal if we are looking for conflicts |
348 |
17800 |
if( !p->areDisequal( n, cv ) ){ |
349 |
|
//TODO : check for entailed disequal |
350 |
|
|
351 |
10199 |
return false; |
352 |
|
} |
353 |
|
} |
354 |
|
} |
355 |
|
} |
356 |
1605066 |
return true; |
357 |
|
} |
358 |
|
|
359 |
|
int QuantInfo::addConstraint( QuantConflictFind * p, int v, TNode n, bool polarity ) { |
360 |
|
v = getCurrentRepVar( v ); |
361 |
|
int vn = getVarNum( n ); |
362 |
|
vn = vn==-1 ? -1 : getCurrentRepVar( vn ); |
363 |
|
n = getCurrentValue( n ); |
364 |
|
return addConstraint( p, v, n, vn, polarity, false ); |
365 |
|
} |
366 |
|
|
367 |
267791 |
int QuantInfo::addConstraint( QuantConflictFind * p, int v, TNode n, int vn, bool polarity, bool doRemove ) { |
368 |
|
//for handling equalities between variables, and disequalities involving variables |
369 |
267791 |
Debug("qcf-match-debug") << "- " << (doRemove ? "un" : "" ) << "constrain : " << v << " -> " << n << " (cv=" << getCurrentValue( n ) << ")"; |
370 |
267791 |
Debug("qcf-match-debug") << ", (vn=" << vn << "), polarity = " << polarity << std::endl; |
371 |
267791 |
Assert(doRemove || n == getCurrentValue(n)); |
372 |
267791 |
Assert(doRemove || v == getCurrentRepVar(v)); |
373 |
267791 |
Assert(doRemove || vn == getCurrentRepVar(getVarNum(n))); |
374 |
267791 |
if( polarity ){ |
375 |
185889 |
if( vn!=v ){ |
376 |
185889 |
if( doRemove ){ |
377 |
92611 |
if( vn!=-1 ){ |
378 |
|
//if set to this in the opposite direction, clean up opposite instead |
379 |
|
// std::map< int, TNode >::iterator itmn = d_match.find( vn ); |
380 |
8394 |
if( d_match[vn]==d_vars[v] ){ |
381 |
|
return addConstraint( p, vn, d_vars[v], v, true, true ); |
382 |
|
}else{ |
383 |
|
//unsetting variables equal |
384 |
8394 |
std::map< int, std::map< TNode, int > >::iterator itd = d_curr_var_deq.find( vn ); |
385 |
8394 |
if( itd!=d_curr_var_deq.end() ){ |
386 |
|
//remove disequalities owned by this |
387 |
11262 |
std::vector< TNode > remDeq; |
388 |
5668 |
for( std::map< TNode, int >::iterator it = itd->second.begin(); it != itd->second.end(); ++it ){ |
389 |
37 |
if( it->second==v ){ |
390 |
37 |
remDeq.push_back( it->first ); |
391 |
|
} |
392 |
|
} |
393 |
5668 |
for( unsigned i=0; i<remDeq.size(); i++ ){ |
394 |
37 |
d_curr_var_deq[vn].erase( remDeq[i] ); |
395 |
|
} |
396 |
|
} |
397 |
|
} |
398 |
|
} |
399 |
92611 |
unsetMatch( p, v ); |
400 |
92611 |
return 1; |
401 |
|
}else{ |
402 |
|
//std::map< int, TNode >::iterator itm = d_match.find( v ); |
403 |
93278 |
bool isGroundRep = false; |
404 |
93278 |
bool isGround = false; |
405 |
93278 |
if( vn!=-1 ){ |
406 |
8534 |
Debug("qcf-match-debug") << " ...Variable bound to variable" << std::endl; |
407 |
|
//std::map< int, TNode >::iterator itmn = d_match.find( vn ); |
408 |
8534 |
if( d_match[v].isNull() ){ |
409 |
|
//setting variables equal |
410 |
8534 |
bool alreadySet = false; |
411 |
8534 |
if( !d_match[vn].isNull() ){ |
412 |
|
alreadySet = true; |
413 |
|
Assert(!isVar(d_match[vn])); |
414 |
|
} |
415 |
|
|
416 |
|
//copy or check disequalities |
417 |
8534 |
std::map< int, std::map< TNode, int > >::iterator itd = d_curr_var_deq.find( v ); |
418 |
8534 |
if( itd!=d_curr_var_deq.end() ){ |
419 |
5998 |
for( std::map< TNode, int >::iterator it = itd->second.begin(); it != itd->second.end(); ++it ){ |
420 |
74 |
Node dv = getCurrentValue( it->first ); |
421 |
37 |
if( !alreadySet ){ |
422 |
37 |
if( d_curr_var_deq[vn].find( dv )==d_curr_var_deq[vn].end() ){ |
423 |
37 |
d_curr_var_deq[vn][dv] = v; |
424 |
|
} |
425 |
|
}else{ |
426 |
|
if( !p->areMatchDisequal( d_match[vn], dv ) ){ |
427 |
|
Debug("qcf-match-debug") << " -> fail, conflicting disequality" << std::endl; |
428 |
|
return -1; |
429 |
|
} |
430 |
|
} |
431 |
|
} |
432 |
|
} |
433 |
8534 |
if( alreadySet ){ |
434 |
|
n = getCurrentValue( n ); |
435 |
|
} |
436 |
|
}else{ |
437 |
|
if( d_match[vn].isNull() ){ |
438 |
|
Debug("qcf-match-debug") << " ...Reverse direction" << std::endl; |
439 |
|
//set the opposite direction |
440 |
|
return addConstraint( p, vn, d_vars[v], v, true, false ); |
441 |
|
}else{ |
442 |
|
Debug("qcf-match-debug") << " -> Both variables bound, compare" << std::endl; |
443 |
|
//are they currently equal |
444 |
|
return p->areMatchEqual( d_match[v], d_match[vn] ) ? 0 : -1; |
445 |
|
} |
446 |
|
} |
447 |
|
}else{ |
448 |
84744 |
Debug("qcf-match-debug") << " ...Variable bound to ground" << std::endl; |
449 |
84744 |
if( d_match[v].isNull() ){ |
450 |
|
//isGroundRep = true; ?? |
451 |
84744 |
isGround = true; |
452 |
|
}else{ |
453 |
|
//compare ground values |
454 |
|
Debug("qcf-match-debug") << " -> Ground value, compare " << d_match[v] << " "<< n << std::endl; |
455 |
|
return p->areMatchEqual( d_match[v], n ) ? 0 : -1; |
456 |
|
} |
457 |
|
} |
458 |
93278 |
if( setMatch( p, v, n, isGroundRep, isGround ) ){ |
459 |
93271 |
Debug("qcf-match-debug") << " -> success" << std::endl; |
460 |
93271 |
return 1; |
461 |
|
}else{ |
462 |
7 |
Debug("qcf-match-debug") << " -> fail, conflicting disequality" << std::endl; |
463 |
7 |
return -1; |
464 |
|
} |
465 |
|
} |
466 |
|
}else{ |
467 |
|
Debug("qcf-match-debug") << " -> redundant, variable identity" << std::endl; |
468 |
|
return 0; |
469 |
|
} |
470 |
|
}else{ |
471 |
81902 |
if( vn==v ){ |
472 |
|
Debug("qcf-match-debug") << " -> fail, variable identity" << std::endl; |
473 |
|
return -1; |
474 |
|
}else{ |
475 |
81902 |
if( doRemove ){ |
476 |
40816 |
Assert(d_curr_var_deq[v].find(n) != d_curr_var_deq[v].end()); |
477 |
40816 |
d_curr_var_deq[v].erase( n ); |
478 |
40816 |
return 1; |
479 |
|
}else{ |
480 |
41086 |
if( d_curr_var_deq[v].find( n )==d_curr_var_deq[v].end() ){ |
481 |
|
//check if it respects equality |
482 |
|
//std::map< int, TNode >::iterator itm = d_match.find( v ); |
483 |
41034 |
if( !d_match[v].isNull() ){ |
484 |
|
TNode nv = getCurrentValue( n ); |
485 |
|
if( !p->areMatchDisequal( nv, d_match[v] ) ){ |
486 |
|
Debug("qcf-match-debug") << " -> fail, conflicting disequality" << std::endl; |
487 |
|
return -1; |
488 |
|
} |
489 |
|
} |
490 |
41034 |
d_curr_var_deq[v][n] = v; |
491 |
41034 |
Debug("qcf-match-debug") << " -> success" << std::endl; |
492 |
41034 |
return 1; |
493 |
|
}else{ |
494 |
52 |
Debug("qcf-match-debug") << " -> redundant disequality" << std::endl; |
495 |
52 |
return 0; |
496 |
|
} |
497 |
|
} |
498 |
|
} |
499 |
|
} |
500 |
|
} |
501 |
|
|
502 |
70 |
bool QuantInfo::isConstrainedVar( int v ) { |
503 |
70 |
if( d_curr_var_deq.find( v )!=d_curr_var_deq.end() && !d_curr_var_deq[v].empty() ){ |
504 |
|
return true; |
505 |
|
}else{ |
506 |
140 |
Node vv = getVar( v ); |
507 |
|
//for( std::map< int, TNode >::iterator it = d_match.begin(); it != d_match.end(); ++it ){ |
508 |
1020 |
for( unsigned i=0; i<d_match.size(); i++ ){ |
509 |
950 |
if( d_match[i]==vv ){ |
510 |
|
return true; |
511 |
|
} |
512 |
|
} |
513 |
490 |
for( std::map< int, std::map< TNode, int > >::iterator it = d_curr_var_deq.begin(); it != d_curr_var_deq.end(); ++it ){ |
514 |
484 |
for( std::map< TNode, int >::iterator it2 = it->second.begin(); it2 != it->second.end(); ++it2 ){ |
515 |
64 |
if( it2->first==vv ){ |
516 |
|
return true; |
517 |
|
} |
518 |
|
} |
519 |
|
} |
520 |
70 |
return false; |
521 |
|
} |
522 |
|
} |
523 |
|
|
524 |
1260198 |
bool QuantInfo::setMatch( QuantConflictFind * p, int v, TNode n, bool isGroundRep, bool isGround ) { |
525 |
1260198 |
if( getCurrentCanBeEqual( p, v, n ) ){ |
526 |
1243326 |
if( isGroundRep ){ |
527 |
|
//fail if n does not exist in the relevant domain of each of the argument positions |
528 |
1149448 |
std::map< int, std::map< TNode, std::vector< unsigned > > >::iterator it = d_var_rel_dom.find( v ); |
529 |
1149448 |
if( it!=d_var_rel_dom.end() ){ |
530 |
1052023 |
for( std::map< TNode, std::vector< unsigned > >::iterator it2 = it->second.begin(); it2 != it->second.end(); ++it2 ){ |
531 |
1286789 |
for( unsigned j=0; j<it2->second.size(); j++ ){ |
532 |
680907 |
Debug("qcf-match-debug2") << n << " in relevant domain " << it2->first << "." << it2->second[j] << "?" << std::endl; |
533 |
680907 |
if( !p->getTermDatabase()->inRelevantDomain( it2->first, it2->second[j], n ) ){ |
534 |
50334 |
Debug("qcf-match-debug") << " -> fail, since " << n << " is not in relevant domain of " << it2->first << "." << it2->second[j] << std::endl; |
535 |
50334 |
return false; |
536 |
|
} |
537 |
|
} |
538 |
|
} |
539 |
|
} |
540 |
|
} |
541 |
1192992 |
Debug("qcf-match-debug") << "-- bind : " << v << " -> " << n << ", checked " << d_curr_var_deq[v].size() << " disequalities" << std::endl; |
542 |
1192992 |
if( isGround ){ |
543 |
1184458 |
if( d_vars[v].getKind()==BOUND_VARIABLE ){ |
544 |
495958 |
d_vars_set[v] = true; |
545 |
495958 |
Debug("qcf-match-debug") << "---- now bound " << d_vars_set.size() << " / " << d_q[0].getNumChildren() << " base variables." << std::endl; |
546 |
|
} |
547 |
|
} |
548 |
1192992 |
d_match[v] = n; |
549 |
1192992 |
return true; |
550 |
|
}else{ |
551 |
16872 |
return false; |
552 |
|
} |
553 |
|
} |
554 |
|
|
555 |
827885 |
void QuantInfo::unsetMatch( QuantConflictFind * p, int v ) { |
556 |
827885 |
Debug("qcf-match-debug") << "-- unbind : " << v << std::endl; |
557 |
827885 |
if( d_vars[v].getKind()==BOUND_VARIABLE && d_vars_set.find( v )!=d_vars_set.end() ){ |
558 |
293363 |
d_vars_set.erase( v ); |
559 |
|
} |
560 |
827885 |
d_match[ v ] = TNode::null(); |
561 |
827885 |
} |
562 |
|
|
563 |
84150 |
bool QuantInfo::isMatchSpurious( QuantConflictFind * p ) { |
564 |
568278 |
for( int i=0; i<getNumVars(); i++ ){ |
565 |
|
//std::map< int, TNode >::iterator it = d_match.find( i ); |
566 |
502371 |
if( !d_match[i].isNull() ){ |
567 |
379983 |
if (!getCurrentCanBeEqual(p, i, d_match[i], p->atConflictEffort())) { |
568 |
18243 |
return true; |
569 |
|
} |
570 |
|
} |
571 |
|
} |
572 |
65907 |
return false; |
573 |
|
} |
574 |
|
|
575 |
65811 |
bool QuantInfo::isTConstraintSpurious(QuantConflictFind* p, |
576 |
|
std::vector<Node>& terms) |
577 |
|
{ |
578 |
65811 |
if( options::qcfEagerTest() ){ |
579 |
|
//check whether the instantiation evaluates as expected |
580 |
65811 |
if (p->atConflictEffort()) { |
581 |
34403 |
Trace("qcf-instance-check") << "Possible conflict instance for " << d_q << " : " << std::endl; |
582 |
34799 |
std::map< TNode, TNode > subs; |
583 |
134041 |
for( unsigned i=0; i<terms.size(); i++ ){ |
584 |
99638 |
Trace("qcf-instance-check") << " " << terms[i] << std::endl; |
585 |
99638 |
subs[d_q[0][i]] = terms[i]; |
586 |
|
} |
587 |
34403 |
TermDb* tdb = p->getTermDatabase(); |
588 |
34404 |
for( unsigned i=0; i<d_extra_var.size(); i++ ){ |
589 |
2 |
Node n = getCurrentExpValue( d_extra_var[i] ); |
590 |
1 |
Trace("qcf-instance-check") << " " << d_extra_var[i] << " -> " << n << std::endl; |
591 |
1 |
subs[d_extra_var[i]] = n; |
592 |
|
} |
593 |
34403 |
if (!tdb->isEntailed(d_q[1], subs, false, false)) |
594 |
|
{ |
595 |
34007 |
Trace("qcf-instance-check") << "...not entailed to be false." << std::endl; |
596 |
34007 |
return true; |
597 |
|
} |
598 |
|
}else{ |
599 |
|
Node inst = |
600 |
32031 |
getInferenceManager().getInstantiate()->getInstantiation(d_q, terms); |
601 |
31408 |
inst = Rewriter::rewrite(inst); |
602 |
|
Node inst_eval = p->getTermDatabase()->evaluateTerm( |
603 |
32031 |
inst, options::qcfTConstraint(), true); |
604 |
31408 |
if( Trace.isOn("qcf-instance-check") ){ |
605 |
|
Trace("qcf-instance-check") << "Possible propagating instance for " << d_q << " : " << std::endl; |
606 |
|
for( unsigned i=0; i<terms.size(); i++ ){ |
607 |
|
Trace("qcf-instance-check") << " " << terms[i] << std::endl; |
608 |
|
} |
609 |
|
Trace("qcf-instance-check") << "...evaluates to " << inst_eval << std::endl; |
610 |
|
} |
611 |
62816 |
if (inst_eval.isNull() |
612 |
31408 |
|| (inst_eval.isConst() && inst_eval.getConst<bool>())) |
613 |
|
{ |
614 |
30785 |
Trace("qcf-instance-check") << "...spurious." << std::endl; |
615 |
30785 |
return true; |
616 |
|
}else{ |
617 |
623 |
if (Configuration::isDebugBuild()) |
618 |
|
{ |
619 |
623 |
if (!p->isPropagatingInstance(inst_eval)) |
620 |
|
{ |
621 |
|
// Notice that this can happen in cases where: |
622 |
|
// (1) x = -1*y is rewritten to y = -1*x, and |
623 |
|
// (2) -1*y is a term in the master equality engine but -1*x is not. |
624 |
|
// In other words, we determined that x = -1*y is a relevant |
625 |
|
// equality to propagate since it involves two known terms, but |
626 |
|
// after rewriting, the equality y = -1*x involves an unknown term |
627 |
|
// -1*x. In this case, the equality is still relevant to propagate, |
628 |
|
// despite the above function not being precise enough to realize |
629 |
|
// it. We output a warning in debug for this. See #2993. |
630 |
|
Trace("qcf-instance-check") |
631 |
|
<< "WARNING: not propagating." << std::endl; |
632 |
|
} |
633 |
|
} |
634 |
623 |
Trace("qcf-instance-check") << "...not spurious." << std::endl; |
635 |
|
} |
636 |
|
} |
637 |
|
} |
638 |
1019 |
if( !d_tconstraints.empty() ){ |
639 |
|
//check constraints |
640 |
7 |
for( std::map< Node, bool >::iterator it = d_tconstraints.begin(); it != d_tconstraints.end(); ++it ){ |
641 |
|
//apply substitution to the tconstraint |
642 |
4 |
Node cons = p->getQuantifiersRegistry().substituteBoundVariables( |
643 |
8 |
it->first, d_q, terms); |
644 |
4 |
cons = it->second ? cons : cons.negate(); |
645 |
4 |
if (!entailmentTest(p, cons, p->atConflictEffort())) { |
646 |
|
return true; |
647 |
|
} |
648 |
|
} |
649 |
|
} |
650 |
|
// spurious if quantifiers engine is in conflict |
651 |
1019 |
return p->d_qstate.isInConflict(); |
652 |
|
} |
653 |
|
|
654 |
4 |
bool QuantInfo::entailmentTest( QuantConflictFind * p, Node lit, bool chEnt ) { |
655 |
4 |
Trace("qcf-tconstraint-debug") << "Check : " << lit << std::endl; |
656 |
8 |
Node rew = Rewriter::rewrite( lit ); |
657 |
4 |
if (rew.isConst()) |
658 |
|
{ |
659 |
2 |
Trace("qcf-tconstraint-debug") << "...constraint " << lit << " rewrites to " |
660 |
1 |
<< rew << "." << std::endl; |
661 |
1 |
return rew.getConst<bool>(); |
662 |
|
} |
663 |
|
// if checking for conflicts, we must be sure that the (negation of) |
664 |
|
// constraint is (not) entailed |
665 |
3 |
if (!chEnt) |
666 |
|
{ |
667 |
3 |
rew = Rewriter::rewrite(rew.negate()); |
668 |
|
} |
669 |
|
// check if it is entailed |
670 |
6 |
Trace("qcf-tconstraint-debug") |
671 |
3 |
<< "Check entailment of " << rew << "..." << std::endl; |
672 |
3 |
std::pair<bool, Node> et = p->getState().getValuation().entailmentCheck( |
673 |
6 |
options::TheoryOfMode::THEORY_OF_TYPE_BASED, rew); |
674 |
3 |
++(p->d_statistics.d_entailment_checks); |
675 |
6 |
Trace("qcf-tconstraint-debug") |
676 |
3 |
<< "ET result : " << et.first << " " << et.second << std::endl; |
677 |
3 |
if (!et.first) |
678 |
|
{ |
679 |
6 |
Trace("qcf-tconstraint-debug") |
680 |
3 |
<< "...cannot show entailment of " << rew << "." << std::endl; |
681 |
3 |
return !chEnt; |
682 |
|
} |
683 |
|
return chEnt; |
684 |
|
} |
685 |
|
|
686 |
65882 |
bool QuantInfo::completeMatch( QuantConflictFind * p, std::vector< int >& assigned, bool doContinue ) { |
687 |
|
//assign values for variables that were unassigned (usually not necessary, but handles corner cases) |
688 |
65882 |
bool doFail = false; |
689 |
65882 |
bool success = true; |
690 |
65882 |
if( doContinue ){ |
691 |
|
doFail = true; |
692 |
|
success = false; |
693 |
|
}else{ |
694 |
65882 |
if( isBaseMatchComplete() && options::qcfEagerTest() ){ |
695 |
65783 |
return true; |
696 |
|
} |
697 |
|
//solve for interpreted symbol matches |
698 |
|
// this breaks the invariant that all introduced constraints are over existing terms |
699 |
101 |
for( int i=(int)(d_tsym_vars.size()-1); i>=0; i-- ){ |
700 |
2 |
int index = d_tsym_vars[i]; |
701 |
4 |
TNode v = getCurrentValue( d_vars[index] ); |
702 |
2 |
int slv_v = -1; |
703 |
2 |
if( v==d_vars[index] ){ |
704 |
2 |
slv_v = index; |
705 |
|
} |
706 |
2 |
Trace("qcf-tconstraint-debug") << "Solve " << d_vars[index] << " = " << v << " " << d_vars[index].getKind() << std::endl; |
707 |
2 |
if( d_vars[index].getKind()==PLUS || d_vars[index].getKind()==MULT ){ |
708 |
2 |
Kind k = d_vars[index].getKind(); |
709 |
4 |
std::vector< TNode > children; |
710 |
6 |
for( unsigned j=0; j<d_vars[index].getNumChildren(); j++ ){ |
711 |
4 |
int vn = getVarNum( d_vars[index][j] ); |
712 |
4 |
if( vn!=-1 ){ |
713 |
6 |
TNode vv = getCurrentValue( d_vars[index][j] ); |
714 |
3 |
if( vv==d_vars[index][j] ){ |
715 |
|
//we will assign this |
716 |
2 |
if( slv_v==-1 ){ |
717 |
|
Trace("qcf-tconstraint-debug") << "...will solve for var #" << vn << std::endl; |
718 |
|
slv_v = vn; |
719 |
|
if (!p->atConflictEffort()) { |
720 |
|
break; |
721 |
|
} |
722 |
|
}else{ |
723 |
4 |
Node z = p->getZero( k ); |
724 |
2 |
if( !z.isNull() ){ |
725 |
1 |
Trace("qcf-tconstraint-debug") << "...set " << d_vars[vn] << " = " << z << std::endl; |
726 |
1 |
assigned.push_back( vn ); |
727 |
1 |
if( !setMatch( p, vn, z, false, true ) ){ |
728 |
|
success = false; |
729 |
|
break; |
730 |
|
} |
731 |
|
} |
732 |
|
} |
733 |
|
}else{ |
734 |
1 |
Trace("qcf-tconstraint-debug") << "...sum value " << vv << std::endl; |
735 |
1 |
children.push_back( vv ); |
736 |
|
} |
737 |
|
}else{ |
738 |
1 |
Trace("qcf-tconstraint-debug") << "...sum " << d_vars[index][j] << std::endl; |
739 |
1 |
children.push_back( d_vars[index][j] ); |
740 |
|
} |
741 |
|
} |
742 |
2 |
if( success ){ |
743 |
2 |
if( slv_v!=-1 ){ |
744 |
4 |
Node lhs; |
745 |
2 |
if( children.empty() ){ |
746 |
|
lhs = p->getZero( k ); |
747 |
2 |
}else if( children.size()==1 ){ |
748 |
2 |
lhs = children[0]; |
749 |
|
}else{ |
750 |
|
lhs = NodeManager::currentNM()->mkNode( k, children ); |
751 |
|
} |
752 |
4 |
Node sum; |
753 |
2 |
if( v==d_vars[index] ){ |
754 |
2 |
sum = lhs; |
755 |
|
}else{ |
756 |
|
if (p->atConflictEffort()) { |
757 |
|
Kind kn = k; |
758 |
|
if( d_vars[index].getKind()==PLUS ){ |
759 |
|
kn = MINUS; |
760 |
|
} |
761 |
|
if( kn!=k ){ |
762 |
|
sum = NodeManager::currentNM()->mkNode( kn, v, lhs ); |
763 |
|
} |
764 |
|
} |
765 |
|
} |
766 |
2 |
if( !sum.isNull() ){ |
767 |
2 |
assigned.push_back( slv_v ); |
768 |
2 |
Trace("qcf-tconstraint-debug") << "...set " << d_vars[slv_v] << " = " << sum << std::endl; |
769 |
2 |
if( !setMatch( p, slv_v, sum, false, true ) ){ |
770 |
|
success = false; |
771 |
|
} |
772 |
2 |
p->d_tempCache.push_back( sum ); |
773 |
|
} |
774 |
|
}else{ |
775 |
|
//must show that constraint is met |
776 |
|
Node sum = NodeManager::currentNM()->mkNode( k, children ); |
777 |
|
Node eq = sum.eqNode( v ); |
778 |
|
if( !entailmentTest( p, eq ) ){ |
779 |
|
success = false; |
780 |
|
} |
781 |
|
p->d_tempCache.push_back( sum ); |
782 |
|
} |
783 |
|
} |
784 |
|
} |
785 |
|
|
786 |
2 |
if( !success ){ |
787 |
|
break; |
788 |
|
} |
789 |
|
} |
790 |
99 |
if( success ){ |
791 |
|
//check what is left to assign |
792 |
99 |
d_unassigned.clear(); |
793 |
99 |
d_unassigned_tn.clear(); |
794 |
198 |
std::vector< int > unassigned[2]; |
795 |
198 |
std::vector< TypeNode > unassigned_tn[2]; |
796 |
339 |
for( int i=0; i<getNumVars(); i++ ){ |
797 |
240 |
if( d_match[i].isNull() ){ |
798 |
196 |
int rindex = d_var_mg.find( i )==d_var_mg.end() ? 1 : 0; |
799 |
196 |
unassigned[rindex].push_back( i ); |
800 |
196 |
unassigned_tn[rindex].push_back( getVar( i ).getType() ); |
801 |
196 |
assigned.push_back( i ); |
802 |
|
} |
803 |
|
} |
804 |
99 |
d_unassigned_nvar = unassigned[0].size(); |
805 |
297 |
for( unsigned i=0; i<2; i++ ){ |
806 |
198 |
d_unassigned.insert( d_unassigned.end(), unassigned[i].begin(), unassigned[i].end() ); |
807 |
198 |
d_unassigned_tn.insert( d_unassigned_tn.end(), unassigned_tn[i].begin(), unassigned_tn[i].end() ); |
808 |
|
} |
809 |
99 |
d_una_eqc_count.clear(); |
810 |
99 |
d_una_index = 0; |
811 |
|
} |
812 |
|
} |
813 |
|
|
814 |
99 |
if( !d_unassigned.empty() && ( success || doContinue ) ){ |
815 |
96 |
Trace("qcf-check") << "Assign to unassigned (" << d_unassigned.size() << ")..." << std::endl; |
816 |
81 |
do { |
817 |
177 |
if( doFail ){ |
818 |
81 |
Trace("qcf-check-unassign") << "Failure, try again..." << std::endl; |
819 |
|
} |
820 |
177 |
bool invalidMatch = false; |
821 |
1501 |
while( ( d_una_index>=0 && (int)d_una_index<(int)d_unassigned.size() ) || invalidMatch || doFail ){ |
822 |
662 |
invalidMatch = false; |
823 |
662 |
if( !doFail && d_una_index==(int)d_una_eqc_count.size() ){ |
824 |
|
//check if it has now been assigned |
825 |
193 |
if( d_una_index<d_unassigned_nvar ){ |
826 |
35 |
if( !isConstrainedVar( d_unassigned[d_una_index] ) ){ |
827 |
35 |
d_una_eqc_count.push_back( -1 ); |
828 |
|
}else{ |
829 |
|
d_var_mg[ d_unassigned[d_una_index] ]->reset( p, true, this ); |
830 |
|
d_una_eqc_count.push_back( 0 ); |
831 |
|
} |
832 |
|
}else{ |
833 |
158 |
d_una_eqc_count.push_back( 0 ); |
834 |
|
} |
835 |
|
}else{ |
836 |
469 |
bool failed = false; |
837 |
469 |
if( !doFail ){ |
838 |
388 |
if( d_una_index<d_unassigned_nvar ){ |
839 |
35 |
if( !isConstrainedVar( d_unassigned[d_una_index] ) ){ |
840 |
35 |
Trace("qcf-check-unassign") << "Succeeded, variable unconstrained at " << d_una_index << std::endl; |
841 |
35 |
d_una_index++; |
842 |
|
}else if( d_var_mg[d_unassigned[d_una_index]]->getNextMatch( p, this ) ){ |
843 |
|
Trace("qcf-check-unassign") << "Succeeded match with mg at " << d_una_index << std::endl; |
844 |
|
d_una_index++; |
845 |
|
}else{ |
846 |
|
failed = true; |
847 |
|
Trace("qcf-check-unassign") << "Failed match with mg at " << d_una_index << std::endl; |
848 |
|
} |
849 |
|
}else{ |
850 |
353 |
Assert(doFail || d_una_index == (int)d_una_eqc_count.size() - 1); |
851 |
353 |
if( d_una_eqc_count[d_una_index]<(int)p->d_eqcs[d_unassigned_tn[d_una_index]].size() ){ |
852 |
233 |
int currIndex = d_una_eqc_count[d_una_index]; |
853 |
233 |
d_una_eqc_count[d_una_index]++; |
854 |
233 |
Trace("qcf-check-unassign") << d_unassigned[d_una_index] << "->" << p->d_eqcs[d_unassigned_tn[d_una_index]][currIndex] << std::endl; |
855 |
233 |
if( setMatch( p, d_unassigned[d_una_index], p->d_eqcs[d_unassigned_tn[d_una_index]][currIndex], true, true ) ){ |
856 |
168 |
d_match_term[d_unassigned[d_una_index]] = TNode::null(); |
857 |
168 |
Trace("qcf-check-unassign") << "Succeeded match " << d_una_index << std::endl; |
858 |
168 |
d_una_index++; |
859 |
|
}else{ |
860 |
65 |
Trace("qcf-check-unassign") << "Failed match " << d_una_index << std::endl; |
861 |
65 |
invalidMatch = true; |
862 |
|
} |
863 |
|
}else{ |
864 |
120 |
failed = true; |
865 |
120 |
Trace("qcf-check-unassign") << "No more matches " << d_una_index << std::endl; |
866 |
|
} |
867 |
|
} |
868 |
|
} |
869 |
469 |
if( doFail || failed ){ |
870 |
|
do{ |
871 |
201 |
if( !doFail ){ |
872 |
120 |
d_una_eqc_count.pop_back(); |
873 |
|
}else{ |
874 |
81 |
doFail = false; |
875 |
|
} |
876 |
201 |
d_una_index--; |
877 |
201 |
}while( d_una_index>=0 && d_una_eqc_count[d_una_index]==-1 ); |
878 |
|
} |
879 |
|
} |
880 |
|
} |
881 |
177 |
success = d_una_index>=0; |
882 |
177 |
if( success ){ |
883 |
106 |
doFail = true; |
884 |
106 |
Trace("qcf-check-unassign") << " Try: " << std::endl; |
885 |
328 |
for( unsigned i=0; i<d_unassigned.size(); i++ ){ |
886 |
222 |
int ui = d_unassigned[i]; |
887 |
222 |
if( !d_match[ui].isNull() ){ |
888 |
187 |
Trace("qcf-check-unassign") << " Assigned #" << ui << " : " << d_vars[ui] << " -> " << d_match[ui] << std::endl; |
889 |
|
} |
890 |
|
} |
891 |
|
} |
892 |
177 |
}while( success && isMatchSpurious( p ) ); |
893 |
96 |
Trace("qcf-check") << "done assigning." << std::endl; |
894 |
|
} |
895 |
99 |
if( success ){ |
896 |
101 |
for( unsigned i=0; i<d_unassigned.size(); i++ ){ |
897 |
73 |
int ui = d_unassigned[i]; |
898 |
73 |
if( !d_match[ui].isNull() ){ |
899 |
38 |
Trace("qcf-check") << " Assigned #" << ui << " : " << d_vars[ui] << " -> " << d_match[ui] << std::endl; |
900 |
|
} |
901 |
|
} |
902 |
28 |
return true; |
903 |
|
}else{ |
904 |
71 |
revertMatch( p, assigned ); |
905 |
71 |
assigned.clear(); |
906 |
71 |
return false; |
907 |
|
} |
908 |
|
} |
909 |
|
|
910 |
65811 |
void QuantInfo::getMatch( std::vector< Node >& terms ){ |
911 |
251801 |
for( unsigned i=0; i<d_q[0].getNumChildren(); i++ ){ |
912 |
|
//Node cv = qi->getCurrentValue( qi->d_match[i] ); |
913 |
185990 |
int repVar = getCurrentRepVar( i ); |
914 |
371980 |
Node cv; |
915 |
|
//std::map< int, TNode >::iterator itmt = qi->d_match_term.find( repVar ); |
916 |
185990 |
if( !d_match_term[repVar].isNull() ){ |
917 |
183908 |
cv = d_match_term[repVar]; |
918 |
|
}else{ |
919 |
2082 |
cv = d_match[repVar]; |
920 |
|
} |
921 |
185990 |
Debug("qcf-check-inst") << "INST : " << i << " -> " << cv << ", from " << d_match[i] << std::endl; |
922 |
185990 |
terms.push_back( cv ); |
923 |
|
} |
924 |
65811 |
} |
925 |
|
|
926 |
65386 |
void QuantInfo::revertMatch( QuantConflictFind * p, std::vector< int >& assigned ) { |
927 |
65574 |
for( unsigned i=0; i<assigned.size(); i++ ){ |
928 |
188 |
unsetMatch( p, assigned[i] ); |
929 |
|
} |
930 |
65386 |
} |
931 |
|
|
932 |
|
void QuantInfo::debugPrintMatch( const char * c ) { |
933 |
|
for( int i=0; i<getNumVars(); i++ ){ |
934 |
|
Trace(c) << " " << d_vars[i] << " -> "; |
935 |
|
if( !d_match[i].isNull() ){ |
936 |
|
Trace(c) << d_match[i]; |
937 |
|
}else{ |
938 |
|
Trace(c) << "(unassigned) "; |
939 |
|
} |
940 |
|
if( !d_curr_var_deq[i].empty() ){ |
941 |
|
Trace(c) << ", DEQ{ "; |
942 |
|
for( std::map< TNode, int >::iterator it = d_curr_var_deq[i].begin(); it != d_curr_var_deq[i].end(); ++it ){ |
943 |
|
Trace(c) << it->first << " "; |
944 |
|
} |
945 |
|
Trace(c) << "}"; |
946 |
|
} |
947 |
|
if( !d_match_term[i].isNull() && d_match_term[i]!=d_match[i] ){ |
948 |
|
Trace(c) << ", EXP : " << d_match_term[i]; |
949 |
|
} |
950 |
|
Trace(c) << std::endl; |
951 |
|
} |
952 |
|
if( !d_tconstraints.empty() ){ |
953 |
|
Trace(c) << "ADDITIONAL CONSTRAINTS : " << std::endl; |
954 |
|
for( std::map< Node, bool >::iterator it = d_tconstraints.begin(); it != d_tconstraints.end(); ++it ){ |
955 |
|
Trace(c) << " " << it->first << " -> " << it->second << std::endl; |
956 |
|
} |
957 |
|
} |
958 |
|
} |
959 |
|
|
960 |
|
MatchGen::MatchGen() |
961 |
|
: d_matched_basis(), |
962 |
|
d_binding(), |
963 |
|
d_tgt(), |
964 |
|
d_tgt_orig(), |
965 |
|
d_wasSet(), |
966 |
|
d_n(), |
967 |
|
d_type( typ_invalid ), |
968 |
|
d_type_not() |
969 |
|
{ |
970 |
|
d_qni_size = 0; |
971 |
|
d_child_counter = -1; |
972 |
|
d_use_children = true; |
973 |
|
} |
974 |
|
|
975 |
|
|
976 |
60825 |
MatchGen::MatchGen( QuantInfo * qi, Node n, bool isVar ) |
977 |
|
: d_matched_basis(), |
978 |
|
d_binding(), |
979 |
|
d_tgt(), |
980 |
|
d_tgt_orig(), |
981 |
|
d_wasSet(), |
982 |
|
d_n(), |
983 |
|
d_type(), |
984 |
60825 |
d_type_not() |
985 |
|
{ |
986 |
|
//initialize temporary |
987 |
60825 |
d_child_counter = -1; |
988 |
60825 |
d_use_children = true; |
989 |
|
|
990 |
60825 |
Trace("qcf-qregister-debug") << "Make match gen for " << n << ", isVar = " << isVar << std::endl; |
991 |
121650 |
std::vector< Node > qni_apps; |
992 |
60825 |
d_qni_size = 0; |
993 |
60825 |
if( isVar ){ |
994 |
31226 |
Assert(qi->d_var_num.find(n) != qi->d_var_num.end()); |
995 |
|
// rare case where we have a free variable in an operator, we are invalid |
996 |
62452 |
if (n.getKind() == ITE |
997 |
63011 |
|| (options::ufHo() && n.getKind() == APPLY_UF |
998 |
39362 |
&& expr::hasFreeVar(n.getOperator()))) |
999 |
|
{ |
1000 |
559 |
d_type = typ_invalid; |
1001 |
|
}else{ |
1002 |
30667 |
d_type = isHandledUfTerm( n ) ? typ_var : typ_tsym; |
1003 |
30667 |
d_qni_var_num[0] = qi->getVarNum( n ); |
1004 |
30667 |
d_qni_size++; |
1005 |
30667 |
d_type_not = false; |
1006 |
30667 |
d_n = n; |
1007 |
|
//Node f = getMatchOperator( n ); |
1008 |
94065 |
for( unsigned j=0; j<d_n.getNumChildren(); j++ ){ |
1009 |
126796 |
Node nn = d_n[j]; |
1010 |
63398 |
Trace("qcf-qregister-debug") << " " << d_qni_size; |
1011 |
63398 |
if( qi->isVar( nn ) ){ |
1012 |
54447 |
int v = qi->d_var_num[nn]; |
1013 |
54447 |
Trace("qcf-qregister-debug") << " is var #" << v << std::endl; |
1014 |
54447 |
d_qni_var_num[d_qni_size] = v; |
1015 |
|
//qi->addFuncParent( v, f, j ); |
1016 |
|
}else{ |
1017 |
8951 |
Trace("qcf-qregister-debug") << " is gterm " << nn << std::endl; |
1018 |
8951 |
d_qni_gterm[d_qni_size] = nn; |
1019 |
|
} |
1020 |
63398 |
d_qni_size++; |
1021 |
|
} |
1022 |
|
} |
1023 |
|
}else{ |
1024 |
29599 |
if (expr::hasBoundVar(n)) |
1025 |
|
{ |
1026 |
29565 |
d_type_not = false; |
1027 |
29565 |
d_n = n; |
1028 |
29565 |
if( d_n.getKind()==NOT ){ |
1029 |
9599 |
d_n = d_n[0]; |
1030 |
9599 |
d_type_not = !d_type_not; |
1031 |
|
} |
1032 |
|
|
1033 |
29565 |
if( isHandledBoolConnective( d_n ) ){ |
1034 |
|
//non-literals |
1035 |
10269 |
d_type = typ_formula; |
1036 |
31545 |
for( unsigned i=0; i<d_n.getNumChildren(); i++ ){ |
1037 |
22962 |
if( d_n.getKind()!=FORALL || i==1 ){ |
1038 |
20966 |
d_children.push_back( MatchGen( qi, d_n[i], false ) ); |
1039 |
20966 |
if( !d_children[d_children.size()-1].isValid() ){ |
1040 |
1686 |
setInvalid(); |
1041 |
1686 |
break; |
1042 |
|
} |
1043 |
|
} |
1044 |
|
} |
1045 |
|
}else{ |
1046 |
19296 |
d_type = typ_invalid; |
1047 |
|
//literals |
1048 |
19296 |
if( isHandledUfTerm( d_n ) ){ |
1049 |
7228 |
Assert(qi->isVar(d_n)); |
1050 |
7228 |
d_type = typ_pred; |
1051 |
12068 |
}else if( d_n.getKind()==BOUND_VARIABLE ){ |
1052 |
89 |
Assert(d_n.getType().isBoolean()); |
1053 |
89 |
d_type = typ_bool_var; |
1054 |
11979 |
}else if( d_n.getKind()==EQUAL || options::qcfTConstraint() ){ |
1055 |
32019 |
for (unsigned i = 0; i < d_n.getNumChildren(); i++) |
1056 |
|
{ |
1057 |
21346 |
if (expr::hasBoundVar(d_n[i])) |
1058 |
|
{ |
1059 |
16061 |
if (!qi->isVar(d_n[i])) |
1060 |
|
{ |
1061 |
|
Trace("qcf-qregister-debug") |
1062 |
|
<< "ERROR : not var " << d_n[i] << std::endl; |
1063 |
|
} |
1064 |
16061 |
Assert(qi->isVar(d_n[i])); |
1065 |
16061 |
if (d_n.getKind() != EQUAL && qi->isVar(d_n[i])) |
1066 |
|
{ |
1067 |
110 |
d_qni_var_num[i + 1] = qi->d_var_num[d_n[i]]; |
1068 |
|
} |
1069 |
|
} |
1070 |
|
else |
1071 |
|
{ |
1072 |
5285 |
d_qni_gterm[i] = d_n[i]; |
1073 |
|
} |
1074 |
|
} |
1075 |
10673 |
d_type = d_n.getKind() == EQUAL ? typ_eq : typ_tconstraint; |
1076 |
10673 |
Trace("qcf-tconstraint") << "T-Constraint : " << d_n << std::endl; |
1077 |
|
} |
1078 |
|
} |
1079 |
|
}else{ |
1080 |
|
//we will just evaluate |
1081 |
34 |
d_n = n; |
1082 |
34 |
d_type = typ_ground; |
1083 |
|
} |
1084 |
|
} |
1085 |
60825 |
Trace("qcf-qregister-debug") << "Done make match gen " << n << ", type = "; |
1086 |
60825 |
debugPrintType( "qcf-qregister-debug", d_type, true ); |
1087 |
60825 |
Trace("qcf-qregister-debug") << std::endl; |
1088 |
|
//Assert( d_children.size()==d_children_order.size() ); |
1089 |
|
|
1090 |
60825 |
} |
1091 |
|
|
1092 |
168901 |
void MatchGen::collectBoundVar( QuantInfo * qi, Node n, std::vector< int >& cbvars, std::map< Node, bool >& visited, bool& hasNested ) { |
1093 |
168901 |
if( visited.find( n )==visited.end() ){ |
1094 |
146331 |
visited[n] = true; |
1095 |
146331 |
if( n.getKind()==FORALL ){ |
1096 |
1522 |
hasNested = true; |
1097 |
|
} |
1098 |
146331 |
int v = qi->getVarNum( n ); |
1099 |
146331 |
if( v!=-1 && std::find( cbvars.begin(), cbvars.end(), v )==cbvars.end() ){ |
1100 |
94405 |
cbvars.push_back( v ); |
1101 |
|
} |
1102 |
298466 |
for( unsigned i=0; i<n.getNumChildren(); i++ ){ |
1103 |
152135 |
collectBoundVar( qi, n[i], cbvars, visited, hasNested ); |
1104 |
|
} |
1105 |
|
} |
1106 |
168901 |
} |
1107 |
|
|
1108 |
54034 |
void MatchGen::determineVariableOrder( QuantInfo * qi, std::vector< int >& bvars ) { |
1109 |
54034 |
Trace("qcf-qregister-debug") << "Determine variable order " << d_n << ", #bvars = " << bvars.size() << std::endl; |
1110 |
54034 |
bool isComm = d_type==typ_formula && ( d_n.getKind()==OR || d_n.getKind()==AND || d_n.getKind()==EQUAL ); |
1111 |
54034 |
if( isComm ){ |
1112 |
12208 |
std::map< int, std::vector< int > > c_to_vars; |
1113 |
12208 |
std::map< int, std::vector< int > > vars_to_c; |
1114 |
12208 |
std::map< int, int > vb_count; |
1115 |
12208 |
std::map< int, int > vu_count; |
1116 |
12208 |
std::map< int, bool > has_nested; |
1117 |
12208 |
std::vector< bool > assigned; |
1118 |
6104 |
Trace("qcf-qregister-debug") << "Calculate bound variables..." << std::endl; |
1119 |
21231 |
for( unsigned i=0; i<d_children.size(); i++ ){ |
1120 |
30254 |
std::map< Node, bool > visited; |
1121 |
15127 |
has_nested[i] = false; |
1122 |
15127 |
collectBoundVar( qi, d_children[i].d_n, c_to_vars[i], visited, has_nested[i] ); |
1123 |
15127 |
assigned.push_back( false ); |
1124 |
15127 |
vb_count[i] = 0; |
1125 |
15127 |
vu_count[i] = 0; |
1126 |
91523 |
for( unsigned j=0; j<c_to_vars[i].size(); j++ ){ |
1127 |
76396 |
int v = c_to_vars[i][j]; |
1128 |
76396 |
vars_to_c[v].push_back( i ); |
1129 |
76396 |
if( std::find( bvars.begin(), bvars.end(), v )==bvars.end() ){ |
1130 |
69690 |
vu_count[i]++; |
1131 |
|
}else{ |
1132 |
6706 |
vb_count[i]++; |
1133 |
|
} |
1134 |
|
} |
1135 |
|
} |
1136 |
|
//children that bind no unbound variable, then the most number of bound, unbound variables go first |
1137 |
6104 |
Trace("qcf-qregister-vo") << "Variable order for " << d_n << " : " << std::endl; |
1138 |
9023 |
do { |
1139 |
15127 |
int min_score0 = -1; |
1140 |
15127 |
int min_score = -1; |
1141 |
15127 |
int min_score_index = -1; |
1142 |
207480 |
for( unsigned i=0; i<d_children.size(); i++ ){ |
1143 |
192353 |
if( !assigned[i] ){ |
1144 |
103740 |
Trace("qcf-qregister-debug2") << "Child " << i << " has b/ub : " << vb_count[i] << "/" << vu_count[i] << std::endl; |
1145 |
103740 |
int score0 = 0;//has_nested[i] ? 0 : 1; |
1146 |
|
int score; |
1147 |
103740 |
if( !options::qcfVoExp() ){ |
1148 |
103740 |
score = vu_count[i]; |
1149 |
|
}else{ |
1150 |
|
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] ) ); |
1151 |
|
} |
1152 |
103740 |
if( min_score==-1 || score0<min_score0 || ( score0==min_score0 && score<min_score ) ){ |
1153 |
24127 |
min_score0 = score0; |
1154 |
24127 |
min_score = score; |
1155 |
24127 |
min_score_index = i; |
1156 |
|
} |
1157 |
|
} |
1158 |
|
} |
1159 |
15127 |
Trace("qcf-qregister-vo") << " " << d_children_order.size()+1 << ": " << d_children[min_score_index].d_n << " : "; |
1160 |
15127 |
Trace("qcf-qregister-vo") << vu_count[min_score_index] << " " << vb_count[min_score_index] << " " << has_nested[min_score_index] << std::endl; |
1161 |
15127 |
Trace("qcf-qregister-debug") << "...assign child " << min_score_index << std::endl; |
1162 |
15127 |
Trace("qcf-qregister-debug") << "...score : " << min_score << std::endl; |
1163 |
15127 |
Assert(min_score_index != -1); |
1164 |
|
//add to children order |
1165 |
15127 |
d_children_order.push_back( min_score_index ); |
1166 |
15127 |
assigned[min_score_index] = true; |
1167 |
|
//determine order internal to children |
1168 |
15127 |
d_children[min_score_index].determineVariableOrder( qi, bvars ); |
1169 |
15127 |
Trace("qcf-qregister-debug") << "...bind variables" << std::endl; |
1170 |
|
//now, make it a bound variable |
1171 |
15127 |
if( vu_count[min_score_index]>0 ){ |
1172 |
86236 |
for( unsigned i=0; i<c_to_vars[min_score_index].size(); i++ ){ |
1173 |
71813 |
int v = c_to_vars[min_score_index][i]; |
1174 |
71813 |
if( std::find( bvars.begin(), bvars.end(), v )==bvars.end() ){ |
1175 |
89308 |
for( unsigned j=0; j<vars_to_c[v].size(); j++ ){ |
1176 |
56738 |
int vc = vars_to_c[v][j]; |
1177 |
56738 |
vu_count[vc]--; |
1178 |
56738 |
vb_count[vc]++; |
1179 |
|
} |
1180 |
32570 |
bvars.push_back( v ); |
1181 |
|
} |
1182 |
|
} |
1183 |
|
} |
1184 |
15127 |
Trace("qcf-qregister-debug") << "...done assign child " << min_score_index << std::endl; |
1185 |
15127 |
}while( d_children_order.size()!=d_children.size() ); |
1186 |
6104 |
Trace("qcf-qregister-debug") << "Done assign variable ordering for " << d_n << std::endl; |
1187 |
|
}else{ |
1188 |
49569 |
for( unsigned i=0; i<d_children.size(); i++ ){ |
1189 |
1639 |
d_children_order.push_back( i ); |
1190 |
1639 |
d_children[i].determineVariableOrder( qi, bvars ); |
1191 |
|
//now add to bvars |
1192 |
3278 |
std::map< Node, bool > visited; |
1193 |
3278 |
std::vector< int > cvars; |
1194 |
1639 |
bool has_nested = false; |
1195 |
1639 |
collectBoundVar( qi, d_children[i].d_n, cvars, visited, has_nested ); |
1196 |
19648 |
for( unsigned j=0; j<cvars.size(); j++ ){ |
1197 |
18009 |
if( std::find( bvars.begin(), bvars.end(), cvars[j] )==bvars.end() ){ |
1198 |
2736 |
bvars.push_back( cvars[j] ); |
1199 |
|
} |
1200 |
|
} |
1201 |
|
} |
1202 |
|
} |
1203 |
54034 |
} |
1204 |
|
|
1205 |
379799 |
bool MatchGen::reset_round(QuantConflictFind* p) |
1206 |
|
{ |
1207 |
379799 |
d_wasSet = false; |
1208 |
514425 |
for( unsigned i=0; i<d_children.size(); i++ ){ |
1209 |
134626 |
if (!d_children[i].reset_round(p)) |
1210 |
|
{ |
1211 |
|
return false; |
1212 |
|
} |
1213 |
|
} |
1214 |
379799 |
if( d_type==typ_ground ){ |
1215 |
|
// int e = p->evaluate( d_n ); |
1216 |
|
// if( e==1 ){ |
1217 |
|
// d_ground_eval[0] = p->d_true; |
1218 |
|
//}else if( e==-1 ){ |
1219 |
|
// d_ground_eval[0] = p->d_false; |
1220 |
|
//} |
1221 |
|
// modified |
1222 |
198 |
TermDb* tdb = p->getTermDatabase(); |
1223 |
198 |
QuantifiersState& qs = p->getState(); |
1224 |
594 |
for (unsigned i = 0; i < 2; i++) |
1225 |
|
{ |
1226 |
396 |
if (tdb->isEntailed(d_n, i == 0)) |
1227 |
|
{ |
1228 |
8 |
d_ground_eval[0] = i==0 ? p->d_true : p->d_false; |
1229 |
|
} |
1230 |
396 |
if (qs.isInConflict()) |
1231 |
|
{ |
1232 |
|
return false; |
1233 |
|
} |
1234 |
|
} |
1235 |
379601 |
}else if( d_type==typ_eq ){ |
1236 |
63682 |
TermDb* tdb = p->getTermDatabase(); |
1237 |
63682 |
QuantifiersState& qs = p->getState(); |
1238 |
191046 |
for (unsigned i = 0, size = d_n.getNumChildren(); i < size; i++) |
1239 |
|
{ |
1240 |
127364 |
if (!expr::hasBoundVar(d_n[i])) |
1241 |
|
{ |
1242 |
69608 |
TNode t = tdb->getEntailedTerm(d_n[i]); |
1243 |
34804 |
if (qs.isInConflict()) |
1244 |
|
{ |
1245 |
|
return false; |
1246 |
|
} |
1247 |
34804 |
if (t.isNull()) |
1248 |
|
{ |
1249 |
974 |
d_ground_eval[i] = d_n[i]; |
1250 |
|
} |
1251 |
|
else |
1252 |
|
{ |
1253 |
33830 |
d_ground_eval[i] = t; |
1254 |
|
} |
1255 |
|
} |
1256 |
|
} |
1257 |
|
} |
1258 |
379799 |
d_qni_bound_cons.clear(); |
1259 |
379799 |
d_qni_bound_cons_var.clear(); |
1260 |
379799 |
d_qni_bound.clear(); |
1261 |
379799 |
return true; |
1262 |
|
} |
1263 |
|
|
1264 |
580295 |
void MatchGen::reset( QuantConflictFind * p, bool tgt, QuantInfo * qi ) { |
1265 |
580295 |
d_tgt = d_type_not ? !tgt : tgt; |
1266 |
580295 |
Debug("qcf-match") << " Reset for : " << d_n << ", type : "; |
1267 |
580295 |
debugPrintType( "qcf-match", d_type ); |
1268 |
580295 |
Debug("qcf-match") << ", tgt = " << d_tgt << ", children = " << d_children.size() << " " << d_children_order.size() << std::endl; |
1269 |
580295 |
d_qn.clear(); |
1270 |
580295 |
d_qni.clear(); |
1271 |
580295 |
d_qni_bound.clear(); |
1272 |
580295 |
d_child_counter = -1; |
1273 |
580295 |
d_use_children = true; |
1274 |
580295 |
d_tgt_orig = d_tgt; |
1275 |
|
|
1276 |
|
//set up processing matches |
1277 |
580295 |
if( d_type==typ_invalid ){ |
1278 |
|
d_use_children = false; |
1279 |
580295 |
}else if( d_type==typ_ground ){ |
1280 |
76 |
d_use_children = false; |
1281 |
76 |
if( d_ground_eval[0]==( d_tgt ? p->d_true : p->d_false ) ){ |
1282 |
6 |
d_child_counter = 0; |
1283 |
|
} |
1284 |
580219 |
}else if( qi->isBaseMatchComplete() && options::qcfEagerTest() ){ |
1285 |
84228 |
d_use_children = false; |
1286 |
84228 |
d_child_counter = 0; |
1287 |
495991 |
}else if( d_type==typ_bool_var ){ |
1288 |
|
//get current value of the variable |
1289 |
1208 |
TNode n = qi->getCurrentValue( d_n ); |
1290 |
604 |
int vn = qi->getCurrentRepVar( qi->getVarNum( n ) ); |
1291 |
604 |
if( vn==-1 ){ |
1292 |
|
//evaluate the value, see if it is compatible |
1293 |
|
//int e = p->evaluate( n ); |
1294 |
|
//if( ( e==1 && d_tgt ) || ( e==0 && !d_tgt ) ){ |
1295 |
|
// d_child_counter = 0; |
1296 |
|
//} |
1297 |
|
//modified |
1298 |
|
if( p->getTermDatabase()->isEntailed( n, d_tgt ) ){ |
1299 |
|
d_child_counter = 0; |
1300 |
|
} |
1301 |
|
}else{ |
1302 |
|
//unassigned, set match to true/false |
1303 |
604 |
d_qni_bound[0] = vn; |
1304 |
604 |
qi->setMatch( p, vn, d_tgt ? p->d_true : p->d_false, false, true ); |
1305 |
604 |
d_child_counter = 0; |
1306 |
|
} |
1307 |
604 |
if( d_child_counter==0 ){ |
1308 |
604 |
d_qn.push_back( NULL ); |
1309 |
|
} |
1310 |
495387 |
}else if( d_type==typ_var ){ |
1311 |
306549 |
Assert(isHandledUfTerm(d_n)); |
1312 |
613098 |
TNode f = getMatchOperator( p, d_n ); |
1313 |
306549 |
Debug("qcf-match-debug") << " reset: Var will match operators of " << f << std::endl; |
1314 |
306549 |
TNodeTrie* qni = p->getTermDatabase()->getTermArgTrie(Node::null(), f); |
1315 |
306549 |
if (qni == nullptr || qni->empty()) |
1316 |
|
{ |
1317 |
|
//inform irrelevant quantifiers |
1318 |
35176 |
p->setIrrelevantFunction( f ); |
1319 |
|
} |
1320 |
|
else |
1321 |
|
{ |
1322 |
271373 |
d_qn.push_back(qni); |
1323 |
|
} |
1324 |
306549 |
d_matched_basis = false; |
1325 |
188838 |
}else if( d_type==typ_tsym || d_type==typ_tconstraint ){ |
1326 |
1065 |
for( std::map< int, int >::iterator it = d_qni_var_num.begin(); it != d_qni_var_num.end(); ++it ){ |
1327 |
636 |
int repVar = qi->getCurrentRepVar( it->second ); |
1328 |
636 |
if( qi->d_match[repVar].isNull() ){ |
1329 |
614 |
Debug("qcf-match-debug") << "Force matching on child #" << it->first << ", which is var #" << repVar << std::endl; |
1330 |
614 |
d_qni_bound[it->first] = repVar; |
1331 |
|
} |
1332 |
|
} |
1333 |
429 |
d_qn.push_back( NULL ); |
1334 |
188409 |
}else if( d_type==typ_pred || d_type==typ_eq ){ |
1335 |
|
//add initial constraint |
1336 |
269298 |
Node nn[2]; |
1337 |
|
int vn[2]; |
1338 |
134649 |
if( d_type==typ_pred ){ |
1339 |
58005 |
nn[0] = qi->getCurrentValue( d_n ); |
1340 |
58005 |
vn[0] = qi->getCurrentRepVar( qi->getVarNum( nn[0] ) ); |
1341 |
58005 |
nn[1] = d_tgt ? p->d_true : p->d_false; |
1342 |
58005 |
vn[1] = -1; |
1343 |
58005 |
d_tgt = true; |
1344 |
|
}else{ |
1345 |
229932 |
for( unsigned i=0; i<2; i++ ){ |
1346 |
306576 |
TNode nc; |
1347 |
153288 |
std::map<int, TNode>::iterator it = d_qni_gterm.find(i); |
1348 |
153288 |
if (it != d_qni_gterm.end()) |
1349 |
|
{ |
1350 |
49138 |
nc = it->second; |
1351 |
|
}else{ |
1352 |
104150 |
nc = d_n[i]; |
1353 |
|
} |
1354 |
153288 |
nn[i] = qi->getCurrentValue( nc ); |
1355 |
153288 |
vn[i] = qi->getCurrentRepVar( qi->getVarNum( nn[i] ) ); |
1356 |
|
} |
1357 |
|
} |
1358 |
|
bool success; |
1359 |
134649 |
if( vn[0]==-1 && vn[1]==-1 ){ |
1360 |
|
//Trace("qcf-explain") << " reset : " << d_n << " check ground values " << nn[0] << " " << nn[1] << " (tgt=" << d_tgt << ")" << std::endl; |
1361 |
285 |
Debug("qcf-match-debug") << " reset: check ground values " << nn[0] << " " << nn[1] << " (" << d_tgt << ")" << std::endl; |
1362 |
|
//just compare values |
1363 |
570 |
if( d_tgt ){ |
1364 |
258 |
success = p->areMatchEqual( nn[0], nn[1] ); |
1365 |
|
}else{ |
1366 |
27 |
if (p->atConflictEffort()) { |
1367 |
14 |
success = p->areDisequal( nn[0], nn[1] ); |
1368 |
|
}else{ |
1369 |
13 |
success = p->areMatchDisequal( nn[0], nn[1] ); |
1370 |
|
} |
1371 |
|
} |
1372 |
|
}else{ |
1373 |
|
//otherwise, add a constraint to a variable TODO: this may be over-eager at effort > conflict, since equality may be a propagation |
1374 |
134364 |
if( vn[1]!=-1 && vn[0]==-1 ){ |
1375 |
|
//swap |
1376 |
44838 |
Node t = nn[1]; |
1377 |
22419 |
nn[1] = nn[0]; |
1378 |
22419 |
nn[0] = t; |
1379 |
22419 |
vn[0] = vn[1]; |
1380 |
22419 |
vn[1] = -1; |
1381 |
|
} |
1382 |
134364 |
Debug("qcf-match-debug") << " reset: add constraint " << vn[0] << " -> " << nn[1] << " (vn=" << vn[1] << ")" << std::endl; |
1383 |
|
//add some constraint |
1384 |
134364 |
int addc = qi->addConstraint( p, vn[0], nn[1], vn[1], d_tgt, false ); |
1385 |
134364 |
success = addc!=-1; |
1386 |
|
//if successful and non-redundant, store that we need to cleanup this |
1387 |
134364 |
if( addc==1 ){ |
1388 |
|
//Trace("qcf-explain") << " reset: " << d_n << " add constraint " << vn[0] << " -> " << nn[1] << " (vn=" << vn[1] << ")" << ", d_tgt = " << d_tgt << std::endl; |
1389 |
402915 |
for( unsigned i=0; i<2; i++ ){ |
1390 |
268610 |
if( vn[i]!=-1 && std::find( d_qni_bound_except.begin(), d_qni_bound_except.end(), i )==d_qni_bound_except.end() ){ |
1391 |
160463 |
d_qni_bound[vn[i]] = vn[i]; |
1392 |
|
} |
1393 |
|
} |
1394 |
134305 |
d_qni_bound_cons[vn[0]] = nn[1]; |
1395 |
134305 |
d_qni_bound_cons_var[vn[0]] = vn[1]; |
1396 |
|
} |
1397 |
|
} |
1398 |
|
//if successful, we will bind values to variables |
1399 |
134649 |
if( success ){ |
1400 |
134419 |
d_qn.push_back( NULL ); |
1401 |
134649 |
} |
1402 |
|
}else{ |
1403 |
53760 |
if( d_children.empty() ){ |
1404 |
|
//add dummy |
1405 |
|
d_qn.push_back( NULL ); |
1406 |
|
}else{ |
1407 |
53760 |
if( d_tgt && d_n.getKind()==FORALL ){ |
1408 |
|
//fail |
1409 |
46835 |
} else if (d_n.getKind() == FORALL && p->atConflictEffort() && |
1410 |
1239 |
!options::qcfNestedConflict()) { |
1411 |
|
//fail |
1412 |
|
}else{ |
1413 |
|
//reset the first child to d_tgt |
1414 |
44357 |
d_child_counter = 0; |
1415 |
44357 |
getChild( d_child_counter )->reset( p, d_tgt, qi ); |
1416 |
|
} |
1417 |
|
} |
1418 |
|
} |
1419 |
580295 |
d_binding = false; |
1420 |
580295 |
d_wasSet = true; |
1421 |
580295 |
Debug("qcf-match") << " reset: Finished reset for " << d_n << ", success = " << ( !d_qn.empty() || d_child_counter!=-1 ) << std::endl; |
1422 |
580295 |
} |
1423 |
|
|
1424 |
1106380 |
bool MatchGen::getNextMatch( QuantConflictFind * p, QuantInfo * qi ) { |
1425 |
1106380 |
Debug("qcf-match") << " Get next match for : " << d_n << ", type = "; |
1426 |
1106380 |
debugPrintType( "qcf-match", d_type ); |
1427 |
1106380 |
Debug("qcf-match") << ", children = " << d_children.size() << ", binding = " << d_binding << std::endl; |
1428 |
1106380 |
if( !d_use_children ){ |
1429 |
168193 |
if( d_child_counter==0 ){ |
1430 |
84234 |
d_child_counter = -1; |
1431 |
84234 |
return true; |
1432 |
|
}else{ |
1433 |
83959 |
d_wasSet = false; |
1434 |
83959 |
return false; |
1435 |
|
} |
1436 |
938187 |
}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 ){ |
1437 |
791319 |
bool success = false; |
1438 |
791319 |
bool terminate = false; |
1439 |
460169 |
do { |
1440 |
1251488 |
bool doReset = false; |
1441 |
1251488 |
bool doFail = false; |
1442 |
1251488 |
if( !d_binding ){ |
1443 |
904204 |
if( doMatching( p, qi ) ){ |
1444 |
463972 |
Debug("qcf-match-debug") << " - Matching succeeded" << std::endl; |
1445 |
463972 |
d_binding = true; |
1446 |
463972 |
d_binding_it = d_qni_bound.begin(); |
1447 |
463972 |
doReset = true; |
1448 |
|
//for tconstraint, add constraint |
1449 |
463972 |
if( d_type==typ_tconstraint ){ |
1450 |
289 |
std::map< Node, bool >::iterator it = qi->d_tconstraints.find( d_n ); |
1451 |
289 |
if( it==qi->d_tconstraints.end() ){ |
1452 |
289 |
qi->d_tconstraints[d_n] = d_tgt; |
1453 |
|
//store that we added this constraint |
1454 |
289 |
d_qni_bound_cons[0] = d_n; |
1455 |
|
}else if( d_tgt!=it->second ){ |
1456 |
|
success = false; |
1457 |
|
terminate = true; |
1458 |
|
} |
1459 |
|
} |
1460 |
|
}else{ |
1461 |
440232 |
Debug("qcf-match-debug") << " - Matching failed" << std::endl; |
1462 |
440232 |
success = false; |
1463 |
440232 |
terminate = true; |
1464 |
|
} |
1465 |
|
}else{ |
1466 |
347284 |
doFail = true; |
1467 |
|
} |
1468 |
1251488 |
if( d_binding ){ |
1469 |
|
//also need to create match for each variable we bound |
1470 |
811256 |
success = true; |
1471 |
811256 |
Debug("qcf-match-debug") << " Produce matches for bound variables by " << d_n << ", type = "; |
1472 |
811256 |
debugPrintType( "qcf-match-debug", d_type ); |
1473 |
811256 |
Debug("qcf-match-debug") << "..." << std::endl; |
1474 |
|
|
1475 |
3485880 |
while( ( success && d_binding_it!=d_qni_bound.end() ) || doFail ){ |
1476 |
1337312 |
QuantInfo::VarMgMap::const_iterator itm; |
1477 |
1337312 |
if( !doFail ){ |
1478 |
990028 |
Debug("qcf-match-debug") << " check variable " << d_binding_it->second << std::endl; |
1479 |
990028 |
itm = qi->var_mg_find( d_binding_it->second ); |
1480 |
|
} |
1481 |
1337312 |
if( doFail || ( d_binding_it->first!=0 && itm != qi->var_mg_end() ) ){ |
1482 |
899074 |
Debug("qcf-match-debug") << " we had bound variable " << d_binding_it->second << ", reset = " << doReset << std::endl; |
1483 |
899074 |
if( doReset ){ |
1484 |
332926 |
itm->second->reset( p, true, qi ); |
1485 |
|
} |
1486 |
899074 |
if( doFail || !itm->second->getNextMatch( p, qi ) ){ |
1487 |
436438 |
do { |
1488 |
1115471 |
if( d_binding_it==d_qni_bound.begin() ){ |
1489 |
460169 |
Debug("qcf-match-debug") << " failed." << std::endl; |
1490 |
460169 |
success = false; |
1491 |
|
}else{ |
1492 |
655302 |
--d_binding_it; |
1493 |
655302 |
Debug("qcf-match-debug") << " decrement..." << std::endl; |
1494 |
|
} |
1495 |
2207211 |
}while( success && |
1496 |
1147714 |
( d_binding_it->first==0 || |
1497 |
492412 |
(!qi->containsVarMg(d_binding_it->second)))); |
1498 |
679033 |
doReset = false; |
1499 |
679033 |
doFail = false; |
1500 |
|
}else{ |
1501 |
220041 |
Debug("qcf-match-debug") << " increment..." << std::endl; |
1502 |
220041 |
++d_binding_it; |
1503 |
220041 |
doReset = true; |
1504 |
|
} |
1505 |
|
}else{ |
1506 |
438238 |
Debug("qcf-match-debug") << " skip..." << d_binding_it->second << std::endl; |
1507 |
438238 |
++d_binding_it; |
1508 |
438238 |
doReset = true; |
1509 |
|
} |
1510 |
|
} |
1511 |
811256 |
if( !success ){ |
1512 |
460169 |
d_binding = false; |
1513 |
|
}else{ |
1514 |
351087 |
terminate = true; |
1515 |
351087 |
if( d_binding_it==d_qni_bound.begin() ){ |
1516 |
1824 |
d_binding = false; |
1517 |
|
} |
1518 |
|
} |
1519 |
|
} |
1520 |
1251488 |
}while( !terminate ); |
1521 |
|
//if not successful, clean up the variables you bound |
1522 |
791319 |
if( !success ){ |
1523 |
440232 |
if( d_type==typ_eq || d_type==typ_pred ){ |
1524 |
|
//clean up the constraints you added |
1525 |
267195 |
for( std::map< int, TNode >::iterator it = d_qni_bound_cons.begin(); it != d_qni_bound_cons.end(); ++it ){ |
1526 |
133427 |
if( !it->second.isNull() ){ |
1527 |
133427 |
Debug("qcf-match") << " Clean up bound var " << it->first << (d_tgt ? "!" : "") << " = " << it->second << std::endl; |
1528 |
133427 |
std::map< int, int >::iterator itb = d_qni_bound_cons_var.find( it->first ); |
1529 |
133427 |
int vn = itb!=d_qni_bound_cons_var.end() ? itb->second : -1; |
1530 |
|
//Trace("qcf-explain") << " cleanup: " << d_n << " remove constraint " << it->first << " -> " << it->second << " (vn=" << vn << ")" << ", d_tgt = " << d_tgt << std::endl; |
1531 |
133427 |
qi->addConstraint( p, it->first, it->second, vn, d_tgt, true ); |
1532 |
|
} |
1533 |
|
} |
1534 |
133768 |
d_qni_bound_cons.clear(); |
1535 |
133768 |
d_qni_bound_cons_var.clear(); |
1536 |
133768 |
d_qni_bound.clear(); |
1537 |
|
}else{ |
1538 |
|
//clean up the matches you set |
1539 |
532339 |
for( std::map< int, int >::iterator it = d_qni_bound.begin(); it != d_qni_bound.end(); ++it ){ |
1540 |
225875 |
Debug("qcf-match") << " Clean up bound var " << it->second << std::endl; |
1541 |
225875 |
Assert(it->second < qi->getNumVars()); |
1542 |
225875 |
qi->unsetMatch( p, it->second ); |
1543 |
225875 |
qi->d_match_term[ it->second ] = TNode::null(); |
1544 |
|
} |
1545 |
306464 |
d_qni_bound.clear(); |
1546 |
|
} |
1547 |
440232 |
if( d_type==typ_tconstraint ){ |
1548 |
|
//remove constraint if applicable |
1549 |
287 |
if( d_qni_bound_cons.find( 0 )!=d_qni_bound_cons.end() ){ |
1550 |
287 |
qi->d_tconstraints.erase( d_n ); |
1551 |
287 |
d_qni_bound_cons.clear(); |
1552 |
|
} |
1553 |
|
} |
1554 |
|
} |
1555 |
791319 |
Debug("qcf-match") << " ...finished matching for " << d_n << ", success = " << success << std::endl; |
1556 |
791319 |
d_wasSet = success; |
1557 |
791319 |
return success; |
1558 |
|
} |
1559 |
146868 |
else if (d_type == typ_formula) |
1560 |
|
{ |
1561 |
146868 |
bool success = false; |
1562 |
146868 |
if( d_child_counter<0 ){ |
1563 |
9403 |
if( d_child_counter<-1 ){ |
1564 |
|
success = true; |
1565 |
|
d_child_counter = -1; |
1566 |
|
} |
1567 |
|
}else{ |
1568 |
890231 |
while( !success && d_child_counter>=0 ){ |
1569 |
|
//transition system based on d_child_counter |
1570 |
376383 |
if( d_n.getKind()==OR || d_n.getKind()==AND ){ |
1571 |
271749 |
if( (d_n.getKind()==AND)==d_tgt ){ |
1572 |
|
//all children must match simultaneously |
1573 |
252811 |
if( getChild( d_child_counter )->getNextMatch( p, qi ) ){ |
1574 |
143232 |
if( d_child_counter<(int)(getNumChildren()-1) ){ |
1575 |
87079 |
d_child_counter++; |
1576 |
87079 |
Debug("qcf-match-debug") << " Reset child " << d_child_counter << " of " << d_n << std::endl; |
1577 |
87079 |
getChild( d_child_counter )->reset( p, d_tgt, qi ); |
1578 |
|
}else{ |
1579 |
56153 |
success = true; |
1580 |
|
} |
1581 |
|
}else{ |
1582 |
|
//if( std::find( d_independent.begin(), d_independent.end(), d_child_counter )!=d_independent.end() ){ |
1583 |
|
// d_child_counter--; |
1584 |
|
//}else{ |
1585 |
109579 |
d_child_counter--; |
1586 |
|
//} |
1587 |
|
} |
1588 |
|
}else{ |
1589 |
|
//one child must match |
1590 |
18938 |
if( !getChild( d_child_counter )->getNextMatch( p, qi ) ){ |
1591 |
8507 |
if( d_child_counter<(int)(getNumChildren()-1) ){ |
1592 |
4782 |
d_child_counter++; |
1593 |
4782 |
Debug("qcf-match-debug") << " Reset child " << d_child_counter << " of " << d_n << ", one match" << std::endl; |
1594 |
4782 |
getChild( d_child_counter )->reset( p, d_tgt, qi ); |
1595 |
|
}else{ |
1596 |
3725 |
d_child_counter = -1; |
1597 |
|
} |
1598 |
|
}else{ |
1599 |
10431 |
success = true; |
1600 |
|
} |
1601 |
|
} |
1602 |
104634 |
}else if( d_n.getKind()==EQUAL ){ |
1603 |
|
//construct match based on both children |
1604 |
95471 |
if( d_child_counter%2==0 ){ |
1605 |
71294 |
if( getChild( 0 )->getNextMatch( p, qi ) ){ |
1606 |
40119 |
d_child_counter++; |
1607 |
40119 |
getChild( 1 )->reset( p, d_child_counter==1, qi ); |
1608 |
|
}else{ |
1609 |
31175 |
if( d_child_counter==0 ){ |
1610 |
15608 |
d_child_counter = 2; |
1611 |
15608 |
getChild( 0 )->reset( p, !d_tgt, qi ); |
1612 |
|
}else{ |
1613 |
15567 |
d_child_counter = -1; |
1614 |
|
} |
1615 |
|
} |
1616 |
|
} |
1617 |
95471 |
if( d_child_counter>=0 && d_child_counter%2==1 ){ |
1618 |
64296 |
if( getChild( 1 )->getNextMatch( p, qi ) ){ |
1619 |
24287 |
success = true; |
1620 |
|
}else{ |
1621 |
40009 |
d_child_counter--; |
1622 |
|
} |
1623 |
|
} |
1624 |
9163 |
}else if( d_n.getKind()==ITE ){ |
1625 |
7980 |
if( d_child_counter%2==0 ){ |
1626 |
5356 |
int index1 = d_child_counter==4 ? 1 : 0; |
1627 |
5356 |
if( getChild( index1 )->getNextMatch( p, qi ) ){ |
1628 |
4033 |
d_child_counter++; |
1629 |
4033 |
getChild( d_child_counter==5 ? 2 : (d_tgt==(d_child_counter==1) ? 1 : 2) )->reset( p, d_tgt, qi ); |
1630 |
|
}else{ |
1631 |
1323 |
if (d_child_counter == 4) |
1632 |
|
{ |
1633 |
439 |
d_child_counter = -1; |
1634 |
|
}else{ |
1635 |
884 |
d_child_counter +=2; |
1636 |
884 |
getChild( d_child_counter==2 ? 0 : 1 )->reset( p, d_child_counter==2 ? !d_tgt : d_tgt, qi ); |
1637 |
|
} |
1638 |
|
} |
1639 |
|
} |
1640 |
7980 |
if( d_child_counter>=0 && d_child_counter%2==1 ){ |
1641 |
6657 |
int index2 = d_child_counter==5 ? 2 : (d_tgt==(d_child_counter==1) ? 1 : 2); |
1642 |
6657 |
if( getChild( index2 )->getNextMatch( p, qi ) ){ |
1643 |
2654 |
success = true; |
1644 |
|
}else{ |
1645 |
4003 |
d_child_counter--; |
1646 |
|
} |
1647 |
|
} |
1648 |
1183 |
}else if( d_n.getKind()==FORALL ){ |
1649 |
1183 |
if( getChild( d_child_counter )->getNextMatch( p, qi ) ){ |
1650 |
120 |
success = true; |
1651 |
|
}else{ |
1652 |
1063 |
d_child_counter = -1; |
1653 |
|
} |
1654 |
|
} |
1655 |
|
} |
1656 |
137465 |
d_wasSet = success; |
1657 |
137465 |
Debug("qcf-match") << " ...finished construct match for " << d_n << ", success = " << success << std::endl; |
1658 |
137465 |
return success; |
1659 |
|
} |
1660 |
|
} |
1661 |
9403 |
Debug("qcf-match") << " ...already finished for " << d_n << std::endl; |
1662 |
9403 |
return false; |
1663 |
|
} |
1664 |
|
|
1665 |
904204 |
bool MatchGen::doMatching( QuantConflictFind * p, QuantInfo * qi ) { |
1666 |
904204 |
if( !d_qn.empty() ){ |
1667 |
734229 |
if( d_qn[0]==NULL ){ |
1668 |
135452 |
d_qn.clear(); |
1669 |
135452 |
return true; |
1670 |
|
}else{ |
1671 |
598777 |
Assert(d_type == typ_var); |
1672 |
598777 |
Assert(d_qni_size > 0); |
1673 |
|
bool invalidMatch; |
1674 |
2474560 |
do { |
1675 |
3073337 |
invalidMatch = false; |
1676 |
3073337 |
Debug("qcf-match-debug") << " Do matching " << d_n << " " << d_qn.size() << " " << d_qni.size() << std::endl; |
1677 |
3073337 |
if( d_qn.size()==d_qni.size()+1 ) { |
1678 |
1476583 |
int index = (int)d_qni.size(); |
1679 |
|
//initialize |
1680 |
2953166 |
TNode val; |
1681 |
1476583 |
std::map< int, int >::iterator itv = d_qni_var_num.find( index ); |
1682 |
1476583 |
if( itv!=d_qni_var_num.end() ){ |
1683 |
|
//get the representative variable this variable is equal to |
1684 |
1375276 |
int repVar = qi->getCurrentRepVar( itv->second ); |
1685 |
1375276 |
Debug("qcf-match-debug") << " Match " << index << " is a variable " << itv->second << ", which is repVar " << repVar << std::endl; |
1686 |
|
//get the value the rep variable |
1687 |
|
//std::map< int, TNode >::iterator itm = qi->d_match.find( repVar ); |
1688 |
1375276 |
if( !qi->d_match[repVar].isNull() ){ |
1689 |
864214 |
val = qi->d_match[repVar]; |
1690 |
864214 |
Debug("qcf-match-debug") << " Variable is already bound to " << val << std::endl; |
1691 |
|
}else{ |
1692 |
|
//binding a variable |
1693 |
511062 |
d_qni_bound[index] = repVar; |
1694 |
|
std::map<TNode, TNodeTrie>::iterator it = |
1695 |
511062 |
d_qn[index]->d_data.begin(); |
1696 |
511062 |
if( it != d_qn[index]->d_data.end() ) { |
1697 |
511062 |
d_qni.push_back( it ); |
1698 |
|
//set the match |
1699 |
511062 |
if( it->first.getType().isComparableTo( qi->d_var_types[repVar] ) && qi->setMatch( p, d_qni_bound[index], it->first, true, true ) ){ |
1700 |
470886 |
Debug("qcf-match-debug") << " Binding variable" << std::endl; |
1701 |
470886 |
if( d_qn.size()<d_qni_size ){ |
1702 |
234144 |
d_qn.push_back( &it->second ); |
1703 |
|
} |
1704 |
|
}else{ |
1705 |
40176 |
Debug("qcf-match") << " Binding variable, currently fail." << std::endl; |
1706 |
40176 |
invalidMatch = true; |
1707 |
|
} |
1708 |
|
}else{ |
1709 |
|
Debug("qcf-match-debug") << " Binding variable, fail, no more variables to bind" << std::endl; |
1710 |
|
d_qn.pop_back(); |
1711 |
|
} |
1712 |
|
} |
1713 |
|
}else{ |
1714 |
101307 |
Debug("qcf-match-debug") << " Match " << index << " is ground term" << std::endl; |
1715 |
101307 |
Assert(d_qni_gterm.find(index) != d_qni_gterm.end()); |
1716 |
101307 |
val = d_qni_gterm[index]; |
1717 |
101307 |
Assert(!val.isNull()); |
1718 |
|
} |
1719 |
1476583 |
if( !val.isNull() ){ |
1720 |
1931042 |
Node valr = p->getRepresentative(val); |
1721 |
|
//constrained by val |
1722 |
|
std::map<TNode, TNodeTrie>::iterator it = |
1723 |
965521 |
d_qn[index]->d_data.find(valr); |
1724 |
965521 |
if( it!=d_qn[index]->d_data.end() ){ |
1725 |
434784 |
Debug("qcf-match-debug") << " Match" << std::endl; |
1726 |
434784 |
d_qni.push_back( it ); |
1727 |
434784 |
if( d_qn.size()<d_qni_size ){ |
1728 |
395873 |
d_qn.push_back( &it->second ); |
1729 |
|
} |
1730 |
|
}else{ |
1731 |
530737 |
Debug("qcf-match-debug") << " Failed to match" << std::endl; |
1732 |
530737 |
d_qn.pop_back(); |
1733 |
|
} |
1734 |
|
} |
1735 |
|
}else{ |
1736 |
1596754 |
Assert(d_qn.size() == d_qni.size()); |
1737 |
1596754 |
int index = d_qni.size()-1; |
1738 |
|
//increment if binding this variable |
1739 |
1596754 |
bool success = false; |
1740 |
1596754 |
std::map< int, int >::iterator itb = d_qni_bound.find( index ); |
1741 |
1596754 |
if( itb!=d_qni_bound.end() ){ |
1742 |
1164229 |
d_qni[index]++; |
1743 |
1164229 |
if( d_qni[index]!=d_qn[index]->d_data.end() ){ |
1744 |
655018 |
success = true; |
1745 |
655018 |
if( qi->setMatch( p, itb->second, d_qni[index]->first, true, true ) ){ |
1746 |
628060 |
Debug("qcf-match-debug") << " Bind next variable" << std::endl; |
1747 |
628060 |
if( d_qn.size()<d_qni_size ){ |
1748 |
575193 |
d_qn.push_back( &d_qni[index]->second ); |
1749 |
|
} |
1750 |
|
}else{ |
1751 |
26958 |
Debug("qcf-match-debug") << " Bind next variable, currently fail" << std::endl; |
1752 |
26958 |
invalidMatch = true; |
1753 |
|
} |
1754 |
|
}else{ |
1755 |
509211 |
qi->unsetMatch( p, itb->second ); |
1756 |
509211 |
qi->d_match_term[ itb->second ] = TNode::null(); |
1757 |
509211 |
Debug("qcf-match-debug") << " Bind next variable, no more variables to bind" << std::endl; |
1758 |
|
} |
1759 |
|
}else{ |
1760 |
|
//TODO : if it equal to something else, also try that |
1761 |
|
} |
1762 |
|
//if not incrementing, move to next |
1763 |
1596754 |
if( !success ){ |
1764 |
941736 |
d_qn.pop_back(); |
1765 |
941736 |
d_qni.pop_back(); |
1766 |
|
} |
1767 |
|
} |
1768 |
3073337 |
}while( ( !d_qn.empty() && d_qni.size()!=d_qni_size ) || invalidMatch ); |
1769 |
598777 |
if( d_qni.size()==d_qni_size ){ |
1770 |
|
//Assert( !d_qni[d_qni.size()-1]->second.d_data.empty() ); |
1771 |
|
//Debug("qcf-match-debug") << " We matched " << d_qni[d_qni.size()-1]->second.d_children.begin()->first << std::endl; |
1772 |
328520 |
Assert(!d_qni[d_qni.size() - 1]->second.d_data.empty()); |
1773 |
657040 |
TNode t = d_qni[d_qni.size()-1]->second.d_data.begin()->first; |
1774 |
328520 |
Debug("qcf-match-debug") << " " << d_n << " matched " << t << std::endl; |
1775 |
328520 |
qi->d_match_term[d_qni_var_num[0]] = t; |
1776 |
|
//set the match terms |
1777 |
970308 |
for( std::map< int, int >::iterator it = d_qni_bound.begin(); it != d_qni_bound.end(); ++it ){ |
1778 |
641788 |
Debug("qcf-match-debug") << " position " << it->first << " bounded " << it->second << " / " << qi->d_q[0].getNumChildren() << std::endl; |
1779 |
|
//if( it->second<(int)qi->d_q[0].getNumChildren() ){ //if it is an actual variable, we are interested in knowing the actual term |
1780 |
641788 |
if( it->first>0 ){ |
1781 |
496662 |
Assert(!qi->d_match[it->second].isNull()); |
1782 |
496662 |
Assert(p->areEqual(t[it->first - 1], qi->d_match[it->second])); |
1783 |
496662 |
qi->d_match_term[it->second] = t[it->first-1]; |
1784 |
|
} |
1785 |
|
//} |
1786 |
|
} |
1787 |
|
} |
1788 |
|
} |
1789 |
|
} |
1790 |
768752 |
return !d_qn.empty(); |
1791 |
|
} |
1792 |
|
|
1793 |
2558756 |
void MatchGen::debugPrintType( const char * c, short typ, bool isTrace ) { |
1794 |
2558756 |
if( isTrace ){ |
1795 |
60825 |
switch( typ ){ |
1796 |
3551 |
case typ_invalid: Trace(c) << "invalid";break; |
1797 |
34 |
case typ_ground: Trace(c) << "ground";break; |
1798 |
10563 |
case typ_eq: Trace(c) << "eq";break; |
1799 |
7228 |
case typ_pred: Trace(c) << "pred";break; |
1800 |
8583 |
case typ_formula: Trace(c) << "formula";break; |
1801 |
30543 |
case typ_var: Trace(c) << "var";break; |
1802 |
89 |
case typ_bool_var: Trace(c) << "bool_var";break; |
1803 |
|
} |
1804 |
|
}else{ |
1805 |
2497931 |
switch( typ ){ |
1806 |
|
case typ_invalid: Debug(c) << "invalid";break; |
1807 |
158 |
case typ_ground: Debug(c) << "ground";break; |
1808 |
532915 |
case typ_eq: Debug(c) << "eq";break; |
1809 |
340496 |
case typ_pred: Debug(c) << "pred";break; |
1810 |
215547 |
case typ_formula: Debug(c) << "formula";break; |
1811 |
1403849 |
case typ_var: Debug(c) << "var";break; |
1812 |
3020 |
case typ_bool_var: Debug(c) << "bool_var";break; |
1813 |
|
} |
1814 |
|
} |
1815 |
2558756 |
} |
1816 |
|
|
1817 |
2412 |
void MatchGen::setInvalid() { |
1818 |
2412 |
d_type = typ_invalid; |
1819 |
2412 |
d_children.clear(); |
1820 |
2412 |
} |
1821 |
|
|
1822 |
100761 |
bool MatchGen::isHandledBoolConnective( TNode n ) { |
1823 |
100761 |
return TermUtil::isBoolConnectiveTerm( n ) && n.getKind()!=SEP_STAR; |
1824 |
|
} |
1825 |
|
|
1826 |
706179 |
bool MatchGen::isHandledUfTerm( TNode n ) { |
1827 |
|
//return n.getKind()==APPLY_UF || n.getKind()==STORE || n.getKind()==SELECT || |
1828 |
|
// n.getKind()==APPLY_CONSTRUCTOR || n.getKind()==APPLY_SELECTOR_TOTAL || n.getKind()==APPLY_TESTER; |
1829 |
|
//TODO : treat APPLY_TESTER as a T-constraint instead of matching (currently leads to overabundance of instantiations) |
1830 |
|
//return inst::Trigger::isAtomicTriggerKind( n.getKind() ) && ( !options::qcfTConstraint() || n.getKind()!=APPLY_TESTER ); |
1831 |
706179 |
return inst::TriggerTermInfo::isAtomicTriggerKind(n.getKind()); |
1832 |
|
} |
1833 |
|
|
1834 |
306549 |
Node MatchGen::getMatchOperator( QuantConflictFind * p, Node n ) { |
1835 |
306549 |
if( isHandledUfTerm( n ) ){ |
1836 |
306549 |
return p->getTermDatabase()->getMatchOperator( n ); |
1837 |
|
}else{ |
1838 |
|
return Node::null(); |
1839 |
|
} |
1840 |
|
} |
1841 |
|
|
1842 |
|
bool MatchGen::isHandled( TNode n ) { |
1843 |
|
if (n.getKind() != BOUND_VARIABLE && expr::hasBoundVar(n)) |
1844 |
|
{ |
1845 |
|
if( !isHandledBoolConnective( n ) && !isHandledUfTerm( n ) && n.getKind()!=EQUAL && n.getKind()!=ITE ){ |
1846 |
|
return false; |
1847 |
|
} |
1848 |
|
for( unsigned i=0; i<n.getNumChildren(); i++ ){ |
1849 |
|
if( !isHandled( n[i] ) ){ |
1850 |
|
return false; |
1851 |
|
} |
1852 |
|
} |
1853 |
|
} |
1854 |
|
return true; |
1855 |
|
} |
1856 |
|
|
1857 |
3050 |
QuantConflictFind::QuantConflictFind(Env& env, |
1858 |
|
QuantifiersState& qs, |
1859 |
|
QuantifiersInferenceManager& qim, |
1860 |
|
QuantifiersRegistry& qr, |
1861 |
3050 |
TermRegistry& tr) |
1862 |
|
: QuantifiersModule(env, qs, qim, qr, tr), |
1863 |
|
d_conflict(context(), false), |
1864 |
|
d_true(NodeManager::currentNM()->mkConst<bool>(true)), |
1865 |
|
d_false(NodeManager::currentNM()->mkConst<bool>(false)), |
1866 |
3050 |
d_effort(EFFORT_INVALID) |
1867 |
|
{ |
1868 |
3050 |
} |
1869 |
|
|
1870 |
|
//-------------------------------------------------- registration |
1871 |
|
|
1872 |
9538 |
void QuantConflictFind::registerQuantifier( Node q ) { |
1873 |
9538 |
if (d_qreg.hasOwnership(q, this)) |
1874 |
|
{ |
1875 |
8633 |
d_quants.push_back( q ); |
1876 |
8633 |
d_quant_id[q] = d_quants.size(); |
1877 |
8633 |
if( Trace.isOn("qcf-qregister") ){ |
1878 |
|
Trace("qcf-qregister") << "Register "; |
1879 |
|
debugPrintQuant( "qcf-qregister", q ); |
1880 |
|
Trace("qcf-qregister") << " : " << q << std::endl; |
1881 |
|
} |
1882 |
|
//make QcfNode structure |
1883 |
8633 |
Trace("qcf-qregister") << "- Get relevant equality/disequality pairs, calculate flattening..." << std::endl; |
1884 |
8633 |
d_qinfo[q].initialize( this, q, q[1] ); |
1885 |
|
|
1886 |
|
//debug print |
1887 |
8633 |
if( Trace.isOn("qcf-qregister") ){ |
1888 |
|
Trace("qcf-qregister") << "- Flattened structure is :" << std::endl; |
1889 |
|
Trace("qcf-qregister") << " "; |
1890 |
|
debugPrintQuantBody( "qcf-qregister", q, q[1] ); |
1891 |
|
Trace("qcf-qregister") << std::endl; |
1892 |
|
if( d_qinfo[q].d_vars.size()>q[0].getNumChildren() ){ |
1893 |
|
Trace("qcf-qregister") << " with additional constraints : " << std::endl; |
1894 |
|
for( unsigned j=q[0].getNumChildren(); j<d_qinfo[q].d_vars.size(); j++ ){ |
1895 |
|
Trace("qcf-qregister") << " ?x" << j << " = "; |
1896 |
|
debugPrintQuantBody( "qcf-qregister", q, d_qinfo[q].d_vars[j], false ); |
1897 |
|
Trace("qcf-qregister") << std::endl; |
1898 |
|
} |
1899 |
|
} |
1900 |
|
Trace("qcf-qregister") << "Done registering quantifier." << std::endl; |
1901 |
|
} |
1902 |
|
} |
1903 |
9538 |
} |
1904 |
|
|
1905 |
258 |
bool QuantConflictFind::areMatchEqual( TNode n1, TNode n2 ) { |
1906 |
|
//if( d_effort==QuantConflictFind::effort_mc ){ |
1907 |
|
// return n1==n2 || !areDisequal( n1, n2 ); |
1908 |
|
//}else{ |
1909 |
258 |
return n1==n2; |
1910 |
|
//} |
1911 |
|
} |
1912 |
|
|
1913 |
13 |
bool QuantConflictFind::areMatchDisequal( TNode n1, TNode n2 ) { |
1914 |
|
// if( d_effort==QuantConflictFind::Effort::Conflict ){ |
1915 |
|
// return areDisequal( n1, n2 ); |
1916 |
|
//}else{ |
1917 |
13 |
return n1!=n2; |
1918 |
|
//} |
1919 |
|
} |
1920 |
|
|
1921 |
|
//-------------------------------------------------- check function |
1922 |
|
|
1923 |
21282 |
bool QuantConflictFind::needsCheck( Theory::Effort level ) { |
1924 |
21282 |
bool performCheck = false; |
1925 |
21282 |
if( options::quantConflictFind() && !d_conflict ){ |
1926 |
21278 |
if( level==Theory::EFFORT_LAST_CALL ){ |
1927 |
2992 |
performCheck = options::qcfWhenMode() == options::QcfWhenMode::LAST_CALL; |
1928 |
18286 |
}else if( level==Theory::EFFORT_FULL ){ |
1929 |
10717 |
performCheck = options::qcfWhenMode() == options::QcfWhenMode::DEFAULT; |
1930 |
7569 |
}else if( level==Theory::EFFORT_STANDARD ){ |
1931 |
7569 |
performCheck = options::qcfWhenMode() == options::QcfWhenMode::STD; |
1932 |
|
} |
1933 |
|
} |
1934 |
21282 |
return performCheck; |
1935 |
|
} |
1936 |
|
|
1937 |
13711 |
void QuantConflictFind::reset_round( Theory::Effort level ) { |
1938 |
13711 |
Trace("qcf-check") << "QuantConflictFind::reset_round" << std::endl; |
1939 |
13711 |
Trace("qcf-check") << "Compute relevant equivalence classes..." << std::endl; |
1940 |
13711 |
d_eqcs.clear(); |
1941 |
|
|
1942 |
13711 |
eq::EqClassesIterator eqcs_i = eq::EqClassesIterator(getEqualityEngine()); |
1943 |
13711 |
TermDb* tdb = getTermDatabase(); |
1944 |
1325657 |
while (!eqcs_i.isFinished()) |
1945 |
|
{ |
1946 |
1311946 |
Node r = (*eqcs_i); |
1947 |
655973 |
if (tdb->hasTermCurrent(r)) |
1948 |
|
{ |
1949 |
1311946 |
TypeNode rtn = r.getType(); |
1950 |
655973 |
if (!options::cegqi() || !TermUtil::hasInstConstAttr(r)) |
1951 |
|
{ |
1952 |
638589 |
d_eqcs[rtn].push_back(r); |
1953 |
|
} |
1954 |
|
} |
1955 |
655973 |
++eqcs_i; |
1956 |
|
} |
1957 |
13711 |
} |
1958 |
|
|
1959 |
35176 |
void QuantConflictFind::setIrrelevantFunction( TNode f ) { |
1960 |
35176 |
if( d_irr_func.find( f )==d_irr_func.end() ){ |
1961 |
6881 |
d_irr_func[f] = true; |
1962 |
6881 |
std::map< TNode, std::vector< Node > >::iterator it = d_func_rel_dom.find( f ); |
1963 |
6881 |
if( it != d_func_rel_dom.end()){ |
1964 |
28005 |
for( unsigned j=0; j<it->second.size(); j++ ){ |
1965 |
22677 |
d_irr_quant[it->second[j]] = true; |
1966 |
|
} |
1967 |
|
} |
1968 |
|
} |
1969 |
35176 |
} |
1970 |
|
|
1971 |
|
namespace { |
1972 |
|
|
1973 |
|
// Returns the beginning of a range of efforts. The range can be iterated |
1974 |
|
// through as unsigned using operator++. |
1975 |
10717 |
inline QuantConflictFind::Effort QcfEffortStart() { |
1976 |
10717 |
return QuantConflictFind::EFFORT_CONFLICT; |
1977 |
|
} |
1978 |
|
|
1979 |
|
// Returns the beginning of a range of efforts. The value returned is included |
1980 |
|
// in the range. |
1981 |
10717 |
inline QuantConflictFind::Effort QcfEffortEnd() { |
1982 |
10717 |
return options::qcfMode() == options::QcfMode::PROP_EQ |
1983 |
10717 |
? QuantConflictFind::EFFORT_PROP_EQ |
1984 |
10717 |
: QuantConflictFind::EFFORT_CONFLICT; |
1985 |
|
} |
1986 |
|
|
1987 |
|
} // namespace |
1988 |
|
|
1989 |
|
/** check */ |
1990 |
40873 |
void QuantConflictFind::check(Theory::Effort level, QEffort quant_e) |
1991 |
|
{ |
1992 |
51590 |
CodeTimer codeTimer(d_qstate.getStats().d_qcf_time); |
1993 |
40873 |
if (quant_e != QEFFORT_CONFLICT) |
1994 |
|
{ |
1995 |
30156 |
return; |
1996 |
|
} |
1997 |
10717 |
Trace("qcf-check") << "QCF : check : " << level << std::endl; |
1998 |
10717 |
if (d_conflict) |
1999 |
|
{ |
2000 |
|
Trace("qcf-check2") << "QCF : finished check : already in conflict." |
2001 |
|
<< std::endl; |
2002 |
|
if (level >= Theory::EFFORT_FULL) |
2003 |
|
{ |
2004 |
|
Trace("qcf-warn") << "ALREADY IN CONFLICT? " << level << std::endl; |
2005 |
|
} |
2006 |
|
return; |
2007 |
|
} |
2008 |
10717 |
unsigned addedLemmas = 0; |
2009 |
10717 |
++(d_statistics.d_inst_rounds); |
2010 |
10717 |
double clSet = 0; |
2011 |
10717 |
int prevEt = 0; |
2012 |
10717 |
if (Trace.isOn("qcf-engine")) |
2013 |
|
{ |
2014 |
|
prevEt = d_statistics.d_entailment_checks.get(); |
2015 |
|
clSet = double(clock()) / double(CLOCKS_PER_SEC); |
2016 |
|
Trace("qcf-engine") << "---Conflict Find Engine Round, effort = " << level |
2017 |
|
<< "---" << std::endl; |
2018 |
|
} |
2019 |
|
|
2020 |
|
// reset the round-specific information |
2021 |
10717 |
d_irr_func.clear(); |
2022 |
10717 |
d_irr_quant.clear(); |
2023 |
|
|
2024 |
10717 |
if (Trace.isOn("qcf-debug")) |
2025 |
|
{ |
2026 |
|
Trace("qcf-debug") << std::endl; |
2027 |
|
debugPrint("qcf-debug"); |
2028 |
|
Trace("qcf-debug") << std::endl; |
2029 |
|
} |
2030 |
10717 |
bool isConflict = false; |
2031 |
10717 |
FirstOrderModel* fm = d_treg.getModel(); |
2032 |
10717 |
unsigned nquant = fm->getNumAssertedQuantifiers(); |
2033 |
|
// for each effort level (find conflict, find propagating) |
2034 |
31262 |
for (unsigned e = QcfEffortStart(), end = QcfEffortEnd(); e <= end; ++e) |
2035 |
|
{ |
2036 |
|
// set the effort (data member for convienence of access) |
2037 |
21083 |
d_effort = static_cast<Effort>(e); |
2038 |
42166 |
Trace("qcf-check") << "Checking quantified formulas at effort " << e |
2039 |
21083 |
<< "..." << std::endl; |
2040 |
|
// for each quantified formula |
2041 |
175307 |
for (unsigned i = 0; i < nquant; i++) |
2042 |
|
{ |
2043 |
308799 |
Node q = fm->getAssertedQuantifier(i, true); |
2044 |
463725 |
if (d_qreg.hasOwnership(q, this) |
2045 |
297938 |
&& d_irr_quant.find(q) == d_irr_quant.end() |
2046 |
580716 |
&& fm->isQuantifierActive(q)) |
2047 |
|
{ |
2048 |
|
// check this quantified formula |
2049 |
116939 |
checkQuantifiedFormula(q, isConflict, addedLemmas); |
2050 |
116939 |
if (d_conflict || d_qstate.isInConflict()) |
2051 |
|
{ |
2052 |
351 |
break; |
2053 |
|
} |
2054 |
|
} |
2055 |
|
} |
2056 |
|
// We are done if we added a lemma, or discovered a conflict in another |
2057 |
|
// way. An example of the latter case is when two disequal congruent terms |
2058 |
|
// are discovered during term indexing. |
2059 |
21083 |
if (addedLemmas > 0 || d_qstate.isInConflict()) |
2060 |
|
{ |
2061 |
538 |
break; |
2062 |
|
} |
2063 |
|
} |
2064 |
10717 |
if (isConflict) |
2065 |
|
{ |
2066 |
|
d_conflict.set(true); |
2067 |
|
} |
2068 |
10717 |
if (Trace.isOn("qcf-engine")) |
2069 |
|
{ |
2070 |
|
double clSet2 = double(clock()) / double(CLOCKS_PER_SEC); |
2071 |
|
Trace("qcf-engine") << "Finished conflict find engine, time = " |
2072 |
|
<< (clSet2 - clSet); |
2073 |
|
if (addedLemmas > 0) |
2074 |
|
{ |
2075 |
|
Trace("qcf-engine") << ", effort = " |
2076 |
|
<< (d_effort == EFFORT_CONFLICT |
2077 |
|
? "conflict" |
2078 |
|
: (d_effort == EFFORT_PROP_EQ ? "prop_eq" |
2079 |
|
: "mc")); |
2080 |
|
Trace("qcf-engine") << ", addedLemmas = " << addedLemmas; |
2081 |
|
} |
2082 |
|
Trace("qcf-engine") << std::endl; |
2083 |
|
int currEt = d_statistics.d_entailment_checks.get(); |
2084 |
|
if (currEt != prevEt) |
2085 |
|
{ |
2086 |
|
Trace("qcf-engine") << " Entailment checks = " << (currEt - prevEt) |
2087 |
|
<< std::endl; |
2088 |
|
} |
2089 |
|
} |
2090 |
10717 |
Trace("qcf-check2") << "QCF : finished check : " << level << std::endl; |
2091 |
|
} |
2092 |
|
|
2093 |
116939 |
void QuantConflictFind::checkQuantifiedFormula(Node q, |
2094 |
|
bool& isConflict, |
2095 |
|
unsigned& addedLemmas) |
2096 |
|
{ |
2097 |
116939 |
QuantInfo* qi = &d_qinfo[q]; |
2098 |
116939 |
Assert(d_qinfo.find(q) != d_qinfo.end()); |
2099 |
116939 |
if (!qi->matchGeneratorIsValid()) |
2100 |
|
{ |
2101 |
|
// quantified formula is not properly set up for matching |
2102 |
66432 |
return; |
2103 |
|
} |
2104 |
50507 |
if (Trace.isOn("qcf-check")) |
2105 |
|
{ |
2106 |
|
Trace("qcf-check") << "Check quantified formula "; |
2107 |
|
debugPrintQuant("qcf-check", q); |
2108 |
|
Trace("qcf-check") << " : " << q << "..." << std::endl; |
2109 |
|
} |
2110 |
|
|
2111 |
50507 |
Trace("qcf-check-debug") << "Reset round..." << std::endl; |
2112 |
50507 |
if (!qi->reset_round(this)) |
2113 |
|
{ |
2114 |
|
// it is typically the case that another conflict (e.g. in the term |
2115 |
|
// database) was discovered if we fail here. |
2116 |
|
return; |
2117 |
|
} |
2118 |
|
// try to make a matches making the body false or propagating |
2119 |
50507 |
Trace("qcf-check-debug") << "Get next match..." << std::endl; |
2120 |
50507 |
Instantiate* qinst = d_qim.getInstantiate(); |
2121 |
217603 |
while (qi->getNextMatch(this)) |
2122 |
|
{ |
2123 |
84049 |
if (d_qstate.isInConflict()) |
2124 |
|
{ |
2125 |
5 |
Trace("qcf-check") << " ... Quantifiers engine discovered conflict, "; |
2126 |
10 |
Trace("qcf-check") << "probably related to disequal congruent terms in " |
2127 |
5 |
"master equality engine" |
2128 |
5 |
<< std::endl; |
2129 |
506 |
return; |
2130 |
|
} |
2131 |
84044 |
if (Trace.isOn("qcf-inst")) |
2132 |
|
{ |
2133 |
|
Trace("qcf-inst") << "*** Produced match at effort " << d_effort << " : " |
2134 |
|
<< std::endl; |
2135 |
|
qi->debugPrintMatch("qcf-inst"); |
2136 |
|
Trace("qcf-inst") << std::endl; |
2137 |
|
} |
2138 |
|
// check whether internal match constraints are satisfied |
2139 |
102206 |
if (qi->isMatchSpurious(this)) |
2140 |
|
{ |
2141 |
36324 |
Trace("qcf-inst") << " ... Spurious (match is inconsistent)" |
2142 |
18162 |
<< std::endl; |
2143 |
36395 |
continue; |
2144 |
|
} |
2145 |
|
// check whether match can be completed |
2146 |
131197 |
std::vector<int> assigned; |
2147 |
65953 |
if (!qi->completeMatch(this, assigned)) |
2148 |
|
{ |
2149 |
142 |
Trace("qcf-inst") << " ... Spurious (cannot assign unassigned vars)" |
2150 |
71 |
<< std::endl; |
2151 |
71 |
continue; |
2152 |
|
} |
2153 |
|
// check whether the match is spurious according to (T-)entailment checks |
2154 |
131126 |
std::vector<Node> terms; |
2155 |
65811 |
qi->getMatch(terms); |
2156 |
65811 |
bool tcs = qi->isTConstraintSpurious(this, terms); |
2157 |
65811 |
if (tcs) |
2158 |
|
{ |
2159 |
129586 |
Trace("qcf-inst") << " ... Spurious (match is T-inconsistent)" |
2160 |
64793 |
<< std::endl; |
2161 |
|
} |
2162 |
|
else |
2163 |
|
{ |
2164 |
|
// otherwise, we have a conflict/propagating instance |
2165 |
|
// for debugging |
2166 |
1018 |
if (Debug.isOn("qcf-check-inst")) |
2167 |
|
{ |
2168 |
|
Node inst = qinst->getInstantiation(q, terms); |
2169 |
|
Debug("qcf-check-inst") |
2170 |
|
<< "Check instantiation " << inst << "..." << std::endl; |
2171 |
|
Assert(!getTermDatabase()->isEntailed(inst, true)); |
2172 |
|
Assert(getTermDatabase()->isEntailed(inst, false) |
2173 |
|
|| d_effort > EFFORT_CONFLICT); |
2174 |
|
} |
2175 |
|
// Process the lemma: either add an instantiation or specific lemmas |
2176 |
|
// constructed during the isTConstraintSpurious call, or both. |
2177 |
2036 |
InferenceId id = (d_effort == EFFORT_CONFLICT |
2178 |
1018 |
? InferenceId::QUANTIFIERS_INST_CBQI_CONFLICT |
2179 |
|
: InferenceId::QUANTIFIERS_INST_CBQI_PROP); |
2180 |
1018 |
if (!qinst->addInstantiation(q, terms, id)) |
2181 |
|
{ |
2182 |
151 |
Trace("qcf-inst") << " ... Failed to add instantiation" << std::endl; |
2183 |
|
// This should only happen if the algorithm generates the same |
2184 |
|
// propagating instance twice this round. In this case, return |
2185 |
|
// to avoid exponential behavior. |
2186 |
151 |
return; |
2187 |
|
} |
2188 |
867 |
Trace("qcf-check") << " ... Added instantiation" << std::endl; |
2189 |
867 |
if (Trace.isOn("qcf-inst")) |
2190 |
|
{ |
2191 |
|
Trace("qcf-inst") << "*** Was from effort " << d_effort << " : " |
2192 |
|
<< std::endl; |
2193 |
|
qi->debugPrintMatch("qcf-inst"); |
2194 |
|
Trace("qcf-inst") << std::endl; |
2195 |
|
} |
2196 |
867 |
++addedLemmas; |
2197 |
867 |
if (d_effort == EFFORT_CONFLICT) |
2198 |
|
{ |
2199 |
|
// mark relevant: this ensures that quantified formula q is |
2200 |
|
// checked first on the next round. This is an optimization to |
2201 |
|
// ensure that quantified formulas that are more likely to have |
2202 |
|
// conflicting instances are checked earlier. |
2203 |
345 |
d_treg.getModel()->markRelevant(q); |
2204 |
345 |
if (options::qcfAllConflict()) |
2205 |
|
{ |
2206 |
|
isConflict = true; |
2207 |
|
} |
2208 |
|
else |
2209 |
|
{ |
2210 |
345 |
d_conflict.set(true); |
2211 |
|
} |
2212 |
345 |
return; |
2213 |
|
} |
2214 |
522 |
else if (d_effort == EFFORT_PROP_EQ) |
2215 |
|
{ |
2216 |
522 |
d_treg.getModel()->markRelevant(q); |
2217 |
|
} |
2218 |
|
} |
2219 |
|
// clean up assigned |
2220 |
65315 |
qi->revertMatch(this, assigned); |
2221 |
65315 |
d_tempCache.clear(); |
2222 |
|
} |
2223 |
50006 |
Trace("qcf-check") << "Done, conflict = " << d_conflict << std::endl; |
2224 |
|
} |
2225 |
|
|
2226 |
|
//-------------------------------------------------- debugging |
2227 |
|
|
2228 |
|
void QuantConflictFind::debugPrint( const char * c ) { |
2229 |
|
//print the equivalance classes |
2230 |
|
Trace(c) << "----------EQ classes" << std::endl; |
2231 |
|
eq::EqClassesIterator eqcs_i = eq::EqClassesIterator( getEqualityEngine() ); |
2232 |
|
while( !eqcs_i.isFinished() ){ |
2233 |
|
Node n = (*eqcs_i); |
2234 |
|
//if( !n.getType().isInteger() ){ |
2235 |
|
Trace(c) << " - " << n << " : {"; |
2236 |
|
eq::EqClassIterator eqc_i = eq::EqClassIterator( n, getEqualityEngine() ); |
2237 |
|
bool pr = false; |
2238 |
|
while( !eqc_i.isFinished() ){ |
2239 |
|
Node nn = (*eqc_i); |
2240 |
|
if( nn.getKind()!=EQUAL && nn!=n ){ |
2241 |
|
Trace(c) << (pr ? "," : "" ) << " " << nn; |
2242 |
|
pr = true; |
2243 |
|
} |
2244 |
|
++eqc_i; |
2245 |
|
} |
2246 |
|
Trace(c) << (pr ? " " : "" ) << "}" << std::endl; |
2247 |
|
++eqcs_i; |
2248 |
|
} |
2249 |
|
} |
2250 |
|
|
2251 |
|
void QuantConflictFind::debugPrintQuant( const char * c, Node q ) { |
2252 |
|
Trace(c) << "Q" << d_quant_id[q]; |
2253 |
|
} |
2254 |
|
|
2255 |
|
void QuantConflictFind::debugPrintQuantBody( const char * c, Node q, Node n, bool doVarNum ) { |
2256 |
|
if( n.getNumChildren()==0 ){ |
2257 |
|
Trace(c) << n; |
2258 |
|
}else if( doVarNum && d_qinfo[q].d_var_num.find( n )!=d_qinfo[q].d_var_num.end() ){ |
2259 |
|
Trace(c) << "?x" << d_qinfo[q].d_var_num[n]; |
2260 |
|
}else{ |
2261 |
|
Trace(c) << "("; |
2262 |
|
if( n.getKind()==APPLY_UF ){ |
2263 |
|
Trace(c) << n.getOperator(); |
2264 |
|
}else{ |
2265 |
|
Trace(c) << n.getKind(); |
2266 |
|
} |
2267 |
|
for( unsigned i=0; i<n.getNumChildren(); i++ ){ |
2268 |
|
Trace(c) << " "; |
2269 |
|
debugPrintQuantBody( c, q, n[i] ); |
2270 |
|
} |
2271 |
|
Trace(c) << ")"; |
2272 |
|
} |
2273 |
|
} |
2274 |
|
|
2275 |
3050 |
QuantConflictFind::Statistics::Statistics() |
2276 |
|
: d_inst_rounds( |
2277 |
6100 |
smtStatisticsRegistry().registerInt("QuantConflictFind::Inst_Rounds")), |
2278 |
3050 |
d_entailment_checks(smtStatisticsRegistry().registerInt( |
2279 |
6100 |
"QuantConflictFind::Entailment_Checks")) |
2280 |
|
{ |
2281 |
3050 |
} |
2282 |
|
|
2283 |
2 |
TNode QuantConflictFind::getZero( Kind k ) { |
2284 |
2 |
std::map< Kind, Node >::iterator it = d_zero.find( k ); |
2285 |
2 |
if( it==d_zero.end() ){ |
2286 |
4 |
Node nn; |
2287 |
2 |
if( k==PLUS ){ |
2288 |
1 |
nn = NodeManager::currentNM()->mkConst( Rational(0) ); |
2289 |
|
} |
2290 |
2 |
d_zero[k] = nn; |
2291 |
2 |
return nn; |
2292 |
|
}else{ |
2293 |
|
return it->second; |
2294 |
|
} |
2295 |
|
} |
2296 |
|
|
2297 |
|
std::ostream& operator<<(std::ostream& os, const QuantConflictFind::Effort& e) { |
2298 |
|
switch (e) { |
2299 |
|
case QuantConflictFind::EFFORT_INVALID: |
2300 |
|
os << "Invalid"; |
2301 |
|
break; |
2302 |
|
case QuantConflictFind::EFFORT_CONFLICT: |
2303 |
|
os << "Conflict"; |
2304 |
|
break; |
2305 |
|
case QuantConflictFind::EFFORT_PROP_EQ: |
2306 |
|
os << "PropEq"; |
2307 |
|
break; |
2308 |
|
} |
2309 |
|
return os; |
2310 |
|
} |
2311 |
|
|
2312 |
623 |
bool QuantConflictFind::isPropagatingInstance(Node n) const |
2313 |
|
{ |
2314 |
1246 |
std::unordered_set<TNode> visited; |
2315 |
1246 |
std::vector<TNode> visit; |
2316 |
1246 |
TNode cur; |
2317 |
623 |
visit.push_back(n); |
2318 |
1322 |
do |
2319 |
|
{ |
2320 |
1945 |
cur = visit.back(); |
2321 |
1945 |
visit.pop_back(); |
2322 |
1945 |
if (visited.find(cur) == visited.end()) |
2323 |
|
{ |
2324 |
1905 |
visited.insert(cur); |
2325 |
1905 |
Kind ck = cur.getKind(); |
2326 |
1905 |
if (ck == FORALL) |
2327 |
|
{ |
2328 |
|
// do nothing |
2329 |
|
} |
2330 |
1859 |
else if (TermUtil::isBoolConnective(ck)) |
2331 |
|
{ |
2332 |
2010 |
for (TNode cc : cur) |
2333 |
|
{ |
2334 |
1322 |
visit.push_back(cc); |
2335 |
|
} |
2336 |
|
} |
2337 |
1171 |
else if (!getEqualityEngine()->hasTerm(cur)) |
2338 |
|
{ |
2339 |
|
Trace("qcf-instance-check-debug") |
2340 |
|
<< "...not propagating instance because of " << cur << " " << ck |
2341 |
|
<< std::endl; |
2342 |
|
return false; |
2343 |
|
} |
2344 |
|
} |
2345 |
1945 |
} while (!visit.empty()); |
2346 |
623 |
return true; |
2347 |
|
} |
2348 |
|
|
2349 |
|
} // namespace quantifiers |
2350 |
|
} // namespace theory |
2351 |
22746 |
} // namespace cvc5 |