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 runtime.SetFinalizer(ctx, func(c *Context) {
93 C.Z3_del_context(c.ptr)
94 })
95 return ctx
96}
97
98// NewContextWithConfig creates a new Z3 context with the given configuration.
99func NewContextWithConfig(cfg *Config) *Context {
100 ctx := &Context{ptr: C.Z3_mk_context_rc(cfg.ptr)}
101 runtime.SetFinalizer(ctx, func(c *Context) {
102 C.Z3_del_context(c.ptr)
103 })
104 return ctx
105}
106
107// SetParam sets a global or context parameter.
108func (c *Context) SetParam(key, value string) {
109 cKey := C.CString(key)
110 cValue := C.CString(value)
111 defer C.free(unsafe.Pointer(cKey))
112 defer C.free(unsafe.Pointer(cValue))
113 C.Z3_update_param_value(c.ptr, cKey, cValue)
114}
115
116// Symbol represents a Z3 symbol.
117type Symbol struct {
118 ctx *Context
119 ptr C.Z3_symbol
120}
121
122// newSymbol creates a new Symbol.
123func newSymbol(ctx *Context, ptr C.Z3_symbol) *Symbol {
124 return &Symbol{ctx: ctx, ptr: ptr}
125}
126
127// MkIntSymbol creates an integer symbol.
128func (c *Context) MkIntSymbol(i int) *Symbol {
129 return &Symbol{
130 ctx: c,
131 ptr: C.Z3_mk_int_symbol(c.ptr, C.int(i)),
132 }
133}
134
135// MkStringSymbol creates a string symbol.
136func (c *Context) MkStringSymbol(s string) *Symbol {
137 cStr := C.CString(s)
138 defer C.free(unsafe.Pointer(cStr))
139 return &Symbol{
140 ctx: c,
141 ptr: C.Z3_mk_string_symbol(c.ptr, cStr),
142 }
143}
144
145// String returns the string representation of the symbol.
146func (s *Symbol) String() string {
147 kind := C.Z3_get_symbol_kind(s.ctx.ptr, s.ptr)
148 if kind == C.Z3_INT_SYMBOL {
149 return string(rune(C.Z3_get_symbol_int(s.ctx.ptr, s.ptr)))
150 }
151 return C.GoString(C.Z3_get_symbol_string(s.ctx.ptr, s.ptr))
152}
153
154// AST represents a Z3 abstract syntax tree node.
155type AST struct {
156 ctx *Context
157 ptr C.Z3_ast
158}
159
160// incRef increments the reference count of the AST.
161func (a *AST) incRef() {
162 C.Z3_inc_ref(a.ctx.ptr, a.ptr)
163}
164
165// decRef decrements the reference count of the AST.
166func (a *AST) decRef() {
167 C.Z3_dec_ref(a.ctx.ptr, a.ptr)
168}
169
170// String returns the string representation of the AST.
171func (a *AST) String() string {
172 return C.GoString(C.Z3_ast_to_string(a.ctx.ptr, a.ptr))
173}
174
175// Hash returns the hash code of the AST.
176func (a *AST) Hash() uint32 {
177 return uint32(C.Z3_get_ast_hash(a.ctx.ptr, a.ptr))
178}
179
180// Equal checks if two ASTs are equal.
181func (a *AST) Equal(other *AST) bool {
182 if a.ctx != other.ctx {
183 return false
184 }
185 return bool(C.Z3_is_eq_ast(a.ctx.ptr, a.ptr, other.ptr))
186}
187
188// Sort represents a Z3 sort (type).
189type Sort struct {
190 ctx *Context
191 ptr C.Z3_sort
192}
193
194// newSort creates a new Sort and manages its reference count.
195func newSort(ctx *Context, ptr C.Z3_sort) *Sort {
196 sort := &Sort{ctx: ctx, ptr: ptr}
197 C.Z3_inc_ref(ctx.ptr, C.Z3_sort_to_ast(ctx.ptr, ptr))
198 runtime.SetFinalizer(sort, func(s *Sort) {
199 C.Z3_dec_ref(s.ctx.ptr, C.Z3_sort_to_ast(s.ctx.ptr, s.ptr))
200 })
201 return sort
202}
203
204// String returns the string representation of the sort.
205func (s *Sort) String() string {
206 return C.GoString(C.Z3_sort_to_string(s.ctx.ptr, s.ptr))
207}
208
209// Equal checks if two sorts are equal.
210func (s *Sort) Equal(other *Sort) bool {
211 if s.ctx != other.ctx {
212 return false
213 }
214 return bool(C.Z3_is_eq_sort(s.ctx.ptr, s.ptr, other.ptr))
215}
216
217// MkBoolSort creates the Boolean sort.
218func (c *Context) MkBoolSort() *Sort {
219 return newSort(c, C.Z3_mk_bool_sort(c.ptr))
220}
221
222// MkBvSort creates a bit-vector sort of the given size.
223func (c *Context) MkBvSort(sz uint) *Sort {
224 return newSort(c, C.Z3_mk_bv_sort(c.ptr, C.uint(sz)))
225}
226
227// Expr represents a Z3 expression.
228type Expr struct {
229 ctx *Context
230 ptr C.Z3_ast
231}
232
233// newExpr creates a new Expr and manages its reference count.
234func newExpr(ctx *Context, ptr C.Z3_ast) *Expr {
235 expr := &Expr{ctx: ctx, ptr: ptr}
236 C.Z3_inc_ref(ctx.ptr, ptr)
237 runtime.SetFinalizer(expr, func(e *Expr) {
238 C.Z3_dec_ref(e.ctx.ptr, e.ptr)
239 })
240 return expr
241}
242
243// String returns the string representation of the expression.
244func (e *Expr) String() string {
245 return C.GoString(C.Z3_ast_to_string(e.ctx.ptr, e.ptr))
246}
247
248// Equal checks if two expressions are equal.
249func (e *Expr) Equal(other *Expr) bool {
250 if e.ctx != other.ctx {
251 return false
252 }
253 return bool(C.Z3_is_eq_ast(e.ctx.ptr, e.ptr, other.ptr))
254}
255
256// GetSort returns the sort of the expression.
257func (e *Expr) GetSort() *Sort {
258 return newSort(e.ctx, C.Z3_get_sort(e.ctx.ptr, e.ptr))
259}
260
261// Pattern represents a Z3 pattern for quantifier instantiation.
262type Pattern struct {
263 ctx *Context
264 ptr C.Z3_pattern
265}
266
267// newPattern creates a new Pattern and manages its reference count.
268func newPattern(ctx *Context, ptr C.Z3_pattern) *Pattern {
269 p := &Pattern{ctx: ctx, ptr: ptr}
270 // Patterns are ASTs in the C API
271 C.Z3_inc_ref(ctx.ptr, (C.Z3_ast)(unsafe.Pointer(ptr)))
272 runtime.SetFinalizer(p, func(pat *Pattern) {
273 C.Z3_dec_ref(pat.ctx.ptr, (C.Z3_ast)(unsafe.Pointer(pat.ptr)))
274 })
275 return p
276}
277
278// ASTVector represents a vector of Z3 ASTs.
279type ASTVector struct {
280 ctx *Context
281 ptr C.Z3_ast_vector
282}
283
284// newASTVector creates a new ASTVector and manages its reference count.
285func newASTVector(ctx *Context, ptr C.Z3_ast_vector) *ASTVector {
286 v := &ASTVector{ctx: ctx, ptr: ptr}
287 C.Z3_ast_vector_inc_ref(ctx.ptr, ptr)
288 runtime.SetFinalizer(v, func(vec *ASTVector) {
289 C.Z3_ast_vector_dec_ref(vec.ctx.ptr, vec.ptr)
290 })
291 return v
292}
293
294// ParamDescrs represents parameter descriptions for Z3 objects.
295type ParamDescrs struct {
296 ctx *Context
297 ptr C.Z3_param_descrs
298}
299
300// newParamDescrs creates a new ParamDescrs and manages its reference count.
301func newParamDescrs(ctx *Context, ptr C.Z3_param_descrs) *ParamDescrs {
302 pd := &ParamDescrs{ctx: ctx, ptr: ptr}
303 C.Z3_param_descrs_inc_ref(ctx.ptr, ptr)
304 runtime.SetFinalizer(pd, func(descrs *ParamDescrs) {
305 C.Z3_param_descrs_dec_ref(descrs.ctx.ptr, descrs.ptr)
306 })
307 return pd
308}
309
310// MkTrue creates the Boolean constant true.
311func (c *Context) MkTrue() *Expr {
312 return newExpr(c, C.Z3_mk_true(c.ptr))
313}
314
315// MkFalse creates the Boolean constant false.
316func (c *Context) MkFalse() *Expr {
317 return newExpr(c, C.Z3_mk_false(c.ptr))
318}
319
320// MkBool creates a Boolean constant.
321func (c *Context) MkBool(value bool) *Expr {
322 if value {
323 return c.MkTrue()
324 }
325 return c.MkFalse()
326}
327
328// MkNumeral creates a numeral from a string.
329func (c *Context) MkNumeral(numeral string, sort *Sort) *Expr {
330 cStr := C.CString(numeral)
331 defer C.free(unsafe.Pointer(cStr))
332 return newExpr(c, C.Z3_mk_numeral(c.ptr, cStr, sort.ptr))
333}
334
335// MkConst creates a constant (variable) with the given name and sort.
336func (c *Context) MkConst(name *Symbol, sort *Sort) *Expr {
337 return newExpr(c, C.Z3_mk_const(c.ptr, name.ptr, sort.ptr))
338}
339
340// MkBoolConst creates a Boolean constant (variable) with the given name.
341func (c *Context) MkBoolConst(name string) *Expr {
342 sym := c.MkStringSymbol(name)
343 return c.MkConst(sym, c.MkBoolSort())
344}
345
346// Boolean operations
347
348// MkAnd creates a conjunction.
349func (c *Context) MkAnd(exprs ...*Expr) *Expr {
350 if len(exprs) == 0 {
351 return c.MkTrue()
352 }
353 if len(exprs) == 1 {
354 return exprs[0]
355 }
356 cExprs := make([]C.Z3_ast, len(exprs))
357 for i, e := range exprs {
358 cExprs[i] = e.ptr
359 }
360 return newExpr(c, C.Z3_mk_and(c.ptr, C.uint(len(exprs)), &cExprs[0]))
361}
362
363// MkOr creates a disjunction.
364func (c *Context) MkOr(exprs ...*Expr) *Expr {
365 if len(exprs) == 0 {
366 return c.MkFalse()
367 }
368 if len(exprs) == 1 {
369 return exprs[0]
370 }
371 cExprs := make([]C.Z3_ast, len(exprs))
372 for i, e := range exprs {
373 cExprs[i] = e.ptr
374 }
375 return newExpr(c, C.Z3_mk_or(c.ptr, C.uint(len(exprs)), &cExprs[0]))
376}
377
378// MkNot creates a negation.
379func (c *Context) MkNot(expr *Expr) *Expr {
380 return newExpr(c, C.Z3_mk_not(c.ptr, expr.ptr))
381}
382
383// MkImplies creates an implication.
384func (c *Context) MkImplies(lhs, rhs *Expr) *Expr {
385 return newExpr(c, C.Z3_mk_implies(c.ptr, lhs.ptr, rhs.ptr))
386}
387
388// MkIff creates a bi-implication (if and only if).
389func (c *Context) MkIff(lhs, rhs *Expr) *Expr {
390 return newExpr(c, C.Z3_mk_iff(c.ptr, lhs.ptr, rhs.ptr))
391}
392
393// MkXor creates exclusive or.
394func (c *Context) MkXor(lhs, rhs *Expr) *Expr {
395 return newExpr(c, C.Z3_mk_xor(c.ptr, lhs.ptr, rhs.ptr))
396}
397
398// Comparison operations
399
400// MkEq creates an equality.
401func (c *Context) MkEq(lhs, rhs *Expr) *Expr {
402 return newExpr(c, C.Z3_mk_eq(c.ptr, lhs.ptr, rhs.ptr))
403}
404
405// MkDistinct creates a distinct constraint.
406func (c *Context) MkDistinct(exprs ...*Expr) *Expr {
407 if len(exprs) <= 1 {
408 return c.MkTrue()
409 }
410 cExprs := make([]C.Z3_ast, len(exprs))
411 for i, e := range exprs {
412 cExprs[i] = e.ptr
413 }
414 return newExpr(c, C.Z3_mk_distinct(c.ptr, C.uint(len(exprs)), &cExprs[0]))
415}
416
417// FuncDecl represents a function declaration.
418type FuncDecl struct {
419 ctx *Context
420 ptr C.Z3_func_decl
421}
422
423// newFuncDecl creates a new FuncDecl and manages its reference count.
424func newFuncDecl(ctx *Context, ptr C.Z3_func_decl) *FuncDecl {
425 fd := &FuncDecl{ctx: ctx, ptr: ptr}
426 C.Z3_inc_ref(ctx.ptr, C.Z3_func_decl_to_ast(ctx.ptr, ptr))
427 runtime.SetFinalizer(fd, func(f *FuncDecl) {
428 C.Z3_dec_ref(f.ctx.ptr, C.Z3_func_decl_to_ast(f.ctx.ptr, f.ptr))
429 })
430 return fd
431}
432
433// String returns the string representation of the function declaration.
434func (f *FuncDecl) String() string {
435 return C.GoString(C.Z3_func_decl_to_string(f.ctx.ptr, f.ptr))
436}
437
438// GetName returns the name of the function declaration.
439func (f *FuncDecl) GetName() *Symbol {
440 return &Symbol{
441 ctx: f.ctx,
442 ptr: C.Z3_get_decl_name(f.ctx.ptr, f.ptr),
443 }
444}
445
446// GetArity returns the arity (number of parameters) of the function.
447func (f *FuncDecl) GetArity() int {
448 return int(C.Z3_get_arity(f.ctx.ptr, f.ptr))
449}
450
451// GetDomain returns the sort of the i-th parameter.
452func (f *FuncDecl) GetDomain(i int) *Sort {
453 return newSort(f.ctx, C.Z3_get_domain(f.ctx.ptr, f.ptr, C.uint(i)))
454}
455
456// GetRange returns the sort of the return value.
457func (f *FuncDecl) GetRange() *Sort {
458 return newSort(f.ctx, C.Z3_get_range(f.ctx.ptr, f.ptr))
459}
460
461// MkFuncDecl creates a function declaration.
462func (c *Context) MkFuncDecl(name *Symbol, domain []*Sort, range_ *Sort) *FuncDecl {
463 cDomain := make([]C.Z3_sort, len(domain))
464 for i, s := range domain {
465 cDomain[i] = s.ptr
466 }
467 var domainPtr *C.Z3_sort
468 if len(domain) > 0 {
469 domainPtr = &cDomain[0]
470 }
471 return newFuncDecl(c, C.Z3_mk_func_decl(c.ptr, name.ptr, C.uint(len(domain)), domainPtr, range_.ptr))
472}
473
474// MkApp creates a function application.
475func (c *Context) MkApp(decl *FuncDecl, args ...*Expr) *Expr {
476 cArgs := make([]C.Z3_ast, len(args))
477 for i, a := range args {
478 cArgs[i] = a.ptr
479 }
480 var argsPtr *C.Z3_ast
481 if len(args) > 0 {
482 argsPtr = &cArgs[0]
483 }
484 return newExpr(c, C.Z3_mk_app(c.ptr, decl.ptr, C.uint(len(args)), argsPtr))
485}
486
487// Quantifier operations
488
489// MkForall creates a universal quantifier.
490func (c *Context) MkForall(bound []*Expr, body *Expr) *Expr {
491 cBound := make([]C.Z3_app, len(bound))
492 for i, b := range bound {
493 // Z3_app is a subtype of Z3_ast; constants are apps
494 cBound[i] = (C.Z3_app)(unsafe.Pointer(b.ptr))
495 }
496 var boundPtr *C.Z3_app
497 if len(bound) > 0 {
498 boundPtr = &cBound[0]
499 }
500 return newExpr(c, C.Z3_mk_forall_const(c.ptr, 0, C.uint(len(bound)), boundPtr, 0, nil, body.ptr))
501}
502
503// MkExists creates an existential quantifier.
504func (c *Context) MkExists(bound []*Expr, body *Expr) *Expr {
505 cBound := make([]C.Z3_app, len(bound))
506 for i, b := range bound {
507 // Z3_app is a subtype of Z3_ast; constants are apps
508 cBound[i] = (C.Z3_app)(unsafe.Pointer(b.ptr))
509 }
510 var boundPtr *C.Z3_app
511 if len(bound) > 0 {
512 boundPtr = &cBound[0]
513 }
514 return newExpr(c, C.Z3_mk_exists_const(c.ptr, 0, C.uint(len(bound)), boundPtr, 0, nil, body.ptr))
515}
516
517// Simplify simplifies an expression.
518func (e *Expr) Simplify() *Expr {
519 return newExpr(e.ctx, C.Z3_simplify(e.ctx.ptr, e.ptr))
520}
521
522// MkTypeVariable creates a type variable sort for use in polymorphic functions and datatypes
523func (c *Context) MkTypeVariable(name *Symbol) *Sort {
524 return newSort(c, C.Z3_mk_type_variable(c.ptr, name.ptr))
525}
526
527// Quantifier represents a quantified formula (forall or exists)
528type Quantifier struct {
529 ctx *Context
530 ptr C.Z3_ast
531}
532
533// newQuantifier creates a new Quantifier with proper memory management
534func newQuantifier(ctx *Context, ptr C.Z3_ast) *Quantifier {
535 q := &Quantifier{ctx: ctx, ptr: ptr}
536 C.Z3_inc_ref(ctx.ptr, ptr)
537 runtime.SetFinalizer(q, func(qf *Quantifier) {
538 C.Z3_dec_ref(qf.ctx.ptr, qf.ptr)
539 })
540 return q
541}
542
543// AsExpr converts a Quantifier to an Expr
544func (q *Quantifier) AsExpr() *Expr {
545 return newExpr(q.ctx, q.ptr)
546}
547
548// IsUniversal returns true if this is a universal quantifier (forall)
549func (q *Quantifier) IsUniversal() bool {
550 return bool(C.Z3_is_quantifier_forall(q.ctx.ptr, q.ptr))
551}
552
553// IsExistential returns true if this is an existential quantifier (exists)
554func (q *Quantifier) IsExistential() bool {
555 return bool(C.Z3_is_quantifier_exists(q.ctx.ptr, q.ptr))
556}
557
558// GetWeight returns the weight of the quantifier
559func (q *Quantifier) GetWeight() int {
560 return int(C.Z3_get_quantifier_weight(q.ctx.ptr, q.ptr))
561}
562
563// GetNumPatterns returns the number of patterns
564func (q *Quantifier) GetNumPatterns() int {
565 return int(C.Z3_get_quantifier_num_patterns(q.ctx.ptr, q.ptr))
566}
567
568// GetPattern returns the pattern at the given index
569func (q *Quantifier) GetPattern(idx int) *Pattern {
570 ptr := C.Z3_get_quantifier_pattern_ast(q.ctx.ptr, q.ptr, C.uint(idx))
571 return newPattern(q.ctx, ptr)
572}
573
574// GetNumNoPatterns returns the number of no-patterns
575func (q *Quantifier) GetNumNoPatterns() int {
576 return int(C.Z3_get_quantifier_num_no_patterns(q.ctx.ptr, q.ptr))
577}
578
579// GetNoPattern returns the no-pattern at the given index
580func (q *Quantifier) GetNoPattern(idx int) *Pattern {
581 ptr := C.Z3_get_quantifier_no_pattern_ast(q.ctx.ptr, q.ptr, C.uint(idx))
582 return newPattern(q.ctx, (C.Z3_pattern)(unsafe.Pointer(ptr)))
583}
584
585// GetNumBound returns the number of bound variables
586func (q *Quantifier) GetNumBound() int {
587 return int(C.Z3_get_quantifier_num_bound(q.ctx.ptr, q.ptr))
588}
589
590// GetBoundName returns the name of the bound variable at the given index
591func (q *Quantifier) GetBoundName(idx int) *Symbol {
592 ptr := C.Z3_get_quantifier_bound_name(q.ctx.ptr, q.ptr, C.uint(idx))
593 return newSymbol(q.ctx, ptr)
594}
595
596// GetBoundSort returns the sort of the bound variable at the given index
597func (q *Quantifier) GetBoundSort(idx int) *Sort {
598 ptr := C.Z3_get_quantifier_bound_sort(q.ctx.ptr, q.ptr, C.uint(idx))
599 return newSort(q.ctx, ptr)
600}
601
602// GetBody returns the body of the quantifier
603func (q *Quantifier) GetBody() *Expr {
604 ptr := C.Z3_get_quantifier_body(q.ctx.ptr, q.ptr)
605 return newExpr(q.ctx, ptr)
606}
607
608// String returns the string representation of the quantifier
609func (q *Quantifier) String() string {
610 return q.AsExpr().String()
611}
612
613// MkQuantifier creates a quantifier with patterns
614func (c *Context) MkQuantifier(isForall bool, weight int, sorts []*Sort, names []*Symbol, body *Expr, patterns []*Pattern) *Quantifier {
615 var forallInt C.bool
616 if isForall {
617 forallInt = true
618 } else {
619 forallInt = false
620 }
621
622 numBound := len(sorts)
623 if numBound != len(names) {
624 panic("Number of sorts must match number of names")
625 }
626
627 var cSorts []C.Z3_sort
628 var cNames []C.Z3_symbol
629 if numBound > 0 {
630 cSorts = make([]C.Z3_sort, numBound)
631 cNames = make([]C.Z3_symbol, numBound)
632 for i := 0; i < numBound; i++ {
633 cSorts[i] = sorts[i].ptr
634 cNames[i] = names[i].ptr
635 }
636 }
637
638 var cPatterns []C.Z3_pattern
639 var patternsPtr *C.Z3_pattern
640 numPatterns := len(patterns)
641 if numPatterns > 0 {
642 cPatterns = make([]C.Z3_pattern, numPatterns)
643 for i := 0; i < numPatterns; i++ {
644 cPatterns[i] = patterns[i].ptr
645 }
646 patternsPtr = &cPatterns[0]
647 }
648
649 var sortsPtr *C.Z3_sort
650 var namesPtr *C.Z3_symbol
651 if numBound > 0 {
652 sortsPtr = &cSorts[0]
653 namesPtr = &cNames[0]
654 }
655
656 ptr := C.Z3_mk_quantifier(c.ptr, forallInt, C.uint(weight), C.uint(numPatterns), patternsPtr,
657 C.uint(numBound), sortsPtr, namesPtr, body.ptr)
658 return newQuantifier(c, ptr)
659}
660
661// MkQuantifierConst creates a quantifier using constant bound variables
662func (c *Context) MkQuantifierConst(isForall bool, weight int, bound []*Expr, body *Expr, patterns []*Pattern) *Quantifier {
663 var forallInt C.bool
664 if isForall {
665 forallInt = true
666 } else {
667 forallInt = false
668 }
669
670 numBound := len(bound)
671 var cBound []C.Z3_app
672 var boundPtr *C.Z3_app
673 if numBound > 0 {
674 cBound = make([]C.Z3_app, numBound)
675 for i := 0; i < numBound; i++ {
676 cBound[i] = (C.Z3_app)(unsafe.Pointer(bound[i].ptr))
677 }
678 boundPtr = &cBound[0]
679 }
680
681 var cPatterns []C.Z3_pattern
682 var patternsPtr *C.Z3_pattern
683 numPatterns := len(patterns)
684 if numPatterns > 0 {
685 cPatterns = make([]C.Z3_pattern, numPatterns)
686 for i := 0; i < numPatterns; i++ {
687 cPatterns[i] = patterns[i].ptr
688 }
689 patternsPtr = &cPatterns[0]
690 }
691
692 ptr := C.Z3_mk_quantifier_const(c.ptr, forallInt, C.uint(weight), C.uint(numBound), boundPtr,
693 C.uint(numPatterns), patternsPtr, body.ptr)
694 return newQuantifier(c, ptr)
695}
696
697// Lambda represents a lambda expression
698type Lambda struct {
699 ctx *Context
700 ptr C.Z3_ast
701}
702
703// newLambda creates a new Lambda with proper memory management
704func newLambda(ctx *Context, ptr C.Z3_ast) *Lambda {
705 l := &Lambda{ctx: ctx, ptr: ptr}
706 C.Z3_inc_ref(ctx.ptr, ptr)
707 runtime.SetFinalizer(l, func(lam *Lambda) {
708 C.Z3_dec_ref(lam.ctx.ptr, lam.ptr)
709 })
710 return l
711}
712
713// AsExpr converts a Lambda to an Expr
714func (l *Lambda) AsExpr() *Expr {
715 return newExpr(l.ctx, l.ptr)
716}
717
718// GetNumBound returns the number of bound variables
719func (l *Lambda) GetNumBound() int {
720 return int(C.Z3_get_quantifier_num_bound(l.ctx.ptr, l.ptr))
721}
722
723// GetBoundName returns the name of the bound variable at the given index
724func (l *Lambda) GetBoundName(idx int) *Symbol {
725 ptr := C.Z3_get_quantifier_bound_name(l.ctx.ptr, l.ptr, C.uint(idx))
726 return newSymbol(l.ctx, ptr)
727}
728
729// GetBoundSort returns the sort of the bound variable at the given index
730func (l *Lambda) GetBoundSort(idx int) *Sort {
731 ptr := C.Z3_get_quantifier_bound_sort(l.ctx.ptr, l.ptr, C.uint(idx))
732 return newSort(l.ctx, ptr)
733}
734
735// GetBody returns the body of the lambda expression
736func (l *Lambda) GetBody() *Expr {
737 ptr := C.Z3_get_quantifier_body(l.ctx.ptr, l.ptr)
738 return newExpr(l.ctx, ptr)
739}
740
741// String returns the string representation of the lambda
742func (l *Lambda) String() string {
743 return l.AsExpr().String()
744}
745
746// MkLambda creates a lambda expression with sorts and names
747func (c *Context) MkLambda(sorts []*Sort, names []*Symbol, body *Expr) *Lambda {
748 numBound := len(sorts)
749 if numBound != len(names) {
750 panic("Number of sorts must match number of names")
751 }
752
753 var cSorts []C.Z3_sort
754 var cNames []C.Z3_symbol
755 var sortsPtr *C.Z3_sort
756 var namesPtr *C.Z3_symbol
757
758 if numBound > 0 {
759 cSorts = make([]C.Z3_sort, numBound)
760 cNames = make([]C.Z3_symbol, numBound)
761 for i := 0; i < numBound; i++ {
762 cSorts[i] = sorts[i].ptr
763 cNames[i] = names[i].ptr
764 }
765 sortsPtr = &cSorts[0]
766 namesPtr = &cNames[0]
767 }
768
769 ptr := C.Z3_mk_lambda(c.ptr, C.uint(numBound), sortsPtr, namesPtr, body.ptr)
770 return newLambda(c, ptr)
771}
772
773// MkLambdaConst creates a lambda expression using constant bound variables
774func (c *Context) MkLambdaConst(bound []*Expr, body *Expr) *Lambda {
775 numBound := len(bound)
776 var cBound []C.Z3_app
777 var boundPtr *C.Z3_app
778
779 if numBound > 0 {
780 cBound = make([]C.Z3_app, numBound)
781 for i := 0; i < numBound; i++ {
782 cBound[i] = (C.Z3_app)(unsafe.Pointer(bound[i].ptr))
783 }
784 boundPtr = &cBound[0]
785 }
786
787 ptr := C.Z3_mk_lambda_const(c.ptr, C.uint(numBound), boundPtr, body.ptr)
788 return newLambda(c, ptr)
789}
790
791// astVectorToExprs converts a Z3_ast_vector to a slice of Expr.
792// This function properly manages the reference count of the vector by
793// incrementing it on entry and decrementing it on exit.
794// The individual AST elements are already reference counted by newExpr.
795func astVectorToExprs(ctx *Context, vec C.Z3_ast_vector) []*Expr {
796 // Increment reference count for the vector since we're using it
797 C.Z3_ast_vector_inc_ref(ctx.ptr, vec)
798 defer C.Z3_ast_vector_dec_ref(ctx.ptr, vec)
799
800 size := uint(C.Z3_ast_vector_size(ctx.ptr, vec))
801 result := make([]*Expr, size)
802 for i := uint(0); i < size; i++ {
803 result[i] = newExpr(ctx, C.Z3_ast_vector_get(ctx.ptr, vec, C.uint(i)))
804 }
805 return result
806}