Skip to main content

Overview

Z3 can generate formal proofs of unsatisfiability and produce unsat cores - minimal subsets of constraints that are unsatisfiable. These features are essential for formal verification, debugging unsatisfiable problems, and building trusted systems.

Enabling Proof Generation

Context Configuration

Proof generation must be enabled when creating the Z3 context:
Important: Proof generation cannot be enabled after context creation. You must set this parameter in the configuration.

Enabling Unsat Core Tracking

Retrieving Proofs

Basic Proof Retrieval

Proof Structure

Proofs in Z3 are AST nodes representing proof terms. They form a proof tree where:
  • Leaf nodes are axioms or assumptions
  • Internal nodes are inference rules
  • The root proves the final conclusion (false for unsatisfiability proofs)

Working with Unsat Cores

Basic Unsat Core Extraction

An unsat core is a minimal subset of assertions that is still unsatisfiable:

Tracking Named Assertions

For better unsat core reporting, use named tracking literals:

Minimizing Unsat Cores

Core Minimization Settings

Note: Core minimization increases solving time but produces smaller, more useful cores.

Proof Applications

Verifying Unsatisfiability

Proofs provide mathematical certainty of unsatisfiability:

Debugging Unsatisfiable Constraints

Unsat cores help identify conflicting constraints:

Incremental Debugging

Performance Considerations

Cost of Proof Generation

Proof generation adds overhead:
  • Memory: Proofs can be large, especially for complex problems
  • Time: Proof construction adds 10-30% overhead
  • Storage: Saving proofs requires significant space

Best Practices

When to Use Proofs

Use proofs for:
  • Formal verification requiring mathematical certainty
  • Debugging complex unsatisfiable formulas
  • Building certified tools and proof checkers
  • Academic research on proof systems
  • Trust verification in security-critical applications
Avoid proofs when:
  • Performance is critical and verification isn’t needed
  • Working with very large problems (memory constraints)
  • Running repeated queries (proof overhead accumulates)

When to Use Unsat Cores

Use unsat cores for:
  • Debugging unsatisfiable constraint sets
  • Identifying minimal failing test cases
  • Root cause analysis of specification conflicts
  • Constraint relaxation and repair
  • Incremental constraint addition

Optimization Tips

  1. Enable cores only when needed: Unsat core tracking adds overhead
  2. Use minimization selectively: Minimize only when core quality matters
  3. Name your assumptions: Makes unsat cores easier to interpret
  4. Cache proof results: Don’t recompute proofs for identical queries
  5. Clean up references: Proofs can be large; decrement references promptly

API Reference

Proof Retrieval

  • Z3_solver_get_proof - Get proof from solver (api_solver.cpp:727)

Unsat Core Retrieval

  • Z3_solver_get_unsat_core - Get unsat core (api_solver.cpp:742)
  • Z3_solver_check_assumptions - Check with assumptions for core tracking

Configuration

  • Z3_set_param_value - Set proof parameter in config
  • Z3_mk_goal - Create goal with proof support (z3_api.h:6358)

See Also