3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-04-27 10:55:50 +00:00

merge with master

Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
Nikolaj Bjorner 2022-04-16 18:30:03 +02:00
commit 3533bf486f
223 changed files with 7175 additions and 2167 deletions

View file

@ -309,6 +309,22 @@ extern "C" {
Z3_CATCH_RETURN(nullptr);
}
Z3_sort Z3_API Z3_get_array_sort_domain_n(Z3_context c, Z3_sort t, unsigned idx) {
Z3_TRY;
LOG_Z3_get_array_sort_domain_n(c, t, idx);
RESET_ERROR_CODE();
CHECK_VALID_AST(t, nullptr);
if (to_sort(t)->get_family_id() == mk_c(c)->get_array_fid() &&
to_sort(t)->get_decl_kind() == ARRAY_SORT &&
get_array_arity(to_sort(t)) > idx) {
Z3_sort r = reinterpret_cast<Z3_sort>(get_array_domain(to_sort(t), idx));
RETURN_Z3(r);
}
SET_ERROR_CODE(Z3_INVALID_ARG, nullptr);
RETURN_Z3(nullptr);
Z3_CATCH_RETURN(nullptr);
}
Z3_sort Z3_API Z3_get_array_sort_range(Z3_context c, Z3_sort t) {
Z3_TRY;
LOG_Z3_get_array_sort_range(c, t);

View file

@ -164,7 +164,7 @@ extern "C" {
return;
}
recfun_replace replace(m);
p.set_definition(replace, pd, true, n, _vars.data(), abs_body);
p.set_definition(replace, pd, false, n, _vars.data(), abs_body);
Z3_CATCH;
}
@ -355,7 +355,7 @@ extern "C" {
return mk_c(c)->mk_external_string(buffer.str());
}
else {
return mk_c(c)->mk_external_string(_s.bare_str());
return mk_c(c)->mk_external_string(_s.str());
}
Z3_CATCH_RETURN("");
}
@ -1224,15 +1224,21 @@ extern "C" {
case OP_RE_PLUS: return Z3_OP_RE_PLUS;
case OP_RE_STAR: return Z3_OP_RE_STAR;
case OP_RE_OPTION: return Z3_OP_RE_OPTION;
case OP_RE_RANGE: return Z3_OP_RE_RANGE;
case OP_RE_CONCAT: return Z3_OP_RE_CONCAT;
case OP_RE_UNION: return Z3_OP_RE_UNION;
case OP_RE_DIFF: return Z3_OP_RE_DIFF;
case OP_RE_POWER: return Z3_OP_RE_POWER;
case OP_RE_INTERSECT: return Z3_OP_RE_INTERSECT;
case OP_RE_LOOP: return Z3_OP_RE_LOOP;
case OP_RE_FULL_SEQ_SET: return Z3_OP_RE_FULL_SET;
//case OP_RE_FULL_CHAR_SET: return Z3_OP_RE_FULL_SET;
case OP_RE_POWER: return Z3_OP_RE_POWER;
case OP_RE_COMPLEMENT: return Z3_OP_RE_COMPLEMENT;
case OP_RE_EMPTY_SET: return Z3_OP_RE_EMPTY_SET;
case OP_RE_FULL_SEQ_SET: return Z3_OP_RE_FULL_SET;
case OP_RE_FULL_CHAR_SET: return Z3_OP_RE_FULL_CHAR_SET;
case OP_RE_OF_PRED: return Z3_OP_RE_OF_PRED;
case OP_RE_REVERSE: return Z3_OP_RE_REVERSE;
case OP_RE_DERIVATIVE: return Z3_OP_RE_DERIVATIVE;
default:
return Z3_OP_INTERNAL;
}
@ -1323,6 +1329,9 @@ extern "C" {
}
}
if (mk_c(c)->recfun().get_family_id() == _d->get_family_id())
return Z3_OP_RECURSIVE;
return Z3_OP_UNINTERPRETED;
Z3_CATCH_RETURN(Z3_OP_UNINTERPRETED);
}

View file

@ -88,7 +88,7 @@ void Sy(Z3_symbol sym) {
*g_z3_log << "# " << s.get_num();
}
else {
*g_z3_log << "$ |" << ll_escaped{s.bare_str()} << '|';
*g_z3_log << "$ |" << ll_escaped{s.str().c_str()} << '|';
}
*g_z3_log << std::endl;
}

View file

@ -315,6 +315,17 @@ extern "C" {
Z3_CATCH_RETURN(nullptr);
}
Z3_ast Z3_API Z3_mk_re_power(Z3_context c, Z3_ast r, unsigned n) {
Z3_TRY;
LOG_Z3_mk_re_power(c, r, n);
RESET_ERROR_CODE();
app* a = mk_c(c)->sutil().re.mk_power(to_expr(r), n);
mk_c(c)->save_ast_trail(a);
RETURN_Z3(of_ast(a));
Z3_CATCH_RETURN(nullptr);
}
MK_UNARY(Z3_mk_re_plus, mk_c(c)->get_seq_fid(), OP_RE_PLUS, SKIP);
MK_UNARY(Z3_mk_re_star, mk_c(c)->get_seq_fid(), OP_RE_STAR, SKIP);
MK_UNARY(Z3_mk_re_option, mk_c(c)->get_seq_fid(), OP_RE_OPTION, SKIP);

View file

