Skip to main content

Overview

The Z3 solver is the main interface for checking satisfiability of formulas. It supports incremental solving, allowing you to add constraints progressively and check satisfiability multiple times.

Creating a Solver

Basic Workflow

The typical solver workflow involves:
  1. Add constraints using add()
  2. Check satisfiability using check()
  3. Extract model if satisfiable using model()
  4. Optionally push/pop to manage assertion stack

Incremental Solving

From examples/c++/example.cpp:862:

Push and Pop

The solver maintains a stack of assertion scopes. Use push() to create checkpoints and pop() to backtrack. From examples/c++/example.cpp:875:

Nested Push/Pop

Assumptions

Check satisfiability under temporary assumptions without modifying the solver state. From examples/c++/example.cpp:898:

Multiple Assumptions

Solver State and Reset

Checking with Timeout

Solver Parameters

From src/api/api_solver.cpp:39:

Solver Statistics

Unsat Cores

When a formula is unsatisfiable, extract a minimal unsatisfiable subset:

Solver Assertions

SMT-LIB Output

Export solver state to SMT-LIB format:

Consequences

Compute logical consequences from assumptions:

Solver from Tactic

Create specialized solvers using tactics (see Tactics):

Advanced: Solver Callbacks

Z3 supports user propagators for custom theory reasoning. This is an advanced feature for extending Z3 with domain-specific reasoning.
See examples/userPropagator/ for examples.

Performance Tips

Push/pop has overhead. For simple backtracking, consider using assumptions instead.
Add multiple constraints at once when possible:
Prevent indefinite solving with timeout parameter.
Specifying a logic (e.g., QF_LIA) can improve performance:

SMT Solving

Core SMT concepts

Tactics

Custom solver strategies

Models

Working with solutions

References

  • Z3 API: src/api/api_solver.cpp
  • Solver interface: src/api/z3_api.h
  • Examples: examples/c++/example.cpp:862-922