From f5a44cf0b914d509ffb0105419797c8030616ff0 Mon Sep 17 00:00:00 2001
From: Copilot <198982749+Copilot@users.noreply.github.com>
Date: Mon, 2 Feb 2026 09:01:01 -0800
Subject: [PATCH] Add missing solver APIs to Java and C# bindings (#8464)
* Initial plan
* Add missing solver APIs for Java and C#
- Issue 3: Add getTrailLevels() to Java and TrailLevels property to C#
- Issue 4: Add cube() iterator to Java (C# already had Cube())
- Issue 5: Add setInitialValue() to Java and SetInitialValue() to C#
Co-authored-by: NikolajBjorner <3085284+NikolajBjorner@users.noreply.github.com>
* Fix code review feedback: eliminate redundant trail retrieval
Co-authored-by: NikolajBjorner <3085284+NikolajBjorner@users.noreply.github.com>
* Improve documentation and efficiency based on code review
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/Solver.cs | 32 ++++++++++++++
src/api/java/Solver.java | 90 ++++++++++++++++++++++++++++++++++++++++
2 files changed, 122 insertions(+)
diff --git a/src/api/dotnet/Solver.cs b/src/api/dotnet/Solver.cs
index 19e798452..4b57257d8 100644
--- a/src/api/dotnet/Solver.cs
+++ b/src/api/dotnet/Solver.cs
@@ -553,6 +553,38 @@ namespace Microsoft.Z3
}
}
+ ///
+ /// Retrieve the trail and their associated decision levels after a Check call.
+ /// The trail contains Boolean literals (decisions and propagations), and the levels
+ /// array contains the corresponding decision levels at which each literal was assigned.
+ ///
+ public uint[] TrailLevels
+ {
+ get
+ {
+ using ASTVector trail = new ASTVector(Context, Native.Z3_solver_get_trail(Context.nCtx, NativeObject));
+ uint[] levels = new uint[trail.Size];
+ Native.Z3_solver_get_levels(Context.nCtx, NativeObject, trail.NativeObject, (uint)trail.Size, levels);
+ return levels;
+ }
+ }
+
+ ///
+ /// Set an initial value for a variable to guide the solver's search heuristics.
+ /// This can improve performance when good initial values are known for the problem domain.
+ ///
+ /// The variable to set an initial value for
+ /// The initial value for the variable
+ public void SetInitialValue(Expr var, Expr value)
+ {
+ Debug.Assert(var != null);
+ Debug.Assert(value != null);
+
+ Context.CheckContextMatch(var);
+ Context.CheckContextMatch(value);
+ Native.Z3_solver_set_initial_value(Context.nCtx, NativeObject, var.NativeObject, value.NativeObject);
+ }
+
///
/// Create a clone of the current solver with respect to ctx.
///
diff --git a/src/api/java/Solver.java b/src/api/java/Solver.java
index b34b72e3b..adeeb6234 100644
--- a/src/api/java/Solver.java
+++ b/src/api/java/Solver.java
@@ -390,6 +390,96 @@ public class Solver extends Z3Object {
getNativeObject());
}
+ /**
+ * Retrieve the decision levels for each literal in the solver's trail after a {@code check} call.
+ * The trail contains Boolean literals (decisions and propagations) in the order they were assigned.
+ * The returned array has one entry per trail literal, indicating at which decision level it was assigned.
+ * Use {@link #getTrail()} to retrieve the trail literals themselves.
+ *
+ * @return An array where element i contains the decision level for the i-th trail literal
+ * @throws Z3Exception
+ **/
+ public int[] getTrailLevels()
+ {
+ ASTVector trailVector = new ASTVector(getContext(), Native.solverGetTrail(getContext().nCtx(), getNativeObject()));
+ int[] levels = new int[trailVector.size()];
+ Native.solverGetLevels(getContext().nCtx(), getNativeObject(), trailVector.getNativeObject(), trailVector.size(), levels);
+ return levels;
+ }
+
+ /**
+ * Return a sequence of cubes (conjunctions of literals) for partitioning the search space.
+ * Each cube represents a partial assignment that can be used as a starting point for parallel solving.
+ * This is primarily useful for cube-and-conquer parallel SAT solving strategies, where different
+ * cubes can be solved independently by different workers.
+ * The iterator yields cubes until the search space is exhausted.
+ *
+ * @param vars Optional array of variables to use as initial cube variables. If null, solver decides.
+ * @param cutoff Backtrack level cutoff for cube generation
+ * @return Iterator over arrays of Boolean expressions representing cubes
+ * @throws Z3Exception
+ **/
+ public java.util.Iterator cube(Expr>[] vars, int cutoff)
+ {
+ ASTVector cubeVars = new ASTVector(getContext());
+ if (vars != null) {
+ for (Expr> v : vars) {
+ cubeVars.push(v);
+ }
+ }
+
+ return new java.util.Iterator() {
+ private BoolExpr[] nextCube = computeNext();
+
+ private BoolExpr[] computeNext() {
+ ASTVector result = new ASTVector(getContext(),
+ Native.solverCube(getContext().nCtx(), getNativeObject(),
+ cubeVars.getNativeObject(), cutoff));
+ BoolExpr[] cube = result.ToBoolExprArray();
+
+ // Check for termination conditions
+ if (cube.length == 1 && cube[0].isFalse()) {
+ return null; // No more cubes
+ }
+ if (cube.length == 0) {
+ return null; // Search space exhausted
+ }
+ return cube;
+ }
+
+ @Override
+ public boolean hasNext() {
+ return nextCube != null;
+ }
+
+ @Override
+ public BoolExpr[] next() {
+ if (nextCube == null) {
+ throw new java.util.NoSuchElementException();
+ }
+ BoolExpr[] current = nextCube;
+ nextCube = computeNext();
+ return current;
+ }
+ };
+ }
+
+ /**
+ * Set an initial value for a variable to guide the solver's search heuristics.
+ * This can improve performance when good initial values are known for the problem domain.
+ *
+ * @param var The variable to set an initial value for
+ * @param value The initial value for the variable
+ * @throws Z3Exception
+ **/
+ public void setInitialValue(Expr> var, Expr> value)
+ {
+ getContext().checkContextMatch(var);
+ getContext().checkContextMatch(value);
+ Native.solverSetInitialValue(getContext().nCtx(), getNativeObject(),
+ var.getNativeObject(), value.getNativeObject());
+ }
+
/**
* Create a clone of the current solver with respect to{@code ctx}.
*/