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:
parent
5e5ef50dbc
commit
96f10b8c1c
15 changed files with 219 additions and 127 deletions
|
@ -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):
|
||||
|
|
|
@ -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, ¶ms, 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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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()))
|
||||
|
|
|
@ -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.
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue