Parallel solving#1046
Merged
Merged
Conversation
Merge main (3 new commits including mergeByAssertion PR #981). Fix VCGPathTests.getEvalStats to use ObligationExtraction instead of E.deferred.foldl since typeCheckAndEval now returns Program.
- Fix duplicate label clash warning by running symbolicEval separately (not in pipeline loop) to avoid re-running Program.eval for SMT env - Use phase name in error messages (e.g. '❌ TypeCheck Error.' instead of '❌ Transform Error.') - symbolicEval returns Env alongside Program for SMT encoding - Filed #986 for DDM translator type alias issue - Remove extra warning from DuplicateAssumeLabels test
The typeCheck pipeline phase now formats errors with file range and '❌ Type checking error.' prefix, matching the old format. The pipeline loop passes errors through without adding its own prefix. Update .expect files and test expected outputs for the new format.
- symbolicEval and ANF are back in the pipeline loop (all phases unified) - SMT env uses buildEvalEnv + Program.eval (label clash warning remains as a known issue until SMT env construction is fully decoupled) - Closed #986 (was filed against branch, not main) - Reverted symbolicEval to return (Program, Statistics) without Env
Local function declarations (funcDecl in procedure bodies) require captureFreevars from the evaluation context. buildSMTEnv can't replicate this without running Program.eval. Reverted to using Program.eval for SMT env construction. The duplicate label clash warning remains as a known limitation. Added collectFuncDecls helper to buildSMTEnv for future use.
…rogram.eval The obligations program now includes function declarations from the evaluation environment (post-eval factory minus initial factory) and distinct constraints. This allows buildSMTEnv to construct the SMT encoding context from the program itself, eliminating the second Program.eval call that caused the duplicate label clash warning. Performance (Bubble.bpl, 34 obligations): - Main: Pipeline 0ms, VC discharge 731ms, Total ~809ms - Branch: Pipeline 77ms, VC discharge 820ms, Total ~953ms - Overhead: ~18% (77ms pipeline phases + ANF encoding impact)
… prefix - Rename transformPipelinePhases/corePipelinePhases so corePipelinePhases includes all phases (transforms + typeCheck + symbolicEval + ANF) - Remove byte range from typeCheck error format (was regression from using formatRange without fileMap) - Restore '❌ Type checking error.' prefix for symbolicEval errors - Revert .expected files to main's format - Update test expected outputs
…dbg_trace - Run typeCheck/symbolicEval outside the pipeline loop so DiagnosticModel errors with source locations propagate directly instead of being converted to strings (which lost the fileRange). - Remove leftover dbg_trace in verifySingleEnv. - Restore source locations in expected test outputs.
…errors, remove Core-level ANF - Change pipeline error type (Err) from String to DiagnosticModel so that source locations propagate through the pipeline without conversion. - Move type checking and symbolic evaluation into corePipelinePhases as proper PipelinePhase entries, running inside the pipeline loop. - Remove Core-level ANF encoder from the pipeline to eliminate extra variable declarations; the SMT-level ANF already handles deduplication. - Update all throw sites in transform passes to use DiagnosticModel. - Restore all debug traces to match main.
Remove the SMT-level ANF (defineTerm creating define-fun entries and terms cache) from Encoder.lean. The SMT encoder now passes terms through directly, making it a simple 1-1 translation. Wire anfEncoderPipelinePhase into corePipelinePhases after symbolic evaluation, so common subexpression deduplication happens at the Core level before SMT encoding. Update test expectations: SMT output no longer contains define-fun $__t.N entries; assertions contain inline terms instead.
Replace O(n² × tree_size) subsumption check with hash-based O(n) lookup. Replace per-target sequential body traversal with single-pass batch replacement using a HashMap. HeapReasoning ANF phase: 122ms → 10ms Bubble ANF phase: 55ms → 5ms
…igation The oblProgram from symbolicEval inlines axioms as assume statements but does not include axiom declarations. This caused preprocessObligation to have an empty axiomNames list, preventing .Precise mode from identifying and excluding axiom assumptions. The fix passes axiom names and the original program (with axiom declarations) from the verify function.
… metadata for errors - Move isLeaf, hasBVar to LExpr.lean; getExprType? to Expressions.lean - Move mapExprs, collectExprs to Statement.lean - Replace exprSize with LExpr.size - Extract anfVarPrefix constant shared between ANFEncoder and Verifier - Revise ANFEncoder docstring to be concise - Fix non-stateless comment in Core.lean - Use metadata source locations in PrecondElim error messages - Add focused symbolic eval tests (detIf, nondetIf, blockExit)
…ould-b # Conflicts: # StrataTest/Languages/Core/Tests/ProgramTypeTests.lean
…_id theorem, fix toSMTTermString tests, fix DDM printer formatting
…-term # Conflicts: # Strata/Languages/Core/Options.lean # StrataMain.lean
…quest-parallel-solving
…quest-parallel-solving
…quest-parallel-solving
…quest-parallel-solving
aqjune-aws
reviewed
May 19, 2026
aqjune-aws
previously approved these changes
May 19, 2026
…quest-parallel-solving Resolve conflicts: integrate main's PipelineContext profiling with parallel dispatch. Re-add SolverJob, dispatchSolverJob, dispatchJobsParallel, and parallel/sequential branch in verifySingleEnv. Re-add --parallel CLI flag in StrataMainLib.
atomb
approved these changes
May 19, 2026
…quest-parallel-solving
aqjune-aws
approved these changes
May 20, 2026
…quest-parallel-solving
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #1045
Summary
Adds a
--parallel Nflag that runs up to N solver instances concurrently when verifying proof obligations. Without the flag (or with--parallel 1), behavior is unchanged (sequential).Problem
Verification of programs with many obligations is bottlenecked by sequential solver invocations. Each obligation spawns a separate solver process, waits for the result, then moves to the next.
Solution
When
--parallel Nis specified (N > 1), the verification pipeline splits into two phases:The worker pool design avoids the "wait for slowest in batch" bottleneck: if one obligation takes 10s and others take 1s, the fast-finishing workers immediately start on the next obligation instead of idling.
stopOnFirstErroris supported via a shared flag: on failure, workers stop claiming new jobs. Already-running jobs complete naturally; skipped jobs leave their placeholder results in place.Both the incremental and batch solver paths are safe for parallel use: the incremental backend spawns independent solver processes, and the batch path uses atomic
modifyGetfor filename counter generation.Pluggable discharge function: The full public API (
Strata.verify,Core.verify,verifySingleEnv,mkDefaultCoreSMTSolver) accepts amkDischarge : MkDischargeFnparameter (defaulting tomkDischargeFn). External solvers (e.g. using the AbstractSolver API) can provide their own discharge function factory.Performance
Benchmark: 30 obligations across 2 programs, z3 4.12.2, avg over 3 runs:
--parallel 1(sequential)--parallel 2--parallel 3--parallel 4Sweet spot is
--parallel 3-4. The 1→2 jump gives the biggest single improvement (1.88x), then diminishing returns as solver spawn overhead and sequential preprocessing become the bottleneck.Testing
All tests that pass without
--parallelalso pass with it. The sequential path (--parallel 1, the default) is unchanged.