# Z3 Go Bindings

This directory contains Go language bindings for the Z3 theorem prover.

## Overview

The Go bindings provide a comprehensive interface to Z3's C API using CGO. The bindings support:

- **Core Z3 Types**: Context, Config, Symbol, AST, Sort, Expr, FuncDecl
- **Solver Operations**: Creating solvers, asserting constraints, checking satisfiability
- **Model Manipulation**: Extracting and evaluating models
- **Boolean Logic**: And, Or, Not, Implies, Iff, Xor
- **Arithmetic**: Add, Sub, Mul, Div, Mod, comparison operators
- **Bit-vectors**: Full bit-vector arithmetic, bitwise operations, shifts, comparisons
- **Floating Point**: IEEE 754 floating-point arithmetic with rounding modes
- **Arrays**: Select, Store, constant arrays
- **Sequences/Strings**: String operations, concatenation, contains, indexing
- **Regular Expressions**: Pattern matching, Kleene star/plus, regex operations
- **Quantifiers**: Forall, Exists
- **Functions**: Function declarations and applications
- **Tactics & Goals**: Goal-based solving and tactic combinators
- **Probes**: Goal property checking
- **Datatypes**: Algebraic datatypes, tuples, enumerations, lists
- **Parameters**: Solver and tactic configuration
- **Optimize**: Optimization problems with maximize/minimize objectives

## Building

### Prerequisites

- Go 1.20 or later
- Z3 library built and installed
- CGO enabled

### With CMake

```bash
mkdir build && cd build
cmake -DBUILD_GO_BINDINGS=ON ..
make
```

### With Python Build System

```bash
python scripts/mk_make.py --go
cd build
make
```

## Usage

### Basic Example

```go
package main

import (
    "fmt"
    "github.com/Z3Prover/z3/src/api/go"
)

func main() {
    // Create a context
    ctx := z3.NewContext()
    
    // Create variables
    x := ctx.MkIntConst("x")
    y := ctx.MkIntConst("y")
    
    // Create constraints: x + y == 10 && x > y
    ten := ctx.MkInt(10, ctx.MkIntSort())
    eq := ctx.MkEq(ctx.MkAdd(x, y), ten)
    gt := ctx.MkGt(x, y)
    
    // Create solver and check
    solver := ctx.NewSolver()
    solver.Assert(eq)
    solver.Assert(gt)
    
    if solver.Check() == z3.Satisfiable {
        model := solver.Model()
        if xVal, ok := model.Eval(x, true); ok {
            fmt.Println("x =", xVal.String())
        }
        if yVal, ok := model.Eval(y, true); ok {
            fmt.Println("y =", yVal.String())
        }
    }
}
```

### Running Examples

```bash
cd examples/go

# Set library path (Linux/Mac)
export LD_LIBRARY_PATH=../../build:$LD_LIBRARY_PATH
export CGO_CFLAGS="-I../../src/api"
export CGO_LDFLAGS="-L../../build -lz3"

# Set library path (Windows)
set PATH=..\..\build;%PATH%
set CGO_CFLAGS=-I../../src/api
set CGO_LDFLAGS=-L../../build -lz3

# Run example
go run basic_example.go
```

## API Reference

### Context

- `NewContext()` - Create a new Z3 context
- `NewContextWithConfig(cfg *Config)` - Create context with configuration
- `SetParam(key, value string)` - Set context parameters

### Creating Expressions

- `MkBoolConst(name string)` - Create Boolean variable
- `MkIntConst(name string)` - Create integer variable
- `MkRealConst(name string)` - Create real variable
- `MkInt(value int, sort *Sort)` - Create integer constant
- `MkReal(num, den int)` - Create rational constant

### Boolean Operations

- `MkAnd(exprs ...*Expr)` - Conjunction
- `MkOr(exprs ...*Expr)` - Disjunction
- `MkNot(expr *Expr)` - Negation
- `MkImplies(lhs, rhs *Expr)` - Implication
- `MkIff(lhs, rhs *Expr)` - If-and-only-if
- `MkXor(lhs, rhs *Expr)` - Exclusive or

### Arithmetic Operations

- `MkAdd(exprs ...*Expr)` - Addition
- `MkSub(exprs ...*Expr)` - Subtraction
- `MkMul(exprs ...*Expr)` - Multiplication
- `MkDiv(lhs, rhs *Expr)` - Division
- `MkMod(lhs, rhs *Expr)` - Modulo
- `MkRem(lhs, rhs *Expr)` - Remainder

