Merge from cudd branch. This mostly just adds support for linking
authorMorgan Deters <mdeters@gmail.com>
Tue, 15 Mar 2011 20:32:13 +0000 (20:32 +0000)
committerMorgan Deters <mdeters@gmail.com>
Tue, 15 Mar 2011 20:32:13 +0000 (20:32 +0000)
against cudd libraries, the propositional_query class (in util/),
which uses cudd if it's available (and otherwise answers UNKNOWN for
all queries), and the arith theory support for it (currently disabled
per Tim's request, so he can clean it up).

Other changes include:

* contrib/debug-keys - script to print all used keys under Debug(), Trace()
* test/regress/run_regression - minor fix (don't export a variable)
* configure.ac - replace a comment removed by dejan's google perf commit
* some minor copyright/documentation updates, and minor changes to source
  text to make 'clang --analyze' happy.

25 files changed:
Makefile
Makefile.subdir
README
configure.ac
contrib/addsourcedir
contrib/configure-in-place
contrib/debug-keys [new file with mode: 0755]
contrib/dimacs_to_smt.pl
contrib/get-authors
src/expr/type.h
src/prop/Makefile.am
src/smt/smt_engine.cpp
src/theory/arith/theory_arith.cpp
src/theory/arith/theory_arith.h
src/util/Makefile.am
src/util/configuration.cpp
src/util/configuration.h
src/util/configuration_private.h
src/util/options.cpp
src/util/propositional_query.cpp [new file with mode: 0644]
src/util/propositional_query.h [new file with mode: 0644]
src/util/result.h
src/util/stats.h
test/regress/regress0/arith/Makefile.am
test/regress/regress0/arith/miplibtrick.smt [new file with mode: 0644]

index 0f04a94cb268cfcb86f86723f79465ae5bdd5090..4b731cb04b98d0c784e4d525f52518acbe412ff2 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,3 +1,10 @@
+# -*-makefile-*-
+#
+# This makefile is the _source_ directory's makefile, and is static,
+# not generated.  Makefile.am is the automake makefile for the build
+# top-level (its corresponding Makefile.in is here, too, but the
+# corresponding Makefile is under builds/$arch/$buildid.
+#
 builddir = builds
 
 .PHONY: _default_build_ all
index 293b2771b60164175452a71c4a009739f2480450..7b7c90561fa4569345ecd465ec27dbcc5918b3a9 100644 (file)
@@ -1,4 +1,10 @@
 # -*-makefile-*-
+#
+# This makefile is included from source directories in order to
+# trigger a build in the corresponding build directory.
+#
+# See src/Makefile for an example.
+#
 include $(topdir)/builds/current
 builddir = $(topdir)/builds/$(CURRENT_BUILD)/$(srcdir)
 unittestdir = $(topdir)/builds/$(CURRENT_BUILD)/test/unit
diff --git a/README b/README
index d064c226dde49adcbc499d9ab475cac1e5590720..aaa36ff67392ddff27a7394a5718a6827849bcd6 100644 (file)
--- a/README
+++ b/README
@@ -27,9 +27,25 @@ given are minimum versions; more recent versions should be compatible.
 
 GNU C and C++ (gcc and g++), reasonably recent versions
 GNU Make
-GMP v4.2
-libantlr3c v3.2
-Optional: CLN v1.3
+GMP v4.2 (GNU Multi-Precision arithmetic library)
+libantlr3c v3.2 (ANTLR parser generator)
+Optional: CLN v1.3 (Class Library for Numbers)
+Optional: CUDD v2.4.2 (Colorado University Decision Diagram package)
+
+CUDD, if desired, must be installed in a special manner.  The default
+distribution from vlsi.colorado.edu doesn't build shared objects,
+and names things that make it difficult to compose software
+dependences (e.g. a "libutil" is distributed).  So we packaged our
+own version of cudd that changes only its build process, making it
+play nicely with libtool and packaging all the various cudd libraries
+into just a few.  This version must be used for cvc4, and is available
+from the CVC4 apt repository by dropping the following line into your
+/etc/apt/sources.list:
+
+  deb http://goedel.cims.nyu.edu/cvc4-builds/debian unstable/
+
+The debian source package "cudd", available from the same repository,
+includes a diff of all changes made to cudd makefiles.
 
 *** Build dependencies
 
index 66e8acd7dc3279010aa4fb2fbb6aff8e6a5e6507..05e3bac8e19e1d54d031103dd99523d12cae39b0 100644 (file)
@@ -662,6 +662,49 @@ AC_SEARCH_LIBS([clock_gettime], [rt],
                           [Defined to 1 if clock_gettime() is supported by the platform.])],
                [AC_LIBOBJ([clock_gettime])])
 
