3
0
Fork 0
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:
Clemens Eisenhofer 2023-06-02 09:52:54 +02:00 committed by GitHub
parent d59bf55539
commit 82667bd86b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
18 changed files with 174 additions and 169 deletions

View file

@ -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) {

View file

@ -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);
}
/**

View file

@ -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>

View file

@ -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));
}

View file

@ -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());
}
}
}

View file

@ -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.

View file

@ -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.