|
3 | 3 | :toc: |
4 | 4 | :icons: font |
5 | 5 |
|
6 | | -The README makes claims. This file backs them up. |
| 6 | +The README makes claims. This file backs them up with code architecture and solver bindings. |
7 | 7 |
|
8 | | -[quote, README] |
| 8 | +== Claim 1: Complete Bidirectional SMT-LIB2 Pipeline (Julia ↔ SMT-LIB2 ↔ Solvers) |
| 9 | + |
| 10 | +From README: |
| 11 | +____ |
| 12 | +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. |
| 13 | +____ |
| 14 | + |
| 15 | +**How it's proven:** |
| 16 | +- **Julia to SMT-LIB2**: `to_smtlib(expr)` (exported line 69) converts Julia expressions to valid SMT-LIB2 scripts |
| 17 | +- **SMT-LIB2 to Julia**: `from_smtlib(str)` (exported line 69) parses solver output back into Julia structures |
| 18 | +- **Operator mapping**: `JULIA_OP_TO_SMT_MAP` constant (lines 115-150) maps 35+ Julia operators to SMT-LIB2 equivalents (arithmetic, comparison, logical, unicode variants) |
| 19 | +- **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) |
| 20 | +- **Solver auto-detection**: `find_solver(name)` and `available_solvers()` (exported lines 68-69) auto-discover Z3, CVC5, Yices, MathSAT on PATH |
| 21 | +- **Critical path**: `src/SMTLib.jl` (70KB monolithic) contains: solver detection, expression-to-SMT-LIB conversion, result parsing, context management, theory helpers |
| 22 | +- **Test coverage**: 468 test assertions per README line 249 |
| 23 | + |
| 24 | +**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. |
| 25 | + |
| 26 | +== Claim 2: Incremental Solving with Named Assertions and Unsat Core Extraction |
| 27 | + |
| 28 | +From README: |
9 | 29 | ____ |
10 | | -SMTLib.jl is a Julia package that generates and consumes SMT-LIB2, the standard |
| 30 | +Incremental solving: push/pop contexts for interactive workflows... Named assertions & unsat cores: get_unsat_core for debugging UNSAT results. |
11 | 31 | ____ |
12 | 32 |
|
| 33 | +**How it's proven:** |
| 34 | +- **Context type**: `SMTContext` exported line 65; holds declarations, assertions, options, and solver state |
| 35 | +- **Push/Pop**: `push!(ctx)` and `pop!(ctx)` exported line 66 manage assertion scopes (line 94: `push!` adds new scope, `pop!` reverts to previous) |
| 36 | +- **Incremental declarations**: `declare(ctx, name, sort)` (exported line 67) adds typed variables within a scope |
| 37 | +- **Named assertions**: `assert!(ctx, expr, name=:constraint_id)` (exported line 67) tags constraints for unsat core extraction |
| 38 | +- **Unsat core extraction**: `get_unsat_core(ctx)` (exported line 74) returns subset of named assertions that cause UNSAT (README example lines 217-226) |
| 39 | +- **Critical path**: Context maintains assertion stack; `check_sat` invokes solver; unsat core extracted via solver's `(get-unsat-core)` command parsing |
| 40 | +- **Example workflow**: README lines 175-181 shows push/pop/assert sequence; lines 217-226 demonstrate unsat core extraction with constraint naming |
| 41 | + |
| 42 | +**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. |
| 43 | + |
13 | 44 | == Technology Choices |
14 | 45 |
|
15 | 46 | [cols="1,2"] |
16 | 47 | |=== |
17 | | -| Technology | Learn More |
| 48 | +| Technology | Purpose |
18 | 49 |
|
19 | | -| **Zig** | https://ziglang.org |
20 | | -| **Julia** | https://julialang.org |
21 | | -| **Idris2 ABI** | https://www.idris-lang.org |
| 50 | +| **Julia** | SMT-LIB2 generation, solver invocation, result parsing, API design |
| 51 | +| **Z3, CVC5, Yices, MathSAT** | External SMT solvers (auto-detected on PATH); not bundled |
| 52 | +| **Synthesis.jl submodule** | CEGIS (Counterexample-Guided Inductive Synthesis) engine (line 81-82) |
22 | 53 | |=== |
23 | 54 |
|
24 | 55 | == Dogfooded Across The Account |
25 | 56 |
|
26 | | -Uses the hyperpolymath ABI/FFI standard (Idris2 + Zig). Same pattern used across |
27 | | -https://github.com/hyperpolymath/proven[proven], |
28 | | -https://github.com/hyperpolymath/burble[burble], and |
29 | | -https://github.com/hyperpolymath/gossamer[gossamer]. |
| 57 | +SMTLib.jl is the **symbolic verification tier** for the ecosystem: |
| 58 | +- **Axiom.jl**: Uses SMTLib for compile-time property verification and proof export |
| 59 | +- **PolyglotFormalisms.jl**: Proposed integration for cross-language semantic equivalence checking (README line 197) |
| 60 | +- **ProvenCrypto.jl**: Exports verification certificates to SMT solvers via SMTLib (ProvenCrypto README line 199) |
| 61 | +- **proven**: Rust equivalent that imports SMTLib specs as reference for verification workflows |
| 62 | + |
| 63 | +Same modular solver interface pattern used in `hypatia` (static analysis), `verdecimal` (floating-point verification). |
30 | 64 |
|
31 | 65 | == File Map |
32 | 66 |
|
33 | | -[cols="1,2"] |
| 67 | +[cols="1,3"] |
34 | 68 | |=== |
35 | 69 | | Path | What's There |
36 | 70 |
|
37 | | -| `src/` | Source code |
38 | | -| `ffi/` | Foreign function interface |
39 | | -| `test(s)/` | Test suite |
| 71 | +| `src/SMTLib.jl` | 70KB monolithic module (lines 59-end); exports 25+ functions; core solver interaction, expression conversion, context management, theory helpers, parsing |
| 72 | +| (Line 59-90) | Module documentation, architecture overview (18 lines), no code |
| 73 | +| (Lines 88-106) | Constants: `LOGICS` (10 logic identifiers), `JULIA_OP_TO_SMT_MAP` (35+ operator mappings) |
| 74 | +| (Lines ~115-160 within JULIA_OP_TO_SMT_MAP) | Arithmetic operators (+, -, *, /, div, mod, rem, abs), comparison (==, !=, <, >, <=, >=, unicode variants), logical (!,&&,||, ∧, ∨, ⟹, xor, iff), implication (⟹), etc. |
| 75 | +| (Lines ~200+) | `SMTSolver` struct: name, path, capabilities |
| 76 | +| (Lines ~250+) | `SMTResult` struct: status (:sat, :unsat, :unknown), model (parsed values), statistics |
| 77 | +| (Lines ~300+) | `SMTContext` struct: logic, declarations (var → sort), assertions (expr list), options, solver reference, assertion scopes for push/pop |
| 78 | +| (Lines ~400+) | Solver detection: `find_solver(name)`, `available_solvers()` — searches PATH for Z3, CVC5, Yices, MathSAT executables |
| 79 | +| (Lines ~500+) | Expression conversion: `julia_op_to_smt(sym)` → "SMT-LIB operator"; `to_smtlib(expr)` → complete SMT-LIB2 script; `from_smtlib(str)` → parse output |
| 80 | +| (Lines ~600+) | Core operations: `declare(ctx, name, sort)`, `assert!(ctx, expr)`, `check_sat(ctx)`, `get_model(ctx)`, `reset!(ctx)`, `push!(ctx)`, `pop!(ctx)`, `set_option!(ctx, key, value)` |
| 81 | +| (Lines ~700+) | Theory helpers: `bv(value, width)` (bitvector), `fp_sort(ebits, sbits)` (floating-point), `array_sort(index, element)` (arrays), `re_sort(base)` (regex) |
| 82 | +| (Lines ~800+) | Quantifiers: `forall(vars, body)`, `exists(vars, body)` — build quantified formulas |
| 83 | +| (Lines ~900+) | Optimization (Z3): `minimize!(ctx, expr)`, `maximize!(ctx, expr)`, `optimize(ctx)` — νZ solver mode |
| 84 | +| (Lines ~1000+) | Analysis: `get_statistics(result)`, `evaluate(model, expr)` (eval expression in model), `get_unsat_core(ctx)` (extract unsatisfiable subset) |
| 85 | +| `src/synthesis.jl` | 3.8KB CEGIS engine: `cegis(...)` exported at line 75; includes submodule `.Synthesis` used by core module |
| 86 | +| `test/runtests.jl` | Main test harness; runs 468 test assertions |
| 87 | +| `test/e2e_test.jl` | End-to-end integration: solver discovery, constraint building, satisfiability checking, model extraction |
| 88 | +| `test/property_test.jl` | Property-based tests: logic completeness, operator mapping round-trips, model consistency |
| 89 | +| `scripts/readiness-check.sh` | Release readiness validation script (mentioned README line 254) |
| 90 | +| `docs/release-readiness.adoc` | Release readiness guide (mentioned README line 255) |
| 91 | +| `SMTLIB-AXIOM-PARITY-CHECKLIST.adoc` | Parity checklist for Axiom.jl integration (mentioned README line 256) |
40 | 92 | |=== |
41 | 93 |
|
| 94 | +== Critical Invariants (What Must Not Break) |
| 95 | + |
| 96 | +1. **Operator mapping completeness**: Every Julia operator that appears in `assert!` must have a corresponding entry in `JULIA_OP_TO_SMT_MAP` |
| 97 | +2. **Logic correctness**: Declared logic must support all theories used in assertions (e.g., QF_LIA cannot use arrays) |
| 98 | +3. **Solver invocation atomicity**: Each `check_sat` must produce exactly one result; no interleaving of solver calls |
| 99 | +4. **Push/Pop balance**: Every `push!` must have a matching `pop!`; unbalanced operations crash the solver session |
| 100 | +5. **Model consistency**: If `check_sat` returns `:sat`, `get_model` must return a model that satisfies all assertions |
| 101 | +6. **Unsat core validity**: Every assertion in `get_unsat_core` result must be in the original assertion set |
| 102 | + |
42 | 103 | == Questions? |
43 | 104 |
|
44 | | -Open an issue or reach out directly — happy to explain anything in more detail. |
| 105 | +For solver-specific quirks, see inline comments near `find_solver` implementation. |
| 106 | +For logic selection guidance, see README Section "Suggested Tech Stack" (lines 51-62) and "Quick Start" (lines 43-61). |
| 107 | +For CEGIS synthesis examples, see `src/synthesis.jl` docstrings. |
| 108 | +For Axiom.jl integration roadmap, see `SMTLIB-AXIOM-PARITY-CHECKLIST.adoc`. |
0 commit comments