/*++ Copyright () 2012 Microsoft Corporation Module Name: Expr.cs Abstract: Z3 Managed API: Expressions Author: Christoph Wintersteiger (cwinter) 2012-03-20 Notes: --*/ using System; using System.Diagnostics.Contracts; namespace Microsoft.Z3 { /// /// Expressions are terms. /// [ContractVerification(true)] public class Expr : AST { /// /// Returns a simplified version of the expression. /// /// A set of parameters to configure the simplifier /// public Expr Simplify(Params p = null) { Contract.Ensures(Contract.Result() != null); if (p == null) return Expr.Create(Context, Native.Z3_simplify(Context.nCtx, NativeObject)); else return Expr.Create(Context, Native.Z3_simplify_ex(Context.nCtx, NativeObject, p.NativeObject)); } /// /// The function declaration of the function that is applied in this expression. /// public FuncDecl FuncDecl { get { Contract.Ensures(Contract.Result() != null); return new FuncDecl(Context, Native.Z3_get_app_decl(Context.nCtx, NativeObject)); } } /// /// Indicates whether the expression is the true or false expression /// or something else (Z3_L_UNDEF). /// public Z3_lbool BoolValue { get { return (Z3_lbool)Native.Z3_get_bool_value(Context.nCtx, NativeObject); } } /// /// The number of arguments of the expression. /// public uint NumArgs { get { return Native.Z3_get_app_num_args(Context.nCtx, NativeObject); } } /// /// The arguments of the expression. /// public Expr[] Args { get { Contract.Ensures(Contract.Result() != null); uint n = NumArgs; Expr[] res = new Expr[n]; for (uint i = 0; i < n; i++) res[i] = Expr.Create(Context, Native.Z3_get_app_arg(Context.nCtx, NativeObject, i)); return res; } } /// /// Update the arguments of the expression using the arguments /// The number of new arguments should coincide with the current number of arguments. /// public void Update(Expr[] args) { Contract.Requires(args != null); Contract.Requires(Contract.ForAll(args, a => a != null)); Context.CheckContextMatch(args); if (args.Length != NumArgs) throw new Z3Exception("Number of arguments does not match"); NativeObject = Native.Z3_update_term(Context.nCtx, NativeObject, (uint)args.Length, Expr.ArrayToNative(args)); } /// /// Substitute every occurrence of from[i] in the expression with to[i], for i smaller than num_exprs. /// /// /// The result is the new expression. The arrays from and to must have size num_exprs. /// For every i smaller than num_exprs, we must have that /// sort of from[i] must be equal to sort of to[i]. /// public Expr Substitute(Expr[] from, Expr[] to) { Contract.Requires(from != null); Contract.Requires(to != null); Contract.Requires(Contract.ForAll(from, f => f != null)); Contract.Requires(Contract.ForAll(to, t => t != null)); Contract.Ensures(Contract.Result() != null); Context.CheckContextMatch(from); Context.CheckContextMatch(to); if (from.Length != to.Length) throw new Z3Exception("Argument sizes do not match"); return Expr.Create(Context, Native.Z3_substitute(Context.nCtx, NativeObject, (uint)from.Length, Expr.ArrayToNative(from), Expr.ArrayToNative(to))); } /// /// Substitute every occurrence of from in the expression with to. /// /// public Expr Substitute(Expr from, Expr to) { Contract.Requires(from != null); Contract.Requires(to != null); Contract.Ensures(Contract.Result() != null); return Substitute(new Expr[] { from }, new Expr[] { to }); } /// /// Substitute the free variables in the expression with the expressions in /// /// /// For every i smaller than num_exprs, the variable with de-Bruijn index i is replaced with term to[i]. /// public Expr SubstituteVars(Expr[] to) { Contract.Requires(to != null); Contract.Requires(Contract.ForAll(to, t => t != null)); Contract.Ensures(Contract.Result() != null); Context.CheckContextMatch(to); return Expr.Create(Context, Native.Z3_substitute_vars(Context.nCtx, NativeObject, (uint)to.Length, Expr.ArrayToNative(to))); } /// /// Translates (copies) the term to the Context . /// /// A context /// A copy of the term which is associated with new public Expr Translate(Context ctx) { Contract.Requires(ctx != null); Contract.Ensures(Contract.Result() != null); if (ReferenceEquals(Context, ctx)) return this; else return Expr.Create(ctx, Native.Z3_translate(Context.nCtx, NativeObject, ctx.nCtx)); } /// /// Returns a string representation of the expression. /// public override string ToString() { return base.ToString(); } /// /// Indicates whether the term is a numeral /// public bool IsNumeral { get { return Native.Z3_is_numeral_ast(Context.nCtx, NativeObject) != 0; } } /// /// Indicates whether the term is well-sorted. /// /// True if the term is well-sorted, false otherwise. public bool IsWellSorted { get { return Native.Z3_is_well_sorted(Context.nCtx, NativeObject) != 0; } } /// /// The Sort of the term. /// public Sort Sort { get { Contract.Ensures(Contract.Result() != null); return Sort.Create(Context, Native.Z3_get_sort(Context.nCtx, NativeObject)); } } #region Constants /// /// Indicates whether the term represents a constant. /// public bool IsConst { get { return IsExpr && NumArgs == 0 && FuncDecl.DomainSize == 0; } } #endregion #region Integer Numerals /// /// Indicates whether the term is an integer numeral. /// public bool IsIntNum { get { return IsNumeral && IsInt; } } #endregion #region Real Numerals /// /// Indicates whether the term is a real numeral. /// public bool IsRatNum { get { return IsNumeral && IsReal; } } #endregion #region Algebraic Numbers /// /// Indicates whether the term is an algebraic number /// public bool IsAlgebraicNumber { get { return Native.Z3_is_algebraic_number(Context.nCtx, NativeObject) != 0; } } #endregion #region Term Kind Tests #region Boolean Terms /// /// Indicates whether the term has Boolean sort. /// public bool IsBool { get { return (IsExpr && Native.Z3_is_eq_sort(Context.nCtx, Native.Z3_mk_bool_sort(Context.nCtx), Native.Z3_get_sort(Context.nCtx, NativeObject)) != 0); } } /// /// Indicates whether the term is the constant true. /// public bool IsTrue { get { return FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_TRUE; } } /// /// Indicates whether the term is the constant false. /// public bool IsFalse { get { return FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_FALSE; } } /// /// Indicates whether the term is an equality predicate. /// public bool IsEq { get { return FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_EQ; } } /// /// Indicates whether the term is an n-ary distinct predicate (every argument is mutually distinct). /// public bool IsDistinct { get { return FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_DISTINCT; } } /// /// Indicates whether the term is a ternary if-then-else term /// public bool IsITE { get { return FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_ITE; } } /// /// Indicates whether the term is an n-ary conjunction /// public bool IsAnd { get { return FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_AND; } } /// /// Indicates whether the term is an n-ary disjunction /// public bool IsOr { get { return FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_OR; } } /// /// Indicates whether the term is an if-and-only-if (Boolean equivalence, binary) /// public bool IsIff { get { return FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_IFF; } } /// /// Indicates whether the term is an exclusive or /// public bool IsXor { get { return FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_XOR; } } /// /// Indicates whether the term is a negation /// public bool IsNot { get { return FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_NOT; } } /// /// Indicates whether the term is an implication /// public bool IsImplies { get { return FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_IMPLIES; } } #endregion #region Arithmetic Terms /// /// Indicates whether the term is of integer sort. /// public bool IsInt { get { return (Native.Z3_is_numeral_ast(Context.nCtx, NativeObject) != 0 && Native.Z3_get_sort_kind(Context.nCtx, Native.Z3_get_sort(Context.nCtx, NativeObject)) == (uint)Z3_sort_kind.Z3_INT_SORT); } } /// /// Indicates whether the term is of sort real. /// public bool IsReal { get { return Native.Z3_get_sort_kind(Context.nCtx, Native.Z3_get_sort(Context.nCtx, NativeObject)) == (uint)Z3_sort_kind.Z3_REAL_SORT; } } /// /// Indicates whether the term is an arithmetic numeral. /// public bool IsArithmeticNumeral { get { return FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_ANUM; } } /// /// Indicates whether the term is a less-than-or-equal /// public bool IsLE { get { return FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_LE; } } /// /// Indicates whether the term is a greater-than-or-equal /// public bool IsGE { get { return FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_GE; } } /// /// Indicates whether the term is a less-than /// public bool IsLT { get { return FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_LT; } } /// /// Indicates whether the term is a greater-than /// public bool IsGT { get { return FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_GT; } } /// /// Indicates whether the term is addition (binary) /// public bool IsAdd { get { return FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_ADD; } } /// /// Indicates whether the term is subtraction (binary) /// public bool IsSub { get { return FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_SUB; } } /// /// Indicates whether the term is a unary minus /// public bool IsUMinus { get { return FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_UMINUS; } } /// /// Indicates whether the term is multiplication (binary) /// public bool IsMul { get { return FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_MUL; } } /// /// Indicates whether the term is division (binary) /// public bool IsDiv { get { return FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_DIV; } } /// /// Indicates whether the term is integer division (binary) /// public bool IsIDiv { get { return FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_IDIV; } } /// /// Indicates whether the term is remainder (binary) /// public bool IsRemainder { get { return FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_REM; } } /// /// Indicates whether the term is modulus (binary) /// public bool IsModulus { get { return FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_MOD; } } /// /// Indicates whether the term is a coercion of integer to real (unary) /// public bool IsIntToReal { get { return FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_TO_REAL; } } /// /// Indicates whether the term is a coercion of real to integer (unary) /// public bool IsRealToInt { get { return FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_TO_INT; } } /// /// Indicates whether the term is a check that tests whether a real is integral (unary) /// public bool IsRealIsInt { get { return FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_IS_INT; } } #endregion #region Array Terms /// /// Indicates whether the term is of an array sort. /// public bool IsArray { get { return (Native.Z3_is_app(Context.nCtx, NativeObject) != 0 && (Z3_sort_kind)Native.Z3_get_sort_kind(Context.nCtx, Native.Z3_get_sort(Context.nCtx, NativeObject)) == Z3_sort_kind.Z3_ARRAY_SORT); } } /// /// Indicates whether the term is an array store. /// /// It satisfies select(store(a,i,v),j) = if i = j then v else select(a,j). /// Array store takes at least 3 arguments. public bool IsStore { get { return FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_STORE; } } /// /// Indicates whether the term is an array select. /// public bool IsSelect { get { return FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_SELECT; } } /// /// Indicates whether the term is a constant array. /// /// For example, select(const(v),i) = v holds for every v and i. The function is unary. public bool IsConstantArray { get { return FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_CONST_ARRAY; } } /// /// Indicates whether the term is a default array. /// /// For example default(const(v)) = v. The function is unary. public bool IsDefaultArray { get { return FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_ARRAY_DEFAULT; } } /// /// Indicates whether the term is an array map. /// /// It satisfies map[f](a1,..,a_n)[i] = f(a1[i],...,a_n[i]) for every i. public bool IsArrayMap { get { return FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_ARRAY_MAP; } } /// /// Indicates whether the term is an as-array term. /// /// An as-array term is n array value that behaves as the function graph of the /// function passed as parameter. public bool IsAsArray { get { return FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_AS_ARRAY; } } #endregion #region Set Terms /// /// Indicates whether the term is set union /// public bool IsSetUnion { get { return FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_SET_UNION; } } /// /// Indicates whether the term is set intersection /// public bool IsSetIntersect { get { return FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_SET_INTERSECT; } } /// /// Indicates whether the term is set difference /// public bool IsSetDifference { get { return FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_SET_DIFFERENCE; } } /// /// Indicates whether the term is set complement /// public bool IsSetComplement { get { return FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_SET_COMPLEMENT; } } /// /// Indicates whether the term is set subset /// public bool IsSetSubset { get { return FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_SET_SUBSET; } } #endregion #region Bit-vector terms /// /// Indicates whether the terms is of bit-vector sort. /// public bool IsBV { get { return Native.Z3_get_sort_kind(Context.nCtx, Native.Z3_get_sort(Context.nCtx, NativeObject)) == (uint)Z3_sort_kind.Z3_BV_SORT; } } /// /// Indicates whether the term is a bit-vector numeral /// public bool IsBVNumeral { get { return FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_BNUM; } } /// /// Indicates whether the term is a one-bit bit-vector with value one /// public bool IsBVBitOne { get { return FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_BIT1; } } /// /// Indicates whether the term is a one-bit bit-vector with value zero /// public bool IsBVBitZero { get { return FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_BIT0; } } /// /// Indicates whether the term is a bit-vector unary minus /// public bool IsBVUMinus { get { return FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_BNEG; } } /// /// Indicates whether the term is a bit-vector addition (binary) /// public bool IsBVAdd { get { return FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_BADD; } } /// /// Indicates whether the term is a bit-vector subtraction (binary) /// public bool IsBVSub { get { return FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_BSUB; } } /// /// Indicates whether the term is a bit-vector multiplication (binary) /// public bool IsBVMul { get { return FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_BMUL; } } /// /// Indicates whether the term is a bit-vector signed division (binary) /// public bool IsBVSDiv { get { return FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_BSDIV; } } /// /// Indicates whether the term is a bit-vector unsigned division (binary) /// public bool IsBVUDiv { get { return FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_BUDIV; } } /// /// Indicates whether the term is a bit-vector signed remainder (binary) /// public bool IsBVSRem { get { return FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_BSREM; } } /// /// Indicates whether the term is a bit-vector unsigned remainder (binary) /// public bool IsBVURem { get { return FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_BUREM; } } /// /// Indicates whether the term is a bit-vector signed modulus /// public bool IsBVSMod { get { return FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_BSMOD; } } /// /// Indicates whether the term is a bit-vector signed division by zero /// internal bool IsBVSDiv0 { get { return FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_BSDIV0; } } /// /// Indicates whether the term is a bit-vector unsigned division by zero /// internal bool IsBVUDiv0 { get { return FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_BUDIV0; } } /// /// Indicates whether the term is a bit-vector signed remainder by zero /// internal bool IsBVSRem0 { get { return FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_BSREM0; } } /// /// Indicates whether the term is a bit-vector unsigned remainder by zero /// internal bool IsBVURem0 { get { return FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_BUREM0; } } /// /// Indicates whether the term is a bit-vector signed modulus by zero /// internal bool IsBVSMod0 { get { return FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_BSMOD0; } } /// /// Indicates whether the term is an unsigned bit-vector less-than-or-equal /// public bool IsBVULE { get { return FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_ULEQ; } } /// /// Indicates whether the term is a signed bit-vector less-than-or-equal /// public bool IsBVSLE { get { return FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_SLEQ; } } /// /// Indicates whether the term is an unsigned bit-vector greater-than-or-equal /// public bool IsBVUGE { get { return FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_UGEQ; } } /// /// Indicates whether the term is a signed bit-vector greater-than-or-equal /// public bool IsBVSGE { get { return FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_SGEQ; } } /// /// Indicates whether the term is an unsigned bit-vector less-than /// public bool IsBVULT { get { return FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_ULT; } } /// /// Indicates whether the term is a signed bit-vector less-than /// public bool IsBVSLT { get { return FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_SLT; } } /// /// Indicates whether the term is an unsigned bit-vector greater-than /// public bool IsBVUGT { get { return FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_UGT; } } /// /// Indicates whether the term is a signed bit-vector greater-than /// public bool IsBVSGT { get { return FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_SGT; } } /// /// Indicates whether the term is a bit-wise AND /// public bool IsBVAND { get { return FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_BAND; } } /// /// Indicates whether the term is a bit-wise OR /// public bool IsBVOR { get { return FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_BOR; } } /// /// Indicates whether the term is a bit-wise NOT /// public bool IsBVNOT { get { return FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_BNOT; } } /// /// Indicates whether the term is a bit-wise XOR /// public bool IsBVXOR { get { return FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_BXOR; } } /// /// Indicates whether the term is a bit-wise NAND /// public bool IsBVNAND { get { return FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_BNAND; } } /// /// Indicates whether the term is a bit-wise NOR /// public bool IsBVNOR { get { return FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_BNOR; } } /// /// Indicates whether the term is a bit-wise XNOR /// public bool IsBVXNOR { get { return FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_BXNOR; } } /// /// Indicates whether the term is a bit-vector concatenation (binary) /// public bool IsBVConcat { get { return FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_CONCAT; } } /// /// Indicates whether the term is a bit-vector sign extension /// public bool IsBVSignExtension { get { return FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_SIGN_EXT; } } /// /// Indicates whether the term is a bit-vector zero extension /// public bool IsBVZeroExtension { get { return FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_ZERO_EXT; } } /// /// Indicates whether the term is a bit-vector extraction /// public bool IsBVExtract { get { return FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_EXTRACT; } } /// /// Indicates whether the term is a bit-vector repetition /// public bool IsBVRepeat { get { return FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_REPEAT; } } /// /// Indicates whether the term is a bit-vector reduce OR /// public bool IsBVReduceOR { get { return FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_BREDOR; } } /// /// Indicates whether the term is a bit-vector reduce AND /// public bool IsBVReduceAND { get { return FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_BREDAND; } } /// /// Indicates whether the term is a bit-vector comparison /// public bool IsBVComp { get { return FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_BCOMP; } } /// /// Indicates whether the term is a bit-vector shift left /// public bool IsBVShiftLeft { get { return FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_BSHL; } } /// /// Indicates whether the term is a bit-vector logical shift right /// public bool IsBVShiftRightLogical { get { return FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_BLSHR; } } /// /// Indicates whether the term is a bit-vector arithmetic shift left /// public bool IsBVShiftRightArithmetic { get { return FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_BASHR; } } /// /// Indicates whether the term is a bit-vector rotate left /// public bool IsBVRotateLeft { get { return FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_ROTATE_LEFT; } } /// /// Indicates whether the term is a bit-vector rotate right /// public bool IsBVRotateRight { get { return FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_ROTATE_RIGHT; } } /// /// Indicates whether the term is a bit-vector rotate left (extended) /// /// Similar to Z3_OP_ROTATE_LEFT, but it is a binary operator instead of a parametric one. public bool IsBVRotateLeftExtended { get { return FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_EXT_ROTATE_LEFT; } } /// /// Indicates whether the term is a bit-vector rotate right (extended) /// /// Similar to Z3_OP_ROTATE_RIGHT, but it is a binary operator instead of a parametric one. public bool IsBVRotateRightExtended { get { return FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_EXT_ROTATE_RIGHT; } } /// /// Indicates whether the term is a coercion from integer to bit-vector /// /// This function is not supported by the decision procedures. Only the most /// rudimentary simplification rules are applied to this function. public bool IsIntToBV { get { return FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_INT2BV; } } /// /// Indicates whether the term is a coercion from bit-vector to integer /// /// This function is not supported by the decision procedures. Only the most /// rudimentary simplification rules are applied to this function. public bool IsBVToInt { get { return FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_BV2INT; } } /// /// Indicates whether the term is a bit-vector carry /// /// Compute the carry bit in a full-adder. The meaning is given by the /// equivalence (carry l1 l2 l3) <=> (or (and l1 l2) (and l1 l3) (and l2 l3))) public bool IsBVCarry { get { return FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_CARRY; } } /// /// Indicates whether the term is a bit-vector ternary XOR /// /// The meaning is given by the equivalence (xor3 l1 l2 l3) <=> (xor (xor l1 l2) l3) public bool IsBVXOR3 { get { return FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_XOR3; } } #endregion #region Labels /// /// Indicates whether the term is a label (used by the Boogie Verification condition generator). /// /// The label has two parameters, a string and a Boolean polarity. It takes one argument, a formula. public bool IsLabel { get { return FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_LABEL; } } /// /// Indicates whether the term is a label literal (used by the Boogie Verification condition generator). /// /// A label literal has a set of string parameters. It takes no arguments. public bool IsLabelLit { get { return FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_LABEL_LIT; } } #endregion #region Proof Terms /// /// Indicates whether the term is a binary equivalence modulo namings. /// /// This binary predicate is used in proof terms. /// It captures equisatisfiability and equivalence modulo renamings. public bool IsOEQ { get { return FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_OEQ; } } /// /// Indicates whether the term is a Proof for the expression 'true'. /// public bool IsProofTrue { get { return FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_PR_TRUE; } } /// /// Indicates whether the term is a proof for a fact asserted by the user. /// public bool IsProofAsserted { get { return FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_PR_ASSERTED; } } /// /// Indicates whether the term is a proof for a fact (tagged as goal) asserted by the user. /// public bool IsProofGoal { get { return FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_PR_GOAL; } } /// /// Indicates whether the term is proof via modus ponens /// /// /// Given a proof for p and a proof for (implies p q), produces a proof for q. /// T1: p /// T2: (implies p q) /// [mp T1 T2]: q /// The second antecedents may also be a proof for (iff p q). public bool IsProofModusPonens { get { return FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_PR_MODUS_PONENS; } } /// /// Indicates whether the term is a proof for (R t t), where R is a reflexive relation. /// /// This proof object has no antecedents. /// The only reflexive relations that are used are /// equivalence modulo namings, equality and equivalence. /// That is, R is either '~', '=' or 'iff'. public bool IsProofReflexivity { get { return FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_PR_REFLEXIVITY; } } /// /// Indicates whether the term is proof by symmetricity of a relation /// /// /// Given an symmetric relation R and a proof for (R t s), produces a proof for (R s t). /// T1: (R t s) /// [symmetry T1]: (R s t) /// T1 is the antecedent of this proof object. /// public bool IsProofSymmetry { get { return FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_PR_SYMMETRY; } } /// /// Indicates whether the term is a proof by transitivity of a relation /// /// /// Given a transitive relation R, and proofs for (R t s) and (R s u), produces a proof /// for (R t u). /// T1: (R t s) /// T2: (R s u) /// [trans T1 T2]: (R t u) /// public bool IsProofTransitivity { get { return FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_PR_TRANSITIVITY; } } /// /// Indicates whether the term is a proof by condensed transitivity of a relation /// /// /// Condensed transitivity proof. This proof object is only used if the parameter PROOF_MODE is 1. /// It combines several symmetry and transitivity proofs. /// Example: /// T1: (R a b) /// T2: (R c b) /// T3: (R c d) /// [trans* T1 T2 T3]: (R a d) /// R must be a symmetric and transitive relation. /// /// Assuming that this proof object is a proof for (R s t), then /// a proof checker must check if it is possible to prove (R s t) /// using the antecedents, symmetry and transitivity. That is, /// if there is a path from s to t, if we view every /// antecedent (R a b) as an edge between a and b. /// public bool IsProofTransitivityStar { get { return FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_PR_TRANSITIVITY_STAR; } } /// /// Indicates whether the term is a monotonicity proof object. /// /// /// T1: (R t_1 s_1) /// ... /// Tn: (R t_n s_n) /// [monotonicity T1 ... Tn]: (R (f t_1 ... t_n) (f s_1 ... s_n)) /// Remark: if t_i == s_i, then the antecedent Ti is suppressed. /// That is, reflexivity proofs are supressed to save space. /// public bool IsProofMonotonicity { get { return FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_PR_MONOTONICITY; } } /// /// Indicates whether the term is a quant-intro proof /// /// /// Given a proof for (~ p q), produces a proof for (~ (forall (x) p) (forall (x) q)). /// T1: (~ p q) /// [quant-intro T1]: (~ (forall (x) p) (forall (x) q)) /// public bool IsProofQuantIntro { get { return FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_PR_QUANT_INTRO; } } /// /// Indicates whether the term is a distributivity proof object. /// /// /// Given that f (= or) distributes over g (= and), produces a proof for /// (= (f a (g c d)) /// (g (f a c) (f a d))) /// If f and g are associative, this proof also justifies the following equality: /// (= (f (g a b) (g c d)) /// (g (f a c) (f a d) (f b c) (f b d))) /// where each f and g can have arbitrary number of arguments. /// /// This proof object has no antecedents. /// Remark. This rule is used by the CNF conversion pass and /// instantiated by f = or, and g = and. /// public bool IsProofDistributivity { get { return FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_PR_DISTRIBUTIVITY; } } /// /// Indicates whether the term is a proof by elimination of AND /// /// /// Given a proof for (and l_1 ... l_n), produces a proof for l_i /// T1: (and l_1 ... l_n) /// [and-elim T1]: l_i /// public bool IsProofAndElimination { get { return FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_PR_AND_ELIM; } } /// /// Indicates whether the term is a proof by eliminiation of not-or /// /// /// Given a proof for (not (or l_1 ... l_n)), produces a proof for (not l_i). /// T1: (not (or l_1 ... l_n)) /// [not-or-elim T1]: (not l_i) /// public bool IsProofOrElimination { get { return FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_PR_NOT_OR_ELIM; } } /// /// Indicates whether the term is a proof by rewriting /// /// /// A proof for a local rewriting step (= t s). /// The head function symbol of t is interpreted. /// /// This proof object has no antecedents. /// The conclusion of a rewrite rule is either an equality (= t s), /// an equivalence (iff t s), or equi-satisfiability (~ t s). /// Remark: if f is bool, then = is iff. /// /// Examples: /// (= (+ x 0) x) /// (= (+ x 1 2) (+ 3 x)) /// (iff (or x false) x) /// public bool IsProofRewrite { get { return FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_PR_REWRITE; } } /// /// Indicates whether the term is a proof by rewriting /// /// /// A proof for rewriting an expression t into an expression s. /// This proof object is used if the parameter PROOF_MODE is 1. /// This proof object can have n antecedents. /// The antecedents are proofs for equalities used as substitution rules. /// The object is also used in a few cases if the parameter PROOF_MODE is 2. /// The cases are: /// - When applying contextual simplification (CONTEXT_SIMPLIFIER=true) /// - When converting bit-vectors to Booleans (BIT2BOOL=true) /// - When pulling ite expression up (PULL_CHEAP_ITE_TREES=true) /// public bool IsProofRewriteStar { get { return FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_PR_REWRITE_STAR; } } /// /// Indicates whether the term is a proof for pulling quantifiers out. /// /// /// A proof for (iff (f (forall (x) q(x)) r) (forall (x) (f (q x) r))). This proof object has no antecedents. /// public bool IsProofPullQuant { get { return FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_PR_PULL_QUANT; } } /// /// Indicates whether the term is a proof for pulling quantifiers out. /// /// /// A proof for (iff P Q) where Q is in prenex normal form. /// This proof object is only used if the parameter PROOF_MODE is 1. /// This proof object has no antecedents /// public bool IsProofPullQuantStar { get { return FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_PR_PULL_QUANT_STAR; } } /// /// Indicates whether the term is a proof for pushing quantifiers in. /// /// /// A proof for: /// (iff (forall (x_1 ... x_m) (and p_1[x_1 ... x_m] ... p_n[x_1 ... x_m])) /// (and (forall (x_1 ... x_m) p_1[x_1 ... x_m]) /// ... /// (forall (x_1 ... x_m) p_n[x_1 ... x_m]))) /// This proof object has no antecedents /// public bool IsProofPushQuant { get { return FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_PR_PUSH_QUANT; } } /// /// Indicates whether the term is a proof for elimination of unused variables. /// /// /// A proof for (iff (forall (x_1 ... x_n y_1 ... y_m) p[x_1 ... x_n]) /// (forall (x_1 ... x_n) p[x_1 ... x_n])) /// /// It is used to justify the elimination of unused variables. /// This proof object has no antecedents. /// public bool IsProofElimUnusedVars { get { return FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_PR_ELIM_UNUSED_VARS; } } /// /// Indicates whether the term is a proof for destructive equality resolution /// /// /// A proof for destructive equality resolution: /// (iff (forall (x) (or (not (= x t)) P[x])) P[t]) /// if x does not occur in t. /// /// This proof object has no antecedents. /// /// Several variables can be eliminated simultaneously. /// public bool IsProofDER { get { return FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_PR_DER; } } /// /// Indicates whether the term is a proof for quantifier instantiation /// /// /// A proof of (or (not (forall (x) (P x))) (P a)) /// public bool IsProofQuantInst { get { return FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_PR_QUANT_INST; } } /// /// Indicates whether the term is a hypthesis marker. /// /// Mark a hypothesis in a natural deduction style proof. public bool IsProofHypothesis { get { return FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_PR_HYPOTHESIS; } } /// /// Indicates whether the term is a proof by lemma /// /// /// T1: false /// [lemma T1]: (or (not l_1) ... (not l_n)) /// /// This proof object has one antecedent: a hypothetical proof for false. /// It converts the proof in a proof for (or (not l_1) ... (not l_n)), /// when T1 contains the hypotheses: l_1, ..., l_n. /// public bool IsProofLemma { get { return FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_PR_LEMMA; } } /// /// Indicates whether the term is a proof by unit resolution /// /// /// T1: (or l_1 ... l_n l_1' ... l_m') /// T2: (not l_1) /// ... /// T(n+1): (not l_n) /// [unit-resolution T1 ... T(n+1)]: (or l_1' ... l_m') /// public bool IsProofUnitResolution { get { return FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_PR_UNIT_RESOLUTION; } } /// /// Indicates whether the term is a proof by iff-true /// /// /// T1: p /// [iff-true T1]: (iff p true) /// public bool IsProofIFFTrue { get { return FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_PR_IFF_TRUE; } } /// /// Indicates whether the term is a proof by iff-false /// /// /// T1: (not p) /// [iff-false T1]: (iff p false) /// public bool IsProofIFFFalse { get { return FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_PR_IFF_FALSE; } } /// /// Indicates whether the term is a proof by commutativity /// /// /// [comm]: (= (f a b) (f b a)) /// /// f is a commutative operator. /// /// This proof object has no antecedents. /// Remark: if f is bool, then = is iff. /// public bool IsProofCommutativity { get { return FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_PR_COMMUTATIVITY; } } /// /// Indicates whether the term is a proof for Tseitin-like axioms /// /// /// Proof object used to justify Tseitin's like axioms: /// /// (or (not (and p q)) p) /// (or (not (and p q)) q) /// (or (not (and p q r)) p) /// (or (not (and p q r)) q) /// (or (not (and p q r)) r) /// ... /// (or (and p q) (not p) (not q)) /// (or (not (or p q)) p q) /// (or (or p q) (not p)) /// (or (or p q) (not q)) /// (or (not (iff p q)) (not p) q) /// (or (not (iff p q)) p (not q)) /// (or (iff p q) (not p) (not q)) /// (or (iff p q) p q) /// (or (not (ite a b c)) (not a) b) /// (or (not (ite a b c)) a c) /// (or (ite a b c) (not a) (not b)) /// (or (ite a b c) a (not c)) /// (or (not (not a)) (not a)) /// (or (not a) a) /// /// This proof object has no antecedents. /// Note: all axioms are propositional tautologies. /// Note also that 'and' and 'or' can take multiple arguments. /// You can recover the propositional tautologies by /// unfolding the Boolean connectives in the axioms a small /// bounded number of steps (=3). /// public bool IsProofDefAxiom { get { return FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_PR_DEF_AXIOM; } } /// /// Indicates whether the term is a proof for introduction of a name /// /// /// Introduces a name for a formula/term. /// Suppose e is an expression with free variables x, and def-intro /// introduces the name n(x). The possible cases are: /// /// When e is of Boolean type: /// [def-intro]: (and (or n (not e)) (or (not n) e)) /// /// or: /// [def-intro]: (or (not n) e) /// when e only occurs positively. /// /// When e is of the form (ite cond th el): /// [def-intro]: (and (or (not cond) (= n th)) (or cond (= n el))) /// /// Otherwise: /// [def-intro]: (= n e) /// public bool IsProofDefIntro { get { return FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_PR_DEF_INTRO; } } /// /// Indicates whether the term is a proof for application of a definition /// /// /// [apply-def T1]: F ~ n /// F is 'equivalent' to n, given that T1 is a proof that /// n is a name for F. /// public bool IsProofApplyDef { get { return FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_PR_APPLY_DEF; } } /// /// Indicates whether the term is a proof iff-oeq /// /// /// T1: (iff p q) /// [iff~ T1]: (~ p q) /// public bool IsProofIFFOEQ { get { return FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_PR_IFF_OEQ; } } /// /// Indicates whether the term is a proof for a positive NNF step /// /// /// Proof for a (positive) NNF step. Example: /// /// T1: (not s_1) ~ r_1 /// T2: (not s_2) ~ r_2 /// T3: s_1 ~ r_1' /// T4: s_2 ~ r_2' /// [nnf-pos T1 T2 T3 T4]: (~ (iff s_1 s_2) /// (and (or r_1 r_2') (or r_1' r_2))) /// /// The negation normal form steps NNF_POS and NNF_NEG are used in the following cases: /// (a) When creating the NNF of a positive force quantifier. /// The quantifier is retained (unless the bound variables are eliminated). /// Example /// T1: q ~ q_new /// [nnf-pos T1]: (~ (forall (x T) q) (forall (x T) q_new)) /// /// (b) When recursively creating NNF over Boolean formulas, where the top-level /// connective is changed during NNF conversion. The relevant Boolean connectives /// for NNF_POS are 'implies', 'iff', 'xor', 'ite'. /// NNF_NEG furthermore handles the case where negation is pushed /// over Boolean connectives 'and' and 'or'. /// public bool IsProofNNFPos { get { return FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_PR_NNF_POS; } } /// /// Indicates whether the term is a proof for a negative NNF step /// /// /// Proof for a (negative) NNF step. Examples: /// /// T1: (not s_1) ~ r_1 /// ... /// Tn: (not s_n) ~ r_n /// [nnf-neg T1 ... Tn]: (not (and s_1 ... s_n)) ~ (or r_1 ... r_n) /// and /// T1: (not s_1) ~ r_1 /// ... /// Tn: (not s_n) ~ r_n /// [nnf-neg T1 ... Tn]: (not (or s_1 ... s_n)) ~ (and r_1 ... r_n) /// and /// T1: (not s_1) ~ r_1 /// T2: (not s_2) ~ r_2 /// T3: s_1 ~ r_1' /// T4: s_2 ~ r_2' /// [nnf-neg T1 T2 T3 T4]: (~ (not (iff s_1 s_2)) /// (and (or r_1 r_2) (or r_1' r_2'))) /// public bool IsProofNNFNeg { get { return FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_PR_NNF_NEG; } } /// /// Indicates whether the term is a proof for (~ P Q) here Q is in negation normal form. /// /// /// A proof for (~ P Q) where Q is in negation normal form. /// /// This proof object is only used if the parameter PROOF_MODE is 1. /// /// This proof object may have n antecedents. Each antecedent is a PR_DEF_INTRO. /// public bool IsProofNNFStar { get { return FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_PR_NNF_STAR; } } /// /// Indicates whether the term is a proof for (~ P Q) where Q is in conjunctive normal form. /// /// /// A proof for (~ P Q) where Q is in conjunctive normal form. /// This proof object is only used if the parameter PROOF_MODE is 1. /// This proof object may have n antecedents. Each antecedent is a PR_DEF_INTRO. /// public bool IsProofCNFStar { get { return FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_PR_CNF_STAR; } } /// /// Indicates whether the term is a proof for a Skolemization step /// /// /// Proof for: /// /// [sk]: (~ (not (forall x (p x y))) (not (p (sk y) y))) /// [sk]: (~ (exists x (p x y)) (p (sk y) y)) /// /// This proof object has no antecedents. /// public bool IsProofSkolemize { get { return FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_PR_SKOLEMIZE; } } /// /// Indicates whether the term is a proof by modus ponens for equi-satisfiability. /// /// /// Modus ponens style rule for equi-satisfiability. /// T1: p /// T2: (~ p q) /// [mp~ T1 T2]: q /// public bool IsProofModusPonensOEQ { get { return FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_PR_MODUS_PONENS_OEQ; } } /// /// Indicates whether the term is a proof for theory lemma /// /// /// Generic proof for theory lemmas. /// /// The theory lemma function comes with one or more parameters. /// The first parameter indicates the name of the theory. /// For the theory of arithmetic, additional parameters provide hints for /// checking the theory lemma. /// The hints for arithmetic are: /// - farkas - followed by rational coefficients. Multiply the coefficients to the /// inequalities in the lemma, add the (negated) inequalities and obtain a contradiction. /// - triangle-eq - Indicates a lemma related to the equivalence: /// (iff (= t1 t2) (and (<= t1 t2) (<= t2 t1))) /// - gcd-test - Indicates an integer linear arithmetic lemma that uses a gcd test. /// public bool IsProofTheoryLemma { get { return FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_PR_TH_LEMMA; } } #endregion #region Relational Terms /// /// Indicates whether the term is of an array sort. /// public bool IsRelation { get { return (Native.Z3_is_app(Context.nCtx, NativeObject) != 0 && (Z3_sort_kind)Native.Z3_get_sort_kind(Context.nCtx, Native.Z3_get_sort(Context.nCtx, NativeObject)) == Z3_sort_kind.Z3_RELATION_SORT); } } /// /// Indicates whether the term is an relation store /// /// /// Insert a record into a relation. /// The function takes n+1 arguments, where the first argument is the relation and the remaining n elements /// correspond to the n columns of the relation. /// public bool IsRelationStore { get { return FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_RA_STORE; } } /// /// Indicates whether the term is an empty relation /// public bool IsEmptyRelation { get { return FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_RA_EMPTY; } } /// /// Indicates whether the term is a test for the emptiness of a relation /// public bool IsIsEmptyRelation { get { return FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_RA_IS_EMPTY; } } /// /// Indicates whether the term is a relational join /// public bool IsRelationalJoin { get { return FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_RA_JOIN; } } /// /// Indicates whether the term is the union or convex hull of two relations. /// /// The function takes two arguments. public bool IsRelationUnion { get { return FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_RA_UNION; } } /// /// Indicates whether the term is the widening of two relations /// /// The function takes two arguments. public bool IsRelationWiden { get { return FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_RA_WIDEN; } } /// /// Indicates whether the term is a projection of columns (provided as numbers in the parameters). /// /// The function takes one argument. public bool IsRelationProject { get { return FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_RA_PROJECT; } } /// /// Indicates whether the term is a relation filter /// /// /// Filter (restrict) a relation with respect to a predicate. /// The first argument is a relation. /// The second argument is a predicate with free de-Brujin indices /// corresponding to the columns of the relation. /// So the first column in the relation has index 0. /// public bool IsRelationFilter { get { return FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_RA_FILTER; } } /// /// Indicates whether the term is an intersection of a relation with the negation of another. /// /// /// Intersect the first relation with respect to negation /// of the second relation (the function takes two arguments). /// Logically, the specification can be described by a function /// /// target = filter_by_negation(pos, neg, columns) /// /// where columns are pairs c1, d1, .., cN, dN of columns from pos and neg, such that /// target are elements in x in pos, such that there is no y in neg that agrees with /// x on the columns c1, d1, .., cN, dN. /// public bool IsRelationNegationFilter { get { return FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_RA_NEGATION_FILTER; } } /// /// Indicates whether the term is the renaming of a column in a relation /// /// /// The function takes one argument. /// The parameters contain the renaming as a cycle. /// public bool IsRelationRename { get { return FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_RA_RENAME; } } /// /// Indicates whether the term is the complement of a relation /// public bool IsRelationComplement { get { return FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_RA_COMPLEMENT; } } /// /// Indicates whether the term is a relational select /// /// /// Check if a record is an element of the relation. /// The function takes n+1 arguments, where the first argument is a relation, /// and the remaining n arguments correspond to a record. /// public bool IsRelationSelect { get { return FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_RA_SELECT; } } /// /// Indicates whether the term is a relational clone (copy) /// /// /// Create a fresh copy (clone) of a relation. /// The function is logically the identity, but /// in the context of a register machine allows /// for terms of kind /// to perform destructive updates to the first argument. /// public bool IsRelationClone { get { return FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_RA_CLONE; } } #endregion #region Finite domain terms /// /// Indicates whether the term is of an array sort. /// public bool IsFiniteDomain { get { return (Native.Z3_is_app(Context.nCtx, NativeObject) != 0 && (Z3_sort_kind)Native.Z3_get_sort_kind(Context.nCtx, Native.Z3_get_sort(Context.nCtx, NativeObject)) == Z3_sort_kind.Z3_FINITE_DOMAIN_SORT); } } /// /// Indicates whether the term is a less than predicate over a finite domain. /// public bool IsFiniteDomainLT { get { return FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_FD_LT; } } #endregion #endregion #region Bound Variables /// /// The de-Burijn index of a bound variable. /// /// /// Bound variables are indexed by de-Bruijn indices. It is perhaps easiest to explain /// the meaning of de-Bruijn indices by indicating the compilation process from /// non-de-Bruijn formulas to de-Bruijn format. /// /// abs(forall (x1) phi) = forall (x1) abs1(phi, x1, 0) /// abs(forall (x1, x2) phi) = abs(forall (x1) abs(forall (x2) phi)) /// abs1(x, x, n) = b_n /// abs1(y, x, n) = y /// abs1(f(t1,...,tn), x, n) = f(abs1(t1,x,n), ..., abs1(tn,x,n)) /// abs1(forall (x1) phi, x, n) = forall (x1) (abs1(phi, x, n+1)) /// /// The last line is significant: the index of a bound variable is different depending /// on the scope in which it appears. The deeper x appears, the higher is its /// index. /// public uint Index { get { if (!IsVar) throw new Z3Exception("Term is not a bound variable."); Contract.EndContractBlock(); return Native.Z3_get_index_value(Context.nCtx, NativeObject); } } #endregion #region Internal /// Constructor for Expr internal protected Expr(Context ctx) : base(ctx) { Contract.Requires(ctx != null); } /// Constructor for Expr internal protected Expr(Context ctx, IntPtr obj) : base(ctx, obj) { Contract.Requires(ctx != null); } #if DEBUG [Pure] internal override void CheckNativeObject(IntPtr obj) { if (Native.Z3_is_app(Context.nCtx, obj) == 0 && (Z3_ast_kind)Native.Z3_get_ast_kind(Context.nCtx, obj) != Z3_ast_kind.Z3_VAR_AST && (Z3_ast_kind)Native.Z3_get_ast_kind(Context.nCtx, obj) != Z3_ast_kind.Z3_QUANTIFIER_AST) throw new Z3Exception("Underlying object is not a term"); base.CheckNativeObject(obj); } #endif [Pure] internal static Expr Create(Context ctx, FuncDecl f, params Expr[] arguments) { Contract.Requires(ctx != null); Contract.Requires(f != null); Contract.Ensures(Contract.Result() != null); IntPtr obj = Native.Z3_mk_app(ctx.nCtx, f.NativeObject, AST.ArrayLength(arguments), AST.ArrayToNative(arguments)); return Create(ctx, obj); } [Pure] new internal static Expr Create(Context ctx, IntPtr obj) { Contract.Requires(ctx != null); Contract.Ensures(Contract.Result() != null); Z3_ast_kind k = (Z3_ast_kind)Native.Z3_get_ast_kind(ctx.nCtx, obj); if (k == Z3_ast_kind.Z3_QUANTIFIER_AST) return new Quantifier(ctx, obj); IntPtr s = Native.Z3_get_sort(ctx.nCtx, obj); Z3_sort_kind sk = (Z3_sort_kind)Native.Z3_get_sort_kind(ctx.nCtx, s); if (Native.Z3_is_algebraic_number(ctx.nCtx, obj) != 0) // is this a numeral ast? return new AlgebraicNum(ctx, obj); if (Native.Z3_is_numeral_ast(ctx.nCtx, obj) != 0) { switch (sk) { case Z3_sort_kind.Z3_INT_SORT: return new IntNum(ctx, obj); case Z3_sort_kind.Z3_REAL_SORT: return new RatNum(ctx, obj); case Z3_sort_kind.Z3_BV_SORT: return new BitVecNum(ctx, obj); } } switch (sk) { case Z3_sort_kind.Z3_BOOL_SORT: return new BoolExpr(ctx, obj); case Z3_sort_kind.Z3_INT_SORT: return new IntExpr(ctx, obj); case Z3_sort_kind.Z3_REAL_SORT: return new RealExpr(ctx, obj); case Z3_sort_kind.Z3_BV_SORT: return new BitVecExpr(ctx, obj); case Z3_sort_kind.Z3_ARRAY_SORT: return new ArrayExpr(ctx, obj); case Z3_sort_kind.Z3_DATATYPE_SORT: return new DatatypeExpr(ctx, obj); } return new Expr(ctx, obj); } #endregion } /// /// Boolean expressions /// public class BoolExpr : Expr { #region Internal /// Constructor for BoolExpr internal protected BoolExpr(Context ctx) : base(ctx) { Contract.Requires(ctx != null); } /// Constructor for BoolExpr internal BoolExpr(Context ctx, IntPtr obj) : base(ctx, obj) { Contract.Requires(ctx != null); } #endregion } /// /// Arithmetic expressions (int/real) /// public class ArithExpr : Expr { #region Internal /// Constructor for ArithExpr internal protected ArithExpr(Context ctx) : base(ctx) { Contract.Requires(ctx != null); } internal ArithExpr(Context ctx, IntPtr obj) : base(ctx, obj) { Contract.Requires(ctx != null); } #endregion } /// /// Int expressions /// public class IntExpr : ArithExpr { #region Internal /// Constructor for IntExpr internal protected IntExpr(Context ctx) : base(ctx) { Contract.Requires(ctx != null); } internal IntExpr(Context ctx, IntPtr obj) : base(ctx, obj) { Contract.Requires(ctx != null); } #endregion } /// /// Real expressions /// public class RealExpr : ArithExpr { #region Internal /// Constructor for RealExpr internal protected RealExpr(Context ctx) : base(ctx) { Contract.Requires(ctx != null); } internal RealExpr(Context ctx, IntPtr obj) : base(ctx, obj) { Contract.Requires(ctx != null); } #endregion } /// /// Bit-vector expressions /// public class BitVecExpr : Expr { /// /// The size of the sort of a bit-vector term. /// public uint SortSize { get { return ((BitVecSort)Sort).Size; } } #region Internal /// Constructor for BitVecExpr internal protected BitVecExpr(Context ctx) : base(ctx) { Contract.Requires(ctx != null); } internal BitVecExpr(Context ctx, IntPtr obj) : base(ctx, obj) { Contract.Requires(ctx != null); } #endregion } /// /// Array expressions /// public class ArrayExpr : Expr { #region Internal /// Constructor for ArrayExpr internal protected ArrayExpr(Context ctx) : base(ctx) { Contract.Requires(ctx != null); } internal ArrayExpr(Context ctx, IntPtr obj) : base(ctx, obj) { Contract.Requires(ctx != null); } #endregion } /// /// Datatype expressions /// public class DatatypeExpr : Expr { #region Internal /// Constructor for DatatypeExpr internal protected DatatypeExpr(Context ctx) : base(ctx) { Contract.Requires(ctx != null); } internal DatatypeExpr(Context ctx, IntPtr obj) : base(ctx, obj) { Contract.Requires(ctx != null); } #endregion } }