/** pre register quantifier */ void QuantDSplit::preRegisterQuantifier( Node q ) { int max_index = -1; int max_score = -1; if( q.getNumChildren()==3 ){ return; } Trace("quant-dsplit-debug") << "Check split quantified formula : " << q << std::endl; for( unsigned i=0; i<q[0].getNumChildren(); i++ ){ TypeNode tn = q[0][i].getType(); if( tn.isDatatype() ){ const Datatype& dt = ((DatatypeType)(tn).toType()).getDatatype(); if( dt.isRecursiveSingleton() ){ Trace("quant-dsplit-debug") << "Datatype " << dt.getName() << " is recursive singleton." << std::endl; }else{ int score = -1; if( options::quantDynamicSplit()==quantifiers::QUANT_DSPLIT_MODE_AGG ){ score = dt.isUFinite() ? 1 : -1; }else if( options::quantDynamicSplit()==quantifiers::QUANT_DSPLIT_MODE_DEFAULT ){ score = dt.isUFinite() ? 1 : -1; } Trace("quant-dsplit-debug") << "Datatype " << dt.getName() << " is score " << score << " (" << dt.isUFinite() << " " << dt.isFinite() << ")" << std::endl; if( score>max_score ){ max_index = i; max_score = score; } } } } if( max_index!=-1 ){ Trace("quant-dsplit-debug") << "Will split at index " << max_index << "." << std::endl; d_quant_to_reduce[q] = max_index; d_quantEngine->setOwner( q, this ); } }
/* Call during quantifier engine's check */ void QuantDSplit::check( Theory::Effort e, unsigned quant_e ) { //add lemmas ASAP (they are a reduction) if( quant_e==QuantifiersEngine::QEFFORT_CONFLICT ){ std::vector< Node > lemmas; for(std::map< Node, int >::iterator it = d_quant_to_reduce.begin(); it != d_quant_to_reduce.end(); ++it) { Node q = it->first; if( d_added_split.find( q )==d_added_split.end() ){ d_added_split.insert( q ); std::vector< Node > bvs; for( unsigned i=0; i<q[0].getNumChildren(); i++ ){ if( (int)i!=it->second ){ bvs.push_back( q[0][i] ); } } std::vector< Node > disj; disj.push_back( q.negate() ); TNode svar = q[0][it->second]; TypeNode tn = svar.getType(); if( tn.isDatatype() ){ std::vector< Node > cons; const Datatype& dt = ((DatatypeType)(tn).toType()).getDatatype(); for( unsigned j=0; j<dt.getNumConstructors(); j++ ){ std::vector< Node > vars; for( unsigned k=0; k<dt[j].getNumArgs(); k++ ){ TypeNode tns = TypeNode::fromType( dt[j][k].getRangeType() ); Node v = NodeManager::currentNM()->mkBoundVar( tns ); vars.push_back( v ); } std::vector< Node > bvs_cmb; bvs_cmb.insert( bvs_cmb.end(), bvs.begin(), bvs.end() ); bvs_cmb.insert( bvs_cmb.end(), vars.begin(), vars.end() ); vars.insert( vars.begin(), Node::fromExpr( dt[j].getConstructor() ) ); Node c = NodeManager::currentNM()->mkNode( kind::APPLY_CONSTRUCTOR, vars ); TNode ct = c; Node body = q[1].substitute( svar, ct ); if( !bvs_cmb.empty() ){ body = NodeManager::currentNM()->mkNode( kind::FORALL, NodeManager::currentNM()->mkNode( kind::BOUND_VAR_LIST, bvs_cmb ), body ); } cons.push_back( body ); } Node conc = cons.size()==1 ? cons[0] : NodeManager::currentNM()->mkNode( kind::AND, cons ); disj.push_back( conc ); }else{ Assert( false ); } lemmas.push_back( disj.size()==1 ? disj[0] : NodeManager::currentNM()->mkNode( kind::OR, disj ) ); } } //add lemmas to quantifiers engine for( unsigned i=0; i<lemmas.size(); i++ ){ Trace("quant-dsplit") << "QuantDSplit lemma : " << lemmas[i] << std::endl; d_quantEngine->addLemma( lemmas[i], false ); } d_quant_to_reduce.clear(); } }
Node ModelPostprocessor::rewriteAs(TNode n, TypeNode asType) { if(n.getType().isSubtypeOf(asType)) { // good to go, we have the right type return n; } if(!n.isConst()) { // we don't handle non-const right now return n; } if(asType.isBoolean()) { if(n.getType().isBitVector(1u)) { // type mismatch: should only happen for Boolean-term conversion under // datatype constructor applications; rewrite from BV(1) back to Boolean bool tf = (n.getConst<BitVector>().getValue() == 1); return NodeManager::currentNM()->mkConst(tf); } if(n.getType().isDatatype() && n.getType().hasAttribute(BooleanTermAttr())) { // type mismatch: should only happen for Boolean-term conversion under // datatype constructor applications; rewrite from datatype back to Boolean Assert(n.getKind() == kind::APPLY_CONSTRUCTOR); Assert(n.getNumChildren() == 0); // we assume (by construction) false is first; see boolean_terms.cpp bool tf = (Datatype::indexOf(n.getOperator().toExpr()) == 1); Debug("boolean-terms") << "+++ rewriteAs " << n << " : " << asType << " ==> " << tf << endl; return NodeManager::currentNM()->mkConst(tf); } } if(n.getType().isBoolean()) { bool tf = n.getConst<bool>(); if(asType.isBitVector(1u)) { return NodeManager::currentNM()->mkConst(BitVector(1u, tf ? 1u : 0u)); } if(asType.isDatatype() && asType.hasAttribute(BooleanTermAttr())) { const Datatype& asDatatype = asType.getConst<Datatype>(); return NodeManager::currentNM()->mkNode(kind::APPLY_CONSTRUCTOR, (tf ? asDatatype[0] : asDatatype[1]).getConstructor()); } } if(n.getType().isRecord() && asType.isRecord()) { Debug("boolean-terms") << "+++ got a record - rewriteAs " << n << " : " << asType << endl; const Record& rec CVC4_UNUSED = n.getType().getConst<Record>(); const Record& asRec = asType.getConst<Record>(); Assert(rec.getNumFields() == asRec.getNumFields()); Assert(n.getNumChildren() == asRec.getNumFields()); NodeBuilder<> b(n.getKind()); b << asType; for(size_t i = 0; i < n.getNumChildren(); ++i) { b << rewriteAs(n[i], TypeNode::fromType(asRec[i].second)); } Node out = b; Debug("boolean-terms") << "+++ returning record " << out << endl; return out; }
void SygusRedundantCons::initialize(QuantifiersEngine* qe, TypeNode tn) { Assert(qe != nullptr); Trace("sygus-red") << "Compute redundant cons for " << tn << std::endl; d_type = tn; Assert(tn.isDatatype()); TermDbSygus* tds = qe->getTermDatabaseSygus(); tds->registerSygusType(tn); const Datatype& dt = static_cast<DatatypeType>(tn.toType()).getDatatype(); Assert(dt.isSygus()); TypeNode btn = TypeNode::fromType(dt.getSygusType()); for (unsigned i = 0, ncons = dt.getNumConstructors(); i < ncons; i++) { Trace("sygus-red") << " Is " << dt[i].getName() << " a redundant operator?" << std::endl; std::map<int, Node> pre; Node g = tds->mkGeneric(dt, i, pre); Trace("sygus-red-debug") << " ...pre-rewrite : " << g << std::endl; Assert(g.getNumChildren() == dt[i].getNumArgs()); d_gen_terms[i] = g; for (unsigned j = 0, nargs = dt[i].getNumArgs(); j < nargs; j++) { pre[j] = g[j]; } std::vector<Node> glist; getGenericList(tds, dt, i, 0, pre, glist); // call the extended rewriter bool red = false; for (const Node& gr : glist) { Trace("sygus-red-debug") << " ...variant : " << gr << std::endl; std::map<Node, unsigned>::iterator itg = d_gen_cons.find(gr); if (itg != d_gen_cons.end() && itg->second != i) { red = true; Trace("sygus-red") << " ......redundant, since a variant of " << g << " and " << d_gen_terms[itg->second] << " both rewrite to " << gr << std::endl; break; } else { d_gen_cons[gr] = i; Trace("sygus-red") << " ......not redundant." << std::endl; } } d_sygus_red_status.push_back(red ? 1 : 0); } }
bool InstStrategyCbqi::hasNonCbqiVariable( Node q ){ for( unsigned i=0; i<q[0].getNumChildren(); i++ ){ TypeNode tn = q[0][i].getType(); if( !tn.isInteger() && !tn.isReal() && !tn.isBoolean() ){ if( options::cbqiSplx() ){ return true; }else{ //datatypes supported in new implementation if( !tn.isDatatype() ){ return true; } } } } return false; }
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; } }
Node DatatypesEnumerator::getTermEnum( TypeNode tn, unsigned i ){ Node ret; if( i<d_terms[tn].size() ){ ret = d_terms[tn][i]; }else{ Debug("dt-enum-debug") << "get term enum " << tn << " " << i << std::endl; std::map< TypeNode, unsigned >::iterator it = d_te_index.find( tn ); unsigned tei; if( it==d_te_index.end() ){ //initialize child enumerator for type tei = d_children.size(); d_te_index[tn] = tei; if( tn.isDatatype() && d_has_debruijn ){ //must indicate that this is a child enumerator (do not normalize constants for it) DatatypesEnumerator * dte = new DatatypesEnumerator( tn, true ); d_children.push_back( TypeEnumerator( dte ) ); }else{ d_children.push_back( TypeEnumerator( tn ) ); } d_terms[tn].push_back( *d_children[tei] ); }else{ tei = it->second; } //enumerate terms until index is reached while( i>=d_terms[tn].size() ){ ++d_children[tei]; if( d_children[tei].isFinished() ){ Debug("dt-enum-debug") << "...fail term enum " << tn << " " << i << std::endl; return Node::null(); } d_terms[tn].push_back( *d_children[tei] ); } Debug("dt-enum-debug") << "...return term enum " << tn << " " << i << " : " << d_terms[tn][i] << std::endl; ret = d_terms[tn][i]; } return ret; }