Overview
Z3 simplifiers are lightweight formula transformations that reduce formula complexity before solving. Unlike tactics (which are heavy preprocessing pipelines), simplifiers are fast, composable transformations that can significantly improve solver performance.Understanding Simplifiers
Simplifiers vs. Tactics
Simplifiers:- Lightweight transformations
- Fast and incremental
- Compose naturally with
and-then - Applied before solving
- Don’t change the solver strategy
- Heavy preprocessing pipelines
- Complete solving strategies
- Transform goals into subgoals
- May apply multiple techniques
When to Use Simplifiers
Use simplifiers when you want to:- Preprocess formulas before solving
- Eliminate redundant constraints
- Propagate constants and bounds
- Simplify arithmetic expressions
- Improve solver performance without changing strategy
Creating and Using Simplifiers
Basic Simplifier Usage
Listing Available Simplifiers
Common Simplifiers
Core Simplifiers
simplify
General-purpose simplification:
propagate-values
Propagates constants and simplifies based on known values:
solve-eqs
Solves for variables in equations and substitutes:
elim-uncnstr
Eliminates unconstrained variables:
Arithmetic Simplifiers
normalize-bounds
Normalizes arithmetic bounds:
lia2pb
Converts linear integer arithmetic to pseudo-boolean:
Boolean Simplifiers
propagate-ineqs
Propagates inequalities:
ctx-solver-simplify
Context-aware simplification using solver state:
Composing Simplifiers
Sequential Composition
Chain simplifiers usingand-then:
Building a Simplification Pipeline
Configuring Simplifiers with Parameters
Setting Simplifier Parameters
Discovering Simplifier Parameters
Getting Simplifier Help
Domain-Specific Simplification
Bit-Vector Simplification
Arithmetic Simplification
Performance Considerations
Simplifier Overhead
Best Practices
When to Use Simplifiers
Use simplifiers when:- Formulas contain obvious redundancies
- Constants can be propagated
- Variables can be eliminated
- Bounds can be normalized
- You want to improve performance without changing solver strategy
- Formulas are already in optimal form
- Simplification overhead exceeds benefits
- Debugging and need to preserve original formula structure
Recommended Pipelines
Lightweight preprocessing:Common Pitfalls
- Adding simplifier after assertions: Simplifiers must be added before assertions
- Over-simplification: Too many simplifiers can increase overhead
- Wrong simplifier order: Order matters in composition
- Forgetting reference counting: Always pair inc_ref with dec_ref
Limitations
Simplifier Restrictions
API Reference
Simplifier Creation
Z3_mk_simplifier- Create simplifier by name (api_tactic.cpp:533)Z3_simplifier_inc_ref- Increment reference counter (api_tactic.cpp:549)Z3_simplifier_dec_ref- Decrement reference counter (api_tactic.cpp:557)
Simplifier Discovery
Z3_get_num_simplifiers- Get number of available simplifiers (api_tactic.cpp:565)Z3_get_simplifier_name- Get simplifier name by index (api_tactic.cpp:573)Z3_simplifier_get_descr- Get simplifier description (api_tactic.cpp:657)
Simplifier Composition
Z3_simplifier_and_then- Sequential composition (api_tactic.cpp:585)Z3_simplifier_using_params- Add parameters to simplifier (api_tactic.cpp:601)
Simplifier Information
Z3_simplifier_get_help- Get help text (api_tactic.cpp:625)Z3_simplifier_get_param_descrs- Get parameter descriptions (api_tactic.cpp:641)
Solver Integration
Z3_solver_add_simplifier- Attach simplifier to solver (api_solver.cpp:244)
See Also
- Parameters - Configuring simplifiers
- Solver API - Using solvers with simplifiers
- Tactics - Heavy preprocessing strategies
