diff --git a/scripts/update_api.py b/scripts/update_api.py
index b0b795b23..0553843cb 100755
--- a/scripts/update_api.py
+++ b/scripts/update_api.py
@@ -414,6 +414,7 @@ def mk_dotnet(dotnet):
for name, ret, sig in Closures:
sig = sig.replace("void*","voidp").replace("unsigned","uint")
+ sig = sig.replace("Z3_ast*","ref IntPtr").replace("uint*","ref uint").replace("Z3_lbool*","ref int")
ret = ret.replace("void*","voidp").replace("unsigned","uint")
if "*" in sig or "*" in ret:
continue
@@ -1349,7 +1350,8 @@ z3_ml_callbacks = frozenset([
'Z3_solver_propagate_final',
'Z3_solver_propagate_eq',
'Z3_solver_propagate_diseq',
- 'Z3_solver_propagate_created'
+ 'Z3_solver_propagate_created',
+ 'Z3_solver_propagate_decide'
])
def mk_ml(ml_src_dir, ml_output_dir):
diff --git a/src/api/dotnet/UserPropagator.cs b/src/api/dotnet/UserPropagator.cs
index 13532fdf4..4f604b4cb 100644
--- a/src/api/dotnet/UserPropagator.cs
+++ b/src/api/dotnet/UserPropagator.cs
@@ -55,6 +55,14 @@ namespace Microsoft.Z3
///
public delegate void CreatedEh(Expr term);
+ ///
+ /// Delegate type for callback into solver's branching
+ /// A bit-vector or Boolean used for branching
+ /// If the term is a bit-vector, then an index into the bit-vector being branched on
+ /// Set phase to -1 (false) or 1 (true) to override solver's phase
+ ///
+ public delegate void DecideEh(ref Expr term, ref uint idx, ref int phase);
+
Solver solver;
Context ctx;
GCHandle gch;
@@ -64,6 +72,7 @@ namespace Microsoft.Z3
EqEh eq_eh;
EqEh diseq_eh;
CreatedEh created_eh;
+ DecideEh decide_eh;
static void _push(voidp ctx, Z3_solver_callback cb) {
@@ -137,6 +146,20 @@ namespace Microsoft.Z3
prop.callback = IntPtr.Zero;
}
+ static void _decide(voidp ctx, Z3_solver_callback cb, ref Z3_ast a, ref uint idx, ref int phase) {
+ var gch = GCHandle.FromIntPtr(ctx);
+ var prop = (UserPropagator)gch.Target;
+ var t = Expr.Create(prop.ctx, a);
+ var u = t;
+ prop.callback = cb;
+ prop.decide_eh(ref t, ref idx, ref phase);
+ prop.callback = IntPtr.Zero;
+ if (u != t) {
+ a = t.NativeObject;
+ }
+ t.Dispose();
+ }
+
///
/// Propagator constructor from a solver class.
///
@@ -266,6 +289,19 @@ namespace Microsoft.Z3
}
}
+ ///
+ /// Set decision callback
+ ///
+ public DecideEh Decide
+ {
+ set
+ {
+ this.decide_eh = value;
+ if (solver != null)
+ Native.Z3_solver_propagate_decide(ctx.nCtx, solver.NativeObject, _decide);
+ }
+ }
+
///
/// Track assignments to a term
///
diff --git a/src/api/z3_api.h b/src/api/z3_api.h
index e7528da55..4e5f5f5b5 100644
--- a/src/api/z3_api.h
+++ b/src/api/z3_api.h
@@ -6801,6 +6801,7 @@ extern "C" {
In case the expression is a bitvector the bit to split on is determined by the bit argument and the
truth-value to try first is given by is_pos. In case the truth value is undefined the solver will decide.
+ def_API('Z3_solver_propagate_decide', VOID, (_in(CONTEXT), _in(SOLVER), _fnptr(Z3_decide_eh)))
*/
void Z3_API Z3_solver_propagate_decide(Z3_context c, Z3_solver s, Z3_decide_eh decide_eh);