mirror of
https://github.com/Z3Prover/z3
synced 2025-04-23 09:05:31 +00:00
refactor basic plugin and clause generation
Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
parent
438389771d
commit
98f4b5103e
8 changed files with 248 additions and 466 deletions
|
@ -604,10 +604,9 @@ namespace sls {
|
|||
bool arith_base<num_t>::update(var_t v, num_t const& new_value) {
|
||||
auto& vi = m_vars[v];
|
||||
expr* e = vi.m_expr;
|
||||
SASSERT(!m.is_value(e));
|
||||
auto old_value = vi.m_value;
|
||||
if (old_value == new_value)
|
||||
return true;
|
||||
return true;
|
||||
if (!vi.in_range(new_value))
|
||||
return false;
|
||||
if (!in_bounds(v, new_value) && in_bounds(v, old_value))
|
||||
|
|
|
@ -29,246 +29,85 @@ namespace sls {
|
|||
bool basic_plugin::is_basic(expr* e) const {
|
||||
if (!e || !is_app(e))
|
||||
return false;
|
||||
if (to_app(e)->get_family_id() != basic_family_id)
|
||||
return false;
|
||||
if (!m.is_bool(e))
|
||||
return false;
|
||||
expr* x, * y;
|
||||
if (m.is_eq(e, x, y) && !m.is_bool(x))
|
||||
return false;
|
||||
if (m.is_distinct(e) && !m.is_bool(to_app(e)->get_arg(0)))
|
||||
return false;
|
||||
if (m.is_not(e, x))
|
||||
return is_basic(x);
|
||||
return true;
|
||||
if (m.is_ite(e) && !m.is_bool(e))
|
||||
return true;
|
||||
if (m.is_xor(e) && to_app(e)->get_num_args() != 2)
|
||||
return true;
|
||||
if (m.is_distinct(e))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
void basic_plugin::propagate_literal(sat::literal lit) {
|
||||
auto a = ctx.atom(lit.var());
|
||||
if (!is_basic(a))
|
||||
return;
|
||||
if (bval1(to_app(a)) != bval0(to_app(a)))
|
||||
ctx.new_value_eh(a);
|
||||
}
|
||||
|
||||
void basic_plugin::register_term(expr* e) {
|
||||
if (is_basic(e) && m.is_bool(e))
|
||||
m_values.setx(e->get_id(), bval1(to_app(e)), false);
|
||||
}
|
||||
|
||||
void basic_plugin::initialize() {
|
||||
}
|
||||
|
||||
bool basic_plugin::propagate() {
|
||||
for (auto t : ctx.subterms())
|
||||
if (is_basic(t) && !m.is_not(t) &&
|
||||
bval0(t) != bval1(to_app(t))) {
|
||||
add_clause(to_app(t));
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool basic_plugin::is_sat() {
|
||||
for (auto t : ctx.subterms())
|
||||
if (is_basic(t) && !m.is_not(t) &&
|
||||
bval0(t) != bval1(to_app(t))) {
|
||||
verbose_stream() << mk_bounded_pp(t, m) << " := " << (bval0(t) ? "T" : "F") << " eval: " << (bval1(to_app(t)) ? "T" : "F") << "\n";
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
std::ostream& basic_plugin::display(std::ostream& out) const {
|
||||
for (auto t : ctx.subterms())
|
||||
if (is_basic(t))
|
||||
out << mk_bounded_pp(t, m) << " := " << (bval0(t)?"T":"F") << " eval: " << (bval1(to_app(t))?"T":"F") << "\n";
|
||||
return out;
|
||||
}
|
||||
|
||||
bool basic_plugin::set_value(expr* e, expr* v) {
|
||||
if (!is_basic(e))
|
||||
if (!m.is_bool(e))
|
||||
return false;
|
||||
SASSERT(m.is_true(v) || m.is_false(v));
|
||||
return set_value(e, m.is_true(v));
|
||||
}
|
||||
|
||||
bool basic_plugin::bval1(app* e) const {
|
||||
verbose_stream() << mk_bounded_pp(e, m) << "\n";
|
||||
if (m.is_not(e))
|
||||
return bval1(to_app(e->get_arg(0)));
|
||||
SASSERT(m.is_bool(e));
|
||||
SASSERT(e->get_family_id() == basic_family_id);
|
||||
expr_ref basic_plugin::eval_ite(app* e) {
|
||||
expr* c, * th, * el;
|
||||
VERIFY(m.is_ite(e, c, th, el));
|
||||
if (bval0(c))
|
||||
return ctx.get_value(th);
|
||||
else
|
||||
return ctx.get_value(el);
|
||||
}
|
||||
|
||||
auto id = e->get_id();
|
||||
switch (e->get_decl_kind()) {
|
||||
case OP_TRUE:
|
||||
return true;
|
||||
case OP_FALSE:
|
||||
return false;
|
||||
case OP_AND:
|
||||
return all_of(*to_app(e), [&](expr* arg) { return bval0(arg); });
|
||||
case OP_OR:
|
||||
return any_of(*to_app(e), [&](expr* arg) { return bval0(arg); });
|
||||
case OP_NOT:
|
||||
return !bval0(e->get_arg(0));
|
||||
case OP_XOR: {
|
||||
bool r = false;
|
||||
for (auto* arg : *to_app(e))
|
||||
r ^= bval0(arg);
|
||||
return r;
|
||||
expr_ref basic_plugin::eval_distinct(app* e) {
|
||||
for (unsigned i = 0; i < e->get_num_args(); ++i) {
|
||||
for (unsigned j = i + 1; j < e->get_num_args(); ++j) {
|
||||
if (bval0(e->get_arg(i)) == bval0(e->get_arg(j)))
|
||||
return expr_ref(m.mk_false(), m);
|
||||
}
|
||||
}
|
||||
case OP_IMPLIES: {
|
||||
auto a = e->get_arg(0);
|
||||
auto b = e->get_arg(1);
|
||||
return !bval0(a) || bval0(b);
|
||||
}
|
||||
case OP_ITE: {
|
||||
auto c = bval0(e->get_arg(0));
|
||||
return bval0(c ? e->get_arg(1) : e->get_arg(2));
|
||||
}
|
||||
case OP_EQ: {
|
||||
auto a = e->get_arg(0);
|
||||
auto b = e->get_arg(1);
|
||||
if (m.is_bool(a))
|
||||
return bval0(a) == bval0(b);
|
||||
verbose_stream() << mk_bounded_pp(e, m) << " " << ctx.get_value(a) << " " << ctx.get_value(b) << "\n";
|
||||
return ctx.get_value(a) == ctx.get_value(b);
|
||||
}
|
||||
case OP_DISTINCT: {
|
||||
for (unsigned i = 0; i < e->get_num_args(); ++i)
|
||||
for (unsigned j = i + 1; j < e->get_num_args(); ++j)
|
||||
if (ctx.get_value(e->get_arg(i)) == ctx.get_value(e->get_arg(j)))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
default:
|
||||
verbose_stream() << mk_bounded_pp(e, m) << "\n";
|
||||
UNREACHABLE();
|
||||
break;
|
||||
}
|
||||
UNREACHABLE();
|
||||
return false;
|
||||
return expr_ref(m.mk_true(), m);
|
||||
}
|
||||
|
||||
expr_ref basic_plugin::eval_xor(app* e) {
|
||||
bool b = false;
|
||||
for (expr* arg : *e)
|
||||
b ^= bval0(arg);
|
||||
return expr_ref(m.mk_bool_val(b), m);
|
||||
}
|
||||
|
||||
bool basic_plugin::bval0(expr* e) const {
|
||||
SASSERT(m.is_bool(e));
|
||||
bool b = true;
|
||||
while (m.is_not(e, e))
|
||||
b = !b;
|
||||
sat::bool_var v = ctx.atom2bool_var(e);
|
||||
if (v == sat::null_bool_var)
|
||||
return b == m_values.get(e->get_id(), false);
|
||||
else
|
||||
return b == ctx.is_true(v);
|
||||
SASSERT(m.is_bool(e));
|
||||
return ctx.is_true(ctx.mk_literal(e));
|
||||
}
|
||||
|
||||
bool basic_plugin::try_repair(app* e, unsigned i) {
|
||||
switch (e->get_decl_kind()) {
|
||||
case OP_AND:
|
||||
return try_repair_and_or(e, i);
|
||||
case OP_OR:
|
||||
return try_repair_and_or(e, i);
|
||||
case OP_NOT:
|
||||
return try_repair_not(e);
|
||||
case OP_FALSE:
|
||||
return false;
|
||||
case OP_TRUE:
|
||||
return false;
|
||||
case OP_EQ:
|
||||
return try_repair_eq(e, i);
|
||||
case OP_IMPLIES:
|
||||
return try_repair_implies(e, i);
|
||||
case OP_XOR:
|
||||
return try_repair_xor(e, i);
|
||||
case OP_ITE:
|
||||
return try_repair_ite(e, i);
|
||||
case OP_DISTINCT:
|
||||
return try_repair_distinct(e, i);
|
||||
default:
|
||||
UNREACHABLE();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void basic_plugin::add_clause(app* e) {
|
||||
expr_ref_vector es(m);
|
||||
expr_ref fml(m);
|
||||
expr* x, *y;
|
||||
switch (e->get_decl_kind()) {
|
||||
case OP_AND:
|
||||
for (expr* arg : *e) {
|
||||
ctx.add_constraint(m.mk_or(m.mk_not(e), arg));
|
||||
es.push_back(mk_not(m, arg));
|
||||
}
|
||||
es.push_back(e);
|
||||
ctx.add_constraint(m.mk_or(es));
|
||||
break;
|
||||
case OP_OR:
|
||||
for (expr* arg : *e) {
|
||||
ctx.add_constraint(m.mk_or(mk_not(m, arg), e));
|
||||
es.push_back(arg);
|
||||
}
|
||||
es.push_back(m.mk_not(e));
|
||||
ctx.add_constraint(m.mk_or(es));
|
||||
break;
|
||||
case OP_NOT:
|
||||
break;
|
||||
case OP_FALSE:
|
||||
break;
|
||||
case OP_TRUE:
|
||||
break;
|
||||
case OP_EQ:
|
||||
VERIFY(m.is_eq(e, x, y));
|
||||
ctx.add_constraint(m.mk_or(m.mk_not(e), mk_not(m, x), y));
|
||||
ctx.add_constraint(m.mk_or(m.mk_not(e), mk_not(m, y), x));
|
||||
ctx.add_constraint(m.mk_or(e, y, x));
|
||||
ctx.add_constraint(m.mk_or(e, mk_not(m, x), mk_not(m, y)));
|
||||
break;
|
||||
case OP_IMPLIES:
|
||||
NOT_IMPLEMENTED_YET();
|
||||
case OP_XOR:
|
||||
NOT_IMPLEMENTED_YET();
|
||||
case OP_ITE:
|
||||
|
||||
NOT_IMPLEMENTED_YET();
|
||||
case OP_DISTINCT:
|
||||
NOT_IMPLEMENTED_YET();
|
||||
default:
|
||||
UNREACHABLE();
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
bool basic_plugin::try_repair_and_or(app* e, unsigned i) {
|
||||
auto b = bval0(e);
|
||||
if ((b && m.is_and(e)) || (!b && m.is_or(e))) {
|
||||
for (auto arg : *e)
|
||||
if (!set_value(arg, b))
|
||||
return false;
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
auto child = e->get_arg(i);
|
||||
if (b == bval0(child))
|
||||
return false;
|
||||
return set_value(child, b);
|
||||
}
|
||||
|
||||
bool basic_plugin::try_repair_not(app* e) {
|
||||
auto child = e->get_arg(0);
|
||||
return set_value(child, !bval0(e));
|
||||
}
|
||||
|
||||
bool basic_plugin::try_repair_eq(app* e, unsigned i) {
|
||||
auto child = e->get_arg(i);
|
||||
auto sibling = e->get_arg(1 - i);
|
||||
if (!m.is_bool(child))
|
||||
return false;
|
||||
return set_value(child, bval0(e) == bval0(sibling));
|
||||
}
|
||||
}
|
||||
|
||||
bool basic_plugin::try_repair_xor(app* e, unsigned i) {
|
||||
|
@ -283,12 +122,7 @@ namespace sls {
|
|||
|
||||
bool basic_plugin::try_repair_ite(app* e, unsigned i) {
|
||||
if (m.is_bool(e))
|
||||
return try_repair_ite_bool(e, i);
|
||||
else
|
||||
return try_repair_ite_nonbool(e, i);
|
||||
}
|
||||
|
||||
bool basic_plugin::try_repair_ite_nonbool(app* e, unsigned i) {
|
||||
return true;
|
||||
auto child = e->get_arg(i);
|
||||
auto cond = e->get_arg(0);
|
||||
bool c = bval0(cond);
|
||||
|
@ -307,85 +141,45 @@ namespace sls {
|
|||
}
|
||||
if (c != (i == 1))
|
||||
return false;
|
||||
return ctx.set_value(child, ctx.get_value(e));
|
||||
}
|
||||
|
||||
bool basic_plugin::try_repair_ite_bool(app* e, unsigned i) {
|
||||
auto child = e->get_arg(i);
|
||||
auto cond = e->get_arg(0);
|
||||
bool c = bval0(cond);
|
||||
if (i == 0) {
|
||||
if (ctx.rand(2) == 0)
|
||||
return set_value(cond, true) && set_value(e->get_arg(1), bval0(e));
|
||||
else
|
||||
return set_value(cond, false) && set_value(e->get_arg(2), bval0(e));
|
||||
}
|
||||
|
||||
if (!set_value(child, bval0(e)))
|
||||
if (m.is_value(child))
|
||||
return false;
|
||||
return (c == (i == 1)) || set_value(cond, !c);
|
||||
}
|
||||
|
||||
bool basic_plugin::try_repair_implies(app* e, unsigned i) {
|
||||
auto child = e->get_arg(i);
|
||||
auto sibling = e->get_arg(1 - i);
|
||||
bool ev = bval0(e);
|
||||
bool av = bval0(child);
|
||||
bool bv = bval0(sibling);
|
||||
if (ev) {
|
||||
|
||||
if (i == 0 && (!av || bv))
|
||||
return true;
|
||||
if (i == 1 && (!bv || av))
|
||||
return true;
|
||||
if (i == 0) {
|
||||
return set_value(child, false);
|
||||
}
|
||||
if (i == 1) {
|
||||
return set_value(child, true);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
if (i == 0 && av && !bv)
|
||||
return true;
|
||||
if (i == 1 && bv && !av)
|
||||
return true;
|
||||
if (i == 0)
|
||||
return set_value(child, true) && set_value(sibling, false);
|
||||
if (i == 1)
|
||||
return set_value(child, false) && set_value(sibling, true);
|
||||
return false;
|
||||
bool r = ctx.set_value(child, ctx.get_value(e));
|
||||
verbose_stream() << "repair-ite-down " << mk_bounded_pp(e, m) << " @ " << mk_bounded_pp(child, m) << " := " << ctx.get_value(e) << " success " << r << "\n";
|
||||
return r;
|
||||
}
|
||||
|
||||
void basic_plugin::repair_up(app* e) {
|
||||
expr* c, * th, * el;
|
||||
expr_ref val(m);
|
||||
if (!is_basic(e))
|
||||
return;
|
||||
auto b = bval1(e);
|
||||
if (bval0(e) == b)
|
||||
if (m.is_ite(e, c, th, el) && !m.is_bool(e))
|
||||
val = eval_ite(e);
|
||||
else if (m.is_xor(e))
|
||||
val = eval_xor(e);
|
||||
else if (m.is_distinct(e))
|
||||
val = eval_distinct(e);
|
||||
else
|
||||
return;
|
||||
set_value(e, b);
|
||||
verbose_stream() << "repair-up " << mk_bounded_pp(e, m) << " " << val << "\n";
|
||||
if (!ctx.set_value(e, val))
|
||||
ctx.new_value_eh(e);
|
||||
}
|
||||
|
||||
void basic_plugin::repair_literal(sat::literal lit) {
|
||||
auto a = ctx.atom(lit.var());
|
||||
if (!is_basic(a))
|
||||
return;
|
||||
if (bval1(to_app(a)) != bval0(to_app(a)))
|
||||
ctx.flip(lit.var());
|
||||
}
|
||||
|
||||
bool basic_plugin::repair_down(app* e) {
|
||||
SASSERT(m.is_bool(e));
|
||||
|
||||
unsigned n = e->get_num_args();
|
||||
bool basic_plugin::repair_down(app* e) {
|
||||
if (!is_basic(e))
|
||||
return false;
|
||||
if (n == 0)
|
||||
return true;
|
||||
if (m.is_xor(e) && eval_xor(e) == ctx.get_value(e))
|
||||
return true;
|
||||
|
||||
if (bval0(e) == bval1(e))
|
||||
if (m.is_ite(e) && eval_ite(e) == ctx.get_value(e))
|
||||
return true;
|
||||
if (m.is_distinct(e) && eval_distinct(e) == ctx.get_value(e))
|
||||
return true;
|
||||
verbose_stream() << "basic repair down " << mk_bounded_pp(e, m) << "\n";
|
||||
unsigned n = e->get_num_args();
|
||||
unsigned s = ctx.rand(n);
|
||||
for (unsigned i = 0; i < n; ++i) {
|
||||
auto j = (i + s) % n;
|
||||
|
@ -396,23 +190,14 @@ namespace sls {
|
|||
}
|
||||
|
||||
bool basic_plugin::try_repair_distinct(app* e, unsigned i) {
|
||||
NOT_IMPLEMENTED_YET();
|
||||
return false;
|
||||
}
|
||||
|
||||
bool basic_plugin::set_value(expr* e, bool b) {
|
||||
if (m.is_true(e) && !b)
|
||||
return false;
|
||||
if (m.is_false(e) && b)
|
||||
return false;
|
||||
sat::bool_var v = ctx.atom2bool_var(e);
|
||||
if (v == sat::null_bool_var) {
|
||||
if (m_values.get(e->get_id(), b) != b) {
|
||||
m_values.set(e->get_id(), b);
|
||||
ctx.new_value_eh(e);
|
||||
}
|
||||
}
|
||||
else if (ctx.is_true(v) != b) {
|
||||
ctx.flip(v);
|
||||
auto lit = ctx.mk_literal(e);
|
||||
if (ctx.is_true(lit) != b) {
|
||||
ctx.flip(lit.var());
|
||||
ctx.new_value_eh(e);
|
||||
}
|
||||
return true;
|
||||
|
|
|
@ -17,25 +17,20 @@ Author:
|
|||
namespace sls {
|
||||
|
||||
class basic_plugin : public plugin {
|
||||
bool_vector m_values;
|
||||
bool m_initialized = false;
|
||||
expr_mark m_axiomatized;
|
||||
|
||||
bool is_basic(expr* e) const;
|
||||
bool bval1(app* e) const;
|
||||
bool bval0(expr* e) const;
|
||||
bool try_repair(app* e, unsigned i);
|
||||
bool try_repair_and_or(app* e, unsigned i);
|
||||
bool try_repair_not(app* e);
|
||||
bool try_repair_eq(app* e, unsigned i);
|
||||
bool try_repair_xor(app* e, unsigned i);
|
||||
bool try_repair_ite(app* e, unsigned i);
|
||||
bool try_repair_ite_nonbool(app* e, unsigned i);
|
||||
bool try_repair_ite_bool(app* e, unsigned i);
|
||||
bool try_repair_implies(app* e, unsigned i);
|
||||
bool try_repair_distinct(app* e, unsigned i);
|
||||
bool set_value(expr* e, bool b);
|
||||
|
||||
void add_clause(app* e);
|
||||
expr_ref eval_ite(app* e);
|
||||
expr_ref eval_distinct(app* e);
|
||||
expr_ref eval_xor(app* e);
|
||||
|
||||
public:
|
||||
basic_plugin(context& ctx) :
|
||||
|
|
|
@ -21,6 +21,7 @@ Author:
|
|||
#include "ast/sls/sls_bv_plugin.h"
|
||||
#include "ast/sls/sls_basic_plugin.h"
|
||||
#include "ast/ast_ll_pp.h"
|
||||
#include "ast/ast_pp.h"
|
||||
|
||||
namespace sls {
|
||||
|
||||
|
@ -96,9 +97,9 @@ namespace sls {
|
|||
reinit_relevant();
|
||||
|
||||
for (sat::literal lit : root_literals()) {
|
||||
if (m_new_constraint)
|
||||
break;
|
||||
propagate_literal(lit);
|
||||
if (m_new_constraint)
|
||||
return;
|
||||
}
|
||||
|
||||
while (!m_new_constraint && m.inc() && (!m_repair_up.empty() || !m_repair_down.empty())) {
|
||||
|
@ -125,15 +126,20 @@ namespace sls {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// propagate "final checks"
|
||||
bool propagated = true;
|
||||
while (propagated && !m_new_constraint) {
|
||||
propagated = false;
|
||||
for (auto p : m_plugins)
|
||||
propagated |= p && !m_new_constraint && p->propagate();
|
||||
}
|
||||
}
|
||||
|
||||
for (sat::bool_var v = 0; v < s.num_vars(); ++v) {
|
||||
if (m_new_constraint)
|
||||
return;
|
||||
|
||||
for (sat::bool_var v = 0; v < s.num_vars() && !m_new_constraint; ++v) {
|
||||
auto a = atom(v);
|
||||
if (!a)
|
||||
continue;
|
||||
|
@ -148,10 +154,8 @@ namespace sls {
|
|||
if (!is_app(e))
|
||||
return null_family_id;
|
||||
family_id fid = to_app(e)->get_family_id();
|
||||
if (m.is_eq(e) || m.is_distinct(e))
|
||||
if (m.is_eq(e))
|
||||
fid = to_app(e)->get_arg(0)->get_sort()->get_family_id();
|
||||
else if (m.is_ite(e))
|
||||
fid = to_app(e)->get_arg(1)->get_sort()->get_family_id();
|
||||
return fid;
|
||||
}
|
||||
|
||||
|
@ -191,7 +195,6 @@ namespace sls {
|
|||
return expr_ref(e, m);
|
||||
}
|
||||
|
||||
|
||||
bool context::set_value(expr * e, expr * v) {
|
||||
for (auto p : m_plugins)
|
||||
if (p && p->set_value(e, v))
|
||||
|
@ -215,34 +218,151 @@ namespace sls {
|
|||
return false;
|
||||
}
|
||||
|
||||
void context::add_constraint(expr* e) {
|
||||
expr_ref _e(e, m);
|
||||
sat::literal_vector lits;
|
||||
auto add_literal = [&](expr* e) {
|
||||
bool is_neg = m.is_not(e, e);
|
||||
auto v = mk_atom(e);
|
||||
lits.push_back(sat::literal(v, is_neg));
|
||||
};
|
||||
if (m.is_or(e))
|
||||
for (auto arg : *to_app(e))
|
||||
add_literal(arg);
|
||||
else
|
||||
add_literal(e);
|
||||
TRACE("sls", tout << "new clause " << lits << "\n");
|
||||
s.add_clause(lits.size(), lits.data());
|
||||
void context::add_constraint(expr* e) {
|
||||
add_clause(e);
|
||||
m_new_constraint = true;
|
||||
}
|
||||
|
||||
sat::bool_var context::mk_atom(expr* e) {
|
||||
auto v = m_atom2bool_var.get(e->get_id(), sat::null_bool_var);
|
||||
if (v == sat::null_bool_var) {
|
||||
v = s.add_var();
|
||||
register_atom(v, e);
|
||||
register_terms(e);
|
||||
void context::add_clause(expr* f) {
|
||||
expr_ref _e(f, m);
|
||||
verbose_stream() << "add constraint " << _e << "\n";
|
||||
expr* g, * h, * k;
|
||||
sat::literal_vector clause;
|
||||
if (m.is_not(f, g) && m.is_not(g, g)) {
|
||||
add_clause(g);
|
||||
return;
|
||||
}
|
||||
bool sign = m.is_not(f, f);
|
||||
if (!sign && m.is_or(f)) {
|
||||
clause.reset();
|
||||
for (auto arg : *to_app(f))
|
||||
clause.push_back(mk_literal(arg));
|
||||
s.add_clause(clause.size(), clause.data());
|
||||
}
|
||||
else if (!sign && m.is_and(f)) {
|
||||
for (auto arg : *to_app(f))
|
||||
add_clause(arg);
|
||||
}
|
||||
else if (sign && m.is_or(f)) {
|
||||
for (auto arg : *to_app(f)) {
|
||||
expr_ref fml(m.mk_not(arg), m);;
|
||||
add_clause(fml);
|
||||
}
|
||||
}
|
||||
else if (sign && m.is_and(f)) {
|
||||
clause.reset();
|
||||
for (auto arg : *to_app(f))
|
||||
clause.push_back(~mk_literal(arg));
|
||||
s.add_clause(clause.size(), clause.data());
|
||||
}
|
||||
else if (m.is_iff(f, g, h)) {
|
||||
auto lit1 = mk_literal(g);
|
||||
auto lit2 = mk_literal(h);
|
||||
sat::literal cls1[2] = { sign ? lit1 : ~lit1, lit2 };
|
||||
sat::literal cls2[2] = { sign ? ~lit1 : lit1, ~lit2 };
|
||||
s.add_clause(2, cls1);
|
||||
s.add_clause(2, cls2);
|
||||
}
|
||||
else if (m.is_ite(f, g, h, k)) {
|
||||
auto lit1 = mk_literal(g);
|
||||
auto lit2 = mk_literal(h);
|
||||
auto lit3 = mk_literal(k);
|
||||
// (g -> h) & (~g -> k)
|
||||
// (g & h) | (~g & k)
|
||||
// negated: (g -> ~h) & (g -> ~k)
|
||||
sat::literal cls1[2] = { ~lit1, sign ? ~lit2 : lit2 };
|
||||
sat::literal cls2[2] = { lit1, sign ? ~lit3 : lit3 };
|
||||
s.add_clause(2, cls1);
|
||||
s.add_clause(2, cls2);
|
||||
}
|
||||
else {
|
||||
sat::literal lit = mk_literal(f);
|
||||
if (sign)
|
||||
lit.neg();
|
||||
s.add_clause(1, &lit);
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
sat::literal context::mk_literal() {
|
||||
sat::bool_var v = s.add_var();
|
||||
return sat::literal(v, false);
|
||||
}
|
||||
|
||||
sat::literal context::mk_literal(expr* e) {
|
||||
sat::literal lit;
|
||||
bool neg = false;
|
||||
expr* a, * b, * c;
|
||||
while (m.is_not(e, e))
|
||||
neg = !neg;
|
||||
auto v = m_atom2bool_var.get(e->get_id(), sat::null_bool_var);
|
||||
if (v != sat::null_bool_var)
|
||||
return sat::literal(v, neg);
|
||||
sat::literal_vector clause;
|
||||
lit = mk_literal();
|
||||
if (m.is_true(e)) {
|
||||
clause.push_back(lit);
|
||||
s.add_clause(clause.size(), clause.data());
|
||||
}
|
||||
else if (m.is_false(e)) {
|
||||
clause.push_back(~lit);
|
||||
s.add_clause(clause.size(), clause.data());
|
||||
}
|
||||
else if (m.is_and(e)) {
|
||||
for (expr* arg : *to_app(e)) {
|
||||
auto lit2 = mk_literal(arg);
|
||||
clause.push_back(~lit2);
|
||||
sat::literal lits[2] = { ~lit, lit2 };
|
||||
s.add_clause(2, lits);
|
||||
}
|
||||
clause.push_back(lit);
|
||||
s.add_clause(clause.size(), clause.data());
|
||||
}
|
||||
else if (m.is_or(e)) {
|
||||
for (expr* arg : *to_app(e)) {
|
||||
auto lit2 = mk_literal(arg);
|
||||
clause.push_back(lit2);
|
||||
sat::literal lits[2] = { lit, ~lit2 };
|
||||
s.add_clause(2, lits);
|
||||
}
|
||||
clause.push_back(~lit);
|
||||
s.add_clause(clause.size(), clause.data());
|
||||
}
|
||||
else if (m.is_iff(e, a, b) || m.is_xor(e, a, b)) {
|
||||
auto lit1 = mk_literal(a);
|
||||
auto lit2 = mk_literal(b);
|
||||
if (m.is_xor(e))
|
||||
lit2.neg();
|
||||
sat::literal cls1[3] = { ~lit, ~lit1, lit2 };
|
||||
sat::literal cls2[3] = { ~lit, lit1, ~lit2 };
|
||||
sat::literal cls3[3] = { lit, lit1, lit2 };
|
||||
sat::literal cls4[3] = { lit, ~lit1, ~lit2 };
|
||||
s.add_clause(3, cls1);
|
||||
s.add_clause(3, cls2);
|
||||
s.add_clause(3, cls3);
|
||||
s.add_clause(3, cls4);
|
||||
}
|
||||
else if (m.is_ite(e, a, b, c)) {
|
||||
auto lit1 = mk_literal(a);
|
||||
auto lit2 = mk_literal(b);
|
||||
auto lit3 = mk_literal(c);
|
||||
sat::literal cls1[3] = { ~lit, ~lit1, lit2 };
|
||||
sat::literal cls2[3] = { ~lit, lit1, lit3 };
|
||||
sat::literal cls3[3] = { lit, ~lit1, ~lit2 };
|
||||
sat::literal cls4[3] = { lit, lit1, ~lit3 };
|
||||
s.add_clause(3, cls1);
|
||||
s.add_clause(3, cls2);
|
||||
s.add_clause(3, cls3);
|
||||
s.add_clause(3, cls4);
|
||||
}
|
||||
else
|
||||
register_terms(e);
|
||||
|
||||
register_atom(lit.var(), e);
|
||||
|
||||
return neg ? ~lit : lit;
|
||||
}
|
||||
|
||||
|
||||
void context::init() {
|
||||
m_new_constraint = false;
|
||||
if (m_initialized)
|
||||
|
|
|
@ -104,12 +104,13 @@ namespace sls {
|
|||
random_gen m_rand;
|
||||
bool m_initialized = false;
|
||||
bool m_new_constraint = false;
|
||||
bool m_dirty = false;
|
||||
expr_ref_vector m_allterms;
|
||||
ptr_vector<expr> m_subterms;
|
||||
greater_depth m_gd;
|
||||
less_depth m_ld;
|
||||
heap<greater_depth> m_repair_down;
|
||||
heap<less_depth> m_repair_up;
|
||||
heap<less_depth> m_repair_up;
|
||||
|
||||
void register_plugin(plugin* p);
|
||||
|
||||
|
@ -117,12 +118,14 @@ namespace sls {
|
|||
ptr_vector<expr> m_todo;
|
||||
void register_terms(expr* e);
|
||||
void register_term(expr* e);
|
||||
sat::bool_var mk_atom(expr* e);
|
||||
|
||||
void propagate_boolean_assignment();
|
||||
void propagate_literal(sat::literal lit);
|
||||
|
||||
family_id get_fid(expr* e) const;
|
||||
|
||||
|
||||
sat::literal mk_literal();
|
||||
|
||||
public:
|
||||
context(ast_manager& m, sat_solver_context& s);
|
||||
|
@ -142,6 +145,8 @@ namespace sls {
|
|||
expr* atom(sat::bool_var v) { return m_atoms.get(v, nullptr); }
|
||||
expr* term(unsigned id) const { return m_allterms.get(id); }
|
||||
sat::bool_var atom2bool_var(expr* e) const { return m_atom2bool_var.get(e->get_id(), sat::null_bool_var); }
|
||||
sat::literal mk_literal(expr* e);
|
||||
void add_clause(expr* f);
|
||||
void flip(sat::bool_var v) { s.flip(v); }
|
||||
double reward(sat::bool_var v) { return s.reward(v); }
|
||||
indexed_uint_set const& unsat() const { return s.unsat(); }
|
||||
|
|
|
@ -27,8 +27,9 @@ namespace sls {
|
|||
ast_manager& m;
|
||||
sat::ddfw& m_ddfw;
|
||||
context m_context;
|
||||
bool m_new_clause_added = false;
|
||||
bool m_dirty = false;
|
||||
model_ref m_model;
|
||||
obj_map<expr, sat::literal> m_expr2lit;
|
||||
public:
|
||||
solver_ctx(ast_manager& m, sat::ddfw& d) :
|
||||
m(m), m_ddfw(d), m_context(m, *this) {
|
||||
|
@ -54,11 +55,11 @@ namespace sls {
|
|||
TRACE("sls", display(tout));
|
||||
while (unsat().empty()) {
|
||||
m_context.check();
|
||||
if (!m_new_clause_added)
|
||||
if (!m_dirty)
|
||||
break;
|
||||
TRACE("sls", display(tout));
|
||||
m_ddfw.reinit();
|
||||
m_new_clause_added = false;
|
||||
m_dirty = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -80,17 +81,29 @@ namespace sls {
|
|||
vector<sat::clause_info> const& clauses() const override { return m_ddfw.clauses(); }
|
||||
sat::clause_info const& get_clause(unsigned idx) const override { return m_ddfw.get_clause_info(idx); }
|
||||
ptr_iterator<unsigned> get_use_list(sat::literal lit) override { return m_ddfw.use_list(lit); }
|
||||
void flip(sat::bool_var v) override { m_ddfw.flip(v); }
|
||||
void flip(sat::bool_var v) override { if (m_dirty) m_ddfw.reinit(), m_dirty = false; m_ddfw.flip(v); }
|
||||
double reward(sat::bool_var v) override { return m_ddfw.get_reward(v); }
|
||||
double get_weigth(unsigned clause_idx) override { return m_ddfw.get_clause_info(clause_idx).m_weight; }
|
||||
bool is_true(sat::literal lit) override { return m_ddfw.get_value(lit.var()) != lit.sign(); }
|
||||
unsigned num_vars() const override { return m_ddfw.num_vars(); }
|
||||
indexed_uint_set const& unsat() const override { return m_ddfw.unsat_set(); }
|
||||
sat::bool_var add_var() override { return m_ddfw.add_var(); }
|
||||
void add_clause(unsigned n, sat::literal const* lits) override {
|
||||
m_ddfw.add(n, lits);
|
||||
m_new_clause_added = true;
|
||||
sat::bool_var add_var() override { m_dirty = true; return m_ddfw.add_var(); }
|
||||
|
||||
|
||||
void add_clause(expr* f) {
|
||||
m_context.add_clause(f);
|
||||
}
|
||||
|
||||
void add_clause(unsigned n, sat::literal const* lits) override {
|
||||
m_ddfw.add(n, lits);
|
||||
m_dirty = true;
|
||||
}
|
||||
|
||||
sat::literal mk_literal() {
|
||||
sat::bool_var v = add_var();
|
||||
return sat::literal(v, false);
|
||||
}
|
||||
|
||||
model_ref get_model() { return m_model; }
|
||||
|
||||
void collect_statistics(statistics& st) {
|
||||
|
@ -129,143 +142,13 @@ namespace sls {
|
|||
// send expression mapping to m_solver_ctx
|
||||
|
||||
for (auto f : m_assertions)
|
||||
add_clause(f);
|
||||
m_solver_ctx->add_clause(f);
|
||||
|
||||
IF_VERBOSE(10, m_solver_ctx->display(verbose_stream()));
|
||||
auto r = m_ddfw.check(0, nullptr);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
void smt_solver::add_clause(expr* f) {
|
||||
expr* g, * h, * k;
|
||||
sat::literal_vector clause;
|
||||
if (m.is_not(f, g) && m.is_not(g, g)) {
|
||||
add_clause(g);
|
||||
return;
|
||||
}
|
||||
bool sign = m.is_not(f, f);
|
||||
if (!sign && m.is_or(f)) {
|
||||
clause.reset();
|
||||
for (auto arg : *to_app(f))
|
||||
clause.push_back(mk_literal(arg));
|
||||
m_solver_ctx->add_clause(clause.size(), clause.data());
|
||||
}
|
||||
else if (!sign && m.is_and(f)) {
|
||||
for (auto arg : *to_app(f))
|
||||
add_clause(arg);
|
||||
}
|
||||
else if (sign && m.is_or(f)) {
|
||||
for (auto arg : *to_app(f)) {
|
||||
expr_ref fml(m.mk_not(arg), m);;
|
||||
add_clause(fml);
|
||||
}
|
||||
}
|
||||
else if (sign && m.is_and(f)) {
|
||||
clause.reset();
|
||||
for (auto arg : *to_app(f))
|
||||
clause.push_back(~mk_literal(arg));
|
||||
m_solver_ctx->add_clause(clause.size(), clause.data());
|
||||
}
|
||||
else if (m.is_iff(f, g, h)) {
|
||||
auto lit1 = mk_literal(g);
|
||||
auto lit2 = mk_literal(h);
|
||||
sat::literal cls1[2] = { sign ? lit1 :~lit1, lit2 };
|
||||
sat::literal cls2[2] = { sign ? ~lit1 : lit1, ~lit2 };
|
||||
m_solver_ctx->add_clause(2, cls1);
|
||||
m_solver_ctx->add_clause(2, cls2);
|
||||
}
|
||||
else if (m.is_ite(f, g, h, k)) {
|
||||
auto lit1 = mk_literal(g);
|
||||
auto lit2 = mk_literal(h);
|
||||
auto lit3 = mk_literal(k);
|
||||
// (g -> h) & (~g -> k)
|
||||
// (g & h) | (~g & k)
|
||||
// negated: (g -> ~h) & (g -> ~k)
|
||||
sat::literal cls1[2] = { ~lit1, sign ? ~lit2 : lit2 };
|
||||
sat::literal cls2[2] = { lit1, sign ? ~lit3 : lit3 };
|
||||
m_solver_ctx->add_clause(2, cls1);
|
||||
m_solver_ctx->add_clause(2, cls2);
|
||||
}
|
||||
else {
|
||||
sat::literal lit = mk_literal(f);
|
||||
if (sign)
|
||||
lit.neg();
|
||||
m_solver_ctx->add_clause(1, &lit);
|
||||
}
|
||||
}
|
||||
|
||||
sat::literal smt_solver::mk_literal(expr* e) {
|
||||
sat::literal lit;
|
||||
bool neg = false;
|
||||
expr* a, * b, * c;
|
||||
while (m.is_not(e,e))
|
||||
neg = !neg;
|
||||
if (m_expr2lit.find(e, lit))
|
||||
return neg ? ~lit : lit;
|
||||
sat::literal_vector clause;
|
||||
if (m.is_and(e)) {
|
||||
lit = mk_literal();
|
||||
for (expr* arg : *to_app(e)) {
|
||||
auto lit2 = mk_literal(arg);
|
||||
clause.push_back(~lit2);
|
||||
sat::literal lits[2] = { ~lit, lit2 };
|
||||
m_solver_ctx->add_clause(2, lits);
|
||||
}
|
||||
clause.push_back(lit);
|
||||
m_solver_ctx->add_clause(clause.size(), clause.data());
|
||||
}
|
||||
else if (m.is_or(e)) {
|
||||
lit = mk_literal();
|
||||
for (expr* arg : *to_app(e)) {
|
||||
auto lit2 = mk_literal(arg);
|
||||
clause.push_back(lit2);
|
||||
sat::literal lits[2] = { lit, ~lit2 };
|
||||
m_solver_ctx->add_clause(2, lits);
|
||||
}
|
||||
clause.push_back(~lit);
|
||||
m_solver_ctx->add_clause(clause.size(), clause.data());
|
||||
}
|
||||
else if (m.is_iff(e, a, b)) {
|
||||
lit = mk_literal();
|
||||
auto lit1 = mk_literal(a);
|
||||
auto lit2 = mk_literal(b);
|
||||
sat::literal cls1[3] = { ~lit, ~lit1, lit2 };
|
||||
sat::literal cls2[3] = { ~lit, lit1, ~lit2 };
|
||||
sat::literal cls3[3] = { lit, lit1, lit2 };
|
||||
sat::literal cls4[3] = { lit, ~lit1, ~lit2 };
|
||||
m_solver_ctx->add_clause(3, cls1);
|
||||
m_solver_ctx->add_clause(3, cls2);
|
||||
m_solver_ctx->add_clause(3, cls3);
|
||||
m_solver_ctx->add_clause(3, cls4);
|
||||
}
|
||||
else if (m.is_ite(e, a, b, c)) {
|
||||
lit = mk_literal();
|
||||
auto lit1 = mk_literal(a);
|
||||
auto lit2 = mk_literal(b);
|
||||
auto lit3 = mk_literal(c);
|
||||
sat::literal cls1[3] = { ~lit, ~lit1, lit2 };
|
||||
sat::literal cls2[3] = { ~lit, lit1, lit3 };
|
||||
sat::literal cls3[3] = { lit, ~lit1, ~lit2 };
|
||||
sat::literal cls4[3] = { lit, lit1, ~lit3 };
|
||||
m_solver_ctx->add_clause(3, cls1);
|
||||
m_solver_ctx->add_clause(3, cls2);
|
||||
m_solver_ctx->add_clause(3, cls3);
|
||||
m_solver_ctx->add_clause(3, cls4);
|
||||
}
|
||||
else {
|
||||
sat::bool_var v = m_num_vars++;
|
||||
lit = sat::literal(v, false);
|
||||
m_solver_ctx->register_atom(lit.var(), e);
|
||||
}
|
||||
m_expr2lit.insert(e, lit);
|
||||
return neg ? ~lit : lit;
|
||||
}
|
||||
|
||||
sat::literal smt_solver::mk_literal() {
|
||||
sat::bool_var v = m_num_vars++;
|
||||
return sat::literal(v, false);
|
||||
}
|
||||
|
||||
model_ref smt_solver::get_model() {
|
||||
return m_solver_ctx->get_model();
|
||||
|
|
|
@ -29,12 +29,7 @@ namespace sls {
|
|||
solver_ctx* m_solver_ctx = nullptr;
|
||||
expr_ref_vector m_assertions;
|
||||
statistics m_st;
|
||||
obj_map<expr, sat::literal> m_expr2lit;
|
||||
unsigned m_num_vars = 0;
|
||||
|
||||
sat::literal mk_literal(expr* e);
|
||||
sat::literal mk_literal();
|
||||
void add_clause(expr* f);
|
||||
|
||||
public:
|
||||
smt_solver(ast_manager& m, params_ref const& p);
|
||||
~smt_solver();
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue