3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-04-23 17:15:31 +00:00

user propagator

Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
Nikolaj Bjorner 2020-08-22 19:00:58 -07:00
parent 5e5ef50dbc
commit 96f10b8c1c
15 changed files with 219 additions and 127 deletions

View file

@ -116,6 +116,8 @@ namespace api {
DEBUG_CODE(warning_msg("Uncollected memory: %d: %s", kv.m_key, typeid(*val).name()););
dealloc(val);
}
if (m_params.owns_manager())
m_manager.detach();
}
context::set_interruptable::set_interruptable(context & ctx, event_handler & i):

View file

@ -896,9 +896,15 @@ extern "C" {
Z3_TRY;
RESET_ERROR_CODE();
init_solver(c, s);
std::function<void(void*)> _push = push_eh;
std::function<void(void*,unsigned)> _pop = pop_eh;
std::function<void*(void*)> _fresh = fresh_eh;
solver::push_eh_t _push = push_eh;
solver::pop_eh_t _pop = pop_eh;
solver::fresh_eh_t _fresh = [&](void * user_ctx, ast_manager& m, void*& _ctx) {
context_params params;
params.set_foreign_manager(&m);
auto* ctx = reinterpret_cast<Z3_context>(alloc(api::context, &params, false));
_ctx = ctx;
return fresh_eh(user_ctx, ctx);
};
to_solver_ref(s)->user_propagate_init(user_context, _push, _pop, _fresh);
Z3_CATCH;
}
@ -955,11 +961,11 @@ extern "C" {
Z3_CATCH_RETURN(0);
}
void Z3_API Z3_solver_propagate_consequence(Z3_context c, Z3_solver_callback s, unsigned sz, unsigned const* ids, Z3_ast conseq) {
void Z3_API Z3_solver_propagate_consequence(Z3_context c, Z3_solver_callback s, unsigned num_fixed, unsigned const* fixed_ids, unsigned num_eqs, unsigned const* eq_lhs, unsigned const* eq_rhs, Z3_ast conseq) {
Z3_TRY;
LOG_Z3_solver_propagate_consequence(c, s, sz, ids, conseq);
LOG_Z3_solver_propagate_consequence(c, s, num_fixed, fixed_ids, num_eqs, eq_lhs, eq_rhs, conseq);
RESET_ERROR_CODE();
reinterpret_cast<solver::propagate_callback*>(s)->propagate(sz, ids, to_expr(conseq));
reinterpret_cast<solver::propagate_callback*>(s)->propagate(num_fixed, fixed_ids, num_eqs, eq_lhs, eq_rhs, to_expr(conseq));
Z3_CATCH;
}

View file

@ -10506,30 +10506,39 @@ def TransitiveClosure(f):
class PropClosures:
# import thread
def __init__(self):
self.bases = {}
# self.lock = thread.Lock()
self.lock = None
def set_threaded():
if self.lock is None:
import threading
self.lock = threading.thread.Lock()
def get(self, ctx):
# self.lock.acquire()
if self.lock: self.lock.acquire()
r = self.bases[ctx]
# self.lock.release()
if self.lock: self.lock.release()
return r
def set(self, ctx, r):
# self.lock.acquire()
if self.lock: self.lock.acquire()
self.bases[ctx] = r
# self.lock.release()
if self.lock: self.lock.release()
def insert(self, r):
# self.lock.acquire()
if self.lock: self.lock.acquire()
id = len(self.bases) + 3
self.bases[id] = r
# self.lock.release()
if self.lock: self.lock.release()
return id
_prop_closures = PropClosures()
_prop_closures = None
def ensure_prop_closures():
global _prop_closures
if _prop_closures is None:
_prop_closures = PropClosures()
def user_prop_push(ctx):
_prop_closures.get(ctx).push();
@ -10537,9 +10546,10 @@ def user_prop_push(ctx):
def user_prop_pop(ctx, num_scopes):
_prop_closures.get(ctx).pop(num_scopes)
def user_prop_fresh(ctx):
prop = _prop_closures.get(ctx)
new_prop = UsePropagateBase(None, prop.ctx)
def user_prop_fresh(id, ctx):
prop = _prop_closures.get(id)
_prop_closures.set_threaded()
new_prop = UsePropagateBase(None, ctx)
_prop_closures.set(new_prop.id, new_prop.fresh())
return ctypes.c_void_p(new_prop.id)
@ -10577,66 +10587,104 @@ _user_prop_diseq = eq_eh_type(user_prop_diseq)
class UserPropagateBase:
#
# Either solver is set or ctx is set.
# Propagators that are created throuh callbacks
# to "fresh" inherit the context of that is supplied
# as argument to the callback.
# This context should not be deleted. It is owned by the solver.
#
def __init__(self, s, ctx = None):
assert s is None or ctx is None
ensure_prop_closures()
self.solver = s
self.ctx = s.ctx if s is not None else ctx
self._ctx = None
self.cb = None
self.id = _prop_closures.insert(self)
self.fixed = None
self.final = None
self.eq = None
self.diseq = None
if ctx:
self._ctx = Context()
Z3_del_context(self._ctx.ctx)
self._ctx.ctx = ctx
self._ctx.eh = Z3_set_error_handler(ctx, z3_error_handler)
Z3_set_ast_print_mode(ctx, Z3_PRINT_SMTLIB2_COMPLIANT)
if s:
Z3_solver_propagate_init(s.ctx.ref(),
Z3_solver_propagate_init(self.ctx_ref(),
s.solver,
ctypes.c_void_p(self.id),
_user_prop_push,
_user_prop_pop,
_user_prop_fresh)
def __del__(self):
if self._ctx:
self._ctx.ctx = None
def ctx(self):
if self._ctx:
return self._ctx
else:
return self.solver.ctx
def ctx_ref(self):
return self.ctx().ref()
def add_fixed(self, fixed):
assert not self.fixed
Z3_solver_propagate_fixed(self.ctx.ref(), self.solver.solver, _user_prop_fixed)
assert not self._ctx
Z3_solver_propagate_fixed(self.ctx_ref(), self.solver.solver, _user_prop_fixed)
self.fixed = fixed
def add_final(self, final):
assert not self.final
Z3_solver_propagate_final(self.ctx.ref(), self.solver.solver, _user_prop_final)
assert not self._ctx
Z3_solver_propagate_final(self.ctx_ref(), self.solver.solver, _user_prop_final)
self.final = final
def add_eq(self, eq):
assert not self.eq
Z3_solver_propagate_eq(self.ctx.ref(), self.solver.solver, _user_prop_eq)
assert not self._ctx
Z3_solver_propagate_eq(self.ctx_ref(), self.solver.solver, _user_prop_eq)
self.eq = eq
def add_diseq(self, diseq):
assert not self.diseq
Z3_solver_propagate_diseq(self.ctx.ref(), self.solver.solver, _user_prop_diseq)
assert not self._ctx
Z3_solver_propagate_diseq(self.ctx_ref(), self.solver.solver, _user_prop_diseq)
self.diseq = diseq
def push(self):
raise Z3Exception("push has not been overwritten")
raise Z3Exception("push needs to be overwritten")
def pop(self, num_scopes):
raise Z3Exception("pop has not been overwritten")
raise Z3Exception("pop needs to be overwritten")
def fresh(self):
raise Z3Exception("fresh has not been overwritten")
raise Z3Exception("fresh needs to be overwritten")
def add(self, e):
assert self.solver
return Z3_solver_propagate_register(self.ctx.ref(), self.solver.solver, e.ast)
assert not self._ctx
return Z3_solver_propagate_register(self.ctx_ref(), self.solver.solver, e.ast)
#
# Propagation can only be invoked as during a fixed-callback.
#
def propagate(self, ids, e):
sz = len(ids)
_ids = (ctypes.c_uint * sz)()
for i in range(sz):
def propagate(self, e, ids, eqs = []):
num_fixed = len(ids)
_ids = (ctypes.c_uint * num_fixed)()
for i in range(num_fixed):
_ids[i] = ids[i]
Z3_solver_propagate_consequence(self.ctx.ref(), ctypes.c_void_p(self.cb), sz, _ids, e.ast)
num_eqs = len(eqs)
_lhs = (ctypes.c_uint * num_eqs)()
_rhs = (ctypes.c_uint * num_eqs)()
for i in range(num_eqs):
_lhs[i] = eqs[i][0]
_rhs[i] = eqs[i][1]
Z3_solver_propagate_consequence(self.ctx_ref(), ctypes.c_void_p(self.cb), num_fixed, _ids, num_eqs, _lhs, _rhs, e.ast)
def conflict(self, ids):
self.propagate(ids, BoolVal(False, self.ctx))
self.propagate(ids, BoolVal(False, self.ctx_ref()))

View file

@ -1420,7 +1420,7 @@ typedef void Z3_error_handler(Z3_context c, Z3_error_code e);
*/
typedef void Z3_push_eh(void* ctx);
typedef void Z3_pop_eh(void* ctx, unsigned num_scopes);
typedef void* Z3_fresh_eh(void* ctx);
typedef void* Z3_fresh_eh(void* ctx, Z3_context new_context);
typedef void Z3_fixed_eh(void* ctx, Z3_solver_callback cb, unsigned id, Z3_ast value);
typedef void Z3_eq_eh(void* ctx, Z3_solver_callback cb, unsigned x, unsigned y);
typedef void Z3_final_eh(void* ctx, Z3_solver_callback cb);
@ -6586,10 +6586,10 @@ extern "C" {
The callback adds a propagation consequence based on the fixed values of the
\c ids.
def_API('Z3_solver_propagate_consequence', VOID, (_in(CONTEXT), _in(SOLVER_CALLBACK), _in(UINT), _in_array(2, UINT), _in(AST)))
def_API('Z3_solver_propagate_consequence', VOID, (_in(CONTEXT), _in(SOLVER_CALLBACK), _in(UINT), _in_array(2, UINT), _in(UINT), _in_array(4, UINT), _in_array(4, UINT), _in(AST)))
*/
void Z3_API Z3_solver_propagate_consequence(Z3_context c, Z3_solver_callback, unsigned sz, unsigned const* ids, Z3_ast conseq);
void Z3_API Z3_solver_propagate_consequence(Z3_context c, Z3_solver_callback, unsigned num_fixed, unsigned const* fixed_ids, unsigned num_eqs, unsigned const* eq_lhs, unsigned const* eq_rhs, Z3_ast conseq);
/**
\brief Check whether the assertions in a given solver are consistent or not.