mirror of
https://github.com/logos-blockchain/research.git
synced 2026-08-07 03:33:33 +00:00
pd: fix a Poisson underflow that broke the quota ceiling at higher cover rates
Found by the cover-traffic sweep: the 99%-safe stake ceiling FELL as the cover rate rose, while the mean bind rose to 0.38 -- backwards. quota_exceedance_prob summed the Poisson CDF by hand starting from exp(-lam). That underflows to zero past lam ~ 745, so the CDF collapsed to 0 and the function reported every node as exceeding its quota, which drove the bisection in max_alpha_for_confidence to a meaningless answer. The default rate is unaffected (lam ~ 32), but raising the cover rate reaches the broken regime immediately, because the quota and the tolerable block count grow in proportion. Replaced with scipy poisson.sf. Exceedance at the mean bind is now ~0.5 at every rate, as it must be, and the safe/mean ratio rises 0.65 -> 0.81 -> 0.90 -> 0.95 -> 0.98 across the swept rates: Poisson noise shrinks relative to a growing quota, so less headroom is needed for the same confidence. Two regression tests pin both. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
1865b4110d
commit
8a3a43b366
@ -34,6 +34,7 @@ from __future__ import annotations
|
||||
import math
|
||||
|
||||
import numpy as np
|
||||
from scipy.stats import poisson
|
||||
|
||||
|
||||
def assign_stake(n_nodes: int, dist: str, rng: np.random.Generator,
|
||||
@ -179,19 +180,17 @@ def quota_exceedance_prob(alpha: float, f: float, n_nodes: int, slots_per_epoch:
|
||||
|
||||
Wins are Binomial(slots_per_epoch, phi(alpha)); the Poisson limit is used, which is accurate
|
||||
here because phi is tiny and the epoch is long.
|
||||
|
||||
Uses scipy's survival function rather than summing the series by hand: ``exp(-lam)`` underflows
|
||||
to zero past ``lam ~ 745``, which silently collapses a hand-rolled CDF to 0 and reports every
|
||||
node as exceeding. That regime is reached as soon as the cover rate is raised (the quota, and
|
||||
with it the tolerable block count, grows in proportion).
|
||||
"""
|
||||
lam = expected_blocks_per_epoch(alpha, f, slots_per_epoch)
|
||||
quota = quota_per_epoch(n_nodes, slots_per_epoch, cover_rate_mult)
|
||||
k = math.floor(quota)
|
||||
# P(X > k) for X ~ Poisson(lam), summed up from 0 (k is small in every regime of interest)
|
||||
if lam <= 0.0:
|
||||
return 0.0
|
||||
term = math.exp(-lam)
|
||||
cdf = term
|
||||
for i in range(1, k + 1):
|
||||
term *= lam / i
|
||||
cdf += term
|
||||
return max(0.0, min(1.0, 1.0 - cdf))
|
||||
return float(poisson.sf(math.floor(quota), lam))
|
||||
|
||||
|
||||
def max_alpha_for_confidence(f: float, n_nodes: int, slots_per_epoch: int,
|
||||
|
||||
@ -157,3 +157,22 @@ def test_more_cover_traffic_raises_the_ceiling():
|
||||
rich = simulate_epoch_emissions(s, F, n, S, np.random.default_rng(10), cover_rate_mult=32.0)
|
||||
assert rich["compliant_frac"] > lean["compliant_frac"]
|
||||
assert rich["max_compliant_stake"] > lean["max_compliant_stake"]
|
||||
|
||||
|
||||
def test_exceedance_survives_a_large_quota():
|
||||
"""Regression: exp(-lam) underflows past lam ~ 745, which silently collapsed a hand-rolled
|
||||
Poisson CDF to 0 and reported every node as exceeding. Raising the cover rate reaches that
|
||||
regime immediately, so the mean bind must still be a coin flip at every rate."""
|
||||
n, S = 20_000, 648_000
|
||||
for rate in (1.0, 16.0, 64.0, 256.0):
|
||||
p = quota_exceedance_prob(alpha_max(n, F, rate), F, n, S, rate)
|
||||
assert 0.4 < p < 0.6, (rate, p)
|
||||
|
||||
|
||||
def test_the_safe_ceiling_approaches_the_mean_bind_as_the_quota_grows():
|
||||
"""Poisson noise shrinks relative to the mean, so the headroom needed for confidence shrinks."""
|
||||
n, S = 20_000, 648_000
|
||||
ratios = [max_alpha_for_confidence(F, n, S, 0.99, r) / alpha_max(n, F, r)
|
||||
for r in (1.0, 16.0, 256.0)]
|
||||
assert all(b > a for a, b in zip(ratios, ratios[1:], strict=False))
|
||||
assert ratios[-1] > 0.9
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user