mirror of
https://github.com/Z3Prover/z3
synced 2026-07-18 04:55:45 +00:00
Start resolving merge conflicts with master branch
This commit is contained in:
commit
dcf81a2592
1020 changed files with 80693 additions and 20317 deletions
|
|
@ -38,8 +38,7 @@ public:
|
|||
TRACE(goal, g->display(tout << "in\n"););
|
||||
|
||||
ptr_vector<expr> flas;
|
||||
const unsigned sz = g->size();
|
||||
for (unsigned i = 0; i < sz; ++i) flas.push_back(g->form(i));
|
||||
for (auto [f, dep, pr] : *g) flas.push_back(f);
|
||||
lackr lackr(m, m_p, m_st, flas, nullptr);
|
||||
|
||||
// mk result
|
||||
|
|
|
|||
|
|
@ -62,10 +62,9 @@ class ackr_bound_probe : public probe {
|
|||
public:
|
||||
result operator()(goal const & g) override {
|
||||
proc p(g.m());
|
||||
unsigned sz = g.size();
|
||||
expr_fast_mark1 visited;
|
||||
for (unsigned i = 0; i < sz; ++i) {
|
||||
for_each_expr_core<proc, expr_fast_mark1, true, true>(p, visited, g.form(i));
|
||||
for (auto [curr, dep, pr] : g) {
|
||||
for_each_expr_core<proc, expr_fast_mark1, true, true>(p, visited, curr);
|
||||
}
|
||||
p.prune_non_select();
|
||||
double total = ackr_helper::calculate_lemma_bound(p.m_fun2terms, p.m_sel2terms);
|
||||
|
|
|
|||
|
|
@ -18,13 +18,13 @@
|
|||
|
||||
double ackr_helper::calculate_lemma_bound(fun2terms_map const& occs1, sel2terms_map const& occs2) {
|
||||
double total = 0;
|
||||
for (auto const& kv : occs1) {
|
||||
total += n_choose_2_chk(kv.m_value->var_args.size());
|
||||
total += kv.m_value->const_args.size() * kv.m_value->var_args.size();
|
||||
for (auto const &[k, v] : occs1) {
|
||||
total += n_choose_2_chk(v->var_args.size());
|
||||
total += v->const_args.size() * v->var_args.size();
|
||||
}
|
||||
for (auto const& kv : occs2) {
|
||||
total += n_choose_2_chk(kv.m_value->var_args.size());
|
||||
total += kv.m_value->const_args.size() * kv.m_value->var_args.size();
|
||||
for (auto const &[k, v] : occs2) {
|
||||
total += n_choose_2_chk(v->var_args.size());
|
||||
total += v->const_args.size() * v->var_args.size();
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -52,14 +52,26 @@ public:
|
|||
return m_autil.is_select(a) && is_uninterp_const(a->get_arg(0));
|
||||
}
|
||||
|
||||
void mark_non_select_rec(expr* t, expr_mark& visited, expr_mark& non_select) {
|
||||
if (visited.is_marked(t))
|
||||
return;
|
||||
visited.mark(t, true);
|
||||
non_select.mark(t, true);
|
||||
if (is_app(t)) {
|
||||
for (expr *arg : *to_app(t))
|
||||
mark_non_select_rec(arg, visited,non_select);
|
||||
}
|
||||
}
|
||||
|
||||
void mark_non_select(app* a, expr_mark& non_select) {
|
||||
if (m_autil.is_select(a)) {
|
||||
bool first = true;
|
||||
expr_mark visited;
|
||||
for (expr* arg : *a) {
|
||||
if (first)
|
||||
first = false;
|
||||
else
|
||||
non_select.mark(arg, true);
|
||||
mark_non_select_rec(arg, visited, non_select);
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
|
@ -70,10 +82,10 @@ public:
|
|||
|
||||
void prune_non_select(obj_map<app, app_set*> & sels, expr_mark& non_select) {
|
||||
ptr_vector<app> nons;
|
||||
for (auto& kv : sels) {
|
||||
if (non_select.is_marked(kv.m_key)) {
|
||||
nons.push_back(kv.m_key);
|
||||
dealloc(kv.m_value);
|
||||
for (auto &[k, v] : sels) {
|
||||
if (non_select.is_marked(k)) {
|
||||
nons.push_back(k);
|
||||
dealloc(v);
|
||||
}
|
||||
}
|
||||
for (app* s : nons) {
|
||||
|
|
|
|||
|
|
@ -103,7 +103,7 @@ void ackr_model_converter::convert_constants(model * source, model * destination
|
|||
evaluator.set_model_completion(true);
|
||||
array_util autil(m);
|
||||
|
||||
for (unsigned i = 0; i < source->get_num_constants(); ++i) {
|
||||
for (unsigned i = 0, n = source->get_num_constants(); i < n; ++i) {
|
||||
func_decl * const c = source->get_constant(i);
|
||||
app * const term = info->find_term(c);
|
||||
expr * value = source->get_const_interp(c);
|
||||
|
|
|
|||
|
|
@ -149,9 +149,9 @@ void lackr::eager_enc() {
|
|||
checkpoint();
|
||||
ackr(v);
|
||||
}
|
||||
for (auto const& kv : m_sel2terms) {
|
||||
for (auto const &[k, v] : m_sel2terms) {
|
||||
checkpoint();
|
||||
ackr(kv.get_value());
|
||||
ackr(v);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -190,13 +190,13 @@ void lackr::abstract_fun(fun2terms_map const& apps) {
|
|||
}
|
||||
|
||||
void lackr::abstract_sel(sel2terms_map const& apps) {
|
||||
for (auto const& kv : apps) {
|
||||
func_decl * fd = kv.m_key->get_decl();
|
||||
for (app * t : kv.m_value->const_args) {
|
||||
for (auto const &[k, v] : apps) {
|
||||
func_decl * fd = k->get_decl();
|
||||
for (app * t : v->const_args) {
|
||||
app * fc = m.mk_fresh_const(fd->get_name(), t->get_sort());
|
||||
m_info->set_abstr(t, fc);
|
||||
}
|
||||
for (app * t : kv.m_value->var_args) {
|
||||
for (app * t : v->var_args) {
|
||||
app * fc = m.mk_fresh_const(fd->get_name(), t->get_sort());
|
||||
m_info->set_abstr(t, fc);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -44,6 +44,7 @@ z3_add_component(api
|
|||
api_context.cpp
|
||||
api_datalog.cpp
|
||||
api_datatype.cpp
|
||||
api_finite_set.cpp
|
||||
api_fpa.cpp
|
||||
api_goal.cpp
|
||||
api_log.cpp
|
||||
|
|
@ -65,7 +66,7 @@ z3_add_component(api
|
|||
z3_replayer.cpp
|
||||
${full_path_generated_files}
|
||||
COMPONENT_DEPENDENCIES
|
||||
opt
|
||||
z3_opt
|
||||
euf
|
||||
portfolio
|
||||
realclosure
|
||||
|
|
|
|||
|
|
@ -447,4 +447,4 @@ extern "C" {
|
|||
return _am.get_i(av);
|
||||
Z3_CATCH_RETURN(0);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -235,4 +235,4 @@ extern "C" {
|
|||
Z3_CATCH_RETURN(nullptr);
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,6 +38,10 @@ extern "C" {
|
|||
Z3_TRY;
|
||||
LOG_Z3_mk_array_sort_n(c, n, domain, range);
|
||||
RESET_ERROR_CODE();
|
||||
if (n == 0) {
|
||||
SET_ERROR_CODE(Z3_INVALID_ARG, "array sort requires at least one domain sort");
|
||||
RETURN_Z3(nullptr);
|
||||
}
|
||||
vector<parameter> params;
|
||||
for (unsigned i = 0; i < n; ++i) params.push_back(parameter(to_sort(domain[i])));
|
||||
params.push_back(parameter(to_sort(range)));
|
||||
|
|
@ -354,4 +358,4 @@ extern "C" {
|
|||
Z3_CATCH_RETURN(nullptr);
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -129,7 +129,6 @@ extern "C" {
|
|||
Z3_TRY;
|
||||
LOG_Z3_mk_rec_func_decl(c, s, domain_size, domain, range);
|
||||
RESET_ERROR_CODE();
|
||||
//
|
||||
recfun::promise_def def =
|
||||
mk_c(c)->recfun().get_plugin().mk_def(
|
||||
to_symbol(s), domain_size, to_sorts(domain), to_sort(range), false);
|
||||
|
|
@ -898,6 +897,10 @@ extern "C" {
|
|||
RESET_ERROR_CODE();
|
||||
ast_manager & m = mk_c(c)->m();
|
||||
expr * a = to_expr(_a);
|
||||
if (num_exprs > 0 && (!_from || !_to)) {
|
||||
SET_ERROR_CODE(Z3_INVALID_ARG, "null from/to arrays with non-zero num_exprs");
|
||||
RETURN_Z3(of_expr(nullptr));
|
||||
}
|
||||
expr * const * from = to_exprs(num_exprs, _from);
|
||||
expr * const * to = to_exprs(num_exprs, _to);
|
||||
expr * r = nullptr;
|
||||
|
|
@ -1084,388 +1087,425 @@ extern "C" {
|
|||
Z3_CATCH_RETURN("");
|
||||
}
|
||||
|
||||
// Helper functions to reduce instruction cache pressure in Z3_get_decl_kind.
|
||||
// Each theory gets its own function to avoid loading the entire switch table.
|
||||
|
||||
static Z3_decl_kind get_decl_kind_basic(decl_kind k) {
|
||||
switch(k) {
|
||||
case OP_TRUE: return Z3_OP_TRUE;
|
||||
case OP_FALSE: return Z3_OP_FALSE;
|
||||
case OP_EQ: return Z3_OP_EQ;
|
||||
case OP_DISTINCT: return Z3_OP_DISTINCT;
|
||||
case OP_ITE: return Z3_OP_ITE;
|
||||
case OP_AND: return Z3_OP_AND;
|
||||
case OP_OR: return Z3_OP_OR;
|
||||
case OP_XOR: return Z3_OP_XOR;
|
||||
case OP_NOT: return Z3_OP_NOT;
|
||||
case OP_IMPLIES: return Z3_OP_IMPLIES;
|
||||
case OP_OEQ: return Z3_OP_OEQ;
|
||||
case PR_UNDEF: return Z3_OP_PR_UNDEF;
|
||||
case PR_TRUE: return Z3_OP_PR_TRUE;
|
||||
case PR_ASSERTED: return Z3_OP_PR_ASSERTED;
|
||||
case PR_GOAL: return Z3_OP_PR_GOAL;
|
||||
case PR_MODUS_PONENS: return Z3_OP_PR_MODUS_PONENS;
|
||||
case PR_REFLEXIVITY: return Z3_OP_PR_REFLEXIVITY;
|
||||
case PR_SYMMETRY: return Z3_OP_PR_SYMMETRY;
|
||||
case PR_TRANSITIVITY: return Z3_OP_PR_TRANSITIVITY;
|
||||
case PR_TRANSITIVITY_STAR: return Z3_OP_PR_TRANSITIVITY_STAR;
|
||||
case PR_MONOTONICITY: return Z3_OP_PR_MONOTONICITY;
|
||||
case PR_QUANT_INTRO: return Z3_OP_PR_QUANT_INTRO;
|
||||
case PR_BIND: return Z3_OP_PR_BIND;
|
||||
case PR_DISTRIBUTIVITY: return Z3_OP_PR_DISTRIBUTIVITY;
|
||||
case PR_AND_ELIM: return Z3_OP_PR_AND_ELIM;
|
||||
case PR_NOT_OR_ELIM: return Z3_OP_PR_NOT_OR_ELIM;
|
||||
case PR_REWRITE: return Z3_OP_PR_REWRITE;
|
||||
case PR_REWRITE_STAR: return Z3_OP_PR_REWRITE_STAR;
|
||||
case PR_PULL_QUANT: return Z3_OP_PR_PULL_QUANT;
|
||||
case PR_PUSH_QUANT: return Z3_OP_PR_PUSH_QUANT;
|
||||
case PR_ELIM_UNUSED_VARS: return Z3_OP_PR_ELIM_UNUSED_VARS;
|
||||
case PR_DER: return Z3_OP_PR_DER;
|
||||
case PR_QUANT_INST: return Z3_OP_PR_QUANT_INST;
|
||||
case PR_HYPOTHESIS: return Z3_OP_PR_HYPOTHESIS;
|
||||
case PR_LEMMA: return Z3_OP_PR_LEMMA;
|
||||
case PR_UNIT_RESOLUTION: return Z3_OP_PR_UNIT_RESOLUTION;
|
||||
case PR_IFF_TRUE: return Z3_OP_PR_IFF_TRUE;
|
||||
case PR_IFF_FALSE: return Z3_OP_PR_IFF_FALSE;
|
||||
case PR_COMMUTATIVITY: return Z3_OP_PR_COMMUTATIVITY;
|
||||
case PR_DEF_AXIOM: return Z3_OP_PR_DEF_AXIOM;
|
||||
case PR_ASSUMPTION_ADD: return Z3_OP_PR_ASSUMPTION_ADD;
|
||||
case PR_LEMMA_ADD: return Z3_OP_PR_LEMMA_ADD;
|
||||
case PR_REDUNDANT_DEL: return Z3_OP_PR_REDUNDANT_DEL;
|
||||
case PR_CLAUSE_TRAIL: return Z3_OP_PR_CLAUSE_TRAIL;
|
||||
case PR_DEF_INTRO: return Z3_OP_PR_DEF_INTRO;
|
||||
case PR_APPLY_DEF: return Z3_OP_PR_APPLY_DEF;
|
||||
case PR_IFF_OEQ: return Z3_OP_PR_IFF_OEQ;
|
||||
case PR_NNF_POS: return Z3_OP_PR_NNF_POS;
|
||||
case PR_NNF_NEG: return Z3_OP_PR_NNF_NEG;
|
||||
case PR_SKOLEMIZE: return Z3_OP_PR_SKOLEMIZE;
|
||||
case PR_MODUS_PONENS_OEQ: return Z3_OP_PR_MODUS_PONENS_OEQ;
|
||||
case PR_TH_LEMMA: return Z3_OP_PR_TH_LEMMA;
|
||||
case PR_HYPER_RESOLVE: return Z3_OP_PR_HYPER_RESOLVE;
|
||||
default: return Z3_OP_INTERNAL;
|
||||
}
|
||||
}
|
||||
|
||||
static Z3_decl_kind get_decl_kind_arith(decl_kind k) {
|
||||
switch(k) {
|
||||
case OP_NUM: return Z3_OP_ANUM;
|
||||
case OP_IRRATIONAL_ALGEBRAIC_NUM: return Z3_OP_AGNUM;
|
||||
case OP_LE: return Z3_OP_LE;
|
||||
case OP_GE: return Z3_OP_GE;
|
||||
case OP_LT: return Z3_OP_LT;
|
||||
case OP_GT: return Z3_OP_GT;
|
||||
case OP_ADD: return Z3_OP_ADD;
|
||||
case OP_SUB: return Z3_OP_SUB;
|
||||
case OP_UMINUS: return Z3_OP_UMINUS;
|
||||
case OP_MUL: return Z3_OP_MUL;
|
||||
case OP_DIV: return Z3_OP_DIV;
|
||||
case OP_IDIV: return Z3_OP_IDIV;
|
||||
case OP_REM: return Z3_OP_REM;
|
||||
case OP_MOD: return Z3_OP_MOD;
|
||||
case OP_POWER: return Z3_OP_POWER;
|
||||
case OP_ABS: return Z3_OP_ABS;
|
||||
case OP_TO_REAL: return Z3_OP_TO_REAL;
|
||||
case OP_TO_INT: return Z3_OP_TO_INT;
|
||||
case OP_IS_INT: return Z3_OP_IS_INT;
|
||||
default: return Z3_OP_INTERNAL;
|
||||
}
|
||||
}
|
||||
|
||||
static Z3_decl_kind get_decl_kind_array(decl_kind k) {
|
||||
switch(k) {
|
||||
case OP_STORE: return Z3_OP_STORE;
|
||||
case OP_SELECT: return Z3_OP_SELECT;
|
||||
case OP_CONST_ARRAY: return Z3_OP_CONST_ARRAY;
|
||||
case OP_ARRAY_DEFAULT: return Z3_OP_ARRAY_DEFAULT;
|
||||
case OP_ARRAY_MAP: return Z3_OP_ARRAY_MAP;
|
||||
case OP_SET_UNION: return Z3_OP_SET_UNION;
|
||||
case OP_SET_INTERSECT: return Z3_OP_SET_INTERSECT;
|
||||
case OP_SET_DIFFERENCE: return Z3_OP_SET_DIFFERENCE;
|
||||
case OP_SET_COMPLEMENT: return Z3_OP_SET_COMPLEMENT;
|
||||
case OP_SET_SUBSET: return Z3_OP_SET_SUBSET;
|
||||
case OP_AS_ARRAY: return Z3_OP_AS_ARRAY;
|
||||
case OP_ARRAY_EXT: return Z3_OP_ARRAY_EXT;
|
||||
default: return Z3_OP_INTERNAL;
|
||||
}
|
||||
}
|
||||
|
||||
static Z3_decl_kind get_decl_kind_special_relations(decl_kind k) {
|
||||
switch(k) {
|
||||
case OP_SPECIAL_RELATION_LO : return Z3_OP_SPECIAL_RELATION_LO;
|
||||
case OP_SPECIAL_RELATION_PO : return Z3_OP_SPECIAL_RELATION_PO;
|
||||
case OP_SPECIAL_RELATION_PLO: return Z3_OP_SPECIAL_RELATION_PLO;
|
||||
case OP_SPECIAL_RELATION_TO : return Z3_OP_SPECIAL_RELATION_TO;
|
||||
case OP_SPECIAL_RELATION_TC : return Z3_OP_SPECIAL_RELATION_TC;
|
||||
default: UNREACHABLE(); return Z3_OP_INTERNAL;
|
||||
}
|
||||
}
|
||||
|
||||
static Z3_decl_kind get_decl_kind_bv(decl_kind k) {
|
||||
switch(k) {
|
||||
case OP_BV_NUM: return Z3_OP_BNUM;
|
||||
case OP_BIT1: return Z3_OP_BIT1;
|
||||
case OP_BIT0: return Z3_OP_BIT0;
|
||||
case OP_BNEG: return Z3_OP_BNEG;
|
||||
case OP_BADD: return Z3_OP_BADD;
|
||||
case OP_BSUB: return Z3_OP_BSUB;
|
||||
case OP_BMUL: return Z3_OP_BMUL;
|
||||
case OP_BSDIV: return Z3_OP_BSDIV;
|
||||
case OP_BUDIV: return Z3_OP_BUDIV;
|
||||
case OP_BSREM: return Z3_OP_BSREM;
|
||||
case OP_BUREM: return Z3_OP_BUREM;
|
||||
case OP_BSMOD: return Z3_OP_BSMOD;
|
||||
case OP_BSDIV0: return Z3_OP_BSDIV0;
|
||||
case OP_BUDIV0: return Z3_OP_BUDIV0;
|
||||
case OP_BSREM0: return Z3_OP_BSREM0;
|
||||
case OP_BUREM0: return Z3_OP_BUREM0;
|
||||
case OP_BSMOD0: return Z3_OP_BSMOD0;
|
||||
case OP_ULEQ: return Z3_OP_ULEQ;
|
||||
case OP_SLEQ: return Z3_OP_SLEQ;
|
||||
case OP_UGEQ: return Z3_OP_UGEQ;
|
||||
case OP_SGEQ: return Z3_OP_SGEQ;
|
||||
case OP_ULT: return Z3_OP_ULT;
|
||||
case OP_SLT: return Z3_OP_SLT;
|
||||
case OP_UGT: return Z3_OP_UGT;
|
||||
case OP_SGT: return Z3_OP_SGT;
|
||||
case OP_BAND: return Z3_OP_BAND;
|
||||
case OP_BOR: return Z3_OP_BOR;
|
||||
case OP_BNOT: return Z3_OP_BNOT;
|
||||
case OP_BXOR: return Z3_OP_BXOR;
|
||||
case OP_BNAND: return Z3_OP_BNAND;
|
||||
case OP_BNOR: return Z3_OP_BNOR;
|
||||
case OP_BXNOR: return Z3_OP_BXNOR;
|
||||
case OP_CONCAT: return Z3_OP_CONCAT;
|
||||
case OP_SIGN_EXT: return Z3_OP_SIGN_EXT;
|
||||
case OP_ZERO_EXT: return Z3_OP_ZERO_EXT;
|
||||
case OP_EXTRACT: return Z3_OP_EXTRACT;
|
||||
case OP_REPEAT: return Z3_OP_REPEAT;
|
||||
case OP_BREDOR: return Z3_OP_BREDOR;
|
||||
case OP_BREDAND: return Z3_OP_BREDAND;
|
||||
case OP_BCOMP: return Z3_OP_BCOMP;
|
||||
case OP_BSHL: return Z3_OP_BSHL;
|
||||
case OP_BLSHR: return Z3_OP_BLSHR;
|
||||
case OP_BASHR: return Z3_OP_BASHR;
|
||||
case OP_ROTATE_LEFT: return Z3_OP_ROTATE_LEFT;
|
||||
case OP_ROTATE_RIGHT: return Z3_OP_ROTATE_RIGHT;
|
||||
case OP_EXT_ROTATE_LEFT: return Z3_OP_EXT_ROTATE_LEFT;
|
||||
case OP_EXT_ROTATE_RIGHT: return Z3_OP_EXT_ROTATE_RIGHT;
|
||||
case OP_INT2BV: return Z3_OP_INT2BV;
|
||||
case OP_UBV2INT: return Z3_OP_BV2INT;
|
||||
case OP_SBV2INT: return Z3_OP_SBV2INT;
|
||||
case OP_CARRY: return Z3_OP_CARRY;
|
||||
case OP_XOR3: return Z3_OP_XOR3;
|
||||
case OP_BIT2BOOL: return Z3_OP_BIT2BOOL;
|
||||
case OP_BSMUL_NO_OVFL: return Z3_OP_BSMUL_NO_OVFL;
|
||||
case OP_BUMUL_NO_OVFL: return Z3_OP_BUMUL_NO_OVFL;
|
||||
case OP_BSMUL_NO_UDFL: return Z3_OP_BSMUL_NO_UDFL;
|
||||
case OP_BSDIV_I: return Z3_OP_BSDIV_I;
|
||||
case OP_BUDIV_I: return Z3_OP_BUDIV_I;
|
||||
case OP_BSREM_I: return Z3_OP_BSREM_I;
|
||||
case OP_BUREM_I: return Z3_OP_BUREM_I;
|
||||
case OP_BSMOD_I: return Z3_OP_BSMOD_I;
|
||||
default: return Z3_OP_INTERNAL;
|
||||
}
|
||||
}
|
||||
|
||||
static Z3_decl_kind get_decl_kind_dt(decl_kind k) {
|
||||
switch(k) {
|
||||
case OP_DT_CONSTRUCTOR: return Z3_OP_DT_CONSTRUCTOR;
|
||||
case OP_DT_RECOGNISER: return Z3_OP_DT_RECOGNISER;
|
||||
case OP_DT_IS: return Z3_OP_DT_IS;
|
||||
case OP_DT_ACCESSOR: return Z3_OP_DT_ACCESSOR;
|
||||
case OP_DT_UPDATE_FIELD: return Z3_OP_DT_UPDATE_FIELD;
|
||||
default: return Z3_OP_INTERNAL;
|
||||
}
|
||||
}
|
||||
|
||||
static Z3_decl_kind get_decl_kind_datalog(decl_kind k) {
|
||||
switch(k) {
|
||||
case datalog::OP_RA_STORE: return Z3_OP_RA_STORE;
|
||||
case datalog::OP_RA_EMPTY: return Z3_OP_RA_EMPTY;
|
||||
case datalog::OP_RA_IS_EMPTY: return Z3_OP_RA_IS_EMPTY;
|
||||
case datalog::OP_RA_JOIN: return Z3_OP_RA_JOIN;
|
||||
case datalog::OP_RA_UNION: return Z3_OP_RA_UNION;
|
||||
case datalog::OP_RA_WIDEN: return Z3_OP_RA_WIDEN;
|
||||
case datalog::OP_RA_PROJECT: return Z3_OP_RA_PROJECT;
|
||||
case datalog::OP_RA_FILTER: return Z3_OP_RA_FILTER;
|
||||
case datalog::OP_RA_NEGATION_FILTER: return Z3_OP_RA_NEGATION_FILTER;
|
||||
case datalog::OP_RA_RENAME: return Z3_OP_RA_RENAME;
|
||||
case datalog::OP_RA_COMPLEMENT: return Z3_OP_RA_COMPLEMENT;
|
||||
case datalog::OP_RA_SELECT: return Z3_OP_RA_SELECT;
|
||||
case datalog::OP_RA_CLONE: return Z3_OP_RA_CLONE;
|
||||
case datalog::OP_DL_CONSTANT: return Z3_OP_FD_CONSTANT;
|
||||
case datalog::OP_DL_LT: return Z3_OP_FD_LT;
|
||||
default: return Z3_OP_INTERNAL;
|
||||
}
|
||||
}
|
||||
|
||||
static Z3_decl_kind get_decl_kind_seq(decl_kind k) {
|
||||
switch (k) {
|
||||
case OP_SEQ_UNIT: return Z3_OP_SEQ_UNIT;
|
||||
case OP_SEQ_EMPTY: return Z3_OP_SEQ_EMPTY;
|
||||
case OP_SEQ_CONCAT: return Z3_OP_SEQ_CONCAT;
|
||||
case OP_SEQ_PREFIX: return Z3_OP_SEQ_PREFIX;
|
||||
case OP_SEQ_SUFFIX: return Z3_OP_SEQ_SUFFIX;
|
||||
case OP_SEQ_CONTAINS: return Z3_OP_SEQ_CONTAINS;
|
||||
case OP_SEQ_EXTRACT: return Z3_OP_SEQ_EXTRACT;
|
||||
case OP_SEQ_REPLACE: return Z3_OP_SEQ_REPLACE;
|
||||
case OP_SEQ_REPLACE_RE: return Z3_OP_SEQ_REPLACE_RE;
|
||||
case OP_SEQ_REPLACE_RE_ALL: return Z3_OP_SEQ_REPLACE_RE_ALL;
|
||||
case OP_SEQ_REPLACE_ALL: return Z3_OP_SEQ_REPLACE_ALL;
|
||||
case OP_SEQ_AT: return Z3_OP_SEQ_AT;
|
||||
case OP_SEQ_NTH: return Z3_OP_SEQ_NTH;
|
||||
case OP_SEQ_LENGTH: return Z3_OP_SEQ_LENGTH;
|
||||
case OP_SEQ_INDEX: return Z3_OP_SEQ_INDEX;
|
||||
case OP_SEQ_TO_RE: return Z3_OP_SEQ_TO_RE;
|
||||
case OP_SEQ_IN_RE: return Z3_OP_SEQ_IN_RE;
|
||||
case OP_SEQ_MAP: return Z3_OP_SEQ_MAP;
|
||||
case OP_SEQ_MAPI: return Z3_OP_SEQ_MAPI;
|
||||
case OP_SEQ_FOLDL: return Z3_OP_SEQ_FOLDL;
|
||||
case OP_SEQ_FOLDLI: return Z3_OP_SEQ_FOLDLI;
|
||||
case _OP_STRING_STRREPL: return Z3_OP_SEQ_REPLACE;
|
||||
case _OP_STRING_CONCAT: return Z3_OP_SEQ_CONCAT;
|
||||
case _OP_STRING_LENGTH: return Z3_OP_SEQ_LENGTH;
|
||||
case _OP_STRING_STRCTN: return Z3_OP_SEQ_CONTAINS;
|
||||
case _OP_STRING_PREFIX: return Z3_OP_SEQ_PREFIX;
|
||||
case _OP_STRING_SUFFIX: return Z3_OP_SEQ_SUFFIX;
|
||||
case _OP_STRING_IN_REGEXP: return Z3_OP_SEQ_IN_RE;
|
||||
case _OP_STRING_TO_REGEXP: return Z3_OP_SEQ_TO_RE;
|
||||
case _OP_STRING_CHARAT: return Z3_OP_SEQ_AT;
|
||||
case _OP_STRING_SUBSTR: return Z3_OP_SEQ_EXTRACT;
|
||||
case _OP_STRING_STRIDOF: return Z3_OP_SEQ_INDEX;
|
||||
case _OP_REGEXP_EMPTY: return Z3_OP_RE_EMPTY_SET;
|
||||
case _OP_REGEXP_FULL_CHAR: return Z3_OP_RE_FULL_SET;
|
||||
case OP_STRING_STOI: return Z3_OP_STR_TO_INT;
|
||||
case OP_STRING_ITOS: return Z3_OP_INT_TO_STR;
|
||||
case OP_STRING_TO_CODE: return Z3_OP_STR_TO_CODE;
|
||||
case OP_STRING_FROM_CODE: return Z3_OP_STR_FROM_CODE;
|
||||
case OP_STRING_UBVTOS: return Z3_OP_UBV_TO_STR;
|
||||
case OP_STRING_SBVTOS: return Z3_OP_SBV_TO_STR;
|
||||
case OP_STRING_LT: return Z3_OP_STRING_LT;
|
||||
case OP_STRING_LE: return Z3_OP_STRING_LE;
|
||||
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_INTERSECT: return Z3_OP_RE_INTERSECT;
|
||||
case OP_RE_LOOP: return Z3_OP_RE_LOOP;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
static Z3_decl_kind get_decl_kind_char(decl_kind k) {
|
||||
switch (k) {
|
||||
case OP_CHAR_CONST: return Z3_OP_CHAR_CONST;
|
||||
case OP_CHAR_LE: return Z3_OP_CHAR_LE;
|
||||
case OP_CHAR_TO_INT: return Z3_OP_CHAR_TO_INT;
|
||||
case OP_CHAR_TO_BV: return Z3_OP_CHAR_TO_BV;
|
||||
case OP_CHAR_FROM_BV: return Z3_OP_CHAR_FROM_BV;
|
||||
case OP_CHAR_IS_DIGIT: return Z3_OP_CHAR_IS_DIGIT;
|
||||
default: return Z3_OP_INTERNAL;
|
||||
}
|
||||
}
|
||||
|
||||
static Z3_decl_kind get_decl_kind_fpa(decl_kind k) {
|
||||
switch (k) {
|
||||
case OP_FPA_RM_NEAREST_TIES_TO_EVEN: return Z3_OP_FPA_RM_NEAREST_TIES_TO_EVEN;
|
||||
case OP_FPA_RM_NEAREST_TIES_TO_AWAY: return Z3_OP_FPA_RM_NEAREST_TIES_TO_AWAY;
|
||||
case OP_FPA_RM_TOWARD_POSITIVE: return Z3_OP_FPA_RM_TOWARD_POSITIVE;
|
||||
case OP_FPA_RM_TOWARD_NEGATIVE: return Z3_OP_FPA_RM_TOWARD_NEGATIVE;
|
||||
case OP_FPA_RM_TOWARD_ZERO: return Z3_OP_FPA_RM_TOWARD_ZERO;
|
||||
case OP_FPA_NUM: return Z3_OP_FPA_NUM;
|
||||
case OP_FPA_PLUS_INF: return Z3_OP_FPA_PLUS_INF;
|
||||
case OP_FPA_MINUS_INF: return Z3_OP_FPA_MINUS_INF;
|
||||
case OP_FPA_NAN: return Z3_OP_FPA_NAN;
|
||||
case OP_FPA_MINUS_ZERO: return Z3_OP_FPA_MINUS_ZERO;
|
||||
case OP_FPA_PLUS_ZERO: return Z3_OP_FPA_PLUS_ZERO;
|
||||
case OP_FPA_ADD: return Z3_OP_FPA_ADD;
|
||||
case OP_FPA_SUB: return Z3_OP_FPA_SUB;
|
||||
case OP_FPA_NEG: return Z3_OP_FPA_NEG;
|
||||
case OP_FPA_MUL: return Z3_OP_FPA_MUL;
|
||||
case OP_FPA_DIV: return Z3_OP_FPA_DIV;
|
||||
case OP_FPA_REM: return Z3_OP_FPA_REM;
|
||||
case OP_FPA_ABS: return Z3_OP_FPA_ABS;
|
||||
case OP_FPA_MIN: return Z3_OP_FPA_MIN;
|
||||
case OP_FPA_MAX: return Z3_OP_FPA_MAX;
|
||||
case OP_FPA_FMA: return Z3_OP_FPA_FMA;
|
||||
case OP_FPA_SQRT: return Z3_OP_FPA_SQRT;
|
||||
case OP_FPA_EQ: return Z3_OP_FPA_EQ;
|
||||
case OP_FPA_ROUND_TO_INTEGRAL: return Z3_OP_FPA_ROUND_TO_INTEGRAL;
|
||||
case OP_FPA_LT: return Z3_OP_FPA_LT;
|
||||
case OP_FPA_GT: return Z3_OP_FPA_GT;
|
||||
case OP_FPA_LE: return Z3_OP_FPA_LE;
|
||||
case OP_FPA_GE: return Z3_OP_FPA_GE;
|
||||
case OP_FPA_IS_NAN: return Z3_OP_FPA_IS_NAN;
|
||||
case OP_FPA_IS_INF: return Z3_OP_FPA_IS_INF;
|
||||
case OP_FPA_IS_ZERO: return Z3_OP_FPA_IS_ZERO;
|
||||
case OP_FPA_IS_NORMAL: return Z3_OP_FPA_IS_NORMAL;
|
||||
case OP_FPA_IS_SUBNORMAL: return Z3_OP_FPA_IS_SUBNORMAL;
|
||||
case OP_FPA_IS_NEGATIVE: return Z3_OP_FPA_IS_NEGATIVE;
|
||||
case OP_FPA_IS_POSITIVE: return Z3_OP_FPA_IS_POSITIVE;
|
||||
case OP_FPA_FP: return Z3_OP_FPA_FP;
|
||||
case OP_FPA_TO_FP: return Z3_OP_FPA_TO_FP;
|
||||
case OP_FPA_TO_FP_UNSIGNED: return Z3_OP_FPA_TO_FP_UNSIGNED;
|
||||
case OP_FPA_TO_UBV: return Z3_OP_FPA_TO_UBV;
|
||||
case OP_FPA_TO_SBV: return Z3_OP_FPA_TO_SBV;
|
||||
case OP_FPA_TO_REAL: return Z3_OP_FPA_TO_REAL;
|
||||
case OP_FPA_TO_IEEE_BV: return Z3_OP_FPA_TO_IEEE_BV;
|
||||
case OP_FPA_BVWRAP: return Z3_OP_FPA_BVWRAP;
|
||||
case OP_FPA_BV2RM: return Z3_OP_FPA_BV2RM;
|
||||
default: return Z3_OP_INTERNAL;
|
||||
}
|
||||
}
|
||||
|
||||
static Z3_decl_kind get_decl_kind_label(decl_kind k) {
|
||||
switch(k) {
|
||||
case OP_LABEL: return Z3_OP_LABEL;
|
||||
case OP_LABEL_LIT: return Z3_OP_LABEL_LIT;
|
||||
default: return Z3_OP_INTERNAL;
|
||||
}
|
||||
}
|
||||
|
||||
static Z3_decl_kind get_decl_kind_pb(decl_kind k) {
|
||||
switch(k) {
|
||||
case OP_PB_LE: return Z3_OP_PB_LE;
|
||||
case OP_PB_GE: return Z3_OP_PB_GE;
|
||||
case OP_PB_EQ: return Z3_OP_PB_EQ;
|
||||
case OP_AT_MOST_K: return Z3_OP_PB_AT_MOST;
|
||||
case OP_AT_LEAST_K: return Z3_OP_PB_AT_LEAST;
|
||||
default: return Z3_OP_INTERNAL;
|
||||
}
|
||||
}
|
||||
|
||||
static Z3_decl_kind get_decl_kind_finite_set(decl_kind k) {
|
||||
switch(k) {
|
||||
case OP_FINITE_SET_EMPTY: return Z3_OP_FINITE_SET_EMPTY;
|
||||
case OP_FINITE_SET_SINGLETON: return Z3_OP_FINITE_SET_SINGLETON;
|
||||
case OP_FINITE_SET_UNION: return Z3_OP_FINITE_SET_UNION;
|
||||
case OP_FINITE_SET_INTERSECT: return Z3_OP_FINITE_SET_INTERSECT;
|
||||
case OP_FINITE_SET_DIFFERENCE: return Z3_OP_FINITE_SET_DIFFERENCE;
|
||||
case OP_FINITE_SET_IN: return Z3_OP_FINITE_SET_IN;
|
||||
case OP_FINITE_SET_SIZE: return Z3_OP_FINITE_SET_SIZE;
|
||||
case OP_FINITE_SET_SUBSET: return Z3_OP_FINITE_SET_SUBSET;
|
||||
case OP_FINITE_SET_MAP: return Z3_OP_FINITE_SET_MAP;
|
||||
case OP_FINITE_SET_FILTER: return Z3_OP_FINITE_SET_FILTER;
|
||||
case OP_FINITE_SET_RANGE: return Z3_OP_FINITE_SET_RANGE;
|
||||
case OP_FINITE_SET_EXT: return Z3_OP_FINITE_SET_EXT;
|
||||
case OP_FINITE_SET_MAP_INVERSE: return Z3_OP_FINITE_SET_MAP_INVERSE;
|
||||
default: return Z3_OP_INTERNAL;
|
||||
}
|
||||
}
|
||||
|
||||
Z3_decl_kind Z3_API Z3_get_decl_kind(Z3_context c, Z3_func_decl d) {
|
||||
Z3_TRY;
|
||||
LOG_Z3_get_decl_kind(c, d);
|
||||
RESET_ERROR_CODE();
|
||||
func_decl* _d = to_func_decl(d);
|
||||
|
||||
if (d == nullptr || null_family_id == _d->get_family_id()) {
|
||||
if (d == nullptr || null_family_id == _d->get_family_id())
|
||||
return Z3_OP_UNINTERPRETED;
|
||||
}
|
||||
if (mk_c(c)->get_basic_fid() == _d->get_family_id()) {
|
||||
switch(_d->get_decl_kind()) {
|
||||
case OP_TRUE: return Z3_OP_TRUE;
|
||||
case OP_FALSE: return Z3_OP_FALSE;
|
||||
case OP_EQ: return Z3_OP_EQ;
|
||||
case OP_DISTINCT: return Z3_OP_DISTINCT;
|
||||
case OP_ITE: return Z3_OP_ITE;
|
||||
case OP_AND: return Z3_OP_AND;
|
||||
case OP_OR: return Z3_OP_OR;
|
||||
case OP_XOR: return Z3_OP_XOR;
|
||||
case OP_NOT: return Z3_OP_NOT;
|
||||
case OP_IMPLIES: return Z3_OP_IMPLIES;
|
||||
case OP_OEQ: return Z3_OP_OEQ;
|
||||
|
||||
case PR_UNDEF: return Z3_OP_PR_UNDEF;
|
||||
case PR_TRUE: return Z3_OP_PR_TRUE;
|
||||
case PR_ASSERTED: return Z3_OP_PR_ASSERTED;
|
||||
case PR_GOAL: return Z3_OP_PR_GOAL;
|
||||
case PR_MODUS_PONENS: return Z3_OP_PR_MODUS_PONENS;
|
||||
case PR_REFLEXIVITY: return Z3_OP_PR_REFLEXIVITY;
|
||||
case PR_SYMMETRY: return Z3_OP_PR_SYMMETRY;
|
||||
case PR_TRANSITIVITY: return Z3_OP_PR_TRANSITIVITY;
|
||||
case PR_TRANSITIVITY_STAR: return Z3_OP_PR_TRANSITIVITY_STAR;
|
||||
case PR_MONOTONICITY: return Z3_OP_PR_MONOTONICITY;
|
||||
case PR_QUANT_INTRO: return Z3_OP_PR_QUANT_INTRO;
|
||||
case PR_BIND: return Z3_OP_PR_BIND;
|
||||
case PR_DISTRIBUTIVITY: return Z3_OP_PR_DISTRIBUTIVITY;
|
||||
case PR_AND_ELIM: return Z3_OP_PR_AND_ELIM;
|
||||
case PR_NOT_OR_ELIM: return Z3_OP_PR_NOT_OR_ELIM;
|
||||
case PR_REWRITE: return Z3_OP_PR_REWRITE;
|
||||
case PR_REWRITE_STAR: return Z3_OP_PR_REWRITE_STAR;
|
||||
case PR_PULL_QUANT: return Z3_OP_PR_PULL_QUANT;
|
||||
case PR_PUSH_QUANT: return Z3_OP_PR_PUSH_QUANT;
|
||||
case PR_ELIM_UNUSED_VARS: return Z3_OP_PR_ELIM_UNUSED_VARS;
|
||||
case PR_DER: return Z3_OP_PR_DER;
|
||||
case PR_QUANT_INST: return Z3_OP_PR_QUANT_INST;
|
||||
case PR_HYPOTHESIS: return Z3_OP_PR_HYPOTHESIS;
|
||||
case PR_LEMMA: return Z3_OP_PR_LEMMA;
|
||||
case PR_UNIT_RESOLUTION: return Z3_OP_PR_UNIT_RESOLUTION;
|
||||
case PR_IFF_TRUE: return Z3_OP_PR_IFF_TRUE;
|
||||
case PR_IFF_FALSE: return Z3_OP_PR_IFF_FALSE;
|
||||
case PR_COMMUTATIVITY: return Z3_OP_PR_COMMUTATIVITY;
|
||||
case PR_DEF_AXIOM: return Z3_OP_PR_DEF_AXIOM;
|
||||
case PR_ASSUMPTION_ADD: return Z3_OP_PR_ASSUMPTION_ADD;
|
||||
case PR_LEMMA_ADD: return Z3_OP_PR_LEMMA_ADD;
|
||||
case PR_REDUNDANT_DEL: return Z3_OP_PR_REDUNDANT_DEL;
|
||||
case PR_CLAUSE_TRAIL: return Z3_OP_PR_CLAUSE_TRAIL;
|
||||
case PR_DEF_INTRO: return Z3_OP_PR_DEF_INTRO;
|
||||
case PR_APPLY_DEF: return Z3_OP_PR_APPLY_DEF;
|
||||
case PR_IFF_OEQ: return Z3_OP_PR_IFF_OEQ;
|
||||
case PR_NNF_POS: return Z3_OP_PR_NNF_POS;
|
||||
case PR_NNF_NEG: return Z3_OP_PR_NNF_NEG;
|
||||
case PR_SKOLEMIZE: return Z3_OP_PR_SKOLEMIZE;
|
||||
case PR_MODUS_PONENS_OEQ: return Z3_OP_PR_MODUS_PONENS_OEQ;
|
||||
case PR_TH_LEMMA: return Z3_OP_PR_TH_LEMMA;
|
||||
case PR_HYPER_RESOLVE: return Z3_OP_PR_HYPER_RESOLVE;
|
||||
default:
|
||||
return Z3_OP_INTERNAL;
|
||||
}
|
||||
}
|
||||
if (mk_c(c)->get_arith_fid() == _d->get_family_id()) {
|
||||
switch(_d->get_decl_kind()) {
|
||||
case OP_NUM: return Z3_OP_ANUM;
|
||||
case OP_IRRATIONAL_ALGEBRAIC_NUM: return Z3_OP_AGNUM;
|
||||
case OP_LE: return Z3_OP_LE;
|
||||
case OP_GE: return Z3_OP_GE;
|
||||
case OP_LT: return Z3_OP_LT;
|
||||
case OP_GT: return Z3_OP_GT;
|
||||
case OP_ADD: return Z3_OP_ADD;
|
||||
case OP_SUB: return Z3_OP_SUB;
|
||||
case OP_UMINUS: return Z3_OP_UMINUS;
|
||||
case OP_MUL: return Z3_OP_MUL;
|
||||
case OP_DIV: return Z3_OP_DIV;
|
||||
case OP_IDIV: return Z3_OP_IDIV;
|
||||
case OP_REM: return Z3_OP_REM;
|
||||
case OP_MOD: return Z3_OP_MOD;
|
||||
case OP_POWER: return Z3_OP_POWER;
|
||||
case OP_ABS: return Z3_OP_ABS;
|
||||
case OP_TO_REAL: return Z3_OP_TO_REAL;
|
||||
case OP_TO_INT: return Z3_OP_TO_INT;
|
||||
case OP_IS_INT: return Z3_OP_IS_INT;
|
||||
default:
|
||||
return Z3_OP_INTERNAL;
|
||||
}
|
||||
}
|
||||
if (mk_c(c)->get_array_fid() == _d->get_family_id()) {
|
||||
switch(_d->get_decl_kind()) {
|
||||
case OP_STORE: return Z3_OP_STORE;
|
||||
case OP_SELECT: return Z3_OP_SELECT;
|
||||
case OP_CONST_ARRAY: return Z3_OP_CONST_ARRAY;
|
||||
case OP_ARRAY_DEFAULT: return Z3_OP_ARRAY_DEFAULT;
|
||||
case OP_ARRAY_MAP: return Z3_OP_ARRAY_MAP;
|
||||
case OP_SET_UNION: return Z3_OP_SET_UNION;
|
||||
case OP_SET_INTERSECT: return Z3_OP_SET_INTERSECT;
|
||||
case OP_SET_DIFFERENCE: return Z3_OP_SET_DIFFERENCE;
|
||||
case OP_SET_COMPLEMENT: return Z3_OP_SET_COMPLEMENT;
|
||||
case OP_SET_SUBSET: return Z3_OP_SET_SUBSET;
|
||||
case OP_AS_ARRAY: return Z3_OP_AS_ARRAY;
|
||||
case OP_ARRAY_EXT: return Z3_OP_ARRAY_EXT;
|
||||
default:
|
||||
return Z3_OP_INTERNAL;
|
||||
}
|
||||
}
|
||||
family_id fid = _d->get_family_id();
|
||||
decl_kind k = _d->get_decl_kind();
|
||||
|
||||
if (mk_c(c)->get_special_relations_fid() == _d->get_family_id()) {
|
||||
switch(_d->get_decl_kind()) {
|
||||
case OP_SPECIAL_RELATION_LO : return Z3_OP_SPECIAL_RELATION_LO;
|
||||
case OP_SPECIAL_RELATION_PO : return Z3_OP_SPECIAL_RELATION_PO;
|
||||
case OP_SPECIAL_RELATION_PLO: return Z3_OP_SPECIAL_RELATION_PLO;
|
||||
case OP_SPECIAL_RELATION_TO : return Z3_OP_SPECIAL_RELATION_TO;
|
||||
case OP_SPECIAL_RELATION_TC : return Z3_OP_SPECIAL_RELATION_TC;
|
||||
default: UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (mk_c(c)->get_bv_fid() == _d->get_family_id()) {
|
||||
switch(_d->get_decl_kind()) {
|
||||
case OP_BV_NUM: return Z3_OP_BNUM;
|
||||
case OP_BIT1: return Z3_OP_BIT1;
|
||||
case OP_BIT0: return Z3_OP_BIT0;
|
||||
case OP_BNEG: return Z3_OP_BNEG;
|
||||
case OP_BADD: return Z3_OP_BADD;
|
||||
case OP_BSUB: return Z3_OP_BSUB;
|
||||
case OP_BMUL: return Z3_OP_BMUL;
|
||||
case OP_BSDIV: return Z3_OP_BSDIV;
|
||||
case OP_BUDIV: return Z3_OP_BUDIV;
|
||||
case OP_BSREM: return Z3_OP_BSREM;
|
||||
case OP_BUREM: return Z3_OP_BUREM;
|
||||
case OP_BSMOD: return Z3_OP_BSMOD;
|
||||
case OP_BSDIV0: return Z3_OP_BSDIV0;
|
||||
case OP_BUDIV0: return Z3_OP_BUDIV0;
|
||||
case OP_BSREM0: return Z3_OP_BSREM0;
|
||||
case OP_BUREM0: return Z3_OP_BUREM0;
|
||||
case OP_BSMOD0: return Z3_OP_BSMOD0;
|
||||
case OP_ULEQ: return Z3_OP_ULEQ;
|
||||
case OP_SLEQ: return Z3_OP_SLEQ;
|
||||
case OP_UGEQ: return Z3_OP_UGEQ;
|
||||
case OP_SGEQ: return Z3_OP_SGEQ;
|
||||
case OP_ULT: return Z3_OP_ULT;
|
||||
case OP_SLT: return Z3_OP_SLT;
|
||||
case OP_UGT: return Z3_OP_UGT;
|
||||
case OP_SGT: return Z3_OP_SGT;
|
||||
case OP_BAND: return Z3_OP_BAND;
|
||||
case OP_BOR: return Z3_OP_BOR;
|
||||
case OP_BNOT: return Z3_OP_BNOT;
|
||||
case OP_BXOR: return Z3_OP_BXOR;
|
||||
case OP_BNAND: return Z3_OP_BNAND;
|
||||
case OP_BNOR: return Z3_OP_BNOR;
|
||||
case OP_BXNOR: return Z3_OP_BXNOR;
|
||||
case OP_CONCAT: return Z3_OP_CONCAT;
|
||||
case OP_SIGN_EXT: return Z3_OP_SIGN_EXT;
|
||||
case OP_ZERO_EXT: return Z3_OP_ZERO_EXT;
|
||||
case OP_EXTRACT: return Z3_OP_EXTRACT;
|
||||
case OP_REPEAT: return Z3_OP_REPEAT;
|
||||
case OP_BREDOR: return Z3_OP_BREDOR;
|
||||
case OP_BREDAND: return Z3_OP_BREDAND;
|
||||
case OP_BCOMP: return Z3_OP_BCOMP;
|
||||
case OP_BSHL: return Z3_OP_BSHL;
|
||||
case OP_BLSHR: return Z3_OP_BLSHR;
|
||||
case OP_BASHR: return Z3_OP_BASHR;
|
||||
case OP_ROTATE_LEFT: return Z3_OP_ROTATE_LEFT;
|
||||
case OP_ROTATE_RIGHT: return Z3_OP_ROTATE_RIGHT;
|
||||
case OP_EXT_ROTATE_LEFT: return Z3_OP_EXT_ROTATE_LEFT;
|
||||
case OP_EXT_ROTATE_RIGHT: return Z3_OP_EXT_ROTATE_RIGHT;
|
||||
case OP_INT2BV: return Z3_OP_INT2BV;
|
||||
case OP_UBV2INT: return Z3_OP_BV2INT;
|
||||
case OP_SBV2INT: return Z3_OP_SBV2INT;
|
||||
case OP_CARRY: return Z3_OP_CARRY;
|
||||
case OP_XOR3: return Z3_OP_XOR3;
|
||||
case OP_BIT2BOOL: return Z3_OP_BIT2BOOL;
|
||||
case OP_BSMUL_NO_OVFL: return Z3_OP_BSMUL_NO_OVFL;
|
||||
case OP_BUMUL_NO_OVFL: return Z3_OP_BUMUL_NO_OVFL;
|
||||
case OP_BSMUL_NO_UDFL: return Z3_OP_BSMUL_NO_UDFL;
|
||||
case OP_BSDIV_I: return Z3_OP_BSDIV_I;
|
||||
case OP_BUDIV_I: return Z3_OP_BUDIV_I;
|
||||
case OP_BSREM_I: return Z3_OP_BSREM_I;
|
||||
case OP_BUREM_I: return Z3_OP_BUREM_I;
|
||||
case OP_BSMOD_I: return Z3_OP_BSMOD_I;
|
||||
default:
|
||||
return Z3_OP_INTERNAL;
|
||||
}
|
||||
}
|
||||
if (mk_c(c)->get_dt_fid() == _d->get_family_id()) {
|
||||
switch(_d->get_decl_kind()) {
|
||||
case OP_DT_CONSTRUCTOR: return Z3_OP_DT_CONSTRUCTOR;
|
||||
case OP_DT_RECOGNISER: return Z3_OP_DT_RECOGNISER;
|
||||
case OP_DT_IS: return Z3_OP_DT_IS;
|
||||
case OP_DT_ACCESSOR: return Z3_OP_DT_ACCESSOR;
|
||||
case OP_DT_UPDATE_FIELD: return Z3_OP_DT_UPDATE_FIELD;
|
||||
default:
|
||||
return Z3_OP_INTERNAL;
|
||||
}
|
||||
}
|
||||
if (mk_c(c)->get_datalog_fid() == _d->get_family_id()) {
|
||||
switch(_d->get_decl_kind()) {
|
||||
case datalog::OP_RA_STORE: return Z3_OP_RA_STORE;
|
||||
case datalog::OP_RA_EMPTY: return Z3_OP_RA_EMPTY;
|
||||
case datalog::OP_RA_IS_EMPTY: return Z3_OP_RA_IS_EMPTY;
|
||||
case datalog::OP_RA_JOIN: return Z3_OP_RA_JOIN;
|
||||
case datalog::OP_RA_UNION: return Z3_OP_RA_UNION;
|
||||
case datalog::OP_RA_WIDEN: return Z3_OP_RA_WIDEN;
|
||||
case datalog::OP_RA_PROJECT: return Z3_OP_RA_PROJECT;
|
||||
case datalog::OP_RA_FILTER: return Z3_OP_RA_FILTER;
|
||||
case datalog::OP_RA_NEGATION_FILTER: return Z3_OP_RA_NEGATION_FILTER;
|
||||
case datalog::OP_RA_RENAME: return Z3_OP_RA_RENAME;
|
||||
case datalog::OP_RA_COMPLEMENT: return Z3_OP_RA_COMPLEMENT;
|
||||
case datalog::OP_RA_SELECT: return Z3_OP_RA_SELECT;
|
||||
case datalog::OP_RA_CLONE: return Z3_OP_RA_CLONE;
|
||||
case datalog::OP_DL_CONSTANT: return Z3_OP_FD_CONSTANT;
|
||||
case datalog::OP_DL_LT: return Z3_OP_FD_LT;
|
||||
default:
|
||||
return Z3_OP_INTERNAL;
|
||||
}
|
||||
}
|
||||
|
||||
if (mk_c(c)->get_seq_fid() == _d->get_family_id()) {
|
||||
switch (_d->get_decl_kind()) {
|
||||
case OP_SEQ_UNIT: return Z3_OP_SEQ_UNIT;
|
||||
case OP_SEQ_EMPTY: return Z3_OP_SEQ_EMPTY;
|
||||
case OP_SEQ_CONCAT: return Z3_OP_SEQ_CONCAT;
|
||||
case OP_SEQ_PREFIX: return Z3_OP_SEQ_PREFIX;
|
||||
case OP_SEQ_SUFFIX: return Z3_OP_SEQ_SUFFIX;
|
||||
case OP_SEQ_CONTAINS: return Z3_OP_SEQ_CONTAINS;
|
||||
case OP_SEQ_EXTRACT: return Z3_OP_SEQ_EXTRACT;
|
||||
case OP_SEQ_REPLACE: return Z3_OP_SEQ_REPLACE;
|
||||
case OP_SEQ_REPLACE_RE: return Z3_OP_SEQ_REPLACE_RE;
|
||||
case OP_SEQ_REPLACE_RE_ALL: return Z3_OP_SEQ_REPLACE_RE_ALL;
|
||||
case OP_SEQ_REPLACE_ALL: return Z3_OP_SEQ_REPLACE_ALL;
|
||||
case OP_SEQ_AT: return Z3_OP_SEQ_AT;
|
||||
case OP_SEQ_NTH: return Z3_OP_SEQ_NTH;
|
||||
case OP_SEQ_LENGTH: return Z3_OP_SEQ_LENGTH;
|
||||
case OP_SEQ_INDEX: return Z3_OP_SEQ_INDEX;
|
||||
case OP_SEQ_TO_RE: return Z3_OP_SEQ_TO_RE;
|
||||
case OP_SEQ_IN_RE: return Z3_OP_SEQ_IN_RE;
|
||||
case OP_SEQ_MAP: return Z3_OP_SEQ_MAP;
|
||||
case OP_SEQ_MAPI: return Z3_OP_SEQ_MAPI;
|
||||
case OP_SEQ_FOLDL: return Z3_OP_SEQ_FOLDL;
|
||||
case OP_SEQ_FOLDLI: return Z3_OP_SEQ_FOLDLI;
|
||||
|
||||
case _OP_STRING_STRREPL: return Z3_OP_SEQ_REPLACE;
|
||||
case _OP_STRING_CONCAT: return Z3_OP_SEQ_CONCAT;
|
||||
case _OP_STRING_LENGTH: return Z3_OP_SEQ_LENGTH;
|
||||
case _OP_STRING_STRCTN: return Z3_OP_SEQ_CONTAINS;
|
||||
case _OP_STRING_PREFIX: return Z3_OP_SEQ_PREFIX;
|
||||
case _OP_STRING_SUFFIX: return Z3_OP_SEQ_SUFFIX;
|
||||
case _OP_STRING_IN_REGEXP: return Z3_OP_SEQ_IN_RE;
|
||||
case _OP_STRING_TO_REGEXP: return Z3_OP_SEQ_TO_RE;
|
||||
case _OP_STRING_CHARAT: return Z3_OP_SEQ_AT;
|
||||
case _OP_STRING_SUBSTR: return Z3_OP_SEQ_EXTRACT;
|
||||
case _OP_STRING_STRIDOF: return Z3_OP_SEQ_INDEX;
|
||||
case _OP_REGEXP_EMPTY: return Z3_OP_RE_EMPTY_SET;
|
||||
case _OP_REGEXP_FULL_CHAR: return Z3_OP_RE_FULL_SET;
|
||||
|
||||
case OP_STRING_STOI: return Z3_OP_STR_TO_INT;
|
||||
case OP_STRING_ITOS: return Z3_OP_INT_TO_STR;
|
||||
case OP_STRING_TO_CODE: return Z3_OP_STR_TO_CODE;
|
||||
case OP_STRING_FROM_CODE: return Z3_OP_STR_FROM_CODE;
|
||||
|
||||
case OP_STRING_UBVTOS: return Z3_OP_UBV_TO_STR;
|
||||
case OP_STRING_SBVTOS: return Z3_OP_SBV_TO_STR;
|
||||
case OP_STRING_LT: return Z3_OP_STRING_LT;
|
||||
case OP_STRING_LE: return Z3_OP_STRING_LE;
|
||||
|
||||
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_INTERSECT: return Z3_OP_RE_INTERSECT;
|
||||
case OP_RE_LOOP: return Z3_OP_RE_LOOP;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
if (mk_c(c)->get_char_fid() == _d->get_family_id()) {
|
||||
switch (_d->get_decl_kind()) {
|
||||
case OP_CHAR_CONST: return Z3_OP_CHAR_CONST;
|
||||
case OP_CHAR_LE: return Z3_OP_CHAR_LE;
|
||||
case OP_CHAR_TO_INT: return Z3_OP_CHAR_TO_INT;
|
||||
case OP_CHAR_TO_BV: return Z3_OP_CHAR_TO_BV;
|
||||
case OP_CHAR_FROM_BV: return Z3_OP_CHAR_FROM_BV;
|
||||
case OP_CHAR_IS_DIGIT: return Z3_OP_CHAR_IS_DIGIT;
|
||||
default:
|
||||
return Z3_OP_INTERNAL;
|
||||
}
|
||||
}
|
||||
|
||||
if (mk_c(c)->get_fpa_fid() == _d->get_family_id()) {
|
||||
switch (_d->get_decl_kind()) {
|
||||
case OP_FPA_RM_NEAREST_TIES_TO_EVEN: return Z3_OP_FPA_RM_NEAREST_TIES_TO_EVEN;
|
||||
case OP_FPA_RM_NEAREST_TIES_TO_AWAY: return Z3_OP_FPA_RM_NEAREST_TIES_TO_AWAY;
|
||||
case OP_FPA_RM_TOWARD_POSITIVE: return Z3_OP_FPA_RM_TOWARD_POSITIVE;
|
||||
case OP_FPA_RM_TOWARD_NEGATIVE: return Z3_OP_FPA_RM_TOWARD_NEGATIVE;
|
||||
case OP_FPA_RM_TOWARD_ZERO: return Z3_OP_FPA_RM_TOWARD_ZERO;
|
||||
case OP_FPA_NUM: return Z3_OP_FPA_NUM;
|
||||
case OP_FPA_PLUS_INF: return Z3_OP_FPA_PLUS_INF;
|
||||
case OP_FPA_MINUS_INF: return Z3_OP_FPA_MINUS_INF;
|
||||
case OP_FPA_NAN: return Z3_OP_FPA_NAN;
|
||||
case OP_FPA_MINUS_ZERO: return Z3_OP_FPA_MINUS_ZERO;
|
||||
case OP_FPA_PLUS_ZERO: return Z3_OP_FPA_PLUS_ZERO;
|
||||
case OP_FPA_ADD: return Z3_OP_FPA_ADD;
|
||||
case OP_FPA_SUB: return Z3_OP_FPA_SUB;
|
||||
case OP_FPA_NEG: return Z3_OP_FPA_NEG;
|
||||
case OP_FPA_MUL: return Z3_OP_FPA_MUL;
|
||||
case OP_FPA_DIV: return Z3_OP_FPA_DIV;
|
||||
case OP_FPA_REM: return Z3_OP_FPA_REM;
|
||||
case OP_FPA_ABS: return Z3_OP_FPA_ABS;
|
||||
case OP_FPA_MIN: return Z3_OP_FPA_MIN;
|
||||
case OP_FPA_MAX: return Z3_OP_FPA_MAX;
|
||||
case OP_FPA_FMA: return Z3_OP_FPA_FMA;
|
||||
case OP_FPA_SQRT: return Z3_OP_FPA_SQRT;
|
||||
case OP_FPA_EQ: return Z3_OP_FPA_EQ;
|
||||
case OP_FPA_ROUND_TO_INTEGRAL: return Z3_OP_FPA_ROUND_TO_INTEGRAL;
|
||||
case OP_FPA_LT: return Z3_OP_FPA_LT;
|
||||
case OP_FPA_GT: return Z3_OP_FPA_GT;
|
||||
case OP_FPA_LE: return Z3_OP_FPA_LE;
|
||||
case OP_FPA_GE: return Z3_OP_FPA_GE;
|
||||
case OP_FPA_IS_NAN: return Z3_OP_FPA_IS_NAN;
|
||||
case OP_FPA_IS_INF: return Z3_OP_FPA_IS_INF;
|
||||
case OP_FPA_IS_ZERO: return Z3_OP_FPA_IS_ZERO;
|
||||
case OP_FPA_IS_NORMAL: return Z3_OP_FPA_IS_NORMAL;
|
||||
case OP_FPA_IS_SUBNORMAL: return Z3_OP_FPA_IS_SUBNORMAL;
|
||||
case OP_FPA_IS_NEGATIVE: return Z3_OP_FPA_IS_NEGATIVE;
|
||||
case OP_FPA_IS_POSITIVE: return Z3_OP_FPA_IS_POSITIVE;
|
||||
case OP_FPA_FP: return Z3_OP_FPA_FP;
|
||||
case OP_FPA_TO_FP: return Z3_OP_FPA_TO_FP;
|
||||
case OP_FPA_TO_FP_UNSIGNED: return Z3_OP_FPA_TO_FP_UNSIGNED;
|
||||
case OP_FPA_TO_UBV: return Z3_OP_FPA_TO_UBV;
|
||||
case OP_FPA_TO_SBV: return Z3_OP_FPA_TO_SBV;
|
||||
case OP_FPA_TO_REAL: return Z3_OP_FPA_TO_REAL;
|
||||
case OP_FPA_TO_IEEE_BV: return Z3_OP_FPA_TO_IEEE_BV;
|
||||
case OP_FPA_BVWRAP: return Z3_OP_FPA_BVWRAP;
|
||||
case OP_FPA_BV2RM: return Z3_OP_FPA_BV2RM;
|
||||
return Z3_OP_UNINTERPRETED;
|
||||
default:
|
||||
return Z3_OP_INTERNAL;
|
||||
}
|
||||
}
|
||||
|
||||
if (mk_c(c)->m().get_label_family_id() == _d->get_family_id()) {
|
||||
switch(_d->get_decl_kind()) {
|
||||
case OP_LABEL: return Z3_OP_LABEL;
|
||||
case OP_LABEL_LIT: return Z3_OP_LABEL_LIT;
|
||||
default:
|
||||
return Z3_OP_INTERNAL;
|
||||
}
|
||||
}
|
||||
|
||||
if (mk_c(c)->get_pb_fid() == _d->get_family_id()) {
|
||||
switch(_d->get_decl_kind()) {
|
||||
case OP_PB_LE: return Z3_OP_PB_LE;
|
||||
case OP_PB_GE: return Z3_OP_PB_GE;
|
||||
case OP_PB_EQ: return Z3_OP_PB_EQ;
|
||||
case OP_AT_MOST_K: return Z3_OP_PB_AT_MOST;
|
||||
case OP_AT_LEAST_K: return Z3_OP_PB_AT_LEAST;
|
||||
default: return Z3_OP_INTERNAL;
|
||||
}
|
||||
}
|
||||
|
||||
if (mk_c(c)->recfun().get_family_id() == _d->get_family_id())
|
||||
if (mk_c(c)->get_basic_fid() == fid)
|
||||
return get_decl_kind_basic(k);
|
||||
if (mk_c(c)->get_arith_fid() == fid)
|
||||
return get_decl_kind_arith(k);
|
||||
if (mk_c(c)->get_bv_fid() == fid)
|
||||
return get_decl_kind_bv(k);
|
||||
if (mk_c(c)->get_array_fid() == fid)
|
||||
return get_decl_kind_array(k);
|
||||
if (mk_c(c)->get_dt_fid() == fid)
|
||||
return get_decl_kind_dt(k);
|
||||
if (mk_c(c)->get_seq_fid() == fid)
|
||||
return get_decl_kind_seq(k);
|
||||
if (mk_c(c)->get_fpa_fid() == fid)
|
||||
return get_decl_kind_fpa(k);
|
||||
if (mk_c(c)->get_datalog_fid() == fid)
|
||||
return get_decl_kind_datalog(k);
|
||||
if (mk_c(c)->get_pb_fid() == fid)
|
||||
return get_decl_kind_pb(k);
|
||||
if (mk_c(c)->get_special_relations_fid() == fid)
|
||||
return get_decl_kind_special_relations(k);
|
||||
if (mk_c(c)->get_char_fid() == fid)
|
||||
return get_decl_kind_char(k);
|
||||
if (mk_c(c)->m().get_label_family_id() == fid)
|
||||
return get_decl_kind_label(k);
|
||||
if (mk_c(c)->fsutil().get_family_id() == fid)
|
||||
return get_decl_kind_finite_set(k);
|
||||
if (mk_c(c)->recfun().get_family_id() == fid)
|
||||
return Z3_OP_RECURSIVE;
|
||||
|
||||
return Z3_OP_UNINTERPRETED;
|
||||
|
|
@ -1482,11 +1522,7 @@ extern "C" {
|
|||
return 0;
|
||||
}
|
||||
var* va = to_var(_a);
|
||||
if (va) {
|
||||
return va->get_idx();
|
||||
}
|
||||
SET_ERROR_CODE(Z3_INVALID_ARG, nullptr);
|
||||
return 0;
|
||||
return va->get_idx();
|
||||
Z3_CATCH_RETURN(0);
|
||||
}
|
||||
|
||||
|
|
@ -1495,6 +1531,10 @@ extern "C" {
|
|||
LOG_Z3_translate(c, a, target);
|
||||
RESET_ERROR_CODE();
|
||||
CHECK_VALID_AST(a, nullptr);
|
||||
if (!target) {
|
||||
SET_ERROR_CODE(Z3_INVALID_ARG, "null target context");
|
||||
RETURN_Z3(nullptr);
|
||||
}
|
||||
if (c == target) {
|
||||
SET_ERROR_CODE(Z3_INVALID_ARG, nullptr);
|
||||
RETURN_Z3(nullptr);
|
||||
|
|
@ -1507,4 +1547,4 @@ extern "C" {
|
|||
Z3_CATCH_RETURN(nullptr);
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -161,4 +161,4 @@ extern "C" {
|
|||
Z3_CATCH_RETURN(nullptr);
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -135,4 +135,4 @@ extern "C" {
|
|||
Z3_CATCH_RETURN(nullptr);
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ Revision History:
|
|||
|
||||
namespace api {
|
||||
class context;
|
||||
};
|
||||
}
|
||||
|
||||
struct Z3_ast_vector_ref : public api::object {
|
||||
ast_ref_vector m_ast_vector;
|
||||
|
|
|
|||
|
|
@ -399,4 +399,4 @@ Z3_ast Z3_API NAME(Z3_context c, unsigned i, Z3_ast n) { \
|
|||
Z3_CATCH_RETURN(0);
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -121,4 +121,4 @@ extern "C" {
|
|||
Z3_CATCH;
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -133,6 +133,7 @@ namespace api {
|
|||
m_fpa_util(m()),
|
||||
m_sutil(m()),
|
||||
m_recfun(m()),
|
||||
m_finite_set_util(m()),
|
||||
m_ast_trail(m()),
|
||||
m_pmanager(m_limit) {
|
||||
|
||||
|
|
@ -358,7 +359,7 @@ namespace api {
|
|||
return *(m_rcf_manager.get());
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
// ------------------------
|
||||
|
|
@ -530,4 +531,4 @@ extern "C" {
|
|||
Z3_CATCH;
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ Revision History:
|
|||
#include "ast/fpa_decl_plugin.h"
|
||||
#include "ast/recfun_decl_plugin.h"
|
||||
#include "ast/special_relations_decl_plugin.h"
|
||||
#include "ast/finite_set_decl_plugin.h"
|
||||
#include "ast/rewriter/seq_rewriter.h"
|
||||
#include "params/smt_params.h"
|
||||
#include "smt/smt_kernel.h"
|
||||
|
|
@ -44,16 +45,16 @@ Revision History:
|
|||
|
||||
namespace smtlib {
|
||||
class parser;
|
||||
};
|
||||
}
|
||||
|
||||
namespace realclosure {
|
||||
class manager;
|
||||
};
|
||||
}
|
||||
|
||||
namespace smt2 {
|
||||
class parser;
|
||||
void free_parser(parser*);
|
||||
};
|
||||
}
|
||||
|
||||
namespace api {
|
||||
|
||||
|
|
@ -77,6 +78,7 @@ namespace api {
|
|||
fpa_util m_fpa_util;
|
||||
seq_util m_sutil;
|
||||
recfun::util m_recfun;
|
||||
finite_set_util m_finite_set_util;
|
||||
|
||||
// Support for old solver API
|
||||
smt_params m_fparams;
|
||||
|
|
@ -146,6 +148,7 @@ namespace api {
|
|||
datatype_util& dtutil() { return m_dt_plugin->u(); }
|
||||
seq_util& sutil() { return m_sutil; }
|
||||
recfun::util& recfun() { return m_recfun; }
|
||||
finite_set_util& fsutil() { return m_finite_set_util; }
|
||||
family_id get_basic_fid() const { return basic_family_id; }
|
||||
family_id get_array_fid() const { return m_array_fid; }
|
||||
family_id get_arith_fid() const { return arith_family_id; }
|
||||
|
|
@ -264,7 +267,7 @@ namespace api {
|
|||
|
||||
};
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
inline api::context * mk_c(Z3_context c) { return reinterpret_cast<api::context*>(c); }
|
||||
#define RESET_ERROR_CODE() { mk_c(c)->reset_error_code(); }
|
||||
|
|
|
|||
|
|
@ -142,7 +142,7 @@ namespace api {
|
|||
void collect_param_descrs(param_descrs & p) { m_context.collect_params(p); }
|
||||
void updt_params(params_ref const& p) { m_context.updt_params(p); }
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
|
||||
|
|
@ -705,4 +705,4 @@ extern "C" {
|
|||
Z3_CATCH_RETURN(nullptr);
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ typedef void (*reduce_assign_callback_fptr)(void*, func_decl*, unsigned, expr*co
|
|||
namespace api {
|
||||
class fixedpoint_context;
|
||||
class context;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
struct Z3_fixedpoint_ref : public api::object {
|
||||
|
|
|
|||
|
|
@ -687,4 +687,4 @@ extern "C" {
|
|||
}
|
||||
|
||||
|
||||
};
|
||||
}
|
||||
|
|
|
|||
187
src/api/api_finite_set.cpp
Normal file
187
src/api/api_finite_set.cpp
Normal file
|
|
@ -0,0 +1,187 @@
|
|||
/*++
|
||||
Copyright (c) 2025 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
api_finite_set.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
API for finite sets.
|
||||
|
||||
Author:
|
||||
|
||||
Copilot 2025-01-21
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#include "api/z3.h"
|
||||
#include "api/api_log_macros.h"
|
||||
#include "api/api_context.h"
|
||||
#include "api/api_util.h"
|
||||
#include "ast/ast_pp.h"
|
||||
|
||||
extern "C" {
|
||||
|
||||
Z3_sort Z3_API Z3_mk_finite_set_sort(Z3_context c, Z3_sort elem_sort) {
|
||||
Z3_TRY;
|
||||
LOG_Z3_mk_finite_set_sort(c, elem_sort);
|
||||
RESET_ERROR_CODE();
|
||||
parameter param(to_sort(elem_sort));
|
||||
sort* ty = mk_c(c)->m().mk_sort(mk_c(c)->fsutil().get_family_id(), FINITE_SET_SORT, 1, ¶m);
|
||||
mk_c(c)->save_ast_trail(ty);
|
||||
RETURN_Z3(of_sort(ty));
|
||||
Z3_CATCH_RETURN(nullptr);
|
||||
}
|
||||
|
||||
bool Z3_API Z3_is_finite_set_sort(Z3_context c, Z3_sort s) {
|
||||
Z3_TRY;
|
||||
LOG_Z3_is_finite_set_sort(c, s);
|
||||
RESET_ERROR_CODE();
|
||||
return mk_c(c)->fsutil().is_finite_set(to_sort(s));
|
||||
Z3_CATCH_RETURN(false);
|
||||
}
|
||||
|
||||
Z3_sort Z3_API Z3_get_finite_set_sort_basis(Z3_context c, Z3_sort s) {
|
||||
Z3_TRY;
|
||||
LOG_Z3_get_finite_set_sort_basis(c, s);
|
||||
RESET_ERROR_CODE();
|
||||
sort* elem_sort = nullptr;
|
||||
if (!mk_c(c)->fsutil().is_finite_set(to_sort(s), elem_sort)) {
|
||||
SET_ERROR_CODE(Z3_INVALID_ARG, "expected finite set sort");
|
||||
RETURN_Z3(nullptr);
|
||||
}
|
||||
RETURN_Z3(of_sort(elem_sort));
|
||||
Z3_CATCH_RETURN(nullptr);
|
||||
}
|
||||
|
||||
Z3_ast Z3_API Z3_mk_finite_set_empty(Z3_context c, Z3_sort set_sort) {
|
||||
Z3_TRY;
|
||||
LOG_Z3_mk_finite_set_empty(c, set_sort);
|
||||
RESET_ERROR_CODE();
|
||||
app* a = mk_c(c)->fsutil().mk_empty(to_sort(set_sort));
|
||||
mk_c(c)->save_ast_trail(a);
|
||||
RETURN_Z3(of_ast(a));
|
||||
Z3_CATCH_RETURN(nullptr);
|
||||
}
|
||||
|
||||
Z3_ast Z3_API Z3_mk_finite_set_singleton(Z3_context c, Z3_ast elem) {
|
||||
Z3_TRY;
|
||||
LOG_Z3_mk_finite_set_singleton(c, elem);
|
||||
RESET_ERROR_CODE();
|
||||
CHECK_IS_EXPR(elem, nullptr);
|
||||
app* a = mk_c(c)->fsutil().mk_singleton(to_expr(elem));
|
||||
mk_c(c)->save_ast_trail(a);
|
||||
RETURN_Z3(of_ast(a));
|
||||
Z3_CATCH_RETURN(nullptr);
|
||||
}
|
||||
|
||||
Z3_ast Z3_API Z3_mk_finite_set_union(Z3_context c, Z3_ast s1, Z3_ast s2) {
|
||||
Z3_TRY;
|
||||
LOG_Z3_mk_finite_set_union(c, s1, s2);
|
||||
RESET_ERROR_CODE();
|
||||
CHECK_IS_EXPR(s1, nullptr);
|
||||
CHECK_IS_EXPR(s2, nullptr);
|
||||
app* a = mk_c(c)->fsutil().mk_union(to_expr(s1), to_expr(s2));
|
||||
mk_c(c)->save_ast_trail(a);
|
||||
RETURN_Z3(of_ast(a));
|
||||
Z3_CATCH_RETURN(nullptr);
|
||||
}
|
||||
|
||||
Z3_ast Z3_API Z3_mk_finite_set_intersect(Z3_context c, Z3_ast s1, Z3_ast s2) {
|
||||
Z3_TRY;
|
||||
LOG_Z3_mk_finite_set_intersect(c, s1, s2);
|
||||
RESET_ERROR_CODE();
|
||||
CHECK_IS_EXPR(s1, nullptr);
|
||||
CHECK_IS_EXPR(s2, nullptr);
|
||||
app* a = mk_c(c)->fsutil().mk_intersect(to_expr(s1), to_expr(s2));
|
||||
mk_c(c)->save_ast_trail(a);
|
||||
RETURN_Z3(of_ast(a));
|
||||
Z3_CATCH_RETURN(nullptr);
|
||||
}
|
||||
|
||||
Z3_ast Z3_API Z3_mk_finite_set_difference(Z3_context c, Z3_ast s1, Z3_ast s2) {
|
||||
Z3_TRY;
|
||||
LOG_Z3_mk_finite_set_difference(c, s1, s2);
|
||||
RESET_ERROR_CODE();
|
||||
CHECK_IS_EXPR(s1, nullptr);
|
||||
CHECK_IS_EXPR(s2, nullptr);
|
||||
app* a = mk_c(c)->fsutil().mk_difference(to_expr(s1), to_expr(s2));
|
||||
mk_c(c)->save_ast_trail(a);
|
||||
RETURN_Z3(of_ast(a));
|
||||
Z3_CATCH_RETURN(nullptr);
|
||||
}
|
||||
|
||||
Z3_ast Z3_API Z3_mk_finite_set_member(Z3_context c, Z3_ast elem, Z3_ast set) {
|
||||
Z3_TRY;
|
||||
LOG_Z3_mk_finite_set_member(c, elem, set);
|
||||
RESET_ERROR_CODE();
|
||||
CHECK_IS_EXPR(elem, nullptr);
|
||||
CHECK_IS_EXPR(set, nullptr);
|
||||
app* a = mk_c(c)->fsutil().mk_in(to_expr(elem), to_expr(set));
|
||||
mk_c(c)->save_ast_trail(a);
|
||||
RETURN_Z3(of_ast(a));
|
||||
Z3_CATCH_RETURN(nullptr);
|
||||
}
|
||||
|
||||
Z3_ast Z3_API Z3_mk_finite_set_size(Z3_context c, Z3_ast set) {
|
||||
Z3_TRY;
|
||||
LOG_Z3_mk_finite_set_size(c, set);
|
||||
RESET_ERROR_CODE();
|
||||
CHECK_IS_EXPR(set, nullptr);
|
||||
app* a = mk_c(c)->fsutil().mk_size(to_expr(set));
|
||||
mk_c(c)->save_ast_trail(a);
|
||||
RETURN_Z3(of_ast(a));
|
||||
Z3_CATCH_RETURN(nullptr);
|
||||
}
|
||||
|
||||
Z3_ast Z3_API Z3_mk_finite_set_subset(Z3_context c, Z3_ast s1, Z3_ast s2) {
|
||||
Z3_TRY;
|
||||
LOG_Z3_mk_finite_set_subset(c, s1, s2);
|
||||
RESET_ERROR_CODE();
|
||||
CHECK_IS_EXPR(s1, nullptr);
|
||||
CHECK_IS_EXPR(s2, nullptr);
|
||||
app* a = mk_c(c)->fsutil().mk_subset(to_expr(s1), to_expr(s2));
|
||||
mk_c(c)->save_ast_trail(a);
|
||||
RETURN_Z3(of_ast(a));
|
||||
Z3_CATCH_RETURN(nullptr);
|
||||
}
|
||||
|
||||
Z3_ast Z3_API Z3_mk_finite_set_map(Z3_context c, Z3_ast f, Z3_ast set) {
|
||||
Z3_TRY;
|
||||
LOG_Z3_mk_finite_set_map(c, f, set);
|
||||
RESET_ERROR_CODE();
|
||||
CHECK_IS_EXPR(f, nullptr);
|
||||
CHECK_IS_EXPR(set, nullptr);
|
||||
app* a = mk_c(c)->fsutil().mk_map(to_expr(f), to_expr(set));
|
||||
mk_c(c)->save_ast_trail(a);
|
||||
RETURN_Z3(of_ast(a));
|
||||
Z3_CATCH_RETURN(nullptr);
|
||||
}
|
||||
|
||||
Z3_ast Z3_API Z3_mk_finite_set_filter(Z3_context c, Z3_ast f, Z3_ast set) {
|
||||
Z3_TRY;
|
||||
LOG_Z3_mk_finite_set_filter(c, f, set);
|
||||
RESET_ERROR_CODE();
|
||||
CHECK_IS_EXPR(f, nullptr);
|
||||
CHECK_IS_EXPR(set, nullptr);
|
||||
app* a = mk_c(c)->fsutil().mk_filter(to_expr(f), to_expr(set));
|
||||
mk_c(c)->save_ast_trail(a);
|
||||
RETURN_Z3(of_ast(a));
|
||||
Z3_CATCH_RETURN(nullptr);
|
||||
}
|
||||
|
||||
Z3_ast Z3_API Z3_mk_finite_set_range(Z3_context c, Z3_ast low, Z3_ast high) {
|
||||
Z3_TRY;
|
||||
LOG_Z3_mk_finite_set_range(c, low, high);
|
||||
RESET_ERROR_CODE();
|
||||
CHECK_IS_EXPR(low, nullptr);
|
||||
CHECK_IS_EXPR(high, nullptr);
|
||||
app* a = mk_c(c)->fsutil().mk_range(to_expr(low), to_expr(high));
|
||||
mk_c(c)->save_ast_trail(a);
|
||||
RETURN_Z3(of_ast(a));
|
||||
Z3_CATCH_RETURN(nullptr);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -167,6 +167,7 @@ extern "C" {
|
|||
RESET_ERROR_CODE();
|
||||
if (ebits < 2 || sbits < 3) {
|
||||
SET_ERROR_CODE(Z3_INVALID_ARG, "ebits should be at least 2, sbits at least 3");
|
||||
RETURN_Z3(nullptr);
|
||||
}
|
||||
api::context * ctx = mk_c(c);
|
||||
sort * s = ctx->fpautil().mk_float_sort(ebits, sbits);
|
||||
|
|
@ -1336,4 +1337,4 @@ extern "C" {
|
|||
Z3_CATCH_RETURN(false);
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -213,4 +213,4 @@ extern "C" {
|
|||
Z3_CATCH_RETURN("");
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -64,6 +64,7 @@ extern "C" {
|
|||
LOG_Z3_model_get_const_interp(c, m, a);
|
||||
RESET_ERROR_CODE();
|
||||
CHECK_NON_NULL(m, nullptr);
|
||||
CHECK_NON_NULL(a, nullptr);
|
||||
expr * r = to_model_ref(m)->get_const_interp(to_func_decl(a));
|
||||
if (!r) {
|
||||
RETURN_Z3(nullptr);
|
||||
|
|
@ -164,7 +165,7 @@ extern "C" {
|
|||
model::scoped_model_completion _scm(*_m, model_completion);
|
||||
result = (*_m)(to_expr(t));
|
||||
mk_c(c)->save_ast_trail(result.get());
|
||||
*v = of_ast(result.get());
|
||||
if (v) *v = of_ast(result.get());
|
||||
RETURN_Z3_model_eval true;
|
||||
Z3_CATCH_RETURN(false);
|
||||
}
|
||||
|
|
@ -212,6 +213,10 @@ extern "C" {
|
|||
Z3_TRY;
|
||||
LOG_Z3_model_translate(c, m, target);
|
||||
RESET_ERROR_CODE();
|
||||
if (!target) {
|
||||
SET_ERROR_CODE(Z3_INVALID_ARG, "null target context");
|
||||
RETURN_Z3(nullptr);
|
||||
}
|
||||
Z3_model_ref* dst = alloc(Z3_model_ref, *mk_c(target));
|
||||
ast_translation tr(mk_c(c)->m(), mk_c(target)->m());
|
||||
dst->m_model = to_model_ref(m)->translate(tr);
|
||||
|
|
@ -246,7 +251,8 @@ extern "C" {
|
|||
Z3_TRY;
|
||||
LOG_Z3_add_func_interp(c, m, f, else_val);
|
||||
RESET_ERROR_CODE();
|
||||
CHECK_NON_NULL(f, nullptr);
|
||||
CHECK_NON_NULL(m, nullptr);
|
||||
CHECK_NON_NULL(f, nullptr);
|
||||
func_decl* d = to_func_decl(f);
|
||||
model* mdl = to_model_ref(m);
|
||||
Z3_func_interp_ref * f_ref = alloc(Z3_func_interp_ref, *mk_c(c), mdl);
|
||||
|
|
@ -442,4 +448,4 @@ extern "C" {
|
|||
Z3_CATCH_RETURN(nullptr);
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -489,4 +489,4 @@ extern "C" {
|
|||
}
|
||||
#endif
|
||||
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -94,7 +94,11 @@ extern "C" {
|
|||
Z3_TRY;
|
||||
LOG_Z3_optimize_assert_soft(c, o, a, weight, id);
|
||||
RESET_ERROR_CODE();
|
||||
CHECK_FORMULA(a,0);
|
||||
CHECK_FORMULA(a,0);
|
||||
if (!weight) {
|
||||
SET_ERROR_CODE(Z3_INVALID_ARG, "null weight string");
|
||||
return 0;
|
||||
}
|
||||
rational w(weight);
|
||||
return to_optimize_ptr(o)->add_soft_constraint(to_expr(a), w, to_symbol(id));
|
||||
Z3_CATCH_RETURN(0);
|
||||
|
|
@ -499,4 +503,4 @@ extern "C" {
|
|||
Z3_CATCH_RETURN(nullptr);
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -212,4 +212,4 @@ extern "C" {
|
|||
Z3_CATCH_RETURN("");
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -106,4 +106,4 @@ extern "C" {
|
|||
}
|
||||
|
||||
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -80,4 +80,4 @@ extern "C" {
|
|||
Z3_CATCH_RETURN(nullptr);
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -321,6 +321,10 @@ extern "C" {
|
|||
Z3_TRY;
|
||||
LOG_Z3_mk_pattern(c, num_patterns, terms);
|
||||
RESET_ERROR_CODE();
|
||||
if (num_patterns == 0) {
|
||||
SET_ERROR_CODE(Z3_INVALID_ARG, "pattern requires at least one term");
|
||||
RETURN_Z3(nullptr);
|
||||
}
|
||||
for (unsigned i = 0; i < num_patterns; ++i) {
|
||||
if (!is_app(to_expr(terms[i]))) {
|
||||
SET_ERROR_CODE(Z3_INVALID_ARG, nullptr);
|
||||
|
|
@ -579,5 +583,5 @@ extern "C" {
|
|||
return Z3_ast_to_string(c, reinterpret_cast<Z3_ast>(p));
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -437,4 +437,4 @@ extern "C" {
|
|||
return from_rcnumeral(rcfm(c).get_sign_condition_coefficient(to_rcnumeral(a), i, j));
|
||||
Z3_CATCH_RETURN(nullptr);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -48,6 +48,10 @@ extern "C" {
|
|||
Z3_TRY;
|
||||
LOG_Z3_mk_string(c, str);
|
||||
RESET_ERROR_CODE();
|
||||
if (!str) {
|
||||
SET_ERROR_CODE(Z3_INVALID_ARG, "null string");
|
||||
RETURN_Z3(nullptr);
|
||||
}
|
||||
zstring s(str);
|
||||
app* a = mk_c(c)->sutil().str.mk_string(s);
|
||||
mk_c(c)->save_ast_trail(a);
|
||||
|
|
@ -59,6 +63,10 @@ extern "C" {
|
|||
Z3_TRY;
|
||||
LOG_Z3_mk_lstring(c, sz, str);
|
||||
RESET_ERROR_CODE();
|
||||
if (sz > 0 && !str) {
|
||||
SET_ERROR_CODE(Z3_INVALID_ARG, "null string buffer");
|
||||
RETURN_Z3(nullptr);
|
||||
}
|
||||
unsigned_vector chs;
|
||||
for (unsigned i = 0; i < sz; ++i) chs.push_back((unsigned char)str[i]);
|
||||
zstring s(sz, chs.data());
|
||||
|
|
@ -314,6 +322,10 @@ extern "C" {
|
|||
Z3_TRY;
|
||||
LOG_Z3_mk_re_loop(c, r, lo, hi);
|
||||
RESET_ERROR_CODE();
|
||||
if (hi != 0 && lo > hi) {
|
||||
SET_ERROR_CODE(Z3_INVALID_ARG, "loop lower bound must not exceed upper bound");
|
||||
RETURN_Z3(nullptr);
|
||||
}
|
||||
app* a = hi == 0 ? mk_c(c)->sutil().re.mk_loop(to_expr(r), lo) : mk_c(c)->sutil().re.mk_loop(to_expr(r), lo, hi);
|
||||
mk_c(c)->save_ast_trail(a);
|
||||
RETURN_Z3(of_ast(a));
|
||||
|
|
@ -357,4 +369,4 @@ extern "C" {
|
|||
MK_FOURARY(Z3_mk_seq_foldli, mk_c(c)->get_seq_fid(), OP_SEQ_FOLDLI, SKIP);
|
||||
|
||||
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -379,14 +379,15 @@ extern "C" {
|
|||
LOG_Z3_solver_from_file(c, s, file_name);
|
||||
char const* ext = get_extension(file_name);
|
||||
std::ifstream is(file_name);
|
||||
init_solver(c, s);
|
||||
if (!is) {
|
||||
SET_ERROR_CODE(Z3_FILE_ACCESS_ERROR, nullptr);
|
||||
}
|
||||
else if (ext && (std::string("dimacs") == ext || std::string("cnf") == ext)) {
|
||||
init_solver(c, s);
|
||||
solver_from_dimacs_stream(c, s, is);
|
||||
}
|
||||
else {
|
||||
init_solver(c, s);
|
||||
solver_from_stream(c, s, is);
|
||||
}
|
||||
Z3_CATCH;
|
||||
|
|
@ -1153,24 +1154,24 @@ extern "C" {
|
|||
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*))created_eh;
|
||||
to_solver_ref(s)->user_propagate_register_created(c);
|
||||
user_propagator::created_eh_t created_fn = (void(*)(void*, user_propagator::callback*, expr*))created_eh;
|
||||
to_solver_ref(s)->user_propagate_register_created(created_fn);
|
||||
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, bool))decide_eh;
|
||||
to_solver_ref(s)->user_propagate_register_decide(c);
|
||||
user_propagator::decide_eh_t decide_fn = (void(*)(void*, user_propagator::callback*, expr*, unsigned, bool))decide_eh;
|
||||
to_solver_ref(s)->user_propagate_register_decide(decide_fn);
|
||||
Z3_CATCH;
|
||||
}
|
||||
|
||||
void Z3_API Z3_solver_propagate_on_binding(Z3_context c, Z3_solver s, Z3_on_binding_eh binding_eh) {
|
||||
Z3_TRY;
|
||||
RESET_ERROR_CODE();
|
||||
user_propagator::binding_eh_t c = (bool(*)(void*, user_propagator::callback*, expr*, expr*))binding_eh;
|
||||
to_solver_ref(s)->user_propagate_register_on_binding(c);
|
||||
user_propagator::binding_eh_t binding_fn = (bool(*)(void*, user_propagator::callback*, expr*, expr*))binding_eh;
|
||||
to_solver_ref(s)->user_propagate_register_on_binding(binding_fn);
|
||||
Z3_CATCH;
|
||||
}
|
||||
|
||||
|
|
@ -1217,4 +1218,4 @@ extern "C" {
|
|||
|
||||
|
||||
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -61,4 +61,4 @@ extern "C" {
|
|||
}
|
||||
|
||||
MK_DECL(Z3_mk_transitive_closure, OP_SPECIAL_RELATION_TC);
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -133,4 +133,4 @@ extern "C" {
|
|||
return memory::get_allocation_size();
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -669,4 +669,4 @@ extern "C" {
|
|||
|
||||
|
||||
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ namespace api {
|
|||
void inc_ref();
|
||||
void dec_ref();
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
inline ast * to_ast(Z3_ast a) { return reinterpret_cast<ast *>(a); }
|
||||
inline Z3_ast of_ast(ast* a) { return reinterpret_cast<Z3_ast>(a); }
|
||||
|
|
|
|||
|
|
@ -323,6 +323,10 @@ namespace z3 {
|
|||
\brief Return a regular expression sort over sequences \c seq_sort.
|
||||
*/
|
||||
sort re_sort(sort& seq_sort);
|
||||
/**
|
||||
\brief Return a finite set sort over element sort \c s.
|
||||
*/
|
||||
sort finite_set_sort(sort& s);
|
||||
/**
|
||||
\brief Return an array sort for arrays from \c d to \c r.
|
||||
|
||||
|
|
@ -864,6 +868,44 @@ namespace z3 {
|
|||
|
||||
};
|
||||
|
||||
class parser_context : public object {
|
||||
Z3_parser_context m_pc;
|
||||
public:
|
||||
explicit parser_context(context & c):object(c), m_pc(Z3_mk_parser_context(c)) { Z3_parser_context_inc_ref(ctx(), m_pc); }
|
||||
~parser_context() override { if (m_pc) Z3_parser_context_dec_ref(ctx(), m_pc); }
|
||||
explicit operator bool() const { return m_pc; }
|
||||
operator Z3_parser_context() const { return m_pc; }
|
||||
parser_context(const parser_context &o):object(o), m_pc(o.m_pc) { Z3_parser_context_inc_ref(ctx(), m_pc); }
|
||||
parser_context &operator=(const parser_context &o) {
|
||||
if (this != &o) {
|
||||
if (m_pc) Z3_parser_context_dec_ref(*m_ctx, m_pc);
|
||||
Z3_parser_context_inc_ref(*o.m_ctx, o.m_pc);
|
||||
object::operator=(o);
|
||||
m_pc = o.m_pc;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Add a sort declaration.
|
||||
*/
|
||||
void add_sort(const sort & s) { Z3_parser_context_add_sort(ctx(), m_pc, s); check_error(); }
|
||||
|
||||
/**
|
||||
\brief Add a function declaration.
|
||||
*/
|
||||
void add_sort(const func_decl & f) { Z3_parser_context_add_decl(ctx(), m_pc, f); check_error(); }
|
||||
|
||||
/**
|
||||
\brief Parse a string of SMTLIB2 commands. Return assertions.
|
||||
*/
|
||||
expr_vector parse_string(const char * s) {
|
||||
auto result = Z3_parser_context_from_string(ctx(), m_pc, s);
|
||||
m_ctx->check_error();
|
||||
return expr_vector(ctx(), result);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
\brief forward declarations
|
||||
*/
|
||||
|
|
@ -1491,6 +1533,8 @@ namespace z3 {
|
|||
|
||||
expr rotate_left(unsigned i) const { Z3_ast r = Z3_mk_rotate_left(ctx(), i, *this); ctx().check_error(); return expr(ctx(), r); }
|
||||
expr rotate_right(unsigned i) const { Z3_ast r = Z3_mk_rotate_right(ctx(), i, *this); ctx().check_error(); return expr(ctx(), r); }
|
||||
expr ext_rotate_left(expr const& n) const { Z3_ast r = Z3_mk_ext_rotate_left(ctx(), *this, n); ctx().check_error(); return expr(ctx(), r); }
|
||||
expr ext_rotate_right(expr const& n) const { Z3_ast r = Z3_mk_ext_rotate_right(ctx(), *this, n); ctx().check_error(); return expr(ctx(), r); }
|
||||
expr repeat(unsigned i) const { Z3_ast r = Z3_mk_repeat(ctx(), i, *this); ctx().check_error(); return expr(ctx(), r); }
|
||||
|
||||
friend expr bvredor(expr const & a);
|
||||
|
|
@ -3663,6 +3707,7 @@ namespace z3 {
|
|||
inline sort context::char_sort() { Z3_sort s = Z3_mk_char_sort(m_ctx); check_error(); return sort(*this, s); }
|
||||
inline sort context::seq_sort(sort& s) { Z3_sort r = Z3_mk_seq_sort(m_ctx, s); check_error(); return sort(*this, r); }
|
||||
inline sort context::re_sort(sort& s) { Z3_sort r = Z3_mk_re_sort(m_ctx, s); check_error(); return sort(*this, r); }
|
||||
inline sort context::finite_set_sort(sort& s) { Z3_sort r = Z3_mk_finite_set_sort(m_ctx, s); check_error(); return sort(*this, r); }
|
||||
inline sort context::fpa_sort(unsigned ebits, unsigned sbits) { Z3_sort s = Z3_mk_fpa_sort(m_ctx, ebits, sbits); check_error(); return sort(*this, s); }
|
||||
|
||||
template<>
|
||||
|
|
@ -4264,6 +4309,54 @@ namespace z3 {
|
|||
MK_EXPR2(Z3_mk_set_subset, a, b);
|
||||
}
|
||||
|
||||
// finite set operations
|
||||
|
||||
inline expr finite_set_empty(sort const& s) {
|
||||
Z3_ast r = Z3_mk_finite_set_empty(s.ctx(), s);
|
||||
s.check_error();
|
||||
return expr(s.ctx(), r);
|
||||
}
|
||||
|
||||
inline expr finite_set_singleton(expr const& e) {
|
||||
MK_EXPR1(Z3_mk_finite_set_singleton, e);
|
||||
}
|
||||
|
||||
inline expr finite_set_union(expr const& a, expr const& b) {
|
||||
MK_EXPR2(Z3_mk_finite_set_union, a, b);
|
||||
}
|
||||
|
||||
inline expr finite_set_intersect(expr const& a, expr const& b) {
|
||||
MK_EXPR2(Z3_mk_finite_set_intersect, a, b);
|
||||
}
|
||||
|
||||
inline expr finite_set_difference(expr const& a, expr const& b) {
|
||||
MK_EXPR2(Z3_mk_finite_set_difference, a, b);
|
||||
}
|
||||
|
||||
inline expr finite_set_member(expr const& e, expr const& s) {
|
||||
MK_EXPR2(Z3_mk_finite_set_member, e, s);
|
||||
}
|
||||
|
||||
inline expr finite_set_size(expr const& s) {
|
||||
MK_EXPR1(Z3_mk_finite_set_size, s);
|
||||
}
|
||||
|
||||
inline expr finite_set_subset(expr const& a, expr const& b) {
|
||||
MK_EXPR2(Z3_mk_finite_set_subset, a, b);
|
||||
}
|
||||
|
||||
inline expr finite_set_map(expr const& f, expr const& s) {
|
||||
MK_EXPR2(Z3_mk_finite_set_map, f, s);
|
||||
}
|
||||
|
||||
inline expr finite_set_filter(expr const& f, expr const& s) {
|
||||
MK_EXPR2(Z3_mk_finite_set_filter, f, s);
|
||||
}
|
||||
|
||||
inline expr finite_set_range(expr const& low, expr const& high) {
|
||||
MK_EXPR2(Z3_mk_finite_set_range, low, high);
|
||||
}
|
||||
|
||||
// sequence and regular expression operations.
|
||||
// union is +
|
||||
// concat is overloaded to handle sequences and regular expressions
|
||||
|
|
@ -4832,7 +4925,7 @@ namespace z3 {
|
|||
|
||||
void check_context(rcf_num const& other) const {
|
||||
if (m_ctx != other.m_ctx) {
|
||||
throw exception("rcf_num objects from different contexts");
|
||||
Z3_THROW(exception("rcf_num objects from different contexts"));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -5012,9 +5105,9 @@ namespace z3 {
|
|||
*/
|
||||
inline std::vector<rcf_num> rcf_roots(context& c, std::vector<rcf_num> const& coeffs) {
|
||||
if (coeffs.empty()) {
|
||||
throw exception("polynomial coefficients cannot be empty");
|
||||
Z3_THROW(exception("polynomial coefficients cannot be empty"));
|
||||
}
|
||||
|
||||
|
||||
unsigned n = static_cast<unsigned>(coeffs.size());
|
||||
std::vector<Z3_rcf_num> a(n);
|
||||
std::vector<Z3_rcf_num> roots(n);
|
||||
|
|
|
|||
|
|
@ -64,6 +64,7 @@ set(Z3_DOTNET_ASSEMBLY_SOURCES_IN_SRC_TREE
|
|||
FiniteDomainExpr.cs
|
||||
FiniteDomainNum.cs
|
||||
FiniteDomainSort.cs
|
||||
FiniteSetSort.cs
|
||||
Fixedpoint.cs
|
||||
FPExpr.cs
|
||||
FPNum.cs
|
||||
|
|
@ -146,8 +147,13 @@ endforeach()
|
|||
set(Z3_DOTNET_NUPKG_VERSION "${VER_MAJOR}.${VER_MINOR}.${VER_BUILD}")
|
||||
if(TARGET_ARCHITECTURE STREQUAL "i686")
|
||||
set(Z3_DOTNET_PLATFORM "x86")
|
||||
set(Z3_DOTNET_WIN_RID "win-x86")
|
||||
elseif(TARGET_ARCHITECTURE STREQUAL "arm64")
|
||||
set(Z3_DOTNET_PLATFORM "AnyCPU")
|
||||
set(Z3_DOTNET_WIN_RID "win-arm64")
|
||||
else()
|
||||
set(Z3_DOTNET_PLATFORM "AnyCPU")
|
||||
set(Z3_DOTNET_WIN_RID "win-x64")
|
||||
endif()
|
||||
|
||||
# TODO conditional for signing. we can then enable the ``Release_delaysign`` configuration
|
||||
|
|
|
|||
|
|
@ -562,6 +562,63 @@ namespace Microsoft.Z3
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a type variable sort for use as a parameter in polymorphic datatypes.
|
||||
/// </summary>
|
||||
/// <param name="name">name of the type variable</param>
|
||||
public Sort MkTypeVariable(Symbol name)
|
||||
{
|
||||
Debug.Assert(name != null);
|
||||
CheckContextMatch(name);
|
||||
return new Sort(this, Native.Z3_mk_type_variable(nCtx, name.NativeObject));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a type variable sort for use as a parameter in polymorphic datatypes.
|
||||
/// </summary>
|
||||
/// <param name="name">name of the type variable</param>
|
||||
public Sort MkTypeVariable(string name)
|
||||
{
|
||||
using var symbol = MkSymbol(name);
|
||||
return MkTypeVariable(symbol);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a polymorphic datatype sort with explicit type parameters.
|
||||
/// Type parameters should be sorts created with <see cref="MkTypeVariable(string)"/>.
|
||||
/// </summary>
|
||||
/// <param name="name">name of the datatype sort</param>
|
||||
/// <param name="typeParams">array of type variable sorts</param>
|
||||
/// <param name="constructors">array of constructors</param>
|
||||
public DatatypeSort MkPolymorphicDatatypeSort(Symbol name, Sort[] typeParams, Constructor[] constructors)
|
||||
{
|
||||
Debug.Assert(name != null);
|
||||
Debug.Assert(typeParams != null);
|
||||
Debug.Assert(constructors != null);
|
||||
Debug.Assert(constructors.All(c => c != null));
|
||||
|
||||
CheckContextMatch(name);
|
||||
CheckContextMatch<Sort>(typeParams);
|
||||
CheckContextMatch<Constructor>(constructors);
|
||||
return new DatatypeSort(this,
|
||||
Native.Z3_mk_polymorphic_datatype(nCtx, name.NativeObject,
|
||||
(uint)typeParams.Length, AST.ArrayToNative(typeParams),
|
||||
(uint)constructors.Length, Z3Object.ArrayToNative(constructors)));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a polymorphic datatype sort with explicit type parameters.
|
||||
/// Type parameters should be sorts created with <see cref="MkTypeVariable(string)"/>.
|
||||
/// </summary>
|
||||
/// <param name="name">name of the datatype sort</param>
|
||||
/// <param name="typeParams">array of type variable sorts</param>
|
||||
/// <param name="constructors">array of constructors</param>
|
||||
public DatatypeSort MkPolymorphicDatatypeSort(string name, Sort[] typeParams, Constructor[] constructors)
|
||||
{
|
||||
using var symbol = MkSymbol(name);
|
||||
return MkPolymorphicDatatypeSort(symbol, typeParams, constructors);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Update a datatype field at expression t with value v.
|
||||
/// The function performs a record update at t. The field
|
||||
|
|
@ -2442,6 +2499,180 @@ namespace Microsoft.Z3
|
|||
|
||||
#endregion
|
||||
|
||||
#region Finite Sets
|
||||
|
||||
/// <summary>
|
||||
/// Create a finite set sort over the given element sort.
|
||||
/// </summary>
|
||||
public FiniteSetSort MkFiniteSetSort(Sort elemSort)
|
||||
{
|
||||
Debug.Assert(elemSort != null);
|
||||
|
||||
CheckContextMatch(elemSort);
|
||||
return new FiniteSetSort(this, elemSort);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check if a sort is a finite set sort.
|
||||
/// </summary>
|
||||
public bool IsFiniteSetSort(Sort s)
|
||||
{
|
||||
Debug.Assert(s != null);
|
||||
|
||||
CheckContextMatch(s);
|
||||
return Native.Z3_is_finite_set_sort(nCtx, s.NativeObject) != 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the element sort (basis) of a finite set sort.
|
||||
/// </summary>
|
||||
public Sort GetFiniteSetSortBasis(Sort s)
|
||||
{
|
||||
Debug.Assert(s != null);
|
||||
|
||||
CheckContextMatch(s);
|
||||
return Sort.Create(this, Native.Z3_get_finite_set_sort_basis(nCtx, s.NativeObject));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create an empty finite set.
|
||||
/// </summary>
|
||||
public Expr MkFiniteSetEmpty(Sort setSort)
|
||||
{
|
||||
Debug.Assert(setSort != null);
|
||||
|
||||
CheckContextMatch(setSort);
|
||||
return Expr.Create(this, Native.Z3_mk_finite_set_empty(nCtx, setSort.NativeObject));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a singleton finite set.
|
||||
/// </summary>
|
||||
public Expr MkFiniteSetSingleton(Expr elem)
|
||||
{
|
||||
Debug.Assert(elem != null);
|
||||
|
||||
CheckContextMatch(elem);
|
||||
return Expr.Create(this, Native.Z3_mk_finite_set_singleton(nCtx, elem.NativeObject));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create the union of two finite sets.
|
||||
/// </summary>
|
||||
public Expr MkFiniteSetUnion(Expr s1, Expr s2)
|
||||
{
|
||||
Debug.Assert(s1 != null);
|
||||
Debug.Assert(s2 != null);
|
||||
|
||||
CheckContextMatch(s1);
|
||||
CheckContextMatch(s2);
|
||||
return Expr.Create(this, Native.Z3_mk_finite_set_union(nCtx, s1.NativeObject, s2.NativeObject));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create the intersection of two finite sets.
|
||||
/// </summary>
|
||||
public Expr MkFiniteSetIntersect(Expr s1, Expr s2)
|
||||
{
|
||||
Debug.Assert(s1 != null);
|
||||
Debug.Assert(s2 != null);
|
||||
|
||||
CheckContextMatch(s1);
|
||||
CheckContextMatch(s2);
|
||||
return Expr.Create(this, Native.Z3_mk_finite_set_intersect(nCtx, s1.NativeObject, s2.NativeObject));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create the difference of two finite sets.
|
||||
/// </summary>
|
||||
public Expr MkFiniteSetDifference(Expr s1, Expr s2)
|
||||
{
|
||||
Debug.Assert(s1 != null);
|
||||
Debug.Assert(s2 != null);
|
||||
|
||||
CheckContextMatch(s1);
|
||||
CheckContextMatch(s2);
|
||||
return Expr.Create(this, Native.Z3_mk_finite_set_difference(nCtx, s1.NativeObject, s2.NativeObject));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check for membership in a finite set.
|
||||
/// </summary>
|
||||
public BoolExpr MkFiniteSetMember(Expr elem, Expr set)
|
||||
{
|
||||
Debug.Assert(elem != null);
|
||||
Debug.Assert(set != null);
|
||||
|
||||
CheckContextMatch(elem);
|
||||
CheckContextMatch(set);
|
||||
return (BoolExpr)Expr.Create(this, Native.Z3_mk_finite_set_member(nCtx, elem.NativeObject, set.NativeObject));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the cardinality of a finite set.
|
||||
/// </summary>
|
||||
public Expr MkFiniteSetSize(Expr set)
|
||||
{
|
||||
Debug.Assert(set != null);
|
||||
|
||||
CheckContextMatch(set);
|
||||
return Expr.Create(this, Native.Z3_mk_finite_set_size(nCtx, set.NativeObject));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check if one finite set is a subset of another.
|
||||
/// </summary>
|
||||
public BoolExpr MkFiniteSetSubset(Expr s1, Expr s2)
|
||||
{
|
||||
Debug.Assert(s1 != null);
|
||||
Debug.Assert(s2 != null);
|
||||
|
||||
CheckContextMatch(s1);
|
||||
CheckContextMatch(s2);
|
||||
return (BoolExpr)Expr.Create(this, Native.Z3_mk_finite_set_subset(nCtx, s1.NativeObject, s2.NativeObject));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Map a function over all elements in a finite set.
|
||||
/// </summary>
|
||||
public Expr MkFiniteSetMap(Expr f, Expr set)
|
||||
{
|
||||
Debug.Assert(f != null);
|
||||
Debug.Assert(set != null);
|
||||
|
||||
CheckContextMatch(f);
|
||||
CheckContextMatch(set);
|
||||
return Expr.Create(this, Native.Z3_mk_finite_set_map(nCtx, f.NativeObject, set.NativeObject));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Filter a finite set with a predicate.
|
||||
/// </summary>
|
||||
public Expr MkFiniteSetFilter(Expr f, Expr set)
|
||||
{
|
||||
Debug.Assert(f != null);
|
||||
Debug.Assert(set != null);
|
||||
|
||||
CheckContextMatch(f);
|
||||
CheckContextMatch(set);
|
||||
return Expr.Create(this, Native.Z3_mk_finite_set_filter(nCtx, f.NativeObject, set.NativeObject));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a finite set containing integers in the range [low, high].
|
||||
/// </summary>
|
||||
public Expr MkFiniteSetRange(Expr low, Expr high)
|
||||
{
|
||||
Debug.Assert(low != null);
|
||||
Debug.Assert(high != null);
|
||||
|
||||
CheckContextMatch(low);
|
||||
CheckContextMatch(high);
|
||||
return Expr.Create(this, Native.Z3_mk_finite_set_range(nCtx, low.NativeObject, high.NativeObject));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Sequence, string and regular expressions
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -5025,6 +5256,11 @@ namespace Microsoft.Z3
|
|||
internal IntPtr nCtx { get { return m_ctx; } }
|
||||
private Z3_ast_print_mode m_print_mode = Z3_ast_print_mode.Z3_PRINT_SMTLIB2_COMPLIANT;
|
||||
|
||||
// Estimated native memory used per context, for GC memory pressure hints.
|
||||
// The value is a conservative lower bound; actual usage may exceed this.
|
||||
private const long NativeMemoryPressureEstimate = 8 * 1024 * 1024; // 8 MB
|
||||
private bool m_memPressureAdded = false;
|
||||
|
||||
internal void NativeErrorHandler(IntPtr ctx, Z3_error_code errorCode)
|
||||
{
|
||||
// Do-nothing error handler. The wrappers in Z3.Native will throw exceptions upon errors.
|
||||
|
|
@ -5035,6 +5271,11 @@ namespace Microsoft.Z3
|
|||
PrintMode = Z3_ast_print_mode.Z3_PRINT_SMTLIB2_COMPLIANT;
|
||||
m_n_err_handler = new Native.Z3_error_handler(NativeErrorHandler); // keep reference so it doesn't get collected.
|
||||
Native.Z3_set_error_handler(m_ctx, m_n_err_handler);
|
||||
if (!is_external)
|
||||
{
|
||||
GC.AddMemoryPressure(NativeMemoryPressureEstimate);
|
||||
m_memPressureAdded = true;
|
||||
}
|
||||
}
|
||||
|
||||
internal void CheckContextMatch(Z3Object other)
|
||||
|
|
@ -5124,17 +5365,38 @@ namespace Microsoft.Z3
|
|||
m_charSort = null;
|
||||
if (m_ctx != IntPtr.Zero)
|
||||
{
|
||||
IntPtr ctx = m_ctx;
|
||||
// Suppress the finalizer before performing cleanup so that it cannot
|
||||
// run concurrently or redundantly if cleanup raises an exception.
|
||||
GC.SuppressFinalize(this);
|
||||
IntPtr ctx;
|
||||
// Keep a local reference to the error handler delegate to ensure it stays
|
||||
// alive throughout Z3_del_context. Setting m_n_err_handler = null releases
|
||||
// the field reference; without the local variable the GC could collect the
|
||||
// delegate before the native destructor finishes using the handler.
|
||||
Native.Z3_error_handler errHandler;
|
||||
lock (this)
|
||||
{
|
||||
ctx = m_ctx;
|
||||
errHandler = m_n_err_handler;
|
||||
m_n_err_handler = null;
|
||||
m_ctx = IntPtr.Zero;
|
||||
}
|
||||
if (!is_external)
|
||||
Native.Z3_del_context(ctx);
|
||||
// ctx is non-zero only for the thread that wins the lock and zeros m_ctx,
|
||||
// preventing double-free when Dispose() is called concurrently.
|
||||
if (ctx != IntPtr.Zero)
|
||||
{
|
||||
if (!is_external)
|
||||
{
|
||||
Native.Z3_del_context(ctx);
|
||||
GC.KeepAlive(errHandler);
|
||||
}
|
||||
if (m_memPressureAdded)
|
||||
{
|
||||
GC.RemoveMemoryPressure(NativeMemoryPressureEstimate);
|
||||
m_memPressureAdded = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
53
src/api/dotnet/FiniteSetSort.cs
Normal file
53
src/api/dotnet/FiniteSetSort.cs
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
/*++
|
||||
Copyright (c) 2024 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
FiniteSetSort.cs
|
||||
|
||||
Abstract:
|
||||
|
||||
Z3 Managed API: Finite Set Sorts
|
||||
|
||||
Author:
|
||||
|
||||
GitHub Copilot
|
||||
|
||||
Notes:
|
||||
|
||||
--*/
|
||||
|
||||
using System.Diagnostics;
|
||||
using System;
|
||||
|
||||
namespace Microsoft.Z3
|
||||
{
|
||||
/// <summary>
|
||||
/// Finite set sorts.
|
||||
/// </summary>
|
||||
public class FiniteSetSort : Sort
|
||||
{
|
||||
#region Internal
|
||||
internal FiniteSetSort(Context ctx, IntPtr obj)
|
||||
: base(ctx, obj)
|
||||
{
|
||||
Debug.Assert(ctx != null);
|
||||
}
|
||||
|
||||
internal FiniteSetSort(Context ctx, Sort elemSort)
|
||||
: base(ctx, Native.Z3_mk_finite_set_sort(ctx.nCtx, elemSort.NativeObject))
|
||||
{
|
||||
Debug.Assert(ctx != null);
|
||||
Debug.Assert(elemSort != null);
|
||||
}
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Get the element sort (basis) of this finite set sort.
|
||||
/// </summary>
|
||||
public Sort Basis
|
||||
{
|
||||
get { return Sort.Create(Context, Native.Z3_get_finite_set_sort_basis(Context.nCtx, NativeObject)); }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -60,6 +60,7 @@
|
|||
<Warn>4</Warn>
|
||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||
<DocumentationFile>$(OutputPath)\Microsoft.Z3.xml</DocumentationFile>
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
</PropertyGroup>
|
||||
|
||||
<!-- Compilation items -->
|
||||
|
|
@ -84,10 +85,10 @@ ${Z3_DOTNET_COMPILE_ITEMS}
|
|||
|
||||
<!-- TODO we may want to pack x64 and x86 native assemblies into a single nupkg -->
|
||||
|
||||
<!-- Native binaries x64 -->
|
||||
<!-- Native binaries x64/arm64 -->
|
||||
<ItemGroup Condition="'$(Platform)' != 'x86'">
|
||||
<Content Include="${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/$(_DN_CMAKE_CONFIG)/libz3.dll" Condition="Exists('${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/$(_DN_CMAKE_CONFIG)/libz3.dll')">
|
||||
<PackagePath>runtimes\win-x64\native</PackagePath>
|
||||
<Content Include="${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/libz3.dll" Condition="Exists('${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/libz3.dll')">
|
||||
<PackagePath>runtimes\${Z3_DOTNET_WIN_RID}\native</PackagePath>
|
||||
</Content>
|
||||
<Content Include="${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/libz3.so" Condition="Exists('${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/libz3.so')">
|
||||
<PackagePath>runtimes\linux-x64\native</PackagePath>
|
||||
|
|
@ -99,7 +100,7 @@ ${Z3_DOTNET_COMPILE_ITEMS}
|
|||
|
||||
<!-- Native binaries for x86; currently only Windows is supported. -->
|
||||
<ItemGroup Condition="'$(Platform)' == 'x86'">
|
||||
<Content Include="${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/$(_DN_CMAKE_CONFIG)/libz3.dll" Condition="Exists('${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/$(_DN_CMAKE_CONFIG)/libz3.dll')">
|
||||
<Content Include="${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/libz3.dll" Condition="Exists('${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/libz3.dll')">
|
||||
<PackagePath>runtimes\win-x86\native</PackagePath>
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
|
|
|
|||
|
|
@ -9,7 +9,8 @@
|
|||
|
||||
<!-- Probe the package root path -->
|
||||
<Z3_PACKAGE_PATH Condition="('$(Z3_PACKAGE_PATH)' == '')">$(MSBuildThisFileDirectory)..\</Z3_PACKAGE_PATH>
|
||||
<Z3_NATIVE_LIB_PATH Condition="'$(IsWindows)' == 'true' and '$(Platform)' != 'x86'">$(Z3_PACKAGE_PATH)runtimes\win-x64\native\libz3.dll</Z3_NATIVE_LIB_PATH>
|
||||
<Z3_NATIVE_LIB_PATH Condition="'$(IsWindows)' == 'true' and '$(Platform)' == 'arm64'">$(Z3_PACKAGE_PATH)runtimes\win-arm64\native\libz3.dll</Z3_NATIVE_LIB_PATH>
|
||||
<Z3_NATIVE_LIB_PATH Condition="'$(IsWindows)' == 'true' and '$(Platform)' != 'x86' and '$(Platform)' != 'arm64'">$(Z3_PACKAGE_PATH)runtimes\win-x64\native\libz3.dll</Z3_NATIVE_LIB_PATH>
|
||||
<Z3_NATIVE_LIB_PATH Condition="'$(IsWindows)' == 'true' and '$(Platform)' == 'x86'">$(Z3_PACKAGE_PATH)runtimes\win-x86\native\libz3.dll</Z3_NATIVE_LIB_PATH>
|
||||
<Z3_NATIVE_LIB_PATH Condition="'$(IsLinux)' == 'true'">$(Z3_PACKAGE_PATH)runtimes\linux-x64\native\libz3.so</Z3_NATIVE_LIB_PATH>
|
||||
</PropertyGroup>
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
|
||||
<ItemGroup Condition="!$(TargetFramework.Contains('netstandard')) and !$(TargetFramework.Contains('netcoreapp'))">
|
||||
<ItemGroup Condition="!$(TargetFramework.Contains('netstandard')) and !$(TargetFramework.Contains('netcoreapp')) and !$(TargetFramework.Contains('.'))">
|
||||
<None Include="$(Z3_NATIVE_LIB_PATH)">
|
||||
<Link>%(RecursiveDir)%(FileName)%(Extension)</Link>
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
|
|
|
|||
|
|
@ -1334,6 +1334,11 @@ namespace Microsoft.Z3
|
|||
internal Native.Z3_error_handler m_n_err_handler = null;
|
||||
internal IntPtr nCtx { get { return m_ctx; } }
|
||||
|
||||
// Estimated native memory used per context, for GC memory pressure hints.
|
||||
// The value is a conservative lower bound; actual usage may exceed this.
|
||||
private const long NativeMemoryPressureEstimate = 8 * 1024 * 1024; // 8 MB
|
||||
private bool m_memPressureAdded = false;
|
||||
|
||||
internal void NativeErrorHandler(IntPtr ctx, Z3_error_code errorCode)
|
||||
{
|
||||
// Do-nothing error handler. The wrappers in Z3.Native will throw exceptions upon errors.
|
||||
|
|
@ -1344,8 +1349,8 @@ namespace Microsoft.Z3
|
|||
PrintMode = Z3_ast_print_mode.Z3_PRINT_SMTLIB2_COMPLIANT;
|
||||
m_n_err_handler = new Native.Z3_error_handler(NativeErrorHandler); // keep reference so it doesn't get collected.
|
||||
Native.Z3_set_error_handler(m_ctx, m_n_err_handler);
|
||||
|
||||
GC.SuppressFinalize(this);
|
||||
GC.AddMemoryPressure(NativeMemoryPressureEstimate);
|
||||
m_memPressureAdded = true;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
|
@ -1365,20 +1370,39 @@ namespace Microsoft.Z3
|
|||
|
||||
#region Dispose
|
||||
|
||||
/// <summary>
|
||||
/// Finalizer.
|
||||
/// </summary>
|
||||
~NativeContext()
|
||||
{
|
||||
Dispose();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Disposes of the context.
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
if (m_ctx != IntPtr.Zero)
|
||||
IntPtr ctx = System.Threading.Interlocked.Exchange(ref m_ctx, IntPtr.Zero);
|
||||
if (ctx != IntPtr.Zero)
|
||||
{
|
||||
// Suppress the finalizer before performing cleanup so that it cannot
|
||||
// run concurrently or redundantly if cleanup raises an exception.
|
||||
GC.SuppressFinalize(this);
|
||||
// Keep a local reference to the error handler delegate to ensure it stays
|
||||
// alive throughout Z3_del_context. Setting m_n_err_handler = null releases
|
||||
// the field reference; without the local variable the GC could collect the
|
||||
// delegate before the native destructor finishes using the handler.
|
||||
var errHandler = m_n_err_handler;
|
||||
m_n_err_handler = null;
|
||||
IntPtr ctx = m_ctx;
|
||||
m_ctx = IntPtr.Zero;
|
||||
Native.Z3_del_context(ctx);
|
||||
GC.KeepAlive(errHandler);
|
||||
if (m_memPressureAdded)
|
||||
{
|
||||
GC.RemoveMemoryPressure(NativeMemoryPressureEstimate);
|
||||
m_memPressureAdded = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
GC.ReRegisterForFinalize(this);
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
|
|
|||
|
|
@ -437,6 +437,16 @@ namespace Microsoft.Z3
|
|||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Set an initial value for a variable to guide the optimizer's search heuristics.
|
||||
/// </summary>
|
||||
public void SetInitialValue(Expr var, Expr value)
|
||||
{
|
||||
Debug.Assert(var != null);
|
||||
Debug.Assert(value != null);
|
||||
Native.Z3_optimize_set_initial_value(Context.nCtx, NativeObject, var.NativeObject, value.NativeObject);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Optimize statistics.
|
||||
/// </summary>
|
||||
|
|
|
|||
|
|
@ -650,6 +650,17 @@ namespace Microsoft.Z3
|
|||
return Context.BenchmarkToSmtlibString("", "", status, "", assumptions, formula);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Convert the solver's Boolean formula to DIMACS CNF format.
|
||||
/// </summary>
|
||||
/// <param name="includeNames">If true, include variable names in the DIMACS output. Default is true.</param>
|
||||
/// <returns>A string containing the DIMACS CNF representation.</returns>
|
||||
public string ToDimacs(bool includeNames = true)
|
||||
{
|
||||
byte includeNamesByte = includeNames ? (byte)1 : (byte)0;
|
||||
return Native.Z3_solver_to_dimacs_string(Context.nCtx, NativeObject, includeNamesByte);
|
||||
}
|
||||
|
||||
#region Internal
|
||||
internal Solver(Context ctx, IntPtr obj)
|
||||
: base(ctx, obj)
|
||||
|
|
|
|||
|
|
@ -310,7 +310,7 @@ go run basic_example.go
|
|||
|
||||
## Memory Management
|
||||
|
||||
The Go bindings use `runtime.SetFinalizer` to automatically manage Z3 reference counts. You don't need to manually call inc_ref/dec_ref. However, be aware that finalizers run during garbage collection, so resources may not be freed immediately.
|
||||
The Go bindings use `runtime.SetFinalizer` to automatically manage Z3 reference counts. You don't need to manually call inc_ref/dec_ref. However, be aware that finalizers run during garbage collection, so resources may not be freed immediately. The bindings enable `Z3_enable_concurrent_dec_ref` when creating contexts so finalizer-driven decref operations are safe with concurrent GC.
|
||||
|
||||
## Thread Safety
|
||||
|
||||
|
|
|
|||
|
|
@ -124,3 +124,33 @@ func (c *Context) MkGt(lhs, rhs *Expr) *Expr {
|
|||
func (c *Context) MkGe(lhs, rhs *Expr) *Expr {
|
||||
return newExpr(c, C.Z3_mk_ge(c.ptr, lhs.ptr, rhs.ptr))
|
||||
}
|
||||
|
||||
// MkPower creates an exponentiation expression (base^exp).
|
||||
func (c *Context) MkPower(base, exp *Expr) *Expr {
|
||||
return newExpr(c, C.Z3_mk_power(c.ptr, base.ptr, exp.ptr))
|
||||
}
|
||||
|
||||
// MkAbs creates an absolute value expression.
|
||||
func (c *Context) MkAbs(arg *Expr) *Expr {
|
||||
return newExpr(c, C.Z3_mk_abs(c.ptr, arg.ptr))
|
||||
}
|
||||
|
||||
// MkInt2Real coerces an integer expression to a real.
|
||||
func (c *Context) MkInt2Real(arg *Expr) *Expr {
|
||||
return newExpr(c, C.Z3_mk_int2real(c.ptr, arg.ptr))
|
||||
}
|
||||
|
||||
// MkReal2Int converts a real expression to an integer (floor).
|
||||
func (c *Context) MkReal2Int(arg *Expr) *Expr {
|
||||
return newExpr(c, C.Z3_mk_real2int(c.ptr, arg.ptr))
|
||||
}
|
||||
|
||||
// MkIsInt creates a predicate that checks whether a real expression is an integer.
|
||||
func (c *Context) MkIsInt(arg *Expr) *Expr {
|
||||
return newExpr(c, C.Z3_mk_is_int(c.ptr, arg.ptr))
|
||||
}
|
||||
|
||||
// MkDivides creates an integer divisibility predicate (t1 divides t2).
|
||||
func (c *Context) MkDivides(t1, t2 *Expr) *Expr {
|
||||
return newExpr(c, C.Z3_mk_divides(c.ptr, t1.ptr, t2.ptr))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,3 +27,60 @@ func (c *Context) MkStore(array, index, value *Expr) *Expr {
|
|||
func (c *Context) MkConstArray(sort *Sort, value *Expr) *Expr {
|
||||
return newExpr(c, C.Z3_mk_const_array(c.ptr, sort.ptr, value.ptr))
|
||||
}
|
||||
|
||||
// MkSelectN creates a multi-index array read (select) operation.
|
||||
func (c *Context) MkSelectN(array *Expr, indices []*Expr) *Expr {
|
||||
idxs := make([]C.Z3_ast, len(indices))
|
||||
for i, idx := range indices {
|
||||
idxs[i] = idx.ptr
|
||||
}
|
||||
var idxsPtr *C.Z3_ast
|
||||
if len(idxs) > 0 {
|
||||
idxsPtr = &idxs[0]
|
||||
}
|
||||
return newExpr(c, C.Z3_mk_select_n(c.ptr, array.ptr, C.uint(len(idxs)), idxsPtr))
|
||||
}
|
||||
|
||||
// MkStoreN creates a multi-index array write (store) operation.
|
||||
func (c *Context) MkStoreN(array *Expr, indices []*Expr, value *Expr) *Expr {
|
||||
idxs := make([]C.Z3_ast, len(indices))
|
||||
for i, idx := range indices {
|
||||
idxs[i] = idx.ptr
|
||||
}
|
||||
var idxsPtr *C.Z3_ast
|
||||
if len(idxs) > 0 {
|
||||
idxsPtr = &idxs[0]
|
||||
}
|
||||
return newExpr(c, C.Z3_mk_store_n(c.ptr, array.ptr, C.uint(len(idxs)), idxsPtr, value.ptr))
|
||||
}
|
||||
|
||||
// MkArrayDefault returns the default value of an array.
|
||||
func (c *Context) MkArrayDefault(array *Expr) *Expr {
|
||||
return newExpr(c, C.Z3_mk_array_default(c.ptr, array.ptr))
|
||||
}
|
||||
|
||||
// MkArrayExt returns the extensionality witness for two arrays.
|
||||
// Two arrays are equal if and only if they are equal on the index returned by MkArrayExt.
|
||||
func (c *Context) MkArrayExt(a1, a2 *Expr) *Expr {
|
||||
return newExpr(c, C.Z3_mk_array_ext(c.ptr, a1.ptr, a2.ptr))
|
||||
}
|
||||
|
||||
// MkAsArray creates an array from a function declaration.
|
||||
// The resulting array maps each input to the output of the function.
|
||||
func (c *Context) MkAsArray(f *FuncDecl) *Expr {
|
||||
return newExpr(c, C.Z3_mk_as_array(c.ptr, f.ptr))
|
||||
}
|
||||
|
||||
// MkMap applies a function to the elements of one or more arrays, returning a new array.
|
||||
// The function f is applied element-wise to the given arrays.
|
||||
func (c *Context) MkMap(f *FuncDecl, arrays ...*Expr) *Expr {
|
||||
cArrays := make([]C.Z3_ast, len(arrays))
|
||||
for i, a := range arrays {
|
||||
cArrays[i] = a.ptr
|
||||
}
|
||||
var cArraysPtr *C.Z3_ast
|
||||
if len(cArrays) > 0 {
|
||||
cArraysPtr = &cArrays[0]
|
||||
}
|
||||
return newExpr(c, C.Z3_mk_map(c.ptr, f.ptr, C.uint(len(arrays)), cArraysPtr))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -158,3 +158,88 @@ func (c *Context) MkSignExt(i uint, expr *Expr) *Expr {
|
|||
func (c *Context) MkZeroExt(i uint, expr *Expr) *Expr {
|
||||
return newExpr(c, C.Z3_mk_zero_ext(c.ptr, C.uint(i), expr.ptr))
|
||||
}
|
||||
|
||||
// MkBVRotateLeft rotates the bits of t to the left by i positions.
|
||||
func (c *Context) MkBVRotateLeft(i uint, t *Expr) *Expr {
|
||||
return newExpr(c, C.Z3_mk_rotate_left(c.ptr, C.uint(i), t.ptr))
|
||||
}
|
||||
|
||||
// MkBVRotateRight rotates the bits of t to the right by i positions.
|
||||
func (c *Context) MkBVRotateRight(i uint, t *Expr) *Expr {
|
||||
return newExpr(c, C.Z3_mk_rotate_right(c.ptr, C.uint(i), t.ptr))
|
||||
}
|
||||
|
||||
// MkRepeat repeats the given bit-vector t a total of i times.
|
||||
func (c *Context) MkRepeat(i uint, t *Expr) *Expr {
|
||||
return newExpr(c, C.Z3_mk_repeat(c.ptr, C.uint(i), t.ptr))
|
||||
}
|
||||
|
||||
// MkBVAddNoOverflow creates a predicate that checks that the bit-wise addition
|
||||
// of t1 and t2 does not overflow. If isSigned is true, checks for signed overflow.
|
||||
func (c *Context) MkBVAddNoOverflow(t1, t2 *Expr, isSigned bool) *Expr {
|
||||
return newExpr(c, C.Z3_mk_bvadd_no_overflow(c.ptr, t1.ptr, t2.ptr, C.bool(isSigned)))
|
||||
}
|
||||
|
||||
// MkBVAddNoUnderflow creates a predicate that checks that the bit-wise signed addition
|
||||
// of t1 and t2 does not underflow.
|
||||
func (c *Context) MkBVAddNoUnderflow(t1, t2 *Expr) *Expr {
|
||||
return newExpr(c, C.Z3_mk_bvadd_no_underflow(c.ptr, t1.ptr, t2.ptr))
|
||||
}
|
||||
|
||||
// MkBVSubNoOverflow creates a predicate that checks that the bit-wise signed subtraction
|
||||
// of t1 and t2 does not overflow.
|
||||
func (c *Context) MkBVSubNoOverflow(t1, t2 *Expr) *Expr {
|
||||
return newExpr(c, C.Z3_mk_bvsub_no_overflow(c.ptr, t1.ptr, t2.ptr))
|
||||
}
|
||||
|
||||
// MkBVSubNoUnderflow creates a predicate that checks that the bit-wise subtraction
|
||||
// of t1 and t2 does not underflow. If isSigned is true, checks for signed underflow.
|
||||
func (c *Context) MkBVSubNoUnderflow(t1, t2 *Expr, isSigned bool) *Expr {
|
||||
return newExpr(c, C.Z3_mk_bvsub_no_underflow(c.ptr, t1.ptr, t2.ptr, C.bool(isSigned)))
|
||||
}
|
||||
|
||||
// MkBVSdivNoOverflow creates a predicate that checks that the bit-wise signed division
|
||||
// of t1 and t2 does not overflow.
|
||||
func (c *Context) MkBVSdivNoOverflow(t1, t2 *Expr) *Expr {
|
||||
return newExpr(c, C.Z3_mk_bvsdiv_no_overflow(c.ptr, t1.ptr, t2.ptr))
|
||||
}
|
||||
|
||||
// MkBVNegNoOverflow creates a predicate that checks that bit-wise negation does not overflow
|
||||
// when t1 is interpreted as a signed bit-vector.
|
||||
func (c *Context) MkBVNegNoOverflow(t1 *Expr) *Expr {
|
||||
return newExpr(c, C.Z3_mk_bvneg_no_overflow(c.ptr, t1.ptr))
|
||||
}
|
||||
|
||||
// MkBVMulNoOverflow creates a predicate that checks that the bit-wise multiplication
|
||||
// of t1 and t2 does not overflow. If isSigned is true, checks for signed overflow.
|
||||
func (c *Context) MkBVMulNoOverflow(t1, t2 *Expr, isSigned bool) *Expr {
|
||||
return newExpr(c, C.Z3_mk_bvmul_no_overflow(c.ptr, t1.ptr, t2.ptr, C.bool(isSigned)))
|
||||
}
|
||||
|
||||
// MkBVMulNoUnderflow creates a predicate that checks that the bit-wise signed multiplication
|
||||
// of t1 and t2 does not underflow.
|
||||
func (c *Context) MkBVMulNoUnderflow(t1, t2 *Expr) *Expr {
|
||||
return newExpr(c, C.Z3_mk_bvmul_no_underflow(c.ptr, t1.ptr, t2.ptr))
|
||||
}
|
||||
|
||||
// MkBVRedAnd computes the bitwise AND reduction of a bit-vector, returning a 1-bit vector.
|
||||
func (c *Context) MkBVRedAnd(t *Expr) *Expr {
|
||||
return newExpr(c, C.Z3_mk_bvredand(c.ptr, t.ptr))
|
||||
}
|
||||
|
||||
// MkBVRedOr computes the bitwise OR reduction of a bit-vector, returning a 1-bit vector.
|
||||
func (c *Context) MkBVRedOr(t *Expr) *Expr {
|
||||
return newExpr(c, C.Z3_mk_bvredor(c.ptr, t.ptr))
|
||||
}
|
||||
|
||||
// MkBVExtRotateLeft rotates the bits of t1 to the left by the number of bits given by t2.
|
||||
// Both t1 and t2 must be bit-vectors of the same width.
|
||||
func (c *Context) MkBVExtRotateLeft(t1, t2 *Expr) *Expr {
|
||||
return newExpr(c, C.Z3_mk_ext_rotate_left(c.ptr, t1.ptr, t2.ptr))
|
||||
}
|
||||
|
||||
// MkBVExtRotateRight rotates the bits of t1 to the right by the number of bits given by t2.
|
||||
// Both t1 and t2 must be bit-vectors of the same width.
|
||||
func (c *Context) MkBVExtRotateRight(t1, t2 *Expr) *Expr {
|
||||
return newExpr(c, C.Z3_mk_ext_rotate_right(c.ptr, t1.ptr, t2.ptr))
|
||||
}
|
||||
|
|
|
|||
43
src/api/go/char.go
Normal file
43
src/api/go/char.go
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
package z3
|
||||
|
||||
/*
|
||||
#include "z3.h"
|
||||
*/
|
||||
import "C"
|
||||
|
||||
// Char operations
|
||||
|
||||
// MkCharSort creates the character sort (Unicode characters).
|
||||
func (c *Context) MkCharSort() *Sort {
|
||||
return newSort(c, C.Z3_mk_char_sort(c.ptr))
|
||||
}
|
||||
|
||||
// MkChar creates a character literal from a Unicode code point.
|
||||
func (c *Context) MkChar(ch uint) *Expr {
|
||||
return newExpr(c, C.Z3_mk_char(c.ptr, C.uint(ch)))
|
||||
}
|
||||
|
||||
// MkCharLe creates a character less-than-or-equal predicate (ch1 ≤ ch2).
|
||||
func (c *Context) MkCharLe(ch1, ch2 *Expr) *Expr {
|
||||
return newExpr(c, C.Z3_mk_char_le(c.ptr, ch1.ptr, ch2.ptr))
|
||||
}
|
||||
|
||||
// MkCharToInt converts a character to its integer (Unicode code point) value.
|
||||
func (c *Context) MkCharToInt(ch *Expr) *Expr {
|
||||
return newExpr(c, C.Z3_mk_char_to_int(c.ptr, ch.ptr))
|
||||
}
|
||||
|
||||
// MkCharToBV converts a character to a bit-vector.
|
||||
func (c *Context) MkCharToBV(ch *Expr) *Expr {
|
||||
return newExpr(c, C.Z3_mk_char_to_bv(c.ptr, ch.ptr))
|
||||
}
|
||||
|
||||
// MkCharFromBV converts a bit-vector to a character.
|
||||
func (c *Context) MkCharFromBV(bv *Expr) *Expr {
|
||||
return newExpr(c, C.Z3_mk_char_from_bv(c.ptr, bv.ptr))
|
||||
}
|
||||
|
||||
// MkCharIsDigit creates a predicate that is true if the character is a decimal digit.
|
||||
func (c *Context) MkCharIsDigit(ch *Expr) *Expr {
|
||||
return newExpr(c, C.Z3_mk_char_is_digit(c.ptr, ch.ptr))
|
||||
}
|
||||
|
|
@ -127,6 +127,41 @@ func (c *Context) MkDatatypeSort(name string, constructors []*Constructor) *Sort
|
|||
return newSort(c, C.Z3_mk_datatype(c.ptr, sym.ptr, C.uint(numCons), &cons[0]))
|
||||
}
|
||||
|
||||
// MkPolymorphicDatatypeSort creates a polymorphic datatype sort with explicit type parameters.
|
||||
// typeParams should be sorts created with MkTypeVariable.
|
||||
// Self-recursive field sorts should be passed as nil; use the fieldSortRefs parameter in
|
||||
// MkConstructor to indicate the recursive reference by index.
|
||||
func (c *Context) MkPolymorphicDatatypeSort(name string, typeParams []*Sort, constructors []*Constructor) *Sort {
|
||||
sym := c.MkStringSymbol(name)
|
||||
|
||||
numParams := len(typeParams)
|
||||
numCons := len(constructors)
|
||||
|
||||
var paramPtr *C.Z3_sort
|
||||
if numParams > 0 {
|
||||
paramPtrs := make([]C.Z3_sort, numParams)
|
||||
for i, p := range typeParams {
|
||||
paramPtrs[i] = p.ptr
|
||||
}
|
||||
paramPtr = ¶mPtrs[0]
|
||||
}
|
||||
|
||||
var consPtr *C.Z3_constructor
|
||||
if numCons > 0 {
|
||||
consPtrs := make([]C.Z3_constructor, numCons)
|
||||
for i, cons := range constructors {
|
||||
consPtrs[i] = cons.ptr
|
||||
}
|
||||
consPtr = &consPtrs[0]
|
||||
}
|
||||
|
||||
return newSort(c, C.Z3_mk_polymorphic_datatype(
|
||||
c.ptr, sym.ptr,
|
||||
C.uint(numParams), paramPtr,
|
||||
C.uint(numCons), consPtr,
|
||||
))
|
||||
}
|
||||
|
||||
// MkDatatypeSorts creates multiple mutually recursive datatype sorts.
|
||||
func (c *Context) MkDatatypeSorts(names []string, constructorLists [][]*Constructor) []*Sort {
|
||||
numTypes := uint(len(names))
|
||||
|
|
|
|||
78
src/api/go/finiteset.go
Normal file
78
src/api/go/finiteset.go
Normal file
|
|
@ -0,0 +1,78 @@
|
|||
package z3
|
||||
|
||||
/*
|
||||
#include "z3.h"
|
||||
*/
|
||||
import "C"
|
||||
|
||||
// Finite set operations
|
||||
|
||||
// MkFiniteSetSort creates a finite set sort with the given element sort.
|
||||
func (c *Context) MkFiniteSetSort(elemSort *Sort) *Sort {
|
||||
return newSort(c, C.Z3_mk_finite_set_sort(c.ptr, elemSort.ptr))
|
||||
}
|
||||
|
||||
// IsFiniteSetSort returns true if the given sort is a finite set sort.
|
||||
func (c *Context) IsFiniteSetSort(s *Sort) bool {
|
||||
return bool(C.Z3_is_finite_set_sort(c.ptr, s.ptr))
|
||||
}
|
||||
|
||||
// GetFiniteSetSortBasis returns the element sort of a finite set sort.
|
||||
func (c *Context) GetFiniteSetSortBasis(s *Sort) *Sort {
|
||||
return newSort(c, C.Z3_get_finite_set_sort_basis(c.ptr, s.ptr))
|
||||
}
|
||||
|
||||
// MkFiniteSetEmpty creates an empty finite set of the given sort.
|
||||
func (c *Context) MkFiniteSetEmpty(setSort *Sort) *Expr {
|
||||
return newExpr(c, C.Z3_mk_finite_set_empty(c.ptr, setSort.ptr))
|
||||
}
|
||||
|
||||
// MkFiniteSetSingleton creates a singleton finite set containing the given element.
|
||||
func (c *Context) MkFiniteSetSingleton(elem *Expr) *Expr {
|
||||
return newExpr(c, C.Z3_mk_finite_set_singleton(c.ptr, elem.ptr))
|
||||
}
|
||||
|
||||
// MkFiniteSetUnion creates the union of two finite sets.
|
||||
func (c *Context) MkFiniteSetUnion(s1, s2 *Expr) *Expr {
|
||||
return newExpr(c, C.Z3_mk_finite_set_union(c.ptr, s1.ptr, s2.ptr))
|
||||
}
|
||||
|
||||
// MkFiniteSetIntersect creates the intersection of two finite sets.
|
||||
func (c *Context) MkFiniteSetIntersect(s1, s2 *Expr) *Expr {
|
||||
return newExpr(c, C.Z3_mk_finite_set_intersect(c.ptr, s1.ptr, s2.ptr))
|
||||
}
|
||||
|
||||
// MkFiniteSetDifference creates the set difference of two finite sets (s1 \ s2).
|
||||
func (c *Context) MkFiniteSetDifference(s1, s2 *Expr) *Expr {
|
||||
return newExpr(c, C.Z3_mk_finite_set_difference(c.ptr, s1.ptr, s2.ptr))
|
||||
}
|
||||
|
||||
// MkFiniteSetMember creates a membership predicate: elem ∈ set.
|
||||
func (c *Context) MkFiniteSetMember(elem, set *Expr) *Expr {
|
||||
return newExpr(c, C.Z3_mk_finite_set_member(c.ptr, elem.ptr, set.ptr))
|
||||
}
|
||||
|
||||
// MkFiniteSetSize creates an expression for the cardinality of a finite set.
|
||||
func (c *Context) MkFiniteSetSize(set *Expr) *Expr {
|
||||
return newExpr(c, C.Z3_mk_finite_set_size(c.ptr, set.ptr))
|
||||
}
|
||||
|
||||
// MkFiniteSetSubset creates a subset predicate: s1 ⊆ s2.
|
||||
func (c *Context) MkFiniteSetSubset(s1, s2 *Expr) *Expr {
|
||||
return newExpr(c, C.Z3_mk_finite_set_subset(c.ptr, s1.ptr, s2.ptr))
|
||||
}
|
||||
|
||||
// MkFiniteSetMap applies a function to all elements of a finite set.
|
||||
func (c *Context) MkFiniteSetMap(f, set *Expr) *Expr {
|
||||
return newExpr(c, C.Z3_mk_finite_set_map(c.ptr, f.ptr, set.ptr))
|
||||
}
|
||||
|
||||
// MkFiniteSetFilter filters a finite set using a predicate function.
|
||||
func (c *Context) MkFiniteSetFilter(f, set *Expr) *Expr {
|
||||
return newExpr(c, C.Z3_mk_finite_set_filter(c.ptr, f.ptr, set.ptr))
|
||||
}
|
||||
|
||||
// MkFiniteSetRange creates a finite set of integers in the range [low, high].
|
||||
func (c *Context) MkFiniteSetRange(low, high *Expr) *Expr {
|
||||
return newExpr(c, C.Z3_mk_finite_set_range(c.ptr, low.ptr, high.ptr))
|
||||
}
|
||||
|
|
@ -218,6 +218,59 @@ func (f *Fixedpoint) FromFile(filename string) {
|
|||
C.Z3_fixedpoint_from_file(f.ctx.ptr, f.ptr, cstr)
|
||||
}
|
||||
|
||||
// QueryFromLvl poses a query against the asserted rules at the given level.
|
||||
// This is a Spacer-specific function.
|
||||
func (f *Fixedpoint) QueryFromLvl(query *Expr, lvl uint) Status {
|
||||
result := C.Z3_fixedpoint_query_from_lvl(f.ctx.ptr, f.ptr, query.ptr, C.uint(lvl))
|
||||
switch result {
|
||||
case C.Z3_L_TRUE:
|
||||
return Satisfiable
|
||||
case C.Z3_L_FALSE:
|
||||
return Unsatisfiable
|
||||
default:
|
||||
return Unknown
|
||||
}
|
||||
}
|
||||
|
||||
// GetGroundSatAnswer retrieves a bottom-up sequence of ground facts.
|
||||
// The previous call to Query or QueryFromLvl must have returned Satisfiable.
|
||||
// This is a Spacer-specific function.
|
||||
func (f *Fixedpoint) GetGroundSatAnswer() *Expr {
|
||||
ptr := C.Z3_fixedpoint_get_ground_sat_answer(f.ctx.ptr, f.ptr)
|
||||
if ptr == nil {
|
||||
return nil
|
||||
}
|
||||
return newExpr(f.ctx, ptr)
|
||||
}
|
||||
|
||||
// GetRulesAlongTrace returns the list of rules along the counterexample trace.
|
||||
// This is a Spacer-specific function.
|
||||
func (f *Fixedpoint) GetRulesAlongTrace() *ASTVector {
|
||||
return newASTVector(f.ctx, C.Z3_fixedpoint_get_rules_along_trace(f.ctx.ptr, f.ptr))
|
||||
}
|
||||
|
||||
// GetRuleNamesAlongTrace returns the list of rule names along the counterexample trace.
|
||||
// This is a Spacer-specific function.
|
||||
func (f *Fixedpoint) GetRuleNamesAlongTrace() *Symbol {
|
||||
return newSymbol(f.ctx, C.Z3_fixedpoint_get_rule_names_along_trace(f.ctx.ptr, f.ptr))
|
||||
}
|
||||
|
||||
// AddInvariant adds an assumed invariant for the predicate pred.
|
||||
// This is a Spacer-specific function.
|
||||
func (f *Fixedpoint) AddInvariant(pred *FuncDecl, property *Expr) {
|
||||
C.Z3_fixedpoint_add_invariant(f.ctx.ptr, f.ptr, pred.ptr, property.ptr)
|
||||
}
|
||||
|
||||
// GetReachable retrieves the reachable states of a predicate.
|
||||
// This is a Spacer-specific function.
|
||||
func (f *Fixedpoint) GetReachable(pred *FuncDecl) *Expr {
|
||||
ptr := C.Z3_fixedpoint_get_reachable(f.ctx.ptr, f.ptr, pred.ptr)
|
||||
if ptr == nil {
|
||||
return nil
|
||||
}
|
||||
return newExpr(f.ctx, ptr)
|
||||
}
|
||||
|
||||
// Statistics represents statistics for Z3 solvers
|
||||
type Statistics struct {
|
||||
ctx *Context
|
||||
|
|
|
|||
145
src/api/go/fp.go
145
src/api/go/fp.go
|
|
@ -137,3 +137,148 @@ func (c *Context) MkFPIsInf(expr *Expr) *Expr {
|
|||
func (c *Context) MkFPIsZero(expr *Expr) *Expr {
|
||||
return newExpr(c, C.Z3_mk_fpa_is_zero(c.ptr, expr.ptr))
|
||||
}
|
||||
|
||||
// MkFPIsNormal creates a predicate checking if a floating-point number is normal.
|
||||
func (c *Context) MkFPIsNormal(expr *Expr) *Expr {
|
||||
return newExpr(c, C.Z3_mk_fpa_is_normal(c.ptr, expr.ptr))
|
||||
}
|
||||
|
||||
// MkFPIsSubnormal creates a predicate checking if a floating-point number is subnormal.
|
||||
func (c *Context) MkFPIsSubnormal(expr *Expr) *Expr {
|
||||
return newExpr(c, C.Z3_mk_fpa_is_subnormal(c.ptr, expr.ptr))
|
||||
}
|
||||
|
||||
// MkFPIsNegative creates a predicate checking if a floating-point number is negative.
|
||||
func (c *Context) MkFPIsNegative(expr *Expr) *Expr {
|
||||
return newExpr(c, C.Z3_mk_fpa_is_negative(c.ptr, expr.ptr))
|
||||
}
|
||||
|
||||
// MkFPIsPositive creates a predicate checking if a floating-point number is positive.
|
||||
func (c *Context) MkFPIsPositive(expr *Expr) *Expr {
|
||||
return newExpr(c, C.Z3_mk_fpa_is_positive(c.ptr, expr.ptr))
|
||||
}
|
||||
|
||||
// MkFPToIEEEBV converts a floating-point number to its IEEE 754 bit-vector representation.
|
||||
func (c *Context) MkFPToIEEEBV(expr *Expr) *Expr {
|
||||
return newExpr(c, C.Z3_mk_fpa_to_ieee_bv(c.ptr, expr.ptr))
|
||||
}
|
||||
|
||||
// MkFPToReal converts a floating-point number to a real number.
|
||||
func (c *Context) MkFPToReal(expr *Expr) *Expr {
|
||||
return newExpr(c, C.Z3_mk_fpa_to_real(c.ptr, expr.ptr))
|
||||
}
|
||||
|
||||
// MkFPRNE creates the round-nearest-ties-to-even rounding mode.
|
||||
func (c *Context) MkFPRNE() *Expr {
|
||||
return newExpr(c, C.Z3_mk_fpa_rne(c.ptr))
|
||||
}
|
||||
|
||||
// MkFPRNA creates the round-nearest-ties-to-away rounding mode.
|
||||
func (c *Context) MkFPRNA() *Expr {
|
||||
return newExpr(c, C.Z3_mk_fpa_rna(c.ptr))
|
||||
}
|
||||
|
||||
// MkFPRTP creates the round-toward-positive rounding mode.
|
||||
func (c *Context) MkFPRTP() *Expr {
|
||||
return newExpr(c, C.Z3_mk_fpa_rtp(c.ptr))
|
||||
}
|
||||
|
||||
// MkFPRTN creates the round-toward-negative rounding mode.
|
||||
func (c *Context) MkFPRTN() *Expr {
|
||||
return newExpr(c, C.Z3_mk_fpa_rtn(c.ptr))
|
||||
}
|
||||
|
||||
// MkFPRTZ creates the round-toward-zero rounding mode.
|
||||
func (c *Context) MkFPRTZ() *Expr {
|
||||
return newExpr(c, C.Z3_mk_fpa_rtz(c.ptr))
|
||||
}
|
||||
|
||||
// MkFPFP creates a floating-point number from a sign bit (1-bit BV), exponent BV, and significand BV.
|
||||
func (c *Context) MkFPFP(sgn, exp, sig *Expr) *Expr {
|
||||
return newExpr(c, C.Z3_mk_fpa_fp(c.ptr, sgn.ptr, exp.ptr, sig.ptr))
|
||||
}
|
||||
|
||||
// MkFPNumeralFloat creates a floating-point numeral from a float32 value.
|
||||
func (c *Context) MkFPNumeralFloat(v float32, sort *Sort) *Expr {
|
||||
return newExpr(c, C.Z3_mk_fpa_numeral_float(c.ptr, C.float(v), sort.ptr))
|
||||
}
|
||||
|
||||
// MkFPNumeralDouble creates a floating-point numeral from a float64 value.
|
||||
func (c *Context) MkFPNumeralDouble(v float64, sort *Sort) *Expr {
|
||||
return newExpr(c, C.Z3_mk_fpa_numeral_double(c.ptr, C.double(v), sort.ptr))
|
||||
}
|
||||
|
||||
// MkFPNumeralInt creates a floating-point numeral from a signed integer.
|
||||
func (c *Context) MkFPNumeralInt(v int, sort *Sort) *Expr {
|
||||
return newExpr(c, C.Z3_mk_fpa_numeral_int(c.ptr, C.int(v), sort.ptr))
|
||||
}
|
||||
|
||||
// MkFPNumeralIntUint creates a floating-point numeral from a sign, signed exponent, and unsigned significand.
|
||||
func (c *Context) MkFPNumeralIntUint(sgn bool, exp int, sig uint, sort *Sort) *Expr {
|
||||
return newExpr(c, C.Z3_mk_fpa_numeral_int_uint(c.ptr, C.bool(sgn), C.int(exp), C.uint(sig), sort.ptr))
|
||||
}
|
||||
|
||||
// MkFPNumeralInt64Uint64 creates a floating-point numeral from a sign, int64 exponent, and uint64 significand.
|
||||
func (c *Context) MkFPNumeralInt64Uint64(sgn bool, exp int64, sig uint64, sort *Sort) *Expr {
|
||||
return newExpr(c, C.Z3_mk_fpa_numeral_int64_uint64(c.ptr, C.bool(sgn), C.int64_t(exp), C.uint64_t(sig), sort.ptr))
|
||||
}
|
||||
|
||||
// MkFPFMA creates a floating-point fused multiply-add: round((t1 * t2) + t3, rm).
|
||||
func (c *Context) MkFPFMA(rm, t1, t2, t3 *Expr) *Expr {
|
||||
return newExpr(c, C.Z3_mk_fpa_fma(c.ptr, rm.ptr, t1.ptr, t2.ptr, t3.ptr))
|
||||
}
|
||||
|
||||
// MkFPRem creates a floating-point remainder.
|
||||
func (c *Context) MkFPRem(t1, t2 *Expr) *Expr {
|
||||
return newExpr(c, C.Z3_mk_fpa_rem(c.ptr, t1.ptr, t2.ptr))
|
||||
}
|
||||
|
||||
// MkFPMin creates the minimum of two floating-point values.
|
||||
func (c *Context) MkFPMin(t1, t2 *Expr) *Expr {
|
||||
return newExpr(c, C.Z3_mk_fpa_min(c.ptr, t1.ptr, t2.ptr))
|
||||
}
|
||||
|
||||
// MkFPMax creates the maximum of two floating-point values.
|
||||
func (c *Context) MkFPMax(t1, t2 *Expr) *Expr {
|
||||
return newExpr(c, C.Z3_mk_fpa_max(c.ptr, t1.ptr, t2.ptr))
|
||||
}
|
||||
|
||||
// MkFPRoundToIntegral creates a floating-point round-to-integral operation.
|
||||
func (c *Context) MkFPRoundToIntegral(rm, t *Expr) *Expr {
|
||||
return newExpr(c, C.Z3_mk_fpa_round_to_integral(c.ptr, rm.ptr, t.ptr))
|
||||
}
|
||||
|
||||
// MkFPToFPBV converts a bit-vector to a floating-point number (reinterpretation of IEEE 754 bits).
|
||||
func (c *Context) MkFPToFPBV(bv *Expr, sort *Sort) *Expr {
|
||||
return newExpr(c, C.Z3_mk_fpa_to_fp_bv(c.ptr, bv.ptr, sort.ptr))
|
||||
}
|
||||
|
||||
// MkFPToFPFloat converts a floating-point number to another floating-point sort with rounding.
|
||||
func (c *Context) MkFPToFPFloat(rm, t *Expr, sort *Sort) *Expr {
|
||||
return newExpr(c, C.Z3_mk_fpa_to_fp_float(c.ptr, rm.ptr, t.ptr, sort.ptr))
|
||||
}
|
||||
|
||||
// MkFPToFPReal converts a real number to a floating-point number with rounding.
|
||||
func (c *Context) MkFPToFPReal(rm, t *Expr, sort *Sort) *Expr {
|
||||
return newExpr(c, C.Z3_mk_fpa_to_fp_real(c.ptr, rm.ptr, t.ptr, sort.ptr))
|
||||
}
|
||||
|
||||
// MkFPToFPSigned converts a signed bit-vector to a floating-point number with rounding.
|
||||
func (c *Context) MkFPToFPSigned(rm, t *Expr, sort *Sort) *Expr {
|
||||
return newExpr(c, C.Z3_mk_fpa_to_fp_signed(c.ptr, rm.ptr, t.ptr, sort.ptr))
|
||||
}
|
||||
|
||||
// MkFPToFPUnsigned converts an unsigned bit-vector to a floating-point number with rounding.
|
||||
func (c *Context) MkFPToFPUnsigned(rm, t *Expr, sort *Sort) *Expr {
|
||||
return newExpr(c, C.Z3_mk_fpa_to_fp_unsigned(c.ptr, rm.ptr, t.ptr, sort.ptr))
|
||||
}
|
||||
|
||||
// MkFPToSBV converts a floating-point number to a signed bit-vector with rounding.
|
||||
func (c *Context) MkFPToSBV(rm, t *Expr, sz uint) *Expr {
|
||||
return newExpr(c, C.Z3_mk_fpa_to_sbv(c.ptr, rm.ptr, t.ptr, C.uint(sz)))
|
||||
}
|
||||
|
||||
// MkFPToUBV converts a floating-point number to an unsigned bit-vector with rounding.
|
||||
func (c *Context) MkFPToUBV(rm, t *Expr, sz uint) *Expr {
|
||||
return newExpr(c, C.Z3_mk_fpa_to_ubv(c.ptr, rm.ptr, t.ptr, C.uint(sz)))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -193,3 +193,15 @@ func (o *Optimize) FromString(s string) {
|
|||
defer C.free(unsafe.Pointer(cStr))
|
||||
C.Z3_optimize_from_string(o.ctx.ptr, o.ptr, cStr)
|
||||
}
|
||||
|
||||
// Translate creates a copy of the optimize context in the target context.
|
||||
// This is useful when working with multiple Z3 contexts.
|
||||
func (o *Optimize) Translate(target *Context) *Optimize {
|
||||
ptr := C.Z3_optimize_translate(o.ctx.ptr, o.ptr, target.ptr)
|
||||
newOpt := &Optimize{ctx: target, ptr: ptr}
|
||||
C.Z3_optimize_inc_ref(target.ptr, ptr)
|
||||
runtime.SetFinalizer(newOpt, func(opt *Optimize) {
|
||||
C.Z3_optimize_dec_ref(opt.ctx.ptr, opt.ptr)
|
||||
})
|
||||
return newOpt
|
||||
}
|
||||
|
|
|
|||
278
src/api/go/propagator.go
Normal file
278
src/api/go/propagator.go
Normal file
|
|
@ -0,0 +1,278 @@
|
|||
package z3
|
||||
|
||||
/*
|
||||
#include "z3.h"
|
||||
#include <stdint.h>
|
||||
|
||||
// Declarations for C helper functions defined in propagator_bridge.c
|
||||
extern void z3go_solver_propagate_init(Z3_context ctx, Z3_solver s, uintptr_t user_ctx);
|
||||
extern void z3go_solver_propagate_fixed(Z3_context ctx, Z3_solver s);
|
||||
extern void z3go_solver_propagate_final(Z3_context ctx, Z3_solver s);
|
||||
extern void z3go_solver_propagate_eq(Z3_context ctx, Z3_solver s);
|
||||
extern void z3go_solver_propagate_diseq(Z3_context ctx, Z3_solver s);
|
||||
extern void z3go_solver_propagate_created(Z3_context ctx, Z3_solver s);
|
||||
extern void z3go_solver_propagate_decide(Z3_context ctx, Z3_solver s);
|
||||
extern void z3go_solver_propagate_on_binding(Z3_context ctx, Z3_solver s);
|
||||
extern void z3go_solver_register_on_clause(Z3_context ctx, Z3_solver s, uintptr_t user_ctx);
|
||||
*/
|
||||
import "C"
|
||||
import (
|
||||
"runtime/cgo"
|
||||
)
|
||||
|
||||
// UserPropagator implements a custom theory propagator for Z3.
|
||||
// Embed this type and override callback methods to implement a propagator.
|
||||
//
|
||||
// Example usage:
|
||||
//
|
||||
// type MyPropagator struct {
|
||||
// z3.UserPropagator
|
||||
// }
|
||||
//
|
||||
// func (p *MyPropagator) Push() { ... }
|
||||
// func (p *MyPropagator) Pop(n uint) { ... }
|
||||
// func (p *MyPropagator) Fresh(ctx *z3.Context) z3.UserPropagatorCallbacks { return &MyPropagator{} }
|
||||
type UserPropagator struct {
|
||||
ctx *Context
|
||||
solver *Solver
|
||||
cb C.Z3_solver_callback // current callback context, valid only during a callback
|
||||
handle cgo.Handle // handle for passing to C as void* context
|
||||
iface UserPropagatorCallbacks
|
||||
}
|
||||
|
||||
// UserPropagatorCallbacks is the interface that a user propagator must implement.
|
||||
// Push, Pop, and Fresh are mandatory. The other callbacks are optional.
|
||||
type UserPropagatorCallbacks interface {
|
||||
// Push is called when the solver creates a new backtracking scope.
|
||||
Push()
|
||||
// Pop is called when the solver backtracks n scopes.
|
||||
Pop(n uint)
|
||||
// Fresh is called when the solver spawns a new internal solver instance.
|
||||
// Return a propagator for the new context. The callbacks registered on the
|
||||
// original propagator will also be registered on the fresh one.
|
||||
Fresh(ctx *Context) UserPropagatorCallbacks
|
||||
}
|
||||
|
||||
// FixedHandler is implemented by propagators that handle fixed-value assignments.
|
||||
type FixedHandler interface {
|
||||
Fixed(term *Expr, value *Expr)
|
||||
}
|
||||
|
||||
// FinalHandler is implemented by propagators that handle the final check.
|
||||
// The final check is invoked when all decision variables have been assigned.
|
||||
type FinalHandler interface {
|
||||
Final()
|
||||
}
|
||||
|
||||
// EqHandler is implemented by propagators that handle expression equalities.
|
||||
type EqHandler interface {
|
||||
Eq(a *Expr, b *Expr)
|
||||
}
|
||||
|
||||
// DiseqHandler is implemented by propagators that handle expression disequalities.
|
||||
type DiseqHandler interface {
|
||||
Diseq(a *Expr, b *Expr)
|
||||
}
|
||||
|
||||
// CreatedHandler is implemented by propagators that handle term creation events.
|
||||
// Terms are created when they use a function declared with PropagatorDeclare.
|
||||
type CreatedHandler interface {
|
||||
Created(t *Expr)
|
||||
}
|
||||
|
||||
// DecideHandler is implemented by propagators that handle solver decision events.
|
||||
type DecideHandler interface {
|
||||
Decide(t *Expr, idx uint, phase bool)
|
||||
}
|
||||
|
||||
// OnBindingHandler is implemented by propagators that handle quantifier binding events.
|
||||
// Return false to block the instantiation.
|
||||
type OnBindingHandler interface {
|
||||
OnBinding(q *Expr, inst *Expr) bool
|
||||
}
|
||||
|
||||
// newUserPropagator creates a new UserPropagator wrapping the given callbacks.
|
||||
func newUserPropagator(ctx *Context, solver *Solver, iface UserPropagatorCallbacks) *UserPropagator {
|
||||
p := &UserPropagator{
|
||||
ctx: ctx,
|
||||
solver: solver,
|
||||
iface: iface,
|
||||
}
|
||||
p.handle = cgo.NewHandle(p)
|
||||
C.z3go_solver_propagate_init(ctx.ptr, solver.ptr, C.uintptr_t(p.handle))
|
||||
return p
|
||||
}
|
||||
|
||||
// Close releases the resources associated with this propagator.
|
||||
// It must be called when the propagator is no longer needed.
|
||||
func (p *UserPropagator) Close() {
|
||||
if p.handle != 0 {
|
||||
p.handle.Delete()
|
||||
p.handle = 0
|
||||
}
|
||||
}
|
||||
|
||||
// RegisterFixed registers the fixed-value callback.
|
||||
// The propagator's iface must implement FixedHandler.
|
||||
func (p *UserPropagator) RegisterFixed() {
|
||||
C.z3go_solver_propagate_fixed(p.ctx.ptr, p.solver.ptr)
|
||||
}
|
||||
|
||||
// RegisterFinal registers the final-check callback.
|
||||
// The propagator's iface must implement FinalHandler.
|
||||
func (p *UserPropagator) RegisterFinal() {
|
||||
C.z3go_solver_propagate_final(p.ctx.ptr, p.solver.ptr)
|
||||
}
|
||||
|
||||
// RegisterEq registers the equality callback.
|
||||
// The propagator's iface must implement EqHandler.
|
||||
func (p *UserPropagator) RegisterEq() {
|
||||
C.z3go_solver_propagate_eq(p.ctx.ptr, p.solver.ptr)
|
||||
}
|
||||
|
||||
// RegisterDiseq registers the disequality callback.
|
||||
// The propagator's iface must implement DiseqHandler.
|
||||
func (p *UserPropagator) RegisterDiseq() {
|
||||
C.z3go_solver_propagate_diseq(p.ctx.ptr, p.solver.ptr)
|
||||
}
|
||||
|
||||
// RegisterCreated registers the term-creation callback.
|
||||
// The propagator's iface must implement CreatedHandler.
|
||||
func (p *UserPropagator) RegisterCreated() {
|
||||
C.z3go_solver_propagate_created(p.ctx.ptr, p.solver.ptr)
|
||||
}
|
||||
|
||||
// RegisterDecide registers the decision callback.
|
||||
// The propagator's iface must implement DecideHandler.
|
||||
func (p *UserPropagator) RegisterDecide() {
|
||||
C.z3go_solver_propagate_decide(p.ctx.ptr, p.solver.ptr)
|
||||
}
|
||||
|
||||
// RegisterOnBinding registers the quantifier-binding callback.
|
||||
// The propagator's iface must implement OnBindingHandler.
|
||||
func (p *UserPropagator) RegisterOnBinding() {
|
||||
C.z3go_solver_propagate_on_binding(p.ctx.ptr, p.solver.ptr)
|
||||
}
|
||||
|
||||
// Add registers an expression for propagation.
|
||||
// Only Bool and BitVector expressions can be registered.
|
||||
// May be called during a callback (uses the solver callback) or outside (uses the solver directly).
|
||||
func (p *UserPropagator) Add(e *Expr) {
|
||||
if p.cb != nil {
|
||||
C.Z3_solver_propagate_register_cb(p.ctx.ptr, p.cb, e.ptr)
|
||||
} else {
|
||||
C.Z3_solver_propagate_register(p.ctx.ptr, p.solver.ptr, e.ptr)
|
||||
}
|
||||
}
|
||||
|
||||
// Consequence propagates a consequence based on fixed terms.
|
||||
// fixed is the list of fixed terms used as premises.
|
||||
// Returns true if the propagation was accepted.
|
||||
func (p *UserPropagator) Consequence(fixed []*Expr, consequence *Expr) bool {
|
||||
return p.ConsequenceWithEqs(fixed, nil, nil, consequence)
|
||||
}
|
||||
|
||||
// ConsequenceWithEqs propagates a consequence based on fixed values and equalities.
|
||||
// fixed are the premise fixed terms, lhs/rhs are equality premises, consequence is the result.
|
||||
// Returns true if the propagation was accepted.
|
||||
func (p *UserPropagator) ConsequenceWithEqs(fixed []*Expr, lhs []*Expr, rhs []*Expr, consequence *Expr) bool {
|
||||
numFixed := C.uint(len(fixed))
|
||||
numEqs := C.uint(len(lhs))
|
||||
var fixedPtr *C.Z3_ast
|
||||
var lhsPtr *C.Z3_ast
|
||||
var rhsPtr *C.Z3_ast
|
||||
if numFixed > 0 {
|
||||
cFixed := make([]C.Z3_ast, numFixed)
|
||||
for i, e := range fixed {
|
||||
cFixed[i] = e.ptr
|
||||
}
|
||||
fixedPtr = &cFixed[0]
|
||||
}
|
||||
if numEqs > 0 {
|
||||
cLhs := make([]C.Z3_ast, numEqs)
|
||||
cRhs := make([]C.Z3_ast, numEqs)
|
||||
for i := range lhs {
|
||||
cLhs[i] = lhs[i].ptr
|
||||
cRhs[i] = rhs[i].ptr
|
||||
}
|
||||
lhsPtr = &cLhs[0]
|
||||
rhsPtr = &cRhs[0]
|
||||
}
|
||||
result := C.Z3_solver_propagate_consequence(p.ctx.ptr, p.cb,
|
||||
numFixed, fixedPtr,
|
||||
numEqs, lhsPtr, rhsPtr,
|
||||
consequence.ptr)
|
||||
return result == C.bool(true)
|
||||
}
|
||||
|
||||
// NextSplit overrides the solver's next variable to split on.
|
||||
// This should be called during the Decide callback to override the decision.
|
||||
// phase: -1 for false, 0 for default, 1 for true (as Z3_lbool values).
|
||||
func (p *UserPropagator) NextSplit(e *Expr, idx uint, phase int) bool {
|
||||
result := C.Z3_solver_next_split(p.ctx.ptr, p.cb, e.ptr, C.uint(idx), C.Z3_lbool(phase))
|
||||
return result == C.bool(true)
|
||||
}
|
||||
|
||||
// PropagatorDeclare creates an uninterpreted function declaration for the user propagator.
|
||||
// When expressions using this function are created, the Created callback is invoked.
|
||||
func (ctx *Context) PropagatorDeclare(name string, domain []*Sort, rangeSort *Sort) *FuncDecl {
|
||||
sym := ctx.MkStringSymbol(name)
|
||||
n := C.uint(len(domain))
|
||||
var domainPtr *C.Z3_sort
|
||||
if n > 0 {
|
||||
cDomain := make([]C.Z3_sort, n)
|
||||
for i, s := range domain {
|
||||
cDomain[i] = s.ptr
|
||||
}
|
||||
domainPtr = &cDomain[0]
|
||||
}
|
||||
result := C.Z3_solver_propagate_declare(ctx.ptr, sym.ptr, n, domainPtr, rangeSort.ptr)
|
||||
return newFuncDecl(ctx, result)
|
||||
}
|
||||
|
||||
// NewUserPropagator attaches a user propagator to the solver.
|
||||
// The callbacks object must implement UserPropagatorCallbacks (Push, Pop, Fresh).
|
||||
// Optional callbacks (Fixed, Final, Eq, Diseq, Created, Decide, OnBinding)
|
||||
// are registered by calling the corresponding Register* methods on the returned propagator.
|
||||
//
|
||||
// The propagator must be closed by calling Close() when no longer needed.
|
||||
func (s *Solver) NewUserPropagator(callbacks UserPropagatorCallbacks) *UserPropagator {
|
||||
return newUserPropagator(s.ctx, s, callbacks)
|
||||
}
|
||||
|
||||
// OnClauseHandler is the callback function type for clause inference events.
|
||||
// proofHint is a partial derivation justifying the inference (may be nil).
|
||||
// deps contains dependency indices.
|
||||
// literals is the inferred clause as an AST vector.
|
||||
// The lifetime of proofHint and literals is limited to the callback scope.
|
||||
type OnClauseHandler func(proofHint *Expr, deps []uint, literals *ASTVector)
|
||||
|
||||
// OnClause registers a callback for clause inferences during solving.
|
||||
// Useful for observing learned clauses, custom learning strategies,
|
||||
// clause sharing in parallel solvers, and proof extraction.
|
||||
// Call Close when the callback is no longer needed.
|
||||
type OnClause struct {
|
||||
handle cgo.Handle
|
||||
ctx *Context
|
||||
handler OnClauseHandler
|
||||
}
|
||||
|
||||
// NewOnClause registers a callback for clause inferences on the given solver.
|
||||
// The returned OnClause must be closed by calling Close() when done.
|
||||
func (s *Solver) NewOnClause(handler OnClauseHandler) *OnClause {
|
||||
oc := &OnClause{
|
||||
ctx: s.ctx,
|
||||
handler: handler,
|
||||
}
|
||||
oc.handle = cgo.NewHandle(oc)
|
||||
C.z3go_solver_register_on_clause(s.ctx.ptr, s.ptr, C.uintptr_t(oc.handle))
|
||||
return oc
|
||||
}
|
||||
|
||||
// Close releases the resources associated with this on-clause callback.
|
||||
func (oc *OnClause) Close() {
|
||||
if oc.handle != 0 {
|
||||
oc.handle.Delete()
|
||||
oc.handle = 0
|
||||
}
|
||||
}
|
||||
93
src/api/go/propagator_bridge.c
Normal file
93
src/api/go/propagator_bridge.c
Normal file
|
|
@ -0,0 +1,93 @@
|
|||
#include "z3.h"
|
||||
#include "_cgo_export.h"
|
||||
#include <stdint.h>
|
||||
|
||||
/* Bridge functions that adapt C callback signatures to exported Go functions.
|
||||
* The user context (void*) is stored/received as uintptr_t to avoid unsafe pointer
|
||||
* conversion warnings in Go. */
|
||||
|
||||
static void propagator_push_bridge(void* ctx, Z3_solver_callback cb) {
|
||||
goPushCb((uintptr_t)ctx, cb);
|
||||
}
|
||||
|
||||
static void propagator_pop_bridge(void* ctx, Z3_solver_callback cb, unsigned num_scopes) {
|
||||
goPopCb((uintptr_t)ctx, cb, num_scopes);
|
||||
}
|
||||
|
||||
static void* propagator_fresh_bridge(void* ctx, Z3_context new_context) {
|
||||
return (void*)goFreshCb((uintptr_t)ctx, new_context);
|
||||
}
|
||||
|
||||
static void propagator_fixed_bridge(void* ctx, Z3_solver_callback cb, Z3_ast t, Z3_ast value) {
|
||||
goFixedCb((uintptr_t)ctx, cb, t, value);
|
||||
}
|
||||
|
||||
static void propagator_eq_bridge(void* ctx, Z3_solver_callback cb, Z3_ast s, Z3_ast t) {
|
||||
goEqCb((uintptr_t)ctx, cb, s, t);
|
||||
}
|
||||
|
||||
static void propagator_diseq_bridge(void* ctx, Z3_solver_callback cb, Z3_ast s, Z3_ast t) {
|
||||
goDiseqCb((uintptr_t)ctx, cb, s, t);
|
||||
}
|
||||
|
||||
static void propagator_final_bridge(void* ctx, Z3_solver_callback cb) {
|
||||
goFinalCb((uintptr_t)ctx, cb);
|
||||
}
|
||||
|
||||
static void propagator_created_bridge(void* ctx, Z3_solver_callback cb, Z3_ast t) {
|
||||
goCreatedCb((uintptr_t)ctx, cb, t);
|
||||
}
|
||||
|
||||
static void propagator_decide_bridge(void* ctx, Z3_solver_callback cb, Z3_ast t, unsigned idx, bool phase) {
|
||||
goDecideCb((uintptr_t)ctx, cb, t, idx, phase);
|
||||
}
|
||||
|
||||
static bool propagator_on_binding_bridge(void* ctx, Z3_solver_callback cb, Z3_ast q, Z3_ast inst) {
|
||||
return goOnBindingCb((uintptr_t)ctx, cb, q, inst);
|
||||
}
|
||||
|
||||
static void on_clause_bridge(void* ctx, Z3_ast proof_hint, unsigned n, unsigned const* deps, Z3_ast_vector literals) {
|
||||
goOnClauseCb((uintptr_t)ctx, proof_hint, n, (unsigned*)deps, literals);
|
||||
}
|
||||
|
||||
/* C helper functions that Go calls to register callbacks.
|
||||
* These take uintptr_t for the user context and cast it to void* internally. */
|
||||
|
||||
void z3go_solver_propagate_init(Z3_context ctx, Z3_solver s, uintptr_t user_ctx) {
|
||||
Z3_solver_propagate_init(ctx, s, (void*)user_ctx,
|
||||
propagator_push_bridge,
|
||||
propagator_pop_bridge,
|
||||
propagator_fresh_bridge);
|
||||
}
|
||||
|
||||
void z3go_solver_propagate_fixed(Z3_context ctx, Z3_solver s) {
|
||||
Z3_solver_propagate_fixed(ctx, s, propagator_fixed_bridge);
|
||||
}
|
||||
|
||||
void z3go_solver_propagate_final(Z3_context ctx, Z3_solver s) {
|
||||
Z3_solver_propagate_final(ctx, s, propagator_final_bridge);
|
||||
}
|
||||
|
||||
void z3go_solver_propagate_eq(Z3_context ctx, Z3_solver s) {
|
||||
Z3_solver_propagate_eq(ctx, s, propagator_eq_bridge);
|
||||
}
|
||||
|
||||
void z3go_solver_propagate_diseq(Z3_context ctx, Z3_solver s) {
|
||||
Z3_solver_propagate_diseq(ctx, s, propagator_diseq_bridge);
|
||||
}
|
||||
|
||||
void z3go_solver_propagate_created(Z3_context ctx, Z3_solver s) {
|
||||
Z3_solver_propagate_created(ctx, s, propagator_created_bridge);
|
||||
}
|
||||
|
||||
void z3go_solver_propagate_decide(Z3_context ctx, Z3_solver s) {
|
||||
Z3_solver_propagate_decide(ctx, s, propagator_decide_bridge);
|
||||
}
|
||||
|
||||
void z3go_solver_propagate_on_binding(Z3_context ctx, Z3_solver s) {
|
||||
Z3_solver_propagate_on_binding(ctx, s, propagator_on_binding_bridge);
|
||||
}
|
||||
|
||||
void z3go_solver_register_on_clause(Z3_context ctx, Z3_solver s, uintptr_t user_ctx) {
|
||||
Z3_solver_register_on_clause(ctx, s, (void*)user_ctx, on_clause_bridge);
|
||||
}
|
||||
158
src/api/go/propagator_callbacks.go
Normal file
158
src/api/go/propagator_callbacks.go
Normal file
|
|
@ -0,0 +1,158 @@
|
|||
package z3
|
||||
|
||||
/*
|
||||
#include "z3.h"
|
||||
#include <stdint.h>
|
||||
*/
|
||||
import "C"
|
||||
import (
|
||||
"runtime/cgo"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// withCallback temporarily sets the callback context, calls fn, and restores the old context.
|
||||
func (p *UserPropagator) withCallback(cb C.Z3_solver_callback, fn func()) {
|
||||
old := p.cb
|
||||
p.cb = cb
|
||||
defer func() { p.cb = old }()
|
||||
fn()
|
||||
}
|
||||
|
||||
// goPushCb is exported to C as a callback for Z3_push_eh.
|
||||
//
|
||||
//export goPushCb
|
||||
func goPushCb(ctx C.uintptr_t, cb C.Z3_solver_callback) {
|
||||
p := cgo.Handle(ctx).Value().(*UserPropagator)
|
||||
p.withCallback(cb, p.iface.Push)
|
||||
}
|
||||
|
||||
// goPopCb is exported to C as a callback for Z3_pop_eh.
|
||||
//
|
||||
//export goPopCb
|
||||
func goPopCb(ctx C.uintptr_t, cb C.Z3_solver_callback, numScopes C.uint) {
|
||||
p := cgo.Handle(ctx).Value().(*UserPropagator)
|
||||
p.withCallback(cb, func() {
|
||||
p.iface.Pop(uint(numScopes))
|
||||
})
|
||||
}
|
||||
|
||||
// goFreshCb is exported to C as a callback for Z3_fresh_eh.
|
||||
//
|
||||
//export goFreshCb
|
||||
func goFreshCb(ctx C.uintptr_t, newContext C.Z3_context) C.uintptr_t {
|
||||
p := cgo.Handle(ctx).Value().(*UserPropagator)
|
||||
freshCtx := &Context{ptr: newContext}
|
||||
freshIface := p.iface.Fresh(freshCtx)
|
||||
freshProp := &UserPropagator{
|
||||
ctx: freshCtx,
|
||||
iface: freshIface,
|
||||
}
|
||||
freshProp.handle = cgo.NewHandle(freshProp)
|
||||
return C.uintptr_t(freshProp.handle)
|
||||
}
|
||||
|
||||
// goFixedCb is exported to C as a callback for Z3_fixed_eh.
|
||||
//
|
||||
//export goFixedCb
|
||||
func goFixedCb(ctx C.uintptr_t, cb C.Z3_solver_callback, t C.Z3_ast, value C.Z3_ast) {
|
||||
p := cgo.Handle(ctx).Value().(*UserPropagator)
|
||||
if h, ok := p.iface.(FixedHandler); ok {
|
||||
p.withCallback(cb, func() {
|
||||
h.Fixed(newExpr(p.ctx, t), newExpr(p.ctx, value))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// goEqCb is exported to C as a callback for Z3_eq_eh (equality).
|
||||
//
|
||||
//export goEqCb
|
||||
func goEqCb(ctx C.uintptr_t, cb C.Z3_solver_callback, s C.Z3_ast, t C.Z3_ast) {
|
||||
p := cgo.Handle(ctx).Value().(*UserPropagator)
|
||||
if h, ok := p.iface.(EqHandler); ok {
|
||||
p.withCallback(cb, func() {
|
||||
h.Eq(newExpr(p.ctx, s), newExpr(p.ctx, t))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// goDiseqCb is exported to C as a callback for Z3_eq_eh (disequality).
|
||||
//
|
||||
//export goDiseqCb
|
||||
func goDiseqCb(ctx C.uintptr_t, cb C.Z3_solver_callback, s C.Z3_ast, t C.Z3_ast) {
|
||||
p := cgo.Handle(ctx).Value().(*UserPropagator)
|
||||
if h, ok := p.iface.(DiseqHandler); ok {
|
||||
p.withCallback(cb, func() {
|
||||
h.Diseq(newExpr(p.ctx, s), newExpr(p.ctx, t))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// goFinalCb is exported to C as a callback for Z3_final_eh.
|
||||
//
|
||||
//export goFinalCb
|
||||
func goFinalCb(ctx C.uintptr_t, cb C.Z3_solver_callback) {
|
||||
p := cgo.Handle(ctx).Value().(*UserPropagator)
|
||||
if h, ok := p.iface.(FinalHandler); ok {
|
||||
p.withCallback(cb, h.Final)
|
||||
}
|
||||
}
|
||||
|
||||
// goCreatedCb is exported to C as a callback for Z3_created_eh.
|
||||
//
|
||||
//export goCreatedCb
|
||||
func goCreatedCb(ctx C.uintptr_t, cb C.Z3_solver_callback, t C.Z3_ast) {
|
||||
p := cgo.Handle(ctx).Value().(*UserPropagator)
|
||||
if h, ok := p.iface.(CreatedHandler); ok {
|
||||
p.withCallback(cb, func() {
|
||||
h.Created(newExpr(p.ctx, t))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// goDecideCb is exported to C as a callback for Z3_decide_eh.
|
||||
//
|
||||
//export goDecideCb
|
||||
func goDecideCb(ctx C.uintptr_t, cb C.Z3_solver_callback, t C.Z3_ast, idx C.uint, phase C.bool) {
|
||||
p := cgo.Handle(ctx).Value().(*UserPropagator)
|
||||
if h, ok := p.iface.(DecideHandler); ok {
|
||||
p.withCallback(cb, func() {
|
||||
h.Decide(newExpr(p.ctx, t), uint(idx), phase == C.bool(true))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// goOnBindingCb is exported to C as a callback for Z3_on_binding_eh.
|
||||
//
|
||||
//export goOnBindingCb
|
||||
func goOnBindingCb(ctx C.uintptr_t, cb C.Z3_solver_callback, q C.Z3_ast, inst C.Z3_ast) C.bool {
|
||||
p := cgo.Handle(ctx).Value().(*UserPropagator)
|
||||
result := C.bool(true) // default: allow binding when handler is not implemented
|
||||
if h, ok := p.iface.(OnBindingHandler); ok {
|
||||
p.withCallback(cb, func() {
|
||||
if !h.OnBinding(newExpr(p.ctx, q), newExpr(p.ctx, inst)) {
|
||||
result = C.bool(false)
|
||||
}
|
||||
})
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// goOnClauseCb is exported to C as a callback for Z3_on_clause_eh.
|
||||
//
|
||||
//export goOnClauseCb
|
||||
func goOnClauseCb(ctx C.uintptr_t, proofHint C.Z3_ast, n C.uint, deps *C.uint, literals C.Z3_ast_vector) {
|
||||
oc := cgo.Handle(ctx).Value().(*OnClause)
|
||||
var ph *Expr
|
||||
if proofHint != nil {
|
||||
ph = newExpr(oc.ctx, proofHint)
|
||||
}
|
||||
goDepSlice := make([]uint, uint(n))
|
||||
if n > 0 {
|
||||
depSlice := (*[1 << 28]C.uint)(unsafe.Pointer(deps))[:n:n]
|
||||
for i := uint(0); i < uint(n); i++ {
|
||||
goDepSlice[i] = uint(depSlice[i])
|
||||
}
|
||||
}
|
||||
vec := newASTVector(oc.ctx, literals)
|
||||
oc.handler(ph, goDepSlice, vec)
|
||||
}
|
||||
38
src/api/go/relations.go
Normal file
38
src/api/go/relations.go
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
package z3
|
||||
|
||||
/*
|
||||
#include "z3.h"
|
||||
*/
|
||||
import "C"
|
||||
|
||||
// Special relation constructors
|
||||
|
||||
// MkLinearOrder creates a linear (total) order relation over the given sort.
|
||||
// The id parameter distinguishes multiple linear orders over the same sort.
|
||||
func (c *Context) MkLinearOrder(s *Sort, id uint) *FuncDecl {
|
||||
return newFuncDecl(c, C.Z3_mk_linear_order(c.ptr, s.ptr, C.uint(id)))
|
||||
}
|
||||
|
||||
// MkPartialOrder creates a partial order relation over the given sort.
|
||||
// The id parameter distinguishes multiple partial orders over the same sort.
|
||||
func (c *Context) MkPartialOrder(s *Sort, id uint) *FuncDecl {
|
||||
return newFuncDecl(c, C.Z3_mk_partial_order(c.ptr, s.ptr, C.uint(id)))
|
||||
}
|
||||
|
||||
// MkPiecewiseLinearOrder creates a piecewise linear order relation over the given sort.
|
||||
// The id parameter distinguishes multiple piecewise linear orders over the same sort.
|
||||
func (c *Context) MkPiecewiseLinearOrder(s *Sort, id uint) *FuncDecl {
|
||||
return newFuncDecl(c, C.Z3_mk_piecewise_linear_order(c.ptr, s.ptr, C.uint(id)))
|
||||
}
|
||||
|
||||
// MkTreeOrder creates a tree order relation over the given sort.
|
||||
// The id parameter distinguishes multiple tree orders over the same sort.
|
||||
func (c *Context) MkTreeOrder(s *Sort, id uint) *FuncDecl {
|
||||
return newFuncDecl(c, C.Z3_mk_tree_order(c.ptr, s.ptr, C.uint(id)))
|
||||
}
|
||||
|
||||
// MkTransitiveClosure creates the transitive closure of a binary relation.
|
||||
// The resulting relation is recursive.
|
||||
func (c *Context) MkTransitiveClosure(f *FuncDecl) *FuncDecl {
|
||||
return newFuncDecl(c, C.Z3_mk_transitive_closure(c.ptr, f.ptr))
|
||||
}
|
||||
|
|
@ -230,3 +230,58 @@ func (c *Context) MkSeqReplaceRe(seq, re, replacement *Expr) *Expr {
|
|||
func (c *Context) MkSeqReplaceReAll(seq, re, replacement *Expr) *Expr {
|
||||
return newExpr(c, C.Z3_mk_seq_replace_re_all(c.ptr, seq.ptr, re.ptr, replacement.ptr))
|
||||
}
|
||||
|
||||
// MkSeqReplaceAll replaces all occurrences of src with dst in seq.
|
||||
func (c *Context) MkSeqReplaceAll(seq, src, dst *Expr) *Expr {
|
||||
return newExpr(c, C.Z3_mk_seq_replace_all(c.ptr, seq.ptr, src.ptr, dst.ptr))
|
||||
}
|
||||
|
||||
// MkSeqNth retrieves the n-th element of a sequence as a single-element expression.
|
||||
func (c *Context) MkSeqNth(seq, index *Expr) *Expr {
|
||||
return newExpr(c, C.Z3_mk_seq_nth(c.ptr, seq.ptr, index.ptr))
|
||||
}
|
||||
|
||||
// MkSeqLastIndex returns the last index of substr in seq.
|
||||
func (c *Context) MkSeqLastIndex(seq, substr *Expr) *Expr {
|
||||
return newExpr(c, C.Z3_mk_seq_last_index(c.ptr, seq.ptr, substr.ptr))
|
||||
}
|
||||
|
||||
// MkSeqMap applies a function to each element of a sequence, returning a new sequence.
|
||||
func (c *Context) MkSeqMap(f, seq *Expr) *Expr {
|
||||
return newExpr(c, C.Z3_mk_seq_map(c.ptr, f.ptr, seq.ptr))
|
||||
}
|
||||
|
||||
// MkSeqMapi applies an indexed function to each element of a sequence, returning a new sequence.
|
||||
func (c *Context) MkSeqMapi(f, i, seq *Expr) *Expr {
|
||||
return newExpr(c, C.Z3_mk_seq_mapi(c.ptr, f.ptr, i.ptr, seq.ptr))
|
||||
}
|
||||
|
||||
// MkSeqFoldl applies a fold-left operation to a sequence.
|
||||
func (c *Context) MkSeqFoldl(f, a, seq *Expr) *Expr {
|
||||
return newExpr(c, C.Z3_mk_seq_foldl(c.ptr, f.ptr, a.ptr, seq.ptr))
|
||||
}
|
||||
|
||||
// MkSeqFoldli applies an indexed fold-left operation to a sequence.
|
||||
func (c *Context) MkSeqFoldli(f, i, a, seq *Expr) *Expr {
|
||||
return newExpr(c, C.Z3_mk_seq_foldli(c.ptr, f.ptr, i.ptr, a.ptr, seq.ptr))
|
||||
}
|
||||
|
||||
// MkStrLt creates a string less-than comparison.
|
||||
func (c *Context) MkStrLt(s1, s2 *Expr) *Expr {
|
||||
return newExpr(c, C.Z3_mk_str_lt(c.ptr, s1.ptr, s2.ptr))
|
||||
}
|
||||
|
||||
// MkStrLe creates a string less-than-or-equal comparison.
|
||||
func (c *Context) MkStrLe(s1, s2 *Expr) *Expr {
|
||||
return newExpr(c, C.Z3_mk_str_le(c.ptr, s1.ptr, s2.ptr))
|
||||
}
|
||||
|
||||
// MkStringToCode converts a single-character string to its Unicode code point.
|
||||
func (c *Context) MkStringToCode(s *Expr) *Expr {
|
||||
return newExpr(c, C.Z3_mk_string_to_code(c.ptr, s.ptr))
|
||||
}
|
||||
|
||||
// MkStringFromCode converts a Unicode code point to a single-character string.
|
||||
func (c *Context) MkStringFromCode(code *Expr) *Expr {
|
||||
return newExpr(c, C.Z3_mk_string_from_code(c.ptr, code.ptr))
|
||||
}
|
||||
|
|
|
|||
77
src/api/go/set.go
Normal file
77
src/api/go/set.go
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
package z3
|
||||
|
||||
/*
|
||||
#include "z3.h"
|
||||
*/
|
||||
import "C"
|
||||
|
||||
// Regular (array-encoded) Set operations
|
||||
|
||||
// MkSetSort creates a set sort with the given element sort.
|
||||
func (c *Context) MkSetSort(elemSort *Sort) *Sort {
|
||||
return newSort(c, C.Z3_mk_set_sort(c.ptr, elemSort.ptr))
|
||||
}
|
||||
|
||||
// MkEmptySet creates an empty set of the given element sort.
|
||||
func (c *Context) MkEmptySet(elemSort *Sort) *Expr {
|
||||
return newExpr(c, C.Z3_mk_empty_set(c.ptr, elemSort.ptr))
|
||||
}
|
||||
|
||||
// MkFullSet creates the full set (universe) of the given element sort.
|
||||
func (c *Context) MkFullSet(elemSort *Sort) *Expr {
|
||||
return newExpr(c, C.Z3_mk_full_set(c.ptr, elemSort.ptr))
|
||||
}
|
||||
|
||||
// MkSetAdd adds an element to a set.
|
||||
func (c *Context) MkSetAdd(set, elem *Expr) *Expr {
|
||||
return newExpr(c, C.Z3_mk_set_add(c.ptr, set.ptr, elem.ptr))
|
||||
}
|
||||
|
||||
// MkSetDel removes an element from a set.
|
||||
func (c *Context) MkSetDel(set, elem *Expr) *Expr {
|
||||
return newExpr(c, C.Z3_mk_set_del(c.ptr, set.ptr, elem.ptr))
|
||||
}
|
||||
|
||||
// MkSetUnion creates the union of two or more sets.
|
||||
func (c *Context) MkSetUnion(sets ...*Expr) *Expr {
|
||||
if len(sets) == 0 {
|
||||
return nil
|
||||
}
|
||||
cSets := make([]C.Z3_ast, len(sets))
|
||||
for i, s := range sets {
|
||||
cSets[i] = s.ptr
|
||||
}
|
||||
return newExpr(c, C.Z3_mk_set_union(c.ptr, C.uint(len(sets)), &cSets[0]))
|
||||
}
|
||||
|
||||
// MkSetIntersect creates the intersection of two or more sets.
|
||||
func (c *Context) MkSetIntersect(sets ...*Expr) *Expr {
|
||||
if len(sets) == 0 {
|
||||
return nil
|
||||
}
|
||||
cSets := make([]C.Z3_ast, len(sets))
|
||||
for i, s := range sets {
|
||||
cSets[i] = s.ptr
|
||||
}
|
||||
return newExpr(c, C.Z3_mk_set_intersect(c.ptr, C.uint(len(sets)), &cSets[0]))
|
||||
}
|
||||
|
||||
// MkSetDifference creates the set difference (set1 \ set2).
|
||||
func (c *Context) MkSetDifference(set1, set2 *Expr) *Expr {
|
||||
return newExpr(c, C.Z3_mk_set_difference(c.ptr, set1.ptr, set2.ptr))
|
||||
}
|
||||
|
||||
// MkSetComplement creates the complement of a set.
|
||||
func (c *Context) MkSetComplement(set *Expr) *Expr {
|
||||
return newExpr(c, C.Z3_mk_set_complement(c.ptr, set.ptr))
|
||||
}
|
||||
|
||||
// MkSetMember creates a membership predicate: elem ∈ set.
|
||||
func (c *Context) MkSetMember(elem, set *Expr) *Expr {
|
||||
return newExpr(c, C.Z3_mk_set_member(c.ptr, elem.ptr, set.ptr))
|
||||
}
|
||||
|
||||
// MkSetSubset creates a subset predicate: set1 ⊆ set2.
|
||||
func (c *Context) MkSetSubset(set1, set2 *Expr) *Expr {
|
||||
return newExpr(c, C.Z3_mk_set_subset(c.ptr, set1.ptr, set2.ptr))
|
||||
}
|
||||
61
src/api/go/simplifier.go
Normal file
61
src/api/go/simplifier.go
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
package z3
|
||||
|
||||
/*
|
||||
#include "z3.h"
|
||||
#include <stdlib.h>
|
||||
*/
|
||||
import "C"
|
||||
import (
|
||||
"runtime"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// Simplifier represents a Z3 simplifier for pre-processing solver assertions.
|
||||
type Simplifier struct {
|
||||
ctx *Context
|
||||
ptr C.Z3_simplifier
|
||||
}
|
||||
|
||||
// newSimplifier creates a new Simplifier and manages its reference count.
|
||||
func newSimplifier(ctx *Context, ptr C.Z3_simplifier) *Simplifier {
|
||||
s := &Simplifier{ctx: ctx, ptr: ptr}
|
||||
C.Z3_simplifier_inc_ref(ctx.ptr, ptr)
|
||||
runtime.SetFinalizer(s, func(simp *Simplifier) {
|
||||
C.Z3_simplifier_dec_ref(simp.ctx.ptr, simp.ptr)
|
||||
})
|
||||
return s
|
||||
}
|
||||
|
||||
// MkSimplifier creates a simplifier with the given name.
|
||||
func (c *Context) MkSimplifier(name string) *Simplifier {
|
||||
cName := C.CString(name)
|
||||
defer C.free(unsafe.Pointer(cName))
|
||||
return newSimplifier(c, C.Z3_mk_simplifier(c.ptr, cName))
|
||||
}
|
||||
|
||||
// AndThen creates a simplifier that applies s followed by s2.
|
||||
func (s *Simplifier) AndThen(s2 *Simplifier) *Simplifier {
|
||||
return newSimplifier(s.ctx, C.Z3_simplifier_and_then(s.ctx.ptr, s.ptr, s2.ptr))
|
||||
}
|
||||
|
||||
// UsingParams creates a simplifier that uses the given parameters.
|
||||
func (s *Simplifier) UsingParams(params *Params) *Simplifier {
|
||||
return newSimplifier(s.ctx, C.Z3_simplifier_using_params(s.ctx.ptr, s.ptr, params.ptr))
|
||||
}
|
||||
|
||||
// GetHelp returns help information for the simplifier.
|
||||
func (s *Simplifier) GetHelp() string {
|
||||
return C.GoString(C.Z3_simplifier_get_help(s.ctx.ptr, s.ptr))
|
||||
}
|
||||
|
||||
// GetParamDescrs returns parameter descriptions for the simplifier.
|
||||
func (s *Simplifier) GetParamDescrs() *ParamDescrs {
|
||||
return newParamDescrs(s.ctx, C.Z3_simplifier_get_param_descrs(s.ctx.ptr, s.ptr))
|
||||
}
|
||||
|
||||
// GetSimplifierDescr returns a description of the simplifier with the given name.
|
||||
func (c *Context) GetSimplifierDescr(name string) string {
|
||||
cName := C.CString(name)
|
||||
defer C.free(unsafe.Pointer(cName))
|
||||
return C.GoString(C.Z3_simplifier_get_descr(c.ptr, cName))
|
||||
}
|
||||
|
|
@ -195,6 +195,209 @@ func (s *Solver) Interrupt() {
|
|||
C.Z3_solver_interrupt(s.ctx.ptr, s.ptr)
|
||||
}
|
||||
|
||||
// Units returns the unit clauses (literals) learned by the solver.
|
||||
// Unit clauses are assertions that have been simplified to single literals.
|
||||
// This is useful for debugging and understanding solver behavior.
|
||||
func (s *Solver) Units() []*Expr {
|
||||
vec := C.Z3_solver_get_units(s.ctx.ptr, s.ptr)
|
||||
return astVectorToExprs(s.ctx, vec)
|
||||
}
|
||||
|
||||
// NonUnits returns the non-unit clauses in the solver's current state.
|
||||
// These are clauses that have not been reduced to unit clauses.
|
||||
// This is useful for debugging and understanding solver behavior.
|
||||
func (s *Solver) NonUnits() []*Expr {
|
||||
vec := C.Z3_solver_get_non_units(s.ctx.ptr, s.ptr)
|
||||
return astVectorToExprs(s.ctx, vec)
|
||||
}
|
||||
|
||||
// Trail returns the decision trail of the solver.
|
||||
// The trail contains the sequence of literals assigned during search.
|
||||
// This is useful for understanding the solver's decision history.
|
||||
// Note: This function works primarily with SimpleSolver. For solvers created
|
||||
// using tactics (e.g., NewSolver()), it may return an error.
|
||||
func (s *Solver) Trail() []*Expr {
|
||||
vec := C.Z3_solver_get_trail(s.ctx.ptr, s.ptr)
|
||||
return astVectorToExprs(s.ctx, vec)
|
||||
}
|
||||
|
||||
// TrailLevels returns the decision levels for each literal in the trail.
|
||||
// The returned slice has the same length as the trail, where each element
|
||||
// indicates the decision level at which the corresponding trail literal was assigned.
|
||||
// This is useful for understanding the structure of the search tree.
|
||||
// Note: This function works primarily with SimpleSolver. For solvers created
|
||||
// using tactics (e.g., NewSolver()), it may return an error.
|
||||
func (s *Solver) TrailLevels() []uint {
|
||||
// Get the trail vector directly from the C API
|
||||
trailVec := C.Z3_solver_get_trail(s.ctx.ptr, s.ptr)
|
||||
C.Z3_ast_vector_inc_ref(s.ctx.ptr, trailVec)
|
||||
defer C.Z3_ast_vector_dec_ref(s.ctx.ptr, trailVec)
|
||||
|
||||
n := uint(C.Z3_ast_vector_size(s.ctx.ptr, trailVec))
|
||||
if n == 0 {
|
||||
return []uint{}
|
||||
}
|
||||
|
||||
// Allocate the levels array
|
||||
levels := make([]C.uint, n)
|
||||
|
||||
// Get the levels using the trail vector directly
|
||||
// Safe to pass &levels[0] because we checked n > 0 above
|
||||
C.Z3_solver_get_levels(s.ctx.ptr, s.ptr, trailVec, C.uint(n), &levels[0])
|
||||
|
||||
// Convert to Go slice
|
||||
result := make([]uint, n)
|
||||
for i := uint(0); i < n; i++ {
|
||||
result[i] = uint(levels[i])
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// CongruenceRoot returns the congruence class representative of the given expression.
|
||||
// This returns the root element in the congruence closure for the term.
|
||||
// Note: This function works primarily with SimpleSolver. Terms and variables that
|
||||
// are eliminated during pre-processing are not visible to the congruence closure.
|
||||
func (s *Solver) CongruenceRoot(expr *Expr) *Expr {
|
||||
ast := C.Z3_solver_congruence_root(s.ctx.ptr, s.ptr, expr.ptr)
|
||||
return newExpr(s.ctx, ast)
|
||||
}
|
||||
|
||||
// CongruenceNext returns the next element in the congruence class of the given expression.
|
||||
// This allows iteration through all elements in a congruence class.
|
||||
// Note: This function works primarily with SimpleSolver. Terms and variables that
|
||||
// are eliminated during pre-processing are not visible to the congruence closure.
|
||||
func (s *Solver) CongruenceNext(expr *Expr) *Expr {
|
||||
ast := C.Z3_solver_congruence_next(s.ctx.ptr, s.ptr, expr.ptr)
|
||||
return newExpr(s.ctx, ast)
|
||||
}
|
||||
|
||||
// CongruenceExplain returns an explanation for why two expressions are congruent.
|
||||
// The result is an expression that justifies the congruence between a and b.
|
||||
// Note: This function works primarily with SimpleSolver. Terms and variables that
|
||||
// are eliminated during pre-processing are not visible to the congruence closure.
|
||||
func (s *Solver) CongruenceExplain(a, b *Expr) *Expr {
|
||||
ast := C.Z3_solver_congruence_explain(s.ctx.ptr, s.ptr, a.ptr, b.ptr)
|
||||
return newExpr(s.ctx, ast)
|
||||
}
|
||||
|
||||
// SetInitialValue provides an initial value hint for a variable to the solver.
|
||||
// This can help guide the solver to find solutions more efficiently.
|
||||
// The variable must be a constant or function application, and the value must be
|
||||
// compatible with the variable's sort.
|
||||
func (s *Solver) SetInitialValue(variable, value *Expr) {
|
||||
C.Z3_solver_set_initial_value(s.ctx.ptr, s.ptr, variable.ptr, value.ptr)
|
||||
}
|
||||
|
||||
// Cube extracts a cube (conjunction of literals) from the solver state.
|
||||
// vars is an optional list of variables to use as cube variables; if nil, the solver decides.
|
||||
// cutoff specifies the backtrack level cutoff for cube generation.
|
||||
// Returns a slice of expressions representing the cube, or nil when the search space is exhausted.
|
||||
func (s *Solver) Cube(vars []*Expr, cutoff uint) []*Expr {
|
||||
varVec := C.Z3_mk_ast_vector(s.ctx.ptr)
|
||||
C.Z3_ast_vector_inc_ref(s.ctx.ptr, varVec)
|
||||
defer C.Z3_ast_vector_dec_ref(s.ctx.ptr, varVec)
|
||||
for _, v := range vars {
|
||||
C.Z3_ast_vector_push(s.ctx.ptr, varVec, v.ptr)
|
||||
}
|
||||
result := C.Z3_solver_cube(s.ctx.ptr, s.ptr, varVec, C.uint(cutoff))
|
||||
return astVectorToExprs(s.ctx, result)
|
||||
}
|
||||
|
||||
// GetConsequences retrieves fixed assignments for variables given assumptions.
|
||||
// Returns the status and the set of consequences as implications.
|
||||
func (s *Solver) GetConsequences(assumptions []*Expr, variables []*Expr) (Status, []*Expr) {
|
||||
asmVec := C.Z3_mk_ast_vector(s.ctx.ptr)
|
||||
C.Z3_ast_vector_inc_ref(s.ctx.ptr, asmVec)
|
||||
defer C.Z3_ast_vector_dec_ref(s.ctx.ptr, asmVec)
|
||||
varVec := C.Z3_mk_ast_vector(s.ctx.ptr)
|
||||
C.Z3_ast_vector_inc_ref(s.ctx.ptr, varVec)
|
||||
defer C.Z3_ast_vector_dec_ref(s.ctx.ptr, varVec)
|
||||
consVec := C.Z3_mk_ast_vector(s.ctx.ptr)
|
||||
C.Z3_ast_vector_inc_ref(s.ctx.ptr, consVec)
|
||||
defer C.Z3_ast_vector_dec_ref(s.ctx.ptr, consVec)
|
||||
for _, a := range assumptions {
|
||||
C.Z3_ast_vector_push(s.ctx.ptr, asmVec, a.ptr)
|
||||
}
|
||||
for _, v := range variables {
|
||||
C.Z3_ast_vector_push(s.ctx.ptr, varVec, v.ptr)
|
||||
}
|
||||
r := Status(C.Z3_solver_get_consequences(s.ctx.ptr, s.ptr, asmVec, varVec, consVec))
|
||||
return r, astVectorToExprs(s.ctx, consVec)
|
||||
}
|
||||
|
||||
// SolveFor solves constraints treating given variables symbolically.
|
||||
// variables are the variables to solve for, terms are the substitution terms,
|
||||
// and guards are the Boolean guards for the substitutions.
|
||||
func (s *Solver) SolveFor(variables []*Expr, terms []*Expr, guards []*Expr) {
|
||||
varVec := C.Z3_mk_ast_vector(s.ctx.ptr)
|
||||
C.Z3_ast_vector_inc_ref(s.ctx.ptr, varVec)
|
||||
defer C.Z3_ast_vector_dec_ref(s.ctx.ptr, varVec)
|
||||
termVec := C.Z3_mk_ast_vector(s.ctx.ptr)
|
||||
C.Z3_ast_vector_inc_ref(s.ctx.ptr, termVec)
|
||||
defer C.Z3_ast_vector_dec_ref(s.ctx.ptr, termVec)
|
||||
guardVec := C.Z3_mk_ast_vector(s.ctx.ptr)
|
||||
C.Z3_ast_vector_inc_ref(s.ctx.ptr, guardVec)
|
||||
defer C.Z3_ast_vector_dec_ref(s.ctx.ptr, guardVec)
|
||||
for _, v := range variables {
|
||||
C.Z3_ast_vector_push(s.ctx.ptr, varVec, v.ptr)
|
||||
}
|
||||
for _, t := range terms {
|
||||
C.Z3_ast_vector_push(s.ctx.ptr, termVec, t.ptr)
|
||||
}
|
||||
for _, g := range guards {
|
||||
C.Z3_ast_vector_push(s.ctx.ptr, guardVec, g.ptr)
|
||||
}
|
||||
C.Z3_solver_solve_for(s.ctx.ptr, s.ptr, varVec, termVec, guardVec)
|
||||
}
|
||||
|
||||
// ImportModelConverter imports the model converter from src into this solver.
|
||||
// This transfers model simplifications from one solver instance to another,
|
||||
// useful when combining results from multiple solver instances.
|
||||
func (dst *Solver) ImportModelConverter(src *Solver) {
|
||||
C.Z3_solver_import_model_converter(dst.ctx.ptr, src.ptr, dst.ptr)
|
||||
}
|
||||
|
||||
// Translate creates a copy of the solver in the target context.
|
||||
// This is useful when working with multiple Z3 contexts.
|
||||
func (s *Solver) Translate(target *Context) *Solver {
|
||||
ptr := C.Z3_solver_translate(s.ctx.ptr, s.ptr, target.ptr)
|
||||
newSolver := &Solver{ctx: target, ptr: ptr}
|
||||
C.Z3_solver_inc_ref(target.ptr, ptr)
|
||||
runtime.SetFinalizer(newSolver, func(solver *Solver) {
|
||||
C.Z3_solver_dec_ref(solver.ctx.ptr, solver.ptr)
|
||||
})
|
||||
return newSolver
|
||||
}
|
||||
|
||||
// GetProof returns the proof of unsatisfiability from the last check.
|
||||
// Returns nil if no proof is available (e.g. the result was not UNSAT,
|
||||
// or proof production is disabled).
|
||||
func (s *Solver) GetProof() *Expr {
|
||||
result := C.Z3_solver_get_proof(s.ctx.ptr, s.ptr)
|
||||
if result == nil {
|
||||
return nil
|
||||
}
|
||||
return newExpr(s.ctx, result)
|
||||
}
|
||||
|
||||
// AddSimplifier creates a new solver with the given simplifier attached for
|
||||
// pre-processing assertions before solving.
|
||||
func (s *Solver) AddSimplifier(simplifier *Simplifier) *Solver {
|
||||
ptr := C.Z3_solver_add_simplifier(s.ctx.ptr, s.ptr, simplifier.ptr)
|
||||
newSolver := &Solver{ctx: s.ctx, ptr: ptr}
|
||||
C.Z3_solver_inc_ref(s.ctx.ptr, ptr)
|
||||
runtime.SetFinalizer(newSolver, func(solver *Solver) {
|
||||
C.Z3_solver_dec_ref(solver.ctx.ptr, solver.ptr)
|
||||
})
|
||||
return newSolver
|
||||
}
|
||||
|
||||
// Dimacs converts the solver's Boolean formula to DIMACS CNF format.
|
||||
// If includeNames is true, variable names are included in the output.
|
||||
func (s *Solver) Dimacs(includeNames bool) string {
|
||||
return C.GoString(C.Z3_solver_to_dimacs_string(s.ctx.ptr, s.ptr, C.bool(includeNames)))
|
||||
}
|
||||
|
||||
// Model represents a Z3 model (satisfying assignment).
|
||||
type Model struct {
|
||||
ctx *Context
|
||||
|
|
@ -297,3 +500,78 @@ func (fi *FuncInterp) GetElse() *Expr {
|
|||
func (fi *FuncInterp) GetArity() uint {
|
||||
return uint(C.Z3_func_interp_get_arity(fi.ctx.ptr, fi.ptr))
|
||||
}
|
||||
|
||||
// FuncEntry represents a single entry in a FuncInterp finite map.
|
||||
type FuncEntry struct {
|
||||
ctx *Context
|
||||
ptr C.Z3_func_entry
|
||||
}
|
||||
|
||||
// newFuncEntry creates a new FuncEntry and manages its reference count.
|
||||
func newFuncEntry(ctx *Context, ptr C.Z3_func_entry) *FuncEntry {
|
||||
e := &FuncEntry{ctx: ctx, ptr: ptr}
|
||||
C.Z3_func_entry_inc_ref(ctx.ptr, ptr)
|
||||
runtime.SetFinalizer(e, func(entry *FuncEntry) {
|
||||
C.Z3_func_entry_dec_ref(entry.ctx.ptr, entry.ptr)
|
||||
})
|
||||
return e
|
||||
}
|
||||
|
||||
// GetEntry returns the i-th entry in the function interpretation.
|
||||
func (fi *FuncInterp) GetEntry(i uint) *FuncEntry {
|
||||
return newFuncEntry(fi.ctx, C.Z3_func_interp_get_entry(fi.ctx.ptr, fi.ptr, C.uint(i)))
|
||||
}
|
||||
|
||||
// SetElse sets the else value of the function interpretation.
|
||||
func (fi *FuncInterp) SetElse(val *Expr) {
|
||||
C.Z3_func_interp_set_else(fi.ctx.ptr, fi.ptr, val.ptr)
|
||||
}
|
||||
|
||||
// AddEntry adds a new entry to the function interpretation.
|
||||
// The args slice provides the argument values and val is the return value.
|
||||
func (fi *FuncInterp) AddEntry(args []*Expr, val *Expr) {
|
||||
vec := C.Z3_mk_ast_vector(fi.ctx.ptr)
|
||||
C.Z3_ast_vector_inc_ref(fi.ctx.ptr, vec)
|
||||
defer C.Z3_ast_vector_dec_ref(fi.ctx.ptr, vec)
|
||||
for _, a := range args {
|
||||
C.Z3_ast_vector_push(fi.ctx.ptr, vec, a.ptr)
|
||||
}
|
||||
C.Z3_func_interp_add_entry(fi.ctx.ptr, fi.ptr, vec, val.ptr)
|
||||
}
|
||||
|
||||
// GetValue returns the return value of the function entry.
|
||||
func (e *FuncEntry) GetValue() *Expr {
|
||||
return newExpr(e.ctx, C.Z3_func_entry_get_value(e.ctx.ptr, e.ptr))
|
||||
}
|
||||
|
||||
// GetNumArgs returns the number of arguments in the function entry.
|
||||
func (e *FuncEntry) GetNumArgs() uint {
|
||||
return uint(C.Z3_func_entry_get_num_args(e.ctx.ptr, e.ptr))
|
||||
}
|
||||
|
||||
// GetArg returns the i-th argument of the function entry.
|
||||
func (e *FuncEntry) GetArg(i uint) *Expr {
|
||||
return newExpr(e.ctx, C.Z3_func_entry_get_arg(e.ctx.ptr, e.ptr, C.uint(i)))
|
||||
}
|
||||
|
||||
// HasInterp reports whether the model contains an interpretation for the given declaration.
|
||||
func (m *Model) HasInterp(decl *FuncDecl) bool {
|
||||
return bool(C.Z3_model_has_interp(m.ctx.ptr, m.ptr, decl.ptr))
|
||||
}
|
||||
|
||||
// SortUniverse returns the universe of values for an uninterpreted sort in the model.
|
||||
// The universe is represented as a list of distinct expressions.
|
||||
// Returns nil if the sort is not an uninterpreted sort in this model.
|
||||
func (m *Model) SortUniverse(sort *Sort) []*Expr {
|
||||
vec := C.Z3_model_get_sort_universe(m.ctx.ptr, m.ptr, sort.ptr)
|
||||
if vec == nil {
|
||||
return nil
|
||||
}
|
||||
return astVectorToExprs(m.ctx, vec)
|
||||
}
|
||||
|
||||
// Translate creates a copy of the model in the target context.
|
||||
func (m *Model) Translate(target *Context) *Model {
|
||||
ptr := C.Z3_model_translate(m.ctx.ptr, m.ptr, target.ptr)
|
||||
return newModel(target, ptr)
|
||||
}
|
||||
|
|
|
|||
131
src/api/go/spacer.go
Normal file
131
src/api/go/spacer.go
Normal file
|
|
@ -0,0 +1,131 @@
|
|||
// Copyright (c) Microsoft Corporation 2025
|
||||
// Z3 Go API: Spacer quantifier elimination and model projection functions
|
||||
|
||||
package z3
|
||||
|
||||
/*
|
||||
#include "z3.h"
|
||||
#include <stdlib.h>
|
||||
*/
|
||||
import "C"
|
||||
import "runtime"
|
||||
|
||||
// ASTMap represents a mapping from Z3 ASTs to Z3 ASTs.
|
||||
type ASTMap struct {
|
||||
ctx *Context
|
||||
ptr C.Z3_ast_map
|
||||
}
|
||||
|
||||
// newASTMap creates a new ASTMap and manages its reference count.
|
||||
func newASTMap(ctx *Context, ptr C.Z3_ast_map) *ASTMap {
|
||||
m := &ASTMap{ctx: ctx, ptr: ptr}
|
||||
C.Z3_ast_map_inc_ref(ctx.ptr, ptr)
|
||||
runtime.SetFinalizer(m, func(am *ASTMap) {
|
||||
C.Z3_ast_map_dec_ref(am.ctx.ptr, am.ptr)
|
||||
})
|
||||
return m
|
||||
}
|
||||
|
||||
// MkASTMap creates a new empty AST map.
|
||||
func (c *Context) MkASTMap() *ASTMap {
|
||||
return newASTMap(c, C.Z3_mk_ast_map(c.ptr))
|
||||
}
|
||||
|
||||
// Contains returns true if the map contains the key k.
|
||||
func (m *ASTMap) Contains(k *Expr) bool {
|
||||
return bool(C.Z3_ast_map_contains(m.ctx.ptr, m.ptr, k.ptr))
|
||||
}
|
||||
|
||||
// Find returns the value associated with key k.
|
||||
func (m *ASTMap) Find(k *Expr) *Expr {
|
||||
return newExpr(m.ctx, C.Z3_ast_map_find(m.ctx.ptr, m.ptr, k.ptr))
|
||||
}
|
||||
|
||||
// Insert associates key k with value v in the map.
|
||||
func (m *ASTMap) Insert(k, v *Expr) {
|
||||
C.Z3_ast_map_insert(m.ctx.ptr, m.ptr, k.ptr, v.ptr)
|
||||
}
|
||||
|
||||
// Erase removes the entry with key k from the map.
|
||||
func (m *ASTMap) Erase(k *Expr) {
|
||||
C.Z3_ast_map_erase(m.ctx.ptr, m.ptr, k.ptr)
|
||||
}
|
||||
|
||||
// Reset removes all entries from the map.
|
||||
func (m *ASTMap) Reset() {
|
||||
C.Z3_ast_map_reset(m.ctx.ptr, m.ptr)
|
||||
}
|
||||
|
||||
// Size returns the number of entries in the map.
|
||||
func (m *ASTMap) Size() uint {
|
||||
return uint(C.Z3_ast_map_size(m.ctx.ptr, m.ptr))
|
||||
}
|
||||
|
||||
// Keys returns all keys in the map as an ASTVector.
|
||||
func (m *ASTMap) Keys() *ASTVector {
|
||||
return newASTVector(m.ctx, C.Z3_ast_map_keys(m.ctx.ptr, m.ptr))
|
||||
}
|
||||
|
||||
// String returns the string representation of the map.
|
||||
func (m *ASTMap) String() string {
|
||||
return C.GoString(C.Z3_ast_map_to_string(m.ctx.ptr, m.ptr))
|
||||
}
|
||||
|
||||
// ModelExtrapolate extrapolates a model of a formula.
|
||||
// Given a model m and formula fml, returns an expression that is implied by fml
|
||||
// and is consistent with the model. This is a Spacer-specific function.
|
||||
func (c *Context) ModelExtrapolate(m *Model, fml *Expr) *Expr {
|
||||
return newExpr(c, C.Z3_model_extrapolate(c.ptr, m.ptr, fml.ptr))
|
||||
}
|
||||
|
||||
// QeLite performs best-effort quantifier elimination.
|
||||
// vars is a vector of variables to eliminate, body is the formula.
|
||||
func (c *Context) QeLite(vars *ASTVector, body *Expr) *Expr {
|
||||
return newExpr(c, C.Z3_qe_lite(c.ptr, vars.ptr, body.ptr))
|
||||
}
|
||||
|
||||
// QeModelProject projects variables given a model.
|
||||
// bound is a slice of application expressions representing the variables to project.
|
||||
func (c *Context) QeModelProject(m *Model, bound []*Expr, body *Expr) *Expr {
|
||||
n := len(bound)
|
||||
cBound := make([]C.Z3_app, n)
|
||||
for i, b := range bound {
|
||||
cBound[i] = C.Z3_to_app(c.ptr, b.ptr)
|
||||
}
|
||||
var boundPtr *C.Z3_app
|
||||
if n > 0 {
|
||||
boundPtr = &cBound[0]
|
||||
}
|
||||
return newExpr(c, C.Z3_qe_model_project(c.ptr, m.ptr, C.uint(n), boundPtr, body.ptr))
|
||||
}
|
||||
|
||||
// QeModelProjectSkolem projects variables given a model, storing the skolem witnesses in map_.
|
||||
// bound is a slice of application expressions representing the variables to project.
|
||||
func (c *Context) QeModelProjectSkolem(m *Model, bound []*Expr, body *Expr, map_ *ASTMap) *Expr {
|
||||
n := len(bound)
|
||||
cBound := make([]C.Z3_app, n)
|
||||
for i, b := range bound {
|
||||
cBound[i] = C.Z3_to_app(c.ptr, b.ptr)
|
||||
}
|
||||
var boundPtr *C.Z3_app
|
||||
if n > 0 {
|
||||
boundPtr = &cBound[0]
|
||||
}
|
||||
return newExpr(c, C.Z3_qe_model_project_skolem(c.ptr, m.ptr, C.uint(n), boundPtr, body.ptr, map_.ptr))
|
||||
}
|
||||
|
||||
// QeModelProjectWithWitness projects variables given a model and extracts witnesses.
|
||||
// The map_ is populated with bindings of projected variables to witness terms.
|
||||
// bound is a slice of application expressions representing the variables to project.
|
||||
func (c *Context) QeModelProjectWithWitness(m *Model, bound []*Expr, body *Expr, map_ *ASTMap) *Expr {
|
||||
n := len(bound)
|
||||
cBound := make([]C.Z3_app, n)
|
||||
for i, b := range bound {
|
||||
cBound[i] = C.Z3_to_app(c.ptr, b.ptr)
|
||||
}
|
||||
var boundPtr *C.Z3_app
|
||||
if n > 0 {
|
||||
boundPtr = &cBound[0]
|
||||
}
|
||||
return newExpr(c, C.Z3_qe_model_project_with_witness(c.ptr, m.ptr, C.uint(n), boundPtr, body.ptr, map_.ptr))
|
||||
}
|
||||
|
|
@ -78,6 +78,72 @@ func (c *Context) TacticSkip() *Tactic {
|
|||
return newTactic(c, C.Z3_tactic_skip(c.ptr))
|
||||
}
|
||||
|
||||
// TryFor returns a tactic that applies t for at most ms milliseconds.
|
||||
// If t does not terminate in ms milliseconds, then it fails.
|
||||
func (t *Tactic) TryFor(ms uint) *Tactic {
|
||||
return newTactic(t.ctx, C.Z3_tactic_try_for(t.ctx.ptr, t.ptr, C.uint(ms)))
|
||||
}
|
||||
|
||||
// UsingParams returns a tactic that applies t using the given parameters.
|
||||
func (t *Tactic) UsingParams(params *Params) *Tactic {
|
||||
return newTactic(t.ctx, C.Z3_tactic_using_params(t.ctx.ptr, t.ptr, params.ptr))
|
||||
}
|
||||
|
||||
// GetParamDescrs returns parameter descriptions for the tactic.
|
||||
func (t *Tactic) GetParamDescrs() *ParamDescrs {
|
||||
return newParamDescrs(t.ctx, C.Z3_tactic_get_param_descrs(t.ctx.ptr, t.ptr))
|
||||
}
|
||||
|
||||
// ApplyEx applies the tactic to a goal with the given parameters.
|
||||
func (t *Tactic) ApplyEx(g *Goal, params *Params) *ApplyResult {
|
||||
return newApplyResult(t.ctx, C.Z3_tactic_apply_ex(t.ctx.ptr, t.ptr, g.ptr, params.ptr))
|
||||
}
|
||||
|
||||
// TacticFailIf creates a tactic that fails if the probe p evaluates to false.
|
||||
func (c *Context) TacticFailIf(p *Probe) *Tactic {
|
||||
return newTactic(c, C.Z3_tactic_fail_if(c.ptr, p.ptr))
|
||||
}
|
||||
|
||||
// TacticFailIfNotDecided creates a tactic that fails if the goal is not
|
||||
// trivially satisfiable (empty) or trivially unsatisfiable (contains false).
|
||||
func (c *Context) TacticFailIfNotDecided() *Tactic {
|
||||
return newTactic(c, C.Z3_tactic_fail_if_not_decided(c.ptr))
|
||||
}
|
||||
|
||||
// ParOr creates a tactic that applies the given tactics in parallel.
|
||||
func (c *Context) ParOr(tactics []*Tactic) *Tactic {
|
||||
cTactics := make([]C.Z3_tactic, len(tactics))
|
||||
for i, t := range tactics {
|
||||
cTactics[i] = t.ptr
|
||||
}
|
||||
return newTactic(c, C.Z3_tactic_par_or(c.ptr, C.uint(len(tactics)), &cTactics[0]))
|
||||
}
|
||||
|
||||
// ParAndThen creates a tactic that applies t to a goal and then t2 to every
|
||||
// subgoal produced by t, processing subgoals in parallel.
|
||||
func (t *Tactic) ParAndThen(t2 *Tactic) *Tactic {
|
||||
return newTactic(t.ctx, C.Z3_tactic_par_and_then(t.ctx.ptr, t.ptr, t2.ptr))
|
||||
}
|
||||
|
||||
// GetTacticDescr returns a description of the tactic with the given name.
|
||||
func (c *Context) GetTacticDescr(name string) string {
|
||||
cName := C.CString(name)
|
||||
defer C.free(unsafe.Pointer(cName))
|
||||
return C.GoString(C.Z3_tactic_get_descr(c.ptr, cName))
|
||||
}
|
||||
|
||||
// NewSolverFromTactic creates a solver from the given tactic.
|
||||
// The solver uses the tactic to solve goals.
|
||||
func (c *Context) NewSolverFromTactic(t *Tactic) *Solver {
|
||||
ptr := C.Z3_mk_solver_from_tactic(c.ptr, t.ptr)
|
||||
s := &Solver{ctx: c, ptr: ptr}
|
||||
C.Z3_solver_inc_ref(c.ptr, ptr)
|
||||
runtime.SetFinalizer(s, func(solver *Solver) {
|
||||
C.Z3_solver_dec_ref(solver.ctx.ptr, solver.ptr)
|
||||
})
|
||||
return s
|
||||
}
|
||||
|
||||
// Goal represents a set of formulas that can be solved or transformed.
|
||||
type Goal struct {
|
||||
ctx *Context
|
||||
|
|
@ -134,11 +200,45 @@ func (g *Goal) Reset() {
|
|||
C.Z3_goal_reset(g.ctx.ptr, g.ptr)
|
||||
}
|
||||
|
||||
// Depth returns the depth of the goal.
|
||||
// It tracks how many times the goal was transformed by a tactic.
|
||||
func (g *Goal) Depth() uint {
|
||||
return uint(C.Z3_goal_depth(g.ctx.ptr, g.ptr))
|
||||
}
|
||||
|
||||
// Precision returns the precision of the goal as a uint.
|
||||
// Possible values: 0 = precise, 1 = under-approximation, 2 = over-approximation, 3 = under+over.
|
||||
func (g *Goal) Precision() uint {
|
||||
return uint(C.Z3_goal_precision(g.ctx.ptr, g.ptr))
|
||||
}
|
||||
|
||||
// Translate creates a copy of the goal in the target context.
|
||||
func (g *Goal) Translate(target *Context) *Goal {
|
||||
return newGoal(target, C.Z3_goal_translate(g.ctx.ptr, g.ptr, target.ptr))
|
||||
}
|
||||
|
||||
// ConvertModel converts a model from the original goal into a model for this goal.
|
||||
// Use this when a tactic has transformed the goal and you need a model for the original.
|
||||
func (g *Goal) ConvertModel(m *Model) *Model {
|
||||
return newModel(g.ctx, C.Z3_goal_convert_model(g.ctx.ptr, g.ptr, m.ptr))
|
||||
}
|
||||
|
||||
// String returns the string representation of the goal.
|
||||
func (g *Goal) String() string {
|
||||
return C.GoString(C.Z3_goal_to_string(g.ctx.ptr, g.ptr))
|
||||
}
|
||||
|
||||
// IsInconsistent returns true if the goal contains the formula false.
|
||||
func (g *Goal) IsInconsistent() bool {
|
||||
return bool(C.Z3_goal_inconsistent(g.ctx.ptr, g.ptr))
|
||||
}
|
||||
|
||||
// ToDimacsString converts the goal to a string in DIMACS format.
|
||||
// If includeNames is true, formula names are included as comments.
|
||||
func (g *Goal) ToDimacsString(includeNames bool) string {
|
||||
return C.GoString(C.Z3_goal_to_dimacs_string(g.ctx.ptr, g.ptr, C.bool(includeNames)))
|
||||
}
|
||||
|
||||
// ApplyResult represents the result of applying a tactic to a goal.
|
||||
type ApplyResult struct {
|
||||
ctx *Context
|
||||
|
|
@ -243,6 +343,13 @@ func (p *Probe) Not() *Probe {
|
|||
return newProbe(p.ctx, C.Z3_probe_not(p.ctx.ptr, p.ptr))
|
||||
}
|
||||
|
||||
// GetProbeDescr returns a description of the probe with the given name.
|
||||
func (c *Context) GetProbeDescr(name string) string {
|
||||
cName := C.CString(name)
|
||||
defer C.free(unsafe.Pointer(cName))
|
||||
return C.GoString(C.Z3_probe_get_descr(c.ptr, cName))
|
||||
}
|
||||
|
||||
// Params represents a parameter set.
|
||||
type Params struct {
|
||||
ctx *Context
|
||||
|
|
|
|||
251
src/api/go/z3.go
251
src/api/go/z3.go
|
|
@ -89,6 +89,7 @@ type Context struct {
|
|||
// NewContext creates a new Z3 context with default configuration.
|
||||
func NewContext() *Context {
|
||||
ctx := &Context{ptr: C.Z3_mk_context_rc(C.Z3_mk_config())}
|
||||
C.Z3_enable_concurrent_dec_ref(ctx.ptr)
|
||||
runtime.SetFinalizer(ctx, func(c *Context) {
|
||||
C.Z3_del_context(c.ptr)
|
||||
})
|
||||
|
|
@ -98,6 +99,7 @@ func NewContext() *Context {
|
|||
// NewContextWithConfig creates a new Z3 context with the given configuration.
|
||||
func NewContextWithConfig(cfg *Config) *Context {
|
||||
ctx := &Context{ptr: C.Z3_mk_context_rc(cfg.ptr)}
|
||||
C.Z3_enable_concurrent_dec_ref(ctx.ptr)
|
||||
runtime.SetFinalizer(ctx, func(c *Context) {
|
||||
C.Z3_del_context(c.ptr)
|
||||
})
|
||||
|
|
@ -240,6 +242,45 @@ func newExpr(ctx *Context, ptr C.Z3_ast) *Expr {
|
|||
return expr
|
||||
}
|
||||
|
||||
// intsToCs converts a []int slice to []C.int, returning the slice and
|
||||
// a pointer to its first element (nil if empty).
|
||||
func intsToCs(ints []int) ([]C.int, *C.int) {
|
||||
if len(ints) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
cInts := make([]C.int, len(ints))
|
||||
for i, v := range ints {
|
||||
cInts[i] = C.int(v)
|
||||
}
|
||||
return cInts, &cInts[0]
|
||||
}
|
||||
|
||||
// exprsToASTs converts a []*Expr slice to []C.Z3_ast, returning the slice and
|
||||
// a pointer to its first element (nil if empty).
|
||||
func exprsToASTs(exprs []*Expr) ([]C.Z3_ast, *C.Z3_ast) {
|
||||
if len(exprs) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
cExprs := make([]C.Z3_ast, len(exprs))
|
||||
for i, e := range exprs {
|
||||
cExprs[i] = e.ptr
|
||||
}
|
||||
return cExprs, &cExprs[0]
|
||||
}
|
||||
|
||||
// sortsToCSorts converts a []*Sort slice to []C.Z3_sort, returning the slice and
|
||||
// a pointer to its first element (nil if empty).
|
||||
func sortsToCSorts(sorts []*Sort) ([]C.Z3_sort, *C.Z3_sort) {
|
||||
if len(sorts) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
cSorts := make([]C.Z3_sort, len(sorts))
|
||||
for i, s := range sorts {
|
||||
cSorts[i] = s.ptr
|
||||
}
|
||||
return cSorts, &cSorts[0]
|
||||
}
|
||||
|
||||
// String returns the string representation of the expression.
|
||||
func (e *Expr) String() string {
|
||||
return C.GoString(C.Z3_ast_to_string(e.ctx.ptr, e.ptr))
|
||||
|
|
@ -291,6 +332,21 @@ func newASTVector(ctx *Context, ptr C.Z3_ast_vector) *ASTVector {
|
|||
return v
|
||||
}
|
||||
|
||||
// Size returns the number of ASTs in the vector.
|
||||
func (v *ASTVector) Size() uint {
|
||||
return uint(C.Z3_ast_vector_size(v.ctx.ptr, v.ptr))
|
||||
}
|
||||
|
||||
// Get returns the i-th AST in the vector.
|
||||
func (v *ASTVector) Get(i uint) *Expr {
|
||||
return newExpr(v.ctx, C.Z3_ast_vector_get(v.ctx.ptr, v.ptr, C.uint(i)))
|
||||
}
|
||||
|
||||
// String returns the string representation of the AST vector.
|
||||
func (v *ASTVector) String() string {
|
||||
return C.GoString(C.Z3_ast_vector_to_string(v.ctx.ptr, v.ptr))
|
||||
}
|
||||
|
||||
// ParamDescrs represents parameter descriptions for Z3 objects.
|
||||
type ParamDescrs struct {
|
||||
ctx *Context
|
||||
|
|
@ -353,11 +409,8 @@ func (c *Context) MkAnd(exprs ...*Expr) *Expr {
|
|||
if len(exprs) == 1 {
|
||||
return exprs[0]
|
||||
}
|
||||
cExprs := make([]C.Z3_ast, len(exprs))
|
||||
for i, e := range exprs {
|
||||
cExprs[i] = e.ptr
|
||||
}
|
||||
return newExpr(c, C.Z3_mk_and(c.ptr, C.uint(len(exprs)), &cExprs[0]))
|
||||
_, cExprsPtr := exprsToASTs(exprs)
|
||||
return newExpr(c, C.Z3_mk_and(c.ptr, C.uint(len(exprs)), cExprsPtr))
|
||||
}
|
||||
|
||||
// MkOr creates a disjunction.
|
||||
|
|
@ -368,11 +421,8 @@ func (c *Context) MkOr(exprs ...*Expr) *Expr {
|
|||
if len(exprs) == 1 {
|
||||
return exprs[0]
|
||||
}
|
||||
cExprs := make([]C.Z3_ast, len(exprs))
|
||||
for i, e := range exprs {
|
||||
cExprs[i] = e.ptr
|
||||
}
|
||||
return newExpr(c, C.Z3_mk_or(c.ptr, C.uint(len(exprs)), &cExprs[0]))
|
||||
_, cExprsPtr := exprsToASTs(exprs)
|
||||
return newExpr(c, C.Z3_mk_or(c.ptr, C.uint(len(exprs)), cExprsPtr))
|
||||
}
|
||||
|
||||
// MkNot creates a negation.
|
||||
|
|
@ -407,11 +457,52 @@ func (c *Context) MkDistinct(exprs ...*Expr) *Expr {
|
|||
if len(exprs) <= 1 {
|
||||
return c.MkTrue()
|
||||
}
|
||||
cExprs := make([]C.Z3_ast, len(exprs))
|
||||
for i, e := range exprs {
|
||||
cExprs[i] = e.ptr
|
||||
_, cExprsPtr := exprsToASTs(exprs)
|
||||
return newExpr(c, C.Z3_mk_distinct(c.ptr, C.uint(len(exprs)), cExprsPtr))
|
||||
}
|
||||
|
||||
// Pseudo-Boolean / cardinality constraints
|
||||
|
||||
// MkAtMost encodes p1 + p2 + ... + pn <= k.
|
||||
func (c *Context) MkAtMost(args []*Expr, k uint) *Expr {
|
||||
_, cArgsPtr := exprsToASTs(args)
|
||||
return newExpr(c, C.Z3_mk_atmost(c.ptr, C.uint(len(args)), cArgsPtr, C.uint(k)))
|
||||
}
|
||||
|
||||
// MkAtLeast encodes p1 + p2 + ... + pn >= k.
|
||||
func (c *Context) MkAtLeast(args []*Expr, k uint) *Expr {
|
||||
_, cArgsPtr := exprsToASTs(args)
|
||||
return newExpr(c, C.Z3_mk_atleast(c.ptr, C.uint(len(args)), cArgsPtr, C.uint(k)))
|
||||
}
|
||||
|
||||
// MkPBLe encodes k1*p1 + k2*p2 + ... + kn*pn <= k.
|
||||
func (c *Context) MkPBLe(args []*Expr, coeffs []int, k int) *Expr {
|
||||
if len(args) != len(coeffs) {
|
||||
panic("MkPBLe: args and coeffs must have the same length")
|
||||
}
|
||||
return newExpr(c, C.Z3_mk_distinct(c.ptr, C.uint(len(exprs)), &cExprs[0]))
|
||||
_, cArgsPtr := exprsToASTs(args)
|
||||
_, cCoeffsPtr := intsToCs(coeffs)
|
||||
return newExpr(c, C.Z3_mk_pble(c.ptr, C.uint(len(args)), cArgsPtr, cCoeffsPtr, C.int(k)))
|
||||
}
|
||||
|
||||
// MkPBGe encodes k1*p1 + k2*p2 + ... + kn*pn >= k.
|
||||
func (c *Context) MkPBGe(args []*Expr, coeffs []int, k int) *Expr {
|
||||
if len(args) != len(coeffs) {
|
||||
panic("MkPBGe: args and coeffs must have the same length")
|
||||
}
|
||||
_, cArgsPtr := exprsToASTs(args)
|
||||
_, cCoeffsPtr := intsToCs(coeffs)
|
||||
return newExpr(c, C.Z3_mk_pbge(c.ptr, C.uint(len(args)), cArgsPtr, cCoeffsPtr, C.int(k)))
|
||||
}
|
||||
|
||||
// MkPBEq encodes k1*p1 + k2*p2 + ... + kn*pn = k.
|
||||
func (c *Context) MkPBEq(args []*Expr, coeffs []int, k int) *Expr {
|
||||
if len(args) != len(coeffs) {
|
||||
panic("MkPBEq: args and coeffs must have the same length")
|
||||
}
|
||||
_, cArgsPtr := exprsToASTs(args)
|
||||
_, cCoeffsPtr := intsToCs(coeffs)
|
||||
return newExpr(c, C.Z3_mk_pbeq(c.ptr, C.uint(len(args)), cArgsPtr, cCoeffsPtr, C.int(k)))
|
||||
}
|
||||
|
||||
// FuncDecl represents a function declaration.
|
||||
|
|
@ -460,27 +551,26 @@ func (f *FuncDecl) GetRange() *Sort {
|
|||
|
||||
// MkFuncDecl creates a function declaration.
|
||||
func (c *Context) MkFuncDecl(name *Symbol, domain []*Sort, range_ *Sort) *FuncDecl {
|
||||
cDomain := make([]C.Z3_sort, len(domain))
|
||||
for i, s := range domain {
|
||||
cDomain[i] = s.ptr
|
||||
}
|
||||
var domainPtr *C.Z3_sort
|
||||
if len(domain) > 0 {
|
||||
domainPtr = &cDomain[0]
|
||||
}
|
||||
_, domainPtr := sortsToCSorts(domain)
|
||||
return newFuncDecl(c, C.Z3_mk_func_decl(c.ptr, name.ptr, C.uint(len(domain)), domainPtr, range_.ptr))
|
||||
}
|
||||
|
||||
// MkRecFuncDecl creates a recursive function declaration.
|
||||
// After creating, use AddRecDef to provide the function body.
|
||||
func (c *Context) MkRecFuncDecl(name *Symbol, domain []*Sort, range_ *Sort) *FuncDecl {
|
||||
_, domainPtr := sortsToCSorts(domain)
|
||||
return newFuncDecl(c, C.Z3_mk_rec_func_decl(c.ptr, name.ptr, C.uint(len(domain)), domainPtr, range_.ptr))
|
||||
}
|
||||
|
||||
// AddRecDef adds the definition (body) for a recursive function created with MkRecFuncDecl.
|
||||
func (c *Context) AddRecDef(f *FuncDecl, args []*Expr, body *Expr) {
|
||||
_, argsPtr := exprsToASTs(args)
|
||||
C.Z3_add_rec_def(c.ptr, f.ptr, C.uint(len(args)), argsPtr, body.ptr)
|
||||
}
|
||||
|
||||
// MkApp creates a function application.
|
||||
func (c *Context) MkApp(decl *FuncDecl, args ...*Expr) *Expr {
|
||||
cArgs := make([]C.Z3_ast, len(args))
|
||||
for i, a := range args {
|
||||
cArgs[i] = a.ptr
|
||||
}
|
||||
var argsPtr *C.Z3_ast
|
||||
if len(args) > 0 {
|
||||
argsPtr = &cArgs[0]
|
||||
}
|
||||
_, argsPtr := exprsToASTs(args)
|
||||
return newExpr(c, C.Z3_mk_app(c.ptr, decl.ptr, C.uint(len(args)), argsPtr))
|
||||
}
|
||||
|
||||
|
|
@ -519,6 +609,66 @@ func (e *Expr) Simplify() *Expr {
|
|||
return newExpr(e.ctx, C.Z3_simplify(e.ctx.ptr, e.ptr))
|
||||
}
|
||||
|
||||
// GetDecl returns the function declaration of an application expression.
|
||||
func (e *Expr) GetDecl() *FuncDecl {
|
||||
return newFuncDecl(e.ctx, C.Z3_get_app_decl(e.ctx.ptr, C.Z3_to_app(e.ctx.ptr, e.ptr)))
|
||||
}
|
||||
|
||||
// NumArgs returns the number of arguments of an application expression.
|
||||
func (e *Expr) NumArgs() uint {
|
||||
return uint(C.Z3_get_app_num_args(e.ctx.ptr, C.Z3_to_app(e.ctx.ptr, e.ptr)))
|
||||
}
|
||||
|
||||
// Arg returns the i-th argument of an application expression.
|
||||
func (e *Expr) Arg(i uint) *Expr {
|
||||
return newExpr(e.ctx, C.Z3_get_app_arg(e.ctx.ptr, C.Z3_to_app(e.ctx.ptr, e.ptr), C.uint(i)))
|
||||
}
|
||||
|
||||
// Substitute replaces every occurrence of from[i] in the expression with to[i].
|
||||
// The from and to slices must have the same length.
|
||||
func (e *Expr) Substitute(from, to []*Expr) *Expr {
|
||||
n := len(from)
|
||||
cFrom := make([]C.Z3_ast, n)
|
||||
cTo := make([]C.Z3_ast, n)
|
||||
for i := range from {
|
||||
cFrom[i] = from[i].ptr
|
||||
cTo[i] = to[i].ptr
|
||||
}
|
||||
var fromPtr, toPtr *C.Z3_ast
|
||||
if n > 0 {
|
||||
fromPtr = &cFrom[0]
|
||||
toPtr = &cTo[0]
|
||||
}
|
||||
return newExpr(e.ctx, C.Z3_substitute(e.ctx.ptr, e.ptr, C.uint(n), fromPtr, toPtr))
|
||||
}
|
||||
|
||||
// SubstituteVars replaces free variables in the expression with the expressions in to.
|
||||
// Variable with de-Bruijn index i is replaced with to[i].
|
||||
func (e *Expr) SubstituteVars(to []*Expr) *Expr {
|
||||
_, toPtr := exprsToASTs(to)
|
||||
return newExpr(e.ctx, C.Z3_substitute_vars(e.ctx.ptr, e.ptr, C.uint(len(to)), toPtr))
|
||||
}
|
||||
|
||||
// SubstituteFuns replaces every occurrence of from[i] applied to arguments
|
||||
// with to[i] in the expression.
|
||||
// The from and to slices must have the same length.
|
||||
func (e *Expr) SubstituteFuns(from []*FuncDecl, to []*Expr) *Expr {
|
||||
n := len(from)
|
||||
cFrom := make([]C.Z3_func_decl, n)
|
||||
cTo := make([]C.Z3_ast, n)
|
||||
for i := range from {
|
||||
cFrom[i] = from[i].ptr
|
||||
cTo[i] = to[i].ptr
|
||||
}
|
||||
var fromPtr *C.Z3_func_decl
|
||||
var toPtr *C.Z3_ast
|
||||
if n > 0 {
|
||||
fromPtr = &cFrom[0]
|
||||
toPtr = &cTo[0]
|
||||
}
|
||||
return newExpr(e.ctx, C.Z3_substitute_funs(e.ctx.ptr, e.ptr, C.uint(n), fromPtr, toPtr))
|
||||
}
|
||||
|
||||
// MkTypeVariable creates a type variable sort for use in polymorphic functions and datatypes
|
||||
func (c *Context) MkTypeVariable(name *Symbol) *Sort {
|
||||
return newSort(c, C.Z3_mk_type_variable(c.ptr, name.ptr))
|
||||
|
|
@ -612,12 +762,7 @@ func (q *Quantifier) String() string {
|
|||
|
||||
// MkQuantifier creates a quantifier with patterns
|
||||
func (c *Context) MkQuantifier(isForall bool, weight int, sorts []*Sort, names []*Symbol, body *Expr, patterns []*Pattern) *Quantifier {
|
||||
var forallInt C.bool
|
||||
if isForall {
|
||||
forallInt = true
|
||||
} else {
|
||||
forallInt = false
|
||||
}
|
||||
forallInt := C.bool(isForall)
|
||||
|
||||
numBound := len(sorts)
|
||||
if numBound != len(names) {
|
||||
|
|
@ -660,12 +805,7 @@ func (c *Context) MkQuantifier(isForall bool, weight int, sorts []*Sort, names [
|
|||
|
||||
// MkQuantifierConst creates a quantifier using constant bound variables
|
||||
func (c *Context) MkQuantifierConst(isForall bool, weight int, bound []*Expr, body *Expr, patterns []*Pattern) *Quantifier {
|
||||
var forallInt C.bool
|
||||
if isForall {
|
||||
forallInt = true
|
||||
} else {
|
||||
forallInt = false
|
||||
}
|
||||
forallInt := C.bool(isForall)
|
||||
|
||||
numBound := len(bound)
|
||||
var cBound []C.Z3_app
|
||||
|
|
@ -788,6 +928,33 @@ func (c *Context) MkLambdaConst(bound []*Expr, body *Expr) *Lambda {
|
|||
return newLambda(c, ptr)
|
||||
}
|
||||
|
||||
// SetGlobalParam sets a global Z3 parameter.
|
||||
func SetGlobalParam(id, value string) {
|
||||
cID := C.CString(id)
|
||||
cValue := C.CString(value)
|
||||
defer C.free(unsafe.Pointer(cID))
|
||||
defer C.free(unsafe.Pointer(cValue))
|
||||
C.Z3_global_param_set(cID, cValue)
|
||||
}
|
||||
|
||||
// GetGlobalParam retrieves the value of a global Z3 parameter.
|
||||
// Returns the value and true if the parameter exists, or empty string and false otherwise.
|
||||
func GetGlobalParam(id string) (string, bool) {
|
||||
cID := C.CString(id)
|
||||
defer C.free(unsafe.Pointer(cID))
|
||||
var cValue C.Z3_string
|
||||
ok := C.Z3_global_param_get(cID, &cValue)
|
||||
if ok == C.bool(false) {
|
||||
return "", false
|
||||
}
|
||||
return C.GoString(cValue), true
|
||||
}
|
||||
|
||||
// ResetAllGlobalParams resets all global Z3 parameters to their default values.
|
||||
func ResetAllGlobalParams() {
|
||||
C.Z3_global_param_reset_all()
|
||||
}
|
||||
|
||||
// astVectorToExprs converts a Z3_ast_vector to a slice of Expr.
|
||||
// This function properly manages the reference count of the vector by
|
||||
// incrementing it on entry and decrementing it on exit.
|
||||
|
|
|
|||
|
|
@ -80,6 +80,16 @@ public class AST extends Z3Object implements Comparable<AST>
|
|||
return Native.getAstId(getContext().nCtx(), getNativeObject());
|
||||
}
|
||||
|
||||
/**
|
||||
* The depth of the AST (max nodes on any root-to-leaf path).
|
||||
* @throws Z3Exception on error
|
||||
* @return an int
|
||||
**/
|
||||
public int getDepth()
|
||||
{
|
||||
return Native.getDepth(getContext().nCtx(), getNativeObject());
|
||||
}
|
||||
|
||||
/**
|
||||
* Translates (copies) the AST to the Context {@code ctx}.
|
||||
* @param ctx A context
|
||||
|
|
|
|||
|
|
@ -59,6 +59,16 @@ public class ArraySort<D extends Sort, R extends Sort> extends Sort
|
|||
Native.getArraySortRange(getContext().nCtx(), getNativeObject()));
|
||||
}
|
||||
|
||||
/**
|
||||
* The number of dimensions of the array sort.
|
||||
* @throws Z3Exception on error
|
||||
* @return an int
|
||||
**/
|
||||
public int getArity()
|
||||
{
|
||||
return Native.getArrayArity(getContext().nCtx(), getNativeObject());
|
||||
}
|
||||
|
||||
ArraySort(Context ctx, long obj)
|
||||
{
|
||||
super(ctx, obj);
|
||||
|
|
|
|||
|
|
@ -48,17 +48,18 @@ target_include_directories(z3java PRIVATE
|
|||
"${PROJECT_BINARY_DIR}/src/api"
|
||||
${JNI_INCLUDE_DIRS}
|
||||
)
|
||||
# Add header padding for macOS to allow install_name_tool to modify the dylib
|
||||
# On macOS, set rpath so libz3java.dylib can find libz3.dylib in the same directory,
|
||||
# and add header padding to allow install_name_tool to modify the dylib.
|
||||
if (CMAKE_SYSTEM_NAME STREQUAL "Darwin")
|
||||
set_target_properties(z3java PROPERTIES
|
||||
MACOSX_RPATH TRUE
|
||||
INSTALL_RPATH "@loader_path"
|
||||
BUILD_RPATH "@loader_path"
|
||||
)
|
||||
target_link_options(z3java PRIVATE "-Wl,-headerpad_max_install_names")
|
||||
endif()
|
||||
# FIXME: Should this library have SONAME and VERSION set?
|
||||
|
||||
# On macOS, add headerpad for install_name_tool compatibility
|
||||
if(CMAKE_SYSTEM_NAME STREQUAL "Darwin")
|
||||
target_link_options(z3java PRIVATE "-Wl,-headerpad_max_install_names")
|
||||
endif()
|
||||
|
||||
# This prevents CMake from automatically defining ``z3java_EXPORTS``
|
||||
set_property(TARGET z3java PROPERTY DEFINE_SYMBOL "")
|
||||
|
||||
|
|
@ -124,6 +125,7 @@ set(Z3_JAVA_JAR_SOURCE_FILES
|
|||
FiniteDomainExpr.java
|
||||
FiniteDomainNum.java
|
||||
FiniteDomainSort.java
|
||||
FiniteSetSort.java
|
||||
Fixedpoint.java
|
||||
FPExpr.java
|
||||
FPNum.java
|
||||
|
|
|
|||
|
|
@ -1152,6 +1152,27 @@ public class Context implements AutoCloseable {
|
|||
return new BoolExpr(this, Native.mkIsInt(nCtx(), t.getNativeObject()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the absolute value of an arithmetic expression.
|
||||
* Remarks: The argument must have integer or real sort.
|
||||
**/
|
||||
public <R extends ArithSort> ArithExpr<R> mkAbs(Expr<? extends R> arg)
|
||||
{
|
||||
checkContextMatch(arg);
|
||||
return (ArithExpr<R>) Expr.create(this, Native.mkAbs(nCtx(), arg.getNativeObject()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an integer divisibility predicate (t1 divides t2).
|
||||
* Remarks: Both arguments must have integer sort.
|
||||
**/
|
||||
public BoolExpr mkDivides(Expr<IntSort> t1, Expr<IntSort> t2)
|
||||
{
|
||||
checkContextMatch(t1);
|
||||
checkContextMatch(t2);
|
||||
return new BoolExpr(this, Native.mkDivides(nCtx(), t1.getNativeObject(), t2.getNativeObject()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Bitwise negation.
|
||||
* Remarks: The argument must have a bit-vector
|
||||
|
|
@ -1999,6 +2020,19 @@ public class Context implements AutoCloseable {
|
|||
Native.mkArrayDefault(nCtx(), array.getNativeObject()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an as-array expression from a function declaration.
|
||||
* @param f the function declaration to lift into an array.
|
||||
* Must have exactly one domain sort.
|
||||
* @see #mkTermArray(Expr)
|
||||
* @see #mkMap(FuncDecl, Expr[])
|
||||
**/
|
||||
public final <D extends Sort, R extends Sort> ArrayExpr<D, R> mkAsArray(FuncDecl<R> f)
|
||||
{
|
||||
checkContextMatch(f);
|
||||
return (ArrayExpr<D, R>) Expr.create(this, Native.mkAsArray(nCtx(), f.getNativeObject()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create Extentionality index. Two arrays are equal if and only if they are equal on the index returned by MkArrayExt.
|
||||
**/
|
||||
|
|
@ -2134,6 +2168,145 @@ public class Context implements AutoCloseable {
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
* Finite Sets
|
||||
*/
|
||||
|
||||
/**
|
||||
* Create a finite set sort over the given element sort.
|
||||
**/
|
||||
public final FiniteSetSort mkFiniteSetSort(Sort elemSort)
|
||||
{
|
||||
checkContextMatch(elemSort);
|
||||
return new FiniteSetSort(this, elemSort);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a sort is a finite set sort.
|
||||
**/
|
||||
public final boolean isFiniteSetSort(Sort s)
|
||||
{
|
||||
checkContextMatch(s);
|
||||
return Native.isFiniteSetSort(nCtx(), s.getNativeObject());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the element sort (basis) of a finite set sort.
|
||||
**/
|
||||
public final Sort getFiniteSetSortBasis(Sort s)
|
||||
{
|
||||
checkContextMatch(s);
|
||||
return Sort.create(this, Native.getFiniteSetSortBasis(nCtx(), s.getNativeObject()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an empty finite set.
|
||||
**/
|
||||
public final Expr mkFiniteSetEmpty(Sort setSort)
|
||||
{
|
||||
checkContextMatch(setSort);
|
||||
return Expr.create(this, Native.mkFiniteSetEmpty(nCtx(), setSort.getNativeObject()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a singleton finite set.
|
||||
**/
|
||||
public final Expr mkFiniteSetSingleton(Expr elem)
|
||||
{
|
||||
checkContextMatch(elem);
|
||||
return Expr.create(this, Native.mkFiniteSetSingleton(nCtx(), elem.getNativeObject()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the union of two finite sets.
|
||||
**/
|
||||
public final Expr mkFiniteSetUnion(Expr s1, Expr s2)
|
||||
{
|
||||
checkContextMatch(s1);
|
||||
checkContextMatch(s2);
|
||||
return Expr.create(this, Native.mkFiniteSetUnion(nCtx(), s1.getNativeObject(), s2.getNativeObject()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the intersection of two finite sets.
|
||||
**/
|
||||
public final Expr mkFiniteSetIntersect(Expr s1, Expr s2)
|
||||
{
|
||||
checkContextMatch(s1);
|
||||
checkContextMatch(s2);
|
||||
return Expr.create(this, Native.mkFiniteSetIntersect(nCtx(), s1.getNativeObject(), s2.getNativeObject()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the difference of two finite sets.
|
||||
**/
|
||||
public final Expr mkFiniteSetDifference(Expr s1, Expr s2)
|
||||
{
|
||||
checkContextMatch(s1);
|
||||
checkContextMatch(s2);
|
||||
return Expr.create(this, Native.mkFiniteSetDifference(nCtx(), s1.getNativeObject(), s2.getNativeObject()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Check for membership in a finite set.
|
||||
**/
|
||||
public final BoolExpr mkFiniteSetMember(Expr elem, Expr set)
|
||||
{
|
||||
checkContextMatch(elem);
|
||||
checkContextMatch(set);
|
||||
return (BoolExpr) Expr.create(this, Native.mkFiniteSetMember(nCtx(), elem.getNativeObject(), set.getNativeObject()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the cardinality of a finite set.
|
||||
**/
|
||||
public final Expr mkFiniteSetSize(Expr set)
|
||||
{
|
||||
checkContextMatch(set);
|
||||
return Expr.create(this, Native.mkFiniteSetSize(nCtx(), set.getNativeObject()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if one finite set is a subset of another.
|
||||
**/
|
||||
public final BoolExpr mkFiniteSetSubset(Expr s1, Expr s2)
|
||||
{
|
||||
checkContextMatch(s1);
|
||||
checkContextMatch(s2);
|
||||
return (BoolExpr) Expr.create(this, Native.mkFiniteSetSubset(nCtx(), s1.getNativeObject(), s2.getNativeObject()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Map a function over all elements in a finite set.
|
||||
**/
|
||||
public final Expr mkFiniteSetMap(Expr f, Expr set)
|
||||
{
|
||||
checkContextMatch(f);
|
||||
checkContextMatch(set);
|
||||
return Expr.create(this, Native.mkFiniteSetMap(nCtx(), f.getNativeObject(), set.getNativeObject()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter a finite set with a predicate.
|
||||
**/
|
||||
public final Expr mkFiniteSetFilter(Expr f, Expr set)
|
||||
{
|
||||
checkContextMatch(f);
|
||||
checkContextMatch(set);
|
||||
return Expr.create(this, Native.mkFiniteSetFilter(nCtx(), f.getNativeObject(), set.getNativeObject()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a finite set containing integers in the range [low, high].
|
||||
**/
|
||||
public final Expr mkFiniteSetRange(Expr low, Expr high)
|
||||
{
|
||||
checkContextMatch(low);
|
||||
checkContextMatch(high);
|
||||
return Expr.create(this, Native.mkFiniteSetRange(nCtx(), low.getNativeObject(), high.getNativeObject()));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sequences, Strings and regular expressions.
|
||||
*/
|
||||
|
|
@ -4443,6 +4616,38 @@ public class Context implements AutoCloseable {
|
|||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a piecewise linear order.
|
||||
* @param index The index of the order.
|
||||
* @param sort The sort of the order.
|
||||
*/
|
||||
public final <R extends Sort> FuncDecl<BoolSort> mkPiecewiseLinearOrder(R sort, int index) {
|
||||
return (FuncDecl<BoolSort>) FuncDecl.create(
|
||||
this,
|
||||
Native.mkPiecewiseLinearOrder(
|
||||
nCtx(),
|
||||
sort.getNativeObject(),
|
||||
index
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a tree order.
|
||||
* @param index The index of the order.
|
||||
* @param sort The sort of the order.
|
||||
*/
|
||||
public final <R extends Sort> FuncDecl<BoolSort> mkTreeOrder(R sort, int index) {
|
||||
return (FuncDecl<BoolSort>) FuncDecl.create(
|
||||
this,
|
||||
Native.mkTreeOrder(
|
||||
nCtx(),
|
||||
sort.getNativeObject(),
|
||||
index
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the nonzero subresultants of p and q with respect to the "variable" x.
|
||||
* Note that any subterm that cannot be viewed as a polynomial is assumed to be a variable.
|
||||
|
|
|
|||
|
|
@ -33,6 +33,17 @@ public class DatatypeSort<R> extends Sort
|
|||
getNativeObject());
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates whether the datatype sort is recursive.
|
||||
* @throws Z3Exception on error
|
||||
* @return a boolean
|
||||
**/
|
||||
public boolean isRecursive()
|
||||
{
|
||||
return Native.isRecursiveDatatypeSort(getContext().nCtx(),
|
||||
getNativeObject());
|
||||
}
|
||||
|
||||
/**
|
||||
* The constructors.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -92,6 +92,11 @@ public class EnumSort<R> extends Sort
|
|||
return new FuncDecl<>(getContext(), Native.getDatatypeSortRecognizer(getContext().nCtx(), getNativeObject(), inx));
|
||||
}
|
||||
|
||||
EnumSort(Context ctx, long obj)
|
||||
{
|
||||
super(ctx, obj);
|
||||
}
|
||||
|
||||
EnumSort(Context ctx, Symbol name, Symbol[] enumNames)
|
||||
{
|
||||
super(ctx, Native.mkEnumerationSort(ctx.nCtx(),
|
||||
|
|
|
|||
|
|
@ -244,6 +244,15 @@ public class Expr<R extends Sort> extends AST
|
|||
return Native.isNumeralAst(getContext().nCtx(), getNativeObject());
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the numeral value as a double.
|
||||
* The expression must be a numeral or an algebraic number.
|
||||
**/
|
||||
public double getNumeralDouble()
|
||||
{
|
||||
return Native.getNumeralDouble(getContext().nCtx(), getNativeObject());
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates whether the term is well-sorted.
|
||||
*
|
||||
|
|
@ -306,6 +315,26 @@ public class Expr<R extends Sort> extends AST
|
|||
return Native.isAlgebraicNumber(getContext().nCtx(), getNativeObject());
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates whether the term is ground (contains no free variables).
|
||||
* @throws Z3Exception on error
|
||||
* @return a boolean
|
||||
**/
|
||||
public boolean isGround()
|
||||
{
|
||||
return Native.isGround(getContext().nCtx(), getNativeObject());
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates whether the term is a lambda expression.
|
||||
* @throws Z3Exception on error
|
||||
* @return a boolean
|
||||
**/
|
||||
public boolean isLambda()
|
||||
{
|
||||
return Native.isLambda(getContext().nCtx(), getNativeObject());
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates whether the term has Boolean sort.
|
||||
* @throws Z3Exception on error
|
||||
|
|
|
|||
|
|
@ -32,7 +32,17 @@ public class FPExpr extends Expr<FPSort>
|
|||
* @throws Z3Exception
|
||||
*/
|
||||
public int getSBits() { return ((FPSort)getSort()).getSBits(); }
|
||||
|
||||
|
||||
/**
|
||||
* Indicates whether the floating-point expression is a numeral.
|
||||
* @throws Z3Exception on error
|
||||
* @return a boolean
|
||||
**/
|
||||
public boolean isNumeral()
|
||||
{
|
||||
return Native.fpaIsNumeral(getContext().nCtx(), getNativeObject());
|
||||
}
|
||||
|
||||
public FPExpr(Context ctx, long obj)
|
||||
{
|
||||
super(ctx, obj);
|
||||
|
|
|
|||
42
src/api/java/FiniteSetSort.java
Normal file
42
src/api/java/FiniteSetSort.java
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
/**
|
||||
Copyright (c) 2024 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
FiniteSetSort.java
|
||||
|
||||
Abstract:
|
||||
|
||||
Author:
|
||||
|
||||
GitHub Copilot
|
||||
|
||||
Notes:
|
||||
|
||||
**/
|
||||
|
||||
package com.microsoft.z3;
|
||||
|
||||
/**
|
||||
* Finite set sorts.
|
||||
**/
|
||||
public class FiniteSetSort extends Sort
|
||||
{
|
||||
FiniteSetSort(Context ctx, long obj)
|
||||
{
|
||||
super(ctx, obj);
|
||||
}
|
||||
|
||||
FiniteSetSort(Context ctx, Sort elemSort)
|
||||
{
|
||||
super(ctx, Native.mkFiniteSetSort(ctx.nCtx(), elemSort.getNativeObject()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the element sort (basis) of this finite set sort.
|
||||
**/
|
||||
public Sort getBasis()
|
||||
{
|
||||
return Sort.create(getContext(), Native.getFiniteSetSortBasis(getContext().nCtx(), getNativeObject()));
|
||||
}
|
||||
}
|
||||
|
|
@ -52,6 +52,33 @@ public class IntNum extends IntExpr
|
|||
return res.value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the unsigned 32-bit value.
|
||||
* The returned Java {@code int} holds the raw bit pattern;
|
||||
* use {@code Integer.toUnsignedLong(v)} for unsigned interpretation.
|
||||
**/
|
||||
public int getUint()
|
||||
{
|
||||
Native.IntPtr res = new Native.IntPtr();
|
||||
if (!Native.getNumeralUint(getContext().nCtx(), getNativeObject(), res))
|
||||
throw new Z3Exception("Numeral is not a uint");
|
||||
return res.value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the unsigned 64-bit value.
|
||||
* The returned Java {@code long} holds the raw bit pattern;
|
||||
* use {@code Long.toUnsignedString(v)} or {@link #getBigInteger()}
|
||||
* for values exceeding {@code Long.MAX_VALUE}.
|
||||
**/
|
||||
public long getUint64()
|
||||
{
|
||||
Native.LongPtr res = new Native.LongPtr();
|
||||
if (!Native.getNumeralUint64(getContext().nCtx(), getNativeObject(), res))
|
||||
throw new Z3Exception("Numeral is not a uint64");
|
||||
return res.value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the BigInteger value.
|
||||
**/
|
||||
|
|
|
|||
|
|
@ -154,7 +154,7 @@ static void decide_eh(void* _p, Z3_solver_callback cb, Z3_ast _val, unsigned bit
|
|||
info->jenv->CallVoidMethod(info->jobj, info->decide, (jlong)_val, bit, is_pos);
|
||||
}
|
||||
|
||||
static jboolean on_binding_eh(void* _p, Z3_solver_callback cb, Z3_ast _q, Z3_ast _inst) {
|
||||
[[maybe_unused]] static jboolean on_binding_eh(void* _p, Z3_solver_callback cb, Z3_ast _q, Z3_ast _inst) {
|
||||
JavaInfo *info = static_cast<JavaInfo*>(_p);
|
||||
ScopedCB scoped(info, cb);
|
||||
return info->jenv->CallBooleanMethod(info->jobj, info->on_binding, (jlong)_q, (jlong)_inst);
|
||||
|
|
@ -241,3 +241,40 @@ DLL_VIS JNIEXPORT jboolean JNICALL Java_com_microsoft_z3_Native_propagateNextSpl
|
|||
Z3_solver_callback cb = info->cb;
|
||||
return (jboolean) Z3_solver_next_split((Z3_context)ctx, cb, (Z3_ast)e, idx, Z3_lbool(phase));
|
||||
}
|
||||
|
||||
struct JavaOnClauseInfo {
|
||||
JNIEnv *jenv = nullptr;
|
||||
jobject jobj = nullptr;
|
||||
jmethodID on_clause = nullptr;
|
||||
};
|
||||
|
||||
static void java_on_clause_eh(void* _p, Z3_ast proof_hint, unsigned n, unsigned const* deps, Z3_ast_vector literals) {
|
||||
JavaOnClauseInfo *info = static_cast<JavaOnClauseInfo*>(_p);
|
||||
jintArray jdeps = info->jenv->NewIntArray((jsize)n);
|
||||
info->jenv->SetIntArrayRegion(jdeps, 0, (jsize)n, (jint*)deps);
|
||||
info->jenv->CallVoidMethod(info->jobj, info->on_clause, (jlong)proof_hint, jdeps, (jlong)literals);
|
||||
info->jenv->DeleteLocalRef(jdeps);
|
||||
}
|
||||
|
||||
DLL_VIS JNIEXPORT jlong JNICALL Java_com_microsoft_z3_Native_onClauseInit(JNIEnv *jenv, jclass cls, jobject jobj, jlong ctx, jlong solver) {
|
||||
JavaOnClauseInfo *info = new JavaOnClauseInfo;
|
||||
info->jenv = jenv;
|
||||
info->jobj = jenv->NewGlobalRef(jobj);
|
||||
jclass jcls = jenv->GetObjectClass(info->jobj);
|
||||
info->on_clause = jenv->GetMethodID(jcls, "onClauseWrapper", "(J[IJ)V");
|
||||
if (!info->on_clause) {
|
||||
jenv->DeleteGlobalRef(info->jobj);
|
||||
delete info;
|
||||
return 0;
|
||||
}
|
||||
Z3_solver_register_on_clause((Z3_context)ctx, (Z3_solver)solver, info, java_on_clause_eh);
|
||||
return (jlong)info;
|
||||
}
|
||||
|
||||
DLL_VIS JNIEXPORT void JNICALL Java_com_microsoft_z3_Native_onClauseDestroy(JNIEnv *jenv, jclass cls, jlong javainfo) {
|
||||
JavaOnClauseInfo *info = (JavaOnClauseInfo*)javainfo;
|
||||
if (info) {
|
||||
info->jenv->DeleteGlobalRef(info->jobj);
|
||||
delete info;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
85
src/api/java/OnClause.java
Normal file
85
src/api/java/OnClause.java
Normal file
|
|
@ -0,0 +1,85 @@
|
|||
/**
|
||||
Copyright (c) 2012-2014 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
OnClause.java
|
||||
|
||||
Abstract:
|
||||
|
||||
Callback on clause inferences
|
||||
|
||||
Author:
|
||||
|
||||
Nikolaj Bjorner (nbjorner) 2022-10-19
|
||||
|
||||
Notes:
|
||||
|
||||
**/
|
||||
|
||||
package com.microsoft.z3;
|
||||
|
||||
/**
|
||||
* Clause inference callback.
|
||||
* <p>
|
||||
* Allows users to observe clauses learned during solving.
|
||||
* Useful for custom learning strategies, clause sharing in parallel solvers,
|
||||
* debugging, and proof extraction.
|
||||
* </p>
|
||||
* <p>
|
||||
* Usage: create an instance, override {@link #onClause(Expr, int[], ASTVector)},
|
||||
* and close the instance when done.
|
||||
* </p>
|
||||
**/
|
||||
public class OnClause implements AutoCloseable {
|
||||
|
||||
private long javainfo;
|
||||
private final Context ctx;
|
||||
|
||||
/**
|
||||
* Creates an on-clause callback for the given solver.
|
||||
*
|
||||
* @param ctx The Z3 context
|
||||
* @param solver The solver to register the callback with
|
||||
* @throws Z3Exception
|
||||
**/
|
||||
public OnClause(Context ctx, Solver solver) {
|
||||
this.ctx = ctx;
|
||||
javainfo = Native.onClauseInit(this, ctx.nCtx(), solver.getNativeObject());
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when a clause is inferred during solving.
|
||||
* <p>
|
||||
* The life-time of {@code proof_hint} and {@code literals} is limited to
|
||||
* the scope of this callback. If you want to store them, you must duplicate
|
||||
* the expressions or extract the literals before returning.
|
||||
* </p>
|
||||
*
|
||||
* @param proof_hint A partial or comprehensive derivation justifying the inference (may be null)
|
||||
* @param deps Dependency indices
|
||||
* @param literals The inferred clause as a vector of literals
|
||||
**/
|
||||
public void onClause(Expr<?> proof_hint, int[] deps, ASTVector literals) {}
|
||||
|
||||
/**
|
||||
* Internal wrapper called from JNI. Do not override.
|
||||
**/
|
||||
final void onClauseWrapper(long proofHintPtr, int[] deps, long literalsPtr) {
|
||||
Expr<?> proof_hint = proofHintPtr != 0 ? (Expr<?>) Expr.create(ctx, proofHintPtr) : null;
|
||||
ASTVector literals = new ASTVector(ctx, literalsPtr);
|
||||
onClause(proof_hint, deps, literals);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unregisters the callback and frees associated resources.
|
||||
* Must be called when the callback is no longer needed.
|
||||
**/
|
||||
@Override
|
||||
public void close() {
|
||||
if (javainfo != 0) {
|
||||
Native.onClauseDestroy(javainfo);
|
||||
javainfo = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -397,6 +397,22 @@ public class Optimize extends Z3Object {
|
|||
return objectives.ToExprArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set an initial value for a variable to guide the optimizer's search heuristics.
|
||||
* This can improve performance when a good initial value is known for the variable.
|
||||
*
|
||||
* @param var The variable to set an initial value for
|
||||
* @param value The initial value for the variable
|
||||
* @throws Z3Exception
|
||||
**/
|
||||
public void setInitialValue(Expr<?> var, Expr<?> value)
|
||||
{
|
||||
getContext().checkContextMatch(var);
|
||||
getContext().checkContextMatch(value);
|
||||
Native.optimizeSetInitialValue(getContext().nCtx(), getNativeObject(),
|
||||
var.getNativeObject(), value.getNativeObject());
|
||||
}
|
||||
|
||||
/**
|
||||
* Optimize statistics.
|
||||
**/
|
||||
|
|
|
|||
|
|
@ -60,6 +60,34 @@ public class RatNum extends RealExpr
|
|||
return new BigInteger(n.toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the numerator and denominator as 64-bit integers.
|
||||
* Throws if the value does not fit in 64-bit integers.
|
||||
* @return a two-element array [numerator, denominator]
|
||||
**/
|
||||
public long[] getSmall()
|
||||
{
|
||||
Native.LongPtr num = new Native.LongPtr();
|
||||
Native.LongPtr den = new Native.LongPtr();
|
||||
if (!Native.getNumeralSmall(getContext().nCtx(), getNativeObject(), num, den))
|
||||
throw new Z3Exception("Numeral does not fit in int64");
|
||||
return new long[] { num.value, den.value };
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the numerator and denominator as 64-bit integers.
|
||||
* Returns null if the value does not fit in 64-bit integers.
|
||||
* @return a two-element array [numerator, denominator], or null
|
||||
**/
|
||||
public long[] getRationalInt64()
|
||||
{
|
||||
Native.LongPtr num = new Native.LongPtr();
|
||||
Native.LongPtr den = new Native.LongPtr();
|
||||
if (!Native.getNumeralRationalInt64(getContext().nCtx(), getNativeObject(), num, den))
|
||||
return null;
|
||||
return new long[] { num.value, den.value };
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string representation in decimal notation.
|
||||
* Remarks: The result
|
||||
|
|
|
|||
|
|
@ -464,6 +464,74 @@ public class Solver extends Z3Object {
|
|||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the congruence class representative of the given expression.
|
||||
* This is useful for querying the equality reasoning performed by the solver.
|
||||
*
|
||||
* @param t The expression to find the congruence root for
|
||||
* @return The root expression of the congruence class
|
||||
* @throws Z3Exception
|
||||
**/
|
||||
public Expr<?> congruenceRoot(Expr<?> t)
|
||||
{
|
||||
getContext().checkContextMatch(t);
|
||||
return Expr.create(getContext(),
|
||||
Native.solverCongruenceRoot(getContext().nCtx(), getNativeObject(), t.getNativeObject()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the next element in the congruence class of the given expression.
|
||||
* The congruence class forms a circular linked list.
|
||||
*
|
||||
* @param t The expression to find the next congruent expression for
|
||||
* @return The next expression in the congruence class
|
||||
* @throws Z3Exception
|
||||
**/
|
||||
public Expr<?> congruenceNext(Expr<?> t)
|
||||
{
|
||||
getContext().checkContextMatch(t);
|
||||
return Expr.create(getContext(),
|
||||
Native.solverCongruenceNext(getContext().nCtx(), getNativeObject(), t.getNativeObject()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an explanation for why two expressions are congruent.
|
||||
*
|
||||
* @param a First expression
|
||||
* @param b Second expression
|
||||
* @return An expression explaining the congruence between a and b
|
||||
* @throws Z3Exception
|
||||
**/
|
||||
public Expr<?> congruenceExplain(Expr<?> a, Expr<?> b)
|
||||
{
|
||||
getContext().checkContextMatch(a);
|
||||
getContext().checkContextMatch(b);
|
||||
return Expr.create(getContext(),
|
||||
Native.solverCongruenceExplain(getContext().nCtx(), getNativeObject(),
|
||||
a.getNativeObject(), b.getNativeObject()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Solve constraints for given variables, replacing their occurrences by terms.
|
||||
* Guards are used to guard substitutions.
|
||||
*
|
||||
* @param variables Array of variables to solve for
|
||||
* @param terms Array of terms to substitute for the variables
|
||||
* @param guards Array of Boolean guards for the substitutions
|
||||
* @throws Z3Exception
|
||||
**/
|
||||
public void solveFor(Expr<?>[] variables, Expr<?>[] terms, BoolExpr[] guards)
|
||||
{
|
||||
ASTVector vars = new ASTVector(getContext());
|
||||
ASTVector termVec = new ASTVector(getContext());
|
||||
ASTVector guardVec = new ASTVector(getContext());
|
||||
for (Expr<?> v : variables) vars.push(v);
|
||||
for (Expr<?> t : terms) termVec.push(t);
|
||||
for (BoolExpr g : guards) guardVec.push(g);
|
||||
Native.solverSolveFor(getContext().nCtx(), getNativeObject(),
|
||||
vars.getNativeObject(), termVec.getNativeObject(), guardVec.getNativeObject());
|
||||
}
|
||||
|
||||
/**
|
||||
* Set an initial value for a variable to guide the solver's search heuristics.
|
||||
* This can improve performance when good initial values are known for the problem domain.
|
||||
|
|
@ -480,6 +548,16 @@ public class Solver extends Z3Object {
|
|||
var.getNativeObject(), value.getNativeObject());
|
||||
}
|
||||
|
||||
/**
|
||||
* Import model converter from other solver.
|
||||
*
|
||||
* @param src The solver to import the model converter from
|
||||
**/
|
||||
public void importModelConverter(Solver src)
|
||||
{
|
||||
Native.solverImportModelConverter(getContext().nCtx(), src.getNativeObject(), getNativeObject());
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a clone of the current solver with respect to{@code ctx}.
|
||||
*/
|
||||
|
|
@ -488,6 +566,29 @@ public class Solver extends Z3Object {
|
|||
return new Solver(ctx, Native.solverTranslate(getContext().nCtx(), getNativeObject(), ctx.nCtx()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new solver with pre-processing simplification attached.
|
||||
*
|
||||
* @param simplifier The simplifier to attach for pre-processing
|
||||
* @return A new solver with the simplifier applied
|
||||
**/
|
||||
public Solver addSimplifier(Simplifier simplifier)
|
||||
{
|
||||
return new Solver(getContext(), Native.solverAddSimplifier(
|
||||
getContext().nCtx(), getNativeObject(), simplifier.getNativeObject()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the solver's Boolean formula to DIMACS CNF format.
|
||||
*
|
||||
* @param includeNames If true, include variable names in the DIMACS output
|
||||
* @return A string containing the DIMACS CNF representation
|
||||
**/
|
||||
public String toDimacs(boolean includeNames)
|
||||
{
|
||||
return Native.solverToDimacsString(getContext().nCtx(), getNativeObject(), includeNames);
|
||||
}
|
||||
|
||||
/**
|
||||
* Solver statistics.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -125,6 +125,17 @@ public class Sort extends AST
|
|||
case Z3_BV_SORT:
|
||||
return new BitVecSort(ctx, obj);
|
||||
case Z3_DATATYPE_SORT:
|
||||
int n = Native.getDatatypeSortNumConstructors(ctx.nCtx(), obj);
|
||||
boolean isEnum = true;
|
||||
for (int i = 0; i < n && isEnum; i++) {
|
||||
long ctor = Native.getDatatypeSortConstructor(ctx.nCtx(), obj, i);
|
||||
if (Native.getDomainSize(ctx.nCtx(), ctor) != 0) {
|
||||
isEnum = false;
|
||||
}
|
||||
}
|
||||
if (isEnum) {
|
||||
return new EnumSort<>(ctx, obj);
|
||||
}
|
||||
return new DatatypeSort<>(ctx, obj);
|
||||
case Z3_INT_SORT:
|
||||
return new IntSort(ctx, obj);
|
||||
|
|
|
|||
|
|
@ -16,6 +16,17 @@ const {
|
|||
|
||||
This package has different initialization for browser and node. Your bundler and node should choose good version automatically, but you can import the one you need manually - `const { init } = require('z3-solver/node');` or `const { init } = require('z3-solver/browser');`.
|
||||
|
||||
The `init` function also accepts an optional Emscripten module overrides object. This is useful in runtimes such as Deno where you may want to provide a wasm load path explicitly instead of relying on filesystem reads. In Deno 2.1+, `import.meta.resolve(...)` returns a string synchronously, so it can be used directly in `locateFile`. For example:
|
||||
|
||||
```typescript
|
||||
import { init } from 'npm:z3-solver';
|
||||
|
||||
const api = await init({
|
||||
locateFile: (file, _prefix): string =>
|
||||
import.meta.resolve(`npm:z3-solver/build/${file}`), // _prefix is unused here
|
||||
});
|
||||
```
|
||||
|
||||
### Limitations
|
||||
|
||||
The package requires threads, which means you'll need to be running in an environment which supports `SharedArrayBuffer`. In browsers, in addition to ensuring the browser has implemented `SharedArrayBuffer`, you'll need to serve your page with [special headers](https://web.dev/coop-coep/). There's a [neat trick](https://github.com/gzuidhof/coi-serviceworker) for doing that client-side on e.g. Github Pages, though you shouldn't use that trick in more complex applications.
|
||||
|
|
|
|||
71
src/api/js/package-lock.json
generated
71
src/api/js/package-lock.json
generated
|
|
@ -5400,10 +5400,20 @@
|
|||
"dev": true
|
||||
},
|
||||
"node_modules/linkify-it": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-5.0.0.tgz",
|
||||
"integrity": "sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==",
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-5.0.1.tgz",
|
||||
"integrity": "sha512-wVoTjP4Q6R0NW5hiZkVJaFZPWgtXfoGF+6LucL3/FtiNjmcHhYjEr5f1Kqjirc1nBW07J/ZuRFumqr2oqccEWg==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/puzrin"
|
||||
},
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/markdown-it"
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"uc.micro": "^2.0.0"
|
||||
|
|
@ -5501,15 +5511,25 @@
|
|||
}
|
||||
},
|
||||
"node_modules/markdown-it": {
|
||||
"version": "14.1.0",
|
||||
"resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-14.1.0.tgz",
|
||||
"integrity": "sha512-a54IwgWPaeBCAAsv13YgmALOF1elABB08FxO9i+r4VFk5Vl4pKokRPeX8u5TCgSsPi6ec1otfLjdOpVcgbpshg==",
|
||||
"version": "14.2.0",
|
||||
"resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-14.2.0.tgz",
|
||||
"integrity": "sha512-1TGiQiJVRQ3NPmZH6sx5Cfnmg6GQm9jvC1ch4TK511NjSJvjzKLzn5pPfZRNZkRPZP0HqCioSndqH8v2nRaWVQ==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/puzrin"
|
||||
},
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/markdown-it"
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"argparse": "^2.0.1",
|
||||
"entities": "^4.4.0",
|
||||
"linkify-it": "^5.0.0",
|
||||
"linkify-it": "^5.0.1",
|
||||
"mdurl": "^2.0.0",
|
||||
"punycode.js": "^2.3.1",
|
||||
"uc.micro": "^2.1.0"
|
||||
|
|
@ -5571,10 +5591,11 @@
|
|||
}
|
||||
},
|
||||
"node_modules/minimatch": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
|
||||
"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
|
||||
"version": "3.1.5",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz",
|
||||
"integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"brace-expansion": "^1.1.7"
|
||||
},
|
||||
|
|
@ -5841,10 +5862,11 @@
|
|||
"license": "ISC"
|
||||
},
|
||||
"node_modules/picomatch": {
|
||||
"version": "2.3.1",
|
||||
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
|
||||
"integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
|
||||
"version": "2.3.2",
|
||||
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz",
|
||||
"integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=8.6"
|
||||
},
|
||||
|
|
@ -6110,10 +6132,17 @@
|
|||
}
|
||||
},
|
||||
"node_modules/shell-quote": {
|
||||
"version": "1.7.3",
|
||||
"resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.7.3.tgz",
|
||||
"integrity": "sha512-Vpfqwm4EnqGdlsBFNmHhxhElJYrdfcxPThu+ryKS5J8L/fhAwLazFZtq+S+TWZ9ANj2piSQLGj6NQg+lKPmxrw==",
|
||||
"dev": true
|
||||
"version": "1.8.4",
|
||||
"resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.4.tgz",
|
||||
"integrity": "sha512-VsC6n6vz1ihYYyZZwX7YZSF5l5x36ca17OC+a69h94YqB7X6XLwf+5MOgynYir2SLFUbl8gIYvBo8K8RoNQ6bQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/side-channel": {
|
||||
"version": "1.0.4",
|
||||
|
|
@ -6638,13 +6667,13 @@
|
|||
}
|
||||
},
|
||||
"node_modules/typedoc/node_modules/minimatch": {
|
||||
"version": "9.0.5",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz",
|
||||
"integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==",
|
||||
"version": "9.0.9",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz",
|
||||
"integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"brace-expansion": "^2.0.1"
|
||||
"brace-expansion": "^2.0.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=16 || 14 >=14.17"
|
||||
|
|
|
|||
|
|
@ -72,10 +72,10 @@ fs.mkdirSync(path.dirname(ccWrapperPath), { recursive: true });
|
|||
fs.writeFileSync(ccWrapperPath, makeCCWrapper());
|
||||
|
||||
const fns = JSON.stringify(exportedFuncs());
|
||||
const methods = '["PThread","ccall","FS","UTF8ToString","intArrayFromString"]';
|
||||
const methods = '["PThread","ccall","FS","UTF8ToString","intArrayFromString","addFunction","removeFunction"]';
|
||||
const libz3a = path.normalize('../../../build/libz3.a');
|
||||
spawnSync(
|
||||
`emcc build/async-fns.cc ${libz3a} --std=c++20 --pre-js src/low-level/async-wrapper.js -g2 -pthread -fexceptions -s WASM_BIGINT -s USE_PTHREADS=1 -s PTHREAD_POOL_SIZE=0 -s PTHREAD_POOL_SIZE_STRICT=0 -s MODULARIZE=1 -s 'EXPORT_NAME="initZ3"' -s EXPORTED_RUNTIME_METHODS=${methods} -s EXPORTED_FUNCTIONS=${fns} -s DISABLE_EXCEPTION_CATCHING=0 -s SAFE_HEAP=0 -s TOTAL_MEMORY=2GB -s TOTAL_STACK=20MB -I z3/src/api/ -o build/z3-built.js`,
|
||||
`emcc build/async-fns.cc ${libz3a} --std=c++20 --pre-js src/low-level/async-wrapper.js -g2 -pthread -fexceptions -s WASM_BIGINT -s USE_PTHREADS=1 -s PTHREAD_POOL_SIZE=0 -s PTHREAD_POOL_SIZE_STRICT=0 -s MODULARIZE=1 -s 'EXPORT_NAME="initZ3"' -s EXPORTED_RUNTIME_METHODS=${methods} -s EXPORTED_FUNCTIONS=${fns} -s DISABLE_EXCEPTION_CATCHING=0 -s SAFE_HEAP=0 -s TOTAL_MEMORY=2GB -s TOTAL_STACK=20MB -s ALLOW_TABLE_GROWTH=1 -I z3/src/api/ -o build/z3-built.js`,
|
||||
);
|
||||
|
||||
fs.rmSync(ccWrapperPath);
|
||||
|
|
|
|||
|
|
@ -444,8 +444,8 @@ ${Object.entries(primitiveTypes)
|
|||
.map(e => `type ${e[0]} = ${e[1]};`)
|
||||
.join('\n')}
|
||||
|
||||
export async function init(initModule: any) {
|
||||
let Mod = await initModule();
|
||||
export async function init(initModule: any, moduleOverrides: Record<string, unknown> = {}) {
|
||||
let Mod = await initModule(moduleOverrides);
|
||||
|
||||
// this works for both signed and unsigned, because JS will wrap for you when constructing the Uint32Array
|
||||
function intArrayToByteArr(ints: number[]) {
|
||||
|
|
@ -461,13 +461,13 @@ export async function init(initModule: any) {
|
|||
}
|
||||
|
||||
let outAddress = Mod._malloc(${BYTES_TO_ALLOCATE_FOR_OUT_PARAMS});
|
||||
let outUintArray = (new Uint32Array(Mod.HEAPU32.buffer, outAddress, 4));
|
||||
let outUintArray = (new Uint32Array(Mod.HEAPU32.buffer, outAddress, ${BYTES_TO_ALLOCATE_FOR_OUT_PARAMS / 4}));
|
||||
let getOutUint = (i: ${getValidOutArrayIndexes(4)}) => outUintArray[i];
|
||||
let outIntArray = (new Int32Array(Mod.HEAPU32.buffer, outAddress, 4));
|
||||
let outIntArray = (new Int32Array(Mod.HEAPU32.buffer, outAddress, ${BYTES_TO_ALLOCATE_FOR_OUT_PARAMS / 4}));
|
||||
let getOutInt = (i: ${getValidOutArrayIndexes(4)}) => outIntArray[i];
|
||||
let outUint64Array = (new BigUint64Array(Mod.HEAPU32.buffer, outAddress, 2));
|
||||
let outUint64Array = (new BigUint64Array(Mod.HEAPU32.buffer, outAddress, ${BYTES_TO_ALLOCATE_FOR_OUT_PARAMS / 8}));
|
||||
let getOutUint64 = (i: ${getValidOutArrayIndexes(8)}) => outUint64Array[i];
|
||||
let outInt64Array = (new BigInt64Array(Mod.HEAPU32.buffer, outAddress, 2));
|
||||
let outInt64Array = (new BigInt64Array(Mod.HEAPU32.buffer, outAddress, ${BYTES_TO_ALLOCATE_FOR_OUT_PARAMS / 8}));
|
||||
let getOutInt64 = (i: ${getValidOutArrayIndexes(8)}) => outInt64Array[i];
|
||||
|
||||
return {
|
||||
|
|
|
|||
43
src/api/js/src/browser.test.ts
Normal file
43
src/api/js/src/browser.test.ts
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
const mockInitWrapper = jest.fn();
|
||||
const mockCreateApi = jest.fn();
|
||||
|
||||
jest.mock('./low-level', () => ({
|
||||
init: mockInitWrapper,
|
||||
Z3Core: undefined,
|
||||
Z3LowLevel: undefined,
|
||||
}));
|
||||
jest.mock('./high-level', () => ({
|
||||
createApi: mockCreateApi,
|
||||
}));
|
||||
|
||||
import { init } from './browser';
|
||||
|
||||
describe('browser init', () => {
|
||||
beforeEach(() => {
|
||||
delete (global as any).initZ3;
|
||||
mockInitWrapper.mockReset();
|
||||
mockCreateApi.mockReset();
|
||||
});
|
||||
|
||||
it('passes module overrides to the browser initializer', async () => {
|
||||
const initZ3 = jest.fn();
|
||||
const locateFile = jest.fn((file: string) => `https://example.test/${file}`);
|
||||
const lowLevel = { Z3: { low: true }, em: { module: true } };
|
||||
const highLevel = { Context: jest.fn() };
|
||||
(global as any).initZ3 = initZ3;
|
||||
mockInitWrapper.mockResolvedValue(lowLevel);
|
||||
mockCreateApi.mockReturnValue(highLevel);
|
||||
|
||||
const api = await init({ locateFile });
|
||||
|
||||
expect(mockInitWrapper).toHaveBeenCalledWith(initZ3, { locateFile });
|
||||
expect(mockCreateApi).toHaveBeenCalledWith(lowLevel.Z3, lowLevel.em);
|
||||
expect(api).toEqual({ ...lowLevel, ...highLevel });
|
||||
});
|
||||
|
||||
it('throws when initZ3 is unavailable', async () => {
|
||||
await expect(init()).rejects.toThrow(
|
||||
'initZ3 was not imported correctly. Please consult documentation on how to load Z3 in browser',
|
||||
);
|
||||
});
|
||||
});
|
||||
|
|
@ -1,16 +1,16 @@
|
|||
import { createApi, Z3HighLevel } from './high-level';
|
||||
import { init as initWrapper, Z3LowLevel } from './low-level';
|
||||
import { init as initWrapper, Z3LowLevel, Z3ModuleOverrides } from './low-level';
|
||||
export * from './high-level/types';
|
||||
export { Z3Core, Z3LowLevel } from './low-level';
|
||||
export * from './low-level/types.__GENERATED__';
|
||||
|
||||
export async function init(): Promise<Z3LowLevel & Z3HighLevel> {
|
||||
export async function init(moduleOverrides: Z3ModuleOverrides = {}): Promise<Z3LowLevel & Z3HighLevel> {
|
||||
const initZ3 = (global as any).initZ3;
|
||||
if (initZ3 === undefined) {
|
||||
throw new Error('initZ3 was not imported correctly. Please consult documentation on how to load Z3 in browser');
|
||||
}
|
||||
|
||||
const lowLevel = await initWrapper(initZ3);
|
||||
const highLevel = createApi(lowLevel.Z3);
|
||||
const lowLevel = await initWrapper(initZ3, moduleOverrides);
|
||||
const highLevel = createApi(lowLevel.Z3, lowLevel.em);
|
||||
return { ...lowLevel, ...highLevel };
|
||||
}
|
||||
|
|
|
|||
|
|
@ -824,6 +824,41 @@ describe('high-level', () => {
|
|||
expect(core.length()).toBeGreaterThan(0);
|
||||
expect(core.length()).toBeLessThanOrEqual(3);
|
||||
});
|
||||
|
||||
it('can use addAndTrack to extract unsat core', async () => {
|
||||
const { Solver, Int, Bool } = api.Context('main');
|
||||
const solver = new Solver();
|
||||
const x = Int.const('x');
|
||||
const p1 = Bool.const('p1');
|
||||
const p2 = Bool.const('p2');
|
||||
|
||||
// Track conflicting constraints using addAndTrack
|
||||
solver.addAndTrack(x.gt(0), p1);
|
||||
solver.addAndTrack(x.lt(0), p2);
|
||||
|
||||
const result = await solver.check();
|
||||
expect(result).toStrictEqual('unsat');
|
||||
|
||||
// The unsat core should contain the tracking literals
|
||||
const core = solver.unsatCore();
|
||||
expect(core.length()).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
it('can use addAndTrack with string constant name', async () => {
|
||||
const { Solver, Int } = api.Context('main');
|
||||
const solver = new Solver();
|
||||
const x = Int.const('x');
|
||||
|
||||
// addAndTrack accepts a string as the tracking constant name
|
||||
solver.addAndTrack(x.gt(0), 'p1');
|
||||
solver.addAndTrack(x.lt(0), 'p2');
|
||||
|
||||
const result = await solver.check();
|
||||
expect(result).toStrictEqual('unsat');
|
||||
|
||||
const core = solver.unsatCore();
|
||||
expect(core.length()).toBeGreaterThan(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe('AstVector', () => {
|
||||
|
|
@ -943,6 +978,22 @@ describe('high-level', () => {
|
|||
expect(model.eval(y).eqIdentity(Int.val(0))).toBeTruthy();
|
||||
expect(model.eval(z).eqIdentity(Int.val(5))).toBeTruthy();
|
||||
});
|
||||
|
||||
it('can use addAndTrack with Optimize', async () => {
|
||||
const { Int, Bool, Optimize } = api.Context('main');
|
||||
|
||||
const opt = new Optimize();
|
||||
const x = Int.const('x');
|
||||
const p1 = Bool.const('p1');
|
||||
const p2 = Bool.const('p2');
|
||||
|
||||
// Track conflicting constraints using addAndTrack
|
||||
opt.addAndTrack(x.gt(0), p1);
|
||||
opt.addAndTrack(x.lt(0), p2);
|
||||
|
||||
const result = await opt.check();
|
||||
expect(result).toStrictEqual('unsat');
|
||||
});
|
||||
});
|
||||
|
||||
describe('datatypes', () => {
|
||||
|
|
|
|||
|
|
@ -123,6 +123,9 @@ import {
|
|||
DatatypeSort,
|
||||
DatatypeExpr,
|
||||
DatatypeCreation,
|
||||
FiniteSet,
|
||||
FiniteSetSort,
|
||||
FiniteSetCreation,
|
||||
} from './types';
|
||||
import { allSatisfy, assert, assertExhaustive } from './utils';
|
||||
|
||||
|
|
@ -149,7 +152,7 @@ function isCoercibleRational(obj: any): obj is CoercibleRational {
|
|||
return r;
|
||||
}
|
||||
|
||||
export function createApi(Z3: Z3Core): Z3HighLevel {
|
||||
export function createApi(Z3: Z3Core, em?: any): Z3HighLevel {
|
||||
// TODO(ritave): Create a custom linting rule that checks if the provided callbacks to cleanup
|
||||
// Don't capture `this`
|
||||
const cleanup = new FinalizationRegistry<() => void>(callback => callback());
|
||||
|
|
@ -305,6 +308,9 @@ export function createApi(Z3: Z3Core): Z3HighLevel {
|
|||
case Z3_sort_kind.Z3_ARRAY_SORT:
|
||||
return new ArraySortImpl(ast);
|
||||
default:
|
||||
if (Z3.is_finite_set_sort(contextPtr, ast)) {
|
||||
return new FiniteSetSortImpl(ast);
|
||||
}
|
||||
return new SortImpl(ast);
|
||||
}
|
||||
}
|
||||
|
|
@ -350,6 +356,9 @@ export function createApi(Z3: Z3Core): Z3HighLevel {
|
|||
case Z3_sort_kind.Z3_ARRAY_SORT:
|
||||
return new ArrayImpl(ast);
|
||||
default:
|
||||
if (Z3.is_finite_set_sort(contextPtr, Z3.get_sort(contextPtr, ast))) {
|
||||
return new FiniteSetImpl(ast);
|
||||
}
|
||||
return new ExprImpl(ast);
|
||||
}
|
||||
}
|
||||
|
|
@ -638,6 +647,18 @@ export function createApi(Z3: Z3Core): Z3HighLevel {
|
|||
return isSeq(obj) && obj.isString();
|
||||
}
|
||||
|
||||
function isFiniteSetSort(obj: unknown): obj is FiniteSetSort<Name> {
|
||||
const r = obj instanceof FiniteSetSortImpl;
|
||||
r && _assertContext(obj);
|
||||
return r;
|
||||
}
|
||||
|
||||
function isFiniteSet(obj: unknown): obj is FiniteSet<Name> {
|
||||
const r = obj instanceof FiniteSetImpl;
|
||||
r && _assertContext(obj);
|
||||
return r;
|
||||
}
|
||||
|
||||
function isProbe(obj: unknown): obj is Probe<Name> {
|
||||
const r = obj instanceof ProbeImpl;
|
||||
r && _assertContext(obj);
|
||||
|
|
@ -1003,6 +1024,16 @@ export function createApi(Z3: Z3Core): Z3HighLevel {
|
|||
val(value: string): Seq<Name> {
|
||||
return new SeqImpl(check(Z3.mk_string(contextPtr, value)));
|
||||
},
|
||||
|
||||
fromCode(code: Arith<Name> | number | bigint): Seq<Name> {
|
||||
const codeExpr = isArith(code) ? code : Int.val(code);
|
||||
return new SeqImpl(check(Z3.mk_string_from_code(contextPtr, codeExpr.ast)));
|
||||
},
|
||||
|
||||
fromInt(n: Arith<Name> | number | bigint): Seq<Name> {
|
||||
const nExpr = isArith(n) ? n : Int.val(n);
|
||||
return new SeqImpl(check(Z3.mk_int_to_str(contextPtr, nExpr.ast)));
|
||||
},
|
||||
};
|
||||
|
||||
const Seq = {
|
||||
|
|
@ -1072,6 +1103,9 @@ export function createApi(Z3: Z3Core): Z3HighLevel {
|
|||
): SMTArray<Name, [DomainSort], RangeSort> {
|
||||
return new ArrayImpl<[DomainSort], RangeSort>(check(Z3.mk_const_array(contextPtr, domain.ptr, value.ptr)));
|
||||
},
|
||||
fromFunc(f: FuncDecl<Name>): SMTArray<Name> {
|
||||
return new ArrayImpl(check(Z3.mk_as_array(contextPtr, f.ptr)));
|
||||
},
|
||||
};
|
||||
const Set = {
|
||||
// reference: https://z3prover.github.io/api/html/namespacez3py.html#a545f894afeb24caa1b88b7f2a324ee7e
|
||||
|
|
@ -1104,6 +1138,32 @@ export function createApi(Z3: Z3Core): Z3HighLevel {
|
|||
},
|
||||
};
|
||||
|
||||
const FiniteSet = {
|
||||
sort<ElemSort extends Sort<Name>>(elemSort: ElemSort): FiniteSetSort<Name, ElemSort> {
|
||||
return new FiniteSetSortImpl<ElemSort>(check(Z3.mk_finite_set_sort(contextPtr, elemSort.ptr)));
|
||||
},
|
||||
const<ElemSort extends Sort<Name>>(name: string, elemSort: ElemSort): FiniteSet<Name, ElemSort> {
|
||||
return new FiniteSetImpl<ElemSort>(
|
||||
check(Z3.mk_const(contextPtr, _toSymbol(name), FiniteSet.sort(elemSort).ptr)),
|
||||
);
|
||||
},
|
||||
consts<ElemSort extends Sort<Name>>(names: string | string[], elemSort: ElemSort): FiniteSet<Name, ElemSort>[] {
|
||||
if (typeof names === 'string') {
|
||||
names = names.split(' ');
|
||||
}
|
||||
return names.map(name => FiniteSet.const(name, elemSort));
|
||||
},
|
||||
empty<ElemSort extends Sort<Name>>(sort: ElemSort): FiniteSet<Name, ElemSort> {
|
||||
return new FiniteSetImpl<ElemSort>(check(Z3.mk_finite_set_empty(contextPtr, FiniteSet.sort(sort).ptr)));
|
||||
},
|
||||
singleton<ElemSort extends Sort<Name>>(elem: Expr<Name>): FiniteSet<Name, ElemSort> {
|
||||
return new FiniteSetImpl<ElemSort>(check(Z3.mk_finite_set_singleton(contextPtr, elem.ast)));
|
||||
},
|
||||
range(low: Expr<Name>, high: Expr<Name>): FiniteSet<Name, Sort<Name>> {
|
||||
return new FiniteSetImpl(check(Z3.mk_finite_set_range(contextPtr, low.ast, high.ast)));
|
||||
},
|
||||
};
|
||||
|
||||
const Datatype = Object.assign(
|
||||
(name: string): DatatypeImpl => {
|
||||
return new DatatypeImpl(ctx, name);
|
||||
|
|
@ -1112,9 +1172,16 @@ export function createApi(Z3: Z3Core): Z3HighLevel {
|
|||
createDatatypes(...datatypes: DatatypeImpl[]): DatatypeSortImpl[] {
|
||||
return createDatatypes(...datatypes);
|
||||
},
|
||||
createPolymorphicDatatype(typeParams: Sort<Name>[], datatype: DatatypeImpl): DatatypeSortImpl {
|
||||
return createPolymorphicDatatype(typeParams, datatype);
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
function TypeVariable(name: string): Sort<Name> {
|
||||
return new SortImpl(check(Z3.mk_type_variable(contextPtr, Z3.mk_string_symbol(contextPtr, name))));
|
||||
}
|
||||
|
||||
////////////////
|
||||
// Operations //
|
||||
////////////////
|
||||
|
|
@ -1890,10 +1957,46 @@ export function createApi(Z3: Z3Core): Z3HighLevel {
|
|||
return new FuncDeclImpl(check(Z3.mk_partial_order(contextPtr, sort.ptr, index)));
|
||||
}
|
||||
|
||||
function mkLinearOrder(sort: Sort<Name>, index: number): FuncDecl<Name> {
|
||||
return new FuncDeclImpl(check(Z3.mk_linear_order(contextPtr, sort.ptr, index)));
|
||||
}
|
||||
|
||||
function mkPiecewiseLinearOrder(sort: Sort<Name>, index: number): FuncDecl<Name> {
|
||||
return new FuncDeclImpl(check(Z3.mk_piecewise_linear_order(contextPtr, sort.ptr, index)));
|
||||
}
|
||||
|
||||
function mkTreeOrder(sort: Sort<Name>, index: number): FuncDecl<Name> {
|
||||
return new FuncDeclImpl(check(Z3.mk_tree_order(contextPtr, sort.ptr, index)));
|
||||
}
|
||||
|
||||
function mkTransitiveClosure(f: FuncDecl<Name>): FuncDecl<Name> {
|
||||
return new FuncDeclImpl(check(Z3.mk_transitive_closure(contextPtr, f.ptr)));
|
||||
}
|
||||
|
||||
function mkChar(ch: number): Expr<Name> {
|
||||
return new ExprImpl(check(Z3.mk_char(contextPtr, ch)));
|
||||
}
|
||||
|
||||
function mkCharLe(ch1: Expr<Name>, ch2: Expr<Name>): Bool<Name> {
|
||||
return new BoolImpl(check(Z3.mk_char_le(contextPtr, ch1.ast, ch2.ast)));
|
||||
}
|
||||
|
||||
function mkCharToInt(ch: Expr<Name>): Arith<Name> {
|
||||
return new ArithImpl(check(Z3.mk_char_to_int(contextPtr, ch.ast)));
|
||||
}
|
||||
|
||||
function mkCharToBV(ch: Expr<Name>): Expr<Name> {
|
||||
return new ExprImpl(check(Z3.mk_char_to_bv(contextPtr, ch.ast)));
|
||||
}
|
||||
|
||||
function mkCharFromBV(bv: Expr<Name>): Expr<Name> {
|
||||
return new ExprImpl(check(Z3.mk_char_from_bv(contextPtr, bv.ast)));
|
||||
}
|
||||
|
||||
function mkCharIsDigit(ch: Expr<Name>): Bool<Name> {
|
||||
return new BoolImpl(check(Z3.mk_char_is_digit(contextPtr, ch.ast)));
|
||||
}
|
||||
|
||||
async function polynomialSubresultants(
|
||||
p: Arith<Name>,
|
||||
q: Arith<Name>,
|
||||
|
|
@ -1951,6 +2054,8 @@ export function createApi(Z3: Z3Core): Z3HighLevel {
|
|||
|
||||
readonly ctx: Context<Name>;
|
||||
private _ptr: Z3_solver | null;
|
||||
// Tracks a registered on_clause WASM callback index so it can be cleaned up
|
||||
private _onClauseCallbackIdx!: { value: number | null };
|
||||
get ptr(): Z3_solver {
|
||||
_assertPtr(this._ptr);
|
||||
return this._ptr;
|
||||
|
|
@ -1966,7 +2071,20 @@ export function createApi(Z3: Z3Core): Z3HighLevel {
|
|||
}
|
||||
this._ptr = myPtr;
|
||||
Z3.solver_inc_ref(contextPtr, myPtr);
|
||||
cleanup.register(this, () => Z3.solver_dec_ref(contextPtr, myPtr), this);
|
||||
// Shared mutable holder so registerOnClause and the cleanup closure see the same slot
|
||||
const onClauseCallbackIdx: { value: number | null } = { value: null };
|
||||
this._onClauseCallbackIdx = onClauseCallbackIdx;
|
||||
cleanup.register(
|
||||
this,
|
||||
() => {
|
||||
Z3.solver_dec_ref(contextPtr, myPtr);
|
||||
if (onClauseCallbackIdx.value !== null && em) {
|
||||
em.removeFunction(onClauseCallbackIdx.value);
|
||||
onClauseCallbackIdx.value = null;
|
||||
}
|
||||
},
|
||||
this,
|
||||
);
|
||||
}
|
||||
|
||||
set(key: string, value: any): void {
|
||||
|
|
@ -2083,6 +2201,24 @@ export function createApi(Z3: Z3Core): Z3HighLevel {
|
|||
));
|
||||
}
|
||||
|
||||
dimacs(includeNames: boolean = true): string {
|
||||
return check(Z3.solver_to_dimacs_string(contextPtr, this.ptr, includeNames));
|
||||
}
|
||||
|
||||
translate(target: Context<Name>): Solver<Name> {
|
||||
const ptr = check(Z3.solver_translate(contextPtr, this.ptr, target.ptr));
|
||||
return new (target.Solver as unknown as new (ptr: Z3_solver) => Solver<Name>)(ptr);
|
||||
}
|
||||
|
||||
proof(): Expr<Name> | null {
|
||||
const result = Z3.solver_get_proof(contextPtr, this.ptr);
|
||||
throwIfError();
|
||||
if (!result) {
|
||||
return null;
|
||||
}
|
||||
return _toExpr(result);
|
||||
}
|
||||
|
||||
fromString(s: string) {
|
||||
Z3.solver_from_string(contextPtr, this.ptr, s);
|
||||
throwIfError();
|
||||
|
|
@ -2100,6 +2236,79 @@ export function createApi(Z3: Z3Core): Z3HighLevel {
|
|||
return new AstVectorImpl(check(Z3.solver_get_trail(contextPtr, this.ptr)));
|
||||
}
|
||||
|
||||
trailLevels(): number[] {
|
||||
const trailVec = check(Z3.solver_get_trail(contextPtr, this.ptr));
|
||||
const n = Z3.ast_vector_size(contextPtr, trailVec);
|
||||
return check(Z3.solver_get_levels(contextPtr, this.ptr, trailVec, n));
|
||||
}
|
||||
|
||||
async cube(vars?: AstVector<Name, Bool<Name>>, cutoff: number = 0xFFFFFFFF): Promise<AstVector<Name, Bool<Name>>> {
|
||||
const tempVars = vars ?? new AstVectorImpl();
|
||||
const result = await asyncMutex.runExclusive(() =>
|
||||
check(Z3.solver_cube(contextPtr, this.ptr, tempVars.ptr, cutoff)),
|
||||
);
|
||||
return new AstVectorImpl(result);
|
||||
}
|
||||
|
||||
async getConsequences(
|
||||
assumptions: (Bool<Name> | AstVector<Name, Bool<Name>>)[],
|
||||
variables: Expr<Name>[],
|
||||
): Promise<[CheckSatResult, AstVector<Name, Bool<Name>>]> {
|
||||
const asmsVec = new AstVectorImpl();
|
||||
const varsVec = new AstVectorImpl();
|
||||
const consVec = new AstVectorImpl<Bool<Name>>();
|
||||
_flattenArgs(assumptions).forEach(expr => {
|
||||
_assertContext(expr);
|
||||
Z3.ast_vector_push(contextPtr, asmsVec.ptr, expr.ast);
|
||||
});
|
||||
variables.forEach(v => {
|
||||
_assertContext(v);
|
||||
Z3.ast_vector_push(contextPtr, varsVec.ptr, v.ast);
|
||||
});
|
||||
const r = await asyncMutex.runExclusive(() =>
|
||||
check(Z3.solver_get_consequences(contextPtr, this.ptr, asmsVec.ptr, varsVec.ptr, consVec.ptr)),
|
||||
);
|
||||
let status: CheckSatResult;
|
||||
switch (r) {
|
||||
case Z3_lbool.Z3_L_FALSE:
|
||||
status = 'unsat';
|
||||
break;
|
||||
case Z3_lbool.Z3_L_TRUE:
|
||||
status = 'sat';
|
||||
break;
|
||||
default:
|
||||
status = 'unknown';
|
||||
}
|
||||
return [status, consVec];
|
||||
}
|
||||
|
||||
solveFor(variables: Expr<Name>[], terms: Expr<Name>[], guards: Bool<Name>[]): void {
|
||||
const varsVec = new AstVectorImpl();
|
||||
const termsVec = new AstVectorImpl();
|
||||
const guardsVec = new AstVectorImpl();
|
||||
variables.forEach(v => {
|
||||
_assertContext(v);
|
||||
Z3.ast_vector_push(contextPtr, varsVec.ptr, v.ast);
|
||||
});
|
||||
terms.forEach(t => {
|
||||
_assertContext(t);
|
||||
Z3.ast_vector_push(contextPtr, termsVec.ptr, t.ast);
|
||||
});
|
||||
guards.forEach(g => {
|
||||
_assertContext(g);
|
||||
Z3.ast_vector_push(contextPtr, guardsVec.ptr, g.ast);
|
||||
});
|
||||
Z3.solver_solve_for(contextPtr, this.ptr, varsVec.ptr, termsVec.ptr, guardsVec.ptr);
|
||||
throwIfError();
|
||||
}
|
||||
|
||||
setInitialValue(variable: Expr<Name>, value: Expr<Name>): void {
|
||||
_assertContext(variable);
|
||||
_assertContext(value);
|
||||
Z3.solver_set_initial_value(contextPtr, this.ptr, variable.ast, value.ast);
|
||||
throwIfError();
|
||||
}
|
||||
|
||||
congruenceRoot(expr: Expr<Name>): Expr<Name> {
|
||||
_assertContext(expr);
|
||||
return _toExpr(check(Z3.solver_congruence_root(contextPtr, this.ptr, expr.ast)));
|
||||
|
|
@ -2122,11 +2331,46 @@ export function createApi(Z3: Z3Core): Z3HighLevel {
|
|||
}
|
||||
|
||||
release() {
|
||||
// Clean up any registered on_clause callback
|
||||
if (this._onClauseCallbackIdx.value !== null && em) {
|
||||
em.removeFunction(this._onClauseCallbackIdx.value);
|
||||
this._onClauseCallbackIdx.value = null;
|
||||
}
|
||||
Z3.solver_dec_ref(contextPtr, this.ptr);
|
||||
// Mark the ptr as null to prevent double free
|
||||
this._ptr = null;
|
||||
cleanup.unregister(this);
|
||||
}
|
||||
|
||||
registerOnClause(
|
||||
callback: (proofHint: Expr<Name> | null, deps: number[], clause: AstVector<Name, Bool<Name>>) => void,
|
||||
): void {
|
||||
if (!em) {
|
||||
throw new Error('registerOnClause requires the Emscripten module; pass it to createApi');
|
||||
}
|
||||
// Remove any previously registered callback before registering a new one
|
||||
if (this._onClauseCallbackIdx.value !== null) {
|
||||
em.removeFunction(this._onClauseCallbackIdx.value);
|
||||
this._onClauseCallbackIdx.value = null;
|
||||
}
|
||||
// Signature: void(void* ctx, Z3_ast proof_hint, unsigned n, const unsigned* deps, Z3_ast_vector literals)
|
||||
const cCallback = em.addFunction(
|
||||
(_ctxPtr: number, proofHintPtr: number, n: number, depsPtr: number, literalsPtr: number) => {
|
||||
const proofHint = proofHintPtr ? _toExpr(proofHintPtr as unknown as Z3_ast) : null;
|
||||
const deps: number[] = [];
|
||||
for (let i = 0; i < n; i++) {
|
||||
deps.push(em.HEAPU32[(depsPtr >> 2) + i]);
|
||||
}
|
||||
const clause = new AstVectorImpl(literalsPtr as unknown as Z3_ast_vector) as AstVector<Name, Bool<Name>>;
|
||||
callback(proofHint, deps, clause);
|
||||
},
|
||||
'viiiii',
|
||||
);
|
||||
this._onClauseCallbackIdx.value = cCallback;
|
||||
// solver_register_on_clause is not auto-wrapped (has void* and fnptr params),
|
||||
// so we call the raw Emscripten export directly.
|
||||
em._Z3_solver_register_on_clause(contextPtr as unknown as number, this.ptr as unknown as number, 0, cCallback);
|
||||
}
|
||||
}
|
||||
|
||||
class OptimizeImpl implements Optimize<Name> {
|
||||
|
|
@ -2186,12 +2430,42 @@ export function createApi(Z3: Z3Core): Z3HighLevel {
|
|||
return new AstVectorImpl(check(Z3.optimize_get_assertions(contextPtr, this.ptr)));
|
||||
}
|
||||
|
||||
maximize(expr: Arith<Name> | BitVec<number, Name>) {
|
||||
check(Z3.optimize_maximize(contextPtr, this.ptr, expr.ast));
|
||||
maximize(expr: Arith<Name> | BitVec<number, Name>): number {
|
||||
return check(Z3.optimize_maximize(contextPtr, this.ptr, expr.ast));
|
||||
}
|
||||
|
||||
minimize(expr: Arith<Name> | BitVec<number, Name>) {
|
||||
check(Z3.optimize_minimize(contextPtr, this.ptr, expr.ast));
|
||||
minimize(expr: Arith<Name> | BitVec<number, Name>): number {
|
||||
return check(Z3.optimize_minimize(contextPtr, this.ptr, expr.ast));
|
||||
}
|
||||
|
||||
getLower(index: number): Expr<Name> {
|
||||
return _toExpr(check(Z3.optimize_get_lower(contextPtr, this.ptr, index)));
|
||||
}
|
||||
|
||||
getUpper(index: number): Expr<Name> {
|
||||
return _toExpr(check(Z3.optimize_get_upper(contextPtr, this.ptr, index)));
|
||||
}
|
||||
|
||||
unsatCore(): AstVector<Name, Bool<Name>> {
|
||||
return new AstVectorImpl(check(Z3.optimize_get_unsat_core(contextPtr, this.ptr)));
|
||||
}
|
||||
|
||||
objectives(): AstVector<Name, Expr<Name>> {
|
||||
return new AstVectorImpl(check(Z3.optimize_get_objectives(contextPtr, this.ptr)));
|
||||
}
|
||||
|
||||
reasonUnknown(): string {
|
||||
return check(Z3.optimize_get_reason_unknown(contextPtr, this.ptr));
|
||||
}
|
||||
|
||||
fromFile(filename: string): void {
|
||||
Z3.optimize_from_file(contextPtr, this.ptr, filename);
|
||||
throwIfError();
|
||||
}
|
||||
|
||||
translate(target: Context<Name>): Optimize<Name> {
|
||||
const ptr = check(Z3.optimize_translate(contextPtr, this.ptr, target.ptr));
|
||||
return new (target.Optimize as unknown as new (ptr: Z3_optimize) => Optimize<Name>)(ptr);
|
||||
}
|
||||
|
||||
async check(...exprs: (Bool<Name> | AstVector<Name, Bool<Name>>)[]): Promise<CheckSatResult> {
|
||||
|
|
@ -2220,6 +2494,13 @@ export function createApi(Z3: Z3Core): Z3HighLevel {
|
|||
return new StatisticsImpl(check(Z3.optimize_get_statistics(contextPtr, this.ptr)));
|
||||
}
|
||||
|
||||
setInitialValue(variable: Expr<Name>, value: Expr<Name>): void {
|
||||
_assertContext(variable);
|
||||
_assertContext(value);
|
||||
Z3.optimize_set_initial_value(contextPtr, this.ptr, variable.ast, value.ast);
|
||||
throwIfError();
|
||||
}
|
||||
|
||||
toString() {
|
||||
return check(Z3.optimize_to_string(contextPtr, this.ptr));
|
||||
}
|
||||
|
|
@ -2587,6 +2868,11 @@ export function createApi(Z3: Z3Core): Z3HighLevel {
|
|||
return this.getUniverse(sort) as AstVector<Name, AnyExpr<Name>>;
|
||||
}
|
||||
|
||||
translate(target: Context<Name>): Model<Name> {
|
||||
const ptr = check(Z3.model_translate(contextPtr, this.ptr, target.ptr));
|
||||
return new (target.Model as unknown as new (ptr: Z3_model) => Model<Name>)(ptr);
|
||||
}
|
||||
|
||||
release() {
|
||||
Z3.model_dec_ref(contextPtr, this.ptr);
|
||||
this._ptr = null;
|
||||
|
|
@ -4026,6 +4312,14 @@ export function createApi(Z3: Z3Core): Z3HighLevel {
|
|||
isPositive(): Bool<Name> {
|
||||
return new BoolImpl(check(Z3.mk_fpa_is_positive(contextPtr, this.ast)));
|
||||
}
|
||||
|
||||
toIEEEBV(): BitVec<number, Name> {
|
||||
return new BitVecImpl(check(Z3.mk_fpa_to_ieee_bv(contextPtr, this.ast)));
|
||||
}
|
||||
|
||||
toReal(): Arith<Name> {
|
||||
return new ArithImpl(check(Z3.mk_fpa_to_real(contextPtr, this.ast)));
|
||||
}
|
||||
}
|
||||
|
||||
class FPNumImpl extends FPImpl implements FPNum<Name> {
|
||||
|
|
@ -4143,6 +4437,52 @@ export function createApi(Z3: Z3Core): Z3HighLevel {
|
|||
const dstSeq = isSeq(dst) ? dst : String.val(dst);
|
||||
return new SeqImpl<ElemSort>(check(Z3.mk_seq_replace_all(contextPtr, this.ast, srcSeq.ast, dstSeq.ast)));
|
||||
}
|
||||
|
||||
replaceRe(re: Re<Name>, dst: Seq<Name, ElemSort> | string): Seq<Name, ElemSort> {
|
||||
const dstSeq = isSeq(dst) ? dst : String.val(dst);
|
||||
return new SeqImpl<ElemSort>(check(Z3.mk_seq_replace_re(contextPtr, this.ast, re.ast, dstSeq.ast)));
|
||||
}
|
||||
|
||||
replaceReAll(re: Re<Name>, dst: Seq<Name, ElemSort> | string): Seq<Name, ElemSort> {
|
||||
const dstSeq = isSeq(dst) ? dst : String.val(dst);
|
||||
return new SeqImpl<ElemSort>(check(Z3.mk_seq_replace_re_all(contextPtr, this.ast, re.ast, dstSeq.ast)));
|
||||
}
|
||||
|
||||
toInt(): Arith<Name> {
|
||||
return new ArithImpl(check(Z3.mk_str_to_int(contextPtr, this.ast)));
|
||||
}
|
||||
|
||||
toCode(): Arith<Name> {
|
||||
return new ArithImpl(check(Z3.mk_string_to_code(contextPtr, this.ast)));
|
||||
}
|
||||
|
||||
lt(other: Seq<Name, ElemSort> | string): Bool<Name> {
|
||||
const otherSeq = isSeq(other) ? other : String.val(other);
|
||||
return new BoolImpl(check(Z3.mk_str_lt(contextPtr, this.ast, otherSeq.ast)));
|
||||
}
|
||||
|
||||
le(other: Seq<Name, ElemSort> | string): Bool<Name> {
|
||||
const otherSeq = isSeq(other) ? other : String.val(other);
|
||||
return new BoolImpl(check(Z3.mk_str_le(contextPtr, this.ast, otherSeq.ast)));
|
||||
}
|
||||
|
||||
map(f: Expr<Name>): Seq<Name> {
|
||||
return new SeqImpl(check(Z3.mk_seq_map(contextPtr, f.ast, this.ast)));
|
||||
}
|
||||
|
||||
mapi(f: Expr<Name>, i: Arith<Name> | number | bigint): Seq<Name> {
|
||||
const iExpr = isArith(i) ? i : Int.val(i);
|
||||
return new SeqImpl(check(Z3.mk_seq_mapi(contextPtr, f.ast, iExpr.ast, this.ast)));
|
||||
}
|
||||
|
||||
foldl(f: Expr<Name>, a: Expr<Name>): Expr<Name> {
|
||||
return _toExpr(check(Z3.mk_seq_foldl(contextPtr, f.ast, a.ast, this.ast)));
|
||||
}
|
||||
|
||||
foldli(f: Expr<Name>, i: Arith<Name> | number | bigint, a: Expr<Name>): Expr<Name> {
|
||||
const iExpr = isArith(i) ? i : Int.val(i);
|
||||
return _toExpr(check(Z3.mk_seq_foldli(contextPtr, f.ast, iExpr.ast, a.ast, this.ast)));
|
||||
}
|
||||
}
|
||||
|
||||
class ReSortImpl<SeqSortRef extends SeqSort<Name> = SeqSort<Name>> extends SortImpl implements ReSort<Name, SeqSortRef> {
|
||||
|
|
@ -4310,6 +4650,65 @@ export function createApi(Z3: Z3Core): Z3HighLevel {
|
|||
}
|
||||
}
|
||||
|
||||
////////////////////////////
|
||||
// Finite Sets
|
||||
////////////////////////////
|
||||
|
||||
class FiniteSetSortImpl<ElemSort extends Sort<Name> = Sort<Name>>
|
||||
extends SortImpl
|
||||
implements FiniteSetSort<Name, ElemSort>
|
||||
{
|
||||
declare readonly __typename: 'FiniteSetSort';
|
||||
|
||||
elemSort(): ElemSort {
|
||||
return _toSort(check(Z3.get_finite_set_sort_basis(contextPtr, this.ptr))) as ElemSort;
|
||||
}
|
||||
|
||||
cast(other: Expr<Name>): Expr<Name> {
|
||||
_assertContext(other);
|
||||
return other;
|
||||
}
|
||||
}
|
||||
|
||||
class FiniteSetImpl<ElemSort extends Sort<Name> = Sort<Name>>
|
||||
extends ExprImpl<Z3_ast, FiniteSetSortImpl<ElemSort>>
|
||||
implements FiniteSet<Name, ElemSort>
|
||||
{
|
||||
declare readonly __typename: 'FiniteSet';
|
||||
|
||||
union(other: FiniteSet<Name, ElemSort>): FiniteSet<Name, ElemSort> {
|
||||
return new FiniteSetImpl<ElemSort>(check(Z3.mk_finite_set_union(contextPtr, this.ast, other.ast)));
|
||||
}
|
||||
|
||||
intersect(other: FiniteSet<Name, ElemSort>): FiniteSet<Name, ElemSort> {
|
||||
return new FiniteSetImpl<ElemSort>(check(Z3.mk_finite_set_intersect(contextPtr, this.ast, other.ast)));
|
||||
}
|
||||
|
||||
diff(other: FiniteSet<Name, ElemSort>): FiniteSet<Name, ElemSort> {
|
||||
return new FiniteSetImpl<ElemSort>(check(Z3.mk_finite_set_difference(contextPtr, this.ast, other.ast)));
|
||||
}
|
||||
|
||||
contains(elem: Expr<Name>): Bool<Name> {
|
||||
return new BoolImpl(check(Z3.mk_finite_set_member(contextPtr, elem.ast, this.ast)));
|
||||
}
|
||||
|
||||
size(): Expr<Name> {
|
||||
return new ExprImpl(check(Z3.mk_finite_set_size(contextPtr, this.ast)));
|
||||
}
|
||||
|
||||
subsetOf(other: FiniteSet<Name, ElemSort>): Bool<Name> {
|
||||
return new BoolImpl(check(Z3.mk_finite_set_subset(contextPtr, this.ast, other.ast)));
|
||||
}
|
||||
|
||||
map(f: Expr<Name>): FiniteSet<Name, Sort<Name>> {
|
||||
return new FiniteSetImpl(check(Z3.mk_finite_set_map(contextPtr, f.ast, this.ast)));
|
||||
}
|
||||
|
||||
filter(f: Expr<Name>): FiniteSet<Name, ElemSort> {
|
||||
return new FiniteSetImpl<ElemSort>(check(Z3.mk_finite_set_filter(contextPtr, f.ast, this.ast)));
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////
|
||||
// Datatypes
|
||||
////////////////////////////
|
||||
|
|
@ -4333,6 +4732,10 @@ export function createApi(Z3: Z3Core): Z3HighLevel {
|
|||
const datatypes = createDatatypes(this);
|
||||
return datatypes[0];
|
||||
}
|
||||
|
||||
createPolymorphic(typeParams: Sort<Name>[]): DatatypeSort<Name> {
|
||||
return createPolymorphicDatatype(typeParams, this);
|
||||
}
|
||||
}
|
||||
|
||||
class DatatypeSortImpl extends SortImpl implements DatatypeSort<Name> {
|
||||
|
|
@ -4489,6 +4892,84 @@ export function createApi(Z3: Z3Core): Z3HighLevel {
|
|||
}
|
||||
}
|
||||
|
||||
function createPolymorphicDatatype(typeParams: Sort<Name>[], datatype: DatatypeImpl): DatatypeSortImpl {
|
||||
if (!(datatype instanceof DatatypeImpl)) {
|
||||
throw new Error('Datatype instance expected');
|
||||
}
|
||||
|
||||
const constructors: Z3_constructor[] = [];
|
||||
|
||||
try {
|
||||
for (const [constructorName, fields] of datatype.constructors) {
|
||||
const fieldNames: string[] = [];
|
||||
const fieldSorts: Z3_sort[] = [];
|
||||
const fieldRefs: number[] = [];
|
||||
|
||||
for (const [fieldName, fieldSort] of fields) {
|
||||
fieldNames.push(fieldName);
|
||||
|
||||
if (fieldSort instanceof DatatypeImpl) {
|
||||
// Self-recursive reference
|
||||
if (fieldSort !== datatype) {
|
||||
throw new Error(
|
||||
`Referenced datatype "${fieldSort.name}" is not the polymorphic datatype being created; mutual recursion is not supported in createPolymorphicDatatype`,
|
||||
);
|
||||
}
|
||||
fieldSorts.push(null as any);
|
||||
fieldRefs.push(0);
|
||||
} else {
|
||||
fieldSorts.push((fieldSort as Sort<Name>).ptr);
|
||||
fieldRefs.push(0);
|
||||
}
|
||||
}
|
||||
|
||||
const constructor = Z3.mk_constructor(
|
||||
contextPtr,
|
||||
Z3.mk_string_symbol(contextPtr, constructorName),
|
||||
Z3.mk_string_symbol(contextPtr, `is_${constructorName}`),
|
||||
fieldNames.map(name => Z3.mk_string_symbol(contextPtr, name)),
|
||||
fieldSorts,
|
||||
fieldRefs,
|
||||
);
|
||||
constructors.push(constructor);
|
||||
}
|
||||
|
||||
const nameSymbol = Z3.mk_string_symbol(contextPtr, datatype.name);
|
||||
const paramPtrs = typeParams.map(p => p.ptr);
|
||||
const resultSort = Z3.mk_polymorphic_datatype(contextPtr, nameSymbol, paramPtrs, constructors);
|
||||
|
||||
const sortImpl = new DatatypeSortImpl(resultSort);
|
||||
|
||||
// Attach constructor, recognizer, and accessor functions dynamically
|
||||
const numConstructors = sortImpl.numConstructors();
|
||||
for (let j = 0; j < numConstructors; j++) {
|
||||
const constructor = sortImpl.constructorDecl(j);
|
||||
const recognizer = sortImpl.recognizer(j);
|
||||
const constructorName = constructor.name().toString();
|
||||
|
||||
if (constructor.arity() === 0) {
|
||||
(sortImpl as any)[constructorName] = constructor.call();
|
||||
} else {
|
||||
(sortImpl as any)[constructorName] = constructor;
|
||||
}
|
||||
|
||||
(sortImpl as any)[`is_${constructorName}`] = recognizer;
|
||||
|
||||
for (let k = 0; k < constructor.arity(); k++) {
|
||||
const accessor = sortImpl.accessor(j, k);
|
||||
const accessorName = accessor.name().toString();
|
||||
(sortImpl as any)[accessorName] = accessor;
|
||||
}
|
||||
}
|
||||
|
||||
return sortImpl;
|
||||
} finally {
|
||||
for (const constructor of constructors) {
|
||||
Z3.del_constructor(contextPtr, constructor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class QuantifierImpl<
|
||||
QVarSorts extends NonEmptySortArray<Name>,
|
||||
QSort extends BoolSort<Name> | SMTArraySort<Name, QVarSorts>,
|
||||
|
|
@ -4902,6 +5383,8 @@ export function createApi(Z3: Z3Core): Z3HighLevel {
|
|||
isSeq,
|
||||
isStringSort,
|
||||
isString,
|
||||
isFiniteSetSort,
|
||||
isFiniteSet,
|
||||
isArraySort,
|
||||
isArray,
|
||||
isConstArray,
|
||||
|
|
@ -4932,7 +5415,9 @@ export function createApi(Z3: Z3Core): Z3HighLevel {
|
|||
Re,
|
||||
Array,
|
||||
Set,
|
||||
FiniteSet,
|
||||
Datatype,
|
||||
TypeVariable,
|
||||
|
||||
////////////////
|
||||
// Operations //
|
||||
|
|
@ -5041,7 +5526,16 @@ export function createApi(Z3: Z3Core): Z3HighLevel {
|
|||
Full,
|
||||
|
||||
mkPartialOrder,
|
||||
mkLinearOrder,
|
||||
mkPiecewiseLinearOrder,
|
||||
mkTreeOrder,
|
||||
mkTransitiveClosure,
|
||||
mkChar,
|
||||
mkCharLe,
|
||||
mkCharToInt,
|
||||
mkCharToBV,
|
||||
mkCharFromBV,
|
||||
mkCharIsDigit,
|
||||
polynomialSubresultants,
|
||||
};
|
||||
cleanup.register(ctx, () => Z3.del_context(contextPtr));
|
||||
|
|
|
|||
|
|
@ -52,7 +52,8 @@ export type AnyExpr<Name extends string = 'main'> =
|
|||
| FPNum<Name>
|
||||
| FPRM<Name>
|
||||
| Seq<Name>
|
||||
| Re<Name>;
|
||||
| Re<Name>
|
||||
| FiniteSet<Name>;
|
||||
/** @hidden */
|
||||
export type AnyAst<Name extends string = 'main'> = AnyExpr<Name> | AnySort<Name> | FuncDecl<Name>;
|
||||
|
||||
|
|
@ -330,6 +331,12 @@ export interface Context<Name extends string = 'main'> {
|
|||
/** @category Functions */
|
||||
isString(obj: unknown): obj is Seq<Name>;
|
||||
|
||||
/** @category Functions */
|
||||
isFiniteSetSort(obj: unknown): obj is FiniteSetSort<Name>;
|
||||
|
||||
/** @category Functions */
|
||||
isFiniteSet(obj: unknown): obj is FiniteSet<Name>;
|
||||
|
||||
/** @category Functions */
|
||||
isProbe(obj: unknown): obj is Probe<Name>;
|
||||
|
||||
|
|
@ -468,8 +475,16 @@ export interface Context<Name extends string = 'main'> {
|
|||
/** @category Expressions */
|
||||
readonly Set: SMTSetCreation<Name>;
|
||||
/** @category Expressions */
|
||||
readonly FiniteSet: FiniteSetCreation<Name>;
|
||||
/** @category Expressions */
|
||||
readonly Datatype: DatatypeCreation<Name>;
|
||||
|
||||
/**
|
||||
* Create a type variable sort for use as a parameter in polymorphic datatypes.
|
||||
* @category Sorts
|
||||
*/
|
||||
TypeVariable(name: string): Sort<Name>;
|
||||
|
||||
////////////////
|
||||
// Operations //
|
||||
////////////////
|
||||
|
|
@ -918,6 +933,30 @@ export interface Context<Name extends string = 'main'> {
|
|||
*/
|
||||
mkPartialOrder(sort: Sort<Name>, index: number): FuncDecl<Name>;
|
||||
|
||||
/**
|
||||
* Create a linear (total) order relation over a sort.
|
||||
* @param sort The sort of the relation
|
||||
* @param index The index of the relation
|
||||
* @category Operations
|
||||
*/
|
||||
mkLinearOrder(sort: Sort<Name>, index: number): FuncDecl<Name>;
|
||||
|
||||
/**
|
||||
* Create a piecewise linear order relation over a sort.
|
||||
* @param sort The sort of the relation
|
||||
* @param index The index of the relation
|
||||
* @category Operations
|
||||
*/
|
||||
mkPiecewiseLinearOrder(sort: Sort<Name>, index: number): FuncDecl<Name>;
|
||||
|
||||
/**
|
||||
* Create a tree order relation over a sort.
|
||||
* @param sort The sort of the relation
|
||||
* @param index The index of the relation
|
||||
* @category Operations
|
||||
*/
|
||||
mkTreeOrder(sort: Sort<Name>, index: number): FuncDecl<Name>;
|
||||
|
||||
/**
|
||||
* Create the transitive closure of a binary relation.
|
||||
* The resulting relation is recursive.
|
||||
|
|
@ -926,6 +965,49 @@ export interface Context<Name extends string = 'main'> {
|
|||
*/
|
||||
mkTransitiveClosure(f: FuncDecl<Name>): FuncDecl<Name>;
|
||||
|
||||
/**
|
||||
* Create a character literal from a Unicode code point.
|
||||
* @param ch The Unicode code point
|
||||
* @category Characters
|
||||
*/
|
||||
mkChar(ch: number): Expr<Name>;
|
||||
|
||||
/**
|
||||
* Create a character less-than-or-equal predicate (ch1 ≤ ch2).
|
||||
* @param ch1 First character
|
||||
* @param ch2 Second character
|
||||
* @category Characters
|
||||
*/
|
||||
mkCharLe(ch1: Expr<Name>, ch2: Expr<Name>): Bool<Name>;
|
||||
|
||||
/**
|
||||
* Convert a character to its integer (Unicode code point) value.
|
||||
* @param ch The character expression
|
||||
* @category Characters
|
||||
*/
|
||||
mkCharToInt(ch: Expr<Name>): Arith<Name>;
|
||||
|
||||
/**
|
||||
* Convert a character to a bit-vector.
|
||||
* @param ch The character expression
|
||||
* @category Characters
|
||||
*/
|
||||
mkCharToBV(ch: Expr<Name>): Expr<Name>;
|
||||
|
||||
/**
|
||||
* Convert a bit-vector to a character.
|
||||
* @param bv The bit-vector expression
|
||||
* @category Characters
|
||||
*/
|
||||
mkCharFromBV(bv: Expr<Name>): Expr<Name>;
|
||||
|
||||
/**
|
||||
* Create a predicate that is true if the character is a decimal digit.
|
||||
* @param ch The character expression
|
||||
* @category Characters
|
||||
*/
|
||||
mkCharIsDigit(ch: Expr<Name>): Bool<Name>;
|
||||
|
||||
/**
|
||||
* Return the nonzero subresultants of p and q with respect to the "variable" x.
|
||||
* Note that any subterm that cannot be viewed as a polynomial is assumed to be a variable.
|
||||
|
|
@ -987,6 +1069,29 @@ export interface Solver<Name extends string = 'main'> {
|
|||
|
||||
add(...exprs: (Bool<Name> | AstVector<Name, Bool<Name>>)[]): void;
|
||||
|
||||
/**
|
||||
* Assert a constraint and associate it with a tracking literal (Boolean constant).
|
||||
* This is the TypeScript equivalent of `assertAndTrack` in other Z3 language bindings.
|
||||
*
|
||||
* When the solver returns `unsat`, the tracked literals that contributed to
|
||||
* unsatisfiability can be retrieved via {@link unsatCore}.
|
||||
*
|
||||
* @param expr - The Boolean expression to assert
|
||||
* @param constant - A Boolean constant (or its name as a string) used as the tracking literal
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* const solver = new Solver();
|
||||
* const x = Int.const('x');
|
||||
* const p1 = Bool.const('p1');
|
||||
* const p2 = Bool.const('p2');
|
||||
* solver.addAndTrack(x.gt(0), p1);
|
||||
* solver.addAndTrack(x.lt(0), p2);
|
||||
* if (await solver.check() === 'unsat') {
|
||||
* const core = solver.unsatCore(); // contains p1 and p2
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
addAndTrack(expr: Bool<Name>, constant: Bool<Name> | string): void;
|
||||
|
||||
/**
|
||||
|
|
@ -1158,6 +1263,105 @@ export interface Solver<Name extends string = 'main'> {
|
|||
*/
|
||||
trail(): AstVector<Name, Bool<Name>>;
|
||||
|
||||
/**
|
||||
* Retrieve the decision levels for each literal in the solver's trail.
|
||||
* The returned array has one entry per trail literal, indicating at which
|
||||
* decision level it was assigned.
|
||||
*
|
||||
* @returns An array of numbers where element i is the decision level of the i-th trail literal
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* const solver = new Solver();
|
||||
* const x = Bool.const('x');
|
||||
* solver.add(x);
|
||||
* await solver.check();
|
||||
* const levels = solver.trailLevels();
|
||||
* console.log('Trail levels:', levels);
|
||||
* ```
|
||||
*/
|
||||
trailLevels(): number[];
|
||||
|
||||
/**
|
||||
* Extract cubes from the solver for cube-and-conquer parallel solving.
|
||||
* Each call returns the next cube (conjunction of literals) from the solver.
|
||||
* Returns an empty AstVector when the search space is exhausted.
|
||||
*
|
||||
* @param vars - Optional vector of variables to use as cube variables
|
||||
* @param cutoff - Backtrack level cutoff for cube generation (default: 0xFFFFFFFF)
|
||||
* @returns A promise resolving to an AstVector containing the cube literals
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* const solver = new Solver();
|
||||
* const x = Bool.const('x');
|
||||
* const y = Bool.const('y');
|
||||
* solver.add(x.or(y));
|
||||
* const cube = await solver.cube(undefined, 1);
|
||||
* console.log('Cube length:', cube.length());
|
||||
* ```
|
||||
*/
|
||||
cube(vars?: AstVector<Name, Bool<Name>>, cutoff?: number): Promise<AstVector<Name, Bool<Name>>>;
|
||||
|
||||
/**
|
||||
* Retrieve fixed assignments to a set of variables as consequences given assumptions.
|
||||
* Each consequence is an implication: assumptions => variable = value.
|
||||
*
|
||||
* @param assumptions - Assumptions to use during consequence finding
|
||||
* @param variables - Variables to find consequences for
|
||||
* @returns A promise resolving to the status and a vector of consequence expressions
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* const solver = new Solver();
|
||||
* const x = Bool.const('x');
|
||||
* const y = Bool.const('y');
|
||||
* solver.add(x.implies(y));
|
||||
* const [status, consequences] = await solver.getConsequences([], [x, y]);
|
||||
* ```
|
||||
*/
|
||||
getConsequences(
|
||||
assumptions: (Bool<Name> | AstVector<Name, Bool<Name>>)[],
|
||||
variables: Expr<Name>[],
|
||||
): Promise<[CheckSatResult, AstVector<Name, Bool<Name>>]>;
|
||||
|
||||
/**
|
||||
* Solve constraints treating given variables symbolically, replacing their
|
||||
* occurrences by terms. Guards condition the substitutions.
|
||||
*
|
||||
* @param variables - Variables to solve for
|
||||
* @param terms - Substitution terms for the variables
|
||||
* @param guards - Boolean guards for the substitutions
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* const solver = new Solver();
|
||||
* const x = Int.const('x');
|
||||
* const y = Int.const('y');
|
||||
* solver.add(x.eq(y.add(1)));
|
||||
* solver.solveFor([x], [y.add(1)], []);
|
||||
* ```
|
||||
*/
|
||||
solveFor(variables: Expr<Name>[], terms: Expr<Name>[], guards: Bool<Name>[]): void;
|
||||
|
||||
/**
|
||||
* Set an initial value hint for a variable to guide the solver's search heuristics.
|
||||
* This can improve performance when a good initial value is known.
|
||||
*
|
||||
* @param variable - The variable to set an initial value for
|
||||
* @param value - The initial value for the variable
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* const solver = new Solver();
|
||||
* const x = Int.const('x');
|
||||
* solver.setInitialValue(x, Int.val(42));
|
||||
* solver.add(x.gt(0));
|
||||
* await solver.check();
|
||||
* ```
|
||||
*/
|
||||
setInitialValue(variable: Expr<Name>, value: Expr<Name>): void;
|
||||
|
||||
/**
|
||||
* Retrieve the root of the congruence class containing the given expression.
|
||||
* This is useful for understanding equality reasoning in the solver.
|
||||
|
|
@ -1263,12 +1467,52 @@ export interface Solver<Name extends string = 'main'> {
|
|||
*/
|
||||
toSmtlib2(status?: string): string;
|
||||
|
||||
/**
|
||||
* Convert the solver's Boolean formula to DIMACS CNF format.
|
||||
*
|
||||
* @param includeNames - If true, include variable names in the output (default: true)
|
||||
* @returns A string containing the DIMACS CNF representation
|
||||
*/
|
||||
dimacs(includeNames?: boolean): string;
|
||||
|
||||
/**
|
||||
* Translate the solver to a different context.
|
||||
* @param target - The target context
|
||||
* @returns A new Solver instance in the target context
|
||||
*/
|
||||
translate(target: Context<Name>): Solver<Name>;
|
||||
|
||||
/**
|
||||
* Retrieve a proof of unsatisfiability after a check that returned 'unsat'.
|
||||
* Requires proof production to be enabled.
|
||||
* @returns An expression representing the proof, or null if unavailable
|
||||
*/
|
||||
proof(): Expr<Name> | null;
|
||||
|
||||
/**
|
||||
* Manually decrease the reference count of the solver
|
||||
* This is automatically done when the solver is garbage collected,
|
||||
* but calling this eagerly can help release memory sooner.
|
||||
*/
|
||||
release(): void;
|
||||
|
||||
/**
|
||||
* Register a callback that is invoked when clauses are inferred during solving.
|
||||
* The callback is called when a clause is:
|
||||
* - asserted to the CDCL engine (input clause after pre-processing)
|
||||
* - inferred by CDCL(T) using a SAT or theory conflict/propagation
|
||||
* - deleted by the CDCL(T) engine
|
||||
*
|
||||
* Requires the Emscripten module to be passed to `createApi`.
|
||||
*
|
||||
* @param callback - Function called with:
|
||||
* - proofHint: optional proof hint expression (may be null)
|
||||
* - deps: array of clause dependency indices
|
||||
* - clause: the clause as a vector of literals
|
||||
*/
|
||||
registerOnClause(
|
||||
callback: (proofHint: Expr<Name> | null, deps: number[], clause: AstVector<Name, Bool<Name>>) => void,
|
||||
): void;
|
||||
}
|
||||
|
||||
export interface Optimize<Name extends string = 'main'> {
|
||||
|
|
@ -1288,15 +1532,113 @@ export interface Optimize<Name extends string = 'main'> {
|
|||
|
||||
addSoft(expr: Bool<Name>, weight: number | bigint | string | CoercibleRational, id?: number | string): void;
|
||||
|
||||
/**
|
||||
* Assert a constraint and associate it with a tracking literal (Boolean constant).
|
||||
* This is the TypeScript equivalent of `assertAndTrack` in other Z3 language bindings.
|
||||
*
|
||||
* When the optimizer returns `unsat`, the tracked literals that contributed to
|
||||
* unsatisfiability can be used to identify which constraints caused the conflict.
|
||||
*
|
||||
* @param expr - The Boolean expression to assert
|
||||
* @param constant - A Boolean constant (or its name as a string) used as the tracking literal
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* const opt = new Optimize();
|
||||
* const x = Int.const('x');
|
||||
* const p1 = Bool.const('p1');
|
||||
* const p2 = Bool.const('p2');
|
||||
* opt.addAndTrack(x.gt(0), p1);
|
||||
* opt.addAndTrack(x.lt(0), p2);
|
||||
* const result = await opt.check(); // 'unsat'
|
||||
* ```
|
||||
*/
|
||||
addAndTrack(expr: Bool<Name>, constant: Bool<Name> | string): void;
|
||||
|
||||
assertions(): AstVector<Name, Bool<Name>>;
|
||||
|
||||
fromString(s: string): void;
|
||||
|
||||
maximize(expr: Arith<Name>): void;
|
||||
/**
|
||||
* Load SMT-LIB2 format assertions from a file into the optimizer.
|
||||
*
|
||||
* @param filename - Path to the file containing SMT-LIB2 format assertions
|
||||
*/
|
||||
fromFile(filename: string): void;
|
||||
|
||||
minimize(expr: Arith<Name>): void;
|
||||
/**
|
||||
* Add a maximization objective.
|
||||
* @param expr - The expression to maximize
|
||||
* @returns A zero-based numeric handle index for this objective, used to retrieve bounds
|
||||
* via {@link getLower}/{@link getUpper} after calling {@link check}
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* const opt = new Optimize();
|
||||
* const x = Int.const('x');
|
||||
* opt.add(x.ge(0), x.le(10));
|
||||
* const h = opt.maximize(x);
|
||||
* await opt.check();
|
||||
* console.log('Max x:', opt.getUpper(h).toString()); // '10'
|
||||
* ```
|
||||
*/
|
||||
maximize(expr: Arith<Name> | BitVec<number, Name>): number;
|
||||
|
||||
/**
|
||||
* Add a minimization objective.
|
||||
* @param expr - The expression to minimize
|
||||
* @returns A zero-based numeric handle index for this objective, used to retrieve bounds
|
||||
* via {@link getLower}/{@link getUpper} after calling {@link check}
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* const opt = new Optimize();
|
||||
* const x = Int.const('x');
|
||||
* opt.add(x.ge(0), x.le(10));
|
||||
* const h = opt.minimize(x);
|
||||
* await opt.check();
|
||||
* console.log('Min x:', opt.getLower(h).toString()); // '0'
|
||||
* ```
|
||||
*/
|
||||
minimize(expr: Arith<Name> | BitVec<number, Name>): number;
|
||||
|
||||
/**
|
||||
* Retrieve the lower bound for the objective at the given handle index.
|
||||
* Call this after {@link check} returns 'sat'.
|
||||
* @param index - The handle index returned by {@link maximize} or {@link minimize}
|
||||
*/
|
||||
getLower(index: number): Expr<Name>;
|
||||
|
||||
/**
|
||||
* Retrieve the upper bound for the objective at the given handle index.
|
||||
* Call this after {@link check} returns 'sat'.
|
||||
* @param index - The handle index returned by {@link maximize} or {@link minimize}
|
||||
*/
|
||||
getUpper(index: number): Expr<Name>;
|
||||
|
||||
/**
|
||||
* Retrieve the unsat core after a check that returned 'unsat'.
|
||||
* @returns An AstVector containing the subset of assumptions that caused UNSAT
|
||||
*/
|
||||
unsatCore(): AstVector<Name, Bool<Name>>;
|
||||
|
||||
/**
|
||||
* Retrieve the set of objective expressions.
|
||||
* @returns An AstVector containing the objectives
|
||||
*/
|
||||
objectives(): AstVector<Name, Expr<Name>>;
|
||||
|
||||
/**
|
||||
* Return a string describing why the last call to {@link check} returned 'unknown'.
|
||||
*/
|
||||
reasonUnknown(): string;
|
||||
|
||||
/**
|
||||
* Translate the optimize context to a different context.
|
||||
* @param target - The target context
|
||||
* @returns A new Optimize instance in the target context
|
||||
*/
|
||||
translate(target: Context<Name>): Optimize<Name>;
|
||||
|
||||
check(...exprs: (Bool<Name> | AstVector<Name, Bool<Name>>)[]): Promise<CheckSatResult>;
|
||||
|
||||
|
|
@ -1304,6 +1646,25 @@ export interface Optimize<Name extends string = 'main'> {
|
|||
|
||||
statistics(): Statistics<Name>;
|
||||
|
||||
/**
|
||||
* Set an initial value hint for a variable to guide the optimizer's search heuristics.
|
||||
* This can improve performance when a good initial value is known.
|
||||
*
|
||||
* @param variable - The variable to set an initial value for
|
||||
* @param value - The initial value for the variable
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* const opt = new Optimize();
|
||||
* const x = Int.const('x');
|
||||
* opt.setInitialValue(x, Int.val(42));
|
||||
* opt.add(x.gt(0));
|
||||
* opt.maximize(x);
|
||||
* await opt.check();
|
||||
* ```
|
||||
*/
|
||||
setInitialValue(variable: Expr<Name>, value: Expr<Name>): void;
|
||||
|
||||
/**
|
||||
* Manually decrease the reference count of the optimize
|
||||
* This is automatically done when the optimize is garbage collected,
|
||||
|
|
@ -1595,6 +1956,14 @@ export interface Model<Name extends string = 'main'> extends Iterable<FuncDecl<N
|
|||
*/
|
||||
sortUniverse(sort: Sort<Name>): AstVector<Name, AnyExpr<Name>>;
|
||||
|
||||
/**
|
||||
* Translate the model to a different context.
|
||||
*
|
||||
* @param target - The target context
|
||||
* @returns A new model in the target context
|
||||
*/
|
||||
translate(target: Context<Name>): Model<Name>;
|
||||
|
||||
/**
|
||||
* Manually decrease the reference count of the model
|
||||
* This is automatically done when the model is garbage collected,
|
||||
|
|
@ -1706,7 +2075,8 @@ export interface Sort<Name extends string = 'main'> extends Ast<Name, Z3_sort> {
|
|||
| FPSort['__typename']
|
||||
| FPRMSort['__typename']
|
||||
| SeqSort['__typename']
|
||||
| ReSort['__typename'];
|
||||
| ReSort['__typename']
|
||||
| FiniteSetSort['__typename'];
|
||||
|
||||
kind(): Z3_sort_kind;
|
||||
|
||||
|
|
@ -1835,7 +2205,8 @@ export interface Expr<Name extends string = 'main', S extends Sort<Name> = AnySo
|
|||
| Seq['__typename']
|
||||
| Re['__typename']
|
||||
| SMTArray['__typename']
|
||||
| DatatypeExpr['__typename'];
|
||||
| DatatypeExpr['__typename']
|
||||
| FiniteSet['__typename'];
|
||||
|
||||
get sort(): S;
|
||||
|
||||
|
|
@ -2625,6 +2996,12 @@ export interface SMTArrayCreation<Name extends string> {
|
|||
domain: DomainSort,
|
||||
value: SortToExprMap<RangeSort, Name>,
|
||||
): SMTArray<Name, [DomainSort], RangeSort>;
|
||||
|
||||
/**
|
||||
* Create an array from a function declaration.
|
||||
* The resulting array maps each input to the output of the function.
|
||||
*/
|
||||
fromFunc(f: FuncDecl<Name>): SMTArray<Name>;
|
||||
}
|
||||
|
||||
export type NonEmptySortArray<Name extends string = 'main'> = [Sort<Name>, ...Array<Sort<Name>>];
|
||||
|
|
@ -2739,6 +3116,60 @@ export interface SMTSet<Name extends string = 'main', ElemSort extends AnySort<N
|
|||
contains(elem: CoercibleToMap<SortToExprMap<ElemSort, Name>, Name>): Bool<Name>;
|
||||
subsetOf(b: SMTSet<Name, ElemSort>): Bool<Name>;
|
||||
}
|
||||
//////////////////////////////////////////
|
||||
//
|
||||
// Finite Sets
|
||||
//
|
||||
//////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* Represents a finite set sort
|
||||
*
|
||||
* @typeParam ElemSort The sort of elements in the finite set
|
||||
* @category Finite Sets
|
||||
*/
|
||||
export interface FiniteSetSort<Name extends string = 'main', ElemSort extends Sort<Name> = Sort<Name>>
|
||||
extends Sort<Name> {
|
||||
readonly __typename: 'FiniteSetSort';
|
||||
/** Returns the element sort of this finite set sort */
|
||||
elemSort(): ElemSort;
|
||||
}
|
||||
|
||||
/** @category Finite Sets */
|
||||
export interface FiniteSetCreation<Name extends string> {
|
||||
sort<ElemSort extends Sort<Name>>(elemSort: ElemSort): FiniteSetSort<Name, ElemSort>;
|
||||
|
||||
const<ElemSort extends Sort<Name>>(name: string, elemSort: ElemSort): FiniteSet<Name, ElemSort>;
|
||||
|
||||
consts<ElemSort extends Sort<Name>>(names: string | string[], elemSort: ElemSort): FiniteSet<Name, ElemSort>[];
|
||||
|
||||
empty<ElemSort extends Sort<Name>>(sort: ElemSort): FiniteSet<Name, ElemSort>;
|
||||
|
||||
singleton<ElemSort extends Sort<Name>>(elem: Expr<Name>): FiniteSet<Name, ElemSort>;
|
||||
|
||||
range(low: Expr<Name>, high: Expr<Name>): FiniteSet<Name, Sort<Name>>;
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a finite set expression
|
||||
*
|
||||
* @typeParam ElemSort The sort of elements in the finite set
|
||||
* @category Finite Sets
|
||||
*/
|
||||
export interface FiniteSet<Name extends string = 'main', ElemSort extends Sort<Name> = Sort<Name>>
|
||||
extends Expr<Name, FiniteSetSort<Name, ElemSort>, Z3_ast> {
|
||||
readonly __typename: 'FiniteSet';
|
||||
|
||||
union(other: FiniteSet<Name, ElemSort>): FiniteSet<Name, ElemSort>;
|
||||
intersect(other: FiniteSet<Name, ElemSort>): FiniteSet<Name, ElemSort>;
|
||||
diff(other: FiniteSet<Name, ElemSort>): FiniteSet<Name, ElemSort>;
|
||||
contains(elem: Expr<Name>): Bool<Name>;
|
||||
size(): Expr<Name>;
|
||||
subsetOf(other: FiniteSet<Name, ElemSort>): Bool<Name>;
|
||||
map(f: Expr<Name>): FiniteSet<Name, Sort<Name>>;
|
||||
filter(f: Expr<Name>): FiniteSet<Name, ElemSort>;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////
|
||||
//
|
||||
// Datatypes
|
||||
|
|
@ -2778,6 +3209,15 @@ export interface Datatype<Name extends string = 'main'> {
|
|||
* For mutually recursive datatypes, use Context.createDatatypes instead.
|
||||
*/
|
||||
create(): DatatypeSort<Name>;
|
||||
|
||||
/**
|
||||
* Create a polymorphic datatype sort with explicit type parameters.
|
||||
* Type parameters should be sorts created with Context.TypeVariable.
|
||||
* Self-recursive fields may reference this Datatype object directly.
|
||||
*
|
||||
* @param typeParams Array of type variable sorts
|
||||
*/
|
||||
createPolymorphic(typeParams: AnySort<Name>[]): DatatypeSort<Name>;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -2796,6 +3236,17 @@ export interface DatatypeCreation<Name extends string> {
|
|||
* @returns Array of created DatatypeSort instances
|
||||
*/
|
||||
createDatatypes(...datatypes: Datatype<Name>[]): DatatypeSort<Name>[];
|
||||
|
||||
/**
|
||||
* Create a single polymorphic datatype sort with explicit type parameters.
|
||||
* Type parameters should be sorts created with Context.TypeVariable.
|
||||
* Self-recursive fields in constructors may reference the Datatype object directly.
|
||||
*
|
||||
* @param typeParams Array of type variable sorts
|
||||
* @param datatype Datatype declaration with constructors
|
||||
* @returns Created DatatypeSort instance
|
||||
*/
|
||||
createPolymorphicDatatype(typeParams: AnySort<Name>[], datatype: Datatype<Name>): DatatypeSort<Name>;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -3054,6 +3505,12 @@ export interface FP<Name extends string = 'main'> extends Expr<Name, FPSort<Name
|
|||
|
||||
/** @category Predicates */
|
||||
isPositive(): Bool<Name>;
|
||||
|
||||
/** @category Conversion */
|
||||
toIEEEBV(): BitVec<number, Name>;
|
||||
|
||||
/** @category Conversion */
|
||||
toReal(): Arith<Name>;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -3119,6 +3576,16 @@ export interface StringCreation<Name extends string> {
|
|||
* Create a string value
|
||||
*/
|
||||
val(value: string): Seq<Name>;
|
||||
|
||||
/**
|
||||
* Create a single-character string from a Unicode code point (str.from_code).
|
||||
*/
|
||||
fromCode(code: Arith<Name> | number | bigint): Seq<Name>;
|
||||
|
||||
/**
|
||||
* Convert an integer expression to its string representation (int.to.str).
|
||||
*/
|
||||
fromInt(n: Arith<Name> | number | bigint): Seq<Name>;
|
||||
}
|
||||
|
||||
/** @category String/Sequence */
|
||||
|
|
@ -3193,6 +3660,60 @@ export interface Seq<Name extends string = 'main', ElemSort extends Sort<Name> =
|
|||
|
||||
/** @category Operations */
|
||||
replaceAll(src: Seq<Name, ElemSort> | string, dst: Seq<Name, ElemSort> | string): Seq<Name, ElemSort>;
|
||||
|
||||
/** @category Operations */
|
||||
replaceRe(re: Re<Name>, dst: Seq<Name, ElemSort> | string): Seq<Name, ElemSort>;
|
||||
|
||||
/** @category Operations */
|
||||
replaceReAll(re: Re<Name>, dst: Seq<Name, ElemSort> | string): Seq<Name, ElemSort>;
|
||||
|
||||
/**
|
||||
* Convert a string to its integer value (str.to.int).
|
||||
* @category Operations
|
||||
*/
|
||||
toInt(): Arith<Name>;
|
||||
|
||||
/**
|
||||
* Convert a single-character string to its Unicode code point (str.to_code).
|
||||
* @category Operations
|
||||
*/
|
||||
toCode(): Arith<Name>;
|
||||
|
||||
/**
|
||||
* String less-than comparison (str.lt).
|
||||
* @category Operations
|
||||
*/
|
||||
lt(other: Seq<Name, ElemSort> | string): Bool<Name>;
|
||||
|
||||
/**
|
||||
* String less-than-or-equal comparison (str.le).
|
||||
* @category Operations
|
||||
*/
|
||||
le(other: Seq<Name, ElemSort> | string): Bool<Name>;
|
||||
|
||||
/**
|
||||
* Apply function f to each element of the sequence (seq.map).
|
||||
* @category Operations
|
||||
*/
|
||||
map(f: Expr<Name>): Seq<Name>;
|
||||
|
||||
/**
|
||||
* Apply function f to each element and its index in the sequence (seq.mapi).
|
||||
* @category Operations
|
||||
*/
|
||||
mapi(f: Expr<Name>, i: Arith<Name> | number | bigint): Seq<Name>;
|
||||
|
||||
/**
|
||||
* Left-fold function f over the sequence with initial accumulator a (seq.foldl).
|
||||
* @category Operations
|
||||
*/
|
||||
foldl(f: Expr<Name>, a: Expr<Name>): Expr<Name>;
|
||||
|
||||
/**
|
||||
* Left-fold function f with index over the sequence with initial accumulator a (seq.foldli).
|
||||
* @category Operations
|
||||
*/
|
||||
foldli(f: Expr<Name>, i: Arith<Name> | number | bigint, a: Expr<Name>): Expr<Name>;
|
||||
}
|
||||
|
||||
///////////////////////
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ export * from './low-level/types.__GENERATED__';
|
|||
|
||||
export async function init(): Promise<Z3HighLevel & Z3LowLevel> {
|
||||
const lowLevel = await initWrapper(initModule);
|
||||
const highLevel = createApi(lowLevel.Z3);
|
||||
const highLevel = createApi(lowLevel.Z3, lowLevel.em);
|
||||
return { ...lowLevel, ...highLevel };
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,8 @@
|
|||
export * from './types.__GENERATED__';
|
||||
export * from './wrapper.__GENERATED__';
|
||||
export type Z3ModuleOverrides = {
|
||||
locateFile?: (path: string, prefix: string) => string;
|
||||
[key: string]: unknown;
|
||||
};
|
||||
export type Z3Core = Awaited<ReturnType<(typeof import('./wrapper.__GENERATED__'))['init']>>['Z3'];
|
||||
export type Z3LowLevel = Awaited<ReturnType<(typeof import('./wrapper.__GENERATED__'))['init']>>;
|
||||
|
|
|
|||
37
src/api/js/src/node.test.ts
Normal file
37
src/api/js/src/node.test.ts
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
const mockInitModule = jest.fn();
|
||||
const mockInitWrapper = jest.fn();
|
||||
const mockCreateApi = jest.fn();
|
||||
|
||||
jest.mock('./z3-built', () => mockInitModule, { virtual: true });
|
||||
jest.mock('./low-level', () => ({
|
||||
init: mockInitWrapper,
|
||||
Z3Core: undefined,
|
||||
Z3LowLevel: undefined,
|
||||
}));
|
||||
jest.mock('./high-level', () => ({
|
||||
createApi: mockCreateApi,
|
||||
}));
|
||||
|
||||
import { init } from './node';
|
||||
|
||||
describe('node init', () => {
|
||||
beforeEach(() => {
|
||||
mockInitModule.mockReset();
|
||||
mockInitWrapper.mockReset();
|
||||
mockCreateApi.mockReset();
|
||||
});
|
||||
|
||||
it('passes module overrides to the low-level initializer', async () => {
|
||||
const locateFile = jest.fn((file: string) => `npm:z3-solver/build/${file}`);
|
||||
const lowLevel = { Z3: { low: true }, em: { module: true } };
|
||||
const highLevel = { Context: jest.fn() };
|
||||
mockInitWrapper.mockResolvedValue(lowLevel);
|
||||
mockCreateApi.mockReturnValue(highLevel);
|
||||
|
||||
const api = await init({ locateFile });
|
||||
|
||||
expect(mockInitWrapper).toHaveBeenCalledWith(mockInitModule, { locateFile });
|
||||
expect(mockCreateApi).toHaveBeenCalledWith(lowLevel.Z3, lowLevel.em);
|
||||
expect(api).toEqual({ ...lowLevel, ...highLevel });
|
||||
});
|
||||
});
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
import initModule = require('./z3-built');
|
||||
|
||||
import { createApi, Z3HighLevel } from './high-level';
|
||||
import { init as initWrapper, Z3LowLevel } from './low-level';
|
||||
import { init as initWrapper, Z3LowLevel, Z3ModuleOverrides } from './low-level';
|
||||
export * from './high-level/types';
|
||||
export { Z3Core, Z3LowLevel } from './low-level';
|
||||
export * from './low-level/types.__GENERATED__';
|
||||
|
|
@ -29,10 +29,17 @@ export * from './low-level/types.__GENERATED__';
|
|||
*
|
||||
* console.log(`x=${model.get(x)}, y=${model.get(y)}`);
|
||||
* // x=0, y=12
|
||||
*
|
||||
* // Deno users can provide an Emscripten locateFile hook to load the wasm
|
||||
* // through npm's asset resolution instead of filesystem reads.
|
||||
* // const api = await init({
|
||||
* // locateFile: (file, _prefix): string =>
|
||||
* // import.meta.resolve(`npm:z3-solver/build/${file}`), // _prefix is unused here
|
||||
* // });
|
||||
* ```
|
||||
* @category Global */
|
||||
export async function init(): Promise<Z3HighLevel & Z3LowLevel> {
|
||||
const lowLevel = await initWrapper(initModule);
|
||||
const highLevel = createApi(lowLevel.Z3);
|
||||
export async function init(moduleOverrides: Z3ModuleOverrides = {}): Promise<Z3HighLevel & Z3LowLevel> {
|
||||
const lowLevel = await initWrapper(initModule, moduleOverrides);
|
||||
const highLevel = createApi(lowLevel.Z3, lowLevel.em);
|
||||
return { ...lowLevel, ...highLevel };
|
||||
}
|
||||
|
|
|
|||
|
|
@ -309,6 +309,31 @@ JLCXX_MODULE define_julia_module(jlcxx::Module &m)
|
|||
m.method("sqrt", static_cast<expr (*)(expr const &, expr const &)>(&sqrt));
|
||||
m.method("fma", static_cast<expr (*)(expr const &, expr const &, expr const &, expr const &)>(&fma));
|
||||
m.method("range", &range);
|
||||
m.method("finite_set_empty", &finite_set_empty);
|
||||
m.method("finite_set_singleton", &finite_set_singleton);
|
||||
m.method("finite_set_union", &finite_set_union);
|
||||
m.method("finite_set_intersect", &finite_set_intersect);
|
||||
m.method("finite_set_difference", &finite_set_difference);
|
||||
m.method("finite_set_member", &finite_set_member);
|
||||
m.method("finite_set_size", &finite_set_size);
|
||||
m.method("finite_set_subset", &finite_set_subset);
|
||||
m.method("finite_set_map", &finite_set_map);
|
||||
m.method("finite_set_filter", &finite_set_filter);
|
||||
m.method("finite_set_range", &finite_set_range);
|
||||
m.method("empty_set", &empty_set);
|
||||
m.method("full_set", &full_set);
|
||||
m.method("set_add", &set_add);
|
||||
m.method("set_del", &set_del);
|
||||
m.method("set_union", &set_union);
|
||||
m.method("set_intersect", &set_intersect);
|
||||
m.method("set_difference", &set_difference);
|
||||
m.method("set_complement", &set_complement);
|
||||
m.method("set_member", &set_member);
|
||||
m.method("set_subset", &set_subset);
|
||||
m.method("linear_order", &linear_order);
|
||||
m.method("partial_order", &partial_order);
|
||||
m.method("piecewise_linear_order", &piecewise_linear_order);
|
||||
m.method("tree_order", &tree_order);
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
|
|
@ -618,6 +643,13 @@ JLCXX_MODULE define_julia_module(jlcxx::Module &m)
|
|||
.MM(context, string_sort)
|
||||
.MM(context, seq_sort)
|
||||
.MM(context, re_sort)
|
||||
.MM(context, char_sort)
|
||||
.MM(context, finite_set_sort)
|
||||
.method("set_sort", [](context &c, sort s) {
|
||||
Z3_sort r = Z3_mk_set_sort(c, s);
|
||||
c.check_error();
|
||||
return sort(c, r);
|
||||
})
|
||||
.method("array_sort", static_cast<sort (context::*)(sort, sort)>(&context::array_sort))
|
||||
.method("array_sort", static_cast<sort (context::*)(sort_vector const&, sort)>(&context::array_sort))
|
||||
.method("fpa_sort", static_cast<sort (context::*)(unsigned, unsigned)>(&context::fpa_sort))
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
|
||||
find_package(OCaml REQUIRED)
|
||||
|
||||
set(exe_ext ${CMAKE_EXECUTABLE_SUFFIX})
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue