The README makes claims. This file backs them up with code architecture and solver bindings.
From README:
SMTLib.jl gives you a clean Julia API for building constraints, checking satisfiability, and parsing models — with support for quantifiers, optimization, theory helpers, unsat cores, and more.
How it’s proven:
- Julia to SMT-LIB2: to_smtlib(expr) (exported line 69) converts Julia expressions to valid SMT-LIB2 scripts
- SMT-LIB2 to Julia: from_smtlib(str) (exported line 69) parses solver output back into Julia structures
- Operator mapping: JULIA_OP_TO_SMT_MAP constant (lines 115-150) maps 35+ Julia operators to SMT-LIB2 equivalents (arithmetic, comparison, logical, unicode variants)
- Logic support: LOGICS constant (lines 94-106) lists 10 supported SMT-LIB2 logics (QF_LIA, QF_LRA, QF_NIA, QF_NRA, QF_BV, QF_AUFLIA, LIA, LRA, AUFLIRA, QF_S)
- Solver auto-detection: find_solver(name) and available_solvers() (exported lines 68-69) auto-discover Z3, CVC5, Yices, MathSAT on PATH
- Critical path: src/SMTLib.jl (70KB monolithic) contains: solver detection, expression-to-SMT-LIB conversion, result parsing, context management, theory helpers
- Test coverage: 468 test assertions per README line 249
Caveat: The 70KB monolithic design in src/SMTLib.jl means all solver interaction code is in one file. This is maintainable but could be refactored into src/solver_detection.jl, src/smt_generation.jl, src/result_parsing.jl, src/context.jl for better organization.
From README:
Incremental solving: push/pop contexts for interactive workflows… Named assertions & unsat cores: get_unsat_core for debugging UNSAT results.
How it’s proven:
- Context type: SMTContext exported line 65; holds declarations, assertions, options, and solver state
- Push/Pop: push!(ctx) and pop!(ctx) exported line 66 manage assertion scopes (line 94: push! adds new scope, pop! reverts to previous)
- Incremental declarations: declare(ctx, name, sort) (exported line 67) adds typed variables within a scope
- Named assertions: assert!(ctx, expr, name=:constraint_id) (exported line 67) tags constraints for unsat core extraction
- Unsat core extraction: get_unsat_core(ctx) (exported line 74) returns subset of named assertions that cause UNSAT (README example lines 217-226)
- Critical path: Context maintains assertion stack; check_sat invokes solver; unsat core extracted via solver’s (get-unsat-core) command parsing
- Example workflow: README lines 175-181 shows push/pop/assert sequence; lines 217-226 demonstrate unsat core extraction with constraint naming
Caveat: Unsat core extraction requires solver support (produce-unsat-cores option must be set via set_option!). Not all solvers expose unsat cores; MathSAT and CVC5 support it, but Yices may have limitations.
| Technology | Purpose |
|---|---|
Julia |
SMT-LIB2 generation, solver invocation, result parsing, API design |
Z3, CVC5, Yices, MathSAT |
External SMT solvers (auto-detected on PATH); not bundled |
Synthesis.jl submodule |
CEGIS (Counterexample-Guided Inductive Synthesis) engine (line 81-82) |
SMTLib.jl is the symbolic verification tier for the ecosystem: - Axiom.jl: Uses SMTLib for compile-time property verification and proof export - PolyglotFormalisms.jl: Proposed integration for cross-language semantic equivalence checking (README line 197) - ProvenCrypto.jl: Exports verification certificates to SMT solvers via SMTLib (ProvenCrypto README line 199) - proven: Rust equivalent that imports SMTLib specs as reference for verification workflows
Same modular solver interface pattern used in hypatia (static analysis), verdecimal (floating-point verification).
| Path | What’s There |
|---|---|
|
70KB monolithic module (lines 59-end); exports 25+ functions; core solver interaction, expression conversion, context management, theory helpers, parsing |
(Line 59-90) |
Module documentation, architecture overview (18 lines), no code |
(Lines 88-106) |
Constants: |
(Lines ~115-160 within JULIA_OP_TO_SMT_MAP) |
Arithmetic operators (+, -, *, /, div, mod, rem, abs), comparison (==, !=, <, >, ⇐, >=, unicode variants), logical (!,&&, |
, ∧, ∨, ⟹, xor, iff), implication (⟹), etc. |
|
(Lines ~200+) |
|
(Lines ~250+) |
|
(Lines ~300+) |
|
(Lines ~400+) |
Solver detection: |
(Lines ~500+) |
Expression conversion: |
(Lines ~600+) |
Core operations: |
(Lines ~700+) |
Theory helpers: |
(Lines ~800+) |
Quantifiers: |
(Lines ~900+) |
Optimization (Z3): |
(Lines ~1000+) |
Analysis: |
|
3.8KB CEGIS engine: |
|
Main test harness; runs 468 test assertions |
|
End-to-end integration: solver discovery, constraint building, satisfiability checking, model extraction |
|
Property-based tests: logic completeness, operator mapping round-trips, model consistency |
|
Release readiness validation script (mentioned README line 254) |
|
Release readiness guide (mentioned README line 255) |
|
Parity checklist for Axiom.jl integration (mentioned README line 256) |
-
Operator mapping completeness: Every Julia operator that appears in
assert!must have a corresponding entry inJULIA_OP_TO_SMT_MAP -
Logic correctness: Declared logic must support all theories used in assertions (e.g., QF_LIA cannot use arrays)
-
Solver invocation atomicity: Each
check_satmust produce exactly one result; no interleaving of solver calls -
Push/Pop balance: Every
push!must have a matchingpop!; unbalanced operations crash the solver session -
Model consistency: If
check_satreturns:sat,get_modelmust return a model that satisfies all assertions -
Unsat core validity: Every assertion in
get_unsat_coreresult must be in the original assertion set
For solver-specific quirks, see inline comments near find_solver implementation.
For logic selection guidance, see README Section "Suggested Tech Stack" (lines 51-62) and "Quick Start" (lines 43-61).
For CEGIS synthesis examples, see src/synthesis.jl docstrings.
For Axiom.jl integration roadmap, see SMTLIB-AXIOM-PARITY-CHECKLIST.adoc.