Skip to content

Count nested rewrite savings once per retained argument - #271

Open
DDDOH wants to merge 1 commit into
mlb2251:mainfrom
DDDOH:fix/nested-multiuse-utility
Open

DDDOH wants to merge 1 commit into
mlb2251:mainfrom
DDDOH:fix/nested-multiuse-utility

Conversation

@DDDOH

@DDDOH DDDOH commented Oct 13, 2026

Copy link
Copy Markdown

Nested matches inside a repeated abstraction argument can have their savings counted twice, although rewriting the outer match retains the argument only once. This makes the predicted cost disagree with rewrite_fast and triggers the mismatch assertion.

Minimal example (default costs):

program:     (f (g x (L x y)) (L (g x (L x y)) z))
abstraction: (#2 #1 (L #1 #0))
rewrite:     (fn_0 z (fn_0 y x g) f)

The original costs 1312, and the rewrite costs 706. The inner rewrite saves 101. The old prediction is 605: it also counts the savings in the copy removed by the outer rewrite. With definition cost 104, net utility should be 502.

For candidates with repeated arguments, compute marginal savings bottom-up by comparing:

  • retaining all rewritten children;
  • applying the abstraction and retaining the rewritten value of each argument once.

Memoize subtree utility, then pass the marginal deltas through the existing root/task/weight aggregation. Candidates without repeated arguments keep the existing path. Cost weights, pruning flags and mismatch assertions are unchanged.

Five standalone Rust regressions cover the exact example, nonmatching wrappers and nesting depths, lambda scope, overlapping matches, and weighted/task-grouped inputs. The original four unweighted regression cases fail on the base; all five pass with this patch.

Validation (macOS arm64, Rust 1.94.0):

  • cargo test --release --test nested_multiuse: 5 passed.
  • Existing integration tests: 27 passed, with the expensive python_symbols_regression filtered out on this branch.
  • Existing TDFA tests: 4 passed.
  • cargo clippy --no-deps -- -Dwarnings: passed.
  • A small CLI comparison on nuts-bolts, furniture, wheels and dials (3 iterations, arity 2, three repetitions) produced identical abstractions, rewritten programs and final costs. Other regression tests were running concurrently, so its timings are not evidence of performance parity. The complete documented benchmark suite has not been run.

A full fuzz baseline on unmodified 350804b produced 98 passes and two existing 600-second timeouts (seeds 62 and 81); full patched fuzz coverage remains unverified. I checked the open optimization PRs #195 and #244: they target older correction code and do not contain this fix. The historical mismatch report #129 has a similar symptom, but this PR does not assume it has the same root cause.

This change is independent of the rejected-pattern/utility_by_rewrite crash fix.

Copilot AI balanced review requested due to automatic review settings October 13, 2026 02:55

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants