From bc4f587acc8a70cfbe4b934c024830f07e592536 Mon Sep 17 00:00:00 2001
From: Copilot <198982749+Copilot@users.noreply.github.com>
Date: Thu, 8 Jan 2026 18:46:47 -0800
Subject: [PATCH] Add missing C# API functions for solver introspection and
congruence closure (#8126)
* Initial plan
* Add missing C# API functions for NonUnits, Trail, and Congruence methods
Co-authored-by: NikolajBjorner <3085284+NikolajBjorner@users.noreply.github.com>
* Fix formatting: remove extra blank lines in new properties
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>
---
src/api/dotnet/NativeSolver.cs | 44 +++++++++++++++++++++++++
src/api/dotnet/Solver.cs | 60 ++++++++++++++++++++++++++++++++++
2 files changed, 104 insertions(+)
diff --git a/src/api/dotnet/NativeSolver.cs b/src/api/dotnet/NativeSolver.cs
index 7dc937234..acf8b177d 100644
--- a/src/api/dotnet/NativeSolver.cs
+++ b/src/api/dotnet/NativeSolver.cs
@@ -277,6 +277,50 @@ namespace Microsoft.Z3
public Z3_ast[] Units
=> ntvContext.ToArray(Native.Z3_solver_get_units(nCtx, z3solver));
+ ///
+ /// Non-unit literals in the solver state.
+ ///
+ public Z3_ast[] NonUnits
+ => ntvContext.ToArray(Native.Z3_solver_get_non_units(nCtx, z3solver));
+
+ ///
+ /// Trail of the solver state after a check() call.
+ ///
+ public Z3_ast[] Trail
+ => ntvContext.ToArray(Native.Z3_solver_get_trail(nCtx, z3solver));
+
+ ///
+ /// Retrieve congruence closure root of the term t relative to the current search state.
+ /// The function primarily works for SimpleSolver.
+ /// Terms and variables that are eliminated during pre-processing are not visible to the congruence closure.
+ ///
+ public Z3_ast CongruenceRoot(Z3_ast t)
+ {
+ Debug.Assert(t != IntPtr.Zero);
+ return Native.Z3_solver_congruence_root(nCtx, z3solver, t);
+ }
+
+ ///
+ /// Retrieve congruence closure sibling of the term t relative to the current search state.
+ /// The function primarily works for SimpleSolver.
+ /// Terms and variables that are eliminated during pre-processing are not visible to the congruence closure.
+ ///
+ public Z3_ast CongruenceNext(Z3_ast t)
+ {
+ Debug.Assert(t != IntPtr.Zero);
+ return Native.Z3_solver_congruence_next(nCtx, z3solver, t);
+ }
+
+ ///
+ /// Explain congruence of a and b relative to the current search state.
+ ///
+ public Z3_ast CongruenceExplain(Z3_ast a, Z3_ast b)
+ {
+ Debug.Assert(a != IntPtr.Zero);
+ Debug.Assert(b != IntPtr.Zero);
+ return Native.Z3_solver_congruence_explain(nCtx, z3solver, a, b);
+ }
+
///
/// Checks whether the assertions in the solver are consistent or not.
///
diff --git a/src/api/dotnet/Solver.cs b/src/api/dotnet/Solver.cs
index 00b5117ea..c9651e16a 100644
--- a/src/api/dotnet/Solver.cs
+++ b/src/api/dotnet/Solver.cs
@@ -325,6 +325,66 @@ namespace Microsoft.Z3
}
}
+ ///
+ /// Non-unit literals in the solver state.
+ ///
+ public BoolExpr[] NonUnits
+ {
+ get
+ {
+ using ASTVector assertions = new ASTVector(Context, Native.Z3_solver_get_non_units(Context.nCtx, NativeObject));
+ return assertions.ToBoolExprArray();
+ }
+ }
+
+ ///
+ /// Trail of the solver state after a check() call.
+ ///
+ public BoolExpr[] Trail
+ {
+ get
+ {
+ using ASTVector trail = new ASTVector(Context, Native.Z3_solver_get_trail(Context.nCtx, NativeObject));
+ return trail.ToBoolExprArray();
+ }
+ }
+
+ ///
+ /// Retrieve congruence closure root of the term t relative to the current search state.
+ /// The function primarily works for SimpleSolver.
+ /// Terms and variables that are eliminated during pre-processing are not visible to the congruence closure.
+ ///
+ public Expr CongruenceRoot(Expr t)
+ {
+ Debug.Assert(t != null);
+ Context.CheckContextMatch(t);
+ return Expr.Create(Context, Native.Z3_solver_congruence_root(Context.nCtx, NativeObject, t.NativeObject));
+ }
+
+ ///
+ /// Retrieve congruence closure sibling of the term t relative to the current search state.
+ /// The function primarily works for SimpleSolver.
+ /// Terms and variables that are eliminated during pre-processing are not visible to the congruence closure.
+ ///
+ public Expr CongruenceNext(Expr t)
+ {
+ Debug.Assert(t != null);
+ Context.CheckContextMatch(t);
+ return Expr.Create(Context, Native.Z3_solver_congruence_next(Context.nCtx, NativeObject, t.NativeObject));
+ }
+
+ ///
+ /// Explain congruence of a and b relative to the current search state.
+ ///
+ public Expr CongruenceExplain(Expr a, Expr b)
+ {
+ Debug.Assert(a != null);
+ Debug.Assert(b != null);
+ Context.CheckContextMatch(a);
+ Context.CheckContextMatch(b);
+ return Expr.Create(Context, Native.Z3_solver_congruence_explain(Context.nCtx, NativeObject, a.NativeObject, b.NativeObject));
+ }
+
///
/// Checks whether the assertions in the solver are consistent or not.
///