3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2026-02-17 14:21:45 +00:00
z3/src/api/go/tactic.go
2026-02-15 21:24:40 -08:00

294 lines
8.7 KiB
Go

package z3
/*
#include "z3.h"
#include <stdlib.h>
*/
import "C"
import (
"runtime"
"unsafe"
)
// Tactic represents a Z3 tactic for transforming goals.
type Tactic struct {
ctx *Context
ptr C.Z3_tactic
}
// newTactic creates a new Tactic and manages its reference count.
func newTactic(ctx *Context, ptr C.Z3_tactic) *Tactic {
t := &Tactic{ctx: ctx, ptr: ptr}
C.Z3_tactic_inc_ref(ctx.ptr, ptr)
runtime.SetFinalizer(t, func(tactic *Tactic) {
C.Z3_tactic_dec_ref(tactic.ctx.ptr, tactic.ptr)
})
return t
}
// MkTactic creates a tactic with the given name.
func (c *Context) MkTactic(name string) *Tactic {
cName := C.CString(name)
defer C.free(unsafe.Pointer(cName))
return newTactic(c, C.Z3_mk_tactic(c.ptr, cName))
}
// Apply applies the tactic to a goal.
func (t *Tactic) Apply(g *Goal) *ApplyResult {
return newApplyResult(t.ctx, C.Z3_tactic_apply(t.ctx.ptr, t.ptr, g.ptr))
}
// GetHelp returns help information for the tactic.
func (t *Tactic) GetHelp() string {
return C.GoString(C.Z3_tactic_get_help(t.ctx.ptr, t.ptr))
}
// AndThen creates a tactic that applies t1 and then t2.
func (t *Tactic) AndThen(t2 *Tactic) *Tactic {
return newTactic(t.ctx, C.Z3_tactic_and_then(t.ctx.ptr, t.ptr, t2.ptr))
}
// OrElse creates a tactic that applies t1, and if it fails, applies t2.
func (t *Tactic) OrElse(t2 *Tactic) *Tactic {
return newTactic(t.ctx, C.Z3_tactic_or_else(t.ctx.ptr, t.ptr, t2.ptr))
}
// Repeat creates a tactic that applies t repeatedly (at most max times).
func (t *Tactic) Repeat(max uint) *Tactic {
return newTactic(t.ctx, C.Z3_tactic_repeat(t.ctx.ptr, t.ptr, C.uint(max)))
}
// When creates a conditional tactic that applies t only if probe p evaluates to true.
func (c *Context) TacticWhen(p *Probe, t *Tactic) *Tactic {
return newTactic(c, C.Z3_tactic_when(c.ptr, p.ptr, t.ptr))
}
// TacticCond creates a conditional tactic: if p then t1 else t2.
func (c *Context) TacticCond(p *Probe, t1, t2 *Tactic) *Tactic {
return newTactic(c, C.Z3_tactic_cond(c.ptr, p.ptr, t1.ptr, t2.ptr))
}
// TacticFail creates a tactic that always fails.
func (c *Context) TacticFail() *Tactic {
return newTactic(c, C.Z3_tactic_fail(c.ptr))
}
// TacticSkip creates a tactic that always succeeds.
func (c *Context) TacticSkip() *Tactic {
return newTactic(c, C.Z3_tactic_skip(c.ptr))
}
// Goal represents a set of formulas that can be solved or transformed.
type Goal struct {
ctx *Context
ptr C.Z3_goal
}
// newGoal creates a new Goal and manages its reference count.
func newGoal(ctx *Context, ptr C.Z3_goal) *Goal {
g := &Goal{ctx: ctx, ptr: ptr}
C.Z3_goal_inc_ref(ctx.ptr, ptr)
runtime.SetFinalizer(g, func(goal *Goal) {
C.Z3_goal_dec_ref(goal.ctx.ptr, goal.ptr)
})
return g
}
// MkGoal creates a new goal.
func (c *Context) MkGoal(models, unsatCores, proofs bool) *Goal {
return newGoal(c, C.Z3_mk_goal(c.ptr, C.bool(models), C.bool(unsatCores), C.bool(proofs)))
}
// Assert adds a constraint to the goal.
func (g *Goal) Assert(constraint *Expr) {
C.Z3_goal_assert(g.ctx.ptr, g.ptr, constraint.ptr)
}
// Size returns the number of formulas in the goal.
func (g *Goal) Size() uint {
return uint(C.Z3_goal_size(g.ctx.ptr, g.ptr))
}
// Formula returns the i-th formula in the goal.
func (g *Goal) Formula(i uint) *Expr {
return newExpr(g.ctx, C.Z3_goal_formula(g.ctx.ptr, g.ptr, C.uint(i)))
}
// NumExprs returns the number of expressions in the goal.
func (g *Goal) NumExprs() uint {
return uint(C.Z3_goal_num_exprs(g.ctx.ptr, g.ptr))
}
// IsDecidedSat returns true if the goal is decided to be satisfiable.
func (g *Goal) IsDecidedSat() bool {
return bool(C.Z3_goal_is_decided_sat(g.ctx.ptr, g.ptr))
}
// IsDecidedUnsat returns true if the goal is decided to be unsatisfiable.
func (g *Goal) IsDecidedUnsat() bool {
return bool(C.Z3_goal_is_decided_unsat(g.ctx.ptr, g.ptr))
}
// Reset removes all formulas from the goal.
func (g *Goal) Reset() {
C.Z3_goal_reset(g.ctx.ptr, g.ptr)
}
// String returns the string representation of the goal.
func (g *Goal) String() string {
return C.GoString(C.Z3_goal_to_string(g.ctx.ptr, g.ptr))
}
// ApplyResult represents the result of applying a tactic to a goal.
type ApplyResult struct {
ctx *Context
ptr C.Z3_apply_result
}
// newApplyResult creates a new ApplyResult and manages its reference count.
func newApplyResult(ctx *Context, ptr C.Z3_apply_result) *ApplyResult {
ar := &ApplyResult{ctx: ctx, ptr: ptr}
C.Z3_apply_result_inc_ref(ctx.ptr, ptr)
runtime.SetFinalizer(ar, func(result *ApplyResult) {
C.Z3_apply_result_dec_ref(result.ctx.ptr, result.ptr)
})
return ar
}
// NumSubgoals returns the number of subgoals in the result.
func (ar *ApplyResult) NumSubgoals() uint {
return uint(C.Z3_apply_result_get_num_subgoals(ar.ctx.ptr, ar.ptr))
}
// Subgoal returns the i-th subgoal.
func (ar *ApplyResult) Subgoal(i uint) *Goal {
return newGoal(ar.ctx, C.Z3_apply_result_get_subgoal(ar.ctx.ptr, ar.ptr, C.uint(i)))
}
// String returns the string representation of the apply result.
func (ar *ApplyResult) String() string {
return C.GoString(C.Z3_apply_result_to_string(ar.ctx.ptr, ar.ptr))
}
// Probe represents a probe for checking properties of goals.
type Probe struct {
ctx *Context
ptr C.Z3_probe
}
// newProbe creates a new Probe and manages its reference count.
func newProbe(ctx *Context, ptr C.Z3_probe) *Probe {
p := &Probe{ctx: ctx, ptr: ptr}
C.Z3_probe_inc_ref(ctx.ptr, ptr)
runtime.SetFinalizer(p, func(probe *Probe) {
C.Z3_probe_dec_ref(probe.ctx.ptr, probe.ptr)
})
return p
}
// MkProbe creates a probe with the given name.
func (c *Context) MkProbe(name string) *Probe {
cName := C.CString(name)
defer C.free(unsafe.Pointer(cName))
return newProbe(c, C.Z3_mk_probe(c.ptr, cName))
}
// Apply evaluates the probe on a goal.
func (p *Probe) Apply(g *Goal) float64 {
return float64(C.Z3_probe_apply(p.ctx.ptr, p.ptr, g.ptr))
}
// ProbeConst creates a probe that always evaluates to the given value.
func (c *Context) ProbeConst(val float64) *Probe {
return newProbe(c, C.Z3_probe_const(c.ptr, C.double(val)))
}
// ProbeLt creates a probe that evaluates to true if p1 < p2.
func (p *Probe) Lt(p2 *Probe) *Probe {
return newProbe(p.ctx, C.Z3_probe_lt(p.ctx.ptr, p.ptr, p2.ptr))
}
// ProbeGt creates a probe that evaluates to true if p1 > p2.
func (p *Probe) Gt(p2 *Probe) *Probe {
return newProbe(p.ctx, C.Z3_probe_gt(p.ctx.ptr, p.ptr, p2.ptr))
}
// ProbeLe creates a probe that evaluates to true if p1 <= p2.
func (p *Probe) Le(p2 *Probe) *Probe {
return newProbe(p.ctx, C.Z3_probe_le(p.ctx.ptr, p.ptr, p2.ptr))
}
// ProbeGe creates a probe that evaluates to true if p1 >= p2.
func (p *Probe) Ge(p2 *Probe) *Probe {
return newProbe(p.ctx, C.Z3_probe_ge(p.ctx.ptr, p.ptr, p2.ptr))
}
// ProbeEq creates a probe that evaluates to true if p1 == p2.
func (p *Probe) Eq(p2 *Probe) *Probe {
return newProbe(p.ctx, C.Z3_probe_eq(p.ctx.ptr, p.ptr, p2.ptr))
}
// ProbeAnd creates a probe that is the conjunction of p1 and p2.
func (p *Probe) And(p2 *Probe) *Probe {
return newProbe(p.ctx, C.Z3_probe_and(p.ctx.ptr, p.ptr, p2.ptr))
}
// ProbeOr creates a probe that is the disjunction of p1 and p2.
func (p *Probe) Or(p2 *Probe) *Probe {
return newProbe(p.ctx, C.Z3_probe_or(p.ctx.ptr, p.ptr, p2.ptr))
}
// ProbeNot creates a probe that is the negation of p.
func (p *Probe) Not() *Probe {
return newProbe(p.ctx, C.Z3_probe_not(p.ctx.ptr, p.ptr))
}
// Params represents a parameter set.
type Params struct {
ctx *Context
ptr C.Z3_params
}
// newParams creates a new Params and manages its reference count.
func newParams(ctx *Context, ptr C.Z3_params) *Params {
params := &Params{ctx: ctx, ptr: ptr}
C.Z3_params_inc_ref(ctx.ptr, ptr)
runtime.SetFinalizer(params, func(p *Params) {
C.Z3_params_dec_ref(p.ctx.ptr, p.ptr)
})
return params
}
// MkParams creates a new parameter set.
func (c *Context) MkParams() *Params {
return newParams(c, C.Z3_mk_params(c.ptr))
}
// SetBool sets a Boolean parameter.
func (p *Params) SetBool(key string, value bool) {
sym := p.ctx.MkStringSymbol(key)
C.Z3_params_set_bool(p.ctx.ptr, p.ptr, sym.ptr, C.bool(value))
}
// SetUint sets an unsigned integer parameter.
func (p *Params) SetUint(key string, value uint) {
sym := p.ctx.MkStringSymbol(key)
C.Z3_params_set_uint(p.ctx.ptr, p.ptr, sym.ptr, C.uint(value))
}
// SetDouble sets a double parameter.
func (p *Params) SetDouble(key string, value float64) {
sym := p.ctx.MkStringSymbol(key)
C.Z3_params_set_double(p.ctx.ptr, p.ptr, sym.ptr, C.double(value))
}
// SetSymbol sets a symbol parameter.
func (p *Params) SetSymbol(key string, value *Symbol) {
sym := p.ctx.MkStringSymbol(key)
C.Z3_params_set_symbol(p.ctx.ptr, p.ptr, sym.ptr, value.ptr)
}
// String returns the string representation of the parameters.
func (p *Params) String() string {
return C.GoString(C.Z3_params_to_string(p.ctx.ptr, p.ptr))
}