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