/*++
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
}
}