Skip to content

Make the strategy cost structure explicit#3904

Open
unp1 wants to merge 8 commits into
mainfrom
bubel/strategy-cost-cleanup
Open

Make the strategy cost structure explicit#3904
unp1 wants to merge 8 commits into
mainfrom
bubel/strategy-cost-cleanup

Conversation

@unp1

@unp1 unp1 commented Jul 10, 2026

Copy link
Copy Markdown
Member

Intended Change

This PR is a precursor to a careful refactoring of cost values assigned to rules.
It does not change any computed costs and is identical to current main. Its goal is too make
the current cost structure visible and to allow follow up PRs to consolidate them systematically.

The PR makes the cost structure explicit by naming the costs and organizing them in
three layers (for a detailed explanation see https://keyproject.github.io/key-docs/devel/StrategyCosts/) :

  • CostBand: cost bands express cost tiers for categories that are cross theory
    like (CLOSE, REWRITE, SUBST, …, DEFER, LAST_RESORT) with cost() and at(delta) for fine ordering within a tier. Each tier documents its meaning and, where present, hard ordering constraints (e.g. BLOCK_CONTRACT must stay cheaper than REWRITE and all
    symbolic-execution rules).
  • CombinationCost (new, key.core): costs whose meaning spans theories,
    with the two admission mechanisms documented — (1) rule sets that more than
    one strategy assigns a cost to (conflict-dispatched by
    ModularJavaDLStrategy; ORDERED_REWRITING for apply_equations,
    CNF_CONVERSION for apply_equations_andOr), and (2) taclets whose rule
    sets belong to different strategies, so the tuned quantity is the sum
    (APPLY_SELECT_EQ_EFFECTIVE for the applyEq taclet; the heap-side constant
    is derived from it, turning a previously comment-only "≈ −5700" coupling into
    checked arithmetic). A taclet/rule-set sweep verified these are the only such
    cases.
  • Theory-local cost tiers (new, key.core): FOLCost, the integer-arithmetic
    holders (PolynomialCost, LinearEquationCost, LinearInequationCost,
    NonlinearArithmeticCost, DivModCost — grouped anticipating a future split
    of the integer strategy), SymExCost, StringCost, JavaCardDLCost and
    HeapSelectCost (the pull-out-select pipeline, kept separate to pre-stage a
    future heap/select module). Constants are named for what they achieve;
    related values are expressed as arithmetic on their sibling
    (MERGE_POINT_SKIP = MERGE_RULE - 1000). Theory-local constants are
    deliberately absolute (not anchored to a band): retuning a band moves exactly
    the rules placed on it.

The five strategies (FOLStrategy, IntegerStrategy, SymExStrategy,
StringStrategy, JavaCardDLStrategy) are converted to this vocabulary;
theory-local constants are imported statically so call sites read as bare
names, while CostBand/CombinationCost stay qualified as a signal that a
shared level is involved.

The commits are per-theory checkpoints (FOL, Integer, SymEx, String,
JavaCardDL, then consolidation and readability) and each compiles and passes
runAllProofs (to check that all proofs stay identical to current main) on its own.

Type of pull request

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

Ensuring quality

  • The refactoring is byte-identical by construction: every named constant
    equals the literal it replaces, verified per theory.
  • Full runAllProofs after each theory checkpoint and after the consolidation
    and readability steps: 674/674 proofs, 0 failures.
  • Model-Search node-for-node comparison on an arithmetic proof corpus against
    the unmodified strategies: identical proofs (same node counts on all
    compared proofs).
  • I made sure that introduced/changed code is well documented (javadoc on every
    band, holder and constant; cross-references between the layers).
  • I made sure that new/changed end-user features are well documented: a new
    developer-guide page "Strategy Costs and the Cost-Band Ladder"
    (https://keyproject.github.io/key-docs/devel/StrategyCosts/) is pushed to
    key-docs together with this PR; the page carries an open-PR notice
    referencing this pull request, and this PR and the page reference each other.

Additional information and contact(s)

This PR is deliberately value-preserving. Follow-up PRs (independent of each
other, based on this one) will normalize individual values where the assessment
found them accidental — e.g. the relative order of goal closure and
loop-invariant application, the Long.MIN_VALUE / -20000 sentinel extremes,
and near-duplicate levels — each gated by its own runAllProofs and
node-for-node comparison.

PR created with AI tooling support

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

unp1 added 7 commits July 10, 2026 11:46
Introduce CostBand (ncore, the shared cross-theory cost-band vocabulary) and
FOLCost (FOL-theory-internal ordering constants), and convert FOLStrategy's
cost literals to them - byte-identical by construction. Deferred: RAP +
Model-Search node-for-node verification (holding proof runs for a benchmark).

Checkpoint before the Integer conversion so the two theory changes stay
separable for bisection if verification later flags a mismatch.

Created with AI tooling support
…hmeticCosts

Convert IntegerStrategy's ~50 cost literals to the shared CostBand ladder
(anchors) and to per-sub-theory holders in IntegerArithmeticCosts
(PolynomialCost / LinearEquationCost / LinearInequationCost /
NonlinearArithmeticCost / DivModCost), grouped to anticipate a future split of
the strategy. Byte-identical by construction; the old IN_EQ_SIMP_NON_LIN_COST /
POLY_DIVISION_COST fields move into the holders.

Deferred: RAP + Model-Search node-for-node verification (holding proof runs for
a benchmark). Checkpoint after FOL (21a475ebb9) so the two theory conversions
stay bisectable.

Created with AI tooling support
Byte-identical. Shared-ladder anchors -> CostBand (block/loop contracts
BLOCK_CONTRACT, loopInvariant LOOP_INVARIANT, concrete_java REWRITE,
simplify_java SIMPLIFY, simplify_prog_subset EXECUTE). SE-internal nudges ->
SymExCost (PROGRAM_STEP and its throwing/under-quantifier variants, method
expand pair, LOOP_SCOPE_EXPAND, MERGE_RULE + MERGE_POINT_SKIP delta,
MODAL_TAUTOLOGY, BOX_DIAMOND_CONV, SPLIT_IF, the 42 loop-contract tie-break).
EXECUTE reserved for genuine program-execution rules (merge is not one);
modal_tautology named separately from SUBST. Enabled-gates (longConst(0)) and
the findDepth scale left raw.

Created with AI tooling support
Byte-identical. String theory splits into an eager side (negatives, named in
StringCost: INTEGER_TO_STRING, REPLACE_INLINE, CHAR_TO_INT_LITERAL,
BELOW_MODALITY_PENALTY; plus stringsSimplify -> CostBand.NORMALIZE) and a lazy
unfold ladder (positives) anchored to CostBand.DEFER.at(delta), so each defOps*/
strings* rule reads as "defer, by this much". instantiate default longConst(0)
left raw; stringsConcatNotBothLiterals stays inftyConst.

Created with AI tooling support
Byte-identical; RAP verification pending (deferred to resume). Band uses
verified against the band docs: simplify_literals -> ELIMINATE, query_axiom ->
SOLVE, partialInvAxiom -> DEFER_STRONG, information_flow_contract_appl (1000000
sentinel) -> LAST_RESORT. The pull-out-select ladder -> HeapSelectCost (its own
holder, pre-staging a future heap/select module; carries a comment on the
apply_equations ~-5700 cross-theory coupling). Remaining axiom/observer/
comprehension/induction nudges -> JavaCardDLCost, named by meaning not by value
coincidence (JAVA_INTEGER_SEMANTICS/COMPREHENSION_SIMPLIFY != NORMALIZE,
AUTO_INDUCTION != TYPE). QueryExpandCost tuples, branch count, and enabled-gates
left raw.

Created with AI tooling support
Byte-identical consolidation after the five theory conversions:

- New CombinationCost holder for costs whose meaning spans strategies, with two
  documented admission mechanisms: (1) conflict-dispatched rule sets
  (ORDERED_REWRITING for apply_equations - the demodulation cost, guarded by
  term/monomial-ordering decrease at all four call sites; CNF_CONVERSION for
  apply_equations_andOr, shared deliberately by FOL's conjNormalForm), and
  (2) cost-sum couplings (APPLY_SELECT_EQ_EFFECTIVE = tuned sum of the dual-
  tagged applyEq taclet; HeapSelectCost.APPLY_SELECT_EQ is now derived from it,
  turning the old "about -5700" comment into checked arithmetic).
  FOLCost.APPLY_EQUATIONS/CNF_ORDERING and LinearEquationCost.APPLY_EQUATIONS/
  APPLY_EQ_AND_OR are removed in favour of the shared constants.
- JavaCardDL holders grouped per theory into JavaCardDLCosts.java
  (JavaCardDLCost + HeapSelectCost, Integer-style one file per theory).
- Below-scope penalty names aligned: StringCost.BELOW_MODALITY (matching
  DivModCost.BELOW_MODALITY), SymExCost.PROGRAM_STEP_BELOW_QUANTIFIER.

A sweep over all taclets and rule-set bindings verified completeness: exactly
the three conflict-dispatched rule sets exist (order_terms, apply_equations,
apply_equations_andOr, all FOL/Integer), and the only tuned cost-sum coupling
is the applyEq taclet covered above.

Created with AI tooling support
Pure cosmetic (byte-identical, no cost value changes):
- Rename LinearEquationCost.APPLY_EQ -> APPLY_EQ_MONOMIAL_TIEBREAK (it is a small
  rider delta on CombinationCost.ORDERED_REWRITING via the dual-tagged
  apply_eq_monomials taclet, not a standalone "cost 1"); javadoc clarified.
- Static-wildcard-import the theory-local cost holders in the single-holder
  strategies (FOLCost, SymExCost, StringCost, JavaCardDLCost+HeapSelectCost) so
  call sites read as bare names; the qualifier was pure redundancy there and
  forced spotless line wraps. CostBand and CombinationCost stay qualified (the
  prefix signals the shared ladder / a cross-theory cost). IntegerStrategy stays
  fully qualified: its 5 sub-holders' prefixes say which arithmetic layer.

Created with AI tooling support
@unp1 unp1 changed the title Make the strategy cost structure explicit: CostBand, CombinationCost, theory-local costs (value-preserving) Make the strategy cost structure explicit Jul 10, 2026
@unp1 unp1 added this to the v3.1.0 milestone Jul 10, 2026
@unp1 unp1 added Strategy 🛠 Maintenance Code quality and related things w/o functional changes labels Jul 10, 2026
@unp1 unp1 self-assigned this Jul 10, 2026
@unp1 unp1 force-pushed the bubel/strategy-cost-cleanup branch from 8489846 to 2839edc Compare July 10, 2026 10:02
- cost() and at(delta) return the cost as a constant strategy Feature
  (ConstFeature over NumberRuleAppCost - exactly what longConst produced), so
  call sites lose the redundant wrapper: longConst(CostBand.DEFER.at(500))
  becomes CostBand.DEFER.at(500), and bindRuleSet sites switch transparently to
  the Feature overload. The raw number stays available via value(); no code
  needed it. Behaviour unchanged (runAllProofs 674/674).
- Document the deliberate relation between the layers: theory-local constants
  are absolute values on the same cost line, not anchored to a band, so
  retuning a tier moves exactly the rules placed on it. Point CostBand's javadoc
  at a real theory holder (was a stale IntegerCost reference), and note in
  IntegerArithmeticCosts why the file is not named "IntegerCosts" (would read as
  an integer-valued RuleAppCost type).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

🛠 Maintenance Code quality and related things w/o functional changes Strategy

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant