Skip to content

Cost models for keepPolicies and dropPolicies (CIP-0168) - #7954

Open
Unisay wants to merge 8 commits into
masterfrom
yura/policy-filters-costing
Open

Unisay wants to merge 8 commits into
masterfrom
yura/policy-filters-costing

Conversation

@Unisay

@Unisay Unisay commented Sep 15, 2026

Copy link
Copy Markdown
Contributor

Adds the cost models for keepPolicies and dropPolicies: CPU and memory are both multiplied_sizes in the length of the policy list and the depth of the Value's outer map, eight new parameters. To make that shape sound, Value gains a fifth cache, the count of negative amounts per currency, which removes the only cache-maintenance term proportional to the number of amounts rather than the number of currencies; both filters become O(p log m).

The cache is maintained by insertCoin, unionValue, scaleValue and unValueData, whose benchmarks never held a negative amount and so never paid for it; they now do throughout, and the CPU models are refitted from a run on the reference machine.

cpu memory
keepPolicies multiplied_sizes {355913, 46004} multiplied_sizes {32, 32}
dropPolicies multiplied_sizes {356925, 57953} multiplied_sizes {32, 36}

Both filters fail on a Value with more than 8191 policies (policyFilterMaxSize), which is three to four times the most policies a 16 KB transaction can carry; assetCount v <= 8191 is a free conservative guard for callers. The pages under doc/cost-models draw a two-argument model as a translucent surface, tabulate how many points it over- and undercharges and by how much, and let the coefficients be edited in place to try a candidate fit against the same table.

Collapses #7930, #7937 and #7946 into one PR. Implements IntersectMBO/plutus-private#2310 and IntersectMBO/plutus-private#2311.

@github-actions

github-actions Bot commented Sep 15, 2026

Copy link
Copy Markdown
Contributor
PR Preview Action v1.6.3

🚀 View preview at
https://IntersectMBO.github.io/plutus/pr-preview/cost-models/pr-7954/

Built to branch gh-pages at 2026-09-18 09:57 UTC.
Preview will be ready when the GitHub Pages deployment is complete.

@Unisay Unisay self-assigned this Sep 15, 2026
@Unisay
Unisay force-pushed the yura/policy-filters-costing branch from 0cc03d0 to 3f85fb2 Compare September 15, 2026 14:06
@Unisay
Unisay deployed to github-pages September 15, 2026 14:06 — with GitHub Actions Active
@Unisay
Unisay force-pushed the yura/policy-filters-costing branch from 3f85fb2 to b1883c1 Compare September 15, 2026 14:17
@Unisay
Unisay deployed to github-pages September 15, 2026 14:17 — with GitHub Actions Active
@Unisay
Unisay force-pushed the yura/policy-filters-costing branch from b1883c1 to 9655366 Compare September 15, 2026 15:54
@Unisay
Unisay deployed to github-pages September 15, 2026 15:54 — with GitHub Actions Active
@Unisay
Unisay force-pushed the yura/policy-filters-costing branch from 9655366 to ac15cf8 Compare September 15, 2026 16:02
@Unisay
Unisay deployed to github-pages September 15, 2026 16:02 — with GitHub Actions Active
@Unisay
Unisay force-pushed the yura/policy-filters-costing branch from ac15cf8 to 731b32f Compare September 16, 2026 10:45
@Unisay
Unisay deployed to github-pages September 16, 2026 10:45 — with GitHub Actions Active
@Unisay
Unisay force-pushed the yura/policy-filters-costing branch from 731b32f to de2f3ea Compare September 16, 2026 15:46
@Unisay
Unisay deployed to github-pages September 16, 2026 15:46 — with GitHub Actions Active
@Unisay
Unisay force-pushed the yura/policy-filters-costing branch from de2f3ea to d2de75c Compare September 17, 2026 13:27
@Unisay
Unisay deployed to github-pages September 17, 2026 13:27 — with GitHub Actions Active
`Value` gains a fifth cache, the number of negative amounts per currency, so that removing a whole currency subtracts a cached count instead of recounting its amounts. That recount was the only cache-maintenance term proportional to the number of amounts rather than to the number of currencies, and the one a cost model cannot see.