### Comparison Operations

- `MkEq(lhs, rhs *Expr)` - Equality
- `MkDistinct(exprs ...*Expr)` - Distinct
- `MkLt(lhs, rhs *Expr)` - Less than
- `MkLe(lhs, rhs *Expr)` - Less than or equal
- `MkGt(lhs, rhs *Expr)` - Greater than
- `MkGe(lhs, rhs *Expr)` - Greater than or equal

### Solver Operations

- `NewSolver()` - Create a new solver
- `Assert(constraint *Expr)` - Add constraint
- `Check()` - Check satisfiability (returns Satisfiable, Unsatisfiable, or Unknown)
- `Model()` - Get model (if satisfiable)
- `Push()` - Create backtracking point
- `Pop(n uint)` - Remove backtracking points
- `Reset()` - Remove all assertions

### Model Operations

- `Eval(expr *Expr, modelCompletion bool)` - Evaluate expression in model
- `NumConsts()` - Number of constants in model
- `NumFuncs()` - Number of functions in model
- `String()` - Get string representation

### Bit-vector Operations

- `MkBvSort(sz uint)` - Create bit-vector sort
- `MkBVConst(name string, size uint)` - Create bit-vector variable
- `MkBVAdd/Sub/Mul/UDiv/SDiv(lhs, rhs *Expr)` - Arithmetic operations
- `MkBVAnd/Or/Xor/Not(...)` - Bitwise operations
- `MkBVShl/LShr/AShr(lhs, rhs *Expr)` - Shift operations
- `MkBVULT/SLT/ULE/SLE/UGE/SGE/UGT/SGT(...)` - Comparisons
- `MkConcat(lhs, rhs *Expr)` - Bit-vector concatenation
- `MkExtract(high, low uint, expr *Expr)` - Extract bits
- `MkSignExt/ZeroExt(i uint, expr *Expr)` - Extend bit-vectors

### Floating-Point Operations

- `MkFPSort(ebits, sbits uint)` - Create floating-point sort
- `MkFPSort16/32/64/128()` - Standard IEEE 754 sorts
- `MkFPInf/NaN/Zero(sort *Sort, ...)` - Special values
- `MkFPAdd/Sub/Mul/Div(rm, lhs, rhs *Expr)` - Arithmetic with rounding
- `MkFPNeg/Abs/Sqrt(...)` - Unary operations
- `MkFPLT/GT/LE/GE/Eq(lhs, rhs *Expr)` - Comparisons
- `MkFPIsNaN/IsInf/IsZero(expr *Expr)` - Predicates

### Sequence/String Operations

- `MkStringSort()` - Create string sort
- `MkSeqSort(elemSort *Sort)` - Create sequence sort
- `MkString(value string)` - Create string constant
- `MkSeqConcat(exprs ...*Expr)` - Concatenation
- `MkSeqLength(seq *Expr)` - Length
- `MkSeqPrefix/Suffix/Contains(...)` - Predicates
- `MkSeqAt(seq, index *Expr)` - Element access
- `MkSeqExtract(seq, offset, length *Expr)` - Substring
- `MkStrToInt/IntToStr(...)` - Conversions

### Regular Expression Operations

- `MkReSort(seqSort *Sort)` - Create regex sort
- `MkToRe(seq *Expr)` - Convert string to regex
- `MkInRe(seq, re *Expr)` - String matches regex predicate
- `MkReStar(re *Expr)` - Kleene star (zero or more)
- `MkRePlus(re *Expr)` - Kleene plus (one or more)
- `MkReOption(re *Expr)` - Optional (zero or one)
- `MkRePower(re *Expr, n uint)` - Exactly n repetitions
- `MkReLoop(re *Expr, lo, hi uint)` - Bounded repetition
- `MkReConcat(regexes ...*Expr)` - Concatenation
- `MkReUnion(regexes ...*Expr)` - Alternation (OR)
- `MkReIntersect(regexes ...*Expr)` - Intersection
- `MkReComplement(re *Expr)` - Complement
- `MkReDiff(a, b *Expr)` - Difference
- `MkReEmpty/Full/Allchar(sort *Sort)` - Special regexes
- `MkReRange(lo, hi *Expr)` - Character range
- `MkSeqReplaceRe/ReAll(seq, re, replacement *Expr)` - Regex replace

### Datatype Operations

