/********************* */ /*! \file rep_set.cpp ** \verbatim ** Original author: Andrew Reynolds ** Major contributors: Morgan Deters ** Minor contributors (to current version): none ** This file is part of the CVC4 project. ** Copyright (c) 2009-2013 New York University and The University of Iowa ** See the file COPYING in the top-level source directory for licensing ** information.\endverbatim ** ** \brief Implementation of representative set **/ #include "theory/rep_set.h" #include "theory/type_enumerator.h" #include "theory/quantifiers/bounded_integers.h" using namespace std; using namespace CVC4; using namespace CVC4::kind; using namespace CVC4::context; using namespace CVC4::theory; void RepSet::clear(){ d_type_reps.clear(); d_type_complete.clear(); d_tmap.clear(); } int RepSet::getNumRepresentatives( TypeNode tn ) const{ std::map< TypeNode, std::vector< Node > >::const_iterator it = d_type_reps.find( tn ); if( it!=d_type_reps.end() ){ return (int)it->second.size(); }else{ return 0; } } void RepSet::add( Node n ){ TypeNode t = n.getType(); d_tmap[ n ] = (int)d_type_reps[t].size(); d_type_reps[t].push_back( n ); } int RepSet::getIndexFor( Node n ) const { std::map< Node, int >::const_iterator it = d_tmap.find( n ); if( it!=d_tmap.end() ){ return it->second; }else{ return -1; } } void RepSet::complete( TypeNode t ){ if( d_type_complete.find( t )==d_type_complete.end() ){ d_type_complete[t] = true; TypeEnumerator te(t); while( !te.isFinished() ){ Node n = *te; if( std::find( d_type_reps[t].begin(), d_type_reps[t].end(), n )==d_type_reps[t].end() ){ add( n ); } ++te; } for( size_t i=0; i >::iterator it = d_type_reps.begin(); it != d_type_reps.end(); ++it ){ out << it->first << " : " << std::endl; for( int i=0; i<(int)it->second.size(); i++ ){ out << " " << i << ": " << it->second[i] << std::endl; } } #else for( std::map< TypeNode, std::vector< Node > >::iterator it = d_type_reps.begin(); it != d_type_reps.end(); ++it ){ if( !it->first.isFunction() && !it->first.isPredicate() ){ out << "(" << it->first << " " << it->second.size(); out << " ("; for( int i=0; i<(int)it->second.size(); i++ ){ if( i>0 ){ out << " "; } out << it->second[i]; } out << ")"; out << ")" << std::endl; } } #endif } RepSetIterator::RepSetIterator( QuantifiersEngine * qe, RepSet* rs ) : d_qe(qe), d_rep_set( rs ){ d_incomplete = false; } int RepSetIterator::domainSize( int i ) { Assert(i>=0); if( d_enum_type[i]==ENUM_DOMAIN_ELEMENTS ){ return d_domain[i].size(); }else{ return d_domain[i][0]; } } bool RepSetIterator::setQuantifier( Node f ){ Trace("rsi") << "Make rsi for " << f << std::endl; Assert( d_types.empty() ); //store indicies for( size_t i=0; ihasType( tn ) ){ Node var = NodeManager::currentNM()->mkSkolem( "repSet_$$", tn, "is a variable created by the RepSetIterator" ); Trace("mkVar") << "RepSetIterator:: Make variable " << var << " : " << tn << std::endl; d_rep_set->add( var ); } }else if( tn.isInteger() ){ bool inc = false; //check if it is bound if( d_owner.getKind()==FORALL && d_qe && d_qe->getBoundedIntegers() ){ if( d_qe->getBoundedIntegers()->isBoundVar( d_owner, d_owner[0][i] ) ){ Trace("bound-int-rsi") << "Rep set iterator: variable #" << i << " is bounded integer." << std::endl; d_enum_type.push_back( ENUM_RANGE ); }else{ inc = true; } }else{ inc = true; } if( inc ){ //check if it is otherwise bound if( d_bounds[0].find(i)!=d_bounds[0].end() && d_bounds[1].find(i)!=d_bounds[1].end() ){ Trace("bound-int-rsi") << "Rep set iterator: variable #" << i << " is bounded." << std::endl; d_enum_type.push_back( ENUM_RANGE ); }else{ Trace("fmf-incomplete") << "Incomplete because of integer quantification of " << d_owner[0][i] << "." << std::endl; d_incomplete = true; } } //enumerate if the sort is reasonably small, the upper bound of 1000 is chosen arbitrarily for now }else if( tn.getCardinality().isFinite() && tn.getCardinality().getFiniteCardinality().toUnsignedInt()<=1000 ){ d_rep_set->complete( tn ); }else{ Trace("fmf-incomplete") << "Incomplete because of quantification of type " << tn << std::endl; d_incomplete = true; } if( d_enum_type.size()<=i ){ d_enum_type.push_back( ENUM_DOMAIN_ELEMENTS ); if( d_rep_set->hasType( tn ) ){ for( size_t j=0; jd_type_reps[tn].size(); j++ ){ d_domain[i].push_back( j ); } }else{ return false; } } } //must set a variable index order based on bounded integers if (d_owner.getKind()==FORALL && d_qe && d_qe->getBoundedIntegers()) { Trace("bound-int-rsi") << "Calculating variable order..." << std::endl; std::vector< int > varOrder; for( unsigned i=0; igetBoundedIntegers()->getNumBoundVars(d_owner); i++ ){ varOrder.push_back(d_qe->getBoundedIntegers()->getBoundVarNum(d_owner,i)); } for( unsigned i=0; igetBoundedIntegers()->isBoundVar(d_owner, d_owner[0][i])) { varOrder.push_back(i); } } Trace("bound-int-rsi") << "Variable order : "; for( unsigned i=0; i indexOrder; indexOrder.resize(varOrder.size()); for( unsigned i=0; i& indexOrder ){ d_index_order.clear(); d_index_order.insert( d_index_order.begin(), indexOrder.begin(), indexOrder.end() ); //make the d_var_order mapping for( int i=0; i<(int)d_index_order.size(); i++ ){ d_var_order[d_index_order[i]] = i; } } /* void RepSetIterator::setDomain( std::vector< RepDomain >& domain ){ d_domain.clear(); d_domain.insert( d_domain.begin(), domain.begin(), domain.end() ); //we are done if a domain is empty for( int i=0; i<(int)d_domain.size(); i++ ){ if( d_domain[i].empty() ){ d_index.clear(); } } } */ bool RepSetIterator::resetIndex( int i, bool initial ) { d_index[i] = 0; int ii = d_index_order[i]; Trace("bound-int-rsi") << "Reset " << i << " " << ii << " " << initial << std::endl; //determine the current range if( d_enum_type[ii]==ENUM_RANGE ){ if( initial || !d_qe->getBoundedIntegers()->isGroundRange( d_owner, d_owner[0][ii] ) ){ Trace("bound-int-rsi") << "Getting range of " << d_owner[0][ii] << std::endl; Node l, u; d_qe->getBoundedIntegers()->getBoundValues( d_owner, d_owner[0][ii], this, l, u ); if( l.isNull() || u.isNull() ){ //failed, abort the iterator d_index.clear(); return false; }else{ Trace("bound-int-rsi") << "Can limit bounds of " << d_owner[0][ii] << " to " << l << "..." << u << std::endl; for( unsigned b=0; b<2; b++ ){ if( d_bounds[b].find(ii)!=d_bounds[b].end() ){ Trace("bound-int-rsi") << "May further limit bound(" << b << ") based on " << d_bounds[b][ii] << std::endl; if( b==0 && d_bounds[b][ii].getConst() > l.getConst() ){ l = d_bounds[b][ii]; }else if( b==1 && d_bounds[b][ii].getConst() <= u.getConst() ){ u = NodeManager::currentNM()->mkNode( MINUS, d_bounds[b][ii], NodeManager::currentNM()->mkConst( Rational(1) ) ); u = Rewriter::rewrite( u ); } } } Node range = Rewriter::rewrite( NodeManager::currentNM()->mkNode( MINUS, u, l ) ); Node ra = Rewriter::rewrite( NodeManager::currentNM()->mkNode( LEQ, range, NodeManager::currentNM()->mkConst( Rational( 9999 ) ) ) ); d_domain[ii].clear(); d_lower_bounds[ii] = l; if( ra==NodeManager::currentNM()->mkConst(true) ){ long rr = range.getConst().getNumerator().getLong()+1; Trace("bound-int-rsi") << "Actual bound range is " << rr << std::endl; d_domain[ii].push_back( (int)rr ); }else{ Trace("fmf-incomplete") << "Incomplete because of integer quantification, bounds are too big for " << d_owner[0][ii] << "." << std::endl; d_incomplete = true; d_domain[ii].push_back( 0 ); } } }else{ Trace("bound-int-rsi") << d_owner[0][ii] << " has ground range, skip." << std::endl; } } return true; } int RepSetIterator::increment2( int counter ){ Assert( !isFinished() ); #ifdef DISABLE_EVAL_SKIP_MULTIPLE counter = (int)d_index.size()-1; #endif //increment d_index if( counter>=0){ Trace("rsi-debug") << "domain size of " << counter << " is " << domainSize(counter) << std::endl; } while( counter>=0 && d_index[counter]>=(int)(domainSize(counter)-1) ){ counter--; if( counter>=0){ Trace("rsi-debug") << "domain size of " << counter << " is " << domainSize(counter) << std::endl; } } if( counter==-1 ){ d_index.clear(); }else{ d_index[counter]++; bool emptyDomain = false; for( int i=(int)d_index.size()-1; i>counter; i-- ){ if (!resetIndex(i)){ break; }else if( domainSize(i)<=0 ){ emptyDomain = true; } } if( emptyDomain ){ Trace("rsi-debug") << "This is an empty domain, increment again." << std::endl; return increment(); } } return counter; } int RepSetIterator::increment(){ if( !isFinished() ){ return increment2( (int)d_index.size()-1 ); }else{ return -1; } } bool RepSetIterator::isFinished(){ return d_index.empty(); } Node RepSetIterator::getTerm( int i ){ int index = d_index_order[i]; if( d_enum_type[index]==ENUM_DOMAIN_ELEMENTS ){ TypeNode tn = d_types[index]; Assert( d_rep_set->d_type_reps.find( tn )!=d_rep_set->d_type_reps.end() ); return d_rep_set->d_type_reps[tn][d_domain[index][d_index[index]]]; }else{ Trace("rsi-debug") << index << " " << d_lower_bounds[index] << " " << d_index[index] << std::endl; Node t = NodeManager::currentNM()->mkNode(PLUS, d_lower_bounds[index], NodeManager::currentNM()->mkConst( Rational(d_index[index]) ) ); t = Rewriter::rewrite( t ); return t; } } void RepSetIterator::debugPrint( const char* c ){ for( int i=0; i<(int)d_index.size(); i++ ){ Debug( c ) << i << " : " << d_index[i] << " : " << getTerm( i ) << std::endl; } } void RepSetIterator::debugPrintSmall( const char* c ){ Debug( c ) << "RI: "; for( int i=0; i<(int)d_index.size(); i++ ){ Debug( c ) << d_index[i] << ": " << getTerm( i ) << " "; } Debug( c ) << std::endl; }