Fix for bug303. The problem was with function applications that get normalized when...
authorDejan Jovanović <dejan.jovanovic@gmail.com>
Tue, 21 Feb 2012 19:43:46 +0000 (19:43 +0000)
committerDejan Jovanović <dejan.jovanovic@gmail.com>
Tue, 21 Feb 2012 19:43:46 +0000 (19:43 +0000)
Also added theory::assertions debug flag that will printout assertions of each theory for ease and uniformity of debugging in the future.

src/theory/theory.h
src/theory/theory_engine.cpp
src/theory/uf/equality_engine.h
src/theory/uf/equality_engine_impl.h
test/regress/regress0/Makefile.am
test/regress/regress0/bug303.smt2 [new file with mode: 0644]

index af891e3a35798af44025473f8459497b53d4e46e..cf986a1f266e144fa7fa511fb30d8fdb3fb731dc 100644 (file)
@@ -205,26 +205,6 @@ protected:
     return fact;
   }
 
-  /**
-   * Provides access to the facts queue, primarily intended for theory
-   * debugging purposes.
-   *
-   * @return the iterator to the beginning of the fact queue
-   */
-  context::CDList<Assertion>::const_iterator facts_begin() const {
-    return d_facts.begin();
-  }
-
-  /**
-   * Provides access to the facts queue, primarily intended for theory
-   * debugging purposes.
-   *
-   * @return the iterator to the end of the fact queue
-   */
-  context::CDList<Assertion>::const_iterator facts_end() const {
-    return d_facts.end();
-  }
-
   /**
    * The theory that owns the uninterpreted sort.
    */
@@ -605,6 +585,46 @@ public:
     return ss.str();
   }
 
+  /**
+   * Provides access to the facts queue, primarily intended for theory
+   * debugging purposes.
+   *
+   * @return the iterator to the beginning of the fact queue
+   */
+  context::CDList<Assertion>::const_iterator facts_begin() const {
+    return d_facts.begin();
+  }
+
+  /**
+   * Provides access to the facts queue, primarily intended for theory
+   * debugging purposes.
+   *
+   * @return the iterator to the end of the fact queue
+   */
+  context::CDList<Assertion>::const_iterator facts_end() const {
+    return d_facts.end();
+  }
+
+  /**
+   * Provides access to the shared terms, primarily intended for theory
+   * debugging purposes.
+   *
+   * @return the iterator to the beginning of the shared terms list
+   */
+  context::CDList<TNode>::const_iterator shared_terms_begin() const {
+    return d_sharedTerms.begin();
+  }
+
+  /**
+   * Provides access to the facts queue, primarily intended for theory
+   * debugging purposes.
+   *
+   * @return the iterator to the end of the shared terms list
+   */
+  context::CDList<TNode>::const_iterator shared_terms_end() const {
+    return d_sharedTerms.end();
+  }
+
 };/* class Theory */
 
 std::ostream& operator<<(std::ostream& os, Theory::Effort level);
