Merging CAV14 paper bit-vector work.
authorlianah <lianahady@gmail.com>
Tue, 10 Jun 2014 17:48:45 +0000 (13:48 -0400)
committerlianah <lianahady@gmail.com>
Tue, 10 Jun 2014 17:48:45 +0000 (13:48 -0400)
63 files changed:
configure.ac
contrib/run-script-smtcomp2014
src/Makefile.am
src/main/command_executor_portfolio.cpp
src/main/portfolio.cpp
src/prop/bvminisat/bvminisat.cpp
src/prop/bvminisat/bvminisat.h
src/prop/bvminisat/core/Solver.cc
src/prop/bvminisat/core/Solver.h
src/prop/bvminisat/simp/SimpSolver.cc
src/prop/bvminisat/simp/SimpSolver.h
src/prop/cnf_stream.cpp
src/prop/sat_solver_factory.cpp
src/prop/sat_solver_factory.h
src/smt/options_handlers.h
src/smt/smt_engine.cpp
src/theory/bv/abstraction.cpp [new file with mode: 0644]
src/theory/bv/abstraction.h [new file with mode: 0644]
src/theory/bv/aig_bitblaster.h [new file with mode: 0644]
src/theory/bv/bitblast_mode.cpp [new file with mode: 0644]
src/theory/bv/bitblast_mode.h [new file with mode: 0644]
src/theory/bv/bitblast_strategies.cpp [deleted file]
src/theory/bv/bitblast_strategies.h [deleted file]
src/theory/bv/bitblast_strategies_template.h [new file with mode: 0644]
src/theory/bv/bitblast_utils.h [new file with mode: 0644]
src/theory/bv/bitblaster.cpp [deleted file]
src/theory/bv/bitblaster.h [deleted file]
src/theory/bv/bitblaster_template.h [new file with mode: 0644]
src/theory/bv/bv_eager_solver.cpp [new file with mode: 0644]
src/theory/bv/bv_eager_solver.h [new file with mode: 0644]
src/theory/bv/bv_quick_check.cpp [new file with mode: 0644]
src/theory/bv/bv_quick_check.h [new file with mode: 0644]
src/theory/bv/bv_subtheory.h
src/theory/bv/bv_subtheory_algebraic.cpp [new file with mode: 0644]
src/theory/bv/bv_subtheory_algebraic.h [new file with mode: 0644]
src/theory/bv/bv_subtheory_bitblast.cpp
src/theory/bv/bv_subtheory_bitblast.h
src/theory/bv/bv_subtheory_core.cpp
src/theory/bv/bv_subtheory_core.h
src/theory/bv/bv_to_bool.cpp
src/theory/bv/bv_to_bool.h
src/theory/bv/eager_bitblaster.h [new file with mode: 0644]
src/theory/bv/kinds
src/theory/bv/lazy_bitblaster.h [new file with mode: 0644]
src/theory/bv/options
src/theory/bv/options_handlers.h [new file with mode: 0644]
src/theory/bv/slicer.cpp
src/theory/bv/theory_bv.cpp
src/theory/bv/theory_bv.h
src/theory/bv/theory_bv_rewrite_rules.h
src/theory/bv/theory_bv_rewrite_rules_core.h
src/theory/bv/theory_bv_rewrite_rules_normalization.h
src/theory/bv/theory_bv_rewrite_rules_simplification.h
src/theory/bv/theory_bv_rewriter.cpp
src/theory/bv/theory_bv_type_rules.h
src/theory/bv/theory_bv_utils.cpp [new file with mode: 0644]
src/theory/bv/theory_bv_utils.h
src/theory/theory_engine.cpp
src/theory/theory_engine.h
src/theory/unconstrained_simplifier.cpp
src/util/bitvector.h
test/regress/regress0/bv/Makefile.am
test/regress/regress0/bv/divtest.smt2 [new file with mode: 0644]

index 03fbd690c77b9e7419f9b194d29bad5f575c89ab..cfd65aef44745019e1e6560ec5898df5da5e95e3 100644 (file)
@@ -254,6 +254,9 @@ AC_ARG_WITH(
   ]
 )
 
+# [chris 8/24/2010] --with-gmp has no practical effect, since GMP is
+# the default. Could be useful if other options are added later.
+
 AC_ARG_WITH(
   [gmp],
   AS_HELP_STRING(
@@ -745,6 +748,27 @@ fi
 AM_CONDITIONAL([CVC4_USE_GLPK], [test $have_libglpk -eq 1])
 AC_SUBST([GLPK_LIBS])
 
+AC_ARG_WITH(
+  [abc],
+  AS_HELP_STRING(
+    [--with-abc],
+    [use the ABC AIG library]
+  ),
+  [case "$withval" in
+   y|ye|yes|Y|YE|YES) cvc4_use_abc=1 ;;
+   n|no|N|NO) cvc4_use_abc=0 ;;
+   esac
+  ]
+)
+
+if test $cvc4_use_abc -eq 1; then
+   # must add dl and pthread separately and before abc
+   AC_CHECK_LIB(dl, dlopen, , [AC_MSG_ERROR([dl not found])], [])
+   AC_CHECK_LIB(pthread, pthread_create, , [AC_MSG_ERROR([pthread not found])], [])
+   AC_CHECK_LIB(abc, Abc_Start, , [AC_MSG_ERROR([abc not found])], [-lm -ldl -rdynamic -lreadline -ltermcap -lpthread -lrt -ldl])
+   AC_DEFINE_UNQUOTED(CVC4_USE_ABC, [], [Defined if linked against the ABC AIG library.]) 
+fi
+
 # Check to see if this version/architecture of GNU C++ explicitly
 # instantiates __gnu_cxx::hash<uint64_t> or not.  Some do, some don't.
 # See src/util/hash.h.
@@ -1214,7 +1238,7 @@ AC_DEFINE_UNQUOTED(CVC4_RELEASE_STRING, ["${CVC4_RELEASE_STRING}"], [Full releas
 CPPFLAGS="${CPPFLAGS:+$CPPFLAGS }${BOOST_CPPFLAGS:+$BOOST_CPPFLAGS }$CVC4CPPFLAGS"
 CXXFLAGS="${CXXFLAGS:+$CXXFLAGS }$CVC4CXXFLAGS -Wno-deprecated"
 CFLAGS="${CFLAGS:+$CFLAGS }$CVC4CFLAGS -Wno-deprecated -fexceptions"
-LDFLAGS="${LDFLAGS:+$LDFLAGS }$CVC4LDFLAGS"
+LDFLAGS="${LDFLAGS:+$LDFLAGS }$CVC4LDFLAGS -ldl"
 
 # visibility flag not supported for Windows builds
 # also increase default stack size for Windows binaries
index e723df9c7f53b2eb8efb113f836c01360ed39732..af41aab8b58fb13fb4cd59ea72d1be467138c77a 100755 (executable)
@@ -66,7 +66,7 @@ QF_AUFBV)
   finishwith --decision=justification-stoponly
   ;;
 QF_BV)
-  trywith 10 --bv-core --decision=justification
+  trywith 10 --bv-eq-slicer=auto --decision=justification
   trywith 60 --decision=justification
   trywith 600 --decision=internal --bitblast-eager
   finishwith --decision=justification --decision-use-weight --decision-weight-internal=usr1
index ae7cb619a416894b940f03df4e7d87c9ffd24f86..f3bd8582571395baa444e03c23bd26315ff0b308 100644 (file)
@@ -173,9 +173,8 @@ libcvc4_la_SOURCES = \
        theory/uf/theory_uf_model.cpp \
        theory/uf/options_handlers.h \
        theory/bv/theory_bv_utils.h \
+       theory/bv/theory_bv_utils.cpp \
        theory/bv/type_enumerator.h \
-       theory/bv/bitblaster.h \
-       theory/bv/bitblaster.cpp \
        theory/bv/bv_to_bool.h \
        theory/bv/bv_to_bool.cpp \
        theory/bv/bv_subtheory.h \
@@ -187,8 +186,13 @@ libcvc4_la_SOURCES = \
        theory/bv/bv_subtheory_inequality.cpp \
        theory/bv/bv_inequality_graph.h \
        theory/bv/bv_inequality_graph.cpp \
-       theory/bv/bitblast_strategies.h \
-       theory/bv/bitblast_strategies.cpp \
+       theory/bv/bitblast_strategies_template.h \
+       theory/bv/bitblaster_template.h \
+       theory/bv/lazy_bitblaster.h \
+       theory/bv/eager_bitblaster.h \
+       theory/bv/aig_bitblaster.h \
+       theory/bv/bv_eager_solver.h \
+       theory/bv/bv_eager_solver.cpp \
        theory/bv/slicer.h \
        theory/bv/slicer.cpp \
        theory/bv/theory_bv.h \
@@ -203,6 +207,15 @@ libcvc4_la_SOURCES = \
        theory/bv/theory_bv_rewriter.h \
        theory/bv/theory_bv_rewriter.cpp \
        theory/bv/cd_set_collection.h \
+       theory/bv/abstraction.h \
+       theory/bv/abstraction.cpp \
+       theory/bv/bv_quick_check.h \
+       theory/bv/bv_quick_check.cpp \
+       theory/bv/bv_subtheory_algebraic.h \
+       theory/bv/bv_subtheory_algebraic.cpp \
+       theory/bv/options_handlers.h \
+       theory/bv/bitblast_mode.h \
+       theory/bv/bitblast_mode.cpp \
        theory/idl/idl_model.h \
        theory/idl/idl_model.cpp \
        theory/idl/idl_assertion.h \
index 9de3b21347f2c9772e34040f3ccb0122e9792d11..1cc024117ef27b43c0fc20f9c8d879ab45d1219b 100644 (file)
@@ -330,6 +330,12 @@ bool CommandExecutorPortfolio::doCommandSingleton(Command* cmd)
 
       *d_options[options::out]
         << d_ostringstreams[portfolioReturn.first]->str();
+      // FIXME! MASSIVE HACK!!
+      if(d_options[options::statistics]) {
+        pExecutor->flushStatistics(*d_options[options::err]);
+      }
+
+      exit(0);
     }
 
     /* cleanup this check sat specific stuff */
index ebf36b0cdc1ef0bf48b1376dd98a6814a7fee09c..a5fe46d278023a94db70fd1a38fab4caab537cf4 100644 (file)
@@ -95,7 +95,7 @@ std::pair<int, S> runPortfolio(int numThreads,
   for(int t = 0; t < numThreads; ++t) {
     if(optionWaitToJoin) {
       threads[t].join();
-    }
+    } 
   }
 
   std::pair<int, S> retval(global_winner, threads_returnValue[global_winner]);
index fa5f53113021b23c2f6da76e6388d0ae91c09aa5..46b521e6b198bca50ed8b28406a65264b64caa52 100644 (file)
 using namespace CVC4;
 using namespace prop;
 
-BVMinisatSatSolver::BVMinisatSatSolver(context::Context* mainSatContext)
+BVMinisatSatSolver::BVMinisatSatSolver(context::Context* mainSatContext, const std::string& name)
 : context::ContextNotifyObj(mainSatContext, false),
   d_minisat(new BVMinisat::SimpSolver(mainSatContext)),
   d_minisatNotify(0),
   d_solveCount(0),
   d_assertionsCount(0),
   d_assertionsRealCount(mainSatContext, 0),
-  d_lastPropagation(mainSatContext, 0)
+  d_lastPropagation(mainSatContext, 0),
+  d_statistics(name)
 {
   d_statistics.init(d_minisat); 
 }
@@ -61,6 +62,7 @@ SatValue BVMinisatSatSolver::propagate() {
 
 void BVMinisatSatSolver::addMarkerLiteral(SatLiteral lit) {
   d_minisat->addMarkerLiteral(BVMinisat::var(toMinisatLit(lit)));
+  markUnremovable(lit); 
 }
 
 void BVMinisatSatSolver::explain(SatLiteral lit, std::vector<SatLiteral>& explanation) {
@@ -113,9 +115,9 @@ SatValue BVMinisatSatSolver::solve(long unsigned int& resource){
   } else {
     d_minisat->setConfBudget(resource);
   }
-  BVMinisat::vec<BVMinisat::Lit> empty;
+  //  BVMinisat::vec<BVMinisat::Lit> empty;
   unsigned long conflictsBefore = d_minisat->conflicts;
-  SatValue result = toSatLiteralValue(d_minisat->solveLimited(empty));
+  SatValue result = toSatLiteralValue(d_minisat->solveLimited());
   d_minisat->clearInterrupt();
   resource = d_minisat->conflicts - conflictsBefore;
   Trace("limit") << "<MinisatSatSolver::solve(): it took " << resource << " conflicts" << std::endl;
@@ -211,20 +213,24 @@ void BVMinisatSatSolver::toSatClause(BVMinisat::vec<BVMinisat::Lit>& clause,
 
 // Satistics for BVMinisatSatSolver
 
-BVMinisatSatSolver::Statistics::Statistics() :
-  d_statStarts("theory::bv::bvminisat::starts"),
-  d_statDecisions("theory::bv::bvminisat::decisions"),
-  d_statRndDecisions("theory::bv::bvminisat::rnd_decisions"),
-  d_statPropagations("theory::bv::bvminisat::propagations"),
-  d_statConflicts("theory::bv::bvminisat::conflicts"),
-  d_statClausesLiterals("theory::bv::bvminisat::clauses_literals"),
-  d_statLearntsLiterals("theory::bv::bvminisat::learnts_literals"),
-  d_statMaxLiterals("theory::bv::bvminisat::max_literals"),
-  d_statTotLiterals("theory::bv::bvminisat::tot_literals"),
-  d_statEliminatedVars("theory::bv::bvminisat::eliminated_vars"),
-  d_statCallsToSolve("theory::bv::bvminisat::calls_to_solve", 0),
-  d_statSolveTime("theory::bv::bvminisat::solve_time", 0)
+BVMinisatSatSolver::Statistics::Statistics(const std::string& prefix) :
+  d_statStarts("theory::bv::"+prefix+"bvminisat::starts"),
+  d_statDecisions("theory::bv::"+prefix+"bvminisat::decisions"),
+  d_statRndDecisions("theory::bv::"+prefix+"bvminisat::rnd_decisions"),
+  d_statPropagations("theory::bv::"+prefix+"bvminisat::propagations"),
+  d_statConflicts("theory::bv::"+prefix+"bvminisat::conflicts"),
+  d_statClausesLiterals("theory::bv::"+prefix+"bvminisat::clauses_literals"),
+  d_statLearntsLiterals("theory::bv::"+prefix+"bvminisat::learnts_literals"),
+  d_statMaxLiterals("theory::bv::"+prefix+"bvminisat::max_literals"),
+  d_statTotLiterals("theory::bv::"+prefix+"bvminisat::tot_literals"),
+  d_statEliminatedVars("theory::bv::"+prefix+"bvminisat::eliminated_vars"),
+  d_statCallsToSolve("theory::bv::"+prefix+"bvminisat::calls_to_solve", 0),
+  d_statSolveTime("theory::bv::"+prefix+"bvminisat::solve_time", 0),
+  d_registerStats(!prefix.empty())
 {
+  if (!d_registerStats)
+    return;
+
   StatisticsRegistry::registerStat(&d_statStarts);
   StatisticsRegistry::registerStat(&d_statDecisions);
   StatisticsRegistry::registerStat(&d_statRndDecisions);
@@ -240,6 +246,8 @@ BVMinisatSatSolver::Statistics::Statistics() :
 }
 
 BVMinisatSatSolver::Statistics::~Statistics() {
+  if (!d_registerStats)
+    return;
   StatisticsRegistry::unregisterStat(&d_statStarts);
   StatisticsRegistry::unregisterStat(&d_statDecisions);
   StatisticsRegistry::unregisterStat(&d_statRndDecisions);
@@ -255,6 +263,9 @@ BVMinisatSatSolver::Statistics::~Statistics() {
 }
 
 void BVMinisatSatSolver::Statistics::init(BVMinisat::SimpSolver* minisat){
+  if (!d_registerStats)
+    return;
+  
   d_statStarts.setData(minisat->starts);
   d_statDecisions.setData(minisat->decisions);
   d_statRndDecisions.setData(minisat->rnd_decisions);
index ebf4a44b48f8f0477df042a828751ec81e5e46de..568d89f7fd5e3c7104587268d56ef40e2ff8a44c 100644 (file)
@@ -69,9 +69,10 @@ public:
   BVMinisatSatSolver() :
     ContextNotifyObj(NULL, false),
     d_assertionsRealCount(NULL, (unsigned)0),
-    d_lastPropagation(NULL, (unsigned)0)
+    d_lastPropagation(NULL, (unsigned)0),
+    d_statistics("")
   { Unreachable(); }
-  BVMinisatSatSolver(context::Context* mainSatContext);
+  BVMinisatSatSolver(context::Context* mainSatContext, const std::string& name = "");
   ~BVMinisatSatSolver() throw(AssertionException);
 
   void setNotify(Notify* notify);
@@ -91,7 +92,6 @@ public:
   
   SatValue solve();
   SatValue solve(long unsigned int&);
-  SatValue solve(bool quick_solve);
   void getUnsatCore(SatClause& unsatCore);
 
   SatValue value(SatLiteral l);
@@ -129,8 +129,9 @@ public:
     ReferenceStat<uint64_t> d_statTotLiterals;
     ReferenceStat<int> d_statEliminatedVars;
     IntStat d_statCallsToSolve;
-    BackedStat<double> d_statSolveTime; 
-    Statistics();
+    BackedStat<double> d_statSolveTime;
+    bool d_registerStats;
+    Statistics(const std::string& prefix);
     ~Statistics();
     void init(BVMinisat::SimpSolver* minisat);
   };
index 68969c78b7d6560ced50217435b38b5eab0f9e72..8833eec78a126c3aefcc81d95b5d711bf334005c 100644 (file)
@@ -59,19 +59,31 @@ std::ostream& operator << (std::ostream& out, const BVMinisat::Clause& c) {
 
 static const char* _cat = "CORE";
 
+// static DoubleOption  opt_var_decay         (_cat, "var-decay",   "The variable activity decay factor",            0.95,     DoubleRange(0, false, 1, false));
+// static DoubleOption  opt_clause_decay      (_cat, "cla-decay",   "The clause activity decay factor",              0.999,    DoubleRange(0, false, 1, false));
+// static DoubleOption  opt_random_var_freq   (_cat, "rnd-freq",    "The frequency with which the decision heuristic tries to choose a random variable", 0.0, DoubleRange(0, true, 1, true));
+// static DoubleOption  opt_random_seed       (_cat, "rnd-seed",    "Used by the random variable selection",         91648253, DoubleRange(0, false, HUGE_VAL, false));
+// static IntOption     opt_ccmin_mode        (_cat, "ccmin-mode",  "Controls conflict clause minimization (0=none, 1=basic, 2=deep)", 0, IntRange(0, 2));
+// static IntOption     opt_phase_saving      (_cat, "phase-saving", "Controls the level of phase saving (0=none, 1=limited, 2=full)", 2, IntRange(0, 2));
+// static BoolOption    opt_rnd_init_act      (_cat, "rnd-init",    "Randomize the initial activity", false);
+// static BoolOption    opt_luby_restart      (_cat, "luby",        "Use the Luby restart sequence", true);
+// static IntOption     opt_restart_first     (_cat, "rfirst",      "The base restart interval", 100, IntRange(1, INT32_MAX)); 
+// static DoubleOption  opt_restart_inc       (_cat, "rinc",        "Restart interval increase factor", 1.5, DoubleRange(1, false, HUGE_VAL, false));
+// static DoubleOption  opt_garbage_frac      (_cat, "gc-frac",     "The fraction of wasted memory allowed before a garbage collection is triggered",  0.20, DoubleRange(0, false, HUGE_VAL, false));
+
+
 static DoubleOption  opt_var_decay         (_cat, "var-decay",   "The variable activity decay factor",            0.95,     DoubleRange(0, false, 1, false));
 static DoubleOption  opt_clause_decay      (_cat, "cla-decay",   "The clause activity decay factor",              0.999,    DoubleRange(0, false, 1, false));
-static DoubleOption  opt_random_var_freq   (_cat, "rnd-freq",    "The frequency with which the decision heuristic tries to choose a random variable", 0.0, DoubleRange(0, true, 1, true));
+static DoubleOption  opt_random_var_freq   (_cat, "rnd-freq",    "The frequency with which the decision heuristic tries to choose a random variable", 0, DoubleRange(0, true, 1, true));
 static DoubleOption  opt_random_seed       (_cat, "rnd-seed",    "Used by the random variable selection",         91648253, DoubleRange(0, false, HUGE_VAL, false));
-static IntOption     opt_ccmin_mode        (_cat, "ccmin-mode",  "Controls conflict clause minimization (0=none, 1=basic, 2=deep)", 0, IntRange(0, 2));
+static IntOption     opt_ccmin_mode        (_cat, "ccmin-mode",  "Controls conflict clause minimization (0=none, 1=basic, 2=deep)", 2, IntRange(0, 2));
 static IntOption     opt_phase_saving      (_cat, "phase-saving", "Controls the level of phase saving (0=none, 1=limited, 2=full)", 2, IntRange(0, 2));
 static BoolOption    opt_rnd_init_act      (_cat, "rnd-init",    "Randomize the initial activity", false);
 static BoolOption    opt_luby_restart      (_cat, "luby",        "Use the Luby restart sequence", true);
-static IntOption     opt_restart_first     (_cat, "rfirst",      "The base restart interval", 100, IntRange(1, INT32_MAX));
-static DoubleOption  opt_restart_inc       (_cat, "rinc",        "Restart interval increase factor", 1.5, DoubleRange(1, false, HUGE_VAL, false));
+static IntOption     opt_restart_first     (_cat, "rfirst",      "The base restart interval", 25, IntRange(1, INT32_MAX));
+static DoubleOption  opt_restart_inc       (_cat, "rinc",        "Restart interval increase factor", 3, DoubleRange(1, false, HUGE_VAL, false));
 static DoubleOption  opt_garbage_frac      (_cat, "gc-frac",     "The fraction of wasted memory allowed before a garbage collection is triggered",  0.20, DoubleRange(0, false, HUGE_VAL, false));
 
-
 //=================================================================================================
 // Constructor/Destructor:
 
@@ -395,10 +407,8 @@ void Solver::analyze(CRef confl, vec<Lit>& out_learnt, int& out_btlevel, UIP uip
     out_learnt.shrink(i - j);
     tot_literals += out_learnt.size();
 
-    bool clause_all_marker = true;
     for (int i = 0; i < out_learnt.size(); ++ i) {
       if (marker[var(out_learnt[i])] == 0) {
-        clause_all_marker = false;
         break;
       }
     }
@@ -410,9 +420,6 @@ void Solver::analyze(CRef confl, vec<Lit>& out_learnt, int& out_btlevel, UIP uip
     }
     else{
         int max_i = 1;
-        if (marker[var(out_learnt[0])] == 0) {
-          clause_all_marker = false;
-        }
         // Find the first literal assigned at the next-highest level:
         for (int i = 2; i < out_learnt.size(); i++)
             if (level(var(out_learnt[i])) > level(var(out_learnt[max_i])))
@@ -424,10 +431,6 @@ void Solver::analyze(CRef confl, vec<Lit>& out_learnt, int& out_btlevel, UIP uip
         out_btlevel       = level(var(p));
     }
 
-    if (out_learnt.size() > 0 && clause_all_marker && CVC4::options::bitvectorShareLemmas()) {
-      notify->notify(out_learnt);
-    }
-
     for (int j = 0; j < analyze_toclear.size(); j++) seen[var(analyze_toclear[j])] = 0;    // ('seen[]' is now cleared)
 }
 
@@ -462,6 +465,48 @@ bool Solver::litRedundant(Lit p, uint32_t abstract_levels)
     return true;
 }
 
+/** 
+ * Specialized analyzeFinal procedure where we test the consistency
+ * of the assumptions before backtracking bellow the assumption level.
+ * 
+ * @param p the original uip (may be unit)
+ * @param confl_clause the conflict clause
+ * @param out_conflict the conflict in terms of assumptions we are building
+ */
+void Solver::analyzeFinal2(Lit p, CRef confl_clause, vec<Lit>& out_conflict) {
+  assert (confl_clause != CRef_Undef);
+  assert (decisionLevel() == assumptions.size());
+  assert (level(var(p)) == assumptions.size());
+
+  out_conflict.clear(); 
+  
+  Clause& cl = ca[confl_clause];
+  for (int i = 0; i < cl.size(); ++i) {
+    seen[var(cl[i])] = 1;
+  }
+
+  for (int i = trail.size() - 1; i >= trail_lim[0]; i--) {
+    Var x = var(trail[i]);
+    if (seen[x]) {
+      if (reason(x) == CRef_Undef) {
+        // this is the case when p was a unit
+        if (x == var(p))
+          continue;
+        
+        assert (marker[x] == 2);
+        assert (level(x) > 0);
+        out_conflict.push(~trail[i]); 
+      } else {
+        Clause& c = ca[reason(x)];
+        for (int j = 1; j < c.size(); j++)
+          if (level(var(c[j])) > 0)
+            seen[var(c[j])] = 1;
+      }
+      seen[x] = 0;
+    }
+  }
+  assert (out_conflict.size()); 
+}
 
 /*_________________________________________________________________________________________________
 |
@@ -475,7 +520,9 @@ bool Solver::litRedundant(Lit p, uint32_t abstract_levels)
 void Solver::analyzeFinal(Lit p, vec<Lit>& out_conflict)
 {
     out_conflict.clear();
-    out_conflict.push(p);
+    if (marker[var(p)] == 2) {
+      out_conflict.push(p);
+    }
 
     if (decisionLevel() == 0)
         return;
@@ -500,6 +547,7 @@ void Solver::analyzeFinal(Lit p, vec<Lit>& out_conflict)
     }
 
     seen[var(p)] = 0;
+    assert (out_conflict.size());
 }
 
 
@@ -755,28 +803,46 @@ lbool Solver::search(int nof_conflicts, UIP uip)
             analyze(confl, learnt_clause, backtrack_level, uip);
 
             Lit p = learnt_clause[0];
-            bool assumption = marker[var(p)] == 2;
-
-            cancelUntil(backtrack_level);
-
-            if (learnt_clause.size() == 1){
-                uncheckedEnqueue(p);
-            }else{
-                CRef cr = ca.alloc(learnt_clause, true);
-                learnts.push(cr);
-                attachClause(cr);
-                claBumpActivity(ca[cr]);
-                uncheckedEnqueue(p, cr);
+            //bool assumption = marker[var(p)] == 2;
+
+            CRef cr = CRef_Undef;
+            if (learnt_clause.size() > 1) {
+              cr = ca.alloc(learnt_clause, true);
+              learnts.push(cr);
+              attachClause(cr);
+              claBumpActivity(ca[cr]);
             }
 
-            // if an assumption, we're done
-            if (assumption) {
-              assert(decisionLevel() < assumptions.size());
+            //  if the uip was an assumption we are unsat
+            if (level(var(p)) <= assumptions.size()) {
+              for (int i = 0; i < learnt_clause.size(); ++i) {
+                assert (level(var(learnt_clause[i])) <= decisionLevel()); 
+                seen[var(learnt_clause[i])] = 1;
+              }
               analyzeFinal(p, conflict);
               Debug("bvminisat::search") << OUTPUT_TAG << " conflict on assumptions " << std::endl;
               return l_False;
             }
-            
+
+            if (!CVC4::options::bvEagerExplanations()) {
+              // check if uip leads to a conflict 
+              if (backtrack_level < assumptions.size()) {
+                cancelUntil(assumptions.size());
+                uncheckedEnqueue(p, cr);
+              
+                CRef new_confl = propagate();
+                if (new_confl != CRef_Undef) {
+                  // we have a conflict we now need to explain it
+                  analyzeFinal2(p, new_confl, conflict); 
+                  return l_False;
+                }
+              }
+            }
+
+            cancelUntil(backtrack_level);
+            uncheckedEnqueue(p, cr);
+    
+         
             varDecayActivity();
             claDecayActivity();
 
@@ -835,6 +901,7 @@ lbool Solver::search(int nof_conflicts, UIP uip)
                     // Dummy decision level:
                     newDecisionLevel();
                 }else if (value(p) == l_False){
+                    marker[var(p)] = 2;
                     analyzeFinal(~p, conflict);
                     Debug("bvminisat::search") << OUTPUT_TAG << " assumption false, we're unsat" << std::endl;
                     return l_False;
index 53d92ac39ac6890b6b8179392184c596c8426c25..882f23ef78a25338fc99facef7354aabb489c1a8 100644 (file)
@@ -290,6 +290,7 @@ protected:
 
     void     analyze          (CRef confl, vec<Lit>& out_learnt, int& out_btlevel, UIP uip = UIP_FIRST);    // (bt = backtrack)
     void     analyzeFinal     (Lit p, vec<Lit>& out_conflict);                         // COULD THIS BE IMPLEMENTED BY THE ORDINARIY "analyze" BY SOME REASONABLE GENERALIZATION?
+    void     analyzeFinal2(Lit p, CRef confl_clause, vec<Lit>& out_conflict);
     bool     litRedundant     (Lit p, uint32_t abstract_levels);                       // (helper method for 'analyze()')
     lbool    search           (int nof_conflicts, UIP uip = UIP_FIRST);                // Search for a given number of conflicts.
     lbool    solve_           ();                                                      // Main solve method (assumptions given in 'assumptions').
index 59820e9e3499406030c4a786f3ced87ccea96535..c651899856491afffeaf5f13e642bf5a101b6861 100644 (file)
@@ -21,7 +21,8 @@ OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWA
 #include "mtl/Sort.h"
 #include "simp/SimpSolver.h"
 #include "utils/System.h"
-
+#include "theory/bv/options.h"
+#include "smt/options.h"
 using namespace BVMinisat;
 
 //=================================================================================================
@@ -32,7 +33,7 @@ static const char* _cat = "SIMP";
 
 static BoolOption   opt_use_asymm        (_cat, "asymm",        "Shrink clauses by asymmetric branching.", false);
 static BoolOption   opt_use_rcheck       (_cat, "rcheck",       "Check if a clause is already implied. (costly)", false);
-static BoolOption   opt_use_elim         (_cat, "elim",         "Perform variable elimination.", false);
+static BoolOption   opt_use_elim         (_cat, "elim",         "Perform variable elimination.", true);
 static IntOption    opt_grow             (_cat, "grow",         "Allow a variable elimination step to grow by a number of clauses.", 0);
 static IntOption    opt_clause_lim       (_cat, "cl-lim",       "Variables are not eliminated if it produces a resolvent with a length above this limit. -1 means no limit", 20,   IntRange(-1, INT32_MAX));
 static IntOption    opt_subsumption_lim  (_cat, "sub-lim",      "Do not check if subsumption against a clause larger than this. -1 means no limit.", 1000, IntRange(-1, INT32_MAX));
@@ -51,11 +52,12 @@ SimpSolver::SimpSolver(CVC4::context::Context* c) :
   , simp_garbage_frac  (opt_simp_garbage_frac)
   , use_asymm          (opt_use_asymm)
   , use_rcheck         (opt_use_rcheck)
-  , use_elim           (opt_use_elim)
+  , use_elim           (opt_use_elim &&
+                        CVC4::options::bitblastMode() == CVC4::theory::bv::BITBLAST_MODE_EAGER &&
+                        !CVC4::options::produceModels())
   , merges             (0)
   , asymm_lits         (0)
   , eliminated_vars    (0)
-  , total_eliminate_time("theory::bv::bvminisat::TotalVariableEliminationTime")
   , elimorder          (1)
   , use_simplification (true)
   , occurs             (ClauseDeleted(ca))
@@ -63,7 +65,7 @@ SimpSolver::SimpSolver(CVC4::context::Context* c) :
   , bwdsub_assigns     (0)
   , n_touched          (0)
 {
-    CVC4::StatisticsRegistry::registerStat(&total_eliminate_time);
+
     vec<Lit> dummy(1,lit_Undef);
     ca.extra_clause_field = true; // NOTE: must happen before allocating the dummy clause below.
     bwdsub_tmpunit        = ca.alloc(dummy);
@@ -87,7 +89,7 @@ SimpSolver::SimpSolver(CVC4::context::Context* c) :
 
 SimpSolver::~SimpSolver()
 {
-  CVC4::StatisticsRegistry::unregisterStat(&total_eliminate_time); 
+  //  CVC4::StatisticsRegistry::unregisterStat(&total_eliminate_time); 
 }
 
 
@@ -606,7 +608,7 @@ void SimpSolver::extendModel()
 bool SimpSolver::eliminate(bool turn_off_elim)
 {
 
-  CVC4::TimerStat::CodeTimer codeTimer(total_eliminate_time);
+  //  CVC4::TimerStat::CodeTimer codeTimer(total_eliminate_time);
   
     if (!simplify())
         return false;
index 4af82b02d0f9f394bf83adab49afe53b92524f4c..d808daa226c01dfbd9bd95b42d6b6677bfcd12b5 100644 (file)
@@ -58,6 +58,7 @@ class SimpSolver : public Solver {
     //
     bool    solve       (const vec<Lit>& assumps, bool do_simp = true, bool turn_off_simp = false);
     lbool   solveLimited(const vec<Lit>& assumps, bool do_simp = true, bool turn_off_simp = false);
+    lbool   solveLimited(bool do_simp = true, bool turn_off_simp = false);
     bool    solve       (                     bool do_simp = true, bool turn_off_simp = false);
     bool    solve       (Lit p       ,        bool do_simp = true, bool turn_off_simp = false);       
     bool    solve       (Lit p, Lit q,        bool do_simp = true, bool turn_off_simp = false);
@@ -96,7 +97,7 @@ class SimpSolver : public Solver {
     int     merges;
     int     asymm_lits;
     int     eliminated_vars;
-    CVC4::TimerStat total_eliminate_time;
+  //    CVC4::TimerStat total_eliminate_time;
 
  protected:
 
@@ -195,6 +196,9 @@ inline bool SimpSolver::solve        (const vec<Lit>& assumps, bool do_simp, boo
 inline lbool SimpSolver::solveLimited (const vec<Lit>& assumps, bool do_simp, bool turn_off_simp){ 
     assumps.copyTo(assumptions); return solve_(do_simp, turn_off_simp); }
 
+inline lbool SimpSolver::solveLimited (bool do_simp, bool turn_off_simp){ 
+    return solve_(do_simp, turn_off_simp); }
+
 //=================================================================================================
 }
 
index 47d352949bab154271d07317468e95ba092b0dc0..3d2c29798525a0db91fda7323bbcd0ce8e8a9557 100644 (file)
@@ -228,12 +228,6 @@ SatLiteral CnfStream::convertAtom(TNode node) {
     theoryLiteral = true;
     canEliminate = false;
     preRegister = true;
-
-    if (options::bitvectorEagerBitblast() && theory::Theory::theoryOf(node) == theory::THEORY_BV) {
-      // All BV atoms are treated as boolean except for equality
-      theoryLiteral = false;
-      canEliminate = true;
-    }
   }
 
   // Make a new literal (variables are not considered theory literals)
index 6cda02c00fd2e397e26ae7dc07d29eb3d0320466..e937c718ccf20a05fdf1e511b8b1942cb9a4a6a4 100644 (file)
@@ -25,8 +25,8 @@ namespace prop {
 template class SatSolverConstructor<MinisatSatSolver>;
 template class SatSolverConstructor<BVMinisatSatSolver>;
 
-BVSatSolverInterface* SatSolverFactory::createMinisat(context::Context* mainSatContext) {
-  return new BVMinisatSatSolver(mainSatContext);
+BVSatSolverInterface* SatSolverFactory::createMinisat(context::Context* mainSatContext, const std::string& name) {
+  return new BVMinisatSatSolver(mainSatContext, name);
 }
 
 DPLLSatSolverInterface* SatSolverFactory::createDPLLMinisat() {
index 7d3a45c59f1923d484c30663d09fb1c8d54cb1dc..291609de7ff81a34e1db9a180813c1f5dfcccd56 100644 (file)
@@ -28,7 +28,7 @@ namespace prop {
 class SatSolverFactory {
 public:
 
-  static BVSatSolverInterface* createMinisat(context::Context* mainSatContext);
+  static BVSatSolverInterface* createMinisat(context::Context* mainSatContext, const std::string& name = "");
   static DPLLSatSolverInterface* createDPLLMinisat();
 
   static SatSolver* create(const char* id);
index 058a00f32ebc89f984915b6cddb7ed9d7160d546..af8e8663c8454dc0c9d2af26b31e1914664a4909 100644 (file)
@@ -121,7 +121,13 @@ t-explanations [non-stateful]\n\
 bv-rewrites [non-stateful]\n\
 + Output correctness queries for all bitvector rewrites\n\
 \n\
-theory::fullcheck [non-stateful]\n\
+bv-abstraction [non-stateful]\n\
++ Output correctness queries for all bv abstraction \n\
+\n\
+bv-algebraic [non-stateful]\n\
++ Output correctness queries for bv algebraic solver. \n\
+\n\
+theory::fullcheck [non-stateful]\n                                      \
 + Output completeness queries for all full-check effort-level theory checks\n\
 \n\
 Dump modes can be combined with multiple uses of --dump.  Generally you want\n\
@@ -237,6 +243,10 @@ inline void dumpMode(std::string option, std::string optarg, SmtEngine* smt) {
     } else if(!strcmp(optargPtr, "help")) {
       puts(dumpHelp.c_str());
       exit(1);
+    } else if(!strcmp(optargPtr, "bv-abstraction")) {
+      Dump.on("bv-abstraction");
+    } else if(!strcmp(optargPtr, "bv-algebraic")) {
+      Dump.on("bv-algebraic");
     } else {
       throw OptionException(std::string("unknown option for --dump: `") +
                             optargPtr + "'.  Try --dump help.");
index 33496ac3ba3a966f53287e0285865e0453be61b0..6dbef4fe33a957e514dd8ac8797869d247f76d00 100644 (file)
@@ -361,11 +361,15 @@ private:
   // Lift bit-vectors of size 1 to booleans
   void bvToBool();
 
+  // Abstract common structure over small domains to UF
+  // return true if changes were made. 
+  void bvAbstraction(); 
+  
   // Simplify ITE structure
   bool simpITE();
 
   // Simplify based on unconstrained values
-  void unconstrainedSimp();
+  void unconstrainedSimp(std::vector<Node>& assertions);
 
   // Ensures the assertions asserted after before now
   // effectively come before d_realAssertionsEnd
@@ -896,11 +900,6 @@ void SmtEngine::setDefaults() {
     */
   }
 
-  if(options::bitvectorEagerBitblast()) {
-    // Eager solver should use the internal decision strategy
-    options::decisionMode.set(DECISION_STRATEGY_INTERNAL);
-  }
-
   if(options::checkModels()) {
     if(! options::interactive()) {
       Notice() << "SmtEngine: turning on interactive-mode to support check-models" << endl;
@@ -1069,6 +1068,27 @@ void SmtEngine::setDefaults() {
       setOption("check-models", SExpr("false"));
     }
   }
+
+
+  if (options::bitblastMode() == theory::bv::BITBLAST_MODE_EAGER &&
+      options::incrementalSolving()) {
+    if (options::incrementalSolving.wasSetByUser()) {
+      throw OptionException(std::string("Eager bit-blasting does not currently support incremental mode. \n\
+                                         Try --bitblast=lazy"));
+    }
+    Notice() << "SmtEngine: turning off incremental to support eager bit-blasting" << endl;
+    setOption("incremental", SExpr("false"));
+  }
+  
+  if (! options::bvEagerExplanations.wasSetByUser() &&
+      d_logic.isTheoryEnabled(THEORY_ARRAY) &&
+      d_logic.isTheoryEnabled(THEORY_BV)) {
+    Trace("smt") << "enabling eager bit-vector explanations " << endl;
+    options::bvEagerExplanations.set(true);
+  }
+
+  
+  
   // Turn on arith rewrite equalities only for pure arithmetic
   if(! options::arithRewriteEq.wasSetByUser()) {
     bool arithRewriteEq = d_logic.isPure(THEORY_ARITH) && !d_logic.isQuantified();
@@ -1971,13 +1991,29 @@ bool SmtEnginePrivate::nonClausalSimplify() {
   return true;
 }
 
+void SmtEnginePrivate::bvAbstraction() {
+  Trace("bv-abstraction") << "SmtEnginePrivate::bvAbstraction()" << endl;
+  std::vector<Node> new_assertions;
+  bool changed = d_smt.d_theoryEngine->ppBvAbstraction(d_assertionsToPreprocess, new_assertions);
+  for (unsigned i = 0; i < d_assertionsToPreprocess.size(); ++ i) {
+    d_assertionsToPreprocess[i] = Rewriter::rewrite(new_assertions[i]);
+  }
+  // if we are using the lazy solver and the abstraction
+  // applies, then UF symbols were introduced 
+  if (options::bitblastMode() == theory::bv::BITBLAST_MODE_LAZY &&
+      changed) {
+    LogicRequest req(d_smt);
+    req.widenLogic(THEORY_UF); 
+  }
+}
+
 
 void SmtEnginePrivate::bvToBool() {
   Trace("bv-to-bool") << "SmtEnginePrivate::bvToBool()" << endl;
   std::vector<Node> new_assertions;
-  d_smt.d_theoryEngine->ppBvToBool(d_assertionsToCheck, new_assertions);
-  for (unsigned i = 0; i < d_assertionsToCheck.size(); ++ i) {
-    d_assertionsToCheck[i] = Rewriter::rewrite(new_assertions[i]);
+  d_smt.d_theoryEngine->ppBvToBool(d_assertionsToPreprocess, new_assertions);
+  for (unsigned i = 0; i < d_assertionsToPreprocess.size(); ++ i) {
+    d_assertionsToPreprocess[i] = Rewriter::rewrite(new_assertions[i]);
   }
 }
 
@@ -2032,11 +2068,10 @@ void SmtEnginePrivate::compressBeforeRealAssertions(size_t before){
   Assert(d_assertionsToCheck.size() == before);
 }
 
-void SmtEnginePrivate::unconstrainedSimp() {
+void SmtEnginePrivate::unconstrainedSimp(std::vector<Node>& assertions) {
   TimerStat::CodeTimer unconstrainedSimpTimer(d_smt.d_stats->d_unconstrainedSimpTime);
-
   Trace("simplify") << "SmtEnginePrivate::unconstrainedSimp()" << endl;
-  d_smt.d_theoryEngine->ppUnconstrainedSimp(d_assertionsToCheck);
+  d_smt.d_theoryEngine->ppUnconstrainedSimp(assertions);
 }
 
 
@@ -2533,6 +2568,9 @@ bool SmtEnginePrivate::simplifyAssertions()
     Debug("smt") << " d_assertionsToPreprocess: " << d_assertionsToPreprocess.size() << endl;
     Debug("smt") << " d_assertionsToCheck     : " << d_assertionsToCheck.size() << endl;
 
+    // before ppRewrite check if only core theory for BV theory
+    d_smt.d_theoryEngine->staticInitializeBVOptions(d_assertionsToCheck);
+    
     // Theory preprocessing
     if (d_smt.d_earlyTheoryPP) {
       Chat() << "...doing early theory preprocessing..." << endl;
@@ -2570,7 +2608,7 @@ bool SmtEnginePrivate::simplifyAssertions()
     // Unconstrained simplification
     if(options::unconstrainedSimp()) {
       Chat() << "...doing unconstrained simplification..." << endl;
-      unconstrainedSimp();
+      unconstrainedSimp(d_assertionsToCheck);
     }
 
     dumpAssertions("post-unconstrained", d_assertionsToCheck);
@@ -2825,7 +2863,26 @@ void SmtEnginePrivate::processAssertions() {
 
   Debug("smt") << " d_assertionsToPreprocess: " << d_assertionsToPreprocess.size() << endl;
   Debug("smt") << " d_assertionsToCheck     : " << d_assertionsToCheck.size() << endl;
+  
+  if (options::bitblastMode() == theory::bv::BITBLAST_MODE_EAGER &&
+      !d_smt.d_logic.isPure(THEORY_BV)) {
+    throw ModalException("Eager bit-blasting does not currently support theory combination. "
+                         "Note that in a QF_BV problem UF symbols can be introduced for division. "
+                         "Try --bv-div-zero-const to interpret division by zero as a constant."); 
+  }
 
+  if (options::bitblastMode() == theory::bv::BITBLAST_MODE_EAGER) {
+    d_smt.d_theoryEngine->mkAckermanizationAsssertions(d_assertionsToPreprocess); 
+  }
+  
+
+  if ( options::bvAbstraction() &&
+      !options::incrementalSolving()) {
+    dumpAssertions("pre-bv-abstraction", d_assertionsToPreprocess);
+    bvAbstraction();
+    dumpAssertions("post-bv-abstraction", d_assertionsToPreprocess);
+  }
+  
   dumpAssertions("pre-boolean-terms", d_assertionsToPreprocess);
   {
     Chat() << "rewriting Boolean terms..." << endl;
@@ -2855,6 +2912,15 @@ void SmtEnginePrivate::processAssertions() {
   Debug("smt") << " d_assertionsToPreprocess: " << d_assertionsToPreprocess.size() << endl;
   Debug("smt") << " d_assertionsToCheck     : " << d_assertionsToCheck.size() << endl;
 
+
+  // Unconstrained simplification
+  if(options::unconstrainedSimp()) {
+    dumpAssertions("pre-unconstrained-simp", d_assertionsToPreprocess);
+    Chat() << "...doing unconstrained simplification..." << endl;
+    unconstrainedSimp(d_assertionsToPreprocess);
+    dumpAssertions("post-unconstrained-simp", d_assertionsToPreprocess);
+  }
+
   dumpAssertions("pre-substitution", d_assertionsToPreprocess);
 
   // Apply the substitutions we already have, and normalize
@@ -2871,6 +2937,15 @@ void SmtEnginePrivate::processAssertions() {
 
   // Assertions ARE guaranteed to be rewritten by this point
 
+
+  // Lift bit-vectors of size 1 to bool
+  if(options::bitvectorToBool()) {
+    dumpAssertions("pre-bv-to-bool", d_assertionsToPreprocess);
+    Chat() << "...doing bvToBool..." << endl;
+    bvToBool();
+    dumpAssertions("post-bv-to-bool", d_assertionsToPreprocess);
+  }
+  
   if( d_smt.d_logic.isTheoryEnabled(THEORY_STRINGS) ) {
     dumpAssertions("pre-strings-pp", d_assertionsToPreprocess);
     CVC4::theory::strings::StringsPreprocess sp;
@@ -2957,12 +3032,6 @@ void SmtEnginePrivate::processAssertions() {
   }
   dumpAssertions("post-static-learning", d_assertionsToCheck);
 
-  // Lift bit-vectors of size 1 to bool
-  if(options::bvToBool()) {
-    Chat() << "...doing bvToBool..." << endl;
-    bvToBool();
-  }
-
   Trace("smt") << "POST bvToBool" << endl;
   Debug("smt") << " d_assertionsToPreprocess: " << d_assertionsToPreprocess.size() << endl;
   Debug("smt") << " d_assertionsToCheck     : " << d_assertionsToCheck.size() << endl;
@@ -3086,6 +3155,15 @@ void SmtEnginePrivate::processAssertions() {
   }
   dumpAssertions("post-theory-preprocessing", d_assertionsToCheck);
 
+  // If we are using eager bit-blasting wrap assertions in fake atom so that
+  // everything gets bit-blasted to internal SAT solver
+  if (options::bitblastMode() == theory::bv::BITBLAST_MODE_EAGER) {
+    for (unsigned i = 0; i < d_assertionsToCheck.size(); ++i) {
+      Node eager_atom = NodeManager::currentNM()->mkNode(kind::BITVECTOR_EAGER_ATOM, d_assertionsToCheck[i]);
+      d_assertionsToCheck[i] = eager_atom; 
+    }
+  }
+  
   // Push the formula to decision engine
   if(noConflict) {
     Chat() << "pushing to decision engine..." << endl;
@@ -3099,7 +3177,6 @@ void SmtEnginePrivate::processAssertions() {
 
   dumpAssertions("post-everything", d_assertionsToCheck);
 
-  // Push the formula to SAT
   {
     Chat() << "converting to CNF..." << endl;
     TimerStat::CodeTimer codeTimer(d_smt.d_stats->d_cnfConversionTime);
@@ -3107,6 +3184,7 @@ void SmtEnginePrivate::processAssertions() {
       d_smt.d_propEngine->assertFormula(d_assertionsToCheck[i]);
     }
   }
+  
 
   d_assertionsProcessed = true;
 
@@ -3380,6 +3458,7 @@ Expr SmtEngine::expandDefinitions(const Expr& ex) throw(TypeCheckingException, L
   hash_map<Node, Node, NodeHashFunction> cache;
   Node n = d_private->expandDefinitions(Node::fromExpr(e), cache);
   n = postprocess(n, TypeNode::fromType(e.getType()));
+
   return n.toExpr();
 }
 
diff --git a/src/theory/bv/abstraction.cpp b/src/theory/bv/abstraction.cpp
new file mode 100644 (file)
index 0000000..3bff9fc
--- /dev/null
@@ -0,0 +1,1060 @@
+/*********************                                                        */
+/*! \file abstraction.cpp
+** \verbatim
+** Original author: Liana Hadarean
+** Major contributors: none.
+** 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 [[ Add one-line brief description here ]]
+**
+** [[ Add lengthier description here ]]
+** \todo document this file
+**/
+
+#include "theory/bv/abstraction.h"
+#include "theory/bv/theory_bv_utils.h"
+#include "theory/rewriter.h"
+#include "theory/bv/options.h"
+#include "util/dump.h"
+
+using namespace CVC4;
+using namespace CVC4::theory;
+using namespace CVC4::theory::bv;
+using namespace CVC4::context;
+
+using namespace std;
+using namespace CVC4::theory::bv::utils;
+
+bool AbstractionModule::applyAbstraction(const std::vector<Node>& assertions, std::vector<Node>& new_assertions) {
+  Debug("bv-abstraction") << "AbstractionModule::applyAbstraction\n"; 
+
+  TimerStat::CodeTimer abstractionTimer(d_statistics.d_abstractionTime);
+    
+  for (unsigned i = 0; i < assertions.size(); ++i) {
+    if (assertions[i].getKind() == kind::OR) {
+      for (unsigned j = 0; j < assertions[i].getNumChildren(); ++j) {
+        if (!isConjunctionOfAtoms(assertions[i][j])) {
+          continue;
+        }
+        Node signature = computeSignature(assertions[i][j]);
+        storeSignature(signature, assertions[i][j]); 
+        Debug("bv-abstraction") << "   assertion: " << assertions[i][j] <<"\n";
+        Debug("bv-abstraction") << "   signature: " << signature <<"\n";
+      }
+    }
+  }
+  finalizeSignatures();
+
+  for (unsigned i = 0; i < assertions.size(); ++i) {
+    if (assertions[i].getKind() == kind::OR &&
+        assertions[i][0].getKind() == kind::AND) {
+      std::vector<Node> new_children; 
+      for (unsigned j = 0; j < assertions[i].getNumChildren(); ++j) {
+        if (hasSignature(assertions[i][j])) {
+          new_children.push_back(abstractSignatures(assertions[i][j]));
+        } else {
+          new_children.push_back(assertions[i][j]);
+        }
+      }
+      new_assertions.push_back(utils::mkNode(kind::OR, new_children)); 
+    } else {
+      // assertions that are not changed
+      new_assertions.push_back(assertions[i]); 
+    }
+  }
+
+  if (options::skolemizeArguments()) {
+    skolemizeArguments(new_assertions);
+  }
+
+  
+  // if we are using the eager solver reverse the abstraction
+  if (options::bitblastMode() == theory::bv::BITBLAST_MODE_EAGER) {
+    if (d_funcToSignature.size() == 0) {
+      // we did not change anything
+      return false;
+    }
+    NodeNodeMap seen; 
+    for (unsigned i = 0; i < new_assertions.size(); ++i) {
+      new_assertions[i] = reverseAbstraction(new_assertions[i], seen); 
+    }
+    // we undo the abstraction functions so the logic is QF_BV still
+    return true; 
+  }
+  
+  // return true if we have created new function symbols for the problem
+  return d_funcToSignature.size() != 0;
+}
+
+
+bool AbstractionModule::isConjunctionOfAtoms(TNode node) {
+  TNodeSet seen;
+  return isConjunctionOfAtomsRec(node, seen);
+}
+
+bool AbstractionModule::isConjunctionOfAtomsRec(TNode node, TNodeSet& seen) {
+  if (seen.find(node)!= seen.end())
+    return true;
+  
+  if (!node.getType().isBitVector()) {
+    return (node.getKind() == kind::AND || utils::isBVPredicate(node));
+  }
+
+  if (node.getNumChildren() == 0)
+    return true;
+
+  for (unsigned i = 0; i < node.getNumChildren(); ++i) {
+    if (!isConjunctionOfAtomsRec(node[i], seen))
+      return false;
+  }
+  seen.insert(node);
+  return true;
+}
+
+
+Node AbstractionModule::reverseAbstraction(Node assertion, NodeNodeMap& seen) {
+
+  if (seen.find(assertion) != seen.end())
+    return seen[assertion];
+  
+  if (isAbstraction(assertion)) {
+    Node interp =  getInterpretation(assertion);
+    seen[assertion] = interp;
+    Assert (interp.getType() == assertion.getType()); 
+    return interp;
+  }
+
+  if (assertion.getNumChildren() == 0) {
+    seen[assertion] = assertion;
+    return assertion; 
+  }
+  
+  NodeBuilder<> result(assertion.getKind());
+  if (assertion.getMetaKind() == kind::metakind::PARAMETERIZED) {
+    result << assertion.getOperator(); 
+  }
+
+  for (unsigned i = 0; i < assertion.getNumChildren(); ++i) {
+    result << reverseAbstraction(assertion[i], seen); 
+  }
+  Node res = result;
+  seen[assertion] = res;
+  return res; 
+}
+
+void AbstractionModule::skolemizeArguments(std::vector<Node>& assertions) {
+  for (unsigned i = 0; i < assertions.size(); ++i) {
+    TNode assertion = assertions[i];
+    if (assertion.getKind() != kind::OR)
+      continue;
+    
+    bool is_skolemizable = true;
+    for (unsigned k = 0; k < assertion.getNumChildren(); ++k) {
+      if (assertion[k].getKind() != kind::EQUAL ||
+          assertion[k][0].getKind() != kind::APPLY_UF ||
+          assertion[k][1].getKind() != kind::CONST_BITVECTOR ||
+          assertion[k][1].getConst<BitVector>() != BitVector(1, 1u)) {
+        is_skolemizable = false;
+        break;
+      }
+    }
+
+    if (!is_skolemizable)
+      continue;
+
+    ArgsTable assertion_table;
+
+    // collect function symbols and their arguments
+    for (unsigned j = 0; j < assertion.getNumChildren(); ++j) {
+      TNode current = assertion[j];
+      Assert (current.getKind() == kind::EQUAL &&
+              current[0].getKind() == kind::APPLY_UF);
+      TNode func = current[0];
+      ArgsVec args;
+      for (unsigned k = 0; k < func.getNumChildren(); ++k) {
+        args.push_back(func[k]);
+      }
+      assertion_table.addEntry(func.getOperator(), args);
+    }
+
+    NodeBuilder<> assertion_builder (kind::OR);
+    // construct skolemized assertion
+    for (ArgsTable::iterator it = assertion_table.begin(); it != assertion_table.end(); ++it) {
+      // for each function symbol
+      ++(d_statistics.d_numArgsSkolemized);
+      TNode func = it->first;
+      ArgsTableEntry& args = it->second;
+      NodeBuilder<> skolem_func (kind::APPLY_UF);
+      skolem_func << func;
+      std::vector<Node> skolem_args;
+        
+      for (unsigned j = 0; j < args.getArity(); ++j) {
+        bool all_same = true;
+        for (unsigned k = 1; k < args.getNumEntries(); ++k) {
+          if ( args.getEntry(k)[j] != args.getEntry(0)[j])
+            all_same = false; 
+        }
+        Node new_arg = all_same ? (Node)args.getEntry(0)[j] : utils::mkVar(utils::getSize(args.getEntry(0)[j])); 
+        skolem_args.push_back(new_arg);
+        skolem_func << new_arg; 
+      }
+      
+
+      Node skolem_func_eq1 = utils::mkNode(kind::EQUAL, (Node)skolem_func, utils::mkConst(1, 1u)); 
+      
+      // enumerate arguments assignments
+      std::vector<Node> or_assignments; 
+      for (ArgsTableEntry::iterator it = args.begin(); it != args.end(); ++it) {
+        NodeBuilder<> arg_assignment(kind::AND);
+        ArgsVec& args =  *it;
+        for (unsigned k = 0; k < args.size(); ++k) {
+          Node eq = utils::mkNode(kind::EQUAL, args[k], skolem_args[k]);
+          arg_assignment << eq; 
+        }
+        or_assignments.push_back(arg_assignment);
+      }
+      
+      Node new_func_def = utils::mkNode(kind::AND, skolem_func_eq1, utils::mkNode(kind::OR, or_assignments));
+      assertion_builder << new_func_def; 
+    }
+    Node new_assertion = assertion_builder;
+    Debug("bv-abstraction-dbg") << "AbstractionModule::skolemizeArguments " << assertions[i] << " => \n";
+    Debug("bv-abstraction-dbg") << "    " << new_assertion; 
+    assertions[i] = new_assertion;
+  }
+}
+
+void AbstractionModule::storeSignature(Node signature, TNode assertion) {
+  if(d_signatures.find(signature) == d_signatures.end()) {
+    d_signatures[signature] = 0; 
+  }
+  d_signatures[signature] = d_signatures[signature] + 1; 
+  d_assertionToSignature[assertion] = signature; 
+}
+
+Node AbstractionModule::computeSignature(TNode node) {
+  resetSignatureIndex(); 
+  NodeNodeMap cache; 
+  Node sig = computeSignatureRec(node, cache);
+  return sig;
+}
+
+Node AbstractionModule::getSignatureSkolem(TNode node) {
+  Assert (node.getKind() == kind::VARIABLE);
+  unsigned bitwidth = utils::getSize(node);
+  if (d_signatureSkolems.find(bitwidth) == d_signatureSkolems.end()) {
+    d_signatureSkolems[bitwidth] = vector<Node>(); 
+  }
+  
+  vector<Node>& skolems = d_signatureSkolems[bitwidth];
+  // get the index of bv variables of this size
+  unsigned index = getBitwidthIndex(bitwidth); 
+  Assert (skolems.size() + 1 >= index );
+  if (skolems.size() == index) {
+    ostringstream os;
+    os << "sig_" <<bitwidth <<"_" << index;
+    NodeManager* nm = NodeManager::currentNM(); 
+    skolems.push_back(nm->mkSkolem(os.str(), nm->mkBitVectorType(bitwidth), "skolem for computing signatures"));
+  }
+  ++(d_signatureIndices[bitwidth]);
+  return skolems[index];
+}
+
+unsigned AbstractionModule::getBitwidthIndex(unsigned bitwidth) {
+  if (d_signatureIndices.find(bitwidth) == d_signatureIndices.end()) {
+    d_signatureIndices[bitwidth] = 0;
+  }
+  return d_signatureIndices[bitwidth]; 
+}
+
+void AbstractionModule::resetSignatureIndex() {
+  for (IndexMap::iterator it = d_signatureIndices.begin(); it != d_signatureIndices.end(); ++it) {
+    it->second = 0; 
+  }
+}
+
+bool AbstractionModule::hasSignature(Node node) {
+  return d_assertionToSignature.find(node) != d_assertionToSignature.end();
+}
+
+Node AbstractionModule::getGeneralizedSignature(Node node) {
+  NodeNodeMap::const_iterator it = d_assertionToSignature.find(node); 
+  Assert (it != d_assertionToSignature.end());
+  Node generalized_signature = getGeneralization(it->second); 
+  return generalized_signature; 
+}
+
+Node AbstractionModule::computeSignatureRec(TNode node, NodeNodeMap& cache) {
+  if (cache.find(node) != cache.end()) {
+    return cache.find(node)->second; 
+  }
+  
+  if (node.getNumChildren() == 0) {
+    if (node.getKind() == kind::CONST_BITVECTOR)
+      return node;
+
+    Node sig = getSignatureSkolem(node);
+    cache[node] = sig; 
+    return sig; 
+  }
+
+  NodeBuilder<> builder(node.getKind());
+  if (node.getMetaKind() == kind::metakind::PARAMETERIZED) {
+    builder << node.getOperator();
+  }
+  for (unsigned i = 0; i < node.getNumChildren(); ++i) {
+    Node converted = computeSignatureRec(node[i], cache);
+    builder << converted; 
+  }
+  Node result = builder;
+  cache[node] = result;
+  return result; 
+}
+
+/** 
+ * Returns 0, if the two are equal,
+ * 1 if s is a generalization of t
+ * 2 if t is a generalization of s
+ * -1 if the two cannot be unified
+ *
+ * @param s 
+ * @param t 
+ * 
+ * @return 
+ */
+int AbstractionModule::comparePatterns(TNode s, TNode t) {
+  if (s.getKind() == kind::SKOLEM &&
+      t.getKind() == kind::SKOLEM) {
+    return 0;
+  }
+  
+  if (s.getKind() == kind::CONST_BITVECTOR &&
+      t.getKind() == kind::CONST_BITVECTOR) {
+    if (s == t) {
+      return 0;
+    } else {
+      return -1;
+    }
+  }
+
+  if (s.getKind() == kind::SKOLEM &&
+      t.getKind() == kind::CONST_BITVECTOR) {
+    return 1;
+  }
+
+  if (s.getKind() == kind::CONST_BITVECTOR &&
+      t.getKind() == kind::SKOLEM) {
+    return 2;
+  }
+  
+  if (s.getNumChildren() != t.getNumChildren() ||
+      s.getKind() != t.getKind())
+    return -1;
+
+  int unify = 0;
+  for (unsigned i = 0; i < s.getNumChildren(); ++i) {
+    int unify_i = comparePatterns(s[i], t[i]);
+    if (unify_i < 0)
+      return -1;
+    if (unify == 0) {
+      unify = unify_i;
+    } else if (unify != unify_i && unify_i != 0) {
+      return -1;
+    }
+  }
+  return unify;
+}
+
+TNode AbstractionModule::getGeneralization(TNode term) {
+  NodeNodeMap::iterator it = d_sigToGeneralization.find(term); 
+  // if not in the map we add it
+  if (it == d_sigToGeneralization.end()) {
+    d_sigToGeneralization[term] = term;
+    return term; 
+  }
+  // doesn't have a generalization 
+  if (it->second == term)
+    return term;
+  
+  TNode generalization = getGeneralization(it->second);
+  Assert (generalization != term);
+  d_sigToGeneralization[term] = generalization;
+  return generalization; 
+}
+
+void AbstractionModule::storeGeneralization(TNode s, TNode t) {
+  Assert (s == getGeneralization(s));
+  Assert (t == getGeneralization(t));
+  d_sigToGeneralization[s] = t; 
+}
+
+void AbstractionModule::finalizeSignatures() {
+  NodeManager* nm = NodeManager::currentNM();
+  Debug("bv-abstraction") << "AbstractionModule::finalizeSignatures num signatures = " << d_signatures.size() <<"\n";
+  TNodeSet new_signatures;
+
+  // "unify" signatures
+  for (SignatureMap::const_iterator ss = d_signatures.begin(); ss != d_signatures.end(); ++ss) {
+    for (SignatureMap::const_iterator tt = ss; tt != d_signatures.end(); ++tt) {
+      TNode t = getGeneralization(tt->first);
+      TNode s = getGeneralization(ss->first);
+      
+      if (t != s) {
+        int status = comparePatterns(s, t);
+        Assert (status); 
+        if (status < 0)
+          continue;
+        if (status == 1) {
+          storeGeneralization(t, s); 
+        } else {
+          storeGeneralization(s, t); 
+        }
+      }
+    }
+  }
+  // keep only most general signatures
+  for (SignatureMap::iterator it = d_signatures.begin(); it != d_signatures.end(); ) {
+    TNode sig = it->first; 
+    TNode gen = getGeneralization(sig);
+    if (sig != gen) {
+      Assert (d_signatures.find(gen) != d_signatures.end()); 
+      // update the count
+      d_signatures[gen]+= d_signatures[sig];
+      d_signatures.erase(it++); 
+    } else {
+      ++it;
+    }
+  }
+
+
+  // remove signatures that are not frequent enough
+  for (SignatureMap::iterator it = d_signatures.begin(); it != d_signatures.end(); ) {
+    if (it->second <= 7) {
+      d_signatures.erase(it++); 
+    } else {
+      ++it;
+    }
+  }
+  
+  for (SignatureMap::const_iterator it = d_signatures.begin(); it != d_signatures.end(); ++it) {
+    TNode signature = it->first;
+    // we already processed this signature
+    Assert (d_signatureToFunc.find(signature) == d_signatureToFunc.end());
+
+    Debug("bv-abstraction") << "Processing signature " << signature << " count " << it->second << "\n";
+    std::vector<TypeNode> arg_types;
+    TNodeSet seen;
+    collectArgumentTypes(signature, arg_types, seen);
+    Assert (signature.getType().isBoolean());
+    // make function return a bitvector of size 1
+    //Node bv_function = utils::mkNode(kind::ITE, signature, utils::mkConst(1, 1u), utils::mkConst(1, 0u)); 
+    TypeNode range = NodeManager::currentNM()->mkBitVectorType(1);
+    
+    TypeNode abs_type = nm->mkFunctionType(arg_types, range);
+    Node abs_func = nm->mkSkolem("abs_$$", abs_type, "abstraction function for bv theory");
+    Debug("bv-abstraction") << " abstracted by function " << abs_func << "\n";
+
+    // NOTE: signature expression type is BOOLEAN
+    d_signatureToFunc[signature] = abs_func;
+    d_funcToSignature[abs_func] = signature; 
+  }
+
+  d_statistics.d_numFunctionsAbstracted.setData(d_signatureToFunc.size());
+  
+  Debug("bv-abstraction") << "AbstractionModule::finalizeSignatures abstracted " << d_signatureToFunc.size() << " signatures. \n";
+}
+
+void AbstractionModule::collectArgumentTypes(TNode sig, std::vector<TypeNode>& types, TNodeSet& seen) {
+  if (seen.find(sig) != seen.end())
+    return;
+  
+  if (sig.getKind() == kind::SKOLEM) {
+    types.push_back(sig.getType());
+    seen.insert(sig); 
+    return; 
+  }
+
+  for (unsigned i = 0; i < sig.getNumChildren(); ++i) {
+    collectArgumentTypes(sig[i], types, seen);
+    seen.insert(sig);
+  }
+}
+
+void AbstractionModule::collectArguments(TNode node, TNode signature, std::vector<Node>& args, TNodeSet& seen) {
+  if (seen.find(node)!= seen.end())
+    return;
+  
+  if (node.getKind() == kind::VARIABLE ||
+      node.getKind() == kind::CONST_BITVECTOR) {
+    // a constant in the node can either map to an argument of the abstraction
+    // or can be hard-coded and part of the abstraction 
+    if (signature.getKind() == kind::SKOLEM) {
+      args.push_back(node);
+      seen.insert(node);
+    } else {
+      Assert (signature.getKind() == kind::CONST_BITVECTOR); 
+    }
+    // 
+    return; 
+  }
+  Assert (node.getKind() == signature.getKind() &&
+          node.getNumChildren() == signature.getNumChildren()); 
+
+  for (unsigned i = 0; i < node.getNumChildren(); ++i) {
+    collectArguments(node[i], signature[i], args, seen); 
+    seen.insert(node); 
+  }
+}
+
+
+Node AbstractionModule::abstractSignatures(TNode assertion) {
+  Debug("bv-abstraction") << "AbstractionModule::abstractSignatures "<< assertion <<"\n"; 
+  // assume the assertion has been fully abstracted
+  Node signature = getGeneralizedSignature(assertion);
+  
+  Debug("bv-abstraction") << "   with sig "<< signature <<"\n"; 
+  NodeNodeMap::iterator it = d_signatureToFunc.find(signature);
+  if (it!= d_signatureToFunc.end()) {
+    std::vector<Node> args;
+    TNode func = it->second;
+    // pushing the function symbol
+    args.push_back(func);
+    TNodeSet seen;
+    collectArguments(assertion, signature, args, seen);
+    std::vector<TNode> real_args;
+    for (unsigned i = 1; i < args.size(); ++i) {
+      real_args.push_back(args[i]); 
+    }
+    d_argsTable.addEntry(func, real_args); 
+    Node result = utils::mkNode(kind::EQUAL, utils::mkNode(kind::APPLY_UF, args), 
+                                utils::mkConst(1, 1u));
+    Debug("bv-abstraction") << "=>   "<< result << "\n"; 
+    Assert (result.getType() == assertion.getType()); 
+    return result; 
+  }
+  return assertion; 
+}
+
+bool AbstractionModule::isAbstraction(TNode node) {
+  if (node.getKind() != kind::EQUAL)
+    return false;
+  if ((node[0].getKind() != kind::CONST_BITVECTOR ||
+       node[1].getKind() != kind::APPLY_UF) &&
+      (node[1].getKind() != kind::CONST_BITVECTOR ||
+       node[0].getKind() != kind::APPLY_UF))
+    return false;
+
+  TNode constant = node[0].getKind() == kind::CONST_BITVECTOR ? node[0] : node[1];
+  TNode func = node[0].getKind() == kind::APPLY_UF ? node[0] : node[1];
+  Assert (constant.getKind() == kind::CONST_BITVECTOR &&
+          func.getKind() == kind::APPLY_UF);
+  if (utils::getSize(constant) != 1)
+    return false;
+  if (constant != utils::mkConst(1, 1u))
+    return false;
+
+  TNode func_symbol = func.getOperator(); 
+  if (d_funcToSignature.find(func_symbol) == d_funcToSignature.end())
+    return false;
+
+  return true; 
+}
+
+Node AbstractionModule::getInterpretation(TNode node) {
+  Assert (isAbstraction(node));
+  TNode constant = node[0].getKind() == kind::CONST_BITVECTOR ? node[0] : node[1];
+  TNode apply = node[0].getKind() == kind::APPLY_UF ? node[0] : node[1];
+  Assert (constant.getKind() == kind::CONST_BITVECTOR &&
+          apply.getKind() == kind::APPLY_UF);
+
+  Node func = apply.getOperator(); 
+  Assert (d_funcToSignature.find(func) != d_funcToSignature.end());
+  
+  Node sig = d_funcToSignature[func];
+  
+  // substitute arguments in signature
+  TNodeTNodeMap seen;
+  unsigned index = 0;
+  Node result = substituteArguments(sig, apply, index, seen);
+  Assert (result.getType().isBoolean()); 
+  Assert (index == apply.getNumChildren());
+  // Debug("bv-abstraction") << "AbstractionModule::getInterpretation " << node << "\n";
+  // Debug("bv-abstraction") << "    => " << result << "\n";
+  return result; 
+}
+
+Node AbstractionModule::substituteArguments(TNode signature, TNode apply, unsigned& index, TNodeTNodeMap& seen) {
+  if (seen.find(signature) != seen.end()) {
+    return seen[signature]; 
+  }
+  
+  if (signature.getKind() == kind::SKOLEM) {
+    // return corresponding argument and increment counter
+    seen[signature] = apply[index];
+    return apply[index++]; 
+  }
+
+  if (signature.getNumChildren() == 0) {
+    Assert (signature.getKind() != kind::VARIABLE &&
+            signature.getKind() != kind::SKOLEM); 
+    seen[signature] = signature;
+    return signature; 
+  }
+  
+  NodeBuilder<> builder(signature.getKind());
+  if (signature.getMetaKind() == kind::metakind::PARAMETERIZED) {
+    builder << signature.getOperator();
+  }
+  
+  for (unsigned i = 0; i < signature.getNumChildren(); ++i) {
+    Node child = substituteArguments(signature[i], apply, index, seen);
+    builder << child; 
+  }
+
+  Node result = builder; 
+  seen[signature]= result;
+
+  return result;
+}
+
+Node AbstractionModule::simplifyConflict(TNode conflict) {
+  if (Dump.isOn("bv-abstraction")) {
+    NodeNodeMap seen;
+    Node c = reverseAbstraction(conflict, seen);
+    Dump("bv-abstraction") << PushCommand(); 
+    Dump("bv-abstraction") << AssertCommand(c.toExpr());
+    Dump("bv-abstraction") << CheckSatCommand();
+    Dump("bv-abstraction") << PopCommand(); 
+  }
+
+  Debug("bv-abstraction-dbg") << "AbstractionModule::simplifyConflict " << conflict << "\n"; 
+  if (conflict.getKind() != kind::AND)
+    return conflict; 
+
+  std::vector<Node> conjuncts;
+  for (unsigned i = 0; i < conflict.getNumChildren(); ++i)
+    conjuncts.push_back(conflict[i]);
+  
+  theory::SubstitutionMap subst(new context::Context());
+  for (unsigned i = 0; i < conjuncts.size(); ++i) {
+    TNode conjunct = conjuncts[i];
+    // substitute s -> t
+    Node s, t;
+
+    if (conjunct.getKind() == kind::EQUAL) {
+      if (conjunct[0].getMetaKind() == kind::metakind::VARIABLE &&
+          conjunct[1].getKind() == kind::CONST_BITVECTOR) {
+        s = conjunct[0];
+        t = conjunct[1];
+      }
+      else if (conjunct[1].getMetaKind() == kind::metakind::VARIABLE &&
+               conjunct[0].getKind() == kind::CONST_BITVECTOR) {
+        s = conjunct[1];
+        t = conjunct[0];
+      } else {
+        continue;
+      }
+      
+      Assert (!subst.hasSubstitution(s));
+      Assert (!t.isNull() &&
+              !s.isNull() &&
+              s!= t);
+      subst.addSubstitution(s, t); 
+
+      for (unsigned k = 0; k < conjuncts.size(); k++) {
+        conjuncts[k] = subst.apply(conjuncts[k]);
+      }
+    }
+  }
+  Node new_conflict = Rewriter::rewrite(utils::mkAnd(conjuncts));
+  
+  Debug("bv-abstraction") << "AbstractionModule::simplifyConflict conflict " << conflict <<"\n";
+  Debug("bv-abstraction") << "   => " << new_conflict <<"\n";
+
+  if (Dump.isOn("bv-abstraction")) {
+    
+    NodeNodeMap seen;
+    Node nc = reverseAbstraction(new_conflict, seen);
+    Dump("bv-abstraction") << PushCommand(); 
+    Dump("bv-abstraction") << AssertCommand(nc.toExpr());
+    Dump("bv-abstraction") << CheckSatCommand();
+    Dump("bv-abstraction") << PopCommand(); 
+  }
+  
+  return new_conflict; 
+}
+
+
+void DebugPrintInstantiations(const std::vector< std::vector<ArgsVec> >& instantiations,
+                              const std::vector<TNode> functions) {
+  // print header
+  Debug("bv-abstraction-dbg") <<"[ "; 
+  for (unsigned i = 0; i < functions.size(); ++i) {
+    for (unsigned j = 1; j < functions[i].getNumChildren(); ++j) {
+      Debug("bv-abstraction-dgb") << functions[i][j] <<" ";
+    }
+    Debug("bv-abstraction-dgb") << " || ";
+  }
+  Debug("bv-abstraction-dbg") <<"]\n";
+
+  for (unsigned i = 0; i < instantiations.size(); ++i) {
+    Debug("bv-abstraction-dbg") <<"[";
+    const std::vector<ArgsVec>& inst = instantiations[i];
+    for (unsigned j = 0; j < inst.size(); ++j) {
+      for (unsigned k = 0; k < inst[j].size(); ++k) {
+        Debug("bv-abstraction-dbg") << inst[j][k] << " "; 
+      }
+      Debug("bv-abstraction-dbg") << " || "; 
+    }
+    Debug("bv-abstraction-dbg") <<"]\n";
+  }
+}
+
+void AbstractionModule::generalizeConflict(TNode conflict, std::vector<Node>& lemmas) {
+  Debug("bv-abstraction") << "AbstractionModule::generalizeConflict " << conflict << "\n"; 
+  std::vector<TNode> functions;
+
+  // collect abstract functions
+  if (conflict.getKind() != kind::AND) {
+    if (isAbstraction(conflict)) {
+      Assert (conflict[0].getKind() == kind::APPLY_UF);
+      functions.push_back(conflict[0]);
+    }
+  } else {
+    for (unsigned i = 0; i < conflict.getNumChildren(); ++i) {
+      TNode conjunct = conflict[i];
+      if (isAbstraction(conjunct)) {
+        Assert (conjunct[0].getKind() == kind::APPLY_UF);
+        functions.push_back(conjunct[0]);
+      }
+    }
+  }
+
+  // if (functions.size() >= 3) {
+  //   // dump conflict
+  //   NodeNodeMap seen;
+  //   Node reversed = reverseAbstraction(conflict, seen); 
+  //   std::cout << "CONFLICT " << reversed << "\n"; 
+  // }
+
+  
+  if (functions.size() == 0 || functions.size() > options::bvNumFunc()) {
+    return;
+  }
+
+
+  // Skolemize function arguments to avoid confusion in pattern matching
+  SubstitutionMap skolem_subst(new context::Context());
+  SubstitutionMap reverse_skolem(new context::Context());
+  makeFreshSkolems(conflict, skolem_subst, reverse_skolem);
+  
+  Node skolemized_conflict = skolem_subst.apply(conflict);
+  for (unsigned i = 0; i < functions.size(); ++i) {
+    functions[i] = skolem_subst.apply(functions[i]);
+  }
+
+  conflict = skolem_subst.apply(conflict); 
+
+  LemmaInstantiatior inst(functions, d_argsTable, conflict);
+  std::vector<Node> new_lemmas;
+  inst.generateInstantiations(new_lemmas); 
+  for (unsigned i = 0; i < new_lemmas.size(); ++i) {
+    TNode lemma = reverse_skolem.apply(new_lemmas[i]);
+    if (d_addedLemmas.find(lemma) == d_addedLemmas.end()) {
+      lemmas.push_back(lemma);
+      Debug("bv-abstraction-gen") << "adding lemma " << lemma << "\n"; 
+      storeLemma(lemma);
+
+      if (Dump.isOn("bv-abstraction")) {
+        NodeNodeMap seen;
+        Node l = reverseAbstraction(lemma, seen);
+        Dump("bv-abstraction") << PushCommand(); 
+        Dump("bv-abstraction") << AssertCommand(l.toExpr());
+        Dump("bv-abstraction") << CheckSatCommand();
+        Dump("bv-abstraction") << PopCommand(); 
+      }
+    }
+  }
+}
+
+int AbstractionModule::LemmaInstantiatior::next(int val, int index) {
+  if (val < d_maxMatch[index]  - 1)
+    return val + 1;
+  return -1;
+}
+
+/** 
+ * Assumes the stack without top is consistent, and checks that the
+ * full stack is consistent
+ * 
+ * @param stack 
+ * 
+ * @return 
+ */
+bool AbstractionModule::LemmaInstantiatior::isConsistent(const vector<int>& stack) {
+  if (stack.empty())
+    return true;
+  
+  unsigned current = stack.size() - 1;
+  TNode func = d_functions[current];
+  ArgsTableEntry& matches = d_argsTable.getEntry(func.getOperator());
+  ArgsVec& args = matches.getEntry(stack[current]);
+  Assert (args.size() == func.getNumChildren());
+  for (unsigned k = 0; k < args.size(); ++k) {
+    TNode s = func[k];
+    TNode t = args[k];
+      
+    TNode s0 = s;
+    while (d_subst.hasSubstitution(s0)) {
+      s0 = d_subst.getSubstitution(s0);
+    }
+    
+    TNode t0 = t;
+    while (d_subst.hasSubstitution(t0)) {
+      t0 = d_subst.getSubstitution(t0);
+    }
+
+    if (s0.isConst() && t0.isConst()) {
+      if (s0 != t0)
+        return false; // fail
+      else
+        continue;
+    }
+      
+    if(s0.getMetaKind() == kind::metakind::VARIABLE &&
+       t0.isConst()) {
+      d_subst.addSubstitution(s0, t0);
+      continue;
+    }
+
+    if (s0.isConst() &&
+        t0.getMetaKind() == kind::metakind::VARIABLE) {
+      d_subst.addSubstitution(t0, s0);
+      continue;
+    }
+
+    Assert (s0.getMetaKind() == kind::metakind::VARIABLE &&
+            t0.getMetaKind() == kind::metakind::VARIABLE);
+      
+    if (s0 != t0) {
+      d_subst.addSubstitution(s0, t0);
+    }
+  }
+  return true; 
+}
+
+bool AbstractionModule::LemmaInstantiatior::accept(const vector<int>& stack) {
+  return stack.size() == d_functions.size();
+}
+
+void AbstractionModule::LemmaInstantiatior::mkLemma() {
+  Node lemma = d_subst.apply(d_conflict);
+  // Debug("bv-abstraction-gen") << "AbstractionModule::LemmaInstantiatior::mkLemma " << lemma <<"\n";
+  d_lemmas.push_back(lemma); 
+}
+
+void AbstractionModule::LemmaInstantiatior::backtrack(vector<int>& stack) {
+  if (!isConsistent(stack))
+    return;
+  
+  if (accept(stack)) {
+    mkLemma();
+    return;
+  }
+
+  int x = 0;
+  while (x != -1) {
+    d_ctx->push();
+    stack.push_back(x);
+    backtrack(stack);
+    
+    d_ctx->pop();
+    stack.pop_back();
+    x = next(x, stack.size());
+  }
+}
+
+
+void AbstractionModule::LemmaInstantiatior::generateInstantiations(std::vector<Node>& lemmas) {
+  Debug("bv-abstraction-gen") << "AbstractionModule::LemmaInstantiatior::generateInstantiations "; 
+
+  std::vector<int> stack;
+  backtrack(stack);
+  Assert (d_ctx->getLevel() == 0); 
+  Debug("bv-abstraction-gen") << "numLemmas=" << d_lemmas.size() <<"\n"; 
+  lemmas.swap(d_lemmas); 
+}
+
+void AbstractionModule::makeFreshSkolems(TNode node, SubstitutionMap& map, SubstitutionMap& reverse_map) {
+  if (map.hasSubstitution(node)) {
+    return;
+  }
+  if (node.getMetaKind() == kind::metakind::VARIABLE) {
+    Node skolem = utils::mkVar(utils::getSize(node));
+    map.addSubstitution(node, skolem);
+    reverse_map.addSubstitution(skolem, node);
+    return;
+  }
+  if (node.isConst())
+    return;
+
+  for (unsigned i = 0; i < node.getNumChildren(); ++i) {
+    makeFreshSkolems(node[i], map, reverse_map);
+  }
+}
+
+void AbstractionModule::makeFreshArgs(TNode func, std::vector<Node>& fresh_args) {
+  Assert (fresh_args.size() == 0);
+  Assert (func.getKind() == kind::APPLY_UF);
+  TNodeNodeMap d_map; 
+  for (unsigned i = 0; i < func.getNumChildren(); ++i) {
+    TNode arg = func[i];
+    if (arg.isConst()) {
+      fresh_args.push_back(arg);
+      continue;
+    }
+    Assert (arg.getMetaKind() == kind::metakind::VARIABLE);
+    TNodeNodeMap::iterator it = d_map.find(arg); 
+    if (it != d_map.end()) {
+      fresh_args.push_back(it->second); 
+    } else {
+      Node skolem = utils::mkVar(utils::getSize(arg));
+      d_map[arg] = skolem;
+      fresh_args.push_back(skolem);
+    }
+  }
+  Assert (fresh_args.size() == func.getNumChildren());
+}
+
+Node AbstractionModule::tryMatching(const std::vector<Node>& ss, const std::vector<TNode>& tt, TNode conflict) {
+  Assert (ss.size() == tt.size());
+
+  Debug("bv-abstraction-dbg") << "AbstractionModule::tryMatching conflict = " << conflict << "\n";
+  if (Debug.isOn("bv-abstraction-dbg")) {
+    Debug("bv-abstraction-dbg") << "  Match: ";
+    for (unsigned i = 0; i < ss.size(); ++i) {
+      Debug("bv-abstraction-dbg") << ss[i] <<" ";
+
+    }
+    Debug("bv-abstraction-dbg") << "\n  To: ";
+    for (unsigned i = 0; i < tt.size(); ++i) {
+      Debug("bv-abstraction-dbg") << tt[i] <<" ";
+    }
+    Debug("bv-abstraction-dbg") <<"\n";
+  }
+
+  
+  SubstitutionMap subst(new context::Context());
+
+  for (unsigned i = 0; i < ss.size(); ++i) {
+    TNode s = ss[i];
+    TNode t = tt[i];
+
+    TNode s0 = subst.hasSubstitution(s) ? subst.getSubstitution(s) : s;
+    TNode t0 = subst.hasSubstitution(t) ? subst.getSubstitution(t) : t;
+
+    if (s0.isConst() && t0.isConst()) {
+      if (s0 != t0)
+        return Node(); // fail
+      else
+        continue;
+    }
+
+    if(s0.getMetaKind() == kind::metakind::VARIABLE &&
+       t0.isConst()) {
+      subst.addSubstitution(s0, t0);
+      continue;
+    }
+
+    if (s0.isConst() &&
+        t0.getMetaKind() == kind::metakind::VARIABLE) {
+      subst.addSubstitution(t0, s0);
+      continue;
+    }
+
+    Assert (s0.getMetaKind() == kind::metakind::VARIABLE &&
+            t0.getMetaKind() == kind::metakind::VARIABLE);
+
+    Assert (s0 != t0);
+    subst.addSubstitution(s0, t0);
+  }
+  
+  Node res = subst.apply(conflict);
+  Debug("bv-abstraction-dbg") << "  Lemma: " << res <<"\n"; 
+  return res; 
+}
+
+void AbstractionModule::storeLemma(TNode lemma) {
+  d_addedLemmas.insert(lemma);
+  if (lemma.getKind() == kind::AND) {
+    for (unsigned i = 0; i < lemma.getNumChildren(); i++) {
+      TNode atom = lemma[i];
+      atom = atom.getKind() == kind::NOT ? atom[0] : atom;
+      Assert (atom.getKind() != kind::NOT);
+      Assert (utils::isBVPredicate(atom));
+      d_lemmaAtoms.insert(atom); 
+    }
+  } else {
+    lemma = lemma.getKind() == kind::NOT? lemma[0] : lemma;
+    Assert (utils::isBVPredicate(lemma));
+    d_lemmaAtoms.insert(lemma);
+  }
+}
+
+
+bool AbstractionModule::isLemmaAtom(TNode node) const {
+  Assert (node.getType().isBoolean());
+  node = node.getKind() == kind::NOT? node[0] : node;
+  
+  return d_inputAtoms.find(node) == d_inputAtoms.end() &&
+    d_lemmaAtoms.find(node) != d_lemmaAtoms.end(); 
+}
+
+void AbstractionModule::addInputAtom(TNode atom) {
+  if (options::bitblastMode() == theory::bv::BITBLAST_MODE_LAZY) {
+    d_inputAtoms.insert(atom);
+  }
+}
+
+void AbstractionModule::ArgsTableEntry::addArguments(const ArgsVec& args) {
+  Assert (args.size() == d_arity);
+  d_data.push_back(args); 
+}
+
+void AbstractionModule::ArgsTable::addEntry(TNode signature, const ArgsVec& args) {
+  if (d_data.find(signature) == d_data.end()) {
+    d_data[signature] = ArgsTableEntry(args.size()); 
+  }
+  ArgsTableEntry& entry = d_data[signature];
+  entry.addArguments(args); 
+}
+
+
+bool AbstractionModule::ArgsTable::hasEntry(TNode signature) const {
+  return d_data.find(signature) != d_data.end(); 
+}
+
+AbstractionModule::ArgsTableEntry& AbstractionModule::ArgsTable::getEntry(TNode signature) {
+  Assert (hasEntry(signature));
+  return d_data.find(signature)->second; 
+}
+
+AbstractionModule::Statistics::Statistics()
+  : d_numFunctionsAbstracted("theory::bv::AbstractioModule::NumFunctionsAbstracted", 0)
+  , d_numArgsSkolemized("theory::bv::AbstractioModule::NumArgsSkolemized", 0)
+  , d_abstractionTime("theory::bv::AbstractioModule::AbstractionTime")
+{
+  StatisticsRegistry::registerStat(&d_numFunctionsAbstracted);
+  StatisticsRegistry::registerStat(&d_numArgsSkolemized);
+  StatisticsRegistry::registerStat(&d_abstractionTime);
+}
+
+AbstractionModule::Statistics::~Statistics() {
+  StatisticsRegistry::unregisterStat(&d_numFunctionsAbstracted);
+  StatisticsRegistry::unregisterStat(&d_numArgsSkolemized);
+  StatisticsRegistry::unregisterStat(&d_abstractionTime);
+}
diff --git a/src/theory/bv/abstraction.h b/src/theory/bv/abstraction.h
new file mode 100644 (file)
index 0000000..cd4c443
--- /dev/null
@@ -0,0 +1,247 @@
+ /*********************                                                        */
+/*! \file abstraction.h
+ ** \verbatim
+ ** Original author: Liana Hadarean
+ ** Major contributors: none.
+ ** 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 Bitvector theory.
+ **
+ ** Bitvector theory.
+ **/
+
+
+#ifndef __CVC4__THEORY__BV__ABSTRACTION_H
+#define __CVC4__THEORY__BV__ABSTRACTION_H
+
+#include "cvc4_private.h"
+#include <ext/hash_map>
+#include <ext/hash_set>
+#include "expr/node.h"
+#include "theory/substitutions.h"
+#include "util/statistics_registry.h"
+
+namespace CVC4 {
+namespace theory {
+namespace bv {
+
+
+typedef std::vector<TNode> ArgsVec;
+
+class AbstractionModule {
+
+  struct Statistics {
+    IntStat d_numFunctionsAbstracted;
+    IntStat d_numArgsSkolemized;
+    TimerStat d_abstractionTime;
+    Statistics();
+    ~Statistics();
+  };
+
+  
+  class ArgsTableEntry {
+    std::vector<ArgsVec> d_data;
+    unsigned d_arity;
+  public:
+    ArgsTableEntry(unsigned n)
+      : d_arity(n)
+    {}
+    ArgsTableEntry()
+      : d_arity(0)
+    {}
+    void addArguments(const ArgsVec& args);
+    typedef std::vector<ArgsVec>::iterator iterator;
+
+    iterator begin() { return d_data.begin(); }
+    iterator end() { return d_data.end(); }
+    unsigned getArity() { return d_arity; }
+    unsigned getNumEntries() { return d_data.size(); }
+    ArgsVec& getEntry(unsigned i ) { Assert (i < d_data.size()); return d_data[i]; }
+  }; 
+
+  class ArgsTable {
+    __gnu_cxx::hash_map<TNode, ArgsTableEntry, TNodeHashFunction > d_data;
+    bool hasEntry(TNode signature) const; 
+  public:
+    typedef __gnu_cxx::hash_map<TNode, ArgsTableEntry, TNodeHashFunction >::iterator iterator;
+    ArgsTable() {}
+    void addEntry(TNode signature, const ArgsVec& args);
+    ArgsTableEntry& getEntry(TNode signature);
+    iterator begin() { return d_data.begin(); }
+    iterator end() { return d_data.end(); }
+  };
+
+  /** 
+   * Checks if one pattern is a generalization of the other
+   * 
+   * @param s 
+   * @param t 
+   * 
+   * @return 1 if s :> t, 2 if s <: t, 0 if they equivalent and -1 if they are incomparable
+   */
+  static int comparePatterns(TNode s, TNode t);
+
+  class LemmaInstantiatior {
+    std::vector<TNode> d_functions;
+    std::vector<int> d_maxMatch;
+    ArgsTable& d_argsTable;
+    context::Context* d_ctx;
+    theory::SubstitutionMap d_subst;
+    TNode d_conflict;
+    std::vector<Node> d_lemmas;
+    
+    void backtrack(std::vector<int>& stack);
+    int next(int val, int index);
+    bool isConsistent(const std::vector<int>& stack);
+    bool accept(const std::vector<int>& stack);
+    void mkLemma();
+  public:
+    LemmaInstantiatior(const std::vector<TNode>& functions, ArgsTable& table, TNode conflict)
+      : d_functions(functions)
+      , d_argsTable(table)
+      , d_ctx(new context::Context())
+      , d_subst(d_ctx)
+      , d_conflict(conflict)
+      , d_lemmas()
+    {
+      Debug("bv-abstraction-gen") << "LemmaInstantiator conflict:" << conflict << "\n"; 
+      // initializing the search space
+      for (unsigned i = 0; i < functions.size(); ++i) {
+        TNode func_op = functions[i].getOperator();
+        // number of matches for this function
+        unsigned maxCount = table.getEntry(func_op).getNumEntries();
+        d_maxMatch.push_back(maxCount);
+      }
+    }
+
+    void generateInstantiations(std::vector<Node>& lemmas); 
+    
+  };
+  
+  typedef __gnu_cxx::hash_map<Node, std::vector<Node>, NodeHashFunction> NodeVecMap;
+  typedef __gnu_cxx::hash_map<Node, TNode, NodeHashFunction> NodeTNodeMap;
+  typedef __gnu_cxx::hash_map<TNode, TNode, TNodeHashFunction> TNodeTNodeMap;
+  typedef __gnu_cxx::hash_map<Node, Node, NodeHashFunction> NodeNodeMap;
+  typedef __gnu_cxx::hash_map<Node, TNode, NodeHashFunction> TNodeNodeMap;
+  typedef __gnu_cxx::hash_set<TNode, TNodeHashFunction> TNodeSet;
+  typedef __gnu_cxx::hash_map<unsigned, Node> IntNodeMap; 
+  typedef __gnu_cxx::hash_map<unsigned, unsigned> IndexMap;
+  typedef __gnu_cxx::hash_map<unsigned, std::vector<Node> > SkolemMap;
+  typedef __gnu_cxx::hash_map<TNode, unsigned, TNodeHashFunction > SignatureMap;
+  
+  ArgsTable d_argsTable; 
+
+  // mapping between signature and uninterpreted function symbol used to
+  // abstract the signature
+  NodeNodeMap d_signatureToFunc;
+  NodeNodeMap d_funcToSignature; 
+
+  NodeNodeMap d_assertionToSignature; 
+  SignatureMap d_signatures;
+  NodeNodeMap d_sigToGeneralization; 
+  TNodeSet d_skolems;
+
+  // skolems maps
+  IndexMap d_signatureIndices;
+  SkolemMap d_signatureSkolems;
+
+  void collectArgumentTypes(TNode sig, std::vector<TypeNode>& types, TNodeSet& seen);
+  void collectArguments(TNode node, TNode sig, std::vector<Node>& args, TNodeSet& seen);
+  void finalizeSignatures();
+  Node abstractSignatures(TNode assertion);
+  Node computeSignature(TNode node);
+
+  bool isConjunctionOfAtoms(TNode node);
+  bool isConjunctionOfAtomsRec(TNode node, TNodeSet& seen);
+
+  TNode getGeneralization(TNode term);
+  void storeGeneralization(TNode s, TNode t);
+
+  // signature skolem stuff
+  Node getGeneralizedSignature(Node node);
+  Node getSignatureSkolem(TNode node);
+
+  unsigned getBitwidthIndex(unsigned bitwidth); 
+  void resetSignatureIndex();
+  Node computeSignatureRec(TNode, NodeNodeMap&);
+  void storeSignature(Node signature, TNode assertion);
+  bool hasSignature(Node node);
+
+  Node substituteArguments(TNode signature, TNode apply, unsigned& i, TNodeTNodeMap& seen);
+
+  // crazy instantiation methods
+  void generateInstantiations(unsigned current,
+                              std::vector<ArgsTableEntry>& matches, 
+                              std::vector<std::vector<ArgsVec> >& instantiations,
+                              std::vector<std::vector<ArgsVec> >& new_instantiations);
+
+  Node tryMatching(const std::vector<Node>& ss, const std::vector<TNode>& tt, TNode conflict);
+  void makeFreshArgs(TNode func, std::vector<Node>& fresh_args);
+  void makeFreshSkolems(TNode node, SubstitutionMap& map, SubstitutionMap& reverse_map);
+  
+  void skolemizeArguments(std::vector<Node>& assertions);
+  Node reverseAbstraction(Node assertion, NodeNodeMap& seen);
+
+  TNodeSet d_addedLemmas;
+  TNodeSet d_lemmaAtoms;
+  TNodeSet d_inputAtoms;
+  void storeLemma(TNode lemma);
+
+  Statistics d_statistics;
+  
+public:
+  AbstractionModule()
+    : d_argsTable()
+    , d_signatureToFunc()
+    , d_funcToSignature()
+    , d_assertionToSignature()
+    , d_signatures()
+    , d_sigToGeneralization()
+    , d_skolems()
+    , d_signatureIndices()
+    , d_signatureSkolems()
+    , d_addedLemmas()
+    , d_lemmaAtoms()
+    , d_inputAtoms()
+    , d_statistics()
+  {}
+  /** 
+   * returns true if there are new uninterepreted functions symbols in the output
+   * 
+   * @param assertions 
+   * @param new_assertions 
+   * 
+   * @return 
+   */
+  bool applyAbstraction(const std::vector<Node>& assertions, std::vector<Node>& new_assertions);
+  /** 
+   * Returns true if the node represents an abstraction predicate. 
+   * 
+   * @param node 
+   * 
+   * @return 
+   */
+  bool isAbstraction(TNode node);
+  /** 
+   * Returns the interpretation of the abstraction predicate. 
+   * 
+   * @param node 
+   * 
+   * @return 
+   */
+  Node getInterpretation(TNode node);
+  Node simplifyConflict(TNode conflict); 
+  void generalizeConflict(TNode conflict, std::vector<Node>& lemmas);
+  void addInputAtom(TNode atom);
+  bool isLemmaAtom(TNode node) const;
+};
+
+}
+}
+}
+
+#endif
diff --git a/src/theory/bv/aig_bitblaster.h b/src/theory/bv/aig_bitblaster.h
new file mode 100644 (file)
index 0000000..d1635f9
--- /dev/null
@@ -0,0 +1,658 @@
+/*********************                                                        */
+/*! \file aig_bitblaster.h
+ ** \verbatim
+ ** Original author: Liana Hadarean
+ ** Major contributors: none
+ ** Minor contributors (to current version): lianah
+ ** 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 
+ **
+ ** Bitblaster for the lazy bv solver. 
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef __CVC4__AIG__BITBLASTER_H
+#define __CVC4__AIG__BITBLASTER_H
+
+
+#include "bitblaster_template.h"
+#include "prop/cnf_stream.h"
+#include "prop/sat_solver_factory.h"
+#include "theory/bv/options.h"
+
+
+#ifdef CVC4_USE_ABC
+// Function is defined as static in ABC. Not sure how else to do this. 
+static inline int Cnf_Lit2Var( int Lit ) { return (Lit & 1)? -(Lit >> 1)-1 : (Lit >> 1)+1;  }
+
+extern "C" {
+extern Aig_Man_t * Abc_NtkToDar( Abc_Ntk_t * pNtk, int fExors, int fRegisters );
+}
+
+
+namespace CVC4 {
+namespace theory {
+namespace bv {
+
+template <> inline
+std::string toString<Abc_Obj_t*> (const std::vector<Abc_Obj_t*>& bits) {
+  Unreachable("Don't know how to print AIG");
+} 
+
+
+template <> inline
+Abc_Obj_t* mkTrue<Abc_Obj_t*>() {
+  return Abc_AigConst1(AigBitblaster::currentAigNtk());  
+}
+
+template <> inline
+Abc_Obj_t* mkFalse<Abc_Obj_t*>() {
+  return Abc_ObjNot(mkTrue<Abc_Obj_t*>()); 
+}
+
+template <> inline
+Abc_Obj_t* mkNot<Abc_Obj_t*>(Abc_Obj_t* a) {
+  return Abc_ObjNot(a); 
+}
+
+template <> inline
+Abc_Obj_t* mkOr<Abc_Obj_t*>(Abc_Obj_t* a, Abc_Obj_t* b) {
+  return Abc_AigOr(AigBitblaster::currentAigM(), a, b); 
+}
+
+template <> inline
+Abc_Obj_t* mkOr<Abc_Obj_t*>(const std::vector<Abc_Obj_t*>& children) {
+  Assert (children.size());
+  if (children.size() == 1)
+    return children[0];
+  
+  Abc_Obj_t* result = children[0];
+  for (unsigned i = 1; i < children.size(); ++i) {
+    result = Abc_AigOr(AigBitblaster::currentAigM(), result, children[i]); 
+  }
+  return result;
+}
+
+
+template <> inline
+Abc_Obj_t* mkAnd<Abc_Obj_t*>(Abc_Obj_t* a, Abc_Obj_t* b) {
+  return Abc_AigAnd(AigBitblaster::currentAigM(), a, b); 
+}
+
+template <> inline
+Abc_Obj_t* mkAnd<Abc_Obj_t*>(const std::vector<Abc_Obj_t*>& children) {
+  Assert (children.size());
+  if (children.size() == 1)
+    return children[0];
+  
+  Abc_Obj_t* result = children[0];
+  for (unsigned i = 1; i < children.size(); ++i) {
+    result = Abc_AigAnd(AigBitblaster::currentAigM(), result, children[i]); 
+  }
+  return result;
+}
+
+template <> inline
+Abc_Obj_t* mkXor<Abc_Obj_t*>(Abc_Obj_t* a, Abc_Obj_t* b) {
+  return Abc_AigXor(AigBitblaster::currentAigM(), a, b); 
+}
+
+template <> inline
+Abc_Obj_t* mkIff<Abc_Obj_t*>(Abc_Obj_t* a, Abc_Obj_t* b) {
+  return mkNot(mkXor(a, b)); 
+}
+
+template <> inline
+Abc_Obj_t* mkIte<Abc_Obj_t*>(Abc_Obj_t* cond, Abc_Obj_t* a, Abc_Obj_t* b) {
+  return Abc_AigMux(AigBitblaster::currentAigM(), cond, a, b); 
+}
+
+
+Abc_Ntk_t* AigBitblaster::abcAigNetwork = NULL;
+
+Abc_Ntk_t* AigBitblaster::currentAigNtk() {
+  if (!AigBitblaster::abcAigNetwork) {
+    Abc_Start();
+    abcAigNetwork = Abc_NtkAlloc( ABC_NTK_STRASH, ABC_FUNC_AIG, 1); 
+    char pName[] = "CVC4::theory::bv::AigNetwork";
+    abcAigNetwork->pName = Extra_UtilStrsav(pName);
+  }
+  
+  return abcAigNetwork;
+}
+
+
+Abc_Aig_t* AigBitblaster::currentAigM() {
+  return (Abc_Aig_t*)(currentAigNtk()->pManFunc);
+}
+
+AigBitblaster::AigBitblaster()
+  : TBitblaster<Abc_Obj_t*>()
+  , d_aigCache()
+  , d_bbAtoms()
+  , d_aigOutputNode(NULL)
+{
+  d_nullContext = new context::Context(); 
+  d_satSolver = prop::SatSolverFactory::createMinisat(d_nullContext, "AigBitblaster");
+  MinisatEmptyNotify* notify = new MinisatEmptyNotify();
+  d_satSolver->setNotify(notify);
+}
+
+AigBitblaster::~AigBitblaster() {
+  Assert (abcAigNetwork == NULL);
+  delete d_nullContext;
+}
+
+Abc_Obj_t* AigBitblaster::bbFormula(TNode node) {
+  Assert (node.getType().isBoolean());
+  Debug("bitvector-bitblast") << "AigBitblaster::bbFormula "<< node << "\n"; 
+  
+  if (hasAig(node))
+    return getAig(node);
+  
+  Abc_Obj_t* result = NULL;
+  
+  Debug("bitvector-aig") << "AigBitblaster::convertToAig " << node <<"\n"; 
+  switch (node.getKind()) {
+  case kind::AND:
+    {
+      result = bbFormula(node[0]);
+      for (unsigned i = 1; i < node.getNumChildren(); ++i) {
+        Abc_Obj_t* child = bbFormula(node[i]);
+        result = mkAnd(result, child);
+      }
+      break;
+    }
+  case kind::OR:
+    {
+      result = bbFormula(node[0]);
+      for (unsigned i = 1; i < node.getNumChildren(); ++i) {
+        Abc_Obj_t* child = bbFormula(node[i]);
+        result = mkOr(result, child);
+      }
+      break;
+    }
+  case kind::IFF:
+    {
+      Assert (node.getNumChildren() == 2); 
+      Abc_Obj_t* child1 = bbFormula(node[0]);
+      Abc_Obj_t* child2 = bbFormula(node[1]);
+
+      result = mkIff(child1, child2); 
+      break;
+    }
+  case kind::XOR:
+    {
+      result = bbFormula(node[0]);
+      for (unsigned i = 1; i < node.getNumChildren(); ++i) {
+        Abc_Obj_t* child = bbFormula(node[i]);
+        result = mkXor(result, child);
+      }
+      break;
+    }
+  case kind::IMPLIES:
+    {
+      Assert (node.getNumChildren() == 2); 
+      Abc_Obj_t* child1 = bbFormula(node[0]);
+      Abc_Obj_t* child2 = bbFormula(node[1]);
+
+      result = mkOr(mkNot(child1), child2);
+      break;
+    }
+  case kind::ITE:
+    {
+      Assert (node.getNumChildren() == 3); 
+      Abc_Obj_t* a = bbFormula(node[0]);
+      Abc_Obj_t* b = bbFormula(node[1]);
+      Abc_Obj_t* c = bbFormula(node[2]);
+      result = mkIte(a, b, c); 
+      break;
+    }
+  case kind::NOT:
+    {
+      Abc_Obj_t* child1 = bbFormula(node[0]);
+      result = mkNot(child1);
+      break;
+    }
+  case kind::CONST_BOOLEAN:
+    {
+      result = node.getConst<bool>() ? mkTrue<Abc_Obj_t*>() : mkFalse<Abc_Obj_t*>(); 
+      break;
+    }
+  case kind::VARIABLE:
+  case kind::SKOLEM:
+    {
+      result = mkInput(node);
+      break;
+    }
+  default:
+    bbAtom(node);
+    result = getBBAtom(node);
+  }
+
+  cacheAig(node, result);
+  Debug("bitvector-aig") << "AigBitblaster::bbFormula done " << node << " => " << result <<"\n"; 
+  return result; 
+}
+
+void AigBitblaster::bbAtom(TNode node) {
+  if (hasBBAtom(node)) {
+    return;
+  }
+
+  Debug("bitvector-bitblast") << "Bitblasting atom " << node <<"\n";
+
+  // the bitblasted definition of the atom
+  Node normalized = Rewriter::rewrite(node);
+  Abc_Obj_t* atom_bb = (d_atomBBStrategies[normalized.getKind()])(normalized, this);
+  storeBBAtom(node, atom_bb);
+  Debug("bitvector-bitblast") << "Done bitblasting atom " << node <<"\n";
+}
+
+void AigBitblaster::bbTerm(TNode node, Bits& bits) {
+  if (hasBBTerm(node)) {
+    getBBTerm(node, bits);
+    return;
+  }
+
+  Debug("bitvector-bitblast") << "Bitblasting term " << node <<"\n";
+  d_termBBStrategies[node.getKind()] (node, bits, this);
+
+  Assert (bits.size() == utils::getSize(node));
+  storeBBTerm(node, bits);
+}
+
+
+void AigBitblaster::cacheAig(TNode node, Abc_Obj_t* aig) {
+  Assert (!hasAig(node));
+  d_aigCache.insert(std::make_pair(node, aig));
+}
+bool AigBitblaster::hasAig(TNode node) {
+  return d_aigCache.find(node) != d_aigCache.end(); 
+}
+Abc_Obj_t* AigBitblaster::getAig(TNode node) {
+  Assert(hasAig(node));
+  Debug("bitvector-aig") << "AigSimplifer::getAig " << node << " => " << d_aigCache.find(node)->second <<"\n"; 
+  return d_aigCache.find(node)->second; 
+}
+
+void AigBitblaster::makeVariable(TNode node, Bits& bits) {
+  
+  for (unsigned i = 0; i < utils::getSize(node); ++i) {
+    Node bit = utils::mkBitOf(node, i);
+    Abc_Obj_t* input = mkInput(bit);
+    cacheAig(bit, input); 
+    bits.push_back(input); 
+  }
+}
+
+Abc_Obj_t* AigBitblaster::mkInput(TNode input) {
+  Assert (!hasInput(input));
+  Assert(input.getKind() == kind::BITVECTOR_BITOF ||
+         (input.getType().isBoolean() &&
+          (input.getKind() == kind::VARIABLE ||
+           input.getKind() == kind::SKOLEM)));
+  Abc_Obj_t* aig_input = Abc_NtkCreatePi(currentAigNtk());
+  // d_aigCache.insert(std::make_pair(input, aig_input));
+  d_nodeToAigInput.insert(std::make_pair(input, aig_input));
+  Debug("bitvector-aig") << "AigSimplifer::mkInput " << input << " " << aig_input <<"\n"; 
+  return aig_input; 
+}
+
+bool AigBitblaster::hasInput(TNode input) {
+  return d_nodeToAigInput.find(input) != d_nodeToAigInput.end(); 
+}
+
+bool AigBitblaster::solve(TNode node) {
+  // setting output of network to be the query
+  Assert (d_aigOutputNode == NULL);
+  Abc_Obj_t* query = bbFormula(node);
+  d_aigOutputNode = Abc_NtkCreatePo(currentAigNtk());
+  Abc_ObjAddFanin(d_aigOutputNode, query); 
+
+  simplifyAig();
+  convertToCnfAndAssert();
+  // no need to use abc anymore
+  
+  TimerStat::CodeTimer solveTimer(d_statistics.d_solveTime);
+  prop::SatValue result = d_satSolver->solve();
+
+  Assert (result != prop::SAT_VALUE_UNKNOWN); 
+  return result == prop::SAT_VALUE_TRUE; 
+}
+
+
+void addAliases(Abc_Frame_t* pAbc);
+
+void AigBitblaster::simplifyAig() {
+  TimerStat::CodeTimer simpTimer(d_statistics.d_simplificationTime);
+
+  Abc_AigCleanup(currentAigM());
+  Assert (Abc_NtkCheck(currentAigNtk()));
+
+  const char* command = options::bitvectorAigSimplifications().c_str(); 
+  Abc_Frame_t* pAbc = Abc_FrameGetGlobalFrame();
+  Abc_FrameSetCurrentNetwork(pAbc, currentAigNtk());
+
+  addAliases(pAbc); 
+  if ( Cmd_CommandExecute( pAbc, command ) ) {
+    fprintf( stdout, "Cannot execute command \"%s\".\n", command );
+    exit(-1); 
+  }
+  abcAigNetwork = Abc_FrameReadNtk(pAbc); 
+}
+
+
+void AigBitblaster::convertToCnfAndAssert() {
+  TimerStat::CodeTimer cnfConversionTimer(d_statistics.d_cnfConversionTime);
+  
+  Aig_Man_t * pMan = NULL;
+  Cnf_Dat_t * pCnf = NULL;
+  assert( Abc_NtkIsStrash(currentAigNtk()) );
+  
+  // convert to the AIG manager
+  pMan = Abc_NtkToDar(currentAigNtk(), 0, 0 );
+  Abc_Stop(); 
+
+  // // free old network
+  // Abc_NtkDelete(currentAigNtk());
+  // abcAigNetwork = NULL;
+  
+  Assert (pMan != NULL);
+  Assert (Aig_ManCheck(pMan));
+  pCnf = Cnf_DeriveFast( pMan, 0 );
+
+  assertToSatSolver(pCnf); 
+    
+  Cnf_DataFree( pCnf );
+  Cnf_ManFree();
+  Aig_ManStop(pMan);
+}
+
+void AigBitblaster::assertToSatSolver(Cnf_Dat_t* pCnf) {
+  unsigned numVariables = pCnf->nVars;
+  unsigned numClauses = pCnf->nClauses;
+  
+  d_statistics.d_numVariables += numVariables; 
+  d_statistics.d_numClauses += numClauses; 
+
+  // create variables in the sat solver
+  std::vector<prop::SatVariable> sat_variables;
+  for (unsigned i = 0; i < numVariables; ++i) {
+    sat_variables.push_back(d_satSolver->newVar(false, false, false)); 
+  }
+
+  // construct clauses and add to sat solver
+  int * pLit, * pStop;
+  for (unsigned i = 0; i < numClauses; i++ ) {
+    prop::SatClause clause; 
+    for (pLit = pCnf->pClauses[i], pStop = pCnf->pClauses[i+1]; pLit < pStop; pLit++ ) {
+      int int_lit = Cnf_Lit2Var(*pLit);
+      Assert (int_lit != 0); 
+      unsigned index = int_lit < 0? -int_lit : int_lit;
+      Assert (index - 1 < sat_variables.size()); 
+      prop::SatLiteral lit(sat_variables[index-1], int_lit < 0); 
+      clause.push_back(lit); 
+    }
+    d_satSolver->addClause(clause, false); 
+  }
+}
+
+void addAliases(Abc_Frame_t* pAbc) {
+  std::vector<std::string> aliases;
+  aliases.push_back("alias b balance");
+  aliases.push_back("alias rw rewrite");
+  aliases.push_back("alias rwz rewrite -z");
+  aliases.push_back("alias rf refactor");
+  aliases.push_back("alias rfz refactor -z");
+  aliases.push_back("alias re restructure");
+  aliases.push_back("alias rez restructure -z");
+  aliases.push_back("alias rs resub");
+  aliases.push_back("alias rsz resub -z");
+  aliases.push_back("alias rsk6 rs -K 6");
+  aliases.push_back("alias rszk5 rsz -K 5");
+  aliases.push_back("alias bl b -l");
+  aliases.push_back("alias rwl rw -l");
+  aliases.push_back("alias rwzl rwz -l");
+  aliases.push_back("alias rwzl rwz -l");
+  aliases.push_back("alias rfl rf -l");
+  aliases.push_back("alias rfzl rfz -l");
+  aliases.push_back("alias brw \"b; rw\"");
+
+  for (unsigned i = 0; i < aliases.size(); ++i) {
+    if ( Cmd_CommandExecute( pAbc, aliases[i].c_str() ) ) {
+      fprintf( stdout, "Cannot execute command \"%s\".\n", aliases[i].c_str() );
+      exit(-1); 
+    }
+  }
+}
+
+bool AigBitblaster::hasBBAtom(TNode atom) const {
+  return d_bbAtoms.find(atom) != d_bbAtoms.end(); 
+}
+
+void AigBitblaster::storeBBAtom(TNode atom, Abc_Obj_t* atom_bb) {
+  d_bbAtoms.insert(std::make_pair(atom, atom_bb)); 
+}
+
+Abc_Obj_t* AigBitblaster::getBBAtom(TNode atom) const {
+  Assert (hasBBAtom(atom));
+  return d_bbAtoms.find(atom)->second;
+}
+
+AigBitblaster::Statistics::Statistics()
+  : d_numClauses("theory::bv::AigBitblaster::numClauses", 0)
+  , d_numVariables("theory::bv::AigBitblaster::numVariables", 0)
+  , d_simplificationTime("theory::bv::AigBitblaster::simplificationTime")
+  , d_cnfConversionTime("theory::bv::AigBitblaster::cnfConversionTime")
+  , d_solveTime("theory::bv::AigBitblaster::solveTime")
+{
+  StatisticsRegistry::registerStat(&d_numClauses); 
+  StatisticsRegistry::registerStat(&d_numVariables);
+  StatisticsRegistry::registerStat(&d_simplificationTime); 
+  StatisticsRegistry::registerStat(&d_cnfConversionTime);
+  StatisticsRegistry::registerStat(&d_solveTime); 
+}
+
+AigBitblaster::Statistics::~Statistics() {
+  StatisticsRegistry::unregisterStat(&d_numClauses); 
+  StatisticsRegistry::unregisterStat(&d_numVariables);
+  StatisticsRegistry::unregisterStat(&d_simplificationTime); 
+  StatisticsRegistry::unregisterStat(&d_cnfConversionTime);
+  StatisticsRegistry::unregisterStat(&d_solveTime); 
+}
+
+
+
+} /*bv namespace */
+} /* theory namespace */
+} /* CVC4 namespace*/
+
+
+#else // CVC4_USE_ABC
+
+namespace CVC4 {
+namespace theory {
+namespace bv {
+
+template <> inline
+std::string toString<Abc_Obj_t*> (const std::vector<Abc_Obj_t*>& bits) {
+  Unreachable("Don't know how to print AIG");
+} 
+
+
+template <> inline
+Abc_Obj_t* mkTrue<Abc_Obj_t*>() {
+  Unreachable();
+  return NULL;
+}
+
+template <> inline
+Abc_Obj_t* mkFalse<Abc_Obj_t*>() {
+  Unreachable();
+  return NULL;
+}
+
+template <> inline
+Abc_Obj_t* mkNot<Abc_Obj_t*>(Abc_Obj_t* a) {
+  Unreachable();
+  return NULL;
+}
+
+template <> inline
+Abc_Obj_t* mkOr<Abc_Obj_t*>(Abc_Obj_t* a, Abc_Obj_t* b) {
+  Unreachable();
+  return NULL;
+}
+
+template <> inline
+Abc_Obj_t* mkOr<Abc_Obj_t*>(const std::vector<Abc_Obj_t*>& children) {
+  Unreachable();
+  return NULL;
+}
+
+
+template <> inline
+Abc_Obj_t* mkAnd<Abc_Obj_t*>(Abc_Obj_t* a, Abc_Obj_t* b) {
+  Unreachable();
+  return NULL;
+}
+
+template <> inline
+Abc_Obj_t* mkAnd<Abc_Obj_t*>(const std::vector<Abc_Obj_t*>& children) {
+  Unreachable();
+  return NULL;
+}
+
+template <> inline
+Abc_Obj_t* mkXor<Abc_Obj_t*>(Abc_Obj_t* a, Abc_Obj_t* b) {
+  Unreachable();
+  return NULL;
+}
+
+template <> inline
+Abc_Obj_t* mkIff<Abc_Obj_t*>(Abc_Obj_t* a, Abc_Obj_t* b) {
+  Unreachable();
+  return NULL;
+}
+
+template <> inline
+Abc_Obj_t* mkIte<Abc_Obj_t*>(Abc_Obj_t* cond, Abc_Obj_t* a, Abc_Obj_t* b) {
+  Unreachable();
+  return NULL;
+}
+
+
+Abc_Ntk_t* AigBitblaster::abcAigNetwork = NULL;
+
+Abc_Ntk_t* AigBitblaster::currentAigNtk() {
+  Unreachable();
+  return NULL;
+}
+
+
+Abc_Aig_t* AigBitblaster::currentAigM() {
+  Unreachable();
+  return NULL;
+}
+
+AigBitblaster::~AigBitblaster() {
+  Unreachable();
+}
+
+Abc_Obj_t* AigBitblaster::bbFormula(TNode node) {
+  Unreachable();
+  return NULL;
+}
+
+void AigBitblaster::bbAtom(TNode node) {
+  Unreachable();
+}
+
+void AigBitblaster::bbTerm(TNode node, Bits& bits) {
+  Unreachable();
+}
+
+
+void AigBitblaster::cacheAig(TNode node, Abc_Obj_t* aig) {
+  Unreachable();
+}
+bool AigBitblaster::hasAig(TNode node) {
+  Unreachable();
+  return false; 
+}
+Abc_Obj_t* AigBitblaster::getAig(TNode node) {
+  Unreachable();
+  return NULL;
+}
+
+void AigBitblaster::makeVariable(TNode node, Bits& bits) {
+  Unreachable();  
+}
+
+Abc_Obj_t* AigBitblaster::mkInput(TNode input) {
+  Unreachable();
+  return NULL;
+} 
+
+bool AigBitblaster::hasInput(TNode input) {
+  Unreachable();
+  return false; 
+}
+
+bool AigBitblaster::solve(TNode node) {
+  Unreachable();
+  return false; 
+}
+void AigBitblaster::simplifyAig() {
+  Unreachable();
+}
+
+void AigBitblaster::convertToCnfAndAssert() {
+  Unreachable();
+}
+
+void AigBitblaster::assertToSatSolver(Cnf_Dat_t* pCnf) {
+  Unreachable();
+}
+bool AigBitblaster::hasBBAtom(TNode atom) const {
+  Unreachable();
+  return false;
+}
+
+void AigBitblaster::storeBBAtom(TNode atom, Abc_Obj_t* atom_bb) {
+  Unreachable();
+}
+
+Abc_Obj_t* AigBitblaster::getBBAtom(TNode atom) const {
+  Unreachable();
+  return NULL;
+}
+
+AigBitblaster::Statistics::Statistics()
+  : d_numClauses("theory::bv::AigBitblaster::numClauses", 0)
+  , d_numVariables("theory::bv::AigBitblaster::numVariables", 0)
+  , d_simplificationTime("theory::bv::AigBitblaster::simplificationTime")
+  , d_cnfConversionTime("theory::bv::AigBitblaster::cnfConversionTime")
+  , d_solveTime("theory::bv::AigBitblaster::solveTime")
+{}
+
+AigBitblaster::Statistics::~Statistics() {}
+
+AigBitblaster::AigBitblaster() {
+  Unreachable();
+}
+
+} // namespace bv
+} // namespace theory
+} // namespace CVC4
+
+
+#endif // CVC4_USE_ABC
+
+#endif // __CVC4__AIG__BITBLASTER_H
diff --git a/src/theory/bv/bitblast_mode.cpp b/src/theory/bv/bitblast_mode.cpp
new file mode 100644 (file)
index 0000000..91a1405
--- /dev/null
@@ -0,0 +1,55 @@
+/*********************                                                        */
+/*! \file bitblast_mode.cpp
+ ** \verbatim
+ ** Original author: Liana Hadarean
+ ** Major contributors: none
+ ** 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 Bitblast modes for bit-vector solver.
+ **
+ ** Bitblast modes for bit-vector solver.
+ **/
+
+#include "theory/bv/bitblast_mode.h"
+
+namespace CVC4 {
+
+std::ostream& operator<<(std::ostream& out, theory::bv::BitblastMode mode) {
+  switch(mode) {
+  case theory::bv::BITBLAST_MODE_LAZY:
+    out << "BITBLAST_MODE_LAZY"; 
+    break;
+  case theory::bv::BITBLAST_MODE_EAGER:
+    out << "BITBLAST_MODE_EAGER";
+    break;
+  default:
+    out << "BitblastMode:UNKNOWN![" << unsigned(mode) << "]";
+  }
+
+  return out;
+}
+
+std::ostream& operator<<(std::ostream& out, theory::bv::BvSlicerMode mode) {
+  switch(mode) {
+  case theory::bv::BITVECTOR_SLICER_ON:
+    out << "BITVECTOR_SLICER_ON"; 
+    break;
+  case theory::bv::BITVECTOR_SLICER_OFF:
+    out << "BITVECTOR_SLICER_OFF";
+    break;
+  case theory::bv::BITVECTOR_SLICER_AUTO:
+    out << "BITVECTOR_SLICER_AUTO";
+    break;
+  default:
+    out << "BvSlicerMode:UNKNOWN![" << unsigned(mode) << "]";
+  }
+
+  return out;
+}
+
+
+}/* CVC4 namespace */
diff --git a/src/theory/bv/bitblast_mode.h b/src/theory/bv/bitblast_mode.h
new file mode 100644 (file)
index 0000000..318e174
--- /dev/null
@@ -0,0 +1,72 @@
+/*********************                                                        */
+/*! \file bitblast_mode.h
+ ** \verbatim
+ ** Original author: Liana Hadarean
+ ** Major contributors: none
+ ** 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 Bitblasting modes for bit-vector solver.
+ **
+ ** Bitblasting modes for bit-vector solver.
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef __CVC4__THEORY__BV__BITBLAST_MODE_H
+#define __CVC4__THEORY__BV__BITBLAST_MODE_H
+
+#include <iostream>
+
+namespace CVC4 {
+namespace theory {
+namespace bv {
+
+/** Enumeration of bit-blasting modes */
+enum BitblastMode {
+
+  /**
+   * Lazy bit-blasting that separates boolean reasoning
+   * from term reasoning.
+   */
+  BITBLAST_MODE_LAZY,
+
+  /**
+   * Bit-blast eagerly to the bit-vector SAT solver.
+   */
+  BITBLAST_MODE_EAGER
+};/* enum BitblastMode */
+
+/** Enumeration of bit-vector equality slicer mode */
+enum BvSlicerMode {
+
+  /**
+   * Force the slicer on. 
+   */
+  BITVECTOR_SLICER_ON, 
+
+  /**
+   * Slicer off. 
+   */
+  BITVECTOR_SLICER_OFF, 
+
+  /**
+   * Auto enable slicer if problem has only equalities.
+   */
+  BITVECTOR_SLICER_AUTO
+
+};/* enum BvSlicerMode */
+
+
+}/* CVC4::theory::bv namespace */
+}/* CVC4::theory namespace */
+
+std::ostream& operator<<(std::ostream& out, theory::bv::BitblastMode mode) CVC4_PUBLIC;
+std::ostream& operator<<(std::ostream& out, theory::bv::BvSlicerMode mode) CVC4_PUBLIC;
+
+}/* CVC4 namespace */
+
+#endif /* __CVC4__THEORY__BV__BITBLAST_MODE_H */
diff --git a/src/theory/bv/bitblast_strategies.cpp b/src/theory/bv/bitblast_strategies.cpp
deleted file mode 100644 (file)
index 4a0b45d..0000000
+++ /dev/null
@@ -1,936 +0,0 @@
-/*********************                                                        */
-/*! \file bitblast_strategies.cpp
- ** \verbatim
- ** Original author: Liana Hadarean
- ** Major contributors: none
- ** Minor contributors (to current version): Clark Barrett, Dejan Jovanovic, Morgan Deters, Tim King
- ** 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 bitblasting functions for various operators. 
- **
- ** Implementation of bitblasting functions for various operators. 
- **/
-
-#include "bitblast_strategies.h"
-#include "bitblaster.h"
-#include "prop/sat_solver.h"
-#include "theory/booleans/theory_bool_rewriter.h"
-#include <cmath>
-
-using namespace CVC4::prop; 
-using namespace CVC4::theory::bv::utils;
-namespace CVC4 {
-namespace theory {
-namespace bv {
-
-/*
-  Purely debugging
- */
-
-Bits* rewriteBits(const Bits& bits) {
-  Bits* newbits = new Bits(); 
-  for (unsigned i = 0; i < bits.size(); ++i) {
-    newbits->push_back(Rewriter::rewrite(bits[i])); 
-  }
-  return newbits;
-}
-
-Node rewrite(TNode node) {
-  return Rewriter::rewrite(node); 
-}
-
-/*
- Various helper functions that get called by the bitblasting procedures
- */
-
-void inline extractBits(const Bits& b, Bits& dest, unsigned lo, unsigned hi) {
-  Assert ( lo < b.size() && hi < b.size() && lo <= hi);
-  for (unsigned i = lo; i <= hi; ++i) {
-    dest.push_back(b[i]); 
-  }
-}
-
-void inline negateBits(const Bits& bits, Bits& negated_bits) {
-  for(unsigned i = 0; i < bits.size(); ++i) {
-    negated_bits.push_back(utils::mkNot(bits[i])); 
-  }
-}
-
-bool inline isZero(const Bits& bits) {
-  for(unsigned i = 0; i < bits.size(); ++i) {
-    if(bits[i] != mkFalse()) {
-      return false; 
-    }
-  }
-  return true; 
-}
-
-void inline rshift(Bits& bits, unsigned amount) {
-  for (unsigned i = 0; i < bits.size() - amount; ++i) {
-    bits[i] = bits[i+amount]; 
-  }
-  for(unsigned i = bits.size() - amount; i < bits.size(); ++i) {
-    bits[i] = mkFalse(); 
-  }
-}
-
-void inline lshift(Bits& bits, unsigned amount) {
-  for (int i = (int)bits.size() - 1; i >= (int)amount ; --i) {
-    bits[i] = bits[i-amount]; 
-  }
-  for(unsigned i = 0; i < amount; ++i) {
-    bits[i] = mkFalse(); 
-  }
-}
-
-void inline makeZero(Bits& bits, unsigned width) {
-  Assert(bits.size() == 0); 
-  for(unsigned i = 0; i < width; ++i) {
-    bits.push_back(mkFalse()); 
-  }
-}
-
-
-/** 
- * Constructs a simple ripple carry adder
- * 
- * @param a first term to be added
- * @param b second term to be added
- * @param res the result
- * @param carry the carry-in bit 
- * 
- * @return the carry-out
- */
-Node inline rippleCarryAdder(const Bits&a, const Bits& b, Bits& res, Node carry) {
-  Assert(a.size() == b.size() && res.size() == 0);
-  
-  for (unsigned i = 0 ; i < a.size(); ++i) {
-    Node sum = mkXor(mkXor(a[i], b[i]), carry);
-    carry = mkOr( mkAnd(a[i], b[i]),
-                  mkAnd( mkXor(a[i], b[i]),
-                         carry));
-    res.push_back(sum); 
-  }
-
-  return carry;
-}
-
-inline void shiftAddMultiplier(const Bits&a, const Bits&b, Bits& res) {
-  
-  for (unsigned i = 0; i < a.size(); ++i) {
-    res.push_back(mkNode(kind::AND, b[0], a[i])); 
-  }
-  
-  for(unsigned k = 1; k < res.size(); ++k) {
-  Node carry_in = mkFalse();
-  Node carry_out;
-    for(unsigned j = 0; j < res.size() -k; ++j) {
-      Node aj = mkAnd(a[j], b[k]);
-      carry_out = mkOr(mkAnd(res[j+k], aj),
-                       mkAnd( mkXor(res[j+k], aj), carry_in));
-      res[j+k] = mkXor(mkXor(res[j+k], aj), carry_in);
-      carry_in = carry_out; 
-    }
-  }
-}
-
-Node inline uLessThanBB(const Bits&a, const Bits& b, bool orEqual) {
-  Assert (a.size() && b.size());
-  
-  Node res = mkNode(kind::AND, mkNode(kind::NOT, a[0]), b[0]);
-  
-  if(orEqual) {
-    res = mkNode(kind::OR, res, mkNode(kind::IFF, a[0], b[0])); 
-  }
-  
-  for (unsigned i = 1; i < a.size(); ++i) {
-    // a < b iff ( a[i] <-> b[i] AND a[i-1:0] < b[i-1:0]) OR (~a[i] AND b[i]) 
-    res = mkNode(kind::OR,
-                 mkNode(kind::AND, mkNode(kind::IFF, a[i], b[i]), res),
-                 mkNode(kind::AND, mkNode(kind::NOT, a[i]), b[i])); 
-  }
-  return res;
-}
-
-Node inline sLessThanBB(const Bits&a, const Bits& b, bool orEqual) {
-  Assert (a.size() && b.size());
-  if (a.size() == 1) {
-    if(orEqual) {
-      return  mkNode(kind::OR,
-                     mkNode(kind::IFF, a[0], b[0]),
-                     mkNode(kind::AND, a[0], mkNode(kind::NOT, b[0]))); 
-    }
-
-    return mkNode(kind::AND, a[0], mkNode(kind::NOT, b[0]));
-  }
-  unsigned n = a.size() - 1; 
-  Bits a1, b1;
-  extractBits(a, a1, 0, n-1);
-  extractBits(b, b1, 0, n-1);
-  
-  // unsigned comparison of the first n-1 bits
-  Node ures = uLessThanBB(a1, b1, orEqual);
-  Node res = mkNode(kind::OR,
-                    // a b have the same sign
-                    mkNode(kind::AND,
-                           mkNode(kind::IFF, a[n], b[n]),
-                           ures),
-                    // a is negative and b positive
-                    mkNode(kind::AND,
-                           a[n],
-                           mkNode(kind::NOT, b[n])));
-  return res;
-}
-
-
-/*
-  Atom bitblasting strategies 
- */
-
-
-Node UndefinedAtomBBStrategy(TNode node, Bitblaster* bb) {
-  Debug("bitvector") << "TheoryBV::Bitblaster Undefined bitblasting strategy for kind: "
-                     << node.getKind() << "\n";
-  Unreachable(); 
-}
-
-Node DefaultEqBB(TNode node, Bitblaster* bb) {
-  Debug("bitvector-bb") << "Bitblasting node " << node  << "\n";
-  
-  Assert(node.getKind() == kind::EQUAL);
-  Bits lhs, rhs; 
-  bb->bbTerm(node[0], lhs);
-  bb->bbTerm(node[1], rhs);
-
-  Assert(lhs.size() == rhs.size());
-
-  NodeManager* nm = NodeManager::currentNM();
-
-  std::vector<Node> bits_eq;
-  for (unsigned i = 0; i < lhs.size(); i++) {
-    Node bit_eq = nm->mkNode(kind::IFF, lhs[i], rhs[i]);
-    bits_eq.push_back(bit_eq); 
-  }
-  Node bv_eq = utils::mkAnd(bits_eq);
-  return bv_eq; 
-}
-
-
-Node AdderUltBB(TNode node, Bitblaster* bb) {
-  Debug("bitvector-bb") << "Bitblasting node " << node  << "\n";
-  Assert(node.getKind() == kind::BITVECTOR_ULT);
-  Bits a, b;
-  bb->bbTerm(node[0], a);
-  bb->bbTerm(node[1], b);
-  Assert(a.size() == b.size());
-  
-  // a < b <=> ~ (add(a, ~b, 1).carry_out)
-  Bits not_b;
-  negateBits(b, not_b);
-  Node carry = mkTrue();
-  
-  for (unsigned i = 0 ; i < a.size(); ++i) {
-    carry = mkOr( mkAnd(a[i], not_b[i]),
-                  mkAnd( mkXor(a[i], not_b[i]),
-                         carry));
-  }
-  return mkNot(carry); 
-}
-
-
-Node DefaultUltBB(TNode node, Bitblaster* bb) {
-  Debug("bitvector-bb") << "Bitblasting node " << node  << "\n";
-  Assert(node.getKind() == kind::BITVECTOR_ULT);
-  Bits a, b;
-  bb->bbTerm(node[0], a);
-  bb->bbTerm(node[1], b);
-  Assert(a.size() == b.size());
-  
-  // construct bitwise comparison 
-  Node res = uLessThanBB(a, b, false);
-  return res; 
-}
-
-Node DefaultUleBB(TNode node, Bitblaster* bb){
-  Debug("bitvector-bb") << "Bitblasting node " << node  << "\n";
-  Assert(node.getKind() == kind::BITVECTOR_ULE);
-  Bits a, b;
-  
-  bb->bbTerm(node[0], a);
-  bb->bbTerm(node[1], b);
-  Assert(a.size() == b.size());
-  // construct bitwise comparison 
-  Node res = uLessThanBB(a, b, true);
-  return res; 
-}
-
-Node DefaultUgtBB(TNode node, Bitblaster* bb){
-  Debug("bitvector-bb") << "Bitblasting node " << node  << "\n";
-  // should be rewritten 
-  Unimplemented(); 
-}
-Node DefaultUgeBB(TNode node, Bitblaster* bb){
-  Debug("bitvector-bb") << "Bitblasting node " << node  << "\n";
-  // should be rewritten 
-  Unimplemented(); 
-}
-
-// Node DefaultSltBB(TNode node, Bitblaster* bb){
-//   Debug("bitvector-bb") << "Bitblasting node " << node  << "\n";
-//   // shoudl be rewritten in terms of ult
-//   Unimplemented(); 
-// }
-
-// Node DefaultSleBB(TNode node, Bitblaster* bb){
-//   Debug("bitvector-bb") << "Bitblasting node " << node  << "\n";
-//   // shoudl be rewritten in terms of ule
-//   Unimplemented(); 
-// }
-
-
-Node DefaultSltBB(TNode node, Bitblaster* bb){
-  Debug("bitvector-bb") << "Bitblasting node " << node  << "\n";
-
-  Bits a, b;
-  bb->bbTerm(node[0], a);
-  bb->bbTerm(node[1], b);
-  Assert(a.size() == b.size());
-  
-  Node res = sLessThanBB(a, b, false); 
-  return res;
-}
-
-Node DefaultSleBB(TNode node, Bitblaster* bb){
-  Debug("bitvector-bb") << "Bitblasting node " << node  << "\n";
-
-  Bits a, b;
-  bb->bbTerm(node[0], a);
-  bb->bbTerm(node[1], b);
-  Assert(a.size() == b.size());
-  
-  Node res = sLessThanBB(a, b, true); 
-  return res;
-}
-Node DefaultSgtBB(TNode node, Bitblaster* bb){
-  Debug("bitvector-bb") << "Bitblasting node " << node  << "\n";
-  // should be rewritten 
-  Unimplemented(); 
-}
-
-Node DefaultSgeBB(TNode node, Bitblaster* bb){
-  Debug("bitvector-bb") << "Bitblasting node " << node  << "\n";
-  // should be rewritten 
-  Unimplemented(); 
-}
-
-
-/// Term bitblasting strategies 
-
-void UndefinedTermBBStrategy(TNode node, Bits& bits, Bitblaster* bb) {
-  Debug("bitvector") << "theory::bv:: Undefined bitblasting strategy for kind: "
-                     << node.getKind() << "\n";
-  Unreachable(); 
-}
-
-void DefaultVarBB (TNode node, Bits& bits, Bitblaster* bb) {
-  Assert(bits.size() == 0);
-  for (unsigned i = 0; i < utils::getSize(node); ++i) {
-    bits.push_back(utils::mkBitOf(node, i));
-  }
-
-  if(Debug.isOn("bitvector-bb")) {
-    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) {
-  Debug("bitvector-bb") << "theory::bv::DefaultConstBB bitblasting " << node << "\n";
-  Assert(node.getKind() == kind::CONST_BITVECTOR);
-  Assert(bits.size() == 0);
-  
-  for (unsigned i = 0; i < utils::getSize(node); ++i) {
-    Integer bit = node.getConst<BitVector>().extract(i, i).getValue();
-    if(bit == Integer(0)){
-      bits.push_back(utils::mkFalse());
-    } else {
-      Assert (bit == Integer(1));
-      bits.push_back(utils::mkTrue()); 
-    }
-  }
-  if(Debug.isOn("bitvector-bb")) {
-    Debug("bitvector-bb") << "with  bits: " << toString(bits) << "\n"; 
-  }
-}
-
-
-void DefaultNotBB (TNode node, Bits& bits, Bitblaster* bb) {
-  Debug("bitvector-bb") << "theory::bv::DefaultNotBB bitblasting " << node << "\n";
-  Assert(node.getKind() == kind::BITVECTOR_NOT);
-  Assert(bits.size() == 0);
-  Bits bv; 
-  bb->bbTerm(node[0], bv);
-  negateBits(bv, bits);
-}
-
-void DefaultConcatBB (TNode node, Bits& bits, Bitblaster* bb) {
-  Debug("bitvector-bb") << "theory::bv::DefaultConcatBB bitblasting " << node << "\n";
-  Assert(bits.size() == 0);
-  
-  Assert (node.getKind() == kind::BITVECTOR_CONCAT);
-  for (int i = node.getNumChildren() -1 ; i >= 0; --i ) {
-    TNode current = node[i];
-    Bits current_bits; 
-    bb->bbTerm(current, current_bits);
-
-    for(unsigned j = 0; j < utils::getSize(current); ++j) {
-      bits.push_back(current_bits[j]);
-    }
-  }
-  Assert (bits.size() == utils::getSize(node)); 
-  if(Debug.isOn("bitvector-bb")) {
-    Debug("bitvector-bb") << "with  bits: " << toString(bits) << "\n"; 
-  }
-}
-
-void DefaultAndBB (TNode node, Bits& bits, Bitblaster* bb) {
-  Debug("bitvector-bb") << "theory::bv::DefaultAndBB bitblasting " << node << "\n";
-  
-  Assert(node.getKind() == kind::BITVECTOR_AND &&
-         bits.size() == 0);
-  
-  for(unsigned j = 0; j < utils::getSize(node); ++j) {
-    NodeBuilder<> andBuilder(kind::AND);
-    for (unsigned i = 0; i < node.getNumChildren(); ++i) {
-      Bits current;
-      bb->bbTerm(node[i], current);
-      andBuilder << current[j];
-      Assert(utils::getSize(node) == current.size());
-    }
-    bits.push_back(andBuilder); 
-  }
-}
-
-void DefaultOrBB (TNode node, Bits& bits, Bitblaster* bb) {
-  Debug("bitvector-bb") << "theory::bv::DefaultOrBB bitblasting " << node << "\n";
-
-  Assert(node.getKind() == kind::BITVECTOR_OR &&
-         bits.size() == 0);
-  
-  for(unsigned j = 0; j < utils::getSize(node); ++j) {
-    NodeBuilder<> orBuilder(kind::OR);
-    for (unsigned i = 0; i < node.getNumChildren(); ++i) {
-      Bits current;
-      bb->bbTerm(node[i], current);
-      orBuilder << current[j];
-      Assert(utils::getSize(node) == current.size());
-    }
-    bits.push_back(orBuilder); 
-  }
-}
-
-void DefaultXorBB (TNode node, Bits& bits, Bitblaster* bb) {
-  Debug("bitvector-bb") << "theory::bv::DefaultXorBB bitblasting " << node << "\n";
-
-  Assert(node.getKind() == kind::BITVECTOR_XOR &&
-         bits.size() == 0);
-  
-  for(unsigned j = 0; j < utils::getSize(node); ++j) {
-    Bits first;
-    bb->bbTerm(node[0], first); 
-    Node bitj = first[j];
-    
-    for (unsigned i = 1; i < node.getNumChildren(); ++i) {
-      Bits current;
-      bb->bbTerm(node[i], current);
-      bitj = utils::mkNode(kind::XOR, bitj, current[j]);
-      Assert(utils::getSize(node) == current.size());
-    }
-    bits.push_back(bitj); 
-  }
-}
-
-void DefaultXnorBB (TNode node, Bits& bits, Bitblaster* bb) {
-  Debug("bitvector-bb") << "theory::bv::DefaultXnorBB bitblasting " << node << "\n";
-
-  Assert(node.getNumChildren() == 2 &&
-         node.getKind() == kind::BITVECTOR_XNOR &&
-         bits.size() == 0);
-  Bits lhs, rhs;
-  bb->bbTerm(node[0], lhs);
-  bb->bbTerm(node[1], rhs);
-  Assert(lhs.size() == rhs.size()); 
-  
-  for (unsigned i = 0; i < lhs.size(); ++i) {
-    bits.push_back(utils::mkNode(kind::IFF, lhs[i], rhs[i])); 
-  }
-}
-
-
-void DefaultNandBB (TNode node, Bits& bits, Bitblaster* bb) {
-  Debug("bitvector") << "theory::bv:: Unimplemented kind "
-                     << node.getKind() << "\n";
-  Unimplemented(); 
-}
-void DefaultNorBB (TNode node, Bits& bits, Bitblaster* bb) {
-  Debug("bitvector") << "theory::bv:: Unimplemented kind "
-                     << node.getKind() << "\n";
-  Unimplemented(); 
-}
-void DefaultCompBB (TNode node, Bits& bits, Bitblaster* bb) {
-  Debug("bitvector") << "theory::bv:: DefaultCompBB bitblasting "<< node << "\n";
-
-  Assert(getSize(node) == 1 && bits.size() == 0 && node.getKind() == kind::BITVECTOR_COMP);
-  Bits a, b;
-  bb->bbTerm(node[0], a);
-  bb->bbTerm(node[1], b);
-
-  std::vector<Node> bit_eqs;
-  NodeManager* nm = NodeManager::currentNM(); 
-  for (unsigned i = 0; i < a.size(); ++i) {
-    Node eq = nm->mkNode(kind::IFF, a[i], b[i]);
-    bit_eqs.push_back(eq); 
-  }
-  Node a_eq_b = mkAnd(bit_eqs);
-  bits.push_back(a_eq_b);   
-}
-
-void DefaultMultBB (TNode node, Bits& res, Bitblaster* bb) {
-  Debug("bitvector") << "theory::bv:: DefaultMultBB bitblasting "<< node << "\n";
-  Assert(res.size() == 0 &&
-         node.getKind() == kind::BITVECTOR_MULT);
-
-  Bits newres; 
-  bb->bbTerm(node[0], res); 
-  for(unsigned i = 1; i < node.getNumChildren(); ++i) {
-    Bits current;
-    bb->bbTerm(node[i], current);
-    newres.clear(); 
-    // constructs a simple shift and add multiplier building the result
-    // in res
-    shiftAddMultiplier(res, current, newres);
-    res = newres;
-  }
-  if(Debug.isOn("bitvector-bb")) {
-    Debug("bitvector-bb") << "with bits: " << toString(res)  << "\n";
-  }
-}
-
-void DefaultPlusBB (TNode node, Bits& res, Bitblaster* bb) {
-  Debug("bitvector-bb") << "theory::bv::DefaultPlusBB bitblasting " << node << "\n";
-  Assert(node.getKind() == kind::BITVECTOR_PLUS &&
-         res.size() == 0);
-
-  bb->bbTerm(node[0], res);
-
-  Bits newres;
-
-  for(unsigned i = 1; i < node.getNumChildren(); ++i) {
-    Bits current;
-    bb->bbTerm(node[i], current);
-    newres.clear(); 
-    rippleCarryAdder(res, current, newres, utils::mkFalse());
-    res = newres; 
-  }
-  
-  Assert(res.size() == utils::getSize(node));
-}
-
-
-void DefaultSubBB (TNode node, Bits& bits, Bitblaster* bb) {
-  Debug("bitvector-bb") << "theory::bv::DefaultSubBB bitblasting " << node << "\n";
-  Assert(node.getKind() == kind::BITVECTOR_SUB &&
-         node.getNumChildren() == 2 &&
-         bits.size() == 0);
-    
-  Bits a, b;
-  bb->bbTerm(node[0], a);
-  bb->bbTerm(node[1], b); 
-  Assert(a.size() == b.size() && utils::getSize(node) == a.size());
-
-  // bvsub a b = adder(a, ~b, 1)
-  Bits not_b;
-  negateBits(b, not_b);
-  Node carry = utils::mkTrue();
-  rippleCarryAdder(a, not_b, bits, mkTrue());
-}
-
-void DefaultNegBB (TNode node, Bits& bits, Bitblaster* bb) {
-  Debug("bitvector-bb") << "theory::bv::DefaultNegBB bitblasting " << node << "\n";
-  Assert(node.getKind() == kind::BITVECTOR_NEG);
-  
-  Bits a;
-  bb->bbTerm(node[0], a);
-  Assert(utils::getSize(node) == a.size());
-
-  // -a = add(~a, 0, 1).
-  Bits not_a;
-  negateBits(a, not_a);
-  Bits zero;
-  makeZero(zero, getSize(node)); 
-  
-  rippleCarryAdder(not_a, zero, bits, mkTrue()); 
-}
-
-void uDivModRec(const Bits& a, const Bits& b, Bits& q, Bits& r, unsigned rec_width) {
-  Assert( q.size() == 0 && r.size() == 0);
-
-  if(rec_width == 0 || isZero(a)) {
-    makeZero(q, a.size());
-    makeZero(r, a.size());
-    return;
-  } 
-  
-  Bits q1, r1;
-  Bits a1 = a;
-  rshift(a1, 1); 
-
-  uDivModRec(a1, b, q1, r1, rec_width - 1);
-  // shift the quotient and remainder (i.e. multiply by two) and add 1 to remainder if a is odd
-  lshift(q1, 1);
-  lshift(r1, 1);
-
-  
-  Node is_odd = mkNode(kind::IFF, a[0], mkTrue());
-  Node one_if_odd = mkNode(kind::ITE, is_odd, mkTrue(), mkFalse()); 
-
-  Bits zero;
-  makeZero(zero, b.size());
-  
-  Bits r1_shift_add;
-  // account for a being odd
-  rippleCarryAdder(r1, zero, r1_shift_add, one_if_odd); 
-  // now check if the remainder is greater than b
-  Bits not_b;
-  negateBits(b, not_b);
-  Bits r_minus_b;
-  Node co1;
-  // use adder because we need r_minus_b anyway
-  co1 = rippleCarryAdder(r1_shift_add, not_b, r_minus_b, mkTrue()); 
-  // sign is true if r1 < b
-  Node sign = mkNode(kind::NOT, co1); 
-  
-  q1[0] = mkNode(kind::ITE, sign, q1[0], mkTrue());
-
-  // would be nice to have a high level ITE instead of bitwise
-  for(unsigned i = 0; i < a.size(); ++i) {
-    r1_shift_add[i] = mkNode(kind::ITE, sign, r1_shift_add[i], r_minus_b[i]); 
-  }
-
-  // check if a < b
-
-  Bits a_minus_b;
-  Node co2 = rippleCarryAdder(a, not_b, a_minus_b, mkTrue());
-  // Node a_lt_b = a_minus_b.back();
-  Node a_lt_b = mkNode(kind::NOT, co2); 
-  
-  for(unsigned i = 0; i < a.size(); ++i) {
-    Node qval = mkNode(kind::ITE, a_lt_b, mkFalse(), q1[i]);
-    Node rval = mkNode(kind::ITE, a_lt_b, a[i], r1_shift_add[i]);
-    q.push_back(qval);
-    r.push_back(rval); 
-  }
-
-}
-
-void DefaultUdivBB (TNode node, Bits& q, Bitblaster* bb) {
-  Debug("bitvector-bb") << "theory::bv::DefaultUdivBB bitblasting " << node << "\n";
-  Assert(node.getKind() == kind::BITVECTOR_UDIV_TOTAL &&  q.size() == 0);
-
-  Bits a, b;
-  bb->bbTerm(node[0], a);
-  bb->bbTerm(node[1], b);
-
-  Bits r;
-  uDivModRec(a, b, q, r, getSize(node)); 
-  // adding a special case for division by 0
-  std::vector<Node> iszero; 
-  for (unsigned i = 0; i < b.size(); ++i) {
-    iszero.push_back(utils::mkNode(kind::IFF, b[i], utils::mkFalse())); 
-  }
-  Node b_is_0 = utils::mkAnd(iszero); 
-  
-  for (unsigned i = 0; i < q.size(); ++i) {
-    q[i] = utils::mkNode(kind::ITE, b_is_0, utils::mkFalse(), q[i]);
-    r[i] = utils::mkNode(kind::ITE, b_is_0, utils::mkFalse(), r[i]);
-  }
-
-  // cache the remainder in case we need it later
-  Node remainder = mkNode(kind::BITVECTOR_UREM_TOTAL, node[0], node[1]);
-  bb->cacheTermDef(remainder, r);
-}
-
-void DefaultUremBB (TNode node, Bits& rem, Bitblaster* bb) {
-  Debug("bitvector-bb") << "theory::bv::DefaultUremBB bitblasting " << node << "\n";
-  Assert(node.getKind() == kind::BITVECTOR_UREM_TOTAL &&  rem.size() == 0);
-
-  Bits a, b;
-  bb->bbTerm(node[0], a);
-  bb->bbTerm(node[1], b);
-
-  Bits q;
-  uDivModRec(a, b, q, rem, getSize(node)); 
-  // adding a special case for division by 0
-  std::vector<Node> iszero; 
-  for (unsigned i = 0; i < b.size(); ++i) {
-    iszero.push_back(utils::mkNode(kind::IFF, b[i], utils::mkFalse())); 
-  }
-  Node b_is_0 = utils::mkAnd(iszero); 
-  
-  for (unsigned i = 0; i < q.size(); ++i) {
-    q[i] = utils::mkNode(kind::ITE, b_is_0, utils::mkFalse(), q[i]);
-    rem[i] = utils::mkNode(kind::ITE, b_is_0, utils::mkFalse(), rem[i]);
-  }
-
-  // cache the quotient in case we need it later
-  Node quotient = mkNode(kind::BITVECTOR_UDIV_TOTAL, node[0], node[1]);
-  bb->cacheTermDef(quotient, q);
-}
-
-
-void DefaultSdivBB (TNode node, Bits& bits, Bitblaster* bb) {
-  Debug("bitvector") << "theory::bv:: Unimplemented kind "
-                     << node.getKind() << "\n";
-  Unimplemented(); 
-}
-void DefaultSremBB (TNode node, Bits& bits, Bitblaster* bb) {
-  Debug("bitvector") << "theory::bv:: Unimplemented kind "
-                     << node.getKind() << "\n";
-  Unimplemented(); 
-}
-void DefaultSmodBB (TNode node, Bits& bits, Bitblaster* bb) {
-  Debug("bitvector") << "theory::bv:: Unimplemented kind "
-                     << node.getKind() << "\n";
-  Unimplemented(); 
-}
-
-void DefaultShlBB (TNode node, Bits& res, Bitblaster* bb) {
-  Debug("bitvector-bb") << "theory::bv::DefaultShlBB bitblasting " << node  << "\n";
-  Assert (node.getKind() == kind::BITVECTOR_SHL &&
-          res.size() == 0);
-  Bits a, b;
-  bb->bbTerm(node[0], a);
-  bb->bbTerm(node[1], b);
-
-  // check for b < log2(n)
-  unsigned size = utils::getSize(node);
-  unsigned log2_size = std::ceil(log2((double)size));
-  Node a_size = utils::mkConst(BitVector(size, size)); 
-  Node b_ult_a_size = utils::mkNode(kind::BITVECTOR_ULT, node[1], a_size);
-  // ensure that the inequality is bit-blasted
-  bb->bbAtom(b_ult_a_size); 
-  
-  Bits prev_res;
-  res = a; 
-  // we only need to look at the bits bellow log2_a_size
-  for(unsigned s = 0; s < log2_size; ++s) {
-    // barrel shift stage: at each stage you can either shift by 2^s bits
-    // or leave the previous stage untouched
-    prev_res = res; 
-    unsigned threshold = pow(2, s); 
-    for(unsigned i = 0; i < a.size(); ++i) {
-      if (i < threshold) {
-        // if b[s] is true then we must have shifted by at least 2^b bits so
-        // all bits bellow 2^s will be 0, otherwise just use previous shift value
-        res[i] = mkNode(kind::ITE, b[s], mkFalse(), prev_res[i]);
-      } else {
-        // if b[s]= 0, use previous value, otherwise shift by threshold  bits
-        Assert(i >= threshold); 
-        res[i] = mkNode(kind::ITE, b[s], prev_res[i-threshold], prev_res[i]); 
-      }
-    }
-  }
-  prev_res = res;
-  for (unsigned i = 0; i < b.size(); ++i) {
-    // this is fine  because b_ult_a_size has been bit-blasted
-    res[i] = utils::mkNode(kind::ITE, b_ult_a_size, prev_res[i], utils::mkFalse()); 
-  }
-  
-  if(Debug.isOn("bitvector-bb")) {
-    Debug("bitvector-bb") << "with bits: " << toString(res)  << "\n";
-  }
-}
-
-void DefaultLshrBB (TNode node, Bits& res, Bitblaster* bb) {
-  Debug("bitvector-bb") << "theory::bv::DefaultLshrBB bitblasting " << node  << "\n";
-  Assert (node.getKind() == kind::BITVECTOR_LSHR &&
-          res.size() == 0);
-  Bits a, b;
-  bb->bbTerm(node[0], a);
-  bb->bbTerm(node[1], b);
-
-  // check for b < log2(n)
-  unsigned size = utils::getSize(node);
-  unsigned log2_size = std::ceil(log2((double)size));
-  Node a_size = utils::mkConst(BitVector(size, size)); 
-  Node b_ult_a_size = utils::mkNode(kind::BITVECTOR_ULT, node[1], a_size);
-  // ensure that the inequality is bit-blasted
-  bb->bbAtom(b_ult_a_size); 
-  
-  res = a;
-  Bits prev_res;
-  
-  for(unsigned s = 0; s < log2_size; ++s) {
-    // barrel shift stage: at each stage you can either shift by 2^s bits
-    // or leave the previous stage untouched
-    prev_res = res; 
-    int threshold = pow(2, s); 
-    for(unsigned i = 0; i < a.size(); ++i) {
-      if (i + threshold >= a.size()) {
-        // if b[s] is true then we must have shifted by at least 2^b bits so
-        // all bits above 2^s will be 0, otherwise just use previous shift value
-        res[i] = mkNode(kind::ITE, b[s], mkFalse(), prev_res[i]);
-      } else {
-        // if b[s]= 0, use previous value, otherwise shift by threshold  bits
-        Assert (i+ threshold < a.size()); 
-        res[i] = mkNode(kind::ITE, mkNot(b[s]), prev_res[i], prev_res[i+threshold]);
-      }
-    }
-  }
-  
-  prev_res = res;
-  for (unsigned i = 0; i < b.size(); ++i) {
-    // this is fine  because b_ult_a_size has been bit-blasted
-    res[i] = utils::mkNode(kind::ITE, b_ult_a_size, prev_res[i], utils::mkFalse()); 
-  }
-
-  if(Debug.isOn("bitvector-bb")) {
-    Debug("bitvector-bb") << "with bits: " << toString(res)  << "\n";
-  }
-}
-
-void DefaultAshrBB (TNode node, Bits& res, Bitblaster* bb) {
-
-  Debug("bitvector-bb") << "theory::bv::DefaultAshrBB bitblasting " << node  << "\n";
-  Assert (node.getKind() == kind::BITVECTOR_ASHR &&
-          res.size() == 0);
-  Bits a, b;
-  bb->bbTerm(node[0], a);
-  bb->bbTerm(node[1], b);
-
-  //   check for b < n
-  unsigned size = utils::getSize(node);
-  unsigned log2_size = std::ceil(log2((double)size));
-  Node a_size = utils::mkConst(BitVector(size, size)); 
-  Node b_ult_a_size = utils::mkNode(kind::BITVECTOR_ULT, node[1], a_size);
-  // ensure that the inequality is bit-blasted
-  bb->bbAtom(b_ult_a_size); 
-  
-  res = a;
-  TNode sign_bit = a.back();
-  Bits prev_res;
-
-  for(unsigned s = 0; s < log2_size; ++s) {
-    // barrel shift stage: at each stage you can either shift by 2^s bits
-    // or leave the previous stage untouched
-    prev_res = res; 
-    int threshold = pow(2, s); 
-    for(unsigned i = 0; i < a.size(); ++i) {
-      if (i + threshold >= a.size()) {
-        // if b[s] is true then we must have shifted by at least 2^b bits so
-        // all bits above 2^s will be the sign bit, otherwise just use previous shift value
-        res[i] = mkNode(kind::ITE, b[s], sign_bit, prev_res[i]);
-      } else {
-        // if b[s]= 0, use previous value, otherwise shift by threshold  bits
-        Assert (i+ threshold < a.size()); 
-        res[i] = mkNode(kind::ITE, mkNot(b[s]), prev_res[i], prev_res[i+threshold]);
-      }
-    }
-  }
-
-  prev_res = res;
-  for (unsigned i = 0; i < b.size(); ++i) {
-    // this is fine  because b_ult_a_size has been bit-blasted
-    res[i] = utils::mkNode(kind::ITE, b_ult_a_size, prev_res[i], sign_bit); 
-  }
-
-  if(Debug.isOn("bitvector-bb")) {
-    Debug("bitvector-bb") << "with bits: " << toString(res)  << "\n";
-  }
-}
-
-void DefaultExtractBB (TNode node, Bits& bits, Bitblaster* bb) {
-  Assert (node.getKind() == kind::BITVECTOR_EXTRACT);
-  Assert(bits.size() == 0);
-  
-  Bits base_bits;
-  bb->bbTerm(node[0], base_bits);
-  unsigned high = utils::getExtractHigh(node);
-  unsigned low  = utils::getExtractLow(node);
-
-  for (unsigned i = low; i <= high; ++i) {
-    bits.push_back(base_bits[i]); 
-  }
-  Assert (bits.size() == high - low + 1);   
-
-  if(Debug.isOn("bitvector-bb")) {
-    Debug("bitvector-bb") << "theory::bv::DefaultExtractBB bitblasting " << node << "\n";
-    Debug("bitvector-bb") << "                               with bits " << toString(bits); 
-  }
-}
-
-
-void DefaultRepeatBB (TNode node, Bits& bits, Bitblaster* bb) {
-  Debug("bitvector") << "theory::bv:: Unimplemented kind "
-                     << node.getKind() << "\n";
-  // this should be rewritten 
-  Unimplemented(); 
-}
-
-void DefaultZeroExtendBB (TNode node, Bits& res_bits, Bitblaster* bb) {
-
-  Debug("bitvector-bb") << "theory::bv::DefaultZeroExtendBB bitblasting " << node  << "\n";
-  // this should be rewritten 
-  Unimplemented();
-  
-}
-
-void DefaultSignExtendBB (TNode node, Bits& res_bits, Bitblaster* bb) {
-  Debug("bitvector-bb") << "theory::bv::DefaultSignExtendBB bitblasting " << node  << "\n";
-
-  Assert (node.getKind() == kind::BITVECTOR_SIGN_EXTEND &&
-          res_bits.size() == 0);
-
-  Bits bits;
-  bb->bbTerm(node[0], bits);
-  
-  TNode sign_bit = bits.back(); 
-  unsigned amount = node.getOperator().getConst<BitVectorSignExtend>().signExtendAmount; 
-
-  for (unsigned i = 0; i < bits.size(); ++i ) {
-    res_bits.push_back(bits[i]); 
-  }
-         
-  for (unsigned i = 0 ; i < amount ; ++i ) {
-    res_bits.push_back(sign_bit); 
-  }
-         
-  Assert (res_bits.size() == amount + bits.size()); 
-}
-
-void DefaultRotateRightBB (TNode node, Bits& res, Bitblaster* bb) {
-  Debug("bitvector") << "theory::bv:: Unimplemented kind "
-                     << node.getKind() << "\n";
-
-  Unimplemented(); 
-}
-
-void DefaultRotateLeftBB (TNode node, Bits& bits, Bitblaster* bb) {
-  Debug("bitvector") << "theory::bv:: Unimplemented kind "
-                     << node.getKind() << "\n";
-  Unimplemented(); 
-}
-
-
-}
-}
-}
-
-
diff --git a/src/theory/bv/bitblast_strategies.h b/src/theory/bv/bitblast_strategies.h
deleted file mode 100644 (file)
index cb29e43..0000000
+++ /dev/null
@@ -1,109 +0,0 @@
-/*********************                                                        */
-/*! \file bitblast_strategies.h
- ** \verbatim
- ** Original author: Liana Hadarean
- ** Major contributors: none
- ** Minor contributors (to current version): Dejan Jovanovic, Morgan Deters
- ** 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 bitblasting functions for various operators. 
- **
- ** Implementation of bitblasting functions for various operators. 
- **/
-
-#include "cvc4_private.h"
-
-#ifndef __CVC4__BITBLAST__STRATEGIES_H
-#define __CVC4__BITBLAST__STRATEGIES_H
-
-
-#include "expr/node.h"
-#include "prop/sat_solver.h"
-
-namespace CVC4 {
-
-
-namespace theory {
-namespace bv {
-
-class Bitblaster;
-
-
-typedef std::vector<Node>    Bits; 
-
-
-/** 
- * Default Atom Bitblasting strategies: 
- * 
- * @param node the atom to be bitblasted
- * @param bb the bitblaster
- */
-
-Node UndefinedAtomBBStrategy (TNode node, Bitblaster* bb);                               
-Node DefaultEqBB(TNode node, Bitblaster* bb);
-
-Node DefaultUltBB(TNode node, Bitblaster* bb);
-Node DefaultUleBB(TNode node, Bitblaster* bb);
-Node DefaultUgtBB(TNode node, Bitblaster* bb);
-Node DefaultUgeBB(TNode node, Bitblaster* bb);
-
-Node DefaultSltBB(TNode node, Bitblaster* bb);
-Node DefaultSleBB(TNode node, Bitblaster* bb);
-Node DefaultSgtBB(TNode node, Bitblaster* bb);
-Node DefaultSgeBB(TNode node, Bitblaster* bb);
-
-/// other modes
-Node AdderUltBB(TNode node, Bitblaster* bb);
-Node SltBB(TNode node, Bitblaster* bb);
-Node SleBB(TNode node, Bitblaster* bb); 
-
-
-/** 
- * Default Term Bitblasting strategies
- * 
- * @param node the term to be bitblasted
- * @param bits [output parameter] bits representing the new term 
- * @param bb the bitblaster in which the clauses are added
- */
-
-void UndefinedTermBBStrategy(TNode node, Bits& bits, Bitblaster* bb); 
-
-void DefaultVarBB         (TNode node, Bits& bits, Bitblaster* bb);
-void DefaultConstBB       (TNode node, Bits& bits, Bitblaster* bb);
-void DefaultNotBB         (TNode node, Bits& bits, Bitblaster* bb);
-void DefaultConcatBB      (TNode node, Bits& bits, Bitblaster* bb);
-void DefaultAndBB         (TNode node, Bits& bits, Bitblaster* bb);
-void DefaultOrBB          (TNode node, Bits& bits, Bitblaster* bb);
-void DefaultXorBB         (TNode node, Bits& bits, Bitblaster* bb);
-void DefaultXnorBB         (TNode node, Bits& bits, Bitblaster* bb);
-void DefaultNandBB        (TNode node, Bits& bits, Bitblaster* bb);
-void DefaultNorBB         (TNode node, Bits& bits, Bitblaster* bb);
-void DefaultCompBB        (TNode node, Bits& bits, Bitblaster* bb);
-void DefaultMultBB        (TNode node, Bits& bits, Bitblaster* bb);
-void DefaultPlusBB        (TNode node, Bits& bits, Bitblaster* bb);
-void DefaultSubBB         (TNode node, Bits& bits, Bitblaster* bb);
-void DefaultNegBB         (TNode node, Bits& bits, Bitblaster* bb);
-void DefaultUdivBB        (TNode node, Bits& bits, Bitblaster* bb);
-void DefaultUremBB        (TNode node, Bits& bits, Bitblaster* bb);
-void DefaultSdivBB        (TNode node, Bits& bits, Bitblaster* bb);
-void DefaultSremBB        (TNode node, Bits& bits, Bitblaster* bb);
-void DefaultSmodBB        (TNode node, Bits& bits, Bitblaster* bb);
-void DefaultShlBB         (TNode node, Bits& bits, Bitblaster* bb);
-void DefaultLshrBB        (TNode node, Bits& bits, Bitblaster* bb);
-void DefaultAshrBB        (TNode node, Bits& bits, Bitblaster* bb);
-void DefaultExtractBB     (TNode node, Bits& bits, Bitblaster* bb);
-void DefaultRepeatBB      (TNode node, Bits& bits, Bitblaster* bb);
-void DefaultZeroExtendBB  (TNode node, Bits& bits, Bitblaster* bb);
-void DefaultSignExtendBB  (TNode node, Bits& bits, Bitblaster* bb);
-void DefaultRotateRightBB (TNode node, Bits& bits, Bitblaster* bb);
-void DefaultRotateLeftBB  (TNode node, Bits& bits, Bitblaster* bb);
-
-
-}
-}
-}
-
-#endif
diff --git a/src/theory/bv/bitblast_strategies_template.h b/src/theory/bv/bitblast_strategies_template.h
new file mode 100644 (file)
index 0000000..fba744d
--- /dev/null
@@ -0,0 +1,829 @@
+/*********************                                                        */
+/*! \file bitblast_strategies.h
+ ** \verbatim
+ ** Original author: Liana Hadarean
+ ** Major contributors: Liana Hadarean
+ ** Minor contributors (to current version): Clark Barrett, Dejan Jovanovic, Morgan Deters, Tim King
+ ** 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 bitblasting functions for various operators. 
+ **
+ ** Implementation of bitblasting functions for various operators. 
+ **/
+
+#ifndef __CVC4__BITBLAST__STRATEGIES_TEMPLATE_H
+#define __CVC4__BITBLAST__STRATEGIES_TEMPLATE_H
+
+#include "cvc4_private.h"
+#include "expr/node.h"
+#include "theory/bv/bitblast_utils.h"
+#include "theory/bv/theory_bv_utils.h"
+#include <ostream>
+#include <cmath>
+namespace CVC4 {
+
+namespace theory {
+namespace bv {
+
+/** 
+ * Default Atom Bitblasting strategies: 
+ * 
+ * @param node the atom to be bitblasted
+ * @param bb the bitblaster
+ */
+
+template <class T>
+T UndefinedAtomBBStrategy(TNode node, TBitblaster<T>* bb) {
+  Debug("bitvector") << "TheoryBV::Bitblaster Undefined bitblasting strategy for kind: "
+                     << node.getKind() << "\n";
+  Unreachable(); 
+}
+
+
+template <class T>
+T DefaultEqBB(TNode node, TBitblaster<T>* bb) {
+  Debug("bitvector-bb") << "Bitblasting node " << node  << "\n";
+  
+  Assert(node.getKind() == kind::EQUAL);
+  std::vector<T> lhs, rhs; 
+  bb->bbTerm(node[0], lhs);
+  bb->bbTerm(node[1], rhs);
+
+  Assert(lhs.size() == rhs.size());
+
+  std::vector<T> bits_eq;
+  for (unsigned i = 0; i < lhs.size(); i++) {
+    T bit_eq = mkIff(lhs[i], rhs[i]);
+    bits_eq.push_back(bit_eq); 
+  }
+  T bv_eq = mkAnd(bits_eq);
+  return bv_eq; 
+}
+
+template <class T>
+T AdderUltBB(TNode node, TBitblaster<T>* bb) {
+  Debug("bitvector-bb") << "Bitblasting node " << node  << "\n";
+  Assert(node.getKind() == kind::BITVECTOR_ULT);
+  std::vector<T> a, b;
+  bb->bbTerm(node[0], a);
+  bb->bbTerm(node[1], b);
+  Assert(a.size() == b.size());
+  
+  // a < b <=> ~ (add(a, ~b, 1).carry_out)
+  std::vector<T> not_b;
+  negateBits(b, not_b);
+  T carry = mkTrue<T>();
+  
+  for (unsigned i = 0 ; i < a.size(); ++i) {
+    carry = mkOr( mkAnd(a[i], not_b[i]),
+                  mkAnd( mkXor(a[i], not_b[i]),
+                         carry));
+  }
+  return mkNot(carry); 
+}
+
+
+template <class T>
+T DefaultUltBB(TNode node, TBitblaster<T>* bb) {
+  Debug("bitvector-bb") << "Bitblasting node " << node  << "\n";
+  Assert(node.getKind() == kind::BITVECTOR_ULT);
+  std::vector<T> a, b;
+  bb->bbTerm(node[0], a);
+  bb->bbTerm(node[1], b);
+  Assert(a.size() == b.size());
+  
+  // construct bitwise comparison 
+  T res = uLessThanBB(a, b, false);
+  return res; 
+}
+
+template <class T>
+T DefaultUleBB(TNode node, TBitblaster<T>* bb){
+  Debug("bitvector-bb") << "Bitblasting node " << node  << "\n";
+  Assert(node.getKind() == kind::BITVECTOR_ULE);
+  std::vector<T> a, b;
+  
+  bb->bbTerm(node[0], a);
+  bb->bbTerm(node[1], b);
+  Assert(a.size() == b.size());
+  // construct bitwise comparison 
+  T res = uLessThanBB(a, b, true);
+  return res; 
+}
+
+template <class T>
+T DefaultUgtBB(TNode node, TBitblaster<T>* bb){
+  Debug("bitvector-bb") << "Bitblasting node " << node  << "\n";
+  // should be rewritten 
+  Unimplemented(); 
+}
+template <class T>
+T DefaultUgeBB(TNode node, TBitblaster<T>* bb){
+  Debug("bitvector-bb") << "Bitblasting node " << node  << "\n";
+  // should be rewritten 
+  Unimplemented(); 
+}
+
+template <class T>
+T DefaultSltBB(TNode node, TBitblaster<T>* bb){
+  Debug("bitvector-bb") << "Bitblasting node " << node  << "\n";
+
+  std::vector<T> a, b;
+  bb->bbTerm(node[0], a);
+  bb->bbTerm(node[1], b);
+  Assert(a.size() == b.size());
+  
+  T res = sLessThanBB(a, b, false); 
+  return res;
+}
+
+template <class T>
+T DefaultSleBB(TNode node, TBitblaster<T>* bb){
+  Debug("bitvector-bb") << "Bitblasting node " << node  << "\n";
+
+  std::vector<T> a, b;
+  bb->bbTerm(node[0], a);
+  bb->bbTerm(node[1], b);
+  Assert(a.size() == b.size());
+  
+  T res = sLessThanBB(a, b, true); 
+  return res;
+}
+template <class T>
+T DefaultSgtBB(TNode node, TBitblaster<T>* bb){
+  Debug("bitvector-bb") << "Bitblasting node " << node  << "\n";
+  // should be rewritten 
+  Unimplemented(); 
+}
+
+template <class T>
+T DefaultSgeBB(TNode node, TBitblaster<T>* bb){
+  Debug("bitvector-bb") << "Bitblasting node " << node  << "\n";
+  // should be rewritten 
+  Unimplemented(); 
+}
+
+
+/// Term bitblasting strategies 
+
+/** 
+ * Default Term Bitblasting strategies
+ * 
+ * @param node the term to be bitblasted
+ * @param bits [output parameter] bits representing the new term 
+ * @param bb the bitblaster in which the clauses are added
+ */
+template <class T>
+void UndefinedTermBBStrategy(TNode node, std::vector<T>& bits, TBitblaster<T>* bb) {
+  Debug("bitvector") << "theory::bv:: Undefined bitblasting strategy for kind: "
+                     << node.getKind() << "\n";
+  Unreachable(); 
+}
+
+template <class T>
+void DefaultVarBB (TNode node, std::vector<T>& bits, TBitblaster<T>* bb) {
+  Assert(bits.size() == 0);
+  bb->makeVariable(node, bits);
+
+  if(Debug.isOn("bitvector-bb")) {
+    Debug("bitvector-bb") << "theory::bv::DefaultVarBB bitblasting  " << node << "\n";
+    Debug("bitvector-bb") << "                           with bits  " << toString(bits); 
+  }
+}
+
+template <class T>
+void DefaultConstBB (TNode node, std::vector<T>& bits, TBitblaster<T>* bb) {
+  Debug("bitvector-bb") << "theory::bv::DefaultConstBB bitblasting " << node << "\n";
+  Assert(node.getKind() == kind::CONST_BITVECTOR);
+  Assert(bits.size() == 0);
+  
+  for (unsigned i = 0; i < utils::getSize(node); ++i) {
+    Integer bit = node.getConst<BitVector>().extract(i, i).getValue();
+    if(bit == Integer(0)){
+      bits.push_back(mkFalse<T>());
+    } else {
+      Assert (bit == Integer(1));
+      bits.push_back(mkTrue<T>()); 
+    }
+  }
+  if(Debug.isOn("bitvector-bb")) {
+    Debug("bitvector-bb") << "with  bits: " << toString(bits) << "\n"; 
+  }
+}
+
+
+template <class T>
+void DefaultNotBB (TNode node, std::vector<T>& bits, TBitblaster<T>* bb) {
+  Debug("bitvector-bb") << "theory::bv::DefaultNotBB bitblasting " << node << "\n";
+  Assert(node.getKind() == kind::BITVECTOR_NOT);
+  Assert(bits.size() == 0);
+  std::vector<T> bv; 
+  bb->bbTerm(node[0], bv);
+  negateBits(bv, bits);
+}
+
+template <class T>
+void DefaultConcatBB (TNode node, std::vector<T>& bits, TBitblaster<T>* bb) {
+  Debug("bitvector-bb") << "theory::bv::DefaultConcatBB bitblasting " << node << "\n";
+  Assert(bits.size() == 0);
+  
+  Assert (node.getKind() == kind::BITVECTOR_CONCAT);
+  for (int i = node.getNumChildren() -1 ; i >= 0; --i ) {
+    TNode current = node[i];
+    std::vector<T> current_bits; 
+    bb->bbTerm(current, current_bits);
+
+    for(unsigned j = 0; j < utils::getSize(current); ++j) {
+      bits.push_back(current_bits[j]);
+    }
+  }
+  Assert (bits.size() == utils::getSize(node)); 
+  if(Debug.isOn("bitvector-bb")) {
+    Debug("bitvector-bb") << "with  bits: " << toString(bits) << "\n"; 
+  }
+}
+
+template <class T>
+void DefaultAndBB (TNode node, std::vector<T>& bits, TBitblaster<T>* bb) {
+  Debug("bitvector-bb") << "theory::bv::DefaultAndBB bitblasting " << node << "\n";
+  
+  Assert(node.getKind() == kind::BITVECTOR_AND &&
+         bits.size() == 0);
+  
+  for(unsigned j = 0; j < utils::getSize(node); ++j) {
+    std::vector<T> and_j; 
+    for (unsigned i = 0; i < node.getNumChildren(); ++i) {
+      std::vector<T> current;
+      bb->bbTerm(node[i], current);
+      and_j.push_back(current[j]); 
+      Assert(utils::getSize(node) == current.size());
+    }
+    bits.push_back(mkAnd(and_j)); 
+  }
+}
+
+template <class T>
+void DefaultOrBB (TNode node, std::vector<T>& bits, TBitblaster<T>* bb) {
+  Debug("bitvector-bb") << "theory::bv::DefaultOrBB bitblasting " << node << "\n";
+
+  Assert(node.getKind() == kind::BITVECTOR_OR &&
+         bits.size() == 0);
+  
+  for(unsigned j = 0; j < utils::getSize(node); ++j) {
+    std::vector<T> or_j;
+    for (unsigned i = 0; i < node.getNumChildren(); ++i) {
+      std::vector<T> current;
+      bb->bbTerm(node[i], current);
+      or_j.push_back(current[j]); 
+      Assert(utils::getSize(node) == current.size());
+    }
+    bits.push_back(mkOr(or_j)); 
+  }
+}
+
+template <class T>
+void DefaultXorBB (TNode node, std::vector<T>& bits, TBitblaster<T>* bb) {
+  Debug("bitvector-bb") << "theory::bv::DefaultXorBB bitblasting " << node << "\n";
+
+  Assert(node.getKind() == kind::BITVECTOR_XOR &&
+         bits.size() == 0);
+  
+  for(unsigned j = 0; j < utils::getSize(node); ++j) {
+    std::vector<T> first;
+    bb->bbTerm(node[0], first); 
+    T bitj = first[j];
+    
+    for (unsigned i = 1; i < node.getNumChildren(); ++i) {
+      std::vector<T> current;
+      bb->bbTerm(node[i], current);
+      bitj = mkXor(bitj, current[j]);
+      Assert(utils::getSize(node) == current.size());
+    }
+    bits.push_back(bitj); 
+  }
+}
+
+template <class T>
+void DefaultXnorBB (TNode node, std::vector<T>& bits, TBitblaster<T>* bb) {
+  Debug("bitvector-bb") << "theory::bv::DefaultXnorBB bitblasting " << node << "\n";
+
+  Assert(node.getNumChildren() == 2 &&
+         node.getKind() == kind::BITVECTOR_XNOR &&
+         bits.size() == 0);
+  std::vector<T> lhs, rhs;
+  bb->bbTerm(node[0], lhs);
+  bb->bbTerm(node[1], rhs);
+  Assert(lhs.size() == rhs.size()); 
+  
+  for (unsigned i = 0; i < lhs.size(); ++i) {
+    bits.push_back(mkIff(lhs[i], rhs[i])); 
+  }
+}
+
+
+template <class T>
+void DefaultNandBB (TNode node, std::vector<T>& bits, TBitblaster<T>* bb) {
+  Debug("bitvector") << "theory::bv:: Unimplemented kind "
+                     << node.getKind() << "\n";
+  Unimplemented(); 
+}
+template <class T>
+void DefaultNorBB (TNode node, std::vector<T>& bits, TBitblaster<T>* bb) {
+  Debug("bitvector") << "theory::bv:: Unimplemented kind "
+                     << node.getKind() << "\n";
+  Unimplemented(); 
+}
+template <class T>
+void DefaultCompBB (TNode node, std::vector<T>& bits, TBitblaster<T>* bb) {
+  Debug("bitvector") << "theory::bv:: DefaultCompBB bitblasting "<< node << "\n";
+
+  Assert(utils::getSize(node) == 1 && bits.size() == 0 && node.getKind() == kind::BITVECTOR_COMP);
+  std::vector<T> a, b;
+  bb->bbTerm(node[0], a);
+  bb->bbTerm(node[1], b);
+
+  std::vector<T> bit_eqs;
+  for (unsigned i = 0; i < a.size(); ++i) {
+    T eq = mkIff(a[i], b[i]);
+    bit_eqs.push_back(eq); 
+  }
+  T a_eq_b = mkAnd(bit_eqs);
+  bits.push_back(a_eq_b);   
+}
+
+template <class T>
+void DefaultMultBB (TNode node, std::vector<T>& res, TBitblaster<T>* bb) {
+  Debug("bitvector") << "theory::bv:: DefaultMultBB bitblasting "<< node << "\n";
+  Assert(res.size() == 0 &&
+         node.getKind() == kind::BITVECTOR_MULT);
+
+  // if (node.getNumChildren() == 2) {
+  //   std::vector<T> a;
+  //   std::vector<T> b;
+  //   bb->bbTerm(node[0], a);
+  //   bb->bbTerm(node[1], b);
+  //   unsigned bw = utils::getSize(node);
+  //   unsigned thresh = bw % 2 ? bw/2 : bw/2 - 1;
+  //   bool no_overflow = true; 
+  //   for (unsigned i = thresh; i < bw; ++i) {
+  //     if (a[i] != mkFalse<T> || b[i] != mkFalse<T> ) {
+  //       no_overflow = false; 
+  //     }
+  //   }
+  //   if (no_overflow) {
+  //     shiftAddMultiplier(); 
+  //     return; 
+  //   }
+    
+  // }
+  
+  std::vector<T> newres; 
+  bb->bbTerm(node[0], res); 
+  for(unsigned i = 1; i < node.getNumChildren(); ++i) {
+    std::vector<T> current;
+    bb->bbTerm(node[i], current);
+    newres.clear(); 
+    // constructs a simple shift and add multiplier building the result
+    // in res
+    shiftAddMultiplier(res, current, newres);
+    res = newres;
+  }
+  if(Debug.isOn("bitvector-bb")) {
+    Debug("bitvector-bb") << "with bits: " << toString(res)  << "\n";
+  }
+}
+
+template <class T>
+void DefaultPlusBB (TNode node, std::vector<T>& res, TBitblaster<T>* bb) {
+  Debug("bitvector-bb") << "theory::bv::DefaultPlusBB bitblasting " << node << "\n";
+  Assert(node.getKind() == kind::BITVECTOR_PLUS &&
+         res.size() == 0);
+
+  bb->bbTerm(node[0], res);
+
+  std::vector<T> newres;
+
+  for(unsigned i = 1; i < node.getNumChildren(); ++i) {
+    std::vector<T> current;
+    bb->bbTerm(node[i], current);
+    newres.clear(); 
+    rippleCarryAdder(res, current, newres, mkFalse<T>());
+    res = newres; 
+  }
+  
+  Assert(res.size() == utils::getSize(node));
+}
+
+
+template <class T>
+void DefaultSubBB (TNode node, std::vector<T>& bits, TBitblaster<T>* bb) {
+  Debug("bitvector-bb") << "theory::bv::DefaultSubBB bitblasting " << node << "\n";
+  Assert(node.getKind() == kind::BITVECTOR_SUB &&
+         node.getNumChildren() == 2 &&
+         bits.size() == 0);
+    
+  std::vector<T> a, b;
+  bb->bbTerm(node[0], a);
+  bb->bbTerm(node[1], b); 
+  Assert(a.size() == b.size() && utils::getSize(node) == a.size());
+
+  // bvsub a b = adder(a, ~b, 1)
+  std::vector<T> not_b;
+  negateBits(b, not_b);
+  rippleCarryAdder(a, not_b, bits, mkTrue<T>());
+}
+
+template <class T>
+void DefaultNegBB (TNode node, std::vector<T>& bits, TBitblaster<T>* bb) {
+  Debug("bitvector-bb") << "theory::bv::DefaultNegBB bitblasting " << node << "\n";
+  Assert(node.getKind() == kind::BITVECTOR_NEG);
+  
+  std::vector<T> a;
+  bb->bbTerm(node[0], a);
+  Assert(utils::getSize(node) == a.size());
+
+  // -a = add(~a, 0, 1).
+  std::vector<T> not_a;
+  negateBits(a, not_a);
+  std::vector<T> zero;
+  makeZero(zero, utils::getSize(node)); 
+  
+  rippleCarryAdder(not_a, zero, bits, mkTrue<T>()); 
+}
+
+template <class T>
+void uDivModRec(const std::vector<T>& a, const std::vector<T>& b, std::vector<T>& q, std::vector<T>& r, unsigned rec_width) {
+  Assert( q.size() == 0 && r.size() == 0);
+
+  if(rec_width == 0 || isZero(a)) {
+    makeZero(q, a.size());
+    makeZero(r, a.size());
+    return;
+  } 
+  
+  std::vector<T> q1, r1;
+  std::vector<T> a1 = a;
+  rshift(a1, 1); 
+
+  uDivModRec(a1, b, q1, r1, rec_width - 1);
+  // shift the quotient and remainder (i.e. multiply by two) and add 1 to remainder if a is odd
+  lshift(q1, 1);
+  lshift(r1, 1);
+
+  
+  T is_odd = mkIff(a[0], mkTrue<T>());
+  T one_if_odd = mkIte(is_odd, mkTrue<T>(), mkFalse<T>()); 
+
+  std::vector<T> zero;
+  makeZero(zero, b.size());
+  
+  std::vector<T> r1_shift_add;
+  // account for a being odd
+  rippleCarryAdder(r1, zero, r1_shift_add, one_if_odd); 
+  // now check if the remainder is greater than b
+  std::vector<T> not_b;
+  negateBits(b, not_b);
+  std::vector<T> r_minus_b;
+  T co1;
+  // use adder because we need r_minus_b anyway
+  co1 = rippleCarryAdder(r1_shift_add, not_b, r_minus_b, mkTrue<T>()); 
+  // sign is true if r1 < b
+  T sign = mkNot(co1); 
+  
+  q1[0] = mkIte(sign, q1[0], mkTrue<T>());
+
+  // would be nice to have a high level ITE instead of bitwise
+  for(unsigned i = 0; i < a.size(); ++i) {
+    r1_shift_add[i] = mkIte(sign, r1_shift_add[i], r_minus_b[i]); 
+  }
+
+  // check if a < b
+
+  std::vector<T> a_minus_b;
+  T co2 = rippleCarryAdder(a, not_b, a_minus_b, mkTrue<T>());
+  // Node a_lt_b = a_minus_b.back();
+  T a_lt_b = mkNot(co2); 
+  
+  for(unsigned i = 0; i < a.size(); ++i) {
+    T qval = mkIte(a_lt_b, mkFalse<T>(), q1[i]);
+    T rval = mkIte(a_lt_b, a[i], r1_shift_add[i]);
+    q.push_back(qval);
+    r.push_back(rval); 
+  }
+
+}
+
+template <class T>
+void DefaultUdivBB (TNode node, std::vector<T>& q, TBitblaster<T>* bb) {
+  Debug("bitvector-bb") << "theory::bv::DefaultUdivBB bitblasting " << node << "\n";
+  Assert(node.getKind() == kind::BITVECTOR_UDIV_TOTAL &&  q.size() == 0);
+
+  std::vector<T> a, b;
+  bb->bbTerm(node[0], a);
+  bb->bbTerm(node[1], b);
+
+  std::vector<T> r;
+  uDivModRec(a, b, q, r, utils::getSize(node)); 
+  // adding a special case for division by 0
+  std::vector<T> iszero; 
+  for (unsigned i = 0; i < b.size(); ++i) {
+    iszero.push_back(mkIff(b[i], mkFalse<T>())); 
+  }
+  T b_is_0 = mkAnd(iszero); 
+  
+  for (unsigned i = 0; i < q.size(); ++i) {
+    q[i] = mkIte(b_is_0, mkTrue<T>(), q[i]);
+    r[i] = mkIte(b_is_0, mkTrue<T>(), r[i]);
+  }
+
+  // cache the remainder in case we need it later
+  Node remainder = utils::mkNode(kind::BITVECTOR_UREM_TOTAL, node[0], node[1]);
+  bb->storeBBTerm(remainder, r);
+}
+
+template <class T>
+void DefaultUremBB (TNode node, std::vector<T>& rem, TBitblaster<T>* bb) {
+  Debug("bitvector-bb") << "theory::bv::DefaultUremBB bitblasting " << node << "\n";
+  Assert(node.getKind() == kind::BITVECTOR_UREM_TOTAL &&  rem.size() == 0);
+
+  std::vector<T> a, b;
+  bb->bbTerm(node[0], a);
+  bb->bbTerm(node[1], b);
+
+  std::vector<T> q;
+  uDivModRec(a, b, q, rem, utils::getSize(node)); 
+  // adding a special case for division by 0
+  std::vector<T> iszero; 
+  for (unsigned i = 0; i < b.size(); ++i) {
+    iszero.push_back(mkIff(b[i], mkFalse<T>())); 
+  }
+  T b_is_0 = mkAnd(iszero); 
+  
+  for (unsigned i = 0; i < q.size(); ++i) {
+    q[i] = mkIte(b_is_0, a[i], q[i]);
+    rem[i] = mkIte(b_is_0, a[i], rem[i]);
+  }
+
+  // cache the quotient in case we need it later
+  Node quotient = utils::mkNode(kind::BITVECTOR_UDIV_TOTAL, node[0], node[1]);
+  bb->storeBBTerm(quotient, q);
+}
+
+
+template <class T>
+void DefaultSdivBB (TNode node, std::vector<T>& bits, TBitblaster<T>* bb) {
+  Debug("bitvector") << "theory::bv:: Unimplemented kind "
+                     << node.getKind() << "\n";
+  Unimplemented(); 
+}
+template <class T>
+void DefaultSremBB (TNode node, std::vector<T>& bits, TBitblaster<T>* bb) {
+  Debug("bitvector") << "theory::bv:: Unimplemented kind "
+                     << node.getKind() << "\n";
+  Unimplemented(); 
+}
+template <class T>
+void DefaultSmodBB (TNode node, std::vector<T>& bits, TBitblaster<T>* bb) {
+  Debug("bitvector") << "theory::bv:: Unimplemented kind "
+                     << node.getKind() << "\n";
+  Unimplemented(); 
+}
+
+template <class T>
+void DefaultShlBB (TNode node, std::vector<T>& res, TBitblaster<T>* bb) {
+  Debug("bitvector-bb") << "theory::bv::DefaultShlBB bitblasting " << node  << "\n";
+  Assert (node.getKind() == kind::BITVECTOR_SHL &&
+          res.size() == 0);
+  std::vector<T> a, b;
+  bb->bbTerm(node[0], a);
+  bb->bbTerm(node[1], b);
+
+  // check for b < log2(n)
+  unsigned size = utils::getSize(node);
+  unsigned log2_size = std::ceil(log2((double)size));
+  Node a_size = utils::mkConst(BitVector(size, size)); 
+  Node b_ult_a_size_node = utils::mkNode(kind::BITVECTOR_ULT, node[1], a_size);
+  // ensure that the inequality is bit-blasted
+  bb->bbAtom(b_ult_a_size_node); 
+  T b_ult_a_size = bb->getBBAtom(b_ult_a_size_node);
+  std::vector<T> prev_res;
+  res = a; 
+  // we only need to look at the bits bellow log2_a_size
+  for(unsigned s = 0; s < log2_size; ++s) {
+    // barrel shift stage: at each stage you can either shift by 2^s bits
+    // or leave the previous stage untouched
+    prev_res = res; 
+    unsigned threshold = pow(2, s); 
+    for(unsigned i = 0; i < a.size(); ++i) {
+      if (i < threshold) {
+        // if b[s] is true then we must have shifted by at least 2^b bits so
+        // all bits bellow 2^s will be 0, otherwise just use previous shift value
+        res[i] = mkIte(b[s], mkFalse<T>(), prev_res[i]);
+      } else {
+        // if b[s]= 0, use previous value, otherwise shift by threshold  bits
+        Assert(i >= threshold); 
+        res[i] = mkIte(b[s], prev_res[i-threshold], prev_res[i]); 
+      }
+    }
+  }
+  prev_res = res;
+  for (unsigned i = 0; i < b.size(); ++i) {
+    // this is fine  because b_ult_a_size has been bit-blasted
+    res[i] = mkIte(b_ult_a_size, prev_res[i], mkFalse<T>()); 
+  }
+  
+  if(Debug.isOn("bitvector-bb")) {
+    Debug("bitvector-bb") << "with bits: " << toString(res)  << "\n";
+  }
+}
+
+template <class T>
+void DefaultLshrBB (TNode node, std::vector<T>& res, TBitblaster<T>* bb) {
+  Debug("bitvector-bb") << "theory::bv::DefaultLshrBB bitblasting " << node  << "\n";
+  Assert (node.getKind() == kind::BITVECTOR_LSHR &&
+          res.size() == 0);
+  std::vector<T> a, b;
+  bb->bbTerm(node[0], a);
+  bb->bbTerm(node[1], b);
+
+  // check for b < log2(n)
+  unsigned size = utils::getSize(node);
+  unsigned log2_size = std::ceil(log2((double)size));
+  Node a_size = utils::mkConst(BitVector(size, size)); 
+  Node b_ult_a_size_node = utils::mkNode(kind::BITVECTOR_ULT, node[1], a_size);
+  // ensure that the inequality is bit-blasted
+  bb->bbAtom(b_ult_a_size_node); 
+  T b_ult_a_size = bb->getBBAtom(b_ult_a_size_node); 
+  res = a;
+  std::vector<T> prev_res;
+  
+  for(unsigned s = 0; s < log2_size; ++s) {
+    // barrel shift stage: at each stage you can either shift by 2^s bits
+    // or leave the previous stage untouched
+    prev_res = res; 
+    int threshold = pow(2, s); 
+    for(unsigned i = 0; i < a.size(); ++i) {
+      if (i + threshold >= a.size()) {
+        // if b[s] is true then we must have shifted by at least 2^b bits so
+        // all bits above 2^s will be 0, otherwise just use previous shift value
+        res[i] = mkIte(b[s], mkFalse<T>(), prev_res[i]);
+      } else {
+        // if b[s]= 0, use previous value, otherwise shift by threshold  bits
+        Assert (i+ threshold < a.size()); 
+        res[i] = mkIte(mkNot(b[s]), prev_res[i], prev_res[i+threshold]);
+      }
+    }
+  }
+  
+  prev_res = res;
+  for (unsigned i = 0; i < b.size(); ++i) {
+    // this is fine  because b_ult_a_size has been bit-blasted
+    res[i] = mkIte(b_ult_a_size, prev_res[i], mkFalse<T>()); 
+  }
+
+  if(Debug.isOn("bitvector-bb")) {
+    Debug("bitvector-bb") << "with bits: " << toString(res)  << "\n";
+  }
+}
+
+template <class T>
+void DefaultAshrBB (TNode node, std::vector<T>& res, TBitblaster<T>* bb) {
+
+  Debug("bitvector-bb") << "theory::bv::DefaultAshrBB bitblasting " << node  << "\n";
+  Assert (node.getKind() == kind::BITVECTOR_ASHR &&
+          res.size() == 0);
+  std::vector<T> a, b;
+  bb->bbTerm(node[0], a);
+  bb->bbTerm(node[1], b);
+
+  //   check for b < n
+  unsigned size = utils::getSize(node);
+  unsigned log2_size = std::ceil(log2((double)size));
+  Node a_size = utils::mkConst(BitVector(size, size)); 
+  Node b_ult_a_size_node = utils::mkNode(kind::BITVECTOR_ULT, node[1], a_size);
+  // ensure that the inequality is bit-blasted
+  bb->bbAtom(b_ult_a_size_node); 
+  T b_ult_a_size = bb->getBBAtom(b_ult_a_size_node);
+  
+  res = a;
+  T sign_bit = a.back();
+  std::vector<T> prev_res;
+
+  for(unsigned s = 0; s < log2_size; ++s) {
+    // barrel shift stage: at each stage you can either shift by 2^s bits
+    // or leave the previous stage untouched
+    prev_res = res; 
+    int threshold = pow(2, s); 
+    for(unsigned i = 0; i < a.size(); ++i) {
+      if (i + threshold >= a.size()) {
+        // if b[s] is true then we must have shifted by at least 2^b bits so
+        // all bits above 2^s will be the sign bit, otherwise just use previous shift value
+        res[i] = mkIte(b[s], sign_bit, prev_res[i]);
+      } else {
+        // if b[s]= 0, use previous value, otherwise shift by threshold  bits
+        Assert (i+ threshold < a.size()); 
+        res[i] = mkIte(mkNot(b[s]), prev_res[i], prev_res[i+threshold]);
+      }
+    }
+  }
+
+  prev_res = res;
+  for (unsigned i = 0; i < b.size(); ++i) {
+    // this is fine  because b_ult_a_size has been bit-blasted
+    res[i] = mkIte(b_ult_a_size, prev_res[i], sign_bit); 
+  }
+
+  if(Debug.isOn("bitvector-bb")) {
+    Debug("bitvector-bb") << "with bits: " << toString(res)  << "\n";
+  }
+}
+
+template <class T>
+void DefaultExtractBB (TNode node, std::vector<T>& bits, TBitblaster<T>* bb) {
+  Assert (node.getKind() == kind::BITVECTOR_EXTRACT);
+  Assert(bits.size() == 0);
+  
+  std::vector<T> base_bits;
+  bb->bbTerm(node[0], base_bits);
+  unsigned high = utils::getExtractHigh(node);
+  unsigned low  = utils::getExtractLow(node);
+
+  for (unsigned i = low; i <= high; ++i) {
+    bits.push_back(base_bits[i]); 
+  }
+  Assert (bits.size() == high - low + 1);   
+
+  if(Debug.isOn("bitvector-bb")) {
+    Debug("bitvector-bb") << "theory::bv::DefaultExtractBB bitblasting " << node << "\n";
+    Debug("bitvector-bb") << "                               with bits " << toString(bits); 
+  }
+}
+
+
+template <class T>
+void DefaultRepeatBB (TNode node, std::vector<T>& bits, TBitblaster<T>* bb) {
+  Debug("bitvector") << "theory::bv:: Unimplemented kind "
+                     << node.getKind() << "\n";
+  // this should be rewritten 
+  Unimplemented(); 
+}
+
+template <class T>
+void DefaultZeroExtendBB (TNode node, std::vector<T>& res_bits, TBitblaster<T>* bb) {
+
+  Debug("bitvector-bb") << "theory::bv::DefaultZeroExtendBB bitblasting " << node  << "\n";
+  // this should be rewritten 
+  Unimplemented();
+  
+}
+
+template <class T>
+void DefaultSignExtendBB (TNode node, std::vector<T>& res_bits, TBitblaster<T>* bb) {
+  Debug("bitvector-bb") << "theory::bv::DefaultSignExtendBB bitblasting " << node  << "\n";
+
+  Assert (node.getKind() == kind::BITVECTOR_SIGN_EXTEND &&
+          res_bits.size() == 0);
+
+  std::vector<T> bits;
+  bb->bbTerm(node[0], bits);
+  
+  T sign_bit = bits.back(); 
+  unsigned amount = node.getOperator().getConst<BitVectorSignExtend>().signExtendAmount; 
+
+  for (unsigned i = 0; i < bits.size(); ++i ) {
+    res_bits.push_back(bits[i]); 
+  }
+         
+  for (unsigned i = 0 ; i < amount ; ++i ) {
+    res_bits.push_back(sign_bit); 
+  }
+         
+  Assert (res_bits.size() == amount + bits.size()); 
+}
+
+template <class T>
+void DefaultRotateRightBB (TNode node, std::vector<T>& res, TBitblaster<T>* bb) {
+  Debug("bitvector") << "theory::bv:: Unimplemented kind "
+                     << node.getKind() << "\n";
+
+  Unimplemented(); 
+}
+
+template <class T>
+void DefaultRotateLeftBB (TNode node, std::vector<T>& bits, TBitblaster<T>* bb) {
+  Debug("bitvector") << "theory::bv:: Unimplemented kind "
+                     << node.getKind() << "\n";
+  Unimplemented(); 
+}
+
+
+}
+}
+}
+
+#endif
diff --git a/src/theory/bv/bitblast_utils.h b/src/theory/bv/bitblast_utils.h
new file mode 100644 (file)
index 0000000..91cc2d6
--- /dev/null
@@ -0,0 +1,283 @@
+/*********************                                                        */
+/*! \file bitblast_utils.h
+ ** \verbatim
+ ** Original author: Liana Hadarean
+ ** Major contributors: none
+ ** 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 Various utility functions for bit-blasting.
+ **
+ ** Various utility functions for bit-blasting.
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef __CVC4__BITBLAST__UTILS_H
+#define __CVC4__BITBLAST__UTILS_H
+
+
+#include <ostream>
+#include "expr/node.h"
+
+#ifdef CVC4_USE_ABC
+#include "base/main/main.h"
+#include "base/abc/abc.h"
+
+extern "C" {
+#include "sat/cnf/cnf.h"
+}
+#endif
+
+namespace CVC4 {
+
+namespace theory {
+namespace bv {
+
+template <class T> class TBitblaster;
+
+template <class T> 
+std::string toString (const std::vector<T>& bits);
+
+template <> inline
+std::string toString<Node> (const std::vector<Node>& bits) {
+  std::ostringstream os;
+  for (int i = bits.size() - 1; i >= 0; --i) {
+    TNode bit = bits[i];
+    if (bit.getKind() == kind::CONST_BOOLEAN) {
+      os << (bit.getConst<bool>() ? "1" : "0");
+    } else {
+      os << bit<< " ";
+    }
+  }
+  os <<"\n";
+  return os.str();
+} 
+
+template <class T> T mkTrue(); 
+template <class T> T mkFalse(); 
+template <class T> T mkNot(T a);
+template <class T> T mkOr(T a, T b);
+template <class T> T mkOr(const std::vector<T>& a);
+template <class T> T mkAnd(T a, T b);
+template <class T> T mkAnd(const std::vector<T>& a);
+template <class T> T mkXor(T a, T b);
+template <class T> T mkIff(T a, T b);
+template <class T> T mkIte(T cond, T a, T b);
+
+
+template <> inline
+Node mkTrue<Node>() {
+  return NodeManager::currentNM()->mkConst<bool>(true);
+}
+
+template <> inline
+Node mkFalse<Node>() {
+  return NodeManager::currentNM()->mkConst<bool>(false);
+}
+
+template <> inline
+Node mkNot<Node>(Node a) {
+  return NodeManager::currentNM()->mkNode(kind::NOT, a);
+}
+
+template <> inline
+Node mkOr<Node>(Node a, Node b) {
+  return NodeManager::currentNM()->mkNode(kind::OR, a, b);
+}
+
+template <> inline
+Node mkOr<Node>(const std::vector<Node>& children) {
+  Assert (children.size());
+  if (children.size() == 1)
+    return children[0]; 
+  return NodeManager::currentNM()->mkNode(kind::OR, children); 
+}
+
+
+template <> inline
+Node mkAnd<Node>(Node a, Node b) {
+  return NodeManager::currentNM()->mkNode(kind::AND, a, b);
+}
+
+template <> inline
+Node mkAnd<Node>(const std::vector<Node>& children) {
+  Assert (children.size());
+  if (children.size() == 1)
+    return children[0]; 
+  return NodeManager::currentNM()->mkNode(kind::AND, children); 
+}
+
+
+template <> inline
+Node mkXor<Node>(Node a, Node b) {
+  return NodeManager::currentNM()->mkNode(kind::XOR, a, b);
+}
+
+template <> inline
+Node mkIff<Node>(Node a, Node b) {
+  return NodeManager::currentNM()->mkNode(kind::IFF, a, b);
+}
+
+template <> inline
+Node mkIte<Node>(Node cond, Node a, Node b) {
+  return NodeManager::currentNM()->mkNode(kind::ITE, cond, a, b);
+}
+
+/*
+ Various helper functions that get called by the bitblasting procedures
+ */
+
+template <class T>
+void inline extractBits(const std::vector<T>& b, std::vector<T>& dest, unsigned lo, unsigned hi) {
+  Assert ( lo < b.size() && hi < b.size() && lo <= hi);
+  for (unsigned i = lo; i <= hi; ++i) {
+    dest.push_back(b[i]); 
+  }
+}
+
+template <class T>
+void inline negateBits(const std::vector<T>& bits, std::vector<T>& negated_bits) {
+  for(unsigned i = 0; i < bits.size(); ++i) {
+    negated_bits.push_back(mkNot(bits[i])); 
+  }
+}
+
+template <class T>
+bool inline isZero(const std::vector<T>& bits) {
+  for(unsigned i = 0; i < bits.size(); ++i) {
+    if(bits[i] != mkFalse<T>()) {
+      return false; 
+    }
+  }
+  return true; 
+}
+
+template <class T>
+void inline rshift(std::vector<T>& bits, unsigned amount) {
+  for (unsigned i = 0; i < bits.size() - amount; ++i) {
+    bits[i] = bits[i+amount]; 
+  }
+  for(unsigned i = bits.size() - amount; i < bits.size(); ++i) {
+    bits[i] = mkFalse<T>(); 
+  }
+}
+
+template <class T>
+void inline lshift(std::vector<T>& bits, unsigned amount) {
+  for (int i = (int)bits.size() - 1; i >= (int)amount ; --i) {
+    bits[i] = bits[i-amount]; 
+  }
+  for(unsigned i = 0; i < amount; ++i) {
+    bits[i] = mkFalse<T>(); 
+  }
+}
+
+template <class T>
+void inline makeZero(std::vector<T>& bits, unsigned width) {
+  Assert(bits.size() == 0); 
+  for(unsigned i = 0; i < width; ++i) {
+    bits.push_back(mkFalse<T>()); 
+  }
+}
+
+
+/** 
+ * Constructs a simple ripple carry adder
+ * 
+ * @param a first term to be added
+ * @param b second term to be added
+ * @param res the result
+ * @param carry the carry-in bit 
+ * 
+ * @return the carry-out
+ */
+template <class T>
+T inline rippleCarryAdder(const std::vector<T>&a, const std::vector<T>& b, std::vector<T>& res, T carry) {
+  Assert(a.size() == b.size() && res.size() == 0);
+  
+  for (unsigned i = 0 ; i < a.size(); ++i) {
+    T sum = mkXor(mkXor(a[i], b[i]), carry);
+    carry = mkOr( mkAnd(a[i], b[i]),
+                  mkAnd( mkXor(a[i], b[i]),
+                         carry));
+    res.push_back(sum); 
+  }
+
+  return carry;
+}
+
+template <class T>
+inline void shiftAddMultiplier(const std::vector<T>&a, const std::vector<T>&b, std::vector<T>& res) {
+  
+  for (unsigned i = 0; i < a.size(); ++i) {
+    res.push_back(mkAnd(b[0], a[i])); 
+  }
+  
+  for(unsigned k = 1; k < res.size(); ++k) {
+  T carry_in = mkFalse<T>();
+  T carry_out;
+    for(unsigned j = 0; j < res.size() -k; ++j) {
+      T aj = mkAnd(a[j], b[k]);
+      carry_out = mkOr(mkAnd(res[j+k], aj),
+                       mkAnd( mkXor(res[j+k], aj), carry_in));
+      res[j+k] = mkXor(mkXor(res[j+k], aj), carry_in);
+      carry_in = carry_out; 
+    }
+  }
+}
+
+template <class T>
+T inline uLessThanBB(const std::vector<T>&a, const std::vector<T>& b, bool orEqual) {
+  Assert (a.size() && b.size());
+  
+  T res = mkAnd(mkNot(a[0]), b[0]);
+  
+  if(orEqual) {
+    res = mkOr(res, mkIff(a[0], b[0])); 
+  }
+  
+  for (unsigned i = 1; i < a.size(); ++i) {
+    // a < b iff ( a[i] <-> b[i] AND a[i-1:0] < b[i-1:0]) OR (~a[i] AND b[i]) 
+    res = mkOr(mkAnd(mkIff(a[i], b[i]), res),
+               mkAnd(mkNot(a[i]), b[i])); 
+  }
+  return res;
+}
+
+template <class T>
+T inline sLessThanBB(const std::vector<T>&a, const std::vector<T>& b, bool orEqual) {
+  Assert (a.size() && b.size());
+  if (a.size() == 1) {
+    if(orEqual) {
+      return  mkOr(mkIff(a[0], b[0]),
+                   mkAnd(a[0], mkNot(b[0]))); 
+    }
+
+    return mkAnd(a[0], mkNot(b[0]));
+  }
+  unsigned n = a.size() - 1; 
+  std::vector<T> a1, b1;
+  extractBits(a, a1, 0, n-1);
+  extractBits(b, b1, 0, n-1);
+  
+  // unsigned comparison of the first n-1 bits
+  T ures = uLessThanBB(a1, b1, orEqual);
+  T res = mkOr(// a b have the same sign
+               mkAnd(mkIff(a[n], b[n]),
+                     ures),
+               // a is negative and b positive
+               mkAnd(a[n],
+                     mkNot(b[n])));
+  return res;
+}
+
+
+}
+}
+}
+
+#endif
diff --git a/src/theory/bv/bitblaster.cpp b/src/theory/bv/bitblaster.cpp
deleted file mode 100644 (file)
index 552f3b4..0000000
+++ /dev/null
@@ -1,505 +0,0 @@
-/*********************                                                        */
-/*! \file bitblaster.cpp
- ** \verbatim
- ** Original author: Liana Hadarean
- ** Major contributors: Dejan Jovanovic, Andrew Reynolds
- ** Minor contributors (to current version): Clark Barrett, Kshitij Bansal, Morgan Deters
- ** 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 [[ Add one-line brief description here ]]
- **
- ** [[ Add lengthier description here ]]
- **
- **/
-
-#include "bitblaster.h"
-#include "theory_bv_utils.h"
-#include "theory/rewriter.h"
-#include "prop/cnf_stream.h"
-#include "prop/sat_solver.h"
-#include "prop/sat_solver_factory.h"
-#include "theory/bv/theory_bv_rewrite_rules_simplification.h"
-#include "theory/bv/theory_bv.h"
-#include "theory/bv/options.h"
-#include "theory/theory_model.h"
-
-using namespace std;
-
-using namespace CVC4::theory::bv::utils;
-using namespace CVC4::context;
-using namespace CVC4::prop;
-
-namespace CVC4 {
-namespace theory {
-namespace bv{
-
-std::string toString(Bits&  bits) {
-  ostringstream os;
-  for (int i = bits.size() - 1; i >= 0; --i) {
-    TNode bit = bits[i];
-    if (bit.getKind() == kind::CONST_BOOLEAN) {
-      os << (bit.getConst<bool>() ? "1" : "0");
-    } else {
-      os << bit<< " ";
-    }
-  }
-  os <<"\n";
-
-  return os.str();
-}
-/////// Bitblaster
-
-Bitblaster::Bitblaster(context::Context* c, bv::TheoryBV* bv) :
-    d_bv(bv),
-    d_bvOutput(bv->d_out),
-    d_termCache(),
-    d_bitblastedAtoms(),
-    d_assertedAtoms(c),
-    d_statistics()
-  {
-    d_satSolver = prop::SatSolverFactory::createMinisat(c);
-    d_nullRegistrar = new NullRegistrar();
-    d_nullContext = new Context();
-    d_cnfStream = new TseitinCnfStream(d_satSolver, d_nullRegistrar, d_nullContext);
-
-    d_notify = new MinisatNotify(d_cnfStream, bv);
-    d_satSolver->setNotify(d_notify);
-    // initializing the bit-blasting strategies
-    initAtomBBStrategies();
-    initTermBBStrategies();
-  }
-
-Bitblaster::~Bitblaster() {
-  delete d_cnfStream;
-  delete d_nullContext;
-  delete d_nullRegistrar;
-  delete d_satSolver;
-  delete d_notify;
-}
-
-
-/**
- * Bitblasts the atom, assigns it a marker literal, adding it to the SAT solver
- * NOTE: duplicate clauses are not detected because of marker literal
- * @param node the atom to be bitblasted
- *
- */
-void Bitblaster::bbAtom(TNode node) {
-  node = node.getKind() == kind::NOT?  node[0] : node;
-
-  if (hasBBAtom(node)) {
-    return;
-  }
-
-  // make sure it is marked as an atom
-  addAtom(node);
-
-  Debug("bitvector-bitblast") << "Bitblasting node " << node <<"\n";
-  ++d_statistics.d_numAtoms;
-  // the bitblasted definition of the atom
-  Node normalized = Rewriter::rewrite(node);
-  Node atom_bb = normalized.getKind() != kind::CONST_BOOLEAN ?
-      Rewriter::rewrite(d_atomBBStrategies[normalized.getKind()](normalized, this)) :
-      normalized;
-  // asserting that the atom is true iff the definition holds
-  Node atom_definition = mkNode(kind::IFF, node, atom_bb);
-
-  if (!options::bitvectorEagerBitblast()) {
-    d_cnfStream->convertAndAssert(atom_definition, false, false);
-    d_bitblastedAtoms.insert(node);
-  } else {
-    d_bvOutput->lemma(atom_definition, false);
-    d_bitblastedAtoms.insert(node);
-  }
-}
-
-uint64_t Bitblaster::computeAtomWeight(TNode node) {
-  node = node.getKind() == kind::NOT?  node[0] : node;
-
-  Node atom_bb = Rewriter::rewrite(d_atomBBStrategies[node.getKind()](node, this));
-  uint64_t size = utils::numNodes(atom_bb);
-  return size;
-}
-
-void Bitblaster::bbTerm(TNode node, Bits& bits) {
-
-  if (hasBBTerm(node)) {
-    getBBTerm(node, bits);
-    return;
-  }
-
-  Debug("bitvector-bitblast") << "Bitblasting node " << node <<"\n";
-  ++d_statistics.d_numTerms;
-
-  d_termBBStrategies[node.getKind()] (node, bits,this);
-
-  Assert (bits.size() == utils::getSize(node));
-
-  cacheTermDef(node, bits);
-}
-
-Node Bitblaster::bbOptimize(TNode node) {
-  std::vector<Node> children;
-
-   if (node.getKind() == kind::BITVECTOR_PLUS) {
-    if (RewriteRule<BBPlusNeg>::applies(node)) {
-      Node res = RewriteRule<BBPlusNeg>::run<false>(node);
-      return res;
-    }
-    //  if (RewriteRule<BBFactorOut>::applies(node)) {
-    //   Node res = RewriteRule<BBFactorOut>::run<false>(node);
-    //   return res;
-    // }
-
-  } else if (node.getKind() == kind::BITVECTOR_MULT) {
-    if (RewriteRule<MultPow2>::applies(node)) {
-      Node res = RewriteRule<MultPow2>::run<false>(node);
-      return res;
-    }
-  }
-
-  return node;
-}
-
-/// Public methods
-
-void Bitblaster::addAtom(TNode atom) {
-  if (!options::bitvectorEagerBitblast()) {
-    d_cnfStream->ensureLiteral(atom);
-    SatLiteral lit = d_cnfStream->getLiteral(atom);
-    d_satSolver->addMarkerLiteral(lit);
-  }
-}
-
-void Bitblaster::explain(TNode atom, std::vector<TNode>& explanation) {
-  std::vector<SatLiteral> literal_explanation;
-  d_satSolver->explain(d_cnfStream->getLiteral(atom), literal_explanation);
-  for (unsigned i = 0; i < literal_explanation.size(); ++i) {
-    explanation.push_back(d_cnfStream->getNode(literal_explanation[i]));
-  }
-}
-
-
-/*
- * Asserts the clauses corresponding to the atom to the Sat Solver
- * by turning on the marker literal (i.e. setting it to false)
- * @param node the atom to be asserted
- *
- */
-
-bool Bitblaster::propagate() {
-  return d_satSolver->propagate() == prop::SAT_VALUE_TRUE;
-}
-
-bool Bitblaster::assertToSat(TNode lit, bool propagate) {
-  // strip the not
-  TNode atom;
-  if (lit.getKind() == kind::NOT) {
-    atom = lit[0];
-  } else {
-    atom = lit;
-  }
-
-  Assert (hasBBAtom(atom));
-
-  SatLiteral markerLit = d_cnfStream->getLiteral(atom);
-
-  if(lit.getKind() == kind::NOT) {
-    markerLit = ~markerLit;
-  }
-
-  Debug("bitvector-bb") << "TheoryBV::Bitblaster::assertToSat asserting node: " << atom <<"\n";
-  Debug("bitvector-bb") << "TheoryBV::Bitblaster::assertToSat with literal:   " << markerLit << "\n";
-
-  SatValue ret = d_satSolver->assertAssumption(markerLit, propagate);
-
-  d_assertedAtoms.push_back(markerLit);
-
-  Assert(ret != prop::SAT_VALUE_UNKNOWN);
-  return ret == prop::SAT_VALUE_TRUE;
-}
-
-/**
- * Calls the solve method for the Sat Solver.
- * passing it the marker literals to be asserted
- *
- * @return true for sat, and false for unsat
- */
-
-bool Bitblaster::solve(bool quick_solve) {
-  if (Trace.isOn("bitvector")) {
-    Trace("bitvector") << "Bitblaster::solve() asserted atoms ";
-    context::CDList<prop::SatLiteral>::const_iterator it = d_assertedAtoms.begin();
-    for (; it != d_assertedAtoms.end(); ++it) {
-      Trace("bitvector") << "     " << d_cnfStream->getNode(*it) << "\n";
-    }
-  }
-  Debug("bitvector") << "Bitblaster::solve() asserted atoms " << d_assertedAtoms.size() <<"\n";
-  return SAT_VALUE_TRUE == d_satSolver->solve();
-}
-
-void Bitblaster::getConflict(std::vector<TNode>& conflict) {
-  SatClause conflictClause;
-  d_satSolver->getUnsatCore(conflictClause);
-
-  for (unsigned i = 0; i < conflictClause.size(); i++) {
-    SatLiteral lit = conflictClause[i];
-    TNode atom = d_cnfStream->getNode(lit);
-    Node  not_atom;
-    if (atom.getKind() == kind::NOT) {
-      not_atom = atom[0];
-    } else {
-      not_atom = NodeManager::currentNM()->mkNode(kind::NOT, atom);
-    }
-    conflict.push_back(not_atom);
-  }
-}
-
-
-/// Helper methods
-
-
-void Bitblaster::initAtomBBStrategies() {
-  for (int i = 0 ; i < kind::LAST_KIND; ++i ) {
-    d_atomBBStrategies[i] = UndefinedAtomBBStrategy;
-  }
-
-  /// setting default bb strategies for atoms
-  d_atomBBStrategies [ kind::EQUAL ]           = DefaultEqBB;
-  d_atomBBStrategies [ kind::BITVECTOR_ULT ]   = DefaultUltBB;
-  d_atomBBStrategies [ kind::BITVECTOR_ULE ]   = DefaultUleBB;
-  d_atomBBStrategies [ kind::BITVECTOR_UGT ]   = DefaultUgtBB;
-  d_atomBBStrategies [ kind::BITVECTOR_UGE ]   = DefaultUgeBB;
-  d_atomBBStrategies [ kind::BITVECTOR_SLT ]   = DefaultSltBB;
-  d_atomBBStrategies [ kind::BITVECTOR_SLE ]   = DefaultSleBB;
-  d_atomBBStrategies [ kind::BITVECTOR_SGT ]   = DefaultSgtBB;
-  d_atomBBStrategies [ kind::BITVECTOR_SGE ]   = DefaultSgeBB;
-
-}
-
-void Bitblaster::initTermBBStrategies() {
-  // Changed this to DefaultVarBB because any foreign kind should be treated as a variable
-  // TODO: check this is OK
-  for (int i = 0 ; i < kind::LAST_KIND; ++i ) {
-    d_termBBStrategies[i] = DefaultVarBB;
-  }
-
-  /// setting default bb strategies for terms:
-  //  d_termBBStrategies [ kind::VARIABLE ]               = DefaultVarBB;
-  d_termBBStrategies [ kind::CONST_BITVECTOR ]        = DefaultConstBB;
-  d_termBBStrategies [ kind::BITVECTOR_NOT ]          = DefaultNotBB;
-  d_termBBStrategies [ kind::BITVECTOR_CONCAT ]       = DefaultConcatBB;
-  d_termBBStrategies [ kind::BITVECTOR_AND ]          = DefaultAndBB;
-  d_termBBStrategies [ kind::BITVECTOR_OR ]           = DefaultOrBB;
-  d_termBBStrategies [ kind::BITVECTOR_XOR ]          = DefaultXorBB;
-  d_termBBStrategies [ kind::BITVECTOR_XNOR ]         = DefaultXnorBB;
-  d_termBBStrategies [ kind::BITVECTOR_NAND ]         = DefaultNandBB ;
-  d_termBBStrategies [ kind::BITVECTOR_NOR ]          = DefaultNorBB;
-  d_termBBStrategies [ kind::BITVECTOR_COMP ]         = DefaultCompBB ;
-  d_termBBStrategies [ kind::BITVECTOR_MULT ]         = DefaultMultBB;
-  d_termBBStrategies [ kind::BITVECTOR_PLUS ]         = DefaultPlusBB;
-  d_termBBStrategies [ kind::BITVECTOR_SUB ]          = DefaultSubBB;
-  d_termBBStrategies [ kind::BITVECTOR_NEG ]          = DefaultNegBB;
-  d_termBBStrategies [ kind::BITVECTOR_UDIV ]         = UndefinedTermBBStrategy;
-  d_termBBStrategies [ kind::BITVECTOR_UREM ]         = UndefinedTermBBStrategy;
-  d_termBBStrategies [ kind::BITVECTOR_UDIV_TOTAL ]   = DefaultUdivBB;
-  d_termBBStrategies [ kind::BITVECTOR_UREM_TOTAL ]   = DefaultUremBB;
-  d_termBBStrategies [ kind::BITVECTOR_SDIV ]         = UndefinedTermBBStrategy;
-  d_termBBStrategies [ kind::BITVECTOR_SREM ]         = UndefinedTermBBStrategy;
-  d_termBBStrategies [ kind::BITVECTOR_SMOD ]         = UndefinedTermBBStrategy;
-  d_termBBStrategies [ kind::BITVECTOR_SHL ]          = DefaultShlBB;
-  d_termBBStrategies [ kind::BITVECTOR_LSHR ]         = DefaultLshrBB;
-  d_termBBStrategies [ kind::BITVECTOR_ASHR ]         = DefaultAshrBB;
-  d_termBBStrategies [ kind::BITVECTOR_EXTRACT ]      = DefaultExtractBB;
-  d_termBBStrategies [ kind::BITVECTOR_REPEAT ]       = DefaultRepeatBB;
-  d_termBBStrategies [ kind::BITVECTOR_ZERO_EXTEND ]  = DefaultZeroExtendBB;
-  d_termBBStrategies [ kind::BITVECTOR_SIGN_EXTEND ]  = DefaultSignExtendBB;
-  d_termBBStrategies [ kind::BITVECTOR_ROTATE_RIGHT ] = DefaultRotateRightBB;
-  d_termBBStrategies [ kind::BITVECTOR_ROTATE_LEFT ]  = DefaultRotateLeftBB;
-
-}
-
-bool Bitblaster::hasBBAtom(TNode atom) const {
-  return d_bitblastedAtoms.find(atom) != d_bitblastedAtoms.end();
-}
-
-void Bitblaster::cacheTermDef(TNode term, Bits def) {
-  Assert (d_termCache.find(term) == d_termCache.end());
-  d_termCache[term] = def;
-}
-
-bool Bitblaster::hasBBTerm(TNode node) const {
-  return d_termCache.find(node) != d_termCache.end();
-}
-
-void Bitblaster::getBBTerm(TNode node, Bits& bits) const {
-  Assert (hasBBTerm(node));
-  // copy?
-  bits = d_termCache.find(node)->second;
-}
-
-Bitblaster::Statistics::Statistics() :
-  d_numTermClauses("theory::bv::NumberOfTermSatClauses", 0),
-  d_numAtomClauses("theory::bv::NumberOfAtomSatClauses", 0),
-  d_numTerms("theory::bv::NumberOfBitblastedTerms", 0),
-  d_numAtoms("theory::bv::NumberOfBitblastedAtoms", 0),
-  d_bitblastTimer("theory::bv::BitblastTimer")
-{
-  StatisticsRegistry::registerStat(&d_numTermClauses);
-  StatisticsRegistry::registerStat(&d_numAtomClauses);
-  StatisticsRegistry::registerStat(&d_numTerms);
-  StatisticsRegistry::registerStat(&d_numAtoms);
-  StatisticsRegistry::registerStat(&d_bitblastTimer);
-}
-
-
-Bitblaster::Statistics::~Statistics() {
-  StatisticsRegistry::unregisterStat(&d_numTermClauses);
-  StatisticsRegistry::unregisterStat(&d_numAtomClauses);
-  StatisticsRegistry::unregisterStat(&d_numTerms);
-  StatisticsRegistry::unregisterStat(&d_numAtoms);
-  StatisticsRegistry::unregisterStat(&d_bitblastTimer);
-}
-
-bool Bitblaster::MinisatNotify::notify(prop::SatLiteral lit) {
-  return d_bv->storePropagation(d_cnf->getNode(lit), SUB_BITBLAST);
-};
-
-void Bitblaster::MinisatNotify::notify(prop::SatClause& clause) {
-  if (clause.size() > 1) {
-    NodeBuilder<> lemmab(kind::OR);
-    for (unsigned i = 0; i < clause.size(); ++ i) {
-      lemmab << d_cnf->getNode(clause[i]);
-    }
-    Node lemma = lemmab;
-    d_bv->d_out->lemma(lemma);
-  } else {
-    d_bv->d_out->lemma(d_cnf->getNode(clause[0]));
-  }
-};
-
-void Bitblaster::MinisatNotify::safePoint() {
-  d_bv->d_out->safePoint();
-}
-
-EqualityStatus Bitblaster::getEqualityStatus(TNode a, TNode b) {
-
-  // We don't want to bit-blast every possibly expensive term for the sake of equality checking
-  if (hasBBTerm(a) && hasBBTerm(b)) {
-
-  Bits a_bits, b_bits;
-  getBBTerm(a, a_bits);
-  getBBTerm(b, b_bits);
-  EqualityStatus status = EQUALITY_TRUE_IN_MODEL;
-  for (unsigned i = 0; i < a_bits.size(); ++ i) {
-    if (d_cnfStream->hasLiteral(a_bits[i]) && d_cnfStream->hasLiteral(b_bits[i])) {
-      SatLiteral a_lit = d_cnfStream->getLiteral(a_bits[i]);
-      SatValue a_lit_value = d_satSolver->value(a_lit);
-      if (a_lit_value != SAT_VALUE_UNKNOWN) {
-        SatLiteral b_lit = d_cnfStream->getLiteral(b_bits[i]);
-        SatValue b_lit_value = d_satSolver->value(b_lit);
-        if (b_lit_value != SAT_VALUE_UNKNOWN) {
-          if (a_lit_value != b_lit_value) {
-            return EQUALITY_FALSE_IN_MODEL;
-          }
-        } else {
-          status = EQUALITY_UNKNOWN;
-        }
-      } {
-        status = EQUALITY_UNKNOWN;
-      }
-    } else {
-      status = EQUALITY_UNKNOWN;
-    }
-  }
-
-  return status;
-
-  } else {
-    return EQUALITY_UNKNOWN;
-  }
-}
-
-
-bool Bitblaster::isSharedTerm(TNode node) {
-  return d_bv->d_sharedTermsSet.find(node) != d_bv->d_sharedTermsSet.end();
-}
-
-bool Bitblaster::hasValue(TNode a) {
-  Assert (d_termCache.find(a) != d_termCache.end());
-  Bits bits = d_termCache[a];
-  for (int i = bits.size() -1; i >= 0; --i) {
-    SatValue bit_value;
-    if (d_cnfStream->hasLiteral(bits[i])) {
-      SatLiteral bit = d_cnfStream->getLiteral(bits[i]);
-      bit_value = d_satSolver->value(bit);
-      if (bit_value == SAT_VALUE_UNKNOWN)
-        return false;
-    } else {
-      return false;
-    }
-  }
-  return true;
-}
-/**
- * Returns the value a is currently assigned to in the SAT solver
- * or null if the value is completely unassigned.
- *
- * @param a
- * @param fullModel whether to create a "full model," i.e., add
- * constants to equivalence classes that don't already have them
- *
- * @return
- */
-Node Bitblaster::getVarValue(TNode a, bool fullModel) {
-  if (d_termCache.find(a) == d_termCache.end()) {
-    Assert(isSharedTerm(a));
-    return Node();
-  }
-  Bits bits = d_termCache[a];
-  Integer value(0);
-  for (int i = bits.size() -1; i >= 0; --i) {
-    SatValue bit_value;
-    if (d_cnfStream->hasLiteral(bits[i])) {
-      SatLiteral bit = d_cnfStream->getLiteral(bits[i]);
-      bit_value = d_satSolver->value(bit);
-      Assert (bit_value != SAT_VALUE_UNKNOWN);
-    } else {
-      //TODO: return Node() if fullModel=false?
-      // the bit is unconstrainted so we can give it an arbitrary value
-      bit_value = SAT_VALUE_FALSE;
-    }
-    Integer bit_int = bit_value == SAT_VALUE_TRUE ? Integer(1) : Integer(0);
-    value = value * 2 + bit_int;
-  }
-  return utils::mkConst(BitVector(bits.size(), value));
-}
-
-void Bitblaster::collectModelInfo(TheoryModel* m, bool fullModel) {
-  __gnu_cxx::hash_set<TNode, TNodeHashFunction>::iterator it = d_variables.begin();
-  for (; it!= d_variables.end(); ++it) {
-    TNode var = *it;
-    if (Theory::theoryOf(var) == theory::THEORY_BV || isSharedTerm(var))  {
-      Node const_value = getVarValue(var, fullModel);
-      if(const_value == Node()) {
-        if( fullModel ){
-          // if the value is unassigned just set it to zero
-          const_value = utils::mkConst(BitVector(utils::getSize(var), 0u));
-        }
-      }
-      if(const_value != Node()) {
-        Debug("bitvector-model") << "Bitblaster::collectModelInfo (assert (= "
-                                  << var << " "
-                                  << const_value << "))\n";
-        m->assertEquality(var, const_value, true);
-      }
-    }
-  }
-}
-
-} /*bv namespace */
-} /* theory namespace */
-} /* CVC4 namespace*/
diff --git a/src/theory/bv/bitblaster.h b/src/theory/bv/bitblaster.h
deleted file mode 100644 (file)
index 3434508..0000000
+++ /dev/null
@@ -1,197 +0,0 @@
-/*********************                                                        */
-/*! \file bitblaster.h
- ** \verbatim
- ** Original author: Liana Hadarean
- ** Major contributors: Andrew Reynolds
- ** Minor contributors (to current version): Kshitij Bansal, Morgan Deters, Dejan Jovanovic
- ** 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 Wrapper around the SAT solver used for bitblasting
- **
- ** Wrapper around the SAT solver used for bitblasting.
- **/
-
-#include "cvc4_private.h"
-
-#ifndef __CVC4__BITBLASTER_H
-#define __CVC4__BITBLASTER_H
-
-
-#include "expr/node.h"
-#include <vector>
-#include <list>
-#include <iostream>
-#include <math.h>
-#include <ext/hash_map>
-
-#include "context/cdo.h"
-#include "context/cdhashset.h"
-#include "context/cdlist.h"
-
-#include "theory/theory.h"
-#include "theory_bv_utils.h"
-#include "util/statistics_registry.h"
-#include "bitblast_strategies.h"
-
-#include "prop/sat_solver.h"
-#include "prop/registrar.h"
-
-namespace CVC4 {
-
-// forward declarations
-namespace prop {
-class CnfStream;
-class BVSatSolverInterface;
-}
-
-namespace theory {
-
-class OutputChannel;
-class TheoryModel;
-
-namespace bv {
-
-typedef std::vector<Node> Bits;
-
-std::string toString (Bits& bits);
-
-class TheoryBV;
-
-/**
- * The Bitblaster that manages the mapping between Nodes
- * and their bitwise definition
- *
- */
-class Bitblaster {
-
-  /** This class gets callbacks from minisat on propagations */
-  class MinisatNotify : public prop::BVSatSolverInterface::Notify {
-    prop::CnfStream* d_cnf;
-    TheoryBV *d_bv;
-  public:
-    MinisatNotify(prop::CnfStream* cnf, TheoryBV *bv)
-    : d_cnf(cnf)
-    , d_bv(bv)
-    {}
-    bool notify(prop::SatLiteral lit);
-    void notify(prop::SatClause& clause);
-    void safePoint();
-  };
-
-
-  typedef __gnu_cxx::hash_map <Node, Bits, TNodeHashFunction >              TermDefMap;
-  typedef __gnu_cxx::hash_set<TNode, TNodeHashFunction>                      AtomSet;
-  typedef __gnu_cxx::hash_set<TNode, TNodeHashFunction>                      VarSet;
-
-  typedef void   (*TermBBStrategy) (TNode, Bits&, Bitblaster*);
-  typedef Node   (*AtomBBStrategy) (TNode, Bitblaster*);
-
-  TheoryBV *d_bv;
-
-  // sat solver used for bitblasting and associated CnfStream
-  theory::OutputChannel*             d_bvOutput;
-  MinisatNotify*                     d_notify;
-  prop::BVSatSolverInterface*        d_satSolver;
-  prop::CnfStream*                   d_cnfStream;
-  prop::NullRegistrar*               d_nullRegistrar;
-  context::Context*                  d_nullContext;
-
-  // caches and mappings
-  TermDefMap                   d_termCache;
-  AtomSet                      d_bitblastedAtoms;
-  VarSet                       d_variables;
-  context::CDList<prop::SatLiteral>  d_assertedAtoms; /**< context dependent list storing the atoms
-                                                       currently asserted by the DPLL SAT solver. */
-
-  /// helper methods
-  public:
-  bool          hasBBAtom(TNode node) const;
-  private:
-  bool          hasBBTerm(TNode node) const;
-  void          getBBTerm(TNode node, Bits& bits) const;
-
-  /// function tables for the various bitblasting strategies indexed by node kind
-  TermBBStrategy d_termBBStrategies[kind::LAST_KIND];
-  AtomBBStrategy d_atomBBStrategies[kind::LAST_KIND];
-
-  // helper methods to initialize function tables
-  void initAtomBBStrategies();
-  void initTermBBStrategies();
-
-  // returns a node that might be easier to bitblast
-  Node bbOptimize(TNode node);
-
-  void addAtom(TNode atom);
-  // division is bitblasted in terms of constraints
-  // so it needs to use private bitblaster interface
-  void bbUdiv(TNode node, Bits& bits);
-  void bbUrem(TNode node, Bits& bits);
-  bool hasValue(TNode a);
-public:
-  void cacheTermDef(TNode node, Bits def); // public so we can cache remainder for division
-  void bbTerm(TNode node, Bits&  bits);
-  void bbAtom(TNode node);
-
-  Bitblaster(context::Context* c, bv::TheoryBV* bv);
-  ~Bitblaster();
-  bool assertToSat(TNode node, bool propagate = true);
-  bool propagate();
-  bool solve(bool quick_solve = false);
-  void getConflict(std::vector<TNode>& conflict);
-  void explain(TNode atom, std::vector<TNode>& explanation);
-
-  EqualityStatus getEqualityStatus(TNode a, TNode b);
-  /**
-   * Return a constant Node representing the value of a variable
-   * in the current model.
-   * @param a
-   *
-   * @return
-   */
-  Node getVarValue(TNode a, bool fullModel=true);
-  /**
-   * Adds a constant value for each bit-blasted variable in the model.
-   *
-   * @param m the model
-   * @param fullModel whether to create a "full model," i.e., add
-   * constants to equivalence classes that don't already have them
-   */
-  void collectModelInfo(TheoryModel* m, bool fullModel);
-  /**
-   * Stores the variable (or non-bv term) and its corresponding bits.
-   *
-   * @param var
-   */
-  void storeVariable(TNode var) {
-    d_variables.insert(var);
-  }
-
-  bool isSharedTerm(TNode node);
-  uint64_t computeAtomWeight(TNode node);
-
-private:
-
-  class Statistics {
-  public:
-    IntStat d_numTermClauses, d_numAtomClauses;
-    IntStat d_numTerms, d_numAtoms;
-    TimerStat d_bitblastTimer;
-    Statistics();
-    ~Statistics();
-  };
-
-  Statistics d_statistics;
-};
-
-
-
-} /* bv namespace */
-
-} /* theory namespace */
-
-} /* CVC4 namespace */
-
-#endif /* __CVC4__BITBLASTER_H */
diff --git a/src/theory/bv/bitblaster_template.h b/src/theory/bv/bitblaster_template.h
new file mode 100644 (file)
index 0000000..25de81f
--- /dev/null
@@ -0,0 +1,399 @@
+/*********************                                                        */
+/*! \file bitblaster.h
+ ** \verbatim
+ ** Original author: Liana Hadarean
+ ** Major contributors: none
+ ** Minor contributors (to current version): lianah, Morgan Deters, Dejan Jovanovic
+ ** 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 Wrapper around the SAT solver used for bitblasting
+ **
+ ** Wrapper around the SAT solver used for bitblasting.
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef __CVC4__BITBLASTER_TEMPLATE_H
+#define __CVC4__BITBLASTER_TEMPLATE_H
+
+
+#include "expr/node.h"
+#include <vector>
+#include <ext/hash_map>
+#include "context/cdhashmap.h"
+#include "bitblast_strategies_template.h"
+#include "prop/sat_solver.h"
+#include "theory/valuation.h"
+
+class Abc_Obj_t_;
+typedef Abc_Obj_t_ Abc_Obj_t;
+
+class Abc_Ntk_t_;
+typedef Abc_Ntk_t_ Abc_Ntk_t;
+
+class Abc_Aig_t_;
+typedef Abc_Aig_t_ Abc_Aig_t;
+
+class Cnf_Dat_t_;
+typedef Cnf_Dat_t_ Cnf_Dat_t;
+
+
+namespace CVC4 {
+namespace prop {
+class CnfStream;
+class BVSatSolverInterface;
+class NullRegistrar;
+}
+
+namespace theory {
+class OutputChannel;
+class TheoryModel;
+
+namespace bv {
+
+class BitblastingRegistrar;
+
+typedef __gnu_cxx::hash_set<Node, NodeHashFunction> NodeSet;
+class AbstractionModule;
+
+/**
+ * The Bitblaster that manages the mapping between Nodes
+ * and their bitwise definition
+ *
+ */
+
+template <class T>
+class TBitblaster {
+protected:
+  typedef std::vector<T> Bits;
+  typedef __gnu_cxx::hash_map <Node, Bits, NodeHashFunction>  TermDefMap;
+  typedef __gnu_cxx::hash_set<TNode, TNodeHashFunction>       AtomSet;
+
+  typedef void  (*TermBBStrategy) (TNode, Bits&, TBitblaster<T>*);
+  typedef T     (*AtomBBStrategy) (TNode, TBitblaster<T>*);
+
+  // caches and mappings
+  TermDefMap                   d_termCache;
+
+  void initAtomBBStrategies();
+  void initTermBBStrategies();
+protected:
+  /// function tables for the various bitblasting strategies indexed by node kind
+  TermBBStrategy d_termBBStrategies[kind::LAST_KIND];
+  AtomBBStrategy d_atomBBStrategies[kind::LAST_KIND]; 
+public:
+  TBitblaster(); 
+  virtual ~TBitblaster() {}
+  virtual void bbAtom(TNode node) = 0; 
+  virtual void bbTerm(TNode node, Bits&  bits) = 0;
+  virtual void makeVariable(TNode node, Bits& bits) = 0;
+  virtual T getBBAtom(TNode atom) const = 0;
+  virtual bool hasBBAtom(TNode atom) const = 0;
+  virtual void storeBBAtom(TNode atom, T atom_bb) = 0;
+  
+  bool hasBBTerm(TNode node) const;
+  void getBBTerm(TNode node, Bits& bits) const;
+  void storeBBTerm(TNode term, const Bits& bits); 
+}; 
+
+
+class TheoryBV; 
+
+class TLazyBitblaster :  public TBitblaster<Node> {
+  typedef std::vector<Node> Bits;
+  typedef __gnu_cxx::hash_set<TNode, TNodeHashFunction> VarSet;
+  typedef __gnu_cxx::hash_set<TNode, TNodeHashFunction> AtomSet;
+  typedef context::CDList<prop::SatLiteral> AssertionList;
+  typedef context::CDHashMap<prop::SatLiteral, std::vector<prop::SatLiteral> , prop::SatLiteralHashFunction> ExplanationMap;
+  
+  /** This class gets callbacks from minisat on propagations */
+  class MinisatNotify : public prop::BVSatSolverInterface::Notify {
+    prop::CnfStream* d_cnf;
+    TheoryBV *d_bv;
+    TLazyBitblaster* d_lazyBB; 
+  public:
+    MinisatNotify(prop::CnfStream* cnf, TheoryBV *bv, TLazyBitblaster* lbv)
+    : d_cnf(cnf)
+    , d_bv(bv)
+    , d_lazyBB(lbv)
+    {}
+    bool notify(prop::SatLiteral lit);
+    void notify(prop::SatClause& clause);
+    void safePoint();
+  };
+  
+  TheoryBV *d_bv;
+  context::Context* d_ctx;
+
+  prop::NullRegistrar* d_nullRegistrar;
+  context::Context* d_nullContext;
+  // sat solver used for bitblasting and associated CnfStream
+  prop::BVSatSolverInterface*        d_satSolver;
+  prop::CnfStream*                   d_cnfStream;
+
+  AssertionList d_assertedAtoms; /**< context dependent list storing the atoms
+                                     currently asserted by the DPLL SAT solver. */
+  ExplanationMap d_explanations; /**< context dependent list of explanations for the propagated literals.
+                                    Only used when bvEagerPropagate option enabled. */
+  VarSet d_variables;
+  AtomSet d_bbAtoms; 
+  AbstractionModule* d_abstraction;
+  bool d_emptyNotify;
+  
+  void addAtom(TNode atom);
+  bool hasValue(TNode a);
+public:
+  void bbTerm(TNode node, Bits&  bits);
+  void bbAtom(TNode node);
+  Node getBBAtom(TNode atom) const;
+  void storeBBAtom(TNode atom, Node atom_bb);
+  bool hasBBAtom(TNode atom) const; 
+  TLazyBitblaster(context::Context* c, bv::TheoryBV* bv, const std::string name="", bool emptyNotify = false);
+  ~TLazyBitblaster();
+  /** 
+   * Pushes the assumption literal associated with node to the SAT
+   * solver assumption queue. 
+   * 
+   * @param node assumption
+   * @param propagate run bcp or not
+   * 
+   * @return false if a conflict detected
+   */
+  bool assertToSat(TNode node, bool propagate = true);
+  bool propagate();
+  bool solve();
+  prop::SatValue solveWithBudget(unsigned long conflict_budget);
+  void getConflict(std::vector<TNode>& conflict);
+  void explain(TNode atom, std::vector<TNode>& explanation);
+  void setAbstraction(AbstractionModule* abs);
+  
+  theory::EqualityStatus getEqualityStatus(TNode a, TNode b);
+  /**
+   * Return a constant Node representing the value of a variable
+   * in the current model.
+   * @param a
+   *
+   * @return
+   */
+  Node getVarValue(TNode a, bool fullModel=true);
+  /**
+   * Adds a constant value for each bit-blasted variable in the model.
+   *
+   * @param m the model
+   * @param fullModel whether to create a "full model," i.e., add
+   * constants to equivalence classes that don't already have them
+   */
+  void collectModelInfo(TheoryModel* m, bool fullModel);
+
+  typedef VarSet::const_iterator vars_iterator;
+  vars_iterator beginVars() { return d_variables.begin(); }
+  vars_iterator endVars() { return d_variables.end(); }
+
+  /**
+   * Creates the bits corresponding to the variable (or non-bv term). 
+   *
+   * @param var
+   */
+  void makeVariable(TNode var, Bits& bits);
+
+  bool isSharedTerm(TNode node);
+  uint64_t computeAtomWeight(TNode node, NodeSet& seen);
+  /** 
+   * Deletes SatSolver and CnfCache, but maintains bit-blasting
+   * terms cache. 
+   * 
+   */
+  void clearSolver(); 
+private:
+
+  class Statistics {
+  public:
+    IntStat d_numTermClauses, d_numAtomClauses;
+    IntStat d_numTerms, d_numAtoms;
+    IntStat d_numExplainedPropagations;
+    IntStat d_numBitblastingPropagations;
+    TimerStat d_bitblastTimer;
+    Statistics(const std::string& name);
+    ~Statistics();
+  };
+  std::string d_name; 
+  Statistics d_statistics;
+};
+
+class MinisatEmptyNotify : public prop::BVSatSolverInterface::Notify {
+public:
+  MinisatEmptyNotify() {}
+  bool notify(prop::SatLiteral lit) { return true; }
+  void notify(prop::SatClause& clause) { }
+  void safePoint() {}
+};
+
+
+class EagerBitblaster : public TBitblaster<Node> {
+  typedef __gnu_cxx::hash_set<TNode, TNodeHashFunction> TNodeSet;
+  // sat solver used for bitblasting and associated CnfStream
+  prop::BVSatSolverInterface*        d_satSolver;
+  BitblastingRegistrar*              d_bitblastingRegistrar;
+  context::Context*                  d_nullContext;
+  prop::CnfStream*                   d_cnfStream;
+  TNodeSet d_bbAtoms; 
+public:
+  void addAtom(TNode atom);
+  void makeVariable(TNode node, Bits& bits);
+  void bbTerm(TNode node, Bits&  bits);
+  void bbAtom(TNode node);
+  Node getBBAtom(TNode node) const;
+  bool hasBBAtom(TNode atom) const; 
+  void bbFormula(TNode formula);
+  void storeBBAtom(TNode atom, Node atom_bb);
+  EagerBitblaster(); 
+  ~EagerBitblaster();
+  bool assertToSat(TNode node, bool propagate = true);
+  bool solve(); 
+};
+
+class AigBitblaster : public TBitblaster<Abc_Obj_t*> {
+  typedef std::hash_map<TNode, Abc_Obj_t*, TNodeHashFunction > TNodeAigMap;
+  typedef std::hash_map<Node, Abc_Obj_t*, NodeHashFunction > NodeAigMap;
+  
+  static Abc_Ntk_t* abcAigNetwork;
+  context::Context* d_nullContext;
+  prop::BVSatSolverInterface* d_satSolver;
+  TNodeAigMap d_aigCache;
+  NodeAigMap d_bbAtoms;
+  
+  NodeAigMap d_nodeToAigInput;
+  // the thing we are checking for sat
+  Abc_Obj_t* d_aigOutputNode;
+
+  void addAtom(TNode atom);
+  void simplifyAig();
+  void storeBBAtom(TNode atom, Abc_Obj_t* atom_bb);
+  Abc_Obj_t* getBBAtom(TNode atom) const;
+  bool hasBBAtom(TNode atom) const;
+  void cacheAig(TNode node, Abc_Obj_t* aig);
+  bool hasAig(TNode node);
+  Abc_Obj_t* getAig(TNode node);
+  Abc_Obj_t* mkInput(TNode input);
+  bool hasInput(TNode input);
+  void convertToCnfAndAssert();
+  void assertToSatSolver(Cnf_Dat_t* pCnf);
+
+public:
+  AigBitblaster();
+  ~AigBitblaster();
+
+  void makeVariable(TNode node, Bits& bits);
+  void bbTerm(TNode node, Bits&  bits);
+  void bbAtom(TNode node);
+  Abc_Obj_t* bbFormula(TNode formula);
+  bool solve(TNode query); 
+  static Abc_Aig_t* currentAigM();
+  static Abc_Ntk_t* currentAigNtk();
+  
+private:
+  class Statistics {
+  public:
+    IntStat     d_numClauses;
+    IntStat     d_numVariables; 
+    TimerStat   d_simplificationTime;
+    TimerStat   d_cnfConversionTime;
+    TimerStat   d_solveTime; 
+    Statistics();
+    ~Statistics();
+  };
+
+  Statistics d_statistics;
+
+};
+
+
+// Bitblaster implementation
+
+template <class T> void TBitblaster<T>::initAtomBBStrategies() {
+  for (int i = 0 ; i < kind::LAST_KIND; ++i ) {
+    d_atomBBStrategies[i] = UndefinedAtomBBStrategy<T>;
+  }
+  /// setting default bb strategies for atoms
+  d_atomBBStrategies [ kind::EQUAL ]           = DefaultEqBB<T>;
+  d_atomBBStrategies [ kind::BITVECTOR_ULT ]   = DefaultUltBB<T>;
+  d_atomBBStrategies [ kind::BITVECTOR_ULE ]   = DefaultUleBB<T>;
+  d_atomBBStrategies [ kind::BITVECTOR_UGT ]   = DefaultUgtBB<T>;
+  d_atomBBStrategies [ kind::BITVECTOR_UGE ]   = DefaultUgeBB<T>;
+  d_atomBBStrategies [ kind::BITVECTOR_SLT ]   = DefaultSltBB<T>;
+  d_atomBBStrategies [ kind::BITVECTOR_SLE ]   = DefaultSleBB<T>;
+  d_atomBBStrategies [ kind::BITVECTOR_SGT ]   = DefaultSgtBB<T>;
+  d_atomBBStrategies [ kind::BITVECTOR_SGE ]   = DefaultSgeBB<T>;
+}
+
+template <class T> void TBitblaster<T>::initTermBBStrategies() {
+  for (int i = 0 ; i < kind::LAST_KIND; ++i ) {
+    d_termBBStrategies[i] = DefaultVarBB<T>;
+  }
+  /// setting default bb strategies for terms:
+  d_termBBStrategies [ kind::CONST_BITVECTOR ]        = DefaultConstBB<T>;
+  d_termBBStrategies [ kind::BITVECTOR_NOT ]          = DefaultNotBB<T>;
+  d_termBBStrategies [ kind::BITVECTOR_CONCAT ]       = DefaultConcatBB<T>;
+  d_termBBStrategies [ kind::BITVECTOR_AND ]          = DefaultAndBB<T>;
+  d_termBBStrategies [ kind::BITVECTOR_OR ]           = DefaultOrBB<T>;
+  d_termBBStrategies [ kind::BITVECTOR_XOR ]          = DefaultXorBB<T>;
+  d_termBBStrategies [ kind::BITVECTOR_XNOR ]         = DefaultXnorBB<T>;
+  d_termBBStrategies [ kind::BITVECTOR_NAND ]         = DefaultNandBB<T>;
+  d_termBBStrategies [ kind::BITVECTOR_NOR ]          = DefaultNorBB<T>;
+  d_termBBStrategies [ kind::BITVECTOR_COMP ]         = DefaultCompBB<T>;
+  d_termBBStrategies [ kind::BITVECTOR_MULT ]         = DefaultMultBB<T>;
+  d_termBBStrategies [ kind::BITVECTOR_PLUS ]         = DefaultPlusBB<T>;
+  d_termBBStrategies [ kind::BITVECTOR_SUB ]          = DefaultSubBB<T>;
+  d_termBBStrategies [ kind::BITVECTOR_NEG ]          = DefaultNegBB<T>;
+  d_termBBStrategies [ kind::BITVECTOR_UDIV ]         = UndefinedTermBBStrategy<T>;
+  d_termBBStrategies [ kind::BITVECTOR_UREM ]         = UndefinedTermBBStrategy<T>;
+  d_termBBStrategies [ kind::BITVECTOR_UDIV_TOTAL ]   = DefaultUdivBB<T>;
+  d_termBBStrategies [ kind::BITVECTOR_UREM_TOTAL ]   = DefaultUremBB<T>;
+  d_termBBStrategies [ kind::BITVECTOR_SDIV ]         = UndefinedTermBBStrategy<T>;
+  d_termBBStrategies [ kind::BITVECTOR_SREM ]         = UndefinedTermBBStrategy<T>;
+  d_termBBStrategies [ kind::BITVECTOR_SMOD ]         = UndefinedTermBBStrategy<T>;
+  d_termBBStrategies [ kind::BITVECTOR_SHL ]          = DefaultShlBB<T>;
+  d_termBBStrategies [ kind::BITVECTOR_LSHR ]         = DefaultLshrBB<T>;
+  d_termBBStrategies [ kind::BITVECTOR_ASHR ]         = DefaultAshrBB<T>;
+  d_termBBStrategies [ kind::BITVECTOR_EXTRACT ]      = DefaultExtractBB<T>;
+  d_termBBStrategies [ kind::BITVECTOR_REPEAT ]       = DefaultRepeatBB<T>;
+  d_termBBStrategies [ kind::BITVECTOR_ZERO_EXTEND ]  = DefaultZeroExtendBB<T>;
+  d_termBBStrategies [ kind::BITVECTOR_SIGN_EXTEND ]  = DefaultSignExtendBB<T>;
+  d_termBBStrategies [ kind::BITVECTOR_ROTATE_RIGHT ] = DefaultRotateRightBB<T>;
+  d_termBBStrategies [ kind::BITVECTOR_ROTATE_LEFT ]  = DefaultRotateLeftBB<T>;
+}
+
+template <class T>
+TBitblaster<T>::TBitblaster()
+  : d_termCache()
+{
+  initAtomBBStrategies();
+  initTermBBStrategies(); 
+}
+
+template <class T>
+bool TBitblaster<T>::hasBBTerm(TNode node) const {
+  return d_termCache.find(node) != d_termCache.end();
+}
+template <class T>
+void TBitblaster<T>::getBBTerm(TNode node, Bits& bits) const {
+  Assert (hasBBTerm(node));
+  bits = d_termCache.find(node)->second;
+}
+
+template <class T>
+void TBitblaster<T>::storeBBTerm(TNode node, const Bits& bits) {
+  d_termCache.insert(std::make_pair(node, bits));
+}
+
+
+} /* bv namespace */
+
+} /* theory namespace */
+
+} /* CVC4 namespace */
+
+#endif /* __CVC4__BITBLASTER_H */
diff --git a/src/theory/bv/bv_eager_solver.cpp b/src/theory/bv/bv_eager_solver.cpp
new file mode 100644 (file)
index 0000000..af35c04
--- /dev/null
@@ -0,0 +1,108 @@
+/*********************                                                        */
+/*! \file bv_eager_solver.h
+ ** \verbatim
+ ** Original author: Liana Hadarean 
+ ** Major contributors: none
+ ** Minor contributors (to current version): 
+ ** 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 Eager bit-blasting solver. 
+ **
+ ** Eager bit-blasting solver.
+ **/
+
+#include "theory/bv/bv_eager_solver.h"
+#include "theory/bv/bitblaster_template.h"
+#include "theory/bv/eager_bitblaster.h"
+#include "theory/bv/aig_bitblaster.h"
+
+using namespace std;
+using namespace CVC4;
+using namespace CVC4::theory;
+using namespace CVC4::theory::bv;
+
+EagerBitblastSolver::EagerBitblastSolver()
+  : d_assertionSet()
+  , d_bitblaster(NULL)
+  , d_aigBitblaster(NULL)
+  , d_useAig(options::bitvectorAig())
+{}
+
+EagerBitblastSolver::~EagerBitblastSolver() {
+  if (d_useAig) {
+    Assert (d_bitblaster == NULL); 
+    delete d_aigBitblaster;
+  }
+  else {
+    Assert (d_aigBitblaster == NULL); 
+    delete d_bitblaster;
+  }
+}
+
+void EagerBitblastSolver::turnOffAig() {
+  Assert (d_aigBitblaster == NULL &&
+          d_bitblaster == NULL);
+  d_useAig = false;
+}
+
+void EagerBitblastSolver::initialize() {
+  Assert(!isInitialized());
+  if (d_useAig) {
+    d_aigBitblaster = new AigBitblaster();
+  } else {
+    d_bitblaster = new EagerBitblaster();
+  }
+}
+
+bool EagerBitblastSolver::isInitialized() {
+  bool init = d_aigBitblaster != NULL || d_bitblaster != NULL;
+  if (init) {
+    Assert (!d_useAig || d_aigBitblaster);
+    Assert (d_useAig || d_bitblaster);
+  }
+  return init;
+}
+
+void EagerBitblastSolver::assertFormula(TNode formula) {
+  Assert (isInitialized());
+  Debug("bitvector-eager") << "EagerBitblastSolver::assertFormula "<< formula <<"\n"; 
+  d_assertionSet.insert(formula);
+  //ensures all atoms are bit-blasted and converted to AIG
+  if (d_useAig) 
+    d_aigBitblaster->bbFormula(formula);
+  else
+    d_bitblaster->bbFormula(formula);
+}
+
+bool EagerBitblastSolver::checkSat() {
+  Assert (isInitialized());
+  std::vector<TNode> assertions; 
+  for (AssertionSet::const_iterator it = d_assertionSet.begin(); it != d_assertionSet.end(); ++it) {
+    assertions.push_back(*it); 
+  }
+  if (!assertions.size())
+    return true;
+  
+  if (d_useAig) {
+    Node query = utils::mkAnd(assertions); 
+    return d_aigBitblaster->solve(query);
+  }
+  
+  return d_bitblaster->solve(); 
+}
+
+bool EagerBitblastSolver::hasAssertions(const std::vector<TNode> &formulas) {
+  Assert (isInitialized());
+  if (formulas.size() != d_assertionSet.size())
+    return false; 
+  for (unsigned i = 0; i < formulas.size(); ++i) {
+    Assert (formulas[i].getKind() == kind::BITVECTOR_EAGER_ATOM);
+    TNode formula = formulas[i][0];
+    if (d_assertionSet.find(formula) == d_assertionSet.end())
+      return false; 
+  }
+  return true; 
+}
diff --git a/src/theory/bv/bv_eager_solver.h b/src/theory/bv/bv_eager_solver.h
new file mode 100644 (file)
index 0000000..1fb65c9
--- /dev/null
@@ -0,0 +1,55 @@
+/*********************                                                        */
+/*! \file bv_eager_solver.h
+ ** \verbatim
+ ** Original author: Liana Hadarean 
+ ** Major contributors: none
+ ** Minor contributors (to current version): 
+ ** 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 Eager bit-blasting solver. 
+ **
+ ** Eager bit-blasting solver.
+ **/
+
+#include "cvc4_private.h"
+#include "expr/node.h"
+#include <vector>
+#pragma once
+
+
+namespace CVC4 {
+namespace theory {
+namespace bv {
+
+class EagerBitblaster;
+class AigBitblaster;
+
+/**
+ * BitblastSolver
+ */
+class EagerBitblastSolver {
+  typedef __gnu_cxx::hash_set<TNode, TNodeHashFunction> AssertionSet; 
+  AssertionSet d_assertionSet;
+  /** Bitblasters */
+  EagerBitblaster* d_bitblaster;
+  AigBitblaster* d_aigBitblaster;
+  bool d_useAig;
+public:
+  EagerBitblastSolver(); 
+  ~EagerBitblastSolver();
+  bool checkSat();
+  void assertFormula(TNode formula);
+  // purely for debugging purposes
+  bool hasAssertions(const std::vector<TNode> &formulas);
+
+  void turnOffAig();
+  bool isInitialized();
+  void initialize();
+};
+
+}
+}
+}
diff --git a/src/theory/bv/bv_quick_check.cpp b/src/theory/bv/bv_quick_check.cpp
new file mode 100644 (file)
index 0000000..1adbb83
--- /dev/null
@@ -0,0 +1,377 @@
+/*********************                                                        */
+/*! \file bv_quick_check.cpp
+ ** \verbatim
+ ** Original author: Liana Hadaren
+ ** Major contributors: none
+ ** 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 Wrapper around the SAT solver used for bitblasting.
+ **
+ ** Wrapper around the SAT solver used for bitblasting.
+ **/
+
+#include "theory/bv/bv_quick_check.h"
+#include "theory/bv/theory_bv_utils.h"
+
+#include "theory/bv/bitblaster_template.h"
+
+using namespace CVC4;
+using namespace CVC4::theory;
+using namespace CVC4::theory::bv;
+using namespace CVC4::prop;
+
+BVQuickCheck::BVQuickCheck(const std::string& name, theory::bv::TheoryBV* bv)
+  : d_ctx(new context::Context())
+  , d_bitblaster(new TLazyBitblaster(d_ctx, bv, name, true))
+  , d_conflict()
+  , d_inConflict(d_ctx, false)
+{}
+
+
+bool BVQuickCheck::inConflict() { return d_inConflict.get(); }
+
+uint64_t BVQuickCheck::computeAtomWeight(TNode node, NodeSet& seen) {
+  return d_bitblaster->computeAtomWeight(node, seen);
+}
+
+void BVQuickCheck::setConflict() {
+  Assert (!inConflict());
+  std::vector<TNode> conflict;
+  d_bitblaster->getConflict(conflict);
+  Node confl = utils::mkConjunction(conflict);
+  d_inConflict = true;
+  d_conflict = confl;
+}
+
+prop::SatValue BVQuickCheck::checkSat(std::vector<Node>& assumptions, unsigned long budget) {
+  Node conflict; 
+
+  for (unsigned i = 0; i < assumptions.size(); ++i) {
+    TNode a = assumptions[i];
+    Assert (a.getType().isBoolean());
+    d_bitblaster->bbAtom(a);
+    bool ok = d_bitblaster->assertToSat(a, false);
+    if (!ok) {
+      setConflict(); 
+      return SAT_VALUE_FALSE; 
+    }
+  }
+  
+  if (budget == 0) {
+    bool ok = d_bitblaster->propagate();
+    if (!ok) {
+      setConflict();
+      return SAT_VALUE_FALSE;
+    }
+    return SAT_VALUE_UNKNOWN; // could check if assignment is full and return SAT_VALUE_TRUE
+  }
+
+  prop::SatValue res = d_bitblaster->solveWithBudget(budget);
+  if (res == SAT_VALUE_FALSE) {
+    setConflict();
+    return res;
+  }
+  // could be unknown or could be sat
+   return res;
+}
+
+prop::SatValue BVQuickCheck::checkSat(unsigned long budget) {
+  prop::SatValue res = d_bitblaster->solveWithBudget(budget);
+  if (res == SAT_VALUE_FALSE) {
+    setConflict();
+  }
+  return res;
+}
+
+bool BVQuickCheck::addAssertion(TNode assertion) {
+  Assert (assertion.getType().isBoolean());
+  d_bitblaster->bbAtom(assertion);
+  // assert to sat solver and run bcp to detect easy conflicts
+  bool ok = d_bitblaster->assertToSat(assertion, true);
+  if (!ok) {
+    setConflict();
+  }
+  return ok;
+}
+
+
+void BVQuickCheck::push() {
+  d_ctx->push();
+}
+
+void BVQuickCheck::pop() {
+  d_ctx->pop();
+}
+
+BVQuickCheck::vars_iterator BVQuickCheck::beginVars() {
+  return d_bitblaster->beginVars(); 
+}
+BVQuickCheck::vars_iterator BVQuickCheck::endVars() {
+  return d_bitblaster->endVars(); 
+}
+
+Node BVQuickCheck::getVarValue(TNode var) {
+  return d_bitblaster->getVarValue(var); 
+}
+
+
+/** 
+ * Constructs a new sat solver which requires throwing out the atomBBCache
+ * but keeps all the termBBCache
+ * 
+ */
+void BVQuickCheck::clearSolver() {
+  popToZero();
+  d_bitblaster->clearSolver();
+}
+
+void BVQuickCheck::popToZero() {
+  while (d_ctx->getLevel() > 0) {
+    d_ctx->pop();
+  }
+}
+
+void BVQuickCheck::collectModelInfo(theory::TheoryModel* model, bool fullModel) {
+  d_bitblaster->collectModelInfo(model, fullModel);
+}
+
+BVQuickCheck::~BVQuickCheck() {
+  delete d_bitblaster;
+}
+
+QuickXPlain::QuickXPlain(const std::string& name, BVQuickCheck* solver, unsigned long budget)
+  : d_solver(solver)
+  , d_budget(budget)
+  , d_numCalled(0)
+  , d_minRatioSum(0)
+  , d_numConflicts(0)
+  , d_period(20)
+  , d_thresh(0.7)
+  , d_hardThresh(0.9)
+  , d_statistics(name)
+{}
+QuickXPlain::~QuickXPlain() {}
+
+unsigned QuickXPlain::selectUnsatCore(unsigned low, unsigned high,
+                                      std::vector<TNode>& conflict) {
+
+  Assert(!d_solver->getConflict().isNull() &&
+         d_solver->inConflict());
+  Node query_confl = d_solver->getConflict();
+
+  // conflict wasn't actually minimized
+  if (query_confl.getNumChildren() == high - low + 1) {
+    return high;
+  }
+
+  TNodeSet nodes;
+  for (unsigned i = low; i <= high; i++) {
+    nodes.insert(conflict[i]);
+  }
+  
+  unsigned write = low;
+  for (unsigned i = 0; i < query_confl.getNumChildren(); ++i) {
+    TNode current = query_confl[i];
+    // the conflict can have nodes in lower decision levels
+    if (nodes.find(current) != nodes.end()) {
+      conflict[write++] = current;
+      nodes.erase(nodes.find(current));
+    }
+  }
+  // if all of the nodes in the conflict were on a lower level
+  if (write == low) {
+    return low;
+  }
+  Assert (write != 0);
+  unsigned new_high = write - 1;
+
+  for (TNodeSet::const_iterator it = nodes.begin(); it != nodes.end(); ++it) {
+    conflict[write++] = *it;
+  }
+  Assert (write -1 == high);
+  Assert (new_high <= high);
+  
+  return new_high;
+}
+
+void QuickXPlain::minimizeConflictInternal(unsigned low, unsigned high,
+                                           std::vector<TNode>& conflict,
+                                           std::vector<TNode>& new_conflict) {
+
+  Assert (low <= high && high < conflict.size());
+  
+  if (low == high) {
+    new_conflict.push_back(conflict[low]);
+    return;
+  }
+
+  // check if top half is unsat
+  unsigned new_low = (high - low + 1)/ 2 + low;
+  d_solver->push();
+  
+  for (unsigned i = new_low; i <=high; ++i) {
+    bool ok = d_solver->addAssertion(conflict[i]);
+    if (!ok) {
+      unsigned top = selectUnsatCore(new_low, i, conflict);
+      d_solver->pop(); 
+      minimizeConflictInternal(new_low, top, conflict, new_conflict);
+      return;
+    }
+  }
+
+  SatValue res = d_solver->checkSat(d_budget);
+
+  if (res == SAT_VALUE_UNKNOWN) {
+    ++(d_statistics.d_numUnknown);
+  } else {
+    ++(d_statistics.d_numSolved);
+  }
+
+  if (res == SAT_VALUE_FALSE) {
+    unsigned top = selectUnsatCore(new_low, high, conflict);
+    d_solver->pop();
+    minimizeConflictInternal(new_low, top, conflict, new_conflict);
+    return;
+  }
+  
+  d_solver->pop();
+  unsigned new_high = new_low - 1;
+  d_solver->push();
+
+  // check bottom half
+  for (unsigned i = low; i <= new_high; ++i) {
+    bool ok = d_solver->addAssertion(conflict[i]);
+    if (!ok) {
+      unsigned top = selectUnsatCore(low, i, conflict);
+      d_solver->pop();
+      minimizeConflictInternal(low, top, conflict, new_conflict);
+      return;
+    }
+  }
+  
+  res = d_solver->checkSat(d_budget);
+
+  if (res == SAT_VALUE_UNKNOWN) {
+    ++(d_statistics.d_numUnknown);
+  } else {
+    ++(d_statistics.d_numSolved);
+  }
+
+  if (res == SAT_VALUE_FALSE) {
+    unsigned top = selectUnsatCore(low, new_high, conflict);
+    d_solver->pop();
+    minimizeConflictInternal(low, top, conflict, new_conflict);
+    return;
+  }
+
+  // conflict (probably) contains literals in both halves
+  // keep bottom half in context (no pop)
+  minimizeConflictInternal(new_low, high, conflict, new_conflict);
+  d_solver->pop();
+  d_solver->push();
+  for (unsigned i = 0; i < new_conflict.size(); ++i) {
+    bool ok = d_solver->addAssertion(new_conflict[i]);
+    if (!ok) {
+      ++(d_statistics.d_numUnknownWasUnsat);
+      d_solver->pop(); 
+      return; 
+    }
+  }
+  minimizeConflictInternal(low, new_high, conflict, new_conflict);
+  d_solver->pop();
+}
+
+
+bool QuickXPlain::useHeuristic() {
+  return true; 
+  // d_statistics.d_finalPeriod.setData(d_period);
+  // // try to minimize conflict periodically 
+  // if (d_numConflicts % d_period == 0)
+  //   return true;
+
+  // if (d_numCalled == 0) {
+  //   return true;
+  // }
+  
+  // if (d_minRatioSum / d_numCalled >= d_thresh &&
+  //     d_numCalled <= 20 ) {
+  //   return false;
+  // }
+
+  // if (d_minRatioSum / d_numCalled >= d_hardThresh) {
+  //   return false;
+  // }
+
+  // return true;
+}
+
+Node QuickXPlain::minimizeConflict(TNode confl) {
+  ++d_numConflicts;
+
+  if (!useHeuristic()) {
+    return confl;
+  }
+
+  ++d_numCalled;
+  ++(d_statistics.d_numConflictsMinimized);
+  TimerStat::CodeTimer xplainTimer(d_statistics.d_xplainTime);
+  Assert (confl.getNumChildren() > 2);
+  std::vector<TNode> conflict;
+  for (unsigned i = 0; i < confl.getNumChildren(); ++i) {
+    conflict.push_back(confl[i]);
+  }
+  d_solver->popToZero();
+  std::vector<TNode> minimized;
+  minimizeConflictInternal(0, conflict.size() - 1, conflict, minimized);
+
+  double minimization_ratio = ((double) minimized.size())/confl.getNumChildren();
+  d_minRatioSum+= minimization_ratio;
+  
+
+  // if (minimization_ratio >= d_hardThresh) {
+  //   d_period = d_period * 5; 
+  // }
+
+  // if (minimization_ratio <= d_thresh && d_period >= 40) {
+  //   d_period = d_period *0.5; 
+  // }
+
+  // if (1.5* d_statistics.d_numUnknown.getData() > d_statistics.d_numSolved.getData()) {
+  //   d_period = d_period * 2;
+  // }
+  d_statistics.d_avgMinimizationRatio.addEntry(minimization_ratio);
+  return utils::mkAnd(minimized); 
+}
+
+QuickXPlain::Statistics::Statistics(const std::string& name)
+  : d_xplainTime("theory::bv::"+name+"::QuickXplain::Time")
+  , d_numSolved("theory::bv::"+name+"::QuickXplain::NumSolved", 0)
+  , d_numUnknown("theory::bv::"+name+"::QuickXplain::NumUnknown", 0)
+  , d_numUnknownWasUnsat("theory::bv::"+name+"::QuickXplain::NumUnknownWasUnsat", 0)
+  , d_numConflictsMinimized("theory::bv::"+name+"::QuickXplain::NumConflictsMinimized", 0)
+  , d_finalPeriod("theory::bv::"+name+"::QuickXplain::FinalPeriod", 0)
+  , d_avgMinimizationRatio("theory::bv::"+name+"::QuickXplain::AvgMinRatio")
+{
+  StatisticsRegistry::registerStat(&d_xplainTime);
+  StatisticsRegistry::registerStat(&d_numSolved);
+  StatisticsRegistry::registerStat(&d_numUnknown);
+  StatisticsRegistry::registerStat(&d_numUnknownWasUnsat);
+  StatisticsRegistry::registerStat(&d_numConflictsMinimized);
+  StatisticsRegistry::registerStat(&d_finalPeriod);
+  StatisticsRegistry::registerStat(&d_avgMinimizationRatio);  
+}
+
+QuickXPlain::Statistics::~Statistics() {
+  StatisticsRegistry::unregisterStat(&d_xplainTime);
+  StatisticsRegistry::unregisterStat(&d_numSolved);
+  StatisticsRegistry::unregisterStat(&d_numUnknown);
+  StatisticsRegistry::unregisterStat(&d_numUnknownWasUnsat);
+  StatisticsRegistry::unregisterStat(&d_numConflictsMinimized);
+  StatisticsRegistry::unregisterStat(&d_finalPeriod);
+  StatisticsRegistry::unregisterStat(&d_avgMinimizationRatio);  
+}
+
diff --git a/src/theory/bv/bv_quick_check.h b/src/theory/bv/bv_quick_check.h
new file mode 100644 (file)
index 0000000..c09994c
--- /dev/null
@@ -0,0 +1,179 @@
+/*********************                                                        */
+/*! \file bv_quick_check.h
+ ** \verbatim
+ ** Original author: Liana Hadarean
+ ** Major contributors: none
+ ** 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 Sandboxed sat solver for bv quickchecks.
+ **
+ ** Sandboxed sat solver for bv quickchecks.
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef __CVC4__BV_QUICK_CHECK_H
+#define __CVC4__BV_QUICK_CHECK_H
+
+#include <vector>
+#include <ext/hash_map>
+
+#include "expr/node.h"
+#include "context/cdo.h"
+#include "prop/sat_solver_types.h"
+#include "util/statistics_registry.h"
+
+namespace CVC4 {
+namespace theory {
+
+class TheoryModel;
+
+namespace bv {
+
+
+
+typedef __gnu_cxx::hash_set<Node, NodeHashFunction> NodeSet;
+typedef __gnu_cxx::hash_set<TNode, TNodeHashFunction> TNodeSet;
+
+class TLazyBitblaster; 
+class TheoryBV;
+
+class BVQuickCheck {
+  context::Context* d_ctx;
+  TLazyBitblaster* d_bitblaster;
+  Node d_conflict;
+  context::CDO<bool> d_inConflict;
+  void setConflict();
+
+public:
+  BVQuickCheck(const std::string& name, theory::bv::TheoryBV* bv);
+  ~BVQuickCheck();
+  bool inConflict();
+  Node getConflict() { return d_conflict; }
+  /** 
+   * Checks the satisfiability for a given set of assumptions.
+   * 
+   * @param assumptions literals assumed true
+   * @param budget max number of conflicts
+   * 
+   * @return 
+   */
+  prop::SatValue checkSat(std::vector<Node>& assumptions, unsigned long budget);
+  /** 
+   * Checks the satisfiability of given assertions.
+   * 
+   * @param budget max number of conflicts
+   * 
+   * @return 
+   */
+  prop::SatValue checkSat(unsigned long budget);
+  
+  /** 
+   * Convert to CNF and assert the given literal.
+   * 
+   * @param assumption bv literal
+   * 
+   * @return false if a conflict has been found via bcp.
+   */
+  bool addAssertion(TNode assumption);
+
+  void push();
+  void pop();
+  void popToZero();
+  /** 
+   * Deletes the SAT solver and CNF stream, but maintains the
+   * bit-blasting term cache. 
+   * 
+   */
+  void clearSolver(); 
+
+  /** 
+   * Computes the size of the circuit required to bit-blast
+   * atom, by not recounting the nodes in seen. 
+   * 
+   * @param node 
+   * @param seen 
+   * 
+   * @return 
+   */
+  uint64_t computeAtomWeight(TNode atom, NodeSet& seen);
+  void collectModelInfo(theory::TheoryModel* model, bool fullModel); 
+
+  typedef __gnu_cxx::hash_set<TNode, TNodeHashFunction>::const_iterator vars_iterator;
+  vars_iterator beginVars(); 
+  vars_iterator endVars(); 
+
+  Node getVarValue(TNode var); 
+
+};
+
+
+class QuickXPlain {
+  struct Statistics {
+    TimerStat d_xplainTime;
+    IntStat d_numSolved;
+    IntStat d_numUnknown;
+    IntStat d_numUnknownWasUnsat;
+    IntStat d_numConflictsMinimized;
+    IntStat d_finalPeriod;
+    AverageStat d_avgMinimizationRatio;
+    Statistics(const std::string&);
+    ~Statistics();
+  };
+  BVQuickCheck* d_solver;
+  unsigned long d_budget;
+
+  // crazy heuristic variables
+  unsigned d_numCalled; // number of times called
+  double d_minRatioSum; // sum of minimization ratio for computing average min ratio  
+  unsigned d_numConflicts; // number of conflicts (including when minimization not applied)
+  unsigned d_period; // after how many conflicts to try minimizing again
+
+  double d_thresh; // if minimization ratio is less, increase period
+  double d_hardThresh; // decrease period if minimization ratio is greater than this
+  
+  
+  Statistics d_statistics;
+  /** 
+   * Uses solve with assumptions unsat core feature to
+   * further minimize a conflict. The minimized conflict
+   * will be between low and the returned value in conflict.
+   * 
+   * @param low 
+   * @param high 
+   * @param conflict 
+   * 
+   * @return 
+   */
+  unsigned selectUnsatCore(unsigned low, unsigned high,
+                           std::vector<TNode>& conflict);
+  /** 
+   * Internal conflict  minimization, attempts to minimize
+   * literals in conflict between low and high and adds the
+   * result in new_conflict. 
+   * 
+   * @param low 
+   * @param high 
+   * @param conflict 
+   * @param new_conflict 
+   */
+  void minimizeConflictInternal(unsigned low, unsigned high,
+                                std::vector<TNode>& conflict,
+                                std::vector<TNode>& new_conflict);
+
+  bool useHeuristic();
+public:
+  QuickXPlain(const std::string& name, BVQuickCheck* solver, unsigned long budged = 10000);
+  ~QuickXPlain();
+  Node minimizeConflict(TNode conflict); 
+};
+
+} /* bv namespace */
+} /* theory namespace */
+} /* CVC4 namespace */
+
+#endif /* __CVC4__BV_QUICK_CHECK_H */
index 5a46f7a0fc2698df8e980345603485b4cef04313..8d21734db15ba8719f9e9d325d51123d852f9a4b 100644 (file)
@@ -9,16 +9,15 @@
  ** See the file COPYING in the top-level source directory for licensing
  ** information.\endverbatim
  **
- ** \brief Algebraic solver.
+ ** \brief Interface for bit-vectors sub-solvers.
  **
- ** Algebraic solver.
+ ** Interface for bit-vectors sub-solvers.
  **/
 
-#include "cvc4_private.h"
-
 #ifndef __CVC4__THEORY__BV__BV_SUBTHEORY_H
 #define __CVC4__THEORY__BV__BV_SUBTHEORY_H
 
+#include "cvc4_private.h"
 #include "context/context.h"
 #include "context/cdqueue.h"
 #include "theory/uf/equality_engine.h"
@@ -34,7 +33,8 @@ namespace bv {
 enum SubTheory {
   SUB_CORE = 1,
   SUB_BITBLAST = 2,
-  SUB_INEQUALITY = 3
+  SUB_INEQUALITY = 3,
+  SUB_ALGEBRAIC = 4
 };
 
 inline std::ostream& operator << (std::ostream& out, SubTheory subtheory) {
@@ -47,6 +47,8 @@ inline std::ostream& operator << (std::ostream& out, SubTheory subtheory) {
     break;
   case SUB_INEQUALITY:
     out << "BV_INEQUALITY_SUBTHEORY";
+  case SUB_ALGEBRAIC:
+    out << "BV_ALGEBRAIC_SUBTHEORY";
   default:
     Unreachable();
     break;
@@ -100,6 +102,8 @@ public:
     return res;
   }
   virtual void assertFact(TNode fact) { d_assertionQueue.push_back(fact); }
+  AssertionQueue::const_iterator assertionsBegin() { return d_assertionQueue.begin(); }
+  AssertionQueue::const_iterator assertionsEnd() { return d_assertionQueue.end(); }
 };
 
 }
diff --git a/src/theory/bv/bv_subtheory_algebraic.cpp b/src/theory/bv/bv_subtheory_algebraic.cpp
new file mode 100644 (file)
index 0000000..0b65ea0
--- /dev/null
@@ -0,0 +1,948 @@
+/*********************                                                        */
+/*! \file bv_subtheory_bitblast.cpp
+** \verbatim
+** Original author: Liana Hadarean 
+** Major contributors: none
+** 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 Algebraic solver.
+**
+** Algebraic solver.
+**/
+#include "util/boolean_simplification.h"
+#include "theory/theory_model.h"
+
+#include "theory/bv/options.h"
+#include "theory/bv/theory_bv.h"
+#include "theory/bv/bv_subtheory_algebraic.h"
+#include "theory/bv/bv_quick_check.h"
+#include "theory/bv/theory_bv_utils.h"
+
+
+using namespace std;
+using namespace CVC4;
+using namespace CVC4::context;
+using namespace CVC4::prop;
+using namespace CVC4::theory;
+using namespace CVC4::theory::bv;
+using namespace CVC4::theory::bv::utils;
+
+bool hasExpensiveBVOperators(TNode fact);
+
+SubstitutionEx::SubstitutionEx(theory::SubstitutionMap* modelMap)
+  : d_substitutions()
+  , d_cache()
+  , d_cacheInvalid(true)
+  , d_modelMap(modelMap)
+{}
+
+void SubstitutionEx::addSubstitution(TNode from, TNode to, TNode reason) {
+  Debug("bv-substitution") << "SubstitutionEx::addSubstitution: "<< from <<" => "<< to <<"\n";
+  Debug("bv-substitution") << " reason "<<reason << "\n";
+  
+  d_modelMap->addSubstitution(from, to); 
+
+  d_cacheInvalid = true;
+  Assert (from != to);
+  Assert (d_substitutions.find(from) == d_substitutions.end());
+  d_substitutions[from] = SubstitutionElement(to, reason);
+}
+
+Node SubstitutionEx::apply(TNode node) {
+  Debug("bv-substitution") << "SubstitutionEx::apply("<< node <<")\n";
+  if (d_cacheInvalid) {
+    d_cache.clear();
+    d_cacheInvalid = false;
+  }
+
+  SubstitutionsCache::iterator it = d_cache.find(node);
+
+  if (it != d_cache.end()) {
+    Node res = it->second.to;
+    Debug("bv-substitution") << "   =>"<< res <<"\n";
+    return res;
+  }
+
+  Node result = internalApply(node);
+  Debug("bv-substitution") << "   =>"<< result <<"\n";
+  return result;
+}
+
+Node SubstitutionEx::internalApply(TNode node) {
+  if (d_substitutions.empty())
+    return node;
+
+  vector<SubstitutionStackElement> stack;
+  stack.push_back(SubstitutionStackElement(node));
+
+  while (!stack.empty()) {
+    SubstitutionStackElement head = stack.back();
+    stack.pop_back();
+    
+    TNode current = head.node;
+
+    if (hasCache(current)) {
+      continue;
+    }
+
+    // check if it has substitution
+    Substitutions::const_iterator it = d_substitutions.find(current);
+    if (it != d_substitutions.end()) {
+      vector<Node> reasons;
+      TNode to = it->second.to;
+      reasons.push_back(it->second.reason);
+      // check if the thing we subsituted to has substitutions
+      TNode res = internalApply(to);
+      // update reasons
+      reasons.push_back(getReason(to));
+      Node reason = mergeExplanations(reasons);
+      storeCache(current, res, reason);
+      continue;
+    }
+
+    // if no children then just continue
+    if(current.getNumChildren() == 0) {
+      storeCache(current, current, utils::mkTrue());
+      continue;
+    }
+    
+    // children already processed 
+    if (head.childrenAdded) {
+      NodeBuilder<> nb(current.getKind());
+      std::vector<Node> reasons;
+      
+      if (current.getMetaKind() == kind::metakind::PARAMETERIZED) {
+        TNode op = current.getOperator();
+        Assert (hasCache(op));
+        nb << getCache(op);
+        reasons.push_back(getReason(op));
+      }
+      for (unsigned i = 0; i < current.getNumChildren(); ++i) {
+        Assert (hasCache(current[i]));
+        nb << getCache(current[i]);
+        reasons.push_back(getReason(current[i]));
+      }
+      Node result = nb;
+      // if the node is new apply substitutions to it
+      Node subst_result = result;
+      if (result != current) {
+        subst_result = result!= current? internalApply(result) : result;
+        reasons.push_back(getReason(result));
+      }
+      Node reason = mergeExplanations(reasons);
+      storeCache(current, subst_result, reason);
+      continue;
+    } else {
+      // add children to stack
+      stack.push_back(SubstitutionStackElement(current, true));
+      if (current.getMetaKind() == kind::metakind::PARAMETERIZED) {
+        stack.push_back(SubstitutionStackElement(current.getOperator()));
+      }
+      for (unsigned i = 0; i < current.getNumChildren(); ++i) {
+        stack.push_back(SubstitutionStackElement(current[i]));
+      }
+    }
+  }
+
+  Assert(hasCache(node));
+  return getCache(node);
+}
+
+Node SubstitutionEx::explain(TNode node) const {
+  if(!hasCache(node))
+    return utils::mkTrue();
+  
+  Debug("bv-substitution") << "SubstitutionEx::explain("<< node <<")\n";
+  Node res = getReason(node);
+  Debug("bv-substitution") << "  with "<< res <<"\n";
+  return res;
+}
+
+Node SubstitutionEx::getReason(TNode node) const {
+  Assert(hasCache(node));
+  SubstitutionsCache::const_iterator it = d_cache.find(node);
+  return it->second.reason;
+}
+
+bool SubstitutionEx::hasCache(TNode node) const {
+  return d_cache.find(node) != d_cache.end();
+}
+
+Node SubstitutionEx::getCache(TNode node) const {
+  Assert (hasCache(node));
+  return d_cache.find(node)->second.to;
+}
+
+void SubstitutionEx::storeCache(TNode from, TNode to, Node reason) {
+  //  Debug("bv-substitution") << "SubstitutionEx::storeCache(" << from <<", " << to <<", "<< reason<<")\n"; 
+  Assert (!hasCache(from));
+  d_cache[from] = SubstitutionElement(to, reason);
+}
+
+AlgebraicSolver::AlgebraicSolver(context::Context* c, TheoryBV* bv)
+  : SubtheorySolver(c, bv)
+  , d_modelMap(NULL)
+  , d_quickSolver(new BVQuickCheck("alg", bv))
+  , d_isComplete(c, false)
+  , d_isDifficult(c, false)
+  , d_budget(options::bitvectorAlgebraicBudget())
+  , d_explanations()
+  , d_ctx(new context::Context())
+  , d_quickXplain(options::bitvectorQuickXplain() ? new QuickXPlain("alg", d_quickSolver) : NULL)
+  , d_statistics()
+{}
+
+AlgebraicSolver::~AlgebraicSolver() {
+  delete d_quickXplain;
+  delete d_quickSolver;
+  delete d_ctx;
+}
+
+
+
+bool AlgebraicSolver::check(Theory::Effort e) {
+  Assert(options::bitblastMode() == theory::bv::BITBLAST_MODE_LAZY); 
+
+  if (!Theory::fullEffort(e))
+    return true;
+
+  if (!useHeuristic())
+    return true;
+  
+  ++(d_numCalls);
+  
+  TimerStat::CodeTimer algebraicTimer(d_statistics.d_solveTime);
+  Debug("bv-subtheory-algebraic") << "AlgebraicSolver::check (" << e << ")\n";
+  ++(d_statistics.d_numCallstoCheck);
+
+  d_explanations.clear();
+  d_ids.clear(); 
+  d_inputAssertions.clear(); 
+
+  std::vector<WorklistElement> worklist;
+
+  uint64_t original_bb_cost = 0;
+
+  NodeSet seen_assertions;
+  // Processing assertions from scratch
+  for (AssertionQueue::const_iterator it = assertionsBegin(); it != assertionsEnd(); ++it) {
+    Debug("bv-subtheory-algebraic") << "   " << *it << "\n";
+    TNode assertion = *it;
+    unsigned id = worklist.size();
+    d_ids[assertion] = id; 
+    worklist.push_back(WorklistElement(assertion, id));
+    d_inputAssertions.insert(assertion); 
+    storeExplanation(assertion);
+
+    uint64_t assertion_size = d_quickSolver->computeAtomWeight(assertion, seen_assertions);
+    Assert (original_bb_cost <= original_bb_cost + assertion_size);
+    original_bb_cost+= assertion_size; 
+  }
+
+  for (unsigned i = 0; i < worklist.size(); ++i) {
+    d_ids[worklist[i].node] = worklist[i].id;
+  }
+  
+  Debug("bv-subtheory-algebraic") << "Assertions " << worklist.size() <<" : \n";
+
+  Assert (d_explanations.size() == worklist.size()); 
+
+  delete d_modelMap;
+  d_modelMap = new SubstitutionMap(d_context);
+  SubstitutionEx subst(d_modelMap);
+
+  // first round of substitutions
+  processAssertions(worklist, subst); 
+
+  if (!d_isDifficult.get()) {
+    // skolemize all possible extracts
+    ExtractSkolemizer skolemizer(d_modelMap);
+    skolemizer.skolemize(worklist);
+    // second round of substitutions
+    processAssertions(worklist, subst); 
+  }
+  
+  NodeSet subst_seen;
+  uint64_t subst_bb_cost = 0;
+
+  unsigned r = 0;
+  unsigned w = 0;
+
+  for (; r < worklist.size(); ++r) {
+
+    TNode fact = worklist[r].node;
+    unsigned id = worklist[r].id;
+    
+    if (Dump.isOn("bv-algebraic")) {
+      Node expl = d_explanations[id];
+      Node query = utils::mkNot(utils::mkNode(kind::IMPLIES, expl, fact));
+      Dump("bv-algebraic") << EchoCommand("ThoeryBV::AlgebraicSolver::substitution explanation"); 
+      Dump("bv-algebraic") << PushCommand(); 
+      Dump("bv-algebraic") << AssertCommand(query.toExpr());
+      Dump("bv-algebraic") << CheckSatCommand();
+      Dump("bv-algebraic") << PopCommand(); 
+    }
+
+    if (fact.isConst() &&
+        fact.getConst<bool>() == true) {
+      continue;
+    }
+
+    if (fact.isConst() &&
+        fact.getConst<bool>() == false) {
+      // we have a conflict
+      Node conflict = BooleanSimplification::simplify(d_explanations[id]);
+      d_bv->setConflict(conflict);
+      d_isComplete.set(true);
+      Debug("bv-subtheory-algebraic") << " UNSAT: assertion simplfies to false with conflict: "<< conflict << "\n";
+       
+      if (Dump.isOn("bv-algebraic")) {
+        Dump("bv-algebraic") << EchoCommand("TheoryBV::AlgebraicSolver::conflict"); 
+        Dump("bv-algebraic") << PushCommand(); 
+        Dump("bv-algebraic") << AssertCommand(conflict.toExpr());
+        Dump("bv-algebraic") << CheckSatCommand();
+        Dump("bv-algebraic") << PopCommand(); 
+      }
+
+      
+      ++(d_statistics.d_numSimplifiesToFalse);
+      ++(d_numSolved);
+      return false;
+    }
+
+    subst_bb_cost+= d_quickSolver->computeAtomWeight(fact, subst_seen);
+    worklist[w] = WorklistElement(fact, id);
+    Node expl =  BooleanSimplification::simplify(d_explanations[id]);
+    storeExplanation(id, expl);
+    d_ids[fact] = id;
+    ++w;
+  }
+
+  worklist.resize(w);
+
+  
+  if(Debug.isOn("bv-subtheory-algebraic")) {
+    Debug("bv-subtheory-algebraic") << "Assertions post-substitutions " << worklist.size() << ":\n";
+    for (unsigned i = 0; i < worklist.size(); ++i) {
+      Debug("bv-subtheory-algebraic") << "   " << worklist[i].node << "\n";
+    }
+  }
+
+  
+  // all facts solved to true
+  if (worklist.empty()) {
+    Debug("bv-subtheory-algebraic") << " SAT: everything simplifies to true.\n";
+    ++(d_statistics.d_numSimplifiesToTrue);
+    ++(d_numSolved);
+    return true;
+  }
+
+  double ratio = ((double)subst_bb_cost)/original_bb_cost;
+  if (ratio > 0.5 ||
+      !d_isDifficult.get()) {
+    // give up if problem not reduced enough
+    d_isComplete.set(false);
+    return true;
+  }
+  
+  d_quickSolver->clearSolver();
+
+  d_quickSolver->push();
+  std::vector<Node> facts;
+  for (unsigned i = 0; i < worklist.size(); ++i) {
+    facts.push_back(worklist[i].node); 
+  }
+  bool ok = quickCheck(facts);
+
+  Debug("bv-subtheory-algebraic") << "AlgebraicSolver::check done " << ok << ".\n";
+  return ok;
+}
+
+bool AlgebraicSolver::quickCheck(std::vector<Node>& facts) {
+  SatValue res = d_quickSolver->checkSat(facts, d_budget);
+
+  if (res == SAT_VALUE_UNKNOWN) {
+    d_isComplete.set(false);
+    Debug("bv-subtheory-algebraic") << " Unknown.\n";
+    ++(d_statistics.d_numUnknown);
+    return true;
+  }
+  
+  if (res == SAT_VALUE_TRUE) {
+    Debug("bv-subtheory-algebraic") << " Sat.\n";
+    ++(d_statistics.d_numSat);
+    ++(d_numSolved);
+    d_isComplete.set(true);
+    return true;
+  }
+
+  Assert (res == SAT_VALUE_FALSE);
+  Assert (d_quickSolver->inConflict());  
+  d_isComplete.set(true);
+  
+  Debug("bv-subtheory-algebraic") << " Unsat.\n";
+  ++(d_numSolved);
+  ++(d_statistics.d_numUnsat);
+
+  
+  Node conflict = d_quickSolver->getConflict();
+  Debug("bv-subtheory-algebraic") << " Conflict: " << conflict << "\n";
+
+  // singleton conflict
+  if (conflict.getKind() != kind::AND) {
+    Assert (d_ids.find(conflict) != d_ids.end());
+    unsigned id = d_ids[conflict]; 
+    Assert (id < d_explanations.size()); 
+    Node theory_confl = d_explanations[id];
+    d_bv->setConflict(theory_confl);
+    return false;
+  }
+
+  Assert (conflict.getKind() == kind::AND);
+  if (options::bitvectorQuickXplain()) {
+    d_quickSolver->popToZero();
+    Debug("bv-quick-xplain") << "AlgebraicSolver::quickCheck original conflict size " << conflict.getNumChildren() << "\n";
+    conflict = d_quickXplain->minimizeConflict(conflict);
+    Debug("bv-quick-xplain") << "AlgebraicSolver::quickCheck minimized conflict size " << conflict.getNumChildren() << "\n";
+  }
+  
+  vector<TNode> theory_confl;
+  for (unsigned i = 0; i < conflict.getNumChildren(); ++i) {
+    TNode c = conflict[i];
+
+    Assert (d_ids.find(c) != d_ids.end()); 
+    unsigned c_id = d_ids[c];
+    Assert (c_id < d_explanations.size());
+    TNode c_expl = d_explanations[c_id];
+    theory_confl.push_back(c_expl);
+  }
+  
+  Node confl = BooleanSimplification::simplify(utils::mkAnd(theory_confl));
+
+  Debug("bv-subtheory-algebraic") << " Out Conflict: " << confl << "\n";
+  setConflict(confl);
+  return false;
+}
+
+void AlgebraicSolver::setConflict(TNode conflict) {
+  Node final_conflict = conflict;
+  if (options::bitvectorQuickXplain() &&
+      conflict.getKind() == kind::AND &&
+      conflict.getNumChildren() > 4) {
+    final_conflict = d_quickXplain->minimizeConflict(conflict);
+  }
+  d_bv->setConflict(final_conflict);
+}
+
+bool AlgebraicSolver::solve(TNode fact, TNode reason, SubstitutionEx& subst) {
+  if (fact.getKind() != kind::EQUAL) return false;
+
+  TNode left = fact[0];
+  TNode right = fact[1];
+
+  
+  if (left.isVar() && !right.hasSubterm(left)) {
+    subst.addSubstitution(left, right, reason);
+    return true;
+  }
+  if (right.isVar() && !left.hasSubterm(right)) {
+    subst.addSubstitution(right, left, reason);
+    return true;
+  }
+
+  // xor simplification
+  if (right.getKind() == kind::BITVECTOR_XOR &&
+      left.getKind() == kind::BITVECTOR_XOR) {
+    TNode var = left[0];
+    if (!var.getMetaKind() == kind::metakind::VARIABLE)
+      return false; 
+
+    // simplify xor with same variable on both sides
+    if (right.hasSubterm(var)) {
+      std::vector<Node> right_children;
+      for (unsigned i = 0; i < right.getNumChildren(); ++i) {
+        if (right[i] != var)
+          right_children.push_back(right[i]); 
+      }
+      Assert (right_children.size());
+      Node new_right = right_children.size() > 1 ? utils::mkNode(kind::BITVECTOR_XOR, right_children)
+                                                 : right_children[0];
+      std::vector<Node> left_children;
+      for (unsigned i = 1; i < left.getNumChildren(); ++i) {
+        left_children.push_back(left[i]);
+      }
+      Node new_left = left_children.size() > 1 ? utils::mkNode(kind::BITVECTOR_XOR, left_children)
+                                               : left_children[0];
+      Node new_fact = utils::mkNode(kind::EQUAL, new_left, new_right);
+      subst.addSubstitution(fact, new_fact, reason);
+      return true;
+    }
+    
+    NodeBuilder<> nb(kind::BITVECTOR_XOR);
+    for (unsigned i = 1; i < left.getNumChildren(); ++i) {
+      nb << left[i];
+    }
+    Node inverse = left.getNumChildren() == 2? (Node)left[1] : (Node)nb;
+    Node new_right = utils::mkNode(kind::BITVECTOR_XOR, right, inverse);
+    subst.addSubstitution(var, new_right, reason);
+
+    if (Dump.isOn("bv-algebraic")) {
+      Node query = utils::mkNot(utils::mkNode(kind::IFF, fact, utils::mkNode(kind::EQUAL, var, new_right)));
+      Dump("bv-algebraic") << EchoCommand("ThoeryBV::AlgebraicSolver::substitution explanation"); 
+      Dump("bv-algebraic") << PushCommand(); 
+      Dump("bv-algebraic") << AssertCommand(query.toExpr());
+      Dump("bv-algebraic") << CheckSatCommand();
+      Dump("bv-algebraic") << PopCommand(); 
+    }
+
+    
+    return true;
+  }
+
+  // (a xor t = a) <=> (t = 0)
+  if (left.getKind() == kind::BITVECTOR_XOR &&
+      right.getMetaKind() == kind::metakind::VARIABLE &&
+      left.hasSubterm(right)) {
+    TNode var = right;
+    Node new_left = utils::mkNode(kind::BITVECTOR_XOR, var, left);
+    Node zero = utils::mkConst(utils::getSize(var), 0u);
+    Node new_fact = utils::mkNode(kind::EQUAL, zero, new_left);
+    subst.addSubstitution(fact, new_fact, reason);
+    return true; 
+  }
+  
+  if (right.getKind() == kind::BITVECTOR_XOR &&
+      left.getMetaKind() == kind::metakind::VARIABLE &&
+      right.hasSubterm(left)) {
+    TNode var = left;
+    Node new_right = utils::mkNode(kind::BITVECTOR_XOR, var, right);
+    Node zero = utils::mkConst(utils::getSize(var), 0u);
+    Node new_fact = utils::mkNode(kind::EQUAL, zero, new_right);
+    subst.addSubstitution(fact, new_fact, reason);
+    return true; 
+  }
+
+  // (a xor b = 0) <=> (a = b)
+  if (left.getKind() == kind::BITVECTOR_XOR &&
+      left.getNumChildren() == 2 &&
+      right.getKind() == kind::CONST_BITVECTOR &&
+      right.getConst<BitVector>() == BitVector(utils::getSize(left), 0u)) {
+    Node new_fact = utils::mkNode(kind::EQUAL, left[0], left[1]);
+    subst.addSubstitution(fact, new_fact, reason);
+    return true; 
+  }
+  
+
+  return false;
+} 
+
+bool AlgebraicSolver::isSubstitutableIn(TNode node, TNode in) {
+  if (node.getMetaKind() == kind::metakind::VARIABLE &&
+      !in.hasSubterm(node))
+    return true;
+  return false; 
+}
+
+void AlgebraicSolver::processAssertions(std::vector<WorklistElement>& worklist, SubstitutionEx& subst) {
+  bool changed = true;
+  while(changed) {
+    changed = false;
+    for (unsigned i = 0; i < worklist.size(); ++i) {
+      // apply current substitutions
+      Node current = subst.apply(worklist[i].node);
+      unsigned current_id = worklist[i].id;
+      Node subst_expl = subst.explain(worklist[i].node);
+      worklist[i] = WorklistElement(Rewriter::rewrite(current), current_id);
+      // explanation for this assertion
+      Node old_expl = d_explanations[current_id];
+      Node new_expl = mergeExplanations(subst_expl, old_expl); 
+      storeExplanation(current_id, new_expl);
+      
+      // use the new substitution to solve
+      if(solve(worklist[i].node, new_expl, subst)) {
+        changed = true;
+      }
+    }
+
+    // check for concat slicings
+    for (unsigned i = 0; i < worklist.size(); ++i) {
+      TNode fact = worklist[i].node;
+      unsigned current_id = worklist[i].id;
+      
+      if (fact.getKind() != kind::EQUAL)
+        continue;
+
+      TNode left = fact[0];
+      TNode right = fact[1];
+      if (left.getKind() != kind::BITVECTOR_CONCAT ||
+          right.getKind() != kind::BITVECTOR_CONCAT ||
+          left.getNumChildren() != right.getNumChildren())
+        continue;
+
+      bool can_slice = true;
+      for (unsigned j = 0; j < left.getNumChildren(); ++j) {
+        if (utils::getSize(left[j]) != utils::getSize(right[j]))
+          can_slice = false;
+      }
+      
+      if (!can_slice)
+        continue; 
+      
+      for (unsigned j = 0; j < left.getNumChildren(); ++j) {
+        Node eq_j = utils::mkNode(kind::EQUAL, left[j], right[j]);
+        unsigned id = d_explanations.size();
+        TNode expl = d_explanations[current_id];
+        storeExplanation(expl);
+        worklist.push_back(WorklistElement(eq_j, id));
+        d_ids[eq_j] = id; 
+      }
+      worklist[i] = WorklistElement(utils::mkTrue(), worklist[i].id);
+      changed = true;
+    }
+    Assert (d_explanations.size() == worklist.size()); 
+  }
+}
+
+void AlgebraicSolver::storeExplanation(unsigned id, TNode explanation) {
+  Assert (checkExplanation(explanation)); 
+  d_explanations[id] = explanation;
+}
+
+void AlgebraicSolver::storeExplanation(TNode explanation) {
+  Assert (checkExplanation(explanation));
+  d_explanations.push_back(explanation); 
+}
+
+bool AlgebraicSolver::checkExplanation(TNode explanation) {
+  Node simplified_explanation = explanation; //BooleanSimplification::simplify(explanation);
+  if (simplified_explanation.getKind() != kind::AND) {
+    return d_inputAssertions.find(simplified_explanation) != d_inputAssertions.end();
+  }
+  for (unsigned i = 0; i < simplified_explanation.getNumChildren(); ++i) {
+    if (d_inputAssertions.find(simplified_explanation[i]) == d_inputAssertions.end()) {
+      return false;
+    }
+  }
+  return true; 
+}
+
+
+bool AlgebraicSolver::isComplete() {
+  return d_isComplete.get(); 
+}
+
+bool AlgebraicSolver::useHeuristic() {
+  if (d_numCalls == 0)
+    return true;
+  
+  double success_rate = d_numSolved/d_numCalls;
+  d_statistics.d_useHeuristic.setData(success_rate);
+  return success_rate > 0.8;
+}
+
+
+void AlgebraicSolver::assertFact(TNode fact) {
+  d_assertionQueue.push_back(fact);
+  if (!d_isDifficult.get()) {
+    d_isDifficult.set(hasExpensiveBVOperators(fact));
+  }
+}
+
+EqualityStatus AlgebraicSolver::getEqualityStatus(TNode a, TNode b) {
+  return EQUALITY_UNKNOWN;
+}
+void AlgebraicSolver::collectModelInfo(TheoryModel* model, bool fullModel) {
+  Debug("bv-subtheory-algebraic-models") << "AlgebraicSolver::collectModelInfo\n"; 
+  AlwaysAssert (!d_quickSolver->inConflict());
+  set<Node> termSet;
+  d_bv->computeRelevantTerms(termSet);
+
+  // collect relevant terms that the bv theory abstracts to variables
+  // (variables and parametric terms such as select apply_uf)
+  std::vector<TNode> variables;
+  std::vector<Node> values;
+  for (set<Node>::const_iterator it = termSet.begin(); it != termSet.end(); ++it) {
+    TNode term = *it; 
+    if (term.getType().isBitVector() &&
+        (term.getMetaKind() == kind::metakind::VARIABLE ||
+         Theory::theoryOf(term) != THEORY_BV)) {
+      variables.push_back(term);
+      values.push_back(term);
+    }
+  }
+
+  Debug("bv-subtheory-algebraic-models") << "Substitutions:\n";
+  for (unsigned i = 0; i < variables.size(); ++i) {
+    TNode current = variables[i];
+    TNode subst = Rewriter::rewrite(d_modelMap->apply(current));
+    Debug("bv-subtheory-algebraic-models") << "   " << current << " => " << subst << "\n";
+    values[i] = subst;
+  }
+
+  Debug("bv-subtheory-algebraic-models") << "Model:\n";
+  for (BVQuickCheck::vars_iterator it = d_quickSolver->beginVars(); it != d_quickSolver->endVars(); ++it) {
+    TNode var = *it;
+    Node value = d_quickSolver->getVarValue(var);
+    Debug("bv-subtheory-algebraic-models") << "   " << var << " => " << value << "\n";
+    Assert (value.getKind() == kind::CONST_BITVECTOR); 
+    d_modelMap->addSubstitution(var, value); 
+  }
+
+  Debug("bv-subtheory-algebraic-models") << "Final Model:\n";
+  for (unsigned i = 0; i < variables.size(); ++i) {
+    TNode current = values[i];
+    TNode subst = Rewriter::rewrite(d_modelMap->apply(current));
+    Debug("bv-subtheory-algebraic-models") << "   " << variables[i] << " => " << subst << "\n"; 
+    // Doesn't have to be constant as it may be irrelevant
+    // Assert (subst.getKind() == kind::CONST_BITVECTOR); 
+    model->assertEquality(variables[i], subst, true);
+  }
+
+ }
+
+Node AlgebraicSolver::getModelValue(TNode node) {
+  return Node::null(); 
+}
+
+AlgebraicSolver::Statistics::Statistics()
+  : d_numCallstoCheck("theory::bv::AlgebraicSolver::NumCallsToCheck", 0)
+  , d_numSimplifiesToTrue("theory::bv::AlgebraicSolver::NumSimplifiesToTrue", 0)
+  , d_numSimplifiesToFalse("theory::bv::AlgebraicSolver::NumSimplifiesToFalse", 0)
+  , d_numUnsat("theory::bv::AlgebraicSolver::NumUnsat", 0)
+  , d_numSat("theory::bv::AlgebraicSolver::NumSat", 0)
+  , d_numUnknown("theory::bv::AlgebraicSolver::NumUnknown", 0)
+  , d_solveTime("theory::bv::AlgebraicSolver::SolveTime")
+  , d_useHeuristic("theory::bv::AlgebraicSolver::UseHeuristic", 0.2)
+{
+  StatisticsRegistry::registerStat(&d_numCallstoCheck);
+  StatisticsRegistry::registerStat(&d_numSimplifiesToTrue);
+  StatisticsRegistry::registerStat(&d_numSimplifiesToFalse);
+  StatisticsRegistry::registerStat(&d_numUnsat);
+  StatisticsRegistry::registerStat(&d_numSat);
+  StatisticsRegistry::registerStat(&d_numUnknown);
+  StatisticsRegistry::registerStat(&d_solveTime);
+  StatisticsRegistry::registerStat(&d_useHeuristic);
+}
+
+AlgebraicSolver::Statistics::~Statistics() {
+  StatisticsRegistry::unregisterStat(&d_numCallstoCheck);
+  StatisticsRegistry::unregisterStat(&d_numSimplifiesToTrue);
+  StatisticsRegistry::unregisterStat(&d_numSimplifiesToFalse);
+  StatisticsRegistry::unregisterStat(&d_numUnsat);
+  StatisticsRegistry::unregisterStat(&d_numSat);
+  StatisticsRegistry::unregisterStat(&d_numUnknown);
+  StatisticsRegistry::unregisterStat(&d_solveTime);
+  StatisticsRegistry::unregisterStat(&d_useHeuristic);
+}
+
+bool hasExpensiveBVOperatorsRec(TNode fact, TNodeSet& seen) {
+  if (fact.getKind() == kind::BITVECTOR_MULT ||
+      fact.getKind() == kind::BITVECTOR_UDIV_TOTAL ||
+      fact.getKind() == kind::BITVECTOR_UREM_TOTAL) {
+    return true;
+  }
+
+  if (seen.find(fact) != seen.end())
+    return false;
+  
+  if (fact.getNumChildren() == 0)
+    return false;
+  
+  for (unsigned i = 0; i < fact.getNumChildren(); ++i) {
+    bool difficult = hasExpensiveBVOperatorsRec(fact[i], seen);
+    if (difficult)
+      return true;
+  }
+  seen.insert(fact);
+  return false;
+}
+
+bool hasExpensiveBVOperators(TNode fact) {
+  TNodeSet seen;
+  return hasExpensiveBVOperatorsRec(fact, seen);
+}
+
+void ExtractSkolemizer::skolemize(std::vector<WorklistElement>& facts) {
+  TNodeSet seen;
+  for (unsigned i = 0; i < facts.size(); ++i) {
+    TNode current = facts[i].node;
+    collectExtracts(current, seen); 
+  }
+
+  for (VarExtractMap::iterator it = d_varToExtract.begin(); it != d_varToExtract.end(); ++it) {
+    ExtractList& el = it->second;
+    TNode var = it->first; 
+    Base& base = el.base;
+
+    unsigned bw = utils::getSize(var); 
+    // compute decomposition
+    std::vector<unsigned> cuts;
+    for (unsigned i = 1; i <= bw; ++i) {
+      if (base.isCutPoint(i)) {
+        cuts.push_back(i);
+      }
+    }
+    unsigned previous = 0;
+    unsigned current = 0;
+    std::vector<Node> skolems;
+    for (unsigned i = 0; i < cuts.size(); ++i) {
+      current = cuts[i];
+      Assert (current > 0);
+      int size = current - previous;
+      Assert (size > 0);
+      Node sk = utils::mkVar(size);
+      skolems.push_back(sk);
+      previous = current; 
+    }
+    if (current < bw -1) {
+      int size = bw - current;
+      Assert (size > 0);
+      Node sk = utils::mkVar(size);
+      skolems.push_back(sk);
+    }
+    NodeBuilder<> skolem_nb(kind::BITVECTOR_CONCAT);
+
+    for (int i = skolems.size() - 1; i >= 0; --i) {
+      skolem_nb << skolems[i]; 
+    }
+
+    Node skolem_concat = skolems.size() == 1 ? (Node)skolems[0] : (Node) skolem_nb;
+    Assert (utils::getSize(skolem_concat) == utils::getSize(var));
+    storeSkolem(var, skolem_concat);
+
+    for (unsigned i = 0; i < el.extracts.size(); ++i) {
+      unsigned h = el.extracts[i].high;
+      unsigned l = el.extracts[i].low;
+      Node extract = utils::mkExtract(var, h, l);
+      Node skolem_extract = Rewriter::rewrite(utils::mkExtract(skolem_concat, h, l));
+      Assert (skolem_extract.getMetaKind() == kind::metakind::VARIABLE ||
+              skolem_extract.getKind() == kind::BITVECTOR_CONCAT);
+      storeSkolem(extract, skolem_extract); 
+    }
+  }
+  
+  for (unsigned i = 0; i < facts.size(); ++i) {
+    facts[i] = WorklistElement(skolemize(facts[i].node), facts[i].id);
+  }
+}
+
+Node ExtractSkolemizer::mkSkolem(Node node) {
+  Assert (node.getKind() == kind::BITVECTOR_EXTRACT &&
+          node[0].getMetaKind() == kind::metakind::VARIABLE);
+  Assert (!d_skolemSubst.hasSubstitution(node));
+  return utils::mkVar(utils::getSize(node)); 
+}
+
+void ExtractSkolemizer::unSkolemize(std::vector<WorklistElement>& facts) {
+  for (unsigned i = 0; i < facts.size(); ++i) {
+    facts[i] = WorklistElement(unSkolemize(facts[i].node), facts[i].id);
+  }
+}
+
+void ExtractSkolemizer::storeSkolem(TNode node, TNode skolem) {
+  d_skolemSubst.addSubstitution(node, skolem);
+  d_modelMap->addSubstitution(node, skolem); 
+  d_skolemSubstRev.addSubstitution(skolem, node);
+}
+
+Node ExtractSkolemizer::unSkolemize(TNode node) {
+  return d_skolemSubstRev.apply(node); 
+}
+
+Node ExtractSkolemizer::skolemize(TNode node) {
+  return d_skolemSubst.apply(node); 
+}
+
+void ExtractSkolemizer::ExtractList::addExtract(Extract& e) {
+  extracts.push_back(e);
+  base.sliceAt(e.low);
+  base.sliceAt(e.high+1);
+}
+
+void ExtractSkolemizer::storeExtract(TNode var, unsigned high, unsigned low) {
+  Assert (var.getMetaKind() == kind::metakind::VARIABLE);
+  if (d_varToExtract.find(var) == d_varToExtract.end()) {
+    d_varToExtract[var] = ExtractList(utils::getSize(var));
+  }
+  //  std::cout << "extract " << var <<"["<<high<<":"<<low<<"]\n"; 
+  VarExtractMap::iterator it = d_varToExtract.find(var);
+  ExtractList& el = it->second;
+  Extract e(high, low);
+  el.addExtract(e);
+}
+  
+void ExtractSkolemizer::collectExtracts(TNode node, TNodeSet& seen) {
+  if (seen.find(node) != seen.end()) {
+    return;
+  }
+  
+  if (node.getKind() == kind::BITVECTOR_EXTRACT &&
+      node[0].getMetaKind() == kind::metakind::VARIABLE) {
+    unsigned high = utils::getExtractHigh(node);
+    unsigned low = utils::getExtractLow(node);
+    TNode var = node[0];
+    storeExtract(var, high, low);
+    seen.insert(node);
+    return;
+  }
+
+  if (node.getNumChildren() == 0)
+    return;
+
+  for (unsigned i = 0; i < node.getNumChildren(); ++i) {
+    collectExtracts(node[i], seen);
+  }
+  seen.insert(node); 
+}
+
+ExtractSkolemizer::ExtractSkolemizer(theory::SubstitutionMap* modelMap)
+  : d_emptyContext()
+  , d_varToExtract()
+  , d_modelMap(modelMap)
+  , d_skolemSubst(&d_emptyContext)
+  , d_skolemSubstRev(&d_emptyContext)
+{}
+
+ExtractSkolemizer::~ExtractSkolemizer() {
+}
+
+Node CVC4::theory::bv::mergeExplanations(const std::vector<Node>& expls) {
+  TNodeSet literals;
+  for (unsigned i = 0; i < expls.size(); ++i) {
+    TNode expl = expls[i]; 
+    Assert (expl.getType().isBoolean()); 
+    if (expl.getKind() == kind::AND) {
+      for (unsigned i = 0; i < expl.getNumChildren(); ++i) {
+        TNode child = expl[i];
+        if (child == utils::mkTrue())
+          continue;
+        literals.insert(child); 
+      }
+    } else if (expl != utils::mkTrue()) {
+      literals.insert(expl);
+    }
+  }
+  if (literals.size() == 0)
+    return utils::mkTrue();
+
+  if (literals.size() == 1) 
+    return *literals.begin(); 
+  
+  NodeBuilder<> nb(kind::AND); 
+
+  for (TNodeSet::const_iterator it = literals.begin(); it!= literals.end(); ++it) {
+    nb << *it; 
+  }
+  return nb; 
+}
+
+Node CVC4::theory::bv::mergeExplanations(TNode expl1, TNode expl2) {
+  std::vector<Node> expls;
+  expls.push_back(expl1);
+  expls.push_back(expl2);
+  return mergeExplanations(expls); 
+}
diff --git a/src/theory/bv/bv_subtheory_algebraic.h b/src/theory/bv/bv_subtheory_algebraic.h
new file mode 100644 (file)
index 0000000..4acab29
--- /dev/null
@@ -0,0 +1,226 @@
+/*********************                                                        */
+/*! \file bv_subtheory_algebraic.h
+** \verbatim
+** Original author: Liana Hadarean 
+** Major contributors: none
+** 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 Algebraic solver.
+**
+** Algebraic solver.
+**/
+
+#pragma once
+
+#include "cvc4_private.h"
+#include "theory/bv/bv_subtheory.h"
+#include "theory/substitutions.h"
+#include "theory/bv/slicer.h"
+
+namespace CVC4 {
+namespace theory {
+namespace bv {
+
+class AlgebraicSolver;
+
+
+Node mergeExplanations(TNode expl1, TNode expl2);
+Node mergeExplanations(const std::vector<Node>& expls);
+
+
+/**
+ * Non-context dependent substitution with explanations.
+ * 
+ */
+class SubstitutionEx {
+  struct SubstitutionElement {
+    Node to;
+    Node reason;
+    SubstitutionElement()
+      : to()
+      , reason()
+    {}
+    
+    SubstitutionElement(TNode t, TNode r)
+      : to(t)
+      , reason(r)
+    {}
+  };
+
+  struct SubstitutionStackElement {
+    TNode node;
+    bool childrenAdded;
+    SubstitutionStackElement(TNode n, bool ca = false)
+      : node(n)
+      , childrenAdded(ca)
+    {}
+  };
+
+  typedef __gnu_cxx::hash_map<Node, SubstitutionElement, NodeHashFunction> Substitutions;
+  typedef __gnu_cxx::hash_map<Node, SubstitutionElement, NodeHashFunction> SubstitutionsCache;
+
+  Substitutions d_substitutions;
+  SubstitutionsCache d_cache;
+  bool d_cacheInvalid;
+  theory::SubstitutionMap* d_modelMap; 
+
+  
+  Node getReason(TNode node) const;
+  bool hasCache(TNode node) const;
+  Node getCache(TNode node) const;
+  void storeCache(TNode from, TNode to, Node rason);
+  Node internalApply(TNode node);
+
+public:
+  SubstitutionEx(theory::SubstitutionMap* modelMap);
+  void addSubstitution(TNode from, TNode to, TNode reason);
+  Node apply(TNode node);
+  Node explain(TNode node) const;
+};
+
+/**
+ * In-processing worklist element, id keeps track of
+ * original assertion. 
+ * 
+ */
+struct WorklistElement {
+  Node node;
+  unsigned id;
+  WorklistElement(Node n, unsigned i) : node(n), id(i) {}
+  WorklistElement() : node(), id(-1) {}
+}; 
+
+
+typedef __gnu_cxx::hash_map<Node, Node, NodeHashFunction> NodeNodeMap;
+typedef __gnu_cxx::hash_map<Node, unsigned, NodeHashFunction> NodeIdMap;
+typedef __gnu_cxx::hash_set<TNode, TNodeHashFunction> TNodeSet;
+
+
+class ExtractSkolemizer {
+  struct Extract {
+    unsigned high;
+    unsigned low;
+    Extract(unsigned h, unsigned l) : high(h), low(l) {}
+  };
+    
+  struct ExtractList {
+    Base base;
+    std::vector<Extract> extracts;
+    ExtractList(unsigned bitwidth) : base(bitwidth), extracts() {}
+    ExtractList() : base(1), extracts() {}
+    void addExtract(Extract& e); 
+  };
+  typedef   __gnu_cxx::hash_map<Node, ExtractList, NodeHashFunction> VarExtractMap;
+  context::Context d_emptyContext;
+  VarExtractMap d_varToExtract;
+  theory::SubstitutionMap* d_modelMap;
+  theory::SubstitutionMap d_skolemSubst;
+  theory::SubstitutionMap d_skolemSubstRev;
+
+  void storeSkolem(TNode node, TNode skolem);
+  void storeExtract(TNode var, unsigned high, unsigned low);
+  void collectExtracts(TNode node, TNodeSet& seen);
+  Node skolemize(TNode);
+  Node unSkolemize(TNode);
+
+  Node mkSkolem(Node node);
+public:
+  ExtractSkolemizer(theory::SubstitutionMap* modelMap); 
+  void skolemize(std::vector<WorklistElement>&);
+  void unSkolemize(std::vector<WorklistElement>&);
+  ~ExtractSkolemizer();
+}; 
+
+class BVQuickCheck;
+class QuickXPlain;
+
+/**
+ * AlgebraicSolver
+ */
+class AlgebraicSolver : public SubtheorySolver {
+  
+  struct Statistics {
+    IntStat d_numCallstoCheck;
+    IntStat d_numSimplifiesToTrue;
+    IntStat d_numSimplifiesToFalse;
+    IntStat d_numUnsat;
+    IntStat d_numSat;
+    IntStat d_numUnknown;
+    TimerStat d_solveTime;
+    BackedStat<double> d_useHeuristic;
+    Statistics();
+    ~Statistics();
+  };
+
+  SubstitutionMap* d_modelMap;
+  BVQuickCheck* d_quickSolver;
+  context::CDO<bool> d_isComplete; 
+  context::CDO<bool> d_isDifficult; /**< flag to indicate whether the current assertions contain expensive BV operators */
+  
+  unsigned long d_budget;
+  std::vector<Node> d_explanations; /**< explanations for assertions indexed by assertion id */
+  TNodeSet d_inputAssertions;   /**< assertions in current context (for debugging purposes only) */
+  NodeIdMap d_ids;              /**< map from assertions to ids */
+  double d_numSolved;
+  double d_numCalls;
+
+  context::Context* d_ctx;
+  QuickXPlain* d_quickXplain;   /**< separate quickXplain module as it can reuse the current SAT solver */
+  
+  Statistics d_statistics;
+  bool useHeuristic();
+  void setConflict(TNode conflict);
+  bool isSubstitutableIn(TNode node, TNode in);
+  bool checkExplanation(TNode expl);
+  void storeExplanation(TNode expl);
+  void storeExplanation(unsigned id, TNode expl);
+  /** 
+   * Apply substitutions and rewriting to the worklist assertions to a fixpoint.
+   * Subsitutions learned store in subst. 
+   *
+   * @param worklist 
+   * @param subst 
+   */
+  void processAssertions(std::vector<WorklistElement>& worklist, SubstitutionEx& subst);
+  /** 
+   * Attempt to solve the equation in fact, and if successful
+   * add a substitution to subst. 
+   * 
+   * @param fact equation we are trying to solve
+   * @param reason the reason in terms of original assertions
+   * @param subst substitution map
+   * 
+   * @return true if added a substitution to subst
+   */
+  bool solve(TNode fact, TNode reason, SubstitutionEx& subst);
+  /** 
+   * Run a SAT solver on the given facts with the given budget.
+   * Sets the isComplete flag and conflict accordingly. 
+   * 
+   * @param facts 
+   * 
+   * @return true if no conflict was detected. 
+   */
+  bool quickCheck(std::vector<Node>& facts);
+
+public:
+  AlgebraicSolver(context::Context* c, TheoryBV* bv);
+  ~AlgebraicSolver();
+
+  void  preRegister(TNode node) {}
+  bool  check(Theory::Effort e);
+  void  explain(TNode literal, std::vector<TNode>& assumptions) {Unreachable("AlgebraicSolver does not propagate.\n");}
+  EqualityStatus getEqualityStatus(TNode a, TNode b); 
+  void collectModelInfo(TheoryModel* m, bool fullModel); 
+  Node getModelValue(TNode node); 
+  bool isComplete();
+  virtual void assertFact(TNode fact);
+};
+
+}
+}
+}
index e4b1a346d4f9ee19598d53979261c04264646914..d606ccee8a63d079447769df423fc421db098e2e 100644 (file)
 #include "theory/bv/bv_subtheory_bitblast.h"
 #include "theory/bv/theory_bv.h"
 #include "theory/bv/theory_bv_utils.h"
-#include "theory/bv/bitblaster.h"
+#include "theory/bv/lazy_bitblaster.h"
+#include "theory/bv/bv_quick_check.h"
 #include "theory/bv/options.h"
 #include "theory/decision_attributes.h"
 #include "decision/options.h"
 
+
 using namespace std;
 using namespace CVC4;
 using namespace CVC4::context;
@@ -31,24 +33,38 @@ using namespace CVC4::theory::bv::utils;
 
 BitblastSolver::BitblastSolver(context::Context* c, TheoryBV* bv)
   : SubtheorySolver(c, bv),
-    d_bitblaster(new Bitblaster(c, bv)),
+    d_bitblaster(new TLazyBitblaster(c, bv, "lazy")),
     d_bitblastQueue(c),
     d_statistics(),
     d_validModelCache(c, true),
-    d_useSatPropagation(options::bvPropagate())
+    d_lemmaAtomsQueue(c),
+    d_useSatPropagation(options::bitvectorPropagate()),
+    d_abstractionModule(NULL),
+    d_quickCheck(options::bitvectorQuickXplain() ? new BVQuickCheck("bb", bv) : NULL),
+    d_quickXplain(options::bitvectorQuickXplain() ? new QuickXPlain("bb", d_quickCheck) :  NULL)
 {}
 
 BitblastSolver::~BitblastSolver() {
+  delete d_quickXplain;
+  delete d_quickCheck;
   delete d_bitblaster;
 }
 
 BitblastSolver::Statistics::Statistics()
   : d_numCallstoCheck("theory::bv::BitblastSolver::NumCallsToCheck", 0)
+  , d_numBBLemmas("theory::bv::BitblastSolver::NumTimesLemmasBB", 0)
 {
   StatisticsRegistry::registerStat(&d_numCallstoCheck);
+  StatisticsRegistry::registerStat(&d_numBBLemmas);
 }
 BitblastSolver::Statistics::~Statistics() {
   StatisticsRegistry::unregisterStat(&d_numCallstoCheck);
+  StatisticsRegistry::unregisterStat(&d_numBBLemmas);
+}
+
+void BitblastSolver::setAbstraction(AbstractionModule* abs) {
+  d_abstractionModule = abs; 
+  d_bitblaster->setAbstraction(abs); 
 }
 
 void BitblastSolver::preRegister(TNode node) {
@@ -58,19 +74,20 @@ void BitblastSolver::preRegister(TNode node) {
        node.getKind() == kind::BITVECTOR_SLT ||
        node.getKind() == kind::BITVECTOR_SLE) &&
       !d_bitblaster->hasBBAtom(node)) {
-    if (options::bitvectorEagerBitblast()) {
-      d_bitblaster->bbAtom(node);
-    } else {
-      CodeTimer weightComputationTime(d_bv->d_statistics.d_weightComputationTimer);
-      d_bitblastQueue.push_back(node);
-      if ((options::decisionUseWeight() || options::decisionThreshold() != 0) &&
-          !node.hasAttribute(theory::DecisionWeightAttr())) {
-        node.setAttribute(theory::DecisionWeightAttr(), d_bitblaster->computeAtomWeight(node));
-      }
+    CodeTimer weightComputationTime(d_bv->d_statistics.d_weightComputationTimer);
+    d_bitblastQueue.push_back(node);
+    if ((options::decisionUseWeight() || options::decisionThreshold() != 0) &&
+        !node.hasAttribute(theory::DecisionWeightAttr())) {
+      node.setAttribute(theory::DecisionWeightAttr(),computeAtomWeight(node));
     }
   }
 }
 
+uint64_t BitblastSolver::computeAtomWeight(TNode node) {
+  NodeSet seen;
+  return d_bitblaster->computeAtomWeight(node, seen);
+}
+
 void BitblastSolver::explain(TNode literal, std::vector<TNode>& assumptions) {
   d_bitblaster->explain(literal, assumptions);
 }
@@ -78,14 +95,19 @@ void BitblastSolver::explain(TNode literal, std::vector<TNode>& assumptions) {
 void BitblastSolver::bitblastQueue() {
   while (!d_bitblastQueue.empty()) {
     TNode atom = d_bitblastQueue.front();
-    d_bitblaster->bbAtom(atom);
     d_bitblastQueue.pop();
+    if (options::bvAbstraction() &&
+        d_abstractionModule->isLemmaAtom(atom)) {
+      // don't bit-blast lemma atoms
+      continue;
+    }
+    d_bitblaster->bbAtom(atom);
   }
 }
 
 bool BitblastSolver::check(Theory::Effort e) {
   Debug("bv-bitblast") << "BitblastSolver::check (" << e << ")\n";
-  Assert(!options::bitvectorEagerBitblast());
+  Assert(options::bitblastMode() == theory::bv::BITBLAST_MODE_LAZY); 
 
   ++(d_statistics.d_numCallstoCheck);
 
@@ -98,7 +120,17 @@ bool BitblastSolver::check(Theory::Effort e) {
     TNode fact = get();
     d_validModelCache = false;
     Debug("bv-bitblast") << "  fact " << fact << ")\n";
-    if (!d_bv->inConflict() && (!d_bv->wasPropagatedBySubtheory(fact) || d_bv->getPropagatingSubtheory(fact) != SUB_BITBLAST)) {
+
+    if (options::bvAbstraction()) {
+      // skip atoms that are the result of abstraction lemmas
+      if (d_abstractionModule->isLemmaAtom(fact)) {
+        d_lemmaAtomsQueue.push_back(fact);
+        continue; 
+      }
+    }
+    
+    if (!d_bv->inConflict() &&
+        (!d_bv->wasPropagatedBySubtheory(fact) || d_bv->getPropagatingSubtheory(fact) != SUB_BITBLAST)) {
       // Some atoms have not been bit-blasted yet
       d_bitblaster->bbAtom(fact);
       // Assert to sat
@@ -106,7 +138,7 @@ bool BitblastSolver::check(Theory::Effort e) {
       if (!ok) {
         std::vector<TNode> conflictAtoms;
         d_bitblaster->getConflict(conflictAtoms);
-        d_bv->setConflict(mkConjunction(conflictAtoms));
+        setConflict(mkConjunction(conflictAtoms));
         return false;
       }
     }
@@ -118,13 +150,13 @@ bool BitblastSolver::check(Theory::Effort e) {
     if (!ok) {
       std::vector<TNode> conflictAtoms;
       d_bitblaster->getConflict(conflictAtoms);
-      d_bv->setConflict(mkConjunction(conflictAtoms));
+      setConflict(mkConjunction(conflictAtoms));
       return false;
     }
   }
 
   // Solving
-  if (e == Theory::EFFORT_FULL || options::bitvectorEagerFullcheck()) {
+  if (e == Theory::EFFORT_FULL) {
     Assert(!d_bv->inConflict());
     Debug("bitvector::bitblaster") << "BitblastSolver::addAssertions solving. \n";
     bool ok = d_bitblaster->solve();
@@ -132,11 +164,45 @@ bool BitblastSolver::check(Theory::Effort e) {
       std::vector<TNode> conflictAtoms;
       d_bitblaster->getConflict(conflictAtoms);
       Node conflict = mkConjunction(conflictAtoms);
-      d_bv->setConflict(conflict);
+      setConflict(conflict);
       return false;
     }
   }
 
+  if (options::bvAbstraction() &&
+      e == Theory::EFFORT_FULL &&
+      d_lemmaAtomsQueue.size()) {
+    
+    // bit-blast lemma atoms
+    while(!d_lemmaAtomsQueue.empty()) {
+      TNode lemma_atom = d_lemmaAtomsQueue.front();
+      d_bitblaster->bbAtom(lemma_atom);
+      d_lemmaAtomsQueue.pop();
+
+      // Assert to sat and check for conflicts
+      bool ok = d_bitblaster->assertToSat(lemma_atom, d_useSatPropagation);
+      if (!ok) {
+        std::vector<TNode> conflictAtoms;
+        d_bitblaster->getConflict(conflictAtoms);
+        setConflict(mkConjunction(conflictAtoms));
+        return false;
+      }
+    }
+    
+    Assert(!d_bv->inConflict());
+    bool ok = d_bitblaster->solve();
+    if (!ok) {
+      std::vector<TNode> conflictAtoms;
+      d_bitblaster->getConflict(conflictAtoms);
+      Node conflict = mkConjunction(conflictAtoms);
+      setConflict(conflict);
+      ++(d_statistics.d_numBBLemmas);
+      return false;
+    }
+    
+  }
+  
+
   return true;
 }
 
@@ -191,3 +257,15 @@ Node BitblastSolver::getModelValueRec(TNode node)
   Debug("bitvector-model") << node << " => " << val <<"\n";
   return val;
 }
+
+
+void BitblastSolver::setConflict(TNode conflict) {
+  Node final_conflict = conflict;
+  if (options::bitvectorQuickXplain() &&
+      conflict.getKind() == kind::AND) {
+    // std::cout << "Original conflict " << conflict.getNumChildren() << "\n"; 
+    final_conflict = d_quickXplain->minimizeConflict(conflict);
+    //std::cout << "Minimized conflict " << final_conflict.getNumChildren() << "\n"; 
+  }
+  d_bv->setConflict(final_conflict);
+}
index b1c1b3b66f7e5148ac853aff6b410e88c0d4fc09..511318521f4b7e8c5169b00f0fcc81c0a703dd3f 100644 (file)
 #pragma once
 
 #include "theory/bv/bv_subtheory.h"
+#include "theory/bv/bitblaster_template.h"
+
 namespace CVC4 {
 namespace theory {
 namespace bv {
 
-class Bitblaster;
+class LazyBitblaster;
+class AbstractionModule;
+class BVQuickCheck;
+class QuickXPlain;
 
 /**
  * BitblastSolver
@@ -31,11 +36,12 @@ class Bitblaster;
 class BitblastSolver : public SubtheorySolver {
   struct Statistics {
     IntStat d_numCallstoCheck;
+    IntStat d_numBBLemmas;
     Statistics();
     ~Statistics();
   };
   /** Bitblaster */
-  Bitblaster* d_bitblaster;
+  TLazyBitblaster* d_bitblaster;
 
   /** Nodes that still need to be bit-blasted */
   context::CDQueue<TNode> d_bitblastQueue;
@@ -44,9 +50,15 @@ class BitblastSolver : public SubtheorySolver {
   typedef std::hash_map<Node, Node, NodeHashFunction> NodeMap;
   NodeMap d_modelCache;
   context::CDO<bool> d_validModelCache;
-  Node getModelValueRec(TNode node);
 
+  /** Queue for bit-blasting lemma atoms only in full check if we are sat */
+  context::CDQueue<TNode> d_lemmaAtomsQueue;
   bool  d_useSatPropagation;
+  AbstractionModule* d_abstractionModule;
+  BVQuickCheck* d_quickCheck;
+  QuickXPlain* d_quickXplain;
+  Node getModelValueRec(TNode node);
+  void setConflict(TNode conflict); 
 public:
   BitblastSolver(context::Context* c, TheoryBV* bv);
   ~BitblastSolver();
@@ -59,6 +71,8 @@ public:
   Node getModelValue(TNode node);
   bool isComplete() { return true; }
   void bitblastQueue();
+  void setAbstraction(AbstractionModule* module); 
+  uint64_t computeAtomWeight(TNode atom); 
 };
 
 }
index 2433dc1ee0d8e3487de6e2b54132c6a001a9fc47..ca414a2ff8da16cff2f95df9749a8053322c0f20 100644 (file)
@@ -34,10 +34,12 @@ CoreSolver::CoreSolver(context::Context* c, TheoryBV* bv)
     d_notify(*this),
     d_equalityEngine(d_notify, c, "theory::bv::TheoryBV"),
     d_slicer(new Slicer()),
-    d_isCoreTheory(c, true),
+    d_isComplete(c, true),
+    d_useSlicer(false),
+    d_preregisterCalled(false),
+    d_checkCalled(false),
     d_reasons(c)
 {
-
   // The kinds we are treating as function application in congruence
   d_equalityEngine.addFunctionKind(kind::BITVECTOR_CONCAT, true);
   //    d_equalityEngine.addFunctionKind(kind::BITVECTOR_AND);
@@ -78,11 +80,19 @@ void CoreSolver::setMasterEqualityEngine(eq::EqualityEngine* eq) {
   d_equalityEngine.setMasterEqualityEngine(eq);
 }
 
+void CoreSolver::enableSlicer() {
+  AlwaysAssert (!d_preregisterCalled);
+  d_useSlicer = true;
+  d_statistics.d_slicerEnabled.setData(true);
+}
+
 void CoreSolver::preRegister(TNode node) {
+  d_preregisterCalled = true;
   if (node.getKind() == kind::EQUAL) {
       d_equalityEngine.addTriggerEquality(node);
-      if (options::bitvectorCoreSolver()) {
+      if (d_useSlicer) {
         d_slicer->processEquality(node);
+        AlwaysAssert(!d_checkCalled); 
       }
   } else {
     d_equalityEngine.addTerm(node);
@@ -109,11 +119,6 @@ Node CoreSolver::getBaseDecomposition(TNode a) {
 }
 
 bool CoreSolver::decomposeFact(TNode fact) {
-  Debug("bv-slicer") << "CoreSolver::decomposeFact fact=" << fact << endl;
-  // assert decompositions since the equality engine does not know the semantics of
-  // concat:
-  //   a == a_1 concat ... concat a_k
-  //   b == b_1 concat ... concat b_k
   Debug("bv-slicer") << "CoreSolver::decomposeFact fact=" << fact << endl;
   // FIXME: are this the right things to assert?
   // assert decompositions since the equality engine does not know the semantics of
@@ -161,21 +166,21 @@ bool CoreSolver::decomposeFact(TNode fact) {
 
 bool CoreSolver::check(Theory::Effort e) {
   Trace("bitvector::core") << "CoreSolver::check \n";
+  d_checkCalled = true; 
   Assert (!d_bv->inConflict());
   ++(d_statistics.d_numCallstoCheck);
   bool ok = true;
   std::vector<Node> core_eqs;
+  TNodeBoolMap seen;
   while (! done()) {
     TNode fact = get();
-
-    // update whether we are in the core fragment
-    if (d_isCoreTheory && !d_slicer->isCoreTerm(fact)) {
-      d_isCoreTheory = false;
+    if (d_isComplete && !isCompleteForTerm(fact, seen)) {
+      d_isComplete = false;
     }
-
+    
     // only reason about equalities
     if (fact.getKind() == kind::EQUAL || (fact.getKind() == kind::NOT && fact[0].getKind() == kind::EQUAL)) {
-      if (options::bitvectorCoreSolver()) {
+      if (d_useSlicer) {
         ok = decomposeFact(fact);
       } else {
         ok = assertFactToEqualityEngine(fact, fact);
@@ -195,11 +200,6 @@ bool CoreSolver::check(Theory::Effort e) {
 }
 
 void CoreSolver::buildModel() {
-  if (options::bitvectorCoreSolver()) {
-    // FIXME
-    Unreachable();
-    return;
-  }
   Debug("bv-core") << "CoreSolver::buildModel() \n";
   d_modelValues.clear();
   TNodeSet constants;
@@ -218,6 +218,7 @@ void CoreSolver::buildModel() {
     }
     ++eqcs_i;
   }
+
   // build repr to value map
 
   eqcs_i = eq::EqClassesIterator(&d_equalityEngine);
@@ -356,10 +357,16 @@ void CoreSolver::conflict(TNode a, TNode b) {
   d_bv->setConflict(conflict);
 }
 
+bool CoreSolver::isCompleteForTerm(TNode term, TNodeBoolMap& seen) {
+  if (d_useSlicer)
+    return utils::isCoreTerm(term, seen);
+  
+  return utils::isEqualityTerm(term, seen); 
+}
+
 void CoreSolver::collectModelInfo(TheoryModel* m, bool fullModel) {
-  if (options::bitvectorCoreSolver()) {
-    Unreachable();
-    return;
+  if (d_useSlicer) {
+    Unreachable(); 
   }
   if (Debug.isOn("bitvector-model")) {
     context::CDQueue<Node>::const_iterator it = d_assertionQueue.begin();
@@ -376,6 +383,8 @@ void CoreSolver::collectModelInfo(TheoryModel* m, bool fullModel) {
     for (ModelValue::const_iterator it = d_modelValues.begin(); it != d_modelValues.end(); ++it) {
       Node a = it->first;
       Node b = it->second;
+      Debug("bitvector-model") << "CoreSolver::collectModelInfo modelValues "
+                               << a << " => " << b <<")\n"; 
       m->assertEquality(a, b, true);
     }
   }
@@ -406,9 +415,12 @@ Node CoreSolver::getModelValue(TNode var) {
 
 CoreSolver::Statistics::Statistics()
   : d_numCallstoCheck("theory::bv::CoreSolver::NumCallsToCheck", 0)
+  , d_slicerEnabled("theory::bv::CoreSolver::SlicerEnabled", false)
 {
   StatisticsRegistry::registerStat(&d_numCallstoCheck);
+  StatisticsRegistry::registerStat(&d_slicerEnabled);
 }
 CoreSolver::Statistics::~Statistics() {
   StatisticsRegistry::unregisterStat(&d_numCallstoCheck);
+  StatisticsRegistry::unregisterStat(&d_slicerEnabled);
 }
index e1a73d40446ba13e6b6a9939f3dee7b291d17696..9ab6cfce4e9785e5629b423a835998f3f7dcfe76 100644 (file)
@@ -32,10 +32,13 @@ class Base;
  */
 class CoreSolver : public SubtheorySolver {
   typedef __gnu_cxx::hash_map<TNode, Node, TNodeHashFunction> ModelValue;
+  typedef __gnu_cxx::hash_map<TNode, bool, TNodeHashFunction> TNodeBoolMap;
   typedef __gnu_cxx::hash_set<TNode, TNodeHashFunction> TNodeSet;
 
+
   struct Statistics {
     IntStat d_numCallstoCheck;
+    BackedStat<bool> d_slicerEnabled;
     Statistics();
     ~Statistics();
   };
@@ -70,7 +73,13 @@ class CoreSolver : public SubtheorySolver {
   void conflict(TNode a, TNode b);
 
   Slicer* d_slicer;
-  context::CDO<bool> d_isCoreTheory;
+  context::CDO<bool> d_isComplete;
+  
+  /** Used to ensure that the core slicer is used properly*/
+  bool d_useSlicer; 
+  bool d_preregisterCalled;
+  bool d_checkCalled;
+  
   /** To make sure we keep the explanations */
   context::CDHashSet<Node, NodeHashFunction> d_reasons;
   ModelValue d_modelValues;
@@ -78,11 +87,12 @@ class CoreSolver : public SubtheorySolver {
   bool assertFactToEqualityEngine(TNode fact, TNode reason);
   bool decomposeFact(TNode fact);
   Node getBaseDecomposition(TNode a);
+  bool isCompleteForTerm(TNode term, TNodeBoolMap& seen);
   Statistics d_statistics;
 public:
   CoreSolver(context::Context* c, TheoryBV* bv);
   ~CoreSolver();
-  bool  isComplete() { return d_isCoreTheory; }
+  bool  isComplete() { return d_isComplete; }
   void  setMasterEqualityEngine(eq::EqualityEngine* eq);
   void  preRegister(TNode node);
   bool  check(Theory::Effort e);
@@ -105,6 +115,7 @@ public:
   }
   bool hasTerm(TNode node) const { return d_equalityEngine.hasTerm(node); }
   void addTermToEqualityEngine(TNode node) { d_equalityEngine.addTerm(node); }
+  void enableSlicer();
 };
 
 
index d137d09a0064ca7b1ebfaff88d91ad8c2971a866..72131d6e716c66e32f1952fe283d99e8909cf4c6 100644 (file)
@@ -23,171 +23,141 @@ using namespace CVC4;
 using namespace CVC4::theory;
 using namespace CVC4::theory::bv;
 
-void BvToBoolVisitor::addToCache(TNode term, Node new_term) {
+BvToBoolPreprocessor::BvToBoolPreprocessor()
+  : d_liftCache()
+  , d_boolCache()
+  , d_one(utils::mkConst(BitVector(1, 1u)))
+  , d_zero(utils::mkConst(BitVector(1, 0u)))
+  , d_statistics()
+{}
+
+void BvToBoolPreprocessor::addToLiftCache(TNode term, Node new_term) {
   Assert (new_term != Node()); 
-  Assert (!hasCache(term));
-  d_cache[term] = new_term; 
+  Assert (!hasLiftCache(term));
+  Assert (term.getType() == new_term.getType());
+  d_liftCache[term] = new_term; 
 }
 
-Node BvToBoolVisitor::getCache(TNode term) const {
-  if (!hasCache(term) || term.getKind() == kind::CONST_BITVECTOR) {
-    return term; 
-  }
-  return d_cache.find(term)->second; 
+Node BvToBoolPreprocessor::getLiftCache(TNode term) const {
+  Assert(hasLiftCache(term)); 
+  return d_liftCache.find(term)->second; 
 }
 
-bool BvToBoolVisitor::hasCache(TNode term) const {
-  return d_cache.find(term) != d_cache.end(); 
+bool BvToBoolPreprocessor::hasLiftCache(TNode term) const {
+  return d_liftCache.find(term) != d_liftCache.end(); 
 }
 
-void BvToBoolVisitor::start(TNode node) {}
-
-void BvToBoolVisitor::storeBvToBool(TNode bv_term, TNode bool_term) {
-  Assert (bv_term.getType().isBitVector() &&
-          bv_term.getType().getBitVectorSize() == 1 &&
-          bool_term.getType().isBoolean() && bv_term != Node() && bool_term != Node());
-  if (d_bvToBoolMap.find(bv_term) != d_bvToBoolMap.end()) {
-    Assert (d_bvToBoolMap[bv_term] == bool_term); 
-  }
-  d_bvToBoolMap[bv_term] = bool_term; 
+void BvToBoolPreprocessor::addToBoolCache(TNode term, Node new_term) {
+  Assert (new_term != Node()); 
+  Assert (!hasBoolCache(term));
+  Assert (utils::getSize(term) == 1);
+  Assert (new_term.getType().isBoolean());
+  d_boolCache[term] = new_term; 
 }
 
-Node BvToBoolVisitor::getBoolForBvTerm(TNode node) {
-  Assert (d_bvToBoolMap.find(node) != d_bvToBoolMap.end());
-  return d_bvToBoolMap[node]
+Node BvToBoolPreprocessor::getBoolCache(TNode term) const {
+  Assert(hasBoolCache(term)); 
+  return d_boolCache.find(term)->second
 }
 
-bool BvToBoolVisitor::alreadyVisited(TNode current, TNode parent) {
-  return d_cache.find(current) != d_cache.end(); 
+bool BvToBoolPreprocessor::hasBoolCache(TNode term) const {
+  return d_boolCache.find(term) != d_boolCache.end(); 
 }
-
-bool BvToBoolVisitor::isConvertibleBvAtom(TNode node) {
+bool BvToBoolPreprocessor::isConvertibleBvAtom(TNode node) {
   Kind kind = node.getKind();
-  return (kind == kind::BITVECTOR_ULT ||
-          kind == kind::BITVECTOR_ULE ||
-          kind == kind::BITVECTOR_SLT ||
-          kind == kind::BITVECTOR_SLE ||
-          kind == kind::EQUAL) &&
-    isConvertibleBvTerm(node[0]) &&
-    isConvertibleBvTerm(node[1]); 
-}
-
-bool BvToBoolVisitor::isConvertibleBvTerm(TNode node) {
-  // we have already converted it and the result is cached
-  if (d_bvToBoolMap.find(node) != d_bvToBoolMap.end()) {
-    return true;
-  }
-  
-  if (!node.getType().isBitVector() || node.getType().getBitVectorSize() != 1)
+  return (kind == kind::EQUAL &&
+          node[0].getType().isBitVector() &&
+          node[0].getType().getBitVectorSize() == 1 &&
+          node[1].getType().isBitVector() &&
+          node[1].getType().getBitVectorSize() == 1 &&
+          node[0].getKind() != kind::BITVECTOR_EXTRACT &&
+          node[1].getKind() != kind::BITVECTOR_EXTRACT); 
+}
+
+bool BvToBoolPreprocessor::isConvertibleBvTerm(TNode node) {
+  if (!node.getType().isBitVector() ||
+      node.getType().getBitVectorSize() != 1)
     return false;
 
   Kind kind = node.getKind();
   
-  if (kind == kind::CONST_BITVECTOR) {
+  if (kind == kind::CONST_BITVECTOR ||
+      kind == kind::ITE ||
+      kind == kind::BITVECTOR_AND ||
+      kind == kind::BITVECTOR_OR ||
+      kind == kind::BITVECTOR_NOT ||
+      kind == kind::BITVECTOR_XOR) {
     return true; 
   }
 
-  if (kind == kind::ITE) {
-    return isConvertibleBvTerm(node[1]) && isConvertibleBvTerm(node[2]); 
-  }
-
-  if (kind == kind::BITVECTOR_AND || kind == kind::BITVECTOR_OR ||
-      kind == kind::BITVECTOR_NOT || kind == kind::BITVECTOR_XOR) {
-    for (unsigned i = 0; i < node.getNumChildren(); ++i) {
-      if (!isConvertibleBvTerm(node[i]))
-        return false; 
-    }
-    return true; 
-  }
-  if (kind == kind::VARIABLE) {
-    storeBvToBool(node, utils::mkNode(kind::EQUAL, node, utils::mkConst(BitVector(1, 1u)))); 
-    return true; 
-  }
   return false; 
 }
 
-Node BvToBoolVisitor::convertBvAtom(TNode node) {
-  Assert (node.getType().isBoolean());
-  Kind kind = node.getKind();
-  Node result; 
-  switch(kind) {
-  case kind::BITVECTOR_ULT: {
-    Node a = getBoolForBvTerm(node[0]);
-    Node b = getBoolForBvTerm(node[1]);
-    Node a_eq_0 = utils::mkNode(kind::IFF, a, utils::mkFalse());
-    Node b_eq_1 = utils::mkNode(kind::IFF, b, utils::mkTrue());
-    result = utils::mkNode(kind::AND, a_eq_0, b_eq_1);
-    break;
-  }
-  case kind::BITVECTOR_ULE: {
-   Node a = getBoolForBvTerm(node[0]);
-   Node b = getBoolForBvTerm(node[1]);
-   Node a_eq_0 = utils::mkNode(kind::IFF, a, utils::mkFalse());
-   Node b_eq_1 = utils::mkNode(kind::IFF, b, utils::mkTrue());
-   Node a_lt_b = utils::mkNode(kind::AND, a_eq_0, b_eq_1); 
-   Node a_eq_b = utils::mkNode(kind::IFF, a, b);
-   result = utils::mkNode(kind::OR, a_lt_b, a_eq_b);    
-   break;
-  }
-  case kind::BITVECTOR_SLT: {
-    Node a = getBoolForBvTerm(node[0]);
-    Node b = getBoolForBvTerm(node[1]);
-    Node a_eq_1 = utils::mkNode(kind::IFF, a, utils::mkTrue());
-    Node b_eq_0 = utils::mkNode(kind::IFF, b, utils::mkFalse());
-    result = utils::mkNode(kind::AND, a_eq_1, b_eq_0);
-    break; 
-  }
-  case kind::BITVECTOR_SLE: {
-    Node a = getBoolForBvTerm(node[0]);
-    Node b = getBoolForBvTerm(node[1]);
-    Node a_eq_1 = utils::mkNode(kind::IFF, a, utils::mkTrue());
-    Node b_eq_0 = utils::mkNode(kind::IFF, b, utils::mkFalse());
-    Node a_slt_b = utils::mkNode(kind::AND, a_eq_1, b_eq_0);
-    Node a_eq_b = utils::mkNode(kind::IFF, a, b);
-    result = utils::mkNode(kind::OR, a_slt_b, a_eq_b); 
-    break; 
-  }
-  case kind::EQUAL: {
-    Node a = getBoolForBvTerm(node[0]);
-    Node b = getBoolForBvTerm(node[1]);
-    result = utils::mkNode(kind::IFF, a, b); 
-    break;
-  }
-  default:
-    Unhandled(); 
-  }
-  Debug("bv-to-bool") << "BvToBoolVisitor::convertBvAtom " << node <<" => " << result << "\n"; 
-  Assert (result != Node());
+Node BvToBoolPreprocessor::convertBvAtom(TNode node) {
+  Assert (node.getType().isBoolean() &&
+          node.getKind() == kind::EQUAL);
+  Assert (utils::getSize(node[0]) == 1);
+  Assert (utils::getSize(node[1]) == 1);
+  Node a = convertBvTerm(node[0]);
+  Node b = convertBvTerm(node[1]);
+  Node result = utils::mkNode(kind::IFF, a, b); 
+  Debug("bv-to-bool") << "BvToBoolPreprocessor::convertBvAtom " << node <<" => " << result << "\n";
+
+  ++(d_statistics.d_numAtomsLifted);
   return result;
 }
 
-Node BvToBoolVisitor::convertBvTerm(TNode node) {
+Node BvToBoolPreprocessor::convertBvTerm(TNode node) {
   Assert (node.getType().isBitVector() &&
           node.getType().getBitVectorSize() == 1);
-  Kind kind = node.getKind(); 
+
+  if (hasBoolCache(node))
+    return getBoolCache(node);
+  
+  if (!isConvertibleBvTerm(node)) {
+    ++(d_statistics.d_numTermsForcedLifted);
+    Node result = utils::mkNode(kind::EQUAL, node, d_one);
+    addToBoolCache(node, result);
+    Debug("bv-to-bool") << "BvToBoolPreprocessor::convertBvTerm " << node <<" => " << result << "\n"; 
+    return result;
+  }
 
   if (node.getNumChildren() == 0) {
-    if (node.getKind() == kind::VARIABLE) {
-      return getBoolForBvTerm(node);
-    }
-    if (node.getKind() == kind::CONST_BITVECTOR) {
-      Node result = node == d_one ? utils::mkTrue() : utils::mkFalse();
-      storeBvToBool(node, result); 
-      return result; 
-    }
+    Assert (node.getKind() == kind::CONST_BITVECTOR);
+    Node result = node == d_one ? utils::mkTrue() : utils::mkFalse();
+    // addToCache(node, result);
+    Debug("bv-to-bool") << "BvToBoolPreprocessor::convertBvTerm " << node <<" => " << result << "\n"; 
+    return result; 
   }
+
+  ++(d_statistics.d_numTermsLifted);
   
+  Kind kind = node.getKind();
   if (kind == kind::ITE) {
-    Node cond = getCache(node[0]);
-    Node true_branch = getBoolForBvTerm(node[1]);
-    Node false_branch = getBoolForBvTerm(node[2]);
+    Node cond = liftNode(node[0]);
+    Node true_branch = convertBvTerm(node[1]);
+    Node false_branch = convertBvTerm(node[2]);
     Node result = utils::mkNode(kind::ITE, cond, true_branch, false_branch);
-    storeBvToBool(node, result);
-    Debug("bv-to-bool") << "BvToBoolVisitor::convertBvTerm " << node <<" => " << result << "\n"; 
+    addToBoolCache(node, result);
+    Debug("bv-to-bool") << "BvToBoolPreprocessor::convertBvTerm " << node <<" => " << result << "\n"; 
+    return result; 
+  }
+
+  Kind new_kind;
+  // special case for XOR as it has to be binary
+  // while BITVECTOR_XOR can be n-ary
+  if (kind == kind::BITVECTOR_XOR) {
+    new_kind = kind::XOR;
+    Node result = convertBvTerm(node[0]);
+    for (unsigned i = 1; i < node.getNumChildren(); ++i) {
+      Node converted = convertBvTerm(node[i]);
+      result = utils::mkNode(kind::XOR, result, converted); 
+    }
+    Debug("bv-to-bool") << "BvToBoolPreprocessor::convertBvTerm " << node <<" => " << result << "\n"; 
     return result; 
   }
   
-  Kind new_kind; 
+
   switch(kind) {
   case kind::BITVECTOR_OR:
     new_kind = kind::OR;
@@ -207,108 +177,69 @@ Node BvToBoolVisitor::convertBvTerm(TNode node) {
 
   NodeBuilder<> builder(new_kind);
   for (unsigned i = 0; i < node.getNumChildren(); ++i) {
-    builder << getBoolForBvTerm(node[i]); 
+    builder << convertBvTerm(node[i]); 
   }
+  
   Node result = builder;
-  storeBvToBool(node, result);
-  Debug("bv-to-bool") << "BvToBoolVisitor::convertBvTerm " << node <<" => " << result << "\n"; 
+  addToBoolCache(node, result);
+  Debug("bv-to-bool") << "BvToBoolPreprocessor::convertBvTerm " << node <<" => " << result << "\n"; 
   return result; 
 }
 
-void BvToBoolVisitor::check(TNode current, TNode parent) {
-  if (d_bvToBoolMap.find(current) != d_bvToBoolMap.end()) {
-    if (!isConvertibleBvTerm(parent) && !isConvertibleBvAtom(parent)) {
-      Debug("bv-to-bool") << "BvToBoolVisitor::check " << current << " in non boolean context: \n"
-                          << "           " << parent << "\n"; 
-    }
-  }
-}
 
-void BvToBoolVisitor::visit(TNode current, TNode parent) {
-  Debug("bv-to-bool") << "BvToBoolVisitor visit (" << current << ", " << parent << ")\n"; 
-  Assert (!alreadyVisited(current, parent) &&
-          !hasCache(current));
 
+Node BvToBoolPreprocessor::liftNode(TNode current) {
   Node result;
-  // make sure that the bv terms we are replacing to not occur in other contexts
-  check(current, parent); 
   
-  if (isConvertibleBvAtom(current)) {
+  if (hasLiftCache(current)) {
+    result = getLiftCache(current); 
+  }else if (isConvertibleBvAtom(current)) {
     result = convertBvAtom(current);
-    addToCache(current, result);
-  } else if (isConvertibleBvTerm(current)) {
-    result = convertBvTerm(current); 
+    addToLiftCache(current, result);
   } else {
     if (current.getNumChildren() == 0) {
-      result = current; 
+      result = current;
     } else {
       NodeBuilder<> builder(current.getKind());
       if (current.getMetaKind() == kind::metakind::PARAMETERIZED) {
         builder << current.getOperator();
       }
       for (unsigned i = 0; i < current.getNumChildren(); ++i) {
-        Node converted = getCache(current[i]);
+        Node converted = liftNode(current[i]);
         Assert (converted.getType() == current[i].getType()); 
         builder << converted; 
       }
       result = builder;
+      addToLiftCache(current, result);
     }
-    addToCache(current, result);
   }
   Assert (result != Node());
-  Debug("bv-to-bool") << "    =>" << result <<"\n"; 
-}
-
-
-BvToBoolVisitor::return_type BvToBoolVisitor::done(TNode node) {
-  Assert (hasCache(node)); 
-  Node result = getCache(node);
+  Assert(result.getType() == current.getType());
+  Debug("bv-to-bool") << "BvToBoolPreprocessor::liftNode " << current << " => \n" << result << "\n"; 
   return result; 
 }
 
-bool BvToBoolVisitor::hasBoolTerm(TNode node) {
-  return d_bvToBoolMap.find(node) != d_bvToBoolMap.end(); 
-}
 
-bool BvToBoolPreprocessor::matchesBooleanPatern(TNode current) {
-  // we are looking for something of the type (= (bvvar 1) (some predicate))
-  if (current.getKind() == kind::IFF &&
-      current[0].getKind() == kind::EQUAL &&
-      current[0][0].getType().isBitVector() &&
-      current[0][0].getType().getBitVectorSize() == 1 &&
-      current[0][0].getKind() == kind::VARIABLE &&
-      current[0][1].getKind() == kind::CONST_BITVECTOR) {
-    return true; 
-  }    
-  return false; 
-}
-
-
-void BvToBoolPreprocessor::liftBoolToBV(const std::vector<Node>& assertions, std::vector<Node>& new_assertions) {
-  BvToBoolVisitor bvToBoolVisitor;
-  
+void BvToBoolPreprocessor::liftBvToBool(const std::vector<Node>& assertions, std::vector<Node>& new_assertions) {
   for (unsigned i = 0; i < assertions.size(); ++i) {
-    if (matchesBooleanPatern(assertions[i])) {
-      TNode assertion = assertions[i]; 
-      TNode bv_var = assertion[0][0];
-      Assert (bv_var.getKind() == kind::VARIABLE &&
-              bv_var.getType().isBitVector() &&
-              bv_var.getType().getBitVectorSize() == 1);
-      Node bool_cond = NodeVisitor<BvToBoolVisitor>::run(bvToBoolVisitor, assertion[1]);
-      Assert (bool_cond.getType().isBoolean());
-      if (!bvToBoolVisitor.hasBoolTerm(bv_var)) {
-        Debug("bv-to-bool") << "BBvToBoolPreprocessor::liftBvToBoolBV candidate: " << bv_var <<"\n"; 
-        bvToBoolVisitor.storeBvToBool(bv_var, bool_cond); 
-      } else {
-        Debug("bv-to-bool") << "BvToBoolPreprocessor::liftBvToBoolBV multiple def " << bv_var <<"\n"; 
-      }
-    }
-  }
-  
-  for (unsigned i = 0; i < assertions.size(); ++i) {
-    Node new_assertion = NodeVisitor<BvToBoolVisitor>::run(bvToBoolVisitor,
-                                              assertions[i]);
+    Node new_assertion = liftNode(assertions[i]);
     new_assertions.push_back(new_assertion);
     Trace("bv-to-bool") << "  " << assertions[i] <<" => " << new_assertions[i] <<"\n"; 
   }
 }
+
+BvToBoolPreprocessor::Statistics::Statistics()
+  : d_numTermsLifted("theory::bv::BvToBoolPreprocess::NumberOfTermsLifted", 0)
+  , d_numAtomsLifted("theory::bv::BvToBoolPreprocess::NumberOfAtomsLifted", 0)
+  , d_numTermsForcedLifted("theory::bv::BvToBoolPreprocess::NumberOfTermsForcedLifted", 0)
+{
+  StatisticsRegistry::registerStat(&d_numTermsLifted);
+  StatisticsRegistry::registerStat(&d_numAtomsLifted);
+  StatisticsRegistry::registerStat(&d_numTermsForcedLifted);
+}
+
+BvToBoolPreprocessor::Statistics::~Statistics() {
+  StatisticsRegistry::unregisterStat(&d_numTermsLifted);
+  StatisticsRegistry::unregisterStat(&d_numAtomsLifted);
+  StatisticsRegistry::unregisterStat(&d_numTermsForcedLifted);
+}
index b349237280e941afd3e8600c382ad58db4c6feaa..28501ba96519b86ee0e1a28dc8b972f1524297a1 100644 (file)
@@ -16,6 +16,7 @@
 
 #include "cvc4_private.h"
 #include "theory/bv/theory_bv_utils.h"
+#include "util/statistics_registry.h"
 
 #ifndef __CVC4__THEORY__BV__BV_TO_BOOL_H
 #define __CVC4__THEORY__BV__BV_TO_BOOL_H
@@ -24,51 +25,43 @@ namespace CVC4 {
 namespace theory {
 namespace bv {
 
-typedef __gnu_cxx::hash_set<TNode, TNodeHashFunction> TNodeSet; 
-typedef __gnu_cxx::hash_map<Node, Node, TNodeHashFunction> NodeNodeMap; 
+typedef __gnu_cxx::hash_map<Node, Node, NodeHashFunction> NodeNodeMap; 
 
-class BvToBoolVisitor {
-  NodeNodeMap d_bvToBoolMap; 
-  NodeNodeMap d_cache;
+class BvToBoolPreprocessor {
+
+  struct Statistics {
+    IntStat d_numTermsLifted;
+    IntStat d_numAtomsLifted;
+    IntStat d_numTermsForcedLifted;
+    Statistics();
+    ~Statistics();
+  };
+  
+  NodeNodeMap d_liftCache;
+  NodeNodeMap d_boolCache;
   Node d_one;
   Node d_zero;
 
-  void addToCache(TNode term, Node new_term);
-  Node getCache(TNode term) const;
-  bool hasCache(TNode term) const; 
+  void addToBoolCache(TNode term, Node new_term);
+  Node getBoolCache(TNode term) const;
+  bool hasBoolCache(TNode term) const; 
+
+  void addToLiftCache(TNode term, Node new_term);
+  Node getLiftCache(TNode term) const;
+  bool hasLiftCache(TNode term) const; 
   
   bool isConvertibleBvTerm(TNode node);
   bool isConvertibleBvAtom(TNode node);
-  Node getBoolForBvTerm(TNode node);
   Node convertBvAtom(TNode node);
   Node convertBvTerm(TNode node);
-  void check(TNode current, TNode parent);
+  Node liftNode(TNode current);
+  Statistics d_statistics;
 public:
-  typedef Node return_type;
-  BvToBoolVisitor()
-    : d_bvToBoolMap(), 
-      d_cache(),
-      d_one(utils::mkConst(BitVector(1, 1u))),
-      d_zero(utils::mkConst(BitVector(1, 0u)))
-  {}
-  void start(TNode node);
-  bool alreadyVisited(TNode current, TNode parent);
-  void visit(TNode current, TNode parent);
-  return_type done(TNode node);
-  void storeBvToBool(TNode bv_term, TNode bool_term);
-  bool hasBoolTerm(TNode node); 
+  BvToBoolPreprocessor();
+  void liftBvToBool(const std::vector<Node>& assertions, std::vector<Node>& new_assertions);
 }; 
 
 
-class BvToBoolPreprocessor {
-  bool matchesBooleanPatern(TNode node);
-public:
-  BvToBoolPreprocessor()
-  {}
-  ~BvToBoolPreprocessor() {}
-  void liftBoolToBV(const std::vector<Node>& assertions, std::vector<Node>& new_assertions);
-}; 
-
 
 }/* CVC4::theory::bv namespace */
 }/* CVC4::theory namespace */
diff --git a/src/theory/bv/eager_bitblaster.h b/src/theory/bv/eager_bitblaster.h
new file mode 100644 (file)
index 0000000..da73c7f
--- /dev/null
@@ -0,0 +1,163 @@
+/*********************                                                        */
+/*! \file eager_bitblaster.h
+ ** \verbatim
+ ** Original author: Liana Hadarean
+ ** Major contributors: none
+ ** Minor contributors (to current version): lianah
+ ** 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 
+ **
+ ** Bitblaster for the lazy bv solver. 
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef __CVC4__EAGER__BITBLASTER_H
+#define __CVC4__EAGER__BITBLASTER_H
+
+
+#include "bitblaster_template.h"
+#include "theory/theory_registrar.h"
+#include "prop/cnf_stream.h"
+#include "prop/sat_solver_factory.h"
+#include "theory/bv/options.h"
+
+namespace CVC4 {
+namespace theory {
+namespace bv {
+
+
+class BitblastingRegistrar: public prop::Registrar {
+  EagerBitblaster* d_bitblaster; 
+public:
+  BitblastingRegistrar(EagerBitblaster* bb)
+    : d_bitblaster(bb)
+  {}
+  void preRegister(Node n) {
+    d_bitblaster->bbAtom(n); 
+  };
+
+};/* class Registrar */
+
+EagerBitblaster::EagerBitblaster()
+  : TBitblaster<Node>()
+  , d_bbAtoms()
+{
+  d_bitblastingRegistrar = new BitblastingRegistrar(this); 
+  d_nullContext = new context::Context();
+
+  d_satSolver = prop::SatSolverFactory::createMinisat(d_nullContext, "EagerBitblaster");
+  d_cnfStream = new prop::TseitinCnfStream(d_satSolver, d_bitblastingRegistrar, d_nullContext);
+  
+  MinisatEmptyNotify* notify = new MinisatEmptyNotify();
+  d_satSolver->setNotify(notify);
+}
+
+EagerBitblaster::~EagerBitblaster() {
+  delete d_cnfStream;
+  delete d_satSolver;
+  delete d_nullContext;
+  delete d_bitblastingRegistrar;
+}
+
+void EagerBitblaster::bbFormula(TNode node) {
+  d_cnfStream->convertAndAssert(node, false, false); 
+}
+
+/**
+ * Bitblasts the atom, assigns it a marker literal, adding it to the SAT solver
+ * NOTE: duplicate clauses are not detected because of marker literal
+ * @param node the atom to be bitblasted
+ *
+ */
+void EagerBitblaster::bbAtom(TNode node) {
+  node = node.getKind() == kind::NOT?  node[0] : node;
+  if (node.getKind() == kind::BITVECTOR_BITOF)
+    return; 
+  if (hasBBAtom(node)) {
+    return;
+  }
+
+  Debug("bitvector-bitblast") << "Bitblasting node " << node <<"\n";
+
+  // the bitblasted definition of the atom
+  Node normalized = Rewriter::rewrite(node);
+  Node atom_bb = normalized.getKind() != kind::CONST_BOOLEAN ?
+      Rewriter::rewrite(d_atomBBStrategies[normalized.getKind()](normalized, this)) :
+      normalized;
+  // asserting that the atom is true iff the definition holds
+  Node atom_definition = utils::mkNode(kind::IFF, node, atom_bb);
+
+  AlwaysAssert (options::bitblastMode() == theory::bv::BITBLAST_MODE_EAGER); 
+  storeBBAtom(node, atom_definition);
+  d_cnfStream->convertAndAssert(atom_definition, false, false);
+}
+
+void EagerBitblaster::storeBBAtom(TNode atom, Node atom_bb) {
+  // no need to store the definition for the lazy bit-blaster
+  d_bbAtoms.insert(atom); 
+}
+
+bool EagerBitblaster::hasBBAtom(TNode atom) const {
+  return d_bbAtoms.find(atom) != d_bbAtoms.end(); 
+}
+
+void EagerBitblaster::bbTerm(TNode node, Bits& bits) {
+  if (hasBBTerm(node)) {
+    getBBTerm(node, bits);
+    return;
+  }
+
+  Debug("bitvector-bitblast") << "Bitblasting node " << node <<"\n";
+
+  d_termBBStrategies[node.getKind()] (node, bits, this);
+
+  Assert (bits.size() == utils::getSize(node));
+
+  storeBBTerm(node, bits);
+}
+
+void EagerBitblaster::makeVariable(TNode var, Bits& bits) {
+  Assert(bits.size() == 0);
+  for (unsigned i = 0; i < utils::getSize(var); ++i) {
+    bits.push_back(utils::mkBitOf(var, i)); 
+  }
+}
+
+Node EagerBitblaster::getBBAtom(TNode node) const {
+  return node; 
+}
+
+
+/**
+ * Calls the solve method for the Sat Solver.
+ *
+ * @return true for sat, and false for unsat
+ */
+
+bool EagerBitblaster::solve() {
+  if (Trace.isOn("bitvector")) {
+    Trace("bitvector") << "EagerBitblaster::solve(). \n";
+  }
+  Debug("bitvector") << "EagerBitblaster::solve(). \n";
+  // TODO: clear some memory
+  // if (something) {
+  //   NodeManager* nm= NodeManager::currentNM();
+  //   Rewriter::garbageCollect();
+  //   nm->reclaimZombiesUntil(options::zombieHuntThreshold());
+  // }
+  return prop::SAT_VALUE_TRUE == d_satSolver->solve();
+}
+
+
+} /*bv namespace */
+} /* theory namespace */
+} /* CVC4 namespace*/
+
+
+
+#endif
index cf83150e1ae7b301eaa5e292ce1d51dac4dcf9d6..4b2bba741c5e31ebbc8e4063bd168938452aa42f 100644 (file)
@@ -8,7 +8,7 @@ theory THEORY_BV ::CVC4::theory::bv::TheoryBV "theory/bv/theory_bv.h"
 typechecker "theory/bv/theory_bv_type_rules.h"
 
 properties finite
-properties check propagate presolve
+properties check propagate presolve ppStaticLearn
 
 rewriter ::CVC4::theory::bv::TheoryBVRewriter "theory/bv/theory_bv_rewriter.h"
 
@@ -70,6 +70,10 @@ operator BITVECTOR_SLE 2 "bit-vector signed less than or equal"
 operator BITVECTOR_SGT 2 "bit-vector signed greater than"
 operator BITVECTOR_SGE 2 "signed greater than or equal"
 
+operator BITVECTOR_EAGER_ATOM 1 "formula to be treated as a bv atom via eager bit-blasting"
+operator BITVECTOR_ACKERMANIZE_UDIV 1 "term to be treated as a variable; used for eager bitblasting ackerman expansion of bvudiv"
+operator BITVECTOR_ACKERMANIZE_UREM 1 "term to be treated as a variable; used for eager bitblasting ackerman expansion of bvurem"
+
 constant BITVECTOR_BITOF_OP \
        ::CVC4::BitVectorBitOf \
        ::CVC4::BitVectorBitOfHashFunction \
@@ -167,6 +171,10 @@ typerule BITVECTOR_SLE ::CVC4::theory::bv::BitVectorPredicateTypeRule
 typerule BITVECTOR_SGT ::CVC4::theory::bv::BitVectorPredicateTypeRule
 typerule BITVECTOR_SGE ::CVC4::theory::bv::BitVectorPredicateTypeRule
 
+typerule BITVECTOR_EAGER_ATOM ::CVC4::theory::bv::BitVectorEagerAtomTypeRule
+typerule BITVECTOR_ACKERMANIZE_UDIV ::CVC4::theory::bv::BitVectorAckermanizationUdivTypeRule
+typerule BITVECTOR_ACKERMANIZE_UREM ::CVC4::theory::bv::BitVectorAckermanizationUremTypeRule
+
 typerule BITVECTOR_EXTRACT_OP ::CVC4::theory::bv::BitVectorExtractOpTypeRule
 typerule BITVECTOR_EXTRACT ::CVC4::theory::bv::BitVectorExtractTypeRule
 typerule BITVECTOR_BITOF   ::CVC4::theory::bv::BitVectorBitOfTypeRule
diff --git a/src/theory/bv/lazy_bitblaster.h b/src/theory/bv/lazy_bitblaster.h
new file mode 100644 (file)
index 0000000..013e230
--- /dev/null
@@ -0,0 +1,503 @@
+/*********************                                                        */
+/*! \file lazy_bitblaster.h
+** \verbatim
+** Original author: Liana Hadarean
+** Major contributors: none
+** Minor contributors (to current version): lianah
+** 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 
+**
+** Bitblaster for the lazy bv solver. 
+**/
+
+#include "cvc4_private.h"
+
+#ifndef __CVC4__LAZY__BITBLASTER_H
+#define __CVC4__LAZY__BITBLASTER_H
+
+
+#include "bitblaster_template.h"
+#include "theory_bv_utils.h"
+#include "theory/rewriter.h"
+#include "prop/cnf_stream.h"
+#include "prop/sat_solver.h"
+#include "prop/sat_solver_factory.h"
+#include "theory/bv/theory_bv.h"
+#include "theory/bv/options.h"
+#include "theory/theory_model.h"
+#include "theory/bv/abstraction.h"
+
+namespace CVC4 {
+namespace theory {
+namespace bv {
+
+TLazyBitblaster::TLazyBitblaster(context::Context* c, bv::TheoryBV* bv, const std::string name, bool emptyNotify)
+  : TBitblaster()
+  , d_bv(bv)
+  , d_ctx(c)
+  , d_assertedAtoms(c)
+  , d_explanations(c)
+  , d_variables()
+  , d_bbAtoms()
+  , d_abstraction(NULL)
+  , d_emptyNotify(emptyNotify)
+  , d_name(name)
+  , d_statistics(name) {
+  d_satSolver = prop::SatSolverFactory::createMinisat(c, name);
+  d_nullRegistrar = new prop::NullRegistrar();
+  d_nullContext = new context::Context();
+  d_cnfStream = new prop::TseitinCnfStream(d_satSolver,
+                                           d_nullRegistrar,
+                                           d_nullContext);
+  
+  prop::BVSatSolverInterface::Notify* notify = d_emptyNotify ?
+    (prop::BVSatSolverInterface::Notify*) new MinisatEmptyNotify() :
+    (prop::BVSatSolverInterface::Notify*) new MinisatNotify(d_cnfStream, bv, this);
+
+  d_satSolver->setNotify(notify);
+}
+
+void TLazyBitblaster::setAbstraction(AbstractionModule* abs) {
+  d_abstraction = abs; 
+}
+
+TLazyBitblaster::~TLazyBitblaster() {
+  delete d_cnfStream;
+  delete d_nullRegistrar;
+  delete d_nullContext;
+  delete d_satSolver;
+}
+
+
+/**
+ * Bitblasts the atom, assigns it a marker literal, adding it to the SAT solver
+ * NOTE: duplicate clauses are not detected because of marker literal
+ * @param node the atom to be bitblasted
+ *
+ */
+void TLazyBitblaster::bbAtom(TNode node) {
+  node = node.getKind() == kind::NOT?  node[0] : node;
+
+  if (hasBBAtom(node)) {
+    return;
+  }
+
+  // make sure it is marked as an atom
+  addAtom(node);
+
+  Debug("bitvector-bitblast") << "Bitblasting node " << node <<"\n";
+  ++d_statistics.d_numAtoms;
+
+  /// if we are using bit-vector abstraction bit-blast the original interpretation
+  if (options::bvAbstraction() &&
+      d_abstraction != NULL &&
+      d_abstraction->isAbstraction(node)) {
+    // node must be of the form P(args) = bv1
+    Node expansion = Rewriter::rewrite(d_abstraction->getInterpretation(node));
+
+    Node atom_bb;
+    if (expansion.getKind() == kind::CONST_BOOLEAN) {
+      atom_bb = expansion;
+    } else {
+      Assert (expansion.getKind() == kind::AND); 
+      std::vector<Node> atoms; 
+      for (unsigned i = 0; i < expansion.getNumChildren(); ++i) {
+        Node normalized_i = Rewriter::rewrite(expansion[i]);
+        Node atom_i = normalized_i.getKind() != kind::CONST_BOOLEAN ?
+          Rewriter::rewrite(d_atomBBStrategies[normalized_i.getKind()](normalized_i, this)) :
+          normalized_i;
+        atoms.push_back(atom_i);
+      }
+      atom_bb = utils::mkAnd(atoms);
+    }
+    Assert (!atom_bb.isNull()); 
+    Node atom_definition = utils::mkNode(kind::IFF, node, atom_bb);
+    storeBBAtom(node, atom_bb);
+    d_cnfStream->convertAndAssert(atom_definition, false, false); 
+    return; 
+  }
+
+  // the bitblasted definition of the atom
+  Node normalized = Rewriter::rewrite(node);
+  Node atom_bb = normalized.getKind() != kind::CONST_BOOLEAN ?
+    Rewriter::rewrite(d_atomBBStrategies[normalized.getKind()](normalized, this)) :
+    normalized;
+  // asserting that the atom is true iff the definition holds
+  Node atom_definition = utils::mkNode(kind::IFF, node, atom_bb);
+  storeBBAtom(node, atom_bb);
+  d_cnfStream->convertAndAssert(atom_definition, false, false);
+}
+
+void TLazyBitblaster::storeBBAtom(TNode atom, Node atom_bb) {
+  // no need to store the definition for the lazy bit-blaster
+  d_bbAtoms.insert(atom); 
+}
+
+bool TLazyBitblaster::hasBBAtom(TNode atom) const {
+  return d_bbAtoms.find(atom) != d_bbAtoms.end(); 
+}
+
+
+void TLazyBitblaster::makeVariable(TNode var, Bits& bits) {
+  Assert(bits.size() == 0);
+  for (unsigned i = 0; i < utils::getSize(var); ++i) {
+    bits.push_back(utils::mkBitOf(var, i)); 
+  }
+  d_variables.insert(var); 
+}
+
+uint64_t TLazyBitblaster::computeAtomWeight(TNode node, NodeSet& seen) {
+  node = node.getKind() == kind::NOT?  node[0] : node;
+
+  Node atom_bb = Rewriter::rewrite(d_atomBBStrategies[node.getKind()](node, this));
+  uint64_t size = utils::numNodes(atom_bb, seen);
+  return size;
+}
+
+// cnf conversion ensures the atom represents itself
+Node TLazyBitblaster::getBBAtom(TNode node) const {
+  return node; 
+}
+
+void TLazyBitblaster::bbTerm(TNode node, Bits& bits) {
+
+  if (hasBBTerm(node)) {
+    getBBTerm(node, bits);
+    return;
+  }
+
+  Debug("bitvector-bitblast") << "Bitblasting node " << node <<"\n";
+  ++d_statistics.d_numTerms;
+
+  d_termBBStrategies[node.getKind()] (node, bits,this);
+
+  Assert (bits.size() == utils::getSize(node));
+
+  storeBBTerm(node, bits);
+}
+/// Public methods
+
+void TLazyBitblaster::addAtom(TNode atom) {
+  d_cnfStream->ensureLiteral(atom);
+  prop::SatLiteral lit = d_cnfStream->getLiteral(atom);
+  d_satSolver->addMarkerLiteral(lit);
+}
+
+void TLazyBitblaster::explain(TNode atom, std::vector<TNode>& explanation) {
+  prop::SatLiteral lit = d_cnfStream->getLiteral(atom);
+
+  ++(d_statistics.d_numExplainedPropagations);
+  if (options::bvEagerExplanations()) {
+    Assert (d_explanations.find(lit) != d_explanations.end());
+    const std::vector<prop::SatLiteral>& literal_explanation = d_explanations[lit].get();
+    for (unsigned i = 0; i < literal_explanation.size(); ++i) {
+      explanation.push_back(d_cnfStream->getNode(literal_explanation[i]));
+    }
+    return; 
+  }
+  
+  std::vector<prop::SatLiteral> literal_explanation;
+  d_satSolver->explain(lit, literal_explanation);
+  for (unsigned i = 0; i < literal_explanation.size(); ++i) {
+    explanation.push_back(d_cnfStream->getNode(literal_explanation[i]));
+  }
+}
+
+
+/*
+ * Asserts the clauses corresponding to the atom to the Sat Solver
+ * by turning on the marker literal (i.e. setting it to false)
+ * @param node the atom to be asserted
+ *
+ */
+
+bool TLazyBitblaster::propagate() {
+  return d_satSolver->propagate() == prop::SAT_VALUE_TRUE;
+}
+
+bool TLazyBitblaster::assertToSat(TNode lit, bool propagate) {
+  // strip the not
+  TNode atom;
+  if (lit.getKind() == kind::NOT) {
+    atom = lit[0];
+  } else {
+    atom = lit;
+  }
+
+  Assert (hasBBAtom(atom));
+
+  prop::SatLiteral markerLit = d_cnfStream->getLiteral(atom);
+
+  if(lit.getKind() == kind::NOT) {
+    markerLit = ~markerLit;
+  }
+
+  Debug("bitvector-bb") << "TheoryBV::TLazyBitblaster::assertToSat asserting node: " << atom <<"\n";
+  Debug("bitvector-bb") << "TheoryBV::TLazyBitblaster::assertToSat with literal:   " << markerLit << "\n";
+
+  prop::SatValue ret = d_satSolver->assertAssumption(markerLit, propagate);
+
+  d_assertedAtoms.push_back(markerLit);
+
+  return ret == prop::SAT_VALUE_TRUE || ret == prop::SAT_VALUE_UNKNOWN;
+}
+
+/**
+ * Calls the solve method for the Sat Solver.
+ * passing it the marker literals to be asserted
+ *
+ * @return true for sat, and false for unsat
+ */
+
+bool TLazyBitblaster::solve() {
+  if (Trace.isOn("bitvector")) {
+    Trace("bitvector") << "TLazyBitblaster::solve() asserted atoms ";
+    context::CDList<prop::SatLiteral>::const_iterator it = d_assertedAtoms.begin();
+    for (; it != d_assertedAtoms.end(); ++it) {
+      Trace("bitvector") << "     " << d_cnfStream->getNode(*it) << "\n";
+    }
+  }
+  Debug("bitvector") << "TLazyBitblaster::solve() asserted atoms " << d_assertedAtoms.size() <<"\n";
+  return prop::SAT_VALUE_TRUE == d_satSolver->solve();
+}
+
+prop::SatValue TLazyBitblaster::solveWithBudget(unsigned long budget) {
+  if (Trace.isOn("bitvector")) {
+    Trace("bitvector") << "TLazyBitblaster::solveWithBudget() asserted atoms ";
+    context::CDList<prop::SatLiteral>::const_iterator it = d_assertedAtoms.begin();
+    for (; it != d_assertedAtoms.end(); ++it) {
+      Trace("bitvector") << "     " << d_cnfStream->getNode(*it) << "\n";
+    }
+  }
+  Debug("bitvector") << "TLazyBitblaster::solveWithBudget() asserted atoms " << d_assertedAtoms.size() <<"\n";
+  return d_satSolver->solve(budget);
+}
+
+
+void TLazyBitblaster::getConflict(std::vector<TNode>& conflict) {
+  prop::SatClause conflictClause;
+  d_satSolver->getUnsatCore(conflictClause);
+
+  for (unsigned i = 0; i < conflictClause.size(); i++) {
+    prop::SatLiteral lit = conflictClause[i];
+    TNode atom = d_cnfStream->getNode(lit);
+    Node  not_atom;
+    if (atom.getKind() == kind::NOT) {
+      not_atom = atom[0];
+    } else {
+      not_atom = NodeManager::currentNM()->mkNode(kind::NOT, atom);
+    }
+    conflict.push_back(not_atom);
+  }
+}
+
+TLazyBitblaster::Statistics::Statistics(const std::string& prefix) :
+  d_numTermClauses("theory::bv::"+prefix+"::NumberOfTermSatClauses", 0),
+  d_numAtomClauses("theory::bv::"+prefix+"::NumberOfAtomSatClauses", 0),
+  d_numTerms("theory::bv::"+prefix+"::NumberOfBitblastedTerms", 0),
+  d_numAtoms("theory::bv::"+prefix+"::NumberOfBitblastedAtoms", 0),
+  d_numExplainedPropagations("theory::bv::"+prefix+"::NumberOfExplainedPropagations", 0),
+  d_numBitblastingPropagations("theory::bv::"+prefix+"::NumberOfBitblastingPropagations", 0),
+  d_bitblastTimer("theory::bv::"+prefix+"::BitblastTimer")
+{
+  StatisticsRegistry::registerStat(&d_numTermClauses);
+  StatisticsRegistry::registerStat(&d_numAtomClauses);
+  StatisticsRegistry::registerStat(&d_numTerms);
+  StatisticsRegistry::registerStat(&d_numAtoms);
+  StatisticsRegistry::registerStat(&d_numExplainedPropagations);
+  StatisticsRegistry::registerStat(&d_numBitblastingPropagations);
+  StatisticsRegistry::registerStat(&d_bitblastTimer);
+}
+
+
+TLazyBitblaster::Statistics::~Statistics() {
+  StatisticsRegistry::unregisterStat(&d_numTermClauses);
+  StatisticsRegistry::unregisterStat(&d_numAtomClauses);
+  StatisticsRegistry::unregisterStat(&d_numTerms);
+  StatisticsRegistry::unregisterStat(&d_numAtoms);
+  StatisticsRegistry::unregisterStat(&d_numExplainedPropagations);
+  StatisticsRegistry::unregisterStat(&d_numBitblastingPropagations);
+  StatisticsRegistry::unregisterStat(&d_bitblastTimer);
+}
+
+bool TLazyBitblaster::MinisatNotify::notify(prop::SatLiteral lit) {
+  if(options::bvEagerExplanations()) {
+    // compute explanation
+    if (d_lazyBB->d_explanations.find(lit) == d_lazyBB->d_explanations.end()) {
+      std::vector<prop::SatLiteral> literal_explanation;
+      d_lazyBB->d_satSolver->explain(lit, literal_explanation);
+      d_lazyBB->d_explanations.insert(lit, literal_explanation);
+    } else {
+      // we propagated it at a lower level
+      return true; 
+    }
+  }
+  ++(d_lazyBB->d_statistics.d_numBitblastingPropagations);
+  TNode atom = d_cnf->getNode(lit); 
+  return d_bv->storePropagation(atom, SUB_BITBLAST);
+}
+
+void TLazyBitblaster::MinisatNotify::notify(prop::SatClause& clause) {
+  if (clause.size() > 1) {
+    NodeBuilder<> lemmab(kind::OR);
+    for (unsigned i = 0; i < clause.size(); ++ i) {
+      lemmab << d_cnf->getNode(clause[i]);
+    }
+    Node lemma = lemmab;
+    d_bv->d_out->lemma(lemma);
+  } else {
+    d_bv->d_out->lemma(d_cnf->getNode(clause[0]));
+  }
+}
+
+void TLazyBitblaster::MinisatNotify::safePoint() {
+  d_bv->d_out->safePoint();
+}
+
+EqualityStatus TLazyBitblaster::getEqualityStatus(TNode a, TNode b) {
+
+  // We don't want to bit-blast every possibly expensive term for the sake of equality checking
+  if (hasBBTerm(a) && hasBBTerm(b)) {
+
+    Bits a_bits, b_bits;
+    getBBTerm(a, a_bits);
+    getBBTerm(b, b_bits);
+    theory::EqualityStatus status = theory::EQUALITY_TRUE_IN_MODEL;
+    for (unsigned i = 0; i < a_bits.size(); ++ i) {
+      if (d_cnfStream->hasLiteral(a_bits[i]) && d_cnfStream->hasLiteral(b_bits[i])) {
+        prop::SatLiteral a_lit = d_cnfStream->getLiteral(a_bits[i]);
+        prop::SatValue a_lit_value = d_satSolver->value(a_lit);
+        if (a_lit_value != prop::SAT_VALUE_UNKNOWN) {
+          prop::SatLiteral b_lit = d_cnfStream->getLiteral(b_bits[i]);
+          prop::SatValue b_lit_value = d_satSolver->value(b_lit);
+          if (b_lit_value != prop::SAT_VALUE_UNKNOWN) {
+            if (a_lit_value != b_lit_value) {
+              return theory::EQUALITY_FALSE_IN_MODEL;
+            }
+          } else {
+            status = theory::EQUALITY_UNKNOWN;
+          }
+        } {
+          status = theory::EQUALITY_UNKNOWN;
+        }
+      } else {
+        status = theory::EQUALITY_UNKNOWN;
+      }
+    }
+
+    return status;
+
+  } else {
+    return theory::EQUALITY_UNKNOWN;
+  }
+}
+
+
+bool TLazyBitblaster::isSharedTerm(TNode node) {
+  return d_bv->d_sharedTermsSet.find(node) != d_bv->d_sharedTermsSet.end();
+}
+
+bool TLazyBitblaster::hasValue(TNode a) {
+  Assert (hasBBTerm(a)); 
+  Bits bits;
+  getBBTerm(a, bits); 
+  for (int i = bits.size() -1; i >= 0; --i) {
+    prop::SatValue bit_value;
+    if (d_cnfStream->hasLiteral(bits[i])) {
+      prop::SatLiteral bit = d_cnfStream->getLiteral(bits[i]);
+      bit_value = d_satSolver->value(bit);
+      if (bit_value ==  prop::SAT_VALUE_UNKNOWN)
+        return false;
+    } else {
+      return false;
+    }
+  }
+  return true;
+}
+/**
+ * Returns the value a is currently assigned to in the SAT solver
+ * or null if the value is completely unassigned.
+ *
+ * @param a
+ * @param fullModel whether to create a "full model," i.e., add
+ * constants to equivalence classes that don't already have them
+ *
+ * @return
+ */
+Node TLazyBitblaster::getVarValue(TNode a, bool fullModel) {
+  if (!hasBBTerm(a)) {
+    Assert(isSharedTerm(a));
+    return Node();
+  }
+  Bits bits;
+  getBBTerm(a, bits);
+  Integer value(0);
+  for (int i = bits.size() -1; i >= 0; --i) {
+    prop::SatValue bit_value;
+    if (d_cnfStream->hasLiteral(bits[i])) {
+      prop::SatLiteral bit = d_cnfStream->getLiteral(bits[i]);
+      bit_value = d_satSolver->value(bit);
+      Assert (bit_value != prop::SAT_VALUE_UNKNOWN);
+    } else {
+      // the bit is unconstrainted so we can give it an arbitrary value
+      bit_value = prop::SAT_VALUE_FALSE;
+    }
+    Integer bit_int = bit_value == prop::SAT_VALUE_TRUE ? Integer(1) : Integer(0);
+    value = value * 2 + bit_int;
+  }
+  return utils::mkConst(BitVector(bits.size(), value));
+}
+
+void TLazyBitblaster::collectModelInfo(TheoryModel* m, bool fullModel) {
+  __gnu_cxx::hash_set<TNode, TNodeHashFunction>::iterator it = d_variables.begin();
+  for (; it!= d_variables.end(); ++it) {
+    TNode var = *it;
+    if (Theory::theoryOf(var) == theory::THEORY_BV || isSharedTerm(var))  {
+      Node const_value = getVarValue(var, fullModel);
+      if(const_value == Node()) {
+        if( fullModel ){
+          // if the value is unassigned just set it to zero
+          const_value = utils::mkConst(BitVector(utils::getSize(var), 0u));
+        }
+      }
+      if(const_value != Node()) {
+        Debug("bitvector-model") << "TLazyBitblaster::collectModelInfo (assert (= "
+                                 << var << " "
+                                 << const_value << "))\n";
+        m->assertEquality(var, const_value, true);
+      }
+    }
+  }
+}
+
+void TLazyBitblaster::clearSolver() {
+  Assert (d_ctx->getLevel() == 0); 
+  delete d_satSolver;
+  delete d_cnfStream;
+  d_assertedAtoms = context::CDList<prop::SatLiteral>(d_ctx);
+  d_explanations = ExplanationMap(d_ctx);
+  d_bbAtoms.clear();
+  d_variables.clear();
+  d_termCache.clear(); 
+
+  // recreate sat solver
+  d_satSolver = prop::SatSolverFactory::createMinisat(d_ctx);
+  d_cnfStream = new prop::TseitinCnfStream(d_satSolver,
+                                           new prop::NullRegistrar(),
+                                           new context::Context());
+
+  prop::BVSatSolverInterface::Notify* notify = d_emptyNotify ?
+    (prop::BVSatSolverInterface::Notify*) new MinisatEmptyNotify() :
+    (prop::BVSatSolverInterface::Notify*) new MinisatNotify(d_cnfStream, d_bv, this);
+  d_satSolver->setNotify(notify);
+}
+
+} /*bv namespace */
+} /* theory namespace */
+} /* CVC4 namespace*/
+
+#endif
index 077299d1fcaa9b6a64bed4406d58ba51e70ecdab..f59d675a7365caa44dda0e978c2d09ce658575b7 100644 (file)
@@ -5,28 +5,61 @@
 
 module BV "theory/bv/options.h" Bitvector theory
 
-option bitvectorEagerBitblast --bitblast-eager bool
- eagerly bitblast the bitvectors to the main SAT solver
+# Option to set the bit-blasting mode (lazy, eager, eager-aig)
 
-option bitvectorShareLemmas --bitblast-share-lemmas bool
- share lemmas from the bitblasting solver with the main solver
+option bitblastMode --bitblast=MODE CVC4::theory::bv::BitblastMode :handler CVC4::theory::bv::stringToBitblastMode :default CVC4::theory::bv::BITBLAST_MODE_LAZY :read-write :include "theory/bv/bitblast_mode.h" :handler-include "theory/bv/options_handlers.h"
+ choose bitblasting mode, see --bitblast=help
 
-option bitvectorEagerFullcheck --bitblast-eager-fullcheck bool
- check the bitblasting eagerly
+# Options for eager bit-blasting
+option bitvectorAig --bitblast-aig bool :default false :read-write :link --bitblast=eager
+ bitblast by first converting to AIG (only if --bitblast=eager)
+
+expert-option bitvectorAigSimplifications --bv-aig-simp=FILE std::string :default "" :read-write :link --bitblast-aig
+ abc command to run AIG simplifications
+
+# Options for lazy bit-blasting  
+
+option bitvectorPropagate --bv-propagate bool :default true :read-write :link --bitblast=lazy 
+ use bit-vector propagation in the bit-blaster
+
+option bitvectorEqualitySolver --bv-eq-solver bool :default true :read-write :link --bitblast=lazy
+ use the equality engine for the bit-vector theory (only if --bitblast=lazy)
 
-option bitvectorInequalitySolver --bv-inequality-solver bool :default true
- turn on the inequality solver for the bit-vector theory 
+option bitvectorEqualitySlicer --bv-eq-slicer=MODE CVC4::theory::bv::BvSlicerMode :handler CVC4::theory::bv::stringToBvSlicerMode :default CVC4::theory::bv::BITVECTOR_SLICER_OFF :read-write :include "theory/bv/bitblast_mode.h" :handler-include "theory/bv/options_handlers.h" :read-write :link --bv-eq-solver
+ turn on the slicing equality solver for the bit-vector theory (only if --bitblast=lazy)
 
-option bitvectorCoreSolver --bv-core-solver bool
- turn on the core solver for the bit-vector theory 
+option bitvectorInequalitySolver --bv-inequality-solver bool :default true :read-write :link --bitblast=lazy
+ turn on the inequality solver for the bit-vector theory (only if --bitblast=lazy)
+
+option bitvectorAlgebraicSolver --bv-algebraic-solver bool :default true :read-write :link --bitblast=lazy
+ turn on the algebraic solver for the bit-vector theory (only if --bitblast=lazy)
+expert-option bitvectorAlgebraicBudget --bv-algebraic-budget unsigned :default 1500 :read-write :link --bv-algebraic-solver
+ the budget allowed for the algebraic solver in number of SAT conflicts
 
-option bvToBool --bv-to-bool bool
+# General options
+
+option bitvectorToBool --bv-to-bool bool :default false :read-write 
  lift bit-vectors of size 1 to booleans when possible
 
-option bvPropagate --bv-propagate bool :default true
- use bit-vector propagation in the bit-blaster
+option bitvectorDivByZeroConst --bv-div-zero-const bool :default false
+ always return -1 on division by zero
+
+expert-option bvAbstraction --bv-abstraction bool :default false :read-write
+ mcm benchmark abstraction 
+
+expert-option skolemizeArguments --bv-skolemize bool :default false :read-write 
+ skolemize arguments for bv abstraction (only does something if --bv-abstraction is on)
 
-option bvEquality --bv-eq bool :default true
- use the equality engine for the bit-vector theory
+expert-option bvNumFunc --bv-num-func=NUM unsigned :default 1
+ number of function symbols in conflicts that are generalized
+
+expert-option bvEagerExplanations --bv-eager-explanations bool :default false :read-write
+ compute bit-blasting propagation explanations eagerly
+
+expert-option bitvectorQuickXplain --bv-quick-xplain bool :default false
+ minimize bv conflicts using the QuickXplain algorithm
  
 endmodule
diff --git a/src/theory/bv/options_handlers.h b/src/theory/bv/options_handlers.h
new file mode 100644 (file)
index 0000000..bc01d4d
--- /dev/null
@@ -0,0 +1,138 @@
+/*********************                                                        */
+/*! \file options_handlers.h
+ ** \verbatim
+ ** Original author: Liana Hadarean
+ ** Major contributors: none
+ ** 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 Custom handlers and predicates for TheoryBV options
+ **
+ ** Custom handlers and predicates for TheoryBV options.
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef __CVC4__THEORY__BV__OPTIONS_HANDLERS_H
+#define __CVC4__THEORY__BV__OPTIONS_HANDLERS_H
+
+#include "theory/bv/bitblast_mode.h"
+#include "main/options.h"
+
+namespace CVC4 {
+namespace theory {
+namespace bv {
+
+static const std::string bitblastingModeHelp = "\
+Bit-blasting modes currently supported by the --bitblast option:\n\
+\n\
+lazy (default)\n\
++ Separate boolean structure and term reasoning betwen the core\n\
+  SAT solver and the bv SAT solver\n\
+\n\
+eager\n\
++ Bitblast eagerly to bv SAT solver\n\
+\n\
+aig\n\
++ Bitblast eagerly to bv SAT solver by converting to AIG\n\
+";
+
+inline BitblastMode stringToBitblastMode(std::string option, std::string optarg, SmtEngine* smt) throw(OptionException) {
+  if(optarg == "lazy") {
+    if (!options::bitvectorPropagate.wasSetByUser()) {
+      options::bitvectorPropagate.set(true);
+    }
+    if (!options::bitvectorEqualitySolver.wasSetByUser()) {
+      options::bitvectorEqualitySolver.set(true);
+    }
+    if (!options::bitvectorEqualitySlicer.wasSetByUser()) {
+      if (options::incrementalSolving()) {
+        options::bitvectorEqualitySlicer.set(BITVECTOR_SLICER_OFF);
+      } else {
+        options::bitvectorEqualitySlicer.set(BITVECTOR_SLICER_AUTO);
+      }
+    }
+    
+    if (!options::bitvectorInequalitySolver.wasSetByUser()) {
+      options::bitvectorInequalitySolver.set(true);
+    }
+    if (!options::bitvectorAlgebraicSolver.wasSetByUser()) {
+      options::bitvectorAlgebraicSolver.set(true);
+    }
+    return BITBLAST_MODE_LAZY;
+  } else if(optarg == "eager") {
+    if (options::produceModels()) {
+      throw OptionException(std::string("Eager bit-blasting does not currently support model generation. \n\
+                                         Try --bitblast=lazy")); 
+    }
+
+    if (options::incrementalSolving() &&
+        options::incrementalSolving.wasSetByUser()) {
+      throw OptionException(std::string("Eager bit-blasting does not currently support incremental mode. \n\
+                                         Try --bitblast=lazy"));
+    }
+    
+    if (!options::bitvectorAig.wasSetByUser()) {
+      options::bitvectorAig.set(true);
+    }
+    if (!options::bitvectorAigSimplifications.wasSetByUser()) {
+      // due to a known bug in abc switching to using drw instead of rw
+      options::bitvectorAigSimplifications.set("balance;drw");
+    }
+    if (!options::bitvectorToBool.wasSetByUser()) {
+      options::bitvectorToBool.set(true);
+    }
+
+    if (!options::bvAbstraction.wasSetByUser() &&
+        !options::skolemizeArguments.wasSetByUser()) {
+      options::bvAbstraction.set(true);
+      options::skolemizeArguments.set(true); 
+    }
+    return BITBLAST_MODE_EAGER;
+  } else if(optarg == "help") {
+    puts(bitblastingModeHelp.c_str());
+    exit(1);
+  } else {
+    throw OptionException(std::string("unknown option for --bitblast: `") +
+                          optarg + "'.  Try --bitblast=help.");
+  }
+}
+
+static const std::string bvSlicerModeHelp = "\
+Bit-vector equality slicer modes supported by the --bv-eq-slicer option:\n\
+\n\
+auto (default)\n\
++ Turn slicer on if input has only equalities over core symbols\n\
+\n\
+on\n\
++ Turn slicer on\n\
+\n\
+off\n\
++ Turn slicer off\n\
+";
+
+inline BvSlicerMode stringToBvSlicerMode(std::string option, std::string optarg, SmtEngine* smt) throw(OptionException) {
+
+  if(optarg == "auto") {
+    return BITVECTOR_SLICER_AUTO;
+  } else if(optarg == "on") {
+    return BITVECTOR_SLICER_ON;
+  } else if(optarg == "off") {
+    return BITVECTOR_SLICER_OFF; 
+  } else if(optarg == "help") {
+    puts(bitblastingModeHelp.c_str());
+    exit(1);
+  } else {
+    throw OptionException(std::string("unknown option for --bv-eq-slicer: `") +
+                          optarg + "'.  Try --bv-eq-slicer=help.");
+  }
+}
+
+}/* CVC4::theory::bv namespace */
+}/* CVC4::theory namespace */
+}/* CVC4 namespace */
+
+#endif /* __CVC4__THEORY__BV__OPTIONS_HANDLERS_H */
index 56e0a479e1413d22dcafec27ac7ad16ee1f92685..0644900fabc589fb458baa876ab24a479182ee32 100644 (file)
@@ -469,7 +469,7 @@ void Slicer::getBaseDecomposition(TNode node, std::vector<Node>& decomp) {
     low = utils::getExtractLow(node);
     top = node[0]; 
   }
-  Assert (d_nodeToId.find(top) != d_nodeToId.end()); 
+  AlwaysAssert (d_nodeToId.find(top) != d_nodeToId.end()); 
   TermId id = d_nodeToId[top];
   NormalForm nf(high-low+1); 
   d_unionFind.getNormalForm(ExtractTerm(id, high, low), nf);
@@ -498,7 +498,7 @@ bool Slicer::isCoreTerm(TNode node) {
   if (d_coreTermCache.find(node) == d_coreTermCache.end()) {
     Kind kind = node.getKind();
     bool not_core;
-    if (options::bitvectorCoreSolver()) {
+    if (options::bitvectorEqualitySlicer()) {
       not_core = (kind != kind::BITVECTOR_EXTRACT && kind != kind::BITVECTOR_CONCAT); 
     } else {
       not_core = true; 
index 5d5e0a97c86c5fb12e910b1ecbc2ee66c91d8e51..117a3e552767e87a66acff23592a73cd88e1ac9b 100644 (file)
@@ -1,32 +1,36 @@
 /*********************                                                        */
 /*! \file theory_bv.cpp
- ** \verbatim
- ** Original author: Dejan Jovanovic
- ** Major contributors: Morgan Deters, Liana Hadarean
- ** Minor contributors (to current version): Tim King, Kshitij Bansal, Clark Barrett, Andrew Reynolds
- ** 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 [[ Add one-line brief description here ]]
- **
- ** [[ Add lengthier description here ]]
- ** \todo document this file
- **/
-
+** \verbatim
+** Original author: Dejan Jovanovic
+** Major contributors: Morgan Deters, Liana Hadarean
+** Minor contributors (to current version): Tim King, Kshitij Bansal, Clark Barrett, Andrew Reynolds
+** 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 [[ Add one-line brief description here ]]
+**
+** [[ Add lengthier description here ]]
+** \todo document this file
+**/
+
+#include "smt/options.h"
 #include "theory/bv/theory_bv.h"
 #include "theory/bv/theory_bv_utils.h"
 #include "theory/bv/slicer.h"
 #include "theory/valuation.h"
-#include "theory/bv/bitblaster.h"
 #include "theory/bv/options.h"
 #include "theory/bv/theory_bv_rewrite_rules_normalization.h"
+#include "theory/bv/theory_bv_rewrite_rules_simplification.h"
 #include "theory/bv/bv_subtheory_core.h"
 #include "theory/bv/bv_subtheory_inequality.h"
+#include "theory/bv/bv_subtheory_algebraic.h"
 #include "theory/bv/bv_subtheory_bitblast.h"
+#include "theory/bv/bv_eager_solver.h"
 #include "theory/bv/theory_bv_rewriter.h"
 #include "theory/theory_model.h"
+#include "theory/bv/abstraction.h"
 
 using namespace CVC4;
 using namespace CVC4::theory;
@@ -48,24 +52,45 @@ TheoryBV::TheoryBV(context::Context* c, context::UserContext* u, OutputChannel&
     d_conflict(c, false),
     d_literalsToPropagate(c),
     d_literalsToPropagateIndex(c, 0),
-    d_propagatedBy(c)
-  {
-    if (options::bvEquality()) {
-      SubtheorySolver* core_solver = new CoreSolver(c, this);
-      d_subtheories.push_back(core_solver);
-      d_subtheoryMap[SUB_CORE] = core_solver;
-    }
-    if (options::bitvectorInequalitySolver()) {
-      SubtheorySolver* ineq_solver = new InequalitySolver(c, this);
-      d_subtheories.push_back(ineq_solver);
-      d_subtheoryMap[SUB_INEQUALITY] = ineq_solver;
-    }
+    d_propagatedBy(c),
+    d_eagerSolver(NULL),
+    d_abstractionModule(new AbstractionModule()),
+    d_isCoreTheory(false),
+    d_calledPreregister(false)
+{
+
+  if (options::bitblastMode() == theory::bv::BITBLAST_MODE_EAGER) {
+    d_eagerSolver = new EagerBitblastSolver();
+    return; 
+  }
 
-    SubtheorySolver* bb_solver = new BitblastSolver(c, this);
-    d_subtheories.push_back(bb_solver);
-    d_subtheoryMap[SUB_BITBLAST] = bb_solver;
+  if (options::bitvectorEqualitySolver()) {
+    SubtheorySolver* core_solver = new CoreSolver(c, this);
+    d_subtheories.push_back(core_solver);
+    d_subtheoryMap[SUB_CORE] = core_solver;
+  }
+  
+  if (options::bitvectorInequalitySolver()) {
+    SubtheorySolver* ineq_solver = new InequalitySolver(c, this);
+    d_subtheories.push_back(ineq_solver);
+    d_subtheoryMap[SUB_INEQUALITY] = ineq_solver;
   }
 
+  if (options::bitvectorAlgebraicSolver()) {
+    SubtheorySolver* alg_solver = new AlgebraicSolver(c, this);
+    d_subtheories.push_back(alg_solver);
+    d_subtheoryMap[SUB_ALGEBRAIC] = alg_solver;
+  }
+
+  BitblastSolver* bb_solver = new BitblastSolver(c, this);
+  if (options::bvAbstraction()) {
+    bb_solver->setAbstraction(d_abstractionModule);
+  }
+  d_subtheories.push_back(bb_solver);
+  d_subtheoryMap[SUB_BITBLAST] = bb_solver;
+}
+
+
 TheoryBV::~TheoryBV() {
   for (unsigned i = 0; i < d_subtheories.size(); ++i) {
     delete d_subtheories[i];
@@ -73,7 +98,10 @@ TheoryBV::~TheoryBV() {
 }
 
 void TheoryBV::setMasterEqualityEngine(eq::EqualityEngine* eq) {
-  if (options::bvEquality()) {
+  if (options::bitblastMode() == theory::bv::BITBLAST_MODE_EAGER) {
+    return; 
+  }
+  if (options::bitvectorEqualitySolver()) {
     dynamic_cast<CoreSolver*>(d_subtheoryMap[SUB_CORE])->setMasterEqualityEngine(eq);
   }
 }
@@ -84,7 +112,8 @@ TheoryBV::Statistics::Statistics():
   d_solveTimer("theory::bv::solveTimer"),
   d_numCallsToCheckFullEffort("theory::bv::NumberOfFullCheckCalls", 0),
   d_numCallsToCheckStandardEffort("theory::bv::NumberOfStandardCheckCalls", 0),
-  d_weightComputationTimer("theory::bv::weightComputationTimer")
+  d_weightComputationTimer("theory::bv::weightComputationTimer"),
+  d_numMultSlice("theory::bv::NumMultSliceApplied", 0)
 {
   StatisticsRegistry::registerStat(&d_avgConflictSize);
   StatisticsRegistry::registerStat(&d_solveSubstitutions);
@@ -92,6 +121,7 @@ TheoryBV::Statistics::Statistics():
   StatisticsRegistry::registerStat(&d_numCallsToCheckFullEffort);
   StatisticsRegistry::registerStat(&d_numCallsToCheckStandardEffort);
   StatisticsRegistry::registerStat(&d_weightComputationTimer);
+  StatisticsRegistry::registerStat(&d_numMultSlice);
 }
 
 TheoryBV::Statistics::~Statistics() {
@@ -101,6 +131,7 @@ TheoryBV::Statistics::~Statistics() {
   StatisticsRegistry::unregisterStat(&d_numCallsToCheckFullEffort);
   StatisticsRegistry::unregisterStat(&d_numCallsToCheckStandardEffort);
   StatisticsRegistry::unregisterStat(&d_weightComputationTimer);
+  StatisticsRegistry::unregisterStat(&d_numMultSlice);
 }
 
 Node TheoryBV::getBVDivByZero(Kind k, unsigned width) {
@@ -133,6 +164,83 @@ Node TheoryBV::getBVDivByZero(Kind k, unsigned width) {
 }
 
 
+void TheoryBV::collectNumerators(TNode term, TNodeSet& seen) {
+  if (seen.find(term) != seen.end())
+    return;
+  if (term.getKind() == kind::BITVECTOR_ACKERMANIZE_UDIV) {
+    unsigned size = utils::getSize(term[0]);
+    if (d_BVDivByZeroAckerman.find(size) == d_BVDivByZeroAckerman.end()) {
+      d_BVDivByZeroAckerman[size] = TNodeSet();
+    }
+    d_BVDivByZeroAckerman[size].insert(term[0]);
+    seen.insert(term); 
+  } else if (term.getKind() == kind::BITVECTOR_ACKERMANIZE_UREM) {
+    unsigned size = utils::getSize(term[0]);
+    if (d_BVRemByZeroAckerman.find(size) == d_BVRemByZeroAckerman.end()) {
+      d_BVRemByZeroAckerman[size] = TNodeSet();
+    }
+    d_BVRemByZeroAckerman[size].insert(term[0]);
+    seen.insert(term); 
+  }
+  for (unsigned i = 0; i < term.getNumChildren(); ++i) {
+    collectNumerators(term[i], seen); 
+  }
+}
+
+void TheoryBV::mkAckermanizationAsssertions(std::vector<Node>& assertions) {
+  Debug("bv-ackermanize") << "TheoryBV::mkAckermanizationAsssertions\n";
+  
+  Assert(options::bitblastMode() == theory::bv::BITBLAST_MODE_EAGER);
+  AlwaysAssert(!options::incrementalSolving());
+  TNodeSet seen; 
+  for (unsigned i = 0; i < assertions.size(); ++i) {
+    collectNumerators(assertions[i], seen); 
+  }
+  
+  // process division UF
+  Debug("bv-ackermanize") << "Process division UF...\n";
+  for (WidthToNumerators::const_iterator it = d_BVDivByZeroAckerman.begin(); it != d_BVDivByZeroAckerman.end(); ++it) {
+    const TNodeSet& numerators= it->second;
+    for (TNodeSet::const_iterator i = numerators.begin(); i != numerators.end(); ++i) {
+      TNodeSet::const_iterator j = i;
+      j++;
+      for (; j != numerators.end(); ++j) {
+        TNode arg1 = *i;
+        TNode arg2 = *j;
+        TNode acker1 = utils::mkNode(kind::BITVECTOR_ACKERMANIZE_UDIV, arg1);
+        TNode acker2 = utils::mkNode(kind::BITVECTOR_ACKERMANIZE_UDIV, arg2); 
+
+        Node arg_eq = utils::mkNode(kind::EQUAL, arg1, arg2);
+        Node acker_eq = utils::mkNode(kind::EQUAL, acker1, acker2);
+        Node lemma = utils::mkNode(kind::IMPLIES, arg_eq, acker_eq);
+        Debug("bv-ackermanize") << "  " << lemma << "\n";
+        assertions.push_back(lemma); 
+      }
+    }
+  }
+  // process remainder UF
+  Debug("bv-ackermanize") << "Process remainder UF...\n";
+  for (WidthToNumerators::const_iterator it = d_BVRemByZeroAckerman.begin(); it != d_BVRemByZeroAckerman.end(); ++it) {
+    const TNodeSet& numerators= it->second;
+    for (TNodeSet::const_iterator i = numerators.begin(); i != numerators.end(); ++i) {
+      TNodeSet::const_iterator j = i;
+      j++;
+      for (; j != numerators.end(); ++j) {
+        TNode arg1 = *i;
+        TNode arg2 = *j;
+        TNode acker1 = utils::mkNode(kind::BITVECTOR_ACKERMANIZE_UREM, arg1);
+        TNode acker2 = utils::mkNode(kind::BITVECTOR_ACKERMANIZE_UREM, arg2); 
+
+        Node arg_eq = utils::mkNode(kind::EQUAL, arg1, arg2);
+        Node acker_eq = utils::mkNode(kind::EQUAL, acker1, acker2);
+        Node lemma = utils::mkNode(kind::IMPLIES, arg_eq, acker_eq);
+        Debug("bv-ackermanize") << "  " << lemma << "\n";
+        assertions.push_back(lemma); 
+      }
+    }
+  }
+}
+
 Node TheoryBV::expandDefinition(LogicRequest &logicRequest, Node node) {
   Debug("bitvector-expandDefinition") << "TheoryBV::expandDefinition(" << node << ")" << std::endl;
 
@@ -147,15 +255,29 @@ Node TheoryBV::expandDefinition(LogicRequest &logicRequest, Node node) {
   case kind::BITVECTOR_UREM: {
     NodeManager* nm = NodeManager::currentNM();
     unsigned width = node.getType().getBitVectorSize();
-    Node divByZero = getBVDivByZero(node.getKind(), width);
+
+    if (options::bitvectorDivByZeroConst()) {
+      Kind kind = node.getKind() == kind::BITVECTOR_UDIV ? kind::BITVECTOR_UDIV_TOTAL : kind::BITVECTOR_UREM_TOTAL;
+      return nm->mkNode(kind, node[0], node[1]); 
+    }
+
     TNode num = node[0], den = node[1];
     Node den_eq_0 = nm->mkNode(kind::EQUAL, den, nm->mkConst(BitVector(width, Integer(0))));
-    Node divByZeroNum = nm->mkNode(kind::APPLY_UF, divByZero, num);
     Node divTotalNumDen = nm->mkNode(node.getKind() == kind::BITVECTOR_UDIV ? kind::BITVECTOR_UDIV_TOTAL :
                                     kind::BITVECTOR_UREM_TOTAL, num, den);
-    node = nm->mkNode(kind::ITE, den_eq_0, divByZeroNum, divTotalNumDen);
-    logicRequest.widenLogic(THEORY_UF);
-    return node;
+
+    if (options::bitblastMode() == theory::bv::BITBLAST_MODE_EAGER) {
+      // Ackermanize UF if using eager bit-blasting
+      Node ackerman_var = nm->mkNode(node.getKind() == kind::BITVECTOR_UDIV ? kind::BITVECTOR_ACKERMANIZE_UDIV : kind::BITVECTOR_ACKERMANIZE_UREM, num); 
+      node = nm->mkNode(kind::ITE, den_eq_0, ackerman_var, divTotalNumDen);
+      return node; 
+    } else {
+      Node divByZero = getBVDivByZero(node.getKind(), width);
+      Node divByZeroNum = nm->mkNode(kind::APPLY_UF, divByZero, num);
+      node = nm->mkNode(kind::ITE, den_eq_0, divByZeroNum, divTotalNumDen);
+      logicRequest.widenLogic(THEORY_UF);
+      return node;
+    }
   }
     break;
 
@@ -169,13 +291,24 @@ Node TheoryBV::expandDefinition(LogicRequest &logicRequest, Node node) {
 
 
 void TheoryBV::preRegisterTerm(TNode node) {
+  d_calledPreregister = true;
   Debug("bitvector-preregister") << "TheoryBV::preRegister(" << node << ")" << std::endl;
+  if (options::bitblastMode() == theory::bv::BITBLAST_MODE_EAGER) {
+    // the aig bit-blaster option is set heuristically
+    // if bv abstraction is not used
+    if (!d_eagerSolver->isInitialized()) {
+      d_eagerSolver->initialize();
+    }
 
-  if (options::bitvectorEagerBitblast()) {
-    // don't use the equality engine in the eager bit-blasting
-    d_subtheoryMap[SUB_BITBLAST]->preRegister(node);
-    return;
+    if (node.getKind() == kind::BITVECTOR_EAGER_ATOM) {
+      Node formula = node[0]; 
+      d_eagerSolver->assertFormula(formula);
+    }
+    // nothing to do for the other terms
+    return; 
   }
+  
   for (unsigned i = 0; i < d_subtheories.size(); ++i) {
     d_subtheories[i]->preRegister(node);
   }
@@ -212,8 +345,8 @@ void TheoryBV::checkForLemma(TNode fact) {
       TNode divisor = urem[1];
       Node result_ult_div = mkNode(kind::BITVECTOR_ULT, result, divisor);
       Node divisor_eq_0 = mkNode(kind::EQUAL,
-                                  divisor,
-                                  mkConst(BitVector(getSize(divisor), 0u)));
+                                 divisor,
+                                 mkConst(BitVector(getSize(divisor), 0u)));
       Node split = utils::mkNode(kind::OR, divisor_eq_0, mkNode(kind::NOT, fact), result_ult_div);
       lemma(split);
     }
@@ -224,10 +357,38 @@ void TheoryBV::checkForLemma(TNode fact) {
 void TheoryBV::check(Effort e)
 {
   Debug("bitvector") << "TheoryBV::check(" << e << ")" << std::endl;
-  if (options::bitvectorEagerBitblast()) {
+
+  // if we are using the eager solver
+  if (options::bitblastMode() == theory::bv::BITBLAST_MODE_EAGER) {
+    // this can only happen on an empty benchmark
+    if (!d_eagerSolver->isInitialized()) {
+      d_eagerSolver->initialize();
+    }
+    if (!Theory::fullEffort(e))
+      return;
+
+    std::vector<TNode> assertions; 
+    while (!done()) {
+      TNode fact = get().assertion;
+      Assert (fact.getKind() == kind::BITVECTOR_EAGER_ATOM);
+      assertions.push_back(fact); 
+    }
+    Assert (d_eagerSolver->hasAssertions(assertions)); 
+    
+    bool ok = d_eagerSolver->checkSat();
+    if (!ok) {
+      if (assertions.size() == 1) {
+        d_out->conflict(assertions[0]);
+        return; 
+      }
+      Node conflict = NodeManager::currentNM()->mkNode(kind::AND, assertions);
+      d_out->conflict(conflict);
+      return; 
+    }
     return;
   }
-
+  
+  
   if (Theory::fullEffort(e)) {
     ++(d_statistics.d_numCallsToCheckFullEffort);
   } else {
@@ -241,6 +402,7 @@ void TheoryBV::check(Effort e)
 
   while (!done()) {
     TNode fact = get().assertion;
+
     checkForLemma(fact);
 
     for (unsigned i = 0; i < d_subtheories.size(); ++i) {
@@ -270,7 +432,7 @@ void TheoryBV::check(Effort e)
 
 void TheoryBV::collectModelInfo( TheoryModel* m, bool fullModel ){
   Assert(!inConflict());
-  //  Assert (fullModel); // can only query full model
+
   for (unsigned i = 0; i < d_subtheories.size(); ++i) {
     if (d_subtheories[i]->isComplete()) {
       d_subtheories[i]->collectModelInfo(m, fullModel);
@@ -291,9 +453,8 @@ Node TheoryBV::getModelValue(TNode var) {
 
 void TheoryBV::propagate(Effort e) {
   Debug("bitvector") << indent() << "TheoryBV::propagate()" << std::endl;
-
-  if (options::bitvectorEagerBitblast()) {
-    return;
+  if (options::bitblastMode() == theory::bv::BITBLAST_MODE_EAGER) {
+    return; 
   }
 
   if (inConflict()) {
@@ -321,22 +482,62 @@ void TheoryBV::propagate(Effort e) {
 Theory::PPAssertStatus TheoryBV::ppAssert(TNode in, SubstitutionMap& outSubstitutions) {
   switch(in.getKind()) {
   case kind::EQUAL:
-
-    if (in[0].isVar() && !in[1].hasSubterm(in[0])) {
-      ++(d_statistics.d_solveSubstitutions);
-      outSubstitutions.addSubstitution(in[0], in[1]);
-      return PP_ASSERT_STATUS_SOLVED;
-    }
-    if (in[1].isVar() && !in[0].hasSubterm(in[1])) {
-      ++(d_statistics.d_solveSubstitutions);
-      outSubstitutions.addSubstitution(in[1], in[0]);
-      return PP_ASSERT_STATUS_SOLVED;
+    {
+      if (in[0].isVar() && !in[1].hasSubterm(in[0])) {
+        ++(d_statistics.d_solveSubstitutions);
+        outSubstitutions.addSubstitution(in[0], in[1]);
+        return PP_ASSERT_STATUS_SOLVED;
+      }
+      if (in[1].isVar() && !in[0].hasSubterm(in[1])) {
+        ++(d_statistics.d_solveSubstitutions);
+        outSubstitutions.addSubstitution(in[1], in[0]);
+        return PP_ASSERT_STATUS_SOLVED;
+      }
+      Node node = Rewriter::rewrite(in); 
+      if ((node[0].getKind() == kind::BITVECTOR_EXTRACT && node[1].isConst()) ||
+          (node[1].getKind() == kind::BITVECTOR_EXTRACT && node[0].isConst())) {
+        Node extract = node[0].isConst() ? node[1] : node[0];
+        if (extract[0].getKind() == kind::VARIABLE) {
+          Node c = node[0].isConst() ? node[0] : node[1];
+        
+          unsigned high = utils::getExtractHigh(extract);
+          unsigned low = utils::getExtractLow(extract);
+          unsigned var_bitwidth = utils::getSize(extract[0]);
+          std::vector<Node> children;
+        
+          if (low == 0) {
+            Assert (high != var_bitwidth - 1);
+            unsigned skolem_size = var_bitwidth - high - 1;
+            Node skolem = utils::mkVar(skolem_size);
+            children.push_back(skolem); 
+            children.push_back(c);
+          } else if (high == var_bitwidth - 1) {
+            unsigned skolem_size = low;
+            Node skolem = utils::mkVar(skolem_size);
+            children.push_back(c);
+            children.push_back(skolem); 
+          } else {
+            unsigned skolem1_size = low;
+            unsigned skolem2_size = var_bitwidth - high - 1;
+            Node skolem1 = utils::mkVar(skolem1_size);
+            Node skolem2 = utils::mkVar(skolem2_size);
+            children.push_back(skolem2);
+            children.push_back(c);
+            children.push_back(skolem1);
+          }
+          Node concat = utils::mkNode(kind::BITVECTOR_CONCAT, children);
+          Assert (utils::getSize(concat) == utils::getSize(extract[0])); 
+          outSubstitutions.addSubstitution(extract[0], concat);
+          return PP_ASSERT_STATUS_SOLVED;
+        }
+      }
     }
-    // to do constant propagations
-
-    break;
-  case kind::NOT:
     break;
+  case kind::BITVECTOR_ULT:
+  case kind::BITVECTOR_SLT:
+  case kind::BITVECTOR_ULE:
+  case kind::BITVECTOR_SLE:
+    
   default:
     // TODO other predicates
     break;
@@ -346,28 +547,65 @@ Theory::PPAssertStatus TheoryBV::ppAssert(TNode in, SubstitutionMap& outSubstitu
 
 Node TheoryBV::ppRewrite(TNode t)
 {
+  Node res = t;
   if (RewriteRule<BitwiseEq>::applies(t)) {
     Node result = RewriteRule<BitwiseEq>::run<false>(t);
-    return Rewriter::rewrite(result);
-  }
-
-  if (options::bitvectorCoreSolver() && t.getKind() == kind::EQUAL) {
+    res = Rewriter::rewrite(result);
+  } else if (d_isCoreTheory && t.getKind() == kind::EQUAL) {
     std::vector<Node> equalities;
     Slicer::splitEqualities(t, equalities);
-    return utils::mkAnd(equalities);
-  }
-
-  return t;
+    res = utils::mkAnd(equalities);
+  }
+
+  // if(t.getKind() == kind::EQUAL &&
+  //    ((t[0].getKind() == kind::BITVECTOR_MULT && t[1].getKind() == kind::BITVECTOR_PLUS) ||
+  //     (t[1].getKind() == kind::BITVECTOR_MULT && t[0].getKind() == kind::BITVECTOR_PLUS))) {
+  //   // if we have an equality between a multiplication and addition
+  //   // try to express multiplication in terms of addition
+  //   Node mult = t[0].getKind() == kind::BITVECTOR_MULT? t[0] : t[1];
+  //   Node add = t[0].getKind() == kind::BITVECTOR_PLUS? t[0] : t[1];
+  //   if (RewriteRule<MultSlice>::applies(mult)) {
+  //     Node new_mult = RewriteRule<MultSlice>::run<false>(mult);
+  //     Node new_eq = Rewriter::rewrite(utils::mkNode(kind::EQUAL, new_mult, add));
+
+  //     // the simplification can cause the formula to blow up
+  //     // only apply if formula reduced
+  //     if (d_subtheoryMap.find(SUB_BITBLAST) != d_subtheoryMap.end()) {
+  //       BitblastSolver* bv = (BitblastSolver*)d_subtheoryMap[SUB_BITBLAST];
+  //       uint64_t old_size = bv->computeAtomWeight(t);
+  //       Assert (old_size);
+  //       uint64_t new_size = bv->computeAtomWeight(new_eq);
+  //       double ratio = ((double)new_size)/old_size;
+  //       if (ratio <= 0.4) {
+  //         ++(d_statistics.d_numMultSlice);
+  //         return new_eq;
+  //       }
+  //     }
+      
+  //     if (new_eq.getKind() == kind::CONST_BOOLEAN) {
+  //       ++(d_statistics.d_numMultSlice);
+  //       return new_eq;
+  //     }
+  //   }
+  // }
+  
+  if (options::bvAbstraction() && t.getType().isBoolean()) {
+    d_abstractionModule->addInputAtom(res); 
+  }
+  return res;
 }
 
 void TheoryBV::presolve() {
   Debug("bitvector") << "TheoryBV::presolve" << endl;
 }
 
+static int prop_count = 0; 
+
 bool TheoryBV::storePropagation(TNode literal, SubTheory subtheory)
 {
   Debug("bitvector::propagate") << indent() << getSatContext()->getLevel() << " " << "TheoryBV::storePropagation(" << literal << ", " << subtheory << ")" << std::endl;
-
+  prop_count++; 
+  
   // If already in conflict, no more propagation
   if (d_conflict) {
     Debug("bitvector::propagate") << indent() << "TheoryBV::storePropagation(" << literal << ", " << subtheory << "): already in conflict" << std::endl;
@@ -425,7 +663,7 @@ Node TheoryBV::explain(TNode node) {
     return utils::mkTrue();
   }
   // return the explanation
-  Node explanation = mkAnd(assumptions);
+  Node explanation = utils::mkAnd(assumptions);
   Debug("bitvector::explain") << "TheoryBV::explain(" << node << ") => " << explanation << std::endl;
   return explanation;
 }
@@ -434,7 +672,7 @@ Node TheoryBV::explain(TNode node) {
 void TheoryBV::addSharedTerm(TNode t) {
   Debug("bitvector::sharing") << indent() << "TheoryBV::addSharedTerm(" << t << ")" << std::endl;
   d_sharedTermsSet.insert(t);
-  if (!options::bitvectorEagerBitblast() && options::bvEquality()) {
+  if (options::bitvectorEqualitySolver()) {
     for (unsigned i = 0; i < d_subtheories.size(); ++i) {
       d_subtheories[i]->addSharedTerm(t);
     }
@@ -444,10 +682,7 @@ void TheoryBV::addSharedTerm(TNode t) {
 
 EqualityStatus TheoryBV::getEqualityStatus(TNode a, TNode b)
 {
-  if (options::bitvectorEagerBitblast()) {
-    return EQUALITY_UNKNOWN;
-  }
-
+  Assert (options::bitblastMode() == theory::bv::BITBLAST_MODE_LAZY); 
   for (unsigned i = 0; i < d_subtheories.size(); ++i) {
     EqualityStatus status = d_subtheories[i]->getEqualityStatus(a, b);
     if (status != EQUALITY_UNKNOWN) {
@@ -457,3 +692,43 @@ EqualityStatus TheoryBV::getEqualityStatus(TNode a, TNode b)
   return EQUALITY_UNKNOWN; ;
 }
 
+
+void TheoryBV::enableCoreTheorySlicer() {
+  Assert (!d_calledPreregister);
+  d_isCoreTheory = true;
+  if (d_subtheoryMap.find(SUB_CORE) != d_subtheoryMap.end()) {
+    CoreSolver* core = (CoreSolver*)d_subtheoryMap[SUB_CORE];
+    core->enableSlicer(); 
+  }
+}
+
+
+void TheoryBV::ppStaticLearn(TNode in, NodeBuilder<>& learned) {}
+
+bool TheoryBV::applyAbstraction(const std::vector<Node>& assertions, std::vector<Node>& new_assertions) {
+  bool changed = d_abstractionModule->applyAbstraction(assertions, new_assertions);
+  if (changed &&
+      options::bitblastMode() == theory::bv::BITBLAST_MODE_EAGER &&
+      options::bitvectorAig()) {
+    // disable AIG mode
+    AlwaysAssert (!d_eagerSolver->isInitialized());
+    d_eagerSolver->turnOffAig();
+    d_eagerSolver->initialize();
+  }
+  return changed;
+}
+
+void TheoryBV::setConflict(Node conflict) {
+  if (options::bvAbstraction()) {
+    Node new_conflict = d_abstractionModule->simplifyConflict(conflict);
+      
+    std::vector<Node> lemmas;
+    lemmas.push_back(new_conflict); 
+    d_abstractionModule->generalizeConflict(new_conflict, lemmas);
+    for (unsigned i = 0; i < lemmas.size(); ++i) {
+      lemma(utils::mkNode(kind::NOT, lemmas[i])); 
+    }
+  }
+  d_conflict = true;
+  d_conflictNode = conflict;
+}
index a5e2ac9ea7a31771d4334de09ffced2afe894fe0..27b6b37c4a3060706fb5556d040f0de729e1e420 100644 (file)
  ** Bitvector theory.
  **/
 
-#include "cvc4_private.h"
-
 #ifndef __CVC4__THEORY__BV__THEORY_BV_H
 #define __CVC4__THEORY__BV__THEORY_BV_H
 
+#include "cvc4_private.h"
 #include "theory/theory.h"
 #include "context/context.h"
 #include "context/cdlist.h"
@@ -34,8 +33,13 @@ namespace bv {
 
 class CoreSolver;
 class InequalitySolver;
+class AlgebraicSolver;
 class BitblastSolver; 
 
+class EagerBitblastSolver;
+  
+class AbstractionModule;
+
 class TheoryBV : public Theory {
 
   /** The context we are using */
@@ -58,6 +62,8 @@ public:
 
   Node expandDefinition(LogicRequest &logicRequest, Node node);
 
+  void mkAckermanizationAsssertions(std::vector<Node>& assertions);
+
   void preRegisterTerm(TNode n);
 
   void check(Effort e);
@@ -71,9 +77,15 @@ public:
   std::string identify() const { return std::string("TheoryBV"); }
 
   PPAssertStatus ppAssert(TNode in, SubstitutionMap& outSubstitutions);
+
+  void enableCoreTheorySlicer();
+  
   Node ppRewrite(TNode t);
 
+  void ppStaticLearn(TNode in, NodeBuilder<>& learned);
+  
   void presolve();
+  bool applyAbstraction(const std::vector<Node>& assertions, std::vector<Node>& new_assertions); 
 private:
 
   class Statistics {
@@ -81,9 +93,10 @@ private:
     AverageStat d_avgConflictSize;
     IntStat     d_solveSubstitutions;
     TimerStat   d_solveTimer;
-    IntStat d_numCallsToCheckFullEffort;
-    IntStat d_numCallsToCheckStandardEffort; 
+    IntStat     d_numCallsToCheckFullEffort;
+    IntStat     d_numCallsToCheckStandardEffort; 
     TimerStat   d_weightComputationTimer;
+    IntStat     d_numMultSlice;
     Statistics();
     ~Statistics();
   };
@@ -101,6 +114,9 @@ private:
    */
   Node getBVDivByZero(Kind k, unsigned width);
 
+  typedef __gnu_cxx::hash_set<TNode, TNodeHashFunction> TNodeSet; 
+  void collectNumerators(TNode term, TNodeSet& seen);
+  
   /**
    * Maps from bit-vector width to divison-by-zero uninterpreted
    * function symbols.
@@ -108,6 +124,14 @@ private:
   __gnu_cxx::hash_map<unsigned, Node> d_BVDivByZero;
   __gnu_cxx::hash_map<unsigned, Node> d_BVRemByZero;
 
+  /**
+   * Maps from bit-vector width to numerators
+   * of uninterpreted function symbol
+   */
+  typedef __gnu_cxx::hash_map<unsigned, TNodeSet > WidthToNumerators;
+
+  WidthToNumerators d_BVDivByZeroAckerman;
+  WidthToNumerators d_BVRemByZeroAckerman;
 
   context::CDO<bool> d_lemmasAdded;
   
@@ -130,6 +154,11 @@ private:
   typedef context::CDHashMap<Node, SubTheory, NodeHashFunction> PropagatedMap;
   PropagatedMap d_propagatedBy;
 
+  EagerBitblastSolver* d_eagerSolver; 
+  AbstractionModule* d_abstractionModule;
+  bool d_isCoreTheory;
+  bool d_calledPreregister;
+  
   bool wasPropagatedBySubtheory(TNode literal) const {
     return d_propagatedBy.find(literal) != d_propagatedBy.end(); 
   }
@@ -162,10 +191,7 @@ private:
     return indentStr;
   }
 
-  void setConflict(Node conflict = Node::null()) {
-    d_conflict = true;
-    d_conflictNode = conflict;
-  }
+  void setConflict(Node conflict = Node::null());
 
   bool inConflict() {
     return d_conflict;
@@ -176,12 +202,15 @@ private:
   void lemma(TNode node) { d_out->lemma(node); d_lemmasAdded = true; }
 
   void checkForLemma(TNode node); 
-  
-  friend class Bitblaster;
+
+  friend class LazyBitblaster;
+  friend class TLazyBitblaster;
   friend class BitblastSolver;
   friend class EqualitySolver;
   friend class CoreSolver;
-  friend class InequalitySolver; 
+  friend class InequalitySolver;
+  friend class AlgebraicSolver;
 };/* class TheoryBV */
 
 }/* CVC4::theory::bv namespace */
index db48a1d05854b8cc1daee1db23dcd382ac567d97..9f01e46dad5a43d7f0998634410b832e7f1f9082 100644 (file)
@@ -121,6 +121,8 @@ enum RewriteRuleId {
   NotUlt,
   NotUle,
   MultPow2,
+  MultSlice,
+  ExtractMultLeadingBit,
   NegIdemp,
   UdivPow2,
   UdivOne,
@@ -133,6 +135,7 @@ enum RewriteRuleId {
   UltOne,
   SltZero, 
   ZeroUlt,
+  MergeSignExtend,
   
   /// normalization rules
   ExtractBitwise,
@@ -152,7 +155,7 @@ enum RewriteRuleId {
   PlusCombineLikeTerms,
   MultSimplify,
   MultDistribConst,
-  MultDistribVariable,
+  MultDistrib,
   SolveEq,
   BitwiseEq,
   AndSimplify,
@@ -248,6 +251,8 @@ inline std::ostream& operator << (std::ostream& out, RewriteRuleId ruleId) {
   case XorOne :       out << "XorOne";        return out;
   case XorZero :       out << "XorZero";        return out;
   case MultPow2 :            out << "MultPow2";             return out;
+  case MultSlice :            out << "MultSlice";             return out;
+  case ExtractMultLeadingBit :            out << "ExtractMultLeadingBit";             return out;
   case NegIdemp :            out << "NegIdemp";             return out;
   case UdivPow2 :            out << "UdivPow2";             return out;
   case UdivOne :            out << "UdivOne";             return out;
@@ -266,7 +271,6 @@ inline std::ostream& operator << (std::ostream& out, RewriteRuleId ruleId) {
   case PlusCombineLikeTerms: out << "PlusCombineLikeTerms"; return out;
   case MultSimplify: out << "MultSimplify"; return out;
   case MultDistribConst: out << "MultDistribConst"; return out;
-  case MultDistribVariable: out << "MultDistribConst"; return out;
   case SolveEq : out << "SolveEq"; return out;
   case BitwiseEq : out << "BitwiseEq"; return out;
   case NegMult : out << "NegMult"; return out;
@@ -279,9 +283,12 @@ inline std::ostream& operator << (std::ostream& out, RewriteRuleId ruleId) {
   case UltOne : out << "UltOne"; return out;
   case SltZero : out << "SltZero"; return out;
   case ZeroUlt : out << "ZeroUlt"; return out;
+  case MergeSignExtend : out << "MergeSignExtend"; return out;
+    
   case UleEliminate : out << "UleEliminate"; return out;
   case BitwiseSlicing : out << "BitwiseSlicing"; return out;
-  case ExtractSignExtend : out << "ExtractSignExtend"; return out; 
+  case ExtractSignExtend : out << "ExtractSignExtend"; return out;
+  case MultDistrib: out << "MultDistrib"; return out;
   default:
     Unreachable();
   }
@@ -473,6 +480,8 @@ struct AllRewriteRules {
   RewriteRule<XorOne> rule83;
   RewriteRule<XorZero> rule84;
   RewriteRule<MultPow2> rule87;
+  RewriteRule<MultSlice> rule85;
+  RewriteRule<ExtractMultLeadingBit> rule88;
   RewriteRule<NegIdemp> rule91;
   RewriteRule<UdivPow2> rule92;
   RewriteRule<UdivOne> rule93;
@@ -500,7 +509,7 @@ struct AllRewriteRules {
   RewriteRule<SltZero> rule115;
   RewriteRule<BVToNatEliminate>  rule116;
   RewriteRule<IntToBVEliminate>  rule117;
-  RewriteRule<MultDistribVariable> rule118;
+  RewriteRule<MultDistrib> rule118;
 };
 
 template<> inline
index 43acfef7567cff42ec5e685e710884b7034fbf0e..649af5ff987557c1dd6e21452889efb6351f6b7d 100644 (file)
@@ -270,7 +270,7 @@ Node RewriteRule<SimplifyEq>::apply(TNode node) {
 
 template<> inline
 bool RewriteRule<ReflexivityEq>::applies(TNode node) {
-  return (node.getKind() == kind::EQUAL && node[0] < node[1]);
+  return (node.getKind() == kind::EQUAL && node[0] > node[1]);
 }
 
 template<> inline
index bb5c94b1ead0386700f96d89598cbeb23a059eb6..b13172bfaa3b1e86ed8544f56ff7a2a5425d606a 100644 (file)
@@ -431,35 +431,6 @@ Node RewriteRule<MultSimplify>::apply(TNode node) {
   return utils::mkNode(kind::BITVECTOR_MULT, children); 
 }
 
-template<> inline
-bool RewriteRule<MultDistribVariable>::applies(TNode node) {
-  if (node.getKind() != kind::BITVECTOR_MULT ||
-      node.getNumChildren() != 2) {
-    return false;
-  }
-  Assert(!node[0].isConst());
-  if (!node[1].getNumChildren() == 0) {
-    return false;
-  }
-  TNode factor = node[0];
-  return (factor.getKind() == kind::BITVECTOR_PLUS ||
-          factor.getKind() == kind::BITVECTOR_SUB); 
-}
-
-template<> inline
-Node RewriteRule<MultDistribVariable>::apply(TNode node) {
-  Debug("bv-rewrite") << "RewriteRule<MultDistrib>(" << node << ")" << std::endl;
-  TNode var = node[1];
-  TNode factor = node[0];
-
-  std::vector<Node> children;
-  for(unsigned i = 0; i < factor.getNumChildren(); ++i) {
-    children.push_back(utils::mkNode(kind::BITVECTOR_MULT, factor[i], var));
-  }
-  
-  return utils::mkNode(factor.getKind(), children); 
-}
-
 
 template<> inline
 bool RewriteRule<MultDistribConst>::applies(TNode node) {
@@ -501,6 +472,40 @@ Node RewriteRule<MultDistribConst>::apply(TNode node) {
   return utils::mkNode(factor.getKind(), children); 
 }
 
+template<> inline
+bool RewriteRule<MultDistrib>::applies(TNode node) {
+  if (node.getKind() != kind::BITVECTOR_MULT ||
+      node.getNumChildren() != 2) {
+    return false;
+  }
+  if (node[0].getKind() == kind::BITVECTOR_PLUS ||
+      node[0].getKind() == kind::BITVECTOR_SUB) {
+    return node[1].getKind() != kind::BITVECTOR_PLUS &&
+           node[1].getKind() != kind::BITVECTOR_SUB;
+  }
+  return node[1].getKind() == kind::BITVECTOR_PLUS ||
+         node[1].getKind() == kind::BITVECTOR_SUB; 
+}
+
+template<> inline
+Node RewriteRule<MultDistrib>::apply(TNode node) {
+  Debug("bv-rewrite") << "RewriteRule<MultDistrib>(" << node << ")" << std::endl;
+
+  TNode factor = node[0].getKind() != kind::BITVECTOR_PLUS ? node[0] : node[1];
+  TNode sum = node[0].getKind() == kind::BITVECTOR_PLUS? node[0] : node[1];
+  Assert (factor.getKind() != kind::BITVECTOR_PLUS &&
+          factor.getKind() != kind::BITVECTOR_SUB &&
+          (sum.getKind() == kind::BITVECTOR_PLUS ||
+           sum.getKind() == kind::BITVECTOR_SUB));
+
+  std::vector<Node> children;
+  for(unsigned i = 0; i < sum.getNumChildren(); ++i) {
+    children.push_back(utils::mkNode(kind::BITVECTOR_MULT, sum[i], factor));
+  }
+  
+  return utils::mkNode(sum.getKind(), children); 
+}
+
 
 template<> inline
 bool RewriteRule<SolveEq>::applies(TNode node) {
@@ -679,7 +684,7 @@ Node RewriteRule<SolveEq>::apply(TNode node) {
     return utils::mkTrue();
   }
 
-  if (newLeft < newRight) {
+  if (newLeft > newRight) {
     Assert((newRight == left && newLeft == right) ||
            Rewriter::rewrite(newRight) != left ||
            Rewriter::rewrite(newLeft) != right);
index ff7d67cb0cc876cb9ad6cde4f29875366d62e6d8..db0d8bac83d7d7e35554e9686ea819d6b8fd28e4 100644 (file)
@@ -786,6 +786,84 @@ Node RewriteRule<MultPow2>::apply(TNode node) {
   return utils::mkConcat(extract, zeros); 
 }
 
+/**
+ * ExtractMultLeadingBit
+ *
+ * If the bit-vectors multiplied have enough leading zeros,
+ * we can determine that the top bits of the multiplication
+ * are zero and not compute them. Only apply for large bitwidths
+ * as this can interfere with other mult normalization rewrites such
+ * as flattening. 
+ */
+
+template<> inline
+bool RewriteRule<ExtractMultLeadingBit>::applies(TNode node) {
+  if (node.getKind() != kind::BITVECTOR_EXTRACT)
+    return false;
+  unsigned low = utils::getExtractLow(node);
+  node = node[0];
+  
+  if (node.getKind() != kind::BITVECTOR_MULT ||
+      node.getNumChildren() != 2 ||
+      utils::getSize(node) <= 64)
+    return false;
+
+  if (node[0].getKind() != kind::BITVECTOR_CONCAT ||
+      node[1].getKind() != kind::BITVECTOR_CONCAT ||
+      !node[0][0].isConst() ||
+      !node[1][0].isConst())
+    return false;
+
+  unsigned n = utils::getSize(node);
+  // count number of leading zeroes
+  const Integer& int1 = node[0][0].getConst<BitVector>().toInteger();
+  const Integer& int2 = node[1][0].getConst<BitVector>().toInteger();
+  unsigned zeroes1 = int1.isZero()? utils::getSize(node[0][0]) :
+                                    int1.length();
+
+  unsigned zeroes2 = int2.isZero()? utils::getSize(node[1][0]) :
+                                    int2.length();
+
+  // first k bits are not zero in the result
+  unsigned k = 2 * n - (zeroes1 + zeroes2);
+  
+  if (k > low)
+    return false; 
+
+  return true; 
+}
+
+template<> inline
+Node RewriteRule<ExtractMultLeadingBit>::apply(TNode node) {
+  Debug("bv-rewrite") << "RewriteRule<MultLeadingBit>(" << node << ")" << std::endl;
+
+  unsigned bitwidth = utils::getSize(node); 
+  
+  // node = node[0];
+  // const Integer& int1 = node[0][0].getConst<BitVector>().toInteger();
+  // const Integer& int2 = node[1][0].getConst<BitVector>().toInteger();
+  // unsigned zeroes1 = int1.isZero()? utils::getSize(node[0][0]) :
+  //                                   int1.length();
+
+  // unsigned zeroes2 = int2.isZero()? utils::getSize(node[1][0]) :
+  //                                   int2.length();
+  // all bits >= k in the multiplier will have to be 0
+  // unsigned n = utils::getSize(node); 
+  // unsigned k = 2 * n - (zeroes1 + zeroes2);
+  // Node extract1 = utils::mkExtract(node[0], k - 1, 0);
+  // Node extract2 = utils::mkExtract(node[1], k - 1, 0);
+  // Node k_zeroes = utils::mkConst(n - k, 0u);
+
+  // Node new_mult = utils::mkNode(kind::BITVECTOR_MULT, extract1, extract2);
+  // Node result = utils::mkExtract(utils::mkNode(kind::BITVECTOR_CONCAT, k_zeroes, new_mult),
+  //                                high, low); 
+  // since the extract is over multiplier bits that have to be 0, return 0
+  Node result = utils::mkConst(bitwidth, 0u); 
+  //  std::cout << "MultLeadingBit " << node <<" => " << result <<"\n";
+  return result;
+}
+
 /**
  * NegIdemp
  *
@@ -989,6 +1067,93 @@ Node RewriteRule<BBPlusNeg>::apply(TNode node) {
   return utils::mkNode(kind::BITVECTOR_PLUS, children); 
 }
 
+template<> inline
+bool RewriteRule<MergeSignExtend>::applies(TNode node) {
+  if (node.getKind() != kind::BITVECTOR_SIGN_EXTEND ||
+      (node[0].getKind() != kind::BITVECTOR_SIGN_EXTEND &&
+       node[0].getKind() != kind::BITVECTOR_ZERO_EXTEND))
+    return false;
+  return true;
+}
+
+template<> inline
+Node RewriteRule<MergeSignExtend>::apply(TNode node) {
+  Debug("bv-rewrite") << "RewriteRule<MergeSignExtend>(" << node << ")" << std::endl;
+  unsigned ammount1 = node.getOperator().getConst<BitVectorSignExtend>().signExtendAmount;
+
+  NodeManager* nm = NodeManager::currentNM();
+  if (node[0].getKind() == kind::BITVECTOR_ZERO_EXTEND) {
+    unsigned ammount2 = node[0].getOperator().getConst<BitVectorZeroExtend>().zeroExtendAmount;
+    if (ammount2 == 0) {
+      NodeBuilder<> nb(kind::BITVECTOR_SIGN_EXTEND);
+      Node op = nm->mkConst<BitVectorSignExtend>(BitVectorSignExtend(ammount1));
+      nb << op << node[0][0];
+      Node res = nb;
+      return res;
+    }
+    NodeBuilder<> nb(kind::BITVECTOR_ZERO_EXTEND);
+    Node op = nm->mkConst<BitVectorZeroExtend>(BitVectorZeroExtend(ammount1 + ammount2));
+    nb << op << node[0][0];
+    Node res = nb;
+    return res;
+  }
+  Assert (node[0].getKind() == kind::BITVECTOR_SIGN_EXTEND);
+  unsigned ammount2 = node[0].getOperator().getConst<BitVectorSignExtend>().signExtendAmount;
+  NodeBuilder<> nb(kind::BITVECTOR_SIGN_EXTEND);
+  Node op = nm->mkConst<BitVectorSignExtend>(BitVectorSignExtend(ammount1+ ammount2));
+  nb << op << node[0][0];
+  Node res = nb;
+  return res;
+}
+
+
+template<> inline
+bool RewriteRule<MultSlice>::applies(TNode node) {
+  if (node.getKind() != kind::BITVECTOR_MULT) {
+    return false; 
+  }
+  if (utils::getSize(node[0]) % 2 != 0) {
+    return false; 
+  }
+  return true; 
+}
+
+/** 
+ * Expressses the multiplication in terms of the top and bottom
+ * slices of the terms. Note increases circuit size, but could
+ * lead to simplifications (use wisely!).
+ * 
+ * @param node 
+ * 
+ * @return 
+ */
+template<> inline
+Node RewriteRule<MultSlice>::apply(TNode node) {
+  Debug("bv-rewrite") << "RewriteRule<MultSlice>(" << node << ")" << std::endl;
+  unsigned bitwidth = utils::getSize(node[0]);
+  Node zeros = utils::mkConst(bitwidth/2, 0);
+  TNode a = node[0];
+  Node bottom_a = utils::mkExtract(a, bitwidth/2 - 1, 0);
+  Node top_a = utils::mkExtract(a, bitwidth -1, bitwidth/2); 
+  TNode b = node[1];
+  Node bottom_b = utils::mkExtract(b, bitwidth/2 - 1, 0);
+  Node top_b = utils::mkExtract(b, bitwidth -1, bitwidth/2); 
+
+  Node term1 = utils::mkNode(kind::BITVECTOR_MULT,
+                             utils::mkNode(kind::BITVECTOR_CONCAT, zeros, bottom_a),
+                             utils::mkNode(kind::BITVECTOR_CONCAT, zeros, bottom_b));
+
+  Node term2 = utils::mkNode(kind::BITVECTOR_CONCAT,
+                             utils::mkNode(kind::BITVECTOR_MULT, top_b, bottom_a),
+                             zeros);
+  Node term3 = utils::mkNode(kind::BITVECTOR_CONCAT,
+                             utils::mkNode(kind::BITVECTOR_MULT, top_a, bottom_b),
+                             zeros);
+  return utils::mkNode(kind::BITVECTOR_PLUS, term1, term2, term3); 
+}
+
+
+
 // /**
 //  * 
 //  *
index 0b09bce4dcef2c980624bd6e0db2be2f8c209f30..6fd3bbf9276844398d6e9726db3400accaf1f8f6 100644 (file)
@@ -60,7 +60,14 @@ RewriteResponse TheoryBVRewriter::postRewrite(TNode node) {
   if(res.node!= node) {
     Debug("bitvector-rewrite") << "TheoryBV::postRewrite    " << node << std::endl;
     Debug("bitvector-rewrite") << "TheoryBV::postRewrite to " << res.node << std::endl;
+    if (res.node.getKind() == kind::EQUAL) {
+      Assert (res.node[0] < res.node[1]); 
+    }
+  }
+  if (res.node.getKind() == kind::EQUAL) {
+    Assert (res.node[0] < res.node[1]); 
   }
+
   // if (res.status == REWRITE_DONE) {
   //   Node rewr = res.node;
   //   Node rerewr = d_rewriteTable[rewr.getKind()](rewr, false).node;
@@ -154,10 +161,10 @@ RewriteResponse TheoryBVRewriter::RewriteSge(TNode node, bool prerewrite){
 RewriteResponse TheoryBVRewriter::RewriteNot(TNode node, bool prerewrite){
   Node resultNode = node;
   
-  if(RewriteRule<NotXor>::applies(node)) {
-    resultNode = RewriteRule<NotXor>::run<false>(node);
-    return RewriteResponse(REWRITE_AGAIN_FULL, resultNode); 
-  }
+  // // if(RewriteRule<NotXor>::applies(node)) {
+  // //   resultNode = RewriteRule<NotXor>::run<false>(node);
+  // //   return RewriteResponse(REWRITE_AGAIN_FULL, resultNode); 
+  // // }
   resultNode = LinearRewriteStrategy
     < RewriteRule<EvalNot>,
       RewriteRule<NotIdemp>
@@ -179,27 +186,24 @@ RewriteResponse TheoryBVRewriter::RewriteExtract(TNode node, bool prerewrite) {
     return RewriteResponse(REWRITE_AGAIN_FULL, resultNode); 
   }
 
-  if (RewriteRule<ExtractBitwise>::applies(node)) {
-    resultNode = RewriteRule<ExtractBitwise>::run<false>(node);
-    return RewriteResponse(REWRITE_AGAIN_FULL, resultNode); 
-  }
-  
   if (RewriteRule<ExtractNot>::applies(node)) {
     resultNode = RewriteRule<ExtractNot>::run<false>(node);
     return RewriteResponse(REWRITE_AGAIN_FULL, resultNode); 
   }
 
-  if (RewriteRule<ExtractArith>::applies(node)) {
-    resultNode = RewriteRule<ExtractArith>::run<false>(node);
-    return RewriteResponse(REWRITE_AGAIN_FULL, resultNode); 
-  }
+  // if (RewriteRule<ExtractArith>::applies(node)) {
+  //   resultNode = RewriteRule<ExtractArith>::run<false>(node);
+  //   return RewriteResponse(REWRITE_AGAIN_FULL, resultNode); 
+  // }
 
+  
   resultNode = LinearRewriteStrategy
     < RewriteRule<ExtractConstant>, 
       RewriteRule<ExtractExtract>,
       // We could get another extract over extract
-      RewriteRule<ExtractWhole>
+      RewriteRule<ExtractWhole>,
       // At this point only Extract-Whole could apply
+      RewriteRule<ExtractMultLeadingBit>
       >::apply(node);
   
   return RewriteResponse(REWRITE_DONE, resultNode); 
@@ -317,27 +321,18 @@ RewriteResponse TheoryBVRewriter::RewriteComp(TNode node, bool prerewrite) {
 
 RewriteResponse TheoryBVRewriter::RewriteMult(TNode node, bool prerewrite) {
   Node resultNode = node; 
-
   resultNode = LinearRewriteStrategy
     < RewriteRule<FlattenAssocCommut>, // flattens and sorts
       RewriteRule<MultSimplify>,       // multiplies constant part and checks for 0
       RewriteRule<MultPow2>            // replaces multiplication by a power of 2 by a shift
-    >::apply(node);
+    >::apply(resultNode);
 
   // only apply if every subterm was already rewritten 
   if (!prerewrite) {
-    // distributes multiplication by constant over +, - and unary -
-    if(RewriteRule<MultDistribConst>::applies(resultNode)) {
-      resultNode = RewriteRule<MultDistribConst>::run<false>(resultNode);
-      // creating new terms that might simplify further
-      return RewriteResponse(REWRITE_AGAIN_FULL, resultNode); 
-    }
-    if(RewriteRule<MultDistribVariable>::applies(resultNode)) {
-      resultNode = RewriteRule<MultDistribVariable>::run<false>(resultNode);
-      // creating new terms that might simplify further
-      return RewriteResponse(REWRITE_AGAIN_FULL, resultNode); 
-    }
-
+    resultNode = LinearRewriteStrategy
+      <   RewriteRule<MultDistribConst>
+        , RewriteRule<MultDistrib>
+        >::apply(resultNode);
   }
 
   if(resultNode == node) {
@@ -540,10 +535,14 @@ RewriteResponse TheoryBVRewriter::RewriteZeroExtend(TNode node, bool prerewrite)
 
 RewriteResponse TheoryBVRewriter::RewriteSignExtend(TNode node, bool prerewrite) {
   Node resultNode = LinearRewriteStrategy
-    < RewriteRule<EvalSignExtend>
+    < RewriteRule<MergeSignExtend>
+    , RewriteRule<EvalSignExtend>
     >::apply(node);
+
   
-  // return RewriteResponse(REWRITE_AGAIN_FULL, resultNode);
+  if (resultNode != node) {
+    return RewriteResponse(REWRITE_AGAIN, resultNode);
+  }
   return RewriteResponse(REWRITE_DONE, resultNode); 
 }
 
index 12e2581772f063c21cc05b6a0a90a25f9dbaa540..c1829ce69ef436fed44f4ac99b0fd0b1588ac964 100644 (file)
@@ -114,6 +114,49 @@ public:
   }
 };
 
+class BitVectorEagerAtomTypeRule {
+public:
+  inline static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check)
+      throw (TypeCheckingExceptionPrivate, AssertionException) {
+    if( check ) {
+      TypeNode lhsType = n[0].getType(check);
+      if (!lhsType.isBoolean()) {
+        throw TypeCheckingExceptionPrivate(n, "expecting boolean term");
+      }
+    }
+    return nodeManager->booleanType();
+  }
+};
+
+class BitVectorAckermanizationUdivTypeRule {
+public:
+  inline static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check)
+      throw (TypeCheckingExceptionPrivate, AssertionException) {
+    TypeNode lhsType = n[0].getType(check);
+    if( check ) {
+      if (!lhsType.isBitVector()) {
+        throw TypeCheckingExceptionPrivate(n, "expecting bit-vector term");
+      }
+    }
+    return lhsType; 
+  }
+};
+
+class BitVectorAckermanizationUremTypeRule {
+public:
+  inline static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check)
+      throw (TypeCheckingExceptionPrivate, AssertionException) {
+    TypeNode lhsType = n[0].getType(check);
+    if( check ) {
+      if (!lhsType.isBitVector()) {
+        throw TypeCheckingExceptionPrivate(n, "expecting bit-vector term");
+      }
+    }
+    return lhsType; 
+  }
+};
+
+
 class BitVectorExtractTypeRule {
 public:
   inline static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check)
diff --git a/src/theory/bv/theory_bv_utils.cpp b/src/theory/bv/theory_bv_utils.cpp
new file mode 100644 (file)
index 0000000..705a784
--- /dev/null
@@ -0,0 +1,102 @@
+/*********************                                                        */
+/*! \file theory_bv_utils.h
+ ** \verbatim
+ ** Original author: Dejan Jovanovic
+ ** Major contributors: Liana Hadarean
+ ** Minor contributors (to current version): Clark Barrett, Morgan Deters, Kshitij Bansal
+ ** 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 [[ Add one-line brief description here ]]
+ **
+ ** [[ Add lengthier description here ]]
+ ** \todo document this file
+ **/
+
+#include "theory/bv/theory_bv_utils.h"
+#include "theory/decision_attributes.h"
+#include "theory/theory.h"
+
+using namespace CVC4;
+using namespace CVC4::theory;
+using namespace CVC4::theory::bv;
+using namespace CVC4::theory::bv::utils;
+
+bool CVC4::theory::bv::utils::isCoreTerm(TNode term, TNodeBoolMap& cache) {
+  term = term.getKind() == kind::NOT ? term[0] : term; 
+  TNodeBoolMap::const_iterator it = cache.find(term); 
+  if (it != cache.end()) {
+    return it->second;
+  }
+    
+  if (term.getNumChildren() == 0)
+    return true;
+  
+  if (theory::Theory::theoryOf(theory::THEORY_OF_TERM_BASED, term) == THEORY_BV) {
+    Kind k = term.getKind();
+    if (k != kind::CONST_BITVECTOR &&
+        k != kind::BITVECTOR_CONCAT &&
+        k != kind::BITVECTOR_EXTRACT &&
+        k != kind::EQUAL &&
+        term.getMetaKind() != kind::metakind::VARIABLE) {
+      cache[term] = false;
+      return false;
+    }
+  }
+
+  for (unsigned i = 0; i < term.getNumChildren(); ++i) {
+    if (!isCoreTerm(term[i], cache)) {
+      cache[term] = false;
+      return false;
+    }
+  }
+  
+  cache[term]= true; 
+  return true;
+}
+
+bool CVC4::theory::bv::utils::isEqualityTerm(TNode term, TNodeBoolMap& cache) {
+  term = term.getKind() == kind::NOT ? term[0] : term; 
+  TNodeBoolMap::const_iterator it = cache.find(term); 
+  if (it != cache.end()) {
+    return it->second;
+  }
+    
+  if (term.getNumChildren() == 0)
+    return true;
+  
+  if (theory::Theory::theoryOf(theory::THEORY_OF_TERM_BASED, term) == THEORY_BV) {
+    Kind k = term.getKind();
+    if (k != kind::CONST_BITVECTOR &&
+        k != kind::EQUAL &&
+        term.getMetaKind() != kind::metakind::VARIABLE) {
+      cache[term] = false;
+      return false;
+    }
+  }
+
+  for (unsigned i = 0; i < term.getNumChildren(); ++i) {
+    if (!isEqualityTerm(term[i], cache)) {
+      cache[term] = false;
+      return false;
+    }
+  }
+  
+  cache[term]= true; 
+  return true;
+}
+
+
+uint64_t CVC4::theory::bv::utils::numNodes(TNode node, NodeSet& seen) {
+  if (seen.find(node) != seen.end())
+    return 0;
+
+  uint64_t size = 1;
+  for (unsigned i = 0; i < node.getNumChildren(); ++i) {
+    size += numNodes(node[i], seen);
+  }
+  seen.insert(node);
+  return size;
+}
index 95136598c13526c2160f55b6d9472490ee240a67..3650d3091897c89bc7bf5ccc789670d70edd944e 100644 (file)
@@ -23,7 +23,7 @@
 #include <vector>
 #include <sstream>
 #include "expr/node_manager.h"
-#include "theory/decision_attributes.h"
+
 
 namespace CVC4 {
 namespace theory {
@@ -65,7 +65,8 @@ inline Node mkFalse() {
 
 inline Node mkVar(unsigned size) {
   NodeManager* nm =  NodeManager::currentNM();
-  return nm->mkSkolem("bv", nm->mkBitVectorType(size), "is a variable created by the theory of bitvectors"); 
+
+  return nm->mkSkolem("BVSKOLEM$$", nm->mkBitVectorType(size), "is a variable created by the theory of bitvectors"); 
 }
 
 
@@ -435,8 +436,6 @@ inline Node mkConjunction(const std::vector<TNode>& nodes) {
 
 
 
-
-
 // Turn a set into a string
 inline std::string setToString(const std::set<TNode>& nodeSet) {
   std::stringstream out;
@@ -498,26 +497,13 @@ inline T gcd(T a, T b) {
   return a;
 }
 
+typedef __gnu_cxx::hash_map<TNode, bool, TNodeHashFunction> TNodeBoolMap;
 
-typedef __gnu_cxx::hash_set<TNode, TNodeHashFunction> TNodeSet;
-
-inline uint64_t numNodesAux(TNode node, TNodeSet& seen) {
-  if (seen.find(node) != seen.end())
-    return 0;
+bool isCoreTerm(TNode term, TNodeBoolMap& cache);
+bool isEqualityTerm(TNode term, TNodeBoolMap& cache);
+typedef __gnu_cxx::hash_set<Node, NodeHashFunction> NodeSet;
 
-  uint64_t size = 1;
-  for (unsigned i = 0; i < node.getNumChildren(); ++i) {
-    size += numNodesAux(node[i], seen);
-  }
-  seen.insert(node);
-  return size;
-}
-
-inline uint64_t numNodes(TNode node) {
-  TNodeSet seen;
-  uint64_t size = numNodesAux(node, seen);
-  return size;
-}
+uint64_t numNodes(TNode node, NodeSet& seen);
 
 }
 }
index c63df83ee1478998e7c507e3c14c642a463b5c56..2e80e1cda59e0ebf092e93cd83d402bd24c39441 100644 (file)
@@ -51,8 +51,9 @@
 #include "theory/quantifiers/first_order_model.h"
 
 #include "theory/uf/equality_engine.h"
-
 //#include "theory/rewriterules/efficient_e_matching.h"
+#include "theory/bv/theory_bv_utils.h"
+#include "theory/bv/options.h"
 
 #include "proof/proof_manager.h"
 
@@ -1445,8 +1446,49 @@ void TheoryEngine::conflict(TNode conflict, TheoryId theoryId) {
   }
 }
 
+void TheoryEngine::staticInitializeBVOptions(const std::vector<Node>& assertions) {
+  bool useSlicer = true;
+  if (options::bitvectorEqualitySlicer() == bv::BITVECTOR_SLICER_ON) {
+    if (options::incrementalSolving())
+      throw ModalException("Slicer does not currently support incremental mode. Use --bv-eq-slicer=off");
+    if (options::produceModels())
+      throw ModalException("Slicer does not currently support model generation. Use --bv-eq-slicer=off");
+    useSlicer = true;
+    
+  } else if (options::bitvectorEqualitySlicer() == bv::BITVECTOR_SLICER_OFF) {
+    return;
+    
+  } else if (options::bitvectorEqualitySlicer() == bv::BITVECTOR_SLICER_AUTO) {
+    if (options::incrementalSolving() ||
+        options::produceModels())
+      return;
+
+    useSlicer = true; 
+    bv::utils::TNodeBoolMap cache;
+    for (unsigned i = 0; i < assertions.size(); ++i) {
+      useSlicer = useSlicer && bv::utils::isCoreTerm(assertions[i], cache); 
+    }
+  }
+  
+  if (useSlicer) {
+    bv::TheoryBV* bv_theory = (bv::TheoryBV*)d_theoryTable[THEORY_BV]; 
+    bv_theory->enableCoreTheorySlicer();
+  }
+  
+}
+
 void TheoryEngine::ppBvToBool(const std::vector<Node>& assertions, std::vector<Node>& new_assertions) {
-  d_bvToBoolPreprocessor.liftBoolToBV(assertions, new_assertions);
+  d_bvToBoolPreprocessor.liftBvToBool(assertions, new_assertions);
+}
+
+bool  TheoryEngine::ppBvAbstraction(const std::vector<Node>& assertions, std::vector<Node>& new_assertions) {
+  bv::TheoryBV* bv_theory = (bv::TheoryBV*)d_theoryTable[THEORY_BV]; 
+  return bv_theory->applyAbstraction(assertions, new_assertions); 
+}
+
+void TheoryEngine::mkAckermanizationAsssertions(std::vector<Node>& assertions) {
+  bv::TheoryBV* bv_theory = (bv::TheoryBV*)d_theoryTable[THEORY_BV]; 
+  bv_theory->mkAckermanizationAsssertions(assertions);
 }
 
 Node TheoryEngine::ppSimpITE(TNode assertion)
index 615598e441ad4746bdd440e04ecef0c1bea12197..9460911670ffd16a44bc4076aae7f7ccbfb3cf0a 100644 (file)
@@ -795,8 +795,11 @@ private:
   /** For preprocessing pass lifting bit-vectors of size 1 to booleans */
   theory::bv::BvToBoolPreprocessor d_bvToBoolPreprocessor;
 public:
-
+  void staticInitializeBVOptions(const std::vector<Node>& assertions);
   void ppBvToBool(const std::vector<Node>& assertions, std::vector<Node>& new_assertions);
+  bool ppBvAbstraction(const std::vector<Node>& assertions, std::vector<Node>& new_assertions);
+  void mkAckermanizationAsssertions(std::vector<Node>& assertions);
+
   Node ppSimpITE(TNode assertion);
   /** Returns false if an assertion simplified to false. */
   bool donePPSimpITE(std::vector<Node>& assertions);
index 7509c7f4f2624d52fefa64c2dca3ab7690384591..c2fc9929a836862c218e04df17de528ba324156b 100644 (file)
@@ -280,8 +280,8 @@ void UnconstrainedSimplifier::processUnconstrained()
         case kind::BITVECTOR_SHL:
         case kind::BITVECTOR_LSHR:
         case kind::BITVECTOR_ASHR:
-        case kind::BITVECTOR_UDIV:
-        case kind::BITVECTOR_UREM:
+        case kind::BITVECTOR_UDIV_TOTAL:
+        case kind::BITVECTOR_UREM_TOTAL:
         case kind::BITVECTOR_SDIV:
         case kind::BITVECTOR_SREM:
         case kind::BITVECTOR_SMOD: {
@@ -634,16 +634,13 @@ void UnconstrainedSimplifier::processUnconstrained()
           break;
         }
 
-        // These should have been rewritten up front
-        case kind::BITVECTOR_REPEAT:
+        // Do nothing 
+        case kind::BITVECTOR_SIGN_EXTEND:
         case kind::BITVECTOR_ZERO_EXTEND:
+        case kind::BITVECTOR_REPEAT:
         case kind::BITVECTOR_ROTATE_LEFT:
         case kind::BITVECTOR_ROTATE_RIGHT:
-          Unreachable();
-          break;
 
-        // Do nothing
-        case kind::BITVECTOR_SIGN_EXTEND:
         default:
           break;
       }
index e826a6704c8ce14117be4a5012bf8546a6199f1a..35b052531af5f8070c814cf37b79d265061f70e8 100644 (file)
@@ -197,7 +197,8 @@ public:
 
     CheckArgument(d_size == y.d_size, y);
     if (y.d_value == 0) {
-      return BitVector(d_size, 0u);
+      // under division by zero return -1
+      return BitVector(d_size, Integer(1).oneExtend(1, d_size - 1));
     }
     CheckArgument(d_value >= 0, this);
     CheckArgument(y.d_value > 0, y);
@@ -210,7 +211,7 @@ public:
   BitVector unsignedRemTotal(const BitVector& y) const {
     CheckArgument(d_size == y.d_size, y);
     if (y.d_value == 0) {
-      return BitVector(d_size, 0u);
+      return BitVector(d_size, d_value);
     }
     CheckArgument(d_value >= 0, this);
     CheckArgument(y.d_value > 0, y);
index 5d2a54b11e4dccfec7372b64ca7ec11b9ace1cc0..4c2b1c7736ce70213fd4a1c4d85f19cf0e35ff5f 100644 (file)
@@ -94,7 +94,7 @@ SMT_TESTS = \
        smtcompbug.smt
 
 # Regression tests for SMT2 inputs
-SMT2_TESTS =
+SMT2_TESTS = divtest.smt2
 
 # Regression tests for PL inputs
 CVC_TESTS = bvsimple.cvc sizecheck.cvc
diff --git a/test/regress/regress0/bv/divtest.smt2 b/test/regress/regress0/bv/divtest.smt2
new file mode 100644 (file)
index 0000000..fe91cb8
--- /dev/null
@@ -0,0 +1,53 @@
+(set-logic QF_BV)
+(set-info :status unsat)
+(declare-fun x1 () (_ BitVec 12))
+(declare-fun x2 () (_ BitVec 12))
+(declare-fun x3 () (_ BitVec 12))
+
+(declare-fun y1 () (_ BitVec 12))
+(declare-fun y2 () (_ BitVec 12))
+(declare-fun y3 () (_ BitVec 12))
+
+(declare-fun z1 () (_ BitVec 12))
+(declare-fun z2 () (_ BitVec 12))
+(declare-fun z3 () (_ BitVec 12))
+
+(declare-fun a () (_ BitVec 12))
+
+(declare-fun x01 () (_ BitVec 10))
+(declare-fun x02 () (_ BitVec 10))
+(declare-fun x03 () (_ BitVec 10))
+
+(declare-fun y01 () (_ BitVec 10))
+(declare-fun y02 () (_ BitVec 10))
+(declare-fun y03 () (_ BitVec 10))
+
+(declare-fun z01 () (_ BitVec 10))
+(declare-fun z02 () (_ BitVec 10))
+(declare-fun z03 () (_ BitVec 10))
+
+(declare-fun a0 () (_ BitVec 10))
+
+(assert
+(or 
+(and 
+       (= a (_ bv0 12))
+       (or (not (= (bvudiv x1 a) (bvudiv x2 a)))
+           (not (= (bvudiv x1 a) (bvudiv x3 a)))
+           (not (= (bvudiv x2 a) (bvudiv x3 a))))
+       (or (and (= x1 y1) (= y1 x2))
+           (and (= x1 z1) (= z1 x2)))
+       (or (and (= x2 y2) (= y2 x3))
+           (and (= x2 z2) (= z2 x3))))
+
+(and 
+       (= a0 (_ bv0 10))
+       (or (not (= (bvurem x01 a0) (bvurem x02 a0)))
+           (not (= (bvurem x01 a0) (bvurem x03 a0)))
+           (not (= (bvurem x02 a0) (bvurem x03 a0))))
+       (or (and (= x01 y01) (= y01 x02))
+           (and (= x01 z01) (= z01 x02)))
+       (or (and (= x02 y02) (= y02 x03))
+           (and (= x02 z02) (= z02 x03))))))
+           
+(check-sat)