Z3
 
Loading...
Searching...
No Matches
z3.go
Go to the documentation of this file.
1// Package z3 provides Go bindings for the Z3 theorem prover.
2//
3// Z3 is a high-performance SMT (Satisfiability Modulo Theories) solver
4// developed at Microsoft Research. These bindings wrap the Z3 C API using
5// CGO and provide idiomatic Go interfaces with automatic memory management.
6//
7// # Basic Usage
8//
9// Create a context and solver:
10//
11// ctx := z3.NewContext()
12// solver := ctx.NewSolver()
13//
14// Create variables and constraints:
15//
16// x := ctx.MkIntConst("x")
17// y := ctx.MkIntConst("y")
18// solver.Assert(ctx.MkEq(ctx.MkAdd(x, y), ctx.MkInt(10, ctx.MkIntSort())))
19// solver.Assert(ctx.MkGt(x, y))
20//
21// Check satisfiability and get model:
22//
23// if solver.Check() == z3.Satisfiable {
24// model := solver.Model()
25// xVal, _ := model.Eval(x, true)
26// fmt.Println("x =", xVal.String())
27// }
28//
29// # Memory Management
30//
31// All Z3 objects are automatically managed using Go finalizers. Reference
32// counting is handled transparently - you don't need to manually free objects.
33//
34// # Supported Features
35//
36// - Boolean logic, integer and real arithmetic
37// - Bit-vectors and floating-point arithmetic
38// - Arrays, sequences, and strings
39// - Regular expressions
40// - Algebraic datatypes
41// - Quantifiers and lambda expressions
42// - Tactics and goal-based solving
43// - Optimization (MaxSMT)
44// - Fixedpoint solver (Datalog/CHC)
45//
46// For more examples, see the examples/go directory in the Z3 repository.
47package z3
48
49/*
50#cgo CFLAGS: -I${SRCDIR}/..
51#cgo LDFLAGS: -lz3
52#include "z3.h"
53#include <stdlib.h>
54*/
55import "C"
56import (
57 "runtime"
58 "unsafe"
59)
60
61// Config represents a Z3 configuration object.
62type Config struct {
63 ptr C.Z3_config
64}
65
66// NewConfig creates a new Z3 configuration.
67func NewConfig() *Config {
68 cfg := &Config{ptr: C.Z3_mk_config()}
69 runtime.SetFinalizer(cfg, func(c *Config) {
70 C.Z3_del_config(c.ptr)
71 })
72 return cfg
73}
74
75// SetParamValue sets a configuration parameter.
76func (c *Config) SetParamValue(paramID, paramValue string) {
77 cParamID := C.CString(paramID)
78 cParamValue := C.CString(paramValue)
79 defer C.free(unsafe.Pointer(cParamID))
80 defer C.free(unsafe.Pointer(cParamValue))
81 C.Z3_set_param_value(c.ptr, cParamID, cParamValue)
82}
83
84// Context represents a Z3 logical context.
85type Context struct {
86 ptr C.Z3_context
87}
88
89// NewContext creates a new Z3 context with default configuration.
90func NewContext() *Context {
91 ctx := &Context{ptr: C.Z3_mk_context_rc(C.Z3_mk_config())}
92 C.Z3_enable_concurrent_dec_ref(ctx.ptr)
93 runtime.SetFinalizer(ctx, func(c *Context) {
94 C.Z3_del_context(c.ptr)
95 })
96 return ctx
97}
98
99// NewContextWithConfig creates a new Z3 context with the given configuration.
100func NewContextWithConfig(cfg *Config) *Context {
101 ctx := &Context{ptr: C.Z3_mk_context_rc(cfg.ptr)}
102 C.Z3_enable_concurrent_dec_ref(ctx.ptr)
103 runtime.SetFinalizer(ctx, func(c *Context) {
104 C.Z3_del_context(c.ptr)
105 })
106 return ctx
107}
108
109// SetParam sets a global or context parameter.
110func (c *Context) SetParam(key, value string) {
111 cKey := C.CString(key)
112 cValue := C.CString(value)
113 defer C.free(unsafe.Pointer(cKey))
114 defer C.free(unsafe.Pointer(cValue))
115 C.Z3_update_param_value(c.ptr, cKey, cValue)
116}
117
118// Symbol represents a Z3 symbol.
119type Symbol struct {
120 ctx *Context
121 ptr C.Z3_symbol
122}
123
124// newSymbol creates a new Symbol.
125func newSymbol(ctx *Context, ptr C.Z3_symbol) *Symbol {
126 return &Symbol{ctx: ctx, ptr: ptr}
127}
128
129// MkIntSymbol creates an integer symbol.
130func (c *Context) MkIntSymbol(i int) *Symbol {
131 return &Symbol{
132 ctx: c,
133 ptr: C.Z3_mk_int_symbol(c.ptr, C.int(i)),
134 }
135}
136
137// MkStringSymbol creates a string symbol.
138func (c *Context) MkStringSymbol(s string) *Symbol {
139 cStr := C.CString(s)
140 defer C.free(unsafe.Pointer(cStr))
141 return &Symbol{
142 ctx: c,
143 ptr: C.Z3_mk_string_symbol(c.ptr, cStr),
144 }
145}
146
147// String returns the string representation of the symbol.
148func (s *Symbol) String() string {
149 kind := C.Z3_get_symbol_kind(s.ctx.ptr, s.ptr)
150 if kind == C.Z3_INT_SYMBOL {
151 return string(rune(C.Z3_get_symbol_int(s.ctx.ptr, s.ptr)))
152 }
153 return C.GoString(C.Z3_get_symbol_string(s.ctx.ptr, s.ptr))
154}
155
156// AST represents a Z3 abstract syntax tree node.
157type AST struct {
158 ctx *Context
159 ptr C.Z3_ast
160}
161
162// incRef increments the reference count of the AST.
163func (a *AST) incRef() {
164 C.Z3_inc_ref(a.ctx.ptr, a.ptr)
165}
166
167// decRef decrements the reference count of the AST.
168func (a *AST) decRef() {
169 C.Z3_dec_ref(a.ctx.ptr, a.ptr)
170}
171
172// String returns the string representation of the AST.
173func (a *AST) String() string {
174 return C.GoString(C.Z3_ast_to_string(a.ctx.ptr, a.ptr))
175}
176
177// Hash returns the hash code of the AST.
178func (a *AST) Hash() uint32 {
179 return uint32(C.Z3_get_ast_hash(a.ctx.ptr, a.ptr))
180}
181
182// Equal checks if two ASTs are equal.
183func (a *AST) Equal(other *AST) bool {
184 if a.ctx != other.ctx {
185 return false
186 }
187 return bool(C.Z3_is_eq_ast(a.ctx.ptr, a.ptr, other.ptr))
188}
189
190// Sort represents a Z3 sort (type).
191type Sort struct {
192 ctx *Context
193 ptr C.Z3_sort
194}
195
196// newSort creates a new Sort and manages its reference count.
197func newSort(ctx *Context, ptr C.Z3_sort) *Sort {
198 sort := &Sort{ctx: ctx, ptr: ptr}
199 C.Z3_inc_ref(ctx.ptr, C.Z3_sort_to_ast(ctx.ptr, ptr))
200 runtime.SetFinalizer(sort, func(s *Sort) {
201 C.Z3_dec_ref(s.ctx.ptr, C.Z3_sort_to_ast(s.ctx.ptr, s.ptr))
202 })
203 return sort
204}
205
206// String returns the string representation of the sort.
207func (s *Sort) String() string {
208 return C.GoString(C.Z3_sort_to_string(s.ctx.ptr, s.ptr))
209}
210
211// Equal checks if two sorts are equal.
212func (s *Sort) Equal(other *Sort) bool {
213 if s.ctx != other.ctx {
214 return false
215 }
216 return bool(C.Z3_is_eq_sort(s.ctx.ptr, s.ptr, other.ptr))
217}
218
219// MkBoolSort creates the Boolean sort.
220func (c *Context) MkBoolSort() *Sort {
221 return newSort(c, C.Z3_mk_bool_sort(c.ptr))
222}
223
224// MkBvSort creates a bit-vector sort of the given size.
225func (c *Context) MkBvSort(sz uint) *Sort {
226 return newSort(c, C.Z3_mk_bv_sort(c.ptr, C.uint(sz)))
227}
228
229// Expr represents a Z3 expression.
230type Expr struct {
231 ctx *Context
232 ptr C.Z3_ast
233}
234
235// newExpr creates a new Expr and manages its reference count.
236func newExpr(ctx *Context, ptr C.Z3_ast) *Expr {
237 expr := &Expr{ctx: ctx, ptr: ptr}
238 C.Z3_inc_ref(ctx.ptr, ptr)
239 runtime.SetFinalizer(expr, func(e *Expr) {
240 C.Z3_dec_ref(e.ctx.ptr, e.ptr)
241 })
242 return expr
243}
244
245// intsToCs converts a []int slice to []C.int, returning the slice and
246// a pointer to its first element (nil if empty).
247func intsToCs(ints []int) ([]C.int, *C.int) {
248 if len(ints) == 0 {
249 return nil, nil
250 }
251 cInts := make([]C.int, len(ints))
252 for i, v := range ints {
253 cInts[i] = C.int(v)
254 }
255 return cInts, &cInts[0]
256}
257
258// exprsToASTs converts a []*Expr slice to []C.Z3_ast, returning the slice and
259// a pointer to its first element (nil if empty).
260func exprsToASTs(exprs []*Expr) ([]C.Z3_ast, *C.Z3_ast) {
261 if len(exprs) == 0 {
262 return nil, nil
263 }
264 cExprs := make([]C.Z3_ast, len(exprs))
265 for i, e := range exprs {
266 cExprs[i] = e.ptr
267 }
268 return cExprs, &cExprs[0]
269}
270
271// sortsToCSorts converts a []*Sort slice to []C.Z3_sort, returning the slice and
272// a pointer to its first element (nil if empty).
273func sortsToCSorts(sorts []*Sort) ([]C.Z3_sort, *C.Z3_sort) {
274 if len(sorts) == 0 {
275 return nil, nil
276 }
277 cSorts := make([]C.Z3_sort, len(sorts))
278 for i, s := range sorts {
279 cSorts[i] = s.ptr
280 }
281 return cSorts, &cSorts[0]
282}
283
284// String returns the string representation of the expression.
285func (e *Expr) String() string {
286 return C.GoString(C.Z3_ast_to_string(e.ctx.ptr, e.ptr))
287}
288
289// Equal checks if two expressions are equal.
290func (e *Expr) Equal(other *Expr) bool {
291 if e.ctx != other.ctx {
292 return false
293 }
294 return bool(C.Z3_is_eq_ast(e.ctx.ptr, e.ptr, other.ptr))
295}
296
297// GetSort returns the sort of the expression.
298func (e *Expr) GetSort() *Sort {
299 return newSort(e.ctx, C.Z3_get_sort(e.ctx.ptr, e.ptr))
300}
301
302// Pattern represents a Z3 pattern for quantifier instantiation.
303type Pattern struct {
304 ctx *Context
305 ptr C.Z3_pattern
306}
307
308// newPattern creates a new Pattern and manages its reference count.
309func newPattern(ctx *Context, ptr C.Z3_pattern) *Pattern {
310 p := &Pattern{ctx: ctx, ptr: ptr}
311 // Patterns are ASTs in the C API
312 C.Z3_inc_ref(ctx.ptr, (C.Z3_ast)(unsafe.Pointer(ptr)))
313 runtime.SetFinalizer(p, func(pat *Pattern) {
314 C.Z3_dec_ref(pat.ctx.ptr, (C.Z3_ast)(unsafe.Pointer(pat.ptr)))
315 })
316 return p
317}
318
319// ASTVector represents a vector of Z3 ASTs.
320type ASTVector struct {
321 ctx *Context
322 ptr C.Z3_ast_vector
323}
324
325// newASTVector creates a new ASTVector and manages its reference count.
326func newASTVector(ctx *Context, ptr C.Z3_ast_vector) *ASTVector {
327 v := &ASTVector{ctx: ctx, ptr: ptr}
328 C.Z3_ast_vector_inc_ref(ctx.ptr, ptr)
329 runtime.SetFinalizer(v, func(vec *ASTVector) {
330 C.Z3_ast_vector_dec_ref(vec.ctx.ptr, vec.ptr)
331 })
332 return v
333}
334
335// Size returns the number of ASTs in the vector.
336func (v *ASTVector) Size() uint {
337 return uint(C.Z3_ast_vector_size(v.ctx.ptr, v.ptr))
338}
339
340// Get returns the i-th AST in the vector.
341func (v *ASTVector) Get(i uint) *Expr {
342 return newExpr(v.ctx, C.Z3_ast_vector_get(v.ctx.ptr, v.ptr, C.uint(i)))
343}
344
345// String returns the string representation of the AST vector.
346func (v *ASTVector) String() string {
347 return C.GoString(C.Z3_ast_vector_to_string(v.ctx.ptr, v.ptr))
348}
349
350// ParamDescrs represents parameter descriptions for Z3 objects.
351type ParamDescrs struct {
352 ctx *Context
353 ptr C.Z3_param_descrs
354}
355
356// newParamDescrs creates a new ParamDescrs and manages its reference count.
357func newParamDescrs(ctx *Context, ptr C.Z3_param_descrs) *ParamDescrs {
358 pd := &ParamDescrs{ctx: ctx, ptr: ptr}
359 C.Z3_param_descrs_inc_ref(ctx.ptr, ptr)
360 runtime.SetFinalizer(pd, func(descrs *ParamDescrs) {
361 C.Z3_param_descrs_dec_ref(descrs.ctx.ptr, descrs.ptr)
362 })
363 return pd
364}
365
366// MkTrue creates the Boolean constant true.
367func (c *Context) MkTrue() *Expr {
368 return newExpr(c, C.Z3_mk_true(c.ptr))
369}
370
371// MkFalse creates the Boolean constant false.
372func (c *Context) MkFalse() *Expr {
373 return newExpr(c, C.Z3_mk_false(c.ptr))
374}
375
376// MkBool creates a Boolean constant.
377func (c *Context) MkBool(value bool) *Expr {
378 if value {
379 return c.MkTrue()
380 }
381 return c.MkFalse()
382}
383
384// MkNumeral creates a numeral from a string.
385func (c *Context) MkNumeral(numeral string, sort *Sort) *Expr {
386 cStr := C.CString(numeral)
387 defer C.free(unsafe.Pointer(cStr))
388 return newExpr(c, C.Z3_mk_numeral(c.ptr, cStr, sort.ptr))
389}
390
391// MkConst creates a constant (variable) with the given name and sort.
392func (c *Context) MkConst(name *Symbol, sort *Sort) *Expr {
393 return newExpr(c, C.Z3_mk_const(c.ptr, name.ptr, sort.ptr))
394}
395
396// MkFreshConst creates a fresh constant with a name prefixed by prefix.
397func (c *Context) MkFreshConst(prefix string, sort *Sort) *Expr {
398 cPrefix := C.CString(prefix)
399 defer C.free(unsafe.Pointer(cPrefix))
400 return newExpr(c, C.Z3_mk_fresh_const(c.ptr, cPrefix, sort.ptr))
401}
402
403// MkBoolConst creates a Boolean constant (variable) with the given name.
404func (c *Context) MkBoolConst(name string) *Expr {
405 sym := c.MkStringSymbol(name)
406 return c.MkConst(sym, c.MkBoolSort())
407}
408
409// Boolean operations
410
411// MkAnd creates a conjunction.
412func (c *Context) MkAnd(exprs ...*Expr) *Expr {
413 if len(exprs) == 0 {
414 return c.MkTrue()
415 }
416 if len(exprs) == 1 {
417 return exprs[0]
418 }
419 _, cExprsPtr := exprsToASTs(exprs)
420 return newExpr(c, C.Z3_mk_and(c.ptr, C.uint(len(exprs)), cExprsPtr))
421}
422
423// MkOr creates a disjunction.
424func (c *Context) MkOr(exprs ...*Expr) *Expr {
425 if len(exprs) == 0 {
426 return c.MkFalse()
427 }
428 if len(exprs) == 1 {
429 return exprs[0]
430 }
431 _, cExprsPtr := exprsToASTs(exprs)
432 return newExpr(c, C.Z3_mk_or(c.ptr, C.uint(len(exprs)), cExprsPtr))
433}
434
435// MkNot creates a negation.
436func (c *Context) MkNot(expr *Expr) *Expr {
437 return newExpr(c, C.Z3_mk_not(c.ptr, expr.ptr))
438}
439
440// MkImplies creates an implication.
441func (c *Context) MkImplies(lhs, rhs *Expr) *Expr {
442 return newExpr(c, C.Z3_mk_implies(c.ptr, lhs.ptr, rhs.ptr))
443}
444
445// MkIff creates a bi-implication (if and only if).
446func (c *Context) MkIff(lhs, rhs *Expr) *Expr {
447 return newExpr(c, C.Z3_mk_iff(c.ptr, lhs.ptr, rhs.ptr))
448}
449
450// MkXor creates exclusive or.
451func (c *Context) MkXor(lhs, rhs *Expr) *Expr {
452 return newExpr(c, C.Z3_mk_xor(c.ptr, lhs.ptr, rhs.ptr))
453}
454
455// Comparison operations
456
457// MkEq creates an equality.
458func (c *Context) MkEq(lhs, rhs *Expr) *Expr {
459 return newExpr(c, C.Z3_mk_eq(c.ptr, lhs.ptr, rhs.ptr))
460}
461
462// MkDistinct creates a distinct constraint.
463func (c *Context) MkDistinct(exprs ...*Expr) *Expr {
464 if len(exprs) <= 1 {
465 return c.MkTrue()
466 }
467 _, cExprsPtr := exprsToASTs(exprs)
468 return newExpr(c, C.Z3_mk_distinct(c.ptr, C.uint(len(exprs)), cExprsPtr))
469}
470
471// Pseudo-Boolean / cardinality constraints
472
473// MkAtMost encodes p1 + p2 + ... + pn <= k.
474func (c *Context) MkAtMost(args []*Expr, k uint) *Expr {
475 _, cArgsPtr := exprsToASTs(args)
476 return newExpr(c, C.Z3_mk_atmost(c.ptr, C.uint(len(args)), cArgsPtr, C.uint(k)))
477}
478
479// MkAtLeast encodes p1 + p2 + ... + pn >= k.
480func (c *Context) MkAtLeast(args []*Expr, k uint) *Expr {
481 _, cArgsPtr := exprsToASTs(args)
482 return newExpr(c, C.Z3_mk_atleast(c.ptr, C.uint(len(args)), cArgsPtr, C.uint(k)))
483}
484
485// MkPBLe encodes k1*p1 + k2*p2 + ... + kn*pn <= k.
486func (c *Context) MkPBLe(args []*Expr, coeffs []int, k int) *Expr {
487 if len(args) != len(coeffs) {
488 panic("MkPBLe: args and coeffs must have the same length")
489 }
490 _, cArgsPtr := exprsToASTs(args)
491 _, cCoeffsPtr := intsToCs(coeffs)
492 return newExpr(c, C.Z3_mk_pble(c.ptr, C.uint(len(args)), cArgsPtr, cCoeffsPtr, C.int(k)))
493}
494
495// MkPBGe encodes k1*p1 + k2*p2 + ... + kn*pn >= k.
496func (c *Context) MkPBGe(args []*Expr, coeffs []int, k int) *Expr {
497 if len(args) != len(coeffs) {
498 panic("MkPBGe: args and coeffs must have the same length")
499 }
500 _, cArgsPtr := exprsToASTs(args)
501 _, cCoeffsPtr := intsToCs(coeffs)
502 return newExpr(c, C.Z3_mk_pbge(c.ptr, C.uint(len(args)), cArgsPtr, cCoeffsPtr, C.int(k)))
503}
504
505// MkPBEq encodes k1*p1 + k2*p2 + ... + kn*pn = k.
506func (c *Context) MkPBEq(args []*Expr, coeffs []int, k int) *Expr {
507 if len(args) != len(coeffs) {
508 panic("MkPBEq: args and coeffs must have the same length")
509 }
510 _, cArgsPtr := exprsToASTs(args)
511 _, cCoeffsPtr := intsToCs(coeffs)
512 return newExpr(c, C.Z3_mk_pbeq(c.ptr, C.uint(len(args)), cArgsPtr, cCoeffsPtr, C.int(k)))
513}
514
515// FuncDecl represents a function declaration.
516type FuncDecl struct {
517 ctx *Context
518 ptr C.Z3_func_decl
519}
520
521// newFuncDecl creates a new FuncDecl and manages its reference count.
522func newFuncDecl(ctx *Context, ptr C.Z3_func_decl) *FuncDecl {
523 fd := &FuncDecl{ctx: ctx, ptr: ptr}
524 C.Z3_inc_ref(ctx.ptr, C.Z3_func_decl_to_ast(ctx.ptr, ptr))
525 runtime.SetFinalizer(fd, func(f *FuncDecl) {
526 C.Z3_dec_ref(f.ctx.ptr, C.Z3_func_decl_to_ast(f.ctx.ptr, f.ptr))
527 })
528 return fd
529}
530
531// String returns the string representation of the function declaration.
532func (f *FuncDecl) String() string {
533 return C.GoString(C.Z3_func_decl_to_string(f.ctx.ptr, f.ptr))
534}
535
536// GetName returns the name of the function declaration.
537func (f *FuncDecl) GetName() *Symbol {
538 return &Symbol{
539 ctx: f.ctx,
540 ptr: C.Z3_get_decl_name(f.ctx.ptr, f.ptr),
541 }
542}
543
544// GetArity returns the arity (number of parameters) of the function.
545func (f *FuncDecl) GetArity() int {
546 return int(C.Z3_get_arity(f.ctx.ptr, f.ptr))
547}
548
549// GetDomain returns the sort of the i-th parameter.
550func (f *FuncDecl) GetDomain(i int) *Sort {
551 return newSort(f.ctx, C.Z3_get_domain(f.ctx.ptr, f.ptr, C.uint(i)))
552}
553
554// GetRange returns the sort of the return value.
555func (f *FuncDecl) GetRange() *Sort {
556 return newSort(f.ctx, C.Z3_get_range(f.ctx.ptr, f.ptr))
557}
558
559// MkFuncDecl creates a function declaration.
560func (c *Context) MkFuncDecl(name *Symbol, domain []*Sort, range_ *Sort) *FuncDecl {
561 _, domainPtr := sortsToCSorts(domain)
562 return newFuncDecl(c, C.Z3_mk_func_decl(c.ptr, name.ptr, C.uint(len(domain)), domainPtr, range_.ptr))
563}
564
565// MkFreshFuncDecl creates a fresh function declaration with a name prefixed by prefix.
566func (c *Context) MkFreshFuncDecl(prefix string, domain []*Sort, range_ *Sort) *FuncDecl {
567 cPrefix := C.CString(prefix)
568 defer C.free(unsafe.Pointer(cPrefix))
569 _, domainPtr := sortsToCSorts(domain)
570 return newFuncDecl(c, C.Z3_mk_fresh_func_decl(c.ptr, cPrefix, C.uint(len(domain)), domainPtr, range_.ptr))
571}
572
573// PolynomialSubresultants returns the nonzero subresultants of p and q with
574// respect to x. Non-polynomial subterms are treated as variables.
575func (c *Context) PolynomialSubresultants(p, q, x *Expr) *ASTVector {
576 return newASTVector(c, C.Z3_polynomial_subresultants(c.ptr, p.ptr, q.ptr, x.ptr))
577}
578
579// MkRecFuncDecl creates a recursive function declaration.
580// After creating, use AddRecDef to provide the function body.
581func (c *Context) MkRecFuncDecl(name *Symbol, domain []*Sort, range_ *Sort) *FuncDecl {
582 _, domainPtr := sortsToCSorts(domain)
583 return newFuncDecl(c, C.Z3_mk_rec_func_decl(c.ptr, name.ptr, C.uint(len(domain)), domainPtr, range_.ptr))
584}
585
586// AddRecDef adds the definition (body) for a recursive function created with MkRecFuncDecl.
587func (c *Context) AddRecDef(f *FuncDecl, args []*Expr, body *Expr) {
588 _, argsPtr := exprsToASTs(args)
589 C.Z3_add_rec_def(c.ptr, f.ptr, C.uint(len(args)), argsPtr, body.ptr)
590}
591
592// MkApp creates a function application.
593func (c *Context) MkApp(decl *FuncDecl, args ...*Expr) *Expr {
594 _, argsPtr := exprsToASTs(args)
595 return newExpr(c, C.Z3_mk_app(c.ptr, decl.ptr, C.uint(len(args)), argsPtr))
596}
597
598// Quantifier operations
599
600// MkForall creates a universal quantifier.
601func (c *Context) MkForall(bound []*Expr, body *Expr) *Expr {
602 cBound := make([]C.Z3_app, len(bound))
603 for i, b := range bound {
604 // Z3_app is a subtype of Z3_ast; constants are apps
605 cBound[i] = (C.Z3_app)(unsafe.Pointer(b.ptr))
606 }
607 var boundPtr *C.Z3_app
608 if len(bound) > 0 {
609 boundPtr = &cBound[0]
610 }
611 return newExpr(c, C.Z3_mk_forall_const(c.ptr, 0, C.uint(len(bound)), boundPtr, 0, nil, body.ptr))
612}
613
614// MkExists creates an existential quantifier.
615func (c *Context) MkExists(bound []*Expr, body *Expr) *Expr {
616 cBound := make([]C.Z3_app, len(bound))
617 for i, b := range bound {
618 // Z3_app is a subtype of Z3_ast; constants are apps
619 cBound[i] = (C.Z3_app)(unsafe.Pointer(b.ptr))
620 }
621 var boundPtr *C.Z3_app
622 if len(bound) > 0 {
623 boundPtr = &cBound[0]
624 }
625 return newExpr(c, C.Z3_mk_exists_const(c.ptr, 0, C.uint(len(bound)), boundPtr, 0, nil, body.ptr))
626}
627
628// Simplify simplifies an expression.
629func (e *Expr) Simplify() *Expr {
630 return newExpr(e.ctx, C.Z3_simplify(e.ctx.ptr, e.ptr))
631}
632
633// GetDecl returns the function declaration of an application expression.
634func (e *Expr) GetDecl() *FuncDecl {
635 return newFuncDecl(e.ctx, C.Z3_get_app_decl(e.ctx.ptr, C.Z3_to_app(e.ctx.ptr, e.ptr)))
636}
637
638// NumArgs returns the number of arguments of an application expression.
639func (e *Expr) NumArgs() uint {
640 return uint(C.Z3_get_app_num_args(e.ctx.ptr, C.Z3_to_app(e.ctx.ptr, e.ptr)))
641}
642
643// Arg returns the i-th argument of an application expression.
644func (e *Expr) Arg(i uint) *Expr {
645 return newExpr(e.ctx, C.Z3_get_app_arg(e.ctx.ptr, C.Z3_to_app(e.ctx.ptr, e.ptr), C.uint(i)))
646}
647
648// Substitute replaces every occurrence of from[i] in the expression with to[i].
649// The from and to slices must have the same length.
650func (e *Expr) Substitute(from, to []*Expr) *Expr {
651 n := len(from)
652 cFrom := make([]C.Z3_ast, n)
653 cTo := make([]C.Z3_ast, n)
654 for i := range from {
655 cFrom[i] = from[i].ptr
656 cTo[i] = to[i].ptr
657 }
658 var fromPtr, toPtr *C.Z3_ast
659 if n > 0 {
660 fromPtr = &cFrom[0]
661 toPtr = &cTo[0]
662 }
663 return newExpr(e.ctx, C.Z3_substitute(e.ctx.ptr, e.ptr, C.uint(n), fromPtr, toPtr))
664}
665
666// SubstituteVars replaces free variables in the expression with the expressions in to.
667// Variable with de-Bruijn index i is replaced with to[i].
668func (e *Expr) SubstituteVars(to []*Expr) *Expr {
669 _, toPtr := exprsToASTs(to)
670 return newExpr(e.ctx, C.Z3_substitute_vars(e.ctx.ptr, e.ptr, C.uint(len(to)), toPtr))
671}
672
673// SubstituteFuns replaces every occurrence of from[i] applied to arguments
674// with to[i] in the expression.
675// The from and to slices must have the same length.
676func (e *Expr) SubstituteFuns(from []*FuncDecl, to []*Expr) *Expr {
677 n := len(from)
678 cFrom := make([]C.Z3_func_decl, n)
679 cTo := make([]C.Z3_ast, n)
680 for i := range from {
681 cFrom[i] = from[i].ptr
682 cTo[i] = to[i].ptr
683 }
684 var fromPtr *C.Z3_func_decl
685 var toPtr *C.Z3_ast
686 if n > 0 {
687 fromPtr = &cFrom[0]
688 toPtr = &cTo[0]
689 }
690 return newExpr(e.ctx, C.Z3_substitute_funs(e.ctx.ptr, e.ptr, C.uint(n), fromPtr, toPtr))
691}
692
693// MkTypeVariable creates a type variable sort for use in polymorphic functions and datatypes
694func (c *Context) MkTypeVariable(name *Symbol) *Sort {
695 return newSort(c, C.Z3_mk_type_variable(c.ptr, name.ptr))
696}
697
698// Quantifier represents a quantified formula (forall or exists)
699type Quantifier struct {
700 ctx *Context
701 ptr C.Z3_ast
702}
703
704// newQuantifier creates a new Quantifier with proper memory management
705func newQuantifier(ctx *Context, ptr C.Z3_ast) *Quantifier {
706 q := &Quantifier{ctx: ctx, ptr: ptr}
707 C.Z3_inc_ref(ctx.ptr, ptr)
708 runtime.SetFinalizer(q, func(qf *Quantifier) {
709 C.Z3_dec_ref(qf.ctx.ptr, qf.ptr)
710 })
711 return q
712}
713
714// AsExpr converts a Quantifier to an Expr
715func (q *Quantifier) AsExpr() *Expr {
716 return newExpr(q.ctx, q.ptr)
717}
718
719// IsUniversal returns true if this is a universal quantifier (forall)
720func (q *Quantifier) IsUniversal() bool {
721 return bool(C.Z3_is_quantifier_forall(q.ctx.ptr, q.ptr))
722}
723
724// IsExistential returns true if this is an existential quantifier (exists)
725func (q *Quantifier) IsExistential() bool {
726 return bool(C.Z3_is_quantifier_exists(q.ctx.ptr, q.ptr))
727}
728
729// GetWeight returns the weight of the quantifier
730func (q *Quantifier) GetWeight() int {
731 return int(C.Z3_get_quantifier_weight(q.ctx.ptr, q.ptr))
732}
733
734// GetNumPatterns returns the number of patterns
735func (q *Quantifier) GetNumPatterns() int {
736 return int(C.Z3_get_quantifier_num_patterns(q.ctx.ptr, q.ptr))
737}
738
739// GetPattern returns the pattern at the given index
740func (q *Quantifier) GetPattern(idx int) *Pattern {
741 ptr := C.Z3_get_quantifier_pattern_ast(q.ctx.ptr, q.ptr, C.uint(idx))
742 return newPattern(q.ctx, ptr)
743}
744
745// GetNumNoPatterns returns the number of no-patterns
746func (q *Quantifier) GetNumNoPatterns() int {
747 return int(C.Z3_get_quantifier_num_no_patterns(q.ctx.ptr, q.ptr))
748}
749
750// GetNoPattern returns the no-pattern at the given index
751func (q *Quantifier) GetNoPattern(idx int) *Pattern {
752 ptr := C.Z3_get_quantifier_no_pattern_ast(q.ctx.ptr, q.ptr, C.uint(idx))
753 return newPattern(q.ctx, (C.Z3_pattern)(unsafe.Pointer(ptr)))
754}
755
756// GetNumBound returns the number of bound variables
757func (q *Quantifier) GetNumBound() int {
758 return int(C.Z3_get_quantifier_num_bound(q.ctx.ptr, q.ptr))
759}
760
761// GetBoundName returns the name of the bound variable at the given index
762func (q *Quantifier) GetBoundName(idx int) *Symbol {
763 ptr := C.Z3_get_quantifier_bound_name(q.ctx.ptr, q.ptr, C.uint(idx))
764 return newSymbol(q.ctx, ptr)
765}
766
767// GetBoundSort returns the sort of the bound variable at the given index
768func (q *Quantifier) GetBoundSort(idx int) *Sort {
769 ptr := C.Z3_get_quantifier_bound_sort(q.ctx.ptr, q.ptr, C.uint(idx))
770 return newSort(q.ctx, ptr)
771}
772
773// GetBody returns the body of the quantifier
774func (q *Quantifier) GetBody() *Expr {
775 ptr := C.Z3_get_quantifier_body(q.ctx.ptr, q.ptr)
776 return newExpr(q.ctx, ptr)
777}
778
779// String returns the string representation of the quantifier
780func (q *Quantifier) String() string {
781 return q.AsExpr().String()
782}
783
784// MkQuantifier creates a quantifier with patterns
785func (c *Context) MkQuantifier(isForall bool, weight int, sorts []*Sort, names []*Symbol, body *Expr, patterns []*Pattern) *Quantifier {
786 forallInt := C.bool(isForall)
787
788 numBound := len(sorts)
789 if numBound != len(names) {
790 panic("Number of sorts must match number of names")
791 }
792
793 var cSorts []C.Z3_sort
794 var cNames []C.Z3_symbol
795 if numBound > 0 {
796 cSorts = make([]C.Z3_sort, numBound)
797 cNames = make([]C.Z3_symbol, numBound)
798 for i := 0; i < numBound; i++ {
799 cSorts[i] = sorts[i].ptr
800 cNames[i] = names[i].ptr
801 }
802 }
803
804 var cPatterns []C.Z3_pattern
805 var patternsPtr *C.Z3_pattern
806 numPatterns := len(patterns)
807 if numPatterns > 0 {
808 cPatterns = make([]C.Z3_pattern, numPatterns)
809 for i := 0; i < numPatterns; i++ {
810 cPatterns[i] = patterns[i].ptr
811 }
812 patternsPtr = &cPatterns[0]
813 }
814
815 var sortsPtr *C.Z3_sort
816 var namesPtr *C.Z3_symbol
817 if numBound > 0 {
818 sortsPtr = &cSorts[0]
819 namesPtr = &cNames[0]
820 }
821
822 ptr := C.Z3_mk_quantifier(c.ptr, forallInt, C.uint(weight), C.uint(numPatterns), patternsPtr,
823 C.uint(numBound), sortsPtr, namesPtr, body.ptr)
824 return newQuantifier(c, ptr)
825}
826
827// MkQuantifierConst creates a quantifier using constant bound variables
828func (c *Context) MkQuantifierConst(isForall bool, weight int, bound []*Expr, body *Expr, patterns []*Pattern) *Quantifier {
829 forallInt := C.bool(isForall)
830
831 numBound := len(bound)
832 var cBound []C.Z3_app
833 var boundPtr *C.Z3_app
834 if numBound > 0 {
835 cBound = make([]C.Z3_app, numBound)
836 for i := 0; i < numBound; i++ {
837 cBound[i] = (C.Z3_app)(unsafe.Pointer(bound[i].ptr))
838 }
839 boundPtr = &cBound[0]
840 }
841
842 var cPatterns []C.Z3_pattern
843 var patternsPtr *C.Z3_pattern
844 numPatterns := len(patterns)
845 if numPatterns > 0 {
846 cPatterns = make([]C.Z3_pattern, numPatterns)
847 for i := 0; i < numPatterns; i++ {
848 cPatterns[i] = patterns[i].ptr
849 }
850 patternsPtr = &cPatterns[0]
851 }
852
853 ptr := C.Z3_mk_quantifier_const(c.ptr, forallInt, C.uint(weight), C.uint(numBound), boundPtr,
854 C.uint(numPatterns), patternsPtr, body.ptr)
855 return newQuantifier(c, ptr)
856}
857
858// Lambda represents a lambda expression
859type Lambda struct {
860 ctx *Context
861 ptr C.Z3_ast
862}
863
864// newLambda creates a new Lambda with proper memory management
865func newLambda(ctx *Context, ptr C.Z3_ast) *Lambda {
866 l := &Lambda{ctx: ctx, ptr: ptr}
867 C.Z3_inc_ref(ctx.ptr, ptr)
868 runtime.SetFinalizer(l, func(lam *Lambda) {
869 C.Z3_dec_ref(lam.ctx.ptr, lam.ptr)
870 })
871 return l
872}
873
874// AsExpr converts a Lambda to an Expr
875func (l *Lambda) AsExpr() *Expr {
876 return newExpr(l.ctx, l.ptr)
877}
878
879// GetNumBound returns the number of bound variables
880func (l *Lambda) GetNumBound() int {
881 return int(C.Z3_get_quantifier_num_bound(l.ctx.ptr, l.ptr))
882}
883
884// GetBoundName returns the name of the bound variable at the given index
885func (l *Lambda) GetBoundName(idx int) *Symbol {
886 ptr := C.Z3_get_quantifier_bound_name(l.ctx.ptr, l.ptr, C.uint(idx))
887 return newSymbol(l.ctx, ptr)
888}
889
890// GetBoundSort returns the sort of the bound variable at the given index
891func (l *Lambda) GetBoundSort(idx int) *Sort {
892 ptr := C.Z3_get_quantifier_bound_sort(l.ctx.ptr, l.ptr, C.uint(idx))
893 return newSort(l.ctx, ptr)
894}
895
896// GetBody returns the body of the lambda expression
897func (l *Lambda) GetBody() *Expr {
898 ptr := C.Z3_get_quantifier_body(l.ctx.ptr, l.ptr)
899 return newExpr(l.ctx, ptr)
900}
901
902// String returns the string representation of the lambda
903func (l *Lambda) String() string {
904 return l.AsExpr().String()
905}
906
907// MkLambda creates a lambda expression with sorts and names
908func (c *Context) MkLambda(sorts []*Sort, names []*Symbol, body *Expr) *Lambda {
909 numBound := len(sorts)
910 if numBound != len(names) {
911 panic("Number of sorts must match number of names")
912 }
913
914 var cSorts []C.Z3_sort
915 var cNames []C.Z3_symbol
916 var sortsPtr *C.Z3_sort
917 var namesPtr *C.Z3_symbol
918
919 if numBound > 0 {
920 cSorts = make([]C.Z3_sort, numBound)
921 cNames = make([]C.Z3_symbol, numBound)
922 for i := 0; i < numBound; i++ {
923 cSorts[i] = sorts[i].ptr
924 cNames[i] = names[i].ptr
925 }
926 sortsPtr = &cSorts[0]
927 namesPtr = &cNames[0]
928 }
929
930 ptr := C.Z3_mk_lambda(c.ptr, C.uint(numBound), sortsPtr, namesPtr, body.ptr)
931 return newLambda(c, ptr)
932}
933
934// MkLambdaConst creates a lambda expression using constant bound variables
935func (c *Context) MkLambdaConst(bound []*Expr, body *Expr) *Lambda {
936 numBound := len(bound)
937 var cBound []C.Z3_app
938 var boundPtr *C.Z3_app
939
940 if numBound > 0 {
941 cBound = make([]C.Z3_app, numBound)
942 for i := 0; i < numBound; i++ {
943 cBound[i] = (C.Z3_app)(unsafe.Pointer(bound[i].ptr))
944 }
945 boundPtr = &cBound[0]
946 }
947
948 ptr := C.Z3_mk_lambda_const(c.ptr, C.uint(numBound), boundPtr, body.ptr)
949 return newLambda(c, ptr)
950}
951
952// SetGlobalParam sets a global Z3 parameter.
953func SetGlobalParam(id, value string) {
954 cID := C.CString(id)
955 cValue := C.CString(value)
956 defer C.free(unsafe.Pointer(cID))
957 defer C.free(unsafe.Pointer(cValue))
958 C.Z3_global_param_set(cID, cValue)
959}
960
961// GetGlobalParam retrieves the value of a global Z3 parameter.
962// Returns the value and true if the parameter exists, or empty string and false otherwise.
963func GetGlobalParam(id string) (string, bool) {
964 cID := C.CString(id)
965 defer C.free(unsafe.Pointer(cID))
966 var cValue C.Z3_string
967 ok := C.Z3_global_param_get(cID, &cValue)
968 if ok == C.bool(false) {
969 return "", false
970 }
971 return C.GoString(cValue), true
972}
973
974// ResetAllGlobalParams resets all global Z3 parameters to their default values.
975func ResetAllGlobalParams() {
976 C.Z3_global_param_reset_all()
977}
978
979// astVectorToExprs converts a Z3_ast_vector to a slice of Expr.
980// This function properly manages the reference count of the vector by
981// incrementing it on entry and decrementing it on exit.
982// The individual AST elements are already reference counted by newExpr.
983func astVectorToExprs(ctx *Context, vec C.Z3_ast_vector) []*Expr {
984 // Increment reference count for the vector since we're using it
985 C.Z3_ast_vector_inc_ref(ctx.ptr, vec)
986 defer C.Z3_ast_vector_dec_ref(ctx.ptr, vec)
987
988 size := uint(C.Z3_ast_vector_size(ctx.ptr, vec))
989 result := make([]*Expr, size)
990 for i := uint(0); i < size; i++ {
991 result[i] = newExpr(ctx, C.Z3_ast_vector_get(ctx.ptr, vec, C.uint(i)))
992 }
993 return result
994}