1 /*********************                                                        */
2 /*! \file candidate_generator.cpp
3  ** \verbatim
4  ** Top contributors (to current version):
5  **   Andrew Reynolds, Morgan Deters, Francois Bobot
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 theory uf candidate generator class
13  **/
14 
15 #include "theory/quantifiers/ematching/candidate_generator.h"
16 #include "options/quantifiers_options.h"
17 #include "theory/quantifiers/inst_match.h"
18 #include "theory/quantifiers/instantiate.h"
19 #include "theory/quantifiers/term_database.h"
20 #include "theory/quantifiers/term_util.h"
21 #include "theory/quantifiers_engine.h"
22 #include "theory/theory_engine.h"
23 #include "theory/uf/theory_uf.h"
24 
25 using namespace std;
26 using namespace CVC4;
27 using namespace CVC4::kind;
28 using namespace CVC4::context;
29 using namespace CVC4::theory;
30 using namespace CVC4::theory::inst;
31 
isLegalCandidate(Node n)32 bool CandidateGenerator::isLegalCandidate( Node n ){
33   return d_qe->getTermDatabase()->isTermActive( n ) && ( !options::cbqi() || !quantifiers::TermUtil::hasInstConstAttr(n) );
34 }
35 
CandidateGeneratorQE(QuantifiersEngine * qe,Node pat)36 CandidateGeneratorQE::CandidateGeneratorQE(QuantifiersEngine* qe, Node pat)
37     : CandidateGenerator(qe),
38       d_term_iter(-1),
39       d_term_iter_limit(0),
40       d_mode(cand_term_none)
41 {
42   d_op = qe->getTermDatabase()->getMatchOperator( pat );
43   Assert( !d_op.isNull() );
44 }
45 
resetInstantiationRound()46 void CandidateGeneratorQE::resetInstantiationRound(){
47   d_term_iter_limit = d_qe->getTermDatabase()->getNumGroundTerms( d_op );
48 }
49 
reset(Node eqc)50 void CandidateGeneratorQE::reset( Node eqc ){
51   d_term_iter = 0;
52   if( eqc.isNull() ){
53     d_mode = cand_term_db;
54   }else{
55     if( isExcludedEqc( eqc ) ){
56       d_mode = cand_term_none;
57     }else{
58       eq::EqualityEngine* ee = d_qe->getEqualityQuery()->getEngine();
59       if( ee->hasTerm( eqc ) ){
60         TNodeTrie* tat = d_qe->getTermDatabase()->getTermArgTrie(eqc, d_op);
61         if( tat ){
62           //create an equivalence class iterator in eq class eqc
63           Node rep = ee->getRepresentative( eqc );
64           d_eqc_iter = eq::EqClassIterator( rep, ee );
65           d_mode = cand_term_eqc;
66         }else{
67           d_mode = cand_term_none;
68         }
69       }else{
70         //the only match is this term itself
71         d_eqc = eqc;
72         d_mode = cand_term_ident;
73       }
74     }
75   }
76 }
isLegalOpCandidate(Node n)77 bool CandidateGeneratorQE::isLegalOpCandidate( Node n ) {
78   if( n.hasOperator() ){
79     if( isLegalCandidate( n ) ){
80       return d_qe->getTermDatabase()->getMatchOperator( n )==d_op;
81     }
82   }
83   return false;
84 }
85 
getNextCandidate()86 Node CandidateGeneratorQE::getNextCandidate(){
87   if( d_mode==cand_term_db ){
88     Debug("cand-gen-qe") << "...get next candidate in tbd" << std::endl;
89     //get next candidate term in the uf term database
90     while( d_term_iter<d_term_iter_limit ){
91       Node n = d_qe->getTermDatabase()->getGroundTerm( d_op, d_term_iter );
92       d_term_iter++;
93       if( isLegalCandidate( n ) ){
94         if( d_qe->getTermDatabase()->hasTermCurrent( n ) ){
95           if( d_exclude_eqc.empty() ){
96             return n;
97           }else{
98             Node r = d_qe->getEqualityQuery()->getRepresentative( n );
99             if( d_exclude_eqc.find( r )==d_exclude_eqc.end() ){
100               Debug("cand-gen-qe") << "...returning " << n << std::endl;
101               return n;
102             }
103           }
104         }
105       }
106     }
107   }else if( d_mode==cand_term_eqc ){
108     Debug("cand-gen-qe") << "...get next candidate in eqc" << std::endl;
109     while( !d_eqc_iter.isFinished() ){
110       Node n = *d_eqc_iter;
111       ++d_eqc_iter;
112       if( isLegalOpCandidate( n ) ){
113         Debug("cand-gen-qe") << "...returning " << n << std::endl;
114         return n;
115       }
116     }
117   }else if( d_mode==cand_term_ident ){
118     Debug("cand-gen-qe") << "...get next candidate identity" << std::endl;
119     if (!d_eqc.isNull())
120     {
121       Node n = d_eqc;
122       d_eqc = Node::null();
123       if( isLegalOpCandidate( n ) ){
124         return n;
125       }
126     }
127   }
128   return Node::null();
129 }
130 
CandidateGeneratorQELitDeq(QuantifiersEngine * qe,Node mpat)131 CandidateGeneratorQELitDeq::CandidateGeneratorQELitDeq( QuantifiersEngine* qe, Node mpat ) :
132 CandidateGenerator( qe ), d_match_pattern( mpat ){
133 
134   Assert( d_match_pattern.getKind()==EQUAL );
135   d_match_pattern_type = d_match_pattern[0].getType();
136 }
137 
reset(Node eqc)138 void CandidateGeneratorQELitDeq::reset( Node eqc ){
139   Node false_term = d_qe->getEqualityQuery()->getEngine()->getRepresentative( NodeManager::currentNM()->mkConst<bool>(false) );
140   d_eqc_false = eq::EqClassIterator( false_term, d_qe->getEqualityQuery()->getEngine() );
141 }
142 
getNextCandidate()143 Node CandidateGeneratorQELitDeq::getNextCandidate(){
144   //get next candidate term in equivalence class
145   while( !d_eqc_false.isFinished() ){
146     Node n = (*d_eqc_false);
147     ++d_eqc_false;
148     if( n.getKind()==d_match_pattern.getKind() ){
149       if( n[0].getType().isComparableTo( d_match_pattern_type ) ){
150         //found an iff or equality, try to match it
151         //DO_THIS: cache to avoid redundancies?
152         //DO_THIS: do we need to try the symmetric equality for n?  or will it also exist in the eq class of false?
153         return n;
154       }
155     }
156   }
157   return Node::null();
158 }
159 
160 
CandidateGeneratorQEAll(QuantifiersEngine * qe,Node mpat)161 CandidateGeneratorQEAll::CandidateGeneratorQEAll( QuantifiersEngine* qe, Node mpat ) :
162   CandidateGenerator( qe ), d_match_pattern( mpat ){
163   d_match_pattern_type = mpat.getType();
164   Assert( mpat.getKind()==INST_CONSTANT );
165   d_f = quantifiers::TermUtil::getInstConstAttr( mpat );
166   d_index = mpat.getAttribute(InstVarNumAttribute());
167   d_firstTime = false;
168 }
169 
reset(Node eqc)170 void CandidateGeneratorQEAll::reset( Node eqc ) {
171   d_eq = eq::EqClassesIterator( d_qe->getEqualityQuery()->getEngine() );
172   d_firstTime = true;
173 }
174 
getNextCandidate()175 Node CandidateGeneratorQEAll::getNextCandidate() {
176   while( !d_eq.isFinished() ){
177     TNode n = (*d_eq);
178     ++d_eq;
179     if( n.getType().isComparableTo( d_match_pattern_type ) ){
180       TNode nh = d_qe->getTermDatabase()->getEligibleTermInEqc( n );
181       if( !nh.isNull() ){
182         if( options::instMaxLevel()!=-1 || options::lteRestrictInstClosure() ){
183           nh = d_qe->getInternalRepresentative( nh, d_f, d_index );
184           //don't consider this if already the instantiation is ineligible
185           if( !d_qe->getTermDatabase()->isTermEligibleForInstantiation( nh, d_f, false ) ){
186             nh = Node::null();
187           }
188         }
189         if( !nh.isNull() ){
190           d_firstTime = false;
191           //an equivalence class with the same type as the pattern, return it
192           return nh;
193         }
194       }
195     }
196   }
197   if( d_firstTime ){
198     //must return something
199     d_firstTime = false;
200     return d_qe->getInstantiate()->getTermForType(d_match_pattern_type);
201   }
202   return Node::null();
203 }
204 
CandidateGeneratorConsExpand(QuantifiersEngine * qe,Node mpat)205 CandidateGeneratorConsExpand::CandidateGeneratorConsExpand(
206     QuantifiersEngine* qe, Node mpat)
207     : CandidateGeneratorQE(qe, mpat)
208 {
209   Assert(mpat.getKind() == APPLY_CONSTRUCTOR);
210   d_mpat_type = static_cast<DatatypeType>(mpat.getType().toType());
211 }
212 
reset(Node eqc)213 void CandidateGeneratorConsExpand::reset(Node eqc)
214 {
215   d_term_iter = 0;
216   if (eqc.isNull())
217   {
218     d_mode = cand_term_db;
219   }
220   else
221   {
222     d_eqc = eqc;
223     d_mode = cand_term_ident;
224     Assert(d_eqc.getType().toType() == d_mpat_type);
225   }
226 }
227 
getNextCandidate()228 Node CandidateGeneratorConsExpand::getNextCandidate()
229 {
230   // get the next term from the base class
231   Node curr = CandidateGeneratorQE::getNextCandidate();
232   if (curr.isNull() || (curr.hasOperator() && curr.getOperator() == d_op))
233   {
234     return curr;
235   }
236   // expand it
237   NodeManager* nm = NodeManager::currentNM();
238   std::vector<Node> children;
239   const Datatype& dt = d_mpat_type.getDatatype();
240   Assert(dt.getNumConstructors() == 1);
241   children.push_back(d_op);
242   for (unsigned i = 0, nargs = dt[0].getNumArgs(); i < nargs; i++)
243   {
244     Node sel =
245         nm->mkNode(APPLY_SELECTOR_TOTAL,
246                    Node::fromExpr(dt[0].getSelectorInternal(d_mpat_type, i)),
247                    curr);
248     children.push_back(sel);
249   }
250   return nm->mkNode(APPLY_CONSTRUCTOR, children);
251 }
252 
isLegalOpCandidate(Node n)253 bool CandidateGeneratorConsExpand::isLegalOpCandidate(Node n)
254 {
255   return isLegalCandidate(n);
256 }
257