+AC_ARG_WITH([cudd-dir],
+  [AS_HELP_STRING([--with-cudd-dir=DIR], [path to cudd installation])],
+  [CUDD_DIR="$withval"])
+if test -z "$CUDD_DIR"; then
+  CUDD_DIR=/usr
+fi
+AC_MSG_CHECKING([for cudd includes under $CUDD_DIR])
+CUDD_CPPFLAGS=
+CUDD_LDFLAGS=
+cvc4cudd=no
+result="not found"
+for cuddinc in "$CUDD_DIR/include" "$CUDD_DIR/include/cudd" "$CUDD_DIR"; do
+  if test -r "$cuddinc/cudd.h"; then
+    dnl TODO - should do a TRY_COMPILE instead
+    CUDD_CPPFLAGS="\"-I$cuddinc\""
+    result="$cuddinc"
+    cvc4cudd=yes
+    break
+  fi
+done
+AC_MSG_RESULT([$result])
+if test $cvc4cudd = yes; then
+  AC_MSG_CHECKING([for cudd libraries under $CUDD_DIR])
+  cvc4cudd=no
+  result="not found"
+  for cuddlib in "$CUDD_DIR/lib" "$CUDD_DIR/lib/cudd" "$CUDD_DIR"; do
+    if test -r "$cuddlib/libcuddxx.la"; then
+      dnl TODO - should do a TRY_LINK instead, that has the extra benefit
+      dnl of making sure both shared & static work
+      CUDD_LDFLAGS="\"-L$cuddlib\" -lcuddxx"
+      result="$cuddlib"
+      cvc4cudd=yes
+      break
+    fi
+  done
+  AC_MSG_RESULT([$result]);
+  if test $cvc4cudd = yes; then
+    AC_DEFINE_UNQUOTED(CVC4_CUDD, [], [Defined if using the CU Decision Diagram package (cudd).])
+  fi
+fi
+AC_SUBST([CUDD_CPPFLAGS])
+AC_SUBST([CUDD_LDFLAGS])
+
 # Check for antlr C++ runtime (defined in config/antlr.m4)
 AC_LIB_ANTLR
 
index ef6aedd156f70da3228554fc1c262f4f1b63c623..00357cadf4a5f16ca3a3a6979b2c0d02eb5b41b3 100755 (executable)
@@ -2,7 +2,7 @@
 #
 # addsourcedir
 # Morgan Deters <mdeters@cs.nyu.edu> for the CVC4 project
-# Copyright (c) 2010  The CVC4 Project
+# Copyright (c) 2010, 2011  The CVC4 Project
 #
 # usage: addsourcedir paths...
 #
index 09771676e2b7ddd6de80597bb053bb48db88032d..9da584d36f9d6d12c385771a736848e709eb425e 100755 (executable)
@@ -2,7 +2,7 @@
 #
 # configure-in-place
 # Morgan Deters <mdeters@cs.nyu.edu> for CVC4
-# Copyright (c) 2010  The CVC4 Project
+# Copyright (c) 2010, 2011  The CVC4 Project
 #
 # usage: configure-in-place [ arguments... ]
 #
