1 /*********************                                                        */
2 /*! \file inst_strategy_cegqi.cpp
3  ** \verbatim
4  ** Top contributors (to current version):
5  **   Andrew Reynolds, Morgan Deters, Andres Noetzli
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 counterexample-guided quantifier instantiation strategies
13  **/
14 #include "theory/quantifiers/cegqi/inst_strategy_cegqi.h"
15 
16 #include "expr/node_algorithm.h"
17 #include "options/quantifiers_options.h"
18 #include "smt/term_formula_removal.h"
19 #include "theory/arith/partial_model.h"
20 #include "theory/arith/theory_arith.h"
21 #include "theory/arith/theory_arith_private.h"
22 #include "theory/quantifiers/first_order_model.h"
23 #include "theory/quantifiers/instantiate.h"
24 #include "theory/quantifiers/quant_epr.h"
25 #include "theory/quantifiers/quantifiers_attributes.h"
26 #include "theory/quantifiers/quantifiers_rewriter.h"
27 #include "theory/quantifiers/term_database.h"
28 #include "theory/quantifiers/term_util.h"
29 #include "theory/theory_engine.h"
30 
31 using namespace std;
32 using namespace CVC4;
33 using namespace CVC4::kind;
34 using namespace CVC4::context;
35 using namespace CVC4::theory;
36 using namespace CVC4::theory::quantifiers;
37 
doAddInstantiation(std::vector<Node> & subs)38 bool CegqiOutputInstStrategy::doAddInstantiation(std::vector<Node>& subs)
39 {
40   return d_out->doAddInstantiation(subs);
41 }
42 
isEligibleForInstantiation(Node n)43 bool CegqiOutputInstStrategy::isEligibleForInstantiation(Node n)
44 {
45   return d_out->isEligibleForInstantiation(n);
46 }
47 
addLemma(Node lem)48 bool CegqiOutputInstStrategy::addLemma(Node lem)
49 {
50   return d_out->addLemma(lem);
51 }
52 
InstStrategyCegqi(QuantifiersEngine * qe)53 InstStrategyCegqi::InstStrategyCegqi(QuantifiersEngine* qe)
54     : QuantifiersModule(qe),
55       d_cbqi_set_quant_inactive(false),
56       d_incomplete_check(false),
57       d_added_cbqi_lemma(qe->getUserContext()),
58       d_elim_quants(qe->getSatContext()),
59       d_out(new CegqiOutputInstStrategy(this)),
60       d_nested_qe_waitlist_size(qe->getUserContext()),
61       d_nested_qe_waitlist_proc(qe->getUserContext())
62 //, d_added_inst( qe->getUserContext() )
63 {
64   d_qid_count = 0;
65   d_small_const =
66       NodeManager::currentNM()->mkConst(Rational(1) / Rational(1000000));
67   d_check_vts_lemma_lc = false;
68 }
69 
~InstStrategyCegqi()70 InstStrategyCegqi::~InstStrategyCegqi() {}
71 
needsCheck(Theory::Effort e)72 bool InstStrategyCegqi::needsCheck(Theory::Effort e)
73 {
74   return e>=Theory::EFFORT_LAST_CALL;
75 }
76 
needsModel(Theory::Effort e)77 QuantifiersModule::QEffort InstStrategyCegqi::needsModel(Theory::Effort e)
78 {
79   for( unsigned i=0; i<d_quantEngine->getModel()->getNumAssertedQuantifiers(); i++ ){
80     Node q = d_quantEngine->getModel()->getAssertedQuantifier( i );
81     if( doCbqi( q ) && d_quantEngine->getModel()->isQuantifierActive( q ) ){
82       return QEFFORT_STANDARD;
83     }
84   }
85   return QEFFORT_NONE;
86 }
87 
registerCbqiLemma(Node q)88 bool InstStrategyCegqi::registerCbqiLemma(Node q)
89 {
90   if( !hasAddedCbqiLemma( q ) ){
91     d_added_cbqi_lemma.insert( q );
92     Trace("cbqi-debug") << "Do cbqi for " << q << std::endl;
93     //add cbqi lemma
94     //get the counterexample literal
95     Node ceLit = d_quantEngine->getTermUtil()->getCounterexampleLiteral( q );
96     Node ceBody = d_quantEngine->getTermUtil()->getInstConstantBody( q );
97     if( !ceBody.isNull() ){
98       //add counterexample lemma
99       Node lem = NodeManager::currentNM()->mkNode( OR, ceLit.negate(), ceBody.negate() );
100       //require any decision on cel to be phase=true
101       d_quantEngine->addRequirePhase( ceLit, true );
102       Debug("cbqi-debug") << "Require phase " << ceLit << " = true." << std::endl;
103       //add counterexample lemma
104       lem = Rewriter::rewrite( lem );
105       Trace("cbqi-lemma") << "Counterexample lemma : " << lem << std::endl;
106       registerCounterexampleLemma( q, lem );
107 
108       //totality lemmas for EPR
109       QuantEPR * qepr = d_quantEngine->getQuantEPR();
110       if( qepr!=NULL ){
111         for( unsigned i=0; i<q[0].getNumChildren(); i++ ){
112           TypeNode tn = q[0][i].getType();
113           if( tn.isSort() ){
114             if( qepr->isEPR( tn ) ){
115               //add totality lemma
116               std::map< TypeNode, std::vector< Node > >::iterator itc = qepr->d_consts.find( tn );
117               if( itc!=qepr->d_consts.end() ){
118                 Assert( !itc->second.empty() );
119                 Node ic = d_quantEngine->getTermUtil()->getInstantiationConstant( q, i );
120                 std::vector< Node > disj;
121                 for( unsigned j=0; j<itc->second.size(); j++ ){
122                   disj.push_back( ic.eqNode( itc->second[j] ) );
123                 }
124                 Node tlem = disj.size()==1 ? disj[0] : NodeManager::currentNM()->mkNode( kind::OR, disj );
125                 Trace("cbqi-lemma") << "EPR totality lemma : " << tlem << std::endl;
126                 d_quantEngine->getOutputChannel().lemma( tlem );
127               }else{
128                 Assert( false );
129               }
130             }else{
131               Assert( !options::cbqiAll() );
132             }
133           }
134         }
135       }
136 
137       //compute dependencies between quantified formulas
138       if( options::cbqiLitDepend() || options::cbqiInnermost() ){
139         std::vector< Node > ics;
140         TermUtil::computeInstConstContains(q, ics);
141         d_parent_quant[q].clear();
142         d_children_quant[q].clear();
143         std::vector< Node > dep;
144         for( unsigned i=0; i<ics.size(); i++ ){
145           Node qi = ics[i].getAttribute(InstConstantAttribute());
146           if( std::find( d_parent_quant[q].begin(), d_parent_quant[q].end(), qi )==d_parent_quant[q].end() ){
147             d_parent_quant[q].push_back( qi );
148             d_children_quant[qi].push_back( q );
149             Assert( hasAddedCbqiLemma( qi ) );
150             Node qicel = d_quantEngine->getTermUtil()->getCounterexampleLiteral( qi );
151             dep.push_back( qi );
152             dep.push_back( qicel );
153           }
154         }
155         if( !dep.empty() ){
156           Node dep_lemma = NodeManager::currentNM()->mkNode( kind::IMPLIES, ceLit, NodeManager::currentNM()->mkNode( kind::AND, dep ) );
157           Trace("cbqi-lemma") << "Counterexample dependency lemma : " << dep_lemma << std::endl;
158           d_quantEngine->getOutputChannel().lemma( dep_lemma );
159         }
160       }
161 
162       //must register all sub-quantifiers of counterexample lemma, register their lemmas
163       std::vector< Node > quants;
164       TermUtil::computeQuantContains( lem, quants );
165       for( unsigned i=0; i<quants.size(); i++ ){
166         if( doCbqi( quants[i] ) ){
167           registerCbqiLemma( quants[i] );
168         }
169         if( options::cbqiNestedQE() ){
170           //record these as counterexample quantifiers
171           QAttributes qa;
172           QuantAttributes::computeQuantAttributes( quants[i], qa );
173           if( !qa.d_qid_num.isNull() ){
174             d_id_to_ce_quant[ qa.d_qid_num ] = quants[i];
175             d_ce_quant_to_id[ quants[i] ] = qa.d_qid_num;
176             Trace("cbqi-nqe") << "CE quant id = " << qa.d_qid_num << " is " << quants[i] << std::endl;
177           }
178         }
179       }
180     }
181     // The decision strategy for this quantified formula ensures that its
182     // counterexample literal is decided on first. It is user-context dependent.
183     std::map<Node, std::unique_ptr<DecisionStrategy>>::iterator itds =
184         d_dstrat.find(q);
185     DecisionStrategy* dlds = nullptr;
186     if (itds == d_dstrat.end())
187     {
188       d_dstrat[q].reset(
189           new DecisionStrategySingleton("CexLiteral",
190                                         ceLit,
191                                         d_quantEngine->getSatContext(),
192                                         d_quantEngine->getValuation()));
193       dlds = d_dstrat[q].get();
194     }
195     else
196     {
197       dlds = itds->second.get();
198     }
199     // it is appended to the list of strategies
200     d_quantEngine->getTheoryEngine()->getDecisionManager()->registerStrategy(
201         DecisionManager::STRAT_QUANT_CEGQI_FEASIBLE, dlds);
202     return true;
203   }else{
204     return false;
205   }
206 }
207 
reset_round(Theory::Effort effort)208 void InstStrategyCegqi::reset_round(Theory::Effort effort)
209 {
210   d_cbqi_set_quant_inactive = false;
211   d_incomplete_check = false;
212   d_active_quant.clear();
213   //check if any cbqi lemma has not been added yet
214   for( unsigned i=0; i<d_quantEngine->getModel()->getNumAssertedQuantifiers(); i++ ){
215     Node q = d_quantEngine->getModel()->getAssertedQuantifier( i );
216     //it is not active if it corresponds to a rewrite rule: we will process in rewrite engine
217     if( doCbqi( q ) ){
218       Assert( hasAddedCbqiLemma( q ) );
219       if( d_quantEngine->getModel()->isQuantifierActive( q ) ){
220         d_active_quant[q] = true;
221         Debug("cbqi-debug") << "Check quantified formula " << q << "..." << std::endl;
222         Node cel = d_quantEngine->getTermUtil()->getCounterexampleLiteral( q );
223         bool value;
224         if( d_quantEngine->getValuation().hasSatValue( cel, value ) ){
225           Debug("cbqi-debug") << "...CE Literal has value " << value << std::endl;
226           if( !value ){
227             if( d_quantEngine->getValuation().isDecision( cel ) ){
228               Trace("cbqi-warn") << "CBQI WARNING: Bad decision on CE Literal." << std::endl;
229             }else{
230               Trace("cbqi") << "Inactive : " << q << std::endl;
231               d_quantEngine->getModel()->setQuantifierActive( q, false );
232               d_cbqi_set_quant_inactive = true;
233               d_active_quant.erase( q );
234               d_elim_quants.insert( q );
235               Trace("cbqi-nqe") << "Inactive, waitlist proc/size = " << d_nested_qe_waitlist_proc[q].get() << "/" << d_nested_qe_waitlist_size[q].get() << std::endl;
236               //process from waitlist
237               while( d_nested_qe_waitlist_proc[q]<d_nested_qe_waitlist_size[q] ){
238                 int index = d_nested_qe_waitlist_proc[q];
239                 Assert( index>=0 );
240                 Assert( index<(int)d_nested_qe_waitlist[q].size() );
241                 Node nq = d_nested_qe_waitlist[q][index];
242                 Node nqeqn = doNestedQENode( d_nested_qe_info[nq].d_q, q, nq, d_nested_qe_info[nq].d_inst_terms, d_nested_qe_info[nq].d_doVts );
243                 Node dqelem = nq.eqNode( nqeqn );
244                 Trace("cbqi-lemma") << "Delayed nested quantifier elimination lemma : " << dqelem << std::endl;
245                 d_quantEngine->getOutputChannel().lemma( dqelem );
246                 d_nested_qe_waitlist_proc[q] = index + 1;
247               }
248             }
249           }
250         }else{
251           Debug("cbqi-debug") << "...CE Literal does not have value " << std::endl;
252         }
253       }
254     }
255   }
256 
257   //refinement: only consider innermost active quantified formulas
258   if( options::cbqiInnermost() ){
259     if( !d_children_quant.empty() && !d_active_quant.empty() ){
260       Trace("cbqi-debug") << "Find non-innermost quantifiers..." << std::endl;
261       std::vector< Node > ninner;
262       for( std::map< Node, bool >::iterator it = d_active_quant.begin(); it != d_active_quant.end(); ++it ){
263         std::map< Node, std::vector< Node > >::iterator itc = d_children_quant.find( it->first );
264         if( itc!=d_children_quant.end() ){
265           for( unsigned j=0; j<itc->second.size(); j++ ){
266             if( d_active_quant.find( itc->second[j] )!=d_active_quant.end() ){
267               Trace("cbqi-debug") << "Do not consider " << it->first << " since it is not innermost (" << itc->second[j] << std::endl;
268               ninner.push_back( it->first );
269               break;
270             }
271           }
272         }
273       }
274       Trace("cbqi-debug") << "Found " << ninner.size() << " non-innermost." << std::endl;
275       for( unsigned i=0; i<ninner.size(); i++ ){
276         Assert( d_active_quant.find( ninner[i] )!=d_active_quant.end() );
277         d_active_quant.erase( ninner[i] );
278       }
279       Assert( !d_active_quant.empty() );
280       Trace("cbqi-debug") << "...done removing." << std::endl;
281     }
282   }
283   d_check_vts_lemma_lc = false;
284 }
285 
check(Theory::Effort e,QEffort quant_e)286 void InstStrategyCegqi::check(Theory::Effort e, QEffort quant_e)
287 {
288   if (quant_e == QEFFORT_STANDARD)
289   {
290     Assert( !d_quantEngine->inConflict() );
291     double clSet = 0;
292     if( Trace.isOn("cbqi-engine") ){
293       clSet = double(clock())/double(CLOCKS_PER_SEC);
294       Trace("cbqi-engine") << "---Cbqi Engine Round, effort = " << e << "---" << std::endl;
295     }
296     unsigned lastWaiting = d_quantEngine->getNumLemmasWaiting();
297     for( int ee=0; ee<=1; ee++ ){
298       //for( unsigned i=0; i<d_quantEngine->getModel()->getNumAssertedQuantifiers(); i++ ){
299       //  Node q = d_quantEngine->getModel()->getAssertedQuantifier( i );
300       //  if( doCbqi( q ) && d_quantEngine->getModel()->isQuantifierActive( q ) ){
301       for( std::map< Node, bool >::iterator it = d_active_quant.begin(); it != d_active_quant.end(); ++it ){
302         Node q = it->first;
303         Trace("cbqi") << "CBQI : Process quantifier " << q[0] << " at effort " << ee << std::endl;
304         if( d_nested_qe.find( q )==d_nested_qe.end() ){
305           process( q, e, ee );
306           if( d_quantEngine->inConflict() ){
307             break;
308           }
309         }else{
310           Trace("cbqi-warn") << "CBQI : Cannot process already eliminated quantified formula " << q << std::endl;
311           Assert( false );
312         }
313       }
314       if( d_quantEngine->inConflict() || d_quantEngine->getNumLemmasWaiting()>lastWaiting ){
315         break;
316       }
317     }
318     if( Trace.isOn("cbqi-engine") ){
319       if( d_quantEngine->getNumLemmasWaiting()>lastWaiting ){
320         Trace("cbqi-engine") << "Added lemmas = " << (d_quantEngine->getNumLemmasWaiting()-lastWaiting) << std::endl;
321       }
322       double clSet2 = double(clock())/double(CLOCKS_PER_SEC);
323       Trace("cbqi-engine") << "Finished cbqi engine, time = " << (clSet2-clSet) << std::endl;
324     }
325   }
326 }
327 
checkComplete()328 bool InstStrategyCegqi::checkComplete()
329 {
330   if( ( !options::cbqiSat() && d_cbqi_set_quant_inactive ) || d_incomplete_check ){
331     return false;
332   }else{
333     return true;
334   }
335 }
336 
checkCompleteFor(Node q)337 bool InstStrategyCegqi::checkCompleteFor(Node q)
338 {
339   std::map<Node, CegHandledStatus>::iterator it = d_do_cbqi.find(q);
340   if( it!=d_do_cbqi.end() ){
341     return it->second != CEG_UNHANDLED;
342   }else{
343     return false;
344   }
345 }
346 
getIdMarkedQuantNode(Node n,std::map<Node,Node> & visited)347 Node InstStrategyCegqi::getIdMarkedQuantNode(Node n,
348                                              std::map<Node, Node>& visited)
349 {
350   std::map< Node, Node >::iterator it = visited.find( n );
351   if( it==visited.end() ){
352     Node ret = n;
353     if( n.getKind()==FORALL ){
354       QAttributes qa;
355       QuantAttributes::computeQuantAttributes( n, qa );
356       if( qa.d_qid_num.isNull() ){
357         std::vector< Node > rc;
358         rc.push_back( n[0] );
359         rc.push_back( getIdMarkedQuantNode( n[1], visited ) );
360         Node avar = NodeManager::currentNM()->mkSkolem( "id", NodeManager::currentNM()->booleanType() );
361         QuantIdNumAttribute ida;
362         avar.setAttribute(ida,d_qid_count);
363         d_qid_count++;
364         std::vector< Node > iplc;
365         iplc.push_back( NodeManager::currentNM()->mkNode( INST_ATTRIBUTE, avar ) );
366         if( n.getNumChildren()==3 ){
367           for( unsigned i=0; i<n[2].getNumChildren(); i++ ){
368             iplc.push_back( n[2][i] );
369           }
370         }
371         rc.push_back( NodeManager::currentNM()->mkNode( INST_PATTERN_LIST, iplc ) );
372         ret = NodeManager::currentNM()->mkNode( FORALL, rc );
373       }
374     }else if( n.getNumChildren()>0 ){
375       std::vector< Node > children;
376       if( n.getMetaKind() == kind::metakind::PARAMETERIZED ){
377         children.push_back( n.getOperator() );
378       }
379       bool childChanged = false;
380       for( unsigned i=0; i<n.getNumChildren(); i++ ){
381         Node nc = getIdMarkedQuantNode( n[i], visited );
382         childChanged = childChanged || nc!=n[i];
383         children.push_back( nc );
384       }
385       if( childChanged ){
386         ret = NodeManager::currentNM()->mkNode( n.getKind(), children );
387       }
388     }
389     visited[n] = ret;
390     return ret;
391   }else{
392     return it->second;
393   }
394 }
395 
checkOwnership(Node q)396 void InstStrategyCegqi::checkOwnership(Node q)
397 {
398   if( d_quantEngine->getOwner( q )==NULL && doCbqi( q ) ){
399     if (d_do_cbqi[q] == CEG_HANDLED)
400     {
401       //take full ownership of the quantified formula
402       d_quantEngine->setOwner( q, this );
403     }
404   }
405 }
406 
preRegisterQuantifier(Node q)407 void InstStrategyCegqi::preRegisterQuantifier(Node q)
408 {
409   // mark all nested quantifiers with id
410   if (options::cbqiNestedQE())
411   {
412     if( d_quantEngine->getOwner(q)==this )
413     {
414       std::map<Node, Node> visited;
415       Node mq = getIdMarkedQuantNode(q[1], visited);
416       if (mq != q[1])
417       {
418         // do not do cbqi, we are reducing this quantified formula to a marked
419         // one
420         d_do_cbqi[q] = CEG_UNHANDLED;
421         // instead do reduction
422         std::vector<Node> qqc;
423         qqc.push_back(q[0]);
424         qqc.push_back(mq);
425         if (q.getNumChildren() == 3)
426         {
427           qqc.push_back(q[2]);
428         }
429         Node qq = NodeManager::currentNM()->mkNode(FORALL, qqc);
430         Node mlem = NodeManager::currentNM()->mkNode(IMPLIES, q, qq);
431         Trace("cbqi-lemma") << "Mark quant id lemma : " << mlem << std::endl;
432         d_quantEngine->addLemma(mlem);
433       }
434     }
435   }
436   if( doCbqi( q ) ){
437     // get the instantiator
438     if (options::cbqiPreRegInst())
439     {
440       getInstantiator(q);
441     }
442     // register the cbqi lemma
443     if( registerCbqiLemma( q ) ){
444       Trace("cbqi") << "Registered cbqi lemma for quantifier : " << q << std::endl;
445     }
446   }
447 }
448 
doNestedQENode(Node q,Node ceq,Node n,std::vector<Node> & inst_terms,bool doVts)449 Node InstStrategyCegqi::doNestedQENode(
450     Node q, Node ceq, Node n, std::vector<Node>& inst_terms, bool doVts)
451 {
452   // there is a nested quantified formula (forall y. nq[y,x]) such that
453   //    q is (forall y. nq[y,t]) for ground terms t,
454   //    ceq is (forall y. nq[y,e]) for CE variables e.
455   // we call this function when we know (forall y. nq[y,e]) is equivalent to quantifier-free formula C[e].
456   // in this case, q is equivalent to the quantifier-free formula C[t].
457   if( d_nested_qe.find( ceq )==d_nested_qe.end() ){
458     d_nested_qe[ceq] = d_quantEngine->getInstantiatedConjunction( ceq );
459     Trace("cbqi-nqe") << "CE quantifier elimination : " << std::endl;
460     Trace("cbqi-nqe") << "  " << ceq << std::endl;
461     Trace("cbqi-nqe") << "  " << d_nested_qe[ceq] << std::endl;
462     //should not contain quantifiers
463     Assert( !QuantifiersRewriter::containsQuantifiers( d_nested_qe[ceq] ) );
464   }
465   Assert( d_quantEngine->getTermUtil()->d_inst_constants[q].size()==inst_terms.size() );
466   //replace inst constants with instantiation
467   Node ret = d_nested_qe[ceq].substitute( d_quantEngine->getTermUtil()->d_inst_constants[q].begin(),
468                                           d_quantEngine->getTermUtil()->d_inst_constants[q].end(),
469                                           inst_terms.begin(), inst_terms.end() );
470   if( doVts ){
471     //do virtual term substitution
472     ret = Rewriter::rewrite( ret );
473     ret = d_quantEngine->getTermUtil()->rewriteVtsSymbols( ret );
474   }
475   Trace("cbqi-nqe") << "Nested quantifier elimination: " << std::endl;
476   Trace("cbqi-nqe") << "  " << n << std::endl;
477   Trace("cbqi-nqe") << "  " << ret << std::endl;
478   return ret;
479 }
480 
doNestedQERec(Node q,Node n,std::map<Node,Node> & visited,std::vector<Node> & inst_terms,bool doVts)481 Node InstStrategyCegqi::doNestedQERec(Node q,
482                                       Node n,
483                                       std::map<Node, Node>& visited,
484                                       std::vector<Node>& inst_terms,
485                                       bool doVts)
486 {
487   if( visited.find( n )==visited.end() ){
488     Node ret = n;
489     if( n.getKind()==FORALL ){
490       QAttributes qa;
491       QuantAttributes::computeQuantAttributes( n, qa );
492       if( !qa.d_qid_num.isNull() ){
493         //if it has an id, check whether we have done quantifier elimination for this id
494         std::map< Node, Node >::iterator it = d_id_to_ce_quant.find( qa.d_qid_num );
495         if( it!=d_id_to_ce_quant.end() ){
496           Node ceq = it->second;
497           bool doNestedQe = d_elim_quants.contains( ceq );
498           if( doNestedQe ){
499             ret = doNestedQENode( q, ceq, n, inst_terms, doVts );
500           }else{
501             Trace("cbqi-nqe") << "Add to nested qe waitlist : " << std::endl;
502             Node nr = Rewriter::rewrite( n );
503             Trace("cbqi-nqe") << "  " << ceq << std::endl;
504             Trace("cbqi-nqe") << "  " << nr << std::endl;
505             int wlsize = d_nested_qe_waitlist_size[ceq] + 1;
506             d_nested_qe_waitlist_size[ceq] = wlsize;
507             if( wlsize<(int)d_nested_qe_waitlist[ceq].size() ){
508               d_nested_qe_waitlist[ceq][wlsize] = nr;
509             }else{
510               d_nested_qe_waitlist[ceq].push_back( nr );
511             }
512             d_nested_qe_info[nr].d_q = q;
513             d_nested_qe_info[nr].d_inst_terms.clear();
514             d_nested_qe_info[nr].d_inst_terms.insert( d_nested_qe_info[nr].d_inst_terms.end(), inst_terms.begin(), inst_terms.end() );
515             d_nested_qe_info[nr].d_doVts = doVts;
516             //TODO: ensure this holds by restricting prenex when cbqiNestedQe is true.
517             Assert( !options::cbqiInnermost() );
518           }
519         }
520       }
521     }else if( n.getNumChildren()>0 ){
522       std::vector< Node > children;
523       if( n.getMetaKind() == kind::metakind::PARAMETERIZED ){
524         children.push_back( n.getOperator() );
525       }
526       bool childChanged = false;
527       for( unsigned i=0; i<n.getNumChildren(); i++ ){
528         Node nc = doNestedQERec( q, n[i], visited, inst_terms, doVts );
529         childChanged = childChanged || nc!=n[i];
530         children.push_back( nc );
531       }
532       if( childChanged ){
533         ret = NodeManager::currentNM()->mkNode( n.getKind(), children );
534       }
535     }
536     visited[n] = ret;
537     return ret;
538   }else{
539     return n;
540   }
541 }
542 
doNestedQE(Node q,std::vector<Node> & inst_terms,Node lem,bool doVts)543 Node InstStrategyCegqi::doNestedQE(Node q,
544                                    std::vector<Node>& inst_terms,
545                                    Node lem,
546                                    bool doVts)
547 {
548   std::map< Node, Node > visited;
549   return doNestedQERec( q, lem, visited, inst_terms, doVts );
550 }
551 
registerCounterexampleLemma(Node q,Node lem)552 void InstStrategyCegqi::registerCounterexampleLemma(Node q, Node lem)
553 {
554   // must register with the instantiator
555   // must explicitly remove ITEs so that we record dependencies
556   std::vector<Node> ce_vars;
557   TermUtil* tutil = d_quantEngine->getTermUtil();
558   for (unsigned i = 0, nics = tutil->getNumInstantiationConstants(q); i < nics;
559        i++)
560   {
561     ce_vars.push_back(tutil->getInstantiationConstant(q, i));
562   }
563   std::vector<Node> lems;
564   lems.push_back(lem);
565   CegInstantiator* cinst = getInstantiator(q);
566   cinst->registerCounterexampleLemma(lems, ce_vars);
567   for (unsigned i = 0, size = lems.size(); i < size; i++)
568   {
569     Trace("cbqi-debug") << "Counterexample lemma " << i << " : " << lems[i]
570                         << std::endl;
571     d_quantEngine->addLemma(lems[i], false);
572   }
573 }
574 
doCbqi(Node q)575 bool InstStrategyCegqi::doCbqi(Node q)
576 {
577   std::map<Node, CegHandledStatus>::iterator it = d_do_cbqi.find(q);
578   if( it==d_do_cbqi.end() ){
579     CegHandledStatus ret = CegInstantiator::isCbqiQuant(q, d_quantEngine);
580     Trace("cbqi-quant") << "doCbqi " << q << " returned " << ret << std::endl;
581     d_do_cbqi[q] = ret;
582     return ret != CEG_UNHANDLED;
583   }
584   return it->second != CEG_UNHANDLED;
585 }
586 
process(Node q,Theory::Effort effort,int e)587 void InstStrategyCegqi::process( Node q, Theory::Effort effort, int e ) {
588   if( e==0 ){
589     CegInstantiator * cinst = getInstantiator( q );
590     Trace("inst-alg") << "-> Run cegqi for " << q << std::endl;
591     d_curr_quant = q;
592     if( !cinst->check() ){
593       d_incomplete_check = true;
594       d_check_vts_lemma_lc = true;
595     }
596     d_curr_quant = Node::null();
597   }else if( e==1 ){
598     //minimize the free delta heuristically on demand
599     if( d_check_vts_lemma_lc ){
600       Trace("inst-alg") << "-> Minimize delta heuristic, for " << q << std::endl;
601       d_check_vts_lemma_lc = false;
602       d_small_const = NodeManager::currentNM()->mkNode( MULT, d_small_const, d_small_const );
603       d_small_const = Rewriter::rewrite( d_small_const );
604       //heuristic for now, until we know how to do nested quantification
605       Node delta = d_quantEngine->getTermUtil()->getVtsDelta( true, false );
606       if( !delta.isNull() ){
607         Trace("quant-vts-debug") << "Delta lemma for " << d_small_const << std::endl;
608         Node delta_lem_ub = NodeManager::currentNM()->mkNode( LT, delta, d_small_const );
609         d_quantEngine->getOutputChannel().lemma( delta_lem_ub );
610       }
611       std::vector< Node > inf;
612       d_quantEngine->getTermUtil()->getVtsTerms( inf, true, false, false );
613       for( unsigned i=0; i<inf.size(); i++ ){
614         Trace("quant-vts-debug") << "Infinity lemma for " << inf[i] << " " << d_small_const << std::endl;
615         Node inf_lem_lb = NodeManager::currentNM()->mkNode( GT, inf[i], NodeManager::currentNM()->mkConst( Rational(1)/d_small_const.getConst<Rational>() ) );
616         d_quantEngine->getOutputChannel().lemma( inf_lem_lb );
617       }
618     }
619   }
620 }
621 
doAddInstantiation(std::vector<Node> & subs)622 bool InstStrategyCegqi::doAddInstantiation( std::vector< Node >& subs ) {
623   Assert( !d_curr_quant.isNull() );
624   //if doing partial quantifier elimination, record the instantiation and set the incomplete flag instead of sending instantiation lemma
625   if( d_quantEngine->getQuantAttributes()->isQuantElimPartial( d_curr_quant ) ){
626     d_cbqi_set_quant_inactive = true;
627     d_incomplete_check = true;
628     d_quantEngine->getInstantiate()->recordInstantiation(
629         d_curr_quant, subs, false, false);
630     return true;
631   }else{
632     //check if we need virtual term substitution (if used delta or infinity)
633     bool used_vts = d_quantEngine->getTermUtil()->containsVtsTerm( subs, false );
634     if (d_quantEngine->getInstantiate()->addInstantiation(
635             d_curr_quant, subs, false, false, used_vts))
636     {
637       ++(d_quantEngine->d_statistics.d_instantiations_cbqi);
638       //d_added_inst.insert( d_curr_quant );
639       return true;
640     }else{
641       //this should never happen for monotonic selection strategies
642       Trace("cbqi-warn") << "WARNING: Existing instantiation" << std::endl;
643       return false;
644     }
645   }
646 }
647 
addLemma(Node lem)648 bool InstStrategyCegqi::addLemma( Node lem ) {
649   return d_quantEngine->addLemma( lem );
650 }
651 
isEligibleForInstantiation(Node n)652 bool InstStrategyCegqi::isEligibleForInstantiation( Node n ) {
653   if( n.getKind()==INST_CONSTANT || n.getKind()==SKOLEM ){
654     if( n.getAttribute(VirtualTermSkolemAttribute()) ){
655       // virtual terms are allowed
656       return true;
657     }else{
658       TypeNode tn = n.getType();
659       if( tn.isSort() ){
660         QuantEPR * qepr = d_quantEngine->getQuantEPR();
661         if( qepr!=NULL ){
662           //legal if in the finite set of constants of type tn
663           if( qepr->isEPRConstant( tn, n ) ){
664             return true;
665           }
666         }
667       }
668       //only legal if current quantified formula contains n
669       return expr::hasSubterm(d_curr_quant, n);
670     }
671   }else{
672     return true;
673   }
674 }
675 
getInstantiator(Node q)676 CegInstantiator * InstStrategyCegqi::getInstantiator( Node q ) {
677   std::map<Node, std::unique_ptr<CegInstantiator>>::iterator it =
678       d_cinst.find(q);
679   if( it==d_cinst.end() ){
680     d_cinst[q].reset(
681         new CegInstantiator(d_quantEngine, d_out.get(), true, true));
682     return d_cinst[q].get();
683   }
684   return it->second.get();
685 }
686 
presolve()687 void InstStrategyCegqi::presolve() {
688   if (!options::cbqiPreRegInst())
689   {
690     return;
691   }
692   for (std::pair<const Node, std::unique_ptr<CegInstantiator>>& ci : d_cinst)
693   {
694     Trace("cbqi-presolve") << "Presolve " << ci.first << std::endl;
695     ci.second->presolve(ci.first);
696   }
697 }
698 
699