Repository navigation
Solve floating-point queries with Z3's qffp tactic first - #98
Merged
Merged
Conversation
Z3's default solver bit-blasts floating point eagerly only for pure QF_FP/QF_FPBV. A
SampledMath UF or a string term (parseFloat) in the query sends it to the lazy theory_fpa of
the SMT core, which is far slower on these queries. Z3Handler.solve now gives every query with
an FP- or RM-sorted term to Tactic('qffp').solver() first (new Z3Handler.check_query):
- SAT counts only if the model satisfies every assertion (lifted and pre-lifting), checked on a
copy so model completion does not change the reported inputs; otherwise the default solver
decides.
- UNSAT is trusted (same fpa2bv rewriting the default solver uses on pure QF_FP).
- Unknown because the rlimit ran out, the timeout passed or the ResourceBudget interrupted the
context is the result (LIMIT/UNKNOWN as before), with no fallback. Any other unknown or a
Z3 exception falls back to the default solver with the remaining timeout and rlimit.
Whether a query has FP terms is computed once per cached constraint (kept in the cache entry)
with an iterative walk over the C API, plus the retry constraints.
--no-fp-tactic switches it off (Database.fp_tactic).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Contributor
Author
|
Full campaign: 1713 SV-COMP jobs (300 s CPU, no SA, sv-comp.cfg, 15 GB / -Xmx12g), dev 209cc0e and
Attribution: the 20 runs that changed were re-run with each change switched off ( This PR accounts for all verdict changes (with
float-nonlinear-calculation CPU -47%, juliet-java -50%. 🤖 Generated with Claude Code |
This was referenced Oct 21, 2026
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.
Z3's default solver bit-blasts floating point eagerly only for pure QF_FP/QF_FPBV queries. An uninterpreted function (the SampledMath models) or a string term (parseFloat) in an FP query makes it fall back to the lazy
theory_fpaof the SMT core, which is much slower on these queries.Changes
Z3Handler.solvegives every query that contains an FP- or RoundingMode-sorted term toTactic('qffp').solver()first, through the newZ3Handler.check_query. Whatever remains after bit-blasting (strings, Int arithmetic, arrays, UFs) is handled by the SMT core at the end of the tactic pipeline.model_completion=True, evaluated on a copy so the reported inputs are unchanged). Otherwise the default solver decides.--approximate-rlimit) reaches further.--no-fp-tacticswitches it off (on by default).Measured
--no-fp-tacticcoral16 is UNKNOWN again.tests/test_fp_tactic.py(selection incl. FP+UF/strings/arrays, model shape, fallback on unknown/exception/wrong model, no fallback on limit/timeout/interrupt, a real FP+UF core). Explorer suite: 227 passed, 6 skipped (dev: 200 passed, 6 skipped).Full-campaign numbers follow in a comment.
🤖 Generated with Claude Code