Z3
 
Loading...
Searching...
No Matches
solver.go
Go to the documentation of this file.
1package z3
2
3/*
4#include "z3.h"
5#include <stdlib.h>
6*/
7import "C"
8import (
9 "runtime"
10 "unsafe"
11)
12
13// Status represents the result of a satisfiability check.
14type Status int
15
16const (
17 // Unsatisfiable means the constraints are unsatisfiable.
18 Unsatisfiable Status = -1
19 // Unknown means Z3 could not determine satisfiability.
20 Unknown Status = 0
21 // Satisfiable means the constraints are satisfiable.
22 Satisfiable Status = 1
23)
24
25// String returns the string representation of the status.
26func (s Status) String() string {
27 switch s {
28 case Unsatisfiable:
29 return "unsat"
30 case Unknown:
31 return "unknown"
32 case Satisfiable:
33 return "sat"
34 default:
35 return "unknown"
36 }
37}
38
39// Solver represents a Z3 solver.
40type Solver struct {
41 ctx *Context
42 ptr C.Z3_solver
43}
44
45// NewSolver creates a new solver for the given context.
46func (c *Context) NewSolver() *Solver {
47 s := &Solver{
48 ctx: c,
49 ptr: C.Z3_mk_solver(c.ptr),
50 }
51 C.Z3_solver_inc_ref(c.ptr, s.ptr)
52 runtime.SetFinalizer(s, func(solver *Solver) {
53 C.Z3_solver_dec_ref(solver.ctx.ptr, solver.ptr)
54 })
55 return s
56}
57
58// NewSolverForLogic creates a solver for a specific logic.
59func (c *Context) NewSolverForLogic(logic string) *Solver {
60 sym := c.MkStringSymbol(logic)
61 s := &Solver{
62 ctx: c,
63 ptr: C.Z3_mk_solver_for_logic(c.ptr, sym.ptr),
64 }
65 C.Z3_solver_inc_ref(c.ptr, s.ptr)
66 runtime.SetFinalizer(s, func(solver *Solver) {
67 C.Z3_solver_dec_ref(solver.ctx.ptr, solver.ptr)
68 })
69 return s
70}
71
72// String returns the string representation of the solver.
73func (s *Solver) String() string {
74 return C.GoString(C.Z3_solver_to_string(s.ctx.ptr, s.ptr))
75}
76
77// Assert adds a constraint to the solver.
78func (s *Solver) Assert(constraint *Expr) {
79 C.Z3_solver_assert(s.ctx.ptr, s.ptr, constraint.ptr)
80}
81
82// AssertAndTrack adds a constraint with a tracking literal.
83func (s *Solver) AssertAndTrack(constraint, track *Expr) {
84 C.Z3_solver_assert_and_track(s.ctx.ptr, s.ptr, constraint.ptr, track.ptr)
85}
86
87// Check checks the satisfiability of the constraints.
88func (s *Solver) Check() Status {
89 result := C.Z3_solver_check(s.ctx.ptr, s.ptr)
90 return Status(result)
91}
92
93// CheckAssumptions checks satisfiability under assumptions.
94func (s *Solver) CheckAssumptions(assumptions ...*Expr) Status {
95 if len(assumptions) == 0 {
96 return s.Check()
97 }
98 cAssumptions := make([]C.Z3_ast, len(assumptions))
99 for i, a := range assumptions {
100 cAssumptions[i] = a.ptr
101 }
102 result := C.Z3_solver_check_assumptions(s.ctx.ptr, s.ptr, C.uint(len(assumptions)), &cAssumptions[0])
103 return Status(result)
104}
105
106// Model returns the model if the constraints are satisfiable.
107func (s *Solver) Model() *Model {
108 modelPtr := C.Z3_solver_get_model(s.ctx.ptr, s.ptr)
109 if modelPtr == nil {
110 return nil
111 }
112 return newModel(s.ctx, modelPtr)
113}
114
115// Push creates a backtracking point.
116func (s *Solver) Push() {
117 C.Z3_solver_push(s.ctx.ptr, s.ptr)
118}
119
120// Pop removes backtracking points.
121func (s *Solver) Pop(n uint) {
122 C.Z3_solver_pop(s.ctx.ptr, s.ptr, C.uint(n))
123}
124
125// Reset removes all assertions from the solver.
126func (s *Solver) Reset() {
127 C.Z3_solver_reset(s.ctx.ptr, s.ptr)
128}
129
130// NumScopes returns the number of backtracking points.
131func (s *Solver) NumScopes() uint {
132 return uint(C.Z3_solver_get_num_scopes(s.ctx.ptr, s.ptr))
133}
134
135// Assertions returns the assertions in the solver.
136func (s *Solver) Assertions() []*Expr {
137 vec := C.Z3_solver_get_assertions(s.ctx.ptr, s.ptr)
138 return astVectorToExprs(s.ctx, vec)
139}
140
141// UnsatCore returns the unsat core if the constraints are unsatisfiable.
142func (s *Solver) UnsatCore() []*Expr {
143 vec := C.Z3_solver_get_unsat_core(s.ctx.ptr, s.ptr)
144 return astVectorToExprs(s.ctx, vec)
145}
146
147// ReasonUnknown returns the reason why the result is unknown.
148func (s *Solver) ReasonUnknown() string {
149 return C.GoString(C.Z3_solver_get_reason_unknown(s.ctx.ptr, s.ptr))
150}
151
152// GetStatistics returns the statistics for the solver.
153// Statistics include performance metrics, memory usage, and decision statistics.
154func (s *Solver) GetStatistics() *Statistics {
155 ptr := C.Z3_solver_get_statistics(s.ctx.ptr, s.ptr)
156 return newStatistics(s.ctx, ptr)
157}
158
159// FromFile parses and asserts SMT-LIB2 formulas from a file.
160// The solver will contain the assertions from the file after this call.
161func (s *Solver) FromFile(filename string) {
162 cFilename := C.CString(filename)
163 defer C.free(unsafe.Pointer(cFilename))
164 C.Z3_solver_from_file(s.ctx.ptr, s.ptr, cFilename)
165}
166
167// FromString parses and asserts SMT-LIB2 formulas from a string.
168// The solver will contain the assertions from the string after this call.
169func (s *Solver) FromString(str string) {
170 cStr := C.CString(str)
171 defer C.free(unsafe.Pointer(cStr))
172 C.Z3_solver_from_string(s.ctx.ptr, s.ptr, cStr)
173}
174
175// GetHelp returns a string describing all available solver parameters.
176func (s *Solver) GetHelp() string {
177 return C.GoString(C.Z3_solver_get_help(s.ctx.ptr, s.ptr))
178}
179
180// SetParams sets solver parameters.
181// Parameters control solver behavior such as timeout, proof generation, etc.
182func (s *Solver) SetParams(params *Params) {
183 C.Z3_solver_set_params(s.ctx.ptr, s.ptr, params.ptr)
184}
185
186// GetParamDescrs returns parameter descriptions for the solver.
187func (s *Solver) GetParamDescrs() *ParamDescrs {
188 ptr := C.Z3_solver_get_param_descrs(s.ctx.ptr, s.ptr)
189 return newParamDescrs(s.ctx, ptr)
190}
191
192// Interrupt interrupts the solver execution.
193// This is useful for stopping long-running solver operations gracefully.
194func (s *Solver) Interrupt() {
195 C.Z3_solver_interrupt(s.ctx.ptr, s.ptr)
196}
197
198// Units returns the unit clauses (literals) learned by the solver.
199// Unit clauses are assertions that have been simplified to single literals.
200// This is useful for debugging and understanding solver behavior.
201func (s *Solver) Units() []*Expr {
202 vec := C.Z3_solver_get_units(s.ctx.ptr, s.ptr)
203 return astVectorToExprs(s.ctx, vec)
204}
205
206// NonUnits returns the non-unit clauses in the solver's current state.
207// These are clauses that have not been reduced to unit clauses.
208// This is useful for debugging and understanding solver behavior.
209func (s *Solver) NonUnits() []*Expr {
210 vec := C.Z3_solver_get_non_units(s.ctx.ptr, s.ptr)
211 return astVectorToExprs(s.ctx, vec)
212}
213
214// Trail returns the decision trail of the solver.
215// The trail contains the sequence of literals assigned during search.
216// This is useful for understanding the solver's decision history.
217// Note: This function works primarily with SimpleSolver. For solvers created
218// using tactics (e.g., NewSolver()), it may return an error.
219func (s *Solver) Trail() []*Expr {
220 vec := C.Z3_solver_get_trail(s.ctx.ptr, s.ptr)
221 return astVectorToExprs(s.ctx, vec)
222}
223
224// TrailLevels returns the decision levels for each literal in the trail.
225// The returned slice has the same length as the trail, where each element
226// indicates the decision level at which the corresponding trail literal was assigned.
227// This is useful for understanding the structure of the search tree.
228// Note: This function works primarily with SimpleSolver. For solvers created
229// using tactics (e.g., NewSolver()), it may return an error.
230func (s *Solver) TrailLevels() []uint {
231 // Get the trail vector directly from the C API
232 trailVec := C.Z3_solver_get_trail(s.ctx.ptr, s.ptr)
233 C.Z3_ast_vector_inc_ref(s.ctx.ptr, trailVec)
234 defer C.Z3_ast_vector_dec_ref(s.ctx.ptr, trailVec)
235
236 n := uint(C.Z3_ast_vector_size(s.ctx.ptr, trailVec))
237 if n == 0 {
238 return []uint{}
239 }
240
241 // Allocate the levels array
242 levels := make([]C.uint, n)
243
244 // Get the levels using the trail vector directly
245 // Safe to pass &levels[0] because we checked n > 0 above
246 C.Z3_solver_get_levels(s.ctx.ptr, s.ptr, trailVec, C.uint(n), &levels[0])
247
248 // Convert to Go slice
249 result := make([]uint, n)
250 for i := uint(0); i < n; i++ {
251 result[i] = uint(levels[i])
252 }
253 return result
254}
255
256// CongruenceRoot returns the congruence class representative of the given expression.
257// This returns the root element in the congruence closure for the term.
258// Note: This function works primarily with SimpleSolver. Terms and variables that
259// are eliminated during pre-processing are not visible to the congruence closure.
260func (s *Solver) CongruenceRoot(expr *Expr) *Expr {
261 ast := C.Z3_solver_congruence_root(s.ctx.ptr, s.ptr, expr.ptr)
262 return newExpr(s.ctx, ast)
263}
264
265// CongruenceNext returns the next element in the congruence class of the given expression.
266// This allows iteration through all elements in a congruence class.
267// Note: This function works primarily with SimpleSolver. Terms and variables that
268// are eliminated during pre-processing are not visible to the congruence closure.
269func (s *Solver) CongruenceNext(expr *Expr) *Expr {
270 ast := C.Z3_solver_congruence_next(s.ctx.ptr, s.ptr, expr.ptr)
271 return newExpr(s.ctx, ast)
272}
273
274// CongruenceExplain returns an explanation for why two expressions are congruent.
275// The result is an expression that justifies the congruence between a and b.
276// Note: This function works primarily with SimpleSolver. Terms and variables that
277// are eliminated during pre-processing are not visible to the congruence closure.
278func (s *Solver) CongruenceExplain(a, b *Expr) *Expr {
279 ast := C.Z3_solver_congruence_explain(s.ctx.ptr, s.ptr, a.ptr, b.ptr)
280 return newExpr(s.ctx, ast)
281}
282
283// SetInitialValue provides an initial value hint for a variable to the solver.
284// This can help guide the solver to find solutions more efficiently.
285// The variable must be a constant or function application, and the value must be
286// compatible with the variable's sort.
287func (s *Solver) SetInitialValue(variable, value *Expr) {
288 C.Z3_solver_set_initial_value(s.ctx.ptr, s.ptr, variable.ptr, value.ptr)
289}
290
291// Model represents a Z3 model (satisfying assignment).
292type Model struct {
293 ctx *Context
294 ptr C.Z3_model
295}
296
297// newModel creates a new Model and manages its reference count.
298func newModel(ctx *Context, ptr C.Z3_model) *Model {
299 m := &Model{ctx: ctx, ptr: ptr}
300 C.Z3_model_inc_ref(ctx.ptr, ptr)
301 runtime.SetFinalizer(m, func(model *Model) {
302 C.Z3_model_dec_ref(model.ctx.ptr, model.ptr)
303 })
304 return m
305}
306
307// String returns the string representation of the model.
308func (m *Model) String() string {
309 return C.GoString(C.Z3_model_to_string(m.ctx.ptr, m.ptr))
310}
311
312// NumConsts returns the number of constants in the model.
313func (m *Model) NumConsts() uint {
314 return uint(C.Z3_model_get_num_consts(m.ctx.ptr, m.ptr))
315}
316
317// NumFuncs returns the number of function interpretations in the model.
318func (m *Model) NumFuncs() uint {
319 return uint(C.Z3_model_get_num_funcs(m.ctx.ptr, m.ptr))
320}
321
322// GetConstDecl returns the i-th constant declaration in the model.
323func (m *Model) GetConstDecl(i uint) *FuncDecl {
324 return newFuncDecl(m.ctx, C.Z3_model_get_const_decl(m.ctx.ptr, m.ptr, C.uint(i)))
325}
326
327// GetFuncDecl returns the i-th function declaration in the model.
328func (m *Model) GetFuncDecl(i uint) *FuncDecl {
329 return newFuncDecl(m.ctx, C.Z3_model_get_func_decl(m.ctx.ptr, m.ptr, C.uint(i)))
330}
331
332// Eval evaluates an expression in the model.
333// If modelCompletion is true, Z3 will assign an interpretation for uninterpreted constants.
334func (m *Model) Eval(expr *Expr, modelCompletion bool) (*Expr, bool) {
335 var result C.Z3_ast
336 var completion C.bool
337 if modelCompletion {
338 completion = C.bool(true)
339 } else {
340 completion = C.bool(false)
341 }
342 success := C.Z3_model_eval(m.ctx.ptr, m.ptr, expr.ptr, completion, &result)
343 if success == C.bool(false) {
344 return nil, false
345 }
346 return newExpr(m.ctx, result), true
347}
348
349// GetConstInterp returns the interpretation of a constant.
350func (m *Model) GetConstInterp(decl *FuncDecl) *Expr {
351 result := C.Z3_model_get_const_interp(m.ctx.ptr, m.ptr, decl.ptr)
352 if result == nil {
353 return nil
354 }
355 return newExpr(m.ctx, result)
356}
357
358// FuncInterp represents a function interpretation in a model.
359type FuncInterp struct {
360 ctx *Context
361 ptr C.Z3_func_interp
362}
363
364// GetFuncInterp returns the interpretation of a function.
365func (m *Model) GetFuncInterp(decl *FuncDecl) *FuncInterp {
366 result := C.Z3_model_get_func_interp(m.ctx.ptr, m.ptr, decl.ptr)
367 if result == nil {
368 return nil
369 }
370 fi := &FuncInterp{ctx: m.ctx, ptr: result}
371 C.Z3_func_interp_inc_ref(m.ctx.ptr, result)
372 runtime.SetFinalizer(fi, func(f *FuncInterp) {
373 C.Z3_func_interp_dec_ref(f.ctx.ptr, f.ptr)
374 })
375 return fi
376}
377
378// NumEntries returns the number of entries in the function interpretation.
379func (fi *FuncInterp) NumEntries() uint {
380 return uint(C.Z3_func_interp_get_num_entries(fi.ctx.ptr, fi.ptr))
381}
382
383// GetElse returns the else value of the function interpretation.
384func (fi *FuncInterp) GetElse() *Expr {
385 result := C.Z3_func_interp_get_else(fi.ctx.ptr, fi.ptr)
386 return newExpr(fi.ctx, result)
387}
388
389// GetArity returns the arity of the function interpretation.
390func (fi *FuncInterp) GetArity() uint {
391 return uint(C.Z3_func_interp_get_arity(fi.ctx.ptr, fi.ptr))
392}
393
394// SortUniverse returns the universe of values for an uninterpreted sort in the model.
395// The universe is represented as a list of distinct expressions.
396// Returns nil if the sort is not an uninterpreted sort in this model.
397func (m *Model) SortUniverse(sort *Sort) []*Expr {
398 vec := C.Z3_model_get_sort_universe(m.ctx.ptr, m.ptr, sort.ptr)
399 if vec == nil {
400 return nil
401 }
402 return astVectorToExprs(m.ctx, vec)
403}