mirror of
https://github.com/Z3Prover/z3
synced 2025-04-22 16:45:31 +00:00
Merge branch 'master' into polysat
This commit is contained in:
commit
8bde66420a
36 changed files with 292 additions and 225 deletions
|
@ -249,7 +249,10 @@ extern "C" {
|
|||
expr_abstract(mk_c(c)->m(), 0, num_bound, bound_asts.data(), pat, result);
|
||||
SASSERT(result.get()->get_kind() == AST_APP);
|
||||
pinned.push_back(result.get());
|
||||
SASSERT(mk_c(c)->m().is_pattern(result.get()));
|
||||
if (!mk_c(c)->m().is_pattern(result.get())) {
|
||||
SET_ERROR_CODE(Z3_INVALID_ARG, "invalid pattern");
|
||||
RETURN_Z3(nullptr);
|
||||
}
|
||||
_patterns.push_back(of_pattern(result.get()));
|
||||
}
|
||||
svector<Z3_ast> _no_patterns;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -202,7 +203,7 @@ DLL_VIS JNIEXPORT void JNICALL Java_com_microsoft_z3_Native_propagateRegisterDec
|
|||
Z3_solver_propagate_decide((Z3_context)ctx, (Z3_solver)solver, decide_eh);
|
||||
}
|
||||
|
||||
DLL_VIS JNIEXPORT void JNICALL Java_com_microsoft_z3_Native_propagateConflict(JNIEnv * jenv, jclass cls, jobject jobj, jlong ctx, jlong solver, jlong javainfo, jlong num_fixed, jlongArray fixed, jlong num_eqs, jlongArray eq_lhs, jlongArray eq_rhs, jlong conseq) {
|
||||
DLL_VIS JNIEXPORT void JNICALL Java_com_microsoft_z3_Native_propagateConflict(JNIEnv * jenv, jclass cls, jobject jobj, jlong ctx, jlong solver, jlong javainfo, long num_fixed, jlongArray fixed, long num_eqs, jlongArray eq_lhs, jlongArray eq_rhs, jlong conseq) {
|
||||
JavaInfo *info = (JavaInfo*)javainfo;
|
||||
GETLONGAELEMS(Z3_ast, fixed, _fixed);
|
||||
GETLONGAELEMS(Z3_ast, eq_lhs, _eq_lhs);
|
||||
|
@ -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, jlong 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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7136,6 +7136,13 @@ class Solver(Z3PPObject):
|
|||
"""Import model converter from other into the current solver"""
|
||||
Z3_solver_import_model_converter(self.ctx.ref(), other.solver, self.solver)
|
||||
|
||||
def interrupt(self):
|
||||
"""Interrupt the execution of the solver object.
|
||||
Remarks: This ensures that the interrupt applies only
|
||||
to the given solver object and it applies only if it is running.
|
||||
"""
|
||||
Z3_solver_interrupt(self.ctx.ref(), self.solver)
|
||||
|
||||
def unsat_core(self):
|
||||
"""Return a subset (as an AST vector) of the assumptions provided to the last check().
|
||||
|
||||
|
@ -11522,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
|
||||
|
||||
|
||||
|
@ -11678,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.
|
||||
|
|
|
@ -3019,8 +3019,8 @@ br_status bv_rewriter::mk_bvumul_no_overflow(unsigned num, expr * const * args,
|
|||
|
||||
br_status bv_rewriter::mk_bvneg_overflow(expr * const arg, expr_ref & result) {
|
||||
unsigned int sz = get_bv_size(arg);
|
||||
auto maxUnsigned = mk_numeral(rational::power_of_two(sz)-1, sz);
|
||||
result = m.mk_eq(arg, maxUnsigned);
|
||||
auto minSigned = mk_numeral(rational::power_of_two(sz - 1), sz); // 0b1000...0
|
||||
result = m.mk_eq(arg, minSigned);
|
||||
return BR_REWRITE3;
|
||||
}
|
||||
|
||||
|
@ -3089,7 +3089,7 @@ br_status bv_rewriter::mk_bvssub_overflow(unsigned num, expr * const * args, exp
|
|||
SASSERT(num == 2);
|
||||
SASSERT(get_bv_size(args[0]) == get_bv_size(args[1]));
|
||||
auto sz = get_bv_size(args[0]);
|
||||
auto minSigned = mk_numeral(-rational::power_of_two(sz-1), sz);
|
||||
auto minSigned = mk_numeral(rational::power_of_two(sz-1), sz);
|
||||
expr_ref bvsaddo {m};
|
||||
expr * args2[2] = { args[0], m_util.mk_bv_neg(args[1]) };
|
||||
auto bvsaddo_stat = mk_bvsadd_overflow(2, args2, bvsaddo);
|
||||
|
@ -3102,7 +3102,7 @@ br_status bv_rewriter::mk_bvsdiv_overflow(unsigned num, expr * const * args, exp
|
|||
SASSERT(num == 2);
|
||||
SASSERT(get_bv_size(args[0]) == get_bv_size(args[1]));
|
||||
auto sz = get_bv_size(args[1]);
|
||||
auto minSigned = mk_numeral(-rational::power_of_two(sz-1), sz);
|
||||
auto minSigned = mk_numeral(rational::power_of_two(sz-1), sz);
|
||||
auto minusOne = mk_numeral(rational::power_of_two(sz) - 1, sz);
|
||||
result = m.mk_and(m.mk_eq(args[0], minSigned), m.mk_eq(args[1], minusOne));
|
||||
return BR_REWRITE_FULL;
|
||||
|
|
|
@ -176,9 +176,9 @@ void der::reduce1(quantifier * q, expr_ref & r, proof_ref & pr) {
|
|||
var * v = nullptr;
|
||||
expr_ref t(m);
|
||||
|
||||
if (is_forall(q) && is_var_diseq(e, num_decls, v, t) && !occurs(v, t))
|
||||
if (is_forall(q) && is_var_diseq(e, num_decls, v, t) && !has_quantifiers(t) && !occurs(v, t))
|
||||
r = m.mk_false();
|
||||
else if (is_exists(q) && is_var_eq(e, num_decls, v, t) && !occurs(v, t))
|
||||
else if (is_exists(q) && is_var_eq(e, num_decls, v, t) && !has_quantifiers(t) && !occurs(v, t))
|
||||
r = m.mk_true();
|
||||
else {
|
||||
expr_ref_vector literals(m);
|
||||
|
|
|
@ -74,6 +74,7 @@ struct th_rewriter_cfg : public default_rewriter_cfg {
|
|||
bool m_push_ite_bv = true;
|
||||
bool m_ignore_patterns_on_ground_qbody = true;
|
||||
bool m_rewrite_patterns = true;
|
||||
bool m_enable_der = true;
|
||||
|
||||
|
||||
ast_manager & m() const { return m_b_rw.m(); }
|
||||
|
@ -89,6 +90,7 @@ struct th_rewriter_cfg : public default_rewriter_cfg {
|
|||
m_push_ite_bv = p.push_ite_bv();
|
||||
m_ignore_patterns_on_ground_qbody = p.ignore_patterns_on_ground_qbody();
|
||||
m_rewrite_patterns = p.rewrite_patterns();
|
||||
m_enable_der = p.enable_der();
|
||||
}
|
||||
|
||||
void updt_params(params_ref const & p) {
|
||||
|
@ -827,11 +829,12 @@ struct th_rewriter_cfg : public default_rewriter_cfg {
|
|||
expr_ref r(m());
|
||||
|
||||
bool der_change = false;
|
||||
if (is_quantifier(result) && to_quantifier(result)->get_num_patterns() == 0) {
|
||||
if (m_enable_der && is_quantifier(result) && to_quantifier(result)->get_num_patterns() == 0) {
|
||||
m_der(to_quantifier(result), r, p2);
|
||||
der_change = result.get() != r.get();
|
||||
if (m().proofs_enabled() && der_change)
|
||||
result_pr = m().mk_transitivity(result_pr, p2);
|
||||
result_pr = m().mk_transitivity(result_pr, p2);
|
||||
|
||||
result = r;
|
||||
}
|
||||
|
||||
|
|
|
@ -58,9 +58,9 @@ struct bound_simplifier::rw : public rewriter_tpl<rw_cfg> {
|
|||
br_status bound_simplifier::reduce_app(func_decl* f, unsigned num_args, expr* const* args, expr_ref& result, proof_ref& pr) {
|
||||
rational N, hi, lo;
|
||||
if (a.is_mod(f) && num_args == 2 && a.is_numeral(args[1], N)) {
|
||||
expr* x = args[0];
|
||||
auto& im = m_interval;
|
||||
scoped_dep_interval i(im);
|
||||
expr* x = args[0];
|
||||
get_bounds(x, i);
|
||||
if (im.upper_is_inf(i) || im.lower_is_inf(i))
|
||||
return BR_FAILED;
|
||||
|
@ -83,7 +83,55 @@ br_status bound_simplifier::reduce_app(func_decl* f, unsigned num_args, expr* co
|
|||
}
|
||||
IF_VERBOSE(2, verbose_stream() << "potentially missed simplification: " << mk_pp(x, m) << " " << lo << " " << hi << " not reduced\n");
|
||||
}
|
||||
return BR_FAILED;
|
||||
|
||||
expr_ref_buffer new_args(m);
|
||||
expr_ref new_arg(m);
|
||||
bool change = false;
|
||||
for (unsigned i = 0; i < num_args; ++i) {
|
||||
expr* arg = args[i];
|
||||
change = reduce_arg(arg, new_arg) || change;
|
||||
new_args.push_back(new_arg);
|
||||
}
|
||||
if (!change)
|
||||
return BR_FAILED;
|
||||
|
||||
result = m.mk_app(f, num_args, new_args.data());
|
||||
|
||||
return BR_DONE;
|
||||
}
|
||||
|
||||
bool bound_simplifier::reduce_arg(expr* arg, expr_ref& result) {
|
||||
result = arg;
|
||||
expr* x, *y;
|
||||
rational N, lo, hi;
|
||||
bool strict;
|
||||
if ((a.is_le(arg, x, y) && a.is_numeral(y, N)) ||
|
||||
(a.is_ge(arg, y, x) && a.is_numeral(y, N))) {
|
||||
|
||||
if (has_upper(x, hi, strict) && !strict && N >= hi) {
|
||||
result = m.mk_true();
|
||||
return true;
|
||||
}
|
||||
if (has_lower(x, lo, strict) && !strict && N < lo) {
|
||||
result = m.mk_false();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((a.is_le(arg, y, x) && a.is_numeral(y, N)) ||
|
||||
(a.is_ge(arg, x, y) && a.is_numeral(y, N))) {
|
||||
if (has_lower(x, lo, strict) && !strict && N <= lo) {
|
||||
result = m.mk_true();
|
||||
return true;
|
||||
}
|
||||
if (has_upper(x, hi, strict) && !strict && N > hi) {
|
||||
result = m.mk_false();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void bound_simplifier::reduce() {
|
||||
|
|
|
@ -77,8 +77,12 @@ class bound_simplifier : public dependent_expr_simplifier {
|
|||
return v;
|
||||
}
|
||||
|
||||
bool reduce_arg(expr* arg, expr_ref& result);
|
||||
|
||||
br_status reduce_app(func_decl* f, unsigned num_args, expr* const* args, expr_ref& result, proof_ref& pr);
|
||||
|
||||
|
||||
|
||||
void assert_lower(expr* x, rational const& n, bool strict);
|
||||
void assert_upper(expr* x, rational const& n, bool strict);
|
||||
|
||||
|
|
|
@ -508,8 +508,12 @@ public:
|
|||
m_owner.m_func_decls.contains(s);
|
||||
}
|
||||
format_ns::format * pp_sort(sort * s) override {
|
||||
return m_owner.pp(s);
|
||||
auto * f = m_owner.try_pp(s);
|
||||
if (f)
|
||||
return f;
|
||||
return smt2_pp_environment::pp_sort(s);
|
||||
}
|
||||
|
||||
format_ns::format * pp_fdecl(func_decl * f, unsigned & len) override {
|
||||
symbol s = f->get_name();
|
||||
func_decls fs;
|
||||
|
@ -2261,8 +2265,12 @@ bool cmd_context::is_model_available(model_ref& md) const {
|
|||
}
|
||||
|
||||
format_ns::format * cmd_context::pp(sort * s) const {
|
||||
return get_pp_env().pp_sort(s);
|
||||
}
|
||||
|
||||
format_ns::format* cmd_context::try_pp(sort* s) const {
|
||||
TRACE("cmd_context", tout << "pp(sort * s), s: " << mk_pp(s, m()) << "\n";);
|
||||
return pm().pp(s);
|
||||
return pm().pp(get_pp_env(), s);
|
||||
}
|
||||
|
||||
cmd_context::pp_env & cmd_context::get_pp_env() const {
|
||||
|
|
|
@ -538,6 +538,7 @@ public:
|
|||
}
|
||||
|
||||
format_ns::format * pp(sort * s) const;
|
||||
format_ns::format* try_pp(sort* s) const;
|
||||
void pp(sort * s, format_ns::format_ref & r) const override { r = pp(s); }
|
||||
void pp(func_decl * f, format_ns::format_ref & r) const override;
|
||||
void pp(expr * n, unsigned num_vars, char const * var_prefix, format_ns::format_ref & r, sbuffer<symbol> & var_names) const override;
|
||||
|
|
|
@ -785,7 +785,7 @@ struct pdecl_manager::sort_info {
|
|||
virtual unsigned obj_size() const { return sizeof(sort_info); }
|
||||
virtual void finalize(pdecl_manager & m) { m.dec_ref(m_decl); }
|
||||
virtual void display(std::ostream & out, pdecl_manager const & m) const = 0;
|
||||
virtual format * pp(pdecl_manager const & m) const = 0;
|
||||
virtual format * pp(smt2_pp_environment& env, pdecl_manager const & m) const = 0;
|
||||
};
|
||||
|
||||
struct pdecl_manager::app_sort_info : public pdecl_manager::sort_info {
|
||||
|
@ -817,14 +817,14 @@ struct pdecl_manager::app_sort_info : public pdecl_manager::sort_info {
|
|||
}
|
||||
}
|
||||
|
||||
format * pp(pdecl_manager const & m) const override {
|
||||
format * pp(smt2_pp_environment& env, pdecl_manager const & m) const override {
|
||||
if (m_args.empty()) {
|
||||
return mk_string(m.m(), m_decl->get_name().str());
|
||||
}
|
||||
else {
|
||||
ptr_buffer<format> b;
|
||||
for (auto arg : m_args)
|
||||
b.push_back(m.pp(arg));
|
||||
b.push_back(m.pp(env, arg));
|
||||
return mk_seq1(m.m(), b.begin(), b.end(), f2f(), m_decl->get_name().str());
|
||||
}
|
||||
}
|
||||
|
@ -853,7 +853,7 @@ struct pdecl_manager::indexed_sort_info : public pdecl_manager::sort_info {
|
|||
}
|
||||
}
|
||||
|
||||
format * pp(pdecl_manager const & m) const override {
|
||||
format * pp(smt2_pp_environment& env, pdecl_manager const & m) const override {
|
||||
if (m_indices.empty()) {
|
||||
return mk_string(m.m(), m_decl->get_name().str());
|
||||
}
|
||||
|
@ -1072,27 +1072,10 @@ void pdecl_manager::display(std::ostream & out, sort * s) const {
|
|||
out << s->get_name();
|
||||
}
|
||||
|
||||
format * pdecl_manager::pp(sort * s) const {
|
||||
format * pdecl_manager::pp(smt2_pp_environment& env, sort * s) const {
|
||||
sort_info * info = nullptr;
|
||||
if (m_sort2info.find(s, info)) {
|
||||
return info->pp(*this);
|
||||
}
|
||||
unsigned num_params = s->get_num_parameters();
|
||||
if (s->get_family_id() != null_family_id && num_params > 0) {
|
||||
// Small hack to display FP and BitVec sorts that were not explicitly referenced by the user.
|
||||
unsigned i = 0;
|
||||
for (i = 0; i < num_params; i++) {
|
||||
if (!s->get_parameter(i).is_int())
|
||||
break;
|
||||
}
|
||||
if (i == num_params) {
|
||||
// all parameters are integer
|
||||
ptr_buffer<format> b;
|
||||
b.push_back(mk_string(m(), s->get_name().str()));
|
||||
for (unsigned i = 0; i < num_params; i++)
|
||||
b.push_back(mk_unsigned(m(), s->get_parameter(i).get_int()));
|
||||
return mk_seq1(m(), b.begin(), b.end(), f2f(), "_");
|
||||
}
|
||||
}
|
||||
return mk_string(m(), s->get_name().str());
|
||||
if (m_sort2info.find(s, info))
|
||||
return info->pp(env, *this);
|
||||
else
|
||||
return nullptr;
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@ Revision History:
|
|||
#include "util/dictionary.h"
|
||||
#include "ast/format.h"
|
||||
#include "ast/datatype_decl_plugin.h"
|
||||
#include "ast/ast_smt2_pp.h"
|
||||
|
||||
class pdecl_manager;
|
||||
|
||||
|
@ -333,7 +334,7 @@ public:
|
|||
void save_info(sort * s, psort_decl * d, unsigned num_args, sort * const * args);
|
||||
void save_info(sort * s, psort_decl * d, unsigned num_indices, unsigned const * indices);
|
||||
void display(std::ostream & out, sort * s) const;
|
||||
format_ns::format * pp(sort * s) const;
|
||||
format_ns::format * pp(smt2_pp_environment& env, sort * s) const;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -1034,14 +1034,10 @@ namespace lp {
|
|||
r += p.coeff() * get_value(p.column());
|
||||
return r;
|
||||
}
|
||||
|
||||
impq lar_solver::get_tv_ivalue(tv const& t) const {
|
||||
if (t.is_var())
|
||||
return get_column_value(t.column());
|
||||
impq r;
|
||||
for (lar_term::ival p : get_term(t))
|
||||
r += p.coeff() * get_column_value(p.column());
|
||||
return r;
|
||||
//fetches the cached value of the term or the variable by the given index
|
||||
const impq& lar_solver::get_tv_ivalue(tv const& t) const {
|
||||
unsigned j = t.is_var()? (unsigned)t.column(): this->map_term_index_to_column_index(t.index());
|
||||
return this->get_column_value(j);
|
||||
}
|
||||
|
||||
void lar_solver::get_rid_of_inf_eps() {
|
||||
|
|
|
@ -506,7 +506,7 @@ public:
|
|||
bool init_model() const;
|
||||
mpq get_value(column_index const& j) const;
|
||||
mpq get_tv_value(tv const& t) const;
|
||||
impq get_tv_ivalue(tv const& t) const;
|
||||
const impq & get_tv_ivalue(tv const& t) const;
|
||||
void get_model(std::unordered_map<var_index, mpq> & variable_values) const;
|
||||
void get_rid_of_inf_eps();
|
||||
void get_model_do_not_care_about_diff_vars(std::unordered_map<var_index, mpq> & variable_values) const;
|
||||
|
|
|
@ -37,6 +37,7 @@ void lp_primal_core_solver<T, X>::sort_non_basis() {
|
|||
unsigned ca = this->m_A.number_of_non_zeroes_in_column(a);
|
||||
unsigned cb = this->m_A.number_of_non_zeroes_in_column(b);
|
||||
if (ca == 0 && cb != 0) return false;
|
||||
if (ca != 0 && cb == 0) return true;
|
||||
return ca < cb;
|
||||
});
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@ def_module_params('rewriter',
|
|||
("pull_cheap_ite", BOOL, False, "pull if-then-else terms when cheap."),
|
||||
("bv_ineq_consistency_test_max", UINT, 0, "max size of conjunctions on which to perform consistency test based on inequalities on bitvectors."),
|
||||
("cache_all", BOOL, False, "cache all intermediate results."),
|
||||
("enable_der", BOOL, True, "enable destructive equality resolution to quantifiers."),
|
||||
("rewrite_patterns", BOOL, False, "rewrite patterns."),
|
||||
("ignore_patterns_on_ground_qbody", BOOL, True, "ignores patterns on quantifiers that don't mention their bound variables.")))
|
||||
|
||||
|
|
|
@ -129,7 +129,7 @@ namespace bv {
|
|||
/**
|
||||
\brief Find an unassigned bit for m_wpos[v], if such bit cannot be found invoke fixed_var_eh
|
||||
*/
|
||||
void solver::find_wpos(theory_var v) {
|
||||
bool solver::find_wpos(theory_var v) {
|
||||
literal_vector const& bits = m_bits[v];
|
||||
unsigned sz = bits.size();
|
||||
unsigned& wpos = m_wpos[v];
|
||||
|
@ -138,11 +138,12 @@ namespace bv {
|
|||
if (s().value(bits[idx]) == l_undef) {
|
||||
wpos = idx;
|
||||
TRACE("bv", tout << "moved wpos of v" << v << " to " << wpos << "\n";);
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
TRACE("bv", tout << "v" << v << " is a fixed variable.\n";);
|
||||
fixed_var_eh(v);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -919,7 +920,17 @@ namespace bv {
|
|||
values[n->get_root_id()] = bv.mk_numeral(val, m_bits[v].size());
|
||||
}
|
||||
|
||||
trail_stack& solver::get_trail_stack() {
|
||||
sat::bool_var solver::get_bit(unsigned bit, euf::enode *n) const {
|
||||
theory_var v = n->get_th_var(get_id());
|
||||
if (v == euf::null_theory_var)
|
||||
return sat::null_bool_var;
|
||||
auto &bits = m_bits[v];
|
||||
if (bit >= bits.size())
|
||||
return sat::null_bool_var;
|
||||
return bits[bit].var();
|
||||
}
|
||||
|
||||
trail_stack &solver::get_trail_stack() {
|
||||
return ctx.get_trail_stack();
|
||||
}
|
||||
|
||||
|
|
|
@ -382,7 +382,7 @@ namespace bv {
|
|||
|
||||
// solving
|
||||
theory_var find(theory_var v) const { return m_find.find(v); }
|
||||
void find_wpos(theory_var v);
|
||||
bool find_wpos(theory_var v);
|
||||
void find_new_diseq_axioms(atom& a, theory_var v, unsigned idx);
|
||||
void mk_new_diseq_axiom(theory_var v1, theory_var v2, unsigned idx);
|
||||
bool get_fixed_value(theory_var v, numeral& result) const;
|
||||
|
@ -395,7 +395,6 @@ namespace bv {
|
|||
numeral const& power2(unsigned i) const;
|
||||
sat::literal mk_true();
|
||||
|
||||
|
||||
// invariants
|
||||
bool check_zero_one_bits(theory_var v);
|
||||
void check_missing_propagation() const;
|
||||
|
@ -452,6 +451,7 @@ namespace bv {
|
|||
euf::theory_var mk_var(euf::enode* n) override;
|
||||
void apply_sort_cnstr(euf::enode * n, sort * s) override;
|
||||
|
||||
bool_var get_bit(unsigned bit, euf::enode* n) const;
|
||||
|
||||
void merge_eh(theory_var, theory_var, theory_var v1, theory_var v2);
|
||||
void after_merge_eh(theory_var r1, theory_var r2, theory_var v1, theory_var v2) { SASSERT(check_zero_one_bits(r1)); }
|
||||
|
|
|
@ -15,8 +15,9 @@ Author:
|
|||
|
||||
--*/
|
||||
|
||||
#include "sat/smt/user_solver.h"
|
||||
#include "sat/smt/bv_solver.h"
|
||||
#include "sat/smt/euf_solver.h"
|
||||
#include "sat/smt/user_solver.h"
|
||||
|
||||
namespace user_solver {
|
||||
|
||||
|
@ -39,7 +40,7 @@ namespace user_solver {
|
|||
expr_ref r(m);
|
||||
sat::literal_vector explain;
|
||||
if (ctx.is_fixed(n, r, explain))
|
||||
m_prop.push_back(prop_info(explain, v, r));
|
||||
m_prop.push_back(prop_info(explain, v, r));
|
||||
}
|
||||
|
||||
void solver::propagate_cb(
|
||||
|
@ -56,17 +57,21 @@ namespace user_solver {
|
|||
void solver::register_cb(expr* e) {
|
||||
add_expr(e);
|
||||
}
|
||||
|
||||
void solver::next_split_cb(expr* e, unsigned idx, lbool phase) {
|
||||
|
||||
bool solver::next_split_cb(expr* e, unsigned idx, lbool phase) {
|
||||
if (e == nullptr) {
|
||||
m_next_split_expr = nullptr;
|
||||
return;
|
||||
m_next_split_var = sat::null_bool_var;
|
||||
return true;
|
||||
}
|
||||
force_push();
|
||||
ctx.internalize(e);
|
||||
m_next_split_expr = e;
|
||||
m_next_split_idx = idx;
|
||||
sat::bool_var var = enode_to_bool(ctx.get_enode(e), idx);
|
||||
m_next_split_phase = phase;
|
||||
if (var == sat::null_bool_var || s().value(var) != l_undef)
|
||||
return false;
|
||||
m_next_split_var = var;
|
||||
m_next_split_phase = phase;
|
||||
return true;
|
||||
}
|
||||
|
||||
sat::check_result solver::check() {
|
||||
|
@ -84,39 +89,41 @@ namespace user_solver {
|
|||
m_id2justification.setx(v, sat::literal_vector(num_lits, jlits), sat::literal_vector());
|
||||
m_fixed_eh(m_user_context, this, var2expr(v), value);
|
||||
}
|
||||
|
||||
|
||||
bool solver::decide(sat::bool_var& var, lbool& phase) {
|
||||
|
||||
|
||||
if (!m_decide_eh)
|
||||
return false;
|
||||
|
||||
|
||||
euf::enode* original_enode = bool_var2enode(var);
|
||||
|
||||
|
||||
if (!original_enode || !is_attached_to_var(original_enode))
|
||||
return false;
|
||||
|
||||
|
||||
unsigned new_bit = 0; // ignored; currently no bv-support
|
||||
expr* e = original_enode->get_expr();
|
||||
|
||||
m_decide_eh(m_user_context, this, &e, &new_bit, &phase);
|
||||
|
||||
euf::enode* new_enode = ctx.get_enode(e);
|
||||
|
||||
if (original_enode == new_enode || new_enode->bool_var() == sat::null_bool_var)
|
||||
|
||||
m_decide_eh(m_user_context, this, e, new_bit, phase);
|
||||
sat::bool_var new_var;
|
||||
if (!get_case_split(new_var, phase) || new_var == var)
|
||||
// The user did not interfere
|
||||
return false;
|
||||
|
||||
var = new_enode->bool_var();
|
||||
var = new_var;
|
||||
|
||||
// check if the new variable is unassigned
|
||||
if (s().value(var) != l_undef)
|
||||
throw default_exception("expression in \"decide\" is already assigned");
|
||||
return true;
|
||||
}
|
||||
|
||||
bool solver::get_case_split(sat::bool_var& var, lbool& phase){
|
||||
if (!m_next_split_expr)
|
||||
|
||||
bool solver::get_case_split(sat::bool_var& var, lbool& phase) {
|
||||
if (m_next_split_var == sat::null_bool_var)
|
||||
return false;
|
||||
|
||||
euf::enode* n = ctx.get_enode(m_next_split_expr);
|
||||
var = n->bool_var();
|
||||
|
||||
var = m_next_split_var;
|
||||
phase = m_next_split_phase;
|
||||
m_next_split_expr = nullptr;
|
||||
m_next_split_var = sat::null_bool_var;
|
||||
m_next_split_phase = l_undef;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -134,14 +141,14 @@ namespace user_solver {
|
|||
m_id2justification.setx(v, lits, sat::literal_vector());
|
||||
m_fixed_eh(m_user_context, this, var2expr(v), lit.sign() ? m.mk_false() : m.mk_true());
|
||||
}
|
||||
|
||||
|
||||
void solver::new_eq_eh(euf::th_eq const& eq) {
|
||||
if (!m_eq_eh)
|
||||
return;
|
||||
force_push();
|
||||
m_eq_eh(m_user_context, this, var2expr(eq.v1()), var2expr(eq.v2()));
|
||||
}
|
||||
|
||||
|
||||
void solver::new_diseq_eh(euf::th_eq const& de) {
|
||||
if (!m_diseq_eh)
|
||||
return;
|
||||
|
@ -188,7 +195,7 @@ namespace user_solver {
|
|||
propagate_consequence(prop);
|
||||
else
|
||||
propagate_new_fixed(prop);
|
||||
}
|
||||
}
|
||||
return np < m_stats.m_num_propagations;
|
||||
}
|
||||
|
||||
|
@ -208,7 +215,7 @@ namespace user_solver {
|
|||
auto& j = justification::from_index(idx);
|
||||
auto const& prop = m_prop[j.m_propagation_index];
|
||||
for (unsigned id : prop.m_ids)
|
||||
r.append(m_id2justification[id]);
|
||||
r.append(m_id2justification[id]);
|
||||
for (auto const& p : prop.m_eqs)
|
||||
ctx.add_antecedent(probing, expr2enode(p.first), expr2enode(p.second));
|
||||
}
|
||||
|
@ -243,7 +250,7 @@ namespace user_solver {
|
|||
}
|
||||
|
||||
std::ostream& solver::display_constraint(std::ostream& out, sat::ext_constraint_idx idx) const {
|
||||
return display_justification(out, idx);
|
||||
return display_justification(out, idx);
|
||||
}
|
||||
|
||||
euf::th_solver* solver::clone(euf::solver& dst_ctx) {
|
||||
|
@ -278,26 +285,35 @@ namespace user_solver {
|
|||
return true;
|
||||
}
|
||||
m_stack.push_back(sat::eframe(e));
|
||||
return false;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool solver::visited(expr* e) {
|
||||
euf::enode* n = expr2enode(e);
|
||||
return n && n->is_attached_to(get_id());
|
||||
return n && n->is_attached_to(get_id());
|
||||
}
|
||||
|
||||
|
||||
bool solver::post_visit(expr* e, bool sign, bool root) {
|
||||
euf::enode* n = expr2enode(e);
|
||||
SASSERT(!n || !n->is_attached_to(get_id()));
|
||||
if (!n)
|
||||
n = mk_enode(e, false);
|
||||
if (!n)
|
||||
n = mk_enode(e, false);
|
||||
add_expr(e);
|
||||
if (m_created_eh)
|
||||
m_created_eh(m_user_context, this, e);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
sat::bool_var solver::enode_to_bool(euf::enode* n, unsigned idx) {
|
||||
if (n->bool_var() != sat::null_bool_var) {
|
||||
// expression is a boolean
|
||||
return n->bool_var();
|
||||
}
|
||||
// expression is a bit-vector
|
||||
bv_util bv(m);
|
||||
th_solver* th = ctx.fid2solver(bv.get_fid());
|
||||
return ((bv::solver*) th)->get_bit(idx, n);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -75,9 +75,8 @@ namespace user_solver {
|
|||
euf::enode_pair_vector m_eqs;
|
||||
unsigned_vector m_fixed_ids;
|
||||
stats m_stats;
|
||||
expr* m_next_split_expr = nullptr;
|
||||
unsigned m_next_split_idx;
|
||||
lbool m_next_split_phase;
|
||||
sat::bool_var m_next_split_var = sat::null_bool_var;
|
||||
lbool m_next_split_phase = l_undef;
|
||||
|
||||
struct justification {
|
||||
unsigned m_propagation_index { 0 };
|
||||
|
@ -104,6 +103,8 @@ namespace user_solver {
|
|||
bool visited(expr* e) override;
|
||||
bool post_visit(expr* e, bool sign, bool root) override;
|
||||
|
||||
sat::bool_var enode_to_bool(euf::enode* n, unsigned idx);
|
||||
|
||||
public:
|
||||
solver(euf::solver& ctx);
|
||||
|
||||
|
@ -136,7 +137,7 @@ namespace user_solver {
|
|||
|
||||
void propagate_cb(unsigned num_fixed, expr* const* fixed_ids, unsigned num_eqs, expr* const* lhs, expr* const* rhs, expr* conseq) override;
|
||||
void register_cb(expr* e) override;
|
||||
void next_split_cb(expr* e, unsigned idx, lbool phase) override;
|
||||
bool next_split_cb(expr* e, unsigned idx, lbool phase) override;
|
||||
|
||||
void new_fixed_eh(euf::theory_var v, expr* value, unsigned num_lits, sat::literal const* jlits);
|
||||
|
||||
|
|
|
@ -131,6 +131,8 @@ namespace smt {
|
|||
// max_top_generation and min_top_generation are not available for computing inc_gen
|
||||
set_values(q, nullptr, generation, 0, 0, cost);
|
||||
float r = m_evaluator(m_new_gen_function, m_vals.size(), m_vals.data());
|
||||
if (q->get_weight() > 0 || r > 0)
|
||||
return static_cast<unsigned>(r);
|
||||
return std::max(generation + 1, static_cast<unsigned>(r));
|
||||
}
|
||||
|
||||
|
|
|
@ -2918,7 +2918,9 @@ namespace smt {
|
|||
bool context::has_split_candidate(bool_var& var, bool& is_pos) {
|
||||
if (!m_user_propagator)
|
||||
return false;
|
||||
return m_user_propagator->get_case_split(var, is_pos);
|
||||
if (!m_user_propagator->get_case_split(var, is_pos))
|
||||
return false;
|
||||
return get_assignment(var) == l_undef;
|
||||
}
|
||||
|
||||
bool context::decide_user_interference(bool_var& var, bool& is_pos) {
|
||||
|
|
|
@ -635,7 +635,7 @@ namespace smt {
|
|||
literal_vector lits;
|
||||
const_cast<conflict_resolution&>(*m_conflict_resolution).justification2literals(j.get_justification(), lits);
|
||||
out << "justification " << j.get_justification()->get_from_theory() << ": ";
|
||||
// display_literals_smt2(out, lits);
|
||||
display_literals_smt2(out, lits);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
|
|
|
@ -969,7 +969,6 @@ namespace smt {
|
|||
}
|
||||
|
||||
model_value_proc * theory_array_base::mk_value(enode * n, model_generator & mg) {
|
||||
SASSERT(ctx.is_relevant(n));
|
||||
theory_var v = n->get_th_var(get_id());
|
||||
SASSERT(v != null_theory_var);
|
||||
sort * s = n->get_expr()->get_sort();
|
||||
|
|
|
@ -1889,21 +1889,14 @@ namespace smt {
|
|||
return var_enode_pos(nullptr, UINT32_MAX);
|
||||
}
|
||||
|
||||
bool_var theory_bv::get_first_unassigned(unsigned start_bit, enode* n) const {
|
||||
bool_var theory_bv::get_bit(unsigned bit, enode* n) const {
|
||||
theory_var v = n->get_th_var(get_family_id());
|
||||
if (v == null_theory_var)
|
||||
return null_bool_var;
|
||||
auto& bits = m_bits[v];
|
||||
unsigned sz = bits.size();
|
||||
|
||||
for (unsigned i = start_bit; i < sz; ++i) {
|
||||
if (ctx.get_assignment(bits[i].var()) == l_undef)
|
||||
return bits[i].var();
|
||||
}
|
||||
for (unsigned i = 0; i < start_bit; ++i) {
|
||||
if (ctx.get_assignment(bits[i].var()) == l_undef)
|
||||
return bits[i].var();
|
||||
}
|
||||
|
||||
return null_bool_var;
|
||||
if (bit >= bits.size())
|
||||
return null_bool_var;
|
||||
return bits[bit].var();
|
||||
}
|
||||
|
||||
bool theory_bv::check_assignment(theory_var v) {
|
||||
|
|
|
@ -291,7 +291,7 @@ namespace smt {
|
|||
bool is_fixed_propagated(theory_var v, expr_ref& val, literal_vector& explain) override;
|
||||
|
||||
var_enode_pos get_bv_with_theory(bool_var v, theory_id id) const;
|
||||
bool_var get_first_unassigned(unsigned start_bit, enode* n) const;
|
||||
bool_var get_bit(unsigned bit, enode* n) const;
|
||||
|
||||
bool check_assignment(theory_var v);
|
||||
bool check_invariant();
|
||||
|
|
|
@ -888,9 +888,14 @@ namespace smt {
|
|||
|
||||
func_decl* memf, *nextf, *connectedf;
|
||||
|
||||
std::string member, next, connected_sym;
|
||||
unsigned index = r.decl()->get_parameter(0).get_int();
|
||||
member = "member" + std::to_string(index);
|
||||
next = "next" + std::to_string(index);
|
||||
connected_sym = "connected" + std::to_string(index);
|
||||
{
|
||||
sort* dom[2] = { s, listS };
|
||||
recfun::promise_def mem = p.ensure_def(symbol("member"), 2, dom, m.mk_bool_sort(), true);
|
||||
recfun::promise_def mem = p.ensure_def(symbol(member), 2, dom, m.mk_bool_sort(), true);
|
||||
memf = mem.get_def()->get_decl();
|
||||
|
||||
var_ref xV(m.mk_var(1, s), m);
|
||||
|
@ -913,7 +918,7 @@ namespace smt {
|
|||
|
||||
{
|
||||
sort* dom[5] = { s, s, listS, listS, tup };
|
||||
recfun::promise_def nxt = p.ensure_def(symbol("next"), 5, dom, tup, true);
|
||||
recfun::promise_def nxt = p.ensure_def(symbol(next), 5, dom, tup, true);
|
||||
nextf = nxt.get_def()->get_decl();
|
||||
|
||||
expr_ref next_body(m);
|
||||
|
@ -934,7 +939,7 @@ namespace smt {
|
|||
|
||||
{
|
||||
sort* dom[3] = { listS, s, listS };
|
||||
recfun::promise_def connected = p.ensure_def(symbol("connected"), 3, dom, m.mk_bool_sort(), true);
|
||||
recfun::promise_def connected = p.ensure_def(symbol(connected_sym), 3, dom, m.mk_bool_sort(), true);
|
||||
connectedf = connected.get_def()->get_decl();
|
||||
var_ref AV(m.mk_var(2, listS), m);
|
||||
var_ref dstV(m.mk_var(1, s), m);
|
||||
|
|
|
@ -107,15 +107,18 @@ void theory_user_propagator::register_cb(expr* e) {
|
|||
add_expr(e, true);
|
||||
}
|
||||
|
||||
void theory_user_propagator::next_split_cb(expr* e, unsigned idx, lbool phase) {
|
||||
bool theory_user_propagator::next_split_cb(expr* e, unsigned idx, lbool phase) {
|
||||
if (e == nullptr) { // clear
|
||||
m_next_split_expr = nullptr;
|
||||
return;
|
||||
m_next_split_var = null_bool_var;
|
||||
return true;
|
||||
}
|
||||
ensure_enode(e);
|
||||
m_next_split_expr = e;
|
||||
m_next_split_idx = idx;
|
||||
bool_var b = enode_to_bool(ctx.get_enode(e), idx);
|
||||
if (b == null_bool_var || ctx.get_assignment(b) != l_undef)
|
||||
return false;
|
||||
m_next_split_var = b;
|
||||
m_next_split_phase = phase;
|
||||
return true;
|
||||
}
|
||||
|
||||
theory * theory_user_propagator::mk_fresh(context * new_ctx) {
|
||||
|
@ -174,18 +177,15 @@ void theory_user_propagator::new_fixed_eh(theory_var v, expr* value, unsigned nu
|
|||
}
|
||||
}
|
||||
|
||||
bool_var theory_user_propagator::enode_to_bool(enode* n, unsigned bit) {
|
||||
bool_var theory_user_propagator::enode_to_bool(enode* n, unsigned idx) {
|
||||
if (n->is_bool()) {
|
||||
// expression is a boolean
|
||||
bool_var new_var = ctx.enode2bool_var(n);
|
||||
if (ctx.get_assignment(new_var) == l_undef)
|
||||
return new_var;
|
||||
return null_bool_var;
|
||||
return ctx.enode2bool_var(n);
|
||||
}
|
||||
// expression is a bit-vector
|
||||
bv_util bv(m);
|
||||
auto th_bv = (theory_bv*)ctx.get_theory(bv.get_fid());
|
||||
return th_bv->get_first_unassigned(bit, n);
|
||||
return th_bv->get_bit(idx, n);
|
||||
}
|
||||
|
||||
void theory_user_propagator::decide(bool_var& var, bool& is_pos) {
|
||||
|
@ -225,7 +225,7 @@ void theory_user_propagator::decide(bool_var& var, bool& is_pos) {
|
|||
|
||||
if (v == null_theory_var) {
|
||||
// it is not a registered boolean value but it is a bitvector
|
||||
auto registered_bv = ((theory_bv*)th)->get_bv_with_theory(var, get_family_id());
|
||||
auto registered_bv = ((theory_bv *) th)->get_bv_with_theory(var, get_family_id());
|
||||
if (!registered_bv.first)
|
||||
// there is no registered bv associated with the bit
|
||||
return;
|
||||
|
@ -236,47 +236,33 @@ void theory_user_propagator::decide(bool_var& var, bool& is_pos) {
|
|||
|
||||
// call the registered callback
|
||||
unsigned new_bit = original_bit;
|
||||
lbool phase = is_pos ? l_true : l_false;
|
||||
|
||||
expr* e = var2expr(v);
|
||||
m_decide_eh(m_user_context, this, &e, &new_bit, &phase);
|
||||
enode* new_enode = ctx.get_enode(e);
|
||||
|
||||
// check if the callback changed something
|
||||
if (original_enode == new_enode && (new_enode->is_bool() || original_bit == new_bit)) {
|
||||
if (phase != l_undef)
|
||||
// it only affected the truth value
|
||||
is_pos = phase == l_true;
|
||||
expr *e = var2expr(v);
|
||||
m_decide_eh(m_user_context, this, e, new_bit, is_pos);
|
||||
|
||||
bool_var new_var;
|
||||
if (!get_case_split(new_var, is_pos) || new_var == var)
|
||||
// The user did not interfere
|
||||
return;
|
||||
}
|
||||
var = new_var;
|
||||
|
||||
// get unassigned variable from enode
|
||||
var = enode_to_bool(new_enode, new_bit);
|
||||
|
||||
if (var == null_bool_var)
|
||||
// selected variable is already assigned
|
||||
// check if the new variable is unassigned
|
||||
if (ctx.get_assignment(var) != l_undef)
|
||||
throw default_exception("expression in \"decide\" is already assigned");
|
||||
|
||||
// in case the callback did not decide on a truth value -> let Z3 decide
|
||||
is_pos = ctx.guess(var, phase);
|
||||
}
|
||||
|
||||
bool theory_user_propagator::get_case_split(bool_var& var, bool& is_pos){
|
||||
if (!m_next_split_expr)
|
||||
bool theory_user_propagator::get_case_split(bool_var& var, bool& is_pos) {
|
||||
if (m_next_split_var == null_bool_var)
|
||||
return false;
|
||||
enode* n = ctx.get_enode(m_next_split_expr);
|
||||
|
||||
var = enode_to_bool(n, m_next_split_idx);
|
||||
|
||||
if (var == null_bool_var)
|
||||
return false;
|
||||
|
||||
|
||||
var = m_next_split_var;
|
||||
is_pos = ctx.guess(var, m_next_split_phase);
|
||||
m_next_split_expr = nullptr;
|
||||
m_next_split_var = null_bool_var;
|
||||
m_next_split_phase = l_undef;
|
||||
return true;
|
||||
}
|
||||
|
||||
void theory_user_propagator::push_scope_eh() {
|
||||
void theory_user_propagator::push_scope_eh() {
|
||||
++m_num_scopes;
|
||||
}
|
||||
|
||||
|
@ -421,9 +407,9 @@ bool theory_user_propagator::internalize_term(app* term) {
|
|||
return true;
|
||||
}
|
||||
|
||||
void theory_user_propagator::collect_statistics(::statistics & st) const {
|
||||
void theory_user_propagator::collect_statistics(::statistics& st) const {
|
||||
st.update("user-propagations", m_stats.m_num_propagations);
|
||||
st.update("user-watched", get_num_vars());
|
||||
st.update("user-watched", get_num_vars());
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -83,9 +83,8 @@ namespace smt {
|
|||
expr_ref_vector m_to_add;
|
||||
unsigned_vector m_to_add_lim;
|
||||
unsigned m_to_add_qhead = 0;
|
||||
expr* m_next_split_expr = nullptr;
|
||||
unsigned m_next_split_idx;
|
||||
lbool m_next_split_phase;
|
||||
bool_var m_next_split_var = null_bool_var;
|
||||
lbool m_next_split_phase = l_undef;
|
||||
|
||||
expr* var2expr(theory_var v) { return m_var2expr.get(v); }
|
||||
theory_var expr2var(expr* e) { check_defined(e); return m_expr2var[e->get_id()]; }
|
||||
|
@ -133,7 +132,7 @@ namespace smt {
|
|||
|
||||
void propagate_cb(unsigned num_fixed, expr* const* fixed_ids, unsigned num_eqs, expr* const* lhs, expr* const* rhs, expr* conseq) override;
|
||||
void register_cb(expr* e) override;
|
||||
void next_split_cb(expr* e, unsigned idx, lbool phase) override;
|
||||
bool next_split_cb(expr* e, unsigned idx, lbool phase) override;
|
||||
|
||||
void new_fixed_eh(theory_var v, expr* value, unsigned num_lits, literal const* jlits);
|
||||
void decide(bool_var& var, bool& is_pos);
|
||||
|
|
|
@ -11,7 +11,7 @@ namespace user_propagator {
|
|||
virtual ~callback() = default;
|
||||
virtual void propagate_cb(unsigned num_fixed, expr* const* fixed_ids, unsigned num_eqs, expr* const* eq_lhs, expr* const* eq_rhs, expr* conseq) = 0;
|
||||
virtual void register_cb(expr* e) = 0;
|
||||
virtual void next_split_cb(expr* e, unsigned idx, lbool phase) = 0;
|
||||
virtual bool next_split_cb(expr* e, unsigned idx, lbool phase) = 0;
|
||||
};
|
||||
|
||||
class context_obj {
|
||||
|
@ -26,7 +26,7 @@ namespace user_propagator {
|
|||
typedef std::function<void(void*, callback*)> push_eh_t;
|
||||
typedef std::function<void(void*, callback*, unsigned)> pop_eh_t;
|
||||
typedef std::function<void(void*, callback*, expr*)> created_eh_t;
|
||||
typedef std::function<void(void*, callback*, expr**, unsigned*, lbool*)> decide_eh_t;
|
||||
typedef std::function<void(void*, callback*, expr*, unsigned, bool)> decide_eh_t;
|
||||
typedef std::function<void(void*, expr*, unsigned, expr* const*)> on_clause_eh_t;
|
||||
|
||||
class plugin : public decl_plugin {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue