3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-06-03 21:01:22 +00:00

Merge branch 'unstable' into interp

This commit is contained in:
Ken McMillan 2013-11-05 12:28:13 -08:00
commit a785a5a4b8
33 changed files with 1995 additions and 1628 deletions

View file

@ -31,7 +31,7 @@ Revision History:
#include"ast_smt2_pp.h" #include"ast_smt2_pp.h"
#include"th_rewriter.h" #include"th_rewriter.h"
#include"var_subst.h" #include"var_subst.h"
#include"expr_substitution.h" #include"expr_safe_replace.h"
#include"pp.h" #include"pp.h"
#include"scoped_ctrl_c.h" #include"scoped_ctrl_c.h"
#include"cancel_eh.h" #include"cancel_eh.h"
@ -787,17 +787,12 @@ extern "C" {
RETURN_Z3(of_expr(0)); RETURN_Z3(of_expr(0));
} }
} }
expr_safe_replace subst(m);
expr_substitution subst(m);
for (unsigned i = 0; i < num_exprs; i++) { for (unsigned i = 0; i < num_exprs; i++) {
subst.insert(from[i], to[i]); subst.insert(from[i], to[i]);
} }
th_rewriter m_rw(m);
m_rw.set_substitution(&subst);
expr_ref new_a(m); expr_ref new_a(m);
proof_ref pr(m); subst(a, new_a);
m_rw(a, new_a, pr);
mk_c(c)->save_ast_trail(new_a); mk_c(c)->save_ast_trail(new_a);
r = new_a.get(); r = new_a.get();
RETURN_Z3(of_expr(r)); RETURN_Z3(of_expr(r));

View file

@ -6449,7 +6449,7 @@ class Tactic:
def _to_goal(a): def _to_goal(a):
if isinstance(a, BoolRef): if isinstance(a, BoolRef):
goal = Goal() goal = Goal(ctx = a.ctx)
goal.add(a) goal.add(a)
return goal return goal
else: else:
@ -6932,10 +6932,10 @@ def substitute(t, *m):
>>> x = Int('x') >>> x = Int('x')
>>> y = Int('y') >>> y = Int('y')
>>> substitute(x + 1, (x, y + 1)) >>> substitute(x + 1, (x, y + 1))
2 + y y + 1 + 1
>>> f = Function('f', IntSort(), IntSort()) >>> f = Function('f', IntSort(), IntSort())
>>> substitute(f(x) + f(y), (f(x), IntVal(1)), (f(y), IntVal(1))) >>> substitute(f(x) + f(y), (f(x), IntVal(1)), (f(y), IntVal(1)))
2 1 + 1
""" """
if isinstance(m, tuple): if isinstance(m, tuple):
m1 = _get_args(m) m1 = _get_args(m)

View file

