mirror of
https://github.com/Z3Prover/z3
synced 2025-06-06 22:23:22 +00:00
extend constant folding for bit-vector overflow/underflow operators, #657
Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
parent
41edf5f91e
commit
914bf2ff3b
10 changed files with 332 additions and 57 deletions
|
@ -522,7 +522,7 @@ void array_decl_plugin::get_sort_names(svector<builtin_name>& sort_names, symbol
|
||||||
void array_decl_plugin::get_op_names(svector<builtin_name>& op_names, symbol const & logic) {
|
void array_decl_plugin::get_op_names(svector<builtin_name>& op_names, symbol const & logic) {
|
||||||
op_names.push_back(builtin_name("store",OP_STORE));
|
op_names.push_back(builtin_name("store",OP_STORE));
|
||||||
op_names.push_back(builtin_name("select",OP_SELECT));
|
op_names.push_back(builtin_name("select",OP_SELECT));
|
||||||
if (logic == symbol::null) {
|
if (true || logic == symbol::null) {
|
||||||
// none of the SMT2 logics support these extensions
|
// none of the SMT2 logics support these extensions
|
||||||
op_names.push_back(builtin_name("const",OP_CONST_ARRAY));
|
op_names.push_back(builtin_name("const",OP_CONST_ARRAY));
|
||||||
op_names.push_back(builtin_name("map",OP_ARRAY_MAP));
|
op_names.push_back(builtin_name("map",OP_ARRAY_MAP));
|
||||||
|
|
|
@ -20,8 +20,8 @@ Revision History:
|
||||||
#define BIT_BLASTER_H_
|
#define BIT_BLASTER_H_
|
||||||
|
|
||||||
#include"bool_rewriter.h"
|
#include"bool_rewriter.h"
|
||||||
#include"bit_blaster_params.h"
|
#include"bit_blaster/bit_blaster_params.h"
|
||||||
#include"bit_blaster_tpl.h"
|
#include"bit_blaster/bit_blaster_tpl.h"
|
||||||
#include"bv_decl_plugin.h"
|
#include"bv_decl_plugin.h"
|
||||||
#include"rational.h"
|
#include"rational.h"
|
||||||
|
|
||||||
|
|
|
@ -20,6 +20,7 @@ Notes:
|
||||||
#include"bv_rewriter_params.hpp"
|
#include"bv_rewriter_params.hpp"
|
||||||
#include"poly_rewriter_def.h"
|
#include"poly_rewriter_def.h"
|
||||||
#include"ast_smt2_pp.h"
|
#include"ast_smt2_pp.h"
|
||||||
|
#include"bit_blaster/bit_blaster.h"
|
||||||
|
|
||||||
|
|
||||||
void bv_rewriter::updt_local_params(params_ref const & _p) {
|
void bv_rewriter::updt_local_params(params_ref const & _p) {
|
||||||
|
@ -189,6 +190,15 @@ br_status bv_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * cons
|
||||||
return mk_bv_comp(args[0], args[1], result);
|
return mk_bv_comp(args[0], args[1], result);
|
||||||
case OP_MKBV:
|
case OP_MKBV:
|
||||||
return mk_mkbv(num_args, args, result);
|
return mk_mkbv(num_args, args, result);
|
||||||
|
case OP_BUMUL_NO_OVFL:
|
||||||
|
SASSERT(num_args == 2);
|
||||||
|
return mk_bv_umul_no_ovfl(args[0], args[1], result);
|
||||||
|
case OP_BSMUL_NO_OVFL:
|
||||||
|
SASSERT(num_args == 2);
|
||||||
|
return mk_bv_smul_no_ovfl(args[0], args[1], result);
|
||||||
|
case OP_BSMUL_NO_UDFL:
|
||||||
|
SASSERT(num_args == 2);
|
||||||
|
return mk_bv_smul_no_udfl(args[0], args[1], result);
|
||||||
default:
|
default:
|
||||||
return BR_FAILED;
|
return BR_FAILED;
|
||||||
}
|
}
|
||||||
|
@ -1100,6 +1110,92 @@ br_status bv_rewriter::mk_concat(unsigned num_args, expr * const * args, expr_re
|
||||||
return BR_DONE;
|
return BR_DONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
br_status bv_rewriter::mk_bv_umul_no_ovfl(expr * arg1, expr * arg2, expr_ref& result) {
|
||||||
|
rational val1, val2;
|
||||||
|
unsigned bv_size;
|
||||||
|
bool is_num1 = is_numeral(arg1, val1, bv_size);
|
||||||
|
bool is_num2 = is_numeral(arg2, val2, bv_size);
|
||||||
|
if (is_num1 && (val1.is_zero() || val1.is_one())) {
|
||||||
|
result = m().mk_true();
|
||||||
|
return BR_DONE;
|
||||||
|
}
|
||||||
|
if (is_num2 && (val2.is_zero() || val2.is_one())) {
|
||||||
|
result = m().mk_true();
|
||||||
|
return BR_DONE;
|
||||||
|
}
|
||||||
|
if (is_num1 && is_num2) {
|
||||||
|
SASSERT(!val1.is_neg());
|
||||||
|
SASSERT(!val2.is_neg());
|
||||||
|
rational r = val1 * val2;
|
||||||
|
result = m().mk_bool_val(r < rational(2).expt(bv_size));
|
||||||
|
return BR_DONE;
|
||||||
|
}
|
||||||
|
return BR_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
br_status bv_rewriter::mk_bv_smul_no_ovfl(expr * arg1, expr * arg2, expr_ref& result) {
|
||||||
|
rational val1, val2;
|
||||||
|
unsigned bv_size;
|
||||||
|
bool is_num1 = is_numeral(arg1, val1, bv_size);
|
||||||
|
bool is_num2 = is_numeral(arg2, val2, bv_size);
|
||||||
|
if (is_num1 && (val1.is_zero() || val1.is_one())) {
|
||||||
|
result = m().mk_true();
|
||||||
|
return BR_DONE;
|
||||||
|
}
|
||||||
|
if (is_num2 && (val2.is_zero() || val2.is_one())) {
|
||||||
|
result = m().mk_true();
|
||||||
|
return BR_DONE;
|
||||||
|
}
|
||||||
|
if (is_num1 && is_num2) {
|
||||||
|
bit_blaster_params params;
|
||||||
|
bit_blaster blaster(m(), params);
|
||||||
|
SASSERT(!val1.is_neg());
|
||||||
|
SASSERT(!val2.is_neg());
|
||||||
|
expr_ref_vector bits1(m()), bits2(m());
|
||||||
|
for (unsigned i = 0; i < bv_size; ++i) {
|
||||||
|
bits1.push_back(m().mk_bool_val(!val1.is_even()));
|
||||||
|
bits2.push_back(m().mk_bool_val(!val2.is_even()));
|
||||||
|
val1 = div(val1, rational(2));
|
||||||
|
val2 = div(val2, rational(2));
|
||||||
|
}
|
||||||
|
blaster.mk_smul_no_overflow(bits1.size(), bits1.c_ptr(), bits2.c_ptr(), result);
|
||||||
|
return BR_DONE;
|
||||||
|
}
|
||||||
|
return BR_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
br_status bv_rewriter::mk_bv_smul_no_udfl(expr * arg1, expr * arg2, expr_ref& result) {
|
||||||
|
rational val1, val2;
|
||||||
|
unsigned bv_size;
|
||||||
|
bool is_num1 = is_numeral(arg1, val1, bv_size);
|
||||||
|
bool is_num2 = is_numeral(arg2, val2, bv_size);
|
||||||
|
if (is_num1 && (val1.is_zero() || val1.is_one())) {
|
||||||
|
result = m().mk_true();
|
||||||
|
return BR_DONE;
|
||||||
|
}
|
||||||
|
if (is_num2 && (val2.is_zero() || val2.is_one())) {
|
||||||
|
result = m().mk_true();
|
||||||
|
return BR_DONE;
|
||||||
|
}
|
||||||
|
if (is_num1 && is_num2) {
|
||||||
|
bit_blaster_params params;
|
||||||
|
bit_blaster blaster(m(), params);
|
||||||
|
SASSERT(!val1.is_neg());
|
||||||
|
SASSERT(!val2.is_neg());
|
||||||
|
expr_ref_vector bits1(m()), bits2(m());
|
||||||
|
for (unsigned i = 0; i < bv_size; ++i) {
|
||||||
|
bits1.push_back(m().mk_bool_val(!val1.is_even()));
|
||||||
|
bits2.push_back(m().mk_bool_val(!val2.is_even()));
|
||||||
|
val1 = div(val1, rational(2));
|
||||||
|
val2 = div(val2, rational(2));
|
||||||
|
}
|
||||||
|
blaster.mk_smul_no_underflow(bits1.size(), bits1.c_ptr(), bits2.c_ptr(), result);
|
||||||
|
return BR_DONE;
|
||||||
|
}
|
||||||
|
return BR_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
br_status bv_rewriter::mk_zero_extend(unsigned n, expr * arg, expr_ref & result) {
|
br_status bv_rewriter::mk_zero_extend(unsigned n, expr * arg, expr_ref & result) {
|
||||||
if (n == 0) {
|
if (n == 0) {
|
||||||
result = arg;
|
result = arg;
|
||||||
|
|
|
@ -114,6 +114,9 @@ class bv_rewriter : public poly_rewriter<bv_rewriter_core> {
|
||||||
br_status mk_bv_srem_i(expr * arg1, expr * arg2, expr_ref & result) { return mk_bv_srem_core(arg1, arg2, true, result); }
|
br_status mk_bv_srem_i(expr * arg1, expr * arg2, expr_ref & result) { return mk_bv_srem_core(arg1, arg2, true, result); }
|
||||||
br_status mk_bv_urem_i(expr * arg1, expr * arg2, expr_ref & result) { return mk_bv_urem_core(arg1, arg2, true, result); }
|
br_status mk_bv_urem_i(expr * arg1, expr * arg2, expr_ref & result) { return mk_bv_urem_core(arg1, arg2, true, result); }
|
||||||
br_status mk_bv_smod_i(expr * arg1, expr * arg2, expr_ref & result) { return mk_bv_smod_core(arg1, arg2, true, result); }
|
br_status mk_bv_smod_i(expr * arg1, expr * arg2, expr_ref & result) { return mk_bv_smod_core(arg1, arg2, true, result); }
|
||||||
|
br_status mk_bv_umul_no_ovfl(expr * arg1, expr * arg2, expr_ref& result);
|
||||||
|
br_status mk_bv_smul_no_ovfl(expr * arg1, expr * arg2, expr_ref& result);
|
||||||
|
br_status mk_bv_smul_no_udfl(expr * arg1, expr * arg2, expr_ref& result);
|
||||||
br_status mk_int2bv(unsigned bv_size, expr * arg, expr_ref & result);
|
br_status mk_int2bv(unsigned bv_size, expr * arg, expr_ref & result);
|
||||||
br_status mk_bv2int(expr * arg, expr_ref & result);
|
br_status mk_bv2int(expr * arg, expr_ref & result);
|
||||||
br_status mk_bv_redor(expr * arg, expr_ref & result);
|
br_status mk_bv_redor(expr * arg, expr_ref & result);
|
||||||
|
|
|
@ -61,5 +61,6 @@ def_module_params(module_name='smt',
|
||||||
('dack.gc', UINT, 2000, 'Dynamic ackermannization garbage collection frequency (per conflict)'),
|
('dack.gc', UINT, 2000, 'Dynamic ackermannization garbage collection frequency (per conflict)'),
|
||||||
('dack.gc_inv_decay', DOUBLE, 0.8, 'Dynamic ackermannization garbage collection decay'),
|
('dack.gc_inv_decay', DOUBLE, 0.8, 'Dynamic ackermannization garbage collection decay'),
|
||||||
('dack.threshold', UINT, 10, ' number of times the congruence rule must be used before Leibniz\'s axiom is expanded'),
|
('dack.threshold', UINT, 10, ' number of times the congruence rule must be used before Leibniz\'s axiom is expanded'),
|
||||||
('core.validate', BOOL, False, 'validate unsat core produced by SMT context')
|
('core.validate', BOOL, False, 'validate unsat core produced by SMT context'),
|
||||||
|
('core.minimize', BOOL, False, 'minimize unsat core produced by SMT context')
|
||||||
))
|
))
|
||||||
|
|
|
@ -20,19 +20,25 @@ Notes:
|
||||||
#include"smt_kernel.h"
|
#include"smt_kernel.h"
|
||||||
#include"reg_decl_plugins.h"
|
#include"reg_decl_plugins.h"
|
||||||
#include"smt_params.h"
|
#include"smt_params.h"
|
||||||
|
#include"smt_params_helper.hpp"
|
||||||
|
#include"mus.h"
|
||||||
|
|
||||||
namespace smt {
|
namespace smt {
|
||||||
|
|
||||||
class solver : public solver_na2as {
|
class solver : public solver_na2as {
|
||||||
smt_params m_params;
|
smt_params m_smt_params;
|
||||||
|
params_ref m_params;
|
||||||
smt::kernel m_context;
|
smt::kernel m_context;
|
||||||
progress_callback * m_callback;
|
progress_callback * m_callback;
|
||||||
symbol m_logic;
|
symbol m_logic;
|
||||||
|
bool m_minimizing_core;
|
||||||
public:
|
public:
|
||||||
solver(ast_manager & m, params_ref const & p, symbol const & l):
|
solver(ast_manager & m, params_ref const & p, symbol const & l):
|
||||||
solver_na2as(m),
|
solver_na2as(m),
|
||||||
|
m_smt_params(p),
|
||||||
m_params(p),
|
m_params(p),
|
||||||
m_context(m, m_params) {
|
m_context(m, m_smt_params),
|
||||||
|
m_minimizing_core(false) {
|
||||||
m_logic = l;
|
m_logic = l;
|
||||||
if (m_logic != symbol::null)
|
if (m_logic != symbol::null)
|
||||||
m_context.set_logic(m_logic);
|
m_context.set_logic(m_logic);
|
||||||
|
@ -48,7 +54,8 @@ namespace smt {
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void updt_params(params_ref const & p) {
|
virtual void updt_params(params_ref const & p) {
|
||||||
m_params.updt_params(p);
|
m_smt_params.updt_params(p);
|
||||||
|
m_params.copy(p);
|
||||||
m_context.updt_params(p);
|
m_context.updt_params(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -77,12 +84,42 @@ namespace smt {
|
||||||
return m_context.check(num_assumptions, assumptions);
|
return m_context.check(num_assumptions, assumptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct scoped_minimize_core {
|
||||||
|
solver& s;
|
||||||
|
expr_ref_vector m_assumptions;
|
||||||
|
scoped_minimize_core(solver& s): s(s), m_assumptions(s.m_assumptions) {
|
||||||
|
s.m_minimizing_core = true;
|
||||||
|
s.m_assumptions.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
~scoped_minimize_core() {
|
||||||
|
s.m_minimizing_core = false;
|
||||||
|
s.m_assumptions.append(m_assumptions);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
virtual void get_unsat_core(ptr_vector<expr> & r) {
|
virtual void get_unsat_core(ptr_vector<expr> & r) {
|
||||||
unsigned sz = m_context.get_unsat_core_size();
|
unsigned sz = m_context.get_unsat_core_size();
|
||||||
for (unsigned i = 0; i < sz; i++)
|
for (unsigned i = 0; i < sz; i++) {
|
||||||
r.push_back(m_context.get_unsat_core_expr(i));
|
r.push_back(m_context.get_unsat_core_expr(i));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (m_minimizing_core || smt_params_helper(m_params).core_minimize() == false) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
scoped_minimize_core scm(*this);
|
||||||
|
mus mus(*this);
|
||||||
|
|
||||||
|
for (unsigned i = 0; i < r.size(); ++i) {
|
||||||
|
VERIFY(i == mus.add_soft(r[i]));
|
||||||
|
}
|
||||||
|
ptr_vector<expr> r2;
|
||||||
|
if (l_true == mus.get_mus(r2)) {
|
||||||
|
r.reset();
|
||||||
|
r.append(r2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
virtual void get_model(model_ref & m) {
|
virtual void get_model(model_ref & m) {
|
||||||
m_context.get_model(m);
|
m_context.get_model(m);
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,6 +26,9 @@ Notes:
|
||||||
|
|
||||||
|
|
||||||
struct mus::imp {
|
struct mus::imp {
|
||||||
|
|
||||||
|
typedef obj_hashtable<expr> expr_set;
|
||||||
|
|
||||||
solver& m_solver;
|
solver& m_solver;
|
||||||
ast_manager& m;
|
ast_manager& m;
|
||||||
expr_ref_vector m_lit2expr;
|
expr_ref_vector m_lit2expr;
|
||||||
|
@ -65,65 +68,72 @@ struct mus::imp {
|
||||||
m_assumptions.push_back(lit);
|
m_assumptions.push_back(lit);
|
||||||
}
|
}
|
||||||
|
|
||||||
lbool get_mus(unsigned_vector& mus) {
|
lbool get_mus(ptr_vector<expr>& mus) {
|
||||||
// SASSERT: mus does not have duplicates.
|
unsigned_vector result;
|
||||||
m_model.reset();
|
lbool r = get_mus(result);
|
||||||
unsigned_vector core;
|
ids2exprs(mus, result);
|
||||||
for (unsigned i = 0; i < m_lit2expr.size(); ++i) {
|
return r;
|
||||||
core.push_back(i);
|
|
||||||
}
|
}
|
||||||
if (core.size() == 1) {
|
|
||||||
mus.push_back(core.back());
|
lbool get_mus(unsigned_vector& mus_ids) {
|
||||||
|
// SASSERT: mus_ids does not have duplicates.
|
||||||
|
m_model.reset();
|
||||||
|
mus_ids.reset();
|
||||||
|
|
||||||
|
if (m_lit2expr.size() == 1) {
|
||||||
|
mus_ids.push_back(0);
|
||||||
return l_true;
|
return l_true;
|
||||||
}
|
}
|
||||||
|
|
||||||
mus.reset();
|
return get_mus1(mus_ids);
|
||||||
if (false && core.size() > 64) {
|
|
||||||
return qx(mus);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
expr_ref_vector assumptions(m);
|
lbool get_mus1(unsigned_vector& mus_ids) {
|
||||||
|
expr_ref_vector mus(m);
|
||||||
|
lbool result = get_mus1(mus);
|
||||||
|
for (unsigned i = 0; i < mus.size(); ++i) {
|
||||||
|
mus_ids.push_back(m_expr2lit.find(mus[i].get()));
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
lbool get_mus1(expr_ref_vector& mus) {
|
||||||
|
ptr_vector<expr> unknown(m_lit2expr.size(), m_lit2expr.c_ptr());
|
||||||
ptr_vector<expr> core_exprs;
|
ptr_vector<expr> core_exprs;
|
||||||
while (!core.empty()) {
|
while (!unknown.empty()) {
|
||||||
IF_VERBOSE(12, verbose_stream() << "(opt.mus reducing core: " << core.size() << " new core: " << mus.size() << ")\n";);
|
IF_VERBOSE(12, verbose_stream() << "(opt.mus reducing core: " << unknown.size() << " new core: " << mus.size() << ")\n";);
|
||||||
unsigned lit_id = core.back();
|
TRACE("opt", display_vec(tout << "core: ", unknown); display_vec(tout << "mus: ", mus););
|
||||||
TRACE("opt",
|
expr* lit = unknown.back();
|
||||||
display_vec(tout << "core: ", core);
|
unknown.pop_back();
|
||||||
display_vec(tout << "mus: ", mus);
|
expr_ref not_lit(mk_not(m, lit), m);
|
||||||
);
|
|
||||||
core.pop_back();
|
|
||||||
expr* lit = m_lit2expr[lit_id].get();
|
|
||||||
expr_ref not_lit(m);
|
|
||||||
not_lit = mk_not(m, lit);
|
|
||||||
lbool is_sat = l_undef;
|
lbool is_sat = l_undef;
|
||||||
{
|
{
|
||||||
scoped_append _sa1(*this, assumptions, core);
|
scoped_append _sa1(*this, mus, unknown);
|
||||||
scoped_append _sa2(*this, assumptions, m_assumptions);
|
scoped_append _sa2(*this, mus, m_assumptions);
|
||||||
assumptions.push_back(not_lit);
|
mus.push_back(not_lit);
|
||||||
is_sat = m_solver.check_sat(assumptions);
|
is_sat = m_solver.check_sat(mus);
|
||||||
}
|
}
|
||||||
switch (is_sat) {
|
switch (is_sat) {
|
||||||
case l_undef:
|
case l_undef:
|
||||||
return is_sat;
|
return is_sat;
|
||||||
case l_true:
|
case l_true:
|
||||||
assumptions.push_back(lit);
|
mus.push_back(lit);
|
||||||
mus.push_back(lit_id);
|
|
||||||
update_model();
|
update_model();
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
core_exprs.reset();
|
core_exprs.reset();
|
||||||
m_solver.get_unsat_core(core_exprs);
|
m_solver.get_unsat_core(core_exprs);
|
||||||
if (!core_exprs.contains(not_lit)) {
|
if (!core_exprs.contains(not_lit)) {
|
||||||
// core := core_exprs \ mus
|
// unknown := core_exprs \ mus
|
||||||
core.reset();
|
unknown.reset();
|
||||||
for (unsigned i = 0; i < core_exprs.size(); ++i) {
|
for (unsigned i = 0; i < core_exprs.size(); ++i) {
|
||||||
lit = core_exprs[i];
|
if (!mus.contains(core_exprs[i])) {
|
||||||
if (m_expr2lit.find(lit, lit_id) && !mus.contains(lit_id)) {
|
unknown.push_back(core_exprs[i]);
|
||||||
core.push_back(lit_id);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
TRACE("opt", display_vec(tout << "core exprs:", core_exprs);
|
TRACE("opt", display_vec(tout << "core exprs:", core_exprs);
|
||||||
display_vec(tout << "core:", core);
|
display_vec(tout << "core:", unknown);
|
||||||
display_vec(tout << "mus:", mus);
|
display_vec(tout << "mus:", mus);
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -131,19 +141,118 @@ struct mus::imp {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#if 0
|
// SASSERT(is_core(mus));
|
||||||
DEBUG_CODE(
|
|
||||||
assumptions.reset();
|
|
||||||
for (unsigned i = 0; i < mus.size(); ++i) {
|
|
||||||
assumptions.push_back(m_lit2expr[mus[i]].get());
|
|
||||||
}
|
|
||||||
lbool is_sat = m_solver.check_sat(assumptions.size(), assumptions.c_ptr());
|
|
||||||
SASSERT(is_sat == l_false);
|
|
||||||
);
|
|
||||||
#endif
|
|
||||||
return l_true;
|
return l_true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// use correction sets
|
||||||
|
lbool get_mus2(expr_ref_vector& mus) {
|
||||||
|
scoped_append _sa1(*this, mus, m_assumptions);
|
||||||
|
ptr_vector<expr> unknown(m_lit2expr.size(), m_lit2expr.c_ptr());
|
||||||
|
while (!unknown.empty()) {
|
||||||
|
expr* lit;
|
||||||
|
lbool is_sat = get_next_mcs(mus, unknown, lit);
|
||||||
|
switch (is_sat) {
|
||||||
|
case l_undef:
|
||||||
|
return is_sat;
|
||||||
|
case l_false:
|
||||||
|
mus.push_back(lit);
|
||||||
|
break;
|
||||||
|
case l_true:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return l_true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// find the next literal to be a member of a core.
|
||||||
|
lbool get_next_mcs(expr_ref_vector& mus, ptr_vector<expr>& unknown, expr*& core_literal) {
|
||||||
|
ptr_vector<expr> mss, core, min_core;
|
||||||
|
bool min_core_valid = false;
|
||||||
|
expr* min_lit = 0;
|
||||||
|
while (!unknown.empty()) {
|
||||||
|
expr* lit = unknown.back();
|
||||||
|
unknown.pop_back();
|
||||||
|
model_ref mdl;
|
||||||
|
scoped_append assume_mss(*this, mus, mss);
|
||||||
|
scoped_append assume_lit(*this, mus, lit);
|
||||||
|
switch (m_solver.check_sat(mus)) {
|
||||||
|
case l_true:
|
||||||
|
mss.push_back(lit);
|
||||||
|
m_solver.get_model(mdl);
|
||||||
|
for (unsigned i = 0; i < unknown.size(); ) {
|
||||||
|
expr_ref tmp(m);
|
||||||
|
if (mdl->eval(unknown[i], tmp) && m.is_true(tmp)) {
|
||||||
|
mss.push_back(unknown[i]);
|
||||||
|
unknown[i] = unknown.back();
|
||||||
|
unknown.pop_back();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case l_false:
|
||||||
|
core.reset();
|
||||||
|
m_solver.get_unsat_core(core);
|
||||||
|
// ???
|
||||||
|
if (!core.contains(lit)) {
|
||||||
|
return l_false;
|
||||||
|
}
|
||||||
|
if (!min_core_valid || core.size() < min_core.size()) {
|
||||||
|
min_core.reset();
|
||||||
|
min_core.append(core);
|
||||||
|
min_core_valid = true;
|
||||||
|
min_lit = lit;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case l_undef:
|
||||||
|
return l_undef;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!min_core_valid) {
|
||||||
|
// ???
|
||||||
|
UNREACHABLE();
|
||||||
|
return l_true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
for (unsigned i = 0; i < min_core.size(); ++i) {
|
||||||
|
if (mss.contains(min_core[i]) && min_lit != min_core[i]) {
|
||||||
|
unknown.push_back(min_core[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
core_literal = min_lit;
|
||||||
|
}
|
||||||
|
return l_false;
|
||||||
|
}
|
||||||
|
|
||||||
|
expr* lit2expr(unsigned lit_id) const {
|
||||||
|
return m_lit2expr[lit_id];
|
||||||
|
}
|
||||||
|
|
||||||
|
void ids2exprs(ptr_vector<expr>& dst, unsigned_vector const& ids) const {
|
||||||
|
for (unsigned i = 0; i < ids.size(); ++i) {
|
||||||
|
dst.push_back(lit2expr(ids[i]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_core(unsigned_vector const& mus_ids) {
|
||||||
|
ptr_vector<expr> mus_exprs;
|
||||||
|
ids2exprs(mus_exprs, mus_ids);
|
||||||
|
return l_false == m_solver.check_sat(mus_exprs.size(), mus_exprs.c_ptr());
|
||||||
|
}
|
||||||
|
|
||||||
|
// dst := A \ B
|
||||||
|
void set_difference(unsigned_vector& dst, ptr_vector<expr> const& A, unsigned_vector const& B) {
|
||||||
|
dst.reset();
|
||||||
|
for (unsigned i = 0; i < A.size(); ++i) {
|
||||||
|
unsigned lit_id;
|
||||||
|
if (m_expr2lit.find(A[i], lit_id) && !B.contains(lit_id)) {
|
||||||
|
dst.push_back(lit_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class scoped_append {
|
class scoped_append {
|
||||||
expr_ref_vector& m_fmls;
|
expr_ref_vector& m_fmls;
|
||||||
unsigned m_size;
|
unsigned m_size;
|
||||||
|
@ -152,7 +261,7 @@ struct mus::imp {
|
||||||
m_fmls(fmls1),
|
m_fmls(fmls1),
|
||||||
m_size(fmls1.size()) {
|
m_size(fmls1.size()) {
|
||||||
for (unsigned i = 0; i < fmls2.size(); ++i) {
|
for (unsigned i = 0; i < fmls2.size(); ++i) {
|
||||||
fmls1.push_back(imp.m_lit2expr[fmls2[i]].get());
|
fmls1.push_back(imp.lit2expr(fmls2[i]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
scoped_append(imp& imp, expr_ref_vector& fmls1, uint_set const& fmls2):
|
scoped_append(imp& imp, expr_ref_vector& fmls1, uint_set const& fmls2):
|
||||||
|
@ -160,7 +269,7 @@ struct mus::imp {
|
||||||
m_size(fmls1.size()) {
|
m_size(fmls1.size()) {
|
||||||
uint_set::iterator it = fmls2.begin(), end = fmls2.end();
|
uint_set::iterator it = fmls2.begin(), end = fmls2.end();
|
||||||
for (; it != end; ++it) {
|
for (; it != end; ++it) {
|
||||||
fmls1.push_back(imp.m_lit2expr[*it].get());
|
fmls1.push_back(imp.lit2expr(*it));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
scoped_append(imp& imp, expr_ref_vector& fmls1, expr_ref_vector const& fmls2):
|
scoped_append(imp& imp, expr_ref_vector& fmls1, expr_ref_vector const& fmls2):
|
||||||
|
@ -168,6 +277,16 @@ struct mus::imp {
|
||||||
m_size(fmls1.size()) {
|
m_size(fmls1.size()) {
|
||||||
fmls1.append(fmls2);
|
fmls1.append(fmls2);
|
||||||
}
|
}
|
||||||
|
scoped_append(imp& imp, expr_ref_vector& fmls1, ptr_vector<expr> const& fmls2):
|
||||||
|
m_fmls(fmls1),
|
||||||
|
m_size(fmls1.size()) {
|
||||||
|
fmls1.append(fmls2.size(), fmls2.c_ptr());
|
||||||
|
}
|
||||||
|
scoped_append(imp& imp, expr_ref_vector& fmls1, expr* fml):
|
||||||
|
m_fmls(fmls1),
|
||||||
|
m_size(fmls1.size()) {
|
||||||
|
fmls1.push_back(fml);
|
||||||
|
}
|
||||||
~scoped_append() {
|
~scoped_append() {
|
||||||
m_fmls.shrink(m_size);
|
m_fmls.shrink(m_size);
|
||||||
}
|
}
|
||||||
|
@ -175,7 +294,7 @@ struct mus::imp {
|
||||||
|
|
||||||
void add_core(unsigned_vector const& core, expr_ref_vector& assumptions) {
|
void add_core(unsigned_vector const& core, expr_ref_vector& assumptions) {
|
||||||
for (unsigned i = 0; i < core.size(); ++i) {
|
for (unsigned i = 0; i < core.size(); ++i) {
|
||||||
assumptions.push_back(m_lit2expr[core[i]].get());
|
assumptions.push_back(lit2expr(core[i]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -359,6 +478,17 @@ lbool mus::get_mus(unsigned_vector& mus) {
|
||||||
return m_imp->get_mus(mus);
|
return m_imp->get_mus(mus);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
lbool mus::get_mus(ptr_vector<expr>& mus) {
|
||||||
|
return m_imp->get_mus(mus);
|
||||||
|
}
|
||||||
|
|
||||||
|
lbool mus::get_mus(expr_ref_vector& mus) {
|
||||||
|
ptr_vector<expr> result;
|
||||||
|
lbool r = m_imp->get_mus(result);
|
||||||
|
mus.append(result.size(), result.c_ptr());
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void mus::reset() {
|
void mus::reset() {
|
||||||
m_imp->reset();
|
m_imp->reset();
|
||||||
|
|
|
@ -45,6 +45,10 @@ class mus {
|
||||||
|
|
||||||
lbool get_mus(unsigned_vector& mus);
|
lbool get_mus(unsigned_vector& mus);
|
||||||
|
|
||||||
|
lbool get_mus(ptr_vector<expr>& mus);
|
||||||
|
|
||||||
|
lbool get_mus(expr_ref_vector& mus);
|
||||||
|
|
||||||
void reset();
|
void reset();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -25,6 +25,7 @@ Notes:
|
||||||
#include"solver.h"
|
#include"solver.h"
|
||||||
|
|
||||||
class solver_na2as : public solver {
|
class solver_na2as : public solver {
|
||||||
|
protected:
|
||||||
ast_manager & m;
|
ast_manager & m;
|
||||||
expr_ref_vector m_assumptions;
|
expr_ref_vector m_assumptions;
|
||||||
unsigned_vector m_scopes;
|
unsigned_vector m_scopes;
|
||||||
|
|
|
@ -23,6 +23,7 @@ Notes:
|
||||||
#include"tactic.h"
|
#include"tactic.h"
|
||||||
#include"ast_pp_util.h"
|
#include"ast_pp_util.h"
|
||||||
#include"ast_translation.h"
|
#include"ast_translation.h"
|
||||||
|
#include"mus.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
\brief Simulates the incremental solver interface using a tactic.
|
\brief Simulates the incremental solver interface using a tactic.
|
||||||
|
@ -42,6 +43,7 @@ class tactic2solver : public solver_na2as {
|
||||||
bool m_produce_proofs;
|
bool m_produce_proofs;
|
||||||
bool m_produce_unsat_cores;
|
bool m_produce_unsat_cores;
|
||||||
statistics m_stats;
|
statistics m_stats;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
tactic2solver(ast_manager & m, tactic * t, params_ref const & p, bool produce_proofs, bool produce_models, bool produce_unsat_cores, symbol const & logic);
|
tactic2solver(ast_manager & m, tactic * t, params_ref const & p, bool produce_proofs, bool produce_models, bool produce_unsat_cores, symbol const & logic);
|
||||||
virtual ~tactic2solver();
|
virtual ~tactic2solver();
|
||||||
|
@ -203,9 +205,10 @@ void tactic2solver::collect_statistics(statistics & st) const {
|
||||||
}
|
}
|
||||||
|
|
||||||
void tactic2solver::get_unsat_core(ptr_vector<expr> & r) {
|
void tactic2solver::get_unsat_core(ptr_vector<expr> & r) {
|
||||||
if (m_result.get())
|
if (m_result.get()) {
|
||||||
m_result->get_unsat_core(r);
|
m_result->get_unsat_core(r);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void tactic2solver::get_model(model_ref & m) {
|
void tactic2solver::get_model(model_ref & m) {
|
||||||
if (m_result.get())
|
if (m_result.get())
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue