13// Tactic represents a Z3 tactic for transforming goals.
19// newTactic creates a new Tactic and manages its reference count.
20func newTactic(ctx *Context, ptr C.Z3_tactic) *Tactic {
21 t := &Tactic{ctx: ctx, ptr: ptr}
22 C.Z3_tactic_inc_ref(ctx.ptr, ptr)
23 runtime.SetFinalizer(t, func(tactic *Tactic) {
24 C.Z3_tactic_dec_ref(tactic.ctx.ptr, tactic.ptr)
29// MkTactic creates a tactic with the given name.
30func (c *Context) MkTactic(name string) *Tactic {
31 cName := C.CString(name)
32 defer C.free(unsafe.Pointer(cName))
33 return newTactic(c, C.Z3_mk_tactic(c.ptr, cName))
36// Apply applies the tactic to a goal.
37func (t *Tactic) Apply(g *Goal) *ApplyResult {
38 return newApplyResult(t.ctx, C.Z3_tactic_apply(t.ctx.ptr, t.ptr, g.ptr))
41// GetHelp returns help information for the tactic.
42func (t *Tactic) GetHelp() string {
43 return C.GoString(C.Z3_tactic_get_help(t.ctx.ptr, t.ptr))
46// AndThen creates a tactic that applies t1 and then t2.
47func (t *Tactic) AndThen(t2 *Tactic) *Tactic {
48 return newTactic(t.ctx, C.Z3_tactic_and_then(t.ctx.ptr, t.ptr, t2.ptr))
51// OrElse creates a tactic that applies t1, and if it fails, applies t2.
52func (t *Tactic) OrElse(t2 *Tactic) *Tactic {
53 return newTactic(t.ctx, C.Z3_tactic_or_else(t.ctx.ptr, t.ptr, t2.ptr))
56// Repeat creates a tactic that applies t repeatedly (at most max times).
57func (t *Tactic) Repeat(max uint) *Tactic {
58 return newTactic(t.ctx, C.Z3_tactic_repeat(t.ctx.ptr, t.ptr, C.uint(max)))
61// When creates a conditional tactic that applies t only if probe p evaluates to true.
62func (c *Context) TacticWhen(p *Probe, t *Tactic) *Tactic {
63 return newTactic(c, C.Z3_tactic_when(c.ptr, p.ptr, t.ptr))
66// TacticCond creates a conditional tactic: if p then t1 else t2.
67func (c *Context) TacticCond(p *Probe, t1, t2 *Tactic) *Tactic {
68 return newTactic(c, C.Z3_tactic_cond(c.ptr, p.ptr, t1.ptr, t2.ptr))
71// TacticFail creates a tactic that always fails.
72func (c *Context) TacticFail() *Tactic {
73 return newTactic(c, C.Z3_tactic_fail(c.ptr))
76// TacticSkip creates a tactic that always succeeds.
77func (c *Context) TacticSkip() *Tactic {
78 return newTactic(c, C.Z3_tactic_skip(c.ptr))
81// TryFor returns a tactic that applies t for at most ms milliseconds.
82// If t does not terminate in ms milliseconds, then it fails.
83func (t *Tactic) TryFor(ms uint) *Tactic {
84 return newTactic(t.ctx, C.Z3_tactic_try_for(t.ctx.ptr, t.ptr, C.uint(ms)))
87// UsingParams returns a tactic that applies t using the given parameters.
88func (t *Tactic) UsingParams(params *Params) *Tactic {
89 return newTactic(t.ctx, C.Z3_tactic_using_params(t.ctx.ptr, t.ptr, params.ptr))
92// GetParamDescrs returns parameter descriptions for the tactic.
93func (t *Tactic) GetParamDescrs() *ParamDescrs {
94 return newParamDescrs(t.ctx, C.Z3_tactic_get_param_descrs(t.ctx.ptr, t.ptr))
97// ApplyEx applies the tactic to a goal with the given parameters.
98func (t *Tactic) ApplyEx(g *Goal, params *Params) *ApplyResult {
99 return newApplyResult(t.ctx, C.Z3_tactic_apply_ex(t.ctx.ptr, t.ptr, g.ptr, params.ptr))
102// TacticFailIf creates a tactic that fails if the probe p evaluates to false.
103func (c *Context) TacticFailIf(p *Probe) *Tactic {
104 return newTactic(c, C.Z3_tactic_fail_if(c.ptr, p.ptr))
107// TacticFailIfNotDecided creates a tactic that fails if the goal is not
108// trivially satisfiable (empty) or trivially unsatisfiable (contains false).
109func (c *Context) TacticFailIfNotDecided() *Tactic {
110 return newTactic(c, C.Z3_tactic_fail_if_not_decided(c.ptr))
113// ParOr creates a tactic that applies the given tactics in parallel.
114func (c *Context) ParOr(tactics []*Tactic) *Tactic {
115 cTactics := make([]C.Z3_tactic, len(tactics))
116 for i, t := range tactics {
119 return newTactic(c, C.Z3_tactic_par_or(c.ptr, C.uint(len(tactics)), &cTactics[0]))
122// ParAndThen creates a tactic that applies t to a goal and then t2 to every
123// subgoal produced by t, processing subgoals in parallel.
124func (t *Tactic) ParAndThen(t2 *Tactic) *Tactic {
125 return newTactic(t.ctx, C.Z3_tactic_par_and_then(t.ctx.ptr, t.ptr, t2.ptr))
128// GetTacticDescr returns a description of the tactic with the given name.
129func (c *Context) GetTacticDescr(name string) string {
130 cName := C.CString(name)
131 defer C.free(unsafe.Pointer(cName))
132 return C.GoString(C.Z3_tactic_get_descr(c.ptr, cName))
135// NewSolverFromTactic creates a solver from the given tactic.
136// The solver uses the tactic to solve goals.
137func (c *Context) NewSolverFromTactic(t *Tactic) *Solver {
138 ptr := C.Z3_mk_solver_from_tactic(c.ptr, t.ptr)
139 s := &Solver{ctx: c, ptr: ptr}
140 C.Z3_solver_inc_ref(c.ptr, ptr)
141 runtime.SetFinalizer(s, func(solver *Solver) {
142 C.Z3_solver_dec_ref(solver.ctx.ptr, solver.ptr)
147// Goal represents a set of formulas that can be solved or transformed.
153// newGoal creates a new Goal and manages its reference count.
154func newGoal(ctx *Context, ptr C.Z3_goal) *Goal {
155 g := &Goal{ctx: ctx, ptr: ptr}
156 C.Z3_goal_inc_ref(ctx.ptr, ptr)
157 runtime.SetFinalizer(g, func(goal *Goal) {
158 C.Z3_goal_dec_ref(goal.ctx.ptr, goal.ptr)
163// MkGoal creates a new goal.
164func (c *Context) MkGoal(models, unsatCores, proofs bool) *Goal {
165 return newGoal(c, C.Z3_mk_goal(c.ptr, C.bool(models), C.bool(unsatCores), C.bool(proofs)))
168// Assert adds a constraint to the goal.
169func (g *Goal) Assert(constraint *Expr) {
170 C.Z3_goal_assert(g.ctx.ptr, g.ptr, constraint.ptr)
173// Size returns the number of formulas in the goal.
174func (g *Goal) Size() uint {
175 return uint(C.Z3_goal_size(g.ctx.ptr, g.ptr))
178// Formula returns the i-th formula in the goal.
179func (g *Goal) Formula(i uint) *Expr {
180 return newExpr(g.ctx, C.Z3_goal_formula(g.ctx.ptr, g.ptr, C.uint(i)))
183// NumExprs returns the number of expressions in the goal.
184func (g *Goal) NumExprs() uint {
185 return uint(C.Z3_goal_num_exprs(g.ctx.ptr, g.ptr))
188// IsDecidedSat returns true if the goal is decided to be satisfiable.
189func (g *Goal) IsDecidedSat() bool {
190 return bool(C.Z3_goal_is_decided_sat(g.ctx.ptr, g.ptr))
193// IsDecidedUnsat returns true if the goal is decided to be unsatisfiable.
194func (g *Goal) IsDecidedUnsat() bool {
195 return bool(C.Z3_goal_is_decided_unsat(g.ctx.ptr, g.ptr))
198// Reset removes all formulas from the goal.
199func (g *Goal) Reset() {
200 C.Z3_goal_reset(g.ctx.ptr, g.ptr)
203// Depth returns the depth of the goal.
204// It tracks how many times the goal was transformed by a tactic.
205func (g *Goal) Depth() uint {
206 return uint(C.Z3_goal_depth(g.ctx.ptr, g.ptr))
209// Precision returns the precision of the goal as a uint.
210// Possible values: 0 = precise, 1 = under-approximation, 2 = over-approximation, 3 = under+over.
211func (g *Goal) Precision() uint {
212 return uint(C.Z3_goal_precision(g.ctx.ptr, g.ptr))
215// Translate creates a copy of the goal in the target context.
216func (g *Goal) Translate(target *Context) *Goal {
217 return newGoal(target, C.Z3_goal_translate(g.ctx.ptr, g.ptr, target.ptr))
220// ConvertModel converts a model from the original goal into a model for this goal.
221// Use this when a tactic has transformed the goal and you need a model for the original.
222func (g *Goal) ConvertModel(m *Model) *Model {
223 return newModel(g.ctx, C.Z3_goal_convert_model(g.ctx.ptr, g.ptr, m.ptr))
226// String returns the string representation of the goal.
227func (g *Goal) String() string {
228 return C.GoString(C.Z3_goal_to_string(g.ctx.ptr, g.ptr))
231// IsInconsistent returns true if the goal contains the formula false.
232func (g *Goal) IsInconsistent() bool {
233 return bool(C.Z3_goal_inconsistent(g.ctx.ptr, g.ptr))
236// ToDimacsString converts the goal to a string in DIMACS format.
237// If includeNames is true, formula names are included as comments.
238func (g *Goal) ToDimacsString(includeNames bool) string {
239 return C.GoString(C.Z3_goal_to_dimacs_string(g.ctx.ptr, g.ptr, C.bool(includeNames)))
242// ApplyResult represents the result of applying a tactic to a goal.
243type ApplyResult struct {
245 ptr C.Z3_apply_result
248// newApplyResult creates a new ApplyResult and manages its reference count.
249func newApplyResult(ctx *Context, ptr C.Z3_apply_result) *ApplyResult {
250 ar := &ApplyResult{ctx: ctx, ptr: ptr}
251 C.Z3_apply_result_inc_ref(ctx.ptr, ptr)
252 runtime.SetFinalizer(ar, func(result *ApplyResult) {
253 C.Z3_apply_result_dec_ref(result.ctx.ptr, result.ptr)
258// NumSubgoals returns the number of subgoals in the result.
259func (ar *ApplyResult) NumSubgoals() uint {
260 return uint(C.Z3_apply_result_get_num_subgoals(ar.ctx.ptr, ar.ptr))
263// Subgoal returns the i-th subgoal.
264func (ar *ApplyResult) Subgoal(i uint) *Goal {
265 return newGoal(ar.ctx, C.Z3_apply_result_get_subgoal(ar.ctx.ptr, ar.ptr, C.uint(i)))
268// String returns the string representation of the apply result.
269func (ar *ApplyResult) String() string {
270 return C.GoString(C.Z3_apply_result_to_string(ar.ctx.ptr, ar.ptr))
273// Probe represents a probe for checking properties of goals.
279// newProbe creates a new Probe and manages its reference count.
280func newProbe(ctx *Context, ptr C.Z3_probe) *Probe {
281 p := &Probe{ctx: ctx, ptr: ptr}
282 C.Z3_probe_inc_ref(ctx.ptr, ptr)
283 runtime.SetFinalizer(p, func(probe *Probe) {
284 C.Z3_probe_dec_ref(probe.ctx.ptr, probe.ptr)
289// MkProbe creates a probe with the given name.
290func (c *Context) MkProbe(name string) *Probe {
291 cName := C.CString(name)
292 defer C.free(unsafe.Pointer(cName))
293 return newProbe(c, C.Z3_mk_probe(c.ptr, cName))
296// Apply evaluates the probe on a goal.
297func (p *Probe) Apply(g *Goal) float64 {
298 return float64(C.Z3_probe_apply(p.ctx.ptr, p.ptr, g.ptr))
301// ProbeConst creates a probe that always evaluates to the given value.
302func (c *Context) ProbeConst(val float64) *Probe {
303 return newProbe(c, C.Z3_probe_const(c.ptr, C.double(val)))
306// ProbeLt creates a probe that evaluates to true if p1 < p2.
307func (p *Probe) Lt(p2 *Probe) *Probe {
308 return newProbe(p.ctx, C.Z3_probe_lt(p.ctx.ptr, p.ptr, p2.ptr))
311// ProbeGt creates a probe that evaluates to true if p1 > p2.
312func (p *Probe) Gt(p2 *Probe) *Probe {
313 return newProbe(p.ctx, C.Z3_probe_gt(p.ctx.ptr, p.ptr, p2.ptr))
316// ProbeLe creates a probe that evaluates to true if p1 <= p2.
317func (p *Probe) Le(p2 *Probe) *Probe {
318 return newProbe(p.ctx, C.Z3_probe_le(p.ctx.ptr, p.ptr, p2.ptr))
321// ProbeGe creates a probe that evaluates to true if p1 >= p2.
322func (p *Probe) Ge(p2 *Probe) *Probe {
323 return newProbe(p.ctx, C.Z3_probe_ge(p.ctx.ptr, p.ptr, p2.ptr))
326// ProbeEq creates a probe that evaluates to true if p1 == p2.
327func (p *Probe) Eq(p2 *Probe) *Probe {
328 return newProbe(p.ctx, C.Z3_probe_eq(p.ctx.ptr, p.ptr, p2.ptr))
331// ProbeAnd creates a probe that is the conjunction of p1 and p2.
332func (p *Probe) And(p2 *Probe) *Probe {
333 return newProbe(p.ctx, C.Z3_probe_and(p.ctx.ptr, p.ptr, p2.ptr))
336// ProbeOr creates a probe that is the disjunction of p1 and p2.
337func (p *Probe) Or(p2 *Probe) *Probe {
338 return newProbe(p.ctx, C.Z3_probe_or(p.ctx.ptr, p.ptr, p2.ptr))
341// ProbeNot creates a probe that is the negation of p.
342func (p *Probe) Not() *Probe {
343 return newProbe(p.ctx, C.Z3_probe_not(p.ctx.ptr, p.ptr))
346// GetProbeDescr returns a description of the probe with the given name.
347func (c *Context) GetProbeDescr(name string) string {
348 cName := C.CString(name)
349 defer C.free(unsafe.Pointer(cName))
350 return C.GoString(C.Z3_probe_get_descr(c.ptr, cName))
353// Params represents a parameter set.
359// newParams creates a new Params and manages its reference count.
360func newParams(ctx *Context, ptr C.Z3_params) *Params {
361 params := &Params{ctx: ctx, ptr: ptr}
362 C.Z3_params_inc_ref(ctx.ptr, ptr)
363 runtime.SetFinalizer(params, func(p *Params) {
364 C.Z3_params_dec_ref(p.ctx.ptr, p.ptr)
369// MkParams creates a new parameter set.
370func (c *Context) MkParams() *Params {
371 return newParams(c, C.Z3_mk_params(c.ptr))
374// SetBool sets a Boolean parameter.
375func (p *Params) SetBool(key string, value bool) {
376 sym := p.ctx.MkStringSymbol(key)
377 C.Z3_params_set_bool(p.ctx.ptr, p.ptr, sym.ptr, C.bool(value))
380// SetUint sets an unsigned integer parameter.
381func (p *Params) SetUint(key string, value uint) {
382 sym := p.ctx.MkStringSymbol(key)
383 C.Z3_params_set_uint(p.ctx.ptr, p.ptr, sym.ptr, C.uint(value))
386// SetDouble sets a double parameter.
387func (p *Params) SetDouble(key string, value float64) {
388 sym := p.ctx.MkStringSymbol(key)
389 C.Z3_params_set_double(p.ctx.ptr, p.ptr, sym.ptr, C.double(value))
392// SetSymbol sets a symbol parameter.
393func (p *Params) SetSymbol(key string, value *Symbol) {
394 sym := p.ctx.MkStringSymbol(key)
395 C.Z3_params_set_symbol(p.ctx.ptr, p.ptr, sym.ptr, value.ptr)
398// String returns the string representation of the parameters.
399func (p *Params) String() string {
400 return C.GoString(C.Z3_params_to_string(p.ctx.ptr, p.ptr))