/*++ Copyright (c) 2024 Microsoft Corporation Module Name: RCFNum.cs Abstract: Z3 Managed API: Real Closed Field (RCF) Numerals Author: GitHub Copilot 2024-01-12 Notes: --*/ using System.Diagnostics; using System; namespace Microsoft.Z3 { /// /// Real Closed Field (RCF) numerals. /// /// RCF numerals can represent: /// - Rational numbers /// - Algebraic numbers (roots of polynomials) /// - Transcendental extensions (e.g., pi, e) /// - Infinitesimal extensions /// public class RCFNum : Z3Object { /// /// Create an RCF numeral from a rational string. /// /// Z3 context /// String representation of a rational number (e.g., "3/2", "0.5", "42") public RCFNum(Context ctx, string value) : base(ctx, Native.Z3_rcf_mk_rational(ctx.nCtx, value)) { Debug.Assert(ctx != null); } /// /// Create an RCF numeral from a small integer. /// /// Z3 context /// Integer value public RCFNum(Context ctx, int value) : base(ctx, Native.Z3_rcf_mk_small_int(ctx.nCtx, value)) { Debug.Assert(ctx != null); } /// /// Internal constructor for wrapping native RCF numeral pointers. /// internal RCFNum(Context ctx, IntPtr obj) : base(ctx, obj) { Debug.Assert(ctx != null); } /// /// Create an RCF numeral representing pi. /// /// Z3 context /// RCF numeral for pi public static RCFNum MkPi(Context ctx) { return new RCFNum(ctx, Native.Z3_rcf_mk_pi(ctx.nCtx)); } /// /// Create an RCF numeral representing e (Euler's constant). /// /// Z3 context /// RCF numeral for e public static RCFNum MkE(Context ctx) { return new RCFNum(ctx, Native.Z3_rcf_mk_e(ctx.nCtx)); } /// /// Create an RCF numeral representing an infinitesimal. /// /// Z3 context /// RCF numeral for an infinitesimal public static RCFNum MkInfinitesimal(Context ctx) { return new RCFNum(ctx, Native.Z3_rcf_mk_infinitesimal(ctx.nCtx)); } /// /// Find roots of a polynomial. /// /// The polynomial is a[n-1]*x^(n-1) + ... + a[1]*x + a[0]. /// /// Z3 context /// Polynomial coefficients (constant term first) /// Array of RCF numerals representing the roots public static RCFNum[] MkRoots(Context ctx, RCFNum[] coefficients) { if (coefficients == null || coefficients.Length == 0) { throw new Z3Exception("Polynomial coefficients cannot be empty"); } uint n = (uint)coefficients.Length; IntPtr[] a = new IntPtr[n]; IntPtr[] roots = new IntPtr[n]; for (uint i = 0; i < n; i++) { a[i] = coefficients[i].NativeObject; } uint numRoots = Native.Z3_rcf_mk_roots(ctx.nCtx, n, a, roots); RCFNum[] result = new RCFNum[numRoots]; for (uint i = 0; i < numRoots; i++) { result[i] = new RCFNum(ctx, roots[i]); } return result; } /// /// Add two RCF numerals. /// /// The RCF numeral to add /// this + other public RCFNum Add(RCFNum other) { CheckContext(other); return new RCFNum(Context, Native.Z3_rcf_add(Context.nCtx, NativeObject, other.NativeObject)); } /// /// Subtract two RCF numerals. /// /// The RCF numeral to subtract /// this - other public RCFNum Sub(RCFNum other) { CheckContext(other); return new RCFNum(Context, Native.Z3_rcf_sub(Context.nCtx, NativeObject, other.NativeObject)); } /// /// Multiply two RCF numerals. /// /// The RCF numeral to multiply /// this * other public RCFNum Mul(RCFNum other) { CheckContext(other); return new RCFNum(Context, Native.Z3_rcf_mul(Context.nCtx, NativeObject, other.NativeObject)); } /// /// Divide two RCF numerals. /// /// The RCF numeral to divide by /// this / other public RCFNum Div(RCFNum other) { CheckContext(other); return new RCFNum(Context, Native.Z3_rcf_div(Context.nCtx, NativeObject, other.NativeObject)); } /// /// Negate this RCF numeral. /// /// -this public RCFNum Neg() { return new RCFNum(Context, Native.Z3_rcf_neg(Context.nCtx, NativeObject)); } /// /// Compute the multiplicative inverse. /// /// 1/this public RCFNum Inv() { return new RCFNum(Context, Native.Z3_rcf_inv(Context.nCtx, NativeObject)); } /// /// Raise this RCF numeral to a power. /// /// The exponent /// this^k public RCFNum Power(uint k) { return new RCFNum(Context, Native.Z3_rcf_power(Context.nCtx, NativeObject, k)); } /// /// Operator overload for addition. /// public static RCFNum operator +(RCFNum a, RCFNum b) { return a.Add(b); } /// /// Operator overload for subtraction. /// public static RCFNum operator -(RCFNum a, RCFNum b) { return a.Sub(b); } /// /// Operator overload for multiplication. /// public static RCFNum operator *(RCFNum a, RCFNum b) { return a.Mul(b); } /// /// Operator overload for division. /// public static RCFNum operator /(RCFNum a, RCFNum b) { return a.Div(b); } /// /// Operator overload for negation. /// public static RCFNum operator -(RCFNum a) { return a.Neg(); } /// /// Check if this RCF numeral is less than another. /// /// The RCF numeral to compare with /// true if this < other public bool Lt(RCFNum other) { CheckContext(other); return 0 != Native.Z3_rcf_lt(Context.nCtx, NativeObject, other.NativeObject); } /// /// Check if this RCF numeral is greater than another. /// /// The RCF numeral to compare with /// true if this > other public bool Gt(RCFNum other) { CheckContext(other); return 0 != Native.Z3_rcf_gt(Context.nCtx, NativeObject, other.NativeObject); } /// /// Check if this RCF numeral is less than or equal to another. /// /// The RCF numeral to compare with /// true if this <= other public bool Le(RCFNum other) { CheckContext(other); return 0 != Native.Z3_rcf_le(Context.nCtx, NativeObject, other.NativeObject); } /// /// Check if this RCF numeral is greater than or equal to another. /// /// The RCF numeral to compare with /// true if this >= other public bool Ge(RCFNum other) { CheckContext(other); return 0 != Native.Z3_rcf_ge(Context.nCtx, NativeObject, other.NativeObject); } /// /// Check if this RCF numeral is equal to another. /// /// The RCF numeral to compare with /// true if this == other public bool Eq(RCFNum other) { CheckContext(other); return 0 != Native.Z3_rcf_eq(Context.nCtx, NativeObject, other.NativeObject); } /// /// Check if this RCF numeral is not equal to another. /// /// The RCF numeral to compare with /// true if this != other public bool Neq(RCFNum other) { CheckContext(other); return 0 != Native.Z3_rcf_neq(Context.nCtx, NativeObject, other.NativeObject); } /// /// Operator overload for less than. /// public static bool operator <(RCFNum a, RCFNum b) { return a.Lt(b); } /// /// Operator overload for greater than. /// public static bool operator >(RCFNum a, RCFNum b) { return a.Gt(b); } /// /// Operator overload for less than or equal. /// public static bool operator <=(RCFNum a, RCFNum b) { return a.Le(b); } /// /// Operator overload for greater than or equal. /// public static bool operator >=(RCFNum a, RCFNum b) { return a.Ge(b); } /// /// Operator overload for equality. /// public static bool operator ==(RCFNum a, RCFNum b) { if (ReferenceEquals(a, b)) return true; if (ReferenceEquals(a, null) || ReferenceEquals(b, null)) return false; return a.Eq(b); } /// /// Operator overload for inequality. /// public static bool operator !=(RCFNum a, RCFNum b) { return !(a == b); } /// /// Check if this RCF numeral is a rational number. /// /// true if this is rational public bool IsRational() { return 0 != Native.Z3_rcf_is_rational(Context.nCtx, NativeObject); } /// /// Check if this RCF numeral is an algebraic number. /// /// true if this is algebraic public bool IsAlgebraic() { return 0 != Native.Z3_rcf_is_algebraic(Context.nCtx, NativeObject); } /// /// Check if this RCF numeral is an infinitesimal. /// /// true if this is infinitesimal public bool IsInfinitesimal() { return 0 != Native.Z3_rcf_is_infinitesimal(Context.nCtx, NativeObject); } /// /// Check if this RCF numeral is a transcendental number. /// /// true if this is transcendental public bool IsTranscendental() { return 0 != Native.Z3_rcf_is_transcendental(Context.nCtx, NativeObject); } /// /// Convert this RCF numeral to a string. /// /// If true, use compact representation /// String representation public string ToString(bool compact) { return Native.Z3_rcf_num_to_string(Context.nCtx, NativeObject, compact ? (byte)1 : (byte)0, 0); } /// /// Convert this RCF numeral to a string (non-compact). /// /// String representation public override string ToString() { return ToString(false); } /// /// Convert this RCF numeral to a decimal string. /// /// Number of decimal places /// Decimal string representation public string ToDecimal(uint precision) { return Native.Z3_rcf_num_to_decimal_string(Context.nCtx, NativeObject, precision); } /// /// Override Equals for proper equality semantics. /// public override bool Equals(object obj) { if (obj is RCFNum other) { return this == other; } return false; } /// /// Override GetHashCode for proper equality semantics. /// public override int GetHashCode() { return NativeObject.GetHashCode(); } #region Internal internal override void DecRef(IntPtr o) { Native.Z3_rcf_del(Context.nCtx, o); } private void CheckContext(RCFNum other) { if (Context != other.Context) { throw new Z3Exception("RCF numerals from different contexts"); } } #endregion } }