fully implement the always-check-again-after-the-output-channel-is-used fix for bug...
authorMorgan Deters <mdeters@gmail.com>
Wed, 2 Nov 2011 01:48:41 +0000 (01:48 +0000)
committerMorgan Deters <mdeters@gmail.com>
Wed, 2 Nov 2011 01:48:41 +0000 (01:48 +0000)
src/prop/minisat/core/Solver.cc
src/prop/sat.cpp
src/prop/sat.h
src/theory/theory_engine.cpp
src/theory/theory_engine.h

index 961ef85c56884701a7c699217c1dc37e55ebe987..8a883b1cb4de9016fd1708eb76c88be7d04b5a76 100644 (file)
@@ -654,6 +654,7 @@ CRef Solver::propagate(TheoryCheckType type)
         recheck = true;
         return updateLemmas();
       } else {
+        recheck = proxy->theoryNeedCheck();
         return confl;
       }
     }
index 5d53bf100cc661bbf19f52e34f66c923c20b48a0..36f411df42137eef8d21f213f0f55f17550d7eae 100644 (file)
@@ -70,6 +70,10 @@ void SatSolver::enqueueTheoryLiteral(const SatLiteral& l) {
   d_theoryEngine->assertFact(literalNode);
 }
 
+bool SatSolver::theoryNeedCheck() const {
+  return d_theoryEngine->needCheck();
+}
+
 void SatSolver::setCnfStream(CnfStream* cnfStream) {
   d_cnfStream = cnfStream;
 }
index 026193eaeb8ba8fc0b475c7a2d6f4ac18334ebcf..13b32f18d8ac4bc6dae5f699470f61c20d7ac98c 100644 (file)
@@ -230,6 +230,8 @@ public:
 
   void enqueueTheoryLiteral(const SatLiteral& l);
 
+  bool theoryNeedCheck() const;
+
   void setCnfStream(CnfStream* cnfStream);
 
   /** Call value() during the search.*/
index e09e9f47f0cd44bf81c959e82a638795d9282ea6..386b8bbd4e68a2ce8b3defe93b65912bf70aca44 100644 (file)
@@ -125,6 +125,10 @@ void TheoryEngine::check(Theory::Effort effort) {
     // Mark the lemmas flag (no lemmas added)
     d_lemmasAdded = false;
 
+    // Mark the output channel unused (if this is FULL_EFFORT, and nothing
+    // is done by the theories, no additional check will be needed)
+    d_outputChannelUsed = false;
+
     while (true) {
 
       Debug("theory") << "TheoryEngine::check(" << effort << "): running check" << std::endl;
index 09bb6963e06d307b4e1aa5ba3f169f70d79ae7b7..0d95009960f2be98a4743cb0485f7dd0b08dfaa6 100644 (file)
@@ -191,18 +191,21 @@ class TheoryEngine {
     void conflict(TNode conflictNode) throw(AssertionException) {
       Trace("theory") << "EngineOutputChannel<" << d_theory << ">::conflict(" << conflictNode << ")" << std::endl;
       ++ d_statistics.conflicts;
+      d_engine->d_outputChannelUsed = true;
       d_engine->conflict(conflictNode, d_theory);
     }
 
     void propagate(TNode literal) throw(AssertionException) {
       Trace("theory") << "EngineOutputChannel<" << d_theory << ">::propagate(" << literal << ")" << std::endl;
       ++ d_statistics.propagations;
+      d_engine->d_outputChannelUsed = true;
       d_engine->propagate(literal, d_theory);
     }
 
     unsigned lemma(TNode lemma, bool removable = false) throw(TypeCheckingExceptionPrivate, AssertionException) {
       Trace("theory") << "EngineOutputChannel<" << d_theory << ">::lemma(" << lemma << ")" << std::endl;
       ++ d_statistics.lemmas;
+      d_engine->d_outputChannelUsed = true;
       return d_engine->lemma(lemma, false, removable);
     }
 
@@ -343,6 +346,15 @@ class TheoryEngine {
    */
   bool d_lemmasAdded;
 
+  /**
+   * A variable to mark if the OutputChannel was "used" by any theory
+   * since the start of the last check.  If it has been, we require
+   * a FULL_EFFORT check before exiting and reporting SAT.
+   *
+   * See the documentation for the needCheck() function, below.
+   */
+  bool d_outputChannelUsed;
+
   /**
    * Adds a new lemma
    */
@@ -414,18 +426,38 @@ public:
   }
 
   /**
-   * Runs theory specific preprocesssing on the non-Boolean parts of the formula.
-   * This is only called on input assertions, after ITEs have been removed.
+   * Runs theory specific preprocesssing on the non-Boolean parts of
+   * the formula.  This is only called on input assertions, after ITEs
+   * have been removed.
    */
   Node preprocess(TNode node);
 
   /**
    * Return whether or not we are incomplete (in the current context).
    */
-  inline bool isIncomplete() {
+  inline bool isIncomplete() const {
     return d_incomplete;
   }
 
+  /**
+   * Returns true if we need another round of checking.  If this
+   * returns true, check(FULL_EFFORT) _must_ be called by the
+   * propositional layer before reporting SAT.
+   *
+   * This is especially necessary for incomplete theories that lazily
+   * output some lemmas on FULL_EFFORT check (e.g. quantifier reasoning
+   * outputing quantifier instantiations).  In such a case, a lemma can
+   * be asserted that is simplified away (perhaps it's already true).
+   * However, we must maintain the invariant that, if a theory uses the
+   * OutputChannel, it implicitly requests that another check(FULL_EFFORT)
+   * be performed before exit, even if no new facts are on its fact queue,
+   * as it might decide to further instantiate some lemmas, precluding
+   * a SAT response.
+   */
+  inline bool needCheck() const {
+    return d_outputChannelUsed || d_lemmasAdded;
+  }
+
   /**
    * This is called at shutdown time by the SmtEngine, just before
    * destruction.  It is important because there are destruction