@ -85,6 +85,24 @@ bool float_decl_plugin::is_value(expr * n, mpf & val) {
m_fm.set(val, m_values[to_app(n)->get_decl()->get_parameter(0).get_ext_id()]); m_fm.set(val, m_values[to_app(n)->get_decl()->get_parameter(0).get_ext_id()]);
return true; return true;
} }
else if (is_app_of(n, m_family_id, OP_FLOAT_MINUS_INF)) {
unsigned ebits = to_app(n)->get_decl()->get_range()->get_parameter(0).get_int();
unsigned sbits = to_app(n)->get_decl()->get_range()->get_parameter(1).get_int();
m_fm.mk_ninf(ebits, sbits, val);
return true;
}
else if (is_app_of(n, m_family_id, OP_FLOAT_PLUS_INF)) {
unsigned ebits = to_app(n)->get_decl()->get_range()->get_parameter(0).get_int();
unsigned sbits = to_app(n)->get_decl()->get_range()->get_parameter(1).get_int();
m_fm.mk_pinf(ebits, sbits, val);
return true;
}
else if (is_app_of(n, m_family_id, OP_FLOAT_NAN)) {
unsigned ebits = to_app(n)->get_decl()->get_range()->get_parameter(0).get_int();
unsigned sbits = to_app(n)->get_decl()->get_range()->get_parameter(1).get_int();
m_fm.mk_nan(ebits, sbits, val);
return true;
}
return false; return false;
} }
@ -457,6 +475,7 @@ void float_decl_plugin::get_op_names(svector<builtin_name> & op_names, symbol co
op_names.push_back(builtin_name("plusInfinity", OP_FLOAT_PLUS_INF)); op_names.push_back(builtin_name("plusInfinity", OP_FLOAT_PLUS_INF));
op_names.push_back(builtin_name("minusInfinity", OP_FLOAT_MINUS_INF)); op_names.push_back(builtin_name("minusInfinity", OP_FLOAT_MINUS_INF));
op_names.push_back(builtin_name("NaN", OP_FLOAT_NAN)); op_names.push_back(builtin_name("NaN", OP_FLOAT_NAN));
op_names.push_back(builtin_name("roundNearestTiesToEven", OP_RM_NEAREST_TIES_TO_EVEN)); op_names.push_back(builtin_name("roundNearestTiesToEven", OP_RM_NEAREST_TIES_TO_EVEN));
op_names.push_back(builtin_name("roundNearestTiesToAway", OP_RM_NEAREST_TIES_TO_AWAY)); op_names.push_back(builtin_name("roundNearestTiesToAway", OP_RM_NEAREST_TIES_TO_AWAY));
op_names.push_back(builtin_name("roundTowardPositive", OP_RM_TOWARD_POSITIVE)); op_names.push_back(builtin_name("roundTowardPositive", OP_RM_TOWARD_POSITIVE));
@ -468,7 +487,7 @@ void float_decl_plugin::get_op_names(svector<builtin_name> & op_names, symbol co
op_names.push_back(builtin_name("/", OP_FLOAT_DIV)); op_names.push_back(builtin_name("/", OP_FLOAT_DIV));
op_names.push_back(builtin_name("*", OP_FLOAT_MUL)); op_names.push_back(builtin_name("*", OP_FLOAT_MUL));
op_names.push_back(builtin_name("abs", OP_FLOAT_ABS)); op_names.push_back(builtin_name("abs", OP_FLOAT_ABS));
op_names.push_back(builtin_name("remainder", OP_FLOAT_REM)); op_names.push_back(builtin_name("remainder", OP_FLOAT_REM));
op_names.push_back(builtin_name("fusedMA", OP_FLOAT_FUSED_MA)); op_names.push_back(builtin_name("fusedMA", OP_FLOAT_FUSED_MA));
op_names.push_back(builtin_name("squareRoot", OP_FLOAT_SQRT)); op_names.push_back(builtin_name("squareRoot", OP_FLOAT_SQRT));
@ -497,6 +516,49 @@ void float_decl_plugin::get_op_names(svector<builtin_name> & op_names, symbol co
if (m_bv_plugin) if (m_bv_plugin)
op_names.push_back(builtin_name("asIEEEBV", OP_TO_IEEE_BV)); op_names.push_back(builtin_name("asIEEEBV", OP_TO_IEEE_BV));
// We also support draft version 3
op_names.push_back(builtin_name("fp", OP_TO_FLOAT));
op_names.push_back(builtin_name("RNE", OP_RM_NEAREST_TIES_TO_EVEN));
op_names.push_back(builtin_name("RNA", OP_RM_NEAREST_TIES_TO_AWAY));
op_names.push_back(builtin_name("RTP", OP_RM_TOWARD_POSITIVE));
op_names.push_back(builtin_name("RTN", OP_RM_TOWARD_NEGATIVE));
op_names.push_back(builtin_name("RTZ", OP_RM_TOWARD_ZERO));
op_names.push_back(builtin_name("fp.abs", OP_FLOAT_ABS));
op_names.push_back(builtin_name("fp.neg", OP_FLOAT_UMINUS));
op_names.push_back(builtin_name("fp.add", OP_FLOAT_ADD));
op_names.push_back(builtin_name("fp.sub", OP_FLOAT_SUB));
op_names.push_back(builtin_name("fp.mul", OP_FLOAT_MUL));
op_names.push_back(builtin_name("fp.div", OP_FLOAT_DIV));
op_names.push_back(builtin_name("fp.fma", OP_FLOAT_FUSED_MA));
op_names.push_back(builtin_name("fp.sqrt", OP_FLOAT_SQRT));
op_names.push_back(builtin_name("fp.rem", OP_FLOAT_REM));
op_names.push_back(builtin_name("fp.eq", OP_FLOAT_EQ));
op_names.push_back(builtin_name("fp.leq", OP_FLOAT_LE));
op_names.push_back(builtin_name("fp.lt", OP_FLOAT_LT));
op_names.push_back(builtin_name("fp.geq", OP_FLOAT_GE));
op_names.push_back(builtin_name("fp.gt", OP_FLOAT_GT));
op_names.push_back(builtin_name("fp.isNormal", OP_FLOAT_IS_NORMAL));
op_names.push_back(builtin_name("fp.isSubnormal", OP_FLOAT_IS_SUBNORMAL));
op_names.push_back(builtin_name("fp.isZero", OP_FLOAT_IS_ZERO));
op_names.push_back(builtin_name("fp.isInfinite", OP_FLOAT_IS_INF));
op_names.push_back(builtin_name("fp.isNaN", OP_FLOAT_IS_NAN));
op_names.push_back(builtin_name("fp.min", OP_FLOAT_MIN));
op_names.push_back(builtin_name("fp.max", OP_FLOAT_MAX));
op_names.push_back(builtin_name("fp.convert", OP_TO_FLOAT));
if (m_bv_plugin) {
// op_names.push_back(builtin_name("fp.fromBv", OP_TO_FLOAT));
// op_names.push_back(builtin_name("fp.fromUBv", OP_TO_FLOAT));
// op_names.push_back(builtin_name("fp.fromSBv", OP_TO_FLOAT));
// op_names.push_back(builtin_name("fp.toUBv", OP_TO_IEEE_BV));
// op_names.push_back(builtin_name("fp.toSBv", OP_TO_IEEE_BV));
}
op_names.push_back(builtin_name("fp.fromReal", OP_TO_FLOAT));
// op_names.push_back(builtin_name("fp.toReal", ?));
} }
void float_decl_plugin::get_sort_names(svector<builtin_name> & sort_names, symbol const & logic) { void float_decl_plugin::get_sort_names(svector<builtin_name> & sort_names, symbol const & logic) {
@ -523,6 +585,9 @@ bool float_decl_plugin::is_value(app * e) const {
case OP_RM_TOWARD_NEGATIVE: case OP_RM_TOWARD_NEGATIVE:
case OP_RM_TOWARD_ZERO: case OP_RM_TOWARD_ZERO:
case OP_FLOAT_VALUE: case OP_FLOAT_VALUE:
case OP_FLOAT_PLUS_INF:
case OP_FLOAT_MINUS_INF:
case OP_FLOAT_NAN:
return true; return true;
case OP_TO_FLOAT: case OP_TO_FLOAT:
return m_manager->is_value(e->get_arg(0)); return m_manager->is_value(e->get_arg(0));

View file

@ -354,7 +354,7 @@ br_status float_rewriter::mk_lt(expr * arg1, expr * arg2, expr_ref & result) {
if (m_util.is_minus_inf(arg1)) { if (m_util.is_minus_inf(arg1)) {
// -oo < arg2 --> not(arg2 = -oo) and not(arg2 = NaN) // -oo < arg2 --> not(arg2 = -oo) and not(arg2 = NaN)
result = m().mk_and(m().mk_not(m().mk_eq(arg2, arg1)), mk_neq_nan(arg2)); result = m().mk_and(m().mk_not(m().mk_eq(arg2, arg1)), mk_neq_nan(arg2));
return BR_REWRITE2; return BR_REWRITE3;
} }
if (m_util.is_minus_inf(arg2)) { if (m_util.is_minus_inf(arg2)) {
// arg1 < -oo --> false // arg1 < -oo --> false
@ -369,7 +369,7 @@ br_status float_rewriter::mk_lt(expr * arg1, expr * arg2, expr_ref & result) {
if (m_util.is_plus_inf(arg2)) { if (m_util.is_plus_inf(arg2)) {
// arg1 < +oo --> not(arg1 = +oo) and not(arg1 = NaN) // arg1 < +oo --> not(arg1 = +oo) and not(arg1 = NaN)
result = m().mk_and(m().mk_not(m().mk_eq(arg1, arg2)), mk_neq_nan(arg1)); result = m().mk_and(m().mk_not(m().mk_eq(arg1, arg2)), mk_neq_nan(arg1));
return BR_REWRITE2; return BR_REWRITE3;
} }
scoped_mpf v1(m_util.fm()), v2(m_util.fm()); scoped_mpf v1(m_util.fm()), v2(m_util.fm());
@ -490,7 +490,11 @@ br_status float_rewriter::mk_is_sign_minus(expr * arg1, expr_ref & result) {
br_status float_rewriter::mk_eq_core(expr * arg1, expr * arg2, expr_ref & result) { br_status float_rewriter::mk_eq_core(expr * arg1, expr * arg2, expr_ref & result) {
scoped_mpf v1(m_util.fm()), v2(m_util.fm()); scoped_mpf v1(m_util.fm()), v2(m_util.fm());
if (m_util.is_value(arg1, v1) && m_util.is_value(arg2, v2)) { if (m_util.is_value(arg1, v1) && m_util.is_value(arg2, v2)) {
result = (v1 == v2) ? m().mk_true() : m().mk_false(); // Note: == is the floats-equality, here we need normal equality.
result = (m_fm.is_nan(v1) && m_fm.is_nan(v2)) ? m().mk_true() :
(m_fm.is_zero(v1) && m_fm.is_zero(v2) && m_fm.sgn(v1)!=m_fm.sgn(v2)) ? m().mk_false() :
(v1 == v2) ? m().mk_true() :
m().mk_false();
return BR_DONE; return BR_DONE;
} }

View file

@ -581,7 +581,7 @@ namespace datalog {
void context::check_uninterpreted_free(rule_ref& r) { void context::check_uninterpreted_free(rule_ref& r) {
func_decl* f = 0; func_decl* f = 0;
if (r->has_uninterpreted_non_predicates(f)) { if (r->has_uninterpreted_non_predicates(m, f)) {
std::stringstream stm; std::stringstream stm;
stm << "Uninterpreted '" stm << "Uninterpreted '"
<< f->get_name() << f->get_name()

View file

@ -43,6 +43,7 @@ Revision History:
#include"expr_safe_replace.h" #include"expr_safe_replace.h"
#include"filter_model_converter.h" #include"filter_model_converter.h"
#include"scoped_proof.h" #include"scoped_proof.h"
#include"datatype_decl_plugin.h"
namespace datalog { namespace datalog {
@ -881,9 +882,12 @@ namespace datalog {
} }
struct uninterpreted_function_finder_proc { struct uninterpreted_function_finder_proc {
ast_manager& m;
datatype_util m_dt;
bool m_found; bool m_found;
func_decl* m_func; func_decl* m_func;
uninterpreted_function_finder_proc() : m_found(false), m_func(0) {} uninterpreted_function_finder_proc(ast_manager& m):
m(m), m_dt(m), m_found(false), m_func(0) {}
void operator()(var * n) { } void operator()(var * n) { }
void operator()(quantifier * n) { } void operator()(quantifier * n) { }
void operator()(app * n) { void operator()(app * n) {
@ -891,6 +895,14 @@ namespace datalog {
m_found = true; m_found = true;
m_func = n->get_decl(); m_func = n->get_decl();
} }
else if (m_dt.is_accessor(n)) {
sort* s = m.get_sort(n->get_arg(0));
SASSERT(m_dt.is_datatype(s));
if (m_dt.get_datatype_constructors(s)->size() > 1) {
m_found = true;
m_func = n->get_decl();
}
}
} }
bool found(func_decl*& f) const { f = m_func; return m_found; } bool found(func_decl*& f) const { f = m_func; return m_found; }
@ -900,9 +912,9 @@ namespace datalog {
// non-predicates may appear only in the interpreted tail, it is therefore // non-predicates may appear only in the interpreted tail, it is therefore
// sufficient only to check the tail. // sufficient only to check the tail.
// //
bool rule::has_uninterpreted_non_predicates(func_decl*& f) const { bool rule::has_uninterpreted_non_predicates(ast_manager& m, func_decl*& f) const {
unsigned sz = get_tail_size(); unsigned sz = get_tail_size();
uninterpreted_function_finder_proc proc; uninterpreted_function_finder_proc proc(m);
expr_mark visited; expr_mark visited;
for (unsigned i = get_uninterpreted_tail_size(); i < sz && !proc.found(f); ++i) { for (unsigned i = get_uninterpreted_tail_size(); i < sz && !proc.found(f); ++i) {
for_each_expr(proc, visited, get_tail(i)); for_each_expr(proc, visited, get_tail(i));
@ -910,6 +922,7 @@ namespace datalog {
return proc.found(f); return proc.found(f);
} }
struct quantifier_finder_proc { struct quantifier_finder_proc {
bool m_exist; bool m_exist;
bool m_univ; bool m_univ;

View file

@ -293,7 +293,7 @@ namespace datalog {
*/ */
bool is_in_tail(const func_decl * p, bool only_positive=false) const; bool is_in_tail(const func_decl * p, bool only_positive=false) const;
bool has_uninterpreted_non_predicates(func_decl*& f) const; bool has_uninterpreted_non_predicates(ast_manager& m, func_decl*& f) const;
void has_quantifiers(bool& existential, bool& universal) const; void has_quantifiers(bool& existential, bool& universal) const;
bool has_quantifiers() const; bool has_quantifiers() const;
bool has_negation() const; bool has_negation() const;

View file

@ -1448,6 +1448,10 @@ namespace datalog {
transformer.register_plugin(slice); transformer.register_plugin(slice);
m_ctx.transform_rules(transformer); m_ctx.transform_rules(transformer);
} }
if (m_ctx.get_rules().get_output_predicates().empty()) {
return l_false;
}
m_query_pred = m_ctx.get_rules().get_output_predicate(); m_query_pred = m_ctx.get_rules().get_output_predicate();
m_rules.replace_rules(m_ctx.get_rules()); m_rules.replace_rules(m_ctx.get_rules());
m_rules.close(); m_rules.close();

View file

@ -70,6 +70,9 @@ namespace datalog {
m_goals.reset(); m_goals.reset();
rm.mk_query(query, m_ctx.get_rules()); rm.mk_query(query, m_ctx.get_rules());
apply_default_transformation(m_ctx); apply_default_transformation(m_ctx);
if (m_ctx.get_rules().get_output_predicates().empty()) {
return l_false;
}
func_decl* head_decl = m_ctx.get_rules().get_output_predicate(); func_decl* head_decl = m_ctx.get_rules().get_output_predicate();
rule_set& rules = m_ctx.get_rules(); rule_set& rules = m_ctx.get_rules();
rule_vector const& rv = rules.get_predicate_rules(head_decl); rule_vector const& rv = rules.get_predicate_rules(head_decl);

View file

@ -1123,9 +1123,7 @@ namespace pdr {
n->mk_instantiate(r0, r1, binding); n->mk_instantiate(r0, r1, binding);
proof_ref p1(m), p2(m); proof_ref p1(m), p2(m);
p1 = r0->get_proof(); p1 = r0->get_proof();
if (!p1) { IF_VERBOSE(0, if (!p1) r0->display(dctx, verbose_stream()););
r0->display(dctx, std::cout);
}
SASSERT(p1); SASSERT(p1);
pfs[0] = p1; pfs[0] = p1;
rls[0] = r1; rls[0] = r1;

View file

@ -112,8 +112,8 @@ namespace pdr {
set_value(e, val); set_value(e, val);
} }
else { else {
IF_VERBOSE(3, verbose_stream() << "Not evaluated " << mk_pp(e, m) << "\n";); IF_VERBOSE(3, verbose_stream() << "Not evaluated " << mk_pp(e, m) << " := " << mk_pp(val, m) << "\n";);
TRACE("pdr", tout << "Variable is not tracked: " << mk_pp(e, m) << "\n";); TRACE("pdr", tout << "Variable is not tracked: " << mk_pp(e, m) << " := " << mk_pp(val, m) << "\n";);
set_x(e); set_x(e);
} }
} }
@ -672,7 +672,19 @@ namespace pdr {
eval_array_eq(e, arg1, arg2); eval_array_eq(e, arg1, arg2);
} }
else if (is_x(arg1) || is_x(arg2)) { else if (is_x(arg1) || is_x(arg2)) {
set_x(e); expr_ref eq(m), vl(m);
eq = m.mk_eq(arg1, arg2);
m_model->eval(eq, vl);
if (m.is_true(vl)) {
set_bool(e, true);
}
else if (m.is_false(vl)) {
set_bool(e, false);
}
else {
TRACE("pdr", tout << "cannot evaluate: " << mk_pp(vl, m) << "\n";);
set_x(e);
}
} }
else if (m.is_bool(arg1)) { else if (m.is_bool(arg1)) {
bool val = is_true(arg1) == is_true(arg2); bool val = is_true(arg1) == is_true(arg2);

View file

@ -47,9 +47,9 @@ namespace datalog {
being notified about it, it will surely see the decrease from length 3 to 2 which being notified about it, it will surely see the decrease from length 3 to 2 which
the threshold for rule being counted in this counter. the threshold for rule being counted in this counter.
*/ */
unsigned m_consumers; unsigned m_consumers;
bool m_stratified; bool m_stratified;
unsigned m_src_stratum; unsigned m_src_stratum;
public: public:
var_idx_set m_all_nonlocal_vars; var_idx_set m_all_nonlocal_vars;
rule_vector m_rules; rule_vector m_rules;
@ -57,16 +57,13 @@ namespace datalog {
pair_info() : m_consumers(0), m_stratified(true), m_src_stratum(0) {} pair_info() : m_consumers(0), m_stratified(true), m_src_stratum(0) {}
bool can_be_joined() const { bool can_be_joined() const {
return m_consumers>0; return m_consumers > 0;
} }
cost get_cost() const { cost get_cost() const {
/*if(m_instantiated) { SASSERT(m_consumers > 0);
return std::numeric_limits<cost>::min();
}*/
SASSERT(m_consumers>0);
cost amortized = m_total_cost/m_consumers; cost amortized = m_total_cost/m_consumers;
if(m_stratified) { if (m_stratified) {
return amortized * ( (amortized>0) ? (1/16.0f) : 16.0f); return amortized * ( (amortized>0) ? (1/16.0f) : 16.0f);
} }
else { else {
@ -81,19 +78,20 @@ namespace datalog {
by the time of a call to this function by the time of a call to this function
*/ */
void add_rule(join_planner & pl, app * t1, app * t2, rule * r, void add_rule(join_planner & pl, app * t1, app * t2, rule * r,
const var_idx_set & non_local_vars_normalized) { const var_idx_set & non_local_vars_normalized,
if(m_rules.empty()) { const var_idx_set & non_local_vars) {
m_total_cost = pl.compute_cost(t1, t2); if (m_rules.empty()) {
m_total_cost = pl.compute_cost(t1, t2, non_local_vars);
m_src_stratum = std::max(pl.get_stratum(t1->get_decl()), pl.get_stratum(t2->get_decl())); m_src_stratum = std::max(pl.get_stratum(t1->get_decl()), pl.get_stratum(t2->get_decl()));
} }
m_rules.push_back(r); m_rules.push_back(r);
if(pl.m_rules_content.find_core(r)->get_data().m_value.size()>2) { if (pl.m_rules_content.find(r).size()>2) {
m_consumers++; m_consumers++;
} }
if(m_stratified) { if (m_stratified) {
unsigned head_stratum = pl.get_stratum(r->get_decl()); unsigned head_stratum = pl.get_stratum(r->get_decl());
SASSERT(head_stratum>=m_src_stratum); SASSERT(head_stratum>=m_src_stratum);
if(head_stratum==m_src_stratum) { if (head_stratum==m_src_stratum) {
m_stratified = false; m_stratified = false;
} }
} }
@ -105,7 +103,7 @@ namespace datalog {
*/ */
bool remove_rule(rule * r, unsigned original_length) { bool remove_rule(rule * r, unsigned original_length) {
TRUSTME( remove_from_vector(m_rules, r) ); TRUSTME( remove_from_vector(m_rules, r) );
if(original_length>2) { if (original_length>2) {
SASSERT(m_consumers>0); SASSERT(m_consumers>0);
m_consumers--; m_consumers--;
} }
@ -165,7 +163,7 @@ namespace datalog {
SASSERT(is_var(t->get_arg(i))); SASSERT(is_var(t->get_arg(i)));
var * v = to_var(t->get_arg(i)); var * v = to_var(t->get_arg(i));
unsigned var_idx = v->get_idx(); unsigned var_idx = v->get_idx();
if(result[res_ofs-var_idx]==0) { if (result[res_ofs-var_idx]==0) {
result[res_ofs-var_idx]=m.mk_var(next_var, v->get_sort()); result[res_ofs-var_idx]=m.mk_var(next_var, v->get_sort());
next_var++; next_var++;
} }
@ -174,7 +172,7 @@ namespace datalog {
void get_normalizer(app * t1, app * t2, expr_ref_vector & result) const { void get_normalizer(app * t1, app * t2, expr_ref_vector & result) const {
SASSERT(result.empty()); SASSERT(result.empty());
if(t1->get_num_args()==0 && t2->get_num_args()==0) { if (t1->get_num_args()==0 && t2->get_num_args()==0) {
return; //nothing to normalize return; //nothing to normalize
} }
SASSERT(!t1->is_ground() || !t2->is_ground()); SASSERT(!t1->is_ground() || !t2->is_ground());
@ -186,14 +184,14 @@ namespace datalog {
var_idx_set::iterator ovend = orig_var_set.end(); var_idx_set::iterator ovend = orig_var_set.end();
for(; ovit!=ovend; ++ovit) { for(; ovit!=ovend; ++ovit) {
unsigned var_idx = *ovit; unsigned var_idx = *ovit;
if(var_idx>max_var_idx) { if (var_idx>max_var_idx) {
max_var_idx = var_idx; max_var_idx = var_idx;
} }
} }
} }
if(t1->get_decl()!=t2->get_decl()) { if (t1->get_decl()!=t2->get_decl()) {
if(t1->get_decl()->get_id()<t2->get_decl()->get_id()) { if (t1->get_decl()->get_id()<t2->get_decl()->get_id()) {
std::swap(t1, t2); std::swap(t1, t2);
} }
} }
@ -207,9 +205,9 @@ namespace datalog {
//so the only literals which appear in pairs are the ones that contain only variables. //so the only literals which appear in pairs are the ones that contain only variables.
var * v1 = to_var(t1->get_arg(i)); var * v1 = to_var(t1->get_arg(i));
var * v2 = to_var(t2->get_arg(i)); var * v2 = to_var(t2->get_arg(i));
if(v1->get_sort()!=v2->get_sort()) { if (v1->get_sort()!=v2->get_sort()) {
//different sorts mean we can distinguish the two terms //different sorts mean we can distinguish the two terms
if(v1->get_sort()->get_id()<v2->get_sort()->get_id()) { if (v1->get_sort()->get_id()<v2->get_sort()->get_id()) {
std::swap(t1, t2); std::swap(t1, t2);
} }
break; break;
@ -221,9 +219,9 @@ namespace datalog {
SASSERT(norm1[v1_idx]==-1); SASSERT(norm1[v1_idx]==-1);
SASSERT(norm2[v2_idx]==-1); SASSERT(norm2[v2_idx]==-1);
if(norm2[v1_idx]!=norm1[v2_idx]) { if (norm2[v1_idx]!=norm1[v2_idx]) {
//now we can distinguish the two terms //now we can distinguish the two terms
if(norm2[v1_idx]<norm1[v2_idx]) { if (norm2[v1_idx]<norm1[v2_idx]) {
std::swap(t1, t2); std::swap(t1, t2);
} }
break; break;
@ -250,7 +248,7 @@ namespace datalog {
m_var_subst(t2, norm_subst.size(), norm_subst.c_ptr(), t2n_ref); m_var_subst(t2, norm_subst.size(), norm_subst.c_ptr(), t2n_ref);
app * t1n = to_app(t1n_ref); app * t1n = to_app(t1n_ref);
app * t2n = to_app(t2n_ref); app * t2n = to_app(t2n_ref);
if(t1n>t2n) { if (t1n>t2n) {
std::swap(t1n, t2n); std::swap(t1n, t2n);
} }
m_pinned.push_back(t1n); m_pinned.push_back(t1n);
@ -274,12 +272,10 @@ namespace datalog {
by the time of a call to this function by the time of a call to this function
*/ */
void register_pair(app * t1, app * t2, rule * r, const var_idx_set & non_local_vars) { void register_pair(app * t1, app * t2, rule * r, const var_idx_set & non_local_vars) {
TRACE("dl", tout << mk_pp(t1, m) << " " << mk_pp(t2, m) << "\n";
r->display(m_context, tout); tout << "\n";);
SASSERT(t1!=t2); SASSERT(t1!=t2);
cost_map::entry * e = m_costs.insert_if_not_there2(get_key(t1, t2), 0); cost_map::entry * e = m_costs.insert_if_not_there2(get_key(t1, t2), 0);
pair_info * & ptr_inf = e->get_data().m_value; pair_info * & ptr_inf = e->get_data().m_value;
if(ptr_inf==0) { if (ptr_inf==0) {
ptr_inf = alloc(pair_info); ptr_inf = alloc(pair_info);
} }
pair_info & inf = *ptr_inf; pair_info & inf = *ptr_inf;
@ -288,25 +284,30 @@ namespace datalog {
get_normalizer(t1, t2, normalizer); get_normalizer(t1, t2, normalizer);
unsigned norm_ofs = normalizer.size()-1; unsigned norm_ofs = normalizer.size()-1;
var_idx_set normalized_vars; var_idx_set normalized_vars;
var_idx_set::iterator vit = non_local_vars.begin(); var_idx_set::iterator vit = non_local_vars.begin();
var_idx_set::iterator vend = non_local_vars.end(); var_idx_set::iterator vend = non_local_vars.end();
for(; vit!=vend; ++vit) { for(; vit!=vend; ++vit) {
unsigned norm_var = to_var(normalizer.get(norm_ofs-*vit))->get_idx(); unsigned norm_var = to_var(normalizer.get(norm_ofs-*vit))->get_idx();
normalized_vars.insert(norm_var); normalized_vars.insert(norm_var);
} }
inf.add_rule(*this, t1, t2, r, normalized_vars); inf.add_rule(*this, t1, t2, r, normalized_vars, non_local_vars);
TRACE("dl", tout << mk_pp(t1, m) << " " << mk_pp(t2, m) << " ";
vit = non_local_vars.begin();
for (; vit != vend; ++vit) tout << *vit << " ";
tout << "\n";
r->display(m_context, tout);
if (inf.can_be_joined()) tout << "cost: " << inf.get_cost() << "\n";);
} }
pair_info & get_pair(app_pair key) const { pair_info & get_pair(app_pair key) const {
cost_map::entry * e = m_costs.find_core(key); return *m_costs.find(key);
SASSERT(e);
return *e->get_data().m_value;
} }
void remove_rule_from_pair(app_pair key, rule * r, unsigned original_len) { void remove_rule_from_pair(app_pair key, rule * r, unsigned original_len) {
pair_info * ptr = &get_pair(key); pair_info * ptr = &get_pair(key);
if(ptr->remove_rule(r, original_len)) { if (ptr->remove_rule(r, original_len)) {
SASSERT(ptr->m_rules.empty()); SASSERT(ptr->m_rules.empty());
m_costs.remove(key); m_costs.remove(key);
dealloc(ptr); dealloc(ptr);
@ -349,7 +350,7 @@ namespace datalog {
unsigned n=t->get_num_args(); unsigned n=t->get_num_args();
for(unsigned i=0; i<n; i++) { for(unsigned i=0; i<n; i++) {
var * v=to_var(t->get_arg(i)); var * v=to_var(t->get_arg(i));
if(v->get_idx()==var_idx) { if (v->get_idx()==var_idx) {
args.push_back(v); args.push_back(v);
domain.push_back(m.get_sort(v)); domain.push_back(m.get_sort(v));
return true; return true;
@ -375,7 +376,7 @@ namespace datalog {
unsigned var_idx=*ovit; unsigned var_idx=*ovit;
bool found=extract_argument_info(var_idx, t1, args, domain); bool found=extract_argument_info(var_idx, t1, args, domain);
if(!found) { if (!found) {
found=extract_argument_info(var_idx, t2, args, domain); found=extract_argument_info(var_idx, t2, args, domain);
} }
SASSERT(found); SASSERT(found);
@ -389,7 +390,7 @@ namespace datalog {
func_decl* parent_head = one_parent->get_decl(); func_decl* parent_head = one_parent->get_decl();
const char * one_parent_name = parent_head->get_name().bare_str(); const char * one_parent_name = parent_head->get_name().bare_str();
std::string parent_name; std::string parent_name;
if(inf.m_rules.size()>1) { if (inf.m_rules.size()>1) {
parent_name = one_parent_name + std::string("_and_") + to_string(inf.m_rules.size()-1); parent_name = one_parent_name + std::string("_and_") + to_string(inf.m_rules.size()-1);
} }
else { else {
@ -443,7 +444,7 @@ namespace datalog {
} }
//remove edges between surviving tails and removed tails //remove edges between surviving tails and removed tails
for(unsigned i=0; i<len; i++) { for(unsigned i=0; i<len; i++) {
if(added_tails.contains(rule_content[i])) { if (added_tails.contains(rule_content[i])) {
continue; continue;
} }
for(unsigned ri=0; ri<rt_sz; ri++) { for(unsigned ri=0; ri<rt_sz; ri++) {
@ -452,7 +453,7 @@ namespace datalog {
} }
} }
if(len==1) { if (len==1) {
return; return;
} }
@ -480,7 +481,7 @@ namespace datalog {
for(unsigned i=0; i<len; i++) { for(unsigned i=0; i<len; i++) {
app * o_tail = rule_content[i]; //other tail app * o_tail = rule_content[i]; //other tail
if(added_tails.contains(o_tail)) { if (added_tails.contains(o_tail)) {
//this avoids adding edges between new tails twice //this avoids adding edges between new tails twice
continue; continue;
} }
@ -503,9 +504,9 @@ namespace datalog {
void apply_binary_rule(rule * r, app_pair pair_key, app * t_new) { void apply_binary_rule(rule * r, app_pair pair_key, app * t_new) {
app * t1 = pair_key.first; app * t1 = pair_key.first;
app * t2 = pair_key.second; app * t2 = pair_key.second;
ptr_vector<app> & rule_content = m_rules_content.find_core(r)->get_data().m_value; ptr_vector<app> & rule_content = m_rules_content.find(r);
unsigned len = rule_content.size(); unsigned len = rule_content.size();
if(len==1) { if (len==1) {
return; return;
} }
@ -515,16 +516,16 @@ namespace datalog {
ptr_vector<app> added_tails; ptr_vector<app> added_tails;
for(unsigned i1=0; i1<len; i1++) { for(unsigned i1=0; i1<len; i1++) {
app * rt1 = rule_content[i1]; app * rt1 = rule_content[i1];
if(rt1->get_decl()!=t1_pred) { if (rt1->get_decl()!=t1_pred) {
continue; continue;
} }
unsigned i2start = (t1_pred==t2_pred) ? (i1+1) : 0; unsigned i2start = (t1_pred==t2_pred) ? (i1+1) : 0;
for(unsigned i2=i2start; i2<len; i2++) { for(unsigned i2=i2start; i2<len; i2++) {
app * rt2 = rule_content[i2]; app * rt2 = rule_content[i2];
if(i1==i2 || rt2->get_decl()!=t2_pred) { if (i1==i2 || rt2->get_decl()!=t2_pred) {
continue; continue;
} }
if(get_key(rt1, rt2)!=pair_key) { if (get_key(rt1, rt2)!=pair_key) {
continue; continue;
} }
expr_ref_vector normalizer(m); expr_ref_vector normalizer(m);
@ -558,7 +559,7 @@ namespace datalog {
relation_sort sort = pred->get_domain(arg_index); relation_sort sort = pred->get_domain(arg_index);
return static_cast<cost>(m_context.get_sort_size_estimate(sort)); return static_cast<cost>(m_context.get_sort_size_estimate(sort));
//unsigned sz; //unsigned sz;
//if(!m_context.get_sort_size(sort, sz)) { //if (!m_context.get_sort_size(sort, sz)) {
// sz=UINT_MAX; // sz=UINT_MAX;
//} //}
//return static_cast<cost>(sz); //return static_cast<cost>(sz);
@ -576,15 +577,15 @@ namespace datalog {
return cost(1); return cost(1);
} }
relation_manager& rm = rel->get_rmanager(); relation_manager& rm = rel->get_rmanager();
if( (m_context.saturation_was_run() && rm.try_get_relation(pred)) if ( (m_context.saturation_was_run() && rm.try_get_relation(pred))
|| rm.is_saturated(pred)) { || rm.is_saturated(pred)) {
SASSERT(rm.try_get_relation(pred)); //if it is saturated, it should exist SASSERT(rm.try_get_relation(pred)); //if it is saturated, it should exist
unsigned rel_size_int = rel->get_relation(pred).get_size_estimate_rows(); unsigned rel_size_int = rel->get_relation(pred).get_size_estimate_rows();
if(rel_size_int!=0) { if (rel_size_int!=0) {
cost rel_size = static_cast<cost>(rel_size_int); cost rel_size = static_cast<cost>(rel_size_int);
cost curr_size = rel_size; cost curr_size = rel_size;
for(unsigned i=0; i<n; i++) { for(unsigned i=0; i<n; i++) {
if(!is_var(t->get_arg(i))) { if (!is_var(t->get_arg(i))) {
curr_size /= get_domain_size(pred, i); curr_size /= get_domain_size(pred, i);
} }
} }
@ -593,40 +594,58 @@ namespace datalog {
} }
cost res = 1; cost res = 1;
for(unsigned i=0; i<n; i++) { for(unsigned i=0; i<n; i++) {
if(is_var(t->get_arg(i))) { if (is_var(t->get_arg(i))) {
res *= get_domain_size(pred, i); res *= get_domain_size(pred, i);
} }
} }
return res; return res;
} }
cost compute_cost(app * t1, app * t2) const { cost compute_cost(app * t1, app * t2, const var_idx_set & non_local_vars) const {
func_decl * t1_pred = t1->get_decl(); func_decl * t1_pred = t1->get_decl();
func_decl * t2_pred = t2->get_decl(); func_decl * t2_pred = t2->get_decl();
cost inters_size = 1; cost inters_size = 1;
variable_intersection vi(m_context.get_manager()); variable_intersection vi(m_context.get_manager());
vi.populate(t1, t2); vi.populate(t1, t2);
unsigned n = vi.size(); unsigned n = vi.size();
// remove contributions from joined columns.
for(unsigned i=0; i<n; i++) { for(unsigned i=0; i<n; i++) {
unsigned arg_index1, arg_index2; unsigned arg_index1, arg_index2;
vi.get(i, arg_index1, arg_index2); vi.get(i, arg_index1, arg_index2);
inters_size *= get_domain_size(t1_pred, arg_index1); SASSERT(is_var(t1->get_arg(arg_index1)));
if (non_local_vars.contains(to_var(t1->get_arg(arg_index1))->get_idx())) {
inters_size *= get_domain_size(t1_pred, arg_index1);
}
//joined arguments must have the same domain //joined arguments must have the same domain
SASSERT(get_domain_size(t1_pred, arg_index1)==get_domain_size(t2_pred, arg_index2)); SASSERT(get_domain_size(t1_pred, arg_index1)==get_domain_size(t2_pred, arg_index2));
} }
cost res = estimate_size(t1)*estimate_size(t2)/(inters_size*inters_size); // remove contributions from projected columns.
for (unsigned i = 0; i < t1->get_num_args(); ++i) {
if (is_var(t1->get_arg(i)) &&
!non_local_vars.contains(to_var(t1->get_arg(i))->get_idx())) {
inters_size *= get_domain_size(t1_pred, i);
}
}
for (unsigned i = 0; i < t2->get_num_args(); ++i) {
if (is_var(t2->get_arg(i)) &&
!non_local_vars.contains(to_var(t2->get_arg(i))->get_idx())) {
inters_size *= get_domain_size(t2_pred, i);
}
}
cost res = estimate_size(t1)*estimate_size(t2)/ inters_size; // (inters_size*inters_size);
//cost res = -inters_size; //cost res = -inters_size;
/*unsigned t1_strat = get_stratum(t1_pred); /*unsigned t1_strat = get_stratum(t1_pred);
SASSERT(t1_strat<=m_head_stratum); SASSERT(t1_strat<=m_head_stratum);
if(t1_strat<m_head_stratum) { if (t1_strat<m_head_stratum) {
unsigned t2_strat = get_stratum(t2_pred); unsigned t2_strat = get_stratum(t2_pred);
SASSERT(t2_strat<=m_head_stratum); SASSERT(t2_strat<=m_head_stratum);
if(t2_strat<m_head_stratum) { if (t2_strat<m_head_stratum) {
//the rule of this predicates would depend on predicates //the rule of this predicates would depend on predicates
//in lower stratum than the head, which is a good thing, since //in lower stratum than the head, which is a good thing, since
//then the rule code will not need to appear in a loop //then the rule code will not need to appear in a loop
if(res>0) { if (res>0) {
res /= 2; res /= 2;
} }
else { else {
@ -653,17 +672,17 @@ namespace datalog {
for(; it!=end; ++it) { for(; it!=end; ++it) {
app_pair key = it->m_key; app_pair key = it->m_key;
pair_info & inf = *it->m_value; pair_info & inf = *it->m_value;
if(!inf.can_be_joined()) { if (!inf.can_be_joined()) {
continue; continue;
} }
cost c = inf.get_cost(); cost c = inf.get_cost();
if(!found || c<best_cost) { if (!found || c<best_cost) {
found = true; found = true;
best_cost = c; best_cost = c;
best = key; best = key;
} }
} }
if(!found) { if (!found) {
return false; return false;
} }
p=best; p=best;
@ -684,7 +703,7 @@ namespace datalog {
join_pair(selected); join_pair(selected);
} }
if(m_modified_rules.empty()) { if (m_modified_rules.empty()) {
return 0; return 0;
} }
rule_set * result = alloc(rule_set, m_context); rule_set * result = alloc(rule_set, m_context);
@ -694,7 +713,7 @@ namespace datalog {
rule * orig_r = rcit->m_key; rule * orig_r = rcit->m_key;
ptr_vector<app> content = rcit->m_value; ptr_vector<app> content = rcit->m_value;
SASSERT(content.size()<=2); SASSERT(content.size()<=2);
if(content.size()==orig_r->get_positive_tail_size()) { if (content.size()==orig_r->get_positive_tail_size()) {
//rule did not change //rule did not change
result->add_rule(orig_r); result->add_rule(orig_r);
continue; continue;
@ -728,7 +747,7 @@ namespace datalog {
rule_set * mk_simple_joins::operator()(rule_set const & source) { rule_set * mk_simple_joins::operator()(rule_set const & source) {
rule_set rs_aux_copy(m_context); rule_set rs_aux_copy(m_context);
rs_aux_copy.replace_rules(source); rs_aux_copy.replace_rules(source);
if(!rs_aux_copy.is_closed()) { if (!rs_aux_copy.is_closed()) {
rs_aux_copy.close(); rs_aux_copy.close();
} }

View file

@ -19,6 +19,7 @@ Revision History:
#include "dl_mk_array_blast.h" #include "dl_mk_array_blast.h"
#include "qe_util.h" #include "qe_util.h"
#include "scoped_proof.h"
namespace datalog { namespace datalog {
@ -31,7 +32,6 @@ namespace datalog {
rm(ctx.get_rule_manager()), rm(ctx.get_rule_manager()),
m_rewriter(m, m_params), m_rewriter(m, m_params),
m_simplifier(ctx), m_simplifier(ctx),
m_sub(m),
m_next_var(0) { m_next_var(0) {
m_params.set_bool("expand_select_store",true); m_params.set_bool("expand_select_store",true);
m_rewriter.updt_params(m_params); m_rewriter.updt_params(m_params);
@ -82,7 +82,6 @@ namespace datalog {
return false; return false;
} }
if (v) { if (v) {
m_sub.insert(e, v);
m_defs.insert(e, to_var(v)); m_defs.insert(e, to_var(v));
} }
else { else {
@ -92,71 +91,113 @@ namespace datalog {
m_next_var = vars.size() + 1; m_next_var = vars.size() + 1;
} }
v = m.mk_var(m_next_var, m.get_sort(e)); v = m.mk_var(m_next_var, m.get_sort(e));
m_sub.insert(e, v);
m_defs.insert(e, v); m_defs.insert(e, v);
++m_next_var; ++m_next_var;
} }
return true; return true;
} }
bool mk_array_blast::is_select_eq_var(expr* e, app*& s, var*& v) const {
expr* x, *y;
if (m.is_eq(e, x, y) || m.is_iff(e, x, y)) {
if (a.is_select(y)) {
std::swap(x,y);
}
if (a.is_select(x) && is_var(y)) {
s = to_app(x);
v = to_var(y);
return true;
}
}
return false;
}
bool mk_array_blast::ackermanize(rule const& r, expr_ref& body, expr_ref& head) { bool mk_array_blast::ackermanize(rule const& r, expr_ref& body, expr_ref& head) {
expr_ref_vector conjs(m); expr_ref_vector conjs(m), trail(m);
qe::flatten_and(body, conjs); qe::flatten_and(body, conjs);
m_defs.reset(); m_defs.reset();
m_sub.reset();
m_next_var = 0; m_next_var = 0;
ptr_vector<expr> todo; ptr_vector<expr> todo;
todo.push_back(head); obj_map<expr, expr*> cache;
ptr_vector<expr> args;
app_ref e1(m);
app* s;
var* v;
for (unsigned i = 0; i < conjs.size(); ++i) { for (unsigned i = 0; i < conjs.size(); ++i) {
expr* e = conjs[i].get(); expr* e = conjs[i].get();
expr* x, *y; if (is_select_eq_var(e, s, v)) {
if (m.is_eq(e, x, y) || m.is_iff(e, x, y)) { todo.append(s->get_num_args(), s->get_args());
if (a.is_select(y)) {
std::swap(x,y);
}
if (a.is_select(x) && is_var(y)) {
if (!insert_def(r, to_app(x), to_var(y))) {
return false;
}
}
} }
if (a.is_select(e) && !insert_def(r, to_app(e), 0)) { else {
return false; todo.push_back(e);
} }
todo.push_back(e);
} }
// now make sure to cover all occurrences.
ast_mark mark;
while (!todo.empty()) { while (!todo.empty()) {
expr* e = todo.back(); expr* e = todo.back();
todo.pop_back(); if (cache.contains(e)) {
if (mark.is_marked(e)) { todo.pop_back();
continue; continue;
} }
mark.mark(e, true);
if (is_var(e)) { if (is_var(e)) {
cache.insert(e, e);
todo.pop_back();
continue; continue;
} }
if (!is_app(e)) { if (!is_app(e)) {
return false; return false;
} }
app* ap = to_app(e); app* ap = to_app(e);
if (a.is_select(ap) && !m_defs.contains(ap)) { bool valid = true;
if (!insert_def(r, ap, 0)) { args.reset();
return false; for (unsigned i = 0; i < ap->get_num_args(); ++i) {
expr* arg;
if (cache.find(ap->get_arg(i), arg)) {
args.push_back(arg);
}
else {
todo.push_back(ap->get_arg(i));
valid = false;
} }
} }
if (a.is_select(e)) { if (valid) {
get_select_args(e, todo); todo.pop_back();
continue; e1 = m.mk_app(ap->get_decl(), args.size(), args.c_ptr());
trail.push_back(e1);
if (a.is_select(ap)) {
if (m_defs.find(e1, v)) {
cache.insert(e, v);
}
else if (!insert_def(r, e1, 0)) {
return false;
}
else {
cache.insert(e, m_defs.find(e1));
}
}
else {
cache.insert(e, e1);
}
}
}
for (unsigned i = 0; i < conjs.size(); ++i) {
expr* e = conjs[i].get();
if (is_select_eq_var(e, s, v)) {
args.reset();
for (unsigned j = 0; j < s->get_num_args(); ++j) {
args.push_back(cache.find(s->get_arg(j)));
}
e1 = m.mk_app(s->get_decl(), args.size(), args.c_ptr());
if (!m_defs.contains(e1) && !insert_def(r, e1, v)) {
return false;
}
conjs[i] = m.mk_eq(v, m_defs.find(e1));
} }
for (unsigned i = 0; i < ap->get_num_args(); ++i) { else {
todo.push_back(ap->get_arg(i)); conjs[i] = cache.find(e);
} }
} }
m_sub(body);
m_sub(head);
conjs.reset();
// perform the Ackermann reduction by creating implications // perform the Ackermann reduction by creating implications
// i1 = i2 => val1 = val2 for each equality pair: // i1 = i2 => val1 = val2 for each equality pair:
@ -171,6 +212,7 @@ namespace datalog {
for (; it2 != end; ++it2) { for (; it2 != end; ++it2) {
app* a2 = it2->m_key; app* a2 = it2->m_key;
var* v2 = it2->m_value; var* v2 = it2->m_value;
TRACE("dl", tout << mk_pp(a1, m) << " " << mk_pp(a2, m) << "\n";);
if (get_select(a1) != get_select(a2)) { if (get_select(a1) != get_select(a2)) {
continue; continue;
} }
@ -184,10 +226,7 @@ namespace datalog {
conjs.push_back(m.mk_implies(m.mk_and(eqs.size(), eqs.c_ptr()), m.mk_eq(v1, v2))); conjs.push_back(m.mk_implies(m.mk_and(eqs.size(), eqs.c_ptr()), m.mk_eq(v1, v2)));
} }
} }
if (!conjs.empty()) { body = m.mk_and(conjs.size(), conjs.c_ptr());
conjs.push_back(body);
body = m.mk_and(conjs.size(), conjs.c_ptr());
}
m_rewriter(body); m_rewriter(body);
return true; return true;
} }
@ -232,7 +271,7 @@ namespace datalog {
} }
} }
expr_ref fml2(m), body(m), head(m); expr_ref fml1(m), fml2(m), body(m), head(m);
body = m.mk_and(new_conjs.size(), new_conjs.c_ptr()); body = m.mk_and(new_conjs.size(), new_conjs.c_ptr());
head = r.get_head(); head = r.get_head();
sub(body); sub(body);
@ -249,9 +288,17 @@ namespace datalog {
proof_ref p(m); proof_ref p(m);
rule_set new_rules(m_ctx); rule_set new_rules(m_ctx);
rm.mk_rule(fml2, p, new_rules, r.name()); rm.mk_rule(fml2, p, new_rules, r.name());
rule_ref new_rule(rm); rule_ref new_rule(rm);
if (m_simplifier.transform_rule(new_rules.last(), new_rule)) { if (m_simplifier.transform_rule(new_rules.last(), new_rule)) {
if (r.get_proof()) {
scoped_proof _sc(m);
r.to_formula(fml1);
p = m.mk_rewrite(fml1, fml2);
p = m.mk_modus_ponens(r.get_proof(), p);
new_rule->set_proof(m, p);
}
rules.add_rule(new_rule.get()); rules.add_rule(new_rule.get());
rm.mk_rule_rewrite_proof(r, *new_rule.get()); rm.mk_rule_rewrite_proof(r, *new_rule.get());
TRACE("dl", new_rule->display(m_ctx, tout << "new rule\n");); TRACE("dl", new_rule->display(m_ctx, tout << "new rule\n"););

View file

@ -44,7 +44,6 @@ namespace datalog {
mk_interp_tail_simplifier m_simplifier; mk_interp_tail_simplifier m_simplifier;
defs_t m_defs; defs_t m_defs;
expr_safe_replace m_sub;
unsigned m_next_var; unsigned m_next_var;
bool blast(rule& r, rule_set& new_rules); bool blast(rule& r, rule_set& new_rules);
@ -59,6 +58,8 @@ namespace datalog {
bool insert_def(rule const& r, app* e, var* v); bool insert_def(rule const& r, app* e, var* v);
bool is_select_eq_var(expr* e, app*& s, var*& v) const;
public: public:
/** /**
\brief Create rule transformer that removes array stores and selects by ackermannization. \brief Create rule transformer that removes array stores and selects by ackermannization.

View file

@ -25,6 +25,7 @@ Revision History:
#include "filter_model_converter.h" #include "filter_model_converter.h"
#include "dl_mk_interp_tail_simplifier.h" #include "dl_mk_interp_tail_simplifier.h"
#include "fixedpoint_params.hpp" #include "fixedpoint_params.hpp"
#include "scoped_proof.h"
namespace datalog { namespace datalog {
@ -268,7 +269,8 @@ namespace datalog {
r->to_formula(fml); r->to_formula(fml);
if (blast(r, fml)) { if (blast(r, fml)) {
proof_ref pr(m); proof_ref pr(m);
if (m_context.generate_proof_trace()) { if (r->get_proof()) {
scoped_proof _sc(m);
pr = m.mk_asserted(fml); // loses original proof of r. pr = m.mk_asserted(fml); // loses original proof of r.
} }
// TODO add logic for pc: // TODO add logic for pc:

View file

@ -341,7 +341,6 @@ namespace datalog {
} }
head = mk_head(source, *result, r.get_head(), cnt); head = mk_head(source, *result, r.get_head(), cnt);
fml = m.mk_implies(m.mk_and(tail.size(), tail.c_ptr()), head); fml = m.mk_implies(m.mk_and(tail.size(), tail.c_ptr()), head);
rule_ref_vector added_rules(rm);
proof_ref pr(m); proof_ref pr(m);
rm.mk_rule(fml, pr, *result); rm.mk_rule(fml, pr, *result);
TRACE("dl", result->last()->display(m_ctx, tout);); TRACE("dl", result->last()->display(m_ctx, tout););

View file

@ -9,7 +9,7 @@ Abstract:
SAT simplification procedures that use a "full" occurrence list: SAT simplification procedures that use a "full" occurrence list:
Subsumption, Blocked Clause Removal, Variable Elimination, ... Subsumption, Blocked Clause Removal, Variable Elimination, ...
Author: Author:
@ -54,21 +54,21 @@ namespace sat {
m_use_list[l2.index()].erase(c); m_use_list[l2.index()].erase(c);
} }
} }
simplifier::simplifier(solver & _s, params_ref const & p): simplifier::simplifier(solver & _s, params_ref const & p):
s(_s), s(_s),
m_num_calls(0) { m_num_calls(0) {
updt_params(p); updt_params(p);
reset_statistics(); reset_statistics();
} }
simplifier::~simplifier() { simplifier::~simplifier() {
} }
inline watch_list & simplifier::get_wlist(literal l) { return s.get_wlist(l); } inline watch_list & simplifier::get_wlist(literal l) { return s.get_wlist(l); }
inline watch_list const & simplifier::get_wlist(literal l) const { return s.get_wlist(l); } inline watch_list const & simplifier::get_wlist(literal l) const { return s.get_wlist(l); }
inline bool simplifier::is_external(bool_var v) const { return s.is_external(v); } inline bool simplifier::is_external(bool_var v) const { return s.is_external(v); }
inline bool simplifier::was_eliminated(bool_var v) const { return s.was_eliminated(v); } inline bool simplifier::was_eliminated(bool_var v) const { return s.was_eliminated(v); }
@ -78,7 +78,7 @@ namespace sat {
lbool simplifier::value(literal l) const { return s.value(l); } lbool simplifier::value(literal l) const { return s.value(l); }
inline void simplifier::checkpoint() { s.checkpoint(); } inline void simplifier::checkpoint() { s.checkpoint(); }
void simplifier::register_clauses(clause_vector & cs) { void simplifier::register_clauses(clause_vector & cs) {
std::stable_sort(cs.begin(), cs.end(), size_lt()); std::stable_sort(cs.begin(), cs.end(), size_lt());
clause_vector::iterator it = cs.begin(); clause_vector::iterator it = cs.begin();
@ -117,7 +117,7 @@ namespace sat {
SASSERT(s.get_wlist(~l1).contains(watched(l2, learned))); SASSERT(s.get_wlist(~l1).contains(watched(l2, learned)));
s.get_wlist(~l1).erase(watched(l2, learned)); s.get_wlist(~l1).erase(watched(l2, learned));
} }
void simplifier::init_visited() { void simplifier::init_visited() {
m_visited.reset(); m_visited.reset();
m_visited.resize(2*s.num_vars(), false); m_visited.resize(2*s.num_vars(), false);
@ -155,7 +155,7 @@ namespace sat {
if (!learned && (m_elim_blocked_clauses || m_elim_blocked_clauses_at == m_num_calls)) if (!learned && (m_elim_blocked_clauses || m_elim_blocked_clauses_at == m_num_calls))
elim_blocked_clauses(); elim_blocked_clauses();
if (!learned) if (!learned)
m_num_calls++; m_num_calls++;
@ -180,6 +180,7 @@ namespace sat {
bool vars_eliminated = m_num_elim_vars > old_num_elim_vars; bool vars_eliminated = m_num_elim_vars > old_num_elim_vars;
if (!m_need_cleanup) { if (!m_need_cleanup) {
TRACE("after_simplifier", tout << "skipping cleanup...\n";);
if (vars_eliminated) { if (vars_eliminated) {
// must remove learned clauses with eliminated variables // must remove learned clauses with eliminated variables
cleanup_clauses(s.m_learned, true, true, learned_in_use_lists); cleanup_clauses(s.m_learned, true, true, learned_in_use_lists);
@ -189,6 +190,7 @@ namespace sat {
free_memory(); free_memory();
return; return;
} }
TRACE("after_simplifier", tout << "cleanning watches...\n";);
cleanup_watches(); cleanup_watches();
cleanup_clauses(s.m_learned, true, vars_eliminated, learned_in_use_lists); cleanup_clauses(s.m_learned, true, vars_eliminated, learned_in_use_lists);
cleanup_clauses(s.m_clauses, false, vars_eliminated, true); cleanup_clauses(s.m_clauses, false, vars_eliminated, true);
@ -234,7 +236,7 @@ namespace sat {
s.del_clause(c); s.del_clause(c);
continue; continue;
} }
if (learned && vars_eliminated) { if (learned && vars_eliminated) {
unsigned sz = c.size(); unsigned sz = c.size();
unsigned i; unsigned i;
@ -293,7 +295,7 @@ namespace sat {
mark_visited(c[i]); mark_visited(c[i]);
} }
} }
void simplifier::unmark_all(clause const & c) { void simplifier::unmark_all(clause const & c) {
unsigned sz = c.size(); unsigned sz = c.size();
for (unsigned i = 0; i < sz; i++) for (unsigned i = 0; i < sz; i++)
@ -325,7 +327,7 @@ namespace sat {
*/ */
bool simplifier::subsumes1(clause const & c1, clause const & c2, literal & l) { bool simplifier::subsumes1(clause const & c1, clause const & c2, literal & l) {
unsigned sz2 = c2.size(); unsigned sz2 = c2.size();
for (unsigned i = 0; i < sz2; i++) for (unsigned i = 0; i < sz2; i++)
mark_visited(c2[i]); mark_visited(c2[i]);
bool r = true; bool r = true;
@ -344,7 +346,7 @@ namespace sat {
} }
} }
for (unsigned i = 0; i < sz2; i++) for (unsigned i = 0; i < sz2; i++)
unmark_visited(c2[i]); unmark_visited(c2[i]);
return r; return r;
} }
@ -353,7 +355,7 @@ namespace sat {
\brief Return the clauses subsumed by c1 and the clauses that can be subsumed resolved using c1. \brief Return the clauses subsumed by c1 and the clauses that can be subsumed resolved using c1.
The collections is populated using the use list of target. The collections is populated using the use list of target.
*/ */
void simplifier::collect_subsumed1_core(clause const & c1, clause_vector & out, literal_vector & out_lits, void simplifier::collect_subsumed1_core(clause const & c1, clause_vector & out, literal_vector & out_lits,
literal target) { literal target) {
clause_use_list const & cs = m_use_list.get(target); clause_use_list const & cs = m_use_list.get(target);
clause_use_list::iterator it = cs.mk_iterator(); clause_use_list::iterator it = cs.mk_iterator();
@ -362,7 +364,7 @@ namespace sat {
CTRACE("resolution_bug", c2.was_removed(), tout << "clause has been removed:\n" << c2 << "\n";); CTRACE("resolution_bug", c2.was_removed(), tout << "clause has been removed:\n" << c2 << "\n";);
SASSERT(!c2.was_removed()); SASSERT(!c2.was_removed());
if (&c2 != &c1 && if (&c2 != &c1 &&
c1.size() <= c2.size() && c1.size() <= c2.size() &&
approx_subset(c1.approx(), c2.approx())) { approx_subset(c1.approx(), c2.approx())) {
m_sub_counter -= c1.size() + c2.size(); m_sub_counter -= c1.size() + c2.size();
literal l; literal l;
@ -373,7 +375,7 @@ namespace sat {
} }
it.next(); it.next();
} }
} }
/** /**
\brief Return the clauses subsumed by c1 and the clauses that can be subsumed resolved using c1. \brief Return the clauses subsumed by c1 and the clauses that can be subsumed resolved using c1.
@ -400,12 +402,12 @@ namespace sat {
if (*l_it == null_literal) { if (*l_it == null_literal) {
// c2 was subsumed // c2 was subsumed
if (c1.is_learned() && !c2.is_learned()) if (c1.is_learned() && !c2.is_learned())
c1.unset_learned(); c1.unset_learned();
TRACE("subsumption", tout << c1 << " subsumed " << c2 << "\n";); TRACE("subsumption", tout << c1 << " subsumed " << c2 << "\n";);
remove_clause(c2); remove_clause(c2);
m_num_subsumed++; m_num_subsumed++;
} }
else { else if (!c2.was_removed()) {
// subsumption resolution // subsumption resolution
TRACE("subsumption_resolution", tout << c1 << " sub-ref(" << *l_it << ") " << c2 << "\n";); TRACE("subsumption_resolution", tout << c1 << " sub-ref(" << *l_it << ") " << c2 << "\n";);
elim_lit(c2, *l_it); elim_lit(c2, *l_it);
@ -447,9 +449,9 @@ namespace sat {
*/ */
bool simplifier::subsumes0(clause const & c1, clause const & c2) { bool simplifier::subsumes0(clause const & c1, clause const & c2) {
unsigned sz2 = c2.size(); unsigned sz2 = c2.size();
for (unsigned i = 0; i < sz2; i++) for (unsigned i = 0; i < sz2; i++)
mark_visited(c2[i]); mark_visited(c2[i]);
bool r = true; bool r = true;
unsigned sz1 = c1.size(); unsigned sz1 = c1.size();
for (unsigned i = 0; i < sz1; i++) { for (unsigned i = 0; i < sz1; i++) {
@ -459,12 +461,12 @@ namespace sat {
} }
} }
for (unsigned i = 0; i < sz2; i++) for (unsigned i = 0; i < sz2; i++)
unmark_visited(c2[i]); unmark_visited(c2[i]);
return r; return r;
} }
/** /**
\brief Collect the clauses subsumed by c1 (using the occurrence list of target). \brief Collect the clauses subsumed by c1 (using the occurrence list of target).
*/ */
@ -475,7 +477,7 @@ namespace sat {
clause & c2 = it.curr(); clause & c2 = it.curr();
SASSERT(!c2.was_removed()); SASSERT(!c2.was_removed());
if (&c2 != &c1 && if (&c2 != &c1 &&
c1.size() <= c2.size() && c1.size() <= c2.size() &&
approx_subset(c1.approx(), c2.approx())) { approx_subset(c1.approx(), c2.approx())) {
m_sub_counter -= c1.size() + c2.size(); m_sub_counter -= c1.size() + c2.size();
if (subsumes0(c1, c2)) { if (subsumes0(c1, c2)) {
@ -485,7 +487,7 @@ namespace sat {
it.next(); it.next();
} }
} }
/** /**
\brief Collect the clauses subsumed by c1 \brief Collect the clauses subsumed by c1
*/ */
@ -493,8 +495,8 @@ namespace sat {
literal l = get_min_occ_var0(c1); literal l = get_min_occ_var0(c1);
collect_subsumed0_core(c1, out, l); collect_subsumed0_core(c1, out, l);
} }
/** /**
\brief Perform backward subsumption using c1. \brief Perform backward subsumption using c1.
*/ */
@ -507,16 +509,16 @@ namespace sat {
clause & c2 = *(*it); clause & c2 = *(*it);
// c2 was subsumed // c2 was subsumed
if (c1.is_learned() && !c2.is_learned()) if (c1.is_learned() && !c2.is_learned())
c1.unset_learned(); c1.unset_learned();
TRACE("subsumption", tout << c1 << " subsumed " << c2 << "\n";); TRACE("subsumption", tout << c1 << " subsumed " << c2 << "\n";);
remove_clause(c2); remove_clause(c2);
m_num_subsumed++; m_num_subsumed++;
} }
} }
/** /**
\brief Eliminate false literals from c, and update occurrence lists \brief Eliminate false literals from c, and update occurrence lists
Return true if the clause is satisfied Return true if the clause is satisfied
*/ */
bool simplifier::cleanup_clause(clause & c, bool in_use_list) { bool simplifier::cleanup_clause(clause & c, bool in_use_list) {
@ -666,7 +668,7 @@ namespace sat {
back_subsumption1(c); back_subsumption1(c);
if (w.is_learned() && !c.is_learned()) { if (w.is_learned() && !c.is_learned()) {
SASSERT(wlist[j] == w); SASSERT(wlist[j] == w);
TRACE("mark_not_learned_bug", TRACE("mark_not_learned_bug",
tout << "marking as not learned: " << l2 << " " << wlist[j].is_learned() << "\n";); tout << "marking as not learned: " << l2 << " " << wlist[j].is_learned() << "\n";);
wlist[j].mark_not_learned(); wlist[j].mark_not_learned();
mark_as_not_learned_core(get_wlist(~l2), l); mark_as_not_learned_core(get_wlist(~l2), l);
@ -735,7 +737,7 @@ namespace sat {
continue; continue;
} }
if (it2->get_literal() == last_lit) { if (it2->get_literal() == last_lit) {
TRACE("subsumption", tout << "eliminating: " << ~to_literal(l_idx) TRACE("subsumption", tout << "eliminating: " << ~to_literal(l_idx)
<< " " << it2->get_literal() << "\n";); << " " << it2->get_literal() << "\n";);
elim++; elim++;
} }
@ -762,12 +764,12 @@ namespace sat {
m_num_sub_res(s.m_num_sub_res) { m_num_sub_res(s.m_num_sub_res) {
m_watch.start(); m_watch.start();
} }
~subsumption_report() { ~subsumption_report() {
m_watch.stop(); m_watch.stop();
IF_VERBOSE(SAT_VB_LVL, IF_VERBOSE(SAT_VB_LVL,
verbose_stream() << " (sat-subsumer :subsumed " verbose_stream() << " (sat-subsumer :subsumed "
<< (m_simplifier.m_num_subsumed - m_num_subsumed) << (m_simplifier.m_num_subsumed - m_num_subsumed)
<< " :subsumption-resolution " << (m_simplifier.m_num_sub_res - m_num_sub_res) << " :subsumption-resolution " << (m_simplifier.m_num_sub_res - m_num_sub_res)
<< " :threshold " << m_simplifier.m_sub_counter << " :threshold " << m_simplifier.m_sub_counter
<< mem_stat() << mem_stat()
@ -847,12 +849,12 @@ namespace sat {
vector<watch_list> const & m_watches; vector<watch_list> const & m_watches;
public: public:
literal_lt(use_list const & l, vector<watch_list> const & ws):m_use_list(l), m_watches(ws) {} literal_lt(use_list const & l, vector<watch_list> const & ws):m_use_list(l), m_watches(ws) {}
unsigned weight(unsigned l_idx) const { unsigned weight(unsigned l_idx) const {
return 2*m_use_list.get(~to_literal(l_idx)).size() + m_watches[l_idx].size(); return 2*m_use_list.get(~to_literal(l_idx)).size() + m_watches[l_idx].size();
} }
bool operator()(unsigned l_idx1, unsigned l_idx2) const { bool operator()(unsigned l_idx1, unsigned l_idx2) const {
return weight(l_idx1) < weight(l_idx2); return weight(l_idx1) < weight(l_idx2);
} }
}; };
@ -861,9 +863,9 @@ namespace sat {
heap<literal_lt> m_queue; heap<literal_lt> m_queue;
public: public:
queue(use_list const & l, vector<watch_list> const & ws):m_queue(128, literal_lt(l, ws)) {} queue(use_list const & l, vector<watch_list> const & ws):m_queue(128, literal_lt(l, ws)) {}
void insert(literal l) { void insert(literal l) {
unsigned idx = l.index(); unsigned idx = l.index();
m_queue.reserve(idx + 1); m_queue.reserve(idx + 1);
SASSERT(!m_queue.contains(idx)); SASSERT(!m_queue.contains(idx));
m_queue.insert(idx); m_queue.insert(idx);
} }
@ -877,14 +879,14 @@ namespace sat {
literal next() { SASSERT(!empty()); return to_literal(m_queue.erase_min()); } literal next() { SASSERT(!empty()); return to_literal(m_queue.erase_min()); }
bool empty() const { return m_queue.empty(); } bool empty() const { return m_queue.empty(); }
}; };
simplifier & s; simplifier & s;
int m_counter; int m_counter;
model_converter & mc; model_converter & mc;
queue m_queue; queue m_queue;
clause_vector m_to_remove; clause_vector m_to_remove;
blocked_clause_elim(simplifier & _s, unsigned limit, model_converter & _mc, use_list & l, blocked_clause_elim(simplifier & _s, unsigned limit, model_converter & _mc, use_list & l,
vector<watch_list> & wlist): vector<watch_list> & wlist):
s(_s), s(_s),
m_counter(limit), m_counter(limit),
@ -946,7 +948,7 @@ namespace sat {
clause_vector::iterator it = m_to_remove.begin(); clause_vector::iterator it = m_to_remove.begin();
clause_vector::iterator end = m_to_remove.end(); clause_vector::iterator end = m_to_remove.end();
for (; it != end; ++it) { for (; it != end; ++it) {
s.remove_clause(*(*it)); s.remove_clause(*(*it));
} }
} }
{ {
@ -1025,12 +1027,12 @@ namespace sat {
m_num_blocked_clauses(s.m_num_blocked_clauses) { m_num_blocked_clauses(s.m_num_blocked_clauses) {
m_watch.start(); m_watch.start();
} }
~blocked_cls_report() { ~blocked_cls_report() {
m_watch.stop(); m_watch.stop();
IF_VERBOSE(SAT_VB_LVL, IF_VERBOSE(SAT_VB_LVL,
verbose_stream() << " (sat-blocked-clauses :elim-blocked-clauses " verbose_stream() << " (sat-blocked-clauses :elim-blocked-clauses "
<< (m_simplifier.m_num_blocked_clauses - m_num_blocked_clauses) << (m_simplifier.m_num_blocked_clauses - m_num_blocked_clauses)
<< mem_stat() << mem_stat()
<< " :time " << std::fixed << std::setprecision(2) << m_watch.get_seconds() << ")\n";); << " :time " << std::fixed << std::setprecision(2) << m_watch.get_seconds() << ")\n";);
} }
@ -1062,8 +1064,8 @@ namespace sat {
unsigned num_neg = m_use_list.get(neg_l).size(); unsigned num_neg = m_use_list.get(neg_l).size();
unsigned num_bin_pos = get_num_non_learned_bin(pos_l); unsigned num_bin_pos = get_num_non_learned_bin(pos_l);
unsigned num_bin_neg = get_num_non_learned_bin(neg_l); unsigned num_bin_neg = get_num_non_learned_bin(neg_l);
unsigned cost = 2 * num_pos * num_neg + num_pos * num_bin_neg + num_neg * num_bin_pos; unsigned cost = 2 * num_pos * num_neg + num_pos * num_bin_neg + num_neg * num_bin_pos;
CTRACE("elim_vars_detail", cost == 0, tout << v << " num_pos: " << num_pos << " num_neg: " << num_neg << " num_bin_pos: " << num_bin_pos CTRACE("elim_vars_detail", cost == 0, tout << v << " num_pos: " << num_pos << " num_neg: " << num_neg << " num_bin_pos: " << num_bin_pos
<< " num_bin_neg: " << num_bin_neg << " cost: " << cost << "\n";); << " num_bin_neg: " << num_bin_neg << " cost: " << cost << "\n";);
return cost; return cost;
} }
@ -1071,7 +1073,7 @@ namespace sat {
typedef std::pair<bool_var, unsigned> bool_var_and_cost; typedef std::pair<bool_var, unsigned> bool_var_and_cost;
struct bool_var_and_cost_lt { struct bool_var_and_cost_lt {
bool operator()(bool_var_and_cost const & p1, bool_var_and_cost const & p2) const { return p1.second < p2.second; } bool operator()(bool_var_and_cost const & p1, bool_var_and_cost const & p2) const { return p1.second < p2.second; }
}; };
void simplifier::order_vars_for_elim(bool_var_vector & r) { void simplifier::order_vars_for_elim(bool_var_vector & r) {
@ -1104,7 +1106,7 @@ namespace sat {
r.push_back(it2->first); r.push_back(it2->first);
} }
} }
/** /**
\brief Collect clauses and binary clauses containing l. \brief Collect clauses and binary clauses containing l.
*/ */
@ -1116,7 +1118,7 @@ namespace sat {
SASSERT(r.back().size() == it.curr().size()); SASSERT(r.back().size() == it.curr().size());
it.next(); it.next();
} }
watch_list & wlist = get_wlist(~l); watch_list & wlist = get_wlist(~l);
watch_list::iterator it2 = wlist.begin(); watch_list::iterator it2 = wlist.begin();
watch_list::iterator end2 = wlist.end(); watch_list::iterator end2 = wlist.end();
@ -1129,7 +1131,7 @@ namespace sat {
} }
/** /**
\brief Resolve clauses c1 and c2. \brief Resolve clauses c1 and c2.
c1 must contain l. c1 must contain l.
c2 must contain ~l. c2 must contain ~l.
Store result in r. Store result in r.
@ -1149,7 +1151,7 @@ namespace sat {
m_visited[l2.index()] = true; m_visited[l2.index()] = true;
r.push_back(l2); r.push_back(l2);
} }
literal not_l = ~l; literal not_l = ~l;
sz = c2.size(); sz = c2.size();
m_elim_counter -= sz; m_elim_counter -= sz;
@ -1164,7 +1166,7 @@ namespace sat {
if (!m_visited[l2.index()]) if (!m_visited[l2.index()])
r.push_back(l2); r.push_back(l2);
} }
sz = c1.size(); sz = c1.size();
for (unsigned i = 0; i < sz; i++) { for (unsigned i = 0; i < sz; i++) {
literal l2 = c1[i]; literal l2 = c1[i];
@ -1200,7 +1202,7 @@ namespace sat {
break; break;
} }
} }
CTRACE("resolve_bug", it2 == end2, CTRACE("resolve_bug", it2 == end2,
tout << ~l1 << " -> "; tout << ~l1 << " -> ";
display(tout, s.m_cls_allocator, wlist1); tout << "\n" << ~l2 << " -> "; display(tout, s.m_cls_allocator, wlist1); tout << "\n" << ~l2 << " -> ";
display(tout, s.m_cls_allocator, wlist2); tout << "\n";); display(tout, s.m_cls_allocator, wlist2); tout << "\n";);
@ -1262,7 +1264,7 @@ namespace sat {
TRACE("resolution_bug", tout << "processing: " << v << "\n";); TRACE("resolution_bug", tout << "processing: " << v << "\n";);
if (value(v) != l_undef) if (value(v) != l_undef)
return false; return false;
literal pos_l(v, false); literal pos_l(v, false);
literal neg_l(v, true); literal neg_l(v, true);
unsigned num_bin_pos = get_num_non_learned_bin(pos_l); unsigned num_bin_pos = get_num_non_learned_bin(pos_l);
@ -1274,12 +1276,12 @@ namespace sat {
m_elim_counter -= num_pos + num_neg; m_elim_counter -= num_pos + num_neg;
TRACE("resolution", tout << v << " num_pos: " << num_pos << " neg_pos: " << num_neg << "\n";); TRACE("resolution", tout << v << " num_pos: " << num_pos << " neg_pos: " << num_neg << "\n";);
if (num_pos >= m_res_occ_cutoff && num_neg >= m_res_occ_cutoff) if (num_pos >= m_res_occ_cutoff && num_neg >= m_res_occ_cutoff)
return false; return false;
unsigned before_lits = num_bin_pos*2 + num_bin_neg*2; unsigned before_lits = num_bin_pos*2 + num_bin_neg*2;
{ {
clause_use_list::iterator it = pos_occs.mk_iterator(); clause_use_list::iterator it = pos_occs.mk_iterator();
while (!it.at_end()) { while (!it.at_end()) {
@ -1287,7 +1289,7 @@ namespace sat {
it.next(); it.next();
} }
} }
{ {
clause_use_list::iterator it2 = neg_occs.mk_iterator(); clause_use_list::iterator it2 = neg_occs.mk_iterator();
while (!it2.at_end()) { while (!it2.at_end()) {
@ -1297,23 +1299,23 @@ namespace sat {
} }
TRACE("resolution", tout << v << " num_pos: " << num_pos << " neg_pos: " << num_neg << " before_lits: " << before_lits << "\n";); TRACE("resolution", tout << v << " num_pos: " << num_pos << " neg_pos: " << num_neg << " before_lits: " << before_lits << "\n";);
if (num_pos >= m_res_occ_cutoff3 && num_neg >= m_res_occ_cutoff3 && before_lits > m_res_lit_cutoff3 && s.m_clauses.size() > m_res_cls_cutoff2) if (num_pos >= m_res_occ_cutoff3 && num_neg >= m_res_occ_cutoff3 && before_lits > m_res_lit_cutoff3 && s.m_clauses.size() > m_res_cls_cutoff2)
return false; return false;
if (num_pos >= m_res_occ_cutoff2 && num_neg >= m_res_occ_cutoff2 && before_lits > m_res_lit_cutoff2 && if (num_pos >= m_res_occ_cutoff2 && num_neg >= m_res_occ_cutoff2 && before_lits > m_res_lit_cutoff2 &&
s.m_clauses.size() > m_res_cls_cutoff1 && s.m_clauses.size() <= m_res_cls_cutoff2) s.m_clauses.size() > m_res_cls_cutoff1 && s.m_clauses.size() <= m_res_cls_cutoff2)
return false; return false;
if (num_pos >= m_res_occ_cutoff1 && num_neg >= m_res_occ_cutoff1 && before_lits > m_res_lit_cutoff1 && if (num_pos >= m_res_occ_cutoff1 && num_neg >= m_res_occ_cutoff1 && before_lits > m_res_lit_cutoff1 &&
s.m_clauses.size() <= m_res_cls_cutoff1) s.m_clauses.size() <= m_res_cls_cutoff1)
return false; return false;
m_pos_cls.reset(); m_pos_cls.reset();
m_neg_cls.reset(); m_neg_cls.reset();
collect_clauses(pos_l, m_pos_cls); collect_clauses(pos_l, m_pos_cls);
collect_clauses(neg_l, m_neg_cls); collect_clauses(neg_l, m_neg_cls);
m_elim_counter -= num_pos * num_neg + before_lits; m_elim_counter -= num_pos * num_neg + before_lits;
TRACE("resolution_detail", tout << "collecting number of after_clauses\n";); TRACE("resolution_detail", tout << "collecting number of after_clauses\n";);
unsigned before_clauses = num_pos + num_neg; unsigned before_clauses = num_pos + num_neg;
unsigned after_clauses = 0; unsigned after_clauses = 0;
@ -1350,7 +1352,7 @@ namespace sat {
neg_occs.reset(); neg_occs.reset();
m_elim_counter -= num_pos * num_neg + before_lits; m_elim_counter -= num_pos * num_neg + before_lits;
it1 = m_pos_cls.begin(); it1 = m_pos_cls.begin();
end1 = m_pos_cls.end(); end1 = m_pos_cls.end();
for (; it1 != end1; ++it1) { for (; it1 != end1; ++it1) {
@ -1393,7 +1395,7 @@ namespace sat {
return true; return true;
} }
} }
return true; return true;
} }
@ -1406,10 +1408,10 @@ namespace sat {
m_num_elim_vars(s.m_num_elim_vars) { m_num_elim_vars(s.m_num_elim_vars) {
m_watch.start(); m_watch.start();
} }
~elim_var_report() { ~elim_var_report() {
m_watch.stop(); m_watch.stop();
IF_VERBOSE(SAT_VB_LVL, IF_VERBOSE(SAT_VB_LVL,
verbose_stream() << " (sat-resolution :elim-bool-vars " verbose_stream() << " (sat-resolution :elim-bool-vars "
<< (m_simplifier.m_num_elim_vars - m_num_elim_vars) << (m_simplifier.m_num_elim_vars - m_num_elim_vars)
<< " :threshold " << m_simplifier.m_elim_counter << " :threshold " << m_simplifier.m_elim_counter
@ -1417,12 +1419,12 @@ namespace sat {
<< " :time " << std::fixed << std::setprecision(2) << m_watch.get_seconds() << ")\n";); << " :time " << std::fixed << std::setprecision(2) << m_watch.get_seconds() << ")\n";);
} }
}; };
void simplifier::elim_vars() { void simplifier::elim_vars() {
elim_var_report rpt(*this); elim_var_report rpt(*this);
bool_var_vector vars; bool_var_vector vars;
order_vars_for_elim(vars); order_vars_for_elim(vars);
bool_var_vector::iterator it = vars.begin(); bool_var_vector::iterator it = vars.begin();
bool_var_vector::iterator end = vars.end(); bool_var_vector::iterator end = vars.end();
for (; it != end; ++it) { for (; it != end; ++it) {
@ -1463,7 +1465,7 @@ namespace sat {
void simplifier::collect_param_descrs(param_descrs & r) { void simplifier::collect_param_descrs(param_descrs & r) {
sat_simplifier_params::collect_param_descrs(r); sat_simplifier_params::collect_param_descrs(r);
} }
void simplifier::collect_statistics(statistics & st) { void simplifier::collect_statistics(statistics & st) {
st.update("subsumed", m_num_subsumed); st.update("subsumed", m_num_subsumed);
st.update("subsumption resolution", m_num_sub_res); st.update("subsumption resolution", m_num_sub_res);
@ -1471,7 +1473,7 @@ namespace sat {
st.update("elim bool vars", m_num_elim_vars); st.update("elim bool vars", m_num_elim_vars);
st.update("elim blocked clauses", m_num_blocked_clauses); st.update("elim blocked clauses", m_num_blocked_clauses);
} }
void simplifier::reset_statistics() { void simplifier::reset_statistics() {
m_num_blocked_clauses = 0; m_num_blocked_clauses = 0;
m_num_subsumed = 0; m_num_subsumed = 0;

View file

@ -27,7 +27,7 @@ Revision History:
// define to create a copy of the solver before starting the search // define to create a copy of the solver before starting the search
// useful for checking models // useful for checking models
// #define CLONE_BEFORE_SOLVING // #define CLONE_BEFORE_SOLVING
namespace sat { namespace sat {
solver::solver(params_ref const & p, extension * ext): solver::solver(params_ref const & p, extension * ext):
@ -103,7 +103,7 @@ namespace sat {
} }
} }
} }
// ----------------------- // -----------------------
// //
// Variable & Clause creation // Variable & Clause creation
@ -312,7 +312,7 @@ namespace sat {
/** /**
\brief Select a watch literal starting the search at the given position. \brief Select a watch literal starting the search at the given position.
This method is only used for clauses created during the search. This method is only used for clauses created during the search.
I use the following rules to select a watch literal. I use the following rules to select a watch literal.
1- select a literal l in idx >= starting_at such that value(l) = l_true, 1- select a literal l in idx >= starting_at such that value(l) = l_true,
@ -329,7 +329,7 @@ namespace sat {
lvl(l) >= lvl(l') lvl(l) >= lvl(l')
Without rule 3, boolean propagation is incomplete, that is, it may miss possible propagations. Without rule 3, boolean propagation is incomplete, that is, it may miss possible propagations.
\remark The method select_lemma_watch_lit is used to select the watch literal for regular learned clauses. \remark The method select_lemma_watch_lit is used to select the watch literal for regular learned clauses.
*/ */
unsigned solver::select_watch_lit(clause const & cls, unsigned starting_at) const { unsigned solver::select_watch_lit(clause const & cls, unsigned starting_at) const {
@ -443,7 +443,7 @@ namespace sat {
erase_clause_watch(get_wlist(~c[0]), cls_off); erase_clause_watch(get_wlist(~c[0]), cls_off);
erase_clause_watch(get_wlist(~c[1]), cls_off); erase_clause_watch(get_wlist(~c[1]), cls_off);
} }
void solver::dettach_ter_clause(clause & c) { void solver::dettach_ter_clause(clause & c) {
erase_ternary_watch(get_wlist(~c[0]), c[1], c[2]); erase_ternary_watch(get_wlist(~c[0]), c[1], c[2]);
erase_ternary_watch(get_wlist(~c[1]), c[0], c[2]); erase_ternary_watch(get_wlist(~c[1]), c[0], c[2]);
@ -498,10 +498,10 @@ namespace sat {
unsigned sz = c.size(); unsigned sz = c.size();
for (unsigned i = 0; i < sz; i++) { for (unsigned i = 0; i < sz; i++) {
switch (value(c[i])) { switch (value(c[i])) {
case l_true: case l_true:
return l_true; return l_true;
case l_undef: case l_undef:
found_undef = true; found_undef = true;
break; break;
default: default:
break; break;
@ -515,7 +515,7 @@ namespace sat {
// Propagation // Propagation
// //
// ----------------------- // -----------------------
bool solver::propagate_core(bool update) { bool solver::propagate_core(bool update) {
if (m_inconsistent) if (m_inconsistent)
return false; return false;
@ -545,7 +545,7 @@ namespace sat {
} }
for (; it != end; ++it) { for (; it != end; ++it) {
switch (it->get_kind()) { switch (it->get_kind()) {
case watched::BINARY: case watched::BINARY:
l1 = it->get_literal(); l1 = it->get_literal();
switch (value(l1)) { switch (value(l1)) {
case l_false: case l_false:
@ -585,15 +585,30 @@ namespace sat {
break; break;
case watched::CLAUSE: { case watched::CLAUSE: {
if (value(it->get_blocked_literal()) == l_true) { if (value(it->get_blocked_literal()) == l_true) {
TRACE("propagate_clause_bug", tout << "blocked literal " << it->get_blocked_literal() << "\n";
clause_offset cls_off = it->get_clause_offset();
clause & c = *(m_cls_allocator.get_clause(cls_off));
tout << c << "\n";);
*it2 = *it; *it2 = *it;
it2++; it2++;
break; break;
} }
clause_offset cls_off = it->get_clause_offset(); clause_offset cls_off = it->get_clause_offset();
clause & c = *(m_cls_allocator.get_clause(cls_off)); clause & c = *(m_cls_allocator.get_clause(cls_off));
TRACE("propagate_clause_bug", tout << "processing... " << c << "\nwas_removed: " << c.was_removed() << "\n";);
if (c[0] == not_l) if (c[0] == not_l)
std::swap(c[0], c[1]); std::swap(c[0], c[1]);
CTRACE("propagate_bug", c[1] != not_l, tout << "l: " << l << " " << c << "\n";); CTRACE("propagate_bug", c[1] != not_l, tout << "l: " << l << " " << c << "\n";);
if (c.was_removed() || c[1] != not_l) {
// Remark: this method may be invoked when the watch lists are not in a consistent state,
// and may contain dead/removed clauses, or clauses with removed literals.
// See: method propagate_unit at sat_simplifier.cpp
// So, we must check whether the clause was marked for deletion, or
// c[1] != not_l
*it2 = *it;
it2++;
break;
}
SASSERT(c[1] == not_l); SASSERT(c[1] == not_l);
if (value(c[0]) == l_true) { if (value(c[0]) == l_true) {
it2->set_clause(c[0], cls_off); it2->set_clause(c[0], cls_off);
@ -693,7 +708,7 @@ namespace sat {
m_conflicts_since_restart = 0; m_conflicts_since_restart = 0;
m_restart_threshold = m_config.m_restart_initial; m_restart_threshold = m_config.m_restart_initial;
} }
// iff3_finder(*this)(); // iff3_finder(*this)();
simplify_problem(); simplify_problem();
@ -704,10 +719,10 @@ namespace sat {
IF_VERBOSE(SAT_VB_LVL, verbose_stream() << "\"abort: max-conflicts = 0\"\n";); IF_VERBOSE(SAT_VB_LVL, verbose_stream() << "\"abort: max-conflicts = 0\"\n";);
return l_undef; return l_undef;
} }
while (true) { while (true) {
SASSERT(!inconsistent()); SASSERT(!inconsistent());
lbool r = bounded_search(); lbool r = bounded_search();
if (r != l_undef) if (r != l_undef)
return r; return r;
@ -716,7 +731,7 @@ namespace sat {
IF_VERBOSE(SAT_VB_LVL, verbose_stream() << "\"abort: max-conflicts = " << m_conflicts << "\"\n";); IF_VERBOSE(SAT_VB_LVL, verbose_stream() << "\"abort: max-conflicts = " << m_conflicts << "\"\n";);
return l_undef; return l_undef;
} }
restart(); restart();
if (m_conflicts >= m_next_simplify) { if (m_conflicts >= m_next_simplify) {
simplify_problem(); simplify_problem();
@ -734,7 +749,7 @@ namespace sat {
bool_var solver::next_var() { bool_var solver::next_var() {
bool_var next; bool_var next;
if (m_rand() < static_cast<int>(m_config.m_random_freq * random_gen::max_value())) { if (m_rand() < static_cast<int>(m_config.m_random_freq * random_gen::max_value())) {
if (num_vars() == 0) if (num_vars() == 0)
return null_bool_var; return null_bool_var;
@ -743,16 +758,16 @@ namespace sat {
if (value(next) == l_undef && !was_eliminated(next)) if (value(next) == l_undef && !was_eliminated(next))
return next; return next;
} }
while (!m_case_split_queue.empty()) { while (!m_case_split_queue.empty()) {
next = m_case_split_queue.next_var(); next = m_case_split_queue.next_var();
if (value(next) == l_undef && !was_eliminated(next)) if (value(next) == l_undef && !was_eliminated(next))
return next; return next;
} }
return null_bool_var; return null_bool_var;
} }
bool solver::decide() { bool solver::decide() {
bool_var next = next_var(); bool_var next = next_var();
if (next == null_bool_var) if (next == null_bool_var)
@ -760,7 +775,7 @@ namespace sat {
push(); push();
m_stats.m_decision++; m_stats.m_decision++;
lbool phase = m_ext ? m_ext->get_phase(next) : l_undef; lbool phase = m_ext ? m_ext->get_phase(next) : l_undef;
if (phase == l_undef) { if (phase == l_undef) {
switch (m_config.m_phase) { switch (m_config.m_phase) {
case PS_ALWAYS_TRUE: case PS_ALWAYS_TRUE:
@ -784,7 +799,7 @@ namespace sat {
break; break;
} }
} }
SASSERT(phase != l_undef); SASSERT(phase != l_undef);
literal next_lit(next, phase == l_false); literal next_lit(next, phase == l_false);
assign(next_lit, justification()); assign(next_lit, justification());
@ -807,23 +822,23 @@ namespace sat {
return l_undef; return l_undef;
if (scope_lvl() == 0) { if (scope_lvl() == 0) {
cleanup(); // cleaner may propagate frozen clauses cleanup(); // cleaner may propagate frozen clauses
if (inconsistent()) if (inconsistent())
return l_false; return l_false;
gc(); gc();
} }
} }
gc(); gc();
if (!decide()) { if (!decide()) {
if (m_ext) { if (m_ext) {
switch (m_ext->check()) { switch (m_ext->check()) {
case CR_DONE: case CR_DONE:
mk_model(); mk_model();
return l_true; return l_true;
case CR_CONTINUE: case CR_CONTINUE:
break; break;
case CR_GIVEUP: case CR_GIVEUP:
throw abort_solver(); throw abort_solver();
} }
} }
@ -849,23 +864,23 @@ namespace sat {
m_stopwatch.reset(); m_stopwatch.reset();
m_stopwatch.start(); m_stopwatch.start();
} }
/** /**
\brief Apply all simplifications. \brief Apply all simplifications.
*/ */
void solver::simplify_problem() { void solver::simplify_problem() {
SASSERT(scope_lvl() == 0); SASSERT(scope_lvl() == 0);
m_cleaner(); m_cleaner();
CASSERT("sat_simplify_bug", check_invariant()); CASSERT("sat_simplify_bug", check_invariant());
m_scc(); m_scc();
CASSERT("sat_simplify_bug", check_invariant()); CASSERT("sat_simplify_bug", check_invariant());
m_simplifier(false); m_simplifier(false);
CASSERT("sat_simplify_bug", check_invariant()); CASSERT("sat_simplify_bug", check_invariant());
CASSERT("sat_missed_prop", check_missed_propagation()); CASSERT("sat_missed_prop", check_missed_propagation());
if (!m_learned.empty()) { if (!m_learned.empty()) {
m_simplifier(true); m_simplifier(true);
CASSERT("sat_missed_prop", check_missed_propagation()); CASSERT("sat_missed_prop", check_missed_propagation());
@ -878,11 +893,11 @@ namespace sat {
m_probing(); m_probing();
CASSERT("sat_missed_prop", check_missed_propagation()); CASSERT("sat_missed_prop", check_missed_propagation());
CASSERT("sat_simplify_bug", check_invariant()); CASSERT("sat_simplify_bug", check_invariant());
m_asymm_branch(); m_asymm_branch();
CASSERT("sat_missed_prop", check_missed_propagation()); CASSERT("sat_missed_prop", check_missed_propagation());
CASSERT("sat_simplify_bug", check_invariant()); CASSERT("sat_simplify_bug", check_invariant());
if (m_ext) { if (m_ext) {
m_ext->clauses_modifed(); m_ext->clauses_modifed();
m_ext->simplify(); m_ext->simplify();
@ -956,7 +971,7 @@ namespace sat {
} }
} }
} }
if (!m_mc.check_model(m)) if (!m_mc.check_model(m))
ok = false; ok = false;
CTRACE("sat_model_bug", !ok, tout << m << "\n";); CTRACE("sat_model_bug", !ok, tout << m << "\n";);
return ok; return ok;
@ -964,9 +979,9 @@ namespace sat {
void solver::restart() { void solver::restart() {
m_stats.m_restart++; m_stats.m_restart++;
IF_VERBOSE(1, IF_VERBOSE(1,
verbose_stream() << "(sat-restart :conflicts " << m_stats.m_conflict << " :decisions " << m_stats.m_decision verbose_stream() << "(sat-restart :conflicts " << m_stats.m_conflict << " :decisions " << m_stats.m_decision
<< " :restarts " << m_stats.m_restart << mk_stat(*this) << " :restarts " << m_stats.m_restart << mk_stat(*this)
<< " :time " << std::fixed << std::setprecision(2) << m_stopwatch.get_current_seconds() << ")\n";); << " :time " << std::fixed << std::setprecision(2) << m_stopwatch.get_current_seconds() << ")\n";);
IF_VERBOSE(30, display_status(verbose_stream());); IF_VERBOSE(30, display_status(verbose_stream()););
pop(scope_lvl()); pop(scope_lvl());
@ -991,9 +1006,9 @@ namespace sat {
// GC // GC
// //
// ----------------------- // -----------------------
void solver::gc() { void solver::gc() {
if (m_conflicts_since_gc <= m_gc_threshold) if (m_conflicts_since_gc <= m_gc_threshold)
return; return;
CASSERT("sat_gc_bug", check_invariant()); CASSERT("sat_gc_bug", check_invariant());
switch (m_config.m_gc_strategy) { switch (m_config.m_gc_strategy) {
@ -1073,7 +1088,7 @@ namespace sat {
std::stable_sort(m_learned.begin(), m_learned.end(), glue_lt()); std::stable_sort(m_learned.begin(), m_learned.end(), glue_lt());
gc_half("glue"); gc_half("glue");
} }
void solver::gc_psm() { void solver::gc_psm() {
save_psm(); save_psm();
std::stable_sort(m_learned.begin(), m_learned.end(), psm_lt()); std::stable_sort(m_learned.begin(), m_learned.end(), psm_lt());
@ -1134,8 +1149,8 @@ namespace sat {
void solver::gc_dyn_psm() { void solver::gc_dyn_psm() {
// To do gc at scope_lvl() > 0, I will need to use the reinitialization stack, or live with the fact // To do gc at scope_lvl() > 0, I will need to use the reinitialization stack, or live with the fact
// that I may miss some propagations for reactivated clauses. // that I may miss some propagations for reactivated clauses.
SASSERT(scope_lvl() == 0); SASSERT(scope_lvl() == 0);
// compute // compute
// d_tk // d_tk
unsigned h = 0; unsigned h = 0;
unsigned V_tk = 0; unsigned V_tk = 0;
@ -1152,7 +1167,7 @@ namespace sat {
double d_tk = V_tk == 0 ? static_cast<double>(num_vars() + 1) : static_cast<double>(h)/static_cast<double>(V_tk); double d_tk = V_tk == 0 ? static_cast<double>(num_vars() + 1) : static_cast<double>(h)/static_cast<double>(V_tk);
if (d_tk < m_min_d_tk) if (d_tk < m_min_d_tk)
m_min_d_tk = d_tk; m_min_d_tk = d_tk;
TRACE("sat_frozen", tout << "m_min_d_tk: " << m_min_d_tk << "\n";); TRACE("sat_frozen", tout << "m_min_d_tk: " << m_min_d_tk << "\n";);
unsigned frozen = 0; unsigned frozen = 0;
unsigned deleted = 0; unsigned deleted = 0;
unsigned activated = 0; unsigned activated = 0;
@ -1218,15 +1233,15 @@ namespace sat {
++it2; ++it2;
} }
m_learned.set_end(it2); m_learned.set_end(it2);
IF_VERBOSE(SAT_VB_LVL, verbose_stream() << "(sat-gc :d_tk " << d_tk << " :min-d_tk " << m_min_d_tk << IF_VERBOSE(SAT_VB_LVL, verbose_stream() << "(sat-gc :d_tk " << d_tk << " :min-d_tk " << m_min_d_tk <<
" :frozen " << frozen << " :activated " << activated << " :deleted " << deleted << ")\n";); " :frozen " << frozen << " :activated " << activated << " :deleted " << deleted << ")\n";);
} }
// return true if should keep the clause, and false if we should delete it. // return true if should keep the clause, and false if we should delete it.
bool solver::activate_frozen_clause(clause & c) { bool solver::activate_frozen_clause(clause & c) {
TRACE("sat_gc", tout << "reactivating:\n" << c << "\n";); TRACE("sat_gc", tout << "reactivating:\n" << c << "\n";);
SASSERT(scope_lvl() == 0); SASSERT(scope_lvl() == 0);
// do some cleanup // do some cleanup
unsigned sz = c.size(); unsigned sz = c.size();
unsigned j = 0; unsigned j = 0;
for (unsigned i = 0; i < sz; i++) { for (unsigned i = 0; i < sz; i++) {
@ -1290,13 +1305,13 @@ namespace sat {
bool solver::resolve_conflict() { bool solver::resolve_conflict() {
while (true) { while (true) {
bool r = resolve_conflict_core(); bool r = resolve_conflict_core();
CASSERT("sat_check_marks", check_marks());
// after pop, clauses are reinitialized, this may trigger another conflict. // after pop, clauses are reinitialized, this may trigger another conflict.
if (!r) if (!r)
return false; return false;
if (!inconsistent()) if (!inconsistent())
return true; return true;
} }
CASSERT("sat_check_marks", check_marks());
} }
bool solver::resolve_conflict_core() { bool solver::resolve_conflict_core() {
@ -1311,7 +1326,7 @@ namespace sat {
if (m_conflict_lvl == 0) if (m_conflict_lvl == 0)
return false; return false;
m_lemma.reset(); m_lemma.reset();
forget_phase_of_vars(m_conflict_lvl); forget_phase_of_vars(m_conflict_lvl);
unsigned idx = skip_literals_above_conflict_level(); unsigned idx = skip_literals_above_conflict_level();
@ -1323,10 +1338,10 @@ namespace sat {
TRACE("sat_conflict", tout << "not_l: " << m_not_l << "\n";); TRACE("sat_conflict", tout << "not_l: " << m_not_l << "\n";);
process_antecedent(m_not_l, num_marks); process_antecedent(m_not_l, num_marks);
} }
literal consequent = m_not_l; literal consequent = m_not_l;
justification js = m_conflict; justification js = m_conflict;
do { do {
TRACE("sat_conflict_detail", tout << "processing consequent: " << consequent << "\n"; TRACE("sat_conflict_detail", tout << "processing consequent: " << consequent << "\n";
tout << "num_marks: " << num_marks << ", js kind: " << js.get_kind() << "\n";); tout << "num_marks: " << num_marks << ", js kind: " << js.get_kind() << "\n";);
@ -1362,7 +1377,7 @@ namespace sat {
fill_ext_antecedents(consequent, js); fill_ext_antecedents(consequent, js);
literal_vector::iterator it = m_ext_antecedents.begin(); literal_vector::iterator it = m_ext_antecedents.begin();
literal_vector::iterator end = m_ext_antecedents.end(); literal_vector::iterator end = m_ext_antecedents.end();
for (; it != end; ++it) for (; it != end; ++it)
process_antecedent(*it, num_marks); process_antecedent(*it, num_marks);
break; break;
} }
@ -1370,10 +1385,10 @@ namespace sat {
UNREACHABLE(); UNREACHABLE();
break; break;
} }
while (true) { while (true) {
literal l = m_trail[idx]; literal l = m_trail[idx];
if (is_marked(l.var())) if (is_marked(l.var()))
break; break;
SASSERT(idx > 0); SASSERT(idx > 0);
idx--; idx--;
@ -1386,9 +1401,9 @@ namespace sat {
idx--; idx--;
num_marks--; num_marks--;
reset_mark(c_var); reset_mark(c_var);
} }
while (num_marks > 0); while (num_marks > 0);
m_lemma[0] = ~consequent; m_lemma[0] = ~consequent;
TRACE("sat_lemma", tout << "new lemma size: " << m_lemma.size() << "\n" << m_lemma << "\n";); TRACE("sat_lemma", tout << "new lemma size: " << m_lemma.size() << "\n" << m_lemma << "\n";);
@ -1399,7 +1414,9 @@ namespace sat {
dyn_sub_res(); dyn_sub_res();
TRACE("sat_lemma", tout << "new lemma (after minimization) size: " << m_lemma.size() << "\n" << m_lemma << "\n";); TRACE("sat_lemma", tout << "new lemma (after minimization) size: " << m_lemma.size() << "\n" << m_lemma << "\n";);
} }
else
reset_lemma_var_marks();
literal_vector::iterator it = m_lemma.begin(); literal_vector::iterator it = m_lemma.begin();
literal_vector::iterator end = m_lemma.end(); literal_vector::iterator end = m_lemma.end();
unsigned new_scope_lvl = 0; unsigned new_scope_lvl = 0;
@ -1430,10 +1447,10 @@ namespace sat {
return 0; return 0;
unsigned r = 0; unsigned r = 0;
if (consequent != null_literal) if (consequent != null_literal)
r = lvl(consequent); r = lvl(consequent);
switch (js.get_kind()) { switch (js.get_kind()) {
case justification::NONE: case justification::NONE:
break; break;
@ -1466,7 +1483,7 @@ namespace sat {
fill_ext_antecedents(consequent, js); fill_ext_antecedents(consequent, js);
literal_vector::iterator it = m_ext_antecedents.begin(); literal_vector::iterator it = m_ext_antecedents.begin();
literal_vector::iterator end = m_ext_antecedents.end(); literal_vector::iterator end = m_ext_antecedents.end();
for (; it != end; ++it) for (; it != end; ++it)
r = std::max(r, lvl(*it)); r = std::max(r, lvl(*it));
break; break;
} }
@ -1495,7 +1512,7 @@ namespace sat {
} }
return idx; return idx;
} }
void solver::process_antecedent(literal antecedent, unsigned & num_marks) { void solver::process_antecedent(literal antecedent, unsigned & num_marks) {
bool_var var = antecedent.var(); bool_var var = antecedent.var();
unsigned var_lvl = lvl(var); unsigned var_lvl = lvl(var);
@ -1509,7 +1526,7 @@ namespace sat {
m_lemma.push_back(~antecedent); m_lemma.push_back(~antecedent);
} }
} }
/** /**
\brief js is an external justification. Collect its antecedents and store at m_ext_antecedents. \brief js is an external justification. Collect its antecedents and store at m_ext_antecedents.
*/ */
@ -1576,7 +1593,7 @@ namespace sat {
unsigned var_lvl = lvl(var); unsigned var_lvl = lvl(var);
if (!is_marked(var) && var_lvl > 0) { if (!is_marked(var) && var_lvl > 0) {
if (m_lvl_set.may_contain(var_lvl)) { if (m_lvl_set.may_contain(var_lvl)) {
mark(var); mark(var);
m_unmark.push_back(var); m_unmark.push_back(var);
m_lemma_min_stack.push_back(var); m_lemma_min_stack.push_back(var);
} }
@ -1588,17 +1605,17 @@ namespace sat {
} }
/** /**
\brief Return true if lit is implied by other marked literals \brief Return true if lit is implied by other marked literals
and/or literals assigned at the base level. and/or literals assigned at the base level.
The set lvl_set is used as an optimization. The set lvl_set is used as an optimization.
The idea is to stop the recursive search with a failure The idea is to stop the recursive search with a failure
as soon as we find a literal assigned in a level that is not in lvl_set. as soon as we find a literal assigned in a level that is not in lvl_set.
*/ */
bool solver::implied_by_marked(literal lit) { bool solver::implied_by_marked(literal lit) {
m_lemma_min_stack.reset(); // avoid recursive function m_lemma_min_stack.reset(); // avoid recursive function
m_lemma_min_stack.push_back(lit.var()); m_lemma_min_stack.push_back(lit.var());
unsigned old_size = m_unmark.size(); unsigned old_size = m_unmark.size();
while (!m_lemma_min_stack.empty()) { while (!m_lemma_min_stack.empty()) {
bool_var var = m_lemma_min_stack.back(); bool_var var = m_lemma_min_stack.back();
m_lemma_min_stack.pop_back(); m_lemma_min_stack.pop_back();
@ -1699,7 +1716,7 @@ namespace sat {
void solver::minimize_lemma() { void solver::minimize_lemma() {
m_unmark.reset(); m_unmark.reset();
updt_lemma_lvl_set(); updt_lemma_lvl_set();
unsigned sz = m_lemma.size(); unsigned sz = m_lemma.size();
unsigned i = 1; // the first literal is the FUIP unsigned i = 1; // the first literal is the FUIP
unsigned j = 1; unsigned j = 1;
@ -1715,12 +1732,12 @@ namespace sat {
j++; j++;
} }
} }
reset_unmark(0); reset_unmark(0);
m_lemma.shrink(j); m_lemma.shrink(j);
m_stats.m_minimized_lits += sz - j; m_stats.m_minimized_lits += sz - j;
} }
/** /**
\brief Reset the mark of the variables in the current lemma. \brief Reset the mark of the variables in the current lemma.
*/ */
@ -1740,17 +1757,17 @@ namespace sat {
Only binary and ternary clauses are used. Only binary and ternary clauses are used.
*/ */
void solver::dyn_sub_res() { void solver::dyn_sub_res() {
unsigned sz = m_lemma.size(); unsigned sz = m_lemma.size();
for (unsigned i = 0; i < sz; i++) { for (unsigned i = 0; i < sz; i++) {
mark_lit(m_lemma[i]); mark_lit(m_lemma[i]);
} }
literal l0 = m_lemma[0]; literal l0 = m_lemma[0];
// l0 is the FUIP, and we never remove the FUIP. // l0 is the FUIP, and we never remove the FUIP.
// //
// In the following loop, we use unmark_lit(l) to remove a // In the following loop, we use unmark_lit(l) to remove a
// literal from m_lemma. // literal from m_lemma.
for (unsigned i = 0; i < sz; i++) { for (unsigned i = 0; i < sz; i++) {
literal l = m_lemma[i]; literal l = m_lemma[i];
if (!is_marked_lit(l)) if (!is_marked_lit(l))
@ -1762,8 +1779,8 @@ namespace sat {
for (; it != end; ++it) { for (; it != end; ++it) {
// In this for-loop, the conditions l0 != ~l2 and l0 != ~l3 // In this for-loop, the conditions l0 != ~l2 and l0 != ~l3
// are not really needed if the solver does not miss unit propagations. // are not really needed if the solver does not miss unit propagations.
// However, we add them anyway because we don't want to rely on this // However, we add them anyway because we don't want to rely on this
// property of the propagator. // property of the propagator.
// For example, if this property is relaxed in the future, then the code // For example, if this property is relaxed in the future, then the code
// without the conditions l0 != ~l2 and l0 != ~l3 may remove the FUIP // without the conditions l0 != ~l2 and l0 != ~l3 may remove the FUIP
if (it->is_binary_clause()) { if (it->is_binary_clause()) {
@ -1809,10 +1826,10 @@ namespace sat {
// p1 \/ ~p2 // p1 \/ ~p2
// p2 \/ ~p3 // p2 \/ ~p3
// p3 \/ ~p4 // p3 \/ ~p4
// q1 \/ q2 \/ p1 \/ p2 \/ p3 \/ p4 \/ l2 // q1 \/ q2 \/ p1 \/ p2 \/ p3 \/ p4 \/ l2
// q1 \/ ~q2 \/ p1 \/ p2 \/ p3 \/ p4 \/ l2 // q1 \/ ~q2 \/ p1 \/ p2 \/ p3 \/ p4 \/ l2
// ~q1 \/ q2 \/ p1 \/ p2 \/ p3 \/ p4 \/ l2 // ~q1 \/ q2 \/ p1 \/ p2 \/ p3 \/ p4 \/ l2
// ~q1 \/ ~q2 \/ p1 \/ p2 \/ p3 \/ p4 \/ l2 // ~q1 \/ ~q2 \/ p1 \/ p2 \/ p3 \/ p4 \/ l2
// ... // ...
// //
// 2. Now suppose we learned the lemma // 2. Now suppose we learned the lemma
@ -1823,15 +1840,15 @@ namespace sat {
// That is, l \/ l2 is an implied clause. Note that probing does not add // That is, l \/ l2 is an implied clause. Note that probing does not add
// this clause to the clause database (there are too many). // this clause to the clause database (there are too many).
// //
// 4. Lemma (*) is deleted (garbage collected). // 4. Lemma (*) is deleted (garbage collected).
// //
// 5. l is decided to be false, p1, p2, p3 and p4 are propagated using BCP, // 5. l is decided to be false, p1, p2, p3 and p4 are propagated using BCP,
// but l2 is not since the lemma (*) was deleted. // but l2 is not since the lemma (*) was deleted.
// //
// Probing module still "knows" that l \/ l2 is valid binary clause // Probing module still "knows" that l \/ l2 is valid binary clause
// //
// 6. A new lemma is created where ~l2 is the FUIP and the lemma also contains l. // 6. A new lemma is created where ~l2 is the FUIP and the lemma also contains l.
// If we remove l0 != ~l2 may try to delete the FUIP. // If we remove l0 != ~l2 may try to delete the FUIP.
if (is_marked_lit(~l2) && l0 != ~l2) { if (is_marked_lit(~l2) && l0 != ~l2) {
// eliminate ~l2 from lemma because we have the clause l \/ l2 // eliminate ~l2 from lemma because we have the clause l \/ l2
unmark_lit(~l2); unmark_lit(~l2);
@ -1842,7 +1859,7 @@ namespace sat {
// can't eliminat FUIP // can't eliminat FUIP
SASSERT(is_marked_lit(m_lemma[0])); SASSERT(is_marked_lit(m_lemma[0]));
unsigned j = 0; unsigned j = 0;
for (unsigned i = 0; i < sz; i++) { for (unsigned i = 0; i < sz; i++) {
literal l = m_lemma[i]; literal l = m_lemma[i];
@ -1854,7 +1871,7 @@ namespace sat {
} }
m_stats.m_dyn_sub_res += sz - j; m_stats.m_dyn_sub_res += sz - j;
SASSERT(j >= 1); SASSERT(j >= 1);
m_lemma.shrink(j); m_lemma.shrink(j);
} }
@ -1947,7 +1964,7 @@ namespace sat {
// Misc // Misc
// //
// ----------------------- // -----------------------
void solver::updt_params(params_ref const & p) { void solver::updt_params(params_ref const & p) {
m_params = p; m_params = p;
m_config.updt_params(p); m_config.updt_params(p);
@ -1969,7 +1986,7 @@ namespace sat {
void solver::set_cancel(bool f) { void solver::set_cancel(bool f) {
m_cancel = f; m_cancel = f;
} }
void solver::collect_statistics(statistics & st) { void solver::collect_statistics(statistics & st) {
m_stats.collect_statistics(st); m_stats.collect_statistics(st);
m_cleaner.collect_statistics(st); m_cleaner.collect_statistics(st);
@ -2065,7 +2082,7 @@ namespace sat {
} }
} }
} }
void solver::display_units(std::ostream & out) const { void solver::display_units(std::ostream & out) const {
unsigned end = scope_lvl() == 0 ? m_trail.size() : m_scopes[0].m_trail_lim; unsigned end = scope_lvl() == 0 ? m_trail.size() : m_scopes[0].m_trail_lim;
for (unsigned i = 0; i < end; i++) { for (unsigned i = 0; i < end; i++) {
@ -2219,26 +2236,26 @@ namespace sat {
// Simplification // Simplification
// //
// ----------------------- // -----------------------
void solver::cleanup() { void solver::cleanup() {
if (scope_lvl() > 0 || inconsistent()) if (scope_lvl() > 0 || inconsistent())
return; return;
if (m_cleaner() && m_ext) if (m_cleaner() && m_ext)
m_ext->clauses_modifed(); m_ext->clauses_modifed();
} }
void solver::simplify(bool learned) { void solver::simplify(bool learned) {
if (scope_lvl() > 0 || inconsistent()) if (scope_lvl() > 0 || inconsistent())
return; return;
m_simplifier(learned); m_simplifier(learned);
m_simplifier.free_memory(); m_simplifier.free_memory();
if (m_ext) if (m_ext)
m_ext->clauses_modifed(); m_ext->clauses_modifed();
} }
unsigned solver::scc_bin() { unsigned solver::scc_bin() {
if (scope_lvl() > 0 || inconsistent()) if (scope_lvl() > 0 || inconsistent())
return 0; return 0;
unsigned r = m_scc(); unsigned r = m_scc();
if (r > 0 && m_ext) if (r > 0 && m_ext)
m_ext->clauses_modifed(); m_ext->clauses_modifed();
return r; return r;
@ -2312,10 +2329,10 @@ namespace sat {
out << " :inconsistent " << (m_inconsistent ? "true" : "false") << "\n"; out << " :inconsistent " << (m_inconsistent ? "true" : "false") << "\n";
out << " :vars " << num_vars() << "\n"; out << " :vars " << num_vars() << "\n";
out << " :elim-vars " << num_elim << "\n"; out << " :elim-vars " << num_elim << "\n";
out << " :lits " << num_lits << "\n"; out << " :lits " << num_lits << "\n";
out << " :assigned " << m_trail.size() << "\n"; out << " :assigned " << m_trail.size() << "\n";
out << " :binary-clauses " << num_bin << "\n"; out << " :binary-clauses " << num_bin << "\n";
out << " :ternary-clauses " << num_ter << "\n"; out << " :ternary-clauses " << num_ter << "\n";
out << " :clauses " << num_cls << "\n"; out << " :clauses " << num_cls << "\n";
out << " :del-clause " << m_stats.m_del_clause << "\n"; out << " :del-clause " << m_stats.m_del_clause << "\n";
out << " :avg-clause-size " << (total_cls == 0 ? 0.0 : static_cast<double>(num_lits) / static_cast<double>(total_cls)) << "\n"; out << " :avg-clause-size " << (total_cls == 0 ? 0.0 : static_cast<double>(num_lits) / static_cast<double>(total_cls)) << "\n";

View file

@ -820,6 +820,7 @@ public:
} }
} }
private:
// Update the assignment of variable v, that is, // Update the assignment of variable v, that is,
// m_assignment[v] += inc // m_assignment[v] += inc
// This method also stores the old value of v in the assignment stack. // This method also stores the old value of v in the assignment stack.
@ -829,6 +830,12 @@ public:
m_assignment[v] += inc; m_assignment[v] += inc;
} }
public:
void inc_assignment(dl_var v, numeral const& inc) {
m_assignment[v] += inc;
}
struct every_var_proc { struct every_var_proc {
bool operator()(dl_var v) const { bool operator()(dl_var v) const {

View file

@ -189,11 +189,12 @@ public:
max_size = Number(usz); max_size = Number(usz);
has_max = true; has_max = true;
} }
Number start = set->m_next;
Number & next = set->m_next; Number & next = set->m_next;
while (!is_new) { while (!is_new) {
result = mk_value(next, s, is_new); result = mk_value(next, s, is_new);
next++; next++;
if (has_max && next > max_size + set->m_next) { if (has_max && next > max_size + start) {
return 0; return 0;
} }
} }

View file

@ -975,9 +975,11 @@ namespace smt {
// Moreover, a model assigns an arbitrary intepretation to these sorts using "model_values" a model value. // Moreover, a model assigns an arbitrary intepretation to these sorts using "model_values" a model value.
// If these module values "leak" inside the logical context, they may affect satisfiability. // If these module values "leak" inside the logical context, they may affect satisfiability.
// //
// n->insert(m_model->get_some_value(n->get_sort()), 0); sort * ns = n->get_sort();
// TODO: we can use get_some_value if the sort n->get_sort() does not depend on any uninterpreted sorts. if (m_manager.is_fully_interp(ns))
n->insert(m_manager.mk_fresh_const("elem", n->get_sort()), 0); n->insert(m_model->get_some_value(ns), 0);
else
n->insert(m_manager.mk_fresh_const("elem", ns), 0);
} }
} }
} }

View file

@ -581,10 +581,13 @@ namespace smt {
void theory_bv::assert_int2bv_axiom(app* n) { void theory_bv::assert_int2bv_axiom(app* n) {
// //
// create the axiom: // create the axiom:
// bv2int(n) = e mod 2^bit_width // bv2int(n) = e mod 2^bit_width
//
// where n = int2bv(e) // where n = int2bv(e)
// //
// Create the axioms:
// bit2bool(i,n) == ((e div 2^i) mod 2 != 0)
// for i = 0,.., sz-1
//
SASSERT(get_context().e_internalized(n)); SASSERT(get_context().e_internalized(n));
SASSERT(m_util.is_int2bv(n)); SASSERT(m_util.is_int2bv(n));
ast_manager & m = get_manager(); ast_manager & m = get_manager();
@ -592,10 +595,12 @@ namespace smt {
parameter param(m_autil.mk_int()); parameter param(m_autil.mk_int());
expr* n_expr = n; expr* n_expr = n;
expr* lhs = m.mk_app(get_id(), OP_BV2INT, 1, &param, 1, &n_expr); expr* e = n->get_arg(0);
expr_ref lhs(m), rhs(m);
lhs = m.mk_app(get_id(), OP_BV2INT, 1, &param, 1, &n_expr);
unsigned sz = m_util.get_bv_size(n); unsigned sz = m_util.get_bv_size(n);
numeral mod = power(numeral(2), sz); numeral mod = power(numeral(2), sz);
expr* rhs = m_autil.mk_mod(n->get_arg(0), m_autil.mk_numeral(mod, true)); rhs = m_autil.mk_mod(e, m_autil.mk_numeral(mod, true));
literal l(mk_eq(lhs, rhs, false)); literal l(mk_eq(lhs, rhs, false));
ctx.mark_as_relevant(l); ctx.mark_as_relevant(l);
@ -605,6 +610,24 @@ namespace smt {
tout << mk_pp(lhs, m) << " == \n"; tout << mk_pp(lhs, m) << " == \n";
tout << mk_pp(rhs, m) << "\n"; tout << mk_pp(rhs, m) << "\n";
); );
expr_ref_vector n_bits(m);
enode * n_enode = mk_enode(n);
get_bits(n_enode, n_bits);
for (unsigned i = 0; i < sz; ++i) {
numeral div = power(numeral(2), i);
mod = numeral(2);
rhs = m_autil.mk_idiv(e, m_autil.mk_numeral(div,true));
rhs = m_autil.mk_mod(rhs, m_autil.mk_numeral(mod, true));
rhs = m.mk_eq(rhs, m_autil.mk_numeral(rational(1), true));
lhs = n_bits.get(i);
TRACE("bv", tout << mk_pp(lhs, m) << " == " << mk_pp(rhs, m) << "\n";);
l = literal(mk_eq(lhs, rhs, false));
ctx.mark_as_relevant(l);
ctx.mk_th_axiom(get_id(), 1, &l);
}
} }

View file

@ -752,7 +752,8 @@ namespace smt {
for (unsigned j = 0; j < zero_v.size(); ++j) { for (unsigned j = 0; j < zero_v.size(); ++j) {
int v = zero_v[j]; int v = zero_v[j];
m_graph.acc_assignment(v, numeral(-1));
m_graph.inc_assignment(v, numeral(-1));
th_var k = from_var(v); th_var k = from_var(v);
if (!is_parity_ok(k)) { if (!is_parity_ok(k)) {
todo.push_back(k); todo.push_back(k);

View file

@ -50,7 +50,7 @@ class factor_tactic : public tactic {
return args[0]; return args[0];
return m_util.mk_mul(sz, args); return m_util.mk_mul(sz, args);
} }
expr * mk_zero_for(expr * arg) { expr * mk_zero_for(expr * arg) {
return m_util.mk_numeral(rational(0), m_util.is_int(arg)); return m_util.mk_numeral(rational(0), m_util.is_int(arg));
} }
@ -92,10 +92,10 @@ class factor_tactic : public tactic {
return k; return k;
} }
} }
// p1^{2*k1} * p2^{2*k2 + 1} >=< 0 // p1^{2*k1} * p2^{2*k2 + 1} >=< 0
// --> // -->
// (p1^2)*p2 >=<0 // (p1^2)*p2 >=<0
void mk_comp(decl_kind k, polynomial::factors const & fs, expr_ref & result) { void mk_comp(decl_kind k, polynomial::factors const & fs, expr_ref & result) {
SASSERT(k == OP_LT || k == OP_GT || k == OP_LE || k == OP_GE); SASSERT(k == OP_LT || k == OP_GT || k == OP_LE || k == OP_GE);
expr_ref_buffer args(m); expr_ref_buffer args(m);
@ -127,7 +127,7 @@ class factor_tactic : public tactic {
} }
} }
} }
// Strict case // Strict case
// p1^{2*k1} * p2^{2*k2 + 1} >< 0 // p1^{2*k1} * p2^{2*k2 + 1} >< 0
// --> // -->
@ -158,11 +158,11 @@ class factor_tactic : public tactic {
args.push_back(m.mk_app(m_util.get_family_id(), k, mk_mul(odd_factors.size(), odd_factors.c_ptr()), mk_zero_for(odd_factors[0]))); args.push_back(m.mk_app(m_util.get_family_id(), k, mk_mul(odd_factors.size(), odd_factors.c_ptr()), mk_zero_for(odd_factors[0])));
} }
SASSERT(!args.empty()); SASSERT(!args.empty());
if (args.size() == 1) if (args.size() == 1)
result = args[0]; result = args[0];
else if (strict) else if (strict)
result = m.mk_and(args.size(), args.c_ptr()); result = m.mk_and(args.size(), args.c_ptr());
else else
result = m.mk_or(args.size(), args.c_ptr()); result = m.mk_or(args.size(), args.c_ptr());
} }
@ -173,7 +173,7 @@ class factor_tactic : public tactic {
scoped_mpz d2(m_qm); scoped_mpz d2(m_qm);
m_expr2poly.to_polynomial(lhs, p1, d1); m_expr2poly.to_polynomial(lhs, p1, d1);
m_expr2poly.to_polynomial(rhs, p2, d2); m_expr2poly.to_polynomial(rhs, p2, d2);
TRACE("factor_tactic_bug", TRACE("factor_tactic_bug",
tout << "lhs: " << mk_ismt2_pp(lhs, m) << "\n"; tout << "lhs: " << mk_ismt2_pp(lhs, m) << "\n";
tout << "p1: " << p1 << "\n"; tout << "p1: " << p1 << "\n";
tout << "d1: " << d1 << "\n"; tout << "d1: " << d1 << "\n";
@ -195,18 +195,18 @@ class factor_tactic : public tactic {
SASSERT(fs.distinct_factors() > 0); SASSERT(fs.distinct_factors() > 0);
TRACE("factor_tactic_bug", tout << "factors:\n"; fs.display(tout); tout << "\n";); TRACE("factor_tactic_bug", tout << "factors:\n"; fs.display(tout); tout << "\n";);
if (fs.distinct_factors() == 1 && fs.get_degree(0) == 1) if (fs.distinct_factors() == 1 && fs.get_degree(0) == 1)
return BR_FAILED; return BR_FAILED;
if (m.is_eq(f)) { if (m.is_eq(f)) {
if (m_split_factors) if (m_split_factors)
mk_split_eq(fs, result); mk_split_eq(fs, result);
else else
mk_eq(fs, result); mk_eq(fs, result);
} }
else { else {
decl_kind k = f->get_decl_kind(); decl_kind k = f->get_decl_kind();
if (m_qm.is_neg(fs.get_constant())) if (m_qm.is_neg(fs.get_constant()))
k = flip(k); k = flip(k);
if (m_split_factors) if (m_split_factors)
mk_split_comp(k, fs, result); mk_split_comp(k, fs, result);
else else
@ -215,10 +215,10 @@ class factor_tactic : public tactic {
return BR_DONE; return BR_DONE;
} }
br_status reduce_app(func_decl * f, unsigned num, expr * const * args, expr_ref & result, proof_ref & result_pr) { br_status reduce_app(func_decl * f, unsigned num, expr * const * args, expr_ref & result, proof_ref & result_pr) {
if (num != 2) if (num != 2)
return BR_FAILED; return BR_FAILED;
if (m.is_eq(f) && (m_util.is_arith_expr(args[0]) || m_util.is_arith_expr(args[1]))) if (m.is_eq(f) && (m_util.is_arith_expr(args[0]) || m_util.is_arith_expr(args[1])) && (!m.is_bool(args[0])))
return factor(f, args[0], args[1], result); return factor(f, args[0], args[1], result);
if (f->get_family_id() != m_util.get_family_id()) if (f->get_family_id() != m_util.get_family_id())
return BR_FAILED; return BR_FAILED;
@ -232,10 +232,10 @@ class factor_tactic : public tactic {
return BR_FAILED; return BR_FAILED;
} }
}; };
struct rw : public rewriter_tpl<rw_cfg> { struct rw : public rewriter_tpl<rw_cfg> {
rw_cfg m_cfg; rw_cfg m_cfg;
rw(ast_manager & m, params_ref const & p): rw(ast_manager & m, params_ref const & p):
rewriter_tpl<rw_cfg>(m, m.proofs_enabled(), m_cfg), rewriter_tpl<rw_cfg>(m, m.proofs_enabled(), m_cfg),
m_cfg(m, p) { m_cfg(m, p) {
@ -245,24 +245,24 @@ class factor_tactic : public tactic {
struct imp { struct imp {
ast_manager & m; ast_manager & m;
rw m_rw; rw m_rw;
imp(ast_manager & _m, params_ref const & p): imp(ast_manager & _m, params_ref const & p):
m(_m), m(_m),
m_rw(m, p) { m_rw(m, p) {
} }
void set_cancel(bool f) { void set_cancel(bool f) {
m_rw.set_cancel(f); m_rw.set_cancel(f);
m_rw.cfg().m_pm.set_cancel(f); m_rw.cfg().m_pm.set_cancel(f);
} }
void updt_params(params_ref const & p) { void updt_params(params_ref const & p) {
m_rw.cfg().updt_params(p); m_rw.cfg().updt_params(p);
} }
void operator()(goal_ref const & g, void operator()(goal_ref const & g,
goal_ref_buffer & result, goal_ref_buffer & result,
model_converter_ref & mc, model_converter_ref & mc,
proof_converter_ref & pc, proof_converter_ref & pc,
expr_dependency_ref & core) { expr_dependency_ref & core) {
SASSERT(g->is_well_sorted()); SASSERT(g->is_well_sorted());
@ -288,7 +288,7 @@ class factor_tactic : public tactic {
SASSERT(g->is_well_sorted()); SASSERT(g->is_well_sorted());
} }
}; };
imp * m_imp; imp * m_imp;
params_ref m_params; params_ref m_params;
public: public:
@ -300,7 +300,7 @@ public:
virtual tactic * translate(ast_manager & m) { virtual tactic * translate(ast_manager & m) {
return alloc(factor_tactic, m, m_params); return alloc(factor_tactic, m, m_params);
} }
virtual ~factor_tactic() { virtual ~factor_tactic() {
dealloc(m_imp); dealloc(m_imp);
} }
@ -311,14 +311,14 @@ public:
} }
virtual void collect_param_descrs(param_descrs & r) { virtual void collect_param_descrs(param_descrs & r) {
r.insert("split_factors", CPK_BOOL, r.insert("split_factors", CPK_BOOL,
"(default: true) apply simplifications such as (= (* p1 p2) 0) --> (or (= p1 0) (= p2 0))."); "(default: true) apply simplifications such as (= (* p1 p2) 0) --> (or (= p1 0) (= p2 0)).");
polynomial::factor_params::get_param_descrs(r); polynomial::factor_params::get_param_descrs(r);
} }
virtual void operator()(goal_ref const & in, virtual void operator()(goal_ref const & in,
goal_ref_buffer & result, goal_ref_buffer & result,
model_converter_ref & mc, model_converter_ref & mc,
proof_converter_ref & pc, proof_converter_ref & pc,
expr_dependency_ref & core) { expr_dependency_ref & core) {
try { try {
@ -331,7 +331,7 @@ public:
throw tactic_exception(ex.msg()); throw tactic_exception(ex.msg());
} }
} }
virtual void cleanup() { virtual void cleanup() {
ast_manager & m = m_imp->m; ast_manager & m = m_imp->m;
imp * d = m_imp; imp * d = m_imp;

View file

@ -38,7 +38,6 @@ class elim_uncnstr_tactic : public tactic {
typedef std::pair<expr *, unsigned> frame; typedef std::pair<expr *, unsigned> frame;
svector<frame> m_stack; svector<frame> m_stack;
ptr_vector<app> m_vars; ptr_vector<app> m_vars;
expr_sparse_mark m_uncnstr_vars;
bool visit(expr * t) { bool visit(expr * t) {
if (m_visited.is_marked(t)) { if (m_visited.is_marked(t)) {

View file

@ -0,0 +1,620 @@
/*++
Copyright (c) 2012 Microsoft Corporation
Module Name:
sls_evaluator.h
Abstract:
SLS Evaluator
Author:
Christoph (cwinter) 2012-02-29
Notes:
--*/
#ifndef _SLS_EVALUATOR_H_
#define _SLS_EVALUATOR_H_
#include"sls_powers.h"
#include"sls_tracker.h"
class sls_evaluator {
ast_manager & m_manager;
bv_util & m_bv_util;
family_id m_basic_fid;
family_id m_bv_fid;
sls_tracker & m_tracker;
unsynch_mpz_manager & m_mpz_manager;
mpz m_zero, m_one, m_two;
powers & m_powers;
expr_ref_buffer m_temp_exprs;
vector<ptr_vector<expr> > m_traversal_stack;
public:
sls_evaluator(ast_manager & m, bv_util & bvu, sls_tracker & t, unsynch_mpz_manager & mm, powers & p) :
m_manager(m),
m_bv_util(bvu),
m_tracker(t),
m_mpz_manager(mm),
m_zero(m_mpz_manager.mk_z(0)),
m_one(m_mpz_manager.mk_z(1)),
m_two(m_mpz_manager.mk_z(2)),
m_powers(p),
m_temp_exprs(m) {
m_bv_fid = m_bv_util.get_family_id();
m_basic_fid = m_manager.get_basic_family_id();
}
~sls_evaluator() {
m_mpz_manager.del(m_zero);
m_mpz_manager.del(m_one);
m_mpz_manager.del(m_two);
}
void operator()(app * n, mpz & result) {
family_id nfid = n->get_family_id();
func_decl * fd = n->get_decl();
unsigned n_args = n->get_num_args();
if (n_args == 0) {
m_mpz_manager.set(result, m_tracker.get_value(n));
return;
}
expr * const * args = n->get_args();
m_mpz_manager.set(result, m_zero);
if (nfid == m_basic_fid) {
switch (n->get_decl_kind()) {
case OP_AND: {
m_mpz_manager.set(result, m_one);
for (unsigned i = 0; i < n_args; i++)
if (m_mpz_manager.neq(m_tracker.get_value(args[i]), result)) {
m_mpz_manager.set(result, m_zero);
break;
}
break;
}
case OP_OR: {
for (unsigned i = 0; i < n_args; i++)
if (m_mpz_manager.neq(m_tracker.get_value(args[i]), result)) {
m_mpz_manager.set(result, m_one);
break;
}
break;
}
case OP_NOT: {
SASSERT(n_args == 1);
const mpz & child = m_tracker.get_value(args[0]);
SASSERT(m_mpz_manager.is_one(child) || m_mpz_manager.is_zero(child));
m_mpz_manager.set(result, (m_mpz_manager.is_zero(child)) ? m_one : m_zero);
break;
}
case OP_EQ: {
SASSERT(n_args >= 2);
m_mpz_manager.set(result, m_one);
const mpz & first = m_tracker.get_value(args[0]);
for (unsigned i = 1; i < n_args; i++)
if (m_mpz_manager.neq(m_tracker.get_value(args[i]), first)) {
m_mpz_manager.set(result, m_zero);
break;
}
break;
}
case OP_DISTINCT: {
m_mpz_manager.set(result, m_one);
for (unsigned i = 0; i < n_args && m_mpz_manager.is_one(result); i++) {
for (unsigned j = i+1; j < n_args && m_mpz_manager.is_one(result); j++) {
if (m_mpz_manager.eq(m_tracker.get_value(args[i]), m_tracker.get_value(args[j])))
m_mpz_manager.set(result, m_zero);
}
}
break;
}
default:
NOT_IMPLEMENTED_YET();
}
}
else if (nfid == m_bv_fid) {
bv_op_kind k = static_cast<bv_op_kind>(fd->get_decl_kind());
switch(k) {
case OP_CONCAT: {
SASSERT(n_args >= 2);
for (unsigned i = 0; i < n_args; i++) {
if (i != 0) {
const mpz & p = m_powers(m_bv_util.get_bv_size(args[i]));
m_mpz_manager.mul(result, p, result);
}
m_mpz_manager.add(result, m_tracker.get_value(args[i]), result);
}
break;
}
case OP_EXTRACT: {
SASSERT(n_args == 1);
const mpz & child = m_tracker.get_value(args[0]);
unsigned h = m_bv_util.get_extract_high(n);
unsigned l = m_bv_util.get_extract_low(n);
m_mpz_manager.rem(child, m_powers(h+1), result); // result = [h:0] of child
m_mpz_manager.machine_div2k(result, l, result);
break;
}
case OP_BADD: {
SASSERT(n_args >= 2);
for (unsigned i = 0; i < n_args; i++) {
const mpz & next = m_tracker.get_value(args[i]);
m_mpz_manager.add(result, next, result);
}
const mpz & p = m_powers(m_bv_util.get_bv_size(n));
m_mpz_manager.rem(result, p, result);
break;
}
case OP_BSUB: {
SASSERT(n_args == 2);
const mpz & p = m_powers(m_bv_util.get_bv_size(n));
mpz temp;
m_mpz_manager.sub(m_tracker.get_value(args[0]), m_tracker.get_value(args[1]), temp);
m_mpz_manager.mod(temp, p, result);
m_mpz_manager.del(temp);
break;
}
case OP_BMUL: {
SASSERT(n_args >= 2);
m_mpz_manager.set(result, m_tracker.get_value(args[0]));
for (unsigned i = 1; i < n_args; i++) {
const mpz & next = m_tracker.get_value(args[i]);
m_mpz_manager.mul(result, next, result);
}
const mpz & p = m_powers(m_bv_util.get_bv_size(n));
m_mpz_manager.rem(result, p, result);
break;
}
case OP_BNEG: { // 2's complement unary minus
SASSERT(n_args == 1);
const mpz & child = m_tracker.get_value(args[0]);
if (m_mpz_manager.is_zero(child)) {
m_mpz_manager.set(result, m_zero);
}
else {
unsigned bv_sz = m_bv_util.get_bv_size(n);
m_mpz_manager.bitwise_not(bv_sz, child, result);
m_mpz_manager.inc(result); // can't overflow
}
break;
}
case OP_BSDIV:
case OP_BSDIV0:
case OP_BSDIV_I: {
SASSERT(n_args == 2);
mpz x; m_mpz_manager.set(x, m_tracker.get_value(args[0]));
mpz y; m_mpz_manager.set(y, m_tracker.get_value(args[1]));
SASSERT(m_mpz_manager.is_nonneg(x) && m_mpz_manager.is_nonneg(y));
unsigned bv_sz = m_bv_util.get_bv_size(args[0]);
const mpz & p = m_powers(bv_sz);
const mpz & p_half = m_powers(bv_sz-1);
if (x >= p_half) { m_mpz_manager.sub(x, p, x); }
if (y >= p_half) { m_mpz_manager.sub(y, p, y); }
if (m_mpz_manager.is_zero(y)) {
if (m_mpz_manager.is_neg(x))
m_mpz_manager.set(result, m_one);
else {
m_mpz_manager.set(result, m_powers(m_bv_util.get_bv_size(n)));
m_mpz_manager.dec(result);
}
}
else {
m_mpz_manager.machine_div(x, y, result);
}
if (m_mpz_manager.is_neg(result))
m_mpz_manager.add(result, p, result);
m_mpz_manager.del(x);
m_mpz_manager.del(y);
break;
}
case OP_BUDIV:
case OP_BUDIV0:
case OP_BUDIV_I: {
SASSERT(n_args == 2);
mpz x; m_mpz_manager.set(x, m_tracker.get_value(args[0]));
mpz y; m_mpz_manager.set(y, m_tracker.get_value(args[1]));
if (m_mpz_manager.is_zero(y)) {
m_mpz_manager.set(result, m_powers(m_bv_util.get_bv_size(n)));
m_mpz_manager.dec(result);
}
else {
m_mpz_manager.machine_div(x, y, result);
}
m_mpz_manager.del(x);
m_mpz_manager.del(y);
break;
}
case OP_BSREM:
case OP_BSREM0:
case OP_BSREM_I: {
SASSERT(n_args == 2);
mpz x; m_mpz_manager.set(x, m_tracker.get_value(args[0]));
mpz y; m_mpz_manager.set(y, m_tracker.get_value(args[1]));
unsigned bv_sz = m_bv_util.get_bv_size(args[0]);
const mpz & p = m_powers(bv_sz);
const mpz & p_half = m_powers(bv_sz-1);
if (x >= p_half) { m_mpz_manager.sub(x, p, x); }
if (y >= p_half) { m_mpz_manager.sub(y, p, y); }
if (m_mpz_manager.is_zero(y)) {
m_mpz_manager.set(result, x);
}
else {
m_mpz_manager.rem(x, y, result);
}
if (m_mpz_manager.is_neg(result))
m_mpz_manager.add(result, p, result);
m_mpz_manager.del(x);
m_mpz_manager.del(y);
break;
}
case OP_BUREM:
case OP_BUREM0:
case OP_BUREM_I: {
SASSERT(n_args == 2);
mpz x; m_mpz_manager.set(x, m_tracker.get_value(args[0]));
mpz y; m_mpz_manager.set(y, m_tracker.get_value(args[1]));
if (m_mpz_manager.is_zero(y)) {
m_mpz_manager.set(result, x);
}
else {
m_mpz_manager.mod(x, y, result);
}
m_mpz_manager.del(x);
m_mpz_manager.del(y);
break;
}
case OP_BSMOD:
case OP_BSMOD0:
case OP_BSMOD_I:{
SASSERT(n_args == 2);
mpz x; m_mpz_manager.set(x, m_tracker.get_value(args[0]));
mpz y; m_mpz_manager.set(y, m_tracker.get_value(args[1]));
unsigned bv_sz = m_bv_util.get_bv_size(args[0]);
const mpz & p = m_powers(bv_sz);
const mpz & p_half = m_powers(bv_sz-1);
if (x >= p_half) { m_mpz_manager.sub(x, p, x); }
if (y >= p_half) { m_mpz_manager.sub(y, p, y); }
if (m_mpz_manager.is_zero(y))
m_mpz_manager.set(result, x);
else {
bool neg_x = m_mpz_manager.is_neg(x);
bool neg_y = m_mpz_manager.is_neg(y);
mpz abs_x, abs_y;
m_mpz_manager.set(abs_x, x);
m_mpz_manager.set(abs_y, y);
if (neg_x) m_mpz_manager.neg(abs_x);
if (neg_y) m_mpz_manager.neg(abs_y);
SASSERT(m_mpz_manager.is_nonneg(abs_x) && m_mpz_manager.is_nonneg(abs_y));
m_mpz_manager.mod(abs_x, abs_y, result);
if (m_mpz_manager.is_zero(result) || (!neg_x && !neg_y)) {
/* Nothing */
}
else if (neg_x && !neg_y) {
m_mpz_manager.neg(result);
m_mpz_manager.add(result, y, result);
}
else if (!neg_x && neg_y) {
m_mpz_manager.add(result, y, result);
}
else {
m_mpz_manager.neg(result);
}
m_mpz_manager.del(abs_x);
m_mpz_manager.del(abs_y);
}
if (m_mpz_manager.is_neg(result))
m_mpz_manager.add(result, p, result);
m_mpz_manager.del(x);
m_mpz_manager.del(y);
break;
}
case OP_BAND: {
SASSERT(n_args >= 2);
m_mpz_manager.set(result, m_tracker.get_value(args[0]));
for (unsigned i = 1; i < n_args; i++)
m_mpz_manager.bitwise_and(result, m_tracker.get_value(args[i]), result);
break;
}
case OP_BOR: {
SASSERT(n_args >= 2);
m_mpz_manager.set(result, m_tracker.get_value(args[0]));
for (unsigned i = 1; i < n_args; i++) {
m_mpz_manager.bitwise_or(result, m_tracker.get_value(args[i]), result);
}
break;
}
case OP_BXOR: {
SASSERT(n_args >= 2);
m_mpz_manager.set(result, m_tracker.get_value(args[0]));
for (unsigned i = 1; i < n_args; i++)
m_mpz_manager.bitwise_xor(result, m_tracker.get_value(args[i]), result);
break;
}
case OP_BNAND: {
SASSERT(n_args >= 2);
mpz temp;
unsigned bv_sz = m_bv_util.get_bv_size(n);
m_mpz_manager.set(result, m_tracker.get_value(args[0]));
for (unsigned i = 1; i < n_args; i++) {
m_mpz_manager.bitwise_and(result, m_tracker.get_value(args[i]), temp);
m_mpz_manager.bitwise_not(bv_sz, temp, result);
}
m_mpz_manager.del(temp);
break;
}
case OP_BNOR: {
SASSERT(n_args >= 2);
mpz temp;
unsigned bv_sz = m_bv_util.get_bv_size(n);
m_mpz_manager.set(result, m_tracker.get_value(args[0]));
for (unsigned i = 1; i < n_args; i++) {
m_mpz_manager.bitwise_or(result, m_tracker.get_value(args[i]), temp);
m_mpz_manager.bitwise_not(bv_sz, temp, result);
}
m_mpz_manager.del(temp);
break;
}
case OP_BNOT: {
SASSERT(n_args == 1);
m_mpz_manager.bitwise_not(m_bv_util.get_bv_size(args[0]), m_tracker.get_value(args[0]), result);
break;
}
case OP_ULT:
case OP_ULEQ:
case OP_UGT:
case OP_UGEQ: {
SASSERT(n_args == 2);
const mpz & x = m_tracker.get_value(args[0]);
const mpz & y = m_tracker.get_value(args[1]);
if ((k == OP_ULT && m_mpz_manager.lt(x, y)) ||
(k == OP_ULEQ && m_mpz_manager.le(x, y)) ||
(k == OP_UGT && m_mpz_manager.gt(x, y)) ||
(k == OP_UGEQ && m_mpz_manager.ge(x, y)))
m_mpz_manager.set(result, m_one);
break;
}
case OP_SLT:
case OP_SLEQ:
case OP_SGT:
case OP_SGEQ: {
SASSERT(n_args == 2);
mpz x; m_mpz_manager.set(x, m_tracker.get_value(args[0]));
mpz y; m_mpz_manager.set(y, m_tracker.get_value(args[1]));
unsigned bv_sz = m_bv_util.get_bv_size(args[0]);
const mpz & p = m_powers(bv_sz);
const mpz & p_half = m_powers(bv_sz-1);
if (x >= p_half) { m_mpz_manager.sub(x, p, x); }
if (y >= p_half) { m_mpz_manager.sub(y, p, y); }
if ((k == OP_SLT && m_mpz_manager.lt(x, y)) ||
(k == OP_SLEQ && m_mpz_manager.le(x, y)) ||
(k == OP_SGT && m_mpz_manager.gt(x, y)) ||
(k == OP_SGEQ && m_mpz_manager.ge(x, y)))
m_mpz_manager.set(result, m_one);
m_mpz_manager.del(x);
m_mpz_manager.del(y);
break;
}
case OP_BIT2BOOL: {
SASSERT(n_args == 1);
const mpz & child = m_tracker.get_value(args[0]);
m_mpz_manager.set(result, child);
break;
}
case OP_BASHR: {
SASSERT(n_args == 2);
m_mpz_manager.set(result, m_tracker.get_value(args[0]));
mpz first;
const mpz & p = m_powers(m_bv_util.get_bv_size(args[0])-1);
m_mpz_manager.bitwise_and(result, p, first);
mpz shift; m_mpz_manager.set(shift, m_tracker.get_value(args[1]));
mpz temp;
while (!m_mpz_manager.is_zero(shift)) {
m_mpz_manager.machine_div(result, m_two, temp);
m_mpz_manager.add(temp, first, result);
m_mpz_manager.dec(shift);
}
m_mpz_manager.del(first);
m_mpz_manager.del(shift);
m_mpz_manager.del(temp);
break;
}
case OP_BLSHR: {
SASSERT(n_args == 2);
m_mpz_manager.set(result, m_tracker.get_value(args[0]));
mpz shift; m_mpz_manager.set(shift, m_tracker.get_value(args[1]));
while (!m_mpz_manager.is_zero(shift)) {
m_mpz_manager.machine_div(result, m_two, result);
m_mpz_manager.dec(shift);
}
m_mpz_manager.del(shift);
break;
}
case OP_BSHL: {
SASSERT(n_args == 2);
m_mpz_manager.set(result, m_tracker.get_value(args[0]));
mpz shift; m_mpz_manager.set(shift, m_tracker.get_value(args[1]));
while (!m_mpz_manager.is_zero(shift)) {
m_mpz_manager.mul(result, m_two, result);
m_mpz_manager.dec(shift);
}
const mpz & p = m_powers(m_bv_util.get_bv_size(n));
m_mpz_manager.rem(result, p, result);
m_mpz_manager.del(shift);
break;
}
case OP_SIGN_EXT: {
SASSERT(n_args == 1);
m_mpz_manager.set(result, m_tracker.get_value(args[0]));
break;
}
default:
NOT_IMPLEMENTED_YET();
}
}
else {
NOT_IMPLEMENTED_YET();
}
TRACE("sls_eval", tout << "(" << fd->get_name();
for (unsigned i = 0; i < n_args; i++)
tout << " " << m_mpz_manager.to_string(m_tracker.get_value(args[i]));
tout << ") ---> " << m_mpz_manager.to_string(result);
if (m_manager.is_bool(fd->get_range())) tout << " [Boolean]";
else tout << " [vector size: " << m_bv_util.get_bv_size(fd->get_range()) << "]";
tout << std::endl; );
SASSERT(m_mpz_manager.is_nonneg(result));
}
void eval_checked(expr * n, mpz & result) {
switch(n->get_kind()) {
case AST_APP: {
app * a = to_app(n);
(*this)(a, result);
unsigned n_args = a->get_num_args();
m_temp_exprs.reset();
for (unsigned i = 0; i < n_args; i++) {
expr * arg = a->get_arg(i);
const mpz & v = m_tracker.get_value(arg);
m_temp_exprs.push_back(m_tracker.mpz2value(m_manager.get_sort(arg), v));
}
expr_ref q(m_manager), temp(m_manager);
q = m_manager.mk_app(a->get_decl(), m_temp_exprs.size(), m_temp_exprs.c_ptr());
model dummy_model(m_manager);
model_evaluator evaluator(dummy_model);
evaluator(q, temp);
mpz check_res;
m_tracker.value2mpz(temp, check_res);
CTRACE("sls", !m_mpz_manager.eq(check_res, result),
tout << "EVAL BUG: IS " << m_mpz_manager.to_string(result) <<
" SHOULD BE " << m_mpz_manager.to_string(check_res) << std::endl; );
SASSERT(m_mpz_manager.eq(check_res, result));
m_mpz_manager.del(check_res);
break;
}
default:
NOT_IMPLEMENTED_YET();
}
}
void run_update(unsigned cur_depth) {
// precondition: m_traversal_stack contains the entry point(s)
expr_fast_mark1 visited;
mpz new_value;
SASSERT(cur_depth < m_traversal_stack.size());
while (cur_depth != static_cast<unsigned>(-1)) {
ptr_vector<expr> & cur_depth_exprs = m_traversal_stack[cur_depth];
for (unsigned i = 0; i < cur_depth_exprs.size(); i++) {
expr * cur = cur_depth_exprs[i];
(*this)(to_app(cur), new_value);
m_tracker.set_value(cur, new_value);
m_tracker.set_score(cur, m_tracker.score(cur));
if (m_tracker.has_uplinks(cur)) {
ptr_vector<expr> & ups = m_tracker.get_uplinks(cur);
for (unsigned j = 0; j < ups.size(); j++) {
expr * next = ups[j];
unsigned next_d = m_tracker.get_distance(next);
SASSERT(next_d < cur_depth);
if (!visited.is_marked(next)) {
m_traversal_stack[next_d].push_back(next);
visited.mark(next);
}
}
}
}
cur_depth_exprs.reset();
cur_depth--;
}
m_mpz_manager.del(new_value);
}
void update_all() {
unsigned max_depth = 0;
sls_tracker::entry_point_type::iterator start = m_tracker.get_entry_points().begin();
sls_tracker::entry_point_type::iterator end = m_tracker.get_entry_points().end();
for (sls_tracker::entry_point_type::iterator it = start; it != end; it++) {
expr * ep = m_tracker.get_entry_point(it->m_key);
unsigned cur_depth = m_tracker.get_distance(ep);
if (m_traversal_stack.size() <= cur_depth)
m_traversal_stack.resize(cur_depth+1);
m_traversal_stack[cur_depth].push_back(ep);
if (cur_depth > max_depth) max_depth = cur_depth;
}
run_update(max_depth);
}
void update(func_decl * fd, const mpz & new_value) {
m_tracker.set_value(fd, new_value);
expr * ep = m_tracker.get_entry_point(fd);
unsigned cur_depth = m_tracker.get_distance(ep);
if (m_traversal_stack.size() <= cur_depth)
m_traversal_stack.resize(cur_depth+1);
m_traversal_stack[cur_depth].push_back(ep);
run_update(cur_depth);
}
void randomize_local(goal_ref const & g) {
ptr_vector<func_decl> & unsat_constants = m_tracker.get_unsat_constants(g);
// Randomize _all_ candidates:
//// bool did_something = false;
//for (unsigned i = 0; i < unsat_constants.size(); i++) {
// func_decl * fd = unsat_constants[i];
// mpz temp = m_tracker.get_random(fd->get_range());
// // if (m_mpz_manager.neq(temp, m_tracker.get_value(fd))) {
// // did_something = true;
// // }
// update(fd, temp);
// m_mpz_manager.del(temp);
//}
// Randomize _one_ candidate:
unsigned r = m_tracker.get_random_uint(16) % unsat_constants.size();
func_decl * fd = unsat_constants[r];
mpz temp = m_tracker.get_random(fd->get_range());
update(fd, temp);
m_mpz_manager.del(temp);
TRACE("sls", /*tout << "Randomization candidates: ";
for (unsigned i = 0; i < unsat_constants.size(); i++)
tout << unsat_constants[i]->get_name() << ", ";
tout << std::endl;*/
tout << "Randomization candidate: " << unsat_constants[r]->get_name() << std::endl;
tout << "Locally randomized model: " << std::endl;
m_tracker.show_model(tout); );
}
};
#endif

View file

@ -0,0 +1,8 @@
def_module_params('sls',
export=True,
description='Experimental Stochastic Local Search Solver (for QFBV only).',
params=(max_memory_param(),
('restarts', UINT, UINT_MAX, '(max) number of restarts'),
('plateau_limit', UINT, 10, 'pleateau limit'),
('random_seed', UINT, 0, 'random seed')
))

View file

@ -0,0 +1,49 @@
/*++
Copyright (c) 2012 Microsoft Corporation
Module Name:
sls_powers.h
Abstract:
Power-of-2 module for SLS
Author:
Christoph (cwinter) 2012-02-29
Notes:
--*/
#ifndef _SLS_POWERS_H_
#define _SLS_POWERS_H_
#include"mpz.h"
class powers : public u_map<mpz*> {
unsynch_mpz_manager & m;
public:
powers(unsynch_mpz_manager & m) : m(m) {}
~powers() {
for (iterator it = begin(); it != end(); it++) {
m.del(*it->m_value);
dealloc(it->m_value);
}
}
const mpz & operator()(unsigned n) {
u_map<mpz*>::iterator it = find_iterator(n);
if (it != end())
return *it->m_value;
else {
mpz * new_obj = alloc(mpz);
m.mul2k(m.mk_z(1), n, *new_obj);
insert(n, new_obj);
return *new_obj;
}
}
};
#endif

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,675 @@
/*++
Copyright (c) 2012 Microsoft Corporation
Module Name:
sls_score_tracker.h
Abstract:
Score and value tracking module for SLS
Author:
Christoph (cwinter) 2012-02-29
Notes:
--*/
#ifndef _SLS_TRACKER_H_
#define _SLS_TRACKER_H_
class sls_tracker {
ast_manager & m_manager;
unsynch_mpz_manager & m_mpz_manager;
bv_util & m_bv_util;
powers & m_powers;
random_gen m_rng;
unsigned m_random_bits;
unsigned m_random_bits_cnt;
mpz m_zero, m_one, m_two;
struct value_score {
value_score() : m(0), value(unsynch_mpz_manager::mk_z(0)), score(0.0), distance(0) { };
~value_score() { if (m) m->del(value); }
unsynch_mpz_manager * m;
mpz value;
double score;
unsigned distance; // max distance from any root
value_score & operator=(const value_score & other) {
SASSERT(m == 0 || m == other.m);
if (m) m->set(value, 0); else m = other.m;
m->set(value, other.value);
score = other.score;
distance = other.distance;
return *this;
}
};
public:
typedef obj_map<func_decl, expr* > entry_point_type;
private:
typedef obj_map<expr, value_score> scores_type;
typedef obj_map<expr, ptr_vector<expr> > uplinks_type;
typedef obj_map<expr, ptr_vector<func_decl> > occ_type;
scores_type m_scores;
uplinks_type m_uplinks;
entry_point_type m_entry_points;
ptr_vector<func_decl> m_constants;
ptr_vector<func_decl> m_temp_constants;
occ_type m_constants_occ;
public:
sls_tracker(ast_manager & m, bv_util & bvu, unsynch_mpz_manager & mm, powers & p) :
m_manager(m),
m_mpz_manager(mm),
m_bv_util(bvu),
m_powers(p),
m_random_bits_cnt(0),
m_zero(m_mpz_manager.mk_z(0)),
m_one(m_mpz_manager.mk_z(1)),
m_two(m_mpz_manager.mk_z(2)) {
}
~sls_tracker() {
m_mpz_manager.del(m_zero);
m_mpz_manager.del(m_one);
m_mpz_manager.del(m_two);
}
inline void set_value(expr * n, const mpz & r) {
SASSERT(m_scores.contains(n));
m_mpz_manager.set(m_scores.find(n).value, r);
}
inline void set_value(func_decl * fd, const mpz & r) {
SASSERT(m_entry_points.contains(fd));
expr * ep = get_entry_point(fd);
set_value(ep, r);
}
inline mpz & get_value(expr * n) {
SASSERT(m_scores.contains(n));
return m_scores.find(n).value;
}
inline mpz & get_value(func_decl * fd) {
SASSERT(m_entry_points.contains(fd));
expr * ep = get_entry_point(fd);
return get_value(ep);
}
inline void set_score(expr * n, double score) {
SASSERT(m_scores.contains(n));
m_scores.find(n).score = score;
}
inline void set_score(func_decl * fd, double score) {
SASSERT(m_entry_points.contains(fd));
expr * ep = get_entry_point(fd);
set_score(ep, score);
}
inline double & get_score(expr * n) {
SASSERT(m_scores.contains(n));
return m_scores.find(n).score;
}
inline double & get_score(func_decl * fd) {
SASSERT(m_entry_points.contains(fd));
expr * ep = get_entry_point(fd);
return get_score(ep);
}
inline unsigned get_distance(expr * n) {
SASSERT(m_scores.contains(n));
return m_scores.find(n).distance;
}
inline void set_distance(expr * n, unsigned d) {
SASSERT(m_scores.contains(n));
m_scores.find(n).distance = d;
}
inline expr * get_entry_point(func_decl * fd) {
SASSERT(m_entry_points.contains(fd));
return m_entry_points.find(fd);
}
inline entry_point_type const & get_entry_points() {
return m_entry_points;
}
inline bool has_uplinks(expr * n) {
return m_uplinks.contains(n);
}
inline ptr_vector<expr> & get_uplinks(expr * n) {
SASSERT(m_uplinks.contains(n));
return m_uplinks.find(n);
}
void initialize(app * n) {
// Build score table
if (!m_scores.contains(n)) {
value_score vs;
vs.m = & m_mpz_manager;
m_scores.insert(n, vs);
}
// Update uplinks
unsigned na = n->get_num_args();
for (unsigned i = 0; i < na; i++) {
expr * c = n->get_arg(i);
uplinks_type::obj_map_entry * entry = m_uplinks.insert_if_not_there2(c, ptr_vector<expr>());
entry->get_data().m_value.push_back(n);
}
func_decl * d = n->get_decl();
if (n->get_num_args() == 0) {
if (d->get_family_id() != null_family_id) {
// Interpreted constant
mpz t;
value2mpz(n, t);
set_value(n, t);
m_mpz_manager.del(t);
}
else {
// Uninterpreted constant
m_entry_points.insert_if_not_there(d, n);
m_constants.push_back(d);
}
}
}
struct init_proc {
ast_manager & m_manager;
sls_tracker & m_tracker;
init_proc(ast_manager & m, sls_tracker & tracker):
m_manager(m),
m_tracker(tracker) {
}
void operator()(var * n) {}
void operator()(quantifier * n) {}
void operator()(app * n) {
m_tracker.initialize(n);
}
};
struct find_func_decls_proc {
ast_manager & m_manager;
ptr_vector<func_decl> & m_occs;
find_func_decls_proc (ast_manager & m, ptr_vector<func_decl> & occs):
m_manager(m),
m_occs(occs) {
}
void operator()(var * n) {}
void operator()(quantifier * n) {}
void operator()(app * n) {
if (n->get_num_args() != 0)
return;
func_decl * d = n->get_decl();
if (d->get_family_id() != null_family_id)
return;
m_occs.push_back(d);
}
};
void calculate_expr_distances(goal_ref const & g) {
// precondition: m_scores is set up.
unsigned sz = g->size();
ptr_vector<app> stack;
for (unsigned i = 0; i < sz; i++)
stack.push_back(to_app(g->form(i)));
while (!stack.empty()) {
app * cur = stack.back();
stack.pop_back();
unsigned d = get_distance(cur);
for (unsigned i = 0; i < cur->get_num_args(); i++) {
app * child = to_app(cur->get_arg(i));
unsigned d_child = get_distance(child);
if (d >= d_child) {
set_distance(child, d+1);
stack.push_back(child);
}
}
}
}
void initialize(goal_ref const & g) {
init_proc proc(m_manager, *this);
expr_mark visited;
unsigned sz = g->size();
for (unsigned i = 0; i < sz; i++) {
expr * e = g->form(i);
for_each_expr(proc, visited, e);
}
visited.reset();
for (unsigned i = 0; i < sz; i++) {
expr * e = g->form(i);
ptr_vector<func_decl> t;
m_constants_occ.insert_if_not_there(e, t);
find_func_decls_proc ffd_proc(m_manager, m_constants_occ.find(e));
expr_fast_mark1 visited;
quick_for_each_expr(ffd_proc, visited, e);
}
calculate_expr_distances(g);
TRACE("sls", tout << "Initial model:" << std::endl; show_model(tout); );
}
void show_model(std::ostream & out) {
unsigned sz = get_num_constants();
for (unsigned i = 0; i < sz; i++) {
func_decl * fd = get_constant(i);
out << fd->get_name() << " = " << m_mpz_manager.to_string(get_value(fd)) << std::endl;
}
}
model_ref get_model() {
model_ref res = alloc(model, m_manager);
unsigned sz = get_num_constants();
for (unsigned i = 0; i < sz; i++) {
func_decl * fd = get_constant(i);
res->register_decl(fd, mpz2value(fd->get_range(), get_value(fd)));
}
return res;
}
unsigned get_num_constants() {
return m_constants.size();
}
ptr_vector<func_decl> & get_constants() {
return m_constants;
}
func_decl * get_constant(unsigned i) {
return m_constants[i];
}
void set_random_seed(unsigned s) {
m_rng.set_seed(s);
}
mpz get_random_bv(sort * s) {
SASSERT(m_bv_util.is_bv_sort(s));
unsigned bv_size = m_bv_util.get_bv_size(s);
mpz r; m_mpz_manager.set(r, 0);
mpz temp;
do
{
m_mpz_manager.mul(r, m_two, temp);
m_mpz_manager.add(temp, get_random_bool(), r);
} while (--bv_size > 0);
m_mpz_manager.del(temp);
return r;
}
mpz & get_random_bool() {
if (m_random_bits_cnt == 0) {
m_random_bits = m_rng();
m_random_bits_cnt = 15; // random_gen produces 15 bits of randomness.
}
bool val = (m_random_bits & 0x01) != 0;
m_random_bits = m_random_bits >> 1;
m_random_bits_cnt--;
return (val) ? m_one : m_zero;
}
unsigned get_random_uint(unsigned bits) {
if (m_random_bits_cnt == 0) {
m_random_bits = m_rng();
m_random_bits_cnt = 15; // random_gen produces 15 bits of randomness.
}
unsigned val = 0;
while (bits-- > 0) {
if ((m_random_bits & 0x01) != 0) val++;
val <<= 1;
m_random_bits >>= 1;
m_random_bits_cnt--;
if (m_random_bits_cnt == 0) {
m_random_bits = m_rng();
m_random_bits_cnt = 15; // random_gen produces 15 bits of randomness.
}
}
return val;
}
mpz get_random(sort * s) {
if (m_bv_util.is_bv_sort(s))
return get_random_bv(s);
else if (m_manager.is_bool(s))
return get_random_bool();
else
NOT_IMPLEMENTED_YET(); // This only works for bit-vectors for now.
}
void randomize() {
TRACE("sls", tout << "Abandoned model:" << std::endl; show_model(tout); );
for (entry_point_type::iterator it = m_entry_points.begin(); it != m_entry_points.end(); it++) {
func_decl * fd = it->m_key;
sort * s = fd->get_range();
mpz temp = get_random(s);
set_value(it->m_value, temp);
m_mpz_manager.del(temp);
}
TRACE("sls", tout << "Randomized model:" << std::endl; show_model(tout); );
}
#define _SCORE_AND_MIN
double score_bool(expr * n, bool negated = false) {
TRACE("sls_score", tout << ((negated)?"NEG ":"") << "BOOL: " << mk_ismt2_pp(n, m_manager) << std::endl; );
double res = 0.0;
if (is_uninterp_const(n)) {
const mpz & r = get_value(n);
if (negated)
res = (m_mpz_manager.is_one(r)) ? 0.0 : 1.0;
else
res = (m_mpz_manager.is_one(r)) ? 1.0 : 0.0;
}
else if (m_manager.is_and(n)) {
SASSERT(!negated);
app * a = to_app(n);
expr * const * args = a->get_args();
#ifdef _SCORE_AND_MIN
double min = 1.0;
for (unsigned i = 0; i < a->get_num_args(); i++) {
double cur = get_score(args[i]);
if (cur < min) min = cur;
}
res = min;
#else
double sum = 0.0;
for (unsigned i = 0; i < a->get_num_args(); i++)
sum += get_score(args[i]);
res = sum / (double) a->get_num_args();
#endif
}
else if (m_manager.is_or(n)) {
SASSERT(!negated);
app * a = to_app(n);
expr * const * args = a->get_args();
double max = 0.0;
for (unsigned i = 0; i < a->get_num_args(); i++) {
double cur = get_score(args[i]);
if (cur > max) max = cur;
}
res = max;
}
else if (m_manager.is_ite(n)) {
SASSERT(!negated);
app * a = to_app(n);
SASSERT(a->get_num_args() == 3);
const mpz & cond = get_value(a->get_arg(0));
double s_t = get_score(a->get_arg(1));
double s_f = get_score(a->get_arg(2));
res = (m_mpz_manager.is_one(cond)) ? s_t : s_f;
}
else if (m_manager.is_eq(n) || m_manager.is_iff(n)) {
app * a = to_app(n);
SASSERT(a->get_num_args() == 2);
expr * arg0 = a->get_arg(0);
expr * arg1 = a->get_arg(1);
const mpz & v0 = get_value(arg0);
const mpz & v1 = get_value(arg1);
if (negated) {
res = (m_mpz_manager.eq(v0, v1)) ? 0.0 : 1.0;
TRACE("sls_score", tout << "V0 = " << m_mpz_manager.to_string(v0) << " ; V1 = " <<
m_mpz_manager.to_string(v1) << std::endl; );
}
else if (m_manager.is_bool(arg0)) {
res = m_mpz_manager.eq(v0, v1) ? 1.0 : 0.0;
TRACE("sls_score", tout << "V0 = " << m_mpz_manager.to_string(v0) << " ; V1 = " <<
m_mpz_manager.to_string(v1) << std::endl; );
}
else if (m_bv_util.is_bv(arg0)) {
mpz diff, diff_m1;
m_mpz_manager.bitwise_xor(v0, v1, diff);
unsigned hamming_distance = 0;
unsigned bv_sz = m_bv_util.get_bv_size(arg0);
#if 1 // unweighted hamming distance
while (!m_mpz_manager.is_zero(diff)) {
//m_mpz_manager.set(diff_m1, diff);
//m_mpz_manager.dec(diff_m1);
//m_mpz_manager.bitwise_and(diff, diff_m1, diff);
//hamming_distance++;
if (!m_mpz_manager.is_even(diff)) {
hamming_distance++;
}
m_mpz_manager.machine_div(diff, m_two, diff);
}
res = 1.0 - (hamming_distance / (double) bv_sz);
#else
rational r(diff);
r /= m_powers(bv_sz);
double dbl = r.get_double();
res = (dbl < 0.0) ? 1.0 : (dbl > 1.0) ? 0.0 : 1.0 - dbl;
#endif
TRACE("sls_score", tout << "V0 = " << m_mpz_manager.to_string(v0) << " ; V1 = " <<
m_mpz_manager.to_string(v1) << " ; HD = " << hamming_distance <<
" ; SZ = " << bv_sz << std::endl; );
m_mpz_manager.del(diff);
m_mpz_manager.del(diff_m1);
}
else
NOT_IMPLEMENTED_YET();
}
else if (m_bv_util.is_bv_ule(n)) { // x <= y
app * a = to_app(n);
SASSERT(a->get_num_args() == 2);
const mpz & x = get_value(a->get_arg(0));
const mpz & y = get_value(a->get_arg(1));
unsigned bv_sz = m_bv_util.get_bv_size(a->get_decl()->get_domain()[0]);
if (negated) {
if (m_mpz_manager.gt(x, y))
res = 1.0;
else {
mpz diff;
m_mpz_manager.sub(y, x, diff);
m_mpz_manager.inc(diff);
rational n(diff);
n /= rational(m_powers(bv_sz));
double dbl = n.get_double();
// In extreme cases, n is 0.9999 but to_double returns something > 1.0
res = (dbl > 1.0) ? 0.0 : (dbl < 0.0) ? 1.0 : 1.0 - dbl;
m_mpz_manager.del(diff);
}
}
else {
if (m_mpz_manager.le(x, y))
res = 1.0;
else {
mpz diff;
m_mpz_manager.sub(x, y, diff);
rational n(diff);
n /= rational(m_powers(bv_sz));
double dbl = n.get_double();
res = (dbl > 1.0) ? 1.0 : (dbl < 0.0) ? 0.0 : dbl;
m_mpz_manager.del(diff);
}
}
TRACE("sls_score", tout << "x = " << m_mpz_manager.to_string(x) << " ; y = " <<
m_mpz_manager.to_string(y) << " ; SZ = " << bv_sz << std::endl; );
}
else if (m_bv_util.is_bv_sle(n)) { // x <= y
app * a = to_app(n);
SASSERT(a->get_num_args() == 2);
mpz x; m_mpz_manager.set(x, get_value(a->get_arg(0)));
mpz y; m_mpz_manager.set(y, get_value(a->get_arg(1)));
unsigned bv_sz = m_bv_util.get_bv_size(a->get_decl()->get_domain()[0]);
const mpz & p = m_powers(bv_sz);
const mpz & p_half = m_powers(bv_sz-1);
if (x >= p_half) { m_mpz_manager.sub(x, p, x); }
if (y >= p_half) { m_mpz_manager.sub(y, p, y); }
if (negated) {
if (x > y)
res = 1.0;
else {
mpz diff;
m_mpz_manager.sub(y, x, diff);
m_mpz_manager.inc(diff);
rational n(diff);
n /= p;
double dbl = n.get_double();
res = (dbl > 1.0) ? 0.0 : (dbl < 0.0) ? 1.0 : 1.0 - dbl;
m_mpz_manager.del(diff);
}
TRACE("sls_score", tout << "x = " << m_mpz_manager.to_string(x) << " ; y = " <<
m_mpz_manager.to_string(y) << " ; SZ = " << bv_sz << std::endl; );
}
else {
if (x <= y)
res = 1.0;
else {
mpz diff;
m_mpz_manager.sub(x, y, diff);
rational n(diff);
n /= p;
double dbl = n.get_double();
res = (dbl > 1.0) ? 1.0 : (dbl < 0.0) ? 0.0 : dbl;
m_mpz_manager.del(diff);
}
TRACE("sls_score", tout << "x = " << m_mpz_manager.to_string(x) << " ; y = " <<
m_mpz_manager.to_string(y) << " ; SZ = " << bv_sz << std::endl; );
}
m_mpz_manager.del(x);
m_mpz_manager.del(y);
}
else if (m_manager.is_not(n)) {
SASSERT(!negated);
app * a = to_app(n);
SASSERT(a->get_num_args() == 1);
expr * child = a->get_arg(0);
if (m_manager.is_and(child) || m_manager.is_or(child)) // Precondition: Assertion set is in NNF.
NOT_IMPLEMENTED_YET();
res = score_bool(child, true);
}
else if (m_manager.is_distinct(n)) {
app * a = to_app(n);
unsigned pairs = 0, distinct_pairs = 0;
unsigned sz = a->get_num_args();
for (unsigned i = 0; i < sz; i++) {
for (unsigned j = i+1; j < sz; j++) {
// pair i/j
const mpz & v0 = get_value(a->get_arg(0));
const mpz & v1 = get_value(a->get_arg(1));
pairs++;
if (v0 != v1)
distinct_pairs++;
}
}
res = (distinct_pairs/(double)pairs);
if (negated) res = 1.0 - res;
}
else
NOT_IMPLEMENTED_YET();
SASSERT(res >= 0.0 && res <= 1.0);
TRACE("sls_score", tout << "SCORE = " << res << std::endl; );
return res;
}
double score_bv(expr * n) {
return 0.0; // a bv-expr is always scored as 0.0; we won't use those scores.
}
void value2mpz(expr * n, mpz & result) {
m_mpz_manager.set(result, m_zero);
if (m_manager.is_bool(n)) {
m_mpz_manager.set(result, m_manager.is_true(n) ? m_one : m_zero);
}
else if (m_bv_util.is_bv(n)) {
unsigned bv_sz = m_bv_util.get_bv_size(n);
rational q;
if (!m_bv_util.is_numeral(n, q, bv_sz))
NOT_IMPLEMENTED_YET();
mpq temp = q.to_mpq();
SASSERT(m_mpz_manager.is_one(temp.denominator()));
m_mpz_manager.set(result, temp.numerator());
}
else
NOT_IMPLEMENTED_YET();
}
expr_ref mpz2value(sort * s, const mpz & r) {
expr_ref res(m_manager);
if (m_manager.is_bool(s))
res = (m_mpz_manager.is_zero(r)) ? m_manager.mk_false() : m_manager.mk_true();
else if (m_bv_util.is_bv_sort(s)) {
rational rat(r);
res = m_bv_util.mk_numeral(rat, s);
}
else
NOT_IMPLEMENTED_YET();
return res;
}
double score(expr * n) {
if (m_manager.is_bool(n))
return score_bool(n);
else if (m_bv_util.is_bv(n))
return score_bv(n);
else
NOT_IMPLEMENTED_YET();
}
ptr_vector<func_decl> & get_unsat_constants(goal_ref const & g) {
unsigned sz = g->size();
if (sz == 1) {
return get_constants();
}
else {
m_temp_constants.reset();
for (unsigned i = 0; i < sz; i++) {
expr * q = g->form(i);
if (m_mpz_manager.eq(get_value(q), m_one))
continue;
ptr_vector<func_decl> const & this_decls = m_constants_occ.find(q);
unsigned sz2 = this_decls.size();
for (unsigned j = 0; j < sz2; j++) {
func_decl * fd = this_decls[j];
if (!m_temp_constants.contains(fd))
m_temp_constants.push_back(fd);
}
}
return m_temp_constants;
}
}
};
#endif

View file

@ -43,6 +43,8 @@ tactic * mk_qfbv_tactic(ast_manager & m, params_ref const & p) {
simp2_p.set_bool("push_ite_bv", false); simp2_p.set_bool("push_ite_bv", false);
simp2_p.set_bool("local_ctx", true); simp2_p.set_bool("local_ctx", true);
simp2_p.set_uint("local_ctx_limit", 10000000); simp2_p.set_uint("local_ctx_limit", 10000000);
simp2_p.set_bool("flat", true); // required by som
simp2_p.set_bool("hoist_mul", false); // required by som
params_ref local_ctx_p = p; params_ref local_ctx_p = p;
local_ctx_p.set_bool("local_ctx", true); local_ctx_p.set_bool("local_ctx", true);

View file

@ -0,0 +1,56 @@
#include "expr_substitution.h"
#include "smt_params.h"
#include "substitution.h"
#include "unifier.h"
#include "bv_decl_plugin.h"
#include "ast_pp.h"
#include "arith_decl_plugin.h"
#include "reg_decl_plugins.h"
#include "th_rewriter.h"
expr* mk_bv_xor(bv_util& bv, expr* a, expr* b) {
expr* args[2];
args[0] = a;
args[1] = b;
return bv.mk_bv_xor(2, args);
}
expr* mk_bv_and(bv_util& bv, expr* a, expr* b) {
expr* args[2];
args[0] = a;
args[1] = b;
ast_manager& m = bv.get_manager();
return m.mk_app(bv.get_family_id(), OP_BAND, 2, args);
}
void tst_expr_substitution() {
memory::initialize(0);
ast_manager m;
reg_decl_plugins(m);
bv_util bv(m);
expr_ref a(m), b(m), c(m), d(m);
expr_ref x(m);
expr_ref new_a(m);
proof_ref pr(m);
x = m.mk_const(symbol("x"), bv.mk_sort(8));
a = mk_bv_and(bv, mk_bv_xor(bv, x,bv.mk_numeral(8,8)), mk_bv_xor(bv,x,x));
b = x;
c = bv.mk_bv_sub(x, bv.mk_numeral(4, 8));
expr_substitution subst(m);
th_rewriter rw(m);
// normalizing c does not help.
rw(c, d, pr);
subst.insert(b, d);
rw.set_substitution(&subst);
enable_trace("th_rewriter_step");
rw(a, new_a, pr);
std::cout << mk_pp(new_a, m) << "\n";
}

View file

@ -215,6 +215,7 @@ int main(int argc, char ** argv) {
TST(rcf); TST(rcf);
TST(polynorm); TST(polynorm);
TST(qe_arith); TST(qe_arith);
TST(expr_substitution);
} }
void initialize_mam() {} void initialize_mam() {}