diff --git a/contrib/debug-keys b/contrib/debug-keys
new file mode 100755 (executable)
index 0000000..6d28049
--- /dev/null
@@ -0,0 +1,33 @@
+#!/bin/bash
+#
+# Lists the Trace() and Debug() keys used in sources.
+#
+# e.g. if Debug("uf") occurs in the sources, then "uf" is printed by this script.
+
+if [ "$1" = "-h" -o "$1" = "-help" -o "$1" = "-?" -o "$1" = "--help" ]; then
+  echo "usage: `basename $0` [dirs...]" >&2
+  echo "This utility will print all Debug("foo") and Trace("foo") keys."
+  echo "With optional dirs..., use dirs instead of top-level \"src\"." >&2
+  exit 1
+fi
+
+if [ $# -eq 0 ]; then
+  cd `dirname "$0"`/..
+
+  if ! [ -d src ]; then
+    echo "`basename $0`: not in CVC4 directory tree?!" >&2
+    exit 1
+  fi
+
+  set src
+fi
+
+echo "Trace and debug flags used in $*:"
+
+while [ $# -gt 0 ]; do
+  dir="$1"
+  shift
+
+  test -r "$dir" && grep -r --exclude-dir=.svn '\(Debug\|Trace\)\(\.isOn\)\?("[^"]\+")' "$dir" | sed 's,.*\(Debug\|Trace\)\(\.isOn\)\?("\([^"]\+\)").*,\3,' | sort -u
+done | sort -u
+
index 6c1e0eeeaea93f4cf8d957590364aae77e39f20e..701768119e49bfa1e929ef886763dff67f22ca69 100755 (executable)
@@ -1,7 +1,7 @@
 #!/usr/bin/perl -w
 # DIMACS to SMT
 # Morgan Deters
-# Copyright (c) 2009, 2010  The CVC4 Project
+# Copyright (c) 2009, 2010, 2011  The CVC4 Project
 
 use strict;
 
index dbe878d6bff20252886c092402fa8952c218abab..ef6abff8efd3123e4a078d6a1edf344b71af20bf 100755 (executable)
@@ -2,7 +2,7 @@
 #
 # get-authors
 # Morgan Deters <mdeters@cs.nyu.edu> for CVC4
-# Copyright (c) 2009, 2010  The CVC4 Project
+# Copyright (c) 2009, 2010, 2011  The CVC4 Project
 #
 # usage: get-authors [ files... ]
 #
index 453eaf5c4aa049604d2cffd6092ba8e56879f1d9..d357c869ef8d96a386a1a3312bcd92d0896ba6d1 100644 (file)
@@ -34,6 +34,8 @@ class NodeManager;
 class ExprManager;
 class TypeNode;
 
+class SmtEngine;
+
 template <bool ref_count>
 class NodeTemplate;
 
@@ -69,7 +71,6 @@ std::ostream& operator<<(std::ostream& out, const Type& t) CVC4_PUBLIC;
 class CVC4_PUBLIC Type {
 
   friend class SmtEngine;
-  friend class SmtEnginePrivate;
   friend class ExprManager;
   friend class TypeNode;
   friend class TypeHashStrategy;
index 2cdba2d279a7a32be5448abb0702187ba7c92f6c..30be07d7c511734b1152ec594d6bb83b3b835c06 100644 (file)
@@ -11,7 +11,7 @@ libprop_la_SOURCES = \
        prop_engine.cpp \
        prop_engine.h \
        sat.h \
-        sat.cpp \
+       sat.cpp \
        cnf_stream.h \
        cnf_stream.cpp
 
index 273b2322a299f4fcd0471daca9ce8ccb9e92cef2..fe5e55ae6ebf9824e38f9e457fef2de8047b8f32 100644 (file)
@@ -530,7 +530,7 @@ Result SmtEngine::query(const BoolExpr& e) {
   d_queryMade = true;
   ensureBoolean(e);// ensure expr is type-checked at this point
   internalPush();
-  SmtEnginePrivate::addFormula(*this, e.getNode().notNode());
+  smt::SmtEnginePrivate::addFormula(*this, e.getNode().notNode());
   Result r = check().asValidityResult();
   internalPop();
   d_status = r;
@@ -547,7 +547,7 @@ Result SmtEngine::assertFormula(const BoolExpr& e) {
   if(d_assertionList != NULL) {
     d_assertionList->push_back(e);
   }
-  SmtEnginePrivate::addFormula(*this, e.getNode());
+  smt::SmtEnginePrivate::addFormula(*this, e.getNode());
   return quickCheck().asValidityResult();
 }
 
@@ -589,7 +589,7 @@ Expr SmtEngine::getValue(const Expr& e)
 
   NodeManagerScope nms(d_nodeManager);
   Node eNode = e.getNode();
-  Node n = SmtEnginePrivate::preprocess(*this, eNode);
+  Node n = smt::SmtEnginePrivate::preprocess(*this, eNode);
 
   Debug("smt") << "--- getting value of " << n << endl;
   Node resultNode = d_theoryEngine->getValue(n);
@@ -655,7 +655,7 @@ SExpr SmtEngine::getAssignment() throw(ModalException, AssertionException) {
       ++i) {
     Assert((*i).getType() == boolType);
 
-    Node n = SmtEnginePrivate::preprocess(*this, *i);
+    Node n = smt::SmtEnginePrivate::preprocess(*this, *i);
 
     Debug("smt") << "--- getting value of " << n << endl;
     Node resultNode = d_theoryEngine->getValue(n);
index 456fdb746d8ff9cce11a11069742ff1c81a81dee..b75140bc72b003156d7703371c0f15b572679846 100644 (file)
@@ -27,6 +27,8 @@
 #include "util/rational.h"
 #include "util/integer.h"
 
+#include "theory/rewriter.h"
+
 #include "theory/arith/arith_utilities.h"
 #include "theory/arith/delta_rational.h"
 #include "theory/arith/partial_model.h"
@@ -79,6 +81,8 @@ TheoryArith::Statistics::Statistics():
   d_staticLearningTimer("theory::arith::staticLearningTimer"),
   d_permanentlyRemovedVariables("theory::arith::permanentlyRemovedVariables", 0),
   d_presolveTime("theory::arith::presolveTime"),
+  d_miplibtrickApplications("theory::arith::miplibtrickApplications", 0),
+  d_avgNumMiplibtrickValues("theory::arith::avgNumMiplibtrickValues"),
   d_initialTableauDensity("theory::arith::initialTableauDensity", 0.0),
   d_avgTableauDensityAtRestart("theory::arith::avgTableauDensityAtRestarts"),
   d_tableauResets("theory::arith::tableauResets", 0),
@@ -93,6 +97,9 @@ TheoryArith::Statistics::Statistics():
   StatisticsRegistry::registerStat(&d_permanentlyRemovedVariables);
   StatisticsRegistry::registerStat(&d_presolveTime);
 
+  StatisticsRegistry::registerStat(&d_miplibtrickApplications);
+  StatisticsRegistry::registerStat(&d_avgNumMiplibtrickValues);
+
   StatisticsRegistry::registerStat(&d_initialTableauDensity);
   StatisticsRegistry::registerStat(&d_avgTableauDensityAtRestart);
   StatisticsRegistry::registerStat(&d_tableauResets);
@@ -109,19 +116,43 @@ TheoryArith::Statistics::~Statistics(){
   StatisticsRegistry::unregisterStat(&d_permanentlyRemovedVariables);
   StatisticsRegistry::unregisterStat(&d_presolveTime);
 
+  StatisticsRegistry::unregisterStat(&d_miplibtrickApplications);
+  StatisticsRegistry::unregisterStat(&d_avgNumMiplibtrickValues);
+
   StatisticsRegistry::unregisterStat(&d_initialTableauDensity);
   StatisticsRegistry::unregisterStat(&d_avgTableauDensityAtRestart);
   StatisticsRegistry::unregisterStat(&d_tableauResets);
   StatisticsRegistry::unregisterStat(&d_restartTimer);
 }
 
+#include "util/propositional_query.h"
 void TheoryArith::staticLearning(TNode n, NodeBuilder<>& learned) {
   TimerStat::CodeTimer codeTimer(d_statistics.d_staticLearningTimer);
 
+  /*
+  if(Debug.isOn("prop::static")){
+    Debug("prop::static") << n << "is "
+                          << prop::PropositionalQuery::isSatisfiable(n)
+                          << endl;
+  }
+  */
+
   vector<TNode> workList;
   workList.push_back(n);
   __gnu_cxx::hash_set<TNode, TNodeHashFunction> processed;
 
+  //Contains an underapproximation of nodes that must hold.
+  __gnu_cxx::hash_set<TNode, TNodeHashFunction> defTrue;
+
+  /* Maps a variable, x, to the set of defTrue nodes of the form
+   *  (=> _ (= x c))
+   * where c is a constant.
+   */
+  typedef __gnu_cxx::hash_map<TNode, set<TNode>, TNodeHashFunction> VarToNodeSetMap;
+  VarToNodeSetMap miplibTrick;
+
+  defTrue.insert(n);
+
   while(!workList.empty()) {
     n = workList.back();
 
@@ -133,6 +164,11 @@ void TheoryArith::staticLearning(TNode n, NodeBuilder<>& learned) {
         unprocessedChildren = true;
       }
     }
+    if(n.getKind() == AND && defTrue.find(n) != defTrue.end() ){
+      for(TNode::iterator i = n.begin(), iend = n.end(); i != iend; ++i) {
+        defTrue.insert(*i);
+      }
+    }
 
     if(unprocessedChildren) {
       continue;
@@ -202,6 +238,105 @@ void TheoryArith::staticLearning(TNode n, NodeBuilder<>& learned) {
       Debug("arith::mins") << n << " is a constant sandwich"  << nGeqMin << nLeqMax << endl;
       learned << nGeqMin << nLeqMax;
     }
+    // == 3-FINITE VALUE SET : Collect information ==
+    if(n.getKind() == IMPLIES &&
+       n[1].getKind() == EQUAL &&
+       n[1][0].getMetaKind() == metakind::VARIABLE &&
+       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];
+        if(miplibTrick.find(var)  == miplibTrick.end()){
+          //[MGD] commented out following line as per TAK's instructions
+          //miplibTrick.insert(make_pair(var, set<TNode>()));
+        }
+        //[MGD] commented out following line as per TAK's instructions
+        //miplibTrick[var].insert(n);
+        Debug("arith::miplib") << "insert " << var  << " const " << n << endl;
+      }
+    }
+  }
+
+  // == 3-FINITE VALUE SET ==
+  VarToNodeSetMap::iterator i = miplibTrick.begin(), endMipLibTrick = miplibTrick.end();
+  for(; i != endMipLibTrick; ++i){
+    TNode var = i->first;
+    const set<TNode>& imps = i->second;
+
+    Assert(!imps.empty());
+    vector<Node> conditions;
+    vector<Rational> valueCollection;
+    set<TNode>::const_iterator j=imps.begin(), impsEnd=imps.end();
+    for(; j != impsEnd; ++j){
+      TNode imp = *j;
+      Assert(imp.getKind() == IMPLIES);
+      Assert(defTrue.find(imp) != defTrue.end());
+      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]);
+      valueCollection.push_back(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)){
+      Debug("arith::miplib") << var << " found a tautology!"<< endl;
+
+      set<Rational> values(valueCollection.begin(), valueCollection.end());
+      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;
+      }
+    }
   }
 }
 
