diff --git a/src/api/dotnet/Context.cs b/src/api/dotnet/Context.cs index 0d624ab0c..4c46d0a95 100644 --- a/src/api/dotnet/Context.cs +++ b/src/api/dotnet/Context.cs @@ -3491,6 +3491,32 @@ namespace Microsoft.Z3 AST.ArrayLength(decls), Symbol.ArrayToNative(declNames), AST.ArrayToNative(decls))); return assertions.ToBoolExprArray(); } + + /// + /// Convert a benchmark into SMT-LIB2 formatted string. + /// + /// Name of the benchmark. May be null. + /// The benchmark logic. May be null. + /// Status string, such as "sat", "unsat", or "unknown". + /// Other attributes, such as source, difficulty or category. May be null. + /// Auxiliary assumptions. + /// Formula to be checked for consistency in conjunction with assumptions. + /// A string representation of the benchmark in SMT-LIB2 format. + public string BenchmarkToSmtlibString(string name, string logic, string status, string attributes, BoolExpr[] assumptions, BoolExpr formula) + { + Debug.Assert(assumptions != null); + Debug.Assert(formula != null); + + return Native.Z3_benchmark_to_smtlib_string( + nCtx, + name, + logic, + status, + attributes, + (uint)(assumptions?.Length ?? 0), + AST.ArrayToNative(assumptions), + formula.NativeObject); + } #endregion #region Goals diff --git a/src/api/dotnet/Solver.cs b/src/api/dotnet/Solver.cs index c9651e16a..19e798452 100644 --- a/src/api/dotnet/Solver.cs +++ b/src/api/dotnet/Solver.cs @@ -590,6 +590,34 @@ namespace Microsoft.Z3 return Native.Z3_solver_to_string(Context.nCtx, NativeObject); } + /// + /// Convert the solver assertions to SMT-LIB2 format as a benchmark. + /// + /// Status string, such as "sat", "unsat", or "unknown". Default is "unknown". + /// A string representation of the solver's assertions in SMT-LIB2 format. + public string ToSmt2(string status = "unknown") + { + BoolExpr[] assertions = Assertions; + BoolExpr formula; + BoolExpr[] assumptions; + + if (assertions.Length > 0) + { + // Use last assertion as formula and rest as assumptions + assumptions = new BoolExpr[assertions.Length - 1]; + Array.Copy(assertions, assumptions, assertions.Length - 1); + formula = assertions[assertions.Length - 1]; + } + else + { + // No assertions, use true + assumptions = new BoolExpr[0]; + formula = Context.MkTrue(); + } + + return Context.BenchmarkToSmtlibString("", "", status, "", assumptions, formula); + } + #region Internal internal Solver(Context ctx, IntPtr obj) : base(ctx, obj) diff --git a/src/api/js/src/high-level/high-level.ts b/src/api/js/src/high-level/high-level.ts index f1dd85261..b4161ca35 100644 --- a/src/api/js/src/high-level/high-level.ts +++ b/src/api/js/src/high-level/high-level.ts @@ -1899,6 +1899,36 @@ export function createApi(Z3: Z3Core): Z3HighLevel { return check(Z3.solver_to_string(contextPtr, this.ptr)); } + toSmtlib2(status: string = 'unknown'): string { + const assertionsVec = this.assertions(); + const numAssertions = assertionsVec.length(); + let formula: Z3_ast; + let assumptions: Z3_ast[]; + + if (numAssertions > 0) { + // Use last assertion as formula and rest as assumptions + assumptions = []; + for (let i = 0; i < numAssertions - 1; i++) { + assumptions.push(assertionsVec.get(i).ast); + } + formula = assertionsVec.get(numAssertions - 1).ast; + } else { + // No assertions, use true + assumptions = []; + formula = ctx.Bool.val(true).ast; + } + + return check(Z3.benchmark_to_smtlib_string( + contextPtr, + '', + '', + status, + '', + assumptions, + formula + )); + } + fromString(s: string) { Z3.solver_from_string(contextPtr, this.ptr, s); throwIfError(); diff --git a/src/api/js/src/high-level/types.ts b/src/api/js/src/high-level/types.ts index 32d08b6ae..2dad7944f 100644 --- a/src/api/js/src/high-level/types.ts +++ b/src/api/js/src/high-level/types.ts @@ -1172,6 +1172,28 @@ export interface Solver { */ fromFile(filename: string): void; + /** + * Convert the solver's assertions to SMT-LIB2 format as a benchmark. + * + * This exports the current set of assertions in the solver as an SMT-LIB2 string, + * which can be used for bug reporting, sharing problems, or benchmarking. + * + * @param status - Status string such as "sat", "unsat", or "unknown" (default: "unknown") + * @returns A string representation of the solver's assertions in SMT-LIB2 format + * + * @example + * ```typescript + * const solver = new Solver(); + * const x = Int.const('x'); + * const y = Int.const('y'); + * solver.add(x.gt(0)); + * solver.add(y.eq(x.add(1))); + * const smtlib2 = solver.toSmtlib2('unknown'); + * console.log(smtlib2); // Prints SMT-LIB2 formatted problem + * ``` + */ + toSmtlib2(status?: string): string; + /** * Manually decrease the reference count of the solver * This is automatically done when the solver is garbage collected,