3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-06-23 06:13:40 +00:00
z3/src/api/dotnet/NativeContext.cs
Nikolaj Bjorner 7f1893d781 add missing MkSub to NativeContext
Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
2022-07-18 10:21:27 -07:00

1416 lines
No EOL
48 KiB
C#

/*++
Copyright (c) 2012 Microsoft Corporation
Module Name:
NativeContext.cs
Abstract:
Z3 Managed API: Native Context
Author:
Christoph Wintersteiger (cwinter) 2012-03-22
John Fleisher, Nikolaj Bjorner (nbjorner) 2022-03-01
--*/
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Runtime.InteropServices;
namespace Microsoft.Z3
{
using Z3_app = System.IntPtr;
using Z3_ast = System.IntPtr;
using Z3_ast_vector = System.IntPtr;
using Z3_func_decl = System.IntPtr;
using Z3_pattern = System.IntPtr;
using Z3_solver = System.IntPtr;
using Z3_sort = System.IntPtr;
using Z3_stats = System.IntPtr;
using Z3_symbol = System.IntPtr;
/// <summary>
/// The main interaction with Z3 happens via the Context.
/// NativeContext allows for efficient wrapper-reduced interaction with Z3
/// expressions.
/// </summary>
public class NativeContext : IDisposable
{
/// <summary>
/// Constructor.
/// </summary>
/// <remarks>
/// The following parameters can be set:
/// - proof (Boolean) Enable proof generation
/// - debug_ref_count (Boolean) Enable debug support for Z3_ast reference counting
/// - trace (Boolean) Tracing support for VCC
/// - trace_file_name (String) Trace out file for VCC traces
/// - timeout (unsigned) default timeout (in milliseconds) used for solvers
/// - well_sorted_check type checker
/// - auto_config use heuristics to automatically select solver and configure it
/// - model model generation for solvers, this parameter can be overwritten when creating a solver
/// - model_validate validate models produced by solvers
/// - unsat_core unsat-core generation for solvers, this parameter can be overwritten when creating a solver
/// Note that in previous versions of Z3, this constructor was also used to set global and module parameters.
/// For this purpose we should now use <see cref="Global.SetParameter"/>
/// </remarks>
public NativeContext(Dictionary<string, string> settings)
: base()
{
Debug.Assert(settings != null);
lock (creation_lock)
{
IntPtr cfg = Native.Z3_mk_config();
foreach (KeyValuePair<string, string> kv in settings)
Native.Z3_set_param_value(cfg, kv.Key, kv.Value);
m_ctx = Native.Z3_mk_context(cfg);
Native.Z3_del_config(cfg);
InitContext();
}
}
#region Arithmetic
/// <summary>
/// Create an expression representing <c>t[0] + t[1] + ...</c>.
/// </summary>
public Z3_ast MkAdd(params Z3_ast[] t)
{
Debug.Assert(t != null);
Debug.Assert(t.All(a => a != IntPtr.Zero));
return Native.Z3_mk_add(nCtx, (uint)(t?.Length ?? 0), t);
}
/// <summary>
/// Create an expression representing <c>t[0] * t[1] * ...</c>.
/// </summary>
public Z3_ast MkMul(params Z3_ast[] t)
{
Debug.Assert(t != null);
Debug.Assert(t.All(a => a != IntPtr.Zero));
var ts = t.ToArray();
return Native.Z3_mk_mul(nCtx, (uint)(ts?.Length ?? 0), ts);
}
/// <summary>
/// Create an expression representing <c>t[0] - t[1] - ...</c>.
/// </summary>
public Z3_ast MkSub(params Z3_ast[] t)
{
Debug.Assert(t != null);
Debug.Assert(t.All(a => a != IntPtr.Zero));
var ts = t.ToArray();
return Native.Z3_mk_sub(nCtx, (uint)(ts?.Length ?? 0), ts);
}
/// <summary>
/// Create an expression representing <c>t1 / t2</c>.
/// </summary>
public Z3_ast MkDiv(Z3_ast t1, Z3_ast t2)
{
Debug.Assert(t1 != IntPtr.Zero);
Debug.Assert(t2 != IntPtr.Zero);
return Native.Z3_mk_div(nCtx, t1, t2);
}
/// <summary>
/// Create an expression representing <c>t1 &lt;= t2</c>
/// </summary>
public Z3_ast MkLe(Z3_ast t1, Z3_ast t2)
{
Debug.Assert(t1 != IntPtr.Zero);
Debug.Assert(t2 != IntPtr.Zero);
return Native.Z3_mk_le(nCtx, t1, t2);
}
/// <summary>
/// Create an expression representing <c>t1 &lt; t2</c>
/// </summary>
public Z3_ast MkLt(Z3_ast t1, Z3_ast t2)
{
Debug.Assert(t1 != IntPtr.Zero);
Debug.Assert(t2 != IntPtr.Zero);
return Native.Z3_mk_lt(nCtx, t1, t2);
}
/// <summary>
/// Create an expression representing <c>t1 &gt;= t2</c>
/// </summary>
public Z3_ast MkGe(Z3_ast t1, Z3_ast t2)
{
Debug.Assert(t1 != IntPtr.Zero);
Debug.Assert(t2 != IntPtr.Zero);
return Native.Z3_mk_ge(nCtx, t1, t2);
}
/// <summary>
/// Create an expression representing <c>t1 &gt; t2</c>
/// </summary>
public Z3_ast MkGt(Z3_ast t1, Z3_ast t2)
{
Debug.Assert(t1 != IntPtr.Zero);
Debug.Assert(t2 != IntPtr.Zero);
return Native.Z3_mk_gt(nCtx, t1, t2);
}
/// <summary>
/// Unsigned less-than
/// </summary>
/// <remarks>
/// The arguments must have the same bit-vector sort.
/// </remarks>
public Z3_ast MkBvUlt(Z3_ast t1, Z3_ast t2)
{
Debug.Assert(t1 != IntPtr.Zero);
Debug.Assert(t2 != IntPtr.Zero);
return Native.Z3_mk_bvult(nCtx, t1, t2);
}
/// <summary>
/// Unsigned less-than-equal
/// </summary>
/// <remarks>
/// The arguments must have the same bit-vector sort.
/// </remarks>
public Z3_ast MkBvUle(Z3_ast t1, Z3_ast t2)
{
Debug.Assert(t1 != IntPtr.Zero);
Debug.Assert(t2 != IntPtr.Zero);
return Native.Z3_mk_bvule(nCtx, t1, t2);
}
/// <summary>
/// Creates the equality <paramref name="x"/> = <paramref name="y"/>.
/// </summary>
public Z3_ast MkEq(Z3_ast x, Z3_ast y)
{
Debug.Assert(x != IntPtr.Zero);
Debug.Assert(y != IntPtr.Zero);
return Native.Z3_mk_eq(nCtx, x, y);
}
/// <summary>
/// Mk an expression representing <c>not(a)</c>.
/// </summary>
public Z3_ast MkNot(Z3_ast a)
{
Debug.Assert(a != IntPtr.Zero);
return Native.Z3_mk_not(nCtx, a);
}
/// <summary>
/// Create an expression representing <c>t[0] and t[1] and ...</c>.
/// </summary>
public Z3_ast MkAnd(params Z3_ast[] t)
{
Debug.Assert(t != null);
Debug.Assert(t.All(a => a != IntPtr.Zero));
return Native.Z3_mk_and(nCtx, (uint)(t?.Length ?? 0), t);
}
/// <summary>
/// Create an expression representing <c>t[0] or t[1] or ...</c>.
/// </summary>
public Z3_ast MkOr(params Z3_ast[] t)
{
Debug.Assert(t != null);
Debug.Assert(t.All(a => a != IntPtr.Zero));
return Native.Z3_mk_or(nCtx, (uint)(t?.Length ?? 0), t);
}
/// <summary>
/// Create a real numeral.
/// </summary>
/// <param name="v">A string representing the Term value in decimal notation.</param>
/// <returns>A Term with value <paramref name="v"/> and sort Real</returns>
public Z3_ast MkReal(string v)
{
Debug.Assert(!string.IsNullOrEmpty(v));
return Native.Z3_mk_numeral(nCtx, v, RealSort);
}
/// <summary>
/// Create a Term of a given sort. This function can be used to create numerals that fit in a machine integer.
/// </summary>
/// <param name="v">Value of the numeral</param>
/// <param name="sort">Sort of the numeral</param>
public Z3_ast MkNumeral(int v, Z3_sort sort)
{
Debug.Assert(sort != IntPtr.Zero);
return Native.Z3_mk_int(nCtx, v, sort);
}
/// <summary>
/// Create a Term of a given sort. This function can be used to create numerals that fit in a machine integer.
/// </summary>
/// <param name="v">Value of the numeral</param>
/// <param name="sort">Sort of the numeral</param>
public Z3_ast MkNumeral(uint v, Z3_sort sort)
{
Debug.Assert(sort != null);
return Native.Z3_mk_unsigned_int(nCtx, v, sort);
}
/// <summary>
/// Create a Term of a given sort. This function can be used to create numerals that fit in a machine integer.
/// </summary>
/// <param name="v">Value of the numeral</param>
/// <param name="sort">Sort of the numeral</param>
public Z3_ast MkNumeral(long v, Z3_sort sort)
{
Debug.Assert(sort != null);
return Native.Z3_mk_int64(nCtx, v, sort);
}
/// <summary>
/// Create an expression representing an if-then-else: <c>ite(t1, t2, t3)</c>.
/// </summary>
/// <param name="t1">An expression with Boolean sort</param>
/// <param name="t2">An expression </param>
/// <param name="t3">An expression with the same sort as <paramref name="t2"/></param>
public Z3_ast MkIte(Z3_ast t1, Z3_ast t2, Z3_ast t3)
{
Debug.Assert(t1 != IntPtr.Zero);
Debug.Assert(t2 != IntPtr.Zero);
Debug.Assert(t3 != IntPtr.Zero);
return Native.Z3_mk_ite(nCtx, t1, t2, t3);
}
/// <summary>
/// Create an expression representing <c>t1 -> t2</c>.
/// </summary>
public Z3_ast MkImplies(Z3_ast t1, Z3_ast t2)
{
Debug.Assert(t1 != IntPtr.Zero);
Debug.Assert(t2 != IntPtr.Zero);
return Native.Z3_mk_implies(nCtx, t1, t2);
}
#endregion
#region Sort
/// <summary>
/// Integer Sort
/// </summary>
public Z3_sort IntSort => Native.Z3_mk_int_sort(nCtx);
/// <summary>
/// Returns the "singleton" BoolSort for this NativeContext
/// </summary>
public Z3_sort BoolSort => Native.Z3_mk_bool_sort(nCtx);
/// <summary>
/// Returns the "singleton" RealSort for this NativeContext
/// </summary>
public Z3_sort RealSort => Native.Z3_mk_real_sort(nCtx);
/// <summary>
/// Returns the BvSort for size in this NativeContext
/// </summary>
public Z3_sort MkBvSort(uint size) => Native.Z3_mk_bv_sort(nCtx, size);
/// <summary>
/// returns ListSort
/// </summary>
/// <param name="name"></param>
/// <param name="elemSort"></param>
/// <param name="inil"></param>
/// <param name="iisnil"></param>
/// <param name="icons"></param>
/// <param name="iiscons"></param>
/// <param name="ihead"></param>
/// <param name="itail"></param>
/// <returns>The list algebraic datatype</returns>
public Z3_sort MkListSort(string name, Z3_sort elemSort,
out Z3_func_decl inil, out Z3_func_decl iisnil,
out Z3_func_decl icons, out Z3_func_decl iiscons,
out Z3_func_decl ihead, out Z3_func_decl itail)
{
Debug.Assert(!string.IsNullOrEmpty(name));
Debug.Assert(elemSort != IntPtr.Zero);
IntPtr nil = IntPtr.Zero, isnil = IntPtr.Zero,
cons = IntPtr.Zero, iscons = IntPtr.Zero,
head = IntPtr.Zero, tail = IntPtr.Zero;
var symbol = Native.Z3_mk_string_symbol(nCtx, name);
var sort = Native.Z3_mk_list_sort(nCtx, symbol, elemSort,
ref nil, ref isnil, ref cons, ref iscons, ref head, ref tail);
inil = nil;
iisnil = isnil;
icons = cons;
iiscons = iscons;
ihead = head;
itail = tail;
return sort;
}
/// <summary>
/// Create a new array sort.
/// </summary>
public Z3_sort MkArraySort(Z3_sort domain, Z3_sort range)
{
Debug.Assert(domain != IntPtr.Zero);
Debug.Assert(range != IntPtr.Zero);
return Native.Z3_mk_array_sort(nCtx, domain, range);
}
/// <summary>
/// Create a new tuple sort.
/// </summary>
public Z3_sort MkTupleSort(Z3_symbol name, Z3_symbol[] fieldNames, Z3_sort[] fieldSorts, out Z3_func_decl constructor, Z3_func_decl[] projections)
{
Debug.Assert(name != IntPtr.Zero);
Debug.Assert(fieldNames != null);
Debug.Assert(fieldNames.All(fn => fn != IntPtr.Zero));
Debug.Assert(fieldSorts == null || fieldSorts.All(fs => fs != IntPtr.Zero));
var numFields = (uint)(fieldNames?.Length ?? 0);
constructor = IntPtr.Zero;
return Native.Z3_mk_tuple_sort(nCtx, name, numFields, fieldNames, fieldSorts, ref constructor, projections);
}
#endregion
#region Propositional
/// <summary>
/// The true Term.
/// </summary>
public Z3_ast MkTrue() => Native.Z3_mk_true(nCtx);
/// <summary>
/// The false Term.
/// </summary>
public Z3_ast MkFalse() => Native.Z3_mk_false(nCtx);
/// <summary>
/// Creates a Boolean value.
/// </summary>
public Z3_ast MkBool(bool value) => value ? MkTrue() : MkFalse();
/// <summary>
/// Create an expression representing <c>t1 iff t2</c>.
/// </summary>
public Z3_ast MkIff(Z3_ast t1, Z3_ast t2)
{
Debug.Assert(t1 != IntPtr.Zero);
Debug.Assert(t2 != IntPtr.Zero);
return Native.Z3_mk_iff(nCtx, t1, t2);
}
#endregion
#region Constants
/// <summary>
/// Creates a new Constant of sort <paramref name="range"/> and named <paramref name="name"/>.
/// </summary>
public Z3_ast MkConst(string name, Z3_sort range)
{
Debug.Assert(!string.IsNullOrEmpty(name));
Debug.Assert(range != IntPtr.Zero);
return Native.Z3_mk_const(nCtx, MkStringSymbol(name), range);
}
#endregion
#region Symbol
/// <summary>
/// Return a ptr to symbol for string
/// </summary>
/// <param name="name"></param>
/// <returns></returns>
public Z3_symbol MkStringSymbol(string name)
{
Debug.Assert(!string.IsNullOrEmpty(name));
return Native.Z3_mk_string_symbol(nCtx, name);
}
#endregion
#region Terms
/// <summary>
/// Create a new function application.
/// </summary>
public Z3_ast MkApp(Z3_func_decl f, params Z3_ast[] args)
{
Debug.Assert(f != IntPtr.Zero);
Debug.Assert(args == null || args.All(a => a != IntPtr.Zero));
return Native.Z3_mk_app(nCtx, f, (uint)(args?.Length ?? 0), args);
}
#endregion
#region Bound Variables
/// <summary>
/// Creates a new bound variable.
/// </summary>
/// <param name="index">The de-Bruijn index of the variable</param>
/// <param name="sort">The sort of the variable</param>
public Z3_ast MkBound(uint index, Z3_sort sort)
{
Debug.Assert(sort != IntPtr.Zero);
return Native.Z3_mk_bound(nCtx, index, sort);
}
#endregion
#region Bit-vectors
/// <summary>
/// Bitwise conjunction.
/// </summary>
/// <remarks>The arguments must have a bit-vector sort.</remarks>
public Z3_ast_vector MkBvAnd(Z3_ast_vector t1, Z3_ast_vector t2)
{
Debug.Assert(t1 != IntPtr.Zero);
Debug.Assert(t2 != IntPtr.Zero);
return Native.Z3_mk_bvand(nCtx, t1, t2);
}
/// <summary>
/// Bitwise negation.
/// </summary>
/// <remarks>The argument must have a bit-vector sort.</remarks>
public Z3_ast_vector MkBvNot(Z3_ast_vector t)
{
Debug.Assert(t != IntPtr.Zero);
return Native.Z3_mk_bvnot(nCtx, t);
}
/// <summary>
/// Standard two's complement unary minus.
/// </summary>
/// <remarks>The arguments must have a bit-vector sort.</remarks>
public Z3_ast_vector MkBvNeg(Z3_ast_vector t)
{
Debug.Assert(t != IntPtr.Zero);
return Native.Z3_mk_bvneg(nCtx, t);
}
/// <summary>
/// Standard two's complement unary minus.
/// </summary>
/// <remarks>The arguments must have a bit-vector sort.</remarks>
public Z3_ast_vector MkBVNeg(Z3_ast_vector t)
{
Debug.Assert(t != IntPtr.Zero);
return Native.Z3_mk_bvneg(nCtx, t);
}
/// <summary>
/// Two's complement addition.
/// </summary>
/// <remarks>The arguments must have the same bit-vector sort.</remarks>
public Z3_ast_vector MkBvAdd(Z3_ast_vector t1, Z3_ast_vector t2)
{
Debug.Assert(t1 != IntPtr.Zero);
Debug.Assert(t2 != IntPtr.Zero);
return Native.Z3_mk_bvadd(nCtx, t1, t2);
}
/// <summary>
/// Bit-vector extraction.
/// </summary>
/// <remarks>
/// Extract the bits <paramref name="high"/> down to <paramref name="low"/> from a bitvector of
/// size <c>m</c> to yield a new bitvector of size <c>n</c>, where
/// <c>n = high - low + 1</c>.
/// The argument <paramref name="t"/> must have a bit-vector sort.
/// </remarks>
public Z3_ast_vector MkBvExtract(uint high, uint low, Z3_ast_vector t)
{
Debug.Assert(t != IntPtr.Zero);
return Native.Z3_mk_extract(nCtx, high, low, t);
}
/// <summary>
/// Bit-vector sign extension.
/// </summary>
/// <remarks>
/// Sign-extends the given bit-vector to the (signed) equivalent bitvector of
/// size <c>m+i</c>, where \c m is the size of the given bit-vector.
/// The argument <paramref name="t"/> must have a bit-vector sort.
/// </remarks>
public Z3_ast_vector MkBvSignExt(uint i, Z3_ast_vector t)
{
Debug.Assert(t != IntPtr.Zero);
return Native.Z3_mk_sign_ext(nCtx, i, t);
}
/// <summary>
/// Bit-vector zero extension.
/// </summary>
/// <remarks>
/// Extend the given bit-vector with zeros to the (unsigned) equivalent
/// bitvector of size <c>m+i</c>, where \c m is the size of the
/// given bit-vector.
/// The argument <paramref name="t"/> must have a bit-vector sort.
/// </remarks>
public Z3_ast_vector MkBvZeroExt(uint i, Z3_ast_vector t)
{
Debug.Assert(t != IntPtr.Zero);
return Native.Z3_mk_zero_ext(nCtx, i, t);
}
/// <summary>
/// Shift left.
/// </summary>
/// <remarks>
/// It is equivalent to multiplication by <c>2^x</c> where \c x is the value of <paramref name="t2"/>.
///
/// NB. The semantics of shift operations varies between environments. This
/// definition does not necessarily capture directly the semantics of the
/// programming language or assembly architecture you are modeling.
///
/// The arguments must have a bit-vector sort.
/// </remarks>
public Z3_ast_vector MkBvShl(Z3_ast_vector t1, Z3_ast_vector t2)
{
Debug.Assert(t1 != IntPtr.Zero);
Debug.Assert(t2 != IntPtr.Zero);
return Native.Z3_mk_bvshl(nCtx, t1, t2);
}
/// <summary>
/// Logical shift right
/// </summary>
/// <remarks>
/// It is equivalent to unsigned division by <c>2^x</c> where \c x is the value of <paramref name="t2"/>.
///
/// NB. The semantics of shift operations varies between environments. This
/// definition does not necessarily capture directly the semantics of the
/// programming language or assembly architecture you are modeling.
///
/// The arguments must have a bit-vector sort.
/// </remarks>
public Z3_ast_vector MkBvLshr(Z3_ast_vector t1, Z3_ast_vector t2)
{
Debug.Assert(t1 != IntPtr.Zero);
Debug.Assert(t2 != IntPtr.Zero);
return Native.Z3_mk_bvlshr(nCtx, t1, t2);
}
/// <summary>
/// Arithmetic shift right
/// </summary>
/// <remarks>
/// It is like logical shift right except that the most significant
/// bits of the result always copy the most significant bit of the
/// second argument.
///
/// NB. The semantics of shift operations varies between environments. This
/// definition does not necessarily capture directly the semantics of the
/// programming language or assembly architecture you are modeling.
///
/// The arguments must have a bit-vector sort.
/// </remarks>
public Z3_ast_vector MkBvAshr(Z3_ast_vector t1, Z3_ast_vector t2)
{
Debug.Assert(t1 != IntPtr.Zero);
Debug.Assert(t2 != IntPtr.Zero);
return Native.Z3_mk_bvashr(nCtx, t1, t2);
}
/// <summary>
/// Two's complement signed less-than
/// </summary>
/// <remarks>
/// The arguments must have the same bit-vector sort.
/// </remarks>
public Z3_ast MkBvSlt(Z3_ast_vector t1, Z3_ast_vector t2)
{
Debug.Assert(t1 != IntPtr.Zero);
Debug.Assert(t2 != IntPtr.Zero);
return Native.Z3_mk_bvslt(nCtx, t1, t2);
}
/// <summary>
/// Two's complement multiplication.
/// </summary>
/// <remarks>The arguments must have the same bit-vector sort.</remarks>
public Z3_ast_vector MkBvMul(Z3_ast_vector t1, Z3_ast_vector t2)
{
Debug.Assert(t1 != IntPtr.Zero);
Debug.Assert(t2 != IntPtr.Zero);
return Native.Z3_mk_bvmul(nCtx, t1, t2);
}
/// <summary>
/// Unsigned division.
/// </summary>
/// <remarks>
/// It is defined as the floor of <c>t1/t2</c> if \c t2 is
/// different from zero. If <c>t2</c> is zero, then the result
/// is undefined.
/// The arguments must have the same bit-vector sort.
/// </remarks>
public Z3_ast_vector MkBvUdiv(Z3_ast_vector t1, Z3_ast_vector t2)
{
Debug.Assert(t1 != IntPtr.Zero);
Debug.Assert(t2 != IntPtr.Zero);
return Native.Z3_mk_bvudiv(nCtx, t1, t2);
}
/// <summary>
/// Signed division.
/// </summary>
/// <remarks>
/// It is defined in the following way:
///
/// - The \c floor of <c>t1/t2</c> if \c t2 is different from zero, and <c>t1*t2 >= 0</c>.
///
/// - The \c ceiling of <c>t1/t2</c> if \c t2 is different from zero, and <c>t1*t2 &lt; 0</c>.
///
/// If <c>t2</c> is zero, then the result is undefined.
/// The arguments must have the same bit-vector sort.
/// </remarks>
public Z3_ast_vector MkBvSdiv(Z3_ast_vector t1, Z3_ast_vector t2)
{
Debug.Assert(t1 != IntPtr.Zero);
Debug.Assert(t2 != IntPtr.Zero);
return Native.Z3_mk_bvsdiv(nCtx, t1, t2);
}
/// <summary>
/// Unsigned remainder.
/// </summary>
/// <remarks>
/// It is defined as <c>t1 - (t1 /u t2) * t2</c>, where <c>/u</c> represents unsigned division.
/// If <c>t2</c> is zero, then the result is undefined.
/// The arguments must have the same bit-vector sort.
/// </remarks>
public Z3_ast_vector MkBvUrem(Z3_ast_vector t1, Z3_ast_vector t2)
{
Debug.Assert(t1 != IntPtr.Zero);
Debug.Assert(t2 != IntPtr.Zero);
return Native.Z3_mk_bvurem(nCtx, t1, t2);
}
/// <summary>
/// Signed remainder.
/// </summary>
/// <remarks>
/// It is defined as <c>t1 - (t1 /s t2) * t2</c>, where <c>/s</c> represents signed division.
/// The most significant bit (sign) of the result is equal to the most significant bit of \c t1.
///
/// If <c>t2</c> is zero, then the result is undefined.
/// The arguments must have the same bit-vector sort.
/// </remarks>
public Z3_ast_vector MkBvSrem(Z3_ast_vector t1, Z3_ast_vector t2)
{
Debug.Assert(t1 != IntPtr.Zero);
Debug.Assert(t2 != IntPtr.Zero);
return Native.Z3_mk_bvsrem(nCtx, t1, t2);
}
/// <summary>
/// Two's complement subtraction.
/// </summary>
/// <remarks>The arguments must have the same bit-vector sort.</remarks>
public Z3_ast_vector MkBvSub(Z3_ast_vector t1, Z3_ast_vector t2)
{
Debug.Assert(t1 != IntPtr.Zero);
Debug.Assert(t2 != IntPtr.Zero);
return Native.Z3_mk_bvsub(nCtx, t1, t2);
}
/// <summary>
/// Bitwise disjunction.
/// </summary>
/// <remarks>The arguments must have a bit-vector sort.</remarks>
public Z3_ast_vector MkBvOr(Z3_ast_vector t1, Z3_ast_vector t2)
{
Debug.Assert(t1 != IntPtr.Zero);
Debug.Assert(t2 != IntPtr.Zero);
return Native.Z3_mk_bvor(nCtx, t1, t2);
}
/// <summary>
/// Bitwise XOR.
/// </summary>
/// <remarks>The arguments must have a bit-vector sort.</remarks>
public Z3_ast_vector MkBvXor(Z3_ast_vector t1, Z3_ast_vector t2)
{
Debug.Assert(t1 != null);
Debug.Assert(t2 != IntPtr.Zero);
return Native.Z3_mk_bvxor(nCtx, t1, t2);
}
#endregion
#region Quantifiers
/// <summary>
/// Create a universal Quantifier.
/// </summary>
/// <remarks>
/// Creates a forall formula, where <paramref name="weight"/> is the weight,
/// <paramref name="patterns"/> is an array of patterns, <paramref name="sorts"/> is an array
/// with the sorts of the bound variables, <paramref name="names"/> is an array with the
/// 'names' of the bound variables, and <paramref name="body"/> is the body of the
/// quantifier. Quantifiers are associated with weights indicating the importance of
/// using the quantifier during instantiation.
/// Note that the bound variables are de-Bruijn indices created using <see cref="MkBound"/>.
/// Z3 applies the convention that the last element in <paramref name="names"/> and
/// <paramref name="sorts"/> refers to the variable with index 0, the second to last element
/// of <paramref name="names"/> and <paramref name="sorts"/> refers to the variable
/// with index 1, etc.
/// </remarks>
/// <param name="sorts">the sorts of the bound variables.</param>
/// <param name="names">names of the bound variables</param>
/// <param name="body">the body of the quantifier.</param>
/// <param name="weight">quantifiers are associated with weights indicating the importance of using the quantifier during instantiation. By default, pass the weight 0.</param>
/// <param name="patterns">array containing the patterns created using <c>MkPattern</c>.</param>
/// <param name="noPatterns">array containing the anti-patterns created using <c>MkPattern</c>.</param>
/// <param name="quantifierID">optional symbol to track quantifier.</param>
/// <param name="skolemID">optional symbol to track skolem constants.</param>
public Z3_ast MkForall(Z3_sort[] sorts, Z3_symbol[] names, Z3_ast body, uint weight = 1, Z3_ast[] patterns = null, Z3_ast[] noPatterns = null, Symbol quantifierID = null, Symbol skolemID = null)
{
return MkQuantifier(true, sorts, names, body, weight, patterns, noPatterns, quantifierID, skolemID);
}
/// <summary>
/// Same as MkForAll but defaults to "forall" = false
/// Create an existential Quantifier.
/// </summary>
/// <param name="sorts"></param>
/// <param name="names"></param>
/// <param name="body"></param>
/// <param name="weight"></param>
/// <param name="patterns"></param>
/// <param name="noPatterns"></param>
/// <param name="quantifierID"></param>
/// <param name="skolemID"></param>
/// <returns></returns>
public Z3_ast MkExists(Z3_sort[] sorts, Z3_symbol[] names, Z3_ast body, uint weight = 1, Z3_ast[] patterns = null, Z3_ast[] noPatterns = null, Symbol quantifierID = null, Symbol skolemID = null)
{
return MkQuantifier(false, sorts, names, body, weight, patterns, noPatterns, quantifierID, skolemID);
}
/// <summary>
/// Create a quantified expression either forall or exists
/// </summary>
/// <param name="is_forall"></param>
/// <param name="sorts"></param>
/// <param name="names"></param>
/// <param name="body"></param>
/// <param name="weight"></param>
/// <param name="patterns"></param>
/// <param name="noPatterns"></param>
/// <param name="quantifierID"></param>
/// <param name="skolemID"></param>
/// <returns></returns>
private Z3_ast MkQuantifier(bool is_forall, Z3_sort[] sorts, Z3_symbol[] names, Z3_ast body, uint weight, Z3_ast[] patterns, Z3_ast[] noPatterns, Symbol quantifierID, Symbol skolemID)
{
Debug.Assert(sorts != null);
Debug.Assert(names != null);
Debug.Assert(body != null);
Debug.Assert(sorts.Length == names.Length);
Debug.Assert(sorts.All(s => s != IntPtr.Zero));
Debug.Assert(names.All(n => n != IntPtr.Zero));
Debug.Assert(patterns == null || patterns.All(p => p != IntPtr.Zero));
Debug.Assert(noPatterns == null || noPatterns.All(np => np != IntPtr.Zero));
if (noPatterns == null && quantifierID == null && skolemID == null)
{
return Native.Z3_mk_quantifier(nCtx, (byte)(is_forall ? 1 : 0), weight,
(uint)(patterns?.Length ?? 0), patterns,
(uint)(sorts?.Length ?? 0), sorts,
names,
body);
}
else
{
return Native.Z3_mk_quantifier_ex(nCtx, (byte)(is_forall ? 1 : 0), weight,
AST.GetNativeObject(quantifierID), AST.GetNativeObject(skolemID),
(uint)(patterns?.Length ?? 0), patterns,
(uint)(noPatterns?.Length ?? 0), noPatterns,
(uint)(sorts?.Length ?? 0), sorts,
names,
body);
}
}
#endregion
#region Options
/// <summary>
/// Selects the format used for pretty-printing expressions.
/// </summary>
/// <remarks>
/// The default mode for pretty printing expressions is to produce
/// SMT-LIB style output where common subexpressions are printed
/// at each occurrence. The mode is called Z3_PRINT_SMTLIB_FULL.
/// To print shared common subexpressions only once,
/// use the Z3_PRINT_LOW_LEVEL mode.
/// To print in way that conforms to SMT-LIB standards and uses let
/// expressions to share common sub-expressions use Z3_PRINT_SMTLIB_COMPLIANT.
/// </remarks>
/// <seealso cref="AST.ToString()"/>
/// <seealso cref="Pattern.ToString()"/>
/// <seealso cref="FuncDecl.ToString()"/>
/// <seealso cref="Sort.ToString()"/>
public Z3_ast_print_mode PrintMode
{
set { Native.Z3_set_ast_print_mode(nCtx, (uint)value); }
}
#endregion
#region Arrays
/// <summary>
/// Create a constant array.
/// </summary>
/// <remarks>
/// The resulting term is an array, such that a <c>select</c>on an arbitrary index
/// produces the value <c>v</c>.
/// </remarks>
public Z3_ast MkConstArray(Z3_sort domain, Z3_ast v)
{
Debug.Assert(domain != IntPtr.Zero);
Debug.Assert(v != IntPtr.Zero);
return Native.Z3_mk_const_array(nCtx, domain, v);
}
/// <summary>
/// Array update.
/// </summary>
/// <remarks>
/// The node <c>a</c> must have an array sort <c>[domain -> range]</c>,
/// <c>i</c> must have sort <c>domain</c>,
/// <c>v</c> must have sort range. The sort of the result is <c>[domain -> range]</c>.
/// The semantics of this function is given by the theory of arrays described in the SMT-LIB
/// standard. See http://smtlib.org for more details.
/// The result of this function is an array that is equal to <c>a</c>
/// (with respect to <c>select</c>)
/// on all indices except for <c>i</c>, where it maps to <c>v</c>
/// (and the <c>select</c> of <c>a</c> with
/// respect to <c>i</c> may be a different value).
/// </remarks>
public Z3_ast MkStore(Z3_ast a, Z3_ast i, Z3_ast v)
{
Debug.Assert(a != IntPtr.Zero);
Debug.Assert(i != IntPtr.Zero);
Debug.Assert(v != IntPtr.Zero);
return Native.Z3_mk_store(nCtx, a, i, v);
}
/// <summary>
/// Array read.
/// </summary>
/// <remarks>
/// The argument <c>array</c> is the array and <c>index</c> is the index
/// of the array that gets read.
///
/// The node <c>array</c> must have an array sort <c>[domain -> range]</c>,
/// and <c>index</c> must have the sort <c>domain</c>.
/// The sort of the result is <c>range</c>.
/// </remarks>
public Z3_ast MkSelect(Z3_ast array, Z3_ast index)
{
Debug.Assert(array != IntPtr.Zero);
Debug.Assert(index != IntPtr.Zero);
return Native.Z3_mk_select(nCtx, array, index);
}
/// <summary>
/// Access the array default value.
/// </summary>
/// <remarks>
/// Produces the default range value, for arrays that can be represented as
/// finite maps with a default range value.
/// </remarks>
public Z3_ast MkDefault(Z3_ast a)
{
Debug.Assert(a != null);
return Native.Z3_mk_array_default(nCtx, a);
}
#endregion
#region Function Declarations
/// <summary>
/// Creates a new function declaration.
/// </summary>
public Z3_func_decl MkFuncDecl(string name, Z3_sort[] domain, Z3_sort range)
{
Debug.Assert(!string.IsNullOrEmpty(name));
Debug.Assert(range != IntPtr.Zero);
Debug.Assert(domain != null);
Debug.Assert(domain.All(d => d != IntPtr.Zero));
var symbol = Native.Z3_mk_string_symbol(nCtx, name);
return Native.Z3_mk_func_decl(nCtx, symbol, (uint)(domain?.Length ?? 0), domain, range);
}
/// <summary>
/// Creates a new function declaration.
/// </summary>
public Z3_func_decl MkFuncDecl(string name, Z3_sort domain, Z3_sort range)
{
Debug.Assert(!string.IsNullOrEmpty(name));
Debug.Assert(range != IntPtr.Zero);
Debug.Assert(domain != IntPtr.Zero);
var symbol = Native.Z3_mk_string_symbol(nCtx, name);
var q = new Z3_sort[] { domain };
return Native.Z3_mk_func_decl(nCtx, symbol, (uint)q.Length, q, range);
}
/// <summary>
/// Creates a fresh function declaration with a name prefixed with <paramref name="prefix"/>.
/// </summary>
public Z3_func_decl MkFreshFuncDecl(string prefix, Z3_sort[] domain, Z3_sort range)
{
Debug.Assert(domain != null);
Debug.Assert(range != IntPtr.Zero);
Debug.Assert(domain.All(d => d != IntPtr.Zero));
return Native.Z3_mk_fresh_func_decl(nCtx, prefix, (uint)(domain?.Length ?? 0), domain, range);
}
/// <summary>
/// Creates a new constant function declaration.
/// </summary>
public Z3_func_decl MkConstDecl(string name, Z3_sort range)
{
Debug.Assert(range != IntPtr.Zero);
var symbol = Native.Z3_mk_string_symbol(nCtx, name);
return Native.Z3_mk_func_decl(nCtx, symbol, 0, new IntPtr[0], range);
}
/// <summary>
/// Get domain for a funcdecl
/// </summary>
/// <param name="fdecl"></param>
/// <returns></returns>
public Z3_sort[] GetDomain(Z3_func_decl fdecl)
{
Debug.Assert(fdecl != IntPtr.Zero);
var sz = Native.Z3_get_domain_size(nCtx, fdecl);
var domain = new Z3_sort[sz];
for (uint i = 0; i < sz; i++)
{
domain[i] = Native.Z3_get_domain(nCtx, fdecl, i);
}
return domain;
}
/// <summary>
/// Get range for a funcdecl
/// </summary>
/// <param name="fdecl"></param>
/// <returns></returns>
public Z3_sort GetRange(Z3_func_decl fdecl)
{
Debug.Assert(fdecl != IntPtr.Zero);
return Native.Z3_get_range(nCtx, fdecl);
}
#endregion
#region Quantifier Patterns
/// <summary>
/// Create a quantifier pattern.
/// </summary>
public Z3_pattern MkPattern(params Z3_ast[] terms)
{
Debug.Assert(terms != null);
if (terms == null || terms.Length == 0)
throw new Z3Exception("Cannot create a pattern from zero terms");
return Native.Z3_mk_pattern(nCtx, (uint)terms.Length, terms);
}
#endregion
#region Solver
/// <summary>
/// Creates a new (incremental) solver.
/// </summary>
public NativeSolver MkSimpleSolver()
{
Z3_solver nSolver = Native.Z3_mk_simple_solver(nCtx);
return new NativeSolver(this, nSolver);
}
#endregion
#region Utilities
/// <summary>
/// Get the sort kind from IntPtr
/// </summary>
public Z3_sort_kind GetSortKind(Z3_sort sort)
{
Debug.Assert(sort != IntPtr.Zero);
return (Z3_sort_kind)Native.Z3_get_sort_kind(nCtx, sort);
}
/// <summary>
/// Get the AST kind from IntPtr
/// </summary>
public Z3_ast_kind GetAstKind(Z3_ast ast)
{
Debug.Assert(ast != IntPtr.Zero);
return (Z3_ast_kind)Native.Z3_get_ast_kind(nCtx, ast);
}
/// <summary>
/// Get the Decl kind from IntPtr
/// </summary>
public Z3_decl_kind GetDeclKind(Z3_func_decl decl)
{
Debug.Assert(decl != IntPtr.Zero);
return (Z3_decl_kind)Native.Z3_get_decl_kind(nCtx, decl);
}
/// <summary>
/// Get Sort for AST
/// </summary>
public Z3_sort GetSort(Z3_ast ast)
{
Debug.Assert(ast != IntPtr.Zero);
return Native.Z3_get_sort(nCtx, ast);
}
/// <summary>
/// Get the arguments for app
/// </summary>
/// <param name="app"></param>
/// <returns></returns>
public Z3_ast[] GetAppArgs(Z3_app app)
{
var numArgs = GetNumArgs(app);
var args = new Z3_ast[numArgs];
for (uint i = 0; i < numArgs; i++)
{
args[i] = GetAppArg(app, i);
}
return args;
}
/// <summary>
/// Return number of arguments for app
/// </summary>
/// <param name="app"></param>
/// <returns></returns>
public uint GetNumArgs(Z3_app app)
{
Debug.Assert(app != IntPtr.Zero);
return Native.Z3_get_app_num_args(nCtx, app);
}
internal Z3_ast GetAppArg(Z3_app app, uint i) => Native.Z3_get_app_arg(nCtx, app, i);
/// <summary>
/// Get App Decl from IntPtr
/// </summary>
public Z3_func_decl GetAppDecl(Z3_ast ast)
{
Debug.Assert(ast != IntPtr.Zero);
return Native.Z3_get_app_decl(nCtx, ast);
}
/// <summary>
/// Get string name for Decl
/// </summary>
/// <param name="decl"></param>
/// <returns></returns>
public string GetDeclName(Z3_func_decl decl)
{
Debug.Assert(decl != IntPtr.Zero);
var namePtr = Native.Z3_get_decl_name(nCtx, decl);
return Marshal.PtrToStringAnsi(namePtr);
}
/// <summary>
/// Get size of BitVector Sort
/// </summary>
public uint GetBvSortSize(Z3_sort bvSort)
{
Debug.Assert(bvSort != IntPtr.Zero);
return Native.Z3_get_bv_sort_size(nCtx, bvSort);
}
/// <summary>
/// Get the domain IntPtr for Sort
/// </summary>
public Z3_sort GetArraySortDomain(Z3_ast array)
{
Debug.Assert(array != IntPtr.Zero);
return Native.Z3_get_array_sort_domain(nCtx, array);
}
/// <summary>
/// Get the range IntPtr for Sort
/// </summary>
public Z3_sort GetArraySortRange(Z3_ast array)
{
Debug.Assert(array != IntPtr.Zero);
return Native.Z3_get_array_sort_range(nCtx, array);
}
/// <summary>
/// Try to get integer from AST
/// </summary>
/// <param name="v"></param>
/// <param name="i"></param>
/// <returns></returns>
public bool TryGetNumeralInt(Z3_ast v, out int i)
{
Debug.Assert(v != IntPtr.Zero);
int result = i = 0;
if (Native.Z3_get_numeral_int(nCtx, v, ref result) == 0)
{
return false;
}
i = result;
return true;
}
/// <summary>
/// Try to get uint from AST
/// </summary>
/// <param name="v"></param>
/// <param name="u"></param>
/// <returns></returns>
public bool TryGetNumeralUInt(Z3_ast v, out uint u)
{
Debug.Assert(v != IntPtr.Zero);
uint result = u = 0;
if (Native.Z3_get_numeral_uint(nCtx, v, ref result) == 0)
{
return false;
}
u = result;
return true;
}
/// <summary>
/// Try to get long from AST
/// </summary>
/// <param name="v"></param>
/// <param name="i"></param>
/// <returns></returns>
public bool TryGetNumeralInt64(Z3_ast v, out long i)
{
Debug.Assert(v != IntPtr.Zero);
long result = i = 0;
if (Native.Z3_get_numeral_int64(nCtx, v, ref result) == 0)
{
return false;
}
i = result;
return true;
}
/// <summary>
/// Try get ulong from AST
/// </summary>
/// <param name="v"></param>
/// <param name="u"></param>
/// <returns></returns>
public bool TryGetNumeralUInt64(Z3_ast v, out ulong u)
{
Debug.Assert(v != IntPtr.Zero);
ulong result = u = 0;
if (Native.Z3_get_numeral_uint64(nCtx, v, ref result) == 0)
{
return false;
}
u = result;
return true;
}
/// <summary>
/// Get string for numeral ast
/// </summary>
/// <param name="v"></param>
/// <returns></returns>
public string GetNumeralString(Z3_ast v)
{
Debug.Assert(v != IntPtr.Zero);
return Native.Z3_get_numeral_string(nCtx, v);
}
/// <summary>
/// Get printable string representing Z3_ast
/// </summary>
/// <param name="ast"></param>
/// <returns></returns>
public string ToString(Z3_ast ast)
{
Debug.Assert(ast != IntPtr.Zero);
return Native.Z3_ast_to_string(nCtx, ast);
}
/// <summary>
/// Enable or disable warning messages
/// </summary>
/// <param name="turnOn"></param>
public void ToggleWarningMessages(bool turnOn)
=> Native.Z3_toggle_warning_messages(turnOn ? (byte)1 : (byte)0);
#endregion
#region Internal
internal static Object creation_lock = new Object();
internal IntPtr m_ctx = IntPtr.Zero;
internal Native.Z3_error_handler m_n_err_handler = null;
internal IntPtr nCtx { get { return m_ctx; } }
internal void NativeErrorHandler(IntPtr ctx, Z3_error_code errorCode)
{
// Do-nothing error handler. The wrappers in Z3.Native will throw exceptions upon errors.
}
internal void InitContext()
{
PrintMode = Z3_ast_print_mode.Z3_PRINT_SMTLIB2_COMPLIANT;
m_n_err_handler = new Native.Z3_error_handler(NativeErrorHandler); // keep reference so it doesn't get collected.
Native.Z3_set_error_handler(m_ctx, m_n_err_handler);
GC.SuppressFinalize(this);
}
#endregion
#region Tracing
/// <summary>
/// Enable trace to file
/// </summary>
/// <param name="tag">Tag to trace</param>
public static void EnableTrace(string tag)
{
Debug.Assert(!string.IsNullOrEmpty(tag));
Native.Z3_enable_trace(tag);
}
#endregion
#region Dispose
/// <summary>
/// Disposes of the context.
/// </summary>
public void Dispose()
{
if (m_ctx != IntPtr.Zero)
{
m_n_err_handler = null;
IntPtr ctx = m_ctx;
m_ctx = IntPtr.Zero;
Native.Z3_del_context(ctx);
}
else
GC.ReRegisterForFinalize(this);
}
#endregion
/// <summary>
/// Utility to convert a vector object of ast to a .Net array
/// </summary>
/// <param name="vec"></param>
/// <returns></returns>
public Z3_ast[] ToArray(Z3_ast_vector vec)
{
Native.Z3_ast_vector_inc_ref(nCtx, vec);
var sz = Native.Z3_ast_vector_size(nCtx, vec);
var result = new Z3_ast[sz];
for (uint i = 0; i < sz; ++i)
result[i] = Native.Z3_ast_vector_get(nCtx, vec, i);
Native.Z3_ast_vector_dec_ref(nCtx, vec);
return result;
}
/// <summary>
/// Retrieve statistics as an array of entries
/// </summary>
/// <param name="stats"></param>
/// <returns></returns>
public Statistics.Entry[] GetStatistics(Z3_stats stats)
{
Native.Z3_stats_inc_ref(nCtx, stats);
var result = Statistics.NativeEntries(nCtx, stats);
Native.Z3_stats_dec_ref(nCtx, stats);
return result;
}
}
}