index 3ff83abdfffa203c5ebfefb6264e1e86765a0298..1dcdceab0acb993a06d65f60d56c14b4a6bc8e81 100644 (file)
@@ -237,6 +237,9 @@ private:
     IntStat d_permanentlyRemovedVariables;
     TimerStat d_presolveTime;
 
+    IntStat d_miplibtrickApplications;
+    AverageStat d_avgNumMiplibtrickValues;
+
     BackedStat<double> d_initialTableauDensity;
     AverageStat d_avgTableauDensityAtRestart;
     IntStat d_tableauResets;
index 4f853b9e36a6805a6f41600e4bbf70836730d5af..c94d208d220c1442a79aa86035c7d8c58ac4567a 100644 (file)
@@ -3,7 +3,12 @@ AM_CPPFLAGS = \
        -I@srcdir@/../include -I@srcdir@/.. -I@builddir@/..
 AM_CXXFLAGS = -Wall -Wno-unknown-pragmas $(FLAG_VISIBILITY_HIDDEN)
 
-noinst_LTLIBRARIES = libutil.la
+noinst_LTLIBRARIES = libutil.la libutilcudd.la
+
+# libutilcudd.la is a separate library so that we can pass separate
+# compiler flags
+libutilcudd_la_CPPFLAGS = $(CPPFLAGS) $(AM_CPPFLAGS) @CUDD_CPPFLAGS@
+libutilcudd_la_LIBADD = @CUDD_LDFLAGS@
 
 libutil_la_SOURCES = \
        Assert.h \