The cache is maintained by `insertCoin`, `unionValue`, `scaleValue` and `unValueData`. Their memory models account for the extra field, and their CPU models are refitted from benchmarks that hold negative amounts throughout: the rows they were fitted on never held one, so they never paid for the extra search path, and on inputs that do the previous `insertCoin` model undercharged every row, by up to 1.55x, and `scaleValue` three rows in four, by up to 1.46x. Benchmarked on the reference machine.
Looking each id up in the outer map and inserting what it finds costs p log m whatever the list is. Building a `Set` of the list first cost p log p however small the `Value`, and folding the restricted map through `pack'` recounted the negative amounts of every currency kept; with the per-currency counts the caches now come from the kept currencies alone, so both filters are logarithmic in the `Value`.
`ValueOuterDepth` measures the depth of the outer map and nothing else. Neither filter descends an inner map, so `ValueMaxDepth` would over-measure a `Value` of one policy and thousands of tokens by almost the whole measure. The empty `Value` measures 1 rather than 0, so that a product-shaped model cannot charge a policy list its intercept alone.
One generator for both builtins, since both walk the policy list once at one outer-map descent per element. A random sample over the plane of list length and outer-map depth, plus sweeps that isolate the depth term, check that the tokens per policy do not show, and vary what the model cannot see. Each family is defined next to its own description; see Note [Benchmarking keepPolicies and dropPolicies] for what they have in common.
CPU and memory are both `multiplied_sizes` in the length of the policy list and the depth of the `Value`'s outer map, eight new parameters. The CPU models take `fit.fan`'s intercept and the smallest slope that covers every benchmark row rather than nine in ten: the grid is the whole domain the builtins accept, and the cost of a descent keeps growing with the depth up to its edge, so the rows `fit.fan` would leave out are the deepest maps a script can present. Benchmarked on the reference machine: https://github.com/IntersectMBO/plutus/actions/runs/34979629812
Two interactive pages under doc/cost-models plotting the benchmark rows and the shipped model on the plane of list length and outer-map depth, so the charge can be read against the measurement point by point. The pages read the model from the cost-model JSON rather than refitting it.

The shared script gains what reading a two-argument model needs: the model drawn as a translucent surface over the whole plane (the default) or as a cross at each benchmark point, linear or logarithmic axes, a table of how many points the model over- and undercharges with the median and worst factor on each side, and coefficients that can be edited in place so a candidate fit can be tried by hand and read off the same table and surface. The two existing three-dimensional pages, `unionValue` and `valueContains`, use the same controls. A page can be pointed at explicit CSV and JSON files with `?csv=...&json=...`, e.g. a checkout served locally.
Both filters now fail on a `Value` with more than `policyFilterMaxSize` policies. Their models charge on the length of the list times the depth of the outer map, and past that depth a descent into an outer map that no longer fits in cache outgrows the shape; the bound makes those inputs unreachable by construction rather than by an argument about protocol parameters. The benchmark grid stops at the bound, since a row beyond it would fail instead of timing a descent.
@Unisay
Unisay force-pushed the yura/policy-filters-costing branch from d2de75c to 39934e8 Compare September 18, 2026 09:57
@Unisay
Unisay deployed to github-pages September 18, 2026 09:57 — with GitHub Actions Active
@Unisay
Unisay marked this pull request as ready for review September 18, 2026 09:57
@Unisay
Unisay deployed to github-pages September 18, 2026 12:56 — with GitHub Actions Active
@github-actions

Copy link
Copy Markdown
Contributor

@Unisay
Unisay requested a review from kwxm September 18, 2026 13:30
The pages read the benchmark CSV and the cost model JSON from a branch of this
repository and remember the last branch used in the browser, so a preview link
without a branch can plot another branch's data. The preview comment now carries
`?branch=<head ref>`, that parameter wins over what the browser remembers, and
links between pages keep it.
@Unisay
Unisay force-pushed the yura/policy-filters-costing branch from 272a2ee to 3034334 Compare September 18, 2026 13:31
@Unisay
Unisay deployed to github-pages September 18, 2026 13:31 — with GitHub Actions Active
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.

1 participant