1 /*********************                                                        */
2 /*! \file instantiate.cpp
3  ** \verbatim
4  ** Top contributors (to current version):
5  **   Andrew Reynolds, Tim King, Morgan Deters
6  ** This file is part of the CVC4 project.
7  ** Copyright (c) 2009-2019 by the authors listed in the file AUTHORS
8  ** in the top-level source directory) and their institutional affiliations.
9  ** All rights reserved.  See the file COPYING in the top-level source
10  ** directory for licensing information.\endverbatim
11  **
12  ** \brief Implementation of instantiate
13  **/
14 
15 #include "theory/quantifiers/instantiate.h"
16 
17 #include "options/quantifiers_options.h"
18 #include "smt/smt_statistics_registry.h"
19 #include "theory/quantifiers/first_order_model.h"
20 #include "theory/quantifiers/cegqi/inst_strategy_cegqi.h"
21 #include "theory/quantifiers/quantifiers_attributes.h"
22 #include "theory/quantifiers/quantifiers_rewriter.h"
23 #include "theory/quantifiers/term_database.h"
24 #include "theory/quantifiers/term_enumeration.h"
25 #include "theory/quantifiers/term_util.h"
26 
27 using namespace CVC4::kind;
28 using namespace CVC4::context;
29 
30 namespace CVC4 {
31 namespace theory {
32 namespace quantifiers {
33 
Instantiate(QuantifiersEngine * qe,context::UserContext * u)34 Instantiate::Instantiate(QuantifiersEngine* qe, context::UserContext* u)
35     : d_qe(qe),
36       d_term_db(nullptr),
37       d_term_util(nullptr),
38       d_total_inst_count_debug(0),
39       d_c_inst_match_trie_dom(u)
40 {
41 }
42 
~Instantiate()43 Instantiate::~Instantiate()
44 {
45   for (std::pair<const Node, inst::CDInstMatchTrie*>& t : d_c_inst_match_trie)
46   {
47     delete t.second;
48   }
49   d_c_inst_match_trie.clear();
50 }
51 
reset(Theory::Effort e)52 bool Instantiate::reset(Theory::Effort e)
53 {
54   if (!d_recorded_inst.empty())
55   {
56     Trace("quant-engine-debug") << "Removing " << d_recorded_inst.size()
57                                 << " instantiations..." << std::endl;
58     // remove explicitly recorded instantiations
59     for (std::pair<Node, std::vector<Node> >& r : d_recorded_inst)
60     {
61       removeInstantiationInternal(r.first, r.second);
62     }
63     d_recorded_inst.clear();
64   }
65   d_term_db = d_qe->getTermDatabase();
66   d_term_util = d_qe->getTermUtil();
67   return true;
68 }
69 
registerQuantifier(Node q)70 void Instantiate::registerQuantifier(Node q) {}
checkComplete()71 bool Instantiate::checkComplete()
72 {
73   if (!d_recorded_inst.empty())
74   {
75     Trace("quant-engine-debug")
76         << "Set incomplete due to recorded instantiations." << std::endl;
77     return false;
78   }
79   return true;
80 }
81 
addNotify(InstantiationNotify * in)82 void Instantiate::addNotify(InstantiationNotify* in)
83 {
84   d_inst_notify.push_back(in);
85 }
86 
notifyFlushLemmas()87 void Instantiate::notifyFlushLemmas()
88 {
89   for (InstantiationNotify*& in : d_inst_notify)
90   {
91     in->filterInstantiations();
92   }
93 }
94 
addInstantiation(Node q,InstMatch & m,bool mkRep,bool modEq,bool doVts)95 bool Instantiate::addInstantiation(
96     Node q, InstMatch& m, bool mkRep, bool modEq, bool doVts)
97 {
98   Assert(q[0].getNumChildren() == m.d_vals.size());
99   return addInstantiation(q, m.d_vals, mkRep, modEq, doVts);
100 }
101 
addInstantiation(Node q,std::vector<Node> & terms,bool mkRep,bool modEq,bool doVts)102 bool Instantiate::addInstantiation(
103     Node q, std::vector<Node>& terms, bool mkRep, bool modEq, bool doVts)
104 {
105   // For resource-limiting (also does a time check).
106   d_qe->getOutputChannel().safePoint(options::quantifierStep());
107   Assert(!d_qe->inConflict());
108   Assert(terms.size() == q[0].getNumChildren());
109   Assert(d_term_db != nullptr);
110   Assert(d_term_util != nullptr);
111   Trace("inst-add-debug") << "For quantified formula " << q
112                           << ", add instantiation: " << std::endl;
113   for (unsigned i = 0, size = terms.size(); i < size; i++)
114   {
115     Trace("inst-add-debug") << "  " << q[0][i];
116     Trace("inst-add-debug2") << " -> " << terms[i];
117     TypeNode tn = q[0][i].getType();
118     if (terms[i].isNull())
119     {
120       terms[i] = getTermForType(tn);
121     }
122     if (mkRep)
123     {
124       // pick the best possible representative for instantiation, based on past
125       // use and simplicity of term
126       terms[i] = d_qe->getInternalRepresentative(terms[i], q, i);
127     }
128     else
129     {
130       // ensure the type is correct
131       terms[i] = quantifiers::TermUtil::ensureType(terms[i], tn);
132     }
133     Trace("inst-add-debug") << " -> " << terms[i] << std::endl;
134     if (terms[i].isNull())
135     {
136       Trace("inst-add-debug")
137           << " --> Failed to make term vector, due to term/type restrictions."
138           << std::endl;
139       return false;
140     }
141 #ifdef CVC4_ASSERTIONS
142     bool bad_inst = false;
143     if (quantifiers::TermUtil::containsUninterpretedConstant(terms[i]))
144     {
145       Trace("inst") << "***& inst contains uninterpreted constant : "
146                     << terms[i] << std::endl;
147       bad_inst = true;
148     }
149     else if (!terms[i].getType().isSubtypeOf(q[0][i].getType()))
150     {
151       Trace("inst") << "***& inst bad type : " << terms[i] << " "
152                     << terms[i].getType() << "/" << q[0][i].getType()
153                     << std::endl;
154       bad_inst = true;
155     }
156     else if (options::cbqi())
157     {
158       Node icf = quantifiers::TermUtil::getInstConstAttr(terms[i]);
159       if (!icf.isNull())
160       {
161         if (icf == q)
162         {
163           Trace("inst") << "***& inst contains inst constant attr : "
164                         << terms[i] << std::endl;
165           bad_inst = true;
166         }
167         else if (quantifiers::TermUtil::containsTerms(
168                      terms[i], d_term_util->d_inst_constants[q]))
169         {
170           Trace("inst") << "***& inst contains inst constants : " << terms[i]
171                         << std::endl;
172           bad_inst = true;
173         }
174       }
175     }
176     // this assertion is critical to soundness
177     if (bad_inst)
178     {
179       Trace("inst") << "***& Bad Instantiate " << q << " with " << std::endl;
180       for (unsigned j = 0; j < terms.size(); j++)
181       {
182         Trace("inst") << "   " << terms[j] << std::endl;
183       }
184       Assert(false);
185     }
186 #endif
187   }
188 
189   // Note we check for entailment before checking for term vector duplication.
190   // Although checking for term vector duplication is a faster check, it is
191   // included automatically with recordInstantiationInternal, hence we prefer
192   // two checks instead of three. In experiments, it is 1% slower or so to call
193   // existsInstantiation here.
194   // Alternatively, we could return an (index, trie node) in the call to
195   // existsInstantiation here, where this would return the node in the trie
196   // where we determined that there is definitely no duplication, and then
197   // continue from that point in recordInstantiation below. However, for
198   // simplicity, we do not pursue this option (as it would likely only
199   // lead to very small gains).
200 
201   // check for positive entailment
202   if (options::instNoEntail())
203   {
204     // should check consistency of equality engine
205     // (if not aborting on utility's reset)
206     std::map<TNode, TNode> subs;
207     for (unsigned i = 0, size = terms.size(); i < size; i++)
208     {
209       subs[q[0][i]] = terms[i];
210     }
211     if (d_term_db->isEntailed(q[1], subs, false, true))
212     {
213       Trace("inst-add-debug") << " --> Currently entailed." << std::endl;
214       ++(d_statistics.d_inst_duplicate_ent);
215       return false;
216     }
217   }
218 
219   // check based on instantiation level
220   if (options::instMaxLevel() != -1 || options::lteRestrictInstClosure())
221   {
222     for (Node& t : terms)
223     {
224       if (!d_term_db->isTermEligibleForInstantiation(t, q, true))
225       {
226         return false;
227       }
228     }
229   }
230 
231   // record the instantiation
232   bool recorded = recordInstantiationInternal(q, terms, modEq);
233   if (!recorded)
234   {
235     Trace("inst-add-debug") << " --> Already exists (no record)." << std::endl;
236     ++(d_statistics.d_inst_duplicate_eq);
237     return false;
238   }
239 
240   // construct the instantiation
241   Trace("inst-add-debug") << "Constructing instantiation..." << std::endl;
242   Assert(d_term_util->d_vars[q].size() == terms.size());
243   // get the instantiation
244   Node body = getInstantiation(q, d_term_util->d_vars[q], terms, doVts);
245   Node orig_body = body;
246   if (options::cbqiNestedQE())
247   {
248     InstStrategyCegqi* icegqi = d_qe->getInstStrategyCegqi();
249     if (icegqi)
250     {
251       body = icegqi->doNestedQE(q, terms, body, doVts);
252     }
253   }
254   body = quantifiers::QuantifiersRewriter::preprocess(body, true);
255   Trace("inst-debug") << "...preprocess to " << body << std::endl;
256 
257   // construct the lemma
258   Trace("inst-assert") << "(assert " << body << ")" << std::endl;
259 
260   if (d_qe->usingModelEqualityEngine() && options::instNoModelTrue())
261   {
262     Node val_body = d_qe->getModel()->getValue(body);
263     if (val_body.isConst() && val_body.getConst<bool>())
264     {
265       Trace("inst-add-debug") << " --> True in model." << std::endl;
266       ++(d_statistics.d_inst_duplicate_model_true);
267       return false;
268     }
269   }
270 
271   Node lem = NodeManager::currentNM()->mkNode(kind::OR, q.negate(), body);
272   lem = Rewriter::rewrite(lem);
273 
274   // check for lemma duplication
275   if (!d_qe->addLemma(lem, true, false))
276   {
277     Trace("inst-add-debug") << " --> Lemma already exists." << std::endl;
278     ++(d_statistics.d_inst_duplicate);
279     return false;
280   }
281 
282   d_total_inst_debug[q]++;
283   d_temp_inst_debug[q]++;
284   d_total_inst_count_debug++;
285   if (Trace.isOn("inst"))
286   {
287     Trace("inst") << "*** Instantiate " << q << " with " << std::endl;
288     for (unsigned i = 0, size = terms.size(); i < size; i++)
289     {
290       if (Trace.isOn("inst"))
291       {
292         Trace("inst") << "   " << terms[i];
293         if (Trace.isOn("inst-debug"))
294         {
295           Trace("inst-debug") << ", type=" << terms[i].getType()
296                               << ", var_type=" << q[0][i].getType();
297         }
298         Trace("inst") << std::endl;
299       }
300     }
301   }
302   if (options::instMaxLevel() != -1)
303   {
304     if (doVts)
305     {
306       // virtual term substitution/instantiation level features are
307       // incompatible
308       Assert(false);
309     }
310     else
311     {
312       uint64_t maxInstLevel = 0;
313       for (const Node& tc : terms)
314       {
315         if (tc.hasAttribute(InstLevelAttribute())
316             && tc.getAttribute(InstLevelAttribute()) > maxInstLevel)
317         {
318           maxInstLevel = tc.getAttribute(InstLevelAttribute());
319         }
320       }
321       QuantAttributes::setInstantiationLevelAttr(
322           orig_body, q[1], maxInstLevel + 1);
323     }
324   }
325   QuantifiersModule::QEffort elevel = d_qe->getCurrentQEffort();
326   if (elevel > QuantifiersModule::QEFFORT_CONFLICT
327       && elevel < QuantifiersModule::QEFFORT_NONE
328       && !d_inst_notify.empty())
329   {
330     // notify listeners
331     for (InstantiationNotify*& in : d_inst_notify)
332     {
333       if (!in->notifyInstantiation(elevel, q, lem, terms, body))
334       {
335         Trace("inst-add-debug") << "...we are in conflict." << std::endl;
336         d_qe->setConflict();
337         Assert(d_qe->getNumLemmasWaiting() > 0);
338         break;
339       }
340     }
341   }
342   if (options::trackInstLemmas())
343   {
344     bool recorded;
345     if (options::incrementalSolving())
346     {
347       recorded = d_c_inst_match_trie[q]->recordInstLemma(q, terms, lem);
348     }
349     else
350     {
351       recorded = d_inst_match_trie[q].recordInstLemma(q, terms, lem);
352     }
353     Trace("inst-add-debug") << "...was recorded : " << recorded << std::endl;
354     Assert(recorded);
355   }
356   Trace("inst-add-debug") << " --> Success." << std::endl;
357   ++(d_statistics.d_instantiations);
358   return true;
359 }
360 
removeInstantiation(Node q,Node lem,std::vector<Node> & terms)361 bool Instantiate::removeInstantiation(Node q,
362                                       Node lem,
363                                       std::vector<Node>& terms)
364 {
365   // lem must occur in d_waiting_lemmas
366   if (d_qe->removeLemma(lem))
367   {
368     return removeInstantiationInternal(q, terms);
369   }
370   return false;
371 }
372 
recordInstantiation(Node q,std::vector<Node> & terms,bool modEq,bool addedLem)373 bool Instantiate::recordInstantiation(Node q,
374                                       std::vector<Node>& terms,
375                                       bool modEq,
376                                       bool addedLem)
377 {
378   return recordInstantiationInternal(q, terms, modEq, addedLem);
379 }
380 
existsInstantiation(Node q,std::vector<Node> & terms,bool modEq)381 bool Instantiate::existsInstantiation(Node q,
382                                       std::vector<Node>& terms,
383                                       bool modEq)
384 {
385   if (options::incrementalSolving())
386   {
387     std::map<Node, inst::CDInstMatchTrie*>::iterator it =
388         d_c_inst_match_trie.find(q);
389     if (it != d_c_inst_match_trie.end())
390     {
391       return it->second->existsInstMatch(
392           d_qe, q, terms, d_qe->getUserContext(), modEq);
393     }
394   }
395   else
396   {
397     std::map<Node, inst::InstMatchTrie>::iterator it =
398         d_inst_match_trie.find(q);
399     if (it != d_inst_match_trie.end())
400     {
401       return it->second.existsInstMatch(d_qe, q, terms, modEq);
402     }
403   }
404   return false;
405 }
406 
getInstantiation(Node q,std::vector<Node> & vars,std::vector<Node> & terms,bool doVts)407 Node Instantiate::getInstantiation(Node q,
408                                    std::vector<Node>& vars,
409                                    std::vector<Node>& terms,
410                                    bool doVts)
411 {
412   Node body;
413   Assert(vars.size() == terms.size());
414   Assert(q[0].getNumChildren() == vars.size());
415   // TODO (#1386) : optimize this
416   body = q[1].substitute(vars.begin(), vars.end(), terms.begin(), terms.end());
417   if (doVts)
418   {
419     // do virtual term substitution
420     body = Rewriter::rewrite(body);
421     Trace("quant-vts-debug") << "Rewrite vts symbols in " << body << std::endl;
422     Node body_r = d_term_util->rewriteVtsSymbols(body);
423     Trace("quant-vts-debug") << "            ...result: " << body_r
424                              << std::endl;
425     body = body_r;
426   }
427   return body;
428 }
429 
getInstantiation(Node q,InstMatch & m,bool doVts)430 Node Instantiate::getInstantiation(Node q, InstMatch& m, bool doVts)
431 {
432   Assert(d_term_util->d_vars.find(q) != d_term_util->d_vars.end());
433   Assert(m.d_vals.size() == q[0].getNumChildren());
434   return getInstantiation(q, d_term_util->d_vars[q], m.d_vals, doVts);
435 }
436 
getInstantiation(Node q,std::vector<Node> & terms,bool doVts)437 Node Instantiate::getInstantiation(Node q, std::vector<Node>& terms, bool doVts)
438 {
439   Assert(d_term_util->d_vars.find(q) != d_term_util->d_vars.end());
440   return getInstantiation(q, d_term_util->d_vars[q], terms, doVts);
441 }
442 
recordInstantiationInternal(Node q,std::vector<Node> & terms,bool modEq,bool addedLem)443 bool Instantiate::recordInstantiationInternal(Node q,
444                                               std::vector<Node>& terms,
445                                               bool modEq,
446                                               bool addedLem)
447 {
448   if (!addedLem)
449   {
450     // record the instantiation for deletion later
451     d_recorded_inst.push_back(std::pair<Node, std::vector<Node> >(q, terms));
452   }
453   if (options::incrementalSolving())
454   {
455     Trace("inst-add-debug")
456         << "Adding into context-dependent inst trie, modEq = " << modEq
457         << std::endl;
458     inst::CDInstMatchTrie* imt;
459     std::map<Node, inst::CDInstMatchTrie*>::iterator it =
460         d_c_inst_match_trie.find(q);
461     if (it != d_c_inst_match_trie.end())
462     {
463       imt = it->second;
464     }
465     else
466     {
467       imt = new inst::CDInstMatchTrie(d_qe->getUserContext());
468       d_c_inst_match_trie[q] = imt;
469     }
470     d_c_inst_match_trie_dom.insert(q);
471     return imt->addInstMatch(d_qe, q, terms, d_qe->getUserContext(), modEq);
472   }
473   Trace("inst-add-debug") << "Adding into inst trie" << std::endl;
474   return d_inst_match_trie[q].addInstMatch(d_qe, q, terms, modEq);
475 }
476 
removeInstantiationInternal(Node q,std::vector<Node> & terms)477 bool Instantiate::removeInstantiationInternal(Node q, std::vector<Node>& terms)
478 {
479   if (options::incrementalSolving())
480   {
481     std::map<Node, inst::CDInstMatchTrie*>::iterator it =
482         d_c_inst_match_trie.find(q);
483     if (it != d_c_inst_match_trie.end())
484     {
485       return it->second->removeInstMatch(q, terms);
486     }
487     return false;
488   }
489   return d_inst_match_trie[q].removeInstMatch(q, terms);
490 }
491 
getTermForType(TypeNode tn)492 Node Instantiate::getTermForType(TypeNode tn)
493 {
494   if (tn.isClosedEnumerable())
495   {
496     return d_qe->getTermEnumeration()->getEnumerateTerm(tn, 0);
497   }
498   return d_qe->getTermDatabase()->getOrMakeTypeGroundTerm(tn);
499 }
500 
printInstantiations(std::ostream & out)501 bool Instantiate::printInstantiations(std::ostream& out)
502 {
503   bool useUnsatCore = false;
504   std::vector<Node> active_lemmas;
505   if (options::trackInstLemmas() && getUnsatCoreLemmas(active_lemmas))
506   {
507     useUnsatCore = true;
508   }
509   bool printed = false;
510   if (options::incrementalSolving())
511   {
512     for (std::pair<const Node, inst::CDInstMatchTrie*>& t : d_c_inst_match_trie)
513     {
514       bool firstTime = true;
515       t.second->print(out, t.first, firstTime, useUnsatCore, active_lemmas);
516       if (!firstTime)
517       {
518         out << ")" << std::endl;
519       }
520       printed = printed || !firstTime;
521     }
522   }
523   else
524   {
525     for (std::pair<const Node, inst::InstMatchTrie>& t : d_inst_match_trie)
526     {
527       bool firstTime = true;
528       t.second.print(out, t.first, firstTime, useUnsatCore, active_lemmas);
529       if (!firstTime)
530       {
531         out << ")" << std::endl;
532       }
533       printed = printed || !firstTime;
534     }
535   }
536   return printed;
537 }
538 
getInstantiatedQuantifiedFormulas(std::vector<Node> & qs)539 void Instantiate::getInstantiatedQuantifiedFormulas(std::vector<Node>& qs)
540 {
541   if (options::incrementalSolving())
542   {
543     for (context::CDHashSet<Node, NodeHashFunction>::const_iterator it =
544              d_c_inst_match_trie_dom.begin();
545          it != d_c_inst_match_trie_dom.end();
546          ++it)
547     {
548       qs.push_back(*it);
549     }
550   }
551   else
552   {
553     for (std::pair<const Node, inst::InstMatchTrie>& t : d_inst_match_trie)
554     {
555       qs.push_back(t.first);
556     }
557   }
558 }
559 
getUnsatCoreLemmas(std::vector<Node> & active_lemmas)560 bool Instantiate::getUnsatCoreLemmas(std::vector<Node>& active_lemmas)
561 {
562   // only if unsat core available
563   if (options::proof())
564   {
565     if (!ProofManager::currentPM()->unsatCoreAvailable())
566     {
567       return false;
568     }
569   }
570 
571   Trace("inst-unsat-core") << "Get instantiations in unsat core..."
572                            << std::endl;
573   ProofManager::currentPM()->getLemmasInUnsatCore(theory::THEORY_QUANTIFIERS,
574                                                   active_lemmas);
575   if (Trace.isOn("inst-unsat-core"))
576   {
577     Trace("inst-unsat-core") << "Quantifiers lemmas in unsat core: "
578                              << std::endl;
579     for (const Node& lem : active_lemmas)
580     {
581       Trace("inst-unsat-core") << "  " << lem << std::endl;
582     }
583     Trace("inst-unsat-core") << std::endl;
584   }
585   return true;
586 }
587 
getUnsatCoreLemmas(std::vector<Node> & active_lemmas,std::map<Node,Node> & weak_imp)588 bool Instantiate::getUnsatCoreLemmas(std::vector<Node>& active_lemmas,
589                                      std::map<Node, Node>& weak_imp)
590 {
591   if (getUnsatCoreLemmas(active_lemmas))
592   {
593     for (unsigned i = 0, size = active_lemmas.size(); i < size; ++i)
594     {
595       Node n = ProofManager::currentPM()->getWeakestImplicantInUnsatCore(
596           active_lemmas[i]);
597       if (n != active_lemmas[i])
598       {
599         Trace("inst-unsat-core") << "  weaken : " << active_lemmas[i] << " -> "
600                                  << n << std::endl;
601       }
602       weak_imp[active_lemmas[i]] = n;
603     }
604     return true;
605   }
606   return false;
607 }
608 
getInstantiationTermVectors(Node q,std::vector<std::vector<Node>> & tvecs)609 void Instantiate::getInstantiationTermVectors(
610     Node q, std::vector<std::vector<Node> >& tvecs)
611 {
612   std::vector<Node> lemmas;
613   getInstantiations(q, lemmas);
614   std::map<Node, Node> quant;
615   std::map<Node, std::vector<Node> > tvec;
616   getExplanationForInstLemmas(lemmas, quant, tvec);
617   for (std::pair<const Node, std::vector<Node> >& t : tvec)
618   {
619     tvecs.push_back(t.second);
620   }
621 }
622 
getInstantiationTermVectors(std::map<Node,std::vector<std::vector<Node>>> & insts)623 void Instantiate::getInstantiationTermVectors(
624     std::map<Node, std::vector<std::vector<Node> > >& insts)
625 {
626   if (options::incrementalSolving())
627   {
628     for (std::pair<const Node, inst::CDInstMatchTrie*>& t : d_c_inst_match_trie)
629     {
630       getInstantiationTermVectors(t.first, insts[t.first]);
631     }
632   }
633   else
634   {
635     for (std::pair<const Node, inst::InstMatchTrie>& t : d_inst_match_trie)
636     {
637       getInstantiationTermVectors(t.first, insts[t.first]);
638     }
639   }
640 }
641 
getExplanationForInstLemmas(const std::vector<Node> & lems,std::map<Node,Node> & quant,std::map<Node,std::vector<Node>> & tvec)642 void Instantiate::getExplanationForInstLemmas(
643     const std::vector<Node>& lems,
644     std::map<Node, Node>& quant,
645     std::map<Node, std::vector<Node> >& tvec)
646 {
647   if (options::trackInstLemmas())
648   {
649     if (options::incrementalSolving())
650     {
651       for (std::pair<const Node, inst::CDInstMatchTrie*>& t :
652            d_c_inst_match_trie)
653       {
654         t.second->getExplanationForInstLemmas(t.first, lems, quant, tvec);
655       }
656     }
657     else
658     {
659       for (std::pair<const Node, inst::InstMatchTrie>& t : d_inst_match_trie)
660       {
661         t.second.getExplanationForInstLemmas(t.first, lems, quant, tvec);
662       }
663     }
664 #ifdef CVC4_ASSERTIONS
665     for (unsigned j = 0; j < lems.size(); j++)
666     {
667       Assert(quant.find(lems[j]) != quant.end());
668       Assert(tvec.find(lems[j]) != tvec.end());
669     }
670 #endif
671   }
672   Assert(false);
673 }
674 
getInstantiations(std::map<Node,std::vector<Node>> & insts)675 void Instantiate::getInstantiations(std::map<Node, std::vector<Node> >& insts)
676 {
677   bool useUnsatCore = false;
678   std::vector<Node> active_lemmas;
679   if (options::trackInstLemmas() && getUnsatCoreLemmas(active_lemmas))
680   {
681     useUnsatCore = true;
682   }
683 
684   if (options::incrementalSolving())
685   {
686     for (std::pair<const Node, inst::CDInstMatchTrie*>& t : d_c_inst_match_trie)
687     {
688       t.second->getInstantiations(
689           insts[t.first], t.first, d_qe, useUnsatCore, active_lemmas);
690     }
691   }
692   else
693   {
694     for (std::pair<const Node, inst::InstMatchTrie>& t : d_inst_match_trie)
695     {
696       t.second.getInstantiations(
697           insts[t.first], t.first, d_qe, useUnsatCore, active_lemmas);
698     }
699   }
700 }
701 
getInstantiations(Node q,std::vector<Node> & insts)702 void Instantiate::getInstantiations(Node q, std::vector<Node>& insts)
703 {
704   if (options::incrementalSolving())
705   {
706     std::map<Node, inst::CDInstMatchTrie*>::iterator it =
707         d_c_inst_match_trie.find(q);
708     if (it != d_c_inst_match_trie.end())
709     {
710       std::vector<Node> active_lemmas;
711       it->second->getInstantiations(
712           insts, it->first, d_qe, false, active_lemmas);
713     }
714   }
715   else
716   {
717     std::map<Node, inst::InstMatchTrie>::iterator it =
718         d_inst_match_trie.find(q);
719     if (it != d_inst_match_trie.end())
720     {
721       std::vector<Node> active_lemmas;
722       it->second.getInstantiations(
723           insts, it->first, d_qe, false, active_lemmas);
724     }
725   }
726 }
727 
getInstantiatedConjunction(Node q)728 Node Instantiate::getInstantiatedConjunction(Node q)
729 {
730   Assert(q.getKind() == FORALL);
731   std::vector<Node> insts;
732   getInstantiations(q, insts);
733   if (insts.empty())
734   {
735     return NodeManager::currentNM()->mkConst(true);
736   }
737   Node ret;
738   if (insts.size() == 1)
739   {
740     ret = insts[0];
741   }
742   else
743   {
744     ret = NodeManager::currentNM()->mkNode(kind::AND, insts);
745   }
746   // have to remove q
747   // may want to do this in a better way
748   TNode tq = q;
749   TNode tt = NodeManager::currentNM()->mkConst(true);
750   ret = ret.substitute(tq, tt);
751   return ret;
752 }
753 
debugPrint()754 void Instantiate::debugPrint()
755 {
756   // debug information
757   if (Trace.isOn("inst-per-quant-round"))
758   {
759     for (std::pair<const Node, int>& i : d_temp_inst_debug)
760     {
761       Trace("inst-per-quant-round") << " * " << i.second << " for " << i.first
762                                     << std::endl;
763       d_temp_inst_debug[i.first] = 0;
764     }
765   }
766 }
767 
debugPrintModel()768 void Instantiate::debugPrintModel()
769 {
770   if (Trace.isOn("inst-per-quant"))
771   {
772     for (std::pair<const Node, int>& i : d_total_inst_debug)
773     {
774       Trace("inst-per-quant") << " * " << i.second << " for " << i.first
775                               << std::endl;
776     }
777   }
778 }
779 
Statistics()780 Instantiate::Statistics::Statistics()
781     : d_instantiations("Instantiate::Instantiations_Total", 0),
782       d_inst_duplicate("Instantiate::Duplicate_Inst", 0),
783       d_inst_duplicate_eq("Instantiate::Duplicate_Inst_Eq", 0),
784       d_inst_duplicate_ent("Instantiate::Duplicate_Inst_Entailed", 0),
785       d_inst_duplicate_model_true("Instantiate::Duplicate_Inst_Model_True", 0)
786 {
787   smtStatisticsRegistry()->registerStat(&d_instantiations);
788   smtStatisticsRegistry()->registerStat(&d_inst_duplicate);
789   smtStatisticsRegistry()->registerStat(&d_inst_duplicate_eq);
790   smtStatisticsRegistry()->registerStat(&d_inst_duplicate_ent);
791   smtStatisticsRegistry()->registerStat(&d_inst_duplicate_model_true);
792 }
793 
~Statistics()794 Instantiate::Statistics::~Statistics()
795 {
796   smtStatisticsRegistry()->unregisterStat(&d_instantiations);
797   smtStatisticsRegistry()->unregisterStat(&d_inst_duplicate);
798   smtStatisticsRegistry()->unregisterStat(&d_inst_duplicate_eq);
799   smtStatisticsRegistry()->unregisterStat(&d_inst_duplicate_ent);
800   smtStatisticsRegistry()->unregisterStat(&d_inst_duplicate_model_true);
801 }
802 
803 } /* CVC4::theory::quantifiers namespace */
804 } /* CVC4::theory namespace */
805 } /* CVC4 namespace */
806