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 /// </summary> public delegate void CreatedEh(Expr term); + /// <summary> + /// Delegate type for callback into solver's branching + /// <param name="term">A bit-vector or Boolean used for branching</param> + /// <param name="idx">If the term is a bit-vector, then an index into the bit-vector being branched on</param> + /// <param name="phase">Set phase to -1 (false) or 1 (true) to override solver's phase</param> + /// </summary> + 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(); + } + /// <summary> /// Propagator constructor from a solver class. /// </summary> @@ -266,6 +289,19 @@ namespace Microsoft.Z3 } } + /// <summary> + /// Set decision callback + /// </summary> + public DecideEh Decide + { + set + { + this.decide_eh = value; + if (solver != null) + Native.Z3_solver_propagate_decide(ctx.nCtx, solver.NativeObject, _decide); + } + } + /// <summary> /// Track assignments to a term /// </summary> 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);