Skip to content

Performance Series 2 (5/5): Faster quantifier-instantiation heuristic, plus code cleanup#3878

Open
unp1 wants to merge 7 commits into
mainfrom
bubel/quantheur-cleanup
Open

Performance Series 2 (5/5): Faster quantifier-instantiation heuristic, plus code cleanup#3878
unp1 wants to merge 7 commits into
mainfrom
bubel/quantheur-cleanup

Conversation

@unp1

@unp1 unp1 commented Jun 30, 2026

Copy link
Copy Markdown
Member

Intended Change

Code-quality cleanup of the quantifier-instantiation heuristic plus two behaviour-preserving speed-ups: (1) trigger-set construction is clarified and now has characterization tests, and a dead set-size heuristic is fixed; (2) ground substitutions are applied in a single term traversal instead of one pass per variable (~3.6 -> 1); (3) the arithmetic prover is skipped for non-arithmetic literals, which dominate (~98% even on arithmetic proofs). Behaviour-preserving (identical proof node counts across runAllProofs).

Benchmark

Automode time, median of 3 runs, serial forks (-PrapForks=1), isolated user.home per run; baseline = current main (8 representative proofs: 4 quantifier-heavy + 4 mixed). ArrayList.remove.1 is high-variance run-to-run — treat as noise. The gains concentrate on quantifier-heavy proofs (PUZ031p1, SYN550p1), as expected.

proof baseline (ms) this PR (ms) Δ
PUZ031p1 13712 7939 -42%
SimplifiedLinkedList.remove 17469 16651 -5%
Saddleback 13026 12586 -3%
SYN550p1 821 630 -23%
symmArray 12737 12129 -5%
gemplusDecimal 8378 8452 +1%
coincidence 2181 2220 +2%
ArrayList.remove.1 3339 3137 -6%
TOTAL 71663 63744 -11%

Plan

  • Add a focused per-PR benchmark to this description
  • Mark ready for review once the Performance Series 2 determinism gate passes (see overview)

Type of pull request

  • Refactoring (behaviour should not change or only minimally change)
  • There are changes to the (Java) code

Ensuring quality

  • I made sure that introduced/changed code is well documented (javadoc and inline comments).
  • I added new test case(s) for new functionality (TestTriggersSet characterization tests).
  • I have checked that runtime performance has not deteriorated.

Additional information and contact(s)

Part of Performance Series 2 — see the overview (#3879) for the combined benchmark and series context.

Created with AI tooling support.

The contributions within this pull request are licensed under GPLv2 (only) for inclusion in KeY.

@unp1 unp1 self-assigned this Jun 30, 2026
@unp1 unp1 changed the title Quantifier heuristics: trigger-set cleanup + one-pass substitution + arithmetic-prover guard Performance Series 2 (5/5): Faster quantifier-instantiation heuristic, plus code cleanup Jun 30, 2026
@unp1 unp1 force-pushed the bubel/quantheur-cleanup branch from e7b6156 to 67f45dc Compare June 30, 2026 18:24
unp1 added 7 commits June 30, 2026 23:32
Pin the current TriggersSet output for representative quantifier shapes (uni/multi/powerset, equality exclusion, negated implication guards, existential variables, conjunction clauses, and the no-outer-variable case) ahead of a rename/cleanup pass. A behavior-preservation net, not a claim the current output is ideal.

Created with AI tooling support
The three-argument intersect computed all three sizes from set0, so the 'intersect the two smaller sets first' optimization never engaged. Use the respective set sizes. The three-way intersection is order-independent so the result is unchanged; the only caller (SplittableQuantifiedFormulaFeature) inspects just the result's emptiness/size.

Created with AI tooling support
Rename for readability (triggers->elements, qvs->clauseVariables, setMultiSubstitution->combineElementSubstitutions, unifySubstitution->mergeIfCompatible, cryptic locals) and document the class. No behavior change.

Created with AI tooling support
Rename uqvs->universalVariables and the matching helpers, and turn the cycle detection copied from EqualityConstraint into readable, documented containsCycle/reachesItself. No behavior change.

Created with AI tooling support
Rename the trigger-discovery methods and locals (collectUniversalVariables, addMaximalUniTriggers, buildCoveringMultiTriggers, tryAddCoveringMultiTrigger, clauseVariables, ...), rename inner ClauseTrigger to ClauseTriggerFinder, document the multi-trigger powerset pruning, and fix smells (HashSet-declared LinkedHashSet, unused import, generic-array suppression). No behavior change.

Created with AI tooling support
Substitution.applyWithoutCasts applied each variable in its own
ClashFreeSubst pass -- one full traversal of the term per variable. As
the substitution is ground, all variables can be replaced in a single
shadow-aware traversal, keeping the per-variable path only as a fallback
for the rare cast case. Behaviour-preserving; cuts substitution time
roughly threefold on quantifier-heavy proofs.

Created with AI tooling support
When estimating quantifier instantiation cost, PredictCostProver calls
HandleArith.provedByArith for every literal/axiom pair. For a
non-arithmetic literal it allocated a cache key, took the cache lock and
ran formatArithTerm only to return the literal unproved -- and such
literals dominate (~98% of calls even on arithmetic proofs). Both entry
points now bail on a cheap arithmetic-shape check (>=, <=, plus = for the
single-argument variant), exactly the condition under which the full
prover would have returned the literal unchanged. Behaviour-preserving;
cuts refinement time by roughly a third.

Created with AI tooling support
@unp1 unp1 force-pushed the bubel/quantheur-cleanup branch from 67f45dc to 9d2ba94 Compare June 30, 2026 21:33
@unp1 unp1 marked this pull request as ready for review July 1, 2026 07:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants