3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-08-20 02:00:22 +00:00

add an option to register callback on quantifier instantiation

Suppose a user propagator encodes axioms using quantifiers and uses E-matching for instantiation. If it wants to implement a custom priority scheme or drop some instances based on internal checks it can register a callback with quantifier instantiation
This commit is contained in:
Nikolaj Bjorner 2025-08-06 21:11:38 -07:00
parent d4a4dd6cc7
commit b33f444545
24 changed files with 126 additions and 3 deletions

View file

@ -1160,6 +1160,14 @@ extern "C" {
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);
Z3_CATCH;
}
bool Z3_API Z3_solver_next_split(Z3_context c, Z3_solver_callback cb, Z3_ast t, unsigned idx, Z3_lbool phase) {
Z3_TRY;
LOG_Z3_solver_next_split(c, cb, t, idx, phase);

View file

@ -11814,6 +11814,16 @@ def user_prop_decide(ctx, cb, t_ref, idx, phase):
t = _to_expr_ref(to_Ast(t_ref), prop.ctx())
prop.decide(t, idx, phase)
prop.cb = old_cb
def user_prop_binding(ctx, cb, q_ref, inst_ref):
prop = _prop_closures.get(ctx)
old_cb = prop.cb
prop.cb = cb
q = _to_expr_ref(to_Ast(q_ref), prop.ctx())
inst = _to_expr_ref(to_Ast(inst_ref), prop.ctx())
r = prop.binding(q, inst)
prop.cb = old_cb
return r
_user_prop_push = Z3_push_eh(user_prop_push)
@ -11825,6 +11835,7 @@ _user_prop_final = Z3_final_eh(user_prop_final)
_user_prop_eq = Z3_eq_eh(user_prop_eq)
_user_prop_diseq = Z3_eq_eh(user_prop_diseq)
_user_prop_decide = Z3_decide_eh(user_prop_decide)
_user_prop_binding = Z3_on_binding_eh(user_prop_binding)
def PropagateFunction(name, *sig):
@ -11873,6 +11884,7 @@ class UserPropagateBase:
self.diseq = None
self.decide = None
self.created = None
self.binding = None
if ctx:
self.fresh_ctx = ctx
if s:
@ -11936,7 +11948,14 @@ class UserPropagateBase:
assert not self._ctx
if self.solver:
Z3_solver_propagate_decide(self.ctx_ref(), self.solver.solver, _user_prop_decide)
self.decide = decide
self.decide = decide
def add_on_binding(self, binding):
assert not self.binding
assert not self._ctx
if self.solver:
Z3_solver_propagate_on_binding(self.ctx_ref(), self.solver.solver, _user_prop_binding)
self.binding = binding
def push(self):
raise Z3Exception("push needs to be overwritten")

View file

@ -1440,6 +1440,7 @@ Z3_DECLARE_CLOSURE(Z3_eq_eh, void, (void* ctx, Z3_solver_callback cb, Z3_as
Z3_DECLARE_CLOSURE(Z3_final_eh, void, (void* ctx, Z3_solver_callback cb));
Z3_DECLARE_CLOSURE(Z3_created_eh, void, (void* ctx, Z3_solver_callback cb, Z3_ast t));
Z3_DECLARE_CLOSURE(Z3_decide_eh, void, (void* ctx, Z3_solver_callback cb, Z3_ast t, unsigned idx, bool phase));
Z3_DECLARE_CLOSURE(Z3_on_binding_eh, bool, (void* ctx, Z3_solver_callback cb, Z3_ast q, Z3_ast inst));
Z3_DECLARE_CLOSURE(Z3_on_clause_eh, void, (void* ctx, Z3_ast proof_hint, unsigned n, unsigned const* deps, Z3_ast_vector literals));
@ -7225,6 +7226,17 @@ extern "C" {
*/
void Z3_API Z3_solver_propagate_decide(Z3_context c, Z3_solver s, Z3_decide_eh decide_eh);
/**
\brief register a callback when the solver instantiates a quantifier.
If the callback returns false, the actual instantiation of the quantifier is blocked.
This allows the user propagator selectively prioritize instantiations without relying on default
or configured weights.
def_API('Z3_solver_propagate_on_binding', VOID, (_in(CONTEXT), _in(SOLVER), _fnptr(Z3_on_binding_eh)))
*/
void Z3_API Z3_solver_propagate_on_binding(Z3_context c, Z3_solver s, Z3_on_binding_eh on_binding_eh);
/**
Sets the next (registered) expression to split on.
The function returns false and ignores the given expression in case the expression is already assigned internally