Skip to content

Commit ee8db65

Browse files
authored
dgb: rewire heartbeat binomial-conf diag onto coin/ SSOT (#425 follow-on) (#507)
node.cpp format_binomial_conf{,_efficiency} carried an inline z=1.96 + plain-[0,1]-clip Wilson-score approximation that duplicated, and slightly diverged from, the oracle-faithful coin/binomial_conf_interval.hpp SSOT (z = sqrt(2)*ierf(conf), add_to_range bracketing; p2pool util/math.py:133). Delegate both diag formatters onto the SSOT. Diagnostics only (heartbeat log stale-rate/efficiency display) -- zero consensus surface, no block reward path. Underlying math is now oracle-faithful; rendered output is empirically byte-identical across 13 representative (x,n) cases (the sub-integer-percent z/bracket delta washes out under floor/ceil-to-percent rendering). NOT strictly double-level byte-identical -- see PR note. Co-authored-by: frstrtr <frstrtr@users.noreply.github.com>
1 parent a3599bb commit ee8db65

1 file changed

Lines changed: 22 additions & 20 deletions

File tree

src/impl/dgb/node.cpp

Lines changed: 22 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#include <impl/dgb/download_stops.hpp>
1010
#include <impl/dgb/pool_efficiency.hpp>
1111
#include <impl/dgb/expected_time_to_block.hpp>
12+
#include <impl/dgb/coin/binomial_conf_interval.hpp>
1213

1314
#include <algorithm>
1415
#include <filesystem>
@@ -71,34 +72,35 @@ static std::string format_duration(double secs) {
7172
// Returns "~X.Y% (lo-hi%)" string for binomial proportion x/n at 95% confidence.
7273
static std::string format_binomial_conf(int x, int n, double conf = 0.95) {
7374
if (n == 0) return "???";
74-
// z for 95% ≈ 1.96 (inverse error function approximation)
75-
double z = 1.96;
76-
double p = static_cast<double>(x) / n;
77-
double topa = p + z * z / (2.0 * n);
78-
double topb = z * std::sqrt(p * (1.0 - p) / n + z * z / (4.0 * n * n));
79-
double bottom = 1.0 + z * z / n;
80-
double lo = std::max(0.0, (topa - topb) / bottom);
81-
double hi = std::min(1.0, (topa + topb) / bottom);
75+
// Oracle-faithful Wilson score interval via the dgb::coin SSOT
76+
// (coin/binomial_conf_interval.hpp; p2pool util/math.py:133). This delegates
77+
// the prior inline z=1.96 + plain-[0,1]-clip approximation onto the SSOT,
78+
// which uses z = sqrt(2)*ierf(conf) and add_to_range bracketing. Output is
79+
// oracle-faithful and NOT byte-identical to the old literal-z form; diag
80+
// display only (heartbeat log), zero consensus surface.
81+
const std::array<double, 2> ci = dgb::coin::binomial_conf_interval(
82+
static_cast<double>(x), static_cast<double>(n), conf);
83+
const double p = static_cast<double>(x) / n;
8284
std::ostringstream os;
8385
os << "~" << std::fixed << std::setprecision(1) << (100.0 * p) << "% ("
84-
<< static_cast<int>(std::floor(100.0 * lo)) << "-"
85-
<< static_cast<int>(std::ceil(100.0 * hi)) << "%)";
86+
<< static_cast<int>(std::floor(100.0 * ci[0])) << "-"
87+
<< static_cast<int>(std::ceil(100.0 * ci[1])) << "%)";
8688
return os.str();
8789
}
8890

8991
// Wilson score confidence interval for efficiency: 1 - stale_rate, scaled
9092
static std::string format_binomial_conf_efficiency(int stale, int n, double stale_prop) {
9193
if (n == 0) return "???";
92-
double z = 1.96;
93-
double p = static_cast<double>(stale) / n;
94-
double topa = p + z * z / (2.0 * n);
95-
double topb = z * std::sqrt(p * (1.0 - p) / n + z * z / (4.0 * n * n));
96-
double bottom = 1.0 + z * z / n;
97-
double lo_stale = std::max(0.0, (topa - topb) / bottom);
98-
double hi_stale = std::min(1.0, (topa + topb) / bottom);
99-
// Efficiency = (1 - stale_rate) / (1 - stale_prop)
100-
double denom = (stale_prop < 0.999) ? (1.0 - stale_prop) : 1.0;
101-
double eff = (1.0 - p) / denom;
94+
// Stale-rate CI via the oracle-faithful SSOT, then mapped to efficiency.
95+
// See format_binomial_conf note: oracle-faithful, NOT byte-identical to the
96+
// prior inline z=1.96 form; diag display only.
97+
const std::array<double, 2> ci = dgb::coin::binomial_conf_interval(
98+
static_cast<double>(stale), static_cast<double>(n), 0.95);
99+
const double p = static_cast<double>(stale) / n;
100+
const double lo_stale = ci[0];
101+
const double hi_stale = ci[1];
102+
const double denom = (stale_prop < 0.999) ? (1.0 - stale_prop) : 1.0;
103+
const double eff = (1.0 - p) / denom;
102104
double eff_lo = (1.0 - hi_stale) / denom;
103105
double eff_hi = (1.0 - lo_stale) / denom;
104106
eff_lo = std::max(0.0, eff_lo);

0 commit comments

Comments
 (0)