// checks whether a type is closed enumerable and is reasonably small enough (<1000) // such that all of its domain elements can be enumerated bool TermEnumeration::mayComplete(TypeNode tn) { std::unordered_map<TypeNode, bool, TypeNodeHashFunction>::iterator it = d_may_complete.find(tn); if (it == d_may_complete.end()) { bool mc = false; if (isClosedEnumerableType(tn) && tn.getCardinality().isFinite() && !tn.getCardinality().isLargeFinite()) { Node card = NodeManager::currentNM()->mkConst( Rational(tn.getCardinality().getFiniteCardinality())); Node oth = NodeManager::currentNM()->mkConst(Rational(1000)); Node eq = NodeManager::currentNM()->mkNode(LEQ, card, oth); eq = Rewriter::rewrite(eq); mc = eq.isConst() && eq.getConst<bool>(); } d_may_complete[tn] = mc; return mc; } 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 TheoryEngineModelBuilder::buildModel(Model* m, bool fullModel) { TheoryModel* tm = (TheoryModel*)m; // buildModel with fullModel = true should only be called once in any context Assert(!tm->d_modelBuilt); tm->d_modelBuilt = fullModel; // Reset model tm->reset(); // Collect model info from the theories Trace("model-builder") << "TheoryEngineModelBuilder: Collect model info..." << std::endl; d_te->collectModelInfo(tm, fullModel); // Loop through all terms and make sure that assignable sub-terms are in the equality engine eq::EqClassesIterator eqcs_i = eq::EqClassesIterator( &tm->d_equalityEngine ); { NodeSet cache; for ( ; !eqcs_i.isFinished(); ++eqcs_i) { eq::EqClassIterator eqc_i = eq::EqClassIterator((*eqcs_i), &tm->d_equalityEngine); for ( ; !eqc_i.isFinished(); ++eqc_i) { checkTerms(*eqc_i, tm, cache); } } } Trace("model-builder") << "Collect representatives..." << std::endl; // Process all terms in the equality engine, store representatives for each EC std::map< Node, Node > assertedReps, constantReps; TypeSet typeConstSet, typeRepSet, typeNoRepSet; std::set< TypeNode > allTypes; eqcs_i = eq::EqClassesIterator(&tm->d_equalityEngine); for ( ; !eqcs_i.isFinished(); ++eqcs_i) { // eqc is the equivalence class representative Node eqc = (*eqcs_i); Trace("model-builder") << "Processing EC: " << eqc << endl; Assert(tm->d_equalityEngine.getRepresentative(eqc) == eqc); TypeNode eqct = eqc.getType(); Assert(assertedReps.find(eqc) == assertedReps.end()); Assert(constantReps.find(eqc) == constantReps.end()); // Loop through terms in this EC Node rep, const_rep; eq::EqClassIterator eqc_i = eq::EqClassIterator(eqc, &tm->d_equalityEngine); for ( ; !eqc_i.isFinished(); ++eqc_i) { Node n = *eqc_i; Trace("model-builder") << " Processing Term: " << n << endl; // Record as rep if this node was specified as a representative if (tm->d_reps.find(n) != tm->d_reps.end()){ Assert(rep.isNull()); rep = tm->d_reps[n]; Assert(!rep.isNull() ); Trace("model-builder") << " Rep( " << eqc << " ) = " << rep << std::endl; } // Record as const_rep if this node is constant if (n.isConst()) { Assert(const_rep.isNull()); const_rep = n; Trace("model-builder") << " ConstRep( " << eqc << " ) = " << const_rep << std::endl; } //model-specific processing of the term tm->addTerm(n); } // Assign representative for this EC if (!const_rep.isNull()) { // Theories should not specify a rep if there is already a constant in the EC Assert(rep.isNull() || rep == const_rep); constantReps[eqc] = const_rep; typeConstSet.add(eqct.getBaseType(), const_rep); } else if (!rep.isNull()) { assertedReps[eqc] = rep; typeRepSet.add(eqct.getBaseType(), eqc); allTypes.insert(eqct); } else { typeNoRepSet.add(eqct, eqc); allTypes.insert(eqct); } } // Need to ensure that each EC has a constant representative. Trace("model-builder") << "Processing EC's..." << std::endl; TypeSet::iterator it; set<TypeNode>::iterator type_it; set<Node>::iterator i, i2; bool changed, unassignedAssignable, assignOne = false; set<TypeNode> evaluableSet; // Double-fixed-point loop // Outer loop handles a special corner case (see code at end of loop for details) for (;;) { // Inner fixed-point loop: we are trying to learn constant values for every EC. Each time through this loop, we process all of the // types by type and may learn some new EC values. EC's in one type may depend on EC's in another type, so we need a fixed-point loop // to ensure that we learn as many EC values as possible do { changed = false; unassignedAssignable = false; evaluableSet.clear(); // Iterate over all types we've seen for (type_it = allTypes.begin(); type_it != allTypes.end(); ++type_it) { TypeNode t = *type_it; TypeNode tb = t.getBaseType(); set<Node>* noRepSet = typeNoRepSet.getSet(t); // 1. Try to evaluate the EC's in this type if (noRepSet != NULL && !noRepSet->empty()) { Trace("model-builder") << " Eval phase, working on type: " << t << endl; bool assignable, evaluable, evaluated; d_normalizedCache.clear(); for (i = noRepSet->begin(); i != noRepSet->end(); ) { i2 = i; ++i; assignable = false; evaluable = false; evaluated = false; eq::EqClassIterator eqc_i = eq::EqClassIterator(*i2, &tm->d_equalityEngine); for ( ; !eqc_i.isFinished(); ++eqc_i) { Node n = *eqc_i; if (isAssignable(n)) { assignable = true; } else { evaluable = true; Node normalized = normalize(tm, n, constantReps, true); if (normalized.isConst()) { typeConstSet.add(tb, normalized); constantReps[*i2] = normalized; Trace("model-builder") << " Eval: Setting constant rep of " << (*i2) << " to " << normalized << endl; changed = true; evaluated = true; noRepSet->erase(i2); break; } } } if (!evaluated) { if (evaluable) { evaluableSet.insert(tb); } if (assignable) { unassignedAssignable = true; } } } } // 2. Normalize any non-const representative terms for this type set<Node>* repSet = typeRepSet.getSet(t); if (repSet != NULL && !repSet->empty()) { Trace("model-builder") << " Normalization phase, working on type: " << t << endl; d_normalizedCache.clear(); for (i = repSet->begin(); i != repSet->end(); ) { Assert(assertedReps.find(*i) != assertedReps.end()); Node rep = assertedReps[*i]; Node normalized = normalize(tm, rep, constantReps, false); Trace("model-builder") << " Normalizing rep (" << rep << "), normalized to (" << normalized << ")" << endl; if (normalized.isConst()) { changed = true; typeConstSet.add(t.getBaseType(), normalized); constantReps[*i] = normalized; assertedReps.erase(*i); i2 = i; ++i; repSet->erase(i2); } else { if (normalized != rep) { assertedReps[*i] = normalized; changed = true; } ++i; } } } } } while (changed); if (!fullModel || !unassignedAssignable) { break; } // 3. Assign unassigned assignable EC's using type enumeration - assign a value *different* from all other EC's if the type is infinite // Assign first value from type enumerator otherwise - for finite types, we rely on polite framework to ensure that EC's that have to be // different are different. // Only make assignments on a type if: // 1. fullModel is true // 2. there are no terms that share the same base type with un-normalized representatives // 3. there are no terms that share teh same base type that are unevaluated evaluable terms // Alternatively, if 2 or 3 don't hold but we are in a special deadlock-breaking mode where assignOne is true, go ahead and make one assignment changed = false; for (it = typeNoRepSet.begin(); it != typeNoRepSet.end(); ++it) { set<Node>& noRepSet = TypeSet::getSet(it); if (noRepSet.empty()) { continue; } TypeNode t = TypeSet::getType(it); TypeNode tb = t.getBaseType(); if (!assignOne) { set<Node>* repSet = typeRepSet.getSet(tb); if (repSet != NULL && !repSet->empty()) { continue; } if (evaluableSet.find(tb) != evaluableSet.end()) { continue; } } Trace("model-builder") << " Assign phase, working on type: " << t << endl; bool assignable, evaluable CVC4_UNUSED; for (i = noRepSet.begin(); i != noRepSet.end(); ) { i2 = i; ++i; eq::EqClassIterator eqc_i = eq::EqClassIterator(*i2, &tm->d_equalityEngine); assignable = false; evaluable = false; for ( ; !eqc_i.isFinished(); ++eqc_i) { Node n = *eqc_i; if (isAssignable(n)) { assignable = true; } else { evaluable = true; } } if (assignable) { Assert(!evaluable || assignOne); Assert(!t.isBoolean() || (*i2).getKind() == kind::APPLY_UF); Node n; if (t.getCardinality().isInfinite()) { n = typeConstSet.nextTypeEnum(t, true); } else { TypeEnumerator te(t); n = *te; } Assert(!n.isNull()); constantReps[*i2] = n; Trace("model-builder") << " Assign: Setting constant rep of " << (*i2) << " to " << n << endl; changed = true; noRepSet.erase(i2); if (assignOne) { assignOne = false; break; } } } } // Corner case - I'm not sure this can even happen - but it's theoretically possible to have a cyclical dependency // in EC assignment/evaluation, e.g. EC1 = {a, b + 1}; EC2 = {b, a - 1}. In this case, neither one will get assigned because we are waiting // to be able to evaluate. But we will never be able to evaluate because the variables that need to be assigned are in // these same EC's. In this case, repeat the whole fixed-point computation with the difference that the first EC // that has both assignable and evaluable expressions will get assigned. if (!changed) { Assert(!assignOne); // check for infinite loop! assignOne = true; } } #ifdef CVC4_ASSERTIONS if (fullModel) { // Assert that all representatives have been converted to constants for (it = typeRepSet.begin(); it != typeRepSet.end(); ++it) { set<Node>& repSet = TypeSet::getSet(it); if (!repSet.empty()) { Trace("model-builder") << "***Non-empty repSet, size = " << repSet.size() << ", first = " << *(repSet.begin()) << endl; Assert(false); } } } #endif /* CVC4_ASSERTIONS */ Trace("model-builder") << "Copy representatives to model..." << std::endl; tm->d_reps.clear(); std::map< Node, Node >::iterator itMap; for (itMap = constantReps.begin(); itMap != constantReps.end(); ++itMap) { tm->d_reps[itMap->first] = itMap->second; tm->d_rep_set.add(itMap->second); } if (!fullModel) { // Make sure every EC has a rep for (itMap = assertedReps.begin(); itMap != assertedReps.end(); ++itMap ) { tm->d_reps[itMap->first] = itMap->second; tm->d_rep_set.add(itMap->second); } for (it = typeNoRepSet.begin(); it != typeNoRepSet.end(); ++it) { set<Node>& noRepSet = TypeSet::getSet(it); set<Node>::iterator i; for (i = noRepSet.begin(); i != noRepSet.end(); ++i) { tm->d_reps[*i] = *i; tm->d_rep_set.add(*i); } } } //modelBuilder-specific initialization processBuildModel( tm, fullModel ); #ifdef CVC4_ASSERTIONS if (fullModel) { // Check that every term evaluates to its representative in the model for (eqcs_i = eq::EqClassesIterator(&tm->d_equalityEngine); !eqcs_i.isFinished(); ++eqcs_i) { // eqc is the equivalence class representative Node eqc = (*eqcs_i); Node rep; itMap = constantReps.find(eqc); if (itMap == constantReps.end() && eqc.getType().isBoolean()) { rep = tm->getValue(eqc); Assert(rep.isConst()); } else { Assert(itMap != constantReps.end()); rep = itMap->second; } eq::EqClassIterator eqc_i = eq::EqClassIterator(eqc, &tm->d_equalityEngine); for ( ; !eqc_i.isFinished(); ++eqc_i) { Node n = *eqc_i; static int repCheckInstance = 0; ++repCheckInstance; Debug("check-model::rep-checking") << "( " << repCheckInstance <<") " << "n: " << n << endl << "getValue(n): " << tm->getValue(n) << endl << "rep: " << rep << endl; Assert(tm->getValue(*eqc_i) == rep); } } } #endif /* CVC4_ASSERTIONS */ }
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; } }