diff options
Diffstat (limited to 'src/theory')
85 files changed, 7583 insertions, 3626 deletions
diff --git a/src/theory/arith/theory_arith_private.cpp b/src/theory/arith/theory_arith_private.cpp index 220737d2e..c657796ee 100644 --- a/src/theory/arith/theory_arith_private.cpp +++ b/src/theory/arith/theory_arith_private.cpp @@ -335,7 +335,7 @@ TheoryArithPrivate::Statistics::Statistics() , d_unsatPivots("theory::arith::pivots::unsat") , d_unknownPivots("theory::arith::pivots::unkown") , d_solveIntModelsAttempts("theory::arith::z::solveInt::models::attempts", 0) - , d_solveIntModelsSuccessful("zzz::solveInt::models::successful", 0) + , d_solveIntModelsSuccessful("theory::arith::zzz::solveInt::models::successful", 0) , d_mipTimer("theory::arith::z::approx::mip::timer") , d_lpTimer("theory::arith::z::approx::lp::timer") , d_mipProofsAttempted("theory::arith::z::mip::proofs::attempted", 0) diff --git a/src/theory/arrays/array_info.cpp b/src/theory/arrays/array_info.cpp index dc907ba0b..9b2d3647e 100644 --- a/src/theory/arrays/array_info.cpp +++ b/src/theory/arrays/array_info.cpp @@ -181,6 +181,20 @@ void ArrayInfo::setModelRep(const TNode a, const TNode b) { } +void ArrayInfo::setConstArr(const TNode a, const TNode constArr) { + Assert(a.getType().isArray()); + Info* temp_info; + CNodeInfoMap::iterator it = info_map.find(a); + if(it == info_map.end()) { + temp_info = new Info(ct, bck); + temp_info->constArr = constArr; + info_map[a] = temp_info; + } else { + (*it).second->constArr = constArr; + } + +} + /** * Returns the information associated with TNode a */ @@ -224,6 +238,16 @@ const TNode ArrayInfo::getModelRep(const TNode a) const return TNode(); } +const TNode ArrayInfo::getConstArr(const TNode a) const +{ + CNodeInfoMap::const_iterator it = info_map.find(a); + + if(it!= info_map.end()) { + return (*it).second->constArr; + } + return TNode(); +} + const CTNodeList* ArrayInfo::getIndices(const TNode a) const{ CNodeInfoMap::const_iterator it = info_map.find(a); if(it!= info_map.end()) { diff --git a/src/theory/arrays/array_info.h b/src/theory/arrays/array_info.h index 09230bba7..f3c6385e5 100644 --- a/src/theory/arrays/array_info.h +++ b/src/theory/arrays/array_info.h @@ -64,11 +64,12 @@ public: context::CDO<bool> isNonLinear; context::CDO<bool> rIntro1Applied; context::CDO<TNode> modelRep; + context::CDO<TNode> constArr; CTNodeList* indices; CTNodeList* stores; CTNodeList* in_stores; - Info(context::Context* c, Backtracker<TNode>* bck) : isNonLinear(c, false), rIntro1Applied(c, false), modelRep(c,TNode()) { + Info(context::Context* c, Backtracker<TNode>* bck) : isNonLinear(c, false), rIntro1Applied(c, false), modelRep(c,TNode()), constArr(c,TNode()) { indices = new(true)CTNodeList(c); stores = new(true)CTNodeList(c); in_stores = new(true)CTNodeList(c); @@ -210,6 +211,7 @@ public: void setRIntro1Applied(const TNode a); void setModelRep(const TNode a, const TNode rep); + void setConstArr(const TNode a, const TNode constArr); /** * Returns the information associated with TNode a */ @@ -222,6 +224,8 @@ public: const TNode getModelRep(const TNode a) const; + const TNode getConstArr(const TNode a) const; + const CTNodeList* getIndices(const TNode a) const; const CTNodeList* getStores(const TNode a) const; diff --git a/src/theory/arrays/options b/src/theory/arrays/options index 15220fbc2..8ed80c1f1 100644 --- a/src/theory/arrays/options +++ b/src/theory/arrays/options @@ -12,7 +12,7 @@ option arraysLazyRIntro1 --arrays-lazy-rintro1 bool :default true :read-write turn on optimization to only perform RIntro1 rule lazily (see Jovanovic/Barrett 2012: Being Careful with Theory Combination) option arraysModelBased --arrays-model-based bool :default false :read-write - turn on model-based arrray solver + turn on model-based array solver option arraysEagerIndexSplitting --arrays-eager-index bool :default true :read-write turn on eager index splitting for generated array lemmas @@ -20,4 +20,13 @@ option arraysEagerIndexSplitting --arrays-eager-index bool :default true :read-w option arraysEagerLemmas --arrays-eager-lemmas bool :default false :read-write turn on eager lemma generation for arrays +option arraysConfig --arrays-config int :default 0 :read-write + set different array option configurations - for developers only + +option arraysReduceSharing --arrays-reduce-sharing bool :default false :read-write + use model information to reduce size of care graph for arrays + +option arraysPropagate --arrays-prop int :default 2 :read-write + propagation effort for arrays: 0 is none, 1 is some, 2 is full + endmodule diff --git a/src/theory/arrays/theory_arrays.cpp b/src/theory/arrays/theory_arrays.cpp index e73c059d4..cf0eeb14b 100644 --- a/src/theory/arrays/theory_arrays.cpp +++ b/src/theory/arrays/theory_arrays.cpp @@ -40,11 +40,11 @@ namespace arrays { const bool d_ccStore = false; const bool d_useArrTable = false; //const bool d_eagerLemmas = false; -const bool d_propagateLemmas = true; const bool d_preprocess = true; const bool d_solveWrite = true; const bool d_solveWrite2 = false; // These are now options + //const bool d_propagateLemmas = true; //bool d_useNonLinearOpt = true; //bool d_lazyRIntro1 = true; //bool d_eagerIndexSplitting = false; @@ -87,6 +87,7 @@ TheoryArrays::TheoryArrays(context::Context* c, context::UserContext* u, OutputC d_permRef(c), d_modelConstraints(c), d_lemmasSaved(c), + d_defValues(c), d_inCheckModel(false) { StatisticsRegistry::registerStat(&d_numRow); @@ -449,6 +450,7 @@ void TheoryArrays::preRegisterTermInternal(TNode node) if (node.getType().isArray()) { d_equalityEngine.addTriggerTerm(node, THEORY_ARRAY); + d_mayEqualEqualityEngine.addTerm(node); } else { d_equalityEngine.addTerm(node); @@ -468,7 +470,6 @@ void TheoryArrays::preRegisterTermInternal(TNode node) break; } case kind::STORE: { - // Invariant: array terms should be preregistered before being added to the equality engine if (d_equalityEngine.hasTerm(node)) { break; } @@ -499,13 +500,28 @@ void TheoryArrays::preRegisterTermInternal(TNode node) break; } case kind::STORE_ALL: { - throw LogicException("Array theory solver does not yet support assertions using constant array value"); + if (d_equalityEngine.hasTerm(node)) { + break; + } + ArrayStoreAll storeAll = node.getConst<ArrayStoreAll>(); + Node defaultValue = Node::fromExpr(storeAll.getExpr()); + if (!defaultValue.isConst()) { + throw LogicException("Array theory solver does not yet support non-constant default values for arrays"); + } + d_infoMap.setConstArr(node, node); + d_equalityEngine.addTriggerTerm(node, THEORY_ARRAY); + d_mayEqualEqualityEngine.addTerm(node); + Assert(d_mayEqualEqualityEngine.getRepresentative(node) == node); + d_defValues[node] = defaultValue; + break; } default: // Variables etc if (node.getType().isArray()) { d_equalityEngine.addTriggerTerm(node, THEORY_ARRAY); Assert(d_equalityEngine.getSize(node) == 1); + // The may equal needs the node + d_mayEqualEqualityEngine.addTerm(node); } else { d_equalityEngine.addTerm(node); @@ -566,12 +582,11 @@ EqualityStatus TheoryArrays::getEqualityStatus(TNode a, TNode b) { // The terms are implied to be equal return EQUALITY_TRUE; } - if (d_equalityEngine.areDisequal(a, b, false)) { + else if (d_equalityEngine.areDisequal(a, b, false)) { // The terms are implied to be dis-equal return EQUALITY_FALSE; } - //TODO: can we be more precise sometimes? - return EQUALITY_UNKNOWN; + return EQUALITY_UNKNOWN;//FALSE_IN_MODEL; } @@ -665,18 +680,19 @@ void TheoryArrays::computeCareGraph() // Should have been propagated to us Assert(false); break; - case EQUALITY_FALSE_AND_PROPAGATED: - // Should have been propagated to us - Assert(false); - break; - case EQUALITY_FALSE: case EQUALITY_TRUE: // Missed propagation - need to add the pair so that theory engine can force propagation Debug("arrays::sharing") << "TheoryArrays::computeCareGraph(): missed propagation" << std::endl; break; + case EQUALITY_FALSE_AND_PROPAGATED: + // Should have been propagated to us + Assert(false); + case EQUALITY_FALSE: case EQUALITY_FALSE_IN_MODEL: - Debug("arrays::sharing") << "TheoryArrays::computeCareGraph(): false in model" << std::endl; - break; + // Don't need to include this pair + if (options::arraysReduceSharing()) { + continue; + } default: break; } @@ -811,10 +827,22 @@ void TheoryArrays::collectModelInfo( TheoryModel* m, bool fullModel ) } Node rep; - map<Node, Node> defValues; - map<Node, Node>::iterator it; + DefValMap::iterator it; TypeSet defaultValuesSet; + // Compute all default values already in use + if (fullModel) { + for (size_t i=0; i<arrays.size(); ++i) { + TNode nrep = d_equalityEngine.getRepresentative(arrays[i]); + d_mayEqualEqualityEngine.addTerm(nrep); // add the term in case it isn't there already + TNode mayRep = d_mayEqualEqualityEngine.getRepresentative(nrep); + it = d_defValues.find(mayRep); + if (it != d_defValues.end()) { + defaultValuesSet.add(nrep.getType().getArrayConstituentType(), (*it).second); + } + } + } + // Loop through all array equivalence classes that need a representative computed for (size_t i=0; i<arrays.size(); ++i) { TNode n = arrays[i]; @@ -822,11 +850,10 @@ void TheoryArrays::collectModelInfo( TheoryModel* m, bool fullModel ) if (fullModel) { // Compute default value for this array - there is one default value for every mayEqual equivalence class - d_mayEqualEqualityEngine.addTerm(nrep); // add the term in case it isn't there already TNode mayRep = d_mayEqualEqualityEngine.getRepresentative(nrep); - it = defValues.find(mayRep); + it = d_defValues.find(mayRep); // If this mayEqual EC doesn't have a default value associated, get the next available default value for the associated array element type - if (it == defValues.end()) { + if (it == d_defValues.end()) { TypeNode valueType = nrep.getType().getArrayConstituentType(); rep = defaultValuesSet.nextTypeEnum(valueType); if (rep.isNull()) { @@ -834,7 +861,7 @@ void TheoryArrays::collectModelInfo( TheoryModel* m, bool fullModel ) rep = *(defaultValuesSet.getSet(valueType)->begin()); } Trace("arrays-models") << "New default value = " << rep << endl; - defValues[mayRep] = rep; + d_defValues[mayRep] = rep; } else { rep = (*it).second; @@ -992,7 +1019,9 @@ void TheoryArrays::check(Effort e) { if(!options::arraysEagerLemmas() && fullEffort(e) && !d_conflict && !options::arraysModelBased()) { // generate the lemmas on the worklist Trace("arrays-lem")<<"Arrays::discharging lemmas: "<<d_RowQueue.size()<<"\n"; - dischargeLemmas(); + while (d_RowQueue.size() > 0 && !d_conflict) { + dischargeLemmas(); + } } Trace("arrays") << spaces(getSatContext()->getLevel()) << "Arrays::check(): done" << endl; @@ -2036,7 +2065,42 @@ void TheoryArrays::mergeArrays(TNode a, TNode b) } } + TNode constArrA = d_infoMap.getConstArr(a); + TNode constArrB = d_infoMap.getConstArr(b); + if (constArrA.isNull()) { + if (!constArrB.isNull()) { + d_infoMap.setConstArr(a,constArrB); + } + } + else if (!constArrB.isNull()) { + if (constArrA != constArrB) { + conflict(constArrA,constArrB); + } + } + + // If a and b have different default values associated with their mayequal equivalence classes, + // things get complicated - disallow this for now. -Clark + TNode mayRepA = d_mayEqualEqualityEngine.getRepresentative(a); + TNode mayRepB = d_mayEqualEqualityEngine.getRepresentative(b); + + DefValMap::iterator it = d_defValues.find(mayRepA); + DefValMap::iterator it2 = d_defValues.find(mayRepB); + TNode defValue; + + if (it != d_defValues.end()) { + defValue = (*it).second; + if (it2 != d_defValues.end() && (defValue != (*it2).second)) { + throw LogicException("Array theory solver does not yet support write-chains connecting two different constant arrays"); + } + } + else if (it2 != d_defValues.end()) { + defValue = (*it2).second; + } d_mayEqualEqualityEngine.assertEquality(a.eqNode(b), true, d_true); + if (!defValue.isNull()) { + mayRepA = d_mayEqualEqualityEngine.getRepresentative(a); + d_defValues[mayRepA] = defValue; + } checkRowLemmas(a,b); checkRowLemmas(b,a); @@ -2168,6 +2232,17 @@ void TheoryArrays::checkRowForIndex(TNode i, TNode a) Assert(a.getType().isArray()); Assert(d_equalityEngine.getRepresentative(a) == a); + TNode constArr = d_infoMap.getConstArr(a); + if (!constArr.isNull()) { + ArrayStoreAll storeAll = constArr.getConst<ArrayStoreAll>(); + Node defValue = Node::fromExpr(storeAll.getExpr()); + Node selConst = NodeManager::currentNM()->mkNode(kind::SELECT, constArr, i); + if (!d_equalityEngine.hasTerm(selConst)) { + preRegisterTermInternal(selConst); + } + d_equalityEngine.assertEquality(selConst.eqNode(defValue), true, d_true); + } + const CTNodeList* stores = d_infoMap.getStores(a); const CTNodeList* instores = d_infoMap.getInStores(a); size_t it = 0; @@ -2211,15 +2286,25 @@ void TheoryArrays::checkRowLemmas(TNode a, TNode b) d_infoMap.getInfo(b)->print(); const CTNodeList* i_a = d_infoMap.getIndices(a); + size_t it = 0; + TNode constArr = d_infoMap.getConstArr(b); + if (!constArr.isNull()) { + for( ; it < i_a->size(); ++it) { + TNode i = (*i_a)[it]; + Node selConst = NodeManager::currentNM()->mkNode(kind::SELECT, constArr, i); + if (!d_equalityEngine.hasTerm(selConst)) { + preRegisterTermInternal(selConst); + } + } + } + const CTNodeList* st_b = d_infoMap.getStores(b); const CTNodeList* inst_b = d_infoMap.getInStores(b); - - size_t it = 0; size_t its; RowLemmaType lem; - for( ; it < i_a->size(); ++it) { + for(it = 0 ; it < i_a->size(); ++it) { TNode i = (*i_a)[it]; its = 0; for ( ; its < st_b->size(); ++its) { @@ -2277,8 +2362,9 @@ void TheoryArrays::queueRowLemma(RowLemmaType lem) bool bothExist = ajExists && bjExists; // If propagating, check propagations - if (d_propagateLemmas) { - if (d_equalityEngine.areDisequal(i,j,true)) { + int prop = options::arraysPropagate(); + if (prop > 0) { + if (d_equalityEngine.areDisequal(i,j,true) && (bothExist || prop > 1)) { Trace("arrays-lem") << spaces(getSatContext()->getLevel()) <<"Arrays::queueRowLemma: propagating aj = bj ("<<aj<<", "<<bj<<")\n"; Node aj_eq_bj = aj.eqNode(bj); Node i_eq_j = i.eqNode(j); diff --git a/src/theory/arrays/theory_arrays.h b/src/theory/arrays/theory_arrays.h index 9e9d3c890..649232dae 100644 --- a/src/theory/arrays/theory_arrays.h +++ b/src/theory/arrays/theory_arrays.h @@ -361,6 +361,10 @@ class TheoryArrays : public Theory { context::CDHashSet<Node, NodeHashFunction > d_lemmasSaved; std::vector<Node> d_lemmas; + // Default values for each mayEqual equivalence class + typedef context::CDHashMap<Node,Node,NodeHashFunction> DefValMap; + DefValMap d_defValues; + Node getSkolem(TNode ref, const std::string& name, const TypeNode& type, const std::string& comment, bool makeEqual = true); Node mkAnd(std::vector<TNode>& conjunctions, bool invert = false, unsigned startIndex = 0); void setNonLinear(TNode a); diff --git a/src/theory/booleans/circuit_propagator.h b/src/theory/booleans/circuit_propagator.h index 7dbef4041..169ac6fa7 100644 --- a/src/theory/booleans/circuit_propagator.h +++ b/src/theory/booleans/circuit_propagator.h @@ -144,7 +144,7 @@ private: } } - // Get the current assignement + // Get the current assignment AssignmentStatus state = d_state[n]; if(state != UNASSIGNED) { diff --git a/src/theory/builtin/kinds b/src/theory/builtin/kinds index 508106106..44474c18a 100644 --- a/src/theory/builtin/kinds +++ b/src/theory/builtin/kinds @@ -302,9 +302,6 @@ operator SEXPR 0: "a symbolic expression (any arity)" operator LAMBDA 2 "a lambda expression; first parameter is a BOUND_VAR_LIST, second is lambda body" -## for co-datatypes, not yet supported -# operator MU 2 "mu" - parameterized CHAIN CHAIN_OP 2: "chained operator (N-ary), turned into a conjuction of binary applications of the operator on adjoining parameters; first parameter is a CHAIN_OP representing a binary operator, rest are arguments to that operator" constant CHAIN_OP \ ::CVC4::Chain \ @@ -336,7 +333,6 @@ typerule EQUAL ::CVC4::theory::builtin::EqualityTypeRule typerule DISTINCT ::CVC4::theory::builtin::DistinctTypeRule typerule SEXPR ::CVC4::theory::builtin::SExprTypeRule typerule LAMBDA ::CVC4::theory::builtin::LambdaTypeRule -#typerule MU ::CVC4::theory::builtin::MuTypeRule typerule CHAIN ::CVC4::theory::builtin::ChainTypeRule typerule CHAIN_OP ::CVC4::theory::builtin::ChainedOperatorTypeRule diff --git a/src/theory/builtin/theory_builtin_type_rules.h b/src/theory/builtin/theory_builtin_type_rules.h index 045f440e6..977a097d0 100644 --- a/src/theory/builtin/theory_builtin_type_rules.h +++ b/src/theory/builtin/theory_builtin_type_rules.h @@ -164,27 +164,6 @@ public: } };/* class LambdaTypeRule */ -/* For co-datatypes, not yet supported-- -** -class MuTypeRule { -public: - inline static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check) { - if( n[0].getType(check) != nodeManager->boundVarListType() ) { - std::stringstream ss; - ss << "expected a bound var list for MU expression, got `" - << n[0].getType().toString() << "'"; - throw TypeCheckingExceptionPrivate(n, ss.str()); - } - std::vector<TypeNode> argTypes; - for(TNode::iterator i = n[0].begin(); i != n[0].end(); ++i) { - argTypes.push_back((*i).getType()); - } - TypeNode rangeType = n[1].getType(check); - return nodeManager->mkFunctionType(argTypes, rangeType); - } -}; -**/ - class ChainTypeRule { public: inline static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check) { diff --git a/src/theory/bv/aig_bitblaster.cpp b/src/theory/bv/aig_bitblaster.cpp index ce775874f..6270995ef 100644 --- a/src/theory/bv/aig_bitblaster.cpp +++ b/src/theory/bv/aig_bitblaster.cpp @@ -402,7 +402,7 @@ void AigBitblaster::assertToSatSolver(Cnf_Dat_t* pCnf) { prop::SatLiteral lit(sat_variables[index-1], int_lit < 0); clause.push_back(lit); } - d_satSolver->addClause(clause, false); + d_satSolver->addClause(clause, false, RULE_INVALID); } } diff --git a/src/theory/bv/bitblaster_template.h b/src/theory/bv/bitblaster_template.h index ecd7013c7..ea31e3821 100644 --- a/src/theory/bv/bitblaster_template.h +++ b/src/theory/bv/bitblaster_template.h @@ -74,19 +74,22 @@ protected: typedef std::vector<T> Bits; typedef __gnu_cxx::hash_map <Node, Bits, NodeHashFunction> TermDefMap; typedef __gnu_cxx::hash_set<TNode, TNodeHashFunction> TNodeSet; + typedef __gnu_cxx::hash_map<Node, Node, NodeHashFunction> ModelCache; typedef void (*TermBBStrategy) (TNode, Bits&, TBitblaster<T>*); typedef T (*AtomBBStrategy) (TNode, TBitblaster<T>*); // caches and mappings - TermDefMap d_termCache; - + TermDefMap d_termCache; + ModelCache d_modelCache; + void initAtomBBStrategies(); void initTermBBStrategies(); protected: /// function tables for the various bitblasting strategies indexed by node kind TermBBStrategy d_termBBStrategies[kind::LAST_KIND]; AtomBBStrategy d_atomBBStrategies[kind::LAST_KIND]; + virtual Node getModelFromSatSolver(TNode node, bool fullModel) = 0; public: TBitblaster(); virtual ~TBitblaster() {} @@ -97,9 +100,18 @@ public: virtual bool hasBBAtom(TNode atom) const = 0; virtual void storeBBAtom(TNode atom, T atom_bb) = 0; + bool hasBBTerm(TNode node) const; void getBBTerm(TNode node, Bits& bits) const; - void storeBBTerm(TNode term, const Bits& bits); + void storeBBTerm(TNode term, const Bits& bits); + /** + * Return a constant representing the value of a in the model. + * If fullModel is true set unconstrained bits to 0. If not return + * NullNode() for a fully or partially unconstrained. + * + */ + Node getTermModel(TNode node, bool fullModel); + void invalidateModelCache(); }; @@ -109,7 +121,6 @@ class TLazyBitblaster : public TBitblaster<Node> { typedef std::vector<Node> Bits; typedef context::CDList<prop::SatLiteral> AssertionList; typedef context::CDHashMap<prop::SatLiteral, std::vector<prop::SatLiteral> , prop::SatLiteralHashFunction> ExplanationMap; - /** This class gets callbacks from minisat on propagations */ class MinisatNotify : public prop::BVSatSolverInterface::Notify { prop::CnfStream* d_cnf; @@ -143,9 +154,12 @@ class TLazyBitblaster : public TBitblaster<Node> { TNodeSet d_bbAtoms; AbstractionModule* d_abstraction; bool d_emptyNotify; + + context::CDO<bool> d_satSolverFullModel; void addAtom(TNode atom); bool hasValue(TNode a); + Node getModelFromSatSolver(TNode a, bool fullModel); public: void bbTerm(TNode node, Bits& bits); void bbAtom(TNode node); @@ -172,14 +186,7 @@ public: void setAbstraction(AbstractionModule* abs); theory::EqualityStatus getEqualityStatus(TNode a, TNode b); - /** - * Return a constant Node representing the value of a variable - * in the current model. - * @param a - * - * @return - */ - Node getVarValue(TNode a, bool fullModel=true); + /** * Adds a constant value for each bit-blasted variable in the model. * @@ -245,7 +252,7 @@ class EagerBitblaster : public TBitblaster<Node> { TNodeSet d_bbAtoms; TNodeSet d_variables; - Node getVarValue(TNode a, bool fullModel); + Node getModelFromSatSolver(TNode a, bool fullModel); bool isSharedTerm(TNode node); public: @@ -299,7 +306,7 @@ class AigBitblaster : public TBitblaster<Abc_Obj_t*> { bool hasInput(TNode input); void convertToCnfAndAssert(); void assertToSatSolver(Cnf_Dat_t* pCnf); - + Node getModelFromSatSolver(TNode a, bool fullModel) { Unreachable(); } public: AigBitblaster(); ~AigBitblaster(); @@ -387,6 +394,7 @@ template <class T> void TBitblaster<T>::initTermBBStrategies() { template <class T> TBitblaster<T>::TBitblaster() : d_termCache() + , d_modelCache() { initAtomBBStrategies(); initTermBBStrategies(); @@ -407,6 +415,53 @@ void TBitblaster<T>::storeBBTerm(TNode node, const Bits& bits) { d_termCache.insert(std::make_pair(node, bits)); } +template <class T> +void TBitblaster<T>::invalidateModelCache() { + d_modelCache.clear(); +} + +template <class T> +Node TBitblaster<T>::getTermModel(TNode node, bool fullModel) { + if (d_modelCache.find(node) != d_modelCache.end()) + return d_modelCache[node]; + + if (node.isConst()) + return node; + + Node value = getModelFromSatSolver(node, false); + if (!value.isNull()) { + Debug("bv-equality-status")<< "TLazyBitblaster::getTermModel from SatSolver" << node <<" => " << value <<"\n"; + d_modelCache[node] = value; + Assert (value.isConst()); + return value; + } + + if (Theory::isLeafOf(node, theory::THEORY_BV)) { + // if it is a leaf may ask for fullModel + value = getModelFromSatSolver(node, fullModel); + Debug("bv-equality-status")<< "TLazyBitblaster::getTermModel from VarValue" << node <<" => " << value <<"\n"; + Assert (!value.isNull()); + d_modelCache[node] = value; + return value; + } + Assert (node.getType().isBitVector()); + + NodeBuilder<> nb(node.getKind()); + if (node.getMetaKind() == kind::metakind::PARAMETERIZED) { + nb << node.getOperator(); + } + + for (unsigned i = 0; i < node.getNumChildren(); ++i) { + nb << getTermModel(node[i], fullModel); + } + value = nb; + value = Rewriter::rewrite(value); + Assert (value.isConst()); + d_modelCache[node] = value; + Debug("bv-term-model")<< "TLazyBitblaster::getTermModel Building Value" << node <<" => " << value <<"\n"; + return value; +} + } /* bv namespace */ diff --git a/src/theory/bv/bv_quick_check.cpp b/src/theory/bv/bv_quick_check.cpp index 5f35f95e3..b2b4eebdf 100644 --- a/src/theory/bv/bv_quick_check.cpp +++ b/src/theory/bv/bv_quick_check.cpp @@ -115,7 +115,7 @@ BVQuickCheck::vars_iterator BVQuickCheck::endVars() { } Node BVQuickCheck::getVarValue(TNode var) { - return d_bitblaster->getVarValue(var); + return d_bitblaster->getTermModel(var, true); } diff --git a/src/theory/bv/bv_subtheory_bitblast.cpp b/src/theory/bv/bv_subtheory_bitblast.cpp index a2a6e19ac..35542fc68 100644 --- a/src/theory/bv/bv_subtheory_bitblast.cpp +++ b/src/theory/bv/bv_subtheory_bitblast.cpp @@ -103,6 +103,7 @@ void BitblastSolver::bitblastQueue() { // don't bit-blast lemma atoms continue; } + Debug("bitblast-queue") << "Bitblasting atom " << atom <<"\n"; d_bitblaster->bbAtom(atom); } } @@ -218,48 +219,45 @@ void BitblastSolver::collectModelInfo(TheoryModel* m, bool fullModel) { Node BitblastSolver::getModelValue(TNode node) { - if (!d_validModelCache) { - d_modelCache.clear(); - d_validModelCache = true; - } - return getModelValueRec(node); -} - -Node BitblastSolver::getModelValueRec(TNode node) -{ - Node val; - if (node.isConst()) { - return node; - } - NodeMap::iterator it = d_modelCache.find(node); - if (it != d_modelCache.end()) { - val = (*it).second; - Debug("bitvector-model") << node << " => (cached) " << val <<"\n"; - return val; - } - if (d_bv->isLeaf(node)) { - val = d_bitblaster->getVarValue(node); - if (val == Node()) { - // If no value in model, just set to 0 - val = utils::mkConst(utils::getSize(node), (unsigned)0); - } - } else { - NodeBuilder<> valBuilder(node.getKind()); - if (node.getMetaKind() == kind::metakind::PARAMETERIZED) { - valBuilder << node.getOperator(); - } - for (unsigned i = 0; i < node.getNumChildren(); ++i) { - valBuilder << getModelValueRec(node[i]); - } - val = valBuilder; - val = Rewriter::rewrite(val); - } - Assert(val.isConst()); - d_modelCache[node] = val; - Debug("bitvector-model") << node << " => " << val <<"\n"; + Node val = d_bitblaster->getTermModel(node, false); return val; } +// Node BitblastSolver::getModelValueRec(TNode node) +// { +// Node val; +// if (node.isConst()) { +// return node; +// } +// NodeMap::iterator it = d_modelCache.find(node); +// if (it != d_modelCache.end()) { +// val = (*it).second; +// Debug("bitvector-model") << node << " => (cached) " << val <<"\n"; +// return val; +// } +// if (d_bv->isLeaf(node)) { +// val = d_bitblaster->getVarValue(node); +// if (val == Node()) { +// // If no value in model, just set to 0 +// val = utils::mkConst(utils::getSize(node), (unsigned)0); +// } +// } else { +// NodeBuilder<> valBuilder(node.getKind()); +// if (node.getMetaKind() == kind::metakind::PARAMETERIZED) { +// valBuilder << node.getOperator(); +// } +// for (unsigned i = 0; i < node.getNumChildren(); ++i) { +// valBuilder << getModelValueRec(node[i]); +// } +// val = valBuilder; +// val = Rewriter::rewrite(val); +// } +// Assert(val.isConst()); +// d_modelCache[node] = val; +// Debug("bitvector-model") << node << " => " << val <<"\n"; +// return val; +// } + void BitblastSolver::setConflict(TNode conflict) { Node final_conflict = conflict; diff --git a/src/theory/bv/bv_subtheory_bitblast.h b/src/theory/bv/bv_subtheory_bitblast.h index 414abdcce..77461163c 100644 --- a/src/theory/bv/bv_subtheory_bitblast.h +++ b/src/theory/bv/bv_subtheory_bitblast.h @@ -57,7 +57,7 @@ class BitblastSolver : public SubtheorySolver { AbstractionModule* d_abstractionModule; BVQuickCheck* d_quickCheck; QuickXPlain* d_quickXplain; - Node getModelValueRec(TNode node); + // Node getModelValueRec(TNode node); void setConflict(TNode conflict); public: BitblastSolver(context::Context* c, TheoryBV* bv); diff --git a/src/theory/bv/eager_bitblaster.cpp b/src/theory/bv/eager_bitblaster.cpp index e8fee00f5..877baec4e 100644 --- a/src/theory/bv/eager_bitblaster.cpp +++ b/src/theory/bv/eager_bitblaster.cpp @@ -56,7 +56,7 @@ EagerBitblaster::~EagerBitblaster() { } void EagerBitblaster::bbFormula(TNode node) { - d_cnfStream->convertAndAssert(node, false, false); + d_cnfStream->convertAndAssert(node, false, false, RULE_INVALID, TNode::null()); } /** @@ -85,7 +85,7 @@ void EagerBitblaster::bbAtom(TNode node) { AlwaysAssert (options::bitblastMode() == theory::bv::BITBLAST_MODE_EAGER); storeBBAtom(node, atom_definition); - d_cnfStream->convertAndAssert(atom_definition, false, false); + d_cnfStream->convertAndAssert(atom_definition, false, false, RULE_INVALID, TNode::null()); } void EagerBitblaster::storeBBAtom(TNode atom, Node atom_bb) { @@ -156,11 +156,11 @@ bool EagerBitblaster::solve() { * * @return */ -Node EagerBitblaster::getVarValue(TNode a, bool fullModel) { +Node EagerBitblaster::getModelFromSatSolver(TNode a, bool fullModel) { if (!hasBBTerm(a)) { - Assert(isSharedTerm(a)); - return Node(); + return fullModel? utils::mkConst(utils::getSize(a), 0u) : Node(); } + Bits bits; getBBTerm(a, bits); Integer value(0); @@ -171,7 +171,8 @@ Node EagerBitblaster::getVarValue(TNode a, bool fullModel) { bit_value = d_satSolver->value(bit); Assert (bit_value != prop::SAT_VALUE_UNKNOWN); } else { - // the bit is unconstrainted so we can give it an arbitrary value + if (!fullModel) return Node(); + // unconstrained bits default to false bit_value = prop::SAT_VALUE_FALSE; } Integer bit_int = bit_value == prop::SAT_VALUE_TRUE ? Integer(1) : Integer(0); @@ -182,19 +183,17 @@ Node EagerBitblaster::getVarValue(TNode a, bool fullModel) { void EagerBitblaster::collectModelInfo(TheoryModel* m, bool fullModel) { - TNodeSet::const_iterator it = d_variables.begin(); + TNodeSet::iterator it = d_variables.begin(); for (; it!= d_variables.end(); ++it) { TNode var = *it; - if (Theory::theoryOf(var) == theory::THEORY_BV || isSharedTerm(var)) { - Node const_value = getVarValue(var, fullModel); - if(const_value == Node()) { - if( fullModel ){ - // if the value is unassigned just set it to zero - const_value = utils::mkConst(BitVector(utils::getSize(var), 0u)); - } - } + if (d_bv->isLeaf(var) || isSharedTerm(var)) { + // only shared terms could not have been bit-blasted + Assert (hasBBTerm(var) || isSharedTerm(var)); + + Node const_value = getModelFromSatSolver(var, fullModel); + if(const_value != Node()) { - Debug("bitvector-model") << "TLazyBitblaster::collectModelInfo (assert (= " + Debug("bitvector-model") << "EagerBitblaster::collectModelInfo (assert (= " << var << " " << const_value << "))\n"; m->assertEquality(var, const_value, true); diff --git a/src/theory/bv/lazy_bitblaster.cpp b/src/theory/bv/lazy_bitblaster.cpp index f721a22f0..f8927284f 100644 --- a/src/theory/bv/lazy_bitblaster.cpp +++ b/src/theory/bv/lazy_bitblaster.cpp @@ -41,6 +41,7 @@ TLazyBitblaster::TLazyBitblaster(context::Context* c, bv::TheoryBV* bv, const st , d_bbAtoms() , d_abstraction(NULL) , d_emptyNotify(emptyNotify) + , d_satSolverFullModel(c, false) , d_name(name) , d_statistics(name) { d_satSolver = prop::SatSolverFactory::createMinisat(c, name); @@ -113,7 +114,7 @@ void TLazyBitblaster::bbAtom(TNode node) { Assert (!atom_bb.isNull()); Node atom_definition = utils::mkNode(kind::IFF, node, atom_bb); storeBBAtom(node, atom_bb); - d_cnfStream->convertAndAssert(atom_definition, false, false); + d_cnfStream->convertAndAssert(atom_definition, false, false, RULE_INVALID, TNode::null()); return; } @@ -125,7 +126,7 @@ void TLazyBitblaster::bbAtom(TNode node) { // asserting that the atom is true iff the definition holds Node atom_definition = utils::mkNode(kind::IFF, node, atom_bb); storeBBAtom(node, atom_bb); - d_cnfStream->convertAndAssert(atom_definition, false, false); + d_cnfStream->convertAndAssert(atom_definition, false, false, RULE_INVALID, TNode::null()); } void TLazyBitblaster::storeBBAtom(TNode atom, Node atom_bb) { @@ -258,6 +259,7 @@ bool TLazyBitblaster::solve() { } } Debug("bitvector") << "TLazyBitblaster::solve() asserted atoms " << d_assertedAtoms->size() <<"\n"; + d_satSolverFullModel.set(true); return prop::SAT_VALUE_TRUE == d_satSolver->solve(); } @@ -354,42 +356,38 @@ void TLazyBitblaster::MinisatNotify::safePoint() { d_bv->d_out->safePoint(); } + EqualityStatus TLazyBitblaster::getEqualityStatus(TNode a, TNode b) { + Debug("bv-equality-status")<< "TLazyBitblaster::getEqualityStatus " << a <<" = " << b <<"\n"; + Debug("bv-equality-status")<< "BVSatSolver has full model? " << d_satSolverFullModel.get() <<"\n"; - // We don't want to bit-blast every possibly expensive term for the sake of equality checking - if (hasBBTerm(a) && hasBBTerm(b)) { - - Bits a_bits, b_bits; - getBBTerm(a, a_bits); - getBBTerm(b, b_bits); - theory::EqualityStatus status = theory::EQUALITY_TRUE_IN_MODEL; - for (unsigned i = 0; i < a_bits.size(); ++ i) { - if (d_cnfStream->hasLiteral(a_bits[i]) && d_cnfStream->hasLiteral(b_bits[i])) { - prop::SatLiteral a_lit = d_cnfStream->getLiteral(a_bits[i]); - prop::SatValue a_lit_value = d_satSolver->value(a_lit); - if (a_lit_value != prop::SAT_VALUE_UNKNOWN) { - prop::SatLiteral b_lit = d_cnfStream->getLiteral(b_bits[i]); - prop::SatValue b_lit_value = d_satSolver->value(b_lit); - if (b_lit_value != prop::SAT_VALUE_UNKNOWN) { - if (a_lit_value != b_lit_value) { - return theory::EQUALITY_FALSE_IN_MODEL; - } - } else { - status = theory::EQUALITY_UNKNOWN; - } - } { - status = theory::EQUALITY_UNKNOWN; - } - } else { - status = theory::EQUALITY_UNKNOWN; - } - } + // First check if it trivially rewrites to false/true + Node a_eq_b = Rewriter::rewrite(utils::mkNode(kind::EQUAL, a, b)); - return status; + if (a_eq_b == utils::mkFalse()) return theory::EQUALITY_FALSE; + if (a_eq_b == utils::mkTrue()) return theory::EQUALITY_TRUE; - } else { - return theory::EQUALITY_UNKNOWN; + if (!d_satSolverFullModel.get()) + return theory::EQUALITY_UNKNOWN; + + // Check if cache is valid (invalidated in check and pops) + if (d_bv->d_invalidateModelCache.get()) { + invalidateModelCache(); } + d_bv->d_invalidateModelCache.set(false); + + Node a_value = getTermModel(a, true); + Node b_value = getTermModel(b, true); + + Assert (a_value.isConst() && + b_value.isConst()); + + if (a_value == b_value) { + Debug("bv-equality-status")<< "theory::EQUALITY_TRUE_IN_MODEL\n"; + return theory::EQUALITY_TRUE_IN_MODEL; + } + Debug("bv-equality-status")<< "theory::EQUALITY_FALSE_IN_MODEL\n"; + return theory::EQUALITY_FALSE_IN_MODEL; } @@ -424,11 +422,11 @@ bool TLazyBitblaster::hasValue(TNode a) { * * @return */ -Node TLazyBitblaster::getVarValue(TNode a, bool fullModel) { +Node TLazyBitblaster::getModelFromSatSolver(TNode a, bool fullModel) { if (!hasBBTerm(a)) { - Assert(isSharedTerm(a)); - return Node(); + return fullModel? utils::mkConst(utils::getSize(a), 0u) : Node(); } + Bits bits; getBBTerm(a, bits); Integer value(0); @@ -439,7 +437,8 @@ Node TLazyBitblaster::getVarValue(TNode a, bool fullModel) { bit_value = d_satSolver->value(bit); Assert (bit_value != prop::SAT_VALUE_UNKNOWN); } else { - // the bit is unconstrainted so we can give it an arbitrary value + if (!fullModel) return Node(); + // unconstrained bits default to false bit_value = prop::SAT_VALUE_FALSE; } Integer bit_int = bit_value == prop::SAT_VALUE_TRUE ? Integer(1) : Integer(0); @@ -449,23 +448,26 @@ Node TLazyBitblaster::getVarValue(TNode a, bool fullModel) { } void TLazyBitblaster::collectModelInfo(TheoryModel* m, bool fullModel) { - TNodeSet::iterator it = d_variables.begin(); - for (; it!= d_variables.end(); ++it) { + std::set<Node> termSet; + d_bv->computeRelevantTerms(termSet); + + for (std::set<Node>::const_iterator it = termSet.begin(); it != termSet.end(); ++it) { TNode var = *it; - if (Theory::theoryOf(var) == theory::THEORY_BV || isSharedTerm(var)) { - Node const_value = getVarValue(var, fullModel); - if(const_value == Node()) { - if( fullModel ){ - // if the value is unassigned just set it to zero - const_value = utils::mkConst(BitVector(utils::getSize(var), 0u)); - } - } - if(const_value != Node()) { - Debug("bitvector-model") << "TLazyBitblaster::collectModelInfo (assert (= " - << var << " " - << const_value << "))\n"; + // not actually a leaf of the bit-vector theory + if (d_variables.find(var) == d_variables.end()) + continue; + + Assert (Theory::theoryOf(var) == theory::THEORY_BV || isSharedTerm(var)); + // only shared terms could not have been bit-blasted + Assert (hasBBTerm(var) || isSharedTerm(var)); + + Node const_value = getModelFromSatSolver(var, fullModel); + Assert (const_value.isNull() || const_value.isConst()); + if(const_value != Node()) { + Debug("bitvector-model") << "TLazyBitblaster::collectModelInfo (assert (= " + << var << " " + << const_value << "))\n"; m->assertEquality(var, const_value, true); - } } } } @@ -481,7 +483,7 @@ void TLazyBitblaster::clearSolver() { d_bbAtoms.clear(); d_variables.clear(); d_termCache.clear(); - + // recreate sat solver d_satSolver = prop::SatSolverFactory::createMinisat(d_ctx); d_cnfStream = new prop::TseitinCnfStream(d_satSolver, diff --git a/src/theory/bv/theory_bv.cpp b/src/theory/bv/theory_bv.cpp index 4abf25bb1..91150f663 100644 --- a/src/theory/bv/theory_bv.cpp +++ b/src/theory/bv/theory_bv.cpp @@ -49,6 +49,7 @@ TheoryBV::TheoryBV(context::Context* c, context::UserContext* u, OutputChannel& d_staticLearnCache(), d_lemmasAdded(c, false), d_conflict(c, false), + d_invalidateModelCache(c, true), d_literalsToPropagate(c), d_literalsToPropagateIndex(c, 0), d_propagatedBy(c), @@ -356,8 +357,12 @@ void TheoryBV::checkForLemma(TNode fact) { void TheoryBV::check(Effort e) { + if (done() && !fullEffort(e)) { + return; + } Debug("bitvector") << "TheoryBV::check(" << e << ")" << std::endl; - + // we may be getting new assertions so the model cache may not be sound + d_invalidateModelCache.set(true); // if we are using the eager solver if (options::bitblastMode() == theory::bv::BITBLAST_MODE_EAGER) { // this can only happen on an empty benchmark diff --git a/src/theory/bv/theory_bv.h b/src/theory/bv/theory_bv.h index 22d9f6775..a37a4019e 100644 --- a/src/theory/bv/theory_bv.h +++ b/src/theory/bv/theory_bv.h @@ -141,6 +141,9 @@ private: // Are we in conflict? context::CDO<bool> d_conflict; + // Invalidate the model cache if check was called + context::CDO<bool> d_invalidateModelCache; + /** The conflict node */ Node d_conflictNode; diff --git a/src/theory/datatypes/kinds b/src/theory/datatypes/kinds index d8b42111c..faaf78fe4 100644 --- a/src/theory/datatypes/kinds +++ b/src/theory/datatypes/kinds @@ -89,6 +89,12 @@ typerule APPLY_TYPE_ASCRIPTION ::CVC4::theory::datatypes::DatatypeAscriptionType # constructor applications are constant if they are applied only to constants construle APPLY_CONSTRUCTOR ::CVC4::theory::datatypes::DatatypeConstructorTypeRule +## for co-datatypes +operator MU 2 "a mu operator, first argument is a bound variable, second argument is body" +typerule MU ::CVC4::theory::datatypes::DatatypeMuTypeRule +# mu applications are constant expressions +construle MU ::CVC4::theory::datatypes::DatatypeMuTypeRule + operator TUPLE_TYPE 0: "tuple type" cardinality TUPLE_TYPE \ "::CVC4::theory::datatypes::TupleProperties::computeCardinality(%TYPE%)" \ diff --git a/src/theory/datatypes/options b/src/theory/datatypes/options index 5fc59b549..7e56b4d7a 100644 --- a/src/theory/datatypes/options +++ b/src/theory/datatypes/options @@ -13,5 +13,7 @@ expert-option dtRewriteErrorSel --dt-rewrite-error-sel bool :default false rewrite incorrectly applied selectors to arbitrary ground term option dtForceAssignment --dt-force-assignment bool :default false :read-write force the datatypes solver to give specific values to all datatypes terms before answering sat +option cdtBisimilar --cdt-bisimilar bool :default true + do bisimilarity check for co-datatypes endmodule diff --git a/src/theory/datatypes/theory_datatypes.cpp b/src/theory/datatypes/theory_datatypes.cpp index 544589306..145cd32dd 100644 --- a/src/theory/datatypes/theory_datatypes.cpp +++ b/src/theory/datatypes/theory_datatypes.cpp @@ -62,6 +62,7 @@ TheoryDatatypes::TheoryDatatypes(Context* c, UserContext* u, OutputChannel& out, d_equalityEngine.addFunctionKind(kind::APPLY_UF); d_true = NodeManager::currentNM()->mkConst( true ); + d_dtfCounter = 0; } TheoryDatatypes::~TheoryDatatypes() { @@ -118,6 +119,10 @@ TNode TheoryDatatypes::getEqcConstructor( TNode r ) { } void TheoryDatatypes::check(Effort e) { + if (done() && !fullEffort(e)) { + return; + } + Trace("datatypes-debug") << "Check effort " << e << std::endl; while(!done() && !d_conflict) { // Get all the assertions @@ -142,7 +147,7 @@ void TheoryDatatypes::check(Effort e) { flushPendingFacts(); } - if( e == EFFORT_FULL ) { + if( e == EFFORT_FULL && !d_conflict ) { //check for cycles bool addedFact; do { @@ -190,19 +195,23 @@ void TheoryDatatypes::check(Effort e) { } } } - /* - if( !needSplit && mustSpecifyAssignment() ){ + //d_dtfCounter++; + if( !needSplit && options::dtForceAssignment() && d_dtfCounter%2==0 ){ //for the sake of termination, we must choose the constructor of a ground term //NEED GUARENTEE: groundTerm should not contain any subterms of the same type // TODO: this is probably not good enough, actually need fair enumeration strategy - Node groundTerm = n.getType().mkGroundTerm(); - int index = Datatype::indexOf( groundTerm.getOperator().toExpr() ); - if( pcons[index] ){ - consIndex = index; + if( !n.getType().isRecord() ){ //FIXME + Node groundTerm = n.getType().mkGroundTerm(); + if( groundTerm.getOperator().getType().isConstructor() ){ //FIXME + int index = Datatype::indexOf( groundTerm.getOperator().toExpr() ); + if( pcons[index] ){ + consIndex = index; + } + needSplit = true; + } } - needSplit = true; } - */ + if( needSplit && consIndex!=-1 ) { //if only one constructor, then this term must be this constructor if( dt.getNumConstructors()==1 ){ @@ -570,7 +579,12 @@ void TheoryDatatypes::explain(TNode literal, std::vector<TNode>& assumptions){ TNode atom = polarity ? literal : literal[0]; if (atom.getKind() == kind::EQUAL || atom.getKind() == kind::IFF) { explainEquality( atom[0], atom[1], polarity, assumptions ); + } else if( atom.getKind() == kind::AND && polarity ){ + for( unsigned i=0; i<atom.getNumChildren(); i++ ){ + explain( atom[i], assumptions ); + } } else { + Assert( atom.getKind()!=kind::AND ); explainPredicate( atom, polarity, assumptions ); } } @@ -670,7 +684,7 @@ void TheoryDatatypes::merge( Node t1, Node t2 ){ for( unsigned i=0; i<deq_cand.size(); i++ ){ if( d_equalityEngine.areDisequal( deq_cand[i].first, deq_cand[i].second, true ) ){ conf = true; - Node eq = NodeManager::currentNM()->mkNode( deq_cand[i].first.getType().isBoolean() ? kind::IFF : kind::EQUAL, + Node eq = NodeManager::currentNM()->mkNode( deq_cand[i].first.getType().isBoolean() ? kind::IFF : kind::EQUAL, deq_cand[i].first, deq_cand[i].second ); exp.push_back( eq.negate() ); } @@ -1307,32 +1321,44 @@ void TheoryDatatypes::collectModelInfo( TheoryModel* m, bool fullModel ){ const Datatype& dt = ((DatatypeType)(eqc.getType()).toType()).getDatatype(); if( dt.isCodatatype() ){ std::map< Node, Node > vmap; - Node v = getCodatatypesValue( it->first, eqc_cons, eqc_mu, vmap ); - Trace("dt-cmi-cod") << " EQC(" << it->first << "), constructor is " << it->second << ", value is " << v << std::endl; + std::vector< Node > fv; + Node v = getCodatatypesValue( it->first, eqc_cons, eqc_mu, vmap, fv ); + Trace("dt-cmi-cdt") << " EQC(" << it->first << "), constructor is " << it->second << ", value is " << v << ", const = " << v.isConst() << std::endl; + m->assertEquality( eqc, v, true ); } } } -Node TheoryDatatypes::getCodatatypesValue( Node n, std::map< Node, Node >& eqc_cons, std::map< Node, Node >& eqc_mu, std::map< Node, Node >& vmap ){ +Node TheoryDatatypes::getCodatatypesValue( Node n, std::map< Node, Node >& eqc_cons, std::map< Node, Node >& eqc_mu, std::map< Node, Node >& vmap, std::vector< Node >& fv ){ std::map< Node, Node >::iterator itv = vmap.find( n ); if( itv!=vmap.end() ){ + if( std::find( fv.begin(), fv.end(), itv->second )==fv.end() ){ + fv.push_back( itv->second ); + } return itv->second; }else if( DatatypesRewriter::isTermDatatype( n ) ){ - Node nv = NodeManager::currentNM()->mkBoundVar( n.getType() ); + std::stringstream ss; + ss << "$x" << vmap.size(); + Node nv = NodeManager::currentNM()->mkBoundVar( ss.str().c_str(), n.getType() ); vmap[n] = nv; - Trace("dt-cmi-cod-debug") << " map " << n << " -> " << nv << std::endl; + Trace("dt-cmi-cdt-debug") << " map " << n << " -> " << nv << std::endl; Node nc = eqc_cons[n]; Assert( nc.getKind()==APPLY_CONSTRUCTOR ); std::vector< Node > children; children.push_back( nc.getOperator() ); for( unsigned i=0; i<nc.getNumChildren(); i++ ){ Node r = getRepresentative( nc[i] ); - Node rv = getCodatatypesValue( r, eqc_cons, eqc_mu, vmap ); + Node rv = getCodatatypesValue( r, eqc_cons, eqc_mu, vmap, fv ); children.push_back( rv ); } vmap.erase( n ); - return NodeManager::currentNM()->mkNode( APPLY_CONSTRUCTOR, children ); + Node v = NodeManager::currentNM()->mkNode( APPLY_CONSTRUCTOR, children ); + //add mu if we found a circular reference + if( std::find( fv.begin(), fv.end(), nv )!=fv.end() ){ + v = NodeManager::currentNM()->mkNode( MU, nv, v ); + } + return v; }else{ return n; } @@ -1450,7 +1476,7 @@ void TheoryDatatypes::instantiate( EqcInfo* eqc, Node n ){ void TheoryDatatypes::checkCycles() { Debug("datatypes-cycle-check") << "Check cycles" << std::endl; - std::vector< Node > cod_eqc; + std::vector< Node > cdt_eqc; eq::EqClassesIterator eqcs_i = eq::EqClassesIterator( &d_equalityEngine ); while( !eqcs_i.isFinished() ){ Node eqc = (*eqcs_i); @@ -1481,27 +1507,30 @@ void TheoryDatatypes::checkCycles() { } }else{ //indexing - cod_eqc.push_back( eqc ); + cdt_eqc.push_back( eqc ); } } ++eqcs_i; } //process codatatypes - if( cod_eqc.size()>1 ){ + if( cdt_eqc.size()>1 && options::cdtBisimilar() ){ + Trace("dt-cdt-debug") << "Process " << cdt_eqc.size() << " co-datatypes" << std::endl; std::vector< std::vector< Node > > part_out; std::vector< TNode > exp; std::map< Node, Node > cn; std::map< Node, std::map< Node, int > > dni; - for( unsigned i=0; i<cod_eqc.size(); i++ ){ - cn[cod_eqc[i]] = cod_eqc[i]; + for( unsigned i=0; i<cdt_eqc.size(); i++ ){ + cn[cdt_eqc[i]] = cdt_eqc[i]; } - separateBisimilar( cod_eqc, part_out, exp, cn, dni, 0, false ); + separateBisimilar( cdt_eqc, part_out, exp, cn, dni, 0, false ); + Trace("dt-cdt-debug") << "Done separate bisimilar." << std::endl; if( !part_out.empty() ){ + Trace("dt-cdt-debug") << "Process partition size " << part_out.size() << std::endl; for( unsigned i=0; i<part_out.size(); i++ ){ std::vector< Node > part; part.push_back( part_out[i][0] ); for( unsigned j=1; j<part_out[i].size(); j++ ){ - Trace("dt-cod") << "Codatatypes : " << part_out[i][0] << " and " << part_out[i][j] << " must be equal!!" << std::endl; + Trace("dt-cdt") << "Codatatypes : " << part_out[i][0] << " and " << part_out[i][j] << " must be equal!!" << std::endl; part.push_back( part_out[i][j] ); std::vector< std::vector< Node > > tpart_out; exp.clear(); @@ -1513,16 +1542,16 @@ void TheoryDatatypes::checkCycles() { Assert( tpart_out.size()==1 && tpart_out[0].size()==2 ); part.pop_back(); //merge based on explanation - Trace("dt-cod") << " exp is : "; + Trace("dt-cdt") << " exp is : "; for( unsigned k=0; k<exp.size(); k++ ){ - Trace("dt-cod") << exp[k] << " "; + Trace("dt-cdt") << exp[k] << " "; } - Trace("dt-cod") << std::endl; + Trace("dt-cdt") << std::endl; Node eq = part_out[i][0].eqNode( part_out[i][j] ); Node eqExp = mkAnd( exp ); d_pending.push_back( eq ); d_pending_exp[ eq ] = eqExp; - Trace("datatypes-infer") << "DtInfer : cod-bisimilar : " << eq << " by " << eqExp << std::endl; + Trace("datatypes-infer") << "DtInfer : cdt-bisimilar : " << eq << " by " << eqExp << std::endl; d_infer.push_back( eq ); d_infer_exp.push_back( eqExp ); } @@ -1537,9 +1566,9 @@ void TheoryDatatypes::separateBisimilar( std::vector< Node >& part, std::vector< std::map< Node, Node >& cn, std::map< Node, std::map< Node, int > >& dni, int dniLvl, bool mkExp ){ if( !mkExp ){ - Trace("dt-cod-debug") << "Separate bisimilar : " << std::endl; + Trace("dt-cdt-debug") << "Separate bisimilar : " << std::endl; for( unsigned i=0; i<part.size(); i++ ){ - Trace("dt-cod-debug") << " " << part[i] << ", current = " << cn[part[i]] << std::endl; + Trace("dt-cdt-debug") << " " << part[i] << ", current = " << cn[part[i]] << std::endl; } } Assert( part.size()>1 ); @@ -1553,7 +1582,7 @@ void TheoryDatatypes::separateBisimilar( std::vector< Node >& part, std::vector< std::map< Node, int >::iterator it_rec = dni[part[j]].find( c ); if( it_rec!=dni[part[j]].end() ){ //looped - if( !mkExp ){ Trace("dt-cod-debug") << " - " << part[j] << " is looping at index " << it_rec->second << std::endl; } + if( !mkExp ){ Trace("dt-cdt-debug") << " - " << part[j] << " is looping at index " << it_rec->second << std::endl; } new_part_rec[ it_rec->second ].push_back( part[j] ); }else{ if( DatatypesRewriter::isTermDatatype( c ) ){ @@ -1565,14 +1594,14 @@ void TheoryDatatypes::separateBisimilar( std::vector< Node >& part, std::vector< explainEquality( c, ncons, true, exp ); } new_part[cc].push_back( part[j] ); - if( !mkExp ){ Trace("dt-cod-debug") << " - " << part[j] << " is datatype " << ncons << "." << std::endl; } + if( !mkExp ){ Trace("dt-cdt-debug") << " - " << part[j] << " is datatype " << ncons << "." << std::endl; } }else{ new_part_c[c].push_back( part[j] ); - if( !mkExp ){ Trace("dt-cod-debug") << " - " << part[j] << " is unspecified datatype." << std::endl; } + if( !mkExp ){ Trace("dt-cdt-debug") << " - " << part[j] << " is unspecified datatype." << std::endl; } } }else{ //add equivalences - if( !mkExp ){ Trace("dt-cod-debug") << " - " << part[j] << " is term " << c << "." << std::endl; } + if( !mkExp ){ Trace("dt-cdt-debug") << " - " << part[j] << " is term " << c << "." << std::endl; } new_part_c[c].push_back( part[j] ); } } @@ -1614,7 +1643,7 @@ void TheoryDatatypes::separateBisimilar( std::vector< Node >& part, std::vector< //for each child of constructor unsigned cindex = 0; while( cindex<nChildren && !split_new_part.empty() ){ - if( !mkExp ){ Trace("dt-cod-debug") << "Split argument #" << cindex << " of " << it->first << "..." << std::endl; } + if( !mkExp ){ Trace("dt-cdt-debug") << "Split argument #" << cindex << " of " << it->first << "..." << std::endl; } std::vector< std::vector< Node > > next_split_new_part; for( unsigned j=0; j<split_new_part.size(); j++ ){ //set current node diff --git a/src/theory/datatypes/theory_datatypes.h b/src/theory/datatypes/theory_datatypes.h index 132077e29..74d10e754 100644 --- a/src/theory/datatypes/theory_datatypes.h +++ b/src/theory/datatypes/theory_datatypes.h @@ -174,6 +174,8 @@ private: context::CDList<TNode> d_consTerms; /** All the selector terms that the theory has seen */ context::CDList<TNode> d_selTerms; + /** counter for forcing assignments (ensures fairness) */ + unsigned d_dtfCounter; private: /** assert fact */ void assertFact( Node fact, Node exp ); @@ -254,7 +256,7 @@ private: std::map< Node, Node >& cn, std::map< Node, std::map< Node, int > >& dni, int dniLvl, bool mkExp ); /** build model */ - Node getCodatatypesValue( Node n, std::map< Node, Node >& eqc_cons, std::map< Node, Node >& eqc_mu, std::map< Node, Node >& vmap ); + Node getCodatatypesValue( Node n, std::map< Node, Node >& eqc_cons, std::map< Node, Node >& eqc_mu, std::map< Node, Node >& vmap, std::vector< Node >& fv ); /** collect terms */ void collectTerms( Node n ); /** get instantiate cons */ diff --git a/src/theory/datatypes/theory_datatypes_type_rules.h b/src/theory/datatypes/theory_datatypes_type_rules.h index ddad913fe..8ce8ee7df 100644 --- a/src/theory/datatypes/theory_datatypes_type_rules.h +++ b/src/theory/datatypes/theory_datatypes_type_rules.h @@ -209,6 +209,49 @@ struct DatatypeAscriptionTypeRule { } };/* struct DatatypeAscriptionTypeRule */ +/* For co-datatypes */ +class DatatypeMuTypeRule { +private: + //a Mu-expression is constant iff its body is composed of constructors applied to constant expr and bound variables only + inline static bool computeIsConstNode(TNode n, std::vector< TNode >& fv ){ + if( n.getKind()==kind::MU ){ + fv.push_back( n[0] ); + bool ret = computeIsConstNode( n[1], fv ); + fv.pop_back(); + return ret; + }else if( n.isConst() || std::find( fv.begin(), fv.end(), n )!=fv.end() ){ + return true; + }else if( n.getKind()==kind::APPLY_CONSTRUCTOR ){ + for( unsigned i=0; i<n.getNumChildren(); i++ ){ + if( !computeIsConstNode( n[i], fv ) ){ + return false; + } + } + return true; + }else{ + return false; + } + } +public: + inline static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check) { + if( n[0].getKind()!=kind::BOUND_VARIABLE ) { + std::stringstream ss; + ss << "expected a bound var for MU expression, got `" + << n[0] << "'"; + throw TypeCheckingExceptionPrivate(n, ss.str()); + } + return n[1].getType(check); + } + inline static bool computeIsConst(NodeManager* nodeManager, TNode n) + throw(AssertionException) { + Assert(n.getKind() == kind::MU); + NodeManagerScope nms(nodeManager); + std::vector< TNode > fv; + return computeIsConstNode( n, fv ); + } +}; + + struct ConstructorProperties { inline static Cardinality computeCardinality(TypeNode type) { // Constructors aren't exactly functions, they're like diff --git a/src/theory/datatypes/type_enumerator.h b/src/theory/datatypes/type_enumerator.h index 256dcaef2..dc2a83841 100644 --- a/src/theory/datatypes/type_enumerator.h +++ b/src/theory/datatypes/type_enumerator.h @@ -28,168 +28,254 @@ namespace CVC4 { namespace theory { namespace datatypes { + class DatatypesEnumerator : public TypeEnumeratorBase<DatatypesEnumerator> { /** The datatype we're enumerating */ const Datatype& d_datatype; - /** The datatype constructor we're currently enumerating */ - size_t d_ctor; - /** The "first" constructor to consider; it's non-recursive */ - size_t d_zeroCtor; - /** Delegate enumerators for the arguments of the current constructor */ - TypeEnumerator** d_argEnumerators; /** type */ TypeNode d_type; - - /** Allocate and initialize the delegate enumerators */ - void newEnumerators() { - d_argEnumerators = new TypeEnumerator*[d_datatype[d_ctor].getNumArgs()]; - for(size_t a = 0; a < d_datatype[d_ctor].getNumArgs(); ++a) { - d_argEnumerators[a] = NULL; + /** The datatype constructor we're currently enumerating */ + unsigned d_ctor; + /** The "first" constructor to consider; it's non-recursive */ + unsigned d_zeroCtor; + /** list of type enumerators (one for each type in a selector argument) */ + std::map< TypeNode, unsigned > d_te_index; + std::vector< TypeEnumerator > d_children; + /** terms produced for types */ + std::map< TypeNode, std::vector< Node > > d_terms; + /** arg type of each selector, for each constructor */ + std::vector< std::vector< TypeNode > > d_sel_types; + /** current index for each argument, for each constructor */ + std::vector< std::vector< unsigned > > d_sel_index; + /** current sum of argument indicies for each constructor */ + std::vector< int > d_sel_sum; + /** current bound on the number of times we can iterate argument enumerators */ + unsigned d_size_limit; + + Node getTermEnum( TypeNode tn, unsigned i ){ + if( i<d_terms[tn].size() ){ + return 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; + 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; + return d_terms[tn][i]; } } - /** Delete the delegate enumerators */ - void deleteEnumerators() { - if(d_argEnumerators != NULL) { - for(size_t a = 0; a < d_datatype[d_ctor].getNumArgs(); ++a) { - delete d_argEnumerators[a]; + bool increment( unsigned index ){ + Debug("dt-enum") << "Incrementing " << d_type << " " << d_ctor << " at size " << d_sel_sum[index] << "/" << d_size_limit << std::endl; + if( d_sel_sum[index]==-1 ){ + //first time + d_sel_sum[index] = 0; + //special case: no children to iterate + if( d_sel_types[index].size()==0 ){ + Debug("dt-enum") << "...success (nc) = " << (d_size_limit==0) << std::endl; + return d_size_limit==0; + }else{ + Debug("dt-enum") << "...success" << std::endl; + return true; + } + }else{ + unsigned i = 0; + while( i < d_sel_index[index].size() ){ + //increment if the sum of iterations on arguments is less than the limit + if( d_sel_sum[index]<(int)d_size_limit ){ + //also check if child enumerator has enough terms + if( !getTermEnum( d_sel_types[index][i], d_sel_index[index][i]+1 ).isNull() ){ + Debug("dt-enum") << "...success increment child " << i << std::endl; + d_sel_index[index][i]++; + d_sel_sum[index]++; + return true; + } + } + Debug("dt-enum") << "......failed increment child " << i << std::endl; + //reset child, iterate next + d_sel_sum[index] -= d_sel_index[index][i]; + d_sel_index[index][i] = 0; + i++; } - delete [] d_argEnumerators; - d_argEnumerators = NULL; + Debug("dt-enum") << "...failure." << std::endl; + return false; } } + Node getCurrentTerm( unsigned index ){ + Debug("dt-enum-debug") << "Get current term at " << index << " " << d_type << "..." << std::endl; + DatatypeConstructor ctor = d_datatype[index]; + Debug("dt-enum-debug") << "Check last term..." << std::endl; + //we first check if the last argument (which is forced to make sum of iterated arguments equal to d_size_limit) is defined + Node lc; + if( ctor.getNumArgs()>0 ){ + lc = getTermEnum( d_sel_types[index][ctor.getNumArgs()-1], d_size_limit - d_sel_sum[index] ); + if( lc.isNull() ){ + Debug("dt-enum-debug") << "Current infeasible." << std::endl; + return Node::null(); + } + } + Debug("dt-enum-debug") << "Get constructor..." << std::endl; + NodeBuilder<> b(kind::APPLY_CONSTRUCTOR); + Type typ; + if( d_datatype.isParametric() ){ + typ = ctor.getSpecializedConstructorType(d_type.toType()); + b << NodeManager::currentNM()->mkNode(kind::APPLY_TYPE_ASCRIPTION, + NodeManager::currentNM()->mkConst(AscriptionType(typ)), Node::fromExpr( ctor.getConstructor() ) ); + }else{ + b << ctor.getConstructor(); + } + Debug("dt-enum-debug") << "Get arguments..." << std::endl; + if( ctor.getNumArgs()>0 ){ + Assert( index<d_sel_types.size() ); + Assert( index<d_sel_index.size() ); + Assert( d_sel_types[index].size()==ctor.getNumArgs() ); + Assert( d_sel_index[index].size()==ctor.getNumArgs()-1 ); + for( int i=0; i<(int)(ctor.getNumArgs()-1); i++ ){ + Node c = getTermEnum( d_sel_types[index][i], d_sel_index[index][i] ); + Assert( !c.isNull() ); + b << c; + } + b << lc; + } + Node nnn = Node(b); + Debug("dt-enum-debug") << "Return... " << nnn << std::endl; + return nnn; + } public: DatatypesEnumerator(TypeNode type) throw() : TypeEnumeratorBase<DatatypesEnumerator>(type), d_datatype(DatatypeType(type.toType()).getDatatype()), + d_type(type), d_ctor(0), - d_zeroCtor(0), - d_argEnumerators(NULL), - d_type(type) { + d_zeroCtor(0) { //Assert(type.isDatatype()); Debug("te") << "datatype is datatype? " << type.isDatatype() << std::endl; Debug("te") << "datatype is kind " << type.getKind() << std::endl; Debug("te") << "datatype is " << type << std::endl; - /* find the "zero" constructor (the first non-recursive one) */ - /* FIXME: this isn't sufficient for mutually-recursive datatypes! */ - while(d_zeroCtor < d_datatype.getNumConstructors()) { - bool recursive = false; + /* find the "zero" constructor via mkGroundTerm */ + Node t = type.mkGroundTerm(); + Assert( t.getKind()==kind::APPLY_CONSTRUCTOR ); + d_zeroCtor = Datatype::indexOf( t.getOperator().toExpr() ); + /* start with the constructor for which a ground term is constructed */ + d_ctor = d_zeroCtor; + + for( unsigned i=0; i<d_datatype.getNumConstructors(); ++i ){ + d_sel_types.push_back( std::vector< TypeNode >() ); + d_sel_index.push_back( std::vector< unsigned >() ); + d_sel_sum.push_back( -1 ); + DatatypeConstructor ctor = d_datatype[i]; + Type typ; if( d_datatype.isParametric() ){ - TypeNode tn = TypeNode::fromType( d_datatype[d_zeroCtor].getSpecializedConstructorType(d_type.toType()) ); - for( unsigned i=0; i<tn.getNumChildren()-1; i++ ){ - if( tn[i]==type ){ - recursive = true; - break; - } - } - }else{ - for(size_t a = 0; a < d_datatype[d_zeroCtor].getNumArgs() && !recursive; ++a) { - if(Node::fromExpr(d_datatype[d_zeroCtor][a].getSelector()).getType()[1] == type) { - recursive = true; - break; - } + typ = ctor.getSpecializedConstructorType(d_type.toType()); + } + for( unsigned a = 0; a < ctor.getNumArgs(); ++a ){ + TypeNode tn; + if( d_datatype.isParametric() ){ + tn = TypeNode::fromType( typ )[a]; + }else{ + tn = Node::fromExpr(ctor[a].getSelector()).getType()[1]; } + d_sel_types[i].push_back( tn ); + d_sel_index[i].push_back( 0 ); } - if(!recursive) { - break; + if( !d_sel_index[i].empty() ){ + d_sel_index[i].pop_back(); } - ++d_zeroCtor; } - - /* start with the non-recursive constructor */ - d_ctor = d_zeroCtor; - - /* allocate space for the enumerators */ - newEnumerators(); + d_size_limit = 0; + //set up initial conditions (should always succeed) + bool init_inc = increment( d_ctor ); + AlwaysAssert( init_inc ); } DatatypesEnumerator(const DatatypesEnumerator& de) throw() : TypeEnumeratorBase<DatatypesEnumerator>(de.getType()), d_datatype(de.d_datatype), + d_type(de.d_type), d_ctor(de.d_ctor), - d_zeroCtor(de.d_zeroCtor), - d_argEnumerators(NULL), - d_type(de.d_type) { + d_zeroCtor(de.d_zeroCtor) { - if(de.d_argEnumerators != NULL) { - newEnumerators(); - for(size_t a = 0; a < d_datatype[d_ctor].getNumArgs(); ++a) { - if(de.d_argEnumerators[a] != NULL) { - d_argEnumerators[a] = new TypeEnumerator(*de.d_argEnumerators[a]); - } - } + for( std::map< TypeNode, unsigned >::const_iterator it = de.d_te_index.begin(); it != de.d_te_index.end(); ++it ){ + d_te_index[it->first] = it->second; + } + for( std::map< TypeNode, std::vector< Node > >::const_iterator it = de.d_terms.begin(); it != de.d_terms.end(); ++it ){ + d_terms[it->first].insert( d_terms[it->first].end(), it->second.begin(), it->second.end() ); + } + for( unsigned i=0; i<de.d_sel_types.size(); i++ ){ + d_sel_types.push_back( std::vector< TypeNode >() ); + d_sel_types[i].insert( d_sel_types[i].end(), de.d_sel_types[i].begin(), de.d_sel_types[i].end() ); } + for( unsigned i=0; i<de.d_sel_index.size(); i++ ){ + d_sel_index.push_back( std::vector< unsigned >() ); + d_sel_index[i].insert( d_sel_index[i].end(), de.d_sel_index[i].begin(), de.d_sel_index[i].end() ); + } + + d_children.insert( d_children.end(), de.d_children.begin(), de.d_children.end() ); + d_sel_sum.insert( d_sel_sum.end(), de.d_sel_sum.begin(), de.d_sel_sum.end() ); + d_size_limit = de.d_size_limit; } ~DatatypesEnumerator() throw() { - deleteEnumerators(); } Node operator*() throw(NoMoreValuesException) { + Debug("dt-enum-debug") << ": get term " << this << std::endl; if(d_ctor < d_datatype.getNumConstructors()) { - DatatypeConstructor ctor = d_datatype[d_ctor]; - NodeBuilder<> b(kind::APPLY_CONSTRUCTOR); - Type typ; - if( d_datatype.isParametric() ){ - typ = d_datatype[d_ctor].getSpecializedConstructorType(d_type.toType()); - b << NodeManager::currentNM()->mkNode(kind::APPLY_TYPE_ASCRIPTION, - NodeManager::currentNM()->mkConst(AscriptionType(typ)), Node::fromExpr( ctor.getConstructor() ) ); - }else{ - b << ctor.getConstructor(); - } - try { - for(size_t a = 0; a < d_datatype[d_ctor].getNumArgs(); ++a) { - if(d_argEnumerators[a] == NULL) { - if( d_datatype.isParametric() ){ - d_argEnumerators[a] = new TypeEnumerator(TypeNode::fromType( typ )[a]); - }else{ - d_argEnumerators[a] = new TypeEnumerator(Node::fromExpr(d_datatype[d_ctor][a].getSelector()).getType()[1]); - } - } - b << **d_argEnumerators[a]; - } - } catch(NoMoreValuesException&) { - InternalError(); - } - Node nnn = Node(b); - //if( nnn.getType()!=d_type || !nnn.getType().isComparableTo(d_type) ){ - // Debug("dt-warn") << "WARNING : Enum : " << nnn << " bad type : " << nnn.getType() << " " << d_type << std::endl; - //} - return nnn; + return getCurrentTerm( d_ctor ); } else { throw NoMoreValuesException(getType()); } } DatatypesEnumerator& operator++() throw() { - if(d_ctor < d_datatype.getNumConstructors()) { - for(size_t a = d_datatype[d_ctor].getNumArgs(); a > 0; --a) { - if((++*d_argEnumerators[a - 1]).isFinished()) { - *d_argEnumerators[a - 1] = TypeEnumerator(Node::fromExpr(d_datatype[d_ctor][a - 1].getSelector()).getType()[1]); - } else { + Debug("dt-enum-debug") << ": increment " << this << std::endl; + unsigned prevSize = d_size_limit; + while(d_ctor < d_datatype.getNumConstructors()) { + //increment at index + while( increment( d_ctor ) ){ + Node n = getCurrentTerm( d_ctor ); + if( !n.isNull() ){ return *this; } } - // Here, we need to step from the current constructor to the next one - // first, delete the current delegate enumerators - deleteEnumerators(); - // Find the next constructor (only complicated by the notion of the "zero" constructor d_ctor = (d_ctor == d_zeroCtor) ? 0 : d_ctor + 1; if(d_ctor == d_zeroCtor) { ++d_ctor; } - - // If we aren't out of constructors, allocate space for the new delegate enumerators - if(d_ctor < d_datatype.getNumConstructors()) { - newEnumerators(); + if( d_ctor>=d_datatype.getNumConstructors() ){ + //try next size limit as long as new terms were generated at last size + if( prevSize==d_size_limit ){ + d_size_limit++; + d_ctor = d_zeroCtor; + for( unsigned i=0; i<d_sel_sum.size(); i++ ){ + d_sel_sum[i] = -1; + } + } } } return *this; diff --git a/src/theory/idl/theory_idl.cpp b/src/theory/idl/theory_idl.cpp index 8597c117d..9e402f430 100644 --- a/src/theory/idl/theory_idl.cpp +++ b/src/theory/idl/theory_idl.cpp @@ -49,6 +49,10 @@ Node TheoryIdl::ppRewrite(TNode atom) { } void TheoryIdl::check(Effort level) { + //// Not needed for now, as no code outside while() loop below. + // if (done() && !fullEffort(e)) { + // return; + // } while(!done()) { diff --git a/src/theory/quantifiers/bounded_integers.cpp b/src/theory/quantifiers/bounded_integers.cpp index d6f9704b3..57799fd8e 100644 --- a/src/theory/quantifiers/bounded_integers.cpp +++ b/src/theory/quantifiers/bounded_integers.cpp @@ -243,8 +243,13 @@ void BoundedIntegers::process( Node f, Node n, bool pol, } } -void BoundedIntegers::check( Theory::Effort e ) { - if( e==Theory::EFFORT_LAST_CALL ){ +bool BoundedIntegers::needsCheck( Theory::Effort e ) { + return e==Theory::EFFORT_LAST_CALL; +} + +void BoundedIntegers::check( Theory::Effort e, unsigned quant_e ) { + if( quant_e==QuantifiersEngine::QEFFORT_STANDARD ){ + Trace("bint-engine") << "---Bounded Integers---" << std::endl; bool addedLemma = false; //make sure proxies are up-to-date with range for( unsigned i=0; i<d_ranges.size(); i++) { @@ -252,9 +257,7 @@ void BoundedIntegers::check( Theory::Effort e ) { addedLemma = true; } } - if( addedLemma ){ - d_quantEngine->flushLemmas( &d_quantEngine->getOutputChannel() ); - } + Trace("bint-engine") << " addedLemma = " << addedLemma << std::endl; } } diff --git a/src/theory/quantifiers/bounded_integers.h b/src/theory/quantifiers/bounded_integers.h index ac188ca65..355360e41 100644 --- a/src/theory/quantifiers/bounded_integers.h +++ b/src/theory/quantifiers/bounded_integers.h @@ -110,7 +110,8 @@ private: public: BoundedIntegers( context::Context* c, QuantifiersEngine* qe ); - void check( Theory::Effort e ); + bool needsCheck( Theory::Effort e ); + void check( Theory::Effort e, unsigned quant_e ); void registerQuantifier( Node f ); void assertNode( Node n ); Node getNextDecisionRequest(); diff --git a/src/theory/quantifiers/candidate_generator.cpp b/src/theory/quantifiers/candidate_generator.cpp index 9ce79c301..0f2adf3b4 100644 --- a/src/theory/quantifiers/candidate_generator.cpp +++ b/src/theory/quantifiers/candidate_generator.cpp @@ -213,7 +213,10 @@ Node CandidateGeneratorQELitDeq::getNextCandidate(){ CandidateGeneratorQEAll::CandidateGeneratorQEAll( QuantifiersEngine* qe, Node mpat ) : d_match_pattern( mpat ), d_qe( qe ){ - + d_match_pattern_type = mpat.getType(); + Assert( mpat.getKind()==INST_CONSTANT ); + d_f = quantifiers::TermDb::getInstConstAttr( mpat ); + d_index = mpat.getAttribute(InstVarNumAttribute()); } void CandidateGeneratorQEAll::resetInstantiationRound() { @@ -227,6 +230,9 @@ void CandidateGeneratorQEAll::reset( Node eqc ) { Node CandidateGeneratorQEAll::getNextCandidate() { while( !d_eq.isFinished() ){ Node n = (*d_eq); + if( options::instMaxLevel()!=-1 ){ + n = d_qe->getEqualityQuery()->getInternalRepresentative( n, d_f, d_index ); + } ++d_eq; if( n.getType().isSubtypeOf( d_match_pattern.getType() ) ){ //an equivalence class with the same type as the pattern, return it diff --git a/src/theory/quantifiers/candidate_generator.h b/src/theory/quantifiers/candidate_generator.h index 4569c2335..011e2924d 100644 --- a/src/theory/quantifiers/candidate_generator.h +++ b/src/theory/quantifiers/candidate_generator.h @@ -144,8 +144,12 @@ private: eq::EqClassesIterator d_eq; //equality you are trying to match equalities for Node d_match_pattern; + TypeNode d_match_pattern_type; //einstantiator pointer QuantifiersEngine* d_qe; + // quantifier/index for the variable we are matching + Node d_f; + unsigned d_index; public: CandidateGeneratorQEAll( QuantifiersEngine* qe, Node mpat ); ~CandidateGeneratorQEAll(){} diff --git a/src/theory/quantifiers/conjecture_generator.cpp b/src/theory/quantifiers/conjecture_generator.cpp new file mode 100755 index 000000000..fe3c92323 --- /dev/null +++ b/src/theory/quantifiers/conjecture_generator.cpp @@ -0,0 +1,2214 @@ +/********************* */
+/*! \file conjecture_generator.cpp
+ ** \verbatim
+ ** Original author: Andrew Reynolds
+ ** Major contributors: none
+ ** Minor contributors (to current version): none
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2014 New York University and The University of Iowa
+ ** See the file COPYING in the top-level source directory for licensing
+ ** information.\endverbatim
+ **
+ ** \brief conjecture generator class
+ **
+ **/
+
+#include "theory/quantifiers/conjecture_generator.h"
+#include "theory/theory_engine.h"
+#include "theory/quantifiers/options.h"
+#include "theory/quantifiers/term_database.h"
+#include "theory/quantifiers/trigger.h"
+#include "theory/quantifiers/first_order_model.h"
+
+using namespace CVC4;
+using namespace CVC4::kind;
+using namespace CVC4::theory;
+using namespace CVC4::theory::quantifiers;
+using namespace std;
+
+namespace CVC4 {
+
+struct sortConjectureScore {
+ std::vector< int > d_scores;
+ bool operator() (unsigned i, unsigned j) { return d_scores[i]>d_scores[j]; }
+};
+
+
+void OpArgIndex::addTerm( ConjectureGenerator * s, TNode n, unsigned index ){
+ if( index==n.getNumChildren() ){
+ Assert( n.hasOperator() );
+ if( std::find( d_ops.begin(), d_ops.end(), n.getOperator() )==d_ops.end() ){
+ d_ops.push_back( n.getOperator() );
+ d_op_terms.push_back( n );
+ }
+ }else{
+ d_child[s->getTermDatabase()->d_arg_reps[n][index]].addTerm( s, n, index+1 );
+ }
+}
+
+Node OpArgIndex::getGroundTerm( ConjectureGenerator * s, std::vector< TNode >& args ) {
+ if( d_ops.empty() ){
+ for( std::map< TNode, OpArgIndex >::iterator it = d_child.begin(); it != d_child.end(); ++it ){
+ std::map< TNode, Node >::iterator itf = s->d_ground_eqc_map.find( it->first );
+ if( itf!=s->d_ground_eqc_map.end() ){
+ args.push_back( itf->second );
+ Node n = it->second.getGroundTerm( s, args );
+ args.pop_back();
+ if( !n.isNull() ){
+ return n;
+ }
+ }
+ }
+ return Node::null();
+ }else{
+ std::vector< TNode > args2;
+ args2.push_back( d_ops[0] );
+ args2.insert( args2.end(), args.begin(), args.end() );
+ return NodeManager::currentNM()->mkNode( d_op_terms[0].getKind(), args2 );
+ }
+}
+
+void OpArgIndex::getGroundTerms( ConjectureGenerator * s, std::vector< TNode >& terms ) {
+ terms.insert( terms.end(), d_op_terms.begin(), d_op_terms.end() );
+ for( std::map< TNode, OpArgIndex >::iterator it = d_child.begin(); it != d_child.end(); ++it ){
+ if( s->isGroundEqc( it->first ) ){
+ it->second.getGroundTerms( s, terms );
+ }
+ }
+}
+
+
+
+ConjectureGenerator::ConjectureGenerator( QuantifiersEngine * qe, context::Context* c ) : QuantifiersModule( qe ),
+d_notify( *this ),
+d_uequalityEngine(d_notify, c, "ConjectureGenerator::ee"),
+d_ee_conjectures( c ){
+ d_fullEffortCount = 0;
+ d_uequalityEngine.addFunctionKind( kind::APPLY_UF );
+ d_uequalityEngine.addFunctionKind( kind::APPLY_CONSTRUCTOR );
+
+}
+
+void ConjectureGenerator::eqNotifyNewClass( TNode t ){
+ Trace("thm-ee-debug") << "UEE : new equivalence class " << t << std::endl;
+ d_upendingAdds.push_back( t );
+}
+
+void ConjectureGenerator::eqNotifyPreMerge(TNode t1, TNode t2) {
+ //get maintained representatives
+ TNode rt1 = t1;
+ TNode rt2 = t2;
+ std::map< Node, EqcInfo* >::iterator it1 = d_eqc_info.find( t1 );
+ if( it1!=d_eqc_info.end() && !it1->second->d_rep.get().isNull() ){
+ rt1 = it1->second->d_rep.get();
+ }
+ std::map< Node, EqcInfo* >::iterator it2 = d_eqc_info.find( t2 );
+ if( it2!=d_eqc_info.end() && !it2->second->d_rep.get().isNull() ){
+ rt2 = it2->second->d_rep.get();
+ }
+ Trace("thm-ee-debug") << "UEE : equality holds : " << t1 << " == " << t2 << std::endl;
+ Trace("thm-ee-debug") << " ureps : " << rt1 << " == " << rt2 << std::endl;
+ Trace("thm-ee-debug") << " relevant : " << d_pattern_is_relevant[rt1] << " " << d_pattern_is_relevant[rt2] << std::endl;
+ Trace("thm-ee-debug") << " normal : " << d_pattern_is_normal[rt1] << " " << d_pattern_is_normal[rt2] << std::endl;
+ Trace("thm-ee-debug") << " size : " << d_pattern_fun_sum[rt1] << " " << d_pattern_fun_sum[rt2] << std::endl;
+
+ if( isUniversalLessThan( rt2, rt1 ) ){
+ EqcInfo * ei;
+ if( it1==d_eqc_info.end() ){
+ ei = getOrMakeEqcInfo( t1, true );
+ }else{
+ ei = it1->second;
+ }
+ ei->d_rep = t2;
+ }
+}
+
+void ConjectureGenerator::eqNotifyPostMerge(TNode t1, TNode t2) {
+
+}
+
+void ConjectureGenerator::eqNotifyDisequal(TNode t1, TNode t2, TNode reason) {
+ Trace("thm-ee-debug") << "UEE : disequality holds : " << t1 << " != " << t2 << std::endl;
+
+}
+
+
+ConjectureGenerator::EqcInfo::EqcInfo( context::Context* c ) : d_rep( c, Node::null() ){
+
+}
+
+ConjectureGenerator::EqcInfo* ConjectureGenerator::getOrMakeEqcInfo( TNode n, bool doMake ) {
+ //Assert( getUniversalRepresentative( n )==n );
+ std::map< Node, EqcInfo* >::iterator eqc_i = d_eqc_info.find( n );
+ if( eqc_i!=d_eqc_info.end() ){
+ return eqc_i->second;
+ }else if( doMake ){
+ EqcInfo* ei = new EqcInfo( d_quantEngine->getSatContext() );
+ d_eqc_info[n] = ei;
+ return ei;
+ }else{
+ return NULL;
+ }
+}
+
+void ConjectureGenerator::setUniversalRelevant( TNode n ) {
+ //add pattern information
+ registerPattern( n, n.getType() );
+ d_urelevant_terms[n] = true;
+ for( unsigned i=0; i<n.getNumChildren(); i++ ){
+ setUniversalRelevant( n[i] );
+ }
+}
+
+bool ConjectureGenerator::isUniversalLessThan( TNode rt1, TNode rt2 ) {
+ //prefer the one that is (normal, smaller) lexographically
+ Assert( d_pattern_is_relevant.find( rt1 )!=d_pattern_is_relevant.end() );
+ Assert( d_pattern_is_relevant.find( rt2 )!=d_pattern_is_relevant.end() );
+ Assert( d_pattern_is_normal.find( rt1 )!=d_pattern_is_normal.end() );
+ Assert( d_pattern_is_normal.find( rt2 )!=d_pattern_is_normal.end() );
+ Assert( d_pattern_fun_sum.find( rt1 )!=d_pattern_fun_sum.end() );
+ Assert( d_pattern_fun_sum.find( rt2 )!=d_pattern_fun_sum.end() );
+
+ if( d_pattern_is_relevant[rt1] && !d_pattern_is_relevant[rt2] ){
+ Trace("thm-ee-debug") << "UEE : LT due to relevant." << std::endl;
+ return true;
+ }else if( d_pattern_is_relevant[rt1]==d_pattern_is_relevant[rt2] ){
+ if( d_pattern_is_normal[rt1] && !d_pattern_is_normal[rt2] ){
+ Trace("thm-ee-debug") << "UEE : LT due to normal." << std::endl;
+ return true;
+ }else if( d_pattern_is_normal[rt1]==d_pattern_is_normal[rt2] ){
+ if( d_pattern_fun_sum[rt1]<d_pattern_fun_sum[rt2] ){
+ Trace("thm-ee-debug") << "UEE : LT due to size." << std::endl;
+ //decide which representative to use : based on size of the term
+ return true;
+ }else if( d_pattern_fun_sum[rt1]==d_pattern_fun_sum[rt2] ){
+ //same size : tie goes to term that has already been reported
+ return isReportedCanon( rt1 ) && !isReportedCanon( rt2 );
+ }
+ }
+ }
+ return false;
+}
+
+
+bool ConjectureGenerator::isReportedCanon( TNode n ) {
+ return std::find( d_ue_canon.begin(), d_ue_canon.end(), n )==d_ue_canon.end();
+}
+
+void ConjectureGenerator::markReportedCanon( TNode n ) {
+ if( !isReportedCanon( n ) ){
+ d_ue_canon.push_back( n );
+ }
+}
+
+bool ConjectureGenerator::areUniversalEqual( TNode n1, TNode n2 ) {
+ return n1==n2 || ( d_uequalityEngine.hasTerm( n1 ) && d_uequalityEngine.hasTerm( n2 ) && d_uequalityEngine.areEqual( n1, n2 ) );
+}
+
+bool ConjectureGenerator::areUniversalDisequal( TNode n1, TNode n2 ) {
+ return n1!=n2 && d_uequalityEngine.hasTerm( n1 ) && d_uequalityEngine.hasTerm( n2 ) && d_uequalityEngine.areDisequal( n1, n2, false );
+}
+
+TNode ConjectureGenerator::getUniversalRepresentative( TNode n, bool add ) {
+ if( add ){
+ if( d_urelevant_terms.find( n )==d_urelevant_terms.end() ){
+ setUniversalRelevant( n );
+ //add term to universal equality engine
+ d_uequalityEngine.addTerm( n );
+ // addding this term to equality engine will lead to a set of new terms (the new subterms of n)
+ // now, do instantiation-based merging for each of these terms
+ Trace("thm-ee-debug") << "Merge equivalence classes based on instantiations of terms..." << std::endl;
+ //merge all pending equalities
+ while( !d_upendingAdds.empty() ){
+ Trace("sg-pending") << "Add " << d_upendingAdds.size() << " pending terms..." << std::endl;
+ std::vector< Node > pending;
+ pending.insert( pending.end(), d_upendingAdds.begin(), d_upendingAdds.end() );
+ d_upendingAdds.clear();
+ for( unsigned i=0; i<pending.size(); i++ ){
+ Node t = pending[i];
+ TypeNode tn = t.getType();
+ Trace("thm-ee-add") << "UEE : Add universal term " << t << std::endl;
+ std::vector< Node > eq_terms;
+ //if occurs modulo equality at ground level, it is equivalent to representative of ground equality engine
+ TNode gt = getTermDatabase()->evaluateTerm( t );
+ if( !gt.isNull() && gt!=t ){
+ eq_terms.push_back( gt );
+ }
+ //get all equivalent terms based on theorem database
+ d_thm_index.getEquivalentTerms( t, eq_terms );
+ if( !eq_terms.empty() ){
+ Trace("thm-ee-add") << "UEE : Based on ground EE/theorem DB, it is equivalent to " << eq_terms.size() << " terms : " << std::endl;
+ //add equivalent terms as equalities to universal engine
+ for( unsigned i=0; i<eq_terms.size(); i++ ){
+ Trace("thm-ee-add") << " " << eq_terms[i] << std::endl;
+ bool assertEq = false;
+ if( d_urelevant_terms.find( eq_terms[i] )!=d_urelevant_terms.end() ){
+ assertEq = true;
+ }else{
+ Assert( eq_terms[i].getType()==tn );
+ registerPattern( eq_terms[i], tn );
+ if( isUniversalLessThan( eq_terms[i], t ) || ( options::conjectureUeeIntro() && d_pattern_fun_sum[t]>=d_pattern_fun_sum[eq_terms[i]] ) ){
+ setUniversalRelevant( eq_terms[i] );
+ assertEq = true;
+ }
+ }
+ if( assertEq ){
+ Node exp;
+ d_uequalityEngine.assertEquality( t.eqNode( eq_terms[i] ), true, exp );
+ }else{
+ Trace("thm-ee-no-add") << "Do not add : " << t << " == " << eq_terms[i] << std::endl;
+ }
+ }
+ }else{
+ Trace("thm-ee-add") << "UEE : No equivalent terms." << std::endl;
+ }
+ }
+ }
+ }
+ }
+
+ if( d_uequalityEngine.hasTerm( n ) ){
+ Node r = d_uequalityEngine.getRepresentative( n );
+ EqcInfo * ei = getOrMakeEqcInfo( r );
+ if( ei && !ei->d_rep.get().isNull() ){
+ return ei->d_rep.get();
+ }else{
+ return r;
+ }
+ }else{
+ return n;
+ }
+}
+
+eq::EqualityEngine * ConjectureGenerator::getEqualityEngine() {
+ return d_quantEngine->getTheoryEngine()->getMasterEqualityEngine();
+}
+
+bool ConjectureGenerator::areEqual( TNode n1, TNode n2 ) {
+ eq::EqualityEngine * ee = getEqualityEngine();
+ return n1==n2 || ( ee->hasTerm( n1 ) && ee->hasTerm( n2 ) && ee->areEqual( n1, n2 ) );
+}
+
+bool ConjectureGenerator::areDisequal( TNode n1, TNode n2 ) {
+ eq::EqualityEngine * ee = getEqualityEngine();
+ return n1!=n2 && ee->hasTerm( n1 ) && ee->hasTerm( n2 ) && ee->areDisequal( n1, n2, false );
+}
+
+TNode ConjectureGenerator::getRepresentative( TNode n ) {
+ eq::EqualityEngine * ee = getEqualityEngine();
+ if( ee->hasTerm( n ) ){
+ return ee->getRepresentative( n );
+ }else{
+ return n;
+ }
+}
+
+TermDb * ConjectureGenerator::getTermDatabase() {
+ return d_quantEngine->getTermDatabase();
+}
+
+Node ConjectureGenerator::getFreeVar( TypeNode tn, unsigned i ) {
+ Assert( !tn.isNull() );
+ while( d_free_var[tn].size()<=i ){
+ std::stringstream oss;
+ oss << tn;
+ std::stringstream os;
+ os << oss.str()[0] << i;
+ Node x = NodeManager::currentNM()->mkBoundVar( os.str().c_str(), tn );
+ d_free_var_num[x] = d_free_var[tn].size();
+ d_free_var[tn].push_back( x );
+ }
+ return d_free_var[tn][i];
+}
+
+
+
+Node ConjectureGenerator::getCanonicalTerm( TNode n, std::map< TypeNode, unsigned >& var_count, std::map< TNode, TNode >& subs ) {
+ if( n.getKind()==BOUND_VARIABLE ){
+ std::map< TNode, TNode >::iterator it = subs.find( n );
+ if( it==subs.end() ){
+ TypeNode tn = n.getType();
+ //allocate variable
+ unsigned vn = var_count[tn];
+ var_count[tn]++;
+ subs[n] = getFreeVar( tn, vn );
+ return subs[n];
+ }else{
+ return it->second;
+ }
+ }else{
+ std::vector< Node > children;
+ if( n.getKind()!=EQUAL ){
+ if( n.hasOperator() ){
+ TNode op = n.getOperator();
+ if( !d_tge.isRelevantFunc( op ) ){
+ return Node::null();
+ }
+ children.push_back( op );
+ }else{
+ return Node::null();
+ }
+ }
+ for( unsigned i=0; i<n.getNumChildren(); i++ ){
+ Node cn = getCanonicalTerm( n[i], var_count, subs );
+ if( cn.isNull() ){
+ return Node::null();
+ }else{
+ children.push_back( cn );
+ }
+ }
+ return NodeManager::currentNM()->mkNode( n.getKind(), children );
+ }
+}
+
+bool ConjectureGenerator::isHandledTerm( TNode n ){
+ return !n.getAttribute(NoMatchAttribute()) && inst::Trigger::isAtomicTrigger( n ) && ( n.getKind()!=APPLY_UF || n.getOperator().getKind()!=SKOLEM );
+}
+
+Node ConjectureGenerator::getGroundEqc( TNode r ) {
+ std::map< TNode, Node >::iterator it = d_ground_eqc_map.find( r );
+ return it!=d_ground_eqc_map.end() ? it->second : Node::null();
+}
+
+bool ConjectureGenerator::isGroundEqc( TNode r ) {
+ return d_ground_eqc_map.find( r )!=d_ground_eqc_map.end();
+}
+
+bool ConjectureGenerator::isGroundTerm( TNode n ) {
+ return std::find( d_ground_terms.begin(), d_ground_terms.end(), n )!=d_ground_terms.end();
+}
+
+bool ConjectureGenerator::needsCheck( Theory::Effort e ) {
+ return e==Theory::EFFORT_FULL;
+}
+
+bool ConjectureGenerator::hasEnumeratedUf( Node n ) {
+ if( options::conjectureGenGtEnum()>0 ){
+ std::map< Node, bool >::iterator it = d_uf_enum.find( n.getOperator() );
+ if( it==d_uf_enum.end() ){
+ d_uf_enum[n.getOperator()] = true;
+ std::vector< Node > lem;
+ getEnumeratePredUfTerm( n, options::conjectureGenGtEnum(), lem );
+ if( !lem.empty() ){
+ for( unsigned j=0; j<lem.size(); j++ ){
+ d_quantEngine->addLemma( lem[j], false );
+ d_hasAddedLemma = true;
+ }
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+void ConjectureGenerator::reset_round( Theory::Effort e ) {
+
+}
+
+void ConjectureGenerator::check( Theory::Effort e, unsigned quant_e ) {
+ if( quant_e==QuantifiersEngine::QEFFORT_STANDARD ){
+ d_fullEffortCount++;
+ if( d_fullEffortCount%optFullCheckFrequency()==0 ){
+ d_hasAddedLemma = false;
+ d_tge.d_cg = this;
+ double clSet = 0;
+ if( Trace.isOn("sg-engine") ){
+ clSet = double(clock())/double(CLOCKS_PER_SEC);
+ Trace("sg-engine") << "---Conjecture Engine Round, effort = " << e << "---" << std::endl;
+ }
+ eq::EqualityEngine * ee = getEqualityEngine();
+
+ Trace("sg-proc") << "Get eq classes..." << std::endl;
+ d_op_arg_index.clear();
+ d_ground_eqc_map.clear();
+ d_bool_eqc[0] = Node::null();
+ d_bool_eqc[1] = Node::null();
+ std::vector< TNode > eqcs;
+ d_em.clear();
+ eq::EqClassesIterator eqcs_i = eq::EqClassesIterator( ee );
+ while( !eqcs_i.isFinished() ){
+ TNode r = (*eqcs_i);
+ eqcs.push_back( r );
+ if( r.getType().isBoolean() ){
+ if( areEqual( r, getTermDatabase()->d_true ) ){
+ d_ground_eqc_map[r] = getTermDatabase()->d_true;
+ d_bool_eqc[0] = r;
+ }else if( areEqual( r, getTermDatabase()->d_false ) ){
+ d_ground_eqc_map[r] = getTermDatabase()->d_false;
+ d_bool_eqc[1] = r;
+ }
+ }
+ d_em[r] = eqcs.size();
+ eq::EqClassIterator ieqc_i = eq::EqClassIterator( r, ee );
+ while( !ieqc_i.isFinished() ){
+ TNode n = (*ieqc_i);
+ if( isHandledTerm( n ) ){
+ d_op_arg_index[r].addTerm( this, n );
+ }
+ ++ieqc_i;
+ }
+ ++eqcs_i;
+ }
+ Assert( !d_bool_eqc[0].isNull() );
+ Assert( !d_bool_eqc[1].isNull() );
+ d_urelevant_terms.clear();
+ Trace("sg-proc") << "...done get eq classes" << std::endl;
+
+ Trace("sg-proc") << "Determine ground EQC..." << std::endl;
+ bool success;
+ do{
+ success = false;
+ for( unsigned i=0; i<eqcs.size(); i++ ){
+ TNode r = eqcs[i];
+ if( d_ground_eqc_map.find( r )==d_ground_eqc_map.end() ){
+ std::vector< TNode > args;
+ Trace("sg-pat-debug") << "******* Get ground term for " << r << std::endl;
+ Node n;
+ if( getTermDatabase()->isInductionTerm( r ) ){
+ n = d_op_arg_index[r].getGroundTerm( this, args );
+ }else{
+ n = r;
+ }
+ if( !n.isNull() ){
+ Trace("sg-pat") << "Ground term for eqc " << r << " : " << std::endl;
+ Trace("sg-pat") << " " << n << std::endl;
+ d_ground_eqc_map[r] = n;
+ success = true;
+ }else{
+ Trace("sg-pat-debug") << "...could not find ground term." << std::endl;
+ }
+ }
+ }
+ }while( success );
+ //also get ground terms
+ d_ground_terms.clear();
+ for( unsigned i=0; i<eqcs.size(); i++ ){
+ TNode r = eqcs[i];
+ d_op_arg_index[r].getGroundTerms( this, d_ground_terms );
+ }
+ Trace("sg-proc") << "...done determine ground EQC" << std::endl;
+
+ //debug printing
+ if( Trace.isOn("sg-gen-eqc") ){
+ for( unsigned i=0; i<eqcs.size(); i++ ){
+ TNode r = eqcs[i];
+ //print out members
+ bool firstTime = true;
+ bool isFalse = areEqual( r, getTermDatabase()->d_false );
+ eq::EqClassIterator eqc_i = eq::EqClassIterator( r, ee );
+ while( !eqc_i.isFinished() ){
+ TNode n = (*eqc_i);
+ if( !n.getAttribute(NoMatchAttribute()) && ( n.getKind()!=EQUAL || isFalse ) ){
+ if( firstTime ){
+ Trace("sg-gen-eqc") << "e" << d_em[r] << " : { " << std::endl;
+ firstTime = false;
+ }
+ if( n.hasOperator() ){
+ Trace("sg-gen-eqc") << " (" << n.getOperator();
+ getTermDatabase()->computeArgReps( n );
+ for( unsigned i=0; i<getTermDatabase()->d_arg_reps[n].size(); i++ ){
+ Trace("sg-gen-eqc") << " e" << d_em[getTermDatabase()->d_arg_reps[n][i]];
+ }
+ Trace("sg-gen-eqc") << ") :: " << n << std::endl;
+ }else{
+ Trace("sg-gen-eqc") << " " << n << std::endl;
+ }
+ }
+ ++eqc_i;
+ }
+ if( !firstTime ){
+ Trace("sg-gen-eqc") << "}" << std::endl;
+ //print out ground term
+ std::map< TNode, Node >::iterator it = d_ground_eqc_map.find( r );
+ if( it!=d_ground_eqc_map.end() ){
+ Trace("sg-gen-eqc") << "- Ground term : " << it->second << std::endl;
+ }
+ }
+ }
+ }
+
+ Trace("sg-proc") << "Compute relevant eqc..." << std::endl;
+ d_tge.d_relevant_eqc[0].clear();
+ d_tge.d_relevant_eqc[1].clear();
+ for( unsigned i=0; i<eqcs.size(); i++ ){
+ TNode r = eqcs[i];
+ std::map< TNode, Node >::iterator it = d_ground_eqc_map.find( r );
+ unsigned index = 1;
+ if( it==d_ground_eqc_map.end() ){
+ index = 0;
+ }
+ //based on unproven conjectures? TODO
+ d_tge.d_relevant_eqc[index].push_back( r );
+ }
+ Trace("sg-gen-tg-debug") << "Initial relevant eqc : ";
+ for( unsigned i=0; i<d_tge.d_relevant_eqc[0].size(); i++ ){
+ Trace("sg-gen-tg-debug") << "e" << d_em[d_tge.d_relevant_eqc[0][i]] << " ";
+ }
+ Trace("sg-gen-tg-debug") << std::endl;
+ Trace("sg-proc") << "...done compute relevant eqc" << std::endl;
+
+
+ Trace("sg-proc") << "Collect signature information..." << std::endl;
+ d_tge.collectSignatureInformation();
+ if( d_hasAddedLemma ){
+ Trace("sg-proc") << "...added enumeration lemmas." << std::endl;
+ }
+ Trace("sg-proc") << "...done collect signature information" << std::endl;
+
+
+
+ Trace("sg-proc") << "Build theorem index..." << std::endl;
+ d_ue_canon.clear();
+ d_thm_index.clear();
+ std::vector< Node > provenConj;
+ quantifiers::FirstOrderModel* m = d_quantEngine->getModel();
+ for( int i=0; i<m->getNumAssertedQuantifiers(); i++ ){
+ Node q = m->getAssertedQuantifier( i );
+ Trace("thm-db-debug") << "Is " << q << " a relevant theorem?" << std::endl;
+ Node conjEq;
+ if( q[1].getKind()==EQUAL ){
+ bool isSubsume = false;
+ bool inEe = false;
+ for( unsigned r=0; r<2; r++ ){
+ TNode nl = q[1][r==0 ? 0 : 1];
+ TNode nr = q[1][r==0 ? 1 : 0];
+ Node eq = nl.eqNode( nr );
+ if( r==1 || std::find( d_conjectures.begin(), d_conjectures.end(), q )==d_conjectures.end() ){
+ //must make it canonical
+ std::map< TypeNode, unsigned > var_count;
+ std::map< TNode, TNode > subs;
+ Trace("sg-proc-debug") << "get canonical " << eq << std::endl;
+ eq = getCanonicalTerm( eq, var_count, subs );
+ }
+ if( !eq.isNull() ){
+ if( r==0 ){
+ inEe = d_ee_conjectures.find( q[1] )!=d_ee_conjectures.end();
+ if( !inEe ){
+ //add to universal equality engine
+ Node nl = getUniversalRepresentative( eq[0], true );
+ Node nr = getUniversalRepresentative( eq[1], true );
+ if( areUniversalEqual( nl, nr ) ){
+ isSubsume = true;
+ //set inactive (will be ignored by other modules)
+ d_quantEngine->getModel()->setQuantifierActive( q, false );
+ }else{
+ Node exp;
+ d_ee_conjectures[q[1]] = true;
+ d_uequalityEngine.assertEquality( nl.eqNode( nr ), true, exp );
+ }
+ }
+ Trace("sg-conjecture") << "*** CONJECTURE : currently proven" << (isSubsume ? " and subsumed" : "");
+ Trace("sg-conjecture") << " : " << q[1] << std::endl;
+ provenConj.push_back( q );
+ }
+ if( !isSubsume ){
+ Trace("thm-db-debug") << "Adding theorem to database " << eq[0] << " == " << eq[1] << std::endl;
+ d_thm_index.addTheorem( eq[0], eq[1] );
+ }else{
+ break;
+ }
+ }else{
+ break;
+ }
+ }
+ }
+ }
+ //examine status of other conjectures
+ for( unsigned i=0; i<d_conjectures.size(); i++ ){
+ Node q = d_conjectures[i];
+ if( std::find( provenConj.begin(), provenConj.end(), q )==provenConj.end() ){
+ //check each skolem variable
+ bool disproven = true;
+ //std::vector< Node > sk;
+ //getTermDatabase()->getSkolemConstants( q, sk, true );
+ Trace("sg-conjecture") << " CONJECTURE : ";
+ std::vector< Node > ce;
+ for( unsigned j=0; j<getTermDatabase()->d_skolem_constants[q].size(); j++ ){
+ TNode k = getTermDatabase()->d_skolem_constants[q][j];
+ TNode rk = getRepresentative( k );
+ std::map< TNode, Node >::iterator git = d_ground_eqc_map.find( rk );
+ //check if it is a ground term
+ if( git==d_ground_eqc_map.end() ){
+ Trace("sg-conjecture") << "ACTIVE : " << q;
+ if( Trace.isOn("sg-gen-eqc") ){
+ Trace("sg-conjecture") << " { ";
+ for( unsigned k=0; k<getTermDatabase()->d_skolem_constants[q].size(); k++ ){ Trace("sg-conjecture") << getTermDatabase()->d_skolem_constants[q][k] << ( j==k ? "*" : "" ) << " "; }
+ Trace("sg-conjecture") << "}";
+ }
+ Trace("sg-conjecture") << std::endl;
+ disproven = false;
+ break;
+ }else{
+ ce.push_back( git->second );
+ }
+ }
+ if( disproven ){
+ Trace("sg-conjecture") << "disproven : " << q << " : ";
+ for( unsigned i=0; i<ce.size(); i++ ){
+ Trace("sg-conjecture") << q[0][i] << " -> " << ce[i] << " ";
+ }
+ Trace("sg-conjecture") << std::endl;
+ }
+ }
+ }
+ Trace("thm-db") << "Theorem database is : " << std::endl;
+ d_thm_index.debugPrint( "thm-db" );
+ Trace("thm-db") << std::endl;
+ Trace("sg-proc") << "...done build theorem index" << std::endl;
+
+
+ //clear patterns
+ d_patterns.clear();
+ d_pattern_var_id.clear();
+ d_pattern_var_duplicate.clear();
+ d_pattern_is_normal.clear();
+ d_pattern_is_relevant.clear();
+ d_pattern_fun_id.clear();
+ d_pattern_fun_sum.clear();
+ d_rel_patterns.clear();
+ d_rel_pattern_var_sum.clear();
+ d_rel_pattern_typ_index.clear();
+ d_rel_pattern_subs_index.clear();
+
+ unsigned rel_term_count = 0;
+ std::map< TypeNode, unsigned > rt_var_max;
+ std::vector< TypeNode > rt_types;
+ std::map< TypeNode, std::map< int, std::vector< Node > > > conj_lhs;
+ unsigned addedLemmas = 0;
+ for( unsigned depth=1; depth<=3; depth++ ){
+ Trace("sg-proc") << "Generate relevant LHS at depth " << depth << "..." << std::endl;
+ Trace("sg-rel-term") << "Relevant terms of depth " << depth << " : " << std::endl;
+ //set up environment
+ d_tge.d_var_id.clear();
+ d_tge.d_var_limit.clear();
+ d_tge.reset( depth, true, TypeNode::null() );
+ while( d_tge.getNextTerm() ){
+ //construct term
+ Node nn = d_tge.getTerm();
+ if( !options::conjectureFilterCanonical() || considerTermCanon( nn, true ) ){
+ rel_term_count++;
+ Trace("sg-rel-term") << "*** Relevant term : ";
+ d_tge.debugPrint( "sg-rel-term", "sg-rel-term-debug2" );
+ Trace("sg-rel-term") << std::endl;
+
+ for( unsigned r=0; r<2; r++ ){
+ Trace("sg-rel-term-debug") << "...from equivalence classes (" << r << ") : ";
+ int index = d_tge.d_ccand_eqc[r].size()-1;
+ for( unsigned j=0; j<d_tge.d_ccand_eqc[r][index].size(); j++ ){
+ Trace("sg-rel-term-debug") << "e" << d_em[d_tge.d_ccand_eqc[r][index][j]] << " ";
+ }
+ Trace("sg-rel-term-debug") << std::endl;
+ }
+ TypeNode tnn = nn.getType();
+ Trace("sg-gen-tg-debug") << "...term is " << nn << std::endl;
+ conj_lhs[tnn][depth].push_back( nn );
+
+ //add information about pattern
+ Trace("sg-gen-tg-debug") << "Collect pattern information..." << std::endl;
+ Assert( std::find( d_rel_patterns[tnn].begin(), d_rel_patterns[tnn].end(), nn )==d_rel_patterns[tnn].end() );
+ d_rel_patterns[tnn].push_back( nn );
+ //build information concerning the variables in this pattern
+ unsigned sum = 0;
+ std::map< TypeNode, unsigned > typ_to_subs_index;
+ std::vector< TNode > gsubs_vars;
+ for( std::map< TypeNode, unsigned >::iterator it = d_tge.d_var_id.begin(); it != d_tge.d_var_id.end(); ++it ){
+ if( it->second>0 ){
+ typ_to_subs_index[it->first] = sum;
+ sum += it->second;
+ for( unsigned i=0; i<it->second; i++ ){
+ gsubs_vars.push_back( getFreeVar( it->first, i ) );
+ }
+ }
+ }
+ d_rel_pattern_var_sum[nn] = sum;
+ //register the pattern
+ registerPattern( nn, tnn );
+ Assert( d_pattern_is_normal[nn] );
+ Trace("sg-gen-tg-debug") << "...done collect pattern information" << std::endl;
+
+ //record information about types
+ Trace("sg-gen-tg-debug") << "Collect type information..." << std::endl;
+ PatternTypIndex * pti = &d_rel_pattern_typ_index;
+ for( std::map< TypeNode, unsigned >::iterator it = d_tge.d_var_id.begin(); it != d_tge.d_var_id.end(); ++it ){
+ pti = &pti->d_children[it->first][it->second];
+ //record maximum
+ if( rt_var_max.find( it->first )==rt_var_max.end() || it->second>rt_var_max[it->first] ){
+ rt_var_max[it->first] = it->second;
+ }
+ }
+ if( std::find( rt_types.begin(), rt_types.end(), tnn )==rt_types.end() ){
+ rt_types.push_back( tnn );
+ }
+ pti->d_terms.push_back( nn );
+ Trace("sg-gen-tg-debug") << "...done collect type information" << std::endl;
+
+ Trace("sg-gen-tg-debug") << "Build substitutions for ground EQC..." << std::endl;
+ std::vector< TNode > gsubs_terms;
+ gsubs_terms.resize( gsubs_vars.size() );
+ int index = d_tge.d_ccand_eqc[1].size()-1;
+ for( unsigned j=0; j<d_tge.d_ccand_eqc[1][index].size(); j++ ){
+ TNode r = d_tge.d_ccand_eqc[1][index][j];
+ Trace("sg-rel-term-debug") << " Matches for e" << d_em[r] << ", which is ground term " << d_ground_eqc_map[r] << ":" << std::endl;
+ std::map< TypeNode, std::map< unsigned, TNode > > subs;
+ std::map< TNode, bool > rev_subs;
+ //only get ground terms
+ unsigned mode = 2;
+ d_tge.resetMatching( r, mode );
+ while( d_tge.getNextMatch( r, subs, rev_subs ) ){
+ //we will be building substitutions
+ bool firstTime = true;
+ for( std::map< TypeNode, std::map< unsigned, TNode > >::iterator it = subs.begin(); it != subs.end(); ++it ){
+ unsigned tindex = typ_to_subs_index[it->first];
+ for( std::map< unsigned, TNode >::iterator it2 = it->second.begin(); it2 != it->second.end(); ++it2 ){
+ if( !firstTime ){
+ Trace("sg-rel-term-debug") << ", ";
+ }else{
+ firstTime = false;
+ Trace("sg-rel-term-debug") << " ";
+ }
+ Trace("sg-rel-term-debug") << it->first << ":x" << it2->first << " -> " << it2->second;
+ Assert( tindex+it2->first<gsubs_terms.size() );
+ gsubs_terms[tindex+it2->first] = it2->second;
+ }
+ }
+ Trace("sg-rel-term-debug") << std::endl;
+ d_rel_pattern_subs_index[nn].addSubstitution( r, gsubs_vars, gsubs_terms );
+ }
+ }
+ Trace("sg-gen-tg-debug") << "...done build substitutions for ground EQC" << std::endl;
+ }else{
+ Trace("sg-gen-tg-debug") << "> not canonical : " << nn << std::endl;
+ }
+ }
+ Trace("sg-proc") << "...done generate terms at depth " << depth << std::endl;
+ Trace("sg-stats") << "--------> Total LHS of depth " << depth << " : " << rel_term_count << std::endl;
+ //Trace("conjecture-count") << "Total LHS of depth " << depth << " : " << conj_lhs[depth].size() << std::endl;
+
+ /* test...
+ for( unsigned i=0; i<rt_types.size(); i++ ){
+ Trace("sg-term-enum") << "Term enumeration for " << rt_types[i] << " : " << std::endl;
+ Trace("sg-term-enum") << "Ground term : " << rt_types[i].mkGroundTerm() << std::endl;
+ for( unsigned j=0; j<150; j++ ){
+ Trace("sg-term-enum") << " " << getEnumerateTerm( rt_types[i], j ) << std::endl;
+ }
+ }
+ */
+
+ //consider types from relevant terms
+ for( unsigned rdepth=0; rdepth<=depth; rdepth++ ){
+ //set up environment
+ d_tge.d_var_id.clear();
+ d_tge.d_var_limit.clear();
+ for( std::map< TypeNode, unsigned >::iterator it = rt_var_max.begin(); it != rt_var_max.end(); ++it ){
+ d_tge.d_var_id[ it->first ] = it->second;
+ d_tge.d_var_limit[ it->first ] = it->second;
+ }
+ std::random_shuffle( rt_types.begin(), rt_types.end() );
+ std::map< TypeNode, std::vector< Node > > conj_rhs;
+ for( unsigned i=0; i<rt_types.size(); i++ ){
+
+ Trace("sg-proc") << "Generate relevant RHS terms of type " << rt_types[i] << " at depth " << rdepth << "..." << std::endl;
+ d_tge.reset( rdepth, false, rt_types[i] );
+
+ while( d_tge.getNextTerm() ){
+ Node rhs = d_tge.getTerm();
+ if( considerTermCanon( rhs, false ) ){
+ Trace("sg-rel-prop") << "Relevant RHS : " << rhs << std::endl;
+ //register pattern
+ Assert( rhs.getType()==rt_types[i] );
+ registerPattern( rhs, rt_types[i] );
+ if( rdepth<depth ){
+ //consider against all LHS at depth
+ for( unsigned j=0; j<conj_lhs[rt_types[i]][depth].size(); j++ ){
+ processCandidateConjecture( conj_lhs[rt_types[i]][depth][j], rhs, depth, rdepth );
+ }
+ }else{
+ conj_rhs[rt_types[i]].push_back( rhs );
+ }
+ }
+ }
+ }
+ flushWaitingConjectures( addedLemmas, depth, rdepth );
+ //consider against all LHS up to depth
+ if( rdepth==depth ){
+ for( unsigned lhs_depth = 1; lhs_depth<=depth; lhs_depth++ ){
+ if( (int)addedLemmas<options::conjectureGenPerRound() ){
+ Trace("sg-proc") << "Consider conjectures at depth (" << lhs_depth << ", " << rdepth << ")..." << std::endl;
+ for( std::map< TypeNode, std::vector< Node > >::iterator it = conj_rhs.begin(); it != conj_rhs.end(); ++it ){
+ for( unsigned j=0; j<it->second.size(); j++ ){
+ for( unsigned k=0; k<conj_lhs[it->first][lhs_depth].size(); k++ ){
+ processCandidateConjecture( conj_lhs[it->first][lhs_depth][k], it->second[j], lhs_depth, rdepth );
+ }
+ }
+ }
+ flushWaitingConjectures( addedLemmas, lhs_depth, depth );
+ }
+ }
+ }
+ if( (int)addedLemmas>=options::conjectureGenPerRound() ){
+ break;
+ }
+ }
+ if( (int)addedLemmas>=options::conjectureGenPerRound() ){
+ break;
+ }
+ }
+
+ if( Trace.isOn("thm-ee") ){
+ Trace("thm-ee") << "Universal equality engine is : " << std::endl;
+ eq::EqClassesIterator ueqcs_i = eq::EqClassesIterator( &d_uequalityEngine );
+ while( !ueqcs_i.isFinished() ){
+ TNode r = (*ueqcs_i);
+ bool firstTime = true;
+ TNode rr = getUniversalRepresentative( r );
+ Trace("thm-ee") << " " << rr;
+ Trace("thm-ee") << " : { ";
+ eq::EqClassIterator ueqc_i = eq::EqClassIterator( r, &d_uequalityEngine );
+ while( !ueqc_i.isFinished() ){
+ TNode n = (*ueqc_i);
+ if( rr!=n ){
+ if( firstTime ){
+ Trace("thm-ee") << std::endl;
+ firstTime = false;
+ }
+ Trace("thm-ee") << " " << n << std::endl;
+ }
+ ++ueqc_i;
+ }
+ if( !firstTime ){ Trace("thm-ee") << " "; }
+ Trace("thm-ee") << "}" << std::endl;
+ ++ueqcs_i;
+ }
+ Trace("thm-ee") << std::endl;
+ }
+ if( Trace.isOn("sg-engine") ){
+ double clSet2 = double(clock())/double(CLOCKS_PER_SEC);
+ Trace("sg-engine") << "Finished conjecture generator, time = " << (clSet2-clSet) << std::endl;
+ }
+ }
+ }
+}
+
+unsigned ConjectureGenerator::flushWaitingConjectures( unsigned& addedLemmas, int ldepth, int rdepth ) {
+ if( !d_waiting_conjectures_lhs.empty() ){
+ Trace("sg-proc") << "Generated " << d_waiting_conjectures_lhs.size() << " conjectures at depth " << ldepth << "/" << rdepth << "." << std::endl;
+ if( !optStatsOnly() && (int)addedLemmas<options::conjectureGenPerRound() ){
+ std::vector< unsigned > indices;
+ for( unsigned i=0; i<d_waiting_conjectures_lhs.size(); i++ ){
+ indices.push_back( i );
+ }
+ bool doSort = false;
+ if( doSort ){
+ //sort them based on score
+ sortConjectureScore scs;
+ scs.d_scores.insert( scs.d_scores.begin(), d_waiting_conjectures_score.begin(), d_waiting_conjectures_score.end() );
+ std::sort( indices.begin(), indices.end(), scs );
+ }
+ if( doSort && d_waiting_conjectures_score[indices[0]]<optFilterScoreThreshold() ){
+ //do splitting on demand (TODO)
+
+ }else{
+ for( unsigned i=0; i<indices.size(); i++ ){
+ //if( d_waiting_conjectures_score[indices[i]]<optFilterScoreThreshold() ){
+ if( d_waiting_conjectures_score[indices[i]]>=optFilterScoreThreshold() ){
+ //we have determined a relevant subgoal
+ Node lhs = d_waiting_conjectures_lhs[indices[i]];
+ Node rhs = d_waiting_conjectures_rhs[indices[i]];
+ if( options::conjectureFilterCanonical() && ( getUniversalRepresentative( lhs )!=lhs || getUniversalRepresentative( rhs )!=rhs ) ){
+ //skip
+ }else{
+ Trace("sg-engine") << "*** Consider conjecture : " << lhs << " == " << rhs << std::endl;
+ Trace("sg-engine-debug") << " score : " << d_waiting_conjectures_score[indices[i]] << std::endl;
+ std::vector< Node > bvs;
+ for( std::map< TypeNode, unsigned >::iterator it = d_pattern_var_id[lhs].begin(); it != d_pattern_var_id[lhs].end(); ++it ){
+ for( unsigned i=0; i<=it->second; i++ ){
+ bvs.push_back( getFreeVar( it->first, i ) );
+ }
+ }
+ Node rsg;
+ if( !bvs.empty() ){
+ Node bvl = NodeManager::currentNM()->mkNode( BOUND_VAR_LIST, bvs );
+ rsg = NodeManager::currentNM()->mkNode( FORALL, bvl, lhs.eqNode( rhs ) );
+ }else{
+ rsg = lhs.eqNode( rhs );
+ }
+ rsg = Rewriter::rewrite( rsg );
+ d_conjectures.push_back( rsg );
+ d_eq_conjectures[lhs].push_back( rhs );
+ d_eq_conjectures[rhs].push_back( lhs );
+
+ Node lem = NodeManager::currentNM()->mkNode( OR, rsg.negate(), rsg );
+ d_quantEngine->addLemma( lem, false );
+ d_quantEngine->addRequirePhase( rsg, false );
+ addedLemmas++;
+ if( (int)addedLemmas>=options::conjectureGenPerRound() ){
+ break;
+ }
+ }
+ }else{
+ if( doSort ){
+ break;
+ }
+ }
+ }
+ }
+ Trace("sg-proc") << "...have now added " << addedLemmas << " conjecture lemmas." << std::endl;
+ }
+ d_waiting_conjectures_lhs.clear();
+ d_waiting_conjectures_rhs.clear();
+ d_waiting_conjectures_score.clear();
+ d_waiting_conjectures.clear();
+ }
+ return addedLemmas;
+}
+
+void ConjectureGenerator::registerQuantifier( Node q ) {
+
+}
+
+void ConjectureGenerator::assertNode( Node n ) {
+
+}
+
+bool ConjectureGenerator::considerTermCanon( Node ln, bool genRelevant ){
+ if( !ln.isNull() ){
+ //do not consider if it is non-canonical, and either:
+ // (1) we are not generating relevant terms, or
+ // (2) its canonical form is a generalization.
+ TNode lnr = getUniversalRepresentative( ln, true );
+ if( lnr==ln ){
+ markReportedCanon( ln );
+ }else if( !genRelevant || isGeneralization( lnr, ln ) ){
+ Trace("sg-gen-consider-term") << "Do not consider term, " << ln << " is not canonical representation (which is " << lnr << ")." << std::endl;
+ return false;
+ }
+ }
+ Trace("sg-gen-tg-debug") << "Will consider term canon " << ln << std::endl;
+ Trace("sg-gen-consider-term-debug") << std::endl;
+ return true;
+}
+
+unsigned ConjectureGenerator::collectFunctions( TNode opat, TNode pat, std::map< TNode, unsigned >& funcs,
+ std::map< TypeNode, unsigned >& mnvn, std::map< TypeNode, unsigned >& mxvn ){
+ if( pat.hasOperator() ){
+ funcs[pat.getOperator()]++;
+ if( !d_tge.isRelevantFunc( pat.getOperator() ) ){
+ d_pattern_is_relevant[opat] = false;
+ }
+ unsigned sum = 1;
+ for( unsigned i=0; i<pat.getNumChildren(); i++ ){
+ sum += collectFunctions( opat, pat[i], funcs, mnvn, mxvn );
+ }
+ return sum;
+ }else{
+ Assert( pat.getNumChildren()==0 );
+ funcs[pat]++;
+ //for variables
+ if( pat.getKind()==BOUND_VARIABLE ){
+ if( funcs[pat]>1 ){
+ //duplicate variable
+ d_pattern_var_duplicate[opat]++;
+ }else{
+ //check for max/min
+ TypeNode tn = pat.getType();
+ unsigned vn = d_free_var_num[pat];
+ std::map< TypeNode, unsigned >::iterator it = mnvn.find( tn );
+ if( it!=mnvn.end() ){
+ if( vn<it->second ){
+ d_pattern_is_normal[opat] = false;
+ mnvn[tn] = vn;
+ }else if( vn>mxvn[tn] ){
+ if( vn!=mxvn[tn]+1 ){
+ d_pattern_is_normal[opat] = false;
+ }
+ mxvn[tn] = vn;
+ }
+ }else{
+ //first variable of this type
+ mnvn[tn] = vn;
+ mxvn[tn] = vn;
+ }
+ }
+ }else{
+ d_pattern_is_relevant[opat] = false;
+ }
+ return 1;
+ }
+}
+
+void ConjectureGenerator::registerPattern( Node pat, TypeNode tpat ) {
+ if( std::find( d_patterns[tpat].begin(), d_patterns[tpat].end(), pat )==d_patterns[tpat].end() ){
+ d_patterns[TypeNode::null()].push_back( pat );
+ d_patterns[tpat].push_back( pat );
+
+ Assert( d_pattern_fun_id.find( pat )==d_pattern_fun_id.end() );
+ Assert( d_pattern_var_id.find( pat )==d_pattern_var_id.end() );
+
+ //collect functions
+ std::map< TypeNode, unsigned > mnvn;
+ d_pattern_fun_sum[pat] = collectFunctions( pat, pat, d_pattern_fun_id[pat], mnvn, d_pattern_var_id[pat] );
+ if( d_pattern_is_normal.find( pat )==d_pattern_is_normal.end() ){
+ d_pattern_is_normal[pat] = true;
+ }
+ if( d_pattern_is_relevant.find( pat )==d_pattern_is_relevant.end() ){
+ d_pattern_is_relevant[pat] = true;
+ }
+ }
+}
+
+bool ConjectureGenerator::isGeneralization( TNode patg, TNode pat, std::map< TNode, TNode >& subs ) {
+ if( patg.getKind()==BOUND_VARIABLE ){
+ std::map< TNode, TNode >::iterator it = subs.find( patg );
+ if( it!=subs.end() ){
+ return it->second==pat;
+ }else{
+ subs[patg] = pat;
+ return true;
+ }
+ }else{
+ Assert( patg.hasOperator() );
+ if( !pat.hasOperator() || patg.getOperator()!=pat.getOperator() ){
+ return false;
+ }else{
+ Assert( patg.getNumChildren()==pat.getNumChildren() );
+ for( unsigned i=0; i<patg.getNumChildren(); i++ ){
+ if( !isGeneralization( patg[i], pat[i], subs ) ){
+ return false;
+ }
+ }
+ return true;
+ }
+ }
+}
+
+int ConjectureGenerator::calculateGeneralizationDepth( TNode n, std::vector< TNode >& fv ) {
+ if( n.getKind()==BOUND_VARIABLE ){
+ if( std::find( fv.begin(), fv.end(), n )==fv.end() ){
+ fv.push_back( n );
+ return 0;
+ }else{
+ return 1;
+ }
+ }else{
+ int depth = 1;
+ for( unsigned i=0; i<n.getNumChildren(); i++ ){
+ depth += calculateGeneralizationDepth( n[i], fv );
+ }
+ return depth;
+ }
+}
+
+Node ConjectureGenerator::getEnumerateTerm( TypeNode tn, unsigned index ) {
+ std::map< TypeNode, unsigned >::iterator it = d_typ_enum_map.find( tn );
+ unsigned teIndex;
+ if( it==d_typ_enum_map.end() ){
+ teIndex = (int)d_typ_enum.size();
+ d_typ_enum_map[tn] = teIndex;
+ d_typ_enum.push_back( TypeEnumerator(tn) );
+ }else{
+ teIndex = it->second;
+ }
+ while( index>=d_enum_terms[tn].size() ){
+ if( d_typ_enum[teIndex].isFinished() ){
+ return Node::null();
+ }
+ d_enum_terms[tn].push_back( *d_typ_enum[teIndex] );
+ ++d_typ_enum[teIndex];
+ }
+ return d_enum_terms[tn][index];
+}
+
+
+Node ConjectureGenerator::getPredicateForType( TypeNode tn ) {
+ std::map< TypeNode, Node >::iterator it = d_typ_pred.find( tn );
+ if( it==d_typ_pred.end() ){
+ TypeNode op_tn = NodeManager::currentNM()->mkFunctionType( tn, NodeManager::currentNM()->booleanType() );
+ Node op = NodeManager::currentNM()->mkSkolem( "PE", op_tn, "was created by conjecture ground term enumerator." );
+ d_typ_pred[tn] = op;
+ return op;
+ }else{
+ return it->second;
+ }
+}
+
+void ConjectureGenerator::getEnumerateUfTerm( Node n, unsigned num, std::vector< Node >& terms ) {
+ if( n.getNumChildren()>0 ){
+ std::vector< int > vec;
+ for( unsigned i=0; i<n.getNumChildren(); i++ ){
+ vec.push_back( 0 );
+ }
+ vec.pop_back();
+ int size_limit = 0;
+ int vec_sum = -1;
+ unsigned index = 0;
+ unsigned last_size = terms.size();
+ while( terms.size()<num ){
+ bool success = true;
+ if( vec_sum==-1 ){
+ vec_sum = 0;
+ vec.push_back( size_limit );
+ }else{
+ //see if we can iterate current
+ if( vec_sum<size_limit && !getEnumerateTerm( n[index].getType(), vec[index]+1 ).isNull() ){
+ vec[index]++;
+ vec_sum++;
+ vec.push_back( size_limit - vec_sum );
+ }else{
+ vec_sum -= vec[index];
+ vec[index] = 0;
+ index++;
+ if( index==n.getNumChildren() ){
+ success = false;
+ }
+ }
+ }
+ if( success ){
+ if( vec.size()==n.getNumChildren() ){
+ Node lc = getEnumerateTerm( n[vec.size()-1].getType(), vec[vec.size()-1] );
+ if( !lc.isNull() ){
+ for( unsigned i=0; i<vec.size(); i++ ){
+ Trace("sg-gt-enum-debug") << vec[i] << " ";
+ }
+ Trace("sg-gt-enum-debug") << " / " << size_limit << std::endl;
+ for( unsigned i=0; i<n.getNumChildren(); i++ ){
+ Trace("sg-gt-enum-debug") << n[i].getType() << " ";
+ }
+ Trace("sg-gt-enum-debug") << std::endl;
+ std::vector< Node > children;
+ children.push_back( n.getOperator() );
+ for( unsigned i=0; i<(vec.size()-1); i++ ){
+ Node nn = getEnumerateTerm( n[i].getType(), vec[i] );
+ Assert( !nn.isNull() );
+ Assert( nn.getType()==n[i].getType() );
+ children.push_back( nn );
+ }
+ children.push_back( lc );
+ Node n = NodeManager::currentNM()->mkNode( APPLY_UF, children );
+ Trace("sg-gt-enum") << "Ground term enumerate : " << n << std::endl;
+ terms.push_back( n );
+ }
+ vec.pop_back();
+ index = 0;
+ }
+ }else{
+ if( terms.size()>last_size ){
+ last_size = terms.size();
+ size_limit++;
+ for( unsigned i=0; i<vec.size(); i++ ){
+ vec[i] = 0;
+ }
+ vec_sum = -1;
+ }
+ }
+ }
+ }else{
+ terms.push_back( n );
+ }
+}
+
+void ConjectureGenerator::getEnumeratePredUfTerm( Node n, unsigned num, std::vector< Node >& terms ) {
+ std::vector< Node > uf_terms;
+ getEnumerateUfTerm( n, num, uf_terms );
+ Node p = getPredicateForType( n.getType() );
+ for( unsigned i=0; i<uf_terms.size(); i++ ){
+ terms.push_back( NodeManager::currentNM()->mkNode( APPLY_UF, p, uf_terms[i] ) );
+ }
+}
+
+void ConjectureGenerator::processCandidateConjecture( TNode lhs, TNode rhs, unsigned lhs_depth, unsigned rhs_depth ) {
+ int score = considerCandidateConjecture( lhs, rhs );
+ if( score>0 ){
+ Trace("sg-conjecture") << "* Candidate conjecture : " << lhs << " == " << rhs << std::endl;
+ Trace("sg-conjecture-debug") << " LHS, RHS generalization depth : " << lhs_depth << ", " << rhs_depth << std::endl;
+ Trace("sg-conjecture-debug") << " confirmed = " << d_subs_confirmCount << ", #witnesses range = " << d_subs_confirmWitnessRange.size() << "." << std::endl;
+ Trace("sg-conjecture-debug") << " #witnesses for ";
+ bool firstTime = true;
+ for( std::map< TNode, std::vector< TNode > >::iterator it = d_subs_confirmWitnessDomain.begin(); it != d_subs_confirmWitnessDomain.end(); ++it ){
+ if( !firstTime ){
+ Trace("sg-conjecture-debug") << ", ";
+ }
+ Trace("sg-conjecture-debug") << it->first << " : " << it->second.size();
+ //if( it->second.size()==1 ){
+ // Trace("sg-conjecture-debug") << " (" << it->second[0] << ")";
+ //}
+ Trace("sg-conjecture-debug2") << " (";
+ for( unsigned j=0; j<it->second.size(); j++ ){
+ if( j>0 ){ Trace("sg-conjecture-debug2") << " "; }
+ Trace("sg-conjecture-debug2") << d_ground_eqc_map[it->second[j]];
+ }
+ Trace("sg-conjecture-debug2") << ")";
+ firstTime = false;
+ }
+ Trace("sg-conjecture-debug") << std::endl;
+ Trace("sg-conjecture-debug") << " unknown = " << d_subs_unkCount << std::endl;
+ //Assert( getUniversalRepresentative( rhs )==rhs );
+ //Assert( getUniversalRepresentative( lhs )==lhs );
+ d_waiting_conjectures_lhs.push_back( lhs );
+ d_waiting_conjectures_rhs.push_back( rhs );
+ d_waiting_conjectures_score.push_back( score );
+ d_waiting_conjectures[lhs].push_back( rhs );
+ d_waiting_conjectures[rhs].push_back( lhs );
+ }
+}
+
+int ConjectureGenerator::considerCandidateConjecture( TNode lhs, TNode rhs ) {
+ Assert( lhs.getType()==rhs.getType() );
+
+ Trace("sg-cconj-debug") << "Consider candidate conjecture : " << lhs << " == " << rhs << "?" << std::endl;
+ if( lhs==rhs ){
+ Trace("sg-cconj-debug") << " -> trivial." << std::endl;
+ return -1;
+ }else{
+ if( lhs.getKind()==APPLY_CONSTRUCTOR && rhs.getKind()==APPLY_CONSTRUCTOR ){
+ Trace("sg-cconj-debug") << " -> irrelevant by syntactic analysis." << std::endl;
+ return -1;
+ }
+ //variables of LHS must subsume variables of RHS
+ for( std::map< TypeNode, unsigned >::iterator it = d_pattern_var_id[rhs].begin(); it != d_pattern_var_id[rhs].end(); ++it ){
+ std::map< TypeNode, unsigned >::iterator itl = d_pattern_var_id[lhs].find( it->first );
+ if( itl!=d_pattern_var_id[lhs].end() ){
+ if( itl->second<it->second ){
+ Trace("sg-cconj-debug") << " -> variables of sort " << it->first << " are not subsumed." << std::endl;
+ return -1;
+ }else{
+ Trace("sg-cconj-debug2") << " variables of sort " << it->first << " are : " << itl->second << " vs " << it->second << std::endl;
+ }
+ }else{
+ Trace("sg-cconj-debug") << " -> has no variables of sort " << it->first << "." << std::endl;
+ return -1;
+ }
+ }
+
+ //currently active conjecture?
+ std::map< Node, std::vector< Node > >::iterator iteq = d_eq_conjectures.find( lhs );
+ if( iteq!=d_eq_conjectures.end() ){
+ if( std::find( iteq->second.begin(), iteq->second.end(), rhs )!=iteq->second.end() ){
+ Trace("sg-cconj-debug") << " -> this conjecture is already active." << std::endl;
+ return -1;
+ }
+ }
+ //current a waiting conjecture?
+ std::map< Node, std::vector< Node > >::iterator itw = d_waiting_conjectures.find( lhs );
+ if( itw!=d_waiting_conjectures.end() ){
+ if( std::find( itw->second.begin(), itw->second.end(), rhs )!=itw->second.end() ){
+ Trace("sg-cconj-debug") << " -> already are considering this conjecture." << std::endl;
+ return -1;
+ }
+ }
+ //check if canonical representation (should be, but for efficiency this is not guarenteed)
+ //if( options::conjectureFilterCanonical() && ( getUniversalRepresentative( lhs )!=lhs || getUniversalRepresentative( rhs )!=rhs ) ){
+ // Trace("sg-cconj") << " -> after processing, not canonical." << std::endl;
+ // return -1;
+ //}
+
+ int score;
+ bool scoreSet = false;
+
+ Trace("sg-cconj") << "Consider possible candidate conjecture : " << lhs << " == " << rhs << "?" << std::endl;
+ //find witness for counterexample, if possible
+ if( options::conjectureFilterModel() ){
+ Assert( d_rel_pattern_var_sum.find( lhs )!=d_rel_pattern_var_sum.end() );
+ Trace("sg-cconj-debug") << "Notify substitutions over " << d_rel_pattern_var_sum[lhs] << " variables." << std::endl;
+ std::map< TNode, TNode > subs;
+ d_subs_confirmCount = 0;
+ d_subs_confirmWitnessRange.clear();
+ d_subs_confirmWitnessDomain.clear();
+ d_subs_unkCount = 0;
+ if( !d_rel_pattern_subs_index[lhs].notifySubstitutions( this, subs, rhs, d_rel_pattern_var_sum[lhs] ) ){
+ Trace("sg-cconj") << " -> found witness that falsifies the conjecture." << std::endl;
+ return -1;
+ }
+ //score is the minimum number of distinct substitutions for a variable
+ for( std::map< TNode, std::vector< TNode > >::iterator it = d_subs_confirmWitnessDomain.begin(); it != d_subs_confirmWitnessDomain.end(); ++it ){
+ int num = (int)it->second.size();
+ if( !scoreSet || num<score ){
+ score = num;
+ scoreSet = true;
+ }
+ }
+ if( !scoreSet ){
+ score = 0;
+ }
+ Trace("sg-cconj") << " confirmed = " << d_subs_confirmCount << ", #witnesses range = " << d_subs_confirmWitnessRange.size() << "." << std::endl;
+ for( std::map< TNode, std::vector< TNode > >::iterator it = d_subs_confirmWitnessDomain.begin(); it != d_subs_confirmWitnessDomain.end(); ++it ){
+ Trace("sg-cconj") << " #witnesses for " << it->first << " : " << it->second.size() << std::endl;
+ }
+ }else{
+ score = 0;
+ }
+
+ Trace("sg-cconj") << " -> SUCCESS." << std::endl;
+ Trace("sg-cconj") << " score : " << score << std::endl;
+
+ return score;
+ }
+}
+
+bool ConjectureGenerator::notifySubstitution( TNode glhs, std::map< TNode, TNode >& subs, TNode rhs ) {
+ if( Trace.isOn("sg-cconj-debug") ){
+ Trace("sg-cconj-debug") << "Ground eqc for LHS : " << glhs << ", based on substituion: " << std::endl;
+ for( std::map< TNode, TNode >::iterator it = subs.begin(); it != subs.end(); ++it ){
+ Assert( getRepresentative( it->second )==it->second );
+ Trace("sg-cconj-debug") << " " << it->first << " -> " << it->second << std::endl;
+ }
+ }
+ Trace("sg-cconj-debug") << "Evaluate RHS : : " << rhs << std::endl;
+ //get the representative of rhs with substitution subs
+ TNode grhs = getTermDatabase()->evaluateTerm( rhs, subs, true );
+ Trace("sg-cconj-debug") << "...done evaluating term, got : " << grhs << std::endl;
+ if( !grhs.isNull() ){
+ if( glhs!=grhs ){
+ Trace("sg-cconj-debug") << "Ground eqc for RHS : " << grhs << std::endl;
+ //check based on ground terms
+ std::map< TNode, Node >::iterator itl = d_ground_eqc_map.find( glhs );
+ if( itl!=d_ground_eqc_map.end() ){
+ std::map< TNode, Node >::iterator itr = d_ground_eqc_map.find( grhs );
+ if( itr!=d_ground_eqc_map.end() ){
+ Trace("sg-cconj-debug") << "We have ground terms " << itl->second << " and " << itr->second << "." << std::endl;
+ if( itl->second.isConst() && itr->second.isConst() ){
+ Trace("sg-cconj-debug") << "...disequal constants." << std::endl;
+ Trace("sg-cconj-witness") << " Witness of falsification : " << itl->second << " != " << itr->second << ", substutition is : " << std::endl;
+ for( std::map< TNode, TNode >::iterator it = subs.begin(); it != subs.end(); ++it ){
+ Trace("sg-cconj-witness") << " " << it->first << " -> " << it->second << std::endl;
+ }
+ return false;
+ }
+ }
+ }
+ }
+ Trace("sg-cconj-debug") << "RHS is identical." << std::endl;
+ bool isGroundSubs = true;
+ for( std::map< TNode, TNode >::iterator it = subs.begin(); it != subs.end(); ++it ){
+ std::map< TNode, Node >::iterator git = d_ground_eqc_map.find( it->second );
+ if( git==d_ground_eqc_map.end() ){
+ isGroundSubs = false;
+ break;
+ }
+ }
+ if( isGroundSubs ){
+ if( glhs==grhs ){
+ Trace("sg-cconj-witness") << " Witnessed " << glhs << " == " << grhs << ", substutition is : " << std::endl;
+ for( std::map< TNode, TNode >::iterator it = subs.begin(); it != subs.end(); ++it ){
+ Trace("sg-cconj-witness") << " " << it->first << " -> " << it->second << std::endl;
+ if( std::find( d_subs_confirmWitnessDomain[it->first].begin(), d_subs_confirmWitnessDomain[it->first].end(), it->second )==d_subs_confirmWitnessDomain[it->first].end() ){
+ d_subs_confirmWitnessDomain[it->first].push_back( it->second );
+ }
+ }
+ d_subs_confirmCount++;
+ if( std::find( d_subs_confirmWitnessRange.begin(), d_subs_confirmWitnessRange.end(), glhs )==d_subs_confirmWitnessRange.end() ){
+ d_subs_confirmWitnessRange.push_back( glhs );
+ }
+ }else{
+ if( optFilterUnknown() ){
+ Trace("sg-cconj-debug") << "...ground substitution giving terms that are neither equal nor disequal." << std::endl;
+ return false;
+ }
+ }
+ }
+ }else{
+ Trace("sg-cconj-debug") << "(could not ground eqc for RHS)." << std::endl;
+ }
+ return true;
+}
+
+
+
+
+
+
+void TermGenerator::reset( TermGenEnv * s, TypeNode tn ) {
+ Assert( d_children.empty() );
+ d_typ = tn;
+ d_status = 0;
+ d_status_num = 0;
+ d_children.clear();
+ Trace("sg-gen-tg-debug2") << "...add to context " << this << std::endl;
+ d_id = s->d_tg_id;
+ s->changeContext( true );
+}
+
+bool TermGenerator::getNextTerm( TermGenEnv * s, unsigned depth ) {
+ if( Trace.isOn("sg-gen-tg-debug2") ){
+ Trace("sg-gen-tg-debug2") << this << " getNextTerm depth " << depth << " : status = " << d_status << ", num = " << d_status_num;
+ if( d_status==5 ){
+ TNode f = s->getTgFunc( d_typ, d_status_num );
+ Trace("sg-gen-tg-debug2") << ", f = " << f;
+ Trace("sg-gen-tg-debug2") << ", #args = " << s->d_func_args[f].size();
+ Trace("sg-gen-tg-debug2") << ", childNum = " << d_status_child_num;
+ Trace("sg-gen-tg-debug2") << ", #children = " << d_children.size();
+ }
+ Trace("sg-gen-tg-debug2") << std::endl;
+ }
+
+ if( d_status==0 ){
+ d_status++;
+ if( !d_typ.isNull() ){
+ if( s->allowVar( d_typ ) ){
+ //allocate variable
+ d_status_num = s->d_var_id[d_typ];
+ s->addVar( d_typ );
+ Trace("sg-gen-tg-debug2") << this << " ...return unique var #" << d_status_num << std::endl;
+ return s->considerCurrentTerm() ? true : getNextTerm( s, depth );
+ }else{
+ //check allocating new variable
+ d_status++;
+ d_status_num = -1;
+ if( s->d_gen_relevant_terms ){
+ s->d_tg_gdepth++;
+ }
+ return getNextTerm( s, depth );
+ }
+ }else{
+ d_status = 4;
+ d_status_num = -1;
+ return getNextTerm( s, depth );
+ }
+ }else if( d_status==2 ){
+ //cleanup previous information
+ //if( d_status_num>=0 ){
+ // s->d_var_eq_tg[d_status_num].pop_back();
+ //}
+ //check if there is another variable
+ if( (d_status_num+1)<(int)s->getNumTgVars( d_typ ) ){
+ d_status_num++;
+ //we have equated two variables
+ //s->d_var_eq_tg[d_status_num].push_back( d_id );
+ Trace("sg-gen-tg-debug2") << this << "...consider other var #" << d_status_num << std::endl;
+ return s->considerCurrentTerm() ? true : getNextTerm( s, depth );
+ }else{
+ if( s->d_gen_relevant_terms ){
+ s->d_tg_gdepth--;
+ }
+ d_status++;
+ return getNextTerm( s, depth );
+ }
+ }else if( d_status==4 ){
+ d_status++;
+ if( depth>0 && (d_status_num+1)<(int)s->getNumTgFuncs( d_typ ) ){
+ d_status_num++;
+ d_status_child_num = 0;
+ Trace("sg-gen-tg-debug2") << this << "...consider function " << s->getTgFunc( d_typ, d_status_num ) << std::endl;
+ s->d_tg_gdepth++;
+ if( !s->considerCurrentTerm() ){
+ s->d_tg_gdepth--;
+ //don't consider this function
+ d_status--;
+ }else{
+ //we have decided on a function application
+ }
+ return getNextTerm( s, depth );
+ }else{
+ //do not choose function applications at depth 0
+ d_status++;
+ return getNextTerm( s, depth );
+ }
+ }else if( d_status==5 ){
+ //iterating over arguments
+ TNode f = s->getTgFunc( d_typ, d_status_num );
+ if( d_status_child_num<0 ){
+ //no more arguments
+ s->d_tg_gdepth--;
+ d_status--;
+ return getNextTerm( s, depth );
+ }else if( d_status_child_num==(int)s->d_func_args[f].size() ){
+ d_status_child_num--;
+ return s->considerCurrentTermCanon( d_id ) ? true : getNextTerm( s, depth );
+ //return true;
+ }else{
+ Assert( d_status_child_num<(int)s->d_func_args[f].size() );
+ if( d_status_child_num==(int)d_children.size() ){
+ d_children.push_back( s->d_tg_id );
+ Assert( s->d_tg_alloc.find( s->d_tg_id )==s->d_tg_alloc.end() );
+ s->d_tg_alloc[d_children[d_status_child_num]].reset( s, s->d_func_args[f][d_status_child_num] );
+ return getNextTerm( s, depth );
+ }else{
+ Assert( d_status_child_num+1==(int)d_children.size() );
+ if( s->d_tg_alloc[d_children[d_status_child_num]].getNextTerm( s, depth-1 ) ){
+ d_status_child_num++;
+ return getNextTerm( s, depth );
+ }else{
+ d_children.pop_back();
+ d_status_child_num--;
+ return getNextTerm( s, depth );
+ }
+ }
+ }
+ }else if( d_status==1 || d_status==3 ){
+ if( d_status==1 ){
+ s->removeVar( d_typ );
+ Assert( d_status_num==(int)s->d_var_id[d_typ] );
+ //check if there is only one feasible equivalence class. if so, don't make pattern any more specific.
+ //unsigned i = s->d_ccand_eqc[0].size()-1;
+ //if( s->d_ccand_eqc[0][i].size()==1 && s->d_ccand_eqc[1][i].empty() ){
+ // d_status = 6;
+ // return getNextTerm( s, depth );
+ //}
+ s->d_tg_gdepth++;
+ }
+ d_status++;
+ d_status_num = -1;
+ return getNextTerm( s, depth );
+ }else{
+ //clean up
+ Assert( d_children.empty() );
+ Trace("sg-gen-tg-debug2") << "...remove from context " << this << std::endl;
+ s->changeContext( false );
+ Assert( d_id==s->d_tg_id );
+ return false;
+ }
+}
+
+void TermGenerator::resetMatching( TermGenEnv * s, TNode eqc, unsigned mode ) {
+ d_match_status = 0;
+ d_match_status_child_num = 0;
+ d_match_children.clear();
+ d_match_children_end.clear();
+ d_match_mode = mode;
+ //if this term generalizes, it must generalize a non-ground term
+ //if( (d_match_mode & ( 1 << 2 ))!=0 && s->isGroundEqc( eqc ) && d_status==5 ){
+ // d_match_status = -1;
+ //}
+}
+
+bool TermGenerator::getNextMatch( TermGenEnv * s, TNode eqc, std::map< TypeNode, std::map< unsigned, TNode > >& subs, std::map< TNode, bool >& rev_subs ) {
+ if( d_match_status<0 ){
+ return false;
+ }
+ if( Trace.isOn("sg-gen-tg-match") ){
+ Trace("sg-gen-tg-match") << "Matching ";
+ debugPrint( s, "sg-gen-tg-match", "sg-gen-tg-match" );
+ Trace("sg-gen-tg-match") << " with eqc e" << s->d_cg->d_em[eqc] << "..." << std::endl;
+ Trace("sg-gen-tg-match") << " mstatus = " << d_match_status;
+ if( d_status==5 ){
+ TNode f = s->getTgFunc( d_typ, d_status_num );
+ Trace("sg-gen-tg-debug2") << ", f = " << f;
+ Trace("sg-gen-tg-debug2") << ", #args = " << s->d_func_args[f].size();
+ Trace("sg-gen-tg-debug2") << ", mchildNum = " << d_match_status_child_num;
+ Trace("sg-gen-tg-debug2") << ", #mchildren = " << d_match_children.size();
+ }
+ Trace("sg-gen-tg-debug2") << ", current substitution : {";
+ for( std::map< TypeNode, std::map< unsigned, TNode > >::iterator itt = subs.begin(); itt != subs.end(); ++itt ){
+ for( std::map< unsigned, TNode >::iterator it = itt->second.begin(); it != itt->second.end(); ++it ){
+ Trace("sg-gen-tg-debug2") << " " << it->first << " -> e" << s->d_cg->d_em[it->second];
+ }
+ }
+ Trace("sg-gen-tg-debug2") << " } " << std::endl;
+ }
+ if( d_status==1 ){
+ //a variable
+ if( d_match_status==0 ){
+ d_match_status++;
+ if( (d_match_mode & ( 1 << 1 ))!=0 ){
+ //only ground terms
+ if( !s->isGroundEqc( eqc ) ){
+ return false;
+ }
+ }else if( (d_match_mode & ( 1 << 2 ))!=0 ){
+ //only non-ground terms
+ //if( s->isGroundEqc( eqc ) ){
+ // return false;
+ //}
+ }
+ //store the match : restricted if match_mode.0 = 1
+ if( (d_match_mode & ( 1 << 0 ))!=0 ){
+ std::map< TNode, bool >::iterator it = rev_subs.find( eqc );
+ if( it==rev_subs.end() ){
+ rev_subs[eqc] = true;
+ }else{
+ return false;
+ }
+ }
+ Assert( subs[d_typ].find( d_status_num )==subs[d_typ].end() );
+ subs[d_typ][d_status_num] = eqc;
+ return true;
+ }else{
+ //clean up
+ subs[d_typ].erase( d_status_num );
+ if( (d_match_mode & ( 1 << 0 ))!=0 ){
+ rev_subs.erase( eqc );
+ }
+ return false;
+ }
+ }else if( d_status==2 ){
+ if( d_match_status==0 ){
+ d_match_status++;
+ Assert( d_status_num<(int)s->getNumTgVars( d_typ ) );
+ std::map< unsigned, TNode >::iterator it = subs[d_typ].find( d_status_num );
+ Assert( it!=subs[d_typ].end() );
+ return it->second==eqc;
+ }else{
+ return false;
+ }
+ }else if( d_status==5 ){
+ //Assert( d_match_children.size()<=d_children.size() );
+ //enumerating over f-applications in eqc
+ if( d_match_status_child_num<0 ){
+ return false;
+ }else if( d_match_status==0 ){
+ //set up next binding
+ if( d_match_status_child_num==(int)d_match_children.size() ){
+ if( d_match_status_child_num==0 ){
+ //initial binding
+ TNode f = s->getTgFunc( d_typ, d_status_num );
+ std::map< TNode, TermArgTrie >::iterator it = s->getTermDatabase()->d_func_map_eqc_trie[f].d_data.find( eqc );
+ if( it!=s->getTermDatabase()->d_func_map_eqc_trie[f].d_data.end() ){
+ d_match_children.push_back( it->second.d_data.begin() );
+ d_match_children_end.push_back( it->second.d_data.end() );
+ }else{
+ d_match_status++;
+ d_match_status_child_num--;
+ return getNextMatch( s, eqc, subs, rev_subs );
+ }
+ }else{
+ d_match_children.push_back( d_match_children[d_match_status_child_num-1]->second.d_data.begin() );
+ d_match_children_end.push_back( d_match_children[d_match_status_child_num-1]->second.d_data.end() );
+ }
+ }
+ d_match_status++;
+ Assert( d_match_status_child_num+1==(int)d_match_children.size() );
+ if( d_match_children[d_match_status_child_num]==d_match_children_end[d_match_status_child_num] ){
+ //no more arguments to bind
+ d_match_children.pop_back();
+ d_match_children_end.pop_back();
+ d_match_status_child_num--;
+ return getNextMatch( s, eqc, subs, rev_subs );
+ }else{
+ if( d_match_status_child_num==(int)d_children.size() ){
+ //successfully matched all children
+ d_match_children.pop_back();
+ d_match_children_end.pop_back();
+ d_match_status_child_num--;
+ return true;//return d_match_children[d_match_status]!=d_match_children_end[d_match_status];
+ }else{
+ //do next binding
+ s->d_tg_alloc[d_children[d_match_status_child_num]].resetMatching( s, d_match_children[d_match_status_child_num]->first, d_match_mode );
+ return getNextMatch( s, eqc, subs, rev_subs );
+ }
+ }
+ }else{
+ Assert( d_match_status==1 );
+ Assert( d_match_status_child_num+1==(int)d_match_children.size() );
+ Assert( d_match_children[d_match_status_child_num]!=d_match_children_end[d_match_status_child_num] );
+ d_match_status--;
+ if( s->d_tg_alloc[d_children[d_match_status_child_num]].getNextMatch( s, d_match_children[d_match_status_child_num]->first, subs, rev_subs ) ){
+ d_match_status_child_num++;
+ return getNextMatch( s, eqc, subs, rev_subs );
+ }else{
+ //iterate
+ d_match_children[d_match_status_child_num]++;
+ return getNextMatch( s, eqc, subs, rev_subs );
+ }
+ }
+ }
+ Assert( false );
+ return false;
+}
+
+unsigned TermGenerator::getDepth( TermGenEnv * s ) {
+ if( d_status==5 ){
+ unsigned maxd = 0;
+ for( unsigned i=0; i<d_children.size(); i++ ){
+ unsigned d = s->d_tg_alloc[d_children[i]].getDepth( s );
+ if( d>maxd ){
+ maxd = d;
+ }
+ }
+ return 1+maxd;
+ }else{
+ return 0;
+ }
+}
+
+unsigned TermGenerator::calculateGeneralizationDepth( TermGenEnv * s, std::map< TypeNode, std::vector< int > >& fvs ) {
+ if( d_status==5 ){
+ unsigned sum = 1;
+ for( unsigned i=0; i<d_children.size(); i++ ){
+ sum += s->d_tg_alloc[d_children[i]].calculateGeneralizationDepth( s, fvs );
+ }
+ return sum;
+ }else{
+ Assert( d_status==2 || d_status==1 );
+ std::map< TypeNode, std::vector< int > >::iterator it = fvs.find( d_typ );
+ if( it!=fvs.end() ){
+ if( std::find( it->second.begin(), it->second.end(), d_status_num )!=it->second.end() ){
+ return 1;
+ }
+ }
+ fvs[d_typ].push_back( d_status_num );
+ return 0;
+ }
+}
+
+unsigned TermGenerator::getGeneralizationDepth( TermGenEnv * s ) {
+ //if( s->d_gen_relevant_terms ){
+ // return s->d_tg_gdepth;
+ //}else{
+ std::map< TypeNode, std::vector< int > > fvs;
+ return calculateGeneralizationDepth( s, fvs );
+ //}
+}
+
+Node TermGenerator::getTerm( TermGenEnv * s ) {
+ if( d_status==1 || d_status==2 ){
+ Assert( !d_typ.isNull() );
+ return s->getFreeVar( d_typ, d_status_num );
+ }else if( d_status==5 ){
+ Node f = s->getTgFunc( d_typ, d_status_num );
+ if( d_children.size()==s->d_func_args[f].size() ){
+ std::vector< Node > children;
+ children.push_back( f );
+ for( unsigned i=0; i<d_children.size(); i++ ){
+ Node nc = s->d_tg_alloc[d_children[i]].getTerm( s );
+ if( nc.isNull() ){
+ return Node::null();
+ }else{
+ //Assert( nc.getType()==s->d_func_args[f][i] );
+ children.push_back( nc );
+ }
+ }
+ return NodeManager::currentNM()->mkNode( s->d_func_kind[f], children );
+ }
+ }else{
+ Assert( false );
+ }
+ return Node::null();
+}
+
+void TermGenerator::debugPrint( TermGenEnv * s, const char * c, const char * cd ) {
+ Trace(cd) << "[*" << d_id << "," << d_status << "]:";
+ if( d_status==1 || d_status==2 ){
+ Trace(c) << s->getFreeVar( d_typ, d_status_num );
+ }else if( d_status==5 ){
+ TNode f = s->getTgFunc( d_typ, d_status_num );
+ Trace(c) << "(" << f;
+ for( unsigned i=0; i<d_children.size(); i++ ){
+ Trace(c) << " ";
+ s->d_tg_alloc[d_children[i]].debugPrint( s, c, cd );
+ }
+ if( d_children.size()<s->d_func_args[f].size() ){
+ Trace(c) << " ...";
+ }
+ Trace(c) << ")";
+ }else{
+ Trace(c) << "???";
+ }
+}
+
+void TermGenEnv::collectSignatureInformation() {
+ d_typ_tg_funcs.clear();
+ d_funcs.clear();
+ d_func_kind.clear();
+ d_func_args.clear();
+ TypeNode tnull;
+ for( std::map< Node, TermArgTrie >::iterator it = getTermDatabase()->d_func_map_trie.begin(); it != getTermDatabase()->d_func_map_trie.end(); ++it ){
+ if( !getTermDatabase()->d_op_map[it->first].empty() ){
+ Node nn = getTermDatabase()->d_op_map[it->first][0];
+ if( d_cg->isHandledTerm( nn ) && nn.getKind()!=APPLY_SELECTOR_TOTAL && !nn.getType().isBoolean() ){
+ bool do_enum = true;
+ //check if we have enumerated ground terms
+ if( nn.getKind()==APPLY_UF ){
+ if( !d_cg->hasEnumeratedUf( nn ) ){
+ do_enum = false;
+ }
+ }
+ if( do_enum ){
+ d_funcs.push_back( it->first );
+ for( unsigned i=0; i<nn.getNumChildren(); i++ ){
+ d_func_args[it->first].push_back( nn[i].getType() );
+ }
+ d_func_kind[it->first] = nn.getKind();
+ d_typ_tg_funcs[tnull].push_back( it->first );
+ d_typ_tg_funcs[nn.getType()].push_back( it->first );
+ Trace("sg-rel-sig") << "Will enumerate function applications of : " << it->first << ", #args = " << d_func_args[it->first].size() << ", kind = " << nn.getKind() << std::endl;
+ getTermDatabase()->computeUfEqcTerms( it->first );
+ }
+ }
+ }
+ }
+ //shuffle functions
+ for( std::map< TypeNode, std::vector< TNode > >::iterator it = d_typ_tg_funcs.begin(); it != d_typ_tg_funcs.end(); ++it ){
+ std::random_shuffle( it->second.begin(), it->second.end() );
+ if( it->first.isNull() ){
+ Trace("sg-gen-tg-debug") << "In this order : ";
+ for( unsigned i=0; i<it->second.size(); i++ ){
+ Trace("sg-gen-tg-debug") << it->second[i] << " ";
+ }
+ Trace("sg-gen-tg-debug") << std::endl;
+ }
+ }
+}
+
+void TermGenEnv::reset( unsigned depth, bool genRelevant, TypeNode tn ) {
+ Assert( d_tg_alloc.empty() );
+ d_tg_alloc.clear();
+
+ if( genRelevant ){
+ for( unsigned i=0; i<2; i++ ){
+ d_ccand_eqc[i].clear();
+ d_ccand_eqc[i].push_back( d_relevant_eqc[i] );
+ }
+ }
+
+ d_tg_id = 0;
+ d_tg_gdepth = 0;
+ d_tg_gdepth_limit = depth;
+ d_gen_relevant_terms = genRelevant;
+ d_tg_alloc[0].reset( this, tn );
+}
+
+bool TermGenEnv::getNextTerm() {
+ if( d_tg_alloc[0].getNextTerm( this, d_tg_gdepth_limit ) ){
+ Assert( (int)d_tg_alloc[0].getGeneralizationDepth( this )<=d_tg_gdepth_limit );
+ if( (int)d_tg_alloc[0].getGeneralizationDepth( this )!=d_tg_gdepth_limit ){
+ return getNextTerm();
+ }else{
+ return true;
+ }
+ }else{
+ return false;
+ }
+}
+
+//reset matching
+void TermGenEnv::resetMatching( TNode eqc, unsigned mode ) {
+ d_tg_alloc[0].resetMatching( this, eqc, mode );
+}
+
+//get next match
+bool TermGenEnv::getNextMatch( TNode eqc, std::map< TypeNode, std::map< unsigned, TNode > >& subs, std::map< TNode, bool >& rev_subs ) {
+ return d_tg_alloc[0].getNextMatch( this, eqc, subs, rev_subs );
+}
+
+//get term
+Node TermGenEnv::getTerm() {
+ return d_tg_alloc[0].getTerm( this );
+}
+
+void TermGenEnv::debugPrint( const char * c, const char * cd ) {
+ d_tg_alloc[0].debugPrint( this, c, cd );
+}
+
+unsigned TermGenEnv::getNumTgVars( TypeNode tn ) {
+ return d_var_id[tn];
+}
+
+bool TermGenEnv::allowVar( TypeNode tn ) {
+ std::map< TypeNode, unsigned >::iterator it = d_var_limit.find( tn );
+ if( it==d_var_limit.end() ){
+ return true;
+ }else{
+ return d_var_id[tn]<it->second;
+ }
+}
+
+void TermGenEnv::addVar( TypeNode tn ) {
+ d_var_id[tn]++;
+}
+
+void TermGenEnv::removeVar( TypeNode tn ) {
+ d_var_id[tn]--;
+ //d_var_eq_tg.pop_back();
+ //d_var_tg.pop_back();
+}
+
+unsigned TermGenEnv::getNumTgFuncs( TypeNode tn ) {
+ return d_typ_tg_funcs[tn].size();
+}
+
+TNode TermGenEnv::getTgFunc( TypeNode tn, unsigned i ) {
+ return d_typ_tg_funcs[tn][i];
+}
+
+Node TermGenEnv::getFreeVar( TypeNode tn, unsigned i ) {
+ return d_cg->getFreeVar( tn, i );
+}
+
+bool TermGenEnv::considerCurrentTerm() {
+ Assert( !d_tg_alloc.empty() );
+
+ //if generalization depth is too large, don't consider it
+ unsigned i = d_tg_alloc.size();
+ Trace("sg-gen-tg-debug") << "Consider term ";
+ d_tg_alloc[0].debugPrint( this, "sg-gen-tg-debug", "sg-gen-tg-debug" );
+ Trace("sg-gen-tg-debug") << "? curr term size = " << d_tg_alloc.size() << ", last status = " << d_tg_alloc[i-1].d_status;
+ Trace("sg-gen-tg-debug") << std::endl;
+
+ if( d_tg_gdepth_limit>=0 && d_tg_alloc[0].getGeneralizationDepth( this )>(unsigned)d_tg_gdepth_limit ){
+ Trace("sg-gen-consider-term") << "-> generalization depth of ";
+ d_tg_alloc[0].debugPrint( this, "sg-gen-consider-term", "sg-gen-tg-debug" );
+ Trace("sg-gen-consider-term") << " is too high " << d_tg_gdepth << " " << d_tg_alloc[0].getGeneralizationDepth( this ) << ", do not consider." << std::endl;
+ return false;
+ }
+
+ //----optimizations
+ /*
+ if( d_tg_alloc[i-1].d_status==1 ){
+ }else if( d_tg_alloc[i-1].d_status==2 ){
+ }else if( d_tg_alloc[i-1].d_status==5 ){
+ }else{
+ Trace("sg-gen-tg-debug") << "Bad tg: " << &d_tg_alloc[i-1] << std::endl;
+ Assert( false );
+ }
+ */
+ //if equated two variables, first check if context-independent TODO
+ //----end optimizations
+
+
+ //check based on which candidate equivalence classes match
+ if( d_gen_relevant_terms ){
+ Trace("sg-gen-tg-debug") << "Filter based on relevant ground EQC";
+ Trace("sg-gen-tg-debug") << ", #eqc to try = " << d_ccand_eqc[0][i-1].size() << "/" << d_ccand_eqc[1][i-1].size() << std::endl;
+
+ Assert( d_ccand_eqc[0].size()>=2 );
+ Assert( d_ccand_eqc[0].size()==d_ccand_eqc[1].size() );
+ Assert( d_ccand_eqc[0].size()==d_tg_id+1 );
+ Assert( d_tg_id==d_tg_alloc.size() );
+ for( unsigned r=0; r<2; r++ ){
+ d_ccand_eqc[r][i].clear();
+ }
+
+ //re-check feasibility of EQC
+ for( unsigned r=0; r<2; r++ ){
+ for( unsigned j=0; j<d_ccand_eqc[r][i-1].size(); j++ ){
+ std::map< TypeNode, std::map< unsigned, TNode > > subs;
+ std::map< TNode, bool > rev_subs;
+ unsigned mode;
+ if( r==0 ){
+ mode = d_cg->optReqDistinctVarPatterns() ? ( 1 << 0 ) : 0;
+ mode = mode | (1 << 2 );
+ }else{
+ mode = 1 << 1;
+ }
+ d_tg_alloc[0].resetMatching( this, d_ccand_eqc[r][i-1][j], mode );
+ if( d_tg_alloc[0].getNextMatch( this, d_ccand_eqc[r][i-1][j], subs, rev_subs ) ){
+ d_ccand_eqc[r][i].push_back( d_ccand_eqc[r][i-1][j] );
+ }
+ }
+ }
+ for( unsigned r=0; r<2; r++ ){
+ Trace("sg-gen-tg-debug") << "Current eqc of type " << r << " : ";
+ for( unsigned j=0; j<d_ccand_eqc[r][i].size(); j++ ){
+ Trace("sg-gen-tg-debug") << "e" << d_cg->d_em[d_ccand_eqc[r][i][j]] << " ";
+ }
+ Trace("sg-gen-tg-debug") << std::endl;
+ }
+ if( options::conjectureFilterActiveTerms() && d_ccand_eqc[0][i].empty() ){
+ Trace("sg-gen-consider-term") << "Do not consider term of form ";
+ d_tg_alloc[0].debugPrint( this, "sg-gen-consider-term", "sg-gen-consider-term-debug" );
+ Trace("sg-gen-consider-term") << " since no relevant EQC matches it." << std::endl;
+ return false;
+ }
+ if( options::conjectureFilterModel() && d_ccand_eqc[1][i].empty() ){
+ Trace("sg-gen-consider-term") << "Do not consider term of form ";
+ d_tg_alloc[0].debugPrint( this, "sg-gen-consider-term", "sg-gen-consider-term-debug" );
+ Trace("sg-gen-consider-term") << " since no ground EQC matches it." << std::endl;
+ return false;
+ }
+ }
+ Trace("sg-gen-tg-debug") << "Will consider term ";
+ d_tg_alloc[0].debugPrint( this, "sg-gen-tg-debug", "sg-gen-tg-debug" );
+ Trace("sg-gen-tg-debug") << std::endl;
+ Trace("sg-gen-consider-term-debug") << std::endl;
+ return true;
+}
+
+void TermGenEnv::changeContext( bool add ) {
+ if( add ){
+ for( unsigned r=0; r<2; r++ ){
+ d_ccand_eqc[r].push_back( std::vector< TNode >() );
+ }
+ d_tg_id++;
+ }else{
+ for( unsigned r=0; r<2; r++ ){
+ d_ccand_eqc[r].pop_back();
+ }
+ d_tg_id--;
+ Assert( d_tg_alloc.find( d_tg_id )!=d_tg_alloc.end() );
+ d_tg_alloc.erase( d_tg_id );
+ }
+}
+
+bool TermGenEnv::considerCurrentTermCanon( unsigned tg_id ){
+ Assert( tg_id<d_tg_alloc.size() );
+ if( options::conjectureFilterCanonical() ){
+ //check based on a canonicity of the term (if there is one)
+ Trace("sg-gen-tg-debug") << "Consider term canon ";
+ d_tg_alloc[0].debugPrint( this, "sg-gen-tg-debug", "sg-gen-tg-debug" );
+ Trace("sg-gen-tg-debug") << ", tg is [" << tg_id << "]..." << std::endl;
+
+ Node ln = d_tg_alloc[tg_id].getTerm( this );
+ Trace("sg-gen-tg-debug") << "Term is " << ln << std::endl;
+ return d_cg->considerTermCanon( ln, d_gen_relevant_terms );
+ }
+ return true;
+}
+
+bool TermGenEnv::isRelevantFunc( Node f ) {
+ return std::find( d_funcs.begin(), d_funcs.end(), f )!=d_funcs.end();
+}
+TermDb * TermGenEnv::getTermDatabase() {
+ return d_cg->getTermDatabase();
+}
+Node TermGenEnv::getGroundEqc( TNode r ) {
+ return d_cg->getGroundEqc( r );
+}
+bool TermGenEnv::isGroundEqc( TNode r ){
+ return d_cg->isGroundEqc( r );
+}
+bool TermGenEnv::isGroundTerm( TNode n ){
+ return d_cg->isGroundTerm( n );
+}
+
+
+void SubstitutionIndex::addSubstitution( TNode eqc, std::vector< TNode >& vars, std::vector< TNode >& terms, unsigned i ) {
+ if( i==vars.size() ){
+ d_var = eqc;
+ }else{
+ Assert( d_var.isNull() || d_var==vars[i] );
+ d_var = vars[i];
+ d_children[terms[i]].addSubstitution( eqc, vars, terms, i+1 );
+ }
+}
+
+bool SubstitutionIndex::notifySubstitutions( ConjectureGenerator * s, std::map< TNode, TNode >& subs, TNode rhs, unsigned numVars, unsigned i ) {
+ if( i==numVars ){
+ Assert( d_children.empty() );
+ return s->notifySubstitution( d_var, subs, rhs );
+ }else{
+ Assert( i==0 || !d_children.empty() );
+ for( std::map< TNode, SubstitutionIndex >::iterator it = d_children.begin(); it != d_children.end(); ++it ){
+ Trace("sg-cconj-debug2") << "Try " << d_var << " -> " << it->first << " (" << i << "/" << numVars << ")" << std::endl;
+ subs[d_var] = it->first;
+ if( !it->second.notifySubstitutions( s, subs, rhs, numVars, i+1 ) ){
+ return false;
+ }
+ }
+ return true;
+ }
+}
+
+
+void TheoremIndex::addTheorem( std::vector< TNode >& lhs_v, std::vector< unsigned >& lhs_arg, TNode rhs ){
+ if( lhs_v.empty() ){
+ if( std::find( d_terms.begin(), d_terms.end(), rhs )==d_terms.end() ){
+ d_terms.push_back( rhs );
+ }
+ }else{
+ unsigned index = lhs_v.size()-1;
+ if( lhs_arg[index]==lhs_v[index].getNumChildren() ){
+ lhs_v.pop_back();
+ lhs_arg.pop_back();
+ addTheorem( lhs_v, lhs_arg, rhs );
+ }else{
+ lhs_arg[index]++;
+ addTheoremNode( lhs_v[index][lhs_arg[index]-1], lhs_v, lhs_arg, rhs );
+ }
+ }
+}
+
+void TheoremIndex::addTheoremNode( TNode curr, std::vector< TNode >& lhs_v, std::vector< unsigned >& lhs_arg, TNode rhs ){
+ Trace("thm-db-debug") << "Adding conjecture for subterm " << curr << "..." << std::endl;
+ if( curr.hasOperator() ){
+ lhs_v.push_back( curr );
+ lhs_arg.push_back( 0 );
+ d_children[curr.getOperator()].addTheorem( lhs_v, lhs_arg, rhs );
+ }else{
+ Assert( curr.getKind()==kind::BOUND_VARIABLE );
+ TypeNode tn = curr.getType();
+ Assert( d_var[tn].isNull() || d_var[tn]==curr );
+ d_var[tn] = curr;
+ d_children[curr].addTheorem( lhs_v, lhs_arg, rhs );
+ }
+}
+
+void TheoremIndex::getEquivalentTerms( std::vector< TNode >& n_v, std::vector< unsigned >& n_arg,
+ std::map< TNode, TNode >& smap, std::vector< TNode >& vars, std::vector< TNode >& subs,
+ std::vector< Node >& terms ) {
+ Trace("thm-db-debug") << "Get equivalent terms " << n_v.size() << " " << n_arg.size() << std::endl;
+ if( n_v.empty() ){
+ Trace("thm-db-debug") << "Number of terms : " << d_terms.size() << std::endl;
+ //apply substutitions to RHS's
+ for( unsigned i=0; i<d_terms.size(); i++ ){
+ Node n = d_terms[i].substitute( vars.begin(), vars.end(), subs.begin(), subs.end() );
+ terms.push_back( n );
+ }
+ }else{
+ unsigned index = n_v.size()-1;
+ if( n_arg[index]==n_v[index].getNumChildren() ){
+ n_v.pop_back();
+ n_arg.pop_back();
+ getEquivalentTerms( n_v, n_arg, smap, vars, subs, terms );
+ }else{
+ n_arg[index]++;
+ getEquivalentTermsNode( n_v[index][n_arg[index]-1], n_v, n_arg, smap, vars, subs, terms );
+ }
+ }
+}
+
+void TheoremIndex::getEquivalentTermsNode( Node curr, std::vector< TNode >& n_v, std::vector< unsigned >& n_arg,
+ std::map< TNode, TNode >& smap, std::vector< TNode >& vars, std::vector< TNode >& subs,
+ std::vector< Node >& terms ) {
+ Trace("thm-db-debug") << "Get equivalent based on subterm " << curr << "..." << std::endl;
+ if( curr.hasOperator() ){
+ Trace("thm-db-debug") << "Check based on operator..." << std::endl;
+ std::map< TNode, TheoremIndex >::iterator it = d_children.find( curr.getOperator() );
+ if( it!=d_children.end() ){
+ n_v.push_back( curr );
+ n_arg.push_back( 0 );
+ it->second.getEquivalentTerms( n_v, n_arg, smap, vars, subs, terms );
+ }
+ Trace("thm-db-debug") << "...done check based on operator" << std::endl;
+ }
+ TypeNode tn = curr.getType();
+ std::map< TypeNode, TNode >::iterator itt = d_var.find( tn );
+ if( itt!=d_var.end() ){
+ Trace("thm-db-debug") << "Check for substitution with " << itt->second << "..." << std::endl;
+ Assert( curr.getType()==itt->second.getType() );
+ //add to substitution if possible
+ bool success = false;
+ std::map< TNode, TNode >::iterator it = smap.find( itt->second );
+ if( it==smap.end() ){
+ smap[itt->second] = curr;
+ vars.push_back( itt->second );
+ subs.push_back( curr );
+ success = true;
+ }else if( it->second==curr ){
+ success = true;
+ }else{
+ //also check modulo equality (in universal equality engine)
+ }
+ Trace("thm-db-debug") << "...check for substitution with " << itt->second << ", success = " << success << "." << std::endl;
+ if( success ){
+ d_children[itt->second].getEquivalentTerms( n_v, n_arg, smap, vars, subs, terms );
+ }
+ }
+}
+
+void TheoremIndex::debugPrint( const char * c, unsigned ind ) {
+ for( std::map< TNode, TheoremIndex >::iterator it = d_children.begin(); it != d_children.end(); ++it ){
+ for( unsigned i=0; i<ind; i++ ){ Trace(c) << " "; }
+ Trace(c) << it->first << std::endl;
+ it->second.debugPrint( c, ind+1 );
+ }
+ if( !d_terms.empty() ){
+ for( unsigned i=0; i<ind; i++ ){ Trace(c) << " "; }
+ Trace(c) << "{";
+ for( unsigned i=0; i<d_terms.size(); i++ ){
+ Trace(c) << " " << d_terms[i];
+ }
+ Trace(c) << " }" << std::endl;
+ }
+ //if( !d_var.isNull() ){
+ // for( unsigned i=0; i<ind; i++ ){ Trace(c) << " "; }
+ // Trace(c) << "var:" << d_var << std::endl;
+ //}
+}
+
+bool ConjectureGenerator::optReqDistinctVarPatterns() { return false; }
+bool ConjectureGenerator::optFilterUnknown() { return true; } //may change
+int ConjectureGenerator::optFilterScoreThreshold() { return 1; }
+unsigned ConjectureGenerator::optFullCheckFrequency() { return 1; }
+
+bool ConjectureGenerator::optStatsOnly() { return false; }
+
+}
diff --git a/src/theory/quantifiers/conjecture_generator.h b/src/theory/quantifiers/conjecture_generator.h new file mode 100755 index 000000000..23e2b88ba --- /dev/null +++ b/src/theory/quantifiers/conjecture_generator.h @@ -0,0 +1,446 @@ +/********************* */
+/*! \file conjecture_generator.h
+ ** \verbatim
+ ** Original author: Andrew Reynolds
+ ** Major contributors: none
+ ** Minor contributors (to current version): none
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2014 New York University and The University of Iowa
+ ** See the file COPYING in the top-level source directory for licensing
+ ** information.\endverbatim
+ **
+ ** \brief conjecture generator class
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef CONJECTURE_GENERATOR_H
+#define CONJECTURE_GENERATOR_H
+
+#include "context/cdhashmap.h"
+#include "context/cdchunk_list.h"
+#include "theory/quantifiers_engine.h"
+#include "theory/type_enumerator.h"
+
+namespace CVC4 {
+namespace theory {
+namespace quantifiers {
+
+class TermArgTrie;
+
+//algorithm for computing candidate subgoals
+
+class ConjectureGenerator;
+
+// operator independent index of arguments for an EQC
+class OpArgIndex
+{
+public:
+ std::map< TNode, OpArgIndex > d_child;
+ std::vector< TNode > d_ops;
+ std::vector< TNode > d_op_terms;
+ void addTerm( ConjectureGenerator * s, TNode n, unsigned index = 0 );
+ Node getGroundTerm( ConjectureGenerator * s, std::vector< TNode >& args );
+ void getGroundTerms( ConjectureGenerator * s, std::vector< TNode >& terms );
+};
+
+class PatternTypIndex
+{
+public:
+ std::vector< TNode > d_terms;
+ std::map< TypeNode, std::map< unsigned, PatternTypIndex > > d_children;
+ void clear() {
+ d_terms.clear();
+ d_children.clear();
+ }
+};
+
+class SubstitutionIndex
+{
+public:
+ //current variable, or ground EQC if d_children.empty()
+ TNode d_var;
+ std::map< TNode, SubstitutionIndex > d_children;
+ //add substitution
+ void addSubstitution( TNode eqc, std::vector< TNode >& vars, std::vector< TNode >& terms, unsigned i = 0 );
+ //notify substitutions
+ bool notifySubstitutions( ConjectureGenerator * s, std::map< TNode, TNode >& subs, TNode rhs, unsigned numVars, unsigned i = 0 );
+};
+
+class TermGenEnv;
+
+class TermGenerator
+{
+private:
+ unsigned calculateGeneralizationDepth( TermGenEnv * s, std::map< TypeNode, std::vector< int > >& fvs );
+public:
+ TermGenerator(){}
+ TypeNode d_typ;
+ unsigned d_id;
+ //1 : consider as unique variable
+ //2 : consider equal to another variable
+ //5 : consider a function application
+ unsigned d_status;
+ int d_status_num;
+ //for function applications: the number of children you have built
+ int d_status_child_num;
+ //children (pointers to TermGenerators)
+ std::vector< unsigned > d_children;
+
+ //match status
+ int d_match_status;
+ int d_match_status_child_num;
+ //match mode bits
+ //0 : different variables must have different matches
+ //1 : variables must map to ground terms
+ //2 : variables must map to non-ground terms
+ unsigned d_match_mode;
+ //children
+ std::vector< std::map< TNode, TermArgTrie >::iterator > d_match_children;
+ std::vector< std::map< TNode, TermArgTrie >::iterator > d_match_children_end;
+
+ void reset( TermGenEnv * s, TypeNode tn );
+ bool getNextTerm( TermGenEnv * s, unsigned depth );
+ void resetMatching( TermGenEnv * s, TNode eqc, unsigned mode );
+ bool getNextMatch( TermGenEnv * s, TNode eqc, std::map< TypeNode, std::map< unsigned, TNode > >& subs, std::map< TNode, bool >& rev_subs );
+
+ unsigned getDepth( TermGenEnv * s );
+ unsigned getGeneralizationDepth( TermGenEnv * s );
+ Node getTerm( TermGenEnv * s );
+
+ void debugPrint( TermGenEnv * s, const char * c, const char * cd );
+};
+
+
+class TermGenEnv
+{
+public:
+ //collect signature information
+ void collectSignatureInformation();
+ //reset function
+ void reset( unsigned gdepth, bool genRelevant, TypeNode tgen );
+ //get next term
+ bool getNextTerm();
+ //reset matching
+ void resetMatching( TNode eqc, unsigned mode );
+ //get next match
+ bool getNextMatch( TNode eqc, std::map< TypeNode, std::map< unsigned, TNode > >& subs, std::map< TNode, bool >& rev_subs );
+ //get term
+ Node getTerm();
+ //debug print
+ void debugPrint( const char * c, const char * cd );
+
+ //conjecture generation
+ ConjectureGenerator * d_cg;
+ //the current number of enumerated variables per type
+ std::map< TypeNode, unsigned > d_var_id;
+ //the limit of number of variables per type to enumerate
+ std::map< TypeNode, unsigned > d_var_limit;
+ //the functions we can currently generate
+ std::map< TypeNode, std::vector< TNode > > d_typ_tg_funcs;
+ //the equivalence classes (if applicable) that match the currently generated term
+ bool d_gen_relevant_terms;
+ //relevant equivalence classes
+ std::vector< TNode > d_relevant_eqc[2];
+ //candidate equivalence classes
+ std::vector< std::vector< TNode > > d_ccand_eqc[2];
+ //the term generation objects
+ unsigned d_tg_id;
+ std::map< unsigned, TermGenerator > d_tg_alloc;
+ unsigned d_tg_gdepth;
+ int d_tg_gdepth_limit;
+
+ //all functions
+ std::vector< TNode > d_funcs;
+ //function to kind map
+ std::map< TNode, Kind > d_func_kind;
+ //type of each argument of the function
+ std::map< TNode, std::vector< TypeNode > > d_func_args;
+
+ //access functions
+ unsigned getNumTgVars( TypeNode tn );
+ bool allowVar( TypeNode tn );
+ void addVar( TypeNode tn );
+ void removeVar( TypeNode tn );
+ unsigned getNumTgFuncs( TypeNode tn );
+ TNode getTgFunc( TypeNode tn, unsigned i );
+ Node getFreeVar( TypeNode tn, unsigned i );
+ bool considerCurrentTerm();
+ bool considerCurrentTermCanon( unsigned tg_id );
+ void changeContext( bool add );
+ bool isRelevantFunc( Node f );
+ //carry
+ TermDb * getTermDatabase();
+ Node getGroundEqc( TNode r );
+ bool isGroundEqc( TNode r );
+ bool isGroundTerm( TNode n );
+};
+
+
+
+class TheoremIndex
+{
+private:
+ void addTheorem( std::vector< TNode >& lhs_v, std::vector< unsigned >& lhs_arg, TNode rhs );
+ void addTheoremNode( TNode curr, std::vector< TNode >& lhs_v, std::vector< unsigned >& lhs_arg, TNode rhs );
+ void getEquivalentTerms( std::vector< TNode >& n_v, std::vector< unsigned >& n_arg,
+ std::map< TNode, TNode >& smap, std::vector< TNode >& vars, std::vector< TNode >& subs,
+ std::vector< Node >& terms );
+ void getEquivalentTermsNode( Node curr, std::vector< TNode >& n_v, std::vector< unsigned >& n_arg,
+ std::map< TNode, TNode >& smap, std::vector< TNode >& vars, std::vector< TNode >& subs,
+ std::vector< Node >& terms );
+public:
+ std::map< TypeNode, TNode > d_var;
+ std::map< TNode, TheoremIndex > d_children;
+ std::vector< Node > d_terms;
+
+ void addTheorem( TNode lhs, TNode rhs ) {
+ std::vector< TNode > v;
+ std::vector< unsigned > a;
+ addTheoremNode( lhs, v, a, rhs );
+ }
+ void getEquivalentTerms( TNode n, std::vector< Node >& terms ) {
+ std::vector< TNode > nv;
+ std::vector< unsigned > na;
+ std::map< TNode, TNode > smap;
+ std::vector< TNode > vars;
+ std::vector< TNode > subs;
+ getEquivalentTermsNode( n, nv, na, smap, vars, subs, terms );
+ }
+ void clear(){
+ d_var.clear();
+ d_children.clear();
+ d_terms.clear();
+ }
+ void debugPrint( const char * c, unsigned ind = 0 );
+};
+
+
+
+class ConjectureGenerator : public QuantifiersModule
+{
+ friend class OpArgIndex;
+ friend class PatGen;
+ friend class PatternGenEqc;
+ friend class PatternGen;
+ friend class SubsEqcIndex;
+ friend class TermGenerator;
+ friend class TermGenEnv;
+ typedef context::CDChunkList<Node> NodeList;
+ typedef context::CDHashMap< Node, Node, NodeHashFunction > NodeMap;
+ typedef context::CDHashMap< Node, bool, NodeHashFunction > BoolMap;
+//this class maintains a congruence closure for *universal* facts
+private:
+ //notification class for equality engine
+ class NotifyClass : public eq::EqualityEngineNotify {
+ ConjectureGenerator& d_sg;
+ public:
+ NotifyClass(ConjectureGenerator& sg): d_sg(sg) {}
+ bool eqNotifyTriggerEquality(TNode equality, bool value) { return true; }
+ bool eqNotifyTriggerPredicate(TNode predicate, bool value) { return true; }
+ bool eqNotifyTriggerTermEquality(TheoryId tag, TNode t1, TNode t2, bool value) { return true; }
+ void eqNotifyConstantTermMerge(TNode t1, TNode t2) { }
+ void eqNotifyNewClass(TNode t) { d_sg.eqNotifyNewClass(t); }
+ void eqNotifyPreMerge(TNode t1, TNode t2) { d_sg.eqNotifyPreMerge(t1, t2); }
+ void eqNotifyPostMerge(TNode t1, TNode t2) { d_sg.eqNotifyPostMerge(t1, t2); }
+ void eqNotifyDisequal(TNode t1, TNode t2, TNode reason) {d_sg.eqNotifyDisequal(t1, t2, reason); }
+ };/* class ConjectureGenerator::NotifyClass */
+ /** The notify class */
+ NotifyClass d_notify;
+ class EqcInfo{
+ public:
+ EqcInfo( context::Context* c );
+ //representative
+ context::CDO< Node > d_rep;
+ };
+ /** get or make eqc info */
+ EqcInfo* getOrMakeEqcInfo( TNode n, bool doMake = false );
+ /** (universal) equaltity engine */
+ eq::EqualityEngine d_uequalityEngine;
+ /** pending adds */
+ std::vector< Node > d_upendingAdds;
+ /** relevant terms */
+ std::map< Node, bool > d_urelevant_terms;
+ /** information necessary for equivalence classes */
+ std::map< Node, EqcInfo* > d_eqc_info;
+ /** called when a new equivalance class is created */
+ void eqNotifyNewClass(TNode t);
+ /** called when two equivalance classes will merge */
+ void eqNotifyPreMerge(TNode t1, TNode t2);
+ /** called when two equivalance classes have merged */
+ void eqNotifyPostMerge(TNode t1, TNode t2);
+ /** called when two equivalence classes are made disequal */
+ void eqNotifyDisequal(TNode t1, TNode t2, TNode reason);
+ /** are universal equal */
+ bool areUniversalEqual( TNode n1, TNode n2 );
+ /** are universal disequal */
+ bool areUniversalDisequal( TNode n1, TNode n2 );
+ /** get universal representative */
+ TNode getUniversalRepresentative( TNode n, bool add = false );
+ /** set relevant */
+ void setUniversalRelevant( TNode n );
+ /** ordering for universal terms */
+ bool isUniversalLessThan( TNode rt1, TNode rt2 );
+
+ /** the nodes we have reported as canonical representative */
+ std::vector< TNode > d_ue_canon;
+ /** is reported canon */
+ bool isReportedCanon( TNode n );
+ /** mark that term has been reported as canonical rep */
+ void markReportedCanon( TNode n );
+
+private: //information regarding the conjectures
+ /** list of all conjectures */
+ std::vector< Node > d_conjectures;
+ /** list of all waiting conjectures */
+ std::vector< Node > d_waiting_conjectures_lhs;
+ std::vector< Node > d_waiting_conjectures_rhs;
+ std::vector< int > d_waiting_conjectures_score;
+ /** map of currently considered equality conjectures */
+ std::map< Node, std::vector< Node > > d_waiting_conjectures;
+ /** map of equality conjectures */
+ std::map< Node, std::vector< Node > > d_eq_conjectures;
+ /** currently existing conjectures in equality engine */
+ BoolMap d_ee_conjectures;
+ /** conjecture index */
+ TheoremIndex d_thm_index;
+private: //free variable list
+ //free variables
+ std::map< TypeNode, std::vector< Node > > d_free_var;
+ //map from free variable to FV#
+ std::map< TNode, unsigned > d_free_var_num;
+ // get canonical free variable #i of type tn
+ Node getFreeVar( TypeNode tn, unsigned i );
+ // get canonical term, return null if it contains a term apart from handled signature
+ Node getCanonicalTerm( TNode n, std::map< TypeNode, unsigned >& var_count, std::map< TNode, TNode >& subs );
+private: //information regarding the terms
+ //relevant patterns (the LHS's)
+ std::map< TypeNode, std::vector< Node > > d_rel_patterns;
+ //total number of unique variables
+ std::map< TNode, unsigned > d_rel_pattern_var_sum;
+ //by types
+ PatternTypIndex d_rel_pattern_typ_index;
+ // substitution to ground EQC index
+ std::map< TNode, SubstitutionIndex > d_rel_pattern_subs_index;
+ //patterns (the RHS's)
+ std::map< TypeNode, std::vector< Node > > d_patterns;
+ //patterns to # variables per type
+ std::map< TNode, std::map< TypeNode, unsigned > > d_pattern_var_id;
+ // # duplicated variables
+ std::map< TNode, unsigned > d_pattern_var_duplicate;
+ // is normal pattern? (variables allocated in canonical way left to right)
+ std::map< TNode, int > d_pattern_is_normal;
+ std::map< TNode, int > d_pattern_is_relevant;
+ // patterns to a count of # operators (variables and functions)
+ std::map< TNode, std::map< TNode, unsigned > > d_pattern_fun_id;
+ // term size
+ std::map< TNode, unsigned > d_pattern_fun_sum;
+ // collect functions
+ unsigned collectFunctions( TNode opat, TNode pat, std::map< TNode, unsigned >& funcs,
+ std::map< TypeNode, unsigned >& mnvn, std::map< TypeNode, unsigned >& mxvn );
+ // add pattern
+ void registerPattern( Node pat, TypeNode tpat );
+private: //for debugging
+ std::map< TNode, unsigned > d_em;
+public:
+ //term generation environment
+ TermGenEnv d_tge;
+ //consider term canon
+ bool considerTermCanon( Node ln, bool genRelevant );
+public: //for generalization
+ //generalizations
+ bool isGeneralization( TNode patg, TNode pat ) {
+ std::map< TNode, TNode > subs;
+ return isGeneralization( patg, pat, subs );
+ }
+ bool isGeneralization( TNode patg, TNode pat, std::map< TNode, TNode >& subs );
+ // get generalization depth
+ int calculateGeneralizationDepth( TNode n, std::vector< TNode >& fv );
+private:
+ //ground term enumeration
+ std::map< TypeNode, std::vector< Node > > d_enum_terms;
+ //type enumerators
+ std::map< TypeNode, unsigned > d_typ_enum_map;
+ std::vector< TypeEnumerator > d_typ_enum;
+ //get nth term for type
+ Node getEnumerateTerm( TypeNode tn, unsigned index );
+ //predicate for type
+ std::map< TypeNode, Node > d_typ_pred;
+ //get predicate for type
+ Node getPredicateForType( TypeNode tn );
+ //
+ void getEnumerateUfTerm( Node n, unsigned num, std::vector< Node >& terms );
+ //
+ void getEnumeratePredUfTerm( Node n, unsigned num, std::vector< Node >& terms );
+ // uf operators enumerated
+ std::map< Node, bool > d_uf_enum;
+public: //for property enumeration
+ //process this candidate conjecture
+ void processCandidateConjecture( TNode lhs, TNode rhs, unsigned lhs_depth, unsigned rhs_depth );
+ //whether it should be considered, negative : no, positive returns score
+ int considerCandidateConjecture( TNode lhs, TNode rhs );
+ //notified of a substitution
+ bool notifySubstitution( TNode glhs, std::map< TNode, TNode >& subs, TNode rhs );
+ //confirmation count
+ unsigned d_subs_confirmCount;
+ //individual witnesses (for range)
+ std::vector< TNode > d_subs_confirmWitnessRange;
+ //individual witnesses (for domain)
+ std::map< TNode, std::vector< TNode > > d_subs_confirmWitnessDomain;
+ //number of ground substitutions whose equality is unknown
+ unsigned d_subs_unkCount;
+public: //for ground equivalence classes
+ eq::EqualityEngine * getEqualityEngine();
+ bool areDisequal( TNode n1, TNode n2 );
+ bool areEqual( TNode n1, TNode n2 );
+ TNode getRepresentative( TNode n );
+ TermDb * getTermDatabase();
+private: //information about ground equivalence classes
+ TNode d_bool_eqc[2];
+ std::map< TNode, Node > d_ground_eqc_map;
+ std::vector< TNode > d_ground_terms;
+ //operator independent term index
+ std::map< TNode, OpArgIndex > d_op_arg_index;
+ //is handled term
+ bool isHandledTerm( TNode n );
+ Node getGroundEqc( TNode r );
+ bool isGroundEqc( TNode r );
+ bool isGroundTerm( TNode n );
+ //has enumerated UF
+ bool hasEnumeratedUf( Node n );
+ // count of full effort checks
+ unsigned d_fullEffortCount;
+ // has added lemma
+ bool d_hasAddedLemma;
+ //flush the waiting conjectures
+ unsigned flushWaitingConjectures( unsigned& addedLemmas, int ldepth, int rdepth );
+public:
+ ConjectureGenerator( QuantifiersEngine * qe, context::Context* c );
+ /* needs check */
+ bool needsCheck( Theory::Effort e );
+ /* reset at a round */
+ void reset_round( Theory::Effort e );
+ /* Call during quantifier engine's check */
+ void check( Theory::Effort e, unsigned quant_e );
+ /* Called for new quantifiers */
+ void registerQuantifier( Node q );
+ void assertNode( Node n );
+ /** Identify this module (for debugging, dynamic configuration, etc..) */
+ std::string identify() const { return "ConjectureGenerator"; }
+//options
+private:
+ bool optReqDistinctVarPatterns();
+ bool optFilterUnknown();
+ int optFilterScoreThreshold();
+ unsigned optFullCheckFrequency();
+ unsigned optFullCheckConjectures();
+
+ bool optStatsOnly();
+};
+
+
+}
+}
+}
+
+#endif
diff --git a/src/theory/quantifiers/first_order_model.cpp b/src/theory/quantifiers/first_order_model.cpp index 1421c639f..0a0d4eba8 100644 --- a/src/theory/quantifiers/first_order_model.cpp +++ b/src/theory/quantifiers/first_order_model.cpp @@ -115,6 +115,24 @@ Node FirstOrderModel::getSomeDomainElement(TypeNode tn){ return d_rep_set.d_type_reps[tn][0]; } +void FirstOrderModel::reset_round() { + d_quant_active.clear(); +} + +void FirstOrderModel::setQuantifierActive( TNode q, bool active ) { + d_quant_active[q] = active; +} + +bool FirstOrderModel::isQuantifierActive( TNode q ) { + std::map< TNode, bool >::iterator it = d_quant_active.find( q ); + if( it==d_quant_active.end() ){ + return true; + }else{ + return it->second; + } +} + + FirstOrderModelIG::FirstOrderModelIG(QuantifiersEngine * qe, context::Context* c, std::string name) : FirstOrderModel(qe, c,name) { diff --git a/src/theory/quantifiers/first_order_model.h b/src/theory/quantifiers/first_order_model.h index 76c3946ce..6ad04a1e6 100644 --- a/src/theory/quantifiers/first_order_model.h +++ b/src/theory/quantifiers/first_order_model.h @@ -92,6 +92,19 @@ public: } /** get some domain element */ Node getSomeDomainElement(TypeNode tn); +private: + //list of inactive quantified formulas + std::map< TNode, bool > d_quant_active; +public: + /** reset round */ + void reset_round(); + /** set quantified formula active/inactive + * a quantified formula may be set inactive if for instance: + * - it is entailed by other quantified formulas + */ + void setQuantifierActive( TNode q, bool active ); + /** is quantified formula active */ + bool isQuantifierActive( TNode q ); };/* class FirstOrderModel */ diff --git a/src/theory/quantifiers/full_model_check.cpp b/src/theory/quantifiers/full_model_check.cpp index d5ed5589b..64ebb6cda 100644 --- a/src/theory/quantifiers/full_model_check.cpp +++ b/src/theory/quantifiers/full_model_check.cpp @@ -811,9 +811,11 @@ bool FullModelChecker::exhaustiveInstantiate(FirstOrderModelFmc * fm, Node f, No Trace("fmc-exh-debug") << std::endl; int index = riter.increment(); Trace("fmc-exh-debug") << "Incremented index " << index << std::endl; - if (index>=0 && riter.d_index[index]>0 && addedLemmas>0 && riter.d_enum_type[index]==RepSetIterator::ENUM_RANGE) { - Trace("fmc-exh-debug") << "Since this is a range enumeration, skip to the next..." << std::endl; - riter.increment2( index-1 ); + if( !riter.isFinished() ){ + if (index>=0 && riter.d_index[index]>0 && addedLemmas>0 && riter.d_enum_type[index]==RepSetIterator::ENUM_RANGE) { + Trace("fmc-exh-debug") << "Since this is a range enumeration, skip to the next..." << std::endl; + riter.increment2( index-1 ); + } } } d_addedLemmas += addedLemmas; @@ -871,7 +873,7 @@ void FullModelChecker::doCheck(FirstOrderModelFmc * fm, Node f, Def & d, Node n Trace("fmc-debug") << "Can't process base array " << r << std::endl; //can't process this array d.reset(); - d.addEntry(fm, defC, Node::null()); + d.addEntry(fm, mkCondDefault(fm, f), Node::null()); } } else if( n.getNumChildren()==0 ){ diff --git a/src/theory/quantifiers/inst_match_generator.cpp b/src/theory/quantifiers/inst_match_generator.cpp index c024d0bab..35809b536 100644 --- a/src/theory/quantifiers/inst_match_generator.cpp +++ b/src/theory/quantifiers/inst_match_generator.cpp @@ -30,14 +30,21 @@ namespace CVC4 { namespace theory { namespace inst { - -InstMatchGenerator::InstMatchGenerator( Node pat, int matchPolicy ) : d_matchPolicy( matchPolicy ){ +InstMatchGenerator::InstMatchGenerator( Node pat ){ d_needsReset = true; d_active_add = false; Assert( quantifiers::TermDb::hasInstConstAttr(pat) ); d_pattern = pat; d_match_pattern = pat; d_next = NULL; + d_matchPolicy = MATCH_GEN_DEFAULT; +} + +InstMatchGenerator::InstMatchGenerator() { + d_needsReset = true; + d_active_add = false; + d_next = NULL; + d_matchPolicy = MATCH_GEN_DEFAULT; } void InstMatchGenerator::setActiveAdd(bool val){ @@ -89,24 +96,31 @@ void InstMatchGenerator::initialize( QuantifiersEngine* qe, std::vector< InstMat d_match_pattern_op = qe->getTermDatabase()->getOperator( d_match_pattern ); //now, collect children of d_match_pattern - int childMatchPolicy = MATCH_GEN_DEFAULT; + //int childMatchPolicy = MATCH_GEN_DEFAULT; for( int i=0; i<(int)d_match_pattern.getNumChildren(); i++ ){ if( quantifiers::TermDb::hasInstConstAttr(d_match_pattern[i]) ){ - if( d_match_pattern[i].getKind()!=INST_CONSTANT && !Trigger::isBooleanTermTrigger( d_match_pattern[i] ) ){ - InstMatchGenerator * cimg = new InstMatchGenerator( d_match_pattern[i], childMatchPolicy ); + InstMatchGenerator * cimg = Trigger::getInstMatchGenerator( d_match_pattern[i] ); + if( cimg ){ d_children.push_back( cimg ); d_children_index.push_back( i ); gens.push_back( cimg ); + d_children_types.push_back( 1 ); + }else{ + d_var_num[i] = d_match_pattern[i].getAttribute(InstVarNumAttribute()); + d_children_types.push_back( 0 ); } + }else{ + d_children_types.push_back( -1 ); } } + if( d_match_pattern.getKind()==INST_CONSTANT ){ + d_var_num[0] = d_match_pattern.getAttribute(InstVarNumAttribute()); + } //create candidate generator if( d_match_pattern.getKind()==INST_CONSTANT ){ d_cg = new CandidateGeneratorQEAll( qe, d_match_pattern ); - } - else if( d_match_pattern.getKind()==EQUAL || d_match_pattern.getKind()==IFF ){ - Assert( d_matchPolicy==MATCH_GEN_DEFAULT ); + }else if( d_match_pattern.getKind()==EQUAL || d_match_pattern.getKind()==IFF ){ //we will be producing candidates via literal matching heuristics if( d_pattern.getKind()!=NOT ){ //candidates will be all equalities @@ -139,15 +153,6 @@ void InstMatchGenerator::initialize( QuantifiersEngine* qe, std::vector< InstMat Trace("inst-match-gen-warn") << "(?) Unknown matching pattern is " << d_match_pattern << std::endl; d_matchPolicy = MATCH_GEN_INTERNAL_ERROR; } - for( int i=0; i<(int)d_match_pattern.getNumChildren(); i++ ){ - if( d_match_pattern[i].getKind()==INST_CONSTANT || Trigger::isBooleanTermTrigger( d_match_pattern[i] ) ){ - Node vv = d_match_pattern[i]; - if( Trigger::isBooleanTermTrigger( d_match_pattern[i] ) ){ - vv = d_match_pattern[i][0]; - } - d_var_num[i] = vv.getAttribute(InstVarNumAttribute()); - } - } } } @@ -157,6 +162,7 @@ bool InstMatchGenerator::getMatch( Node f, Node t, InstMatch& m, QuantifiersEngi << m << ")" << ", " << d_children.size() << ", pattern is " << d_pattern << std::endl; Assert( !d_match_pattern.isNull() ); if( d_matchPolicy==MATCH_GEN_INTERNAL_ERROR ){ + Trace("matching-fail") << "Internal error for match generator." << std::endl; return false; }else{ EqualityQuery* q = qe->getEqualityQuery(); @@ -167,27 +173,23 @@ bool InstMatchGenerator::getMatch( Node f, Node t, InstMatch& m, QuantifiersEngi //if t is null Assert( !t.isNull() ); Assert( !quantifiers::TermDb::hasInstConstAttr(t) ); - Assert( t.getKind()==d_match_pattern.getKind() ); + Assert( d_match_pattern.getKind()==INST_CONSTANT || t.getKind()==d_match_pattern.getKind() ); Assert( !Trigger::isAtomicTrigger( d_match_pattern ) || t.getOperator()==d_match_pattern.getOperator() ); //first, check if ground arguments are not equal, or a match is in conflict for( int i=0; i<(int)d_match_pattern.getNumChildren(); i++ ){ - if( quantifiers::TermDb::hasInstConstAttr(d_match_pattern[i]) ){ - if( d_match_pattern[i].getKind()==INST_CONSTANT || Trigger::isBooleanTermTrigger( d_match_pattern[i] ) ){ - Node tt = t[i]; - if( Trigger::isBooleanTermTrigger( d_match_pattern[i] ) ){ - tt = NodeManager::currentNM()->mkConst(q->areEqual( tt, d_match_pattern[i][1] )); - } - bool addToPrev = m.get( d_var_num[i] ).isNull(); - if( !m.set( qe, d_var_num[i], tt ) ){ - //match is in conflict - Trace("matching-fail") << "Match fail: " << m.get(d_var_num[i]) << " and " << tt << std::endl; - success = false; - break; - }else if( addToPrev ){ - prev.push_back( d_var_num[i] ); - } + if( d_children_types[i]==0 ){ + Trace("matching-debug2") << "Setting " << d_var_num[i] << " to " << t[i] << "..." << std::endl; + bool addToPrev = m.get( d_var_num[i] ).isNull(); + if( !m.set( qe, d_var_num[i], t[i] ) ){ + //match is in conflict + Trace("matching-fail") << "Match fail: " << m.get(d_var_num[i]) << " and " << t[i] << std::endl; + success = false; + break; + }else if( addToPrev ){ + Trace("matching-debug2") << "Success." << std::endl; + prev.push_back( d_var_num[i] ); } - }else{ + }else if( d_children_types[i]==-1 ){ if( !q->areEqual( d_match_pattern[i], t[i] ) ){ Trace("matching-fail") << "Match fail arg: " << d_match_pattern[i] << " and " << t[i] << std::endl; //ground arguments are not equal @@ -196,8 +198,18 @@ bool InstMatchGenerator::getMatch( Node f, Node t, InstMatch& m, QuantifiersEngi } } } + //for variable matching + if( d_match_pattern.getKind()==INST_CONSTANT ){ + bool addToPrev = m.get( d_var_num[0] ).isNull(); + if( !m.set( qe, d_var_num[0], t ) ){ + success = false; + }else{ + if( addToPrev ){ + prev.push_back( d_var_num[0] ); + } + } //for relational matching - if( !d_eq_class.isNull() && d_eq_class.getKind()==INST_CONSTANT ){ + }else if( !d_eq_class.isNull() && d_eq_class.getKind()==INST_CONSTANT ){ int v = d_eq_class.getAttribute(InstVarNumAttribute()); //also must fit match to equivalence class bool pol = d_pattern.getKind()!=NOT; @@ -236,18 +248,9 @@ bool InstMatchGenerator::getMatch( Node f, Node t, InstMatch& m, QuantifiersEngi //now, fit children into match //we will be requesting candidates for matching terms for each child for( int i=0; i<(int)d_children.size(); i++ ){ - Node rep = q->getRepresentative( t[ d_children_index[i] ] ); - d_children[i]->reset( rep, qe ); - } - if( d_next!=NULL ){ - success = d_next->getNextMatch( f, m, qe ); - }else{ - if( d_active_add ){ - Trace("active-add") << "Active Adding instantiation " << m << std::endl; - success = qe->addInstantiation( f, m, false ); - Trace("active-add") << "Success = " << success << std::endl; - } + d_children[i]->reset( t[ d_children_index[i] ], qe ); } + success = continueNextMatch( f, m, qe ); } if( !success ){ //m = InstMatch( &prev ); @@ -259,6 +262,18 @@ bool InstMatchGenerator::getMatch( Node f, Node t, InstMatch& m, QuantifiersEngi } } +bool InstMatchGenerator::continueNextMatch( Node f, InstMatch& m, QuantifiersEngine* qe ){ + if( d_next!=NULL ){ + return d_next->getNextMatch( f, m, qe ); + }else{ + if( d_active_add ){ + return qe->addInstantiation( f, m, false ); + }else{ + return true; + } + } +} + /** reset instantiation round */ void InstMatchGenerator::resetInstantiationRound( QuantifiersEngine* qe ){ if( !d_match_pattern.isNull() ){ @@ -274,6 +289,7 @@ void InstMatchGenerator::resetInstantiationRound( QuantifiersEngine* qe ){ } void InstMatchGenerator::reset( Node eqc, QuantifiersEngine* qe ){ + eqc = qe->getEqualityQuery()->getRepresentative( eqc ); Trace("matching-debug2") << this << " reset " << eqc << "." << std::endl; if( !eqc.isNull() ){ d_eq_class = eqc; @@ -384,6 +400,59 @@ InstMatchGenerator* InstMatchGenerator::mkInstMatchGenerator( std::vector< Node return oinit; } +VarMatchGeneratorBooleanTerm::VarMatchGeneratorBooleanTerm( Node var, Node comp ) : + InstMatchGenerator(), d_comp( comp ), d_rm_prev( false ) { + d_var_num[0] = var.getAttribute(InstVarNumAttribute()); +} + +bool VarMatchGeneratorBooleanTerm::getNextMatch( Node f, InstMatch& m, QuantifiersEngine* qe ) { + if( !d_eq_class.isNull() ){ + Node s = NodeManager::currentNM()->mkConst(qe->getEqualityQuery()->areEqual( d_eq_class, d_pattern )); + d_eq_class = Node::null(); + d_rm_prev = m.get( d_var_num[0] ).isNull(); + if( !m.set( qe, d_var_num[0], s ) ){ + return false; + }else{ + if( continueNextMatch( f, m, qe ) ){ + return true; + } + } + } + if( d_rm_prev ){ + m.d_vals[d_var_num[0]] = Node::null(); + d_rm_prev = false; + } + return false; +} + +VarMatchGeneratorTermSubs::VarMatchGeneratorTermSubs( Node var, Node subs ) : + InstMatchGenerator(), d_var( var ), d_subs( subs ), d_rm_prev( false ){ + d_var_num[0] = d_var.getAttribute(InstVarNumAttribute()); +} + +bool VarMatchGeneratorTermSubs::getNextMatch( Node f, InstMatch& m, QuantifiersEngine* qe ) { + if( !d_eq_class.isNull() ){ + Trace("var-trigger-matching") << "Matching " << d_eq_class << " against " << d_var << " in " << d_subs << std::endl; + Node s = d_subs.substitute( d_var, d_eq_class ); + s = Rewriter::rewrite( s ); + Trace("var-trigger-matching") << "...got " << s << std::endl; + d_eq_class = Node::null(); + d_rm_prev = m.get( d_var_num[0] ).isNull(); + if( !m.set( qe, d_var_num[0], s ) ){ + return false; + }else{ + if( continueNextMatch( f, m, qe ) ){ + return true; + } + } + } + if( d_rm_prev ){ + m.d_vals[d_var_num[0]] = Node::null(); + d_rm_prev = false; + } + return false; +} + /** constructors */ InstMatchGeneratorMulti::InstMatchGeneratorMulti( Node f, std::vector< Node >& pats, QuantifiersEngine* qe, int matchOption ) : d_f( f ){ @@ -618,13 +687,7 @@ int InstMatchGeneratorSimple::addInstantiations( Node f, InstMatch& baseMatch, Q m.add( baseMatch ); int addedLemmas = 0; - if( d_match_pattern.getType()==NodeManager::currentNM()->booleanType() ){ - for( int i=0; i<2; i++ ){ - addInstantiations( m, qe, addedLemmas, 0, &(qe->getTermDatabase()->d_pred_map_trie[i][ d_op ]) ); - } - }else{ - addInstantiations( m, qe, addedLemmas, 0, &(qe->getTermDatabase()->d_func_map_trie[ d_op ]) ); - } + addInstantiations( m, qe, addedLemmas, 0, &(qe->getTermDatabase()->d_func_map_trie[ d_op ]) ); return addedLemmas; } @@ -646,7 +709,7 @@ void InstMatchGeneratorSimple::addInstantiations( InstMatch& m, QuantifiersEngin }else{ if( d_match_pattern[argIndex].getKind()==INST_CONSTANT ){ int v = d_var_num[argIndex]; - for( std::map< Node, quantifiers::TermArgTrie >::iterator it = tat->d_data.begin(); it != tat->d_data.end(); ++it ){ + for( std::map< TNode, quantifiers::TermArgTrie >::iterator it = tat->d_data.begin(); it != tat->d_data.end(); ++it ){ Node t = it->first; Node prev = m.get( v ); //using representatives, just check if equal @@ -658,7 +721,7 @@ void InstMatchGeneratorSimple::addInstantiations( InstMatch& m, QuantifiersEngin } }else{ Node r = qe->getEqualityQuery()->getRepresentative( d_match_pattern[argIndex] ); - std::map< Node, quantifiers::TermArgTrie >::iterator it = tat->d_data.find( r ); + std::map< TNode, quantifiers::TermArgTrie >::iterator it = tat->d_data.find( r ); if( it!=tat->d_data.end() ){ addInstantiations( m, qe, addedLemmas, argIndex+1, &(it->second) ); } diff --git a/src/theory/quantifiers/inst_match_generator.h b/src/theory/quantifiers/inst_match_generator.h index 56eaf2c17..aa5d37713 100644 --- a/src/theory/quantifiers/inst_match_generator.h +++ b/src/theory/quantifiers/inst_match_generator.h @@ -42,7 +42,7 @@ public: /** add instantiations directly */ virtual int addInstantiations( Node f, InstMatch& baseMatch, QuantifiersEngine* qe ) = 0; /** add ground term t, called when t is added to term db */ - virtual int addTerm( Node f, Node t, QuantifiersEngine* qe ) = 0; + virtual int addTerm( Node f, Node t, QuantifiersEngine* qe ) { return 0; } /** set active add */ virtual void setActiveAdd( bool val ) {} };/* class IMGenerator */ @@ -50,7 +50,7 @@ public: class CandidateGenerator; class InstMatchGenerator : public IMGenerator { -private: +protected: bool d_needsReset; /** candidate generator */ CandidateGenerator* d_cg; @@ -63,17 +63,18 @@ private: InstMatchGenerator* d_next; /** eq class */ Node d_eq_class; - /** for arithmetic matching */ - std::map< Node, Node > d_arith_coeffs; /** variable numbers */ std::map< int, int > d_var_num; /** initialize pattern */ void initialize( QuantifiersEngine* qe, std::vector< InstMatchGenerator * > & gens ); + /** children types 0 : variable, 1 : child term, -1 : ground term */ + std::vector< int > d_children_types; + /** continue */ + bool continueNextMatch( Node f, InstMatch& m, QuantifiersEngine* qe ); public: enum { //options for producing matches MATCH_GEN_DEFAULT = 0, - MATCH_GEN_EFFICIENT_E_MATCH, //generate matches via Efficient E-matching for SMT solvers //others (internally used) MATCH_GEN_INTERNAL_ERROR, }; @@ -85,7 +86,8 @@ public: bool getMatch( Node f, Node t, InstMatch& m, QuantifiersEngine* qe ); /** constructors */ - InstMatchGenerator( Node pat, int matchOption = 0 ); + InstMatchGenerator( Node pat ); + InstMatchGenerator(); /** destructor */ ~InstMatchGenerator(){} /** The pattern we are producing matches for. @@ -115,6 +117,39 @@ public: static InstMatchGenerator* mkInstMatchGenerator( std::vector< Node >& pats, QuantifiersEngine* qe ); };/* class InstMatchGenerator */ +//match generator for boolean term ITEs +class VarMatchGeneratorBooleanTerm : public InstMatchGenerator { +public: + VarMatchGeneratorBooleanTerm( Node var, Node comp ); + Node d_comp; + bool d_rm_prev; + /** reset instantiation round (call this at beginning of instantiation round) */ + void resetInstantiationRound( QuantifiersEngine* qe ){} + /** reset, eqc is the equivalence class to search in (any if eqc=null) */ + void reset( Node eqc, QuantifiersEngine* qe ){ d_eq_class = eqc; } + /** get the next match. must call reset( eqc ) before this function. */ + bool getNextMatch( Node f, InstMatch& m, QuantifiersEngine* qe ); + /** add instantiations directly */ + int addInstantiations( Node f, InstMatch& baseMatch, QuantifiersEngine* qe ){ return 0; } +}; + +//match generator for purified terms (matched term is substituted into d_subs) +class VarMatchGeneratorTermSubs : public InstMatchGenerator { +public: + VarMatchGeneratorTermSubs( Node var, Node subs ); + TNode d_var; + Node d_subs; + bool d_rm_prev; + /** reset instantiation round (call this at beginning of instantiation round) */ + void resetInstantiationRound( QuantifiersEngine* qe ){} + /** reset, eqc is the equivalence class to search in (any if eqc=null) */ + void reset( Node eqc, QuantifiersEngine* qe ){ d_eq_class = eqc; } + /** get the next match. must call reset( eqc ) before this function. */ + bool getNextMatch( Node f, InstMatch& m, QuantifiersEngine* qe ); + /** add instantiations directly */ + int addInstantiations( Node f, InstMatch& baseMatch, QuantifiersEngine* qe ) { return 0; } +}; + /** smart multi-trigger implementation */ class InstMatchGeneratorMulti : public IMGenerator { private: diff --git a/src/theory/quantifiers/inst_strategy_e_matching.cpp b/src/theory/quantifiers/inst_strategy_e_matching.cpp index 5b0fade71..a32e7f6b0 100644 --- a/src/theory/quantifiers/inst_strategy_e_matching.cpp +++ b/src/theory/quantifiers/inst_strategy_e_matching.cpp @@ -68,12 +68,12 @@ int InstStrategyUserPatterns::process( Node f, Theory::Effort effort, int e ){ for( int i=0; i<(int)d_user_gen[f].size(); i++ ){ bool processTrigger = true; if( processTrigger ){ - //if( d_user_gen[f][i]->isMultiTrigger() ) - Trace("process-trigger") << " Process (user) " << (*d_user_gen[f][i]) << "..." << std::endl; + Trace("process-trigger") << " Process (user) "; + d_user_gen[f][i]->debugPrint("process-trigger"); + Trace("process-trigger") << "..." << std::endl; InstMatch baseMatch( f ); int numInst = d_user_gen[f][i]->addInstantiations( baseMatch ); - //if( d_user_gen[f][i]->isMultiTrigger() ) - Trace("process-trigger") << " Done, numInst = " << numInst << "." << std::endl; + Trace("process-trigger") << " Done, numInst = " << numInst << "." << std::endl; d_quantEngine->getInstantiationEngine()->d_statistics.d_instantiations_user_patterns += numInst; if( d_user_gen[f][i]->isMultiTrigger() ){ d_quantEngine->d_statistics.d_multi_trigger_instantiations += numInst; @@ -88,18 +88,25 @@ int InstStrategyUserPatterns::process( Node f, Theory::Effort effort, int e ){ } void InstStrategyUserPatterns::addUserPattern( Node f, Node pat ){ + Assert( pat.getKind()==INST_PATTERN ); //add to generators + bool usable = true; std::vector< Node > nodes; for( int i=0; i<(int)pat.getNumChildren(); i++ ){ nodes.push_back( pat[i] ); + if( pat[i].getKind()!=INST_CONSTANT && !Trigger::isUsableTrigger( pat[i], f ) ){ + Trace("trigger-warn") << "User-provided trigger is not usable : " << pat << " because of " << pat[i] << std::endl; + usable = false; + break; + } } - if( Trigger::isUsableTrigger( nodes, f ) ){ + if( usable ){ + Trace("user-pat") << "Add user pattern: " << pat << " for " << f << std::endl; //extend to literal matching d_quantEngine->getPhaseReqTerms( f, nodes ); //check match option int matchOption = 0; - d_user_gen[f].push_back( Trigger::mkTrigger( d_quantEngine, f, nodes, matchOption, true, Trigger::TR_MAKE_NEW, - options::smartTriggers() ) ); + d_user_gen[f].push_back( Trigger::mkTrigger( d_quantEngine, f, nodes, matchOption, true, Trigger::TR_MAKE_NEW, options::smartTriggers() ) ); } } @@ -156,14 +163,12 @@ int InstStrategyAutoGenTriggers::process( Node f, Theory::Effort effort, int e ) bool processTrigger = itt->second; if( processTrigger && d_processed_trigger[f].find( tr )==d_processed_trigger[f].end() ){ d_processed_trigger[f][tr] = true; - //if( tr->isMultiTrigger() ) - Trace("process-trigger") << " Process "; - tr->debugPrint("process-trigger"); - Trace("process-trigger") << "..." << std::endl; + Trace("process-trigger") << " Process "; + tr->debugPrint("process-trigger"); + Trace("process-trigger") << "..." << std::endl; InstMatch baseMatch( f ); int numInst = tr->addInstantiations( baseMatch ); - //if( tr->isMultiTrigger() ) - Trace("process-trigger") << " Done, numInst = " << numInst << "." << std::endl; + Trace("process-trigger") << " Done, numInst = " << numInst << "." << std::endl; if( d_tr_strategy==Trigger::TS_MIN_TRIGGER ){ d_quantEngine->getInstantiationEngine()->d_statistics.d_instantiations_auto_gen_min += numInst; }else{ @@ -193,8 +198,8 @@ void InstStrategyAutoGenTriggers::generateTriggers( Node f, Theory::Effort effor d_patTerms[0][f].clear(); d_patTerms[1][f].clear(); std::vector< Node > patTermsF; - Trigger::collectPatTerms( d_quantEngine, f, d_quantEngine->getTermDatabase()->getInstConstantBody( f ), patTermsF, d_tr_strategy, true ); - Trace("auto-gen-trigger") << "Collected pat terms for " << d_quantEngine->getTermDatabase()->getInstConstantBody( f ) << std::endl; + Trigger::collectPatTerms( d_quantEngine, f, d_quantEngine->getTermDatabase()->getInstConstantBody( f ), patTermsF, d_tr_strategy, d_user_no_gen[f], true ); + Trace("auto-gen-trigger") << "Collected pat terms for " << d_quantEngine->getTermDatabase()->getInstConstantBody( f ) << ", no-patterns : " << d_user_no_gen.size() << std::endl; Trace("auto-gen-trigger") << " "; for( int i=0; i<(int)patTermsF.size(); i++ ){ Trace("auto-gen-trigger") << patTermsF[i] << " "; @@ -206,7 +211,7 @@ void InstStrategyAutoGenTriggers::generateTriggers( Node f, Theory::Effort effor std::map< Node, std::vector< Node > > varContains; d_quantEngine->getTermDatabase()->getVarContains( f, patTermsF, varContains ); for( std::map< Node, std::vector< Node > >::iterator it = varContains.begin(); it != varContains.end(); ++it ){ - if( it->second.size()==f[0].getNumChildren() ){ + if( it->second.size()==f[0].getNumChildren() && !Trigger::isPureTheoryTrigger( it->first ) ){ d_patTerms[0][f].push_back( it->first ); d_is_single_trigger[ it->first ] = true; }else{ @@ -342,6 +347,14 @@ void InstStrategyAutoGenTriggers::generateTriggers( Node f, Theory::Effort effor } } +void InstStrategyAutoGenTriggers::addUserNoPattern( Node f, Node pat ) { + Assert( pat.getKind()==INST_NO_PATTERN && pat.getNumChildren()==1 ); + if( std::find( d_user_no_gen[f].begin(), d_user_no_gen[f].end(), pat[0] )==d_user_no_gen[f].end() ){ + Trace("user-pat") << "Add user no-pattern: " << pat[0] << " for " << f << std::endl; + d_user_no_gen[f].push_back( pat[0] ); + } +} + void InstStrategyFreeVariable::processResetInstantiationRound( Theory::Effort effort ){ } diff --git a/src/theory/quantifiers/inst_strategy_e_matching.h b/src/theory/quantifiers/inst_strategy_e_matching.h index 968194e49..53ca5bf78 100644 --- a/src/theory/quantifiers/inst_strategy_e_matching.h +++ b/src/theory/quantifiers/inst_strategy_e_matching.h @@ -80,6 +80,8 @@ private: std::map< Node, bool > d_made_multi_trigger; //processed trigger this round std::map< Node, std::map< inst::Trigger*, bool > > d_processed_trigger; + //instantiation no patterns + std::map< Node, std::vector< Node > > d_user_no_gen; private: /** process functions */ void processResetInstantiationRound( Theory::Effort effort ); @@ -111,6 +113,8 @@ public: } /** set generate additional */ void setGenerateAdditional( bool val ) { d_generate_additional = val; } + /** add pattern */ + void addUserNoPattern( Node f, Node pat ); };/* class InstStrategyAutoGenTriggers */ class InstStrategyFreeVariable : public InstStrategy{ diff --git a/src/theory/quantifiers/instantiation_engine.cpp b/src/theory/quantifiers/instantiation_engine.cpp index 3dd4423de..7207ceefb 100644 --- a/src/theory/quantifiers/instantiation_engine.cpp +++ b/src/theory/quantifiers/instantiation_engine.cpp @@ -31,7 +31,7 @@ using namespace CVC4::theory::quantifiers; using namespace CVC4::theory::inst; InstantiationEngine::InstantiationEngine( QuantifiersEngine* qe, bool setIncomplete ) : -QuantifiersModule( qe ), d_isup(NULL), d_i_ag(NULL), d_setIncomplete( setIncomplete ), d_ierCounter( 0 ), d_performCheck( false ){ +QuantifiersModule( qe ), d_isup(NULL), d_i_ag(NULL), d_setIncomplete( setIncomplete ), d_ierCounter( 0 ){ } @@ -41,41 +41,45 @@ InstantiationEngine::~InstantiationEngine() { } void InstantiationEngine::finishInit(){ - //for UF terms if( !options::finiteModelFind() || options::fmfInstEngine() ){ - //if( options::cbqi() ){ - // addInstStrategy( new InstStrategyCheckCESolved( this, d_quantEngine ) ); - //} - //these are the instantiation strategies for basic E-matching + + //these are the instantiation strategies for E-matching + + //user-provided patterns if( options::userPatternsQuant()!=USER_PAT_MODE_IGNORE ){ d_isup = new InstStrategyUserPatterns( d_quantEngine ); addInstStrategy( d_isup ); }else{ d_isup = NULL; } - d_i_ag = new InstStrategyAutoGenTriggers( d_quantEngine, Trigger::TS_ALL, 3 ); + + //auto-generated patterns + int tstrt = Trigger::TS_ALL; + if( options::triggerSelMode()==TRIGGER_SEL_MIN ){ + tstrt = Trigger::TS_MIN_TRIGGER; + }else if( options::triggerSelMode()==TRIGGER_SEL_MAX ){ + tstrt = Trigger::TS_MAX_TRIGGER; + } + d_i_ag = new InstStrategyAutoGenTriggers( d_quantEngine, tstrt, 3 ); d_i_ag->setGenerateAdditional( true ); addInstStrategy( d_i_ag ); - //addInstStrategy( new InstStrategyAddFailSplits( this, ie ) ); + + //full saturation : instantiate from relevant domain, then arbitrary terms if( !options::finiteModelFind() && options::fullSaturateQuant() ){ addInstStrategy( new InstStrategyFreeVariable( d_quantEngine ) ); } - //d_isup->setPriorityOver( d_i_ag ); - //d_isup->setPriorityOver( i_agm ); - //i_ag->setPriorityOver( i_agm ); } - //for arithmetic + + //counterexample-based quantifier instantiation if( options::cbqi() ){ addInstStrategy( new InstStrategySimplex( (arith::TheoryArith*)d_quantEngine->getTheoryEngine()->theoryOf( THEORY_ARITH ), d_quantEngine ) ); - } - //for datatypes - //if( options::cbqi() ){ // addInstStrategy( new InstStrategyDatatypesValue( d_quantEngine ) ); - //} + } } bool InstantiationEngine::doInstantiationRound( Theory::Effort effort ){ + unsigned lastWaiting = d_quantEngine->d_lemmas_waiting.size(); //if counterexample-based quantifier instantiation is active if( options::cbqi() ){ //check if any cbqi lemma has not been added yet @@ -149,7 +153,7 @@ bool InstantiationEngine::doInstantiationRound( Theory::Effort effort ){ } } //do not consider another level if already added lemma at this level - if( d_quantEngine->hasAddedLemma() ){ + if( d_quantEngine->d_lemmas_waiting.size()>lastWaiting ){ d_inst_round_status = InstStrategy::STATUS_UNKNOWN; } e++; @@ -158,14 +162,11 @@ bool InstantiationEngine::doInstantiationRound( Theory::Effort effort ){ Debug("inst-engine") << (int)d_quantEngine->d_lemmas_waiting.size() << std::endl; //Notice() << "All instantiators finished, # added lemmas = " << (int)d_lemmas_waiting.size() << std::endl; if( !d_quantEngine->hasAddedLemma() ){ - Debug("inst-engine-stuck") << "No instantiations produced at this state." << std::endl; Debug("inst-engine-ctrl") << "---Fail." << std::endl; return false; }else{ - Debug("inst-engine-ctrl") << "---Done. " << (int)d_quantEngine->d_lemmas_waiting.size() << std::endl; - Trace("inst-engine") << "Added lemmas = " << (int)d_quantEngine->d_lemmas_waiting.size() << std::endl; - //flush lemmas to output channel - d_quantEngine->flushLemmas( &d_quantEngine->getOutputChannel() ); + Debug("inst-engine-ctrl") << "---Done. " << (int)(d_quantEngine->d_lemmas_waiting.size()-lastWaiting) << std::endl; + Trace("inst-engine") << "Added lemmas = " << (int)(d_quantEngine->d_lemmas_waiting.size()-lastWaiting) << std::endl; return true; } } @@ -175,17 +176,17 @@ bool InstantiationEngine::needsCheck( Theory::Effort e ){ d_ierCounter++; } //determine if we should perform check, based on instWhenMode - d_performCheck = false; + bool performCheck = false; if( options::instWhenMode()==INST_WHEN_FULL ){ - d_performCheck = ( e >= Theory::EFFORT_FULL ); + performCheck = ( e >= Theory::EFFORT_FULL ); }else if( options::instWhenMode()==INST_WHEN_FULL_DELAY ){ - d_performCheck = ( e >= Theory::EFFORT_FULL ) && !d_quantEngine->getTheoryEngine()->needCheck(); + performCheck = ( e >= Theory::EFFORT_FULL ) && !d_quantEngine->getTheoryEngine()->needCheck(); }else if( options::instWhenMode()==INST_WHEN_FULL_LAST_CALL ){ - d_performCheck = ( ( e==Theory::EFFORT_FULL && d_ierCounter%2==0 ) || e==Theory::EFFORT_LAST_CALL ); + performCheck = ( ( e==Theory::EFFORT_FULL && d_ierCounter%2==0 ) || e==Theory::EFFORT_LAST_CALL ); }else if( options::instWhenMode()==INST_WHEN_LAST_CALL ){ - d_performCheck = ( e >= Theory::EFFORT_LAST_CALL ); + performCheck = ( e >= Theory::EFFORT_LAST_CALL ); }else{ - d_performCheck = true; + performCheck = true; } static int ierCounter2 = 0; if( e==Theory::EFFORT_LAST_CALL ){ @@ -193,15 +194,14 @@ bool InstantiationEngine::needsCheck( Theory::Effort e ){ //with bounded integers, skip every other last call, // since matching loops may occur with infinite quantification if( ierCounter2%2==0 && options::fmfBoundInt() ){ - d_performCheck = false; + performCheck = false; } } - - return d_performCheck; + return performCheck; } -void InstantiationEngine::check( Theory::Effort e ){ - if( d_performCheck && !d_quantEngine->hasAddedLemma() ){ +void InstantiationEngine::check( Theory::Effort e, unsigned quant_e ){ + if( quant_e==QuantifiersEngine::QEFFORT_STANDARD ){ Debug("inst-engine") << "IE: Check " << e << " " << d_ierCounter << std::endl; double clSet = 0; if( Trace.isOn("inst-engine") ){ @@ -211,12 +211,15 @@ void InstantiationEngine::check( Theory::Effort e ){ ++(d_statistics.d_instantiation_rounds); bool quantActive = false; Debug("quantifiers") << "quantifiers: check: asserted quantifiers size=" - << d_quantEngine->getModel()->getNumAssertedQuantifiers() << std::endl; + << d_quantEngine->getModel()->getNumAssertedQuantifiers() << std::endl; for( int i=0; i<(int)d_quantEngine->getModel()->getNumAssertedQuantifiers(); i++ ){ Node n = d_quantEngine->getModel()->getAssertedQuantifier( i ); - //it is not active if we have found the skolemized negation is unsat + //it is not active if it corresponds to a rewrite rule: we will process in rewrite engine if( TermDb::isRewriteRule( n ) ){ d_quant_active[n] = false; + }else if( !d_quantEngine->getModel()->isQuantifierActive( n ) ){ + d_quant_active[n] = false; + //it is not active if we have found the skolemized negation is unsat }else if( options::cbqi() && hasAddedCbqiLemma( n ) ){ Node cel = d_quantEngine->getTermDatabase()->getCounterexampleLiteral( n ); bool active, value; @@ -248,7 +251,6 @@ void InstantiationEngine::check( Theory::Effort e ){ Debug("quantifiers") << ", ce is asserted"; } Debug("quantifiers") << std::endl; - //it is not active if it corresponds to a rewrite rule: we will process in rewrite engine }else{ d_quant_active[n] = true; if( !TermDb::hasInstConstAttr(n) ){ @@ -313,7 +315,11 @@ void InstantiationEngine::registerQuantifier( Node f ){ //add patterns for( int i=0; i<(int)subsPat.getNumChildren(); i++ ){ //Notice() << "Add pattern " << subsPat[i] << " for " << f << std::endl; - addUserPattern( f, subsPat[i] ); + if( subsPat[i].getKind()==INST_PATTERN ){ + addUserPattern( f, subsPat[i] ); + }else if( subsPat[i].getKind()==INST_NO_PATTERN ){ + addUserNoPattern( f, subsPat[i] ); + } } } } @@ -430,6 +436,12 @@ void InstantiationEngine::addUserPattern( Node f, Node pat ){ } } +void InstantiationEngine::addUserNoPattern( Node f, Node pat ){ + if( d_i_ag ){ + d_i_ag->addUserNoPattern( f, pat ); + } +} + InstantiationEngine::Statistics::Statistics(): d_instantiations_user_patterns("InstantiationEngine::Instantiations_User_Patterns", 0), d_instantiations_auto_gen("InstantiationEngine::Instantiations_Auto_Gen", 0), diff --git a/src/theory/quantifiers/instantiation_engine.h b/src/theory/quantifiers/instantiation_engine.h index 7a3528217..bf0bb03e1 100644 --- a/src/theory/quantifiers/instantiation_engine.h +++ b/src/theory/quantifiers/instantiation_engine.h @@ -99,7 +99,6 @@ private: bool d_setIncomplete; /** inst round counter */ int d_ierCounter; - bool d_performCheck; /** whether each quantifier is active */ std::map< Node, bool > d_quant_active; /** whether we have added cbqi lemma */ @@ -131,13 +130,14 @@ public: void finishInit(); bool needsCheck( Theory::Effort e ); - void check( Theory::Effort e ); + void check( Theory::Effort e, unsigned quant_e ); void registerQuantifier( Node f ); void assertNode( Node f ); Node explain(TNode n){ return Node::null(); } Node getNextDecisionRequest(); /** add user pattern */ void addUserPattern( Node f, Node pat ); + void addUserNoPattern( Node f, Node pat ); public: /** statistics class */ class Statistics { diff --git a/src/theory/quantifiers/kinds b/src/theory/quantifiers/kinds index 6fb480c3d..1fda30301 100644 --- a/src/theory/quantifiers/kinds +++ b/src/theory/quantifiers/kinds @@ -33,6 +33,7 @@ sort INST_PATTERN_TYPE \ # This node is used for specifying hints for quantifier instantiation. # An instantiation pattern may have more than 1 child, in which case it specifies a multi-trigger. operator INST_PATTERN 1: "instantiation pattern" +operator INST_NO_PATTERN 1 "instantiation no-pattern" sort INST_PATTERN_LIST_TYPE \ Cardinality::INTEGERS \ @@ -46,6 +47,7 @@ typerule FORALL ::CVC4::theory::quantifiers::QuantifierForallTypeRule typerule EXISTS ::CVC4::theory::quantifiers::QuantifierExistsTypeRule typerule BOUND_VAR_LIST ::CVC4::theory::quantifiers::QuantifierBoundVarListTypeRule typerule INST_PATTERN ::CVC4::theory::quantifiers::QuantifierInstPatternTypeRule +typerule INST_NO_PATTERN ::CVC4::theory::quantifiers::QuantifierInstNoPatternTypeRule typerule INST_PATTERN_LIST ::CVC4::theory::quantifiers::QuantifierInstPatternListTypeRule # for rewrite rules diff --git a/src/theory/quantifiers/macros.cpp b/src/theory/quantifiers/macros.cpp index 11734c43f..7321e22b4 100644 --- a/src/theory/quantifiers/macros.cpp +++ b/src/theory/quantifiers/macros.cpp @@ -98,10 +98,14 @@ bool QuantifierMacros::isMacroLiteral( Node n, bool pol ){ bool QuantifierMacros::isBoundVarApplyUf( Node n ) { Assert( n.getKind()==APPLY_UF ); + TypeNode tn = n.getOperator().getType(); for( unsigned i=0; i<n.getNumChildren(); i++ ){ if( n[i].getKind()!=BOUND_VARIABLE ){ return false; } + if( n[i].getType()!=tn[i] ){ + return false; + } for( unsigned j=0; j<i; j++ ){ if( n[j]==n[i] ){ return false; diff --git a/src/theory/quantifiers/model_engine.cpp b/src/theory/quantifiers/model_engine.cpp index d68c66535..9e5a8997b 100644 --- a/src/theory/quantifiers/model_engine.cpp +++ b/src/theory/quantifiers/model_engine.cpp @@ -35,7 +35,12 @@ using namespace CVC4::theory::inst; //Model Engine constructor ModelEngine::ModelEngine( context::Context* c, QuantifiersEngine* qe ) : -QuantifiersModule( qe ){ +QuantifiersModule( qe ), +d_incomplete_check(false), +d_addedLemmas(0), +d_triedLemmas(0), +d_totalLemmas(0) +{ Trace("model-engine-debug") << "Initialize model engine, mbqi : " << options::mbqiMode() << " " << options::fmfBoundInt() << std::endl; if( options::mbqiMode()==MBQI_FMC || options::mbqiMode()==quantifiers::MBQI_FMC_INTERVAL || @@ -61,8 +66,12 @@ ModelEngine::~ModelEngine() { delete d_builder; } -void ModelEngine::check( Theory::Effort e ){ - if( e==Theory::EFFORT_LAST_CALL && !d_quantEngine->hasAddedLemma() ){ +bool ModelEngine::needsCheck( Theory::Effort e ) { + return e==Theory::EFFORT_LAST_CALL; +} + +void ModelEngine::check( Theory::Effort e, unsigned quant_e ){ + if( quant_e==QuantifiersEngine::QEFFORT_MODEL ){ int addedLemmas = 0; bool needsBuild = true; FirstOrderModel* fm = d_quantEngine->getModel(); @@ -94,7 +103,8 @@ void ModelEngine::check( Theory::Effort e ){ Trace("model-engine-debug") << "Verify uf ss is minimal..." << std::endl; //let the strong solver verify that the model is minimal //for debugging, this will if there are terms in the model that the strong solver was not notified of - if( ((uf::TheoryUF*)d_quantEngine->getTheoryEngine()->theoryOf( THEORY_UF ))->getStrongSolver()->debugModel( fm ) ){ + uf::StrongSolverTheoryUF * ufss = ((uf::TheoryUF*)d_quantEngine->getTheoryEngine()->theoryOf( THEORY_UF ))->getStrongSolver(); + if( !ufss || ufss->debugModel( fm ) ){ Trace("model-engine-debug") << "Check model..." << std::endl; d_incomplete_check = false; //print debug @@ -140,7 +150,6 @@ void ModelEngine::check( Theory::Effort e ){ } }else{ //otherwise, the search will continue - d_quantEngine->flushLemmas( &d_quantEngine->getOutputChannel() ); } } } diff --git a/src/theory/quantifiers/model_engine.h b/src/theory/quantifiers/model_engine.h index caf27f691..890af1643 100644 --- a/src/theory/quantifiers/model_engine.h +++ b/src/theory/quantifiers/model_engine.h @@ -52,7 +52,8 @@ public: //get the builder QModelBuilder* getModelBuilder() { return d_builder; } public: - void check( Theory::Effort e ); + bool needsCheck( Theory::Effort e ); + void check( Theory::Effort e, unsigned quant_e ); void registerQuantifier( Node f ); void assertNode( Node f ); Node explain(TNode n){ return Node::null(); } diff --git a/src/theory/quantifiers/modes.h b/src/theory/quantifiers/modes.h index 112e052c2..26978c8f9 100644 --- a/src/theory/quantifiers/modes.h +++ b/src/theory/quantifiers/modes.h @@ -107,6 +107,15 @@ typedef enum { USER_PAT_MODE_IGNORE, } UserPatMode; +typedef enum { + /** default for trigger selection */ + TRIGGER_SEL_DEFAULT, + /** only consider minimal terms for triggers */ + TRIGGER_SEL_MIN, + /** only consider maximal terms for triggers */ + TRIGGER_SEL_MAX, +} TriggerSelMode; + }/* CVC4::theory::quantifiers namespace */ }/* CVC4::theory namespace */ diff --git a/src/theory/quantifiers/options b/src/theory/quantifiers/options index 1cdf5e8bd..162bbc158 100644 --- a/src/theory/quantifiers/options +++ b/src/theory/quantifiers/options @@ -26,6 +26,8 @@ option prenexQuant /--disable-prenex-quant bool :default true # forall y. P( c, y ) option varElimQuant /--disable-var-elim-quant bool :default true disable simple variable elimination for quantified formulas +option dtVarExpandQuant --dt-var-exp-quant bool :default true + expand datatype variables bound to one constructor in quantifiers option simpleIteLiftQuant /--disable-ite-lift-quant bool :default true disable simple ite lifting for quantified formulas @@ -63,6 +65,10 @@ option relevantTriggers --relevant-triggers bool :default false prefer triggers that are more relevant based on SInE style analysis option relationalTriggers --relational-triggers bool :default false choose relational triggers such as x = f(y), x >= f(y) +option purifyTriggers --purify-triggers bool :default false :read-write + purify triggers, e.g. f( x+1 ) becomes f( y ), x mapsto y-1 +option triggerSelMode --trigger-sel CVC4::theory::quantifiers::TriggerSelMode :default CVC4::theory::quantifiers::TRIGGER_SEL_DEFAULT :read-write :include "theory/quantifiers/modes.h" :handler CVC4::theory::quantifiers::stringToTriggerSelMode :handler-include "theory/quantifiers/options_handlers.h" + selection mode for triggers # Whether to consider terms in the bodies of quantifiers for matching option registerQuantBodyTerms --register-quant-body-terms bool :default false @@ -72,10 +78,15 @@ option instWhenMode --inst-when=MODE CVC4::theory::quantifiers::InstWhenMode :de when to apply instantiation option instMaxLevel --inst-max-level=N int :default -1 maximum inst level of terms used to instantiate quantified formulas with (-1 == no limit, default) +option instLevelInputOnly --inst-level-input-only bool :default true + only input terms are assigned instantiation level zero option eagerInstQuant --eager-inst-quant bool :default false apply quantifier instantiation eagerly +option instNoEntail --inst-no-entail bool :read-write :default false + do not consider instances of quantified formulas that are currently entailed + option fullSaturateQuant --full-saturate-quant bool :default false when all other quantifier instantiation strategies fail, instantiate with ground terms from relevant domain, then arbitrary ground terms before answering unknown @@ -139,7 +150,27 @@ option quantRewriteRules --rewrite-rules bool :default true option rrOneInstPerRound --rr-one-inst-per-round bool :default false add one instance of rewrite rule per round -option dtStcInduction --dt-stc-ind bool :default false +option quantInduction --quant-ind bool :default false + use all available techniques for inductive reasoning +option dtStcInduction --dt-stc-ind bool :read-write :default false apply strengthening for existential quantification over datatypes based on structural induction - +option intWfInduction --int-wf-ind bool :read-write :default false + apply strengthening for integers based on well-founded induction +option conjectureGen --conjecture-gen bool :read-write :default false + generate candidate conjectures for inductive proofs + +option conjectureGenPerRound --conjecture-gen-per-round=N int :default 1 + number of conjectures to generate per instantiation round +option conjectureNoFilter --conjecture-no-filter bool :default false + do not filter conjectures +option conjectureFilterActiveTerms --conjecture-filter-active-terms bool :read-write :default true + filter based on active terms +option conjectureFilterCanonical --conjecture-filter-canonical bool :read-write :default true + filter based on canonicity +option conjectureFilterModel --conjecture-filter-model bool :read-write :default true + filter based on model +option conjectureGenGtEnum --conjecture-gen-gt-enum=N int :default 0 + number of ground terms to generate for model filtering +option conjectureUeeIntro --conjecture-gen-uee-intro bool :default false + more aggressive merging for universal equality engine, introduces terms endmodule diff --git a/src/theory/quantifiers/options_handlers.h b/src/theory/quantifiers/options_handlers.h index 38567d166..97eaf4aaa 100644 --- a/src/theory/quantifiers/options_handlers.h +++ b/src/theory/quantifiers/options_handlers.h @@ -152,6 +152,19 @@ ignore \n\ + Ignore user-provided patterns. \n\ \n\ "; +static const std::string triggerSelModeHelp = "\ +Trigger selection modes currently supported by the --trigger-sel option:\n\ +\n\ +default \n\ ++ Default, consider all subterms of quantified formulas for trigger selection.\n\ +\n\ +min \n\ ++ Consider only minimal subterms that meet criteria for triggers.\n\ +\n\ +max \n\ ++ Consider only maximal subterms that meet criteria for triggers. \n\ +\n\ +"; inline InstWhenMode stringToInstWhenMode(std::string option, std::string optarg, SmtEngine* smt) throw(OptionException) { if(optarg == "pre-full") { return INST_WHEN_PRE_FULL; @@ -296,6 +309,21 @@ inline UserPatMode stringToUserPatMode(std::string option, std::string optarg, S optarg + "'. Try --user-pat help."); } } +inline TriggerSelMode stringToTriggerSelMode(std::string option, std::string optarg, SmtEngine* smt) throw(OptionException) { + if(optarg == "default" || optarg == "all" ) { + return TRIGGER_SEL_DEFAULT; + } else if(optarg == "min") { + return TRIGGER_SEL_MIN; + } else if(optarg == "max") { + return TRIGGER_SEL_MAX; + } else if(optarg == "help") { + puts(triggerSelModeHelp.c_str()); + exit(1); + } else { + throw OptionException(std::string("unknown option for --trigger-sel: `") + + optarg + "'. Try --trigger-sel help."); + } +} }/* CVC4::theory::quantifiers namespace */ }/* CVC4::theory namespace */ }/* CVC4 namespace */ diff --git a/src/theory/quantifiers/quant_conflict_find.cpp b/src/theory/quantifiers/quant_conflict_find.cpp index c6e881986..ee4464f87 100644..100755 --- a/src/theory/quantifiers/quant_conflict_find.cpp +++ b/src/theory/quantifiers/quant_conflict_find.cpp @@ -1,2529 +1,2246 @@ -/********************* */ -/*! \file quant_conflict_find.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-2014 New York University and The University of Iowa - ** See the file COPYING in the top-level source directory for licensing - ** information.\endverbatim - ** - ** \brief quant conflict find class - ** - **/ - -#include <vector> - -#include "theory/quantifiers/quant_conflict_find.h" -#include "theory/quantifiers/quant_util.h" -#include "theory/theory_engine.h" -#include "theory/quantifiers/options.h" -#include "theory/quantifiers/term_database.h" -#include "theory/quantifiers/trigger.h" - -using namespace CVC4; -using namespace CVC4::kind; -using namespace CVC4::theory; -using namespace CVC4::theory::quantifiers; -using namespace std; - -namespace CVC4 { - -Node QcfNodeIndex::existsTerm( TNode n, std::vector< TNode >& reps, int index ) { - if( index==(int)reps.size() ){ - if( d_children.empty() ){ - return Node::null(); - }else{ - return d_children.begin()->first; - } - }else{ - std::map< TNode, QcfNodeIndex >::iterator it = d_children.find( reps[index] ); - if( it==d_children.end() ){ - return Node::null(); - }else{ - return it->second.existsTerm( n, reps, index+1 ); - } - } -} - -Node QcfNodeIndex::addTerm( TNode n, std::vector< TNode >& reps, int index ) { - if( index==(int)reps.size() ){ - if( d_children.empty() ){ - d_children[ n ].clear(); - return n; - }else{ - return d_children.begin()->first; - } - }else{ - return d_children[reps[index]].addTerm( n, reps, index+1 ); - } -} - - -void QcfNodeIndex::debugPrint( const char * c, int t ) { - for( std::map< TNode, QcfNodeIndex >::iterator it = d_children.begin(); it != d_children.end(); ++it ){ - if( !it->first.isNull() ){ - for( int j=0; j<t; j++ ){ Trace(c) << " "; } - Trace(c) << it->first << " : " << std::endl; - it->second.debugPrint( c, t+1 ); - } - } -} - - -void QuantInfo::initialize( Node q, Node qn ) { - d_q = q; - for( unsigned i=0; i<q[0].getNumChildren(); i++ ){ - d_match.push_back( TNode::null() ); - d_match_term.push_back( TNode::null() ); - } - - //register the variables - for( unsigned i=0; i<q[0].getNumChildren(); i++ ){ - d_var_num[q[0][i]] = i; - d_vars.push_back( q[0][i] ); - } - - registerNode( qn, true, true ); - - - Trace("qcf-qregister") << "- Make match gen structure..." << std::endl; - d_mg = new MatchGen( this, qn ); - - if( d_mg->isValid() ){ - /* - for( unsigned j=0; j<q[0].getNumChildren(); j++ ){ - if( d_inMatchConstraint.find( q[0][j] )==d_inMatchConstraint.end() ){ - Trace("qcf-invalid") << "QCF invalid : variable " << q[0][j] << " does not exist in a matching constraint." << std::endl; - d_mg->setInvalid(); - break; - } - } - */ - if( d_mg->isValid() ){ - for( unsigned j=q[0].getNumChildren(); j<d_vars.size(); j++ ){ - if( d_vars[j].getKind()!=BOUND_VARIABLE ){ - d_var_mg[j] = NULL; - bool is_tsym = false; - if( !MatchGen::isHandledUfTerm( d_vars[j] ) && d_vars[j].getKind()!=ITE ){ - is_tsym = true; - d_tsym_vars.push_back( j ); - } - if( !is_tsym || options::qcfTConstraint() ){ - d_var_mg[j] = new MatchGen( this, d_vars[j], true ); - } - if( !d_var_mg[j] || !d_var_mg[j]->isValid() ){ - Trace("qcf-invalid") << "QCF invalid : cannot match for " << d_vars[j] << std::endl; - d_mg->setInvalid(); - break; - }else{ - std::vector< int > bvars; - d_var_mg[j]->determineVariableOrder( this, bvars ); - } - } - } - if( d_mg->isValid() ){ - std::vector< int > bvars; - d_mg->determineVariableOrder( this, bvars ); - } - } - }else{ - Trace("qcf-invalid") << "QCF invalid : body of formula cannot be processed." << std::endl; - } - Trace("qcf-qregister-summary") << "QCF register : " << ( d_mg->isValid() ? "VALID " : "INVALID" ) << " : " << q << std::endl; -} - -void QuantInfo::registerNode( Node n, bool hasPol, bool pol, bool beneathQuant ) { - Trace("qcf-qregister-debug2") << "Register : " << n << std::endl; - if( n.getKind()==FORALL ){ - registerNode( n[1], hasPol, pol, true ); - }else{ - if( !MatchGen::isHandledBoolConnective( n ) ){ - if( n.hasBoundVar() ){ - //literals - if( n.getKind()==EQUAL ){ - for( unsigned i=0; i<n.getNumChildren(); i++ ){ - flatten( n[i], beneathQuant ); - } - }else if( MatchGen::isHandledUfTerm( n ) ){ - flatten( n, beneathQuant ); - }else if( n.getKind()==ITE ){ - for( unsigned i=1; i<=2; i++ ){ - flatten( n[i], beneathQuant ); - } - registerNode( n[0], false, pol, beneathQuant ); - }else if( options::qcfTConstraint() ){ - //a theory-specific predicate - for( unsigned i=0; i<n.getNumChildren(); i++ ){ - flatten( n[i], beneathQuant ); - } - } - } - }else{ - for( unsigned i=0; i<n.getNumChildren(); i++ ){ - bool newHasPol; - bool newPol; - QuantPhaseReq::getPolarity( n, i, hasPol, pol, newHasPol, newPol ); - //QcfNode * qcfc = new QcfNode( d_c ); - //qcfc->d_parent = qcf; - //qcf->d_child[i] = qcfc; - registerNode( n[i], newHasPol, newPol, beneathQuant ); - } - } - } -} - -void QuantInfo::flatten( Node n, bool beneathQuant ) { - Trace("qcf-qregister-debug2") << "Flatten : " << n << std::endl; - if( n.hasBoundVar() ){ - if( n.getKind()==BOUND_VARIABLE ){ - d_inMatchConstraint[n] = true; - } - //if( MatchGen::isHandledUfTerm( n ) || n.getKind()==ITE ){ - if( d_var_num.find( n )==d_var_num.end() ){ - Trace("qcf-qregister-debug2") << "Add FLATTEN VAR : " << n << std::endl; - d_var_num[n] = d_vars.size(); - d_vars.push_back( n ); - d_match.push_back( TNode::null() ); - d_match_term.push_back( TNode::null() ); - if( n.getKind()==ITE ){ - registerNode( n, false, false ); - }else{ - for( unsigned i=0; i<n.getNumChildren(); i++ ){ - flatten( n[i], beneathQuant ); - } - } - }else{ - Trace("qcf-qregister-debug2") << "...already processed" << std::endl; - } - }else{ - Trace("qcf-qregister-debug2") << "...is ground." << std::endl; - } -} - - -void QuantInfo::reset_round( QuantConflictFind * p ) { - for( unsigned i=0; i<d_match.size(); i++ ){ - d_match[i] = TNode::null(); - d_match_term[i] = TNode::null(); - } - d_curr_var_deq.clear(); - d_tconstraints.clear(); - //add built-in variable constraints - for( unsigned r=0; r<2; r++ ){ - for( std::map< int, std::vector< Node > >::iterator it = d_var_constraint[r].begin(); - it != d_var_constraint[r].end(); ++it ){ - for( unsigned j=0; j<it->second.size(); j++ ){ - Node rr = it->second[j]; - if( !isVar( rr ) ){ - rr = p->getRepresentative( rr ); - } - if( addConstraint( p, it->first, rr, r==0 )==-1 ){ - d_var_constraint[0].clear(); - d_var_constraint[1].clear(); - //quantified formula is actually equivalent to true - Trace("qcf-qregister") << "Quantifier is equivalent to true!!!" << std::endl; - d_mg->d_children.clear(); - d_mg->d_n = NodeManager::currentNM()->mkConst( true ); - d_mg->d_type = MatchGen::typ_ground; - return; - } - } - } - } - d_mg->reset_round( p ); - for( std::map< int, MatchGen * >::iterator it = d_var_mg.begin(); it != d_var_mg.end(); ++it ){ - it->second->reset_round( p ); - } - //now, reset for matching - d_mg->reset( p, false, this ); -} - -int QuantInfo::getCurrentRepVar( int v ) { - if( v!=-1 && !d_match[v].isNull() ){ - int vn = getVarNum( d_match[v] ); - if( vn!=-1 ){ - //int vr = getCurrentRepVar( vn ); - //d_match[v] = d_vars[vr]; - //return vr; - return getCurrentRepVar( vn ); - } - } - return v; -} - -TNode QuantInfo::getCurrentValue( TNode n ) { - int v = getVarNum( n ); - if( v==-1 ){ - return n; - }else{ - if( d_match[v].isNull() ){ - return n; - }else{ - Assert( getVarNum( d_match[v] )!=v ); - return getCurrentValue( d_match[v] ); - } - } -} - -TNode QuantInfo::getCurrentExpValue( TNode n ) { - int v = getVarNum( n ); - if( v==-1 ){ - return n; - }else{ - if( d_match[v].isNull() ){ - return n; - }else{ - Assert( getVarNum( d_match[v] )!=v ); - if( d_match_term[v].isNull() ){ - return getCurrentValue( d_match[v] ); - }else{ - return d_match_term[v]; - } - } - } -} - -bool QuantInfo::getCurrentCanBeEqual( QuantConflictFind * p, int v, TNode n, bool chDiseq ) { - //check disequalities - std::map< int, std::map< TNode, int > >::iterator itd = d_curr_var_deq.find( v ); - if( itd!=d_curr_var_deq.end() ){ - for( std::map< TNode, int >::iterator it = itd->second.begin(); it != itd->second.end(); ++it ){ - Node cv = getCurrentValue( it->first ); - Debug("qcf-ccbe") << "compare " << cv << " " << n << std::endl; - if( cv==n ){ - return false; - }else if( chDiseq && !isVar( n ) && !isVar( cv ) ){ - //they must actually be disequal if we are looking for conflicts - if( !p->areDisequal( n, cv ) ){ - //TODO : check for entailed disequal - - return false; - } - } - } - } - return true; -} - -int QuantInfo::addConstraint( QuantConflictFind * p, int v, TNode n, bool polarity ) { - v = getCurrentRepVar( v ); - int vn = getVarNum( n ); - vn = vn==-1 ? -1 : getCurrentRepVar( vn ); - n = getCurrentValue( n ); - return addConstraint( p, v, n, vn, polarity, false ); -} - -int QuantInfo::addConstraint( QuantConflictFind * p, int v, TNode n, int vn, bool polarity, bool doRemove ) { - //for handling equalities between variables, and disequalities involving variables - Debug("qcf-match-debug") << "- " << (doRemove ? "un" : "" ) << "constrain : " << v << " -> " << n << " (cv=" << getCurrentValue( n ) << ")"; - Debug("qcf-match-debug") << ", (vn=" << vn << "), polarity = " << polarity << std::endl; - Assert( doRemove || n==getCurrentValue( n ) ); - Assert( doRemove || v==getCurrentRepVar( v ) ); - Assert( doRemove || vn==getCurrentRepVar( getVarNum( n ) ) ); - if( polarity ){ - if( vn!=v ){ - if( doRemove ){ - if( vn!=-1 ){ - //if set to this in the opposite direction, clean up opposite instead - // std::map< int, TNode >::iterator itmn = d_match.find( vn ); - if( d_match[vn]==d_vars[v] ){ - return addConstraint( p, vn, d_vars[v], v, true, true ); - }else{ - //unsetting variables equal - std::map< int, std::map< TNode, int > >::iterator itd = d_curr_var_deq.find( vn ); - if( itd!=d_curr_var_deq.end() ){ - //remove disequalities owned by this - std::vector< TNode > remDeq; - for( std::map< TNode, int >::iterator it = itd->second.begin(); it != itd->second.end(); ++it ){ - if( it->second==v ){ - remDeq.push_back( it->first ); - } - } - for( unsigned i=0; i<remDeq.size(); i++ ){ - d_curr_var_deq[vn].erase( remDeq[i] ); - } - } - } - } - d_match[v] = TNode::null(); - return 1; - }else{ - //std::map< int, TNode >::iterator itm = d_match.find( v ); - - if( vn!=-1 ){ - Debug("qcf-match-debug") << " ...Variable bound to variable" << std::endl; - //std::map< int, TNode >::iterator itmn = d_match.find( vn ); - if( d_match[v].isNull() ){ - //setting variables equal - bool alreadySet = false; - if( !d_match[vn].isNull() ){ - alreadySet = true; - Assert( !isVar( d_match[vn] ) ); - } - - //copy or check disequalities - std::map< int, std::map< TNode, int > >::iterator itd = d_curr_var_deq.find( v ); - if( itd!=d_curr_var_deq.end() ){ - for( std::map< TNode, int >::iterator it = itd->second.begin(); it != itd->second.end(); ++it ){ - Node dv = getCurrentValue( it->first ); - if( !alreadySet ){ - if( d_curr_var_deq[vn].find( dv )==d_curr_var_deq[vn].end() ){ - d_curr_var_deq[vn][dv] = v; - } - }else{ - if( !p->areMatchDisequal( d_match[vn], dv ) ){ - Debug("qcf-match-debug") << " -> fail, conflicting disequality" << std::endl; - return -1; - } - } - } - } - if( alreadySet ){ - n = getCurrentValue( n ); - } - }else{ - if( d_match[vn].isNull() ){ - Debug("qcf-match-debug") << " ...Reverse direction" << std::endl; - //set the opposite direction - return addConstraint( p, vn, d_vars[v], v, true, false ); - }else{ - Debug("qcf-match-debug") << " -> Both variables bound, compare" << std::endl; - //are they currently equal - return p->areMatchEqual( d_match[v], d_match[vn] ) ? 0 : -1; - } - } - }else{ - Debug("qcf-match-debug") << " ...Variable bound to ground" << std::endl; - if( d_match[v].isNull() ){ - }else{ - //compare ground values - Debug("qcf-match-debug") << " -> Ground value, compare " << d_match[v] << " "<< n << std::endl; - return p->areMatchEqual( d_match[v], n ) ? 0 : -1; - } - } - if( setMatch( p, v, n ) ){ - Debug("qcf-match-debug") << " -> success" << std::endl; - return 1; - }else{ - Debug("qcf-match-debug") << " -> fail, conflicting disequality" << std::endl; - return -1; - } - } - }else{ - Debug("qcf-match-debug") << " -> redundant, variable identity" << std::endl; - return 0; - } - }else{ - if( vn==v ){ - Debug("qcf-match-debug") << " -> fail, variable identity" << std::endl; - return -1; - }else{ - if( doRemove ){ - Assert( d_curr_var_deq[v].find( n )!=d_curr_var_deq[v].end() ); - d_curr_var_deq[v].erase( n ); - return 1; - }else{ - if( d_curr_var_deq[v].find( n )==d_curr_var_deq[v].end() ){ - //check if it respects equality - //std::map< int, TNode >::iterator itm = d_match.find( v ); - if( !d_match[v].isNull() ){ - TNode nv = getCurrentValue( n ); - if( !p->areMatchDisequal( nv, d_match[v] ) ){ - Debug("qcf-match-debug") << " -> fail, conflicting disequality" << std::endl; - return -1; - } - } - d_curr_var_deq[v][n] = v; - Debug("qcf-match-debug") << " -> success" << std::endl; - return 1; - }else{ - Debug("qcf-match-debug") << " -> redundant disequality" << std::endl; - return 0; - } - } - } - } -} - -bool QuantInfo::isConstrainedVar( int v ) { - if( d_curr_var_deq.find( v )!=d_curr_var_deq.end() && !d_curr_var_deq[v].empty() ){ - return true; - }else{ - Node vv = getVar( v ); - //for( std::map< int, TNode >::iterator it = d_match.begin(); it != d_match.end(); ++it ){ - for( unsigned i=0; i<d_match.size(); i++ ){ - if( d_match[i]==vv ){ - return true; - } - } - for( std::map< int, std::map< TNode, int > >::iterator it = d_curr_var_deq.begin(); it != d_curr_var_deq.end(); ++it ){ - for( std::map< TNode, int >::iterator it2 = it->second.begin(); it2 != it->second.end(); ++it2 ){ - if( it2->first==vv ){ - return true; - } - } - } - return false; - } -} - -bool QuantInfo::setMatch( QuantConflictFind * p, int v, TNode n ) { - if( getCurrentCanBeEqual( p, v, n ) ){ - Debug("qcf-match-debug") << "-- bind : " << v << " -> " << n << ", checked " << d_curr_var_deq[v].size() << " disequalities" << std::endl; - d_match[v] = n; - return true; - }else{ - return false; - } -} - -bool QuantInfo::isMatchSpurious( QuantConflictFind * p ) { - for( int i=0; i<getNumVars(); i++ ){ - //std::map< int, TNode >::iterator it = d_match.find( i ); - if( !d_match[i].isNull() ){ - if( !getCurrentCanBeEqual( p, i, d_match[i], p->d_effort==QuantConflictFind::effort_conflict ) ){ - return true; - } - } - } - return false; -} - -bool QuantInfo::isTConstraintSpurious( QuantConflictFind * p, std::vector< Node >& terms ) { - if( !d_tconstraints.empty() ){ - //check constraints - for( std::map< Node, bool >::iterator it = d_tconstraints.begin(); it != d_tconstraints.end(); ++it ){ - //apply substitution to the tconstraint - Node cons = it->first.substitute( p->getQuantifiersEngine()->getTermDatabase()->d_vars[d_q].begin(), - p->getQuantifiersEngine()->getTermDatabase()->d_vars[d_q].end(), - terms.begin(), terms.end() ); - cons = it->second ? cons : cons.negate(); - if( !entailmentTest( p, cons, p->d_effort==QuantConflictFind::effort_conflict ) ){ - return true; - } - } - } - return false; -} - -bool QuantInfo::entailmentTest( QuantConflictFind * p, Node lit, bool chEnt ) { - Trace("qcf-tconstraint-debug") << "Check : " << lit << std::endl; - Node rew = Rewriter::rewrite( lit ); - if( rew==p->d_false ){ - Trace("qcf-tconstraint-debug") << "...constraint " << lit << " is disentailed (rewrites to false)." << std::endl; - return false; - }else if( rew!=p->d_true ){ - //if checking for conflicts, we must be sure that the constraint is entailed - if( chEnt ){ - //check if it is entailed - Trace("qcf-tconstraint-debug") << "Check entailment of " << rew << "..." << std::endl; - std::pair<bool, Node> et = p->getQuantifiersEngine()->getTheoryEngine()->entailmentCheck(THEORY_OF_TYPE_BASED, rew ); - ++(p->d_statistics.d_entailment_checks); - Trace("qcf-tconstraint-debug") << "ET result : " << et.first << " " << et.second << std::endl; - if( !et.first ){ - Trace("qcf-tconstraint-debug") << "...cannot show entailment of " << rew << "." << std::endl; - return false; - }else{ - return true; - } - }else{ - Trace("qcf-tconstraint-debug") << "...does not need to be entailed." << std::endl; - return true; - } - }else{ - Trace("qcf-tconstraint-debug") << "...rewrites to true." << std::endl; - return true; - } -} - -bool QuantInfo::completeMatch( QuantConflictFind * p, std::vector< int >& assigned, bool doContinue ) { - //assign values for variables that were unassigned (usually not necessary, but handles corner cases) - bool doFail = false; - bool success = true; - if( doContinue ){ - doFail = true; - success = false; - }else{ - //solve for interpreted symbol matches - // this breaks the invariant that all introduced constraints are over existing terms - for( int i=(int)(d_tsym_vars.size()-1); i>=0; i-- ){ - int index = d_tsym_vars[i]; - TNode v = getCurrentValue( d_vars[index] ); - int slv_v = -1; - if( v==d_vars[index] ){ - slv_v = index; - } - Trace("qcf-tconstraint-debug") << "Solve " << d_vars[index] << " = " << v << " " << d_vars[index].getKind() << std::endl; - if( d_vars[index].getKind()==PLUS || d_vars[index].getKind()==MULT ){ - Kind k = d_vars[index].getKind(); - std::vector< TNode > children; - for( unsigned j=0; j<d_vars[index].getNumChildren(); j++ ){ - int vn = getVarNum( d_vars[index][j] ); - if( vn!=-1 ){ - TNode vv = getCurrentValue( d_vars[index][j] ); - if( vv==d_vars[index][j] ){ - //we will assign this - if( slv_v==-1 ){ - Trace("qcf-tconstraint-debug") << "...will solve for var #" << vn << std::endl; - slv_v = vn; - if( p->d_effort!=QuantConflictFind::effort_conflict ){ - break; - } - }else{ - Node z = p->getZero( k ); - if( !z.isNull() ){ - Trace("qcf-tconstraint-debug") << "...set " << d_vars[vn] << " = " << z << std::endl; - assigned.push_back( vn ); - if( !setMatch( p, vn, z ) ){ - success = false; - break; - } - } - } - }else{ - Trace("qcf-tconstraint-debug") << "...sum value " << vv << std::endl; - children.push_back( vv ); - } - }else{ - Trace("qcf-tconstraint-debug") << "...sum " << d_vars[index][j] << std::endl; - children.push_back( d_vars[index][j] ); - } - } - if( success ){ - if( slv_v!=-1 ){ - Node lhs; - if( children.empty() ){ - lhs = p->getZero( k ); - }else if( children.size()==1 ){ - lhs = children[0]; - }else{ - lhs = NodeManager::currentNM()->mkNode( k, children ); - } - Node sum; - if( v==d_vars[index] ){ - sum = lhs; - }else{ - if( p->d_effort==QuantConflictFind::effort_conflict ){ - Kind kn = k; - if( d_vars[index].getKind()==PLUS ){ - kn = MINUS; - } - if( kn!=k ){ - sum = NodeManager::currentNM()->mkNode( kn, v, lhs ); - } - } - } - if( !sum.isNull() ){ - assigned.push_back( slv_v ); - Trace("qcf-tconstraint-debug") << "...set " << d_vars[slv_v] << " = " << sum << std::endl; - if( !setMatch( p, slv_v, sum ) ){ - success = false; - } - p->d_tempCache.push_back( sum ); - } - }else{ - //must show that constraint is met - Node sum = NodeManager::currentNM()->mkNode( k, children ); - Node eq = sum.eqNode( v ); - if( !entailmentTest( p, eq ) ){ - success = false; - } - p->d_tempCache.push_back( sum ); - } - } - } - - if( !success ){ - break; - } - } - if( success ){ - //check what is left to assign - d_unassigned.clear(); - d_unassigned_tn.clear(); - std::vector< int > unassigned[2]; - std::vector< TypeNode > unassigned_tn[2]; - for( int i=0; i<getNumVars(); i++ ){ - if( d_match[i].isNull() ){ - int rindex = d_var_mg.find( i )==d_var_mg.end() ? 1 : 0; - unassigned[rindex].push_back( i ); - unassigned_tn[rindex].push_back( getVar( i ).getType() ); - assigned.push_back( i ); - } - } - d_unassigned_nvar = unassigned[0].size(); - for( unsigned i=0; i<2; i++ ){ - d_unassigned.insert( d_unassigned.end(), unassigned[i].begin(), unassigned[i].end() ); - d_unassigned_tn.insert( d_unassigned_tn.end(), unassigned_tn[i].begin(), unassigned_tn[i].end() ); - } - d_una_eqc_count.clear(); - d_una_index = 0; - } - } - - if( !d_unassigned.empty() && ( success || doContinue ) ){ - Trace("qcf-check") << "Assign to unassigned..." << std::endl; - do { - if( doFail ){ - Trace("qcf-check-unassign") << "Failure, try again..." << std::endl; - } - bool invalidMatch = false; - while( ( d_una_index>=0 && (int)d_una_index<(int)d_unassigned.size() ) || invalidMatch || doFail ){ - invalidMatch = false; - if( !doFail && d_una_index==(int)d_una_eqc_count.size() ){ - //check if it has now been assigned - if( d_una_index<d_unassigned_nvar ){ - if( !isConstrainedVar( d_unassigned[d_una_index] ) ){ - d_una_eqc_count.push_back( -1 ); - }else{ - d_var_mg[ d_unassigned[d_una_index] ]->reset( p, true, this ); - d_una_eqc_count.push_back( 0 ); - } - }else{ - d_una_eqc_count.push_back( 0 ); - } - }else{ - bool failed = false; - if( !doFail ){ - if( d_una_index<d_unassigned_nvar ){ - if( !isConstrainedVar( d_unassigned[d_una_index] ) ){ - Trace("qcf-check-unassign") << "Succeeded, variable unconstrained at " << d_una_index << std::endl; - d_una_index++; - }else if( d_var_mg[d_unassigned[d_una_index]]->getNextMatch( p, this ) ){ - Trace("qcf-check-unassign") << "Succeeded match with mg at " << d_una_index << std::endl; - d_una_index++; - }else{ - failed = true; - Trace("qcf-check-unassign") << "Failed match with mg at " << d_una_index << std::endl; - } - }else{ - Assert( doFail || d_una_index==(int)d_una_eqc_count.size()-1 ); - if( d_una_eqc_count[d_una_index]<(int)p->d_eqcs[d_unassigned_tn[d_una_index]].size() ){ - int currIndex = d_una_eqc_count[d_una_index]; - d_una_eqc_count[d_una_index]++; - Trace("qcf-check-unassign") << d_unassigned[d_una_index] << "->" << p->d_eqcs[d_unassigned_tn[d_una_index]][currIndex] << std::endl; - if( setMatch( p, d_unassigned[d_una_index], p->d_eqcs[d_unassigned_tn[d_una_index]][currIndex] ) ){ - d_match_term[d_unassigned[d_una_index]] = TNode::null(); - Trace("qcf-check-unassign") << "Succeeded match " << d_una_index << std::endl; - d_una_index++; - }else{ - Trace("qcf-check-unassign") << "Failed match " << d_una_index << std::endl; - invalidMatch = true; - } - }else{ - failed = true; - Trace("qcf-check-unassign") << "No more matches " << d_una_index << std::endl; - } - } - } - if( doFail || failed ){ - do{ - if( !doFail ){ - d_una_eqc_count.pop_back(); - }else{ - doFail = false; - } - d_una_index--; - }while( d_una_index>=0 && d_una_eqc_count[d_una_index]==-1 ); - } - } - } - success = d_una_index>=0; - if( success ){ - doFail = true; - Trace("qcf-check-unassign") << " Try: " << std::endl; - for( unsigned i=0; i<d_unassigned.size(); i++ ){ - int ui = d_unassigned[i]; - if( !d_match[ui].isNull() ){ - Trace("qcf-check-unassign") << " Assigned #" << ui << " : " << d_vars[ui] << " -> " << d_match[ui] << std::endl; - } - } - } - }while( success && isMatchSpurious( p ) ); - } - if( success ){ - for( unsigned i=0; i<d_unassigned.size(); i++ ){ - int ui = d_unassigned[i]; - if( !d_match[ui].isNull() ){ - Trace("qcf-check") << " Assigned #" << ui << " : " << d_vars[ui] << " -> " << d_match[ui] << std::endl; - } - } - return true; - }else{ - for( unsigned i=0; i<assigned.size(); i++ ){ - d_match[ assigned[i] ] = TNode::null(); - } - assigned.clear(); - return false; - } -} - -void QuantInfo::getMatch( std::vector< Node >& terms ){ - for( unsigned i=0; i<d_q[0].getNumChildren(); i++ ){ - //Node cv = qi->getCurrentValue( qi->d_match[i] ); - int repVar = getCurrentRepVar( i ); - Node cv; - //std::map< int, TNode >::iterator itmt = qi->d_match_term.find( repVar ); - if( !d_match_term[repVar].isNull() ){ - cv = d_match_term[repVar]; - }else{ - cv = d_match[repVar]; - } - Debug("qcf-check-inst") << "INST : " << i << " -> " << cv << ", from " << d_match[i] << std::endl; - terms.push_back( cv ); - } -} - -void QuantInfo::revertMatch( std::vector< int >& assigned ) { - for( unsigned i=0; i<assigned.size(); i++ ){ - d_match[ assigned[i] ] = TNode::null(); - } -} - -void QuantInfo::debugPrintMatch( const char * c ) { - for( int i=0; i<getNumVars(); i++ ){ - Trace(c) << " " << d_vars[i] << " -> "; - if( !d_match[i].isNull() ){ - Trace(c) << d_match[i]; - }else{ - Trace(c) << "(unassigned) "; - } - if( !d_curr_var_deq[i].empty() ){ - Trace(c) << ", DEQ{ "; - for( std::map< TNode, int >::iterator it = d_curr_var_deq[i].begin(); it != d_curr_var_deq[i].end(); ++it ){ - Trace(c) << it->first << " "; - } - Trace(c) << "}"; - } - if( !d_match_term[i].isNull() && d_match_term[i]!=d_match[i] ){ - Trace(c) << ", EXP : " << d_match_term[i]; - } - Trace(c) << std::endl; - } - if( !d_tconstraints.empty() ){ - Trace(c) << "ADDITIONAL CONSTRAINTS : " << std::endl; - for( std::map< Node, bool >::iterator it = d_tconstraints.begin(); it != d_tconstraints.end(); ++it ){ - Trace(c) << " " << it->first << " -> " << it->second << std::endl; - } - } -} - -MatchGen::MatchGen( QuantInfo * qi, Node n, bool isVar ){ - Trace("qcf-qregister-debug") << "Make match gen for " << n << ", isVar = " << isVar << std::endl; - std::vector< Node > qni_apps; - d_qni_size = 0; - if( isVar ){ - Assert( qi->d_var_num.find( n )!=qi->d_var_num.end() ); - if( n.getKind()==ITE ){ - d_type = typ_ite_var; - d_type_not = false; - d_n = n; - d_children.push_back( MatchGen( qi, d_n[0] ) ); - if( d_children[0].isValid() ){ - d_type = typ_ite_var; - for( unsigned i=1; i<=2; i++ ){ - Node nn = n.eqNode( n[i] ); - d_children.push_back( MatchGen( qi, nn ) ); - d_children[d_children.size()-1].d_qni_bound_except.push_back( 0 ); - if( !d_children[d_children.size()-1].isValid() ){ - setInvalid(); - break; - } - } - }else{ - d_type = typ_invalid; - } - }else{ - d_type = isHandledUfTerm( n ) ? typ_var : typ_tsym; - d_qni_var_num[0] = qi->getVarNum( n ); - d_qni_size++; - d_type_not = false; - d_n = n; - //Node f = getOperator( n ); - for( unsigned j=0; j<d_n.getNumChildren(); j++ ){ - Node nn = d_n[j]; - Trace("qcf-qregister-debug") << " " << d_qni_size; - if( qi->isVar( nn ) ){ - int v = qi->d_var_num[nn]; - Trace("qcf-qregister-debug") << " is var #" << v << std::endl; - d_qni_var_num[d_qni_size] = v; - //qi->addFuncParent( v, f, j ); - }else{ - Trace("qcf-qregister-debug") << " is gterm " << nn << std::endl; - d_qni_gterm[d_qni_size] = nn; - } - d_qni_size++; - } - } - }else{ - if( n.hasBoundVar() ){ - d_type_not = false; - d_n = n; - if( d_n.getKind()==NOT ){ - d_n = d_n[0]; - d_type_not = !d_type_not; - } - - if( isHandledBoolConnective( d_n ) ){ - //non-literals - d_type = typ_formula; - for( unsigned i=0; i<d_n.getNumChildren(); i++ ){ - if( d_n.getKind()!=FORALL || i==1 ){ - d_children.push_back( MatchGen( qi, d_n[i], false ) ); - if( !d_children[d_children.size()-1].isValid() ){ - setInvalid(); - break; - } - } - /* - else if( isTop && n.getKind()==OR && d_children[d_children.size()-1].d_type==typ_var_eq ){ - Trace("qcf-qregister-debug") << "Remove child, make built-in constraint" << std::endl; - //if variable equality/disequality at top level, remove immediately - bool cIsNot = d_children[d_children.size()-1].d_type_not; - Node cn = d_children[d_children.size()-1].d_n; - Assert( cn.getKind()==EQUAL ); - Assert( p->d_qinfo[q].isVar( cn[0] ) || p->d_qinfo[q].isVar( cn[1] ) ); - //make it a built-in constraint instead - for( unsigned i=0; i<2; i++ ){ - if( p->d_qinfo[q].isVar( cn[i] ) ){ - int v = p->d_qinfo[q].getVarNum( cn[i] ); - Node cno = cn[i==0 ? 1 : 0]; - p->d_qinfo[q].d_var_constraint[ cIsNot ? 0 : 1 ][v].push_back( cno ); - break; - } - } - d_children.pop_back(); - } - */ - } - }else{ - d_type = typ_invalid; - //literals - if( isHandledUfTerm( d_n ) ){ - Assert( qi->isVar( d_n ) ); - d_type = typ_pred; - }else if( d_n.getKind()==BOUND_VARIABLE ){ - Assert( d_n.getType().isBoolean() ); - d_type = typ_bool_var; - }else if( d_n.getKind()==EQUAL || options::qcfTConstraint() ){ - for( unsigned i=0; i<d_n.getNumChildren(); i++ ){ - if( d_n[i].hasBoundVar() ){ - if( !qi->isVar( d_n[i] ) ){ - Trace("qcf-qregister-debug") << "ERROR : not var " << d_n[i] << std::endl; - } - Assert( qi->isVar( d_n[i] ) ); - if( d_n.getKind()!=EQUAL && qi->isVar( d_n[i] ) ){ - d_qni_var_num[i+1] = qi->d_var_num[d_n[i]]; - } - }else{ - d_qni_gterm[i] = d_n[i]; - } - } - d_type = d_n.getKind()==EQUAL ? typ_eq : typ_tconstraint; - Trace("qcf-tconstraint") << "T-Constraint : " << d_n << std::endl; - } - } - }else{ - //we will just evaluate - d_n = n; - d_type = typ_ground; - } - //if( d_type!=typ_invalid ){ - //determine an efficient children ordering - //if( !d_children.empty() ){ - //for( unsigned i=0; i<d_children.size(); i++ ){ - // d_children_order.push_back( i ); - //} - //if( !d_n.isNull() && ( d_n.getKind()==OR || d_n.getKind()==AND || d_n.getKind()==IFF ) ){ - //sort based on the type of the constraint : ground comes first, then literals, then others - //MatchGenSort mgs; - //mgs.d_mg = this; - //std::sort( d_children_order.begin(), d_children_order.end(), mgs ); - //} - //} - //} - } - Trace("qcf-qregister-debug") << "Done make match gen " << n << ", type = "; - debugPrintType( "qcf-qregister-debug", d_type, true ); - Trace("qcf-qregister-debug") << std::endl; - //Assert( d_children.size()==d_children_order.size() ); - -} - -void MatchGen::collectBoundVar( QuantInfo * qi, Node n, std::vector< int >& cbvars ) { - int v = qi->getVarNum( n ); - if( v!=-1 && std::find( cbvars.begin(), cbvars.end(), v )==cbvars.end() ){ - cbvars.push_back( v ); - } - for( unsigned i=0; i<n.getNumChildren(); i++ ){ - collectBoundVar( qi, n[i], cbvars ); - } -} - -void MatchGen::determineVariableOrder( QuantInfo * qi, std::vector< int >& bvars ) { - Trace("qcf-qregister-debug") << "Determine variable order " << d_n << std::endl; - bool isCom = d_type==typ_formula && ( d_n.getKind()==OR || d_n.getKind()==AND || d_n.getKind()==IFF ); - std::map< int, std::vector< int > > c_to_vars; - std::map< int, std::vector< int > > vars_to_c; - std::map< int, int > vb_count; - std::map< int, int > vu_count; - std::vector< bool > assigned; - Trace("qcf-qregister-debug") << "Calculate bound variables..." << std::endl; - for( unsigned i=0; i<d_children.size(); i++ ){ - collectBoundVar( qi, d_children[i].d_n, c_to_vars[i] ); - assigned.push_back( false ); - vb_count[i] = 0; - vu_count[i] = 0; - for( unsigned j=0; j<c_to_vars[i].size(); j++ ){ - int v = c_to_vars[i][j]; - vars_to_c[v].push_back( i ); - if( std::find( bvars.begin(), bvars.end(), v )==bvars.end() ){ - vu_count[i]++; - if( !isCom ){ - bvars.push_back( v ); - } - }else{ - vb_count[i]++; - } - } - } - if( isCom ){ - //children that bind the least number of unbound variables go first - do { - int min_score = -1; - int min_score_index = -1; - for( unsigned i=0; i<d_children.size(); i++ ){ - if( !assigned[i] ){ - int score = vu_count[i]; - if( min_score==-1 || score<min_score ){ - min_score = score; - min_score_index = i; - } - } - } - Trace("qcf-qregister-debug") << "...assign child " << min_score_index << "/" << d_children.size() << std::endl; - Assert( min_score_index!=-1 ); - //add to children order - d_children_order.push_back( min_score_index ); - assigned[min_score_index] = true; - //if( vb_count[min_score_index]==0 ){ - // d_independent.push_back( min_score_index ); - //} - //determine order internal to children - d_children[min_score_index].determineVariableOrder( qi, bvars ); - Trace("qcf-qregister-debug") << "...bind variables" << std::endl; - //now, make it a bound variable - for( unsigned i=0; i<c_to_vars[min_score_index].size(); i++ ){ - int v = c_to_vars[min_score_index][i]; - if( std::find( bvars.begin(), bvars.end(), v )==bvars.end() ){ - for( unsigned j=0; j<vars_to_c[v].size(); j++ ){ - int vc = vars_to_c[v][j]; - vu_count[vc]--; - vb_count[vc]++; - } - bvars.push_back( v ); - } - } - Trace("qcf-qregister-debug") << "...done assign child " << min_score_index << std::endl; - }while( d_children_order.size()!=d_children.size() ); - Trace("qcf-qregister-debug") << "Done assign variable ordering for " << d_n << std::endl; - }else{ - for( unsigned i=0; i<d_children.size(); i++ ){ - d_children_order.push_back( i ); - d_children[i].determineVariableOrder( qi, bvars ); - } - } -} - - -void MatchGen::reset_round( QuantConflictFind * p ) { - d_wasSet = false; - for( unsigned i=0; i<d_children.size(); i++ ){ - d_children[i].reset_round( p ); - } - for( std::map< int, TNode >::iterator it = d_qni_gterm.begin(); it != d_qni_gterm.end(); ++it ){ - d_qni_gterm_rep[it->first] = p->getRepresentative( it->second ); - } - if( d_type==typ_ground ){ - int e = p->evaluate( d_n ); - if( e==1 ){ - d_ground_eval[0] = p->d_true; - }else if( e==-1 ){ - d_ground_eval[0] = p->d_false; - } - }else if( d_type==typ_eq ){ - for( unsigned i=0; i<d_n.getNumChildren(); i++ ){ - if( !d_n[i].hasBoundVar() ){ - d_ground_eval[i] = p->evaluateTerm( d_n[i] ); - } - } - } - d_qni_bound_cons.clear(); - d_qni_bound_cons_var.clear(); - d_qni_bound.clear(); -} - -void MatchGen::reset( QuantConflictFind * p, bool tgt, QuantInfo * qi ) { - d_tgt = d_type_not ? !tgt : tgt; - Debug("qcf-match") << " Reset for : " << d_n << ", type : "; - debugPrintType( "qcf-match", d_type ); - Debug("qcf-match") << ", tgt = " << d_tgt << ", children = " << d_children.size() << " " << d_children_order.size() << std::endl; - d_qn.clear(); - d_qni.clear(); - d_qni_bound.clear(); - d_child_counter = -1; - d_tgt_orig = d_tgt; - - //set up processing matches - if( d_type==typ_invalid ){ - //do nothing - }else if( d_type==typ_ground ){ - if( d_ground_eval[0]==( d_tgt ? p->d_true : p->d_false ) ){ - d_child_counter = 0; - } - }else if( d_type==typ_bool_var ){ - //get current value of the variable - TNode n = qi->getCurrentValue( d_n ); - int vn = qi->getCurrentRepVar( qi->getVarNum( n ) ); - if( vn==-1 ){ - //evaluate the value, see if it is compatible - int e = p->evaluate( n ); - if( ( e==1 && d_tgt ) || ( e==0 && !d_tgt ) ){ - d_child_counter = 0; - } - }else{ - //unassigned, set match to true/false - d_qni_bound[0] = vn; - qi->setMatch( p, vn, d_tgt ? p->d_true : p->d_false ); - d_child_counter = 0; - } - if( d_child_counter==0 ){ - d_qn.push_back( NULL ); - } - }else if( d_type==typ_var ){ - Assert( isHandledUfTerm( d_n ) ); - Node f = getOperator( p, d_n ); - Debug("qcf-match-debug") << " reset: Var will match operators of " << f << std::endl; - QcfNodeIndex * qni = p->getQcfNodeIndex( Node::null(), f ); - if( qni!=NULL ){ - d_qn.push_back( qni ); - } - d_matched_basis = false; - }else if( d_type==typ_tsym || d_type==typ_tconstraint ){ - for( std::map< int, int >::iterator it = d_qni_var_num.begin(); it != d_qni_var_num.end(); ++it ){ - int repVar = qi->getCurrentRepVar( it->second ); - if( qi->d_match[repVar].isNull() ){ - Debug("qcf-match-debug") << "Force matching on child #" << it->first << ", which is var #" << repVar << std::endl; - d_qni_bound[it->first] = repVar; - } - } - d_qn.push_back( NULL ); - }else if( d_type==typ_pred || d_type==typ_eq ){ - //add initial constraint - Node nn[2]; - int vn[2]; - if( d_type==typ_pred ){ - nn[0] = qi->getCurrentValue( d_n ); - vn[0] = qi->getCurrentRepVar( qi->getVarNum( nn[0] ) ); - nn[1] = p->getRepresentative( d_tgt ? p->d_true : p->d_false ); - vn[1] = -1; - d_tgt = true; - }else{ - for( unsigned i=0; i<2; i++ ){ - TNode nc; - std::map< int, TNode >::iterator it = d_qni_gterm_rep.find( i ); - if( it!=d_qni_gterm_rep.end() ){ - nc = it->second; - }else{ - nc = d_n[i]; - } - nn[i] = qi->getCurrentValue( nc ); - vn[i] = qi->getCurrentRepVar( qi->getVarNum( nn[i] ) ); - } - } - bool success; - if( vn[0]==-1 && vn[1]==-1 ){ - //Trace("qcf-explain") << " reset : " << d_n << " check ground values " << nn[0] << " " << nn[1] << " (tgt=" << d_tgt << ")" << std::endl; - Debug("qcf-match-debug") << " reset: check ground values " << nn[0] << " " << nn[1] << " (" << d_tgt << ")" << std::endl; - //just compare values - if( d_tgt ){ - success = p->areMatchEqual( nn[0], nn[1] ); - }else{ - if( p->d_effort==QuantConflictFind::effort_conflict ){ - success = p->areDisequal( nn[0], nn[1] ); - }else{ - success = p->areMatchDisequal( nn[0], nn[1] ); - } - } - }else{ - //otherwise, add a constraint to a variable - if( vn[1]!=-1 && vn[0]==-1 ){ - //swap - Node t = nn[1]; - nn[1] = nn[0]; - nn[0] = t; - vn[0] = vn[1]; - vn[1] = -1; - } - Debug("qcf-match-debug") << " reset: add constraint " << vn[0] << " -> " << nn[1] << " (vn=" << vn[1] << ")" << std::endl; - //add some constraint - int addc = qi->addConstraint( p, vn[0], nn[1], vn[1], d_tgt, false ); - success = addc!=-1; - //if successful and non-redundant, store that we need to cleanup this - if( addc==1 ){ - //Trace("qcf-explain") << " reset: " << d_n << " add constraint " << vn[0] << " -> " << nn[1] << " (vn=" << vn[1] << ")" << ", d_tgt = " << d_tgt << std::endl; - for( unsigned i=0; i<2; i++ ){ - if( vn[i]!=-1 && std::find( d_qni_bound_except.begin(), d_qni_bound_except.end(), i )==d_qni_bound_except.end() ){ - d_qni_bound[vn[i]] = vn[i]; - } - } - d_qni_bound_cons[vn[0]] = nn[1]; - d_qni_bound_cons_var[vn[0]] = vn[1]; - } - } - //if successful, we will bind values to variables - if( success ){ - d_qn.push_back( NULL ); - } - }else{ - if( d_children.empty() ){ - //add dummy - d_qn.push_back( NULL ); - }else{ - if( d_tgt && d_n.getKind()==FORALL ){ - //do nothing - }else{ - //reset the first child to d_tgt - d_child_counter = 0; - getChild( d_child_counter )->reset( p, d_tgt, qi ); - } - } - } - d_binding = false; - d_wasSet = true; - Debug("qcf-match") << " reset: Finished reset for " << d_n << ", success = " << ( !d_qn.empty() || d_child_counter!=-1 ) << std::endl; -} - -bool MatchGen::getNextMatch( QuantConflictFind * p, QuantInfo * qi ) { - Debug("qcf-match") << " Get next match for : " << d_n << ", type = "; - debugPrintType( "qcf-match", d_type ); - Debug("qcf-match") << ", children = " << d_children.size() << ", binding = " << d_binding << std::endl; - if( d_type==typ_invalid || d_type==typ_ground ){ - if( d_child_counter==0 ){ - d_child_counter = -1; - return true; - }else{ - d_wasSet = false; - return false; - } - }else if( d_type==typ_var || d_type==typ_eq || d_type==typ_pred || d_type==typ_bool_var || d_type==typ_tconstraint || d_type==typ_tsym ){ - bool success = false; - bool terminate = false; - do { - bool doReset = false; - bool doFail = false; - if( !d_binding ){ - if( doMatching( p, qi ) ){ - Debug("qcf-match-debug") << " - Matching succeeded" << std::endl; - d_binding = true; - d_binding_it = d_qni_bound.begin(); - doReset = true; - //for tconstraint, add constraint - if( d_type==typ_tconstraint ){ - std::map< Node, bool >::iterator it = qi->d_tconstraints.find( d_n ); - if( it==qi->d_tconstraints.end() ){ - qi->d_tconstraints[d_n] = d_tgt; - //store that we added this constraint - d_qni_bound_cons[0] = d_n; - }else if( d_tgt!=it->second ){ - success = false; - terminate = true; - } - } - }else{ - Debug("qcf-match-debug") << " - Matching failed" << std::endl; - success = false; - terminate = true; - } - }else{ - doFail = true; - } - if( d_binding ){ - //also need to create match for each variable we bound - success = true; - Debug("qcf-match-debug") << " Produce matches for bound variables by " << d_n << ", type = "; - debugPrintType( "qcf-match-debug", d_type ); - Debug("qcf-match-debug") << "..." << std::endl; - - while( ( success && d_binding_it!=d_qni_bound.end() ) || doFail ){ - std::map< int, MatchGen * >::iterator itm; - if( !doFail ){ - Debug("qcf-match-debug") << " check variable " << d_binding_it->second << std::endl; - itm = qi->d_var_mg.find( d_binding_it->second ); - } - if( doFail || ( d_binding_it->first!=0 && itm!=qi->d_var_mg.end() ) ){ - Debug("qcf-match-debug") << " we had bound variable " << d_binding_it->second << ", reset = " << doReset << std::endl; - if( doReset ){ - itm->second->reset( p, true, qi ); - } - if( doFail || !itm->second->getNextMatch( p, qi ) ){ - do { - if( d_binding_it==d_qni_bound.begin() ){ - Debug("qcf-match-debug") << " failed." << std::endl; - success = false; - }else{ - --d_binding_it; - Debug("qcf-match-debug") << " decrement..." << std::endl; - } - }while( success && ( d_binding_it->first==0 || qi->d_var_mg.find( d_binding_it->second )==qi->d_var_mg.end() ) ); - doReset = false; - doFail = false; - }else{ - Debug("qcf-match-debug") << " increment..." << std::endl; - ++d_binding_it; - doReset = true; - } - }else{ - Debug("qcf-match-debug") << " skip..." << d_binding_it->second << std::endl; - ++d_binding_it; - doReset = true; - } - } - if( !success ){ - d_binding = false; - }else{ - terminate = true; - if( d_binding_it==d_qni_bound.begin() ){ - d_binding = false; - } - } - } - }while( !terminate ); - //if not successful, clean up the variables you bound - if( !success ){ - if( d_type==typ_eq || d_type==typ_pred ){ - //clean up the constraints you added - for( std::map< int, TNode >::iterator it = d_qni_bound_cons.begin(); it != d_qni_bound_cons.end(); ++it ){ - if( !it->second.isNull() ){ - Debug("qcf-match") << " Clean up bound var " << it->first << (d_tgt ? "!" : "") << " = " << it->second << std::endl; - std::map< int, int >::iterator itb = d_qni_bound_cons_var.find( it->first ); - int vn = itb!=d_qni_bound_cons_var.end() ? itb->second : -1; - //Trace("qcf-explain") << " cleanup: " << d_n << " remove constraint " << it->first << " -> " << it->second << " (vn=" << vn << ")" << ", d_tgt = " << d_tgt << std::endl; - qi->addConstraint( p, it->first, it->second, vn, d_tgt, true ); - } - } - d_qni_bound_cons.clear(); - d_qni_bound_cons_var.clear(); - d_qni_bound.clear(); - }else{ - //clean up the matches you set - for( std::map< int, int >::iterator it = d_qni_bound.begin(); it != d_qni_bound.end(); ++it ){ - Debug("qcf-match") << " Clean up bound var " << it->second << std::endl; - Assert( it->second<qi->getNumVars() ); - qi->d_match[ it->second ] = TNode::null(); - qi->d_match_term[ it->second ] = TNode::null(); - } - d_qni_bound.clear(); - } - if( d_type==typ_tconstraint ){ - //remove constraint if applicable - if( d_qni_bound_cons.find( 0 )!=d_qni_bound_cons.end() ){ - qi->d_tconstraints.erase( d_n ); - d_qni_bound_cons.clear(); - } - } - /* - if( d_type==typ_var && p->d_effort==QuantConflictFind::effort_mc && !d_matched_basis ){ - d_matched_basis = true; - Node f = getOperator( d_n ); - TNode mbo = p->getQuantifiersEngine()->getTermDatabase()->getModelBasisOpTerm( f ); - if( qi->setMatch( p, d_qni_var_num[0], mbo ) ){ - success = true; - d_qni_bound[0] = d_qni_var_num[0]; - } - } - */ - } - Debug("qcf-match") << " ...finished matching for " << d_n << ", success = " << success << std::endl; - d_wasSet = success; - return success; - }else if( d_type==typ_formula || d_type==typ_ite_var ){ - bool success = false; - if( d_child_counter<0 ){ - if( d_child_counter<-1 ){ - success = true; - d_child_counter = -1; - } - }else{ - while( !success && d_child_counter>=0 ){ - //transition system based on d_child_counter - if( d_n.getKind()==OR || d_n.getKind()==AND ){ - if( (d_n.getKind()==AND)==d_tgt ){ - //all children must match simultaneously - if( getChild( d_child_counter )->getNextMatch( p, qi ) ){ - if( d_child_counter<(int)(getNumChildren()-1) ){ - d_child_counter++; - Debug("qcf-match-debug") << " Reset child " << d_child_counter << " of " << d_n << std::endl; - getChild( d_child_counter )->reset( p, d_tgt, qi ); - }else{ - success = true; - } - }else{ - //if( std::find( d_independent.begin(), d_independent.end(), d_child_counter )!=d_independent.end() ){ - // d_child_counter--; - //}else{ - d_child_counter--; - //} - } - }else{ - //one child must match - if( !getChild( d_child_counter )->getNextMatch( p, qi ) ){ - if( d_child_counter<(int)(getNumChildren()-1) ){ - d_child_counter++; - Debug("qcf-match-debug") << " Reset child " << d_child_counter << " of " << d_n << ", one match" << std::endl; - getChild( d_child_counter )->reset( p, d_tgt, qi ); - }else{ - d_child_counter = -1; - } - }else{ - success = true; - } - } - }else if( d_n.getKind()==IFF ){ - //construct match based on both children - if( d_child_counter%2==0 ){ - if( getChild( 0 )->getNextMatch( p, qi ) ){ - d_child_counter++; - getChild( 1 )->reset( p, d_child_counter==1, qi ); - }else{ - if( d_child_counter==0 ){ - d_child_counter = 2; - getChild( 0 )->reset( p, !d_tgt, qi ); - }else{ - d_child_counter = -1; - } - } - } - if( d_child_counter>=0 && d_child_counter%2==1 ){ - if( getChild( 1 )->getNextMatch( p, qi ) ){ - success = true; - }else{ - d_child_counter--; - } - } - }else if( d_n.getKind()==ITE ){ - if( d_child_counter%2==0 ){ - int index1 = d_child_counter==4 ? 1 : 0; - if( getChild( index1 )->getNextMatch( p, qi ) ){ - d_child_counter++; - getChild( d_child_counter==5 ? 2 : (d_tgt==(d_child_counter==1) ? 1 : 2) )->reset( p, d_tgt, qi ); - }else{ - if( d_child_counter==4 || ( d_type==typ_ite_var && d_child_counter==2 ) ){ - d_child_counter = -1; - }else{ - d_child_counter +=2; - getChild( d_child_counter==2 ? 0 : 1 )->reset( p, d_child_counter==2 ? !d_tgt : d_tgt, qi ); - } - } - } - if( d_child_counter>=0 && d_child_counter%2==1 ){ - int index2 = d_child_counter==5 ? 2 : (d_tgt==(d_child_counter==1) ? 1 : 2); - if( getChild( index2 )->getNextMatch( p, qi ) ){ - success = true; - }else{ - d_child_counter--; - } - } - }else if( d_n.getKind()==FORALL ){ - if( getChild( d_child_counter )->getNextMatch( p, qi ) ){ - success = true; - }else{ - d_child_counter = -1; - } - } - } - d_wasSet = success; - Debug("qcf-match") << " ...finished construct match for " << d_n << ", success = " << success << std::endl; - return success; - } - } - Debug("qcf-match") << " ...already finished for " << d_n << std::endl; - return false; -} - -bool MatchGen::getExplanation( QuantConflictFind * p, QuantInfo * qi, std::vector< Node >& exp ) { - if( d_type==typ_eq ){ - Node n[2]; - for( unsigned i=0; i<2; i++ ){ - Trace("qcf-explain") << "Explain term " << d_n[i] << "..." << std::endl; - n[i] = getExplanationTerm( p, qi, d_n[i], exp ); - } - Node eq = n[0].eqNode( n[1] ); - if( !d_tgt_orig ){ - eq = eq.negate(); - } - exp.push_back( eq ); - Trace("qcf-explain") << "Explanation for " << d_n << " (tgt=" << d_tgt_orig << ") is " << eq << ", set = " << d_wasSet << std::endl; - return true; - }else if( d_type==typ_pred ){ - Trace("qcf-explain") << "Explain term " << d_n << "..." << std::endl; - Node n = getExplanationTerm( p, qi, d_n, exp ); - if( !d_tgt_orig ){ - n = n.negate(); - } - exp.push_back( n ); - Trace("qcf-explain") << "Explanation for " << d_n << " (tgt=" << d_tgt_orig << ") is " << n << ", set = " << d_wasSet << std::endl; - return true; - }else if( d_type==typ_formula ){ - Trace("qcf-explain") << "Explanation get for " << d_n << ", counter = " << d_child_counter << ", tgt = " << d_tgt_orig << ", set = " << d_wasSet << std::endl; - if( d_n.getKind()==OR || d_n.getKind()==AND ){ - if( (d_n.getKind()==AND)==d_tgt ){ - for( unsigned i=0; i<getNumChildren(); i++ ){ - if( !getChild( i )->getExplanation( p, qi, exp ) ){ - return false; - } - } - }else{ - return getChild( d_child_counter )->getExplanation( p, qi, exp ); - } - }else if( d_n.getKind()==IFF ){ - for( unsigned i=0; i<2; i++ ){ - if( !getChild( i )->getExplanation( p, qi, exp ) ){ - return false; - } - } - }else if( d_n.getKind()==ITE ){ - for( unsigned i=0; i<3; i++ ){ - bool isActive = ( ( i==0 && d_child_counter!=5 ) || - ( i==1 && d_child_counter!=( d_tgt ? 3 : 1 ) ) || - ( i==2 && d_child_counter!=( d_tgt ? 1 : 3 ) ) ); - if( isActive ){ - if( !getChild( i )->getExplanation( p, qi, exp ) ){ - return false; - } - } - } - }else{ - return false; - } - return true; - }else{ - return false; - } -} - -Node MatchGen::getExplanationTerm( QuantConflictFind * p, QuantInfo * qi, Node t, std::vector< Node >& exp ) { - Node v = qi->getCurrentExpValue( t ); - if( isHandledUfTerm( t ) ){ - for( unsigned i=0; i<t.getNumChildren(); i++ ){ - Node vi = getExplanationTerm( p, qi, t[i], exp ); - if( vi!=v[i] ){ - Node eq = vi.eqNode( v[i] ); - if( std::find( exp.begin(), exp.end(), eq )==exp.end() ){ - Trace("qcf-explain") << " add : " << eq << "." << std::endl; - exp.push_back( eq ); - } - } - } - } - return v; -} - -bool MatchGen::doMatching( QuantConflictFind * p, QuantInfo * qi ) { - if( !d_qn.empty() ){ - if( d_qn[0]==NULL ){ - d_qn.clear(); - return true; - }else{ - Assert( d_type==typ_var ); - Assert( d_qni_size>0 ); - bool invalidMatch; - do { - invalidMatch = false; - Debug("qcf-match-debug") << " Do matching " << d_n << " " << d_qn.size() << " " << d_qni.size() << std::endl; - if( d_qn.size()==d_qni.size()+1 ) { - int index = (int)d_qni.size(); - //initialize - TNode val; - std::map< int, int >::iterator itv = d_qni_var_num.find( index ); - if( itv!=d_qni_var_num.end() ){ - //get the representative variable this variable is equal to - int repVar = qi->getCurrentRepVar( itv->second ); - Debug("qcf-match-debug") << " Match " << index << " is a variable " << itv->second << ", which is repVar " << repVar << std::endl; - //get the value the rep variable - //std::map< int, TNode >::iterator itm = qi->d_match.find( repVar ); - if( !qi->d_match[repVar].isNull() ){ - val = qi->d_match[repVar]; - Debug("qcf-match-debug") << " Variable is already bound to " << val << std::endl; - }else{ - //binding a variable - d_qni_bound[index] = repVar; - std::map< TNode, QcfNodeIndex >::iterator it = d_qn[index]->d_children.begin(); - if( it != d_qn[index]->d_children.end() ) { - d_qni.push_back( it ); - //set the match - if( qi->setMatch( p, d_qni_bound[index], it->first ) ){ - Debug("qcf-match-debug") << " Binding variable" << std::endl; - if( d_qn.size()<d_qni_size ){ - d_qn.push_back( &it->second ); - } - }else{ - Debug("qcf-match") << " Binding variable, currently fail." << std::endl; - invalidMatch = true; - } - }else{ - Debug("qcf-match-debug") << " Binding variable, fail, no more variables to bind" << std::endl; - d_qn.pop_back(); - } - } - }else{ - Debug("qcf-match-debug") << " Match " << index << " is ground term" << std::endl; - Assert( d_qni_gterm.find( index )!=d_qni_gterm.end() ); - Assert( d_qni_gterm_rep.find( index )!=d_qni_gterm_rep.end() ); - val = d_qni_gterm_rep[index]; - Assert( !val.isNull() ); - } - if( !val.isNull() ){ - //constrained by val - std::map< TNode, QcfNodeIndex >::iterator it = d_qn[index]->d_children.find( val ); - if( it!=d_qn[index]->d_children.end() ){ - Debug("qcf-match-debug") << " Match" << std::endl; - d_qni.push_back( it ); - if( d_qn.size()<d_qni_size ){ - d_qn.push_back( &it->second ); - } - }else{ - Debug("qcf-match-debug") << " Failed to match" << std::endl; - d_qn.pop_back(); - } - } - }else{ - Assert( d_qn.size()==d_qni.size() ); - int index = d_qni.size()-1; - //increment if binding this variable - bool success = false; - std::map< int, int >::iterator itb = d_qni_bound.find( index ); - if( itb!=d_qni_bound.end() ){ - d_qni[index]++; - if( d_qni[index]!=d_qn[index]->d_children.end() ){ - success = true; - if( qi->setMatch( p, itb->second, d_qni[index]->first ) ){ - Debug("qcf-match-debug") << " Bind next variable" << std::endl; - if( d_qn.size()<d_qni_size ){ - d_qn.push_back( &d_qni[index]->second ); - } - }else{ - Debug("qcf-match-debug") << " Bind next variable, currently fail" << std::endl; - invalidMatch = true; - } - }else{ - qi->d_match[ itb->second ] = TNode::null(); - qi->d_match_term[ itb->second ] = TNode::null(); - Debug("qcf-match-debug") << " Bind next variable, no more variables to bind" << std::endl; - } - }else{ - //TODO : if it equal to something else, also try that - } - //if not incrementing, move to next - if( !success ){ - d_qn.pop_back(); - d_qni.pop_back(); - } - } - }while( ( !d_qn.empty() && d_qni.size()!=d_qni_size ) || invalidMatch ); - if( d_qni.size()==d_qni_size ){ - //Assert( !d_qni[d_qni.size()-1]->second.d_children.empty() ); - //Debug("qcf-match-debug") << " We matched " << d_qni[d_qni.size()-1]->second.d_children.begin()->first << std::endl; - Assert( !d_qni[d_qni.size()-1]->second.d_children.empty() ); - TNode t = d_qni[d_qni.size()-1]->second.d_children.begin()->first; - Debug("qcf-match-debug") << " " << d_n << " matched " << t << std::endl; - qi->d_match_term[d_qni_var_num[0]] = t; - //set the match terms - for( std::map< int, int >::iterator it = d_qni_bound.begin(); it != d_qni_bound.end(); ++it ){ - Debug("qcf-match-debug") << " position " << it->first << " bounded " << it->second << " / " << qi->d_q[0].getNumChildren() << std::endl; - //if( it->second<(int)qi->d_q[0].getNumChildren() ){ //if it is an actual variable, we are interested in knowing the actual term - if( it->first>0 ){ - Assert( !qi->d_match[ it->second ].isNull() ); - Assert( p->areEqual( t[it->first-1], qi->d_match[ it->second ] ) ); - qi->d_match_term[it->second] = t[it->first-1]; - } - //} - } - } - } - } - return !d_qn.empty(); -} - -void MatchGen::debugPrintType( const char * c, short typ, bool isTrace ) { - if( isTrace ){ - switch( typ ){ - case typ_invalid: Trace(c) << "invalid";break; - case typ_ground: Trace(c) << "ground";break; - case typ_eq: Trace(c) << "eq";break; - case typ_pred: Trace(c) << "pred";break; - case typ_formula: Trace(c) << "formula";break; - case typ_var: Trace(c) << "var";break; - case typ_ite_var: Trace(c) << "ite_var";break; - case typ_bool_var: Trace(c) << "bool_var";break; - } - }else{ - switch( typ ){ - case typ_invalid: Debug(c) << "invalid";break; - case typ_ground: Debug(c) << "ground";break; - case typ_eq: Debug(c) << "eq";break; - case typ_pred: Debug(c) << "pred";break; - case typ_formula: Debug(c) << "formula";break; - case typ_var: Debug(c) << "var";break; - case typ_ite_var: Debug(c) << "ite_var";break; - case typ_bool_var: Debug(c) << "bool_var";break; - } - } -} - -void MatchGen::setInvalid() { - d_type = typ_invalid; - d_children.clear(); -} - -bool MatchGen::isHandledBoolConnective( TNode n ) { - return n.getType().isBoolean() && ( n.getKind()==OR || n.getKind()==AND || n.getKind()==IFF || n.getKind()==ITE || n.getKind()==FORALL || n.getKind()==NOT ); -} - -bool MatchGen::isHandledUfTerm( TNode n ) { - //return n.getKind()==APPLY_UF || n.getKind()==STORE || n.getKind()==SELECT || - // n.getKind()==APPLY_CONSTRUCTOR || n.getKind()==APPLY_SELECTOR_TOTAL || n.getKind()==APPLY_TESTER; - return inst::Trigger::isAtomicTriggerKind( n.getKind() ); -} - -Node MatchGen::getOperator( QuantConflictFind * p, Node n ) { - if( isHandledUfTerm( n ) ){ - return p->getQuantifiersEngine()->getTermDatabase()->getOperator( n ); - }else{ - return Node::null(); - } -} - -bool MatchGen::isHandled( TNode n ) { - if( n.getKind()!=BOUND_VARIABLE && n.hasBoundVar() ){ - if( !isHandledBoolConnective( n ) && !isHandledUfTerm( n ) && n.getKind()!=EQUAL && n.getKind()!=ITE ){ - return false; - } - for( unsigned i=0; i<n.getNumChildren(); i++ ){ - if( !isHandled( n[i] ) ){ - return false; - } - } - } - return true; -} - - -QuantConflictFind::QuantConflictFind( QuantifiersEngine * qe, context::Context* c ) : -QuantifiersModule( qe ), -d_c( c ), -d_conflict( c, false ), -d_qassert( c ) { - d_fid_count = 0; - d_true = NodeManager::currentNM()->mkConst<bool>(true); - d_false = NodeManager::currentNM()->mkConst<bool>(false); -} - -Node QuantConflictFind::mkEqNode( Node a, Node b ) { - if( a.getType().isBoolean() ){ - return a.iffNode( b ); - }else{ - return a.eqNode( b ); - } -} - -//-------------------------------------------------- registration - -void QuantConflictFind::registerQuantifier( Node q ) { - if( !TermDb::isRewriteRule( q ) ){ - d_quants.push_back( q ); - d_quant_id[q] = d_quants.size(); - Trace("qcf-qregister") << "Register "; - debugPrintQuant( "qcf-qregister", q ); - Trace("qcf-qregister") << " : " << q << std::endl; - //make QcfNode structure - Trace("qcf-qregister") << "- Get relevant equality/disequality pairs, calculate flattening..." << std::endl; - d_qinfo[q].initialize( q, q[1] ); - - //debug print - Trace("qcf-qregister") << "- Flattened structure is :" << std::endl; - Trace("qcf-qregister") << " "; - debugPrintQuantBody( "qcf-qregister", q, q[1] ); - Trace("qcf-qregister") << std::endl; - if( d_qinfo[q].d_vars.size()>q[0].getNumChildren() ){ - Trace("qcf-qregister") << " with additional constraints : " << std::endl; - for( unsigned j=q[0].getNumChildren(); j<d_qinfo[q].d_vars.size(); j++ ){ - Trace("qcf-qregister") << " ?x" << j << " = "; - debugPrintQuantBody( "qcf-qregister", q, d_qinfo[q].d_vars[j], false ); - Trace("qcf-qregister") << std::endl; - } - } - - Trace("qcf-qregister") << "Done registering quantifier." << std::endl; - } -} - -int QuantConflictFind::evaluate( Node n, bool pref, bool hasPref ) { - int ret = 0; - if( n.getKind()==EQUAL ){ - Node n1 = evaluateTerm( n[0] ); - Node n2 = evaluateTerm( n[1] ); - Debug("qcf-eval") << "Evaluate : Normalize " << n << " to " << n1 << " = " << n2 << std::endl; - if( areEqual( n1, n2 ) ){ - ret = 1; - }else if( areDisequal( n1, n2 ) ){ - ret = -1; - } - //else if( d_effort>QuantConflictFind::effort_conflict ){ - // ret = -1; - //} - }else if( MatchGen::isHandledUfTerm( n ) ){ //predicate - Node nn = evaluateTerm( n ); - Debug("qcf-eval") << "Evaluate : Normalize " << nn << " to " << n << std::endl; - if( areEqual( nn, d_true ) ){ - ret = 1; - }else if( areEqual( nn, d_false ) ){ - ret = -1; - } - //else if( d_effort>QuantConflictFind::effort_conflict ){ - // ret = -1; - //} - }else if( n.getKind()==NOT ){ - return -evaluate( n[0] ); - }else if( n.getKind()==ITE ){ - int cev1 = evaluate( n[0] ); - int cevc[2] = { 0, 0 }; - for( unsigned i=0; i<2; i++ ){ - if( ( i==0 && cev1!=-1 ) || ( i==1 && cev1!=1 ) ){ - cevc[i] = evaluate( n[i+1] ); - if( cev1!=0 ){ - ret = cevc[i]; - break; - }else if( cevc[i]==0 ){ - break; - } - } - } - if( ret==0 && cevc[0]!=0 && cevc[0]==cevc[1] ){ - ret = cevc[0]; - } - }else if( n.getKind()==IFF ){ - int cev1 = evaluate( n[0] ); - if( cev1!=0 ){ - int cev2 = evaluate( n[1] ); - if( cev2!=0 ){ - ret = cev1==cev2 ? 1 : -1; - } - } - - }else{ - int ssval = 0; - if( n.getKind()==OR ){ - ssval = 1; - }else if( n.getKind()==AND ){ - ssval = -1; - } - bool isUnk = false; - for( unsigned i=0; i<n.getNumChildren(); i++ ){ - int cev = evaluate( n[i] ); - if( cev==ssval ){ - ret = ssval; - break; - }else if( cev==0 ){ - isUnk = true; - } - } - if( ret==0 && !isUnk ){ - ret = -ssval; - } - } - Debug("qcf-eval") << "Evaluate " << n << " to " << ret << std::endl; - return ret; -} - -short QuantConflictFind::getMaxQcfEffort() { - if( options::qcfMode()==QCF_CONFLICT_ONLY ){ - return effort_conflict; - }else if( options::qcfMode()==QCF_PROP_EQ ){ - return effort_prop_eq; - }else if( options::qcfMode()==QCF_MC ){ - return effort_mc; - }else{ - return 0; - } -} - -bool QuantConflictFind::areMatchEqual( TNode n1, TNode n2 ) { - //if( d_effort==QuantConflictFind::effort_mc ){ - // return n1==n2 || !areDisequal( n1, n2 ); - //}else{ - return n1==n2; - //} -} - -bool QuantConflictFind::areMatchDisequal( TNode n1, TNode n2 ) { - //if( d_effort==QuantConflictFind::effort_conflict ){ - // return areDisequal( n1, n2 ); - //}else{ - return n1!=n2; - //} -} - -//-------------------------------------------------- handling assertions / eqc - -void QuantConflictFind::assertNode( Node q ) { - if( !TermDb::isRewriteRule( q ) ){ - Trace("qcf-proc") << "QCF : assertQuantifier : "; - debugPrintQuant("qcf-proc", q); - Trace("qcf-proc") << std::endl; - d_qassert.push_back( q ); - //set the eqRegistries that this depends on to true - //for( std::map< EqRegistry *, bool >::iterator it = d_qinfo[q].d_rel_eqr.begin(); it != d_qinfo[q].d_rel_eqr.end(); ++it ){ - // it->first->d_active.set( true ); - //} - } -} - -eq::EqualityEngine * QuantConflictFind::getEqualityEngine() { - //return ((uf::TheoryUF*)d_quantEngine->getTheoryEngine()->theoryOf( theory::THEORY_UF ))->getEqualityEngine(); - return d_quantEngine->getTheoryEngine()->getMasterEqualityEngine(); -} -bool QuantConflictFind::areEqual( Node n1, Node n2 ) { - return getEqualityEngine()->hasTerm( n1 ) && getEqualityEngine()->hasTerm( n2 ) && getEqualityEngine()->areEqual( n1,n2 ); -} -bool QuantConflictFind::areDisequal( Node n1, Node n2 ) { - return n1!=n2 && getEqualityEngine()->hasTerm( n1 ) && getEqualityEngine()->hasTerm( n2 ) && getEqualityEngine()->areDisequal( n1,n2, false ); -} -Node QuantConflictFind::getRepresentative( Node n ) { - if( getEqualityEngine()->hasTerm( n ) ){ - return getEqualityEngine()->getRepresentative( n ); - }else{ - return n; - } -} -Node QuantConflictFind::evaluateTerm( Node n ) { - if( MatchGen::isHandledUfTerm( n ) ){ - Node f = MatchGen::getOperator( this, n ); - Node nn; - computeUfTerms( f ); - if( getEqualityEngine()->hasTerm( n ) ){ - computeArgReps( n ); - nn = d_uf_terms[f].existsTerm( n, d_arg_reps[n] ); - }else{ - std::vector< TNode > args; - for( unsigned i=0; i<n.getNumChildren(); i++ ){ - Node c = evaluateTerm( n[i] ); - args.push_back( c ); - } - nn = d_uf_terms[f].existsTerm( n, args ); - } - if( !nn.isNull() ){ - Debug("qcf-eval") << "GT: Term " << nn << " for " << n << " hasTerm = " << getEqualityEngine()->hasTerm( n ) << std::endl; - return getRepresentative( nn ); - }else{ - Debug("qcf-eval") << "GT: No term for " << n << " hasTerm = " << getEqualityEngine()->hasTerm( n ) << std::endl; - return n; - } - }else if( n.getKind()==ITE ){ - int v = evaluate( n[0], false, false ); - if( v==1 ){ - return evaluateTerm( n[1] ); - }else if( v==-1 ){ - return evaluateTerm( n[2] ); - } - } - return getRepresentative( n ); -} - -/* -QuantConflictFind::EqcInfo * QuantConflictFind::getEqcInfo( Node n, bool doCreate ) { - std::map< Node, EqcInfo * >::iterator it2 = d_eqc_info.find( n ); - if( it2==d_eqc_info.end() ){ - if( doCreate ){ - EqcInfo * eqci = new EqcInfo( d_c ); - d_eqc_info[n] = eqci; - return eqci; - }else{ - return NULL; - } - } - return it2->second; -} -*/ - -QcfNodeIndex * QuantConflictFind::getQcfNodeIndex( Node eqc, Node f ) { - computeUfTerms( f ); - std::map< TNode, QcfNodeIndex >::iterator itut = d_eqc_uf_terms.find( f ); - if( itut==d_eqc_uf_terms.end() ){ - return NULL; - }else{ - if( eqc.isNull() ){ - return &itut->second; - }else{ - std::map< TNode, QcfNodeIndex >::iterator itute = itut->second.d_children.find( eqc ); - if( itute!=itut->second.d_children.end() ){ - return &itute->second; - }else{ - return NULL; - } - } - } -} - -QcfNodeIndex * QuantConflictFind::getQcfNodeIndex( Node f ) { - computeUfTerms( f ); - std::map< TNode, QcfNodeIndex >::iterator itut = d_uf_terms.find( f ); - if( itut!=d_uf_terms.end() ){ - return &itut->second; - }else{ - return NULL; - } -} - -/** new node */ -void QuantConflictFind::newEqClass( Node n ) { - //Trace("qcf-proc-debug") << "QCF : newEqClass : " << n << std::endl; - //Trace("qcf-proc2-debug") << "QCF : finished newEqClass : " << n << std::endl; -} - -/** merge */ -void QuantConflictFind::merge( Node a, Node b ) { - /* - if( b.getKind()==EQUAL ){ - if( a==d_true ){ - //will merge anyways - //merge( b[0], b[1] ); - }else if( a==d_false ){ - assertDisequal( b[0], b[1] ); - } - }else{ - Trace("qcf-proc") << "QCF : merge : " << a << " " << b << std::endl; - EqcInfo * eqc_b = getEqcInfo( b, false ); - EqcInfo * eqc_a = NULL; - if( eqc_b ){ - eqc_a = getEqcInfo( a ); - //move disequalities of b into a - for( NodeBoolMap::iterator it = eqc_b->d_diseq.begin(); it != eqc_b->d_diseq.end(); ++it ){ - if( (*it).second ){ - Node n = (*it).first; - EqcInfo * eqc_n = getEqcInfo( n, false ); - Assert( eqc_n ); - if( !eqc_n->isDisequal( a ) ){ - Assert( !eqc_a->isDisequal( n ) ); - eqc_n->setDisequal( a ); - eqc_a->setDisequal( n ); - //setEqual( eqc_a, eqc_b, a, n, false ); - } - eqc_n->setDisequal( b, false ); - } - } - ////move all previous EqcRegistry's regarding equalities within b - //for( NodeBoolMap::iterator it = eqc_b->d_rel_eqr_e.begin(); it != eqc_b->d_rel_eqr_e.end(); ++it ){ - // if( (*it).second ){ - // eqc_a->d_rel_eqr_e[(*it).first] = true; - // } - //} - } - //process new equalities - //setEqual( eqc_a, eqc_b, a, b, true ); - Trace("qcf-proc2") << "QCF : finished merge : " << a << " " << b << std::endl; - } - */ -} - -/** assert disequal */ -void QuantConflictFind::assertDisequal( Node a, Node b ) { - /* - a = getRepresentative( a ); - b = getRepresentative( b ); - Trace("qcf-proc") << "QCF : assert disequal : " << a << " " << b << std::endl; - EqcInfo * eqc_a = getEqcInfo( a ); - EqcInfo * eqc_b = getEqcInfo( b ); - if( !eqc_a->isDisequal( b ) ){ - Assert( !eqc_b->isDisequal( a ) ); - eqc_b->setDisequal( a ); - eqc_a->setDisequal( b ); - //setEqual( eqc_a, eqc_b, a, b, false ); - } - Trace("qcf-proc2") << "QCF : finished assert disequal : " << a << " " << b << std::endl; - */ -} - -//-------------------------------------------------- check function - -void QuantConflictFind::reset_round( Theory::Effort level ) { - d_needs_computeRelEqr = true; -} - -/** check */ -void QuantConflictFind::check( Theory::Effort level ) { - Trace("qcf-check") << "QCF : check : " << level << std::endl; - if( d_conflict ){ - Trace("qcf-check2") << "QCF : finished check : already in conflict." << std::endl; - if( level>=Theory::EFFORT_FULL ){ - Trace("qcf-warn") << "ALREADY IN CONFLICT? " << level << std::endl; - //Assert( false ); - } - }else{ - int addedLemmas = 0; - if( d_performCheck ){ - ++(d_statistics.d_inst_rounds); - double clSet = 0; - int prevEt = 0; - if( Trace.isOn("qcf-engine") ){ - prevEt = d_statistics.d_entailment_checks.getData(); - clSet = double(clock())/double(CLOCKS_PER_SEC); - Trace("qcf-engine") << "---Conflict Find Engine Round, effort = " << level << "---" << std::endl; - } - computeRelevantEqr(); - - //determine order for quantified formulas - std::vector< Node > qorder; - std::map< Node, bool > qassert; - //mark which are asserted - for( unsigned i=0; i<d_qassert.size(); i++ ){ - qassert[d_qassert[i]] = true; - } - //add which ones are specified in the order - for( unsigned i=0; i<d_quant_order.size(); i++ ){ - Node n = d_quant_order[i]; - if( std::find( qorder.begin(), qorder.end(), n )==qorder.end() && qassert.find( n )!=qassert.end() ){ - qorder.push_back( n ); - } - } - d_quant_order.clear(); - d_quant_order.insert( d_quant_order.begin(), qorder.begin(), qorder.end() ); - //add remaining - for( unsigned i=0; i<d_qassert.size(); i++ ){ - Node n = d_qassert[i]; - if( std::find( qorder.begin(), qorder.end(), n )==qorder.end() ){ - qorder.push_back( n ); - } - } - - if( Trace.isOn("qcf-debug") ){ - Trace("qcf-debug") << std::endl; - debugPrint("qcf-debug"); - Trace("qcf-debug") << std::endl; - } - short end_e = getMaxQcfEffort(); - for( short e = effort_conflict; e<=end_e; e++ ){ - d_effort = e; - Trace("qcf-check") << "Checking quantified formulas at effort " << e << "..." << std::endl; - for( unsigned j=0; j<qorder.size(); j++ ){ - Node q = qorder[j]; - QuantInfo * qi = &d_qinfo[q]; - - Assert( d_qinfo.find( q )!=d_qinfo.end() ); - if( qi->d_mg->isValid() ){ - Trace("qcf-check") << "Check quantified formula "; - debugPrintQuant("qcf-check", q); - Trace("qcf-check") << " : " << q << "..." << std::endl; - - Trace("qcf-check-debug") << "Reset round..." << std::endl; - qi->reset_round( this ); - //try to make a matches making the body false - Trace("qcf-check-debug") << "Get next match..." << std::endl; - while( qi->d_mg->getNextMatch( this, qi ) ){ - Trace("qcf-check") << "*** Produced match at effort " << e << " : " << std::endl; - qi->debugPrintMatch("qcf-check"); - Trace("qcf-check") << std::endl; - std::vector< int > assigned; - if( !qi->isMatchSpurious( this ) ){ - if( qi->completeMatch( this, assigned ) ){ - /* - if( options::qcfExp() && d_effort==effort_conflict ){ - std::vector< Node > exp; - if( qi->d_mg->getExplanation( this, qi, exp ) ){ - Trace("qcf-check-exp") << "Base explanation is : " << std::endl; - for( unsigned c=0; c<exp.size(); c++ ){ - Trace("qcf-check-exp") << " " << exp[c] << std::endl; - } - std::vector< TNode > c_exp; - eq::EqualityEngine* ee = ((uf::TheoryUF*)d_quantEngine->getTheoryEngine()->theoryOf( THEORY_UF ))->getEqualityEngine() ; - for( unsigned c=0; c<exp.size(); c++ ){ - bool pol = exp[c].getKind()!=NOT; - TNode lit = pol ? exp[c] : exp[c][0]; - Trace("qcf-check-exp") << "Explain " << lit << ", polarity " << pol << std::endl; - if( lit.getKind()==EQUAL ){ - if( !pol && !ee->areDisequal( lit[0], lit[1], true ) ){ - exit( 98 ); - }else if( pol && !ee->areEqual( lit[0], lit[1] ) ){ - exit( 99 ); - } - ee->explainEquality( lit[0], lit[1], pol, c_exp ); - }else{ - if( !ee->areEqual( lit, pol ? d_true : d_false ) ){ - exit( pol ? 96 : 97 ); - } - ee->explainPredicate( lit, pol, c_exp ); - } - } - std::vector< Node > c_lem; - Trace("qcf-check-exp") << "Actual explanation is : " << std::endl; - for( unsigned c=0; c<c_exp.size(); c++ ){ - Trace("qcf-check-exp") << " " << c_exp[c] << std::endl; - Node ccc = c_exp[c].negate(); - if( std::find( c_lem.begin(), c_lem.end(), ccc )==c_lem.end() ){ - c_lem.push_back( ccc ); - } - } - - c_lem.push_back( q.negate() ); - Node conf = NodeManager::currentNM()->mkNode( OR, c_lem ); - Trace("qcf-conflict") << "QCF conflict : " << conf << std::endl; - d_quantEngine->addLemma( conf, false ); - d_conflict.set( true ); - ++(d_statistics.d_conflict_inst); - ++addedLemmas; - break; - } - } - */ - std::vector< Node > terms; - qi->getMatch( terms ); - if( !qi->isTConstraintSpurious( this, terms ) ){ - if( Debug.isOn("qcf-check-inst") ){ - //if( e==effort_conflict ){ - Node inst = d_quantEngine->getInstantiation( q, terms ); - Debug("qcf-check-inst") << "Check instantiation " << inst << "..." << std::endl; - Assert( evaluate( inst )!=1 ); - Assert( evaluate( inst )==-1 || e>effort_conflict ); - //} - } - if( d_quantEngine->addInstantiation( q, terms, false ) ){ - Trace("qcf-check") << " ... Added instantiation" << std::endl; - Trace("qcf-inst") << "*** Was from effort " << e << " : " << std::endl; - qi->debugPrintMatch("qcf-inst"); - Trace("qcf-inst") << std::endl; - ++addedLemmas; - if( e==effort_conflict ){ - d_quant_order.insert( d_quant_order.begin(), q ); - d_conflict.set( true ); - ++(d_statistics.d_conflict_inst); - break; - }else if( e==effort_prop_eq ){ - ++(d_statistics.d_prop_inst); - } - }else{ - Trace("qcf-check") << " ... Failed to add instantiation" << std::endl; - //Assert( false ); - } - } - //clean up assigned - qi->revertMatch( assigned ); - d_tempCache.clear(); - }else{ - Trace("qcf-check") << " ... Spurious instantiation (cannot assign unassigned variables)" << std::endl; - } - }else{ - Trace("qcf-check") << " ... Spurious instantiation (match is inconsistent)" << std::endl; - } - } - if( d_conflict ){ - break; - } - } - } - if( addedLemmas>0 ){ - d_quantEngine->flushLemmas(); - break; - } - } - if( Trace.isOn("qcf-engine") ){ - double clSet2 = double(clock())/double(CLOCKS_PER_SEC); - Trace("qcf-engine") << "Finished conflict find engine, time = " << (clSet2-clSet); - if( addedLemmas>0 ){ - Trace("qcf-engine") << ", effort = " << ( d_effort==effort_conflict ? "conflict" : ( d_effort==effort_prop_eq ? "prop_eq" : "mc" ) ); - Trace("qcf-engine") << ", addedLemmas = " << addedLemmas; - } - Trace("qcf-engine") << std::endl; - int currEt = d_statistics.d_entailment_checks.getData(); - if( currEt!=prevEt ){ - Trace("qcf-engine") << " Entailment checks = " << ( currEt - prevEt ) << std::endl; - } - } - } - Trace("qcf-check2") << "QCF : finished check : " << level << std::endl; - } -} - -bool QuantConflictFind::needsCheck( Theory::Effort level ) { - d_performCheck = false; - if( options::quantConflictFind() && !d_conflict ){ - if( level==Theory::EFFORT_LAST_CALL ){ - d_performCheck = options::qcfWhenMode()==QCF_WHEN_MODE_LAST_CALL; - }else if( level==Theory::EFFORT_FULL ){ - d_performCheck = options::qcfWhenMode()==QCF_WHEN_MODE_DEFAULT; - }else if( level==Theory::EFFORT_STANDARD ){ - d_performCheck = options::qcfWhenMode()==QCF_WHEN_MODE_STD; - } - } - return d_performCheck; -} - -void QuantConflictFind::computeRelevantEqr() { - if( d_needs_computeRelEqr ){ - d_needs_computeRelEqr = false; - Trace("qcf-check") << "Compute relevant equalities..." << std::endl; - d_uf_terms.clear(); - d_eqc_uf_terms.clear(); - d_eqcs.clear(); - d_model_basis.clear(); - d_arg_reps.clear(); - //double clSet = 0; - //if( Trace.isOn("qcf-opt") ){ - // clSet = double(clock())/double(CLOCKS_PER_SEC); - //} - - //long nTermst = 0; - //long nTerms = 0; - //long nEqc = 0; - - //which nodes are irrelevant for disequality matches - std::map< TNode, bool > irrelevant_dnode; - //now, store matches - eq::EqClassesIterator eqcs_i = eq::EqClassesIterator( getEqualityEngine() ); - while( !eqcs_i.isFinished() ){ - //nEqc++; - Node r = (*eqcs_i); - TypeNode rtn = r.getType(); - if( options::qcfMode()==QCF_MC ){ - std::map< TypeNode, std::vector< TNode > >::iterator itt = d_eqcs.find( rtn ); - if( itt==d_eqcs.end() ){ - Node mb = getQuantifiersEngine()->getTermDatabase()->getModelBasisTerm( rtn ); - if( !getEqualityEngine()->hasTerm( mb ) ){ - Trace("qcf-warn") << "WARNING: Model basis term does not exist!" << std::endl; - Assert( false ); - } - Node mbr = getRepresentative( mb ); - if( mbr!=r ){ - d_eqcs[rtn].push_back( mbr ); - } - d_eqcs[rtn].push_back( r ); - d_model_basis[rtn] = mb; - }else{ - itt->second.push_back( r ); - } - }else{ - d_eqcs[rtn].push_back( r ); - } - /* - eq::EqClassIterator eqc_i = eq::EqClassIterator( r, getEqualityEngine() ); - while( !eqc_i.isFinished() ){ - TNode n = (*eqc_i); - if( n.hasBoundVar() ){ - std::cout << "BAD TERM IN DB : " << n << std::endl; - exit( 199 ); - } - ++eqc_i; - } - - */ - - //if( r.getType().isInteger() ){ - // Trace("qcf-mv") << "Model value for eqc(" << r << ") : " << d_quantEngine->getValuation().getModelValue( r ) << std::endl; - //} - //EqcInfo * eqcir = getEqcInfo( r, false ); - //get relevant nodes that we are disequal from - /* - std::vector< Node > deqc; - if( eqcir ){ - for( NodeBoolMap::iterator it = eqcir->d_diseq.begin(); it != eqcir->d_diseq.end(); ++it ){ - if( (*it).second ){ - //Node rd = (*it).first; - //if( rd!=getRepresentative( rd ) ){ - // std::cout << "Bad rep!" << std::endl; - // exit( 0 ); - //} - deqc.push_back( (*it).first ); - } - } - } - */ - //process disequalities - /* - eq::EqClassIterator eqc_i = eq::EqClassIterator( r, getEqualityEngine() ); - while( !eqc_i.isFinished() ){ - TNode n = (*eqc_i); - if( n.getKind()!=EQUAL ){ - nTermst++; - //node_to_rep[n] = r; - //if( n.getNumChildren()>0 ){ - // if( n.getKind()!=APPLY_UF ){ - // std::cout << n.getKind() << " " << n.getOperator() << " " << n << std::endl; - // } - //} - if( !quantifiers::TermDb::hasBoundVarAttr( n ) ){ //temporary - - bool isRedundant; - std::map< TNode, std::vector< TNode > >::iterator it_na; - TNode fn; - if( MatchGen::isHandledUfTerm( n ) ){ - Node f = MatchGen::getOperator( this, n ); - computeArgReps( n ); - it_na = d_arg_reps.find( n ); - Assert( it_na!=d_arg_reps.end() ); - Node nadd = d_eqc_uf_terms[f].d_children[r].addTerm( n, d_arg_reps[n] ); - isRedundant = (nadd!=n); - d_uf_terms[f].addTerm( n, d_arg_reps[n] ); - }else{ - isRedundant = false; - } - nTerms += isRedundant ? 0 : 1; - }else{ - if( Debug.isOn("qcf-nground") ){ - Debug("qcf-nground") << "Non-ground term in eqc : " << n << std::endl; - Assert( false ); - } - } - } - ++eqc_i; - } - */ - ++eqcs_i; - } - /* - if( Trace.isOn("qcf-opt") ){ - double clSet2 = double(clock())/double(CLOCKS_PER_SEC); - Trace("qcf-opt") << "Compute rel eqc : " << std::endl; - Trace("qcf-opt") << " " << nEqc << " equivalence classes. " << std::endl; - Trace("qcf-opt") << " " << nTerms << " / " << nTermst << " terms." << std::endl; - Trace("qcf-opt") << " Time : " << (clSet2-clSet) << std::endl; - } - */ - } -} - -void QuantConflictFind::computeArgReps( TNode n ) { - if( d_arg_reps.find( n )==d_arg_reps.end() ){ - Assert( MatchGen::isHandledUfTerm( n ) ); - for( unsigned j=0; j<n.getNumChildren(); j++ ){ - d_arg_reps[n].push_back( getRepresentative( n[j] ) ); - } - } -} - -void QuantConflictFind::computeUfTerms( TNode f ) { - if( d_uf_terms.find( f )==d_uf_terms.end() ){ - d_uf_terms[f].clear(); - unsigned nt = d_quantEngine->getTermDatabase()->getNumGroundTerms( f ); - for( unsigned i=0; i<nt; i++ ){ - Node n = d_quantEngine->getTermDatabase()->d_op_map[f][i]; - if( getEqualityEngine()->hasTerm( n ) && !n.getAttribute(NoMatchAttribute()) ){ - Node r = getRepresentative( n ); - computeArgReps( n ); - d_eqc_uf_terms[f].d_children[r].addTerm( n, d_arg_reps[n] ); - d_uf_terms[f].addTerm( n, d_arg_reps[n] ); - } - } - } -} - -//-------------------------------------------------- debugging - - -void QuantConflictFind::debugPrint( const char * c ) { - //print the equivalance classes - Trace(c) << "----------EQ classes" << std::endl; - eq::EqClassesIterator eqcs_i = eq::EqClassesIterator( getEqualityEngine() ); - while( !eqcs_i.isFinished() ){ - Node n = (*eqcs_i); - //if( !n.getType().isInteger() ){ - Trace(c) << " - " << n << " : {"; - eq::EqClassIterator eqc_i = eq::EqClassIterator( n, getEqualityEngine() ); - bool pr = false; - while( !eqc_i.isFinished() ){ - Node nn = (*eqc_i); - if( nn.getKind()!=EQUAL && nn!=n ){ - Trace(c) << (pr ? "," : "" ) << " " << nn; - pr = true; - } - ++eqc_i; - } - Trace(c) << (pr ? " " : "" ) << "}" << std::endl; - /* - EqcInfo * eqcn = getEqcInfo( n, false ); - if( eqcn ){ - Trace(c) << " DEQ : {"; - pr = false; - for( NodeBoolMap::iterator it = eqcn->d_diseq.begin(); it != eqcn->d_diseq.end(); ++it ){ - if( (*it).second ){ - Trace(c) << (pr ? "," : "" ) << " " << (*it).first; - pr = true; - } - } - Trace(c) << (pr ? " " : "" ) << "}" << std::endl; - } - //} - */ - ++eqcs_i; - } -} - -void QuantConflictFind::debugPrintQuant( const char * c, Node q ) { - Trace(c) << "Q" << d_quant_id[q]; -} - -void QuantConflictFind::debugPrintQuantBody( const char * c, Node q, Node n, bool doVarNum ) { - if( n.getNumChildren()==0 ){ - Trace(c) << n; - }else if( doVarNum && d_qinfo[q].d_var_num.find( n )!=d_qinfo[q].d_var_num.end() ){ - Trace(c) << "?x" << d_qinfo[q].d_var_num[n]; - }else{ - Trace(c) << "("; - if( n.getKind()==APPLY_UF ){ - Trace(c) << n.getOperator(); - }else{ - Trace(c) << n.getKind(); - } - for( unsigned i=0; i<n.getNumChildren(); i++ ){ - Trace(c) << " "; - debugPrintQuantBody( c, q, n[i] ); - } - Trace(c) << ")"; - } -} - -QuantConflictFind::Statistics::Statistics(): - d_inst_rounds("QuantConflictFind::Inst_Rounds", 0), - d_conflict_inst("QuantConflictFind::Instantiations_Conflict_Find", 0 ), - d_prop_inst("QuantConflictFind::Instantiations_Prop", 0 ), - d_entailment_checks("QuantConflictFind::Entailment_Checks",0) -{ - StatisticsRegistry::registerStat(&d_inst_rounds); - StatisticsRegistry::registerStat(&d_conflict_inst); - StatisticsRegistry::registerStat(&d_prop_inst); - StatisticsRegistry::registerStat(&d_entailment_checks); -} - -QuantConflictFind::Statistics::~Statistics(){ - StatisticsRegistry::unregisterStat(&d_inst_rounds); - StatisticsRegistry::unregisterStat(&d_conflict_inst); - StatisticsRegistry::unregisterStat(&d_prop_inst); - StatisticsRegistry::unregisterStat(&d_entailment_checks); -} - -TNode QuantConflictFind::getZero( Kind k ) { - std::map< Kind, Node >::iterator it = d_zero.find( k ); - if( it==d_zero.end() ){ - Node nn; - if( k==PLUS ){ - nn = NodeManager::currentNM()->mkConst( Rational(0) ); - } - d_zero[k] = nn; - return nn; - }else{ - return it->second; - } -} - - -} +/********************* */
+/*! \file quant_conflict_find.cpp
+ ** \verbatim
+ ** Original author: Andrew Reynolds
+ ** Major contributors: none
+ ** Minor contributors (to current version): none
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2014 New York University and The University of Iowa
+ ** See the file COPYING in the top-level source directory for licensing
+ ** information.\endverbatim
+ **
+ ** \brief quant conflict find class
+ **
+ **/
+
+#include <vector>
+
+#include "theory/quantifiers/quant_conflict_find.h"
+#include "theory/quantifiers/quant_util.h"
+#include "theory/theory_engine.h"
+#include "theory/quantifiers/options.h"
+#include "theory/quantifiers/term_database.h"
+#include "theory/quantifiers/trigger.h"
+
+using namespace CVC4;
+using namespace CVC4::kind;
+using namespace CVC4::theory;
+using namespace CVC4::theory::quantifiers;
+using namespace std;
+
+namespace CVC4 {
+
+
+
+void QuantInfo::initialize( Node q, Node qn ) {
+ d_q = q;
+ for( unsigned i=0; i<q[0].getNumChildren(); i++ ){
+ d_match.push_back( TNode::null() );
+ d_match_term.push_back( TNode::null() );
+ }
+
+ //register the variables
+ for( unsigned i=0; i<q[0].getNumChildren(); i++ ){
+ d_var_num[q[0][i]] = i;
+ d_vars.push_back( q[0][i] );
+ }
+
+ registerNode( qn, true, true );
+
+
+ Trace("qcf-qregister") << "- Make match gen structure..." << std::endl;
+ d_mg = new MatchGen( this, qn );
+
+ if( d_mg->isValid() ){
+ /*
+ for( unsigned j=0; j<q[0].getNumChildren(); j++ ){
+ if( d_inMatchConstraint.find( q[0][j] )==d_inMatchConstraint.end() ){
+ Trace("qcf-invalid") << "QCF invalid : variable " << q[0][j] << " does not exist in a matching constraint." << std::endl;
+ d_mg->setInvalid();
+ break;
+ }
+ }
+ */
+ if( d_mg->isValid() ){
+ for( unsigned j=q[0].getNumChildren(); j<d_vars.size(); j++ ){
+ if( d_vars[j].getKind()!=BOUND_VARIABLE ){
+ d_var_mg[j] = NULL;
+ bool is_tsym = false;
+ if( !MatchGen::isHandledUfTerm( d_vars[j] ) && d_vars[j].getKind()!=ITE ){
+ is_tsym = true;
+ d_tsym_vars.push_back( j );
+ }
+ if( !is_tsym || options::qcfTConstraint() ){
+ d_var_mg[j] = new MatchGen( this, d_vars[j], true );
+ }
+ if( !d_var_mg[j] || !d_var_mg[j]->isValid() ){
+ Trace("qcf-invalid") << "QCF invalid : cannot match for " << d_vars[j] << std::endl;
+ d_mg->setInvalid();
+ break;
+ }else{
+ std::vector< int > bvars;
+ d_var_mg[j]->determineVariableOrder( this, bvars );
+ }
+ }
+ }
+ if( d_mg->isValid() ){
+ std::vector< int > bvars;
+ d_mg->determineVariableOrder( this, bvars );
+ }
+ }
+ }else{
+ Trace("qcf-invalid") << "QCF invalid : body of formula cannot be processed." << std::endl;
+ }
+ Trace("qcf-qregister-summary") << "QCF register : " << ( d_mg->isValid() ? "VALID " : "INVALID" ) << " : " << q << std::endl;
+}
+
+void QuantInfo::registerNode( Node n, bool hasPol, bool pol, bool beneathQuant ) {
+ Trace("qcf-qregister-debug2") << "Register : " << n << std::endl;
+ if( n.getKind()==FORALL ){
+ registerNode( n[1], hasPol, pol, true );
+ }else{
+ if( !MatchGen::isHandledBoolConnective( n ) ){
+ if( n.hasBoundVar() ){
+ //literals
+ if( n.getKind()==EQUAL ){
+ for( unsigned i=0; i<n.getNumChildren(); i++ ){
+ flatten( n[i], beneathQuant );
+ }
+ }else if( MatchGen::isHandledUfTerm( n ) ){
+ flatten( n, beneathQuant );
+ }else if( n.getKind()==ITE ){
+ for( unsigned i=1; i<=2; i++ ){
+ flatten( n[i], beneathQuant );
+ }
+ registerNode( n[0], false, pol, beneathQuant );
+ }else if( options::qcfTConstraint() ){
+ //a theory-specific predicate
+ for( unsigned i=0; i<n.getNumChildren(); i++ ){
+ flatten( n[i], beneathQuant );
+ }
+ }
+ }
+ }else{
+ for( unsigned i=0; i<n.getNumChildren(); i++ ){
+ bool newHasPol;
+ bool newPol;
+ QuantPhaseReq::getPolarity( n, i, hasPol, pol, newHasPol, newPol );
+ //QcfNode * qcfc = new QcfNode( d_c );
+ //qcfc->d_parent = qcf;
+ //qcf->d_child[i] = qcfc;
+ registerNode( n[i], newHasPol, newPol, beneathQuant );
+ }
+ }
+ }
+}
+
+void QuantInfo::flatten( Node n, bool beneathQuant ) {
+ Trace("qcf-qregister-debug2") << "Flatten : " << n << std::endl;
+ if( n.hasBoundVar() ){
+ if( n.getKind()==BOUND_VARIABLE ){
+ d_inMatchConstraint[n] = true;
+ }
+ //if( MatchGen::isHandledUfTerm( n ) || n.getKind()==ITE ){
+ if( d_var_num.find( n )==d_var_num.end() ){
+ Trace("qcf-qregister-debug2") << "Add FLATTEN VAR : " << n << std::endl;
+ d_var_num[n] = d_vars.size();
+ d_vars.push_back( n );
+ d_match.push_back( TNode::null() );
+ d_match_term.push_back( TNode::null() );
+ if( n.getKind()==ITE ){
+ registerNode( n, false, false );
+ }else{
+ for( unsigned i=0; i<n.getNumChildren(); i++ ){
+ flatten( n[i], beneathQuant );
+ }
+ }
+ }else{
+ Trace("qcf-qregister-debug2") << "...already processed" << std::endl;
+ }
+ }else{
+ Trace("qcf-qregister-debug2") << "...is ground." << std::endl;
+ }
+}
+
+
+void QuantInfo::reset_round( QuantConflictFind * p ) {
+ for( unsigned i=0; i<d_match.size(); i++ ){
+ d_match[i] = TNode::null();
+ d_match_term[i] = TNode::null();
+ }
+ d_curr_var_deq.clear();
+ d_tconstraints.clear();
+ //add built-in variable constraints
+ for( unsigned r=0; r<2; r++ ){
+ for( std::map< int, std::vector< Node > >::iterator it = d_var_constraint[r].begin();
+ it != d_var_constraint[r].end(); ++it ){
+ for( unsigned j=0; j<it->second.size(); j++ ){
+ Node rr = it->second[j];
+ if( !isVar( rr ) ){
+ rr = p->getRepresentative( rr );
+ }
+ if( addConstraint( p, it->first, rr, r==0 )==-1 ){
+ d_var_constraint[0].clear();
+ d_var_constraint[1].clear();
+ //quantified formula is actually equivalent to true
+ Trace("qcf-qregister") << "Quantifier is equivalent to true!!!" << std::endl;
+ d_mg->d_children.clear();
+ d_mg->d_n = NodeManager::currentNM()->mkConst( true );
+ d_mg->d_type = MatchGen::typ_ground;
+ return;
+ }
+ }
+ }
+ }
+ d_mg->reset_round( p );
+ for( std::map< int, MatchGen * >::iterator it = d_var_mg.begin(); it != d_var_mg.end(); ++it ){
+ it->second->reset_round( p );
+ }
+ //now, reset for matching
+ d_mg->reset( p, false, this );
+}
+
+int QuantInfo::getCurrentRepVar( int v ) {
+ if( v!=-1 && !d_match[v].isNull() ){
+ int vn = getVarNum( d_match[v] );
+ if( vn!=-1 ){
+ //int vr = getCurrentRepVar( vn );
+ //d_match[v] = d_vars[vr];
+ //return vr;
+ return getCurrentRepVar( vn );
+ }
+ }
+ return v;
+}
+
+TNode QuantInfo::getCurrentValue( TNode n ) {
+ int v = getVarNum( n );
+ if( v==-1 ){
+ return n;
+ }else{
+ if( d_match[v].isNull() ){
+ return n;
+ }else{
+ Assert( getVarNum( d_match[v] )!=v );
+ return getCurrentValue( d_match[v] );
+ }
+ }
+}
+
+TNode QuantInfo::getCurrentExpValue( TNode n ) {
+ int v = getVarNum( n );
+ if( v==-1 ){
+ return n;
+ }else{
+ if( d_match[v].isNull() ){
+ return n;
+ }else{
+ Assert( getVarNum( d_match[v] )!=v );
+ if( d_match_term[v].isNull() ){
+ return getCurrentValue( d_match[v] );
+ }else{
+ return d_match_term[v];
+ }
+ }
+ }
+}
+
+bool QuantInfo::getCurrentCanBeEqual( QuantConflictFind * p, int v, TNode n, bool chDiseq ) {
+ //check disequalities
+ std::map< int, std::map< TNode, int > >::iterator itd = d_curr_var_deq.find( v );
+ if( itd!=d_curr_var_deq.end() ){
+ for( std::map< TNode, int >::iterator it = itd->second.begin(); it != itd->second.end(); ++it ){
+ Node cv = getCurrentValue( it->first );
+ Debug("qcf-ccbe") << "compare " << cv << " " << n << std::endl;
+ if( cv==n ){
+ return false;
+ }else if( chDiseq && !isVar( n ) && !isVar( cv ) ){
+ //they must actually be disequal if we are looking for conflicts
+ if( !p->areDisequal( n, cv ) ){
+ //TODO : check for entailed disequal
+
+ return false;
+ }
+ }
+ }
+ }
+ return true;
+}
+
+int QuantInfo::addConstraint( QuantConflictFind * p, int v, TNode n, bool polarity ) {
+ v = getCurrentRepVar( v );
+ int vn = getVarNum( n );
+ vn = vn==-1 ? -1 : getCurrentRepVar( vn );
+ n = getCurrentValue( n );
+ return addConstraint( p, v, n, vn, polarity, false );
+}
+
+int QuantInfo::addConstraint( QuantConflictFind * p, int v, TNode n, int vn, bool polarity, bool doRemove ) {
+ //for handling equalities between variables, and disequalities involving variables
+ Debug("qcf-match-debug") << "- " << (doRemove ? "un" : "" ) << "constrain : " << v << " -> " << n << " (cv=" << getCurrentValue( n ) << ")";
+ Debug("qcf-match-debug") << ", (vn=" << vn << "), polarity = " << polarity << std::endl;
+ Assert( doRemove || n==getCurrentValue( n ) );
+ Assert( doRemove || v==getCurrentRepVar( v ) );
+ Assert( doRemove || vn==getCurrentRepVar( getVarNum( n ) ) );
+ if( polarity ){
+ if( vn!=v ){
+ if( doRemove ){
+ if( vn!=-1 ){
+ //if set to this in the opposite direction, clean up opposite instead
+ // std::map< int, TNode >::iterator itmn = d_match.find( vn );
+ if( d_match[vn]==d_vars[v] ){
+ return addConstraint( p, vn, d_vars[v], v, true, true );
+ }else{
+ //unsetting variables equal
+ std::map< int, std::map< TNode, int > >::iterator itd = d_curr_var_deq.find( vn );
+ if( itd!=d_curr_var_deq.end() ){
+ //remove disequalities owned by this
+ std::vector< TNode > remDeq;
+ for( std::map< TNode, int >::iterator it = itd->second.begin(); it != itd->second.end(); ++it ){
+ if( it->second==v ){
+ remDeq.push_back( it->first );
+ }
+ }
+ for( unsigned i=0; i<remDeq.size(); i++ ){
+ d_curr_var_deq[vn].erase( remDeq[i] );
+ }
+ }
+ }
+ }
+ d_match[v] = TNode::null();
+ return 1;
+ }else{
+ //std::map< int, TNode >::iterator itm = d_match.find( v );
+
+ if( vn!=-1 ){
+ Debug("qcf-match-debug") << " ...Variable bound to variable" << std::endl;
+ //std::map< int, TNode >::iterator itmn = d_match.find( vn );
+ if( d_match[v].isNull() ){
+ //setting variables equal
+ bool alreadySet = false;
+ if( !d_match[vn].isNull() ){
+ alreadySet = true;
+ Assert( !isVar( d_match[vn] ) );
+ }
+
+ //copy or check disequalities
+ std::map< int, std::map< TNode, int > >::iterator itd = d_curr_var_deq.find( v );
+ if( itd!=d_curr_var_deq.end() ){
+ for( std::map< TNode, int >::iterator it = itd->second.begin(); it != itd->second.end(); ++it ){
+ Node dv = getCurrentValue( it->first );
+ if( !alreadySet ){
+ if( d_curr_var_deq[vn].find( dv )==d_curr_var_deq[vn].end() ){
+ d_curr_var_deq[vn][dv] = v;
+ }
+ }else{
+ if( !p->areMatchDisequal( d_match[vn], dv ) ){
+ Debug("qcf-match-debug") << " -> fail, conflicting disequality" << std::endl;
+ return -1;
+ }
+ }
+ }
+ }
+ if( alreadySet ){
+ n = getCurrentValue( n );
+ }
+ }else{
+ if( d_match[vn].isNull() ){
+ Debug("qcf-match-debug") << " ...Reverse direction" << std::endl;
+ //set the opposite direction
+ return addConstraint( p, vn, d_vars[v], v, true, false );
+ }else{
+ Debug("qcf-match-debug") << " -> Both variables bound, compare" << std::endl;
+ //are they currently equal
+ return p->areMatchEqual( d_match[v], d_match[vn] ) ? 0 : -1;
+ }
+ }
+ }else{
+ Debug("qcf-match-debug") << " ...Variable bound to ground" << std::endl;
+ if( d_match[v].isNull() ){
+ }else{
+ //compare ground values
+ Debug("qcf-match-debug") << " -> Ground value, compare " << d_match[v] << " "<< n << std::endl;
+ return p->areMatchEqual( d_match[v], n ) ? 0 : -1;
+ }
+ }
+ if( setMatch( p, v, n ) ){
+ Debug("qcf-match-debug") << " -> success" << std::endl;
+ return 1;
+ }else{
+ Debug("qcf-match-debug") << " -> fail, conflicting disequality" << std::endl;
+ return -1;
+ }
+ }
+ }else{
+ Debug("qcf-match-debug") << " -> redundant, variable identity" << std::endl;
+ return 0;
+ }
+ }else{
+ if( vn==v ){
+ Debug("qcf-match-debug") << " -> fail, variable identity" << std::endl;
+ return -1;
+ }else{
+ if( doRemove ){
+ Assert( d_curr_var_deq[v].find( n )!=d_curr_var_deq[v].end() );
+ d_curr_var_deq[v].erase( n );
+ return 1;
+ }else{
+ if( d_curr_var_deq[v].find( n )==d_curr_var_deq[v].end() ){
+ //check if it respects equality
+ //std::map< int, TNode >::iterator itm = d_match.find( v );
+ if( !d_match[v].isNull() ){
+ TNode nv = getCurrentValue( n );
+ if( !p->areMatchDisequal( nv, d_match[v] ) ){
+ Debug("qcf-match-debug") << " -> fail, conflicting disequality" << std::endl;
+ return -1;
+ }
+ }
+ d_curr_var_deq[v][n] = v;
+ Debug("qcf-match-debug") << " -> success" << std::endl;
+ return 1;
+ }else{
+ Debug("qcf-match-debug") << " -> redundant disequality" << std::endl;
+ return 0;
+ }
+ }
+ }
+ }
+}
+
+bool QuantInfo::isConstrainedVar( int v ) {
+ if( d_curr_var_deq.find( v )!=d_curr_var_deq.end() && !d_curr_var_deq[v].empty() ){
+ return true;
+ }else{
+ Node vv = getVar( v );
+ //for( std::map< int, TNode >::iterator it = d_match.begin(); it != d_match.end(); ++it ){
+ for( unsigned i=0; i<d_match.size(); i++ ){
+ if( d_match[i]==vv ){
+ return true;
+ }
+ }
+ for( std::map< int, std::map< TNode, int > >::iterator it = d_curr_var_deq.begin(); it != d_curr_var_deq.end(); ++it ){
+ for( std::map< TNode, int >::iterator it2 = it->second.begin(); it2 != it->second.end(); ++it2 ){
+ if( it2->first==vv ){
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+}
+
+bool QuantInfo::setMatch( QuantConflictFind * p, int v, TNode n ) {
+ if( getCurrentCanBeEqual( p, v, n ) ){
+ Debug("qcf-match-debug") << "-- bind : " << v << " -> " << n << ", checked " << d_curr_var_deq[v].size() << " disequalities" << std::endl;
+ d_match[v] = n;
+ return true;
+ }else{
+ return false;
+ }
+}
+
+bool QuantInfo::isMatchSpurious( QuantConflictFind * p ) {
+ for( int i=0; i<getNumVars(); i++ ){
+ //std::map< int, TNode >::iterator it = d_match.find( i );
+ if( !d_match[i].isNull() ){
+ if( !getCurrentCanBeEqual( p, i, d_match[i], p->d_effort==QuantConflictFind::effort_conflict ) ){
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+bool QuantInfo::isTConstraintSpurious( QuantConflictFind * p, std::vector< Node >& terms ) {
+ if( !d_tconstraints.empty() ){
+ //check constraints
+ for( std::map< Node, bool >::iterator it = d_tconstraints.begin(); it != d_tconstraints.end(); ++it ){
+ //apply substitution to the tconstraint
+ Node cons = it->first.substitute( p->getQuantifiersEngine()->getTermDatabase()->d_vars[d_q].begin(),
+ p->getQuantifiersEngine()->getTermDatabase()->d_vars[d_q].end(),
+ terms.begin(), terms.end() );
+ cons = it->second ? cons : cons.negate();
+ if( !entailmentTest( p, cons, p->d_effort==QuantConflictFind::effort_conflict ) ){
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+bool QuantInfo::entailmentTest( QuantConflictFind * p, Node lit, bool chEnt ) {
+ Trace("qcf-tconstraint-debug") << "Check : " << lit << std::endl;
+ Node rew = Rewriter::rewrite( lit );
+ if( rew==p->d_false ){
+ Trace("qcf-tconstraint-debug") << "...constraint " << lit << " is disentailed (rewrites to false)." << std::endl;
+ return false;
+ }else if( rew!=p->d_true ){
+ //if checking for conflicts, we must be sure that the constraint is entailed
+ if( chEnt ){
+ //check if it is entailed
+ Trace("qcf-tconstraint-debug") << "Check entailment of " << rew << "..." << std::endl;
+ std::pair<bool, Node> et = p->getQuantifiersEngine()->getTheoryEngine()->entailmentCheck(THEORY_OF_TYPE_BASED, rew );
+ ++(p->d_statistics.d_entailment_checks);
+ Trace("qcf-tconstraint-debug") << "ET result : " << et.first << " " << et.second << std::endl;
+ if( !et.first ){
+ Trace("qcf-tconstraint-debug") << "...cannot show entailment of " << rew << "." << std::endl;
+ return false;
+ }else{
+ return true;
+ }
+ }else{
+ Trace("qcf-tconstraint-debug") << "...does not need to be entailed." << std::endl;
+ return true;
+ }
+ }else{
+ Trace("qcf-tconstraint-debug") << "...rewrites to true." << std::endl;
+ return true;
+ }
+}
+
+bool QuantInfo::completeMatch( QuantConflictFind * p, std::vector< int >& assigned, bool doContinue ) {
+ //assign values for variables that were unassigned (usually not necessary, but handles corner cases)
+ bool doFail = false;
+ bool success = true;
+ if( doContinue ){
+ doFail = true;
+ success = false;
+ }else{
+ //solve for interpreted symbol matches
+ // this breaks the invariant that all introduced constraints are over existing terms
+ for( int i=(int)(d_tsym_vars.size()-1); i>=0; i-- ){
+ int index = d_tsym_vars[i];
+ TNode v = getCurrentValue( d_vars[index] );
+ int slv_v = -1;
+ if( v==d_vars[index] ){
+ slv_v = index;
+ }
+ Trace("qcf-tconstraint-debug") << "Solve " << d_vars[index] << " = " << v << " " << d_vars[index].getKind() << std::endl;
+ if( d_vars[index].getKind()==PLUS || d_vars[index].getKind()==MULT ){
+ Kind k = d_vars[index].getKind();
+ std::vector< TNode > children;
+ for( unsigned j=0; j<d_vars[index].getNumChildren(); j++ ){
+ int vn = getVarNum( d_vars[index][j] );
+ if( vn!=-1 ){
+ TNode vv = getCurrentValue( d_vars[index][j] );
+ if( vv==d_vars[index][j] ){
+ //we will assign this
+ if( slv_v==-1 ){
+ Trace("qcf-tconstraint-debug") << "...will solve for var #" << vn << std::endl;
+ slv_v = vn;
+ if( p->d_effort!=QuantConflictFind::effort_conflict ){
+ break;
+ }
+ }else{
+ Node z = p->getZero( k );
+ if( !z.isNull() ){
+ Trace("qcf-tconstraint-debug") << "...set " << d_vars[vn] << " = " << z << std::endl;
+ assigned.push_back( vn );
+ if( !setMatch( p, vn, z ) ){
+ success = false;
+ break;
+ }
+ }
+ }
+ }else{
+ Trace("qcf-tconstraint-debug") << "...sum value " << vv << std::endl;
+ children.push_back( vv );
+ }
+ }else{
+ Trace("qcf-tconstraint-debug") << "...sum " << d_vars[index][j] << std::endl;
+ children.push_back( d_vars[index][j] );
+ }
+ }
+ if( success ){
+ if( slv_v!=-1 ){
+ Node lhs;
+ if( children.empty() ){
+ lhs = p->getZero( k );
+ }else if( children.size()==1 ){
+ lhs = children[0];
+ }else{
+ lhs = NodeManager::currentNM()->mkNode( k, children );
+ }
+ Node sum;
+ if( v==d_vars[index] ){
+ sum = lhs;
+ }else{
+ if( p->d_effort==QuantConflictFind::effort_conflict ){
+ Kind kn = k;
+ if( d_vars[index].getKind()==PLUS ){
+ kn = MINUS;
+ }
+ if( kn!=k ){
+ sum = NodeManager::currentNM()->mkNode( kn, v, lhs );
+ }
+ }
+ }
+ if( !sum.isNull() ){
+ assigned.push_back( slv_v );
+ Trace("qcf-tconstraint-debug") << "...set " << d_vars[slv_v] << " = " << sum << std::endl;
+ if( !setMatch( p, slv_v, sum ) ){
+ success = false;
+ }
+ p->d_tempCache.push_back( sum );
+ }
+ }else{
+ //must show that constraint is met
+ Node sum = NodeManager::currentNM()->mkNode( k, children );
+ Node eq = sum.eqNode( v );
+ if( !entailmentTest( p, eq ) ){
+ success = false;
+ }
+ p->d_tempCache.push_back( sum );
+ }
+ }
+ }
+
+ if( !success ){
+ break;
+ }
+ }
+ if( success ){
+ //check what is left to assign
+ d_unassigned.clear();
+ d_unassigned_tn.clear();
+ std::vector< int > unassigned[2];
+ std::vector< TypeNode > unassigned_tn[2];
+ for( int i=0; i<getNumVars(); i++ ){
+ if( d_match[i].isNull() ){
+ int rindex = d_var_mg.find( i )==d_var_mg.end() ? 1 : 0;
+ unassigned[rindex].push_back( i );
+ unassigned_tn[rindex].push_back( getVar( i ).getType() );
+ assigned.push_back( i );
+ }
+ }
+ d_unassigned_nvar = unassigned[0].size();
+ for( unsigned i=0; i<2; i++ ){
+ d_unassigned.insert( d_unassigned.end(), unassigned[i].begin(), unassigned[i].end() );
+ d_unassigned_tn.insert( d_unassigned_tn.end(), unassigned_tn[i].begin(), unassigned_tn[i].end() );
+ }
+ d_una_eqc_count.clear();
+ d_una_index = 0;
+ }
+ }
+
+ if( !d_unassigned.empty() && ( success || doContinue ) ){
+ Trace("qcf-check") << "Assign to unassigned..." << std::endl;
+ do {
+ if( doFail ){
+ Trace("qcf-check-unassign") << "Failure, try again..." << std::endl;
+ }
+ bool invalidMatch = false;
+ while( ( d_una_index>=0 && (int)d_una_index<(int)d_unassigned.size() ) || invalidMatch || doFail ){
+ invalidMatch = false;
+ if( !doFail && d_una_index==(int)d_una_eqc_count.size() ){
+ //check if it has now been assigned
+ if( d_una_index<d_unassigned_nvar ){
+ if( !isConstrainedVar( d_unassigned[d_una_index] ) ){
+ d_una_eqc_count.push_back( -1 );
+ }else{
+ d_var_mg[ d_unassigned[d_una_index] ]->reset( p, true, this );
+ d_una_eqc_count.push_back( 0 );
+ }
+ }else{
+ d_una_eqc_count.push_back( 0 );
+ }
+ }else{
+ bool failed = false;
+ if( !doFail ){
+ if( d_una_index<d_unassigned_nvar ){
+ if( !isConstrainedVar( d_unassigned[d_una_index] ) ){
+ Trace("qcf-check-unassign") << "Succeeded, variable unconstrained at " << d_una_index << std::endl;
+ d_una_index++;
+ }else if( d_var_mg[d_unassigned[d_una_index]]->getNextMatch( p, this ) ){
+ Trace("qcf-check-unassign") << "Succeeded match with mg at " << d_una_index << std::endl;
+ d_una_index++;
+ }else{
+ failed = true;
+ Trace("qcf-check-unassign") << "Failed match with mg at " << d_una_index << std::endl;
+ }
+ }else{
+ Assert( doFail || d_una_index==(int)d_una_eqc_count.size()-1 );
+ if( d_una_eqc_count[d_una_index]<(int)p->d_eqcs[d_unassigned_tn[d_una_index]].size() ){
+ int currIndex = d_una_eqc_count[d_una_index];
+ d_una_eqc_count[d_una_index]++;
+ Trace("qcf-check-unassign") << d_unassigned[d_una_index] << "->" << p->d_eqcs[d_unassigned_tn[d_una_index]][currIndex] << std::endl;
+ if( setMatch( p, d_unassigned[d_una_index], p->d_eqcs[d_unassigned_tn[d_una_index]][currIndex] ) ){
+ d_match_term[d_unassigned[d_una_index]] = TNode::null();
+ Trace("qcf-check-unassign") << "Succeeded match " << d_una_index << std::endl;
+ d_una_index++;
+ }else{
+ Trace("qcf-check-unassign") << "Failed match " << d_una_index << std::endl;
+ invalidMatch = true;
+ }
+ }else{
+ failed = true;
+ Trace("qcf-check-unassign") << "No more matches " << d_una_index << std::endl;
+ }
+ }
+ }
+ if( doFail || failed ){
+ do{
+ if( !doFail ){
+ d_una_eqc_count.pop_back();
+ }else{
+ doFail = false;
+ }
+ d_una_index--;
+ }while( d_una_index>=0 && d_una_eqc_count[d_una_index]==-1 );
+ }
+ }
+ }
+ success = d_una_index>=0;
+ if( success ){
+ doFail = true;
+ Trace("qcf-check-unassign") << " Try: " << std::endl;
+ for( unsigned i=0; i<d_unassigned.size(); i++ ){
+ int ui = d_unassigned[i];
+ if( !d_match[ui].isNull() ){
+ Trace("qcf-check-unassign") << " Assigned #" << ui << " : " << d_vars[ui] << " -> " << d_match[ui] << std::endl;
+ }
+ }
+ }
+ }while( success && isMatchSpurious( p ) );
+ }
+ if( success ){
+ for( unsigned i=0; i<d_unassigned.size(); i++ ){
+ int ui = d_unassigned[i];
+ if( !d_match[ui].isNull() ){
+ Trace("qcf-check") << " Assigned #" << ui << " : " << d_vars[ui] << " -> " << d_match[ui] << std::endl;
+ }
+ }
+ return true;
+ }else{
+ for( unsigned i=0; i<assigned.size(); i++ ){
+ d_match[ assigned[i] ] = TNode::null();
+ }
+ assigned.clear();
+ return false;
+ }
+}
+
+void QuantInfo::getMatch( std::vector< Node >& terms ){
+ for( unsigned i=0; i<d_q[0].getNumChildren(); i++ ){
+ //Node cv = qi->getCurrentValue( qi->d_match[i] );
+ int repVar = getCurrentRepVar( i );
+ Node cv;
+ //std::map< int, TNode >::iterator itmt = qi->d_match_term.find( repVar );
+ if( !d_match_term[repVar].isNull() ){
+ cv = d_match_term[repVar];
+ }else{
+ cv = d_match[repVar];
+ }
+ Debug("qcf-check-inst") << "INST : " << i << " -> " << cv << ", from " << d_match[i] << std::endl;
+ terms.push_back( cv );
+ }
+}
+
+void QuantInfo::revertMatch( std::vector< int >& assigned ) {
+ for( unsigned i=0; i<assigned.size(); i++ ){
+ d_match[ assigned[i] ] = TNode::null();
+ }
+}
+
+void QuantInfo::debugPrintMatch( const char * c ) {
+ for( int i=0; i<getNumVars(); i++ ){
+ Trace(c) << " " << d_vars[i] << " -> ";
+ if( !d_match[i].isNull() ){
+ Trace(c) << d_match[i];
+ }else{
+ Trace(c) << "(unassigned) ";
+ }
+ if( !d_curr_var_deq[i].empty() ){
+ Trace(c) << ", DEQ{ ";
+ for( std::map< TNode, int >::iterator it = d_curr_var_deq[i].begin(); it != d_curr_var_deq[i].end(); ++it ){
+ Trace(c) << it->first << " ";
+ }
+ Trace(c) << "}";
+ }
+ if( !d_match_term[i].isNull() && d_match_term[i]!=d_match[i] ){
+ Trace(c) << ", EXP : " << d_match_term[i];
+ }
+ Trace(c) << std::endl;
+ }
+ if( !d_tconstraints.empty() ){
+ Trace(c) << "ADDITIONAL CONSTRAINTS : " << std::endl;
+ for( std::map< Node, bool >::iterator it = d_tconstraints.begin(); it != d_tconstraints.end(); ++it ){
+ Trace(c) << " " << it->first << " -> " << it->second << std::endl;
+ }
+ }
+}
+
+MatchGen::MatchGen( QuantInfo * qi, Node n, bool isVar ){
+ Trace("qcf-qregister-debug") << "Make match gen for " << n << ", isVar = " << isVar << std::endl;
+ std::vector< Node > qni_apps;
+ d_qni_size = 0;
+ if( isVar ){
+ Assert( qi->d_var_num.find( n )!=qi->d_var_num.end() );
+ if( n.getKind()==ITE ){
+ d_type = typ_ite_var;
+ d_type_not = false;
+ d_n = n;
+ d_children.push_back( MatchGen( qi, d_n[0] ) );
+ if( d_children[0].isValid() ){
+ d_type = typ_ite_var;
+ for( unsigned i=1; i<=2; i++ ){
+ Node nn = n.eqNode( n[i] );
+ d_children.push_back( MatchGen( qi, nn ) );
+ d_children[d_children.size()-1].d_qni_bound_except.push_back( 0 );
+ if( !d_children[d_children.size()-1].isValid() ){
+ setInvalid();
+ break;
+ }
+ }
+ }else{
+ d_type = typ_invalid;
+ }
+ }else{
+ d_type = isHandledUfTerm( n ) ? typ_var : typ_tsym;
+ d_qni_var_num[0] = qi->getVarNum( n );
+ d_qni_size++;
+ d_type_not = false;
+ d_n = n;
+ //Node f = getOperator( n );
+ for( unsigned j=0; j<d_n.getNumChildren(); j++ ){
+ Node nn = d_n[j];
+ Trace("qcf-qregister-debug") << " " << d_qni_size;
+ if( qi->isVar( nn ) ){
+ int v = qi->d_var_num[nn];
+ Trace("qcf-qregister-debug") << " is var #" << v << std::endl;
+ d_qni_var_num[d_qni_size] = v;
+ //qi->addFuncParent( v, f, j );
+ }else{
+ Trace("qcf-qregister-debug") << " is gterm " << nn << std::endl;
+ d_qni_gterm[d_qni_size] = nn;
+ }
+ d_qni_size++;
+ }
+ }
+ }else{
+ if( n.hasBoundVar() ){
+ d_type_not = false;
+ d_n = n;
+ if( d_n.getKind()==NOT ){
+ d_n = d_n[0];
+ d_type_not = !d_type_not;
+ }
+
+ if( isHandledBoolConnective( d_n ) ){
+ //non-literals
+ d_type = typ_formula;
+ for( unsigned i=0; i<d_n.getNumChildren(); i++ ){
+ if( d_n.getKind()!=FORALL || i==1 ){
+ d_children.push_back( MatchGen( qi, d_n[i], false ) );
+ if( !d_children[d_children.size()-1].isValid() ){
+ setInvalid();
+ break;
+ }
+ }
+ /*
+ else if( isTop && n.getKind()==OR && d_children[d_children.size()-1].d_type==typ_var_eq ){
+ Trace("qcf-qregister-debug") << "Remove child, make built-in constraint" << std::endl;
+ //if variable equality/disequality at top level, remove immediately
+ bool cIsNot = d_children[d_children.size()-1].d_type_not;
+ Node cn = d_children[d_children.size()-1].d_n;
+ Assert( cn.getKind()==EQUAL );
+ Assert( p->d_qinfo[q].isVar( cn[0] ) || p->d_qinfo[q].isVar( cn[1] ) );
+ //make it a built-in constraint instead
+ for( unsigned i=0; i<2; i++ ){
+ if( p->d_qinfo[q].isVar( cn[i] ) ){
+ int v = p->d_qinfo[q].getVarNum( cn[i] );
+ Node cno = cn[i==0 ? 1 : 0];
+ p->d_qinfo[q].d_var_constraint[ cIsNot ? 0 : 1 ][v].push_back( cno );
+ break;
+ }
+ }
+ d_children.pop_back();
+ }
+ */
+ }
+ }else{
+ d_type = typ_invalid;
+ //literals
+ if( isHandledUfTerm( d_n ) ){
+ Assert( qi->isVar( d_n ) );
+ d_type = typ_pred;
+ }else if( d_n.getKind()==BOUND_VARIABLE ){
+ Assert( d_n.getType().isBoolean() );
+ d_type = typ_bool_var;
+ }else if( d_n.getKind()==EQUAL || options::qcfTConstraint() ){
+ for( unsigned i=0; i<d_n.getNumChildren(); i++ ){
+ if( d_n[i].hasBoundVar() ){
+ if( !qi->isVar( d_n[i] ) ){
+ Trace("qcf-qregister-debug") << "ERROR : not var " << d_n[i] << std::endl;
+ }
+ Assert( qi->isVar( d_n[i] ) );
+ if( d_n.getKind()!=EQUAL && qi->isVar( d_n[i] ) ){
+ d_qni_var_num[i+1] = qi->d_var_num[d_n[i]];
+ }
+ }else{
+ d_qni_gterm[i] = d_n[i];
+ }
+ }
+ d_type = d_n.getKind()==EQUAL ? typ_eq : typ_tconstraint;
+ Trace("qcf-tconstraint") << "T-Constraint : " << d_n << std::endl;
+ }
+ }
+ }else{
+ //we will just evaluate
+ d_n = n;
+ d_type = typ_ground;
+ }
+ //if( d_type!=typ_invalid ){
+ //determine an efficient children ordering
+ //if( !d_children.empty() ){
+ //for( unsigned i=0; i<d_children.size(); i++ ){
+ // d_children_order.push_back( i );
+ //}
+ //if( !d_n.isNull() && ( d_n.getKind()==OR || d_n.getKind()==AND || d_n.getKind()==IFF ) ){
+ //sort based on the type of the constraint : ground comes first, then literals, then others
+ //MatchGenSort mgs;
+ //mgs.d_mg = this;
+ //std::sort( d_children_order.begin(), d_children_order.end(), mgs );
+ //}
+ //}
+ //}
+ }
+ Trace("qcf-qregister-debug") << "Done make match gen " << n << ", type = ";
+ debugPrintType( "qcf-qregister-debug", d_type, true );
+ Trace("qcf-qregister-debug") << std::endl;
+ //Assert( d_children.size()==d_children_order.size() );
+
+}
+
+void MatchGen::collectBoundVar( QuantInfo * qi, Node n, std::vector< int >& cbvars ) {
+ int v = qi->getVarNum( n );
+ if( v!=-1 && std::find( cbvars.begin(), cbvars.end(), v )==cbvars.end() ){
+ cbvars.push_back( v );
+ }
+ for( unsigned i=0; i<n.getNumChildren(); i++ ){
+ collectBoundVar( qi, n[i], cbvars );
+ }
+}
+
+void MatchGen::determineVariableOrder( QuantInfo * qi, std::vector< int >& bvars ) {
+ Trace("qcf-qregister-debug") << "Determine variable order " << d_n << std::endl;
+ bool isCom = d_type==typ_formula && ( d_n.getKind()==OR || d_n.getKind()==AND || d_n.getKind()==IFF );
+ std::map< int, std::vector< int > > c_to_vars;
+ std::map< int, std::vector< int > > vars_to_c;
+ std::map< int, int > vb_count;
+ std::map< int, int > vu_count;
+ std::vector< bool > assigned;
+ Trace("qcf-qregister-debug") << "Calculate bound variables..." << std::endl;
+ for( unsigned i=0; i<d_children.size(); i++ ){
+ collectBoundVar( qi, d_children[i].d_n, c_to_vars[i] );
+ assigned.push_back( false );
+ vb_count[i] = 0;
+ vu_count[i] = 0;
+ for( unsigned j=0; j<c_to_vars[i].size(); j++ ){
+ int v = c_to_vars[i][j];
+ vars_to_c[v].push_back( i );
+ if( std::find( bvars.begin(), bvars.end(), v )==bvars.end() ){
+ vu_count[i]++;
+ if( !isCom ){
+ bvars.push_back( v );
+ }
+ }else{
+ vb_count[i]++;
+ }
+ }
+ }
+ if( isCom ){
+ //children that bind the least number of unbound variables go first
+ do {
+ int min_score = -1;
+ int min_score_index = -1;
+ for( unsigned i=0; i<d_children.size(); i++ ){
+ if( !assigned[i] ){
+ int score = vu_count[i];
+ if( min_score==-1 || score<min_score ){
+ min_score = score;
+ min_score_index = i;
+ }
+ }
+ }
+ Trace("qcf-qregister-debug") << "...assign child " << min_score_index << "/" << d_children.size() << std::endl;
+ Assert( min_score_index!=-1 );
+ //add to children order
+ d_children_order.push_back( min_score_index );
+ assigned[min_score_index] = true;
+ //if( vb_count[min_score_index]==0 ){
+ // d_independent.push_back( min_score_index );
+ //}
+ //determine order internal to children
+ d_children[min_score_index].determineVariableOrder( qi, bvars );
+ Trace("qcf-qregister-debug") << "...bind variables" << std::endl;
+ //now, make it a bound variable
+ for( unsigned i=0; i<c_to_vars[min_score_index].size(); i++ ){
+ int v = c_to_vars[min_score_index][i];
+ if( std::find( bvars.begin(), bvars.end(), v )==bvars.end() ){
+ for( unsigned j=0; j<vars_to_c[v].size(); j++ ){
+ int vc = vars_to_c[v][j];
+ vu_count[vc]--;
+ vb_count[vc]++;
+ }
+ bvars.push_back( v );
+ }
+ }
+ Trace("qcf-qregister-debug") << "...done assign child " << min_score_index << std::endl;
+ }while( d_children_order.size()!=d_children.size() );
+ Trace("qcf-qregister-debug") << "Done assign variable ordering for " << d_n << std::endl;
+ }else{
+ for( unsigned i=0; i<d_children.size(); i++ ){
+ d_children_order.push_back( i );
+ d_children[i].determineVariableOrder( qi, bvars );
+ }
+ }
+}
+
+
+void MatchGen::reset_round( QuantConflictFind * p ) {
+ d_wasSet = false;
+ for( unsigned i=0; i<d_children.size(); i++ ){
+ d_children[i].reset_round( p );
+ }
+ for( std::map< int, TNode >::iterator it = d_qni_gterm.begin(); it != d_qni_gterm.end(); ++it ){
+ d_qni_gterm_rep[it->first] = p->getRepresentative( it->second );
+ }
+ if( d_type==typ_ground ){
+ int e = p->evaluate( d_n );
+ if( e==1 ){
+ d_ground_eval[0] = p->d_true;
+ }else if( e==-1 ){
+ d_ground_eval[0] = p->d_false;
+ }
+ }else if( d_type==typ_eq ){
+ for( unsigned i=0; i<d_n.getNumChildren(); i++ ){
+ if( !d_n[i].hasBoundVar() ){
+ d_ground_eval[i] = p->evaluateTerm( d_n[i] );
+ }
+ }
+ }
+ d_qni_bound_cons.clear();
+ d_qni_bound_cons_var.clear();
+ d_qni_bound.clear();
+}
+
+void MatchGen::reset( QuantConflictFind * p, bool tgt, QuantInfo * qi ) {
+ d_tgt = d_type_not ? !tgt : tgt;
+ Debug("qcf-match") << " Reset for : " << d_n << ", type : ";
+ debugPrintType( "qcf-match", d_type );
+ Debug("qcf-match") << ", tgt = " << d_tgt << ", children = " << d_children.size() << " " << d_children_order.size() << std::endl;
+ d_qn.clear();
+ d_qni.clear();
+ d_qni_bound.clear();
+ d_child_counter = -1;
+ d_tgt_orig = d_tgt;
+
+ //set up processing matches
+ if( d_type==typ_invalid ){
+ //do nothing
+ }else if( d_type==typ_ground ){
+ if( d_ground_eval[0]==( d_tgt ? p->d_true : p->d_false ) ){
+ d_child_counter = 0;
+ }
+ }else if( d_type==typ_bool_var ){
+ //get current value of the variable
+ TNode n = qi->getCurrentValue( d_n );
+ int vn = qi->getCurrentRepVar( qi->getVarNum( n ) );
+ if( vn==-1 ){
+ //evaluate the value, see if it is compatible
+ int e = p->evaluate( n );
+ if( ( e==1 && d_tgt ) || ( e==0 && !d_tgt ) ){
+ d_child_counter = 0;
+ }
+ }else{
+ //unassigned, set match to true/false
+ d_qni_bound[0] = vn;
+ qi->setMatch( p, vn, d_tgt ? p->d_true : p->d_false );
+ d_child_counter = 0;
+ }
+ if( d_child_counter==0 ){
+ d_qn.push_back( NULL );
+ }
+ }else if( d_type==typ_var ){
+ Assert( isHandledUfTerm( d_n ) );
+ Node f = getOperator( p, d_n );
+ Debug("qcf-match-debug") << " reset: Var will match operators of " << f << std::endl;
+ TermArgTrie * qni = p->getTermDatabase()->getTermArgTrie( Node::null(), f );
+ if( qni!=NULL ){
+ d_qn.push_back( qni );
+ }
+ d_matched_basis = false;
+ }else if( d_type==typ_tsym || d_type==typ_tconstraint ){
+ for( std::map< int, int >::iterator it = d_qni_var_num.begin(); it != d_qni_var_num.end(); ++it ){
+ int repVar = qi->getCurrentRepVar( it->second );
+ if( qi->d_match[repVar].isNull() ){
+ Debug("qcf-match-debug") << "Force matching on child #" << it->first << ", which is var #" << repVar << std::endl;
+ d_qni_bound[it->first] = repVar;
+ }
+ }
+ d_qn.push_back( NULL );
+ }else if( d_type==typ_pred || d_type==typ_eq ){
+ //add initial constraint
+ Node nn[2];
+ int vn[2];
+ if( d_type==typ_pred ){
+ nn[0] = qi->getCurrentValue( d_n );
+ vn[0] = qi->getCurrentRepVar( qi->getVarNum( nn[0] ) );
+ nn[1] = p->getRepresentative( d_tgt ? p->d_true : p->d_false );
+ vn[1] = -1;
+ d_tgt = true;
+ }else{
+ for( unsigned i=0; i<2; i++ ){
+ TNode nc;
+ std::map< int, TNode >::iterator it = d_qni_gterm_rep.find( i );
+ if( it!=d_qni_gterm_rep.end() ){
+ nc = it->second;
+ }else{
+ nc = d_n[i];
+ }
+ nn[i] = qi->getCurrentValue( nc );
+ vn[i] = qi->getCurrentRepVar( qi->getVarNum( nn[i] ) );
+ }
+ }
+ bool success;
+ if( vn[0]==-1 && vn[1]==-1 ){
+ //Trace("qcf-explain") << " reset : " << d_n << " check ground values " << nn[0] << " " << nn[1] << " (tgt=" << d_tgt << ")" << std::endl;
+ Debug("qcf-match-debug") << " reset: check ground values " << nn[0] << " " << nn[1] << " (" << d_tgt << ")" << std::endl;
+ //just compare values
+ if( d_tgt ){
+ success = p->areMatchEqual( nn[0], nn[1] );
+ }else{
+ if( p->d_effort==QuantConflictFind::effort_conflict ){
+ success = p->areDisequal( nn[0], nn[1] );
+ }else{
+ success = p->areMatchDisequal( nn[0], nn[1] );
+ }
+ }
+ }else{
+ //otherwise, add a constraint to a variable
+ if( vn[1]!=-1 && vn[0]==-1 ){
+ //swap
+ Node t = nn[1];
+ nn[1] = nn[0];
+ nn[0] = t;
+ vn[0] = vn[1];
+ vn[1] = -1;
+ }
+ Debug("qcf-match-debug") << " reset: add constraint " << vn[0] << " -> " << nn[1] << " (vn=" << vn[1] << ")" << std::endl;
+ //add some constraint
+ int addc = qi->addConstraint( p, vn[0], nn[1], vn[1], d_tgt, false );
+ success = addc!=-1;
+ //if successful and non-redundant, store that we need to cleanup this
+ if( addc==1 ){
+ //Trace("qcf-explain") << " reset: " << d_n << " add constraint " << vn[0] << " -> " << nn[1] << " (vn=" << vn[1] << ")" << ", d_tgt = " << d_tgt << std::endl;
+ for( unsigned i=0; i<2; i++ ){
+ if( vn[i]!=-1 && std::find( d_qni_bound_except.begin(), d_qni_bound_except.end(), i )==d_qni_bound_except.end() ){
+ d_qni_bound[vn[i]] = vn[i];
+ }
+ }
+ d_qni_bound_cons[vn[0]] = nn[1];
+ d_qni_bound_cons_var[vn[0]] = vn[1];
+ }
+ }
+ //if successful, we will bind values to variables
+ if( success ){
+ d_qn.push_back( NULL );
+ }
+ }else{
+ if( d_children.empty() ){
+ //add dummy
+ d_qn.push_back( NULL );
+ }else{
+ if( d_tgt && d_n.getKind()==FORALL ){
+ //do nothing
+ }else{
+ //reset the first child to d_tgt
+ d_child_counter = 0;
+ getChild( d_child_counter )->reset( p, d_tgt, qi );
+ }
+ }
+ }
+ d_binding = false;
+ d_wasSet = true;
+ Debug("qcf-match") << " reset: Finished reset for " << d_n << ", success = " << ( !d_qn.empty() || d_child_counter!=-1 ) << std::endl;
+}
+
+bool MatchGen::getNextMatch( QuantConflictFind * p, QuantInfo * qi ) {
+ Debug("qcf-match") << " Get next match for : " << d_n << ", type = ";
+ debugPrintType( "qcf-match", d_type );
+ Debug("qcf-match") << ", children = " << d_children.size() << ", binding = " << d_binding << std::endl;
+ if( d_type==typ_invalid || d_type==typ_ground ){
+ if( d_child_counter==0 ){
+ d_child_counter = -1;
+ return true;
+ }else{
+ d_wasSet = false;
+ return false;
+ }
+ }else if( d_type==typ_var || d_type==typ_eq || d_type==typ_pred || d_type==typ_bool_var || d_type==typ_tconstraint || d_type==typ_tsym ){
+ bool success = false;
+ bool terminate = false;
+ do {
+ bool doReset = false;
+ bool doFail = false;
+ if( !d_binding ){
+ if( doMatching( p, qi ) ){
+ Debug("qcf-match-debug") << " - Matching succeeded" << std::endl;
+ d_binding = true;
+ d_binding_it = d_qni_bound.begin();
+ doReset = true;
+ //for tconstraint, add constraint
+ if( d_type==typ_tconstraint ){
+ std::map< Node, bool >::iterator it = qi->d_tconstraints.find( d_n );
+ if( it==qi->d_tconstraints.end() ){
+ qi->d_tconstraints[d_n] = d_tgt;
+ //store that we added this constraint
+ d_qni_bound_cons[0] = d_n;
+ }else if( d_tgt!=it->second ){
+ success = false;
+ terminate = true;
+ }
+ }
+ }else{
+ Debug("qcf-match-debug") << " - Matching failed" << std::endl;
+ success = false;
+ terminate = true;
+ }
+ }else{
+ doFail = true;
+ }
+ if( d_binding ){
+ //also need to create match for each variable we bound
+ success = true;
+ Debug("qcf-match-debug") << " Produce matches for bound variables by " << d_n << ", type = ";
+ debugPrintType( "qcf-match-debug", d_type );
+ Debug("qcf-match-debug") << "..." << std::endl;
+
+ while( ( success && d_binding_it!=d_qni_bound.end() ) || doFail ){
+ std::map< int, MatchGen * >::iterator itm;
+ if( !doFail ){
+ Debug("qcf-match-debug") << " check variable " << d_binding_it->second << std::endl;
+ itm = qi->d_var_mg.find( d_binding_it->second );
+ }
+ if( doFail || ( d_binding_it->first!=0 && itm!=qi->d_var_mg.end() ) ){
+ Debug("qcf-match-debug") << " we had bound variable " << d_binding_it->second << ", reset = " << doReset << std::endl;
+ if( doReset ){
+ itm->second->reset( p, true, qi );
+ }
+ if( doFail || !itm->second->getNextMatch( p, qi ) ){
+ do {
+ if( d_binding_it==d_qni_bound.begin() ){
+ Debug("qcf-match-debug") << " failed." << std::endl;
+ success = false;
+ }else{
+ --d_binding_it;
+ Debug("qcf-match-debug") << " decrement..." << std::endl;
+ }
+ }while( success && ( d_binding_it->first==0 || qi->d_var_mg.find( d_binding_it->second )==qi->d_var_mg.end() ) );
+ doReset = false;
+ doFail = false;
+ }else{
+ Debug("qcf-match-debug") << " increment..." << std::endl;
+ ++d_binding_it;
+ doReset = true;
+ }
+ }else{
+ Debug("qcf-match-debug") << " skip..." << d_binding_it->second << std::endl;
+ ++d_binding_it;
+ doReset = true;
+ }
+ }
+ if( !success ){
+ d_binding = false;
+ }else{
+ terminate = true;
+ if( d_binding_it==d_qni_bound.begin() ){
+ d_binding = false;
+ }
+ }
+ }
+ }while( !terminate );
+ //if not successful, clean up the variables you bound
+ if( !success ){
+ if( d_type==typ_eq || d_type==typ_pred ){
+ //clean up the constraints you added
+ for( std::map< int, TNode >::iterator it = d_qni_bound_cons.begin(); it != d_qni_bound_cons.end(); ++it ){
+ if( !it->second.isNull() ){
+ Debug("qcf-match") << " Clean up bound var " << it->first << (d_tgt ? "!" : "") << " = " << it->second << std::endl;
+ std::map< int, int >::iterator itb = d_qni_bound_cons_var.find( it->first );
+ int vn = itb!=d_qni_bound_cons_var.end() ? itb->second : -1;
+ //Trace("qcf-explain") << " cleanup: " << d_n << " remove constraint " << it->first << " -> " << it->second << " (vn=" << vn << ")" << ", d_tgt = " << d_tgt << std::endl;
+ qi->addConstraint( p, it->first, it->second, vn, d_tgt, true );
+ }
+ }
+ d_qni_bound_cons.clear();
+ d_qni_bound_cons_var.clear();
+ d_qni_bound.clear();
+ }else{
+ //clean up the matches you set
+ for( std::map< int, int >::iterator it = d_qni_bound.begin(); it != d_qni_bound.end(); ++it ){
+ Debug("qcf-match") << " Clean up bound var " << it->second << std::endl;
+ Assert( it->second<qi->getNumVars() );
+ qi->d_match[ it->second ] = TNode::null();
+ qi->d_match_term[ it->second ] = TNode::null();
+ }
+ d_qni_bound.clear();
+ }
+ if( d_type==typ_tconstraint ){
+ //remove constraint if applicable
+ if( d_qni_bound_cons.find( 0 )!=d_qni_bound_cons.end() ){
+ qi->d_tconstraints.erase( d_n );
+ d_qni_bound_cons.clear();
+ }
+ }
+ /*
+ if( d_type==typ_var && p->d_effort==QuantConflictFind::effort_mc && !d_matched_basis ){
+ d_matched_basis = true;
+ Node f = getOperator( d_n );
+ TNode mbo = p->getQuantifiersEngine()->getTermDatabase()->getModelBasisOpTerm( f );
+ if( qi->setMatch( p, d_qni_var_num[0], mbo ) ){
+ success = true;
+ d_qni_bound[0] = d_qni_var_num[0];
+ }
+ }
+ */
+ }
+ Debug("qcf-match") << " ...finished matching for " << d_n << ", success = " << success << std::endl;
+ d_wasSet = success;
+ return success;
+ }else if( d_type==typ_formula || d_type==typ_ite_var ){
+ bool success = false;
+ if( d_child_counter<0 ){
+ if( d_child_counter<-1 ){
+ success = true;
+ d_child_counter = -1;
+ }
+ }else{
+ while( !success && d_child_counter>=0 ){
+ //transition system based on d_child_counter
+ if( d_n.getKind()==OR || d_n.getKind()==AND ){
+ if( (d_n.getKind()==AND)==d_tgt ){
+ //all children must match simultaneously
+ if( getChild( d_child_counter )->getNextMatch( p, qi ) ){
+ if( d_child_counter<(int)(getNumChildren()-1) ){
+ d_child_counter++;
+ Debug("qcf-match-debug") << " Reset child " << d_child_counter << " of " << d_n << std::endl;
+ getChild( d_child_counter )->reset( p, d_tgt, qi );
+ }else{
+ success = true;
+ }
+ }else{
+ //if( std::find( d_independent.begin(), d_independent.end(), d_child_counter )!=d_independent.end() ){
+ // d_child_counter--;
+ //}else{
+ d_child_counter--;
+ //}
+ }
+ }else{
+ //one child must match
+ if( !getChild( d_child_counter )->getNextMatch( p, qi ) ){
+ if( d_child_counter<(int)(getNumChildren()-1) ){
+ d_child_counter++;
+ Debug("qcf-match-debug") << " Reset child " << d_child_counter << " of " << d_n << ", one match" << std::endl;
+ getChild( d_child_counter )->reset( p, d_tgt, qi );
+ }else{
+ d_child_counter = -1;
+ }
+ }else{
+ success = true;
+ }
+ }
+ }else if( d_n.getKind()==IFF ){
+ //construct match based on both children
+ if( d_child_counter%2==0 ){
+ if( getChild( 0 )->getNextMatch( p, qi ) ){
+ d_child_counter++;
+ getChild( 1 )->reset( p, d_child_counter==1, qi );
+ }else{
+ if( d_child_counter==0 ){
+ d_child_counter = 2;
+ getChild( 0 )->reset( p, !d_tgt, qi );
+ }else{
+ d_child_counter = -1;
+ }
+ }
+ }
+ if( d_child_counter>=0 && d_child_counter%2==1 ){
+ if( getChild( 1 )->getNextMatch( p, qi ) ){
+ success = true;
+ }else{
+ d_child_counter--;
+ }
+ }
+ }else if( d_n.getKind()==ITE ){
+ if( d_child_counter%2==0 ){
+ int index1 = d_child_counter==4 ? 1 : 0;
+ if( getChild( index1 )->getNextMatch( p, qi ) ){
+ d_child_counter++;
+ getChild( d_child_counter==5 ? 2 : (d_tgt==(d_child_counter==1) ? 1 : 2) )->reset( p, d_tgt, qi );
+ }else{
+ if( d_child_counter==4 || ( d_type==typ_ite_var && d_child_counter==2 ) ){
+ d_child_counter = -1;
+ }else{
+ d_child_counter +=2;
+ getChild( d_child_counter==2 ? 0 : 1 )->reset( p, d_child_counter==2 ? !d_tgt : d_tgt, qi );
+ }
+ }
+ }
+ if( d_child_counter>=0 && d_child_counter%2==1 ){
+ int index2 = d_child_counter==5 ? 2 : (d_tgt==(d_child_counter==1) ? 1 : 2);
+ if( getChild( index2 )->getNextMatch( p, qi ) ){
+ success = true;
+ }else{
+ d_child_counter--;
+ }
+ }
+ }else if( d_n.getKind()==FORALL ){
+ if( getChild( d_child_counter )->getNextMatch( p, qi ) ){
+ success = true;
+ }else{
+ d_child_counter = -1;
+ }
+ }
+ }
+ d_wasSet = success;
+ Debug("qcf-match") << " ...finished construct match for " << d_n << ", success = " << success << std::endl;
+ return success;
+ }
+ }
+ Debug("qcf-match") << " ...already finished for " << d_n << std::endl;
+ return false;
+}
+
+bool MatchGen::getExplanation( QuantConflictFind * p, QuantInfo * qi, std::vector< Node >& exp ) {
+ if( d_type==typ_eq ){
+ Node n[2];
+ for( unsigned i=0; i<2; i++ ){
+ Trace("qcf-explain") << "Explain term " << d_n[i] << "..." << std::endl;
+ n[i] = getExplanationTerm( p, qi, d_n[i], exp );
+ }
+ Node eq = n[0].eqNode( n[1] );
+ if( !d_tgt_orig ){
+ eq = eq.negate();
+ }
+ exp.push_back( eq );
+ Trace("qcf-explain") << "Explanation for " << d_n << " (tgt=" << d_tgt_orig << ") is " << eq << ", set = " << d_wasSet << std::endl;
+ return true;
+ }else if( d_type==typ_pred ){
+ Trace("qcf-explain") << "Explain term " << d_n << "..." << std::endl;
+ Node n = getExplanationTerm( p, qi, d_n, exp );
+ if( !d_tgt_orig ){
+ n = n.negate();
+ }
+ exp.push_back( n );
+ Trace("qcf-explain") << "Explanation for " << d_n << " (tgt=" << d_tgt_orig << ") is " << n << ", set = " << d_wasSet << std::endl;
+ return true;
+ }else if( d_type==typ_formula ){
+ Trace("qcf-explain") << "Explanation get for " << d_n << ", counter = " << d_child_counter << ", tgt = " << d_tgt_orig << ", set = " << d_wasSet << std::endl;
+ if( d_n.getKind()==OR || d_n.getKind()==AND ){
+ if( (d_n.getKind()==AND)==d_tgt ){
+ for( unsigned i=0; i<getNumChildren(); i++ ){
+ if( !getChild( i )->getExplanation( p, qi, exp ) ){
+ return false;
+ }
+ }
+ }else{
+ return getChild( d_child_counter )->getExplanation( p, qi, exp );
+ }
+ }else if( d_n.getKind()==IFF ){
+ for( unsigned i=0; i<2; i++ ){
+ if( !getChild( i )->getExplanation( p, qi, exp ) ){
+ return false;
+ }
+ }
+ }else if( d_n.getKind()==ITE ){
+ for( unsigned i=0; i<3; i++ ){
+ bool isActive = ( ( i==0 && d_child_counter!=5 ) ||
+ ( i==1 && d_child_counter!=( d_tgt ? 3 : 1 ) ) ||
+ ( i==2 && d_child_counter!=( d_tgt ? 1 : 3 ) ) );
+ if( isActive ){
+ if( !getChild( i )->getExplanation( p, qi, exp ) ){
+ return false;
+ }
+ }
+ }
+ }else{
+ return false;
+ }
+ return true;
+ }else{
+ return false;
+ }
+}
+
+Node MatchGen::getExplanationTerm( QuantConflictFind * p, QuantInfo * qi, Node t, std::vector< Node >& exp ) {
+ Node v = qi->getCurrentExpValue( t );
+ if( isHandledUfTerm( t ) ){
+ for( unsigned i=0; i<t.getNumChildren(); i++ ){
+ Node vi = getExplanationTerm( p, qi, t[i], exp );
+ if( vi!=v[i] ){
+ Node eq = vi.eqNode( v[i] );
+ if( std::find( exp.begin(), exp.end(), eq )==exp.end() ){
+ Trace("qcf-explain") << " add : " << eq << "." << std::endl;
+ exp.push_back( eq );
+ }
+ }
+ }
+ }
+ return v;
+}
+
+bool MatchGen::doMatching( QuantConflictFind * p, QuantInfo * qi ) {
+ if( !d_qn.empty() ){
+ if( d_qn[0]==NULL ){
+ d_qn.clear();
+ return true;
+ }else{
+ Assert( d_type==typ_var );
+ Assert( d_qni_size>0 );
+ bool invalidMatch;
+ do {
+ invalidMatch = false;
+ Debug("qcf-match-debug") << " Do matching " << d_n << " " << d_qn.size() << " " << d_qni.size() << std::endl;
+ if( d_qn.size()==d_qni.size()+1 ) {
+ int index = (int)d_qni.size();
+ //initialize
+ TNode val;
+ std::map< int, int >::iterator itv = d_qni_var_num.find( index );
+ if( itv!=d_qni_var_num.end() ){
+ //get the representative variable this variable is equal to
+ int repVar = qi->getCurrentRepVar( itv->second );
+ Debug("qcf-match-debug") << " Match " << index << " is a variable " << itv->second << ", which is repVar " << repVar << std::endl;
+ //get the value the rep variable
+ //std::map< int, TNode >::iterator itm = qi->d_match.find( repVar );
+ if( !qi->d_match[repVar].isNull() ){
+ val = qi->d_match[repVar];
+ Debug("qcf-match-debug") << " Variable is already bound to " << val << std::endl;
+ }else{
+ //binding a variable
+ d_qni_bound[index] = repVar;
+ std::map< TNode, TermArgTrie >::iterator it = d_qn[index]->d_data.begin();
+ if( it != d_qn[index]->d_data.end() ) {
+ d_qni.push_back( it );
+ //set the match
+ if( qi->setMatch( p, d_qni_bound[index], it->first ) ){
+ Debug("qcf-match-debug") << " Binding variable" << std::endl;
+ if( d_qn.size()<d_qni_size ){
+ d_qn.push_back( &it->second );
+ }
+ }else{
+ Debug("qcf-match") << " Binding variable, currently fail." << std::endl;
+ invalidMatch = true;
+ }
+ }else{
+ Debug("qcf-match-debug") << " Binding variable, fail, no more variables to bind" << std::endl;
+ d_qn.pop_back();
+ }
+ }
+ }else{
+ Debug("qcf-match-debug") << " Match " << index << " is ground term" << std::endl;
+ Assert( d_qni_gterm.find( index )!=d_qni_gterm.end() );
+ Assert( d_qni_gterm_rep.find( index )!=d_qni_gterm_rep.end() );
+ val = d_qni_gterm_rep[index];
+ Assert( !val.isNull() );
+ }
+ if( !val.isNull() ){
+ //constrained by val
+ std::map< TNode, TermArgTrie >::iterator it = d_qn[index]->d_data.find( val );
+ if( it!=d_qn[index]->d_data.end() ){
+ Debug("qcf-match-debug") << " Match" << std::endl;
+ d_qni.push_back( it );
+ if( d_qn.size()<d_qni_size ){
+ d_qn.push_back( &it->second );
+ }
+ }else{
+ Debug("qcf-match-debug") << " Failed to match" << std::endl;
+ d_qn.pop_back();
+ }
+ }
+ }else{
+ Assert( d_qn.size()==d_qni.size() );
+ int index = d_qni.size()-1;
+ //increment if binding this variable
+ bool success = false;
+ std::map< int, int >::iterator itb = d_qni_bound.find( index );
+ if( itb!=d_qni_bound.end() ){
+ d_qni[index]++;
+ if( d_qni[index]!=d_qn[index]->d_data.end() ){
+ success = true;
+ if( qi->setMatch( p, itb->second, d_qni[index]->first ) ){
+ Debug("qcf-match-debug") << " Bind next variable" << std::endl;
+ if( d_qn.size()<d_qni_size ){
+ d_qn.push_back( &d_qni[index]->second );
+ }
+ }else{
+ Debug("qcf-match-debug") << " Bind next variable, currently fail" << std::endl;
+ invalidMatch = true;
+ }
+ }else{
+ qi->d_match[ itb->second ] = TNode::null();
+ qi->d_match_term[ itb->second ] = TNode::null();
+ Debug("qcf-match-debug") << " Bind next variable, no more variables to bind" << std::endl;
+ }
+ }else{
+ //TODO : if it equal to something else, also try that
+ }
+ //if not incrementing, move to next
+ if( !success ){
+ d_qn.pop_back();
+ d_qni.pop_back();
+ }
+ }
+ }while( ( !d_qn.empty() && d_qni.size()!=d_qni_size ) || invalidMatch );
+ if( d_qni.size()==d_qni_size ){
+ //Assert( !d_qni[d_qni.size()-1]->second.d_data.empty() );
+ //Debug("qcf-match-debug") << " We matched " << d_qni[d_qni.size()-1]->second.d_children.begin()->first << std::endl;
+ Assert( !d_qni[d_qni.size()-1]->second.d_data.empty() );
+ TNode t = d_qni[d_qni.size()-1]->second.d_data.begin()->first;
+ Debug("qcf-match-debug") << " " << d_n << " matched " << t << std::endl;
+ qi->d_match_term[d_qni_var_num[0]] = t;
+ //set the match terms
+ for( std::map< int, int >::iterator it = d_qni_bound.begin(); it != d_qni_bound.end(); ++it ){
+ Debug("qcf-match-debug") << " position " << it->first << " bounded " << it->second << " / " << qi->d_q[0].getNumChildren() << std::endl;
+ //if( it->second<(int)qi->d_q[0].getNumChildren() ){ //if it is an actual variable, we are interested in knowing the actual term
+ if( it->first>0 ){
+ Assert( !qi->d_match[ it->second ].isNull() );
+ Assert( p->areEqual( t[it->first-1], qi->d_match[ it->second ] ) );
+ qi->d_match_term[it->second] = t[it->first-1];
+ }
+ //}
+ }
+ }
+ }
+ }
+ return !d_qn.empty();
+}
+
+void MatchGen::debugPrintType( const char * c, short typ, bool isTrace ) {
+ if( isTrace ){
+ switch( typ ){
+ case typ_invalid: Trace(c) << "invalid";break;
+ case typ_ground: Trace(c) << "ground";break;
+ case typ_eq: Trace(c) << "eq";break;
+ case typ_pred: Trace(c) << "pred";break;
+ case typ_formula: Trace(c) << "formula";break;
+ case typ_var: Trace(c) << "var";break;
+ case typ_ite_var: Trace(c) << "ite_var";break;
+ case typ_bool_var: Trace(c) << "bool_var";break;
+ }
+ }else{
+ switch( typ ){
+ case typ_invalid: Debug(c) << "invalid";break;
+ case typ_ground: Debug(c) << "ground";break;
+ case typ_eq: Debug(c) << "eq";break;
+ case typ_pred: Debug(c) << "pred";break;
+ case typ_formula: Debug(c) << "formula";break;
+ case typ_var: Debug(c) << "var";break;
+ case typ_ite_var: Debug(c) << "ite_var";break;
+ case typ_bool_var: Debug(c) << "bool_var";break;
+ }
+ }
+}
+
+void MatchGen::setInvalid() {
+ d_type = typ_invalid;
+ d_children.clear();
+}
+
+bool MatchGen::isHandledBoolConnective( TNode n ) {
+ return n.getType().isBoolean() && ( n.getKind()==OR || n.getKind()==AND || n.getKind()==IFF || n.getKind()==ITE || n.getKind()==FORALL || n.getKind()==NOT );
+}
+
+bool MatchGen::isHandledUfTerm( TNode n ) {
+ //return n.getKind()==APPLY_UF || n.getKind()==STORE || n.getKind()==SELECT ||
+ // n.getKind()==APPLY_CONSTRUCTOR || n.getKind()==APPLY_SELECTOR_TOTAL || n.getKind()==APPLY_TESTER;
+ return inst::Trigger::isAtomicTriggerKind( n.getKind() );
+}
+
+Node MatchGen::getOperator( QuantConflictFind * p, Node n ) {
+ if( isHandledUfTerm( n ) ){
+ return p->getQuantifiersEngine()->getTermDatabase()->getOperator( n );
+ }else{
+ return Node::null();
+ }
+}
+
+bool MatchGen::isHandled( TNode n ) {
+ if( n.getKind()!=BOUND_VARIABLE && n.hasBoundVar() ){
+ if( !isHandledBoolConnective( n ) && !isHandledUfTerm( n ) && n.getKind()!=EQUAL && n.getKind()!=ITE ){
+ return false;
+ }
+ for( unsigned i=0; i<n.getNumChildren(); i++ ){
+ if( !isHandled( n[i] ) ){
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+
+QuantConflictFind::QuantConflictFind( QuantifiersEngine * qe, context::Context* c ) :
+QuantifiersModule( qe ),
+d_c( c ),
+d_conflict( c, false ),
+d_qassert( c ) {
+ d_fid_count = 0;
+ d_true = NodeManager::currentNM()->mkConst<bool>(true);
+ d_false = NodeManager::currentNM()->mkConst<bool>(false);
+}
+
+Node QuantConflictFind::mkEqNode( Node a, Node b ) {
+ if( a.getType().isBoolean() ){
+ return a.iffNode( b );
+ }else{
+ return a.eqNode( b );
+ }
+}
+
+//-------------------------------------------------- registration
+
+void QuantConflictFind::registerQuantifier( Node q ) {
+ if( !TermDb::isRewriteRule( q ) ){
+ d_quants.push_back( q );
+ d_quant_id[q] = d_quants.size();
+ Trace("qcf-qregister") << "Register ";
+ debugPrintQuant( "qcf-qregister", q );
+ Trace("qcf-qregister") << " : " << q << std::endl;
+ //make QcfNode structure
+ Trace("qcf-qregister") << "- Get relevant equality/disequality pairs, calculate flattening..." << std::endl;
+ d_qinfo[q].initialize( q, q[1] );
+
+ //debug print
+ Trace("qcf-qregister") << "- Flattened structure is :" << std::endl;
+ Trace("qcf-qregister") << " ";
+ debugPrintQuantBody( "qcf-qregister", q, q[1] );
+ Trace("qcf-qregister") << std::endl;
+ if( d_qinfo[q].d_vars.size()>q[0].getNumChildren() ){
+ Trace("qcf-qregister") << " with additional constraints : " << std::endl;
+ for( unsigned j=q[0].getNumChildren(); j<d_qinfo[q].d_vars.size(); j++ ){
+ Trace("qcf-qregister") << " ?x" << j << " = ";
+ debugPrintQuantBody( "qcf-qregister", q, d_qinfo[q].d_vars[j], false );
+ Trace("qcf-qregister") << std::endl;
+ }
+ }
+
+ Trace("qcf-qregister") << "Done registering quantifier." << std::endl;
+ }
+}
+
+int QuantConflictFind::evaluate( Node n, bool pref, bool hasPref ) {
+ int ret = 0;
+ if( n.getKind()==EQUAL ){
+ Node n1 = evaluateTerm( n[0] );
+ Node n2 = evaluateTerm( n[1] );
+ Debug("qcf-eval") << "Evaluate : Normalize " << n << " to " << n1 << " = " << n2 << std::endl;
+ if( areEqual( n1, n2 ) ){
+ ret = 1;
+ }else if( areDisequal( n1, n2 ) ){
+ ret = -1;
+ }
+ //else if( d_effort>QuantConflictFind::effort_conflict ){
+ // ret = -1;
+ //}
+ }else if( MatchGen::isHandledUfTerm( n ) ){ //predicate
+ Node nn = evaluateTerm( n );
+ Debug("qcf-eval") << "Evaluate : Normalize " << nn << " to " << n << std::endl;
+ if( areEqual( nn, d_true ) ){
+ ret = 1;
+ }else if( areEqual( nn, d_false ) ){
+ ret = -1;
+ }
+ //else if( d_effort>QuantConflictFind::effort_conflict ){
+ // ret = -1;
+ //}
+ }else if( n.getKind()==NOT ){
+ return -evaluate( n[0] );
+ }else if( n.getKind()==ITE ){
+ int cev1 = evaluate( n[0] );
+ int cevc[2] = { 0, 0 };
+ for( unsigned i=0; i<2; i++ ){
+ if( ( i==0 && cev1!=-1 ) || ( i==1 && cev1!=1 ) ){
+ cevc[i] = evaluate( n[i+1] );
+ if( cev1!=0 ){
+ ret = cevc[i];
+ break;
+ }else if( cevc[i]==0 ){
+ break;
+ }
+ }
+ }
+ if( ret==0 && cevc[0]!=0 && cevc[0]==cevc[1] ){
+ ret = cevc[0];
+ }
+ }else if( n.getKind()==IFF ){
+ int cev1 = evaluate( n[0] );
+ if( cev1!=0 ){
+ int cev2 = evaluate( n[1] );
+ if( cev2!=0 ){
+ ret = cev1==cev2 ? 1 : -1;
+ }
+ }
+
+ }else{
+ int ssval = 0;
+ if( n.getKind()==OR ){
+ ssval = 1;
+ }else if( n.getKind()==AND ){
+ ssval = -1;
+ }
+ bool isUnk = false;
+ for( unsigned i=0; i<n.getNumChildren(); i++ ){
+ int cev = evaluate( n[i] );
+ if( cev==ssval ){
+ ret = ssval;
+ break;
+ }else if( cev==0 ){
+ isUnk = true;
+ }
+ }
+ if( ret==0 && !isUnk ){
+ ret = -ssval;
+ }
+ }
+ Debug("qcf-eval") << "Evaluate " << n << " to " << ret << std::endl;
+ return ret;
+}
+
+short QuantConflictFind::getMaxQcfEffort() {
+ if( options::qcfMode()==QCF_CONFLICT_ONLY ){
+ return effort_conflict;
+ }else if( options::qcfMode()==QCF_PROP_EQ ){
+ return effort_prop_eq;
+ }else if( options::qcfMode()==QCF_MC ){
+ return effort_mc;
+ }else{
+ return 0;
+ }
+}
+
+bool QuantConflictFind::areMatchEqual( TNode n1, TNode n2 ) {
+ //if( d_effort==QuantConflictFind::effort_mc ){
+ // return n1==n2 || !areDisequal( n1, n2 );
+ //}else{
+ return n1==n2;
+ //}
+}
+
+bool QuantConflictFind::areMatchDisequal( TNode n1, TNode n2 ) {
+ //if( d_effort==QuantConflictFind::effort_conflict ){
+ // return areDisequal( n1, n2 );
+ //}else{
+ return n1!=n2;
+ //}
+}
+
+//-------------------------------------------------- handling assertions / eqc
+
+void QuantConflictFind::assertNode( Node q ) {
+ if( !TermDb::isRewriteRule( q ) ){
+ Trace("qcf-proc") << "QCF : assertQuantifier : ";
+ debugPrintQuant("qcf-proc", q);
+ Trace("qcf-proc") << std::endl;
+ d_qassert.push_back( q );
+ //set the eqRegistries that this depends on to true
+ //for( std::map< EqRegistry *, bool >::iterator it = d_qinfo[q].d_rel_eqr.begin(); it != d_qinfo[q].d_rel_eqr.end(); ++it ){
+ // it->first->d_active.set( true );
+ //}
+ }
+}
+
+eq::EqualityEngine * QuantConflictFind::getEqualityEngine() {
+ //return ((uf::TheoryUF*)d_quantEngine->getTheoryEngine()->theoryOf( theory::THEORY_UF ))->getEqualityEngine();
+ return d_quantEngine->getTheoryEngine()->getMasterEqualityEngine();
+}
+bool QuantConflictFind::areEqual( Node n1, Node n2 ) {
+ return getEqualityEngine()->hasTerm( n1 ) && getEqualityEngine()->hasTerm( n2 ) && getEqualityEngine()->areEqual( n1,n2 );
+}
+bool QuantConflictFind::areDisequal( Node n1, Node n2 ) {
+ return n1!=n2 && getEqualityEngine()->hasTerm( n1 ) && getEqualityEngine()->hasTerm( n2 ) && getEqualityEngine()->areDisequal( n1,n2, false );
+}
+Node QuantConflictFind::getRepresentative( Node n ) {
+ if( getEqualityEngine()->hasTerm( n ) ){
+ return getEqualityEngine()->getRepresentative( n );
+ }else{
+ return n;
+ }
+}
+TermDb* QuantConflictFind::getTermDatabase() {
+ return d_quantEngine->getTermDatabase();
+}
+
+Node QuantConflictFind::evaluateTerm( Node n ) {
+ if( MatchGen::isHandledUfTerm( n ) ){
+ Node f = MatchGen::getOperator( this, n );
+ Node nn;
+ if( getEqualityEngine()->hasTerm( n ) ){
+ nn = getTermDatabase()->existsTerm( f, n );
+ }else{
+ std::vector< TNode > args;
+ for( unsigned i=0; i<n.getNumChildren(); i++ ){
+ Node c = evaluateTerm( n[i] );
+ args.push_back( c );
+ }
+ nn = getTermDatabase()->d_func_map_trie[f].existsTerm( args );
+ }
+ if( !nn.isNull() ){
+ Debug("qcf-eval") << "GT: Term " << nn << " for " << n << " hasTerm = " << getEqualityEngine()->hasTerm( n ) << std::endl;
+ return getRepresentative( nn );
+ }else{
+ Debug("qcf-eval") << "GT: No term for " << n << " hasTerm = " << getEqualityEngine()->hasTerm( n ) << std::endl;
+ return n;
+ }
+ }else if( n.getKind()==ITE ){
+ int v = evaluate( n[0], false, false );
+ if( v==1 ){
+ return evaluateTerm( n[1] );
+ }else if( v==-1 ){
+ return evaluateTerm( n[2] );
+ }
+ }
+ return getRepresentative( n );
+}
+
+/** new node */
+void QuantConflictFind::newEqClass( Node n ) {
+ //Trace("qcf-proc-debug") << "QCF : newEqClass : " << n << std::endl;
+ //Trace("qcf-proc2-debug") << "QCF : finished newEqClass : " << n << std::endl;
+}
+
+/** merge */
+void QuantConflictFind::merge( Node a, Node b ) {
+
+}
+
+/** assert disequal */
+void QuantConflictFind::assertDisequal( Node a, Node b ) {
+
+}
+
+//-------------------------------------------------- check function
+
+bool QuantConflictFind::needsCheck( Theory::Effort level ) {
+ bool performCheck = false;
+ if( options::quantConflictFind() && !d_conflict ){
+ if( level==Theory::EFFORT_LAST_CALL ){
+ performCheck = options::qcfWhenMode()==QCF_WHEN_MODE_LAST_CALL;
+ }else if( level==Theory::EFFORT_FULL ){
+ performCheck = options::qcfWhenMode()==QCF_WHEN_MODE_DEFAULT;
+ }else if( level==Theory::EFFORT_STANDARD ){
+ performCheck = options::qcfWhenMode()==QCF_WHEN_MODE_STD;
+ }
+ }
+ return performCheck;
+}
+
+void QuantConflictFind::reset_round( Theory::Effort level ) {
+ d_needs_computeRelEqr = true;
+}
+
+/** check */
+void QuantConflictFind::check( Theory::Effort level, unsigned quant_e ) {
+ if( quant_e==QuantifiersEngine::QEFFORT_CONFLICT ){
+ Trace("qcf-check") << "QCF : check : " << level << std::endl;
+ if( d_conflict ){
+ Trace("qcf-check2") << "QCF : finished check : already in conflict." << std::endl;
+ if( level>=Theory::EFFORT_FULL ){
+ Trace("qcf-warn") << "ALREADY IN CONFLICT? " << level << std::endl;
+ //Assert( false );
+ }
+ }else{
+ int addedLemmas = 0;
+ ++(d_statistics.d_inst_rounds);
+ double clSet = 0;
+ int prevEt = 0;
+ if( Trace.isOn("qcf-engine") ){
+ prevEt = d_statistics.d_entailment_checks.getData();
+ clSet = double(clock())/double(CLOCKS_PER_SEC);
+ Trace("qcf-engine") << "---Conflict Find Engine Round, effort = " << level << "---" << std::endl;
+ }
+ computeRelevantEqr();
+
+ //determine order for quantified formulas
+ std::vector< Node > qorder;
+ std::map< Node, bool > qassert;
+ //mark which are asserted
+ for( unsigned i=0; i<d_qassert.size(); i++ ){
+ qassert[d_qassert[i]] = true;
+ }
+ //add which ones are specified in the order
+ for( unsigned i=0; i<d_quant_order.size(); i++ ){
+ Node n = d_quant_order[i];
+ if( std::find( qorder.begin(), qorder.end(), n )==qorder.end() && qassert.find( n )!=qassert.end() ){
+ qorder.push_back( n );
+ }
+ }
+ d_quant_order.clear();
+ d_quant_order.insert( d_quant_order.begin(), qorder.begin(), qorder.end() );
+ //add remaining
+ for( unsigned i=0; i<d_qassert.size(); i++ ){
+ Node n = d_qassert[i];
+ if( std::find( qorder.begin(), qorder.end(), n )==qorder.end() ){
+ qorder.push_back( n );
+ }
+ }
+
+ if( Trace.isOn("qcf-debug") ){
+ Trace("qcf-debug") << std::endl;
+ debugPrint("qcf-debug");
+ Trace("qcf-debug") << std::endl;
+ }
+ short end_e = getMaxQcfEffort();
+ for( short e = effort_conflict; e<=end_e; e++ ){
+ d_effort = e;
+ Trace("qcf-check") << "Checking quantified formulas at effort " << e << "..." << std::endl;
+ for( unsigned j=0; j<qorder.size(); j++ ){
+ Node q = qorder[j];
+ QuantInfo * qi = &d_qinfo[q];
+
+ Assert( d_qinfo.find( q )!=d_qinfo.end() );
+ if( qi->d_mg->isValid() ){
+ Trace("qcf-check") << "Check quantified formula ";
+ debugPrintQuant("qcf-check", q);
+ Trace("qcf-check") << " : " << q << "..." << std::endl;
+
+ Trace("qcf-check-debug") << "Reset round..." << std::endl;
+ qi->reset_round( this );
+ //try to make a matches making the body false
+ Trace("qcf-check-debug") << "Get next match..." << std::endl;
+ while( qi->d_mg->getNextMatch( this, qi ) ){
+ Trace("qcf-inst") << "*** Produced match at effort " << e << " : " << std::endl;
+ qi->debugPrintMatch("qcf-inst");
+ Trace("qcf-inst") << std::endl;
+ std::vector< int > assigned;
+ if( !qi->isMatchSpurious( this ) ){
+ if( qi->completeMatch( this, assigned ) ){
+ std::vector< Node > terms;
+ qi->getMatch( terms );
+ if( !qi->isTConstraintSpurious( this, terms ) ){
+ if( Debug.isOn("qcf-check-inst") ){
+ //if( e==effort_conflict ){
+ Node inst = d_quantEngine->getInstantiation( q, terms );
+ Debug("qcf-check-inst") << "Check instantiation " << inst << "..." << std::endl;
+ Assert( evaluate( inst )!=1 );
+ Assert( evaluate( inst )==-1 || e>effort_conflict );
+ //}
+ }
+ if( d_quantEngine->addInstantiation( q, terms, false ) ){
+ Trace("qcf-check") << " ... Added instantiation" << std::endl;
+ Trace("qcf-inst") << "*** Was from effort " << e << " : " << std::endl;
+ qi->debugPrintMatch("qcf-inst");
+ Trace("qcf-inst") << std::endl;
+ ++addedLemmas;
+ if( e==effort_conflict ){
+ d_quant_order.insert( d_quant_order.begin(), q );
+ d_conflict.set( true );
+ ++(d_statistics.d_conflict_inst);
+ break;
+ }else if( e==effort_prop_eq ){
+ ++(d_statistics.d_prop_inst);
+ }
+ }else{
+ Trace("qcf-inst") << " ... Failed to add instantiation" << std::endl;
+ //Assert( false );
+ }
+ }
+ //clean up assigned
+ qi->revertMatch( assigned );
+ d_tempCache.clear();
+ }else{
+ Trace("qcf-inst") << " ... Spurious instantiation (cannot assign unassigned variables)" << std::endl;
+ }
+ }else{
+ Trace("qcf-inst") << " ... Spurious instantiation (match is inconsistent)" << std::endl;
+ }
+ }
+ if( d_conflict ){
+ break;
+ }
+ }
+ }
+ if( addedLemmas>0 ){
+ break;
+ }
+ }
+ if( Trace.isOn("qcf-engine") ){
+ double clSet2 = double(clock())/double(CLOCKS_PER_SEC);
+ Trace("qcf-engine") << "Finished conflict find engine, time = " << (clSet2-clSet);
+ if( addedLemmas>0 ){
+ Trace("qcf-engine") << ", effort = " << ( d_effort==effort_conflict ? "conflict" : ( d_effort==effort_prop_eq ? "prop_eq" : "mc" ) );
+ Trace("qcf-engine") << ", addedLemmas = " << addedLemmas;
+ }
+ Trace("qcf-engine") << std::endl;
+ int currEt = d_statistics.d_entailment_checks.getData();
+ if( currEt!=prevEt ){
+ Trace("qcf-engine") << " Entailment checks = " << ( currEt - prevEt ) << std::endl;
+ }
+ }
+ Trace("qcf-check2") << "QCF : finished check : " << level << std::endl;
+ }
+ }
+}
+
+void QuantConflictFind::computeRelevantEqr() {
+ if( d_needs_computeRelEqr ){
+ d_needs_computeRelEqr = false;
+ Trace("qcf-check") << "Compute relevant equalities..." << std::endl;
+ //d_uf_terms.clear();
+ //d_eqc_uf_terms.clear();
+ d_eqcs.clear();
+ d_model_basis.clear();
+ //d_arg_reps.clear();
+ //double clSet = 0;
+ //if( Trace.isOn("qcf-opt") ){
+ // clSet = double(clock())/double(CLOCKS_PER_SEC);
+ //}
+
+ //long nTermst = 0;
+ //long nTerms = 0;
+ //long nEqc = 0;
+
+ //which nodes are irrelevant for disequality matches
+ std::map< TNode, bool > irrelevant_dnode;
+ //now, store matches
+ eq::EqClassesIterator eqcs_i = eq::EqClassesIterator( getEqualityEngine() );
+ while( !eqcs_i.isFinished() ){
+ //nEqc++;
+ Node r = (*eqcs_i);
+ TypeNode rtn = r.getType();
+ if( options::qcfMode()==QCF_MC ){
+ std::map< TypeNode, std::vector< TNode > >::iterator itt = d_eqcs.find( rtn );
+ if( itt==d_eqcs.end() ){
+ Node mb = getQuantifiersEngine()->getTermDatabase()->getModelBasisTerm( rtn );
+ if( !getEqualityEngine()->hasTerm( mb ) ){
+ Trace("qcf-warn") << "WARNING: Model basis term does not exist!" << std::endl;
+ Assert( false );
+ }
+ Node mbr = getRepresentative( mb );
+ if( mbr!=r ){
+ d_eqcs[rtn].push_back( mbr );
+ }
+ d_eqcs[rtn].push_back( r );
+ d_model_basis[rtn] = mb;
+ }else{
+ itt->second.push_back( r );
+ }
+ }else{
+ d_eqcs[rtn].push_back( r );
+ }
+ ++eqcs_i;
+ }
+ /*
+ if( Trace.isOn("qcf-opt") ){
+ double clSet2 = double(clock())/double(CLOCKS_PER_SEC);
+ Trace("qcf-opt") << "Compute rel eqc : " << std::endl;
+ Trace("qcf-opt") << " " << nEqc << " equivalence classes. " << std::endl;
+ Trace("qcf-opt") << " " << nTerms << " / " << nTermst << " terms." << std::endl;
+ Trace("qcf-opt") << " Time : " << (clSet2-clSet) << std::endl;
+ }
+ */
+ }
+}
+
+
+//-------------------------------------------------- debugging
+
+
+void QuantConflictFind::debugPrint( const char * c ) {
+ //print the equivalance classes
+ Trace(c) << "----------EQ classes" << std::endl;
+ eq::EqClassesIterator eqcs_i = eq::EqClassesIterator( getEqualityEngine() );
+ while( !eqcs_i.isFinished() ){
+ Node n = (*eqcs_i);
+ //if( !n.getType().isInteger() ){
+ Trace(c) << " - " << n << " : {";
+ eq::EqClassIterator eqc_i = eq::EqClassIterator( n, getEqualityEngine() );
+ bool pr = false;
+ while( !eqc_i.isFinished() ){
+ Node nn = (*eqc_i);
+ if( nn.getKind()!=EQUAL && nn!=n ){
+ Trace(c) << (pr ? "," : "" ) << " " << nn;
+ pr = true;
+ }
+ ++eqc_i;
+ }
+ Trace(c) << (pr ? " " : "" ) << "}" << std::endl;
+ /*
+ EqcInfo * eqcn = getEqcInfo( n, false );
+ if( eqcn ){
+ Trace(c) << " DEQ : {";
+ pr = false;
+ for( NodeBoolMap::iterator it = eqcn->d_diseq.begin(); it != eqcn->d_diseq.end(); ++it ){
+ if( (*it).second ){
+ Trace(c) << (pr ? "," : "" ) << " " << (*it).first;
+ pr = true;
+ }
+ }
+ Trace(c) << (pr ? " " : "" ) << "}" << std::endl;
+ }
+ //}
+ */
+ ++eqcs_i;
+ }
+}
+
+void QuantConflictFind::debugPrintQuant( const char * c, Node q ) {
+ Trace(c) << "Q" << d_quant_id[q];
+}
+
+void QuantConflictFind::debugPrintQuantBody( const char * c, Node q, Node n, bool doVarNum ) {
+ if( n.getNumChildren()==0 ){
+ Trace(c) << n;
+ }else if( doVarNum && d_qinfo[q].d_var_num.find( n )!=d_qinfo[q].d_var_num.end() ){
+ Trace(c) << "?x" << d_qinfo[q].d_var_num[n];
+ }else{
+ Trace(c) << "(";
+ if( n.getKind()==APPLY_UF ){
+ Trace(c) << n.getOperator();
+ }else{
+ Trace(c) << n.getKind();
+ }
+ for( unsigned i=0; i<n.getNumChildren(); i++ ){
+ Trace(c) << " ";
+ debugPrintQuantBody( c, q, n[i] );
+ }
+ Trace(c) << ")";
+ }
+}
+
+QuantConflictFind::Statistics::Statistics():
+ d_inst_rounds("QuantConflictFind::Inst_Rounds", 0),
+ d_conflict_inst("QuantConflictFind::Instantiations_Conflict_Find", 0 ),
+ d_prop_inst("QuantConflictFind::Instantiations_Prop", 0 ),
+ d_entailment_checks("QuantConflictFind::Entailment_Checks",0)
+{
+ StatisticsRegistry::registerStat(&d_inst_rounds);
+ StatisticsRegistry::registerStat(&d_conflict_inst);
+ StatisticsRegistry::registerStat(&d_prop_inst);
+ StatisticsRegistry::registerStat(&d_entailment_checks);
+}
+
+QuantConflictFind::Statistics::~Statistics(){
+ StatisticsRegistry::unregisterStat(&d_inst_rounds);
+ StatisticsRegistry::unregisterStat(&d_conflict_inst);
+ StatisticsRegistry::unregisterStat(&d_prop_inst);
+ StatisticsRegistry::unregisterStat(&d_entailment_checks);
+}
+
+TNode QuantConflictFind::getZero( Kind k ) {
+ std::map< Kind, Node >::iterator it = d_zero.find( k );
+ if( it==d_zero.end() ){
+ Node nn;
+ if( k==PLUS ){
+ nn = NodeManager::currentNM()->mkConst( Rational(0) );
+ }
+ d_zero[k] = nn;
+ return nn;
+ }else{
+ return it->second;
+ }
+}
+
+
+}
diff --git a/src/theory/quantifiers/quant_conflict_find.h b/src/theory/quantifiers/quant_conflict_find.h index 0464c04e5..d8f1c8e6f 100644..100755 --- a/src/theory/quantifiers/quant_conflict_find.h +++ b/src/theory/quantifiers/quant_conflict_find.h @@ -1,297 +1,259 @@ -/********************* */ -/*! \file quant_conflict_find.h - ** \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-2014 New York University and The University of Iowa - ** See the file COPYING in the top-level source directory for licensing - ** information.\endverbatim - ** - ** \brief quantifiers conflict find class - **/ - -#include "cvc4_private.h" - -#ifndef QUANT_CONFLICT_FIND -#define QUANT_CONFLICT_FIND - -#include "context/cdhashmap.h" -#include "context/cdchunk_list.h" -#include "theory/quantifiers_engine.h" - -namespace CVC4 { -namespace theory { -namespace quantifiers { - -class QcfNode; - -class QuantConflictFind; - -class QcfNodeIndex { -public: - std::map< TNode, QcfNodeIndex > d_children; - void clear() { d_children.clear(); } - void debugPrint( const char * c, int t ); - Node existsTerm( TNode n, std::vector< TNode >& reps, int index = 0 ); - Node addTerm( TNode n, std::vector< TNode >& reps, int index = 0 ); -}; - -class QuantInfo; - -//match generator -class MatchGen { - friend class QuantInfo; -private: - //current children information - int d_child_counter; - //children of this object - std::vector< int > d_children_order; - unsigned getNumChildren() { return d_children.size(); } - MatchGen * getChild( int i ) { return &d_children[d_children_order[i]]; } - //MatchGen * getChild( int i ) { return &d_children[i]; } - //current matching information - std::vector< QcfNodeIndex * > d_qn; - std::vector< std::map< TNode, QcfNodeIndex >::iterator > d_qni; - bool doMatching( QuantConflictFind * p, QuantInfo * qi ); - //for matching : each index is either a variable or a ground term - unsigned d_qni_size; - std::map< int, int > d_qni_var_num; - std::map< int, TNode > d_qni_gterm; - std::map< int, TNode > d_qni_gterm_rep; - std::map< int, int > d_qni_bound; - std::vector< int > d_qni_bound_except; - std::map< int, TNode > d_qni_bound_cons; - std::map< int, int > d_qni_bound_cons_var; - std::map< int, int >::iterator d_binding_it; - //std::vector< int > d_independent; - bool d_matched_basis; - bool d_binding; - //int getVarBindingVar(); - std::map< int, Node > d_ground_eval; - //determine variable order - void determineVariableOrder( QuantInfo * qi, std::vector< int >& bvars ); - void collectBoundVar( QuantInfo * qi, Node n, std::vector< int >& cbvars ); -public: - //type of the match generator - enum { - typ_invalid, - typ_ground, - typ_pred, - typ_eq, - typ_formula, - typ_var, - typ_ite_var, - typ_bool_var, - typ_tconstraint, - typ_tsym, - }; - void debugPrintType( const char * c, short typ, bool isTrace = false ); -public: - MatchGen() : d_type( typ_invalid ){} - MatchGen( QuantInfo * qi, Node n, bool isVar = false ); - bool d_tgt; - bool d_tgt_orig; - bool d_wasSet; - Node d_n; - std::vector< MatchGen > d_children; - short d_type; - bool d_type_not; - void reset_round( QuantConflictFind * p ); - void reset( QuantConflictFind * p, bool tgt, QuantInfo * qi ); - bool getNextMatch( QuantConflictFind * p, QuantInfo * qi ); - bool getExplanation( QuantConflictFind * p, QuantInfo * qi, std::vector< Node >& exp ); - Node getExplanationTerm( QuantConflictFind * p, QuantInfo * qi, Node t, std::vector< Node >& exp ); - bool isValid() { return d_type!=typ_invalid; } - void setInvalid(); - - // is this term treated as UF application? - static bool isHandledBoolConnective( TNode n ); - static bool isHandledUfTerm( TNode n ); - static Node getOperator( QuantConflictFind * p, Node n ); - //can this node be handled by the algorithm - static bool isHandled( TNode n ); -}; - -//info for quantifiers -class QuantInfo { -private: - void registerNode( Node n, bool hasPol, bool pol, bool beneathQuant = false ); - void flatten( Node n, bool beneathQuant ); -private: //for completing match - std::vector< int > d_unassigned; - std::vector< TypeNode > d_unassigned_tn; - int d_unassigned_nvar; - int d_una_index; - std::vector< int > d_una_eqc_count; -public: - QuantInfo() : d_mg( NULL ) {} - ~QuantInfo() { delete d_mg; } - std::vector< TNode > d_vars; - std::map< TNode, int > d_var_num; - std::vector< int > d_tsym_vars; - std::map< TNode, bool > d_inMatchConstraint; - std::map< int, std::vector< Node > > d_var_constraint[2]; - int getVarNum( TNode v ) { return d_var_num.find( v )!=d_var_num.end() ? d_var_num[v] : -1; } - bool isVar( TNode v ) { return d_var_num.find( v )!=d_var_num.end(); } - int getNumVars() { return (int)d_vars.size(); } - TNode getVar( int i ) { return d_vars[i]; } - - MatchGen * d_mg; - Node d_q; - std::map< int, MatchGen * > d_var_mg; - void reset_round( QuantConflictFind * p ); -public: - //initialize - void initialize( Node q, Node qn ); - //current constraints - std::vector< TNode > d_match; - std::vector< TNode > d_match_term; - std::map< int, std::map< TNode, int > > d_curr_var_deq; - std::map< Node, bool > d_tconstraints; - int getCurrentRepVar( int v ); - TNode getCurrentValue( TNode n ); - TNode getCurrentExpValue( TNode n ); - bool getCurrentCanBeEqual( QuantConflictFind * p, int v, TNode n, bool chDiseq = false ); - int addConstraint( QuantConflictFind * p, int v, TNode n, bool polarity ); - int addConstraint( QuantConflictFind * p, int v, TNode n, int vn, bool polarity, bool doRemove ); - bool setMatch( QuantConflictFind * p, int v, TNode n ); - bool isMatchSpurious( QuantConflictFind * p ); - bool isTConstraintSpurious( QuantConflictFind * p, std::vector< Node >& terms ); - bool entailmentTest( QuantConflictFind * p, Node lit, bool chEnt = true ); - bool completeMatch( QuantConflictFind * p, std::vector< int >& assigned, bool doContinue = false ); - void revertMatch( std::vector< int >& assigned ); - void debugPrintMatch( const char * c ); - bool isConstrainedVar( int v ); -public: - void getMatch( std::vector< Node >& terms ); -}; - -class QuantConflictFind : public QuantifiersModule -{ - friend class QcfNodeIndex; - friend class MatchGen; - friend class QuantInfo; - typedef context::CDChunkList<Node> NodeList; - typedef context::CDHashMap<Node, bool, NodeHashFunction> NodeBoolMap; -private: - context::Context* d_c; - context::CDO< bool > d_conflict; - bool d_performCheck; - std::vector< Node > d_quant_order; - std::map< Kind, Node > d_zero; - //for storing nodes created during t-constraint solving (prevents memory leaks) - std::vector< Node > d_tempCache; -private: - std::map< Node, Node > d_op_node; - int d_fid_count; - std::map< Node, int > d_fid; - Node mkEqNode( Node a, Node b ); -public: //for ground terms - Node d_true; - Node d_false; - TNode getZero( Kind k ); -private: - Node evaluateTerm( Node n ); - int evaluate( Node n, bool pref = false, bool hasPref = false ); -private: - //currently asserted quantifiers - NodeList d_qassert; - std::map< Node, QuantInfo > d_qinfo; -private: //for equivalence classes - eq::EqualityEngine * getEqualityEngine(); - bool areDisequal( Node n1, Node n2 ); - bool areEqual( Node n1, Node n2 ); - Node getRepresentative( Node n ); - -/* - class EqcInfo { - public: - EqcInfo( context::Context* c ) : d_diseq( c ) {} - NodeBoolMap d_diseq; - bool isDisequal( Node n ) { return d_diseq.find( n )!=d_diseq.end() && d_diseq[n]; } - void setDisequal( Node n, bool val = true ) { d_diseq[n] = val; } - //NodeBoolMap& getRelEqr( int index ) { return index==0 ? d_rel_eqr_e : d_rel_eqr_d; } - }; - std::map< Node, EqcInfo * > d_eqc_info; - EqcInfo * getEqcInfo( Node n, bool doCreate = true ); -*/ - // operator -> index(terms) - std::map< TNode, QcfNodeIndex > d_uf_terms; - // operator -> index(eqc -> terms) - std::map< TNode, QcfNodeIndex > d_eqc_uf_terms; - //get qcf node index - QcfNodeIndex * getQcfNodeIndex( Node eqc, Node f ); - QcfNodeIndex * getQcfNodeIndex( Node f ); - // type -> list(eqc) - std::map< TypeNode, std::vector< TNode > > d_eqcs; - std::map< TypeNode, Node > d_model_basis; - //mapping from UF terms to representatives of their arguments - std::map< TNode, std::vector< TNode > > d_arg_reps; - //compute arg reps - void computeArgReps( TNode n ); - //compute - void computeUfTerms( TNode f ); -public: - enum { - effort_conflict, - effort_prop_eq, - effort_mc, - }; - short d_effort; - void setEffort( int e ) { d_effort = e; } - static short getMaxQcfEffort(); - bool areMatchEqual( TNode n1, TNode n2 ); - bool areMatchDisequal( TNode n1, TNode n2 ); -public: - QuantConflictFind( QuantifiersEngine * qe, context::Context* c ); - /** register quantifier */ - void registerQuantifier( Node q ); -public: - /** assert quantifier */ - void assertNode( Node q ); - /** new node */ - void newEqClass( Node n ); - /** merge */ - void merge( Node a, Node b ); - /** assert disequal */ - void assertDisequal( Node a, Node b ); - /** reset round */ - void reset_round( Theory::Effort level ); - /** check */ - void check( Theory::Effort level ); - /** needs check */ - bool needsCheck( Theory::Effort level ); -private: - bool d_needs_computeRelEqr; -public: - void computeRelevantEqr(); -private: - void debugPrint( const char * c ); - //for debugging - std::vector< Node > d_quants; - std::map< Node, int > d_quant_id; - void debugPrintQuant( const char * c, Node q ); - void debugPrintQuantBody( const char * c, Node q, Node n, bool doVarNum = true ); -public: - /** statistics class */ - class Statistics { - public: - IntStat d_inst_rounds; - IntStat d_conflict_inst; - IntStat d_prop_inst; - IntStat d_entailment_checks; - Statistics(); - ~Statistics(); - }; - Statistics d_statistics; - /** Identify this module */ - std::string identify() const { return "QcfEngine"; } -}; - -} -} -} - -#endif +/********************* */
+/*! \file quant_conflict_find.h
+ ** \verbatim
+ ** Original author: Andrew Reynolds
+ ** Major contributors: none
+ ** Minor contributors (to current version): none
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2014 New York University and The University of Iowa
+ ** See the file COPYING in the top-level source directory for licensing
+ ** information.\endverbatim
+ **
+ ** \brief quantifiers conflict find class
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef QUANT_CONFLICT_FIND
+#define QUANT_CONFLICT_FIND
+
+#include "context/cdhashmap.h"
+#include "context/cdchunk_list.h"
+#include "theory/quantifiers_engine.h"
+#include "theory/quantifiers/term_database.h"
+
+namespace CVC4 {
+namespace theory {
+namespace quantifiers {
+
+class QuantConflictFind;
+class QuantInfo;
+
+//match generator
+class MatchGen {
+ friend class QuantInfo;
+private:
+ //current children information
+ int d_child_counter;
+ //children of this object
+ std::vector< int > d_children_order;
+ unsigned getNumChildren() { return d_children.size(); }
+ MatchGen * getChild( int i ) { return &d_children[d_children_order[i]]; }
+ //MatchGen * getChild( int i ) { return &d_children[i]; }
+ //current matching information
+ std::vector< TermArgTrie * > d_qn;
+ std::vector< std::map< TNode, TermArgTrie >::iterator > d_qni;
+ bool doMatching( QuantConflictFind * p, QuantInfo * qi );
+ //for matching : each index is either a variable or a ground term
+ unsigned d_qni_size;
+ std::map< int, int > d_qni_var_num;
+ std::map< int, TNode > d_qni_gterm;
+ std::map< int, TNode > d_qni_gterm_rep;
+ std::map< int, int > d_qni_bound;
+ std::vector< int > d_qni_bound_except;
+ std::map< int, TNode > d_qni_bound_cons;
+ std::map< int, int > d_qni_bound_cons_var;
+ std::map< int, int >::iterator d_binding_it;
+ //std::vector< int > d_independent;
+ bool d_matched_basis;
+ bool d_binding;
+ //int getVarBindingVar();
+ std::map< int, Node > d_ground_eval;
+ //determine variable order
+ void determineVariableOrder( QuantInfo * qi, std::vector< int >& bvars );
+ void collectBoundVar( QuantInfo * qi, Node n, std::vector< int >& cbvars );
+public:
+ //type of the match generator
+ enum {
+ typ_invalid,
+ typ_ground,
+ typ_pred,
+ typ_eq,
+ typ_formula,
+ typ_var,
+ typ_ite_var,
+ typ_bool_var,
+ typ_tconstraint,
+ typ_tsym,
+ };
+ void debugPrintType( const char * c, short typ, bool isTrace = false );
+public:
+ MatchGen() : d_type( typ_invalid ){}
+ MatchGen( QuantInfo * qi, Node n, bool isVar = false );
+ bool d_tgt;
+ bool d_tgt_orig;
+ bool d_wasSet;
+ Node d_n;
+ std::vector< MatchGen > d_children;
+ short d_type;
+ bool d_type_not;
+ void reset_round( QuantConflictFind * p );
+ void reset( QuantConflictFind * p, bool tgt, QuantInfo * qi );
+ bool getNextMatch( QuantConflictFind * p, QuantInfo * qi );
+ bool getExplanation( QuantConflictFind * p, QuantInfo * qi, std::vector< Node >& exp );
+ Node getExplanationTerm( QuantConflictFind * p, QuantInfo * qi, Node t, std::vector< Node >& exp );
+ bool isValid() { return d_type!=typ_invalid; }
+ void setInvalid();
+
+ // is this term treated as UF application?
+ static bool isHandledBoolConnective( TNode n );
+ static bool isHandledUfTerm( TNode n );
+ static Node getOperator( QuantConflictFind * p, Node n );
+ //can this node be handled by the algorithm
+ static bool isHandled( TNode n );
+};
+
+//info for quantifiers
+class QuantInfo {
+private:
+ void registerNode( Node n, bool hasPol, bool pol, bool beneathQuant = false );
+ void flatten( Node n, bool beneathQuant );
+private: //for completing match
+ std::vector< int > d_unassigned;
+ std::vector< TypeNode > d_unassigned_tn;
+ int d_unassigned_nvar;
+ int d_una_index;
+ std::vector< int > d_una_eqc_count;
+public:
+ QuantInfo() : d_mg( NULL ) {}
+ ~QuantInfo() { delete d_mg; }
+ std::vector< TNode > d_vars;
+ std::map< TNode, int > d_var_num;
+ std::vector< int > d_tsym_vars;
+ std::map< TNode, bool > d_inMatchConstraint;
+ std::map< int, std::vector< Node > > d_var_constraint[2];
+ int getVarNum( TNode v ) { return d_var_num.find( v )!=d_var_num.end() ? d_var_num[v] : -1; }
+ bool isVar( TNode v ) { return d_var_num.find( v )!=d_var_num.end(); }
+ int getNumVars() { return (int)d_vars.size(); }
+ TNode getVar( int i ) { return d_vars[i]; }
+
+ MatchGen * d_mg;
+ Node d_q;
+ std::map< int, MatchGen * > d_var_mg;
+ void reset_round( QuantConflictFind * p );
+public:
+ //initialize
+ void initialize( Node q, Node qn );
+ //current constraints
+ std::vector< TNode > d_match;
+ std::vector< TNode > d_match_term;
+ std::map< int, std::map< TNode, int > > d_curr_var_deq;
+ std::map< Node, bool > d_tconstraints;
+ int getCurrentRepVar( int v );
+ TNode getCurrentValue( TNode n );
+ TNode getCurrentExpValue( TNode n );
+ bool getCurrentCanBeEqual( QuantConflictFind * p, int v, TNode n, bool chDiseq = false );
+ int addConstraint( QuantConflictFind * p, int v, TNode n, bool polarity );
+ int addConstraint( QuantConflictFind * p, int v, TNode n, int vn, bool polarity, bool doRemove );
+ bool setMatch( QuantConflictFind * p, int v, TNode n );
+ bool isMatchSpurious( QuantConflictFind * p );
+ bool isTConstraintSpurious( QuantConflictFind * p, std::vector< Node >& terms );
+ bool entailmentTest( QuantConflictFind * p, Node lit, bool chEnt = true );
+ bool completeMatch( QuantConflictFind * p, std::vector< int >& assigned, bool doContinue = false );
+ void revertMatch( std::vector< int >& assigned );
+ void debugPrintMatch( const char * c );
+ bool isConstrainedVar( int v );
+public:
+ void getMatch( std::vector< Node >& terms );
+};
+
+class QuantConflictFind : public QuantifiersModule
+{
+ friend class MatchGen;
+ friend class QuantInfo;
+ typedef context::CDChunkList<Node> NodeList;
+ typedef context::CDHashMap<Node, bool, NodeHashFunction> NodeBoolMap;
+private:
+ context::Context* d_c;
+ context::CDO< bool > d_conflict;
+ std::vector< Node > d_quant_order;
+ std::map< Kind, Node > d_zero;
+ //for storing nodes created during t-constraint solving (prevents memory leaks)
+ std::vector< Node > d_tempCache;
+private:
+ std::map< Node, Node > d_op_node;
+ int d_fid_count;
+ std::map< Node, int > d_fid;
+ Node mkEqNode( Node a, Node b );
+public: //for ground terms
+ Node d_true;
+ Node d_false;
+ TNode getZero( Kind k );
+private:
+ Node evaluateTerm( Node n );
+ int evaluate( Node n, bool pref = false, bool hasPref = false );
+private:
+ //currently asserted quantifiers
+ NodeList d_qassert;
+ std::map< Node, QuantInfo > d_qinfo;
+private: //for equivalence classes
+ eq::EqualityEngine * getEqualityEngine();
+ bool areDisequal( Node n1, Node n2 );
+ bool areEqual( Node n1, Node n2 );
+ Node getRepresentative( Node n );
+ TermDb* getTermDatabase();
+ // type -> list(eqc)
+ std::map< TypeNode, std::vector< TNode > > d_eqcs;
+ std::map< TypeNode, Node > d_model_basis;
+public:
+ enum {
+ effort_conflict,
+ effort_prop_eq,
+ effort_mc,
+ };
+ short d_effort;
+ void setEffort( int e ) { d_effort = e; }
+ static short getMaxQcfEffort();
+ bool areMatchEqual( TNode n1, TNode n2 );
+ bool areMatchDisequal( TNode n1, TNode n2 );
+public:
+ QuantConflictFind( QuantifiersEngine * qe, context::Context* c );
+ /** register quantifier */
+ void registerQuantifier( Node q );
+public:
+ /** assert quantifier */
+ void assertNode( Node q );
+ /** new node */
+ void newEqClass( Node n );
+ /** merge */
+ void merge( Node a, Node b );
+ /** assert disequal */
+ void assertDisequal( Node a, Node b );
+ /** needs check */
+ bool needsCheck( Theory::Effort level );
+ /** reset round */
+ void reset_round( Theory::Effort level );
+ /** check */
+ void check( Theory::Effort level, unsigned quant_e );
+private:
+ bool d_needs_computeRelEqr;
+public:
+ void computeRelevantEqr();
+private:
+ void debugPrint( const char * c );
+ //for debugging
+ std::vector< Node > d_quants;
+ std::map< Node, int > d_quant_id;
+ void debugPrintQuant( const char * c, Node q );
+ void debugPrintQuantBody( const char * c, Node q, Node n, bool doVarNum = true );
+public:
+ /** statistics class */
+ class Statistics {
+ public:
+ IntStat d_inst_rounds;
+ IntStat d_conflict_inst;
+ IntStat d_prop_inst;
+ IntStat d_entailment_checks;
+ Statistics();
+ ~Statistics();
+ };
+ Statistics d_statistics;
+ /** Identify this module */
+ std::string identify() const { return "QcfEngine"; }
+};
+
+}
+}
+}
+
+#endif
diff --git a/src/theory/quantifiers/quantifiers_attributes.cpp b/src/theory/quantifiers/quantifiers_attributes.cpp index a5de6ffa9..8d479c29e 100644 --- a/src/theory/quantifiers/quantifiers_attributes.cpp +++ b/src/theory/quantifiers/quantifiers_attributes.cpp @@ -14,6 +14,7 @@ #include "theory/quantifiers/quantifiers_attributes.h" #include "theory/quantifiers/options.h" +#include "theory/quantifiers/term_database.h" using namespace std; using namespace CVC4; @@ -22,7 +23,8 @@ using namespace CVC4::context; using namespace CVC4::theory; using namespace CVC4::theory::quantifiers; -void QuantifiersAttributes::setUserAttribute( const std::string& attr, Node n ){ +void QuantifiersAttributes::setUserAttribute( const std::string& attr, Node n, std::vector<Node> node_values, std::string str_value ){ + Trace("quant-attr-debug") << "Set " << attr << " " << n << std::endl; if( n.getKind()==FORALL ){ if( attr=="axiom" ){ Trace("quant-attr") << "Set axiom " << n << std::endl; @@ -32,14 +34,22 @@ void QuantifiersAttributes::setUserAttribute( const std::string& attr, Node n ){ Trace("quant-attr") << "Set conjecture " << n << std::endl; ConjectureAttribute ca; n.setAttribute( ca, true ); - }else if( attr=="rr_priority" ){ - //Trace("quant-attr") << "Set rr priority " << n << std::endl; - //RrPriorityAttribute rra; - + }else if( attr=="quant-inst-max-level" ){ + Assert( node_values.size()==1 ); + uint64_t lvl = node_values[0].getConst<Rational>().getNumerator().getLong(); + Trace("quant-attr") << "Set instantiation level " << n << " to " << lvl << std::endl; + QuantInstLevelAttribute qila; + n.setAttribute( qila, lvl ); + }else if( attr=="rr-priority" ){ + Assert( node_values.size()==1 ); + uint64_t lvl = node_values[0].getConst<Rational>().getNumerator().getLong(); + Trace("quant-attr") << "Set rewrite rule priority " << n << " to " << lvl << std::endl; + RrPriorityAttribute rrpa; + n.setAttribute( rrpa, lvl ); } }else{ for( size_t i=0; i<n.getNumChildren(); i++ ){ - setUserAttribute( attr, n[i] ); + setUserAttribute( attr, n[i], node_values, str_value ); } } } diff --git a/src/theory/quantifiers/quantifiers_attributes.h b/src/theory/quantifiers/quantifiers_attributes.h index cf9620a07..34649ae05 100644 --- a/src/theory/quantifiers/quantifiers_attributes.h +++ b/src/theory/quantifiers/quantifiers_attributes.h @@ -44,7 +44,7 @@ struct QuantifiersAttributes * This function will apply a custom set of attributes to all top-level universal * quantifiers contained in n */ - static void setUserAttribute( const std::string& attr, Node n ); + static void setUserAttribute( const std::string& attr, Node n, std::vector<Node> node_values, std::string str_value ); }; diff --git a/src/theory/quantifiers/quantifiers_rewriter.cpp b/src/theory/quantifiers/quantifiers_rewriter.cpp index eb14b0abe..754bfacb1 100644 --- a/src/theory/quantifiers/quantifiers_rewriter.cpp +++ b/src/theory/quantifiers/quantifiers_rewriter.cpp @@ -159,7 +159,13 @@ RewriteResponse QuantifiersRewriter::preRewrite(TNode in) { } Node body = in[1]; bool doRewrite = false; + std::vector< Node > ipl; while( body.getNumChildren()>=2 && body.getKind()==in.getKind() ){ + if( body.getNumChildren()==3 ){ + for( unsigned i=0; i<body[2].getNumChildren(); i++ ){ + ipl.push_back( body[2][i] ); + } + } for( int i=0; i<(int)body[0].getNumChildren(); i++ ){ args.push_back( body[0][i] ); } @@ -171,7 +177,12 @@ RewriteResponse QuantifiersRewriter::preRewrite(TNode in) { children.push_back( NodeManager::currentNM()->mkNode(kind::BOUND_VAR_LIST,args) ); children.push_back( body ); if( in.getNumChildren()==3 ){ - children.push_back( in[2] ); + for( unsigned i=0; i<in[2].getNumChildren(); i++ ){ + ipl.push_back( in[2][i] ); + } + } + if( !ipl.empty() ){ + children.push_back( NodeManager::currentNM()->mkNode( INST_PATTERN_LIST, ipl ) ); } Node n = NodeManager::currentNM()->mkNode( in.getKind(), children ); if( in!=n ){ @@ -357,7 +368,7 @@ Node QuantifiersRewriter::computeVarElimination( Node body, std::vector< Node >& for( std::map< Node, bool >::iterator it = qpr.d_phase_reqs.begin(); it != qpr.d_phase_reqs.end(); ++it ){ //Notice() << " " << it->first << " -> " << ( it->second ? "true" : "false" ) << std::endl; if( it->first.getKind()==EQUAL ){ - if( it->second ){ + if( it->second && options::varElimQuant() ){ for( int i=0; i<2; i++ ){ int j = i==0 ? 1 : 0; std::vector< Node >::iterator ita = std::find( args.begin(), args.end(), it->first[i] ); @@ -377,6 +388,33 @@ Node QuantifiersRewriter::computeVarElimination( Node body, std::vector< Node >& } } } + else if( it->first.getKind()==APPLY_TESTER ){ + if( options::dtVarExpandQuant() && it->second && it->first[0].getKind()==BOUND_VARIABLE ){ + Trace("dt-var-expand") << "Expand datatype variable based on : " << it->first << std::endl; + std::vector< Node >::iterator ita = std::find( args.begin(), args.end(), it->first[0] ); + if( ita!=args.end() ){ + vars.push_back( it->first[0] ); + Expr testerExpr = it->first.getOperator().toExpr(); + int index = Datatype::indexOf( testerExpr ); + const Datatype& dt = Datatype::datatypeOf(testerExpr); + const DatatypeConstructor& c = dt[index]; + std::vector< Node > newChildren; + newChildren.push_back( Node::fromExpr( c.getConstructor() ) ); + std::vector< Node > newVars; + for( unsigned j=0; j<c.getNumArgs(); j++ ){ + TypeNode tn = TypeNode::fromType( c[j].getSelector().getType() ); + tn = tn[1]; + Node v = NodeManager::currentNM()->mkBoundVar( tn ); + newChildren.push_back( v ); + newVars.push_back( v ); + } + subs.push_back( NodeManager::currentNM()->mkNode( APPLY_CONSTRUCTOR, newChildren ) ); + Trace("dt-var-expand") << "...apply substitution " << subs[0] << "/" << vars[0] << std::endl; + args.erase( ita ); + args.insert( args.end(), newVars.begin(), newVars.end() ); + } + } + } } if( !vars.empty() ){ Trace("var-elim-quant") << "VE " << vars.size() << "/" << args.size() << std::endl; @@ -914,7 +952,7 @@ bool QuantifiersRewriter::doOperation( Node f, bool isNested, int computeOption }else if( computeOption==COMPUTE_PRENEX ){ return options::prenexQuant() && !options::aggressiveMiniscopeQuant(); }else if( computeOption==COMPUTE_VAR_ELIMINATION ){ - return options::varElimQuant(); + return options::varElimQuant() || options::dtVarExpandQuant(); }else if( computeOption==COMPUTE_CNF ){ return false;//return options::cnfQuant() ; FIXME }else if( computeOption==COMPUTE_SPLIT ){ @@ -1142,8 +1180,10 @@ Node QuantifiersRewriter::preSkolemizeQuantifiers( Node n, bool polarity, std::v //process body Node nn = preSkolemizeQuantifiers( n[1], polarity, fvTypes, fvs ); std::vector< Node > sk; + Node sub; + std::vector< unsigned > sub_vars; //return skolemized body - return TermDb::mkSkolemizedBody( n, nn, fvTypes, fvs, sk ); + return TermDb::mkSkolemizedBody( n, nn, fvTypes, fvs, sk, sub, sub_vars ); } }else{ //check if it contains a quantifier as a subterm diff --git a/src/theory/quantifiers/rewrite_engine.cpp b/src/theory/quantifiers/rewrite_engine.cpp index 1b13d772e..05e33c7b2 100644 --- a/src/theory/quantifiers/rewrite_engine.cpp +++ b/src/theory/quantifiers/rewrite_engine.cpp @@ -39,7 +39,7 @@ struct PrioritySort { RewriteEngine::RewriteEngine( context::Context* c, QuantifiersEngine* qe ) : QuantifiersModule(qe) { d_true = NodeManager::currentNM()->mkConst( true ); - d_needsSort = true; + d_needsSort = false; } double RewriteEngine::getPriority( Node f ) { @@ -61,8 +61,14 @@ double RewriteEngine::getPriority( Node f ) { //return deterministic ? 0.0 : 1.0; } -void RewriteEngine::check( Theory::Effort e ) { - if( e==Theory::EFFORT_FULL ){ +bool RewriteEngine::needsCheck( Theory::Effort e ){ + return e==Theory::EFFORT_FULL; + //return e>=Theory::EFFORT_LAST_CALL; +} + +void RewriteEngine::check( Theory::Effort e, unsigned quant_e ) { + if( quant_e==QuantifiersEngine::QEFFORT_STANDARD ){ + //if( e==Theory::EFFORT_FULL ){ Trace("rewrite-engine") << "---Rewrite Engine Round, effort = " << e << "---" << std::endl; //if( e==Theory::EFFORT_LAST_CALL ){ // if( !d_quantEngine->getModel()->isModelSet() ){ @@ -102,7 +108,6 @@ void RewriteEngine::check( Theory::Effort e ) { }else{ //otherwise, the search will continue - d_quantEngine->flushLemmas( &d_quantEngine->getOutputChannel() ); } } } diff --git a/src/theory/quantifiers/rewrite_engine.h b/src/theory/quantifiers/rewrite_engine.h index d2108bf3e..1703a9bfc 100644 --- a/src/theory/quantifiers/rewrite_engine.h +++ b/src/theory/quantifiers/rewrite_engine.h @@ -54,7 +54,8 @@ private: public: RewriteEngine( context::Context* c, QuantifiersEngine* qe ); - void check( Theory::Effort e ); + bool needsCheck( Theory::Effort e ); + void check( Theory::Effort e, unsigned quant_e ); void registerQuantifier( Node f ); void assertNode( Node n ); /** Identify this module */ diff --git a/src/theory/quantifiers/term_database.cpp b/src/theory/quantifiers/term_database.cpp index 9ea9ee962..0d85eae83 100644 --- a/src/theory/quantifiers/term_database.cpp +++ b/src/theory/quantifiers/term_database.cpp @@ -31,25 +31,39 @@ using namespace CVC4::theory::quantifiers; using namespace CVC4::theory::inst; -bool TermArgTrie::addTerm2( QuantifiersEngine* qe, Node n, int argIndex ){ - if( argIndex<(int)n.getNumChildren() ){ - Node r = qe->getEqualityQuery()->getRepresentative( n[ argIndex ] ); - std::map< Node, TermArgTrie >::iterator it = d_data.find( r ); +TNode TermArgTrie::existsTerm( std::vector< TNode >& reps, int argIndex ) { + if( argIndex==(int)reps.size() ){ + if( d_data.empty() ){ + return Node::null(); + }else{ + return d_data.begin()->first; + } + }else{ + std::map< TNode, TermArgTrie >::iterator it = d_data.find( reps[argIndex] ); if( it==d_data.end() ){ - d_data[r].addTerm2( qe, n, argIndex+1 ); + return Node::null(); + }else{ + return it->second.existsTerm( reps, argIndex+1 ); + } + } +} + +bool TermArgTrie::addTerm( TNode n, std::vector< TNode >& reps, int argIndex ){ + if( argIndex==(int)reps.size() ){ + if( d_data.empty() ){ + //store n in d_data (this should be interpretted as the "data" and not as a reference to a child) + d_data[n].clear(); return true; }else{ - return it->second.addTerm2( qe, n, argIndex+1 ); + return false; } }else{ - //store n in d_data (this should be interpretted as the "data" and not as a reference to a child) - d_data[n].d_data.clear(); - return false; + return d_data[reps[argIndex]].addTerm( n, reps, argIndex+1 ); } } void TermArgTrie::debugPrint( const char * c, Node n, unsigned depth ) { - for( std::map< Node, TermArgTrie >::iterator it = d_data.begin(); it != d_data.end(); ++it ){ + for( std::map< TNode, TermArgTrie >::iterator it = d_data.begin(); it != d_data.end(); ++it ){ for( unsigned i=0; i<depth; i++ ){ Debug(c) << " "; } Debug(c) << it->first << std::endl; it->second.debugPrint( c, n, depth+1 ); @@ -57,7 +71,8 @@ void TermArgTrie::debugPrint( const char * c, Node n, unsigned depth ) { } TermDb::TermDb( context::Context* c, context::UserContext* u, QuantifiersEngine* qe ) : d_quantEngine( qe ), d_op_ccount( u ) { - + d_true = NodeManager::currentNM()->mkConst( true ); + d_false = NodeManager::currentNM()->mkConst( false ); } /** ground terms */ @@ -129,8 +144,6 @@ void TermDb::addTerm( Node n, std::set< Node >& added, bool withinQuant ){ for( size_t i=0; i<d_op_triggers[op].size(); i++ ){ addedLemmas += d_op_triggers[op][i]->addTerm( n ); } - //Message() << "Terms, added lemmas: " << addedLemmas << std::endl; - d_quantEngine->flushLemmas( &d_quantEngine->getOutputChannel() ); } } } @@ -143,65 +156,193 @@ void TermDb::addTerm( Node n, std::set< Node >& added, bool withinQuant ){ } } - void TermDb::reset( Theory::Effort effort ){ +void TermDb::computeArgReps( TNode n ) { + if( d_arg_reps.find( n )==d_arg_reps.end() ){ + eq::EqualityEngine * ee = d_quantEngine->getTheoryEngine()->getMasterEqualityEngine(); + for( unsigned j=0; j<n.getNumChildren(); j++ ){ + TNode r = ee->hasTerm( n[j] ) ? ee->getRepresentative( n[j] ) : n[j]; + d_arg_reps[n].push_back( r ); + } + } +} + +void TermDb::computeUfEqcTerms( TNode f ) { + if( d_func_map_eqc_trie.find( f )==d_func_map_eqc_trie.end() ){ + d_func_map_eqc_trie[f].clear(); + eq::EqualityEngine * ee = d_quantEngine->getTheoryEngine()->getMasterEqualityEngine(); + for( unsigned i=0; i<d_op_map[f].size(); i++ ){ + TNode n = d_op_map[f][i]; + if( !n.getAttribute(NoMatchAttribute()) ){ + computeArgReps( n ); + TNode r = ee->hasTerm( n ) ? ee->getRepresentative( n ) : n; + d_func_map_eqc_trie[f].d_data[r].addTerm( n, d_arg_reps[n] ); + } + } + } +} + +TNode TermDb::evaluateTerm( TNode n, std::map< TNode, TNode >& subs, bool subsRep ) { + Trace("term-db-eval") << "evaluate term : " << n << std::endl; + eq::EqualityEngine * ee = d_quantEngine->getTheoryEngine()->getMasterEqualityEngine(); + if( ee->hasTerm( n ) ){ + Trace("term-db-eval") << "...exists in ee, return rep " << std::endl; + return ee->getRepresentative( n ); + }else if( n.getKind()==BOUND_VARIABLE ){ + Assert( subs.find( n )!=subs.end() ); + Trace("term-db-eval") << "...substitution is : " << subs[n] << std::endl; + if( subsRep ){ + Assert( ee->hasTerm( subs[n] ) ); + Assert( ee->getRepresentative( subs[n] )==subs[n] ); + return subs[n]; + }else{ + return evaluateTerm( subs[n], subs, subsRep ); + } + }else{ + if( n.hasOperator() ){ + TNode f = getOperator( n ); + if( !f.isNull() ){ + std::vector< TNode > args; + for( unsigned i=0; i<n.getNumChildren(); i++ ){ + TNode c = evaluateTerm( n[i], subs, subsRep ); + if( c.isNull() ){ + return TNode::null(); + } + Trace("term-db-eval") << "Got child : " << c << std::endl; + args.push_back( c ); + } + Trace("term-db-eval") << "Get term from DB" << std::endl; + TNode nn = d_func_map_trie[f].existsTerm( args ); + Trace("term-db-eval") << "Got term " << nn << std::endl; + if( !nn.isNull() ){ + if( ee->hasTerm( nn ) ){ + Trace("term-db-eval") << "return rep " << std::endl; + return ee->getRepresentative( nn ); + }else{ + //Assert( false ); + } + } + } + } + return TNode::null(); + } +} + +TNode TermDb::evaluateTerm( TNode n ) { + eq::EqualityEngine * ee = d_quantEngine->getTheoryEngine()->getMasterEqualityEngine(); + if( ee->hasTerm( n ) ){ + return ee->getRepresentative( n ); + }else if( n.getKind()!=BOUND_VARIABLE ){ + if( n.hasOperator() ){ + TNode f = getOperator( n ); + if( !f.isNull() ){ + std::vector< TNode > args; + for( unsigned i=0; i<n.getNumChildren(); i++ ){ + TNode c = evaluateTerm( n[i] ); + if( c.isNull() ){ + return TNode::null(); + } + args.push_back( c ); + } + TNode nn = d_func_map_trie[f].existsTerm( args ); + if( !nn.isNull() ){ + if( ee->hasTerm( nn ) ){ + return ee->getRepresentative( nn ); + }else{ + //Assert( false ); + } + } + } + } + } + return TNode::null(); +} + +bool TermDb::isEntailed( TNode n, std::map< TNode, TNode >& subs, bool subsRep, bool pol ) { + Trace("term-db-eval") << "Check entailed : " << n << ", pol = " << pol << std::endl; + Assert( n.getType().isBoolean() ); + if( n.getKind()==EQUAL ){ + TNode n1 = evaluateTerm( n[0], subs, subsRep ); + if( !n1.isNull() ){ + TNode n2 = evaluateTerm( n[1], subs, subsRep ); + if( !n2.isNull() ){ + eq::EqualityEngine * ee = d_quantEngine->getTheoryEngine()->getMasterEqualityEngine(); + Assert( ee->hasTerm( n1 ) ); + Assert( ee->hasTerm( n2 ) ); + if( pol ){ + return n1==n2 || ee->areEqual( n1, n2 ); + }else{ + return n1!=n2 && ee->areDisequal( n1, n2, false ); + } + } + } + }else if( n.getKind()==APPLY_UF ){ + TNode n1 = evaluateTerm( n, subs, subsRep ); + if( !n1.isNull() ){ + eq::EqualityEngine * ee = d_quantEngine->getTheoryEngine()->getMasterEqualityEngine(); + Assert( ee->hasTerm( n1 ) ); + TNode n2 = pol ? d_true : d_false; + if( ee->hasTerm( n2 ) ){ + return ee->areEqual( n1, n2 ); + } + } + }else if( n.getKind()==NOT ){ + return isEntailed( n[0], subs, subsRep, !pol ); + }else if( n.getKind()==OR || n.getKind()==AND ){ + bool simPol = ( pol && n.getKind()==OR ) || ( !pol && n.getKind()==AND ); + for( unsigned i=0; i<n.getNumChildren(); i++ ){ + if( isEntailed( n[i], subs, subsRep, pol ) ){ + if( simPol ){ + return true; + } + }else{ + if( !simPol ){ + return false; + } + } + } + return !simPol; + }else if( n.getKind()==IFF || n.getKind()==ITE ){ + for( unsigned i=0; i<2; i++ ){ + if( isEntailed( n[0], subs, subsRep, i==0 ) ){ + unsigned ch = ( n.getKind()==IFF || i==0 ) ? 1 : 2; + bool reqPol = ( n.getKind()==ITE || i==0 ) ? pol : !pol; + return isEntailed( n[ch], subs, subsRep, reqPol ); + } + } + } + return false; +} + +void TermDb::reset( Theory::Effort effort ){ int nonCongruentCount = 0; int congruentCount = 0; int alreadyCongruentCount = 0; + d_op_nonred_count.clear(); + d_arg_reps.clear(); + d_func_map_trie.clear(); + d_func_map_eqc_trie.clear(); //rebuild d_func/pred_map_trie for each operation, this will calculate all congruent terms for( std::map< Node, std::vector< Node > >::iterator it = d_op_map.begin(); it != d_op_map.end(); ++it ){ d_op_nonred_count[ it->first ] = 0; if( !it->second.empty() ){ - if( it->second[0].getType().isBoolean() ){ - d_pred_map_trie[ 0 ][ it->first ].d_data.clear(); - d_pred_map_trie[ 1 ][ it->first ].d_data.clear(); - }else{ - d_func_map_trie[ it->first ].d_data.clear(); - for( int i=0; i<(int)it->second.size(); i++ ){ - Node n = it->second[i]; - computeModelBasisArgAttribute( n ); - if( !n.getAttribute(NoMatchAttribute()) ){ - if( !d_func_map_trie[ it->first ].addTerm( d_quantEngine, n ) ){ - NoMatchAttribute nma; - n.setAttribute(nma,true); - Debug("term-db-cong") << n << " is redundant." << std::endl; - congruentCount++; - }else{ - nonCongruentCount++; - d_op_nonred_count[ it->first ]++; - } - }else{ + for( unsigned i=0; i<it->second.size(); i++ ){ + Node n = it->second[i]; + computeModelBasisArgAttribute( n ); + if( !n.getAttribute(NoMatchAttribute()) ){ + computeArgReps( n ); + if( !d_func_map_trie[ it->first ].addTerm( n, d_arg_reps[n] ) ){ + NoMatchAttribute nma; + n.setAttribute(nma,true); + Debug("term-db-cong") << n << " is redundant." << std::endl; congruentCount++; - alreadyCongruentCount++; - } - } - } - } - } - for( int i=0; i<2; i++ ){ - Node n = NodeManager::currentNM()->mkConst( i==1 ); - if( d_quantEngine->getEqualityQuery()->getEngine()->hasTerm( n ) ){ - eq::EqClassIterator eqc( d_quantEngine->getEqualityQuery()->getEngine()->getRepresentative( n ), - d_quantEngine->getEqualityQuery()->getEngine() ); - while( !eqc.isFinished() ){ - Node en = (*eqc); - computeModelBasisArgAttribute( en ); - if( en.getKind()==APPLY_UF && !TermDb::hasInstConstAttr(en) ){ - if( !en.getAttribute(NoMatchAttribute()) ){ - Node op = getOperator( en ); - if( !d_pred_map_trie[i][op].addTerm( d_quantEngine, en ) ){ - NoMatchAttribute nma; - en.setAttribute(nma,true); - Debug("term-db-cong") << en << " is redundant." << std::endl; - congruentCount++; - }else{ - nonCongruentCount++; - d_op_nonred_count[ op ]++; - } }else{ - alreadyCongruentCount++; + nonCongruentCount++; + d_op_nonred_count[ it->first ]++; } + }else{ + congruentCount++; + alreadyCongruentCount++; } - ++eqc; } } } @@ -219,6 +360,39 @@ void TermDb::addTerm( Node n, std::set< Node >& added, bool withinQuant ){ } } +TermArgTrie * TermDb::getTermArgTrie( Node f ) { + std::map< Node, TermArgTrie >::iterator itut = d_func_map_trie.find( f ); + if( itut!=d_func_map_trie.end() ){ + return &itut->second; + }else{ + return NULL; + } +} + +TermArgTrie * TermDb::getTermArgTrie( Node eqc, Node f ) { + computeUfEqcTerms( f ); + std::map< Node, TermArgTrie >::iterator itut = d_func_map_eqc_trie.find( f ); + if( itut==d_func_map_eqc_trie.end() ){ + return NULL; + }else{ + if( eqc.isNull() ){ + return &itut->second; + }else{ + std::map< TNode, TermArgTrie >::iterator itute = itut->second.d_data.find( eqc ); + if( itute!=itut->second.d_data.end() ){ + return &itute->second; + }else{ + return NULL; + } + } + } +} + +TNode TermDb::existsTerm( Node f, Node n ) { + computeArgReps( n ); + return d_func_map_trie[f].existsTerm( d_arg_reps[n] ); +} + Node TermDb::getModelBasisTerm( TypeNode tn, int i ){ if( d_model_basis_term.find( tn )==d_model_basis_term.end() ){ Node mbt; @@ -448,14 +622,15 @@ void getSelfSel( const DatatypeConstructor& dc, Node n, TypeNode ntn, std::vecto Node TermDb::mkSkolemizedBody( Node f, Node n, std::vector< TypeNode >& argTypes, std::vector< TNode >& fvs, - std::vector< Node >& sk ) { + std::vector< Node >& sk, Node& sub, std::vector< unsigned >& sub_vars ) { + Assert( sk.empty() || sk.size()==f[0].getNumChildren() ); //calculate the variables and substitution std::vector< TNode > ind_vars; std::vector< unsigned > ind_var_indicies; std::vector< TNode > vars; std::vector< unsigned > var_indicies; for( unsigned i=0; i<f[0].getNumChildren(); i++ ){ - if( options::dtStcInduction() && datatypes::DatatypesRewriter::isTermDatatype( f[0][i] ) ){ + if( isInductionTerm( f[0][i] ) ){ ind_vars.push_back( f[0][i] ); ind_var_indicies.push_back( i ); }else{ @@ -463,19 +638,23 @@ Node TermDb::mkSkolemizedBody( Node f, Node n, std::vector< TypeNode >& argTypes var_indicies.push_back( i ); } Node s; - //make the new function symbol - if( argTypes.empty() ){ - s = NodeManager::currentNM()->mkSkolem( "skv", f[0][i].getType(), "created during skolemization" ); + //make the new function symbol or use existing + if( i>=sk.size() ){ + if( argTypes.empty() ){ + s = NodeManager::currentNM()->mkSkolem( "skv", f[0][i].getType(), "created during skolemization" ); + }else{ + TypeNode typ = NodeManager::currentNM()->mkFunctionType( argTypes, f[0][i].getType() ); + Node op = NodeManager::currentNM()->mkSkolem( "skop", typ, "op created during pre-skolemization" ); + //DOTHIS: set attribute on op, marking that it should not be selected as trigger + std::vector< Node > funcArgs; + funcArgs.push_back( op ); + funcArgs.insert( funcArgs.end(), fvs.begin(), fvs.end() ); + s = NodeManager::currentNM()->mkNode( kind::APPLY_UF, funcArgs ); + } + sk.push_back( s ); }else{ - TypeNode typ = NodeManager::currentNM()->mkFunctionType( argTypes, f[0][i].getType() ); - Node op = NodeManager::currentNM()->mkSkolem( "skop", typ, "op created during pre-skolemization" ); - //DOTHIS: set attribute on op, marking that it should not be selected as trigger - std::vector< Node > funcArgs; - funcArgs.push_back( op ); - funcArgs.insert( funcArgs.end(), fvs.begin(), fvs.end() ); - s = NodeManager::currentNM()->mkNode( kind::APPLY_UF, funcArgs ); + Assert( sk[i].getType()==f[0][i].getType() ); } - sk.push_back( s ); } Node ret; if( vars.empty() ){ @@ -489,44 +668,57 @@ Node TermDb::mkSkolemizedBody( Node f, Node n, std::vector< TypeNode >& argTypes ret = n.substitute( vars.begin(), vars.end(), var_sk.begin(), var_sk.end() ); } if( !ind_vars.empty() ){ - Trace("stc-ind") << "Ind strengthen : (not " << f << ")" << std::endl; - Trace("stc-ind") << "Skolemized is : " << ret << std::endl; - Node nret; + Trace("sk-ind") << "Ind strengthen : (not " << f << ")" << std::endl; + Trace("sk-ind") << "Skolemized is : " << ret << std::endl; Node n_str_ind; TypeNode tn = ind_vars[0].getType(); - if( datatypes::DatatypesRewriter::isTypeDatatype(tn) ){ - Node k = sk[ind_var_indicies[0]]; + Node k = sk[ind_var_indicies[0]]; + Node nret = ret.substitute( ind_vars[0], k ); + //note : everything is under a negation + //the following constructs ~( R( x, k ) => ~P( x ) ) + if( options::dtStcInduction() && datatypes::DatatypesRewriter::isTypeDatatype(tn) ){ const Datatype& dt = ((DatatypeType)(tn).toType()).getDatatype(); std::vector< Node > disj; for( unsigned i=0; i<dt.getNumConstructors(); i++ ){ - std::vector< Node > selfSel; - getSelfSel( dt[i], k, tn, selfSel ); - std::vector< Node > conj; - conj.push_back( NodeManager::currentNM()->mkNode( APPLY_TESTER, Node::fromExpr( dt[i].getTester() ), k ).negate() ); - for( unsigned j=0; j<selfSel.size(); j++ ){ - conj.push_back( ret.substitute( ind_vars[0], selfSel[j] ).negate() ); - } - disj.push_back( conj.size()==1 ? conj[0] : NodeManager::currentNM()->mkNode( OR, conj ) ); + std::vector< Node > selfSel; + getSelfSel( dt[i], k, tn, selfSel ); + std::vector< Node > conj; + conj.push_back( NodeManager::currentNM()->mkNode( APPLY_TESTER, Node::fromExpr( dt[i].getTester() ), k ).negate() ); + for( unsigned j=0; j<selfSel.size(); j++ ){ + conj.push_back( ret.substitute( ind_vars[0], selfSel[j] ).negate() ); + } + disj.push_back( conj.size()==1 ? conj[0] : NodeManager::currentNM()->mkNode( OR, conj ) ); } Assert( !disj.empty() ); n_str_ind = disj.size()==1 ? disj[0] : NodeManager::currentNM()->mkNode( AND, disj ); - Trace("stc-ind") << "Strengthening is : " << n_str_ind << std::endl; - nret = ret.substitute( ind_vars[0], k ); + }else if( options::intWfInduction() && tn.isInteger() ){ + Node icond = NodeManager::currentNM()->mkNode( GEQ, k, NodeManager::currentNM()->mkConst( Rational(0) ) ); + Node iret = ret.substitute( ind_vars[0], NodeManager::currentNM()->mkNode( MINUS, k, NodeManager::currentNM()->mkConst( Rational(1) ) ) ).negate(); + n_str_ind = NodeManager::currentNM()->mkNode( OR, icond.negate(), iret ); + n_str_ind = NodeManager::currentNM()->mkNode( AND, icond, n_str_ind ); }else{ - Trace("stc-ind") << "Unknown induction for term : " << ind_vars[0] << ", type = " << tn << std::endl; + Trace("sk-ind") << "Unknown induction for term : " << ind_vars[0] << ", type = " << tn << std::endl; Assert( false ); } - + Trace("sk-ind") << "Strengthening is : " << n_str_ind << std::endl; + std::vector< Node > rem_ind_vars; rem_ind_vars.insert( rem_ind_vars.end(), ind_vars.begin()+1, ind_vars.end() ); if( !rem_ind_vars.empty() ){ Node bvl = NodeManager::currentNM()->mkNode( BOUND_VAR_LIST, rem_ind_vars ); nret = NodeManager::currentNM()->mkNode( FORALL, bvl, nret ); + nret = Rewriter::rewrite( nret ); + sub = nret; + sub_vars.insert( sub_vars.end(), ind_var_indicies.begin()+1, ind_var_indicies.end() ); n_str_ind = NodeManager::currentNM()->mkNode( FORALL, bvl, n_str_ind.negate() ).negate(); } ret = NodeManager::currentNM()->mkNode( OR, nret, n_str_ind ); } Trace("quantifiers-sk") << "mkSkolem body for " << f << " returns : " << ret << std::endl; + //if it has an instantiation level, set the skolemized body to that level + if( f.hasAttribute(InstLevelAttribute()) ){ + theory::QuantifiersEngine::setInstantiationLevelAttr( ret, f.getAttribute(InstLevelAttribute()) ); + } return ret; } @@ -535,7 +727,17 @@ Node TermDb::getSkolemizedBody( Node f ){ if( d_skolem_body.find( f )==d_skolem_body.end() ){ std::vector< TypeNode > fvTypes; std::vector< TNode > fvs; - d_skolem_body[ f ] = mkSkolemizedBody( f, f[1], fvTypes, fvs, d_skolem_constants[f] ); + Node sub; + std::vector< unsigned > sub_vars; + d_skolem_body[ f ] = mkSkolemizedBody( f, f[1], fvTypes, fvs, d_skolem_constants[f], sub, sub_vars ); + //store sub quantifier information + if( !sub.isNull() ){ + //if we are skolemizing one at a time, we already know the skolem constants of the sub-quantified formula, store them + Assert( d_skolem_constants[sub].empty() ); + for( unsigned i=0; i<sub_vars.size(); i++ ){ + d_skolem_constants[sub].push_back( d_skolem_constants[f][sub_vars[i]] ); + } + } Assert( d_skolem_constants[f].size()==f[0].getNumChildren() ); if( options::sortInference() ){ for( unsigned i=0; i<d_skolem_constants[f].size(); i++ ){ @@ -752,6 +954,17 @@ void TermDb::registerTrigger( theory::inst::Trigger* tr, Node op ){ } } +bool TermDb::isInductionTerm( Node n ) { + if( options::dtStcInduction() && datatypes::DatatypesRewriter::isTermDatatype( n ) ){ + return true; + } + if( options::intWfInduction() && n.getType().isInteger() ){ + return true; + } + return false; +} + + bool TermDb::isRewriteRule( Node q ) { return !getRewriteRule( q ).isNull(); } diff --git a/src/theory/quantifiers/term_database.h b/src/theory/quantifiers/term_database.h index c839d08d7..91ad0135b 100644 --- a/src/theory/quantifiers/term_database.h +++ b/src/theory/quantifiers/term_database.h @@ -55,6 +55,13 @@ typedef expr::Attribute<ModelBasisArgAttributeId, uint64_t> ModelBasisArgAttribu struct BoundIntLitAttributeId {}; typedef expr::Attribute<BoundIntLitAttributeId, uint64_t> BoundIntLitAttribute; +//for quantifier instantiation level +struct QuantInstLevelAttributeId {}; +typedef expr::Attribute<QuantInstLevelAttributeId, uint64_t> QuantInstLevelAttribute; + +//rewrite-rule priority +struct RrPriorityAttributeId {}; +typedef expr::Attribute<RrPriorityAttributeId, uint64_t> RrPriorityAttribute; class QuantifiersEngine; @@ -69,14 +76,14 @@ namespace rrinst{ namespace quantifiers { class TermArgTrie { -private: - bool addTerm2( QuantifiersEngine* qe, Node n, int argIndex ); public: /** the data */ - std::map< Node, TermArgTrie > d_data; + std::map< TNode, TermArgTrie > d_data; public: - bool addTerm( QuantifiersEngine* qe, Node n ) { return addTerm2( qe, n, 0 ); } + TNode existsTerm( std::vector< TNode >& reps, int argIndex = 0 ); + bool addTerm( TNode n, std::vector< TNode >& reps, int argIndex = 0 ); void debugPrint( const char * c, Node n, unsigned depth = 0 ); + void clear() { d_data.clear(); } };/* class TermArgTrie */ @@ -103,6 +110,9 @@ private: public: TermDb( context::Context* c, context::UserContext* u, QuantifiersEngine* qe ); ~TermDb(){} + /** boolean terms */ + Node d_true; + Node d_false; /** ground terms */ unsigned getNumGroundTerms( Node f ); /** count number of non-redundant ground terms per operator */ @@ -111,16 +121,34 @@ public: std::map< Node, std::vector< Node > > d_op_map; /** map from APPLY_UF functions to trie */ std::map< Node, TermArgTrie > d_func_map_trie; - /** map from APPLY_UF predicates to trie */ - std::map< Node, TermArgTrie > d_pred_map_trie[2]; + std::map< Node, TermArgTrie > d_func_map_eqc_trie; + /**mapping from UF terms to representatives of their arguments */ + std::map< TNode, std::vector< TNode > > d_arg_reps; /** map from type nodes to terms of that type */ std::map< TypeNode, std::vector< Node > > d_type_map; /** add a term to the database */ void addTerm( Node n, std::set< Node >& added, bool withinQuant = false ); /** reset (calculate which terms are active) */ void reset( Theory::Effort effort ); - /** get operation */ + /** get operator*/ Node getOperator( Node n ); + /** get term arg index */ + TermArgTrie * getTermArgTrie( Node f ); + TermArgTrie * getTermArgTrie( Node eqc, Node f ); + /** exists term */ + TNode existsTerm( Node f, Node n ); + /** compute arg reps */ + void computeArgReps( TNode n ); + /** compute uf eqc terms */ + void computeUfEqcTerms( TNode f ); + /** evaluate a term under a substitution. Return representative in EE if possible. + * subsRep is whether subs contains only representatives + */ + TNode evaluateTerm( TNode n, std::map< TNode, TNode >& subs, bool subsRep ); + /** same as above, but without substitution */ + TNode evaluateTerm( TNode n ); + /** is entailed (incomplete check) */ + bool isEntailed( TNode n, std::map< TNode, TNode >& subs, bool subsRep, bool pol ); public: /** parent structure (for efficient E-matching): n -> op -> index -> L @@ -206,7 +234,7 @@ public: std::map< Node, std::vector< Node > > d_skolem_constants; /** make the skolemized body f[e/x] */ static Node mkSkolemizedBody( Node f, Node n, std::vector< TypeNode >& fvTypes, std::vector< TNode >& fvs, - std::vector< Node >& sk ); + std::vector< Node >& sk, Node& sub, std::vector< unsigned >& sub_vars ); /** get the skolemized body */ Node getSkolemizedBody( Node f); @@ -245,11 +273,18 @@ public: int isInstanceOf( Node n1, Node n2 ); /** filter all nodes that have instances */ void filterInstances( std::vector< Node >& nodes ); -public: + +public: //for induction + /** is induction variable */ + static bool isInductionTerm( Node n ); + + +public: //general queries concerning quantified formulas wrt modules /** is quantifier treated as a rewrite rule? */ static bool isRewriteRule( Node q ); /** get the rewrite rule associated with the quanfied formula */ static Node getRewriteRule( Node q ); + };/* class TermDb */ }/* CVC4::theory::quantifiers namespace */ diff --git a/src/theory/quantifiers/theory_quantifiers.cpp b/src/theory/quantifiers/theory_quantifiers.cpp index 4ba3c499d..18546b09c 100644 --- a/src/theory/quantifiers/theory_quantifiers.cpp +++ b/src/theory/quantifiers/theory_quantifiers.cpp @@ -42,6 +42,8 @@ TheoryQuantifiers::TheoryQuantifiers(Context* c, context::UserContext* u, Output d_baseDecLevel = -1; out.handleUserAttribute( "axiom", this ); out.handleUserAttribute( "conjecture", this ); + out.handleUserAttribute( "inst-level", this ); + out.handleUserAttribute( "rr-priority", this ); } TheoryQuantifiers::~TheoryQuantifiers() { @@ -107,6 +109,10 @@ void TheoryQuantifiers::collectModelInfo(TheoryModel* m, bool fullModel) { } void TheoryQuantifiers::check(Effort e) { + if (done() && !fullEffort(e)) { + return; + } + CodeTimer codeTimer(d_theoryTime); Trace("quantifiers-check") << "quantifiers::check(" << e << ")" << std::endl; @@ -193,6 +199,6 @@ bool TheoryQuantifiers::restart(){ } } -void TheoryQuantifiers::setUserAttribute( const std::string& attr, Node n ){ - QuantifiersAttributes::setUserAttribute( attr, n ); +void TheoryQuantifiers::setUserAttribute(const std::string& attr, Node n, std::vector<Node> node_values, std::string str_value){ + QuantifiersAttributes::setUserAttribute( attr, n, node_values, str_value ); } diff --git a/src/theory/quantifiers/theory_quantifiers.h b/src/theory/quantifiers/theory_quantifiers.h index ffd3c4c59..6febc8417 100644 --- a/src/theory/quantifiers/theory_quantifiers.h +++ b/src/theory/quantifiers/theory_quantifiers.h @@ -69,7 +69,7 @@ public: void shutdown() { } std::string identify() const { return std::string("TheoryQuantifiers"); } bool flipDecision(); - void setUserAttribute( const std::string& attr, Node n ); + void setUserAttribute(const std::string& attr, Node n, std::vector<Node> node_values, std::string str_value); eq::EqualityEngine* getMasterEqualityEngine() { return d_masterEqualityEngine; } bool ppDontRewriteSubterm(TNode atom) { return atom.getKind() == kind::FORALL || atom.getKind() == kind::EXISTS; } private: diff --git a/src/theory/quantifiers/theory_quantifiers_type_rules.h b/src/theory/quantifiers/theory_quantifiers_type_rules.h index e4b1732dd..7fc69c539 100644 --- a/src/theory/quantifiers/theory_quantifiers_type_rules.h +++ b/src/theory/quantifiers/theory_quantifiers_type_rules.h @@ -88,6 +88,13 @@ struct QuantifierInstPatternTypeRule { } };/* struct QuantifierInstPatternTypeRule */ +struct QuantifierInstNoPatternTypeRule { + inline static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check) + throw(TypeCheckingExceptionPrivate) { + Assert(n.getKind() == kind::INST_NO_PATTERN ); + return nodeManager->instPatternType(); + } +};/* struct QuantifierInstNoPatternTypeRule */ struct QuantifierInstPatternListTypeRule { inline static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check) @@ -95,7 +102,7 @@ struct QuantifierInstPatternListTypeRule { Assert(n.getKind() == kind::INST_PATTERN_LIST ); if( check ){ for( int i=0; i<(int)n.getNumChildren(); i++ ){ - if( n[i].getKind()!=kind::INST_PATTERN ){ + if( n[i].getKind()!=kind::INST_PATTERN && n[i].getKind()!=kind::INST_NO_PATTERN ){ throw TypeCheckingExceptionPrivate(n, "argument of inst pattern list is not inst pattern"); } } diff --git a/src/theory/quantifiers/trigger.cpp b/src/theory/quantifiers/trigger.cpp index c6ee48057..b2b8e7197 100644 --- a/src/theory/quantifiers/trigger.cpp +++ b/src/theory/quantifiers/trigger.cpp @@ -188,19 +188,7 @@ Trigger* Trigger::mkTrigger( QuantifiersEngine* qe, Node f, std::vector< Node >& } //check for duplicate? - if( trOption==TR_MAKE_NEW ){ - //static int trNew = 0; - //static int trOld = 0; - //Trigger* t = qe->getTermDatabase()->getTrigger( trNodes ); - //if( t ){ - // trOld++; - //}else{ - // trNew++; - //} - //if( (trNew+trOld)%100==0 ){ - // Notice() << "Trigger new old = " << trNew << " " << trOld << std::endl; - //} - }else{ + if( trOption!=TR_MAKE_NEW ){ Trigger* t = qe->getTriggerDatabase()->getTrigger( trNodes ); if( t ){ if( trOption==TR_GET_OLD ){ @@ -215,21 +203,13 @@ Trigger* Trigger::mkTrigger( QuantifiersEngine* qe, Node f, std::vector< Node >& qe->getTriggerDatabase()->addTrigger( trNodes, t ); return t; } + Trigger* Trigger::mkTrigger( QuantifiersEngine* qe, Node f, Node n, int matchOption, bool keepAll, int trOption, bool smartTriggers ){ std::vector< Node > nodes; nodes.push_back( n ); return mkTrigger( qe, f, nodes, matchOption, keepAll, trOption, smartTriggers ); } -bool Trigger::isUsableTrigger( std::vector< Node >& nodes, Node f ){ - for( int i=0; i<(int)nodes.size(); i++ ){ - if( !isUsableTrigger( nodes[i], f ) ){ - return false; - } - } - return true; -} - bool Trigger::isUsable( Node n, Node f ){ if( quantifiers::TermDb::getInstConstAttr(n)==f ){ if( isAtomicTrigger( n ) ){ @@ -243,9 +223,7 @@ bool Trigger::isUsable( Node n, Node f ){ return true; }else{ std::map< Node, Node > coeffs; - if( isArithmeticTrigger( f, n, coeffs ) ){ - return true; - }else if( isBooleanTermTrigger( n ) ){ + if( isBooleanTermTrigger( n ) ){ return true; } } @@ -324,7 +302,7 @@ bool Trigger::isUsableTrigger( Node n, Node f ){ bool Trigger::isAtomicTrigger( Node n ){ Kind k = n.getKind(); - return ( k==APPLY_UF && !n.getOperator().getAttribute(NoMatchAttribute()) ) || + return ( k==APPLY_UF && !n.getOperator().getAttribute(NoMatchAttribute()) ) || ( k!=APPLY_UF && isAtomicTriggerKind( k ) ); } bool Trigger::isAtomicTriggerKind( Kind k ) { @@ -347,7 +325,7 @@ bool Trigger::isSimpleTrigger( Node n ){ } -bool Trigger::collectPatTerms2( QuantifiersEngine* qe, Node f, Node n, std::map< Node, bool >& patMap, int tstrt, bool pol, bool hasPol ){ +bool Trigger::collectPatTerms2( QuantifiersEngine* qe, Node f, Node n, std::map< Node, bool >& patMap, int tstrt, std::vector< Node >& exclude, bool pol, bool hasPol ){ if( patMap.find( n )==patMap.end() ){ patMap[ n ] = false; bool newHasPol = n.getKind()==IFF ? false : hasPol; @@ -359,14 +337,17 @@ bool Trigger::collectPatTerms2( QuantifiersEngine* qe, Node f, Node n, std::map< bool retVal = false; for( int i=0; i<(int)n.getNumChildren(); i++ ){ bool newHasPol2 = (n.getKind()==ITE && i==0) ? false : newHasPol; - if( collectPatTerms2( qe, f, n[i], patMap, tstrt, newPol, newHasPol2 ) ){ + if( collectPatTerms2( qe, f, n[i], patMap, tstrt, exclude, newPol, newHasPol2 ) ){ retVal = true; } } if( retVal ){ return true; }else{ - Node nu = getIsUsableTrigger( n, f, pol, hasPol ); + Node nu; + if( std::find( exclude.begin(), exclude.end(), n )==exclude.end() ){ + nu = getIsUsableTrigger( n, f, pol, hasPol ); + } if( !nu.isNull() ){ patMap[ nu ] = true; return true; @@ -377,7 +358,10 @@ bool Trigger::collectPatTerms2( QuantifiersEngine* qe, Node f, Node n, std::map< } }else{ bool retVal = false; - Node nu = getIsUsableTrigger( n, f, pol, hasPol ); + Node nu; + if( std::find( exclude.begin(), exclude.end(), n )==exclude.end() ){ + nu = getIsUsableTrigger( n, f, pol, hasPol ); + } if( !nu.isNull() ){ patMap[ nu ] = true; if( tstrt==TS_MAX_TRIGGER ){ @@ -389,7 +373,7 @@ bool Trigger::collectPatTerms2( QuantifiersEngine* qe, Node f, Node n, std::map< if( n.getKind()!=FORALL ){ for( int i=0; i<(int)n.getNumChildren(); i++ ){ bool newHasPol2 = (n.getKind()==ITE && i==0) ? false : newHasPol; - if( collectPatTerms2( qe, f, n[i], patMap, tstrt, newPol, newHasPol2 ) ){ + if( collectPatTerms2( qe, f, n[i], patMap, tstrt, exclude, newPol, newHasPol2 ) ){ retVal = true; } } @@ -401,12 +385,41 @@ bool Trigger::collectPatTerms2( QuantifiersEngine* qe, Node f, Node n, std::map< } } -void Trigger::collectPatTerms( QuantifiersEngine* qe, Node f, Node n, std::vector< Node >& patTerms, int tstrt, bool filterInst ){ +bool Trigger::isBooleanTermTrigger( Node n ) { + if( n.getKind()==ITE ){ + //check for boolean term converted to ITE + if( n[0].getKind()==INST_CONSTANT && + n[1].getKind()==CONST_BITVECTOR && + n[2].getKind()==CONST_BITVECTOR ){ + if( ((BitVectorType)n[1].getType().toType()).getSize()==1 && + n[1].getConst<BitVector>().toInteger()==1 && + n[2].getConst<BitVector>().toInteger()==0 ){ + return true; + } + } + } + return false; +} + +bool Trigger::isPureTheoryTrigger( Node n ) { + if( n.getKind()==APPLY_UF || n.getKind()==VARIABLE || n.getKind()==SKOLEM ){ //|| !quantifiers::TermDb::hasInstConstAttr( n ) ){ + return false; + }else{ + for( unsigned i=0; i<n.getNumChildren(); i++ ){ + if( !isPureTheoryTrigger( n[i] ) ){ + return false; + } + } + return true; + } +} + +void Trigger::collectPatTerms( QuantifiersEngine* qe, Node f, Node n, std::vector< Node >& patTerms, int tstrt, std::vector< Node >& exclude, bool filterInst ){ std::map< Node, bool > patMap; if( filterInst ){ //immediately do not consider any term t for which another term is an instance of t std::vector< Node > patTerms2; - collectPatTerms( qe, f, n, patTerms2, TS_ALL, false ); + collectPatTerms( qe, f, n, patTerms2, TS_ALL, exclude, false ); std::vector< Node > temp; temp.insert( temp.begin(), patTerms2.begin(), patTerms2.end() ); qe->getTermDatabase()->filterInstances( temp ); @@ -434,7 +447,7 @@ void Trigger::collectPatTerms( QuantifiersEngine* qe, Node f, Node n, std::vecto } } } - collectPatTerms2( qe, f, n, patMap, tstrt, true, true ); + collectPatTerms2( qe, f, n, patMap, tstrt, exclude, true, true ); for( std::map< Node, bool >::iterator it = patMap.begin(); it != patMap.end(); ++it ){ if( it->second ){ patTerms.push_back( it->first ); @@ -442,65 +455,91 @@ void Trigger::collectPatTerms( QuantifiersEngine* qe, Node f, Node n, std::vecto } } -bool Trigger::isArithmeticTrigger( Node f, Node n, std::map< Node, Node >& coeffs ){ - if( n.getKind()==PLUS ){ - Assert( coeffs.empty() ); - NodeBuilder<> t(kind::PLUS); - for( int i=0; i<(int)n.getNumChildren(); i++ ){ +Node Trigger::getInversionVariable( Node n ) { + if( n.getKind()==INST_CONSTANT ){ + return n; + }else if( n.getKind()==PLUS || n.getKind()==MULT ){ + Node ret; + for( unsigned i=0; i<n.getNumChildren(); i++ ){ if( quantifiers::TermDb::hasInstConstAttr(n[i]) ){ - if( n[i].getKind()==INST_CONSTANT ){ - if( quantifiers::TermDb::getInstConstAttr(n[i])==f ){ - coeffs[ n[i] ] = Node::null(); - }else{ - coeffs.clear(); - return false; + if( ret.isNull() ){ + ret = getInversionVariable( n[i] ); + if( ret.isNull() ){ + Trace("var-trigger-debug") << "No : multiple variables " << n << std::endl; + return Node::null(); + } + }else{ + return Node::null(); + } + }else if( n.getKind()==MULT ){ + if( !n[i].isConst() ){ + Trace("var-trigger-debug") << "No : non-linear coefficient " << n << std::endl; + return Node::null(); + }else if( n.getType().isInteger() ){ + Rational r = n[i].getConst<Rational>(); + if( r!=Rational(-1) && r!=Rational(1) ){ + Trace("var-trigger-debug") << "No : not integer coefficient " << n << std::endl; + return Node::null(); } - }else if( !isArithmeticTrigger( f, n[i], coeffs ) ){ - coeffs.clear(); - return false; } - }else{ - t << n[i]; } } - if( t.getNumChildren()==0 ){ - coeffs[ Node::null() ] = NodeManager::currentNM()->mkConst( Rational(0) ); - }else if( t.getNumChildren()==1 ){ - coeffs[ Node::null() ] = t.getChild( 0 ); - }else{ - coeffs[ Node::null() ] = t; - } - return true; - }else if( n.getKind()==MULT ){ - if( n[0].getKind()==INST_CONSTANT && quantifiers::TermDb::getInstConstAttr(n[0])==f ){ - if( !quantifiers::TermDb::hasInstConstAttr(n[1]) ){ - coeffs[ n[0] ] = n[1]; - return true; - } - }else if( n[1].getKind()==INST_CONSTANT && quantifiers::TermDb::getInstConstAttr(n[1])==f ){ - if( !quantifiers::TermDb::hasInstConstAttr(n[0]) ){ - coeffs[ n[1] ] = n[0]; - return true; + return ret; + }else{ + Trace("var-trigger-debug") << "No : unsupported operator " << n << "." << std::endl; + } + return Node::null(); +} + +Node Trigger::getInversion( Node n, Node x ) { + if( n.getKind()==INST_CONSTANT ){ + return x; + }else if( n.getKind()==PLUS || n.getKind()==MULT ){ + int cindex = -1; + for( unsigned i=0; i<n.getNumChildren(); i++ ){ + if( !quantifiers::TermDb::hasInstConstAttr(n[i]) ){ + if( n.getKind()==PLUS ){ + x = NodeManager::currentNM()->mkNode( MINUS, x, n[i] ); + }else if( n.getKind()==MULT ){ + Assert( n[i].isConst() ); + Node coeff = NodeManager::currentNM()->mkConst( Rational(1) / n[i].getConst<Rational>() ); + x = NodeManager::currentNM()->mkNode( MULT, x, coeff ); + } + }else{ + Assert( cindex==-1 ); + cindex = i; } } + Assert( cindex!=-1 ); + return getInversion( n[cindex], x ); } - return false; + return Node::null(); } -bool Trigger::isBooleanTermTrigger( Node n ) { - if( n.getKind()==ITE ){ - //check for boolean term converted to ITE - if( n[0].getKind()==INST_CONSTANT && - n[1].getKind()==CONST_BITVECTOR && - n[2].getKind()==CONST_BITVECTOR ){ - if( ((BitVectorType)n[1].getType().toType()).getSize()==1 && - n[1].getConst<BitVector>().toInteger()==1 && - n[2].getConst<BitVector>().toInteger()==0 ){ - return true; +InstMatchGenerator* Trigger::getInstMatchGenerator( Node n ) { + if( n.getKind()==INST_CONSTANT ){ + return NULL; + }else{ + Trace("var-trigger-debug") << "Is " << n << " a variable trigger?" << std::endl; + if( isBooleanTermTrigger( n ) ){ + VarMatchGeneratorBooleanTerm* vmg = new VarMatchGeneratorBooleanTerm( n[0], n[1] ); + Trace("var-trigger") << "Boolean term trigger : " << n << ", var = " << n[0] << std::endl; + return vmg; + }else{ + Node x; + if( options::purifyTriggers() ){ + x = getInversionVariable( n ); + } + if( !x.isNull() ){ + Node s = getInversion( n, x ); + VarMatchGeneratorTermSubs* vmg = new VarMatchGeneratorTermSubs( x, s ); + Trace("var-trigger") << "Term substitution trigger : " << n << ", var = " << x << ", subs = " << s << std::endl; + return vmg; + }else{ + return new InstMatchGenerator( n ); } } } - return false; } Trigger* TriggerTrie::getTrigger2( std::vector< Node >& nodes ){ diff --git a/src/theory/quantifiers/trigger.h b/src/theory/quantifiers/trigger.h index 17da6f0d5..75ada4f83 100644 --- a/src/theory/quantifiers/trigger.h +++ b/src/theory/quantifiers/trigger.h @@ -30,6 +30,7 @@ class QuantifiersEngine; namespace inst { class IMGenerator; +class InstMatchGenerator; //a collect of nodes representing a trigger class Trigger { @@ -93,7 +94,7 @@ private: static bool isUsable( Node n, Node f ); static Node getIsUsableTrigger( Node n, Node f, bool pol = true, bool hasPol = false ); /** collect all APPLY_UF pattern terms for f in n */ - static bool collectPatTerms2( QuantifiersEngine* qe, Node f, Node n, std::map< Node, bool >& patMap, int tstrt, bool pol, bool hasPol ); + static bool collectPatTerms2( QuantifiersEngine* qe, Node f, Node n, std::map< Node, bool >& patMap, int tstrt, std::vector< Node >& exclude, bool pol, bool hasPol ); public: //different strategies for choosing trigger terms enum { @@ -101,17 +102,19 @@ public: TS_MIN_TRIGGER, TS_ALL, }; - static void collectPatTerms( QuantifiersEngine* qe, Node f, Node n, std::vector< Node >& patTerms, int tstrt, bool filterInst = false ); + static void collectPatTerms( QuantifiersEngine* qe, Node f, Node n, std::vector< Node >& patTerms, int tstrt, std::vector< Node >& exclude, bool filterInst = false ); public: /** is usable trigger */ - static bool isUsableTrigger( std::vector< Node >& nodes, Node f ); static bool isUsableTrigger( Node n, Node f ); static bool isAtomicTrigger( Node n ); static bool isAtomicTriggerKind( Kind k ); static bool isSimpleTrigger( Node n ); - /** get pattern arithmetic */ - static bool isArithmeticTrigger( Node f, Node n, std::map< Node, Node >& coeffs ); static bool isBooleanTermTrigger( Node n ); + static bool isPureTheoryTrigger( Node n ); + /** return data structure for producing matches for this trigger. */ + static InstMatchGenerator* getInstMatchGenerator( Node n ); + static Node getInversionVariable( Node n ); + static Node getInversion( Node n, Node x ); inline void toStream(std::ostream& out) const { /* diff --git a/src/theory/quantifiers_engine.cpp b/src/theory/quantifiers_engine.cpp index c55ffa2a6..a4d7aaec1 100644 --- a/src/theory/quantifiers_engine.cpp +++ b/src/theory/quantifiers_engine.cpp @@ -30,6 +30,7 @@ #include "theory/quantifiers/bounded_integers.h" #include "theory/quantifiers/rewrite_engine.h" #include "theory/quantifiers/quant_conflict_find.h" +#include "theory/quantifiers/conjecture_generator.h" #include "theory/quantifiers/relevant_domain.h" #include "theory/uf/options.h" #include "theory/uf/theory_uf.h" @@ -83,6 +84,12 @@ d_lemmas_produced_c(u){ }else{ d_qcf = NULL; } + if( options::conjectureGen() ){ + d_sg_gen = new quantifiers::ConjectureGenerator( this, c ); + d_modules.push_back( d_sg_gen ); + }else{ + d_sg_gen = NULL; + } if( !options::finiteModelFind() || options::fmfInstEngine() ){ //the instantiation must set incomplete flag unless finite model finding is turned on d_inst_engine = new quantifiers::InstantiationEngine( this, !options::finiteModelFind() ); @@ -159,56 +166,85 @@ void QuantifiersEngine::finishInit(){ void QuantifiersEngine::check( Theory::Effort e ){ CodeTimer codeTimer(d_time); - bool needsCheck = e>=Theory::EFFORT_LAST_CALL; //always need to check at or above last call - for( int i=0; i<(int)d_modules.size(); i++ ){ - if( d_modules[i]->needsCheck( e ) ){ - needsCheck = true; + bool needsCheck = false; + bool needsBuildModel = false; + std::vector< QuantifiersModule* > qm; + if( d_model->getNumAssertedQuantifiers()>0 ){ + needsCheck = e>=Theory::EFFORT_LAST_CALL; //always need to check at or above last call + for( int i=0; i<(int)d_modules.size(); i++ ){ + if( d_modules[i]->needsCheck( e ) ){ + qm.push_back( d_modules[i] ); + needsCheck = true; + } } } if( needsCheck ){ Trace("quant-engine") << "Quantifiers Engine check, level = " << e << std::endl; + Trace("quant-engine-debug") << " modules to check : "; + for( unsigned i=0; i<qm.size(); i++ ){ + Trace("quant-engine-debug") << qm[i]->identify() << " "; + } + Trace("quant-engine-debug") << std::endl; + Trace("quant-engine-debug") << " # quantified formulas = " << d_model->getNumAssertedQuantifiers() << std::endl; + Trace("quant-engine-debug") << " Theory engine finished : " << !d_te->needCheck() << std::endl; + if( !getMasterEqualityEngine()->consistent() ){ Trace("quant-engine") << "Master equality engine not consistent, return." << std::endl; return; } - Trace("quant-engine-debug") << "Resetting modules..." << std::endl; + Trace("quant-engine-debug") << "Resetting all modules..." << std::endl; //reset relevant information + d_conflict = false; d_hasAddedLemma = false; + + //flush previous lemmas (for instance, if was interupted) + flushLemmas(); + if( d_hasAddedLemma ){ + return; + } + d_term_db->reset( e ); d_eq_query->reset(); if( d_rel_dom ){ d_rel_dom->reset(); } + d_model->reset_round(); for( int i=0; i<(int)d_modules.size(); i++ ){ d_modules[i]->reset_round( e ); } - Trace("quant-engine-debug") << "Done resetting modules." << std::endl; + Trace("quant-engine-debug") << "Done resetting all modules." << std::endl; if( e==Theory::EFFORT_LAST_CALL ){ - //if effort is last call, try to minimize model first - if( options::finiteModelFind() ){ - //first, check if we can minimize the model further - if( !((uf::TheoryUF*)getTheoryEngine()->theoryOf( THEORY_UF ))->getStrongSolver()->minimize() ){ - return; - } + //if effort is last call, try to minimize model first FIXME: remove? + uf::StrongSolverTheoryUF * ufss = ((uf::TheoryUF*)getTheoryEngine()->theoryOf( THEORY_UF ))->getStrongSolver(); + if( ufss && !ufss->minimize() ){ + return; } ++(d_statistics.d_instantiation_rounds_lc); }else if( e==Theory::EFFORT_FULL ){ ++(d_statistics.d_instantiation_rounds); } - Trace("quant-engine-debug") << "Check with modules..." << std::endl; - for( int i=0; i<(int)d_modules.size(); i++ ){ - Trace("quant-engine-debug") << "Check " << d_modules[i]->identify().c_str() << "..." << std::endl; - d_modules[i]->check( e ); + + Trace("quant-engine-debug") << "Check modules that needed check..." << std::endl; + for( unsigned quant_e = QEFFORT_CONFLICT; quant_e<=QEFFORT_MODEL; quant_e++ ){ + for( int i=0; i<(int)qm.size(); i++ ){ + Trace("quant-engine-debug") << "Check " << qm[i]->identify().c_str() << " at effort " << quant_e << "..." << std::endl; + qm[i]->check( e, quant_e ); + } + //flush all current lemmas + flushLemmas(); + //if we have added one, stop + if( d_hasAddedLemma ){ + break; + } } - Trace("quant-engine-debug") << "Done check with modules." << std::endl; + Trace("quant-engine-debug") << "Done check modules that needed check." << std::endl; + //build the model if not done so already // this happens if no quantifiers are currently asserted and no model-building module is enabled if( e==Theory::EFFORT_LAST_CALL && !d_hasAddedLemma ){ if( options::produceModels() && !d_model->isModelSet() ){ - Trace("quant-engine-debug") << "Build the model..." << std::endl; - d_te->getModelBuilder()->buildModel( d_model, true ); - Trace("quant-engine-debug") << "Done building the model." << std::endl; + needsBuildModel = true; } if( Trace.isOn("inst-per-quant") ){ for( std::map< Node, int >::iterator it = d_total_inst_debug.begin(); it != d_total_inst_debug.end(); ++it ){ @@ -224,6 +260,16 @@ void QuantifiersEngine::check( Theory::Effort e ){ } } Trace("quant-engine") << "Finished quantifiers engine check." << std::endl; + }else{ + if( e==Theory::EFFORT_LAST_CALL && options::produceModels() ){ + needsBuildModel = true; + } + } + + if( needsBuildModel ){ + Trace("quant-engine-debug") << "Build the model..." << std::endl; + d_te->getModelBuilder()->buildModel( d_model, true ); + Trace("quant-engine-debug") << "Done building the model." << std::endl; } } @@ -261,7 +307,7 @@ void QuantifiersEngine::registerQuantifier( Node f ){ void QuantifiersEngine::registerPattern( std::vector<Node> & pattern) { for(std::vector<Node>::iterator p = pattern.begin(); p != pattern.end(); ++p){ std::set< Node > added; - getTermDatabase()->addTerm(*p,added); + getTermDatabase()->addTerm( *p, added ); } } @@ -314,6 +360,10 @@ Node QuantifiersEngine::getNextDecisionRequest(){ void QuantifiersEngine::addTermToDatabase( Node n, bool withinQuant ){ std::set< Node > added; getTermDatabase()->addTerm( n, added, withinQuant ); + //maybe have triggered instantiations if we are doing eager instantiation + if( options::eagerInstQuant() ){ + flushLemmas(); + } //added contains also the Node that just have been asserted in this branch if( d_quant_rel ){ for( std::set< Node >::iterator i=added.begin(), end=added.end(); i!=end; i++ ){ @@ -338,6 +388,7 @@ bool QuantifiersEngine::addInstantiation( Node f, std::vector< Node >& vars, std Assert( f.getKind()==FORALL ); Assert( vars.size()==terms.size() ); Node body = getInstantiation( f, vars, terms ); + Trace("inst-assert") << "(assert " << body << ")" << std::endl; //make the lemma NodeBuilder<> nb(kind::OR); nb << f.notNode() << body; @@ -372,7 +423,7 @@ bool QuantifiersEngine::addInstantiation( Node f, std::vector< Node >& vars, std } } } - setInstantiationLevelAttr( body, f[1], maxInstLevel+1, terms ); + setInstantiationLevelAttr( body, f[1], maxInstLevel+1 ); } Trace("inst-debug") << "*** Lemma is " << lem << std::endl; ++(d_statistics.d_instantiations); @@ -383,22 +434,55 @@ bool QuantifiersEngine::addInstantiation( Node f, std::vector< Node >& vars, std } } -void QuantifiersEngine::setInstantiationLevelAttr( Node n, Node qn, uint64_t level, std::vector< Node >& inst_terms ){ +void QuantifiersEngine::setInstantiationLevelAttr( Node n, Node qn, uint64_t level ){ + Trace("inst-level-debug2") << "IL : " << n << " " << qn << " " << level << std::endl; //if not from the vector of terms we instantiatied - if( std::find( inst_terms.begin(), inst_terms.end(), n )==inst_terms.end() ){ + if( qn.getKind()!=BOUND_VARIABLE && n!=qn ){ //if this is a new term, without an instantiation level - if( n!=qn && !n.hasAttribute(InstLevelAttribute()) ){ + if( !n.hasAttribute(InstLevelAttribute()) ){ InstLevelAttribute ila; n.setAttribute(ila,level); + Trace("inst-level-debug") << "Set instantiation level " << n << " to " << level << std::endl; } - Assert( qn.getKind()!=BOUND_VARIABLE ); Assert( n.getNumChildren()==qn.getNumChildren() ); for( int i=0; i<(int)n.getNumChildren(); i++ ){ - setInstantiationLevelAttr( n[i], qn[i], level, inst_terms ); + setInstantiationLevelAttr( n[i], qn[i], level ); } } } +void QuantifiersEngine::setInstantiationLevelAttr( Node n, uint64_t level ){ + if( !n.hasAttribute(InstLevelAttribute()) ){ + InstLevelAttribute ila; + n.setAttribute(ila,level); + Trace("inst-level-debug") << "Set instantiation level " << n << " to " << level << std::endl; + } + for( int i=0; i<(int)n.getNumChildren(); i++ ){ + setInstantiationLevelAttr( n[i], level ); + } +} + +bool QuantifiersEngine::isTermEligibleForInstantiation( Node n, Node f, bool print ) { + if( n.hasAttribute(InstLevelAttribute()) ){ + unsigned ml = options::instMaxLevel(); + if( f.hasAttribute(QuantInstLevelAttribute()) ){ + ml = f.getAttribute(QuantInstLevelAttribute()); + } + if( n.getAttribute(InstLevelAttribute())>ml ){ + Trace("inst-add-debug") << "Term " << n << " has instantiation level " << n.getAttribute(InstLevelAttribute()); + Trace("inst-add-debug") << ", which is more than maximum allowed level " << ml << " for this quantified formula." << std::endl; + return false; + } + }else{ + if( options::instLevelInputOnly() ){ + Trace("inst-add-debug") << "Term " << n << " does not have an instantiation level." << std::endl; + return false; + } + } + return true; +} + + Node QuantifiersEngine::getSubstitute( Node n, std::vector< Node >& terms ){ if( n.getKind()==INST_CONSTANT ){ Debug("check-inst") << "Substitute inst constant : " << n << std::endl; @@ -511,7 +595,14 @@ bool QuantifiersEngine::addLemma( Node lem, bool doCache ){ } } +void QuantifiersEngine::addRequirePhase( Node lit, bool req ){ + d_phase_req_waiting[lit] = req; +} + bool QuantifiersEngine::addInstantiation( Node f, InstMatch& m, bool mkRep, bool modEq, bool modInst ){ + // For resource-limiting (also does a time check). + getOutputChannel().spendResource(); + std::vector< Node > terms; //make sure there are values for each variable we are instantiating for( size_t i=0; i<f[0].getNumChildren(); i++ ){ @@ -536,24 +627,32 @@ bool QuantifiersEngine::addInstantiation( Node f, std::vector< Node >& terms, bo if( mkRep ){ //pick the best possible representative for instantiation, based on past use and simplicity of term terms[i] = d_eq_query->getInternalRepresentative( terms[i], f, i ); - //Trace("inst-add-debug") << " (" << terms[i] << ")"; + Trace("inst-add-debug2") << " (" << terms[i] << ")"; } } Trace("inst-add-debug") << std::endl; + //check based on instantiation level if( options::instMaxLevel()!=-1 ){ for( unsigned i=0; i<terms.size(); i++ ){ - if( terms[i].hasAttribute(InstLevelAttribute()) && - (int)terms[i].getAttribute(InstLevelAttribute())>options::instMaxLevel() ){ - Trace("inst-add-debug") << "Term " << terms[i] << " has instantiation level " << terms[i].getAttribute(InstLevelAttribute()); - Trace("inst-add-debug") << ", which is more than maximum allowed level " << options::instMaxLevel() << std::endl; + if( !isTermEligibleForInstantiation( terms[i], f, true ) ){ return false; } } } + //check for entailment + if( options::instNoEntail() ){ + std::map< TNode, TNode > subs; + for( unsigned i=0; i<terms.size(); i++ ){ + subs[f[0][i]] = terms[i]; + } + if( d_term_db->isEntailed( f[1], subs, false, true ) ){ + Trace("inst-add-debug") << " -> Currently entailed." << std::endl; + return false; + } + } //check for duplication - ///* bool alreadyExists = false; if( options::incrementalSolving() ){ Trace("inst-add-debug") << "Adding into context-dependent inst trie, modEq = " << modEq << ", modInst = " << modInst << std::endl; @@ -575,9 +674,10 @@ bool QuantifiersEngine::addInstantiation( Node f, std::vector< Node >& terms, bo ++(d_statistics.d_inst_duplicate_eq); return false; } - //*/ + //add the instantiation + Trace("inst-add-debug") << "Constructing instantiation..." << std::endl; bool addedInst = addInstantiation( f, d_term_db->d_vars[f], terms ); //report the result if( addedInst ){ @@ -608,18 +708,21 @@ bool QuantifiersEngine::addSplitEquality( Node n1, Node n2, bool reqPhase, bool return addSplit( fm ); } -void QuantifiersEngine::flushLemmas( OutputChannel* out ){ +void QuantifiersEngine::flushLemmas(){ if( !d_lemmas_waiting.empty() ){ - if( !out ){ - out = &getOutputChannel(); - } //take default output channel if none is provided d_hasAddedLemma = true; for( int i=0; i<(int)d_lemmas_waiting.size(); i++ ){ - out->lemma( d_lemmas_waiting[i], false, true ); + getOutputChannel().lemma( d_lemmas_waiting[i], false, true ); } d_lemmas_waiting.clear(); } + if( !d_phase_req_waiting.empty() ){ + for( std::map< Node, bool >::iterator it = d_phase_req_waiting.begin(); it != d_phase_req_waiting.end(); ++it ){ + getOutputChannel().requirePhase( it->first, it->second ); + } + d_phase_req_waiting.clear(); + } } void QuantifiersEngine::getPhaseReqTerms( Node f, std::vector< Node >& nodes ){ @@ -793,7 +896,6 @@ Node EqualityQueryQuantifiersEngine::getInternalRepresentative( Node a, Node f, //if cbqi is active, do not choose instantiation constant terms if( !options::cbqi() || !quantifiers::TermDb::hasInstConstAttr(eqc[i]) ){ int score = getRepScore( eqc[i], f, index ); - //score prefers earliest use of this term as a representative if( r_best.isNull() || ( score>=0 && ( r_best_score<0 || score<r_best_score ) ) ){ r_best = eqc[i]; r_best_score = score; @@ -945,8 +1047,21 @@ int getDepth( Node n ){ } } +//smaller the score, the better int EqualityQueryQuantifiersEngine::getRepScore( Node n, Node f, int index ){ - return d_rep_score.find( n )==d_rep_score.end() ? -1 : d_rep_score[n]; //initial + int s; + if( options::instMaxLevel()!=-1 ){ + //score prefer lowest instantiation level + if( n.hasAttribute(InstLevelAttribute()) ){ + s = n.getAttribute(InstLevelAttribute()); + }else{ + s = options::instLevelInputOnly() ? -1 : 0; + } + }else{ + //score prefers earliest use of this term as a representative + s = d_rep_score.find( n )==d_rep_score.end() ? -1 : d_rep_score[n]; + } + return s; //return ( d_rep_score.find( n )==d_rep_score.end() ? 100 : 0 ) + getDepth( n ); //term depth } diff --git a/src/theory/quantifiers_engine.h b/src/theory/quantifiers_engine.h index 7786e0b70..e914280c5 100644 --- a/src/theory/quantifiers_engine.h +++ b/src/theory/quantifiers_engine.h @@ -52,7 +52,7 @@ public: /* reset at a round */ virtual void reset_round( Theory::Effort e ){} /* Call during quantifier engine's check */ - virtual void check( Theory::Effort e ) = 0; + virtual void check( Theory::Effort e, unsigned quant_e ) = 0; /* Called for new quantifiers */ virtual void registerQuantifier( Node q ) = 0; virtual void assertNode( Node n ) = 0; @@ -73,6 +73,7 @@ namespace quantifiers { class QuantConflictFind; class RewriteEngine; class RelevantDomain; + class ConjectureGenerator; }/* CVC4::theory::quantifiers */ namespace inst { @@ -112,6 +113,14 @@ private: quantifiers::QuantConflictFind* d_qcf; /** rewrite rules utility */ quantifiers::RewriteEngine * d_rr_engine; + /** subgoal generator */ + quantifiers::ConjectureGenerator * d_sg_gen; +public: //effort levels + enum { + QEFFORT_CONFLICT, + QEFFORT_STANDARD, + QEFFORT_MODEL, + }; private: /** list of all quantifiers seen */ std::vector< Node > d_quants; @@ -120,8 +129,12 @@ private: BoolMap d_lemmas_produced_c; /** lemmas waiting */ std::vector< Node > d_lemmas_waiting; + /** phase requirements waiting */ + std::map< Node, bool > d_phase_req_waiting; /** has added lemma this round */ bool d_hasAddedLemma; + /** has a conflict been found */ + bool d_conflict; /** list of all instantiations produced for each quantifier */ std::map< Node, inst::InstMatchTrie > d_inst_match_trie; std::map< Node, inst::CDInstMatchTrie* > d_c_inst_match_trie; @@ -192,7 +205,9 @@ private: /** instantiate f with arguments terms */ bool addInstantiation( Node f, std::vector< Node >& vars, std::vector< Node >& terms ); /** set instantiation level attr */ - void setInstantiationLevelAttr( Node n, Node qn, uint64_t level, std::vector< Node >& inst_terms ); + static void setInstantiationLevelAttr( Node n, Node qn, uint64_t level ); + /** flush lemmas */ + void flushLemmas(); public: /** get instantiation */ Node getInstantiation( Node f, std::vector< Node >& vars, std::vector< Node >& terms ); @@ -206,6 +221,8 @@ public: bool existsInstantiation( Node f, InstMatch& m, bool modEq = true, bool modInst = false ); /** add lemma lem */ bool addLemma( Node lem, bool doCache = true ); + /** add require phase */ + void addRequirePhase( Node lit, bool req ); /** do instantiation specified by m */ bool addInstantiation( Node f, InstMatch& m, bool mkRep = true, bool modEq = false, bool modInst = false ); /** add instantiation */ @@ -216,10 +233,12 @@ public: bool addSplitEquality( Node n1, Node n2, bool reqPhase = false, bool reqPhasePol = true ); /** has added lemma */ bool hasAddedLemma() { return !d_lemmas_waiting.empty() || d_hasAddedLemma; } - /** flush lemmas */ - void flushLemmas( OutputChannel* out = NULL ); /** get number of waiting lemmas */ int getNumLemmasWaiting() { return (int)d_lemmas_waiting.size(); } + /** set instantiation level attr */ + static void setInstantiationLevelAttr( Node n, uint64_t level ); + /** is term eligble for instantiation? */ + bool isTermEligibleForInstantiation( Node n, Node f, bool print = false ); public: /** get number of quantifiers */ int getNumQuantifiers() { return (int)d_quants.size(); } diff --git a/src/theory/rep_set.cpp b/src/theory/rep_set.cpp index 954272549..ee14d6fc1 100644 --- a/src/theory/rep_set.cpp +++ b/src/theory/rep_set.cpp @@ -38,8 +38,9 @@ int RepSet::getNumRepresentatives( TypeNode tn ) const{ } void RepSet::add( TypeNode tn, Node n ){ - d_tmap[ n ] = (int)d_type_reps[tn].size(); Trace("rsi-debug") << "Add rep #" << d_type_reps[tn].size() << " for " << tn << " : " << n << std::endl; + Assert( n.getType().isSubtypeOf( tn ) ); + d_tmap[ n ] = (int)d_type_reps[tn].size(); d_type_reps[tn].push_back( n ); } diff --git a/src/theory/sets/options b/src/theory/sets/options index 1c95e78e4..7cb3eb677 100644 --- a/src/theory/sets/options +++ b/src/theory/sets/options @@ -11,4 +11,7 @@ option setsPropagate --sets-propagate bool :default true option setsEagerLemmas --sets-eager-lemmas bool :default true add lemmas even at regular effort +option setsCare1 --sets-care1 bool :default false + generate one lemma at a time for care graph + endmodule diff --git a/src/theory/sets/theory_sets.cpp b/src/theory/sets/theory_sets.cpp index b59beac8d..106ad6e56 100644 --- a/src/theory/sets/theory_sets.cpp +++ b/src/theory/sets/theory_sets.cpp @@ -39,6 +39,9 @@ void TheorySets::addSharedTerm(TNode n) { } void TheorySets::check(Effort e) { + if (done() && !fullEffort(e)) { + return; + } d_internal->check(e); } @@ -54,6 +57,14 @@ Node TheorySets::explain(TNode node) { return d_internal->explain(node); } +EqualityStatus TheorySets::getEqualityStatus(TNode a, TNode b) { + return d_internal->getEqualityStatus(a, b); +} + +Node TheorySets::getModelValue(TNode node) { + return d_internal->getModelValue(node); +} + void TheorySets::preRegisterTerm(TNode node) { d_internal->preRegisterTerm(node); } diff --git a/src/theory/sets/theory_sets.h b/src/theory/sets/theory_sets.h index a16832389..6136fc8f8 100644 --- a/src/theory/sets/theory_sets.h +++ b/src/theory/sets/theory_sets.h @@ -58,6 +58,10 @@ public: Node explain(TNode); + EqualityStatus getEqualityStatus(TNode a, TNode b); + + Node getModelValue(TNode); + std::string identify() const { return "THEORY_SETS"; } void preRegisterTerm(TNode node); diff --git a/src/theory/sets/theory_sets_private.cpp b/src/theory/sets/theory_sets_private.cpp index 2035c18b0..4125fd193 100644 --- a/src/theory/sets/theory_sets_private.cpp +++ b/src/theory/sets/theory_sets_private.cpp @@ -417,32 +417,176 @@ void TheorySetsPrivate::addSharedTerm(TNode n) { d_equalityEngine.addTriggerTerm(n, THEORY_SETS); } +void TheorySetsPrivate::dumpAssertionsHumanified() const +{ + std::string tag = "sets-assertions"; + context::CDList<Assertion>::const_iterator it = d_external.facts_begin(), it_end = d_external.facts_end(); + + std::map<TNode, std::set<TNode> > equalities; + std::set< pair<TNode, TNode> > disequalities; + std::map<TNode, std::pair<std::set<TNode>, std::set<TNode> > > members; + static std::map<TNode, int> numbering; + static int number = 0; + + for (unsigned i = 0; it != it_end; ++ it, ++i) { + TNode ass = (*it).assertion; + // Trace("sets-care-dump") << AssertCommand(ass.toExpr()) << endl; + bool polarity = ass.getKind() != kind::NOT; + ass = polarity ? ass : ass[0]; + Assert( ass.getNumChildren() == 2); + TNode left = d_equalityEngine.getRepresentative(ass[0]); + TNode right = d_equalityEngine.getRepresentative(ass[1]); + if(numbering[left] == 0) numbering[left] = ++number; + if(numbering[right] == 0) numbering[right] = ++number; + equalities[left].insert(ass[0]); + equalities[right].insert(ass[1]); + if(ass.getKind() == kind::EQUAL) { + if(polarity) { + Assert(left == right); + } else { + if(left > right) std::swap(left, right); + disequalities.insert(make_pair(left, right)); + } + } else if(ass.getKind() == kind::MEMBER) { + (polarity ? members[right].first : members[right].second).insert(left); + } + } +#define FORIT(it, container) for(typeof((container).begin()) it=(container).begin(); (it) != (container).end(); ++(it)) + FORIT(kt, equalities) { + Trace(tag) << " Eq class of t" << numbering[(*kt).first] << ": " << std::endl; + FORIT(jt, (*kt).second) { + TNode S = (*jt); + if( S.getKind() != kind::UNION && S.getKind() != kind::INTERSECTION && S.getKind() != kind::SETMINUS) { + Trace(tag) << " " << *jt << ((*jt).getType().isSet() ? "\n": " "); + } else { + Trace(tag) << " "; + if(S[0].isConst() || numbering.find(d_equalityEngine.getRepresentative(S[0])) == numbering.end()) { + Trace(tag) << S[0]; + } else { + Trace(tag) << "t" << numbering[d_equalityEngine.getRepresentative(S[0])]; + } + Trace(tag) << " " << (S.getKind() == kind::UNION ? "|" : (S.getKind() == kind::INTERSECTION ? "&" : "-")) << " "; + if(S[1].isConst() || numbering.find(d_equalityEngine.getRepresentative(S[1])) == numbering.end()) { + Trace(tag) << S[1]; + } else { + Trace(tag) << "t" << numbering[d_equalityEngine.getRepresentative(S[1])]; + } + Trace(tag) << std::endl; + } + } + Trace(tag) << std::endl; + } + FORIT(kt, disequalities) Trace(tag) << "NOT(t"<<numbering[(*kt).first]<<" = t" <<numbering[(*kt).second] <<")"<< std::endl; + FORIT(kt, members) { + if( (*kt).second.first.size() > 0) { + Trace(tag) << "IN t" << numbering[(*kt).first] << ": "; + FORIT(jt, (*kt).second.first) { + TNode x = (*jt); + if(x.isConst() || numbering.find(d_equalityEngine.getRepresentative(x)) == numbering.end()) { + Trace(tag) << x; + } else { + Trace(tag) << "x" << numbering[d_equalityEngine.getRepresentative(x)] << ", "; + } + } + Trace(tag) << std::endl; + } + if( (*kt).second.second.size() > 0) { + Trace(tag) << "NOT IN t" << numbering[(*kt).first] << ": "; + FORIT(jt, (*kt).second.second) { + TNode x = (*jt); + if(x.isConst() || numbering.find(d_equalityEngine.getRepresentative(x)) == numbering.end()) { + Trace(tag) << x; + } else { + Trace(tag) << "x" << numbering[d_equalityEngine.getRepresentative(x)] << ", "; + } + } + Trace(tag) << std::endl; + } + } + Trace(tag) << std::endl; +#undef FORIT +} void TheorySetsPrivate::computeCareGraph() { Debug("sharing") << "Theory::computeCareGraph<" << d_external.identify() << ">()" << endl; - for (unsigned i = 0; i < d_external.d_sharedTerms.size(); ++ i) { + + if(Trace.isOn("sets-assertions")) { + // dump our understanding of assertions + dumpAssertionsHumanified(); + } + + unsigned i_st = 0; + if(options::setsCare1()) { i_st = d_ccg_i; } + for (unsigned i = i_st; i < d_external.d_sharedTerms.size(); ++ i) { TNode a = d_external.d_sharedTerms[i]; TypeNode aType = a.getType(); - for (unsigned j = i + 1; j < d_external.d_sharedTerms.size(); ++ j) { + + unsigned j_st = i + 1; + if(options::setsCare1()) { if(i == d_ccg_i) j_st = d_ccg_j + 1; } + + for (unsigned j = j_st; j < d_external.d_sharedTerms.size(); ++ j) { TNode b = d_external.d_sharedTerms[j]; if (b.getType() != aType) { // We don't care about the terms of different types continue; } + switch (d_external.d_valuation.getEqualityStatus(a, b)) { case EQUALITY_TRUE_AND_PROPAGATED: + // If we know about it, we should have propagated it, so we can skip + Trace("sets-care") << "[sets-care] Know: " << EQUAL(a, b) << std::endl; + break; case EQUALITY_FALSE_AND_PROPAGATED: // If we know about it, we should have propagated it, so we can skip + Trace("sets-care") << "[sets-care] Know: " << NOT(EQUAL(a, b)) << std::endl; break; - default: + case EQUALITY_FALSE: + case EQUALITY_TRUE: + Assert(false, "ERROR: Equality status true/false but not propagated (sets care graph computation)."); + break; + case EQUALITY_TRUE_IN_MODEL: + d_external.addCarePair(a, b); + case EQUALITY_FALSE_IN_MODEL: + if(Trace.isOn("sets-care-performance-test")) { + // TODO: delete these lines, only for performance testing for now + d_external.addCarePair(a, b); + } + break; + case EQUALITY_UNKNOWN: // Let's split on it d_external.addCarePair(a, b); + if(options::setsCare1()) { + d_ccg_i = i; + d_ccg_j = j; + return; + } break; + default: + Unreachable(); } } } } +EqualityStatus TheorySetsPrivate::getEqualityStatus(TNode a, TNode b) { + Assert(d_equalityEngine.hasTerm(a) && d_equalityEngine.hasTerm(b)); + if (d_equalityEngine.areEqual(a, b)) { + // The terms are implied to be equal + return EQUALITY_TRUE; + } + if (d_equalityEngine.areDisequal(a, b, false)) { + // The terms are implied to be dis-equal + return EQUALITY_FALSE; + } + if( d_external.d_valuation.getModelValue(a) == d_external.d_valuation.getModelValue(b) ) { + // Ther term are true in current model + return EQUALITY_TRUE_IN_MODEL; + } + return EQUALITY_FALSE_IN_MODEL; + // } + // //TODO: can we be more precise sometimes? + // return EQUALITY_UNKNOWN; +} /******************** Model generation ********************/ /******************** Model generation ********************/ @@ -583,6 +727,21 @@ Node TheorySetsPrivate::elementsToShape(Elements elements, TypeNode setType) con return cur; } } +Node TheorySetsPrivate::elementsToShape(set<Node> elements, TypeNode setType) const +{ + NodeManager* nm = NodeManager::currentNM(); + + if(elements.size() == 0) { + return nm->mkConst(EmptySet(nm->toType(setType))); + } else { + typeof(elements.begin()) it = elements.begin(); + Node cur = SINGLETON(*it); + while( ++it != elements.end() ) { + cur = nm->mkNode(kind::UNION, cur, SINGLETON(*it)); + } + return cur; + } +} void TheorySetsPrivate::collectModelInfo(TheoryModel* m, bool fullModel) { @@ -689,6 +848,11 @@ void TheorySetsPrivate::collectModelInfo(TheoryModel* m, bool fullModel) #endif } +Node TheorySetsPrivate::getModelValue(TNode n) +{ + CodeTimer codeTimer(d_statistics.d_getModelValueTime); + return d_termInfoManager->getModelValue(n); +} /********************** Helper functions ***************************/ /********************** Helper functions ***************************/ @@ -735,14 +899,17 @@ Node mkAnd(const std::vector<TNode>& conjunctions) { TheorySetsPrivate::Statistics::Statistics() : - d_checkTime("theory::sets::time") { - + d_checkTime("theory::sets::time") + , d_getModelValueTime("theory::sets::getModelValueTime") +{ StatisticsRegistry::registerStat(&d_checkTime); + StatisticsRegistry::registerStat(&d_getModelValueTime); } TheorySetsPrivate::Statistics::~Statistics() { StatisticsRegistry::unregisterStat(&d_checkTime); + StatisticsRegistry::unregisterStat(&d_getModelValueTime); } @@ -881,6 +1048,9 @@ TheorySetsPrivate::TheorySetsPrivate(TheorySets& external, d_pending(c), d_pendingDisequal(c), d_pendingEverInserted(u), + d_modelCache(c), + d_ccg_i(c), + d_ccg_j(c), d_scrutinize(NULL) { d_termInfoManager = new TermInfoManager(*this, c, &d_equalityEngine); @@ -1111,6 +1281,8 @@ void TheorySetsPrivate::TermInfoManager::notifyMembership(TNode fact) { d_info[S]->addToElementList(x, polarity); d_info[x]->addToSetList(S, polarity); + + d_theory.d_modelCache.clear(); } const CDTNodeList* TheorySetsPrivate::TermInfoManager::getParents(TNode x) { @@ -1264,8 +1436,38 @@ void TheorySetsPrivate::TermInfoManager::mergeTerms(TNode a, TNode b) { (*itb).second->setsContainingThisElement ); mergeLists( (*ita).second->setsNotContainingThisElement, (*itb).second->setsNotContainingThisElement ); + + d_theory.d_modelCache.clear(); } +Node TheorySetsPrivate::TermInfoManager::getModelValue(TNode n) +{ + if(d_terms.find(n) == d_terms.end()) { + return Node(); + } + Assert(n.getType().isSet()); + set<Node> elements, elements_const; + Node S = d_eqEngine->getRepresentative(n); + typeof(d_theory.d_modelCache.begin()) it = d_theory.d_modelCache.find(S); + if(it != d_theory.d_modelCache.end()) { + return (*it).second; + } + const CDTNodeList* l = getMembers(S); + for(typeof(l->begin()) it = l->begin(); it != l->end(); ++it) { + TNode n = *it; + elements.insert(d_eqEngine->getRepresentative(n)); + } + BOOST_FOREACH(TNode e, elements) { + if(e.isConst()) { + elements_const.insert(e); + } else { + elements_const.insert(d_theory.d_external.d_valuation.getModelValue(e)); + } + } + Node v = d_theory.elementsToShape(elements_const, n.getType()); + d_theory.d_modelCache[n] = v; + return v; +} }/* CVC4::theory::sets namespace */ }/* CVC4::theory namespace */ diff --git a/src/theory/sets/theory_sets_private.h b/src/theory/sets/theory_sets_private.h index 78a415529..72c041d49 100644 --- a/src/theory/sets/theory_sets_private.h +++ b/src/theory/sets/theory_sets_private.h @@ -60,6 +60,10 @@ public: Node explain(TNode); + EqualityStatus getEqualityStatus(TNode a, TNode b); + + Node getModelValue(TNode); + void preRegisterTerm(TNode node); void propagate(Theory::Effort) { /* we don't depend on this call */ } @@ -70,6 +74,7 @@ private: class Statistics { public: TimerStat d_checkTime; + TimerStat d_getModelValueTime; Statistics(); ~Statistics(); @@ -123,6 +128,7 @@ private: void notifyMembership(TNode fact); const CDTNodeList* getParents(TNode x); const CDTNodeList* getMembers(TNode S); + Node getModelValue(TNode n); const CDTNodeList* getNonMembers(TNode S); void addTerm(TNode n); void mergeTerms(TNode a, TNode b); @@ -174,11 +180,19 @@ private: typedef std::hash_map<TNode, Elements, TNodeHashFunction> SettermElementsMap; const Elements& getElements(TNode setterm, SettermElementsMap& settermElementsMap) const; Node elementsToShape(Elements elements, TypeNode setType) const; + Node elementsToShape(std::set<Node> elements, TypeNode setType) const; bool checkModel(const SettermElementsMap& settermElementsMap, TNode S) const; + context::CDHashMap <Node, Node, NodeHashFunction> d_modelCache; + + + // sharing related + context::CDO<unsigned> d_ccg_i, d_ccg_j; + // more debugging stuff friend class TheorySetsScrutinize; TheorySetsScrutinize* d_scrutinize; + void dumpAssertionsHumanified() const; /** do some formatting to make them more readable */ };/* class TheorySetsPrivate */ diff --git a/src/theory/sets/theory_sets_type_rules.h b/src/theory/sets/theory_sets_type_rules.h index eb270202a..6754bbb9e 100644 --- a/src/theory/sets/theory_sets_type_rules.h +++ b/src/theory/sets/theory_sets_type_rules.h @@ -100,7 +100,7 @@ struct MemberTypeRule { } TypeNode elementType = n[0].getType(check); if(elementType != setType.getSetElementType()) { - throw TypeCheckingExceptionPrivate(n, "set in operating on sets of different types"); + throw TypeCheckingExceptionPrivate(n, "member operating on sets of different types"); } } return nodeManager->booleanType(); diff --git a/src/theory/strings/kinds b/src/theory/strings/kinds index 4266c02f5..0f68d1207 100644 --- a/src/theory/strings/kinds +++ b/src/theory/strings/kinds @@ -88,6 +88,11 @@ operator REGEXP_LOOP 2:3 "regexp loop" operator REGEXP_EMPTY 0 "regexp empty" operator REGEXP_SIGMA 0 "regexp all characters" +#internal +operator REGEXP_RV 1 "regexp rv (internal use only)" +typerule REGEXP_RV ::CVC4::theory::strings::RegExpRVTypeRule + +#typerules typerule REGEXP_CONCAT ::CVC4::theory::strings::RegExpConcatTypeRule typerule REGEXP_UNION ::CVC4::theory::strings::RegExpUnionTypeRule typerule REGEXP_INTER ::CVC4::theory::strings::RegExpInterTypeRule diff --git a/src/theory/strings/regexp_operation.cpp b/src/theory/strings/regexp_operation.cpp index 369278994..e769eb712 100644 --- a/src/theory/strings/regexp_operation.cpp +++ b/src/theory/strings/regexp_operation.cpp @@ -1183,8 +1183,19 @@ void RegExpOpr::getCharSet( Node r, std::set<unsigned> &pcset, SetNodes &pvset ) } } +bool RegExpOpr::isPairNodesInSet(std::set< PairNodes > &s, Node n1, Node n2) { + for(std::set< PairNodes >::const_iterator itr = s.begin(); + itr != s.end(); ++itr) { + if(itr->first == n1 && itr->second == n2 || + itr->first == n2 && itr->second == n1) { + return true; + } + } + return false; +} Node RegExpOpr::intersectInternal( Node r1, Node r2, std::map< unsigned, std::set< PairNodes > > cache, bool &spflag ) { + Trace("regexp-intersect") << "Starting INTERSECT:\n "<< mkString(r1) << ",\n " << mkString(r2) << std::endl; if(spflag) { //TODO: var return Node::null(); @@ -1230,11 +1241,18 @@ Node RegExpOpr::intersectInternal( Node r1, Node r2, std::map< unsigned, std::se spflag = true; } } + if(Trace.isOn("regexp-debug")) { + Trace("regexp-debug") << "Try CSET( " << cset.size() << " ) = "; + for(std::set<unsigned>::const_iterator itr = cset.begin(); + itr != cset.end(); itr++) { + Trace("regexp-debug") << *itr << ", "; + } + Trace("regexp-debug") << std::endl; + } for(std::set<unsigned>::const_iterator itr = cset.begin(); itr != cset.end(); itr++) { CVC4::String c( CVC4::String::convertUnsignedIntToChar(*itr) ); - std::pair< Node, Node > p(r1, r2); - if(cache[ *itr ].find(p) == cache[ *itr ].end()) { + if(!isPairNodesInSet(cache[ *itr ], r1, r2)) { Node r1l = derivativeSingle(r1, c); Node r2l = derivativeSingle(r2, c); std::map< unsigned, std::set< PairNodes > > cache2(cache); @@ -1263,10 +1281,208 @@ Node RegExpOpr::intersectInternal( Node r1, Node r2, std::map< unsigned, std::se Trace("regexp-intersect") << "INTERSECT( " << mkString(r1) << ", " << mkString(r2) << " ) = " << mkString(rNode) << std::endl; return rNode; } + +bool RegExpOpr::containC2(unsigned cnt, Node n) { + if(n.getKind() == kind::REGEXP_RV) { + unsigned y = n[0].getConst<Rational>().getNumerator().toUnsignedInt(); + return cnt == y; + } else if(n.getKind() == kind::REGEXP_CONCAT) { + for( unsigned i=0; i<n.getNumChildren(); i++ ) { + if(containC2(cnt, n[i])) { + return true; + } + } + } else if(n.getKind() == kind::REGEXP_STAR) { + return containC2(cnt, n[0]); + } else if(n.getKind() == kind::REGEXP_UNION) { + for( unsigned i=0; i<n.getNumChildren(); i++ ) { + if(containC2(cnt, n[i])) { + return true; + } + } + } + return false; +} +Node RegExpOpr::convert1(unsigned cnt, Node n) { + Trace("regexp-debug") << "Converting " << n << " at " << cnt << "... " << std::endl; + Node r1, r2; + convert2(cnt, n, r1, r2); + Trace("regexp-debug") << "... getting r1=" << r1 << ", and r2=" << r2 << std::endl; + Node ret = NodeManager::currentNM()->mkNode(kind::REGEXP_CONCAT, + NodeManager::currentNM()->mkNode(kind::REGEXP_STAR, r1), r2); + ret = Rewriter::rewrite( ret ); + Trace("regexp-debug") << "... done convert at " << cnt << ", with return " << ret << std::endl; + return ret; +} +void RegExpOpr::convert2(unsigned cnt, Node n, Node &r1, Node &r2) { + if(n == d_emptyRegexp) { + r1 = d_emptyRegexp; + r2 = d_emptyRegexp; + } else if(n == d_emptySingleton) { + r1 = d_emptySingleton; + r2 = d_emptySingleton; + } else if(n.getKind() == kind::REGEXP_RV) { + unsigned y = n[0].getConst<Rational>().getNumerator().toUnsignedInt(); + r1 = d_emptySingleton; + if(cnt == y) { + r2 = d_emptyRegexp; + } else { + r2 = n; + } + } else if(n.getKind() == kind::REGEXP_CONCAT) { + //TODO + //convert2 x (r@(Seq l r1)) + // | contains x r1 = let (r2,r3) = convert2 x r1 + // in (Seq l r2, r3) + // | otherwise = (Empty, r) + bool flag = true; + std::vector<Node> vr1, vr2; + for( unsigned i=0; i<n.getNumChildren(); i++ ) { + if(containC2(cnt, n[i])) { + Node t1, t2; + convert2(cnt, n[i], t1, t2); + vr1.push_back(t1); + r1 = vr1.size()==0 ? d_emptyRegexp : vr1.size()==1 ? vr1[0] : + NodeManager::currentNM()->mkNode(kind::REGEXP_CONCAT, vr1); + vr2.push_back(t2); + for( unsigned j=i+1; j<n.getNumChildren(); j++ ) { + vr2.push_back(n[j]); + } + r2 = vr2.size()==0 ? d_emptyRegexp : vr2.size()==1 ? vr2[0] : + NodeManager::currentNM()->mkNode(kind::REGEXP_CONCAT, vr2); + flag = false; + break; + } else { + vr1.push_back(n[i]); + } + } + if(flag) { + r1 = d_emptySingleton; + r2 = n; + } + } else if(n.getKind() == kind::REGEXP_UNION) { + std::vector<Node> vr1, vr2; + for( unsigned i=0; i<n.getNumChildren(); i++ ) { + Node t1, t2; + convert2(cnt, n[i], t1, t2); + vr1.push_back(t1); + vr2.push_back(t2); + } + r1 = NodeManager::currentNM()->mkNode(kind::REGEXP_UNION, vr1); + r2 = NodeManager::currentNM()->mkNode(kind::REGEXP_UNION, vr2); + } else if(n.getKind() == kind::STRING_TO_REGEXP) { + r1 = d_emptySingleton; + r2 = n; + } else { + //is it possible? + } +} +Node RegExpOpr::intersectInternal2( Node r1, Node r2, std::map< PairNodes, Node > cache, bool &spflag, unsigned cnt ) { + Trace("regexp-intersect") << "Starting INTERSECT:\n "<< mkString(r1) << ",\n " << mkString(r2) << std::endl; + //if(Trace.isOn("regexp-debug")) { + // Trace("regexp-debug") << "... with cache:\n"; + // for(std::map< PairNodes, Node >::const_iterator itr=cache.begin(); + // itr!=cache.end();itr++) { + // Trace("regexp-debug") << "(" << itr->first.first << "," << itr->first.second << ")->" << itr->second << std::endl; + // } + //} + if(spflag) { + //TODO: var + return Node::null(); + } + std::pair < Node, Node > p(r1, r2); + std::map < std::pair< Node, Node >, Node >::const_iterator itr = d_inter_cache.find(p); + Node rNode; + if(itr != d_inter_cache.end()) { + rNode = itr->second; + } else { + if(r1 == d_emptyRegexp || r2 == d_emptyRegexp) { + rNode = d_emptyRegexp; + } else if(r1 == d_emptySingleton || r2 == d_emptySingleton) { + Node exp; + int r = delta((r1 == d_emptySingleton ? r2 : r1), exp); + if(r == 0) { + //TODO: variable + spflag = true; + } else if(r == 1) { + rNode = d_emptySingleton; + } else { + rNode = d_emptyRegexp; + } + } else if(r1 == r2) { + rNode = convert1(cnt, r1); + } else { + PairNodes p(r1, r2); + std::map< PairNodes, Node >::const_iterator itrcache = cache.find(p); + if(itrcache != cache.end()) { + rNode = itrcache->second; + } else { + if(checkConstRegExp(r1) && checkConstRegExp(r2)) { + std::vector< unsigned > cset; + std::set< unsigned > cset1, cset2; + std::set< Node > vset1, vset2; + firstChars(r1, cset1, vset1); + firstChars(r2, cset2, vset2); + std::set_intersection(cset1.begin(), cset1.end(), cset2.begin(), cset1.end(), + std::inserter(cset, cset.begin())); + std::vector< Node > vec_nodes; + Node delta_exp; + int flag = delta(r1, delta_exp); + int flag2 = delta(r2, delta_exp); + if(flag != 2 && flag2 != 2) { + if(flag == 1 && flag2 == 1) { + vec_nodes.push_back(d_emptySingleton); + } else { + //TODO + spflag = true; + } + } + if(Trace.isOn("regexp-debug")) { + Trace("regexp-debug") << "Try CSET( " << cset.size() << " ) = "; + for(std::vector<unsigned>::const_iterator itr = cset.begin(); + itr != cset.end(); itr++) { + CVC4::String c( CVC4::String::convertUnsignedIntToChar(*itr) ); + Trace("regexp-debug") << c << ", "; + } + Trace("regexp-debug") << std::endl; + } + for(std::vector<unsigned>::const_iterator itr = cset.begin(); + itr != cset.end(); itr++) { + CVC4::String c( CVC4::String::convertUnsignedIntToChar(*itr) ); + Node r1l = derivativeSingle(r1, c); + Node r2l = derivativeSingle(r2, c); + std::map< PairNodes, Node > cache2(cache); + PairNodes p(r1, r2); + cache2[ p ] = NodeManager::currentNM()->mkNode(kind::REGEXP_RV, NodeManager::currentNM()->mkConst(CVC4::Rational(cnt))); + Node rt = intersectInternal2(r1l, r2l, cache2, spflag, cnt+1); + rt = convert1(cnt, rt); + if(spflag) { + //TODO: + return Node::null(); + } + rt = Rewriter::rewrite( NodeManager::currentNM()->mkNode(kind::REGEXP_CONCAT, + NodeManager::currentNM()->mkNode(kind::STRING_TO_REGEXP, NodeManager::currentNM()->mkConst(c)), rt) ); + vec_nodes.push_back(rt); + } + rNode = vec_nodes.size()==0 ? d_emptyRegexp : vec_nodes.size()==1 ? vec_nodes[0] : + NodeManager::currentNM()->mkNode(kind::REGEXP_UNION, vec_nodes); + rNode = Rewriter::rewrite( rNode ); + } else { + //TODO: non-empty var set + spflag = true; + } + } + } + d_inter_cache[p] = rNode; + } + Trace("regexp-intersect") << "End of INTERSECT( " << mkString(r1) << ", " << mkString(r2) << " ) = " << mkString(rNode) << std::endl; + return rNode; +} Node RegExpOpr::intersect(Node r1, Node r2, bool &spflag) { - std::map< unsigned, std::set< PairNodes > > cache; + //std::map< unsigned, std::set< PairNodes > > cache; + std::map< PairNodes, Node > cache; if(checkConstRegExp(r1) && checkConstRegExp(r2)) { - return intersectInternal(r1, r2, cache, spflag); + return intersectInternal2(r1, r2, cache, spflag, 1); } else { spflag = true; return Node::null(); @@ -1516,6 +1732,12 @@ std::string RegExpOpr::mkString( Node r ) { retStr += "]"; break; } + case kind::REGEXP_RV: { + retStr += "<"; + retStr += r[0].getConst<Rational>().getNumerator().toString(); + retStr += ">"; + break; + } default: Trace("strings-error") << "Unsupported term: " << r << " in RegExp." << std::endl; //Assert( false ); diff --git a/src/theory/strings/regexp_operation.h b/src/theory/strings/regexp_operation.h index e4ae1208d..2ae578cd6 100644 --- a/src/theory/strings/regexp_operation.h +++ b/src/theory/strings/regexp_operation.h @@ -69,9 +69,14 @@ private: std::string niceChar( Node r ); int gcd ( int a, int b ); Node mkAllExceptOne( char c ); + bool isPairNodesInSet(std::set< PairNodes > &s, Node n1, Node n2); void getCharSet( Node r, std::set<unsigned> &pcset, SetNodes &pvset ); Node intersectInternal( Node r1, Node r2, std::map< unsigned, std::set< PairNodes > > cache, bool &spflag ); + bool containC2(unsigned cnt, Node n); + Node convert1(unsigned cnt, Node n); + void convert2(unsigned cnt, Node n, Node &r1, Node &r2); + Node intersectInternal2( Node r1, Node r2, std::map< PairNodes, Node > cache, bool &spflag, unsigned cnt ); void firstChars( Node r, std::set<unsigned> &pcset, SetNodes &pvset ); //TODO: for intersection diff --git a/src/theory/strings/theory_strings.cpp b/src/theory/strings/theory_strings.cpp index 2856ce1e0..ac1b1b1ed 100644 --- a/src/theory/strings/theory_strings.cpp +++ b/src/theory/strings/theory_strings.cpp @@ -550,6 +550,10 @@ Node TheoryStrings::expandDefinition(LogicRequest &logicRequest, Node node) { void TheoryStrings::check(Effort e) { + if (done() && !fullEffort(e)) { + return; + } + bool polarity; TNode atom; @@ -2500,6 +2504,7 @@ bool TheoryStrings::checkMemberships() { std::vector< Node > processed; std::vector< Node > cprocessed; + Trace("regexp-debug") << "Checking Memberships ... " << std::endl; //if(options::stringEIT()) { //TODO: Opt for normal forms for(NodeListMap::const_iterator itr_xr = d_str_re_map.begin(); @@ -2507,6 +2512,7 @@ bool TheoryStrings::checkMemberships() { bool spflag = false; Node x = (*itr_xr).first; NodeList* lst = (*itr_xr).second; + Trace("regexp-debug") << "Checking Memberships for " << x << std::endl; if(d_inter_index.find(x) == d_inter_index.end()) { d_inter_index[x] = 0; } @@ -2515,6 +2521,7 @@ bool TheoryStrings::checkMemberships() { if(lst->size() == 1) { d_inter_cache[x] = (*lst)[0]; d_inter_index[x] = 1; + Trace("regexp-debug") << "... only one choice " << std::endl; } else if(lst->size() > 1) { Node r; if(d_inter_cache.find(x) != d_inter_cache.end()) { @@ -2528,6 +2535,7 @@ bool TheoryStrings::checkMemberships() { for(int i=0; i<cur_inter_idx; i++) { ++itr_lst; } + Trace("regexp-debug") << "... staring from : " << cur_inter_idx << ", we have " << lst->size() << std::endl; for(;itr_lst != lst->end(); ++itr_lst) { Node r2 = *itr_lst; r = d_regexp_opr.intersect(r, r2, spflag); @@ -2561,6 +2569,7 @@ bool TheoryStrings::checkMemberships() { } //} + Trace("regexp-debug") << "... No Intersec Conflict in Memberships " << std::endl; if(!addedLemma) { for( unsigned i=0; i<d_regexp_memberships.size(); i++ ) { //check regular expression membership @@ -3325,4 +3334,4 @@ TheoryStrings::Statistics::~Statistics(){ }/* CVC4::theory::strings namespace */ }/* CVC4::theory namespace */ -}/* CVC4 namespace */
\ No newline at end of file +}/* CVC4 namespace */ diff --git a/src/theory/strings/theory_strings_rewriter.cpp b/src/theory/strings/theory_strings_rewriter.cpp index 12ff92b5e..e37cabfb6 100644 --- a/src/theory/strings/theory_strings_rewriter.cpp +++ b/src/theory/strings/theory_strings_rewriter.cpp @@ -164,8 +164,12 @@ Node TheoryStringsRewriter::prerewriteOrRegExp(TNode node) { for(unsigned i=0; i<node.getNumChildren(); ++i) { if(node[i].getKind() == kind::REGEXP_UNION) { Node tmpNode = prerewriteOrRegExp( node[i] ); - for(unsigned int j=0; j<tmpNode.getNumChildren(); ++j) { - node_vec.push_back( tmpNode[j] ); + if(tmpNode.getKind() == kind::REGEXP_UNION) { + for(unsigned int j=0; j<tmpNode.getNumChildren(); ++j) { + node_vec.push_back( tmpNode[j] ); + } + } else { + node_vec.push_back( tmpNode ); } flag = true; } else if(node[i].getKind() == kind::REGEXP_EMPTY) { @@ -200,6 +204,7 @@ bool TheoryStringsRewriter::checkConstRegExp( TNode t ) { bool TheoryStringsRewriter::testConstStringInRegExp( CVC4::String &s, unsigned int index_start, TNode r ) { Assert( index_start <= s.size() ); + Trace("regexp-debug") << "Checking " << s << " in " << r << ", starting at " << index_start << std::endl; int k = r.getKind(); switch( k ) { case kind::STRING_TO_REGEXP: { @@ -278,7 +283,7 @@ bool TheoryStringsRewriter::testConstStringInRegExp( CVC4::String &s, unsigned i return false; } case kind::REGEXP_SIGMA: { - if(s.size() == 1) { + if(s.size() == index_start + 1) { return true; } else { return false; @@ -302,7 +307,7 @@ Node TheoryStringsRewriter::rewriteMembership(TNode node) { if(node[1].getKind() == kind::REGEXP_EMPTY) { retNode = NodeManager::currentNM()->mkConst( false ); - } else if( x.getKind() == kind::CONST_STRING && checkConstRegExp(node[1]) ) { + } else if(x.getKind()==kind::CONST_STRING && checkConstRegExp(node[1])) { //test whether x in node[1] CVC4::String s = x.getConst<String>(); retNode = NodeManager::currentNM()->mkConst( testConstStringInRegExp( s, 0, node[1] ) ); @@ -311,10 +316,12 @@ Node TheoryStringsRewriter::rewriteMembership(TNode node) { retNode = one.eqNode(NodeManager::currentNM()->mkNode(kind::STRING_LENGTH, x)); } else if(node[1].getKind() == kind::REGEXP_STAR && node[1][0].getKind() == kind::REGEXP_SIGMA) { retNode = NodeManager::currentNM()->mkConst( true ); - } else if( x != node[0] ) { + } else if(node[1].getKind() == kind::STRING_TO_REGEXP) { + retNode = x.eqNode(node[1][0]); + } else if(x != node[0]) { retNode = NodeManager::currentNM()->mkNode( kind::STRING_IN_REGEXP, x, node[1] ); } - return retNode; + return retNode; } RewriteResponse TheoryStringsRewriter::postRewrite(TNode node) { diff --git a/src/theory/strings/theory_strings_type_rules.h b/src/theory/strings/theory_strings_type_rules.h index 6d1bb1c98..8a51ea36c 100644 --- a/src/theory/strings/theory_strings_type_rules.h +++ b/src/theory/strings/theory_strings_type_rules.h @@ -466,6 +466,21 @@ public: } }; +class RegExpRVTypeRule { +public: + inline static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check) + throw (TypeCheckingExceptionPrivate, AssertionException) { + if( check ) { + TypeNode t = n[0].getType(check); + if (!t.isInteger()) { + throw TypeCheckingExceptionPrivate(n, "expecting an integer term in RV"); + } + } + return nodeManager->regexpType(); + } +}; + + }/* CVC4::theory::strings namespace */ }/* CVC4::theory namespace */ }/* CVC4 namespace */ diff --git a/src/theory/theory.h b/src/theory/theory.h index 7bfc7051f..867dd7c31 100644 --- a/src/theory/theory.h +++ b/src/theory/theory.h @@ -377,7 +377,7 @@ public: /** * Returns true if the assertFact queue is empty */ - bool done() throw() { + bool done() const throw() { return d_factsHead == d_facts.size(); } @@ -678,7 +678,7 @@ public: * This function is called when an attribute is set by a user. In SMT-LIBv2 this is done * via the syntax (! n :attr) */ - virtual void setUserAttribute(const std::string& attr, Node n) { + virtual void setUserAttribute(const std::string& attr, Node n, std::vector<Node> node_values, std::string str_value) { Unimplemented("Theory %s doesn't support Theory::setUserAttribute interface", identify().c_str()); } diff --git a/src/theory/theory_engine.cpp b/src/theory/theory_engine.cpp index eb1da84b2..ed56890ae 100644 --- a/src/theory/theory_engine.cpp +++ b/src/theory/theory_engine.cpp @@ -34,6 +34,8 @@ #include "smt/logic_exception.h" +#include "proof/proof_manager.h" + #include "util/node_visitor.h" #include "util/ite_removal.h" @@ -63,6 +65,8 @@ using namespace CVC4; using namespace CVC4::theory; void TheoryEngine::finishInit() { + PROOF (ProofManager::initTheoryProof(); ); + // initialize the quantifiers engine d_quantEngine = new QuantifiersEngine(d_context, d_userContext, this); @@ -153,7 +157,7 @@ TheoryEngine::TheoryEngine(context::Context* context, d_sharedTermsVisitor(d_sharedTerms), d_unconstrainedSimp(new UnconstrainedSimplifier(context, logicInfo)), d_bvToBoolPreprocessor(), - d_arithSubstitutionsAdded("zzz::arith::substitutions", 0) + d_arithSubstitutionsAdded("theory::arith::zzz::arith::substitutions", 0) { for(TheoryId theoryId = theory::THEORY_FIRST; theoryId != theory::THEORY_LAST; ++ theoryId) { d_theoryTable[theoryId] = NULL; @@ -168,8 +172,6 @@ TheoryEngine::TheoryEngine(context::Context* context, d_true = NodeManager::currentNM()->mkConst<bool>(true); d_false = NodeManager::currentNM()->mkConst<bool>(false); - PROOF (ProofManager::currentPM()->initTheoryProof(); ); - d_iteUtilities = new ITEUtilities(d_iteRemover.getContainsVisitor()); StatisticsRegistry::registerStat(&d_arithSubstitutionsAdded); @@ -403,7 +405,7 @@ void TheoryEngine::check(Theory::Effort effort) { propagate(effort); // We do combination if all has been processed and we are in fullcheck - if (Theory::fullEffort(effort) && d_logicInfo.isSharingEnabled() && !d_factsAsserted && !d_lemmasAdded) { + if (Theory::fullEffort(effort) && d_logicInfo.isSharingEnabled() && !d_factsAsserted && !d_lemmasAdded && !d_inConflict) { // Do the combination Debug("theory") << "TheoryEngine::check(" << effort << "): running combination" << endl; combineTheories(); @@ -451,7 +453,7 @@ void TheoryEngine::check(Theory::Effort effort) { void TheoryEngine::combineTheories() { - Debug("sharing") << "TheoryEngine::combineTheories()" << endl; + Trace("combineTheories") << "TheoryEngine::combineTheories()" << endl; TimerStat::CodeTimer combineTheoriesTimer(d_combineTheoriesTime); @@ -469,25 +471,48 @@ void TheoryEngine::combineTheories() { // Call on each parametric theory to give us its care graph CVC4_FOR_EACH_THEORY; - Debug("sharing") << "TheoryEngine::combineTheories(): care graph size = " << careGraph.size() << endl; + Trace("combineTheories") << "TheoryEngine::combineTheories(): care graph size = " << careGraph.size() << endl; // Now add splitters for the ones we are interested in CareGraph::const_iterator care_it = careGraph.begin(); CareGraph::const_iterator care_it_end = careGraph.end(); + for (; care_it != care_it_end; ++ care_it) { const CarePair& carePair = *care_it; - Debug("sharing") << "TheoryEngine::combineTheories(): checking " << carePair.a << " = " << carePair.b << " from " << carePair.theory << endl; + Debug("combineTheories") << "TheoryEngine::combineTheories(): checking " << carePair.a << " = " << carePair.b << " from " << carePair.theory << endl; Assert(d_sharedTerms.isShared(carePair.a) || carePair.a.isConst()); Assert(d_sharedTerms.isShared(carePair.b) || carePair.b.isConst()); // The equality in question (order for no repetition) Node equality = carePair.a.eqNode(carePair.b); + EqualityStatus es = getEqualityStatus(carePair.a, carePair.b); + Debug("combineTheories") << "TheoryEngine::combineTheories(): " << + (es == EQUALITY_TRUE_AND_PROPAGATED ? "EQUALITY_TRUE_AND_PROPAGATED" : + es == EQUALITY_FALSE_AND_PROPAGATED ? "EQUALITY_FALSE_AND_PROPAGATED" : + es == EQUALITY_TRUE ? "EQUALITY_TRUE" : + es == EQUALITY_FALSE ? "EQUALITY_FALSE" : + es == EQUALITY_TRUE_IN_MODEL ? "EQUALITY_TRUE_IN_MODEL" : + es == EQUALITY_FALSE_IN_MODEL ? "EQUALITY_FALSE_IN_MODEL" : + es == EQUALITY_UNKNOWN ? "EQUALITY_UNKNOWN" : + "Unexpected case") << endl; // We need to split on it - Debug("sharing") << "TheoryEngine::combineTheories(): requesting a split " << endl; + Debug("combineTheories") << "TheoryEngine::combineTheories(): requesting a split " << endl; lemma(equality.orNode(equality.notNode()), false, false, false, carePair.theory); + // This code is supposed to force preference to follow what the theory models already have + // but it doesn't seem to make a big difference - need to explore more -Clark + // if (true) { + // if (es == EQUALITY_TRUE || es == EQUALITY_TRUE_IN_MODEL) { + // Node e = ensureLiteral(equality); + // d_propEngine->requirePhase(e, true); + // } + // else if (es == EQUALITY_FALSE_IN_MODEL) { + // Node e = ensureLiteral(equality); + // d_propEngine->requirePhase(e, false); + // } + // } } } @@ -1180,6 +1205,18 @@ Node TheoryEngine::getModelValue(TNode var) { return theoryOf(Theory::theoryOf(var.getType()))->getModelValue(var); } + +Node TheoryEngine::ensureLiteral(TNode n) { + Debug("ensureLiteral") << "rewriting: " << n << std::endl; + Node rewritten = Rewriter::rewrite(n); + Debug("ensureLiteral") << " got: " << rewritten << std::endl; + Node preprocessed = preprocess(rewritten); + Debug("ensureLiteral") << "preprocessed: " << preprocessed << std::endl; + d_propEngine->ensureLiteral(preprocessed); + return preprocessed; +} + + void TheoryEngine::printInstantiations( std::ostream& out ) { if( d_quantEngine ){ d_quantEngine->printInstantiations( out ); @@ -1339,6 +1376,8 @@ void TheoryEngine::ensureLemmaAtoms(const std::vector<TNode>& atoms, theory::The } theory::LemmaStatus TheoryEngine::lemma(TNode node, bool negated, bool removable, bool preprocess, theory::TheoryId atomsTo) { + // For resource-limiting (also does a time check). + spendResource(); // Do we need to check atoms if (atomsTo != theory::THEORY_LAST) { @@ -1385,23 +1424,17 @@ theory::LemmaStatus TheoryEngine::lemma(TNode node, bool negated, bool removable } // assert to prop engine - d_propEngine->assertLemma(additionalLemmas[0], negated, removable); + d_propEngine->assertLemma(additionalLemmas[0], negated, removable, RULE_INVALID, node); for (unsigned i = 1; i < additionalLemmas.size(); ++ i) { additionalLemmas[i] = theory::Rewriter::rewrite(additionalLemmas[i]); - d_propEngine->assertLemma(additionalLemmas[i], false, removable); + d_propEngine->assertLemma(additionalLemmas[i], false, removable, RULE_INVALID, node); } // WARNING: Below this point don't assume additionalLemmas[0] to be not negated. - // WARNING: Below this point don't assume additionalLemmas[0] to be not negated. if(negated) { - // Can't we just get rid of passing around this 'negated' stuff? - // Is it that hard for the propEngine to figure that out itself? - // (I like the use of triple negation <evil laugh>.) --K additionalLemmas[0] = additionalLemmas[0].notNode(); negated = false; } - // WARNING: Below this point don't assume additionalLemmas[0] to be not negated. - // WARNING: Below this point don't assume additionalLemmas[0] to be not negated. // assert to decision engine if(!removable) { @@ -1668,11 +1701,11 @@ void TheoryEngine::ppUnconstrainedSimp(vector<Node>& assertions) } -void TheoryEngine::setUserAttribute(const std::string& attr, Node n) { +void TheoryEngine::setUserAttribute(const std::string& attr, Node n, std::vector<Node> node_values, std::string str_value) { Trace("te-attr") << "set user attribute " << attr << " " << n << endl; if( d_attr_handle.find( attr )!=d_attr_handle.end() ){ for( size_t i=0; i<d_attr_handle[attr].size(); i++ ){ - d_attr_handle[attr][i]->setUserAttribute(attr, n); + d_attr_handle[attr][i]->setUserAttribute(attr, n, node_values, str_value); } } else { //unhandled exception? diff --git a/src/theory/theory_engine.h b/src/theory/theory_engine.h index e6684d56e..e589e8f87 100644 --- a/src/theory/theory_engine.h +++ b/src/theory/theory_engine.h @@ -759,6 +759,11 @@ public: Node getModelValue(TNode var); /** + * Takes a literal and returns an equivalent literal that is guaranteed to be a SAT literal + */ + Node ensureLiteral(TNode n); + + /** * Print all instantiations made by the quantifiers module. */ void printInstantiations( std::ostream& out ); @@ -820,7 +825,7 @@ public: * This function is called when an attribute is set by a user. In SMT-LIBv2 this is done * via the syntax (! n :attr) */ - void setUserAttribute(const std::string& attr, Node n); + void setUserAttribute(const std::string& attr, Node n, std::vector<Node> node_values, std::string str_value); /** * Handle user attribute. diff --git a/src/theory/uf/options b/src/theory/uf/options index 26f87da79..d9e4c9477 100644 --- a/src/theory/uf/options +++ b/src/theory/uf/options @@ -29,8 +29,8 @@ option ufssSimpleCliques --uf-ss-simple-cliques bool :default true always use simple clique lemmas for uf strong solver option ufssDiseqPropagation --uf-ss-deq-prop bool :default false eagerly propagate disequalities for uf strong solver -option ufssMinimalModel /--disable-uf-ss-min-model bool :default true - disable finding a minimal model in uf strong solver +option ufssMode --uf-ss=MODE CVC4::theory::uf::UfssMode :default CVC4::theory::uf::UF_SS_FULL :include "theory/uf/options_handlers.h" :handler CVC4::theory::uf::stringToUfssMode :handler-include "theory/uf/options_handlers.h" + mode of operation for uf strong solver. option ufssCliqueSplits --uf-ss-clique-splits bool :default false use cliques instead of splitting on demand to shrink model diff --git a/src/theory/uf/options_handlers.h b/src/theory/uf/options_handlers.h index a885a10d2..8c072e232 100644 --- a/src/theory/uf/options_handlers.h +++ b/src/theory/uf/options_handlers.h @@ -2,7 +2,7 @@ /*! \file options_handlers.h ** \verbatim ** Original author: Morgan Deters - ** Major contributors: none + ** Major contributors: Andrew Reynolds ** Minor contributors (to current version): none ** This file is part of the CVC4 project. ** Copyright (c) 2009-2014 New York University and The University of Iowa @@ -22,6 +22,45 @@ namespace CVC4 { namespace theory { namespace uf { + +typedef enum { + /** default, use uf strong solver to find minimal models for uninterpreted sorts */ + UF_SS_FULL, + /** use uf strong solver to shrink model sizes, but do no enforce minimality */ + UF_SS_NO_MINIMAL, + /** do not use uf strong solver */ + UF_SS_NONE, +} UfssMode; + +static const std::string ufssModeHelp = "\ +UF strong solver options currently supported by the --uf-ss option:\n\ +\n\ +full \n\ ++ Default, use uf strong solver to find minimal models for uninterpreted sorts.\n\ +\n\ +no-minimal \n\ ++ Use uf strong solver to shrink model sizes, but do no enforce minimality.\n\ +\n\ +none \n\ ++ Do not use uf strong solver to shrink model sizes. \n\ +\n\ +"; + +inline UfssMode stringToUfssMode(std::string option, std::string optarg, SmtEngine* smt) throw(OptionException) { + if(optarg == "default" || optarg == "full" ) { + return UF_SS_FULL; + } else if(optarg == "no-minimal") { + return UF_SS_NO_MINIMAL; + } else if(optarg == "none") { + return UF_SS_NONE; + } else if(optarg == "help") { + puts(ufssModeHelp.c_str()); + exit(1); + } else { + throw OptionException(std::string("unknown option for --uf-ss: `") + + optarg + "'. Try --uf-ss help."); + } +} }/* CVC4::theory::uf namespace */ }/* CVC4::theory namespace */ diff --git a/src/theory/uf/theory_uf.cpp b/src/theory/uf/theory_uf.cpp index 0da8e8c32..2b9fc3daf 100644 --- a/src/theory/uf/theory_uf.cpp +++ b/src/theory/uf/theory_uf.cpp @@ -61,7 +61,7 @@ void TheoryUF::setMasterEqualityEngine(eq::EqualityEngine* eq) { void TheoryUF::finishInit() { // initialize the strong solver - if (options::finiteModelFind()) { + if (options::finiteModelFind() && options::ufssMode()!=UF_SS_NONE) { d_thss = new StrongSolverTheoryUF(getSatContext(), getUserContext(), *d_out, this); } } @@ -89,6 +89,10 @@ static Node mkAnd(const std::vector<TNode>& conjunctions) { }/* mkAnd() */ void TheoryUF::check(Effort level) { + if (done() && !fullEffort(level)) { + return; + } + while (!done() && !d_conflict) { // Get all the assertions diff --git a/src/theory/uf/theory_uf_strong_solver.cpp b/src/theory/uf/theory_uf_strong_solver.cpp index 001b21d0a..cddaace3e 100644 --- a/src/theory/uf/theory_uf_strong_solver.cpp +++ b/src/theory/uf/theory_uf_strong_solver.cpp @@ -339,16 +339,6 @@ bool StrongSolverTheoryUF::SortModel::Region::getCandidateClique( int cardinalit return false; } - -void StrongSolverTheoryUF::SortModel::Region::getRepresentatives( std::vector< Node >& reps ){ - for( std::map< Node, RegionNodeInfo* >::iterator it = d_nodes.begin(); it != d_nodes.end(); ++it ){ - RegionNodeInfo* rni = it->second; - if( rni->d_valid ){ - reps.push_back( it->first ); - } - } -} - void StrongSolverTheoryUF::SortModel::Region::getNumExternalDisequalities( std::map< Node, int >& num_ext_disequalities ){ for( std::map< Node, RegionNodeInfo* >::iterator it = d_nodes.begin(); it != d_nodes.end(); ++it ){ RegionNodeInfo* rni = it->second; @@ -624,7 +614,7 @@ void StrongSolverTheoryUF::SortModel::check( Theory::Effort level, OutputChannel if( d_regions[i]->d_valid ){ std::vector< Node > clique; if( d_regions[i]->check( level, d_cardinality, clique ) ){ - if( options::ufssMinimalModel() ){ + if( options::ufssMode()==UF_SS_FULL ){ //add clique lemma addCliqueLemma( clique, out ); return; @@ -695,7 +685,7 @@ void StrongSolverTheoryUF::SortModel::check( Theory::Effort level, OutputChannel if( d_regions[i]->d_valid ){ int fcr = forceCombineRegion( i, false ); Trace("uf-ss-debug") << "Combined regions " << i << " " << fcr << std::endl; - if( options::ufssMinimalModel() || fcr!=-1 ){ + if( options::ufssMode()==UF_SS_FULL || fcr!=-1 ){ recheck = true; break; } @@ -921,7 +911,7 @@ void StrongSolverTheoryUF::SortModel::checkRegion( int ri, bool checkCombine ){ //now check if region is in conflict std::vector< Node > clique; if( d_regions[ri]->check( Theory::EFFORT_STANDARD, d_cardinality, clique ) ){ - if( options::ufssMinimalModel() ){ + if( options::ufssMode()==UF_SS_FULL ){ //explain clique addCliqueLemma( clique, &d_thss->getOutputChannel() ); } @@ -1085,7 +1075,7 @@ int StrongSolverTheoryUF::SortModel::addSplit( Region* r, OutputChannel* out ){ } Assert( s!=Node::null() ); }else{ - if( !options::ufssMinimalModel() ){ + if( options::ufssMode()!=UF_SS_FULL ){ //since candidate clique is not reported, we may need to find splits manually for ( std::map< Node, Region::RegionNodeInfo* >::iterator it = r->d_nodes.begin(); it != r->d_nodes.end(); ++it ){ if ( it->second->d_valid ){ @@ -1480,19 +1470,6 @@ int StrongSolverTheoryUF::SortModel::getNumRegions(){ return count; } -void StrongSolverTheoryUF::SortModel::getRepresentatives( std::vector< Node >& reps ){ - for( int i=0; i<(int)d_regions_index; i++ ){ - //should not have multiple regions at this point - //if( foundRegion ){ - // Assert( !d_regions[i]->d_valid ); - //} - if( d_regions[i]->d_valid ){ - //this is the only valid region - d_regions[i]->getRepresentatives( reps ); - } - } -} - Node StrongSolverTheoryUF::SortModel::getCardinalityLiteral( int c ) { if( d_cardinality_literal.find( c )==d_cardinality_literal.end() ){ d_cardinality_literal[c] = NodeManager::currentNM()->mkNode( CARDINALITY_CONSTRAINT, d_cardinality_term, @@ -1661,7 +1638,7 @@ bool StrongSolverTheoryUF::areDisequal( Node a, Node b ) { void StrongSolverTheoryUF::check( Theory::Effort level ){ if( !d_conflict ){ Trace("uf-ss-solver") << "StrongSolverTheoryUF: check " << level << std::endl; - if( level==Theory::EFFORT_FULL ){ + if( level==Theory::EFFORT_FULL && Debug.isOn( "uf-ss-debug" ) ){ debugPrint( "uf-ss-debug" ); } for( std::map< TypeNode, SortModel* >::iterator it = d_rep_model.begin(); it != d_rep_model.end(); ++it ){ @@ -1801,19 +1778,6 @@ int StrongSolverTheoryUF::getCardinality( TypeNode tn ) { return -1; } -/* -void StrongSolverTheoryUF::getRepresentatives( Node n, std::vector< Node >& reps ){ - SortModel* c = getSortModel( n ); - if( c ){ - c->getRepresentatives( reps ); - if( (int)reps.size()!=c->getCardinality() ){ - Trace("uf-ss-warn") << "Sort " << n.getType() << " has cardinality " << c->getCardinality(); - Trace("uf-ss-warn") << ", but provided " << reps.size() << " representatives!!!" << std::endl; - } - } -} -*/ - bool StrongSolverTheoryUF::minimize( TheoryModel* m ){ for( std::map< TypeNode, SortModel* >::iterator it = d_rep_model.begin(); it != d_rep_model.end(); ++it ){ if( !it->second->minimize( d_out, m ) ){ diff --git a/src/theory/uf/theory_uf_strong_solver.h b/src/theory/uf/theory_uf_strong_solver.h index 1e5a361a7..333f1717e 100644 --- a/src/theory/uf/theory_uf_strong_solver.h +++ b/src/theory/uf/theory_uf_strong_solver.h @@ -146,8 +146,6 @@ public: bool getMustCombine( int cardinality ); /** has splits */ bool hasSplits() { return d_splitsSize>0; } - /** get representatives */ - void getRepresentatives( std::vector< Node >& reps ); /** get external disequalities */ void getNumExternalDisequalities( std::map< Node, int >& num_ext_disequalities ); public: @@ -280,8 +278,6 @@ public: bool isConflict() { return d_conflict; } /** get cardinality */ int getCardinality() { return d_cardinality; } - /** get representatives */ - void getRepresentatives( std::vector< Node >& reps ); /** has cardinality */ bool hasCardinalityAsserted() { return d_hasCard; } /** get cardinality term */ @@ -381,8 +377,6 @@ public: int getCardinality( Node n ); /** get cardinality for type */ int getCardinality( TypeNode tn ); - /** get representatives */ - //void getRepresentatives( Node n, std::vector< Node >& reps ); /** minimize */ bool minimize( TheoryModel* m = NULL ); diff --git a/src/theory/valuation.cpp b/src/theory/valuation.cpp index 72d878782..b2d7f4b21 100644 --- a/src/theory/valuation.cpp +++ b/src/theory/valuation.cpp @@ -88,13 +88,7 @@ Node Valuation::getModelValue(TNode var) { } Node Valuation::ensureLiteral(TNode n) { - Debug("ensureLiteral") << "rewriting: " << n << std::endl; - Node rewritten = Rewriter::rewrite(n); - Debug("ensureLiteral") << " got: " << rewritten << std::endl; - Node preprocessed = d_engine->preprocess(rewritten); - Debug("ensureLiteral") << "preproced: " << preprocessed << std::endl; - d_engine->getPropEngine()->ensureLiteral(preprocessed); - return preprocessed; + return d_engine->ensureLiteral(n); } bool Valuation::isDecision(Node lit) const { |