Merge branch '1.4.x'
[cvc5.git] / src / theory / rep_set.cpp
1 /********************* */
2 /*! \file rep_set.cpp
3 ** \verbatim
4 ** Original author: Andrew Reynolds
5 ** Major contributors: Morgan Deters
6 ** Minor contributors (to current version): Kshitij Bansal
7 ** This file is part of the CVC4 project.
8 ** Copyright (c) 2009-2014 New York University and The University of Iowa
9 ** See the file COPYING in the top-level source directory for licensing
10 ** information.\endverbatim
11 **
12 ** \brief Implementation of representative set
13 **/
14
15 #include "theory/rep_set.h"
16 #include "theory/type_enumerator.h"
17 #include "theory/quantifiers/bounded_integers.h"
18
19 using namespace std;
20 using namespace CVC4;
21 using namespace CVC4::kind;
22 using namespace CVC4::context;
23 using namespace CVC4::theory;
24
25 void RepSet::clear(){
26 d_type_reps.clear();
27 d_type_complete.clear();
28 d_tmap.clear();
29 }
30
31 int RepSet::getNumRepresentatives( TypeNode tn ) const{
32 std::map< TypeNode, std::vector< Node > >::const_iterator it = d_type_reps.find( tn );
33 if( it!=d_type_reps.end() ){
34 return (int)it->second.size();
35 }else{
36 return 0;
37 }
38 }
39
40 void RepSet::add( TypeNode tn, Node n ){
41 Assert( n.getType()==tn );
42 d_tmap[ n ] = (int)d_type_reps[tn].size();
43 Trace("rsi-debug") << "Add rep #" << d_type_reps[tn].size() << " for " << tn << " : " << n << std::endl;
44 d_type_reps[tn].push_back( n );
45 }
46
47 int RepSet::getIndexFor( Node n ) const {
48 std::map< Node, int >::const_iterator it = d_tmap.find( n );
49 if( it!=d_tmap.end() ){
50 return it->second;
51 }else{
52 return -1;
53 }
54 }
55
56 void RepSet::complete( TypeNode t ){
57 if( d_type_complete.find( t )==d_type_complete.end() ){
58 d_type_complete[t] = true;
59 TypeEnumerator te(t);
60 while( !te.isFinished() ){
61 Node n = *te;
62 if( std::find( d_type_reps[t].begin(), d_type_reps[t].end(), n )==d_type_reps[t].end() ){
63 add( t, n );
64 }
65 ++te;
66 }
67 for( size_t i=0; i<d_type_reps[t].size(); i++ ){
68 Trace("reps-complete") << d_type_reps[t][i] << " ";
69 }
70 Trace("reps-complete") << std::endl;
71 }
72 }
73
74 void RepSet::toStream(std::ostream& out){
75 #if 0
76 for( std::map< TypeNode, std::vector< Node > >::iterator it = d_type_reps.begin(); it != d_type_reps.end(); ++it ){
77 out << it->first << " : " << std::endl;
78 for( int i=0; i<(int)it->second.size(); i++ ){
79 out << " " << i << ": " << it->second[i] << std::endl;
80 }
81 }
82 #else
83 for( std::map< TypeNode, std::vector< Node > >::iterator it = d_type_reps.begin(); it != d_type_reps.end(); ++it ){
84 if( !it->first.isFunction() && !it->first.isPredicate() ){
85 out << "(" << it->first << " " << it->second.size();
86 out << " (";
87 for( int i=0; i<(int)it->second.size(); i++ ){
88 if( i>0 ){ out << " "; }
89 out << it->second[i];
90 }
91 out << ")";
92 out << ")" << std::endl;
93 }
94 }
95 #endif
96 }
97
98
99 RepSetIterator::RepSetIterator( QuantifiersEngine * qe, RepSet* rs ) : d_qe(qe), d_rep_set( rs ){
100 d_incomplete = false;
101 }
102
103 int RepSetIterator::domainSize( int i ) {
104 Assert(i>=0);
105 if( d_enum_type[i]==ENUM_DOMAIN_ELEMENTS ){
106 return d_domain[i].size();
107 }else{
108 return d_domain[i][0];
109 }
110 }
111
112 bool RepSetIterator::setQuantifier( Node f ){
113 Trace("rsi") << "Make rsi for " << f << std::endl;
114 Assert( d_types.empty() );
115 //store indicies
116 for( size_t i=0; i<f[0].getNumChildren(); i++ ){
117 d_types.push_back( f[0][i].getType() );
118 }
119 d_owner = f;
120 return initialize();
121 }
122
123 bool RepSetIterator::setFunctionDomain( Node op ){
124 Trace("rsi") << "Make rsi for " << op << std::endl;
125 Assert( d_types.empty() );
126 TypeNode tn = op.getType();
127 for( size_t i=0; i<tn.getNumChildren()-1; i++ ){
128 d_types.push_back( tn[i] );
129 }
130 d_owner = op;
131 return initialize();
132 }
133
134 bool RepSetIterator::initialize(){
135 for( size_t i=0; i<d_types.size(); i++ ){
136 d_index.push_back( 0 );
137 //store default index order
138 d_index_order.push_back( i );
139 d_var_order[i] = i;
140 //store default domain
141 d_domain.push_back( RepDomain() );
142 TypeNode tn = d_types[i];
143 if( tn.isSort() ){
144 if( !d_rep_set->hasType( tn ) ){
145 Node var = NodeManager::currentNM()->mkSkolem( "repSet", tn, "is a variable created by the RepSetIterator" );
146 Trace("mkVar") << "RepSetIterator:: Make variable " << var << " : " << tn << std::endl;
147 d_rep_set->add( tn, var );
148 }
149 }else if( tn.isInteger() ){
150 bool inc = false;
151 //check if it is bound
152 if( d_owner.getKind()==FORALL && d_qe && d_qe->getBoundedIntegers() ){
153 if( d_qe->getBoundedIntegers()->isBoundVar( d_owner, d_owner[0][i] ) ){
154 Trace("bound-int-rsi") << "Rep set iterator: variable #" << i << " is bounded integer." << std::endl;
155 d_enum_type.push_back( ENUM_RANGE );
156 }else{
157 inc = true;
158 }
159 }else{
160 inc = true;
161 }
162 if( inc ){
163 //check if it is otherwise bound
164 if( d_bounds[0].find(i)!=d_bounds[0].end() && d_bounds[1].find(i)!=d_bounds[1].end() ){
165 Trace("bound-int-rsi") << "Rep set iterator: variable #" << i << " is bounded." << std::endl;
166 d_enum_type.push_back( ENUM_RANGE );
167 }else{
168 Trace("fmf-incomplete") << "Incomplete because of integer quantification of " << d_owner[0][i] << "." << std::endl;
169 d_incomplete = true;
170 }
171 }
172 //enumerate if the sort is reasonably small, the upper bound of 1000 is chosen arbitrarily for now
173 }else if( tn.getCardinality().isFinite() && !tn.getCardinality().isLargeFinite() &&
174 tn.getCardinality().getFiniteCardinality().toUnsignedInt()<=1000 ){
175 d_rep_set->complete( tn );
176 }else{
177 Trace("fmf-incomplete") << "Incomplete because of quantification of type " << tn << std::endl;
178 d_incomplete = true;
179 }
180 if( d_enum_type.size()<=i ){
181 d_enum_type.push_back( ENUM_DOMAIN_ELEMENTS );
182 if( d_rep_set->hasType( tn ) ){
183 for( size_t j=0; j<d_rep_set->d_type_reps[tn].size(); j++ ){
184 d_domain[i].push_back( j );
185 }
186 }else{
187 return false;
188 }
189 }
190 }
191 //must set a variable index order based on bounded integers
192 if (d_owner.getKind()==FORALL && d_qe && d_qe->getBoundedIntegers()) {
193 Trace("bound-int-rsi") << "Calculating variable order..." << std::endl;
194 std::vector< int > varOrder;
195 for( unsigned i=0; i<d_qe->getBoundedIntegers()->getNumBoundVars(d_owner); i++ ){
196 varOrder.push_back(d_qe->getBoundedIntegers()->getBoundVarNum(d_owner,i));
197 }
198 for( unsigned i=0; i<d_owner[0].getNumChildren(); i++) {
199 if( !d_qe->getBoundedIntegers()->isBoundVar(d_owner, d_owner[0][i])) {
200 varOrder.push_back(i);
201 }
202 }
203 Trace("bound-int-rsi") << "Variable order : ";
204 for( unsigned i=0; i<varOrder.size(); i++) {
205 Trace("bound-int-rsi") << varOrder[i] << " ";
206 }
207 Trace("bound-int-rsi") << std::endl;
208 std::vector< int > indexOrder;
209 indexOrder.resize(varOrder.size());
210 for( unsigned i=0; i<varOrder.size(); i++){
211 indexOrder[varOrder[i]] = i;
212 }
213 Trace("bound-int-rsi") << "Will use index order : ";
214 for( unsigned i=0; i<indexOrder.size(); i++) {
215 Trace("bound-int-rsi") << indexOrder[i] << " ";
216 }
217 Trace("bound-int-rsi") << std::endl;
218 setIndexOrder(indexOrder);
219 }
220 //now reset the indices
221 for (unsigned i=0; i<d_index.size(); i++) {
222 if (!resetIndex(i, true)){
223 break;
224 }
225 }
226 return true;
227 }
228
229 void RepSetIterator::setIndexOrder( std::vector< int >& indexOrder ){
230 d_index_order.clear();
231 d_index_order.insert( d_index_order.begin(), indexOrder.begin(), indexOrder.end() );
232 //make the d_var_order mapping
233 for( int i=0; i<(int)d_index_order.size(); i++ ){
234 d_var_order[d_index_order[i]] = i;
235 }
236 }
237 /*
238 void RepSetIterator::setDomain( std::vector< RepDomain >& domain ){
239 d_domain.clear();
240 d_domain.insert( d_domain.begin(), domain.begin(), domain.end() );
241 //we are done if a domain is empty
242 for( int i=0; i<(int)d_domain.size(); i++ ){
243 if( d_domain[i].empty() ){
244 d_index.clear();
245 }
246 }
247 }
248 */
249 bool RepSetIterator::resetIndex( int i, bool initial ) {
250 d_index[i] = 0;
251 int ii = d_index_order[i];
252 Trace("bound-int-rsi") << "Reset " << i << " " << ii << " " << initial << std::endl;
253 //determine the current range
254 if( d_enum_type[ii]==ENUM_RANGE ){
255 if( initial || ( d_qe->getBoundedIntegers() && !d_qe->getBoundedIntegers()->isGroundRange( d_owner, d_owner[0][ii] ) ) ){
256 Trace("bound-int-rsi") << "Getting range of " << d_owner[0][ii] << std::endl;
257 Node actual_l;
258 Node l, u;
259 if( d_qe->getBoundedIntegers() && d_qe->getBoundedIntegers()->isBoundVar( d_owner, d_owner[0][ii] ) ){
260 d_qe->getBoundedIntegers()->getBoundValues( d_owner, d_owner[0][ii], this, l, u );
261 }
262 for( unsigned b=0; b<2; b++ ){
263 if( d_bounds[b].find(ii)!=d_bounds[b].end() ){
264 Trace("bound-int-rsi") << "May further limit bound(" << b << ") based on " << d_bounds[b][ii] << std::endl;
265 if( b==0 && (l.isNull() || d_bounds[b][ii].getConst<Rational>() > l.getConst<Rational>()) ){
266 if( !l.isNull() ){
267 //bound was limited externally, record that the value lower bound is not equal to the term lower bound
268 actual_l = NodeManager::currentNM()->mkNode( MINUS, d_bounds[b][ii], l );
269 }
270 l = d_bounds[b][ii];
271 }else if( b==1 && (u.isNull() || d_bounds[b][ii].getConst<Rational>() <= u.getConst<Rational>()) ){
272 u = NodeManager::currentNM()->mkNode( MINUS, d_bounds[b][ii],
273 NodeManager::currentNM()->mkConst( Rational(1) ) );
274 u = Rewriter::rewrite( u );
275 }
276 }
277 }
278
279 if( l.isNull() || u.isNull() ){
280 //failed, abort the iterator
281 d_index.clear();
282 return false;
283 }else{
284 Trace("bound-int-rsi") << "Can limit bounds of " << d_owner[0][ii] << " to " << l << "..." << u << std::endl;
285 Node range = Rewriter::rewrite( NodeManager::currentNM()->mkNode( MINUS, u, l ) );
286 Node ra = Rewriter::rewrite( NodeManager::currentNM()->mkNode( LEQ, range, NodeManager::currentNM()->mkConst( Rational( 9999 ) ) ) );
287 d_domain[ii].clear();
288 Node tl = l;
289 Node tu = u;
290 if( d_qe->getBoundedIntegers() && d_qe->getBoundedIntegers()->isBoundVar( d_owner, d_owner[0][ii] ) ){
291 d_qe->getBoundedIntegers()->getBounds( d_owner, d_owner[0][ii], this, tl, tu );
292 }
293 d_lower_bounds[ii] = tl;
294 if( !actual_l.isNull() ){
295 //if bound was limited externally, must consider the offset
296 d_lower_bounds[ii] = Rewriter::rewrite( NodeManager::currentNM()->mkNode( PLUS, tl, actual_l ) );
297 }
298 if( ra==NodeManager::currentNM()->mkConst(true) ){
299 long rr = range.getConst<Rational>().getNumerator().getLong()+1;
300 Trace("bound-int-rsi") << "Actual bound range is " << rr << std::endl;
301 d_domain[ii].push_back( (int)rr );
302 }else{
303 Trace("fmf-incomplete") << "Incomplete because of integer quantification, bounds are too big for " << d_owner[0][ii] << "." << std::endl;
304 d_incomplete = true;
305 d_domain[ii].push_back( 0 );
306 }
307 }
308 }else{
309 Trace("bound-int-rsi") << d_owner[0][ii] << " has ground range, skip." << std::endl;
310 }
311 }
312 return true;
313 }
314
315 int RepSetIterator::increment2( int counter ){
316 Assert( !isFinished() );
317 #ifdef DISABLE_EVAL_SKIP_MULTIPLE
318 counter = (int)d_index.size()-1;
319 #endif
320 //increment d_index
321 if( counter>=0){
322 Trace("rsi-debug") << "domain size of " << counter << " is " << domainSize(counter) << std::endl;
323 }
324 while( counter>=0 && d_index[counter]>=(int)(domainSize(counter)-1) ){
325 counter--;
326 if( counter>=0){
327 Trace("rsi-debug") << "domain size of " << counter << " is " << domainSize(counter) << std::endl;
328 }
329 }
330 if( counter==-1 ){
331 d_index.clear();
332 }else{
333 d_index[counter]++;
334 bool emptyDomain = false;
335 for( int i=(int)d_index.size()-1; i>counter; i-- ){
336 if (!resetIndex(i)){
337 break;
338 }else if( domainSize(i)<=0 ){
339 emptyDomain = true;
340 }
341 }
342 if( emptyDomain ){
343 Trace("rsi-debug") << "This is an empty domain, increment again." << std::endl;
344 return increment();
345 }
346 }
347 return counter;
348 }
349
350 int RepSetIterator::increment(){
351 if( !isFinished() ){
352 return increment2( (int)d_index.size()-1 );
353 }else{
354 return -1;
355 }
356 }
357
358 bool RepSetIterator::isFinished(){
359 return d_index.empty();
360 }
361
362 Node RepSetIterator::getTerm( int i ){
363 int index = d_index_order[i];
364 if( d_enum_type[index]==ENUM_DOMAIN_ELEMENTS ){
365 TypeNode tn = d_types[index];
366 Assert( d_rep_set->d_type_reps.find( tn )!=d_rep_set->d_type_reps.end() );
367 return d_rep_set->d_type_reps[tn][d_domain[index][d_index[index]]];
368 }else{
369 Trace("rsi-debug") << "Get, with offset : " << index << " " << d_lower_bounds[index] << " " << d_index[index] << std::endl;
370 Node t = NodeManager::currentNM()->mkNode(PLUS, d_lower_bounds[index],
371 NodeManager::currentNM()->mkConst( Rational(d_index[index]) ) );
372 t = Rewriter::rewrite( t );
373 return t;
374 }
375 }
376
377 void RepSetIterator::debugPrint( const char* c ){
378 for( int i=0; i<(int)d_index.size(); i++ ){
379 Debug( c ) << i << " : " << d_index[i] << " : " << getTerm( i ) << std::endl;
380 }
381 }
382
383 void RepSetIterator::debugPrintSmall( const char* c ){
384 Debug( c ) << "RI: ";
385 for( int i=0; i<(int)d_index.size(); i++ ){
386 Debug( c ) << d_index[i] << ": " << getTerm( i ) << " ";
387 }
388 Debug( c ) << std::endl;
389 }