mirror of
https://github.com/Z3Prover/z3
synced 2025-04-23 09:05:31 +00:00
Fix UP's decide callback (#6707)
* Query Boolean Assignment in the UP * UP's decide ref arguments => next_split * Fixed wrapper * More fixes
This commit is contained in:
parent
d59bf55539
commit
82667bd86b
18 changed files with 174 additions and 169 deletions
|
@ -1114,17 +1114,17 @@ extern "C" {
|
|||
void Z3_API Z3_solver_propagate_decide(Z3_context c, Z3_solver s, Z3_decide_eh decide_eh) {
|
||||
Z3_TRY;
|
||||
RESET_ERROR_CODE();
|
||||
user_propagator::decide_eh_t c = (void(*)(void*, user_propagator::callback*, expr**, unsigned*, lbool*))decide_eh;
|
||||
user_propagator::decide_eh_t c = (void(*)(void*, user_propagator::callback*, expr*, unsigned, bool))decide_eh;
|
||||
to_solver_ref(s)->user_propagate_register_decide(c);
|
||||
Z3_CATCH;
|
||||
}
|
||||
|
||||
void Z3_API Z3_solver_next_split(Z3_context c, Z3_solver_callback cb, Z3_ast t, unsigned idx, Z3_lbool phase) {
|
||||
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);
|
||||
RESET_ERROR_CODE();
|
||||
reinterpret_cast<user_propagator::callback*>(cb)->next_split_cb(to_expr(t), idx, (lbool)phase);
|
||||
Z3_CATCH;
|
||||
return reinterpret_cast<user_propagator::callback*>(cb)->next_split_cb(to_expr(t), idx, (lbool)phase);
|
||||
Z3_CATCH_RETURN(false);
|
||||
}
|
||||
|
||||
Z3_func_decl Z3_API Z3_solver_propagate_declare(Z3_context c, Z3_symbol name, unsigned n, Z3_sort* domain, Z3_sort range) {
|
||||
|
|
|
@ -4240,7 +4240,7 @@ namespace z3 {
|
|||
typedef std::function<void(void)> final_eh_t;
|
||||
typedef std::function<void(expr const&, expr const&)> eq_eh_t;
|
||||
typedef std::function<void(expr const&)> created_eh_t;
|
||||
typedef std::function<void(expr&, unsigned&, Z3_lbool&)> decide_eh_t;
|
||||
typedef std::function<void(expr, unsigned, bool)> decide_eh_t;
|
||||
|
||||
final_eh_t m_final_eh;
|
||||
eq_eh_t m_eq_eh;
|
||||
|
@ -4309,13 +4309,11 @@ namespace z3 {
|
|||
p->m_created_eh(e);
|
||||
}
|
||||
|
||||
static void decide_eh(void* _p, Z3_solver_callback cb, Z3_ast* _val, unsigned* bit, Z3_lbool* is_pos) {
|
||||
static void decide_eh(void* _p, Z3_solver_callback cb, Z3_ast _val, unsigned bit, bool is_pos) {
|
||||
user_propagator_base* p = static_cast<user_propagator_base*>(_p);
|
||||
scoped_cb _cb(p, cb);
|
||||
expr val(p->ctx(), *_val);
|
||||
p->m_decide_eh(val, *bit, *is_pos);
|
||||
// TBD: life time of val is within the scope of this callback.
|
||||
*_val = val;
|
||||
expr val(p->ctx(), _val);
|
||||
p->m_decide_eh(val, bit, is_pos);
|
||||
}
|
||||
|
||||
public:
|
||||
|
@ -4435,7 +4433,7 @@ namespace z3 {
|
|||
}
|
||||
|
||||
void register_decide() {
|
||||
m_decide_eh = [this](expr& val, unsigned& bit, Z3_lbool& is_pos) {
|
||||
m_decide_eh = [this](expr val, unsigned bit, bool is_pos) {
|
||||
decide(val, bit, is_pos);
|
||||
};
|
||||
if (s) {
|
||||
|
@ -4451,11 +4449,11 @@ namespace z3 {
|
|||
|
||||
virtual void created(expr const& /*e*/) {}
|
||||
|
||||
virtual void decide(expr& /*val*/, unsigned& /*bit*/, Z3_lbool& /*is_pos*/) {}
|
||||
virtual void decide(expr const& /*val*/, unsigned /*bit*/, bool /*is_pos*/) {}
|
||||
|
||||
void next_split(expr const & e, unsigned idx, Z3_lbool phase) {
|
||||
bool next_split(expr const& e, unsigned idx, Z3_lbool phase) {
|
||||
assert(cb);
|
||||
Z3_solver_next_split(ctx(), cb, e, idx, phase);
|
||||
return Z3_solver_next_split(ctx(), cb, e, idx, phase);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -58,12 +58,12 @@ namespace Microsoft.Z3
|
|||
public delegate void CreatedEh(Expr term);
|
||||
|
||||
/// <summary>
|
||||
/// Delegate type for callback into solver's branching
|
||||
/// Delegate type for callback into solver's branching. The values can be overriden by calling <see cref="NextSplit" />.
|
||||
/// </summary>
|
||||
/// <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);
|
||||
/// <param name="phase">The tentative truth-value</param>
|
||||
public delegate void DecideEh(Expr term, uint idx, bool phase);
|
||||
|
||||
// access managed objects through a static array.
|
||||
// thread safety is ignored for now.
|
||||
|
@ -168,16 +168,11 @@ namespace Microsoft.Z3
|
|||
prop.Callback(() => prop.created_eh(t), cb);
|
||||
}
|
||||
|
||||
static void _decide(voidp ctx, Z3_solver_callback cb, ref Z3_ast a, ref uint idx, ref int phase)
|
||||
static void _decide(voidp ctx, Z3_solver_callback cb, Z3_ast a, uint idx, bool phase)
|
||||
{
|
||||
var prop = (UserPropagator)GCHandle.FromIntPtr(ctx).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;
|
||||
using var t = Expr.Create(prop.ctx, a);
|
||||
prop.Callback(() => prop.decide_eh(t, idx, phase), cb);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -352,10 +347,17 @@ namespace Microsoft.Z3
|
|||
|
||||
/// <summary>
|
||||
/// Set the next decision
|
||||
/// <param name="e">A bit-vector or Boolean used for branching. Use <see langword="null" /> to clear</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">The tentative truth-value (-1/false, 1/true, 0/let Z3 decide)</param>
|
||||
/// </summary>
|
||||
public void NextSplit(Expr e, uint idx, int phase)
|
||||
/// <returns>
|
||||
/// <see langword="true" /> in case the value was successfully set;
|
||||
/// <see langword="false" /> if the next split could not be set
|
||||
/// </returns>
|
||||
public bool NextSplit(Expr e, uint idx, int phase)
|
||||
{
|
||||
Native.Z3_solver_next_split(ctx.nCtx, this.callback, e.NativeObject, idx, phase);
|
||||
return Native.Z3_solver_next_split(ctx.nCtx, this.callback, e?.NativeObject ?? IntPtr.Zero, idx, phase) != 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -91,6 +91,7 @@ struct JavaInfo {
|
|||
jmethodID fixed = nullptr;
|
||||
jmethodID eq = nullptr;
|
||||
jmethodID final = nullptr;
|
||||
jmethodID decide = nullptr;
|
||||
|
||||
Z3_solver_callback cb = nullptr;
|
||||
};
|
||||
|
@ -146,11 +147,10 @@ static void final_eh(void* _p, Z3_solver_callback cb) {
|
|||
info->jenv->CallVoidMethod(info->jobj, info->final);
|
||||
}
|
||||
|
||||
// TODO: implement decide
|
||||
static void decide_eh(void* _p, Z3_solver_callback cb, Z3_ast* _val, unsigned* bit, Z3_lbool* is_pos) {
|
||||
static void decide_eh(void* _p, Z3_solver_callback cb, Z3_ast _val, unsigned bit, bool is_pos) {
|
||||
JavaInfo *info = static_cast<JavaInfo*>(_p);
|
||||
ScopedCB scoped(info, cb);
|
||||
|
||||
info->jenv->CallVoidMethod(info->jobj, info->decide, (jlong)_val);
|
||||
}
|
||||
|
||||
DLL_VIS JNIEXPORT jlong JNICALL Java_com_microsoft_z3_Native_propagateInit(JNIEnv *jenv, jclass cls, jobject jobj, jlong ctx, jlong solver) {
|
||||
|
@ -166,8 +166,9 @@ DLL_VIS JNIEXPORT jlong JNICALL Java_com_microsoft_z3_Native_propagateInit(JNIEn
|
|||
info->fixed = jenv->GetMethodID(jcls, "fixedWrapper", "(JJ)V");
|
||||
info->eq = jenv->GetMethodID(jcls, "eqWrapper", "(JJ)V");
|
||||
info->final = jenv->GetMethodID(jcls, "finWrapper", "()V");
|
||||
|
||||
if (!info->push || !info->pop || !info->fresh || !info->created || !info->fixed || !info->eq || !info->final) {
|
||||
info->decide = jenv->GetMethodID(jcls, "decideWrapper", "(JII)V");
|
||||
|
||||
if (!info->push || !info->pop || !info->fresh || !info->created || !info->fixed || !info->eq || !info->final || !info->decide) {
|
||||
assert(false);
|
||||
}
|
||||
|
||||
|
@ -225,8 +226,8 @@ DLL_VIS JNIEXPORT void JNICALL Java_com_microsoft_z3_Native_propagateAdd(JNIEnv
|
|||
}
|
||||
}
|
||||
|
||||
DLL_VIS JNIEXPORT void JNICALL Java_com_microsoft_z3_Native_propagateNextSplit(JNIEnv * jenv, jclass cls, jobject jobj, jlong ctx, jlong solver, jlong javainfo, long e, long idx, long phase) {
|
||||
DLL_VIS JNIEXPORT bool JNICALL Java_com_microsoft_z3_Native_propagateNextSplit(JNIEnv * jenv, jclass cls, jobject jobj, jlong ctx, jlong solver, jlong javainfo, long e, long idx, int phase) {
|
||||
JavaInfo *info = (JavaInfo*)javainfo;
|
||||
Z3_solver_callback cb = info->cb;
|
||||
Z3_solver_next_split((Z3_context)ctx, cb, (Z3_ast)e, idx, Z3_lbool(phase));
|
||||
return Z3_solver_next_split((Z3_context)ctx, cb, (Z3_ast)e, idx, Z3_lbool(phase));
|
||||
}
|
||||
|
|
|
@ -89,9 +89,9 @@ public abstract class UserPropagatorBase extends Native.UserPropagatorBase {
|
|||
fixed.length, AST.arrayToNative(fixed), lhs.length, AST.arrayToNative(lhs), AST.arrayToNative(rhs), conseq.getNativeObject());
|
||||
}
|
||||
|
||||
public final <R extends Sort> void nextSplit(Expr<R> e, long idx, Z3_lbool phase) {
|
||||
Native.propagateNextSplit(
|
||||
public final <R extends Sort> boolean nextSplit(Expr<R> e, long idx, Z3_lbool phase) {
|
||||
return Native.propagateNextSplit(
|
||||
this, ctx.nCtx(), solver.getNativeObject(), javainfo,
|
||||
e.getNativeObject(), idx, phase.toInt());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11529,16 +11529,11 @@ def user_prop_diseq(ctx, cb, x, y):
|
|||
prop.diseq(x, y)
|
||||
prop.cb = None
|
||||
|
||||
# TODO The decision callback is not fully implemented.
|
||||
# It needs to handle the ast*, unsigned* idx, and Z3_lbool*
|
||||
def user_prop_decide(ctx, cb, t_ref, idx_ref, phase_ref):
|
||||
def user_prop_decide(ctx, cb, t, idx, phase):
|
||||
prop = _prop_closures.get(ctx)
|
||||
prop.cb = cb
|
||||
t = _to_expr_ref(to_Ast(t_ref), prop.ctx())
|
||||
t, idx, phase = prop.decide(t, idx, phase)
|
||||
t_ref = t
|
||||
idx_ref = idx
|
||||
phase_ref = phase
|
||||
prop.decide(t, idx, phase)
|
||||
prop.cb = None
|
||||
|
||||
|
||||
|
@ -11685,7 +11680,7 @@ class UserPropagateBase:
|
|||
# split on. A phase of true = 1/false = -1/undef = 0 = let solver decide is the last argument.
|
||||
#
|
||||
def next_split(self, t, idx, phase):
|
||||
Z3_solver_next_split(self.ctx_ref(), ctypes.c_void_p(self.cb), t.ast, idx, phase)
|
||||
return Z3_solver_next_split(self.ctx_ref(), ctypes.c_void_p(self.cb), t.ast, idx, phase)
|
||||
|
||||
#
|
||||
# Propagation can only be invoked as during a fixed or final callback.
|
||||
|
|
|
@ -1435,7 +1435,7 @@ Z3_DECLARE_CLOSURE(Z3_fixed_eh, void, (void* ctx, Z3_solver_callback cb, Z3_as
|
|||
Z3_DECLARE_CLOSURE(Z3_eq_eh, void, (void* ctx, Z3_solver_callback cb, Z3_ast s, Z3_ast t));
|
||||
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, Z3_lbool* phase));
|
||||
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_clause_eh, void, (void* ctx, Z3_ast proof_hint, Z3_ast_vector literals));
|
||||
|
||||
|
||||
|
@ -7098,20 +7098,21 @@ extern "C" {
|
|||
|
||||
/**
|
||||
\brief register a callback when the solver decides to split on a registered expression.
|
||||
The callback may set the passed expression to another registered expression which will be selected instead.
|
||||
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.
|
||||
The callback may change the arguments by providing other values by calling \ref Z3_solver_next_split
|
||||
|
||||
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);
|
||||
|
||||
/**
|
||||
Sets the next expression to split on
|
||||
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
|
||||
(due to relevancy propagation, this assignments might not have been reported yet by the fixed callback).
|
||||
In case the function is called in the decide callback, it overrides the currently selected variable and phase.
|
||||
|
||||
def_API('Z3_solver_next_split', VOID, (_in(CONTEXT), _in(SOLVER_CALLBACK), _in(AST), _in(UINT), _in(LBOOL)))
|
||||
def_API('Z3_solver_next_split', BOOL, (_in(CONTEXT), _in(SOLVER_CALLBACK), _in(AST), _in(UINT), _in(LBOOL)))
|
||||
*/
|
||||
void Z3_API Z3_solver_next_split(Z3_context c, Z3_solver_callback cb, Z3_ast t, unsigned idx, Z3_lbool phase);
|
||||
bool Z3_API Z3_solver_next_split(Z3_context c, Z3_solver_callback cb, Z3_ast t, unsigned idx, Z3_lbool phase);
|
||||
|
||||
/**
|
||||
Create uninterpreted function declaration for the user propagator.
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue