mirror of
https://github.com/Z3Prover/z3
synced 2026-01-19 08:43:18 +00:00
Add RCF (Real Closed Field) bindings to C++, Java, C#, and TypeScript (#8171)
* Initial plan * Add RCF (Real Closed Field) bindings to C++ API Co-authored-by: NikolajBjorner <3085284+NikolajBjorner@users.noreply.github.com> * Add RCF (Real Closed Field) bindings to Java API Co-authored-by: NikolajBjorner <3085284+NikolajBjorner@users.noreply.github.com> * Add RCF (Real Closed Field) bindings to C# (.NET) API Co-authored-by: NikolajBjorner <3085284+NikolajBjorner@users.noreply.github.com> * Add RCF (Real Closed Field) example for TypeScript/JavaScript API Co-authored-by: NikolajBjorner <3085284+NikolajBjorner@users.noreply.github.com> * Add comprehensive RCF implementation summary documentation Co-authored-by: NikolajBjorner <3085284+NikolajBjorner@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: NikolajBjorner <3085284+NikolajBjorner@users.noreply.github.com>
This commit is contained in:
parent
cfd40d2588
commit
bd0eba812d
8 changed files with 1874 additions and 0 deletions
|
|
@ -26,6 +26,7 @@ Notes:
|
|||
#include<memory>
|
||||
#include<vector>
|
||||
#include<z3.h>
|
||||
#include<z3_rcf.h>
|
||||
#include<limits.h>
|
||||
#include<functional>
|
||||
|
||||
|
|
@ -4760,6 +4761,223 @@ namespace z3 {
|
|||
}
|
||||
};
|
||||
|
||||
/**
|
||||
\brief Wrapper for 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
|
||||
*/
|
||||
class rcf_num {
|
||||
Z3_context m_ctx;
|
||||
Z3_rcf_num m_num;
|
||||
|
||||
void check_context(rcf_num const& other) const {
|
||||
if (m_ctx != other.m_ctx) {
|
||||
throw exception("rcf_num objects from different contexts");
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
rcf_num(context& c, Z3_rcf_num n): m_ctx(c), m_num(n) {}
|
||||
|
||||
rcf_num(context& c, int val): m_ctx(c) {
|
||||
m_num = Z3_rcf_mk_small_int(c, val);
|
||||
}
|
||||
|
||||
rcf_num(context& c, char const* val): m_ctx(c) {
|
||||
m_num = Z3_rcf_mk_rational(c, val);
|
||||
}
|
||||
|
||||
rcf_num(rcf_num const& other): m_ctx(other.m_ctx) {
|
||||
// Create a copy by converting to string and back
|
||||
std::string str = Z3_rcf_num_to_string(m_ctx, other.m_num, false, false);
|
||||
m_num = Z3_rcf_mk_rational(m_ctx, str.c_str());
|
||||
}
|
||||
|
||||
rcf_num& operator=(rcf_num const& other) {
|
||||
if (this != &other) {
|
||||
Z3_rcf_del(m_ctx, m_num);
|
||||
m_ctx = other.m_ctx;
|
||||
std::string str = Z3_rcf_num_to_string(m_ctx, other.m_num, false, false);
|
||||
m_num = Z3_rcf_mk_rational(m_ctx, str.c_str());
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
~rcf_num() {
|
||||
Z3_rcf_del(m_ctx, m_num);
|
||||
}
|
||||
|
||||
operator Z3_rcf_num() const { return m_num; }
|
||||
Z3_context ctx() const { return m_ctx; }
|
||||
|
||||
/**
|
||||
\brief Return string representation of the RCF numeral.
|
||||
*/
|
||||
std::string to_string(bool compact = false) const {
|
||||
return std::string(Z3_rcf_num_to_string(m_ctx, m_num, compact, false));
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Return decimal string representation with given precision.
|
||||
*/
|
||||
std::string to_decimal(unsigned precision = 10) const {
|
||||
return std::string(Z3_rcf_num_to_decimal_string(m_ctx, m_num, precision));
|
||||
}
|
||||
|
||||
// Arithmetic operations
|
||||
rcf_num operator+(rcf_num const& other) const {
|
||||
check_context(other);
|
||||
return rcf_num(*const_cast<context*>(reinterpret_cast<context const*>(&m_ctx)),
|
||||
Z3_rcf_add(m_ctx, m_num, other.m_num));
|
||||
}
|
||||
|
||||
rcf_num operator-(rcf_num const& other) const {
|
||||
check_context(other);
|
||||
return rcf_num(*const_cast<context*>(reinterpret_cast<context const*>(&m_ctx)),
|
||||
Z3_rcf_sub(m_ctx, m_num, other.m_num));
|
||||
}
|
||||
|
||||
rcf_num operator*(rcf_num const& other) const {
|
||||
check_context(other);
|
||||
return rcf_num(*const_cast<context*>(reinterpret_cast<context const*>(&m_ctx)),
|
||||
Z3_rcf_mul(m_ctx, m_num, other.m_num));
|
||||
}
|
||||
|
||||
rcf_num operator/(rcf_num const& other) const {
|
||||
check_context(other);
|
||||
return rcf_num(*const_cast<context*>(reinterpret_cast<context const*>(&m_ctx)),
|
||||
Z3_rcf_div(m_ctx, m_num, other.m_num));
|
||||
}
|
||||
|
||||
rcf_num operator-() const {
|
||||
return rcf_num(*const_cast<context*>(reinterpret_cast<context const*>(&m_ctx)),
|
||||
Z3_rcf_neg(m_ctx, m_num));
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Return the power of this number raised to k.
|
||||
*/
|
||||
rcf_num power(unsigned k) const {
|
||||
return rcf_num(*const_cast<context*>(reinterpret_cast<context const*>(&m_ctx)),
|
||||
Z3_rcf_power(m_ctx, m_num, k));
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Return the multiplicative inverse (1/this).
|
||||
*/
|
||||
rcf_num inv() const {
|
||||
return rcf_num(*const_cast<context*>(reinterpret_cast<context const*>(&m_ctx)),
|
||||
Z3_rcf_inv(m_ctx, m_num));
|
||||
}
|
||||
|
||||
// Comparison operations
|
||||
bool operator<(rcf_num const& other) const {
|
||||
check_context(other);
|
||||
return Z3_rcf_lt(m_ctx, m_num, other.m_num);
|
||||
}
|
||||
|
||||
bool operator>(rcf_num const& other) const {
|
||||
check_context(other);
|
||||
return Z3_rcf_gt(m_ctx, m_num, other.m_num);
|
||||
}
|
||||
|
||||
bool operator<=(rcf_num const& other) const {
|
||||
check_context(other);
|
||||
return Z3_rcf_le(m_ctx, m_num, other.m_num);
|
||||
}
|
||||
|
||||
bool operator>=(rcf_num const& other) const {
|
||||
check_context(other);
|
||||
return Z3_rcf_ge(m_ctx, m_num, other.m_num);
|
||||
}
|
||||
|
||||
bool operator==(rcf_num const& other) const {
|
||||
check_context(other);
|
||||
return Z3_rcf_eq(m_ctx, m_num, other.m_num);
|
||||
}
|
||||
|
||||
bool operator!=(rcf_num const& other) const {
|
||||
check_context(other);
|
||||
return Z3_rcf_neq(m_ctx, m_num, other.m_num);
|
||||
}
|
||||
|
||||
// Type queries
|
||||
bool is_rational() const {
|
||||
return Z3_rcf_is_rational(m_ctx, m_num);
|
||||
}
|
||||
|
||||
bool is_algebraic() const {
|
||||
return Z3_rcf_is_algebraic(m_ctx, m_num);
|
||||
}
|
||||
|
||||
bool is_infinitesimal() const {
|
||||
return Z3_rcf_is_infinitesimal(m_ctx, m_num);
|
||||
}
|
||||
|
||||
bool is_transcendental() const {
|
||||
return Z3_rcf_is_transcendental(m_ctx, m_num);
|
||||
}
|
||||
|
||||
friend std::ostream& operator<<(std::ostream& out, rcf_num const& n) {
|
||||
return out << n.to_string();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
\brief Create an RCF numeral representing pi.
|
||||
*/
|
||||
inline rcf_num rcf_pi(context& c) {
|
||||
return rcf_num(c, Z3_rcf_mk_pi(c));
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Create an RCF numeral representing e (Euler's constant).
|
||||
*/
|
||||
inline rcf_num rcf_e(context& c) {
|
||||
return rcf_num(c, Z3_rcf_mk_e(c));
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Create an RCF numeral representing an infinitesimal.
|
||||
*/
|
||||
inline rcf_num rcf_infinitesimal(context& c) {
|
||||
return rcf_num(c, Z3_rcf_mk_infinitesimal(c));
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Find roots of a polynomial with given coefficients.
|
||||
|
||||
The polynomial is a[n-1]*x^(n-1) + ... + a[1]*x + a[0].
|
||||
Returns a vector of RCF numerals representing the roots.
|
||||
*/
|
||||
inline std::vector<rcf_num> rcf_roots(context& c, std::vector<rcf_num> const& coeffs) {
|
||||
if (coeffs.empty()) {
|
||||
throw exception("polynomial coefficients cannot be empty");
|
||||
}
|
||||
|
||||
unsigned n = static_cast<unsigned>(coeffs.size());
|
||||
std::vector<Z3_rcf_num> a(n);
|
||||
std::vector<Z3_rcf_num> roots(n);
|
||||
|
||||
for (unsigned i = 0; i < n; i++) {
|
||||
a[i] = coeffs[i];
|
||||
}
|
||||
|
||||
unsigned num_roots = Z3_rcf_mk_roots(c, n, a.data(), roots.data());
|
||||
|
||||
std::vector<rcf_num> result;
|
||||
result.reserve(num_roots);
|
||||
for (unsigned i = 0; i < num_roots; i++) {
|
||||
result.push_back(rcf_num(c, roots[i]));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**@}*/
|
||||
|
|
|
|||
459
src/api/dotnet/RCFNum.cs
Normal file
459
src/api/dotnet/RCFNum.cs
Normal file
|
|
@ -0,0 +1,459 @@
|
|||
/*++
|
||||
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
|
||||
{
|
||||
/// <summary>
|
||||
/// Real Closed Field (RCF) numerals.
|
||||
///
|
||||
/// RCF numerals can represent:
|
||||
/// - Rational numbers
|
||||
/// - Algebraic numbers (roots of polynomials)
|
||||
/// - Transcendental extensions (e.g., pi, e)
|
||||
/// - Infinitesimal extensions
|
||||
/// </summary>
|
||||
public class RCFNum : Z3Object
|
||||
{
|
||||
/// <summary>
|
||||
/// Create an RCF numeral from a rational string.
|
||||
/// </summary>
|
||||
/// <param name="ctx">Z3 context</param>
|
||||
/// <param name="value">String representation of a rational number (e.g., "3/2", "0.5", "42")</param>
|
||||
public RCFNum(Context ctx, string value)
|
||||
: base(ctx, Native.Z3_rcf_mk_rational(ctx.nCtx, value))
|
||||
{
|
||||
Debug.Assert(ctx != null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create an RCF numeral from a small integer.
|
||||
/// </summary>
|
||||
/// <param name="ctx">Z3 context</param>
|
||||
/// <param name="value">Integer value</param>
|
||||
public RCFNum(Context ctx, int value)
|
||||
: base(ctx, Native.Z3_rcf_mk_small_int(ctx.nCtx, value))
|
||||
{
|
||||
Debug.Assert(ctx != null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Internal constructor for wrapping native RCF numeral pointers.
|
||||
/// </summary>
|
||||
internal RCFNum(Context ctx, IntPtr obj)
|
||||
: base(ctx, obj)
|
||||
{
|
||||
Debug.Assert(ctx != null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create an RCF numeral representing pi.
|
||||
/// </summary>
|
||||
/// <param name="ctx">Z3 context</param>
|
||||
/// <returns>RCF numeral for pi</returns>
|
||||
public static RCFNum MkPi(Context ctx)
|
||||
{
|
||||
return new RCFNum(ctx, Native.Z3_rcf_mk_pi(ctx.nCtx));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create an RCF numeral representing e (Euler's constant).
|
||||
/// </summary>
|
||||
/// <param name="ctx">Z3 context</param>
|
||||
/// <returns>RCF numeral for e</returns>
|
||||
public static RCFNum MkE(Context ctx)
|
||||
{
|
||||
return new RCFNum(ctx, Native.Z3_rcf_mk_e(ctx.nCtx));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create an RCF numeral representing an infinitesimal.
|
||||
/// </summary>
|
||||
/// <param name="ctx">Z3 context</param>
|
||||
/// <returns>RCF numeral for an infinitesimal</returns>
|
||||
public static RCFNum MkInfinitesimal(Context ctx)
|
||||
{
|
||||
return new RCFNum(ctx, Native.Z3_rcf_mk_infinitesimal(ctx.nCtx));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Find roots of a polynomial.
|
||||
///
|
||||
/// The polynomial is a[n-1]*x^(n-1) + ... + a[1]*x + a[0].
|
||||
/// </summary>
|
||||
/// <param name="ctx">Z3 context</param>
|
||||
/// <param name="coefficients">Polynomial coefficients (constant term first)</param>
|
||||
/// <returns>Array of RCF numerals representing the roots</returns>
|
||||
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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add two RCF numerals.
|
||||
/// </summary>
|
||||
/// <param name="other">The RCF numeral to add</param>
|
||||
/// <returns>this + other</returns>
|
||||
public RCFNum Add(RCFNum other)
|
||||
{
|
||||
CheckContext(other);
|
||||
return new RCFNum(Context, Native.Z3_rcf_add(Context.nCtx, NativeObject, other.NativeObject));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Subtract two RCF numerals.
|
||||
/// </summary>
|
||||
/// <param name="other">The RCF numeral to subtract</param>
|
||||
/// <returns>this - other</returns>
|
||||
public RCFNum Sub(RCFNum other)
|
||||
{
|
||||
CheckContext(other);
|
||||
return new RCFNum(Context, Native.Z3_rcf_sub(Context.nCtx, NativeObject, other.NativeObject));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Multiply two RCF numerals.
|
||||
/// </summary>
|
||||
/// <param name="other">The RCF numeral to multiply</param>
|
||||
/// <returns>this * other</returns>
|
||||
public RCFNum Mul(RCFNum other)
|
||||
{
|
||||
CheckContext(other);
|
||||
return new RCFNum(Context, Native.Z3_rcf_mul(Context.nCtx, NativeObject, other.NativeObject));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Divide two RCF numerals.
|
||||
/// </summary>
|
||||
/// <param name="other">The RCF numeral to divide by</param>
|
||||
/// <returns>this / other</returns>
|
||||
public RCFNum Div(RCFNum other)
|
||||
{
|
||||
CheckContext(other);
|
||||
return new RCFNum(Context, Native.Z3_rcf_div(Context.nCtx, NativeObject, other.NativeObject));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Negate this RCF numeral.
|
||||
/// </summary>
|
||||
/// <returns>-this</returns>
|
||||
public RCFNum Neg()
|
||||
{
|
||||
return new RCFNum(Context, Native.Z3_rcf_neg(Context.nCtx, NativeObject));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Compute the multiplicative inverse.
|
||||
/// </summary>
|
||||
/// <returns>1/this</returns>
|
||||
public RCFNum Inv()
|
||||
{
|
||||
return new RCFNum(Context, Native.Z3_rcf_inv(Context.nCtx, NativeObject));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Raise this RCF numeral to a power.
|
||||
/// </summary>
|
||||
/// <param name="k">The exponent</param>
|
||||
/// <returns>this^k</returns>
|
||||
public RCFNum Power(uint k)
|
||||
{
|
||||
return new RCFNum(Context, Native.Z3_rcf_power(Context.nCtx, NativeObject, k));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Operator overload for addition.
|
||||
/// </summary>
|
||||
public static RCFNum operator +(RCFNum a, RCFNum b)
|
||||
{
|
||||
return a.Add(b);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Operator overload for subtraction.
|
||||
/// </summary>
|
||||
public static RCFNum operator -(RCFNum a, RCFNum b)
|
||||
{
|
||||
return a.Sub(b);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Operator overload for multiplication.
|
||||
/// </summary>
|
||||
public static RCFNum operator *(RCFNum a, RCFNum b)
|
||||
{
|
||||
return a.Mul(b);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Operator overload for division.
|
||||
/// </summary>
|
||||
public static RCFNum operator /(RCFNum a, RCFNum b)
|
||||
{
|
||||
return a.Div(b);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Operator overload for negation.
|
||||
/// </summary>
|
||||
public static RCFNum operator -(RCFNum a)
|
||||
{
|
||||
return a.Neg();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check if this RCF numeral is less than another.
|
||||
/// </summary>
|
||||
/// <param name="other">The RCF numeral to compare with</param>
|
||||
/// <returns>true if this < other</returns>
|
||||
public bool Lt(RCFNum other)
|
||||
{
|
||||
CheckContext(other);
|
||||
return Native.Z3_rcf_lt(Context.nCtx, NativeObject, other.NativeObject);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check if this RCF numeral is greater than another.
|
||||
/// </summary>
|
||||
/// <param name="other">The RCF numeral to compare with</param>
|
||||
/// <returns>true if this > other</returns>
|
||||
public bool Gt(RCFNum other)
|
||||
{
|
||||
CheckContext(other);
|
||||
return Native.Z3_rcf_gt(Context.nCtx, NativeObject, other.NativeObject);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check if this RCF numeral is less than or equal to another.
|
||||
/// </summary>
|
||||
/// <param name="other">The RCF numeral to compare with</param>
|
||||
/// <returns>true if this <= other</returns>
|
||||
public bool Le(RCFNum other)
|
||||
{
|
||||
CheckContext(other);
|
||||
return Native.Z3_rcf_le(Context.nCtx, NativeObject, other.NativeObject);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check if this RCF numeral is greater than or equal to another.
|
||||
/// </summary>
|
||||
/// <param name="other">The RCF numeral to compare with</param>
|
||||
/// <returns>true if this >= other</returns>
|
||||
public bool Ge(RCFNum other)
|
||||
{
|
||||
CheckContext(other);
|
||||
return Native.Z3_rcf_ge(Context.nCtx, NativeObject, other.NativeObject);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check if this RCF numeral is equal to another.
|
||||
/// </summary>
|
||||
/// <param name="other">The RCF numeral to compare with</param>
|
||||
/// <returns>true if this == other</returns>
|
||||
public bool Eq(RCFNum other)
|
||||
{
|
||||
CheckContext(other);
|
||||
return Native.Z3_rcf_eq(Context.nCtx, NativeObject, other.NativeObject);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check if this RCF numeral is not equal to another.
|
||||
/// </summary>
|
||||
/// <param name="other">The RCF numeral to compare with</param>
|
||||
/// <returns>true if this != other</returns>
|
||||
public bool Neq(RCFNum other)
|
||||
{
|
||||
CheckContext(other);
|
||||
return Native.Z3_rcf_neq(Context.nCtx, NativeObject, other.NativeObject);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Operator overload for less than.
|
||||
/// </summary>
|
||||
public static bool operator <(RCFNum a, RCFNum b)
|
||||
{
|
||||
return a.Lt(b);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Operator overload for greater than.
|
||||
/// </summary>
|
||||
public static bool operator >(RCFNum a, RCFNum b)
|
||||
{
|
||||
return a.Gt(b);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Operator overload for less than or equal.
|
||||
/// </summary>
|
||||
public static bool operator <=(RCFNum a, RCFNum b)
|
||||
{
|
||||
return a.Le(b);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Operator overload for greater than or equal.
|
||||
/// </summary>
|
||||
public static bool operator >=(RCFNum a, RCFNum b)
|
||||
{
|
||||
return a.Ge(b);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Operator overload for equality.
|
||||
/// </summary>
|
||||
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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Operator overload for inequality.
|
||||
/// </summary>
|
||||
public static bool operator !=(RCFNum a, RCFNum b)
|
||||
{
|
||||
return !(a == b);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check if this RCF numeral is a rational number.
|
||||
/// </summary>
|
||||
/// <returns>true if this is rational</returns>
|
||||
public bool IsRational()
|
||||
{
|
||||
return Native.Z3_rcf_is_rational(Context.nCtx, NativeObject);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check if this RCF numeral is an algebraic number.
|
||||
/// </summary>
|
||||
/// <returns>true if this is algebraic</returns>
|
||||
public bool IsAlgebraic()
|
||||
{
|
||||
return Native.Z3_rcf_is_algebraic(Context.nCtx, NativeObject);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check if this RCF numeral is an infinitesimal.
|
||||
/// </summary>
|
||||
/// <returns>true if this is infinitesimal</returns>
|
||||
public bool IsInfinitesimal()
|
||||
{
|
||||
return Native.Z3_rcf_is_infinitesimal(Context.nCtx, NativeObject);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check if this RCF numeral is a transcendental number.
|
||||
/// </summary>
|
||||
/// <returns>true if this is transcendental</returns>
|
||||
public bool IsTranscendental()
|
||||
{
|
||||
return Native.Z3_rcf_is_transcendental(Context.nCtx, NativeObject);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Convert this RCF numeral to a string.
|
||||
/// </summary>
|
||||
/// <param name="compact">If true, use compact representation</param>
|
||||
/// <returns>String representation</returns>
|
||||
public string ToString(bool compact)
|
||||
{
|
||||
return Native.Z3_rcf_num_to_string(Context.nCtx, NativeObject, compact, false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Convert this RCF numeral to a string (non-compact).
|
||||
/// </summary>
|
||||
/// <returns>String representation</returns>
|
||||
public override string ToString()
|
||||
{
|
||||
return ToString(false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Convert this RCF numeral to a decimal string.
|
||||
/// </summary>
|
||||
/// <param name="precision">Number of decimal places</param>
|
||||
/// <returns>Decimal string representation</returns>
|
||||
public string ToDecimal(uint precision)
|
||||
{
|
||||
return Native.Z3_rcf_num_to_decimal_string(Context.nCtx, NativeObject, precision);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Override Equals for proper equality semantics.
|
||||
/// </summary>
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (obj is RCFNum other)
|
||||
{
|
||||
return this == other;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Override GetHashCode for proper equality semantics.
|
||||
/// </summary>
|
||||
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
|
||||
}
|
||||
}
|
||||
374
src/api/java/RCFNum.java
Normal file
374
src/api/java/RCFNum.java
Normal file
|
|
@ -0,0 +1,374 @@
|
|||
/**
|
||||
Copyright (c) 2024 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
RCFNum.java
|
||||
|
||||
Abstract:
|
||||
|
||||
Real Closed Field (RCF) numerals
|
||||
|
||||
Author:
|
||||
|
||||
GitHub Copilot 2024-01-12
|
||||
|
||||
Notes:
|
||||
|
||||
**/
|
||||
|
||||
package com.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 extends Z3Object {
|
||||
|
||||
/**
|
||||
* Create an RCF numeral from a rational string.
|
||||
* @param ctx Z3 context
|
||||
* @param value String representation of a rational number (e.g., "3/2", "0.5", "42")
|
||||
* @throws Z3Exception on error
|
||||
**/
|
||||
public RCFNum(Context ctx, String value) {
|
||||
super(ctx, Native.rcfMkRational(ctx.nCtx(), value));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an RCF numeral from a small integer.
|
||||
* @param ctx Z3 context
|
||||
* @param value Integer value
|
||||
* @throws Z3Exception on error
|
||||
**/
|
||||
public RCFNum(Context ctx, int value) {
|
||||
super(ctx, Native.rcfMkSmallInt(ctx.nCtx(), value));
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal constructor for wrapping native RCF numeral pointers.
|
||||
**/
|
||||
RCFNum(Context ctx, long obj) {
|
||||
super(ctx, obj);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an RCF numeral representing pi.
|
||||
* @param ctx Z3 context
|
||||
* @return RCF numeral for pi
|
||||
* @throws Z3Exception on error
|
||||
**/
|
||||
public static RCFNum mkPi(Context ctx) {
|
||||
return new RCFNum(ctx, Native.rcfMkPi(ctx.nCtx()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an RCF numeral representing e (Euler's constant).
|
||||
* @param ctx Z3 context
|
||||
* @return RCF numeral for e
|
||||
* @throws Z3Exception on error
|
||||
**/
|
||||
public static RCFNum mkE(Context ctx) {
|
||||
return new RCFNum(ctx, Native.rcfMkE(ctx.nCtx()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an RCF numeral representing an infinitesimal.
|
||||
* @param ctx Z3 context
|
||||
* @return RCF numeral for an infinitesimal
|
||||
* @throws Z3Exception on error
|
||||
**/
|
||||
public static RCFNum mkInfinitesimal(Context ctx) {
|
||||
return new RCFNum(ctx, Native.rcfMkInfinitesimal(ctx.nCtx()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Find roots of a polynomial.
|
||||
*
|
||||
* The polynomial is a[n-1]*x^(n-1) + ... + a[1]*x + a[0].
|
||||
*
|
||||
* @param ctx Z3 context
|
||||
* @param coefficients Polynomial coefficients (constant term first)
|
||||
* @return Array of RCF numerals representing the roots
|
||||
* @throws Z3Exception on error
|
||||
**/
|
||||
public static RCFNum[] mkRoots(Context ctx, RCFNum[] coefficients) {
|
||||
if (coefficients == null || coefficients.length == 0) {
|
||||
throw new Z3Exception("Polynomial coefficients cannot be empty");
|
||||
}
|
||||
|
||||
int n = coefficients.length;
|
||||
long[] a = new long[n];
|
||||
long[] roots = new long[n];
|
||||
|
||||
for (int i = 0; i < n; i++) {
|
||||
a[i] = coefficients[i].getNativeObject();
|
||||
}
|
||||
|
||||
int numRoots = Native.rcfMkRoots(ctx.nCtx(), n, a, roots);
|
||||
|
||||
RCFNum[] result = new RCFNum[numRoots];
|
||||
for (int i = 0; i < numRoots; i++) {
|
||||
result[i] = new RCFNum(ctx, roots[i]);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add two RCF numerals.
|
||||
* @param other The RCF numeral to add
|
||||
* @return this + other
|
||||
* @throws Z3Exception on error
|
||||
**/
|
||||
public RCFNum add(RCFNum other) {
|
||||
checkContext(other);
|
||||
return new RCFNum(getContext(), Native.rcfAdd(getContext().nCtx(),
|
||||
getNativeObject(),
|
||||
other.getNativeObject()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Subtract two RCF numerals.
|
||||
* @param other The RCF numeral to subtract
|
||||
* @return this - other
|
||||
* @throws Z3Exception on error
|
||||
**/
|
||||
public RCFNum sub(RCFNum other) {
|
||||
checkContext(other);
|
||||
return new RCFNum(getContext(), Native.rcfSub(getContext().nCtx(),
|
||||
getNativeObject(),
|
||||
other.getNativeObject()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Multiply two RCF numerals.
|
||||
* @param other The RCF numeral to multiply
|
||||
* @return this * other
|
||||
* @throws Z3Exception on error
|
||||
**/
|
||||
public RCFNum mul(RCFNum other) {
|
||||
checkContext(other);
|
||||
return new RCFNum(getContext(), Native.rcfMul(getContext().nCtx(),
|
||||
getNativeObject(),
|
||||
other.getNativeObject()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Divide two RCF numerals.
|
||||
* @param other The RCF numeral to divide by
|
||||
* @return this / other
|
||||
* @throws Z3Exception on error
|
||||
**/
|
||||
public RCFNum div(RCFNum other) {
|
||||
checkContext(other);
|
||||
return new RCFNum(getContext(), Native.rcfDiv(getContext().nCtx(),
|
||||
getNativeObject(),
|
||||
other.getNativeObject()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Negate this RCF numeral.
|
||||
* @return -this
|
||||
* @throws Z3Exception on error
|
||||
**/
|
||||
public RCFNum neg() {
|
||||
return new RCFNum(getContext(), Native.rcfNeg(getContext().nCtx(),
|
||||
getNativeObject()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute the multiplicative inverse.
|
||||
* @return 1/this
|
||||
* @throws Z3Exception on error
|
||||
**/
|
||||
public RCFNum inv() {
|
||||
return new RCFNum(getContext(), Native.rcfInv(getContext().nCtx(),
|
||||
getNativeObject()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Raise this RCF numeral to a power.
|
||||
* @param k The exponent
|
||||
* @return this^k
|
||||
* @throws Z3Exception on error
|
||||
**/
|
||||
public RCFNum power(int k) {
|
||||
return new RCFNum(getContext(), Native.rcfPower(getContext().nCtx(),
|
||||
getNativeObject(), k));
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if this RCF numeral is less than another.
|
||||
* @param other The RCF numeral to compare with
|
||||
* @return true if this < other
|
||||
* @throws Z3Exception on error
|
||||
**/
|
||||
public boolean lt(RCFNum other) {
|
||||
checkContext(other);
|
||||
return Native.rcfLt(getContext().nCtx(), getNativeObject(),
|
||||
other.getNativeObject());
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if this RCF numeral is greater than another.
|
||||
* @param other The RCF numeral to compare with
|
||||
* @return true if this > other
|
||||
* @throws Z3Exception on error
|
||||
**/
|
||||
public boolean gt(RCFNum other) {
|
||||
checkContext(other);
|
||||
return Native.rcfGt(getContext().nCtx(), getNativeObject(),
|
||||
other.getNativeObject());
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if this RCF numeral is less than or equal to another.
|
||||
* @param other The RCF numeral to compare with
|
||||
* @return true if this <= other
|
||||
* @throws Z3Exception on error
|
||||
**/
|
||||
public boolean le(RCFNum other) {
|
||||
checkContext(other);
|
||||
return Native.rcfLe(getContext().nCtx(), getNativeObject(),
|
||||
other.getNativeObject());
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if this RCF numeral is greater than or equal to another.
|
||||
* @param other The RCF numeral to compare with
|
||||
* @return true if this >= other
|
||||
* @throws Z3Exception on error
|
||||
**/
|
||||
public boolean ge(RCFNum other) {
|
||||
checkContext(other);
|
||||
return Native.rcfGe(getContext().nCtx(), getNativeObject(),
|
||||
other.getNativeObject());
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if this RCF numeral is equal to another.
|
||||
* @param other The RCF numeral to compare with
|
||||
* @return true if this == other
|
||||
* @throws Z3Exception on error
|
||||
**/
|
||||
public boolean eq(RCFNum other) {
|
||||
checkContext(other);
|
||||
return Native.rcfEq(getContext().nCtx(), getNativeObject(),
|
||||
other.getNativeObject());
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if this RCF numeral is not equal to another.
|
||||
* @param other The RCF numeral to compare with
|
||||
* @return true if this != other
|
||||
* @throws Z3Exception on error
|
||||
**/
|
||||
public boolean neq(RCFNum other) {
|
||||
checkContext(other);
|
||||
return Native.rcfNeq(getContext().nCtx(), getNativeObject(),
|
||||
other.getNativeObject());
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if this RCF numeral is a rational number.
|
||||
* @return true if this is rational
|
||||
* @throws Z3Exception on error
|
||||
**/
|
||||
public boolean isRational() {
|
||||
return Native.rcfIsRational(getContext().nCtx(), getNativeObject());
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if this RCF numeral is an algebraic number.
|
||||
* @return true if this is algebraic
|
||||
* @throws Z3Exception on error
|
||||
**/
|
||||
public boolean isAlgebraic() {
|
||||
return Native.rcfIsAlgebraic(getContext().nCtx(), getNativeObject());
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if this RCF numeral is an infinitesimal.
|
||||
* @return true if this is infinitesimal
|
||||
* @throws Z3Exception on error
|
||||
**/
|
||||
public boolean isInfinitesimal() {
|
||||
return Native.rcfIsInfinitesimal(getContext().nCtx(), getNativeObject());
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if this RCF numeral is a transcendental number.
|
||||
* @return true if this is transcendental
|
||||
* @throws Z3Exception on error
|
||||
**/
|
||||
public boolean isTranscendental() {
|
||||
return Native.rcfIsTranscendental(getContext().nCtx(), getNativeObject());
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert this RCF numeral to a string.
|
||||
* @param compact If true, use compact representation
|
||||
* @return String representation
|
||||
* @throws Z3Exception on error
|
||||
**/
|
||||
public String toString(boolean compact) {
|
||||
return Native.rcfNumToString(getContext().nCtx(), getNativeObject(),
|
||||
compact, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert this RCF numeral to a string (non-compact).
|
||||
* @return String representation
|
||||
* @throws Z3Exception on error
|
||||
**/
|
||||
@Override
|
||||
public String toString() {
|
||||
return toString(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert this RCF numeral to a decimal string.
|
||||
* @param precision Number of decimal places
|
||||
* @return Decimal string representation
|
||||
* @throws Z3Exception on error
|
||||
**/
|
||||
public String toDecimal(int precision) {
|
||||
return Native.rcfNumToDecimalString(getContext().nCtx(),
|
||||
getNativeObject(), precision);
|
||||
}
|
||||
|
||||
@Override
|
||||
void incRef() {
|
||||
// RCF numerals don't use standard reference counting
|
||||
// They are managed through Z3_rcf_del
|
||||
}
|
||||
|
||||
@Override
|
||||
void addToReferenceQueue() {
|
||||
getContext().getReferenceQueue().storeReference(this, RCFNumRef::new);
|
||||
}
|
||||
|
||||
private static class RCFNumRef extends Z3ReferenceQueue.Reference<RCFNum> {
|
||||
|
||||
private RCFNumRef(RCFNum referent, java.lang.ref.ReferenceQueue<Z3Object> q) {
|
||||
super(referent, q);
|
||||
}
|
||||
|
||||
@Override
|
||||
void decRef(Context ctx, long z3Obj) {
|
||||
Native.rcfDel(ctx.nCtx(), z3Obj);
|
||||
}
|
||||
}
|
||||
|
||||
private void checkContext(RCFNum other) {
|
||||
if (getContext() != other.getContext()) {
|
||||
throw new Z3Exception("RCF numerals from different contexts");
|
||||
}
|
||||
}
|
||||
}
|
||||
165
src/api/js/examples/low-level/rcf-example.ts
Normal file
165
src/api/js/examples/low-level/rcf-example.ts
Normal file
|
|
@ -0,0 +1,165 @@
|
|||
/**
|
||||
* Example demonstrating the RCF (Real Closed Field) API in TypeScript.
|
||||
*
|
||||
* This example shows how to use RCF numerals to work with:
|
||||
* - Transcendental numbers (pi, e)
|
||||
* - Algebraic numbers (roots of polynomials)
|
||||
* - Infinitesimals
|
||||
* - Exact real arithmetic
|
||||
*
|
||||
* Note: The RCF API is exposed at the low-level API layer.
|
||||
* Import from 'z3-solver' for low-level access.
|
||||
*/
|
||||
|
||||
import { init } from 'z3-solver';
|
||||
|
||||
async function rcfBasicExample() {
|
||||
console.log('RCF Basic Example');
|
||||
console.log('=================');
|
||||
|
||||
const { Z3 } = await init();
|
||||
const ctx = Z3.mk_context_rc(Z3.mk_config());
|
||||
|
||||
try {
|
||||
// Create pi and e
|
||||
const pi = Z3.rcf_mk_pi(ctx);
|
||||
const e = Z3.rcf_mk_e(ctx);
|
||||
|
||||
console.log('pi =', Z3.rcf_num_to_string(ctx, pi, false, false));
|
||||
console.log('e =', Z3.rcf_num_to_string(ctx, e, false, false));
|
||||
|
||||
// Arithmetic operations
|
||||
const sum = Z3.rcf_add(ctx, pi, e);
|
||||
const prod = Z3.rcf_mul(ctx, pi, e);
|
||||
|
||||
console.log('pi + e =', Z3.rcf_num_to_string(ctx, sum, false, false));
|
||||
console.log('pi * e =', Z3.rcf_num_to_string(ctx, prod, false, false));
|
||||
|
||||
// Decimal approximations
|
||||
console.log('pi (10 decimals) =', Z3.rcf_num_to_decimal_string(ctx, pi, 10));
|
||||
console.log('e (10 decimals) =', Z3.rcf_num_to_decimal_string(ctx, e, 10));
|
||||
|
||||
// Comparisons
|
||||
console.log('pi < e?', Z3.rcf_lt(ctx, pi, e) ? 'yes' : 'no');
|
||||
console.log('pi > e?', Z3.rcf_gt(ctx, pi, e) ? 'yes' : 'no');
|
||||
|
||||
// Cleanup
|
||||
Z3.rcf_del(ctx, pi);
|
||||
Z3.rcf_del(ctx, e);
|
||||
Z3.rcf_del(ctx, sum);
|
||||
Z3.rcf_del(ctx, prod);
|
||||
} finally {
|
||||
Z3.del_context(ctx);
|
||||
}
|
||||
}
|
||||
|
||||
async function rcfRationalExample() {
|
||||
console.log('\nRCF Rational Example');
|
||||
console.log('====================');
|
||||
|
||||
const { Z3 } = await init();
|
||||
const ctx = Z3.mk_context_rc(Z3.mk_config());
|
||||
|
||||
try {
|
||||
// Create rational numbers
|
||||
const half = Z3.rcf_mk_rational(ctx, '1/2');
|
||||
const third = Z3.rcf_mk_rational(ctx, '1/3');
|
||||
|
||||
console.log('1/2 =', Z3.rcf_num_to_string(ctx, half, false, false));
|
||||
console.log('1/3 =', Z3.rcf_num_to_string(ctx, third, false, false));
|
||||
|
||||
// Arithmetic
|
||||
const sum = Z3.rcf_add(ctx, half, third);
|
||||
console.log('1/2 + 1/3 =', Z3.rcf_num_to_string(ctx, sum, false, false));
|
||||
|
||||
// Type queries
|
||||
console.log('Is 1/2 rational?', Z3.rcf_is_rational(ctx, half) ? 'yes' : 'no');
|
||||
console.log('Is 1/2 algebraic?', Z3.rcf_is_algebraic(ctx, half) ? 'yes' : 'no');
|
||||
|
||||
// Cleanup
|
||||
Z3.rcf_del(ctx, half);
|
||||
Z3.rcf_del(ctx, third);
|
||||
Z3.rcf_del(ctx, sum);
|
||||
} finally {
|
||||
Z3.del_context(ctx);
|
||||
}
|
||||
}
|
||||
|
||||
async function rcfRootsExample() {
|
||||
console.log('\nRCF Roots Example');
|
||||
console.log('=================');
|
||||
|
||||
const { Z3 } = await init();
|
||||
const ctx = Z3.mk_context_rc(Z3.mk_config());
|
||||
|
||||
try {
|
||||
// Find roots of x^2 - 2 = 0
|
||||
// Polynomial: -2 + 0*x + 1*x^2
|
||||
const coeffs = [
|
||||
Z3.rcf_mk_small_int(ctx, -2), // constant term
|
||||
Z3.rcf_mk_small_int(ctx, 0), // x coefficient
|
||||
Z3.rcf_mk_small_int(ctx, 1) // x^2 coefficient
|
||||
];
|
||||
|
||||
const roots = new Array(coeffs.length);
|
||||
const numRoots = Z3.rcf_mk_roots(ctx, coeffs, roots);
|
||||
|
||||
console.log('Roots of x^2 - 2 = 0:');
|
||||
for (let i = 0; i < numRoots; i++) {
|
||||
console.log(` root[${i}] =`, Z3.rcf_num_to_string(ctx, roots[i], false, false));
|
||||
console.log(` decimal =`, Z3.rcf_num_to_decimal_string(ctx, roots[i], 15));
|
||||
console.log(` is_algebraic =`, Z3.rcf_is_algebraic(ctx, roots[i]) ? 'yes' : 'no');
|
||||
}
|
||||
|
||||
// Cleanup
|
||||
for (const coeff of coeffs) {
|
||||
Z3.rcf_del(ctx, coeff);
|
||||
}
|
||||
for (let i = 0; i < numRoots; i++) {
|
||||
Z3.rcf_del(ctx, roots[i]);
|
||||
}
|
||||
} finally {
|
||||
Z3.del_context(ctx);
|
||||
}
|
||||
}
|
||||
|
||||
async function rcfInfinitesimalExample() {
|
||||
console.log('\nRCF Infinitesimal Example');
|
||||
console.log('=========================');
|
||||
|
||||
const { Z3 } = await init();
|
||||
const ctx = Z3.mk_context_rc(Z3.mk_config());
|
||||
|
||||
try {
|
||||
// Create an infinitesimal
|
||||
const eps = Z3.rcf_mk_infinitesimal(ctx);
|
||||
console.log('eps =', Z3.rcf_num_to_string(ctx, eps, false, false));
|
||||
console.log('Is eps infinitesimal?', Z3.rcf_is_infinitesimal(ctx, eps) ? 'yes' : 'no');
|
||||
|
||||
// Infinitesimals are smaller than any positive real number
|
||||
const tiny = Z3.rcf_mk_rational(ctx, '1/1000000000');
|
||||
console.log('eps < 1/1000000000?', Z3.rcf_lt(ctx, eps, tiny) ? 'yes' : 'no');
|
||||
|
||||
// Cleanup
|
||||
Z3.rcf_del(ctx, eps);
|
||||
Z3.rcf_del(ctx, tiny);
|
||||
} finally {
|
||||
Z3.del_context(ctx);
|
||||
}
|
||||
}
|
||||
|
||||
async function main() {
|
||||
try {
|
||||
await rcfBasicExample();
|
||||
await rcfRationalExample();
|
||||
await rcfRootsExample();
|
||||
await rcfInfinitesimalExample();
|
||||
|
||||
console.log('\nAll RCF examples completed successfully!');
|
||||
} catch (error) {
|
||||
console.error('Error:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
main();
|
||||
Loading…
Add table
Add a link
Reference in a new issue