mirror of
https://github.com/Z3Prover/z3
synced 2025-04-23 09:05:31 +00:00
added API to monitor clause inferences
See RELEASE_NOTES for more information examples pending.
This commit is contained in:
parent
77cbd89420
commit
07dd1065db
34 changed files with 505 additions and 122 deletions
|
@ -907,6 +907,33 @@ extern "C" {
|
|||
~api_context_obj() override { dealloc(c); }
|
||||
};
|
||||
|
||||
struct scoped_ast_vector {
|
||||
Z3_ast_vector_ref* v;
|
||||
scoped_ast_vector(Z3_ast_vector_ref* v): v(v) { v->inc_ref(); }
|
||||
~scoped_ast_vector() { v->dec_ref(); }
|
||||
};
|
||||
|
||||
void Z3_API Z3_solver_register_on_clause(
|
||||
Z3_context c,
|
||||
Z3_solver s,
|
||||
void* user_context,
|
||||
Z3_on_clause_eh on_clause_eh) {
|
||||
Z3_TRY;
|
||||
RESET_ERROR_CODE();
|
||||
init_solver(c, s);
|
||||
user_propagator::on_clause_eh_t _on_clause = [=](void* user_ctx, expr* proof, unsigned n, expr* const* _literals) {
|
||||
Z3_ast_vector_ref * literals = alloc(Z3_ast_vector_ref, *mk_c(c), mk_c(c)->m());
|
||||
mk_c(c)->save_object(literals);
|
||||
expr_ref pr(proof, mk_c(c)->m());
|
||||
scoped_ast_vector _sc(literals);
|
||||
for (unsigned i = 0; i < n; ++i)
|
||||
literals->m_ast_vector.push_back(_literals[i]);
|
||||
on_clause_eh(user_ctx, of_expr(pr.get()), of_ast_vector(literals));
|
||||
};
|
||||
to_solver_ref(s)->register_on_clause(user_context, _on_clause);
|
||||
Z3_CATCH;
|
||||
}
|
||||
|
||||
void Z3_API Z3_solver_propagate_init(
|
||||
Z3_context c,
|
||||
Z3_solver s,
|
||||
|
|
|
@ -158,7 +158,7 @@ namespace z3 {
|
|||
class context {
|
||||
private:
|
||||
friend class user_propagator_base;
|
||||
bool m_enable_exceptions;
|
||||
bool m_enable_exceptions = true;
|
||||
rounding_mode m_rounding_mode;
|
||||
Z3_context m_ctx = nullptr;
|
||||
void init(config & c) {
|
||||
|
@ -2670,10 +2670,10 @@ namespace z3 {
|
|||
public:
|
||||
struct simple {};
|
||||
struct translate {};
|
||||
solver(context & c):object(c) { init(Z3_mk_solver(c)); }
|
||||
solver(context & c, simple):object(c) { init(Z3_mk_simple_solver(c)); }
|
||||
solver(context & c):object(c) { init(Z3_mk_solver(c)); check_error(); }
|
||||
solver(context & c, simple):object(c) { init(Z3_mk_simple_solver(c)); check_error(); }
|
||||
solver(context & c, Z3_solver s):object(c) { init(s); }
|
||||
solver(context & c, char const * logic):object(c) { init(Z3_mk_solver_for_logic(c, c.str_symbol(logic))); }
|
||||
solver(context & c, char const * logic):object(c) { init(Z3_mk_solver_for_logic(c, c.str_symbol(logic))); check_error(); }
|
||||
solver(context & c, solver const& src, translate): object(c) { Z3_solver s = Z3_solver_translate(src.ctx(), src, c); check_error(); init(s); }
|
||||
solver(solver const & s):object(s) { init(s.m_solver); }
|
||||
~solver() { Z3_solver_dec_ref(ctx(), m_solver); }
|
||||
|
@ -4059,6 +4059,25 @@ namespace z3 {
|
|||
return expr(ctx(), r);
|
||||
}
|
||||
|
||||
typedef std::function<void(expr const& proof, expr_vector const& clause)> on_clause_eh_t;
|
||||
|
||||
class on_clause {
|
||||
context& c;
|
||||
on_clause_eh_t m_on_clause;
|
||||
|
||||
static void _on_clause_eh(void* _ctx, Z3_ast _proof, Z3_ast_vector _literals) {
|
||||
on_clause* ctx = static_cast<on_clause*>(_ctx);
|
||||
expr_vector lits(ctx->c, _literals);
|
||||
expr proof(ctx->c, _proof);
|
||||
ctx->m_on_clause(proof, lits);
|
||||
}
|
||||
public:
|
||||
on_clause(solver& s, on_clause_eh_t& on_clause_eh): c(s.ctx()) {
|
||||
m_on_clause = on_clause_eh;
|
||||
Z3_solver_register_on_clause(c, s, this, _on_clause_eh);
|
||||
c.check_error();
|
||||
}
|
||||
};
|
||||
|
||||
class user_propagator_base {
|
||||
|
||||
|
|
|
@ -87,6 +87,7 @@ set(Z3_DOTNET_ASSEMBLY_SOURCES_IN_SRC_TREE
|
|||
NativeFuncInterp.cs
|
||||
NativeModel.cs
|
||||
NativeSolver.cs
|
||||
OnClause.cs
|
||||
Optimize.cs
|
||||
ParamDescrs.cs
|
||||
Params.cs
|
||||
|
|
102
src/api/dotnet/OnClause.cs
Normal file
102
src/api/dotnet/OnClause.cs
Normal file
|
@ -0,0 +1,102 @@
|
|||
/*++
|
||||
Copyright (c) 2012 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
OnClause.cs
|
||||
|
||||
Abstract:
|
||||
|
||||
Callback on clause inferences
|
||||
|
||||
Author:
|
||||
|
||||
Nikolaj Bjorner (nbjorner) 2022-10-19
|
||||
|
||||
Notes:
|
||||
|
||||
|
||||
--*/
|
||||
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Microsoft.Z3
|
||||
{
|
||||
|
||||
using Z3_context = System.IntPtr;
|
||||
using Z3_solver = System.IntPtr;
|
||||
using voidp = System.IntPtr;
|
||||
using Z3_ast = System.IntPtr;
|
||||
using Z3_ast_vector = System.IntPtr;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// OnClause - clause inference callback
|
||||
/// </summary>
|
||||
public class OnClause : IDisposable
|
||||
{
|
||||
/// <summary>
|
||||
/// Delegate type for when clauses are inferred.
|
||||
/// An inference is a pair comprising of
|
||||
/// - a proof (hint). A partial (or comprehensive) derivation justifying the inference.
|
||||
/// - a clause (vector of literals)
|
||||
/// The life-time of the proof hint and clause vector is limited to the scope of the callback.
|
||||
/// should the callback want to store hints or clauses it will need to call Dup on the hints
|
||||
/// and/or extract literals from the clause, respectively.
|
||||
/// </summary>
|
||||
public delegate void OnClauseEh(Expr proof_hint, ASTVector clause);
|
||||
|
||||
|
||||
// access managed objects through a static array.
|
||||
// thread safety is ignored for now.
|
||||
GCHandle gch;
|
||||
Solver solver;
|
||||
Context ctx;
|
||||
OnClauseEh on_clause;
|
||||
|
||||
Native.Z3_on_clause_eh on_clause_eh;
|
||||
|
||||
static void _on_clause(voidp ctx, Z3_ast _proof_hint, Z3_ast_vector _clause)
|
||||
{
|
||||
var onc = (OnClause)GCHandle.FromIntPtr(ctx).Target;
|
||||
using var proof_hint = Expr.Create(onc.ctx, _proof_hint);
|
||||
using var clause = new ASTVector(onc.ctx, _clause);
|
||||
onc.on_clause(proof_hint, clause);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// OnClause constructor
|
||||
/// </summary>
|
||||
public OnClause(Solver s, OnClauseEh onc)
|
||||
{
|
||||
gch = GCHandle.Alloc(this);
|
||||
solver = s;
|
||||
ctx = solver.Context;
|
||||
on_clause = onc;
|
||||
on_clause_eh = _on_clause;
|
||||
Native.Z3_solver_register_on_clause(ctx.nCtx, solver.NativeObject, GCHandle.ToIntPtr(gch), on_clause_eh);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Release private memory.
|
||||
/// </summary>
|
||||
~OnClause()
|
||||
{
|
||||
Dispose();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Must be called. The object will not be garbage collected automatically even if the context is disposed
|
||||
/// </summary>
|
||||
public virtual void Dispose()
|
||||
{
|
||||
if (!gch.IsAllocated)
|
||||
return;
|
||||
gch.Free();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -11301,6 +11301,45 @@ def TransitiveClosure(f):
|
|||
"""
|
||||
return FuncDeclRef(Z3_mk_transitive_closure(f.ctx_ref(), f.ast), f.ctx)
|
||||
|
||||
def to_Ast(ptr,):
|
||||
ast = Ast(ptr)
|
||||
super(ctypes.c_void_p, ast).__init__(ptr)
|
||||
return ast
|
||||
|
||||
def to_ContextObj(ptr,):
|
||||
ctx = ContextObj(ptr)
|
||||
super(ctypes.c_void_p, ctx).__init__(ptr)
|
||||
return ctx
|
||||
|
||||
def to_AstVectorObj(ptr,):
|
||||
v = AstVectorObj(ptr)
|
||||
super(ctypes.c_void_p, v).__init__(ptr)
|
||||
return v
|
||||
|
||||
# NB. my-hacky-class only works for a single instance of OnClause
|
||||
# it should be replaced with a proper correlation between OnClause
|
||||
# and object references that can be passed over the FFI.
|
||||
# for UserPropagator we use a global dictionary, which isn't great code.
|
||||
|
||||
_my_hacky_class = None
|
||||
def on_clause_eh(ctx, p, clause):
|
||||
onc = _my_hacky_class
|
||||
p = _to_expr_ref(to_Ast(p), onc.ctx)
|
||||
clause = AstVector(to_AstVectorObj(clause), onc.ctx)
|
||||
onc.on_clause(p, clause)
|
||||
|
||||
_on_clause_eh = Z3_on_clause_eh(on_clause_eh)
|
||||
|
||||
class OnClause:
|
||||
def __init__(self, s, on_clause):
|
||||
self.s = s
|
||||
self.ctx = s.ctx
|
||||
self.on_clause = on_clause
|
||||
self.idx = 22
|
||||
global _my_hacky_class
|
||||
_my_hacky_class = self
|
||||
Z3_solver_register_on_clause(self.ctx.ref(), self.s.solver, self.idx, _on_clause_eh)
|
||||
|
||||
|
||||
class PropClosures:
|
||||
def __init__(self):
|
||||
|
@ -11358,11 +11397,6 @@ def user_prop_pop(ctx, cb, num_scopes):
|
|||
prop.cb = cb
|
||||
prop.pop(num_scopes)
|
||||
|
||||
def to_ContextObj(ptr,):
|
||||
ctx = ContextObj(ptr)
|
||||
super(ctypes.c_void_p, ctx).__init__(ptr)
|
||||
return ctx
|
||||
|
||||
|
||||
def user_prop_fresh(ctx, _new_ctx):
|
||||
_prop_closures.set_threaded()
|
||||
|
@ -11377,10 +11411,6 @@ def user_prop_fresh(ctx, _new_ctx):
|
|||
_prop_closures.set(new_prop.id, new_prop)
|
||||
return new_prop.id
|
||||
|
||||
def to_Ast(ptr,):
|
||||
ast = Ast(ptr)
|
||||
super(ctypes.c_void_p, ast).__init__(ptr)
|
||||
return ast
|
||||
|
||||
def user_prop_fixed(ctx, cb, id, value):
|
||||
prop = _prop_closures.get(ctx)
|
||||
|
@ -11442,6 +11472,7 @@ _user_prop_eq = Z3_eq_eh(user_prop_eq)
|
|||
_user_prop_diseq = Z3_eq_eh(user_prop_diseq)
|
||||
_user_prop_decide = Z3_decide_eh(user_prop_decide)
|
||||
|
||||
|
||||
def PropagateFunction(name, *sig):
|
||||
"""Create a function that gets tracked by user propagator.
|
||||
Every term headed by this function symbol is tracked.
|
||||
|
@ -11462,7 +11493,8 @@ def PropagateFunction(name, *sig):
|
|||
dom[i] = sig[i].ast
|
||||
ctx = rng.ctx
|
||||
return FuncDeclRef(Z3_solver_propagate_declare(ctx.ref(), to_symbol(name, ctx), arity, dom, rng.ast), ctx)
|
||||
|
||||
|
||||
|
||||
|
||||
class UserPropagateBase:
|
||||
|
||||
|
|
|
@ -1433,6 +1433,7 @@ Z3_DECLARE_CLOSURE(Z3_eq_eh, void, (void* ctx, Z3_solver_callback cb, Z3_as
|
|||
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_on_clause_eh, void, (void* ctx, Z3_ast proof_hint, Z3_ast_vector literals));
|
||||
|
||||
|
||||
/**
|
||||
|
@ -6877,6 +6878,24 @@ extern "C" {
|
|||
*/
|
||||
void Z3_API Z3_solver_get_levels(Z3_context c, Z3_solver s, Z3_ast_vector literals, unsigned sz, unsigned levels[]);
|
||||
|
||||
/**
|
||||
\brief register a callback to that retrieves assumed, inferred and deleted clauses during search.
|
||||
|
||||
\param c - context.
|
||||
\param s - solver object.
|
||||
\param user_context - a context used to maintain state for callbacks.
|
||||
\param on_clause_eh - a callback that is invoked by when a clause is
|
||||
- asserted to the CDCL engine (corresponding to an input clause after pre-processing)
|
||||
- inferred by CDCL(T) using either a SAT or theory conflict/propagation
|
||||
- deleted by the CDCL(T) engine
|
||||
|
||||
def_API('Z3_solver_register_on_clause', VOID, (_in(CONTEXT), _in(SOLVER), _in(VOID_PTR), _fnptr(Z3_on_clause_eh)))
|
||||
*/
|
||||
void Z3_API Z3_solver_register_on_clause(
|
||||
Z3_context c,
|
||||
Z3_solver s,
|
||||
void* user_context,
|
||||
Z3_on_clause_eh on_clause_eh);
|
||||
|
||||
/**
|
||||
\brief register a user-properator with the solver.
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue