Merge pull request #95 from 4tXJ7f/fix_sierra_build
[cvc5.git] / src / theory / rep_set.cpp
1 /********************* */
2 /*! \file rep_set.cpp
3 ** \verbatim
4 ** Top contributors (to current version):
5 ** Andrew Reynolds, Morgan Deters, Tim King
6 ** This file is part of the CVC4 project.
7 ** Copyright (c) 2009-2016 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 representative set
13 **/
14
15 #include "theory/rep_set.h"
16 #include "theory/type_enumerator.h"
17 #include "theory/quantifiers/bounded_integers.h"
18 #include "theory/quantifiers/term_database.h"
19 #include "theory/quantifiers/first_order_model.h"
20
21 using namespace std;
22 using namespace CVC4;
23 using namespace CVC4::kind;
24 using namespace CVC4::context;
25 using namespace CVC4::theory;
26
27 void RepSet::clear(){
28 d_type_reps.clear();
29 d_type_complete.clear();
30 d_tmap.clear();
31 d_values_to_terms.clear();
32 }
33
34 bool RepSet::hasRep( TypeNode tn, Node n ) {
35 std::map< TypeNode, std::vector< Node > >::iterator it = d_type_reps.find( tn );
36 if( it==d_type_reps.end() ){
37 return false;
38 }else{
39 return std::find( it->second.begin(), it->second.end(), n )!=it->second.end();
40 }
41 }
42
43 int RepSet::getNumRepresentatives( TypeNode tn ) const{
44 std::map< TypeNode, std::vector< Node > >::const_iterator it = d_type_reps.find( tn );
45 if( it!=d_type_reps.end() ){
46 return (int)it->second.size();
47 }else{
48 return 0;
49 }
50 }
51
52 bool containsStoreAll( Node n, std::vector< Node >& cache ){
53 if( std::find( cache.begin(), cache.end(), n )==cache.end() ){
54 cache.push_back( n );
55 if( n.getKind()==STORE_ALL ){
56 return true;
57 }else{
58 for( unsigned i=0; i<n.getNumChildren(); i++ ){
59 if( containsStoreAll( n[i], cache ) ){
60 return true;
61 }
62 }
63 }
64 }
65 return false;
66 }
67
68 void RepSet::add( TypeNode tn, Node n ){
69 //for now, do not add array constants FIXME
70 if( tn.isArray() ){
71 std::vector< Node > cache;
72 if( containsStoreAll( n, cache ) ){
73 return;
74 }
75 }
76 Trace("rsi-debug") << "Add rep #" << d_type_reps[tn].size() << " for " << tn << " : " << n << std::endl;
77 Assert( n.getType().isSubtypeOf( tn ) );
78 d_tmap[ n ] = (int)d_type_reps[tn].size();
79 d_type_reps[tn].push_back( n );
80 }
81
82 int RepSet::getIndexFor( Node n ) const {
83 std::map< Node, int >::const_iterator it = d_tmap.find( n );
84 if( it!=d_tmap.end() ){
85 return it->second;
86 }else{
87 return -1;
88 }
89 }
90
91 bool RepSet::complete( TypeNode t ){
92 std::map< TypeNode, bool >::iterator it = d_type_complete.find( t );
93 if( it==d_type_complete.end() ){
94 //remove all previous
95 for( unsigned i=0; i<d_type_reps[t].size(); i++ ){
96 d_tmap.erase( d_type_reps[t][i] );
97 }
98 d_type_reps[t].clear();
99 //now complete the type
100 d_type_complete[t] = true;
101 TypeEnumerator te(t);
102 while( !te.isFinished() ){
103 Node n = *te;
104 if( std::find( d_type_reps[t].begin(), d_type_reps[t].end(), n )==d_type_reps[t].end() ){
105 add( t, n );
106 }
107 ++te;
108 }
109 for( size_t i=0; i<d_type_reps[t].size(); i++ ){
110 Trace("reps-complete") << d_type_reps[t][i] << " ";
111 }
112 Trace("reps-complete") << std::endl;
113 return true;
114 }else{
115 return it->second;
116 }
117 }
118
119 void RepSet::toStream(std::ostream& out){
120 for( std::map< TypeNode, std::vector< Node > >::iterator it = d_type_reps.begin(); it != d_type_reps.end(); ++it ){
121 if( !it->first.isFunction() && !it->first.isPredicate() ){
122 out << "(" << it->first << " " << it->second.size();
123 out << " (";
124 for( unsigned i=0; i<it->second.size(); i++ ){
125 if( i>0 ){ out << " "; }
126 out << it->second[i];
127 }
128 out << ")";
129 out << ")" << std::endl;
130 }
131 }
132 }
133
134
135 RepSetIterator::RepSetIterator( QuantifiersEngine * qe, RepSet* rs ) : d_qe(qe), d_rep_set( rs ){
136 d_incomplete = false;
137 }
138
139 int RepSetIterator::domainSize( int i ) {
140 Assert(i>=0);
141 int v = d_var_order[i];
142 if( d_enum_type[v]==ENUM_DOMAIN_ELEMENTS ){
143 return d_domain[v].size();
144 }else{
145 return d_domain[v][0];
146 }
147 }
148
149 bool RepSetIterator::setQuantifier( Node f ){
150 Trace("rsi") << "Make rsi for " << f << std::endl;
151 Assert( d_types.empty() );
152 //store indicies
153 for( size_t i=0; i<f[0].getNumChildren(); i++ ){
154 d_types.push_back( f[0][i].getType() );
155 }
156 d_owner = f;
157 return initialize();
158 }
159
160 bool RepSetIterator::setFunctionDomain( Node op ){
161 Trace("rsi") << "Make rsi for " << op << std::endl;
162 Assert( d_types.empty() );
163 TypeNode tn = op.getType();
164 for( size_t i=0; i<tn.getNumChildren()-1; i++ ){
165 d_types.push_back( tn[i] );
166 }
167 d_owner = op;
168 return initialize();
169 }
170
171 bool RepSetIterator::initialize(){
172 Trace("rsi") << "Initialize rep set iterator..." << std::endl;
173 for( unsigned v=0; v<d_types.size(); v++ ){
174 d_index.push_back( 0 );
175 //store default index order
176 d_index_order.push_back( v );
177 d_var_order[v] = v;
178 //store default domain
179 d_domain.push_back( RepDomain() );
180 TypeNode tn = d_types[v];
181 Trace("rsi") << "Var #" << v << " is type " << tn << "..." << std::endl;
182 if( tn.isSort() ){
183 //must ensure uninterpreted type is non-empty.
184 if( !d_rep_set->hasType( tn ) ){
185 //FIXME:
186 // terms in rep_set are now constants which mapped to terms through TheoryModel
187 // thus, should introduce a constant and a term. for now, just a term.
188
189 //Node c = d_qe->getTermDatabase()->getEnumerateTerm( tn, 0 );
190 Node var = d_qe->getModel()->getSomeDomainElement( tn );
191 Trace("mkVar") << "RepSetIterator:: Make variable " << var << " : " << tn << std::endl;
192 d_rep_set->add( tn, var );
193 }
194 }else{
195 bool inc = true;
196 //check if it is bound by bounded integer module
197 if( d_owner.getKind()==FORALL && d_qe && d_qe->getBoundedIntegers() ){
198 unsigned bvt = d_qe->getBoundedIntegers()->getBoundVarType( d_owner, d_owner[0][v] );
199 if( bvt==quantifiers::BoundedIntegers::BOUND_INT_RANGE ){
200 Trace("rsi") << " variable is bounded integer." << std::endl;
201 d_enum_type.push_back( ENUM_INT_RANGE );
202 inc = false;
203 }else if( bvt==quantifiers::BoundedIntegers::BOUND_SET_MEMBER ){
204 Trace("rsi") << " variable is bounded by set membership." << std::endl;
205 d_enum_type.push_back( ENUM_SET_MEMBERS );
206 inc = false;
207 }
208 }
209 if( inc ){
210 //check if it is otherwise bound
211 if( d_bounds[0].find( v )!=d_bounds[0].end() && d_bounds[1].find( v )!=d_bounds[1].end() ){
212 Trace("rsi") << " variable is bounded." << std::endl;
213 d_enum_type.push_back( ENUM_INT_RANGE );
214 }else if( d_qe->getTermDatabase()->mayComplete( tn ) ){
215 Trace("rsi") << " do complete, since cardinality is small (" << tn.getCardinality() << ")..." << std::endl;
216 d_rep_set->complete( tn );
217 //must have succeeded
218 Assert( d_rep_set->hasType( tn ) );
219 }else{
220 Trace("rsi") << " variable cannot be bounded." << std::endl;
221 Trace("fmf-incomplete") << "Incomplete because of quantification of type " << tn << std::endl;
222 d_incomplete = true;
223 }
224 }
225 }
226 //if we have yet to determine the type of enumeration
227 if( d_enum_type.size()<=v ){
228 d_enum_type.push_back( ENUM_DOMAIN_ELEMENTS );
229 if( d_rep_set->hasType( tn ) ){
230 for( unsigned j=0; j<d_rep_set->d_type_reps[tn].size(); j++ ){
231 d_domain[v].push_back( j );
232 }
233 }else{
234 Assert( d_incomplete );
235 return false;
236 }
237 }
238 }
239 //must set a variable index order based on bounded integers
240 if( d_owner.getKind()==FORALL && d_qe && d_qe->getBoundedIntegers() ){
241 Trace("bound-int-rsi") << "Calculating variable order..." << std::endl;
242 std::vector< int > varOrder;
243 for( unsigned i=0; i<d_qe->getBoundedIntegers()->getNumBoundVars( d_owner ); i++ ){
244 Node v = d_qe->getBoundedIntegers()->getBoundVar( d_owner, i );
245 Trace("bound-int-rsi") << " bound var #" << i << " is " << v << std::endl;
246 varOrder.push_back( d_qe->getTermDatabase()->getVariableNum( d_owner, v ) );
247 }
248 for( unsigned i=0; i<d_owner[0].getNumChildren(); i++) {
249 if( !d_qe->getBoundedIntegers()->isBoundVar(d_owner, d_owner[0][i])) {
250 varOrder.push_back(i);
251 }
252 }
253 Trace("bound-int-rsi") << "Variable order : ";
254 for( unsigned i=0; i<varOrder.size(); i++) {
255 Trace("bound-int-rsi") << varOrder[i] << " ";
256 }
257 Trace("bound-int-rsi") << std::endl;
258 std::vector< int > indexOrder;
259 indexOrder.resize(varOrder.size());
260 for( unsigned i=0; i<varOrder.size(); i++){
261 indexOrder[varOrder[i]] = i;
262 }
263 Trace("bound-int-rsi") << "Will use index order : ";
264 for( unsigned i=0; i<indexOrder.size(); i++) {
265 Trace("bound-int-rsi") << indexOrder[i] << " ";
266 }
267 Trace("bound-int-rsi") << std::endl;
268 setIndexOrder( indexOrder );
269 }
270 //now reset the indices
271 do_reset_increment( -1, true );
272 return true;
273 }
274
275 void RepSetIterator::setIndexOrder( std::vector< int >& indexOrder ){
276 d_index_order.clear();
277 d_index_order.insert( d_index_order.begin(), indexOrder.begin(), indexOrder.end() );
278 //make the d_var_order mapping
279 for( unsigned i=0; i<d_index_order.size(); i++ ){
280 d_var_order[d_index_order[i]] = i;
281 }
282 }
283
284 int RepSetIterator::resetIndex( int i, bool initial ) {
285 d_index[i] = 0;
286 int v = d_var_order[i];
287 Trace("bound-int-rsi") << "Reset " << i << ", var order = " << v << ", initial = " << initial << std::endl;
288 //determine the current range
289 if( initial || ( d_owner.getKind()==FORALL && d_qe && d_qe->getBoundedIntegers() &&
290 d_qe->getBoundedIntegers()->isBoundVar( d_owner, d_owner[0][v] ) &&
291 !d_qe->getBoundedIntegers()->isGroundRange( d_owner, d_owner[0][v] ) ) ){
292 Trace("bound-int-rsi") << "Getting range of " << d_owner[0][v] << std::endl;
293 if( d_enum_type[v]==ENUM_INT_RANGE ){
294 Node actual_l;
295 Node l, u;
296 if( d_qe->getBoundedIntegers() ){
297 unsigned bvt = d_qe->getBoundedIntegers()->getBoundVarType( d_owner, d_owner[0][v] );
298 if( bvt==quantifiers::BoundedIntegers::BOUND_INT_RANGE ){
299 d_qe->getBoundedIntegers()->getBoundValues( d_owner, d_owner[0][v], this, l, u );
300 }
301 }
302 for( unsigned b=0; b<2; b++ ){
303 if( d_bounds[b].find(v)!=d_bounds[b].end() ){
304 Trace("bound-int-rsi") << "May further limit bound(" << b << ") based on " << d_bounds[b][v] << std::endl;
305 if( b==0 && (l.isNull() || d_bounds[b][v].getConst<Rational>() > l.getConst<Rational>()) ){
306 if( !l.isNull() ){
307 //bound was limited externally, record that the value lower bound is not equal to the term lower bound
308 actual_l = NodeManager::currentNM()->mkNode( MINUS, d_bounds[b][v], l );
309 }
310 l = d_bounds[b][v];
311 }else if( b==1 && (u.isNull() || d_bounds[b][v].getConst<Rational>() <= u.getConst<Rational>()) ){
312 u = NodeManager::currentNM()->mkNode( MINUS, d_bounds[b][v],
313 NodeManager::currentNM()->mkConst( Rational(1) ) );
314 u = Rewriter::rewrite( u );
315 }
316 }
317 }
318
319 if( l.isNull() || u.isNull() ){
320 //failed, abort the iterator
321 return -1;
322 }else{
323 Trace("bound-int-rsi") << "Can limit bounds of " << d_owner[0][v] << " to " << l << "..." << u << std::endl;
324 Node range = Rewriter::rewrite( NodeManager::currentNM()->mkNode( MINUS, u, l ) );
325 Node ra = Rewriter::rewrite( NodeManager::currentNM()->mkNode( LEQ, range, NodeManager::currentNM()->mkConst( Rational( 9999 ) ) ) );
326 d_domain[v].clear();
327 Node tl = l;
328 Node tu = u;
329 if( d_qe->getBoundedIntegers() && d_qe->getBoundedIntegers()->isBoundVar( d_owner, d_owner[0][v] ) ){
330 d_qe->getBoundedIntegers()->getBounds( d_owner, d_owner[0][v], this, tl, tu );
331 }
332 d_lower_bounds[v] = tl;
333 if( !actual_l.isNull() ){
334 //if bound was limited externally, must consider the offset
335 d_lower_bounds[v] = Rewriter::rewrite( NodeManager::currentNM()->mkNode( PLUS, tl, actual_l ) );
336 }
337 if( ra==d_qe->getTermDatabase()->d_true ){
338 long rr = range.getConst<Rational>().getNumerator().getLong()+1;
339 Trace("bound-int-rsi") << "Actual bound range is " << rr << std::endl;
340 d_domain[v].push_back( (int)rr );
341 if( rr<=0 ){
342 return 0;
343 }
344 }else{
345 Trace("fmf-incomplete") << "Incomplete because of integer quantification, bounds are too big for " << d_owner[0][v] << "." << std::endl;
346 return -1;
347 }
348 }
349 }else if( d_enum_type[v]==ENUM_SET_MEMBERS ){
350 Assert( d_qe->getBoundedIntegers()->getBoundVarType( d_owner, d_owner[0][v] )==quantifiers::BoundedIntegers::BOUND_SET_MEMBER );
351 Node srv = d_qe->getBoundedIntegers()->getSetRangeValue( d_owner, d_owner[0][v], this );
352 if( srv.isNull() ){
353 return -1;
354 }
355 Trace("bound-int-rsi") << "Bounded by set membership : " << srv << std::endl;
356 d_domain[v].clear();
357 d_setm_bounds[v].clear();
358 if( srv.getKind()!=EMPTYSET ){
359 while( srv.getKind()==UNION ){
360 Assert( srv[1].getKind()==kind::SINGLETON );
361 d_setm_bounds[v].push_back( srv[1][0] );
362 srv = srv[0];
363 }
364 Assert( srv.getKind()==kind::SINGLETON );
365 d_setm_bounds[v].push_back( srv[0] );
366 d_domain[v].push_back( d_setm_bounds[v].size() );
367 }else{
368 d_domain[v].push_back( 0 );
369 return 0;
370 }
371 }
372 }
373 return 1;
374 }
375
376 int RepSetIterator::increment2( int i ){
377 Assert( !isFinished() );
378 #ifdef DISABLE_EVAL_SKIP_MULTIPLE
379 i = (int)d_index.size()-1;
380 #endif
381 //increment d_index
382 if( i>=0){
383 Trace("rsi-debug") << "domain size of " << i << " is " << domainSize(i) << std::endl;
384 }
385 while( i>=0 && d_index[i]>=(int)(domainSize(i)-1) ){
386 i--;
387 if( i>=0){
388 Trace("rsi-debug") << "domain size of " << i << " is " << domainSize(i) << std::endl;
389 }
390 }
391 if( i==-1 ){
392 d_index.clear();
393 return -1;
394 }else{
395 Trace("rsi-debug") << "increment " << i << std::endl;
396 d_index[i]++;
397 return do_reset_increment( i );
398 }
399 }
400
401 int RepSetIterator::do_reset_increment( int i, bool initial ) {
402 bool emptyDomain = false;
403 for( unsigned ii=(i+1); ii<d_index.size(); ii++ ){
404 int ri_res = resetIndex( ii, initial );
405 if( ri_res==-1 ){
406 //failed
407 d_index.clear();
408 d_incomplete = true;
409 break;
410 }else if( ri_res==0 ){
411 emptyDomain = true;
412 }
413 //force next iteration if currently an empty domain
414 if( emptyDomain ){
415 d_index[ii] = domainSize(ii)-1;
416 }
417 }
418 if( emptyDomain ){
419 Trace("rsi-debug") << "This is an empty domain, increment." << std::endl;
420 return increment();
421 }else{
422 return i;
423 }
424 }
425
426 int RepSetIterator::increment(){
427 if( !isFinished() ){
428 return increment2( (int)d_index.size()-1 );
429 }else{
430 return -1;
431 }
432 }
433
434 bool RepSetIterator::isFinished(){
435 return d_index.empty();
436 }
437
438 Node RepSetIterator::getCurrentTerm( int v ){
439 Trace("rsi-debug") << "rsi : get term " << v << ", index order = " << d_index_order[v] << std::endl;
440 int ii = d_index_order[v];
441 int curr = d_index[ii];
442 if( d_enum_type[v]==ENUM_DOMAIN_ELEMENTS ){
443 TypeNode tn = d_types[v];
444 Assert( d_rep_set->d_type_reps.find( tn )!=d_rep_set->d_type_reps.end() );
445 Assert( 0<=d_domain[v][curr] && d_domain[v][curr]<(int)d_rep_set->d_type_reps[tn].size() );
446 return d_rep_set->d_type_reps[tn][d_domain[v][curr]];
447 }else if( d_enum_type[v]==ENUM_SET_MEMBERS ){
448 Assert( 0<=curr && curr<(int)d_setm_bounds[v].size() );
449 return d_setm_bounds[v][curr];
450 }else{
451 Trace("rsi-debug") << "Get, with offset : " << v << " " << d_lower_bounds[v] << " " << curr << std::endl;
452 Assert( !d_lower_bounds[v].isNull() );
453 Node t = NodeManager::currentNM()->mkNode(PLUS, d_lower_bounds[v], NodeManager::currentNM()->mkConst( Rational(curr) ) );
454 t = Rewriter::rewrite( t );
455 return t;
456 }
457 }
458
459 void RepSetIterator::debugPrint( const char* c ){
460 for( unsigned v=0; v<d_index.size(); v++ ){
461 Debug( c ) << v << " : " << getCurrentTerm( v ) << std::endl;
462 }
463 }
464
465 void RepSetIterator::debugPrintSmall( const char* c ){
466 Debug( c ) << "RI: ";
467 for( unsigned v=0; v<d_index.size(); v++ ){
468 Debug( c ) << v << ": " << getCurrentTerm( v ) << " ";
469 }
470 Debug( c ) << std::endl;
471 }
472