Skip to content

Commit fa3d341

Browse files
add on_binding callbacks across APIs
update release notes, add to Java, .Net, C++
1 parent 30830aa commit fa3d341

6 files changed

Lines changed: 90 additions & 1 deletion

File tree

RELEASE_NOTES.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,15 @@ Version 4.next
77
- CDCL core for SMT queries. It extends the SAT engine with theory solver plugins.
88
- add global incremental pre-processing for the legacy core.
99

10+
Version 4.15.3
11+
==============
12+
- Add UserPropagator callback option for quantifier instantiations. It allows the user propagator to
13+
intercept quantifier instantiations. It can then inspect these in the callback. By returning false,
14+
the callback signals that the instantiation should be discarded by the solver. The user propagator
15+
is then able to apply finer control over instantiations. It can also use this mechanism to delay
16+
instantiations.
17+
18+
1019
Version 4.15.2
1120
==============
1221
- #7690, #7691 - fix leak introduced in arithmetic solver.

scripts/update_api.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -641,6 +641,7 @@ def mk_java(java_src, java_dir, package_name):
641641
public static native void propagateRegisterEq(Object o, long ctx, long solver);
642642
public static native void propagateRegisterDecide(Object o, long ctx, long solver);
643643
public static native void propagateRegisterFinal(Object o, long ctx, long solver);
644+
public static native void propagateRegisterOnBinding(Object o, long ctx, long solver);
644645
public static native void propagateAdd(Object o, long ctx, long solver, long javainfo, long e);
645646
public static native boolean propagateConsequence(Object o, long ctx, long solver, long javainfo, int num_fixed, long[] fixed, long num_eqs, long[] eq_lhs, long[] eq_rhs, long conseq);
646647
public static native boolean propagateNextSplit(Object o, long ctx, long solver, long javainfo, long e, long idx, int phase);
@@ -684,6 +685,10 @@ def mk_java(java_src, java_dir, package_name):
684685
protected final void registerFinal() {
685686
Native.propagateRegisterFinal(this, ctx, solver);
686687
}
688+
689+
protected final void registerOnBinding() {
690+
Native.propagateRegisterOnBinding(this, ctx, solver);
691+
}
687692
688693
protected abstract void pushWrapper();
689694
@@ -700,6 +705,8 @@ def mk_java(java_src, java_dir, package_name):
700705
protected abstract void fixedWrapper(long lvar, long lvalue);
701706
702707
protected abstract void decideWrapper(long lvar, int bit, boolean is_pos);
708+
709+
protected abstract boolean onBindingWrapper(long q, long inst);
703710
}
704711
""")
705712
java_native.write('\n')

src/api/c++/z3++.h

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4295,12 +4295,14 @@ namespace z3 {
42954295
typedef std::function<void(expr const&, expr const&)> eq_eh_t;
42964296
typedef std::function<void(expr const&)> created_eh_t;
42974297
typedef std::function<void(expr, unsigned, bool)> decide_eh_t;
4298+
typedef std::function<bool(expr const&, expr const&)> on_binding_eh_t;
42984299

42994300
final_eh_t m_final_eh;
43004301
eq_eh_t m_eq_eh;
43014302
fixed_eh_t m_fixed_eh;
43024303
created_eh_t m_created_eh;
43034304
decide_eh_t m_decide_eh;
4305+
on_binding_eh_t m_on_binding_eh;
43044306
solver* s;
43054307
context* c;
43064308
std::vector<z3::context*> subcontexts;
@@ -4372,6 +4374,13 @@ namespace z3 {
43724374
expr val(p->ctx(), _val);
43734375
p->m_decide_eh(val, bit, is_pos);
43744376
}
4377+
4378+
static bool on_binding_eh(void* _p, Z3_solver_callback cb, Z3_ast _q, Z3_ast _inst) {
4379+
user_propagator_base* p = static_cast<user_propagator_base*>(_p);
4380+
scoped_cb _cb(p, cb);
4381+
expr q(p->ctx(), _q), inst(p->ctx(), _inst);
4382+
return p->m_on_binding_eh(q, inst);
4383+
}
43754384

43764385
public:
43774386
user_propagator_base(context& c) : s(nullptr), c(&c) {}
@@ -4498,6 +4507,14 @@ namespace z3 {
44984507
}
44994508
}
45004509

4510+
void register_on_binding() {
4511+
m_on_binding_eh = [this](expr const& q, expr const& inst) {
4512+
return on_binding(q, inst);
4513+
};
4514+
if (s)
4515+
Z3_solver_propagate_on_binding(ctx(), *s, on_binding_eh);
4516+
}
4517+
45014518
virtual void fixed(expr const& /*id*/, expr const& /*e*/) { }
45024519

45034520
virtual void eq(expr const& /*x*/, expr const& /*y*/) { }
@@ -4508,6 +4525,8 @@ namespace z3 {
45084525

45094526
virtual void decide(expr const& /*val*/, unsigned /*bit*/, bool /*is_pos*/) {}
45104527

4528+
virtual bool on_binding(expr const& /*q*/, expr const& /*inst*/) { return true; }
4529+
45114530
bool next_split(expr const& e, unsigned idx, Z3_lbool phase) {
45124531
assert(cb);
45134532
return Z3_solver_next_split(ctx(), cb, e, idx, phase);

src/api/dotnet/UserPropagator.cs

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,15 @@ public class UserPropagator : IDisposable
6464
/// <param name="idx">If the term is a bit-vector, then an index into the bit-vector being branched on</param>
6565
/// <param name="phase">The tentative truth-value</param>
6666
public delegate void DecideEh(Expr term, uint idx, bool phase);
67-
67+
68+
/// <summary>
69+
/// Delegate type for callback when a quantifier is bound to an instance.
70+
/// </summary>
71+
/// <param name="q">Quantifier</param>
72+
/// <param name="inst">Instance</param>
73+
/// <returns>true if binding is allowed to take effect in the solver, false if blocked by callback</returns>
74+
public delegate bool OnBindingEh(Expr q, Expr inst);
75+
6876
// access managed objects through a static array.
6977
// thread safety is ignored for now.
7078
GCHandle gch;
@@ -78,6 +86,7 @@ public class UserPropagator : IDisposable
7886
EqEh diseq_eh;
7987
CreatedEh created_eh;
8088
DecideEh decide_eh;
89+
OnBindingEh on_binding_eh;
8190

8291
Native.Z3_push_eh push_eh;
8392
Native.Z3_pop_eh pop_eh;
@@ -89,6 +98,7 @@ public class UserPropagator : IDisposable
8998
Native.Z3_eq_eh diseq_wrapper;
9099
Native.Z3_decide_eh decide_wrapper;
91100
Native.Z3_created_eh created_wrapper;
101+
Native.Z3_on_binding_eh on_binding_wrapper;
92102

93103
void Callback(Action fn, Z3_solver_callback cb)
94104
{
@@ -175,6 +185,19 @@ static void _decide(voidp ctx, Z3_solver_callback cb, Z3_ast a, uint idx, bool p
175185
prop.Callback(() => prop.decide_eh(t, idx, phase), cb);
176186
}
177187

188+
static bool _on_binding(voidp _ctx, Z3_solver_callback cb, Z3_ast _q, Z3_ast _inst)
189+
{
190+
var prop = (UserPropagator)GCHandle.FromIntPtr(_ctx).Target;
191+
using var q = Expr.Create(prop.ctx, _q);
192+
using var inst = Expr.Create(prop.ctx, _inst);
193+
bool result = true;
194+
prop.Callback(() => {
195+
if (prop.on_binding_wrapper != null)
196+
result = prop.on_binding_eh(q, inst);
197+
}, cb);
198+
return result;
199+
}
200+
178201
/// <summary>
179202
/// Propagator constructor from a solver class.
180203
/// </summary>
@@ -362,6 +385,20 @@ public DecideEh Decide
362385
}
363386
}
364387

388+
/// <summary>
389+
/// Set binding callback
390+
/// </summary>
391+
public OnBindingEh OnBinding
392+
{
393+
set
394+
{
395+
this.on_binding_wrapper = _on_binding;
396+
this.on_binding_eh = value;
397+
if (solver != null)
398+
Native.Z3_solver_propagate_on_binding(ctx.nCtx, solver.NativeObject, on_binding_wrapper);
399+
}
400+
}
401+
365402

366403
/// <summary>
367404
/// Set the next decision
@@ -378,6 +415,8 @@ public bool NextSplit(Expr e, uint idx, int phase)
378415
return Native.Z3_solver_next_split(ctx.nCtx, this.callback, e?.NativeObject ?? IntPtr.Zero, idx, phase) != 0;
379416
}
380417

418+
419+
381420
/// <summary>
382421
/// Track assignments to a term
383422
/// </summary>

src/api/java/NativeStatic.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,12 @@ static void decide_eh(void* _p, Z3_solver_callback cb, Z3_ast _val, unsigned bit
153153
info->jenv->CallVoidMethod(info->jobj, info->decide, (jlong)_val, bit, is_pos);
154154
}
155155

156+
static boolean on_binding_eh(void* _p, Z3_solver_callback cb, Z3_ast _q, Z3_ast _inst) {
157+
JavaInfo *info = static_cast<JavaInfo*>(_p);
158+
ScopedCB scoped(info, cb);
159+
return info->jenv->CallVoidMethod(info->jobj, info->on_binding, (jlong)_q, (jlong)_inst);
160+
}
161+
156162
DLL_VIS JNIEXPORT jlong JNICALL Java_com_microsoft_z3_Native_propagateInit(JNIEnv *jenv, jclass cls, jobject jobj, jlong ctx, jlong solver) {
157163
JavaInfo *info = new JavaInfo;
158164

src/api/java/UserPropagatorBase.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,13 @@ protected final void eqWrapper(long lx, long ly) {
4343
eq(x, y);
4444
}
4545

46+
@Override
47+
protected final boolean onBindingWrapper(long lq, long linst) {
48+
Expr q = new Expr(ctx, lq);
49+
Expr inst = new Expr(ctx, linst);
50+
return on_binding(q, inst);
51+
}
52+
4653
@Override
4754
protected final UserPropagatorBase freshWrapper(long lctx) {
4855
return fresh(new Context(lctx));
@@ -77,6 +84,8 @@ public void created(Expr<?> ast) {}
7784
public void fixed(Expr<?> var, Expr<?> value) {}
7885

7986
public void eq(Expr<?> x, Expr<?> y) {}
87+
88+
public boolean on_binding(Expr<?> q, Expr<?> inst) { return true; }
8089

8190
public void decide(Expr<?> var, int bit, boolean is_pos) {}
8291

0 commit comments

Comments
 (0)