@ -114,7 +114,7 @@ extern "C" {
}
solver2smt2_pp::solver2smt2_pp(ast_manager& m, const std::string& file):
m_pp_util(m), m_out(file), m_tracked(m) {
m_pp_util(m), m_out(file, std::ofstream::trunc | std::ofstream::out), m_tracked(m) {
if (!m_out) {
throw default_exception("could not open " + file + " for output");
}
@ -564,7 +564,7 @@ extern "C" {
init_solver(c, s);
Z3_ast_vector_ref * v = alloc(Z3_ast_vector_ref, *mk_c(c), mk_c(c)->m());
mk_c(c)->save_object(v);
expr_ref_vector trail = to_solver_ref(s)->get_trail();
expr_ref_vector trail = to_solver_ref(s)->get_trail(UINT_MAX);
for (expr* f : trail) {
v->m_ast_vector.push_back(f);
}
@ -883,8 +883,8 @@ extern "C" {
Z3_TRY;
RESET_ERROR_CODE();
init_solver(c, s);
user_propagator::push_eh_t _push = push_eh;
user_propagator::pop_eh_t _pop = pop_eh;
user_propagator::push_eh_t _push = (void(*)(void*,user_propagator::callback*)) push_eh;
user_propagator::pop_eh_t _pop = (void(*)(void*,user_propagator::callback*,unsigned)) pop_eh;
user_propagator::fresh_eh_t _fresh = [=](void * user_ctx, ast_manager& m, user_propagator::context_obj*& _ctx) {
ast_context_params params;
params.set_foreign_manager(&m);
@ -902,7 +902,7 @@ extern "C" {
Z3_fixed_eh fixed_eh) {
Z3_TRY;
RESET_ERROR_CODE();
user_propagator::fixed_eh_t _fixed = (void(*)(void*,user_propagator::callback*,unsigned,expr*))fixed_eh;
user_propagator::fixed_eh_t _fixed = (void(*)(void*,user_propagator::callback*,expr*,expr*))fixed_eh;
to_solver_ref(s)->user_propagate_register_fixed(_fixed);
Z3_CATCH;
}
@ -924,7 +924,7 @@ extern "C" {
Z3_eq_eh eq_eh) {
Z3_TRY;
RESET_ERROR_CODE();
user_propagator::eq_eh_t _eq = (void(*)(void*,user_propagator::callback*,unsigned,unsigned))eq_eh;
user_propagator::eq_eh_t _eq = (void(*)(void*,user_propagator::callback*,expr*,expr*))eq_eh;
to_solver_ref(s)->user_propagate_register_eq(_eq);
Z3_CATCH;
}
@ -935,43 +935,54 @@ extern "C" {
Z3_eq_eh diseq_eh) {
Z3_TRY;
RESET_ERROR_CODE();
user_propagator::eq_eh_t _diseq = (void(*)(void*,user_propagator::callback*,unsigned,unsigned))diseq_eh;
user_propagator::eq_eh_t _diseq = (void(*)(void*,user_propagator::callback*,expr*,expr*))diseq_eh;
to_solver_ref(s)->user_propagate_register_diseq(_diseq);
Z3_CATCH;
}
unsigned Z3_API Z3_solver_propagate_register(Z3_context c, Z3_solver s, Z3_ast e) {
void Z3_API Z3_solver_propagate_register(Z3_context c, Z3_solver s, Z3_ast e) {
Z3_TRY;
LOG_Z3_solver_propagate_register(c, s, e);
RESET_ERROR_CODE();
return to_solver_ref(s)->user_propagate_register_expr(to_expr(e));
Z3_CATCH_RETURN(0);
to_solver_ref(s)->user_propagate_register_expr(to_expr(e));
Z3_CATCH;
}
unsigned Z3_API Z3_solver_propagate_register_cb(Z3_context c, Z3_solver_callback s, Z3_ast e) {
void Z3_API Z3_solver_propagate_register_cb(Z3_context c, Z3_solver_callback s, Z3_ast e) {
Z3_TRY;
LOG_Z3_solver_propagate_register_cb(c, s, e);
RESET_ERROR_CODE();
return reinterpret_cast<user_propagator::callback*>(s)->register_cb(to_expr(e));
Z3_CATCH_RETURN(0);
reinterpret_cast<user_propagator::callback*>(s)->register_cb(to_expr(e));
Z3_CATCH;
}
void Z3_API Z3_solver_propagate_consequence(Z3_context c, Z3_solver_callback s, unsigned num_fixed, unsigned const* fixed_ids, unsigned num_eqs, unsigned const* eq_lhs, unsigned const* eq_rhs, Z3_ast conseq) {
void Z3_API Z3_solver_propagate_consequence(Z3_context c, Z3_solver_callback s, unsigned num_fixed, Z3_ast const* fixed_ids, unsigned num_eqs, Z3_ast const* eq_lhs, Z3_ast const* eq_rhs, Z3_ast conseq) {
Z3_TRY;
LOG_Z3_solver_propagate_consequence(c, s, num_fixed, fixed_ids, num_eqs, eq_lhs, eq_rhs, conseq);
RESET_ERROR_CODE();
reinterpret_cast<user_propagator::callback*>(s)->propagate_cb(num_fixed, fixed_ids, num_eqs, eq_lhs, eq_rhs, to_expr(conseq));
expr* const * _fixed_ids = (expr* const*) fixed_ids;
expr* const * _eq_lhs = (expr*const*) eq_lhs;
expr* const * _eq_rhs = (expr*const*) eq_rhs;
reinterpret_cast<user_propagator::callback*>(s)->propagate_cb(num_fixed, _fixed_ids, num_eqs, _eq_lhs, _eq_rhs, to_expr(conseq));
Z3_CATCH;
}
void Z3_API Z3_solver_propagate_created(Z3_context c, Z3_solver s, Z3_created_eh created_eh) {
Z3_TRY;
RESET_ERROR_CODE();
user_propagator::created_eh_t c = (void(*)(void*, user_propagator::callback*, expr*, unsigned))created_eh;
user_propagator::created_eh_t c = (void(*)(void*, user_propagator::callback*, expr*))created_eh;
to_solver_ref(s)->user_propagate_register_created(c);
Z3_CATCH;
}
void Z3_API Z3_solver_propagate_decide(Z3_context c, Z3_solver s, Z3_decide_eh decide_eh) {
Z3_TRY;
RESET_ERROR_CODE();
user_propagator::decide_eh_t c = (void(*)(void*, user_propagator::callback*, expr**, unsigned*, lbool*))decide_eh;
to_solver_ref(s)->user_propagate_register_decide(c);
Z3_CATCH;
}
Z3_func_decl Z3_API Z3_solver_propagate_declare(Z3_context c, Z3_symbol name, unsigned n, Z3_sort* domain, Z3_sort range) {
Z3_TRY;
LOG_Z3_solver_propagate_declare(c, name, n, domain, range);

View file

@ -331,8 +331,8 @@ extern "C" {
if (idx >= mk_c(c)->num_tactics()) {
SET_ERROR_CODE(Z3_IOB, nullptr);
return "";
}
return mk_c(c)->get_tactic(idx)->get_name().bare_str();
}
return mk_c(c)->mk_external_string(mk_c(c)->get_tactic(idx)->get_name().str().c_str());
Z3_CATCH_RETURN("");
}
@ -352,7 +352,7 @@ extern "C" {
SET_ERROR_CODE(Z3_IOB, nullptr);
return "";
}
return mk_c(c)->get_probe(idx)->get_name().bare_str();
return mk_c(c)->mk_external_string(mk_c(c)->get_probe(idx)->get_name().str().c_str());
Z3_CATCH_RETURN("");
}

View file

@ -25,6 +25,7 @@ Notes:
#include<string>
#include<sstream>
#include<memory>
#include<vector>
#include<z3.h>
#include<limits.h>
#include<functional>
@ -155,9 +156,10 @@ namespace z3 {
class context {
private:
friend class user_propagator_base;
bool m_enable_exceptions;
rounding_mode m_rounding_mode;
Z3_context m_ctx;
Z3_context m_ctx = nullptr;
void init(config & c) {
set_context(Z3_mk_context_rc(c));
}
@ -173,7 +175,6 @@ namespace z3 {
context(context const &) = delete;
context & operator=(context const &) = delete;
friend class scoped_context;
context(Z3_context c) { set_context(c); }
void detach() { m_ctx = nullptr; }
public:
@ -394,14 +395,6 @@ namespace z3 {
expr_vector parse_file(char const* s, sort_vector const& sorts, func_decl_vector const& decls);
};
class scoped_context final {
context m_ctx;
public:
scoped_context(Z3_context c): m_ctx(c) {}
~scoped_context() { m_ctx.detach(); }
context& operator()() { return m_ctx; }
};
template<typename T>
class array {
@ -509,7 +502,7 @@ namespace z3 {
ast(context & c):object(c), m_ast(0) {}
ast(context & c, Z3_ast n):object(c), m_ast(n) { Z3_inc_ref(ctx(), m_ast); }
ast(ast const & s) :object(s), m_ast(s.m_ast) { Z3_inc_ref(ctx(), m_ast); }
~ast() { if (m_ast) Z3_dec_ref(*m_ctx, m_ast); }
~ast() { if (m_ast) { Z3_dec_ref(*m_ctx, m_ast); } }
operator Z3_ast() const { return m_ast; }
operator bool() const { return m_ast != 0; }
ast & operator=(ast const & s) {
@ -550,7 +543,7 @@ namespace z3 {
~ast_vector_tpl() { Z3_ast_vector_dec_ref(ctx(), m_vector); }
operator Z3_ast_vector() const { return m_vector; }
unsigned size() const { return Z3_ast_vector_size(ctx(), m_vector); }
T operator[](int i) const { assert(0 <= i); Z3_ast r = Z3_ast_vector_get(ctx(), m_vector, i); check_error(); return cast_ast<T>()(ctx(), r); }
T operator[](unsigned i) const { Z3_ast r = Z3_ast_vector_get(ctx(), m_vector, i); check_error(); return cast_ast<T>()(ctx(), r); }
void push_back(T const & e) { Z3_ast_vector_push(ctx(), m_vector, e); check_error(); }
void resize(unsigned sz) { Z3_ast_vector_resize(ctx(), m_vector, sz); check_error(); }
T back() const { return operator[](size() - 1); }
@ -1157,6 +1150,19 @@ namespace z3 {
\pre i < num_args()
*/
expr arg(unsigned i) const { Z3_ast r = Z3_get_app_arg(ctx(), *this, i); check_error(); return expr(ctx(), r); }
/**
\brief Return a vector of all the arguments of this application.
This method assumes the expression is an application.
\pre is_app()
*/
expr_vector args() const {
expr_vector vec(ctx());
unsigned argCnt = num_args();
for (unsigned i = 0; i < argCnt; i++)
vec.push_back(arg(i));
return vec;
}
/**
\brief Return the 'body' of this quantifier.
@ -2327,7 +2333,7 @@ namespace z3 {
inline expr pble(expr_vector const& es, int const* coeffs, int bound) {
assert(es.size() > 0);
context& ctx = es[0].ctx();
context& ctx = es[0u].ctx();
array<Z3_ast> _es(es);
Z3_ast r = Z3_mk_pble(ctx, _es.size(), _es.ptr(), coeffs, bound);
ctx.check_error();
@ -2335,7 +2341,7 @@ namespace z3 {
}
inline expr pbge(expr_vector const& es, int const* coeffs, int bound) {
assert(es.size() > 0);
context& ctx = es[0].ctx();
context& ctx = es[0u].ctx();
array<Z3_ast> _es(es);
Z3_ast r = Z3_mk_pbge(ctx, _es.size(), _es.ptr(), coeffs, bound);
ctx.check_error();
@ -2343,7 +2349,7 @@ namespace z3 {
}
inline expr pbeq(expr_vector const& es, int const* coeffs, int bound) {
assert(es.size() > 0);
context& ctx = es[0].ctx();
context& ctx = es[0u].ctx();
array<Z3_ast> _es(es);
Z3_ast r = Z3_mk_pbeq(ctx, _es.size(), _es.ptr(), coeffs, bound);
ctx.check_error();
@ -2351,7 +2357,7 @@ namespace z3 {
}
inline expr atmost(expr_vector const& es, unsigned bound) {
assert(es.size() > 0);
context& ctx = es[0].ctx();
context& ctx = es[0u].ctx();
array<Z3_ast> _es(es);
Z3_ast r = Z3_mk_atmost(ctx, _es.size(), _es.ptr(), bound);
ctx.check_error();
@ -2359,7 +2365,7 @@ namespace z3 {
}
inline expr atleast(expr_vector const& es, unsigned bound) {
assert(es.size() > 0);
context& ctx = es[0].ctx();
context& ctx = es[0u].ctx();
array<Z3_ast> _es(es);
Z3_ast r = Z3_mk_atleast(ctx, _es.size(), _es.ptr(), bound);
ctx.check_error();
@ -2367,7 +2373,7 @@ namespace z3 {
}
inline expr sum(expr_vector const& args) {
assert(args.size() > 0);
context& ctx = args[0].ctx();
context& ctx = args[0u].ctx();
array<Z3_ast> _args(args);
Z3_ast r = Z3_mk_add(ctx, _args.size(), _args.ptr());
ctx.check_error();
@ -2376,7 +2382,7 @@ namespace z3 {
inline expr distinct(expr_vector const& args) {
assert(args.size() > 0);
context& ctx = args[0].ctx();
context& ctx = args[0u].ctx();
array<Z3_ast> _args(args);
Z3_ast r = Z3_mk_distinct(ctx, _args.size(), _args.ptr());
ctx.check_error();
@ -2405,14 +2411,14 @@ namespace z3 {
Z3_ast r;
assert(args.size() > 0);
if (args.size() == 1) {
return args[0];
return args[0u];
}
context& ctx = args[0].ctx();
context& ctx = args[0u].ctx();
array<Z3_ast> _args(args);
if (Z3_is_seq_sort(ctx, args[0].get_sort())) {
if (Z3_is_seq_sort(ctx, args[0u].get_sort())) {
r = Z3_mk_seq_concat(ctx, _args.size(), _args.ptr());
}
else if (Z3_is_re_sort(ctx, args[0].get_sort())) {
else if (Z3_is_re_sort(ctx, args[0u].get_sort())) {
r = Z3_mk_re_concat(ctx, _args.size(), _args.ptr());
}
else {
@ -2442,7 +2448,7 @@ namespace z3 {
inline expr mk_xor(expr_vector const& args) {
if (args.empty())
return args.ctx().bool_val(false);
expr r = args[0];
expr r = args[0u];
for (unsigned i = 1; i < args.size(); ++i)
r = r ^ args[i];
return r;
@ -2581,9 +2587,9 @@ namespace z3 {
friend std::ostream & operator<<(std::ostream & out, model const & m);
std::string to_string() const { return std::string(Z3_model_to_string(ctx(), m_model)); }
std::string to_string() const { return m_model ? std::string(Z3_model_to_string(ctx(), m_model)) : "null"; }
};
inline std::ostream & operator<<(std::ostream & out, model const & m) { out << Z3_model_to_string(m.ctx(), m); return out; }
inline std::ostream & operator<<(std::ostream & out, model const & m) { return out << m.to_string(); }
class stats : public object {
Z3_stats m_stats;
@ -2627,7 +2633,8 @@ namespace z3 {
Z3_solver m_solver;
void init(Z3_solver s) {
m_solver = s;
Z3_solver_inc_ref(ctx(), s);
if (s)
Z3_solver_inc_ref(ctx(), s);
}
public:
struct simple {};
@ -2636,7 +2643,7 @@ namespace z3 {
solver(context & c, simple):object(c) { init(Z3_mk_simple_solver(c)); }
solver(context & c, Z3_solver s):object(c) { init(s); }
solver(context & c, char const * logic):object(c) { init(Z3_mk_solver_for_logic(c, c.str_symbol(logic))); }
solver(context & c, solver const& src, translate): object(c) { init(Z3_solver_translate(src.ctx(), src, c)); }
solver(context & c, solver const& src, translate): object(c) { Z3_solver s = Z3_solver_translate(src.ctx(), src, c); check_error(); init(s); }
solver(solver const & s):object(s) { init(s.m_solver); }
~solver() { Z3_solver_dec_ref(ctx(), m_solver); }
operator Z3_solver() const { return m_solver; }
@ -2764,7 +2771,7 @@ namespace z3 {
assert(!m_end && !m_empty);
m_cube = m_solver.cube(m_vars, m_cutoff);
m_cutoff = 0xFFFFFFFF;
if (m_cube.size() == 1 && m_cube[0].is_false()) {
if (m_cube.size() == 1 && m_cube[0u].is_false()) {
m_cube = z3::expr_vector(m_solver.ctx());
m_end = true;
}
@ -2998,7 +3005,7 @@ namespace z3 {
}
array<Z3_tactic> buffer(n);
for (unsigned i = 0; i < n; ++i) buffer[i] = tactics[i];
return tactic(tactics[0].ctx(), Z3_tactic_par_or(tactics[0].ctx(), n, buffer.ptr()));
return tactic(tactics[0u].ctx(), Z3_tactic_par_or(tactics[0u].ctx(), n, buffer.ptr()));
}
inline tactic par_and_then(tactic const & t1, tactic const & t2) {
@ -3797,7 +3804,7 @@ namespace z3 {
}
inline expr re_intersect(expr_vector const& args) {
assert(args.size() > 0);
context& ctx = args[0].ctx();
context& ctx = args[0u].ctx();
array<Z3_ast> _args(args);
Z3_ast r = Z3_mk_re_intersect(ctx, _args.size(), _args.ptr());
ctx.check_error();
@ -3932,56 +3939,65 @@ namespace z3 {
class user_propagator_base {
typedef std::function<void(unsigned, expr const&)> fixed_eh_t;
typedef std::function<void(expr const&, expr const&)> fixed_eh_t;
typedef std::function<void(void)> final_eh_t;
typedef std::function<void(unsigned, unsigned)> eq_eh_t;
typedef std::function<void(unsigned, expr const&)> created_eh_t;
typedef std::function<void(expr const&, expr const&)> eq_eh_t;
typedef std::function<void(expr const&)> created_eh_t;
typedef std::function<void(expr&, unsigned&, Z3_lbool&)> decide_eh_t;
final_eh_t m_final_eh;
eq_eh_t m_eq_eh;
fixed_eh_t m_fixed_eh;
created_eh_t m_created_eh;
decide_eh_t m_decide_eh;
solver* s;
Z3_context c;
Z3_solver_callback cb { nullptr };
context* c;
std::vector<z3::context*> subcontexts;
Z3_context ctx() {
return c ? c : (Z3_context)s->ctx();
}
Z3_solver_callback cb { nullptr };
struct scoped_cb {
user_propagator_base& p;
scoped_cb(void* _p, Z3_solver_callback cb):p(*static_cast<user_propagator_base*>(_p)) {
p.cb = cb;
}
~scoped_cb() {
p.cb = nullptr;
~scoped_cb() {
p.cb = nullptr;
}
};
static void push_eh(void* p) {
static void push_eh(void* _p, Z3_solver_callback cb) {
user_propagator_base* p = static_cast<user_propagator_base*>(_p);
scoped_cb _cb(p, cb);
static_cast<user_propagator_base*>(p)->push();
}
static void pop_eh(void* p, unsigned num_scopes) {
static_cast<user_propagator_base*>(p)->pop(num_scopes);
}
static void* fresh_eh(void* p, Z3_context ctx) {
return static_cast<user_propagator_base*>(p)->fresh(ctx);
}
static void fixed_eh(void* _p, Z3_solver_callback cb, unsigned id, Z3_ast _value) {
static void pop_eh(void* _p, Z3_solver_callback cb, unsigned num_scopes) {
user_propagator_base* p = static_cast<user_propagator_base*>(_p);
scoped_cb _cb(p, cb);
scoped_context ctx(p->ctx());
expr value(ctx(), _value);
static_cast<user_propagator_base*>(p)->m_fixed_eh(id, value);
static_cast<user_propagator_base*>(_p)->pop(num_scopes);
}
static void eq_eh(void* p, Z3_solver_callback cb, unsigned x, unsigned y) {
static void* fresh_eh(void* _p, Z3_context ctx) {
user_propagator_base* p = static_cast<user_propagator_base*>(_p);
context* c = new context(ctx);
p->subcontexts.push_back(c);
return p->fresh(*c);
}
static void fixed_eh(void* _p, Z3_solver_callback cb, Z3_ast _var, Z3_ast _value) {
user_propagator_base* p = static_cast<user_propagator_base*>(_p);
scoped_cb _cb(p, cb);
static_cast<user_propagator_base*>(p)->m_eq_eh(x, y);
expr value(p->ctx(), _value);
expr var(p->ctx(), _var);
p->m_fixed_eh(var, value);
}
static void eq_eh(void* _p, Z3_solver_callback cb, Z3_ast _x, Z3_ast _y) {
user_propagator_base* p = static_cast<user_propagator_base*>(_p);
scoped_cb _cb(p, cb);
expr x(p->ctx(), _x), y(p->ctx(), _y);
p->m_eq_eh(x, y);
}
static void final_eh(void* p, Z3_solver_callback cb) {
@ -3989,69 +4005,89 @@ namespace z3 {
static_cast<user_propagator_base*>(p)->m_final_eh();
}
static void created_eh(void* _p, Z3_solver_callback cb, Z3_ast _e, unsigned id) {
static void created_eh(void* _p, Z3_solver_callback cb, Z3_ast _e) {
user_propagator_base* p = static_cast<user_propagator_base*>(_p);
scoped_cb _cb(p, cb);
scoped_context ctx(p->ctx());
expr e(ctx(), _e);
static_cast<user_propagator_base*>(p)->m_created_eh(id, e);
expr e(p->ctx(), _e);
p->m_created_eh(e);
}
static void decide_eh(void* _p, Z3_solver_callback cb, Z3_ast* _val, unsigned* bit, Z3_lbool* is_pos) {
user_propagator_base* p = static_cast<user_propagator_base*>(_p);
scoped_cb _cb(p, cb);
expr val(p->ctx(), *_val);
p->m_decide_eh(val, *bit, *is_pos);
// TBD: life time of val is within the scope of this callback.
*_val = val;
}
public:
user_propagator_base(Z3_context c) : s(nullptr), c(c) {}
user_propagator_base(context& c) : s(nullptr), c(&c) {}
user_propagator_base(solver* s): s(s), c(nullptr) {
Z3_solver_propagate_init(ctx(), *s, this, push_eh, pop_eh, fresh_eh);
Z3_solver_propagate_init(ctx(), *s, this, push_eh, pop_eh, fresh_eh);
}
virtual void push() = 0;
virtual void pop(unsigned num_scopes) = 0;
virtual ~user_propagator_base() = default;
virtual ~user_propagator_base() {
for (auto& subcontext : subcontexts) {
subcontext->detach(); // detach first; the subcontexts will be freed internally!
delete subcontext;
}
}
context& ctx() {
return c ? *c : s->ctx();
}
/**
\brief user_propagators created using \c fresh() are created during
\brief user_propagators created using \c fresh() are created during
search and their lifetimes are restricted to search time. They should
be garbage collected by the propagator used to invoke \c fresh().
The life-time of the Z3_context object can only be assumed valid during
callbacks, such as \c fixed(), which contains expressions based on the
context.
*/
virtual user_propagator_base* fresh(Z3_context ctx) = 0;
virtual user_propagator_base* fresh(context& ctx) = 0;
/**
\brief register callbacks.
Callbacks can only be registered with user_propagators
that were created using a solver.
that were created using a solver.
*/
void register_fixed(fixed_eh_t& f) {
assert(s);
m_fixed_eh = f;
Z3_solver_propagate_fixed(ctx(), *s, fixed_eh);
void register_fixed(fixed_eh_t& f) {
m_fixed_eh = f;
if (s) {
Z3_solver_propagate_fixed(ctx(), *s, fixed_eh);
}
}
void register_fixed() {
assert(s);
m_fixed_eh = [this](unsigned id, expr const& e) {
m_fixed_eh = [this](expr const &id, expr const &e) {
fixed(id, e);
};
Z3_solver_propagate_fixed(ctx(), *s, fixed_eh);
if (s) {
Z3_solver_propagate_fixed(ctx(), *s, fixed_eh);
}
}
void register_eq(eq_eh_t& f) {
assert(s);
m_eq_eh = f;
Z3_solver_propagate_eq(ctx(), *s, eq_eh);
void register_eq(eq_eh_t& f) {
m_eq_eh = f;
if (s) {
Z3_solver_propagate_eq(ctx(), *s, eq_eh);
}
}
void register_eq() {
assert(s);
m_eq_eh = [this](unsigned x, unsigned y) {
m_eq_eh = [this](expr const& x, expr const& y) {
eq(x, y);
};
Z3_solver_propagate_eq(ctx(), *s, eq_eh);
if (s) {
Z3_solver_propagate_eq(ctx(), *s, eq_eh);
}
}
/**
@ -4059,51 +4095,74 @@ namespace z3 {
During the final check stage, all propagations have been processed.
This is an opportunity for the user-propagator to delay some analysis
that could be expensive to perform incrementally. It is also an opportunity
for the propagator to implement branch and bound optimization.
for the propagator to implement branch and bound optimization.
*/
void register_final(final_eh_t& f) {
assert(s);
m_final_eh = f;
Z3_solver_propagate_final(ctx(), *s, final_eh);
void register_final(final_eh_t& f) {
m_final_eh = f;
if (s) {
Z3_solver_propagate_final(ctx(), *s, final_eh);
}
}
void register_final() {
assert(s);
void register_final() {
m_final_eh = [this]() {
final();
};
Z3_solver_propagate_final(ctx(), *s, final_eh);
if (s) {
Z3_solver_propagate_final(ctx(), *s, final_eh);
}
}
void register_created(created_eh_t& c) {
assert(s);
m_created_eh = c;
Z3_solver_propagate_created(ctx(), *s, created_eh);
if (s) {
Z3_solver_propagate_created(ctx(), *s, created_eh);
}
}
void register_created() {
m_created_eh = [this](unsigned id, expr const& e) {
created(id, e);
m_created_eh = [this](expr const& e) {
created(e);
};
Z3_solver_propagate_created(ctx(), *s, created_eh);
if (s) {
Z3_solver_propagate_created(ctx(), *s, created_eh);
}
}
void register_decide(decide_eh_t& c) {
m_decide_eh = c;
if (s) {
Z3_solver_propagate_decide(ctx(), *s, decide_eh);
}
}
virtual void fixed(unsigned /*id*/, expr const& /*e*/) { }
void register_decide() {
m_decide_eh = [this](expr& val, unsigned& bit, Z3_lbool& is_pos) {
decide(val, bit, is_pos);
};
if (s) {
Z3_solver_propagate_decide(ctx(), *s, decide_eh);
}
}
virtual void eq(unsigned /*x*/, unsigned /*y*/) { }
virtual void fixed(expr const& /*id*/, expr const& /*e*/) { }
virtual void eq(expr const& /*x*/, expr const& /*y*/) { }
virtual void final() { }
virtual void created(unsigned /*id*/, expr const& /*e*/) {}
virtual void created(expr const& /*e*/) {}
virtual void decide(expr& /*val*/, unsigned& /*bit*/, Z3_lbool& /*is_pos*/) {}
/**
\brief tracks \c e by a unique identifier that is returned by the call.
If the \c fixed() callback is registered and if \c e is a Boolean or Bit-vector,
If the \c fixed() callback is registered and if \c e is a Boolean or Bit-vector,
the \c fixed() callback gets invoked when \c e is bound to a value.
If the \c eq() callback is registered, then equalities between registered expressions
are reported.
are reported.
A consumer can use the \c propagate or \c conflict functions to invoke propagations
or conflicts as a consequence of these callbacks. These functions take a list of identifiers
for registered expressions that have been fixed. The list of identifiers must correspond to
@ -4111,40 +4170,43 @@ namespace z3 {
correspond to equalities that have been registered during a callback.
*/
unsigned add(expr const& e) {
void add(expr const& e) {
if (cb)
return Z3_solver_propagate_register_cb(ctx(), cb, e);
if (s)
return Z3_solver_propagate_register(ctx(), *s, e);
assert(false);
return 0;
Z3_solver_propagate_register_cb(ctx(), cb, e);
else if (s)
Z3_solver_propagate_register(ctx(), *s, e);
else
assert(false);
}
void conflict(unsigned num_fixed, unsigned const* fixed) {
void conflict(expr_vector const& fixed) {
assert(cb);
scoped_context _ctx(ctx());
expr conseq = _ctx().bool_val(false);
Z3_solver_propagate_consequence(ctx(), cb, num_fixed, fixed, 0, nullptr, nullptr, conseq);
expr conseq = ctx().bool_val(false);
array<Z3_ast> _fixed(fixed);
Z3_solver_propagate_consequence(ctx(), cb, fixed.size(), _fixed.ptr(), 0, nullptr, nullptr, conseq);
}
void propagate(unsigned num_fixed, unsigned const* fixed, expr const& conseq) {
void propagate(expr_vector const& fixed, expr const& conseq) {
assert(cb);
assert(conseq.ctx() == ctx());
Z3_solver_propagate_consequence(ctx(), cb, num_fixed, fixed, 0, nullptr, nullptr, conseq);
assert((Z3_context)conseq.ctx() == (Z3_context)ctx());
array<Z3_ast> _fixed(fixed);
Z3_solver_propagate_consequence(ctx(), cb, _fixed.size(), _fixed.ptr(), 0, nullptr, nullptr, conseq);
}
void propagate(unsigned num_fixed, unsigned const* fixed,
unsigned num_eqs, unsigned const* lhs, unsigned const * rhs,
void propagate(expr_vector const& fixed,
expr_vector const& lhs, expr_vector const& rhs,
expr const& conseq) {
assert(cb);
assert(conseq.ctx() == ctx());
Z3_solver_propagate_consequence(ctx(), cb, num_fixed, fixed, num_eqs, lhs, rhs, conseq);
assert((Z3_context)conseq.ctx() == (Z3_context)ctx());
assert(lhs.size() == rhs.size());
array<Z3_ast> _fixed(fixed);
array<Z3_ast> _lhs(lhs);
array<Z3_ast> _rhs(rhs);
Z3_solver_propagate_consequence(ctx(), cb, _fixed.size(), _fixed.ptr(), lhs.size(), _lhs.ptr(), _rhs.ptr(), conseq);
}
};
}
/**@}*/

View file

@ -100,7 +100,7 @@ namespace Microsoft.Z3
{
get
{
ASTVector res = new ASTVector(Context, Native.Z3_ast_map_keys(Context.nCtx, NativeObject));
using ASTVector res = new ASTVector(Context, Native.Z3_ast_map_keys(Context.nCtx, NativeObject));
return res.ToArray();
}
}

View file

@ -22,7 +22,6 @@ using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Microsoft.Z3
{
/// <summary>
@ -41,24 +40,48 @@ namespace Microsoft.Z3
#region Operators
private static ArithExpr MkNum(ArithExpr e, int i) { return (ArithExpr)e.Context.MkNumeral(i, e.Context.MkIntSort()); }
private static ArithExpr MkNum(ArithExpr e, int i)
{
using var sort = e.Context.MkIntSort();
return (ArithExpr)e.Context.MkNumeral(i, sort);
}
private static ArithExpr MkNum(ArithExpr e, double d) { return (ArithExpr)e.Context.MkNumeral(d.ToString(), e.Context.MkRealSort()); }
private static ArithExpr MkNum(ArithExpr e, double d)
{
using var sort = e.Context.MkRealSort();
return (ArithExpr)e.Context.MkNumeral(d.ToString(), sort);
}
/// <summary> Operator overloading for arithmetical division operator (over reals) </summary>
public static ArithExpr operator /(ArithExpr a, ArithExpr b) { return a.Context.MkDiv(a, b); }
/// <summary> Operator overloading for arithmetical operator </summary>
public static ArithExpr operator /(ArithExpr a, int b) { return a / MkNum(a, b); }
public static ArithExpr operator /(ArithExpr a, int b)
{
using var denominator = MkNum(a, b);
return a / denominator;
}
/// <summary> Operator overloading for arithmetical operator </summary>
public static ArithExpr operator /(ArithExpr a, double b) { return a / MkNum(a, b); }
public static ArithExpr operator /(ArithExpr a, double b)
{
using var denominator = MkNum(a, b);
return a / denominator;
}
/// <summary> Operator overloading for arithmetical operator </summary>
public static ArithExpr operator /(int a, ArithExpr b) { return MkNum(b, a) / b; }
public static ArithExpr operator /(int a, ArithExpr b)
{
using var numerator = MkNum(b, a);
return numerator / b;
}
/// <summary> Operator overloading for arithmetical operator </summary>
public static ArithExpr operator /(double a, ArithExpr b) { return MkNum(b, a) / b; }
public static ArithExpr operator /(double a, ArithExpr b)
{
using var numerator = MkNum(b, a);
return numerator / b;
}
/// <summary> Operator overloading for arithmetical operator </summary>
public static ArithExpr operator -(ArithExpr a) { return a.Context.MkUnaryMinus(a); }
@ -67,106 +90,218 @@ namespace Microsoft.Z3
public static ArithExpr operator -(ArithExpr a, ArithExpr b) { return a.Context.MkSub(a, b); }
/// <summary> Operator overloading for arithmetical operator </summary>
public static ArithExpr operator -(ArithExpr a, int b) { return a - MkNum(a, b); }
public static ArithExpr operator -(ArithExpr a, int b)
{
using var rhs = MkNum(a, b);
return a - rhs;
}
/// <summary> Operator overloading for arithmetical operator </summary>
public static ArithExpr operator -(ArithExpr a, double b) { return a - MkNum(a, b); }
public static ArithExpr operator -(ArithExpr a, double b)
{
using var rhs = MkNum(a, b);
return a - rhs;
}
/// <summary> Operator overloading for arithmetical operator </summary>
public static ArithExpr operator -(int a, ArithExpr b) { return MkNum(b, a) - b; }
public static ArithExpr operator -(int a, ArithExpr b)
{
using var lhs = MkNum(b, a);
return lhs - b;
}
/// <summary> Operator overloading for arithmetical operator </summary>
public static ArithExpr operator -(double a, ArithExpr b) { return MkNum(b, a) - b; }
public static ArithExpr operator -(double a, ArithExpr b)
{
using var lhs = MkNum(b, a);
return lhs - b;
}
/// <summary> Operator overloading for arithmetical operator </summary>
public static ArithExpr operator +(ArithExpr a, ArithExpr b) { return a.Context.MkAdd(a, b); }
/// <summary> Operator overloading for arithmetical operator </summary>
public static ArithExpr operator +(ArithExpr a, int b) { return a + MkNum(a, b); }
public static ArithExpr operator +(ArithExpr a, int b)
{
using var rhs = MkNum(a, b);
return a + rhs;
}
/// <summary> Operator overloading for arithmetical operator </summary>
public static ArithExpr operator +(ArithExpr a, double b) { return a + MkNum(a, b); }
public static ArithExpr operator +(ArithExpr a, double b)
{
using var rhs = MkNum(a, b);
return a + rhs;
}
/// <summary> Operator overloading for arithmetical operator </summary>
public static ArithExpr operator +(int a, ArithExpr b) { return MkNum(b, a) + b; }
public static ArithExpr operator +(int a, ArithExpr b)
{
using var lhs = MkNum(b, a);
return lhs + b;
}
/// <summary> Operator overloading for arithmetical operator </summary>
public static ArithExpr operator +(double a, ArithExpr b) { return MkNum(b, a) + b; }
public static ArithExpr operator +(double a, ArithExpr b)
{
using var lhs = MkNum(b, a);
return lhs + b;
}
/// <summary> Operator overloading for arithmetical operator </summary>
public static ArithExpr operator *(ArithExpr a, ArithExpr b) { return a.Context.MkMul(a, b); }
/// <summary> Operator overloading for arithmetical operator </summary>
public static ArithExpr operator *(ArithExpr a, int b) { return a * MkNum(a, b); }
public static ArithExpr operator *(ArithExpr a, int b)
{
using var rhs = MkNum(a, b);
return a * rhs;
}
/// <summary> Operator overloading for arithmetical operator </summary>
public static ArithExpr operator *(ArithExpr a, double b) { return a * MkNum(a, b); }
public static ArithExpr operator *(ArithExpr a, double b)
{
using var rhs = MkNum(a, b);
return a * rhs;
}
/// <summary> Operator overloading for arithmetical operator </summary>
public static ArithExpr operator *(int a, ArithExpr b) { return MkNum(b, a) * b; }
public static ArithExpr operator *(int a, ArithExpr b)
{
using var lhs = MkNum(b, a);
return lhs * b;
}
/// <summary> Operator overloading for arithmetical operator </summary>
public static ArithExpr operator *(double a, ArithExpr b) { return MkNum(b, a) * b; }
public static ArithExpr operator *(double a, ArithExpr b)
{
using var lhs = MkNum(b, a);
return lhs * b;
}
/// <summary> Operator overloading for arithmetical operator </summary>
public static BoolExpr operator <=(ArithExpr a, ArithExpr b) { return a.Context.MkLe(a, b); }
/// <summary> Operator overloading for arithmetical operator </summary>
public static BoolExpr operator <=(ArithExpr a, int b) { return a <= MkNum(a, b); }
public static BoolExpr operator <=(ArithExpr a, int b)
{
using var rhs = MkNum(a, b);
return a <= rhs;
}
/// <summary> Operator overloading for arithmetical operator </summary>
public static BoolExpr operator <=(ArithExpr a, double b) { return a <= MkNum(a, b); }
public static BoolExpr operator <=(ArithExpr a, double b)
{
using var rhs = MkNum(a, b);
return a <= rhs;
}
/// <summary> Operator overloading for arithmetical operator </summary>
public static BoolExpr operator <=(int a, ArithExpr b) { return MkNum(b, a) <= b; }
public static BoolExpr operator <=(int a, ArithExpr b)
{
using var lhs = MkNum(b, a);
return lhs <= b;
}
/// <summary> Operator overloading for arithmetical operator </summary>
public static BoolExpr operator <=(double a, ArithExpr b) { return MkNum(b, a) <= b; }
public static BoolExpr operator <=(double a, ArithExpr b)
{
using var lhs = MkNum(b, a);
return lhs <= b;
}
/// <summary> Operator overloading for arithmetical operator </summary>
public static BoolExpr operator <(ArithExpr a, ArithExpr b) { return a.Context.MkLt(a, b); }
/// <summary> Operator overloading for arithmetical operator </summary>
public static BoolExpr operator <(ArithExpr a, int b) { return a < MkNum(a, b); }
public static BoolExpr operator <(ArithExpr a, int b)
{
using var rhs = MkNum(a, b);
return a < rhs;
}
/// <summary> Operator overloading for arithmetical operator </summary>
public static BoolExpr operator <(ArithExpr a, double b) { return a < MkNum(a, b); }
public static BoolExpr operator <(ArithExpr a, double b)
{
using var rhs = MkNum(a, b);
return a < rhs;
}
/// <summary> Operator overloading for arithmetical operator </summary>
public static BoolExpr operator <(int a, ArithExpr b) { return MkNum(b, a) < b; }
public static BoolExpr operator <(int a, ArithExpr b)
{
using var lhs = MkNum(b, a);
return lhs < b;
}
/// <summary> Operator overloading for arithmetical operator </summary>
public static BoolExpr operator <(double a, ArithExpr b) { return MkNum(b, a) < b; }
public static BoolExpr operator <(double a, ArithExpr b)
{
using var lhs = MkNum(b, a);
return lhs < b;
}
/// <summary> Operator overloading for arithmetical operator </summary>
public static BoolExpr operator >(ArithExpr a, ArithExpr b) { return a.Context.MkGt(a, b); }
/// <summary> Operator overloading for arithmetical operator </summary>
public static BoolExpr operator >(ArithExpr a, int b) { return a > MkNum(a, b); }
public static BoolExpr operator >(ArithExpr a, int b)
{
using var rhs = MkNum(a, b);
return a > rhs;
}
/// <summary> Operator overloading for arithmetical operator </summary>
public static BoolExpr operator >(ArithExpr a, double b) { return a > MkNum(a, b); }
public static BoolExpr operator >(ArithExpr a, double b)
{
using var rhs = MkNum(a, b);
return a > rhs;
}
/// <summary> Operator overloading for arithmetical operator </summary>
public static BoolExpr operator >(int a, ArithExpr b) { return MkNum(b, a) > b; }
public static BoolExpr operator >(int a, ArithExpr b)
{
using var lhs = MkNum(b, a);
return lhs > b;
}
/// <summary> Operator overloading for arithmetical operator </summary>
public static BoolExpr operator >(double a, ArithExpr b) { return MkNum(b, a) > b; }
public static BoolExpr operator >(double a, ArithExpr b)
{
using var lhs = MkNum(b, a);
return lhs > b;
}
/// <summary> Operator overloading for arithmetical operator </summary>
public static BoolExpr operator >=(ArithExpr a, ArithExpr b) { return a.Context.MkGe(a, b); }
/// <summary> Operator overloading for arithmetical operator </summary>
public static BoolExpr operator >=(ArithExpr a, int b) { return a >= MkNum(a, b); }
public static BoolExpr operator >=(ArithExpr a, int b)
{
using var rhs = MkNum(a, b);
return a >= rhs;
}
/// <summary> Operator overloading for arithmetical operator </summary>
public static BoolExpr operator >=(ArithExpr a, double b) { return a >= MkNum(a, b); }
public static BoolExpr operator >=(ArithExpr a, double b)
{
using var rhs = MkNum(a, b);
return a >= rhs;
}
/// <summary> Operator overloading for arithmetical operator </summary>
public static BoolExpr operator >=(int a, ArithExpr b) { return MkNum(b, a) >= b; }
public static BoolExpr operator >=(int a, ArithExpr b)
{
using var lhs = MkNum(b, a);
return lhs >= b;
}
/// <summary> Operator overloading for arithmetical operator </summary>
public static BoolExpr operator >=(double a, ArithExpr b) { return MkNum(b, a) >= b; }
public static BoolExpr operator >=(double a, ArithExpr b)
{
using var lhs = MkNum(b, a);
return lhs >= b;
}
#endregion
}

View file

@ -85,6 +85,10 @@ set(Z3_DOTNET_ASSEMBLY_SOURCES_IN_SRC_TREE
ListSort.cs
Log.cs
Model.cs
NativeContext.cs
NativeFuncInterp.cs
NativeModel.cs
NativeSolver.cs
Optimize.cs
ParamDescrs.cs
Params.cs

View file

@ -18,10 +18,10 @@ Notes:
--*/
using System;
using System.Diagnostics;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Diagnostics;
using System.Linq;
using System.Runtime.InteropServices;
namespace Microsoft.Z3
{
@ -202,8 +202,8 @@ namespace Microsoft.Z3
/// </summary>
public UninterpretedSort MkUninterpretedSort(string str)
{
return MkUninterpretedSort(MkSymbol(str));
using var sym = MkSymbol(str);
return MkUninterpretedSort(sym);
}
/// <summary>
@ -231,7 +231,6 @@ namespace Microsoft.Z3
return new BitVecSort(this, Native.Z3_mk_bv_sort(nCtx, size));
}
/// <summary>
/// Create a new sequence sort.
/// </summary>
@ -314,7 +313,17 @@ namespace Microsoft.Z3
{
Debug.Assert(enumNames != null);
return new EnumSort(this, MkSymbol(name), MkSymbols(enumNames));
var enumSymbols = MkSymbols(enumNames);
try
{
using var symbol = MkSymbol(name);
return new EnumSort(this, symbol, enumSymbols);
}
finally
{
foreach (var enumSymbol in enumSymbols)
enumSymbol.Dispose();
}
}
/// <summary>
@ -338,7 +347,8 @@ namespace Microsoft.Z3
Debug.Assert(elemSort != null);
CheckContextMatch(elemSort);
return new ListSort(this, MkSymbol(name), elemSort);
using var symbol = MkSymbol(name);
return new ListSort(this, symbol, elemSort);
}
/// <summary>
@ -365,8 +375,8 @@ namespace Microsoft.Z3
/// <param name="size">The size of the sort</param>
public FiniteDomainSort MkFiniteDomainSort(string name, ulong size)
{
return new FiniteDomainSort(this, MkSymbol(name), size);
using var symbol = MkSymbol(name);
return new FiniteDomainSort(this, symbol, size);
}
@ -401,7 +411,18 @@ namespace Microsoft.Z3
public Constructor MkConstructor(string name, string recognizer, string[] fieldNames = null, Sort[] sorts = null, uint[] sortRefs = null)
{
return new Constructor(this, MkSymbol(name), MkSymbol(recognizer), MkSymbols(fieldNames), sorts, sortRefs);
using var nameSymbol = MkSymbol(name);
using var recognizerSymbol = MkSymbol(recognizer);
var fieldSymbols = MkSymbols(fieldNames);
try
{
return new Constructor(this, nameSymbol, recognizerSymbol, fieldSymbols, sorts, sortRefs);
}
finally
{
foreach (var fieldSymbol in fieldSymbols)
fieldSymbol.Dispose();
}
}
/// <summary>
@ -428,7 +449,8 @@ namespace Microsoft.Z3
Debug.Assert(constructors.All(c => c != null));
CheckContextMatch<Constructor>(constructors);
return new DatatypeSort(this, MkSymbol(name), constructors);
using var symbol = MkSymbol(name);
return new DatatypeSort(this, symbol, constructors);
}
/// <summary>
@ -477,7 +499,16 @@ namespace Microsoft.Z3
//Debug.Assert(Contract.ForAll(0, c.Length, j => c[j] != null));
//Debug.Assert(names.All(name => name != null));
return MkDatatypeSorts(MkSymbols(names), c);
var symbols = MkSymbols(names);
try
{
return MkDatatypeSorts(symbols, c);
}
finally
{
foreach (var symbol in symbols)
symbol.Dispose();
}
}
/// <summary>
@ -485,7 +516,7 @@ namespace Microsoft.Z3
/// The function performs a record update at t. The field
/// that is passed in as argument is updated with value v,
/// the remaining fields of t are unchanged.
/// </summary>
/// </summary>
public Expr MkUpdateField(FuncDecl field, Expr t, Expr v)
{
return Expr.Create(this, Native.Z3_datatype_update_field(
@ -538,7 +569,8 @@ namespace Microsoft.Z3
CheckContextMatch<Sort>(domain);
CheckContextMatch(range);
return new FuncDecl(this, MkSymbol(name), domain, range);
using var symbol = MkSymbol(name);
return new FuncDecl(this, symbol, domain, range);
}
/// <summary>
@ -551,7 +583,8 @@ namespace Microsoft.Z3
CheckContextMatch<Sort>(domain);
CheckContextMatch(range);
return new FuncDecl(this, MkSymbol(name), domain, range, true);
using var symbol = MkSymbol(name);
return new FuncDecl(this, symbol, domain, range, true);
}
/// <summary>
@ -560,14 +593,14 @@ namespace Microsoft.Z3
/// MkRecFuncDecl. The body may contain recursive uses of the function or
/// other mutually recursive functions.
/// </summary>
public void AddRecDef(FuncDecl f, Expr[] args, Expr body)
{
CheckContextMatch(f);
CheckContextMatch<Expr>(args);
CheckContextMatch(body);
public void AddRecDef(FuncDecl f, Expr[] args, Expr body)
{
CheckContextMatch(f);
CheckContextMatch<Expr>(args);
CheckContextMatch(body);
IntPtr[] argsNative = AST.ArrayToNative(args);
Native.Z3_add_rec_def(nCtx, f.NativeObject, (uint)args.Length, argsNative, body.NativeObject);
}
Native.Z3_add_rec_def(nCtx, f.NativeObject, (uint)args.Length, argsNative, body.NativeObject);
}
/// <summary>
/// Creates a new function declaration.
@ -579,8 +612,9 @@ namespace Microsoft.Z3
CheckContextMatch(domain);
CheckContextMatch(range);
using var symbol = MkSymbol(name);
Sort[] q = new Sort[] { domain };
return new FuncDecl(this, MkSymbol(name), q, range);
return new FuncDecl(this, symbol, q, range);
}
/// <summary>
@ -619,7 +653,8 @@ namespace Microsoft.Z3
Debug.Assert(range != null);
CheckContextMatch(range);
return new FuncDecl(this, MkSymbol(name), null, range);
using var symbol = MkSymbol(name);
return new FuncDecl(this, symbol, null, range);
}
/// <summary>
@ -687,7 +722,8 @@ namespace Microsoft.Z3
{
Debug.Assert(range != null);
return MkConst(MkSymbol(name), range);
using var symbol = MkSymbol(name);
return MkConst(symbol, range);
}
/// <summary>
@ -728,8 +764,8 @@ namespace Microsoft.Z3
/// </summary>
public BoolExpr MkBoolConst(string name)
{
return (BoolExpr)MkConst(MkSymbol(name), BoolSort);
using var symbol = MkSymbol(name);
return (BoolExpr)MkConst(symbol, BoolSort);
}
/// <summary>
@ -778,7 +814,8 @@ namespace Microsoft.Z3
{
Debug.Assert(name != null);
return (BitVecExpr)MkConst(name, MkBitVecSort(size));
using var sort = MkBitVecSort(size);
return (BitVecExpr)MkConst(name, sort);
}
/// <summary>
@ -786,8 +823,8 @@ namespace Microsoft.Z3
/// </summary>
public BitVecExpr MkBVConst(string name, uint size)
{
return (BitVecExpr)MkConst(name, MkBitVecSort(size));
using var sort = MkBitVecSort(size);
return (BitVecExpr)MkConst(name, sort);
}
#endregion
@ -811,7 +848,7 @@ namespace Microsoft.Z3
public Expr MkApp(FuncDecl f, IEnumerable<Expr> args)
{
Debug.Assert(f != null);
Debug.Assert(args == null || args.All( a => a != null));
Debug.Assert(args == null || args.All(a => a != null));
CheckContextMatch(f);
CheckContextMatch(args);
@ -948,16 +985,12 @@ namespace Microsoft.Z3
Debug.Assert(ts != null);
Debug.Assert(ts.All(a => a != null));
CheckContextMatch<BoolExpr>(ts);
BoolExpr r = null;
foreach (var t in ts) {
if (r == null)
r = t;
else
r = MkXor(r, t);
}
if (r == null)
r = MkTrue();
return r;
return ts.Aggregate(MkFalse(), (r, t) =>
{
using (r)
return MkXor(r, t);
});
}
/// <summary>
@ -2032,7 +2065,8 @@ namespace Microsoft.Z3
Debug.Assert(domain != null);
Debug.Assert(range != null);
return (ArrayExpr)MkConst(name, MkArraySort(domain, range));
using var sort = MkArraySort(domain, range);
return (ArrayExpr)MkConst(name, sort);
}
/// <summary>
@ -2043,7 +2077,9 @@ namespace Microsoft.Z3
Debug.Assert(domain != null);
Debug.Assert(range != null);
return (ArrayExpr)MkConst(MkSymbol(name), MkArraySort(domain, range));
using var symbol = MkSymbol(name);
using var sort = MkArraySort(domain, range);
return (ArrayExpr)MkConst(symbol, sort);
}
@ -2343,7 +2379,7 @@ namespace Microsoft.Z3
CheckContextMatch(elem);
CheckContextMatch(set);
return (BoolExpr) Expr.Create(this, Native.Z3_mk_set_member(nCtx, elem.NativeObject, set.NativeObject));
return (BoolExpr)Expr.Create(this, Native.Z3_mk_set_member(nCtx, elem.NativeObject, set.NativeObject));
}
/// <summary>
@ -2356,7 +2392,7 @@ namespace Microsoft.Z3
CheckContextMatch(arg1);
CheckContextMatch(arg2);
return (BoolExpr) Expr.Create(this, Native.Z3_mk_set_subset(nCtx, arg1.NativeObject, arg2.NativeObject));
return (BoolExpr)Expr.Create(this, Native.Z3_mk_set_subset(nCtx, arg1.NativeObject, arg2.NativeObject));
}
#endregion
@ -2366,7 +2402,7 @@ namespace Microsoft.Z3
/// <summary>
/// Create the empty sequence.
/// </summary>
public SeqExpr MkEmptySeq(Sort s)
public SeqExpr MkEmptySeq(Sort s)
{
Debug.Assert(s != null);
return new SeqExpr(this, Native.Z3_mk_seq_empty(nCtx, s.NativeObject));
@ -2375,7 +2411,7 @@ namespace Microsoft.Z3
/// <summary>
/// Create the singleton sequence.
/// </summary>
public SeqExpr MkUnit(Expr elem)
public SeqExpr MkUnit(Expr elem)
{
Debug.Assert(elem != null);
return new SeqExpr(this, Native.Z3_mk_seq_unit(nCtx, elem.NativeObject));
@ -2384,7 +2420,7 @@ namespace Microsoft.Z3
/// <summary>
/// Create a string constant.
/// </summary>
public SeqExpr MkString(string s)
public SeqExpr MkString(string s)
{
Debug.Assert(s != null);
return new SeqExpr(this, Native.Z3_mk_string(nCtx, s));
@ -2393,7 +2429,7 @@ namespace Microsoft.Z3
/// <summary>
/// Convert an integer expression to a string.
/// </summary>
public SeqExpr IntToString(Expr e)
public SeqExpr IntToString(Expr e)
{
Debug.Assert(e != null);
Debug.Assert(e is ArithExpr);
@ -2413,7 +2449,8 @@ namespace Microsoft.Z3
/// <summary>
/// Convert a bit-vector expression, represented as an signed number, to a string.
/// </summary>
public SeqExpr SbvToString(Expr e) {
public SeqExpr SbvToString(Expr e)
{
Debug.Assert(e != null);
Debug.Assert(e is ArithExpr);
return new SeqExpr(this, Native.Z3_mk_sbv_to_str(nCtx, e.NativeObject));
@ -2422,7 +2459,7 @@ namespace Microsoft.Z3
/// <summary>
/// Convert an integer expression to a string.
/// </summary>
public IntExpr StringToInt(Expr e)
public IntExpr StringToInt(Expr e)
{
Debug.Assert(e != null);
Debug.Assert(e is SeqExpr);
@ -2449,13 +2486,13 @@ namespace Microsoft.Z3
public IntExpr MkLength(SeqExpr s)
{
Debug.Assert(s != null);
return (IntExpr) Expr.Create(this, Native.Z3_mk_seq_length(nCtx, s.NativeObject));
return (IntExpr)Expr.Create(this, Native.Z3_mk_seq_length(nCtx, s.NativeObject));
}
/// <summary>
/// Check for sequence prefix.
/// </summary>
public BoolExpr MkPrefixOf(SeqExpr s1, SeqExpr s2)
public BoolExpr MkPrefixOf(SeqExpr s1, SeqExpr s2)
{
Debug.Assert(s1 != null);
Debug.Assert(s2 != null);
@ -2466,7 +2503,7 @@ namespace Microsoft.Z3
/// <summary>
/// Check for sequence suffix.
/// </summary>
public BoolExpr MkSuffixOf(SeqExpr s1, SeqExpr s2)
public BoolExpr MkSuffixOf(SeqExpr s1, SeqExpr s2)
{
Debug.Assert(s1 != null);
Debug.Assert(s2 != null);
@ -2477,7 +2514,7 @@ namespace Microsoft.Z3
/// <summary>
/// Check for sequence containment of s2 in s1.
/// </summary>
public BoolExpr MkContains(SeqExpr s1, SeqExpr s2)
public BoolExpr MkContains(SeqExpr s1, SeqExpr s2)
{
Debug.Assert(s1 != null);
Debug.Assert(s2 != null);
@ -2488,7 +2525,7 @@ namespace Microsoft.Z3
/// <summary>
/// Check if the string s1 is lexicographically strictly less than s2.
/// </summary>
public BoolExpr MkStringLt(SeqExpr s1, SeqExpr s2)
public BoolExpr MkStringLt(SeqExpr s1, SeqExpr s2)
{
Debug.Assert(s1 != null);
Debug.Assert(s2 != null);
@ -2497,9 +2534,9 @@ namespace Microsoft.Z3
}
/// <summary>
/// Check if the string s1 is lexicographically strictly less than s2.
/// Check if the string s1 is lexicographically less or equal to s2.
/// </summary>
public BoolExpr MkStringLe(SeqExpr s1, SeqExpr s2)
public BoolExpr MkStringLe(SeqExpr s1, SeqExpr s2)
{
Debug.Assert(s1 != null);
Debug.Assert(s2 != null);
@ -2568,10 +2605,10 @@ namespace Microsoft.Z3
/// <summary>
/// Convert a regular expression that accepts sequence s.
/// </summary>
public ReExpr MkToRe(SeqExpr s)
public ReExpr MkToRe(SeqExpr s)
{
Debug.Assert(s != null);
return new ReExpr(this, Native.Z3_mk_seq_to_re(nCtx, s.NativeObject));
return new ReExpr(this, Native.Z3_mk_seq_to_re(nCtx, s.NativeObject));
}
@ -2583,7 +2620,7 @@ namespace Microsoft.Z3
Debug.Assert(s != null);
Debug.Assert(re != null);
CheckContextMatch(s, re);
return new BoolExpr(this, Native.Z3_mk_seq_in_re(nCtx, s.NativeObject, re.NativeObject));
return new BoolExpr(this, Native.Z3_mk_seq_in_re(nCtx, s.NativeObject, re.NativeObject));
}
/// <summary>
@ -2592,7 +2629,7 @@ namespace Microsoft.Z3
public ReExpr MkStar(ReExpr re)
{
Debug.Assert(re != null);
return new ReExpr(this, Native.Z3_mk_re_star(nCtx, re.NativeObject));
return new ReExpr(this, Native.Z3_mk_re_star(nCtx, re.NativeObject));
}
/// <summary>
@ -2601,7 +2638,7 @@ namespace Microsoft.Z3
public ReExpr MkLoop(ReExpr re, uint lo, uint hi = 0)
{
Debug.Assert(re != null);
return new ReExpr(this, Native.Z3_mk_re_loop(nCtx, re.NativeObject, lo, hi));
return new ReExpr(this, Native.Z3_mk_re_loop(nCtx, re.NativeObject, lo, hi));
}
/// <summary>
@ -2610,7 +2647,7 @@ namespace Microsoft.Z3
public ReExpr MkPlus(ReExpr re)
{
Debug.Assert(re != null);
return new ReExpr(this, Native.Z3_mk_re_plus(nCtx, re.NativeObject));
return new ReExpr(this, Native.Z3_mk_re_plus(nCtx, re.NativeObject));
}
/// <summary>
@ -2619,7 +2656,7 @@ namespace Microsoft.Z3
public ReExpr MkOption(ReExpr re)
{
Debug.Assert(re != null);
return new ReExpr(this, Native.Z3_mk_re_option(nCtx, re.NativeObject));
return new ReExpr(this, Native.Z3_mk_re_option(nCtx, re.NativeObject));
}
/// <summary>
@ -2628,7 +2665,7 @@ namespace Microsoft.Z3
public ReExpr MkComplement(ReExpr re)
{
Debug.Assert(re != null);
return new ReExpr(this, Native.Z3_mk_re_complement(nCtx, re.NativeObject));
return new ReExpr(this, Native.Z3_mk_re_complement(nCtx, re.NativeObject));
}
/// <summary>
@ -2670,7 +2707,7 @@ namespace Microsoft.Z3
/// <summary>
/// Create a difference regular expression.
/// </summary>
public ReExpr MkDiff(ReExpr a, ReExpr b)
public ReExpr MkDiff(ReExpr a, ReExpr b)
{
Debug.Assert(a != null);
Debug.Assert(b != null);
@ -2682,7 +2719,7 @@ namespace Microsoft.Z3
/// Create the empty regular expression.
/// The sort s should be a regular expression.
/// </summary>
public ReExpr MkEmptyRe(Sort s)
public ReExpr MkEmptyRe(Sort s)
{
Debug.Assert(s != null);
return new ReExpr(this, Native.Z3_mk_re_empty(nCtx, s.NativeObject));
@ -2692,7 +2729,7 @@ namespace Microsoft.Z3
/// Create the full regular expression.
/// The sort s should be a regular expression.
/// </summary>
public ReExpr MkFullRe(Sort s)
public ReExpr MkFullRe(Sort s)
{
Debug.Assert(s != null);
return new ReExpr(this, Native.Z3_mk_re_full(nCtx, s.NativeObject));
@ -2702,7 +2739,7 @@ namespace Microsoft.Z3
/// <summary>
/// Create a range expression.
/// </summary>
public ReExpr MkRange(SeqExpr lo, SeqExpr hi)
public ReExpr MkRange(SeqExpr lo, SeqExpr hi)
{
Debug.Assert(lo != null);
Debug.Assert(hi != null);
@ -2713,7 +2750,7 @@ namespace Microsoft.Z3
/// <summary>
/// Create less than or equal to between two characters.
/// </summary>
public BoolExpr MkCharLe(Expr ch1, Expr ch2)
public BoolExpr MkCharLe(Expr ch1, Expr ch2)
{
Debug.Assert(ch1 != null);
Debug.Assert(ch2 != null);
@ -2723,7 +2760,7 @@ namespace Microsoft.Z3
/// <summary>
/// Create an integer (code point) from character.
/// </summary>
public IntExpr CharToInt(Expr ch)
public IntExpr CharToInt(Expr ch)
{
Debug.Assert(ch != null);
return new IntExpr(this, Native.Z3_mk_char_to_int(nCtx, ch.NativeObject));
@ -2732,7 +2769,7 @@ namespace Microsoft.Z3
/// <summary>
/// Create a bit-vector (code point) from character.
/// </summary>
public BitVecExpr CharToBV(Expr ch)
public BitVecExpr CharToBV(Expr ch)
{
Debug.Assert(ch != null);
return new BitVecExpr(this, Native.Z3_mk_char_to_bv(nCtx, ch.NativeObject));
@ -2741,7 +2778,7 @@ namespace Microsoft.Z3
/// <summary>
/// Create a character from a bit-vector (code point).
/// </summary>
public Expr CharFromBV(BitVecExpr bv)
public Expr CharFromBV(BitVecExpr bv)
{
Debug.Assert(bv != null);
return new Expr(this, Native.Z3_mk_char_from_bv(nCtx, bv.NativeObject));
@ -2750,7 +2787,7 @@ namespace Microsoft.Z3
/// <summary>
/// Create a check if the character is a digit.
/// </summary>
public BoolExpr MkIsDigit(Expr ch)
public BoolExpr MkIsDigit(Expr ch)
{
Debug.Assert(ch != null);
return new BoolExpr(this, Native.Z3_mk_char_is_digit(nCtx, ch.NativeObject));
@ -2768,7 +2805,7 @@ namespace Microsoft.Z3
Debug.Assert(args != null);
CheckContextMatch<BoolExpr>(args);
var ts = args.ToArray();
return new BoolExpr(this, Native.Z3_mk_atmost(nCtx, (uint) ts.Length,
return new BoolExpr(this, Native.Z3_mk_atmost(nCtx, (uint)ts.Length,
AST.ArrayToNative(ts), k));
}
@ -2780,7 +2817,7 @@ namespace Microsoft.Z3
Debug.Assert(args != null);
CheckContextMatch<BoolExpr>(args);
var ts = args.ToArray();
return new BoolExpr(this, Native.Z3_mk_atleast(nCtx, (uint) ts.Length,
return new BoolExpr(this, Native.Z3_mk_atleast(nCtx, (uint)ts.Length,
AST.ArrayToNative(ts), k));
}
@ -2789,13 +2826,13 @@ namespace Microsoft.Z3
/// </summary>
public BoolExpr MkPBLe(int[] coeffs, BoolExpr[] args, int k)
{
Debug.Assert(args != null);
Debug.Assert(coeffs != null);
Debug.Assert(args.Length == coeffs.Length);
CheckContextMatch<BoolExpr>(args);
return new BoolExpr(this, Native.Z3_mk_pble(nCtx, (uint) args.Length,
AST.ArrayToNative(args),
coeffs, k));
Debug.Assert(args != null);
Debug.Assert(coeffs != null);
Debug.Assert(args.Length == coeffs.Length);
CheckContextMatch<BoolExpr>(args);
return new BoolExpr(this, Native.Z3_mk_pble(nCtx, (uint)args.Length,
AST.ArrayToNative(args),
coeffs, k));
}
/// <summary>
@ -2803,26 +2840,26 @@ namespace Microsoft.Z3
/// </summary>
public BoolExpr MkPBGe(int[] coeffs, BoolExpr[] args, int k)
{
Debug.Assert(args != null);
Debug.Assert(coeffs != null);
Debug.Assert(args.Length == coeffs.Length);
CheckContextMatch<BoolExpr>(args);
return new BoolExpr(this, Native.Z3_mk_pbge(nCtx, (uint) args.Length,
AST.ArrayToNative(args),
coeffs, k));
Debug.Assert(args != null);
Debug.Assert(coeffs != null);
Debug.Assert(args.Length == coeffs.Length);
CheckContextMatch<BoolExpr>(args);
return new BoolExpr(this, Native.Z3_mk_pbge(nCtx, (uint)args.Length,
AST.ArrayToNative(args),
coeffs, k));
}
/// <summary>
/// Create a pseudo-Boolean equal constraint.
/// </summary>
public BoolExpr MkPBEq(int[] coeffs, BoolExpr[] args, int k)
{
Debug.Assert(args != null);
Debug.Assert(coeffs != null);
Debug.Assert(args.Length == coeffs.Length);
CheckContextMatch<BoolExpr>(args);
return new BoolExpr(this, Native.Z3_mk_pbeq(nCtx, (uint) args.Length,
AST.ArrayToNative(args),
coeffs, k));
Debug.Assert(args != null);
Debug.Assert(coeffs != null);
Debug.Assert(args.Length == coeffs.Length);
CheckContextMatch<BoolExpr>(args);
return new BoolExpr(this, Native.Z3_mk_pbeq(nCtx, (uint)args.Length,
AST.ArrayToNative(args),
coeffs, k));
}
#endregion
@ -3040,8 +3077,8 @@ namespace Microsoft.Z3
/// <param name="size">the size of the bit-vector</param>
public BitVecNum MkBV(string v, uint size)
{
return (BitVecNum)MkNumeral(v, MkBitVecSort(size));
using var sort = MkBitVecSort(size);
return (BitVecNum)MkNumeral(v, sort);
}
/// <summary>
@ -3051,8 +3088,8 @@ namespace Microsoft.Z3
/// <param name="size">the size of the bit-vector</param>
public BitVecNum MkBV(int v, uint size)
{
return (BitVecNum)MkNumeral(v, MkBitVecSort(size));
using var sort = MkBitVecSort(size);
return (BitVecNum)MkNumeral(v, sort);
}
/// <summary>
@ -3062,8 +3099,8 @@ namespace Microsoft.Z3
/// <param name="size">the size of the bit-vector</param>
public BitVecNum MkBV(uint v, uint size)
{
return (BitVecNum)MkNumeral(v, MkBitVecSort(size));
using var sort = MkBitVecSort(size);
return (BitVecNum)MkNumeral(v, sort);
}
/// <summary>
@ -3073,8 +3110,8 @@ namespace Microsoft.Z3
/// <param name="size">the size of the bit-vector</param>
public BitVecNum MkBV(long v, uint size)
{
return (BitVecNum)MkNumeral(v, MkBitVecSort(size));
using var sort = MkBitVecSort(size);
return (BitVecNum)MkNumeral(v, sort);
}
/// <summary>
@ -3084,8 +3121,8 @@ namespace Microsoft.Z3
/// <param name="size">the size of the bit-vector</param>
public BitVecNum MkBV(ulong v, uint size)
{
return (BitVecNum)MkNumeral(v, MkBitVecSort(size));
using var sort = MkBitVecSort(size);
return (BitVecNum)MkNumeral(v, sort);
}
/// <summary>
@ -3332,7 +3369,7 @@ namespace Microsoft.Z3
uint cd = AST.ArrayLength(decls);
if (csn != cs || cdn != cd)
throw new Z3Exception("Argument size mismatch");
ASTVector assertions = new ASTVector(this, Native.Z3_parse_smtlib2_string(nCtx, str,
using ASTVector assertions = new ASTVector(this, Native.Z3_parse_smtlib2_string(nCtx, str,
AST.ArrayLength(sorts), Symbol.ArrayToNative(sortNames), AST.ArrayToNative(sorts),
AST.ArrayLength(decls), Symbol.ArrayToNative(declNames), AST.ArrayToNative(decls)));
return assertions.ToBoolExprArray();
@ -3351,7 +3388,7 @@ namespace Microsoft.Z3
uint cd = AST.ArrayLength(decls);
if (csn != cs || cdn != cd)
throw new Z3Exception("Argument size mismatch");
ASTVector assertions = new ASTVector(this, Native.Z3_parse_smtlib2_file(nCtx, fileName,
using ASTVector assertions = new ASTVector(this, Native.Z3_parse_smtlib2_file(nCtx, fileName,
AST.ArrayLength(sorts), Symbol.ArrayToNative(sortNames), AST.ArrayToNative(sorts),
AST.ArrayLength(decls), Symbol.ArrayToNative(declNames), AST.ArrayToNative(decls)));
return assertions.ToBoolExprArray();
@ -3836,8 +3873,8 @@ namespace Microsoft.Z3
/// <seealso cref="MkSolver(Symbol)"/>
public Solver MkSolver(string logic)
{
return MkSolver(MkSymbol(logic));
using var symbol = MkSymbol(logic);
return MkSolver(symbol);
}
/// <summary>
@ -4085,7 +4122,7 @@ namespace Microsoft.Z3
/// <param name="negative">indicates whether the result should be negative.</param>
public FPNum MkFPZero(FPSort s, bool negative)
{
return new FPNum(this, Native.Z3_mk_fpa_zero(nCtx, s.NativeObject, (byte)(negative ? 1 : 0)));
return new FPNum(this, Native.Z3_mk_fpa_zero(nCtx, s.NativeObject, (byte)(negative ? 1 : 0)));
}
/// <summary>
@ -4127,7 +4164,7 @@ namespace Microsoft.Z3
/// <param name="s">FloatingPoint sort.</param>
public FPNum MkFPNumeral(bool sgn, uint sig, int exp, FPSort s)
{
return new FPNum(this, Native.Z3_mk_fpa_numeral_int_uint(nCtx, (byte)(sgn ? 1 : 0), exp, sig, s.NativeObject));
return new FPNum(this, Native.Z3_mk_fpa_numeral_int_uint(nCtx, (byte)(sgn ? 1 : 0), exp, sig, s.NativeObject));
}
/// <summary>
@ -4139,7 +4176,7 @@ namespace Microsoft.Z3
/// <param name="s">FloatingPoint sort.</param>
public FPNum MkFPNumeral(bool sgn, Int64 exp, UInt64 sig, FPSort s)
{
return new FPNum(this, Native.Z3_mk_fpa_numeral_int64_uint64(nCtx, (byte)(sgn ? 1 : 0), exp, sig, s.NativeObject));
return new FPNum(this, Native.Z3_mk_fpa_numeral_int64_uint64(nCtx, (byte)(sgn ? 1 : 0), exp, sig, s.NativeObject));
}
/// <summary>
@ -4825,12 +4862,12 @@ namespace Microsoft.Z3
/// <summary>
/// ASTVector DRQ
/// </summary>
public IDecRefQueue ASTVector_DRQ { get { return m_ASTVector_DRQ; } }
public IDecRefQueue ASTVector_DRQ { get { return m_ASTVector_DRQ; } }
/// <summary>
/// ApplyResult DRQ
/// </summary>
public IDecRefQueue ApplyResult_DRQ { get { return m_ApplyResult_DRQ; } }
public IDecRefQueue ApplyResult_DRQ { get { return m_ApplyResult_DRQ; } }
/// <summary>
/// FuncEntry DRQ
@ -4926,10 +4963,16 @@ namespace Microsoft.Z3
Fixedpoint_DRQ.Clear(this);
Optimize_DRQ.Clear(this);
if (m_boolSort != null) m_boolSort.Dispose();
if (m_intSort != null) m_intSort.Dispose();
if (m_realSort != null) m_realSort.Dispose();
if (m_stringSort != null) m_stringSort.Dispose();
if (m_charSort != null) m_charSort.Dispose();
m_boolSort = null;
m_intSort = null;
m_realSort = null;
m_stringSort = null;
m_charSort = null;
if (refCount == 0 && m_ctx != IntPtr.Zero)
{
m_n_err_handler = null;
@ -4937,7 +4980,7 @@ namespace Microsoft.Z3
m_ctx = IntPtr.Zero;
Native.Z3_del_context(ctx);
}
else
else
GC.ReRegisterForFinalize(this);
}
#endregion

View file

@ -79,7 +79,7 @@ namespace Microsoft.Z3
FuncDecl[][] res = new FuncDecl[n][];
for (uint i = 0; i < n; i++)
{
FuncDecl fd = new FuncDecl(Context, Native.Z3_get_datatype_sort_constructor(Context.nCtx, NativeObject, i));
using FuncDecl fd = new FuncDecl(Context, Native.Z3_get_datatype_sort_constructor(Context.nCtx, NativeObject, i));
uint ds = fd.DomainSize;
FuncDecl[] tmp = new FuncDecl[ds];
for (uint j = 0; j < ds; j++)

View file

@ -74,7 +74,8 @@ namespace Microsoft.Z3
/// <returns></returns>
public Expr Const(uint inx)
{
return Context.MkApp(ConstDecl(inx));
using var decl = ConstDecl(inx);
return Context.MkApp(decl);
}
/// <summary>

View file

@ -255,7 +255,7 @@ namespace Microsoft.Z3
get
{
ASTVector av = new ASTVector(Context, Native.Z3_fixedpoint_get_rules(Context.nCtx, NativeObject));
using ASTVector av = new ASTVector(Context, Native.Z3_fixedpoint_get_rules(Context.nCtx, NativeObject));
return av.ToBoolExprArray();
}
}
@ -268,7 +268,7 @@ namespace Microsoft.Z3
get
{
ASTVector av = new ASTVector(Context, Native.Z3_fixedpoint_get_assertions(Context.nCtx, NativeObject));
using ASTVector av = new ASTVector(Context, Native.Z3_fixedpoint_get_assertions(Context.nCtx, NativeObject));
return av.ToBoolExprArray();
}
}
@ -292,7 +292,7 @@ namespace Microsoft.Z3
/// </summary>
public BoolExpr[] ParseFile(string file)
{
ASTVector av = new ASTVector(Context, Native.Z3_fixedpoint_from_file(Context.nCtx, NativeObject, file));
using ASTVector av = new ASTVector(Context, Native.Z3_fixedpoint_from_file(Context.nCtx, NativeObject, file));
return av.ToBoolExprArray();
}
@ -301,7 +301,7 @@ namespace Microsoft.Z3
/// </summary>
public BoolExpr[] ParseString(string s)
{
ASTVector av = new ASTVector(Context, Native.Z3_fixedpoint_from_string(Context.nCtx, NativeObject, s));
using ASTVector av = new ASTVector(Context, Native.Z3_fixedpoint_from_string(Context.nCtx, NativeObject, s));
return av.ToBoolExprArray();
}

View file

@ -203,8 +203,8 @@ namespace Microsoft.Z3
/// <remarks>Essentially invokes the `simplify' tactic on the goal.</remarks>
public Goal Simplify(Params p = null)
{
Tactic t = Context.MkTactic("simplify");
ApplyResult res = t.Apply(this, p);
using Tactic t = Context.MkTactic("simplify");
using ApplyResult res = t.Apply(this, p);
if (res.NumSubgoals == 0)
throw new Z3Exception("No subgoals");

View file

@ -32,6 +32,8 @@
<Authors>Microsoft</Authors>
<Company>Microsoft</Company>
<LangVersion>8.0</LangVersion>
</PropertyGroup>
<!-- Code contract & signing properties -->

View file

@ -87,7 +87,8 @@ namespace Microsoft.Z3
if (Native.Z3_is_as_array(Context.nCtx, n) == 0)
throw new Z3Exception("Argument was not an array constant");
IntPtr fd = Native.Z3_get_as_array_func_decl(Context.nCtx, n);
return FuncInterp(new FuncDecl(Context, fd));
using var decl = new FuncDecl(Context, fd);
return FuncInterp(decl);
}
}
else
@ -241,7 +242,7 @@ namespace Microsoft.Z3
/// Evaluate expression to a double, assuming it is a numeral already.
/// </summary>
public double Double(Expr t) {
var r = Eval(t, true);
using var r = Eval(t, true);
return Native.Z3_get_numeral_double(Context.nCtx, r.NativeObject);
}
@ -283,7 +284,7 @@ namespace Microsoft.Z3
{
Debug.Assert(s != null);
ASTVector av = new ASTVector(Context, Native.Z3_model_get_sort_universe(Context.nCtx, NativeObject, s.NativeObject));
using ASTVector av = new ASTVector(Context, Native.Z3_model_get_sort_universe(Context.nCtx, NativeObject, s.NativeObject));
return av.ToExprArray();
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,104 @@
/*++
Copyright (c) 2012 Microsoft Corporation
Module Name:
NativeFuncInterp.cs
Abstract:
Z3 Managed API: Function Interpretations
Author:
Christoph Wintersteiger (cwinter) 2012-03-21
Notes:
--*/
using System.Diagnostics;
using System;
namespace Microsoft.Z3
{
using Z3_context = System.IntPtr;
using Z3_ast = System.IntPtr;
using Z3_app = System.IntPtr;
using Z3_sort = System.IntPtr;
using Z3_func_decl = System.IntPtr;
using Z3_model = System.IntPtr;
using Z3_func_interp = System.IntPtr;
using Z3_func_entry = System.IntPtr;
/// <summary>
/// A function interpretation is represented as a finite map and an 'else' value.
/// Each entry in the finite map represents the value of a function given a set of arguments.
/// </summary>
public class NativeFuncInterp
{
/// <summary>
/// Evaluation entry of a function
/// </summary>
public class Entry
{
/// <summary>
/// Argument values that define entry
/// </summary>
public Z3_ast[] Arguments;
/// <summary>
/// Result of applying function to Arguments in the interpretation
/// </summary>
public Z3_ast Result;
}
/// <summary>
/// Function that is interpreted
/// </summary>
public Z3_func_decl Declaration;
/// <summary>
/// Set of non-default entries defining the function graph
/// </summary>
public Entry[] Entries;
/// <summary>
/// Default cause of the function interpretation
/// </summary>
public Z3_ast Else;
#region Internal
internal NativeFuncInterp(NativeContext ctx, NativeModel mdl, Z3_func_decl decl, Z3_func_interp fi)
{
Debug.Assert(ctx != null);
Z3_context nCtx = ctx.nCtx;
Native.Z3_func_interp_inc_ref(nCtx, fi);
Declaration = decl;
Else = Native.Z3_func_interp_get_else(nCtx, fi);
uint numEntries = Native.Z3_func_interp_get_num_entries(nCtx, fi);
uint numArgs = Native.Z3_func_interp_get_arity(nCtx, fi);
Entries = new Entry[numEntries];
for (uint j = 0; j < numEntries; ++j)
{
var ntvEntry = Native.Z3_func_interp_get_entry(nCtx, fi, j);
Entries[j] = new Entry();
Native.Z3_func_entry_inc_ref(nCtx, ntvEntry);
Entries[j].Arguments = new Z3_ast[numArgs];
for (uint i = 0; i < numArgs; ++i)
Entries[j].Arguments[i] = Native.Z3_func_entry_get_arg(nCtx, ntvEntry, i);
Entries[j].Result = Native.Z3_func_entry_get_value(nCtx, ntvEntry);
Native.Z3_func_entry_dec_ref(nCtx, ntvEntry);
}
Native.Z3_func_interp_dec_ref(nCtx, fi);
}
#endregion
}
}

View file

@ -0,0 +1,383 @@
/*++
Copyright (c) 2012 Microsoft Corporation
Module Name:
NativeModel.cs
Abstract:
Z3 Managed API: Models
Native interface to model objects.
Author:
Christoph Wintersteiger (cwinter) 2012-03-21
Nikolaj Bjorner (nbjorner) 2022-03-01
Notes:
--*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Diagnostics;
namespace Microsoft.Z3
{
using Z3_ast = System.IntPtr;
using Z3_func_decl = System.IntPtr;
using Z3_sort = System.IntPtr;
/// <summary>
/// A Model contains interpretations (assignments) of constants and functions.
/// </summary>
public class NativeModel : IDisposable
{
/// <summary>
/// Retrieves the interpretation (the assignment) of <paramref name="a"/> in the model.
/// </summary>
/// <param name="a">A Constant</param>
/// <returns>An expression if the constant has an interpretation in the model, null otherwise.</returns>
public Z3_ast ConstInterp(Z3_ast a) => ConstFuncInterp(Native.Z3_get_app_decl(ntvContext.nCtx, a));
/// <summary>
/// Retrieves the interpretation (the assignment) of <paramref name="f"/> in the model.
/// </summary>
/// <param name="f">A function declaration of zero arity</param>
/// <returns>An expression if the function has an interpretation in the model, null otherwise.</returns>
public Z3_ast ConstFuncInterp(Z3_func_decl f)
{
if (Native.Z3_get_arity(ntvContext.nCtx, f) != 0)
throw new Z3Exception("Non-zero arity functions have FunctionInterpretations as a model. Use FuncInterp.");
return Native.Z3_model_get_const_interp(ntvContext.nCtx, NativeObject, f);
}
/// <summary>
/// Retrieves the interpretation (the assignment) of a non-constant <paramref name="f"/> in the model.
/// </summary>
/// <param name="f">A function declaration of non-zero arity</param>
/// <returns>A FunctionInterpretation if the function has an interpretation in the model, null otherwise.</returns>
public NativeFuncInterp FuncInterp(Z3_func_decl f)
{
Z3_sort_kind sk = (Z3_sort_kind)Native.Z3_get_sort_kind(ntvContext.nCtx, Native.Z3_get_range(ntvContext.nCtx, f));
if (Native.Z3_get_arity(ntvContext.nCtx, f) == 0)
{
IntPtr n = Native.Z3_model_get_const_interp(ntvContext.nCtx, NativeObject, f);
if (sk == Z3_sort_kind.Z3_ARRAY_SORT)
{
if (n == IntPtr.Zero)
return null;
else
{
if (Native.Z3_is_as_array(ntvContext.nCtx, n) == 0)
throw new Z3Exception("Argument was not an array constant");
var fd = Native.Z3_get_as_array_func_decl(ntvContext.nCtx, n);
return new NativeFuncInterp(ntvContext, this, f, fd);
}
}
else
{
throw new Z3Exception("Constant functions do not have a function interpretation; use ConstInterp");
}
}
else
{
IntPtr n = Native.Z3_model_get_func_interp(ntvContext.nCtx, NativeObject, f);
if (n == IntPtr.Zero)
return null;
else
return new NativeFuncInterp(ntvContext, this, f, n);
}
}
/// <summary>
/// The number of constants that have an interpretation in the model.
/// </summary>
public uint NumConsts
{
get { return Native.Z3_model_get_num_consts(ntvContext.nCtx, NativeObject); }
}
/// <summary>
/// The function declarations of the constants in the model.
/// </summary>
public Z3_func_decl[] ConstDecls
{
get
{
uint n = NumConsts;
Z3_func_decl[] res = new Z3_func_decl[n];
for (uint i = 0; i < n; i++)
res[i] = Native.Z3_model_get_const_decl(ntvContext.nCtx, NativeObject, i);
return res;
}
}
/// <summary>
/// Enumerate constants in model.
/// </summary>
public IEnumerable<KeyValuePair<Z3_func_decl, Z3_ast>> Consts
{
get
{
uint nc = NumConsts;
for (uint i = 0; i < nc; ++i)
{
var f = Native.Z3_model_get_const_decl(ntvContext.nCtx, NativeObject, i);
IntPtr n = Native.Z3_model_get_const_interp(ntvContext.nCtx, NativeObject, f);
if (n == IntPtr.Zero) continue;
yield return new KeyValuePair<Z3_func_decl, Z3_ast>(f, n);
}
}
}
/// <summary>
/// The number of function interpretations in the model.
/// </summary>
public uint NumFuncs
{
get { return Native.Z3_model_get_num_funcs(ntvContext.nCtx, NativeObject); }
}
/// <summary>
/// The function declarations of the function interpretations in the model.
/// </summary>
public Z3_func_decl[] FuncDecls
{
get
{
uint n = NumFuncs;
Z3_func_decl[] res = new Z3_func_decl[n];
for (uint i = 0; i < n; i++)
res[i] = Native.Z3_model_get_func_decl(ntvContext.nCtx, NativeObject, i);
return res;
}
}
/// <summary>
/// All symbols that have an interpretation in the model.
/// </summary>
public Z3_func_decl[] Decls
{
get
{
uint nFuncs = NumFuncs;
uint nConsts = NumConsts;
uint n = nFuncs + nConsts;
Z3_func_decl[] res = new Z3_func_decl[n];
for (uint i = 0; i < nConsts; i++)
res[i] = Native.Z3_model_get_const_decl(ntvContext.nCtx, NativeObject, i);
for (uint i = 0; i < nFuncs; i++)
res[nConsts + i] = Native.Z3_model_get_func_decl(ntvContext.nCtx, NativeObject, i);
return res;
}
}
/// <summary>
/// A ModelEvaluationFailedException is thrown when an expression cannot be evaluated by the model.
/// </summary>
public class ModelEvaluationFailedException : Z3Exception
{
/// <summary>
/// An exception that is thrown when model evaluation fails.
/// </summary>
public ModelEvaluationFailedException() : base() { }
}
/// <summary>
/// Evaluates the expression <paramref name="t"/> in the current model.
/// </summary>
/// <remarks>
/// This function may fail if <paramref name="t"/> contains quantifiers,
/// is partial (MODEL_PARTIAL enabled), or if <paramref name="t"/> is not well-sorted.
/// In this case a <c>ModelEvaluationFailedException</c> is thrown.
/// </remarks>
/// <param name="t">An expression</param>
/// <param name="completion">
/// When this flag is enabled, a model value will be assigned to any constant
/// or function that does not have an interpretation in the model.
/// </param>
/// <returns>The evaluation of <paramref name="t"/> in the model.</returns>
public Z3_ast Eval(Z3_ast t, bool completion = false)
{
IntPtr v = IntPtr.Zero;
if (Native.Z3_model_eval(ntvContext.nCtx, NativeObject, t, (byte)(completion ? 1 : 0), ref v) == (byte)0)
throw new ModelEvaluationFailedException();
else
return v;
}
/// <summary>
/// Alias for <c>Eval</c>.
/// </summary>
public Z3_ast Evaluate(Z3_ast t, bool completion = false) => Eval(t, completion);
/// <summary>
/// Evaluate expression to a double, assuming it is a numeral already.
/// </summary>
public double Double(Z3_ast t)
{
var r = Eval(t, true);
return Native.Z3_get_numeral_double(ntvContext.nCtx, r);
}
/// <summary>
/// An array value obtained by untangling a model assignment.
/// </summary>
public class ArrayValue
{
/// <summary>
/// One dimensional array of indices where the array is updated
/// </summary>
public KeyValuePair<Z3_ast, Z3_ast>[] Updates;
/// <summary>
/// default Else case
/// </summary>
public Z3_ast Else;
/// <summary>
/// Domain for array
/// Updates.Keys
/// </summary>
public Z3_ast[] Domain;
/// <summary>
/// Range for array
/// Updates.Values
/// </summary>
public Z3_ast[] Range;
}
/// <summary>
/// Convert the interpretation of t into a sequence of array updates
/// </summary>
/// <param name="t"></param>
/// <param name="result"></param>
/// <returns>null if the argument does evaluate to a sequence of stores to an array</returns>
public bool TryGetArrayValue(Z3_ast t, out ArrayValue result)
{
var r = Eval(t, true);
// check that r is a sequence of store over a constant default array.
var updates = new Dictionary<Z3_ast, Z3_ast>();
result = null;
while (true)
{
if (ntvContext.GetAstKind(r) != Z3_ast_kind.Z3_APP_AST)
return false;
Z3_func_decl f = ntvContext.GetAppDecl(r);
var kind = ntvContext.GetDeclKind(f);
if (kind == Z3_decl_kind.Z3_OP_CONST_ARRAY)
{
result = new ArrayValue();
result.Else = ntvContext.GetAppArg(r, 0);
result.Updates = updates.ToArray();
result.Domain = updates.Keys.ToArray();
result.Range = updates.Values.ToArray();
return true;
}
else if (kind == Z3_decl_kind.Z3_OP_STORE)
{
Debug.Assert(ntvContext.GetNumArgs(r) == 3);
updates[ntvContext.GetAppArg(r, 1)] = ntvContext.GetAppArg(r, 2);
r = ntvContext.GetAppArg(r, 0);
}
else
{
return false;
}
}
}
/// <summary>
/// The number of uninterpreted sorts that the model has an interpretation for.
/// </summary>
public uint NumSorts { get { return Native.Z3_model_get_num_sorts(ntvContext.nCtx, NativeObject); } }
/// <summary>
/// The uninterpreted sorts that the model has an interpretation for.
/// </summary>
/// <remarks>
/// Z3 also provides an interpretation for uninterpreted sorts used in a formula.
/// The interpretation for a sort is a finite set of distinct values. We say this finite set is
/// the "universe" of the sort.
/// </remarks>
/// <seealso cref="NumSorts"/>
public Z3_sort[] Sorts
{
get
{
uint n = NumSorts;
Z3_sort[] res = new Z3_sort[n];
for (uint i = 0; i < n; i++)
res[i] = Native.Z3_model_get_sort(ntvContext.nCtx, NativeObject, i);
return res;
}
}
/// <summary>
/// Conversion of models to strings.
/// </summary>
/// <returns>A string representation of the model.</returns>
public override string ToString()
{
return Native.Z3_model_to_string(ntvContext.nCtx, NativeObject);
}
IntPtr NativeObject;
NativeContext ntvContext;
internal NativeModel(NativeContext ctx, IntPtr obj)
{
ntvContext = ctx;
NativeObject = obj;
Debug.Assert(ctx != null);
Native.Z3_model_inc_ref(ctx.nCtx, obj);
}
/// <summary>
/// Finalizer.
/// </summary>
~NativeModel()
{
Dispose();
}
/// <summary>
/// Disposes of the underlying native Z3 object.
/// </summary>
public void Dispose()
{
if (NativeObject != IntPtr.Zero)
{
Native.Z3_model_dec_ref(ntvContext.nCtx, NativeObject);
NativeObject = IntPtr.Zero;
}
GC.SuppressFinalize(this);
}
}
}

View file

@ -0,0 +1,451 @@
/*++
Copyright (c) 2012 Microsoft Corporation
Module Name:
NativeSolver.cs
Abstract:
Z3 Managed API: Native Solver
Author:
Christoph Wintersteiger (cwinter) 2012-03-22
Nikolaj Bjorner (nbjorner) 2022-03-01
Notes:
--*/
using System;
using System.Diagnostics;
using System.Collections.Generic;
using System.Linq;
namespace Microsoft.Z3
{
using Z3_ast = System.IntPtr;
using Z3_context = System.IntPtr;
using Z3_func_decl = System.IntPtr;
using Z3_params = System.IntPtr;
using Z3_solver = System.IntPtr;
using Z3_sort = System.IntPtr;
using Z3_symbol = System.IntPtr;
/// <summary>
/// Solvers.
/// </summary>
public class NativeSolver : IDisposable
{
/// <summary>
/// A string that describes all available solver parameters.
/// </summary>
public string Help => Native.Z3_solver_get_help(nCtx, z3solver);
private void SetParam(Action<Z3_params> setter)
{
Z3_params p = Native.Z3_mk_params(nCtx);
Native.Z3_params_inc_ref(nCtx, p);
setter(p);
Native.Z3_solver_set_params(nCtx, z3solver, p);
Native.Z3_params_dec_ref(nCtx, p);
}
/// <summary>
/// Sets parameter on the solver
/// </summary>
public void Set(string name, bool value)
{
SetParam((Z3_params p) => Native.Z3_params_set_bool(nCtx, p, Native.Z3_mk_string_symbol(nCtx, name), (byte)(value ? 1 : 0)));
}
/// <summary>
/// Sets parameter on the solver
/// </summary>
public void Set(string name, uint value)
{
SetParam((Z3_params p) => Native.Z3_params_set_uint(nCtx, p, Native.Z3_mk_string_symbol(nCtx, name), value));
}
/// <summary>
/// Sets parameter on the solver
/// </summary>
public void Set(string name, double value)
{
SetParam((Z3_params p) => Native.Z3_params_set_double(nCtx, p, Native.Z3_mk_string_symbol(nCtx, name), value));
}
/// <summary>
/// Sets parameter on the solver
/// </summary>
public void Set(string name, string value)
{
var value_sym = Native.Z3_mk_string_symbol(nCtx, value);
SetParam((Z3_params p) => Native.Z3_params_set_symbol(nCtx, p, Native.Z3_mk_string_symbol(nCtx, name), value_sym));
}
#if false
/// <summary>
/// Sets parameter on the solver
/// </summary>
public void Set(string name, Symbol value) { Parameters = Context.MkParams().Add(name, value); }
/// <summary>
/// Sets parameter on the solver
/// </summary>
public void Set(Symbol name, bool value) { Parameters = Context.MkParams().Add(name, value); }
/// <summary>
/// Sets parameter on the solver
/// </summary>
public void Set(Symbol name, uint value) { Parameters = Context.MkParams().Add(name, value); }
/// <summary>
/// Sets parameter on the solver
/// </summary>
public void Set(Symbol name, double value) { Parameters = Context.MkParams().Add(name, value); }
/// <summary>
/// Sets parameter on the solver
/// </summary>
public void Set(Symbol name, string value) { Parameters = Context.MkParams().Add(name, value); }
/// <summary>
/// Sets parameter on the solver
/// </summary>
public void Set(Symbol name, Symbol value) { Parameters = Context.MkParams().Add(name, value); }
/// <summary>
/// Retrieves parameter descriptions for solver.
/// </summary>
public ParamDescrs ParameterDescriptions
{
get { return new ParamDescrs(Context, Native.Z3_solver_get_param_descrs(nCtx, NativeObject)); }
}
#endif
/// <summary>
/// The current number of backtracking points (scopes).
/// </summary>
/// <seealso cref="Pop"/>
/// <seealso cref="Push"/>
public uint NumScopes => Native.Z3_solver_get_num_scopes(nCtx, z3solver);
/// <summary>
/// Creates a backtracking point.
/// </summary>
/// <seealso cref="Pop"/>
public void Push() => Native.Z3_solver_push(nCtx, z3solver);
/// <summary>
/// Backtracks <paramref name="n"/> backtracking points.
/// </summary>
/// <remarks>Note that an exception is thrown if <paramref name="n"/> is not smaller than <c>NumScopes</c></remarks>
/// <seealso cref="Push"/>
public void Pop(uint n = 1) => Native.Z3_solver_pop(nCtx, z3solver, n);
/// <summary>
/// Resets the Solver.
/// </summary>
/// <remarks>This removes all assertions from the solver.</remarks>
public void Reset() => Native.Z3_solver_reset(nCtx, z3solver);
/// <summary>
/// Assert a constraint (or multiple) into the solver.
/// </summary>
public void Assert(params Z3_ast[] constraints)
{
Debug.Assert(constraints != null);
Debug.Assert(constraints.All(c => c != IntPtr.Zero));
foreach (Z3_ast a in constraints)
{
Native.Z3_solver_assert(nCtx, z3solver, a);
}
}
/// <summary>
/// Alias for Assert.
/// </summary>
public void Add(params Z3_ast[] constraints) => Assert(constraints);
/// <summary>
/// Alias for Assert.
/// </summary>
public void Add(IEnumerable<Z3_ast> constraints) => Assert(constraints.ToArray());
/// <summary>
/// Add constraints to ensure the function f can only be injective.
/// Example:
/// for function f : D1 x D2 -> R
/// assert axioms
/// forall (x1 : D1, x2 : D2) x1 = inv1(f(x1,x2))
/// forall (x1 : D1, x2 : D2) x2 = inv2(f(x1,x2))
/// </summary>
/// <param name="f"></param>
public void AssertInjective(Z3_func_decl f)
{
uint arity = Native.Z3_get_arity(nCtx, f);
Z3_sort range = Native.Z3_get_range(nCtx, f);
Z3_ast[] vars = new Z3_ast[arity];
Z3_sort[] sorts = new Z3_sort[arity];
Z3_symbol[] names = new Z3_symbol[arity];
for (uint i = 0; i < arity; ++i)
{
Z3_sort domain = Native.Z3_get_domain(nCtx, f, i);
vars[i] = ntvContext.MkBound(arity - i - 1, domain);
sorts[i] = domain;
names[i] = Native.Z3_mk_int_symbol(nCtx, (int)i);
}
Z3_ast app_f = IntPtr.Zero; // Context.MkApp(f, vars);
for (uint i = 0; i < arity; ++i)
{
Z3_sort domain = Native.Z3_get_domain(nCtx, f, i);
Z3_func_decl proj = ntvContext.MkFreshFuncDecl("inv", new Z3_sort[] { range }, domain);
Z3_ast body = ntvContext.MkEq(vars[i], ntvContext.MkApp(proj, app_f));
Z3_ast q = ntvContext.MkForall(names, sorts, body);
Assert(q);
}
}
/// <summary>
/// Assert multiple constraints into the solver, and track them (in the unsat) core
/// using the Boolean constants in ps.
/// </summary>
/// <remarks>
/// This API is an alternative to <see cref="Check(Z3_ast[])"/> with assumptions for extracting unsat cores.
/// Both APIs can be used in the same solver. The unsat core will contain a combination
/// of the Boolean variables provided using <see cref="AssertAndTrack(Z3_ast[],Z3_ast[])"/>
/// and the Boolean literals
/// provided using <see cref="Check(Z3_ast[])"/> with assumptions.
/// </remarks>
public void AssertAndTrack(Z3_ast[] constraints, Z3_ast[] ps)
{
Debug.Assert(constraints != null);
Debug.Assert(constraints.All(c => c != IntPtr.Zero));
Debug.Assert(ps.All(c => c != IntPtr.Zero));
if (constraints.Length != ps.Length)
throw new Z3Exception("Argument size mismatch");
for (int i = 0; i < constraints.Length; i++)
Native.Z3_solver_assert_and_track(nCtx, z3solver, constraints[i], ps[i]);
}
/// <summary>
/// Assert a constraint into the solver, and track it (in the unsat) core
/// using the Boolean constant p.
/// </summary>
/// <remarks>
/// This API is an alternative to <see cref="Check(Z3_ast[])"/> with assumptions for extracting unsat cores.
/// Both APIs can be used in the same solver. The unsat core will contain a combination
/// of the Boolean variables provided using <see cref="AssertAndTrack(Z3_ast[],Z3_ast[])"/>
/// and the Boolean literals
/// provided using <see cref="Check(Z3_ast[])"/> with assumptions.
/// </remarks>
public void AssertAndTrack(Z3_ast constraint, Z3_ast p)
{
Debug.Assert(constraint != null);
Debug.Assert(p != null);
Native.Z3_solver_assert_and_track(nCtx, z3solver, constraint, p);
}
/// <summary>
/// Load solver assertions from a file.
/// </summary>
public void FromFile(string file)
=> Native.Z3_solver_from_file(nCtx, z3solver, file);
/// <summary>
/// Load solver assertions from a string.
/// </summary>
public void FromString(string str)
=> Native.Z3_solver_from_string(nCtx, z3solver, str);
/// <summary>
/// The number of assertions in the solver.
/// </summary>
public uint NumAssertions
=> (uint)ntvContext.ToArray(Native.Z3_solver_get_assertions(nCtx, z3solver)).Length;
/// <summary>
/// The set of asserted formulas.
/// </summary>
public Z3_ast[] Assertions
=> ntvContext.ToArray(Native.Z3_solver_get_assertions(nCtx, z3solver));
/// <summary>
/// Currently inferred units.
/// </summary>
public Z3_ast[] Units
=> ntvContext.ToArray(Native.Z3_solver_get_units(nCtx, z3solver));
/// <summary>
/// Checks whether the assertions in the solver are consistent or not.
/// </summary>
/// <remarks>
/// <seealso cref="Model"/>
/// <seealso cref="UnsatCore"/>
/// <seealso cref="Proof"/>
/// </remarks>
public Status Check(params Z3_ast[] assumptions)
{
Z3_lbool r;
if (assumptions == null || assumptions.Length == 0)
r = (Z3_lbool)Native.Z3_solver_check(nCtx, z3solver);
else
r = (Z3_lbool)Native.Z3_solver_check_assumptions(nCtx, z3solver, (uint)assumptions.Length, assumptions);
return lboolToStatus(r);
}
/// <summary>
/// Checks whether the assertions in the solver are consistent or not.
/// </summary>
/// <remarks>
/// <seealso cref="Model"/>
/// <seealso cref="UnsatCore"/>
/// <seealso cref="Proof"/>
/// </remarks>
public Status Check(IEnumerable<Z3_ast> assumptions)
{
Z3_lbool r;
Z3_ast[] asms = assumptions.ToArray();
if (asms.Length == 0)
r = (Z3_lbool)Native.Z3_solver_check(nCtx, z3solver);
else
r = (Z3_lbool)Native.Z3_solver_check_assumptions(nCtx, z3solver, (uint)asms.Length, asms);
return lboolToStatus(r);
}
/// <summary>
/// The model of the last <c>Check(params Expr[] assumptions)</c>.
/// </summary>
/// <remarks>
/// The result is <c>null</c> if <c>Check(params Expr[] assumptions)</c> was not invoked before,
/// if its results was not <c>SATISFIABLE</c>, or if model production is not enabled.
/// </remarks>
public NativeModel Model
{
get
{
IntPtr x = Native.Z3_solver_get_model(nCtx, z3solver);
return x == IntPtr.Zero
? null
: new NativeModel(ntvContext, x);
}
}
/// <summary>
/// The proof of the last <c>Check(params Expr[] assumptions)</c>.
/// </summary>
/// <remarks>
/// The result is <c>null</c> if <c>Check(params Expr[] assumptions)</c> was not invoked before,
/// if its results was not <c>UNSATISFIABLE</c>, or if proof production is disabled.
/// </remarks>
public Z3_ast Proof
=> Native.Z3_solver_get_proof(nCtx, z3solver);
/// <summary>
/// The unsat core of the last <c>Check</c>.
/// </summary>
/// <remarks>
/// The unsat core is a subset of <c>Assertions</c>
/// The result is empty if <c>Check</c> was not invoked before,
/// if its results was not <c>UNSATISFIABLE</c>, or if core production is disabled.
/// </remarks>
public Z3_ast[] UnsatCore
=> ntvContext.ToArray(Native.Z3_solver_get_unsat_core(nCtx, z3solver));
/// <summary>
/// A brief justification of why the last call to <c>Check</c> returned <c>UNKNOWN</c>.
/// </summary>
public string ReasonUnknown
=> Native.Z3_solver_get_reason_unknown(nCtx, z3solver);
/// <summary>
/// Create a clone of the current solver with respect to <c>ctx</c>.
/// </summary>
public NativeSolver Translate(NativeContext ctx)
{
Debug.Assert(ctx != null);
return new NativeSolver(ctx, Native.Z3_solver_translate(nCtx, z3solver, ctx.nCtx));
}
/// <summary>
/// Import model converter from other solver.
/// </summary>
public void ImportModelConverter(NativeSolver src)
{
Debug.Assert(src != null);
Native.Z3_solver_import_model_converter(nCtx, src.z3solver, z3solver);
}
/// <summary>
/// Solver statistics.
/// </summary>
public Statistics.Entry[] Statistics
{
get
{
var stats = Native.Z3_solver_get_statistics(nCtx, z3solver);
return ntvContext.GetStatistics(stats);
}
}
/// <summary>
/// A string representation of the solver.
/// </summary>
public override string ToString()
{
return Native.Z3_solver_to_string(nCtx, z3solver);
}
#region Internal
readonly NativeContext ntvContext;
Z3_solver z3solver;
Z3_context nCtx => ntvContext.nCtx;
internal NativeSolver(NativeContext nativeCtx, Z3_solver z3solver)
{
Debug.Assert(nativeCtx != null);
Debug.Assert(z3solver != IntPtr.Zero);
this.ntvContext = nativeCtx;
this.z3solver = z3solver;
Native.Z3_solver_inc_ref(nCtx, z3solver);
}
/// <summary>
/// Finalizer.
/// </summary>
~NativeSolver()
{
Dispose();
}
/// <summary>
/// Disposes of the underlying native Z3 object.
/// </summary>
public void Dispose()
{
if (z3solver != IntPtr.Zero)
{
Native.Z3_solver_dec_ref(nCtx, z3solver);
z3solver = IntPtr.Zero;
}
GC.SuppressFinalize(this);
}
private Status lboolToStatus(Z3_lbool r)
{
switch (r)
{
case Z3_lbool.Z3_L_TRUE: return Status.SATISFIABLE;
case Z3_lbool.Z3_L_FALSE: return Status.UNSATISFIABLE;
default: return Status.UNKNOWN;
}
}
#endregion
}
}

View file

@ -212,7 +212,7 @@ namespace Microsoft.Z3
public Handle AssertSoft(BoolExpr constraint, uint weight, string group)
{
Context.CheckContextMatch(constraint);
Symbol s = Context.MkSymbol(group);
using Symbol s = Context.MkSymbol(group);
return new Handle(this, Native.Z3_optimize_assert_soft(Context.nCtx, NativeObject, constraint.NativeObject, weight.ToString(), s.NativeObject));
}
@ -289,7 +289,7 @@ namespace Microsoft.Z3
get
{
ASTVector core = new ASTVector(Context, Native.Z3_optimize_get_unsat_core(Context.nCtx, NativeObject));
using ASTVector core = new ASTVector(Context, Native.Z3_optimize_get_unsat_core(Context.nCtx, NativeObject));
return core.ToBoolExprArray();
}
}
@ -337,7 +337,7 @@ namespace Microsoft.Z3
/// </summary>
private Expr[] GetLowerAsVector(uint index)
{
ASTVector v = new ASTVector(Context, Native.Z3_optimize_get_lower_as_vector(Context.nCtx, NativeObject, index));
using ASTVector v = new ASTVector(Context, Native.Z3_optimize_get_lower_as_vector(Context.nCtx, NativeObject, index));
return v.ToExprArray();
}
@ -347,7 +347,7 @@ namespace Microsoft.Z3
/// </summary>
private Expr[] GetUpperAsVector(uint index)
{
ASTVector v = new ASTVector(Context, Native.Z3_optimize_get_upper_as_vector(Context.nCtx, NativeObject, index));
using ASTVector v = new ASTVector(Context, Native.Z3_optimize_get_upper_as_vector(Context.nCtx, NativeObject, index));
return v.ToExprArray();
}
@ -396,7 +396,7 @@ namespace Microsoft.Z3
get
{
ASTVector assertions = new ASTVector(Context, Native.Z3_optimize_get_assertions(Context.nCtx, NativeObject));
using ASTVector assertions = new ASTVector(Context, Native.Z3_optimize_get_assertions(Context.nCtx, NativeObject));
return assertions.ToBoolExprArray();
}
}
@ -409,7 +409,7 @@ namespace Microsoft.Z3
get
{
ASTVector objectives = new ASTVector(Context, Native.Z3_optimize_get_objectives(Context.nCtx, NativeObject));
using ASTVector objectives = new ASTVector(Context, Native.Z3_optimize_get_objectives(Context.nCtx, NativeObject));
return objectives.ToExprArray();
}
}

View file

@ -62,7 +62,7 @@ namespace Microsoft.Z3
{
get
{
IntNum n = Numerator;
using IntNum n = Numerator;
return BigInteger.Parse(n.ToString());
}
}
@ -74,7 +74,7 @@ namespace Microsoft.Z3
{
get
{
IntNum n = Denominator;
using IntNum n = Denominator;
return BigInteger.Parse(n.ToString());
}
}

View file

@ -58,43 +58,92 @@ namespace Microsoft.Z3
/// <summary>
/// Sets parameter on the solver
/// </summary>
public void Set(string name, bool value) { Parameters = Context.MkParams().Add(name, value); }
public void Set(string name, bool value)
{
using var parameters = Context.MkParams().Add(name, value);
Parameters = parameters;
}
/// <summary>
/// Sets parameter on the solver
/// </summary>
public void Set(string name, uint value) { Parameters = Context.MkParams().Add(name, value); }
public void Set(string name, uint value)
{
using var parameters = Context.MkParams().Add(name, value);
Parameters = parameters;
}
/// <summary>
/// Sets parameter on the solver
/// </summary>
public void Set(string name, double value) { Parameters = Context.MkParams().Add(name, value); }
public void Set(string name, double value)
{
using var parameters = Context.MkParams().Add(name, value);
Parameters = parameters;
}
/// <summary>
/// Sets parameter on the solver
/// </summary>
public void Set(string name, string value) { Parameters = Context.MkParams().Add(name, value); }
public void Set(string name, string value)
{
using var parameters = Context.MkParams().Add(name, value);
Parameters = parameters;
}
/// <summary>
/// Sets parameter on the solver
/// </summary>
public void Set(string name, Symbol value) { Parameters = Context.MkParams().Add(name, value); }
public void Set(string name, Symbol value)
{
using var parameters = Context.MkParams().Add(name, value);
Parameters = parameters;
}
/// <summary>
/// Sets parameter on the solver
/// </summary>
public void Set(Symbol name, bool value) { Parameters = Context.MkParams().Add(name, value); }
public void Set(Symbol name, bool value)
{
using var parameters = Context.MkParams().Add(name, value);
Parameters = parameters;
}
/// <summary>
/// Sets parameter on the solver
/// </summary>
public void Set(Symbol name, uint value) { Parameters = Context.MkParams().Add(name, value); }
public void Set(Symbol name, uint value)
{
using var parameters = Context.MkParams().Add(name, value);
Parameters = parameters;
}
/// <summary>
/// Sets parameter on the solver
/// </summary>
public void Set(Symbol name, double value) { Parameters = Context.MkParams().Add(name, value); }
public void Set(Symbol name, double value)
{
using var parameters = Context.MkParams().Add(name, value);
Parameters = parameters;
}
/// <summary>
/// Sets parameter on the solver
/// </summary>
public void Set(Symbol name, string value) { Parameters = Context.MkParams().Add(name, value); }
public void Set(Symbol name, string value)
{
using var parameters = Context.MkParams().Add(name, value);
Parameters = parameters;
}
/// <summary>
/// Sets parameter on the solver
/// </summary>
public void Set(Symbol name, Symbol value) { Parameters = Context.MkParams().Add(name, value); }
public void Set(Symbol name, Symbol value)
{
using var parameters = Context.MkParams().Add(name, value);
Parameters = parameters;
}
@ -245,7 +294,7 @@ namespace Microsoft.Z3
{
get
{
ASTVector assertions = new ASTVector(Context, Native.Z3_solver_get_assertions(Context.nCtx, NativeObject));
using ASTVector assertions = new ASTVector(Context, Native.Z3_solver_get_assertions(Context.nCtx, NativeObject));
return assertions.Size;
}
}
@ -258,7 +307,7 @@ namespace Microsoft.Z3
get
{
ASTVector assertions = new ASTVector(Context, Native.Z3_solver_get_assertions(Context.nCtx, NativeObject));
using ASTVector assertions = new ASTVector(Context, Native.Z3_solver_get_assertions(Context.nCtx, NativeObject));
return assertions.ToBoolExprArray();
}
}
@ -271,7 +320,7 @@ namespace Microsoft.Z3
get
{
ASTVector assertions = new ASTVector(Context, Native.Z3_solver_get_units(Context.nCtx, NativeObject));
using ASTVector assertions = new ASTVector(Context, Native.Z3_solver_get_units(Context.nCtx, NativeObject));
return assertions.ToBoolExprArray();
}
}
@ -330,9 +379,9 @@ namespace Microsoft.Z3
/// </remarks>
public Status Consequences(IEnumerable<BoolExpr> assumptions, IEnumerable<Expr> variables, out BoolExpr[] consequences)
{
ASTVector result = new ASTVector(Context);
ASTVector asms = new ASTVector(Context);
ASTVector vars = new ASTVector(Context);
using ASTVector result = new ASTVector(Context);
using ASTVector asms = new ASTVector(Context);
using ASTVector vars = new ASTVector(Context);
foreach (var asm in assumptions) asms.Push(asm);
foreach (var v in variables) vars.Push(v);
Z3_lbool r = (Z3_lbool)Native.Z3_solver_get_consequences(Context.nCtx, NativeObject, asms.NativeObject, vars.NativeObject, result.NativeObject);
@ -391,7 +440,7 @@ namespace Microsoft.Z3
get
{
ASTVector core = new ASTVector(Context, Native.Z3_solver_get_unsat_core(Context.nCtx, NativeObject));
using ASTVector core = new ASTVector(Context, Native.Z3_solver_get_unsat_core(Context.nCtx, NativeObject));
return core.ToBoolExprArray();
}
}
@ -424,14 +473,14 @@ namespace Microsoft.Z3
/// </summary>
public IEnumerable<BoolExpr[]> Cube()
{
ASTVector cv = new ASTVector(Context);
using ASTVector cv = new ASTVector(Context);
if (CubeVariables != null)
foreach (var b in CubeVariables) cv.Push(b);
while (true) {
var lvl = BacktrackLevel;
BacktrackLevel = uint.MaxValue;
ASTVector r = new ASTVector(Context, Native.Z3_solver_cube(Context.nCtx, NativeObject, cv.NativeObject, lvl));
using ASTVector r = new ASTVector(Context, Native.Z3_solver_cube(Context.nCtx, NativeObject, cv.NativeObject, lvl));
var v = r.ToBoolExprArray();
CubeVariables = cv.ToBoolExprArray();
if (v.Length == 1 && v[0].IsFalse) {

View file

@ -23,6 +23,9 @@ using System.Diagnostics;
namespace Microsoft.Z3
{
using Z3_context = System.IntPtr;
using Z3_stats = System.IntPtr;
/// <summary>
/// Objects of this class track statistical information about solvers.
/// </summary>
@ -123,25 +126,29 @@ namespace Microsoft.Z3
{
get
{
uint n = Size;
Entry[] res = new Entry[n];
for (uint i = 0; i < n; i++)
{
Entry e;
string k = Native.Z3_stats_get_key(Context.nCtx, NativeObject, i);
if (Native.Z3_stats_is_uint(Context.nCtx, NativeObject, i) != 0)
e = new Entry(k, Native.Z3_stats_get_uint_value(Context.nCtx, NativeObject, i));
else if (Native.Z3_stats_is_double(Context.nCtx, NativeObject, i) != 0)
e = new Entry(k, Native.Z3_stats_get_double_value(Context.nCtx, NativeObject, i));
else
throw new Z3Exception("Unknown data entry value");
res[i] = e;
}
return res;
return NativeEntries(Context.nCtx, NativeObject);
}
}
internal static Entry[] NativeEntries(Z3_context ctx, Z3_stats stats)
{
uint n = Native.Z3_stats_size(ctx, stats);
Entry[] res = new Entry[n];
for (uint i = 0; i < n; i++)
{
Entry e;
string k = Native.Z3_stats_get_key(ctx, stats, i);
if (Native.Z3_stats_is_uint(ctx, stats, i) != 0)
e = new Entry(k, Native.Z3_stats_get_uint_value(ctx, stats, i));
else if (Native.Z3_stats_is_double(ctx, stats, i) != 0)
e = new Entry(k, Native.Z3_stats_get_double_value(ctx, stats, i));
else
throw new Z3Exception("Unknown data entry value");
res[i] = e;
}
return res;
}
/// <summary>
/// The statistical counters.
/// </summary>

View file

@ -2106,6 +2106,26 @@ public class Context implements AutoCloseable {
return (BoolExpr) Expr.create(this, Native.mkSeqContains(nCtx(), s1.getNativeObject(), s2.getNativeObject()));
}
/**
* Check if the string s1 is lexicographically strictly less than s2.
*/
public BoolExpr MkStringLt(SeqSort<CharSort> s1, SeqSort<CharSort> s2)
{
checkContextMatch(s1, s2);
return new BoolExpr(this, Native.mkStrLt(nCtx(), s1.getNativeObject(), s2.getNativeObject()));
}
/**
* Check if the string s1 is lexicographically less or equal to s2.
*/
public BoolExpr MkStringLe(SeqSort<CharSort> s1, SeqSort<CharSort> s2)
{
checkContextMatch(s1, s2);
return new BoolExpr(this, Native.mkStrLe(nCtx(), s1.getNativeObject(), s2.getNativeObject()));
}
/**
* Retrieve sequence of length one at index.
*/
@ -2180,6 +2200,14 @@ public class Context implements AutoCloseable {
return (ReExpr<R>) Expr.create(this, Native.mkReStar(nCtx(), re.getNativeObject()));
}
/**
* Create power regular expression.
*/
public <R extends Sort> ReExpr<R> mkPower(Expr<ReSort<R>> re, int n)
{
return (ReExpr<R>) Expr.create(this, Native.mkRePower(nCtx(), re.getNativeObject(), n));
}
/**
* Take the lower and upper-bounded Kleene star of a regular expression.
*/
@ -4038,6 +4066,37 @@ public class Context implements AutoCloseable {
return new BitVecExpr(this, Native.mkFpaToFpIntReal(nCtx(), rm.getNativeObject(), exp.getNativeObject(), sig.getNativeObject(), s.getNativeObject()));
}
/**
* Creates or a linear order.
* @param index The index of the order.
* @param sort The sort of the order.
*/
public <R extends Sort> FuncDecl<BoolSort> mkLinearOrder(R sort, int index) {
return (FuncDecl<BoolSort>) FuncDecl.create(
this,
Native.mkLinearOrder(
nCtx(),
sort.getNativeObject(),
index
)
);
}
/**
* Creates or a partial order.
* @param index The index of the order.
* @param sort The sort of the order.
*/
public <R extends Sort> FuncDecl<BoolSort> mkPartialOrder(R sort, int index) {
return (FuncDecl<BoolSort>) FuncDecl.create(
this,
Native.mkPartialOrder(
nCtx(),
sort.getNativeObject(),
index
)
);
}
/**
* Wraps an AST.

View file

@ -294,7 +294,8 @@ static struct custom_operations Z3_ast_plus_custom_ops = {
Z3_ast_compare_ext
};
MK_CTX_OF(ast, 16) // let's say 16 bytes per ast
// FUDGE
MK_CTX_OF(ast, 8) // let's say 16 bytes per ast
#define MK_PLUS_OBJ_NO_REF(X, USED) \
typedef struct { \
@ -410,25 +411,26 @@ MK_CTX_OF(ast, 16) // let's say 16 bytes per ast
\
MK_CTX_OF(X, USED)
MK_PLUS_OBJ_NO_REF(symbol, 32)
MK_PLUS_OBJ_NO_REF(constructor, 32)
MK_PLUS_OBJ_NO_REF(constructor_list, 32)
MK_PLUS_OBJ_NO_REF(rcf_num, 32)
MK_PLUS_OBJ(params, 128)
MK_PLUS_OBJ(param_descrs, 128)
MK_PLUS_OBJ(model, 512)
MK_PLUS_OBJ(func_interp, 128)
MK_PLUS_OBJ(func_entry, 128)
MK_PLUS_OBJ(goal, 128)
MK_PLUS_OBJ(tactic, 128)
MK_PLUS_OBJ(probe, 128)
MK_PLUS_OBJ(apply_result, 128)
MK_PLUS_OBJ(solver, 20 * 1000 * 1000) // pretend a solver is 20MB
MK_PLUS_OBJ(stats, 128)
MK_PLUS_OBJ(ast_map, 1024 * 2)
MK_PLUS_OBJ(ast_vector, 128)
MK_PLUS_OBJ(fixedpoint, 20 * 1000 * 1000)
MK_PLUS_OBJ(optimize, 20 * 1000 * 1000)
// FUDGE
MK_PLUS_OBJ_NO_REF(symbol, 16)
MK_PLUS_OBJ_NO_REF(constructor, 16)
MK_PLUS_OBJ_NO_REF(constructor_list, 16)
MK_PLUS_OBJ_NO_REF(rcf_num, 16)
MK_PLUS_OBJ(params, 64)
MK_PLUS_OBJ(param_descrs, 64)
MK_PLUS_OBJ(model, 64)
MK_PLUS_OBJ(func_interp, 32)
MK_PLUS_OBJ(func_entry, 32)
MK_PLUS_OBJ(goal, 64)
MK_PLUS_OBJ(tactic, 64)
MK_PLUS_OBJ(probe, 64)
MK_PLUS_OBJ(apply_result, 32)
MK_PLUS_OBJ(solver, 20 * 1000)
MK_PLUS_OBJ(stats, 32)
MK_PLUS_OBJ(ast_map, 32)
MK_PLUS_OBJ(ast_vector, 32)
MK_PLUS_OBJ(fixedpoint, 20 * 1000)
MK_PLUS_OBJ(optimize, 20 * 1000)
#ifdef __cplusplus
extern "C" {

View file

@ -42,8 +42,6 @@ add_custom_command(OUTPUT "${z3py_bindings_build_dest}/z3/z3core.py"
${Z3_FULL_PATH_API_HEADER_FILES_TO_SCAN}
"${PROJECT_SOURCE_DIR}/scripts/update_api.py"
${Z3_GENERATED_FILE_EXTRA_DEPENDENCIES}
# FIXME: When update_api.py no longer uses ``mk_util`` drop this dependency
"${PROJECT_SOURCE_DIR}/scripts/mk_util.py"
COMMENT "Generating z3core.py"
${ADD_CUSTOM_COMMAND_USES_TERMINAL_ARG}
)

View file

@ -5,3 +5,4 @@ recursive-include core *.cmake
recursive-include core/src *
recursive-include core/cmake *
recursive-include core/scripts *
include pyproject.toml

View file

@ -0,0 +1,3 @@
[build-system]
requires = ["setuptools>=46.4.0", "wheel", "cmake"]
build-backend = "setuptools.build_meta"

View file

@ -154,16 +154,10 @@ def _copy_bins():
_clean_bins()
python_dir = None
if RELEASE_DIR is not None:
python_dir = os.path.join(RELEASE_DIR, 'bin', 'python')
elif SRC_DIR == SRC_DIR_LOCAL:
python_dir = os.path.join(SRC_DIR, 'src', 'api', 'python')
if python_dir is not None:
py_z3_build_dir = os.path.join(BUILD_DIR, 'python', 'z3')
root_z3_dir = os.path.join(ROOT_DIR, 'z3')
shutil.copy(os.path.join(py_z3_build_dir, 'z3core.py'), root_z3_dir)
shutil.copy(os.path.join(py_z3_build_dir, 'z3consts.py'), root_z3_dir)
py_z3_build_dir = os.path.join(BUILD_DIR, 'python', 'z3')
root_z3_dir = os.path.join(ROOT_DIR, 'z3')
shutil.copy(os.path.join(py_z3_build_dir, 'z3core.py'), root_z3_dir)
shutil.copy(os.path.join(py_z3_build_dir, 'z3consts.py'), root_z3_dir)
# STEP 2: Copy the shared library, the executable and the headers
@ -184,6 +178,20 @@ def _copy_bins():
continue
shutil.copy(os.path.join(header_dir, fname), os.path.join(HEADERS_DIR, fname))
# This hack lets z3 installed libs link on M1 macs; it is a hack, not a proper fix
# @TODO: Linked issue: https://github.com/Z3Prover/z3/issues/5926
major_minor = '.'.join(_z3_version().split('.')[:2])
link_name = None
if BUILD_PLATFORM in ('win32', 'cygwin', 'win'):
pass # TODO: When windows VMs work on M1, fill this in
elif BUILD_PLATFORM in ('darwin', 'osx'):
split = LIBRARY_FILE.split('.')
link_name = split[0] + '.' + major_minor + '.' + split[1]
else:
link_name = LIBRARY_FILE + '.' + major_minor
if link_name:
os.symlink(LIBRARY_FILE, os.path.join(LIBS_DIR, link_name), True)
def _copy_sources():
"""
Prepare for a source distribution by assembling a minimal set of source files needed
@ -281,6 +289,8 @@ if 'bdist_wheel' in sys.argv and '--plat-name' not in sys.argv:
osver = '.'.join(osver.split('.')[:2])
if arch == 'x64':
plat_name ='macosx_%s_x86_64' % osver.replace('.', '_')
elif arch == 'arm64':
plat_name ='macosx_%s_arm64' % osver.replace('.', '_')
else:
raise Exception(f"idk how os {distos} {osver} works. what goes here?")
else:
@ -291,7 +301,6 @@ if 'bdist_wheel' in sys.argv and '--plat-name' not in sys.argv:
sys.argv.insert(idx + 1, plat_name)
sys.argv.insert(idx + 2, '--universal') # supports py2+py3. if --plat-name is not specified this will also mean that the package can be installed on any machine regardless of architecture, so watch out!
setup(
name='z3-solver',
version=_z3_version(),

View file

@ -12,8 +12,6 @@ Z3 is used in many applications such as: software/hardware verification and test
constraint solving, analysis of hybrid systems, security, biology (in silico analysis),
and geometrical problems.
Several online tutorials for Z3Py are available at:
http://rise4fun.com/Z3Py/tutorial/guide
Please send feedback, comments and/or corrections on the Issue tracker for
https://github.com/Z3prover/z3.git. Your comments are very valuable.
@ -103,9 +101,6 @@ def get_version():
def get_full_version():
return Z3_get_full_version()
# We use _z3_assert instead of the assert command because we want to
# produce nice error messages in Z3Py at rise4fun.com
def _z3_assert(cond, msg):
if not cond:
@ -1771,7 +1766,7 @@ def Xor(a, b, ctx=None):
>>> Xor(p, q)
Xor(p, q)
>>> simplify(Xor(p, q))
Not(p) == q
Not(p == q)
"""
ctx = _get_ctx(_ctx_from_ast_arg_list([a, b], ctx))
s = BoolSort(ctx)
@ -2015,8 +2010,7 @@ class QuantifierRef(BoolRef):
"""
if z3_debug():
_z3_assert(self.is_lambda(), "quantifier should be a lambda expression")
arg = self.sort().domain().cast(arg)
return _to_expr_ref(Z3_mk_select(self.ctx_ref(), self.as_ast(), arg.as_ast()), self.ctx)
return _array_select(self, arg)
def weight(self):
"""Return the weight annotation of `self`.
@ -2285,6 +2279,9 @@ class ArithSortRef(SortRef):
"""
return self.kind() == Z3_INT_SORT
def is_bool(self):
return False
def subsort(self, other):
"""Return `True` if `self` is a subsort of `other`."""
return self.is_int() and is_arith_sort(other) and other.is_real()
@ -4496,6 +4493,11 @@ class ArraySortRef(SortRef):
"""
return _to_sort_ref(Z3_get_array_sort_domain(self.ctx_ref(), self.ast), self.ctx)
def domain_n(self, i):
"""Return the domain of the array sort `self`.
"""
return _to_sort_ref(Z3_get_array_sort_domain_n(self.ctx_ref(), self.ast, i), self.ctx)
def range(self):
"""Return the range of the array sort `self`.
@ -4527,6 +4529,10 @@ class ArrayRef(ExprRef):
"""
return self.sort().domain()
def domain_n(self, i):
"""Shorthand for self.sort().domain_n(i)`."""
return self.sort().domain_n(i)
def range(self):
"""Shorthand for `self.sort().range()`.
@ -4546,13 +4552,21 @@ class ArrayRef(ExprRef):
>>> a[i].sexpr()
'(select a i)'
"""
arg = self.domain().cast(arg)
return _to_expr_ref(Z3_mk_select(self.ctx_ref(), self.as_ast(), arg.as_ast()), self.ctx)
return _array_select(self, arg)
def default(self):
return _to_expr_ref(Z3_mk_array_default(self.ctx_ref(), self.as_ast()), self.ctx)
def _array_select(ar, arg):
if isinstance(arg, tuple):
args = [ar.domain_n(i).cast(arg[i]) for i in range(len(arg))]
_args, sz = _to_ast_array(args)
return _to_expr_ref(Z3_mk_select_n(ar.ctx_ref(), ar.as_ast(), sz, _args), ar.ctx)
arg = ar.domain().cast(arg)
return _to_expr_ref(Z3_mk_select(ar.ctx_ref(), ar.as_ast(), arg.as_ast()), ar.ctx)
def is_array_sort(a):
return Z3_get_sort_kind(a.ctx.ref(), Z3_get_sort(a.ctx.ref(), a.ast)) == Z3_ARRAY_SORT
@ -4679,7 +4693,7 @@ def ArraySort(*sig):
return ArraySortRef(Z3_mk_array_sort_n(ctx.ref(), arity, dom, r.ast), ctx)
def Array(name, dom, rng):
def Array(name, *sorts):
"""Return an array constant named `name` with the given domain and range sorts.
>>> a = Array('a', IntSort(), IntSort())
@ -4688,12 +4702,12 @@ def Array(name, dom, rng):
>>> a[0]
a[0]
"""
s = ArraySort(dom, rng)
s = ArraySort(sorts)
ctx = s.ctx
return ArrayRef(Z3_mk_const(ctx.ref(), to_symbol(name, ctx), s.ast), ctx)
def Update(a, i, v):
def Update(a, *args):
"""Return a Z3 store array expression.
>>> a = Array('a', IntSort(), IntSort())
@ -4709,10 +4723,20 @@ def Update(a, i, v):
"""
if z3_debug():
_z3_assert(is_array_sort(a), "First argument must be a Z3 array expression")
i = a.sort().domain().cast(i)
v = a.sort().range().cast(v)
args = _get_args(args)
ctx = a.ctx
return _to_expr_ref(Z3_mk_store(ctx.ref(), a.as_ast(), i.as_ast(), v.as_ast()), ctx)
if len(args) <= 1:
raise Z3Exception("array update requires index and value arguments")
if len(args) == 2:
i = args[0]
v = args[1]
i = a.sort().domain().cast(i)
v = a.sort().range().cast(v)
return _to_expr_ref(Z3_mk_store(ctx.ref(), a.as_ast(), i.as_ast(), v.as_ast()), ctx)
v = a.sort().range().cast(args[-1])
idxs = [a.sort().domain_n(i).cast(args[i]) for i in range(len(args)-1)]
_args, sz = _to_ast_array(idxs)
return _to_expr_ref(Z3_mk_store_n(ctx.ref(), a.as_ast(), sz, _args, v.as_ast()), ctx)
def Default(a):
@ -4726,7 +4750,7 @@ def Default(a):
return a.default()
def Store(a, i, v):
def Store(a, *args):
"""Return a Z3 store array expression.
>>> a = Array('a', IntSort(), IntSort())
@ -4740,10 +4764,10 @@ def Store(a, i, v):
>>> prove(Implies(i != j, s[j] == a[j]))
proved
"""
return Update(a, i, v)
return Update(a, args)
def Select(a, i):
def Select(a, *args):
"""Return a Z3 select array expression.
>>> a = Array('a', IntSort(), IntSort())
@ -4753,9 +4777,10 @@ def Select(a, i):
>>> eq(Select(a, i), a[i])
True
"""
args = _get_args(args)
if z3_debug():
_z3_assert(is_array_sort(a), "First argument must be a Z3 array expression")
return a[i]
return a[args]
def Map(f, *args):
@ -6569,6 +6594,19 @@ class ModelRef(Z3PPObject):
"""Update the interpretation of a constant"""
if is_expr(x):
x = x.decl()
if is_func_decl(x) and x.arity() != 0 and isinstance(value, FuncInterp):
fi1 = value.f
fi2 = Z3_add_func_interp(x.ctx_ref(), self.model, x.ast, value.else_value().ast);
fi2 = FuncInterp(fi2, x.ctx)
for i in range(value.num_entries()):
e = value.entry(i)
n = Z3_func_entry_get_num_args(x.ctx_ref(), e.entry)
v = AstVector()
for j in range(n):
v.push(entry.arg_value(j))
val = Z3_func_entry_get_value(x.ctx_ref(), e.entry)
Z3_func_interp_add_entry(x.ctx_ref(), fi2.f, v.vector, val)
return
if not is_func_decl(x) or x.arity() != 0:
raise Z3Exception("Expecting 0-ary function or constant expression")
value = _py2expr(value)
@ -8856,7 +8894,7 @@ def _pb_args_coeffs(args, default_ctx=None):
for i in range(len(coeffs)):
_z3_check_cint_overflow(coeffs[i], "coefficient")
_coeffs[i] = coeffs[i]
return ctx, sz, _args, _coeffs
return ctx, sz, _args, _coeffs, args
def PbLe(args, k):
@ -8866,7 +8904,7 @@ def PbLe(args, k):
>>> f = PbLe(((a,1),(b,3),(c,2)), 3)
"""
_z3_check_cint_overflow(k, "k")
ctx, sz, _args, _coeffs = _pb_args_coeffs(args)
ctx, sz, _args, _coeffs, args = _pb_args_coeffs(args)
return BoolRef(Z3_mk_pble(ctx.ref(), sz, _args, _coeffs, k), ctx)
@ -8877,7 +8915,7 @@ def PbGe(args, k):
>>> f = PbGe(((a,1),(b,3),(c,2)), 3)
"""
_z3_check_cint_overflow(k, "k")
ctx, sz, _args, _coeffs = _pb_args_coeffs(args)
ctx, sz, _args, _coeffs, args = _pb_args_coeffs(args)
return BoolRef(Z3_mk_pbge(ctx.ref(), sz, _args, _coeffs, k), ctx)
@ -8888,7 +8926,7 @@ def PbEq(args, k, ctx=None):
>>> f = PbEq(((a,1),(b,3),(c,2)), 3)
"""
_z3_check_cint_overflow(k, "k")
ctx, sz, _args, _coeffs = _pb_args_coeffs(args)
ctx, sz, _args, _coeffs, args = _pb_args_coeffs(args)
return BoolRef(Z3_mk_pbeq(ctx.ref(), sz, _args, _coeffs, k), ctx)
@ -8982,7 +9020,7 @@ def prove(claim, show=False, **keywords):
def _solve_html(*args, **keywords):
"""Version of function `solve` used in RiSE4Fun."""
"""Version of function `solve` that renders HTML output."""
show = keywords.pop("show", False)
s = Solver()
s.set(**keywords)
@ -9006,7 +9044,7 @@ def _solve_html(*args, **keywords):
def _solve_using_html(s, *args, **keywords):
"""Version of function `solve_using` used in RiSE4Fun."""
"""Version of function `solve_using` that renders HTML."""
show = keywords.pop("show", False)
if z3_debug():
_z3_assert(isinstance(s, Solver), "Solver object expected")
@ -9031,7 +9069,7 @@ def _solve_using_html(s, *args, **keywords):
def _prove_html(claim, show=False, **keywords):
"""Version of function `prove` used in RiSE4Fun."""
"""Version of function `prove` that renders HTML."""
if z3_debug():
_z3_assert(is_bool(claim), "Z3 Boolean expression expected")
s = Solver()
@ -11215,12 +11253,16 @@ def ensure_prop_closures():
_prop_closures = PropClosures()
def user_prop_push(ctx):
_prop_closures.get(ctx).push()
def user_prop_push(ctx, cb):
prop = _prop_closures.get(ctx)
prop.cb = cb
prop.push()
def user_prop_pop(ctx, num_scopes):
_prop_closures.get(ctx).pop(num_scopes)
def user_prop_pop(ctx, cb, num_scopes):
prop = _prop_closures.get(ctx)
prop.cb = cb
pop(num_scopes)
def user_prop_fresh(id, ctx):
@ -11230,31 +11272,38 @@ def user_prop_fresh(id, ctx):
_prop_closures.set(new_prop.id, new_prop)
return ctypes.c_void_p(new_prop.id)
def to_Ast(ptr,):
ast = Ast(ptr)
super(ctypes.c_void_p, ast).__init__(ptr)
return ast
def user_prop_fixed(ctx, cb, id, value):
prop = _prop_closures.get(ctx)
prop.cb = cb
prop.fixed(id, _to_expr_ref(ctypes.c_void_p(value), prop.ctx()))
id = _to_expr_ref(to_Ast(id), prop.ctx())
value = _to_expr_ref(to_Ast(value), prop.ctx())
prop.fixed(id, value)
prop.cb = None
def user_prop_final(ctx, cb):
prop = _prop_closures.get(ctx)
prop.cb = cb
prop.final()
prop.cb = None
def user_prop_eq(ctx, cb, x, y):
prop = _prop_closures.get(ctx)
prop.cb = cb
x = _to_expr_ref(to_Ast(x), prop.ctx())
y = _to_expr_ref(to_Ast(y), prop.ctx())
prop.eq(x, y)
prop.cb = None
def user_prop_diseq(ctx, cb, x, y):
prop = _prop_closures.get(ctx)
prop.cb = cb
x = _to_expr_ref(to_Ast(x), prop.ctx())
y = _to_expr_ref(to_Ast(y), prop.ctx())
prop.diseq(x, y)
prop.cb = None
@ -11352,24 +11401,18 @@ class UserPropagateBase:
def add(self, e):
assert self.solver
assert not self._ctx
return Z3_solver_propagate_register(self.ctx_ref(), self.solver.solver, e.ast)
Z3_solver_propagate_register(self.ctx_ref(), self.solver.solver, e.ast)
#
# Propagation can only be invoked as during a fixed or final callback.
#
def propagate(self, e, ids, eqs=[]):
num_fixed = len(ids)
_ids = (ctypes.c_uint * num_fixed)()
for i in range(num_fixed):
_ids[i] = ids[i]
_ids, num_fixed = _to_ast_array(ids)
num_eqs = len(eqs)
_lhs = (ctypes.c_uint * num_eqs)()
_rhs = (ctypes.c_uint * num_eqs)()
for i in range(num_eqs):
_lhs[i] = eqs[i][0]
_rhs[i] = eqs[i][1]
_lhs, _num_lhs = _to_ast_array([x for x, y in eqs])
_rhs, _num_rhs = _to_ast_array([y for x, y in eqs])
Z3_solver_propagate_consequence(e.ctx.ref(), ctypes.c_void_p(
self.cb), num_fixed, _ids, num_eqs, _lhs, _rhs, e.ast)
def conflict(self, ids):
self.propagate(BoolVal(False, self.ctx()), ids, eqs=[])
def conflict(self, deps):
self.propagate(BoolVal(False, self.ctx()), deps, eqs=[])

View file

@ -996,6 +996,8 @@ typedef enum
information is exposed. Tools may use the string representation of the
function declaration to obtain more information.
- Z3_OP_RECURSIVE: function declared as recursive
- Z3_OP_UNINTERPRETED: kind used for uninterpreted symbols.
*/
typedef enum {
@ -1220,13 +1222,17 @@ typedef enum {
Z3_OP_RE_CONCAT,
Z3_OP_RE_UNION,
Z3_OP_RE_RANGE,
Z3_OP_RE_DIFF,
Z3_OP_RE_INTERSECT,
Z3_OP_RE_LOOP,
Z3_OP_RE_POWER,
Z3_OP_RE_INTERSECT,
Z3_OP_RE_DIFF,
Z3_OP_RE_COMPLEMENT,
Z3_OP_RE_EMPTY_SET,
Z3_OP_RE_FULL_SET,
Z3_OP_RE_COMPLEMENT,
Z3_OP_RE_FULL_CHAR_SET,
Z3_OP_RE_OF_PRED,
Z3_OP_RE_REVERSE,
Z3_OP_RE_DERIVATIVE,
// char
Z3_OP_CHAR_CONST,
@ -1316,6 +1322,7 @@ typedef enum {
Z3_OP_FPA_BV2RM,
Z3_OP_INTERNAL,
Z3_OP_RECURSIVE,
Z3_OP_UNINTERPRETED
} Z3_decl_kind;
@ -1430,13 +1437,14 @@ Z3_DECLARE_CLOSURE(Z3_error_handler, void, (Z3_context c, Z3_error_code e));
/**
\brief callback functions for user propagator.
*/
Z3_DECLARE_CLOSURE(Z3_push_eh, void, (void* ctx));
Z3_DECLARE_CLOSURE(Z3_pop_eh, void, (void* ctx, unsigned num_scopes));
Z3_DECLARE_CLOSURE(Z3_push_eh, void, (void* ctx, Z3_solver_callback cb));
Z3_DECLARE_CLOSURE(Z3_pop_eh, void, (void* ctx, Z3_solver_callback cb, unsigned num_scopes));
Z3_DECLARE_CLOSURE(Z3_fresh_eh, void*, (void* ctx, Z3_context new_context));
Z3_DECLARE_CLOSURE(Z3_fixed_eh, void, (void* ctx, Z3_solver_callback cb, unsigned id, Z3_ast value));
Z3_DECLARE_CLOSURE(Z3_eq_eh, void, (void* ctx, Z3_solver_callback cb, unsigned x, unsigned y));
Z3_DECLARE_CLOSURE(Z3_fixed_eh, void, (void* ctx, Z3_solver_callback cb, Z3_ast t, Z3_ast value));
Z3_DECLARE_CLOSURE(Z3_eq_eh, void, (void* ctx, Z3_solver_callback cb, Z3_ast s, Z3_ast t));
Z3_DECLARE_CLOSURE(Z3_final_eh, void, (void* ctx, Z3_solver_callback cb));
Z3_DECLARE_CLOSURE(Z3_created_eh, void, (void* ctx, Z3_solver_callback cb, Z3_ast e, unsigned id));
Z3_DECLARE_CLOSURE(Z3_created_eh, void, (void* ctx, Z3_solver_callback cb, Z3_ast t));
Z3_DECLARE_CLOSURE(Z3_decide_eh, void, (void* ctx, Z3_solver_callback cb, Z3_ast*, unsigned*, Z3_lbool*));
/**
@ -3817,6 +3825,13 @@ extern "C" {
*/
Z3_ast Z3_API Z3_mk_re_loop(Z3_context c, Z3_ast r, unsigned lo, unsigned hi);
/**
\brief Create a power regular expression.
def_API('Z3_mk_re_power', AST, (_in(CONTEXT), _in(AST), _in(UINT)))
*/
Z3_ast Z3_API Z3_mk_re_power(Z3_context c, Z3_ast, unsigned n);
/**
\brief Create the intersection of the regular languages.
@ -4358,11 +4373,27 @@ extern "C" {
\sa Z3_mk_array_sort
\sa Z3_get_sort_kind
\sa Z3_get_array_sort_domain_n
def_API('Z3_get_array_sort_domain', SORT, (_in(CONTEXT), _in(SORT)))
*/
Z3_sort Z3_API Z3_get_array_sort_domain(Z3_context c, Z3_sort t);
/**
\brief Return the i'th domain sort of an n-dimensional array.
\pre Z3_get_sort_kind(c, t) == Z3_ARRAY_SORT
\sa Z3_mk_array_sort
\sa Z3_get_sort_kind
\sa Z3_get_array_sort_domain
def_API('Z3_get_array_sort_domain_n', SORT, (_in(CONTEXT), _in(SORT), _in(UINT)))
*/
Z3_sort Z3_API Z3_get_array_sort_domain_n(Z3_context c, Z3_sort t, unsigned idx);
/**
\brief Return the range of the given array sort.
@ -6672,6 +6703,13 @@ extern "C" {
/**
\brief register a user-properator with the solver.
\param c - context.
\param s - solver object.
\param user_context - a context used to maintain state for callbacks.
\param push_eh - a callback invoked when scopes are pushed
\param pop_eh - a callback invoked when scopes are poped
\param fresh_eh - a solver may spawn new solvers internally. This callback is used to produce a fresh user_context to be associated with fresh solvers.
*/
void Z3_API Z3_solver_propagate_init(
@ -6694,11 +6732,15 @@ extern "C" {
/**
\brief register a callback on final check.
This provides freedom to the propagator to delay actions or implement a branch-and bound solver.
The final check is invoked when all decision variables have been assigned by the solver.
The final_eh callback takes as argument the original user_context that was used
when calling \c Z3_solver_propagate_init, and it takes a callback context for propagations.
If may use the callback context to invoke the \c Z3_solver_propagate_consequence function.
If the callback context gets used, the solver continues.
The \c final_eh callback takes as argument the original user_context that was used
when calling \c Z3_solver_propagate_init, and it takes a callback context with the
opaque type \c Z3_solver_callback.
The callback context is passed as argument to invoke the \c Z3_solver_propagate_consequence function.
The callback context can only be accessed (for propagation and for dynamically registering expressions) within a callback.
If the callback context gets used for propagation or conflicts, those propagations take effect and
may trigger new decision variables to be set.
*/
void Z3_API Z3_solver_propagate_final(Z3_context c, Z3_solver s, Z3_final_eh final_eh);
@ -6717,6 +6759,14 @@ extern "C" {
* The registered function appears at the top level and is created using \ref Z3_propagate_solver_declare.
*/
void Z3_API Z3_solver_propagate_created(Z3_context c, Z3_solver s, Z3_created_eh created_eh);
/**
* \brief register a callback when a the solver decides to split on a registered expression
* The callback may set passed expression to another registered expression which will be selected instead.
* In case the expression is a bitvector the bit to split on is determined by the bit argument and the
* truth-value to try first is given by is_pos
*/
void Z3_API Z3_solver_propagate_decide(Z3_context c, Z3_solver s, Z3_decide_eh decide_eh);
/**
Create uninterpreted function declaration for the user propagator.
@ -6734,10 +6784,10 @@ extern "C" {
\brief register an expression to propagate on with the solver.
Only expressions of type Bool and type Bit-Vector can be registered for propagation.
def_API('Z3_solver_propagate_register', UINT, (_in(CONTEXT), _in(SOLVER), _in(AST)))
def_API('Z3_solver_propagate_register', VOID, (_in(CONTEXT), _in(SOLVER), _in(AST)))
*/
unsigned Z3_API Z3_solver_propagate_register(Z3_context c, Z3_solver s, Z3_ast e);
void Z3_API Z3_solver_propagate_register(Z3_context c, Z3_solver s, Z3_ast e);
/**
\brief register an expression to propagate on with the solver.
@ -6745,9 +6795,9 @@ extern "C" {
Unlike \ref Z3_solver_propagate_register, this function takes a solver callback context
as argument. It can be invoked during a callback to register new expressions.
def_API('Z3_solver_propagate_register_cb', UINT, (_in(CONTEXT), _in(SOLVER_CALLBACK), _in(AST)))
def_API('Z3_solver_propagate_register_cb', VOID, (_in(CONTEXT), _in(SOLVER_CALLBACK), _in(AST)))
*/
unsigned Z3_API Z3_solver_propagate_register_cb(Z3_context c, Z3_solver_callback cb, Z3_ast e);
void Z3_API Z3_solver_propagate_register_cb(Z3_context c, Z3_solver_callback cb, Z3_ast e);
/**
\brief propagate a consequence based on fixed values.
@ -6755,10 +6805,10 @@ extern "C" {
The callback adds a propagation consequence based on the fixed values of the
\c ids.
def_API('Z3_solver_propagate_consequence', VOID, (_in(CONTEXT), _in(SOLVER_CALLBACK), _in(UINT), _in_array(2, UINT), _in(UINT), _in_array(4, UINT), _in_array(4, UINT), _in(AST)))
def_API('Z3_solver_propagate_consequence', VOID, (_in(CONTEXT), _in(SOLVER_CALLBACK), _in(UINT), _in_array(2, AST), _in(UINT), _in_array(4, AST), _in_array(4, AST), _in(AST)))
*/
void Z3_API Z3_solver_propagate_consequence(Z3_context c, Z3_solver_callback, unsigned num_fixed, unsigned const* fixed_ids, unsigned num_eqs, unsigned const* eq_lhs, unsigned const* eq_rhs, Z3_ast conseq);
void Z3_API Z3_solver_propagate_consequence(Z3_context c, Z3_solver_callback, unsigned num_fixed, Z3_ast const* fixed, unsigned num_eqs, Z3_ast const* eq_lhs, Z3_ast const* eq_rhs, Z3_ast conseq);
/**
\brief Check whether the assertions in a given solver are consistent or not.

View file

@ -82,7 +82,7 @@ extern "C" {
\param c - context
\param o - optimization context
\param a - formula
\param weight - a positive weight, penalty for violating soft constraint
\param weight - a penalty for violating soft constraint. Negative weights convert into rewards.
\param id - optional identifier to group soft constraints
\sa Z3_optimize_assert

View file

@ -27,6 +27,7 @@ Revision History:
#include "ast/ast_util.h"
#include "ast/ast_smt2_pp.h"
#include "ast/array_decl_plugin.h"
#include "ast/arith_decl_plugin.h"
#include "ast/ast_translation.h"
#include "util/z3_version.h"
@ -233,8 +234,7 @@ std::ostream& operator<<(std::ostream& out, sort_size const & ss) {
// -----------------------------------
std::ostream & operator<<(std::ostream & out, sort_info const & info) {
operator<<(out, static_cast<decl_info const&>(info));
out << " :size " << info.get_num_elements();
return out;
return out << " :size " << info.get_num_elements();
}
// -----------------------------------
@ -1758,13 +1758,13 @@ ast * ast_manager::register_node_core(ast * n) {
switch (n->get_kind()) {
case AST_SORT:
if (to_sort(n)->m_info != nullptr) {
to_sort(n)->m_info = alloc(sort_info, *(to_sort(n)->get_info()));
to_sort(n)->m_info = alloc(sort_info, std::move(*(to_sort(n)->get_info())));
to_sort(n)->m_info->init_eh(*this);
}
break;
case AST_FUNC_DECL:
if (to_func_decl(n)->m_info != nullptr) {
to_func_decl(n)->m_info = alloc(func_decl_info, *(to_func_decl(n)->get_info()));
to_func_decl(n)->m_info = alloc(func_decl_info, std::move(*(to_func_decl(n)->get_info())));
to_func_decl(n)->m_info->init_eh(*this);
}
inc_array_ref(to_func_decl(n)->get_arity(), to_func_decl(n)->get_domain());
@ -1992,7 +1992,7 @@ sort * ast_manager::substitute(sort* s, unsigned n, sort * const * src, sort * c
return s;
}
decl_info dinfo(s->get_family_id(), s->get_decl_kind(), ps.size(), ps.data(), s->private_parameters());
sort_info sinfo(dinfo, s->get_num_elements());
sort_info sinfo(std::move(dinfo), s->get_num_elements());
return mk_sort(s->get_name(), &sinfo);
}
@ -2131,12 +2131,17 @@ bool ast_manager::coercion_needed(func_decl * decl, unsigned num_args, expr * co
expr* ast_manager::coerce_to(expr* e, sort* s) {
sort* se = e->get_sort();
if (s != se && s->get_family_id() == arith_family_id && se->get_family_id() == arith_family_id) {
if (s->get_decl_kind() == REAL_SORT) {
if (s->get_decl_kind() == REAL_SORT)
return mk_app(arith_family_id, OP_TO_REAL, e);
}
else {
return mk_app(arith_family_id, OP_TO_INT, e);
}
else
return mk_app(arith_family_id, OP_TO_INT, e);
}
if (s != se && s->get_family_id() == arith_family_id && is_bool(e)) {
arith_util au(*this);
if (s->get_decl_kind() == REAL_SORT)
return mk_ite(e, au.mk_real(1), au.mk_real(0));
else
return mk_ite(e, au.mk_int(1), au.mk_int(0));
}
else {
return e;
@ -2231,7 +2236,7 @@ app * ast_manager::mk_app(func_decl * decl, unsigned num_args, expr * const * ar
std::ostringstream buffer;
buffer << "Wrong number of arguments (" << num_args
<< ") passed to function " << mk_pp(decl, *this);
throw ast_exception(buffer.str());
throw ast_exception(std::move(buffer).str());
}
app * r = nullptr;
if (num_args == 1 && decl->is_chainable() && decl->get_arity() == 2) {

View file

@ -367,8 +367,8 @@ public:
decl_info(family_id, k, num_parameters, parameters, private_parameters), m_num_elements(num_elements) {
}
sort_info(decl_info const& di, sort_size const& num_elements) :
decl_info(di), m_num_elements(num_elements) {}
sort_info(decl_info && di, sort_size const& num_elements) :
decl_info(std::move(di)), m_num_elements(num_elements) {}
bool is_infinite() const { return m_num_elements.is_infinite(); }
bool is_very_big() const { return m_num_elements.is_very_big(); }

View file

@ -47,18 +47,14 @@ format * smt2_pp_environment::pp_fdecl_name(symbol const & s, unsigned & len, bo
len = static_cast<unsigned>(str.length());
return mk_string(m, str);
}
else if (s.is_numerical()) {
std::string str = s.str();
len = static_cast<unsigned>(str.length());
return mk_string(m, str);
}
else if (!s.bare_str()) {
else if (s.is_null()) {
len = 4;
return mk_string(m, "null");
}
else {
len = static_cast<unsigned>(strlen(s.bare_str()));
return mk_string(m, s.bare_str());
std::string str = s.str();
len = static_cast<unsigned>(str.length());
return mk_string(m, str);
}
}

View file

@ -170,12 +170,20 @@ void ast_translation::mk_func_decl(func_decl * f, frame & fr) {
new_fi.set_injective(fi->is_injective());
new_fi.set_skolem(fi->is_skolem());
new_fi.set_idempotent(fi->is_idempotent());
new_fi.set_lambda(fi->is_lambda());
new_f = m_to_manager.mk_func_decl(f->get_name(),
f->get_arity(),
new_domain,
new_range,
new_fi);
if (new_fi.is_lambda()) {
quantifier* q = from().is_lambda_def(f);
ast_translation tr(from(), to());
quantifier* new_q = tr(q);
to().add_lambda_def(new_f, new_q);
}
}
TRACE("ast_translation",
tout << f->get_name() << " "; if (fi) tout << *fi; tout << "\n";

View file

@ -886,8 +886,8 @@ app * bv_util::mk_numeral(rational const & val, unsigned bv_size) const {
}
sort * bv_util::mk_sort(unsigned bv_size) {
parameter p[1] = { parameter(bv_size) };
return m_manager.mk_sort(get_fid(), BV_SORT, 1, p);
parameter p(bv_size);
return m_manager.mk_sort(get_fid(), BV_SORT, 1, &p);
}
unsigned bv_util::get_int2bv_size(parameter const& p) {

View file

@ -16,6 +16,7 @@ Author:
--*/
#include "util/gparams.h"
#include "ast/bv_decl_plugin.h"
#include "ast/char_decl_plugin.h"
#include "ast/arith_decl_plugin.h"
#include "ast/ast_pp.h"
@ -164,6 +165,14 @@ app* char_decl_plugin::mk_le(expr* a, expr* b) {
unsigned v1 = 0, v2 = 0;
if (a == b)
return m_manager->mk_true();
bv_util bv(*m_manager);
if (bv.is_bv(a))
return bv.mk_ule(a, b);
arith_util arith(*m_manager);
if (arith.is_int_real(a))
return arith.mk_le(a, b);
if (a->get_sort() != char_sort())
throw default_exception("range comparison is only supported for bit-vectors, int, real and characters");
bool c1 = is_const_char(a, v1);
bool c2 = is_const_char(b, v2);
if (c1 && c2)

View file

@ -69,8 +69,8 @@ namespace datatype {
domain.push_back(a->instantiate(ps)->get_range());
}
sort_ref range = get_def().instantiate(ps);
parameter pas[1] = { parameter(name()) };
return func_decl_ref(m.mk_func_decl(u().get_family_id(), OP_DT_CONSTRUCTOR, 1, pas, domain.size(), domain.data(), range), m);
parameter pas(name());
return func_decl_ref(m.mk_func_decl(u().get_family_id(), OP_DT_CONSTRUCTOR, 1, &pas, domain.size(), domain.data(), range), m);
}
func_decl_ref constructor::instantiate(sort* dt) const {
@ -1052,8 +1052,8 @@ namespace datatype {
func_decl * util::get_constructor_is(func_decl * con) {
SASSERT(is_constructor(con));
sort * datatype = con->get_range();
parameter ps[1] = { parameter(con)};
return m.mk_func_decl(fid(), OP_DT_IS, 1, ps, 1, &datatype);
parameter ps(con);
return m.mk_func_decl(fid(), OP_DT_IS, 1, &ps, 1, &datatype);
}
func_decl * util::get_constructor_recognizer(func_decl * con) {

View file

@ -293,11 +293,12 @@ namespace euf {
VERIFY(n->num_args() == 0 || !n->merge_enabled() || m_table.contains(n));
}
void egraph::set_value(enode* n, lbool value) {
void egraph::set_value(enode* n, lbool value, justification j) {
if (n->value() == l_undef) {
force_push();
TRACE("euf", tout << bpp(n) << " := " << value << "\n";);
n->set_value(value);
n->m_lit_justification = j;
m_updates.push_back(update_record(n, update_record::value_assignment()));
}
}
@ -657,6 +658,7 @@ namespace euf {
push_lca(n1->get_arg(1), n2->get_arg(0));
return;
}
TRACE("euf_verbose", tout << bpp(n1) << " " << bpp(n2) << "\n");
for (unsigned i = 0; i < n1->num_args(); ++i)
push_lca(n1->get_arg(i), n2->get_arg(i));
@ -713,6 +715,15 @@ namespace euf {
explain_todo(justifications);
}
template <typename T>
void egraph::explain_eq(ptr_vector<T>& justifications, enode* a, enode* b, justification const& j) {
if (j.is_external())
justifications.push_back(j.ext<T>());
else if (j.is_congruence())
push_congruence(a, b, j.is_commutative());
}
template <typename T>
void egraph::explain_eq(ptr_vector<T>& justifications, enode* a, enode* b) {
SASSERT(a->get_root() == b->get_root());
@ -746,11 +757,21 @@ namespace euf {
void egraph::explain_todo(ptr_vector<T>& justifications) {
for (unsigned i = 0; i < m_todo.size(); ++i) {
enode* n = m_todo[i];
if (n->m_target && !n->is_marked1()) {
if (n->is_marked1())
continue;
if (n->m_target) {
n->mark1();
CTRACE("euf_verbose", m_display_justification, n->m_justification.display(tout << n->get_expr_id() << " = " << n->m_target->get_expr_id() << " ", m_display_justification) << "\n";);
explain_eq(justifications, n, n->m_target, n->m_justification);
}
else if (!n->is_marked1() && n->value() != l_undef) {
n->mark1();
if (m.is_true(n->get_expr()) || m.is_false(n->get_expr()))
continue;
justification j = n->m_lit_justification;
SASSERT(j.is_external());
justifications.push_back(j.ext<T>());
}
}
}

View file

@ -226,12 +226,8 @@ namespace euf {
void erase_from_table(enode* p);
template <typename T>
void explain_eq(ptr_vector<T>& justifications, enode* a, enode* b, justification const& j) {
if (j.is_external())
justifications.push_back(j.ext<T>());
else if (j.is_congruence())
push_congruence(a, b, j.is_commutative());
}
void explain_eq(ptr_vector<T>& justifications, enode* a, enode* b, justification const& j);
template <typename T>
void explain_todo(ptr_vector<T>& justifications);
@ -295,7 +291,7 @@ namespace euf {
void add_th_var(enode* n, theory_var v, theory_id id);
void set_th_propagates_diseqs(theory_id id);
void set_merge_enabled(enode* n, bool enable_merge);
void set_value(enode* n, lbool value);
void set_value(enode* n, lbool value, justification j);
void set_bool_var(enode* n, unsigned v) { n->set_bool_var(v); }
void set_relevant(enode* n);
void set_default_relevant(bool b) { m_default_relevant = b; }

View file

@ -63,6 +63,7 @@ namespace euf {
enode* m_cg = nullptr;
th_var_list m_th_vars;
justification m_justification;
justification m_lit_justification;
unsigned m_num_args = 0;
signed char m_lbl_hash = -1; // It is different from -1, if enode is used in a pattern
approx_set m_lbls;
@ -133,6 +134,7 @@ namespace euf {
void del_th_var(theory_id id) { m_th_vars.del_var(id); }
void set_merge_enabled(bool m) { m_merge_enabled = m; }
void set_value(lbool v) { m_value = v; }
void set_justification(justification j) { m_justification = j; }
void set_is_equality() { m_is_equality = true; }
void set_bool_var(sat::bool_var v) { m_bool_var = v; }

View file

@ -33,11 +33,9 @@ func_decl * pb_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters, p
unsigned arity, sort * const * domain, sort * range) {
SASSERT(m_manager);
ast_manager& m = *m_manager;
for (unsigned i = 0; i < arity; ++i) {
if (!m.is_bool(domain[i])) {
m.raise_exception("invalid non-Boolean sort applied to 'at-most'");
}
}
for (unsigned i = 0; i < arity; ++i)
if (!m.is_bool(domain[i]))
m.raise_exception("invalid non-Boolean sort applied to Pseudo-Boolean relation");
symbol sym;
switch(k) {
case OP_AT_LEAST_K: sym = m_at_least_sym; break;
@ -50,9 +48,8 @@ func_decl * pb_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters, p
switch(k) {
case OP_AT_LEAST_K:
case OP_AT_MOST_K: {
if (num_parameters != 1 || !parameters[0].is_int() || parameters[0].get_int() < 0) {
if (num_parameters != 1 || !parameters[0].is_int() || parameters[0].get_int() < 0)
m.raise_exception("function expects one non-negative integer parameter");
}
func_decl_info info(m_family_id, k, 1, parameters);
return m.mk_func_decl(sym, arity, domain, m.mk_bool_sort(), info);
}
@ -93,11 +90,11 @@ func_decl * pb_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters, p
void pb_decl_plugin::get_op_names(svector<builtin_name> & op_names, symbol const & logic) {
if (logic == symbol::null || logic == "QF_FD" || logic == "ALL" || logic == "HORN") {
op_names.push_back(builtin_name(m_at_most_sym.bare_str(), OP_AT_MOST_K));
op_names.push_back(builtin_name(m_at_least_sym.bare_str(), OP_AT_LEAST_K));
op_names.push_back(builtin_name(m_pble_sym.bare_str(), OP_PB_LE));
op_names.push_back(builtin_name(m_pbge_sym.bare_str(), OP_PB_GE));
op_names.push_back(builtin_name(m_pbeq_sym.bare_str(), OP_PB_EQ));
op_names.push_back(builtin_name(m_at_most_sym.str(), OP_AT_MOST_K));
op_names.push_back(builtin_name(m_at_least_sym.str(), OP_AT_LEAST_K));
op_names.push_back(builtin_name(m_pble_sym.str(), OP_PB_LE));
op_names.push_back(builtin_name(m_pbge_sym.str(), OP_PB_GE));
op_names.push_back(builtin_name(m_pbeq_sym.str(), OP_PB_EQ));
}
}

View file

@ -225,6 +225,11 @@ namespace recfun {
m_vars.append(n_vars, vars);
m_rhs = rhs;
if (!is_macro)
for (expr* e : subterms::all(m_rhs))
if (is_lambda(e))
throw default_exception("recursive definitions with lambdas are not supported");
expr_ref_vector conditions(m);
// is the function a macro (unconditional body)?
@ -233,6 +238,8 @@ namespace recfun {
add_case(name, 0, conditions, rhs);
return;
}
// analyze control flow of `rhs`, accumulating guards and
// rebuilding a `ite`-free RHS on the fly for each path in `rhs`.

View file

@ -9,6 +9,7 @@ z3_add_component(rewriter
bv_elim.cpp
bv_rewriter.cpp
cached_var_subst.cpp
char_rewriter.cpp
datatype_rewriter.cpp
der.cpp
distribute_forall.cpp

View file

@ -37,6 +37,7 @@ void bv_rewriter::updt_local_params(params_ref const & _p) {
m_extract_prop = p.bv_extract_prop();
m_ite2id = p.bv_ite2id();
m_le_extra = p.bv_le_extra();
m_le2extract = p.bv_le2extract();
set_sort_sums(p.bv_sort_ac());
}
@ -196,11 +197,11 @@ br_status bv_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * cons
SASSERT(num_args == 1);
return mk_bit2bool(args[0], f->get_parameter(0).get_int(), result);
case OP_BSMUL_NO_OVFL:
return mk_bvsmul_no_overflow(num_args, args, result);
return mk_bvsmul_no_overflow(num_args, args, true, result);
case OP_BSMUL_NO_UDFL:
return mk_bvsmul_no_overflow(num_args, args, false, result);
case OP_BUMUL_NO_OVFL:
return mk_bvumul_no_overflow(num_args, args, result);
case OP_BSMUL_NO_UDFL:
return mk_bvsmul_no_underflow(num_args, args, result);
default:
return BR_FAILED;
}
@ -577,7 +578,7 @@ br_status bv_rewriter::mk_leq_core(bool is_signed, expr * a, expr * b, expr_ref
result = m().mk_eq(a, m_util.mk_numeral(numeral(0), bv_sz));
return BR_REWRITE1;
}
else if (first_non_zero < bv_sz - 1) {
else if (first_non_zero < bv_sz - 1 && m_le2extract) {
result = m().mk_and(m().mk_eq(m_mk_extract(bv_sz - 1, first_non_zero + 1, a), m_util.mk_numeral(numeral(0), bv_sz - first_non_zero - 1)),
m_util.mk_ule(m_mk_extract(first_non_zero, 0, a), m_mk_extract(first_non_zero, 0, b)));
return BR_REWRITE3;
@ -2802,30 +2803,51 @@ br_status bv_rewriter::mk_ite_core(expr * c, expr * t, expr * e, expr_ref & resu
return BR_FAILED;
}
br_status bv_rewriter::mk_bvsmul_no_overflow(unsigned num, expr * const * args, expr_ref & result) {
br_status bv_rewriter::mk_distinct(unsigned num_args, expr * const * args, expr_ref & result) {
if (num_args <= 1) {
result = m().mk_true();
return BR_DONE;
}
unsigned sz = get_bv_size(args[0]);
// check if num_args > 2^sz
if (sz >= 32)
return BR_FAILED;
if (num_args <= 1u << sz)
return BR_FAILED;
result = m().mk_false();
return BR_DONE;
}
br_status bv_rewriter::mk_bvsmul_no_overflow(unsigned num, expr * const * args, bool is_overflow, expr_ref & result) {
SASSERT(num == 2);
unsigned bv_sz;
rational a0_val, a1_val;
bool is_num1 = is_numeral(args[0], a0_val, bv_sz);
bool is_num2 = is_numeral(args[1], a1_val, bv_sz);
if (is_num1 && (a0_val.is_zero() || a0_val.is_one())) {
if (is_num1 && (a0_val.is_zero() || (bv_sz != 1 && a0_val.is_one()))) {
result = m().mk_true();
return BR_DONE;
}
if (is_num2 && (a1_val.is_zero() || a1_val.is_one())) {
if (is_num2 && (a1_val.is_zero() || (bv_sz != 1 && a1_val.is_one()))) {
result = m().mk_true();
return BR_DONE;
}
if (!is_num1 || !is_num2)
return BR_FAILED;
rational lim = rational::power_of_two(bv_sz);
bool sign0 = m_util.has_sign_bit(a0_val, bv_sz);
bool sign1 = m_util.has_sign_bit(a1_val, bv_sz);
if (sign0) a0_val = rational::power_of_two(bv_sz) - a0_val;
if (sign1) a1_val = rational::power_of_two(bv_sz) - a1_val;
rational lim = rational::power_of_two(bv_sz-1);
rational r = a0_val * a1_val;
bool sign1 = m_util.has_sign_bit(a0_val, bv_sz);
bool sign2 = m_util.has_sign_bit(a1_val, bv_sz);
result = m().mk_bool_val((sign1 != sign2) || r < lim);
if (is_overflow)
result = m().mk_bool_val(sign0 != sign1 || r < lim);
else
result = m().mk_bool_val(sign0 == sign1 || r <= lim);
return BR_DONE;
}
@ -2855,36 +2877,5 @@ br_status bv_rewriter::mk_bvumul_no_overflow(unsigned num, expr * const * args,
return BR_FAILED;
}
br_status bv_rewriter::mk_bvsmul_no_underflow(unsigned num, expr * const * args, expr_ref & result) {
SASSERT(num == 2);
unsigned bv_sz;
rational a0_val, a1_val;
bool is_num1 = is_numeral(args[0], a0_val, bv_sz);
bool is_num2 = is_numeral(args[1], a1_val, bv_sz);
if (is_num1 && (a0_val.is_zero() || a0_val.is_one())) {
result = m().mk_true();
return BR_DONE;
}
if (is_num2 && (a1_val.is_zero() || a1_val.is_one())) {
result = m().mk_true();
return BR_DONE;
}
if (is_num1 && is_num2) {
rational ul = rational::power_of_two(bv_sz);
rational lim = rational::power_of_two(bv_sz-1);
if (a0_val >= lim) a0_val -= ul;
if (a1_val >= lim) a1_val -= ul;
rational mr = a0_val * a1_val;
rational neg_lim = -lim;
TRACE("bv_rewriter_bvsmul_no_underflow", tout << "a0:" << a0_val << " a1:" << a1_val << " mr:" << mr << " neg_lim:" << neg_lim << std::endl;);
result = m().mk_bool_val(mr >= neg_lim);
return BR_DONE;
}
return BR_FAILED;
}
template class poly_rewriter<bv_rewriter_core>;

View file

@ -62,6 +62,7 @@ class bv_rewriter : public poly_rewriter<bv_rewriter_core> {
bool m_extract_prop;
bool m_bvnot_simpl;
bool m_le_extra;
bool m_le2extract;
bool is_zero_bit(expr * x, unsigned idx);
@ -134,9 +135,8 @@ class bv_rewriter : public poly_rewriter<bv_rewriter_core> {
br_status mk_blast_eq_value(expr * lhs, expr * rhs, expr_ref & result);
br_status mk_eq_concat(expr * lhs, expr * rhs, expr_ref & result);
br_status mk_mkbv(unsigned num, expr * const * args, expr_ref & result);
br_status mk_bvsmul_no_overflow(unsigned num, expr * const * args, expr_ref & result);
br_status mk_bvsmul_no_overflow(unsigned num, expr * const * args, bool is_overflow, expr_ref & result);
br_status mk_bvumul_no_overflow(unsigned num, expr * const * args, expr_ref & result);
br_status mk_bvsmul_no_underflow(unsigned num, expr * const * args, expr_ref & result);
bool is_minus_one_times_t(expr * arg);
void mk_t1_add_t2_eq_c(expr * t1, expr * t2, expr * c, expr_ref & result);
@ -180,7 +180,8 @@ public:
bool is_urem_any(expr * e, expr * & dividend, expr * & divisor);
br_status mk_eq_core(expr * lhs, expr * rhs, expr_ref & result);
br_status mk_ite_core(expr * c, expr * t, expr * e, expr_ref & resul);
br_status mk_ite_core(expr * c, expr * t, expr * e, expr_ref & result);
br_status mk_distinct(unsigned num_args, expr * const * args, expr_ref & result);
bool hi_div0() const { return m_hi_div0; }

View file

@ -0,0 +1,73 @@
/*++
Copyright (c) 2015 Microsoft Corporation
Module Name:
char_rewriter.cpp
Abstract:
Basic rewriting rules for character constraints
Author:
Nikolaj Bjorner (nbjorner) 2015-12-5
--*/
#include "util/debug.h"
#include "ast/rewriter/char_rewriter.h"
#include "ast/bv_decl_plugin.h"
#include "ast/arith_decl_plugin.h"
char_rewriter::char_rewriter(ast_manager& m):
m(m) {
m_char = static_cast<char_decl_plugin*>(m.get_plugin(m.mk_family_id("char")));
}
family_id char_rewriter::get_fid() {
return m_char->get_family_id();
}
br_status char_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * const * args, expr_ref & result) {
SASSERT(f->get_family_id() == get_fid());
br_status st = BR_FAILED;
switch (f->get_decl_kind()) {
case OP_CHAR_CONST:
break;
case OP_CHAR_LE:
break;
case OP_CHAR_TO_INT:
st = mk_char_to_int(args[0], result);
break;
case OP_CHAR_TO_BV:
break;
case OP_CHAR_FROM_BV:
st = mk_char_from_bv(args[0], result);
break;
case OP_CHAR_IS_DIGIT:
break;
}
return st;
}
br_status char_rewriter::mk_char_from_bv(expr* e, expr_ref& result) {
bv_util bv(m);
rational n;
if (bv.is_numeral(e, n) && n.is_unsigned() && n <= m_char->max_char()) {
result = m_char->mk_char(n.get_unsigned());
return BR_DONE;
}
return BR_FAILED;
}
br_status char_rewriter::mk_char_to_int(expr* e, expr_ref& result) {
unsigned n = 0;
if (m_char->is_const_char(e, n)) {
arith_util arith(m);
result = arith.mk_int(n);
return BR_DONE;
}
return BR_FAILED;
}

View file

@ -0,0 +1,57 @@
/*++
Copyright (c) 2015 Microsoft Corporation
Module Name:
char_rewriter.h
Abstract:
Basic rewriting rules for characters constraints.
Author:
Nikolaj Bjorner (nbjorner) 2022-03-10
Notes:
--*/
#pragma once
#include "ast/char_decl_plugin.h"
#include "ast/rewriter/rewriter_types.h"
#include "util/params.h"
#include "util/lbool.h"
/**
\brief Cheap rewrite rules for character constraints
*/
class char_rewriter {
ast_manager& m;
char_decl_plugin* m_char;
br_status mk_char_from_bv(expr* e, expr_ref& result);
br_status mk_char_to_int(expr* e, expr_ref& result);
public:
char_rewriter(ast_manager& m);
family_id get_fid();
br_status mk_app_core(func_decl * f, unsigned num_args, expr * const * args, expr_ref & result);
expr_ref mk_app(func_decl* f, expr_ref_vector const& args) { return mk_app(f, args.size(), args.data()); }
expr_ref mk_app(func_decl* f, unsigned n, expr* const* args) {
expr_ref result(m);
if (f->get_family_id() != get_fid() ||
BR_FAILED == mk_app_core(f, n, args, result))
result = m.mk_app(f, n, args);
return result;
}
};

View file

@ -23,7 +23,8 @@ Revision History:
expr_ref func_decl_replace::operator()(expr* e) {
m_todo.push_back(e);
m_refs.push_back(e);
while (!m_todo.empty()) {
expr* a = m_todo.back(), *b;
if (m_cache.contains(a)) {

View file

@ -979,9 +979,8 @@ expr* poly_rewriter<Config>::merge_muls(expr* x, expr* y) {
template<typename Config>
bool poly_rewriter<Config>::hoist_ite(expr_ref& e) {
if (!m_hoist_ite) {
if (!m_hoist_ite)
return false;
}
obj_hashtable<expr> shared;
ptr_buffer<expr> adds;
expr_ref_vector bs(m()), pinned(m());

View file

@ -936,22 +936,13 @@ expr_ref seq_rewriter::mk_seq_last(expr* t) {
}
/*
* In general constructs substring(t,0,|t|-1) but if t = substring(s,0,k) then simplifies to substring(s,0,k-1)
* This method assumes that |t| > 0, thus, if t = substring(s,0,k) then k > 0 so substring(s,0,k-1) is correct.
* In general constructs substring(t,0,|t|-1)
* Incorrect comment: "but if t = substring(s,0,k) then simplifies to substring(s,0,k-1).
* This method assumes that |t| > 0, thus, if t = substring(s,0,k) then k > 0 so substring(s,0,k-1) is correct."
* No: if k > |s| then substring(s,0,k) = substring(s,0,k-1)
*/
expr_ref seq_rewriter::mk_seq_butlast(expr* t) {
expr_ref result(m());
expr* s, * j, * k;
rational v;
if (str().is_extract(t, s, j, k) && m_autil.is_numeral(j, v) && v.is_zero()) {
expr_ref_vector k_min_1(m());
k_min_1.push_back(k);
k_min_1.push_back(minus_one());
result = str().mk_substr(s, j, m_autil.mk_add_simplify(k_min_1));
}
else
result = str().mk_substr(t, zero(), m_autil.mk_sub(str().mk_length(t), one()));
return result;
return expr_ref(str().mk_substr(t, zero(), m_autil.mk_sub(str().mk_length(t), one())), m());
}
/*
@ -3128,8 +3119,8 @@ void seq_rewriter::mk_antimirov_deriv_rec(expr* e, expr* r, expr* path, expr_ref
expr_ref range(m());
expr_ref psi(m().mk_false(), m());
if (str().is_unit_string(r1, c1) && str().is_unit_string(r2, c2)) {
SASSERT(u().is_char(c1));
SASSERT(u().is_char(c2));
// SASSERT(u().is_char(c1));
// SASSERT(u().is_char(c2));
// case: c1 <= e <= c2
range = simplify_path(e, m().mk_and(u().mk_le(c1, e), u().mk_le(e, c2)));
psi = simplify_path(e, m().mk_and(path, range));
@ -5531,44 +5522,37 @@ lbool seq_rewriter::eq_length(expr* x, expr* y) {
maximal length (the sequence is bounded).
*/
bool seq_rewriter::min_length(expr* e, unsigned& len) {
bool seq_rewriter::min_length(unsigned sz, expr* const* ss, unsigned& len) {
ptr_buffer<expr> es;
for (unsigned i = 0; i < sz; ++i)
es.push_back(ss[i]);
zstring s;
len = 0;
if (str().is_unit(e)) {
len = 1;
return true;
bool bounded = true;
while (!es.empty()) {
expr* e = es.back();
es.pop_back();
if (str().is_unit(e))
len += 1;
else if (str().is_empty(e))
continue;
else if (str().is_string(e, s))
len += s.length();
else if (str().is_concat(e))
for (expr* arg : *to_app(e))
es.push_back(arg);
else
bounded = false;
}
else if (str().is_empty(e)) {
len = 0;
return true;
}
else if (str().is_string(e, s)) {
len = s.length();
return true;
}
else if (str().is_concat(e)) {
unsigned min_l = 0;
bool bounded = true;
for (expr* arg : *to_app(e)) {
if (!min_length(arg, min_l))
bounded = false;
len += min_l;
}
return bounded;
}
return false;
return bounded;
}
bool seq_rewriter::min_length(expr* e, unsigned& len) {
return min_length(1, &e, len);
}
bool seq_rewriter::min_length(expr_ref_vector const& es, unsigned& len) {
unsigned min_l = 0;
bool bounded = true;
len = 0;
for (expr* arg : es) {
if (!min_length(arg, min_l))
bounded = false;
len += min_l;
}
return bounded;
return min_length(es.size(), es.data(), len);
}
bool seq_rewriter::max_length(expr* e, rational& len) {

View file

@ -322,6 +322,7 @@ class seq_rewriter {
bool reduce_eq_empty(expr* l, expr* r, expr_ref& result);
bool min_length(expr_ref_vector const& es, unsigned& len);
bool min_length(expr* e, unsigned& len);
bool min_length(unsigned sz, expr* const* es, unsigned& len);
bool max_length(expr* e, rational& len);
lbool eq_length(expr* x, expr* y);
expr* concat_non_empty(expr_ref_vector& es);

View file

@ -21,6 +21,7 @@ Notes:
#include "ast/rewriter/bool_rewriter.h"
#include "ast/rewriter/arith_rewriter.h"
#include "ast/rewriter/bv_rewriter.h"
#include "ast/rewriter/char_rewriter.h"
#include "ast/rewriter/datatype_rewriter.h"
#include "ast/rewriter/array_rewriter.h"
#include "ast/rewriter/fpa_rewriter.h"
@ -48,6 +49,7 @@ struct th_rewriter_cfg : public default_rewriter_cfg {
dl_rewriter m_dl_rw;
pb_rewriter m_pb_rw;
seq_rewriter m_seq_rw;
char_rewriter m_char_rw;
recfun_rewriter m_rec_rw;
arith_util m_a_util;
bv_util m_bv_util;
@ -58,7 +60,7 @@ struct th_rewriter_cfg : public default_rewriter_cfg {
expr_substitution * m_subst = nullptr;
unsigned long long m_max_memory; // in bytes
bool m_new_subst = false;
unsigned m_max_steps = UINT_MAX;
unsigned m_max_steps = UINT_MAX;
bool m_pull_cheap_ite = true;
bool m_flat = true;
bool m_cache_all = false;
@ -178,7 +180,7 @@ struct th_rewriter_cfg : public default_rewriter_cfg {
// theory dispatch for =
SASSERT(num == 2);
family_id s_fid = args[0]->get_sort()->get_family_id();
if (s_fid == m_a_rw.get_fid())
if (s_fid == m_a_rw.get_fid())
st = m_a_rw.mk_eq_core(args[0], args[1], result);
else if (s_fid == m_bv_rw.get_fid())
st = m_bv_rw.mk_eq_core(args[0], args[1], result);
@ -191,10 +193,7 @@ struct th_rewriter_cfg : public default_rewriter_cfg {
else if (s_fid == m_seq_rw.get_fid())
st = m_seq_rw.mk_eq_core(args[0], args[1], result);
if (st != BR_FAILED)
return st;
}
if (k == OP_EQ) {
SASSERT(num == 2);
return st;
st = apply_tamagotchi(args[0], args[1], result);
if (st != BR_FAILED)
return st;
@ -208,16 +207,21 @@ struct th_rewriter_cfg : public default_rewriter_cfg {
return st;
}
if ((k == OP_AND || k == OP_OR) && m_seq_rw.u().has_re()) {
st = m_seq_rw.mk_bool_app(f, num, args, result);
st = m_seq_rw.mk_bool_app(f, num, args, result);
if (st != BR_FAILED)
return st;
}
if (k == OP_EQ && m_seq_rw.u().has_seq() && is_app(args[0]) &&
if (k == OP_EQ && m_seq_rw.u().has_seq() && is_app(args[0]) &&
to_app(args[0])->get_family_id() == m_seq_rw.get_fid()) {
st = m_seq_rw.mk_eq_core(args[0], args[1], result);
if (st != BR_FAILED)
return st;
}
if (k == OP_DISTINCT && num > 0 && m_bv_rw.is_bv(args[0])) {
st = m_bv_rw.mk_distinct(num, args, result);
if (st != BR_FAILED)
return st;
}
return m_b_rw.mk_app_core(f, num, args, result);
}
@ -247,6 +251,8 @@ struct th_rewriter_cfg : public default_rewriter_cfg {
return m_pb_rw.mk_app_core(f, num, args, result);
if (fid == m_seq_rw.get_fid())
return m_seq_rw.mk_app_core(f, num, args, result);
if (fid == m_char_rw.get_fid())
return m_char_rw.mk_app_core(f, num, args, result);
if (fid == m_rec_rw.get_fid())
return m_rec_rw.mk_app_core(f, num, args, result);
return BR_FAILED;
@ -295,6 +301,8 @@ struct th_rewriter_cfg : public default_rewriter_cfg {
bool is_ite_value_tree(expr * t) {
if (!m().is_ite(t))
return false;
if (t->get_ref_count() != 1)
return false;
ptr_buffer<app> todo;
todo.push_back(to_app(t));
while (!todo.empty()) {
@ -303,12 +311,12 @@ struct th_rewriter_cfg : public default_rewriter_cfg {
expr * arg1 = ite->get_arg(1);
expr * arg2 = ite->get_arg(2);
if (m().is_ite(arg1) && arg1->get_ref_count() == 1) // do not apply on shared terms, since it may blowup
if (m().is_ite(arg1) && arg1->get_ref_count() == 1) // do not apply on shared terms, since it may blow up
todo.push_back(to_app(arg1));
else if (!m().is_value(arg1))
return false;
if (m().is_ite(arg2) && arg2->get_ref_count() == 1) // do not apply on shared terms, since it may blowup
if (m().is_ite(arg2) && arg2->get_ref_count() == 1) // do not apply on shared terms, since it may blow up
todo.push_back(to_app(arg2));
else if (!m().is_value(arg2))
return false;
@ -319,7 +327,7 @@ struct th_rewriter_cfg : public default_rewriter_cfg {
br_status pull_ite(func_decl * f, unsigned num, expr * const * args, expr_ref & result) {
if (num == 2 && m().is_bool(f->get_range()) && !m().is_bool(args[0])) {
if (m().is_ite(args[0])) {
if (m().is_value(args[1]))
if (m().is_value(args[1]) && args[0]->get_ref_count() == 1)
return pull_ite_core<false>(f, to_app(args[0]), to_app(args[1]), result);
if (m().is_ite(args[1]) && to_app(args[0])->get_arg(0) == to_app(args[1])->get_arg(0)) {
// (p (ite C A1 B1) (ite C A2 B2)) --> (ite (p A1 A2) (p B1 B2))
@ -329,17 +337,17 @@ struct th_rewriter_cfg : public default_rewriter_cfg {
return BR_REWRITE2;
}
}
if (m().is_ite(args[1]) && m().is_value(args[0]))
if (m().is_ite(args[1]) && m().is_value(args[0]) && args[1]->get_ref_count() == 1)
return pull_ite_core<true>(f, to_app(args[1]), to_app(args[0]), result);
}
family_id fid = f->get_family_id();
if (num == 2 && (fid == m().get_basic_family_id() || fid == m_a_rw.get_fid() || fid == m_bv_rw.get_fid())) {
// (f v3 (ite c v1 v2)) --> (ite v (f v3 v1) (f v3 v2))
if (m().is_value(args[0]) && is_ite_value_tree(args[1]))
if (m().is_value(args[0]) && is_ite_value_tree(args[1]))
return pull_ite_core<true>(f, to_app(args[1]), to_app(args[0]), result);
// (f (ite c v1 v2) v3) --> (ite v (f v1 v3) (f v2 v3))
if (m().is_value(args[1]) && is_ite_value_tree(args[0]))
if (m().is_value(args[1]) && is_ite_value_tree(args[0]))
return pull_ite_core<false>(f, to_app(args[0]), to_app(args[1]), result);
}
return BR_FAILED;
@ -800,6 +808,7 @@ struct th_rewriter_cfg : public default_rewriter_cfg {
m_dl_rw(m),
m_pb_rw(m),
m_seq_rw(m),
m_char_rw(m),
m_rec_rw(m),
m_a_util(m),
m_bv_util(m),

View file

@ -1053,6 +1053,12 @@ sort* seq_util::rex::to_seq(sort* re) {
return to_sort(re->get_parameter(0).get_ast());
}
app* seq_util::rex::mk_power(expr* r, unsigned n) {
parameter param(n);
return m.mk_app(m_fid, OP_RE_POWER, 1, &param, 1, &r);
}
app* seq_util::rex::mk_loop(expr* r, unsigned lo) {
parameter param(lo);
return m.mk_app(m_fid, OP_RE_LOOP, 1, &param, 1, &r);

View file

@ -502,6 +502,7 @@ public:
app* mk_star(expr* r) { return m.mk_app(m_fid, OP_RE_STAR, r); }
app* mk_plus(expr* r) { return m.mk_app(m_fid, OP_RE_PLUS, r); }
app* mk_opt(expr* r) { return m.mk_app(m_fid, OP_RE_OPTION, r); }
app* mk_power(expr* r, unsigned n);
app* mk_loop(expr* r, unsigned lo);
app* mk_loop(expr* r, unsigned lo, unsigned hi);
expr* mk_loop_proper(expr* r, unsigned lo, unsigned hi);

View file

@ -61,11 +61,11 @@ func_decl * special_relations_decl_plugin::mk_func_decl(
void special_relations_decl_plugin::get_op_names(svector<builtin_name> & op_names, symbol const & logic) {
if (logic == symbol::null) {
op_names.push_back(builtin_name(m_po.bare_str(), OP_SPECIAL_RELATION_PO));
op_names.push_back(builtin_name(m_lo.bare_str(), OP_SPECIAL_RELATION_LO));
op_names.push_back(builtin_name(m_plo.bare_str(), OP_SPECIAL_RELATION_PLO));
op_names.push_back(builtin_name(m_to.bare_str(), OP_SPECIAL_RELATION_TO));
op_names.push_back(builtin_name(m_tc.bare_str(), OP_SPECIAL_RELATION_TC));
op_names.push_back(builtin_name(m_po.str(), OP_SPECIAL_RELATION_PO));
op_names.push_back(builtin_name(m_lo.str(), OP_SPECIAL_RELATION_LO));
op_names.push_back(builtin_name(m_plo.str(), OP_SPECIAL_RELATION_PLO));
op_names.push_back(builtin_name(m_to.str(), OP_SPECIAL_RELATION_TO));
op_names.push_back(builtin_name(m_tc.str(), OP_SPECIAL_RELATION_TC));
}
}

View file

@ -58,7 +58,7 @@ public:
cmd * c = ctx.find_cmd(s);
if (c == nullptr) {
std::string err_msg("unknown command '");
err_msg = err_msg + s.bare_str() + "'";
err_msg = err_msg + s.str() + "'";
throw cmd_exception(std::move(err_msg));
}
m_cmds.push_back(s);
@ -817,9 +817,9 @@ public:
sort_ref range(ctx.m());
array_sort_args.push_back(m_f->get_range());
range = array_sort->instantiate(ctx.pm(), array_sort_args.size(), array_sort_args.data());
parameter p[1] = { parameter(m_f) };
parameter p(m_f);
func_decl_ref new_map(ctx.m());
new_map = ctx.m().mk_func_decl(get_array_fid(ctx), OP_ARRAY_MAP, 1, p, domain.size(), domain.data(), range.get());
new_map = ctx.m().mk_func_decl(get_array_fid(ctx), OP_ARRAY_MAP, 1, &p, domain.size(), domain.data(), range.get());
if (new_map == 0)
throw cmd_exception("invalid array map operator");
ctx.insert(m_name, new_map);

View file

@ -1636,6 +1636,7 @@ void cmd_context::pop(unsigned n) {
restore_aux_pdecls(s.m_aux_pdecls_lim);
restore_assertions(s.m_assertions_lim);
restore_psort_inst(s.m_psort_inst_stack_lim);
m_dt_eh.get()->reset();
m_mcs.shrink(m_mcs.size() - n);
m_scopes.shrink(new_lvl);
if (!m_global_decls)
@ -1815,6 +1816,9 @@ void cmd_context::display_model(model_ref& mdl) {
}
void cmd_context::add_declared_functions(model& mdl) {
model_params p;
if (!p.user_functions())
return;
for (auto const& kv : m_func_decls) {
func_decl* f = kv.m_value.first();
if (f->get_family_id() == null_family_id && !mdl.has_interpretation(f)) {

View file

@ -267,6 +267,7 @@ protected:
cmd_context & m_owner;
datatype_util m_dt_util;
public:
void reset() { m_dt_util.reset(); }
dt_eh(cmd_context & owner);
~dt_eh() override;
void operator()(sort * dt, pdecl* pd) override;

View file

@ -57,6 +57,8 @@ public:
void execute(cmd_context & ctx) override {
model_ref md;
if (ctx.ignore_check())
return;
if (!ctx.is_model_available(md))
throw cmd_exception("model is not available");
if (!m_target)

View file

@ -156,8 +156,8 @@ public:
return false;
return m_sort == static_cast<psort_sort const *>(other)->m_sort;
}
void display(std::ostream & out) const override {
out << m_sort->get_name();
std::ostream& display(std::ostream & out) const override {
return out << m_sort->get_name();
}
};
@ -180,8 +180,8 @@ public:
get_num_params() == other->get_num_params() &&
m_idx == static_cast<psort_var const *>(other)->m_idx;
}
void display(std::ostream & out) const override {
out << "s_" << m_idx;
std::ostream& display(std::ostream & out) const override {
return out << "s_" << m_idx;
}
unsigned idx() const { return m_idx; }
};
@ -254,7 +254,7 @@ public:
}
return true;
}
void display(std::ostream & out) const override {
std::ostream& display(std::ostream & out) const override {
if (m_args.empty()) {
out << m_decl->get_name();
}
@ -267,6 +267,7 @@ public:
}
out << ")";
}
return out;
}
};
@ -342,12 +343,12 @@ void display_sort_args(std::ostream & out, unsigned num_params) {
out << ") ";
}
void psort_user_decl::display(std::ostream & out) const {
std::ostream& psort_user_decl::display(std::ostream & out) const {
out << "(declare-sort " << m_name;
display_sort_args(out, m_num_params);
if (m_def)
m_def->display(out);
out << ")";
return out << ")";
}
// -------------------
@ -364,8 +365,8 @@ sort * psort_dt_decl::instantiate(pdecl_manager & m, unsigned n, sort * const *
return m.instantiate_datatype(this, m_name, n, s);
}
void psort_dt_decl::display(std::ostream & out) const {
out << "(datatype-sort " << m_name << ")";
std::ostream& psort_dt_decl::display(std::ostream & out) const {
return out << "(datatype-sort " << m_name << ")";
}
// -------------------
@ -410,8 +411,8 @@ sort * psort_builtin_decl::instantiate(pdecl_manager & m, unsigned n, unsigned c
}
}
void psort_builtin_decl::display(std::ostream & out) const {
out << "(declare-builtin-sort " << m_name << ")";
std::ostream& psort_builtin_decl::display(std::ostream & out) const {
return out << "(declare-builtin-sort " << m_name << ")";
}
void ptype::display(std::ostream & out, pdatatype_decl const * const * dts) const {
@ -615,7 +616,7 @@ sort * pdatatype_decl::instantiate(pdecl_manager & m, unsigned n, sort * const *
}
void pdatatype_decl::display(std::ostream & out) const {
std::ostream& pdatatype_decl::display(std::ostream & out) const {
out << "(declare-datatype " << m_name;
display_sort_args(out, m_num_params);
bool first = true;
@ -631,7 +632,7 @@ void pdatatype_decl::display(std::ostream & out) const {
}
first = false;
}
out << ")";
return out << ")";
}
bool pdatatype_decl::commit(pdecl_manager& m) {
@ -645,9 +646,11 @@ bool pdatatype_decl::commit(pdecl_manager& m) {
datatype_decl * d_ptr = dts.m_buffer[0];
sort_ref_vector sorts(m.m());
bool is_ok = m.get_dt_plugin()->mk_datatypes(1, &d_ptr, m_num_params, ps.data(), sorts);
m.notify_mk_datatype(m_name);
if (is_ok && m_num_params == 0) {
m.notify_new_dt(sorts.get(0), this);
}
return is_ok;
}
@ -722,6 +725,7 @@ void pdecl_manager::notify_datatype(sort *r, psort_decl* p, unsigned n, sort* co
void pdecl_manager::push() {
m_notified_lim.push_back(m_notified_trail.size());
m_datatypes_lim.push_back(m_datatypes_trail.size());
}
void pdecl_manager::pop(unsigned n) {
@ -732,6 +736,16 @@ void pdecl_manager::pop(unsigned n) {
}
m_notified_trail.shrink(new_sz);
m_notified_lim.shrink(m_notified_lim.size() - n);
new_sz = m_datatypes_lim[m_datatypes_lim.size() - n];
if (new_sz != m_datatypes_trail.size()) {
datatype_util util(m());
for (unsigned i = m_datatypes_trail.size(); i-- > new_sz; )
util.plugin().remove(m_datatypes_trail[i]);
}
m_datatypes_trail.shrink(new_sz);
m_datatypes_lim.shrink(m_datatypes_lim.size() - n);
}
bool pdatatypes_decl::instantiate(pdecl_manager & m, sort * const * s) {
@ -751,16 +765,24 @@ bool pdatatypes_decl::commit(pdecl_manager& m) {
sort_ref_vector sorts(m.m());
bool is_ok = m.get_dt_plugin()->mk_datatypes(m_datatypes.size(), dts.m_buffer.data(), 0, nullptr, sorts);
if (is_ok) {
for (pdatatype_decl* d : m_datatypes) {
m.notify_mk_datatype(d->get_name());
}
for (unsigned i = 0; i < m_datatypes.size(); ++i) {
pdatatype_decl* d = m_datatypes[i];
if (d->get_num_params() == 0) {
if (d->get_num_params() == 0)
m.notify_new_dt(sorts.get(i), this);
}
}
}
return is_ok;
}
void pdecl_manager::notify_mk_datatype(symbol const& name) {
m_datatypes_trail.push_back(name);
}
struct pdecl_manager::sort_info {
psort_decl * m_decl;
@ -985,16 +1007,19 @@ void pdecl_manager::del_decl_core(pdecl * p) {
}
void pdecl_manager::del_decl(pdecl * p) {
TRACE("pdecl_manager", tout << "del psort "; p->display(tout); tout << "\n";);
TRACE("pdecl_manager", tout << "del psort "; p->display(tout); tout << "\n";);
if (p->is_psort()) {
psort * _p = static_cast<psort*>(p);
if (_p->is_sort_wrapper()) {
m_sort2psort.erase(static_cast<psort_sort*>(_p)->get_sort());
sort* s = static_cast<psort_sort*>(_p)->get_sort();
m_sort2psort.erase(s);
}
else {
m_table.erase(_p);
}
}
del_decl_core(p);
}

View file

@ -45,7 +45,7 @@ public:
unsigned get_id() const { return m_id; }
unsigned get_ref_count() const { return m_ref_count; }
unsigned hash() const { return m_id; }
virtual void display(std::ostream & out) const {}
virtual std::ostream& display(std::ostream & out) const { return out;}
virtual void reset_cache(pdecl_manager& m) {}
};
@ -123,7 +123,7 @@ protected:
~psort_user_decl() override {}
public:
sort * instantiate(pdecl_manager & m, unsigned n, sort * const * s) override;
void display(std::ostream & out) const override;
std::ostream& display(std::ostream & out) const override;
};
class psort_builtin_decl : public psort_decl {
@ -137,7 +137,7 @@ protected:
public:
sort * instantiate(pdecl_manager & m, unsigned n, sort * const * s) override;
sort * instantiate(pdecl_manager & m, unsigned n, unsigned const * s) override;
void display(std::ostream & out) const override;
std::ostream& display(std::ostream & out) const override;
};
class psort_dt_decl : public psort_decl {
@ -148,7 +148,7 @@ protected:
~psort_dt_decl() override {}
public:
sort * instantiate(pdecl_manager & m, unsigned n, sort * const * s) override;
void display(std::ostream & out) const override;
std::ostream& display(std::ostream & out) const override;
};
@ -198,7 +198,7 @@ class paccessor_decl : public pdecl {
ptype const & get_type() const { return m_type; }
~paccessor_decl() override {}
public:
void display(std::ostream & out) const override { pdecl::display(out); }
std::ostream& display(std::ostream & out) const override { pdecl::display(out); return out; }
void display(std::ostream & out, pdatatype_decl const * const * dts) const;
};
@ -219,7 +219,7 @@ class pconstructor_decl : public pdecl {
constructor_decl * instantiate_decl(pdecl_manager & m, unsigned n, sort * const * s);
~pconstructor_decl() override {}
public:
void display(std::ostream & out) const override { pdecl::display(out); }
std::ostream& display(std::ostream & out) const override { pdecl::display(out); return out; }
void display(std::ostream & out, pdatatype_decl const * const * dts) const;
};
@ -237,7 +237,7 @@ class pdatatype_decl : public psort_decl {
~pdatatype_decl() override {}
public:
sort * instantiate(pdecl_manager & m, unsigned n, sort * const * s) override;
void display(std::ostream & out) const override;
std::ostream& display(std::ostream & out) const override;
bool has_missing_refs(symbol & missing) const;
bool has_duplicate_accessors(symbol & repeated) const;
bool commit(pdecl_manager& m);
@ -289,6 +289,8 @@ class pdecl_manager {
obj_hashtable<sort> m_notified;
ptr_vector<sort> m_notified_trail;
unsigned_vector m_notified_lim;
svector<symbol> m_datatypes_trail;
unsigned_vector m_datatypes_lim;
void init_list();
void del_decl_core(pdecl * p);
@ -319,6 +321,7 @@ public:
sort * instantiate_datatype(psort_decl* p, symbol const& name, unsigned n, sort * const* s);
sort * instantiate(psort * s, unsigned num, sort * const * args);
void notify_datatype(sort *r, psort_decl* p, unsigned n, sort* const* s);
void notify_mk_datatype(symbol const& name);
void push();
void pop(unsigned n);

View file

@ -223,7 +223,7 @@ class lar_solver : public column_namer {
void insert_row_with_changed_bounds(unsigned rid);
void detect_rows_with_changed_bounds_for_column(unsigned j);
void detect_rows_with_changed_bounds();
void set_value_for_nbasic_column(unsigned j, const impq & new_val);
void update_x_and_inf_costs_for_columns_with_changed_bounds();
void update_x_and_inf_costs_for_columns_with_changed_bounds_tableau();
void solve_with_core_solver();
@ -355,6 +355,9 @@ public:
bp.consume(a, witness);
}
}
void set_value_for_nbasic_column(unsigned j, const impq& new_val);
// lp_assert(implied_bound_is_correctly_explained(ib, explanation)); }
constraint_index mk_var_bound(var_index j, lconstraint_kind kind, const mpq & right_side);
void activate_check_on_equal(constraint_index, var_index&);

View file

@ -217,14 +217,14 @@ template <typename T, typename X> void lp_dual_simplex<T, X>::fill_costs_bounds_
m_can_enter_basis[j] = true;
this->set_scaled_cost(j);
this->m_lower_bounds[j] = numeric_traits<T>::zero();
this->m_upper_bounds[j] =numeric_traits<T>::one();
this->m_upper_bounds[j] = numeric_traits<T>::one();
break;
}
case column_type::free_column: {
m_can_enter_basis[j] = true;
this->set_scaled_cost(j);
this->m_upper_bounds[j] = free_bound;
this->m_lower_bounds[j] = -free_bound;
this->m_upper_bounds[j] = free_bound;
this->m_lower_bounds[j] = -free_bound;
break;
}
case column_type::boxed:

View file

@ -2013,6 +2013,11 @@ namespace algebraic_numbers {
}
else {
algebraic_cell * c = a.to_algebraic();
if (c->m_i == 0) {
// undefined
c->m_i = upm().get_root_id(c->m_p_sz, c->m_p, lower(c)) + 1;
}
SASSERT(c->m_i > 0);
return c->m_i;
}
}

View file

@ -45,8 +45,8 @@ expr * array_factory::mk_array_interp(sort * s, func_interp * & fi) {
func_decl * f = mk_aux_decl_for_array_sort(m_manager, s);
fi = alloc(func_interp, m_manager, get_array_arity(s));
m_model.register_decl(f, fi);
parameter p[1] = { parameter(f) };
expr * val = m_manager.mk_app(get_family_id(), OP_AS_ARRAY, 1, p);
parameter p(f);
expr * val = m_manager.mk_app(get_family_id(), OP_AS_ARRAY, 1, &p);
register_value(val);
return val;
}

View file

@ -48,10 +48,8 @@ expr * datatype_factory::get_some_value(sort * s) {
*/
expr * datatype_factory::get_last_fresh_value(sort * s) {
expr * val = nullptr;
if (m_last_fresh_value.find(s, val)) {
TRACE("datatype", tout << "cached fresh value: " << mk_pp(val, m_manager) << "\n";);
if (m_last_fresh_value.find(s, val))
return val;
}
value_set * set = get_value_set(s);
if (set->empty())
val = get_some_value(s);
@ -200,7 +198,7 @@ expr * datatype_factory::get_fresh_value(sort * s) {
if (m_util.is_recursive(s)) {
while (true) {
++num_iterations;
TRACE("datatype", tout << mk_pp(get_last_fresh_value(s), m_manager) << "\n";);
TRACE("datatype", tout << num_iterations << " " << mk_pp(get_last_fresh_value(s), m_manager) << "\n";);
ptr_vector<func_decl> const & constructors = *m_util.get_datatype_constructors(s);
for (func_decl * constructor : constructors) {
expr_ref_vector args(m_manager);
@ -219,7 +217,7 @@ expr * datatype_factory::get_fresh_value(sort * s) {
expr * maybe_new_arg = nullptr;
if (!m_util.is_datatype(s_arg))
maybe_new_arg = m_model.get_fresh_value(s_arg);
else if (num_iterations <= 1)
else if (num_iterations <= 1 || m_util.is_recursive(s_arg))
maybe_new_arg = get_almost_fresh_value(s_arg);
else
maybe_new_arg = get_fresh_value(s_arg);

View file

@ -5,6 +5,7 @@ def_module_params('model',
('v2', BOOL, False, 'use Z3 version 2.x (x <= 16) pretty printer'),
('compact', BOOL, True, 'try to compact function graph (i.e., function interpretations that are lookup tables)'),
('inline_def', BOOL, False, 'inline local function definitions ignoring possible expansion'),
('user_functions', BOOL, True, 'include user defined functions in model'),
('completion', BOOL, False, 'enable/disable model completion'),
))

View file

@ -281,14 +281,19 @@ namespace datalog {
return get_max_var(has_var);
}
void del_rule(horn_subsume_model_converter* mc, rule& r, bool unreachable) {
void del_rule(horn_subsume_model_converter* mc, rule& r, lbool unreachable) {
if (mc) {
ast_manager& m = mc->get_manager();
expr_ref_vector body(m);
if (unreachable) {
TRACE("dl", tout << "unreachable: " << unreachable << " " << r.get_decl()->get_name() << "\n");
switch (unreachable) {
case l_true:
body.push_back(m.mk_true());
break;
case l_false:
body.push_back(m.mk_false());
}
else {
break;
default:
for (unsigned i = 0; i < r.get_tail_size(); ++i) {
if (r.is_neg_tail(i)) {
body.push_back(m.mk_not(r.get_tail(i)));
@ -297,11 +302,12 @@ namespace datalog {
body.push_back(r.get_tail(i));
}
}
break;
}
TRACE("dl_dr",
TRACE("dl",
tout << mk_pp(r.get_head(), m) << " :- \n";
for (unsigned i = 0; i < body.size(); ++i) {
tout << mk_pp(body[i].get(), m) << "\n";
tout << mk_pp(body.get(i), m) << "\n";
});
mc->insert(r.get_head(), body.size(), body.data());

View file

@ -353,7 +353,7 @@ namespace datalog {
unsigned get_max_rule_var(const rule& r);
};
void del_rule(horn_subsume_model_converter* mc, rule& r, bool unreachable);
void del_rule(horn_subsume_model_converter* mc, rule& r, lbool unreachable);
void resolve_rule(rule_manager& rm,
replace_proof_converter* pc, rule const& r1, rule const& r2, unsigned idx,

View file

@ -210,19 +210,35 @@ bool rule_properties::check_accessor(app* n) {
SASSERT(m_dt.is_datatype(s));
if (m_dt.get_datatype_constructors(s)->size() <= 1)
return true;
func_decl* f = n->get_decl();
func_decl * c = m_dt.get_accessor_constructor(f);
func_decl* c = m_dt.get_accessor_constructor(f);
unsigned ut_size = m_rule->get_uninterpreted_tail_size();
unsigned t_size = m_rule->get_tail_size();
ptr_vector<func_decl> ctors;
// add recognizer constructor to ctors
auto add_recognizer = [&](expr* r) {
if (!m_dt.is_recognizer(r))
return;
if (n->get_arg(0) != to_app(r)->get_arg(0))
return;
auto* c2 = m_dt.get_recognizer_constructor(to_app(r)->get_decl());
if (c == c2)
return;
ctors.push_back(c2);
};
auto add_not_recognizer = [&](expr* r) {
if (m.is_not(r, r))
add_recognizer(r);
};
// t is a recognizer for n
auto is_recognizer_base = [&](expr* t) {
return m_dt.is_recognizer(t) &&
to_app(t)->get_arg(0) == n->get_arg(0) &&
m_dt.get_recognizer_constructor(to_app(t)->get_decl()) == c;
};
auto is_recognizer = [&](expr* t) {
if (m.is_and(t))
for (expr* arg : *to_app(t))
@ -231,43 +247,78 @@ bool rule_properties::check_accessor(app* n) {
return is_recognizer_base(t);
};
for (unsigned i = ut_size; i < t_size; ++i)
if (is_recognizer(m_rule->get_tail(i)))
for (unsigned i = ut_size; i < t_size; ++i) {
auto* tail = m_rule->get_tail(i);
if (is_recognizer(tail))
return true;
add_not_recognizer(tail);
}
// create parent use list for every sub-expression in the rule
obj_map<expr, ptr_vector<expr>> use_list;
for (unsigned i = ut_size; i < t_size; ++i) {
app* t = m_rule->get_tail(i);
use_list.insert_if_not_there(t, ptr_vector<expr>()).push_back(nullptr); // add marker for top-level expression.
for (expr* sub : subterms::all(expr_ref(t, m)))
for (expr* sub : subterms::all(expr_ref(t, m)))
if (is_app(sub))
for (expr* arg : *to_app(sub))
use_list.insert_if_not_there(arg, ptr_vector<expr>()).push_back(sub);
}
// walk parents of n to check that each path is guarded by a recognizer.
ptr_vector<expr> todo;
todo.push_back(n);
for (unsigned i = 0; i < todo.size(); ++i) {
expr* e = todo[i];
// walk parents of n depth first to check that each path is guarded by a recognizer.
vector<std::tuple<expr *, unsigned int, bool>> todo;
todo.push_back({n, ctors.size(), false});
while(!todo.empty()) {
auto [e, ctors_size, visited] = todo.back();
if (visited) {
todo.pop_back();
while (ctors.size() > ctors_size) ctors.pop_back();
continue;
}
std::get<2>(todo.back()) = true; // set visited
if (!use_list.contains(e))
return false;
for (expr* parent : use_list[e]) {
if (!parent)
return false; // top-level expressions are not guarded
if (is_recognizer(parent))
if (!parent) { // top-level expression
// check if n is an unguarded "else" branch
ptr_vector<func_decl> diff;
for (auto* dtc : *m_dt.get_datatype_constructors(s))
if (!ctors.contains(dtc))
diff.push_back(dtc);
// the only unguarded constructor for s is c:
// all the others are guarded and we are in an "else" branch so the accessor is safe
if (diff.size() == 1 && diff[0] == c)
continue;
return false; // the accessor is not safe
}
if (is_recognizer(parent))
continue;
if (m.is_ite(parent) && to_app(parent)->get_arg(1) == e && is_recognizer(to_app(parent)->get_arg(0)))
continue;
todo.push_back(parent);
expr *cnd, *thn, *els;
if (m.is_ite(parent, cnd, thn, els)) {
if (thn == e) {
if (is_recognizer(cnd) && els != e)
continue; // e is guarded
}
add_recognizer(cnd);
}
if (m.is_and(parent))
for (expr* arg : *to_app(parent))
add_not_recognizer(arg);
if (m.is_or(parent))
for (expr* arg : *to_app(parent)) {
add_recognizer(arg);
// if one branch is not(recognizer) then the accessor is safe
if (m.is_not(arg, arg) && is_recognizer(arg))
goto _continue;
}
todo.push_back({parent, ctors.size(), false});
_continue:;
}
}
return true;
}
void rule_properties::operator()(app* n) {

View file

@ -777,6 +777,7 @@ protected:
// Sym ::= String | NUM | Var
//
dtoken parse_infix(dtoken tok1, char const* td, app_ref& pred) {
std::string td1_(td);
symbol td1(td);
expr_ref v1(m), v2(m);
sort* s = nullptr;
@ -793,12 +794,12 @@ protected:
if (tok1 == TK_ID) {
expr* _v1 = nullptr;
m_vars.find(td1.bare_str(), _v1);
m_vars.find(td1_, _v1);
v1 = _v1;
}
if (tok3 == TK_ID) {
expr* _v2 = nullptr;
m_vars.find(td2.bare_str(), _v2);
m_vars.find(td, _v2);
v2 = _v2;
}
if (!v1 && !v2) {
@ -950,18 +951,19 @@ protected:
break;
}
case TK_ID: {
symbol data (m_lexer->get_token_data());
if (is_var(data.bare_str())) {
char const* d = m_lexer->get_token_data();
symbol data (d);
if (is_var(d)) {
unsigned idx = 0;
expr* v = nullptr;
if (!m_vars.find(data.bare_str(), v)) {
if (!m_vars.find(d, v)) {
idx = m_num_vars++;
v = m.mk_var(idx, s);
m_vars.insert(data.bare_str(), v);
m_vars.insert(d, v);
}
else if (s != v->get_sort()) {
throw default_exception(default_exception::fmt(), "sort: %s expected, but got: %s\n",
s->get_name().bare_str(), v->get_sort()->get_name().bare_str());
s->get_name().str().c_str(), v->get_sort()->get_name().str().c_str());
}
args.push_back(v);
}
@ -1075,21 +1077,21 @@ protected:
}
sort * register_finite_sort(symbol name, uint64_t domain_size, context::sort_kind k) {
if(m_sort_dict.contains(name.bare_str())) {
throw default_exception(default_exception::fmt(), "sort %s already declared", name.bare_str());
if(m_sort_dict.contains(name.str().c_str())) {
throw default_exception(default_exception::fmt(), "sort %s already declared", name.str().c_str());
}
sort * s = m_decl_util.mk_sort(name, domain_size);
m_context.register_finite_sort(s, k);
m_sort_dict.insert(name.bare_str(), s);
m_sort_dict.insert(name.str(), s);
return s;
}
sort * register_int_sort(symbol name) {
if(m_sort_dict.contains(name.bare_str())) {
throw default_exception(default_exception::fmt(), "sort %s already declared", name.bare_str());
if(m_sort_dict.contains(name.str().c_str())) {
throw default_exception(default_exception::fmt(), "sort %s already declared", name.str().c_str());
}
sort * s = m_arith.mk_int();
m_sort_dict.insert(name.bare_str(), s);
m_sort_dict.insert(name.str(), s);
return s;
}
@ -1105,8 +1107,8 @@ protected:
app * res;
if(m_arith.is_int(s)) {
uint64_t val;
if (!string_to_uint64(name.bare_str(), val)) {
throw default_exception(default_exception::fmt(), "Invalid integer: \"%s\"", name.bare_str());
if (!string_to_uint64(name.str().c_str(), val)) {
throw default_exception(default_exception::fmt(), "Invalid integer: \"%s\"", name.str().c_str());
}
res = m_arith.mk_numeral(rational(val, rational::ui64()), s);
}
@ -1288,7 +1290,7 @@ private:
uint64_set & sort_content = *e->get_data().m_value;
if(!sort_content.contains(num)) {
warning_msg("symbol number %I64u on line %d in file %s does not belong to sort %s",
num, m_current_line, m_current_file.c_str(), s->get_name().bare_str());
num, m_current_line, m_current_file.c_str(), s->get_name().str().c_str());
return false;
}
if(!m_use_map_names) {
@ -1366,7 +1368,7 @@ private:
func_decl * pred = m_context.try_get_predicate_decl(predicate_name);
if(!pred) {
throw default_exception(default_exception::fmt(), "tuple file %s for undeclared predicate %s",
m_current_file.c_str(), predicate_name.bare_str());
m_current_file.c_str(), predicate_name.str().c_str());
}
unsigned pred_arity = pred->get_arity();
sort * const * arg_sorts = pred->get_domain();
@ -1531,9 +1533,9 @@ private:
if(m_use_map_names) {
auto const & value = m_number_names.insert_if_not_there(num, el_name);
if (value!=el_name) {
if (value != el_name) {
warning_msg("mismatch of number names on line %d in file %s. old: \"%s\" new: \"%s\"",
m_current_line, fname.c_str(), value.bare_str(), el_name.bare_str());
m_current_line, fname.c_str(), value.str().c_str(), el_name.str().c_str());
}
}
}

View file

@ -241,7 +241,7 @@ class horn_tactic : public tactic {
verify(q, g, result, mc, pc);
}
g->set(pc.get());
g->set(mc.get());
g->add(mc.get());
}
void verify(expr* q,
@ -282,12 +282,11 @@ class horn_tactic : public tactic {
}
case l_false: {
// goal is sat
mc = concat(g->mc(), mc.get());
g->reset();
if (produce_models) {
model_ref md = m_ctx.get_model();
model_converter_ref mc2 = model2model_converter(md.get());
mc = concat(mc.get(), mc2.get());
mc = mc2.get();
TRACE("dl", mc->display(tout << *md << "\n"););
}
break;
@ -345,6 +344,7 @@ class horn_tactic : public tactic {
g->assert_expr(fml);
}
g->set_prec(goal::UNDER_OVER);
mc = g->mc();
}
void check_parameters() {

View file

@ -64,7 +64,7 @@ namespace datalog {
}
symbol finite_product_relation_plugin::get_name(relation_plugin & inner_plugin) {
std::string str = std::string("fpr_")+inner_plugin.get_name().bare_str();
std::string str = std::string("fpr_")+inner_plugin.get_name().str();
return symbol(str.c_str());
}

View file

@ -213,10 +213,10 @@ namespace datalog {
return true;
}
void make_annotations(execution_context & ctx) override {
ctx.set_register_annotation(m_reg, m_pred->get_name().bare_str());
ctx.set_register_annotation(m_reg, m_pred->get_name().str().c_str());
}
std::ostream& display_head_impl(execution_context const& ctx, std::ostream & out) const override {
const char * rel_name = m_pred->get_name().bare_str();
auto rel_name = m_pred->get_name();
if (m_store) {
return out << "store " << m_reg << " into " << rel_name;
}
@ -378,7 +378,7 @@ namespace datalog {
if (!fn) {
throw default_exception(default_exception::fmt(),
"trying to perform unsupported join operation on relations of kinds %s and %s",
r1.get_plugin().get_name().bare_str(), r2.get_plugin().get_name().bare_str());
r1.get_plugin().get_name().str().c_str(), r2.get_plugin().get_name().str().c_str());
}
store_fn(r1, r2, fn);
}
@ -441,7 +441,7 @@ namespace datalog {
if (!fn) {
throw default_exception(default_exception::fmt(),
"trying to perform unsupported filter_equal operation on a relation of kind %s",
r.get_plugin().get_name().bare_str());
r.get_plugin().get_name().str().c_str());
}
store_fn(r, fn);
}
@ -490,7 +490,7 @@ namespace datalog {
if (!fn) {
throw default_exception(default_exception::fmt(),
"trying to perform unsupported filter_identical operation on a relation of kind %s",
r.get_plugin().get_name().bare_str());
r.get_plugin().get_name().str().c_str());
}
store_fn(r, fn);
}
@ -537,7 +537,7 @@ namespace datalog {
if (!fn) {
throw default_exception(default_exception::fmt(),
"trying to perform unsupported filter_interpreted operation on a relation of kind %s",
r.get_plugin().get_name().bare_str());
r.get_plugin().get_name().str().c_str());
}
store_fn(r, fn);
}
@ -594,7 +594,7 @@ namespace datalog {
if (!fn) {
throw default_exception(default_exception::fmt(),
"trying to perform unsupported filter_interpreted_and_project operation on a relation of kind %s",
reg.get_plugin().get_name().bare_str());
reg.get_plugin().get_name().str().c_str());
}
store_fn(reg, fn);
}
@ -837,7 +837,7 @@ namespace datalog {
if (!fn) {
throw default_exception(default_exception::fmt(),
"trying to perform unsupported join-project operation on relations of kinds %s and %s",
r1.get_plugin().get_name().bare_str(), r2.get_plugin().get_name().bare_str());
r1.get_plugin().get_name().str().c_str(), r2.get_plugin().get_name().str().c_str());
}
store_fn(r1, r2, fn);
}
@ -910,7 +910,7 @@ namespace datalog {
if (!fn) {
throw default_exception(default_exception::fmt(),
"trying to perform unsupported select_equal_and_project operation on a relation of kind %s",
r.get_plugin().get_name().bare_str());
r.get_plugin().get_name().str().c_str());
}
store_fn(r, fn);
}
@ -1076,7 +1076,7 @@ namespace datalog {
return true;
}
std::ostream& display_head_impl(execution_context const& ctx, std::ostream & out) const override {
return out << "mark_saturated " << m_pred->get_name().bare_str();
return out << "mark_saturated " << m_pred->get_name();
}
void make_annotations(execution_context & ctx) override {
}

View file

@ -370,7 +370,7 @@ namespace datalog {
rule * one_parent = inf.m_rules.back();
func_decl* parent_head = one_parent->get_decl();
const char * one_parent_name = parent_head->get_name().bare_str();
std::string one_parent_name = parent_head->get_name().str();
std::string parent_name;
if (inf.m_rules.size() > 1) {
parent_name = one_parent_name + std::string("_and_") + to_string(inf.m_rules.size()-1);

View file

@ -33,7 +33,7 @@ namespace datalog {
// -----------------------------------
symbol table_relation_plugin::create_plugin_name(const table_plugin &p) {
std::string name = std::string("tr_") + p.get_name().bare_str();
std::string name = std::string("tr_") + p.get_name().str();
return symbol(name.c_str());
}

View file

@ -157,7 +157,7 @@ namespace datalog {
//IF_VERBOSE(3, m_context.display_smt2(0,0,verbose_stream()););
if (m_context.print_aig().is_non_empty_string()) {
const char *filename = m_context.print_aig().bare_str();
std::string filename = m_context.print_aig().str();
aig_exporter aig(m_context.get_rules(), get_context(), &m_table_facts);
std::ofstream strm(filename, std::ios_base::binary);
aig(strm);

View file

@ -126,7 +126,7 @@ public:
void move_to_front(expr* e) override { m_solver.move_to_front(e); }
expr_ref_vector cube(expr_ref_vector&, unsigned) override { return expr_ref_vector(m); }
void get_levels(ptr_vector<expr> const& vars, unsigned_vector& depth) override { m_solver.get_levels(vars, depth); }
expr_ref_vector get_trail() override { return m_solver.get_trail(); }
expr_ref_vector get_trail(unsigned max_level) override { return m_solver.get_trail(max_level); }
void push() override;
void pop(unsigned n) override;

View file

@ -118,7 +118,7 @@ namespace datalog {
}
rule_set * mk_coi_filter::top_down(rule_set const & source) {
func_decl_set pruned_preds;
func_decl_set pruned_preds, seen;
dataflow_engine<reachability_info> engine(source.get_manager(), source);
engine.run_top_down();
scoped_ptr<rule_set> res = alloc(rule_set, m_context);
@ -126,37 +126,51 @@ namespace datalog {
for (rule * r : source) {
func_decl * pred = r->get_decl();
if (engine.get_fact(pred).is_reachable()) {
res->add_rule(r);
}
bool should_keep = false;
if (seen.contains(pred))
continue;
seen.insert(pred);
if (engine.get_fact(pred).is_reachable())
should_keep = true;
else if (m_context.get_model_converter()) {
pruned_preds.insert(pred);
for (rule* pr : source.get_predicate_rules(pred))
for (unsigned i = 0; i < pr->get_uninterpreted_tail_size(); ++i)
if (pr->get_tail(i)->get_decl() != pred)
// don't try to eliminate across predicates
return nullptr;
}
else
continue;
if (should_keep)
for (rule* pr : source.get_predicate_rules(pred))
res->add_rule(pr);
else
pruned_preds.insert(pred);
}
if (res->get_num_rules() == source.get_num_rules()) {
TRACE("dl", tout << "No transformation\n";);
res = nullptr;
}
if (res && m_context.get_model_converter()) {
generic_model_converter* mc0 = alloc(generic_model_converter, m, "dl_coi");
for (func_decl* f : pruned_preds) {
if (res && m_context.get_model_converter() && !pruned_preds.empty()) {
auto* mc0 = alloc(generic_model_converter, m, "dl_coi");
horn_subsume_model_converter hmc(m);
for (func_decl* f : pruned_preds) {
const rule_vector& rules = source.get_predicate_rules(f);
expr_ref_vector fmls(m);
for (rule * r : rules) {
app* head = r->get_head();
expr_ref_vector conj(m);
for (unsigned j = 0; j < head->get_num_args(); ++j) {
expr* arg = head->get_arg(j);
if (!is_var(arg)) {
conj.push_back(m.mk_eq(m.mk_var(j, arg->get_sort()), arg));
}
}
fmls.push_back(mk_and(conj));
for (rule* r : rules) {
expr_ref_vector constraints(m);
expr_ref body_res(m);
func_decl_ref pred(m);
for (unsigned i = r->get_uninterpreted_tail_size(); i < r->get_tail_size(); ++i)
constraints.push_back(r->get_tail(i));
expr_ref body = mk_and(constraints);
VERIFY(hmc.mk_horn(r->get_head(), body, pred, body_res));
fmls.push_back(body_res);
}
expr_ref fml(m);
fml = m.mk_or(fmls.size(), fmls.data());
mc0->add(f, fml);
mc0->add(f, mk_or(fmls));
}
m_context.add_model_converter(mc0);
}

View file

@ -44,6 +44,11 @@ Subsumption transformation (remove rule):
P(x) := P(x) or (exists y . Q(y) & phi(x,y))
For plan_inlining:
TODO: order of rule inlining would affect model converter?
so shouldn't model converter process inlined rules in a specific (topopologial) order?
--*/
@ -377,18 +382,15 @@ namespace datalog {
return something_forbidden;
}
void mk_rule_inliner::plan_inlining(rule_set const & orig)
{
void mk_rule_inliner::plan_inlining(rule_set const & orig) {
count_pred_occurrences(orig);
scoped_ptr<rule_set> candidate_inlined_set = create_allowed_rule_set(orig);
while (forbid_preds_from_cycles(*candidate_inlined_set)) {
while (forbid_preds_from_cycles(*candidate_inlined_set))
candidate_inlined_set = create_allowed_rule_set(orig);
}
if (forbid_multiple_multipliers(orig, *candidate_inlined_set)) {
if (forbid_multiple_multipliers(orig, *candidate_inlined_set))
candidate_inlined_set = create_allowed_rule_set(orig);
}
TRACE("dl", tout<<"rules to be inlined:\n" << (*candidate_inlined_set); );
@ -402,16 +404,13 @@ namespace datalog {
for (rule_stratifier::item_set * stratum : comps) {
SASSERT(stratum->size() == 1);
func_decl * pred = *stratum->begin();
for (rule * r : candidate_inlined_set->get_predicate_rules(pred)) {
for (rule * r : candidate_inlined_set->get_predicate_rules(pred))
transform_rule(orig, r, m_inlined_rules);
}
}
TRACE("dl", tout << "inlined rules after mutual inlining:\n" << m_inlined_rules; );
for (rule * r : m_inlined_rules)
datalog::del_rule(m_mc, *r, l_undef);
for (rule * r : m_inlined_rules) {
datalog::del_rule(m_mc, *r, false);
}
}
bool mk_rule_inliner::transform_rule(rule_set const& orig, rule * r0, rule_set& tgt) {
@ -437,20 +436,19 @@ namespace datalog {
tgt.add_rule(r);
continue;
}
modified = true;
func_decl * pred = r->get_decl(i);
const rule_vector& pred_rules = m_inlined_rules.get_predicate_rules(pred);
for (rule * inl_rule : pred_rules) {
rule_ref inl_result(m_rm);
if (try_to_inline_rule(*r.get(), *inl_rule, i, inl_result)) {
if (try_to_inline_rule(*r.get(), *inl_rule, i, inl_result))
todo.push_back(inl_result);
}
}
}
if (modified) {
datalog::del_rule(m_mc, *r0, true);
}
if (modified)
datalog::del_rule(m_mc, *r0, l_undef);
return modified;
}
@ -473,7 +471,7 @@ namespace datalog {
if (something_done && m_mc) {
for (rule* r : orig) {
if (inlining_allowed(orig, r->get_decl())) {
datalog::del_rule(m_mc, *r, true);
datalog::del_rule(m_mc, *r, l_undef);
}
}
}
@ -558,7 +556,7 @@ namespace datalog {
// nothing unifies with the tail atom, therefore the rule is unsatisfiable
// (we can say this because relation pred doesn't have any ground facts either)
res = nullptr;
datalog::del_rule(m_mc, *r, false);
datalog::del_rule(m_mc, *r, l_false);
return true;
}
if (!is_oriented_rewriter(inlining_candidate, strat)) {
@ -568,7 +566,7 @@ namespace datalog {
goto process_next_tail;
}
if (!try_to_inline_rule(*r, *inlining_candidate, ti, res)) {
datalog::del_rule(m_mc, *r, false);
datalog::del_rule(m_mc, *r, l_false);
res = nullptr;
}
return true;
@ -768,7 +766,7 @@ namespace datalog {
break;
}
rule* r2 = acc[j].get();
rule* r2 = acc.get(j);
// check that the head of r2 only unifies with this single body position.
TRACE("dl", output_predicate(m_context, r2->get_head(), tout << "unify head: "); tout << "\n";);
@ -801,7 +799,7 @@ namespace datalog {
if (num_tail_unifiers == 1) {
TRACE("dl", tout << "setting invalid: " << j << "\n";);
valid.set(j, false);
datalog::del_rule(m_mc, *r2, true);
datalog::del_rule(m_mc, *r2, l_undef);
del_rule(r2, j);
}

View file

@ -8,6 +8,7 @@ z3_add_component(opt
opt_lns.cpp
opt_pareto.cpp
opt_parse.cpp
opt_preprocess.cpp
optsmt.cpp
opt_solver.cpp
pb_sls.cpp

View file

@ -26,15 +26,15 @@ Author:
namespace opt {
bool is_maxlex(weights_t & _ws) {
vector<rational> ws(_ws);
std::sort(ws.begin(), ws.end());
bool is_maxlex(vector<soft> const & _ws) {
vector<soft> ws(_ws);
std::sort(ws.begin(), ws.end(), [&](soft const& s1, soft const& s2) { return s1.weight < s2.weight; });
ws.reverse();
rational sum(0);
for (rational const& w : ws) {
for (auto const& [e, w, t] : ws) {
sum += w;
}
for (rational const& w : ws) {
for (auto const& [e, w, t] : ws) {
if (sum > w + w) return false;
sum -= w;
}
@ -185,8 +185,8 @@ namespace opt {
public:
maxlex(maxsat_context& c, unsigned id, weights_t & ws, expr_ref_vector const& s):
maxsmt_solver_base(c, ws, s),
maxlex(maxsat_context& c, unsigned id, vector<soft>& s):
maxsmt_solver_base(c, s, id),
m(c.get_manager()),
m_c(c) {
// ensure that soft constraints are sorted with largest soft constraints first.
@ -210,8 +210,8 @@ namespace opt {
}
};
maxsmt_solver_base* mk_maxlex(maxsat_context& c, unsigned id, weights_t & ws, expr_ref_vector const& soft) {
return alloc(maxlex, c, id, ws, soft);
maxsmt_solver_base* mk_maxlex(maxsat_context& c, unsigned id, vector<soft>& soft) {
return alloc(maxlex, c, id, soft);
}
}

View file

@ -21,9 +21,9 @@ Notes:
namespace opt {
bool is_maxlex(weights_t & ws);
bool is_maxlex(vector<soft> const & ws);
maxsmt_solver_base* mk_maxlex(maxsat_context& c, unsigned id, weights_t & ws, expr_ref_vector const& soft);
maxsmt_solver_base* mk_maxlex(maxsat_context& c, unsigned id, vector<soft>& soft);
};

View file

@ -72,7 +72,9 @@ class maxres : public maxsmt_solver_base {
public:
enum strategy_t {
s_primal,
s_primal_dual
s_primal_dual,
s_primal_binary,
s_primal_binary_delay
};
private:
struct stats {
@ -95,7 +97,6 @@ private:
expr_ref_vector const& soft() override { return i.m_asms; }
};
unsigned m_index;
stats m_stats;
expr_ref_vector m_B;
expr_ref_vector m_asms;
@ -129,11 +130,10 @@ private:
typedef ptr_vector<expr> exprs;
public:
maxres(maxsat_context& c, unsigned index,
weights_t& ws, expr_ref_vector const& soft,
maxres(maxsat_context& c, unsigned index,
vector<soft>& soft,
strategy_t st):
maxsmt_solver_base(c, ws, soft),
m_index(index),
maxsmt_solver_base(c, soft, index),
m_B(m), m_asms(m), m_defs(m),
m_new_core(m),
m_mus(c.get_solver()),
@ -159,6 +159,12 @@ public:
case s_primal_dual:
m_trace_id = "pd-maxres";
break;
case s_primal_binary:
m_trace_id = "maxres-bin";
break;
case s_primal_binary_delay:
m_trace_id = "maxres-bin-delay";
break;
}
}
@ -359,6 +365,8 @@ public:
m_defs.reset();
switch(m_st) {
case s_primal:
case s_primal_binary:
case s_primal_binary_delay:
return mus_solver();
case s_primal_dual:
return primal_dual_solver();
@ -534,8 +542,18 @@ public:
expr_ref fml(m);
SASSERT(!core.empty());
TRACE("opt", display_vec(tout << "minimized core: ", core););
IF_VERBOSE(10, display_vec(verbose_stream() << "core: ", core););
max_resolve(core, w);
IF_VERBOSE(10, display_vec(verbose_stream() << "core: ", core););
switch (m_st) {
case strategy_t::s_primal_binary:
bin_max_resolve(core, w);
break;
case strategy_t::s_primal_binary_delay:
bin_delay_max_resolve(core, w);
break;
default:
max_resolve(core, w);
break;
}
fml = mk_not(m, mk_and(m, core.size(), core.data()));
add(fml);
// save small cores such that lex-combinations of maxres can reuse these cores.
@ -651,6 +669,7 @@ public:
}
}
void max_resolve(exprs const& core, rational const& w) {
SASSERT(!core.empty());
expr_ref fml(m), asum(m);
@ -701,6 +720,107 @@ public:
}
}
void bin_max_resolve(exprs const& _core, rational const& w) {
expr_ref_vector core(m, _core.size(), _core.data());
expr_ref fml(m), cls(m);
for (unsigned i = 0; i + 1 < core.size(); i += 2) {
expr* a = core.get(i);
expr* b = core.get(i + 1);
expr* u = mk_fresh_bool("u");
expr* v = mk_fresh_bool("v");
// u = a or b
// v = a and b
cls = m.mk_or(a, b);
fml = m.mk_implies(u, cls);
add(fml);
update_model(u, cls);
m_defs.push_back(fml);
cls = m.mk_and(a, b);
fml = m.mk_implies(v, cls);
add(fml);
update_model(v, cls);
m_defs.push_back(fml);
new_assumption(u, w);
core.push_back(v);
}
s().assert_expr(m.mk_not(core.back()));
}
struct unfold_record {
ptr_vector<expr> ws;
rational weight;
};
obj_map<expr, unfold_record> m_unfold;
rational m_unfold_upper;
void bin_delay_max_resolve(exprs const& _core, rational const& weight) {
expr_ref_vector core(m, _core.size(), _core.data()), partial(m);
expr_ref fml(m), cls(m);
for (expr* c : core) {
unfold_record r;
if (!m_unfold.find(c, r))
continue;
IF_VERBOSE(2, verbose_stream() << "to unfold " << mk_pp(c, m) << "\n");
for (expr* f : r.ws) {
IF_VERBOSE(2, verbose_stream() << "unfold " << mk_pp(f, m) << "\n");
new_assumption(f, r.weight);
}
m_unfold_upper -= r.weight * rational(r.ws.size() - 1);
m_unfold.remove(c);
}
for (expr* _ : core)
partial.push_back(nullptr);
std::cout << "Core size " << core.size() << "\n";
if (core.size() > 2)
m_unfold_upper += rational(core.size()-2)*weight;
expr* w = nullptr;
for (unsigned i = 0; i + 1 < core.size(); i += 2) {
expr* a = core.get(i);
expr* b = core.get(i + 1);
expr* u = mk_fresh_bool("u");
expr* v = mk_fresh_bool("v");
// u = a or b
// v = a and b
cls = m.mk_or(a, b);
fml = m.mk_implies(u, cls);
add(fml);
update_model(u, cls);
m_defs.push_back(fml);
cls = m.mk_and(a, b);
fml = m.mk_implies(v, cls);
add(fml);
update_model(v, cls);
m_defs.push_back(fml);
core.push_back(v);
// w = u and w1 and w2
unfold_record r;
r.ws.push_back(u);
if (partial.get(i))
r.ws.push_back(partial.get(i));
if (partial.get(i + 1))
r.ws.push_back(partial.get(i + 1));
m_trail.append(r.ws.size(), r.ws.data());
w = mk_fresh_bool("w");
cls = m.mk_and(r.ws);
fml = m.mk_implies(w, cls);
partial.push_back(w);
add(fml);
update_model(w, cls);
m_defs.push_back(fml);
m_unfold.insert(w, r);
}
new_assumption(w, weight);
s().assert_expr(m.mk_not(core.back()));
}
// cs is a correction set (a complement of a (maximal) satisfying assignment).
void cs_max_resolve(exprs const& cs, rational const& w) {
if (cs.empty()) return;
@ -780,7 +900,7 @@ public:
}
rational cost(model& mdl) {
rational upper(0);
rational upper = m_unfold_upper;
for (soft& s : m_soft)
if (!mdl.is_true(s.s))
upper += s.weight;
@ -791,11 +911,10 @@ public:
improve_model(mdl);
mdl->set_model_completion(true);
unsigned correction_set_size = 0;
for (expr* a : m_asms) {
if (mdl->is_false(a)) {
for (expr* a : m_asms)
if (mdl->is_false(a))
++correction_set_size;
}
}
if (!m_csmodel.get() || correction_set_size < m_correction_set_size) {
m_csmodel = mdl;
m_correction_set_size = correction_set_size;
@ -810,22 +929,22 @@ public:
return;
}
if (!m_c.verify_model(m_index, mdl.get(), upper)) {
if (!m_c.verify_model(m_index, mdl.get(), upper))
return;
}
unsigned num_assertions = s().get_num_assertions();
m_model = mdl;
m_c.model_updated(mdl.get());
TRACE("opt", tout << "updated upper: " << upper << "\n";);
for (soft& s : m_soft) {
for (soft& s : m_soft)
s.set_value(m_model->is_true(s.s));
}
verify_assignment();
m_upper = upper;
if (num_assertions == s().get_num_assertions())
m_upper = upper;
trace();
@ -876,23 +995,18 @@ public:
}
lbool init_local() {
m_lower.reset();
m_trail.reset();
lbool is_sat = l_true;
obj_map<expr, rational> new_soft;
is_sat = find_mutexes(new_soft);
if (is_sat != l_true) {
return is_sat;
}
for (auto const& kv : new_soft) {
add_soft(kv.m_key, kv.m_value);
}
for (auto const& [e, w, t] : m_soft)
add_soft(e, w);
m_max_upper = m_upper;
m_found_feasible_optimum = false;
m_last_index = 0;
add_upper_bound_block();
m_csmodel = nullptr;
m_correction_set_size = 0;
m_unfold.reset();
m_unfold_upper = 0;
return l_true;
}
@ -954,12 +1068,22 @@ public:
};
opt::maxsmt_solver_base* opt::mk_maxres(
maxsat_context& c, unsigned id, weights_t& ws, expr_ref_vector const& soft) {
return alloc(maxres, c, id, ws, soft, maxres::s_primal);
maxsat_context& c, unsigned id, vector<soft>& soft) {
return alloc(maxres, c, id, soft, maxres::s_primal);
}
opt::maxsmt_solver_base* opt::mk_maxres_binary(
maxsat_context& c, unsigned id, vector<soft>& soft) {
return alloc(maxres, c, id, soft, maxres::s_primal_binary);
}
opt::maxsmt_solver_base* opt::mk_maxres_binary_delay(
maxsat_context& c, unsigned id, vector<soft>& soft) {
return alloc(maxres, c, id, soft, maxres::s_primal_binary_delay);
}
opt::maxsmt_solver_base* opt::mk_primal_dual_maxres(
maxsat_context& c, unsigned id, weights_t& ws, expr_ref_vector const& soft) {
return alloc(maxres, c, id, ws, soft, maxres::s_primal_dual);
maxsat_context& c, unsigned id, vector<soft>& soft) {
return alloc(maxres, c, id, soft, maxres::s_primal_dual);
}

View file

@ -21,9 +21,13 @@ Notes:
namespace opt {
maxsmt_solver_base* mk_maxres(maxsat_context& c, unsigned id, weights_t & ws, expr_ref_vector const& soft);
maxsmt_solver_base* mk_maxres(maxsat_context& c, unsigned id, vector<soft>& soft);
maxsmt_solver_base* mk_primal_dual_maxres(maxsat_context& c, unsigned id, weights_t & ws, expr_ref_vector const& soft);
maxsmt_solver_base* mk_maxres_binary(maxsat_context& c, unsigned id, vector<soft>& soft);
maxsmt_solver_base* mk_maxres_binary_delay(maxsat_context& c, unsigned id, vector<soft>& soft);
maxsmt_solver_base* mk_primal_dual_maxres(maxsat_context& c, unsigned id, vector<soft>& soft);
};

View file

@ -28,29 +28,34 @@ Notes:
#include "opt/wmax.h"
#include "opt/opt_params.hpp"
#include "opt/opt_context.h"
#include "opt/opt_preprocess.h"
#include "smt/theory_wmaxsat.h"
#include "smt/theory_pb.h"
namespace opt {
maxsmt_solver_base::maxsmt_solver_base(
maxsat_context& c, vector<rational> const& ws, expr_ref_vector const& softs):
maxsmt_solver_base::maxsmt_solver_base(maxsat_context& c, vector<soft>& s, unsigned index):
m(c.get_manager()),
m_c(c),
m_index(index),
m_soft(s),
m_assertions(m),
m_trail(m) {
c.get_base_model(m_model);
SASSERT(m_model);
updt_params(c.params());
for (unsigned i = 0; i < ws.size(); ++i) {
m_soft.push_back(soft(expr_ref(softs.get(i), m), ws[i], false));
}
}
void maxsmt_solver_base::updt_params(params_ref& p) {
m_params.copy(p);
}
}
void maxsmt_solver_base::reset_upper() {
m_upper = m_lower;
for (soft& s : m_soft)
m_upper += s.weight;
}
solver& maxsmt_solver_base::s() {
return m_c.get_solver();
@ -82,14 +87,24 @@ namespace opt {
m_upper.reset();
for (soft& s : m_soft) {
s.set_value(m.is_true(s.s));
if (!s.is_true()) m_upper += s.weight;
if (!s.is_true())
m_upper += s.weight;
}
// return true;
preprocess pp(s());
rational lower(0);
bool r = pp(m_soft, lower);
m_c.add_offset(m_index, lower);
m_upper -= lower;
TRACE("opt",
tout << "upper: " << m_upper << " assignments: ";
tout << "lower " << lower << " upper: " << m_upper << " assignments: ";
for (soft& s : m_soft) tout << (s.is_true()?"T":"F");
tout << "\n";);
return true;
return r;
}
void maxsmt_solver_base::set_mus(bool f) {
@ -153,80 +168,15 @@ namespace opt {
void maxsmt_solver_base::trace_bounds(char const * solver) {
IF_VERBOSE(1,
rational l = m_adjust_value(m_lower);
rational u = m_adjust_value(m_upper);
rational l = m_c.adjust(m_index, m_lower);
rational u = m_c.adjust(m_index, m_upper);
if (l > u) std::swap(l, u);
verbose_stream() << "(opt." << solver << " [" << l << ":" << u << "])\n";);
}
lbool maxsmt_solver_base::find_mutexes(obj_map<expr, rational>& new_soft) {
m_lower.reset();
expr_ref_vector fmls(m);
for (soft& s : m_soft) {
new_soft.insert(s.s, s.weight);
fmls.push_back(s.s);
}
vector<expr_ref_vector> mutexes;
lbool is_sat = s().find_mutexes(fmls, mutexes);
if (is_sat != l_true) {
return is_sat;
}
for (auto& mux : mutexes) {
process_mutex(mux, new_soft);
}
return l_true;
}
struct maxsmt_compare_soft {
obj_map<expr, rational> const& m_soft;
maxsmt_compare_soft(obj_map<expr, rational> const& soft): m_soft(soft) {}
bool operator()(expr* a, expr* b) const {
return m_soft.find(a) > m_soft.find(b);
}
};
void maxsmt_solver_base::process_mutex(expr_ref_vector& mutex, obj_map<expr, rational>& new_soft) {
TRACE("opt",
for (expr* e : mutex) {
tout << mk_pp(e, m) << " |-> " << new_soft.find(e) << "\n";
});
if (mutex.size() <= 1) {
return;
}
maxsmt_compare_soft cmp(new_soft);
ptr_vector<expr> _mutex(mutex.size(), mutex.data());
std::sort(_mutex.begin(), _mutex.end(), cmp);
mutex.reset();
mutex.append(_mutex.size(), _mutex.data());
rational weight(0), sum1(0), sum2(0);
vector<rational> weights;
for (expr* e : mutex) {
rational w = new_soft.find(e);
weights.push_back(w);
sum1 += w;
new_soft.remove(e);
}
for (unsigned i = mutex.size(); i-- > 0; ) {
expr_ref soft(m.mk_or(i+1, mutex.data()), m);
m_trail.push_back(soft);
rational w = weights[i];
weight = w - weight;
m_lower += weight*rational(i);
IF_VERBOSE(1, verbose_stream() << "(opt.maxsat mutex size: " << i + 1 << " weight: " << weight << ")\n";);
sum2 += weight*rational(i+1);
new_soft.insert(soft, weight);
for (; i > 0 && weights[i-1] == w; --i) {}
weight = w;
}
SASSERT(sum1 == sum2);
}
maxsmt::maxsmt(maxsat_context& c, unsigned index):
m(c.get_manager()), m_c(c), m_index(index),
m_soft_constraints(m), m_answer(m) {}
m(c.get_manager()), m_c(c), m_index(index), m_answer(m) {}
lbool maxsmt::operator()() {
lbool is_sat = l_undef;
@ -235,30 +185,35 @@ namespace opt {
symbol const& maxsat_engine = m_c.maxsat_engine();
IF_VERBOSE(1, verbose_stream() << "(maxsmt)\n";);
TRACE("opt_verbose", s().display(tout << "maxsmt\n") << "\n";);
if (optp.maxlex_enable() && is_maxlex(m_weights)) {
m_msolver = mk_maxlex(m_c, m_index, m_weights, m_soft_constraints);
if (optp.maxlex_enable() && is_maxlex(m_soft)) {
m_msolver = mk_maxlex(m_c, m_index, m_soft);
}
else if (m_soft_constraints.empty() || maxsat_engine == symbol("maxres") || maxsat_engine == symbol::null) {
m_msolver = mk_maxres(m_c, m_index, m_weights, m_soft_constraints);
else if (m_soft.empty() || maxsat_engine == symbol("maxres") || maxsat_engine == symbol::null) {
m_msolver = mk_maxres(m_c, m_index, m_soft);
}
else if (maxsat_engine == symbol("maxres-bin")) {
m_msolver = mk_maxres_binary(m_c, m_index, m_soft);
}
else if (maxsat_engine == symbol("maxres-bin-delay")) {
m_msolver = mk_maxres_binary_delay(m_c, m_index, m_soft);
}
else if (maxsat_engine == symbol("pd-maxres")) {
m_msolver = mk_primal_dual_maxres(m_c, m_index, m_weights, m_soft_constraints);
m_msolver = mk_primal_dual_maxres(m_c, m_index, m_soft);
}
else if (maxsat_engine == symbol("wmax")) {
m_msolver = mk_wmax(m_c, m_weights, m_soft_constraints);
m_msolver = mk_wmax(m_c, m_soft, m_index);
}
else if (maxsat_engine == symbol("sortmax")) {
m_msolver = mk_sortmax(m_c, m_weights, m_soft_constraints);
m_msolver = mk_sortmax(m_c, m_soft, m_index);
}
else {
auto str = maxsat_engine.str();
warning_msg("solver %s is not recognized, using default 'maxres'", str.c_str());
m_msolver = mk_maxres(m_c, m_index, m_weights, m_soft_constraints);
m_msolver = mk_maxres(m_c, m_index, m_soft);
}
if (m_msolver) {
m_msolver->updt_params(m_params);
m_msolver->set_adjust_value(m_adjust_value);
is_sat = l_undef;
try {
is_sat = (*m_msolver)();
@ -282,14 +237,13 @@ namespace opt {
return is_sat;
}
void maxsmt::set_adjust_value(adjust_value& adj) {
m_adjust_value = adj;
void maxsmt::reset_upper() {
if (m_msolver) {
m_msolver->set_adjust_value(m_adjust_value);
m_msolver->reset_upper();
m_upper = m_msolver->get_upper();
}
}
void maxsmt::verify_assignment() {
// TBD: have to use a different solver
// because we don't push local scope any longer.
@ -311,7 +265,7 @@ namespace opt {
rational q = m_msolver->get_lower();
if (q > r) r = q;
}
return m_adjust_value(r);
return m_c.adjust(m_index, r);
}
rational maxsmt::get_upper() const {
@ -320,7 +274,7 @@ namespace opt {
rational q = m_msolver->get_upper();
if (q < r) r = q;
}
return m_adjust_value(r);
return m_c.adjust(m_index, r);
}
void maxsmt::update_lower(rational const& r) {
@ -348,39 +302,32 @@ namespace opt {
SASSERT(w.is_pos());
unsigned index = 0;
if (m_soft_constraint_index.find(f, index)) {
m_weights[index] += w;
m_soft[index].weight += w;
}
else {
m_soft_constraint_index.insert(f, m_weights.size());
m_soft_constraints.push_back(f);
m_weights.push_back(w);
m_soft_constraint_index.insert(f, m_soft.size());
m_soft.push_back(soft(expr_ref(f, m), w, false));
}
m_upper += w;
}
struct cmp_first {
bool operator()(std::pair<unsigned, rational> const& x, std::pair<unsigned, rational> const& y) const {
return x.first < y.first;
return x.second < y.second;
}
};
void maxsmt::display_answer(std::ostream& out) const {
vector<std::pair<unsigned, rational>> sorted_weights;
unsigned n = m_weights.size();
for (unsigned i = 0; i < n; ++i) {
sorted_weights.push_back(std::make_pair(i, m_weights[i]));
}
std::sort(sorted_weights.begin(), sorted_weights.end(), cmp_first());
sorted_weights.reverse();
for (unsigned i = 0; i < n; ++i) {
unsigned idx = sorted_weights[i].first;
expr* e = m_soft_constraints[idx];
unsigned idx = 0;
for (auto const & [_e, w, t] : m_soft) {
expr* e = _e.get();
bool is_not = m.is_not(e, e);
out << m_weights[idx] << ": " << mk_pp(e, m)
out << w << ": " << mk_pp(e, m)
<< ((is_not != get_assignment(idx))?" |-> true ":" |-> false ")
<< "\n";
}
++idx;
}
}
@ -420,6 +367,7 @@ namespace opt {
model_ref m_model;
ref<generic_model_converter> m_fm;
symbol m_maxsat_engine;
vector<rational> m_offsets;
public:
solver_maxsat_context(params_ref& p, solver* s, model * m):
m_params(p),
@ -444,6 +392,14 @@ namespace opt {
bool verify_model(unsigned id, model* mdl, rational const& v) override { return true; };
void set_model(model_ref& _m) override { m_model = _m; }
void model_updated(model* mdl) override { } // no-op
rational adjust(unsigned id, rational const& r) override {
m_offsets.reserve(id+1);
return r + m_offsets[id];
}
void add_offset(unsigned id, rational const& r) override {
m_offsets.reserve(id+1);
m_offsets[id] += r;
}
};
lbool maxsmt_wrapper::operator()(vector<std::pair<expr*,rational>>& soft) {

View file

@ -34,8 +34,6 @@ namespace opt {
class maxsat_context;
class maxsmt_solver {
protected:
adjust_value m_adjust_value;
public:
virtual ~maxsmt_solver() {}
virtual lbool operator()() = 0;
@ -45,28 +43,30 @@ namespace opt {
virtual void collect_statistics(statistics& st) const = 0;
virtual void get_model(model_ref& mdl, svector<symbol>& labels) = 0;
virtual void updt_params(params_ref& p) = 0;
void set_adjust_value(adjust_value& adj) { m_adjust_value = adj; }
};
// ---------------------------------------------
// base class with common utilities used
// by maxsmt solvers
//
//
struct soft {
expr_ref s;
rational weight;
lbool value;
void set_value(bool t) { value = t?l_true:l_undef; }
void set_value(lbool t) { value = t; }
bool is_true() const { return value == l_true; }
soft(expr_ref const& s, rational const& w, bool t): s(s), weight(w), value(t?l_true:l_undef) {}
};
class maxsmt_solver_base : public maxsmt_solver {
protected:
struct soft {
expr_ref s;
rational weight;
lbool value;
void set_value(bool t) { value = t?l_true:l_undef; }
void set_value(lbool t) { value = t; }
bool is_true() const { return value == l_true; }
soft(expr_ref const& s, rational const& w, bool t): s(s), weight(w), value(t?l_true:l_undef) {}
};
ast_manager& m;
maxsat_context& m_c;
vector<soft> m_soft;
maxsat_context& m_c;
unsigned m_index;
vector<soft>& m_soft;
expr_ref_vector m_assertions;
expr_ref_vector m_trail;
rational m_lower;
@ -76,8 +76,8 @@ namespace opt {
params_ref m_params; // config
public:
maxsmt_solver_base(maxsat_context& c, weights_t& ws, expr_ref_vector const& soft);
maxsmt_solver_base(maxsat_context& c, vector<soft>& soft, unsigned index);
~maxsmt_solver_base() override {}
rational get_lower() const override { return m_lower; }
rational get_upper() const override { return m_upper; }
@ -102,16 +102,13 @@ namespace opt {
smt::theory_wmaxsat& operator()();
};
lbool find_mutexes(obj_map<expr, rational>& new_soft);
void reset_upper();
protected:
void enable_sls(bool force);
void trace_bounds(char const* solver);
void process_mutex(expr_ref_vector& mutex, obj_map<expr, rational>& new_soft);
};
/**
@ -124,13 +121,11 @@ namespace opt {
maxsat_context& m_c;
unsigned m_index;
scoped_ptr<maxsmt_solver_base> m_msolver;
expr_ref_vector m_soft_constraints;
vector<soft> m_soft;
obj_map<expr, unsigned> m_soft_constraint_index;
expr_ref_vector m_answer;
vector<rational> m_weights;
rational m_lower;
rational m_upper;
adjust_value m_adjust_value;
model_ref m_model;
svector<symbol> m_labels;
params_ref m_params;
@ -139,10 +134,9 @@ namespace opt {
lbool operator()();
void updt_params(params_ref& p);
void add(expr* f, rational const& w);
void set_adjust_value(adjust_value& adj);
unsigned size() const { return m_soft_constraints.size(); }
expr* operator[](unsigned idx) const { return m_soft_constraints[idx]; }
rational weight(unsigned idx) const { return m_weights[idx]; }
unsigned size() const { return m_soft.size(); }
expr* operator[](unsigned idx) const { return m_soft[idx].s; }
rational weight(unsigned idx) const { return m_soft[idx].weight; }
void commit_assignment();
rational get_lower() const;
rational get_upper() const;
@ -153,6 +147,7 @@ namespace opt {
void display_answer(std::ostream& out) const;
void collect_statistics(statistics& st) const;
void model_updated(model* mdl);
void reset_upper();
private:
bool is_maxsat_problem(weights_t& ws) const;
void verify_assignment();

View file

@ -185,17 +185,36 @@ namespace opt {
}
void context::set_hard_constraints(expr_ref_vector const& fmls) {
if (m_scoped_state.set(fmls)) {
if (m_calling_on_model) {
for (expr* f : fmls)
add_hard_constraint(f);
return;
}
if (m_scoped_state.set(fmls))
clear_state();
}
void context::add_hard_constraint(expr* f) {
if (m_calling_on_model) {
get_solver().assert_expr(f);
for (auto const& [k, v] : m_maxsmts)
v->reset_upper();
for (unsigned i = 0; i < num_objectives(); ++i) {
auto const& o = m_scoped_state.m_objectives[i];
if (o.m_type != O_MAXSMT)
m_optsmt.update_upper(o.m_index, inf_eps::infinity());
}
}
else {
m_scoped_state.add(f);
clear_state();
}
}
void context::add_hard_constraint(expr* f) {
m_scoped_state.add(f);
clear_state();
}
void context::add_hard_constraint(expr* f, expr* t) {
if (m_calling_on_model)
throw default_exception("adding soft constraints is not supported during callbacks");
m_scoped_state.m_asms.push_back(t);
m_scoped_state.add(m.mk_implies(t, f));
clear_state();
@ -301,7 +320,7 @@ namespace opt {
IF_VERBOSE(1, verbose_stream() << "(optimize:check-sat)\n");
lbool is_sat = s.check_sat(asms.size(),asms.data());
lbool is_sat = s.check_sat(asms.size(), asms.data());
TRACE("opt", s.display(tout << "initial search result: " << is_sat << "\n"););
if (is_sat != l_false) {
@ -379,7 +398,7 @@ namespace opt {
}
void context::set_model(model_ref& m) {
m_model = m;
m_model = m;
opt_params optp(m_params);
if (optp.dump_models() && m) {
model_ref md = m->copy();
@ -389,6 +408,7 @@ namespace opt {
model_ref md = m->copy();
if (!m_model_fixed.contains(md.get()))
fix_model(md);
flet<bool> _calling(m_calling_on_model, true);
m_on_model_eh(m_on_model_ctx, md);
m_model_fixed.pop_back();
}
@ -910,7 +930,8 @@ namespace opt {
bool context::is_maxsat(expr* fml, expr_ref_vector& terms,
vector<rational>& weights, rational& offset,
bool& neg, symbol& id, expr_ref& orig_term, unsigned& index) {
if (!is_app(fml)) return false;
if (!is_app(fml))
return false;
neg = false;
orig_term = nullptr;
index = 0;
@ -1085,8 +1106,7 @@ namespace opt {
obj.m_weights.append(weights);
obj.m_adjust_value.set_offset(offset);
obj.m_adjust_value.set_negate(neg);
m_maxsmts.find(id)->set_adjust_value(obj.m_adjust_value);
TRACE("opt", tout << "maxsat: " << id << " offset:" << offset << "\n";
TRACE("opt", tout << "maxsat: " << neg << " " << id << " offset: " << offset << "\n";
tout << terms << "\n";);
}
else if (is_maximize(fml, tr, orig_term, index)) {
@ -1138,7 +1158,14 @@ namespace opt {
#endif
}
rational context::adjust(unsigned id, rational const& v) {
return m_objectives[id].m_adjust_value(v);
}
void context::add_offset(unsigned id, rational const& o) {
m_objectives[id].m_adjust_value.add_offset(o);
}
bool context::verify_model(unsigned index, model* md, rational const& _v) {
rational r;
app_ref term = m_objectives[index].m_term;
@ -1321,24 +1348,21 @@ namespace opt {
break;
}
case O_MAXSMT: {
bool ok = true;
for (unsigned j = 0; ok && j < obj.m_terms.size(); ++j) {
for (unsigned j = 0; j < obj.m_terms.size(); ++j) {
val = (*m_model)(obj.m_terms[j]);
TRACE("opt", tout << mk_pp(obj.m_terms[j], m) << " " << val << "\n";);
if (!m.is_true(val)) {
if (!m.is_true(val))
r += obj.m_weights[j];
}
}
if (ok) {
maxsmt& ms = *m_maxsmts.find(obj.m_id);
if (is_lower) {
ms.update_upper(r);
TRACE("opt", tout << "update upper from " << r << " to " << ms.get_upper() << "\n";);
}
else {
ms.update_lower(r);
TRACE("opt", tout << "update lower from " << r << " to " << ms.get_lower() << "\n";);
}
maxsmt& ms = *m_maxsmts.find(obj.m_id);
if (is_lower) {
ms.update_upper(r);
TRACE("opt", tout << "update upper from " << r << " to " << ms.get_upper() << "\n";);
}
else {
ms.update_lower(r);
TRACE("opt", tout << "update lower from " << r << " to " << ms.get_lower() << "\n";);
}
break;
}

View file

@ -57,6 +57,8 @@ namespace opt {
virtual smt::context& smt_context() = 0; // access SMT context for SMT based MaxSMT solver (wmax requires SMT core)
virtual unsigned num_objectives() = 0;
virtual bool verify_model(unsigned id, model* mdl, rational const& v) = 0;
virtual rational adjust(unsigned id, rational const& v) = 0;
virtual void add_offset(unsigned id, rational const& o) = 0;
virtual void set_model(model_ref& _m) = 0;
virtual void model_updated(model* mdl) = 0;
};
@ -93,7 +95,7 @@ namespace opt {
app_ref m_term; // for maximize, minimize term
expr_ref_vector m_terms; // for maxsmt
vector<rational> m_weights; // for maxsmt
adjust_value m_adjust_value;
adjust_value m_adjust_value;
symbol m_id; // for maxsmt
unsigned m_index; // for maximize/minimize index
@ -165,6 +167,7 @@ namespace opt {
ast_manager& m;
on_model_t m_on_model_ctx;
std::function<void(on_model_t&, model_ref&)> m_on_model_eh;
bool m_calling_on_model = false;
arith_util m_arith;
bv_util m_bv;
expr_ref_vector m_hard_constraints;
@ -268,11 +271,14 @@ namespace opt {
void model_updated(model* mdl) override;
rational adjust(unsigned id, rational const& v) override;
void add_offset(unsigned id, rational const& o) override;
void register_on_model(on_model_t& ctx, std::function<void(on_model_t&, model_ref&)>& on_model) {
m_on_model_ctx = ctx;
m_on_model_eh = on_model;
}
void collect_timer_stats(statistics& st) const {
if (m_time != 0)

32
src/opt/opt_mux.h Normal file
View file

@ -0,0 +1,32 @@
/*++
Copyright (c) 2021 Microsoft Corporation
Module Name:
opt_mux.h
Abstract:
Find mutexes - at most 1 constraints and modify soft constraints and bounds.
Author:
Nikolaj Bjorner (nbjorner) 2022-04-11
--*/
#pragma once
#include "opt/maxsmt.h"
namespace opt {
class mux {
ast_manager& m;
solver& s;
public:
mux(solver& s);
lbool operator()(vector<soft>& soft, rational& bound);
};
};

View file

@ -2,7 +2,7 @@ def_module_params('opt',
description='optimization parameters',
export=True,
params=(('optsmt_engine', SYMBOL, 'basic', "select optimization engine: 'basic', 'symba'"),
('maxsat_engine', SYMBOL, 'maxres', "select engine for maxsat: 'core_maxsat', 'wmax', 'maxres', 'pd-maxres'"),
('maxsat_engine', SYMBOL, 'maxres', "select engine for maxsat: 'core_maxsat', 'wmax', 'maxres', 'pd-maxres', 'maxres-bin', 'maxres-bin-delay'"),
('priority', SYMBOL, 'lex', "select how to priortize objectives: 'lex' (lexicographic), 'pareto', 'box'"),
('dump_benchmarks', BOOL, False, 'dump benchmarks for profiling'),
('dump_models', BOOL, False, 'display intermediary models to stdout'),

195
src/opt/opt_preprocess.cpp Normal file
View file

@ -0,0 +1,195 @@
/*++
Copyright (c) 2021 Microsoft Corporation
Module Name:
opt_preprocess.cpp
Abstract:
Pre-processing for MaxSMT
Find mutexes - at most 1 constraints and modify soft constraints and bounds.
Author:
Nikolaj Bjorner (nbjorner) 2022-04-11
--*/
#pragma once
#include "opt/opt_preprocess.h"
#include "util/max_cliques.h"
namespace opt {
expr_ref_vector preprocess::propagate(expr* f, lbool& is_sat) {
expr_ref_vector asms(m);
asms.push_back(f);
is_sat = s.check_sat(asms);
return s.get_trail(1);
}
bool preprocess::prop_mutexes(vector<soft>& softs, rational& lower) {
expr_ref_vector fmls(m);
obj_map<expr, rational> new_soft = soft2map(softs, fmls);
params_ref p;
p.set_uint("max_conflicts", 1);
s.updt_params(p);
obj_hashtable<expr> pfmls, nfmls;
for (expr* f : fmls)
if (m.is_not(f, f))
nfmls.insert(f);
else
pfmls.insert(f);
u_map<expr*> ids;
unsigned_vector ps;
for (expr* f : fmls) {
ids.insert(f->get_id(), f);
ps.push_back(f->get_id());
}
u_map<uint_set> conns;
for (expr* f : fmls) {
lbool is_sat;
expr_ref_vector trail = propagate(f, is_sat);
if (is_sat == l_false) {
rational w = new_soft[f];
lower += w;
s.assert_expr(m.mk_not(f));
new_soft.remove(f);
continue;
}
expr_ref_vector mux(m);
for (expr* g : trail) {
if (m.is_not(g, g)) {
if (pfmls.contains(g))
mux.push_back(g);
}
else if (nfmls.contains(g))
mux.push_back(m.mk_not(g));
}
uint_set reach;
for (expr* g : mux)
reach.insert(g->get_id());
conns.insert(f->get_id(), reach);
}
p.set_uint("max_conflicts", UINT_MAX);
s.updt_params(p);
struct neg_literal {
unsigned negate(unsigned id) {
throw default_exception("unexpected call");
}
};
max_cliques<neg_literal> mc;
vector<unsigned_vector> mutexes;
mc.cliques(ps, conns, mutexes);
for (auto& mux : mutexes) {
expr_ref_vector _mux(m);
for (auto p : mux)
_mux.push_back(ids[p]);
process_mutex(_mux, new_soft, lower);
}
softs.reset();
for (auto const& [k, v] : new_soft)
softs.push_back(soft(expr_ref(k, m), v, false));
m_trail.reset();
return true;
}
obj_map<expr, rational> preprocess::soft2map(vector<soft> const& softs, expr_ref_vector& fmls) {
obj_map<expr, rational> new_soft;
for (soft const& sf : softs) {
m_trail.push_back(sf.s);
if (new_soft.contains(sf.s))
new_soft[sf.s] += sf.weight;
else
new_soft.insert(sf.s, sf.weight);
fmls.push_back(sf.s);
}
return new_soft;
}
bool preprocess::find_mutexes(vector<soft>& softs, rational& lower) {
expr_ref_vector fmls(m);
obj_map<expr, rational> new_soft = soft2map(softs, fmls);
vector<expr_ref_vector> mutexes;
lbool is_sat = s.find_mutexes(fmls, mutexes);
if (is_sat == l_false)
return true;
if (is_sat == l_undef)
return false;
for (auto& mux : mutexes)
process_mutex(mux, new_soft, lower);
softs.reset();
for (auto const& [k, v] : new_soft)
softs.push_back(soft(expr_ref(k, m), v, false));
m_trail.reset();
return true;
}
struct maxsmt_compare_soft {
obj_map<expr, rational> const& m_soft;
maxsmt_compare_soft(obj_map<expr, rational> const& soft): m_soft(soft) {}
bool operator()(expr* a, expr* b) const {
return m_soft.find(a) > m_soft.find(b);
}
};
void preprocess::process_mutex(expr_ref_vector& mutex, obj_map<expr, rational>& new_soft, rational& lower) {
TRACE("opt",
for (expr* e : mutex) {
tout << mk_pp(e, m) << " |-> " << new_soft.find(e) << "\n";
});
if (mutex.size() <= 1)
return;
maxsmt_compare_soft cmp(new_soft);
ptr_vector<expr> _mutex(mutex.size(), mutex.data());
std::sort(_mutex.begin(), _mutex.end(), cmp);
mutex.reset();
mutex.append(_mutex.size(), _mutex.data());
rational weight(0), sum1(0), sum2(0);
vector<rational> weights;
for (expr* e : mutex) {
rational w = new_soft.find(e);
weights.push_back(w);
sum1 += w;
new_soft.remove(e);
}
for (unsigned i = mutex.size(); i-- > 0; ) {
expr_ref soft(m.mk_or(i+1, mutex.data()), m);
m_trail.push_back(soft);
rational w = weights[i];
weight = w - weight;
lower += weight*rational(i);
IF_VERBOSE(1, verbose_stream() << "(opt.maxsat mutex size: " << i + 1 << " weight: " << weight << ")\n";);
sum2 += weight*rational(i+1);
new_soft.insert(soft, weight);
for (; i > 0 && weights[i-1] == w; --i) {}
weight = w;
}
SASSERT(sum1 == sum2);
}
preprocess::preprocess(solver& s): m(s.get_manager()), s(s), m_trail(m) {}
bool preprocess::operator()(vector<soft>& soft, rational& lower) {
if (!find_mutexes(soft, lower))
return false;
if (false && !prop_mutexes(soft, lower))
return false;
return true;
}
};

41
src/opt/opt_preprocess.h Normal file
View file

@ -0,0 +1,41 @@
/*++
Copyright (c) 2021 Microsoft Corporation
Module Name:
opt_preprocess.h
Abstract:
Pre-processing for MaxSMT
Find mutexes - at most 1 constraints and modify soft constraints and bounds.
Author:
Nikolaj Bjorner (nbjorner) 2022-04-11
--*/
#pragma once
#include "opt/maxsmt.h"
namespace opt {
class preprocess {
ast_manager& m;
solver& s;
expr_ref_vector m_trail;
expr_ref_vector propagate(expr* f, lbool& is_sat);
obj_map<expr, rational> soft2map(vector<soft> const& softs, expr_ref_vector& fmls);
bool find_mutexes(vector<soft>& softs, rational& lower);
bool prop_mutexes(vector<soft>& softs, rational& lower);
void process_mutex(expr_ref_vector& mutex, obj_map<expr, rational>& new_soft, rational& lower);
public:
preprocess(solver& s);
bool operator()(vector<soft>& soft, rational& lower);
};
};

View file

@ -48,6 +48,7 @@ namespace opt {
void set_offset(rational const& o) { m_offset = o; }
void set_negate(bool neg) { m_negate = neg; }
rational const& get_offset() const { return m_offset; }
void add_offset(rational const& o) { if (m_negate) m_offset -= o; else m_offset += o; }
bool get_negate() { return m_negate; }
inf_eps operator()(inf_eps const& r) const {
inf_eps result = r;
@ -107,7 +108,7 @@ namespace opt {
lbool find_mutexes(expr_ref_vector const& vars, vector<expr_ref_vector>& mutexes) override;
lbool preferred_sat(expr_ref_vector const& asms, vector<expr_ref_vector>& cores) override;
void get_levels(ptr_vector<expr> const& vars, unsigned_vector& depth) override;
expr_ref_vector get_trail() override { return m_context.get_trail(); }
expr_ref_vector get_trail(unsigned max_level) override { return m_context.get_trail(max_level); }
expr_ref_vector cube(expr_ref_vector&, unsigned) override { return expr_ref_vector(m); }
void set_phase(expr* e) override { m_context.set_phase(e); }
phase* get_phase() override { return m_context.get_phase(); }

View file

@ -36,34 +36,27 @@ namespace opt {
expr_ref_vector m_trail;
func_decl_ref_vector m_fresh;
ref<generic_model_converter> m_filter;
sortmax(maxsat_context& c, weights_t& ws, expr_ref_vector const& soft):
maxsmt_solver_base(c, ws, soft), m_sort(*this), m_trail(m), m_fresh(m) {}
sortmax(maxsat_context& c, vector<soft>& s, unsigned index):
maxsmt_solver_base(c, s, index), m_sort(*this), m_trail(m), m_fresh(m) {}
~sortmax() override {}
lbool operator()() override {
obj_map<expr, rational> soft;
if (!init()) {
return l_false;
}
lbool is_sat = find_mutexes(soft);
if (is_sat != l_true) {
return is_sat;
}
if (!init())
return l_undef;
lbool is_sat = l_true;
m_filter = alloc(generic_model_converter, m, "sortmax");
rational offset = m_lower;
m_upper = offset;
expr_ref_vector in(m);
expr_ref tmp(m);
ptr_vector<expr> out;
obj_map<expr, rational>::iterator it = soft.begin(), end = soft.end();
for (; it != end; ++it) {
if (!it->m_value.is_unsigned()) {
for (auto const & [e, w, t] : m_soft) {
if (!w.is_unsigned()) {
throw default_exception("sortmax can only handle unsigned weights. Use a different heuristic.");
}
unsigned n = it->m_value.get_unsigned();
unsigned n = w.get_unsigned();
while (n > 0) {
in.push_back(it->m_key);
in.push_back(e);
--n;
}
}
@ -71,19 +64,15 @@ namespace opt {
// initialize sorting network outputs using the initial assignment.
unsigned first = 0;
it = soft.begin();
for (; it != end; ++it) {
if (m_model->is_true(it->m_key)) {
unsigned n = it->m_value.get_unsigned();
for (auto const & [e, w, t] : m_soft) {
if (t == l_true) {
unsigned n = w.get_unsigned();
while (n > 0) {
s().assert_expr(out[first]);
++first;
--n;
}
}
else {
m_upper += it->m_value;
}
}
while (l_true == is_sat && first < out.size() && m_lower < m_upper) {
trace_bounds("sortmax");
@ -149,8 +138,8 @@ namespace opt {
};
maxsmt_solver_base* mk_sortmax(maxsat_context& c, weights_t& ws, expr_ref_vector const& soft) {
return alloc(sortmax, c, ws, soft);
maxsmt_solver_base* mk_sortmax(maxsat_context& c, vector<soft>& s, unsigned index) {
return alloc(sortmax, c, s, index);
}
}

View file

@ -44,8 +44,8 @@ namespace opt {
}
public:
wmax(maxsat_context& c, weights_t& ws, expr_ref_vector const& soft):
maxsmt_solver_base(c, ws, soft),
wmax(maxsat_context& c, vector<soft>& s, unsigned index):
maxsmt_solver_base(c, s, index),
m_trail(m),
m_defs(m) {}
@ -54,22 +54,18 @@ namespace opt {
lbool operator()() override {
TRACE("opt", tout << "weighted maxsat\n";);
scoped_ensure_theory wth(*this);
obj_map<expr, rational> soft;
reset();
lbool is_sat = find_mutexes(soft);
if (is_sat != l_true) {
return is_sat;
}
m_upper = m_lower;
if (init())
return l_undef;
lbool is_sat = l_true;
expr_ref_vector asms(m);
vector<expr_ref_vector> cores;
for (auto const& kv : soft) {
assert_weighted(wth(), kv.m_key, kv.m_value);
if (!is_true(kv.m_key)) {
m_upper += kv.m_value;
}
}
for (auto const& [k, w, t] : m_soft)
assert_weighted(wth(), k, w);
wth().init_min_cost(m_upper - m_lower);
trace_bounds("wmax");
@ -308,8 +304,8 @@ namespace opt {
};
maxsmt_solver_base* mk_wmax(maxsat_context& c, weights_t& ws, expr_ref_vector const& soft) {
return alloc(wmax, c, ws, soft);
maxsmt_solver_base* mk_wmax(maxsat_context& c, vector<soft> & s, unsigned index) {
return alloc(wmax, c, s, index);
}
}

Some files were not shown because too many files have changed in this diff Show more