Skip to content

Cost model for keepPolicies (CIP-0168) - #7930

Draft
Unisay wants to merge 3 commits into
masterfrom
yura/issue-2310-keep-policies-costing
Draft

Cost model for keepPolicies (CIP-0168)#7930
Unisay wants to merge 3 commits into
masterfrom
yura/issue-2310-keep-policies-costing

Conversation

@Unisay

@Unisay Unisay commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

Adds the cost model for keepPolicies, five parameters: CPU linear in the length of the policy list and in Value.totalSize, memory linear in Value.totalSize. The denotation takes the plain Value, because instance ExMemoryUsage Value already reports totalSize. ValueOuterSize is not the measure here even though keepPolicies looks like policies from the outside: it reports the policy count, so a Value of one policy holding 10000 tokens would be measured as size 1 while pack' folds all 10000 pairs.

Memory is six words per new outer-map node, at most one per pair in the result. The result shares the inner maps wholesale and the policy ids by pointer, so the outer spine is the only new structure.

Implements IntersectMBO/plutus-private#2310.

@Unisay Unisay self-assigned this Sep 1, 2026
@Unisay
Unisay changed the base branch from master to yura/issue-2306-keep-drop-policies September 1, 2026 12:37
@Unisay
Unisay force-pushed the yura/issue-2310-keep-policies-costing branch from b7c3892 to ae4a298 Compare September 2, 2026 08:44
@github-actions

github-actions Bot commented Sep 2, 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-7930/

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

@Unisay
Unisay force-pushed the yura/issue-2310-keep-policies-costing branch from ae4a298 to e491998 Compare September 2, 2026 09:15
@Unisay
Unisay force-pushed the yura/issue-2310-keep-policies-costing branch from e491998 to 3dc9dba Compare September 2, 2026 10:10
Base automatically changed from yura/issue-2306-keep-drop-policies to master September 3, 2026 11:57
Every point of the main sweep is the costliest input for its pair of sizes:
the builtin skips the part of the outer map the list cannot reach, so the
pairs that cost anything are the pairs the list names, and packing them
into as few policies as the list covers puts all of them in reach.

The list length and the total size are sampled log-uniformly and
independently, and two sweeps hold both fixed while varying what a cost model
cannot see: the policy count and how much of the list hits. Both move the
cost, so no model of the two sizes is right everywhere, and these sweeps
are what measures how far wrong it gets. The shape sweep runs against a
short list as well as a long one, because the list term swamps the `Value`
term once the list is long.

The points with an empty `Value` double as a control on the rig: the builtin
returns before it looks at the list there, so the same list costs about a
hundredth of what it costs against a `Value` that is not empty. A benchmark
that floated the list work out of the measured loop would show no such gap.

Shares the log-uniform sampler and the `Value` generator with the `policies`
benchmark, which had its own copies of both.
Linear in the length of the policy list and in `Value.totalSize`, which
is what `instance ExMemoryUsage Value` already reports, so the denotation
needs no size wrapper. Five parameters, fitted against semantics variant E,
which is what PlutusV3 and PlutusV4 map to.

The fit undercharges 8 of its 126 points, at worst by 1.28x and in seven of
the eight by between 1.01x and 1.18x. That is the file's normal condition:
scored the same way against their own rows, the shipped `addInteger`
undercharges 48% of its 225 rows, `appendByteString` 59% of 441 and
`valueContains` 49% of 1158, none by more than 1.2x.

Points with an empty outer map are left out of the fit, because the builtin
returns before it looks at the list and an element costs single-digit
nanoseconds there against the hundreds the real work costs. Scoring on
only the 120 rows the fit sees gives 7 undercharges rather than 8.

Memory is six words per new outer-map node, at most one per pair in the
result: the result shares the inner maps wholesale and the policy ids by
pointer, so the outer spine is the only new structure.

Implements IntersectMBO/plutus-private#2310.
One 3D plot: list length against `Value.totalSize` against time, with
the measured points in blue and the model's charge for the same inputs
in red. The spread at a fixed pair of sizes is what no model of those two
numbers can capture, and in three dimensions it reads straight off the plot.

The page computes a least-squares fit from the CSV it has already loaded and
reports it beside the shipped coefficients, so the figures follow whatever
data the page is pointed at rather than the JSON alone. `fitLinearInXAndY`
in the shared code does that and reproduces what `models.R` gets from the
same rows.

The plot panel is created in `renderPlots` rather than declared in the
page, because the shared loader replaces the contents of `#plot-container`
with its own status message before it calls the page's render. Every other
page targets that container itself, so nothing there noticed.
@Unisay
Unisay force-pushed the yura/issue-2310-keep-policies-costing branch from 3dc9dba to b181995 Compare September 3, 2026 11:57
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.

1 participant