Branch data Line data Source code
1 : : /******************************************************************************
2 : : * This file is part of the cvc5 project.
3 : : *
4 : : * Copyright (c) 2009-2026 by the authors listed in the file AUTHORS
5 : : * in the top-level source directory and their institutional affiliations.
6 : : * All rights reserved. See the file COPYING in the top-level source
7 : : * directory for licensing information.
8 : : * ****************************************************************************
9 : : *
10 : : * Implements conflict-based instantiation (Reynolds et al FMCAD 2014).
11 : : */
12 : :
13 : : #include "theory/quantifiers/quant_conflict_find.h"
14 : :
15 : : #include "base/configuration.h"
16 : : #include "expr/node_algorithm.h"
17 : : #include "options/quantifiers_options.h"
18 : : #include "options/theory_options.h"
19 : : #include "options/uf_options.h"
20 : : #include "theory/quantifiers/ematching/trigger_term_info.h"
21 : : #include "theory/quantifiers/first_order_model.h"
22 : : #include "theory/quantifiers/instantiate.h"
23 : : #include "theory/quantifiers/quant_util.h"
24 : : #include "theory/quantifiers/term_database.h"
25 : : #include "theory/quantifiers/term_util.h"
26 : : #include "theory/rewriter.h"
27 : : #include "util/rational.h"
28 : :
29 : : using namespace cvc5::internal::kind;
30 : : using namespace std;
31 : :
32 : : namespace cvc5::internal {
33 : : namespace theory {
34 : : namespace quantifiers {
35 : :
36 : 47541 : QuantInfo::QuantInfo(Env& env,
37 : : QuantifiersState& qs,
38 : : TermRegistry& tr,
39 : : QuantConflictFind* p,
40 : 47541 : Node q)
41 : : : EnvObj(env),
42 : 47541 : d_qs(qs),
43 : 47541 : d_parent(p),
44 : 47541 : d_instMatch(env, qs, tr, q),
45 : 47541 : d_mg(nullptr),
46 : 47541 : d_q(q),
47 : 47541 : d_unassigned_nvar(0),
48 : 95082 : d_una_index(0)
49 : : {
50 : 47541 : Node qn = d_q[1];
51 : 47541 : d_extra_var.clear();
52 : :
53 : : // register the variables
54 [ + + ]: 154613 : for (size_t i = 0, nvars = d_q[0].getNumChildren(); i < nvars; i++)
55 : : {
56 : 107072 : Node v = d_q[0][i];
57 : 107072 : d_match.push_back(TNode::null());
58 : 107072 : d_match_term.push_back(TNode::null());
59 : 107072 : d_var_num[v] = i;
60 : 107072 : d_vars.push_back(v);
61 : 107072 : d_var_types.push_back(v.getType());
62 : 107072 : }
63 : :
64 : 47541 : registerNode(qn, true, true);
65 : :
66 [ + - ]: 47541 : Trace("qcf-qregister") << "- Make match gen structure..." << std::endl;
67 : 47541 : d_mg = std::make_unique<MatchGen>(d_env, p, this, qn);
68 : :
69 [ + + ]: 47541 : if (d_mg->isValid())
70 : : {
71 [ + + ]: 215239 : for (size_t j = q[0].getNumChildren(), nvars = d_vars.size(); j < nvars;
72 : : j++)
73 : : {
74 [ + + ]: 178557 : if (d_vars[j].getKind() != Kind::BOUND_VARIABLE)
75 : : {
76 : 165904 : d_var_mg[j] = nullptr;
77 : 165904 : bool is_tsym = false;
78 [ + + ][ - - ]: 331808 : if (!MatchGen::isHandledUfTerm(d_vars[j])
79 [ + + ][ + + ]: 331808 : && d_vars[j].getKind() != Kind::ITE)
[ + - ]
80 : : {
81 : 1769 : is_tsym = true;
82 : 1769 : d_tsym_vars.push_back(j);
83 : : }
84 [ + + ][ + + ]: 165904 : if (!is_tsym || options().quantifiers.cbqiTConstraint)
[ + + ]
85 : : {
86 : 164856 : d_var_mg[j] =
87 : 329712 : std::make_unique<MatchGen>(d_env, p, this, d_vars[j], true);
88 : : }
89 [ + + ][ + + ]: 165904 : if (!d_var_mg[j] || !d_var_mg[j]->isValid())
[ + + ]
90 : : {
91 [ + - ]: 9870 : Trace("qcf-invalid")
92 : 4935 : << "QCF invalid : cannot match for " << d_vars[j] << std::endl;
93 : 4935 : d_mg->setInvalid();
94 : 4935 : break;
95 : : }
96 : : else
97 : : {
98 : 160969 : std::vector<size_t> bvars;
99 : 160969 : d_var_mg[j]->determineVariableOrder(bvars);
100 : 160969 : }
101 : : }
102 : : }
103 [ + + ]: 41617 : if (d_mg->isValid())
104 : : {
105 : 36682 : std::vector<size_t> bvars;
106 : 36682 : d_mg->determineVariableOrder(bvars);
107 : 36682 : }
108 : : }
109 : : else
110 : : {
111 [ + - ]: 11848 : Trace("qcf-invalid") << "QCF invalid : body of formula cannot be processed."
112 : 5924 : << std::endl;
113 : : }
114 [ + - ]: 95082 : Trace("qcf-qregister-summary")
115 [ - - ]: 47541 : << "QCF register : " << (d_mg->isValid() ? "VALID " : "INVALID") << " : "
116 : 47541 : << q << std::endl;
117 : :
118 [ + + ]: 47541 : if (d_mg->isValid())
119 : : {
120 : : // optimization : record variable argument positions for terms that must be
121 : : // matched
122 : 36682 : std::vector<TNode> vars;
123 : : // TODO: revisit this, makes QCF faster, but misses conflicts due to caring
124 : : // about paths that may not be relevant (starExec jobs 14136/14137)
125 [ - + ]: 36682 : if (options().quantifiers.cbqiSkipRd)
126 : : {
127 [ - - ]: 0 : for (unsigned j = q[0].getNumChildren(); j < d_vars.size(); j++)
128 : : {
129 : 0 : vars.push_back(d_vars[j]);
130 : : }
131 : : }
132 : : else
133 : : {
134 : : // get all variables that are always relevant
135 : 36682 : std::map<TNode, bool> visited;
136 : 36682 : getPropagateVars(vars, q[1], false, visited);
137 : 36682 : }
138 [ + + ]: 199944 : for (TNode v : vars)
139 : : {
140 : 326524 : TNode f = p->getTermDatabase()->getMatchOperator(v);
141 [ + + ]: 163262 : if (!f.isNull())
142 : : {
143 [ + - ]: 197232 : Trace("qcf-opt") << "Record variable argument positions in " << v
144 : 98616 : << ", op=" << f << "..." << std::endl;
145 [ + + ]: 321512 : for (size_t k = 0, vnchild = v.getNumChildren(); k < vnchild; k++)
146 : : {
147 : 222896 : Node n = v[k];
148 : 222896 : std::map<TNode, size_t>::iterator itv = d_var_num.find(n);
149 [ + + ]: 222896 : if (itv != d_var_num.end())
150 : : {
151 : 191441 : std::vector<size_t>& vrd = d_var_rel_dom[itv->second][f];
152 [ + - ]: 382882 : Trace("qcf-opt")
153 : 191441 : << " arg " << k << " is var #" << itv->second << std::endl;
154 [ + + ]: 191441 : if (std::find(vrd.begin(), vrd.end(), k) == vrd.end())
155 : : {
156 : 179914 : vrd.push_back(k);
157 : : }
158 : : }
159 : 222896 : }
160 : : }
161 : 163262 : }
162 : 36682 : }
163 : 47541 : }
164 : :
165 : 95082 : QuantInfo::~QuantInfo() {}
166 : :
167 : 2850075 : Node QuantInfo::getQuantifiedFormula() const { return d_q; }
168 : :
169 : 0 : QuantifiersInferenceManager& QuantInfo::getInferenceManager()
170 : : {
171 : 0 : Assert(d_parent != nullptr);
172 : 0 : return d_parent->getInferenceManager();
173 : : }
174 : :
175 : 421483 : void QuantInfo::getPropagateVars(std::vector<TNode>& vars,
176 : : TNode n,
177 : : bool pol,
178 : : std::map<TNode, bool>& visited)
179 : : {
180 : 421483 : std::map<TNode, bool>::iterator itv = visited.find(n);
181 [ + + ]: 421483 : if (itv == visited.end())
182 : : {
183 : 310435 : visited[n] = true;
184 : 310435 : bool rec = true;
185 : 310435 : bool newPol = pol;
186 [ + + ]: 310435 : if (d_var_num.find(n) != d_var_num.end())
187 : : {
188 [ - + ][ - + ]: 163262 : Assert(std::find(vars.begin(), vars.end(), n) == vars.end());
[ - - ]
189 : 163262 : vars.push_back(n);
190 : 326524 : TNode f = d_parent->getTermDatabase()->getMatchOperator(n);
191 [ + + ]: 163262 : if (!f.isNull())
192 : : {
193 : 98616 : std::vector<Node>& rd = d_parent->d_func_rel_dom[f];
194 [ + + ]: 98616 : if (std::find(rd.begin(), rd.end(), d_q) == rd.end())
195 : : {
196 : 75384 : rd.push_back(d_q);
197 : : }
198 : : }
199 : 163262 : }
200 [ + + ]: 147173 : else if (MatchGen::isHandledBoolConnective(n))
201 : : {
202 [ - + ][ - + ]: 59777 : Assert(n.getKind() != Kind::IMPLIES);
[ - - ]
203 : 59777 : QuantPhaseReq::getEntailPolarity(n, 0, true, pol, rec, newPol);
204 : : }
205 [ + - ]: 620870 : Trace("qcf-opt-debug") << "getPropagateVars " << n << ", pol = " << pol
206 : 310435 : << ", rec = " << rec << std::endl;
207 [ + + ]: 310435 : if (rec)
208 : : {
209 [ + + ]: 681340 : for (const Node& nc : n)
210 : : {
211 : 384801 : getPropagateVars(vars, nc, pol, visited);
212 : 384801 : }
213 : : }
214 : : }
215 : 421483 : }
216 : :
217 : 4244339 : bool QuantInfo::isBaseMatchComplete()
218 : : {
219 : 4244339 : return d_vars_set.size() == (d_q[0].getNumChildren() + d_extra_var.size());
220 : : }
221 : :
222 : 249132 : void QuantInfo::registerNode(Node n, bool hasPol, bool pol, bool beneathQuant)
223 : : {
224 [ + - ]: 249132 : Trace("qcf-qregister-debug2") << "Register : " << n << std::endl;
225 [ + + ]: 249132 : if (n.getKind() == Kind::FORALL)
226 : : {
227 : 11519 : registerNode(n[1], hasPol, pol, true);
228 : : }
229 : : else
230 : : {
231 [ + + ]: 237613 : if (!MatchGen::isHandledBoolConnective(n))
232 : : {
233 [ + + ]: 130551 : if (expr::hasBoundVar(n))
234 : : {
235 : : // literals
236 [ + + ]: 130202 : if (n.getKind() == Kind::EQUAL)
237 : : {
238 [ + + ]: 205203 : for (unsigned i = 0; i < n.getNumChildren(); i++)
239 : : {
240 : 136802 : flatten(n[i], beneathQuant);
241 : : }
242 : : }
243 [ + + ]: 61801 : else if (MatchGen::isHandledUfTerm(n))
244 : : {
245 : 43907 : flatten(n, beneathQuant);
246 : : }
247 [ + + ]: 17894 : else if (n.getKind() == Kind::ITE)
248 : : {
249 [ + + ]: 10488 : for (unsigned i = 1; i <= 2; i++)
250 : : {
251 : 6992 : flatten(n[i], beneathQuant);
252 : : }
253 : 3496 : registerNode(n[0], false, pol, beneathQuant);
254 : : }
255 [ + + ]: 14398 : else if (options().quantifiers.cbqiTConstraint)
256 : : {
257 : : // a theory-specific predicate
258 [ + + ]: 1944 : for (unsigned i = 0; i < n.getNumChildren(); i++)
259 : : {
260 : 1296 : flatten(n[i], beneathQuant);
261 : : }
262 : : }
263 : : }
264 : : }
265 : : else
266 : : {
267 [ + + ]: 290142 : for (unsigned i = 0; i < n.getNumChildren(); i++)
268 : : {
269 : : bool newHasPol;
270 : : bool newPol;
271 : 183080 : QuantPhaseReq::getPolarity(n, i, hasPol, pol, newHasPol, newPol);
272 : 183080 : registerNode(n[i], newHasPol, newPol, beneathQuant);
273 : : }
274 : : }
275 : : }
276 : 249132 : }
277 : :
278 : 597907 : void QuantInfo::flatten(Node n, bool beneathQuant)
279 : : {
280 [ + - ]: 597907 : Trace("qcf-qregister-debug2") << "Flatten : " << n << std::endl;
281 [ + + ]: 597907 : if (expr::hasBoundVar(n))
282 : : {
283 [ + + ]: 500677 : if (d_var_num.find(n) == d_var_num.end())
284 : : {
285 [ + - ]: 216792 : Trace("qcf-qregister-debug2") << "Add FLATTEN VAR : " << n << std::endl;
286 : 216792 : d_var_num[n] = d_vars.size();
287 : 216792 : d_vars.push_back(n);
288 : 216792 : d_var_types.push_back(n.getType());
289 : 216792 : d_match.push_back(TNode::null());
290 : 216792 : d_match_term.push_back(TNode::null());
291 [ + + ]: 216792 : if (n.getKind() == Kind::ITE)
292 : : {
293 : 3496 : registerNode(n, false, false);
294 : : }
295 [ + + ]: 213296 : else if (n.getKind() == Kind::BOUND_VARIABLE)
296 : : {
297 : 14618 : d_extra_var.push_back(n);
298 : : }
299 : : else
300 : : {
301 [ + + ]: 607588 : for (unsigned i = 0; i < n.getNumChildren(); i++)
302 : : {
303 : 408910 : flatten(n[i], beneathQuant);
304 : : }
305 : : }
306 : : }
307 : : else
308 : : {
309 [ + - ]: 283885 : Trace("qcf-qregister-debug2") << "...already processed" << std::endl;
310 : : }
311 : : }
312 : : else
313 : : {
314 [ + - ]: 97230 : Trace("qcf-qregister-debug2") << "...is ground." << std::endl;
315 : : }
316 : 597907 : }
317 : :
318 : 2830517 : int QuantInfo::getVarNum(TNode v) const
319 : : {
320 : 2830517 : std::map<TNode, size_t>::const_iterator it = d_var_num.find(v);
321 [ + + ]: 2830517 : return it != d_var_num.end() ? static_cast<int>(it->second) : -1;
322 : : }
323 : :
324 : 269046 : bool QuantInfo::reset_round()
325 : : {
326 [ + + ]: 2157224 : for (size_t i = 0, nmatch = d_match.size(); i < nmatch; i++)
327 : : {
328 : 1888178 : d_match[i] = TNode::null();
329 : 1888178 : d_match_term[i] = TNode::null();
330 : : }
331 : 269046 : d_instMatch.resetAll();
332 : 269046 : ieval::TermEvaluatorMode tev = d_parent->atConflictEffort()
333 [ + + ]: 269046 : ? ieval::TermEvaluatorMode::CONFLICT
334 : 269046 : : ieval::TermEvaluatorMode::PROP;
335 : 269046 : d_instMatch.setEvaluatorMode(tev);
336 : 269046 : d_vars_set.clear();
337 : 269046 : d_curr_var_deq.clear();
338 : 269046 : d_tconstraints.clear();
339 : :
340 : 269046 : d_mg->reset_round();
341 [ + + ]: 1399779 : for (const std::pair<const size_t, std::unique_ptr<MatchGen>>& vg : d_var_mg)
342 : : {
343 [ - + ]: 1130733 : if (!vg.second->reset_round())
344 : : {
345 : 0 : return false;
346 : : }
347 : : }
348 : : // now, reset for matching
349 : 269046 : d_mg->reset(false);
350 : 269046 : return true;
351 : : }
352 : :
353 : 14036250 : size_t QuantInfo::getCurrentRepVar(size_t v)
354 : : {
355 [ - + ][ - + ]: 14036250 : Assert(v < d_match.size());
[ - - ]
356 : 14036250 : TNode m = d_match[v];
357 [ + + ]: 14036250 : if (!m.isNull())
358 : : {
359 : 7695692 : std::map<TNode, size_t>::const_iterator it = d_var_num.find(m);
360 [ + + ]: 7695692 : if (it != d_var_num.end())
361 : : {
362 : 40907 : return getCurrentRepVar(it->second);
363 : : }
364 : : }
365 : 13995343 : return v;
366 : 14036250 : }
367 : :
368 : 6531214 : TNode QuantInfo::getCurrentValue(TNode n)
369 : : {
370 : 6531214 : std::map<TNode, size_t>::const_iterator it = d_var_num.find(n);
371 [ + + ]: 6531214 : if (it == d_var_num.end())
372 : : {
373 : 1936213 : return n;
374 : : }
375 : 4595001 : Node m = d_match[it->second];
376 [ + + ]: 4595001 : if (m.isNull())
377 : : {
378 : 4335571 : return n;
379 : : }
380 : 259430 : return getCurrentValue(m);
381 : 4595001 : }
382 : :
383 : 70 : TNode QuantInfo::getCurrentExpValue(TNode n)
384 : : {
385 : 70 : std::map<TNode, size_t>::const_iterator it = d_var_num.find(n);
386 [ - + ]: 70 : if (it == d_var_num.end())
387 : : {
388 : 0 : return n;
389 : : }
390 : 70 : Node m = d_match[it->second];
391 [ - + ]: 70 : if (m.isNull())
392 : : {
393 : 0 : return n;
394 : : }
395 [ - + ][ - + ]: 70 : Assert(m != n);
[ - - ]
396 : 70 : Node mt = d_match_term[it->second];
397 [ - + ]: 70 : if (mt.isNull())
398 : : {
399 : 0 : return getCurrentValue(m);
400 : : }
401 : 70 : return mt;
402 : 70 : }
403 : :
404 : 12631392 : bool QuantInfo::getCurrentCanBeEqual(size_t v, TNode n, bool chDiseq)
405 : : {
406 : : // check disequalities
407 : : std::map<size_t, std::map<TNode, size_t>>::iterator itd =
408 : 12631392 : d_curr_var_deq.find(v);
409 [ + + ]: 12631392 : if (itd == d_curr_var_deq.end())
410 : : {
411 : 8135721 : return true;
412 : : }
413 [ + + ]: 8788237 : for (std::pair<const TNode, size_t>& dd : itd->second)
414 : : {
415 : 8831766 : Node cv = getCurrentValue(dd.first);
416 [ + - ]: 4415883 : Trace("qcf-ccbe") << "compare " << cv << " " << n << std::endl;
417 [ + + ]: 4415883 : if (cv == n)
418 : : {
419 : 123242 : return false;
420 : : }
421 : 4292641 : else if (chDiseq && !isVar(n) && !isVar(cv))
422 : : {
423 : : // they must actually be disequal if we are looking for conflicts
424 [ + + ]: 1117 : if (!d_qs.areDisequal(n, cv))
425 : : {
426 : : // TODO : check for entailed disequal
427 : 75 : return false;
428 : : }
429 : : }
430 [ + + ]: 4415883 : }
431 : :
432 : 4372354 : return true;
433 : : }
434 : :
435 : 0 : int QuantInfo::addConstraint(size_t v, TNode n, bool polarity)
436 : : {
437 : 0 : v = getCurrentRepVar(v);
438 : 0 : int vn = getVarNum(n);
439 [ - - ]: 0 : if (vn != -1)
440 : : {
441 : 0 : vn = static_cast<int>(getCurrentRepVar(static_cast<size_t>(vn)));
442 : : }
443 : 0 : n = getCurrentValue(n);
444 : 0 : return addConstraint(v, n, vn, polarity, false);
445 : : }
446 : :
447 : 1430946 : int QuantInfo::addConstraint(
448 : : size_t v, TNode n, int vn, bool polarity, bool doRemove)
449 : : {
450 [ - + ][ - + ]: 1430946 : Assert(v < d_match.size());
[ - - ]
451 : : // for handling equalities between variables, and disequalities involving
452 : : // variables
453 [ + - ][ - - ]: 2861892 : Trace("qcf-match-debug") << "- " << (doRemove ? "un" : "")
454 : 0 : << "constrain : " << v << " -> " << n
455 : 1430946 : << " (cv=" << getCurrentValue(n) << ")";
456 [ + - ]: 2861892 : Trace("qcf-match-debug") << ", (vn=" << vn << "), polarity = " << polarity
457 : 1430946 : << std::endl;
458 : 1430946 : Assert(doRemove || n == getCurrentValue(n));
459 [ + + ][ + - ]: 1430946 : Assert(doRemove || v == getCurrentRepVar(v));
[ - + ][ - + ]
[ - - ]
460 : 1430946 : Assert(doRemove || (vn == -1 && getVarNum(n) == -1)
461 : : || (vn >= 0
462 : : && static_cast<size_t>(vn)
463 : : == getCurrentRepVar(static_cast<size_t>(getVarNum(n)))));
464 [ + + ]: 1430946 : if (polarity)
465 : : {
466 [ + - ]: 992779 : if (vn != static_cast<int>(v))
467 : : {
468 [ + + ]: 992779 : if (doRemove)
469 : : {
470 [ + + ]: 481392 : if (vn != -1)
471 : : {
472 : : // if set to this in the opposite direction, clean up opposite instead
473 : : // std::map< int, TNode >::iterator itmn = d_match.find( vn
474 : : // );
475 [ - + ]: 31070 : if (d_match[vn] == d_vars[v])
476 : : {
477 : 0 : return addConstraint(vn, d_vars[v], v, true, true);
478 : : }
479 : : else
480 : : {
481 : : // unsetting variables equal
482 : : std::map<size_t, std::map<TNode, size_t>>::iterator itd =
483 : 31070 : d_curr_var_deq.find(vn);
484 [ + + ]: 31070 : if (itd != d_curr_var_deq.end())
485 : : {
486 : : // remove disequalities owned by this
487 : 12079 : std::vector<TNode> remDeq;
488 [ + + ]: 12518 : for (const std::pair<const TNode, size_t>& dd : itd->second)
489 : : {
490 [ + - ]: 439 : if (dd.second == v)
491 : : {
492 : 439 : remDeq.push_back(dd.first);
493 : : }
494 : : }
495 [ + + ]: 12518 : for (TNode rd : remDeq)
496 : : {
497 : 439 : itd->second.erase(rd);
498 : 439 : }
499 : 12079 : }
500 : : }
501 : : }
502 : 481392 : unsetMatch(v);
503 : 481392 : return 1;
504 : : }
505 : : else
506 : : {
507 : 511387 : bool isGroundRep = false;
508 : 511387 : bool isGround = false;
509 [ + + ]: 511387 : if (vn != -1)
510 : : {
511 [ + - ]: 63044 : Trace("qcf-match-debug")
512 : 31522 : << " ...Variable bound to variable" << std::endl;
513 [ + - ]: 31522 : if (d_match[v].isNull())
514 : : {
515 : : // setting variables equal
516 : 31522 : bool alreadySet = false;
517 [ - + ]: 31522 : if (!d_match[vn].isNull())
518 : : {
519 : 0 : alreadySet = true;
520 : 0 : Assert(!isVar(d_match[vn]));
521 : : }
522 : :
523 : : // copy or check disequalities
524 : : std::map<size_t, std::map<TNode, size_t>>::iterator itd =
525 : 31522 : d_curr_var_deq.find(v);
526 [ + + ]: 31522 : if (itd != d_curr_var_deq.end())
527 : : {
528 : 12094 : std::map<TNode, size_t>& cvd = d_curr_var_deq[vn];
529 [ + + ]: 12533 : for (const std::pair<const TNode, size_t>& dd : itd->second)
530 : : {
531 : 878 : Node dv = getCurrentValue(dd.first);
532 [ + - ]: 439 : if (!alreadySet)
533 : : {
534 [ + - ]: 439 : if (cvd.find(dv) == cvd.end())
535 : : {
536 : 439 : cvd[dv] = v;
537 : : }
538 : : }
539 [ - - ]: 0 : else if (d_match[vn] == dv)
540 : : {
541 [ - - ]: 0 : Trace("qcf-match-debug")
542 : 0 : << " -> fail, conflicting disequality" << std::endl;
543 : 0 : return -1;
544 : : }
545 [ + - ]: 439 : }
546 : : }
547 [ - + ]: 31522 : if (alreadySet)
548 : : {
549 : 0 : n = getCurrentValue(n);
550 : : }
551 : : }
552 : : else
553 : : {
554 [ - - ]: 0 : if (d_match[vn].isNull())
555 : : {
556 [ - - ]: 0 : Trace("qcf-match-debug") << " ...Reverse direction" << std::endl;
557 : : // set the opposite direction
558 : 0 : return addConstraint(vn, d_vars[v], v, true, false);
559 : : }
560 : : else
561 : : {
562 [ - - ]: 0 : Trace("qcf-match-debug")
563 : 0 : << " -> Both variables bound, compare" << std::endl;
564 : : // are they currently equal
565 [ - - ]: 0 : return d_match[v] == d_match[vn] ? 0 : -1;
566 : : }
567 : : }
568 : : }
569 : : else
570 : : {
571 [ + - ]: 959730 : Trace("qcf-match-debug")
572 : 479865 : << " ...Variable bound to ground" << std::endl;
573 [ + - ]: 479865 : if (d_match[v].isNull())
574 : : {
575 : : // isGroundRep = true; ??
576 : 479865 : isGround = true;
577 : : }
578 : : else
579 : : {
580 : : // compare ground values
581 [ - - ]: 0 : Trace("qcf-match-debug") << " -> Ground value, compare "
582 : 0 : << d_match[v] << " " << n << std::endl;
583 [ - - ]: 0 : return d_match[v] == n ? 0 : -1;
584 : : }
585 : : }
586 [ + + ]: 511387 : if (setMatch(v, n, isGroundRep, isGround))
587 : : {
588 [ + - ]: 485990 : Trace("qcf-match-debug") << " -> success" << std::endl;
589 : 485990 : return 1;
590 : : }
591 : : else
592 : : {
593 [ + - ]: 50794 : Trace("qcf-match-debug")
594 : 25397 : << " -> fail, conflicting disequality" << std::endl;
595 : 25397 : return -1;
596 : : }
597 : : }
598 : : }
599 : : else
600 : : {
601 [ - - ]: 0 : Trace("qcf-match-debug")
602 : 0 : << " -> redundant, variable identity" << std::endl;
603 : 0 : return 0;
604 : : }
605 : : }
606 : : else
607 : : {
608 [ - + ]: 438167 : if (vn == static_cast<int>(v))
609 : : {
610 [ - - ]: 0 : Trace("qcf-match-debug") << " -> fail, variable identity" << std::endl;
611 : 0 : return -1;
612 : : }
613 : : else
614 : : {
615 [ + + ]: 438167 : if (doRemove)
616 : : {
617 [ - + ][ - + ]: 218115 : Assert(d_curr_var_deq[v].find(n) != d_curr_var_deq[v].end());
[ - - ]
618 : 218115 : d_curr_var_deq[v].erase(n);
619 : 218115 : return 1;
620 : : }
621 : : else
622 : : {
623 [ + + ]: 220052 : if (d_curr_var_deq[v].find(n) == d_curr_var_deq[v].end())
624 : : {
625 : : // check if it respects equality
626 [ - + ]: 219590 : if (!d_match[v].isNull())
627 : : {
628 : 0 : TNode nv = getCurrentValue(n);
629 [ - - ]: 0 : if (nv == d_match[v])
630 : : {
631 [ - - ]: 0 : Trace("qcf-match-debug")
632 : 0 : << " -> fail, conflicting disequality" << std::endl;
633 : 0 : return -1;
634 : : }
635 [ - - ]: 0 : }
636 : 219590 : d_curr_var_deq[v][n] = v;
637 [ + - ]: 219590 : Trace("qcf-match-debug") << " -> success" << std::endl;
638 : 219590 : return 1;
639 : : }
640 : : else
641 : : {
642 [ + - ]: 462 : Trace("qcf-match-debug") << " -> redundant disequality" << std::endl;
643 : 462 : return 0;
644 : : }
645 : : }
646 : : }
647 : : }
648 : : }
649 : :
650 : 160 : bool QuantInfo::isConstrainedVar(size_t v)
651 : : {
652 : : std::map<size_t, std::map<TNode, size_t>>::const_iterator it =
653 : 160 : d_curr_var_deq.find(v);
654 [ + + ][ - + ]: 160 : if (it != d_curr_var_deq.end() && !it->second.empty())
[ - + ]
655 : : {
656 : 0 : return true;
657 : : }
658 : 160 : TNode vv = getVar(v);
659 [ - + ]: 160 : if (std::find(d_match.begin(), d_match.end(), vv) != d_match.end())
660 : : {
661 : 0 : return true;
662 : : }
663 : 160 : for (const std::pair<const size_t, std::map<TNode, size_t>>& d :
664 [ + + ]: 404 : d_curr_var_deq)
665 : : {
666 [ + + ]: 116 : for (const std::pair<const TNode, size_t>& dd : d.second)
667 : : {
668 [ - + ]: 32 : if (dd.first == vv)
669 : : {
670 : 0 : return true;
671 : : }
672 : : }
673 : : }
674 : 160 : return false;
675 : 160 : }
676 : :
677 : 12463363 : bool QuantInfo::setMatch(size_t v, TNode n, bool isGroundRep, bool isGround)
678 : : {
679 [ + + ]: 12463363 : if (!getCurrentCanBeEqual(v, n))
680 : : {
681 : 119037 : return false;
682 : : }
683 [ + + ]: 12344326 : if (isGroundRep)
684 : : {
685 : : // fail if n does not exist in the relevant domain of each of the argument
686 : : // positions
687 : : std::map<size_t, std::map<TNode, std::vector<size_t>>>::iterator it =
688 : 11830322 : d_var_rel_dom.find(v);
689 [ + + ]: 11830322 : if (it != d_var_rel_dom.end())
690 : : {
691 : 6065514 : TermDb* tdb = d_parent->getTermDatabase();
692 [ + + ]: 13619478 : for (std::pair<const TNode, std::vector<size_t>>& rd : it->second)
693 : : {
694 [ + + ]: 16131523 : for (size_t index : rd.second)
695 : : {
696 [ + - ]: 17155118 : Trace("qcf-match-debug2") << n << " in relevant domain " << rd.first
697 : 8577559 : << "." << index << "?" << std::endl;
698 [ + + ]: 8577559 : if (!tdb->inRelevantDomain(rd.first, index, n))
699 : : {
700 [ + - ]: 845422 : Trace("qcf-match-debug")
701 : 0 : << " -> fail, since " << n << " is not in relevant domain of "
702 : 422711 : << rd.first << "." << index << std::endl;
703 : 422711 : return false;
704 : : }
705 : : }
706 : : }
707 : : }
708 : : }
709 [ + - ]: 23843230 : Trace("qcf-match-debug") << "-- bind : " << v << " -> " << n << ", checked "
710 : 11921615 : << d_curr_var_deq[v].size() << " disequalities"
711 : 11921615 : << std::endl;
712 [ + + ][ + + ]: 11921615 : if (isGround && d_vars[v].getKind() == Kind::BOUND_VARIABLE)
[ + + ]
713 : : {
714 : : // Set the inst match object if this corresponds to an original variable
715 [ + + ]: 4381977 : if (v < d_q[0].getNumChildren())
716 : : {
717 : : // we overwrite, so we must reset/set here
718 [ + + ]: 4378418 : if (!d_instMatch.get(v).isNull())
719 : : {
720 : 457571 : d_instMatch.reset(v);
721 : : }
722 [ + + ]: 4378418 : if (!d_instMatch.set(v, n))
723 : : {
724 : 2987894 : return false;
725 : : }
726 : : }
727 : 1394083 : d_vars_set.insert(v);
728 [ + - ]: 2788166 : Trace("qcf-match-debug")
729 : 0 : << "---- now bound " << d_vars_set.size() << " / "
730 [ - + ][ - - ]: 1394083 : << d_q[0].getNumChildren() << " base variables." << std::endl;
731 : : }
732 : : // Note that assigning to a variable that an original variable is equal to
733 : : // should trigger the match object. For example, if we have auxiliary
734 : : // variable k and original variable x where x <-> k currently, and we set
735 : : // k -> t, then we should notify the match object that x -> t. However,
736 : : // this is not done, as it would require more complex bookkeeping. Overall,
737 : : // this means that we may fail in some rare cases to eagerly recognize when a
738 : : // substitution is entailed.
739 : 8933721 : d_match[v] = n;
740 : 8933721 : return true;
741 : : }
742 : :
743 : 7451318 : void QuantInfo::unsetMatch(size_t v)
744 : : {
745 [ + - ]: 7451318 : Trace("qcf-match-debug") << "-- unbind : " << v << std::endl;
746 : 7451318 : if (d_vars[v].getKind() == Kind::BOUND_VARIABLE
747 [ + + ][ + + ]: 7451318 : && d_vars_set.find(v) != d_vars_set.end())
[ + + ]
748 : : {
749 : 934458 : d_vars_set.erase(v);
750 : : // Reset the inst match object if this corresponds to an original variable
751 [ + + ]: 934458 : if (v < d_q[0].getNumChildren())
752 : : {
753 [ + + ]: 931886 : if (!d_instMatch.get(v).isNull())
754 : : {
755 : 925174 : d_instMatch.reset(v);
756 : : }
757 : : }
758 : : }
759 : 7451318 : d_match[v] = TNode::null();
760 : 7451318 : }
761 : :
762 : 36101 : bool QuantInfo::isMatchSpurious()
763 : : {
764 [ + + ]: 259565 : for (size_t i = 0, nvars = getNumVars(); i < nvars; i++)
765 : : {
766 [ + + ]: 227744 : if (!d_match[i].isNull())
767 : : {
768 [ + + ]: 168029 : if (!getCurrentCanBeEqual(i, d_match[i], d_parent->atConflictEffort()))
769 : : {
770 : 4280 : return true;
771 : : }
772 : : }
773 : : }
774 : 31821 : return false;
775 : : }
776 : :
777 : 30580 : bool QuantInfo::isTConstraintSpurious(const std::vector<Node>& terms)
778 : : {
779 [ + + ]: 30580 : if (options().quantifiers.ievalMode != options::IevalMode::OFF)
780 : : {
781 : : // We rely on the instantiation evaluator. When the instantiation evaluator
782 : : // is enabled, this method (almost) always returns false. The code may
783 : : // return true based on minor differences in the entailment tests, which
784 : : // would allow us in very rare cases to recognize when an instantiation
785 : : // is spurious.
786 : 6757 : return false;
787 : : }
788 : 23823 : EntailmentCheck* echeck = d_parent->getTermRegistry().getEntailmentCheck();
789 : : // check whether the instantiation evaluates as expected
790 : 23823 : std::map<TNode, TNode> subs;
791 [ + + ]: 94526 : for (size_t i = 0, tsize = terms.size(); i < tsize; i++)
792 : : {
793 [ + - ]: 70703 : Trace("qcf-instance-check") << " " << terms[i] << std::endl;
794 : 70703 : subs[d_q[0][i]] = terms[i];
795 : : }
796 [ + + ]: 23893 : for (size_t i = 0, evsize = d_extra_var.size(); i < evsize; i++)
797 : : {
798 : 140 : Node n = getCurrentExpValue(d_extra_var[i]);
799 [ + - ]: 140 : Trace("qcf-instance-check")
800 : 70 : << " " << d_extra_var[i] << " -> " << n << std::endl;
801 : 70 : subs[d_extra_var[i]] = n;
802 : 70 : }
803 [ + + ]: 23823 : if (d_parent->atConflictEffort())
804 : : {
805 [ + - ]: 33926 : Trace("qcf-instance-check")
806 : 16963 : << "Possible conflict instance for " << d_q << " : " << std::endl;
807 [ + + ]: 16963 : if (!echeck->isEntailed(d_q[1], subs, false, false))
808 : : {
809 [ + - ]: 33866 : Trace("qcf-instance-check")
810 : 16933 : << "...not entailed to be false." << std::endl;
811 : 16933 : return true;
812 : : }
813 : : }
814 : : else
815 : : {
816 : : // see if the body of the quantified formula evaluates to a Boolean
817 : : // combination of known terms under the current substitution. We use
818 : : // the helper method evaluateTerm from the entailment check utility.
819 : : Node inst_eval = echeck->evaluateTerm(
820 : 13720 : d_q[1], subs, false, options().quantifiers.cbqiTConstraint, true);
821 [ - + ]: 6860 : if (TraceIsOn("qcf-instance-check"))
822 : : {
823 [ - - ]: 0 : Trace("qcf-instance-check")
824 : 0 : << "Possible propagating instance for " << d_q << " : " << std::endl;
825 [ - - ]: 0 : Trace("qcf-instance-check") << " " << terms << std::endl;
826 [ - - ]: 0 : Trace("qcf-instance-check")
827 : 0 : << "...evaluates to " << inst_eval << std::endl;
828 : : }
829 : : // If it is the case that instantiation can be rewritten to a Boolean
830 : : // combination of terms that exist in the current context, then inst_eval
831 : : // is non-null. Moreover, we insist that inst_eval is not true, or else
832 : : // the instantiation is trivially entailed and hence is spurious.
833 : 6860 : if (inst_eval.isNull()
834 [ + + ][ + + ]: 6860 : || (inst_eval.isConst() && inst_eval.getConst<bool>()))
[ + + ][ + + ]
835 : : {
836 [ + - ]: 6753 : Trace("qcf-instance-check") << "...spurious." << std::endl;
837 : 6753 : return true;
838 : : }
839 : : else
840 : : {
841 [ + - ]: 107 : if (Configuration::isDebugBuild())
842 : : {
843 [ - + ]: 107 : if (!d_parent->isPropagatingInstance(inst_eval))
844 : : {
845 : : // Notice that this can happen in cases where:
846 : : // (1) x = -1*y is rewritten to y = -1*x, and
847 : : // (2) -1*y is a term in the master equality engine but -1*x is not.
848 : : // In other words, we determined that x = -1*y is a relevant
849 : : // equality to propagate since it involves two known terms, but
850 : : // after rewriting, the equality y = -1*x involves an unknown term
851 : : // -1*x. In this case, the equality is still relevant to propagate,
852 : : // despite the above function not being precise enough to realize
853 : : // it. We output a warning in debug for this. See #2993.
854 [ - - ]: 0 : Trace("qcf-instance-check")
855 : 0 : << "WARNING: not propagating." << std::endl;
856 : : }
857 : : }
858 [ + - ]: 107 : Trace("qcf-instance-check") << "...not spurious." << std::endl;
859 : : }
860 [ + + ]: 6860 : }
861 [ - + ]: 137 : if (!d_tconstraints.empty())
862 : : {
863 : : // check constraints
864 : 0 : QuantifiersRegistry& qr = d_parent->getQuantifiersRegistry();
865 : 0 : for (std::map<Node, bool>::iterator it = d_tconstraints.begin();
866 [ - - ]: 0 : it != d_tconstraints.end();
867 : 0 : ++it)
868 : : {
869 : : // apply substitution to the tconstraint
870 : 0 : Node cons = qr.substituteBoundVariables(it->first, d_q, terms);
871 [ - - ]: 0 : cons = it->second ? cons : cons.negate();
872 [ - - ]: 0 : if (!entailmentTest(cons, d_parent->atConflictEffort()))
873 : : {
874 : 0 : return true;
875 : : }
876 [ - - ]: 0 : }
877 : : }
878 : : // spurious if quantifiers engine is in conflict
879 : 137 : return d_parent->d_qstate.isInConflict();
880 : 23823 : }
881 : :
882 : 0 : bool QuantInfo::entailmentTest(Node lit, bool chEnt)
883 : : {
884 [ - - ]: 0 : Trace("qcf-tconstraint-debug") << "Check : " << lit << std::endl;
885 : 0 : Node rew = rewrite(lit);
886 [ - - ]: 0 : if (rew.isConst())
887 : : {
888 [ - - ]: 0 : Trace("qcf-tconstraint-debug") << "...constraint " << lit << " rewrites to "
889 : 0 : << rew << "." << std::endl;
890 : 0 : return rew.getConst<bool>();
891 : : }
892 : : // if checking for conflicts, we must be sure that the (negation of)
893 : : // constraint is (not) entailed
894 [ - - ]: 0 : if (!chEnt)
895 : : {
896 : 0 : rew = rewrite(rew.negate());
897 : : }
898 : : // check if it is entailed
899 [ - - ]: 0 : Trace("qcf-tconstraint-debug")
900 : 0 : << "Check entailment of " << rew << "..." << std::endl;
901 : : std::pair<bool, Node> et =
902 : 0 : d_parent->getState().getValuation().entailmentCheck(
903 : 0 : options::TheoryOfMode::THEORY_OF_TYPE_BASED, rew);
904 : 0 : ++(d_parent->d_statistics.d_entailment_checks);
905 [ - - ]: 0 : Trace("qcf-tconstraint-debug")
906 : 0 : << "ET result : " << et.first << " " << et.second << std::endl;
907 [ - - ]: 0 : if (!et.first)
908 : : {
909 [ - - ]: 0 : Trace("qcf-tconstraint-debug")
910 : 0 : << "...cannot show entailment of " << rew << "." << std::endl;
911 : 0 : return !chEnt;
912 : : }
913 : 0 : return chEnt;
914 : 0 : }
915 : :
916 : 31587 : bool QuantInfo::completeMatch(std::vector<size_t>& assigned, bool doContinue)
917 : : {
918 : : // assign values for variables that were unassigned (usually not necessary,
919 : : // but handles corner cases)
920 : 31587 : bool doFail = false;
921 : 31587 : bool success = true;
922 [ - + ]: 31587 : if (doContinue)
923 : : {
924 : 0 : doFail = true;
925 : 0 : success = false;
926 : : }
927 : : else
928 : : {
929 [ + + ]: 31587 : if (isBaseMatchComplete())
930 : : {
931 : 30277 : return true;
932 : : }
933 : : // solve for interpreted symbol matches
934 : : // this breaks the invariant that all introduced constraints are over
935 : : // existing terms
936 [ + + ]: 1350 : for (int i = (int)(d_tsym_vars.size() - 1); i >= 0; i--)
937 : : {
938 : 66 : int index = d_tsym_vars[i];
939 : 66 : TNode v = getCurrentValue(d_vars[index]);
940 : 66 : int slv_v = -1;
941 [ + + ]: 66 : if (v == d_vars[index])
942 : : {
943 : 40 : slv_v = index;
944 : : }
945 [ + - ]: 132 : Trace("qcf-tconstraint-debug")
946 : 0 : << "Solve " << d_vars[index] << " = " << v << " "
947 : 66 : << d_vars[index].getKind() << std::endl;
948 : 66 : if (d_vars[index].getKind() == Kind::ADD
949 [ + + ][ + + ]: 66 : || d_vars[index].getKind() == Kind::MULT)
[ + + ]
950 : : {
951 : 40 : Kind k = d_vars[index].getKind();
952 : 40 : std::vector<TNode> children;
953 [ + + ]: 76 : for (const Node& vi : d_vars[index])
954 : : {
955 : 62 : int vn = getVarNum(vi);
956 [ + + ]: 62 : if (vn != -1)
957 : : {
958 : 47 : TNode vv = getCurrentValue(vi);
959 [ + + ]: 47 : if (vv == vi)
960 : : {
961 : : // we will assign this
962 [ - + ]: 40 : if (slv_v == -1)
963 : : {
964 [ - - ]: 0 : Trace("qcf-tconstraint-debug")
965 : 0 : << "...will solve for var #" << vn << std::endl;
966 : 0 : slv_v = vn;
967 [ - - ]: 0 : if (!d_parent->atConflictEffort())
968 : : {
969 : 0 : break;
970 : : }
971 : : }
972 : : else
973 : : {
974 : 80 : Node z = d_parent->getZero(d_vars[index].getType(), k);
975 [ + + ]: 40 : if (!z.isNull())
976 : : {
977 : 33 : size_t vni = static_cast<size_t>(vn);
978 [ + - ]: 66 : Trace("qcf-tconstraint-debug")
979 : 33 : << "...set " << d_vars[vn] << " = " << z << std::endl;
980 : 33 : assigned.push_back(vni);
981 [ + + ]: 33 : if (!setMatch(vni, z, false, true))
982 : : {
983 : 26 : success = false;
984 : 26 : break;
985 : : }
986 : : }
987 [ + + ]: 40 : }
988 : : }
989 : : else
990 : : {
991 [ + - ]: 14 : Trace("qcf-tconstraint-debug")
992 : 7 : << "...sum value " << vv << std::endl;
993 : 7 : children.push_back(vv);
994 : : }
995 [ + + ]: 47 : }
996 : : else
997 : : {
998 [ + - ]: 15 : Trace("qcf-tconstraint-debug") << "...sum " << vi << std::endl;
999 : 15 : children.push_back(vi);
1000 : : }
1001 [ + + ]: 62 : }
1002 [ + + ]: 40 : if (success)
1003 : : {
1004 [ + - ]: 14 : if (slv_v != -1)
1005 : : {
1006 : 14 : Node lhs;
1007 [ - + ]: 14 : if (children.empty())
1008 : : {
1009 : 0 : lhs = d_parent->getZero(d_vars[index].getType(), k);
1010 : : }
1011 [ + - ]: 14 : else if (children.size() == 1)
1012 : : {
1013 : 14 : lhs = children[0];
1014 : : }
1015 : : else
1016 : : {
1017 : 0 : lhs = nodeManager()->mkNode(k, children);
1018 : : }
1019 : 14 : Node sum;
1020 [ + - ]: 14 : if (v == d_vars[index])
1021 : : {
1022 : 14 : sum = lhs;
1023 : : }
1024 : : else
1025 : : {
1026 [ - - ]: 0 : if (d_parent->atConflictEffort())
1027 : : {
1028 : 0 : Kind kn = k;
1029 [ - - ]: 0 : if (d_vars[index].getKind() == Kind::ADD)
1030 : : {
1031 : 0 : kn = Kind::SUB;
1032 : : }
1033 [ - - ]: 0 : if (kn != k)
1034 : : {
1035 : 0 : sum = nodeManager()->mkNode(kn, v, lhs);
1036 : : }
1037 : : }
1038 : : }
1039 [ + - ]: 14 : if (!sum.isNull())
1040 : : {
1041 : 14 : assigned.push_back(slv_v);
1042 [ + - ]: 28 : Trace("qcf-tconstraint-debug")
1043 : 14 : << "...set " << d_vars[slv_v] << " = " << sum << std::endl;
1044 [ - + ]: 14 : if (!setMatch(slv_v, sum, false, true))
1045 : : {
1046 : 0 : success = false;
1047 : : }
1048 : 14 : d_parent->d_tempCache.push_back(sum);
1049 : : }
1050 : 14 : }
1051 : : else
1052 : : {
1053 : : // must show that constraint is met
1054 : 0 : Node sum = nodeManager()->mkNode(k, children);
1055 : 0 : Node eq = sum.eqNode(v);
1056 [ - - ]: 0 : if (!entailmentTest(eq))
1057 : : {
1058 : 0 : success = false;
1059 : : }
1060 : 0 : d_parent->d_tempCache.push_back(sum);
1061 : 0 : }
1062 : : }
1063 : 40 : }
1064 : :
1065 [ + + ]: 66 : if (!success)
1066 : : {
1067 : 26 : break;
1068 : : }
1069 [ + + ]: 66 : }
1070 [ + + ]: 1310 : if (success)
1071 : : {
1072 : : // check what is left to assign
1073 : 1284 : d_unassigned.clear();
1074 : 1284 : d_unassigned_tn.clear();
1075 [ + + ]: 7704 : std::vector<size_t> unassigned[2];
1076 [ + + ]: 6420 : std::vector<TypeNode> unassigned_tn[2];
1077 [ + + ]: 3551 : for (size_t i = 0, nvars = getNumVars(); i < nvars; i++)
1078 : : {
1079 [ + + ]: 2267 : if (d_match[i].isNull())
1080 : : {
1081 [ + + ]: 1803 : int rindex = d_var_mg.find(i) == d_var_mg.end() ? 1 : 0;
1082 : 1803 : unassigned[rindex].push_back(i);
1083 : 1803 : unassigned_tn[rindex].push_back(getVar(i).getType());
1084 : 1803 : assigned.push_back(i);
1085 : : }
1086 : : }
1087 : 1284 : d_unassigned_nvar = unassigned[0].size();
1088 [ + + ]: 3852 : for (unsigned i = 0; i < 2; i++)
1089 : : {
1090 : 5136 : d_unassigned.insert(
1091 : 2568 : d_unassigned.end(), unassigned[i].begin(), unassigned[i].end());
1092 : 2568 : d_unassigned_tn.insert(d_unassigned_tn.end(),
1093 : : unassigned_tn[i].begin(),
1094 : : unassigned_tn[i].end());
1095 : : }
1096 : 1284 : d_una_eqc_count.clear();
1097 : 1284 : d_una_index = 0;
1098 [ + + ][ + + ]: 7704 : }
[ - - ][ - - ]
1099 : : }
1100 : :
1101 [ + + ][ - + ]: 1310 : if (!d_unassigned.empty() && (success || doContinue))
[ - - ][ + + ]
1102 : : {
1103 [ + - ]: 2430 : Trace("qcf-check") << "Assign to unassigned (" << d_unassigned.size()
1104 : 1215 : << ")..." << std::endl;
1105 : : do
1106 : : {
1107 [ - + ]: 1215 : if (doFail)
1108 : : {
1109 [ - - ]: 0 : Trace("qcf-check-unassign") << "Failure, try again..." << std::endl;
1110 : : }
1111 : 1215 : bool invalidMatch = false;
1112 [ + + ][ + - ]: 8126 : while ((success && d_una_index < d_unassigned.size()) || invalidMatch
1113 [ + + ][ - + ]: 13822 : || doFail)
[ + + ]
1114 : : {
1115 : 5696 : invalidMatch = false;
1116 [ + - ][ + + ]: 5696 : if (!doFail && d_una_index == d_una_eqc_count.size())
[ + + ]
1117 : : {
1118 : : // check if it has now been assigned
1119 [ + + ]: 1703 : if (d_una_index < d_unassigned_nvar)
1120 : : {
1121 [ + - ]: 80 : if (!isConstrainedVar(d_unassigned[d_una_index]))
1122 : : {
1123 : 80 : d_una_eqc_count.push_back(-1);
1124 : : }
1125 : : else
1126 : : {
1127 : 0 : d_var_mg[d_unassigned[d_una_index]]->reset(true);
1128 : 0 : d_una_eqc_count.push_back(0);
1129 : : }
1130 : : }
1131 : : else
1132 : : {
1133 : 1623 : d_una_eqc_count.push_back(0);
1134 : : }
1135 : : }
1136 : : else
1137 : : {
1138 : 3993 : bool failed = false;
1139 [ + - ]: 3993 : if (!doFail)
1140 : : {
1141 [ + + ]: 3993 : if (d_una_index < d_unassigned_nvar)
1142 : : {
1143 [ + - ]: 80 : if (!isConstrainedVar(d_unassigned[d_una_index]))
1144 : : {
1145 [ + - ]: 160 : Trace("qcf-check-unassign")
1146 : 0 : << "Succeeded, variable unconstrained at " << d_una_index
1147 : 80 : << std::endl;
1148 : 80 : d_una_index++;
1149 : : }
1150 [ - - ]: 0 : else if (d_var_mg[d_unassigned[d_una_index]]->getNextMatch())
1151 : : {
1152 [ - - ]: 0 : Trace("qcf-check-unassign") << "Succeeded match with mg at "
1153 : 0 : << d_una_index << std::endl;
1154 : 0 : d_una_index++;
1155 : : }
1156 : : else
1157 : : {
1158 : 0 : failed = true;
1159 [ - - ]: 0 : Trace("qcf-check-unassign")
1160 : 0 : << "Failed match with mg at " << d_una_index << std::endl;
1161 : : }
1162 : : }
1163 : : else
1164 : : {
1165 [ + - ][ + - ]: 3913 : Assert(doFail || d_una_index + 1 == d_una_eqc_count.size());
[ - + ][ - + ]
[ - - ]
1166 : : const std::vector<TNode>& eqcs =
1167 : 3913 : d_parent->d_eqcs[d_unassigned_tn[d_una_index]];
1168 [ + + ]: 3913 : if (d_una_eqc_count[d_una_index] < static_cast<int>(eqcs.size()))
1169 : : {
1170 : 2581 : int currIndex = d_una_eqc_count[d_una_index];
1171 : 2581 : d_una_eqc_count[d_una_index]++;
1172 [ + - ]: 5162 : Trace("qcf-check-unassign") << d_unassigned[d_una_index] << "->"
1173 : 2581 : << eqcs[currIndex] << std::endl;
1174 [ + + ]: 5162 : if (setMatch(
1175 : 5162 : d_unassigned[d_una_index], eqcs[currIndex], true, true))
1176 : : {
1177 : 642 : d_match_term[d_unassigned[d_una_index]] = TNode::null();
1178 [ + - ]: 1284 : Trace("qcf-check-unassign")
1179 : 642 : << "Succeeded match " << d_una_index << std::endl;
1180 : 642 : d_una_index++;
1181 : : }
1182 : : else
1183 : : {
1184 [ + - ]: 3878 : Trace("qcf-check-unassign")
1185 : 1939 : << "Failed match " << d_una_index << std::endl;
1186 : 1939 : invalidMatch = true;
1187 : : }
1188 : : }
1189 : : else
1190 : : {
1191 : 1332 : failed = true;
1192 [ + - ]: 2664 : Trace("qcf-check-unassign")
1193 : 1332 : << "No more matches " << d_una_index << std::endl;
1194 : : }
1195 : : }
1196 : : }
1197 [ + - ][ + + ]: 3993 : if (doFail || failed)
1198 : : {
1199 : : do
1200 : : {
1201 [ + - ]: 1332 : if (!doFail)
1202 : : {
1203 : 1332 : d_una_eqc_count.pop_back();
1204 : : }
1205 : : else
1206 : : {
1207 : 0 : doFail = false;
1208 : : }
1209 [ + + ]: 1332 : if (d_una_index == 0)
1210 : : {
1211 : 981 : success = false;
1212 : 981 : break;
1213 : : }
1214 : 351 : d_una_index--;
1215 [ - + ]: 351 : } while (d_una_eqc_count[d_una_index] == -1);
1216 : : }
1217 : : }
1218 : : }
1219 [ + + ]: 1215 : if (success)
1220 : : {
1221 : 234 : doFail = true;
1222 [ + - ]: 234 : Trace("qcf-check-unassign") << " Try: " << std::endl;
1223 [ - + ]: 234 : if (TraceIsOn("qcf-check"))
1224 : : {
1225 [ - - ]: 0 : for (int ui : d_unassigned)
1226 : : {
1227 [ - - ]: 0 : if (!d_match[ui].isNull())
1228 : : {
1229 [ - - ]: 0 : Trace("qcf-check-unassign")
1230 : 0 : << " Assigned #" << ui << " : " << d_vars[ui] << " -> "
1231 : 0 : << d_match[ui] << std::endl;
1232 : : }
1233 : : }
1234 : : }
1235 : : }
1236 [ + + ][ - + ]: 1215 : } while (success && isMatchSpurious());
[ - + ]
1237 [ + - ]: 1215 : Trace("qcf-check") << "done assigning." << std::endl;
1238 : : }
1239 [ + + ]: 1310 : if (success)
1240 : : {
1241 [ - + ]: 303 : if (TraceIsOn("qcf-check"))
1242 : : {
1243 [ - - ]: 0 : for (int ui : d_unassigned)
1244 : : {
1245 [ - - ]: 0 : if (!d_match[ui].isNull())
1246 : : {
1247 [ - - ]: 0 : Trace("qcf-check") << " Assigned #" << ui << " : " << d_vars[ui]
1248 : 0 : << " -> " << d_match[ui] << std::endl;
1249 : : }
1250 : : }
1251 : : }
1252 : 303 : return true;
1253 : : }
1254 : 1007 : revertMatch(assigned);
1255 : 1007 : assigned.clear();
1256 : 1007 : return false;
1257 : : }
1258 : :
1259 : 30580 : void QuantInfo::getMatch(std::vector<Node>& terms)
1260 : : {
1261 [ + + ]: 118186 : for (size_t i = 0, nvars = d_q[0].getNumChildren(); i < nvars; i++)
1262 : : {
1263 : 87606 : size_t repVar = getCurrentRepVar(i);
1264 : 87606 : Node cv;
1265 [ + + ]: 87606 : if (!d_match_term[repVar].isNull())
1266 : : {
1267 : 87209 : cv = d_match_term[repVar];
1268 : : }
1269 : : else
1270 : : {
1271 : 397 : cv = d_match[repVar];
1272 : : }
1273 [ + - ]: 175212 : Trace("qcf-check-inst") << "INST : " << i << " -> " << cv << ", from "
1274 : 87606 : << d_match[i] << std::endl;
1275 : 87606 : terms.push_back(cv);
1276 : 87606 : }
1277 : 30580 : }
1278 : :
1279 : 28557 : void QuantInfo::revertMatch(const std::vector<size_t>& assigned)
1280 : : {
1281 [ + + ]: 30200 : for (size_t a : assigned)
1282 : : {
1283 : 1643 : unsetMatch(a);
1284 : : }
1285 : 28557 : }
1286 : :
1287 : 0 : void QuantInfo::debugPrintMatch(CVC5_UNUSED const char* c) const
1288 : : {
1289 [ - - ]: 0 : for (size_t i = 0, nvars = getNumVars(); i < nvars; i++)
1290 : : {
1291 [ - - ]: 0 : Trace(c) << " " << d_vars[i] << " -> ";
1292 [ - - ]: 0 : if (!d_match[i].isNull())
1293 : : {
1294 [ - - ]: 0 : Trace(c) << d_match[i];
1295 : : }
1296 : : else
1297 : : {
1298 [ - - ]: 0 : Trace(c) << "(unassigned) ";
1299 : : }
1300 : : std::map<size_t, std::map<TNode, size_t>>::const_iterator itc =
1301 : 0 : d_curr_var_deq.find(i);
1302 [ - - ]: 0 : if (!itc->second.empty())
1303 : : {
1304 [ - - ]: 0 : Trace(c) << ", DEQ{ ";
1305 [ - - ]: 0 : for (const std::pair<const TNode, size_t>& d : itc->second)
1306 : : {
1307 [ - - ]: 0 : Trace(c) << d.first << " ";
1308 : : }
1309 [ - - ]: 0 : Trace(c) << "}";
1310 : : }
1311 : 0 : if (!d_match_term[i].isNull() && d_match_term[i] != d_match[i])
1312 : : {
1313 [ - - ]: 0 : Trace(c) << ", EXP : " << d_match_term[i];
1314 : : }
1315 [ - - ]: 0 : Trace(c) << std::endl;
1316 : : }
1317 [ - - ]: 0 : if (!d_tconstraints.empty())
1318 : : {
1319 [ - - ]: 0 : Trace(c) << "ADDITIONAL CONSTRAINTS : " << std::endl;
1320 [ - - ]: 0 : for (const std::pair<const Node, bool>& tc : d_tconstraints)
1321 : : {
1322 [ - - ]: 0 : Trace(c) << " " << tc.first << " -> " << tc.second << std::endl;
1323 : : }
1324 : : }
1325 : 0 : }
1326 : :
1327 : 331561 : MatchGen::MatchGen(
1328 : 331561 : Env& env, QuantConflictFind* p, QuantInfo* qi, Node n, bool isVar)
1329 : : : EnvObj(env),
1330 : 331561 : d_tgt(),
1331 : 331561 : d_tgt_orig(),
1332 : 331561 : d_wasSet(),
1333 : 331561 : d_n(),
1334 : 331561 : d_type(),
1335 : 331561 : d_type_not(),
1336 : 331561 : d_parent(p),
1337 : 331561 : d_qi(qi),
1338 : 331561 : d_matched_basis(),
1339 : 331561 : d_binding()
1340 : : {
1341 : : // initialize temporary
1342 : 331561 : d_child_counter = -1;
1343 : 331561 : d_use_children = true;
1344 : :
1345 [ + - ]: 663122 : Trace("qcf-qregister-debug")
1346 : 331561 : << "Make match gen for " << n << ", isVar = " << isVar << std::endl;
1347 : 331561 : std::vector<Node> qni_apps;
1348 : 331561 : d_qni_size = 0;
1349 [ + + ]: 331561 : if (isVar)
1350 : : {
1351 [ - + ][ - + ]: 164856 : Assert(qi->d_var_num.find(n) != qi->d_var_num.end());
[ - - ]
1352 : : // rare case where we have a free variable in an operator, we are invalid
1353 : 494568 : if (n.getKind() == Kind::ITE
1354 : 164856 : || (n.getKind() == Kind::APPLY_UF && expr::hasFreeVar(n.getOperator())))
1355 : : {
1356 : 3887 : d_type = typ_invalid;
1357 : : }
1358 : : else
1359 : : {
1360 [ + + ]: 160969 : d_type = isHandledUfTerm(n) ? typ_var : typ_tsym;
1361 : 160969 : int vn = qi->getVarNum(n);
1362 [ - + ][ - + ]: 160969 : Assert(vn >= 0);
[ - - ]
1363 : 160969 : d_qni_var_num[0] = static_cast<size_t>(vn);
1364 : 160969 : d_qni_size++;
1365 : 160969 : d_type_not = false;
1366 : 160969 : d_n = n;
1367 : : // Node f = getMatchOperator( n );
1368 [ + + ]: 503452 : for (unsigned j = 0; j < d_n.getNumChildren(); j++)
1369 : : {
1370 : 342483 : Node nn = d_n[j];
1371 [ + - ]: 342483 : Trace("qcf-qregister-debug") << " " << d_qni_size;
1372 [ + + ]: 342483 : if (qi->isVar(nn))
1373 : : {
1374 : 293305 : size_t v = qi->d_var_num[nn];
1375 [ + - ]: 293305 : Trace("qcf-qregister-debug") << " is var #" << v << std::endl;
1376 : 293305 : d_qni_var_num[d_qni_size] = v;
1377 : : // qi->addFuncParent( v, f, j );
1378 : : }
1379 : : else
1380 : : {
1381 [ + - ]: 49178 : Trace("qcf-qregister-debug") << " is gterm " << nn << std::endl;
1382 : 49178 : d_qni_gterm[d_qni_size] = nn;
1383 : : }
1384 : 342483 : d_qni_size++;
1385 : 342483 : }
1386 : : }
1387 : : }
1388 : : else
1389 : : {
1390 [ + + ]: 166705 : if (expr::hasBoundVar(n))
1391 : : {
1392 : 166448 : d_type_not = false;
1393 : 166448 : d_n = n;
1394 [ + + ]: 166448 : if (d_n.getKind() == Kind::NOT)
1395 : : {
1396 : 52921 : d_n = d_n[0];
1397 : 52921 : d_type_not = !d_type_not;
1398 : : }
1399 : :
1400 [ + + ]: 166448 : if (isHandledBoolConnective(d_n))
1401 : : {
1402 : : // non-literals
1403 : 57165 : d_type = typ_formula;
1404 [ + + ]: 179942 : for (unsigned i = 0; i < d_n.getNumChildren(); i++)
1405 : : {
1406 [ + + ][ + + ]: 130325 : if (d_n.getKind() != Kind::FORALL || i == 1)
[ + + ]
1407 : : {
1408 : : std::unique_ptr<MatchGen> mg =
1409 : 119164 : std::make_unique<MatchGen>(d_env, p, qi, d_n[i], false);
1410 [ + + ]: 119164 : if (!mg->isValid())
1411 : : {
1412 : 7548 : setInvalid();
1413 : 7548 : break;
1414 : : }
1415 : 111616 : d_children.push_back(std::move(mg));
1416 [ + + ]: 119164 : }
1417 : : }
1418 : : }
1419 : : else
1420 : : {
1421 : 109283 : d_type = typ_invalid;
1422 : : // literals
1423 [ + + ]: 109283 : if (isHandledUfTerm(d_n))
1424 : : {
1425 [ - + ][ - + ]: 42086 : Assert(qi->isVar(d_n));
[ - - ]
1426 : 42086 : d_type = typ_pred;
1427 : : }
1428 [ + + ]: 67197 : else if (d_n.getKind() == Kind::BOUND_VARIABLE)
1429 : : {
1430 [ - + ][ - + ]: 344 : Assert(d_n.getType().isBoolean());
[ - - ]
1431 : 344 : d_type = typ_bool_var;
1432 : : }
1433 : 66853 : else if (d_n.getKind() == Kind::EQUAL
1434 [ + + ][ + + ]: 66853 : || options().quantifiers.cbqiTConstraint)
[ + + ]
1435 : : {
1436 [ + + ]: 182787 : for (unsigned i = 0; i < d_n.getNumChildren(); i++)
1437 : : {
1438 [ + + ]: 121858 : if (expr::hasBoundVar(d_n[i]))
1439 : : {
1440 [ - + ]: 92124 : if (!qi->isVar(d_n[i]))
1441 : : {
1442 [ - - ]: 0 : Trace("qcf-qregister-debug")
1443 : 0 : << "ERROR : not var " << d_n[i] << std::endl;
1444 : : }
1445 [ - + ][ - + ]: 92124 : Assert(qi->isVar(d_n[i]));
[ - - ]
1446 : 92124 : if (d_n.getKind() != Kind::EQUAL && qi->isVar(d_n[i]))
1447 : : {
1448 : 648 : d_qni_var_num[i + 1] = qi->d_var_num[d_n[i]];
1449 : : }
1450 : : }
1451 : : else
1452 : : {
1453 : 29734 : d_qni_gterm[i] = d_n[i];
1454 : : }
1455 : : }
1456 [ + + ]: 60929 : d_type = d_n.getKind() == Kind::EQUAL ? typ_eq : typ_tconstraint;
1457 [ + - ]: 60929 : Trace("qcf-tconstraint") << "T-Constraint : " << d_n << std::endl;
1458 : : }
1459 : : }
1460 : : }
1461 : : else
1462 : : {
1463 : : // we will just evaluate
1464 : 257 : d_n = n;
1465 : 257 : d_type = typ_ground;
1466 : : }
1467 : : }
1468 [ + - ]: 331561 : Trace("qcf-qregister-debug") << "Done make match gen " << n << ", type = ";
1469 : 331561 : debugPrintType("qcf-qregister-debug", d_type);
1470 [ + - ]: 331561 : Trace("qcf-qregister-debug") << std::endl;
1471 : 331561 : }
1472 : :
1473 : 943438 : void MatchGen::collectBoundVar(Node n,
1474 : : std::vector<int>& cbvars,
1475 : : std::map<Node, bool>& visited,
1476 : : bool& hasNested)
1477 : : {
1478 [ + + ]: 943438 : if (visited.find(n) == visited.end())
1479 : : {
1480 : 814137 : visited[n] = true;
1481 [ + + ]: 814137 : if (n.getKind() == Kind::FORALL)
1482 : : {
1483 : 7790 : hasNested = true;
1484 : : }
1485 : 814137 : int v = d_qi->getVarNum(n);
1486 [ + + ][ + - ]: 814137 : if (v != -1 && std::find(cbvars.begin(), cbvars.end(), v) == cbvars.end())
[ + + ]
1487 : : {
1488 : 518746 : cbvars.push_back(v);
1489 : : }
1490 [ + + ]: 1663307 : for (const Node& nc : n)
1491 : : {
1492 : 849170 : collectBoundVar(nc, cbvars, visited, hasNested);
1493 : 849170 : }
1494 : : }
1495 : 943438 : }
1496 : :
1497 : 291919 : void MatchGen::determineVariableOrder(std::vector<size_t>& bvars)
1498 : : {
1499 [ + - ]: 583838 : Trace("qcf-qregister-debug") << "Determine variable order " << d_n
1500 : 291919 : << ", #bvars = " << bvars.size() << std::endl;
1501 : 291919 : bool isComm = d_type == typ_formula
1502 [ + + ][ + + ]: 307852 : && (d_n.getKind() == Kind::OR || d_n.getKind() == Kind::AND
[ + + ]
1503 [ + + ]: 15933 : || d_n.getKind() == Kind::EQUAL);
1504 [ + + ]: 291919 : if (isComm)
1505 : : {
1506 : 34230 : std::map<int, std::vector<int>> c_to_vars;
1507 : 34230 : std::map<int, std::vector<int>> vars_to_c;
1508 : 34230 : std::map<int, int> vb_count;
1509 : 34230 : std::map<int, int> vu_count;
1510 : 34230 : std::map<int, bool> has_nested;
1511 : 34230 : std::vector<bool> assigned;
1512 [ + - ]: 34230 : Trace("qcf-qregister-debug") << "Calculate bound variables..." << std::endl;
1513 [ + + ]: 119473 : for (size_t i = 0, nchild = d_children.size(); i < nchild; i++)
1514 : : {
1515 : 85243 : std::map<Node, bool> visited;
1516 : 85243 : has_nested[i] = false;
1517 : 85243 : collectBoundVar(
1518 : 170486 : d_children[i]->getNode(), c_to_vars[i], visited, has_nested[i]);
1519 : 85243 : assigned.push_back(false);
1520 : 85243 : vb_count[i] = 0;
1521 : 85243 : vu_count[i] = 0;
1522 [ + + ]: 500497 : for (unsigned j = 0; j < c_to_vars[i].size(); j++)
1523 : : {
1524 : 415254 : int v = c_to_vars[i][j];
1525 : 415254 : vars_to_c[v].push_back(i);
1526 [ + + ]: 415254 : if (std::find(bvars.begin(), bvars.end(), v) == bvars.end())
1527 : : {
1528 : 377114 : vu_count[i]++;
1529 : : }
1530 : : else
1531 : : {
1532 : 38140 : vb_count[i]++;
1533 : : }
1534 : : }
1535 : 85243 : }
1536 : : // children that bind no unbound variable, then the most number of bound,
1537 : : // unbound variables go first
1538 [ + - ]: 68460 : Trace("qcf-qregister-vo")
1539 : 34230 : << "Variable order for " << d_n << " : " << std::endl;
1540 : 34230 : size_t nqvars = d_qi->d_vars.size();
1541 : : do
1542 : : {
1543 : 85243 : int min_score0 = -1;
1544 : 85243 : int min_score = -1;
1545 : 85243 : int min_score_index = -1;
1546 [ + + ]: 1228658 : for (size_t i = 0, nchild = d_children.size(); i < nchild; i++)
1547 : : {
1548 [ + + ]: 1143415 : if (!assigned[i])
1549 : : {
1550 [ + - ]: 1228658 : Trace("qcf-qregister-debug2")
1551 : 0 : << "Child " << i << " has b/ub : " << vb_count[i] << "/"
1552 : 614329 : << vu_count[i] << std::endl;
1553 : 614329 : int score0 = 0; // has_nested[i] ? 0 : 1;
1554 : : int score;
1555 [ + - ]: 614329 : if (!options().quantifiers.cbqiVoExp)
1556 : : {
1557 : 614329 : score = vu_count[i];
1558 : : }
1559 : : else
1560 : : {
1561 [ - - ]: 0 : score = vu_count[i] == 0 ? 0
1562 : 0 : : (1 + nqvars * (nqvars - vb_count[i])
1563 : 0 : + (nqvars - vu_count[i]));
1564 : : }
1565 [ + + ][ + - ]: 614329 : if (min_score == -1 || score0 < min_score0
1566 [ + - ][ + + ]: 529086 : || (score0 == min_score0 && score < min_score))
1567 : : {
1568 : 139769 : min_score0 = score0;
1569 : 139769 : min_score = score;
1570 : 139769 : min_score_index = i;
1571 : : }
1572 : : }
1573 : : }
1574 [ + - ]: 170486 : Trace("qcf-qregister-vo")
1575 : 0 : << " " << d_children_order.size() + 1 << ": "
1576 [ - + ][ - - ]: 85243 : << d_children[min_score_index]->getNode() << " : ";
1577 [ + - ]: 170486 : Trace("qcf-qregister-vo")
1578 : 0 : << vu_count[min_score_index] << " " << vb_count[min_score_index]
1579 : 85243 : << " " << has_nested[min_score_index] << std::endl;
1580 [ + - ]: 170486 : Trace("qcf-qregister-debug")
1581 : 85243 : << "...assign child " << min_score_index << std::endl;
1582 [ + - ]: 85243 : Trace("qcf-qregister-debug") << "...score : " << min_score << std::endl;
1583 [ - + ][ - + ]: 85243 : Assert(min_score_index != -1);
[ - - ]
1584 : : // add to children order
1585 : 85243 : d_children_order.push_back(min_score_index);
1586 : 85243 : assigned[min_score_index] = true;
1587 : : // determine order internal to children
1588 : 85243 : d_children[min_score_index]->determineVariableOrder(bvars);
1589 [ + - ]: 85243 : Trace("qcf-qregister-debug") << "...bind variables" << std::endl;
1590 : : // now, make it a bound variable
1591 [ + + ]: 85243 : if (vu_count[min_score_index] > 0)
1592 : : {
1593 [ + + ]: 467098 : for (unsigned i = 0; i < c_to_vars[min_score_index].size(); i++)
1594 : : {
1595 : 386596 : int v = c_to_vars[min_score_index][i];
1596 [ + + ]: 386596 : if (std::find(bvars.begin(), bvars.end(), v) == bvars.end())
1597 : : {
1598 [ + + ]: 483726 : for (unsigned j = 0; j < vars_to_c[v].size(); j++)
1599 : : {
1600 : 310653 : int vc = vars_to_c[v][j];
1601 : 310653 : vu_count[vc]--;
1602 : 310653 : vb_count[vc]++;
1603 : : }
1604 : 173073 : bvars.push_back(v);
1605 : : }
1606 : : }
1607 : : }
1608 [ + - ]: 170486 : Trace("qcf-qregister-debug")
1609 : 85243 : << "...done assign child " << min_score_index << std::endl;
1610 [ + + ]: 85243 : } while (d_children_order.size() != d_children.size());
1611 [ + - ]: 68460 : Trace("qcf-qregister-debug")
1612 : 34230 : << "Done assign variable ordering for " << d_n << std::endl;
1613 : 34230 : }
1614 : : else
1615 : : {
1616 [ + + ]: 266714 : for (size_t i = 0, nchild = d_children.size(); i < nchild; i++)
1617 : : {
1618 : 9025 : d_children_order.push_back(i);
1619 : 9025 : d_children[i]->determineVariableOrder(bvars);
1620 : : // now add to bvars
1621 : 9025 : std::map<Node, bool> visited;
1622 : 9025 : std::vector<int> cvars;
1623 : 9025 : bool has_nested = false;
1624 : 9025 : collectBoundVar(d_children[i]->getNode(), cvars, visited, has_nested);
1625 [ + + ]: 112517 : for (unsigned j = 0; j < cvars.size(); j++)
1626 : : {
1627 [ + + ]: 103492 : if (std::find(bvars.begin(), bvars.end(), cvars[j]) == bvars.end())
1628 : : {
1629 : 13713 : bvars.push_back(cvars[j]);
1630 : : }
1631 : : }
1632 : 9025 : }
1633 : : }
1634 : 291919 : }
1635 : :
1636 : 2291094 : bool MatchGen::reset_round()
1637 : : {
1638 : 2291094 : d_wasSet = false;
1639 [ + + ]: 3182409 : for (std::unique_ptr<MatchGen>& mg : d_children)
1640 : : {
1641 [ - + ]: 891315 : if (!mg->reset_round())
1642 : : {
1643 : 0 : return false;
1644 : : }
1645 : : }
1646 [ + + ]: 2291094 : if (d_type == typ_ground)
1647 : : {
1648 : 2283 : EntailmentCheck* echeck = d_parent->getTermRegistry().getEntailmentCheck();
1649 : 2283 : QuantifiersState& qs = d_parent->getState();
1650 [ + + ]: 6849 : for (unsigned i = 0; i < 2; i++)
1651 : : {
1652 [ + + ]: 4566 : if (echeck->isEntailed(d_n, i == 0))
1653 : : {
1654 : 48 : d_ground_eval[0] = nodeManager()->mkConst(i == 0);
1655 : : }
1656 [ - + ]: 4566 : if (qs.isInConflict())
1657 : : {
1658 : 0 : return false;
1659 : : }
1660 : : }
1661 : : }
1662 [ + + ]: 2288811 : else if (d_type == typ_eq)
1663 : : {
1664 : 374791 : EntailmentCheck* echeck = d_parent->getTermRegistry().getEntailmentCheck();
1665 : 374791 : QuantifiersState& qs = d_parent->getState();
1666 [ + + ]: 1124373 : for (unsigned i = 0, size = d_n.getNumChildren(); i < size; i++)
1667 : : {
1668 [ + + ]: 749582 : if (!expr::hasBoundVar(d_n[i]))
1669 : : {
1670 : 410108 : TNode t = echeck->getEntailedTerm(d_n[i]);
1671 [ - + ]: 205054 : if (qs.isInConflict())
1672 : : {
1673 : 0 : return false;
1674 : : }
1675 [ + + ]: 205054 : if (t.isNull())
1676 : : {
1677 : 2995 : d_ground_eval[i] = d_n[i];
1678 : : }
1679 : : else
1680 : : {
1681 : 202059 : d_ground_eval[i] = t;
1682 : : }
1683 [ + - ]: 205054 : }
1684 : : }
1685 : : }
1686 : 2291094 : d_qni_bound_cons.clear();
1687 : 2291094 : d_qni_bound_cons_var.clear();
1688 : 2291094 : d_qni_bound.clear();
1689 : 2291094 : return true;
1690 : : }
1691 : :
1692 : 4213665 : void MatchGen::reset(bool tgt)
1693 : : {
1694 [ + + ]: 4213665 : d_tgt = d_type_not ? !tgt : tgt;
1695 [ + - ]: 4213665 : Trace("qcf-match") << " Reset for : " << d_n << ", type : ";
1696 : 4213665 : debugPrintType("qcf-match", d_type);
1697 [ + - ]: 8427330 : Trace("qcf-match") << ", tgt = " << d_tgt
1698 : 0 : << ", children = " << d_children.size() << " "
1699 : 4213665 : << d_children_order.size() << std::endl;
1700 : 4213665 : d_qn.clear();
1701 : 4213665 : d_qni.clear();
1702 : 4213665 : d_qni_bound.clear();
1703 : 4213665 : d_child_counter = -1;
1704 : 4213665 : d_use_children = true;
1705 : 4213665 : d_tgt_orig = d_tgt;
1706 : :
1707 : : // set up processing matches
1708 [ - + ]: 4213665 : if (d_type == typ_invalid)
1709 : : {
1710 : 0 : d_use_children = false;
1711 : : }
1712 [ + + ]: 4213665 : else if (d_type == typ_ground)
1713 : : {
1714 : 913 : d_use_children = false;
1715 : 913 : if (d_ground_eval[0].isConst()
1716 [ + + ][ + + ]: 913 : && d_ground_eval[0].getConst<bool>() == d_tgt)
[ + + ]
1717 : : {
1718 : 62 : d_child_counter = 0;
1719 : : }
1720 : : }
1721 [ + + ]: 4212752 : else if (d_qi->isBaseMatchComplete())
1722 : : {
1723 : 27636 : d_use_children = false;
1724 : 27636 : d_child_counter = 0;
1725 : : }
1726 [ + + ]: 4185116 : else if (d_type == typ_bool_var)
1727 : : {
1728 : : // get current value of the variable
1729 : 2645 : TNode n = d_qi->getCurrentValue(d_n);
1730 : 2645 : int vnn = d_qi->getVarNum(n);
1731 [ - + ]: 2645 : if (vnn == -1)
1732 : : {
1733 : : // evaluate the value, see if it is compatible
1734 : : EntailmentCheck* echeck =
1735 : 0 : d_parent->getTermRegistry().getEntailmentCheck();
1736 [ - - ]: 0 : if (echeck->isEntailed(n, d_tgt))
1737 : : {
1738 : 0 : d_child_counter = 0;
1739 : : }
1740 : : }
1741 : : else
1742 : : {
1743 : 2645 : size_t vn = d_qi->getCurrentRepVar(static_cast<size_t>(vnn));
1744 : : // unassigned, set match to true/false
1745 : 2645 : d_qni_bound[0] = vn;
1746 : 2645 : d_qi->setMatch(vn, nodeManager()->mkConst(d_tgt), false, true);
1747 : 2645 : d_child_counter = 0;
1748 : : }
1749 [ + - ]: 2645 : if (d_child_counter == 0)
1750 : : {
1751 : 2645 : d_qn.push_back(nullptr);
1752 : : }
1753 : 2645 : }
1754 [ + + ]: 4182471 : else if (d_type == typ_var)
1755 : : {
1756 [ - + ][ - + ]: 3151036 : Assert(isHandledUfTerm(d_n));
[ - - ]
1757 : 6302072 : TNode f = d_parent->getTermDatabase()->getMatchOperator(d_n);
1758 [ + - ]: 6302072 : Trace("qcf-match-debug")
1759 : 3151036 : << " reset: Var will match operators of " << f << std::endl;
1760 : : TNodeTrie* qni =
1761 : 3151036 : d_parent->getTermDatabase()->getTermArgTrie(Node::null(), f);
1762 [ + - ][ + + ]: 3151036 : if (qni == nullptr || qni->empty())
[ + + ]
1763 : : {
1764 : : // inform irrelevant quantifiers
1765 : 266356 : d_parent->setIrrelevantFunction(f);
1766 : : }
1767 : : else
1768 : : {
1769 : 2884680 : d_qn.push_back(qni);
1770 : : }
1771 : 3151036 : d_matched_basis = false;
1772 : 3151036 : }
1773 [ + + ][ + + ]: 1031435 : else if (d_type == typ_tsym || d_type == typ_tconstraint)
1774 : : {
1775 [ + + ]: 7060 : for (std::pair<const size_t, size_t>& qvn : d_qni_var_num)
1776 : : {
1777 : 4239 : size_t repVar = d_qi->getCurrentRepVar(qvn.second);
1778 [ + + ]: 4239 : if (d_qi->d_match[repVar].isNull())
1779 : : {
1780 [ + - ]: 8118 : Trace("qcf-match-debug") << "Force matching on child #" << qvn.first
1781 : 4059 : << ", which is var #" << repVar << std::endl;
1782 : 4059 : d_qni_bound[qvn.first] = repVar;
1783 : : }
1784 : : }
1785 : 2821 : d_qn.push_back(nullptr);
1786 : 2821 : }
1787 [ + + ][ + + ]: 1028614 : else if (d_type == typ_pred || d_type == typ_eq)
1788 : : {
1789 : : // add initial constraint
1790 [ + + ]: 4393326 : Node nn[2];
1791 : : int vn[2];
1792 [ + + ]: 732221 : if (d_type == typ_pred)
1793 : : {
1794 : 343177 : nn[0] = d_qi->getCurrentValue(d_n);
1795 : 343177 : int vnn = d_qi->getVarNum(nn[0]);
1796 [ + + ]: 343177 : vn[0] =
1797 : 342625 : vnn == -1 ? vnn : d_qi->getCurrentRepVar(static_cast<size_t>(vnn));
1798 : 343177 : nn[1] = nodeManager()->mkConst(d_tgt);
1799 : 343177 : vn[1] = -1;
1800 : 343177 : d_tgt = true;
1801 : : }
1802 : : else
1803 : : {
1804 [ + + ]: 1167132 : for (unsigned i = 0; i < 2; i++)
1805 : : {
1806 : 778088 : TNode nc;
1807 : 778088 : std::map<size_t, TNode>::iterator it = d_qni_gterm.find(i);
1808 [ + + ]: 778088 : if (it != d_qni_gterm.end())
1809 : : {
1810 : 243286 : nc = it->second;
1811 : : }
1812 : : else
1813 : : {
1814 : 534802 : nc = d_n[i];
1815 : : }
1816 : 778088 : nn[i] = d_qi->getCurrentValue(nc);
1817 : 778088 : int vnn = d_qi->getVarNum(nn[i]);
1818 [ + + ]: 778088 : vn[i] =
1819 : 524928 : vnn == -1 ? vnn : d_qi->getCurrentRepVar(static_cast<size_t>(vnn));
1820 : 778088 : }
1821 : : }
1822 : : bool success;
1823 [ + + ][ + + ]: 732221 : if (vn[0] == -1 && vn[1] == -1)
1824 : : {
1825 : : // Trace("qcf-explain") << " reset : " << d_n << " check ground values
1826 : : // " << nn[0] << " " << nn[1] << " (tgt=" << d_tgt << ")" << std::endl;
1827 [ + - ]: 1564 : Trace("qcf-match-debug")
1828 : 0 : << " reset: check ground values " << nn[0] << " " << nn[1]
1829 : 782 : << " (" << d_tgt << ")" << std::endl;
1830 : : // just compare values
1831 [ + + ]: 782 : if (d_tgt)
1832 : : {
1833 : 710 : success = nn[0] == nn[1];
1834 : : }
1835 : : else
1836 : : {
1837 [ + + ]: 72 : if (d_parent->atConflictEffort())
1838 : : {
1839 : 24 : success = d_parent->areDisequal(nn[0], nn[1]);
1840 : : }
1841 : : else
1842 : : {
1843 : 48 : success = (nn[0] != nn[1]);
1844 : : }
1845 : : }
1846 : : }
1847 : : else
1848 : : {
1849 : : // otherwise, add a constraint to a variable TODO: this may be over-eager
1850 : : // at effort > conflict, since equality may be a propagation
1851 [ + + ][ + + ]: 731439 : if (vn[1] != -1 && vn[0] == -1)
1852 : : {
1853 : : // swap
1854 : 103323 : Node t = nn[1];
1855 : 103323 : nn[1] = nn[0];
1856 : 103323 : nn[0] = t;
1857 : 103323 : vn[0] = vn[1];
1858 : 103323 : vn[1] = -1;
1859 : 103323 : }
1860 [ + - ]: 1462878 : Trace("qcf-match-debug")
1861 : 0 : << " reset: add constraint " << vn[0] << " -> " << nn[1]
1862 : 731439 : << " (vn=" << vn[1] << ")" << std::endl;
1863 : : // add some constraint
1864 : 731439 : int addc = d_qi->addConstraint(vn[0], nn[1], vn[1], d_tgt, false);
1865 : 731439 : success = addc != -1;
1866 : : // if successful and non-redundant, store that we need to cleanup this
1867 [ + + ]: 731439 : if (addc == 1)
1868 : : {
1869 [ + + ]: 2116740 : for (size_t i = 0; i < 2; i++)
1870 : : {
1871 : 2822320 : if (vn[i] != -1
1872 [ + + ][ + - ]: 3094548 : && std::find(
1873 : : d_qni_bound_except.begin(), d_qni_bound_except.end(), i)
1874 [ + + ]: 3094548 : == d_qni_bound_except.end())
1875 : : {
1876 : 841694 : d_qni_bound[vn[i]] = vn[i];
1877 : : }
1878 : : }
1879 : 705580 : d_qni_bound_cons[vn[0]] = nn[1];
1880 : 705580 : d_qni_bound_cons_var[vn[0]] = vn[1];
1881 : : }
1882 : : }
1883 : : // if successful, we will bind values to variables
1884 [ + + ]: 732221 : if (success)
1885 : : {
1886 : 706263 : d_qn.push_back(nullptr);
1887 : : }
1888 [ + + ][ - - ]: 2928884 : }
1889 : : else
1890 : : {
1891 [ - + ]: 296393 : if (d_children.empty())
1892 : : {
1893 : : // add dummy
1894 : 0 : d_qn.push_back(nullptr);
1895 : : }
1896 : : else
1897 : : {
1898 [ + + ][ + + ]: 296393 : if (d_tgt && d_n.getKind() == Kind::FORALL)
[ + + ]
1899 : : {
1900 : : // fail
1901 : : }
1902 [ + + ][ + + ]: 263156 : else if (d_n.getKind() == Kind::FORALL && d_parent->atConflictEffort())
[ + + ]
1903 : : {
1904 : : // fail
1905 : : }
1906 : : else
1907 : : {
1908 : : // reset the first child to d_tgt
1909 : 261631 : d_child_counter = 0;
1910 : 261631 : getChild(d_child_counter)->reset(d_tgt);
1911 : : }
1912 : : }
1913 : : }
1914 : 4213665 : d_binding = false;
1915 : 4213665 : d_wasSet = true;
1916 [ + - ]: 8427330 : Trace("qcf-match") << " reset: Finished reset for " << d_n
1917 : 0 : << ", success = "
1918 [ - - ][ - - ]: 4213665 : << (!d_qn.empty() || d_child_counter != -1) << std::endl;
1919 : 8065571 : }
1920 : :
1921 : 5091817 : bool MatchGen::getNextMatch()
1922 : : {
1923 [ + - ]: 5091817 : Trace("qcf-match") << " Get next match for : " << d_n << ", type = ";
1924 : 5091817 : debugPrintType("qcf-match", d_type);
1925 [ + - ]: 10183634 : Trace("qcf-match") << ", children = " << d_children.size()
1926 : 5091817 : << ", binding = " << d_binding << std::endl;
1927 [ + + ]: 5091817 : if (!d_use_children)
1928 : : {
1929 [ + + ]: 54734 : if (d_child_counter == 0)
1930 : : {
1931 : 27698 : d_child_counter = -1;
1932 : 27698 : return true;
1933 : : }
1934 : : else
1935 : : {
1936 : 27036 : d_wasSet = false;
1937 : 27036 : return false;
1938 : : }
1939 : : }
1940 [ + + ][ + + ]: 5037083 : else if (d_type == typ_var || d_type == typ_eq || d_type == typ_pred
[ + + ]
1941 [ + + ][ + + ]: 336840 : || d_type == typ_bool_var || d_type == typ_tconstraint
1942 [ + + ]: 328537 : || d_type == typ_tsym)
1943 : : {
1944 : 4709655 : bool success = false;
1945 : 4709655 : bool terminate = false;
1946 : : do
1947 : : {
1948 : 8250237 : bool doReset = false;
1949 : 8250237 : bool doFail = false;
1950 [ + + ]: 8250237 : if (!d_binding)
1951 : : {
1952 [ + + ]: 7437376 : if (doMatching())
1953 : : {
1954 [ + - ]: 3561804 : Trace("qcf-match-debug") << " - Matching succeeded" << std::endl;
1955 : 3561804 : d_binding = true;
1956 : 3561804 : d_binding_it = d_qni_bound.begin();
1957 : 3561804 : doReset = true;
1958 : : // for tconstraint, add constraint
1959 [ + + ]: 3561804 : if (d_type == typ_tconstraint)
1960 : : {
1961 : 1868 : std::map<Node, bool>::iterator it = d_qi->d_tconstraints.find(d_n);
1962 [ + - ]: 1868 : if (it == d_qi->d_tconstraints.end())
1963 : : {
1964 : 1868 : d_qi->d_tconstraints[d_n] = d_tgt;
1965 : : // store that we added this constraint
1966 : 1868 : d_qni_bound_cons[0] = d_n;
1967 : : }
1968 [ - - ]: 0 : else if (d_tgt != it->second)
1969 : : {
1970 : 0 : success = false;
1971 : 0 : terminate = true;
1972 : : }
1973 : : }
1974 : : }
1975 : : else
1976 : : {
1977 [ + - ]: 3875572 : Trace("qcf-match-debug") << " - Matching failed" << std::endl;
1978 : 3875572 : success = false;
1979 : 3875572 : terminate = true;
1980 : : }
1981 : : }
1982 : : else
1983 : : {
1984 : 812861 : doFail = true;
1985 : : }
1986 [ + + ]: 8250237 : if (d_binding)
1987 : : {
1988 : : // also need to create match for each variable we bound
1989 : 4374665 : success = true;
1990 [ + - ]: 8749330 : Trace("qcf-match-debug")
1991 : 0 : << " Produce matches for bound variables by " << d_n
1992 : 4374665 : << ", type = ";
1993 : 4374665 : debugPrintType("qcf-match-debug", d_type);
1994 [ + - ]: 4374665 : Trace("qcf-match-debug") << "..." << std::endl;
1995 : :
1996 [ + + ][ + + ]: 11871945 : while ((success && d_binding_it != d_qni_bound.end()) || doFail)
[ + + ][ + + ]
1997 : : {
1998 : 7497280 : QuantInfo::VarMgMap::const_iterator itm;
1999 [ + + ]: 7497280 : if (!doFail)
2000 : : {
2001 [ + - ]: 13368838 : Trace("qcf-match-debug") << " check variable "
2002 : 6684419 : << d_binding_it->second << std::endl;
2003 : 6684419 : itm = d_qi->var_mg_find(d_binding_it->second);
2004 : : }
2005 [ + + ][ + + ]: 7497280 : if (doFail || (d_binding_it->first != 0 && itm != d_qi->var_mg_end()))
[ + + ][ + + ]
2006 : : {
2007 [ + - ]: 8865570 : Trace("qcf-match-debug")
2008 : 0 : << " we had bound variable " << d_binding_it->second
2009 : 4432785 : << ", reset = " << doReset << std::endl;
2010 [ + + ]: 4432785 : if (doReset)
2011 : : {
2012 : 3177543 : itm->second->reset(true);
2013 : : }
2014 [ + + ][ + + ]: 4432785 : if (doFail || !itm->second->getNextMatch())
[ + + ]
2015 : : {
2016 : : do
2017 : : {
2018 [ + + ]: 7036831 : if (d_binding_it == d_qni_bound.begin())
2019 : : {
2020 [ + - ]: 3540582 : Trace("qcf-match-debug") << " failed." << std::endl;
2021 : 3540582 : success = false;
2022 : : }
2023 : : else
2024 : : {
2025 : 3496249 : --d_binding_it;
2026 [ + - ]: 6992498 : Trace("qcf-match-debug")
2027 : 3496249 : << " decrement..." << std::endl;
2028 : : }
2029 : : } while (success
2030 [ + + ][ + + ]: 8259672 : && (d_binding_it->first == 0
[ + + ]
2031 [ + + ]: 1222841 : || (!d_qi->containsVarMg(d_binding_it->second))));
2032 : 3982963 : doReset = false;
2033 : 3982963 : doFail = false;
2034 : : }
2035 : : else
2036 : : {
2037 [ + - ]: 449822 : Trace("qcf-match-debug") << " increment..." << std::endl;
2038 : 449822 : ++d_binding_it;
2039 : 449822 : doReset = true;
2040 : : }
2041 : : }
2042 : : else
2043 : : {
2044 [ + - ]: 6128990 : Trace("qcf-match-debug")
2045 : 3064495 : << " skip..." << d_binding_it->second << std::endl;
2046 : 3064495 : ++d_binding_it;
2047 : 3064495 : doReset = true;
2048 : : }
2049 : : }
2050 [ + + ]: 4374665 : if (!success)
2051 : : {
2052 : 3540582 : d_binding = false;
2053 : : }
2054 : : else
2055 : : {
2056 : 834083 : terminate = true;
2057 [ + + ]: 834083 : if (d_binding_it == d_qni_bound.begin())
2058 : : {
2059 : 8249 : d_binding = false;
2060 : : }
2061 : : }
2062 : : }
2063 [ + + ]: 8250237 : } while (!terminate);
2064 : : // if not successful, clean up the variables you bound
2065 [ + + ]: 4709655 : if (!success)
2066 : : {
2067 [ + + ][ + + ]: 3875572 : if (d_type == typ_eq || d_type == typ_pred)
2068 : : {
2069 : : // clean up the constraints you added
2070 : 726125 : std::map<size_t, size_t>::iterator itb;
2071 [ + + ]: 1425632 : for (const std::pair<const size_t, TNode>& qb : d_qni_bound_cons)
2072 : : {
2073 [ + - ]: 699507 : if (!qb.second.isNull())
2074 : : {
2075 [ + - ]: 1399014 : Trace("qcf-match")
2076 : 0 : << " Clean up bound var " << qb.first
2077 [ - - ]: 699507 : << (d_tgt ? "!" : "") << " = " << qb.second << std::endl;
2078 : 699507 : itb = d_qni_bound_cons_var.find(qb.first);
2079 [ + - ]: 699507 : int vn = itb != d_qni_bound_cons_var.end() ? itb->second : -1;
2080 : 699507 : d_qi->addConstraint(qb.first, qb.second, vn, d_tgt, true);
2081 : : }
2082 : : }
2083 : 726125 : d_qni_bound_cons.clear();
2084 : 726125 : d_qni_bound_cons_var.clear();
2085 : 726125 : d_qni_bound.clear();
2086 : 726125 : }
2087 : : else
2088 : : {
2089 : : // clean up the matches you set
2090 [ + + ]: 5529597 : for (const std::pair<const size_t, size_t>& qb : d_qni_bound)
2091 : : {
2092 [ + - ]: 4760300 : Trace("qcf-match")
2093 : 2380150 : << " Clean up bound var " << qb.second << std::endl;
2094 [ - + ][ - + ]: 2380150 : Assert(qb.second < d_qi->getNumVars());
[ - - ]
2095 : 2380150 : d_qi->unsetMatch(qb.second);
2096 : 2380150 : d_qi->d_match_term[qb.second] = TNode::null();
2097 : : }
2098 : 3149447 : d_qni_bound.clear();
2099 : : }
2100 [ + + ]: 3875572 : if (d_type == typ_tconstraint)
2101 : : {
2102 : : // remove constraint if applicable
2103 [ + - ]: 1854 : if (d_qni_bound_cons.find(0) != d_qni_bound_cons.end())
2104 : : {
2105 : 1854 : d_qi->d_tconstraints.erase(d_n);
2106 : 1854 : d_qni_bound_cons.clear();
2107 : : }
2108 : : }
2109 : : }
2110 [ + - ]: 9419310 : Trace("qcf-match") << " ...finished matching for " << d_n
2111 : 4709655 : << ", success = " << success << std::endl;
2112 : 4709655 : d_wasSet = success;
2113 : 4709655 : return success;
2114 : : }
2115 [ + - ]: 327428 : else if (d_type == typ_formula)
2116 : : {
2117 : 327428 : bool success = false;
2118 [ + + ]: 327428 : if (d_child_counter < 0)
2119 : : {
2120 [ - + ]: 34762 : if (d_child_counter < -1)
2121 : : {
2122 : 0 : d_child_counter = -1;
2123 : : }
2124 : : }
2125 : : else
2126 : : {
2127 [ + + ][ + + ]: 1394830 : while (!success && d_child_counter >= 0)
2128 : : {
2129 : : // transition system based on d_child_counter
2130 [ + + ][ + + ]: 1102164 : if (d_n.getKind() == Kind::OR || d_n.getKind() == Kind::AND)
[ + + ]
2131 : : {
2132 [ + + ]: 843646 : if ((d_n.getKind() == Kind::AND) == d_tgt)
2133 : : {
2134 : : // all children must match simultaneously
2135 [ + + ]: 756466 : if (getChild(d_child_counter)->getNextMatch())
2136 : : {
2137 [ + + ]: 316082 : if (d_child_counter < (int)(getNumChildren() - 1))
2138 : : {
2139 : 308246 : d_child_counter++;
2140 [ + - ]: 616492 : Trace("qcf-match-debug")
2141 : 0 : << " Reset child " << d_child_counter << " of " << d_n
2142 : 308246 : << std::endl;
2143 : 308246 : getChild(d_child_counter)->reset(d_tgt);
2144 : : }
2145 : : else
2146 : : {
2147 : 7836 : success = true;
2148 : : }
2149 : : }
2150 : : else
2151 : : {
2152 : 440384 : d_child_counter--;
2153 : : }
2154 : : }
2155 : : else
2156 : : {
2157 : : // one child must match
2158 [ + + ]: 87180 : if (!getChild(d_child_counter)->getNextMatch())
2159 : : {
2160 [ + + ]: 68249 : if (d_child_counter < (int)(getNumChildren() - 1))
2161 : : {
2162 : 36306 : d_child_counter++;
2163 [ + - ]: 72612 : Trace("qcf-match-debug")
2164 : 0 : << " Reset child " << d_child_counter << " of " << d_n
2165 : 36306 : << ", one match" << std::endl;
2166 : 36306 : getChild(d_child_counter)->reset(d_tgt);
2167 : : }
2168 : : else
2169 : : {
2170 : 31943 : d_child_counter = -1;
2171 : : }
2172 : : }
2173 : : else
2174 : : {
2175 : 18931 : success = true;
2176 : : }
2177 : : }
2178 : : }
2179 [ + + ]: 258518 : else if (d_n.getKind() == Kind::EQUAL)
2180 : : {
2181 : : // construct match based on both children
2182 [ + + ]: 226531 : if (d_child_counter % 2 == 0)
2183 : : {
2184 [ + + ]: 221479 : if (getChild(0)->getNextMatch())
2185 : : {
2186 : 49404 : d_child_counter++;
2187 : 49404 : getChild(1)->reset(d_child_counter == 1);
2188 : : }
2189 : : else
2190 : : {
2191 [ + + ]: 172075 : if (d_child_counter == 0)
2192 : : {
2193 : 86225 : d_child_counter = 2;
2194 : 86225 : getChild(0)->reset(!d_tgt);
2195 : : }
2196 : : else
2197 : : {
2198 : 85850 : d_child_counter = -1;
2199 : : }
2200 : : }
2201 : : }
2202 [ + + ][ + + ]: 226531 : if (d_child_counter >= 0 && d_child_counter % 2 == 1)
2203 : : {
2204 [ + + ]: 54456 : if (getChild(1)->getNextMatch())
2205 : : {
2206 : 5828 : success = true;
2207 : : }
2208 : : else
2209 : : {
2210 : 48628 : d_child_counter--;
2211 : : }
2212 : : }
2213 : : }
2214 [ + + ]: 31987 : else if (d_n.getKind() == Kind::ITE)
2215 : : {
2216 [ + + ]: 28686 : if (d_child_counter % 2 == 0)
2217 : : {
2218 [ + + ]: 28657 : int index1 = d_child_counter == 4 ? 1 : 0;
2219 [ + + ]: 28657 : if (getChild(index1)->getNextMatch())
2220 : : {
2221 : 18442 : d_child_counter++;
2222 : 18442 : getChild(d_child_counter == 5
2223 : 18431 : ? 2
2224 [ + + ]: 18431 : : (d_tgt == (d_child_counter == 1) ? 1 : 2))
2225 [ + + ]: 36873 : ->reset(d_tgt);
2226 : : }
2227 : : else
2228 : : {
2229 [ + + ]: 10215 : if (d_child_counter == 4)
2230 : : {
2231 : 3393 : d_child_counter = -1;
2232 : : }
2233 : : else
2234 : : {
2235 : 6822 : d_child_counter += 2;
2236 : 6822 : getChild(d_child_counter == 2 ? 0 : 1)
2237 [ + + ]: 6822 : ->reset(d_child_counter == 2 ? !d_tgt : d_tgt);
2238 : : }
2239 : : }
2240 : : }
2241 [ + + ][ + + ]: 28686 : if (d_child_counter >= 0 && d_child_counter % 2 == 1)
2242 : : {
2243 : 36942 : int index2 = d_child_counter == 5
2244 [ + + ]: 36931 : ? 2
2245 [ + + ]: 18460 : : (d_tgt == (d_child_counter == 1) ? 1 : 2);
2246 [ + + ]: 18471 : if (getChild(index2)->getNextMatch())
2247 : : {
2248 : 243 : success = true;
2249 : : }
2250 : : else
2251 : : {
2252 : 18228 : d_child_counter--;
2253 : : }
2254 : : }
2255 : : }
2256 [ + - ]: 3301 : else if (d_n.getKind() == Kind::FORALL)
2257 : : {
2258 [ + + ]: 3301 : if (getChild(d_child_counter)->getNextMatch())
2259 : : {
2260 : 975 : success = true;
2261 : : }
2262 : : else
2263 : : {
2264 : 2326 : d_child_counter = -1;
2265 : : }
2266 : : }
2267 : : }
2268 : 292666 : d_wasSet = success;
2269 [ + - ]: 585332 : Trace("qcf-match") << " ...finished construct match for " << d_n
2270 : 292666 : << ", success = " << success << std::endl;
2271 : 292666 : return success;
2272 : : }
2273 : : }
2274 [ + - ]: 34762 : Trace("qcf-match") << " ...already finished for " << d_n << std::endl;
2275 : 34762 : return false;
2276 : : }
2277 : :
2278 : 7437376 : bool MatchGen::doMatching()
2279 : : {
2280 [ + + ]: 7437376 : if (d_qn.empty())
2281 : : {
2282 : 997902 : return false;
2283 : : }
2284 [ + + ]: 6439474 : if (d_qn[0] == nullptr)
2285 : : {
2286 : 711729 : d_qn.clear();
2287 : 711729 : return true;
2288 : : }
2289 [ - + ][ - + ]: 5727745 : Assert(d_type == typ_var);
[ - - ]
2290 [ - + ][ - + ]: 5727745 : Assert(d_qni_size > 0);
[ - - ]
2291 : : bool invalidMatch;
2292 : : do
2293 : : {
2294 : 28603075 : invalidMatch = false;
2295 [ + - ]: 57206150 : Trace("qcf-match-debug") << " Do matching " << d_n << " "
2296 : 28603075 : << d_qn.size() << " " << d_qni.size() << std::endl;
2297 [ + + ]: 28603075 : if (d_qn.size() == d_qni.size() + 1)
2298 : : {
2299 : 12585068 : size_t index = d_qni.size();
2300 : : // initialize
2301 : 12585068 : TNode val;
2302 : 12585068 : std::map<size_t, size_t>::iterator itv = d_qni_var_num.find(index);
2303 [ + + ]: 12585068 : if (itv != d_qni_var_num.end())
2304 : : {
2305 : : // get the representative variable this variable is equal to
2306 : 12165747 : size_t repVar = d_qi->getCurrentRepVar(itv->second);
2307 [ + - ]: 24331494 : Trace("qcf-match-debug")
2308 : 0 : << " Match " << index << " is a variable " << itv->second
2309 : 12165747 : << ", which is repVar " << repVar << std::endl;
2310 : : // get the value the rep variable
2311 [ + + ]: 12165747 : if (!d_qi->d_match[repVar].isNull())
2312 : : {
2313 : 7566999 : val = d_qi->d_match[repVar];
2314 [ + - ]: 15133998 : Trace("qcf-match-debug")
2315 : 7566999 : << " Variable is already bound to " << val << std::endl;
2316 : : }
2317 : : else
2318 : : {
2319 : : // binding a variable
2320 : 4598748 : d_qni_bound[index] = repVar;
2321 : 4598748 : std::map<TNode, TNodeTrie>::iterator it = d_qn[index]->d_data.begin();
2322 [ + - ]: 4598748 : if (it != d_qn[index]->d_data.end())
2323 : : {
2324 : 4598748 : d_qni.push_back(it);
2325 : : // set the match
2326 [ + + ][ - - ]: 9197496 : if (it->first.getType() == d_qi->d_var_types[repVar]
2327 [ + - ][ + + ]: 9197496 : && d_qi->setMatch(d_qni_bound[index], it->first, true, true))
[ + - ][ + - ]
[ - - ]
2328 : : {
2329 [ + - ]: 4689614 : Trace("qcf-match-debug")
2330 : 2344807 : << " Binding variable" << std::endl;
2331 [ + + ]: 2344807 : if (d_qn.size() < d_qni_size)
2332 : : {
2333 : 752536 : d_qn.push_back(&it->second);
2334 : : }
2335 : : }
2336 : : else
2337 : : {
2338 [ + - ]: 4507882 : Trace("qcf-match")
2339 : 2253941 : << " Binding variable, currently fail." << std::endl;
2340 : 2253941 : invalidMatch = true;
2341 : : }
2342 : : }
2343 : : else
2344 : : {
2345 [ - - ]: 0 : Trace("qcf-match-debug")
2346 : 0 : << " Binding variable, fail, no more variables to bind"
2347 : 0 : << std::endl;
2348 : 0 : d_qn.pop_back();
2349 : : }
2350 : : }
2351 : : }
2352 : : else
2353 : : {
2354 [ + - ]: 838642 : Trace("qcf-match-debug")
2355 : 419321 : << " Match " << index << " is ground term" << std::endl;
2356 [ - + ][ - + ]: 419321 : Assert(d_qni_gterm.find(index) != d_qni_gterm.end());
[ - - ]
2357 : 419321 : val = d_qni_gterm[index];
2358 [ - + ][ - + ]: 419321 : Assert(!val.isNull());
[ - - ]
2359 : : }
2360 [ + + ]: 12585068 : if (!val.isNull())
2361 : : {
2362 : 15972640 : Node valr = d_parent->getRepresentative(val);
2363 : : // constrained by val
2364 : : std::map<TNode, TNodeTrie>::iterator it =
2365 : 7986320 : d_qn[index]->d_data.find(valr);
2366 [ + + ]: 7986320 : if (it != d_qn[index]->d_data.end())
2367 : : {
2368 [ + - ]: 4103534 : Trace("qcf-match-debug") << " Match" << std::endl;
2369 : 4103534 : d_qni.push_back(it);
2370 [ + + ]: 4103534 : if (d_qn.size() < d_qni_size)
2371 : : {
2372 : 3989850 : d_qn.push_back(&it->second);
2373 : : }
2374 : : }
2375 : : else
2376 : : {
2377 [ + - ]: 3882786 : Trace("qcf-match-debug") << " Failed to match" << std::endl;
2378 : 3882786 : d_qn.pop_back();
2379 : : }
2380 : 7986320 : }
2381 : 12585068 : }
2382 : : else
2383 : : {
2384 [ - + ][ - + ]: 16018007 : Assert(d_qn.size() == d_qni.size());
[ - - ]
2385 : 16018007 : size_t index = d_qni.size() - 1;
2386 : : // increment if binding this variable
2387 : 16018007 : bool success = false;
2388 : 16018007 : std::map<size_t, size_t>::iterator itb = d_qni_bound.find(index);
2389 [ + + ]: 16018007 : if (itb != d_qni_bound.end())
2390 : : {
2391 : 11936088 : d_qni[index]++;
2392 [ + + ]: 11936088 : if (d_qni[index] != d_qn[index]->d_data.end())
2393 : : {
2394 : 7347955 : success = true;
2395 [ + + ]: 7347955 : if (d_qi->setMatch(itb->second, d_qni[index]->first, true, true))
2396 : : {
2397 [ + - ]: 12204244 : Trace("qcf-match-debug")
2398 : 6102122 : << " Bind next variable" << std::endl;
2399 [ + + ]: 6102122 : if (d_qn.size() < d_qni_size)
2400 : : {
2401 : 4958002 : d_qn.push_back(&d_qni[index]->second);
2402 : : }
2403 : : }
2404 : : else
2405 : : {
2406 [ + - ]: 2491666 : Trace("qcf-match-debug")
2407 : 1245833 : << " Bind next variable, currently fail" << std::endl;
2408 : 1245833 : invalidMatch = true;
2409 : : }
2410 : : }
2411 : : else
2412 : : {
2413 : 4588133 : d_qi->unsetMatch(itb->second);
2414 : 4588133 : d_qi->d_match_term[itb->second] = TNode::null();
2415 [ + - ]: 9176266 : Trace("qcf-match-debug")
2416 : 0 : << " Bind next variable, no more variables to bind"
2417 : 4588133 : << std::endl;
2418 : : }
2419 : : }
2420 : : else
2421 : : {
2422 : : // TODO : if it equal to something else, also try that
2423 : : }
2424 : : // if not incrementing, move to next
2425 [ + + ]: 16018007 : if (!success)
2426 : : {
2427 : 8670052 : d_qn.pop_back();
2428 : 8670052 : d_qni.pop_back();
2429 : : }
2430 : : }
2431 [ + + ][ + + ]: 28603075 : } while ((!d_qn.empty() && d_qni.size() != d_qni_size) || invalidMatch);
[ + + ][ + + ]
2432 [ + + ]: 5727745 : if (d_qni.size() == d_qni_size)
2433 : : {
2434 [ - + ][ - + ]: 2850075 : Assert(!d_qni[d_qni.size() - 1]->second.d_data.empty());
[ - - ]
2435 : 2850075 : TNode t = d_qni[d_qni.size() - 1]->second.d_data.begin()->first;
2436 [ + - ]: 5700150 : Trace("qcf-match-debug")
2437 : 2850075 : << " " << d_n << " matched " << t << std::endl;
2438 : 2850075 : d_qi->d_match_term[d_qni_var_num[0]] = t;
2439 : : // set the match terms
2440 : 2850075 : Node q = d_qi->getQuantifiedFormula();
2441 [ + + ]: 8654416 : for (const std::pair<const size_t, size_t>& qb : d_qni_bound)
2442 : : {
2443 [ + - ]: 11608682 : Trace("qcf-match-debug")
2444 : 0 : << " position " << qb.first << " bounded " << qb.second << " / "
2445 [ - + ][ - - ]: 5804341 : << q[0].getNumChildren() << std::endl;
2446 [ + + ]: 5804341 : if (qb.first > 0)
2447 : : {
2448 [ - + ][ - + ]: 3625411 : Assert(!d_qi->d_match[qb.second].isNull());
[ - - ]
2449 [ - + ][ - + ]: 3625411 : Assert(d_parent->areEqual(t[qb.first - 1], d_qi->d_match[qb.second]));
[ - - ]
2450 : 3625411 : d_qi->d_match_term[qb.second] = t[qb.first - 1];
2451 : : }
2452 : : }
2453 : 2850075 : }
2454 : 5727745 : return !d_qn.empty();
2455 : : }
2456 : :
2457 : 14011708 : void MatchGen::debugPrintType(CVC5_UNUSED const char* c, short typ)
2458 : : {
2459 [ + + ][ + + ]: 14011708 : switch (typ)
[ + + ][ + + ]
2460 : : {
2461 [ + - ]: 17359 : case typ_invalid: Trace(c) << "invalid"; break;
2462 [ + - ]: 2140 : case typ_ground: Trace(c) << "ground"; break;
2463 [ + - ]: 1599705 : case typ_eq: Trace(c) << "eq"; break;
2464 [ + - ]: 1476379 : case typ_pred: Trace(c) << "pred"; break;
2465 [ + - ]: 674675 : case typ_formula: Trace(c) << "formula"; break;
2466 [ + - ]: 10215419 : case typ_var: Trace(c) << "var"; break;
2467 [ + - ]: 13507 : case typ_bool_var: Trace(c) << "bool_var"; break;
2468 : : }
2469 : 14011708 : }
2470 : :
2471 : 12483 : void MatchGen::setInvalid()
2472 : : {
2473 : 12483 : d_type = typ_invalid;
2474 : 12483 : d_children.clear();
2475 : 12483 : }
2476 : :
2477 : 551234 : bool MatchGen::isHandledBoolConnective(TNode n)
2478 : : {
2479 [ + + ][ + + ]: 551234 : return TermUtil::isBoolConnectiveTerm(n) && n.getKind() != Kind::SEP_STAR;
[ + - ][ - - ]
2480 : : }
2481 : :
2482 : 3648993 : bool MatchGen::isHandledUfTerm(TNode n)
2483 : : {
2484 : 3648993 : return inst::TriggerTermInfo::isAtomicTriggerKind(n.getKind());
2485 : : }
2486 : :
2487 : 0 : bool MatchGen::isHandled(TNode n)
2488 : : {
2489 : 0 : if (n.getKind() != Kind::BOUND_VARIABLE && expr::hasBoundVar(n))
2490 : : {
2491 : 0 : if (!isHandledBoolConnective(n) && !isHandledUfTerm(n)
2492 : 0 : && n.getKind() != Kind::EQUAL && n.getKind() != Kind::ITE)
2493 : : {
2494 : 0 : return false;
2495 : : }
2496 [ - - ]: 0 : for (unsigned i = 0; i < n.getNumChildren(); i++)
2497 : : {
2498 [ - - ]: 0 : if (!isHandled(n[i]))
2499 : : {
2500 : 0 : return false;
2501 : : }
2502 : : }
2503 : : }
2504 : 0 : return true;
2505 : : }
2506 : :
2507 : 13099 : QuantConflictFind::QuantConflictFind(Env& env,
2508 : : QuantifiersState& qs,
2509 : : QuantifiersInferenceManager& qim,
2510 : : QuantifiersRegistry& qr,
2511 : 13099 : TermRegistry& tr)
2512 : : : QuantifiersModule(env, qs, qim, qr, tr),
2513 : 13099 : d_statistics(statisticsRegistry()),
2514 : 26198 : d_effort(EFFORT_INVALID)
2515 : : {
2516 : 13099 : }
2517 : :
2518 : : //-------------------------------------------------- registration
2519 : :
2520 : 49047 : void QuantConflictFind::registerQuantifier(Node q)
2521 : : {
2522 [ + + ]: 49047 : if (!d_qreg.hasOwnership(q, this))
2523 : : {
2524 : 1506 : return;
2525 : : }
2526 : 47541 : d_quants.push_back(q);
2527 : 47541 : d_quant_id[q] = d_quants.size();
2528 [ - + ]: 47541 : if (TraceIsOn("qcf-qregister"))
2529 : : {
2530 [ - - ]: 0 : Trace("qcf-qregister") << "Register ";
2531 : 0 : debugPrintQuant("qcf-qregister", q);
2532 [ - - ]: 0 : Trace("qcf-qregister") << " : " << q << std::endl;
2533 : : }
2534 : : // make QcfNode structure
2535 [ + - ]: 95082 : Trace("qcf-qregister")
2536 : 0 : << "- Get relevant equality/disequality pairs, calculate flattening..."
2537 : 47541 : << std::endl;
2538 : 47541 : d_qinfo[q].reset(new QuantInfo(d_env, d_qstate, d_treg, this, q));
2539 : :
2540 : : // debug print
2541 [ - + ]: 47541 : if (TraceIsOn("qcf-qregister"))
2542 : : {
2543 : 0 : QuantInfo* qi = d_qinfo[q].get();
2544 [ - - ]: 0 : Trace("qcf-qregister") << "- Flattened structure is :" << std::endl;
2545 [ - - ]: 0 : Trace("qcf-qregister") << " ";
2546 : 0 : debugPrintQuantBody("qcf-qregister", q, q[1]);
2547 [ - - ]: 0 : Trace("qcf-qregister") << std::endl;
2548 [ - - ]: 0 : if (qi->d_vars.size() > q[0].getNumChildren())
2549 : : {
2550 [ - - ]: 0 : Trace("qcf-qregister") << " with additional constraints : " << std::endl;
2551 : 0 : for (size_t j = q[0].getNumChildren(), nvars = qi->d_vars.size();
2552 [ - - ]: 0 : j < nvars;
2553 : : j++)
2554 : : {
2555 [ - - ]: 0 : Trace("qcf-qregister") << " ?x" << j << " = ";
2556 : 0 : debugPrintQuantBody("qcf-qregister", q, qi->d_vars[j], false);
2557 [ - - ]: 0 : Trace("qcf-qregister") << std::endl;
2558 : : }
2559 : : }
2560 [ - - ]: 0 : Trace("qcf-qregister") << "Done registering quantifier." << std::endl;
2561 : : }
2562 : : }
2563 : :
2564 : : //-------------------------------------------------- check function
2565 : :
2566 : 101420 : bool QuantConflictFind::needsCheck(Theory::Effort level)
2567 : : {
2568 [ + + ][ + + ]: 101420 : return !d_qstate.isConflictingInst() && (level == Theory::EFFORT_FULL);
2569 : : }
2570 : :
2571 : 39835 : void QuantConflictFind::reset_round(CVC5_UNUSED Theory::Effort level)
2572 : : {
2573 [ + - ]: 39835 : Trace("qcf-check") << "QuantConflictFind::reset_round" << std::endl;
2574 [ + - ]: 39835 : Trace("qcf-check") << "Compute relevant equivalence classes..." << std::endl;
2575 : 39835 : d_eqcs.clear();
2576 : :
2577 : 39835 : eq::EqClassesIterator eqcs_i = eq::EqClassesIterator(getEqualityEngine());
2578 : 39835 : TermDb* tdb = getTermDatabase();
2579 [ + + ]: 2635213 : while (!eqcs_i.isFinished())
2580 : : {
2581 : 2595378 : Node r = (*eqcs_i);
2582 [ + + ]: 2595378 : if (tdb->hasTermCurrent(r))
2583 : : {
2584 : 1791793 : TypeNode rtn = r.getType();
2585 : : // check regardless of options
2586 [ + + ]: 1791793 : if (!TermUtil::hasInstConstAttr(r))
2587 : : {
2588 : 1654118 : d_eqcs[rtn].push_back(r);
2589 : : }
2590 : 1791793 : }
2591 : 2595378 : ++eqcs_i;
2592 : 2595378 : }
2593 : 39835 : }
2594 : :
2595 : 266356 : void QuantConflictFind::setIrrelevantFunction(TNode f)
2596 : : {
2597 [ + + ]: 266356 : if (d_irr_func.find(f) == d_irr_func.end())
2598 : : {
2599 : 34996 : d_irr_func[f] = true;
2600 : 34996 : std::map<TNode, std::vector<Node>>::iterator it = d_func_rel_dom.find(f);
2601 [ + + ]: 34996 : if (it != d_func_rel_dom.end())
2602 : : {
2603 [ + + ]: 125267 : for (unsigned j = 0; j < it->second.size(); j++)
2604 : : {
2605 : 100077 : d_irr_quant[it->second[j]] = true;
2606 : : }
2607 : : }
2608 : : }
2609 : 266356 : }
2610 : :
2611 : : namespace {
2612 : :
2613 : : // Returns the beginning of a range of efforts. The range can be iterated
2614 : : // through as unsigned using operator++.
2615 : 31345 : inline QuantConflictFind::Effort QcfEffortStart()
2616 : : {
2617 : 31345 : return QuantConflictFind::EFFORT_CONFLICT;
2618 : : }
2619 : :
2620 : : // Returns the beginning of a range of efforts. The value returned is included
2621 : : // in the range.
2622 : 31345 : inline QuantConflictFind::Effort QcfEffortEnd(options::QcfMode m)
2623 : : {
2624 [ + - ]: 31345 : return m == options::QcfMode::PROP_EQ ? QuantConflictFind::EFFORT_PROP_EQ
2625 : 31345 : : QuantConflictFind::EFFORT_CONFLICT;
2626 : : }
2627 : :
2628 : : } // namespace
2629 : :
2630 : : /** check */
2631 : 111063 : void QuantConflictFind::check(Theory::Effort level, QEffort quant_e)
2632 : : {
2633 : 111063 : CodeTimer codeTimer(d_qstate.getStats().d_cbqi_time);
2634 [ + + ]: 111063 : if (quant_e != QEFFORT_CONFLICT)
2635 : : {
2636 : 79718 : return;
2637 : : }
2638 [ + - ]: 31345 : Trace("qcf-check") << "QCF : check : " << level << std::endl;
2639 [ - + ]: 31345 : if (d_qstate.isConflictingInst())
2640 : : {
2641 [ - - ]: 0 : Trace("qcf-check2") << "QCF : finished check : already in conflict."
2642 : 0 : << std::endl;
2643 [ - - ]: 0 : if (level >= Theory::EFFORT_FULL)
2644 : : {
2645 [ - - ]: 0 : Trace("qcf-warn") << "ALREADY IN CONFLICT? " << level << std::endl;
2646 : : }
2647 : 0 : return;
2648 : : }
2649 : 31345 : unsigned addedLemmas = 0;
2650 : 31345 : ++(d_statistics.d_inst_rounds);
2651 : 31345 : beginCallDebug();
2652 : 31345 : int prevEt = 0;
2653 [ - + ]: 31345 : if (TraceIsOn("qcf-engine"))
2654 : : {
2655 : 0 : prevEt = d_statistics.d_entailment_checks.get();
2656 [ - - ]: 0 : Trace("qcf-engine") << "---Conflict Find Engine Round, effort = " << level
2657 : 0 : << "---" << std::endl;
2658 : : }
2659 : :
2660 : : // reset the round-specific information
2661 : 31345 : d_irr_func.clear();
2662 : 31345 : d_irr_quant.clear();
2663 : :
2664 [ - + ]: 31345 : if (TraceIsOn("qcf-debug"))
2665 : : {
2666 [ - - ]: 0 : Trace("qcf-debug") << std::endl;
2667 : 0 : debugPrint("qcf-debug");
2668 [ - - ]: 0 : Trace("qcf-debug") << std::endl;
2669 : : }
2670 : 31345 : bool isConflict = false;
2671 : 31345 : FirstOrderModel* fm = d_treg.getModel();
2672 : 31345 : size_t nquant = fm->getNumAssertedQuantifiers();
2673 : : // for each effort level (find conflict, find propagating)
2674 : 31345 : unsigned end = QcfEffortEnd(options().quantifiers.cbqiMode);
2675 [ + + ]: 87618 : for (unsigned e = QcfEffortStart(); e <= end; ++e)
2676 : : {
2677 : : // set the effort (data member for convienence of access)
2678 : 60016 : d_effort = static_cast<Effort>(e);
2679 [ + - ]: 120032 : Trace("qcf-check") << "Checking quantified formulas at effort " << e
2680 : 60016 : << "..." << std::endl;
2681 : : // for each quantified formula
2682 [ + + ]: 613015 : for (size_t i = 0; i < nquant; i++)
2683 : : {
2684 : 555673 : Node q = fm->getAssertedQuantifier(i, true);
2685 [ + + ][ - - ]: 555673 : if (d_qreg.hasOwnership(q, this)
2686 [ + + ]: 543646 : && d_irr_quant.find(q) == d_irr_quant.end()
2687 [ + + ][ + + ]: 1099319 : && fm->isQuantifierActive(q))
[ + + ][ + - ]
[ - - ]
2688 : : {
2689 : : // check this quantified formula
2690 : 434161 : checkQuantifiedFormula(q, isConflict, addedLemmas);
2691 [ + + ][ + + ]: 434161 : if (d_qstate.isConflictingInst() || d_qstate.isInConflict())
[ + + ]
2692 : : {
2693 : 2674 : break;
2694 : : }
2695 : : }
2696 [ + + ]: 555673 : }
2697 : : // We are done if we added a lemma, or discovered a conflict in another
2698 : : // way. An example of the latter case is when two disequal congruent terms
2699 : : // are discovered during term indexing.
2700 [ + + ][ + + ]: 60016 : if (addedLemmas > 0 || d_qstate.isInConflict())
[ + + ]
2701 : : {
2702 : 3743 : break;
2703 : : }
2704 : : }
2705 [ - + ]: 31345 : if (isConflict)
2706 : : {
2707 : 0 : d_qstate.notifyConflictingInst();
2708 : : }
2709 [ - + ]: 31345 : if (TraceIsOn("qcf-engine"))
2710 : : {
2711 [ - - ]: 0 : Trace("qcf-engine") << "Finished conflict find engine";
2712 [ - - ]: 0 : if (addedLemmas > 0)
2713 : : {
2714 [ - - ]: 0 : Trace("qcf-engine") << ", effort = "
2715 : 0 : << (d_effort == EFFORT_CONFLICT
2716 [ - - ]: 0 : ? "conflict"
2717 [ - - ]: 0 : : (d_effort == EFFORT_PROP_EQ ? "prop_eq"
2718 : 0 : : "mc"));
2719 [ - - ]: 0 : Trace("qcf-engine") << ", addedLemmas = " << addedLemmas;
2720 : : }
2721 [ - - ]: 0 : Trace("qcf-engine") << std::endl;
2722 : 0 : int currEt = d_statistics.d_entailment_checks.get();
2723 [ - - ]: 0 : if (currEt != prevEt)
2724 : : {
2725 [ - - ]: 0 : Trace("qcf-engine") << " Entailment checks = " << (currEt - prevEt)
2726 : 0 : << std::endl;
2727 : : }
2728 : : }
2729 [ + - ]: 31345 : Trace("qcf-check2") << "QCF : finished check : " << level << std::endl;
2730 : 31345 : endCallDebug();
2731 [ + + ]: 111063 : }
2732 : :
2733 : 0 : std::string QuantConflictFind::identify() const { return "cbqi"; }
2734 : :
2735 : 434161 : void QuantConflictFind::checkQuantifiedFormula(Node q,
2736 : : bool& isConflict,
2737 : : unsigned& addedLemmas)
2738 : : {
2739 [ - + ][ - + ]: 434161 : Assert(d_qinfo.find(q) != d_qinfo.end());
[ - - ]
2740 : 434161 : QuantInfo* qi = d_qinfo[q].get();
2741 [ + + ]: 434161 : if (!qi->matchGeneratorIsValid())
2742 : : {
2743 : : // quantified formula is not properly set up for matching
2744 : 165115 : return;
2745 : : }
2746 [ - + ]: 269046 : if (TraceIsOn("qcf-check"))
2747 : : {
2748 [ - - ]: 0 : Trace("qcf-check") << "Check quantified formula ";
2749 : 0 : debugPrintQuant("qcf-check", q);
2750 [ - - ]: 0 : Trace("qcf-check") << " : " << q << "..." << std::endl;
2751 : : }
2752 : :
2753 [ + - ]: 269046 : Trace("qcf-check-debug") << "Reset round..." << std::endl;
2754 [ - + ]: 269046 : if (!qi->reset_round())
2755 : : {
2756 : : // it is typically the case that another conflict (e.g. in the term
2757 : : // database) was discovered if we fail here.
2758 : 0 : return;
2759 : : }
2760 : : // try to make a matches making the body false or propagating
2761 [ + - ]: 269046 : Trace("qcf-check-debug") << "Get next match..." << std::endl;
2762 : 269046 : Instantiate* qinst = d_qim.getInstantiate();
2763 [ + + ]: 301883 : while (qi->getNextMatch())
2764 : : {
2765 [ - + ]: 35867 : if (d_qstate.isInConflict())
2766 : : {
2767 [ - - ]: 0 : Trace("qcf-check") << " ... Quantifiers engine discovered conflict, ";
2768 [ - - ]: 0 : Trace("qcf-check") << "probably related to disequal congruent terms in "
2769 : 0 : "master equality engine"
2770 : 0 : << std::endl;
2771 : 3030 : return;
2772 : : }
2773 [ - + ]: 35867 : if (TraceIsOn("qcf-inst"))
2774 : : {
2775 [ - - ]: 0 : Trace("qcf-inst") << "*** Produced match at effort " << d_effort << " : "
2776 : 0 : << std::endl;
2777 : 0 : qi->debugPrintMatch("qcf-inst");
2778 [ - - ]: 0 : Trace("qcf-inst") << std::endl;
2779 : : }
2780 : : // check whether internal match constraints are satisfied
2781 [ + + ]: 35867 : if (qi->isMatchSpurious())
2782 : : {
2783 [ + - ]: 8560 : Trace("qcf-inst") << " ... Spurious (match is inconsistent)"
2784 : 4280 : << std::endl;
2785 : 5287 : continue;
2786 : : }
2787 : : // check whether match can be completed
2788 : 31587 : std::vector<size_t> assigned;
2789 [ + + ]: 31587 : if (!qi->completeMatch(assigned))
2790 : : {
2791 [ + - ]: 2014 : Trace("qcf-inst") << " ... Spurious (cannot assign unassigned vars)"
2792 : 1007 : << std::endl;
2793 : 1007 : continue;
2794 : : }
2795 : : // check whether the match is spurious according to (T-)entailment checks
2796 : 30580 : std::vector<Node> terms;
2797 : 30580 : qi->getMatch(terms);
2798 : 30580 : bool tcs = qi->isTConstraintSpurious(terms);
2799 [ + + ]: 30580 : if (tcs)
2800 : : {
2801 [ + - ]: 47372 : Trace("qcf-inst") << " ... Spurious (match is T-inconsistent)"
2802 : 23686 : << std::endl;
2803 : : }
2804 : : else
2805 : : {
2806 : : // otherwise, we have a conflict/propagating instance
2807 : : // for debugging
2808 [ - + ]: 6894 : if (TraceIsOn("qcf-check-inst"))
2809 : : {
2810 : 0 : Node inst = qinst->getInstantiation(q, terms);
2811 [ - - ]: 0 : Trace("qcf-check-inst")
2812 : 0 : << "Check instantiation " << inst << "..." << std::endl;
2813 : 0 : Assert(!d_treg.getEntailmentCheck()->isEntailed(inst, true));
2814 : 0 : Assert(d_treg.getEntailmentCheck()->isEntailed(inst, false)
2815 : : || d_effort > EFFORT_CONFLICT);
2816 : 0 : }
2817 : : // Process the lemma: either add an instantiation or specific lemmas
2818 : : // constructed during the isTConstraintSpurious call, or both.
2819 : 13788 : InferenceId id = (d_effort == EFFORT_CONFLICT
2820 [ + + ]: 6894 : ? InferenceId::QUANTIFIERS_INST_CBQI_CONFLICT
2821 : : : InferenceId::QUANTIFIERS_INST_CBQI_PROP);
2822 [ + + ]: 6894 : if (!qinst->addInstantiation(q, terms, id))
2823 : : {
2824 [ + - ]: 405 : Trace("qcf-inst") << " ... Failed to add instantiation" << std::endl;
2825 : : // This should only happen if the algorithm generates the same
2826 : : // propagating instance twice this round. In this case, return
2827 : : // to avoid exponential behavior.
2828 : 405 : return;
2829 : : }
2830 [ + - ]: 6489 : Trace("qcf-check") << " ... Added instantiation" << std::endl;
2831 [ - + ]: 6489 : if (TraceIsOn("qcf-instantiate"))
2832 : : {
2833 [ - - ]: 0 : Trace("qcf-instantiate") << "QCF instantiation: " << q << std::endl;
2834 [ - - ]: 0 : for (const Node& t : terms)
2835 : : {
2836 [ - - ]: 0 : Trace("qcf-instantiate") << " " << t << std::endl;
2837 : : }
2838 : : }
2839 [ - + ]: 6489 : if (TraceIsOn("qcf-inst"))
2840 : : {
2841 [ - - ]: 0 : Trace("qcf-inst") << "*** Was from effort " << d_effort << " : "
2842 : 0 : << std::endl;
2843 : 0 : qi->debugPrintMatch("qcf-inst");
2844 [ - - ]: 0 : Trace("qcf-inst") << std::endl;
2845 : : }
2846 : 6489 : ++addedLemmas;
2847 [ + + ]: 6489 : if (d_effort == EFFORT_CONFLICT)
2848 : : {
2849 : : // mark relevant: this ensures that quantified formula q is
2850 : : // checked first on the next round. This is an optimization to
2851 : : // ensure that quantified formulas that are more likely to have
2852 : : // conflicting instances are checked earlier.
2853 : 2625 : d_treg.getModel()->markRelevant(q);
2854 [ - + ]: 2625 : if (options().quantifiers.cbqiAllConflict)
2855 : : {
2856 : 0 : isConflict = true;
2857 : : }
2858 : : else
2859 : : {
2860 : 2625 : d_qstate.notifyConflictingInst();
2861 : : }
2862 : 2625 : return;
2863 : : }
2864 [ + - ]: 3864 : else if (d_effort == EFFORT_PROP_EQ)
2865 : : {
2866 : 3864 : d_treg.getModel()->markRelevant(q);
2867 : : }
2868 : : }
2869 : : // clean up assigned
2870 : 27550 : qi->revertMatch(assigned);
2871 : 27550 : d_tempCache.clear();
2872 [ + + ][ + + ]: 34617 : }
[ + ]
2873 [ + - ]: 532032 : Trace("qcf-check") << "Done, conflict = " << d_qstate.isConflictingInst()
2874 : 266016 : << std::endl;
2875 : : }
2876 : :
2877 : : //-------------------------------------------------- debugging
2878 : :
2879 : 0 : void QuantConflictFind::debugPrint(CVC5_UNUSED const char* c) const
2880 : : {
2881 : : // print the equivalance classes
2882 [ - - ]: 0 : Trace(c) << "----------EQ classes" << std::endl;
2883 : 0 : eq::EqClassesIterator eqcs_i = eq::EqClassesIterator(getEqualityEngine());
2884 [ - - ]: 0 : while (!eqcs_i.isFinished())
2885 : : {
2886 : 0 : Node n = (*eqcs_i);
2887 : : // if( !n.getType().isInteger() ){
2888 [ - - ]: 0 : Trace(c) << " - " << n << " : {";
2889 : 0 : eq::EqClassIterator eqc_i = eq::EqClassIterator(n, getEqualityEngine());
2890 : 0 : bool pr = false;
2891 [ - - ]: 0 : while (!eqc_i.isFinished())
2892 : : {
2893 : 0 : Node nn = (*eqc_i);
2894 : 0 : if (nn.getKind() != Kind::EQUAL && nn != n)
2895 : : {
2896 : 0 : Trace(c) << (pr ? "," : "") << " " << nn;
2897 : 0 : pr = true;
2898 : : }
2899 : 0 : ++eqc_i;
2900 : 0 : }
2901 : 0 : Trace(c) << (pr ? " " : "") << "}" << std::endl;
2902 : 0 : ++eqcs_i;
2903 : 0 : }
2904 : 0 : }
2905 : :
2906 : 0 : void QuantConflictFind::debugPrintQuant(CVC5_UNUSED const char* c, Node q) const
2907 : : {
2908 : 0 : std::map<Node, size_t>::const_iterator it = d_quant_id.find(q);
2909 [ - - ]: 0 : if (it == d_quant_id.end())
2910 : : {
2911 [ - - ]: 0 : Trace(c) << q;
2912 : 0 : return;
2913 : : }
2914 [ - - ]: 0 : Trace(c) << "Q" << it->second;
2915 : : }
2916 : :
2917 : 0 : void QuantConflictFind::debugPrintQuantBody(const char* c,
2918 : : Node q,
2919 : : Node n,
2920 : : bool doVarNum) const
2921 : : {
2922 [ - - ]: 0 : if (n.getNumChildren() == 0)
2923 : : {
2924 [ - - ]: 0 : Trace(c) << n;
2925 : 0 : return;
2926 : : }
2927 : : std::map<Node, std::unique_ptr<QuantInfo>>::const_iterator itq =
2928 : 0 : d_qinfo.find(q);
2929 [ - - ]: 0 : if (itq != d_qinfo.end())
2930 : : {
2931 : 0 : const QuantInfo* qi = itq->second.get();
2932 : 0 : std::map<TNode, size_t>::const_iterator itv = qi->d_var_num.find(n);
2933 [ - - ][ - - ]: 0 : if (doVarNum && itv != qi->d_var_num.end())
[ - - ]
2934 : : {
2935 [ - - ]: 0 : Trace(c) << "?x" << itv->second;
2936 : 0 : return;
2937 : : }
2938 : : }
2939 [ - - ]: 0 : Trace(c) << "(";
2940 [ - - ]: 0 : if (n.getKind() == Kind::APPLY_UF)
2941 : : {
2942 : 0 : Trace(c) << n.getOperator();
2943 : : }
2944 : : else
2945 : : {
2946 [ - - ]: 0 : Trace(c) << n.getKind();
2947 : : }
2948 [ - - ]: 0 : for (const Node& nc : n)
2949 : : {
2950 [ - - ]: 0 : Trace(c) << " ";
2951 : 0 : debugPrintQuantBody(c, q, nc);
2952 : 0 : }
2953 [ - - ]: 0 : Trace(c) << ")";
2954 : : }
2955 : :
2956 : 13099 : QuantConflictFind::Statistics::Statistics(StatisticsRegistry& sr)
2957 : 13099 : : d_inst_rounds(sr.registerInt("QuantConflictFind::Inst_Rounds")),
2958 : : d_entailment_checks(
2959 : 13099 : sr.registerInt("QuantConflictFind::Entailment_Checks"))
2960 : : {
2961 : 13099 : }
2962 : :
2963 : 40 : TNode QuantConflictFind::getZero(TypeNode tn, Kind k)
2964 : : {
2965 : 40 : std::pair<TypeNode, Kind> key(tn, k);
2966 : 40 : std::map<std::pair<TypeNode, Kind>, Node>::iterator it = d_zero.find(key);
2967 [ + + ]: 40 : if (it == d_zero.end())
2968 : : {
2969 : 16 : Node nn;
2970 [ + + ]: 16 : if (k == Kind::ADD)
2971 : : {
2972 : 9 : nn = nodeManager()->mkConstRealOrInt(tn, Rational(0));
2973 : : }
2974 : 16 : d_zero[key] = nn;
2975 : 16 : return nn;
2976 : 16 : }
2977 : 24 : return it->second;
2978 : 40 : }
2979 : :
2980 : 0 : std::ostream& operator<<(std::ostream& os, const QuantConflictFind::Effort& e)
2981 : : {
2982 [ - - ][ - - ]: 0 : switch (e)
2983 : : {
2984 : 0 : case QuantConflictFind::EFFORT_INVALID: os << "Invalid"; break;
2985 : 0 : case QuantConflictFind::EFFORT_CONFLICT: os << "Conflict"; break;
2986 : 0 : case QuantConflictFind::EFFORT_PROP_EQ: os << "PropEq"; break;
2987 : : }
2988 : 0 : return os;
2989 : : }
2990 : :
2991 : 107 : bool QuantConflictFind::isPropagatingInstance(Node n) const
2992 : : {
2993 : 107 : std::unordered_set<TNode> visited;
2994 : 107 : std::vector<TNode> visit;
2995 : 107 : TNode cur;
2996 : 107 : visit.push_back(n);
2997 : : do
2998 : : {
2999 : 229 : cur = visit.back();
3000 : 229 : visit.pop_back();
3001 [ + - ]: 229 : if (visited.find(cur) == visited.end())
3002 : : {
3003 : 229 : visited.insert(cur);
3004 : 229 : Kind ck = cur.getKind();
3005 [ + + ]: 229 : if (ck == Kind::FORALL)
3006 : : {
3007 : : // do nothing
3008 : : }
3009 [ + + ]: 189 : else if (TermUtil::isBoolConnective(ck))
3010 : : {
3011 [ + + ]: 183 : for (TNode cc : cur)
3012 : : {
3013 : 122 : visit.push_back(cc);
3014 : 122 : }
3015 : : }
3016 [ - + ]: 128 : else if (!getEqualityEngine()->hasTerm(cur))
3017 : : {
3018 [ - - ]: 0 : Trace("qcf-instance-check-debug")
3019 : 0 : << "...not propagating instance because of " << cur << " " << ck
3020 : 0 : << std::endl;
3021 : 0 : return false;
3022 : : }
3023 : : }
3024 [ + + ]: 229 : } while (!visit.empty());
3025 : 107 : return true;
3026 : 107 : }
3027 : :
3028 : : } // namespace quantifiers
3029 : : } // namespace theory
3030 : : } // namespace cvc5::internal
|