index e21e8367108218320ce76a58c873844b783ee436..75c64654d5f0da7eb12d76501ce84c80a4f64a89 100644 (file)
@@ -133,6 +133,33 @@ void TheoryEngine::check(Theory::Effort effort) {
 
       Debug("theory") << "TheoryEngine::check(" << effort << "): running check" << std::endl;
 
+      if (Debug.isOn("theory::assertions")) {
+        for (unsigned theoryId = 0; theoryId < THEORY_LAST; ++ theoryId) {
+          Theory* theory = d_theoryTable[theoryId];
+          if (theory && Theory::setContains((TheoryId)theoryId, d_activeTheories)) {
+            Debug("theory::assertions") << "--------------------------------------------" << std::endl;
+            Debug("theory::assertions") << "Assertions of " << theory->getId() << ": " << std::endl;
+            context::CDList<Assertion>::const_iterator it = theory->facts_begin(), it_end = theory->facts_end();
+            for (unsigned i = 0; it != it_end; ++ it, ++i) {
+                if ((*it).isPreregistered) {
+                  Debug("theory::assertions") << "[" << i << "]: ";
+                } else {
+                  Debug("theory::assertions") << "(" << i << "): ";
+                }
+                Debug("theory::assertions") << (*it).assertion << endl;
+            }
+
+            if (d_sharedTermsExist) {
+              Debug("theory::assertions") << "Shared terms of " << theory->getId() << ": " << std::endl;
+              context::CDList<TNode>::const_iterator it = theory->shared_terms_begin(), it_end = theory->shared_terms_end();
+              for (unsigned i = 0; it != it_end; ++ it, ++i) {
+                  Debug("theory::assertions") << "[" << i << "]: " << (*it) << endl;
+              }
+            }
+          }
+        }
+      }
+
       // Do the checking
       CVC4_FOR_EACH_THEORY;
 
index 29f932e04d4d738497da6a94e4e846a98c367415..41b39af97e92a1b4687ed61bd13698f1360303cd 100644 (file)
@@ -311,8 +311,22 @@ private:
   /** A context-dependents count of nodes */
   context::CDO<size_t> d_nodesCount;
 
+  /**
+   * At time of addition a function application can already normalize to something, so
+   * we keep both the original, and the normalized version.
+   */
+  struct FunctionApplicationPair {
+    FunctionApplication original;
+    FunctionApplication normalized;
+    FunctionApplicationPair() {}
+    FunctionApplicationPair(const FunctionApplication& original, const FunctionApplication& normalized)
+    : original(original), normalized(normalized) {}
+    bool isNull() const {
+      return !original.isApplication();
+    }
+  };
   /** Map from ids to the applications */
-  std::vector<FunctionApplication> d_applications;
+  std::vector<FunctionApplicationPair> d_applications;
 
   /** Map from ids to the equality nodes */
   std::vector<EqualityNode> d_equalityNodes;
index f30006cb9dac0d64873a285f42306b5fffe090a8..02426c8499bad794db36ede42a9ba87447a1e2cb 100644 (file)
@@ -41,13 +41,14 @@ EqualityNodeId EqualityEngine<NotifyClass>::newApplicationNode(TNode original, E
 
   // Get another id for this
   EqualityNodeId funId = newNode(original, true);
-    // The function application we're creating
+  FunctionApplication funOriginal(t1, t2);
+  // The function application we're creating
   EqualityNodeId t1ClassId = getEqualityNode(t1).getFind();
   EqualityNodeId t2ClassId = getEqualityNode(t2).getFind();
   FunctionApplication funNormalized(t1ClassId, t2ClassId);
 
-  // We add the normalized version, the term needs to be re-added on each backtrack
-  d_applications[funId] = funNormalized;
+  // We add the original version
+  d_applications[funId] = FunctionApplicationPair(funOriginal, funNormalized);
 
   // Add the lookup data, if it's not already there
   typename ApplicationIdsMap::iterator find = d_applicationLookup.find(funNormalized);
@@ -86,7 +87,7 @@ EqualityNodeId EqualityEngine<NotifyClass>::newNode(TNode node, bool isApplicati
   // Add the node to it's position
   d_nodes.push_back(node);
   // Note if this is an application or not
-  d_applications.push_back(FunctionApplication());
+  d_applications.push_back(FunctionApplicationPair());
   // Add the trigger list for this node
   d_nodeTriggers.push_back(+null_trigger);
   // Add it to the equality graph
@@ -294,7 +295,7 @@ void EqualityEngine<NotifyClass>::merge(EqualityNode& class1, EqualityNode& clas
       // Get the function application
       EqualityNodeId funId = useNode.getApplicationId();
       Debug("equality") << "EqualityEngine::merge(" << class1.getFind() << "," << class2.getFind() << "): " << currentId << " in " << d_nodes[funId] << std::endl;
-      const FunctionApplication& fun = d_applications[useNode.getApplicationId()];
+      const FunctionApplication& fun = d_applications[useNode.getApplicationId()].normalized;
       // Check if there is an application with find arguments
       EqualityNodeId aNormalized = getEqualityNode(fun.a).getFind();
       EqualityNodeId bNormalized = getEqualityNode(fun.b).getFind();
@@ -441,7 +442,7 @@ void EqualityEngine<NotifyClass>::backtrack() {
       Debug("equality") << "EqualityEngine::backtrack(): removing node " << d_nodes[i] << std::endl;
       d_nodeIds.erase(d_nodes[i]);
 
-      const FunctionApplication& app = d_applications[i];
+      const FunctionApplication& app = d_applications[i].normalized;
       if (app.isApplication()) {
         // Remove b from use-list
         getEqualityNode(app.b).removeTopFromUseList(d_useListNodes);
@@ -593,8 +594,8 @@ void EqualityEngine<NotifyClass>::getExplanation(EqualityNodeId t1Id, EqualityNo
             if (reasonType == MERGED_THROUGH_CONGRUENCE) {
               // f(x1, x2) == f(y1, y2) because x1 = y1 and x2 = y2
               Debug("equality") << "EqualityEngine::getExplanation(): due to congruence, going deeper" << std::endl;
-              const FunctionApplication& f1 = d_applications[currentNode];
-              const FunctionApplication& f2 = d_applications[edgeNode];
+              const FunctionApplication& f1 = d_applications[currentNode].original;
+              const FunctionApplication& f2 = d_applications[edgeNode].original;
               Debug("equality") << push;
               getExplanation(f1.a, f2.a, equalities);
               getExplanation(f1.b, f2.b, equalities);
index 0bc78e6c44bdf8e61452ff65379ad8402404f6ea..6947ea7c4e483ebf0fc3d06c4df6b890f7533341 100644 (file)
@@ -94,7 +94,8 @@ BUG_TESTS = \
        bug187.smt2 \
        bug220.smt2 \
        bug239.smt \
-       buggy-ite.smt2
+       buggy-ite.smt2 \
+       bug303.smt2
 
 TESTS =        $(SMT_TESTS) $(SMT2_TESTS) $(CVC_TESTS) $(BUG_TESTS)
 
diff --git a/test/regress/regress0/bug303.smt2 b/test/regress/regress0/bug303.smt2
new file mode 100644 (file)
index 0000000..bf603bc
--- /dev/null
@@ -0,0 +1,23 @@
+(set-logic QF_LIA)
+(set-info :status unsat)
+
+;; don't use a datatypes for currently focusing in uf
+(declare-sort list 0)
+
+(declare-fun cons (Int list) list)
+(declare-fun nil () list)
+
+;;define length
+(declare-fun length (list) Int)
+
+(assert (= (length nil) 0))
+
+(declare-fun one_cons (list) list)
+
+(assert (= (length (cons 1 nil)) (+ 1 (length nil))))
+(assert (= (one_cons nil) (cons 1 nil)))
+(assert (not (= (length (one_cons nil)) 1)))
+
+(check-sat)
+
+(exit)