diff options
Diffstat (limited to 'src')
133 files changed, 7579 insertions, 6827 deletions
diff --git a/src/Makefile.am b/src/Makefile.am index 40d3823e9..c9f928ba8 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -30,8 +30,8 @@ libcvc4_la_LDFLAGS = -version-info $(LIBCVC4_VERSION) # as a C library, which messes up exception handling support) nodist_EXTRA_libcvc4_noinst_la_SOURCES = dummy.cpp nodist_EXTRA_libcvc4_la_SOURCES = dummy.cpp -libcvc4_noinst_la_SOURCES = subversion_versioninfo.cpp -libcvc4_la_SOURCES = subversion_versioninfo.cpp +libcvc4_noinst_la_SOURCES = git_versioninfo.cpp svn_versioninfo.cpp +libcvc4_la_SOURCES = git_versioninfo.cpp svn_versioninfo.cpp libcvc4_la_LIBADD = \ @builddir@/options/liboptions.la \ @builddir@/util/libutil.la \ @@ -67,9 +67,12 @@ libcvc4_noinst_la_LIBADD += \ endif CLEANFILES = \ - subversion_versioninfo.cpp \ + svn_versioninfo.cpp \ svninfo.tmp \ - svninfo + svninfo \ + git_versioninfo.cpp \ + gitinfo.tmp \ + gitinfo EXTRA_DIST = \ include/cvc4_private_library.h \ @@ -80,13 +83,13 @@ EXTRA_DIST = \ include/cvc4.h \ cvc4.i -subversion_versioninfo.cpp: svninfo +svn_versioninfo.cpp: svninfo $(AM_V_GEN)( \ if test -s svninfo; then \ issvn=true; \ branch=`grep '^URL: ' svninfo | sed 's,.*/cvc4/,,'`; \ rev=`grep '^Revision: ' svninfo | awk '{print$$2}'`; \ - mods=`grep '^Modifications: ' svninfo | awk '{print$$2}'`; \ + mods=`grep '^Modifications: ' svninfo | awk '{print$$2} END { if(!NR) print "false" }'`; \ else \ issvn=false; \ branch=unknown; \ @@ -108,6 +111,34 @@ svninfo: svninfo.tmp svninfo.tmp: $(AM_V_GEN)(cd "$(top_srcdir)" && svn info && echo "Modifications: `test -z \"\`svn status -q\`\" && echo false || echo true`") >"$@" 2>/dev/null || true +git_versioninfo.cpp: gitinfo + $(AM_V_GEN)( \ + if test -s gitinfo; then \ + isgit=true; \ + branch=`head -1 gitinfo`; \ + rev=`head -2 gitinfo | tail -1 | awk '{print$$1}'`; \ + mods=`grep '^Modifications: ' gitinfo | awk '{print$$2} END { if(!NR) print "false" }'`; \ + else \ + isgit=false; \ + branch=unknown; \ + rev=unknown; \ + mods=false; \ + fi; \ + echo "#include \"util/configuration.h\""; \ + echo "const bool ::CVC4::Configuration::IS_GIT_BUILD = $$isgit;"; \ + echo "const char* const ::CVC4::Configuration::GIT_BRANCH_NAME = \"$$branch\";"; \ + echo "const char* const ::CVC4::Configuration::GIT_COMMIT = \"$$rev\";"; \ + echo "const bool ::CVC4::Configuration::GIT_HAS_MODIFICATIONS = $$mods;"; \ + ) >"$@" +# This .tmp business is to keep from having to re-compile options.cpp +# (and then re-link the libraries) if nothing has changed. +gitinfo: gitinfo.tmp + $(AM_V_GEN)diff -q gitinfo.tmp gitinfo &>/dev/null || mv gitinfo.tmp gitinfo || true +# .PHONY ensures the .tmp version is always rebuilt (to check for any changes) +.PHONY: gitinfo.tmp +gitinfo.tmp: + $(AM_V_GEN)(cd "$(top_srcdir)" && sed 's,^ref: refs/heads/,,' .git/HEAD && git show-ref refs/heads/`sed 's,^ref: refs/heads/,,' .git/HEAD` && echo "Modifications: `test -z \"\`git status -s -uno\`\" && echo false || echo true`") >"$@" 2>/dev/null || true + install-data-local: (echo include/cvc4.h; \ echo include/cvc4_public.h; \ @@ -120,7 +151,7 @@ install-data-local: (cd "$(srcdir)" && find * -name '*.h' | \ xargs grep -l '^# *include *"cvc4.*_public\.h"')) | \ while read f; do \ - if expr "$$f" : ".*_\(template\|private\|test_utils\)\.h$$" &>/dev/null; then \ + if expr "$$f" : ".*_\(template\|private\|private_library\|test_utils\)\.h$$" &>/dev/null; then \ continue; \ fi; \ d="$$(echo "$$f" | sed 's,^include/,,')"; \ @@ -150,7 +181,7 @@ uninstall-local: (cd "$(srcdir)" && find * -name '*.h' | \ xargs grep -l '^# *include *"cvc4.*_public\.h"')) | \ while read f; do \ - if expr "$$f" : ".*_\(template\|private\|test_utils\)\.h$$" &>/dev/null; then \ + if expr "$$f" : ".*_\(template\|private\|private_library\|test_utils\)\.h$$" &>/dev/null; then \ continue; \ fi; \ d="$$(echo "$$f" | sed 's,^include/,,')"; \ @@ -175,7 +206,7 @@ mostlyclean-local: (cd "$(srcdir)" && find * -name '*.h' | \ xargs grep -l '^# *include *"cvc4.*_public\.h"')) | \ while read f; do \ - if expr "$$f" : ".*_\(template\|private\|test_utils\)\.h$$" &>/dev/null; then \ + if expr "$$f" : ".*_\(template\|private\|private_library\|test_utils\)\.h$$" &>/dev/null; then \ continue; \ fi; \ d="$$(echo "$$f" | sed 's,^include/,,')"; \ diff --git a/src/compat/cvc3_compat.cpp b/src/compat/cvc3_compat.cpp index 2a8673451..0cd35ce0d 100644 --- a/src/compat/cvc3_compat.cpp +++ b/src/compat/cvc3_compat.cpp @@ -1075,7 +1075,7 @@ Type ValidityChecker::subrangeType(const Expr& l, const Expr& r) { } Type ValidityChecker::subtypeType(const Expr& pred, const Expr& witness) { - Unimplemented("Records not supported by CVC4 yet (sorry!)"); + Unimplemented("Predicate subtyping not supported by CVC4 yet (sorry!)"); /* if(witness.isNull()) { return d_em->mkPredicateSubtype(pred); diff --git a/src/context/cdinsert_hashmap.h b/src/context/cdinsert_hashmap.h index 0c84eda80..74e2fcf28 100644 --- a/src/context/cdinsert_hashmap.h +++ b/src/context/cdinsert_hashmap.h @@ -392,7 +392,7 @@ class CDInsertHashMap <TNode, Data, HashFcn > : public ContextObj { * If the key is a TNode and the backing (the hard node reference) * for the key in another data structure removes the key at the same context * the ref count could drop to 0. The key would then not be eligible to be - * hashed. Getting the order right with a guarentee is to hard. + * hashed. Getting the order right with a guarantee is too hard. */ BOOST_STATIC_ASSERT(sizeof(Data) == 0); diff --git a/src/context/cdtrail_hashmap.h b/src/context/cdtrail_hashmap.h index 5f090341d..2d2020a16 100644 --- a/src/context/cdtrail_hashmap.h +++ b/src/context/cdtrail_hashmap.h @@ -540,7 +540,7 @@ public: return d_trailMap->find(k); } - /** Returns an iterator to the begining of the map. */ + /** Returns an iterator to the beginning of the map. */ const_iterator begin() const{ return d_trailMap->begin(); } @@ -561,7 +561,7 @@ class CDTrailHashMap <TNode, Data, HashFcn > : public ContextObj { * If the key is a TNode and the backing (the hard node reference) * for the key in another data structure removes the key at the same context * the ref count could drop to 0. The key would then not be eligible to be - * hashed. Getting the order right with a guarentee is to hard. + * hashed. Getting the order right with a guarantee is too hard. */ BOOST_STATIC_ASSERT(sizeof(Data) == 0); diff --git a/src/decision/decision_engine.cpp b/src/decision/decision_engine.cpp index 9e8add752..08a3e49d0 100644 --- a/src/decision/decision_engine.cpp +++ b/src/decision/decision_engine.cpp @@ -96,7 +96,7 @@ bool DecisionEngine::isRelevant(SatVariable var) SatValue DecisionEngine::getPolarity(SatVariable var) { - Debug("decision") << "getPolariry(" << var <<")" << std::endl; + Debug("decision") << "getPolarity(" << var <<")" << std::endl; if(d_relevancyStrategy != NULL) { Assert(isRelevant(var)); return d_relevancyStrategy->getPolarity( d_cnfStream->getNode(SatLiteral(var)) ); diff --git a/src/decision/decision_strategy.h b/src/decision/decision_strategy.h index a3c0d1684..a2fda44fe 100644 --- a/src/decision/decision_strategy.h +++ b/src/decision/decision_strategy.h @@ -9,7 +9,7 @@ ** See the file COPYING in the top-level source directory for licensing ** information.\endverbatim ** - ** \brief Decision stategy + ** \brief Decision strategy ** ** Decision strategy **/ diff --git a/src/decision/justification_heuristic.cpp b/src/decision/justification_heuristic.cpp index 46ec6f09f..0b63dfbe1 100644 --- a/src/decision/justification_heuristic.cpp +++ b/src/decision/justification_heuristic.cpp @@ -16,25 +16,6 @@ ** ** It needs access to the simplified but non-clausal formula. **/ -/*****************************************************************************/ -/*! - * file search_sat.cpp - * brief Implementation of Search engine with generic external sat solver - * - * Author: Clark Barrett - * - * Created: Wed Dec 7 21:00:24 2005 - * - * <hr> - * - * License to use, copy, modify, sell and/or distribute this software - * and its documentation for any purpose is hereby granted without - * royalty, subject to the terms and conditions defined in the \ref - * LICENSE file provided with this distribution. - * - * <hr> - */ -/*****************************************************************************/ #include "justification_heuristic.h" @@ -43,7 +24,158 @@ #include "theory/rewriter.h" #include "util/ite_removal.h" -// JustificationHeuristic stuff + +using namespace CVC4; + +JustificationHeuristic::JustificationHeuristic(CVC4::DecisionEngine* de, + context::Context *uc, + context::Context *c): + ITEDecisionStrategy(de, c), + d_justified(c), + d_prvsIndex(c, 0), + d_helfulness("decision::jh::helpfulness", 0), + d_giveup("decision::jh::giveup", 0), + d_timestat("decision::jh::time"), + d_assertions(uc), + d_iteAssertions(uc), + d_iteCache(), + d_visited(), + d_visitedComputeITE(), + d_curDecision() { + StatisticsRegistry::registerStat(&d_helfulness); + StatisticsRegistry::registerStat(&d_giveup); + StatisticsRegistry::registerStat(&d_timestat); + Trace("decision") << "Justification heuristic enabled" << std::endl; +} + +JustificationHeuristic::~JustificationHeuristic() { + StatisticsRegistry::unregisterStat(&d_helfulness); + StatisticsRegistry::unregisterStat(&d_giveup); + StatisticsRegistry::unregisterStat(&d_timestat); +} + +CVC4::prop::SatLiteral JustificationHeuristic::getNext(bool &stopSearch) { + Trace("decision") << "JustificationHeuristic::getNext()" << std::endl; + TimerStat::CodeTimer codeTimer(d_timestat); + + d_visited.clear(); + + if(Trace.isOn("justified")) { + for(JustifiedSet::key_iterator i = d_justified.key_begin(); + i != d_justified.key_end(); ++i) { + TNode n = *i; + SatLiteral l = d_decisionEngine->hasSatLiteral(n) ? + d_decisionEngine->getSatLiteral(n) : -1; + SatValue v = tryGetSatValue(n); + Trace("justified") <<"{ "<<l<<"}" << n <<": "<<v << std::endl; + } + } + + for(unsigned i = d_prvsIndex; i < d_assertions.size(); ++i) { + Debug("decision") << "---" << std::endl << d_assertions[i] << std::endl; + + // Sanity check: if it was false, aren't we inconsistent? + Assert( tryGetSatValue(d_assertions[i]) != SAT_VALUE_FALSE); + + SatValue desiredVal = SAT_VALUE_TRUE; + SatLiteral litDecision; + + litDecision = findSplitter(d_assertions[i], desiredVal); + + if(litDecision != undefSatLiteral) { + d_prvsIndex = i; + return litDecision; + } + } + + Trace("decision") << "jh: Nothing to split on " << std::endl; + +#if defined CVC4_DEBUG + bool alljustified = true; + for(unsigned i = 0 ; i < d_assertions.size() && alljustified ; ++i) { + TNode curass = d_assertions[i]; + while(curass.getKind() == kind::NOT) + curass = curass[0]; + alljustified &= checkJustified(curass); + + if(Debug.isOn("decision")) { + if(!checkJustified(curass)) + Debug("decision") << "****** Not justified [i="<<i<<"]: " + << d_assertions[i] << std::endl; + } + } + Assert(alljustified); +#endif + + // SAT solver can stop... + stopSearch = true; + d_decisionEngine->setResult(SAT_VALUE_TRUE); + return prop::undefSatLiteral; +} + + +inline void computeXorIffDesiredValues +(Kind k, SatValue desiredVal, SatValue &desiredVal1, SatValue &desiredVal2) +{ + Assert(k == kind::IFF || k == kind::XOR); + + bool shouldInvert = + (desiredVal == SAT_VALUE_TRUE && k == kind::IFF) || + (desiredVal == SAT_VALUE_FALSE && k == kind::XOR); + + if(desiredVal1 == SAT_VALUE_UNKNOWN && + desiredVal2 == SAT_VALUE_UNKNOWN) { + // CHOICE: pick one of them arbitarily + desiredVal1 = SAT_VALUE_FALSE; + } + + if(desiredVal2 == SAT_VALUE_UNKNOWN) { + desiredVal2 = shouldInvert ? invertValue(desiredVal1) : desiredVal1; + } else if(desiredVal1 == SAT_VALUE_UNKNOWN) { + desiredVal1 = shouldInvert ? invertValue(desiredVal2) : desiredVal2; + } +} + + + +void JustificationHeuristic::addAssertions +(const std::vector<Node> &assertions, + unsigned assertionsEnd, + IteSkolemMap iteSkolemMap) { + + Trace("decision") + << "JustificationHeuristic::addAssertions()" + << " size = " << assertions.size() + << " assertionsEnd = " << assertionsEnd + << std::endl; + + // Save the 'real' assertions locally + for(unsigned i = 0; i < assertionsEnd; ++i) + d_assertions.push_back(assertions[i]); + + // Save mapping between ite skolems and ite assertions + for(IteSkolemMap::iterator i = iteSkolemMap.begin(); + i != iteSkolemMap.end(); ++i) { + + Trace("decision::jh::ite") + << " jh-ite: " << (i->first) << " maps to " + << assertions[(i->second)] << std::endl; + Assert(i->second >= assertionsEnd && i->second < assertions.size()); + + d_iteAssertions[i->first] = assertions[i->second]; + } +} + +SatLiteral JustificationHeuristic::findSplitter(TNode node, + SatValue desiredVal) +{ + d_curDecision = undefSatLiteral; + if(findSplitterRec(node, desiredVal)) { + ++d_helfulness; + } + return d_curDecision; +} + void JustificationHeuristic::setJustified(TNode n) { @@ -67,9 +199,25 @@ SatValue JustificationHeuristic::tryGetSatValue(Node n) }//end of else } +const JustificationHeuristic::IteList& +JustificationHeuristic::getITEs(TNode n) +{ + IteCache::iterator it = d_iteCache.find(n); + if(it != d_iteCache.end()) { + return it->second; + } else { + // Compute the list of ITEs + // TODO: optimize by avoiding multiple lookup for d_iteCache[n] + d_iteCache[n] = IteList(); + d_visitedComputeITE.clear(); + computeITEs(n, d_iteCache[n]); + return d_iteCache[n]; + } +} + void JustificationHeuristic::computeITEs(TNode n, IteList &l) { - Trace("jh-ite") << " computeITEs( " << n << ", &l)\n"; + Trace("decision::jh::ite") << " computeITEs( " << n << ", &l)\n"; d_visitedComputeITE.insert(n); for(unsigned i=0; i<n.getNumChildren(); ++i) { SkolemMap::iterator it2 = d_iteAssertions.find(n[i]); @@ -84,35 +232,19 @@ void JustificationHeuristic::computeITEs(TNode n, IteList &l) } } -const JustificationHeuristic::IteList& JustificationHeuristic::getITEs(TNode n) -{ - IteCache::iterator it = d_iteCache.find(n); - if(it != d_iteCache.end()) { - return it->second; - } else { - // Compute the list of ITEs - // TODO: optimize by avoiding multiple lookup for d_iteCache[n] - d_iteCache[n] = IteList(); - d_visitedComputeITE.clear(); - computeITEs(n, d_iteCache[n]); - return d_iteCache[n]; - } -} - bool JustificationHeuristic::findSplitterRec(TNode node, - SatValue desiredVal, - SatLiteral* litDecision) + SatValue desiredVal) { /** * Main idea * * Given a boolean formula "node", the goal is to try to make it - * evaluate to "desiredVal" (true/false). for instance if "node" is a AND + * evaluate to "desiredVal" (true/false). for instance if "node" is a OR * formula we want to make it evaluate to true, we'd like one of the * children to be true. this is done recursively. */ - Trace("jh-findSplitterRec") + Trace("decision::jh") << "findSplitterRec(" << node << ", " << desiredVal << ", .. )" << std::endl; @@ -122,13 +254,9 @@ bool JustificationHeuristic::findSplitterRec(TNode node, node = node[0]; } - if(Debug.isOn("decision")) { - if(checkJustified(node)) - Debug("decision") << " justified, returning" << std::endl; - } - /* Base case */ if (checkJustified(node)) { + Debug("decision::jh") << " justified, returning" << std::endl; return false; } @@ -141,7 +269,6 @@ bool JustificationHeuristic::findSplitterRec(TNode node, Debug("decision") << "no sat literal for this node" << std::endl; } } - //Assert(litPresent); -- fails #endif // Get value of sat literal for the node, if there is one @@ -151,11 +278,6 @@ bool JustificationHeuristic::findSplitterRec(TNode node, Assert(desiredVal != SAT_VALUE_UNKNOWN, "expected known value"); /* Good luck, hope you can get what you want */ - // if(not (litVal == desiredVal || litVal == SAT_VALUE_UNKNOWN)) { - // Warning() << "WARNING: IMPORTANT: Please look into this. Sat solver is asking for a decision" << std::endl - // << "when the assertion we are trying to justify is already unsat. OR there is a bug" << std::endl; - // GiveUpException(); - // } Assert(litVal == desiredVal || litVal == SAT_VALUE_UNKNOWN, "invariant violated"); @@ -164,247 +286,192 @@ bool JustificationHeuristic::findSplitterRec(TNode node, theory::TheoryId tId = theory::kindToTheoryId(k); /* Some debugging stuff */ - Debug("jh-findSplitterRec") << "kind = " << k << std::endl; - Debug("jh-findSplitterRec") << "theoryId = " << tId << std::endl; - Debug("jh-findSplitterRec") << "node = " << node << std::endl; - Debug("jh-findSplitterRec") << "litVal = " << litVal << std::endl; + Debug("decision::jh") << "kind = " << k << std::endl + << "theoryId = " << tId << std::endl + << "node = " << node << std::endl + << "litVal = " << litVal << std::endl; /** - * If not in theory of booleans, and not a "boolean" EQUAL (IFF), - * then check if this is something to split-on. + * If not in theory of booleans, check if this is something to split-on. */ - if(tId != theory::THEORY_BOOL - // && !(k == kind::EQUAL && node[0].getType().isBoolean()) - ) { - - // if node has embedded ites -- which currently happens iff it got - // replaced during ite removal -- then try to resolve that first - const IteList& l = getITEs(node); - Trace("jh-ite") << " ite size = " << l.size() << std::endl; - /*d_visited.insert(node);*/ - for(IteList::const_iterator i = l.begin(); i != l.end(); ++i) { - if(d_visited.find(i->first) == d_visited.end()) { - d_visited.insert(i->first); - Debug("jh-ite") << "jh-ite: adding visited " << i->first << std::endl; - if(findSplitterRec(i->second, SAT_VALUE_TRUE, litDecision)) - return true; - Debug("jh-ite") << "jh-ite: removing visited " << i->first << std::endl; - d_visited.erase(i->first); - } else { - Debug("jh-ite") << "jh-ite: already visited " << i->first << std::endl; - } - } + if(tId != theory::THEORY_BOOL) { + + // if node has embedded ites, resolve that first + if(handleEmbeddedITEs(node)) + return true; if(litVal != SAT_VALUE_UNKNOWN) { setJustified(node); return false; - } else { - Assert(d_decisionEngine->hasSatLiteral(node)); - /* if(not d_decisionEngine->hasSatLiteral(node)) - throw GiveUpException(); */ + } + else { Assert(d_decisionEngine->hasSatLiteral(node)); - SatVariable v = d_decisionEngine->getSatLiteral(node).getSatVariable(); - *litDecision = SatLiteral(v, desiredVal != SAT_VALUE_TRUE ); - Trace("decision") << "decision " << *litDecision << std::endl; - Trace("decision") << "Found something to split. Glad to be able to serve you." << std::endl; + SatVariable v = + d_decisionEngine->getSatLiteral(node).getSatVariable(); + d_curDecision = SatLiteral(v, desiredVal != SAT_VALUE_TRUE ); return true; } } - SatValue valHard = SAT_VALUE_FALSE; + bool ret = false; switch (k) { case kind::CONST_BOOLEAN: Assert(node.getConst<bool>() == false || desiredVal == SAT_VALUE_TRUE); - Assert(node.getConst<bool>() == true || desiredVal == SAT_VALUE_FALSE); - setJustified(node); - return false; + Assert(node.getConst<bool>() == true || desiredVal == SAT_VALUE_FALSE); + break; case kind::AND: - valHard = SAT_VALUE_TRUE; + if (desiredVal == SAT_VALUE_FALSE) + ret = handleAndOrEasy(node, desiredVal); + else + ret = handleAndOrHard(node, desiredVal); + break; case kind::OR: - if (desiredVal == valHard) { - int n = node.getNumChildren(); - for(int i = 0; i < n; ++i) { - if (findSplitterRec(node[i], valHard, litDecision)) { - return true; - } - } - Assert(litPresent == false || litVal == valHard, - "Output should be justified"); - setJustified(node); - return false; - } - else { - SatValue valEasy = invertValue(valHard); - int n = node.getNumChildren(); - for(int i = 0; i < n; ++i) { - Debug("jh-findSplitterRec") << " node[i] = " << node[i] << " " - << tryGetSatValue(node[i]) << std::endl; - if ( tryGetSatValue(node[i]) != valHard) { - Debug("jh-findSplitterRec") << "hi"<< std::endl; - if (findSplitterRec(node[i], valEasy, litDecision)) { - return true; - } - Assert(litPresent == false || litVal == valEasy, "Output should be justified"); - setJustified(node); - return false; - } - } - if(Debug.isOn("jh-findSplitterRec")) { - Debug("jh-findSplitterRec") << " * ** " << std::endl; - Debug("jh-findSplitterRec") << node.getKind() << " " - << node << std::endl; - for(unsigned i = 0; i < node.getNumChildren(); ++i) - Debug("jh-findSplitterRec") << "child: " << tryGetSatValue(node[i]) - << std::endl; - Debug("jh-findSplitterRec") << "node: " << tryGetSatValue(node) - << std::endl; - } - Assert(false, "No controlling input found (2)"); - } + if (desiredVal == SAT_VALUE_FALSE) + ret = handleAndOrHard(node, desiredVal); + else + ret = handleAndOrEasy(node, desiredVal); break; case kind::IMPLIES: - //throw GiveUpException(); - Assert(node.getNumChildren() == 2, "Expected 2 fanins"); - if (desiredVal == SAT_VALUE_FALSE) { - if (findSplitterRec(node[0], SAT_VALUE_TRUE, litDecision)) { - return true; - } - if (findSplitterRec(node[1], SAT_VALUE_FALSE, litDecision)) { - return true; - } - Assert(litPresent == false || litVal == SAT_VALUE_FALSE, - "Output should be justified"); - setJustified(node); - return false; - } - else { - if (tryGetSatValue(node[0]) != SAT_VALUE_TRUE) { - if (findSplitterRec(node[0], SAT_VALUE_FALSE, litDecision)) { - return true; - } - Assert(litPresent == false || litVal == SAT_VALUE_TRUE, - "Output should be justified"); - setJustified(node); - return false; - } - if (tryGetSatValue(node[1]) != SAT_VALUE_FALSE) { - if (findSplitterRec(node[1], SAT_VALUE_TRUE, litDecision)) { - return true; - } - Assert(litPresent == false || litVal == SAT_VALUE_TRUE, - "Output should be justified"); - setJustified(node); - return false; - } - Assert(false, "No controlling input found (3)"); - } - break; - - case kind::IFF: - //throw GiveUpException(); - { - SatValue val = tryGetSatValue(node[0]); - if (val != SAT_VALUE_UNKNOWN) { - if (findSplitterRec(node[0], val, litDecision)) { - return true; - } - if (desiredVal == SAT_VALUE_FALSE) val = invertValue(val); + if (desiredVal == SAT_VALUE_FALSE) + ret = handleBinaryHard(node[0], SAT_VALUE_TRUE, + node[1], SAT_VALUE_FALSE); - if (findSplitterRec(node[1], val, litDecision)) { - return true; - } - Assert(litPresent == false || litVal == desiredVal, - "Output should be justified"); - setJustified(node); - return false; - } - else { - val = tryGetSatValue(node[1]); - if (val == SAT_VALUE_UNKNOWN) val = SAT_VALUE_FALSE; - if (desiredVal == SAT_VALUE_FALSE) val = invertValue(val); - if (findSplitterRec(node[0], val, litDecision)) { - return true; - } - Assert(false, "Unable to find controlling input (4)"); - } + else + ret = handleBinaryEasy(node[0], SAT_VALUE_FALSE, + node[1], SAT_VALUE_TRUE); break; - } - - case kind::XOR: - //throw GiveUpException(); - { - SatValue val = tryGetSatValue(node[0]); - if (val != SAT_VALUE_UNKNOWN) { - if (findSplitterRec(node[0], val, litDecision)) { - return true; - } - if (desiredVal == SAT_VALUE_TRUE) val = invertValue(val); - if (findSplitterRec(node[1], val, litDecision)) { - return true; - } - Assert(litPresent == false || litVal == desiredVal, - "Output should be justified"); - setJustified(node); - return false; - } - else { - SatValue val = tryGetSatValue(node[1]); - if (val == SAT_VALUE_UNKNOWN) val = SAT_VALUE_FALSE; - if (desiredVal == SAT_VALUE_TRUE) val = invertValue(val); - if (findSplitterRec(node[0], val, litDecision)) { - return true; - } - Assert(false, "Unable to find controlling input (5)"); - } + case kind::XOR: + case kind::IFF: { + SatValue desiredVal1 = tryGetSatValue(node[0]); + SatValue desiredVal2 = tryGetSatValue(node[1]); + computeXorIffDesiredValues(k, desiredVal, desiredVal1, desiredVal2); + ret = handleBinaryHard(node[0], desiredVal1, + node[1], desiredVal2); break; } - case kind::ITE: { - //[0]: if, [1]: then, [2]: else - SatValue ifVal = tryGetSatValue(node[0]); - if (ifVal == SAT_VALUE_UNKNOWN) { - - // are we better off trying false? if not, try true - SatValue ifDesiredVal = - (tryGetSatValue(node[2]) == desiredVal || - tryGetSatValue(node[1]) == invertValue(desiredVal)) - ? SAT_VALUE_FALSE : SAT_VALUE_TRUE; - - if(findSplitterRec(node[0], ifDesiredVal, litDecision)) { - return true; - } - Assert(false, "No controlling input found (6)"); - } else { - - // Try to justify 'if' - if (findSplitterRec(node[0], ifVal, litDecision)) { - return true; - } - - // If that was successful, we need to go into only one of 'then' - // or 'else' - int ch = (ifVal == SAT_VALUE_TRUE) ? 1 : 2; - int chVal = tryGetSatValue(node[ch]); - if( (chVal == SAT_VALUE_UNKNOWN || chVal == desiredVal) - && findSplitterRec(node[ch], desiredVal, litDecision) ) { - return true; - } - } - Assert(litPresent == false || litVal == desiredVal, - "Output should be justified"); - setJustified(node); - return false; - } + case kind::ITE: + ret = handleITE(node, desiredVal); + break; default: Assert(false, "Unexpected Boolean operator"); break; }//end of switch(k) - Unreachable(); + if(ret == false) { + Assert(litPresent == false || litVal == desiredVal, + "Output should be justified"); + setJustified(node); + } + return ret; }/* findRecSplit method */ + +bool JustificationHeuristic::handleAndOrEasy(TNode node, + SatValue desiredVal) +{ + Assert( (node.getKind() == kind::AND and desiredVal == SAT_VALUE_FALSE) or + (node.getKind() == kind::OR and desiredVal == SAT_VALUE_TRUE) ); + + int numChildren = node.getNumChildren(); + SatValue desiredValInverted = invertValue(desiredVal); + for(int i = 0; i < numChildren; ++i) + if ( tryGetSatValue(node[i]) != desiredValInverted ) + return findSplitterRec(node[i], desiredVal); + Assert(false, "handleAndOrEasy: No controlling input found"); + return false; +} + +bool JustificationHeuristic::handleAndOrHard(TNode node, + SatValue desiredVal) { + Assert( (node.getKind() == kind::AND and desiredVal == SAT_VALUE_TRUE) or + (node.getKind() == kind::OR and desiredVal == SAT_VALUE_FALSE) ); + + int numChildren = node.getNumChildren(); + for(int i = 0; i < numChildren; ++i) + if (findSplitterRec(node[i], desiredVal)) + return true; + return false; +} + +bool JustificationHeuristic::handleBinaryEasy(TNode node1, + SatValue desiredVal1, + TNode node2, + SatValue desiredVal2) +{ + if ( tryGetSatValue(node1) != invertValue(desiredVal1) ) + return findSplitterRec(node1, desiredVal1); + if ( tryGetSatValue(node2) != invertValue(desiredVal2) ) + return findSplitterRec(node2, desiredVal2); + Assert(false, "handleBinaryEasy: No controlling input found"); + return false; +} + +bool JustificationHeuristic::handleBinaryHard(TNode node1, + SatValue desiredVal1, + TNode node2, + SatValue desiredVal2) +{ + if( findSplitterRec(node1, desiredVal1) ) + return true; + return findSplitterRec(node2, desiredVal2); +} + +bool JustificationHeuristic::handleITE(TNode node, SatValue desiredVal) +{ + Debug("decision::jh") << " handleITE (" << node << ", " + << desiredVal << std::endl; + + //[0]: if, [1]: then, [2]: else + SatValue ifVal = tryGetSatValue(node[0]); + if (ifVal == SAT_VALUE_UNKNOWN) { + + // are we better off trying false? if not, try true [CHOICE] + SatValue ifDesiredVal = + (tryGetSatValue(node[2]) == desiredVal || + tryGetSatValue(node[1]) == invertValue(desiredVal)) + ? SAT_VALUE_FALSE : SAT_VALUE_TRUE; + + if(findSplitterRec(node[0], ifDesiredVal)) return true; + + Assert(false, "No controlling input found (6)"); + } else { + // Try to justify 'if' + if(findSplitterRec(node[0], ifVal)) return true; + + // If that was successful, we need to go into only one of 'then' + // or 'else' + int ch = (ifVal == SAT_VALUE_TRUE) ? 1 : 2; + + // STALE code: remove after tests or mar 2013, whichever earlier + // int chVal = tryGetSatValue(node[ch]); + // Assert(chVal == SAT_VALUE_UNKNOWN || chVal == desiredVal); + // end STALE code: remove + + if( findSplitterRec(node[ch], desiredVal) ) { + return true; + } + }// else (...ifVal...) + return false; +} + +bool JustificationHeuristic::handleEmbeddedITEs(TNode node) +{ + const IteList& l = getITEs(node); + Trace("decision::jh::ite") << " ite size = " << l.size() << std::endl; + + for(IteList::const_iterator i = l.begin(); i != l.end(); ++i) { + if(d_visited.find(i->first) == d_visited.end()) { + d_visited.insert(i->first); + if(findSplitterRec(i->second, SAT_VALUE_TRUE)) + return true; + d_visited.erase(i->first); + } + } + return false; +} diff --git a/src/decision/justification_heuristic.h b/src/decision/justification_heuristic.h index ea67fee29..91c21d981 100644 --- a/src/decision/justification_heuristic.h +++ b/src/decision/justification_heuristic.h @@ -36,13 +36,6 @@ namespace CVC4 { namespace decision { -class GiveUpException : public Exception { -public: - GiveUpException() : - Exception("justification heuristic: giving up") { - } -};/* class GiveUpException */ - class JustificationHeuristic : public ITEDecisionStrategy { typedef std::vector<pair<TNode,TNode> > IteList; typedef hash_map<TNode,IteList,TNodeHashFunction> IteCache; @@ -84,130 +77,29 @@ class JustificationHeuristic : public ITEDecisionStrategy { * function */ hash_set<TNode,TNodeHashFunction> d_visitedComputeITE; + + /** current decision for the recursive call */ + SatLiteral d_curDecision; public: JustificationHeuristic(CVC4::DecisionEngine* de, context::Context *uc, - context::Context *c): - ITEDecisionStrategy(de, c), - d_justified(c), - d_prvsIndex(c, 0), - d_helfulness("decision::jh::helpfulness", 0), - d_giveup("decision::jh::giveup", 0), - d_timestat("decision::jh::time"), - d_assertions(uc), - d_iteAssertions(uc) { - StatisticsRegistry::registerStat(&d_helfulness); - StatisticsRegistry::registerStat(&d_giveup); - StatisticsRegistry::registerStat(&d_timestat); - Trace("decision") << "Justification heuristic enabled" << std::endl; - } - ~JustificationHeuristic() { - StatisticsRegistry::unregisterStat(&d_helfulness); - StatisticsRegistry::unregisterStat(&d_giveup); - StatisticsRegistry::unregisterStat(&d_timestat); - } - prop::SatLiteral getNext(bool &stopSearch) { - Trace("decision") << "JustificationHeuristic::getNext()" << std::endl; - TimerStat::CodeTimer codeTimer(d_timestat); - - d_visited.clear(); - - if(Trace.isOn("justified")) { - for(JustifiedSet::key_iterator i = d_justified.key_begin(); - i != d_justified.key_end(); ++i) { - TNode n = *i; - SatLiteral l = d_decisionEngine->hasSatLiteral(n) ? - d_decisionEngine->getSatLiteral(n) : -1; - SatValue v = tryGetSatValue(n); - Trace("justified") <<"{ "<<l<<"}" << n <<": "<<v << std::endl; - } - } - - for(unsigned i = d_prvsIndex; i < d_assertions.size(); ++i) { - Debug("decision") << "---" << std::endl << d_assertions[i] << std::endl; - - // Sanity check: if it was false, aren't we inconsistent? - Assert( tryGetSatValue(d_assertions[i]) != SAT_VALUE_FALSE); - - SatValue desiredVal = SAT_VALUE_TRUE; - SatLiteral litDecision; - try { - litDecision = findSplitter(d_assertions[i], desiredVal); - }catch(GiveUpException &e) { - return prop::undefSatLiteral; - } - - if(litDecision != undefSatLiteral) - return litDecision; - } - - Trace("decision") << "jh: Nothing to split on " << std::endl; - -#if defined CVC4_DEBUG - bool alljustified = true; - for(unsigned i = 0 ; i < d_assertions.size() && alljustified ; ++i) { - TNode curass = d_assertions[i]; - while(curass.getKind() == kind::NOT) - curass = curass[0]; - alljustified &= checkJustified(curass); - - if(Debug.isOn("decision")) { - if(!checkJustified(curass)) - Debug("decision") << "****** Not justified [i="<<i<<"]: " - << d_assertions[i] << std::endl; - } - } - Assert(alljustified); -#endif - - // SAT solver can stop... - stopSearch = true; - d_decisionEngine->setResult(SAT_VALUE_TRUE); - return prop::undefSatLiteral; - } + context::Context *c); + + ~JustificationHeuristic(); + + prop::SatLiteral getNext(bool &stopSearch); void addAssertions(const std::vector<Node> &assertions, unsigned assertionsEnd, - IteSkolemMap iteSkolemMap) { - Trace("decision") - << "JustificationHeuristic::addAssertions()" - << " size = " << assertions.size() - << " assertionsEnd = " << assertionsEnd - << std::endl; - - // Save the 'real' assertions locally - for(unsigned i = 0; i < assertionsEnd; ++i) - d_assertions.push_back(assertions[i]); - - // Save mapping between ite skolems and ite assertions - for(IteSkolemMap::iterator i = iteSkolemMap.begin(); - i != iteSkolemMap.end(); ++i) { - Trace("jh-ite") << " jh-ite: " << (i->first) << " maps to " - << assertions[(i->second)] << std::endl; - Assert(i->second >= assertionsEnd && i->second < assertions.size()); - d_iteAssertions[i->first] = assertions[i->second]; - } - } + IteSkolemMap iteSkolemMap); private: - SatLiteral findSplitter(TNode node, SatValue desiredVal) - { - bool ret; - SatLiteral litDecision; - ret = findSplitterRec(node, desiredVal, &litDecision); - if(ret == true) { - Debug("decision") << "Yippee!!" << std::endl; - ++d_helfulness; - return litDecision; - } else { - return undefSatLiteral; - } - } + SatLiteral findSplitter(TNode node, SatValue desiredVal); /** * Do all the hard work. */ - bool findSplitterRec(TNode node, SatValue value, SatLiteral* litDecision); + bool findSplitterRec(TNode node, SatValue value); /* Helper functions */ void setJustified(TNode); @@ -222,6 +114,15 @@ private: /* Compute all term-ITEs in a node recursively */ void computeITEs(TNode n, IteList &l); + + bool handleAndOrEasy(TNode node, SatValue desiredVal); + bool handleAndOrHard(TNode node, SatValue desiredVal); + bool handleBinaryEasy(TNode node1, SatValue desiredVal1, + TNode node2, SatValue desiredVal2); + bool handleBinaryHard(TNode node1, SatValue desiredVal1, + TNode node2, SatValue desiredVal2); + bool handleITE(TNode node, SatValue desiredVal); + bool handleEmbeddedITEs(TNode node); };/* class JustificationHeuristic */ }/* namespace decision */ diff --git a/src/expr/command.cpp b/src/expr/command.cpp index fa2a8d1f2..9edc77e39 100644 --- a/src/expr/command.cpp +++ b/src/expr/command.cpp @@ -703,8 +703,12 @@ Expr SimplifyCommand::getTerm() const throw() { } void SimplifyCommand::invoke(SmtEngine* smtEngine) throw() { - d_result = smtEngine->simplify(d_term); - d_commandStatus = CommandSuccess::instance(); + try { + d_result = smtEngine->simplify(d_term); + d_commandStatus = CommandSuccess::instance(); + } catch(exception& e) { + d_commandStatus = new CommandFailure(e.what()); + } } Expr SimplifyCommand::getResult() const throw() { diff --git a/src/expr/command.h b/src/expr/command.h index 342aec5ff..9877044fb 100644 --- a/src/expr/command.h +++ b/src/expr/command.h @@ -401,7 +401,7 @@ public: /** * The command when an attribute is set by a user. In SMT-LIBv2 this is done - * via the syntax (! expr :atrr) + * via the syntax (! expr :attr) */ class CVC4_PUBLIC SetUserAttributeCommand : public Command { protected: diff --git a/src/expr/expr_template.h b/src/expr/expr_template.h index b353ec5dc..f5df63f8c 100644 --- a/src/expr/expr_template.h +++ b/src/expr/expr_template.h @@ -654,6 +654,11 @@ public: l = options::defaultExprDepth(); } if(l == 0) { + // if called from outside the library, we may not have options + // available to us at this point (or perhaps the output language + // is not set in Options). Default to something reasonable, but + // don't set "l" since that would make it "sticky" for this + // stream. return s_defaultPrintDepth; } } @@ -797,7 +802,17 @@ public: if(l == 0) { // set the default dag setting on this ostream // (offset by one to detect whether default has been set yet) - l = s_defaultDag + 1; + if(&Options::current() != NULL) { + l = options::defaultDagThresh() + 1; + } + if(l == 0) { + // if called from outside the library, we may not have options + // available to us at this point (or perhaps the output language + // is not set in Options). Default to something reasonable, but + // don't set "l" since that would make it "sticky" for this + // stream. + return s_defaultDag + 1; + } } return static_cast<size_t>(l - 1); } diff --git a/src/expr/mkexpr b/src/expr/mkexpr index 5134d561e..ca89dfc91 100755 --- a/src/expr/mkexpr +++ b/src/expr/mkexpr @@ -2,7 +2,7 @@ # # mkexpr # Morgan Deters <mdeters@cs.nyu.edu> for CVC4 -# Copyright (c) 2010-2012 The CVC4 Project +# Copyright (c) 2010-2013 The CVC4 Project # # The purpose of this script is to create {expr,expr_manager}.{h,cpp} # from template files and a list of theory kinds. Basically it just @@ -15,7 +15,7 @@ # Output is to standard out. # -copyright=2010-2012 +copyright=2010-2013 filename=`basename "$1" | sed 's,_template,,'` @@ -23,7 +23,8 @@ cat <<EOF /********************* */ /** $filename ** - ** Copyright $copyright The AcSys Group, New York University, and as below. + ** Copyright $copyright New York University and The University of Iowa, + ** and as below. ** ** This file automatically generated by: ** diff --git a/src/expr/mkkind b/src/expr/mkkind index 786d6187b..f8432466d 100755 --- a/src/expr/mkkind +++ b/src/expr/mkkind @@ -2,7 +2,7 @@ # # mkkind # Morgan Deters <mdeters@cs.nyu.edu> for CVC4 -# Copyright (c) 2010-2012 The CVC4 Project +# Copyright (c) 2010-2013 The CVC4 Project # # The purpose of this script is to create kind.h (and also # type_properties.h) from a template and a list of theory kinds. @@ -14,7 +14,7 @@ # Output is to standard out. # -copyright=2010-2012 +copyright=2010-2013 filename=`basename "$1" | sed 's,_template,,'` @@ -22,7 +22,8 @@ cat <<EOF /********************* */ /** $filename ** - ** Copyright $copyright The AcSys Group, New York University, and as below. + ** Copyright $copyright New York University and The University of Iowa, + ** and as below. ** ** This header file automatically generated by: ** diff --git a/src/expr/mkmetakind b/src/expr/mkmetakind index 47ffc77f9..160a74eac 100755 --- a/src/expr/mkmetakind +++ b/src/expr/mkmetakind @@ -2,7 +2,7 @@ # # mkmetakind # Morgan Deters <mdeters@cs.nyu.edu> for CVC4 -# Copyright (c) 2010-2012 The CVC4 Project +# Copyright (c) 2010-2013 The CVC4 Project # # The purpose of this script is to create metakind.h from a template # and a list of theory kinds. @@ -17,13 +17,14 @@ # Output is to standard out. # -copyright=2010-2012 +copyright=2010-2013 cat <<EOF /********************* */ /** metakind.h ** - ** Copyright $copyright The AcSys Group, New York University, and as below. + ** Copyright $copyright New York University and The University of Iowa, + ** and as below. ** ** This header file automatically generated by: ** diff --git a/src/expr/node_builder.h b/src/expr/node_builder.h index f6aa1920d..5f813dbe8 100644 --- a/src/expr/node_builder.h +++ b/src/expr/node_builder.h @@ -1,11 +1,11 @@ /********************* */ /*! \file node_builder.h ** \verbatim - ** Original author: mdeters - ** Major contributors: dejan - ** Minor contributors (to current version): taking, cconway - ** This file is part of the CVC4 prototype. - ** Copyright (c) 2009-2012 New York University and The University of Iowa + ** Original author: Dejan Jovanović <dejan.jovanovic@gmail.com> + ** Major contributors: Morgan Deters <mdeters@cs.nyu.edu> + ** Minor contributors (to current version): Tim King <taking@cs.nyu.edu>, Christopher L. Conway <christopherleeconway@gmail.com> + ** This file is part of the CVC4 project. + ** Copyright (c) 2009-2013 New York University and The University of Iowa ** See the file COPYING in the top-level source directory for licensing ** information.\endverbatim ** @@ -277,7 +277,9 @@ class NodeBuilder { * double-decremented later (on destruction/clear). */ inline void realloc() { - realloc(d_nvMaxChildren * 2); + size_t newSize = 2 * size_t(d_nvMaxChildren); + size_t hardLimit = (1lu << __CVC4__EXPR__NODE_VALUE__NBITS__NCHILDREN) - 1; + realloc(EXPECT_FALSE( newSize > hardLimit ) ? hardLimit : newSize); } /** @@ -662,6 +664,7 @@ public: expr::NodeValue* nv = n.d_nv; nv->inc(); d_nv->d_children[d_nv->d_nchildren++] = nv; + Assert(d_nv->d_nchildren <= d_nvMaxChildren); return *this; } @@ -674,6 +677,7 @@ public: expr::NodeValue* nv = typeNode.d_nv; nv->inc(); d_nv->d_children[d_nv->d_nchildren++] = nv; + Assert(d_nv->d_nchildren <= d_nvMaxChildren); return *this; } @@ -771,6 +775,9 @@ template <unsigned nchild_thresh> void NodeBuilder<nchild_thresh>::realloc(size_t toSize) { Assert( toSize > d_nvMaxChildren, "attempt to realloc() a NodeBuilder to a smaller/equal size!" ); + Assert( toSize < (1lu << __CVC4__EXPR__NODE_VALUE__NBITS__NCHILDREN), + "attempt to realloc() a NodeBuilder to size %u (beyond hard limit of %u)", + toSize, (1lu << __CVC4__EXPR__NODE_VALUE__NBITS__NCHILDREN) - 1 ); if(EXPECT_FALSE( nvIsAllocated() )) { // Ensure d_nv is not modified on allocation failure @@ -783,6 +790,7 @@ void NodeBuilder<nchild_thresh>::realloc(size_t toSize) { throw std::bad_alloc(); } d_nvMaxChildren = toSize; + Assert(d_nvMaxChildren == toSize);//overflow check // Here, the copy (between two heap-allocated buffers) has already // been done for us by the std::realloc(). d_nv = newBlock; @@ -795,6 +803,7 @@ void NodeBuilder<nchild_thresh>::realloc(size_t toSize) { throw std::bad_alloc(); } d_nvMaxChildren = toSize; + Assert(d_nvMaxChildren == toSize);//overflow check d_nv = newBlock; d_nv->d_id = d_inlineNv.d_id; @@ -1276,10 +1285,14 @@ void NodeBuilder<nchild_thresh>::internalCopy(const NodeBuilder<N>& nb) { return; } + bool realloced CVC4_UNUSED = false; if(nb.d_nvMaxChildren > d_nvMaxChildren) { + realloced = true; realloc(nb.d_nvMaxChildren); } + Assert(nb.d_nvMaxChildren <= d_nvMaxChildren); + Assert(nb.d_nv->nv_end() - nb.d_nv->nv_begin() <= d_nvMaxChildren, "realloced:%s, d_nvMax:%u, size:%u, nc:%u", realloced ? "true" : "false", d_nvMaxChildren, nb.d_nv->nv_end() - nb.d_nv->nv_begin(), nb.d_nv->getNumChildren()); std::copy(nb.d_nv->nv_begin(), nb.d_nv->nv_end(), d_nv->nv_begin()); diff --git a/src/expr/node_manager.cpp b/src/expr/node_manager.cpp index 59d23c6ea..a3c968158 100644 --- a/src/expr/node_manager.cpp +++ b/src/expr/node_manager.cpp @@ -412,6 +412,7 @@ TypeNode NodeManager::getDatatypeForTupleRecord(TypeNode t) { dt.addConstructor(c); dtt = TypeNode::fromType(toExprManager()->mkDatatypeType(dt)); Debug("tuprec") << "REWROTE " << t << " to " << dtt << std::endl; + dtt.setAttribute(DatatypeTupleAttr(), t); } else { const Record& rec = t.getRecord(); Datatype dt("__cvc4_record"); @@ -422,8 +423,8 @@ TypeNode NodeManager::getDatatypeForTupleRecord(TypeNode t) { dt.addConstructor(c); dtt = TypeNode::fromType(toExprManager()->mkDatatypeType(dt)); Debug("tuprec") << "REWROTE " << t << " to " << dtt << std::endl; + dtt.setAttribute(DatatypeRecordAttr(), t); } - dtt.setAttribute(DatatypeRecordAttr(), t); } else { Debug("tuprec") << "REUSING cached " << t << ": " << dtt << std::endl; } diff --git a/src/expr/options b/src/expr/options index cd59e4875..223189d1b 100644 --- a/src/expr/options +++ b/src/expr/options @@ -5,9 +5,9 @@ module EXPR "expr/options.h" Expression package -option defaultExprDepth --default-expr-depth=N int :predicate CVC4::expr::setDefaultExprDepth :predicate-include "expr/options_handlers.h" +option defaultExprDepth --default-expr-depth=N int :default 0 :predicate CVC4::expr::setDefaultExprDepth :predicate-include "expr/options_handlers.h" print exprs to depth N (0 == default, -1 == no limit) -option - default-dag-thresh --default-dag-thresh=N argument :handler CVC4::expr::setDefaultDagThresh :handler-include "expr/options_handlers.h" +option defaultDagThresh default-dag-thresh --default-dag-thresh=N int :default 1 :predicate CVC4::expr::setDefaultDagThresh :predicate-include "expr/options_handlers.h" dagify common subexprs appearing > N times (1 == default, 0 == don't dagify) option - --print-expr-types void :handler CVC4::expr::setPrintExprTypes :handler-include "expr/options_handlers.h" print types with variables when printing exprs diff --git a/src/expr/options_handlers.h b/src/expr/options_handlers.h index 7a1d73c36..57c4d1aa4 100644 --- a/src/expr/options_handlers.h +++ b/src/expr/options_handlers.h @@ -39,8 +39,7 @@ inline void setDefaultExprDepth(std::string option, int depth, SmtEngine* smt) { // intentionally exclude Dump stream from this list } -inline void setDefaultDagThresh(std::string option, std::string optarg, SmtEngine* smt) { - int dag = atoi(optarg.c_str()); +inline void setDefaultDagThresh(std::string option, int dag, SmtEngine* smt) { if(dag < 0) { throw OptionException("--default-dag-thresh requires a nonnegative argument."); } diff --git a/src/expr/type.i b/src/expr/type.i index 870cb228c..e227cca23 100644 --- a/src/expr/type.i +++ b/src/expr/type.i @@ -14,24 +14,6 @@ %rename(greater) CVC4::Type::operator>(const Type&) const; %rename(greaterEqual) CVC4::Type::operator>=(const Type&) const; -%rename(toBooleanType) CVC4::Type::operator BooleanType() const; -%rename(toIntegerType) CVC4::Type::operator IntegerType() const; -%rename(toRealType) CVC4::Type::operator RealType() const; -%rename(toStringType) CVC4::Type::operator StringType() const; -%rename(toBitVectorType) CVC4::Type::operator BitVectorType() const; -%rename(toFunctionType) CVC4::Type::operator FunctionType() const; -%rename(toTupleType) CVC4::Type::operator TupleType() const; -%rename(toSExprType) CVC4::Type::operator SExprType() const; -%rename(toArrayType) CVC4::Type::operator ArrayType() const; -%rename(toDatatypeType) CVC4::Type::operator DatatypeType() const; -%rename(toConstructorType) CVC4::Type::operator ConstructorType() const; -%rename(toSelectorType) CVC4::Type::operator SelectorType() const; -%rename(toTesterType) CVC4::Type::operator TesterType() const; -%rename(toSortType) CVC4::Type::operator SortType() const; -%rename(toSortConstructorType) CVC4::Type::operator SortConstructorType() const; -%rename(toPredicateSubtype) CVC4::Type::operator PredicateSubtype() const; -%rename(toSubrangeType) CVC4::Type::operator SubrangeType() const; - namespace CVC4 { namespace expr { %ignore exportTypeInternal; diff --git a/src/main/command_executor.cpp b/src/main/command_executor.cpp index 14625f1d8..6a4e18b5b 100644 --- a/src/main/command_executor.cpp +++ b/src/main/command_executor.cpp @@ -48,7 +48,7 @@ bool CommandExecutor::doCommand(Command* cmd) return status; } else { - if(d_options[options::verbosity] > 0) { + if(d_options[options::verbosity] > 2) { *d_options[options::out] << "Invoking: " << *cmd << std::endl; } @@ -59,7 +59,7 @@ bool CommandExecutor::doCommand(Command* cmd) bool CommandExecutor::doCommandSingleton(Command *cmd) { bool status = true; - if(d_options[options::verbosity] >= 0) { + if(d_options[options::verbosity] >= -1) { status = smtEngineInvoke(&d_smtEngine, cmd, d_options[options::out]); } else { status = smtEngineInvoke(&d_smtEngine, cmd, NULL); diff --git a/src/main/driver_unified.cpp b/src/main/driver_unified.cpp index b429ad0c2..9fa40d3ab 100644 --- a/src/main/driver_unified.cpp +++ b/src/main/driver_unified.cpp @@ -26,6 +26,7 @@ #include "cvc4autoconfig.h" #include "main/main.h" #include "main/interactive_shell.h" +#include "main/options.h" #include "parser/parser.h" #include "parser/parser_builder.h" #include "parser/parser_exception.h" @@ -43,6 +44,7 @@ #include "util/output.h" #include "util/dump.h" #include "util/result.h" +#include "util/statistics_registry.h" using namespace std; using namespace CVC4; @@ -63,6 +65,9 @@ namespace CVC4 { /** A pointer to the CommandExecutor (the signal handlers need it) */ CVC4::main::CommandExecutor* pExecutor = NULL; + /** A pointer to the totalTime driver stat (the signal handlers need it) */ + CVC4::TimerStat* pTotalTime = NULL; + }/* CVC4::main namespace */ }/* CVC4 namespace */ @@ -84,8 +89,8 @@ void printUsage(Options& opts, bool full) { int runCvc4(int argc, char* argv[], Options& opts) { // Timer statistic - TimerStat s_totalTime("totalTime"); - s_totalTime.start(); + pTotalTime = new TimerStat("totalTime"); + pTotalTime->start(); // For the signal handlers' benefit pOptions = &opts; @@ -183,17 +188,22 @@ int runCvc4(int argc, char* argv[], Options& opts) { DumpChannel.getStream() << Expr::setlanguage(opts[options::outputLanguage]); // Create the expression manager using appropriate options + ExprManager* exprMgr; # ifndef PORTFOLIO_BUILD - ExprManager* exprMgr = new ExprManager(opts); -# else - vector<Options> threadOpts = parseThreadSpecificOptions(opts); - ExprManager* exprMgr = new ExprManager(threadOpts[0]); -# endif - -# ifndef PORTFOLIO_BUILD + exprMgr = new ExprManager(opts); pExecutor = new CommandExecutor(*exprMgr, opts); # else - pExecutor = new CommandExecutorPortfolio(*exprMgr, opts, threadOpts); + vector<Options> threadOpts = parseThreadSpecificOptions(opts); + if(opts[options::incrementalSolving] && !opts[options::incrementalParallel]) { + Notice() << "Notice: In --incremental mode, using the sequential solver unless forced by...\n" + << "Notice: ...the experimental --incremental-parallel option.\n"; + exprMgr = new ExprManager(opts); + pExecutor = new CommandExecutor(*exprMgr, opts); + } + else { + exprMgr = new ExprManager(threadOpts[0]); + pExecutor = new CommandExecutorPortfolio(*exprMgr, opts, threadOpts); + } # endif Parser* replayParser = NULL; @@ -216,7 +226,7 @@ int runCvc4(int argc, char* argv[], Options& opts) { int returnValue = 0; { // Timer statistic - RegisterStatistic statTotalTime(&pExecutor->getStatisticsRegistry(), &s_totalTime); + RegisterStatistic statTotalTime(&pExecutor->getStatisticsRegistry(), pTotalTime); // Filename statistics ReferenceStat< const char* > s_statFilename("filename", filename); @@ -229,7 +239,9 @@ int runCvc4(int argc, char* argv[], Options& opts) { InteractiveShell shell(*exprMgr, opts); Message() << Configuration::getPackageName() << " " << Configuration::getVersionString(); - if(Configuration::isSubversionBuild()) { + if(Configuration::isGitBuild()) { + Message() << " [" << Configuration::getGitId() << "]"; + } else if(Configuration::isSubversionBuild()) { Message() << " [" << Configuration::getSubversionId() << "]"; } Message() << (Configuration::isDebugBuild() ? " DEBUG" : "") @@ -304,7 +316,7 @@ int runCvc4(int argc, char* argv[], Options& opts) { ReferenceStat< Result > s_statSatResult("sat/unsat", result); RegisterStatistic statSatResultReg(&pExecutor->getStatisticsRegistry(), &s_statSatResult); - s_totalTime.stop(); + pTotalTime->stop(); // Set the global executor pointer to NULL first. If we get a // signal while dumping statistics, we don't want to try again. @@ -334,9 +346,11 @@ int runCvc4(int argc, char* argv[], Options& opts) { // On exceptional exit, these are leaked, but that's okay... they // need to be around in that case for main() to print statistics. + delete pTotalTime; delete pExecutor; delete exprMgr; + pTotalTime = NULL; pExecutor = NULL; return returnValue; diff --git a/src/main/main.cpp b/src/main/main.cpp index 3e45b4f14..a83baf45f 100644 --- a/src/main/main.cpp +++ b/src/main/main.cpp @@ -66,6 +66,7 @@ int main(int argc, char* argv[]) { #endif *opts[options::err] << "CVC4 Error:" << endl << e << endl; if(opts[options::statistics] && pExecutor != NULL) { + pTotalTime->stop(); pExecutor->flushStatistics(*opts[options::err]); } } diff --git a/src/main/main.h b/src/main/main.h index 5b202c532..56cd866da 100644 --- a/src/main/main.h +++ b/src/main/main.h @@ -23,6 +23,7 @@ #include "util/exception.h" #include "util/statistics.h" #include "util/tls.h" +#include "util/statistics_registry.h" #include "cvc4autoconfig.h" #ifndef __CVC4__MAIN__MAIN_H @@ -42,6 +43,9 @@ extern const char* progName; /** A reference for use by the signal handlers to print statistics */ extern CVC4::main::CommandExecutor* pExecutor; +/** A reference for use by the signal handlers to print statistics */ +extern CVC4::TimerStat* pTotalTime; + /** * If true, will not spin on segfault even when CVC4_DEBUG is on. * Useful for nightly regressions, noninteractive performance runs diff --git a/src/main/options b/src/main/options index 53c04a2c4..caea63f5a 100644 --- a/src/main/options +++ b/src/main/options @@ -37,6 +37,8 @@ option sharingFilterByLength --filter-lemma-length=N int :default -1 :read-write don't share (among portfolio threads) lemmas strictly longer than N option fallbackSequential --fallback-sequential bool :default false Switch to sequential mode (instead of printing an error) if it can't be solved in portfolio mode +option incrementalParallel --incremental-parallel bool :default false :link --incremental + Use parallel solver even in incremental mode (may print 'unknown's at times) expert-option waitToJoin --wait-to-join bool :default true wait for other threads to join before quitting diff --git a/src/main/options_handlers.h b/src/main/options_handlers.h index c2eb489ed..f14a67d5f 100644 --- a/src/main/options_handlers.h +++ b/src/main/options_handlers.h @@ -26,14 +26,20 @@ inline void showConfiguration(std::string option, SmtEngine* smt) { fputs(Configuration::about().c_str(), stdout); printf("\n"); printf("version : %s\n", Configuration::getVersionString().c_str()); - if(Configuration::isSubversionBuild()) { - printf("subversion : yes [%s r%u%s]\n", + if(Configuration::isGitBuild()) { + printf("scm : git [%s %s%s]\n", + Configuration::getGitBranchName(), + std::string(Configuration::getGitCommit()).substr(0, 8).c_str(), + Configuration::hasGitModifications() ? + " (with modifications)" : ""); + } else if(Configuration::isSubversionBuild()) { + printf("scm : svn [%s r%u%s]\n", Configuration::getSubversionBranchName(), Configuration::getSubversionRevision(), Configuration::hasSubversionModifications() ? " (with modifications)" : ""); } else { - printf("subversion : %s\n", Configuration::isSubversionBuild() ? "yes" : "no"); + printf("scm : no\n"); } printf("\n"); printf("library : %u.%u.%u\n", diff --git a/src/main/util.cpp b/src/main/util.cpp index 9ade23630..a6fcddf3b 100644 --- a/src/main/util.cpp +++ b/src/main/util.cpp @@ -65,6 +65,7 @@ void* cvc4StackBase; void timeout_handler(int sig, siginfo_t* info, void*) { fprintf(stderr, "CVC4 interrupted by timeout.\n"); if((*pOptions)[options::statistics] && pExecutor != NULL) { + pTotalTime->stop(); pExecutor->flushStatistics(cerr); } abort(); @@ -74,6 +75,7 @@ void timeout_handler(int sig, siginfo_t* info, void*) { void sigint_handler(int sig, siginfo_t* info, void*) { fprintf(stderr, "CVC4 interrupted by user.\n"); if((*pOptions)[options::statistics] && pExecutor != NULL) { + pTotalTime->stop(); pExecutor->flushStatistics(cerr); } abort(); @@ -99,6 +101,7 @@ void segv_handler(int sig, siginfo_t* info, void* c) { if(segvNoSpin) { fprintf(stderr, "No-spin requested, aborting...\n"); if((*pOptions)[options::statistics] && pExecutor != NULL) { + pTotalTime->stop(); pExecutor->flushStatistics(cerr); } abort(); @@ -119,6 +122,7 @@ void segv_handler(int sig, siginfo_t* info, void* c) { cerr << "Looks like a NULL pointer was dereferenced." << endl; } if((*pOptions)[options::statistics] && pExecutor != NULL) { + pTotalTime->stop(); pExecutor->flushStatistics(cerr); } abort(); @@ -132,6 +136,7 @@ void ill_handler(int sig, siginfo_t* info, void*) { if(segvNoSpin) { fprintf(stderr, "No-spin requested, aborting...\n"); if((*pOptions)[options::statistics] && pExecutor != NULL) { + pTotalTime->stop(); pExecutor->flushStatistics(cerr); } abort(); @@ -145,6 +150,7 @@ void ill_handler(int sig, siginfo_t* info, void*) { #else /* CVC4_DEBUG */ fprintf(stderr, "CVC4 executed an illegal instruction.\n"); if((*pOptions)[options::statistics] && pExecutor != NULL) { + pTotalTime->stop(); pExecutor->flushStatistics(cerr); } abort(); @@ -171,6 +177,7 @@ void cvc4unexpected() { if(segvNoSpin) { fprintf(stderr, "No-spin requested.\n"); if((*pOptions)[options::statistics] && pExecutor != NULL) { + pTotalTime->stop(); pExecutor->flushStatistics(cerr); } set_terminate(default_terminator); @@ -184,6 +191,7 @@ void cvc4unexpected() { #else /* CVC4_DEBUG */ fprintf(stderr, "CVC4 threw an \"unexpected\" exception.\n"); if((*pOptions)[options::statistics] && pExecutor != NULL) { + pTotalTime->stop(); pExecutor->flushStatistics(cerr); } set_terminate(default_terminator); @@ -197,6 +205,7 @@ void cvc4terminate() { "Perhaps an exception was thrown during stack unwinding. " "(Don't do that.)\n"); if((*pOptions)[options::statistics] && pExecutor != NULL) { + pTotalTime->stop(); pExecutor->flushStatistics(cerr); } default_terminator(); @@ -205,6 +214,7 @@ void cvc4terminate() { "CVC4 was terminated by the C++ runtime.\n" "Perhaps an exception was thrown during stack unwinding.\n"); if((*pOptions)[options::statistics] && pExecutor != NULL) { + pTotalTime->stop(); pExecutor->flushStatistics(cerr); } default_terminator(); diff --git a/src/options/mkoptions b/src/options/mkoptions index 0632cb3f9..fa6c4c260 100755 --- a/src/options/mkoptions +++ b/src/options/mkoptions @@ -2,7 +2,7 @@ # # mkoptions # Morgan Deters <mdeters@cs.nyu.edu> for CVC4 -# Copyright (c) 2011-2012 The CVC4 Project +# Copyright (c) 2011-2013 The CVC4 Project # # The purpose of this script is to create options.{h,cpp} # from template files and a list of options. @@ -12,7 +12,7 @@ # mkoptions (template-file output-file)+ -t options.h-template options.cpp-template (options-file output-dir)+ # -copyright=2011-2012 +copyright=2011-2013 me=$(basename "$0") @@ -1314,7 +1314,8 @@ function output_module { /********************* */ /** $filename ** - ** Copyright $copyright The AcSys Group, New York University, and as below. + ** Copyright $copyright New York University and The University of Iowa, + ** and as below. ** ** This file automatically generated by: ** @@ -1496,7 +1497,8 @@ cat <<EOF /********************* */ /** $filename ** - ** Copyright $copyright The AcSys Group, New York University, and as below. + ** Copyright $copyright New York University and The University of Iowa, + ** and as below. ** ** This file automatically generated by: ** diff --git a/src/parser/bounded_token_buffer.cpp b/src/parser/bounded_token_buffer.cpp index 904f9a7fa..6a6ae8609 100644 --- a/src/parser/bounded_token_buffer.cpp +++ b/src/parser/bounded_token_buffer.cpp @@ -512,7 +512,7 @@ static pANTLR3_COMMON_TOKEN nextToken(pBOUNDED_TOKEN_BUFFER buffer) { } -/// Return a string that represents the name assoicated with the input source +/// Return a string that represents the name associated with the input source /// /// /param[in] is The ANTLR3_INT_STREAM interface that is representing this token stream. /// diff --git a/src/parser/cvc/Cvc.g b/src/parser/cvc/Cvc.g index d0fe9036b..b8ec160e8 100644 --- a/src/parser/cvc/Cvc.g +++ b/src/parser/cvc/Cvc.g @@ -416,10 +416,8 @@ Expr addNots(ExprManager* em, size_t n, Expr e) { @header { /** - ** This file is part of the CVC4 prototype. - ** Copyright (c) 2009, 2010, 2011 The Analysis of Computer Systems Group (ACSys) - ** Courant Institute of Mathematical Sciences - ** New York University + ** This file is part of CVC4. + ** Copyright (c) 2009-2013 New York University and The University of Iowa ** See the file COPYING in the top-level source directory for licensing ** information. **/ @@ -742,10 +740,7 @@ mainCommand[CVC4::Command*& cmd] | ECHO_TOK ( simpleSymbolicExpr[sexpr] - { std::stringstream ss; - ss << sexpr; - cmd = new EchoCommand(ss.str()); - } + { cmd = new EchoCommand(sexpr.getValue()); } | { cmd = new EchoCommand(); } ) diff --git a/src/parser/smt1/Smt1.g b/src/parser/smt1/Smt1.g index 0f76baace..f8331c899 100644 --- a/src/parser/smt1/Smt1.g +++ b/src/parser/smt1/Smt1.g @@ -1,3 +1,4 @@ +/* ******************* */ /*! \file Smt1.g ** \verbatim ** Original author: cconway @@ -30,10 +31,8 @@ options { @header { /** - ** This file is part of the CVC4 prototype. - ** Copyright (c) 2009, 2010, 2011 The Analysis of Computer Systems Group (ACSys) - ** Courant Institute of Mathematical Sciences - ** New York University + ** This file is part of CVC4. + ** Copyright (c) 2009-2013 New York University and The University of Iowa ** See the file COPYING in the top-level source directory for licensing ** information. **/ @@ -783,7 +782,15 @@ FLET_IDENTIFIER */ userValue[std::string& s] : USER_VALUE - { s = AntlrInput::tokenText($USER_VALUE); } + { s = AntlrInput::tokenText($USER_VALUE); + assert(*s.begin() == '{'); + assert(*s.rbegin() == '}'); + // trim whitespace + s.erase(s.begin(), s.begin() + 1); + s.erase(s.begin(), std::find_if(s.begin(), s.end(), std::not1(std::ptr_fun<int, int>(std::isspace)))); + s.erase(s.end() - 1); + s.erase(std::find_if(s.rbegin(), s.rend(), std::not1(std::ptr_fun<int, int>(std::isspace))).base(), s.end()); + } ; PATTERN_ANNOTATION_BEGIN diff --git a/src/parser/smt2/Smt2.g b/src/parser/smt2/Smt2.g index 648666091..1ee288aa4 100644 --- a/src/parser/smt2/Smt2.g +++ b/src/parser/smt2/Smt2.g @@ -31,10 +31,8 @@ options { @header { /** - ** This file is part of the CVC4 prototype. - ** Copyright (c) 2009-2012 The Analysis of Computer Systems Group (ACSys) - ** Courant Institute of Mathematical Sciences - ** New York University + ** This file is part of CVC4. + ** Copyright (c) 2009-2013 New York University and The University of Iowa ** See the file COPYING in the top-level source directory for licensing ** information. **/ diff --git a/src/parser/smt2/smt2_input.h b/src/parser/smt2/smt2_input.h index 62ed33632..62959c766 100644 --- a/src/parser/smt2/smt2_input.h +++ b/src/parser/smt2/smt2_input.h @@ -41,7 +41,7 @@ class Smt2Input : public AntlrInput { /** The ANTLR3 SMT2 lexer for the input. */ pSmt2Lexer d_pSmt2Lexer; - /** The ANTLR3 CVC parser for the input. */ + /** The ANTLR3 SMT2 parser for the input. */ pSmt2Parser d_pSmt2Parser; /** diff --git a/src/parser/tptp/Tptp.g b/src/parser/tptp/Tptp.g index 2180255ca..ec6868c5b 100644 --- a/src/parser/tptp/Tptp.g +++ b/src/parser/tptp/Tptp.g @@ -32,10 +32,8 @@ options { @header { /** - ** This file is part of the CVC4 prototype. - ** Copyright (c) 2009, 2010, 2011 The Analysis of Computer Systems Group (ACSys) - ** Courant Institute of Mathematical Sciences - ** New York University + ** This file is part of CVC4. + ** Copyright (c) 2009-2013 New York University and The University of Iowa ** See the file COPYING in the top-level source directory for licensing ** information. **/ diff --git a/src/parser/tptp/tptp.cpp b/src/parser/tptp/tptp.cpp index 1e40ea63f..59b1d205b 100644 --- a/src/parser/tptp/tptp.cpp +++ b/src/parser/tptp/tptp.cpp @@ -151,7 +151,7 @@ void Tptp::includeFile(std::string fileName){ if( d_tptpDir.empty() ){ parseError("Couldn't open included file: " + fileName - + " at " + currentDirFileName + " and the TPTP directory is not specified (environnement variable TPTP)"); + + " at " + currentDirFileName + " and the TPTP directory is not specified (environment variable TPTP)"); }; std::string tptpDirFileName = d_tptpDir + fileName; diff --git a/src/printer/cvc/cvc_printer.cpp b/src/printer/cvc/cvc_printer.cpp index e0d4656f4..0206c4252 100644 --- a/src/printer/cvc/cvc_printer.cpp +++ b/src/printer/cvc/cvc_printer.cpp @@ -21,7 +21,9 @@ #include "expr/command.h" #include "theory/substitutions.h" #include "smt/smt_engine.h" +#include "smt/options.h" #include "theory/model.h" +#include "theory/arrays/theory_arrays_rewriter.h" #include <iostream> #include <vector> @@ -813,21 +815,34 @@ void CvcPrinter::toStream(std::ostream& out, Model& m, const Command* c) const t theory::TheoryModel& tm = (theory::TheoryModel&) m; if(dynamic_cast<const DeclareTypeCommand*>(c) != NULL) { TypeNode tn = TypeNode::fromType( ((const DeclareTypeCommand*)c)->getType() ); - if( tn.isSort() ){ - // print the cardinality - if( tm.d_rep_set.d_type_reps.find( tn )!=tm.d_rep_set.d_type_reps.end() ){ - out << "; cardinality of " << tn << " is " << (*tm.d_rep_set.d_type_reps.find(tn)).second.size() << std::endl; + if( options::modelUninterpDtEnum() && tn.isSort() && + tm.d_rep_set.d_type_reps.find( tn )!=tm.d_rep_set.d_type_reps.end() ){ + out << "DATATYPE " << std::endl; + out << " " << dynamic_cast<const DeclareTypeCommand*>(c)->getSymbol() << " = "; + for( size_t i=0; i<(*tm.d_rep_set.d_type_reps.find(tn)).second.size(); i++ ){ + if (i>0) { + out << "| "; + } + out << (*tm.d_rep_set.d_type_reps.find(tn)).second[i] << " "; } - } - out << c << std::endl; - if( tn.isSort() ){ - // print the representatives - if( tm.d_rep_set.d_type_reps.find( tn )!=tm.d_rep_set.d_type_reps.end() ){ - for( size_t i=0; i<(*tm.d_rep_set.d_type_reps.find(tn)).second.size(); i++ ){ - if( (*tm.d_rep_set.d_type_reps.find(tn)).second[i].isVar() ){ - out << (*tm.d_rep_set.d_type_reps.find(tn)).second[i] << " : " << tn << ";" << std::endl; - }else{ - out << "% rep: " << (*tm.d_rep_set.d_type_reps.find(tn)).second[i] << std::endl; + out << std::endl << "END;" << std::endl; + } else { + if( tn.isSort() ){ + // print the cardinality + if( tm.d_rep_set.d_type_reps.find( tn )!=tm.d_rep_set.d_type_reps.end() ){ + out << "% cardinality of " << tn << " is " << (*tm.d_rep_set.d_type_reps.find(tn)).second.size() << std::endl; + } + } + out << c << std::endl; + if( tn.isSort() ){ + // print the representatives + if( tm.d_rep_set.d_type_reps.find( tn )!=tm.d_rep_set.d_type_reps.end() ){ + for( size_t i=0; i<(*tm.d_rep_set.d_type_reps.find(tn)).second.size(); i++ ){ + if( (*tm.d_rep_set.d_type_reps.find(tn)).second[i].isVar() ){ + out << (*tm.d_rep_set.d_type_reps.find(tn)).second[i] << " : " << tn << ";" << std::endl; + }else{ + out << "% rep: " << (*tm.d_rep_set.d_type_reps.find(tn)).second[i] << std::endl; + } } } } @@ -850,7 +865,15 @@ void CvcPrinter::toStream(std::ostream& out, Model& m, const Command* c) const t }else{ out << tn; } - out << " = " << Node::fromExpr(tm.getSmtEngine()->getValue(n.toExpr())) << ";" << std::endl; + Node val = Node::fromExpr(tm.getSmtEngine()->getValue(n.toExpr())); + if( options::modelUninterpDtEnum() && val.getKind() == kind::STORE ) { + TypeNode tn = val[1].getType(); + if (tn.isSort() && tm.d_rep_set.d_type_reps.find( tn )!=tm.d_rep_set.d_type_reps.end() ){ + Cardinality indexCard((*tm.d_rep_set.d_type_reps.find(tn)).second.size()); + val = theory::arrays::TheoryArraysRewriter::normalizeConstant( val, indexCard ); + } + } + out << " = " << val << ";" << std::endl; /* //for table format (work in progress) diff --git a/src/printer/smt2/smt2_printer.cpp b/src/printer/smt2/smt2_printer.cpp index 000fd2fbf..8541ca6ae 100644 --- a/src/printer/smt2/smt2_printer.cpp +++ b/src/printer/smt2/smt2_printer.cpp @@ -27,8 +27,10 @@ #include "theory/substitutions.h" #include "util/language.h" #include "smt/smt_engine.h" +#include "smt/options.h" #include "theory/model.h" +#include "theory/arrays/theory_arrays_rewriter.h" using namespace std; @@ -552,21 +554,30 @@ void Smt2Printer::toStream(std::ostream& out, Model& m, const Command* c) const theory::TheoryModel& tm = (theory::TheoryModel&) m; if(dynamic_cast<const DeclareTypeCommand*>(c) != NULL) { TypeNode tn = TypeNode::fromType( ((const DeclareTypeCommand*)c)->getType() ); - if( tn.isSort() ){ - //print the cardinality - if( tm.d_rep_set.d_type_reps.find( tn )!=tm.d_rep_set.d_type_reps.end() ){ - out << "; cardinality of " << tn << " is " << (*tm.d_rep_set.d_type_reps.find(tn)).second.size() << std::endl; + if( options::modelUninterpDtEnum() && tn.isSort() && + tm.d_rep_set.d_type_reps.find( tn )!=tm.d_rep_set.d_type_reps.end() ){ + out << "(declare-datatypes () ((" << dynamic_cast<const DeclareTypeCommand*>(c)->getSymbol() << " "; + for( size_t i=0; i<(*tm.d_rep_set.d_type_reps.find(tn)).second.size(); i++ ){ + out << "(" << (*tm.d_rep_set.d_type_reps.find(tn)).second[i] << ")"; } - } - out << c << std::endl; - if( tn.isSort() ){ - //print the representatives - if( tm.d_rep_set.d_type_reps.find( tn )!=tm.d_rep_set.d_type_reps.end() ){ - for( size_t i=0; i<(*tm.d_rep_set.d_type_reps.find(tn)).second.size(); i++ ){ - if( (*tm.d_rep_set.d_type_reps.find(tn)).second[i].isVar() ){ - out << "(declare-fun " << (*tm.d_rep_set.d_type_reps.find(tn)).second[i] << " () " << tn << ")" << std::endl; - }else{ - out << "; rep: " << (*tm.d_rep_set.d_type_reps.find(tn)).second[i] << std::endl; + out << ")))" << std::endl; + } else { + if( tn.isSort() ){ + //print the cardinality + if( tm.d_rep_set.d_type_reps.find( tn )!=tm.d_rep_set.d_type_reps.end() ){ + out << "; cardinality of " << tn << " is " << (*tm.d_rep_set.d_type_reps.find(tn)).second.size() << std::endl; + } + } + out << c << std::endl; + if( tn.isSort() ){ + //print the representatives + if( tm.d_rep_set.d_type_reps.find( tn )!=tm.d_rep_set.d_type_reps.end() ){ + for( size_t i=0; i<(*tm.d_rep_set.d_type_reps.find(tn)).second.size(); i++ ){ + if( (*tm.d_rep_set.d_type_reps.find(tn)).second[i].isVar() ){ + out << "(declare-fun " << (*tm.d_rep_set.d_type_reps.find(tn)).second[i] << " () " << tn << ")" << std::endl; + }else{ + out << "; rep: " << (*tm.d_rep_set.d_type_reps.find(tn)).second[i] << std::endl; + } } } } @@ -583,6 +594,13 @@ void Smt2Printer::toStream(std::ostream& out, Model& m, const Command* c) const << " " << n.getType().getRangeType() << " " << val[1] << ")" << std::endl; } else { + if( options::modelUninterpDtEnum() && val.getKind() == kind::STORE ) { + TypeNode tn = val[1].getType(); + if (tn.isSort() && tm.d_rep_set.d_type_reps.find( tn )!=tm.d_rep_set.d_type_reps.end() ){ + Cardinality indexCard((*tm.d_rep_set.d_type_reps.find(tn)).second.size()); + val = theory::arrays::TheoryArraysRewriter::normalizeConstant( val, indexCard ); + } + } out << "(define-fun " << n << " () " << n.getType() << " " << val << ")" << std::endl; } diff --git a/src/proof/sat_proof.h b/src/proof/sat_proof.h index 324988585..ccbde6e80 100644 --- a/src/proof/sat_proof.h +++ b/src/proof/sat_proof.h @@ -160,8 +160,8 @@ protected: * Does a depth first search on removed literals and adds the literals * to be removed in the proper order to the stack. * - * @param lit the literal we are recusing on - * @param removedSet the previously computed set of redundantant literals + * @param lit the literal we are recursing on + * @param removedSet the previously computed set of redundant literals * @param removeStack the stack of literals in reverse order of resolution */ void removedDfs(::Minisat::Lit lit, LitSet* removedSet, LitVector& removeStack, LitSet& inClause, LitSet& seen); diff --git a/src/prop/bvminisat/Makefile b/src/prop/bvminisat/Makefile new file mode 100644 index 000000000..71888016d --- /dev/null +++ b/src/prop/bvminisat/Makefile @@ -0,0 +1,4 @@ +topdir = ../../.. +srcdir = src/prop/bvminisat + +include $(topdir)/Makefile.subdir diff --git a/src/smt/boolean_terms.cpp b/src/smt/boolean_terms.cpp index 696622cfe..262244f42 100644 --- a/src/smt/boolean_terms.cpp +++ b/src/smt/boolean_terms.cpp @@ -39,6 +39,13 @@ static inline bool isBoolean(TNode top, unsigned i) { case kind::IMPLIES: case kind::OR: case kind::XOR: + case kind::FORALL: + case kind::EXISTS: + case kind::REWRITE_RULE: + case kind::RR_REWRITE: + case kind::RR_DEDUCTION: + case kind::RR_REDUCTION: + case kind::INST_PATTERN: return true; case kind::ITE: @@ -289,13 +296,16 @@ Node BooleanTermConverter::rewriteBooleanTerms(TNode top, bool boolParent) throw } switch(k) { case kind::LAMBDA: - case kind::FORALL: - case kind::EXISTS: + Unreachable("not expecting a LAMBDA in boolean-term conversion: %s", top.toString().c_str()); + + case kind::BOUND_VAR_LIST: + return top; + case kind::REWRITE_RULE: case kind::RR_REWRITE: - case kind::RR_REDUCTION: case kind::RR_DEDUCTION: - //Assert(false, "not yet supported"); + case kind::RR_REDUCTION: + // not yet supported return top; default: diff --git a/src/smt/options b/src/smt/options index fc5ccf4c4..2680f4105 100644 --- a/src/smt/options +++ b/src/smt/options @@ -54,6 +54,8 @@ common-option incrementalSolving incremental -i --incremental bool option abstractValues abstract-values --abstract-values bool :default false in models, output arrays (and in future, maybe others) using abstract values, as required by the SMT-LIB standard +option modelUninterpDtEnum --model-u-dt-enum bool :default false + in models, output uninterpreted sorts as datatype enumerations option - regular-output-channel argument :handler CVC4::smt::setRegularOutputChannel :handler-include "smt/options_handlers.h" set the regular output channel of the solver diff --git a/src/smt/smt_engine.cpp b/src/smt/smt_engine.cpp index 1d98ce115..8eb6664ca 100644 --- a/src/smt/smt_engine.cpp +++ b/src/smt/smt_engine.cpp @@ -36,6 +36,7 @@ #include "expr/metakind.h" #include "expr/node_builder.h" #include "expr/node.h" +#include "expr/node_self_iterator.h" #include "prop/prop_engine.h" #include "smt/modal_exception.h" #include "smt/smt_engine.h" @@ -111,7 +112,11 @@ struct SmtEngineStatistics { TimerStat d_rewriteBooleanTermsTime; /** time spent in non-clausal simplification */ TimerStat d_nonclausalSimplificationTime; - /** Num of constant propagations found during nonclausal simp */ + /** time spent in miplib pass */ + TimerStat d_miplibPassTime; + /** number of assertions removed by miplib pass */ + IntStat d_numMiplibAssertionsRemoved; + /** number of constant propagations found during nonclausal simp */ IntStat d_numConstantProps; /** time spent in static learning */ TimerStat d_staticLearningTime; @@ -136,6 +141,8 @@ struct SmtEngineStatistics { d_definitionExpansionTime("smt::SmtEngine::definitionExpansionTime"), d_rewriteBooleanTermsTime("smt::SmtEngine::rewriteBooleanTermsTime"), d_nonclausalSimplificationTime("smt::SmtEngine::nonclausalSimplificationTime"), + d_miplibPassTime("smt::SmtEngine::miplibPassTime"), + d_numMiplibAssertionsRemoved("smt::SmtEngine::numMiplibAssertionsRemoved", 0), d_numConstantProps("smt::SmtEngine::numConstantProps", 0), d_staticLearningTime("smt::SmtEngine::staticLearningTime"), d_simpITETime("smt::SmtEngine::simpITETime"), @@ -150,6 +157,8 @@ struct SmtEngineStatistics { StatisticsRegistry::registerStat(&d_definitionExpansionTime); StatisticsRegistry::registerStat(&d_rewriteBooleanTermsTime); StatisticsRegistry::registerStat(&d_nonclausalSimplificationTime); + StatisticsRegistry::registerStat(&d_miplibPassTime); + StatisticsRegistry::registerStat(&d_numMiplibAssertionsRemoved); StatisticsRegistry::registerStat(&d_numConstantProps); StatisticsRegistry::registerStat(&d_staticLearningTime); StatisticsRegistry::registerStat(&d_simpITETime); @@ -166,6 +175,8 @@ struct SmtEngineStatistics { StatisticsRegistry::unregisterStat(&d_definitionExpansionTime); StatisticsRegistry::unregisterStat(&d_rewriteBooleanTermsTime); StatisticsRegistry::unregisterStat(&d_nonclausalSimplificationTime); + StatisticsRegistry::unregisterStat(&d_miplibPassTime); + StatisticsRegistry::unregisterStat(&d_numMiplibAssertionsRemoved); StatisticsRegistry::unregisterStat(&d_numConstantProps); StatisticsRegistry::unregisterStat(&d_staticLearningTime); StatisticsRegistry::unregisterStat(&d_simpITETime); @@ -210,6 +221,8 @@ class SmtEnginePrivate : public NodeManagerListener { /** A circuit propagator for non-clausal propositional deduction */ booleans::CircuitPropagator d_propagator; + bool d_propagatorNeedsFinish; + std::vector<Node> d_boolVars; /** Assertions to push to sat */ vector<Node> d_assertionsToCheck; @@ -333,6 +346,14 @@ private: void constrainSubtypes(TNode n, std::vector<Node>& assertions) throw(); + // trace nodes back to their assertions using CircuitPropagator's BackEdgesMap + void traceBackToAssertions(const std::vector<Node>& nodes, std::vector<TNode>& assertions); + // remove conjuncts in toRemove from conjunction n; return # of removed conjuncts + size_t removeFromConjunction(Node& n, const std::hash_set<unsigned>& toRemove); + + // scrub miplib encodings + void doMiplibTrick(); + /** * Perform non-clausal simplification of a Node. This involves * Theory implementations, but does NOT involve the SAT solver in @@ -351,6 +372,7 @@ public: d_realAssertionsEnd(0), d_booleanTermConverter(d_smt), d_propagator(d_nonClausalLearnedLiterals, true, true), + d_propagatorNeedsFinish(false), d_assertionsToCheck(), d_fakeContext(), d_abstractValueMap(&d_fakeContext), @@ -365,6 +387,14 @@ public: d_smt.d_nodeManager->subscribeEvents(this); } + ~SmtEnginePrivate() { + if(d_propagatorNeedsFinish) { + d_propagator.finish(); + d_propagatorNeedsFinish = false; + } + d_smt.d_nodeManager->unsubscribeEvents(this); + } + void nmNotifyNewSort(TypeNode tn) { DeclareTypeCommand c(tn.getAttribute(expr::VarNameAttr()), 0, @@ -389,10 +419,13 @@ public: n.toExpr(), n.getType().toType()); d_smt.addToModelCommandAndDump(c, isGlobal); + if(n.getType().isBoolean() && !options::incrementalSolving()) { + d_boolVars.push_back(n); + } } void nmNotifyNewSkolem(TNode n, const std::string& comment, bool isGlobal) { - std::string id = n.getAttribute(expr::VarNameAttr()); + string id = n.getAttribute(expr::VarNameAttr()); DeclareFunctionCommand c(id, n.toExpr(), n.getType().toType()); @@ -400,6 +433,9 @@ public: Dump("skolems") << CommentCommand(id + " is " + comment); } d_smt.addToModelCommandAndDump(c, isGlobal, false, "skolems"); + if(n.getType().isBoolean() && !options::incrementalSolving()) { + d_boolVars.push_back(n); + } } Node applySubstitutions(TNode node) const { @@ -506,8 +542,6 @@ public: }/* namespace CVC4::smt */ -using namespace CVC4::smt; - SmtEngine::SmtEngine(ExprManager* em) throw() : d_context(em->getContext()), d_userLevels(), @@ -623,17 +657,17 @@ void SmtEngine::finalOptionsAreSet() { if(options::checkModels()) { if(! options::produceModels()) { - Notice() << "SmtEngine: turning on produce-models to support check-model" << std::endl; + Notice() << "SmtEngine: turning on produce-models to support check-model" << endl; setOption("produce-models", SExpr("true")); } if(! options::interactive()) { - Notice() << "SmtEngine: turning on interactive-mode to support check-model" << std::endl; + Notice() << "SmtEngine: turning on interactive-mode to support check-model" << endl; setOption("interactive-mode", SExpr("true")); } } if(options::produceAssignments() && !options::produceModels()) { - Notice() << "SmtEngine: turning on produce-models to support produce-assignments" << std::endl; + Notice() << "SmtEngine: turning on produce-models to support produce-assignments" << endl; setOption("produce-models", SExpr("true")); } @@ -784,15 +818,15 @@ void SmtEngine::setLogicInternal() throw() { // by default, symmetry breaker is on only for QF_UF if(! options::ufSymmetryBreaker.wasSetByUser()) { bool qf_uf = d_logic.isPure(THEORY_UF) && !d_logic.isQuantified(); - Trace("smt") << "setting uf symmetry breaker to " << qf_uf << std::endl; + Trace("smt") << "setting uf symmetry breaker to " << qf_uf << endl; options::ufSymmetryBreaker.set(qf_uf); } // by default, nonclausal simplification is off for QF_SAT and for quantifiers if(! options::simplificationMode.wasSetByUser()) { bool qf_sat = d_logic.isPure(THEORY_BOOL) && !d_logic.isQuantified(); bool quantifiers = d_logic.isQuantified(); - Trace("smt") << "setting simplification mode to <" << d_logic.getLogicString() << "> " << (!qf_sat && !quantifiers) << std::endl; - //simplifaction=none works better for SMT LIB benchmarks with quantifiers, not others + Trace("smt") << "setting simplification mode to <" << d_logic.getLogicString() << "> " << (!qf_sat && !quantifiers) << endl; + //simplification=none works better for SMT LIB benchmarks with quantifiers, not others //options::simplificationMode.set(qf_sat || quantifiers ? SIMPLIFICATION_MODE_NONE : SIMPLIFICATION_MODE_BATCH); options::simplificationMode.set(qf_sat ? SIMPLIFICATION_MODE_NONE : SIMPLIFICATION_MODE_BATCH); } @@ -808,14 +842,14 @@ void SmtEngine::setLogicInternal() throw() { bool iteSimp = !d_logic.isQuantified() && ((d_logic.isPure(THEORY_ARITH) && d_logic.isLinear() && !d_logic.isDifferenceLogic() && !d_logic.areRealsUsed()) || (d_logic.isTheoryEnabled(THEORY_ARRAY) && d_logic.isTheoryEnabled(THEORY_UF) && d_logic.isTheoryEnabled(THEORY_BV))); - Trace("smt") << "setting ite simplification to " << iteSimp << std::endl; + Trace("smt") << "setting ite simplification to " << iteSimp << endl; options::doITESimp.set(iteSimp); } // Turn on multiple-pass non-clausal simplification for QF_AUFBV if(! options::repeatSimp.wasSetByUser()) { bool repeatSimp = !d_logic.isQuantified() && (d_logic.isTheoryEnabled(THEORY_ARRAY) && d_logic.isTheoryEnabled(THEORY_UF) && d_logic.isTheoryEnabled(THEORY_BV)); - Trace("smt") << "setting repeat simplification to " << repeatSimp << std::endl; + Trace("smt") << "setting repeat simplification to " << repeatSimp << endl; options::repeatSimp.set(repeatSimp); } // Turn on unconstrained simplification for QF_AUFBV @@ -824,24 +858,24 @@ void SmtEngine::setLogicInternal() throw() { // bool uncSimp = false && !qf_sat && !options::incrementalSolving(); bool uncSimp = !options::incrementalSolving() && !d_logic.isQuantified() && !options::produceModels() && !options::checkModels() && (d_logic.isTheoryEnabled(THEORY_ARRAY) && d_logic.isTheoryEnabled(THEORY_BV)); - Trace("smt") << "setting unconstrained simplification to " << uncSimp << std::endl; + Trace("smt") << "setting unconstrained simplification to " << uncSimp << endl; options::unconstrainedSimp.set(uncSimp); } // Unconstrained simp currently does *not* support model generation if (options::unconstrainedSimp.wasSetByUser() && options::unconstrainedSimp()) { if (options::produceModels()) { - Notice() << "SmtEngine: turning off produce-models to support unconstrainedSimp" << std::endl; + Notice() << "SmtEngine: turning off produce-models to support unconstrainedSimp" << endl; setOption("produce-models", SExpr("false")); } if (options::checkModels()) { - Notice() << "SmtEngine: turning off check-models to support unconstrainedSimp" << std::endl; + Notice() << "SmtEngine: turning off check-models to support unconstrainedSimp" << endl; setOption("check-models", SExpr("false")); } } // Turn on arith rewrite equalities only for pure arithmetic if(! options::arithRewriteEq.wasSetByUser()) { bool arithRewriteEq = d_logic.isPure(THEORY_ARITH) && !d_logic.isQuantified(); - Trace("smt") << "setting arith rewrite equalities " << arithRewriteEq << std::endl; + Trace("smt") << "setting arith rewrite equalities " << arithRewriteEq << endl; options::arithRewriteEq.set(arithRewriteEq); } if(! options::arithHeuristicPivots.wasSetByUser()) { @@ -853,7 +887,7 @@ void SmtEngine::setLogicInternal() throw() { heuristicPivots = 0; } } - Trace("smt") << "setting arithHeuristicPivots " << heuristicPivots << std::endl; + Trace("smt") << "setting arithHeuristicPivots " << heuristicPivots << endl; options::arithHeuristicPivots.set(heuristicPivots); } if(! options::arithPivotThreshold.wasSetByUser()){ @@ -863,7 +897,7 @@ void SmtEngine::setLogicInternal() throw() { pivotThreshold = 16; } } - Trace("smt") << "setting arith arithPivotThreshold " << pivotThreshold << std::endl; + Trace("smt") << "setting arith arithPivotThreshold " << pivotThreshold << endl; options::arithPivotThreshold.set(pivotThreshold); } if(! options::arithStandardCheckVarOrderPivots.wasSetByUser()){ @@ -871,7 +905,7 @@ void SmtEngine::setLogicInternal() throw() { if(d_logic.isPure(THEORY_ARITH) && !d_logic.isQuantified()){ varOrderPivots = 200; } - Trace("smt") << "setting arithStandardCheckVarOrderPivots " << varOrderPivots << std::endl; + Trace("smt") << "setting arithStandardCheckVarOrderPivots " << varOrderPivots << endl; options::arithStandardCheckVarOrderPivots.set(varOrderPivots); } // Turn off early theory preprocessing if arithRewriteEq is on @@ -930,7 +964,7 @@ void SmtEngine::setLogicInternal() throw() { ? true : false ); - Trace("smt") << "setting decision mode to " << decMode << std::endl; + Trace("smt") << "setting decision mode to " << decMode << endl; options::decisionMode.set(decMode); options::decisionStopOnly.set(stoponly); } @@ -938,7 +972,7 @@ void SmtEngine::setLogicInternal() throw() { //for finite model finding if( ! options::instWhenMode.wasSetByUser()){ if( options::fmfInstEngine() ){ - Trace("smt") << "setting inst when mode to LAST_CALL" << std::endl; + Trace("smt") << "setting inst when mode to LAST_CALL" << endl; options::instWhenMode.set( INST_WHEN_LAST_CALL ); } } @@ -951,11 +985,11 @@ void SmtEngine::setLogicInternal() throw() { } else if (options::minisatUseElim()) { if (options::produceModels()) { - Notice() << "SmtEngine: turning off produce-models to support minisatUseElim" << std::endl; + Notice() << "SmtEngine: turning off produce-models to support minisatUseElim" << endl; setOption("produce-models", SExpr("false")); } if (options::checkModels()) { - Notice() << "SmtEngine: turning off check-models to support minisatUseElim" << std::endl; + Notice() << "SmtEngine: turning off check-models to support minisatUseElim" << endl; setOption("check-models", SExpr("false")); } } @@ -970,11 +1004,11 @@ void SmtEngine::setLogicInternal() throw() { if (d_logic.isTheoryEnabled(theory::THEORY_ARITH) && !d_logic.isLinear()) { if (options::produceModels()) { - Warning() << "SmtEngine: turning off produce-models because unsupported for nonlinear arith" << std::endl; + Warning() << "SmtEngine: turning off produce-models because unsupported for nonlinear arith" << endl; setOption("produce-models", SExpr("false")); } if (options::checkModels()) { - Warning() << "SmtEngine: turning off check-models because unsupported for nonlinear arith" << std::endl; + Warning() << "SmtEngine: turning off check-models because unsupported for nonlinear arith" << endl; setOption("check-models", SExpr("false")); } } @@ -995,7 +1029,7 @@ void SmtEngine::setInfo(const std::string& key, const CVC4::SExpr& value) Trace("smt") << "SMT setInfo(" << key << ", " << value << ")" << endl; if(Dump.isOn("benchmark")) { if(key == "status") { - std::string s = value.getValue(); + string s = value.getValue(); BenchmarkStatus status = (s == "sat") ? SMT_SATISFIABLE : ((s == "unsat") ? SMT_UNSATISFIABLE : SMT_UNKNOWN); @@ -1175,7 +1209,7 @@ void SmtEngine::defineFunction(Expr func, // Permit (check-sat) (define-fun ...) (get-value ...) sequences. // Otherwise, (check-sat) (get-value ((! foo :named bar))) breaks // d_haveAdditions = true; - Debug("smt") << "definedFunctions insert " << funcNode << " " << formNode << std::endl; + Debug("smt") << "definedFunctions insert " << funcNode << " " << formNode << endl; d_definedFunctions->insert(funcNode, def); } @@ -1185,7 +1219,7 @@ Node SmtEnginePrivate::getBVDivByZero(Kind k, unsigned width) { if (k == kind::BITVECTOR_UDIV) { if (d_BVDivByZero.find(width) == d_BVDivByZero.end()) { // lazily create the function symbols - std::ostringstream os; + ostringstream os; os << "BVUDivByZero_" << width; Node divByZero = nm->mkSkolem(os.str(), nm->mkFunctionType(nm->mkBitVectorType(width), nm->mkBitVectorType(width)), @@ -1196,7 +1230,7 @@ Node SmtEnginePrivate::getBVDivByZero(Kind k, unsigned width) { } else if (k == kind::BITVECTOR_UREM) { if (d_BVRemByZero.find(width) == d_BVRemByZero.end()) { - std::ostringstream os; + ostringstream os; os << "BVURemByZero_" << width; Node divByZero = nm->mkSkolem(os.str(), nm->mkFunctionType(nm->mkBitVectorType(width), nm->mkBitVectorType(width)), @@ -1236,7 +1270,7 @@ Node SmtEnginePrivate::expandDefinitions(TNode n, hash_map<Node, Node, NodeHashF if(i != d_smt.d_definedFunctions->end()) { // replacement must be closed if((*i).second.getFormals().size() > 0) { - throw TypeCheckingException(n.toExpr(), std::string("Defined function requires arguments: `") + n.toString() + "'"); + throw TypeCheckingException(n.toExpr(), string("Defined function requires arguments: `") + n.toString() + "'"); } // don't bother putting in the cache return (*i).second.getFormula(); @@ -1265,9 +1299,9 @@ Node SmtEnginePrivate::expandDefinitions(TNode n, hash_map<Node, Node, NodeHashF break; } - case kind::BITVECTOR_UDIV: - case kind::BITVECTOR_UREM: { - node = expandBVDivByZero(node); + case kind::BITVECTOR_UDIV: + case kind::BITVECTOR_UREM: { + node = expandBVDivByZero(node); break; } case kind::DIVISION: { @@ -1339,7 +1373,7 @@ Node SmtEnginePrivate::expandDefinitions(TNode n, hash_map<Node, Node, NodeHashF Debug("expand") << " : \"" << name << "\"" << endl; } if(i == d_smt.d_definedFunctions->end()) { - throw TypeCheckingException(n.toExpr(), std::string("Undefined function: `") + func.toString() + "'"); + throw TypeCheckingException(n.toExpr(), string("Undefined function: `") + func.toString() + "'"); } if(Debug.isOn("expand")) { Debug("expand") << " defn: " << def.getFunction() << endl @@ -1408,16 +1442,16 @@ static bool containsQuantifiers(Node n) { } Node SmtEnginePrivate::preSkolemizeQuantifiers( Node n, bool polarity, std::vector< Node >& fvs ){ - Trace("pre-sk") << "Pre-skolem " << n << " " << polarity << " " << fvs.size() << std::endl; + Trace("pre-sk") << "Pre-skolem " << n << " " << polarity << " " << fvs.size() << endl; if( n.getKind()==kind::NOT ){ Node nn = preSkolemizeQuantifiers( n[0], !polarity, fvs ); return nn.negate(); }else if( n.getKind()==kind::FORALL ){ if( polarity ){ - std::vector< Node > children; + vector< Node > children; children.push_back( n[0] ); //add children to current scope - std::vector< Node > fvss; + vector< Node > fvss; fvss.insert( fvss.begin(), fvs.begin(), fvs.end() ); for( int i=0; i<(int)n[0].getNumChildren(); i++ ){ fvss.push_back( n[0][i] ); @@ -1433,13 +1467,13 @@ Node SmtEnginePrivate::preSkolemizeQuantifiers( Node n, bool polarity, std::vect //process body Node nn = preSkolemizeQuantifiers( n[1], polarity, fvs ); //now, substitute skolems for the variables - std::vector< TypeNode > argTypes; + vector< TypeNode > argTypes; for( int i=0; i<(int)fvs.size(); i++ ){ argTypes.push_back( fvs[i].getType() ); } //calculate the variables and substitution - std::vector< Node > vars; - std::vector< Node > subs; + vector< Node > vars; + vector< Node > subs; for( int i=0; i<(int)n[0].getNumChildren(); i++ ){ vars.push_back( n[0][i] ); } @@ -1452,7 +1486,7 @@ Node SmtEnginePrivate::preSkolemizeQuantifiers( Node n, bool polarity, std::vect TypeNode typ = NodeManager::currentNM()->mkFunctionType( argTypes, n[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; + vector< Node > funcArgs; funcArgs.push_back( op ); funcArgs.insert( funcArgs.end(), fvs.begin(), fvs.end() ); subs.push_back( NodeManager::currentNM()->mkNode( kind::APPLY_UF, funcArgs ) ); @@ -1492,7 +1526,7 @@ Node SmtEnginePrivate::preSkolemizeQuantifiers( Node n, bool polarity, std::vect return preSkolemizeQuantifiers( nn, polarity, fvs ); }else{ Assert( n.getKind() == kind::AND || n.getKind() == kind::OR ); - std::vector< Node > children; + vector< Node > children; for( int i=0; i<(int)n.getNumChildren(); i++ ){ children.push_back( preSkolemizeQuantifiers( n[i], polarity, fvs ) ); } @@ -1541,7 +1575,7 @@ void SmtEnginePrivate::staticLearning() { static void dumpAssertions(const char* key, const std::vector<Node>& assertionList) { if( Dump.isOn("assertions") && - Dump.isOn(std::string("assertions:") + key) ) { + Dump.isOn(string("assertions:") + key) ) { // Push the simplified assertions to the dump output stream for(unsigned i = 0; i < assertionList.size(); ++ i) { TNode n = assertionList[i]; @@ -1558,6 +1592,10 @@ bool SmtEnginePrivate::nonClausalSimplify() { Trace("simplify") << "SmtEnginePrivate::nonClausalSimplify()" << endl; + if(d_propagatorNeedsFinish) { + d_propagator.finish(); + d_propagatorNeedsFinish = false; + } d_propagator.initialize(); // Assert all the assertions to the propagator @@ -1577,7 +1615,7 @@ bool SmtEnginePrivate::nonClausalSimplify() { << "conflict in non-clausal propagation" << endl; d_assertionsToPreprocess.clear(); d_assertionsToCheck.push_back(NodeManager::currentNM()->mkConst<bool>(false)); - d_propagator.finish(); + d_propagatorNeedsFinish = true; return false; } @@ -1612,7 +1650,7 @@ bool SmtEnginePrivate::nonClausalSimplify() { << d_nonClausalLearnedLiterals[i] << endl; d_assertionsToPreprocess.clear(); d_assertionsToCheck.push_back(NodeManager::currentNM()->mkConst<bool>(false)); - d_propagator.finish(); + d_propagatorNeedsFinish = true; return false; } } @@ -1644,7 +1682,7 @@ bool SmtEnginePrivate::nonClausalSimplify() { << learnedLiteral << endl; d_assertionsToPreprocess.clear(); d_assertionsToCheck.push_back(NodeManager::currentNM()->mkConst<bool>(false)); - d_propagator.finish(); + d_propagatorNeedsFinish = true; return false; default: if (d_doConstantProp && learnedLiteral.getKind() == kind::EQUAL && (learnedLiteral[0].isConst() || learnedLiteral[1].isConst())) { @@ -1714,6 +1752,17 @@ bool SmtEnginePrivate::nonClausalSimplify() { // Resize the learnt d_nonClausalLearnedLiterals.resize(j); + //must add substitutions to model + TheoryModel* m = d_smt.d_theoryEngine->getModel(); + if(m != NULL) { + for( SubstitutionMap::iterator pos = d_topLevelSubstitutions.begin(); pos != d_topLevelSubstitutions.end(); ++pos) { + Node n = (*pos).first; + Node v = (*pos).second; + Trace("model") << "Add substitution : " << n << " " << v << std::endl; + m->addSubstitution( n, v ); + } + } + hash_set<TNode, TNodeHashFunction> s; for (unsigned i = 0; i < d_assertionsToPreprocess.size(); ++ i) { Node assertion = d_assertionsToPreprocess[i]; @@ -1812,7 +1861,7 @@ bool SmtEnginePrivate::nonClausalSimplify() { Rewriter::rewrite(Node(learnedBuilder)); } - d_propagator.finish(); + d_propagatorNeedsFinish = true; return true; } @@ -1894,6 +1943,366 @@ void SmtEnginePrivate::constrainSubtypes(TNode top, std::vector<Node>& assertion } while(! worklist.empty()); } +void SmtEnginePrivate::traceBackToAssertions(const std::vector<Node>& nodes, std::vector<TNode>& assertions) { + const booleans::CircuitPropagator::BackEdgesMap& backEdges = d_propagator.getBackEdges(); + for(vector<Node>::const_iterator i = nodes.begin(); i != nodes.end(); ++i) { + booleans::CircuitPropagator::BackEdgesMap::const_iterator j = backEdges.find(*i); + // term must appear in map, otherwise how did we get here?! + Assert(j != backEdges.end()); + // if term maps to empty, that means it's a top-level assertion + if(!(*j).second.empty()) { + traceBackToAssertions((*j).second, assertions); + } else { + assertions.push_back(*i); + } + } +} + +size_t SmtEnginePrivate::removeFromConjunction(Node& n, const std::hash_set<unsigned>& toRemove) { + Assert(n.getKind() == kind::AND); + Node trueNode = NodeManager::currentNM()->mkConst(true); + size_t removals = 0; + for(Node::iterator j = n.begin(); j != n.end(); ++j) { + size_t subremovals = 0; + Node sub = *j; + if(toRemove.find(sub.getId()) != toRemove.end() || + (sub.getKind() == kind::AND && (subremovals = removeFromConjunction(sub, toRemove)) > 0)) { + NodeBuilder<> b(kind::AND); + b.append(n.begin(), j); + if(subremovals > 0) { + removals += subremovals; + b << sub; + } else { + ++removals; + } + for(++j; j != n.end(); ++j) { + if(toRemove.find((*j).getId()) != toRemove.end()) { + ++removals; + } else if((*j).getKind() == kind::AND) { + sub = *j; + if((subremovals = removeFromConjunction(sub, toRemove)) > 0) { + removals += subremovals; + b << sub; + } else { + b << *j; + } + } else { + b << *j; + } + } + if(b.getNumChildren() == 0) { + n = trueNode; + b.clear(); + } else if(b.getNumChildren() == 1) { + n = b[0]; + b.clear(); + } else { + n = b; + } + n = Rewriter::rewrite(n); + return removals; + } + } + + Assert(removals == 0); + return 0; +} + +void SmtEnginePrivate::doMiplibTrick() { + Assert(d_assertionsToPreprocess.empty()); + Assert(d_realAssertionsEnd == d_assertionsToCheck.size()); + Assert(!options::incrementalSolving()); + + const booleans::CircuitPropagator::BackEdgesMap& backEdges = d_propagator.getBackEdges(); + hash_set<unsigned> removeAssertions; + + NodeManager* nm = NodeManager::currentNM(); + Node zero = nm->mkConst(Rational(0)), one = nm->mkConst(Rational(1)); + + hash_map<TNode, Node, TNodeHashFunction> intVars; + for(vector<Node>::const_iterator i = d_boolVars.begin(); i != d_boolVars.end(); ++i) { + if(d_propagator.isAssigned(*i)) { + Debug("miplib") << "ineligible: " << *i << " because assigned " << d_propagator.getAssignment(*i) << endl; + continue; + } + + vector<TNode> assertions; + booleans::CircuitPropagator::BackEdgesMap::const_iterator j = backEdges.find(*i); + // if not in back edges map, the bool var is unconstrained, showing up in no assertions. + // if maps to an empty vector, that means the bool var was asserted itself. + if(j != backEdges.end()) { + if(!(*j).second.empty()) { + traceBackToAssertions((*j).second, assertions); + } else { + assertions.push_back(*i); + } + } + Debug("miplib") << "for " << *i << endl; + bool eligible = true; + map<pair<Node, Node>, uint64_t> marks; + map<pair<Node, Node>, vector<Rational> > coef; + map<pair<Node, Node>, vector<Rational> > checks; + map<pair<Node, Node>, vector<TNode> > asserts; + for(vector<TNode>::const_iterator j = assertions.begin(); j != assertions.end(); ++j) { + Debug("miplib") << " found: " << *j << endl; + if((*j).getKind() != kind::IMPLIES) { + eligible = false; + Debug("miplib") << " -- INELIGIBLE -- (not =>)" << endl; + break; + } + Node conj = BooleanSimplification::simplify((*j)[0]); + if(conj.getKind() == kind::AND && conj.getNumChildren() > 6) { + eligible = false; + Debug("miplib") << " -- INELIGIBLE -- (N-ary /\\ too big)" << endl; + break; + } + if(conj.getKind() != kind::AND && !conj.isVar() && !(conj.getKind() == kind::NOT && conj[0].isVar())) { + eligible = false; + Debug("miplib") << " -- INELIGIBLE -- (not /\\ or literal)" << endl; + break; + } + if((*j)[1].getKind() != kind::EQUAL || + !( ( (*j)[1][0].isVar() && + (*j)[1][1].getKind() == kind::CONST_RATIONAL ) || + ( (*j)[1][0].getKind() == kind::CONST_RATIONAL && + (*j)[1][1].isVar() ) )) { + eligible = false; + Debug("miplib") << " -- INELIGIBLE -- (=> (and X X) X)" << endl; + break; + } + if(conj.getKind() == kind::AND) { + vector<Node> posv; + bool found_x = false; + map<TNode, bool> neg; + for(Node::iterator ii = conj.begin(); ii != conj.end(); ++ii) { + if((*ii).isVar()) { + posv.push_back(*ii); + neg[*ii] = false; + found_x = found_x || *i == *ii; + } else if((*ii).getKind() == kind::NOT && (*ii)[0].isVar()) { + posv.push_back((*ii)[0]); + neg[(*ii)[0]] = true; + found_x = found_x || *i == (*ii)[0]; + } else { + eligible = false; + Debug("miplib") << " -- INELIGIBLE -- (non-var: " << *ii << ")" << endl; + break; + } + if(d_propagator.isAssigned(posv.back())) { + eligible = false; + Debug("miplib") << " -- INELIGIBLE -- (" << posv.back() << " asserted)" << endl; + break; + } + } + if(!eligible) { + break; + } + if(!found_x) { + eligible = false; + Debug("miplib") << " --INELIGIBLE -- (couldn't find " << *i << " in conjunction)" << endl; + break; + } + sort(posv.begin(), posv.end()); + const Node pos = NodeManager::currentNM()->mkNode(kind::AND, posv); + const TNode var = ((*j)[1][0].getKind() == kind::CONST_RATIONAL) ? (*j)[1][1] : (*j)[1][0]; + const pair<Node, Node> pos_var(pos, var); + const Rational& constant = ((*j)[1][0].getKind() == kind::CONST_RATIONAL) ? (*j)[1][0].getConst<Rational>() : (*j)[1][1].getConst<Rational>(); + uint64_t mark = 0; + unsigned countneg = 0, thepos = 0; + for(unsigned ii = 0; ii < pos.getNumChildren(); ++ii) { + if(neg[pos[ii]]) { + ++countneg; + } else { + thepos = ii; + mark |= (0x1 << ii); + } + } + if((marks[pos_var] & (1lu << mark)) != 0) { + eligible = false; + Debug("miplib") << " -- INELIGIBLE -- (remarked)" << endl; + break; + } + Debug("miplib") << "mark is " << mark << " -- " << (1lu << mark) << endl; + marks[pos_var] |= (1lu << mark); + Debug("miplib") << "marks[" << pos << "," << var << "] now " << marks[pos_var] << endl; + if(countneg == pos.getNumChildren()) { + if(constant != 0) { + eligible = false; + Debug("miplib") << " -- INELIGIBLE -- (nonzero constant)" << endl; + break; + } + } else if(countneg == pos.getNumChildren() - 1) { + Assert(coef[pos_var].size() <= 6 && thepos < 6); + coef[pos_var].resize(6); + coef[pos_var][thepos] = constant; + } else { + if(checks[pos_var].size() <= mark) { + checks[pos_var].resize(mark + 1); + } + checks[pos_var][mark] = constant; + } + asserts[pos_var].push_back(*j); + } else { + TNode x = conj; + if(x != *i && x != (*i).notNode()) { + eligible = false; + Debug("miplib") << " -- INELIGIBLE -- (x not present where I expect it)" << endl; + break; + } + const bool xneg = (x.getKind() == kind::NOT); + x = xneg ? x[0] : x; + Debug("miplib") << " x:" << x << " " << xneg << endl; + const TNode var = ((*j)[1][0].getKind() == kind::CONST_RATIONAL) ? (*j)[1][1] : (*j)[1][0]; + const pair<Node, Node> x_var(x, var); + const Rational& constant = ((*j)[1][0].getKind() == kind::CONST_RATIONAL) ? (*j)[1][0].getConst<Rational>() : (*j)[1][1].getConst<Rational>(); + unsigned mark = (xneg ? 0 : 1); + if((marks[x_var] & (1u << mark)) != 0) { + eligible = false; + Debug("miplib") << " -- INELIGIBLE -- (remarked)" << endl; + break; + } + marks[x_var] |= (1u << mark); + if(xneg) { + if(constant != 0) { + eligible = false; + Debug("miplib") << " -- INELIGIBLE -- (nonzero constant)" << endl; + break; + } + } else { + Assert(coef[x_var].size() <= 6); + coef[x_var].resize(6); + coef[x_var][0] = constant; + if(checks[x_var].size() <= mark) { + checks[x_var].resize(mark + 1); + } + checks[x_var][mark] = constant; + } + asserts[x_var].push_back(*j); + } + } + if(eligible) { + for(map<pair<Node, Node>, uint64_t>::const_iterator j = marks.begin(); j != marks.end(); ++j) { + const TNode pos = (*j).first.first; + const TNode var = (*j).first.second; + const pair<Node, Node>& pos_var = (*j).first; + const uint64_t mark = (*j).second; + const unsigned numVars = pos.getKind() == kind::AND ? pos.getNumChildren() : 1; + uint64_t expected = (uint64_t(1) << (1 << numVars)) - 1; + expected = (expected == 0) ? -1 : expected;// fix for overflow + Debug("miplib") << "[" << pos << "] => " << hex << mark << " expect " << expected << dec << endl; + Assert(pos.getKind() == kind::AND || pos.isVar()); + if(mark != expected) { + Debug("miplib") << " -- INELIGIBLE " << pos << " -- (insufficiently marked, got " << mark << " for " << numVars << " vars, expected " << expected << endl; + } else { + if(false) { //checks[pos] != coef[pos][0] + coef[pos][1]) { + Debug("miplib") << " -- INELIGIBLE " << pos << " -- (not linear combination)" << endl; + } else { + Debug("miplib") << " -- ELIGIBLE " << *i << " , " << pos << " --" << endl; + vector<Node> newVars; + expr::NodeSelfIterator ii, iiend; + if(pos.getKind() == kind::AND) { + ii = pos.begin(); + iiend = pos.end(); + } else { + ii = expr::NodeSelfIterator::self(pos); + iiend = expr::NodeSelfIterator::selfEnd(pos); + } + for(; ii != iiend; ++ii) { + Node& varRef = intVars[*ii]; + if(varRef.isNull()) { + stringstream ss; + ss << "mipvar_" << *ii; + Node newVar = nm->mkSkolem(ss.str(), nm->integerType(), "a variable introduced due to scrubbing a miplib encoding", NodeManager::SKOLEM_EXACT_NAME); + Node geq = Rewriter::rewrite(nm->mkNode(kind::GEQ, newVar, zero)); + Node leq = Rewriter::rewrite(nm->mkNode(kind::LEQ, newVar, one)); + d_assertionsToCheck.push_back(Rewriter::rewrite(geq.andNode(leq))); + SubstitutionMap nullMap(&d_fakeContext); + Theory::PPAssertStatus status CVC4_UNUSED;// just for assertions + status = d_smt.d_theoryEngine->solve(geq, nullMap); + Assert(status == Theory::PP_ASSERT_STATUS_UNSOLVED, + "unexpected solution from arith's ppAssert()"); + Assert(nullMap.empty(), + "unexpected substitution from arith's ppAssert()"); + status = d_smt.d_theoryEngine->solve(leq, nullMap); + Assert(status == Theory::PP_ASSERT_STATUS_UNSOLVED, + "unexpected solution from arith's ppAssert()"); + Assert(nullMap.empty(), + "unexpected substitution from arith's ppAssert()"); + d_smt.d_theoryEngine->getModel()->addSubstitution(*ii, newVar.eqNode(one)); + newVars.push_back(newVar); + varRef = newVar; + } else { + newVars.push_back(varRef); + } + if(!d_smt.d_logic.areIntegersUsed()) { + d_smt.d_logic = d_smt.d_logic.getUnlockedCopy(); + d_smt.d_logic.enableIntegers(); + d_smt.d_logic.lock(); + } + } + Node sum; + if(pos.getKind() == kind::AND) { + NodeBuilder<> sumb(kind::PLUS); + for(size_t ii = 0; ii < pos.getNumChildren(); ++ii) { + sumb << nm->mkNode(kind::MULT, nm->mkConst(coef[pos_var][ii]), newVars[ii]); + } + sum = sumb; + } else { + sum = nm->mkNode(kind::MULT, nm->mkConst(coef[pos_var][0]), newVars[0]); + } + Debug("miplib") << "vars[] " << var << endl + << " eq " << Rewriter::rewrite(sum) << endl; + Node newAssertion = var.eqNode(Rewriter::rewrite(sum)); + if(d_topLevelSubstitutions.hasSubstitution(newAssertion[0])) { + //Warning() << "RE-SUBSTITUTION " << newAssertion[0] << endl; + //Warning() << "REPLACE " << newAssertion[1] << endl; + //Warning() << "ORIG " << d_topLevelSubstitutions.getSubstitution(newAssertion[0]) << endl; + Assert(d_topLevelSubstitutions.getSubstitution(newAssertion[0]) == newAssertion[1]); + } else if(pos.getNumChildren() <= options::arithMLTrickSubstitutions()) { + d_topLevelSubstitutions.addSubstitution(newAssertion[0], newAssertion[1]); + Debug("miplib") << "addSubs: " << newAssertion[0] << " to " << newAssertion[1] << endl; + } else { + Debug("miplib") << "skipSubs: " << newAssertion[0] << " to " << newAssertion[1] << " (threshold is " << options::arithMLTrickSubstitutions() << ")" << endl; + } + newAssertion = Rewriter::rewrite(newAssertion); + Debug("miplib") << " " << newAssertion << endl; + d_assertionsToCheck.push_back(newAssertion); + Debug("miplib") << " assertions to remove: " << endl; + for(vector<TNode>::const_iterator k = asserts[pos_var].begin(), k_end = asserts[pos_var].end(); k != k_end; ++k) { + Debug("miplib") << " " << *k << endl; + removeAssertions.insert((*k).getId()); + } + } + } + } + } + } + if(!removeAssertions.empty()) { + Debug("miplib") << "SmtEnginePrivate::simplify(): scrubbing miplib encoding..." << endl; + Node trueNode = nm->mkConst(true); + for(size_t i = 0; i < d_realAssertionsEnd; ++i) { + if(removeAssertions.find(d_assertionsToCheck[i].getId()) != removeAssertions.end()) { + Debug("miplib") << "SmtEnginePrivate::simplify(): - removing " << d_assertionsToCheck[i] << endl; + d_assertionsToCheck[i] = trueNode; + ++d_smt.d_stats->d_numMiplibAssertionsRemoved; + } else if(d_assertionsToCheck[i].getKind() == kind::AND) { + size_t removals = removeFromConjunction(d_assertionsToCheck[i], removeAssertions); + if(removals > 0) { + Debug("miplib") << "SmtEnginePrivate::simplify(): - reduced " << d_assertionsToCheck[i] << endl; + Debug("miplib") << "SmtEnginePrivate::simplify(): - by " << removals << " conjuncts" << endl; + d_smt.d_stats->d_numMiplibAssertionsRemoved += removals; + } + } + Debug("miplib") << "had: " << d_assertionsToCheck[i] << endl; + d_assertionsToCheck[i] = Rewriter::rewrite(d_topLevelSubstitutions.apply(d_assertionsToCheck[i])); + Debug("miplib") << "now: " << d_assertionsToCheck[i] << endl; + } + } else { + Debug("miplib") << "SmtEnginePrivate::simplify(): miplib pass found nothing." << endl; + } + d_realAssertionsEnd = d_assertionsToCheck.size(); +} + // returns false if simplification led to "false" bool SmtEnginePrivate::simplifyAssertions() throw(TypeCheckingException, LogicException) { @@ -1904,21 +2313,49 @@ bool SmtEnginePrivate::simplifyAssertions() if(options::simplificationMode() != SIMPLIFICATION_MODE_NONE) { // Perform non-clausal simplification + Chat() << "...performing nonclausal simplification..." << endl; Trace("simplify") << "SmtEnginePrivate::simplify(): " << "performing non-clausal simplification" << endl; bool noConflict = nonClausalSimplify(); - if(!noConflict) return false; + if(!noConflict) { + return false; + } + + // We piggy-back off of the BackEdgesMap in the CircuitPropagator to + // do the miplib trick. + if( // check that option is on + options::arithMLTrick() && + // miplib rewrites aren't safe in incremental mode + ! options::incrementalSolving() && + // only useful in arith + d_smt.d_logic.isTheoryEnabled(theory::THEORY_ARITH) && + // we add new assertions and need this (in practice, this + // restriction only disables miplib processing during + // re-simplification, which we don't expect to be useful anyway) + d_realAssertionsEnd == d_assertionsToCheck.size() ) { + Chat() << "...fixing miplib encodings..." << endl; + Trace("simplify") << "SmtEnginePrivate::simplify(): " + << "looking for miplib pseudobooleans..." << endl; + + TimerStat::CodeTimer miplibTimer(d_smt.d_stats->d_miplibPassTime); + + doMiplibTrick(); + } else { + Trace("simplify") << "SmtEnginePrivate::simplify(): " + << "skipping miplib pseudobooleans pass (either incrementalSolving is on, or miplib pbs are turned off)..." << endl; + } } else { Assert(d_assertionsToCheck.empty()); d_assertionsToCheck.swap(d_assertionsToPreprocess); } - Trace("smt") << "POST nonClasualSimplify" << std::endl; + Trace("smt") << "POST nonClausalSimplify" << endl; Debug("smt") << " d_assertionsToPreprocess: " << d_assertionsToPreprocess.size() << endl; Debug("smt") << " d_assertionsToCheck : " << d_assertionsToCheck.size() << endl; // Theory preprocessing if (d_smt.d_earlyTheoryPP) { + Chat() << "...doing early theory preprocessing..." << endl; TimerStat::CodeTimer codeTimer(d_smt.d_stats->d_theoryPreprocessTime); // Call the theory preprocessors d_smt.d_theoryEngine->preprocessStart(); @@ -1929,31 +2366,34 @@ bool SmtEnginePrivate::simplifyAssertions() } } - Trace("smt") << "POST theoryPP" << std::endl; + Trace("smt") << "POST theoryPP" << endl; Debug("smt") << " d_assertionsToPreprocess: " << d_assertionsToPreprocess.size() << endl; Debug("smt") << " d_assertionsToCheck : " << d_assertionsToCheck.size() << endl; // ITE simplification if(options::doITESimp()) { + Chat() << "...doing ITE simplification..." << endl; simpITE(); } - Trace("smt") << "POST iteSimp" << std::endl; + Trace("smt") << "POST iteSimp" << endl; Debug("smt") << " d_assertionsToPreprocess: " << d_assertionsToPreprocess.size() << endl; Debug("smt") << " d_assertionsToCheck : " << d_assertionsToCheck.size() << endl; // Unconstrained simplification if(options::unconstrainedSimp()) { + Chat() << "...doing unconstrained simplification..." << endl; unconstrainedSimp(); } - Trace("smt") << "POST unconstrainedSimp" << std::endl; + Trace("smt") << "POST unconstrainedSimp" << endl; Debug("smt") << " d_assertionsToPreprocess: " << d_assertionsToPreprocess.size() << endl; Debug("smt") << " d_assertionsToCheck : " << d_assertionsToCheck.size() << endl; if(options::repeatSimp() && options::simplificationMode() != SIMPLIFICATION_MODE_NONE) { + Chat() << "...doing another round of nonclausal simplification..." << endl; Trace("simplify") << "SmtEnginePrivate::simplify(): " - << " doing repeated simplification" << std::endl; + << " doing repeated simplification" << endl; d_assertionsToCheck.swap(d_assertionsToPreprocess); Assert(d_assertionsToCheck.empty()); bool noConflict = nonClausalSimplify(); @@ -1962,7 +2402,7 @@ bool SmtEnginePrivate::simplifyAssertions() } } - Trace("smt") << "POST repeatSimp" << std::endl; + Trace("smt") << "POST repeatSimp" << endl; Debug("smt") << " d_assertionsToPreprocess: " << d_assertionsToPreprocess.size() << endl; Debug("smt") << " d_assertionsToCheck : " << d_assertionsToCheck.size() << endl; @@ -2012,6 +2452,7 @@ Result SmtEngine::check() { resource = d_resourceBudgetPerCall; } + Chat() << "solving..." << endl; Trace("smt") << "SmtEngine::check(): running check" << endl; Result result = d_propEngine->checkSat(millis, resource); @@ -2188,11 +2629,11 @@ void SmtEnginePrivate::processAssertions() { //apply pre-skolemization to existential quantifiers for (unsigned i = 0; i < d_assertionsToPreprocess.size(); ++ i) { Node prev = d_assertionsToPreprocess[i]; - std::vector< Node > fvs; + vector< Node > fvs; d_assertionsToPreprocess[i] = Rewriter::rewrite( preSkolemizeQuantifiers( d_assertionsToPreprocess[i], true, fvs ) ); if( prev!=d_assertionsToPreprocess[i] ){ - Trace("quantifiers-rewrite") << "*** Pre-skolemize " << prev << std::endl; - Trace("quantifiers-rewrite") << " ...got " << d_assertionsToPreprocess[i] << std::endl; + Trace("quantifiers-rewrite") << "*** Pre-skolemize " << prev << endl; + Trace("quantifiers-rewrite") << " ...got " << d_assertionsToPreprocess[i] << endl; } } } @@ -2209,8 +2650,7 @@ void SmtEnginePrivate::processAssertions() { if( options::sortInference() ){ //sort inference technique - SortInference si; - si.simplify( d_assertionsToPreprocess ); + d_smt.d_theoryEngine->getSortInference()->simplify( d_assertionsToPreprocess ); } dumpAssertions("pre-simplify", d_assertionsToPreprocess); @@ -2242,7 +2682,7 @@ void SmtEnginePrivate::processAssertions() { dumpAssertions("pre-repeat-simplify", d_assertionsToCheck); if(options::repeatSimp()) { d_assertionsToCheck.swap(d_assertionsToPreprocess); - Chat() << "simplifying assertions..." << endl; + Chat() << "re-simplifying assertions..." << endl; noConflict &= simplifyAssertions(); if (noConflict) { // Need to fix up assertion list to maintain invariants: @@ -2600,7 +3040,7 @@ Expr SmtEngine::expandDefinitions(const Expr& ex) throw(TypeCheckingException, L return n.toExpr(); } -Expr SmtEngine::getValue(const Expr& ex) throw(ModalException, LogicException) { +Expr SmtEngine::getValue(const Expr& ex) throw(ModalException, TypeCheckingException, LogicException) { Assert(ex.getExprManager() == d_exprManager); SmtScope smts(this); @@ -2908,6 +3348,7 @@ void SmtEngine::checkModel(bool hardFailure) { hash_map<Node, Node, NodeHashFunction> cache; n = d_private->expandDefinitions(n, cache); } + Notice() << "SmtEngine::checkModel(): -- expands to " << n << endl; // Apply our model value substitutions. n = substitutions.apply(n); @@ -2929,6 +3370,12 @@ void SmtEngine::checkModel(bool hardFailure) { continue; } + // As a last-ditch effort, ask model to simplify it. + // Presently, this is only an issue for quantifiers, which can have a value + // but don't show up in our substitution map above. + n = m->getValue(n); + Notice() << "SmtEngine::checkModel(): -- model-substitutes to " << n << endl; + // The result should be == true. if(n != NodeManager::currentNM()->mkConst(true)) { Notice() << "SmtEngine::checkModel(): *** PROBLEM: EXPECTED `TRUE' ***" diff --git a/src/smt/smt_engine.h b/src/smt/smt_engine.h index cdae68d96..fecfba14a 100644 --- a/src/smt/smt_engine.h +++ b/src/smt/smt_engine.h @@ -444,7 +444,7 @@ public: * by a SAT or INVALID query). Only permitted if the SmtEngine is * set to operate interactively and produce-models is on. */ - Expr getValue(const Expr& e) throw(ModalException, LogicException); + Expr getValue(const Expr& e) throw(ModalException, TypeCheckingException, LogicException); /** * Add a function to the set of expressions whose value is to be diff --git a/src/theory/arith/arith_static_learner.cpp b/src/theory/arith/arith_static_learner.cpp index 4ee176cf1..124fa8e2a 100644 --- a/src/theory/arith/arith_static_learner.cpp +++ b/src/theory/arith/arith_static_learner.cpp @@ -21,8 +21,6 @@ #include "theory/arith/arith_static_learner.h" #include "theory/arith/options.h" -#include "util/propositional_query.h" - #include "expr/expr.h" #include "expr/convenience_node_builders.h" @@ -37,7 +35,6 @@ namespace arith { ArithStaticLearner::ArithStaticLearner(context::Context* userContext) : - d_miplibTrick(userContext), d_minMap(userContext), d_maxMap(userContext), d_statistics() @@ -45,30 +42,17 @@ ArithStaticLearner::ArithStaticLearner(context::Context* userContext) : ArithStaticLearner::Statistics::Statistics(): d_iteMinMaxApplications("theory::arith::iteMinMaxApplications", 0), - d_iteConstantApplications("theory::arith::iteConstantApplications", 0), - d_miplibtrickApplications("theory::arith::miplibtrickApplications", 0), - d_avgNumMiplibtrickValues("theory::arith::avgNumMiplibtrickValues") + d_iteConstantApplications("theory::arith::iteConstantApplications", 0) { StatisticsRegistry::registerStat(&d_iteMinMaxApplications); StatisticsRegistry::registerStat(&d_iteConstantApplications); - StatisticsRegistry::registerStat(&d_miplibtrickApplications); - StatisticsRegistry::registerStat(&d_avgNumMiplibtrickValues); } ArithStaticLearner::Statistics::~Statistics(){ StatisticsRegistry::unregisterStat(&d_iteMinMaxApplications); StatisticsRegistry::unregisterStat(&d_iteConstantApplications); - StatisticsRegistry::unregisterStat(&d_miplibtrickApplications); - StatisticsRegistry::unregisterStat(&d_avgNumMiplibtrickValues); -} - -void ArithStaticLearner::miplibTrickInsert(Node key, Node value){ - if(options::arithMLTrick()){ - d_miplibTrick.insert(key, value); - } } - void ArithStaticLearner::staticLearning(TNode n, NodeBuilder<>& learned){ vector<TNode> workList; @@ -111,8 +95,6 @@ void ArithStaticLearner::staticLearning(TNode n, NodeBuilder<>& learned){ process(n,learned, defTrue); } - - postProcess(learned); } @@ -134,24 +116,6 @@ void ArithStaticLearner::process(TNode n, NodeBuilder<>& learned, const TNodeSet iteConstant(n, learned); } break; - case IMPLIES: - // == 3-FINITE VALUE SET : Collect information == - if(n[1].getKind() == EQUAL && - n[1][0].isVar() && - defTrue.find(n) != defTrue.end()){ - Node eqTo = n[1][1]; - Node rewriteEqTo = Rewriter::rewrite(eqTo); - if(rewriteEqTo.getKind() == CONST_RATIONAL){ - - TNode var = n[1][0]; - Node current = (d_miplibTrick.find(var) == d_miplibTrick.end()) ? - mkBoolNode(false) : d_miplibTrick[var]; - - miplibTrickInsert(var, n.orNode(current)); - Debug("arith::miplib") << "insert " << var << " const " << n << endl; - } - } - break; case CONST_RATIONAL: // Mark constants as minmax d_minMap.insert(n, n.getConst<Rational>()); @@ -300,99 +264,6 @@ std::set<Node> listToSet(TNode l){ return ret; } -void ArithStaticLearner::postProcess(NodeBuilder<>& learned){ - // == 3-FINITE VALUE SET == - CDNodeToNodeListMap::const_iterator keyIter = d_miplibTrick.begin(); - CDNodeToNodeListMap::const_iterator endKeys = d_miplibTrick.end(); - while(keyIter != endKeys) { - TNode var = (*keyIter).first; - Node list = (*keyIter).second; - const set<Node> imps = listToSet(list); - - if(imps.empty()){ - ++keyIter; - continue; - } - - Assert(!imps.empty()); - vector<Node> conditions; - set<Rational> values; - set<Node>::const_iterator j=imps.begin(), impsEnd=imps.end(); - for(; j != impsEnd; ++j){ - TNode imp = *j; - Assert(imp.getKind() == IMPLIES); - Assert(imp[1].getKind() == EQUAL); - - Node eqTo = imp[1][1]; - Node rewriteEqTo = Rewriter::rewrite(eqTo); - Assert(rewriteEqTo.getKind() == CONST_RATIONAL); - - conditions.push_back(imp[0]); - values.insert(rewriteEqTo.getConst<Rational>()); - } - - Node possibleTaut = Node::null(); - if(conditions.size() == 1){ - possibleTaut = conditions.front(); - }else{ - NodeBuilder<> orBuilder(OR); - orBuilder.append(conditions); - possibleTaut = orBuilder; - } - - - Debug("arith::miplib") << "var: " << var << endl; - Debug("arith::miplib") << "possibleTaut: " << possibleTaut << endl; - - Result isTaut = PropositionalQuery::isTautology(possibleTaut); - if(isTaut == Result(Result::VALID)){ - miplibTrick(var, values, learned); - miplibTrickInsert(var, mkBoolNode(false)); - } - ++keyIter; - } -} - - -void ArithStaticLearner::miplibTrick(TNode var, set<Rational>& values, NodeBuilder<>& learned){ - - Debug("arith::miplib") << var << " found a tautology!"<< endl; - - const Rational& min = *(values.begin()); - const Rational& max = *(values.rbegin()); - - Debug("arith::miplib") << "min: " << min << endl; - Debug("arith::miplib") << "max: " << max << endl; - - Assert(min <= max); - ++(d_statistics.d_miplibtrickApplications); - (d_statistics.d_avgNumMiplibtrickValues).addEntry(values.size()); - - Node nGeqMin = NodeBuilder<2>(GEQ) << var << mkRationalNode(min); - Node nLeqMax = NodeBuilder<2>(LEQ) << var << mkRationalNode(max); - Debug("arith::miplib") << nGeqMin << nLeqMax << endl; - learned << nGeqMin << nLeqMax; - set<Rational>::iterator valuesIter = values.begin(); - set<Rational>::iterator valuesEnd = values.end(); - set<Rational>::iterator valuesPrev = valuesIter; - ++valuesIter; - for(; valuesIter != valuesEnd; valuesPrev = valuesIter, ++valuesIter){ - const Rational& prev = *valuesPrev; - const Rational& curr = *valuesIter; - Assert(prev < curr); - - //The interval (last,curr) can be excluded: - //(not (and (> var prev) (< var curr)) - //<=> (or (not (> var prev)) (not (< var curr))) - //<=> (or (<= var prev) (>= var curr)) - Node leqPrev = NodeBuilder<2>(LEQ) << var << mkRationalNode(prev); - Node geqCurr = NodeBuilder<2>(GEQ) << var << mkRationalNode(curr); - Node excludedMiddle = NodeBuilder<2>(OR) << leqPrev << geqCurr; - Debug("arith::miplib") << excludedMiddle << endl; - learned << excludedMiddle; - } -} - void ArithStaticLearner::addBound(TNode n) { CDNodeToMinMaxMap::const_iterator minFind = d_minMap.find(n[0]); diff --git a/src/theory/arith/arith_static_learner.h b/src/theory/arith/arith_static_learner.h index 041ae6339..48ee6a3bb 100644 --- a/src/theory/arith/arith_static_learner.h +++ b/src/theory/arith/arith_static_learner.h @@ -37,16 +37,6 @@ namespace arith { class ArithStaticLearner { private: - /* Maps a variable, x, to the set of defTrue nodes of the form - * (=> _ (= x c)) - * where c is a constant. - */ - typedef context::CDTrailHashMap<Node, Node, NodeHashFunction> CDNodeToNodeListMap; - // The domain is an implicit list OR(x, OR(y, ..., FALSE )) - // or FALSE - CDNodeToNodeListMap d_miplibTrick; - void miplibTrickInsert(Node key, Node value); - /** * Map from a node to it's minimum and maximum. */ @@ -63,23 +53,15 @@ public: private: void process(TNode n, NodeBuilder<>& learned, const TNodeSet& defTrue); - void postProcess(NodeBuilder<>& learned); - void iteMinMax(TNode n, NodeBuilder<>& learned); void iteConstant(TNode n, NodeBuilder<>& learned); - void miplibTrick(TNode var, std::set<Rational>& values, NodeBuilder<>& learned); - - /** These fields are designed to be accessible to ArithStaticLearner methods. */ class Statistics { public: IntStat d_iteMinMaxApplications; IntStat d_iteConstantApplications; - IntStat d_miplibtrickApplications; - AverageStat d_avgNumMiplibtrickValues; - Statistics(); ~Statistics(); }; diff --git a/src/theory/arith/constraint.cpp b/src/theory/arith/constraint.cpp index cf3aeafee..4655ea34e 100644 --- a/src/theory/arith/constraint.cpp +++ b/src/theory/arith/constraint.cpp @@ -371,8 +371,8 @@ void ConstraintValue::setAssertedToTheTheory(TNode witness) { d_database->pushAssertionOrderWatch(this, witness); } -// bool ConstraintValue::isPsuedoConstraint() const { -// return d_proof == d_database->d_psuedoConstraintProof; +// bool ConstraintValue::isPseudoConstraint() const { +// return d_proof == d_database->d_pseudoConstraintProof; // } bool ConstraintValue::isSelfExplaining() const { @@ -486,7 +486,7 @@ ConstraintDatabase::ConstraintDatabase(context::Context* satContext, context::Co d_equalityEngineProof = d_proofs.size(); d_proofs.push_back(NullConstraint); - // d_psuedoConstraintProof = d_proofs.size(); + // d_pseudoConstraintProof = d_proofs.size(); // d_proofs.push_back(NullConstraint); } @@ -833,11 +833,11 @@ void ConstraintValue::impliedBy(const std::vector<Constraint>& b){ } } -// void ConstraintValue::setPsuedoConstraint(){ +// void ConstraintValue::setPseudoConstraint(){ // Assert(truthIsUnknown()); // Assert(!hasLiteral()); -// d_database->pushProofWatch(this, d_database->d_psuedoConstraintProof); +// d_database->pushProofWatch(this, d_database->d_pseudoConstraintProof); // } void ConstraintValue::setEqualityEngineProof(){ @@ -856,7 +856,7 @@ void ConstraintValue::markAsTrue(){ void ConstraintValue::markAsTrue(Constraint imp){ Assert(truthIsUnknown()); Assert(imp->hasProof()); - //Assert(!imp->isPsuedoConstraint()); + //Assert(!imp->isPseudoConstraint()); d_database->d_proofs.push_back(NullConstraint); d_database->d_proofs.push_back(imp); @@ -868,8 +868,8 @@ void ConstraintValue::markAsTrue(Constraint impA, Constraint impB){ Assert(truthIsUnknown()); Assert(impA->hasProof()); Assert(impB->hasProof()); - //Assert(!impA->isPsuedoConstraint()); - //Assert(!impB->isPsuedoConstraint()); + //Assert(!impA->isPseudoConstraint()); + //Assert(!impB->isPseudoConstraint()); d_database->d_proofs.push_back(NullConstraint); d_database->d_proofs.push_back(impA); @@ -886,7 +886,7 @@ void ConstraintValue::markAsTrue(const vector<Constraint>& a){ for(vector<Constraint>::const_iterator i = a.begin(), end = a.end(); i != end; ++i){ Constraint c_i = *i; Assert(c_i->hasProof()); - //Assert(!c_i->isPsuedoConstraint()); + //Assert(!c_i->isPseudoConstraint()); d_database->d_proofs.push_back(c_i); } @@ -903,7 +903,7 @@ SortedConstraintMap& ConstraintValue::constraintSet() const{ bool ConstraintValue::proofIsEmpty() const{ Assert(hasProof()); bool result = d_database->d_proofs[d_proof] == NullConstraint; - //Assert((!result) || isSelfExplaining() || hasEqualityEngineProof() || isPsuedoConstraint()); + //Assert((!result) || isSelfExplaining() || hasEqualityEngineProof() || isPseudoConstraint()); Assert((!result) || isSelfExplaining() || hasEqualityEngineProof()); return result; } diff --git a/src/theory/arith/constraint.h b/src/theory/arith/constraint.h index 52aa5a5ce..82023a48b 100644 --- a/src/theory/arith/constraint.h +++ b/src/theory/arith/constraint.h @@ -273,7 +273,7 @@ private: */ AssertionOrder _d_assertionOrder; /** - * This is guarenteed to be on the fact queue. + * This is guaranteed to be on the fact queue. * For example if x + y = x + 1 is on the fact queue, then use this */ TNode d_witness; @@ -491,8 +491,8 @@ public: * The explanation is the constant true. * explainInto() does nothing. */ - //void setPsuedoConstraint(); - //bool isPsuedoConstraint() const; + //void setPseudoConstraint(); + //bool isPseudoConstraint() const; /** * Returns a explanation of the constraint that is appropriate for conflicts. @@ -709,7 +709,7 @@ private: * * This is a special proof that is always a member of the list. */ - //ProofId d_psuedoConstraintProof; + //ProofId d_pseudoConstraintProof; typedef context::CDList<Constraint, ConstraintValue::ProofCleanup> ProofCleanupList; typedef context::CDList<Constraint, ConstraintValue::CanBePropagatedCleanup> CBPList; diff --git a/src/theory/arith/delta_rational.h b/src/theory/arith/delta_rational.h index 19a16d558..51c1e5138 100644 --- a/src/theory/arith/delta_rational.h +++ b/src/theory/arith/delta_rational.h @@ -249,7 +249,7 @@ public: } /** - * Computes a sufficient upperbound to seperate two DeltaRationals. + * Computes a sufficient upperbound to separate two DeltaRationals. * This value is stored in res. * For any rational d such that * 0 < d < res diff --git a/src/theory/arith/options b/src/theory/arith/options index 719c826ae..efe594766 100644 --- a/src/theory/arith/options +++ b/src/theory/arith/options @@ -51,13 +51,15 @@ option arithRewriteEq --enable-arith-rewrite-equalities/--disable-arith-rewrite- turns on the preprocessing rewrite turning equalities into a conjunction of inequalities /turns off the preprocessing rewrite turning equalities into a conjunction of inequalities -option arithMLTrick --enable-miplib-trick/--disable-miplib-trick bool :default false :read-write +option arithMLTrick miplib-trick --enable-miplib-trick/--disable-miplib-trick bool :default false turns on the preprocessing step of attempting to infer bounds on miplib problems /turns off the preprocessing step of attempting to infer bounds on miplib problems +option arithMLTrickSubstitutions miplib-trick-subs --miplib-trick-subs unsigned :default 1 + do substitution for miplib 'tmp' vars if defined in <= N eliminated vars + option doCutAllBounded --enable-cut-all-bounded/--disable-cut-all-bounded bool :default false :read-write turns on the integer solving step of periodically cutting all integer variables that have both upper and lower bounds -/ turns off the integer solving step of periodically cutting all integer variables that have both upper and lower bounds - +/turns off the integer solving step of periodically cutting all integer variables that have both upper and lower bounds endmodule diff --git a/src/theory/arith/options_handlers.h b/src/theory/arith/options_handlers.h index 52e7cbf2a..f8f851964 100644 --- a/src/theory/arith/options_handlers.h +++ b/src/theory/arith/options_handlers.h @@ -52,7 +52,7 @@ This decides on kind of propagation arithmetic attempts to do during the search. "; static const std::string heuristicPivotRulesHelp = "\ -This decides on the rule used by simplex during hueristic rounds\n\ +This decides on the rule used by simplex during heuristic rounds\n\ for deciding the next basic variable to select.\n\ Heuristic pivot rules available:\n\ +min\n\ diff --git a/src/theory/arrays/theory_arrays.cpp b/src/theory/arrays/theory_arrays.cpp index aabd3a62d..dcf4813fc 100644 --- a/src/theory/arrays/theory_arrays.cpp +++ b/src/theory/arrays/theory_arrays.cpp @@ -1324,7 +1324,9 @@ void TheoryArrays::queueRowLemma(RowLemmaType lem) // Prefer equality between indexes so as not to introduce new read terms if (d_eagerIndexSplitting && !bothExist && !d_equalityEngine.areDisequal(i,j, false)) { - d_decisionRequests.push(i.eqNode(j)); + Node i_eq_j = d_valuation.ensureLiteral(i.eqNode(j)); + getOutputChannel().requirePhase(i_eq_j, true); + d_decisionRequests.push(i_eq_j); } // TODO: maybe add triggers here @@ -1392,7 +1394,7 @@ void TheoryArrays::queueRowLemma(RowLemmaType lem) Node TheoryArrays::getNextDecisionRequest() { if(! d_decisionRequests.empty()) { - Node n = d_valuation.ensureLiteral(d_decisionRequests.front()); + Node n = d_decisionRequests.front(); d_decisionRequests.pop(); return n; } else { diff --git a/src/theory/arrays/theory_arrays_model.cpp b/src/theory/arrays/theory_arrays_model.cpp index 86bdad53f..4f7584ac1 100644 --- a/src/theory/arrays/theory_arrays_model.cpp +++ b/src/theory/arrays/theory_arrays_model.cpp @@ -41,7 +41,7 @@ Node ArrayModel::getValue( TheoryModel* m, Node i ){ return it->second; }else{ return NodeManager::currentNM()->mkNode( SELECT, getArrayValue(), i ); - //return d_default_value; //TODO: guarentee I can return this here + //return d_default_value; //TODO: guarantee I can return this here } } diff --git a/src/theory/arrays/theory_arrays_model.h b/src/theory/arrays/theory_arrays_model.h index 8dfc7fc4a..c82c7635d 100644 --- a/src/theory/arrays/theory_arrays_model.h +++ b/src/theory/arrays/theory_arrays_model.h @@ -1,58 +1,58 @@ /********************* */ /*! \file theory_arrays_model.h ** \verbatim - ** Original author: ajreynol - ** Major contributors: none + ** Original author: Andrew Reynolds <andrew.j.reynolds@gmail.com> + ** Major contributors: Morgan Deters <mdeters@cs.nyu.edu> ** Minor contributors (to current version): none - ** This file is part of the CVC4 prototype. - ** Copyright (c) 2009-2012 New York University and The University of Iowa + ** This file is part of the CVC4 project. + ** Copyright (c) 2009-2013 New York University and The University of Iowa ** See the file COPYING in the top-level source directory for licensing ** information.\endverbatim ** - ** \brief MODEL for theory of arrays
- **/
-
-
-#include "cvc4_private.h"
-
-#ifndef __CVC4__THEORY_ARRAYS_MODEL_H
-#define __CVC4__THEORY_ARRAYS_MODEL_H
-
-#include "theory/quantifiers_engine.h"
-
-namespace CVC4 {
-namespace theory {
-
-class TheoryModel;
-
-namespace arrays {
-
-class ArrayModel{
-protected:
- /** the array this model is for */
- Node d_arr;
-public:
- ArrayModel(){}
- ArrayModel( Node arr, TheoryModel* m );
- ~ArrayModel() {}
-public:
- /** pre-defined values */
- std::map< Node, Node > d_values;
- /** base array */
- Node d_base_arr;
- /** get value, return arguments that the value depends on */
- Node getValue( TheoryModel* m, Node i );
- /** set value */
- void setValue( TheoryModel* m, Node i, Node e );
- /** set default */
- void setDefaultArray( Node arr );
-public:
- /** get array value */
- Node getArrayValue();
-};/* class ArrayModel */
-
-}
-}
-}
-
+ ** \brief MODEL for theory of arrays + **/ + + +#include "cvc4_private.h" + +#ifndef __CVC4__THEORY_ARRAYS_MODEL_H +#define __CVC4__THEORY_ARRAYS_MODEL_H + +#include "theory/quantifiers_engine.h" + +namespace CVC4 { +namespace theory { + +class TheoryModel; + +namespace arrays { + +class ArrayModel{ +protected: + /** the array this model is for */ + Node d_arr; +public: + ArrayModel(){} + ArrayModel( Node arr, TheoryModel* m ); + ~ArrayModel() {} +public: + /** pre-defined values */ + std::map< Node, Node > d_values; + /** base array */ + Node d_base_arr; + /** get value, return arguments that the value depends on */ + Node getValue( TheoryModel* m, Node i ); + /** set value */ + void setValue( TheoryModel* m, Node i, Node e ); + /** set default */ + void setDefaultArray( Node arr ); +public: + /** get array value */ + Node getArrayValue(); +};/* class ArrayModel */ + +} +} +} + #endif
\ No newline at end of file diff --git a/src/theory/arrays/theory_arrays_rewriter.h b/src/theory/arrays/theory_arrays_rewriter.h index da479616d..9cbb0c9e8 100644 --- a/src/theory/arrays/theory_arrays_rewriter.h +++ b/src/theory/arrays/theory_arrays_rewriter.h @@ -37,8 +37,12 @@ typedef expr::Attribute<attr::ArrayConstantMostFrequentValueCountTag, uint64_t> typedef expr::Attribute<attr::ArrayConstantMostFrequentValueTag, Node> ArrayConstantMostFrequentValueAttr; class TheoryArraysRewriter { - static Node normalizeConstant(TNode node) { + return normalizeConstant(node, node[1].getType().getCardinality()); + } +public: + //this function is called by printers when using the option "--model-u-dt-enum" + static Node normalizeConstant(TNode node, Cardinality indexCard) { TNode store = node[0]; TNode index = node[1]; TNode value = node[2]; @@ -112,7 +116,6 @@ class TheoryArraysRewriter { return n; } - Cardinality indexCard = index.getType().getCardinality(); if (indexCard.isInfinite()) { return n; } @@ -189,13 +192,15 @@ class TheoryArraysRewriter { std::vector<Node> newIndices; TypeEnumerator te(index.getType()); bool needToSort = false; - while (!te.isFinished()) { + unsigned numTe = 0; + while (!te.isFinished() && (!indexCard.isFinite() || numTe<indexCard.getFiniteCardinality().toUnsignedInt())) { if (indexSet.find(*te) == indexSet.end()) { if (!newIndices.empty() && (!(newIndices.back() < (*te)))) { needToSort = true; } newIndices.push_back(*te); } + ++numTe; ++te; } Assert(indexCard.compare(newIndices.size() + depth) == Cardinality::EQUAL); diff --git a/src/theory/booleans/circuit_propagator.h b/src/theory/booleans/circuit_propagator.h index aec0cff58..de4bb30d2 100644 --- a/src/theory/booleans/circuit_propagator.h +++ b/src/theory/booleans/circuit_propagator.h @@ -64,6 +64,8 @@ public: else return ASSIGNED_TO_TRUE; } + typedef std::hash_map<Node, std::vector<Node>, NodeHashFunction> BackEdgesMap; + private: context::Context d_context; @@ -96,7 +98,7 @@ private: */ DataClearer< std::vector<TNode> > d_propagationQueueClearer; - /** Are we in conflict */ + /** Are we in conflict? */ context::CDO<bool> d_conflict; /** Map of substitutions */ @@ -107,8 +109,9 @@ private: */ DataClearer< std::vector<Node> > d_learnedLiteralClearer; - /** Back edges from nodes to where they are used */ - typedef std::hash_map<Node, std::vector<Node>, NodeHashFunction> BackEdgesMap; + /** + * Back edges from nodes to where they are used. + */ BackEdgesMap d_backEdges; /** @@ -157,6 +160,7 @@ private: } } +public: /** True iff Node is assigned in circuit (either true or false). */ bool isAssigned(TNode n) const { AssignmentMap::const_iterator i = d_state.find(n); @@ -179,6 +183,7 @@ private: return (*i).second == ASSIGNED_TO_TRUE; } +private: /** Predicate for use in STL functions. */ class IsAssigned : public std::unary_function<TNode, bool> { CircuitPropagator& d_circuit; @@ -268,6 +273,13 @@ public: */ bool propagate() CVC4_WARN_UNUSED_RESULT; + /** + * Get the back edges of this circuit. + */ + const BackEdgesMap& getBackEdges() const { + return d_backEdges; + } + };/* class CircuitPropagator */ }/* CVC4::theory::booleans namespace */ diff --git a/src/theory/bv/bitblast_strategies.cpp b/src/theory/bv/bitblast_strategies.cpp index 3ce9bcb44..773685997 100644 --- a/src/theory/bv/bitblast_strategies.cpp +++ b/src/theory/bv/bitblast_strategies.cpp @@ -191,13 +191,13 @@ Node inline sLessThanBB(const Bits&a, const Bits& b, bool orEqual) { Node UndefinedAtomBBStrategy(TNode node, Bitblaster* bb) { - BVDebug("bitvector") << "TheoryBV::Bitblaster Undefined bitblasting strategy for kind: " + Debug("bitvector") << "TheoryBV::Bitblaster Undefined bitblasting strategy for kind: " << node.getKind() << "\n"; Unreachable(); } Node DefaultEqBB(TNode node, Bitblaster* bb) { - BVDebug("bitvector-bb") << "Bitblasting node " << node << "\n"; + Debug("bitvector-bb") << "Bitblasting node " << node << "\n"; Assert(node.getKind() == kind::EQUAL); Bits lhs, rhs; @@ -219,7 +219,7 @@ Node DefaultEqBB(TNode node, Bitblaster* bb) { Node AdderUltBB(TNode node, Bitblaster* bb) { - BVDebug("bitvector-bb") << "Bitblasting node " << node << "\n"; + Debug("bitvector-bb") << "Bitblasting node " << node << "\n"; Assert(node.getKind() == kind::BITVECTOR_ULT); Bits a, b; bb->bbTerm(node[0], a); @@ -241,7 +241,7 @@ Node AdderUltBB(TNode node, Bitblaster* bb) { Node DefaultUltBB(TNode node, Bitblaster* bb) { - BVDebug("bitvector-bb") << "Bitblasting node " << node << "\n"; + Debug("bitvector-bb") << "Bitblasting node " << node << "\n"; Assert(node.getKind() == kind::BITVECTOR_ULT); Bits a, b; bb->bbTerm(node[0], a); @@ -254,7 +254,7 @@ Node DefaultUltBB(TNode node, Bitblaster* bb) { } Node DefaultUleBB(TNode node, Bitblaster* bb){ - BVDebug("bitvector-bb") << "Bitblasting node " << node << "\n"; + Debug("bitvector-bb") << "Bitblasting node " << node << "\n"; Assert(node.getKind() == kind::BITVECTOR_ULE); Bits a, b; @@ -267,31 +267,31 @@ Node DefaultUleBB(TNode node, Bitblaster* bb){ } Node DefaultUgtBB(TNode node, Bitblaster* bb){ - BVDebug("bitvector-bb") << "Bitblasting node " << node << "\n"; + Debug("bitvector-bb") << "Bitblasting node " << node << "\n"; // should be rewritten Unimplemented(); } Node DefaultUgeBB(TNode node, Bitblaster* bb){ - BVDebug("bitvector-bb") << "Bitblasting node " << node << "\n"; + Debug("bitvector-bb") << "Bitblasting node " << node << "\n"; // should be rewritten Unimplemented(); } // Node DefaultSltBB(TNode node, Bitblaster* bb){ -// BVDebug("bitvector-bb") << "Bitblasting node " << node << "\n"; +// Debug("bitvector-bb") << "Bitblasting node " << node << "\n"; // // shoudl be rewritten in terms of ult // Unimplemented(); // } // Node DefaultSleBB(TNode node, Bitblaster* bb){ -// BVDebug("bitvector-bb") << "Bitblasting node " << node << "\n"; +// Debug("bitvector-bb") << "Bitblasting node " << node << "\n"; // // shoudl be rewritten in terms of ule // Unimplemented(); // } Node DefaultSltBB(TNode node, Bitblaster* bb){ - BVDebug("bitvector-bb") << "Bitblasting node " << node << "\n"; + Debug("bitvector-bb") << "Bitblasting node " << node << "\n"; Bits a, b; bb->bbTerm(node[0], a); @@ -303,7 +303,7 @@ Node DefaultSltBB(TNode node, Bitblaster* bb){ } Node DefaultSleBB(TNode node, Bitblaster* bb){ - BVDebug("bitvector-bb") << "Bitblasting node " << node << "\n"; + Debug("bitvector-bb") << "Bitblasting node " << node << "\n"; Bits a, b; bb->bbTerm(node[0], a); @@ -315,13 +315,13 @@ Node DefaultSleBB(TNode node, Bitblaster* bb){ } Node DefaultSgtBB(TNode node, Bitblaster* bb){ - BVDebug("bitvector-bb") << "Bitblasting node " << node << "\n"; + Debug("bitvector-bb") << "Bitblasting node " << node << "\n"; // should be rewritten Unimplemented(); } Node DefaultSgeBB(TNode node, Bitblaster* bb){ - BVDebug("bitvector-bb") << "Bitblasting node " << node << "\n"; + Debug("bitvector-bb") << "Bitblasting node " << node << "\n"; // should be rewritten Unimplemented(); } @@ -330,7 +330,7 @@ Node DefaultSgeBB(TNode node, Bitblaster* bb){ /// Term bitblasting strategies void UndefinedTermBBStrategy(TNode node, Bits& bits, Bitblaster* bb) { - BVDebug("bitvector") << "theory::bv:: Undefined bitblasting strategy for kind: " + Debug("bitvector") << "theory::bv:: Undefined bitblasting strategy for kind: " << node.getKind() << "\n"; Unreachable(); } @@ -342,15 +342,15 @@ void DefaultVarBB (TNode node, Bits& bits, Bitblaster* bb) { } if(Debug.isOn("bitvector-bb")) { - BVDebug("bitvector-bb") << "theory::bv::DefaultVarBB bitblasting " << node << "\n"; - BVDebug("bitvector-bb") << " with bits " << toString(bits); + Debug("bitvector-bb") << "theory::bv::DefaultVarBB bitblasting " << node << "\n"; + Debug("bitvector-bb") << " with bits " << toString(bits); } bb->storeVariable(node); } void DefaultConstBB (TNode node, Bits& bits, Bitblaster* bb) { - BVDebug("bitvector-bb") << "theory::bv::DefaultConstBB bitblasting " << node << "\n"; + Debug("bitvector-bb") << "theory::bv::DefaultConstBB bitblasting " << node << "\n"; Assert(node.getKind() == kind::CONST_BITVECTOR); Assert(bits.size() == 0); @@ -364,13 +364,13 @@ void DefaultConstBB (TNode node, Bits& bits, Bitblaster* bb) { } } if(Debug.isOn("bitvector-bb")) { - BVDebug("bitvector-bb") << "with bits: " << toString(bits) << "\n"; + Debug("bitvector-bb") << "with bits: " << toString(bits) << "\n"; } } void DefaultNotBB (TNode node, Bits& bits, Bitblaster* bb) { - BVDebug("bitvector-bb") << "theory::bv::DefaultNotBB bitblasting " << node << "\n"; + Debug("bitvector-bb") << "theory::bv::DefaultNotBB bitblasting " << node << "\n"; Assert(node.getKind() == kind::BITVECTOR_NOT); Assert(bits.size() == 0); Bits bv; @@ -379,7 +379,7 @@ void DefaultNotBB (TNode node, Bits& bits, Bitblaster* bb) { } void DefaultConcatBB (TNode node, Bits& bits, Bitblaster* bb) { - BVDebug("bitvector-bb") << "theory::bv::DefaultConcatBB bitblasting " << node << "\n"; + Debug("bitvector-bb") << "theory::bv::DefaultConcatBB bitblasting " << node << "\n"; Assert(bits.size() == 0); Assert (node.getKind() == kind::BITVECTOR_CONCAT); @@ -394,12 +394,12 @@ void DefaultConcatBB (TNode node, Bits& bits, Bitblaster* bb) { } Assert (bits.size() == utils::getSize(node)); if(Debug.isOn("bitvector-bb")) { - BVDebug("bitvector-bb") << "with bits: " << toString(bits) << "\n"; + Debug("bitvector-bb") << "with bits: " << toString(bits) << "\n"; } } void DefaultAndBB (TNode node, Bits& bits, Bitblaster* bb) { - BVDebug("bitvector-bb") << "theory::bv::DefaultAndBB bitblasting " << node << "\n"; + Debug("bitvector-bb") << "theory::bv::DefaultAndBB bitblasting " << node << "\n"; Assert(node.getKind() == kind::BITVECTOR_AND && bits.size() == 0); @@ -417,7 +417,7 @@ void DefaultAndBB (TNode node, Bits& bits, Bitblaster* bb) { } void DefaultOrBB (TNode node, Bits& bits, Bitblaster* bb) { - BVDebug("bitvector-bb") << "theory::bv::DefaultOrBB bitblasting " << node << "\n"; + Debug("bitvector-bb") << "theory::bv::DefaultOrBB bitblasting " << node << "\n"; Assert(node.getKind() == kind::BITVECTOR_OR && bits.size() == 0); @@ -435,7 +435,7 @@ void DefaultOrBB (TNode node, Bits& bits, Bitblaster* bb) { } void DefaultXorBB (TNode node, Bits& bits, Bitblaster* bb) { - BVDebug("bitvector-bb") << "theory::bv::DefaultXorBB bitblasting " << node << "\n"; + Debug("bitvector-bb") << "theory::bv::DefaultXorBB bitblasting " << node << "\n"; Assert(node.getKind() == kind::BITVECTOR_XOR && bits.size() == 0); @@ -456,7 +456,7 @@ void DefaultXorBB (TNode node, Bits& bits, Bitblaster* bb) { } void DefaultXnorBB (TNode node, Bits& bits, Bitblaster* bb) { - BVDebug("bitvector-bb") << "theory::bv::DefaultXnorBB bitblasting " << node << "\n"; + Debug("bitvector-bb") << "theory::bv::DefaultXnorBB bitblasting " << node << "\n"; Assert(node.getNumChildren() == 2 && node.getKind() == kind::BITVECTOR_XNOR && @@ -473,17 +473,17 @@ void DefaultXnorBB (TNode node, Bits& bits, Bitblaster* bb) { void DefaultNandBB (TNode node, Bits& bits, Bitblaster* bb) { - BVDebug("bitvector") << "theory::bv:: Unimplemented kind " + Debug("bitvector") << "theory::bv:: Unimplemented kind " << node.getKind() << "\n"; Unimplemented(); } void DefaultNorBB (TNode node, Bits& bits, Bitblaster* bb) { - BVDebug("bitvector") << "theory::bv:: Unimplemented kind " + Debug("bitvector") << "theory::bv:: Unimplemented kind " << node.getKind() << "\n"; Unimplemented(); } void DefaultCompBB (TNode node, Bits& bits, Bitblaster* bb) { - BVDebug("bitvector") << "theory::bv:: DefaultCompBB bitblasting "<< node << "\n"; + Debug("bitvector") << "theory::bv:: DefaultCompBB bitblasting "<< node << "\n"; Assert(getSize(node) == 1 && bits.size() == 0 && node.getKind() == kind::BITVECTOR_COMP); Bits a, b; @@ -501,7 +501,7 @@ void DefaultCompBB (TNode node, Bits& bits, Bitblaster* bb) { } void DefaultMultBB (TNode node, Bits& res, Bitblaster* bb) { - BVDebug("bitvector") << "theory::bv:: DefaultMultBB bitblasting "<< node << "\n"; + Debug("bitvector") << "theory::bv:: DefaultMultBB bitblasting "<< node << "\n"; Assert(res.size() == 0 && node.getKind() == kind::BITVECTOR_MULT); @@ -517,12 +517,12 @@ void DefaultMultBB (TNode node, Bits& res, Bitblaster* bb) { res = newres; } if(Debug.isOn("bitvector-bb")) { - BVDebug("bitvector-bb") << "with bits: " << toString(res) << "\n"; + Debug("bitvector-bb") << "with bits: " << toString(res) << "\n"; } } void DefaultPlusBB (TNode node, Bits& res, Bitblaster* bb) { - BVDebug("bitvector-bb") << "theory::bv::DefaultPlusBB bitblasting " << node << "\n"; + Debug("bitvector-bb") << "theory::bv::DefaultPlusBB bitblasting " << node << "\n"; Assert(node.getKind() == kind::BITVECTOR_PLUS && res.size() == 0); @@ -543,7 +543,7 @@ void DefaultPlusBB (TNode node, Bits& res, Bitblaster* bb) { void DefaultSubBB (TNode node, Bits& bits, Bitblaster* bb) { - BVDebug("bitvector-bb") << "theory::bv::DefaultSubBB bitblasting " << node << "\n"; + Debug("bitvector-bb") << "theory::bv::DefaultSubBB bitblasting " << node << "\n"; Assert(node.getKind() == kind::BITVECTOR_SUB && node.getNumChildren() == 2 && bits.size() == 0); @@ -561,7 +561,7 @@ void DefaultSubBB (TNode node, Bits& bits, Bitblaster* bb) { } void DefaultNegBB (TNode node, Bits& bits, Bitblaster* bb) { - BVDebug("bitvector-bb") << "theory::bv::DefaultNegBB bitblasting " << node << "\n"; + Debug("bitvector-bb") << "theory::bv::DefaultNegBB bitblasting " << node << "\n"; Assert(node.getKind() == kind::BITVECTOR_NEG); Bits a; @@ -639,7 +639,7 @@ void uDivModRec(const Bits& a, const Bits& b, Bits& q, Bits& r, unsigned rec_wid } void DefaultUdivBB (TNode node, Bits& q, Bitblaster* bb) { - BVDebug("bitvector-bb") << "theory::bv::DefaultUdivBB bitblasting " << node << "\n"; + Debug("bitvector-bb") << "theory::bv::DefaultUdivBB bitblasting " << node << "\n"; Assert(node.getKind() == kind::BITVECTOR_UDIV_TOTAL && q.size() == 0); Bits a, b; @@ -666,7 +666,7 @@ void DefaultUdivBB (TNode node, Bits& q, Bitblaster* bb) { } void DefaultUremBB (TNode node, Bits& rem, Bitblaster* bb) { - BVDebug("bitvector-bb") << "theory::bv::DefaultUremBB bitblasting " << node << "\n"; + Debug("bitvector-bb") << "theory::bv::DefaultUremBB bitblasting " << node << "\n"; Assert(node.getKind() == kind::BITVECTOR_UREM_TOTAL && rem.size() == 0); Bits a, b; @@ -694,23 +694,23 @@ void DefaultUremBB (TNode node, Bits& rem, Bitblaster* bb) { void DefaultSdivBB (TNode node, Bits& bits, Bitblaster* bb) { - BVDebug("bitvector") << "theory::bv:: Unimplemented kind " + Debug("bitvector") << "theory::bv:: Unimplemented kind " << node.getKind() << "\n"; Unimplemented(); } void DefaultSremBB (TNode node, Bits& bits, Bitblaster* bb) { - BVDebug("bitvector") << "theory::bv:: Unimplemented kind " + Debug("bitvector") << "theory::bv:: Unimplemented kind " << node.getKind() << "\n"; Unimplemented(); } void DefaultSmodBB (TNode node, Bits& bits, Bitblaster* bb) { - BVDebug("bitvector") << "theory::bv:: Unimplemented kind " + Debug("bitvector") << "theory::bv:: Unimplemented kind " << node.getKind() << "\n"; Unimplemented(); } void DefaultShlBB (TNode node, Bits& res, Bitblaster* bb) { - BVDebug("bitvector-bb") << "theory::bv::DefaultShlBB bitblasting " << node << "\n"; + Debug("bitvector-bb") << "theory::bv::DefaultShlBB bitblasting " << node << "\n"; Assert (node.getKind() == kind::BITVECTOR_SHL && res.size() == 0); Bits a, b; @@ -738,12 +738,12 @@ void DefaultShlBB (TNode node, Bits& res, Bitblaster* bb) { } } if(Debug.isOn("bitvector-bb")) { - BVDebug("bitvector-bb") << "with bits: " << toString(res) << "\n"; + Debug("bitvector-bb") << "with bits: " << toString(res) << "\n"; } } void DefaultLshrBB (TNode node, Bits& res, Bitblaster* bb) { - BVDebug("bitvector-bb") << "theory::bv::DefaultLshrBB bitblasting " << node << "\n"; + Debug("bitvector-bb") << "theory::bv::DefaultLshrBB bitblasting " << node << "\n"; Assert (node.getKind() == kind::BITVECTOR_LSHR && res.size() == 0); Bits a, b; @@ -771,13 +771,13 @@ void DefaultLshrBB (TNode node, Bits& res, Bitblaster* bb) { } } if(Debug.isOn("bitvector-bb")) { - BVDebug("bitvector-bb") << "with bits: " << toString(res) << "\n"; + Debug("bitvector-bb") << "with bits: " << toString(res) << "\n"; } } void DefaultAshrBB (TNode node, Bits& res, Bitblaster* bb) { - BVDebug("bitvector-bb") << "theory::bv::DefaultAshrBB bitblasting " << node << "\n"; + Debug("bitvector-bb") << "theory::bv::DefaultAshrBB bitblasting " << node << "\n"; Assert (node.getKind() == kind::BITVECTOR_ASHR && res.size() == 0); Bits a, b; @@ -806,7 +806,7 @@ void DefaultAshrBB (TNode node, Bits& res, Bitblaster* bb) { } } if(Debug.isOn("bitvector-bb")) { - BVDebug("bitvector-bb") << "with bits: " << toString(res) << "\n"; + Debug("bitvector-bb") << "with bits: " << toString(res) << "\n"; } } @@ -825,14 +825,14 @@ void DefaultExtractBB (TNode node, Bits& bits, Bitblaster* bb) { Assert (bits.size() == high - low + 1); if(Debug.isOn("bitvector-bb")) { - BVDebug("bitvector-bb") << "theory::bv::DefaultExtractBB bitblasting " << node << "\n"; - BVDebug("bitvector-bb") << " with bits " << toString(bits); + Debug("bitvector-bb") << "theory::bv::DefaultExtractBB bitblasting " << node << "\n"; + Debug("bitvector-bb") << " with bits " << toString(bits); } } void DefaultRepeatBB (TNode node, Bits& bits, Bitblaster* bb) { - BVDebug("bitvector") << "theory::bv:: Unimplemented kind " + Debug("bitvector") << "theory::bv:: Unimplemented kind " << node.getKind() << "\n"; // this should be rewritten Unimplemented(); @@ -840,7 +840,7 @@ void DefaultRepeatBB (TNode node, Bits& bits, Bitblaster* bb) { void DefaultZeroExtendBB (TNode node, Bits& res_bits, Bitblaster* bb) { - BVDebug("bitvector-bb") << "theory::bv::DefaultZeroExtendBB bitblasting " << node << "\n"; + Debug("bitvector-bb") << "theory::bv::DefaultZeroExtendBB bitblasting " << node << "\n"; // this should be rewritten Unimplemented(); @@ -848,7 +848,7 @@ void DefaultZeroExtendBB (TNode node, Bits& res_bits, Bitblaster* bb) { } void DefaultSignExtendBB (TNode node, Bits& res_bits, Bitblaster* bb) { - BVDebug("bitvector-bb") << "theory::bv::DefaultSignExtendBB bitblasting " << node << "\n"; + Debug("bitvector-bb") << "theory::bv::DefaultSignExtendBB bitblasting " << node << "\n"; Assert (node.getKind() == kind::BITVECTOR_SIGN_EXTEND && res_bits.size() == 0); @@ -871,14 +871,14 @@ void DefaultSignExtendBB (TNode node, Bits& res_bits, Bitblaster* bb) { } void DefaultRotateRightBB (TNode node, Bits& res, Bitblaster* bb) { - BVDebug("bitvector") << "theory::bv:: Unimplemented kind " + Debug("bitvector") << "theory::bv:: Unimplemented kind " << node.getKind() << "\n"; Unimplemented(); } void DefaultRotateLeftBB (TNode node, Bits& bits, Bitblaster* bb) { - BVDebug("bitvector") << "theory::bv:: Unimplemented kind " + Debug("bitvector") << "theory::bv:: Unimplemented kind " << node.getKind() << "\n"; Unimplemented(); } diff --git a/src/theory/bv/bv_subtheory.h b/src/theory/bv/bv_subtheory.h index a256b6001..d95aaa873 100644 --- a/src/theory/bv/bv_subtheory.h +++ b/src/theory/bv/bv_subtheory.h @@ -72,19 +72,31 @@ protected: /** The bit-vector theory */ TheoryBV* d_bv; - + context::CDQueue<TNode> d_assertionQueue; + context::CDO<uint32_t> d_assertionIndex; public: SubtheorySolver(context::Context* c, TheoryBV* bv) : d_context(c), - d_bv(bv) + d_bv(bv), + d_assertionQueue(c), + d_assertionIndex(c, 0) {} virtual ~SubtheorySolver() {} + + virtual bool check(Theory::Effort e) = 0; + virtual void explain(TNode literal, std::vector<TNode>& assumptions) = 0; + virtual void preRegister(TNode node) {} + virtual void collectModelInfo(TheoryModel* m) = 0; + bool done() { return d_assertionQueue.size() == d_assertionIndex; } + TNode get() { + Assert (!done()); + TNode res = d_assertionQueue[d_assertionIndex]; + d_assertionIndex = d_assertionIndex + 1; + return res; + } + void assertFact(TNode fact) { d_assertionQueue.push_back(fact); } - virtual bool addAssertions(const std::vector<TNode>& assertions, Theory::Effort e) = 0; - virtual void explain(TNode literal, std::vector<TNode>& assumptions) = 0; - virtual void preRegister(TNode node) {} - virtual void collectModelInfo(TheoryModel* m) = 0; }; } diff --git a/src/theory/bv/bv_subtheory_bitblast.cpp b/src/theory/bv/bv_subtheory_bitblast.cpp index 985a9b500..2f76e32d3 100644 --- a/src/theory/bv/bv_subtheory_bitblast.cpp +++ b/src/theory/bv/bv_subtheory_bitblast.cpp @@ -52,12 +52,21 @@ void BitblastSolver::explain(TNode literal, std::vector<TNode>& assumptions) { d_bitblaster->explain(literal, assumptions); } -bool BitblastSolver::addAssertions(const std::vector<TNode>& assertions, Theory::Effort e) { - Debug("bitvector::bitblaster") << "BitblastSolver::addAssertions (" << e << ")" << std::endl; - Debug("bitvector::bitblaster") << "number of assertions: " << assertions.size() << std::endl; - //// Lazy bit-blasting +bool BitblastSolver::check(Theory::Effort e) { + //// Eager bit-blasting + if (options::bitvectorEagerBitblast()) { + while (!done()) { + TNode assertion = get(); + TNode atom = assertion.getKind() == kind::NOT ? assertion[0] : assertion; + if (atom.getKind() != kind::BITVECTOR_BITOF) { + d_bitblaster->bbAtom(atom); + } + return true; + } + } + //// Lazy bit-blasting // bit-blast enqueued nodes while (!d_bitblastQueue.empty()) { TNode atom = d_bitblastQueue.front(); @@ -65,9 +74,9 @@ bool BitblastSolver::addAssertions(const std::vector<TNode>& assertions, Theory: d_bitblastQueue.pop(); } - // propagation - for (unsigned i = 0; i < assertions.size(); ++i) { - TNode fact = assertions[i]; + // Processinga ssertions + while (!done()) { + TNode fact = get(); if (!d_bv->inConflict() && !d_bv->propagatedBy(fact, SUB_BITBLAST)) { // Some atoms have not been bit-blasted yet d_bitblaster->bbAtom(fact); @@ -93,7 +102,7 @@ bool BitblastSolver::addAssertions(const std::vector<TNode>& assertions, Theory: } } - // solving + // Solving if (e == Theory::EFFORT_FULL || options::bitvectorEagerFullcheck()) { Assert(!d_bv->inConflict()); Debug("bitvector::bitblaster") << "BitblastSolver::addAssertions solving. \n"; diff --git a/src/theory/bv/bv_subtheory_bitblast.h b/src/theory/bv/bv_subtheory_bitblast.h index 3396d813b..318fdd230 100644 --- a/src/theory/bv/bv_subtheory_bitblast.h +++ b/src/theory/bv/bv_subtheory_bitblast.h @@ -42,7 +42,7 @@ public: ~BitblastSolver(); void preRegister(TNode node); - bool addAssertions(const std::vector<TNode>& assertions, Theory::Effort e); + bool check(Theory::Effort e); void explain(TNode literal, std::vector<TNode>& assumptions); EqualityStatus getEqualityStatus(TNode a, TNode b); void collectModelInfo(TheoryModel* m); diff --git a/src/theory/bv/bv_subtheory_core.cpp b/src/theory/bv/bv_subtheory_core.cpp index 91cf29ee9..2e1320d1a 100644 --- a/src/theory/bv/bv_subtheory_core.cpp +++ b/src/theory/bv/bv_subtheory_core.cpp @@ -35,7 +35,9 @@ CoreSolver::CoreSolver(context::Context* c, TheoryBV* bv, Slicer* slicer) d_assertions(c), d_normalFormCache(), d_slicer(slicer), - d_isCoreTheory(c, true) + d_isCoreTheory(c, true), + d_baseChanged(false), + d_checkCalled(false) { if (d_useEqualityEngine) { @@ -83,6 +85,7 @@ void CoreSolver::preRegister(TNode node) { if (node.getKind() == kind::EQUAL) { d_equalityEngine.addTriggerEquality(node); + d_slicer->processEquality(node); } else { d_equalityEngine.addTerm(node); } @@ -101,6 +104,11 @@ void CoreSolver::explain(TNode literal, std::vector<TNode>& assumptions) { Node CoreSolver::getBaseDecomposition(TNode a) { std::vector<Node> a_decomp; + // FIXME: hack to do bitwise decomposition + // for (int i = utils::getSize(a) - 1; i>= 0; --i) { + // Node bit = Rewriter::rewrite(utils::mkExtract(a, i, i)); + // a_decomp.push_back(bit); + // } d_slicer->getBaseDecomposition(a, a_decomp); Node new_a = utils::mkConcat(a_decomp); return new_a; @@ -116,11 +124,8 @@ bool CoreSolver::decomposeFact(TNode fact) { TNode a = eq[0]; TNode b = eq[1]; - // we need to get the old decomposition to keep track of the cuts we added - Base a_old_base = d_slicer->getTopLevelBase(a); - Base b_old_base = d_slicer->getTopLevelBase(b); - d_slicer->processEquality(eq); + // d_slicer->processEquality(eq); Node new_a = getBaseDecomposition(a); Node new_b = getBaseDecomposition(b); @@ -132,20 +137,12 @@ bool CoreSolver::decomposeFact(TNode fact) { Node a_eq_new_a = nm->mkNode(kind::EQUAL, a, new_a); Node b_eq_new_b = nm->mkNode(kind::EQUAL, b, new_b); - Base a_new_base = d_slicer->getTopLevelBase(a); - Base b_new_base = d_slicer->getTopLevelBase(b); - bool ok = true; - ok = addNewSplits(a, a_old_base, a_new_base); - if (!ok) return false; - ok = addNewSplits(b, b_old_base, b_new_base); - if (!ok) return false; - - ok = assertFact(a_eq_new_a, utils::mkTrue()); + ok = assertFactToEqualityEngine(a_eq_new_a, utils::mkTrue()); if (!ok) return false; - ok = assertFact(b_eq_new_b, utils::mkTrue()); + ok = assertFactToEqualityEngine(b_eq_new_b, utils::mkTrue()); if (!ok) return false; - ok = assertFact(fact, fact); + ok = assertFactToEqualityEngine(fact, fact); if (!ok) return false; if (fact.getKind() == kind::EQUAL) { @@ -157,7 +154,7 @@ bool CoreSolver::decomposeFact(TNode fact) { Assert (new_a.getNumChildren() == new_b.getNumChildren()); for (unsigned i = 0; i < new_a.getNumChildren(); ++i) { Node eq_i = nm->mkNode(kind::EQUAL, new_a[i], new_b[i]); - ok = assertFact(eq_i, fact); + ok = assertFactToEqualityEngine(eq_i, fact); if (!ok) return false; } } @@ -165,64 +162,15 @@ bool CoreSolver::decomposeFact(TNode fact) { return true; } -bool CoreSolver::addNewSplits(TNode n, Base& old_base, Base& new_base) { - if (n.getKind() == kind::BITVECTOR_EXTRACT) { - n = n[0]; - } - Assert (old_base.getBitwidth() == new_base.getBitwidth() && - utils::getSize(n) == old_base.getBitwidth()); - - Index high, low = 0; - std::vector<std::pair<Index, Index> > toSlice; - bool hasNewCut = false; - // collect the intervals that need to be sliced - for (unsigned i = 0; i <= old_base.getBitwidth(); ++i) { - Assert (! old_base.isCutPoint(i) || new_base.isCutPoint(i)); - if (new_base.isCutPoint(i) && !old_base.isCutPoint(i)) { - hasNewCut = true; - } - if (new_base.isCutPoint(i) && old_base.isCutPoint(i)) { - high = i; - if (hasNewCut) { - toSlice.push_back(std::pair<Index, Index>(high, low)); - } - low = i; - hasNewCut = false; - } - } - // for each interval, assert the proper equality - for (unsigned i = 0; i < toSlice.size(); ++i) { - int high = toSlice[i].first; - int low = toSlice[i].second; - int prev = high; - std::vector<Node> extracts; - for (int k = high -1; k >= low; --k) { - if (new_base.isCutPoint(k) && (!old_base.isCutPoint(k) || k == low)) { - // add a new extract - Node ex = utils::mkExtract(n, prev - 1, k); - prev = k; - extracts.push_back(ex); - } - } - Node concat = utils::mkConcat(extracts); - Node current = utils::mkExtract(n, high - 1, low); - Node eq = utils::mkNode(kind::EQUAL, concat, current); - bool ok = assertFact(eq, utils::mkTrue()); - if (!ok) - return false; - } - return true; -} - - -bool CoreSolver::addAssertions(const std::vector<TNode>& assertions, Theory::Effort e) { - Trace("bitvector::core") << "CoreSolver::addAssertions \n"; +bool CoreSolver::check(Theory::Effort e) { + d_checkCalled = true; + Trace("bitvector::core") << "CoreSolver::check \n"; Assert (!d_bv->inConflict()); bool ok = true; std::vector<Node> core_eqs; - for (unsigned i = 0; i < assertions.size(); ++i) { - TNode fact = assertions[i]; + while (! done()) { + TNode fact = get(); // update whether we are in the core fragment if (d_isCoreTheory && !d_slicer->isCoreTerm(fact)) { @@ -234,17 +182,17 @@ bool CoreSolver::addAssertions(const std::vector<TNode>& assertions, Theory::Eff TNode eq = fact.getKind() == kind::EQUAL ? fact : fact[0]; ok = decomposeFact(fact); } else { - ok = assertFact(fact, fact); + ok = assertFactToEqualityEngine(fact, fact); } if (!ok) return false; } - + return true; } -bool CoreSolver::assertFact(TNode fact, TNode reason) { - Debug("bv-slicer") << "CoreSolver::assertFact fact=" << fact << endl; +bool CoreSolver::assertFactToEqualityEngine(TNode fact, TNode reason) { + Debug("bv-slicer") << "CoreSolver::assertFactToEqualityEngine fact=" << fact << endl; Debug("bv-slicer") << " reason=" << reason << endl; // Notify the equality engine if (d_useEqualityEngine && !d_bv->inConflict() && !d_bv->propagatedBy(fact, SUB_CORE) ) { @@ -276,7 +224,7 @@ bool CoreSolver::assertFact(TNode fact, TNode reason) { } bool CoreSolver::NotifyClass::eqNotifyTriggerEquality(TNode equality, bool value) { - BVDebug("bitvector::core") << "NotifyClass::eqNotifyTriggerEquality(" << equality << ", " << (value ? "true" : "false" )<< ")" << std::endl; + Debug("bitvector::core") << "NotifyClass::eqNotifyTriggerEquality(" << equality << ", " << (value ? "true" : "false" )<< ")" << std::endl; if (value) { return d_solver.storePropagation(equality); } else { @@ -285,7 +233,7 @@ bool CoreSolver::NotifyClass::eqNotifyTriggerEquality(TNode equality, bool value } bool CoreSolver::NotifyClass::eqNotifyTriggerPredicate(TNode predicate, bool value) { - BVDebug("bitvector::core") << "NotifyClass::eqNotifyTriggerPredicate(" << predicate << ", " << (value ? "true" : "false" ) << ")" << std::endl; + Debug("bitvector::core") << "NotifyClass::eqNotifyTriggerPredicate(" << predicate << ", " << (value ? "true" : "false" ) << ")" << std::endl; if (value) { return d_solver.storePropagation(predicate); } else { diff --git a/src/theory/bv/bv_subtheory_core.h b/src/theory/bv/bv_subtheory_core.h index 1adf813ff..d5235a864 100644 --- a/src/theory/bv/bv_subtheory_core.h +++ b/src/theory/bv/bv_subtheory_core.h @@ -73,16 +73,17 @@ class CoreSolver : public SubtheorySolver { Slicer* d_slicer; context::CDO<bool> d_isCoreTheory; - bool assertFact(TNode fact, TNode reason); + bool assertFactToEqualityEngine(TNode fact, TNode reason); bool decomposeFact(TNode fact); Node getBaseDecomposition(TNode a); - bool addNewSplits(TNode n, Base& old_base, Base& new_base); + bool d_baseChanged; + bool d_checkCalled; public: - bool isCoreTheory() {return d_isCoreTheory; } CoreSolver(context::Context* c, TheoryBV* bv, Slicer* slicer); - void setMasterEqualityEngine(eq::EqualityEngine* eq); + bool isCoreTheory() { return d_isCoreTheory; } + void setMasterEqualityEngine(eq::EqualityEngine* eq); void preRegister(TNode node); - bool addAssertions(const std::vector<TNode>& assertions, Theory::Effort e); + bool check(Theory::Effort e); void explain(TNode literal, std::vector<TNode>& assumptions); void collectModelInfo(TheoryModel* m); void addSharedTerm(TNode t) { diff --git a/src/theory/bv/bv_subtheory_eq.cpp b/src/theory/bv/bv_subtheory_eq.cpp index ca3e3e35c..f11b1252b 100644 --- a/src/theory/bv/bv_subtheory_eq.cpp +++ b/src/theory/bv/bv_subtheory_eq.cpp @@ -131,7 +131,7 @@ bool EqualitySolver::addAssertions(const std::vector<TNode>& assertions, Theory: } bool EqualitySolver::NotifyClass::eqNotifyTriggerEquality(TNode equality, bool value) { - BVDebug("bitvector::equality") << "NotifyClass::eqNotifyTriggerEquality(" << equality << ", " << (value ? "true" : "false" )<< ")" << std::endl; + Debug("bitvector::equality") << "NotifyClass::eqNotifyTriggerEquality(" << equality << ", " << (value ? "true" : "false" )<< ")" << std::endl; if (value) { return d_solver.storePropagation(equality); } else { @@ -140,7 +140,7 @@ bool EqualitySolver::NotifyClass::eqNotifyTriggerEquality(TNode equality, bool v } bool EqualitySolver::NotifyClass::eqNotifyTriggerPredicate(TNode predicate, bool value) { - BVDebug("bitvector::equality") << "NotifyClass::eqNotifyTriggerPredicate(" << predicate << ", " << (value ? "true" : "false" ) << ")" << std::endl; + Debug("bitvector::equality") << "NotifyClass::eqNotifyTriggerPredicate(" << predicate << ", " << (value ? "true" : "false" ) << ")" << std::endl; if (value) { return d_solver.storePropagation(predicate); } else { diff --git a/src/theory/bv/cd_set_collection.h b/src/theory/bv/cd_set_collection.h index e4bcbca47..ec7f6d66d 100644 --- a/src/theory/bv/cd_set_collection.h +++ b/src/theory/bv/cd_set_collection.h @@ -71,7 +71,7 @@ class BacktrackableSetCollection { const tree_entry_type& node = d_memory.back(); if(Debug.isOn("cd_set_collection")) { - BVDebug("cd_set_collection") << "BacktrackableSetCollection::backtrack(): removing " << node.getValue() + Debug("cd_set_collection") << "BacktrackableSetCollection::backtrack(): removing " << node.getValue() << " from " << internalToString(getRoot(d_memory.size()-1)) << std::endl; } @@ -279,7 +279,7 @@ public: // Find the biggest node smaleer than value (it must exist) while (set != null) { if(Debug.isOn("set_collection")) { - BVDebug("set_collection") << "BacktrackableSetCollection::getPrev(" << toString(set) << "," << value << ")" << std::endl; + Debug("set_collection") << "BacktrackableSetCollection::getPrev(" << toString(set) << "," << value << ")" << std::endl; } const tree_entry_type& node = d_memory[set]; if (node.getValue() >= value) { @@ -308,7 +308,7 @@ public: // Find the smallest node bigger than value (it must exist) while (set != null) { if(Debug.isOn("set_collection")) { - BVDebug("set_collection") << "BacktrackableSetCollection::getNext(" << toString(set) << "," << value << ")" << std::endl; + Debug("set_collection") << "BacktrackableSetCollection::getNext(" << toString(set) << "," << value << ")" << std::endl; } const tree_entry_type& node = d_memory[set]; if (node.getValue() <= value) { @@ -377,7 +377,7 @@ public: Assert(isValid(set)); if(Debug.isOn("set_collection")) { - BVDebug("set_collection") << "BacktrackableSetCollection::getElements(" << toString(set) << "," << lowerBound << "," << upperBound << ")" << std::endl; + Debug("set_collection") << "BacktrackableSetCollection::getElements(" << toString(set) << "," << lowerBound << "," << upperBound << ")" << std::endl; } // Empty set no elements diff --git a/src/theory/bv/slicer.cpp b/src/theory/bv/slicer.cpp index 2334ed2b0..ac668ab20 100644 --- a/src/theory/bv/slicer.cpp +++ b/src/theory/bv/slicer.cpp @@ -48,6 +48,14 @@ void Base::sliceAt(Index index) { d_repr[vector_index] = d_repr[vector_index] | bit_mask; } +void Base::undoSliceAt(Index index) { + Index vector_index = index / 32; + Assert (vector_index < d_size); + Index int_index = index % 32; + uint32_t bit_mask = utils::pow2(int_index); + d_repr[vector_index] = d_repr[vector_index] ^ bit_mask; +} + void Base::sliceWith(const Base& other) { Assert (d_size == other.d_size); for (unsigned i = 0; i < d_repr.size(); ++i) { @@ -245,8 +253,9 @@ void UnionFind::split(TermId id, Index i) { if (i == 0 || i == getBitwidth(id)) { // nothing to do - return; + return; } + Assert (i < getBitwidth(id)); if (!hasChildren(id)) { // first time we split this term @@ -417,6 +426,7 @@ void UnionFind::ensureSlicing(const ExtractTerm& term) { } void UnionFind::backtrack() { + return; int size = d_undoStack.size(); for (int i = size; i > d_undoStackIndex.get(); --i) { Operation op = d_undoStack.back(); @@ -443,6 +453,9 @@ void UnionFind::undoSplit(TermId id) { } void UnionFind::recordOperation(OperationKind op, TermId term) { + if (op == SPLIT) { + d_newSplit = true; + } d_undoStackIndex.set(d_undoStackIndex.get() + 1); d_undoStack.push_back(Operation(op, term)); Assert (d_undoStack.size() == d_undoStackIndex); diff --git a/src/theory/bv/slicer.h b/src/theory/bv/slicer.h index 0508c67c1..6e09d971b 100644 --- a/src/theory/bv/slicer.h +++ b/src/theory/bv/slicer.h @@ -47,6 +47,7 @@ namespace bv { typedef Index TermId; extern const TermId UndefinedId; +class CDBase; /** * Base @@ -55,9 +56,11 @@ extern const TermId UndefinedId; class Base { Index d_size; std::vector<uint32_t> d_repr; + void undoSliceAt(Index index); public: Base (Index size); - void sliceAt(Index index); + void sliceAt(Index index); + void sliceWith(const Base& other); bool isCutPoint(Index index) const; void diffCutPoints(const Base& other, Base& res) const; @@ -78,6 +81,47 @@ public: } return true; } + friend class CDBase; +}; + + +class CDBase : public context::ContextNotifyObj { + context::Context* d_ctx; + context::CDO<unsigned> d_undoIndex; + + std::vector<unsigned> d_undoStack; + Base d_base; + CDBase(context::Context* ctx, Index bitwidth) + : ContextNotifyObj(ctx), + d_ctx(ctx), + d_undoIndex(d_ctx), + d_undoStack(), + d_base(bitwidth) + {} + void sliceAt(Index i) { + Assert (!d_base.isCutPoint(i)); + d_undoStack.push_back(i); + d_undoIndex.set(d_undoIndex.get() + 1); + d_base.sliceAt(i); + } + bool isCutPoint(Index i) { + return d_base.isCutPoint(i); + } + Index getBitwidth() const {return d_base.getBitwidth(); } + virtual ~CDBase() throw(AssertionException) {} + void contextNotifyPop() { + backtrack(); + } + + void backtrack() { + for (unsigned i = d_undoIndex.get(); i < d_undoStack.size(); ++i) { + Index i = d_undoStack.back(); + d_undoStack.pop_back(); + d_base.undoSliceAt(i); + } + Assert(d_undoIndex.get() == d_undoStack.size()); + } + }; /** @@ -227,11 +271,11 @@ class UnionFind : public context::ContextNotifyObj { }; Statistics d_statistics; + bool d_newSplit; public: UnionFind(context::Context* ctx) : ContextNotifyObj(ctx), d_nodes(), - // d_representatives(ctx), d_undoStack(), d_undoStackIndex(ctx), d_statistics() @@ -256,6 +300,8 @@ public: void contextNotifyPop() { backtrack(); } + bool hasNewSplit() { return d_newSplit; } + void resetNewSplit() { d_newSplit = false; } friend class Slicer; }; @@ -279,7 +325,9 @@ public: bool isCoreTerm (TNode node); Base getTopLevelBase(TNode node); static void splitEqualities(TNode node, std::vector<Node>& equalities); - static unsigned d_numAddedEqualities; + static unsigned d_numAddedEqualities; + inline bool hasNewSplit() { return d_unionFind.hasNewSplit(); } + inline void resetNewSplit() { d_unionFind.resetNewSplit(); } }; diff --git a/src/theory/bv/theory_bv.cpp b/src/theory/bv/theory_bv.cpp index 6248782bd..5d034287d 100644 --- a/src/theory/bv/theory_bv.cpp +++ b/src/theory/bv/theory_bv.cpp @@ -41,7 +41,6 @@ TheoryBV::TheoryBV(context::Context* c, context::UserContext* u, OutputChannel& d_alreadyPropagatedSet(c), d_sharedTermsSet(c), d_slicer(c), - d_bitblastAssertionsQueue(c), d_bitblastSolver(c, this), d_coreSolver(c, this, &d_slicer), d_statistics(), @@ -110,29 +109,23 @@ void TheoryBV::check(Effort e) return; } - // getting the new assertions - std::vector<TNode> new_assertions; while (!done()) { - Assertion assertion = get(); - TNode fact = assertion.assertion; - new_assertions.push_back(fact); - d_bitblastAssertionsQueue.push_back(fact); - Debug("bitvector-assertions") << "TheoryBV::check assertion " << fact << "\n"; + TNode fact = get().assertion; + d_coreSolver.assertFact(fact); + d_bitblastSolver.assertFact(fact); } + bool ok = true; if (!inConflict()) { - // sending assertions to the equality solver first - d_coreSolver.addAssertions(new_assertions, e); + ok = d_coreSolver.check(e); } + Assert (!ok == inConflict()); if (!inConflict() && !d_coreSolver.isCoreTheory()) { - // sending assertions to the bitblast solver if it's not just core theory - d_bitblastSolver.addAssertions(new_assertions, e); - } else { - // sending assertions to the bitblast solver if it's not just core theory - d_bitblastSolver.addAssertions(new_assertions, EFFORT_STANDARD); + ok = d_bitblastSolver.check(e); } + Assert (!ok == inConflict()); if (inConflict()) { sendConflict(); } @@ -156,7 +149,10 @@ void TheoryBV::propagate(Effort e) { bool ok = true; for (; d_literalsToPropagateIndex < d_literalsToPropagate.size() && ok; d_literalsToPropagateIndex = d_literalsToPropagateIndex + 1) { TNode literal = d_literalsToPropagate[d_literalsToPropagateIndex]; - ok = d_out->propagate(literal); + // temporary fix for incremental bit-blasting + if (d_valuation.isSatLiteral(literal)) { + ok = d_out->propagate(literal); + } } if (!ok) { @@ -214,7 +210,7 @@ void TheoryBV::presolve() { bool TheoryBV::storePropagation(TNode literal, SubTheory subtheory) { - Debug("bitvector::propagate") << indent() << "TheoryBV::storePropagation(" << literal << ", " << subtheory << ")" << std::endl; + Debug("bitvector::propagate") << indent() << getSatContext()->getLevel() << " " << "TheoryBV::storePropagation(" << literal << ", " << subtheory << ")" << std::endl; // If already in conflict, no more propagation if (d_conflict) { diff --git a/src/theory/bv/theory_bv.h b/src/theory/bv/theory_bv.h index ec72f40e1..3e14584ed 100644 --- a/src/theory/bv/theory_bv.h +++ b/src/theory/bv/theory_bv.h @@ -25,7 +25,6 @@ #include "context/cdhashset.h" #include "theory/bv/theory_bv_utils.h" #include "util/statistics_registry.h" -#include "context/cdqueue.h" #include "theory/bv/bv_subtheory.h" #include "theory/bv/bv_subtheory_eq.h" #include "theory/bv/bv_subtheory_core.h" @@ -46,11 +45,8 @@ class TheoryBV : public Theory { context::CDHashSet<Node, NodeHashFunction> d_sharedTermsSet; Slicer d_slicer; - - context::CDQueue<TNode> d_bitblastAssertionsQueue; - BitblastSolver d_bitblastSolver; - CoreSolver d_coreSolver; + CoreSolver d_coreSolver; public: diff --git a/src/theory/bv/theory_bv_rewrite_rules.h b/src/theory/bv/theory_bv_rewrite_rules.h index f9650932e..bd7a8131a 100644 --- a/src/theory/bv/theory_bv_rewrite_rules.h +++ b/src/theory/bv/theory_bv_rewrite_rules.h @@ -334,7 +334,7 @@ public: template<bool checkApplies> static inline Node run(TNode node) { if (!checkApplies || applies(node)) { - BVDebug("theory::bv::rewrite") << "RewriteRule<" << rule << ">(" << node << ")" << std::endl; + Debug("theory::bv::rewrite") << "RewriteRule<" << rule << ">(" << node << ")" << std::endl; Assert(checkApplies || applies(node)); //++ s_statistics->d_ruleApplications; Node result = apply(node); @@ -355,7 +355,7 @@ public: << CheckSatCommand(condition.toExpr()); } } - BVDebug("theory::bv::rewrite") << "RewriteRule<" << rule << ">(" << node << ") => " << result << std::endl; + Debug("theory::bv::rewrite") << "RewriteRule<" << rule << ">(" << node << ") => " << result << std::endl; return result; } else { return node; @@ -486,7 +486,7 @@ bool RewriteRule<EmptyRule>::applies(TNode node) { template<> inline Node RewriteRule<EmptyRule>::apply(TNode node) { - BVDebug("bv-rewrite") << "RewriteRule<EmptyRule> for " << node.getKind() <<"\n"; + Debug("bv-rewrite") << "RewriteRule<EmptyRule> for " << node.getKind() <<"\n"; Unreachable(); return node; } diff --git a/src/theory/bv/theory_bv_rewrite_rules_constant_evaluation.h b/src/theory/bv/theory_bv_rewrite_rules_constant_evaluation.h index 498378638..178b17b43 100644 --- a/src/theory/bv/theory_bv_rewrite_rules_constant_evaluation.h +++ b/src/theory/bv/theory_bv_rewrite_rules_constant_evaluation.h @@ -37,7 +37,7 @@ bool RewriteRule<EvalAnd>::applies(TNode node) { template<> inline Node RewriteRule<EvalAnd>::apply(TNode node) { Unreachable(); - BVDebug("bv-rewrite") << "RewriteRule<EvalAnd>(" << node << ")" << std::endl; + Debug("bv-rewrite") << "RewriteRule<EvalAnd>(" << node << ")" << std::endl; BitVector a = node[0].getConst<BitVector>(); BitVector b = node[1].getConst<BitVector>(); BitVector res = a & b; @@ -56,7 +56,7 @@ bool RewriteRule<EvalOr>::applies(TNode node) { template<> inline Node RewriteRule<EvalOr>::apply(TNode node) { Unreachable(); - BVDebug("bv-rewrite") << "RewriteRule<EvalOr>(" << node << ")" << std::endl; + Debug("bv-rewrite") << "RewriteRule<EvalOr>(" << node << ")" << std::endl; BitVector a = node[0].getConst<BitVector>(); BitVector b = node[1].getConst<BitVector>(); BitVector res = a | b; @@ -75,7 +75,7 @@ bool RewriteRule<EvalXor>::applies(TNode node) { template<> inline Node RewriteRule<EvalXor>::apply(TNode node) { Unreachable(); - BVDebug("bv-rewrite") << "RewriteRule<EvalXor>(" << node << ")" << std::endl; + Debug("bv-rewrite") << "RewriteRule<EvalXor>(" << node << ")" << std::endl; BitVector a = node[0].getConst<BitVector>(); BitVector b = node[1].getConst<BitVector>(); BitVector res = a ^ b; @@ -91,7 +91,7 @@ Node RewriteRule<EvalXor>::apply(TNode node) { // template<> inline // Node RewriteRule<EvalXnor>::apply(TNode node) { -// BVDebug("bv-rewrite") << "RewriteRule<EvalXnor>(" << node << ")" << std::endl; +// Debug("bv-rewrite") << "RewriteRule<EvalXnor>(" << node << ")" << std::endl; // BitVector a = node[0].getConst<BitVector>(); // BitVector b = node[1].getConst<BitVector>(); // BitVector res = ~ (a ^ b); @@ -106,7 +106,7 @@ bool RewriteRule<EvalNot>::applies(TNode node) { template<> inline Node RewriteRule<EvalNot>::apply(TNode node) { - BVDebug("bv-rewrite") << "RewriteRule<EvalNot>(" << node << ")" << std::endl; + Debug("bv-rewrite") << "RewriteRule<EvalNot>(" << node << ")" << std::endl; BitVector a = node[0].getConst<BitVector>(); BitVector res = ~ a; return utils::mkConst(res); @@ -120,7 +120,7 @@ Node RewriteRule<EvalNot>::apply(TNode node) { // template<> inline // Node RewriteRule<EvalComp>::apply(TNode node) { -// BVDebug("bv-rewrite") << "RewriteRule<EvalComp>(" << node << ")" << std::endl; +// Debug("bv-rewrite") << "RewriteRule<EvalComp>(" << node << ")" << std::endl; // BitVector a = node[0].getConst<BitVector>(); // BitVector b = node[1].getConst<BitVector>(); // BitVector res; @@ -141,7 +141,7 @@ bool RewriteRule<EvalMult>::applies(TNode node) { template<> inline Node RewriteRule<EvalMult>::apply(TNode node) { - BVDebug("bv-rewrite") << "RewriteRule<EvalMult>(" << node << ")" << std::endl; + Debug("bv-rewrite") << "RewriteRule<EvalMult>(" << node << ")" << std::endl; TNode::iterator child_it = node.begin(); BitVector res = (*child_it).getConst<BitVector>(); for(++child_it; child_it != node.end(); ++child_it) { @@ -158,7 +158,7 @@ bool RewriteRule<EvalPlus>::applies(TNode node) { template<> inline Node RewriteRule<EvalPlus>::apply(TNode node) { - BVDebug("bv-rewrite") << "RewriteRule<EvalPlus>(" << node << ")" << std::endl; + Debug("bv-rewrite") << "RewriteRule<EvalPlus>(" << node << ")" << std::endl; TNode::iterator child_it = node.begin(); BitVector res = (*child_it).getConst<BitVector>(); for(++child_it; child_it != node.end(); ++child_it) { @@ -175,7 +175,7 @@ Node RewriteRule<EvalPlus>::apply(TNode node) { // template<> inline // Node RewriteRule<EvalSub>::apply(TNode node) { -// BVDebug("bv-rewrite") << "RewriteRule<EvalSub>(" << node << ")" << std::endl; +// Debug("bv-rewrite") << "RewriteRule<EvalSub>(" << node << ")" << std::endl; // BitVector a = node[0].getConst<BitVector>(); // BitVector b = node[1].getConst<BitVector>(); // BitVector res = a - b; @@ -190,7 +190,7 @@ bool RewriteRule<EvalNeg>::applies(TNode node) { template<> inline Node RewriteRule<EvalNeg>::apply(TNode node) { - BVDebug("bv-rewrite") << "RewriteRule<EvalNeg>(" << node << ")" << std::endl; + Debug("bv-rewrite") << "RewriteRule<EvalNeg>(" << node << ")" << std::endl; BitVector a = node[0].getConst<BitVector>(); BitVector res = - a; @@ -204,7 +204,7 @@ bool RewriteRule<EvalUdiv>::applies(TNode node) { template<> inline Node RewriteRule<EvalUdiv>::apply(TNode node) { - BVDebug("bv-rewrite") << "RewriteRule<EvalUdiv>(" << node << ")" << std::endl; + Debug("bv-rewrite") << "RewriteRule<EvalUdiv>(" << node << ")" << std::endl; BitVector a = node[0].getConst<BitVector>(); BitVector b = node[1].getConst<BitVector>(); BitVector res = a.unsignedDivTotal(b); @@ -219,7 +219,7 @@ bool RewriteRule<EvalUrem>::applies(TNode node) { template<> inline Node RewriteRule<EvalUrem>::apply(TNode node) { - BVDebug("bv-rewrite") << "RewriteRule<EvalUrem>(" << node << ")" << std::endl; + Debug("bv-rewrite") << "RewriteRule<EvalUrem>(" << node << ")" << std::endl; BitVector a = node[0].getConst<BitVector>(); BitVector b = node[1].getConst<BitVector>(); BitVector res = a.unsignedRemTotal(b); @@ -234,7 +234,7 @@ bool RewriteRule<EvalShl>::applies(TNode node) { template<> inline Node RewriteRule<EvalShl>::apply(TNode node) { - BVDebug("bv-rewrite") << "RewriteRule<EvalShl>(" << node << ")" << std::endl; + Debug("bv-rewrite") << "RewriteRule<EvalShl>(" << node << ")" << std::endl; BitVector a = node[0].getConst<BitVector>(); BitVector b = node[1].getConst<BitVector>(); @@ -250,7 +250,7 @@ bool RewriteRule<EvalLshr>::applies(TNode node) { template<> inline Node RewriteRule<EvalLshr>::apply(TNode node) { - BVDebug("bv-rewrite") << "RewriteRule<EvalLshr>(" << node << ")" << std::endl; + Debug("bv-rewrite") << "RewriteRule<EvalLshr>(" << node << ")" << std::endl; BitVector a = node[0].getConst<BitVector>(); BitVector b = node[1].getConst<BitVector>(); @@ -266,7 +266,7 @@ bool RewriteRule<EvalAshr>::applies(TNode node) { template<> inline Node RewriteRule<EvalAshr>::apply(TNode node) { - BVDebug("bv-rewrite") << "RewriteRule<EvalAshr>(" << node << ")" << std::endl; + Debug("bv-rewrite") << "RewriteRule<EvalAshr>(" << node << ")" << std::endl; BitVector a = node[0].getConst<BitVector>(); BitVector b = node[1].getConst<BitVector>(); @@ -282,7 +282,7 @@ bool RewriteRule<EvalUlt>::applies(TNode node) { template<> inline Node RewriteRule<EvalUlt>::apply(TNode node) { - BVDebug("bv-rewrite") << "RewriteRule<EvalUlt>(" << node << ")" << std::endl; + Debug("bv-rewrite") << "RewriteRule<EvalUlt>(" << node << ")" << std::endl; BitVector a = node[0].getConst<BitVector>(); BitVector b = node[1].getConst<BitVector>(); @@ -300,7 +300,7 @@ bool RewriteRule<EvalSlt>::applies(TNode node) { template<> inline Node RewriteRule<EvalSlt>::apply(TNode node) { - BVDebug("bv-rewrite") << "RewriteRule<EvalSlt>(" << node << ")" << std::endl; + Debug("bv-rewrite") << "RewriteRule<EvalSlt>(" << node << ")" << std::endl; BitVector a = node[0].getConst<BitVector>(); BitVector b = node[1].getConst<BitVector>(); @@ -319,7 +319,7 @@ bool RewriteRule<EvalUle>::applies(TNode node) { template<> inline Node RewriteRule<EvalUle>::apply(TNode node) { - BVDebug("bv-rewrite") << "RewriteRule<EvalUle>(" << node << ")" << std::endl; + Debug("bv-rewrite") << "RewriteRule<EvalUle>(" << node << ")" << std::endl; BitVector a = node[0].getConst<BitVector>(); BitVector b = node[1].getConst<BitVector>(); @@ -337,7 +337,7 @@ bool RewriteRule<EvalSle>::applies(TNode node) { template<> inline Node RewriteRule<EvalSle>::apply(TNode node) { - BVDebug("bv-rewrite") << "RewriteRule<EvalSle>(" << node << ")" << std::endl; + Debug("bv-rewrite") << "RewriteRule<EvalSle>(" << node << ")" << std::endl; BitVector a = node[0].getConst<BitVector>(); BitVector b = node[1].getConst<BitVector>(); @@ -355,7 +355,7 @@ bool RewriteRule<EvalExtract>::applies(TNode node) { template<> inline Node RewriteRule<EvalExtract>::apply(TNode node) { - BVDebug("bv-rewrite") << "RewriteRule<EvalExtract>(" << node << ")" << std::endl; + Debug("bv-rewrite") << "RewriteRule<EvalExtract>(" << node << ")" << std::endl; BitVector a = node[0].getConst<BitVector>(); unsigned lo = utils::getExtractLow(node); unsigned hi = utils::getExtractHigh(node); @@ -373,7 +373,7 @@ bool RewriteRule<EvalConcat>::applies(TNode node) { template<> inline Node RewriteRule<EvalConcat>::apply(TNode node) { - BVDebug("bv-rewrite") << "RewriteRule<EvalConcat>(" << node << ")" << std::endl; + Debug("bv-rewrite") << "RewriteRule<EvalConcat>(" << node << ")" << std::endl; unsigned num = node.getNumChildren(); BitVector res = node[0].getConst<BitVector>(); for(unsigned i = 1; i < num; ++i ) { @@ -391,7 +391,7 @@ bool RewriteRule<EvalSignExtend>::applies(TNode node) { template<> inline Node RewriteRule<EvalSignExtend>::apply(TNode node) { - BVDebug("bv-rewrite") << "RewriteRule<EvalSignExtend>(" << node << ")" << std::endl; + Debug("bv-rewrite") << "RewriteRule<EvalSignExtend>(" << node << ")" << std::endl; BitVector a = node[0].getConst<BitVector>(); unsigned amount = node.getOperator().getConst<BitVectorSignExtend>().signExtendAmount; BitVector res = a.signExtend(amount); @@ -407,7 +407,7 @@ bool RewriteRule<EvalEquals>::applies(TNode node) { template<> inline Node RewriteRule<EvalEquals>::apply(TNode node) { - BVDebug("bv-rewrite") << "RewriteRule<EvalEquals>(" << node << ")" << std::endl; + Debug("bv-rewrite") << "RewriteRule<EvalEquals>(" << node << ")" << std::endl; BitVector a = node[0].getConst<BitVector>(); BitVector b = node[1].getConst<BitVector>(); if (a == b) { diff --git a/src/theory/bv/theory_bv_rewrite_rules_core.h b/src/theory/bv/theory_bv_rewrite_rules_core.h index b44c72f74..ade345d1c 100644 --- a/src/theory/bv/theory_bv_rewrite_rules_core.h +++ b/src/theory/bv/theory_bv_rewrite_rules_core.h @@ -33,7 +33,7 @@ bool RewriteRule<ConcatFlatten>::applies(TNode node) { template<> inline Node RewriteRule<ConcatFlatten>::apply(TNode node) { - BVDebug("bv-rewrite") << "RewriteRule<ConcatFlatten>(" << node << ")" << std::endl; + Debug("bv-rewrite") << "RewriteRule<ConcatFlatten>(" << node << ")" << std::endl; NodeBuilder<> result(kind::BITVECTOR_CONCAT); std::vector<Node> processing_stack; processing_stack.push_back(node); @@ -48,7 +48,7 @@ Node RewriteRule<ConcatFlatten>::apply(TNode node) { } } Node resultNode = result; - BVDebug("bv-rewrite") << "RewriteRule<ConcatFlatten>(" << resultNode << ")" << std::endl; + Debug("bv-rewrite") << "RewriteRule<ConcatFlatten>(" << resultNode << ")" << std::endl; return resultNode; } @@ -60,7 +60,7 @@ bool RewriteRule<ConcatExtractMerge>::applies(TNode node) { template<> inline Node RewriteRule<ConcatExtractMerge>::apply(TNode node) { - BVDebug("bv-rewrite") << "RewriteRule<ConcatExtractMerge>(" << node << ")" << std::endl; + Debug("bv-rewrite") << "RewriteRule<ConcatExtractMerge>(" << node << ")" << std::endl; std::vector<Node> mergedExtracts; @@ -121,7 +121,7 @@ bool RewriteRule<ConcatConstantMerge>::applies(TNode node) { template<> inline Node RewriteRule<ConcatConstantMerge>::apply(TNode node) { - BVDebug("bv-rewrite") << "RewriteRule<ConcatConstantMerge>(" << node << ")" << std::endl; + Debug("bv-rewrite") << "RewriteRule<ConcatConstantMerge>(" << node << ")" << std::endl; std::vector<Node> mergedConstants; for (unsigned i = 0, end = node.getNumChildren(); i < end;) { @@ -150,7 +150,7 @@ Node RewriteRule<ConcatConstantMerge>::apply(TNode node) { } } - BVDebug("bv-rewrite") << "RewriteRule<ConcatConstantMerge>(" << node << ") => " << utils::mkConcat(mergedConstants) << std::endl; + Debug("bv-rewrite") << "RewriteRule<ConcatConstantMerge>(" << node << ") => " << utils::mkConcat(mergedConstants) << std::endl; return utils::mkConcat(mergedConstants); } @@ -168,7 +168,7 @@ bool RewriteRule<ExtractWhole>::applies(TNode node) { template<> inline Node RewriteRule<ExtractWhole>::apply(TNode node) { - BVDebug("bv-rewrite") << "RewriteRule<ExtractWhole>(" << node << ")" << std::endl; + Debug("bv-rewrite") << "RewriteRule<ExtractWhole>(" << node << ")" << std::endl; return node[0]; } @@ -181,7 +181,7 @@ bool RewriteRule<ExtractConstant>::applies(TNode node) { template<> inline Node RewriteRule<ExtractConstant>::apply(TNode node) { - BVDebug("bv-rewrite") << "RewriteRule<ExtractConstant>(" << node << ")" << std::endl; + Debug("bv-rewrite") << "RewriteRule<ExtractConstant>(" << node << ")" << std::endl; Node child = node[0]; BitVector childValue = child.getConst<BitVector>(); return utils::mkConst(childValue.extract(utils::getExtractHigh(node), utils::getExtractLow(node))); @@ -189,7 +189,7 @@ Node RewriteRule<ExtractConstant>::apply(TNode node) { template<> inline bool RewriteRule<ExtractConcat>::applies(TNode node) { - //BVDebug("bv-rewrite") << "RewriteRule<ExtractConcat>(" << node << ")" << std::endl; + //Debug("bv-rewrite") << "RewriteRule<ExtractConcat>(" << node << ")" << std::endl; if (node.getKind() != kind::BITVECTOR_EXTRACT) return false; if (node[0].getKind() != kind::BITVECTOR_CONCAT) return false; return true; @@ -197,7 +197,7 @@ bool RewriteRule<ExtractConcat>::applies(TNode node) { template<> inline Node RewriteRule<ExtractConcat>::apply(TNode node) { - BVDebug("bv-rewrite") << "RewriteRule<ExtractConcat>(" << node << ")" << std::endl; + Debug("bv-rewrite") << "RewriteRule<ExtractConcat>(" << node << ")" << std::endl; int extract_high = utils::getExtractHigh(node); int extract_low = utils::getExtractLow(node); @@ -230,7 +230,7 @@ bool RewriteRule<ExtractExtract>::applies(TNode node) { template<> inline Node RewriteRule<ExtractExtract>::apply(TNode node) { - BVDebug("bv-rewrite") << "RewriteRule<ExtractExtract>(" << node << ")" << std::endl; + Debug("bv-rewrite") << "RewriteRule<ExtractExtract>(" << node << ")" << std::endl; // x[i:j][k:l] ~> x[k+j:l+j] Node child = node[0]; @@ -244,7 +244,7 @@ Node RewriteRule<ExtractExtract>::apply(TNode node) { template<> inline bool RewriteRule<FailEq>::applies(TNode node) { - //BVDebug("bv-rewrite") << "RewriteRule<FailEq>(" << node << ")" << std::endl; + //Debug("bv-rewrite") << "RewriteRule<FailEq>(" << node << ")" << std::endl; if (node.getKind() != kind::EQUAL) return false; if (node[0].getKind() != kind::CONST_BITVECTOR) return false; if (node[1].getKind() != kind::CONST_BITVECTOR) return false; @@ -264,7 +264,7 @@ bool RewriteRule<SimplifyEq>::applies(TNode node) { template<> inline Node RewriteRule<SimplifyEq>::apply(TNode node) { - BVDebug("bv-rewrite") << "RewriteRule<SimplifyEq>(" << node << ")" << std::endl; + Debug("bv-rewrite") << "RewriteRule<SimplifyEq>(" << node << ")" << std::endl; return utils::mkTrue(); } @@ -275,7 +275,7 @@ bool RewriteRule<ReflexivityEq>::applies(TNode node) { template<> inline Node RewriteRule<ReflexivityEq>::apply(TNode node) { - BVDebug("bv-rewrite") << "RewriteRule<ReflexivityEq>(" << node << ")" << std::endl; + Debug("bv-rewrite") << "RewriteRule<ReflexivityEq>(" << node << ")" << std::endl; return node[1].eqNode(node[0]); } diff --git a/src/theory/bv/theory_bv_rewrite_rules_normalization.h b/src/theory/bv/theory_bv_rewrite_rules_normalization.h index 6b3d0f770..39f55f26c 100644 --- a/src/theory/bv/theory_bv_rewrite_rules_normalization.h +++ b/src/theory/bv/theory_bv_rewrite_rules_normalization.h @@ -41,7 +41,7 @@ bool RewriteRule<ExtractBitwise>::applies(TNode node) { template<> inline Node RewriteRule<ExtractBitwise>::apply(TNode node) { - BVDebug("bv-rewrite") << "RewriteRule<ExtractBitwise>(" << node << ")" << std::endl; + Debug("bv-rewrite") << "RewriteRule<ExtractBitwise>(" << node << ")" << std::endl; unsigned high = utils::getExtractHigh(node); unsigned low = utils::getExtractLow(node); std::vector<Node> children; @@ -65,7 +65,7 @@ bool RewriteRule<ExtractNot>::applies(TNode node) { template<> inline Node RewriteRule<ExtractNot>::apply(TNode node) { - BVDebug("bv-rewrite") << "RewriteRule<ExtractNot>(" << node << ")" << std::endl; + Debug("bv-rewrite") << "RewriteRule<ExtractNot>(" << node << ")" << std::endl; unsigned low = utils::getExtractLow(node); unsigned high = utils::getExtractHigh(node); Node a = utils::mkExtract(node[0][0], high, low); @@ -88,7 +88,7 @@ bool RewriteRule<ExtractArith>::applies(TNode node) { template<> inline Node RewriteRule<ExtractArith>::apply(TNode node) { - BVDebug("bv-rewrite") << "RewriteRule<ExtractArith>(" << node << ")" << std::endl; + Debug("bv-rewrite") << "RewriteRule<ExtractArith>(" << node << ")" << std::endl; unsigned low = utils::getExtractLow(node); Assert (low == 0); unsigned high = utils::getExtractHigh(node); @@ -117,7 +117,7 @@ bool RewriteRule<ExtractArith2>::applies(TNode node) { template<> inline Node RewriteRule<ExtractArith2>::apply(TNode node) { - BVDebug("bv-rewrite") << "RewriteRule<ExtractArith2>(" << node << ")" << std::endl; + Debug("bv-rewrite") << "RewriteRule<ExtractArith2>(" << node << ")" << std::endl; unsigned low = utils::getExtractLow(node); unsigned high = utils::getExtractHigh(node); std::vector<Node> children; @@ -151,7 +151,7 @@ bool RewriteRule<FlattenAssocCommut>::applies(TNode node) { template<> inline Node RewriteRule<FlattenAssocCommut>::apply(TNode node) { - BVDebug("bv-rewrite") << "RewriteRule<FlattenAssocCommut>(" << node << ")" << std::endl; + Debug("bv-rewrite") << "RewriteRule<FlattenAssocCommut>(" << node << ")" << std::endl; std::vector<Node> processingStack; processingStack.push_back(node); std::vector<Node> children; @@ -291,7 +291,7 @@ bool RewriteRule<PlusCombineLikeTerms>::applies(TNode node) { template<> inline Node RewriteRule<PlusCombineLikeTerms>::apply(TNode node) { - BVDebug("bv-rewrite") << "RewriteRule<PlusCombineLikeTerms>(" << node << ")" << std::endl; + Debug("bv-rewrite") << "RewriteRule<PlusCombineLikeTerms>(" << node << ")" << std::endl; unsigned size = utils::getSize(node); BitVector constSum(size, (unsigned)0); std::map<Node, BitVector> factorToCoefficient; @@ -348,7 +348,7 @@ bool RewriteRule<MultSimplify>::applies(TNode node) { template<> inline Node RewriteRule<MultSimplify>::apply(TNode node) { - BVDebug("bv-rewrite") << "RewriteRule<MultSimplify>(" << node << ")" << std::endl; + Debug("bv-rewrite") << "RewriteRule<MultSimplify>(" << node << ")" << std::endl; unsigned size = utils::getSize(node); BitVector constant(size, Integer(1)); @@ -397,7 +397,7 @@ bool RewriteRule<MultDistribConst>::applies(TNode node) { template<> inline Node RewriteRule<MultDistribConst>::apply(TNode node) { - BVDebug("bv-rewrite") << "RewriteRule<MultDistribConst>(" << node << ")" << std::endl; + Debug("bv-rewrite") << "RewriteRule<MultDistribConst>(" << node << ")" << std::endl; TNode constant = node[1]; TNode factor = node[0]; @@ -434,7 +434,7 @@ bool RewriteRule<SolveEq>::applies(TNode node) { // Doesn't do full solving (yet), instead, if a term appears both on lhs and rhs, it subtracts from both sides so that one side's coeff is zero template<> inline Node RewriteRule<SolveEq>::apply(TNode node) { - BVDebug("bv-rewrite") << "RewriteRule<SolveEq>(" << node << ")" << std::endl; + Debug("bv-rewrite") << "RewriteRule<SolveEq>(" << node << ")" << std::endl; TNode left = node[0]; TNode right = node[1]; @@ -662,7 +662,7 @@ static inline Node mkNodeKind(Kind k, TNode node, TNode c) { template<> inline Node RewriteRule<BitwiseEq>::apply(TNode node) { - BVDebug("bv-rewrite") << "RewriteRule<BitwiseEq>(" << node << ")" << std::endl; + Debug("bv-rewrite") << "RewriteRule<BitwiseEq>(" << node << ")" << std::endl; TNode term; BitVector c; @@ -745,7 +745,7 @@ bool RewriteRule<NegMult>::applies(TNode node) { template<> inline Node RewriteRule<NegMult>::apply(TNode node) { - BVDebug("bv-rewrite") << "RewriteRule<NegMult>(" << node << ")" << std::endl; + Debug("bv-rewrite") << "RewriteRule<NegMult>(" << node << ")" << std::endl; TNode mult = node[0]; NodeBuilder<> nb(kind::BITVECTOR_MULT); BitVector bv(utils::getSize(node), (unsigned)1); @@ -767,7 +767,7 @@ bool RewriteRule<NegSub>::applies(TNode node) { template<> inline Node RewriteRule<NegSub>::apply(TNode node) { - BVDebug("bv-rewrite") << "RewriteRule<NegSub>(" << node << ")" << std::endl; + Debug("bv-rewrite") << "RewriteRule<NegSub>(" << node << ")" << std::endl; return utils::mkNode(kind::BITVECTOR_SUB, node[0][1], node[0][0]); } @@ -779,7 +779,7 @@ bool RewriteRule<NegPlus>::applies(TNode node) { template<> inline Node RewriteRule<NegPlus>::apply(TNode node) { - BVDebug("bv-rewrite") << "RewriteRule<NegPlus>(" << node << ")" << std::endl; + Debug("bv-rewrite") << "RewriteRule<NegPlus>(" << node << ")" << std::endl; std::vector<Node> children; for (unsigned i = 0; i < node[0].getNumChildren(); ++i) { children.push_back(utils::mkNode(kind::BITVECTOR_NEG, node[0][i])); @@ -820,7 +820,7 @@ bool RewriteRule<AndSimplify>::applies(TNode node) { template<> inline Node RewriteRule<AndSimplify>::apply(TNode node) { - BVDebug("bv-rewrite") << "RewriteRule<AndSimplify>(" << node << ")" << std::endl; + Debug("bv-rewrite") << "RewriteRule<AndSimplify>(" << node << ")" << std::endl; // this will remove duplicates std::hash_map<TNode, Count, TNodeHashFunction> subterms; @@ -883,7 +883,7 @@ bool RewriteRule<OrSimplify>::applies(TNode node) { template<> inline Node RewriteRule<OrSimplify>::apply(TNode node) { - BVDebug("bv-rewrite") << "RewriteRule<OrSimplify>(" << node << ")" << std::endl; + Debug("bv-rewrite") << "RewriteRule<OrSimplify>(" << node << ")" << std::endl; // this will remove duplicates std::hash_map<TNode, Count, TNodeHashFunction> subterms; @@ -946,7 +946,7 @@ bool RewriteRule<XorSimplify>::applies(TNode node) { template<> inline Node RewriteRule<XorSimplify>::apply(TNode node) { - BVDebug("bv-rewrite") << "RewriteRule<XorSimplify>(" << node << ")" << std::endl; + Debug("bv-rewrite") << "RewriteRule<XorSimplify>(" << node << ")" << std::endl; std::hash_map<TNode, Count, TNodeHashFunction> subterms; @@ -1041,7 +1041,7 @@ Node RewriteRule<XorSimplify>::apply(TNode node) { // template<> inline // Node RewriteRule<AndSimplify>::apply(TNode node) { -// BVDebug("bv-rewrite") << "RewriteRule<AndSimplify>(" << node << ")" << std::endl; +// Debug("bv-rewrite") << "RewriteRule<AndSimplify>(" << node << ")" << std::endl; // return resultNode; // } @@ -1053,7 +1053,7 @@ Node RewriteRule<XorSimplify>::apply(TNode node) { // template<> inline // Node RewriteRule<>::apply(TNode node) { -// BVDebug("bv-rewrite") << "RewriteRule<>(" << node << ")" << std::endl; +// Debug("bv-rewrite") << "RewriteRule<>(" << node << ")" << std::endl; // return resultNode; // } diff --git a/src/theory/bv/theory_bv_rewrite_rules_operator_elimination.h b/src/theory/bv/theory_bv_rewrite_rules_operator_elimination.h index 94983e03a..4202f8c2e 100644 --- a/src/theory/bv/theory_bv_rewrite_rules_operator_elimination.h +++ b/src/theory/bv/theory_bv_rewrite_rules_operator_elimination.h @@ -33,7 +33,7 @@ bool RewriteRule<UgtEliminate>::applies(TNode node) { template<> Node RewriteRule<UgtEliminate>::apply(TNode node) { - BVDebug("bv-rewrite") << "RewriteRule<UgtEliminate>(" << node << ")" << std::endl; + Debug("bv-rewrite") << "RewriteRule<UgtEliminate>(" << node << ")" << std::endl; TNode a = node[0]; TNode b = node[1]; Node result = utils::mkNode(kind::BITVECTOR_ULT, b, a); @@ -48,7 +48,7 @@ bool RewriteRule<UgeEliminate>::applies(TNode node) { template<> Node RewriteRule<UgeEliminate>::apply(TNode node) { - BVDebug("bv-rewrite") << "RewriteRule<UgeEliminate>(" << node << ")" << std::endl; + Debug("bv-rewrite") << "RewriteRule<UgeEliminate>(" << node << ")" << std::endl; TNode a = node[0]; TNode b = node[1]; Node result = utils::mkNode(kind::BITVECTOR_ULE, b, a); @@ -63,7 +63,7 @@ bool RewriteRule<SgtEliminate>::applies(TNode node) { template<> Node RewriteRule<SgtEliminate>::apply(TNode node) { - BVDebug("bv-rewrite") << "RewriteRule<SgtEliminate>(" << node << ")" << std::endl; + Debug("bv-rewrite") << "RewriteRule<SgtEliminate>(" << node << ")" << std::endl; TNode a = node[0]; TNode b = node[1]; Node result = utils::mkNode(kind::BITVECTOR_SLT, b, a); @@ -78,7 +78,7 @@ bool RewriteRule<SgeEliminate>::applies(TNode node) { template<> Node RewriteRule<SgeEliminate>::apply(TNode node) { - BVDebug("bv-rewrite") << "RewriteRule<SgeEliminate>(" << node << ")" << std::endl; + Debug("bv-rewrite") << "RewriteRule<SgeEliminate>(" << node << ")" << std::endl; TNode a = node[0]; TNode b = node[1]; Node result = utils::mkNode(kind::BITVECTOR_SLE, b, a); @@ -92,7 +92,7 @@ bool RewriteRule<SltEliminate>::applies(TNode node) { template <> Node RewriteRule<SltEliminate>::apply(TNode node) { - BVDebug("bv-rewrite") << "RewriteRule<SltEliminate>(" << node << ")" << std::endl; + Debug("bv-rewrite") << "RewriteRule<SltEliminate>(" << node << ")" << std::endl; unsigned size = utils::getSize(node[0]); Node pow_two = utils::mkConst(BitVector(size, Integer(1).multiplyByPow2(size - 1))); @@ -110,7 +110,7 @@ bool RewriteRule<SleEliminate>::applies(TNode node) { template <> Node RewriteRule<SleEliminate>::apply(TNode node) { - BVDebug("bv-rewrite") << "RewriteRule<SleEliminate>(" << node << ")" << std::endl; + Debug("bv-rewrite") << "RewriteRule<SleEliminate>(" << node << ")" << std::endl; unsigned size = utils::getSize(node[0]); Node pow_two = utils::mkConst(BitVector(size, Integer(1).multiplyByPow2(size - 1))); @@ -128,7 +128,7 @@ bool RewriteRule<CompEliminate>::applies(TNode node) { template <> Node RewriteRule<CompEliminate>::apply(TNode node) { - BVDebug("bv-rewrite") << "RewriteRule<CompEliminate>(" << node << ")" << std::endl; + Debug("bv-rewrite") << "RewriteRule<CompEliminate>(" << node << ")" << std::endl; Node comp = utils::mkNode(kind::EQUAL, node[0], node[1]); Node one = utils::mkConst(1, 1); Node zero = utils::mkConst(1, 0); @@ -143,7 +143,7 @@ bool RewriteRule<SubEliminate>::applies(TNode node) { template <> Node RewriteRule<SubEliminate>::apply(TNode node) { - BVDebug("bv-rewrite") << "RewriteRule<SubEliminate>(" << node << ")" << std::endl; + Debug("bv-rewrite") << "RewriteRule<SubEliminate>(" << node << ")" << std::endl; Node negb = utils::mkNode(kind::BITVECTOR_NEG, node[1]); Node a = node[0]; @@ -158,7 +158,7 @@ bool RewriteRule<RepeatEliminate>::applies(TNode node) { template<> Node RewriteRule<RepeatEliminate>::apply(TNode node) { - BVDebug("bv-rewrite") << "RewriteRule<RepeatEliminate>(" << node << ")" << std::endl; + Debug("bv-rewrite") << "RewriteRule<RepeatEliminate>(" << node << ")" << std::endl; TNode a = node[0]; unsigned amount = node.getOperator().getConst<BitVectorRepeat>().repeatAmount; Assert(amount >= 1); @@ -180,7 +180,7 @@ bool RewriteRule<RotateLeftEliminate>::applies(TNode node) { template<> Node RewriteRule<RotateLeftEliminate>::apply(TNode node) { - BVDebug("bv-rewrite") << "RewriteRule<RotateLeftEliminate>(" << node << ")" << std::endl; + Debug("bv-rewrite") << "RewriteRule<RotateLeftEliminate>(" << node << ")" << std::endl; TNode a = node[0]; unsigned amount = node.getOperator().getConst<BitVectorRotateLeft>().rotateLeftAmount; amount = amount % utils::getSize(a); @@ -202,7 +202,7 @@ bool RewriteRule<RotateRightEliminate>::applies(TNode node) { template<> Node RewriteRule<RotateRightEliminate>::apply(TNode node) { - BVDebug("bv-rewrite") << "RewriteRule<RotateRightEliminate>(" << node << ")" << std::endl; + Debug("bv-rewrite") << "RewriteRule<RotateRightEliminate>(" << node << ")" << std::endl; TNode a = node[0]; unsigned amount = node.getOperator().getConst<BitVectorRotateRight>().rotateRightAmount; amount = amount % utils::getSize(a); @@ -225,7 +225,7 @@ bool RewriteRule<NandEliminate>::applies(TNode node) { template<> Node RewriteRule<NandEliminate>::apply(TNode node) { - BVDebug("bv-rewrite") << "RewriteRule<NandEliminate>(" << node << ")" << std::endl; + Debug("bv-rewrite") << "RewriteRule<NandEliminate>(" << node << ")" << std::endl; TNode a = node[0]; TNode b = node[1]; Node andNode = utils::mkNode(kind::BITVECTOR_AND, a, b); @@ -241,7 +241,7 @@ bool RewriteRule<NorEliminate>::applies(TNode node) { template<> Node RewriteRule<NorEliminate>::apply(TNode node) { - BVDebug("bv-rewrite") << "RewriteRule<NorEliminate>(" << node << ")" << std::endl; + Debug("bv-rewrite") << "RewriteRule<NorEliminate>(" << node << ")" << std::endl; TNode a = node[0]; TNode b = node[1]; Node orNode = utils::mkNode(kind::BITVECTOR_OR, a, b); @@ -257,7 +257,7 @@ bool RewriteRule<XnorEliminate>::applies(TNode node) { template<> Node RewriteRule<XnorEliminate>::apply(TNode node) { - BVDebug("bv-rewrite") << "RewriteRule<XnorEliminate>(" << node << ")" << std::endl; + Debug("bv-rewrite") << "RewriteRule<XnorEliminate>(" << node << ")" << std::endl; TNode a = node[0]; TNode b = node[1]; Node xorNode = utils::mkNode(kind::BITVECTOR_XOR, a, b); @@ -272,7 +272,7 @@ bool RewriteRule<SdivEliminate>::applies(TNode node) { template<> Node RewriteRule<SdivEliminate>::apply(TNode node) { - BVDebug("bv-rewrite") << "RewriteRule<SdivEliminate>(" << node << ")" << std::endl; + Debug("bv-rewrite") << "RewriteRule<SdivEliminate>(" << node << ")" << std::endl; TNode a = node[0]; TNode b = node[1]; @@ -301,7 +301,7 @@ bool RewriteRule<SremEliminate>::applies(TNode node) { template<> Node RewriteRule<SremEliminate>::apply(TNode node) { - BVDebug("bv-rewrite") << "RewriteRule<SremEliminate>(" << node << ")" << std::endl; + Debug("bv-rewrite") << "RewriteRule<SremEliminate>(" << node << ")" << std::endl; TNode a = node[0]; TNode b = node[1]; unsigned size = utils::getSize(a); @@ -327,7 +327,7 @@ bool RewriteRule<SmodEliminate>::applies(TNode node) { template<> Node RewriteRule<SmodEliminate>::apply(TNode node) { - BVDebug("bv-rewrite") << "RewriteRule<SmodEliminate>(" << node << ")" << std::endl; + Debug("bv-rewrite") << "RewriteRule<SmodEliminate>(" << node << ")" << std::endl; TNode s = node[0]; TNode t = node[1]; unsigned size = utils::getSize(s); @@ -382,7 +382,7 @@ bool RewriteRule<ZeroExtendEliminate>::applies(TNode node) { template<> Node RewriteRule<ZeroExtendEliminate>::apply(TNode node) { - BVDebug("bv-rewrite") << "RewriteRule<ZeroExtendEliminate>(" << node << ")" << std::endl; + Debug("bv-rewrite") << "RewriteRule<ZeroExtendEliminate>(" << node << ")" << std::endl; TNode bv = node[0]; unsigned amount = node.getOperator().getConst<BitVectorZeroExtend>().zeroExtendAmount; @@ -402,7 +402,7 @@ bool RewriteRule<SignExtendEliminate>::applies(TNode node) { template<> Node RewriteRule<SignExtendEliminate>::apply(TNode node) { - BVDebug("bv-rewrite") << "RewriteRule<SignExtendEliminate>(" << node << ")" << std::endl; + Debug("bv-rewrite") << "RewriteRule<SignExtendEliminate>(" << node << ")" << std::endl; unsigned amount = node.getOperator().getConst<BitVectorSignExtend>().signExtendAmount; if(amount == 0) { diff --git a/src/theory/bv/theory_bv_rewrite_rules_simplification.h b/src/theory/bv/theory_bv_rewrite_rules_simplification.h index 8bcc64414..9d1cafab9 100644 --- a/src/theory/bv/theory_bv_rewrite_rules_simplification.h +++ b/src/theory/bv/theory_bv_rewrite_rules_simplification.h @@ -43,7 +43,7 @@ bool RewriteRule<ShlByConst>::applies(TNode node) { template<> inline Node RewriteRule<ShlByConst>::apply(TNode node) { - BVDebug("bv-rewrite") << "RewriteRule<ShlByConst>(" << node << ")" << std::endl; + Debug("bv-rewrite") << "RewriteRule<ShlByConst>(" << node << ")" << std::endl; Integer amount = node[1].getConst<BitVector>().toInteger(); Node a = node[0]; @@ -79,7 +79,7 @@ bool RewriteRule<LshrByConst>::applies(TNode node) { template<> inline Node RewriteRule<LshrByConst>::apply(TNode node) { - BVDebug("bv-rewrite") << "RewriteRule<LshrByConst>(" << node << ")" << std::endl; + Debug("bv-rewrite") << "RewriteRule<LshrByConst>(" << node << ")" << std::endl; Integer amount = node[1].getConst<BitVector>().toInteger(); Node a = node[0]; @@ -115,7 +115,7 @@ bool RewriteRule<AshrByConst>::applies(TNode node) { template<> inline Node RewriteRule<AshrByConst>::apply(TNode node) { - BVDebug("bv-rewrite") << "RewriteRule<AshrByConst>(" << node << ")" << std::endl; + Debug("bv-rewrite") << "RewriteRule<AshrByConst>(" << node << ")" << std::endl; Integer amount = node[1].getConst<BitVector>().toInteger(); Node a = node[0]; @@ -160,7 +160,7 @@ bool RewriteRule<BitwiseIdemp>::applies(TNode node) { template<> inline Node RewriteRule<BitwiseIdemp>::apply(TNode node) { Unreachable(); - BVDebug("bv-rewrite") << "RewriteRule<BitwiseIdemp>(" << node << ")" << std::endl; + Debug("bv-rewrite") << "RewriteRule<BitwiseIdemp>(" << node << ")" << std::endl; return node[0]; } @@ -183,7 +183,7 @@ bool RewriteRule<AndZero>::applies(TNode node) { template<> inline Node RewriteRule<AndZero>::apply(TNode node) { Unreachable(); - BVDebug("bv-rewrite") << "RewriteRule<AndZero>(" << node << ")" << std::endl; + Debug("bv-rewrite") << "RewriteRule<AndZero>(" << node << ")" << std::endl; return utils::mkConst(utils::getSize(node), 0); } @@ -207,7 +207,7 @@ bool RewriteRule<AndOne>::applies(TNode node) { template<> inline Node RewriteRule<AndOne>::apply(TNode node) { Unreachable(); - BVDebug("bv-rewrite") << "RewriteRule<AndOne>(" << node << ")" << std::endl; + Debug("bv-rewrite") << "RewriteRule<AndOne>(" << node << ")" << std::endl; unsigned size = utils::getSize(node); if (node[0] == utils::mkOnes(size)) { @@ -237,7 +237,7 @@ bool RewriteRule<OrZero>::applies(TNode node) { template<> inline Node RewriteRule<OrZero>::apply(TNode node) { Unreachable(); - BVDebug("bv-rewrite") << "RewriteRule<OrZero>(" << node << ")" << std::endl; + Debug("bv-rewrite") << "RewriteRule<OrZero>(" << node << ")" << std::endl; unsigned size = utils::getSize(node); if (node[0] == utils::mkConst(size, 0)) { @@ -268,7 +268,7 @@ bool RewriteRule<OrOne>::applies(TNode node) { template<> inline Node RewriteRule<OrOne>::apply(TNode node) { Unreachable(); - BVDebug("bv-rewrite") << "RewriteRule<OrOne>(" << node << ")" << std::endl; + Debug("bv-rewrite") << "RewriteRule<OrOne>(" << node << ")" << std::endl; return utils::mkOnes(utils::getSize(node)); } @@ -290,7 +290,7 @@ bool RewriteRule<XorDuplicate>::applies(TNode node) { template<> inline Node RewriteRule<XorDuplicate>::apply(TNode node) { Unreachable(); - BVDebug("bv-rewrite") << "RewriteRule<XorDuplicate>(" << node << ")" << std::endl; + Debug("bv-rewrite") << "RewriteRule<XorDuplicate>(" << node << ")" << std::endl; return utils::mkConst(BitVector(utils::getSize(node), Integer(0))); } @@ -316,7 +316,7 @@ bool RewriteRule<XorOne>::applies(TNode node) { template<> inline Node RewriteRule<XorOne>::apply(TNode node) { - BVDebug("bv-rewrite") << "RewriteRule<XorOne>(" << node << ")" << std::endl; + Debug("bv-rewrite") << "RewriteRule<XorOne>(" << node << ")" << std::endl; Node ones = utils::mkOnes(utils::getSize(node)); std::vector<Node> children; bool found_ones = false; @@ -360,7 +360,7 @@ bool RewriteRule<XorZero>::applies(TNode node) { template<> inline Node RewriteRule<XorZero>::apply(TNode node) { - BVDebug("bv-rewrite") << "RewriteRule<XorZero>(" << node << ")" << std::endl; + Debug("bv-rewrite") << "RewriteRule<XorZero>(" << node << ")" << std::endl; std::vector<Node> children; Node zero = utils::mkConst(utils::getSize(node), 0); @@ -393,7 +393,7 @@ bool RewriteRule<BitwiseNotAnd>::applies(TNode node) { template<> inline Node RewriteRule<BitwiseNotAnd>::apply(TNode node) { Unreachable(); - BVDebug("bv-rewrite") << "RewriteRule<BitwiseNegAnd>(" << node << ")" << std::endl; + Debug("bv-rewrite") << "RewriteRule<BitwiseNegAnd>(" << node << ")" << std::endl; return utils::mkConst(BitVector(utils::getSize(node), Integer(0))); } @@ -415,7 +415,7 @@ bool RewriteRule<BitwiseNotOr>::applies(TNode node) { template<> inline Node RewriteRule<BitwiseNotOr>::apply(TNode node) { Unreachable(); - BVDebug("bv-rewrite") << "RewriteRule<BitwiseNotOr>(" << node << ")" << std::endl; + Debug("bv-rewrite") << "RewriteRule<BitwiseNotOr>(" << node << ")" << std::endl; uint32_t size = utils::getSize(node); Integer ones = Integer(1).multiplyByPow2(size) - 1; return utils::mkConst(BitVector(size, ones)); @@ -435,7 +435,7 @@ bool RewriteRule<XorNot>::applies(TNode node) { template<> inline Node RewriteRule<XorNot>::apply(TNode node) { Unreachable(); - BVDebug("bv-rewrite") << "RewriteRule<XorNot>(" << node << ")" << std::endl; + Debug("bv-rewrite") << "RewriteRule<XorNot>(" << node << ")" << std::endl; Node a = node[0][0]; Node b = node[1][0]; return utils::mkNode(kind::BITVECTOR_XOR, a, b); @@ -455,7 +455,7 @@ bool RewriteRule<NotXor>::applies(TNode node) { template<> inline Node RewriteRule<NotXor>::apply(TNode node) { - BVDebug("bv-rewrite") << "RewriteRule<NotXor>(" << node << ")" << std::endl; + Debug("bv-rewrite") << "RewriteRule<NotXor>(" << node << ")" << std::endl; std::vector<Node> children; TNode::iterator child_it = node[0].begin(); children.push_back(utils::mkNode(kind::BITVECTOR_NOT, *child_it)); @@ -479,7 +479,7 @@ bool RewriteRule<NotIdemp>::applies(TNode node) { template<> inline Node RewriteRule<NotIdemp>::apply(TNode node) { - BVDebug("bv-rewrite") << "RewriteRule<XorIdemp>(" << node << ")" << std::endl; + Debug("bv-rewrite") << "RewriteRule<XorIdemp>(" << node << ")" << std::endl; return node[0][0]; } @@ -500,7 +500,7 @@ bool RewriteRule<LtSelf>::applies(TNode node) { template<> inline Node RewriteRule<LtSelf>::apply(TNode node) { - BVDebug("bv-rewrite") << "RewriteRule<LtSelf>(" << node << ")" << std::endl; + Debug("bv-rewrite") << "RewriteRule<LtSelf>(" << node << ")" << std::endl; return utils::mkFalse(); } @@ -519,7 +519,7 @@ bool RewriteRule<LteSelf>::applies(TNode node) { template<> inline Node RewriteRule<LteSelf>::apply(TNode node) { - BVDebug("bv-rewrite") << "RewriteRule<LteSelf>(" << node << ")" << std::endl; + Debug("bv-rewrite") << "RewriteRule<LteSelf>(" << node << ")" << std::endl; return utils::mkTrue(); } @@ -537,7 +537,7 @@ bool RewriteRule<UltZero>::applies(TNode node) { template<> inline Node RewriteRule<UltZero>::apply(TNode node) { - BVDebug("bv-rewrite") << "RewriteRule<UltZero>(" << node << ")" << std::endl; + Debug("bv-rewrite") << "RewriteRule<UltZero>(" << node << ")" << std::endl; return utils::mkFalse(); } @@ -555,7 +555,7 @@ bool RewriteRule<UltSelf>::applies(TNode node) { template<> inline Node RewriteRule<UltSelf>::apply(TNode node) { - BVDebug("bv-rewrite") << "RewriteRule<UltSelf>(" << node << ")" << std::endl; + Debug("bv-rewrite") << "RewriteRule<UltSelf>(" << node << ")" << std::endl; return utils::mkFalse(); } @@ -574,7 +574,7 @@ bool RewriteRule<UleZero>::applies(TNode node) { template<> inline Node RewriteRule<UleZero>::apply(TNode node) { - BVDebug("bv-rewrite") << "RewriteRule<UleZero>(" << node << ")" << std::endl; + Debug("bv-rewrite") << "RewriteRule<UleZero>(" << node << ")" << std::endl; return utils::mkNode(kind::EQUAL, node[0], node[1]); } @@ -592,7 +592,7 @@ bool RewriteRule<UleSelf>::applies(TNode node) { template<> inline Node RewriteRule<UleSelf>::apply(TNode node) { - BVDebug("bv-rewrite") << "RewriteRule<UleSelf>(" << node << ")" << std::endl; + Debug("bv-rewrite") << "RewriteRule<UleSelf>(" << node << ")" << std::endl; return utils::mkTrue(); } @@ -611,7 +611,7 @@ bool RewriteRule<ZeroUle>::applies(TNode node) { template<> inline Node RewriteRule<ZeroUle>::apply(TNode node) { - BVDebug("bv-rewrite") << "RewriteRule<ZeroUle>(" << node << ")" << std::endl; + Debug("bv-rewrite") << "RewriteRule<ZeroUle>(" << node << ")" << std::endl; return utils::mkTrue(); } @@ -634,7 +634,7 @@ bool RewriteRule<UleMax>::applies(TNode node) { template<> inline Node RewriteRule<UleMax>::apply(TNode node) { - BVDebug("bv-rewrite") << "RewriteRule<UleMax>(" << node << ")" << std::endl; + Debug("bv-rewrite") << "RewriteRule<UleMax>(" << node << ")" << std::endl; return utils::mkTrue(); } @@ -652,7 +652,7 @@ bool RewriteRule<NotUlt>::applies(TNode node) { template<> inline Node RewriteRule<NotUlt>::apply(TNode node) { - BVDebug("bv-rewrite") << "RewriteRule<NotUlt>(" << node << ")" << std::endl; + Debug("bv-rewrite") << "RewriteRule<NotUlt>(" << node << ")" << std::endl; Node ult = node[0]; Node a = ult[0]; Node b = ult[1]; @@ -673,7 +673,7 @@ bool RewriteRule<NotUle>::applies(TNode node) { template<> inline Node RewriteRule<NotUle>::apply(TNode node) { - BVDebug("bv-rewrite") << "RewriteRule<NotUle>(" << node << ")" << std::endl; + Debug("bv-rewrite") << "RewriteRule<NotUle>(" << node << ")" << std::endl; Node ult = node[0]; Node a = ult[0]; Node b = ult[1]; @@ -701,7 +701,7 @@ bool RewriteRule<MultPow2>::applies(TNode node) { template<> inline Node RewriteRule<MultPow2>::apply(TNode node) { - BVDebug("bv-rewrite") << "RewriteRule<MultPow2>(" << node << ")" << std::endl; + Debug("bv-rewrite") << "RewriteRule<MultPow2>(" << node << ")" << std::endl; std::vector<Node> children; unsigned exponent = 0; @@ -736,7 +736,7 @@ bool RewriteRule<NegIdemp>::applies(TNode node) { template<> inline Node RewriteRule<NegIdemp>::apply(TNode node) { - BVDebug("bv-rewrite") << "RewriteRule<NegIdemp>(" << node << ")" << std::endl; + Debug("bv-rewrite") << "RewriteRule<NegIdemp>(" << node << ")" << std::endl; return node[0][0]; } @@ -754,7 +754,7 @@ bool RewriteRule<UdivPow2>::applies(TNode node) { template<> inline Node RewriteRule<UdivPow2>::apply(TNode node) { - BVDebug("bv-rewrite") << "RewriteRule<UdivPow2>(" << node << ")" << std::endl; + Debug("bv-rewrite") << "RewriteRule<UdivPow2>(" << node << ")" << std::endl; Node a = node[0]; unsigned power = utils::isPow2Const(node[1]) -1; @@ -778,7 +778,7 @@ bool RewriteRule<UdivOne>::applies(TNode node) { template<> inline Node RewriteRule<UdivOne>::apply(TNode node) { - BVDebug("bv-rewrite") << "RewriteRule<UdivOne>(" << node << ")" << std::endl; + Debug("bv-rewrite") << "RewriteRule<UdivOne>(" << node << ")" << std::endl; return node[0]; } @@ -796,7 +796,7 @@ bool RewriteRule<UdivSelf>::applies(TNode node) { template<> inline Node RewriteRule<UdivSelf>::apply(TNode node) { - BVDebug("bv-rewrite") << "RewriteRule<UdivSelf>(" << node << ")" << std::endl; + Debug("bv-rewrite") << "RewriteRule<UdivSelf>(" << node << ")" << std::endl; return utils::mkConst(utils::getSize(node), 1); } @@ -814,7 +814,7 @@ bool RewriteRule<UremPow2>::applies(TNode node) { template<> inline Node RewriteRule<UremPow2>::apply(TNode node) { - BVDebug("bv-rewrite") << "RewriteRule<UremPow2>(" << node << ")" << std::endl; + Debug("bv-rewrite") << "RewriteRule<UremPow2>(" << node << ")" << std::endl; TNode a = node[0]; unsigned power = utils::isPow2Const(node[1]) - 1; if (power == 0) { @@ -839,7 +839,7 @@ bool RewriteRule<UremOne>::applies(TNode node) { template<> inline Node RewriteRule<UremOne>::apply(TNode node) { - BVDebug("bv-rewrite") << "RewriteRule<UremOne>(" << node << ")" << std::endl; + Debug("bv-rewrite") << "RewriteRule<UremOne>(" << node << ")" << std::endl; return utils::mkConst(utils::getSize(node), 0); } @@ -857,7 +857,7 @@ bool RewriteRule<UremSelf>::applies(TNode node) { template<> inline Node RewriteRule<UremSelf>::apply(TNode node) { - BVDebug("bv-rewrite") << "RewriteRule<UremSelf>(" << node << ")" << std::endl; + Debug("bv-rewrite") << "RewriteRule<UremSelf>(" << node << ")" << std::endl; return utils::mkConst(utils::getSize(node), 0); } @@ -877,7 +877,7 @@ bool RewriteRule<ShiftZero>::applies(TNode node) { template<> inline Node RewriteRule<ShiftZero>::apply(TNode node) { - BVDebug("bv-rewrite") << "RewriteRule<ShiftZero>(" << node << ")" << std::endl; + Debug("bv-rewrite") << "RewriteRule<ShiftZero>(" << node << ")" << std::endl; return node[0]; } @@ -905,7 +905,7 @@ bool RewriteRule<BBPlusNeg>::applies(TNode node) { template<> inline Node RewriteRule<BBPlusNeg>::apply(TNode node) { - BVDebug("bv-rewrite") << "RewriteRule<BBPlusNeg>(" << node << ")" << std::endl; + Debug("bv-rewrite") << "RewriteRule<BBPlusNeg>(" << node << ")" << std::endl; std::vector<Node> children; unsigned neg_count = 0; @@ -944,7 +944,7 @@ Node RewriteRule<BBPlusNeg>::apply(TNode node) { // template<> inline // Node RewriteRule<BBFactorOut>::apply(TNode node) { -// BVDebug("bv-rewrite") << "RewriteRule<BBFactorOut>(" << node << ")" << std::endl; +// Debug("bv-rewrite") << "RewriteRule<BBFactorOut>(" << node << ")" << std::endl; // std::hash_set<TNode, TNodeHashFunction> factors; // for (unsigned i = 0; i < node.getNumChildren(); ++i) { @@ -980,7 +980,7 @@ Node RewriteRule<BBPlusNeg>::apply(TNode node) { // template<> inline // Node RewriteRule<>::apply(TNode node) { -// BVDebug("bv-rewrite") << "RewriteRule<>(" << node << ")" << std::endl; +// Debug("bv-rewrite") << "RewriteRule<>(" << node << ")" << std::endl; // return ; // } diff --git a/src/theory/bv/theory_bv_utils.h b/src/theory/bv/theory_bv_utils.h index f87163e37..e5a7bbb84 100644 --- a/src/theory/bv/theory_bv_utils.h +++ b/src/theory/bv/theory_bv_utils.h @@ -24,12 +24,6 @@ #include <sstream> #include "expr/node_manager.h" -#ifdef CVC4_DEBUG -#define BVDebug(x) Debug(x) -#else -#define BVDebug(x) if (false) Debug(x) -#endif - namespace CVC4 { diff --git a/src/theory/datatypes/theory_datatypes_type_rules.h b/src/theory/datatypes/theory_datatypes_type_rules.h index ade9ffc26..9b4f24566 100644 --- a/src/theory/datatypes/theory_datatypes_type_rules.h +++ b/src/theory/datatypes/theory_datatypes_type_rules.h @@ -285,7 +285,7 @@ struct TupleSelectTypeRule { const TupleSelect& ts = n.getOperator().getConst<TupleSelect>(); TypeNode tupleType = n[0].getType(check); if(!tupleType.isTuple()) { - if(!tupleType.hasAttribute(expr::DatatypeRecordAttr())) { + if(!tupleType.hasAttribute(expr::DatatypeTupleAttr())) { throw TypeCheckingExceptionPrivate(n, "Tuple-select expression formed over non-tuple"); } tupleType = tupleType.getAttribute(expr::DatatypeTupleAttr()); @@ -309,7 +309,7 @@ struct TupleUpdateTypeRule { TypeNode newValue = n[1].getType(check); if(check) { if(!tupleType.isTuple()) { - if(!tupleType.hasAttribute(expr::DatatypeRecordAttr())) { + if(!tupleType.hasAttribute(expr::DatatypeTupleAttr())) { throw TypeCheckingExceptionPrivate(n, "Tuple-update expression formed over non-tuple"); } tupleType = tupleType.getAttribute(expr::DatatypeTupleAttr()); diff --git a/src/theory/datatypes/type_enumerator.h b/src/theory/datatypes/type_enumerator.h index 2a14d7fba..2a74f6d15 100644 --- a/src/theory/datatypes/type_enumerator.h +++ b/src/theory/datatypes/type_enumerator.h @@ -92,23 +92,21 @@ public: newEnumerators(); } - DatatypesEnumerator(const DatatypesEnumerator& other) : - TypeEnumeratorBase<DatatypesEnumerator>(other.getType()), - d_datatype(other.d_datatype), - d_ctor(other.d_ctor), - d_zeroCtor(other.d_zeroCtor), + DatatypesEnumerator(const DatatypesEnumerator& de) throw() : + TypeEnumeratorBase<DatatypesEnumerator>(de.getType()), + d_datatype(de.d_datatype), + d_ctor(de.d_ctor), + d_zeroCtor(de.d_zeroCtor), d_argEnumerators(NULL) { - - if (other.d_argEnumerators != NULL) { - d_argEnumerators = new TypeEnumerator*[d_datatype[d_ctor].getNumArgs()]; + + if(de.d_argEnumerators != NULL) { + newEnumerators(); for(size_t a = 0; a < d_datatype[d_ctor].getNumArgs(); ++a) { - if (other.d_argEnumerators[a] != NULL) { - d_argEnumerators[a] = new TypeEnumerator(*other.d_argEnumerators[a]); - } else { - d_argEnumerators[a] = NULL; + if(de.d_argEnumerators[a] != NULL) { + d_argEnumerators[a] = new TypeEnumerator(*de.d_argEnumerators[a]); } - } - } + } + } } ~DatatypesEnumerator() throw() { @@ -139,11 +137,10 @@ public: DatatypesEnumerator& operator++() throw() { if(d_ctor < d_datatype.getNumConstructors()) { for(size_t a = d_datatype[d_ctor].getNumArgs(); a > 0; --a) { - try { - *++*d_argEnumerators[a - 1]; - return *this; - } catch(NoMoreValuesException&) { + if((++*d_argEnumerators[a - 1]).isFinished()) { *d_argEnumerators[a - 1] = TypeEnumerator(Node::fromExpr(d_datatype[d_ctor][a - 1].getSelector()).getType()[1]); + } else { + return *this; } } @@ -175,6 +172,14 @@ public: class TupleEnumerator : public TypeEnumeratorBase<TupleEnumerator> { TypeEnumerator** d_enumerators; + /** Allocate and initialize the delegate enumerators */ + void newEnumerators() { + d_enumerators = new TypeEnumerator*[getType().getNumChildren()]; + for(size_t i = 0; i < getType().getNumChildren(); ++i) { + d_enumerators[i] = NULL; + } + } + void deleteEnumerators() throw() { if(d_enumerators != NULL) { for(size_t i = 0; i < getType().getNumChildren(); ++i) { @@ -190,9 +195,20 @@ public: TupleEnumerator(TypeNode type) throw() : TypeEnumeratorBase<TupleEnumerator>(type) { Assert(type.isTuple()); - d_enumerators = new TypeEnumerator*[type.getNumChildren()]; - for(size_t i = 0; i < type.getNumChildren(); ++i) { - d_enumerators[i] = new TypeEnumerator(type[i]); + newEnumerators(); + } + + TupleEnumerator(const TupleEnumerator& te) throw() : + TypeEnumeratorBase<TupleEnumerator>(te.getType()), + d_enumerators(NULL) { + + if(te.d_enumerators != NULL) { + newEnumerators(); + for(size_t i = 0; i < getType().getNumChildren(); ++i) { + if(te.d_enumerators[i] != NULL) { + d_enumerators[i] = new TypeEnumerator(*te.d_enumerators[i]); + } + } } } @@ -241,9 +257,19 @@ public: class RecordEnumerator : public TypeEnumeratorBase<RecordEnumerator> { TypeEnumerator** d_enumerators; + /** Allocate and initialize the delegate enumerators */ + void newEnumerators() { + const Record& rec = getType().getConst<Record>(); + d_enumerators = new TypeEnumerator*[rec.getNumFields()]; + for(size_t i = 0; i < rec.getNumFields(); ++i) { + d_enumerators[i] = new TypeEnumerator(TypeNode::fromType(rec[i].second)); + } + } + void deleteEnumerators() throw() { if(d_enumerators != NULL) { - for(size_t i = 0; i < getType().getNumChildren(); ++i) { + const Record& rec = getType().getConst<Record>(); + for(size_t i = 0; i < rec.getNumFields(); ++i) { delete d_enumerators[i]; } delete [] d_enumerators; @@ -256,12 +282,20 @@ public: RecordEnumerator(TypeNode type) throw() : TypeEnumeratorBase<RecordEnumerator>(type) { Assert(type.isRecord()); - const Record& rec = getType().getConst<Record>(); - Debug("te") << "creating record enumerator for " << type << std::endl; - d_enumerators = new TypeEnumerator*[rec.getNumFields()]; - for(size_t i = 0; i < rec.getNumFields(); ++i) { - Debug("te") << " - sub-enumerator for " << rec[i].second << std::endl; - d_enumerators[i] = new TypeEnumerator(TypeNode::fromType(rec[i].second)); + newEnumerators(); + } + + RecordEnumerator(const RecordEnumerator& re) throw() : + TypeEnumeratorBase<RecordEnumerator>(re.getType()), + d_enumerators(NULL) { + + if(re.d_enumerators != NULL) { + newEnumerators(); + for(size_t i = 0; i < getType().getNumChildren(); ++i) { + if(re.d_enumerators[i] != NULL) { + d_enumerators[i] = new TypeEnumerator(*re.d_enumerators[i]); + } + } } } diff --git a/src/theory/mkrewriter b/src/theory/mkrewriter index 88ac5b9fb..2d8012bfb 100755 --- a/src/theory/mkrewriter +++ b/src/theory/mkrewriter @@ -2,7 +2,7 @@ # # mkrewriter # Morgan Deters <mdeters@cs.nyu.edu> for CVC4 -# Copyright (c) 2010-2012 The CVC4 Project +# Copyright (c) 2010-2013 The CVC4 Project # # The purpose of this script is to create rewriter_tables.h from a template # and a list of theory kinds. @@ -14,13 +14,14 @@ # Output is to standard out. # -copyright=2010-2012 +copyright=2010-2013 cat <<EOF /********************* */ /** rewriter_tables.h ** - ** Copyright $copyright The AcSys Group, New York University, and as below. + ** Copyright $copyright New York University and The University of Iowa, + ** and as below. ** ** This header file automatically generated by: ** diff --git a/src/theory/mktheorytraits b/src/theory/mktheorytraits index a44d8e9c3..3edc7c140 100755 --- a/src/theory/mktheorytraits +++ b/src/theory/mktheorytraits @@ -2,7 +2,7 @@ # # mktheorytraits # Morgan Deters <mdeters@cs.nyu.edu> for CVC4 -# Copyright (c) 2010-2012 The CVC4 Project +# Copyright (c) 2010-2013 The CVC4 Project # # The purpose of this script is to create theory_traits.h from a template # and a list of theory kinds. @@ -14,7 +14,7 @@ # Output is to standard out. # -copyright=2010-2012 +copyright=2010-2013 filename=`basename "$1" | sed 's,_template,,'` @@ -22,7 +22,8 @@ cat <<EOF /********************* */ /** $filename ** - ** Copyright $copyright The AcSys Group, New York University, and as below. + ** Copyright $copyright New York University and The University of Iowa, + ** and as below. ** ** This header file automatically generated by: ** diff --git a/src/theory/model.cpp b/src/theory/model.cpp index 713587be2..bbc51c9e0 100644 --- a/src/theory/model.cpp +++ b/src/theory/model.cpp @@ -395,6 +395,9 @@ bool TheoryEngineModelBuilder::isAssignable(TNode n) void TheoryEngineModelBuilder::checkTerms(TNode n, TheoryModel* tm, NodeSet& cache) { + if (n.getKind()==FORALL || n.getKind()==EXISTS) { + return; + } if (cache.find(n) != cache.end()) { return; } diff --git a/src/theory/model.h b/src/theory/model.h index e283ee183..98eeda97a 100644 --- a/src/theory/model.h +++ b/src/theory/model.h @@ -87,7 +87,7 @@ public: void addSubstitution(TNode x, TNode t, bool invalidateCache = true); /** add term function * addTerm( n ) will do any model-specific processing necessary for n, - * such as contraining the interpretation of uninterpretted functions, + * such as constraining the interpretation of uninterpreted functions, * and adding n to the equality engine of this model */ virtual void addTerm(TNode n); diff --git a/src/theory/quantifiers/inst_gen.cpp b/src/theory/quantifiers/inst_gen.cpp index d3bd6ad03..dea371e9c 100755..100644 --- a/src/theory/quantifiers/inst_gen.cpp +++ b/src/theory/quantifiers/inst_gen.cpp @@ -1,298 +1,296 @@ -/********************* */
-/*! \file inst_gen.cpp
- ** \verbatim
- ** Original author: ajreynol
- ** Major contributors: none
- ** Minor contributors (to current version): none
- ** This file is part of the CVC4 prototype.
- ** Copyright (c) 2009, 2010, 2011 The Analysis of Computer Systems Group (ACSys)
- ** Courant Institute of Mathematical Sciences
- ** New York University
- ** See the file COPYING in the top-level source directory for licensing
- ** information.\endverbatim
- **
- ** \brief Implementation of inst gen classes
- **/
-
-#include "theory/quantifiers/inst_gen.h"
-#include "theory/quantifiers/model_engine.h"
-#include "theory/quantifiers/model_builder.h"
-#include "theory/quantifiers/first_order_model.h"
-
-//#define CHILD_USE_CONSIDER
-
-using namespace std;
-using namespace CVC4;
-using namespace CVC4::kind;
-using namespace CVC4::context;
-using namespace CVC4::theory;
-using namespace CVC4::theory::quantifiers;
-
-
-
-InstGenProcess::InstGenProcess( Node n ) : d_node( n ){
- Assert( n.hasAttribute(InstConstantAttribute()) );
- int count = 0;
- for( size_t i=0; i<n.getNumChildren(); i++ ){
- if( n[i].getKind()!=INST_CONSTANT && n[i].hasAttribute(InstConstantAttribute()) ){
- d_children.push_back( InstGenProcess( n[i] ) );
- d_children_index.push_back( i );
- d_children_map[ i ] = count;
- count++;
- }
- }
-}
-
-void InstGenProcess::addMatchValue( QuantifiersEngine* qe, Node f, Node val, InstMatch& m ){
- if( !qe->existsInstantiation( f, m, true ) ){
- //make sure no duplicates are produced
- if( d_inst_trie[val].addInstMatch( qe, f, m, true ) ){
- d_match_values.push_back( val );
- d_matches.push_back( InstMatch( &m ) );
- qe->getModelEngine()->getModelBuilder()->d_instGenMatches++;
- }
- }
-}
-
-void InstGenProcess::calculateMatches( QuantifiersEngine* qe, Node f, std::vector< Node >& considerVal, bool useConsider ){
- Trace("inst-gen-cm") << "* Calculate matches " << d_node << std::endl;
- //whether we are doing a product or sum or matches
- bool doProduct = true;
- //get the model
- FirstOrderModel* fm = qe->getModel();
-
- //calculate terms we will consider
- std::vector< Node > considerTerms;
- std::vector< std::vector< Node > > newConsiderVal;
- std::vector< bool > newUseConsider;
- std::map< Node, InstMatch > considerTermsMatch[2];
- std::map< Node, bool > considerTermsSuccess[2];
- newConsiderVal.resize( d_children.size() );
- newUseConsider.resize( d_children.size(), useConsider );
- if( d_node.getKind()==APPLY_UF ){
- Node op = d_node.getOperator();
- if( useConsider ){
-#ifndef CHILD_USE_CONSIDER
- for( size_t i=0; i<newUseConsider.size(); i++ ){
- newUseConsider[i] = false;
- }
-#endif
- for( size_t i=0; i<considerVal.size(); i++ ){
- eq::EqClassIterator eqc( qe->getEqualityQuery()->getEngine()->getRepresentative( considerVal[i] ),
- qe->getEqualityQuery()->getEngine() );
- while( !eqc.isFinished() ){
- Node en = (*eqc);
- if( en.getKind()==APPLY_UF && en.getOperator()==op ){
- considerTerms.push_back( en );
- }
- ++eqc;
- }
- }
- }else{
- considerTerms.insert( considerTerms.begin(), fm->d_uf_terms[op].begin(), fm->d_uf_terms[op].end() );
- }
- //for each term we consider, calculate a current match
- for( size_t i=0; i<considerTerms.size(); i++ ){
- Node n = considerTerms[i];
- bool isSelected = qe->getModelEngine()->getModelBuilder()->isTermSelected( n );
- bool hadSuccess CVC4_UNUSED = false;
- for( int t=(isSelected ? 0 : 1); t<2; t++ ){
- if( t==0 || !n.getAttribute(NoMatchAttribute()) ){
- considerTermsMatch[t][n] = InstMatch();
- considerTermsSuccess[t][n] = true;
- for( size_t j=0; j<d_node.getNumChildren(); j++ ){
- if( d_children_map.find( j )==d_children_map.end() ){
- if( t!=0 || !n[j].getAttribute(ModelBasisAttribute()) ){
- if( d_node[j].getKind()==INST_CONSTANT ){
- if( !considerTermsMatch[t][n].setMatch( qe->getEqualityQuery(), d_node[j], n[j] ) ){
- Trace("inst-gen-cm") << "fail match: " << n[j] << " is not equal to ";
- Trace("inst-gen-cm") << considerTermsMatch[t][n].getValue( d_node[j] ) << std::endl;
- considerTermsSuccess[t][n] = false;
- break;
- }
- }else if( !qe->getEqualityQuery()->areEqual( d_node[j], n[j] ) ){
- Trace("inst-gen-cm") << "fail arg: " << n[j] << " is not equal to " << d_node[j] << std::endl;
- considerTermsSuccess[t][n] = false;
- break;
- }
- }
- }
- }
- //if successful, store it
- if( considerTermsSuccess[t][n] ){
-#ifdef CHILD_USE_CONSIDER
- if( !hadSuccess ){
- hadSuccess = true;
- for( size_t k=0; k<d_children.size(); k++ ){
- if( newUseConsider[k] ){
- int childIndex = d_children_index[k];
- //determine if we are restricted or not
- if( t!=0 || !n[childIndex].getAttribute(ModelBasisAttribute()) ){
- Node r = qe->getModel()->getRepresentative( n[childIndex] );
- if( std::find( newConsiderVal[k].begin(), newConsiderVal[k].end(), r )==newConsiderVal[k].end() ){
- newConsiderVal[k].push_back( r );
- //check if we now need to consider the entire domain
- TypeNode tn = r.getType();
- if( qe->getModel()->d_rep_set.hasType( tn ) ){
- if( (int)newConsiderVal[k].size()>=qe->getModel()->d_rep_set.getNumRepresentatives( tn ) ){
- newConsiderVal[k].clear();
- newUseConsider[k] = false;
- }
- }
- }
- }else{
- //matching against selected term, will need to consider all values
- newConsiderVal[k].clear();
- newUseConsider[k] = false;
- }
- }
- }
- }
-#endif
- }
- }
- }
- }
- }else{
- //the interpretted case
- if( d_node.getType().isBoolean() ){
- if( useConsider ){
- //if( considerVal.size()!=1 ) { std::cout << "consider val = " << considerVal.size() << std::endl; }
- Assert( considerVal.size()==1 );
- bool reqPol = considerVal[0]==fm->d_true;
- Node ncv = considerVal[0];
- if( d_node.getKind()==NOT ){
- ncv = reqPol ? fm->d_false : fm->d_true;
- }
- if( d_node.getKind()==NOT || d_node.getKind()==AND || d_node.getKind()==OR ){
- for( size_t i=0; i<newConsiderVal.size(); i++ ){
- newConsiderVal[i].push_back( ncv );
- }
- //instead we will do a sum
- if( ( d_node.getKind()==AND && !reqPol ) || ( d_node.getKind()==OR && reqPol ) ){
- doProduct = false;
- }
- }else{
- //do not use consider
- for( size_t i=0; i<newUseConsider.size(); i++ ){
- newUseConsider[i] = false;
- }
- }
- }
- }
- }
-
- //calculate all matches for children
- for( int i=0; i<(int)d_children.size(); i++ ){
- d_children[i].calculateMatches( qe, f, newConsiderVal[i], newUseConsider[i] );
- if( doProduct && d_children[i].getNumMatches()==0 ){
- return;
- }
- }
- if( d_node.getKind()==APPLY_UF ){
- //if this is an uninterpreted function
- Node op = d_node.getOperator();
- //process all values
- for( size_t i=0; i<considerTerms.size(); i++ ){
- Node n = considerTerms[i];
- bool isSelected = qe->getModelEngine()->getModelBuilder()->isTermSelected( n );
- for( int t=(isSelected ? 0 : 1); t<2; t++ ){
- //do not consider ground case if it is already congruent to another ground term
- if( t==0 || !n.getAttribute(NoMatchAttribute()) ){
- Trace("inst-gen-cm") << "calculate for " << n << ", selected = " << (t==0) << std::endl;
- if( considerTermsSuccess[t][n] ){
- //try to find unifier for d_node = n
- calculateMatchesUninterpreted( qe, f, considerTermsMatch[t][n], n, 0, t==0 );
- }
- }
- }
- }
- }else{
- //if this is an interpreted function
- if( doProduct ){
- //combining children matches
- InstMatch curr;
- std::vector< Node > terms;
- calculateMatchesInterpreted( qe, f, curr, terms, 0 );
- }else{
- //summing children matches
- Assert( considerVal.size()==1 );
- for( int i=0; i<(int)d_children.size(); i++ ){
- for( int j=0; j<(int)d_children[ i ].getNumMatches(); j++ ){
- InstMatch m;
- if( d_children[ i ].getMatch( qe->getEqualityQuery(), j, m ) ){
- addMatchValue( qe, f, considerVal[0], m );
- }
- }
- }
- }
- }
- Trace("inst-gen-cm") << "done calculate matches" << std::endl;
- //can clear information used for finding duplicates
- d_inst_trie.clear();
-}
-
-bool InstGenProcess::getMatch( EqualityQuery* q, int i, InstMatch& m ){
- //FIXME: is this correct? (query may not be accurate)
- return m.merge( q, d_matches[i] );
-}
-
-void InstGenProcess::calculateMatchesUninterpreted( QuantifiersEngine* qe, Node f, InstMatch& curr, Node n, int childIndex, bool isSelected ){
- if( childIndex==(int)d_children.size() ){
- Node val = qe->getModel()->getRepresentative( n ); //FIXME: is this correct?
- Trace("inst-gen-cm") << " - u-match : " << val << std::endl;
- Trace("inst-gen-cm") << " : " << curr << std::endl;
- addMatchValue( qe, f, val, curr );
- }else{
- Trace("inst-gen-cm") << "Consider child index = " << childIndex << ", against ground term argument " << d_children_index[childIndex] << " ... " << n[d_children_index[childIndex]] << std::endl;
- bool sel = ( isSelected && n[d_children_index[childIndex]].getAttribute(ModelBasisAttribute()) );
- for( int i=0; i<(int)d_children[ childIndex ].getNumMatches(); i++ ){
- //FIXME: is this correct?
- if( sel || qe->getEqualityQuery()->areEqual( d_children[ childIndex ].getMatchValue( i ), n[d_children_index[childIndex]] ) ){
- InstMatch next( &curr );
- if( d_children[ childIndex ].getMatch( qe->getEqualityQuery(), i, next ) ){
- calculateMatchesUninterpreted( qe, f, next, n, childIndex+1, isSelected );
- }else{
- Trace("inst-gen-cm") << curr << " not equal to " << d_children[ childIndex ].d_matches[i] << std::endl;
- Trace("inst-gen-cm") << childIndex << " match " << i << " not equal subs." << std::endl;
- }
- }else{
- Trace("inst-gen-cm") << childIndex << " match " << i << " not equal value." << std::endl;
- }
- }
- }
-}
-
-void InstGenProcess::calculateMatchesInterpreted( QuantifiersEngine* qe, Node f, InstMatch& curr, std::vector< Node >& terms, int argIndex ){
- FirstOrderModel* fm = qe->getModel();
- if( argIndex==(int)d_node.getNumChildren() ){
- Node val;
- if( d_node.getNumChildren()==0 ){
- val = d_node;
- }else if( d_node.getKind()==EQUAL ){
- val = qe->getEqualityQuery()->areEqual( terms[0], terms[1] ) ? fm->d_true : fm->d_false;
- }else{
- val = NodeManager::currentNM()->mkNode( d_node.getKind(), terms );
- val = Rewriter::rewrite( val );
- }
- Trace("inst-gen-cm") << " - i-match : " << d_node << std::endl;
- Trace("inst-gen-cm") << " : " << val << std::endl;
- Trace("inst-gen-cm") << " : " << curr << std::endl;
- addMatchValue( qe, f, val, curr );
- }else{
- if( d_children_map.find( argIndex )==d_children_map.end() ){
- terms.push_back( fm->getRepresentative( d_node[argIndex] ) );
- calculateMatchesInterpreted( qe, f, curr, terms, argIndex+1 );
- terms.pop_back();
- }else{
- for( int i=0; i<(int)d_children[ d_children_map[argIndex] ].getNumMatches(); i++ ){
- InstMatch next( &curr );
- if( d_children[ d_children_map[argIndex] ].getMatch( qe->getEqualityQuery(), i, next ) ){
- terms.push_back( d_children[ d_children_map[argIndex] ].getMatchValue( i ) );
- calculateMatchesInterpreted( qe, f, next, terms, argIndex+1 );
- terms.pop_back();
- }
- }
- }
- }
-}
+/********************* */ +/*! \file inst_gen.cpp + ** \verbatim + ** Original author: Andrew Reynolds <andrew.j.reynolds@gmail.com> + ** Major contributors: Morgan Deters <mdeters@cs.nyu.edu> + ** Minor contributors (to current version): none + ** This file is part of the CVC4 project. + ** Copyright (c) 2009-2013 New York University and The University of Iowa + ** See the file COPYING in the top-level source directory for licensing + ** information.\endverbatim + ** + ** \brief Implementation of inst gen classes + **/ + +#include "theory/quantifiers/inst_gen.h" +#include "theory/quantifiers/model_engine.h" +#include "theory/quantifiers/model_builder.h" +#include "theory/quantifiers/first_order_model.h" + +//#define CHILD_USE_CONSIDER + +using namespace std; +using namespace CVC4; +using namespace CVC4::kind; +using namespace CVC4::context; +using namespace CVC4::theory; +using namespace CVC4::theory::quantifiers; + + + +InstGenProcess::InstGenProcess( Node n ) : d_node( n ){ + Assert( n.hasAttribute(InstConstantAttribute()) ); + int count = 0; + for( size_t i=0; i<n.getNumChildren(); i++ ){ + if( n[i].getKind()!=INST_CONSTANT && n[i].hasAttribute(InstConstantAttribute()) ){ + d_children.push_back( InstGenProcess( n[i] ) ); + d_children_index.push_back( i ); + d_children_map[ i ] = count; + count++; + } + } +} + +void InstGenProcess::addMatchValue( QuantifiersEngine* qe, Node f, Node val, InstMatch& m ){ + if( !qe->existsInstantiation( f, m, true ) ){ + //make sure no duplicates are produced + if( d_inst_trie[val].addInstMatch( qe, f, m, true ) ){ + d_match_values.push_back( val ); + d_matches.push_back( InstMatch( &m ) ); + qe->getModelEngine()->getModelBuilder()->d_instGenMatches++; + } + } +} + +void InstGenProcess::calculateMatches( QuantifiersEngine* qe, Node f, std::vector< Node >& considerVal, bool useConsider ){ + Trace("inst-gen-cm") << "* Calculate matches " << d_node << std::endl; + //whether we are doing a product or sum or matches + bool doProduct = true; + //get the model + FirstOrderModel* fm = qe->getModel(); + + //calculate terms we will consider + std::vector< Node > considerTerms; + std::vector< std::vector< Node > > newConsiderVal; + std::vector< bool > newUseConsider; + std::map< Node, InstMatch > considerTermsMatch[2]; + std::map< Node, bool > considerTermsSuccess[2]; + newConsiderVal.resize( d_children.size() ); + newUseConsider.resize( d_children.size(), useConsider ); + if( d_node.getKind()==APPLY_UF ){ + Node op = d_node.getOperator(); + if( useConsider ){ +#ifndef CHILD_USE_CONSIDER + for( size_t i=0; i<newUseConsider.size(); i++ ){ + newUseConsider[i] = false; + } +#endif + for( size_t i=0; i<considerVal.size(); i++ ){ + eq::EqClassIterator eqc( qe->getEqualityQuery()->getEngine()->getRepresentative( considerVal[i] ), + qe->getEqualityQuery()->getEngine() ); + while( !eqc.isFinished() ){ + Node en = (*eqc); + if( en.getKind()==APPLY_UF && en.getOperator()==op ){ + considerTerms.push_back( en ); + } + ++eqc; + } + } + }else{ + considerTerms.insert( considerTerms.begin(), fm->d_uf_terms[op].begin(), fm->d_uf_terms[op].end() ); + } + //for each term we consider, calculate a current match + for( size_t i=0; i<considerTerms.size(); i++ ){ + Node n = considerTerms[i]; + bool isSelected = qe->getModelEngine()->getModelBuilder()->isTermSelected( n ); + bool hadSuccess CVC4_UNUSED = false; + for( int t=(isSelected ? 0 : 1); t<2; t++ ){ + if( t==0 || !n.getAttribute(NoMatchAttribute()) ){ + considerTermsMatch[t][n] = InstMatch(); + considerTermsSuccess[t][n] = true; + for( size_t j=0; j<d_node.getNumChildren(); j++ ){ + if( d_children_map.find( j )==d_children_map.end() ){ + if( t!=0 || !n[j].getAttribute(ModelBasisAttribute()) ){ + if( d_node[j].getKind()==INST_CONSTANT ){ + if( !considerTermsMatch[t][n].setMatch( qe->getEqualityQuery(), d_node[j], n[j] ) ){ + Trace("inst-gen-cm") << "fail match: " << n[j] << " is not equal to "; + Trace("inst-gen-cm") << considerTermsMatch[t][n].getValue( d_node[j] ) << std::endl; + considerTermsSuccess[t][n] = false; + break; + } + }else if( !qe->getEqualityQuery()->areEqual( d_node[j], n[j] ) ){ + Trace("inst-gen-cm") << "fail arg: " << n[j] << " is not equal to " << d_node[j] << std::endl; + considerTermsSuccess[t][n] = false; + break; + } + } + } + } + //if successful, store it + if( considerTermsSuccess[t][n] ){ +#ifdef CHILD_USE_CONSIDER + if( !hadSuccess ){ + hadSuccess = true; + for( size_t k=0; k<d_children.size(); k++ ){ + if( newUseConsider[k] ){ + int childIndex = d_children_index[k]; + //determine if we are restricted or not + if( t!=0 || !n[childIndex].getAttribute(ModelBasisAttribute()) ){ + Node r = qe->getModel()->getRepresentative( n[childIndex] ); + if( std::find( newConsiderVal[k].begin(), newConsiderVal[k].end(), r )==newConsiderVal[k].end() ){ + newConsiderVal[k].push_back( r ); + //check if we now need to consider the entire domain + TypeNode tn = r.getType(); + if( qe->getModel()->d_rep_set.hasType( tn ) ){ + if( (int)newConsiderVal[k].size()>=qe->getModel()->d_rep_set.getNumRepresentatives( tn ) ){ + newConsiderVal[k].clear(); + newUseConsider[k] = false; + } + } + } + }else{ + //matching against selected term, will need to consider all values + newConsiderVal[k].clear(); + newUseConsider[k] = false; + } + } + } + } +#endif + } + } + } + } + }else{ + //the interpretted case + if( d_node.getType().isBoolean() ){ + if( useConsider ){ + //if( considerVal.size()!=1 ) { std::cout << "consider val = " << considerVal.size() << std::endl; } + Assert( considerVal.size()==1 ); + bool reqPol = considerVal[0]==fm->d_true; + Node ncv = considerVal[0]; + if( d_node.getKind()==NOT ){ + ncv = reqPol ? fm->d_false : fm->d_true; + } + if( d_node.getKind()==NOT || d_node.getKind()==AND || d_node.getKind()==OR ){ + for( size_t i=0; i<newConsiderVal.size(); i++ ){ + newConsiderVal[i].push_back( ncv ); + } + //instead we will do a sum + if( ( d_node.getKind()==AND && !reqPol ) || ( d_node.getKind()==OR && reqPol ) ){ + doProduct = false; + } + }else{ + //do not use consider + for( size_t i=0; i<newUseConsider.size(); i++ ){ + newUseConsider[i] = false; + } + } + } + } + } + + //calculate all matches for children + for( int i=0; i<(int)d_children.size(); i++ ){ + d_children[i].calculateMatches( qe, f, newConsiderVal[i], newUseConsider[i] ); + if( doProduct && d_children[i].getNumMatches()==0 ){ + return; + } + } + if( d_node.getKind()==APPLY_UF ){ + //if this is an uninterpreted function + Node op = d_node.getOperator(); + //process all values + for( size_t i=0; i<considerTerms.size(); i++ ){ + Node n = considerTerms[i]; + bool isSelected = qe->getModelEngine()->getModelBuilder()->isTermSelected( n ); + for( int t=(isSelected ? 0 : 1); t<2; t++ ){ + //do not consider ground case if it is already congruent to another ground term + if( t==0 || !n.getAttribute(NoMatchAttribute()) ){ + Trace("inst-gen-cm") << "calculate for " << n << ", selected = " << (t==0) << std::endl; + if( considerTermsSuccess[t][n] ){ + //try to find unifier for d_node = n + calculateMatchesUninterpreted( qe, f, considerTermsMatch[t][n], n, 0, t==0 ); + } + } + } + } + }else{ + //if this is an interpreted function + if( doProduct ){ + //combining children matches + InstMatch curr; + std::vector< Node > terms; + calculateMatchesInterpreted( qe, f, curr, terms, 0 ); + }else{ + //summing children matches + Assert( considerVal.size()==1 ); + for( int i=0; i<(int)d_children.size(); i++ ){ + for( int j=0; j<(int)d_children[ i ].getNumMatches(); j++ ){ + InstMatch m; + if( d_children[ i ].getMatch( qe->getEqualityQuery(), j, m ) ){ + addMatchValue( qe, f, considerVal[0], m ); + } + } + } + } + } + Trace("inst-gen-cm") << "done calculate matches" << std::endl; + //can clear information used for finding duplicates + d_inst_trie.clear(); +} + +bool InstGenProcess::getMatch( EqualityQuery* q, int i, InstMatch& m ){ + //FIXME: is this correct? (query may not be accurate) + return m.merge( q, d_matches[i] ); +} + +void InstGenProcess::calculateMatchesUninterpreted( QuantifiersEngine* qe, Node f, InstMatch& curr, Node n, int childIndex, bool isSelected ){ + if( childIndex==(int)d_children.size() ){ + Node val = qe->getModel()->getRepresentative( n ); //FIXME: is this correct? + Trace("inst-gen-cm") << " - u-match : " << val << std::endl; + Trace("inst-gen-cm") << " : " << curr << std::endl; + addMatchValue( qe, f, val, curr ); + }else{ + Trace("inst-gen-cm") << "Consider child index = " << childIndex << ", against ground term argument " << d_children_index[childIndex] << " ... " << n[d_children_index[childIndex]] << std::endl; + bool sel = ( isSelected && n[d_children_index[childIndex]].getAttribute(ModelBasisAttribute()) ); + for( int i=0; i<(int)d_children[ childIndex ].getNumMatches(); i++ ){ + //FIXME: is this correct? + if( sel || qe->getEqualityQuery()->areEqual( d_children[ childIndex ].getMatchValue( i ), n[d_children_index[childIndex]] ) ){ + InstMatch next( &curr ); + if( d_children[ childIndex ].getMatch( qe->getEqualityQuery(), i, next ) ){ + calculateMatchesUninterpreted( qe, f, next, n, childIndex+1, isSelected ); + }else{ + Trace("inst-gen-cm") << curr << " not equal to " << d_children[ childIndex ].d_matches[i] << std::endl; + Trace("inst-gen-cm") << childIndex << " match " << i << " not equal subs." << std::endl; + } + }else{ + Trace("inst-gen-cm") << childIndex << " match " << i << " not equal value." << std::endl; + } + } + } +} + +void InstGenProcess::calculateMatchesInterpreted( QuantifiersEngine* qe, Node f, InstMatch& curr, std::vector< Node >& terms, int argIndex ){ + FirstOrderModel* fm = qe->getModel(); + if( argIndex==(int)d_node.getNumChildren() ){ + Node val; + if( d_node.getNumChildren()==0 ){ + val = d_node; + }else if( d_node.getKind()==EQUAL ){ + val = qe->getEqualityQuery()->areEqual( terms[0], terms[1] ) ? fm->d_true : fm->d_false; + }else{ + val = NodeManager::currentNM()->mkNode( d_node.getKind(), terms ); + val = Rewriter::rewrite( val ); + } + Trace("inst-gen-cm") << " - i-match : " << d_node << std::endl; + Trace("inst-gen-cm") << " : " << val << std::endl; + Trace("inst-gen-cm") << " : " << curr << std::endl; + addMatchValue( qe, f, val, curr ); + }else{ + if( d_children_map.find( argIndex )==d_children_map.end() ){ + terms.push_back( fm->getRepresentative( d_node[argIndex] ) ); + calculateMatchesInterpreted( qe, f, curr, terms, argIndex+1 ); + terms.pop_back(); + }else{ + for( int i=0; i<(int)d_children[ d_children_map[argIndex] ].getNumMatches(); i++ ){ + InstMatch next( &curr ); + if( d_children[ d_children_map[argIndex] ].getMatch( qe->getEqualityQuery(), i, next ) ){ + terms.push_back( d_children[ d_children_map[argIndex] ].getMatchValue( i ) ); + calculateMatchesInterpreted( qe, f, next, terms, argIndex+1 ); + terms.pop_back(); + } + } + } + } +} diff --git a/src/theory/quantifiers/inst_gen.h b/src/theory/quantifiers/inst_gen.h index f6e6a372e..930133954 100755..100644 --- a/src/theory/quantifiers/inst_gen.h +++ b/src/theory/quantifiers/inst_gen.h @@ -1,61 +1,59 @@ -/********************* */
-/*! \file inst_gen.h
- ** \verbatim
- ** Original author: ajreynol
- ** Major contributors: none
- ** Minor contributors (to current version): none
- ** This file is part of the CVC4 prototype.
- ** Copyright (c) 2009-2012 The Analysis of Computer Systems Group (ACSys)
- ** Courant Institute of Mathematical Sciences
- ** New York University
- ** See the file COPYING in the top-level source directory for licensing
- ** information.\endverbatim
- **
- ** \brief Inst Gen classes
- **/
-
-#include "cvc4_private.h"
-
-#ifndef __CVC4__THEORY__QUANTIFIERS__INST_GEN_H
-#define __CVC4__THEORY__QUANTIFIERS__INST_GEN_H
-
-#include "theory/quantifiers_engine.h"
-#include "theory/quantifiers/inst_match.h"
-
-namespace CVC4 {
-namespace theory {
-namespace quantifiers {
-
-class InstGenProcess
-{
-private:
- //the node we are processing
- Node d_node;
- //the sub children for this node
- std::vector< InstGenProcess > d_children;
- std::vector< int > d_children_index;
- std::map< int, int > d_children_map;
- //the matches we have produced
- std::vector< InstMatch > d_matches;
- std::vector< Node > d_match_values;
- //add match value
- std::map< Node, inst::InstMatchTrie > d_inst_trie;
- void addMatchValue( QuantifiersEngine* qe, Node f, Node val, InstMatch& m );
-private:
- void calculateMatchesUninterpreted( QuantifiersEngine* qe, Node f, InstMatch& curr, Node n, int childIndex, bool isSelected );
- void calculateMatchesInterpreted( QuantifiersEngine* qe, Node f, InstMatch& curr, std::vector< Node >& terms, int argIndex );
-public:
- InstGenProcess( Node n );
- virtual ~InstGenProcess(){}
-
- void calculateMatches( QuantifiersEngine* qe, Node f, std::vector< Node >& considerVal, bool useConsider );
- int getNumMatches() { return d_matches.size(); }
- bool getMatch( EqualityQuery* q, int i, InstMatch& m );
- Node getMatchValue( int i ) { return d_match_values[i]; }
-};
-
-}
-}
-}
-
-#endif
+/********************* */ +/*! \file inst_gen.h + ** \verbatim + ** Original author: Andrew Reynolds <andrew.j.reynolds@gmail.com> + ** Major contributors: Morgan Deters <mdeters@cs.nyu.edu> + ** Minor contributors (to current version): none + ** This file is part of the CVC4 project. + ** Copyright (c) 2009-2013 New York University and The University of Iowa + ** See the file COPYING in the top-level source directory for licensing + ** information.\endverbatim + ** + ** \brief Inst Gen classes + **/ + +#include "cvc4_private.h" + +#ifndef __CVC4__THEORY__QUANTIFIERS__INST_GEN_H +#define __CVC4__THEORY__QUANTIFIERS__INST_GEN_H + +#include "theory/quantifiers_engine.h" +#include "theory/quantifiers/inst_match.h" + +namespace CVC4 { +namespace theory { +namespace quantifiers { + +class InstGenProcess +{ +private: + //the node we are processing + Node d_node; + //the sub children for this node + std::vector< InstGenProcess > d_children; + std::vector< int > d_children_index; + std::map< int, int > d_children_map; + //the matches we have produced + std::vector< InstMatch > d_matches; + std::vector< Node > d_match_values; + //add match value + std::map< Node, inst::InstMatchTrie > d_inst_trie; + void addMatchValue( QuantifiersEngine* qe, Node f, Node val, InstMatch& m ); +private: + void calculateMatchesUninterpreted( QuantifiersEngine* qe, Node f, InstMatch& curr, Node n, int childIndex, bool isSelected ); + void calculateMatchesInterpreted( QuantifiersEngine* qe, Node f, InstMatch& curr, std::vector< Node >& terms, int argIndex ); +public: + InstGenProcess( Node n ); + virtual ~InstGenProcess(){} + + void calculateMatches( QuantifiersEngine* qe, Node f, std::vector< Node >& considerVal, bool useConsider ); + int getNumMatches() { return d_matches.size(); } + bool getMatch( EqualityQuery* q, int i, InstMatch& m ); + Node getMatchValue( int i ) { return d_match_values[i]; } +};/* class InstGenProcess */ + +}/* CVC4::theory::quantifiers namespace */ +}/* CVC4::theory namespace */ +}/* CVC4 namespace */ + +#endif /* __CVC4__THEORY__QUANTIFIERS__INST_GEN_H */ diff --git a/src/theory/quantifiers/inst_match.cpp b/src/theory/quantifiers/inst_match.cpp index dcd7a1b79..85a96f90a 100644 --- a/src/theory/quantifiers/inst_match.cpp +++ b/src/theory/quantifiers/inst_match.cpp @@ -103,12 +103,12 @@ void InstMatch::makeComplete( Node f, QuantifiersEngine* qe ){ } } -void InstMatch::makeInternalRepresentative( QuantifiersEngine* qe ){ - EqualityQueryQuantifiersEngine* eqqe = (EqualityQueryQuantifiersEngine*)qe->getEqualityQuery(); - for( std::map< Node, Node >::iterator it = d_map.begin(); it != d_map.end(); ++it ){ - d_map[ it->first ] = eqqe->getInternalRepresentative( it->second ); - } -} +//void InstMatch::makeInternalRepresentative( QuantifiersEngine* qe ){ +// EqualityQueryQuantifiersEngine* eqqe = (EqualityQueryQuantifiersEngine*)qe->getEqualityQuery(); +// for( std::map< Node, Node >::iterator it = d_map.begin(); it != d_map.end(); ++it ){ +// d_map[ it->first ] = eqqe->getInternalRepresentative( it->second ); +// } +//} void InstMatch::makeRepresentative( QuantifiersEngine* qe ){ for( std::map< Node, Node >::iterator it = d_map.begin(); it != d_map.end(); ++it ){ diff --git a/src/theory/quantifiers/inst_match.h b/src/theory/quantifiers/inst_match.h index 8b2d9726b..b9e61be20 100644 --- a/src/theory/quantifiers/inst_match.h +++ b/src/theory/quantifiers/inst_match.h @@ -58,7 +58,7 @@ public: /** make complete */ void makeComplete( Node f, QuantifiersEngine* qe ); /** make internal representative */ - void makeInternalRepresentative( QuantifiersEngine* qe ); + //void makeInternalRepresentative( QuantifiersEngine* qe ); /** make representative */ void makeRepresentative( QuantifiersEngine* qe ); /** get value */ diff --git a/src/theory/quantifiers/inst_match_generator.cpp b/src/theory/quantifiers/inst_match_generator.cpp index 3b5e594fb..5484e25e9 100755..100644 --- a/src/theory/quantifiers/inst_match_generator.cpp +++ b/src/theory/quantifiers/inst_match_generator.cpp @@ -1,664 +1,658 @@ -/********************* */
-/*! \file inst_match_generator.cpp
-** \verbatim
-** Original author: ajreynol
-** Major contributors: bobot
-** Minor contributors (to current version): barrett, mdeters
-** This file is part of the CVC4 prototype.
-** Copyright (c) 2009-2012 New York University and The University of Iowa
-** See the file COPYING in the top-level source directory for licensing
-** information.\endverbatim
-**
-** \brief Implementation of inst match generator class
-**/
-
-#include "theory/quantifiers/inst_match_generator.h"
-#include "theory/quantifiers/trigger.h"
-#include "theory/quantifiers/term_database.h"
-#include "theory/quantifiers/candidate_generator.h"
-#include "theory/quantifiers_engine.h"
-
-using namespace std;
-using namespace CVC4;
-using namespace CVC4::kind;
-using namespace CVC4::context;
-using namespace CVC4::theory;
-
-namespace CVC4 {
-namespace theory {
-namespace inst {
-
-
-InstMatchGenerator::InstMatchGenerator( Node pat, QuantifiersEngine* qe, int matchPolicy ) : d_matchPolicy( matchPolicy ){
- initializePattern( pat, qe );
-}
-
-InstMatchGenerator::InstMatchGenerator( std::vector< Node >& pats, QuantifiersEngine* qe, int matchPolicy ) : d_matchPolicy( matchPolicy ){
- if( pats.size()==1 ){
- initializePattern( pats[0], qe );
- }else{
- initializePatterns( pats, qe );
- }
-}
-
-void InstMatchGenerator::initializePatterns( std::vector< Node >& pats, QuantifiersEngine* qe ){
- int childMatchPolicy = d_matchPolicy==MATCH_GEN_EFFICIENT_E_MATCH ? 0 : d_matchPolicy;
- for( int i=0; i<(int)pats.size(); i++ ){
- d_children.push_back( new InstMatchGenerator( pats[i], qe, childMatchPolicy ) );
- }
- d_pattern = Node::null();
- d_match_pattern = Node::null();
- d_cg = NULL;
-}
-
-void InstMatchGenerator::initializePattern( Node pat, QuantifiersEngine* qe ){
- Debug("inst-match-gen") << "Pattern term is " << pat << std::endl;
- Assert( pat.hasAttribute(InstConstantAttribute()) );
- d_pattern = pat;
- d_match_pattern = pat;
- if( d_match_pattern.getKind()==NOT ){
- //we want to add the children of the NOT
- d_match_pattern = d_pattern[0];
- }
- if( d_match_pattern.getKind()==IFF || d_match_pattern.getKind()==EQUAL ){
- if( !d_match_pattern[0].hasAttribute(InstConstantAttribute()) ){
- Assert( d_match_pattern[1].hasAttribute(InstConstantAttribute()) );
- //swap sides
- d_pattern = NodeManager::currentNM()->mkNode( d_match_pattern.getKind(), d_match_pattern[1], d_match_pattern[0] );
- d_pattern = pat.getKind()==NOT ? d_pattern.notNode() : d_pattern;
- if( pat.getKind()!=NOT ){ //TEMPORARY until we do better implementation of disequality matching
- d_match_pattern = d_match_pattern[1];
- }else{
- d_match_pattern = d_pattern[0][0];
- }
- }else if( !d_match_pattern[1].hasAttribute(InstConstantAttribute()) ){
- Assert( d_match_pattern[0].hasAttribute(InstConstantAttribute()) );
- if( pat.getKind()!=NOT ){ //TEMPORARY until we do better implementation of disequality matching
- d_match_pattern = d_match_pattern[0];
- }
- }
- }
- int childMatchPolicy = MATCH_GEN_DEFAULT;
- for( int i=0; i<(int)d_match_pattern.getNumChildren(); i++ ){
- if( d_match_pattern[i].hasAttribute(InstConstantAttribute()) ){
- if( d_match_pattern[i].getKind()!=INST_CONSTANT ){
- d_children.push_back( new InstMatchGenerator( d_match_pattern[i], qe, childMatchPolicy ) );
- d_children_index.push_back( i );
- }
- }
- }
-
- Debug("inst-match-gen") << "Pattern is " << d_pattern << ", match pattern is " << d_match_pattern << std::endl;
-
- //create candidate generator
- if( d_match_pattern.getKind()==EQUAL || d_match_pattern.getKind()==IFF ){
- Assert( d_matchPolicy==MATCH_GEN_DEFAULT );
- //we will be producing candidates via literal matching heuristics
- if( d_pattern.getKind()!=NOT ){
- //candidates will be all equalities
- d_cg = new inst::CandidateGeneratorQELitEq( qe, d_match_pattern );
- }else{
- //candidates will be all disequalities
- d_cg = new inst::CandidateGeneratorQELitDeq( qe, d_match_pattern );
- }
- }else if( d_pattern.getKind()==EQUAL || d_pattern.getKind()==IFF || d_pattern.getKind()==NOT ){
- Assert( d_matchPolicy==MATCH_GEN_DEFAULT );
- if( d_pattern.getKind()==NOT ){
- Unimplemented("Disequal generator unimplemented");
- }else{
- Assert( Trigger::isAtomicTrigger( d_match_pattern ) );
- //we are matching only in a particular equivalence class
- d_cg = new inst::CandidateGeneratorQE( qe, d_match_pattern.getOperator() );
- //store the equivalence class that we will call d_cg->reset( ... ) on
- d_eq_class = d_pattern[1];
- }
- }else if( Trigger::isAtomicTrigger( d_match_pattern ) ){
- //if( d_matchPolicy==MATCH_GEN_EFFICIENT_E_MATCH ){
- //Warning() << "Currently efficient e matching is not taken into account for quantifiers: " << d_pattern << std::endl;
- //}
- //we will be scanning lists trying to find d_match_pattern.getOperator()
- d_cg = new inst::CandidateGeneratorQE( qe, d_match_pattern.getOperator() );
- }else{
- d_cg = new CandidateGeneratorQueue;
- if( !Trigger::getPatternArithmetic( d_match_pattern.getAttribute(InstConstantAttribute()), d_match_pattern, d_arith_coeffs ) ){
- Debug("inst-match-gen") << "(?) Unknown matching pattern is " << d_match_pattern << std::endl;
- //Warning() << "(?) Unknown matching pattern is " << d_match_pattern << std::endl;
- d_matchPolicy = MATCH_GEN_INTERNAL_ERROR;
- }else{
- Debug("matching-arith") << "Generated arithmetic pattern for " << d_match_pattern << ": " << std::endl;
- for( std::map< Node, Node >::iterator it = d_arith_coeffs.begin(); it != d_arith_coeffs.end(); ++it ){
- Debug("matching-arith") << " " << it->first << " -> " << it->second << std::endl;
- }
- //we will treat this as match gen internal arithmetic
- d_matchPolicy = MATCH_GEN_INTERNAL_ARITHMETIC;
- }
- }
-}
-
-/** get match (not modulo equality) */
-bool InstMatchGenerator::getMatch( Node t, InstMatch& m, QuantifiersEngine* qe ){
- Debug("matching") << "Matching " << t << " against pattern " << d_match_pattern << " ("
- << m.size() << ")" << ", " << d_children.size() << std::endl;
- Assert( !d_match_pattern.isNull() );
- if( qe->d_optMatchIgnoreModelBasis && t.getAttribute(ModelBasisAttribute()) ){
- return true;
- }else if( d_matchPolicy==MATCH_GEN_INTERNAL_ARITHMETIC ){
- return getMatchArithmetic( t, m, qe );
- }else if( d_matchPolicy==MATCH_GEN_INTERNAL_ERROR ){
- return false;
- }else{
- EqualityQuery* q = qe->getEqualityQuery();
- //add m to partial match vector
- std::vector< InstMatch > partial;
- partial.push_back( InstMatch( &m ) );
- //if t is null
- Assert( !t.isNull() );
- Assert( !t.hasAttribute(InstConstantAttribute()) );
- Assert( 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( d_match_pattern[i].hasAttribute(InstConstantAttribute()) ){
- if( d_match_pattern[i].getKind()==INST_CONSTANT ){
- if( !partial[0].setMatch( q, d_match_pattern[i], t[i] ) ){
- //match is in conflict
- Debug("matching-debug") << "Match in conflict " << t[i] << " and "
- << d_match_pattern[i] << " because "
- << partial[0].get(d_match_pattern[i])
- << std::endl;
- Debug("matching-fail") << "Match fail: " << partial[0].get(d_match_pattern[i]) << " and " << t[i] << std::endl;
- return false;
- }
- }
- }else{
- if( !q->areEqual( d_match_pattern[i], t[i] ) ){
- Debug("matching-fail") << "Match fail arg: " << d_match_pattern[i] << " and " << t[i] << std::endl;
- //ground arguments are not equal
- return false;
- }
- }
- }
- //now, fit children into match
- //we will be requesting candidates for matching terms for each child
- std::vector< Node > reps;
- for( int i=0; i<(int)d_children.size(); i++ ){
- Node rep = q->getRepresentative( t[ d_children_index[i] ] );
- reps.push_back( rep );
- d_children[i]->d_cg->reset( rep );
- }
-
- //combine child matches
- int index = 0;
- while( index>=0 && index<(int)d_children.size() ){
- partial.push_back( InstMatch( &partial[index] ) );
- if( d_children[index]->getNextMatch2( partial[index+1], qe ) ){
- index++;
- }else{
- d_children[index]->d_cg->reset( reps[index] );
- partial.pop_back();
- if( !partial.empty() ){
- partial.pop_back();
- }
- index--;
- }
- }
- if( index>=0 ){
- m = partial.back();
- return true;
- }else{
- return false;
- }
- }
-}
-
-bool InstMatchGenerator::getNextMatch2( InstMatch& m, QuantifiersEngine* qe, bool saveMatched ){
- bool success = false;
- Node t;
- do{
- //get the next candidate term t
- t = d_cg->getNextCandidate();
- //if t not null, try to fit it into match m
- if( !t.isNull() && t.getType()==d_match_pattern.getType() ){
- success = getMatch( t, m, qe );
- }
- }while( !success && !t.isNull() );
- if (saveMatched) m.d_matched = t;
- return success;
-}
-
-bool InstMatchGenerator::getMatchArithmetic( Node t, InstMatch& m, QuantifiersEngine* qe ){
- Debug("matching-arith") << "Matching " << t << " " << d_match_pattern << std::endl;
- if( !d_arith_coeffs.empty() ){
- NodeBuilder<> tb(kind::PLUS);
- Node ic = Node::null();
- for( std::map< Node, Node >::iterator it = d_arith_coeffs.begin(); it != d_arith_coeffs.end(); ++it ){
- Debug("matching-arith") << it->first << " -> " << it->second << std::endl;
- if( !it->first.isNull() ){
- if( m.find( it->first )==m.end() ){
- //see if we can choose this to set
- if( ic.isNull() && ( it->second.isNull() || !it->first.getType().isInteger() ) ){
- ic = it->first;
- }
- }else{
- Debug("matching-arith") << "already set " << m.get( it->first ) << std::endl;
- Node tm = m.get( it->first );
- if( !it->second.isNull() ){
- tm = NodeManager::currentNM()->mkNode( MULT, it->second, tm );
- }
- tb << tm;
- }
- }else{
- tb << it->second;
- }
- }
- if( !ic.isNull() ){
- Node tm;
- if( tb.getNumChildren()==0 ){
- tm = t;
- }else{
- tm = tb.getNumChildren()==1 ? tb.getChild( 0 ) : tb;
- tm = NodeManager::currentNM()->mkNode( MINUS, t, tm );
- }
- if( !d_arith_coeffs[ ic ].isNull() ){
- Assert( !ic.getType().isInteger() );
- Node coeff = NodeManager::currentNM()->mkConst( Rational(1) / d_arith_coeffs[ ic ].getConst<Rational>() );
- tm = NodeManager::currentNM()->mkNode( MULT, coeff, tm );
- }
- m.set( ic, Rewriter::rewrite( tm ));
- //set the rest to zeros
- for( std::map< Node, Node >::iterator it = d_arith_coeffs.begin(); it != d_arith_coeffs.end(); ++it ){
- if( !it->first.isNull() ){
- if( m.find( it->first )==m.end() ){
- m.set( it->first, NodeManager::currentNM()->mkConst( Rational(0) ) );
- }
- }
- }
- Debug("matching-arith") << "Setting " << ic << " to " << tm << std::endl;
- return true;
- }else{
- return false;
- }
- }else{
- return false;
- }
-}
-
-
-/** reset instantiation round */
-void InstMatchGenerator::resetInstantiationRound( QuantifiersEngine* qe ){
- if( d_match_pattern.isNull() ){
- for( int i=0; i<(int)d_children.size(); i++ ){
- d_children[i]->resetInstantiationRound( qe );
- }
- }else{
- if( d_cg ){
- d_cg->resetInstantiationRound();
- }
- }
-}
-
-void InstMatchGenerator::reset( Node eqc, QuantifiersEngine* qe ){
- if( d_match_pattern.isNull() ){
- for( int i=0; i<(int)d_children.size(); i++ ){
- d_children[i]->reset( eqc, qe );
- }
- d_partial.clear();
- }else{
- if( !d_eq_class.isNull() ){
- //we have a specific equivalence class in mind
- //we are producing matches for f(E) ~ t, where E is a non-ground vector of terms, and t is a ground term
- //just look in equivalence class of the RHS
- d_cg->reset( d_eq_class );
- }else{
- d_cg->reset( eqc );
- }
- }
-}
-
-bool InstMatchGenerator::getNextMatch( InstMatch& m, QuantifiersEngine* qe ){
- m.d_matched = Node::null();
- if( d_match_pattern.isNull() ){
- int index = (int)d_partial.size();
- while( index>=0 && index<(int)d_children.size() ){
- if( index>0 ){
- d_partial.push_back( InstMatch( &d_partial[index-1] ) );
- }else{
- d_partial.push_back( InstMatch() );
- }
- if( d_children[index]->getNextMatch( d_partial[index], qe ) ){
- index++;
- }else{
- d_children[index]->reset( Node::null(), qe );
- d_partial.pop_back();
- if( !d_partial.empty() ){
- d_partial.pop_back();
- }
- index--;
- }
- }
- if( index>=0 ){
- m = d_partial.back();
- d_partial.pop_back();
- return true;
- }else{
- return false;
- }
- }else{
- bool res = getNextMatch2( m, qe, true );
- Assert(!res || !m.d_matched.isNull());
- return res;
- }
-}
-
-
-
-int InstMatchGenerator::addInstantiations( Node f, InstMatch& baseMatch, QuantifiersEngine* qe ){
- //now, try to add instantiation for each match produced
- int addedLemmas = 0;
- InstMatch m;
- while( getNextMatch( m, qe ) ){
- //m.makeInternal( d_quantEngine->getEqualityQuery() );
- m.add( baseMatch );
- if( qe->addInstantiation( f, m ) ){
- addedLemmas++;
- if( qe->d_optInstLimitActive && qe->d_optInstLimit<=0 ){
- return addedLemmas;
- }
- }
- m.clear();
- }
- //return number of lemmas added
- return addedLemmas;
-}
-
-int InstMatchGenerator::addTerm( Node f, Node t, QuantifiersEngine* qe ){
- Assert( options::eagerInstQuant() );
- if( !d_match_pattern.isNull() ){
- InstMatch m;
- if( getMatch( t, m, qe ) ){
- if( qe->addInstantiation( f, m ) ){
- return 1;
- }
- }
- }else{
- for( int i=0; i<(int)d_children.size(); i++ ){
- d_children[i]->addTerm( f, t, qe );
- }
- }
- return 0;
-}
-
-/** constructors */
-InstMatchGeneratorMulti::InstMatchGeneratorMulti( Node f, std::vector< Node >& pats, QuantifiersEngine* qe, int matchOption ) :
-d_f( f ){
- Debug("smart-multi-trigger") << "Making smart multi-trigger for " << f << std::endl;
- std::map< Node, std::vector< Node > > var_contains;
- qe->getTermDatabase()->getVarContains( f, pats, var_contains );
- //convert to indicies
- for( std::map< Node, std::vector< Node > >::iterator it = var_contains.begin(); it != var_contains.end(); ++it ){
- Debug("smart-multi-trigger") << "Pattern " << it->first << " contains: ";
- for( int i=0; i<(int)it->second.size(); i++ ){
- Debug("smart-multi-trigger") << it->second[i] << " ";
- int index = it->second[i].getAttribute(InstVarNumAttribute());
- d_var_contains[ it->first ].push_back( index );
- d_var_to_node[ index ].push_back( it->first );
- }
- Debug("smart-multi-trigger") << std::endl;
- }
- for( int i=0; i<(int)pats.size(); i++ ){
- Node n = pats[i];
- //make the match generator
- d_children.push_back( new InstMatchGenerator( n, qe, matchOption ) );
- //compute unique/shared variables
- std::vector< int > unique_vars;
- std::map< int, bool > shared_vars;
- int numSharedVars = 0;
- for( int j=0; j<(int)d_var_contains[n].size(); j++ ){
- if( d_var_to_node[ d_var_contains[n][j] ].size()==1 ){
- Debug("smart-multi-trigger") << "Var " << d_var_contains[n][j] << " is unique to " << pats[i] << std::endl;
- unique_vars.push_back( d_var_contains[n][j] );
- }else{
- shared_vars[ d_var_contains[n][j] ] = true;
- numSharedVars++;
- }
- }
- //we use the latest shared variables, then unique variables
- std::vector< int > vars;
- int index = i==0 ? (int)(pats.size()-1) : (i-1);
- while( numSharedVars>0 && index!=i ){
- for( std::map< int, bool >::iterator it = shared_vars.begin(); it != shared_vars.end(); ++it ){
- if( it->second ){
- if( std::find( d_var_contains[ pats[index] ].begin(), d_var_contains[ pats[index] ].end(), it->first )!=
- d_var_contains[ pats[index] ].end() ){
- vars.push_back( it->first );
- shared_vars[ it->first ] = false;
- numSharedVars--;
- }
- }
- }
- index = index==0 ? (int)(pats.size()-1) : (index-1);
- }
- vars.insert( vars.end(), unique_vars.begin(), unique_vars.end() );
- Debug("smart-multi-trigger") << " Index[" << i << "]: ";
- for( int i=0; i<(int)vars.size(); i++ ){
- Debug("smart-multi-trigger") << vars[i] << " ";
- }
- Debug("smart-multi-trigger") << std::endl;
- //make ordered inst match trie
- InstMatchTrie::ImtIndexOrder* imtio = new InstMatchTrie::ImtIndexOrder;
- imtio->d_order.insert( imtio->d_order.begin(), vars.begin(), vars.end() );
- d_children_trie.push_back( InstMatchTrieOrdered( imtio ) );
- }
-
-}
-
-/** reset instantiation round (call this whenever equivalence classes have changed) */
-void InstMatchGeneratorMulti::resetInstantiationRound( QuantifiersEngine* qe ){
- for( int i=0; i<(int)d_children.size(); i++ ){
- d_children[i]->resetInstantiationRound( qe );
- }
-}
-
-/** reset, eqc is the equivalence class to search in (any if eqc=null) */
-void InstMatchGeneratorMulti::reset( Node eqc, QuantifiersEngine* qe ){
- for( int i=0; i<(int)d_children.size(); i++ ){
- d_children[i]->reset( eqc, qe );
- }
-}
-
-int InstMatchGeneratorMulti::addInstantiations( Node f, InstMatch& baseMatch, QuantifiersEngine* qe ){
- int addedLemmas = 0;
- Debug("smart-multi-trigger") << "Process smart multi trigger" << std::endl;
- for( int i=0; i<(int)d_children.size(); i++ ){
- Debug("smart-multi-trigger") << "Calculate matches " << i << std::endl;
- std::vector< InstMatch > newMatches;
- InstMatch m;
- while( d_children[i]->getNextMatch( m, qe ) ){
- m.makeRepresentative( qe );
- newMatches.push_back( InstMatch( &m ) );
- m.clear();
- }
- for( int j=0; j<(int)newMatches.size(); j++ ){
- processNewMatch( qe, newMatches[j], i, addedLemmas );
- }
- }
- return addedLemmas;
-}
-
-void InstMatchGeneratorMulti::processNewMatch( QuantifiersEngine* qe, InstMatch& m, int fromChildIndex, int& addedLemmas ){
- //see if these produce new matches
- d_children_trie[fromChildIndex].addInstMatch( qe, d_f, m, true );
- //possibly only do the following if we know that new matches will be produced?
- //the issue is that instantiations are filtered in quantifiers engine, and so there is no guarentee that
- // we can safely skip the following lines, even when we have already produced this match.
- Debug("smart-multi-trigger") << "Child " << fromChildIndex << " produced match " << m << std::endl;
- //process new instantiations
- int childIndex = (fromChildIndex+1)%(int)d_children.size();
- std::vector< IndexedTrie > unique_var_tries;
- processNewInstantiations( qe, m, addedLemmas, d_children_trie[childIndex].getTrie(),
- unique_var_tries, 0, childIndex, fromChildIndex, true );
-}
-
-void InstMatchGeneratorMulti::processNewInstantiations( QuantifiersEngine* qe, InstMatch& m, int& addedLemmas, InstMatchTrie* tr,
- std::vector< IndexedTrie >& unique_var_tries,
- int trieIndex, int childIndex, int endChildIndex, bool modEq ){
- if( childIndex==endChildIndex ){
- //now, process unique variables
- processNewInstantiations2( qe, m, addedLemmas, unique_var_tries, 0 );
- }else if( trieIndex<(int)d_children_trie[childIndex].getOrdering()->d_order.size() ){
- int curr_index = d_children_trie[childIndex].getOrdering()->d_order[trieIndex];
- Node curr_ic = qe->getTermDatabase()->getInstantiationConstant( d_f, curr_index );
- if( m.find( curr_ic )==m.end() ){
- //if( d_var_to_node[ curr_index ].size()==1 ){ //FIXME
- // //unique variable(s), defer calculation
- // unique_var_tries.push_back( IndexedTrie( std::pair< int, int >( childIndex, trieIndex ), tr ) );
- // int newChildIndex = (childIndex+1)%(int)d_children.size();
- // processNewInstantiations( qe, m, d_children_trie[newChildIndex].getTrie(), unique_var_tries,
- // 0, newChildIndex, endChildIndex, modEq );
- //}else{
- //shared and non-set variable, add to InstMatch
- for( std::map< Node, InstMatchTrie >::iterator it = tr->d_data.begin(); it != tr->d_data.end(); ++it ){
- InstMatch mn( &m );
- mn.set( curr_ic, it->first);
- processNewInstantiations( qe, mn, addedLemmas, &(it->second), unique_var_tries,
- trieIndex+1, childIndex, endChildIndex, modEq );
- }
- //}
- }else{
- //shared and set variable, try to merge
- Node n = m.get( curr_ic );
- std::map< Node, InstMatchTrie >::iterator it = tr->d_data.find( n );
- if( it!=tr->d_data.end() ){
- processNewInstantiations( qe, m, addedLemmas, &(it->second), unique_var_tries,
- trieIndex+1, childIndex, endChildIndex, modEq );
- }
- if( modEq ){
- //check modulo equality for other possible instantiations
- if( qe->getEqualityQuery()->getEngine()->hasTerm( n ) ){
- eq::EqClassIterator eqc( qe->getEqualityQuery()->getEngine()->getRepresentative( n ),
- qe->getEqualityQuery()->getEngine() );
- while( !eqc.isFinished() ){
- Node en = (*eqc);
- if( en!=n ){
- std::map< Node, InstMatchTrie >::iterator itc = tr->d_data.find( en );
- if( itc!=tr->d_data.end() ){
- processNewInstantiations( qe, m, addedLemmas, &(itc->second), unique_var_tries,
- trieIndex+1, childIndex, endChildIndex, modEq );
- }
- }
- ++eqc;
- }
- }
- }
- }
- }else{
- int newChildIndex = (childIndex+1)%(int)d_children.size();
- processNewInstantiations( qe, m, addedLemmas, d_children_trie[newChildIndex].getTrie(), unique_var_tries,
- 0, newChildIndex, endChildIndex, modEq );
- }
-}
-
-void InstMatchGeneratorMulti::processNewInstantiations2( QuantifiersEngine* qe, InstMatch& m, int& addedLemmas,
- std::vector< IndexedTrie >& unique_var_tries,
- int uvtIndex, InstMatchTrie* tr, int trieIndex ){
- if( uvtIndex<(int)unique_var_tries.size() ){
- int childIndex = unique_var_tries[uvtIndex].first.first;
- if( !tr ){
- tr = unique_var_tries[uvtIndex].second;
- trieIndex = unique_var_tries[uvtIndex].first.second;
- }
- if( trieIndex<(int)d_children_trie[childIndex].getOrdering()->d_order.size() ){
- int curr_index = d_children_trie[childIndex].getOrdering()->d_order[trieIndex];
- Node curr_ic = qe->getTermDatabase()->getInstantiationConstant( d_f, curr_index );
- //unique non-set variable, add to InstMatch
- for( std::map< Node, InstMatchTrie >::iterator it = tr->d_data.begin(); it != tr->d_data.end(); ++it ){
- InstMatch mn( &m );
- mn.set( curr_ic, it->first);
- processNewInstantiations2( qe, mn, addedLemmas, unique_var_tries, uvtIndex, &(it->second), trieIndex+1 );
- }
- }else{
- processNewInstantiations2( qe, m, addedLemmas, unique_var_tries, uvtIndex+1 );
- }
- }else{
- //m is an instantiation
- if( qe->addInstantiation( d_f, m ) ){
- addedLemmas++;
- Debug("smart-multi-trigger") << "-> Produced instantiation " << m << std::endl;
- }
- }
-}
-
-int InstMatchGeneratorMulti::addTerm( Node f, Node t, QuantifiersEngine* qe ){
- Assert( options::eagerInstQuant() );
- int addedLemmas = 0;
- for( int i=0; i<(int)d_children.size(); i++ ){
- if( ((InstMatchGenerator*)d_children[i])->d_match_pattern.getOperator()==t.getOperator() ){
- InstMatch m;
- //if it produces a match, then process it with the rest
- if( ((InstMatchGenerator*)d_children[i])->getMatch( t, m, qe ) ){
- processNewMatch( qe, m, i, addedLemmas );
- }
- }
- }
- return addedLemmas;
-}
-
-int InstMatchGeneratorSimple::addInstantiations( Node f, InstMatch& baseMatch, QuantifiersEngine* qe ){
- InstMatch m;
- 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_match_pattern.getOperator() ]) );
- }
- }else{
- addInstantiations( m, qe, addedLemmas, 0, &(qe->getTermDatabase()->d_func_map_trie[ d_match_pattern.getOperator() ]) );
- }
- return addedLemmas;
-}
-
-void InstMatchGeneratorSimple::addInstantiations( InstMatch& m, QuantifiersEngine* qe, int& addedLemmas, int argIndex, quantifiers::TermArgTrie* tat ){
- if( argIndex==(int)d_match_pattern.getNumChildren() ){
- //m is an instantiation
- if( qe->addInstantiation( d_f, m ) ){
- addedLemmas++;
- Debug("simple-multi-trigger") << "-> Produced instantiation " << m << std::endl;
- }
- }else{
- if( d_match_pattern[argIndex].getKind()==INST_CONSTANT ){
- Node ic = d_match_pattern[argIndex];
- for( std::map< Node, quantifiers::TermArgTrie >::iterator it = tat->d_data.begin(); it != tat->d_data.end(); ++it ){
- Node t = it->first;
- if( ( m.get( ic ).isNull() || m.get( ic )==t ) && ic.getType()==t.getType() ){
- Node prev = m.get( ic );
- m.set( ic, t);
- addInstantiations( m, qe, addedLemmas, argIndex+1, &(it->second) );
- m.set( ic, prev);
- }
- }
- }else{
- Node r = qe->getEqualityQuery()->getRepresentative( d_match_pattern[argIndex] );
- std::map< Node, quantifiers::TermArgTrie >::iterator it = tat->d_data.find( r );
- if( it!=tat->d_data.end() ){
- addInstantiations( m, qe, addedLemmas, argIndex+1, &(it->second) );
- }
- }
- }
-}
-
-int InstMatchGeneratorSimple::addTerm( Node f, Node t, QuantifiersEngine* qe ){
- Assert( options::eagerInstQuant() );
- InstMatch m;
- for( int i=0; i<(int)t.getNumChildren(); i++ ){
- if( d_match_pattern[i].getKind()==INST_CONSTANT ){
- m.set(d_match_pattern[i], t[i]);
- }else if( !qe->getEqualityQuery()->areEqual( d_match_pattern[i], t[i] ) ){
- return 0;
- }
- }
- return qe->addInstantiation( f, m ) ? 1 : 0;
-}
-
-}/* CVC4::theory::inst namespace */
-}/* CVC4::theory namespace */
-}/* CVC4 namespace */
+/********************* */ +/*! \file inst_match_generator.cpp + ** \verbatim + ** Original author: Andrew Reynolds <andrew.j.reynolds@gmail.com> + ** Major contributors: Morgan Deters <mdeters@cs.nyu.edu> + ** Minor contributors (to current version): none + ** This file is part of the CVC4 project. + ** Copyright (c) 2009-2013 New York University and The University of Iowa + ** See the file COPYING in the top-level source directory for licensing + ** information.\endverbatim + ** + ** [[ Add lengthier description here ]] + ** \todo document this file +**/ + +#include "theory/quantifiers/inst_match_generator.h" +#include "theory/quantifiers/trigger.h" +#include "theory/quantifiers/term_database.h" +#include "theory/quantifiers/candidate_generator.h" +#include "theory/quantifiers_engine.h" + +using namespace std; +using namespace CVC4; +using namespace CVC4::kind; +using namespace CVC4::context; +using namespace CVC4::theory; + +namespace CVC4 { +namespace theory { +namespace inst { + + +InstMatchGenerator::InstMatchGenerator( Node pat, int matchPolicy ) : d_matchPolicy( matchPolicy ){ + d_active_add = false; + Assert( pat.hasAttribute(InstConstantAttribute()) ); + d_pattern = pat; + d_match_pattern = pat; + d_next = NULL; +} + +void InstMatchGenerator::setActiveAdd(){ + d_active_add = true; + if( d_next!=NULL ){ + d_next->setActiveAdd(); + } +} + +void InstMatchGenerator::initialize( QuantifiersEngine* qe, std::vector< InstMatchGenerator * > & gens ){ + if( !d_pattern.isNull() ){ + Debug("inst-match-gen") << "Pattern term is " << d_pattern << std::endl; + if( d_match_pattern.getKind()==NOT ){ + //we want to add the children of the NOT + d_match_pattern = d_pattern[0]; + } + if( d_match_pattern.getKind()==IFF || d_match_pattern.getKind()==EQUAL ){ + if( !d_match_pattern[0].hasAttribute(InstConstantAttribute()) ){ + Assert( d_match_pattern[1].hasAttribute(InstConstantAttribute()) ); + //swap sides + Node pat = d_pattern; + d_pattern = NodeManager::currentNM()->mkNode( d_match_pattern.getKind(), d_match_pattern[1], d_match_pattern[0] ); + d_pattern = pat.getKind()==NOT ? d_pattern.notNode() : d_pattern; + if( pat.getKind()!=NOT ){ //TEMPORARY until we do better implementation of disequality matching + d_match_pattern = d_match_pattern[1]; + }else{ + d_match_pattern = d_pattern[0][0]; + } + }else if( !d_match_pattern[1].hasAttribute(InstConstantAttribute()) ){ + Assert( d_match_pattern[0].hasAttribute(InstConstantAttribute()) ); + if( d_pattern.getKind()!=NOT ){ //TEMPORARY until we do better implementation of disequality matching + d_match_pattern = d_match_pattern[0]; + } + } + } + int childMatchPolicy = MATCH_GEN_DEFAULT; + for( int i=0; i<(int)d_match_pattern.getNumChildren(); i++ ){ + if( d_match_pattern[i].hasAttribute(InstConstantAttribute()) ){ + if( d_match_pattern[i].getKind()!=INST_CONSTANT ){ + InstMatchGenerator * cimg = new InstMatchGenerator( d_match_pattern[i], childMatchPolicy ); + d_children.push_back( cimg ); + d_children_index.push_back( i ); + gens.push_back( cimg ); + } + } + } + + Debug("inst-match-gen") << "Pattern is " << d_pattern << ", match pattern is " << d_match_pattern << std::endl; + + //create candidate generator + if( d_match_pattern.getKind()==EQUAL || d_match_pattern.getKind()==IFF ){ + Assert( d_matchPolicy==MATCH_GEN_DEFAULT ); + //we will be producing candidates via literal matching heuristics + if( d_pattern.getKind()!=NOT ){ + //candidates will be all equalities + d_cg = new inst::CandidateGeneratorQELitEq( qe, d_match_pattern ); + }else{ + //candidates will be all disequalities + d_cg = new inst::CandidateGeneratorQELitDeq( qe, d_match_pattern ); + } + }else if( d_pattern.getKind()==EQUAL || d_pattern.getKind()==IFF || d_pattern.getKind()==NOT ){ + Assert( d_matchPolicy==MATCH_GEN_DEFAULT ); + if( d_pattern.getKind()==NOT ){ + Unimplemented("Disequal generator unimplemented"); + }else{ + Assert( Trigger::isAtomicTrigger( d_match_pattern ) ); + //we are matching only in a particular equivalence class + d_cg = new inst::CandidateGeneratorQE( qe, d_match_pattern.getOperator() ); + //store the equivalence class that we will call d_cg->reset( ... ) on + d_eq_class = d_pattern[1]; + } + }else if( Trigger::isAtomicTrigger( d_match_pattern ) ){ + //if( d_matchPolicy==MATCH_GEN_EFFICIENT_E_MATCH ){ + //Warning() << "Currently efficient e matching is not taken into account for quantifiers: " << d_pattern << std::endl; + //} + //we will be scanning lists trying to find d_match_pattern.getOperator() + d_cg = new inst::CandidateGeneratorQE( qe, d_match_pattern.getOperator() ); + }else{ + d_cg = new CandidateGeneratorQueue; + if( !Trigger::getPatternArithmetic( d_match_pattern.getAttribute(InstConstantAttribute()), d_match_pattern, d_arith_coeffs ) ){ + Debug("inst-match-gen") << "(?) Unknown matching pattern is " << d_match_pattern << std::endl; + //Warning() << "(?) Unknown matching pattern is " << d_match_pattern << std::endl; + d_matchPolicy = MATCH_GEN_INTERNAL_ERROR; + }else{ + Debug("matching-arith") << "Generated arithmetic pattern for " << d_match_pattern << ": " << std::endl; + for( std::map< Node, Node >::iterator it = d_arith_coeffs.begin(); it != d_arith_coeffs.end(); ++it ){ + Debug("matching-arith") << " " << it->first << " -> " << it->second << std::endl; + } + //we will treat this as match gen internal arithmetic + d_matchPolicy = MATCH_GEN_INTERNAL_ARITHMETIC; + } + } + } +} + +/** get match (not modulo equality) */ +bool InstMatchGenerator::getMatch( Node f, Node t, InstMatch& m, QuantifiersEngine* qe ){ + Debug("matching") << "Matching " << t << " against pattern " << d_match_pattern << " (" + << m << ")" << ", " << d_children.size() << std::endl; + Assert( !d_match_pattern.isNull() ); + if( qe->d_optMatchIgnoreModelBasis && t.getAttribute(ModelBasisAttribute()) ){ + return true; + }else if( d_matchPolicy==MATCH_GEN_INTERNAL_ARITHMETIC ){ + return getMatchArithmetic( t, m, qe ); + }else if( d_matchPolicy==MATCH_GEN_INTERNAL_ERROR ){ + return false; + }else{ + EqualityQuery* q = qe->getEqualityQuery(); + bool success = true; + //save previous match + InstMatch prev( &m ); + //if t is null + Assert( !t.isNull() ); + Assert( !t.hasAttribute(InstConstantAttribute()) ); + Assert( 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( d_match_pattern[i].hasAttribute(InstConstantAttribute()) ){ + if( d_match_pattern[i].getKind()==INST_CONSTANT ){ + if( !m.setMatch( q, d_match_pattern[i], t[i] ) ){ + //match is in conflict + Debug("matching-debug") << "Match in conflict " << t[i] << " and " + << d_match_pattern[i] << " because " + << m.get(d_match_pattern[i]) + << std::endl; + Debug("matching-fail") << "Match fail: " << m.get(d_match_pattern[i]) << " and " << t[i] << std::endl; + success = false; + break; + } + } + }else{ + if( !q->areEqual( d_match_pattern[i], t[i] ) ){ + Debug("matching-fail") << "Match fail arg: " << d_match_pattern[i] << " and " << t[i] << std::endl; + //ground arguments are not equal + success = false; + break; + } + } + } + if( success ){ + //now, fit children into match + //we will be requesting candidates for matching terms for each child + std::vector< Node > reps; + for( int i=0; i<(int)d_children.size(); i++ ){ + Node rep = q->getRepresentative( t[ d_children_index[i] ] ); + reps.push_back( rep ); + 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 ); + Trace("active-add") << "Success = " << success << std::endl; + } + } + } + if( !success ){ + m = InstMatch( &prev ); + } + return success; + } +} + +bool InstMatchGenerator::getMatchArithmetic( Node t, InstMatch& m, QuantifiersEngine* qe ){ + Debug("matching-arith") << "Matching " << t << " " << d_match_pattern << std::endl; + if( !d_arith_coeffs.empty() ){ + NodeBuilder<> tb(kind::PLUS); + Node ic = Node::null(); + for( std::map< Node, Node >::iterator it = d_arith_coeffs.begin(); it != d_arith_coeffs.end(); ++it ){ + Debug("matching-arith") << it->first << " -> " << it->second << std::endl; + if( !it->first.isNull() ){ + if( m.find( it->first )==m.end() ){ + //see if we can choose this to set + if( ic.isNull() && ( it->second.isNull() || !it->first.getType().isInteger() ) ){ + ic = it->first; + } + }else{ + Debug("matching-arith") << "already set " << m.get( it->first ) << std::endl; + Node tm = m.get( it->first ); + if( !it->second.isNull() ){ + tm = NodeManager::currentNM()->mkNode( MULT, it->second, tm ); + } + tb << tm; + } + }else{ + tb << it->second; + } + } + if( !ic.isNull() ){ + Node tm; + if( tb.getNumChildren()==0 ){ + tm = t; + }else{ + tm = tb.getNumChildren()==1 ? tb.getChild( 0 ) : tb; + tm = NodeManager::currentNM()->mkNode( MINUS, t, tm ); + } + if( !d_arith_coeffs[ ic ].isNull() ){ + Assert( !ic.getType().isInteger() ); + Node coeff = NodeManager::currentNM()->mkConst( Rational(1) / d_arith_coeffs[ ic ].getConst<Rational>() ); + tm = NodeManager::currentNM()->mkNode( MULT, coeff, tm ); + } + m.set( ic, Rewriter::rewrite( tm )); + //set the rest to zeros + for( std::map< Node, Node >::iterator it = d_arith_coeffs.begin(); it != d_arith_coeffs.end(); ++it ){ + if( !it->first.isNull() ){ + if( m.find( it->first )==m.end() ){ + m.set( it->first, NodeManager::currentNM()->mkConst( Rational(0) ) ); + } + } + } + Debug("matching-arith") << "Setting " << ic << " to " << tm << std::endl; + return true; + }else{ + return false; + } + }else{ + return false; + } +} + + +/** reset instantiation round */ +void InstMatchGenerator::resetInstantiationRound( QuantifiersEngine* qe ){ + if( d_match_pattern.isNull() ){ + for( int i=0; i<(int)d_children.size(); i++ ){ + d_children[i]->resetInstantiationRound( qe ); + } + }else{ + if( d_cg ){ + d_cg->resetInstantiationRound(); + } + } +} + +void InstMatchGenerator::reset( Node eqc, QuantifiersEngine* qe ){ + if( !eqc.isNull() ){ + d_eq_class = eqc; + } + //we have a specific equivalence class in mind + //we are producing matches for f(E) ~ t, where E is a non-ground vector of terms, and t is a ground term + //just look in equivalence class of the RHS + d_cg->reset( d_eq_class ); +} + +bool InstMatchGenerator::getNextMatch( Node f, InstMatch& m, QuantifiersEngine* qe ){ + m.d_matched = Node::null(); + //Debug("matching") << this << " " << d_pattern << " get next match 2 " << m << " in eq class " << d_eq_class << std::endl; + bool success = false; + Node t; + do{ + //get the next candidate term t + t = d_cg->getNextCandidate(); + //if t not null, try to fit it into match m + if( !t.isNull() && t.getType()==d_match_pattern.getType() ){ + success = getMatch( f, t, m, qe ); + } + }while( !success && !t.isNull() ); + m.d_matched = t; + if( !success ){ + //Debug("matching") << this << " failed, reset " << d_eq_class << std::endl; + //we failed, must reset + reset( d_eq_class, qe ); + } + return success; +} + + + +int InstMatchGenerator::addInstantiations( Node f, InstMatch& baseMatch, QuantifiersEngine* qe ){ + //try to add instantiation for each match produced + int addedLemmas = 0; + InstMatch m; + while( getNextMatch( f, m, qe ) ){ + if( !d_active_add ){ + //m.makeInternal( d_quantEngine->getEqualityQuery() ); + m.add( baseMatch ); + if( qe->addInstantiation( f, m ) ){ + addedLemmas++; + if( qe->d_optInstLimitActive && qe->d_optInstLimit<=0 ){ + return addedLemmas; + } + } + }else{ + addedLemmas++; + } + m.clear(); + } + //return number of lemmas added + return addedLemmas; +} + +int InstMatchGenerator::addTerm( Node f, Node t, QuantifiersEngine* qe ){ + Assert( options::eagerInstQuant() ); + if( !d_match_pattern.isNull() ){ + InstMatch m; + if( getMatch( f, t, m, qe ) ){ + if( qe->addInstantiation( f, m ) ){ + return 1; + } + } + }else{ + for( int i=0; i<(int)d_children.size(); i++ ){ + d_children[i]->addTerm( f, t, qe ); + } + } + return 0; +} + + +InstMatchGenerator* InstMatchGenerator::mkInstMatchGenerator( Node pat, QuantifiersEngine* qe ) { + std::vector< Node > pats; + pats.push_back( pat ); + return mkInstMatchGenerator( pats, qe ); +} + +InstMatchGenerator* InstMatchGenerator::mkInstMatchGenerator( std::vector< Node >& pats, QuantifiersEngine* qe ) { + size_t pCounter = 0; + InstMatchGenerator* prev = NULL; + InstMatchGenerator* oinit = NULL; + while( pCounter<pats.size() ){ + size_t counter = 0; + std::vector< InstMatchGenerator* > gens; + InstMatchGenerator* init = new InstMatchGenerator(pats[pCounter]); + if(pCounter==0){ + oinit = init; + } + gens.push_back(init); + //chain the resulting match generators together + while (counter<gens.size()) { + InstMatchGenerator* curr = gens[counter]; + if( prev ){ + prev->d_next = curr; + } + curr->initialize(qe, gens); + prev = curr; + counter++; + } + pCounter++; + } + return oinit; +} + +/** constructors */ +InstMatchGeneratorMulti::InstMatchGeneratorMulti( Node f, std::vector< Node >& pats, QuantifiersEngine* qe, int matchOption ) : +d_f( f ){ + Debug("smart-multi-trigger") << "Making smart multi-trigger for " << f << std::endl; + std::map< Node, std::vector< Node > > var_contains; + qe->getTermDatabase()->getVarContains( f, pats, var_contains ); + //convert to indicies + for( std::map< Node, std::vector< Node > >::iterator it = var_contains.begin(); it != var_contains.end(); ++it ){ + Debug("smart-multi-trigger") << "Pattern " << it->first << " contains: "; + for( int i=0; i<(int)it->second.size(); i++ ){ + Debug("smart-multi-trigger") << it->second[i] << " "; + int index = it->second[i].getAttribute(InstVarNumAttribute()); + d_var_contains[ it->first ].push_back( index ); + d_var_to_node[ index ].push_back( it->first ); + } + Debug("smart-multi-trigger") << std::endl; + } + for( int i=0; i<(int)pats.size(); i++ ){ + Node n = pats[i]; + //make the match generator + d_children.push_back( InstMatchGenerator::mkInstMatchGenerator( n, qe ) ); + //compute unique/shared variables + std::vector< int > unique_vars; + std::map< int, bool > shared_vars; + int numSharedVars = 0; + for( int j=0; j<(int)d_var_contains[n].size(); j++ ){ + if( d_var_to_node[ d_var_contains[n][j] ].size()==1 ){ + Debug("smart-multi-trigger") << "Var " << d_var_contains[n][j] << " is unique to " << pats[i] << std::endl; + unique_vars.push_back( d_var_contains[n][j] ); + }else{ + shared_vars[ d_var_contains[n][j] ] = true; + numSharedVars++; + } + } + //we use the latest shared variables, then unique variables + std::vector< int > vars; + int index = i==0 ? (int)(pats.size()-1) : (i-1); + while( numSharedVars>0 && index!=i ){ + for( std::map< int, bool >::iterator it = shared_vars.begin(); it != shared_vars.end(); ++it ){ + if( it->second ){ + if( std::find( d_var_contains[ pats[index] ].begin(), d_var_contains[ pats[index] ].end(), it->first )!= + d_var_contains[ pats[index] ].end() ){ + vars.push_back( it->first ); + shared_vars[ it->first ] = false; + numSharedVars--; + } + } + } + index = index==0 ? (int)(pats.size()-1) : (index-1); + } + vars.insert( vars.end(), unique_vars.begin(), unique_vars.end() ); + Debug("smart-multi-trigger") << " Index[" << i << "]: "; + for( int i=0; i<(int)vars.size(); i++ ){ + Debug("smart-multi-trigger") << vars[i] << " "; + } + Debug("smart-multi-trigger") << std::endl; + //make ordered inst match trie + InstMatchTrie::ImtIndexOrder* imtio = new InstMatchTrie::ImtIndexOrder; + imtio->d_order.insert( imtio->d_order.begin(), vars.begin(), vars.end() ); + d_children_trie.push_back( InstMatchTrieOrdered( imtio ) ); + } + +} + +/** reset instantiation round (call this whenever equivalence classes have changed) */ +void InstMatchGeneratorMulti::resetInstantiationRound( QuantifiersEngine* qe ){ + for( int i=0; i<(int)d_children.size(); i++ ){ + d_children[i]->resetInstantiationRound( qe ); + } +} + +/** reset, eqc is the equivalence class to search in (any if eqc=null) */ +void InstMatchGeneratorMulti::reset( Node eqc, QuantifiersEngine* qe ){ + for( int i=0; i<(int)d_children.size(); i++ ){ + d_children[i]->reset( eqc, qe ); + } +} + +int InstMatchGeneratorMulti::addInstantiations( Node f, InstMatch& baseMatch, QuantifiersEngine* qe ){ + int addedLemmas = 0; + Debug("smart-multi-trigger") << "Process smart multi trigger" << std::endl; + for( int i=0; i<(int)d_children.size(); i++ ){ + Debug("smart-multi-trigger") << "Calculate matches " << i << std::endl; + std::vector< InstMatch > newMatches; + InstMatch m; + while( d_children[i]->getNextMatch( f, m, qe ) ){ + //m.makeRepresentative( qe ); + newMatches.push_back( InstMatch( &m ) ); + m.clear(); + } + Debug("smart-multi-trigger") << "Made " << newMatches.size() << " new matches for index " << i << std::endl; + for( int j=0; j<(int)newMatches.size(); j++ ){ + processNewMatch( qe, newMatches[j], i, addedLemmas ); + } + } + return addedLemmas; +} + +void InstMatchGeneratorMulti::processNewMatch( QuantifiersEngine* qe, InstMatch& m, int fromChildIndex, int& addedLemmas ){ + //see if these produce new matches + d_children_trie[fromChildIndex].addInstMatch( qe, d_f, m, true ); + //possibly only do the following if we know that new matches will be produced? + //the issue is that instantiations are filtered in quantifiers engine, and so there is no guarentee that + // we can safely skip the following lines, even when we have already produced this match. + Debug("smart-multi-trigger") << "Child " << fromChildIndex << " produced match " << m << std::endl; + //process new instantiations + int childIndex = (fromChildIndex+1)%(int)d_children.size(); + std::vector< IndexedTrie > unique_var_tries; + processNewInstantiations( qe, m, addedLemmas, d_children_trie[childIndex].getTrie(), + unique_var_tries, 0, childIndex, fromChildIndex, true ); +} + +void InstMatchGeneratorMulti::processNewInstantiations( QuantifiersEngine* qe, InstMatch& m, int& addedLemmas, InstMatchTrie* tr, + std::vector< IndexedTrie >& unique_var_tries, + int trieIndex, int childIndex, int endChildIndex, bool modEq ){ + if( childIndex==endChildIndex ){ + //now, process unique variables + processNewInstantiations2( qe, m, addedLemmas, unique_var_tries, 0 ); + }else if( trieIndex<(int)d_children_trie[childIndex].getOrdering()->d_order.size() ){ + int curr_index = d_children_trie[childIndex].getOrdering()->d_order[trieIndex]; + Node curr_ic = qe->getTermDatabase()->getInstantiationConstant( d_f, curr_index ); + if( m.find( curr_ic )==m.end() ){ + //if( d_var_to_node[ curr_index ].size()==1 ){ //FIXME + // //unique variable(s), defer calculation + // unique_var_tries.push_back( IndexedTrie( std::pair< int, int >( childIndex, trieIndex ), tr ) ); + // int newChildIndex = (childIndex+1)%(int)d_children.size(); + // processNewInstantiations( qe, m, d_children_trie[newChildIndex].getTrie(), unique_var_tries, + // 0, newChildIndex, endChildIndex, modEq ); + //}else{ + //shared and non-set variable, add to InstMatch + for( std::map< Node, InstMatchTrie >::iterator it = tr->d_data.begin(); it != tr->d_data.end(); ++it ){ + InstMatch mn( &m ); + mn.set( curr_ic, it->first); + processNewInstantiations( qe, mn, addedLemmas, &(it->second), unique_var_tries, + trieIndex+1, childIndex, endChildIndex, modEq ); + } + //} + }else{ + //shared and set variable, try to merge + Node n = m.get( curr_ic ); + std::map< Node, InstMatchTrie >::iterator it = tr->d_data.find( n ); + if( it!=tr->d_data.end() ){ + processNewInstantiations( qe, m, addedLemmas, &(it->second), unique_var_tries, + trieIndex+1, childIndex, endChildIndex, modEq ); + } + if( modEq ){ + //check modulo equality for other possible instantiations + if( qe->getEqualityQuery()->getEngine()->hasTerm( n ) ){ + eq::EqClassIterator eqc( qe->getEqualityQuery()->getEngine()->getRepresentative( n ), + qe->getEqualityQuery()->getEngine() ); + while( !eqc.isFinished() ){ + Node en = (*eqc); + if( en!=n ){ + std::map< Node, InstMatchTrie >::iterator itc = tr->d_data.find( en ); + if( itc!=tr->d_data.end() ){ + processNewInstantiations( qe, m, addedLemmas, &(itc->second), unique_var_tries, + trieIndex+1, childIndex, endChildIndex, modEq ); + } + } + ++eqc; + } + } + } + } + }else{ + int newChildIndex = (childIndex+1)%(int)d_children.size(); + processNewInstantiations( qe, m, addedLemmas, d_children_trie[newChildIndex].getTrie(), unique_var_tries, + 0, newChildIndex, endChildIndex, modEq ); + } +} + +void InstMatchGeneratorMulti::processNewInstantiations2( QuantifiersEngine* qe, InstMatch& m, int& addedLemmas, + std::vector< IndexedTrie >& unique_var_tries, + int uvtIndex, InstMatchTrie* tr, int trieIndex ){ + if( uvtIndex<(int)unique_var_tries.size() ){ + int childIndex = unique_var_tries[uvtIndex].first.first; + if( !tr ){ + tr = unique_var_tries[uvtIndex].second; + trieIndex = unique_var_tries[uvtIndex].first.second; + } + if( trieIndex<(int)d_children_trie[childIndex].getOrdering()->d_order.size() ){ + int curr_index = d_children_trie[childIndex].getOrdering()->d_order[trieIndex]; + Node curr_ic = qe->getTermDatabase()->getInstantiationConstant( d_f, curr_index ); + //unique non-set variable, add to InstMatch + for( std::map< Node, InstMatchTrie >::iterator it = tr->d_data.begin(); it != tr->d_data.end(); ++it ){ + InstMatch mn( &m ); + mn.set( curr_ic, it->first); + processNewInstantiations2( qe, mn, addedLemmas, unique_var_tries, uvtIndex, &(it->second), trieIndex+1 ); + } + }else{ + processNewInstantiations2( qe, m, addedLemmas, unique_var_tries, uvtIndex+1 ); + } + }else{ + //m is an instantiation + if( qe->addInstantiation( d_f, m ) ){ + addedLemmas++; + Debug("smart-multi-trigger") << "-> Produced instantiation " << m << std::endl; + } + } +} + +int InstMatchGeneratorMulti::addTerm( Node f, Node t, QuantifiersEngine* qe ){ + Assert( options::eagerInstQuant() ); + int addedLemmas = 0; + for( int i=0; i<(int)d_children.size(); i++ ){ + if( ((InstMatchGenerator*)d_children[i])->d_match_pattern.getOperator()==t.getOperator() ){ + InstMatch m; + //if it produces a match, then process it with the rest + if( ((InstMatchGenerator*)d_children[i])->getMatch( f, t, m, qe ) ){ + processNewMatch( qe, m, i, addedLemmas ); + } + } + } + return addedLemmas; +} + +int InstMatchGeneratorSimple::addInstantiations( Node f, InstMatch& baseMatch, QuantifiersEngine* qe ){ + InstMatch m; + 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_match_pattern.getOperator() ]) ); + } + }else{ + addInstantiations( m, qe, addedLemmas, 0, &(qe->getTermDatabase()->d_func_map_trie[ d_match_pattern.getOperator() ]) ); + } + return addedLemmas; +} + +void InstMatchGeneratorSimple::addInstantiations( InstMatch& m, QuantifiersEngine* qe, int& addedLemmas, int argIndex, quantifiers::TermArgTrie* tat ){ + if( argIndex==(int)d_match_pattern.getNumChildren() ){ + //m is an instantiation + if( qe->addInstantiation( d_f, m ) ){ + addedLemmas++; + Debug("simple-multi-trigger") << "-> Produced instantiation " << m << std::endl; + } + }else{ + if( d_match_pattern[argIndex].getKind()==INST_CONSTANT ){ + Node ic = d_match_pattern[argIndex]; + for( std::map< Node, quantifiers::TermArgTrie >::iterator it = tat->d_data.begin(); it != tat->d_data.end(); ++it ){ + Node t = it->first; + if( ( m.get( ic ).isNull() || m.get( ic )==t ) && ic.getType()==t.getType() ){ + Node prev = m.get( ic ); + m.set( ic, t); + addInstantiations( m, qe, addedLemmas, argIndex+1, &(it->second) ); + m.set( ic, prev); + } + } + }else{ + Node r = qe->getEqualityQuery()->getRepresentative( d_match_pattern[argIndex] ); + std::map< Node, quantifiers::TermArgTrie >::iterator it = tat->d_data.find( r ); + if( it!=tat->d_data.end() ){ + addInstantiations( m, qe, addedLemmas, argIndex+1, &(it->second) ); + } + } + } +} + +int InstMatchGeneratorSimple::addTerm( Node f, Node t, QuantifiersEngine* qe ){ + Assert( options::eagerInstQuant() ); + InstMatch m; + for( int i=0; i<(int)t.getNumChildren(); i++ ){ + if( d_match_pattern[i].getKind()==INST_CONSTANT ){ + m.set(d_match_pattern[i], t[i]); + }else if( !qe->getEqualityQuery()->areEqual( d_match_pattern[i], t[i] ) ){ + return 0; + } + } + return qe->addInstantiation( f, m ) ? 1 : 0; +} + +}/* CVC4::theory::inst namespace */ +}/* CVC4::theory namespace */ +}/* CVC4 namespace */ diff --git a/src/theory/quantifiers/inst_match_generator.h b/src/theory/quantifiers/inst_match_generator.h index af65e809b..b201fa60f 100755..100644 --- a/src/theory/quantifiers/inst_match_generator.h +++ b/src/theory/quantifiers/inst_match_generator.h @@ -1,192 +1,194 @@ -/********************* */
-/*! \file inst_match_generator.h
- ** \verbatim
- ** Original author: ajreynol
- ** Major contributors: bobot
- ** Minor contributors (to current version): mdeters
- ** This file is part of the CVC4 prototype.
- ** Copyright (c) 2009-2012 New York University and The University of Iowa
- ** See the file COPYING in the top-level source directory for licensing
- ** information.\endverbatim
- **
- ** \brief inst match generator class
- **/
-
-#include "cvc4_private.h"
-
-#ifndef __CVC4__THEORY__QUANTIFIERS__INST_MATCH_GENERATOR_H
-#define __CVC4__THEORY__QUANTIFIERS__INST_MATCH_GENERATOR_H
-
-#include "theory/quantifiers/inst_match.h"
-#include <map>
-
-namespace CVC4 {
-namespace theory {
-
-class QuantifiersEngine;
-namespace quantifiers{
- class TermArgTrie;
-}
-
-namespace inst {
-
-/** base class for producing InstMatch objects */
-class IMGenerator {
-public:
- /** reset instantiation round (call this at beginning of instantiation round) */
- virtual void resetInstantiationRound( QuantifiersEngine* qe ) = 0;
- /** reset, eqc is the equivalence class to search in (any if eqc=null) */
- virtual void reset( Node eqc, QuantifiersEngine* qe ) = 0;
- /** get the next match. must call reset( eqc ) before this function. */
- virtual bool getNextMatch( InstMatch& m, QuantifiersEngine* qe ) = 0;
- /** 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;
-};/* class IMGenerator */
-
-class CandidateGenerator;
-
-class InstMatchGenerator : public IMGenerator {
-private:
- /** candidate generator */
- CandidateGenerator* d_cg;
- /** policy to use for matching */
- int d_matchPolicy;
- /** children generators */
- std::vector< InstMatchGenerator* > d_children;
- std::vector< int > d_children_index;
- /** partial vector */
- std::vector< InstMatch > d_partial;
- /** eq class */
- Node d_eq_class;
- /** for arithmetic matching */
- std::map< Node, Node > d_arith_coeffs;
- /** initialize pattern */
- void initializePatterns( std::vector< Node >& pats, QuantifiersEngine* qe );
- void initializePattern( Node pat, 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_ARITHMETIC,
- MATCH_GEN_INTERNAL_ERROR,
- };
-private:
- /** get the next match. must call d_cg->reset( ... ) before using.
- only valid for use where !d_match_pattern.isNull().
- */
- bool getNextMatch2( InstMatch& m, QuantifiersEngine* qe, bool saveMatched = false );
- /** for arithmetic */
- bool getMatchArithmetic( Node t, InstMatch& m, QuantifiersEngine* qe );
-public:
- /** get the match against ground term or formula t.
- d_match_pattern and t should have the same shape.
- only valid for use where !d_match_pattern.isNull().
- */
- bool getMatch( Node t, InstMatch& m, QuantifiersEngine* qe );
-
- /** constructors */
- InstMatchGenerator( Node pat, QuantifiersEngine* qe, int matchOption = 0 );
- InstMatchGenerator( std::vector< Node >& pats, QuantifiersEngine* qe, int matchOption = 0 );
- /** destructor */
- ~InstMatchGenerator(){}
- /** The pattern we are producing matches for.
- If null, this is a multi trigger that is merging matches from d_children.
- */
- Node d_pattern;
- /** match pattern */
- Node d_match_pattern;
-public:
- /** reset instantiation round (call this whenever equivalence classes have changed) */
- void resetInstantiationRound( QuantifiersEngine* qe );
- /** reset, eqc is the equivalence class to search in (any if eqc=null) */
- void reset( Node eqc, QuantifiersEngine* qe );
- /** get the next match. must call reset( eqc ) before this function. */
- bool getNextMatch( InstMatch& m, QuantifiersEngine* qe );
- /** add instantiations */
- int addInstantiations( Node f, InstMatch& baseMatch, QuantifiersEngine* qe );
- /** add ground term t */
- int addTerm( Node f, Node t, QuantifiersEngine* qe );
-};/* class InstMatchGenerator */
-
-/** smart multi-trigger implementation */
-class InstMatchGeneratorMulti : public IMGenerator {
-private:
- /** indexed trie */
- typedef std::pair< std::pair< int, int >, InstMatchTrie* > IndexedTrie;
- /** process new match */
- void processNewMatch( QuantifiersEngine* qe, InstMatch& m, int fromChildIndex, int& addedLemmas );
- /** process new instantiations */
- void processNewInstantiations( QuantifiersEngine* qe, InstMatch& m, int& addedLemmas, InstMatchTrie* tr,
- std::vector< IndexedTrie >& unique_var_tries,
- int trieIndex, int childIndex, int endChildIndex, bool modEq );
- /** process new instantiations 2 */
- void processNewInstantiations2( QuantifiersEngine* qe, InstMatch& m, int& addedLemmas,
- std::vector< IndexedTrie >& unique_var_tries,
- int uvtIndex, InstMatchTrie* tr = NULL, int trieIndex = 0 );
-private:
- /** var contains (variable indices) for each pattern node */
- std::map< Node, std::vector< int > > d_var_contains;
- /** variable indices contained to pattern nodes */
- std::map< int, std::vector< Node > > d_var_to_node;
- /** quantifier to use */
- Node d_f;
- /** policy to use for matching */
- int d_matchPolicy;
- /** children generators */
- std::vector< InstMatchGenerator* > d_children;
- /** inst match tries for each child */
- std::vector< InstMatchTrieOrdered > d_children_trie;
- /** calculate matches */
- void calculateMatches( QuantifiersEngine* qe );
-public:
- /** constructors */
- InstMatchGeneratorMulti( Node f, std::vector< Node >& pats, QuantifiersEngine* qe, int matchOption = 0 );
- /** destructor */
- ~InstMatchGeneratorMulti(){}
- /** reset instantiation round (call this whenever equivalence classes have changed) */
- void resetInstantiationRound( QuantifiersEngine* qe );
- /** reset, eqc is the equivalence class to search in (any if eqc=null) */
- void reset( Node eqc, QuantifiersEngine* qe );
- /** get the next match. must call reset( eqc ) before this function. (not implemented) */
- bool getNextMatch( InstMatch& m, QuantifiersEngine* qe ) { return false; }
- /** add instantiations */
- int addInstantiations( Node f, InstMatch& baseMatch, QuantifiersEngine* qe );
- /** add ground term t */
- int addTerm( Node f, Node t, QuantifiersEngine* qe );
-};/* class InstMatchGeneratorMulti */
-
-/** smart (single)-trigger implementation */
-class InstMatchGeneratorSimple : public IMGenerator {
-private:
- /** quantifier for match term */
- Node d_f;
- /** match term */
- Node d_match_pattern;
- /** add instantiations */
- void addInstantiations( InstMatch& m, QuantifiersEngine* qe, int& addedLemmas, int argIndex, quantifiers::TermArgTrie* tat );
-public:
- /** constructors */
- InstMatchGeneratorSimple( Node f, Node pat ) : d_f( f ), d_match_pattern( pat ){}
- /** destructor */
- ~InstMatchGeneratorSimple(){}
- /** reset instantiation round (call this whenever equivalence classes have changed) */
- void resetInstantiationRound( QuantifiersEngine* qe ) {}
- /** reset, eqc is the equivalence class to search in (any if eqc=null) */
- void reset( Node eqc, QuantifiersEngine* qe ) {}
- /** get the next match. must call reset( eqc ) before this function. (not implemented) */
- bool getNextMatch( InstMatch& m, QuantifiersEngine* qe ) { return false; }
- /** add instantiations */
- int addInstantiations( Node f, InstMatch& baseMatch, QuantifiersEngine* qe );
- /** add ground term t, possibly add instantiations */
- int addTerm( Node f, Node t, QuantifiersEngine* qe );
-};/* class InstMatchGeneratorSimple */
-
-}
-}
-}
-
-#endif
+/********************* */ +/*! \file inst_match_generator.h + ** \verbatim + ** Original author: Andrew Reynolds <andrew.j.reynolds@gmail.com> + ** Major contributors: Morgan Deters <mdeters@cs.nyu.edu> + ** Minor contributors (to current version): none + ** This file is part of the CVC4 project. + ** Copyright (c) 2009-2013 New York University and The University of Iowa + ** See the file COPYING in the top-level source directory for licensing + ** information.\endverbatim + ** + ** \brief inst match generator class + **/ + +#include "cvc4_private.h" + +#ifndef __CVC4__THEORY__QUANTIFIERS__INST_MATCH_GENERATOR_H +#define __CVC4__THEORY__QUANTIFIERS__INST_MATCH_GENERATOR_H + +#include "theory/quantifiers/inst_match.h" +#include <map> + +namespace CVC4 { +namespace theory { + +class QuantifiersEngine; +namespace quantifiers{ + class TermArgTrie; +} + +namespace inst { + +/** base class for producing InstMatch objects */ +class IMGenerator { +public: + /** reset instantiation round (call this at beginning of instantiation round) */ + virtual void resetInstantiationRound( QuantifiersEngine* qe ) = 0; + /** reset, eqc is the equivalence class to search in (any if eqc=null) */ + virtual void reset( Node eqc, QuantifiersEngine* qe ) = 0; + /** get the next match. must call reset( eqc ) before this function. */ + virtual bool getNextMatch( Node f, InstMatch& m, QuantifiersEngine* qe ) = 0; + /** 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; + /** set active add */ + virtual void setActiveAdd() {} +};/* class IMGenerator */ + +class CandidateGenerator; + +class InstMatchGenerator : public IMGenerator { +private: + /** candidate generator */ + CandidateGenerator* d_cg; + /** policy to use for matching */ + int d_matchPolicy; + /** children generators */ + std::vector< InstMatchGenerator* > d_children; + std::vector< int > d_children_index; + /** the next generator in order */ + InstMatchGenerator* d_next; + /** eq class */ + Node d_eq_class; + /** for arithmetic matching */ + std::map< Node, Node > d_arith_coeffs; + /** initialize pattern */ + void initialize( QuantifiersEngine* qe, std::vector< InstMatchGenerator * > & gens ); +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_ARITHMETIC, + MATCH_GEN_INTERNAL_ERROR, + }; +private: + /** for arithmetic */ + bool getMatchArithmetic( Node t, InstMatch& m, QuantifiersEngine* qe ); +public: + /** get the match against ground term or formula t. + d_match_pattern and t should have the same shape. + only valid for use where !d_match_pattern.isNull(). + */ + bool getMatch( Node f, Node t, InstMatch& m, QuantifiersEngine* qe ); + + /** constructors */ + InstMatchGenerator( Node pat, int matchOption = 0 ); + /** destructor */ + ~InstMatchGenerator(){} + /** The pattern we are producing matches for. + If null, this is a multi trigger that is merging matches from d_children. + */ + Node d_pattern; + /** match pattern */ + Node d_match_pattern; +public: + /** reset instantiation round (call this whenever equivalence classes have changed) */ + void resetInstantiationRound( QuantifiersEngine* qe ); + /** reset, eqc is the equivalence class to search in (any if eqc=null) */ + void reset( Node eqc, QuantifiersEngine* qe ); + /** get the next match. must call reset( eqc ) before this function. */ + bool getNextMatch( Node f, InstMatch& m, QuantifiersEngine* qe ); + /** add instantiations */ + int addInstantiations( Node f, InstMatch& baseMatch, QuantifiersEngine* qe ); + /** add ground term t */ + int addTerm( Node f, Node t, QuantifiersEngine* qe ); + + bool d_active_add; + void setActiveAdd(); + + static InstMatchGenerator* mkInstMatchGenerator( Node pat, QuantifiersEngine* qe ); + static InstMatchGenerator* mkInstMatchGenerator( std::vector< Node >& pats, QuantifiersEngine* qe ); +};/* class InstMatchGenerator */ + +/** smart multi-trigger implementation */ +class InstMatchGeneratorMulti : public IMGenerator { +private: + /** indexed trie */ + typedef std::pair< std::pair< int, int >, InstMatchTrie* > IndexedTrie; + /** process new match */ + void processNewMatch( QuantifiersEngine* qe, InstMatch& m, int fromChildIndex, int& addedLemmas ); + /** process new instantiations */ + void processNewInstantiations( QuantifiersEngine* qe, InstMatch& m, int& addedLemmas, InstMatchTrie* tr, + std::vector< IndexedTrie >& unique_var_tries, + int trieIndex, int childIndex, int endChildIndex, bool modEq ); + /** process new instantiations 2 */ + void processNewInstantiations2( QuantifiersEngine* qe, InstMatch& m, int& addedLemmas, + std::vector< IndexedTrie >& unique_var_tries, + int uvtIndex, InstMatchTrie* tr = NULL, int trieIndex = 0 ); +private: + /** var contains (variable indices) for each pattern node */ + std::map< Node, std::vector< int > > d_var_contains; + /** variable indices contained to pattern nodes */ + std::map< int, std::vector< Node > > d_var_to_node; + /** quantifier to use */ + Node d_f; + /** policy to use for matching */ + int d_matchPolicy; + /** children generators */ + std::vector< InstMatchGenerator* > d_children; + /** inst match tries for each child */ + std::vector< InstMatchTrieOrdered > d_children_trie; + /** calculate matches */ + void calculateMatches( QuantifiersEngine* qe ); +public: + /** constructors */ + InstMatchGeneratorMulti( Node f, std::vector< Node >& pats, QuantifiersEngine* qe, int matchOption = 0 ); + /** destructor */ + ~InstMatchGeneratorMulti(){} + /** reset instantiation round (call this whenever equivalence classes have changed) */ + void resetInstantiationRound( QuantifiersEngine* qe ); + /** reset, eqc is the equivalence class to search in (any if eqc=null) */ + void reset( Node eqc, QuantifiersEngine* qe ); + /** get the next match. must call reset( eqc ) before this function. (not implemented) */ + bool getNextMatch( Node f, InstMatch& m, QuantifiersEngine* qe ) { return false; } + /** add instantiations */ + int addInstantiations( Node f, InstMatch& baseMatch, QuantifiersEngine* qe ); + /** add ground term t */ + int addTerm( Node f, Node t, QuantifiersEngine* qe ); +};/* class InstMatchGeneratorMulti */ + +/** smart (single)-trigger implementation */ +class InstMatchGeneratorSimple : public IMGenerator { +private: + /** quantifier for match term */ + Node d_f; + /** match term */ + Node d_match_pattern; + /** add instantiations */ + void addInstantiations( InstMatch& m, QuantifiersEngine* qe, int& addedLemmas, int argIndex, quantifiers::TermArgTrie* tat ); +public: + /** constructors */ + InstMatchGeneratorSimple( Node f, Node pat ) : d_f( f ), d_match_pattern( pat ){} + /** destructor */ + ~InstMatchGeneratorSimple(){} + /** reset instantiation round (call this whenever equivalence classes have changed) */ + void resetInstantiationRound( QuantifiersEngine* qe ) {} + /** reset, eqc is the equivalence class to search in (any if eqc=null) */ + void reset( Node eqc, QuantifiersEngine* qe ) {} + /** get the next match. must call reset( eqc ) before this function. (not implemented) */ + bool getNextMatch( Node f, InstMatch& m, QuantifiersEngine* qe ) { return false; } + /** add instantiations */ + int addInstantiations( Node f, InstMatch& baseMatch, QuantifiersEngine* qe ); + /** add ground term t, possibly add instantiations */ + int addTerm( Node f, Node t, QuantifiersEngine* qe ); +};/* class InstMatchGeneratorSimple */ + +} +} +} + +#endif diff --git a/src/theory/quantifiers/inst_strategy_cbqi.cpp b/src/theory/quantifiers/inst_strategy_cbqi.cpp index ddf763b73..b12fed619 100755..100644 --- a/src/theory/quantifiers/inst_strategy_cbqi.cpp +++ b/src/theory/quantifiers/inst_strategy_cbqi.cpp @@ -1,405 +1,405 @@ -/********************* */
-/*! \file inst_strategy_cbqi.cpp
- ** \verbatim
- ** Original author: ajreynol
- ** Major contributors: none
- ** Minor contributors (to current version): bobot, mdeters
- ** This file is part of the CVC4 prototype.
- ** Copyright (c) 2009-2012 New York University and The University of Iowa
- ** See the file COPYING in the top-level source directory for licensing
- ** information.\endverbatim
- **
- ** \brief Implementation of cbqi instantiation strategies
- **/
-
-#include "theory/quantifiers/inst_strategy_cbqi.h"
-#include "theory/arith/theory_arith.h"
-#include "theory/theory_engine.h"
-#include "theory/quantifiers/options.h"
-#include "theory/quantifiers/term_database.h"
-
-using namespace std;
-using namespace CVC4;
-using namespace CVC4::kind;
-using namespace CVC4::context;
-using namespace CVC4::theory;
-using namespace CVC4::theory::quantifiers;
-using namespace CVC4::theory::arith;
-using namespace CVC4::theory::datatypes;
-
-#define ARITH_INSTANTIATOR_USE_MINUS_DELTA
-
-InstStrategySimplex::InstStrategySimplex( TheoryArith* th, QuantifiersEngine* ie ) :
- InstStrategy( ie ), d_th( th ), d_counter( 0 ){
- d_negOne = NodeManager::currentNM()->mkConst( Rational(-1) );
-}
-
-bool InstStrategySimplex::calculateShouldProcess( Node f ){
- //DO_THIS
- return false;
-}
-
-void InstStrategySimplex::processResetInstantiationRound( Theory::Effort effort ){
- Debug("quant-arith") << "Setting up simplex for instantiator... " << std::endl;
- d_instRows.clear();
- d_tableaux_term.clear();
- d_tableaux.clear();
- d_ceTableaux.clear();
- //search for instantiation rows in simplex tableaux
- ArithVarNodeMap& avnm = d_th->d_arithvarNodeMap;
- ArithVarNodeMap::var_iterator vi, vend;
- for(vi = avnm.var_begin(), vend = avnm.var_end(); vi != vend; ++vi ){
- ArithVar x = *vi;
- if( d_th->d_partialModel.hasEitherBound( x ) ){
- Node n = avnm.asNode(x);
- Node f;
- NodeBuilder<> t(kind::PLUS);
- if( n.getKind()==PLUS ){
- for( int i=0; i<(int)n.getNumChildren(); i++ ){
- addTermToRow( x, n[i], f, t );
- }
- }else{
- addTermToRow( x, n, f, t );
- }
- if( f!=Node::null() ){
- d_instRows[f].push_back( x );
- //this theory has constraints from f
- Debug("quant-arith") << "Has constraints from " << f << std::endl;
- //set that we should process it
- d_quantActive[ f ] = true;
- //set tableaux term
- if( t.getNumChildren()==0 ){
- d_tableaux_term[x] = NodeManager::currentNM()->mkConst( Rational(0) );
- }else if( t.getNumChildren()==1 ){
- d_tableaux_term[x] = t.getChild( 0 );
- }else{
- d_tableaux_term[x] = t;
- }
- }
- }
- }
- //print debug
- debugPrint( "quant-arith-debug" );
- d_counter++;
-}
-
-int InstStrategySimplex::process( Node f, Theory::Effort effort, int e ){
- if( e<2 ){
- return STATUS_UNFINISHED;
- }else if( e==2 ){
- //Notice() << f << std::endl;
- //Notice() << "Num inst rows = " << d_th->d_instRows[f].size() << std::endl;
- //Notice() << "Num inst constants = " << d_quantEngine->getNumInstantiationConstants( f ) << std::endl;
- Debug("quant-arith-simplex") << "InstStrategySimplex check " << f << ", rows = " << d_instRows[f].size() << std::endl;
- for( int j=0; j<(int)d_instRows[f].size(); j++ ){
- ArithVar x = d_instRows[f][j];
- if( !d_ceTableaux[x].empty() ){
- Debug("quant-arith-simplex") << "Check row " << x << std::endl;
- //instantiation row will be A*e + B*t = beta,
- // where e is a vector of terms , and t is vector of ground terms.
- // Say one term in A*e is coeff*e_i, where e_i is an instantiation constant
- // We will construct the term ( beta - B*t)/coeff to use for e_i.
- InstMatch m;
- //By default, choose the first instantiation constant to be e_i.
- Node var = d_ceTableaux[x].begin()->first;
- if( var.getType().isInteger() ){
- std::map< Node, Node >::iterator it = d_ceTableaux[x].begin();
- //try to find coefficent that is +/- 1
- while( !var.isNull() && !d_ceTableaux[x][var].isNull() && d_ceTableaux[x][var]!=d_negOne ){
- ++it;
- if( it==d_ceTableaux[x].end() ){
- var = Node::null();
- }else{
- var = it->first;
- }
- }
- //otherwise, try one that divides all ground term coefficients? DO_THIS
- }
- if( !var.isNull() ){
- Debug("quant-arith-simplex") << "Instantiate with var " << var << std::endl;
- doInstantiation( f, d_tableaux_term[x], x, m, var );
- }else{
- Debug("quant-arith-simplex") << "Could not find var." << std::endl;
- }
- ////choose a new variable based on alternation strategy
- //int index = d_counter%(int)d_th->d_ceTableaux[x].size();
- //Node var;
- //for( std::map< Node, Node >::iterator it = d_th->d_ceTableaux[x].begin(); it != d_th->d_ceTableaux[x].end(); ++it ){
- // if( index==0 ){
- // var = it->first;
- // break;
- // }
- // index--;
- //}
- //d_th->doInstantiation( f, d_th->d_tableaux_term[x], x, &m, var );
- }
- }
- }
- return STATUS_UNKNOWN;
-}
-
-
-void InstStrategySimplex::addTermToRow( ArithVar x, Node n, Node& f, NodeBuilder<>& t ){
- if( n.getKind()==MULT ){
- if( n[1].hasAttribute(InstConstantAttribute()) ){
- f = n[1].getAttribute(InstConstantAttribute());
- if( n[1].getKind()==INST_CONSTANT ){
- d_ceTableaux[x][ n[1] ] = n[0];
- }else{
- d_tableaux_ce_term[x][ n[1] ] = n[0];
- }
- }else{
- d_tableaux[x][ n[1] ] = n[0];
- t << n;
- }
- }else{
- if( n.hasAttribute(InstConstantAttribute()) ){
- f = n.getAttribute(InstConstantAttribute());
- if( n.getKind()==INST_CONSTANT ){
- d_ceTableaux[x][ n ] = Node::null();
- }else{
- d_tableaux_ce_term[x][ n ] = NodeManager::currentNM()->mkConst( Rational(1) );
- }
- }else{
- d_tableaux[x][ n ] = NodeManager::currentNM()->mkConst( Rational(1) );
- t << n;
- }
- }
-}
-
-void InstStrategySimplex::debugPrint( const char* c ){
- const ArithVarNodeMap& avnm = d_th->d_arithvarNodeMap;
- ArithVarNodeMap::var_iterator vi, vend;
- for(vi = avnm.var_begin(), vend = avnm.var_end(); vi != vend; ++vi ){
- ArithVar x = *vi;
- Node n = avnm.asNode(x);
- //if( ((TheoryArith*)getTheory())->d_partialModel.hasEitherBound( x ) ){
- Debug(c) << x << " : " << n << ", bounds = ";
- if( d_th->d_partialModel.hasLowerBound( x ) ){
- Debug(c) << d_th->d_partialModel.getLowerBound( x );
- }else{
- Debug(c) << "-infty";
- }
- Debug(c) << " <= ";
- Debug(c) << d_th->d_partialModel.getAssignment( x );
- Debug(c) << " <= ";
- if( d_th->d_partialModel.hasUpperBound( x ) ){
- Debug(c) << d_th->d_partialModel.getUpperBound( x );
- }else{
- Debug(c) << "+infty";
- }
- Debug(c) << std::endl;
- //Debug(c) << " Term = " << d_tableaux_term[x] << std::endl;
- //Debug(c) << " ";
- //for( std::map< Node, Node >::iterator it2 = d_tableaux[x].begin(); it2 != d_tableaux[x].end(); ++it2 ){
- // Debug(c) << "( " << it2->first << ", " << it2->second << " ) ";
- //}
- //for( std::map< Node, Node >::iterator it2 = d_ceTableaux[x].begin(); it2 != d_ceTableaux[x].end(); ++it2 ){
- // Debug(c) << "(CE)( " << it2->first << ", " << it2->second << " ) ";
- //}
- //for( std::map< Node, Node >::iterator it2 = d_tableaux_ce_term[x].begin(); it2 != d_tableaux_ce_term[x].end(); ++it2 ){
- // Debug(c) << "(CE-term)( " << it2->first << ", " << it2->second << " ) ";
- //}
- //Debug(c) << std::endl;
- //}
- }
- Debug(c) << std::endl;
-
- for( int q=0; q<d_quantEngine->getNumQuantifiers(); q++ ){
- Node f = d_quantEngine->getQuantifier( q );
- Debug(c) << f << std::endl;
- Debug(c) << " Inst constants: ";
- for( int i=0; i<(int)d_quantEngine->getTermDatabase()->getNumInstantiationConstants( f ); i++ ){
- if( i>0 ){
- Debug( c ) << ", ";
- }
- Debug( c ) << d_quantEngine->getTermDatabase()->getInstantiationConstant( f, i );
- }
- Debug(c) << std::endl;
- Debug(c) << " Instantiation rows: ";
- for( int i=0; i<(int)d_instRows[f].size(); i++ ){
- if( i>0 ){
- Debug(c) << ", ";
- }
- Debug(c) << d_instRows[f][i];
- }
- Debug(c) << std::endl;
- }
-}
-
-//say instantiation row x for quantifier f is coeff*var + A*t[e] + term = beta,
-// where var is an instantiation constant from f,
-// t[e] is a vector of terms containing instantiation constants from f,
-// and term is a ground term (c1*t1 + ... + cn*tn).
-// We construct the term ( beta - term )/coeff to use as an instantiation for var.
-bool InstStrategySimplex::doInstantiation( Node f, Node term, ArithVar x, InstMatch& m, Node var ){
- //first try +delta
- if( doInstantiation2( f, term, x, m, var ) ){
- ++(d_quantEngine->getInstantiationEngine()->d_statistics.d_instantiations_cbqi_arith);
- return true;
- }else{
-#ifdef ARITH_INSTANTIATOR_USE_MINUS_DELTA
- //otherwise try -delta
- if( doInstantiation2( f, term, x, m, var, true ) ){
- ++(d_quantEngine->getInstantiationEngine()->d_statistics.d_instantiations_cbqi_arith_minus);
- return true;
- }else{
- return false;
- }
-#else
- return false;
-#endif
- }
-}
-
-bool InstStrategySimplex::doInstantiation2( Node f, Node term, ArithVar x, InstMatch& m, Node var, bool minus_delta ){
- // make term ( beta - term )/coeff
- Node beta = getTableauxValue( x, minus_delta );
- Node instVal = NodeManager::currentNM()->mkNode( MINUS, beta, term );
- if( !d_ceTableaux[x][var].isNull() ){
- if( var.getType().isInteger() ){
- Assert( d_ceTableaux[x][var]==NodeManager::currentNM()->mkConst( Rational(-1) ) );
- instVal = NodeManager::currentNM()->mkNode( MULT, d_ceTableaux[x][var], instVal );
- }else{
- Node coeff = NodeManager::currentNM()->mkConst( Rational(1) / d_ceTableaux[x][var].getConst<Rational>() );
- instVal = NodeManager::currentNM()->mkNode( MULT, coeff, instVal );
- }
- }
- instVal = Rewriter::rewrite( instVal );
- //use as instantiation value for var
- m.set(var, instVal);
- Debug("quant-arith") << "Add instantiation " << m << std::endl;
- return d_quantEngine->addInstantiation( f, m );
-}
-
-Node InstStrategySimplex::getTableauxValue( Node n, bool minus_delta ){
- if( d_th->d_arithvarNodeMap.hasArithVar(n) ){
- ArithVar v = d_th->d_arithvarNodeMap.asArithVar( n );
- return getTableauxValue( v, minus_delta );
- }else{
- return NodeManager::currentNM()->mkConst( Rational(0) );
- }
-}
-
-Node InstStrategySimplex::getTableauxValue( ArithVar v, bool minus_delta ){
- const Rational& delta = d_th->d_partialModel.getDelta();
- DeltaRational drv = d_th->d_partialModel.getAssignment( v );
- Rational qmodel = drv.substituteDelta( minus_delta ? -delta : delta );
- return mkRationalNode(qmodel);
-}
-
-
-InstStrategyDatatypesValue::InstStrategyDatatypesValue( TheoryDatatypes* th, QuantifiersEngine* qe ) :
- InstStrategy( qe ), d_th( th ){
-
-}
-
-bool InstStrategyDatatypesValue::calculateShouldProcess( Node f ){
- //DO_THIS
- return false;
-}
-
-void InstStrategyDatatypesValue::processResetInstantiationRound( Theory::Effort effort ){
-
-}
-
-int InstStrategyDatatypesValue::process( Node f, Theory::Effort effort, int e ){
- Debug("quant-datatypes") << "Datatypes: Try to solve (" << e << ") for " << f << "... " << std::endl;
- if( e<2 ){
- return InstStrategy::STATUS_UNFINISHED;
- }else if( e==2 ){
- InstMatch m;
- for( int j = 0; j<(int)d_quantEngine->getTermDatabase()->getNumInstantiationConstants( f ); j++ ){
- Node i = d_quantEngine->getTermDatabase()->getInstantiationConstant( f, j );
- if( i.getType().isDatatype() ){
- Node n = getValueFor( i );
- Debug("quant-datatypes-debug") << "Value for " << i << " is " << n << std::endl;
- m.set(i,n);
- }
- }
- //d_quantEngine->addInstantiation( f, m );
- }
- return InstStrategy::STATUS_UNKNOWN;
-}
-
-Node InstStrategyDatatypesValue::getValueFor( Node n ){
- //simply get the ground value for n in the current model, if it exists,
- // or return an arbitrary ground term otherwise
- if( !n.hasAttribute(InstConstantAttribute()) ){
- return n;
- }else{
- return n;
- }
- /* FIXME
-
- Debug("quant-datatypes-debug") << "get value for " << n << std::endl;
- if( !n.hasAttribute(InstConstantAttribute()) ){
- return n;
- }else{
- Assert( n.getType().isDatatype() );
- //check if in equivalence class with ground term
- Node rep = getRepresentative( n );
- Debug("quant-datatypes-debug") << "Rep is " << rep << std::endl;
- if( !rep.hasAttribute(InstConstantAttribute()) ){
- return rep;
- }else{
- if( !n.getType().isDatatype() ){
- return n.getType().mkGroundTerm();
- }else{
- if( n.getKind()==APPLY_CONSTRUCTOR ){
- std::vector< Node > children;
- children.push_back( n.getOperator() );
- for( int i=0; i<(int)n.getNumChildren(); i++ ){
- children.push_back( getValueFor( n[i] ) );
- }
- return NodeManager::currentNM()->mkNode( APPLY_CONSTRUCTOR, children );
- }else{
- const Datatype& dt = ((DatatypeType)(n.getType()).toType()).getDatatype();
- TheoryDatatypes::EqLists* labels = &((TheoryDatatypes*)d_th)->d_labels;
- //otherwise, use which constructor the inst constant is current chosen to be
- if( labels->find( n )!=labels->end() ){
- TheoryDatatypes::EqList* lbl = (*labels->find( n )).second;
- int tIndex = -1;
- if( !lbl->empty() && (*lbl)[ lbl->size()-1 ].getKind()==APPLY_TESTER ){
- Debug("quant-datatypes-debug") << n << " tester is " << (*lbl)[ lbl->size()-1 ] << std::endl;
- tIndex = Datatype::indexOf((*lbl)[ lbl->size()-1 ].getOperator().toExpr());
- }else{
- Debug("quant-datatypes-debug") << "find possible tester choice" << std::endl;
- //must find a possible choice
- vector< bool > possibleCons;
- possibleCons.resize( dt.getNumConstructors(), true );
- for( TheoryDatatypes::EqList::const_iterator j = lbl->begin(); j != lbl->end(); j++ ) {
- Node leqn = (*j);
- possibleCons[ Datatype::indexOf( leqn[0].getOperator().toExpr() ) ] = false;
- }
- for( unsigned int j=0; j<possibleCons.size(); j++ ) {
- if( possibleCons[j] ){
- tIndex = j;
- break;
- }
- }
- }
- Assert( tIndex!=-1 );
- Node cons = Node::fromExpr( dt[ tIndex ].getConstructor() );
- Debug("quant-datatypes-debug") << n << " cons is " << cons << std::endl;
- std::vector< Node > children;
- children.push_back( cons );
- for( int i=0; i<(int)dt[ tIndex ].getNumArgs(); i++ ) {
- Node sn = NodeManager::currentNM()->mkNode( APPLY_SELECTOR, Node::fromExpr( dt[tIndex][i].getSelector() ), n );
- if( n.hasAttribute(InstConstantAttribute()) ){
- InstConstantAttribute ica;
- sn.setAttribute(ica,n.getAttribute(InstConstantAttribute()) );
- }
- Node snn = getValueFor( sn );
- children.push_back( snn );
- }
- return NodeManager::currentNM()->mkNode( APPLY_CONSTRUCTOR, children );
- }else{
- return n.getType().mkGroundTerm();
- }
- }
- }
- }
- }
- */
-}
+/********************* */ +/*! \file inst_strategy_cbqi.cpp + ** \verbatim + ** Original author: Andrew Reynolds <andrew.j.reynolds@gmail.com> + ** Major contributors: Morgan Deters <mdeters@cs.nyu.edu> + ** Minor contributors (to current version): none + ** This file is part of the CVC4 project. + ** Copyright (c) 2009-2013 New York University and The University of Iowa + ** See the file COPYING in the top-level source directory for licensing + ** information.\endverbatim + ** + ** \brief Implementation of cbqi instantiation strategies + **/ + +#include "theory/quantifiers/inst_strategy_cbqi.h" +#include "theory/arith/theory_arith.h" +#include "theory/theory_engine.h" +#include "theory/quantifiers/options.h" +#include "theory/quantifiers/term_database.h" + +using namespace std; +using namespace CVC4; +using namespace CVC4::kind; +using namespace CVC4::context; +using namespace CVC4::theory; +using namespace CVC4::theory::quantifiers; +using namespace CVC4::theory::arith; +using namespace CVC4::theory::datatypes; + +#define ARITH_INSTANTIATOR_USE_MINUS_DELTA + +InstStrategySimplex::InstStrategySimplex( TheoryArith* th, QuantifiersEngine* ie ) : + InstStrategy( ie ), d_th( th ), d_counter( 0 ){ + d_negOne = NodeManager::currentNM()->mkConst( Rational(-1) ); +} + +bool InstStrategySimplex::calculateShouldProcess( Node f ){ + //DO_THIS + return false; +} + +void InstStrategySimplex::processResetInstantiationRound( Theory::Effort effort ){ + Debug("quant-arith") << "Setting up simplex for instantiator... " << std::endl; + d_instRows.clear(); + d_tableaux_term.clear(); + d_tableaux.clear(); + d_ceTableaux.clear(); + //search for instantiation rows in simplex tableaux + ArithVarNodeMap& avnm = d_th->d_arithvarNodeMap; + ArithVarNodeMap::var_iterator vi, vend; + for(vi = avnm.var_begin(), vend = avnm.var_end(); vi != vend; ++vi ){ + ArithVar x = *vi; + if( d_th->d_partialModel.hasEitherBound( x ) ){ + Node n = avnm.asNode(x); + Node f; + NodeBuilder<> t(kind::PLUS); + if( n.getKind()==PLUS ){ + for( int i=0; i<(int)n.getNumChildren(); i++ ){ + addTermToRow( x, n[i], f, t ); + } + }else{ + addTermToRow( x, n, f, t ); + } + if( f!=Node::null() ){ + d_instRows[f].push_back( x ); + //this theory has constraints from f + Debug("quant-arith") << "Has constraints from " << f << std::endl; + //set that we should process it + d_quantActive[ f ] = true; + //set tableaux term + if( t.getNumChildren()==0 ){ + d_tableaux_term[x] = NodeManager::currentNM()->mkConst( Rational(0) ); + }else if( t.getNumChildren()==1 ){ + d_tableaux_term[x] = t.getChild( 0 ); + }else{ + d_tableaux_term[x] = t; + } + } + } + } + //print debug + debugPrint( "quant-arith-debug" ); + d_counter++; +} + +int InstStrategySimplex::process( Node f, Theory::Effort effort, int e ){ + if( e<2 ){ + return STATUS_UNFINISHED; + }else if( e==2 ){ + //Notice() << f << std::endl; + //Notice() << "Num inst rows = " << d_th->d_instRows[f].size() << std::endl; + //Notice() << "Num inst constants = " << d_quantEngine->getNumInstantiationConstants( f ) << std::endl; + Debug("quant-arith-simplex") << "InstStrategySimplex check " << f << ", rows = " << d_instRows[f].size() << std::endl; + for( int j=0; j<(int)d_instRows[f].size(); j++ ){ + ArithVar x = d_instRows[f][j]; + if( !d_ceTableaux[x].empty() ){ + Debug("quant-arith-simplex") << "Check row " << x << std::endl; + //instantiation row will be A*e + B*t = beta, + // where e is a vector of terms , and t is vector of ground terms. + // Say one term in A*e is coeff*e_i, where e_i is an instantiation constant + // We will construct the term ( beta - B*t)/coeff to use for e_i. + InstMatch m; + //By default, choose the first instantiation constant to be e_i. + Node var = d_ceTableaux[x].begin()->first; + if( var.getType().isInteger() ){ + std::map< Node, Node >::iterator it = d_ceTableaux[x].begin(); + //try to find coefficent that is +/- 1 + while( !var.isNull() && !d_ceTableaux[x][var].isNull() && d_ceTableaux[x][var]!=d_negOne ){ + ++it; + if( it==d_ceTableaux[x].end() ){ + var = Node::null(); + }else{ + var = it->first; + } + } + //otherwise, try one that divides all ground term coefficients? DO_THIS + } + if( !var.isNull() ){ + Debug("quant-arith-simplex") << "Instantiate with var " << var << std::endl; + doInstantiation( f, d_tableaux_term[x], x, m, var ); + }else{ + Debug("quant-arith-simplex") << "Could not find var." << std::endl; + } + ////choose a new variable based on alternation strategy + //int index = d_counter%(int)d_th->d_ceTableaux[x].size(); + //Node var; + //for( std::map< Node, Node >::iterator it = d_th->d_ceTableaux[x].begin(); it != d_th->d_ceTableaux[x].end(); ++it ){ + // if( index==0 ){ + // var = it->first; + // break; + // } + // index--; + //} + //d_th->doInstantiation( f, d_th->d_tableaux_term[x], x, &m, var ); + } + } + } + return STATUS_UNKNOWN; +} + + +void InstStrategySimplex::addTermToRow( ArithVar x, Node n, Node& f, NodeBuilder<>& t ){ + if( n.getKind()==MULT ){ + if( n[1].hasAttribute(InstConstantAttribute()) ){ + f = n[1].getAttribute(InstConstantAttribute()); + if( n[1].getKind()==INST_CONSTANT ){ + d_ceTableaux[x][ n[1] ] = n[0]; + }else{ + d_tableaux_ce_term[x][ n[1] ] = n[0]; + } + }else{ + d_tableaux[x][ n[1] ] = n[0]; + t << n; + } + }else{ + if( n.hasAttribute(InstConstantAttribute()) ){ + f = n.getAttribute(InstConstantAttribute()); + if( n.getKind()==INST_CONSTANT ){ + d_ceTableaux[x][ n ] = Node::null(); + }else{ + d_tableaux_ce_term[x][ n ] = NodeManager::currentNM()->mkConst( Rational(1) ); + } + }else{ + d_tableaux[x][ n ] = NodeManager::currentNM()->mkConst( Rational(1) ); + t << n; + } + } +} + +void InstStrategySimplex::debugPrint( const char* c ){ + const ArithVarNodeMap& avnm = d_th->d_arithvarNodeMap; + ArithVarNodeMap::var_iterator vi, vend; + for(vi = avnm.var_begin(), vend = avnm.var_end(); vi != vend; ++vi ){ + ArithVar x = *vi; + Node n = avnm.asNode(x); + //if( ((TheoryArith*)getTheory())->d_partialModel.hasEitherBound( x ) ){ + Debug(c) << x << " : " << n << ", bounds = "; + if( d_th->d_partialModel.hasLowerBound( x ) ){ + Debug(c) << d_th->d_partialModel.getLowerBound( x ); + }else{ + Debug(c) << "-infty"; + } + Debug(c) << " <= "; + Debug(c) << d_th->d_partialModel.getAssignment( x ); + Debug(c) << " <= "; + if( d_th->d_partialModel.hasUpperBound( x ) ){ + Debug(c) << d_th->d_partialModel.getUpperBound( x ); + }else{ + Debug(c) << "+infty"; + } + Debug(c) << std::endl; + //Debug(c) << " Term = " << d_tableaux_term[x] << std::endl; + //Debug(c) << " "; + //for( std::map< Node, Node >::iterator it2 = d_tableaux[x].begin(); it2 != d_tableaux[x].end(); ++it2 ){ + // Debug(c) << "( " << it2->first << ", " << it2->second << " ) "; + //} + //for( std::map< Node, Node >::iterator it2 = d_ceTableaux[x].begin(); it2 != d_ceTableaux[x].end(); ++it2 ){ + // Debug(c) << "(CE)( " << it2->first << ", " << it2->second << " ) "; + //} + //for( std::map< Node, Node >::iterator it2 = d_tableaux_ce_term[x].begin(); it2 != d_tableaux_ce_term[x].end(); ++it2 ){ + // Debug(c) << "(CE-term)( " << it2->first << ", " << it2->second << " ) "; + //} + //Debug(c) << std::endl; + //} + } + Debug(c) << std::endl; + + for( int q=0; q<d_quantEngine->getNumQuantifiers(); q++ ){ + Node f = d_quantEngine->getQuantifier( q ); + Debug(c) << f << std::endl; + Debug(c) << " Inst constants: "; + for( int i=0; i<(int)d_quantEngine->getTermDatabase()->getNumInstantiationConstants( f ); i++ ){ + if( i>0 ){ + Debug( c ) << ", "; + } + Debug( c ) << d_quantEngine->getTermDatabase()->getInstantiationConstant( f, i ); + } + Debug(c) << std::endl; + Debug(c) << " Instantiation rows: "; + for( int i=0; i<(int)d_instRows[f].size(); i++ ){ + if( i>0 ){ + Debug(c) << ", "; + } + Debug(c) << d_instRows[f][i]; + } + Debug(c) << std::endl; + } +} + +//say instantiation row x for quantifier f is coeff*var + A*t[e] + term = beta, +// where var is an instantiation constant from f, +// t[e] is a vector of terms containing instantiation constants from f, +// and term is a ground term (c1*t1 + ... + cn*tn). +// We construct the term ( beta - term )/coeff to use as an instantiation for var. +bool InstStrategySimplex::doInstantiation( Node f, Node term, ArithVar x, InstMatch& m, Node var ){ + //first try +delta + if( doInstantiation2( f, term, x, m, var ) ){ + ++(d_quantEngine->getInstantiationEngine()->d_statistics.d_instantiations_cbqi_arith); + return true; + }else{ +#ifdef ARITH_INSTANTIATOR_USE_MINUS_DELTA + //otherwise try -delta + if( doInstantiation2( f, term, x, m, var, true ) ){ + ++(d_quantEngine->getInstantiationEngine()->d_statistics.d_instantiations_cbqi_arith_minus); + return true; + }else{ + return false; + } +#else + return false; +#endif + } +} + +bool InstStrategySimplex::doInstantiation2( Node f, Node term, ArithVar x, InstMatch& m, Node var, bool minus_delta ){ + // make term ( beta - term )/coeff + Node beta = getTableauxValue( x, minus_delta ); + Node instVal = NodeManager::currentNM()->mkNode( MINUS, beta, term ); + if( !d_ceTableaux[x][var].isNull() ){ + if( var.getType().isInteger() ){ + Assert( d_ceTableaux[x][var]==NodeManager::currentNM()->mkConst( Rational(-1) ) ); + instVal = NodeManager::currentNM()->mkNode( MULT, d_ceTableaux[x][var], instVal ); + }else{ + Node coeff = NodeManager::currentNM()->mkConst( Rational(1) / d_ceTableaux[x][var].getConst<Rational>() ); + instVal = NodeManager::currentNM()->mkNode( MULT, coeff, instVal ); + } + } + instVal = Rewriter::rewrite( instVal ); + //use as instantiation value for var + m.set(var, instVal); + Debug("quant-arith") << "Add instantiation " << m << std::endl; + return d_quantEngine->addInstantiation( f, m ); +} + +Node InstStrategySimplex::getTableauxValue( Node n, bool minus_delta ){ + if( d_th->d_arithvarNodeMap.hasArithVar(n) ){ + ArithVar v = d_th->d_arithvarNodeMap.asArithVar( n ); + return getTableauxValue( v, minus_delta ); + }else{ + return NodeManager::currentNM()->mkConst( Rational(0) ); + } +} + +Node InstStrategySimplex::getTableauxValue( ArithVar v, bool minus_delta ){ + const Rational& delta = d_th->d_partialModel.getDelta(); + DeltaRational drv = d_th->d_partialModel.getAssignment( v ); + Rational qmodel = drv.substituteDelta( minus_delta ? -delta : delta ); + return mkRationalNode(qmodel); +} + + +InstStrategyDatatypesValue::InstStrategyDatatypesValue( TheoryDatatypes* th, QuantifiersEngine* qe ) : + InstStrategy( qe ), d_th( th ){ + +} + +bool InstStrategyDatatypesValue::calculateShouldProcess( Node f ){ + //DO_THIS + return false; +} + +void InstStrategyDatatypesValue::processResetInstantiationRound( Theory::Effort effort ){ + +} + +int InstStrategyDatatypesValue::process( Node f, Theory::Effort effort, int e ){ + Debug("quant-datatypes") << "Datatypes: Try to solve (" << e << ") for " << f << "... " << std::endl; + if( e<2 ){ + return InstStrategy::STATUS_UNFINISHED; + }else if( e==2 ){ + InstMatch m; + for( int j = 0; j<(int)d_quantEngine->getTermDatabase()->getNumInstantiationConstants( f ); j++ ){ + Node i = d_quantEngine->getTermDatabase()->getInstantiationConstant( f, j ); + if( i.getType().isDatatype() ){ + Node n = getValueFor( i ); + Debug("quant-datatypes-debug") << "Value for " << i << " is " << n << std::endl; + m.set(i,n); + } + } + //d_quantEngine->addInstantiation( f, m ); + } + return InstStrategy::STATUS_UNKNOWN; +} + +Node InstStrategyDatatypesValue::getValueFor( Node n ){ + //simply get the ground value for n in the current model, if it exists, + // or return an arbitrary ground term otherwise + if( !n.hasAttribute(InstConstantAttribute()) ){ + return n; + }else{ + return n; + } + /* FIXME + + Debug("quant-datatypes-debug") << "get value for " << n << std::endl; + if( !n.hasAttribute(InstConstantAttribute()) ){ + return n; + }else{ + Assert( n.getType().isDatatype() ); + //check if in equivalence class with ground term + Node rep = getRepresentative( n ); + Debug("quant-datatypes-debug") << "Rep is " << rep << std::endl; + if( !rep.hasAttribute(InstConstantAttribute()) ){ + return rep; + }else{ + if( !n.getType().isDatatype() ){ + return n.getType().mkGroundTerm(); + }else{ + if( n.getKind()==APPLY_CONSTRUCTOR ){ + std::vector< Node > children; + children.push_back( n.getOperator() ); + for( int i=0; i<(int)n.getNumChildren(); i++ ){ + children.push_back( getValueFor( n[i] ) ); + } + return NodeManager::currentNM()->mkNode( APPLY_CONSTRUCTOR, children ); + }else{ + const Datatype& dt = ((DatatypeType)(n.getType()).toType()).getDatatype(); + TheoryDatatypes::EqLists* labels = &((TheoryDatatypes*)d_th)->d_labels; + //otherwise, use which constructor the inst constant is current chosen to be + if( labels->find( n )!=labels->end() ){ + TheoryDatatypes::EqList* lbl = (*labels->find( n )).second; + int tIndex = -1; + if( !lbl->empty() && (*lbl)[ lbl->size()-1 ].getKind()==APPLY_TESTER ){ + Debug("quant-datatypes-debug") << n << " tester is " << (*lbl)[ lbl->size()-1 ] << std::endl; + tIndex = Datatype::indexOf((*lbl)[ lbl->size()-1 ].getOperator().toExpr()); + }else{ + Debug("quant-datatypes-debug") << "find possible tester choice" << std::endl; + //must find a possible choice + vector< bool > possibleCons; + possibleCons.resize( dt.getNumConstructors(), true ); + for( TheoryDatatypes::EqList::const_iterator j = lbl->begin(); j != lbl->end(); j++ ) { + Node leqn = (*j); + possibleCons[ Datatype::indexOf( leqn[0].getOperator().toExpr() ) ] = false; + } + for( unsigned int j=0; j<possibleCons.size(); j++ ) { + if( possibleCons[j] ){ + tIndex = j; + break; + } + } + } + Assert( tIndex!=-1 ); + Node cons = Node::fromExpr( dt[ tIndex ].getConstructor() ); + Debug("quant-datatypes-debug") << n << " cons is " << cons << std::endl; + std::vector< Node > children; + children.push_back( cons ); + for( int i=0; i<(int)dt[ tIndex ].getNumArgs(); i++ ) { + Node sn = NodeManager::currentNM()->mkNode( APPLY_SELECTOR, Node::fromExpr( dt[tIndex][i].getSelector() ), n ); + if( n.hasAttribute(InstConstantAttribute()) ){ + InstConstantAttribute ica; + sn.setAttribute(ica,n.getAttribute(InstConstantAttribute()) ); + } + Node snn = getValueFor( sn ); + children.push_back( snn ); + } + return NodeManager::currentNM()->mkNode( APPLY_CONSTRUCTOR, children ); + }else{ + return n.getType().mkGroundTerm(); + } + } + } + } + } + */ +} diff --git a/src/theory/quantifiers/inst_strategy_cbqi.h b/src/theory/quantifiers/inst_strategy_cbqi.h index 3ee423fe7..de548ab14 100755..100644 --- a/src/theory/quantifiers/inst_strategy_cbqi.h +++ b/src/theory/quantifiers/inst_strategy_cbqi.h @@ -1,110 +1,110 @@ -/********************* */
-/*! \file inst_strategy_cbqi.h
- ** \verbatim
- ** Original author: ajreynol
- ** Major contributors: none
- ** Minor contributors (to current version): mdeters
- ** This file is part of the CVC4 prototype.
- ** Copyright (c) 2009-2012 New York University and The University of Iowa
- ** See the file COPYING in the top-level source directory for licensing
- ** information.\endverbatim
- **
- ** \brief instantiator_arith_instantiator
- **/
-
-
-#include "cvc4_private.h"
-
-#ifndef __CVC4__INST_STRATEGT_CBQI_H
-#define __CVC4__INST_STRATEGT_CBQI_H
-
-#include "theory/quantifiers/instantiation_engine.h"
-#include "theory/arith/arithvar_node_map.h"
-
-#include "util/statistics_registry.h"
-
-namespace CVC4 {
-namespace theory {
-
-namespace arith {
- class TheoryArith;
-}
-
-namespace datatypes {
- class TheoryDatatypes;
-}
-
-namespace quantifiers {
-
-
-class InstStrategySimplex : public InstStrategy{
-protected:
- /** calculate if we should process this quantifier */
- bool calculateShouldProcess( Node f );
-private:
- /** reference to theory arithmetic */
- arith::TheoryArith* d_th;
- /** delta */
- std::map< TypeNode, Node > d_deltas;
- /** for each quantifier, simplex rows */
- std::map< Node, std::vector< arith::ArithVar > > d_instRows;
- /** tableaux */
- std::map< arith::ArithVar, Node > d_tableaux_term;
- std::map< arith::ArithVar, std::map< Node, Node > > d_tableaux_ce_term;
- std::map< arith::ArithVar, std::map< Node, Node > > d_tableaux;
- /** ce tableaux */
- std::map< arith::ArithVar, std::map< Node, Node > > d_ceTableaux;
- /** get value */
- Node getTableauxValue( Node n, bool minus_delta = false );
- Node getTableauxValue( arith::ArithVar v, bool minus_delta = false );
- /** do instantiation */
- bool doInstantiation( Node f, Node term, arith::ArithVar x, InstMatch& m, Node var );
- bool doInstantiation2( Node f, Node term, arith::ArithVar x, InstMatch& m, Node var, bool minus_delta = false );
- /** add term to row */
- void addTermToRow( arith::ArithVar x, Node n, Node& f, NodeBuilder<>& t );
- /** print debug */
- void debugPrint( const char* c );
-private:
- /** */
- int d_counter;
- /** negative one */
- Node d_negOne;
- /** process functions */
- void processResetInstantiationRound( Theory::Effort effort );
- int process( Node f, Theory::Effort effort, int e );
-public:
- InstStrategySimplex( arith::TheoryArith* th, QuantifiersEngine* ie );
- ~InstStrategySimplex(){}
- /** identify */
- std::string identify() const { return std::string("Simplex"); }
-};
-
-
-class InstStrategyDatatypesValue : public InstStrategy
-{
-protected:
- /** calculate if we should process this quantifier */
- bool calculateShouldProcess( Node f );
-private:
- /** reference to theory datatypes */
- datatypes::TheoryDatatypes* d_th;
- /** get value function */
- Node getValueFor( Node n );
-public:
- //constructor
- InstStrategyDatatypesValue( datatypes::TheoryDatatypes* th, QuantifiersEngine* qe );
- ~InstStrategyDatatypesValue(){}
- /** reset instantiation */
- void processResetInstantiationRound( Theory::Effort effort );
- /** process method, returns a status */
- int process( Node f, Theory::Effort effort, int e );
- /** identify */
- std::string identify() const { return std::string("InstStrategyDatatypesValue"); }
-
-};/* class InstStrategy */
-
-}
-}
-}
-
+/********************* */ +/*! \file inst_strategy_cbqi.h + ** \verbatim + ** Original author: Andrew Reynolds <andrew.j.reynolds@gmail.com> + ** Major contributors: Morgan Deters <mdeters@cs.nyu.edu> + ** Minor contributors (to current version): none + ** This file is part of the CVC4 project. + ** Copyright (c) 2009-2013 New York University and The University of Iowa + ** See the file COPYING in the top-level source directory for licensing + ** information.\endverbatim + ** + ** \brief instantiator_arith_instantiator + **/ + + +#include "cvc4_private.h" + +#ifndef __CVC4__INST_STRATEGT_CBQI_H +#define __CVC4__INST_STRATEGT_CBQI_H + +#include "theory/quantifiers/instantiation_engine.h" +#include "theory/arith/arithvar_node_map.h" + +#include "util/statistics_registry.h" + +namespace CVC4 { +namespace theory { + +namespace arith { + class TheoryArith; +} + +namespace datatypes { + class TheoryDatatypes; +} + +namespace quantifiers { + + +class InstStrategySimplex : public InstStrategy{ +protected: + /** calculate if we should process this quantifier */ + bool calculateShouldProcess( Node f ); +private: + /** reference to theory arithmetic */ + arith::TheoryArith* d_th; + /** delta */ + std::map< TypeNode, Node > d_deltas; + /** for each quantifier, simplex rows */ + std::map< Node, std::vector< arith::ArithVar > > d_instRows; + /** tableaux */ + std::map< arith::ArithVar, Node > d_tableaux_term; + std::map< arith::ArithVar, std::map< Node, Node > > d_tableaux_ce_term; + std::map< arith::ArithVar, std::map< Node, Node > > d_tableaux; + /** ce tableaux */ + std::map< arith::ArithVar, std::map< Node, Node > > d_ceTableaux; + /** get value */ + Node getTableauxValue( Node n, bool minus_delta = false ); + Node getTableauxValue( arith::ArithVar v, bool minus_delta = false ); + /** do instantiation */ + bool doInstantiation( Node f, Node term, arith::ArithVar x, InstMatch& m, Node var ); + bool doInstantiation2( Node f, Node term, arith::ArithVar x, InstMatch& m, Node var, bool minus_delta = false ); + /** add term to row */ + void addTermToRow( arith::ArithVar x, Node n, Node& f, NodeBuilder<>& t ); + /** print debug */ + void debugPrint( const char* c ); +private: + /** */ + int d_counter; + /** negative one */ + Node d_negOne; + /** process functions */ + void processResetInstantiationRound( Theory::Effort effort ); + int process( Node f, Theory::Effort effort, int e ); +public: + InstStrategySimplex( arith::TheoryArith* th, QuantifiersEngine* ie ); + ~InstStrategySimplex(){} + /** identify */ + std::string identify() const { return std::string("Simplex"); } +}; + + +class InstStrategyDatatypesValue : public InstStrategy +{ +protected: + /** calculate if we should process this quantifier */ + bool calculateShouldProcess( Node f ); +private: + /** reference to theory datatypes */ + datatypes::TheoryDatatypes* d_th; + /** get value function */ + Node getValueFor( Node n ); +public: + //constructor + InstStrategyDatatypesValue( datatypes::TheoryDatatypes* th, QuantifiersEngine* qe ); + ~InstStrategyDatatypesValue(){} + /** reset instantiation */ + void processResetInstantiationRound( Theory::Effort effort ); + /** process method, returns a status */ + int process( Node f, Theory::Effort effort, int e ); + /** identify */ + std::string identify() const { return std::string("InstStrategyDatatypesValue"); } + +};/* class InstStrategy */ + +} +} +} + #endif
\ No newline at end of file diff --git a/src/theory/quantifiers/inst_strategy_e_matching.cpp b/src/theory/quantifiers/inst_strategy_e_matching.cpp index 48af334ff..3f5cc7666 100755..100644 --- a/src/theory/quantifiers/inst_strategy_e_matching.cpp +++ b/src/theory/quantifiers/inst_strategy_e_matching.cpp @@ -1,379 +1,375 @@ -/********************* */
-/*! \file inst_strategy_e_matching.cpp
- ** \verbatim
- ** Original author: ajreynol
- ** Major contributors: mdeters
- ** Minor contributors (to current version): bobot
- ** This file is part of the CVC4 prototype.
- ** Copyright (c) 2009-2012 New York University and The University of Iowa
- ** See the file COPYING in the top-level source directory for licensing
- ** information.\endverbatim
- **
- ** \brief Implementation of e matching instantiation strategies
- **/
-
-#include "theory/quantifiers/inst_strategy_e_matching.h"
-
-#include "theory/theory_engine.h"
-#include "theory/quantifiers/options.h"
-#include "theory/quantifiers/term_database.h"
-#include "theory/quantifiers/inst_match_generator.h"
-
-using namespace std;
-using namespace CVC4;
-using namespace CVC4::kind;
-using namespace CVC4::context;
-using namespace CVC4::theory;
-using namespace CVC4::theory::inst;
-using namespace CVC4::theory::quantifiers;
-
-#define USE_SINGLE_TRIGGER_BEFORE_MULTI_TRIGGER
-//#define MULTI_TRIGGER_FULL_EFFORT_HALF
-#define MULTI_MULTI_TRIGGERS
-
-struct sortQuantifiersForSymbol {
- QuantifiersEngine* d_qe;
- bool operator() (Node i, Node j) {
- int nqfsi = d_qe->getQuantifierRelevance()->getNumQuantifiersForSymbol( i.getOperator() );
- int nqfsj = d_qe->getQuantifierRelevance()->getNumQuantifiersForSymbol( j.getOperator() );
- if( nqfsi<nqfsj ){
- return true;
- }else if( nqfsi>nqfsj ){
- return false;
- }else{
- return false;
- }
- }
-};
-
-void InstStrategyUserPatterns::processResetInstantiationRound( Theory::Effort effort ){
- //reset triggers
- for( std::map< Node, std::vector< Trigger* > >::iterator it = d_user_gen.begin(); it != d_user_gen.end(); ++it ){
- for( int i=0; i<(int)it->second.size(); i++ ){
- it->second[i]->resetInstantiationRound();
- it->second[i]->reset( Node::null() );
- }
- }
-}
-
-int InstStrategyUserPatterns::process( Node f, Theory::Effort effort, int e ){
- if( e==0 ){
- return STATUS_UNFINISHED;
- }else if( e==1 ){
- d_counter[f]++;
- Debug("quant-uf-strategy") << "Try user-provided patterns..." << std::endl;
- //Notice() << "Try user-provided patterns..." << std::endl;
- for( int i=0; i<(int)d_user_gen[f].size(); i++ ){
- bool processTrigger = true;
- if( effort!=Theory::EFFORT_LAST_CALL && d_user_gen[f][i]->isMultiTrigger() ){
-//#ifdef MULTI_TRIGGER_FULL_EFFORT_HALF
-// processTrigger = d_counter[f]%2==0;
-//#endif
- }
- if( processTrigger ){
- //if( d_user_gen[f][i]->isMultiTrigger() )
- //Notice() << " Process (user) " << (*d_user_gen[f][i]) << " for " << f << "..." << std::endl;
- InstMatch baseMatch;
- int numInst = d_user_gen[f][i]->addInstantiations( baseMatch );
- //if( d_user_gen[f][i]->isMultiTrigger() )
- //Notice() << " 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;
- }
- //d_quantEngine->d_hasInstantiated[f] = true;
- }
- }
- Debug("quant-uf-strategy") << "done." << std::endl;
- //Notice() << "done" << std::endl;
- }
- return STATUS_UNKNOWN;
-}
-
-void InstStrategyUserPatterns::addUserPattern( Node f, Node pat ){
- //add to generators
- std::vector< Node > nodes;
- for( int i=0; i<(int)pat.getNumChildren(); i++ ){
- nodes.push_back( pat[i] );
- }
- if( Trigger::isUsableTrigger( nodes, f ) ){
- //extend to literal matching
- d_quantEngine->getPhaseReqTerms( f, nodes );
- //check match option
- int matchOption = options::efficientEMatching() ? InstMatchGenerator::MATCH_GEN_EFFICIENT_E_MATCH : 0;
- d_user_gen[f].push_back( Trigger::mkTrigger( d_quantEngine, f, nodes, matchOption, true, Trigger::TR_MAKE_NEW,
- options::smartTriggers() ) );
- }
-}
-/*
-InstStrategyUserPatterns::Statistics::Statistics():
- d_instantiations("InstStrategyUserPatterns::Instantiations", 0)
-{
- StatisticsRegistry::registerStat(&d_instantiations);
-}
-
-InstStrategyUserPatterns::Statistics::~Statistics(){
- StatisticsRegistry::unregisterStat(&d_instantiations);
-}
-*/
-
-void InstStrategyAutoGenTriggers::processResetInstantiationRound( Theory::Effort effort ){
- //reset triggers
- for( std::map< Node, std::map< Trigger*, bool > >::iterator it = d_auto_gen_trigger.begin(); it != d_auto_gen_trigger.end(); ++it ){
- for( std::map< Trigger*, bool >::iterator itt = it->second.begin(); itt != it->second.end(); ++itt ){
- itt->first->resetInstantiationRound();
- itt->first->reset( Node::null() );
- }
- }
-}
-
-int InstStrategyAutoGenTriggers::process( Node f, Theory::Effort effort, int e ){
- int peffort = f.getNumChildren()==3 ? 2 : 1;
- //int peffort = f.getNumChildren()==3 ? 2 : 1;
- //int peffort = 1;
- if( e<peffort ){
- return STATUS_UNFINISHED;
- }else{
- bool gen = false;
- if( e==peffort ){
- if( d_counter.find( f )==d_counter.end() ){
- d_counter[f] = 0;
- gen = true;
- }else{
- d_counter[f]++;
- gen = d_regenerate && d_counter[f]%d_regenerate_frequency==0;
- }
- }else{
- gen = true;
- }
- if( gen ){
- generateTriggers( f );
- }
- Debug("quant-uf-strategy") << "Try auto-generated triggers... " << d_tr_strategy << " " << e << std::endl;
- //Notice() << "Try auto-generated triggers..." << std::endl;
- for( std::map< Trigger*, bool >::iterator itt = d_auto_gen_trigger[f].begin(); itt != d_auto_gen_trigger[f].end(); ++itt ){
- Trigger* tr = itt->first;
- if( tr ){
- bool processTrigger = itt->second;
- if( effort!=Theory::EFFORT_LAST_CALL && tr->isMultiTrigger() ){
-#ifdef MULTI_TRIGGER_FULL_EFFORT_HALF
- processTrigger = d_counter[f]%2==0;
-#endif
- }
- if( processTrigger ){
- //if( tr->isMultiTrigger() )
- Debug("quant-uf-strategy-auto-gen-triggers") << " Process " << (*tr) << "..." << std::endl;
- InstMatch baseMatch;
- int numInst = tr->addInstantiations( baseMatch );
- //if( tr->isMultiTrigger() )
- Debug("quant-uf-strategy-auto-gen-triggers") << " 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{
- d_quantEngine->getInstantiationEngine()->d_statistics.d_instantiations_auto_gen += numInst;
- }
- if( tr->isMultiTrigger() ){
- d_quantEngine->d_statistics.d_multi_trigger_instantiations += numInst;
- }
- //d_quantEngine->d_hasInstantiated[f] = true;
- }
- }
- }
- Debug("quant-uf-strategy") << "done." << std::endl;
- //Notice() << "done" << std::endl;
- }
- return STATUS_UNKNOWN;
-}
-
-void InstStrategyAutoGenTriggers::generateTriggers( Node f ){
- Debug("auto-gen-trigger") << "Generate trigger for " << f << std::endl;
- if( d_patTerms[0].find( f )==d_patTerms[0].end() ){
- //determine all possible pattern terms based on trigger term selection strategy d_tr_strategy
- 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 );
- Debug("auto-gen-trigger") << "Collected pat terms for " << d_quantEngine->getTermDatabase()->getInstConstantBody( f ) << std::endl;
- Debug("auto-gen-trigger") << " ";
- for( int i=0; i<(int)patTermsF.size(); i++ ){
- Debug("auto-gen-trigger") << patTermsF[i] << " ";
- }
- Debug("auto-gen-trigger") << std::endl;
- //extend to literal matching (if applicable)
- d_quantEngine->getPhaseReqTerms( f, patTermsF );
- //sort into single/multi triggers
- 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() ){
- d_patTerms[0][f].push_back( it->first );
- d_is_single_trigger[ it->first ] = true;
- }else{
- d_patTerms[1][f].push_back( it->first );
- d_is_single_trigger[ it->first ] = false;
- }
- }
- d_made_multi_trigger[f] = false;
- Debug("auto-gen-trigger") << "Single triggers for " << f << " : " << std::endl;
- Debug("auto-gen-trigger") << " ";
- for( int i=0; i<(int)d_patTerms[0][f].size(); i++ ){
- Debug("auto-gen-trigger") << d_patTerms[0][f][i] << " ";
- }
- Debug("auto-gen-trigger") << std::endl;
- Debug("auto-gen-trigger") << "Multi-trigger term pool for " << f << " : " << std::endl;
- Debug("auto-gen-trigger") << " ";
- for( int i=0; i<(int)d_patTerms[1][f].size(); i++ ){
- Debug("auto-gen-trigger") << d_patTerms[1][f][i] << " ";
- }
- Debug("auto-gen-trigger") << std::endl;
- }
-
- //populate candidate pattern term vector for the current trigger
- std::vector< Node > patTerms;
-#ifdef USE_SINGLE_TRIGGER_BEFORE_MULTI_TRIGGER
- //try to add single triggers first
- for( int i=0; i<(int)d_patTerms[0][f].size(); i++ ){
- if( !d_single_trigger_gen[d_patTerms[0][f][i]] ){
- patTerms.push_back( d_patTerms[0][f][i] );
- }
- }
- //if no single triggers exist, add multi trigger terms
- if( patTerms.empty() ){
- patTerms.insert( patTerms.begin(), d_patTerms[1][f].begin(), d_patTerms[1][f].end() );
- }
-#else
- patTerms.insert( patTerms.begin(), d_patTerms[0][f].begin(), d_patTerms[0][f].end() );
- patTerms.insert( patTerms.begin(), d_patTerms[1][f].begin(), d_patTerms[1][f].end() );
-#endif
-
- if( !patTerms.empty() ){
- Debug("auto-gen-trigger") << "Generate trigger for " << f << std::endl;
- //sort terms based on relevance
- if( d_rlv_strategy==RELEVANCE_DEFAULT ){
- sortQuantifiersForSymbol sqfs;
- sqfs.d_qe = d_quantEngine;
- //sort based on # occurrences (this will cause Trigger to select rarer symbols)
- std::sort( patTerms.begin(), patTerms.end(), sqfs );
- Debug("relevant-trigger") << "Terms based on relevance: " << std::endl;
- for( int i=0; i<(int)patTerms.size(); i++ ){
- Debug("relevant-trigger") << " " << patTerms[i] << " (";
- Debug("relevant-trigger") << d_quantEngine->getQuantifierRelevance()->getNumQuantifiersForSymbol( patTerms[i].getOperator() ) << ")" << std::endl;
- }
- //Notice() << "Terms based on relevance: " << std::endl;
- //for( int i=0; i<(int)patTerms.size(); i++ ){
- // Notice() << " " << patTerms[i] << " (";
- // Notice() << d_quantEngine->getNumQuantifiersForSymbol( patTerms[i].getOperator() ) << ")" << std::endl;
- //}
- }
- //now, generate the trigger...
- int matchOption = options::efficientEMatching() ? InstMatchGenerator::MATCH_GEN_EFFICIENT_E_MATCH : 0;
- Trigger* tr = NULL;
- if( d_is_single_trigger[ patTerms[0] ] ){
- tr = Trigger::mkTrigger( d_quantEngine, f, patTerms[0], matchOption, false, Trigger::TR_RETURN_NULL,
- options::smartTriggers() );
- d_single_trigger_gen[ patTerms[0] ] = true;
- }else{
- //if we are re-generating triggers, shuffle based on some method
- if( d_made_multi_trigger[f] ){
-#ifndef MULTI_MULTI_TRIGGERS
- return;
-#endif
- std::random_shuffle( patTerms.begin(), patTerms.end() ); //shuffle randomly
- }else{
- d_made_multi_trigger[f] = true;
- }
- //will possibly want to get an old trigger
- tr = Trigger::mkTrigger( d_quantEngine, f, patTerms, matchOption, false, Trigger::TR_GET_OLD,
- options::smartTriggers() );
- }
- if( tr ){
- if( tr->isMultiTrigger() ){
- //disable all other multi triggers
- for( std::map< Trigger*, bool >::iterator it = d_auto_gen_trigger[f].begin(); it != d_auto_gen_trigger[f].end(); ++it ){
- if( it->first->isMultiTrigger() ){
- d_auto_gen_trigger[f][ it->first ] = false;
- }
- }
- }
- //making it during an instantiation round, so must reset
- if( d_auto_gen_trigger[f].find( tr )==d_auto_gen_trigger[f].end() ){
- tr->resetInstantiationRound();
- tr->reset( Node::null() );
- }
- d_auto_gen_trigger[f][tr] = true;
- //if we are generating additional triggers...
- if( d_generate_additional && d_is_single_trigger[ patTerms[0] ] ){
- int index = 0;
- if( index<(int)patTerms.size() ){
- //Notice() << "check add additional" << std::endl;
- //check if similar patterns exist, and if so, add them additionally
- int nqfs_curr = d_quantEngine->getQuantifierRelevance()->getNumQuantifiersForSymbol( patTerms[0].getOperator() );
- index++;
- bool success = true;
- while( success && index<(int)patTerms.size() && d_is_single_trigger[ patTerms[index] ] ){
- success = false;
- if( d_quantEngine->getQuantifierRelevance()->getNumQuantifiersForSymbol( patTerms[index].getOperator() )<=nqfs_curr ){
- d_single_trigger_gen[ patTerms[index] ] = true;
- Trigger* tr2 = Trigger::mkTrigger( d_quantEngine, f, patTerms[index], matchOption, false, Trigger::TR_RETURN_NULL,
- options::smartTriggers() );
- if( tr2 ){
- //Notice() << "Add additional trigger " << patTerms[index] << std::endl;
- tr2->resetInstantiationRound();
- tr2->reset( Node::null() );
- d_auto_gen_trigger[f][tr2] = true;
- }
- success = true;
- }
- index++;
- }
- //Notice() << "done check add additional" << std::endl;
- }
- }
- }
- }
-}
-/*
-InstStrategyAutoGenTriggers::Statistics::Statistics():
- d_instantiations("InstStrategyAutoGenTriggers::Instantiations", 0),
- d_instantiations_min("InstStrategyAutoGenTriggers::Instantiations_min", 0)
-{
- StatisticsRegistry::registerStat(&d_instantiations);
- StatisticsRegistry::registerStat(&d_instantiations_min);
-}
-
-InstStrategyAutoGenTriggers::Statistics::~Statistics(){
- StatisticsRegistry::unregisterStat(&d_instantiations);
- StatisticsRegistry::unregisterStat(&d_instantiations_min);
-}
-*/
-
-void InstStrategyFreeVariable::processResetInstantiationRound( Theory::Effort effort ){
-}
-
-int InstStrategyFreeVariable::process( Node f, Theory::Effort effort, int e ){
- if( e<5 ){
- return STATUS_UNFINISHED;
- }else{
- if( d_guessed.find( f )==d_guessed.end() ){
- d_guessed[f] = true;
- Debug("quant-uf-alg") << "Add guessed instantiation" << std::endl;
- InstMatch m;
- if( d_quantEngine->addInstantiation( f, m ) ){
- ++(d_quantEngine->getInstantiationEngine()->d_statistics.d_instantiations_guess);
- //d_quantEngine->d_hasInstantiated[f] = true;
- }
- }
- return STATUS_UNKNOWN;
- }
-}
-/*
-InstStrategyFreeVariable::Statistics::Statistics():
- d_instantiations("InstStrategyGuess::Instantiations", 0)
-{
- StatisticsRegistry::registerStat(&d_instantiations);
-}
-
-InstStrategyFreeVariable::Statistics::~Statistics(){
- StatisticsRegistry::unregisterStat(&d_instantiations);
-}
-*/
+/********************* */ +/*! \file inst_strategy_e_matching.cpp + ** \verbatim + ** Original author: Andrew Reynolds <andrew.j.reynolds@gmail.com> + ** Major contributors: Morgan Deters <mdeters@cs.nyu.edu> + ** Minor contributors (to current version): none + ** This file is part of the CVC4 project. + ** Copyright (c) 2009-2013 New York University and The University of Iowa + ** See the file COPYING in the top-level source directory for licensing + ** information.\endverbatim + ** + ** \brief Implementation of e matching instantiation strategies + **/ + +#include "theory/quantifiers/inst_strategy_e_matching.h" + +#include "theory/theory_engine.h" +#include "theory/quantifiers/options.h" +#include "theory/quantifiers/term_database.h" +#include "theory/quantifiers/inst_match_generator.h" + +using namespace std; +using namespace CVC4; +using namespace CVC4::kind; +using namespace CVC4::context; +using namespace CVC4::theory; +using namespace CVC4::theory::inst; +using namespace CVC4::theory::quantifiers; + +//#define MULTI_TRIGGER_FULL_EFFORT_HALF +#define MULTI_MULTI_TRIGGERS + +struct sortQuantifiersForSymbol { + QuantifiersEngine* d_qe; + bool operator() (Node i, Node j) { + int nqfsi = d_qe->getQuantifierRelevance()->getNumQuantifiersForSymbol( i.getOperator() ); + int nqfsj = d_qe->getQuantifierRelevance()->getNumQuantifiersForSymbol( j.getOperator() ); + if( nqfsi<nqfsj ){ + return true; + }else if( nqfsi>nqfsj ){ + return false; + }else{ + return false; + } + } +}; + +void InstStrategyUserPatterns::processResetInstantiationRound( Theory::Effort effort ){ + //reset triggers + for( std::map< Node, std::vector< Trigger* > >::iterator it = d_user_gen.begin(); it != d_user_gen.end(); ++it ){ + for( int i=0; i<(int)it->second.size(); i++ ){ + it->second[i]->resetInstantiationRound(); + it->second[i]->reset( Node::null() ); + } + } +} + +int InstStrategyUserPatterns::process( Node f, Theory::Effort effort, int e ){ + if( e==0 ){ + return STATUS_UNFINISHED; + }else if( e==1 ){ + d_counter[f]++; + Debug("quant-uf-strategy") << "Try user-provided patterns..." << std::endl; + //Notice() << "Try user-provided patterns..." << std::endl; + 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; + InstMatch baseMatch; + int numInst = d_user_gen[f][i]->addInstantiations( baseMatch ); + //if( d_user_gen[f][i]->isMultiTrigger() ) + 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; + } + //d_quantEngine->d_hasInstantiated[f] = true; + } + } + Debug("quant-uf-strategy") << "done." << std::endl; + //Notice() << "done" << std::endl; + } + return STATUS_UNKNOWN; +} + +void InstStrategyUserPatterns::addUserPattern( Node f, Node pat ){ + //add to generators + std::vector< Node > nodes; + for( int i=0; i<(int)pat.getNumChildren(); i++ ){ + nodes.push_back( pat[i] ); + } + if( Trigger::isUsableTrigger( nodes, f ) ){ + //extend to literal matching + d_quantEngine->getPhaseReqTerms( f, nodes ); + //check match option + int matchOption = options::efficientEMatching() ? InstMatchGenerator::MATCH_GEN_EFFICIENT_E_MATCH : 0; + d_user_gen[f].push_back( Trigger::mkTrigger( d_quantEngine, f, nodes, matchOption, true, Trigger::TR_MAKE_NEW, + options::smartTriggers() ) ); + } +} +/* +InstStrategyUserPatterns::Statistics::Statistics(): + d_instantiations("InstStrategyUserPatterns::Instantiations", 0) +{ + StatisticsRegistry::registerStat(&d_instantiations); +} + +InstStrategyUserPatterns::Statistics::~Statistics(){ + StatisticsRegistry::unregisterStat(&d_instantiations); +} +*/ + +void InstStrategyAutoGenTriggers::processResetInstantiationRound( Theory::Effort effort ){ + //reset triggers + for( std::map< Node, std::map< Trigger*, bool > >::iterator it = d_auto_gen_trigger.begin(); it != d_auto_gen_trigger.end(); ++it ){ + for( std::map< Trigger*, bool >::iterator itt = it->second.begin(); itt != it->second.end(); ++itt ){ + itt->first->resetInstantiationRound(); + itt->first->reset( Node::null() ); + } + } + d_processed_trigger.clear(); +} + +int InstStrategyAutoGenTriggers::process( Node f, Theory::Effort effort, int e ){ + int peffort = f.getNumChildren()==3 ? 2 : 1; + //int peffort = f.getNumChildren()==3 ? 2 : 1; + //int peffort = 1; + if( e<peffort ){ + return STATUS_UNFINISHED; + }else{ + int status = STATUS_UNKNOWN; + bool gen = false; + if( e==peffort ){ + if( d_counter.find( f )==d_counter.end() ){ + d_counter[f] = 0; + gen = true; + }else{ + d_counter[f]++; + gen = d_regenerate && d_counter[f]%d_regenerate_frequency==0; + } + }else{ + gen = true; + } + if( gen ){ + generateTriggers( f, effort, e, status ); + } + Debug("quant-uf-strategy") << "Try auto-generated triggers... " << d_tr_strategy << " " << e << std::endl; + //Notice() << "Try auto-generated triggers..." << std::endl; + for( std::map< Trigger*, bool >::iterator itt = d_auto_gen_trigger[f].begin(); itt != d_auto_gen_trigger[f].end(); ++itt ){ + Trigger* tr = itt->first; + if( tr ){ + 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) << "..." << std::endl; + InstMatch baseMatch; + int numInst = tr->addInstantiations( baseMatch ); + //if( tr->isMultiTrigger() ) + 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{ + d_quantEngine->getInstantiationEngine()->d_statistics.d_instantiations_auto_gen += numInst; + } + if( tr->isMultiTrigger() ){ + d_quantEngine->d_statistics.d_multi_trigger_instantiations += numInst; + } + //d_quantEngine->d_hasInstantiated[f] = true; + } + } + } + Debug("quant-uf-strategy") << "done." << std::endl; + //Notice() << "done" << std::endl; + return status; + } +} + +void InstStrategyAutoGenTriggers::generateTriggers( Node f, Theory::Effort effort, int e, int & status ){ + Trace("auto-gen-trigger-debug") << "Generate trigger for " << f << std::endl; + if( d_patTerms[0].find( f )==d_patTerms[0].end() ){ + //determine all possible pattern terms based on trigger term selection strategy d_tr_strategy + 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; + Trace("auto-gen-trigger") << " "; + for( int i=0; i<(int)patTermsF.size(); i++ ){ + Trace("auto-gen-trigger") << patTermsF[i] << " "; + } + Trace("auto-gen-trigger") << std::endl; + //extend to literal matching (if applicable) + d_quantEngine->getPhaseReqTerms( f, patTermsF ); + //sort into single/multi triggers + 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() ){ + d_patTerms[0][f].push_back( it->first ); + d_is_single_trigger[ it->first ] = true; + }else{ + d_patTerms[1][f].push_back( it->first ); + d_is_single_trigger[ it->first ] = false; + } + } + d_made_multi_trigger[f] = false; + Trace("auto-gen-trigger") << "Single triggers for " << f << " : " << std::endl; + Trace("auto-gen-trigger") << " "; + for( int i=0; i<(int)d_patTerms[0][f].size(); i++ ){ + Trace("auto-gen-trigger") << d_patTerms[0][f][i] << " "; + } + Trace("auto-gen-trigger") << std::endl; + Trace("auto-gen-trigger") << "Multi-trigger term pool for " << f << " : " << std::endl; + Trace("auto-gen-trigger") << " "; + for( int i=0; i<(int)d_patTerms[1][f].size(); i++ ){ + Trace("auto-gen-trigger") << d_patTerms[1][f][i] << " "; + } + Trace("auto-gen-trigger") << std::endl; + } + + //populate candidate pattern term vector for the current trigger + std::vector< Node > patTerms; + //try to add single triggers first + for( int i=0; i<(int)d_patTerms[0][f].size(); i++ ){ + if( !d_single_trigger_gen[d_patTerms[0][f][i]] ){ + patTerms.push_back( d_patTerms[0][f][i] ); + } + } + //if no single triggers exist, add multi trigger terms + if( patTerms.empty() ){ + patTerms.insert( patTerms.begin(), d_patTerms[1][f].begin(), d_patTerms[1][f].end() ); + } + + if( !patTerms.empty() ){ + Trace("auto-gen-trigger") << "Generate trigger for " << f << std::endl; + //sort terms based on relevance + if( d_rlv_strategy==RELEVANCE_DEFAULT ){ + sortQuantifiersForSymbol sqfs; + sqfs.d_qe = d_quantEngine; + //sort based on # occurrences (this will cause Trigger to select rarer symbols) + std::sort( patTerms.begin(), patTerms.end(), sqfs ); + Debug("relevant-trigger") << "Terms based on relevance: " << std::endl; + for( int i=0; i<(int)patTerms.size(); i++ ){ + Debug("relevant-trigger") << " " << patTerms[i] << " ("; + Debug("relevant-trigger") << d_quantEngine->getQuantifierRelevance()->getNumQuantifiersForSymbol( patTerms[i].getOperator() ) << ")" << std::endl; + } + //Notice() << "Terms based on relevance: " << std::endl; + //for( int i=0; i<(int)patTerms.size(); i++ ){ + // Notice() << " " << patTerms[i] << " ("; + // Notice() << d_quantEngine->getNumQuantifiersForSymbol( patTerms[i].getOperator() ) << ")" << std::endl; + //} + } + //now, generate the trigger... + int matchOption = options::efficientEMatching() ? InstMatchGenerator::MATCH_GEN_EFFICIENT_E_MATCH : 0; + Trigger* tr = NULL; + if( d_is_single_trigger[ patTerms[0] ] ){ + tr = Trigger::mkTrigger( d_quantEngine, f, patTerms[0], matchOption, false, Trigger::TR_RETURN_NULL, + options::smartTriggers() ); + d_single_trigger_gen[ patTerms[0] ] = true; + }else{ + //only generate multi trigger if effort level > 5, or if no single triggers exist + if( !d_patTerms[0][f].empty() ){ + if( e<=5 ){ + status = STATUS_UNFINISHED; + return; + }else{ + Trace("multi-trigger-debug") << "Resort to choosing multi-triggers..." << std::endl; + } + } + //if we are re-generating triggers, shuffle based on some method + if( d_made_multi_trigger[f] ){ +#ifndef MULTI_MULTI_TRIGGERS + return; +#endif + std::random_shuffle( patTerms.begin(), patTerms.end() ); //shuffle randomly + }else{ + d_made_multi_trigger[f] = true; + } + //will possibly want to get an old trigger + tr = Trigger::mkTrigger( d_quantEngine, f, patTerms, matchOption, false, Trigger::TR_GET_OLD, + options::smartTriggers() ); + } + if( tr ){ + if( tr->isMultiTrigger() ){ + //disable all other multi triggers + for( std::map< Trigger*, bool >::iterator it = d_auto_gen_trigger[f].begin(); it != d_auto_gen_trigger[f].end(); ++it ){ + if( it->first->isMultiTrigger() ){ + d_auto_gen_trigger[f][ it->first ] = false; + } + } + } + //making it during an instantiation round, so must reset + if( d_auto_gen_trigger[f].find( tr )==d_auto_gen_trigger[f].end() ){ + tr->resetInstantiationRound(); + tr->reset( Node::null() ); + } + d_auto_gen_trigger[f][tr] = true; + //if we are generating additional triggers... + if( d_generate_additional && d_is_single_trigger[ patTerms[0] ] ){ + int index = 0; + if( index<(int)patTerms.size() ){ + //Notice() << "check add additional" << std::endl; + //check if similar patterns exist, and if so, add them additionally + int nqfs_curr = d_quantEngine->getQuantifierRelevance()->getNumQuantifiersForSymbol( patTerms[0].getOperator() ); + index++; + bool success = true; + while( success && index<(int)patTerms.size() && d_is_single_trigger[ patTerms[index] ] ){ + success = false; + if( d_quantEngine->getQuantifierRelevance()->getNumQuantifiersForSymbol( patTerms[index].getOperator() )<=nqfs_curr ){ + d_single_trigger_gen[ patTerms[index] ] = true; + Trigger* tr2 = Trigger::mkTrigger( d_quantEngine, f, patTerms[index], matchOption, false, Trigger::TR_RETURN_NULL, + options::smartTriggers() ); + if( tr2 ){ + //Notice() << "Add additional trigger " << patTerms[index] << std::endl; + tr2->resetInstantiationRound(); + tr2->reset( Node::null() ); + d_auto_gen_trigger[f][tr2] = true; + } + success = true; + } + index++; + } + //Notice() << "done check add additional" << std::endl; + } + } + } + } +} +/* +InstStrategyAutoGenTriggers::Statistics::Statistics(): + d_instantiations("InstStrategyAutoGenTriggers::Instantiations", 0), + d_instantiations_min("InstStrategyAutoGenTriggers::Instantiations_min", 0) +{ + StatisticsRegistry::registerStat(&d_instantiations); + StatisticsRegistry::registerStat(&d_instantiations_min); +} + +InstStrategyAutoGenTriggers::Statistics::~Statistics(){ + StatisticsRegistry::unregisterStat(&d_instantiations); + StatisticsRegistry::unregisterStat(&d_instantiations_min); +} +*/ + +void InstStrategyFreeVariable::processResetInstantiationRound( Theory::Effort effort ){ +} + +int InstStrategyFreeVariable::process( Node f, Theory::Effort effort, int e ){ + if( e<5 ){ + return STATUS_UNFINISHED; + }else{ + if( d_guessed.find( f )==d_guessed.end() ){ + d_guessed[f] = true; + Debug("quant-uf-alg") << "Add guessed instantiation" << std::endl; + InstMatch m; + if( d_quantEngine->addInstantiation( f, m ) ){ + ++(d_quantEngine->getInstantiationEngine()->d_statistics.d_instantiations_guess); + //d_quantEngine->d_hasInstantiated[f] = true; + } + } + return STATUS_UNKNOWN; + } +} +/* +InstStrategyFreeVariable::Statistics::Statistics(): + d_instantiations("InstStrategyGuess::Instantiations", 0) +{ + StatisticsRegistry::registerStat(&d_instantiations); +} + +InstStrategyFreeVariable::Statistics::~Statistics(){ + StatisticsRegistry::unregisterStat(&d_instantiations); +} +*/ diff --git a/src/theory/quantifiers/inst_strategy_e_matching.h b/src/theory/quantifiers/inst_strategy_e_matching.h index 23f0d8a54..13d443c6a 100755..100644 --- a/src/theory/quantifiers/inst_strategy_e_matching.h +++ b/src/theory/quantifiers/inst_strategy_e_matching.h @@ -1,135 +1,137 @@ -/********************* */
-/*! \file inst_strategy_e_matching.h
- ** \verbatim
- ** Original author: ajreynol
- ** Major contributors: none
- ** Minor contributors (to current version): bobot, mdeters
- ** This file is part of the CVC4 prototype.
- ** Copyright (c) 2009-2012 New York University and The University of Iowa
- ** See the file COPYING in the top-level source directory for licensing
- ** information.\endverbatim
- **
- ** \brief E matching instantiation strategies
- **/
-
-#include "cvc4_private.h"
-
-#ifndef __CVC4__INST_STRATEGY_E_MATCHING_H
-#define __CVC4__INST_STRATEGY_E_MATCHING_H
-
-#include "theory/quantifiers_engine.h"
-#include "theory/quantifiers/trigger.h"
-
-#include "context/context.h"
-#include "context/context_mm.h"
-
-#include "util/statistics_registry.h"
-#include "theory/quantifiers/instantiation_engine.h"
-
-namespace CVC4 {
-namespace theory {
-namespace quantifiers {
-
-//instantiation strategies
-
-class InstStrategyUserPatterns : public InstStrategy{
-private:
- /** explicitly provided patterns */
- std::map< Node, std::vector< inst::Trigger* > > d_user_gen;
- /** counter for quantifiers */
- std::map< Node, int > d_counter;
- /** process functions */
- void processResetInstantiationRound( Theory::Effort effort );
- int process( Node f, Theory::Effort effort, int e );
-public:
- InstStrategyUserPatterns( QuantifiersEngine* ie ) :
- InstStrategy( ie ){}
- ~InstStrategyUserPatterns(){}
-public:
- /** add pattern */
- void addUserPattern( Node f, Node pat );
- /** get num patterns */
- int getNumUserGenerators( Node f ) { return (int)d_user_gen[f].size(); }
- /** get user pattern */
- inst::Trigger* getUserGenerator( Node f, int i ) { return d_user_gen[f][ i ]; }
- /** identify */
- std::string identify() const { return std::string("UserPatterns"); }
-};/* class InstStrategyUserPatterns */
-
-class InstStrategyAutoGenTriggers : public InstStrategy{
-public:
- enum {
- RELEVANCE_NONE,
- RELEVANCE_DEFAULT,
- };
-private:
- /** trigger generation strategy */
- int d_tr_strategy;
- /** relevance strategy */
- int d_rlv_strategy;
- /** regeneration */
- bool d_regenerate;
- int d_regenerate_frequency;
- /** generate additional triggers */
- bool d_generate_additional;
- /** triggers for each quantifier */
- std::map< Node, std::map< inst::Trigger*, bool > > d_auto_gen_trigger;
- std::map< Node, int > d_counter;
- /** single, multi triggers for each quantifier */
- std::map< Node, std::vector< Node > > d_patTerms[2];
- std::map< Node, bool > d_is_single_trigger;
- std::map< Node, bool > d_single_trigger_gen;
- std::map< Node, bool > d_made_multi_trigger;
-private:
- /** process functions */
- void processResetInstantiationRound( Theory::Effort effort );
- int process( Node f, Theory::Effort effort, int e );
- /** generate triggers */
- void generateTriggers( Node f );
-public:
- /** tstrt is the type of triggers to use (maximum depth, minimum depth, or all)
- rstrt is the relevance setting for trigger (use only relevant triggers vs. use all)
- rgfr is the frequency at which triggers are generated */
- InstStrategyAutoGenTriggers( QuantifiersEngine* qe, int tstrt, int rstrt, int rgfr = -1 ) :
- InstStrategy( qe ), d_tr_strategy( tstrt ), d_rlv_strategy( rstrt ), d_generate_additional( false ){
- setRegenerateFrequency( rgfr );
- }
- ~InstStrategyAutoGenTriggers(){}
-public:
- /** get auto-generated trigger */
- inst::Trigger* getAutoGenTrigger( Node f );
- /** identify */
- std::string identify() const { return std::string("AutoGenTriggers"); }
- /** set regenerate frequency, if fr<0, turn off regenerate */
- void setRegenerateFrequency( int fr ){
- if( fr<0 ){
- d_regenerate = false;
- }else{
- d_regenerate_frequency = fr;
- d_regenerate = true;
- }
- }
- /** set generate additional */
- void setGenerateAdditional( bool val ) { d_generate_additional = val; }
-};/* class InstStrategyAutoGenTriggers */
-
-class InstStrategyFreeVariable : public InstStrategy{
-private:
- /** guessed instantiations */
- std::map< Node, bool > d_guessed;
- /** process functions */
- void processResetInstantiationRound( Theory::Effort effort );
- int process( Node f, Theory::Effort effort, int e );
-public:
- InstStrategyFreeVariable( QuantifiersEngine* qe ) :
- InstStrategy( qe ){}
- ~InstStrategyFreeVariable(){}
- /** identify */
- std::string identify() const { return std::string("FreeVariable"); }
-};/* class InstStrategyFreeVariable */
-
-}
-}/* CVC4::theory namespace */
-}/* CVC4 namespace */
-
-#endif
+/********************* */ +/*! \file inst_strategy_e_matching.h + ** \verbatim + ** Original author: Andrew Reynolds <andrew.j.reynolds@gmail.com> + ** Major contributors: Morgan Deters <mdeters@cs.nyu.edu> + ** Minor contributors (to current version): none + ** This file is part of the CVC4 project. + ** Copyright (c) 2009-2013 New York University and The University of Iowa + ** See the file COPYING in the top-level source directory for licensing + ** information.\endverbatim + ** + ** \brief E matching instantiation strategies + **/ + +#include "cvc4_private.h" + +#ifndef __CVC4__INST_STRATEGY_E_MATCHING_H +#define __CVC4__INST_STRATEGY_E_MATCHING_H + +#include "theory/quantifiers_engine.h" +#include "theory/quantifiers/trigger.h" + +#include "context/context.h" +#include "context/context_mm.h" + +#include "util/statistics_registry.h" +#include "theory/quantifiers/instantiation_engine.h" + +namespace CVC4 { +namespace theory { +namespace quantifiers { + +//instantiation strategies + +class InstStrategyUserPatterns : public InstStrategy{ +private: + /** explicitly provided patterns */ + std::map< Node, std::vector< inst::Trigger* > > d_user_gen; + /** counter for quantifiers */ + std::map< Node, int > d_counter; + /** process functions */ + void processResetInstantiationRound( Theory::Effort effort ); + int process( Node f, Theory::Effort effort, int e ); +public: + InstStrategyUserPatterns( QuantifiersEngine* ie ) : + InstStrategy( ie ){} + ~InstStrategyUserPatterns(){} +public: + /** add pattern */ + void addUserPattern( Node f, Node pat ); + /** get num patterns */ + int getNumUserGenerators( Node f ) { return (int)d_user_gen[f].size(); } + /** get user pattern */ + inst::Trigger* getUserGenerator( Node f, int i ) { return d_user_gen[f][ i ]; } + /** identify */ + std::string identify() const { return std::string("UserPatterns"); } +};/* class InstStrategyUserPatterns */ + +class InstStrategyAutoGenTriggers : public InstStrategy{ +public: + enum { + RELEVANCE_NONE, + RELEVANCE_DEFAULT, + }; +private: + /** trigger generation strategy */ + int d_tr_strategy; + /** relevance strategy */ + int d_rlv_strategy; + /** regeneration */ + bool d_regenerate; + int d_regenerate_frequency; + /** generate additional triggers */ + bool d_generate_additional; + /** triggers for each quantifier */ + std::map< Node, std::map< inst::Trigger*, bool > > d_auto_gen_trigger; + std::map< Node, int > d_counter; + /** single, multi triggers for each quantifier */ + std::map< Node, std::vector< Node > > d_patTerms[2]; + std::map< Node, bool > d_is_single_trigger; + std::map< Node, bool > d_single_trigger_gen; + std::map< Node, bool > d_made_multi_trigger; + //processed trigger this round + std::map< Node, std::map< inst::Trigger*, bool > > d_processed_trigger; +private: + /** process functions */ + void processResetInstantiationRound( Theory::Effort effort ); + int process( Node f, Theory::Effort effort, int e ); + /** generate triggers */ + void generateTriggers( Node f, Theory::Effort effort, int e, int & status ); +public: + /** tstrt is the type of triggers to use (maximum depth, minimum depth, or all) + rstrt is the relevance setting for trigger (use only relevant triggers vs. use all) + rgfr is the frequency at which triggers are generated */ + InstStrategyAutoGenTriggers( QuantifiersEngine* qe, int tstrt, int rstrt, int rgfr = -1 ) : + InstStrategy( qe ), d_tr_strategy( tstrt ), d_rlv_strategy( rstrt ), d_generate_additional( false ){ + setRegenerateFrequency( rgfr ); + } + ~InstStrategyAutoGenTriggers(){} +public: + /** get auto-generated trigger */ + inst::Trigger* getAutoGenTrigger( Node f ); + /** identify */ + std::string identify() const { return std::string("AutoGenTriggers"); } + /** set regenerate frequency, if fr<0, turn off regenerate */ + void setRegenerateFrequency( int fr ){ + if( fr<0 ){ + d_regenerate = false; + }else{ + d_regenerate_frequency = fr; + d_regenerate = true; + } + } + /** set generate additional */ + void setGenerateAdditional( bool val ) { d_generate_additional = val; } +};/* class InstStrategyAutoGenTriggers */ + +class InstStrategyFreeVariable : public InstStrategy{ +private: + /** guessed instantiations */ + std::map< Node, bool > d_guessed; + /** process functions */ + void processResetInstantiationRound( Theory::Effort effort ); + int process( Node f, Theory::Effort effort, int e ); +public: + InstStrategyFreeVariable( QuantifiersEngine* qe ) : + InstStrategy( qe ){} + ~InstStrategyFreeVariable(){} + /** identify */ + std::string identify() const { return std::string("FreeVariable"); } +};/* class InstStrategyFreeVariable */ + +} +}/* CVC4::theory namespace */ +}/* CVC4 namespace */ + +#endif diff --git a/src/theory/quantifiers/instantiation_engine.cpp b/src/theory/quantifiers/instantiation_engine.cpp index 53977ee4f..75cc10615 100644 --- a/src/theory/quantifiers/instantiation_engine.cpp +++ b/src/theory/quantifiers/instantiation_engine.cpp @@ -84,16 +84,18 @@ bool InstantiationEngine::doInstantiationRound( Theory::Effort effort ){ //add cbqi lemma //get the counterexample literal Node ceLit = d_quantEngine->getTermDatabase()->getCounterexampleLiteral( f ); - //require any decision on cel to be phase=true - d_quantEngine->getOutputChannel().requirePhase( ceLit, true ); - Debug("cbqi-debug") << "Require phase " << ceLit << " = true." << std::endl; - //add counterexample lemma - NodeBuilder<> nb(kind::OR); - nb << f << ceLit; - Node lem = nb; - Debug("cbqi-debug") << "Counterexample lemma : " << lem << std::endl; - d_quantEngine->getOutputChannel().lemma( lem ); - addedLemma = true; + if( !ceLit.isNull() ){ + //require any decision on cel to be phase=true + d_quantEngine->getOutputChannel().requirePhase( ceLit, true ); + Debug("cbqi-debug") << "Require phase " << ceLit << " = true." << std::endl; + //add counterexample lemma + NodeBuilder<> nb(kind::OR); + nb << f << ceLit; + Node lem = nb; + Debug("cbqi-debug") << "Counterexample lemma : " << lem << std::endl; + d_quantEngine->getOutputChannel().lemma( lem ); + addedLemma = true; + } } } if( addedLemma ){ diff --git a/src/theory/quantifiers/macros.cpp b/src/theory/quantifiers/macros.cpp index c116b73f5..bf67bdd25 100755..100644 --- a/src/theory/quantifiers/macros.cpp +++ b/src/theory/quantifiers/macros.cpp @@ -1,375 +1,375 @@ -/********************* */
-/*! \file macros.cpp
- ** \verbatim
- ** Original author: ajreynol
- ** Major contributors: none
- ** Minor contributors (to current version): none
- ** This file is part of the CVC4 prototype.
- ** Copyright (c) 2009-2012 New York University and The University of Iowa
- ** See the file COPYING in the top-level source directory for licensing
- ** information.\endverbatim
- **
- ** \brief Sort inference module
- **
- ** This class implements quantifiers macro definitions.
- **/
-
-#include <vector>
-
-#include "theory/quantifiers/macros.h"
-#include "theory/rewriter.h"
-
-using namespace CVC4;
-using namespace std;
-using namespace CVC4::theory;
-using namespace CVC4::theory::quantifiers;
-using namespace CVC4::kind;
-using namespace CVC4::context;
-
-bool QuantifierMacros::simplify( std::vector< Node >& assertions, bool doRewrite ){
- //first, collect macro definitions
- for( size_t i=0; i<assertions.size(); i++ ){
- if( assertions[i].getKind()==FORALL ){
- std::vector< Node > args;
- for( size_t j=0; j<assertions[i][0].getNumChildren(); j++ ){
- args.push_back( assertions[i][0][j] );
- }
- //look at the body of the quantifier for macro definition
- process( assertions[i][1], true, args, assertions[i] );
- }
- }
- //create macro defs
- for( std::map< Node, std::vector< std::pair< Node, Node > > >::iterator it = d_macro_def_cases.begin();
- it != d_macro_def_cases.end(); ++it ){
- //create ite based on case definitions
- Node val;
- for( size_t i=0; i<it->second.size(); ++i ){
- if( it->second[i].first.isNull() ){
- Assert( i==0 );
- val = it->second[i].second;
- }else{
- //if value is null, must generate it
- if( val.isNull() ){
- std::stringstream ss;
- ss << "mdo_" << it->first << "_$$";
- Node op = NodeManager::currentNM()->mkSkolem( ss.str(), it->first.getType(), "op created during macro definitions" );
- //will be defined in terms of fresh operator
- std::vector< Node > children;
- children.push_back( op );
- children.insert( children.end(), d_macro_basis[ it->first ].begin(), d_macro_basis[ it->first ].end() );
- val = NodeManager::currentNM()->mkNode( APPLY_UF, children );
- }
- val = NodeManager::currentNM()->mkNode( ITE, it->second[i].first, it->second[i].second, val );
- }
- }
- d_macro_defs[ it->first ] = val;
- Trace("macros-def") << "* " << val << " is a macro for " << it->first << std::endl;
- }
- //now simplify bodies
- for( std::map< Node, Node >::iterator it = d_macro_defs.begin(); it != d_macro_defs.end(); ++it ){
- d_macro_defs[ it->first ] = Rewriter::rewrite( simplify( it->second ) );
- }
- bool retVal = false;
- if( doRewrite && !d_macro_defs.empty() ){
- //now, rewrite based on macro definitions
- for( size_t i=0; i<assertions.size(); i++ ){
- Node prev = assertions[i];
- assertions[i] = simplify( assertions[i] );
- if( prev!=assertions[i] ){
- assertions[i] = Rewriter::rewrite( assertions[i] );
- Trace("macros-rewrite") << "Rewrite " << prev << " to " << assertions[i] << std::endl;
- retVal = true;
- }
- }
- }
- return retVal;
-}
-
-bool QuantifierMacros::contains( Node n, Node n_s ){
- if( n==n_s ){
- return true;
- }else{
- for( size_t i=0; i<n.getNumChildren(); i++ ){
- if( contains( n[i], n_s ) ){
- return true;
- }
- }
- return false;
- }
-}
-
-bool QuantifierMacros::containsBadOp( Node n, Node n_op ){
- if( n!=n_op ){
- if( n.getKind()==APPLY_UF ){
- Node op = n.getOperator();
- if( op==n_op.getOperator() ){
- return true;
- }
- if( d_macro_def_cases.find( op )!=d_macro_def_cases.end() && !d_macro_def_cases[op].empty() ){
- return true;
- }
- }
- for( size_t i=0; i<n.getNumChildren(); i++ ){
- if( containsBadOp( n[i], n_op ) ){
- return true;
- }
- }
- }
- return false;
-}
-
-bool QuantifierMacros::isMacroLiteral( Node n, bool pol ){
- return pol && n.getKind()==EQUAL;//( n.getKind()==EQUAL || n.getKind()==IFF );
-}
-
-void QuantifierMacros::getMacroCandidates( Node n, std::vector< Node >& candidates ){
- if( n.getKind()==APPLY_UF ){
- candidates.push_back( n );
- }else if( n.getKind()==PLUS ){
- for( size_t i=0; i<n.getNumChildren(); i++ ){
- getMacroCandidates( n[i], candidates );
- }
- }else if( n.getKind()==MULT ){
- //if the LHS is a constant
- if( n.getNumChildren()==2 && n[0].isConst() ){
- getMacroCandidates( n[1], candidates );
- }
- }
-}
-
-Node QuantifierMacros::solveInEquality( Node n, Node lit ){
- if( lit.getKind()==IFF || lit.getKind()==EQUAL ){
- //return the opposite side of the equality if defined that way
- for( int i=0; i<2; i++ ){
- if( lit[i]==n ){
- return lit[ i==0 ? 1 : 0];
- }
- }
- //must solve for term n in the literal lit
- if( lit[0].getType().isInteger() || lit[0].getType().isReal() ){
- Node coeff;
- Node term;
- //could be solved for on LHS
- if( lit[0].getKind()==MULT && lit[0][1]==n ){
- Assert( lit[0][0].isConst() );
- term = lit[1];
- coeff = lit[0][0];
- }else{
- Assert( lit[1].getKind()==PLUS );
- std::vector< Node > plus_children;
- //find monomial with n
- for( size_t j=0; j<lit[1].getNumChildren(); j++ ){
- if( lit[1][j]==n ){
- Assert( coeff.isNull() );
- coeff = NodeManager::currentNM()->mkConst( Rational(1) );
- }else if( lit[1][j].getKind()==MULT && lit[1][j][1]==n ){
- Assert( coeff.isNull() );
- Assert( lit[1][j][0].isConst() );
- coeff = lit[1][j][0];
- }else{
- plus_children.push_back( lit[1][j] );
- }
- }
- if( !coeff.isNull() ){
- term = NodeManager::currentNM()->mkNode( PLUS, plus_children );
- term = NodeManager::currentNM()->mkNode( MINUS, lit[0], term );
- }
- }
- if( !coeff.isNull() ){
- coeff = NodeManager::currentNM()->mkConst( Rational(1) / coeff.getConst<Rational>() );
- term = NodeManager::currentNM()->mkNode( MULT, coeff, term );
- term = Rewriter::rewrite( term );
- return term;
- }
- }
- }
- Trace("macros-debug") << "Cannot find for " << lit << " " << n << std::endl;
- return Node::null();
-}
-
-bool QuantifierMacros::isConsistentDefinition( Node op, Node cond, Node def ){
- if( d_macro_def_cases[op].empty() || ( cond.isNull() && !d_macro_def_cases[op][0].first.isNull() ) ){
- return true;
- }else{
- return false;
- }
-}
-
-bool QuantifierMacros::getFreeVariables( Node n, std::vector< Node >& v_quant, std::vector< Node >& vars, bool retOnly ){
- if( std::find( v_quant.begin(), v_quant.end(), n )!=v_quant.end() ){
- if( std::find( vars.begin(), vars.end(), n )==vars.end() ){
- if( retOnly ){
- return true;
- }else{
- vars.push_back( n );
- }
- }
- }
- for( size_t i=0; i<n.getNumChildren(); i++ ){
- if( getFreeVariables( n[i], v_quant, vars, retOnly ) ){
- return true;
- }
- }
- return false;
-}
-
-bool QuantifierMacros::getSubstitution( std::vector< Node >& v_quant, std::map< Node, Node >& solved,
- std::vector< Node >& vars, std::vector< Node >& subs, bool reqComplete ){
- bool success = true;
- for( size_t a=0; a<v_quant.size(); a++ ){
- if( !solved[ v_quant[a] ].isNull() ){
- vars.push_back( v_quant[a] );
- subs.push_back( solved[ v_quant[a] ] );
- }else{
- if( reqComplete ){
- success = false;
- break;
- }
- }
- }
- return success;
-}
-
-void QuantifierMacros::process( Node n, bool pol, std::vector< Node >& args, Node f ){
- if( n.getKind()==NOT ){
- process( n[0], !pol, args, f );
- }else if( n.getKind()==AND || n.getKind()==OR || n.getKind()==IMPLIES ){
- //bool favorPol = (n.getKind()==AND)==pol;
- //conditional?
- }else if( n.getKind()==ITE ){
- //can not do anything
- }else{
- //literal case
- if( isMacroLiteral( n, pol ) ){
- std::vector< Node > candidates;
- for( size_t i=0; i<n.getNumChildren(); i++ ){
- getMacroCandidates( n[i], candidates );
- }
- for( size_t i=0; i<candidates.size(); i++ ){
- Node m = candidates[i];
- Node op = m.getOperator();
- if( !containsBadOp( n, m ) ){
- std::vector< Node > fvs;
- getFreeVariables( m, args, fvs, false );
- //get definition and condition
- Node n_def = solveInEquality( m, n ); //definition for the macro
- //definition must exist and not contain any free variables apart from fvs
- if( !n_def.isNull() && !getFreeVariables( n_def, args, fvs, true ) ){
- Node n_cond; //condition when this definition holds
- //conditional must not contain any free variables apart from fvs
- if( n_cond.isNull() || !getFreeVariables( n_cond, args, fvs, true ) ){
- Trace("macros") << m << " is possible macro in " << f << std::endl;
- //now we must rewrite candidates[i] to a term of form g( x1, ..., xn ) where
- // x1 ... xn are distinct variables
- if( d_macro_basis[op].empty() ){
- for( size_t a=0; a<m.getNumChildren(); a++ ){
- std::stringstream ss;
- ss << "mda_" << op << "_$$";
- Node v = NodeManager::currentNM()->mkSkolem( ss.str(), m[a].getType(), "created during macro definition recognition" );
- d_macro_basis[op].push_back( v );
- }
- }
- std::vector< Node > eq;
- for( size_t a=0; a<m.getNumChildren(); a++ ){
- eq.push_back( m[a] );
- }
- //solve system of equations "d_macro_basis[op] = m" for variables in fvs
- std::map< Node, Node > solved;
- //solve obvious cases first
- for( size_t a=0; a<eq.size(); a++ ){
- if( std::find( fvs.begin(), fvs.end(), eq[a] )!=fvs.end() ){
- if( solved[ eq[a] ].isNull() ){
- solved[ eq[a] ] = d_macro_basis[op][a];
- }
- }
- }
- //now, apply substitution for obvious cases
- std::vector< Node > vars;
- std::vector< Node > subs;
- getSubstitution( fvs, solved, vars, subs, false );
- for( size_t a=0; a<eq.size(); a++ ){
- eq[a] = eq[a].substitute( vars.begin(), vars.end(), subs.begin(), subs.end() );
- }
-
- Trace("macros-eq") << "Solve system of equations : " << std::endl;
- for( size_t a=0; a<m.getNumChildren(); a++ ){
- if( d_macro_basis[op][a]!=eq[a] ){
- Trace("macros-eq") << " " << d_macro_basis[op][a] << " = " << eq[a] << std::endl;
- }
- }
- Trace("macros-eq") << " for ";
- for( size_t a=0; a<fvs.size(); a++ ){
- if( solved[ fvs[a] ].isNull() ){
- Trace("macros-eq") << fvs[a] << " ";
- }
- }
- Trace("macros-eq") << std::endl;
- //DO_THIS
-
-
- vars.clear();
- subs.clear();
- if( getSubstitution( fvs, solved, vars, subs, true ) ){
- //build condition
- std::vector< Node > conds;
- if( !n_cond.isNull() ){
- //must apply substitution obtained from solving system of equations to original condition
- n_cond = n_cond.substitute( vars.begin(), vars.end(), subs.begin(), subs.end() );
- conds.push_back( n_cond );
- }
- for( size_t a=0; a<eq.size(); a++ ){
- //collect conditions based on solving argument's system of equations
- if( d_macro_basis[op][a]!=eq[a] ){
- conds.push_back( NodeManager::currentNM()->mkNode( eq[a].getType().isBoolean() ? IFF : EQUAL, d_macro_basis[op][a], eq[a] ) );
- }
- }
- //build the condition
- if( !conds.empty() ){
- n_cond = conds.size()==1 ? conds[0] : NodeManager::currentNM()->mkNode( AND, conds );
- }
- //apply the substitution to the
- n_def = n_def.substitute( vars.begin(), vars.end(), subs.begin(), subs.end() );
- //now see if definition is consistent with others
- if( isConsistentDefinition( op, n_cond, n_def ) ){
- //must clear if it is a base definition
- if( n_cond.isNull() ){
- d_macro_def_cases[ op ].clear();
- }
- d_macro_def_cases[ op ].push_back( std::pair< Node, Node >( n_cond, n_def ) );
- }
- }
- }
- }
- }
- }
- }
- }
-}
-
-Node QuantifierMacros::simplify( Node n ){
- Trace("macros-debug") << "simplify " << n << std::endl;
- std::vector< Node > children;
- bool childChanged = false;
- for( size_t i=0; i<n.getNumChildren(); i++ ){
- Node nn = simplify( n[i] );
- children.push_back( nn );
- childChanged = childChanged || nn!=n[i];
- }
- if( n.getKind()==APPLY_UF ){
- Node op = n.getOperator();
- if( d_macro_defs.find( op )!=d_macro_defs.end() && !d_macro_defs[op].isNull() ){
- //do subsitutition
- Node ret = d_macro_defs[op];
- ret = ret.substitute( d_macro_basis[op].begin(), d_macro_basis[op].end(), children.begin(), children.end() );
- return ret;
- }
- }
- if( childChanged ){
- if( n.getMetaKind() == kind::metakind::PARAMETERIZED ){
- children.insert( children.begin(), n.getOperator() );
- }
- return NodeManager::currentNM()->mkNode( n.getKind(), children );
- }else{
- return n;
- }
-}
+/********************* */ +/*! \file macros.cpp + ** \verbatim + ** Original author: Andrew Reynolds <andrew.j.reynolds@gmail.com> + ** Major contributors: Morgan Deters <mdeters@cs.nyu.edu> + ** Minor contributors (to current version): none + ** This file is part of the CVC4 project. + ** Copyright (c) 2009-2013 New York University and The University of Iowa + ** See the file COPYING in the top-level source directory for licensing + ** information.\endverbatim + ** + ** \brief Sort inference module + ** + ** This class implements quantifiers macro definitions. + **/ + +#include <vector> + +#include "theory/quantifiers/macros.h" +#include "theory/rewriter.h" + +using namespace CVC4; +using namespace std; +using namespace CVC4::theory; +using namespace CVC4::theory::quantifiers; +using namespace CVC4::kind; +using namespace CVC4::context; + +bool QuantifierMacros::simplify( std::vector< Node >& assertions, bool doRewrite ){ + //first, collect macro definitions + for( size_t i=0; i<assertions.size(); i++ ){ + if( assertions[i].getKind()==FORALL ){ + std::vector< Node > args; + for( size_t j=0; j<assertions[i][0].getNumChildren(); j++ ){ + args.push_back( assertions[i][0][j] ); + } + //look at the body of the quantifier for macro definition + process( assertions[i][1], true, args, assertions[i] ); + } + } + //create macro defs + for( std::map< Node, std::vector< std::pair< Node, Node > > >::iterator it = d_macro_def_cases.begin(); + it != d_macro_def_cases.end(); ++it ){ + //create ite based on case definitions + Node val; + for( size_t i=0; i<it->second.size(); ++i ){ + if( it->second[i].first.isNull() ){ + Assert( i==0 ); + val = it->second[i].second; + }else{ + //if value is null, must generate it + if( val.isNull() ){ + std::stringstream ss; + ss << "mdo_" << it->first << "_$$"; + Node op = NodeManager::currentNM()->mkSkolem( ss.str(), it->first.getType(), "op created during macro definitions" ); + //will be defined in terms of fresh operator + std::vector< Node > children; + children.push_back( op ); + children.insert( children.end(), d_macro_basis[ it->first ].begin(), d_macro_basis[ it->first ].end() ); + val = NodeManager::currentNM()->mkNode( APPLY_UF, children ); + } + val = NodeManager::currentNM()->mkNode( ITE, it->second[i].first, it->second[i].second, val ); + } + } + d_macro_defs[ it->first ] = val; + Trace("macros-def") << "* " << val << " is a macro for " << it->first << std::endl; + } + //now simplify bodies + for( std::map< Node, Node >::iterator it = d_macro_defs.begin(); it != d_macro_defs.end(); ++it ){ + d_macro_defs[ it->first ] = Rewriter::rewrite( simplify( it->second ) ); + } + bool retVal = false; + if( doRewrite && !d_macro_defs.empty() ){ + //now, rewrite based on macro definitions + for( size_t i=0; i<assertions.size(); i++ ){ + Node prev = assertions[i]; + assertions[i] = simplify( assertions[i] ); + if( prev!=assertions[i] ){ + assertions[i] = Rewriter::rewrite( assertions[i] ); + Trace("macros-rewrite") << "Rewrite " << prev << " to " << assertions[i] << std::endl; + retVal = true; + } + } + } + return retVal; +} + +bool QuantifierMacros::contains( Node n, Node n_s ){ + if( n==n_s ){ + return true; + }else{ + for( size_t i=0; i<n.getNumChildren(); i++ ){ + if( contains( n[i], n_s ) ){ + return true; + } + } + return false; + } +} + +bool QuantifierMacros::containsBadOp( Node n, Node n_op ){ + if( n!=n_op ){ + if( n.getKind()==APPLY_UF ){ + Node op = n.getOperator(); + if( op==n_op.getOperator() ){ + return true; + } + if( d_macro_def_cases.find( op )!=d_macro_def_cases.end() && !d_macro_def_cases[op].empty() ){ + return true; + } + } + for( size_t i=0; i<n.getNumChildren(); i++ ){ + if( containsBadOp( n[i], n_op ) ){ + return true; + } + } + } + return false; +} + +bool QuantifierMacros::isMacroLiteral( Node n, bool pol ){ + return pol && n.getKind()==EQUAL;//( n.getKind()==EQUAL || n.getKind()==IFF ); +} + +void QuantifierMacros::getMacroCandidates( Node n, std::vector< Node >& candidates ){ + if( n.getKind()==APPLY_UF ){ + candidates.push_back( n ); + }else if( n.getKind()==PLUS ){ + for( size_t i=0; i<n.getNumChildren(); i++ ){ + getMacroCandidates( n[i], candidates ); + } + }else if( n.getKind()==MULT ){ + //if the LHS is a constant + if( n.getNumChildren()==2 && n[0].isConst() ){ + getMacroCandidates( n[1], candidates ); + } + } +} + +Node QuantifierMacros::solveInEquality( Node n, Node lit ){ + if( lit.getKind()==IFF || lit.getKind()==EQUAL ){ + //return the opposite side of the equality if defined that way + for( int i=0; i<2; i++ ){ + if( lit[i]==n ){ + return lit[ i==0 ? 1 : 0]; + } + } + //must solve for term n in the literal lit + if( lit[0].getType().isInteger() || lit[0].getType().isReal() ){ + Node coeff; + Node term; + //could be solved for on LHS + if( lit[0].getKind()==MULT && lit[0][1]==n ){ + Assert( lit[0][0].isConst() ); + term = lit[1]; + coeff = lit[0][0]; + }else{ + Assert( lit[1].getKind()==PLUS ); + std::vector< Node > plus_children; + //find monomial with n + for( size_t j=0; j<lit[1].getNumChildren(); j++ ){ + if( lit[1][j]==n ){ + Assert( coeff.isNull() ); + coeff = NodeManager::currentNM()->mkConst( Rational(1) ); + }else if( lit[1][j].getKind()==MULT && lit[1][j][1]==n ){ + Assert( coeff.isNull() ); + Assert( lit[1][j][0].isConst() ); + coeff = lit[1][j][0]; + }else{ + plus_children.push_back( lit[1][j] ); + } + } + if( !coeff.isNull() ){ + term = NodeManager::currentNM()->mkNode( PLUS, plus_children ); + term = NodeManager::currentNM()->mkNode( MINUS, lit[0], term ); + } + } + if( !coeff.isNull() ){ + coeff = NodeManager::currentNM()->mkConst( Rational(1) / coeff.getConst<Rational>() ); + term = NodeManager::currentNM()->mkNode( MULT, coeff, term ); + term = Rewriter::rewrite( term ); + return term; + } + } + } + Trace("macros-debug") << "Cannot find for " << lit << " " << n << std::endl; + return Node::null(); +} + +bool QuantifierMacros::isConsistentDefinition( Node op, Node cond, Node def ){ + if( d_macro_def_cases[op].empty() || ( cond.isNull() && !d_macro_def_cases[op][0].first.isNull() ) ){ + return true; + }else{ + return false; + } +} + +bool QuantifierMacros::getFreeVariables( Node n, std::vector< Node >& v_quant, std::vector< Node >& vars, bool retOnly ){ + if( std::find( v_quant.begin(), v_quant.end(), n )!=v_quant.end() ){ + if( std::find( vars.begin(), vars.end(), n )==vars.end() ){ + if( retOnly ){ + return true; + }else{ + vars.push_back( n ); + } + } + } + for( size_t i=0; i<n.getNumChildren(); i++ ){ + if( getFreeVariables( n[i], v_quant, vars, retOnly ) ){ + return true; + } + } + return false; +} + +bool QuantifierMacros::getSubstitution( std::vector< Node >& v_quant, std::map< Node, Node >& solved, + std::vector< Node >& vars, std::vector< Node >& subs, bool reqComplete ){ + bool success = true; + for( size_t a=0; a<v_quant.size(); a++ ){ + if( !solved[ v_quant[a] ].isNull() ){ + vars.push_back( v_quant[a] ); + subs.push_back( solved[ v_quant[a] ] ); + }else{ + if( reqComplete ){ + success = false; + break; + } + } + } + return success; +} + +void QuantifierMacros::process( Node n, bool pol, std::vector< Node >& args, Node f ){ + if( n.getKind()==NOT ){ + process( n[0], !pol, args, f ); + }else if( n.getKind()==AND || n.getKind()==OR || n.getKind()==IMPLIES ){ + //bool favorPol = (n.getKind()==AND)==pol; + //conditional? + }else if( n.getKind()==ITE ){ + //can not do anything + }else{ + //literal case + if( isMacroLiteral( n, pol ) ){ + std::vector< Node > candidates; + for( size_t i=0; i<n.getNumChildren(); i++ ){ + getMacroCandidates( n[i], candidates ); + } + for( size_t i=0; i<candidates.size(); i++ ){ + Node m = candidates[i]; + Node op = m.getOperator(); + if( !containsBadOp( n, m ) ){ + std::vector< Node > fvs; + getFreeVariables( m, args, fvs, false ); + //get definition and condition + Node n_def = solveInEquality( m, n ); //definition for the macro + //definition must exist and not contain any free variables apart from fvs + if( !n_def.isNull() && !getFreeVariables( n_def, args, fvs, true ) ){ + Node n_cond; //condition when this definition holds + //conditional must not contain any free variables apart from fvs + if( n_cond.isNull() || !getFreeVariables( n_cond, args, fvs, true ) ){ + Trace("macros") << m << " is possible macro in " << f << std::endl; + //now we must rewrite candidates[i] to a term of form g( x1, ..., xn ) where + // x1 ... xn are distinct variables + if( d_macro_basis[op].empty() ){ + for( size_t a=0; a<m.getNumChildren(); a++ ){ + std::stringstream ss; + ss << "mda_" << op << "_$$"; + Node v = NodeManager::currentNM()->mkSkolem( ss.str(), m[a].getType(), "created during macro definition recognition" ); + d_macro_basis[op].push_back( v ); + } + } + std::vector< Node > eq; + for( size_t a=0; a<m.getNumChildren(); a++ ){ + eq.push_back( m[a] ); + } + //solve system of equations "d_macro_basis[op] = m" for variables in fvs + std::map< Node, Node > solved; + //solve obvious cases first + for( size_t a=0; a<eq.size(); a++ ){ + if( std::find( fvs.begin(), fvs.end(), eq[a] )!=fvs.end() ){ + if( solved[ eq[a] ].isNull() ){ + solved[ eq[a] ] = d_macro_basis[op][a]; + } + } + } + //now, apply substitution for obvious cases + std::vector< Node > vars; + std::vector< Node > subs; + getSubstitution( fvs, solved, vars, subs, false ); + for( size_t a=0; a<eq.size(); a++ ){ + eq[a] = eq[a].substitute( vars.begin(), vars.end(), subs.begin(), subs.end() ); + } + + Trace("macros-eq") << "Solve system of equations : " << std::endl; + for( size_t a=0; a<m.getNumChildren(); a++ ){ + if( d_macro_basis[op][a]!=eq[a] ){ + Trace("macros-eq") << " " << d_macro_basis[op][a] << " = " << eq[a] << std::endl; + } + } + Trace("macros-eq") << " for "; + for( size_t a=0; a<fvs.size(); a++ ){ + if( solved[ fvs[a] ].isNull() ){ + Trace("macros-eq") << fvs[a] << " "; + } + } + Trace("macros-eq") << std::endl; + //DO_THIS + + + vars.clear(); + subs.clear(); + if( getSubstitution( fvs, solved, vars, subs, true ) ){ + //build condition + std::vector< Node > conds; + if( !n_cond.isNull() ){ + //must apply substitution obtained from solving system of equations to original condition + n_cond = n_cond.substitute( vars.begin(), vars.end(), subs.begin(), subs.end() ); + conds.push_back( n_cond ); + } + for( size_t a=0; a<eq.size(); a++ ){ + //collect conditions based on solving argument's system of equations + if( d_macro_basis[op][a]!=eq[a] ){ + conds.push_back( NodeManager::currentNM()->mkNode( eq[a].getType().isBoolean() ? IFF : EQUAL, d_macro_basis[op][a], eq[a] ) ); + } + } + //build the condition + if( !conds.empty() ){ + n_cond = conds.size()==1 ? conds[0] : NodeManager::currentNM()->mkNode( AND, conds ); + } + //apply the substitution to the + n_def = n_def.substitute( vars.begin(), vars.end(), subs.begin(), subs.end() ); + //now see if definition is consistent with others + if( isConsistentDefinition( op, n_cond, n_def ) ){ + //must clear if it is a base definition + if( n_cond.isNull() ){ + d_macro_def_cases[ op ].clear(); + } + d_macro_def_cases[ op ].push_back( std::pair< Node, Node >( n_cond, n_def ) ); + } + } + } + } + } + } + } + } +} + +Node QuantifierMacros::simplify( Node n ){ + Trace("macros-debug") << "simplify " << n << std::endl; + std::vector< Node > children; + bool childChanged = false; + for( size_t i=0; i<n.getNumChildren(); i++ ){ + Node nn = simplify( n[i] ); + children.push_back( nn ); + childChanged = childChanged || nn!=n[i]; + } + if( n.getKind()==APPLY_UF ){ + Node op = n.getOperator(); + if( d_macro_defs.find( op )!=d_macro_defs.end() && !d_macro_defs[op].isNull() ){ + //do substitution + Node ret = d_macro_defs[op]; + ret = ret.substitute( d_macro_basis[op].begin(), d_macro_basis[op].end(), children.begin(), children.end() ); + return ret; + } + } + if( childChanged ){ + if( n.getMetaKind() == kind::metakind::PARAMETERIZED ){ + children.insert( children.begin(), n.getOperator() ); + } + return NodeManager::currentNM()->mkNode( n.getKind(), children ); + }else{ + return n; + } +} diff --git a/src/theory/quantifiers/macros.h b/src/theory/quantifiers/macros.h index b1fbb3e68..140f02966 100755..100644 --- a/src/theory/quantifiers/macros.h +++ b/src/theory/quantifiers/macros.h @@ -1,62 +1,62 @@ -/********************* */
-/*! \file macros.h
- ** \verbatim
- ** Original author: ajreynol
- ** Major contributors: none
- ** Minor contributors (to current version): none
- ** This file is part of the CVC4 prototype.
- ** Copyright (c) 2009-2012 New York University and The University of Iowa
- ** See the file COPYING in the top-level source directory for licensing
- ** information.\endverbatim
- **
- ** \brief Pre-process step for detecting quantifier macro definitions
- **/
-
-#include "cvc4_private.h"
-
-#ifndef __CVC4__QUANTIFIERS_MACROS_H
-#define __CVC4__QUANTIFIERS_MACROS_H
-
-#include <iostream>
-#include <string>
-#include <vector>
-#include <map>
-#include "expr/node.h"
-#include "expr/type_node.h"
-
-namespace CVC4 {
-namespace theory {
-namespace quantifiers {
-
-class QuantifierMacros{
-private:
- void process( Node n, bool pol, std::vector< Node >& args, Node f );
- bool contains( Node n, Node n_s );
- bool containsBadOp( Node n, Node n_op );
- bool isMacroLiteral( Node n, bool pol );
- void getMacroCandidates( Node n, std::vector< Node >& candidates );
- Node solveInEquality( Node n, Node lit );
- bool isConsistentDefinition( Node op, Node cond, Node def );
- bool getFreeVariables( Node n, std::vector< Node >& v_quant, std::vector< Node >& vars, bool retOnly );
- bool getSubstitution( std::vector< Node >& v_quant, std::map< Node, Node >& solved,
- std::vector< Node >& vars, std::vector< Node >& subs, bool reqComplete );
- //map from operators to macro basis terms
- std::map< Node, std::vector< Node > > d_macro_basis;
- //map from operators to map from conditions to definition cases
- std::map< Node, std::vector< std::pair< Node, Node > > > d_macro_def_cases;
- //map from operators to macro definition
- std::map< Node, Node > d_macro_defs;
-private:
- Node simplify( Node n );
-public:
- QuantifierMacros(){}
- ~QuantifierMacros(){}
-
- bool simplify( std::vector< Node >& assertions, bool doRewrite = false );
-};
-
-}
-}
-}
-
-#endif
+/********************* */ +/*! \file macros.h + ** \verbatim + ** Original author: Andrew Reynolds <andrew.j.reynolds@gmail.com> + ** Major contributors: Morgan Deters <mdeters@cs.nyu.edu> + ** Minor contributors (to current version): none + ** This file is part of the CVC4 project. + ** Copyright (c) 2009-2013 New York University and The University of Iowa + ** See the file COPYING in the top-level source directory for licensing + ** information.\endverbatim + ** + ** \brief Pre-process step for detecting quantifier macro definitions + **/ + +#include "cvc4_private.h" + +#ifndef __CVC4__QUANTIFIERS_MACROS_H +#define __CVC4__QUANTIFIERS_MACROS_H + +#include <iostream> +#include <string> +#include <vector> +#include <map> +#include "expr/node.h" +#include "expr/type_node.h" + +namespace CVC4 { +namespace theory { +namespace quantifiers { + +class QuantifierMacros{ +private: + void process( Node n, bool pol, std::vector< Node >& args, Node f ); + bool contains( Node n, Node n_s ); + bool containsBadOp( Node n, Node n_op ); + bool isMacroLiteral( Node n, bool pol ); + void getMacroCandidates( Node n, std::vector< Node >& candidates ); + Node solveInEquality( Node n, Node lit ); + bool isConsistentDefinition( Node op, Node cond, Node def ); + bool getFreeVariables( Node n, std::vector< Node >& v_quant, std::vector< Node >& vars, bool retOnly ); + bool getSubstitution( std::vector< Node >& v_quant, std::map< Node, Node >& solved, + std::vector< Node >& vars, std::vector< Node >& subs, bool reqComplete ); + //map from operators to macro basis terms + std::map< Node, std::vector< Node > > d_macro_basis; + //map from operators to map from conditions to definition cases + std::map< Node, std::vector< std::pair< Node, Node > > > d_macro_def_cases; + //map from operators to macro definition + std::map< Node, Node > d_macro_defs; +private: + Node simplify( Node n ); +public: + QuantifierMacros(){} + ~QuantifierMacros(){} + + bool simplify( std::vector< Node >& assertions, bool doRewrite = false ); +}; + +} +} +} + +#endif diff --git a/src/theory/quantifiers/model_builder.cpp b/src/theory/quantifiers/model_builder.cpp index 2f44140c2..d8b154b95 100644 --- a/src/theory/quantifiers/model_builder.cpp +++ b/src/theory/quantifiers/model_builder.cpp @@ -368,15 +368,32 @@ void ModelEngineBuilderDefault::reset( FirstOrderModel* fm ){ d_op_selection_terms.clear(); } + +int ModelEngineBuilderDefault::getSelectionScore( std::vector< Node >& uf_terms ) { + /* + size_t maxChildren = 0; + for( size_t i=0; i<uf_terms.size(); i++ ){ + if( uf_terms[i].getNumChildren()>maxChildren ){ + maxChildren = uf_terms[i].getNumChildren(); + } + } + //TODO: look at how many entries they have? + return (int)maxChildren; + */ + return 0; +} + void ModelEngineBuilderDefault::analyzeQuantifier( FirstOrderModel* fm, Node f ){ Debug("fmf-model-prefs") << "Analyze quantifier " << f << std::endl; //the pro/con preferences for this quantifier std::vector< Node > pro_con[2]; //the terms in the selection literal we choose std::vector< Node > selectionLitTerms; + Trace("inst-gen-debug-quant") << "Inst-gen analyze " << f << std::endl; //for each asserted quantifier f, // - determine selection literals // - check which function/predicates have good and bad definitions for satisfying f + int selectLitScore = -1; QuantPhaseReq* qpr = d_qe->getPhaseRequirements( f ); for( std::map< Node, bool >::iterator it = qpr->d_phase_reqs.begin(); it != qpr->d_phase_reqs.end(); ++it ){ //the literal n is phase-required for quantifier f @@ -433,10 +450,18 @@ void ModelEngineBuilderDefault::analyzeQuantifier( FirstOrderModel* fm, Node f ) selectLit = true; } } + //also check if it is naturally a better literal + if( !selectLit ){ + int score = getSelectionScore( uf_terms ); + //Trace("inst-gen-debug") << "Check " << score << " < " << selectLitScore << std::endl; + selectLit = score<selectLitScore; + } //see if we wish to choose this as a selection literal d_quant_selection_lit_candidates[f].push_back( value ? n : n.notNode() ); if( selectLit ){ + selectLitScore = getSelectionScore( uf_terms ); Trace("inst-gen-debug") << "Choose selection literal " << gn << std::endl; + Trace("inst-gen-debug") << " flags: " << isConst << " " << selectLitConstraints << " " << selectLitScore << std::endl; d_quant_selection_lit[f] = value ? n : n.notNode(); selectionLitTerms.clear(); selectionLitTerms.insert( selectionLitTerms.begin(), uf_terms.begin(), uf_terms.end() ); @@ -466,7 +491,7 @@ void ModelEngineBuilderDefault::analyzeQuantifier( FirstOrderModel* fm, Node f ) d_op_selection_terms[ selectionLitTerms[i].getOperator() ].push_back( selectionLitTerms[i] ); } }else{ - Trace("inst-gen-warn") << "WARNING: " << f << " has no selection literals (is the body of f clausified?)" << std::endl; + Trace("inst-gen-warn") << "WARNING: " << f << " has no selection literals" << std::endl; } //process information about requirements and preferences of quantifier f if( d_quant_sat.find( f )!=d_quant_sat.end() ){ @@ -526,7 +551,7 @@ int ModelEngineBuilderDefault::doInstGen( FirstOrderModel* fm, Node f ){ //if applicable, try to add exceptions here if( !tr_terms.empty() ){ //make a trigger for these terms, add instantiations - inst::Trigger* tr = inst::Trigger::mkTrigger( d_qe, f, tr_terms ); + inst::Trigger* tr = inst::Trigger::mkTrigger( d_qe, f, tr_terms, 0, true, inst::Trigger::TR_MAKE_NEW, options::smartTriggers() ); //Notice() << "Trigger = " << (*tr) << std::endl; tr->resetInstantiationRound(); tr->reset( Node::null() ); diff --git a/src/theory/quantifiers/model_builder.h b/src/theory/quantifiers/model_builder.h index 908cfca2b..5490d17dd 100644 --- a/src/theory/quantifiers/model_builder.h +++ b/src/theory/quantifiers/model_builder.h @@ -155,6 +155,8 @@ private: ///information for (old) InstGen std::map< Node, Node > d_term_selection_lit; //map from operators to terms that appear in selection literals std::map< Node, std::vector< Node > > d_op_selection_terms; + //get selection score + int getSelectionScore( std::vector< Node >& uf_terms ); protected: //reset void reset( FirstOrderModel* fm ); diff --git a/src/theory/quantifiers/model_engine.cpp b/src/theory/quantifiers/model_engine.cpp index bf6ea11f0..1522d0828 100644 --- a/src/theory/quantifiers/model_engine.cpp +++ b/src/theory/quantifiers/model_engine.cpp @@ -73,9 +73,8 @@ void ModelEngine::check( Theory::Effort e ){ if( addedLemmas==0 ){ Trace("model-engine-debug") << "Verify uf ss is minimal..." << std::endl; //let the strong solver verify that the model is minimal - uf::StrongSolverTheoryUf* uf_ss = ((uf::TheoryUF*)d_quantEngine->getTheoryEngine()->theoryOf( THEORY_UF ))->getStrongSolver(); //for debugging, this will if there are terms in the model that the strong solver was not notified of - uf_ss->debugModel( fm ); + ((uf::TheoryUF*)d_quantEngine->getTheoryEngine()->theoryOf( THEORY_UF ))->getStrongSolver()->debugModel( fm ); Trace("model-engine-debug") << "Check model..." << std::endl; d_incomplete_check = false; //print debug @@ -164,7 +163,7 @@ int ModelEngine::checkModel( int checkOption ){ Trace("model-engine-debug") << " "; for( size_t i=0; i<it->second.size(); i++ ){ //Trace("model-engine-debug") << it->second[i] << " "; - Node r = ((EqualityQueryQuantifiersEngine*)d_quantEngine->getEqualityQuery())->getInternalRepresentative( it->second[i] ); + Node r = ((EqualityQueryQuantifiersEngine*)d_quantEngine->getEqualityQuery())->getRepresentative( it->second[i] ); Trace("model-engine-debug") << r << " "; } Trace("model-engine-debug") << std::endl; @@ -225,7 +224,7 @@ int ModelEngine::checkModel( int checkOption ){ int ModelEngine::exhaustiveInstantiate( Node f, bool useRelInstDomain ){ int addedLemmas = 0; - Debug("inst-fmf-ei") << "Exhaustive instantiate " << f << "..." << std::endl; + Trace("inst-fmf-ei") << "Exhaustive instantiate " << f << "..." << std::endl; Debug("inst-fmf-ei") << " Instantiation Constants: "; for( size_t i=0; i<f[0].getNumChildren(); i++ ){ Debug("inst-fmf-ei") << d_quantEngine->getTermDatabase()->getInstantiationConstant( f, i ) << " "; @@ -299,12 +298,12 @@ int ModelEngine::exhaustiveInstantiate( Node f, bool useRelInstDomain ){ relevantInst = relevantInst * (int)riter.d_domain[i].size(); } d_relevantLemmas += relevantInst; - Debug("inst-fmf-ei") << "Finished: " << std::endl; + Trace("inst-fmf-ei") << "Finished: " << std::endl; //Debug("inst-fmf-ei") << " Inst Total: " << totalInst << std::endl; - Debug("inst-fmf-ei") << " Inst Relevant: " << relevantInst << std::endl; - Debug("inst-fmf-ei") << " Inst Tried: " << triedLemmas << std::endl; - Debug("inst-fmf-ei") << " Inst Added: " << addedLemmas << std::endl; - Debug("inst-fmf-ei") << " # Tests: " << tests << std::endl; + Trace("inst-fmf-ei") << " Inst Relevant: " << relevantInst << std::endl; + Trace("inst-fmf-ei") << " Inst Tried: " << triedLemmas << std::endl; + Trace("inst-fmf-ei") << " Inst Added: " << addedLemmas << std::endl; + Trace("inst-fmf-ei") << " # Tests: " << tests << std::endl; if( addedLemmas>1000 ){ Trace("model-engine-warn") << "WARNING: many instantiations produced for " << f << ": " << std::endl; //Trace("model-engine-warn") << " Inst Total: " << totalInst << std::endl; diff --git a/src/theory/quantifiers/options b/src/theory/quantifiers/options index bc45e6051..7a3687dd5 100644 --- a/src/theory/quantifiers/options +++ b/src/theory/quantifiers/options @@ -37,6 +37,9 @@ option cnfQuant --cnf-quant bool :default false option preSkolemQuant --pre-skolem-quant bool :default false apply skolemization eagerly to bodies of quantified formulas +# Whether to perform agressive miniscoping +option aggressiveMiniscopeQuant --ag-miniscope-quant bool :default false + perform aggressive miniscoping for quantifiers # Whether to perform quantifier macro expansion option macrosQuant --macros-quant bool :default false perform quantifiers macro expansions @@ -45,8 +48,8 @@ option macrosQuant --macros-quant bool :default false option smartTriggers /--disable-smart-triggers bool :default true disable smart triggers # Whether to use relevent triggers -option relevantTriggers /--relevant-triggers bool :default true - prefer triggers that are more relevant based on SInE style method +option relevantTriggers --relevant-triggers bool :default true + prefer triggers that are more relevant based on SInE style analysis # Whether to consider terms in the bodies of quantifiers for matching option registerQuantBodyTerms --register-quant-body-terms bool :default false @@ -65,13 +68,14 @@ option cbqi --enable-cbqi/--disable-cbqi bool :default false turns on counterexample-based quantifier instantiation [off by default] /turns off counterexample-based quantifier instantiation + option userPatternsQuant /--ignore-user-patterns bool :default true ignore user-provided patterns for quantifier instantiation option flipDecision --flip-decision/ bool :default false turns on flip decision heuristic -option internalReps --disable-quant-internal-reps/ bool :default true +option internalReps /--disable-quant-internal-reps bool :default true disables instantiating with representatives chosen by quantifiers engine option finiteModelFind --finite-model-find bool :default false @@ -94,6 +98,8 @@ option fmfInstGen /--disable-fmf-inst-gen bool :default true disable Inst-Gen instantiation techniques for finite model finding option fmfInstGenOneQuantPerRound --fmf-inst-gen-one-quant-per-round bool :default false only perform Inst-Gen instantiation techniques on one quantifier per round +option fmfFreshDistConst --fmf-fresh-dc bool :default false + use fresh distinguished representative when applying Inst-Gen techniques option axiomInstMode --axiom-inst=MODE CVC4::theory::quantifiers::AxiomInstMode :default CVC4::theory::quantifiers::AXIOM_INST_MODE_DEFAULT :include "theory/quantifiers/modes.h" :handler CVC4::theory::quantifiers::stringToAxiomInstMode :handler-include "theory/quantifiers/options_handlers.h" policy for instantiating axioms diff --git a/src/theory/quantifiers/quant_util.cpp b/src/theory/quantifiers/quant_util.cpp index d1b0e0fea..9e4a2a14a 100755..100644 --- a/src/theory/quantifiers/quant_util.cpp +++ b/src/theory/quantifiers/quant_util.cpp @@ -1,145 +1,145 @@ -/********************* */
-/*! \file quant_util.cpp
- ** \verbatim
- ** Original author: ajreynol
- ** Major contributors: bobot, mdeters
- ** Minor contributors (to current version): none
- ** This file is part of the CVC4 prototype.
- ** Copyright (c) 2009-2012 New York University and The University of Iowa
- ** See the file COPYING in the top-level source directory for licensing
- ** information.\endverbatim
- **
- ** \brief Implementation of quantifier utilities
- **/
-
-#include "theory/quantifiers/quant_util.h"
-#include "theory/quantifiers/inst_match.h"
-#include "theory/quantifiers/term_database.h"
-
-using namespace std;
-using namespace CVC4;
-using namespace CVC4::kind;
-using namespace CVC4::context;
-using namespace CVC4::theory;
-
-void QuantRelevance::registerQuantifier( Node f ){
- //compute symbols in f
- std::vector< Node > syms;
- computeSymbols( f[1], syms );
- d_syms[f].insert( d_syms[f].begin(), syms.begin(), syms.end() );
- //set initial relevance
- int minRelevance = -1;
- for( int i=0; i<(int)syms.size(); i++ ){
- d_syms_quants[ syms[i] ].push_back( f );
- int r = getRelevance( syms[i] );
- if( r!=-1 && ( minRelevance==-1 || r<minRelevance ) ){
- minRelevance = r;
- }
- }
- if( minRelevance!=-1 ){
- setRelevance( f, minRelevance+1 );
- }
-}
-
-
-/** compute symbols */
-void QuantRelevance::computeSymbols( Node n, std::vector< Node >& syms ){
- if( n.getKind()==APPLY_UF ){
- Node op = n.getOperator();
- if( std::find( syms.begin(), syms.end(), op )==syms.end() ){
- syms.push_back( op );
- }
- }
- if( n.getKind()!=FORALL ){
- for( int i=0; i<(int)n.getNumChildren(); i++ ){
- computeSymbols( n[i], syms );
- }
- }
-}
-
-/** set relevance */
-void QuantRelevance::setRelevance( Node s, int r ){
- if( d_computeRel ){
- int rOld = getRelevance( s );
- if( rOld==-1 || r<rOld ){
- d_relevance[s] = r;
- if( s.getKind()==FORALL ){
- for( int i=0; i<(int)d_syms[s].size(); i++ ){
- setRelevance( d_syms[s][i], r );
- }
- }else{
- for( int i=0; i<(int)d_syms_quants[s].size(); i++ ){
- setRelevance( d_syms_quants[s][i], r+1 );
- }
- }
- }
- }
-}
-
-
-QuantPhaseReq::QuantPhaseReq( Node n, bool computeEq ){
- std::map< Node, int > phaseReqs2;
- computePhaseReqs( n, false, phaseReqs2 );
- for( std::map< Node, int >::iterator it = phaseReqs2.begin(); it != phaseReqs2.end(); ++it ){
- if( it->second==1 ){
- d_phase_reqs[ it->first ] = true;
- }else if( it->second==-1 ){
- d_phase_reqs[ it->first ] = false;
- }
- }
- Debug("inst-engine-phase-req") << "Phase requirements for " << n << ":" << std::endl;
- //now, compute if any patterns are equality required
- if( computeEq ){
- for( std::map< Node, bool >::iterator it = d_phase_reqs.begin(); it != d_phase_reqs.end(); ++it ){
- Debug("inst-engine-phase-req") << " " << it->first << " -> " << it->second << std::endl;
- if( it->first.getKind()==EQUAL ){
- if( it->first[0].hasAttribute(InstConstantAttribute()) ){
- if( !it->first[1].hasAttribute(InstConstantAttribute()) ){
- d_phase_reqs_equality_term[ it->first[0] ] = it->first[1];
- d_phase_reqs_equality[ it->first[0] ] = it->second;
- Debug("inst-engine-phase-req") << " " << it->first[0] << ( it->second ? " == " : " != " ) << it->first[1] << std::endl;
- }
- }else if( it->first[1].hasAttribute(InstConstantAttribute()) ){
- d_phase_reqs_equality_term[ it->first[1] ] = it->first[0];
- d_phase_reqs_equality[ it->first[1] ] = it->second;
- Debug("inst-engine-phase-req") << " " << it->first[1] << ( it->second ? " == " : " != " ) << it->first[0] << std::endl;
- }
- }
- }
- }
-}
-
-void QuantPhaseReq::computePhaseReqs( Node n, bool polarity, std::map< Node, int >& phaseReqs ){
- bool newReqPol = false;
- bool newPolarity;
- if( n.getKind()==NOT ){
- newReqPol = true;
- newPolarity = !polarity;
- }else if( n.getKind()==OR || n.getKind()==IMPLIES ){
- if( !polarity ){
- newReqPol = true;
- newPolarity = false;
- }
- }else if( n.getKind()==AND ){
- if( polarity ){
- newReqPol = true;
- newPolarity = true;
- }
- }else{
- int val = polarity ? 1 : -1;
- if( phaseReqs.find( n )==phaseReqs.end() ){
- phaseReqs[n] = val;
- }else if( val!=phaseReqs[n] ){
- phaseReqs[n] = 0;
- }
- }
- if( newReqPol ){
- for( int i=0; i<(int)n.getNumChildren(); i++ ){
- if( n.getKind()==IMPLIES && i==0 ){
- computePhaseReqs( n[i], !newPolarity, phaseReqs );
- }else{
- computePhaseReqs( n[i], newPolarity, phaseReqs );
- }
- }
- }
-}
+/********************* */ +/*! \file quant_util.cpp + ** \verbatim + ** Original author: Andrew Reynolds <andrew.j.reynolds@gmail.com> + ** Major contributors: Morgan Deters <mdeters@cs.nyu.edu> + ** Minor contributors (to current version): none + ** This file is part of the CVC4 project. + ** Copyright (c) 2009-2013 New York University and The University of Iowa + ** See the file COPYING in the top-level source directory for licensing + ** information.\endverbatim + ** + ** \brief Implementation of quantifier utilities + **/ + +#include "theory/quantifiers/quant_util.h" +#include "theory/quantifiers/inst_match.h" +#include "theory/quantifiers/term_database.h" + +using namespace std; +using namespace CVC4; +using namespace CVC4::kind; +using namespace CVC4::context; +using namespace CVC4::theory; + +void QuantRelevance::registerQuantifier( Node f ){ + //compute symbols in f + std::vector< Node > syms; + computeSymbols( f[1], syms ); + d_syms[f].insert( d_syms[f].begin(), syms.begin(), syms.end() ); + //set initial relevance + int minRelevance = -1; + for( int i=0; i<(int)syms.size(); i++ ){ + d_syms_quants[ syms[i] ].push_back( f ); + int r = getRelevance( syms[i] ); + if( r!=-1 && ( minRelevance==-1 || r<minRelevance ) ){ + minRelevance = r; + } + } + if( minRelevance!=-1 ){ + setRelevance( f, minRelevance+1 ); + } +} + + +/** compute symbols */ +void QuantRelevance::computeSymbols( Node n, std::vector< Node >& syms ){ + if( n.getKind()==APPLY_UF ){ + Node op = n.getOperator(); + if( std::find( syms.begin(), syms.end(), op )==syms.end() ){ + syms.push_back( op ); + } + } + if( n.getKind()!=FORALL ){ + for( int i=0; i<(int)n.getNumChildren(); i++ ){ + computeSymbols( n[i], syms ); + } + } +} + +/** set relevance */ +void QuantRelevance::setRelevance( Node s, int r ){ + if( d_computeRel ){ + int rOld = getRelevance( s ); + if( rOld==-1 || r<rOld ){ + d_relevance[s] = r; + if( s.getKind()==FORALL ){ + for( int i=0; i<(int)d_syms[s].size(); i++ ){ + setRelevance( d_syms[s][i], r ); + } + }else{ + for( int i=0; i<(int)d_syms_quants[s].size(); i++ ){ + setRelevance( d_syms_quants[s][i], r+1 ); + } + } + } + } +} + + +QuantPhaseReq::QuantPhaseReq( Node n, bool computeEq ){ + std::map< Node, int > phaseReqs2; + computePhaseReqs( n, false, phaseReqs2 ); + for( std::map< Node, int >::iterator it = phaseReqs2.begin(); it != phaseReqs2.end(); ++it ){ + if( it->second==1 ){ + d_phase_reqs[ it->first ] = true; + }else if( it->second==-1 ){ + d_phase_reqs[ it->first ] = false; + } + } + Debug("inst-engine-phase-req") << "Phase requirements for " << n << ":" << std::endl; + //now, compute if any patterns are equality required + if( computeEq ){ + for( std::map< Node, bool >::iterator it = d_phase_reqs.begin(); it != d_phase_reqs.end(); ++it ){ + Debug("inst-engine-phase-req") << " " << it->first << " -> " << it->second << std::endl; + if( it->first.getKind()==EQUAL ){ + if( it->first[0].hasAttribute(InstConstantAttribute()) ){ + if( !it->first[1].hasAttribute(InstConstantAttribute()) ){ + d_phase_reqs_equality_term[ it->first[0] ] = it->first[1]; + d_phase_reqs_equality[ it->first[0] ] = it->second; + Debug("inst-engine-phase-req") << " " << it->first[0] << ( it->second ? " == " : " != " ) << it->first[1] << std::endl; + } + }else if( it->first[1].hasAttribute(InstConstantAttribute()) ){ + d_phase_reqs_equality_term[ it->first[1] ] = it->first[0]; + d_phase_reqs_equality[ it->first[1] ] = it->second; + Debug("inst-engine-phase-req") << " " << it->first[1] << ( it->second ? " == " : " != " ) << it->first[0] << std::endl; + } + } + } + } +} + +void QuantPhaseReq::computePhaseReqs( Node n, bool polarity, std::map< Node, int >& phaseReqs ){ + bool newReqPol = false; + bool newPolarity; + if( n.getKind()==NOT ){ + newReqPol = true; + newPolarity = !polarity; + }else if( n.getKind()==OR || n.getKind()==IMPLIES ){ + if( !polarity ){ + newReqPol = true; + newPolarity = false; + } + }else if( n.getKind()==AND ){ + if( polarity ){ + newReqPol = true; + newPolarity = true; + } + }else{ + int val = polarity ? 1 : -1; + if( phaseReqs.find( n )==phaseReqs.end() ){ + phaseReqs[n] = val; + }else if( val!=phaseReqs[n] ){ + phaseReqs[n] = 0; + } + } + if( newReqPol ){ + for( int i=0; i<(int)n.getNumChildren(); i++ ){ + if( n.getKind()==IMPLIES && i==0 ){ + computePhaseReqs( n[i], !newPolarity, phaseReqs ); + }else{ + computePhaseReqs( n[i], newPolarity, phaseReqs ); + } + } + } +} diff --git a/src/theory/quantifiers/quant_util.h b/src/theory/quantifiers/quant_util.h index bb6855c47..85602dbab 100755..100644 --- a/src/theory/quantifiers/quant_util.h +++ b/src/theory/quantifiers/quant_util.h @@ -1,99 +1,99 @@ -/********************* */
-/*! \file quant_util.h
- ** \verbatim
- ** Original author: ajreynol
- ** Major contributors: none
- ** Minor contributors (to current version): mdeters, bobot
- ** This file is part of the CVC4 prototype.
- ** Copyright (c) 2009-2012 New York University and The University of Iowa
- ** See the file COPYING in the top-level source directory for licensing
- ** information.\endverbatim
- **
- ** \brief quantifier util
- **/
-
-#include "cvc4_private.h"
-
-#ifndef __CVC4__THEORY__QUANT_UTIL_H
-#define __CVC4__THEORY__QUANT_UTIL_H
-
-#include "theory/theory.h"
-#include "theory/uf/equality_engine.h"
-
-#include <ext/hash_set>
-#include <iostream>
-#include <map>
-
-namespace CVC4 {
-namespace theory {
-
-
-class QuantRelevance
-{
-private:
- /** for computing relavance */
- bool d_computeRel;
- /** map from quantifiers to symbols they contain */
- std::map< Node, std::vector< Node > > d_syms;
- /** map from symbols to quantifiers */
- std::map< Node, std::vector< Node > > d_syms_quants;
- /** relevance for quantifiers and symbols */
- std::map< Node, int > d_relevance;
- /** compute symbols */
- void computeSymbols( Node n, std::vector< Node >& syms );
-public:
- QuantRelevance( bool cr ) : d_computeRel( cr ){}
- ~QuantRelevance(){}
- /** register quantifier */
- void registerQuantifier( Node f );
- /** set relevance */
- void setRelevance( Node s, int r );
- /** get relevance */
- int getRelevance( Node s ) { return d_relevance.find( s )==d_relevance.end() ? -1 : d_relevance[s]; }
- /** get number of quantifiers for symbol s */
- int getNumQuantifiersForSymbol( Node s ) { return (int)d_syms_quants[s].size(); }
-};
-
-class QuantPhaseReq
-{
-private:
- /** helper functions compute phase requirements */
- void computePhaseReqs( Node n, bool polarity, std::map< Node, int >& phaseReqs );
-public:
- QuantPhaseReq( Node n, bool computeEq = false );
- ~QuantPhaseReq(){}
- /** is phase required */
- bool isPhaseReq( Node lit ) { return d_phase_reqs.find( lit )!=d_phase_reqs.end(); }
- /** get phase requirement */
- bool getPhaseReq( Node lit ) { return d_phase_reqs.find( lit )==d_phase_reqs.end() ? false : d_phase_reqs[ lit ]; }
- /** phase requirements for each quantifier for each instantiation literal */
- std::map< Node, bool > d_phase_reqs;
- std::map< Node, bool > d_phase_reqs_equality;
- std::map< Node, Node > d_phase_reqs_equality_term;
-};
-
-
-class EqualityQuery {
-public:
- EqualityQuery(){}
- virtual ~EqualityQuery(){};
- /** reset */
- virtual void reset() = 0;
- /** contains term */
- virtual bool hasTerm( Node a ) = 0;
- /** get the representative of the equivalence class of a */
- virtual Node getRepresentative( Node a ) = 0;
- /** returns true if a and b are equal in the current context */
- virtual bool areEqual( Node a, Node b ) = 0;
- /** returns true is a and b are disequal in the current context */
- virtual bool areDisequal( Node a, Node b ) = 0;
- /** get the equality engine associated with this query */
- virtual eq::EqualityEngine* getEngine() = 0;
- /** get the equivalence class of a */
- virtual void getEquivalenceClass( Node a, std::vector< Node >& eqc ) = 0;
-};/* class EqualityQuery */
-
-}
-}
-
-#endif
+/********************* */ +/*! \file quant_util.h + ** \verbatim + ** Original author: Andrew Reynolds <andrew.j.reynolds@gmail.com> + ** Major contributors: Morgan Deters <mdeters@cs.nyu.edu> + ** Minor contributors (to current version): none + ** This file is part of the CVC4 project. + ** Copyright (c) 2009-2013 New York University and The University of Iowa + ** See the file COPYING in the top-level source directory for licensing + ** information.\endverbatim + ** + ** \brief quantifier util + **/ + +#include "cvc4_private.h" + +#ifndef __CVC4__THEORY__QUANT_UTIL_H +#define __CVC4__THEORY__QUANT_UTIL_H + +#include "theory/theory.h" +#include "theory/uf/equality_engine.h" + +#include <ext/hash_set> +#include <iostream> +#include <map> + +namespace CVC4 { +namespace theory { + + +class QuantRelevance +{ +private: + /** for computing relavance */ + bool d_computeRel; + /** map from quantifiers to symbols they contain */ + std::map< Node, std::vector< Node > > d_syms; + /** map from symbols to quantifiers */ + std::map< Node, std::vector< Node > > d_syms_quants; + /** relevance for quantifiers and symbols */ + std::map< Node, int > d_relevance; + /** compute symbols */ + void computeSymbols( Node n, std::vector< Node >& syms ); +public: + QuantRelevance( bool cr ) : d_computeRel( cr ){} + ~QuantRelevance(){} + /** register quantifier */ + void registerQuantifier( Node f ); + /** set relevance */ + void setRelevance( Node s, int r ); + /** get relevance */ + int getRelevance( Node s ) { return d_relevance.find( s )==d_relevance.end() ? -1 : d_relevance[s]; } + /** get number of quantifiers for symbol s */ + int getNumQuantifiersForSymbol( Node s ) { return (int)d_syms_quants[s].size(); } +}; + +class QuantPhaseReq +{ +private: + /** helper functions compute phase requirements */ + void computePhaseReqs( Node n, bool polarity, std::map< Node, int >& phaseReqs ); +public: + QuantPhaseReq( Node n, bool computeEq = false ); + ~QuantPhaseReq(){} + /** is phase required */ + bool isPhaseReq( Node lit ) { return d_phase_reqs.find( lit )!=d_phase_reqs.end(); } + /** get phase requirement */ + bool getPhaseReq( Node lit ) { return d_phase_reqs.find( lit )==d_phase_reqs.end() ? false : d_phase_reqs[ lit ]; } + /** phase requirements for each quantifier for each instantiation literal */ + std::map< Node, bool > d_phase_reqs; + std::map< Node, bool > d_phase_reqs_equality; + std::map< Node, Node > d_phase_reqs_equality_term; +}; + + +class EqualityQuery { +public: + EqualityQuery(){} + virtual ~EqualityQuery(){}; + /** reset */ + virtual void reset() = 0; + /** contains term */ + virtual bool hasTerm( Node a ) = 0; + /** get the representative of the equivalence class of a */ + virtual Node getRepresentative( Node a ) = 0; + /** returns true if a and b are equal in the current context */ + virtual bool areEqual( Node a, Node b ) = 0; + /** returns true is a and b are disequal in the current context */ + virtual bool areDisequal( Node a, Node b ) = 0; + /** get the equality engine associated with this query */ + virtual eq::EqualityEngine* getEngine() = 0; + /** get the equivalence class of a */ + virtual void getEquivalenceClass( Node a, std::vector< Node >& eqc ) = 0; +};/* class EqualityQuery */ + +} +} + +#endif diff --git a/src/theory/quantifiers/quantifiers_attributes.cpp b/src/theory/quantifiers/quantifiers_attributes.cpp index 2f6dc47db..b00fe45f4 100644 --- a/src/theory/quantifiers/quantifiers_attributes.cpp +++ b/src/theory/quantifiers/quantifiers_attributes.cpp @@ -1,41 +1,41 @@ /********************* */ /*! \file quantifiers_attributes.cpp ** \verbatim - ** Original author: ajreynol - ** Major contributors: none + ** Original author: Andrew Reynolds <andrew.j.reynolds@gmail.com> + ** Major contributors: Morgan Deters <mdeters@cs.nyu.edu> ** Minor contributors (to current version): none - ** This file is part of the CVC4 prototype. - ** Copyright (c) 2009-2012 New York University and The University of Iowa + ** This file is part of the CVC4 project. + ** Copyright (c) 2009-2013 New York University and The University of Iowa ** See the file COPYING in the top-level source directory for licensing ** information.\endverbatim ** - ** \brief Implementation of QuantifiersAttributes class
- **/
-
-#include "theory/quantifiers/quantifiers_attributes.h"
-#include "theory/quantifiers/options.h"
-
-using namespace std;
-using namespace CVC4;
-using namespace CVC4::kind;
-using namespace CVC4::context;
-using namespace CVC4::theory;
-using namespace CVC4::theory::quantifiers;
-
-void QuantifiersAttributes::setUserAttribute( const std::string& attr, Node n ){
- if( n.getKind()==FORALL ){
- if( attr=="axiom" ){
- Trace("quant-attr") << "Set axiom " << n << std::endl;
- AxiomAttribute aa;
- n.setAttribute( aa, true );
- }else if( attr=="conjecture" ){
- Trace("quant-attr") << "Set conjecture " << n << std::endl;
- ConjectureAttribute ca;
- n.setAttribute( ca, true );
- }
- }else{
- for( size_t i=0; i<n.getNumChildren(); i++ ){
- setUserAttribute( attr, n[i] );
- }
- }
-}
+ ** \brief Implementation of QuantifiersAttributes class + **/ + +#include "theory/quantifiers/quantifiers_attributes.h" +#include "theory/quantifiers/options.h" + +using namespace std; +using namespace CVC4; +using namespace CVC4::kind; +using namespace CVC4::context; +using namespace CVC4::theory; +using namespace CVC4::theory::quantifiers; + +void QuantifiersAttributes::setUserAttribute( const std::string& attr, Node n ){ + if( n.getKind()==FORALL ){ + if( attr=="axiom" ){ + Trace("quant-attr") << "Set axiom " << n << std::endl; + AxiomAttribute aa; + n.setAttribute( aa, true ); + }else if( attr=="conjecture" ){ + Trace("quant-attr") << "Set conjecture " << n << std::endl; + ConjectureAttribute ca; + n.setAttribute( ca, true ); + } + }else{ + for( size_t i=0; i<n.getNumChildren(); i++ ){ + setUserAttribute( attr, n[i] ); + } + } +} diff --git a/src/theory/quantifiers/quantifiers_attributes.h b/src/theory/quantifiers/quantifiers_attributes.h index 88bac8bc9..8e8ebe97a 100644 --- a/src/theory/quantifiers/quantifiers_attributes.h +++ b/src/theory/quantifiers/quantifiers_attributes.h @@ -1,51 +1,51 @@ /********************* */ /*! \file quantifiers_attributes.h ** \verbatim - ** Original author: ajreynol - ** Major contributors: none + ** Original author: Andrew Reynolds <andrew.j.reynolds@gmail.com> + ** Major contributors: Morgan Deters <mdeters@cs.nyu.edu> ** Minor contributors (to current version): none - ** This file is part of the CVC4 prototype. - ** Copyright (c) 2009-2012 New York University and The University of Iowa + ** This file is part of the CVC4 project. + ** Copyright (c) 2009-2013 New York University and The University of Iowa ** See the file COPYING in the top-level source directory for licensing ** information.\endverbatim ** - ** \brief Attributes for the theory quantifiers
- **
- ** Attributes for the theory quantifiers.
- **/
-
-#include "cvc4_private.h"
-
-#ifndef __CVC4__THEORY__QUANTIFIERS__QUANTIFIERS_REWRITER_H
-#define __CVC4__THEORY__QUANTIFIERS__QUANTIFIERS_REWRITER_H
-
-#include "theory/rewriter.h"
-#include "theory/quantifiers_engine.h"
-
-namespace CVC4 {
-namespace theory {
-namespace quantifiers {
-
-/** Attribute true for quantifiers that are axioms */
-struct AxiomAttributeId {};
-typedef expr::Attribute< AxiomAttributeId, bool > AxiomAttribute;
-
-/** Attribute true for quantifiers that are conjecture */
-struct ConjectureAttributeId {};
-typedef expr::Attribute< ConjectureAttributeId, bool > ConjectureAttribute;
-
-struct QuantifiersAttributes
-{
- /** set user attribute
- * 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 );
-};
-
-
-}
-}
-}
-
-#endif
+ ** \brief Attributes for the theory quantifiers + ** + ** Attributes for the theory quantifiers. + **/ + +#include "cvc4_private.h" + +#ifndef __CVC4__THEORY__QUANTIFIERS__QUANTIFIERS_REWRITER_H +#define __CVC4__THEORY__QUANTIFIERS__QUANTIFIERS_REWRITER_H + +#include "theory/rewriter.h" +#include "theory/quantifiers_engine.h" + +namespace CVC4 { +namespace theory { +namespace quantifiers { + +/** Attribute true for quantifiers that are axioms */ +struct AxiomAttributeId {}; +typedef expr::Attribute< AxiomAttributeId, bool > AxiomAttribute; + +/** Attribute true for quantifiers that are conjecture */ +struct ConjectureAttributeId {}; +typedef expr::Attribute< ConjectureAttributeId, bool > ConjectureAttribute; + +struct QuantifiersAttributes +{ + /** set user attribute + * 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 ); +}; + + +} +} +} + +#endif diff --git a/src/theory/quantifiers/quantifiers_rewriter.cpp b/src/theory/quantifiers/quantifiers_rewriter.cpp index dabaa2188..bf6a025f8 100644 --- a/src/theory/quantifiers/quantifiers_rewriter.cpp +++ b/src/theory/quantifiers/quantifiers_rewriter.cpp @@ -90,29 +90,15 @@ void QuantifiersRewriter::addNodeToOrBuilder( Node n, NodeBuilder<>& t ){ } } -void QuantifiersRewriter::computeArgs( std::map< Node, bool >& active, Node n ){ - if( active.find( n )!=active.end() ){ - active[n] = true; +void QuantifiersRewriter::computeArgs( std::vector< Node >& args, std::vector< Node >& activeArgs, Node n ){ + if( n.getKind()==BOUND_VARIABLE ){ + if( std::find( args.begin(), args.end(), n )!=args.end() && + std::find( activeArgs.begin(), activeArgs.end(), n )==activeArgs.end() ){ + activeArgs.push_back( n ); + } }else{ for( int i=0; i<(int)n.getNumChildren(); i++ ){ - computeArgs( active, n[i] ); - } - } -} - -void QuantifiersRewriter::computeArgs( std::vector< Node >& args, std::vector< Node >& activeArgs, Node n ){ - std::map< Node, bool > active; - for( int i=0; i<(int)args.size(); i++ ){ - active[ args[i] ] = false; - } - //Notice() << "For " << n << " : " << std::endl; - computeArgs( active, n ); - activeArgs.clear(); - for( std::map< Node, bool >::iterator it = active.begin(); it != active.end(); ++it ){ - Node n = it->first; - //Notice() << " " << it->first << " is " << it->second << std::endl; - if( it->second ){ //only add bound variables that occur in body - activeArgs.push_back( it->first ); + computeArgs( args, activeArgs, n[i] ); } } } @@ -468,37 +454,19 @@ Node QuantifiersRewriter::computeCNF( Node n, std::vector< Node >& args, NodeBui } } -Node QuantifiersRewriter::computePrenex( Node body, std::vector< Node >& args, bool pol, bool polReq ){ +Node QuantifiersRewriter::computePrenex( Node body, std::vector< Node >& args, bool pol ){ if( body.getKind()==FORALL ){ - if( pol==polReq ){ + if( pol ){ std::vector< Node > terms; std::vector< Node > subs; - if( polReq ){ - //for doing prenexing of same-signed quantifiers - //must rename each variable that already exists - for( int i=0; i<(int)body[0].getNumChildren(); i++ ){ - //if( std::find( args.begin(), args.end(), body[0][i] )!=args.end() ){ - terms.push_back( body[0][i] ); - subs.push_back( NodeManager::currentNM()->mkBoundVar( body[0][i].getType() ) ); - } - args.insert( args.end(), subs.begin(), subs.end() ); - }else{ - std::vector< TypeNode > argTypes; - for( int i=0; i<(int)args.size(); i++ ){ - argTypes.push_back( args[i].getType() ); - } - //for doing pre-skolemization of opposite-signed quantifiers - for( int i=0; i<(int)body[0].getNumChildren(); i++ ){ - terms.push_back( body[0][i] ); - //make the new function symbol - TypeNode typ = NodeManager::currentNM()->mkFunctionType( argTypes, body[0][i].getType() ); - Node op = NodeManager::currentNM()->mkSkolem( "op_$$", typ, "was created by the quantifiers rewriter" ); - std::vector< Node > funcArgs; - funcArgs.push_back( op ); - funcArgs.insert( funcArgs.end(), args.begin(), args.end() ); - subs.push_back( NodeManager::currentNM()->mkNode( APPLY_UF, funcArgs ) ); - } + //for doing prenexing of same-signed quantifiers + //must rename each variable that already exists + for( int i=0; i<(int)body[0].getNumChildren(); i++ ){ + //if( std::find( args.begin(), args.end(), body[0][i] )!=args.end() ){ + terms.push_back( body[0][i] ); + subs.push_back( NodeManager::currentNM()->mkBoundVar( body[0][i].getType() ) ); } + args.insert( args.end(), subs.begin(), subs.end() ); Node newBody = body[1]; newBody = newBody.substitute( terms.begin(), terms.end(), subs.begin(), subs.end() ); Debug("quantifiers-substitute-debug") << "Did substitute have an effect" << (body[1] != newBody) << body[1] << " became " << newBody << endl; @@ -514,7 +482,7 @@ Node QuantifiersRewriter::computePrenex( Node body, std::vector< Node >& args, b std::vector< Node > newChildren; for( int i=0; i<(int)body.getNumChildren(); i++ ){ bool newPol = ( body.getKind()==NOT || ( body.getKind()==IMPLIES && i==0 ) ) ? !pol : pol; - Node n = computePrenex( body[i], args, newPol, polReq ); + Node n = computePrenex( body[i], args, newPol ); newChildren.push_back( n ); if( n!=body[i] ){ childrenChanged = true; @@ -549,10 +517,12 @@ Node QuantifiersRewriter::computeOperation( Node f, int computeOption ){ if( computeOption==COMPUTE_MINISCOPING ){ //return directly return computeMiniscoping( args, n, ipl, f.hasAttribute(NestedQuantAttribute()) ); + }else if( computeOption==COMPUTE_AGGRESSIVE_MINISCOPING ){ + return computeAggressiveMiniscoping( args, n, f.hasAttribute(NestedQuantAttribute()) ); }else if( computeOption==COMPUTE_NNF ){ n = computeNNF( n ); - }else if( computeOption==COMPUTE_PRENEX || computeOption==COMPUTE_PRE_SKOLEM ){ - n = computePrenex( n, args, true, computeOption==COMPUTE_PRENEX ); + }else if( computeOption==COMPUTE_PRENEX ){ + n = computePrenex( n, args, true ); }else if( computeOption==COMPUTE_VAR_ELIMINATION ){ Node prev; do{ @@ -670,42 +640,113 @@ Node QuantifiersRewriter::computeMiniscoping( std::vector< Node >& args, Node bo } return mkForAll( args, body, ipl ); } -/* -Node QuantifiersRewriter::rewriteQuants( Node n, bool isNested ){ - if( n.getKind()==FORALL ){ - return rewriteQuant( n, isNested ); - }else if( isLiteral( n ) ){ - return n; - }else{ - NodeBuilder<> tt(n.getKind()); - for( int i=0; i<(int)n.getNumChildren(); i++ ){ - tt << rewriteQuants( n[i], isNested ); - } - return tt.constructNode(); - } -} -Node QuantifiersRewriter::rewriteQuant( Node n, bool isNested ){ - Node prev = n; - for( int op=0; op<COMPUTE_LAST; op++ ){ - if( doOperation( n, isNested, op ) ){ - Node prev2 = n; - n = computeOperation( n, op ); - if( prev2!=n ){ - Trace("quantifiers-rewrite-op") << "Rewrite op " << op << ": rewrite " << prev2 << std::endl; - Trace("quantifiers-rewrite-op") << " to " << std::endl; - Trace("quantifiers-rewrite-op") << n << std::endl; +Node QuantifiersRewriter::computeAggressiveMiniscoping( std::vector< Node >& args, Node body, bool isNested ){ + if( !isNested ){ + std::map< Node, std::vector< Node > > varLits; + std::map< Node, std::vector< Node > > litVars; + if( body.getKind()==OR ){ + Trace("ag-miniscope") << "compute aggressive miniscoping on " << body << std::endl; + for( size_t i=0; i<body.getNumChildren(); i++ ){ + std::vector< Node > activeArgs; + computeArgs( args, activeArgs, body[i] ); + for (unsigned j=0; j<activeArgs.size(); j++ ){ + varLits[activeArgs[j]].push_back( body[i] ); + } + litVars[body[i]].insert( litVars[body[i]].begin(), activeArgs.begin(), activeArgs.end() ); + } + //find the variable in the least number of literals + Node bestVar; + for( std::map< Node, std::vector< Node > >::iterator it = varLits.begin(); it != varLits.end(); ++it ){ + if( bestVar.isNull() || varLits[bestVar].size()>it->second.size() ){ + bestVar = it->first; + } + } + Trace("ag-miniscope-debug") << "Best variable " << bestVar << " occurs in " << varLits[bestVar].size() << "/ " << body.getNumChildren() << " literals." << std::endl; + if( !bestVar.isNull() && varLits[bestVar].size()<body.getNumChildren() ){ + //we can miniscope + Trace("ag-miniscope") << "Miniscope on " << bestVar << std::endl; + //make the bodies + std::vector< Node > qlit1; + qlit1.insert( qlit1.begin(), varLits[bestVar].begin(), varLits[bestVar].end() ); + std::vector< Node > qlitt; + //for all literals not containing bestVar + for( size_t i=0; i<body.getNumChildren(); i++ ){ + if( std::find( qlit1.begin(), qlit1.end(), body[i] )==qlit1.end() ){ + qlitt.push_back( body[i] ); + } + } + //make the variable lists + std::vector< Node > qvl1; + std::vector< Node > qvl2; + std::vector< Node > qvsh; + for( unsigned i=0; i<args.size(); i++ ){ + bool found1 = false; + bool found2 = false; + for( size_t j=0; j<varLits[args[i]].size(); j++ ){ + if( !found1 && std::find( qlit1.begin(), qlit1.end(), varLits[args[i]][j] )!=qlit1.end() ){ + found1 = true; + }else if( !found2 && std::find( qlitt.begin(), qlitt.end(), varLits[args[i]][j] )!=qlitt.end() ){ + found2 = true; + } + if( found1 && found2 ){ + break; + } + } + if( found1 ){ + if( found2 ){ + qvsh.push_back( args[i] ); + }else{ + qvl1.push_back( args[i] ); + } + }else{ + Assert(found2); + qvl2.push_back( args[i] ); + } + } + Assert( !qvl1.empty() ); + Assert( !qvl2.empty() || !qvsh.empty() ); + //check for literals that only contain shared variables + std::vector< Node > qlitsh; + std::vector< Node > qlit2; + for( size_t i=0; i<qlitt.size(); i++ ){ + bool hasVar2 = false; + for( size_t j=0; j<litVars[qlitt[i]].size(); j++ ){ + if( std::find( qvl2.begin(), qvl2.end(), litVars[qlitt[i]][j] )!=qvl2.end() ){ + hasVar2 = true; + break; + } + } + if( hasVar2 ){ + qlit2.push_back( qlitt[i] ); + }else{ + qlitsh.push_back( qlitt[i] ); + } + } + varLits.clear(); + litVars.clear(); + Trace("ag-miniscope-debug") << "Split into literals : " << qlit1.size() << " / " << qlit2.size() << " / " << qlitsh.size(); + Trace("ag-miniscope-debug") << ", variables : " << qvl1.size() << " / " << qvl2.size() << " / " << qvsh.size() << std::endl; + Node n1 = qlit1.size()==1 ? qlit1[0] : NodeManager::currentNM()->mkNode( OR, qlit1 ); + n1 = computeAggressiveMiniscoping( qvl1, n1 ); + qlitsh.push_back( n1 ); + if( !qlit2.empty() ){ + Node n2 = qlit2.size()==1 ? qlit2[0] : NodeManager::currentNM()->mkNode( OR, qlit2 ); + n2 = computeAggressiveMiniscoping( qvl2, n2 ); + qlitsh.push_back( n2 ); + } + Node n = NodeManager::currentNM()->mkNode( OR, qlitsh ); + if( !qvsh.empty() ){ + Node bvl = NodeManager::currentNM()->mkNode(kind::BOUND_VAR_LIST, qvsh); + n = NodeManager::currentNM()->mkNode( FORALL, bvl, n ); + } + Trace("ag-miniscope") << "Return " << n << " for " << body << std::endl; + return n; } } } - if( prev==n ){ - return n; - }else{ - //rewrite again until fix point is reached - return rewriteQuant( n, isNested ); - } + return mkForAll( args, body, Node::null() ); } -*/ bool QuantifiersRewriter::doMiniscopingNoFreeVar(){ return options::miniscopeQuantFreeVar(); @@ -726,12 +767,12 @@ bool QuantifiersRewriter::doMiniscopingAnd(){ bool QuantifiersRewriter::doOperation( Node f, bool isNested, int computeOption ){ if( computeOption==COMPUTE_MINISCOPING ){ return true; + }else if( computeOption==COMPUTE_AGGRESSIVE_MINISCOPING ){ + return options::aggressiveMiniscopeQuant(); }else if( computeOption==COMPUTE_NNF ){ return false;//TODO: compute NNF (current bad idea since arithmetic rewrites equalities) - }else if( computeOption==COMPUTE_PRE_SKOLEM ){ - return false;//options::preSkolemQuant(); }else if( computeOption==COMPUTE_PRENEX ){ - return options::prenexQuant(); + return options::prenexQuant() && !options::aggressiveMiniscopeQuant(); }else if( computeOption==COMPUTE_VAR_ELIMINATION ){ return options::varElimQuant(); }else if( computeOption==COMPUTE_CNF ){ diff --git a/src/theory/quantifiers/quantifiers_rewriter.h b/src/theory/quantifiers/quantifiers_rewriter.h index 00301c610..75b392e15 100644 --- a/src/theory/quantifiers/quantifiers_rewriter.h +++ b/src/theory/quantifiers/quantifiers_rewriter.h @@ -41,19 +41,19 @@ private: static void computeArgs( std::vector< Node >& args, std::vector< Node >& activeArgs, Node n ); static bool hasArg( std::vector< Node >& args, Node n ); static void setNestedQuantifiers( Node n, Node q ); - static void computeArgs( std::map< Node, bool >& active, Node n ); static Node computeClause( Node n ); private: static Node computeMiniscoping( std::vector< Node >& args, Node body, Node ipl, bool isNested = false ); + static Node computeAggressiveMiniscoping( std::vector< Node >& args, Node body, bool isNested = false ); static Node computeNNF( Node body ); static Node computeVarElimination( Node body, std::vector< Node >& args, Node& ipl ); static Node computeCNF( Node body, std::vector< Node >& args, NodeBuilder<>& defs, bool forcePred ); - static Node computePrenex( Node body, std::vector< Node >& args, bool pol, bool polReq ); + static Node computePrenex( Node body, std::vector< Node >& args, bool pol ); private: enum{ COMPUTE_MINISCOPING = 0, + COMPUTE_AGGRESSIVE_MINISCOPING, COMPUTE_NNF, - COMPUTE_PRE_SKOLEM, COMPUTE_PRENEX, COMPUTE_VAR_ELIMINATION, //COMPUTE_FLATTEN_ARGS_UF, diff --git a/src/theory/quantifiers/term_database.cpp b/src/theory/quantifiers/term_database.cpp index d60aa2ef4..f6518cfd3 100644 --- a/src/theory/quantifiers/term_database.cpp +++ b/src/theory/quantifiers/term_database.cpp @@ -75,7 +75,7 @@ void TermDb::addTerm( Node n, std::set< Node >& added, bool withinQuant ){ //Call the children? if( inst::Trigger::isAtomicTrigger( n ) ){ if( !n.hasAttribute(InstConstantAttribute()) ){ - Debug("term-db") << "register trigger term " << n << std::endl; + Trace("term-db") << "register term in db " << n << std::endl; //std::cout << "register trigger term " << n << std::endl; Node op = n.getOperator(); d_op_map[op].push_back( n ); @@ -194,7 +194,7 @@ void TermDb::addTerm( Node n, std::set< Node >& added, bool withinQuant ){ Node TermDb::getModelBasisTerm( TypeNode tn, int i ){ if( d_model_basis_term.find( tn )==d_model_basis_term.end() ){ Node mbt; - if( d_type_map[ tn ].empty() ){ + if( options::fmfFreshDistConst() || d_type_map[ tn ].empty() ){ std::stringstream ss; ss << Expr::setlanguage(options::outputLanguage()); ss << "e_" << tn; @@ -206,6 +206,7 @@ Node TermDb::getModelBasisTerm( TypeNode tn, int i ){ ModelBasisAttribute mba; mbt.setAttribute(mba,true); d_model_basis_term[tn] = mbt; + Trace("model-basis-term") << "Choose " << mbt << " as model basis term for " << tn << std::endl; } return d_model_basis_term[tn]; } @@ -337,6 +338,14 @@ Node TermDb::getInstConstantBody( Node f ){ Node TermDb::getCounterexampleLiteral( Node f ){ if( d_ce_lit.find( f )==d_ce_lit.end() ){ Node ceBody = getInstConstantBody( f ); + //check if any variable are of bad types, and fail if so + for( size_t i=0; i<d_inst_constants[f].size(); i++ ){ + if( d_inst_constants[f][i].getType().isBoolean() ){ + d_ce_lit[ f ] = Node::null(); + return Node::null(); + } + } + //otherwise, ensure literal Node ceLit = d_quantEngine->getValuation().ensureLiteral( ceBody.notNode() ); d_ce_lit[ f ] = ceLit; setInstantiationConstantAttr( ceLit, f ); @@ -367,6 +376,10 @@ Node TermDb::getSkolemizedBody( Node f ){ Node skv = NodeManager::currentNM()->mkSkolem( "skv_$$", f[0][i].getType(), "is a termdb-created skolemized body" ); d_skolem_constants[ f ].push_back( skv ); vars.push_back( f[0][i] ); + //carry information for sort inference + if( options::sortInference() ){ + d_quantEngine->getTheoryEngine()->getSortInference()->setSkolemVar( f, f[0][i], skv ); + } } d_skolem_body[ f ] = f[ 1 ].substitute( vars.begin(), vars.end(), d_skolem_constants[ f ].begin(), d_skolem_constants[ f ].end() ); @@ -515,6 +528,34 @@ int TermDb::isInstanceOf( Node n1, Node n2 ){ return 0; } +bool TermDb::isUnifiableInstanceOf( Node n1, Node n2, std::map< Node, Node >& subs ){ + if( n1==n2 ){ + return true; + }else if( n2.getKind()==INST_CONSTANT ){ + //if( !node_contains( n1, n2 ) ){ + // return false; + //} + if( subs.find( n2 )==subs.end() ){ + subs[n2] = n1; + }else if( subs[n2]!=n1 ){ + return false; + } + return true; + }else if( n1.getKind()==n2.getKind() && n1.getMetaKind()==kind::metakind::PARAMETERIZED ){ + if( n1.getOperator()!=n2.getOperator() ){ + return false; + } + for( int i=0; i<(int)n1.getNumChildren(); i++ ){ + if( !isUnifiableInstanceOf( n1[i], n2[i], subs ) ){ + return false; + } + } + return true; + }else{ + return false; + } +} + void TermDb::filterInstances( std::vector< Node >& nodes ){ std::vector< bool > active; active.resize( nodes.size(), true ); @@ -523,8 +564,10 @@ void TermDb::filterInstances( std::vector< Node >& nodes ){ if( active[i] && active[j] ){ int result = isInstanceOf( nodes[i], nodes[j] ); if( result==1 ){ + Trace("filter-instances") << nodes[j] << " is an instance of " << nodes[i] << std::endl; active[j] = false; }else if( result==-1 ){ + Trace("filter-instances") << nodes[i] << " is an instance of " << nodes[j] << std::endl; active[i] = false; } } diff --git a/src/theory/quantifiers/term_database.h b/src/theory/quantifiers/term_database.h index a1f1de1dc..6bfea5c44 100644 --- a/src/theory/quantifiers/term_database.h +++ b/src/theory/quantifiers/term_database.h @@ -167,7 +167,7 @@ public: /** get counterexample literal (for cbqi) */ Node getCounterexampleLiteral( Node f ); /** returns node n with bound vars of f replaced by instantiation constants of f - node n : is the futur pattern + node n : is the future pattern node f : is the quantifier containing which bind the variable return a pattern where the variable are replaced by variable for instantiation. @@ -212,6 +212,8 @@ private: std::map< TNode, std::vector< TNode > > d_var_contains; /** triggers for each operator */ std::map< Node, std::vector< inst::Trigger* > > d_op_triggers; + /** helper for is intance of */ + bool isUnifiableInstanceOf( Node n1, Node n2, std::map< Node, Node >& subs ); public: /** compute var contains */ void computeVarContains( Node n ); diff --git a/src/theory/quantifiers/theory_quantifiers.cpp b/src/theory/quantifiers/theory_quantifiers.cpp index d1dbae90c..be6dd5b08 100644 --- a/src/theory/quantifiers/theory_quantifiers.cpp +++ b/src/theory/quantifiers/theory_quantifiers.cpp @@ -92,12 +92,14 @@ Node TheoryQuantifiers::getValue(TNode n) { } } -void TheoryQuantifiers::collectModelInfo( TheoryModel* m, bool fullModel ){ - if( fullModel ){ +void TheoryQuantifiers::collectModelInfo(TheoryModel* m, bool fullModel) { + if(fullModel) { for(assertions_iterator i = facts_begin(); i != facts_end(); ++i) { if((*i).assertion.getKind() == kind::NOT) { + Debug("quantifiers::collectModelInfo") << "got quant FALSE: " << (*i).assertion[0] << endl; m->assertPredicate((*i).assertion[0], false); } else { + Debug("quantifiers::collectModelInfo") << "got quant TRUE : " << *i << endl; m->assertPredicate(*i, true); } } diff --git a/src/theory/quantifiers/trigger.cpp b/src/theory/quantifiers/trigger.cpp index bc577fda6..cff28f243 100644 --- a/src/theory/quantifiers/trigger.cpp +++ b/src/theory/quantifiers/trigger.cpp @@ -34,24 +34,29 @@ using namespace CVC4::theory::inst; Trigger::Trigger( QuantifiersEngine* qe, Node f, std::vector< Node >& nodes, int matchOption, bool smartTriggers ) : d_quantEngine( qe ), d_f( f ){ d_nodes.insert( d_nodes.begin(), nodes.begin(), nodes.end() ); + Trace("trigger") << "Trigger for " << f << ": " << std::endl; + for( int i=0; i<(int)d_nodes.size(); i++ ){ + Trace("trigger") << " " << d_nodes[i] << std::endl; + } + Trace("trigger-debug") << ", smart triggers = " << smartTriggers; + Trace("trigger") << std::endl; if( smartTriggers ){ if( d_nodes.size()==1 ){ if( isSimpleTrigger( d_nodes[0] ) ){ d_mg = new InstMatchGeneratorSimple( f, d_nodes[0] ); }else{ - d_mg = new InstMatchGenerator( d_nodes[0], qe, matchOption ); + d_mg = InstMatchGenerator::mkInstMatchGenerator( d_nodes[0], qe ); + d_mg->setActiveAdd(); } }else{ d_mg = new InstMatchGeneratorMulti( f, d_nodes, qe, matchOption ); + //d_mg = InstMatchGenerator::mkInstMatchGenerator( d_nodes, qe ); + //d_mg->setActiveAdd(); } }else{ - d_mg = new InstMatchGenerator( d_nodes, qe, matchOption ); - } - Trace("trigger") << "Trigger for " << f << ": " << std::endl; - for( int i=0; i<(int)d_nodes.size(); i++ ){ - Trace("trigger") << " " << d_nodes[i] << std::endl; + d_mg = InstMatchGenerator::mkInstMatchGenerator( d_nodes, qe ); + d_mg->setActiveAdd(); } - Trace("trigger") << std::endl; if( d_nodes.size()==1 ){ if( isSimpleTrigger( d_nodes[0] ) ){ ++(qe->d_statistics.d_triggers); @@ -59,7 +64,7 @@ d_quantEngine( qe ), d_f( f ){ ++(qe->d_statistics.d_simple_triggers); } }else{ - Debug("multi-trigger") << "Multi-trigger " << (*this) << std::endl; + Trace("multi-trigger") << "Multi-trigger " << (*this) << " for " << f << std::endl; //Notice() << "Multi-trigger for " << f << " : " << std::endl; //Notice() << " " << (*this) << std::endl; ++(qe->d_statistics.d_multi_triggers); @@ -80,14 +85,14 @@ void Trigger::reset( Node eqc ){ d_mg->reset( eqc, d_quantEngine ); } -bool Trigger::getNextMatch( InstMatch& m ){ - bool retVal = d_mg->getNextMatch( m, d_quantEngine ); +bool Trigger::getNextMatch( Node f, InstMatch& m ){ + bool retVal = d_mg->getNextMatch( f, m, d_quantEngine ); return retVal; } -bool Trigger::getMatch( Node t, InstMatch& m ){ +bool Trigger::getMatch( Node f, Node t, InstMatch& m ){ //FIXME: this assumes d_mg is an inst match generator - return ((InstMatchGenerator*)d_mg)->getMatch( t, m, d_quantEngine ); + return ((InstMatchGenerator*)d_mg)->getMatch( f, t, m, d_quantEngine ); } int Trigger::addTerm( Node t ){ @@ -115,6 +120,7 @@ Trigger* Trigger::mkTrigger( QuantifiersEngine* qe, Node f, std::vector< Node >& temp.insert( temp.begin(), nodes.begin(), nodes.end() ); std::map< Node, bool > vars; std::map< Node, std::vector< Node > > patterns; + size_t varCount = 0; for( int i=0; i<(int)temp.size(); i++ ){ bool foundVar = false; qe->getTermDatabase()->computeVarContains( temp[i] ); @@ -122,6 +128,7 @@ Trigger* Trigger::mkTrigger( QuantifiersEngine* qe, Node f, std::vector< Node >& Node v = qe->getTermDatabase()->d_var_contains[ temp[i] ][j]; if( v.getAttribute(InstConstantAttribute())==f ){ if( vars.find( v )==vars.end() ){ + varCount++; vars[ v ] = true; foundVar = true; } @@ -134,32 +141,40 @@ Trigger* Trigger::mkTrigger( QuantifiersEngine* qe, Node f, std::vector< Node >& patterns[ v ].push_back( temp[i] ); } } - } - //now, minimalize the trigger - for( int i=0; i<(int)trNodes.size(); i++ ){ - bool keepPattern = false; - Node n = trNodes[i]; - for( int j=0; j<(int)qe->getTermDatabase()->d_var_contains[ n ].size(); j++ ){ - Node v = qe->getTermDatabase()->d_var_contains[ n ][j]; - if( patterns[v].size()==1 ){ - keepPattern = true; - break; - } + if( varCount==f[0].getNumChildren() ){ + break; } - if( !keepPattern ){ - //remove from pattern vector + } + if( varCount<f[0].getNumChildren() ){ + //do not generate multi-trigger if it does not contain all variables + return NULL; + }else{ + //now, minimize the trigger + for( int i=0; i<(int)trNodes.size(); i++ ){ + bool keepPattern = false; + Node n = trNodes[i]; for( int j=0; j<(int)qe->getTermDatabase()->d_var_contains[ n ].size(); j++ ){ Node v = qe->getTermDatabase()->d_var_contains[ n ][j]; - for( int k=0; k<(int)patterns[v].size(); k++ ){ - if( patterns[v][k]==n ){ - patterns[v].erase( patterns[v].begin() + k, patterns[v].begin() + k + 1 ); - break; + if( patterns[v].size()==1 ){ + keepPattern = true; + break; + } + } + if( !keepPattern ){ + //remove from pattern vector + for( int j=0; j<(int)qe->getTermDatabase()->d_var_contains[ n ].size(); j++ ){ + Node v = qe->getTermDatabase()->d_var_contains[ n ][j]; + for( int k=0; k<(int)patterns[v].size(); k++ ){ + if( patterns[v][k]==n ){ + patterns[v].erase( patterns[v].begin() + k, patterns[v].begin() + k + 1 ); + break; + } } } + //remove from trigger nodes + trNodes.erase( trNodes.begin() + i, trNodes.begin() + i + 1 ); + i--; } - //remove from trigger nodes - trNodes.erase( trNodes.begin() + i, trNodes.begin() + i + 1 ); - i--; } } }else{ @@ -322,16 +337,16 @@ void Trigger::collectPatTerms( QuantifiersEngine* qe, Node f, Node n, std::vecto temp.insert( temp.begin(), patTerms2.begin(), patTerms2.end() ); qe->getTermDatabase()->filterInstances( temp ); if( temp.size()!=patTerms2.size() ){ - Debug("trigger-filter-instance") << "Filtered an instance: " << std::endl; - Debug("trigger-filter-instance") << "Old: "; + Trace("trigger-filter-instance") << "Filtered an instance: " << std::endl; + Trace("trigger-filter-instance") << "Old: "; for( int i=0; i<(int)patTerms2.size(); i++ ){ - Debug("trigger-filter-instance") << patTerms2[i] << " "; + Trace("trigger-filter-instance") << patTerms2[i] << " "; } - Debug("trigger-filter-instance") << std::endl << "New: "; + Trace("trigger-filter-instance") << std::endl << "New: "; for( int i=0; i<(int)temp.size(); i++ ){ - Debug("trigger-filter-instance") << temp[i] << " "; + Trace("trigger-filter-instance") << temp[i] << " "; } - Debug("trigger-filter-instance") << std::endl; + Trace("trigger-filter-instance") << std::endl; } if( tstrt==TS_ALL ){ patTerms.insert( patTerms.begin(), temp.begin(), temp.end() ); diff --git a/src/theory/quantifiers/trigger.h b/src/theory/quantifiers/trigger.h index 6fcd316f4..93731283b 100644 --- a/src/theory/quantifiers/trigger.h +++ b/src/theory/quantifiers/trigger.h @@ -56,12 +56,12 @@ public: /** reset, eqc is the equivalence class to search in (search in any if eqc=null) */ void reset( Node eqc ); /** get next match. must call reset( eqc ) once before this function. */ - bool getNextMatch( InstMatch& m ); + bool getNextMatch( Node f, InstMatch& m ); /** get the match against ground term or formula t. the trigger and t should have the same shape. Currently the trigger should not be a multi-trigger. */ - bool getMatch( Node t, InstMatch& m); + bool getMatch( Node f, Node t, InstMatch& m); /** add ground term t, called when t is added to the TermDb */ int addTerm( Node t ); /** return whether this is a multi-trigger */ diff --git a/src/theory/quantifiers_engine.cpp b/src/theory/quantifiers_engine.cpp index 08bdd496b..a11cc85c0 100644 --- a/src/theory/quantifiers_engine.cpp +++ b/src/theory/quantifiers_engine.cpp @@ -71,6 +71,7 @@ d_lemmas_produced_c(u){ d_optMatchIgnoreModelBasis = false; d_optInstLimitActive = false; d_optInstLimit = 0; + d_total_inst_count_debug = 0; } QuantifiersEngine::~QuantifiersEngine(){ @@ -142,10 +143,23 @@ void QuantifiersEngine::check( Theory::Effort e ){ } //build the model if not done so already // this happens if no quantifiers are currently asserted and no model-building module is enabled - if( options::produceModels() && e==Theory::EFFORT_LAST_CALL && !d_hasAddedLemma && !d_model->isModelSet() ){ - d_te->getModelBuilder()->buildModel( d_model, true ); + if( e==Theory::EFFORT_LAST_CALL && !d_hasAddedLemma ){ + if( options::produceModels() && !d_model->isModelSet() ){ + d_te->getModelBuilder()->buildModel( d_model, 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 ){ + Trace("inst-per-quant") << " * " << it->second << " for " << it->first << std::endl; + } + } + }else{ + if( Trace.isOn("inst-per-quant-round") ){ + for( std::map< Node, int >::iterator it = d_temp_inst_debug.begin(); it != d_temp_inst_debug.end(); ++it ){ + Trace("inst-per-quant-round") << " * " << it->second << " for " << it->first << std::endl; + d_temp_inst_debug[it->first] = 0; + } + } } - Trace("quant-engine") << "Finished quantifiers engine check." << std::endl; } } @@ -242,6 +256,9 @@ bool QuantifiersEngine::addInstantiation( Node f, std::vector< Node >& vars, std Node lem = nb; //check for duplication if( addLemma( lem ) ){ + d_total_inst_debug[f]++; + d_temp_inst_debug[f]++; + d_total_inst_count_debug++; Trace("inst") << "*** Instantiate " << f << " with " << std::endl; uint64_t maxInstLevel = 0; for( int i=0; i<(int)terms.size(); i++ ){ @@ -354,7 +371,7 @@ bool QuantifiersEngine::addInstantiation( Node f, InstMatch& m, bool modEq, bool //make it representative, this is helpful for recognizing duplication if( mkRep ){ //pick the best possible representative for instantiation, based on past use and simplicity of term - Node r = d_eq_query->getInternalRepresentative( val ); + Node r = d_eq_query->getInternalRepresentative( val, f, i ); Trace("inst-add-debug") << "mkRep " << r << " " << val << std::endl; m.set( ic, r ); } @@ -460,56 +477,6 @@ void QuantifiersEngine::getPhaseReqTerms( Node f, std::vector< Node >& nodes ){ d_statistics.d_lit_phase_nreq += (int)nodes.size(); } } -/* -EqualityQuery* QuantifiersEngine::getEqualityQuery(TypeNode t) { - // Should use skeleton (in order to have the type and the kind - // or any needed other information) instead of only the type - - // TheoryId id = Theory::theoryOf(t); - // inst::EqualityQuery* eq = d_eq_query_arr[id]; - // if(eq == NULL) return d_eq_query_arr[theory::THEORY_UF]; - // else return eq; - - // hack because the generic one is too slow - // TheoryId id = Theory::theoryOf(t); - // if( true || id == theory::THEORY_UF){ - // uf::InstantiatorTheoryUf* ith = static_cast<uf::InstantiatorTheoryUf*>( getInstantiator( theory::THEORY_UF )); - // return new uf::EqualityQueryInstantiatorTheoryUf(ith); - // } - // inst::EqualityQuery* eq = d_eq_query_arr[id]; - // if(eq == NULL) return d_eq_query_arr[theory::THEORY_UF]; - // else return eq; - - - //Currently we use the generic EqualityQuery - return getEqualityQuery(); -} - - -rrinst::CandidateGenerator* QuantifiersEngine::getRRCanGenClasses() { - return new GenericCandidateGeneratorClasses(this); -} - -rrinst::CandidateGenerator* QuantifiersEngine::getRRCanGenClass() { - return new GenericCandidateGeneratorClass(this); -} - -rrinst::CandidateGenerator* QuantifiersEngine::getRRCanGenClasses(TypeNode t) { - // TheoryId id = Theory::theoryOf(t); - // rrinst::CandidateGenerator* eq = getInstantiator(id)->getRRCanGenClasses(); - // if(eq == NULL) return getInstantiator(id)->getRRCanGenClasses(); - // else return eq; - return getRRCanGenClasses(); -} - -rrinst::CandidateGenerator* QuantifiersEngine::getRRCanGenClass(TypeNode t) { - // TheoryId id = Theory::theoryOf(t); - // rrinst::CandidateGenerator* eq = getInstantiator(id)->getRRCanGenClass(); - // if(eq == NULL) return getInstantiator(id)->getRRCanGenClass(); - // else return eq; - return getRRCanGenClass(); -} -*/ QuantifiersEngine::Statistics::Statistics(): d_num_quant("QuantifiersEngine::Num_Quantifiers", 0), @@ -635,39 +602,57 @@ bool EqualityQueryQuantifiersEngine::areDisequal( Node a, Node b ){ return false; } -Node EqualityQueryQuantifiersEngine::getInternalRepresentative( Node a ){ +Node EqualityQueryQuantifiersEngine::getInternalRepresentative( Node a, Node f, int index ){ Node r = getRepresentative( a ); if( !options::internalReps() ){ return r; }else{ - if( d_int_rep.find( r )==d_int_rep.end() ){ + int sortId = 0; + if( optInternalRepSortInference() ){ + sortId = d_qe->getTheoryEngine()->getSortInference()->getSortId( f, f[0][index] ); + } + if( d_int_rep[sortId].find( r )==d_int_rep[sortId].end() ){ std::vector< Node > eqc; getEquivalenceClass( r, eqc ); //find best selection for representative - Node r_best = r; - int r_best_score = getRepScore( r ); + Node r_best; + int r_best_score = -1; for( size_t i=0; i<eqc.size(); i++ ){ - int score = getRepScore( eqc[i] ); + int score = getRepScore( eqc[i], f, index ); + if( optInternalRepSortInference() ){ + int e_sortId = d_qe->getTheoryEngine()->getSortInference()->getSortId( eqc[i]); + if( score>=0 && e_sortId!=sortId ){ + score += 100; + } + } //score prefers earliest use of this term as a representative - if( score>=0 && ( r_best_score<0 || score<r_best_score ) ){ + if( r_best.isNull() || ( score>=0 && ( r_best_score<0 || score<r_best_score ) ) ){ r_best = eqc[i]; r_best_score = score; } } //now, make sure that no other member of the class is an instance - r_best = getInstance( r_best, eqc ); + if( !optInternalRepSortInference() ){ + r_best = getInstance( r_best, eqc ); + } //store that this representative was chosen at this point if( d_rep_score.find( r_best )==d_rep_score.end() ){ d_rep_score[ r_best ] = d_reset_count; } - d_int_rep[r] = r_best; + d_int_rep[sortId][r] = r_best; if( r_best!=a ){ Trace("internal-rep-debug") << "rep( " << a << " ) = " << r << ", " << std::endl; Trace("internal-rep-debug") << "int_rep( " << a << " ) = " << r_best << ", " << std::endl; } + if( optInternalRepSortInference() ){ + int sortIdBest = d_qe->getTheoryEngine()->getSortInference()->getSortId( r_best ); + if( sortId!=sortIdBest ){ + Trace("sort-inf-rep") << "Choosing representative with bad type " << r_best << " " << sortId << " " << sortIdBest << std::endl; + } + } return r_best; }else{ - return d_int_rep[r]; + return d_int_rep[sortId][r]; } } } @@ -723,7 +708,11 @@ int getDepth( Node n ){ } } -int EqualityQueryQuantifiersEngine::getRepScore( Node n ){ +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 //return ( d_rep_score.find( n )==d_rep_score.end() ? 100 : 0 ) + getDepth( n ); //term depth } + +bool EqualityQueryQuantifiersEngine::optInternalRepSortInference() { + return false; //shown to be not effective +}
\ No newline at end of file diff --git a/src/theory/quantifiers_engine.h b/src/theory/quantifiers_engine.h index 29381a309..9f520f420 100644 --- a/src/theory/quantifiers_engine.h +++ b/src/theory/quantifiers_engine.h @@ -119,6 +119,10 @@ private: rrinst::TriggerTrie* d_rr_tr_trie; /** extended model object */ quantifiers::FirstOrderModel* d_model; + /** statistics for debugging */ + std::map< Node, int > d_total_inst_debug; + std::map< Node, int > d_temp_inst_debug; + int d_total_inst_count_debug; private: KEEP_STATISTIC(TimerStat, d_time, "theory::QuantifiersEngine::time"); public: @@ -210,6 +214,7 @@ public: rrinst::TriggerTrie* getRRTriggerDatabase() { return d_rr_tr_trie; } /** add term to database */ void addTermToDatabase( Node n, bool withinQuant = false ); + /** get the master equality engine */ eq::EqualityEngine* getMasterEqualityEngine() ; public: /** statistics class */ @@ -262,7 +267,7 @@ private: /** pointer to theory engine */ QuantifiersEngine* d_qe; /** internal representatives */ - std::map< Node, Node > d_int_rep; + std::map< int, std::map< Node, Node > > d_int_rep; /** rep score */ std::map< Node, int > d_rep_score; /** reset count */ @@ -271,7 +276,9 @@ private: /** node contains */ Node getInstance( Node n, std::vector< Node >& eqc ); /** get score */ - int getRepScore( Node n ); + int getRepScore( Node n, Node f, int index ); + /** choose rep based on sort inference */ + bool optInternalRepSortInference(); public: EqualityQueryQuantifiersEngine( QuantifiersEngine* qe ) : d_qe( qe ), d_reset_count( 0 ){} ~EqualityQueryQuantifiersEngine(){} @@ -288,7 +295,7 @@ public: If cbqi is active, this will return a term in the equivalence class of "a" that does not contain instantiation constants, if such a term exists. */ - Node getInternalRepresentative( Node a ); + Node getInternalRepresentative( Node a, Node f, int index ); }; /* EqualityQueryQuantifiersEngine */ }/* CVC4::theory namespace */ diff --git a/src/theory/rep_set.cpp b/src/theory/rep_set.cpp index b50878e70..2df0c3f61 100644 --- a/src/theory/rep_set.cpp +++ b/src/theory/rep_set.cpp @@ -1,231 +1,224 @@ /********************* */ /*! \file rep_set.cpp ** \verbatim - ** Original author: ajreynol - ** Major contributors: none - ** Minor contributors (to current version): mdeters - ** This file is part of the CVC4 prototype. - ** Copyright (c) 2009-2012 New York University and The University of Iowa + ** Original author: Andrew Reynolds <andrew.j.reynolds@gmail.com> + ** Major contributors: Morgan Deters <mdeters@cs.nyu.edu> + ** Minor contributors (to current version): none + ** This file is part of the CVC4 project. + ** Copyright (c) 2009-2013 New York University and The University of Iowa ** See the file COPYING in the top-level source directory for licensing ** information.\endverbatim ** - ** \brief Implementation of representative set
- **/
-
-#include "theory/rep_set.h"
-#include "theory/type_enumerator.h"
-
-using namespace std;
-using namespace CVC4;
-using namespace CVC4::kind;
-using namespace CVC4::context;
-using namespace CVC4::theory;
-
-void RepSet::clear(){
- d_type_reps.clear();
- d_type_complete.clear();
- d_tmap.clear();
-}
-
-int RepSet::getNumRepresentatives( TypeNode tn ) const{
- std::map< TypeNode, std::vector< Node > >::const_iterator it = d_type_reps.find( tn );
- if( it!=d_type_reps.end() ){
- return (int)it->second.size();
- }else{
- return 0;
- }
-}
-
-void RepSet::add( Node n ){
- TypeNode t = n.getType();
- d_tmap[ n ] = (int)d_type_reps[t].size();
- d_type_reps[t].push_back( n );
-}
-
-int RepSet::getIndexFor( Node n ) const {
- std::map< Node, int >::const_iterator it = d_tmap.find( n );
- if( it!=d_tmap.end() ){
- return it->second;
- }else{
- return -1;
- }
-}
-
-void RepSet::complete( TypeNode t ){
- if( d_type_complete.find( t )==d_type_complete.end() ){
- d_type_complete[t] = true;
- TypeEnumerator te(t);
- while( !te.isFinished() ){
- Node n = *te;
- if( std::find( d_type_reps[t].begin(), d_type_reps[t].end(), n )==d_type_reps[t].end() ){
- add( n );
- }
- ++te;
- }
- for( size_t i=0; i<d_type_reps[t].size(); i++ ){
- Trace("reps-complete") << d_type_reps[t][i] << " ";
- }
- Trace("reps-complete") << std::endl;
- }
-}
-
-void RepSet::toStream(std::ostream& out){
-#if 0
- for( std::map< TypeNode, std::vector< Node > >::iterator it = d_type_reps.begin(); it != d_type_reps.end(); ++it ){
- out << it->first << " : " << std::endl;
- for( int i=0; i<(int)it->second.size(); i++ ){
- out << " " << i << ": " << it->second[i] << std::endl;
- }
- }
-#else
- for( std::map< TypeNode, std::vector< Node > >::iterator it = d_type_reps.begin(); it != d_type_reps.end(); ++it ){
- if( !it->first.isFunction() && !it->first.isPredicate() ){
- out << "(" << it->first << " " << it->second.size();
- out << " (";
- for( int i=0; i<(int)it->second.size(); i++ ){
- if( i>0 ){ out << " "; }
- out << it->second[i];
- }
- out << ")";
- out << ")" << std::endl;
- }
- }
-#endif
-}
-
-
-RepSetIterator::RepSetIterator( RepSet* rs ) : d_rep_set( rs ){
- d_incomplete = false;
-
-}
-
-bool RepSetIterator::setQuantifier( Node f ){
- Assert( d_types.empty() );
- //store indicies
- for( size_t i=0; i<f[0].getNumChildren(); i++ ){
- d_types.push_back( f[0][i].getType() );
- }
- return initialize();
-}
-
-bool RepSetIterator::setFunctionDomain( Node op ){
- Assert( d_types.empty() );
- TypeNode tn = op.getType();
- for( size_t i=0; i<tn.getNumChildren()-1; i++ ){
- d_types.push_back( tn[i] );
- }
- return initialize();
-}
-
-bool RepSetIterator::initialize(){
- for( size_t i=0; i<d_types.size(); i++ ){
- d_index.push_back( 0 );
- //store default index order
- d_index_order.push_back( i );
- d_var_order[i] = i;
- //store default domain
- d_domain.push_back( RepDomain() );
- TypeNode tn = d_types[i];
- if( tn.isSort() ){
- if( !d_rep_set->hasType( tn ) ){
- Node var = NodeManager::currentNM()->mkSkolem( "repSet_$$", tn, "is a variable created by the RepSetIterator" );
- Trace("mkVar") << "RepSetIterator:: Make variable " << var << " : " << tn << std::endl;
- d_rep_set->add( var );
- }
- }else if( tn.isInteger() || tn.isReal() ){
- Trace("fmf-incomplete") << "Incomplete because of infinite type " << tn << std::endl;
- d_incomplete = true;
- }else if( tn.isDatatype() ){
- const Datatype& dt = ((DatatypeType)(tn).toType()).getDatatype();
- //if finite, then complete all values of the domain
- if( dt.isFinite() ){
- d_rep_set->complete( tn );
- //d_incomplete = true;
- }else{
- Trace("fmf-incomplete") << "Incomplete because of infinite datatype " << tn << std::endl;
- d_incomplete = true;
- }
- }else{
- Trace("fmf-incomplete") << "Incomplete because of unknown type " << tn << std::endl;
- d_incomplete = true;
- }
- if( d_rep_set->hasType( tn ) ){
- for( size_t j=0; j<d_rep_set->d_type_reps[tn].size(); j++ ){
- d_domain[i].push_back( j );
- }
- }else{
- return false;
- }
- }
- return true;
-}
-
-void RepSetIterator::setIndexOrder( std::vector< int >& indexOrder ){
- d_index_order.clear();
- d_index_order.insert( d_index_order.begin(), indexOrder.begin(), indexOrder.end() );
- //make the d_var_order mapping
- for( int i=0; i<(int)d_index_order.size(); i++ ){
- d_var_order[d_index_order[i]] = i;
- }
-}
-
-void RepSetIterator::setDomain( std::vector< RepDomain >& domain ){
- d_domain.clear();
- d_domain.insert( d_domain.begin(), domain.begin(), domain.end() );
- //we are done if a domain is empty
- for( int i=0; i<(int)d_domain.size(); i++ ){
- if( d_domain[i].empty() ){
- d_index.clear();
- }
- }
-}
-
-void RepSetIterator::increment2( int counter ){
- Assert( !isFinished() );
-#ifdef DISABLE_EVAL_SKIP_MULTIPLE
- counter = (int)d_index.size()-1;
-#endif
- //increment d_index
- while( counter>=0 && d_index[counter]==(int)(d_domain[counter].size()-1) ){
- counter--;
- }
- if( counter==-1 ){
- d_index.clear();
- }else{
- for( int i=(int)d_index.size()-1; i>counter; i-- ){
- d_index[i] = 0;
- }
- d_index[counter]++;
- }
-}
-
-void RepSetIterator::increment(){
- if( !isFinished() ){
- increment2( (int)d_index.size()-1 );
- }
-}
-
-bool RepSetIterator::isFinished(){
- return d_index.empty();
-}
-
-Node RepSetIterator::getTerm( int i ){
- TypeNode tn = d_types[d_index_order[i]];
- Assert( d_rep_set->d_type_reps.find( tn )!=d_rep_set->d_type_reps.end() );
- int index = d_index_order[i];
- return d_rep_set->d_type_reps[tn][d_domain[index][d_index[index]]];
-}
-
-void RepSetIterator::debugPrint( const char* c ){
- for( int i=0; i<(int)d_index.size(); i++ ){
- Debug( c ) << i << " : " << d_index[i] << " : " << getTerm( i ) << std::endl;
- }
-}
-
-void RepSetIterator::debugPrintSmall( const char* c ){
- Debug( c ) << "RI: ";
- for( int i=0; i<(int)d_index.size(); i++ ){
- Debug( c ) << d_index[i] << ": " << getTerm( i ) << " ";
- }
- Debug( c ) << std::endl;
-}
+ ** \brief Implementation of representative set + **/ + +#include "theory/rep_set.h" +#include "theory/type_enumerator.h" + +using namespace std; +using namespace CVC4; +using namespace CVC4::kind; +using namespace CVC4::context; +using namespace CVC4::theory; + +void RepSet::clear(){ + d_type_reps.clear(); + d_type_complete.clear(); + d_tmap.clear(); +} + +int RepSet::getNumRepresentatives( TypeNode tn ) const{ + std::map< TypeNode, std::vector< Node > >::const_iterator it = d_type_reps.find( tn ); + if( it!=d_type_reps.end() ){ + return (int)it->second.size(); + }else{ + return 0; + } +} + +void RepSet::add( Node n ){ + TypeNode t = n.getType(); + d_tmap[ n ] = (int)d_type_reps[t].size(); + d_type_reps[t].push_back( n ); +} + +int RepSet::getIndexFor( Node n ) const { + std::map< Node, int >::const_iterator it = d_tmap.find( n ); + if( it!=d_tmap.end() ){ + return it->second; + }else{ + return -1; + } +} + +void RepSet::complete( TypeNode t ){ + if( d_type_complete.find( t )==d_type_complete.end() ){ + d_type_complete[t] = true; + TypeEnumerator te(t); + while( !te.isFinished() ){ + Node n = *te; + if( std::find( d_type_reps[t].begin(), d_type_reps[t].end(), n )==d_type_reps[t].end() ){ + add( n ); + } + ++te; + } + for( size_t i=0; i<d_type_reps[t].size(); i++ ){ + Trace("reps-complete") << d_type_reps[t][i] << " "; + } + Trace("reps-complete") << std::endl; + } +} + +void RepSet::toStream(std::ostream& out){ +#if 0 + for( std::map< TypeNode, std::vector< Node > >::iterator it = d_type_reps.begin(); it != d_type_reps.end(); ++it ){ + out << it->first << " : " << std::endl; + for( int i=0; i<(int)it->second.size(); i++ ){ + out << " " << i << ": " << it->second[i] << std::endl; + } + } +#else + for( std::map< TypeNode, std::vector< Node > >::iterator it = d_type_reps.begin(); it != d_type_reps.end(); ++it ){ + if( !it->first.isFunction() && !it->first.isPredicate() ){ + out << "(" << it->first << " " << it->second.size(); + out << " ("; + for( int i=0; i<(int)it->second.size(); i++ ){ + if( i>0 ){ out << " "; } + out << it->second[i]; + } + out << ")"; + out << ")" << std::endl; + } + } +#endif +} + + +RepSetIterator::RepSetIterator( RepSet* rs ) : d_rep_set( rs ){ + d_incomplete = false; + +} + +bool RepSetIterator::setQuantifier( Node f ){ + Assert( d_types.empty() ); + //store indicies + for( size_t i=0; i<f[0].getNumChildren(); i++ ){ + d_types.push_back( f[0][i].getType() ); + } + return initialize(); +} + +bool RepSetIterator::setFunctionDomain( Node op ){ + Assert( d_types.empty() ); + TypeNode tn = op.getType(); + for( size_t i=0; i<tn.getNumChildren()-1; i++ ){ + d_types.push_back( tn[i] ); + } + return initialize(); +} + +bool RepSetIterator::initialize(){ + for( size_t i=0; i<d_types.size(); i++ ){ + d_index.push_back( 0 ); + //store default index order + d_index_order.push_back( i ); + d_var_order[i] = i; + //store default domain + d_domain.push_back( RepDomain() ); + TypeNode tn = d_types[i]; + if( tn.isSort() ){ + if( !d_rep_set->hasType( tn ) ){ + Node var = NodeManager::currentNM()->mkSkolem( "repSet_$$", tn, "is a variable created by the RepSetIterator" ); + Trace("mkVar") << "RepSetIterator:: Make variable " << var << " : " << tn << std::endl; + d_rep_set->add( var ); + } + }else if( tn.isInteger() || tn.isReal() ){ + Trace("fmf-incomplete") << "Incomplete because of infinite type " << tn << std::endl; + d_incomplete = true; + //enumerate if the sort is reasonably small, the upper bound of 128 is chosen arbitrarily for now + }else if( tn.getCardinality().isFinite() && tn.getCardinality().getFiniteCardinality().toUnsignedInt()<=128 ){ + d_rep_set->complete( tn ); + }else{ + Trace("fmf-incomplete") << "Incomplete because of unknown type " << tn << std::endl; + d_incomplete = true; + } + if( d_rep_set->hasType( tn ) ){ + for( size_t j=0; j<d_rep_set->d_type_reps[tn].size(); j++ ){ + d_domain[i].push_back( j ); + } + }else{ + return false; + } + } + return true; +} + +void RepSetIterator::setIndexOrder( std::vector< int >& indexOrder ){ + d_index_order.clear(); + d_index_order.insert( d_index_order.begin(), indexOrder.begin(), indexOrder.end() ); + //make the d_var_order mapping + for( int i=0; i<(int)d_index_order.size(); i++ ){ + d_var_order[d_index_order[i]] = i; + } +} + +void RepSetIterator::setDomain( std::vector< RepDomain >& domain ){ + d_domain.clear(); + d_domain.insert( d_domain.begin(), domain.begin(), domain.end() ); + //we are done if a domain is empty + for( int i=0; i<(int)d_domain.size(); i++ ){ + if( d_domain[i].empty() ){ + d_index.clear(); + } + } +} + +void RepSetIterator::increment2( int counter ){ + Assert( !isFinished() ); +#ifdef DISABLE_EVAL_SKIP_MULTIPLE + counter = (int)d_index.size()-1; +#endif + //increment d_index + while( counter>=0 && d_index[counter]==(int)(d_domain[counter].size()-1) ){ + counter--; + } + if( counter==-1 ){ + d_index.clear(); + }else{ + for( int i=(int)d_index.size()-1; i>counter; i-- ){ + d_index[i] = 0; + } + d_index[counter]++; + } +} + +void RepSetIterator::increment(){ + if( !isFinished() ){ + increment2( (int)d_index.size()-1 ); + } +} + +bool RepSetIterator::isFinished(){ + return d_index.empty(); +} + +Node RepSetIterator::getTerm( int i ){ + TypeNode tn = d_types[d_index_order[i]]; + Assert( d_rep_set->d_type_reps.find( tn )!=d_rep_set->d_type_reps.end() ); + int index = d_index_order[i]; + return d_rep_set->d_type_reps[tn][d_domain[index][d_index[index]]]; +} + +void RepSetIterator::debugPrint( const char* c ){ + for( int i=0; i<(int)d_index.size(); i++ ){ + Debug( c ) << i << " : " << d_index[i] << " : " << getTerm( i ) << std::endl; + } +} + +void RepSetIterator::debugPrintSmall( const char* c ){ + Debug( c ) << "RI: "; + for( int i=0; i<(int)d_index.size(); i++ ){ + Debug( c ) << d_index[i] << ": " << getTerm( i ) << " "; + } + Debug( c ) << std::endl; +} diff --git a/src/theory/rep_set.h b/src/theory/rep_set.h index 61b2ebf9f..019f69ec2 100644 --- a/src/theory/rep_set.h +++ b/src/theory/rep_set.h @@ -1,112 +1,112 @@ /********************* */ /*! \file rep_set.h ** \verbatim - ** Original author: ajreynol - ** Major contributors: none + ** Original author: Andrew Reynolds <andrew.j.reynolds@gmail.com> + ** Major contributors: Morgan Deters <mdeters@cs.nyu.edu> ** Minor contributors (to current version): none - ** This file is part of the CVC4 prototype. - ** Copyright (c) 2009-2012 New York University and The University of Iowa + ** This file is part of the CVC4 project. + ** Copyright (c) 2009-2013 New York University and The University of Iowa ** See the file COPYING in the top-level source directory for licensing ** information.\endverbatim ** - ** \brief Representative set class and utilities
- **/
-
-#include "cvc4_private.h"
-
-#ifndef __CVC4__REP_SET_H
-#define __CVC4__REP_SET_H
-
-#include "expr/node.h"
-#include <map>
-
-namespace CVC4 {
-namespace theory {
-
-/** this class stores a representative set */
-class RepSet {
-public:
- RepSet(){}
- ~RepSet(){}
- std::map< TypeNode, std::vector< Node > > d_type_reps;
- std::map< TypeNode, bool > d_type_complete;
- std::map< Node, int > d_tmap;
- /** clear the set */
- void clear();
- /** has type */
- bool hasType( TypeNode tn ) const { return d_type_reps.find( tn )!=d_type_reps.end(); }
- /** get cardinality for type */
- int getNumRepresentatives( TypeNode tn ) const;
- /** add representative for type */
- void add( Node n );
- /** returns index in d_type_reps for node n */
- int getIndexFor( Node n ) const;
- /** complete all values */
- void complete( TypeNode t );
- /** debug print */
- void toStream(std::ostream& out);
-};
-
-//representative domain
-typedef std::vector< int > RepDomain;
-
-/** this class iterates over a RepSet */
-class RepSetIterator {
-private:
- //initialize function
- bool initialize();
-public:
- RepSetIterator( RepSet* rs );
- ~RepSetIterator(){}
- //set that this iterator will be iterating over instantiations for a quantifier
- bool setQuantifier( Node f );
- //set that this iterator will be iterating over the domain of a function
- bool setFunctionDomain( Node op );
-public:
- //pointer to model
- RepSet* d_rep_set;
- //index we are considering
- std::vector< int > d_index;
- //types we are considering
- std::vector< TypeNode > d_types;
- //domain we are considering
- std::vector< RepDomain > d_domain;
- //are we only considering a strict subset of the domain of the quantifier?
- bool d_incomplete;
- //ordering for variables we are indexing over
- // for example, given reps = { a, b } and quantifier forall( x, y, z ) P( x, y, z ) with d_index_order = { 2, 0, 1 },
- // then we consider instantiations in this order:
- // a/x a/y a/z
- // a/x b/y a/z
- // b/x a/y a/z
- // b/x b/y a/z
- // ...
- std::vector< int > d_index_order;
- //variables to index they are considered at
- // for example, if d_index_order = { 2, 0, 1 }
- // then d_var_order = { 0 -> 1, 1 -> 2, 2 -> 0 }
- std::map< int, int > d_var_order;
-public:
- /** set index order */
- void setIndexOrder( std::vector< int >& indexOrder );
- /** set domain */
- void setDomain( std::vector< RepDomain >& domain );
- /** increment the iterator at index=counter */
- void increment2( int counter );
- /** increment the iterator */
- void increment();
- /** is the iterator finished? */
- bool isFinished();
- /** get the i_th term we are considering */
- Node getTerm( int i );
- /** get the number of terms we are considering */
- int getNumTerms() { return (int)d_index_order.size(); }
- /** debug print */
- void debugPrint( const char* c );
- void debugPrintSmall( const char* c );
-};
-
-}
-}
-
-#endif
\ No newline at end of file + ** \brief Representative set class and utilities + **/ + +#include "cvc4_private.h" + +#ifndef __CVC4__THEORY__REP_SET_H +#define __CVC4__THEORY__REP_SET_H + +#include "expr/node.h" +#include <map> + +namespace CVC4 { +namespace theory { + +/** this class stores a representative set */ +class RepSet { +public: + RepSet(){} + ~RepSet(){} + std::map< TypeNode, std::vector< Node > > d_type_reps; + std::map< TypeNode, bool > d_type_complete; + std::map< Node, int > d_tmap; + /** clear the set */ + void clear(); + /** has type */ + bool hasType( TypeNode tn ) const { return d_type_reps.find( tn )!=d_type_reps.end(); } + /** get cardinality for type */ + int getNumRepresentatives( TypeNode tn ) const; + /** add representative for type */ + void add( Node n ); + /** returns index in d_type_reps for node n */ + int getIndexFor( Node n ) const; + /** complete all values */ + void complete( TypeNode t ); + /** debug print */ + void toStream(std::ostream& out); +};/* class RepSet */ + +//representative domain +typedef std::vector< int > RepDomain; + +/** this class iterates over a RepSet */ +class RepSetIterator { +private: + //initialize function + bool initialize(); +public: + RepSetIterator( RepSet* rs ); + ~RepSetIterator(){} + //set that this iterator will be iterating over instantiations for a quantifier + bool setQuantifier( Node f ); + //set that this iterator will be iterating over the domain of a function + bool setFunctionDomain( Node op ); +public: + //pointer to model + RepSet* d_rep_set; + //index we are considering + std::vector< int > d_index; + //types we are considering + std::vector< TypeNode > d_types; + //domain we are considering + std::vector< RepDomain > d_domain; + //are we only considering a strict subset of the domain of the quantifier? + bool d_incomplete; + //ordering for variables we are indexing over + // for example, given reps = { a, b } and quantifier forall( x, y, z ) P( x, y, z ) with d_index_order = { 2, 0, 1 }, + // then we consider instantiations in this order: + // a/x a/y a/z + // a/x b/y a/z + // b/x a/y a/z + // b/x b/y a/z + // ... + std::vector< int > d_index_order; + //variables to index they are considered at + // for example, if d_index_order = { 2, 0, 1 } + // then d_var_order = { 0 -> 1, 1 -> 2, 2 -> 0 } + std::map< int, int > d_var_order; +public: + /** set index order */ + void setIndexOrder( std::vector< int >& indexOrder ); + /** set domain */ + void setDomain( std::vector< RepDomain >& domain ); + /** increment the iterator at index=counter */ + void increment2( int counter ); + /** increment the iterator */ + void increment(); + /** is the iterator finished? */ + bool isFinished(); + /** get the i_th term we are considering */ + Node getTerm( int i ); + /** get the number of terms we are considering */ + int getNumTerms() { return (int)d_index_order.size(); } + /** debug print */ + void debugPrint( const char* c ); + void debugPrintSmall( const char* c ); +};/* class RepSetIterator */ + +}/* CVC4::theory namespace */ +}/* CVC4 namespace */ + +#endif /* __CVC4__THEORY__REP_SET_H */ diff --git a/src/theory/rewriterules/efficient_e_matching.cpp b/src/theory/rewriterules/efficient_e_matching.cpp index 2f39d8098..5ed34d46c 100755..100644 --- a/src/theory/rewriterules/efficient_e_matching.cpp +++ b/src/theory/rewriterules/efficient_e_matching.cpp @@ -1,686 +1,686 @@ -/********************* */
-/*! \file efficient_e_matching.cpp
- ** \verbatim
- ** Original author: ajreynol
- ** Major contributors: bobot
- ** Minor contributors (to current version): mdeters
- ** This file is part of the CVC4 prototype.
- ** Copyright (c) 2009-2012 New York University and The University of Iowa
- ** See the file COPYING in the top-level source directory for licensing
- ** information.\endverbatim
- **
- ** \brief Implementation of theory uf instantiator class
- **/
-
-#include "theory/rewriterules/efficient_e_matching.h"
-#include "theory/rewriterules/rr_candidate_generator.h"
-#include "theory/quantifiers/candidate_generator.h"
-#include "theory/quantifiers/options.h"
-#include "theory/rewriterules/options.h"
-#include "theory/quantifiers/term_database.h"
-
-#include "theory/theory_engine.h"
-
-using namespace std;
-using namespace CVC4;
-using namespace CVC4::kind;
-using namespace CVC4::context;
-using namespace CVC4::theory;
-using namespace CVC4::theory::inst;
-
-namespace CVC4 {
-namespace theory {
-
-inline std::ostream& operator<<(std::ostream& out, const EfficientEMatcher::Ips& ips) {
- return out;
-};
-
-EqClassInfo::EqClassInfo( context::Context* c ) : d_funs( c ), d_pfuns( c ), d_disequal( c ){
-
-}
-
-//set member
-void EqClassInfo::setMember( Node n, quantifiers::TermDb* db ){
- if( n.hasOperator() ){
- d_funs.insertAtContextLevelZero(n.getOperator(),true);
- }
- //add parent functions
- for( std::hash_map< Node, std::hash_map< int, std::vector< Node > >, NodeHashFunction >::iterator it = db->d_parents[n].begin();
- it != db->d_parents[n].end(); ++it ){
- //TODO Is it true to do it at level 0? That depend when SetMember is called
- // At worst it is a good overapproximation
- d_pfuns.insertAtContextLevelZero( it->first, true);
- }
-}
-
-//get has function
-bool EqClassInfo::hasFunction( Node op ){
- return d_funs.find( op )!=d_funs.end();
-}
-
-bool EqClassInfo::hasParent( Node op ){
- return d_pfuns.find( op )!=d_pfuns.end();
-}
-
-//merge with another eq class info
-void EqClassInfo::merge( EqClassInfo* eci ){
- for( BoolMap::iterator it = eci->d_funs.begin(); it != eci->d_funs.end(); it++ ) {
- d_funs[ (*it).first ] = true;
- }
- for( BoolMap::iterator it = eci->d_pfuns.begin(); it != eci->d_pfuns.end(); it++ ) {
- d_pfuns[ (*it).first ] = true;
- }
-}
-
-inline void outputEqClassInfo( const char* c, const EqClassInfo* eci){
- Debug(c) << " funs:";
- for( EqClassInfo::BoolMap::iterator it = eci->d_funs.begin(); it != eci->d_funs.end(); it++ ) {
- Debug(c) << (*it).first << ",";
- }
- Debug(c) << std::endl << "pfuns:";
- for( EqClassInfo::BoolMap::iterator it = eci->d_pfuns.begin(); it != eci->d_pfuns.end(); it++ ) {
- Debug(c) << (*it).first << ",";
- }
- Debug(c) << std::endl;
-}
-
-
-
-EfficientEMatcher::EfficientEMatcher( CVC4::theory::QuantifiersEngine* qe ) : d_quantEngine( qe )
-{
-
-}
-
-eq::EqualityEngine* EfficientEMatcher::getEqualityEngine(){
- //return ((uf::TheoryUF*)d_quantEngine->getTheoryEngine()->theoryOf( THEORY_UF ))->getEqualityEngine();
- return d_quantEngine->getMasterEqualityEngine();
-}
-
-/** new node */
-void EfficientEMatcher::newEqClass( TNode n ){
-
-}
-
-void EfficientEMatcher::newTerms(SetNode& s){
- static NoMatchAttribute rewrittenNodeAttribute;
- /* op -> nodes (if the set is empty, the op is not interesting) */
- std::hash_map< TNode, SetNode, TNodeHashFunction > h;
- /* types -> nodes (if the set is empty, the type is not interesting) */
- std::hash_map< TypeNode, SetNode, TypeNodeHashFunction > tyh;
- for(SetNode::iterator i=s.begin(), end=s.end(); i != end; ++i){
- if (i->getAttribute(rewrittenNodeAttribute)) continue; /* skip it */
- if( !d_cand_gens.empty() ){
- // op
- TNode op = i->getOperator();
- std::hash_map< TNode, SetNode, TNodeHashFunction >::iterator
- is = h.find(op);
- if(is == h.end()){
- std::pair<std::hash_map< TNode, SetNode, TNodeHashFunction >::iterator,bool>
- p = h.insert(make_pair(op,SetNode()));
- is = p.first;
- if(d_cand_gens.find(op) != d_cand_gens.end()){
- is->second.insert(*i);
- } /* else we have inserted an empty set */
- }else if(!is->second.empty()){
- is->second.insert(*i);
- }
- }
- if( !d_cand_gen_types.empty() ){
- //type
- TypeNode ty = i->getType();
- std::hash_map< TypeNode, SetNode, TypeNodeHashFunction >::iterator
- is = tyh.find(ty);
- if(is == tyh.end()){
- std::pair<std::hash_map< TypeNode, SetNode, TypeNodeHashFunction >::iterator,bool>
- p = tyh.insert(make_pair(ty,SetNode()));
- is = p.first;
- if(d_cand_gen_types.find(ty) != d_cand_gen_types.end()){
- is->second.insert(*i);
- } /* else we have inserted an empty set */
- }else if(!is->second.empty()){
- is->second.insert(*i);
- }
- }
- }
- //op
- for(std::hash_map< TNode, SetNode, TNodeHashFunction >::iterator i=h.begin(), end=h.end();
- i != end; ++i){
- //new term, add n to candidate generators
- if(i->second.empty()) continue;
- std::map< Node, NodeNewTermDispatcher >::iterator
- inpc = d_cand_gens.find(i->first);
- //we know that this op exists
- Assert(inpc != d_cand_gens.end());
- inpc->second.send(i->second);
- }
- //type
- for(std::hash_map< TypeNode, SetNode, TypeNodeHashFunction >::iterator i=tyh.begin(), end=tyh.end();
- i != end; ++i){
- //new term, add n to candidate generators
- if(i->second.empty()) continue;
- std::map< TypeNode, NodeNewTermDispatcher >::iterator
- inpc = d_cand_gen_types.find(i->first);
- //we know that this op exists
- Assert(inpc != d_cand_gen_types.end());
- inpc->second.send(i->second);
- }
-
-}
-
-
-/** merge */
-void EfficientEMatcher::merge( TNode a, TNode b ){
- if( options::efficientEMatching() ){
- //merge eqc_ops of b into a
- EqClassInfo* eci_a = getOrCreateEquivalenceClassInfo( a );
- EqClassInfo* eci_b = getOrCreateEquivalenceClassInfo( b );
-
- if( a.getKind()!=IFF && a.getKind()!=EQUAL && b.getKind()!=IFF && b.getKind()!=EQUAL ){
- Debug("efficient-e-match") << "Merging " << a << " with " << b << std::endl;
-
- //determine new candidates for instantiation
- computeCandidatesPcPairs( a, eci_a, b, eci_b );
- computeCandidatesPcPairs( b, eci_b, a, eci_a );
- computeCandidatesPpPairs( a, eci_a, b, eci_b );
- computeCandidatesPpPairs( b, eci_b, a, eci_a );
- }
- computeCandidatesConstants( a, eci_a, b, eci_b);
- computeCandidatesConstants( b, eci_b, a, eci_a);
-
- eci_a->merge( eci_b );
- }
-}
-
-/** assert terms are disequal */
-void EfficientEMatcher::assertDisequal( TNode a, TNode b, TNode reason ){
-
-}
-
-EqClassInfo* EfficientEMatcher::getEquivalenceClassInfo( Node n ) {
- return d_eqc_ops.find( n )==d_eqc_ops.end() ? NULL : d_eqc_ops[n];
-}
-EqClassInfo* EfficientEMatcher::getOrCreateEquivalenceClassInfo( Node n ){
- Assert( n==getEqualityEngine()->getRepresentative( n ) );
- if( d_eqc_ops.find( n )==d_eqc_ops.end() ){
- EqClassInfo* eci = new EqClassInfo( d_quantEngine->getSatContext() );
- eci->setMember( n, d_quantEngine->getTermDatabase() );
- d_eqc_ops[n] = eci;
- }
- return d_eqc_ops[n];
-}
-
-void EfficientEMatcher::computeCandidatesPcPairs( Node a, EqClassInfo* eci_a, Node b, EqClassInfo* eci_b ){
- Debug("efficient-e-match") << "Compute candidates for pc pairs..." << std::endl;
- Debug("efficient-e-match") << " Eq class = [";
- outputEqClass( "efficient-e-match", a);
- Debug("efficient-e-match") << "]" << std::endl;
- outputEqClassInfo("efficient-e-match",eci_a);
- for( EqClassInfo::BoolMap::iterator it = eci_a->d_funs.begin(); it != eci_a->d_funs.end(); it++ ) {
- //the child function: a member of eq_class( a ) has top symbol g, in other words g is in funs( a )
- Node g = (*it).first;
- Debug("efficient-e-match") << " Checking application " << g << std::endl;
- //look at all parent/child pairs
- for( std::map< Node, std::vector< std::pair< NodePcDispatcher*, Ips > > >::iterator itf = d_pc_pairs[g].begin();
- itf != d_pc_pairs[g].end(); ++itf ){
- //f/g is a parent/child pair
- Node f = itf->first;
- if( eci_b->hasParent( f ) ){
- //DO_THIS: determine if f in pfuns( b ), only do the follow if so
- Debug("efficient-e-match") << " Checking parent application " << f << std::endl;
- //scan through the list of inverted path strings/candidate generators
- for( std::vector< std::pair< NodePcDispatcher*, Ips > >::iterator cit = itf->second.begin();
- cit != itf->second.end(); ++cit ){
-#ifdef CVC4_DEBUG
- Debug("efficient-e-match") << " Checking pattern " << cit->first->pat << std::endl;
-#endif
- Debug("efficient-e-match") << " Check inverted path string for pattern ";
- outputIps( "efficient-e-match", cit->second );
- Debug("efficient-e-match") << std::endl;
-
- //collect all new relevant terms
- SetNode terms;
- terms.insert( b );
- collectTermsIps( cit->second, terms );
- if( terms.empty() ) continue;
- Debug("efficient-e-match") << " -> Added terms (" << terms.size() << "): ";
- for( SetNode::const_iterator t=terms.begin(), end=terms.end();
- t!=end; ++t ){
- Debug("efficient-e-match") << (*t) << " ";
- }
- Debug("efficient-e-match") << std::endl;
- //add them as candidates to the candidate generator
- cit->first->send(terms);
- }
- }
- }
- }
-}
-
-void EfficientEMatcher::computeCandidatesPpPairs( Node a, EqClassInfo* eci_a, Node b, EqClassInfo* eci_b ){
- Debug("efficient-e-match") << "Compute candidates for pp pairs..." << std::endl;
- for( std::map< Node, std::map< Node, std::vector< triple< NodePpDispatcher*, Ips, Ips > > > >::iterator it = d_pp_pairs.begin();
- it != d_pp_pairs.end(); ++it ){
- Node f = it->first;
- if( eci_a->hasParent( f ) ){
- Debug("efficient-e-match") << " Checking parent application " << f << std::endl;
- for( std::map< Node, std::vector< triple<NodePpDispatcher*, Ips, Ips> > >::iterator it2 = it->second.begin();
- it2 != it->second.end(); ++it2 ){
- Node g = it2->first;
- if( eci_b->hasParent( g ) ){
- Debug("efficient-e-match") << " Checking parent application " << g << std::endl;
- //if f in pfuns( a ) and g is in pfuns( b ), only do the follow if so
- for( std::vector< triple<NodePpDispatcher*, Ips, Ips> > ::iterator cit = it2->second.begin();
- cit != it2->second.end(); ++cit ){
-#ifdef CVC4_DEBUG
- Debug("efficient-e-match") << " Checking pattern " << cit->first->pat1 << " and " << cit->first->pat2 << std::endl;
-#endif
- Debug("efficient-e-match") << " Check inverted path string ";
- outputIps( "efficient-e-match", cit->second );
- SetNode a_terms;
- a_terms.insert( a );
- collectTermsIps( cit->second, a_terms );
- if( a_terms.empty() ) continue;
- Debug("efficient-e-match") << " And check inverted path string ";
- outputIps( "efficient-e-match", cit->third );
- SetNode b_terms;
- b_terms.insert( b );
- collectTermsIps( cit->third, b_terms );
- if( b_terms.empty() ) continue;
- //Start debug
- Debug("efficient-e-match") << " -> Possibly Added termsA (" << a_terms.size() << "): ";
- for( SetNode::const_iterator t=a_terms.begin(), end=a_terms.end();
- t!=end; ++t ){
- Debug("efficient-e-match") << (*t) << " ";
- }
- Debug("efficient-e-match") << std::endl;
- Debug("efficient-e-match") << " -> Possibly Added termsB (" << b_terms.size() << "): ";
- for( SetNode::const_iterator t=b_terms.begin(), end=b_terms.end();
- t!=end; ++t ){
- Debug("efficient-e-match") << (*t) << " ";
- }
- Debug("efficient-e-match") << std::endl;
- //End debug
-
- cit->first->send(a_terms,b_terms);
- }
- }
- }
- }
- }
-}
-
-
-void EfficientEMatcher::computeCandidatesConstants( Node a, EqClassInfo* eci_a, Node b, EqClassInfo* eci_b ){
- Debug("efficient-e-match") << "Compute candidates constants for cc pairs..." << std::endl;
- Debug("efficient-e-match") << " Eq class = [";
- outputEqClass( "efficient-e-match", a);
- Debug("efficient-e-match") << "]" << std::endl;
- outputEqClassInfo("efficient-e-match",eci_a);
- for( std::map< Node, std::map< Node, NodePcDispatcher* > >::iterator
- it = d_cc_pairs.begin(), end = d_cc_pairs.end();
- it != end; ++it ) {
- Debug("efficient-e-match") << " Checking application " << it->first << std::endl;
- if( !eci_b->hasFunction(it->first) ) continue;
- for( std::map< Node, NodePcDispatcher* >::iterator
- itc = it->second.begin(), end = it->second.end();
- itc != end; ++itc ) {
- //The constant
- Debug("efficient-e-match") << " Checking constant " << a << std::endl;
- if(getEqualityEngine()->getRepresentative(itc->first) != a) continue;
- SetNode s;
- eq::EqClassIterator eqc_iter( b, getEqualityEngine() );
- while( !eqc_iter.isFinished() ){
- Debug("efficient-e-match-debug") << "> look at " << (*eqc_iter)
- << std::endl;
- if( (*eqc_iter).hasOperator() && (*eqc_iter).getOperator() == it->first ) s.insert(*eqc_iter);
- eqc_iter++;
- }
-
- if( s.empty() ) continue;
- Debug("efficient-e-match") << " -> Added terms (" << s.size() << "): ";
- for( SetNode::const_iterator t=s.begin(), end=s.end();
- t!=end; ++t ){
- Debug("efficient-e-match") << (*t) << " ";
- }
- Debug("efficient-e-match") << std::endl;
- itc->second->send(s);
- }
- }
-}
-
-void EfficientEMatcher::collectTermsIps( Ips& ips, SetNode & terms ){
- Assert( ips.size() > 0);
- return collectTermsIps( ips, terms, ips.size() - 1);
-}
-
-void EfficientEMatcher::collectTermsIps( Ips& ips, SetNode& terms, int index ){
- if( !terms.empty() ){
- Debug("efficient-e-match-debug") << "> Process " << index << std::endl;
- Node f = ips[index].first;
- int arg = ips[index].second;
-
- //for each term in terms, determine if any term (modulo equality) has parent "f" from position "arg"
- bool addRep = ( index!=0 ); // We want to keep the top symbol for the last
- SetNode newTerms;
- for( SetNode::const_iterator t=terms.begin(), end=terms.end();
- t!=end; ++t ){
- collectParentsTermsIps( *t, f, arg, newTerms, addRep );
- }
- terms.swap(newTerms);
-
- Debug("efficient-e-match-debug") << "> Terms are now: ";
- for( SetNode::const_iterator t=terms.begin(), end=terms.end();
- t!=end; ++t ){
- Debug("efficient-e-match-debug") << *t << " ";
- }
- Debug("efficient-e-match-debug") << std::endl;
-
- if(index!=0) collectTermsIps( ips, terms, index-1 );
- }
-}
-
-bool EfficientEMatcher::collectParentsTermsIps( Node n, Node f, int arg, SetNode & terms, bool addRep, bool modEq ){ //modEq default true
- bool addedTerm = false;
-
- if( modEq && getEqualityEngine()->hasTerm( n )){
- Assert( getEqualityEngine()->getRepresentative( n )==n );
- //collect modulo equality
- //DO_THIS: this should (if necessary) compute a current set of (f, arg) parents for n and cache it
- eq::EqClassIterator eqc_iter( n, getEqualityEngine() );
- while( !eqc_iter.isFinished() ){
- Debug("efficient-e-match-debug") << "> look at " << (*eqc_iter)
- << std::endl;
- if( collectParentsTermsIps( (*eqc_iter), f, arg, terms, addRep, false ) ){
- //if only one argument, we know we can stop (since all others added will be congruent)
- if( f.getType().getNumChildren()==2 ){
- return true;
- }
- addedTerm = true;
- }
- eqc_iter++;
- }
- }else{
- quantifiers::TermDb* db = d_quantEngine->getTermDatabase();
- //see if parent f exists from argument arg
- const std::vector<Node> & parents = db->getParents(n,f,arg);
- for( size_t i=0; i<parents.size(); ++i ){
- TNode t = parents[i];
- if(!CandidateGenerator::isLegalCandidate(t)) continue;
- if( addRep ) t = getEqualityEngine()->getRepresentative( t );
- terms.insert(t);
- addedTerm = true;
- }
- }
- return addedTerm;
-}
-
-void EfficientEMatcher::registerPatternElementPairs2( Node pat, Ips& ips, PpIpsMap & pp_ips_map, NodePcDispatcher* npc ){
- Assert( pat.hasOperator() );
- //add information for possible pp-pair
- ips.push_back( std::pair< Node, int >( pat.getOperator(), 0 ) ); //0 is just a dumb value
-
- for( int i=0; i<(int)pat.getNumChildren(); i++ ){
- if( pat[i].getKind()==INST_CONSTANT ){
- ips.back().second = i;
- pp_ips_map[ pat[i] ].push_back( make_pair( pat.getOperator(), Ips( ips ) ) );
- }
- }
-
- for( int i=0; i<(int)pat.getNumChildren(); i++ ){
- if( pat[i].getKind()==APPLY_UF ){
- ips.back().second = i;
- registerPatternElementPairs2( pat[i], ips, pp_ips_map, npc );
- Debug("pattern-element-opt") << "Found pc-pair ( " << pat.getOperator() << ", " << pat[i].getOperator() << " )" << std::endl;
- Debug("pattern-element-opt") << " Path = ";
- outputIps( "pattern-element-opt", ips );
- Debug("pattern-element-opt") << std::endl;
- //pat.getOperator() and pat[i].getOperator() are a pc-pair
- d_pc_pairs[ pat[i].getOperator() ][ pat.getOperator() ]
- .push_back( make_pair(npc,Ips(ips)) );
- }
- }
- ips.pop_back();
-}
-
-void EfficientEMatcher::registerPatternElementPairs( Node pat, PpIpsMap & pp_ips_map,
- NodePcDispatcher* npc,
- NodePpDispatcher* npp){
- Ips ips;
- registerPatternElementPairs2( pat, ips, pp_ips_map, npc );
- for( PpIpsMap::iterator it = pp_ips_map.begin(); it != pp_ips_map.end(); ++it ){
- // for each variable construct all the pp-pair
- for( size_t j=0; j<it->second.size(); j++ ){
- for( size_t k=j+1; k<it->second.size(); k++ ){
- //found a pp-pair
- Debug("pattern-element-opt") << "Found pp-pair ( " << it->second[j].first << ", " << it->second[k].first << " )" << std::endl;
- Debug("pattern-element-opt") << " Paths = ";
- outputIps( "pattern-element-opt", it->second[j].second );
- Debug("pattern-element-opt") << " and ";
- outputIps( "pattern-element-opt", it->second[k].second );
- Debug("pattern-element-opt") << std::endl;
- d_pp_pairs[ it->second[j].first ][ it->second[k].first ]
- .push_back( make_triple( npp, it->second[j].second, it->second[k].second ));
- }
- }
- }
-};
-
-void findPpSite(Node pat, EfficientEMatcher::Ips& ips, EfficientEMatcher::PpIpsMap & pp_ips_map){
- Assert( pat.getKind()==APPLY_UF );
- //add information for possible pp-pair
-
- ips.push_back( make_pair( pat.getOperator(), 0) );
- for( size_t i=0; i<pat.getNumChildren(); i++ ){
- if( pat[i].getKind()==INST_CONSTANT ){
- ips.back().second = i;
- pp_ips_map[ pat[i] ].push_back( make_pair( pat.getOperator(), EfficientEMatcher::Ips( ips ) ) );
- }
- }
-
- for( size_t i=0; i<pat.getNumChildren(); i++ ){
- if( pat[i].getKind()==APPLY_UF ){
- ips.back().second = i;
- findPpSite( pat[i], ips, pp_ips_map );
- }
- }
- ips.pop_back();
-}
-
-void EfficientEMatcher::combineMultiPpIpsMap(PpIpsMap & pp_ips_map, MultiPpIpsMap & multi_pp_ips_map,
- EfficientHandler& eh, size_t index2,const std::vector<Node> & pats){
- hash_map<size_t,NodePpDispatcher*> npps;
- for( PpIpsMap::iterator it = pp_ips_map.begin(); it != pp_ips_map.end(); ++it ){
- MultiPpIpsMap::iterator mit = multi_pp_ips_map.find(it->first);
- if(mit == multi_pp_ips_map.end()) continue;
- // for each variable construct all the pp-pair
- // j the last pattern treated
- for( std::vector< std::pair< Node, Ips > >::iterator j=it->second.begin(), jend = it->second.end() ;
- j != jend; ++j){
- // k one of the previous one
- for( std::vector< triple< size_t, Node, Ips > >::iterator k=mit->second.begin(), kend = mit->second.end() ;
- k != kend; ++k){
- //found a pp-pair
- Debug("pattern-element-opt") << "Found multi-pp-pair ( " << j->first
- << ", " << k->second << " in "<< k->first
- << " )" << std::endl;
- Debug("pattern-element-opt") << " Paths = ";
- outputIps( "pattern-element-opt", j->second );
- Debug("pattern-element-opt") << " and ";
- outputIps( "pattern-element-opt", k->third );
- Debug("pattern-element-opt") << std::endl;
- NodePpDispatcher* dispatcher;
- hash_map<size_t,NodePpDispatcher*>::iterator inpp = npps.find(k->first);
- if( inpp != npps.end() ) dispatcher = inpp->second;
- else{
- dispatcher = new NodePpDispatcher();
-#ifdef CVC4_DEBUG
- dispatcher->pat1 = pats[index2];
- dispatcher->pat2 = pats[k->first];
-#endif
- dispatcher->addPpDispatcher(&eh,index2,k->first);
- };
- d_pp_pairs[ j->first ][ k->second ].push_back( make_triple( dispatcher, j->second, k->third ));
- }
- }
- }
-
- /** Put pp_ips_map to multi_pp_ips_map */
- for( PpIpsMap::iterator it = pp_ips_map.begin(); it != pp_ips_map.end(); ++it ){
- for( std::vector< std::pair< Node, Ips > >::iterator j=it->second.begin(), jend = it->second.end() ;
- j != jend; ++j){
- multi_pp_ips_map[it->first].push_back(make_triple(index2, j->first, j->second));
- }
- }
-
-}
-
-
-void EfficientEMatcher::registerEfficientHandler( EfficientHandler& handler,
- const std::vector< Node > & pats ){
- Assert(pats.size() > 0);
-
- MultiPpIpsMap multi_pp_ips_map;
- PpIpsMap pp_ips_map;
- //In a multi-pattern Pattern that is only a variable are specials,
- //if the variable appears in another pattern, it can be discarded.
- //Otherwise new term of this term can be candidate. So we stock them
- //here before adding them.
- std::vector< size_t > patVars;
-
- Debug("pattern-element-opt") << "Register patterns" << pats << std::endl;
- for(size_t i = 0; i < pats.size(); ++i){
- if( pats[i].getKind() == kind::INST_CONSTANT){
- patVars.push_back(i);
- continue;
- }
- //to complete
- if( pats[i].getKind() == kind::NOT && pats[i][0].getKind() == kind::EQUAL){
- Node cst = NodeManager::currentNM()->mkConst<bool>(false);
- TNode op = pats[i][0].getOperator();
- if(d_cc_pairs[op][cst] == NULL){
- d_cc_pairs[op][cst] = new NodePcDispatcher();
- }
- d_cc_pairs[op][cst]->addPcDispatcher(&handler,i);
- continue;
- }
- //end to complete
- Debug("pattern-element-opt") << " Register candidate generator..." << pats[i] << std::endl;
- /* Has the pattern already been seen */
- if( d_pat_cand_gens.find( pats[i] )==d_pat_cand_gens.end() ){
- NodePcDispatcher* npc = new NodePcDispatcher();
- NodePpDispatcher* npp = new NodePpDispatcher();
-#ifdef CVC4_DEBUG
- npc->pat = pats[i];
- npp->pat1 = pats[i];
- npp->pat2 = pats[i];
-#endif
- d_pat_cand_gens[pats[i]] = make_pair(npc,npp);
- registerPatternElementPairs( pats[i], pp_ips_map, npc, npp );
- }else{
- Ips ips;
- findPpSite(pats[i],ips,pp_ips_map);
- }
- //Has the top operator already been seen */
- TNode op = pats[i].getOperator();
- d_pat_cand_gens[pats[i]].first->addPcDispatcher(&handler,i);
- d_pat_cand_gens[pats[i]].second->addPpDispatcher(&handler,i,i);
- d_cand_gens[op].addNewTermDispatcher(&handler,i);
-
- combineMultiPpIpsMap(pp_ips_map,multi_pp_ips_map,handler,i,pats);
-
- pp_ips_map.clear();
- }
-
- for(size_t i = 0; i < patVars.size(); ++i){
- TNode var = pats[patVars[i]];
- Assert( var.getKind() == kind::INST_CONSTANT );
- if( multi_pp_ips_map.find(var) != multi_pp_ips_map.end() ){
- //The variable appear in another pattern, skip it
- continue;
- };
- d_cand_gen_types[var.getType()].addNewTermDispatcher(&handler,patVars[i]);
- }
-
- //take all terms from the uf term db and add to candidate generator
- if( pats[0].getKind() == kind::INST_CONSTANT ){
- TypeNode ty = pats[0].getType();
- rrinst::CandidateGenerator* cg = new GenericCandidateGeneratorClasses(d_quantEngine);
- cg->reset(Node::null());
- TNode c;
- SetNode ele;
- while( !(c = cg->getNextCandidate()).isNull() ){
- if( c.getType() == ty ) ele.insert(c);
- }
- if( !ele.empty() ){
- // for(std::vector<Node>::iterator i = db->d_op_map[op].begin(), end = db->d_op_map[op].end(); i != end; ++i){
- // if(CandidateGenerator::isLegalCandidate(*i)) ele.insert(*i);
- // }
- if(Debug.isOn("efficient-e-match-stats")){
- Debug("efficient-e-match-stats") << "pattern " << pats << " initialized with " << ele.size() << " terms"<< std::endl;
- }
- handler.addMonoCandidate(ele, 0);
- }
-
- } else if( pats[0].getKind() == kind::NOT && pats[0][0].getKind() == kind::EQUAL){
- Node cst = NodeManager::currentNM()->mkConst<bool>(false);
- TNode op = pats[0][0].getOperator();
- cst = getEqualityEngine()->getRepresentative(cst);
- SetNode ele;
- eq::EqClassIterator eqc_iter( cst, getEqualityEngine() );
- while( !eqc_iter.isFinished() ){
- Debug("efficient-e-match-debug") << "> look at " << (*eqc_iter)
- << std::endl;
- if( (*eqc_iter).hasOperator() && (*eqc_iter).getOperator() == op ) ele.insert(*eqc_iter);
- eqc_iter++;
- }
- if( !ele.empty() ){
- if(Debug.isOn("efficient-e-match-stats")){
- Debug("efficient-e-match-stats") << "pattern " << pats << " initialized with " << ele.size() << " terms"<< std::endl;
- }
- handler.addMonoCandidate(ele, 0);
- }
-
- } else {
- Node op = pats[0].getOperator();
- TermDb* db = d_quantEngine->getTermDatabase();
- if(db->d_op_map[op].begin() != db->d_op_map[op].end()){
- SetNode ele;
- // for(std::vector<Node>::iterator i = db->d_op_map[op].begin(), end = db->d_op_map[op].end(); i != end; ++i){
- // if(CandidateGenerator::isLegalCandidate(*i)) ele.insert(*i);
- // }
- ele.insert(db->d_op_map[op].begin(), db->d_op_map[op].end());
- if(Debug.isOn("efficient-e-match-stats")){
- Debug("efficient-e-match-stats") << "pattern " << pats << " initialized with " << ele.size() << " terms"<< std::endl;
- }
- handler.addMonoCandidate(ele, 0);
- }
- }
- Debug("efficient-e-match") << "Done." << std::endl;
-}
-
-void EfficientEMatcher::outputEqClass( const char* c, Node n ){
- if( getEqualityEngine()->hasTerm( n ) ){
- eq::EqClassIterator eqc_iter( getEqualityEngine()->getRepresentative( n ),
- getEqualityEngine() );
- bool firstTime = true;
- while( !eqc_iter.isFinished() ){
- if( !firstTime ){ Debug(c) << ", "; }
- Debug(c) << (*eqc_iter);
- firstTime = false;
- eqc_iter++;
- }
- }else{
- Debug(c) << n;
- }
-}
-
-void EfficientEMatcher::outputIps( const char* c, Ips& ips ){
- for( int i=0; i<(int)ips.size(); i++ ){
- if( i>0 ){ Debug( c ) << "."; }
- Debug( c ) << ips[i].first << "." << ips[i].second;
- }
-}
-
-
-} /* namespace theory */
-} /* namespace cvc4 */
+/********************* */ +/*! \file efficient_e_matching.cpp + ** \verbatim + ** Original author: Andrew Reynolds <andrew.j.reynolds@gmail.com> + ** Major contributors: Morgan Deters <mdeters@cs.nyu.edu> + ** Minor contributors (to current version): none + ** This file is part of the CVC4 project. + ** Copyright (c) 2009-2013 New York University and The University of Iowa + ** See the file COPYING in the top-level source directory for licensing + ** information.\endverbatim + ** + ** \brief Implementation of theory uf instantiator class + **/ + +#include "theory/rewriterules/efficient_e_matching.h" +#include "theory/rewriterules/rr_candidate_generator.h" +#include "theory/quantifiers/candidate_generator.h" +#include "theory/quantifiers/options.h" +#include "theory/rewriterules/options.h" +#include "theory/quantifiers/term_database.h" + +#include "theory/theory_engine.h" + +using namespace std; +using namespace CVC4; +using namespace CVC4::kind; +using namespace CVC4::context; +using namespace CVC4::theory; +using namespace CVC4::theory::inst; + +namespace CVC4 { +namespace theory { + +inline std::ostream& operator<<(std::ostream& out, const EfficientEMatcher::Ips& ips) { + return out; +}; + +EqClassInfo::EqClassInfo( context::Context* c ) : d_funs( c ), d_pfuns( c ), d_disequal( c ){ + +} + +//set member +void EqClassInfo::setMember( Node n, quantifiers::TermDb* db ){ + if( n.hasOperator() ){ + d_funs.insertAtContextLevelZero(n.getOperator(),true); + } + //add parent functions + for( std::hash_map< Node, std::hash_map< int, std::vector< Node > >, NodeHashFunction >::iterator it = db->d_parents[n].begin(); + it != db->d_parents[n].end(); ++it ){ + //TODO Is it true to do it at level 0? That depend when SetMember is called + // At worst it is a good overapproximation + d_pfuns.insertAtContextLevelZero( it->first, true); + } +} + +//get has function +bool EqClassInfo::hasFunction( Node op ){ + return d_funs.find( op )!=d_funs.end(); +} + +bool EqClassInfo::hasParent( Node op ){ + return d_pfuns.find( op )!=d_pfuns.end(); +} + +//merge with another eq class info +void EqClassInfo::merge( EqClassInfo* eci ){ + for( BoolMap::iterator it = eci->d_funs.begin(); it != eci->d_funs.end(); it++ ) { + d_funs[ (*it).first ] = true; + } + for( BoolMap::iterator it = eci->d_pfuns.begin(); it != eci->d_pfuns.end(); it++ ) { + d_pfuns[ (*it).first ] = true; + } +} + +inline void outputEqClassInfo( const char* c, const EqClassInfo* eci){ + Debug(c) << " funs:"; + for( EqClassInfo::BoolMap::iterator it = eci->d_funs.begin(); it != eci->d_funs.end(); it++ ) { + Debug(c) << (*it).first << ","; + } + Debug(c) << std::endl << "pfuns:"; + for( EqClassInfo::BoolMap::iterator it = eci->d_pfuns.begin(); it != eci->d_pfuns.end(); it++ ) { + Debug(c) << (*it).first << ","; + } + Debug(c) << std::endl; +} + + + +EfficientEMatcher::EfficientEMatcher( CVC4::theory::QuantifiersEngine* qe ) : d_quantEngine( qe ) +{ + +} + +eq::EqualityEngine* EfficientEMatcher::getEqualityEngine(){ + //return ((uf::TheoryUF*)d_quantEngine->getTheoryEngine()->theoryOf( THEORY_UF ))->getEqualityEngine(); + return d_quantEngine->getMasterEqualityEngine(); +} + +/** new node */ +void EfficientEMatcher::newEqClass( TNode n ){ + +} + +void EfficientEMatcher::newTerms(SetNode& s){ + static NoMatchAttribute rewrittenNodeAttribute; + /* op -> nodes (if the set is empty, the op is not interesting) */ + std::hash_map< TNode, SetNode, TNodeHashFunction > h; + /* types -> nodes (if the set is empty, the type is not interesting) */ + std::hash_map< TypeNode, SetNode, TypeNodeHashFunction > tyh; + for(SetNode::iterator i=s.begin(), end=s.end(); i != end; ++i){ + if (i->getAttribute(rewrittenNodeAttribute)) continue; /* skip it */ + if( !d_cand_gens.empty() ){ + // op + TNode op = i->getOperator(); + std::hash_map< TNode, SetNode, TNodeHashFunction >::iterator + is = h.find(op); + if(is == h.end()){ + std::pair<std::hash_map< TNode, SetNode, TNodeHashFunction >::iterator,bool> + p = h.insert(make_pair(op,SetNode())); + is = p.first; + if(d_cand_gens.find(op) != d_cand_gens.end()){ + is->second.insert(*i); + } /* else we have inserted an empty set */ + }else if(!is->second.empty()){ + is->second.insert(*i); + } + } + if( !d_cand_gen_types.empty() ){ + //type + TypeNode ty = i->getType(); + std::hash_map< TypeNode, SetNode, TypeNodeHashFunction >::iterator + is = tyh.find(ty); + if(is == tyh.end()){ + std::pair<std::hash_map< TypeNode, SetNode, TypeNodeHashFunction >::iterator,bool> + p = tyh.insert(make_pair(ty,SetNode())); + is = p.first; + if(d_cand_gen_types.find(ty) != d_cand_gen_types.end()){ + is->second.insert(*i); + } /* else we have inserted an empty set */ + }else if(!is->second.empty()){ + is->second.insert(*i); + } + } + } + //op + for(std::hash_map< TNode, SetNode, TNodeHashFunction >::iterator i=h.begin(), end=h.end(); + i != end; ++i){ + //new term, add n to candidate generators + if(i->second.empty()) continue; + std::map< Node, NodeNewTermDispatcher >::iterator + inpc = d_cand_gens.find(i->first); + //we know that this op exists + Assert(inpc != d_cand_gens.end()); + inpc->second.send(i->second); + } + //type + for(std::hash_map< TypeNode, SetNode, TypeNodeHashFunction >::iterator i=tyh.begin(), end=tyh.end(); + i != end; ++i){ + //new term, add n to candidate generators + if(i->second.empty()) continue; + std::map< TypeNode, NodeNewTermDispatcher >::iterator + inpc = d_cand_gen_types.find(i->first); + //we know that this op exists + Assert(inpc != d_cand_gen_types.end()); + inpc->second.send(i->second); + } + +} + + +/** merge */ +void EfficientEMatcher::merge( TNode a, TNode b ){ + if( options::efficientEMatching() ){ + //merge eqc_ops of b into a + EqClassInfo* eci_a = getOrCreateEquivalenceClassInfo( a ); + EqClassInfo* eci_b = getOrCreateEquivalenceClassInfo( b ); + + if( a.getKind()!=IFF && a.getKind()!=EQUAL && b.getKind()!=IFF && b.getKind()!=EQUAL ){ + Debug("efficient-e-match") << "Merging " << a << " with " << b << std::endl; + + //determine new candidates for instantiation + computeCandidatesPcPairs( a, eci_a, b, eci_b ); + computeCandidatesPcPairs( b, eci_b, a, eci_a ); + computeCandidatesPpPairs( a, eci_a, b, eci_b ); + computeCandidatesPpPairs( b, eci_b, a, eci_a ); + } + computeCandidatesConstants( a, eci_a, b, eci_b); + computeCandidatesConstants( b, eci_b, a, eci_a); + + eci_a->merge( eci_b ); + } +} + +/** assert terms are disequal */ +void EfficientEMatcher::assertDisequal( TNode a, TNode b, TNode reason ){ + +} + +EqClassInfo* EfficientEMatcher::getEquivalenceClassInfo( Node n ) { + return d_eqc_ops.find( n )==d_eqc_ops.end() ? NULL : d_eqc_ops[n]; +} +EqClassInfo* EfficientEMatcher::getOrCreateEquivalenceClassInfo( Node n ){ + Assert( n==getEqualityEngine()->getRepresentative( n ) ); + if( d_eqc_ops.find( n )==d_eqc_ops.end() ){ + EqClassInfo* eci = new EqClassInfo( d_quantEngine->getSatContext() ); + eci->setMember( n, d_quantEngine->getTermDatabase() ); + d_eqc_ops[n] = eci; + } + return d_eqc_ops[n]; +} + +void EfficientEMatcher::computeCandidatesPcPairs( Node a, EqClassInfo* eci_a, Node b, EqClassInfo* eci_b ){ + Debug("efficient-e-match") << "Compute candidates for pc pairs..." << std::endl; + Debug("efficient-e-match") << " Eq class = ["; + outputEqClass( "efficient-e-match", a); + Debug("efficient-e-match") << "]" << std::endl; + outputEqClassInfo("efficient-e-match",eci_a); + for( EqClassInfo::BoolMap::iterator it = eci_a->d_funs.begin(); it != eci_a->d_funs.end(); it++ ) { + //the child function: a member of eq_class( a ) has top symbol g, in other words g is in funs( a ) + Node g = (*it).first; + Debug("efficient-e-match") << " Checking application " << g << std::endl; + //look at all parent/child pairs + for( std::map< Node, std::vector< std::pair< NodePcDispatcher*, Ips > > >::iterator itf = d_pc_pairs[g].begin(); + itf != d_pc_pairs[g].end(); ++itf ){ + //f/g is a parent/child pair + Node f = itf->first; + if( eci_b->hasParent( f ) ){ + //DO_THIS: determine if f in pfuns( b ), only do the follow if so + Debug("efficient-e-match") << " Checking parent application " << f << std::endl; + //scan through the list of inverted path strings/candidate generators + for( std::vector< std::pair< NodePcDispatcher*, Ips > >::iterator cit = itf->second.begin(); + cit != itf->second.end(); ++cit ){ +#ifdef CVC4_DEBUG + Debug("efficient-e-match") << " Checking pattern " << cit->first->pat << std::endl; +#endif + Debug("efficient-e-match") << " Check inverted path string for pattern "; + outputIps( "efficient-e-match", cit->second ); + Debug("efficient-e-match") << std::endl; + + //collect all new relevant terms + SetNode terms; + terms.insert( b ); + collectTermsIps( cit->second, terms ); + if( terms.empty() ) continue; + Debug("efficient-e-match") << " -> Added terms (" << terms.size() << "): "; + for( SetNode::const_iterator t=terms.begin(), end=terms.end(); + t!=end; ++t ){ + Debug("efficient-e-match") << (*t) << " "; + } + Debug("efficient-e-match") << std::endl; + //add them as candidates to the candidate generator + cit->first->send(terms); + } + } + } + } +} + +void EfficientEMatcher::computeCandidatesPpPairs( Node a, EqClassInfo* eci_a, Node b, EqClassInfo* eci_b ){ + Debug("efficient-e-match") << "Compute candidates for pp pairs..." << std::endl; + for( std::map< Node, std::map< Node, std::vector< triple< NodePpDispatcher*, Ips, Ips > > > >::iterator it = d_pp_pairs.begin(); + it != d_pp_pairs.end(); ++it ){ + Node f = it->first; + if( eci_a->hasParent( f ) ){ + Debug("efficient-e-match") << " Checking parent application " << f << std::endl; + for( std::map< Node, std::vector< triple<NodePpDispatcher*, Ips, Ips> > >::iterator it2 = it->second.begin(); + it2 != it->second.end(); ++it2 ){ + Node g = it2->first; + if( eci_b->hasParent( g ) ){ + Debug("efficient-e-match") << " Checking parent application " << g << std::endl; + //if f in pfuns( a ) and g is in pfuns( b ), only do the follow if so + for( std::vector< triple<NodePpDispatcher*, Ips, Ips> > ::iterator cit = it2->second.begin(); + cit != it2->second.end(); ++cit ){ +#ifdef CVC4_DEBUG + Debug("efficient-e-match") << " Checking pattern " << cit->first->pat1 << " and " << cit->first->pat2 << std::endl; +#endif + Debug("efficient-e-match") << " Check inverted path string "; + outputIps( "efficient-e-match", cit->second ); + SetNode a_terms; + a_terms.insert( a ); + collectTermsIps( cit->second, a_terms ); + if( a_terms.empty() ) continue; + Debug("efficient-e-match") << " And check inverted path string "; + outputIps( "efficient-e-match", cit->third ); + SetNode b_terms; + b_terms.insert( b ); + collectTermsIps( cit->third, b_terms ); + if( b_terms.empty() ) continue; + //Start debug + Debug("efficient-e-match") << " -> Possibly Added termsA (" << a_terms.size() << "): "; + for( SetNode::const_iterator t=a_terms.begin(), end=a_terms.end(); + t!=end; ++t ){ + Debug("efficient-e-match") << (*t) << " "; + } + Debug("efficient-e-match") << std::endl; + Debug("efficient-e-match") << " -> Possibly Added termsB (" << b_terms.size() << "): "; + for( SetNode::const_iterator t=b_terms.begin(), end=b_terms.end(); + t!=end; ++t ){ + Debug("efficient-e-match") << (*t) << " "; + } + Debug("efficient-e-match") << std::endl; + //End debug + + cit->first->send(a_terms,b_terms); + } + } + } + } + } +} + + +void EfficientEMatcher::computeCandidatesConstants( Node a, EqClassInfo* eci_a, Node b, EqClassInfo* eci_b ){ + Debug("efficient-e-match") << "Compute candidates constants for cc pairs..." << std::endl; + Debug("efficient-e-match") << " Eq class = ["; + outputEqClass( "efficient-e-match", a); + Debug("efficient-e-match") << "]" << std::endl; + outputEqClassInfo("efficient-e-match",eci_a); + for( std::map< Node, std::map< Node, NodePcDispatcher* > >::iterator + it = d_cc_pairs.begin(), end = d_cc_pairs.end(); + it != end; ++it ) { + Debug("efficient-e-match") << " Checking application " << it->first << std::endl; + if( !eci_b->hasFunction(it->first) ) continue; + for( std::map< Node, NodePcDispatcher* >::iterator + itc = it->second.begin(), end = it->second.end(); + itc != end; ++itc ) { + //The constant + Debug("efficient-e-match") << " Checking constant " << a << std::endl; + if(getEqualityEngine()->getRepresentative(itc->first) != a) continue; + SetNode s; + eq::EqClassIterator eqc_iter( b, getEqualityEngine() ); + while( !eqc_iter.isFinished() ){ + Debug("efficient-e-match-debug") << "> look at " << (*eqc_iter) + << std::endl; + if( (*eqc_iter).hasOperator() && (*eqc_iter).getOperator() == it->first ) s.insert(*eqc_iter); + eqc_iter++; + } + + if( s.empty() ) continue; + Debug("efficient-e-match") << " -> Added terms (" << s.size() << "): "; + for( SetNode::const_iterator t=s.begin(), end=s.end(); + t!=end; ++t ){ + Debug("efficient-e-match") << (*t) << " "; + } + Debug("efficient-e-match") << std::endl; + itc->second->send(s); + } + } +} + +void EfficientEMatcher::collectTermsIps( Ips& ips, SetNode & terms ){ + Assert( ips.size() > 0); + return collectTermsIps( ips, terms, ips.size() - 1); +} + +void EfficientEMatcher::collectTermsIps( Ips& ips, SetNode& terms, int index ){ + if( !terms.empty() ){ + Debug("efficient-e-match-debug") << "> Process " << index << std::endl; + Node f = ips[index].first; + int arg = ips[index].second; + + //for each term in terms, determine if any term (modulo equality) has parent "f" from position "arg" + bool addRep = ( index!=0 ); // We want to keep the top symbol for the last + SetNode newTerms; + for( SetNode::const_iterator t=terms.begin(), end=terms.end(); + t!=end; ++t ){ + collectParentsTermsIps( *t, f, arg, newTerms, addRep ); + } + terms.swap(newTerms); + + Debug("efficient-e-match-debug") << "> Terms are now: "; + for( SetNode::const_iterator t=terms.begin(), end=terms.end(); + t!=end; ++t ){ + Debug("efficient-e-match-debug") << *t << " "; + } + Debug("efficient-e-match-debug") << std::endl; + + if(index!=0) collectTermsIps( ips, terms, index-1 ); + } +} + +bool EfficientEMatcher::collectParentsTermsIps( Node n, Node f, int arg, SetNode & terms, bool addRep, bool modEq ){ //modEq default true + bool addedTerm = false; + + if( modEq && getEqualityEngine()->hasTerm( n )){ + Assert( getEqualityEngine()->getRepresentative( n )==n ); + //collect modulo equality + //DO_THIS: this should (if necessary) compute a current set of (f, arg) parents for n and cache it + eq::EqClassIterator eqc_iter( n, getEqualityEngine() ); + while( !eqc_iter.isFinished() ){ + Debug("efficient-e-match-debug") << "> look at " << (*eqc_iter) + << std::endl; + if( collectParentsTermsIps( (*eqc_iter), f, arg, terms, addRep, false ) ){ + //if only one argument, we know we can stop (since all others added will be congruent) + if( f.getType().getNumChildren()==2 ){ + return true; + } + addedTerm = true; + } + eqc_iter++; + } + }else{ + quantifiers::TermDb* db = d_quantEngine->getTermDatabase(); + //see if parent f exists from argument arg + const std::vector<Node> & parents = db->getParents(n,f,arg); + for( size_t i=0; i<parents.size(); ++i ){ + TNode t = parents[i]; + if(!CandidateGenerator::isLegalCandidate(t)) continue; + if( addRep ) t = getEqualityEngine()->getRepresentative( t ); + terms.insert(t); + addedTerm = true; + } + } + return addedTerm; +} + +void EfficientEMatcher::registerPatternElementPairs2( Node pat, Ips& ips, PpIpsMap & pp_ips_map, NodePcDispatcher* npc ){ + Assert( pat.hasOperator() ); + //add information for possible pp-pair + ips.push_back( std::pair< Node, int >( pat.getOperator(), 0 ) ); //0 is just a dumb value + + for( int i=0; i<(int)pat.getNumChildren(); i++ ){ + if( pat[i].getKind()==INST_CONSTANT ){ + ips.back().second = i; + pp_ips_map[ pat[i] ].push_back( make_pair( pat.getOperator(), Ips( ips ) ) ); + } + } + + for( int i=0; i<(int)pat.getNumChildren(); i++ ){ + if( pat[i].getKind()==APPLY_UF ){ + ips.back().second = i; + registerPatternElementPairs2( pat[i], ips, pp_ips_map, npc ); + Debug("pattern-element-opt") << "Found pc-pair ( " << pat.getOperator() << ", " << pat[i].getOperator() << " )" << std::endl; + Debug("pattern-element-opt") << " Path = "; + outputIps( "pattern-element-opt", ips ); + Debug("pattern-element-opt") << std::endl; + //pat.getOperator() and pat[i].getOperator() are a pc-pair + d_pc_pairs[ pat[i].getOperator() ][ pat.getOperator() ] + .push_back( make_pair(npc,Ips(ips)) ); + } + } + ips.pop_back(); +} + +void EfficientEMatcher::registerPatternElementPairs( Node pat, PpIpsMap & pp_ips_map, + NodePcDispatcher* npc, + NodePpDispatcher* npp){ + Ips ips; + registerPatternElementPairs2( pat, ips, pp_ips_map, npc ); + for( PpIpsMap::iterator it = pp_ips_map.begin(); it != pp_ips_map.end(); ++it ){ + // for each variable construct all the pp-pair + for( size_t j=0; j<it->second.size(); j++ ){ + for( size_t k=j+1; k<it->second.size(); k++ ){ + //found a pp-pair + Debug("pattern-element-opt") << "Found pp-pair ( " << it->second[j].first << ", " << it->second[k].first << " )" << std::endl; + Debug("pattern-element-opt") << " Paths = "; + outputIps( "pattern-element-opt", it->second[j].second ); + Debug("pattern-element-opt") << " and "; + outputIps( "pattern-element-opt", it->second[k].second ); + Debug("pattern-element-opt") << std::endl; + d_pp_pairs[ it->second[j].first ][ it->second[k].first ] + .push_back( make_triple( npp, it->second[j].second, it->second[k].second )); + } + } + } +}; + +void findPpSite(Node pat, EfficientEMatcher::Ips& ips, EfficientEMatcher::PpIpsMap & pp_ips_map){ + Assert( pat.getKind()==APPLY_UF ); + //add information for possible pp-pair + + ips.push_back( make_pair( pat.getOperator(), 0) ); + for( size_t i=0; i<pat.getNumChildren(); i++ ){ + if( pat[i].getKind()==INST_CONSTANT ){ + ips.back().second = i; + pp_ips_map[ pat[i] ].push_back( make_pair( pat.getOperator(), EfficientEMatcher::Ips( ips ) ) ); + } + } + + for( size_t i=0; i<pat.getNumChildren(); i++ ){ + if( pat[i].getKind()==APPLY_UF ){ + ips.back().second = i; + findPpSite( pat[i], ips, pp_ips_map ); + } + } + ips.pop_back(); +} + +void EfficientEMatcher::combineMultiPpIpsMap(PpIpsMap & pp_ips_map, MultiPpIpsMap & multi_pp_ips_map, + EfficientHandler& eh, size_t index2,const std::vector<Node> & pats){ + hash_map<size_t,NodePpDispatcher*> npps; + for( PpIpsMap::iterator it = pp_ips_map.begin(); it != pp_ips_map.end(); ++it ){ + MultiPpIpsMap::iterator mit = multi_pp_ips_map.find(it->first); + if(mit == multi_pp_ips_map.end()) continue; + // for each variable construct all the pp-pair + // j the last pattern treated + for( std::vector< std::pair< Node, Ips > >::iterator j=it->second.begin(), jend = it->second.end() ; + j != jend; ++j){ + // k one of the previous one + for( std::vector< triple< size_t, Node, Ips > >::iterator k=mit->second.begin(), kend = mit->second.end() ; + k != kend; ++k){ + //found a pp-pair + Debug("pattern-element-opt") << "Found multi-pp-pair ( " << j->first + << ", " << k->second << " in "<< k->first + << " )" << std::endl; + Debug("pattern-element-opt") << " Paths = "; + outputIps( "pattern-element-opt", j->second ); + Debug("pattern-element-opt") << " and "; + outputIps( "pattern-element-opt", k->third ); + Debug("pattern-element-opt") << std::endl; + NodePpDispatcher* dispatcher; + hash_map<size_t,NodePpDispatcher*>::iterator inpp = npps.find(k->first); + if( inpp != npps.end() ) dispatcher = inpp->second; + else{ + dispatcher = new NodePpDispatcher(); +#ifdef CVC4_DEBUG + dispatcher->pat1 = pats[index2]; + dispatcher->pat2 = pats[k->first]; +#endif + dispatcher->addPpDispatcher(&eh,index2,k->first); + }; + d_pp_pairs[ j->first ][ k->second ].push_back( make_triple( dispatcher, j->second, k->third )); + } + } + } + + /** Put pp_ips_map to multi_pp_ips_map */ + for( PpIpsMap::iterator it = pp_ips_map.begin(); it != pp_ips_map.end(); ++it ){ + for( std::vector< std::pair< Node, Ips > >::iterator j=it->second.begin(), jend = it->second.end() ; + j != jend; ++j){ + multi_pp_ips_map[it->first].push_back(make_triple(index2, j->first, j->second)); + } + } + +} + + +void EfficientEMatcher::registerEfficientHandler( EfficientHandler& handler, + const std::vector< Node > & pats ){ + Assert(pats.size() > 0); + + MultiPpIpsMap multi_pp_ips_map; + PpIpsMap pp_ips_map; + //In a multi-pattern Pattern that is only a variable are specials, + //if the variable appears in another pattern, it can be discarded. + //Otherwise new term of this term can be candidate. So we stock them + //here before adding them. + std::vector< size_t > patVars; + + Debug("pattern-element-opt") << "Register patterns" << pats << std::endl; + for(size_t i = 0; i < pats.size(); ++i){ + if( pats[i].getKind() == kind::INST_CONSTANT){ + patVars.push_back(i); + continue; + } + //to complete + if( pats[i].getKind() == kind::NOT && pats[i][0].getKind() == kind::EQUAL){ + Node cst = NodeManager::currentNM()->mkConst<bool>(false); + TNode op = pats[i][0].getOperator(); + if(d_cc_pairs[op][cst] == NULL){ + d_cc_pairs[op][cst] = new NodePcDispatcher(); + } + d_cc_pairs[op][cst]->addPcDispatcher(&handler,i); + continue; + } + //end to complete + Debug("pattern-element-opt") << " Register candidate generator..." << pats[i] << std::endl; + /* Has the pattern already been seen */ + if( d_pat_cand_gens.find( pats[i] )==d_pat_cand_gens.end() ){ + NodePcDispatcher* npc = new NodePcDispatcher(); + NodePpDispatcher* npp = new NodePpDispatcher(); +#ifdef CVC4_DEBUG + npc->pat = pats[i]; + npp->pat1 = pats[i]; + npp->pat2 = pats[i]; +#endif + d_pat_cand_gens[pats[i]] = make_pair(npc,npp); + registerPatternElementPairs( pats[i], pp_ips_map, npc, npp ); + }else{ + Ips ips; + findPpSite(pats[i],ips,pp_ips_map); + } + //Has the top operator already been seen */ + TNode op = pats[i].getOperator(); + d_pat_cand_gens[pats[i]].first->addPcDispatcher(&handler,i); + d_pat_cand_gens[pats[i]].second->addPpDispatcher(&handler,i,i); + d_cand_gens[op].addNewTermDispatcher(&handler,i); + + combineMultiPpIpsMap(pp_ips_map,multi_pp_ips_map,handler,i,pats); + + pp_ips_map.clear(); + } + + for(size_t i = 0; i < patVars.size(); ++i){ + TNode var = pats[patVars[i]]; + Assert( var.getKind() == kind::INST_CONSTANT ); + if( multi_pp_ips_map.find(var) != multi_pp_ips_map.end() ){ + //The variable appear in another pattern, skip it + continue; + }; + d_cand_gen_types[var.getType()].addNewTermDispatcher(&handler,patVars[i]); + } + + //take all terms from the uf term db and add to candidate generator + if( pats[0].getKind() == kind::INST_CONSTANT ){ + TypeNode ty = pats[0].getType(); + rrinst::CandidateGenerator* cg = new GenericCandidateGeneratorClasses(d_quantEngine); + cg->reset(Node::null()); + TNode c; + SetNode ele; + while( !(c = cg->getNextCandidate()).isNull() ){ + if( c.getType() == ty ) ele.insert(c); + } + if( !ele.empty() ){ + // for(std::vector<Node>::iterator i = db->d_op_map[op].begin(), end = db->d_op_map[op].end(); i != end; ++i){ + // if(CandidateGenerator::isLegalCandidate(*i)) ele.insert(*i); + // } + if(Debug.isOn("efficient-e-match-stats")){ + Debug("efficient-e-match-stats") << "pattern " << pats << " initialized with " << ele.size() << " terms"<< std::endl; + } + handler.addMonoCandidate(ele, 0); + } + + } else if( pats[0].getKind() == kind::NOT && pats[0][0].getKind() == kind::EQUAL){ + Node cst = NodeManager::currentNM()->mkConst<bool>(false); + TNode op = pats[0][0].getOperator(); + cst = getEqualityEngine()->getRepresentative(cst); + SetNode ele; + eq::EqClassIterator eqc_iter( cst, getEqualityEngine() ); + while( !eqc_iter.isFinished() ){ + Debug("efficient-e-match-debug") << "> look at " << (*eqc_iter) + << std::endl; + if( (*eqc_iter).hasOperator() && (*eqc_iter).getOperator() == op ) ele.insert(*eqc_iter); + eqc_iter++; + } + if( !ele.empty() ){ + if(Debug.isOn("efficient-e-match-stats")){ + Debug("efficient-e-match-stats") << "pattern " << pats << " initialized with " << ele.size() << " terms"<< std::endl; + } + handler.addMonoCandidate(ele, 0); + } + + } else { + Node op = pats[0].getOperator(); + TermDb* db = d_quantEngine->getTermDatabase(); + if(db->d_op_map[op].begin() != db->d_op_map[op].end()){ + SetNode ele; + // for(std::vector<Node>::iterator i = db->d_op_map[op].begin(), end = db->d_op_map[op].end(); i != end; ++i){ + // if(CandidateGenerator::isLegalCandidate(*i)) ele.insert(*i); + // } + ele.insert(db->d_op_map[op].begin(), db->d_op_map[op].end()); + if(Debug.isOn("efficient-e-match-stats")){ + Debug("efficient-e-match-stats") << "pattern " << pats << " initialized with " << ele.size() << " terms"<< std::endl; + } + handler.addMonoCandidate(ele, 0); + } + } + Debug("efficient-e-match") << "Done." << std::endl; +} + +void EfficientEMatcher::outputEqClass( const char* c, Node n ){ + if( getEqualityEngine()->hasTerm( n ) ){ + eq::EqClassIterator eqc_iter( getEqualityEngine()->getRepresentative( n ), + getEqualityEngine() ); + bool firstTime = true; + while( !eqc_iter.isFinished() ){ + if( !firstTime ){ Debug(c) << ", "; } + Debug(c) << (*eqc_iter); + firstTime = false; + eqc_iter++; + } + }else{ + Debug(c) << n; + } +} + +void EfficientEMatcher::outputIps( const char* c, Ips& ips ){ + for( int i=0; i<(int)ips.size(); i++ ){ + if( i>0 ){ Debug( c ) << "."; } + Debug( c ) << ips[i].first << "." << ips[i].second; + } +} + + +} /* namespace theory */ +} /* namespace cvc4 */ diff --git a/src/theory/rewriterules/efficient_e_matching.h b/src/theory/rewriterules/efficient_e_matching.h index 2f0a07184..11c6b783e 100755..100644 --- a/src/theory/rewriterules/efficient_e_matching.h +++ b/src/theory/rewriterules/efficient_e_matching.h @@ -1,450 +1,450 @@ -/********************* */
-/*! \file efficient_e_matching.h
- ** \verbatim
- ** Original author: ajreynol
- ** Major contributors: bobot
- ** Minor contributors (to current version): mdeters
- ** This file is part of the CVC4 prototype.
- ** Copyright (c) 2009-2012 New York University and The University of Iowa
- ** See the file COPYING in the top-level source directory for licensing
- ** information.\endverbatim
- **
- ** \brief efficient e-matching
- **/
-
-#include "cvc4_private.h"
-
-#ifndef __CVC4__EFFICIENT_E_MATCHING_H
-#define __CVC4__EFFICIENT_E_MATCHING_H
-
-#include "expr/node.h"
-#include "context/context.h"
-#include "context/context_mm.h"
-#include "context/cdchunk_list.h"
-
-#include "util/statistics_registry.h"
-#include "util/ntuple.h"
-#include "context/cdqueue.h"
-#include "context/cdo.h"
-
-#include "theory/uf/equality_engine.h"
-
-namespace CVC4 {
-namespace theory {
-
-class QuantifiersEngine;
-
-namespace quantifiers{
- class TermDb;
-}
-
-class EfficientEMatcher;
-class HandlerPcDispatcher;
-class HandlerPpDispatcher;
-
-typedef std::set<Node> SetNode;
-
-template<class T>
-class CleanUpPointer{
-public:
- inline void operator()(T** e){
- delete(*e);
- };
-};
-
-class EfficientHandler{
-public:
- typedef std::pair< Node, size_t > MonoCandidate;
- typedef std::pair< MonoCandidate, MonoCandidate > MultiCandidate;
- typedef std::pair< SetNode, size_t > MonoCandidates;
- typedef std::pair< MonoCandidates, MonoCandidates > MultiCandidates;
-private:
- /* Queue of candidates */
- typedef context::CDQueue< MonoCandidates *, CleanUpPointer<MonoCandidates> > MonoCandidatesQueue;
- typedef context::CDQueue< MultiCandidates *, CleanUpPointer<MultiCandidates> > MultiCandidatesQueue;
- MonoCandidatesQueue d_monoCandidates;
- typedef SetNode::iterator SetNodeIter;
- context::CDO<SetNodeIter> d_si;
- context::CDO<bool> d_mono_not_first;
-
- MonoCandidatesQueue d_monoCandidatesNewTerm;
- context::CDO<SetNodeIter> d_si_new_term;
- context::CDO<bool> d_mono_not_first_new_term;
-
-
- MultiCandidatesQueue d_multiCandidates;
- context::CDO<SetNodeIter> d_si1;
- context::CDO<SetNodeIter> d_si2;
- context::CDO<bool> d_multi_not_first;
-
-
- friend class EfficientEMatcher;
- friend class HandlerPcDispatcher;
- friend class HandlerPpDispatcher;
- friend class HandlerNewTermDispatcher;
-protected:
- void addMonoCandidate(SetNode & s, size_t index){
- Assert(!s.empty());
- d_monoCandidates.push(new MonoCandidates(s,index));
- }
- void addMonoCandidateNewTerm(SetNode & s, size_t index){
- Assert(!s.empty());
- d_monoCandidatesNewTerm.push(new MonoCandidates(s,index));
- }
- void addMultiCandidate(SetNode & s1, size_t index1, SetNode & s2, size_t index2){
- Assert(!s1.empty() && !s2.empty());
- d_multiCandidates.push(new MultiCandidates(MonoCandidates(s1,index1),
- MonoCandidates(s2,index2)));
- }
-public:
- EfficientHandler(context::Context * c):
- //false for d_mono_not_first beacause its the default constructor
- d_monoCandidates(c), d_si(c), d_mono_not_first(c,false),
- d_monoCandidatesNewTerm(c), d_si_new_term(c),
- d_mono_not_first_new_term(c,false),
- d_multiCandidates(c) , d_si1(c), d_si2(c), d_multi_not_first(c,false) {};
-
- bool getNextMonoCandidate(MonoCandidate & candidate){
- if(d_monoCandidates.empty()) return false;
- const MonoCandidates * front = d_monoCandidates.front();
- SetNodeIter si_tmp;
- if(!d_mono_not_first){
- Assert(front->first.begin() != front->first.end());
- d_mono_not_first = true;
- si_tmp=front->first.begin();
- }else{
- si_tmp = d_si;
- ++si_tmp;
- };
- if(si_tmp != front->first.end()){
- candidate.first = (*si_tmp);
- candidate.second = front->second;
- d_si = si_tmp;
- Debug("efficienthandler") << "Mono produces " << candidate.first << " for " << candidate.second << std::endl;
- return true;
- };
- d_monoCandidates.pop();
- d_mono_not_first = false;
- return getNextMonoCandidate(candidate);
- };
-
- bool getNextMonoCandidateNewTerm(MonoCandidate & candidate){
- if(d_monoCandidatesNewTerm.empty()) return false;
- const MonoCandidates * front = d_monoCandidatesNewTerm.front();
- SetNodeIter si_tmp;
- if(!d_mono_not_first_new_term){
- Assert(front->first.begin() != front->first.end());
- d_mono_not_first_new_term = true;
- si_tmp=front->first.begin();
- }else{
- si_tmp = d_si_new_term;
- ++si_tmp;
- };
- if(si_tmp != front->first.end()){
- candidate.first = (*si_tmp);
- candidate.second = front->second;
- d_si_new_term = si_tmp;
- Debug("efficienthandler") << "Mono produces " << candidate.first << " for " << candidate.second << std::endl;
- return true;
- };
- d_monoCandidatesNewTerm.pop();
- d_mono_not_first_new_term = false;
- return getNextMonoCandidateNewTerm(candidate);
- };
-
- bool getNextMultiCandidate(MultiCandidate & candidate){
- if(d_multiCandidates.empty()) return false;
- const MultiCandidates* front = d_multiCandidates.front();
- SetNodeIter si1_tmp;
- SetNodeIter si2_tmp;
- if(!d_multi_not_first){
- Assert(front->first.first.begin() != front->first.first.end());
- Assert(front->second.first.begin() != front->second.first.end());
- si1_tmp = front->first.first.begin();
- si2_tmp = front->second.first.begin();
- }else{
- si1_tmp = d_si1;
- si2_tmp = d_si2;
- ++si2_tmp;
- };
- if(si2_tmp != front->second.first.end()){
- candidate.first.first = *si1_tmp;
- candidate.first.second = front->first.second;
- candidate.second.first = *si2_tmp;
- candidate.second.second = front->second.second;
- if(!d_multi_not_first){d_si1 = si1_tmp; d_multi_not_first = true; };
- d_si2 = si2_tmp;
- Debug("efficienthandler") << "Multi1 produces "
- << candidate.first.first << " for "
- << candidate.first.second << " and "
- << candidate.second.first << " for "
- << candidate.second.second << " and "
- << std::endl;
- return true;
- }; // end of the second set
- si2_tmp = front->second.first.begin();
- ++si1_tmp;
- if(si1_tmp != front->first.first.end()){
- candidate.first.first = *si1_tmp;
- candidate.first.second = front->first.second;
- candidate.second.first = *si2_tmp;
- candidate.second.second = front->second.second;
- d_si1 = si1_tmp;
- d_si2 = si2_tmp;
- Debug("efficienthandler") << "Multi2 produces "
- << candidate.first.first << " for "
- << candidate.first.second << " and "
- << candidate.second.first << " for "
- << candidate.second.second << " and "
- << std::endl;
- return true;
- }; // end of the first set
- d_multiCandidates.pop();
- d_multi_not_first = false;
- return getNextMultiCandidate(candidate);
- }
-};
-
-class PcDispatcher{
-public:
- virtual ~PcDispatcher(){};
- /* Send the node to the dispatcher */
- virtual void send(SetNode & s) = 0;
-};
-
-
-class HandlerPcDispatcher: public PcDispatcher{
- EfficientHandler* d_handler;
- size_t d_index;
-public:
- HandlerPcDispatcher(EfficientHandler* handler, size_t index):
- d_handler(handler), d_index(index) {};
- void send(SetNode & s){
- d_handler->addMonoCandidate(s,d_index);
- }
-};
-
-
-/** All the dispatcher that correspond to this node */
-class NodePcDispatcher: public PcDispatcher{
-#ifdef CVC4_DEBUG
-public:
- Node pat;
-#endif/* CVC4_DEBUG*/
-private:
- std::vector<HandlerPcDispatcher> d_dis;
-public:
- void send(SetNode & s){
- Assert(!s.empty());
- for(std::vector<HandlerPcDispatcher>::iterator i = d_dis.begin(), end = d_dis.end();
- i != end; ++i){
- (*i).send(s);
- }
- }
- void addPcDispatcher(EfficientHandler* handler, size_t index){
- d_dis.push_back(HandlerPcDispatcher(handler,index));
- }
-};
-
-
-class HandlerNewTermDispatcher: public PcDispatcher{
- EfficientHandler* d_handler;
- size_t d_index;
-public:
- HandlerNewTermDispatcher(EfficientHandler* handler, size_t index):
- d_handler(handler), d_index(index) {};
- void send(SetNode & s){
- d_handler->addMonoCandidateNewTerm(s,d_index);
- }
-};
-
-/** All the dispatcher that correspond to this node */
-class NodeNewTermDispatcher: public PcDispatcher{
-#ifdef CVC4_DEBUG
-public:
- Node pat;
-#endif/* CVC4_DEBUG*/
-private:
- std::vector<HandlerNewTermDispatcher> d_dis;
-public:
- void send(SetNode & s){
- Assert(!s.empty());
- for(std::vector<HandlerNewTermDispatcher>::iterator i = d_dis.begin(), end = d_dis.end();
- i != end; ++i){
- (*i).send(s);
- }
- }
- void addNewTermDispatcher(EfficientHandler* handler, size_t index){
- d_dis.push_back(HandlerNewTermDispatcher(handler,index));
- }
-};
-
-class PpDispatcher{
-public:
- virtual ~PpDispatcher(){};
- /* Send the node to the dispatcher */
- virtual void send(SetNode & s1, SetNode & s2, SetNode & sinter) = 0;
-};
-
-
-class HandlerPpDispatcher: public PpDispatcher{
- EfficientHandler* d_handler;
- size_t d_index1;
- size_t d_index2;
-public:
- HandlerPpDispatcher(EfficientHandler* handler, size_t index1, size_t index2):
- d_handler(handler), d_index1(index1), d_index2(index2) {};
- void send(SetNode & s1, SetNode & s2, SetNode & sinter){
- if(d_index1 == d_index2){
- if(!sinter.empty())
- d_handler->addMonoCandidate(sinter,d_index1);
- }else{
- d_handler->addMultiCandidate(s1,d_index1,s2,d_index2);
- }
- }
-};
-
-
-/** All the dispatcher that correspond to this node */
-class NodePpDispatcher: public PpDispatcher{
-#ifdef CVC4_DEBUG
-public:
- Node pat1;
- Node pat2;
-#endif/* CVC4_DEBUG */
-private:
- std::vector<HandlerPpDispatcher> d_dis;
- void send(SetNode & s1, SetNode & s2, SetNode & inter){
- for(std::vector<HandlerPpDispatcher>::iterator i = d_dis.begin(), end = d_dis.end();
- i != end; ++i){
- (*i).send(s1,s2,inter);
- }
- }
-public:
- void send(SetNode & s1, SetNode & s2){
- // can be done in HandlerPpDispatcher lazily
- Assert(!s1.empty() && !s2.empty());
- SetNode inter;
- std::set_intersection( s1.begin(), s1.end(), s2.begin(), s2.end(),
- std::inserter( inter, inter.begin() ) );
- send(s1,s2,inter);
- }
- void addPpDispatcher(EfficientHandler* handler, size_t index1, size_t index2){
- d_dis.push_back(HandlerPpDispatcher(handler,index1,index2));
- }
-};
-
-//equivalence class info
-class EqClassInfo
-{
-public:
- typedef context::CDHashMap<Node, bool, NodeHashFunction> BoolMap;
- typedef context::CDChunkList<Node> NodeList;
-public:
- //a list of operators that occur as top symbols in this equivalence class
- // Efficient E-Matching for SMT Solvers: "funs"
- BoolMap d_funs;
- //a list of operators f for which a term of the form f( ... t ... ) exists
- // Efficient E-Matching for SMT Solvers: "pfuns"
- BoolMap d_pfuns;
- //a list of equivalence classes that are disequal
- BoolMap d_disequal;
-public:
- EqClassInfo( context::Context* c );
- ~EqClassInfo(){}
- //set member
- void setMember( Node n, quantifiers::TermDb* db );
- //has function "funs"
- bool hasFunction( Node op );
- //has parent "pfuns"
- bool hasParent( Node op );
- //merge with another eq class info
- void merge( EqClassInfo* eci );
-};
-
-class EfficientEMatcher{
-protected:
- /** reference to the quantifiers engine */
- QuantifiersEngine* d_quantEngine;
-public:
- EfficientEMatcher(CVC4::theory::QuantifiersEngine* qe);
- ~EfficientEMatcher() {
- for(std::map< Node, std::pair<NodePcDispatcher*, NodePpDispatcher*> >::iterator
- i = d_pat_cand_gens.begin(), end = d_pat_cand_gens.end();
- i != end; i++){
- delete(i->second.first);
- delete(i->second.second);
- }
- }
- /** get equality engine we are using */
- eq::EqualityEngine* getEqualityEngine();
-private:
- //information for each equivalence class
- std::map< Node, EqClassInfo* > d_eqc_ops;
-public:
- /** new node */
- void newEqClass( TNode n );
- /** merge */
- void merge( TNode a, TNode b );
- /** assert terms are disequal */
- void assertDisequal( TNode a, TNode b, TNode reason );
- /** get equivalence class info */
- EqClassInfo* getEquivalenceClassInfo( Node n );
- EqClassInfo* getOrCreateEquivalenceClassInfo( Node n );
- typedef std::vector< std::pair< Node, int > > Ips;
- typedef std::map< Node, std::vector< std::pair< Node, Ips > > > PpIpsMap;
- typedef std::map< Node, std::vector< triple< size_t, Node, Ips > > > MultiPpIpsMap;
-private:
- /** Parent/Child Pairs (for efficient E-matching)
- So, for example, if we have the pattern f( g( x ) ), then d_pc_pairs[g][f][f( g( x ) )] = { f.0 }.
- */
- std::map< Node, std::map< Node, std::vector< std::pair< NodePcDispatcher*, Ips > > > > d_pc_pairs;
- /** Parent/Parent Pairs (for efficient E-matching) */
- std::map< Node, std::map< Node, std::vector< triple< NodePpDispatcher*, Ips, Ips > > > > d_pp_pairs;
- /** Constants/Child Pairs
- So, for example, if we have the pattern f( x ) = c, then d_pc_pairs[f][c] = ..., pcdispatcher, ...
- */
- //TODO constant in pattern can use the same thing just add an Ips
- std::map< Node, std::map< Node, NodePcDispatcher* > > d_cc_pairs;
- /** list of all candidate generators for each operator */
- std::map< Node, NodeNewTermDispatcher > d_cand_gens;
- /** list of all candidate generators for each type */
- std::map< TypeNode, NodeNewTermDispatcher > d_cand_gen_types;
- /** map from patterns to candidate generators */
- std::map< Node, std::pair<NodePcDispatcher*, NodePpDispatcher*> > d_pat_cand_gens;
- /** helper functions */
- void registerPatternElementPairs2( Node pat, Ips& ips,
- PpIpsMap & pp_ips_map, NodePcDispatcher* npc);
- void registerPatternElementPairs( Node pat, PpIpsMap & pp_ips_map,
- NodePcDispatcher* npc, NodePpDispatcher* npp);
- /** find the pp-pair between pattern inside multi-pattern*/
- void combineMultiPpIpsMap(PpIpsMap & pp_ips_map, MultiPpIpsMap & multi_pp_ips_map,
- EfficientHandler& eh, size_t index2,
- const std::vector<Node> & pats); //pats for debug
- /** compute candidates for pc pairs */
- void computeCandidatesPcPairs( Node a, EqClassInfo*, Node b, EqClassInfo* );
- /** compute candidates for pp pairs */
- void computeCandidatesPpPairs( Node a, EqClassInfo*, Node b, EqClassInfo* );
- /** compute candidates for cc pairs */
- void computeCandidatesConstants( Node a, EqClassInfo*, Node b, EqClassInfo* );
- /** collect terms based on inverted path string */
- void collectTermsIps( Ips& ips, SetNode& terms, int index);
- bool collectParentsTermsIps( Node n, Node f, int arg, SetNode& terms, bool addRep, bool modEq = true );
-public:
- void collectTermsIps( Ips& ips, SetNode& terms);
-public:
- void registerEfficientHandler( EfficientHandler& eh, const std::vector<Node> & pat );
-public:
- void newTerms(SetNode& s);
-public:
- /** output eq class */
- void outputEqClass( const char* c, Node n );
- /** output inverted path string */
- void outputIps( const char* c, Ips& ips );
-};/* class EfficientEMatcher */
-
-
-}/* CVC4::theory namespace */
-}/* CVC4 namespace */
-
-#endif /* __CVC4__EFFICIENT_E_MATCHING_H */
+/********************* */ +/*! \file efficient_e_matching.h + ** \verbatim + ** Original author: Andrew Reynolds <andrew.j.reynolds@gmail.com> + ** Major contributors: Morgan Deters <mdeters@cs.nyu.edu> + ** Minor contributors (to current version): none + ** This file is part of the CVC4 project. + ** Copyright (c) 2009-2013 New York University and The University of Iowa + ** See the file COPYING in the top-level source directory for licensing + ** information.\endverbatim + ** + ** \brief efficient e-matching + **/ + +#include "cvc4_private.h" + +#ifndef __CVC4__EFFICIENT_E_MATCHING_H +#define __CVC4__EFFICIENT_E_MATCHING_H + +#include "expr/node.h" +#include "context/context.h" +#include "context/context_mm.h" +#include "context/cdchunk_list.h" + +#include "util/statistics_registry.h" +#include "util/ntuple.h" +#include "context/cdqueue.h" +#include "context/cdo.h" + +#include "theory/uf/equality_engine.h" + +namespace CVC4 { +namespace theory { + +class QuantifiersEngine; + +namespace quantifiers{ + class TermDb; +} + +class EfficientEMatcher; +class HandlerPcDispatcher; +class HandlerPpDispatcher; + +typedef std::set<Node> SetNode; + +template<class T> +class CleanUpPointer{ +public: + inline void operator()(T** e){ + delete(*e); + }; +}; + +class EfficientHandler{ +public: + typedef std::pair< Node, size_t > MonoCandidate; + typedef std::pair< MonoCandidate, MonoCandidate > MultiCandidate; + typedef std::pair< SetNode, size_t > MonoCandidates; + typedef std::pair< MonoCandidates, MonoCandidates > MultiCandidates; +private: + /* Queue of candidates */ + typedef context::CDQueue< MonoCandidates *, CleanUpPointer<MonoCandidates> > MonoCandidatesQueue; + typedef context::CDQueue< MultiCandidates *, CleanUpPointer<MultiCandidates> > MultiCandidatesQueue; + MonoCandidatesQueue d_monoCandidates; + typedef SetNode::iterator SetNodeIter; + context::CDO<SetNodeIter> d_si; + context::CDO<bool> d_mono_not_first; + + MonoCandidatesQueue d_monoCandidatesNewTerm; + context::CDO<SetNodeIter> d_si_new_term; + context::CDO<bool> d_mono_not_first_new_term; + + + MultiCandidatesQueue d_multiCandidates; + context::CDO<SetNodeIter> d_si1; + context::CDO<SetNodeIter> d_si2; + context::CDO<bool> d_multi_not_first; + + + friend class EfficientEMatcher; + friend class HandlerPcDispatcher; + friend class HandlerPpDispatcher; + friend class HandlerNewTermDispatcher; +protected: + void addMonoCandidate(SetNode & s, size_t index){ + Assert(!s.empty()); + d_monoCandidates.push(new MonoCandidates(s,index)); + } + void addMonoCandidateNewTerm(SetNode & s, size_t index){ + Assert(!s.empty()); + d_monoCandidatesNewTerm.push(new MonoCandidates(s,index)); + } + void addMultiCandidate(SetNode & s1, size_t index1, SetNode & s2, size_t index2){ + Assert(!s1.empty() && !s2.empty()); + d_multiCandidates.push(new MultiCandidates(MonoCandidates(s1,index1), + MonoCandidates(s2,index2))); + } +public: + EfficientHandler(context::Context * c): + //false for d_mono_not_first beacause its the default constructor + d_monoCandidates(c), d_si(c), d_mono_not_first(c,false), + d_monoCandidatesNewTerm(c), d_si_new_term(c), + d_mono_not_first_new_term(c,false), + d_multiCandidates(c) , d_si1(c), d_si2(c), d_multi_not_first(c,false) {}; + + bool getNextMonoCandidate(MonoCandidate & candidate){ + if(d_monoCandidates.empty()) return false; + const MonoCandidates * front = d_monoCandidates.front(); + SetNodeIter si_tmp; + if(!d_mono_not_first){ + Assert(front->first.begin() != front->first.end()); + d_mono_not_first = true; + si_tmp=front->first.begin(); + }else{ + si_tmp = d_si; + ++si_tmp; + }; + if(si_tmp != front->first.end()){ + candidate.first = (*si_tmp); + candidate.second = front->second; + d_si = si_tmp; + Debug("efficienthandler") << "Mono produces " << candidate.first << " for " << candidate.second << std::endl; + return true; + }; + d_monoCandidates.pop(); + d_mono_not_first = false; + return getNextMonoCandidate(candidate); + }; + + bool getNextMonoCandidateNewTerm(MonoCandidate & candidate){ + if(d_monoCandidatesNewTerm.empty()) return false; + const MonoCandidates * front = d_monoCandidatesNewTerm.front(); + SetNodeIter si_tmp; + if(!d_mono_not_first_new_term){ + Assert(front->first.begin() != front->first.end()); + d_mono_not_first_new_term = true; + si_tmp=front->first.begin(); + }else{ + si_tmp = d_si_new_term; + ++si_tmp; + }; + if(si_tmp != front->first.end()){ + candidate.first = (*si_tmp); + candidate.second = front->second; + d_si_new_term = si_tmp; + Debug("efficienthandler") << "Mono produces " << candidate.first << " for " << candidate.second << std::endl; + return true; + }; + d_monoCandidatesNewTerm.pop(); + d_mono_not_first_new_term = false; + return getNextMonoCandidateNewTerm(candidate); + }; + + bool getNextMultiCandidate(MultiCandidate & candidate){ + if(d_multiCandidates.empty()) return false; + const MultiCandidates* front = d_multiCandidates.front(); + SetNodeIter si1_tmp; + SetNodeIter si2_tmp; + if(!d_multi_not_first){ + Assert(front->first.first.begin() != front->first.first.end()); + Assert(front->second.first.begin() != front->second.first.end()); + si1_tmp = front->first.first.begin(); + si2_tmp = front->second.first.begin(); + }else{ + si1_tmp = d_si1; + si2_tmp = d_si2; + ++si2_tmp; + }; + if(si2_tmp != front->second.first.end()){ + candidate.first.first = *si1_tmp; + candidate.first.second = front->first.second; + candidate.second.first = *si2_tmp; + candidate.second.second = front->second.second; + if(!d_multi_not_first){d_si1 = si1_tmp; d_multi_not_first = true; }; + d_si2 = si2_tmp; + Debug("efficienthandler") << "Multi1 produces " + << candidate.first.first << " for " + << candidate.first.second << " and " + << candidate.second.first << " for " + << candidate.second.second << " and " + << std::endl; + return true; + }; // end of the second set + si2_tmp = front->second.first.begin(); + ++si1_tmp; + if(si1_tmp != front->first.first.end()){ + candidate.first.first = *si1_tmp; + candidate.first.second = front->first.second; + candidate.second.first = *si2_tmp; + candidate.second.second = front->second.second; + d_si1 = si1_tmp; + d_si2 = si2_tmp; + Debug("efficienthandler") << "Multi2 produces " + << candidate.first.first << " for " + << candidate.first.second << " and " + << candidate.second.first << " for " + << candidate.second.second << " and " + << std::endl; + return true; + }; // end of the first set + d_multiCandidates.pop(); + d_multi_not_first = false; + return getNextMultiCandidate(candidate); + } +}; + +class PcDispatcher{ +public: + virtual ~PcDispatcher(){}; + /* Send the node to the dispatcher */ + virtual void send(SetNode & s) = 0; +}; + + +class HandlerPcDispatcher: public PcDispatcher{ + EfficientHandler* d_handler; + size_t d_index; +public: + HandlerPcDispatcher(EfficientHandler* handler, size_t index): + d_handler(handler), d_index(index) {}; + void send(SetNode & s){ + d_handler->addMonoCandidate(s,d_index); + } +}; + + +/** All the dispatcher that correspond to this node */ +class NodePcDispatcher: public PcDispatcher{ +#ifdef CVC4_DEBUG +public: + Node pat; +#endif/* CVC4_DEBUG*/ +private: + std::vector<HandlerPcDispatcher> d_dis; +public: + void send(SetNode & s){ + Assert(!s.empty()); + for(std::vector<HandlerPcDispatcher>::iterator i = d_dis.begin(), end = d_dis.end(); + i != end; ++i){ + (*i).send(s); + } + } + void addPcDispatcher(EfficientHandler* handler, size_t index){ + d_dis.push_back(HandlerPcDispatcher(handler,index)); + } +}; + + +class HandlerNewTermDispatcher: public PcDispatcher{ + EfficientHandler* d_handler; + size_t d_index; +public: + HandlerNewTermDispatcher(EfficientHandler* handler, size_t index): + d_handler(handler), d_index(index) {}; + void send(SetNode & s){ + d_handler->addMonoCandidateNewTerm(s,d_index); + } +}; + +/** All the dispatcher that correspond to this node */ +class NodeNewTermDispatcher: public PcDispatcher{ +#ifdef CVC4_DEBUG +public: + Node pat; +#endif/* CVC4_DEBUG*/ +private: + std::vector<HandlerNewTermDispatcher> d_dis; +public: + void send(SetNode & s){ + Assert(!s.empty()); + for(std::vector<HandlerNewTermDispatcher>::iterator i = d_dis.begin(), end = d_dis.end(); + i != end; ++i){ + (*i).send(s); + } + } + void addNewTermDispatcher(EfficientHandler* handler, size_t index){ + d_dis.push_back(HandlerNewTermDispatcher(handler,index)); + } +}; + +class PpDispatcher{ +public: + virtual ~PpDispatcher(){}; + /* Send the node to the dispatcher */ + virtual void send(SetNode & s1, SetNode & s2, SetNode & sinter) = 0; +}; + + +class HandlerPpDispatcher: public PpDispatcher{ + EfficientHandler* d_handler; + size_t d_index1; + size_t d_index2; +public: + HandlerPpDispatcher(EfficientHandler* handler, size_t index1, size_t index2): + d_handler(handler), d_index1(index1), d_index2(index2) {}; + void send(SetNode & s1, SetNode & s2, SetNode & sinter){ + if(d_index1 == d_index2){ + if(!sinter.empty()) + d_handler->addMonoCandidate(sinter,d_index1); + }else{ + d_handler->addMultiCandidate(s1,d_index1,s2,d_index2); + } + } +}; + + +/** All the dispatcher that correspond to this node */ +class NodePpDispatcher: public PpDispatcher{ +#ifdef CVC4_DEBUG +public: + Node pat1; + Node pat2; +#endif/* CVC4_DEBUG */ +private: + std::vector<HandlerPpDispatcher> d_dis; + void send(SetNode & s1, SetNode & s2, SetNode & inter){ + for(std::vector<HandlerPpDispatcher>::iterator i = d_dis.begin(), end = d_dis.end(); + i != end; ++i){ + (*i).send(s1,s2,inter); + } + } +public: + void send(SetNode & s1, SetNode & s2){ + // can be done in HandlerPpDispatcher lazily + Assert(!s1.empty() && !s2.empty()); + SetNode inter; + std::set_intersection( s1.begin(), s1.end(), s2.begin(), s2.end(), + std::inserter( inter, inter.begin() ) ); + send(s1,s2,inter); + } + void addPpDispatcher(EfficientHandler* handler, size_t index1, size_t index2){ + d_dis.push_back(HandlerPpDispatcher(handler,index1,index2)); + } +}; + +//equivalence class info +class EqClassInfo +{ +public: + typedef context::CDHashMap<Node, bool, NodeHashFunction> BoolMap; + typedef context::CDChunkList<Node> NodeList; +public: + //a list of operators that occur as top symbols in this equivalence class + // Efficient E-Matching for SMT Solvers: "funs" + BoolMap d_funs; + //a list of operators f for which a term of the form f( ... t ... ) exists + // Efficient E-Matching for SMT Solvers: "pfuns" + BoolMap d_pfuns; + //a list of equivalence classes that are disequal + BoolMap d_disequal; +public: + EqClassInfo( context::Context* c ); + ~EqClassInfo(){} + //set member + void setMember( Node n, quantifiers::TermDb* db ); + //has function "funs" + bool hasFunction( Node op ); + //has parent "pfuns" + bool hasParent( Node op ); + //merge with another eq class info + void merge( EqClassInfo* eci ); +}; + +class EfficientEMatcher{ +protected: + /** reference to the quantifiers engine */ + QuantifiersEngine* d_quantEngine; +public: + EfficientEMatcher(CVC4::theory::QuantifiersEngine* qe); + ~EfficientEMatcher() { + for(std::map< Node, std::pair<NodePcDispatcher*, NodePpDispatcher*> >::iterator + i = d_pat_cand_gens.begin(), end = d_pat_cand_gens.end(); + i != end; i++){ + delete(i->second.first); + delete(i->second.second); + } + } + /** get equality engine we are using */ + eq::EqualityEngine* getEqualityEngine(); +private: + //information for each equivalence class + std::map< Node, EqClassInfo* > d_eqc_ops; +public: + /** new node */ + void newEqClass( TNode n ); + /** merge */ + void merge( TNode a, TNode b ); + /** assert terms are disequal */ + void assertDisequal( TNode a, TNode b, TNode reason ); + /** get equivalence class info */ + EqClassInfo* getEquivalenceClassInfo( Node n ); + EqClassInfo* getOrCreateEquivalenceClassInfo( Node n ); + typedef std::vector< std::pair< Node, int > > Ips; + typedef std::map< Node, std::vector< std::pair< Node, Ips > > > PpIpsMap; + typedef std::map< Node, std::vector< triple< size_t, Node, Ips > > > MultiPpIpsMap; +private: + /** Parent/Child Pairs (for efficient E-matching) + So, for example, if we have the pattern f( g( x ) ), then d_pc_pairs[g][f][f( g( x ) )] = { f.0 }. + */ + std::map< Node, std::map< Node, std::vector< std::pair< NodePcDispatcher*, Ips > > > > d_pc_pairs; + /** Parent/Parent Pairs (for efficient E-matching) */ + std::map< Node, std::map< Node, std::vector< triple< NodePpDispatcher*, Ips, Ips > > > > d_pp_pairs; + /** Constants/Child Pairs + So, for example, if we have the pattern f( x ) = c, then d_pc_pairs[f][c] = ..., pcdispatcher, ... + */ + //TODO constant in pattern can use the same thing just add an Ips + std::map< Node, std::map< Node, NodePcDispatcher* > > d_cc_pairs; + /** list of all candidate generators for each operator */ + std::map< Node, NodeNewTermDispatcher > d_cand_gens; + /** list of all candidate generators for each type */ + std::map< TypeNode, NodeNewTermDispatcher > d_cand_gen_types; + /** map from patterns to candidate generators */ + std::map< Node, std::pair<NodePcDispatcher*, NodePpDispatcher*> > d_pat_cand_gens; + /** helper functions */ + void registerPatternElementPairs2( Node pat, Ips& ips, + PpIpsMap & pp_ips_map, NodePcDispatcher* npc); + void registerPatternElementPairs( Node pat, PpIpsMap & pp_ips_map, + NodePcDispatcher* npc, NodePpDispatcher* npp); + /** find the pp-pair between pattern inside multi-pattern*/ + void combineMultiPpIpsMap(PpIpsMap & pp_ips_map, MultiPpIpsMap & multi_pp_ips_map, + EfficientHandler& eh, size_t index2, + const std::vector<Node> & pats); //pats for debug + /** compute candidates for pc pairs */ + void computeCandidatesPcPairs( Node a, EqClassInfo*, Node b, EqClassInfo* ); + /** compute candidates for pp pairs */ + void computeCandidatesPpPairs( Node a, EqClassInfo*, Node b, EqClassInfo* ); + /** compute candidates for cc pairs */ + void computeCandidatesConstants( Node a, EqClassInfo*, Node b, EqClassInfo* ); + /** collect terms based on inverted path string */ + void collectTermsIps( Ips& ips, SetNode& terms, int index); + bool collectParentsTermsIps( Node n, Node f, int arg, SetNode& terms, bool addRep, bool modEq = true ); +public: + void collectTermsIps( Ips& ips, SetNode& terms); +public: + void registerEfficientHandler( EfficientHandler& eh, const std::vector<Node> & pat ); +public: + void newTerms(SetNode& s); +public: + /** output eq class */ + void outputEqClass( const char* c, Node n ); + /** output inverted path string */ + void outputIps( const char* c, Ips& ips ); +};/* class EfficientEMatcher */ + + +}/* CVC4::theory namespace */ +}/* CVC4 namespace */ + +#endif /* __CVC4__EFFICIENT_E_MATCHING_H */ diff --git a/src/theory/rewriterules/rr_candidate_generator.h b/src/theory/rewriterules/rr_candidate_generator.h index 97c710219..d12c67f6a 100644 --- a/src/theory/rewriterules/rr_candidate_generator.h +++ b/src/theory/rewriterules/rr_candidate_generator.h @@ -32,7 +32,7 @@ typedef CVC4::theory::rrinst::CandidateGenerator CandidateGenerator; //New CandidateGenerator. They have a simpler semantic than the old one -// Just iterate amoung the equivalence classes +// Just iterate among the equivalence classes // node::Null() must be given to reset class CandidateGeneratorTheoryEeClasses : public CandidateGenerator{ private: @@ -54,7 +54,7 @@ public: }; }; -// Just iterate amoung the equivalence class of the given node +// Just iterate among the equivalence class of the given node // node::Null() *can't* be given to reset class CandidateGeneratorTheoryEeClass : public CandidateGenerator{ private: diff --git a/src/theory/rewriterules/rr_inst_match.h b/src/theory/rewriterules/rr_inst_match.h index 63728a95b..636a4dbc1 100644 --- a/src/theory/rewriterules/rr_inst_match.h +++ b/src/theory/rewriterules/rr_inst_match.h @@ -180,7 +180,7 @@ public: /** If reset, or getNextMatch return false they remove from the InstMatch the binding that they have previously created */ - /** virtual Matcher in order to have definned behavior */ + /** virtual Matcher in order to have defined behavior */ virtual ~Matcher(){}; }; @@ -195,7 +195,7 @@ private: std::vector< triple< Matcher*, size_t, EqualityQuery* > > d_childrens; /** the variable that have been set by this matcher (during its own reset) */ std::vector< TNode > d_binded; /* TNode because the variable are already in d_pattern */ - /** the representant of the argument of the term given by the last reset */ + /** the representative of the argument of the term given by the last reset */ std::vector< Node > d_reps; public: /** The pattern we are producing matches for */ @@ -250,7 +250,7 @@ public: PatsMatcher* mkPatterns( std::vector< Node > pat, QuantifiersEngine* qe ); PatsMatcher* mkPatternsEfficient( std::vector< Node > pat, QuantifiersEngine* qe ); -/** return true if whatever Node is subsituted for the variables the +/** return true if whatever Node is substituted for the variables the given Node can't match the pattern */ bool nonunifiable( TNode t, TNode pat, const std::vector<Node> & vars); diff --git a/src/theory/rewriterules/rr_trigger.h b/src/theory/rewriterules/rr_trigger.h index 7be5d1507..f11d6ed66 100644 --- a/src/theory/rewriterules/rr_trigger.h +++ b/src/theory/rewriterules/rr_trigger.h @@ -100,6 +100,7 @@ public: static inline bool isAtomicTrigger( TNode n ){ return n.getKind()==kind::APPLY_UF || + n.getKind() == kind::APPLY_CONSTRUCTOR || n.getKind()==kind::SELECT || n.getKind()==kind::STORE; } diff --git a/src/theory/substitutions.cpp b/src/theory/substitutions.cpp index 0cc64e403..8858cc34b 100644 --- a/src/theory/substitutions.cpp +++ b/src/theory/substitutions.cpp @@ -27,12 +27,11 @@ struct substitution_stack_element { bool children_added; substitution_stack_element(TNode node) : node(node), children_added(false) {} -}; - +};/* struct substitution_stack_element */ Node SubstitutionMap::internalSubstitute(TNode t) { - Debug("substitution::internal") << "SubstitutionMap::internalSubstitute(" << t << ")" << std::endl; + Debug("substitution::internal") << "SubstitutionMap::internalSubstitute(" << t << ")" << endl; if (d_substitutions.empty()) { return t; @@ -48,7 +47,7 @@ Node SubstitutionMap::internalSubstitute(TNode t) { substitution_stack_element& stackHead = toVisit.back(); TNode current = stackHead.node; - Debug("substitution::internal") << "SubstitutionMap::internalSubstitute(" << t << "): processing " << current << std::endl; + Debug("substitution::internal") << "SubstitutionMap::internalSubstitute(" << t << "): processing " << current << endl; // If node already in the cache we're done, pop from the stack NodeCache::iterator find = d_substitutionCache.find(current); @@ -57,6 +56,14 @@ Node SubstitutionMap::internalSubstitute(TNode t) { continue; } + if (!d_substituteUnderQuantifiers && + (current.getKind() == kind::FORALL || current.getKind() == kind::EXISTS)) { + Debug("substitution::internal") << "--not substituting under quantifier" << endl; + d_substitutionCache[current] = current; + toVisit.pop_back(); + continue; + } + NodeMap::iterator find2 = d_substitutions.find(current); if (find2 != d_substitutions.end()) { Node rhs = (*find2).second; @@ -98,7 +105,7 @@ Node SubstitutionMap::internalSubstitute(TNode t) { } } } - Debug("substitution::internal") << "SubstitutionMap::internalSubstitute(" << t << "): setting " << current << " -> " << result << std::endl; + Debug("substitution::internal") << "SubstitutionMap::internalSubstitute(" << t << "): setting " << current << " -> " << result << endl; d_substitutionCache[current] = result; toVisit.pop_back(); } else { @@ -123,7 +130,7 @@ Node SubstitutionMap::internalSubstitute(TNode t) { } } else { // No children, so we're done - Debug("substitution::internal") << "SubstitutionMap::internalSubstitute(" << t << "): setting " << current << " -> " << current << std::endl; + Debug("substitution::internal") << "SubstitutionMap::internalSubstitute(" << t << "): setting " << current << " -> " << current << endl; d_substitutionCache[current] = current; toVisit.pop_back(); } @@ -132,7 +139,7 @@ Node SubstitutionMap::internalSubstitute(TNode t) { // Return the substituted version return d_substitutionCache[t]; -} +}/* SubstitutionMap::internalSubstitute() */ /* @@ -258,7 +265,7 @@ void SubstitutionMap::processWorklist(vector<pair<Node, Node> >& equalities, boo void SubstitutionMap::addSubstitution(TNode x, TNode t, bool invalidateCache) { - Debug("substitution") << "SubstitutionMap::addSubstitution(" << x << ", " << t << ")" << std::endl; + Debug("substitution") << "SubstitutionMap::addSubstitution(" << x << ", " << t << ")" << endl; Assert(d_substitutions.find(x) == d_substitutions.end()); // this causes a later assert-fail (the rhs != current one, above) anyway @@ -280,32 +287,32 @@ static bool check(TNode node, const SubstitutionMap::NodeMap& substitutions) CVC static bool check(TNode node, const SubstitutionMap::NodeMap& substitutions) { SubstitutionMap::NodeMap::const_iterator it = substitutions.begin(); SubstitutionMap::NodeMap::const_iterator it_end = substitutions.end(); - Debug("substitution") << "checking " << node << std::endl; + Debug("substitution") << "checking " << node << endl; for (; it != it_end; ++ it) { - Debug("substitution") << "-- hasSubterm( " << (*it).first << " ) ?" << std::endl; + Debug("substitution") << "-- hasSubterm( " << (*it).first << " ) ?" << endl; if (node.hasSubterm((*it).first)) { - Debug("substitution") << "-- FAIL" << std::endl; + Debug("substitution") << "-- FAIL" << endl; return false; } } - Debug("substitution") << "-- SUCCEED" << std::endl; + Debug("substitution") << "-- SUCCEED" << endl; return true; } Node SubstitutionMap::apply(TNode t) { - Debug("substitution") << "SubstitutionMap::apply(" << t << ")" << std::endl; + Debug("substitution") << "SubstitutionMap::apply(" << t << ")" << endl; // Setup the cache if (d_cacheInvalidated) { d_substitutionCache.clear(); d_cacheInvalidated = false; - Debug("substitution") << "-- reset the cache" << std::endl; + Debug("substitution") << "-- reset the cache" << endl; } // Perform the substitution Node result = internalSubstitute(t); - Debug("substitution") << "SubstitutionMap::apply(" << t << ") => " << result << std::endl; + Debug("substitution") << "SubstitutionMap::apply(" << t << ") => " << result << endl; // Assert(check(result, d_substitutions)); diff --git a/src/theory/substitutions.h b/src/theory/substitutions.h index 31a6b9141..a199256e7 100644 --- a/src/theory/substitutions.h +++ b/src/theory/substitutions.h @@ -62,6 +62,9 @@ private: /** Cache of the already performed substitutions */ NodeCache d_substitutionCache; + /** Whether or not to substitute under quantifiers */ + bool d_substituteUnderQuantifiers; + /** Has the cache been invalidated? */ bool d_cacheInvalidated; @@ -95,10 +98,11 @@ private: public: - SubstitutionMap(context::Context* context) : + SubstitutionMap(context::Context* context, bool substituteUnderQuantifiers = true) : d_context(context), d_substitutions(context), d_substitutionCache(), + d_substituteUnderQuantifiers(substituteUnderQuantifiers), d_cacheInvalidated(false), d_cacheInvalidator(context, d_cacheInvalidated) { } diff --git a/src/theory/theory_engine.cpp b/src/theory/theory_engine.cpp index 35ed63bed..f7f689850 100644 --- a/src/theory/theory_engine.cpp +++ b/src/theory/theory_engine.cpp @@ -286,7 +286,9 @@ void TheoryEngine::check(Theory::Effort effort) { #endif #define CVC4_FOR_EACH_THEORY_STATEMENT(THEORY) \ if (theory::TheoryTraits<THEORY>::hasCheck && d_logicInfo.isTheoryEnabled(THEORY)) { \ +Debug("theory") << "check<" << THEORY << ">" << std::endl; \ theoryOf(THEORY)->check(effort); \ +Debug("theory") << "done<" << THEORY << ">" << std::endl; \ if (d_inConflict) { \ break; \ } \ @@ -726,16 +728,6 @@ theory::Theory::PPAssertStatus TheoryEngine::solve(TNode literal, SubstitutionMa Theory::PPAssertStatus solveStatus = theoryOf(atom)->ppAssert(literal, substitutionOut); Trace("theory::solve") << "TheoryEngine::solve(" << literal << ") => " << solveStatus << endl; - //must add substitutions to model - theory::TheoryModel* m = getModel(); - if( m ){ - for( SubstitutionMap::iterator pos = substitutionOut.begin(); pos != substitutionOut.end(); ++pos) { - Node n = (*pos).first; - Node v = (*pos).second; - Trace("model") << "Add substitution : " << n << " " << v << std::endl; - m->addSubstitution( n, v ); - } - } return solveStatus; } @@ -817,7 +809,7 @@ Node TheoryEngine::preprocess(TNode assertion) { stringstream ss; ss << "The logic was specified as " << d_logicInfo.getLogicString() << ", which doesn't include " << Theory::theoryOf(current) - << ", but got a preprocesing-time fact for that theory." << endl + << ", but got a preprocessing-time fact for that theory." << endl << "The fact:" << endl << current; throw LogicException(ss.str()); diff --git a/src/theory/theory_engine.h b/src/theory/theory_engine.h index 27371eac3..a3779f0e8 100644 --- a/src/theory/theory_engine.h +++ b/src/theory/theory_engine.h @@ -41,6 +41,7 @@ #include "util/hash.h" #include "util/cache.h" #include "util/cvc4_assert.h" +#include "util/sort_inference.h" #include "theory/ite_simplifier.h" #include "theory/unconstrained_simplifier.h" #include "theory/uf/equality_engine.h" @@ -268,7 +269,7 @@ class TheoryEngine { void safePoint() throw(theory::Interrupted, AssertionException) { if (d_engine->d_interrupted) throw theory::Interrupted(); - } + } void conflict(TNode conflictNode) throw(AssertionException) { Trace("theory::conflict") << "EngineOutputChannel<" << d_theory << ">::conflict(" << conflictNode << ")" << std::endl; @@ -422,6 +423,9 @@ class TheoryEngine { RemoveITE& d_iteRemover; + /** sort inference module */ + SortInference d_sortInfer; + /** Time spent in theory combination */ TimerStat d_combineTheoriesTime; @@ -732,24 +736,28 @@ public: SharedTermsDatabase* getSharedTermsDatabase() { return &d_sharedTerms; } + SortInference* getSortInference() { return &d_sortInfer; } private: std::map< std::string, std::vector< theory::Theory* > > d_attr_handle; public: - /** Set user attribute - * This function is called when an attribute is set by a user. In SMT-LIBv2 this is done - * via the syntax (! n :attr) - */ + /** + * Set user attribute. + * 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); - /** Handle user attribute - * Associates theory t with the attribute attr. Theory t will be - * notifed whenever an attribute of name attr is set. - */ + /** + * Handle user attribute. + * Associates theory t with the attribute attr. Theory t will be + * notified whenever an attribute of name attr is set. + */ void handleUserAttribute(const char* attr, theory::Theory* t); - /** Check that the theory assertions are satisfied in the model - * This function is called from the smt engine's checkModel routine + /** + * Check that the theory assertions are satisfied in the model. + * This function is called from the smt engine's checkModel routine. */ void checkTheoryAssertionsWithModel(); diff --git a/src/theory/uf/options b/src/theory/uf/options index 2569ccbff..33d1255ef 100644 --- a/src/theory/uf/options +++ b/src/theory/uf/options @@ -25,6 +25,10 @@ option ufssAbortCardinality --uf-ss-abort-card=N int :default -1 option ufssSmartSplits --uf-ss-smart-split bool :default false use smart splitting heuristic for uf strong solver option ufssExplainedCliques --uf-ss-explained-cliques bool :default false - add explained clique lemmas for uf strong solver + use explained clique lemmas for uf strong solver +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 endmodule diff --git a/src/theory/uf/theory_uf.cpp b/src/theory/uf/theory_uf.cpp index 3f033f3b8..bdbb79195 100644 --- a/src/theory/uf/theory_uf.cpp +++ b/src/theory/uf/theory_uf.cpp @@ -33,7 +33,7 @@ TheoryUF::TheoryUF(context::Context* c, context::UserContext* u, OutputChannel& d_notify(*this), /* The strong theory solver can be notified by EqualityEngine::init(), * so make sure it's initialized first. */ - d_thss(options::finiteModelFind() ? new StrongSolverTheoryUf(c, u, out, this) : NULL), + d_thss(options::finiteModelFind() ? new StrongSolverTheoryUF(c, u, out, this) : NULL), d_equalityEngine(d_notify, c, "theory::uf::TheoryUF"), d_conflict(c, false), d_literalsToPropagate(c), @@ -101,12 +101,10 @@ void TheoryUF::check(Effort level) { } - if (d_thss != NULL) { - if (! d_conflict) { - d_thss->check(level); - if( d_thss->isConflict() ){ - d_conflict = true; - } + if (d_thss != NULL && ! d_conflict) { + d_thss->check(level); + if( d_thss->isConflict() ){ + d_conflict = true; } } diff --git a/src/theory/uf/theory_uf.h b/src/theory/uf/theory_uf.h index fe1fc5137..00e270bd0 100644 --- a/src/theory/uf/theory_uf.h +++ b/src/theory/uf/theory_uf.h @@ -35,11 +35,11 @@ namespace theory { namespace uf { class UfTermDb; -class StrongSolverTheoryUf; +class StrongSolverTheoryUF; class TheoryUF : public Theory { - friend class StrongSolverTheoryUf; + friend class StrongSolverTheoryUF; public: @@ -116,7 +116,7 @@ private: NotifyClass d_notify; /** The associated theory strong solver (or NULL if none) */ - StrongSolverTheoryUf* d_thss; + StrongSolverTheoryUF* d_thss; /** Equaltity engine */ eq::EqualityEngine d_equalityEngine; @@ -212,7 +212,7 @@ public: return &d_equalityEngine; } - StrongSolverTheoryUf* getStrongSolver() { + StrongSolverTheoryUF* getStrongSolver() { return d_thss; } diff --git a/src/theory/uf/theory_uf_strong_solver.cpp b/src/theory/uf/theory_uf_strong_solver.cpp index 46ac5aa60..25cb8b66c 100644 --- a/src/theory/uf/theory_uf_strong_solver.cpp +++ b/src/theory/uf/theory_uf_strong_solver.cpp @@ -32,11 +32,11 @@ using namespace CVC4::context; using namespace CVC4::theory; using namespace CVC4::theory::uf; -void StrongSolverTheoryUf::SortRepModel::Region::addRep( Node n ) { +void StrongSolverTheoryUF::SortModel::Region::addRep( Node n ) { setRep( n, true ); } -void StrongSolverTheoryUf::SortRepModel::Region::takeNode( StrongSolverTheoryUf::SortRepModel::Region* r, Node n ){ +void StrongSolverTheoryUF::SortModel::Region::takeNode( StrongSolverTheoryUF::SortModel::Region* r, Node n ){ Assert( !hasRep( n ) ); Assert( r->hasRep( n ) ); //add representative @@ -68,7 +68,7 @@ void StrongSolverTheoryUf::SortRepModel::Region::takeNode( StrongSolverTheoryUf: r->setRep( n, false ); } -void StrongSolverTheoryUf::SortRepModel::Region::combine( StrongSolverTheoryUf::SortRepModel::Region* r ){ +void StrongSolverTheoryUF::SortModel::Region::combine( StrongSolverTheoryUF::SortModel::Region* r ){ //take all nodes from r for( std::map< Node, RegionNodeInfo* >::iterator it = r->d_nodes.begin(); it != r->d_nodes.end(); ++it ){ if( it->second->d_valid ){ @@ -100,7 +100,7 @@ void StrongSolverTheoryUf::SortRepModel::Region::combine( StrongSolverTheoryUf:: } /** setEqual */ -void StrongSolverTheoryUf::SortRepModel::Region::setEqual( Node a, Node b ){ +void StrongSolverTheoryUF::SortModel::Region::setEqual( Node a, Node b ){ Assert( hasRep( a ) && hasRep( b ) ); //move disequalities of b over to a for( int t=0; t<2; t++ ){ @@ -108,10 +108,15 @@ void StrongSolverTheoryUf::SortRepModel::Region::setEqual( Node a, Node b ){ for( NodeBoolMap::iterator it = del->d_disequalities.begin(); it != del->d_disequalities.end(); ++it ){ if( (*it).second ){ Node n = (*it).first; + //get the region that contains the endpoint of the disequality b != ... Region* nr = d_cf->d_regions[ d_cf->d_regions_map[ n ] ]; if( !isDisequal( a, n, t ) ){ setDisequal( a, n, t, true ); nr->setDisequal( n, a, t, true ); + //notify the disequality propagator + if( options::ufssDiseqPropagation() ){ + d_cf->d_thss->getDisequalityPropagator()->assertDisequal(a, n, Node::null()); + } } setDisequal( b, n, t, false ); nr->setDisequal( n, b, t, false ); @@ -122,7 +127,7 @@ void StrongSolverTheoryUf::SortRepModel::Region::setEqual( Node a, Node b ){ setRep( b, false ); } -void StrongSolverTheoryUf::SortRepModel::Region::setDisequal( Node n1, Node n2, int type, bool valid ){ +void StrongSolverTheoryUF::SortModel::Region::setDisequal( Node n1, Node n2, int type, bool valid ){ //Debug("uf-ss-region-debug") << "set disequal " << n1 << " " << n2 << " " << type << " " << valid << std::endl; //debugPrint("uf-ss-region-debug"); //Assert( isDisequal( n1, n2, type )!=valid ); @@ -148,10 +153,10 @@ void StrongSolverTheoryUf::SortRepModel::Region::setDisequal( Node n1, Node n2, } } -void StrongSolverTheoryUf::SortRepModel::Region::setRep( Node n, bool valid ){ +void StrongSolverTheoryUF::SortModel::Region::setRep( Node n, bool valid ){ Assert( hasRep( n )!=valid ); if( valid && d_nodes.find( n )==d_nodes.end() ){ - d_nodes[n] = new RegionNodeInfo( d_cf->d_th->getSatContext() ); + d_nodes[n] = new RegionNodeInfo( d_cf->d_thss->getSatContext() ); } d_nodes[n]->d_valid = valid; d_reps_size = d_reps_size + ( valid ? 1 : -1 ); @@ -172,24 +177,24 @@ void StrongSolverTheoryUf::SortRepModel::Region::setRep( Node n, bool valid ){ } } -bool StrongSolverTheoryUf::SortRepModel::Region::isDisequal( Node n1, Node n2, int type ){ +bool StrongSolverTheoryUF::SortModel::Region::isDisequal( Node n1, Node n2, int type ){ RegionNodeInfo::DiseqList* del = d_nodes[ n1 ]->d_disequalities[type]; return del->d_disequalities.find( n2 )!=del->d_disequalities.end() && del->d_disequalities[n2]; } struct sortInternalDegree { - StrongSolverTheoryUf::SortRepModel::Region* r; + StrongSolverTheoryUF::SortModel::Region* r; bool operator() (Node i,Node j) { return (r->d_nodes[i]->getNumInternalDisequalities()>r->d_nodes[j]->getNumInternalDisequalities());} }; struct sortExternalDegree { - StrongSolverTheoryUf::SortRepModel::Region* r; + StrongSolverTheoryUF::SortModel::Region* r; bool operator() (Node i,Node j) { return (r->d_nodes[i]->getNumExternalDisequalities()>r->d_nodes[j]->getNumExternalDisequalities());} }; int gmcCount = 0; -bool StrongSolverTheoryUf::SortRepModel::Region::getMustCombine( int cardinality ){ +bool StrongSolverTheoryUF::SortModel::Region::getMustCombine( int cardinality ){ if( options::ufssRegions() && d_total_diseq_external>=long(cardinality) ){ //The number of external disequalities is greater than or equal to cardinality. //Thus, a clique of size cardinality+1 may exist between nodes in d_regions[i] and other regions @@ -228,7 +233,7 @@ bool StrongSolverTheoryUf::SortRepModel::Region::getMustCombine( int cardinality return false; } -bool StrongSolverTheoryUf::SortRepModel::Region::check( Theory::Effort level, int cardinality, std::vector< Node >& clique ){ +bool StrongSolverTheoryUF::SortModel::Region::check( Theory::Effort level, int cardinality, std::vector< Node >& clique ){ if( d_reps_size>long(cardinality) ){ if( d_total_diseq_internal==d_reps_size*( d_reps_size - 1 ) ){ if( d_reps_size>1 ){ @@ -317,7 +322,7 @@ bool StrongSolverTheoryUf::SortRepModel::Region::check( Theory::Effort level, in return false; } -void StrongSolverTheoryUf::SortRepModel::Region::getRepresentatives( std::vector< Node >& reps ){ +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 ){ @@ -326,7 +331,7 @@ void StrongSolverTheoryUf::SortRepModel::Region::getRepresentatives( std::vector } } -void StrongSolverTheoryUf::SortRepModel::Region::getNumExternalDisequalities( std::map< Node, int >& num_ext_disequalities ){ +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; if( rni->d_valid ){ @@ -340,7 +345,7 @@ void StrongSolverTheoryUf::SortRepModel::Region::getNumExternalDisequalities( st } } -void StrongSolverTheoryUf::SortRepModel::Region::debugPrint( const char* c, bool incClique ){ +void StrongSolverTheoryUF::SortModel::Region::debugPrint( const char* c, bool incClique ){ Debug( c ) << "Num reps: " << d_reps_size << std::endl; for( std::map< Node, RegionNodeInfo* >::iterator it = d_nodes.begin(); it != d_nodes.end(); ++it ){ RegionNodeInfo* rni = it->second; @@ -389,27 +394,27 @@ void StrongSolverTheoryUf::SortRepModel::Region::debugPrint( const char* c, bool -StrongSolverTheoryUf::SortRepModel::SortRepModel( Node n, context::Context* c, TheoryUF* th ) : RepModel( n.getType() ), - d_th( th ), d_regions_index( c, 0 ), d_regions_map( c ), d_split_score( c ), d_disequalities_index( c, 0 ), +StrongSolverTheoryUF::SortModel::SortModel( Node n, context::Context* c, StrongSolverTheoryUF* thss ) : d_type( n.getType() ), + d_thss( thss ), d_regions_index( c, 0 ), d_regions_map( c ), d_split_score( c ), d_disequalities_index( c, 0 ), d_reps( c, 0 ), d_conflict( c, false ), d_cardinality( c, 1 ), d_aloc_cardinality( 0 ), d_cardinality_assertions( c ), d_hasCard( c, false ){ d_cardinality_term = n; } /** initialize */ -void StrongSolverTheoryUf::SortRepModel::initialize( OutputChannel* out ){ +void StrongSolverTheoryUF::SortModel::initialize( OutputChannel* out ){ allocateCardinality( out ); } /** new node */ -void StrongSolverTheoryUf::SortRepModel::newEqClass( Node n ){ +void StrongSolverTheoryUF::SortModel::newEqClass( Node n ){ if( !d_conflict ){ if( d_regions_map.find( n )==d_regions_map.end() ){ if( !options::ufssTotalityLazy() ){ //must generate totality axioms for every cardinality we have allocated thus far for( std::map< int, Node >::iterator it = d_cardinality_literal.begin(); it != d_cardinality_literal.end(); ++it ){ if( applyTotality( it->first ) ){ - addTotalityAxiom( n, it->first, &d_th->getOutputChannel() ); + addTotalityAxiom( n, it->first, &d_thss->getOutputChannel() ); } } } @@ -429,14 +434,14 @@ void StrongSolverTheoryUf::SortRepModel::newEqClass( Node n ){ if( options::ufssSmartSplits() ){ setSplitScore( n, 0 ); } - Debug("uf-ss") << "StrongSolverTheoryUf: New Eq Class " << n << std::endl; + Debug("uf-ss") << "StrongSolverTheoryUF: New Eq Class " << n << std::endl; Debug("uf-ss-debug") << d_regions_index << " " << (int)d_regions.size() << std::endl; if( d_regions_index<d_regions.size() ){ d_regions[ d_regions_index ]->debugPrint("uf-ss-debug",true); d_regions[ d_regions_index ]->d_valid = true; Assert( !options::ufssRegions() || d_regions[ d_regions_index ]->getNumReps()==0 ); }else{ - d_regions.push_back( new Region( this, d_th->getSatContext() ) ); + d_regions.push_back( new Region( this, d_thss->getSatContext() ) ); } d_regions[ d_regions_index ]->addRep( n ); d_regions_index = d_regions_index + 1; @@ -447,7 +452,7 @@ void StrongSolverTheoryUf::SortRepModel::newEqClass( Node n ){ } /** merge */ -void StrongSolverTheoryUf::SortRepModel::merge( Node a, Node b ){ +void StrongSolverTheoryUF::SortModel::merge( Node a, Node b ){ if( !d_conflict ){ if( options::ufssTotality() ){ if( d_regions_map[b]==-1 ){ @@ -457,7 +462,7 @@ void StrongSolverTheoryUf::SortRepModel::merge( Node a, Node b ){ }else{ //Assert( a==d_th->d_equalityEngine.getRepresentative( a ) ); //Assert( b==d_th->d_equalityEngine.getRepresentative( b ) ); - Debug("uf-ss") << "StrongSolverTheoryUf: Merging " << a << " = " << b << "..." << std::endl; + Debug("uf-ss") << "StrongSolverTheoryUF: Merging " << a << " = " << b << "..." << std::endl; if( a!=b ){ Assert( d_regions_map.find( a )!=d_regions_map.end() ); Assert( d_regions_map.find( b )!=d_regions_map.end() ); @@ -495,21 +500,25 @@ void StrongSolverTheoryUf::SortRepModel::merge( Node a, Node b ){ d_regions_map[b] = -1; } d_reps = d_reps - 1; - Debug("uf-ss") << "Done merge." << std::endl; + + if( options::ufssDiseqPropagation() && !d_conflict ){ + //notify the disequality propagator + d_thss->getDisequalityPropagator()->merge(a, b); + } } } } /** assert terms are disequal */ -void StrongSolverTheoryUf::SortRepModel::assertDisequal( Node a, Node b, Node reason ){ +void StrongSolverTheoryUF::SortModel::assertDisequal( Node a, Node b, Node reason ){ if( !d_conflict ){ if( options::ufssTotality() ){ //do nothing }else{ //if they are not already disequal - a = d_th->d_equalityEngine.getRepresentative( a ); - b = d_th->d_equalityEngine.getRepresentative( b ); - if( !d_th->d_equalityEngine.areDisequal( a, b, true ) ){ + a = d_thss->getTheory()->d_equalityEngine.getRepresentative( a ); + b = d_thss->getTheory()->d_equalityEngine.getRepresentative( b ); + if( !d_thss->getTheory()->d_equalityEngine.areDisequal( a, b, true ) ){ Debug("uf-ss") << "Assert disequal " << a << " != " << b << "..." << std::endl; //if( reason.getKind()!=NOT || ( reason[0].getKind()!=EQUAL && reason[0].getKind()!=IFF ) || // a!=reason[0][0] || b!=reason[0][1] ){ @@ -533,6 +542,7 @@ void StrongSolverTheoryUf::SortRepModel::assertDisequal( Node a, Node b, Node re //internal disequality d_regions[ai]->setDisequal( a, b, 1, true ); d_regions[ai]->setDisequal( b, a, 1, true ); + checkRegion( ai, false ); //do not need to check if it needs to combine (no new ext. disequalities) }else{ //external disequality d_regions[ai]->setDisequal( a, b, 0, true ); @@ -540,18 +550,34 @@ void StrongSolverTheoryUf::SortRepModel::assertDisequal( Node a, Node b, Node re checkRegion( ai ); checkRegion( bi ); } - //Notice() << "done" << std::endl; + + if( options::ufssDiseqPropagation() && !d_conflict ){ + //notify the disequality propagator + d_thss->getDisequalityPropagator()->assertDisequal(a, b, Node::null()); + } } } } } +bool StrongSolverTheoryUF::SortModel::areDisequal( Node a, Node b ) { + Assert( a == d_thss->getTheory()->d_equalityEngine.getRepresentative( a ) ); + Assert( b == d_thss->getTheory()->d_equalityEngine.getRepresentative( b ) ); + if( d_regions_map.find( a )!=d_regions_map.end() && + d_regions_map.find( b )!=d_regions_map.end() ){ + int ai = d_regions_map[a]; + int bi = d_regions_map[b]; + return d_regions[ai]->isDisequal(a, b, ai==bi ? 1 : 0); + }else{ + return false; + } +} /** check */ -void StrongSolverTheoryUf::SortRepModel::check( Theory::Effort level, OutputChannel* out ){ +void StrongSolverTheoryUF::SortModel::check( Theory::Effort level, OutputChannel* out ){ if( level>=Theory::EFFORT_STANDARD && d_hasCard && !d_conflict ){ - Debug("uf-ss") << "StrongSolverTheoryUf: Check " << level << " " << d_type << std::endl; - //Notice() << "StrongSolverTheoryUf: Check " << level << std::endl; + Debug("uf-ss") << "StrongSolverTheoryUF: Check " << level << " " << d_type << std::endl; + //Notice() << "StrongSolverTheoryUF: Check " << level << std::endl; if( d_reps<=(unsigned)d_cardinality ){ Debug("uf-ss-debug") << "We have " << d_reps << " representatives for type " << d_type << ", <= " << d_cardinality << std::endl; if( level==Theory::EFFORT_FULL ){ @@ -584,7 +610,7 @@ void StrongSolverTheoryUf::SortRepModel::check( Theory::Effort level, OutputChan if( level==Theory::EFFORT_FULL ){ for( NodeIntMap::iterator it = d_regions_map.begin(); it != d_regions_map.end(); ++it ){ if( !options::ufssTotality() || d_regions_map[ (*it).first ]!=-1 ){ - addTotalityAxiom( (*it).first, d_cardinality, &d_th->getOutputChannel() ); + addTotalityAxiom( (*it).first, d_cardinality, &d_thss->getOutputChannel() ); } } } @@ -610,8 +636,26 @@ void StrongSolverTheoryUf::SortRepModel::check( Theory::Effort level, OutputChan if( level==Theory::EFFORT_FULL ){ if( !addedLemma ){ Trace("uf-ss-debug") << "No splits added. " << d_cardinality << std::endl; - if( !options::ufssColoringSat() ){ - bool recheck = false; + Trace("uf-ss-si") << "Must combine region" << std::endl; + bool recheck = false; + if( options::sortInference()){ + //if sort inference is enabled, search for regions with same sort + std::map< int, int > sortsFound; + for( int i=0; i<(int)d_regions_index; i++ ){ + if( d_regions[i]->d_valid ){ + Node op = d_regions[i]->d_nodes.begin()->first; + int sort_id = d_thss->getTheory()->getQuantifiersEngine()->getTheoryEngine()->getSortInference()->getSortId(op); + if( sortsFound.find( sort_id )!=sortsFound.end() ){ + combineRegions( sortsFound[sort_id], i ); + recheck = true; + break; + }else{ + sortsFound[sort_id] = i; + } + } + } + } + if( !recheck ) { //naive strategy, force region combination involving the first valid region for( int i=0; i<(int)d_regions_index; i++ ){ if( d_regions[i]->d_valid ){ @@ -620,9 +664,9 @@ void StrongSolverTheoryUf::SortRepModel::check( Theory::Effort level, OutputChan break; } } - if( recheck ){ - check( level, out ); - } + } + if( recheck ){ + check( level, out ); } } } @@ -631,11 +675,11 @@ void StrongSolverTheoryUf::SortRepModel::check( Theory::Effort level, OutputChan } } -void StrongSolverTheoryUf::SortRepModel::propagate( Theory::Effort level, OutputChannel* out ){ +void StrongSolverTheoryUF::SortModel::propagate( Theory::Effort level, OutputChannel* out ){ } -Node StrongSolverTheoryUf::SortRepModel::getNextDecisionRequest(){ +Node StrongSolverTheoryUF::SortModel::getNextDecisionRequest(){ //request the current cardinality as a decision literal, if not already asserted for( int i=1; i<=d_aloc_cardinality; i++ ){ if( !d_hasCard || i<d_cardinality ){ @@ -650,7 +694,7 @@ Node StrongSolverTheoryUf::SortRepModel::getNextDecisionRequest(){ return Node::null(); } -bool StrongSolverTheoryUf::SortRepModel::minimize( OutputChannel* out, TheoryModel* m ){ +bool StrongSolverTheoryUF::SortModel::minimize( OutputChannel* out, TheoryModel* m ){ if( options::ufssTotality() ){ //do nothing }else{ @@ -672,7 +716,7 @@ bool StrongSolverTheoryUf::SortRepModel::minimize( OutputChannel* out, TheoryMod out->split( splitEq ); //tell the sat solver to explore the equals branch first out->requirePhase( splitEq, true ); - ++( d_th->getStrongSolver()->d_statistics.d_split_lemmas ); + ++( d_thss->d_statistics.d_split_lemmas ); return false; } } @@ -706,7 +750,7 @@ bool StrongSolverTheoryUf::SortRepModel::minimize( OutputChannel* out, TheoryMod } -int StrongSolverTheoryUf::SortRepModel::getNumDisequalitiesToRegion( Node n, int ri ){ +int StrongSolverTheoryUF::SortModel::getNumDisequalitiesToRegion( Node n, int ri ){ int ni = d_regions_map[n]; int counter = 0; Region::RegionNodeInfo::DiseqList* del = d_regions[ni]->d_nodes[n]->d_disequalities[0]; @@ -720,7 +764,7 @@ int StrongSolverTheoryUf::SortRepModel::getNumDisequalitiesToRegion( Node n, int return counter; } -void StrongSolverTheoryUf::SortRepModel::getDisequalitiesToRegions( int ri, std::map< int, int >& regions_diseq ){ +void StrongSolverTheoryUF::SortModel::getDisequalitiesToRegions( int ri, std::map< int, int >& regions_diseq ){ for( std::map< Node, Region::RegionNodeInfo* >::iterator it = d_regions[ri]->d_nodes.begin(); it != d_regions[ri]->d_nodes.end(); ++it ){ if( it->second->d_valid ){ @@ -736,7 +780,7 @@ void StrongSolverTheoryUf::SortRepModel::getDisequalitiesToRegions( int ri, std: } } -void StrongSolverTheoryUf::SortRepModel::setSplitScore( Node n, int s ){ +void StrongSolverTheoryUF::SortModel::setSplitScore( Node n, int s ){ if( d_split_score.find( n )!=d_split_score.end() ){ int ss = d_split_score[ n ]; d_split_score[ n ] = s>ss ? s : ss; @@ -748,9 +792,10 @@ void StrongSolverTheoryUf::SortRepModel::setSplitScore( Node n, int s ){ } } -void StrongSolverTheoryUf::SortRepModel::assertCardinality( OutputChannel* out, int c, bool val ){ +void StrongSolverTheoryUF::SortModel::assertCardinality( OutputChannel* out, int c, bool val ){ if( !d_conflict ){ - Trace("uf-ss-assert") << "Assert cardinality " << d_type << " " << c << " " << val << " level = " << d_th->d_valuation.getAssertionLevel() << std::endl; + Trace("uf-ss-assert") << "Assert cardinality " << d_type << " " << c << " " << val << " level = "; + Trace("uf-ss-assert") << d_thss->getTheory()->d_valuation.getAssertionLevel() << std::endl; Assert( d_cardinality_literal.find( c )!=d_cardinality_literal.end() ); d_cardinality_assertions[ d_cardinality_literal[c] ] = val; if( val ){ @@ -803,15 +848,10 @@ void StrongSolverTheoryUf::SortRepModel::assertCardinality( OutputChannel* out, } } -void StrongSolverTheoryUf::SortRepModel::checkRegion( int ri, bool rec ){ +void StrongSolverTheoryUF::SortModel::checkRegion( int ri, bool checkCombine ){ if( isValid(ri) && d_hasCard ){ Assert( d_cardinality>0 ); - //first check if region is in conflict - std::vector< Node > clique; - if( d_regions[ri]->check( Theory::EFFORT_STANDARD, d_cardinality, clique ) ){ - //explain clique - addCliqueLemma( clique, &d_th->getOutputChannel() ); - }else if( d_regions[ri]->getMustCombine( d_cardinality ) ){ + if( checkCombine && d_regions[ri]->getMustCombine( d_cardinality ) ){ ////alternatively, check if we can reduce the number of external disequalities by moving single nodes //for( std::map< Node, bool >::iterator it = d_regions[i]->d_reps.begin(); it != d_regions[i]->d_reps.end(); ++it ){ // if( it->second ){ @@ -822,14 +862,20 @@ void StrongSolverTheoryUf::SortRepModel::checkRegion( int ri, bool rec ){ // } //} int riNew = forceCombineRegion( ri, true ); - if( riNew>=0 && rec ){ - checkRegion( riNew, rec ); + if( riNew>=0 ){ + checkRegion( riNew, checkCombine ); } } + //now check if region is in conflict + std::vector< Node > clique; + if( d_regions[ri]->check( Theory::EFFORT_STANDARD, d_cardinality, clique ) ){ + //explain clique + addCliqueLemma( clique, &d_thss->getOutputChannel() ); + } } } -int StrongSolverTheoryUf::SortRepModel::forceCombineRegion( int ri, bool useDensity ){ +int StrongSolverTheoryUF::SortModel::forceCombineRegion( int ri, bool useDensity ){ if( !useDensity ){ for( int i=0; i<(int)d_regions_index; i++ ){ if( ri!=i && d_regions[i]->d_valid ){ @@ -869,7 +915,7 @@ int StrongSolverTheoryUf::SortRepModel::forceCombineRegion( int ri, bool useDens } -int StrongSolverTheoryUf::SortRepModel::combineRegions( int ai, int bi ){ +int StrongSolverTheoryUF::SortModel::combineRegions( int ai, int bi ){ #ifdef COMBINE_REGIONS_SMALL_INTO_LARGE if( d_regions[ai]->getNumReps()<d_regions[bi]->getNumReps() ){ return combineRegions( bi, ai ); @@ -889,7 +935,7 @@ int StrongSolverTheoryUf::SortRepModel::combineRegions( int ai, int bi ){ return ai; } -void StrongSolverTheoryUf::SortRepModel::moveNode( Node n, int ri ){ +void StrongSolverTheoryUF::SortModel::moveNode( Node n, int ri ){ Debug("uf-ss-region") << "uf-ss: Move node " << n << " to Region #" << ri << std::endl; Assert( isValid( d_regions_map[ n ] ) ); Assert( isValid( ri ) ); @@ -898,7 +944,7 @@ void StrongSolverTheoryUf::SortRepModel::moveNode( Node n, int ri ){ d_regions_map[n] = ri; } -void StrongSolverTheoryUf::SortRepModel::allocateCardinality( OutputChannel* out ){ +void StrongSolverTheoryUF::SortModel::allocateCardinality( OutputChannel* out ){ if( d_aloc_cardinality>0 ){ Trace("uf-ss-fmf") << "No model of size " << d_aloc_cardinality << " exists for type " << d_type << " in this branch" << std::endl; if( Trace.isOn("uf-ss-cliques") ){ @@ -936,7 +982,7 @@ void StrongSolverTheoryUf::SortRepModel::allocateCardinality( OutputChannel* out //must be distinct from all other cardinality terms for( int i=0; i<(int)(d_totality_terms[0].size()-1); i++ ){ Node lem = NodeManager::currentNM()->mkNode( NOT, var.eqNode( d_totality_terms[0][i] ) ); - d_th->getOutputChannel().lemma( lem ); + d_thss->getOutputChannel().lemma( lem ); } } @@ -955,18 +1001,18 @@ void StrongSolverTheoryUf::SortRepModel::allocateCardinality( OutputChannel* out //add the appropriate lemma, propagate as decision //Trace("uf-ss-prop-as-dec") << "Propagate as decision " << lem[0] << " " << d_type << std::endl; //out->propagateAsDecision( lem[0] ); - d_th->getStrongSolver()->d_statistics.d_max_model_size.maxAssign( d_aloc_cardinality ); + d_thss->d_statistics.d_max_model_size.maxAssign( d_aloc_cardinality ); if( applyTotality( d_aloc_cardinality ) && !options::ufssTotalityLazy() ){ //must send totality axioms for each existing term for( NodeIntMap::iterator it = d_regions_map.begin(); it != d_regions_map.end(); ++it ){ - addTotalityAxiom( (*it).first, d_aloc_cardinality, &d_th->getOutputChannel() ); + addTotalityAxiom( (*it).first, d_aloc_cardinality, &d_thss->getOutputChannel() ); } } } } -bool StrongSolverTheoryUf::SortRepModel::addSplit( Region* r, OutputChannel* out ){ +bool StrongSolverTheoryUF::SortModel::addSplit( Region* r, OutputChannel* out ){ if( r->hasSplits() ){ Node s; if( !options::ufssSmartSplits() ){ @@ -996,6 +1042,13 @@ bool StrongSolverTheoryUf::SortRepModel::addSplit( Region* r, OutputChannel* out Assert( s!=Node::null() && s.getKind()==EQUAL ); s = Rewriter::rewrite( s ); Trace("uf-ss-lemma") << "*** Split on " << s << std::endl; + if( options::sortInference()) { + for( int i=0; i<2; i++ ){ + int si = d_thss->getTheory()->getQuantifiersEngine()->getTheoryEngine()->getSortInference()->getSortId( s[i] ); + Trace("uf-ss-split-si") << si << " "; + } + Trace("uf-ss-split-si") << std::endl; + } //Trace("uf-ss-lemma") << d_th->getEqualityEngine()->areEqual( s[0], s[1] ) << " "; //Trace("uf-ss-lemma") << d_th->getEqualityEngine()->areDisequal( s[0], s[1] ) << std::endl; //Trace("uf-ss-lemma") << s[0].getType() << " " << s[1].getType() << std::endl; @@ -1004,7 +1057,7 @@ bool StrongSolverTheoryUf::SortRepModel::addSplit( Region* r, OutputChannel* out out->split( s ); //tell the sat solver to explore the equals branch first out->requirePhase( s, true ); - ++( d_th->getStrongSolver()->d_statistics.d_split_lemmas ); + ++( d_thss->d_statistics.d_split_lemmas ); return true; }else{ return false; @@ -1012,126 +1065,158 @@ bool StrongSolverTheoryUf::SortRepModel::addSplit( Region* r, OutputChannel* out } -void StrongSolverTheoryUf::SortRepModel::addCliqueLemma( std::vector< Node >& clique, OutputChannel* out ){ +void StrongSolverTheoryUF::SortModel::addCliqueLemma( std::vector< Node >& clique, OutputChannel* out ){ Assert( d_hasCard ); Assert( d_cardinality>0 ); while( clique.size()>size_t(d_cardinality+1) ){ clique.pop_back(); } - if( !options::ufssExplainedCliques() ){ + if( options::ufssSimpleCliques() && !options::ufssExplainedCliques() ){ //add as lemma std::vector< Node > eqs; for( int i=0; i<(int)clique.size(); i++ ){ for( int j=0; j<i; j++ ){ + Node r1 = d_thss->getTheory()->d_equalityEngine.getRepresentative(clique[i]); + Node r2 = d_thss->getTheory()->d_equalityEngine.getRepresentative(clique[j]); eqs.push_back( clique[i].eqNode( clique[j] ) ); } } eqs.push_back( d_cardinality_literal[ d_cardinality ].notNode() ); Node lem = NodeManager::currentNM()->mkNode( OR, eqs ); + Trace("uf-ss-lemma") << "*** Add clique conflict " << lem << std::endl; + ++( d_thss->d_statistics.d_clique_lemmas ); out->lemma( lem ); - return; - } - //if( options::ufssModelInference() || - if( Trace.isOn("uf-ss-cliques") ){ - std::vector< Node > clique_vec; - clique_vec.insert( clique_vec.begin(), clique.begin(), clique.end() ); - d_cliques[ d_cardinality ].push_back( clique_vec ); - } - - //found a clique - Debug("uf-ss-cliques") << "Found a clique (cardinality=" << d_cardinality << ") :" << std::endl; - Debug("uf-ss-cliques") << " "; - for( int i=0; i<(int)clique.size(); i++ ){ - Debug("uf-ss-cliques") << clique[i] << " "; - } - Debug("uf-ss-cliques") << std::endl; - Debug("uf-ss-cliques") << "Finding clique disequalities..." << std::endl; - std::vector< Node > conflict; - //collect disequalities, and nodes that must be equal within representatives - std::map< Node, std::map< Node, bool > > explained; - std::map< Node, std::map< Node, bool > > nodesWithinRep; - for( int i=0; i<(int)d_disequalities_index; i++ ){ - //if both sides of disequality exist in clique - Node r1 = d_th->d_equalityEngine.getRepresentative( d_disequalities[i][0][0] ); - Node r2 = d_th->d_equalityEngine.getRepresentative( d_disequalities[i][0][1] ); - if( r1!=r2 && ( explained.find( r1 )==explained.end() || explained[r1].find( r2 )==explained[r1].end() ) && - std::find( clique.begin(), clique.end(), r1 )!=clique.end() && - std::find( clique.begin(), clique.end(), r2 )!=clique.end() ){ - explained[r1][r2] = true; - explained[r2][r1] = true; - conflict.push_back( d_disequalities[i] ); - Debug("uf-ss-cliques") << " -> disequality : " << d_disequalities[i] << std::endl; - nodesWithinRep[r1][ d_disequalities[i][0][0] ] = true; - nodesWithinRep[r2][ d_disequalities[i][0][1] ] = true; - if( conflict.size()==(clique.size()*( clique.size()-1 )/2) ){ - break; + }else{ + //debugging information + if( Trace.isOn("uf-ss-cliques") ){ + std::vector< Node > clique_vec; + clique_vec.insert( clique_vec.begin(), clique.begin(), clique.end() ); + d_cliques[ d_cardinality ].push_back( clique_vec ); + } + //found a clique + Debug("uf-ss-cliques") << "Found a clique (cardinality=" << d_cardinality << ") :" << std::endl; + Debug("uf-ss-cliques") << " "; + for( int i=0; i<(int)clique.size(); i++ ){ + Debug("uf-ss-cliques") << clique[i] << " "; + } + Debug("uf-ss-cliques") << std::endl; + Debug("uf-ss-cliques") << "Finding clique disequalities..." << std::endl; + + //we will scan through each of the disequaltities + bool isSatConflict = true; + std::vector< Node > conflict; + //collect disequalities, and nodes that must be equal within representatives + std::map< Node, std::map< Node, bool > > explained; + std::map< Node, std::map< Node, bool > > nodesWithinRep; + //map from the reprorted clique members to those reported in the lemma + std::map< Node, Node > cliqueRepMap; + for( int i=0; i<(int)d_disequalities_index; i++ ){ + //if both sides of disequality exist in clique + Node r1 = d_thss->getTheory()->d_equalityEngine.getRepresentative( d_disequalities[i][0][0] ); + Node r2 = d_thss->getTheory()->d_equalityEngine.getRepresentative( d_disequalities[i][0][1] ); + if( r1!=r2 && ( explained.find( r1 )==explained.end() || explained[r1].find( r2 )==explained[r1].end() ) && + std::find( clique.begin(), clique.end(), r1 )!=clique.end() && + std::find( clique.begin(), clique.end(), r2 )!=clique.end() ){ + explained[r1][r2] = true; + explained[r2][r1] = true; + if( options::ufssExplainedCliques() ){ + conflict.push_back( d_disequalities[i] ); + Debug("uf-ss-cliques") << " -> disequality : " << d_disequalities[i] << std::endl; + nodesWithinRep[r1][ d_disequalities[i][0][0] ] = true; + nodesWithinRep[r2][ d_disequalities[i][0][1] ] = true; + }else{ + //get the terms we report in the lemma + Node ru1 = r1; + if( cliqueRepMap.find( r1 )==cliqueRepMap.end() ){ + ru1 = d_disequalities[i][0][0]; + cliqueRepMap[r1] = ru1; + }else{ + ru1 = cliqueRepMap[r1]; + } + Node ru2 = r2; + if( cliqueRepMap.find( r2 )==cliqueRepMap.end() ){ + ru2 = d_disequalities[i][0][1]; + cliqueRepMap[r2] = ru2; + }else{ + ru2 = cliqueRepMap[r2]; + } + if( ru1!=d_disequalities[i][0][0] || ru2!=d_disequalities[i][0][1] ){ + //disequalities have endpoints that are not connected within an equivalence class + // we will be producing a lemma, introducing a new literal ru1 != ru2 + conflict.push_back( ru1.eqNode( ru2 ).notNode() ); + isSatConflict = false; + }else{ + conflict.push_back( d_disequalities[i] ); + } + } + if( conflict.size()==(clique.size()*( clique.size()-1 )/2) ){ + break; + } } } - } - //Debug("uf-ss-cliques") << conflict.size() << " " << clique.size() << std::endl; - Assert( (int)conflict.size()==((int)clique.size()*( (int)clique.size()-1 )/2) ); - //Assert( (int)conflict.size()==(int)clique.size()*( (int)clique.size()-1 )/2 ); - Debug("uf-ss-cliques") << "Finding clique equalities internal to eq classes..." << std::endl; - //now, we must explain equalities within each equivalence class - for( std::map< Node, std::map< Node, bool > >::iterator it = nodesWithinRep.begin(); it != nodesWithinRep.end(); ++it ){ - if( it->second.size()>1 ){ - Node prev; - //add explanation of t1 = t2 = ... = tn - Debug("uf-ss-cliques") << "Explain "; - for( std::map< Node, bool >::iterator it2 = it->second.begin(); it2 != it->second.end(); ++it2 ){ - if( prev!=Node::null() ){ - Debug("uf-ss-cliques") << " = "; - //explain it2->first and prev - std::vector< TNode > expl; - d_th->d_equalityEngine.explainEquality( it2->first, prev, true, expl ); - for( int i=0; i<(int)expl.size(); i++ ){ - if( std::find( conflict.begin(), conflict.end(), expl[i] )==conflict.end() ){ - conflict.push_back( expl[i] ); + if( options::ufssExplainedCliques() ){ + //Debug("uf-ss-cliques") << conflict.size() << " " << clique.size() << std::endl; + Assert( (int)conflict.size()==((int)clique.size()*( (int)clique.size()-1 )/2) ); + //Assert( (int)conflict.size()==(int)clique.size()*( (int)clique.size()-1 )/2 ); + Debug("uf-ss-cliques") << "Finding clique equalities internal to eq classes..." << std::endl; + //now, we must explain equalities within each equivalence class + for( std::map< Node, std::map< Node, bool > >::iterator it = nodesWithinRep.begin(); it != nodesWithinRep.end(); ++it ){ + if( it->second.size()>1 ){ + Node prev; + //add explanation of t1 = t2 = ... = tn + Debug("uf-ss-cliques") << "Explain "; + for( std::map< Node, bool >::iterator it2 = it->second.begin(); it2 != it->second.end(); ++it2 ){ + if( prev!=Node::null() ){ + Debug("uf-ss-cliques") << " = "; + //explain it2->first and prev + std::vector< TNode > expl; + d_thss->getTheory()->d_equalityEngine.explainEquality( it2->first, prev, true, expl ); + for( int i=0; i<(int)expl.size(); i++ ){ + if( std::find( conflict.begin(), conflict.end(), expl[i] )==conflict.end() ){ + conflict.push_back( expl[i] ); + } + } } + prev = it2->first; + Debug("uf-ss-cliques") << prev; } + Debug("uf-ss-cliques") << std::endl; } - prev = it2->first; - Debug("uf-ss-cliques") << prev; + } + Debug("uf-ss-cliques") << "Explanation of clique (size=" << conflict.size() << ") = " << std::endl; + for( int i=0; i<(int)conflict.size(); i++ ){ + Debug("uf-ss-cliques") << conflict[i] << " "; } Debug("uf-ss-cliques") << std::endl; } - } - Debug("uf-ss-cliques") << "Explanation of clique (size=" << conflict.size() << ") = " << std::endl; - for( int i=0; i<(int)conflict.size(); i++ ){ - Debug("uf-ss-cliques") << conflict[i] << " "; - //bool value; - //bool hasValue = d_th->getValuation().hasSatValue( conflict[i], value ); - //Assert( hasValue ); - //Assert( value ); - } - Debug("uf-ss-cliques") << std::endl; - //now, make the conflict -#if 1 - conflict.push_back( d_cardinality_literal[ d_cardinality ] ); - Node conflictNode = NodeManager::currentNM()->mkNode( AND, conflict ); - Trace("uf-ss-lemma") << "*** Add clique conflict " << conflictNode << std::endl; - //Notice() << "*** Add clique conflict " << conflictNode << std::endl; - out->conflict( conflictNode ); - d_conflict = true; -#else - Node conflictNode = conflict.size()==1 ? conflict[0] : NodeManager::currentNM()->mkNode( AND, conflict ); - //add cardinality constraint - Node cardNode = d_cardinality_literal[ d_cardinality ]; - //bool value; - //bool hasValue = d_th->getValuation().hasSatValue( cardNode, value ); - //Assert( hasValue ); - //Assert( value ); - conflictNode = NodeManager::currentNM()->mkNode( IMPLIES, conflictNode, cardNode.notNode() ); - Trace("uf-ss-lemma") << "*** Add clique conflict " << conflictNode << std::endl; - //Notice() << "*** Add clique conflict " << conflictNode << std::endl; - out->lemma( conflictNode ); -#endif - ++( d_th->getStrongSolver()->d_statistics.d_clique_lemmas ); + //now, make the conflict + if( isSatConflict ){ + conflict.push_back( d_cardinality_literal[ d_cardinality ] ); + Node conflictNode = NodeManager::currentNM()->mkNode( AND, conflict ); + Trace("uf-ss-lemma") << "*** Add clique conflict " << conflictNode << std::endl; + //Notice() << "*** Add clique conflict " << conflictNode << std::endl; + out->conflict( conflictNode ); + d_conflict = true; + ++( d_thss->d_statistics.d_clique_conflicts ); + }else{ + Node conflictNode = conflict.size()==1 ? conflict[0] : NodeManager::currentNM()->mkNode( AND, conflict ); + //add cardinality constraint + Node cardNode = d_cardinality_literal[ d_cardinality ]; + //bool value; + //bool hasValue = d_th->getValuation().hasSatValue( cardNode, value ); + //Assert( hasValue ); + //Assert( value ); + conflictNode = NodeManager::currentNM()->mkNode( IMPLIES, conflictNode, cardNode.notNode() ); + Trace("uf-ss-lemma") << "*** Add clique lemma " << conflictNode << std::endl; + out->lemma( conflictNode ); + ++( d_thss->d_statistics.d_clique_lemmas ); + } - //DO_THIS: ensure that the same clique is not reported??? Check standard effort after assertDisequal can produce same clique. + //DO_THIS: ensure that the same clique is not reported??? Check standard effort after assertDisequal can produce same clique. + } } -void StrongSolverTheoryUf::SortRepModel::addTotalityAxiom( Node n, int cardinality, OutputChannel* out ){ +void StrongSolverTheoryUF::SortModel::addTotalityAxiom( Node n, int cardinality, OutputChannel* out ){ Node cardLit = d_cardinality_literal[ cardinality ]; std::vector< Node > eqs; for( int i=0; i<cardinality; i++ ){ @@ -1141,25 +1226,25 @@ void StrongSolverTheoryUf::SortRepModel::addTotalityAxiom( Node n, int cardinali Node lem = NodeManager::currentNM()->mkNode( IMPLIES, cardLit, ax ); Trace("uf-ss-lemma") << "*** Add totality axiom " << lem << std::endl; //send as lemma to the output channel - d_th->getOutputChannel().lemma( lem ); - ++( d_th->getStrongSolver()->d_statistics.d_totality_lemmas ); + d_thss->getOutputChannel().lemma( lem ); + ++( d_thss->d_statistics.d_totality_lemmas ); } /** apply totality */ -bool StrongSolverTheoryUf::SortRepModel::applyTotality( int cardinality ){ +bool StrongSolverTheoryUF::SortModel::applyTotality( int cardinality ){ return options::ufssTotality() || cardinality<=options::ufssTotalityLimited(); // || ( options::ufssModelInference() && !d_totality_terms[cardinality].empty() ); } /** get totality lemma terms */ -Node StrongSolverTheoryUf::SortRepModel::getTotalityLemmaTerm( int cardinality, int i ){ +Node StrongSolverTheoryUF::SortModel::getTotalityLemmaTerm( int cardinality, int i ){ return d_totality_terms[0][i]; //}else{ // return d_totality_terms[cardinality][i]; //} } -void StrongSolverTheoryUf::SortRepModel::debugPrint( const char* c ){ +void StrongSolverTheoryUF::SortModel::debugPrint( const char* c ){ Debug( c ) << "-- Conflict Find:" << std::endl; Debug( c ) << "Number of reps = " << d_reps << std::endl; Debug( c ) << "Cardinality req = " << d_cardinality << std::endl; @@ -1184,7 +1269,7 @@ void StrongSolverTheoryUf::SortRepModel::debugPrint( const char* c ){ } } -void StrongSolverTheoryUf::SortRepModel::debugModel( TheoryModel* m ){ +void StrongSolverTheoryUF::SortModel::debugModel( TheoryModel* m ){ if( Trace.isOn("uf-ss-warn") ){ std::vector< Node > eqcs; eq::EqClassesIterator eqcs_i = eq::EqClassesIterator( &m->d_equalityEngine ); @@ -1211,7 +1296,7 @@ void StrongSolverTheoryUf::SortRepModel::debugModel( TheoryModel* m ){ } } -int StrongSolverTheoryUf::SortRepModel::getNumRegions(){ +int StrongSolverTheoryUF::SortModel::getNumRegions(){ int count = 0; for( int i=0; i<(int)d_regions_index; i++ ){ if( d_regions[i]->d_valid ){ @@ -1221,8 +1306,8 @@ int StrongSolverTheoryUf::SortRepModel::getNumRegions(){ return count; } -void StrongSolverTheoryUf::SortRepModel::getRepresentatives( std::vector< Node >& reps ){ - if( !options::ufssColoringSat() ){ +void StrongSolverTheoryUF::SortModel::getRepresentatives( std::vector< Node >& reps ){ + //if( !options::ufssColoringSat() ){ bool foundRegion = false; for( int i=0; i<(int)d_regions_index; i++ ){ //should not have multiple regions at this point @@ -1235,126 +1320,12 @@ void StrongSolverTheoryUf::SortRepModel::getRepresentatives( std::vector< Node > foundRegion = true; } } - }else{ - Unimplemented("Build representatives for fmf region sat is not implemented"); - } -} - - -/** initialize */ -void StrongSolverTheoryUf::InfRepModel::initialize( OutputChannel* out ){ - -} - -/** new node */ -void StrongSolverTheoryUf::InfRepModel::newEqClass( Node n ){ - d_rep[n] = n; - //d_const_rep[n] = n.getMetaKind()==metakind::CONSTANT; -} - -/** merge */ -void StrongSolverTheoryUf::InfRepModel::merge( Node a, Node b ){ - //d_rep[b] = false; - //d_const_rep[a] = d_const_rep[a] || d_const_rep[b]; - Node repb = d_rep[b]; - Assert( !repb.isNull() ); - if( repb.getMetaKind()==metakind::CONSTANT || isBadRepresentative( d_rep[a] ) ){ - d_rep[a] = repb; - } - d_rep[b] = Node::null(); -} - -/** check */ -void StrongSolverTheoryUf::InfRepModel::check( Theory::Effort level, OutputChannel* out ){ - -} - -/** minimize */ -bool StrongSolverTheoryUf::InfRepModel::minimize( OutputChannel* out ){ -#if 0 - bool retVal = true; -#else - bool retVal = !addSplit( out ); -#endif - if( retVal ){ - std::vector< Node > reps; - getRepresentatives( reps ); - Trace("uf-ss-fmf") << "Num representatives of type " << d_type << " : " << reps.size() << std::endl; - /* - for( int i=0; i<(int)reps.size(); i++ ){ - std::cout << reps[i] << " "; - } - std::cout << std::endl; - for( int i=0; i<(int)reps.size(); i++ ){ - std::cout << reps[i].getMetaKind() << " "; - } - std::cout << std::endl; - for( NodeNodeMap::iterator it = d_rep.begin(); it != d_rep.end(); ++it ){ - Node rep = (*it).second; - if( !rep.isNull() && !isBadRepresentative( rep ) ){ - for( NodeNodeMap::iterator it2 = d_rep.begin(); it2 != d_rep.end(); ++it2 ){ - Node rep2 = (*it2).second; - if( !rep2.isNull() && !isBadRepresentative( rep2 ) ){ - if( d_th->getQuantifiersEngine()->getEqualityQuery()->areDisequal( rep, rep2 ) ){ - std::cout << "1 "; - }else{ - std::cout << "0 "; - } - } - } - //std::cout << " : " << rep; - std::cout << std::endl; - } - } - */ - } - return retVal; -} - -/** get representatives */ -void StrongSolverTheoryUf::InfRepModel::getRepresentatives( std::vector< Node >& reps ){ - for( NodeNodeMap::iterator it = d_rep.begin(); it != d_rep.end(); ++it ){ - if( !(*it).second.isNull() ){ - reps.push_back( (*it).first ); - } - } -} - - -/** add split function */ -bool StrongSolverTheoryUf::InfRepModel::addSplit( OutputChannel* out ){ - std::vector< Node > visited; - for( NodeNodeMap::iterator it = d_rep.begin(); it != d_rep.end(); ++it ){ - Node rep = (*it).second; - if( !rep.isNull() && !isBadRepresentative( rep ) ){ - bool constRep = rep.getMetaKind()==metakind::CONSTANT; - for( size_t i=0; i<visited.size(); i++ ){ - if( !constRep || !visited[i].getMetaKind()==metakind::CONSTANT ){ - if( !d_th->getQuantifiersEngine()->getEqualityQuery()->areDisequal( rep, visited[i] ) ){ - //split on these nodes - Node eq = rep.eqNode( visited[i] ); - Trace("uf-ss-lemma") << "*** Split on " << eq << std::endl; - eq = Rewriter::rewrite( eq ); - Debug("uf-ss-lemma-debug") << "Rewritten " << eq << std::endl; - out->split( eq ); - //explore the equals branch first - out->requirePhase( eq, true ); - ++( d_th->getStrongSolver()->d_statistics.d_split_lemmas ); - return true; - } - } - } - visited.push_back( rep ); - } - } - return false; -} - -bool StrongSolverTheoryUf::InfRepModel::isBadRepresentative( Node n ){ - return n.getKind()==kind::PLUS; + //}else{ + // Unimplemented("Build representatives for fmf region sat is not implemented"); + //} } -StrongSolverTheoryUf::StrongSolverTheoryUf(context::Context* c, context::UserContext* u, OutputChannel& out, TheoryUF* th) : +StrongSolverTheoryUF::StrongSolverTheoryUF(context::Context* c, context::UserContext* u, OutputChannel& out, TheoryUF* th) : d_out( &out ), d_th( th ), d_conflict( c, false ), @@ -1367,78 +1338,129 @@ d_rep_model_init( c ) }else{ d_term_amb = NULL; } + if( options::ufssDiseqPropagation() ){ + d_deq_prop = new DisequalityPropagator( th->getQuantifiersEngine(), this ); + }else{ + d_deq_prop = NULL; + } +} + +/** get default sat context */ +context::Context* StrongSolverTheoryUF::getSatContext() { + return d_th->getSatContext(); +} + +/** get default output channel */ +OutputChannel& StrongSolverTheoryUF::getOutputChannel() { + return d_th->getOutputChannel(); } /** new node */ -void StrongSolverTheoryUf::newEqClass( Node n ){ - RepModel* c = getRepModel( n ); +void StrongSolverTheoryUF::newEqClass( Node n ){ + SortModel* c = getSortModel( n ); if( c ){ - Trace("uf-ss-solver") << "StrongSolverTheoryUf: New eq class " << n << " : " << n.getType() << std::endl; + Trace("uf-ss-solver") << "StrongSolverTheoryUF: New eq class " << n << " : " << n.getType() << std::endl; c->newEqClass( n ); } } /** merge */ -void StrongSolverTheoryUf::merge( Node a, Node b ){ - RepModel* c = getRepModel( a ); +void StrongSolverTheoryUF::merge( Node a, Node b ){ + SortModel* c = getSortModel( a ); if( c ){ - Trace("uf-ss-solver") << "StrongSolverTheoryUf: Merge " << a << " " << b << " : " << a.getType() << std::endl; + Trace("uf-ss-solver") << "StrongSolverTheoryUF: Merge " << a << " " << b << " : " << a.getType() << std::endl; c->merge( a, b ); + }else{ + if( options::ufssDiseqPropagation() ){ + d_deq_prop->merge(a, b); + } } } /** assert terms are disequal */ -void StrongSolverTheoryUf::assertDisequal( Node a, Node b, Node reason ){ - RepModel* c = getRepModel( a ); +void StrongSolverTheoryUF::assertDisequal( Node a, Node b, Node reason ){ + SortModel* c = getSortModel( a ); if( c ){ - Trace("uf-ss-solver") << "StrongSolverTheoryUf: Assert disequal " << a << " " << b << " : " << a.getType() << std::endl; + Trace("uf-ss-solver") << "StrongSolverTheoryUF: Assert disequal " << a << " " << b << " : " << a.getType() << std::endl; //Assert( d_th->d_equalityEngine.getRepresentative( a )==a ); //Assert( d_th->d_equalityEngine.getRepresentative( b )==b ); c->assertDisequal( a, b, reason ); + }else{ + if( options::ufssDiseqPropagation() ){ + d_deq_prop->assertDisequal(a, b, reason); + } } } /** assert a node */ -void StrongSolverTheoryUf::assertNode( Node n, bool isDecision ){ +void StrongSolverTheoryUF::assertNode( Node n, bool isDecision ){ Trace("uf-ss") << "Assert " << n << " " << isDecision << std::endl; - if( n.getKind()==CARDINALITY_CONSTRAINT ){ - TypeNode tn = n[0].getType(); + bool polarity = n.getKind() != kind::NOT; + TNode lit = polarity ? n : n[0]; + if( lit.getKind()==CARDINALITY_CONSTRAINT ){ + TypeNode tn = lit[0].getType(); Assert( tn.isSort() ); Assert( d_rep_model[tn] ); - long nCard = n[1].getConst<Rational>().getNumerator().getLong(); - d_rep_model[tn]->assertCardinality( d_out, nCard, true ); - }else if( n.getKind()==NOT && n[0].getKind()==CARDINALITY_CONSTRAINT ){ - Node nn = n[0]; - TypeNode tn = nn[0].getType(); - Assert( tn.isSort() ); - Assert( d_rep_model[tn] ); - long nCard = nn[1].getConst<Rational>().getNumerator().getLong(); - d_rep_model[tn]->assertCardinality( d_out, nCard, false ); + long nCard = lit[1].getConst<Rational>().getNumerator().getLong(); + d_rep_model[tn]->assertCardinality( d_out, nCard, polarity ); }else{ - ////FIXME: this is too strict: theory propagations are showing up as isDecision=true, but - //// a theory propagation is not a decision. - if( isDecision ){ - for( std::map< TypeNode, RepModel* >::iterator it = d_rep_model.begin(); it != d_rep_model.end(); ++it ){ - if( !it->second->hasCardinalityAsserted() ){ - Trace("uf-ss-warn") << "WARNING: Assert " << n << " as a decision before cardinality for " << it->first << "." << std::endl; - //Message() << "Error: constraint asserted before cardinality for " << it->first << std::endl; - //Unimplemented(); + if( Trace.isOn("uf-ss-warn") ){ + ////FIXME: this is too strict: theory propagations are showing up as isDecision=true, but + //// a theory propagation is not a decision. + if( isDecision ){ + for( std::map< TypeNode, SortModel* >::iterator it = d_rep_model.begin(); it != d_rep_model.end(); ++it ){ + if( !it->second->hasCardinalityAsserted() ){ + Trace("uf-ss-warn") << "WARNING: Assert " << n << " as a decision before cardinality for " << it->first << "." << std::endl; + //Message() << "Error: constraint asserted before cardinality for " << it->first << std::endl; + //Unimplemented(); + } } } } + if( lit.getKind()!=EQUAL ){ + //it is a predicate + if( options::ufssDiseqPropagation() ){ + d_deq_prop->assertPredicate(lit, polarity); + } + } } Trace("uf-ss") << "Assert: done " << n << " " << isDecision << std::endl; } +bool StrongSolverTheoryUF::areDisequal( Node a, Node b ) { + if( a==b ){ + return false; + }else{ + a = d_th->d_equalityEngine.getRepresentative( a ); + b = d_th->d_equalityEngine.getRepresentative( b ); + if( d_th->d_equalityEngine.areDisequal( a, b, false ) ){ + return true; + }else{ + SortModel* c = getSortModel( a ); + if( c ){ + return c->areDisequal( a, b ); + }else{ + return false; + } + } + } +} /** check */ -void StrongSolverTheoryUf::check( Theory::Effort level ){ +void StrongSolverTheoryUF::check( Theory::Effort level ){ if( !d_conflict ){ - Trace("uf-ss-solver") << "StrongSolverTheoryUf: check " << level << std::endl; + Trace("uf-ss-solver") << "StrongSolverTheoryUF: check " << level << std::endl; if( level==Theory::EFFORT_FULL ){ debugPrint( "uf-ss-debug" ); } - for( std::map< TypeNode, RepModel* >::iterator it = d_rep_model.begin(); it != d_rep_model.end(); ++it ){ + if( !d_conflict && level==Theory::EFFORT_FULL && options::ufssColoringSat() ){ + int lemmas = d_term_amb->disambiguateTerms( d_out ); + d_statistics.d_disamb_term_lemmas += lemmas; + if( lemmas>=0 ){ + return; + } + } + for( std::map< TypeNode, SortModel* >::iterator it = d_rep_model.begin(); it != d_rep_model.end(); ++it ){ it->second->check( level, d_out ); if( it->second->isConflict() ){ d_conflict = true; @@ -1446,24 +1468,24 @@ void StrongSolverTheoryUf::check( Theory::Effort level ){ } } //disambiguate terms if necessary - if( !d_conflict && level==Theory::EFFORT_FULL && options::ufssColoringSat() ){ - Assert( d_term_amb!=NULL ); - d_statistics.d_disamb_term_lemmas += d_term_amb->disambiguateTerms( d_out ); - } - Trace("uf-ss-solver") << "Done StrongSolverTheoryUf: check " << level << std::endl; + //if( !d_conflict && level==Theory::EFFORT_FULL && options::ufssColoringSat() ){ + // Assert( d_term_amb!=NULL ); + // d_statistics.d_disamb_term_lemmas += d_term_amb->disambiguateTerms( d_out ); + //} + Trace("uf-ss-solver") << "Done StrongSolverTheoryUF: check " << level << std::endl; } } /** propagate */ -void StrongSolverTheoryUf::propagate( Theory::Effort level ){ - //for( std::map< TypeNode, RepModel* >::iterator it = d_rep_model.begin(); it != d_rep_model.end(); ++it ){ +void StrongSolverTheoryUF::propagate( Theory::Effort level ){ + //for( std::map< TypeNode, SortModel* >::iterator it = d_rep_model.begin(); it != d_rep_model.end(); ++it ){ // it->second->propagate( level, d_out ); //} } /** get next decision request */ -Node StrongSolverTheoryUf::getNextDecisionRequest(){ - for( std::map< TypeNode, RepModel* >::iterator it = d_rep_model.begin(); it != d_rep_model.end(); ++it ){ +Node StrongSolverTheoryUF::getNextDecisionRequest(){ + for( std::map< TypeNode, SortModel* >::iterator it = d_rep_model.begin(); it != d_rep_model.end(); ++it ){ Node n = it->second->getNextDecisionRequest(); if( !n.isNull() ){ return n; @@ -1472,18 +1494,15 @@ Node StrongSolverTheoryUf::getNextDecisionRequest(){ return Node::null(); } -void StrongSolverTheoryUf::preRegisterTerm( TNode n ){ +void StrongSolverTheoryUF::preRegisterTerm( TNode n ){ Trace("uf-ss-register") << "Preregister " << n << "." << std::endl; //shouldn't have to preregister this type (it may be that there are no quantifiers over tn) TypeNode tn = n.getType(); if( d_rep_model.find( tn )==d_rep_model.end() ){ - RepModel* rm = NULL; + SortModel* rm = NULL; if( tn.isSort() ){ Trace("uf-ss-register") << "Preregister sort " << tn << "." << std::endl; - rm = new SortRepModel( n, d_th->getSatContext(), d_th ); - }else if( tn.isInteger() ){ - //rm = new InfRepModel( tn, d_th->getSatContext(), d_th ); - //rm = new SortRepModel( tn, d_th->getSatContext(), d_th ); + rm = new SortModel( n, d_th->getSatContext(), this ); }else{ /* if( tn==NodeManager::currentNM()->integerType() || tn==NodeManager::currentNM()->realType() ){ @@ -1509,7 +1528,7 @@ void StrongSolverTheoryUf::preRegisterTerm( TNode n ){ } } -void StrongSolverTheoryUf::registerQuantifier( Node f ){ +void StrongSolverTheoryUF::registerQuantifier( Node f ){ Debug("uf-ss-register") << "Register quantifier " << f << std::endl; //must ensure the quantifier does not quantify over arithmetic //for( int i=0; i<(int)f[0].getNumChildren(); i++ ){ @@ -1519,9 +1538,9 @@ void StrongSolverTheoryUf::registerQuantifier( Node f ){ } -StrongSolverTheoryUf::RepModel* StrongSolverTheoryUf::getRepModel( Node n ){ +StrongSolverTheoryUF::SortModel* StrongSolverTheoryUF::getSortModel( Node n ){ TypeNode tn = n.getType(); - std::map< TypeNode, RepModel* >::iterator it = d_rep_model.find( tn ); + std::map< TypeNode, SortModel* >::iterator it = d_rep_model.find( tn ); //pre-register the type if not done already if( it==d_rep_model.end() ){ preRegisterTerm( n ); @@ -1539,13 +1558,13 @@ StrongSolverTheoryUf::RepModel* StrongSolverTheoryUf::getRepModel( Node n ){ return NULL; } -void StrongSolverTheoryUf::notifyRestart(){ +void StrongSolverTheoryUF::notifyRestart(){ } /** get cardinality for sort */ -int StrongSolverTheoryUf::getCardinality( Node n ) { - RepModel* c = getRepModel( n ); +int StrongSolverTheoryUF::getCardinality( Node n ) { + SortModel* c = getSortModel( n ); if( c ){ return c->getCardinality(); }else{ @@ -1553,27 +1572,27 @@ int StrongSolverTheoryUf::getCardinality( Node n ) { } } -void StrongSolverTheoryUf::getRepresentatives( Node n, std::vector< Node >& reps ){ - RepModel* c = getRepModel( n ); +void StrongSolverTheoryUF::getRepresentatives( Node n, std::vector< Node >& reps ){ + SortModel* c = getSortModel( n ); if( c ){ c->getRepresentatives( reps ); } } -bool StrongSolverTheoryUf::minimize( TheoryModel* m ){ - for( std::map< TypeNode, RepModel* >::iterator it = d_rep_model.begin(); it != d_rep_model.end(); ++it ){ +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 ) ){ return false; } } - for( std::map< TypeNode, RepModel* >::iterator it = d_rep_model.begin(); it != d_rep_model.end(); ++it ){ + for( std::map< TypeNode, SortModel* >::iterator it = d_rep_model.begin(); it != d_rep_model.end(); ++it ){ Trace("uf-ss-minimize") << "Cardinality( " << it->first << " ) : " << it->second->getCardinality() << std::endl; } return true; } //print debug -void StrongSolverTheoryUf::debugPrint( const char* c ){ +void StrongSolverTheoryUF::debugPrint( const char* c ){ //EqClassesIterator< TheoryUF::NotifyClass > eqc_iter( &((TheoryUF*)d_th)->d_equalityEngine ); //while( !eqc_iter.isFinished() ){ // Debug( c ) << "Eq class [[" << (*eqc_iter) << "]]" << std::endl; @@ -1587,28 +1606,30 @@ void StrongSolverTheoryUf::debugPrint( const char* c ){ // eqc_iter++; //} - for( std::map< TypeNode, RepModel* >::iterator it = d_rep_model.begin(); it != d_rep_model.end(); ++it ){ + for( std::map< TypeNode, SortModel* >::iterator it = d_rep_model.begin(); it != d_rep_model.end(); ++it ){ Debug( c ) << "Conflict find structure for " << it->first << ": " << std::endl; it->second->debugPrint( c ); Debug( c ) << std::endl; } } -void StrongSolverTheoryUf::debugModel( TheoryModel* m ){ +void StrongSolverTheoryUF::debugModel( TheoryModel* m ){ if( Trace.isOn("uf-ss-warn") ){ - for( std::map< TypeNode, RepModel* >::iterator it = d_rep_model.begin(); it != d_rep_model.end(); ++it ){ + for( std::map< TypeNode, SortModel* >::iterator it = d_rep_model.begin(); it != d_rep_model.end(); ++it ){ it->second->debugModel( m ); } } } -StrongSolverTheoryUf::Statistics::Statistics(): - d_clique_lemmas("StrongSolverTheoryUf::Clique_Lemmas", 0), - d_split_lemmas("StrongSolverTheoryUf::Split_Lemmas", 0), - d_disamb_term_lemmas("StrongSolverTheoryUf::Disambiguate_Term_Lemmas", 0), - d_totality_lemmas("StrongSolverTheoryUf::Totality_Lemmas", 0), - d_max_model_size("StrongSolverTheoryUf::Max_Model_Size", 1) +StrongSolverTheoryUF::Statistics::Statistics(): + d_clique_conflicts("StrongSolverTheoryUF::Clique_Conflicts", 0), + d_clique_lemmas("StrongSolverTheoryUF::Clique_Lemmas", 0), + d_split_lemmas("StrongSolverTheoryUF::Split_Lemmas", 0), + d_disamb_term_lemmas("StrongSolverTheoryUF::Disambiguate_Term_Lemmas", 0), + d_totality_lemmas("StrongSolverTheoryUF::Totality_Lemmas", 0), + d_max_model_size("StrongSolverTheoryUF::Max_Model_Size", 1) { + StatisticsRegistry::registerStat(&d_clique_conflicts); StatisticsRegistry::registerStat(&d_clique_lemmas); StatisticsRegistry::registerStat(&d_split_lemmas); StatisticsRegistry::registerStat(&d_disamb_term_lemmas); @@ -1616,7 +1637,8 @@ StrongSolverTheoryUf::Statistics::Statistics(): StatisticsRegistry::registerStat(&d_max_model_size); } -StrongSolverTheoryUf::Statistics::~Statistics(){ +StrongSolverTheoryUF::Statistics::~Statistics(){ + StatisticsRegistry::unregisterStat(&d_clique_conflicts); StatisticsRegistry::unregisterStat(&d_clique_lemmas); StatisticsRegistry::unregisterStat(&d_split_lemmas); StatisticsRegistry::unregisterStat(&d_disamb_term_lemmas); @@ -1667,11 +1689,12 @@ int TermDisambiguator::disambiguateTerms( OutputChannel* out ){ } Assert( children.size()>1 ); Node lem = NodeManager::currentNM()->mkNode( OR, children ); - Debug( "uf-ss-lemma" ) << "*** Disambiguate lemma : " << lem << std::endl; + Trace( "uf-ss-lemma" ) << "*** Disambiguate lemma : " << lem << std::endl; //Notice() << "*** Disambiguate lemma : " << lem << std::endl; out->lemma( lem ); d_term_amb[ eq ] = false; lemmaAdded++; + return lemmaAdded; } } } @@ -1693,3 +1716,73 @@ bool TermDisambiguator::involvesRelevantType( Node n ){ } return false; } + +DisequalityPropagator::DisequalityPropagator(QuantifiersEngine* qe, StrongSolverTheoryUF* ufss) : + d_qe(qe), d_ufss(ufss){ + d_true = NodeManager::currentNM()->mkConst( true ); + d_false = NodeManager::currentNM()->mkConst( false ); +} + +void DisequalityPropagator::checkEquivalenceClass( Node t, Node eqc ) { + if( t.getKind()==APPLY_UF ){ + Node op = t.getOperator(); + eqc = d_ufss->getTheory()->getEqualityEngine()->getRepresentative( eqc ); + eq::EqClassIterator eqc_i(eqc, d_ufss->getTheory()->getEqualityEngine()); + while( !eqc_i.isFinished() ){ + Node s = *eqc_i; + if( s.getKind()==APPLY_UF && s.getOperator()==op ){ + int unkIndex = -1; + for( size_t i=0; i<t.getNumChildren(); i++ ){ + //should consult strong solver since it knows more disequalities + if( d_ufss->areDisequal( t[i], s[i] ) ){ + //if( d_qe->getEqualityQuery()->areDisequal( t[i], s[i] ) ){ + unkIndex = -1; + break; + }else if( !d_qe->getEqualityQuery()->areEqual( t[i], s[i] ) ){ + if( unkIndex==-1 ){ + unkIndex = i; + }else{ + unkIndex = -1; + break; + } + } + } + if( unkIndex!=-1 ){ + Trace("deq-prop") << "propagate disequality " << t[unkIndex] << " " << s[unkIndex] << std::endl; + d_ufss->assertDisequal(t[unkIndex], s[unkIndex], Node::null()); + ++( d_statistics.d_propagations ); + if( d_ufss->isConflict() ){ + return; + } + } + } + ++eqc_i; + } + } +} + +/** merge */ +void DisequalityPropagator::merge( Node a, Node b ){ + +} + +/** assert terms are disequal */ +void DisequalityPropagator::assertDisequal( Node a, Node b, Node reason ){ + Trace("deq-prop") << "Notify disequal : " << a << " " << b << std::endl; +} + + +void DisequalityPropagator::assertPredicate( Node p, bool polarity ) { + Trace("deq-prop") << "Assert predicate : " << p << " " << polarity << std::endl; + checkEquivalenceClass( p, polarity ? d_false : d_true ); +} + +DisequalityPropagator::Statistics::Statistics(): + d_propagations("StrongSolverTheoryUF::Disequality_Propagations", 0) +{ + StatisticsRegistry::registerStat(& d_propagations); +} + +DisequalityPropagator::Statistics::~Statistics(){ + StatisticsRegistry::unregisterStat(& d_propagations); +}
\ No newline at end of file diff --git a/src/theory/uf/theory_uf_strong_solver.h b/src/theory/uf/theory_uf_strong_solver.h index febae2eae..33493248d 100644 --- a/src/theory/uf/theory_uf_strong_solver.h +++ b/src/theory/uf/theory_uf_strong_solver.h @@ -31,8 +31,9 @@ namespace uf { class TheoryUF; class TermDisambiguator; +class DisequalityPropagator; -class StrongSolverTheoryUf{ +class StrongSolverTheoryUF{ protected: typedef context::CDHashMap<Node, bool, NodeHashFunction> NodeBoolMap; typedef context::CDHashMap<Node, int, NodeHashFunction> NodeIntMap; @@ -42,51 +43,14 @@ protected: typedef context::CDList<bool> IntList; typedef context::CDHashMap<TypeNode, bool, TypeNodeHashFunction> TypeNodeBoolMap; public: - class RepModel { - protected: - /** type */ - TypeNode d_type; - public: - RepModel( TypeNode tn ) : d_type( tn ){} - virtual ~RepModel(){} - /** initialize */ - virtual void initialize( OutputChannel* out ) = 0; - /** new node */ - virtual void newEqClass( Node n ) = 0; - /** merge */ - virtual void merge( Node a, Node b ) = 0; - /** assert terms are disequal */ - virtual void assertDisequal( Node a, Node b, Node reason ) = 0; - /** check */ - virtual void check( Theory::Effort level, OutputChannel* out ){} - /** get next decision request */ - virtual Node getNextDecisionRequest() { return Node::null(); } - /** minimize */ - virtual bool minimize( OutputChannel* out, TheoryModel* m ){ return true; } - /** assert cardinality */ - virtual void assertCardinality( OutputChannel* out, int c, bool val ){} - /** is in conflict */ - virtual bool isConflict() { return false; } - /** get cardinality */ - virtual int getCardinality() { return -1; } - /** has cardinality */ - virtual bool hasCardinalityAsserted() { return true; } - /** get representatives */ - virtual void getRepresentatives( std::vector< Node >& reps ){} - /** print debug */ - virtual void debugPrint( const char* c ){} - /** debug a model */ - virtual void debugModel( TheoryModel* m ){} - }; -public: /** information for incremental conflict/clique finding for a particular sort */ - class SortRepModel : public RepModel { + class SortModel { public: /** a partition of the current equality graph for which cliques can occur internally */ class Region { public: /** conflict find pointer */ - SortRepModel* d_cf; + SortModel* d_cf; /** information stored about each node in region */ class RegionNodeInfo { public: @@ -142,7 +106,7 @@ public: void setRep( Node n, bool valid ); public: //constructor - Region( SortRepModel* cf, context::Context* c ) : d_cf( cf ), d_testCliqueSize( c, 0 ), + Region( SortModel* cf, context::Context* c ) : d_cf( cf ), d_testCliqueSize( c, 0 ), d_splitsSize( c, 0 ), d_testClique( c ), d_splits( c ), d_reps_size( c, 0 ), d_total_diseq_external( c, 0 ), d_total_diseq_internal( c, 0 ), d_valid( c, true ) { } @@ -186,8 +150,10 @@ public: void debugPrint( const char* c, bool incClique = false ); }; private: - /** theory uf pointer */ - TheoryUF* d_th; + /** the type this model is for */ + TypeNode d_type; + /** strong solver pointer */ + StrongSolverTheoryUF* d_thss; /** regions used to d_region_index */ context::CDO< unsigned > d_regions_index; /** vector of regions */ @@ -213,7 +179,7 @@ public: void setSplitScore( Node n, int s ); private: /** check if we need to combine region ri */ - void checkRegion( int ri, bool rec = true ); + void checkRegion( int ri, bool checkCombine = true ); /** force combine region */ int forceCombineRegion( int ri, bool useDensity = true ); /** merge regions */ @@ -256,8 +222,8 @@ public: /** get totality lemma terms */ Node getTotalityLemmaTerm( int cardinality, int i ); public: - SortRepModel( Node n, context::Context* c, TheoryUF* th ); - virtual ~SortRepModel(){} + SortModel( Node n, context::Context* c, StrongSolverTheoryUF* thss ); + virtual ~SortModel(){} /** initialize */ void initialize( OutputChannel* out ); /** new node */ @@ -266,6 +232,8 @@ public: void merge( Node a, Node b ); /** assert terms are disequal */ void assertDisequal( Node a, Node b, Node reason ); + /** are disequal */ + bool areDisequal( Node a, Node b ); /** check */ void check( Theory::Effort level, OutputChannel* out ); /** propagate */ @@ -291,43 +259,7 @@ public: public: /** get number of regions (for debugging) */ int getNumRegions(); - }; /** class SortRepModel */ -private: - /** infinite rep model */ - class InfRepModel : public RepModel - { - protected: - /** theory uf pointer */ - TheoryUF* d_th; - /** list of representatives */ - NodeNodeMap d_rep; - /** whether representatives are constant */ - NodeBoolMap d_const_rep; - /** add split */ - bool addSplit( OutputChannel* out ); - /** is bad representative */ - bool isBadRepresentative( Node n ); - public: - InfRepModel( TypeNode tn, context::Context* c, TheoryUF* th ) : RepModel( tn ), - d_th( th ), d_rep( c ), d_const_rep( c ){} - virtual ~InfRepModel(){} - /** initialize */ - void initialize( OutputChannel* out ); - /** new node */ - void newEqClass( Node n ); - /** merge */ - void merge( Node a, Node b ); - /** assert terms are disequal */ - void assertDisequal( Node a, Node b, Node reason ){} - /** check */ - void check( Theory::Effort level, OutputChannel* out ); - /** minimize */ - bool minimize( OutputChannel* out ); - /** get representatives */ - void getRepresentatives( std::vector< Node >& reps ); - /** print debug */ - void debugPrint( const char* c ){} - }; + }; /** class SortModel */ private: /** The output channel for the strong solver. */ OutputChannel* d_out; @@ -336,19 +268,31 @@ private: /** Are we in conflict */ context::CDO<bool> d_conflict; /** rep model structure, one for each type */ - std::map< TypeNode, RepModel* > d_rep_model; + std::map< TypeNode, SortModel* > d_rep_model; /** all types */ std::vector< TypeNode > d_conf_types; /** whether conflict find data structures have been initialized */ TypeNodeBoolMap d_rep_model_init; /** get conflict find */ - RepModel* getRepModel( Node n ); + SortModel* getSortModel( Node n ); private: /** term disambiguator */ TermDisambiguator* d_term_amb; + /** disequality propagator */ + DisequalityPropagator* d_deq_prop; public: - StrongSolverTheoryUf(context::Context* c, context::UserContext* u, OutputChannel& out, TheoryUF* th); - ~StrongSolverTheoryUf() {} + StrongSolverTheoryUF(context::Context* c, context::UserContext* u, OutputChannel& out, TheoryUF* th); + ~StrongSolverTheoryUF() {} + /** get theory */ + TheoryUF* getTheory() { return d_th; } + /** term disambiguator */ + TermDisambiguator* getTermDisambiguator() { return d_term_amb; } + /** disequality propagator */ + DisequalityPropagator* getDisequalityPropagator() { return d_deq_prop; } + /** get default sat context */ + context::Context* getSatContext(); + /** get default output channel */ + OutputChannel& getOutputChannel(); /** new node */ void newEqClass( Node n ); /** merge */ @@ -357,6 +301,8 @@ public: void assertDisequal( Node a, Node b, Node reason ); /** assert node */ void assertNode( Node n, bool isDecision ); + /** are disequal */ + bool areDisequal( Node a, Node b ); public: /** check */ void check( Theory::Effort level ); @@ -372,7 +318,7 @@ public: void notifyRestart(); public: /** identify */ - std::string identify() const { return std::string("StrongSolverTheoryUf"); } + std::string identify() const { return std::string("StrongSolverTheoryUF"); } //print debug void debugPrint( const char* c ); /** debug a model */ @@ -393,6 +339,7 @@ public: class Statistics { public: + IntStat d_clique_conflicts; IntStat d_clique_lemmas; IntStat d_split_lemmas; IntStat d_disamb_term_lemmas; @@ -403,7 +350,7 @@ public: }; /** statistics class */ Statistics d_statistics; -};/* class StrongSolverTheoryUf */ +};/* class StrongSolverTheoryUF */ class TermDisambiguator @@ -422,6 +369,37 @@ public: int disambiguateTerms( OutputChannel* out ); }; +class DisequalityPropagator +{ +private: + /** quantifiers engine */ + QuantifiersEngine* d_qe; + /** strong solver */ + StrongSolverTheoryUF* d_ufss; + /** true,false */ + Node d_true; + Node d_false; + /** check term t against equivalence class that t is disequal from */ + void checkEquivalenceClass( Node t, Node eqc ); +public: + DisequalityPropagator(QuantifiersEngine* qe, StrongSolverTheoryUF* ufss); + /** merge */ + void merge( Node a, Node b ); + /** assert terms are disequal */ + void assertDisequal( Node a, Node b, Node reason ); + /** assert predicate */ + void assertPredicate( Node p, bool polarity ); +public: + class Statistics { + public: + IntStat d_propagations; + Statistics(); + ~Statistics(); + }; + /** statistics class */ + Statistics d_statistics; +}; + } }/* CVC4::theory namespace */ }/* CVC4 namespace */ diff --git a/src/util/configuration.cpp b/src/util/configuration.cpp index 59fe28eca..c6e951049 100644 --- a/src/util/configuration.cpp +++ b/src/util/configuration.cpp @@ -195,6 +195,33 @@ bool Configuration::isTraceTag(char const * tag){ return false; } +bool Configuration::isGitBuild() { + return IS_GIT_BUILD; +} + +const char* Configuration::getGitBranchName() { + return GIT_BRANCH_NAME; +} + +const char* Configuration::getGitCommit() { + return GIT_COMMIT; +} + +bool Configuration::hasGitModifications() { + return GIT_HAS_MODIFICATIONS; +} + +std::string Configuration::getGitId() { + if(! isGitBuild()) { + return ""; + } + + stringstream ss; + ss << "git " << getGitBranchName() << " " << string(getGitCommit()).substr(0, 8) + << ( ::CVC4::Configuration::hasGitModifications() ? " (with modifications)" : "" ); + return ss.str(); +} + bool Configuration::isSubversionBuild() { return IS_SUBVERSION_BUILD; } @@ -211,7 +238,7 @@ bool Configuration::hasSubversionModifications() { return SUBVERSION_HAS_MODIFICATIONS; } -string Configuration::getSubversionId() { +std::string Configuration::getSubversionId() { if(! isSubversionBuild()) { return ""; } diff --git a/src/util/configuration.h b/src/util/configuration.h index 3f6547872..c85f62f7f 100644 --- a/src/util/configuration.h +++ b/src/util/configuration.h @@ -38,6 +38,10 @@ class CVC4_PUBLIC Configuration { static const char* const SUBVERSION_BRANCH_NAME; static const unsigned SUBVERSION_REVISION; static const bool SUBVERSION_HAS_MODIFICATIONS; + static const bool IS_GIT_BUILD; + static const char* const GIT_BRANCH_NAME; + static const char* const GIT_COMMIT; + static const bool GIT_HAS_MODIFICATIONS; public: @@ -101,6 +105,12 @@ public: /* Test if the given argument is a known trace tag name */ static bool isTraceTag(char const *); + static bool isGitBuild(); + static const char* getGitBranchName(); + static const char* getGitCommit(); + static bool hasGitModifications(); + static std::string getGitId(); + static bool isSubversionBuild(); static const char* getSubversionBranchName(); static unsigned getSubversionRevision(); diff --git a/src/util/configuration_private.h b/src/util/configuration_private.h index c480b4318..4378badc8 100644 --- a/src/util/configuration_private.h +++ b/src/util/configuration_private.h @@ -115,13 +115,16 @@ namespace CVC4 { #define CVC4_ABOUT_STRING ( ::std::string("\ This is CVC4 version " CVC4_RELEASE_STRING ) + \ + ( ::CVC4::Configuration::isGitBuild() \ + ? ( ::std::string(" [") + ::CVC4::Configuration::getGitId() + "]" ) \ + : \ ( ::CVC4::Configuration::isSubversionBuild() \ ? ( ::std::string(" [") + ::CVC4::Configuration::getSubversionId() + "]" ) \ : ::std::string("") \ - ) + "\n\ + )) + "\n\ compiled with " + ::CVC4::Configuration::getCompiler() + "\n\ on " + ::CVC4::Configuration::getCompiledDateTime() + "\n\n\ -Copyright (C) 2009, 2010, 2011, 2012\n\ +Copyright (C) 2009, 2010, 2011, 2012, 2013\n\ New York University and The University of Iowa\n\n" + \ ( IS_CLN_BUILD ? "\ This CVC4 library uses CLN as its multi-precision arithmetic library.\n\n\ diff --git a/src/util/integer.h.in b/src/util/integer.h.in index 1f0174083..27b589b5a 100644 --- a/src/util/integer.h.in +++ b/src/util/integer.h.in @@ -1,5 +1,5 @@ /********************* */ -/*! \file integer.h +/*! \file integer.h.in ** \verbatim ** Original author: taking ** Major contributors: none diff --git a/src/util/rational.h.in b/src/util/rational.h.in index c8e42a253..7f5b1feb4 100644 --- a/src/util/rational.h.in +++ b/src/util/rational.h.in @@ -1,5 +1,5 @@ /********************* */ -/*! \file rational.h +/*! \file rational.h.in ** \verbatim ** Original author: taking ** Major contributors: none diff --git a/src/util/sort_inference.cpp b/src/util/sort_inference.cpp index 7e0af3e9f..d700b70d9 100755..100644 --- a/src/util/sort_inference.cpp +++ b/src/util/sort_inference.cpp @@ -1,408 +1,428 @@ -/********************* */
-/*! \file sort_inference.cpp
- ** \verbatim
- ** Original author: ajreynol
- ** Major contributors: none
- ** Minor contributors (to current version): none
- ** This file is part of the CVC4 prototype.
- ** Copyright (c) 2009-2012 New York University and The University of Iowa
- ** See the file COPYING in the top-level source directory for licensing
- ** information.\endverbatim
- **
- ** \brief Sort inference module
- **
- ** This class implements sort inference, based on a simple algorithm:
- ** First, we assume all functions and predicates have distinct uninterpreted types.
- ** One pass is made through the input assertions, while a union-find data structure
- ** maintains necessary information regarding constraints on these types.
- **/
-
-#include <vector>
-
-#include "util/sort_inference.h"
-
-using namespace CVC4;
-using namespace std;
-
-namespace CVC4 {
-
-
-void SortInference::printSort( const char* c, int t ){
- int rt = getRepresentative( t );
- if( d_type_types.find( rt )!=d_type_types.end() ){
- Trace(c) << d_type_types[rt];
- }else{
- Trace(c) << "s_" << rt;
- }
-}
-
-void SortInference::simplify( std::vector< Node >& assertions, bool doRewrite ){
- //process all assertions
- for( unsigned i=0; i<assertions.size(); i++ ){
- Trace("sort-inference-debug") << "Process " << assertions[i] << std::endl;
- std::map< Node, Node > var_bound;
- process( assertions[i], var_bound );
- }
- //print debug
- if( Trace.isOn("sort-inference") ){
- for( std::map< Node, int >::iterator it = d_op_return_types.begin(); it != d_op_return_types.end(); ++it ){
- Trace("sort-inference") << it->first << " : ";
- if( !d_op_arg_types[ it->first ].empty() ){
- Trace("sort-inference") << "( ";
- for( size_t i=0; i<d_op_arg_types[ it->first ].size(); i++ ){
- printSort( "sort-inference", d_op_arg_types[ it->first ][i] );
- Trace("sort-inference") << " ";
- }
- Trace("sort-inference") << ") -> ";
- }
- printSort( "sort-inference", it->second );
- Trace("sort-inference") << std::endl;
- }
- }
- if( doRewrite ){
- //simplify all assertions by introducing new symbols wherever necessary (NOTE: this is unsound for quantifiers)
- for( unsigned i=0; i<assertions.size(); i++ ){
- std::map< Node, Node > var_bound;
- assertions[i] = simplify( assertions[i], var_bound );
- Trace("sort-inference-rewrite") << " --> " << assertions[i] << std::endl;
- }
- //now, ensure constants are distinct
- for( std::map< TypeNode, std::map< Node, Node > >::iterator it = d_const_map.begin(); it != d_const_map.end(); ++it ){
- std::vector< Node > consts;
- for( std::map< Node, Node >::iterator it2 = it->second.begin(); it2 != it->second.end(); ++it2 ){
- consts.push_back( it2->second );
- }
- //add lemma enforcing introduced constants to be distinct?
- }
- }
-}
-
-int SortInference::getRepresentative( int t ){
- std::map< int, int >::iterator it = d_type_union_find.find( t );
- if( it!=d_type_union_find.end() ){
- if( it->second==t ){
- return t;
- }else{
- int rt = getRepresentative( it->second );
- d_type_union_find[t] = rt;
- return rt;
- }
- }else{
- return t;
- }
-}
-
-void SortInference::setEqual( int t1, int t2 ){
- if( t1!=t2 ){
- int rt1 = getRepresentative( t1 );
- int rt2 = getRepresentative( t2 );
- if( rt1!=rt2 ){
- Trace("sort-inference-debug") << "Set equal : ";
- printSort( "sort-inference-debug", rt1 );
- Trace("sort-inference-debug") << " ";
- printSort( "sort-inference-debug", rt2 );
- Trace("sort-inference-debug") << std::endl;
- //check if they must be a type
- std::map< int, TypeNode >::iterator it1 = d_type_types.find( rt1 );
- std::map< int, TypeNode >::iterator it2 = d_type_types.find( rt2 );
- if( it2!=d_type_types.end() ){
- if( it1==d_type_types.end() ){
- //swap sides
- int swap = rt1;
- rt1 = rt2;
- rt2 = swap;
- }else{
- Assert( rt1==rt2 );
- }
- }
- /*
- d_type_eq_class[rt1].insert( d_type_eq_class[rt1].end(), d_type_eq_class[rt2].begin(), d_type_eq_class[rt2].end() );
- d_type_eq_class[rt2].clear();
- Trace("sort-inference-debug") << "EqClass : { ";
- for( int i=0; i<(int)d_type_eq_class[rt1].size(); i++ ){
- Trace("sort-inference-debug") << d_type_eq_class[rt1][i] << ", ";
- }
- Trace("sort-inference-debug") << "}" << std::endl;
- */
- d_type_union_find[rt2] = rt1;
- }
- }
-}
-
-int SortInference::getIdForType( TypeNode tn ){
- //register the return type
- std::map< TypeNode, int >::iterator it = d_id_for_types.find( tn );
- if( it==d_id_for_types.end() ){
- int sc = sortCount;
- d_type_types[ sortCount ] = tn;
- d_id_for_types[ tn ] = sortCount;
- sortCount++;
- return sc;
- }else{
- return it->second;
- }
-}
-
-int SortInference::process( Node n, std::map< Node, Node >& var_bound ){
- Trace("sort-inference-debug") << "Process " << n << std::endl;
- //add to variable bindings
- if( n.getKind()==kind::FORALL || n.getKind()==kind::EXISTS ){
- for( size_t i=0; i<n[0].getNumChildren(); i++ ){
- //TODO: try applying sort inference to quantified variables
- //d_var_types[n][ n[0][i] ] = sortCount;
- //sortCount++;
-
- //type of the quantified variable must be the same
- d_var_types[n][ n[0][i] ] = getIdForType( n[0][i].getType() );
- var_bound[ n[0][i] ] = n;
- }
- }
-
- //process children
- std::vector< Node > children;
- std::vector< int > child_types;
- for( size_t i=0; i<n.getNumChildren(); i++ ){
- bool processChild = true;
- if( n.getKind()==kind::FORALL || n.getKind()==kind::EXISTS ){
- processChild = i==1;
- }
- if( processChild ){
- children.push_back( n[i] );
- child_types.push_back( process( n[i], var_bound ) );
- }
- }
-
- //remove from variable bindings
- if( n.getKind()==kind::FORALL || n.getKind()==kind::EXISTS ){
- //erase from variable bound
- for( size_t i=0; i<n[0].getNumChildren(); i++ ){
- var_bound.erase( n[0][i] );
- }
- }
-
- int retType;
- if( n.getKind()==kind::EQUAL ){
- //we only require that the left and right hand side must be equal
- setEqual( child_types[0], child_types[1] );
- retType = getIdForType( n.getType() );
- }else if( n.getKind()==kind::APPLY_UF ){
- Node op = n.getOperator();
- if( d_op_return_types.find( op )==d_op_return_types.end() ){
- //assign arbitrary sort for return type
- d_op_return_types[op] = sortCount;
- sortCount++;
- //d_type_eq_class[sortCount].push_back( op );
- //assign arbitrary sort for argument types
- for( size_t i=0; i<n.getNumChildren(); i++ ){
- d_op_arg_types[op].push_back( sortCount );
- sortCount++;
- }
- }
- for( size_t i=0; i<n.getNumChildren(); i++ ){
- //the argument of the operator must match the return type of the subterm
- setEqual( child_types[i], d_op_arg_types[op][i] );
- }
- //return type is the return type
- retType = d_op_return_types[op];
- }else{
- std::map< Node, Node >::iterator it = var_bound.find( n );
- if( it!=var_bound.end() ){
- Trace("sort-inference-debug") << n << " is a bound variable." << std::endl;
- //the return type was specified while binding
- retType = d_var_types[it->second][n];
- }else if( n.getKind() == kind::VARIABLE ){
- Trace("sort-inference-debug") << n << " is a variable." << std::endl;
- if( d_op_return_types.find( n )==d_op_return_types.end() ){
- //assign arbitrary sort
- d_op_return_types[n] = sortCount;
- sortCount++;
- //d_type_eq_class[sortCount].push_back( n );
- }
- retType = d_op_return_types[n];
- }else if( n.isConst() ){
- Trace("sort-inference-debug") << n << " is a constant." << std::endl;
- //can be any type we want
- retType = sortCount;
- sortCount++;
- }else{
- Trace("sort-inference-debug") << n << " is a interpreted symbol." << std::endl;
- //it is an interpretted term
- for( size_t i=0; i<children.size(); i++ ){
- Trace("sort-inference-debug") << children[i] << " forced to have " << children[i].getType() << std::endl;
- //must enforce the actual type of the operator on the children
- int ct = getIdForType( children[i].getType() );
- setEqual( child_types[i], ct );
- }
- //return type must be the actual return type
- retType = getIdForType( n.getType() );
- }
- }
- Trace("sort-inference-debug") << "Type( " << n << " ) = ";
- printSort("sort-inference-debug", retType );
- Trace("sort-inference-debug") << std::endl;
- return retType;
-}
-
-
-TypeNode SortInference::getOrCreateTypeForId( int t, TypeNode pref ){
- int rt = getRepresentative( t );
- if( d_type_types.find( rt )!=d_type_types.end() ){
- return d_type_types[rt];
- }else{
- TypeNode retType;
- //see if we can assign pref
- if( !pref.isNull() && d_id_for_types.find( pref )==d_id_for_types.end() ){
- retType = pref;
- }else{
- if( d_subtype_count.find( pref )==d_subtype_count.end() ){
- d_subtype_count[pref] = 0;
- }
- //must create new type
- std::stringstream ss;
- ss << "it_" << d_subtype_count[pref] << "_" << pref;
- d_subtype_count[pref]++;
- retType = NodeManager::currentNM()->mkSort( ss.str() );
- }
- d_id_for_types[ retType ] = rt;
- d_type_types[ rt ] = retType;
- return retType;
- }
-}
-
-TypeNode SortInference::getTypeForId( int t ){
- int rt = getRepresentative( t );
- if( d_type_types.find( rt )!=d_type_types.end() ){
- return d_type_types[rt];
- }else{
- return TypeNode::null();
- }
-}
-
-Node SortInference::getNewSymbol( Node old, TypeNode tn ){
- if( tn==old.getType() ){
- return old;
- }else if( old.isConst() ){
- //must make constant of type tn
- if( d_const_map[tn].find( old )==d_const_map[tn].end() ){
- std::stringstream ss;
- ss << "ic_" << tn << "_" << old;
- d_const_map[tn][ old ] = NodeManager::currentNM()->mkSkolem( ss.str(), tn, "constant created during sort inference" ); //use mkConst???
- }
- return d_const_map[tn][ old ];
- }else{
- std::stringstream ss;
- ss << "i_$$_" << old;
- return NodeManager::currentNM()->mkSkolem( ss.str(), tn, "created during sort inference" );
- }
-}
-
-Node SortInference::simplify( Node n, std::map< Node, Node >& var_bound ){
- std::vector< Node > children;
- if( n.getKind()==kind::FORALL || n.getKind()==kind::EXISTS ){
- //recreate based on types of variables
- std::vector< Node > new_children;
- for( size_t i=0; i<n[0].getNumChildren(); i++ ){
- TypeNode tn = getOrCreateTypeForId( d_var_types[n][ n[0][i] ], n[0][i].getType() );
- Node v = getNewSymbol( n[0][i], tn );
- new_children.push_back( v );
- var_bound[ n[0][i] ] = v;
- }
- children.push_back( NodeManager::currentNM()->mkNode( n[0].getKind(), new_children ) );
- }
-
- //process children
- if( n.getMetaKind() == kind::metakind::PARAMETERIZED ){
- children.push_back( n.getOperator() );
- }
- for( size_t i=0; i<n.getNumChildren(); i++ ){
- bool processChild = true;
- if( n.getKind()==kind::FORALL || n.getKind()==kind::EXISTS ){
- processChild = i>=1;
- }
- if( processChild ){
- children.push_back( simplify( n[i], var_bound ) );
- }
- }
-
- //remove from variable bindings
- if( n.getKind()==kind::FORALL || n.getKind()==kind::EXISTS ){
- //erase from variable bound
- for( size_t i=0; i<n[0].getNumChildren(); i++ ){
- var_bound.erase( n[0][i] );
- }
- return NodeManager::currentNM()->mkNode( n.getKind(), children );
- }else if( n.getKind()==kind::EQUAL ){
- if( children[0].getType()!=children[1].getType() ){
- if( children[0].isConst() ){
- children[0] = getNewSymbol( children[0], children[1].getType() );
- }else if( children[1].isConst() ){
- children[1] = getNewSymbol( children[1], children[0].getType() );
- }else{
- Trace("sort-inference-warn") << "Sort inference created bad equality: " << children[0] << " = " << children[1] << std::endl;
- Trace("sort-inference-warn") << " Types : " << children[0].getType() << " " << children[1].getType() << std::endl;
- Assert( false );
- }
- }
- return NodeManager::currentNM()->mkNode( kind::APPLY_UF, children );
- }else if( n.getKind()==kind::APPLY_UF ){
- Node op = n.getOperator();
- if( d_symbol_map.find( op )==d_symbol_map.end() ){
- //make the new operator if necessary
- bool opChanged = false;
- std::vector< TypeNode > argTypes;
- for( size_t i=0; i<n.getNumChildren(); i++ ){
- TypeNode tn = getOrCreateTypeForId( d_op_arg_types[op][i], n[i].getType() );
- argTypes.push_back( tn );
- if( tn!=n[i].getType() ){
- opChanged = true;
- }
- }
- TypeNode retType = getOrCreateTypeForId( d_op_return_types[op], n.getType() );
- if( retType!=n.getType() ){
- opChanged = true;
- }
- if( opChanged ){
- std::stringstream ss;
- ss << "io_$$_" << op;
- TypeNode typ = NodeManager::currentNM()->mkFunctionType( argTypes, retType );
- d_symbol_map[op] = NodeManager::currentNM()->mkSkolem( ss.str(), typ, "op created during sort inference" );
- }else{
- d_symbol_map[op] = op;
- }
- }
- children[0] = d_symbol_map[op];
- //make sure all children have been taken care of
- for( size_t i=0; i<n.getNumChildren(); i++ ){
- TypeNode tn = children[i+1].getType();
- TypeNode tna = getTypeForId( d_op_arg_types[op][i] );
- if( tn!=tna ){
- if( n[i].isConst() ){
- children[i+1] = getNewSymbol( n[i], tna );
- }else{
- Trace("sort-inference-warn") << "Sort inference created bad child: " << n[i] << " " << tn << " " << tna << std::endl;
- Assert( false );
- }
- }
- }
- return NodeManager::currentNM()->mkNode( kind::APPLY_UF, children );
- }else{
- std::map< Node, Node >::iterator it = var_bound.find( n );
- if( it!=var_bound.end() ){
- return it->second;
- }else if( n.getKind() == kind::VARIABLE ){
- if( d_symbol_map.find( n )==d_symbol_map.end() ){
- TypeNode tn = getOrCreateTypeForId( d_op_return_types[n], n.getType() );
- d_symbol_map[n] = getNewSymbol( n, tn );
- }
- return d_symbol_map[n];
- }else if( n.isConst() ){
- //just return n, we will fix at higher scope
- return n;
- }else{
- return NodeManager::currentNM()->mkNode( n.getKind(), children );
- }
- }
-
-}
-
-}
+/********************* */ +/*! \file sort_inference.cpp + ** \verbatim + ** Original author: Andrew Reynolds <andrew.j.reynolds@gmail.com> + ** Major contributors: Morgan Deters <mdeters@cs.nyu.edu> + ** Minor contributors (to current version): none + ** This file is part of the CVC4 project. + ** Copyright (c) 2009-2013 New York University and The University of Iowa + ** See the file COPYING in the top-level source directory for licensing + ** information.\endverbatim + ** + ** \brief Sort inference module + ** + ** This class implements sort inference, based on a simple algorithm: + ** First, we assume all functions and predicates have distinct uninterpreted types. + ** One pass is made through the input assertions, while a union-find data structure + ** maintains necessary information regarding constraints on these types. + **/ + +#include <vector> + +#include "util/sort_inference.h" + +using namespace CVC4; +using namespace std; + +namespace CVC4 { + + +void SortInference::printSort( const char* c, int t ){ + int rt = getRepresentative( t ); + if( d_type_types.find( rt )!=d_type_types.end() ){ + Trace(c) << d_type_types[rt]; + }else{ + Trace(c) << "s_" << rt; + } +} + +void SortInference::simplify( std::vector< Node >& assertions, bool doRewrite ){ + //process all assertions + for( unsigned i=0; i<assertions.size(); i++ ){ + Trace("sort-inference-debug") << "Process " << assertions[i] << std::endl; + std::map< Node, Node > var_bound; + process( assertions[i], var_bound ); + } + //print debug + if( Trace.isOn("sort-inference") ){ + for( std::map< Node, int >::iterator it = d_op_return_types.begin(); it != d_op_return_types.end(); ++it ){ + Trace("sort-inference") << it->first << " : "; + if( !d_op_arg_types[ it->first ].empty() ){ + Trace("sort-inference") << "( "; + for( size_t i=0; i<d_op_arg_types[ it->first ].size(); i++ ){ + printSort( "sort-inference", d_op_arg_types[ it->first ][i] ); + Trace("sort-inference") << " "; + } + Trace("sort-inference") << ") -> "; + } + printSort( "sort-inference", it->second ); + Trace("sort-inference") << std::endl; + } + for( std::map< Node, std::map< Node, int > >::iterator it = d_var_types.begin(); it != d_var_types.end(); ++it ){ + Trace("sort-inference") << "Quantified formula " << it->first << " : " << std::endl; + for( std::map< Node, int >::iterator it2 = it->second.begin(); it2 != it->second.end(); ++it2 ){ + printSort( "sort-inference", it2->second ); + Trace("sort-inference") << std::endl; + } + Trace("sort-inference") << std::endl; + } + } + if( doRewrite ){ + //simplify all assertions by introducing new symbols wherever necessary (NOTE: this is unsound for quantifiers) + for( unsigned i=0; i<assertions.size(); i++ ){ + std::map< Node, Node > var_bound; + assertions[i] = simplify( assertions[i], var_bound ); + Trace("sort-inference-rewrite") << " --> " << assertions[i] << std::endl; + } + //now, ensure constants are distinct + for( std::map< TypeNode, std::map< Node, Node > >::iterator it = d_const_map.begin(); it != d_const_map.end(); ++it ){ + std::vector< Node > consts; + for( std::map< Node, Node >::iterator it2 = it->second.begin(); it2 != it->second.end(); ++it2 ){ + consts.push_back( it2->second ); + } + //add lemma enforcing introduced constants to be distinct? + } + } +} + +int SortInference::getRepresentative( int t ){ + std::map< int, int >::iterator it = d_type_union_find.find( t ); + if( it!=d_type_union_find.end() ){ + if( it->second==t ){ + return t; + }else{ + int rt = getRepresentative( it->second ); + d_type_union_find[t] = rt; + return rt; + } + }else{ + return t; + } +} + +void SortInference::setEqual( int t1, int t2 ){ + if( t1!=t2 ){ + int rt1 = getRepresentative( t1 ); + int rt2 = getRepresentative( t2 ); + if( rt1!=rt2 ){ + Trace("sort-inference-debug") << "Set equal : "; + printSort( "sort-inference-debug", rt1 ); + Trace("sort-inference-debug") << " "; + printSort( "sort-inference-debug", rt2 ); + Trace("sort-inference-debug") << std::endl; + //check if they must be a type + std::map< int, TypeNode >::iterator it1 = d_type_types.find( rt1 ); + std::map< int, TypeNode >::iterator it2 = d_type_types.find( rt2 ); + if( it2!=d_type_types.end() ){ + if( it1==d_type_types.end() ){ + //swap sides + int swap = rt1; + rt1 = rt2; + rt2 = swap; + }else{ + Assert( rt1==rt2 ); + } + } + /* + d_type_eq_class[rt1].insert( d_type_eq_class[rt1].end(), d_type_eq_class[rt2].begin(), d_type_eq_class[rt2].end() ); + d_type_eq_class[rt2].clear(); + Trace("sort-inference-debug") << "EqClass : { "; + for( int i=0; i<(int)d_type_eq_class[rt1].size(); i++ ){ + Trace("sort-inference-debug") << d_type_eq_class[rt1][i] << ", "; + } + Trace("sort-inference-debug") << "}" << std::endl; + */ + d_type_union_find[rt2] = rt1; + } + } +} + +int SortInference::getIdForType( TypeNode tn ){ + //register the return type + std::map< TypeNode, int >::iterator it = d_id_for_types.find( tn ); + if( it==d_id_for_types.end() ){ + int sc = sortCount; + d_type_types[ sortCount ] = tn; + d_id_for_types[ tn ] = sortCount; + sortCount++; + return sc; + }else{ + return it->second; + } +} + +int SortInference::process( Node n, std::map< Node, Node >& var_bound ){ + Trace("sort-inference-debug") << "Process " << n << std::endl; + //add to variable bindings + if( n.getKind()==kind::FORALL || n.getKind()==kind::EXISTS ){ + for( size_t i=0; i<n[0].getNumChildren(); i++ ){ + //TODO: try applying sort inference to quantified variables + d_var_types[n][ n[0][i] ] = sortCount; + sortCount++; + + //type of the quantified variable must be the same + //d_var_types[n][ n[0][i] ] = getIdForType( n[0][i].getType() ); + var_bound[ n[0][i] ] = n; + } + } + + //process children + std::vector< Node > children; + std::vector< int > child_types; + for( size_t i=0; i<n.getNumChildren(); i++ ){ + bool processChild = true; + if( n.getKind()==kind::FORALL || n.getKind()==kind::EXISTS ){ + processChild = i==1; + } + if( processChild ){ + children.push_back( n[i] ); + child_types.push_back( process( n[i], var_bound ) ); + } + } + + //remove from variable bindings + if( n.getKind()==kind::FORALL || n.getKind()==kind::EXISTS ){ + //erase from variable bound + for( size_t i=0; i<n[0].getNumChildren(); i++ ){ + var_bound.erase( n[0][i] ); + } + } + + int retType; + if( n.getKind()==kind::EQUAL ){ + //we only require that the left and right hand side must be equal + setEqual( child_types[0], child_types[1] ); + retType = getIdForType( n.getType() ); + }else if( n.getKind()==kind::APPLY_UF ){ + Node op = n.getOperator(); + if( d_op_return_types.find( op )==d_op_return_types.end() ){ + //assign arbitrary sort for return type + d_op_return_types[op] = sortCount; + sortCount++; + //d_type_eq_class[sortCount].push_back( op ); + //assign arbitrary sort for argument types + for( size_t i=0; i<n.getNumChildren(); i++ ){ + d_op_arg_types[op].push_back( sortCount ); + sortCount++; + } + } + for( size_t i=0; i<n.getNumChildren(); i++ ){ + //the argument of the operator must match the return type of the subterm + setEqual( child_types[i], d_op_arg_types[op][i] ); + } + //return type is the return type + retType = d_op_return_types[op]; + }else{ + std::map< Node, Node >::iterator it = var_bound.find( n ); + if( it!=var_bound.end() ){ + Trace("sort-inference-debug") << n << " is a bound variable." << std::endl; + //the return type was specified while binding + retType = d_var_types[it->second][n]; + }else if( n.getKind() == kind::VARIABLE ){ + Trace("sort-inference-debug") << n << " is a variable." << std::endl; + if( d_op_return_types.find( n )==d_op_return_types.end() ){ + //assign arbitrary sort + d_op_return_types[n] = sortCount; + sortCount++; + //d_type_eq_class[sortCount].push_back( n ); + } + retType = d_op_return_types[n]; + }else if( n.isConst() ){ + Trace("sort-inference-debug") << n << " is a constant." << std::endl; + //can be any type we want + retType = sortCount; + sortCount++; + }else{ + Trace("sort-inference-debug") << n << " is a interpreted symbol." << std::endl; + //it is an interpretted term + for( size_t i=0; i<children.size(); i++ ){ + Trace("sort-inference-debug") << children[i] << " forced to have " << children[i].getType() << std::endl; + //must enforce the actual type of the operator on the children + int ct = getIdForType( children[i].getType() ); + setEqual( child_types[i], ct ); + } + //return type must be the actual return type + retType = getIdForType( n.getType() ); + } + } + Trace("sort-inference-debug") << "Type( " << n << " ) = "; + printSort("sort-inference-debug", retType ); + Trace("sort-inference-debug") << std::endl; + return retType; +} + + +TypeNode SortInference::getOrCreateTypeForId( int t, TypeNode pref ){ + int rt = getRepresentative( t ); + if( d_type_types.find( rt )!=d_type_types.end() ){ + return d_type_types[rt]; + }else{ + TypeNode retType; + //see if we can assign pref + if( !pref.isNull() && d_id_for_types.find( pref )==d_id_for_types.end() ){ + retType = pref; + }else{ + if( d_subtype_count.find( pref )==d_subtype_count.end() ){ + d_subtype_count[pref] = 0; + } + //must create new type + std::stringstream ss; + ss << "it_" << d_subtype_count[pref] << "_" << pref; + d_subtype_count[pref]++; + retType = NodeManager::currentNM()->mkSort( ss.str() ); + } + d_id_for_types[ retType ] = rt; + d_type_types[ rt ] = retType; + return retType; + } +} + +TypeNode SortInference::getTypeForId( int t ){ + int rt = getRepresentative( t ); + if( d_type_types.find( rt )!=d_type_types.end() ){ + return d_type_types[rt]; + }else{ + return TypeNode::null(); + } +} + +Node SortInference::getNewSymbol( Node old, TypeNode tn ){ + if( tn==old.getType() ){ + return old; + }else if( old.isConst() ){ + //must make constant of type tn + if( d_const_map[tn].find( old )==d_const_map[tn].end() ){ + std::stringstream ss; + ss << "ic_" << tn << "_" << old; + d_const_map[tn][ old ] = NodeManager::currentNM()->mkSkolem( ss.str(), tn, "constant created during sort inference" ); //use mkConst??? + } + return d_const_map[tn][ old ]; + }else{ + std::stringstream ss; + ss << "i_$$_" << old; + return NodeManager::currentNM()->mkSkolem( ss.str(), tn, "created during sort inference" ); + } +} + +Node SortInference::simplify( Node n, std::map< Node, Node >& var_bound ){ + std::vector< Node > children; + if( n.getKind()==kind::FORALL || n.getKind()==kind::EXISTS ){ + //recreate based on types of variables + std::vector< Node > new_children; + for( size_t i=0; i<n[0].getNumChildren(); i++ ){ + TypeNode tn = getOrCreateTypeForId( d_var_types[n][ n[0][i] ], n[0][i].getType() ); + Node v = getNewSymbol( n[0][i], tn ); + new_children.push_back( v ); + var_bound[ n[0][i] ] = v; + } + children.push_back( NodeManager::currentNM()->mkNode( n[0].getKind(), new_children ) ); + } + + //process children + if( n.getMetaKind() == kind::metakind::PARAMETERIZED ){ + children.push_back( n.getOperator() ); + } + for( size_t i=0; i<n.getNumChildren(); i++ ){ + bool processChild = true; + if( n.getKind()==kind::FORALL || n.getKind()==kind::EXISTS ){ + processChild = i>=1; + } + if( processChild ){ + children.push_back( simplify( n[i], var_bound ) ); + } + } + + //remove from variable bindings + if( n.getKind()==kind::FORALL || n.getKind()==kind::EXISTS ){ + //erase from variable bound + for( size_t i=0; i<n[0].getNumChildren(); i++ ){ + var_bound.erase( n[0][i] ); + } + return NodeManager::currentNM()->mkNode( n.getKind(), children ); + }else if( n.getKind()==kind::EQUAL ){ + if( children[0].getType()!=children[1].getType() ){ + if( children[0].isConst() ){ + children[0] = getNewSymbol( children[0], children[1].getType() ); + }else if( children[1].isConst() ){ + children[1] = getNewSymbol( children[1], children[0].getType() ); + }else{ + Trace("sort-inference-warn") << "Sort inference created bad equality: " << children[0] << " = " << children[1] << std::endl; + Trace("sort-inference-warn") << " Types : " << children[0].getType() << " " << children[1].getType() << std::endl; + Assert( false ); + } + } + return NodeManager::currentNM()->mkNode( kind::APPLY_UF, children ); + }else if( n.getKind()==kind::APPLY_UF ){ + Node op = n.getOperator(); + if( d_symbol_map.find( op )==d_symbol_map.end() ){ + //make the new operator if necessary + bool opChanged = false; + std::vector< TypeNode > argTypes; + for( size_t i=0; i<n.getNumChildren(); i++ ){ + TypeNode tn = getOrCreateTypeForId( d_op_arg_types[op][i], n[i].getType() ); + argTypes.push_back( tn ); + if( tn!=n[i].getType() ){ + opChanged = true; + } + } + TypeNode retType = getOrCreateTypeForId( d_op_return_types[op], n.getType() ); + if( retType!=n.getType() ){ + opChanged = true; + } + if( opChanged ){ + std::stringstream ss; + ss << "io_$$_" << op; + TypeNode typ = NodeManager::currentNM()->mkFunctionType( argTypes, retType ); + d_symbol_map[op] = NodeManager::currentNM()->mkSkolem( ss.str(), typ, "op created during sort inference" ); + }else{ + d_symbol_map[op] = op; + } + } + children[0] = d_symbol_map[op]; + //make sure all children have been taken care of + for( size_t i=0; i<n.getNumChildren(); i++ ){ + TypeNode tn = children[i+1].getType(); + TypeNode tna = getTypeForId( d_op_arg_types[op][i] ); + if( tn!=tna ){ + if( n[i].isConst() ){ + children[i+1] = getNewSymbol( n[i], tna ); + }else{ + Trace("sort-inference-warn") << "Sort inference created bad child: " << n[i] << " " << tn << " " << tna << std::endl; + Assert( false ); + } + } + } + return NodeManager::currentNM()->mkNode( kind::APPLY_UF, children ); + }else{ + std::map< Node, Node >::iterator it = var_bound.find( n ); + if( it!=var_bound.end() ){ + return it->second; + }else if( n.getKind() == kind::VARIABLE ){ + if( d_symbol_map.find( n )==d_symbol_map.end() ){ + TypeNode tn = getOrCreateTypeForId( d_op_return_types[n], n.getType() ); + d_symbol_map[n] = getNewSymbol( n, tn ); + } + return d_symbol_map[n]; + }else if( n.isConst() ){ + //just return n, we will fix at higher scope + return n; + }else{ + return NodeManager::currentNM()->mkNode( n.getKind(), children ); + } + } + +} +int SortInference::getSortId( Node n ) { + Node op = n.getKind()==kind::APPLY_UF ? n.getOperator() : n; + return getRepresentative( d_op_return_types[op] ); +} + +int SortInference::getSortId( Node f, Node v ) { + return getRepresentative( d_var_types[f][v] ); +} + +void SortInference::setSkolemVar( Node f, Node v, Node sk ){ + d_op_return_types[sk] = getSortId( f, v ); +} + +}/* CVC4 namespace */ diff --git a/src/util/sort_inference.h b/src/util/sort_inference.h index 363dbd84d..0b1f96f85 100755..100644 --- a/src/util/sort_inference.h +++ b/src/util/sort_inference.h @@ -1,72 +1,76 @@ -/********************* */
-/*! \file sort_inference.h
- ** \verbatim
- ** Original author: ajreynol
- ** Major contributors: none
- ** Minor contributors (to current version): none
- ** This file is part of the CVC4 prototype.
- ** Copyright (c) 2009-2012 New York University and The University of Iowa
- ** See the file COPYING in the top-level source directory for licensing
- ** information.\endverbatim
- **
- ** \brief Pre-process step for performing sort inference
- **/
-
-#include "cvc4_private.h"
-
-#ifndef __CVC4__SORT_INFERENCE_H
-#define __CVC4__SORT_INFERENCE_H
-
-#include <iostream>
-#include <string>
-#include <vector>
-#include <map>
-#include "expr/node.h"
-#include "expr/type_node.h"
-
-namespace CVC4 {
-
-class SortInference{
-private:
- //for debugging
- //std::map< int, std::vector< Node > > d_type_eq_class;
-private:
- int sortCount;
- std::map< int, int > d_type_union_find;
- std::map< int, TypeNode > d_type_types;
- std::map< TypeNode, int > d_id_for_types;
- //for apply uf operators
- std::map< Node, int > d_op_return_types;
- std::map< Node, std::vector< int > > d_op_arg_types;
- //for bound variables
- std::map< Node, std::map< Node, int > > d_var_types;
- //get representative
- int getRepresentative( int t );
- void setEqual( int t1, int t2 );
- int getIdForType( TypeNode tn );
- void printSort( const char* c, int t );
- //process
- int process( Node n, std::map< Node, Node >& var_bound );
-private:
- //mapping from old symbols to new symbols
- std::map< Node, Node > d_symbol_map;
- //mapping from constants to new symbols
- std::map< TypeNode, std::map< Node, Node > > d_const_map;
- //number of subtypes generated
- std::map< TypeNode, int > d_subtype_count;
- //helper functions for simplify
- TypeNode getOrCreateTypeForId( int t, TypeNode pref );
- TypeNode getTypeForId( int t );
- Node getNewSymbol( Node old, TypeNode tn );
- //simplify
- Node simplify( Node n, std::map< Node, Node >& var_bound );
-public:
- SortInference() : sortCount( 0 ){}
- ~SortInference(){}
-
- void simplify( std::vector< Node >& assertions, bool doRewrite = false );
-};
-
-}
-
-#endif
+/********************* */ +/*! \file sort_inference.h + ** \verbatim + ** Original author: Andrew Reynolds <andrew.j.reynolds@gmail.com> + ** Major contributors: Morgan Deters <mdeters@cs.nyu.edu> + ** Minor contributors (to current version): none + ** This file is part of the CVC4 project. + ** Copyright (c) 2009-2013 New York University and The University of Iowa + ** See the file COPYING in the top-level source directory for licensing + ** information.\endverbatim + ** + ** \brief Pre-process step for performing sort inference + **/ + +#include "cvc4_private.h" + +#ifndef __CVC4__SORT_INFERENCE_H +#define __CVC4__SORT_INFERENCE_H + +#include <iostream> +#include <string> +#include <vector> +#include <map> +#include "expr/node.h" +#include "expr/type_node.h" + +namespace CVC4 { + +class SortInference{ +private: + //for debugging + //std::map< int, std::vector< Node > > d_type_eq_class; +private: + int sortCount; + std::map< int, int > d_type_union_find; + std::map< int, TypeNode > d_type_types; + std::map< TypeNode, int > d_id_for_types; + //for apply uf operators + std::map< Node, int > d_op_return_types; + std::map< Node, std::vector< int > > d_op_arg_types; + //for bound variables + std::map< Node, std::map< Node, int > > d_var_types; + //get representative + int getRepresentative( int t ); + void setEqual( int t1, int t2 ); + int getIdForType( TypeNode tn ); + void printSort( const char* c, int t ); + //process + int process( Node n, std::map< Node, Node >& var_bound ); +private: + //mapping from old symbols to new symbols + std::map< Node, Node > d_symbol_map; + //mapping from constants to new symbols + std::map< TypeNode, std::map< Node, Node > > d_const_map; + //number of subtypes generated + std::map< TypeNode, int > d_subtype_count; + //helper functions for simplify + TypeNode getOrCreateTypeForId( int t, TypeNode pref ); + TypeNode getTypeForId( int t ); + Node getNewSymbol( Node old, TypeNode tn ); + //simplify + Node simplify( Node n, std::map< Node, Node >& var_bound ); +public: + SortInference() : sortCount( 0 ){} + ~SortInference(){} + + void simplify( std::vector< Node >& assertions, bool doRewrite = false ); + int getSortId( Node n ); + int getSortId( Node f, Node v ); + //set that sk is the skolem variable of v for quantifier f + void setSkolemVar( Node f, Node v, Node sk ); +}; + +} + +#endif diff --git a/src/util/tls.h.in b/src/util/tls.h.in index 17f1f1d6e..935586f77 100644 --- a/src/util/tls.h.in +++ b/src/util/tls.h.in @@ -1,5 +1,5 @@ /********************* */ -/*! \file tls.h +/*! \file tls.h.in ** \verbatim ** Original author: mdeters ** Major contributors: none |