- `MkConstructor(name, recognizer string, ...)` - Create constructor
- `MkDatatypeSort(name string, constructors []*Constructor)` - Create datatype
- `MkDatatypeSorts(names []string, ...)` - Mutually recursive datatypes
- `MkTupleSort(name string, fieldNames []string, fieldSorts []*Sort)` - Tuples
- `MkEnumSort(name string, enumNames []string)` - Enumerations
- `MkListSort(name string, elemSort *Sort)` - Lists

### Tactic Operations

- `MkTactic(name string)` - Create tactic by name
- `MkGoal(models, unsatCores, proofs bool)` - Create goal
- `Apply(g *Goal)` - Apply tactic to goal
- `AndThen(t2 *Tactic)` - Sequential composition
- `OrElse(t2 *Tactic)` - Try first, fallback to second
- `Repeat(max uint)` - Repeat tactic
- `TacticWhen/Cond(...)` - Conditional tactics

### Probe Operations

- `MkProbe(name string)` - Create probe by name
- `Apply(g *Goal)` - Evaluate probe on goal
- `Lt/Gt/Le/Ge/Eq(p2 *Probe)` - Probe comparisons
- `And/Or/Not(...)` - Probe combinators

### Parameter Operations

- `MkParams()` - Create parameter set
- `SetBool/Uint/Double/Symbol(key string, value ...)` - Set parameters

### Optimize Operations

- `NewOptimize()` - Create optimization context
- `Assert(constraint *Expr)` - Add constraint
- `AssertSoft(constraint *Expr, weight, group string)` - Add soft constraint
- `Maximize(expr *Expr)` - Add maximization objective
- `Minimize(expr *Expr)` - Add minimization objective
- `Check(assumptions ...*Expr)` - Check and optimize
- `Model()` - Get optimal model
- `GetLower/Upper(index uint)` - Get objective bounds
- `Push/Pop()` - Backtracking
- `Assertions/Objectives()` - Get assertions and objectives
- `UnsatCore()` - Get unsat core

### Fixedpoint Operations (Datalog/CHC)

- `NewFixedpoint()` - Create fixedpoint solver
- `RegisterRelation(funcDecl *FuncDecl)` - Register predicate
- `AddRule(rule *Expr, name *Symbol)` - Add Horn clause
- `AddFact(pred *FuncDecl, args []int)` - Add table fact
- `Query(query *Expr)` - Query constraints
- `QueryRelations(relations []*FuncDecl)` - Query relations
- `GetAnswer()` - Get satisfying instance or proof
- `Push/Pop()` - Backtracking

### Quantifier Operations

- `MkQuantifier(isForall bool, weight int, sorts, names, body, patterns)` - Create quantifier
- `MkQuantifierConst(isForall bool, weight int, bound, body, patterns)` - Create with bound vars
- `IsUniversal/IsExistential()` - Check quantifier type
- `GetNumBound()` - Number of bound variables
- `GetBoundName/Sort(idx int)` - Get bound variable info
- `GetBody()` - Get quantifier body
- `GetNumPatterns()` - Number of patterns
- `GetPattern(idx int)` - Get pattern

### Lambda Operations

- `MkLambda(sorts, names, body)` - Create lambda expression
- `MkLambdaConst(bound, body)` - Create lambda with bound variables
- `GetNumBound()` - Number of bound variables
- `GetBoundName/Sort(idx int)` - Get bound variable info
- `GetBody()` - Get lambda body

### Type Variables

- `MkTypeVariable(name *Symbol)` - Create polymorphic type variable sort

### Logging

- `OpenLog(filename string)` - Open interaction log
- `CloseLog()` - Close log
- `AppendLog(s string)` - Append to log
- `IsLogOpen()` - Check if log is open

## Memory Management

The Go bindings use `runtime.SetFinalizer` to automatically manage Z3 reference counts. You don't need to manually call inc_ref/dec_ref. However, be aware that finalizers run during garbage collection, so resources may not be freed immediately.

## Thread Safety

Z3 contexts are not thread-safe. Each goroutine should use its own context, or use appropriate synchronization when sharing a context.

## License

Z3 is licensed under the MIT License. See LICENSE.txt in the repository root.

## Contributing

Bug reports and contributions are welcome! Please submit issues and pull requests to the main Z3 repository.

## References

- [Z3 GitHub Repository](https://github.com/Z3Prover/z3)
- [Z3 API Documentation](https://z3prover.github.io/api/html/index.html)
- [Z3 Guide](https://microsoft.github.io/z3guide/)
