]
)
+# [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(
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.
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
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
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 \
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 \
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 \
*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 */
for(int t = 0; t < numThreads; ++t) {
if(optionWaitToJoin) {
threads[t].join();
- }
+ }
}
std::pair<int, S> retval(global_winner, threads_returnValue[global_winner]);
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);
}
void BVMinisatSatSolver::addMarkerLiteral(SatLiteral lit) {
d_minisat->addMarkerLiteral(BVMinisat::var(toMinisatLit(lit)));
+ markUnremovable(lit);
}
void BVMinisatSatSolver::explain(SatLiteral lit, std::vector<SatLiteral>& explanation) {
} 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;
// 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);
}
BVMinisatSatSolver::Statistics::~Statistics() {
+ if (!d_registerStats)
+ return;
StatisticsRegistry::unregisterStat(&d_statStarts);
StatisticsRegistry::unregisterStat(&d_statDecisions);
StatisticsRegistry::unregisterStat(&d_statRndDecisions);
}
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);
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);
SatValue solve();
SatValue solve(long unsigned int&);
- SatValue solve(bool quick_solve);
void getUnsatCore(SatClause& unsatCore);
SatValue value(SatLiteral l);
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);
};
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:
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;
}
}
}
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])))
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)
}
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());
+}
/*_________________________________________________________________________________________________
|
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;
}
seen[var(p)] = 0;
+ assert (out_conflict.size());
}
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();
// 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;
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').
#include "mtl/Sort.h"
#include "simp/SimpSolver.h"
#include "utils/System.h"
-
+#include "theory/bv/options.h"
+#include "smt/options.h"
using namespace BVMinisat;
//=================================================================================================
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));
, 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))
, 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);
SimpSolver::~SimpSolver()
{
- CVC4::StatisticsRegistry::unregisterStat(&total_eliminate_time);
+ // CVC4::StatisticsRegistry::unregisterStat(&total_eliminate_time);
}
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;
//
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);
int merges;
int asymm_lits;
int eliminated_vars;
- CVC4::TimerStat total_eliminate_time;
+ // CVC4::TimerStat total_eliminate_time;
protected:
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); }
+
//=================================================================================================
}
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)
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() {
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);
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\
} 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.");
// 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
*/
}
- 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;
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();
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]);
}
}
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);
}
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;
// Unconstrained simplification
if(options::unconstrainedSimp()) {
Chat() << "...doing unconstrained simplification..." << endl;
- unconstrainedSimp();
+ unconstrainedSimp(d_assertionsToCheck);
}
dumpAssertions("post-unconstrained", d_assertionsToCheck);
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;
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
// 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;
}
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;
}
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;
dumpAssertions("post-everything", d_assertionsToCheck);
- // Push the formula to SAT
{
Chat() << "converting to CNF..." << endl;
TimerStat::CodeTimer codeTimer(d_smt.d_stats->d_cnfConversionTime);
d_smt.d_propEngine->assertFormula(d_assertionsToCheck[i]);
}
}
+
d_assertionsProcessed = true;
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();
}
--- /dev/null
+/********************* */
+/*! \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);
+}
--- /dev/null
+ /********************* */
+/*! \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
--- /dev/null
+/********************* */
+/*! \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
--- /dev/null
+/********************* */
+/*! \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 */
--- /dev/null
+/********************* */
+/*! \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 */
+++ /dev/null
-/********************* */
-/*! \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();
-}
-
-
-}
-}
-}
-
-
+++ /dev/null
-/********************* */
-/*! \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
--- /dev/null
+/********************* */
+/*! \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
--- /dev/null
+/********************* */
+/*! \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
+++ /dev/null
-/********************* */
-/*! \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*/
+++ /dev/null
-/********************* */
-/*! \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 */
--- /dev/null
+/********************* */
+/*! \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 */
--- /dev/null
+/********************* */
+/*! \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;
+}
--- /dev/null
+/********************* */
+/*! \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();
+};
+
+}
+}
+}
--- /dev/null
+/********************* */
+/*! \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);
+}
+
--- /dev/null
+/********************* */
+/*! \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 */
** 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"
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) {
break;
case SUB_INEQUALITY:
out << "BV_INEQUALITY_SUBTHEORY";
+ case SUB_ALGEBRAIC:
+ out << "BV_ALGEBRAIC_SUBTHEORY";
default:
Unreachable();
break;
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(); }
};
}
--- /dev/null
+/********************* */
+/*! \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);
+}
--- /dev/null
+/********************* */
+/*! \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);
+};
+
+}
+}
+}
#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;
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) {
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);
}
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);
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
if (!ok) {
std::vector<TNode> conflictAtoms;
d_bitblaster->getConflict(conflictAtoms);
- d_bv->setConflict(mkConjunction(conflictAtoms));
+ setConflict(mkConjunction(conflictAtoms));
return false;
}
}
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();
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;
}
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);
+}
#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
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;
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();
Node getModelValue(TNode node);
bool isComplete() { return true; }
void bitblastQueue();
+ void setAbstraction(AbstractionModule* module);
+ uint64_t computeAtomWeight(TNode atom);
};
}
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);
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);
}
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
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);
}
void CoreSolver::buildModel() {
- if (options::bitvectorCoreSolver()) {
- // FIXME
- Unreachable();
- return;
- }
Debug("bv-core") << "CoreSolver::buildModel() \n";
d_modelValues.clear();
TNodeSet constants;
}
++eqcs_i;
}
+
// build repr to value map
eqcs_i = eq::EqClassesIterator(&d_equalityEngine);
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();
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);
}
}
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);
}
*/
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();
};
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;
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);
}
bool hasTerm(TNode node) const { return d_equalityEngine.hasTerm(node); }
void addTermToEqualityEngine(TNode node) { d_equalityEngine.addTerm(node); }
+ void enableSlicer();
};
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;
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);
+}
#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
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 */
--- /dev/null
+/********************* */
+/*! \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
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"
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 \
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
--- /dev/null
+/********************* */
+/*! \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
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
--- /dev/null
+/********************* */
+/*! \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 */
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);
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;
/********************* */
/*! \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;
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];
}
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);
}
}
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);
StatisticsRegistry::registerStat(&d_numCallsToCheckFullEffort);
StatisticsRegistry::registerStat(&d_numCallsToCheckStandardEffort);
StatisticsRegistry::registerStat(&d_weightComputationTimer);
+ StatisticsRegistry::registerStat(&d_numMultSlice);
}
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) {
}
+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;
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;
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);
}
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);
}
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 {
while (!done()) {
TNode fact = get().assertion;
+
checkForLemma(fact);
for (unsigned i = 0; i < d_subtheories.size(); ++i) {
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);
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()) {
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;
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;
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;
}
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);
}
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) {
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;
+}
** 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"
class CoreSolver;
class InequalitySolver;
+class AlgebraicSolver;
class BitblastSolver;
+class EagerBitblastSolver;
+
+class AbstractionModule;
+
class TheoryBV : public Theory {
/** The context we are using */
Node expandDefinition(LogicRequest &logicRequest, Node node);
+ void mkAckermanizationAsssertions(std::vector<Node>& assertions);
+
void preRegisterTerm(TNode n);
void check(Effort e);
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 {
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();
};
*/
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.
__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;
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();
}
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;
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 */
NotUlt,
NotUle,
MultPow2,
+ MultSlice,
+ ExtractMultLeadingBit,
NegIdemp,
UdivPow2,
UdivOne,
UltOne,
SltZero,
ZeroUlt,
+ MergeSignExtend,
/// normalization rules
ExtractBitwise,
PlusCombineLikeTerms,
MultSimplify,
MultDistribConst,
- MultDistribVariable,
+ MultDistrib,
SolveEq,
BitwiseEq,
AndSimplify,
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;
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;
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();
}
RewriteRule<XorOne> rule83;
RewriteRule<XorZero> rule84;
RewriteRule<MultPow2> rule87;
+ RewriteRule<MultSlice> rule85;
+ RewriteRule<ExtractMultLeadingBit> rule88;
RewriteRule<NegIdemp> rule91;
RewriteRule<UdivPow2> rule92;
RewriteRule<UdivOne> rule93;
RewriteRule<SltZero> rule115;
RewriteRule<BVToNatEliminate> rule116;
RewriteRule<IntToBVEliminate> rule117;
- RewriteRule<MultDistribVariable> rule118;
+ RewriteRule<MultDistrib> rule118;
};
template<> inline
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
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) {
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) {
return utils::mkTrue();
}
- if (newLeft < newRight) {
+ if (newLeft > newRight) {
Assert((newRight == left && newLeft == right) ||
Rewriter::rewrite(newRight) != left ||
Rewriter::rewrite(newLeft) != right);
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
*
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);
+}
+
+
+
// /**
// *
// *
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;
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>
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);
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) {
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);
}
}
};
+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)
--- /dev/null
+/********************* */
+/*! \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;
+}
#include <vector>
#include <sstream>
#include "expr/node_manager.h"
-#include "theory/decision_attributes.h"
+
namespace CVC4 {
namespace theory {
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");
}
-
-
// Turn a set into a string
inline std::string setToString(const std::set<TNode>& nodeSet) {
std::stringstream out;
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);
}
}
#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"
}
}
+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)
/** 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);
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: {
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;
}
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);
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);
smtcompbug.smt
# Regression tests for SMT2 inputs
-SMT2_TESTS =
+SMT2_TESTS = divtest.smt2
# Regression tests for PL inputs
CVC_TESTS = bvsimple.cvc sizecheck.cvc
--- /dev/null
+(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)