@@ -34,6 +39,11 @@ libutil_la_SOURCES = \
        dynamic_array.h \
        language.h \
        triple.h
+libutil_la_LIBADD = \
+       @builddir@/libutilcudd.la
+libutilcudd_la_SOURCES = \
+       propositional_query.h \
+       propositional_query.cpp
 
 BUILT_SOURCES = \
        rational.h \
index 8cd824b0c3eee89ec3e2f4cfb18e996b585fdc53..94ade5a52eb355d68feeb381d85e09eeca693c6a 100644 (file)
@@ -96,6 +96,10 @@ bool Configuration::isBuiltWithCln() {
   return IS_CLN_BUILD;
 }
 
+bool Configuration::isBuiltWithCudd() {
+  return IS_CUDD_BUILD;
+}
+
 bool Configuration::isBuiltWithTlsSupport() {
   return USING_TLS;
 }
index a9d59a7fed5adcb4be79d8deea3b4cf4a56c9e79..150354c29f0c4c0c875c77dd30221021a551d4f1 100644 (file)
@@ -71,6 +71,8 @@ public:
 
   static bool isBuiltWithCln();
 
+  static bool isBuiltWithCudd();
+
   static bool isBuiltWithTlsSupport();
 };
 
index 56423e7d5a7e388597265a4f37bce2b5d293f762..c0ce86c977dcb6eebda436d116602598fd2d196c 100644 (file)
@@ -70,6 +70,12 @@ namespace CVC4 {
 #  define IS_COMPETITION_BUILD false
 #endif /* CVC4_COMPETITION_MODE */
 
+#ifdef CVC4_CUDD
+#  define IS_CUDD_BUILD true
+#else /* CVC4_CUDD */
+#  define IS_CUDD_BUILD false
+#endif /* CVC4_CUDD */
+
 #ifdef CVC4_GMP_IMP
 #  define IS_GMP_BUILD true
 #else /* CVC4_GMP_IMP */
@@ -90,7 +96,7 @@ namespace CVC4 {
 
 #define CVC4_ABOUT_STRING string("\
 This is CVC4 version " CVC4_RELEASE_STRING "\n\n\
-Copyright (C) 2009, 2010\n\
+Copyright (C) 2009, 2010, 2011\n\
   The ACSys Group\n\
   Courant Institute of Mathematical Sciences\n\
   New York University\n\
index 0c3915d1dd8c37b52ef3d41c3c50bc0662a02176..6fc71bae38f8d210c6ed4af485a19b460731ec06 100644 (file)
@@ -416,6 +416,11 @@ throw(OptionException) {
       printf("coverage   : %s\n", Configuration::isCoverageBuild() ? "yes" : "no");
       printf("profiling  : %s\n", Configuration::isProfilingBuild() ? "yes" : "no");
       printf("competition: %s\n", Configuration::isCompetitionBuild() ? "yes" : "no");
+      printf("\n");
+      printf("cudd       : %s\n", Configuration::isBuiltWithCudd() ? "yes" : "no");
+      printf("cln        : %s\n", Configuration::isBuiltWithCln() ? "yes" : "no");
+      printf("gmp        : %s\n", Configuration::isBuiltWithGmp() ? "yes" : "no");
+      printf("tls        : %s\n", Configuration::isBuiltWithTlsSupport() ? "yes" : "no");
       exit(0);
 
     case '?':
diff --git a/src/util/propositional_query.cpp b/src/util/propositional_query.cpp
new file mode 100644 (file)
index 0000000..0678969
--- /dev/null
@@ -0,0 +1,228 @@
+/*********************                                                        */
+/*! \file propositional_query.cpp
+ ** \verbatim
+ ** Original author: taking
+ ** Major contributors: mdeters
+ ** 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 A class for simple, quick, propositional
+ ** satisfiability/validity checking
+ **
+ ** PropositionalQuery is a way for parts of CVC4 to do quick purely
+ ** propositional satisfiability or validity checks on a Node.  These
+ ** checks do no theory reasoning, and handle atoms as propositional
+ ** variables, but can sometimes be useful for subqueries.
+ **/
+
+#include "util/propositional_query.h"
+
+#include <map>
+#include <algorithm>
+
+using namespace std;
+using namespace CVC4;
+using namespace CVC4::kind;
+
+#ifdef CVC4_CUDD
+
+#include <util.h>
+#include <cudd.h>
+#include <cuddObj.hh>
+
+namespace CVC4 {
+
+class BddInstance {
+private:
+  Cudd d_mgr;
+  typedef std::map<Node, BDD> AtomToIDMap;
+  AtomToIDMap d_atomToBddMap;
+
+  unsigned d_atomId;
+
+  BDD encodeNode(TNode t);
+  BDD encodeAtom(TNode t);
+  BDD encodeCombinator(TNode t);
+
+  bool isAnAtom(TNode t) {
+    switch(t.getKind()) {
+    case NOT:
+    case XOR:
+    case IFF:
+    case IMPLIES:
+    case OR:
+    case AND:
+      return false;
+    case ITE:
+      return t.getType().isBoolean();
+    default:
+      return true;
+    }
+  }
+
+  void setupAtoms(TNode t);
+
+  void clear() {
+    d_atomId = 0;
+    d_atomToBddMap.clear();
+  }
+
+  Result d_result;
+
+public:
+  static const unsigned MAX_VARIABLES = 20;
+
+  BddInstance(TNode t) : d_atomToBddMap(), d_atomId(0) {
+    setupAtoms(t);
+
+    Debug("bdd::sat") << t << endl;
+    Debug("bdd::sat") << d_atomToBddMap.size() << endl;
+
+
+    if(d_atomToBddMap.size() > MAX_VARIABLES) {
+      d_result = Result(Result::SAT_UNKNOWN, Result::TIMEOUT);
+    } else {
+      BDD res = encodeNode(t);
+      BDD falseBdd = d_mgr.bddZero();
+      bool isUnsat = (res == falseBdd);
+
+      clear();
+
+      if(isUnsat) {
+        d_result = Result::UNSAT;
+      } else {
+        d_result = Result::SAT;
+      }
+    }
+  }
+
+  Result getResult() const { return d_result; }
+
+};/* class BddInstance */
+
+}/* CVC4 namespace */
+
+BDD BddInstance::encodeNode(TNode t) {
+  if(isAnAtom(t)) {
+    return encodeAtom(t);
+  } else {
+    return encodeCombinator(t);
+  }
+}
+
+BDD BddInstance::encodeCombinator(TNode t) {
+  switch(t.getKind()) {
+  case XOR: {
+    Assert(t.getNumChildren() == 2);
+    return encodeNode(t[0]).Xor(encodeNode(t[1]));
+  }
+
+  case IFF: {
+    Assert(t.getNumChildren() == 2);
+    BDD left = encodeNode(t[0]);
+    BDD right = encodeNode(t[1]);
+    return (!left | right) & (left | !right);
+  }
+
+  case IMPLIES: {
+    Assert(t.getNumChildren() == 2);
+    BDD left = encodeNode(t[0]);
+    BDD right = encodeNode(t[1]);
+    return (!left | right);
+  }
+
+  case AND:
+  case OR: {
+    Assert(t.getNumChildren() >= 2);
+    TNode::iterator i = t.begin(), end = t.end();
+    BDD tmp = encodeNode(*i);
+    ++i;
+    for(; i != end; ++i) {
+      BDD curr = encodeNode(*i);
+      if(t.getKind() == AND) {
+        tmp = tmp & curr;
+      } else {
+        tmp = tmp | curr;
+      }
+    }
+    return tmp;
+  }
+
+  case ITE: {
+    Assert(t.getType().isBoolean());
+    BDD cnd = encodeNode(t[0]);
+    BDD thenBranch = encodeNode(t[1]);
+    BDD elseBranch = encodeNode(t[2]);
+    return cnd.Ite(thenBranch, elseBranch);
+  }
+
+  case NOT:
+    return ! encodeNode(t[0]);
+
+  default:
+    Unhandled(t.getKind());
+  }
+}
+
+BDD BddInstance::encodeAtom(TNode t) {
+  if(t.getKind() == kind::CONST_BOOLEAN) {
+    if(t.getConst<bool>()) {
+      return d_mgr.bddOne();
+    } else {
+      return d_mgr.bddZero();
+    }
+  }
+  Assert(t.getKind() != kind::CONST_BOOLEAN);
+
+  AtomToIDMap::iterator findT = d_atomToBddMap.find(t);
+
+  Assert(d_atomToBddMap.find(t) != d_atomToBddMap.end());
+  return findT->second;
+}
+
+void BddInstance::setupAtoms(TNode t) {
+  if(t.getKind() == kind::CONST_BOOLEAN) {
+    // do nothing
+  } else if(isAnAtom(t)) {
+    AtomToIDMap::iterator findT = d_atomToBddMap.find(t);
+    if(findT == d_atomToBddMap.end()) {
+      BDD var = d_mgr.bddVar();
+      d_atomToBddMap.insert(make_pair(t, var));
+      d_atomId++;
+    }
+  } else {
+    for(TNode::iterator i = t.begin(), end = t.end(); i != end; ++i) {
+      setupAtoms(*i);
+    }
+  }
+}
+
+Result PropositionalQuery::isSatisfiable(TNode q) {
+  BddInstance instance(q);
+  return instance.getResult();
+}
+
+Result PropositionalQuery::isTautology(TNode q) {
+  Node negQ = q.notNode();
+  Result satResult = isSatisfiable(negQ);
+  return satResult.asValidityResult();
+}
+
+#else /* CVC4_CUDD */
+
+// if CUDD wasn't available at build time, just return UNKNOWN everywhere.
+
+Result PropositionalQuery::isSatisfiable(TNode q) {
+  return Result(Result::SAT_UNKNOWN, Result::UNSUPPORTED);
+}
+
+Result PropositionalQuery::isTautology(TNode q) {
+  return Result(Result::VALIDITY_UNKNOWN, Result::UNSUPPORTED);
+}
+
+#endif /* CVC4_CUDD */
diff --git a/src/util/propositional_query.h b/src/util/propositional_query.h
new file mode 100644 (file)
index 0000000..f520f14
--- /dev/null
@@ -0,0 +1,66 @@
+/*********************                                                        */
+/*! \file propositional_query.h
+ ** \verbatim
+ ** Original author: taking
+ ** Major contributors: mdeters
+ ** 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 A class for simple, quick, propositional
+ ** satisfiability/validity checking
+ **
+ ** PropositionalQuery is a way for parts of CVC4 to do quick purely
+ ** propositional satisfiability or validity checks on a Node.  These
+ ** checks do no theory reasoning, and handle atoms as propositional
+ ** variables, but can sometimes be useful for subqueries.
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef __CVC4__PROPOSITIONAL_QUERY_H
+#define __CVC4__PROPOSITIONAL_QUERY_H
+
+#include "expr/node.h"
+#include "util/result.h"
+
+namespace CVC4 {
+
+/**
+ * PropositionalQuery is a way for parts of CVC4 to do quick purely
+ * propositional satisfiability or validity checks on a Node.
+ */
+class PropositionalQuery {
+public:
+
+  /**
+   * Returns whether a node q is propositionally satisfiable.
+   *
+   * @params q Node to be checked for satisfiability.
+   * @params e A number representing the effort to use between 0 (minimum effort),
+   *  and 1 (maximum effort).
+   * @precondition q is a ground formula.
+   * @precondition effort is between 0 and 1.
+   */
+  static Result isSatisfiable(TNode q);
+
+  /**
+   * Returns whether a node q is a propositional tautology.
+   *
+   * @params q Node to be checked for satisfiability.
+   * @params e A number representing the effort to use between 0 (minimum effort),
+   *  and 1 (maximum effort).
+   * @precondition q is a ground formula.
+   * @precondition effort is between 0 and 1.
+   */
+  static Result isTautology(TNode q);
+
+};/* class PropositionalQuery */
+
+}/* CVC4 namespace */
+
+#endif /* __CVC4__PROPOSITIONAL_QUERY_H */
index 1e07293321b59f94506d6a9e5946d969e467c253..7da1dc0b799c46aa55804264b249d236d3357e6b 100644 (file)
@@ -61,6 +61,7 @@ public:
     TIMEOUT,
     MEMOUT,
     NO_STATUS,
+    UNSUPPORTED,
     OTHER,
     UNKNOWN_REASON
   };
index 4dbf31120bb02b84a2c55a80ab97a3128ffd9c78..a78070de4a3fcdec19b7b3bb84c4965ebf28d85e 100644 (file)
@@ -43,6 +43,8 @@ namespace CVC4 {
 
 class CVC4_PUBLIC Stat;
 
+inline std::ostream& operator<<(std::ostream& os, const ::timespec& t);
+
 /**
  * The main statistics registry.  This registry maintains the list of
  * currently active statistics and is able to "flush" them all.
index 91b1d41c75b7c9b1c248c661afcb56e34cac205c..aca076d9fdc6f153a4f7864afa000a992865e3ee 100644 (file)
@@ -8,7 +8,8 @@ TESTS = \
        arith.02.cvc \
        arith.03.cvc \
        delta-minimized-row-vector-bug.smt \
-       leq.01.smt
+       leq.01.smt \
+       miplibtrick.smt
 
 EXTRA_DIST = $(TESTS)
 
diff --git a/test/regress/regress0/arith/miplibtrick.smt b/test/regress/regress0/arith/miplibtrick.smt
new file mode 100644 (file)
index 0000000..93cd6d2
--- /dev/null
@@ -0,0 +1,11 @@
+(benchmark miplibtrick
+  :status sat
+  :logic QF_LRA
+  :extrafuns ((tmp1 Real))
+  :extrapreds ((x177))
+
+  :formula( and
+    ( implies ( and ( not x177 ) true ) ( = tmp1 0 ) )
+    ( implies ( and x177 true ) ( = tmp1 (~ 350) ) )
+  )
+)