mirror of
https://github.com/Z3Prover/z3
synced 2025-04-24 01:25:31 +00:00
exposing user propagators over .Net
Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
parent
3ae781039b
commit
14214c5a07
7 changed files with 296 additions and 18 deletions
|
@ -113,6 +113,7 @@ set(Z3_DOTNET_ASSEMBLY_SOURCES_IN_SRC_TREE
|
|||
Tactic.cs
|
||||
TupleSort.cs
|
||||
UninterpretedSort.cs
|
||||
UserPropagator.cs
|
||||
Version.cs
|
||||
Z3Exception.cs
|
||||
Z3Object.cs
|
||||
|
|
222
src/api/dotnet/UserPropagator.cs
Normal file
222
src/api/dotnet/UserPropagator.cs
Normal file
|
@ -0,0 +1,222 @@
|
|||
/*++
|
||||
Copyright (c) 2012 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
UserPropagator.cs
|
||||
|
||||
Abstract:
|
||||
|
||||
User Propagator plugin
|
||||
|
||||
Author:
|
||||
|
||||
Nikolaj Bjorner (nbjorner) 2022-05-07
|
||||
|
||||
Notes:
|
||||
|
||||
// Todo: fresh, created, declare user function, register_cb, decide,
|
||||
|
||||
--*/
|
||||
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Microsoft.Z3
|
||||
{
|
||||
|
||||
using Z3_solver_callback = System.IntPtr;
|
||||
using Z3_context = System.IntPtr;
|
||||
using Z3_solver = System.IntPtr;
|
||||
using voidp = System.IntPtr;
|
||||
using Z3_ast = System.IntPtr;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Propagator context for .Net
|
||||
/// </summary>
|
||||
public class UserPropagator
|
||||
{
|
||||
/// <summary>
|
||||
/// Delegate type for fixed callback
|
||||
/// </summary>
|
||||
public delegate void FixedEh(Expr term, Expr value);
|
||||
|
||||
/// <summary>
|
||||
/// Delegate type for equality or disequality callback
|
||||
/// </summary>
|
||||
public delegate void EqEh(Expr term, Expr value);
|
||||
|
||||
|
||||
Solver solver;
|
||||
GCHandle gch;
|
||||
Z3_solver_callback callback;
|
||||
FixedEh fixed_eh;
|
||||
Action final_eh;
|
||||
EqEh eq_eh;
|
||||
EqEh diseq_eh;
|
||||
|
||||
|
||||
unsafe static void _push(voidp ctx, Z3_solver_callback cb) {
|
||||
var gch = GCHandle.FromIntPtr(ctx);
|
||||
var prop = (UserPropagator)gch.Target;
|
||||
prop.callback = cb;
|
||||
prop.Push();
|
||||
}
|
||||
|
||||
unsafe static void _pop(voidp ctx, Z3_solver_callback cb, uint num_scopes) {
|
||||
var gch = GCHandle.FromIntPtr(ctx);
|
||||
var prop = (UserPropagator)gch.Target;
|
||||
prop.callback = cb;
|
||||
prop.Pop(num_scopes);
|
||||
}
|
||||
|
||||
unsafe static voidp _fresh(voidp ctx, Z3_context new_context) {
|
||||
var gch = GCHandle.FromIntPtr(ctx);
|
||||
var prop = (UserPropagator)gch.Target;
|
||||
throw new Z3Exception("fresh is NYI");
|
||||
}
|
||||
|
||||
unsafe static void _fixed(voidp ctx, Z3_solver_callback cb, Z3_ast _term, Z3_ast _value) {
|
||||
var gch = GCHandle.FromIntPtr(ctx);
|
||||
var prop = (UserPropagator)gch.Target;
|
||||
var term = Expr.Create(prop.solver.Context, _term);
|
||||
var value = Expr.Create(prop.solver.Context, _value);
|
||||
prop.callback = cb;
|
||||
prop.fixed_eh(term, value);
|
||||
}
|
||||
|
||||
unsafe static void _final(voidp ctx, Z3_solver_callback cb) {
|
||||
var gch = GCHandle.FromIntPtr(ctx);
|
||||
var prop = (UserPropagator)gch.Target;
|
||||
prop.callback = cb;
|
||||
prop.final_eh();
|
||||
}
|
||||
|
||||
unsafe static void _eq(voidp ctx, Z3_solver_callback cb, Z3_ast a, Z3_ast b) {
|
||||
var gch = GCHandle.FromIntPtr(ctx);
|
||||
var prop = (UserPropagator)gch.Target;
|
||||
var s = Expr.Create(prop.solver.Context, a);
|
||||
var t = Expr.Create(prop.solver.Context, b);
|
||||
prop.callback = cb;
|
||||
prop.eq_eh(s, t);
|
||||
}
|
||||
|
||||
unsafe static void _diseq(voidp ctx, Z3_solver_callback cb, Z3_ast a, Z3_ast b) {
|
||||
var gch = GCHandle.FromIntPtr(ctx);
|
||||
var prop = (UserPropagator)gch.Target;
|
||||
var s = Expr.Create(prop.solver.Context, a);
|
||||
var t = Expr.Create(prop.solver.Context, b);
|
||||
prop.callback = cb;
|
||||
prop.diseq_eh(s, t);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Propagator constructor from a solver class.
|
||||
/// </summary>
|
||||
public UserPropagator(Solver s)
|
||||
{
|
||||
gch = GCHandle.Alloc(this);
|
||||
solver = s;
|
||||
var cb = GCHandle.ToIntPtr(gch);
|
||||
Native.Z3_solver_propagate_init(solver.Context.nCtx, solver.NativeObject, cb, _push, _pop, _fresh);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Release provate memory.
|
||||
/// </summary>
|
||||
~UserPropagator()
|
||||
{
|
||||
gch.Free();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Virtual method for push. It must be overwritten by inherited class.
|
||||
/// </summary>
|
||||
public virtual void Push() { throw new Z3Exception("Push method should be overwritten"); }
|
||||
|
||||
/// <summary>
|
||||
/// Virtual method for pop. It must be overwritten by inherited class.
|
||||
/// </summary>
|
||||
public virtual void Pop(uint n) { throw new Z3Exception("Pop method should be overwritten"); }
|
||||
|
||||
/// <summary>
|
||||
/// Virtual method for fresh. It must be overwritten by inherited class.
|
||||
/// </summary>
|
||||
public virtual UserPropagator Fresh(Context ctx) { throw new Z3Exception("Fresh method should be overwritten"); }
|
||||
|
||||
/// <summary>
|
||||
/// Declare combination of assigned expressions a conflict
|
||||
/// </summary>
|
||||
void Conflict(params Expr[] terms) {
|
||||
Propagate(terms, solver.Context.MkFalse());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Propagate consequence
|
||||
/// </summary>
|
||||
void Propagate(Expr[] terms, Expr conseq) {
|
||||
var nTerms = Z3Object.ArrayToNative(terms);
|
||||
Native.Z3_solver_propagate_consequence(solver.Context.nCtx, this.callback, (uint)nTerms.Length, nTerms, 0u, null, null, conseq.NativeObject);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Set fixed callback
|
||||
/// </summary>
|
||||
public FixedEh Fixed
|
||||
{
|
||||
set
|
||||
{
|
||||
this.fixed_eh = value;
|
||||
Native.Z3_solver_propagate_fixed(solver.Context.nCtx, solver.NativeObject, _fixed);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set final callback
|
||||
/// </summary>
|
||||
public Action Final
|
||||
{
|
||||
set
|
||||
{
|
||||
this.final_eh = value;
|
||||
Native.Z3_solver_propagate_final(solver.Context.nCtx, solver.NativeObject, _final);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set equality event callback
|
||||
/// </summary>
|
||||
public EqEh Eq
|
||||
{
|
||||
set
|
||||
{
|
||||
this.eq_eh = value;
|
||||
Native.Z3_solver_propagate_eq(solver.Context.nCtx, solver.NativeObject, _eq);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set disequality event callback
|
||||
/// </summary>
|
||||
public EqEh Diseq
|
||||
{
|
||||
set
|
||||
{
|
||||
this.diseq_eh = value;
|
||||
Native.Z3_solver_propagate_diseq(solver.Context.nCtx, solver.NativeObject, _diseq);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Track assignments to a term
|
||||
/// </summary>
|
||||
public void Register(Expr term) {
|
||||
Native.Z3_solver_propagate_register(solver.Context.nCtx, solver.NativeObject, term.NativeObject);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1444,7 +1444,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*, unsigned*, Z3_lbool*));
|
||||
Z3_DECLARE_CLOSURE(Z3_decide_eh, void, (void* ctx, Z3_solver_callback cb, Z3_ast* t, unsigned* idx, Z3_lbool* phase));
|
||||
|
||||
|
||||
/**
|
||||
|
@ -6733,6 +6733,8 @@ extern "C" {
|
|||
\param push_eh - a callback invoked when scopes are pushed
|
||||
\param pop_eh - a callback invoked when scopes are poped
|
||||
\param fresh_eh - a solver may spawn new solvers internally. This callback is used to produce a fresh user_context to be associated with fresh solvers.
|
||||
|
||||
def_API('Z3_solver_propagate_init', VOID, (_in(CONTEXT), _in(SOLVER), _in(VOID_PTR), _fnptr(Z3_push_eh), _fnptr(Z3_pop_eh), _fnptr(Z3_fresh_eh)))
|
||||
*/
|
||||
|
||||
void Z3_API Z3_solver_propagate_init(
|
||||
|
@ -6748,6 +6750,8 @@ extern "C" {
|
|||
The supported expression types are
|
||||
- Booleans
|
||||
- Bit-vectors
|
||||
|
||||
def_API('Z3_solver_propagate_fixed', VOID, (_in(CONTEXT), _in(SOLVER), _fnptr(Z3_fixed_eh)))
|
||||
*/
|
||||
|
||||
void Z3_API Z3_solver_propagate_fixed(Z3_context c, Z3_solver s, Z3_fixed_eh fixed_eh);
|
||||
|
@ -6764,22 +6768,30 @@ extern "C" {
|
|||
The callback context can only be accessed (for propagation and for dynamically registering expressions) within a callback.
|
||||
If the callback context gets used for propagation or conflicts, those propagations take effect and
|
||||
may trigger new decision variables to be set.
|
||||
|
||||
def_API('Z3_solver_propagate_final', VOID, (_in(CONTEXT), _in(SOLVER), _fnptr(Z3_final_eh)))
|
||||
*/
|
||||
void Z3_API Z3_solver_propagate_final(Z3_context c, Z3_solver s, Z3_final_eh final_eh);
|
||||
|
||||
/**
|
||||
\brief register a callback on expression equalities.
|
||||
|
||||
def_API('Z3_solver_propagate_eq', VOID, (_in(CONTEXT), _in(SOLVER), _fnptr(Z3_eq_eh)))
|
||||
*/
|
||||
void Z3_API Z3_solver_propagate_eq(Z3_context c, Z3_solver s, Z3_eq_eh eq_eh);
|
||||
|
||||
/**
|
||||
\brief register a callback on expression dis-equalities.
|
||||
|
||||
def_API('Z3_solver_propagate_diseq', VOID, (_in(CONTEXT), _in(SOLVER), _fnptr(Z3_eq_eh)))
|
||||
*/
|
||||
void Z3_API Z3_solver_propagate_diseq(Z3_context c, Z3_solver s, Z3_eq_eh eq_eh);
|
||||
|
||||
/**
|
||||
\brief register a callback when a new expression with a registered function is used by the solver
|
||||
The registered function appears at the top level and is created using \ref Z3_propagate_solver_declare.
|
||||
|
||||
def_API('Z3_solver_propagate_created', VOID, (_in(CONTEXT), _in(SOLVER), _fnptr(Z3_created_eh)))
|
||||
*/
|
||||
void Z3_API Z3_solver_propagate_created(Z3_context c, Z3_solver s, Z3_created_eh created_eh);
|
||||
|
||||
|
@ -6788,6 +6800,7 @@ extern "C" {
|
|||
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.
|
||||
|
||||
*/
|
||||
void Z3_API Z3_solver_propagate_decide(Z3_context c, Z3_solver s, Z3_decide_eh decide_eh);
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue