From 6b74464d8c0f95c8e195cc5f8cfb9d80a167912d Mon Sep 17 00:00:00 2001 From: Yuriy Lazaryev Date: Wed, 19 Aug 2026 17:53:27 +0200 Subject: [PATCH] Cost model for `policies` (CIP-0168) Benchmarks the builtin over 101 values and adds the four resulting parameters to the cost model record, the JSON variants and the ledger API parameter lists. The model is fitted through the measurements rather than by least squares. The cost per policy falls across the range, from 15.2ns below 5000 policies to 14.1ns above 30000, and least squares answers that by trading slope for intercept: it returns an intercept of 7.16us where an empty value measures 0.24us, and that intercept then dominates the charge below roughly 500 policies. Values on chain hold a handful. The model charges the largest per-policy rate measured instead, with the intercept set to the largest amount by which any observation exceeds that rate, which is the measured cost of the empty value. The line sits above every measurement, over-charges the largest benchmarked values by 16%, and prices realistic ones around twenty times cheaper than the least-squares line. The benchmark holds one token per policy so that the total size equals the number of policies. Values carrying more tokens per policy have a larger size for the same work, so they are over-charged rather than under-charged. Memory is charged at three words per cons cell: the result shares its bytestrings with the `Value`, so only the list spine is new. Implements IntersectMBO/plutus-private#2309. --- doc/cost-models/policies/index.html | 118 ++++++++++++ doc/cost-models/policies/plot.js | 171 ++++++++++++++++++ doc/cost-models/shared/utils.js | 1 + ..._154936_yuriy.lazaryev_policies_costing.md | 3 + .../budgeting-bench/Benchmarks/Values.hs | 55 +++++- .../create-cost-model/BuiltinMemoryModels.hs | 6 + .../CreateBuiltinCostModel.hs | 2 + .../cost-model/data/benching-conway.csv | 101 +++++++++++ .../cost-model/data/builtinCostModelA.json | 16 ++ .../cost-model/data/builtinCostModelB.json | 16 ++ .../cost-model/data/builtinCostModelC.json | 16 ++ .../cost-model/data/builtinCostModelD.json | 16 ++ .../cost-model/data/builtinCostModelE.json | 16 ++ plutus-core/cost-model/data/models.R | 38 +++- plutus-core/cost-model/test/TestCostModels.hs | 2 + .../src/PlutusCore/Default/Builtins.hs | 2 +- .../Evaluation/Machine/BuiltinCostModel.hs | 1 + .../Evaluation/Machine/ExBudgetingDefaults.hs | 1 + .../src/PlutusLedgerApi/V1/ParamName.hs | 4 + .../src/PlutusLedgerApi/V2/ParamName.hs | 4 + .../src/PlutusLedgerApi/V3/ParamName.hs | 4 + .../src/PlutusLedgerApi/V4/ParamName.hs | 4 + .../test/Spec/CostModelParams.hs | 8 +- .../test/Spec/Data/CostModelParams.hs | 8 +- 24 files changed, 602 insertions(+), 11 deletions(-) create mode 100644 doc/cost-models/policies/index.html create mode 100644 doc/cost-models/policies/plot.js create mode 100644 plutus-core/changelog.d/20260819_154936_yuriy.lazaryev_policies_costing.md diff --git a/doc/cost-models/policies/index.html b/doc/cost-models/policies/index.html new file mode 100644 index 00000000000..b0824f6d133 --- /dev/null +++ b/doc/cost-models/policies/index.html @@ -0,0 +1,118 @@ + + + + + + Policies - Plutus Cost Model Visualization + + + + + + +
+

Policies Cost Model Visualization

+

+ Interactive visualization of benchmark data and fitted cost model for the Policies builtin function. + This function returns the currency symbols of a Value in ascending order. +

+ +
+

Data Source Configuration

+
+
+ +
+ + +
+
+
+ + +
+
+ + +
+
+ +
+
+
+ +
+

Plot Controls

+
+
+ + +
+
+ + +
+
+
+ +
+
+
Loading data and generating plot...
+
+ +
+

Plot Information

