//FIXME: need to ensure that theory enumerators exist for each sort Node TheoryModel::getNewDomainValue( TypeNode tn ){ if( tn.isSort() ){ return Node::null(); }else{ TypeEnumerator te(tn); while( !te.isFinished() ){ Node r = *te; if(Debug.isOn("getNewDomainValue")) { Debug("getNewDomainValue") << "getNewDomainValue( " << tn << ")" << endl; Debug("getNewDomainValue") << "+ TypeEnumerator gave: " << r << endl; Debug("getNewDomainValue") << "+ d_type_reps are:"; for(vector<Node>::const_iterator i = d_rep_set.d_type_reps[tn].begin(); i != d_rep_set.d_type_reps[tn].end(); ++i) { Debug("getNewDomainValue") << " " << *i; } Debug("getNewDomainValue") << endl; } if( std::find(d_rep_set.d_type_reps[tn].begin(), d_rep_set.d_type_reps[tn].end(), r) ==d_rep_set.d_type_reps[tn].end() ) { Debug("getNewDomainValue") << "+ it's new, so returning " << r << endl; return r; } ++te; } return Node::null(); } }
void FirstOrderModel::initializeModelForTerm( Node n ){ if( n.getKind()==APPLY_UF ){ Node op = n.getOperator(); if( d_uf_model_tree.find( op )==d_uf_model_tree.end() ){ TypeNode tn = op.getType(); tn = tn[ (int)tn.getNumChildren()-1 ]; //only generate models for predicates and functions with uninterpreted range types if( tn==NodeManager::currentNM()->booleanType() || tn.isSort() ){ d_uf_model_tree[ op ] = uf::UfModelTree( op ); d_uf_model_gen[ op ].clear(); } } } /* if( n.getType().isArray() ){ while( n.getKind()==STORE ){ n = n[0]; } Node nn = getRepresentative( n ); if( d_array_model.find( nn )==d_array_model.end() ){ d_array_model[nn] = arrays::ArrayModel( nn, this ); } } */ for( int i=0; i<(int)n.getNumChildren(); i++ ){ initializeModelForTerm( n[i] ); } }
bool ModelEngine::considerQuantifiedFormula( Node q ) { if( !d_quantEngine->getModelBuilder()->isQuantifierActive( q ) ){ //!d_quantEngine->getModel()->isQuantifierActive( q ); return false; }else{ if( options::fmfEmptySorts() ){ for( unsigned i=0; i<q[0].getNumChildren(); i++ ){ TypeNode tn = q[0][i].getType(); //we are allowed to assume the type is empty if( tn.isSort() && d_quantEngine->getModel()->d_rep_set.getNumRelevantGroundReps( tn )==0 ){ Trace("model-engine-debug") << "Empty domain quantified formula : " << q << std::endl; return false; } } }else if( options::fmfFunWellDefinedRelevant() ){ if( q[0].getNumChildren()==1 ){ TypeNode tn = q[0][0].getType(); if( tn.getAttribute(AbsTypeFunDefAttribute()) ){ //we are allowed to assume the introduced type is empty if( d_quantEngine->getModel()->d_rep_set.getNumRelevantGroundReps( tn )==0 ){ Trace("model-engine-debug") << "Irrelevant function definition : " << q << std::endl; return false; } } } } return true; } }
/** get cardinality for sort */ Cardinality TheoryModel::getCardinality( Type t ) const{ TypeNode tn = TypeNode::fromType( t ); //for now, we only handle cardinalities for uninterpreted sorts if( tn.isSort() ){ if( d_rep_set.hasType( tn ) ){ return Cardinality( d_rep_set.getNumRepresentatives( tn ) ); }else{ return Cardinality( CardinalityUnknown() ); } }else{ return Cardinality( CardinalityUnknown() ); } }
bool TermEnumeration::isClosedEnumerableType(TypeNode tn) { std::unordered_map<TypeNode, bool, TypeNodeHashFunction>::iterator it = d_typ_closed_enum.find(tn); if (it == d_typ_closed_enum.end()) { d_typ_closed_enum[tn] = true; bool ret = true; if (tn.isArray() || tn.isSort() || tn.isCodatatype() || tn.isFunction()) { ret = false; } else if (tn.isSet()) { ret = isClosedEnumerableType(tn.getSetElementType()); } else if (tn.isDatatype()) { const Datatype& dt = ((DatatypeType)(tn).toType()).getDatatype(); for (unsigned i = 0; i < dt.getNumConstructors(); i++) { for (unsigned j = 0; j < dt[i].getNumArgs(); j++) { TypeNode ctn = TypeNode::fromType(dt[i][j].getRangeType()); if (tn != ctn && !isClosedEnumerableType(ctn)) { ret = false; break; } } if (!ret) { break; } } } // other parametric sorts go here d_typ_closed_enum[tn] = ret; return ret; } else { return it->second; } }
void ModelEngine::registerQuantifier( Node f ){ if( Trace.isOn("fmf-warn") ){ bool canHandle = true; for( unsigned i=0; i<f[0].getNumChildren(); i++ ){ TypeNode tn = f[0][i].getType(); if( !tn.isSort() ){ if( !tn.getCardinality().isFinite() ){ if( tn.isInteger() ){ if( !options::fmfBoundInt() ){ canHandle = false; } }else{ canHandle = false; } } } } if( !canHandle ){ Trace("fmf-warn") << "Warning : Model Engine : may not be able to answer SAT because of formula : " << f << std::endl; } } }
bool RepSetIterator::initialize( RepBoundExt* rext ){ Trace("rsi") << "Initialize rep set iterator..." << std::endl; for( unsigned v=0; v<d_types.size(); v++ ){ d_index.push_back( 0 ); //store default index order d_index_order.push_back( v ); d_var_order[v] = v; //store default domain //d_domain.push_back( RepDomain() ); d_domain_elements.push_back( std::vector< Node >() ); TypeNode tn = d_types[v]; Trace("rsi") << "Var #" << v << " is type " << tn << "..." << std::endl; if( tn.isSort() ){ //must ensure uninterpreted type is non-empty. if( !d_rep_set->hasType( tn ) ){ //FIXME: // terms in rep_set are now constants which mapped to terms through TheoryModel // thus, should introduce a constant and a term. for now, just a term. //Node c = d_qe->getTermDatabase()->getEnumerateTerm( tn, 0 ); Node var = d_qe->getModel()->getSomeDomainElement( tn ); Trace("mkVar") << "RepSetIterator:: Make variable " << var << " : " << tn << std::endl; d_rep_set->add( tn, var ); } } bool inc = true; //check if it is externally bound if( rext && rext->setBound( d_owner, v, tn, d_domain_elements[v] ) ){ d_enum_type.push_back( ENUM_DEFAULT ); inc = false; //builtin: check if it is bound by bounded integer module }else if( d_owner.getKind()==FORALL && d_qe && d_qe->getBoundedIntegers() ){ if( d_qe->getBoundedIntegers()->isBoundVar( d_owner, d_owner[0][v] ) ){ unsigned bvt = d_qe->getBoundedIntegers()->getBoundVarType( d_owner, d_owner[0][v] ); if( bvt!=quantifiers::BoundedIntegers::BOUND_FINITE ){ d_enum_type.push_back( ENUM_BOUND_INT ); inc = false; }else{ //will treat in default way } } } if( !tn.isSort() ){ if( inc ){ if( d_qe->getTermDatabase()->mayComplete( tn ) ){ Trace("rsi") << " do complete, since cardinality is small (" << tn.getCardinality() << ")..." << std::endl; d_rep_set->complete( tn ); //must have succeeded Assert( d_rep_set->hasType( tn ) ); }else{ Trace("rsi") << " variable cannot be bounded." << std::endl; Trace("fmf-incomplete") << "Incomplete because of quantification of type " << tn << std::endl; d_incomplete = true; } } } //if we have yet to determine the type of enumeration if( d_enum_type.size()<=v ){ if( d_rep_set->hasType( tn ) ){ d_enum_type.push_back( ENUM_DEFAULT ); for( unsigned j=0; j<d_rep_set->d_type_reps[tn].size(); j++ ){ //d_domain[v].push_back( j ); d_domain_elements[v].push_back( d_rep_set->d_type_reps[tn][j] ); } }else{ Assert( d_incomplete ); 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; i<d_qe->getBoundedIntegers()->getNumBoundVars( d_owner ); i++ ){ Node v = d_qe->getBoundedIntegers()->getBoundVar( d_owner, i ); Trace("bound-int-rsi") << " bound var #" << i << " is " << v << std::endl; varOrder.push_back( d_qe->getTermDatabase()->getVariableNum( d_owner, v ) ); } for( unsigned i=0; i<d_owner[0].getNumChildren(); i++) { if( !d_qe->getBoundedIntegers()->isBoundVar(d_owner, d_owner[0][i])) { varOrder.push_back(i); } } Trace("bound-int-rsi") << "Variable order : "; for( unsigned i=0; i<varOrder.size(); i++) { Trace("bound-int-rsi") << varOrder[i] << " "; } Trace("bound-int-rsi") << std::endl; std::vector< int > indexOrder; indexOrder.resize(varOrder.size()); for( unsigned i=0; i<varOrder.size(); i++){ indexOrder[varOrder[i]] = i; } Trace("bound-int-rsi") << "Will use index order : "; for( unsigned i=0; i<indexOrder.size(); i++) { Trace("bound-int-rsi") << indexOrder[i] << " "; } Trace("bound-int-rsi") << std::endl; setIndexOrder( indexOrder ); } //now reset the indices do_reset_increment( -1, true ); return true; }
void BoundedIntegers::registerQuantifier( Node f ) { Trace("bound-int") << "Register quantifier " << f << std::endl; bool success; do{ std::map< Node, unsigned > bound_lit_type_map; std::map< int, std::map< Node, Node > > bound_lit_map; std::map< int, std::map< Node, bool > > bound_lit_pol_map; std::map< int, std::map< Node, Node > > bound_int_range_term; success = false; process( f, f[1], true, bound_lit_type_map, bound_lit_map, bound_lit_pol_map, bound_int_range_term ); //for( std::map< Node, Node >::iterator it = d_bounds[0][f].begin(); it != d_bounds[0][f].end(); ++it ){ for( std::map< Node, unsigned >::iterator it = bound_lit_type_map.begin(); it != bound_lit_type_map.end(); ++it ){ Node v = it->first; if( !isBound( f, v ) ){ bool setBoundVar = false; if( it->second==BOUND_INT_RANGE ){ //must have both if( bound_lit_map[0].find( v )!=bound_lit_map[0].end() && bound_lit_map[1].find( v )!=bound_lit_map[1].end() ){ setBoundedVar( f, v, BOUND_INT_RANGE ); setBoundVar = true; success = true; for( unsigned b=0; b<2; b++ ){ //set the bounds Assert( bound_int_range_term[b].find( v )!=bound_int_range_term[b].end() ); d_bounds[b][f][v] = bound_int_range_term[b][v]; } Node r = NodeManager::currentNM()->mkNode( MINUS, d_bounds[1][f][v], d_bounds[0][f][v] ); d_range[f][v] = Rewriter::rewrite( r ); Trace("bound-int") << "Variable " << v << " is bound because of int range literals " << bound_lit_map[0][v] << " and " << bound_lit_map[1][v] << std::endl; } }else if( it->second==BOUND_SET_MEMBER ){ setBoundedVar( f, v, BOUND_SET_MEMBER ); setBoundVar = true; d_setm_range[f][v] = bound_lit_map[0][v][1]; Trace("bound-int") << "Variable " << v << " is bound because of set membership literal " << bound_lit_map[0][v] << std::endl; } if( setBoundVar ){ //set Attributes on literals for( unsigned b=0; b<2; b++ ){ if( bound_lit_map[b].find( v )!=bound_lit_map[b].end() ){ Assert( bound_lit_pol_map[b].find( v )!=bound_lit_pol_map[b].end() ); BoundIntLitAttribute bila; bound_lit_map[b][v].setAttribute( bila, bound_lit_pol_map[b][v] ? 1 : 0 ); }else{ Assert( it->second!=BOUND_INT_RANGE ); } } } } } }while( success ); Trace("bound-int") << "Bounds are : " << std::endl; for( unsigned i=0; i<d_set[f].size(); i++) { Node v = d_set[f][i]; if( d_bound_type[f][v]==BOUND_INT_RANGE ){ Trace("bound-int") << " " << d_bounds[0][f][v] << " <= " << v << " <= " << d_bounds[1][f][v] << " (range is " << d_range[f][v] << ")" << std::endl; }else if( d_bound_type[f][v]==BOUND_SET_MEMBER ){ Trace("bound-int") << " " << v << " in " << d_setm_range[f][v] << std::endl; } } bool bound_success = true; for( unsigned i=0; i<f[0].getNumChildren(); i++) { if( d_bound_type[f].find( f[0][i] )==d_bound_type[f].end() ){ TypeNode tn = f[0][i].getType(); if( !tn.isSort() && !getTermDatabase()->mayComplete( tn ) ){ Trace("bound-int-warn") << "Warning : Bounded Integers : Due to quantification on " << f[0][i] << ", could not find bounds for " << f << std::endl; bound_success = false; break; } } } if( bound_success ){ d_bound_quants.push_back( f ); for( unsigned i=0; i<d_set[f].size(); i++) { Node v = d_set[f][i]; if( d_bound_type[f][v]==BOUND_INT_RANGE || d_bound_type[f][v]==BOUND_SET_MEMBER ){ Node r; if( d_bound_type[f][v]==BOUND_INT_RANGE ){ r = d_range[f][v]; }else if( d_bound_type[f][v]==BOUND_SET_MEMBER ){ r = NodeManager::currentNM()->mkNode( CARD, d_setm_range[f][v] ); } bool isProxy = false; if( r.hasBoundVar() ){ //introduce a new bound Node new_range = NodeManager::currentNM()->mkSkolem( "bir", r.getType(), "bound for term" ); d_nground_range[f][v] = d_range[f][v]; d_range[f][v] = new_range; r = new_range; isProxy = true; } if( !r.isConst() ){ if( std::find(d_ranges.begin(), d_ranges.end(), r)==d_ranges.end() ){ Trace("bound-int") << "For " << v << ", bounded Integer Module will try to minimize : " << r << std::endl; d_ranges.push_back( r ); d_rms[r] = new IntRangeModel( this, r, d_quantEngine->getSatContext(), d_quantEngine->getUserContext(), isProxy ); d_rms[r]->initialize(); } } } } } }
bool RepSetIterator::initialize(){ for( size_t i=0; i<d_types.size(); i++ ){ d_index.push_back( 0 ); //store default index order d_index_order.push_back( i ); d_var_order[i] = i; //store default domain d_domain.push_back( RepDomain() ); TypeNode tn = d_types[i]; if( tn.isSort() ){ if( !d_rep_set->hasType( 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( tn, 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().isLargeFinite() && 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; j<d_rep_set->d_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; i<d_qe->getBoundedIntegers()->getNumBoundVars(d_owner); i++ ){ varOrder.push_back(d_qe->getBoundedIntegers()->getBoundVarNum(d_owner,i)); } for( unsigned i=0; i<d_owner[0].getNumChildren(); i++) { if( !d_qe->getBoundedIntegers()->isBoundVar(d_owner, d_owner[0][i])) { varOrder.push_back(i); } } Trace("bound-int-rsi") << "Variable order : "; for( unsigned i=0; i<varOrder.size(); i++) { Trace("bound-int-rsi") << varOrder[i] << " "; } Trace("bound-int-rsi") << std::endl; std::vector< int > indexOrder; indexOrder.resize(varOrder.size()); for( unsigned i=0; i<varOrder.size(); i++){ indexOrder[varOrder[i]] = i; } Trace("bound-int-rsi") << "Will use index order : "; for( unsigned i=0; i<indexOrder.size(); i++) { Trace("bound-int-rsi") << indexOrder[i] << " "; } Trace("bound-int-rsi") << std::endl; setIndexOrder(indexOrder); } //now reset the indices for (unsigned i=0; i<d_index.size(); i++) { if (!resetIndex(i, true)){ break; } } return true; }
void SharedTermsVisitor::visit(TNode current, TNode parent) { Debug("register") << "SharedTermsVisitor::visit(" << current << "," << parent << ")" << std::endl; if (Debug.isOn("register::internal")) { Debug("register::internal") << toString() << std::endl; } // Get the theories of the terms TheoryId currentTheoryId = Theory::theoryOf(current); TheoryId parentTheoryId = Theory::theoryOf(parent); #if 0 bool useType = current != parent && currentTheoryId != parentTheoryId; #else // Should we use the theory of the type bool useType = false; TheoryId typeTheoryId = THEORY_LAST; if (current != parent) { if (currentTheoryId != parentTheoryId) { // If enclosed by different theories it's shared -- in read(a, f(a)) f(a) should be shared with integers TypeNode type = current.getType(); useType = true; typeTheoryId = Theory::theoryOf(type); } else { TypeNode type = current.getType(); typeTheoryId = Theory::theoryOf(type); if (typeTheoryId != currentTheoryId) { if (options::finiteModelFind() && type.isSort()) { // We're looking for finite models useType = true; } else { Cardinality card = type.getCardinality(); if (card.isFinite()) { useType = true; } } } } } #endif Theory::Set visitedTheories = d_visited[current]; Debug("register::internal") << "SharedTermsVisitor::visit(" << current << "," << parent << "): previously registered with " << Theory::setToString(visitedTheories) << std::endl; if (!Theory::setContains(currentTheoryId, visitedTheories)) { visitedTheories = Theory::setInsert(currentTheoryId, visitedTheories); Debug("register::internal") << "SharedTermsVisitor::visit(" << current << "," << parent << "): adding " << currentTheoryId << std::endl; } if (!Theory::setContains(parentTheoryId, visitedTheories)) { visitedTheories = Theory::setInsert(parentTheoryId, visitedTheories); Debug("register::internal") << "SharedTermsVisitor::visit(" << current << "," << parent << "): adding " << parentTheoryId << std::endl; } if (useType) { //////TheoryId typeTheoryId = Theory::theoryOf(current.getType()); if (!Theory::setContains(typeTheoryId, visitedTheories)) { visitedTheories = Theory::setInsert(typeTheoryId, visitedTheories); Debug("register::internal") << "SharedTermsVisitor::visit(" << current << "," << parent << "): adding " << typeTheoryId << std::endl; } } Debug("register::internal") << "SharedTermsVisitor::visit(" << current << "," << parent << "): now registered with " << Theory::setToString(visitedTheories) << std::endl; // Record the new theories that we visited d_visited[current] = visitedTheories; // If there is more than two theories and a new one has been added notify the shared terms database if (Theory::setDifference(visitedTheories, Theory::setInsert(currentTheoryId))) { d_sharedTerms.addSharedTerm(d_atom, current, visitedTheories); } Assert(d_visited.find(current) != d_visited.end()); Assert(alreadyVisited(current, parent)); }
bool SharedTermsVisitor::alreadyVisited(TNode current, TNode parent) const { Debug("register::internal") << "SharedTermsVisitor::alreadyVisited(" << current << "," << parent << ")" << std::endl; if( ( parent.getKind() == kind::FORALL || parent.getKind() == kind::EXISTS || parent.getKind() == kind::REWRITE_RULE /*|| parent.getKind() == kind::CARDINALITY_CONSTRAINT*/ ) && current != parent ) { Debug("register::internal") << "quantifier:true" << std::endl; return true; } TNodeVisitedMap::const_iterator find = d_visited.find(current); // If node is not visited at all, just return false if (find == d_visited.end()) { Debug("register::internal") << "1:false" << std::endl; return false; } Theory::Set theories = (*find).second; TheoryId currentTheoryId = Theory::theoryOf(current); TheoryId parentTheoryId = Theory::theoryOf(parent); // Should we use the theory of the type #if 0 bool useType = current != parent && currentTheoryId != parentTheoryId; #else bool useType = false; TheoryId typeTheoryId = THEORY_LAST; if (current != parent) { if (currentTheoryId != parentTheoryId) { // If enclosed by different theories it's shared -- in read(a, f(a)) f(a) should be shared with integers TypeNode type = current.getType(); useType = true; typeTheoryId = Theory::theoryOf(type); } else { TypeNode type = current.getType(); typeTheoryId = Theory::theoryOf(type); if (typeTheoryId != currentTheoryId) { if (options::finiteModelFind() && type.isSort()) { // We're looking for finite models useType = true; } else { Cardinality card = type.getCardinality(); if (card.isFinite()) { useType = true; } } } } } #endif if (Theory::setContains(currentTheoryId, theories)) { if (Theory::setContains(parentTheoryId, theories)) { if (useType) { ////TheoryId typeTheoryId = Theory::theoryOf(current.getType()); return Theory::setContains(typeTheoryId, theories); } else { return true; } } else { return false; } } else { return false; } }