+ +
+
+
X-axis:
+
Value Size
+ +
Y-axis:
+
Time (nanoseconds)
+ +
Description:
+
Each point represents one benchmark run
+
+
+ +
+
Cost Model Type:
+
Loading...
+ +
Model Formula (net):
+
Loading...
+ +
Overhead:
+
Loading...
+
+ +
+
+
Data points:
+
-
+ +
Value Size range:
+
-
+ +
Time range:
+
-
+
+
+ +
+
+
+
+
+
+ + + + + + + diff --git a/doc/cost-models/policies/plot.js b/doc/cost-models/policies/plot.js new file mode 100644 index 00000000000..6419da09279 --- /dev/null +++ b/doc/cost-models/policies/plot.js @@ -0,0 +1,171 @@ +// Policies plot configuration and rendering + +// Configuration +const FUNCTION_NAME = 'Policies'; // CSV uses PascalCase +const COST_MODEL_NAME = 'policies'; // JSON uses camelCase +const ARITY = 1; + +// Global state +let benchmarkData = []; +let modelPredictions = []; +let costModel = null; +let overhead = 0; +let showModel = true; +let yAxisMode = 'zero'; + +setupCostModelPage({ + slug: 'policies', + functionName: FUNCTION_NAME, + costModelName: COST_MODEL_NAME, + arity: ARITY, + render(data) { + ({ benchmarkData, costModel, overhead, modelPredictions } = data); + updateInfoPanel(); + renderPlot(); + }, + setupControls +}); + +function updateInfoPanel() { + // Calculate stats + const stats = calculateStats(benchmarkData, 0); + + // Update data points + document.getElementById('info-data-points').textContent = stats.dataPoints; + + // Update ranges + if (stats.minArg !== undefined) { + document.getElementById('info-x-range').textContent = `${stats.minArg} - ${stats.maxArg}`; + } + + document.getElementById('info-time-range').textContent = stats.timeRange; + + // Update model info + if (costModel) { + document.getElementById('info-model-type').textContent = costModel.modelType; + document.getElementById('info-model-formula').textContent = formatModelFormula( + costModel.modelType, + costModel.coefficients + ); + } else { + document.getElementById('info-model-type').textContent = 'Not available'; + document.getElementById('info-model-formula').textContent = 'Cost model not found'; + } + + // Update overhead + if (overhead > 0) { + document.getElementById('info-overhead').textContent = + `${overhead.toFixed(2)} ns (arity ${ARITY}) added to predictions`; + } else { + document.getElementById('info-overhead').textContent = 'Not calculated'; + } +} + +function renderPlot() { + // Prepare benchmark trace + const benchmarkX = benchmarkData.map(d => d.args[0]); + const benchmarkY = benchmarkData.map(d => d.time); + + const benchmarkTrace = { + x: benchmarkX, + y: benchmarkY, + mode: 'markers', + type: 'scatter', + name: 'Benchmark Data', + marker: { + size: 6, + color: '#0033AD', + opacity: 0.7 + } + }; + + const traces = [benchmarkTrace]; + + // Prepare model trace if available + if (showModel && modelPredictions.length > 0) { + const modelX = modelPredictions.map(d => d.args[0]); + const modelY = modelPredictions.map(d => d.predictedTime); + + const modelTrace = { + x: modelX, + y: modelY, + mode: 'markers', + type: 'scatter', + name: 'Model Predictions', + marker: { + size: 6, + color: '#E53E3E', + opacity: 0.4, + symbol: 'x' + } + }; + + traces.push(modelTrace); + } + + // Layout configuration + const layout = { + title: { + text: `${FUNCTION_NAME} - Benchmark vs Model`, + font: { size: 20 } + }, + xaxis: { + title: 'Value Size', + gridcolor: '#E0E0E0' + }, + yaxis: { + title: 'Time (nanoseconds)', + gridcolor: '#E0E0E0' + }, + hovermode: 'closest', + showlegend: true, + legend: { + x: 0.02, + y: 0.98, + bgcolor: 'rgba(255, 255, 255, 0.8)', + bordercolor: '#BDC3C7', + borderwidth: 1 + }, + plot_bgcolor: '#FAFAFA', + paper_bgcolor: 'rgba(0,0,0,0)' + }; + + // Set Y-axis range based on mode + if (yAxisMode === 'zero') { + layout.yaxis.range = [0, Math.max(...benchmarkY) * 1.1]; + } else { + const minY = Math.min(...benchmarkY); + const maxY = Math.max(...benchmarkY); + const padding = (maxY - minY) * 0.1; + layout.yaxis.range = [minY - padding, maxY + padding]; + } + + // Config + const config = { + responsive: true, + displayModeBar: true, + displaylogo: false + }; + + // Render + // Clear loading message + const container = document.getElementById('plot-container'); + container.innerHTML = ''; + Plotly.newPlot('plot-container', traces, layout, config); +} + +function setupControls() { + // Show/hide model checkbox + const showModelCheckbox = document.getElementById('show-model'); + showModelCheckbox.addEventListener('change', (e) => { + showModel = e.target.checked; + renderPlot(); + }); + + // Y-axis mode selector + const yAxisModeSelect = document.getElementById('y-axis-mode'); + yAxisModeSelect.addEventListener('change', (e) => { + yAxisMode = e.target.value; + renderPlot(); + }); +} diff --git a/doc/cost-models/shared/utils.js b/doc/cost-models/shared/utils.js index 71906fa8b78..7a9c974fe57 100644 --- a/doc/cost-models/shared/utils.js +++ b/doc/cost-models/shared/utils.js @@ -505,6 +505,7 @@ const PAGES = [ ['insertcoin', 'InsertCoin'], ['unionvalue', 'UnionValue'], ['scalevalue', 'ScaleValue'], + ['policies', 'Policies'], ['listtoarray', 'ListToArray'], ['lengthofarray', 'LengthOfArray'], ['indexarray', 'IndexArray'], diff --git a/plutus-core/changelog.d/20260819_154936_yuriy.lazaryev_policies_costing.md b/plutus-core/changelog.d/20260819_154936_yuriy.lazaryev_policies_costing.md new file mode 100644 index 00000000000..e72921336b2 --- /dev/null +++ b/plutus-core/changelog.d/20260819_154936_yuriy.lazaryev_policies_costing.md @@ -0,0 +1,3 @@ +### Added + +- Cost model for the `policies` builtin ([CIP-0168](https://cips.cardano.org/cip/CIP-0168)), with four new cost model parameters. Linear in the size of the `Value`. diff --git a/plutus-core/cost-model/budgeting-bench/Benchmarks/Values.hs b/plutus-core/cost-model/budgeting-bench/Benchmarks/Values.hs index 1c29fa77aae..e916b8a5abd 100644 --- a/plutus-core/cost-model/budgeting-bench/Benchmarks/Values.hs +++ b/plutus-core/cost-model/budgeting-bench/Benchmarks/Values.hs @@ -21,7 +21,16 @@ import Data.Map.Strict qualified as Map import Data.Word (Word8) import GHC.Stack (HasCallStack) import PlutusCore - ( DefaultFun (InsertCoin, LookupCoin, ScaleValue, UnValueData, UnionValue, ValueContains, ValueData) + ( DefaultFun + ( InsertCoin + , LookupCoin + , Policies + , ScaleValue + , UnValueData + , UnionValue + , ValueContains + , ValueData + ) ) import PlutusCore.Builtin (BuiltinResult (BuiltinFailure, BuiltinSuccess, BuiltinSuccessWithLogs)) @@ -57,6 +66,7 @@ makeBenchmarks gen = , insertCoinBenchmark gen , unionValueBenchmark gen , scaleValueBenchmark gen + , policiesBenchmark gen ] ---------------------------------------------------------------------------------------------------- @@ -368,6 +378,49 @@ scaleValueArgs gen = replicateM 200 $ do value = buildValue policyIds [tokenName] amt pure (scalar, value) +---------------------------------------------------------------------------------------------------- +-- Policies ---------------------------------------------------------------------------------------- + +{- Note [Benchmarking policies on the one-token-per-policy diagonal] +`policies` is \(O(m)\) in the size of the outer map, but the argument is costed by +`ValueTotalSize` (the `ExMemoryUsage Value` instance the denotation uses), which measures +the total number of `(policy, token)` pairs. Those two agree only when every policy holds +exactly one token, so the generator fixes that shape: the resulting fit is keyed on a size +measure that equals the number of policies. + +This is deliberately the worst case per unit of the size measure. For any other shape the +total size exceeds the number of policies, so the real cost is lower than the fitted model +predicts and the model over-charges. Benchmarking off the diagonal instead would fit a +shallower slope and under-charge the one-token-per-policy case, which is the failure +direction that matters. + +`nf` rather than `whnf`, for the same reason as `valueData`: the result is a lazy list and +`whnf` would stop at the first cons cell. +-} +policiesBenchmark :: StdGen -> Benchmark +policiesBenchmark gen = + createOneTermBuiltinBenchWithWrapper_NF + ValueTotalSize + Policies + [] + (runBenchGen gen policiesArgs) + +{-| Maximum number of policies for `policies` benchmarking, matching the bound used for +`valueData` so the generated `Value`s stay in the same size regime as the other +single-argument `Value` benchmarks. -} +maxPoliciesEntries :: Int +maxPoliciesEntries = Value.valueDataMaxSize + +{-| Generate `Value`s holding one token per policy, so that total size equals the number of +policies. See Note [Benchmarking policies on the one-token-per-policy diagonal]. -} +policiesArgs :: StatefulGen g m => g -> m [Value] +policiesArgs gen = + (Value.empty :) <$> replicateM 100 do + numPolicyIds <- uniformRM (1, maxPoliciesEntries) gen + policyIds <- replicateM numPolicyIds (generateKey gen) + tokenName <- generateKey gen + pure $ buildValue policyIds [tokenName] (mkQuantity 1) + ---------------------------------------------------------------------------------------------------- -- Value Generators -------------------------------------------------------------------------------- diff --git a/plutus-core/cost-model/create-cost-model/BuiltinMemoryModels.hs b/plutus-core/cost-model/create-cost-model/BuiltinMemoryModels.hs index cd06085cecb..cf39d26cd7d 100644 --- a/plutus-core/cost-model/create-cost-model/BuiltinMemoryModels.hs +++ b/plutus-core/cost-model/create-cost-model/BuiltinMemoryModels.hs @@ -382,6 +382,12 @@ builtinMemoryModels = -- the array; only the spine is new, at three words per cons cell. The nonzero -- intercept keeps the cost nonzero for the empty index list. paramMultiIndexArray = Id $ ModelTwoArgumentsLinearInY $ OneVariableLinearFunction 4 3 + , -- `policies` returns the outer map's keys. The bytestrings are shared with the + -- `Value`, so only the list spine is new, at three words per cons cell (as for + -- `multiIndexArray`). The size measure is the total number of (policy, token) pairs, + -- which is at least the number of policies, so this over-charges values holding more + -- than one token per policy rather than under-charging any of them. + paramPolicies = Id $ ModelOneArgumentLinearInX $ OneVariableLinearFunction 4 3 } where identityFunction = OneVariableLinearFunction 0 1 diff --git a/plutus-core/cost-model/create-cost-model/CreateBuiltinCostModel.hs b/plutus-core/cost-model/create-cost-model/CreateBuiltinCostModel.hs index 3cdb4c13cd9..d3cd9465f5b 100644 --- a/plutus-core/cost-model/create-cost-model/CreateBuiltinCostModel.hs +++ b/plutus-core/cost-model/create-cost-model/CreateBuiltinCostModel.hs @@ -154,6 +154,7 @@ builtinCostModelNames = , paramUnionValue = "unionValueModel" , paramScaleValue = "scaleValueModel" , paramMultiIndexArray = "multiIndexArrayModel" + , paramPolicies = "policiesModel" } {-| Loads the models from R. @@ -310,6 +311,7 @@ createBuiltinCostModel bmfile rfile = do paramUnionValue <- getParams readCF2 paramUnionValue paramScaleValue <- getParams readCF2 paramScaleValue paramMultiIndexArray <- getParams readCF2 paramMultiIndexArray + paramPolicies <- getParams readCF1 paramPolicies pure $ BuiltinCostModelBase {..} diff --git a/plutus-core/cost-model/data/benching-conway.csv b/plutus-core/cost-model/data/benching-conway.csv index b3c15f50d1d..4da098ee036 100644 --- a/plutus-core/cost-model/data/benching-conway.csv +++ b/plutus-core/cost-model/data/benching-conway.csv @@ -14781,3 +14781,104 @@ MultiIndexArray/128/656,9.742384457259018e-6,9.738226628587493e-6,9.758796384809 MultiIndexArray/2048/250,4.545746465191931e-6,4.542337915786206e-6,4.549915914643576e-6,1.2382943128493691e-8,7.933523427199416e-9,1.884083220446766e-8 MultiIndexArray/2048/500,8.030964088467131e-6,8.027945849897267e-6,8.038003334134253e-6,1.4344883735867401e-8,7.222525582368531e-9,2.708292118501812e-8 MultiIndexArray/2048/1024,1.5908025068953797e-5,1.5891687337303956e-5,1.595130243978917e-5,8.451021253065874e-8,3.66756042104449e-8,1.6477584846151207e-7 +Policies/0,9.131855522970573e-7,9.126126628886761e-7,9.138414853838659e-7,2.143248345388286e-9,1.7846318035511555e-9,2.9502029971041177e-9 +Policies/21933,3.135502232821667e-4,3.132424920742215e-4,3.139915491546955e-4,1.2370355588879281e-6,9.137504820862114e-7,1.6931361466004032e-6 +Policies/33125,4.648660927509344e-4,4.6310565494019984e-4,4.666304873531442e-4,5.766783535923867e-6,5.02858860969426e-6,7.17575868653308e-6 +Policies/15568,2.231483897239813e-4,2.228426017730975e-4,2.237459926509625e-4,1.4878215252044066e-6,9.42921107844315e-7,2.7526241455614773e-6 +Policies/16202,2.337068306186552e-4,2.331115402266963e-4,2.3449660158742866e-4,2.2969714224806536e-6,1.6190427025662178e-6,3.590256854030701e-6 +Policies/31535,4.6182415531563807e-4,4.6110575853186905e-4,4.6282161912180214e-4,2.9853640209979655e-6,2.1157817532639455e-6,4.443586490374839e-6 +Policies/10623,1.6649508256592188e-4,1.6568233382409405e-4,1.6726561920083876e-4,2.713760983771339e-6,2.2320513309573755e-6,3.3237329922601326e-6 +Policies/32298,4.6839593009820324e-4,4.674015525245757e-4,4.697699277804703e-4,4.0002425702528185e-6,2.9421678815873625e-6,6.0845075439867145e-6 +Policies/4941,7.334819655801512e-5,7.3199776435787e-5,7.347381126141131e-5,4.675142259727988e-7,3.565004190835575e-7,6.020809038752586e-7 +Policies/25737,3.690081510276924e-4,3.675575979571992e-4,3.7078792385278564e-4,5.592286943945871e-6,4.64879572743689e-6,6.631172737995925e-6 +Policies/32672,4.5509179012548053e-4,4.540592011804767e-4,4.5609542930729653e-4,3.4705496788152714e-6,2.81319364576823e-6,4.072668139800535e-6 +Policies/29569,4.1753562551116735e-4,4.1672991874438576e-4,4.1877552978006116e-4,3.362766416543673e-6,2.3810896179615394e-6,5.232424124819834e-6 +Policies/20634,2.9343774232427206e-4,2.927893693479051e-4,2.940901797453179e-4,2.1336909326303566e-6,1.8268182162337883e-6,2.583350574306775e-6 +Policies/30075,4.291187209772412e-4,4.2848028909823305e-4,4.2983234496415566e-4,2.221874305686318e-6,1.8234445861745025e-6,2.936066455547135e-6 +Policies/15351,2.2911934439554752e-4,2.269198362717838e-4,2.3079893667088712e-4,6.483169131060017e-6,5.6170728341518e-6,7.365009127193493e-6 +Policies/36822,5.097045984839868e-4,5.081561016173017e-4,5.116860160318286e-4,6.033723048960552e-6,4.550781650502326e-6,7.92080924860203e-6 +Policies/15993,2.397581800722469e-4,2.3838818687263092e-4,2.409128847290993e-4,4.156100908622073e-6,3.4230057105340304e-6,5.10710176417085e-6 +Policies/3025,4.671488888575841e-5,4.667444358935709e-5,4.677419645257871e-5,1.5971076504489207e-7,1.1997372050976833e-7,2.1481247338974752e-7 +Policies/15516,2.2788304536501184e-4,2.2717879921174312e-4,2.2899987120827094e-4,2.995324705221257e-6,2.2070359161596315e-6,4.061491801419709e-6 +Policies/7555,1.1608559886262634e-4,1.1595739557017717e-4,1.1622910836868635e-4,4.5669727024386307e-7,3.775298108576534e-7,6.073278016333574e-7 +Policies/3320,5.266221230131826e-5,5.248081865074514e-5,5.286548684182852e-5,6.271661163875053e-7,5.384395377439601e-7,7.519510477549883e-7 +Policies/5127,7.778040245113222e-5,7.751972746318042e-5,7.804959360707097e-5,8.806480084460984e-7,8.01520563672763e-7,9.852040841086238e-7 +Policies/14379,2.1683163498701594e-4,2.16312794232003e-4,2.1752349874193394e-4,2.0579635257256364e-6,1.6958694997150296e-6,2.6068229511041085e-6 +Policies/14547,2.1619865655128886e-4,2.1522914288801546e-4,2.1698365649666136e-4,2.970077361821075e-6,2.3163341459227084e-6,3.7474335963599617e-6 +Policies/1335,2.109125690761253e-5,2.10255422332116e-5,2.113316280523657e-5,1.700770927868924e-7,1.1226792592034611e-7,2.3628530168019454e-7 +Policies/702,1.1289532249771797e-5,1.1264679219467246e-5,1.1324772478680986e-5,1.0201778483005881e-7,7.7299726397786e-8,1.3571425740621686e-7 +Policies/34558,4.775595610648504e-4,4.766450655794333e-4,4.787104914690451e-4,3.391760679181432e-6,2.600304134035987e-6,4.489302283742534e-6 +Policies/25916,3.738532466196209e-4,3.7303382149813497e-4,3.7483570756090685e-4,3.2368677267836197e-6,2.677245680013501e-6,4.185326270455116e-6 +Policies/11675,1.6971559917725043e-4,1.6922409524808494e-4,1.7035735674777343e-4,1.8835851831282912e-6,1.5559717984904454e-6,2.238452215865655e-6 +Policies/878,1.3707996458756375e-5,1.3680453505761118e-5,1.3745464687797095e-5,1.0159859582177393e-7,7.04547141439249e-8,1.6196627853153915e-7 +Policies/1318,2.0839914317311964e-5,2.0724535695422415e-5,2.0989002962709608e-5,4.443306501593533e-7,3.280538929689753e-7,5.560672069733588e-7 +Policies/29829,4.3158104586301743e-4,4.301277749422949e-4,4.333025520355236e-4,5.369780359629833e-6,4.686852098736846e-6,6.534780608416621e-6 +Policies/20218,2.902798558186343e-4,2.8891412549881396e-4,2.9178538103643556e-4,4.824102106702638e-6,4.39143846596575e-6,5.386895708722551e-6 +Policies/5008,7.711984270555451e-5,7.694492936662265e-5,7.740215997155673e-5,7.202482633665469e-7,4.478238325807528e-7,1.2259780095202702e-6 +Policies/10969,1.6430285356997242e-4,1.6369232634626322e-4,1.6485451359746586e-4,1.9837600874540682e-6,1.6311909595613036e-6,2.4195172858556432e-6 +Policies/24232,3.443201484385501e-4,3.433574586509297e-4,3.4532160970461264e-4,3.3419397921811173e-6,2.862564324300231e-6,3.7623833832574452e-6 +Policies/32036,4.5056096286792734e-4,4.4969329405952145e-4,4.5205882868121764e-4,3.6394249763357023e-6,2.461090225826036e-6,5.922144404402781e-6 +Policies/37381,5.338012228205993e-4,5.301696314258291e-4,5.373259054128509e-4,1.1797006500592447e-5,1.0491355471746678e-5,1.3486550190810237e-5 +Policies/20218,2.9396171806328155e-4,2.929056947060712e-4,2.949688372326039e-4,3.6346358477279566e-6,2.944870991073485e-6,4.609669441358329e-6 +Policies/24994,3.5343579456726727e-4,3.5304663563781835e-4,3.5397194449137586e-4,1.578906018797827e-6,1.2047734420777474e-6,2.154710871639216e-6 +Policies/13588,1.9590487077050995e-4,1.9557990679820047e-4,1.9669607120294594e-4,1.5665500074899476e-6,8.018370137006353e-7,2.921813792039714e-6 +Policies/22017,3.2210560151177175e-4,3.208112606714244e-4,3.2315631044910675e-4,4.00246035142115e-6,3.142336032793093e-6,4.850881665540998e-6 +Policies/33492,4.682726421673919e-4,4.663412412433551e-4,4.706071534401548e-4,6.952503801354028e-6,5.556087705844966e-6,8.019538303671656e-6 +Policies/9827,1.4253547315841864e-4,1.422403305109509e-4,1.4287100185921128e-4,1.093327411639789e-6,9.016627674943157e-7,1.3550200174281405e-6 +Policies/18309,2.713024125866962e-4,2.7008684367017745e-4,2.724286778259254e-4,3.983568539493249e-6,3.503297277689087e-6,4.471810986092001e-6 +Policies/6731,1.0316757437637888e-4,1.0306523115972629e-4,1.0328771941647367e-4,3.6794850978149864e-7,2.948153549507961e-7,4.5460260150091985e-7 +Policies/33376,4.6918970569470705e-4,4.678418675458963e-4,4.707577065350775e-4,4.6709666432735765e-6,3.361142501829036e-6,5.8939124070903295e-6 +Policies/27253,3.9125062963124064e-4,3.8969339494434745e-4,3.929077465874276e-4,5.570970077881762e-6,5.273493974042264e-6,6.082097522027978e-6 +Policies/22996,3.262111011831281e-4,3.2598696128937927e-4,3.2662121348562705e-4,9.69095037324153e-7,6.102278872466315e-7,1.6349359677306114e-6 +Policies/1729,2.7283868262548596e-5,2.7230522211249746e-5,2.7343123036442473e-5,1.9335821537972962e-7,1.5459727412021315e-7,2.4170946368746213e-7 +Policies/16223,2.389706460747714e-4,2.3850182327798069e-4,2.395175395730136e-4,1.6638626488648953e-6,1.473228953467051e-6,1.874033462837362e-6 +Policies/24460,3.5279196348291897e-4,3.5145497634936335e-4,3.542283814487531e-4,4.724689945168977e-6,4.285101386149618e-6,5.164843177360141e-6 +Policies/38514,5.401474197890282e-4,5.385104986372556e-4,5.420124845051076e-4,5.979320463477195e-6,4.562497028055993e-6,8.234710575644372e-6 +Policies/19441,2.7966187185046547e-4,2.7943880543538935e-4,2.799082886541207e-4,8.334196964670294e-7,6.712982972255678e-7,1.069301267458982e-6 +Policies/17023,2.4805892803241676e-4,2.474635568875345e-4,2.4893598215214107e-4,2.4244175174308784e-6,1.8757290712874809e-6,2.923719836112785e-6 +Policies/16481,2.3647902597667795e-4,2.3615152270186905e-4,2.3685536224391274e-4,1.17423706949995e-6,1.0008003991442826e-6,1.482379436723364e-6 +Policies/33380,4.6560385846154966e-4,4.6423234439630295e-4,4.6767268683153525e-4,5.575254253730879e-6,4.140646170748946e-6,7.015453275562679e-6 +Policies/39112,5.381439568977499e-4,5.37586680331792e-4,5.386870989577525e-4,1.857619703752122e-6,1.5270171350549078e-6,2.298330438411037e-6 +Policies/31622,4.441320433927214e-4,4.4249670446683547e-4,4.4646971892668924e-4,6.634219612845224e-6,4.610233789654513e-6,9.28992609829243e-6 +Policies/25929,3.687281620166917e-4,3.6842198300595416e-4,3.690807868502561e-4,1.101215491697312e-6,8.568479077831633e-7,1.4999352129785798e-6 +Policies/11182,1.6808268194644144e-4,1.6786732574492285e-4,1.6848159531485202e-4,9.714836288422983e-7,6.603470965620472e-7,1.4215936171431127e-6 +Policies/11198,1.6309514314355014e-4,1.6286079636802474e-4,1.6347481307701366e-4,9.847708463546417e-7,6.40432162906837e-7,1.54820243612342e-6 +Policies/19572,2.84145117463687e-4,2.830046049134821e-4,2.8520084467853295e-4,3.6002752431616183e-6,3.3203374189804887e-6,3.895318641474864e-6 +Policies/35378,4.924341648328958e-4,4.917044894900241e-4,4.931085901916918e-4,2.3859265949530446e-6,1.8953788980476032e-6,3.015131004220731e-6 +Policies/10222,1.5322887302074884e-4,1.5259610396421044e-4,1.5379968974816492e-4,2.0363786317326087e-6,1.784427162523545e-6,2.4820631124537576e-6 +Policies/36275,5.023295337076376e-4,5.011579772787786e-4,5.040909076924859e-4,4.4523747742247146e-6,3.1578306857895134e-6,6.061199608741227e-6 +Policies/10102,1.4725477229318056e-4,1.4715980995155787e-4,1.4736908675225474e-4,3.463141355409694e-7,2.7444237913108165e-7,4.737603344487607e-7 +Policies/5474,8.387917680223125e-5,8.3457345995777e-5,8.41588614264513e-5,1.1377491921606543e-6,8.764137869047576e-7,1.478847416546899e-6 +Policies/10811,1.592640301710783e-4,1.5868556238450498e-4,1.6000082622316463e-4,2.2141084519801446e-6,1.6875894297221697e-6,2.8236126956069825e-6 +Policies/32026,4.609249207350331e-4,4.585947554000628e-4,4.6291636326972985e-4,6.867654845316367e-6,5.023912921646395e-6,9.246185588000589e-6 +Policies/9879,1.458847645769842e-4,1.4552599431091878e-4,1.4640698558696701e-4,1.4810537315325102e-6,1.171308879668304e-6,1.8528581895926608e-6 +Policies/1473,2.309398712147864e-5,2.300775740154692e-5,2.3158382593568606e-5,2.5045677188178255e-7,1.8435269193534121e-7,3.416513722113496e-7 +Policies/24866,3.658579172188184e-4,3.6437642963168957e-4,3.673271783630834e-4,4.845607613676181e-6,4.380569379290976e-6,5.349113634491042e-6 +Policies/27436,3.966386518770602e-4,3.94698116163164e-4,3.98100705500339e-4,5.417284147645655e-6,4.325829186331842e-6,6.425605520118951e-6 +Policies/29495,4.1540463313075694e-4,4.141195145356056e-4,4.1725083465553764e-4,5.18747986342795e-6,3.4473335227173533e-6,6.983689768763312e-6 +Policies/38963,5.423628338481931e-4,5.41539979125111e-4,5.431843139085198e-4,2.7273532674644514e-6,2.355215488706201e-6,3.2608813812964146e-6 +Policies/32515,4.525193704126624e-4,4.520773637696091e-4,4.530324879633117e-4,1.5642462127313792e-6,1.246402194622578e-6,2.01983022746109e-6 +Policies/21485,3.1168632208249754e-4,3.1064961257176797e-4,3.129399237096866e-4,3.8084549595105654e-6,3.0688532933708927e-6,4.760273370341906e-6 +Policies/11613,1.714710798539333e-4,1.7122257426972854e-4,1.717447782289905e-4,8.666125706413362e-7,6.879576183137085e-7,1.1414126620646275e-6 +Policies/33182,4.6358622668655737e-4,4.624058954549852e-4,4.647914558948804e-4,3.89538953935967e-6,2.9369771107792883e-6,4.829018466956586e-6 +Policies/12212,1.7781310836526172e-4,1.7750296190049712e-4,1.7860136986091405e-4,1.5614780032618678e-6,7.800092436507426e-7,3.1244786178198256e-6 +Policies/33252,4.741923149670491e-4,4.7215602740525834e-4,4.763209324608886e-4,7.046210193626091e-6,6.279219958513394e-6,8.25681867565309e-6 +Policies/2758,4.168727918727299e-5,4.1505072286795314e-5,4.1867794150922456e-5,6.232367711851267e-7,5.652580896248828e-7,6.972134691876067e-7 +Policies/20270,2.8837368158019715e-4,2.88065614642687e-4,2.887342360128978e-4,1.1486136469627735e-6,8.949299422091514e-7,1.4110920679913481e-6 +Policies/10380,1.530147466729351e-4,1.5257754483672984e-4,1.5367134320176112e-4,1.877250541237866e-6,1.484122674604654e-6,2.507368143686984e-6 +Policies/15739,2.2715642907494143e-4,2.2697617149917328e-4,2.2739333570501177e-4,6.871674298707241e-7,5.424447776466937e-7,9.56863510086251e-7 +Policies/20395,2.903127904254808e-4,2.895613236223963e-4,2.9142473439883274e-4,3.052098601612166e-6,2.1613227223964195e-6,5.0947748295977986e-6 +Policies/37394,5.376367593362557e-4,5.344645313923734e-4,5.410848715947426e-4,1.0998162385910478e-5,9.522904896615853e-6,1.3060017367195437e-5 +Policies/3635,5.4931673726459577e-5,5.486044960925916e-5,5.5064057244251785e-5,3.0947523022374656e-7,2.0584905564328382e-7,5.155460542285187e-7 +Policies/8624,1.2773017814992404e-4,1.2755853600758313e-4,1.2797207230455778e-4,7.004718125595645e-7,5.416498087440988e-7,9.892919082031474e-7 +Policies/26510,3.8328337908816694e-4,3.8169873486825016e-4,3.844880094866223e-4,4.951123285276782e-6,4.252663850175773e-6,5.610976635001246e-6 +Policies/17071,2.442558210646473e-4,2.4378907841472662e-4,2.448635675252482e-4,1.683458679590913e-6,1.4622145809222045e-6,1.989420002118517e-6 +Policies/2079,3.392256004192105e-5,3.379927094374491e-5,3.405469767511481e-5,4.22022777462817e-7,3.348510785263597e-7,6.012884718166228e-7 +Policies/28081,3.970882345314863e-4,3.961050244234686e-4,3.982853337033692e-4,3.815790483047592e-6,2.5627680750797958e-6,4.764497220569244e-6 +Policies/26124,3.7030788266819364e-4,3.6997399981105166e-4,3.706386856325749e-4,1.1045575398222011e-6,9.340124373674002e-7,1.4117607948976898e-6 +Policies/27323,3.8772381417946926e-4,3.8664053454736286e-4,3.891742428242611e-4,4.185254745819592e-6,3.1941820732598108e-6,5.279061444449415e-6 +Policies/5182,8.041594511238326e-5,8.006884609621973e-5,8.083379840172508e-5,1.2700727304505276e-6,1.1125351978357052e-6,1.4764850467254883e-6 +Policies/28004,3.9577525703963926e-4,3.9418389118987243e-4,3.9695719989387557e-4,4.6982559281621185e-6,3.4074932308425477e-6,5.776508355748856e-6 +Policies/4601,6.881327724268903e-5,6.868229153629646e-5,6.897565481439094e-5,4.986768868262524e-7,4.075444633324556e-7,6.38626422576307e-7 +Policies/856,1.3498107757160584e-5,1.3457202769923031e-5,1.35512033888457e-5,1.5300421872384877e-7,1.2455972492365177e-7,1.8998585648966752e-7 +Policies/13219,1.9409490678077822e-4,1.9365921780047885e-4,1.946116814089425e-4,1.5302399576737378e-6,1.3019335450762688e-6,1.8059268716597244e-6 diff --git a/plutus-core/cost-model/data/builtinCostModelA.json b/plutus-core/cost-model/data/builtinCostModelA.json index 3cf708c8960..ecfb90d2b0c 100644 --- a/plutus-core/cost-model/data/builtinCostModelA.json +++ b/plutus-core/cost-model/data/builtinCostModelA.json @@ -1338,5 +1338,21 @@ }, "type": "linear_in_y" } + }, + "policies": { + "cpu": { + "arguments": { + "intercept": 243433, + "slope": 15995 + }, + "type": "linear_in_x" + }, + "memory": { + "arguments": { + "intercept": 4, + "slope": 3 + }, + "type": "linear_in_x" + } } } diff --git a/plutus-core/cost-model/data/builtinCostModelB.json b/plutus-core/cost-model/data/builtinCostModelB.json index 6cbe5636d7e..27269db777c 100644 --- a/plutus-core/cost-model/data/builtinCostModelB.json +++ b/plutus-core/cost-model/data/builtinCostModelB.json @@ -1338,5 +1338,21 @@ }, "type": "linear_in_y" } + }, + "policies": { + "cpu": { + "arguments": { + "intercept": 243433, + "slope": 15995 + }, + "type": "linear_in_x" + }, + "memory": { + "arguments": { + "intercept": 4, + "slope": 3 + }, + "type": "linear_in_x" + } } } diff --git a/plutus-core/cost-model/data/builtinCostModelC.json b/plutus-core/cost-model/data/builtinCostModelC.json index 24071b72982..8e7b20c69c9 100644 --- a/plutus-core/cost-model/data/builtinCostModelC.json +++ b/plutus-core/cost-model/data/builtinCostModelC.json @@ -1356,5 +1356,21 @@ }, "type": "linear_in_y" } + }, + "policies": { + "cpu": { + "arguments": { + "intercept": 243433, + "slope": 15995 + }, + "type": "linear_in_x" + }, + "memory": { + "arguments": { + "intercept": 4, + "slope": 3 + }, + "type": "linear_in_x" + } } } diff --git a/plutus-core/cost-model/data/builtinCostModelD.json b/plutus-core/cost-model/data/builtinCostModelD.json index d3b6f2e45d1..a99ce397847 100644 --- a/plutus-core/cost-model/data/builtinCostModelD.json +++ b/plutus-core/cost-model/data/builtinCostModelD.json @@ -1338,5 +1338,21 @@ }, "type": "linear_in_y" } + }, + "policies": { + "cpu": { + "arguments": { + "intercept": 243433, + "slope": 15995 + }, + "type": "linear_in_x" + }, + "memory": { + "arguments": { + "intercept": 4, + "slope": 3 + }, + "type": "linear_in_x" + } } } diff --git a/plutus-core/cost-model/data/builtinCostModelE.json b/plutus-core/cost-model/data/builtinCostModelE.json index e225e1f580e..6686f5e07e1 100644 --- a/plutus-core/cost-model/data/builtinCostModelE.json +++ b/plutus-core/cost-model/data/builtinCostModelE.json @@ -1356,5 +1356,21 @@ }, "type": "linear_in_y" } + }, + "policies": { + "cpu": { + "arguments": { + "intercept": 243433, + "slope": 15995 + }, + "type": "linear_in_x" + }, + "memory": { + "arguments": { + "intercept": 4, + "slope": 3 + }, + "type": "linear_in_x" + } } } diff --git a/plutus-core/cost-model/data/models.R b/plutus-core/cost-model/data/models.R index 49269619b2e..e15aefa9750 100644 --- a/plutus-core/cost-model/data/models.R +++ b/plutus-core/cost-model/data/models.R @@ -160,6 +160,7 @@ arity <- function(name) { "UnValueData" = 1, "ScaleValue" = 2, "MultiIndexArray" = 2, + "Policies" = 1, -1 ## Default for missing values ) } @@ -850,6 +851,40 @@ modelFun <- function(path) { mk.result (m, "quadratic_in_y") } + ## `policies` copies the outer map's keys into a list, so the cost is linear in the + ## number of policies. The size measure is the total number of (policy, token) pairs, + ## which equals the number of policies only when each policy holds a single token; the + ## benchmark generates that shape, so the slope below is the per-policy cost. Values + ## carrying more tokens per policy have a larger size for the same work, so they are + ## over-charged rather than under-charged. + ## + ## Least squares is a poor fit here, for the opposite reason to multiIndexArray above. + ## The measured cost per policy *falls* across the range (15.2ns per policy below 5000 + ## policies, 14.1ns above 30000), and least squares answers that by trading slope for + ## intercept: it returns an intercept of 7.16us, thirty times the measured cost of an + ## empty value, which then dominates the charge for anything under about 500 policies. + ## Values on chain hold a handful. + ## + ## Charge at the largest per-policy rate measured, with the intercept taken as the + ## largest amount by which any observation exceeds that rate. Because no observation + ## has a rate above the slope, that intercept is just the measured cost of the empty + ## value, and the line sits above every measurement. It over-charges the largest + ## benchmarked values by 16% and prices realistic ones around twenty times cheaper + ## than the least-squares line. + policiesModel <- { + fname <- "Policies" + filtered <- data %>% + filter.and.check.nonempty (fname) %>% + discard.overhead () + nonzero <- filtered[filtered$x_mem > 0, ] + slope <- max (nonzero$t / nonzero$x_mem) + icept <- max (filtered$t - slope * filtered$x_mem) + m <- lm (t ~ x_mem, filtered) + m$coefficients[["(Intercept)"]] <- icept + m$coefficients[["x_mem"]] <- slope + mk.result (m, "linear_in_x") + } + ## Values # Z wrapped with `Logarithmic . ValueOuterOrMaxInner` @@ -1006,7 +1041,8 @@ modelFun <- function(path) { insertCoinModel = insertCoinModel, unionValueModel = unionValueModel, scaleValueModel = scaleValueModel, - multiIndexArrayModel = multiIndexArrayModel + multiIndexArrayModel = multiIndexArrayModel, + policiesModel = policiesModel ) ## The integer division functions have a complex costing behaviour that requires some negative diff --git a/plutus-core/cost-model/test/TestCostModels.hs b/plutus-core/cost-model/test/TestCostModels.hs index 917c0e2d0fc..9f1710441ec 100644 --- a/plutus-core/cost-model/test/TestCostModels.hs +++ b/plutus-core/cost-model/test/TestCostModels.hs @@ -558,4 +558,6 @@ main = $(genTest 2 "scaleValue") Everywhere , -- Arrays (batch 7) $(genTest 2 "multiIndexArray") Everywhere + , -- Values (batch 7) + $(genTest 1 "policies") ] diff --git a/plutus-core/plutus-core/src/PlutusCore/Default/Builtins.hs b/plutus-core/plutus-core/src/PlutusCore/Default/Builtins.hs index 83b764a9044..735d3ee4968 100644 --- a/plutus-core/plutus-core/src/PlutusCore/Default/Builtins.hs +++ b/plutus-core/plutus-core/src/PlutusCore/Default/Builtins.hs @@ -2499,7 +2499,7 @@ instance uni ~ DefaultUni => ToBuiltinMeaning uni DefaultFun where {-# INLINE policiesDenotation #-} in makeBuiltinMeaning policiesDenotation - (runCostingFunOneArgument . unimplementedCostingFun) + (runCostingFunOneArgument . paramPolicies) toBuiltinMeaning _semvar AssetCount = let assetCountDenotation :: Value -> Integer assetCountDenotation = toInteger . Value.totalSize diff --git a/plutus-core/plutus-core/src/PlutusCore/Evaluation/Machine/BuiltinCostModel.hs b/plutus-core/plutus-core/src/PlutusCore/Evaluation/Machine/BuiltinCostModel.hs index fc57352fd58..0c62c41ef6c 100644 --- a/plutus-core/plutus-core/src/PlutusCore/Evaluation/Machine/BuiltinCostModel.hs +++ b/plutus-core/plutus-core/src/PlutusCore/Evaluation/Machine/BuiltinCostModel.hs @@ -199,6 +199,7 @@ data BuiltinCostModelBase f , paramScaleValue :: f ModelTwoArguments , -- Batch 7 paramMultiIndexArray :: f ModelTwoArguments + , paramPolicies :: f ModelOneArgument } deriving stock (Generic) deriving anyclass (FunctorB, TraversableB, ConstraintsB) diff --git a/plutus-core/plutus-core/src/PlutusCore/Evaluation/Machine/ExBudgetingDefaults.hs b/plutus-core/plutus-core/src/PlutusCore/Evaluation/Machine/ExBudgetingDefaults.hs index dc08e6c3c8e..8ca2dec58a0 100644 --- a/plutus-core/plutus-core/src/PlutusCore/Evaluation/Machine/ExBudgetingDefaults.hs +++ b/plutus-core/plutus-core/src/PlutusCore/Evaluation/Machine/ExBudgetingDefaults.hs @@ -429,6 +429,7 @@ unitCostBuiltinCostModel = , paramScaleValue = unitCostTwoArguments , -- Batch 7 paramMultiIndexArray = unitCostTwoArguments + , paramPolicies = unitCostOneArgument } unitCekParameters diff --git a/plutus-ledger-api/src/PlutusLedgerApi/V1/ParamName.hs b/plutus-ledger-api/src/PlutusLedgerApi/V1/ParamName.hs index f47c26fb943..bf822368cf2 100644 --- a/plutus-ledger-api/src/PlutusLedgerApi/V1/ParamName.hs +++ b/plutus-ledger-api/src/PlutusLedgerApi/V1/ParamName.hs @@ -355,5 +355,9 @@ data ParamName | MultiIndexArray'cpu'arguments'c2 | MultiIndexArray'memory'arguments'intercept | MultiIndexArray'memory'arguments'slope + | Policies'cpu'arguments'intercept + | Policies'cpu'arguments'slope + | Policies'memory'arguments'intercept + | Policies'memory'arguments'slope deriving stock (Eq, Ord, Enum, Ix, Bounded, Generic) deriving (IsParamName) via (GenericParamName ParamName) diff --git a/plutus-ledger-api/src/PlutusLedgerApi/V2/ParamName.hs b/plutus-ledger-api/src/PlutusLedgerApi/V2/ParamName.hs index 0340acbb802..234d1bf3408 100644 --- a/plutus-ledger-api/src/PlutusLedgerApi/V2/ParamName.hs +++ b/plutus-ledger-api/src/PlutusLedgerApi/V2/ParamName.hs @@ -357,5 +357,9 @@ data ParamName | MultiIndexArray'cpu'arguments'c2 | MultiIndexArray'memory'arguments'intercept | MultiIndexArray'memory'arguments'slope + | Policies'cpu'arguments'intercept + | Policies'cpu'arguments'slope + | Policies'memory'arguments'intercept + | Policies'memory'arguments'slope deriving stock (Eq, Ord, Enum, Ix, Bounded, Generic) deriving (IsParamName) via (GenericParamName ParamName) diff --git a/plutus-ledger-api/src/PlutusLedgerApi/V3/ParamName.hs b/plutus-ledger-api/src/PlutusLedgerApi/V3/ParamName.hs index 5c16e227b78..bac4ef57c7c 100644 --- a/plutus-ledger-api/src/PlutusLedgerApi/V3/ParamName.hs +++ b/plutus-ledger-api/src/PlutusLedgerApi/V3/ParamName.hs @@ -373,5 +373,9 @@ data ParamName | MultiIndexArray'cpu'arguments'c2 | MultiIndexArray'memory'arguments'intercept | MultiIndexArray'memory'arguments'slope + | Policies'cpu'arguments'intercept + | Policies'cpu'arguments'slope + | Policies'memory'arguments'intercept + | Policies'memory'arguments'slope deriving stock (Eq, Ord, Enum, Ix, Bounded, Generic) deriving (IsParamName) via (GenericParamName ParamName) diff --git a/plutus-ledger-api/src/PlutusLedgerApi/V4/ParamName.hs b/plutus-ledger-api/src/PlutusLedgerApi/V4/ParamName.hs index f7c3565f9c2..1389d1c2013 100644 --- a/plutus-ledger-api/src/PlutusLedgerApi/V4/ParamName.hs +++ b/plutus-ledger-api/src/PlutusLedgerApi/V4/ParamName.hs @@ -368,5 +368,9 @@ data ParamName | MultiIndexArray'cpu'arguments'c2 | MultiIndexArray'memory'arguments'intercept | MultiIndexArray'memory'arguments'slope + | Policies'cpu'arguments'intercept + | Policies'cpu'arguments'slope + | Policies'memory'arguments'intercept + | Policies'memory'arguments'slope deriving stock (Eq, Ord, Enum, Ix, Bounded, Generic) deriving (IsParamName) via (GenericParamName ParamName) diff --git a/plutus-ledger-api/test/Spec/CostModelParams.hs b/plutus-ledger-api/test/Spec/CostModelParams.hs index 0383ea64207..ec707cfacaf 100644 --- a/plutus-ledger-api/test/Spec/CostModelParams.hs +++ b/plutus-ledger-api/test/Spec/CostModelParams.hs @@ -41,10 +41,10 @@ tests = "CostModelParams" "costModelParams" [ embed $ testCase "length" do - 337 @=? length v1_ParamNames - 337 @=? length v2_ParamNames - 355 @=? length v3_ParamNames - 355 @=? length v4_ParamNames + 341 @=? length v1_ParamNames + 341 @=? length v2_ParamNames + 359 @=? length v3_ParamNames + 359 @=? length v4_ParamNames , embed $ testCase "tripping paramname" do for_ v1_ParamNames \p -> assertBool "tripping v1 cm params failed" $ diff --git a/plutus-ledger-api/test/Spec/Data/CostModelParams.hs b/plutus-ledger-api/test/Spec/Data/CostModelParams.hs index abadbbbbb05..c913203f08c 100644 --- a/plutus-ledger-api/test/Spec/Data/CostModelParams.hs +++ b/plutus-ledger-api/test/Spec/Data/CostModelParams.hs @@ -41,10 +41,10 @@ tests = "CostModelParams" "costModelParams" [ embed $ testCase "length" do - 337 @=? length v1_ParamNames - 337 @=? length v2_ParamNames - 355 @=? length v3_ParamNames - 355 @=? length v4_ParamNames + 341 @=? length v1_ParamNames + 341 @=? length v2_ParamNames + 359 @=? length v3_ParamNames + 359 @=? length v4_ParamNames , embed $ testCase "tripping paramname" do for_ v1_ParamNames \p -> assertBool "tripping v1 cm params failed" $