SpreadBounds

SpreadBounds(x,misrate)=[d(kL),d(kU)]\operatorname{SpreadBounds}(\mathbf{x}, \mathrm{misrate}) = [d_{(k_L)}, d_{(k_U)}]

where m=n2m = \lfloor \frac{n}{2} \rfloor, d\mathbf{d} is the sorted absolute differences from a random disjoint pairing, kL=r+1k_L = r + 1, kU=mrk_U = m - r, and rr is the randomized sign-test cutoff for Binomial(m,12)\text{Binomial}(m, \frac{1}{2}).

Robust bounds on Spread(x)\operatorname{Spread}(\mathbf{x}) with specified coverage.

  • Interpretation misrate\mathrm{misrate} is probability that true spread falls outside bounds
  • Domain any real numbers, n2n \geq 2, misrate21m\mathrm{misrate} \geq 2^{1-m}
  • Assumptions sparity(x)
  • Unit same as measurements
  • Note disjoint-pair sign-test inversion; randomized cutoff matches requested misrate exactly under weak continuity; conservative with ties

Properties

  • Shift invariance SpreadBounds(x+c,misrate)=SpreadBounds(x,misrate)\operatorname{SpreadBounds}(\mathbf{x} + c, \mathrm{misrate}) = \operatorname{SpreadBounds}(\mathbf{x}, \mathrm{misrate})
  • Scale equivariance SpreadBounds(cx,misrate)=cSpreadBounds(x,misrate)\operatorname{SpreadBounds}(c \cdot \mathbf{x}, \mathrm{misrate}) = \lvert c \rvert \cdot \operatorname{SpreadBounds}(\mathbf{x}, \mathrm{misrate})
  • Non-negativity SpreadBounds(x,misrate)=[a,b]\operatorname{SpreadBounds}(\mathbf{x}, \mathrm{misrate}) = [a, b] where a0,b0a \geq 0, b \geq 0
  • Monotonicity in misrate smaller misrate\mathrm{misrate} produces wider bounds

Example

  • SpreadBounds([1..30], 0.01) where Spread = 9
  • Bounds fail to cover true spread with probability misrate\approx \mathrm{misrate}

SpreadBounds\operatorname{SpreadBounds} provides distribution-free bounds on the Spread\operatorname{Spread} estimate. It uses disjoint pairs and an exact sign-test inversion, which guarantees coverage regardless of the underlying distribution. Set misrate\mathrm{misrate} to control how often the bounds might fail to contain the true spread: use 10310^{-3} for everyday analysis or 10610^{-6} for critical decisions. The cutoff rr is clamped so that r2m12\lfloor \frac{r}{2} \rfloor \leq \frac{m - 1}{2}, ensuring the lower and upper order statistics remain within the sorted differences.

Minimum sample size the sign test on m=n2m = \lfloor \frac{n}{2} \rfloor pairs has minimum achievable misrate 21m2^{1-m}:

misrate\mathrm{misrate}10110^{-1}10210^{-2}10310^{-3}10610^{-6}
nminn_{min}10162242

Algorithm

The SpreadBounds\operatorname{SpreadBounds} estimator constructs distribution-free bounds on Spread(x)\operatorname{Spread}(\mathbf{x}) by inverting a sign test on disjoint pairs.

Given a sample x=(x1,,xn)\mathbf{x} = (x_1, \ldots, x_n), the algorithm proceeds as follows:

  • Random disjoint pairing Randomly pair the nn observations into m=n2m = \lfloor \frac{n}{2} \rfloor disjoint pairs. If nn is odd, one observation is discarded. The randomization ensures that the pairing does not depend on the data ordering.

  • Absolute differences For each pair (xai,xbi)(x_{a_i}, x_{b_i}), compute the absolute difference di=xaixbid_i = \lvert x_{a_i} - x_{b_i} \rvert. Under the sparity assumption, these mm absolute differences are exchangeable.

  • Sort Sort the differences to obtain d(1)d(2)d(m)d_{(1)} \leq d_{(2)} \leq \ldots \leq d_{(m)}.

  • SignMargin cutoff Compute r=SignMargin(m,misrate)r = \operatorname{SignMargin}(m, \mathrm{misrate}) (see SignMargin). This determines how many extreme order statistics to exclude from each tail.

  • Order statistic selection Return [d(kL),d(kU)][d_{(k_L)}, d_{(k_U)}] where kL=r2+1k_L = \lfloor \frac{r}{2} \rfloor + 1 and kU=mr2k_U = m - \lfloor \frac{r}{2} \rfloor. Clamping ensures the indices remain within [1,m][1, m].

The key insight is that disjoint pairs provide independence under the symmetry assumption. Under weak symmetry around the true spread, each absolute difference is equally likely to exceed or fall below the population spread. This makes the count of differences exceeding the spread a Binomial(m,12)\text{Binomial}(m, \frac{1}{2}) variable, enabling exact coverage control via the sign test.

The randomized cutoff from SignMargin\operatorname{SignMargin} matches the requested misrate exactly under weak continuity. With tied values, the bounds become conservative (actual coverage exceeds 1misrate1 - \mathrm{misrate}).

using Pragmastat.Functions;
using Pragmastat.Exceptions;
using Pragmastat.Internal;
using Pragmastat.Randomization;

namespace Pragmastat.Estimators;

/// <summary>
/// Distribution-free bounds for Spread using disjoint pairs with sign-test inversion.
/// Randomizes the cutoff between adjacent ranks to match the requested misrate.
/// Requires misrate >= 2^(1 - floor(n/2)).
/// </summary>
public class SpreadBoundsEstimator : IOneSampleBoundsEstimator
{
  public static readonly SpreadBoundsEstimator Instance = new();

  public Bounds Estimate(Sample x, Probability misrate)
  {
    return Estimate(x, misrate, null);
  }

  public Bounds Estimate(Sample x, Probability misrate, string? seed)
  {
    Assertion.Validity(x, Subject.X);

    if (double.IsNaN(misrate) || misrate < 0 || misrate > 1)
      throw AssumptionException.Domain(Subject.Misrate);

    int n = x.Size;
    int m = n / 2;
    double minMisrate = MinAchievableMisrate.OneSample(m);
    if (misrate < minMisrate)
      throw AssumptionException.Domain(Subject.Misrate);

    Assertion.Sparity(x, Subject.X);

    var rng = seed == null ? new Rng() : new Rng(seed);

    int margin = SignMargin.Instance.CalcRandomized(m, misrate, rng);
    int halfMargin = margin / 2;
    int maxHalfMargin = (m - 1) / 2;
    if (halfMargin > maxHalfMargin)
      halfMargin = maxHalfMargin;

    int kLeft = halfMargin + 1;
    int kRight = m - halfMargin;

    int[] indices = Enumerable.Range(0, n).ToArray();
    var shuffled = rng.Shuffle(indices);
    var diffs = new double[m];
    for (int i = 0; i < m; i++)
    {
      int a = shuffled[2 * i];
      int b = shuffled[2 * i + 1];
      diffs[i] = Math.Abs(x.Values[a] - x.Values[b]);
    }
    Array.Sort(diffs);

    double lower = diffs[kLeft - 1];
    double upper = diffs[kRight - 1];

    return new Bounds(lower, upper, x.Unit);
  }
}

Notes

SpreadBounds\operatorname{SpreadBounds} targets the population spread Spread=medianX1X2\operatorname{Spread} = \operatorname{median} \lvert X_1 - X_2 \rvert with distribution-free coverage. This note records the approaches we discussed and tried, why most of them fail, and which theoretical limits force the final design. Here distribution-free means the stated misrate bound holds for all distributions of XX, not just for a parametric family or under smoothness assumptions.

Setup and notation

Let X1,..,XnX_1, .., X_n be i.i.d. real-valued observations. Let m=n2m = \lfloor \frac{n}{2} \rfloor and let π\pi be a random disjoint pairing of indices independent of the values. Define

di=Xπ(2i1)Xπ(2i)d_i = \lvert X_{\pi(2i-1)} - X_{\pi(2i)} \rvert

for i=1..mi = 1..m, and let d(1)..d(m)d_{(1)} \leq .. \leq d_{(m)} be their order statistics.

Let GG be the distribution of D=X1X2D = \lvert X_1 - X_2 \rvert and let θ\theta be any median of GG. The target parameter is Spread=θ\operatorname{Spread} = \theta.

Valid pivot and exact coverage

Assume weak continuity of GG (no ties), so P(Dθ)=12P(D \leq \theta) = \frac{1}{2}. Then the sign count SS (the number of indices ii with diθd_i \leq \theta) has distribution BBinomial(m,12)B \sim \text{Binomial}(m, \frac{1}{2}). For any integer rr,

P(θ<d(r+1))=P(Sr),andP(θ>d(mr))=P(Sr).P(\theta < d_{(r+1)}) = P(S \leq r), and P(\theta > d_{(m-r)}) = P(S \leq r).

Therefore the interval [d(r+1),d(mr)][ d_{(r+1)}, d_{(m-r)} ] has coverage 12P(Sr)1 - 2 P(S \leq r) for all distributions of XX. This is the core distribution-free pivot used by SpreadBounds\operatorname{SpreadBounds}.

If GG has atoms (ties), then P(Dθ)12P(D \leq \theta) \geq \frac{1}{2} for any median θ\theta. The binomial pivot becomes conservative: the same interval still covers with probability at least 12P(Sr)1 - 2 P(S \leq r), but exact matching of a requested misrate is impossible.

Approaches that look reasonable but fail

All pairwise differences as if independent. Construct N=n(n1)2N = \frac{n(n-1)}{2} absolute differences and apply a sign-test or binomial confidence interval as if those NN values were i.i.d. This ignores strong dependence between pairs, so coverage can be arbitrarily wrong. Correcting for dependence would require the joint law of all pairwise differences, which depends on the unknown distribution and is not distribution-free.

U-statistic inequalities for the median. Hoeffding-type bounds give distribution-free confidence bands for U-statistics, but for a median of pairwise differences they are extremely conservative. Intervals frequently collapse to almost [min,max][\min, \max], which is unusable in practice. Asymptotic U-quantile results require smoothness and density assumptions, so they are not distribution-free.

Deterministic pairing based on order or sorting. Pairing consecutive elements in the given order is value-independent, but it is not permutation-invariant: changing the input order changes the result. If the order is adversarial (or structured), coverage can deviate arbitrarily. Pairing after sorting (or pairing extremes) is value-dependent, so the distribution-free pivot no longer applies.

Choose the best pairing based on the data. Searching many pairings and picking the tightest interval is data-dependent. The selection event depends on the observed values, so coverage is not unconditional. Coverage can become arbitrarily low.

Bootstrap, asymptotic normality, or variance estimation. These are not distribution-free and can be anti-conservative for heavy tails or small samples. Studentization helps asymptotically but still depends on distributional regularity (density, smoothness, finite moments).

Mid-p or continuity-corrected binomial intervals. These reduce discreteness but do not guarantee the nominal misrate even for the binomial model itself, so the distribution-free guarantee is lost.

Deterministic disjoint pairs: why it is conservative

With disjoint pairs, the pivot is valid, but the binomial CDF is discrete. The achievable misrates form a grid

2P(Br)2 * P(B \leq r)

. If the requested misrate falls between grid points, a deterministic method must round down, which is conservative by design. The minimum achievable misrate is 21m2^{1-m}.

Deterministic interpolation between neighboring order statistics would use value distances instead of ranks, making coverage distribution-dependent and invalidating the distribution-free guarantee. As mm grows, the grid becomes finer (step size is O(1m)O(\frac{1}{\sqrt{m}})), so deterministic rounding converges asymptotically, but exact matching remains impossible for any finite nn.

Working approach: randomized cutoff

The final design keeps disjoint pairs but randomizes the cutoff rr between adjacent grid points. Let t=misrate2t = \frac{\mathrm{misrate}}{2}. Define F(r)=P(Br)F(r) = P(B \leq r) and f(r)=P(B=r)f(r) = P(B = r). Let rlr_l be the largest integer such that F(rl)tF(r_l) \leq t and let rh=rl+1r_h = r_l + 1. Choose r=rhr = r_h with probability

p=(tF(rl))/f(rh)p = (t - F(r_l)) / f(r_h)

and r=rlr = r_l otherwise. This makes the tail probability exactly tt.

Randomization affects only the cutoff and is independent of data values, so the distribution-free property is preserved.

Theoretical limits

  • Distribution-free + deterministic + exact misrate is impossible for finite nn. The pivot statistic is integer-valued, so the coverage function takes only finitely many values. Exact matching requires randomization.
  • Exact matching for all distributions is impossible because ties break the binomial pivot. Under weak continuity (no ties), randomized cutoffs achieve exact misrate; with atoms, coverage is only guaranteed to be conservative.
  • Deterministic exact misrate is possible only with extra assumptions (parametric family, smooth density at the target, known variance), which violates distribution-free guarantees.
  • Any method that treats all pairwise differences as independent is invalid because dependence destroys the binomial pivot.
  • Any data-dependent choice of pairing or cutoff breaks unconditional coverage and can make the method arbitrarily anti-conservative.

Tests

SpreadBounds(x,misrate)=[L,U]\operatorname{SpreadBounds}(\mathbf{x}, \mathrm{misrate}) = [L, U]

Let m=n2m = \lfloor \frac{n}{2} \rfloor. Draw a value-independent random disjoint pairing of the sample, compute d=xπ(2i1)xπ(2i)\mathbf{d} = { \lvert x_{\pi(2i-1)} - x_{\pi(2i)} \rvert } for i=1..mi = 1..m, and sort ascending.

Let rr be the largest integer such that sumi=0r(mi)2mmisrate2sum_{i=0}^r \frac{\binom{m}{i}}{2^m} \leq \frac{\mathrm{misrate}}{2}. If the target lies between two adjacent CDF steps, rr is randomized between rr and r+1r + 1 to match the requested misrate. Define kL=r+1k_L = r + 1 and kU=mrk_U = m - r.

Return [L,U]=[d(kL),d(kU)][L, U] = [d_{(k_L)}, d_{(k_U)}].

The SpreadBounds\operatorname{SpreadBounds} test suite contains 46 test cases (3 demo + 4 natural + 4 property + 7 edge + 3 additive + 2 uniform + 5 misrate + 5 conservatism + 8 unsorted + 5 error cases). Since SpreadBounds\operatorname{SpreadBounds} returns bounds rather than a point estimate, tests validate that bounds are well-formed and satisfy equivariance properties under a fixed seed. Each test case output is a JSON object with lower and upper fields representing the interval bounds. Because pairing and cutoff selection are randomized, tests fix seed to keep outputs deterministic.

Demo examples from manual introduction, validating basic bounds:

  • demo-1: x=(1,2,,30)\mathbf{x} = (1, 2, \ldots, 30), misrate=0.01\mathrm{misrate} = 0.01, bounds containing Spread=9\operatorname{Spread} = 9
  • demo-2: x=(1,2,,30)\mathbf{x} = (1, 2, \ldots, 30), misrate=0.002\mathrm{misrate} = 0.002, wider bounds (tighter misrate)
  • demo-3: x=(1,2,,15)\mathbf{x} = (1, 2, \ldots, 15), misrate=0.07\mathrm{misrate} = 0.07

These cases illustrate how tighter misrates produce wider bounds and how sample size affects bound width.

Natural sequences (misrate varies by size) 4 tests:

  • natural-10: x=(1,2,,10)\mathbf{x} = (1, 2, \ldots, 10), misrate=0.15\mathrm{misrate} = 0.15
  • natural-15: x=(1,2,,15)\mathbf{x} = (1, 2, \ldots, 15), misrate=0.05\mathrm{misrate} = 0.05
  • natural-20: x=(1,2,,20)\mathbf{x} = (1, 2, \ldots, 20), misrate=0.05\mathrm{misrate} = 0.05
  • natural-30: x=(1,2,,30)\mathbf{x} = (1, 2, \ldots, 30), misrate=0.05\mathrm{misrate} = 0.05

Property validation (n=10n = 10, misrate=0.2\mathrm{misrate} = 0.2) 4 tests:

  • property-identity: x=(1,2,,10)\mathbf{x} = (1, 2, \ldots, 10), bounds must contain Spread\operatorname{Spread}
  • property-location-shift: x=(11,12,,20)\mathbf{x} = (11, 12, \ldots, 20) (= identity + 10), bounds must equal identity bounds (shift invariance)
  • property-scale-2x: x=(2,4,,20)\mathbf{x} = (2, 4, \ldots, 20) (= 2 ×\times identity), bounds must be 2×\times identity bounds (scale equivariance)
  • property-scale-neg: x=(10,9,,1)\mathbf{x} = (-10, -9, \ldots, -1) (= 1×-1 \times identity), bounds must equal identity bounds (k\lvert k \rvert scaling)

Edge cases boundary conditions and extreme scenarios (7 tests):

  • edge-small-non-trivial: x=(1,2,3,4,5)\mathbf{x} = (1, 2, 3, 4, 5), misrate=0.8\mathrm{misrate} = 0.8 (small but non-trivial bounds)
  • edge-large-misrate: x=(1,2,,10)\mathbf{x} = (1, 2, \ldots, 10), misrate=0.5\mathrm{misrate} = 0.5 (permissive bounds)
  • edge-duplicates-mixed: x=(1,1,1,2,3,4,5)\mathbf{x} = (1, 1, 1, 2, 3, 4, 5), misrate=0.5\mathrm{misrate} = 0.5 (partial ties)
  • edge-wide-range: x=(1,10,100,1000,10000)\mathbf{x} = (1, 10, 100, 1000, 10000), misrate=0.8\mathrm{misrate} = 0.8 (extreme value range)
  • edge-negative: x=(5,4,3,2,1)\mathbf{x} = (-5, -4, -3, -2, -1), misrate=0.8\mathrm{misrate} = 0.8 (negative values)
  • edge-large-n: x=(1,2,,100)\mathbf{x} = (1, 2, \ldots, 100), misrate=0.01\mathrm{misrate} = 0.01 (large sample, tighter sign-test bounds)
  • edge-n2: x=(1,3)\mathbf{x} = (1, 3), misrate=1.0\mathrm{misrate} = 1.0 (minimum sample size, only valid misrate is 1.0)

Additive distribution (misrate varies by size) 3 tests with Additive(10,1)\underline{\operatorname{Additive}}(10, 1):

  • additive-20: n=20n = 20, misrate=0.02\mathrm{misrate} = 0.02
  • additive-30: n=30n = 30, misrate=0.01\mathrm{misrate} = 0.01
  • additive-50: n=50n = 50, misrate=0.01\mathrm{misrate} = 0.01

Uniform distribution (misrate varies by size) 2 tests with Uniform(0,1)\underline{\operatorname{Uniform}}(0, 1):

  • uniform-20: n=20n = 20, misrate=0.02\mathrm{misrate} = 0.02
  • uniform-50: n=50n = 50, misrate=0.01\mathrm{misrate} = 0.01

Misrate variation (x=(1,2,,25)\mathbf{x} = (1, 2, \ldots, 25)) 5 tests with varying misrates:

  • misrate-5e-1: misrate=0.5\mathrm{misrate} = 0.5
  • misrate-1e-1: misrate=0.1\mathrm{misrate} = 0.1
  • misrate-5e-2: misrate=0.05\mathrm{misrate} = 0.05
  • misrate-1e-2: misrate=0.01\mathrm{misrate} = 0.01
  • misrate-2e-3: misrate=0.002\mathrm{misrate} = 0.002

These tests validate monotonicity: smaller misrates produce wider bounds.

Conservatism tests (misrate=0.1\mathrm{misrate} = 0.1) 5 tests unique to SpreadBounds\operatorname{SpreadBounds}:

  • conservatism-12: x=(1,2,,12)\mathbf{x} = (1, 2, \ldots, 12), sign-test bounds are wide relative to Spread\operatorname{Spread}
  • conservatism-15: x=(1,2,,15)\mathbf{x} = (1, 2, \ldots, 15)
  • conservatism-20: x=(1,2,,20)\mathbf{x} = (1, 2, \ldots, 20)
  • conservatism-30: x=(1,2,,30)\mathbf{x} = (1, 2, \ldots, 30)
  • conservatism-50: x=(1,2,,50)\mathbf{x} = (1, 2, \ldots, 50)

These tests document how discreteness-driven conservatism decreases with increasing sample size. For small nn, bounds may span a large part of the pairwise-difference range. For large nn, bounds tighten to a practical interval around Spread\operatorname{Spread}.

Unsorted tests verify stable behavior on non-sorted inputs (8 tests):

  • unsorted-reverse-10: x=(10,9,,1)\mathbf{x} = (10, 9, \ldots, 1), misrate=0.2\mathrm{misrate} = 0.2
  • unsorted-reverse-15: x=(15,14,,1)\mathbf{x} = (15, 14, \ldots, 1), misrate=0.07\mathrm{misrate} = 0.07
  • unsorted-shuffle-10: x\mathbf{x} shuffled, misrate=0.2\mathrm{misrate} = 0.2
  • unsorted-shuffle-15: x\mathbf{x} shuffled, misrate=0.07\mathrm{misrate} = 0.07
  • unsorted-negative-5: negative values unsorted (misrate=0.8\mathrm{misrate} = 0.8)
  • unsorted-mixed-signs-5: mixed signs unsorted (misrate=0.8\mathrm{misrate} = 0.8)
  • unsorted-duplicates: x=(1,3,1,3,2)\mathbf{x} = (1, 3, 1, 3, 2), unsorted with duplicates (misrate=0.8\mathrm{misrate} = 0.8)
  • unsorted-wide-range: x=(1000,1,100,10,10000)\mathbf{x} = (1000, 1, 100, 10, 10000), unsorted wide range (misrate=0.8\mathrm{misrate} = 0.8)

These tests validate that SpreadBounds\operatorname{SpreadBounds} produces sensible bounds for arbitrary input order under a fixed seed.

Error cases inputs that violate assumptions (5 tests):

  • error-empty-array: x=()\mathbf{x} = (), misrate=0.5\mathrm{misrate} = 0.5 — empty array violates validity
  • error-single-element: x=(1)\mathbf{x} = (1), misrate=0.5\mathrm{misrate} = 0.5m=0m = 0 violates domain (nn too small to form pairs)
  • error-misrate-zero: x=(1,2,,10)\mathbf{x} = (1, 2, \ldots, 10), misrate=0\mathrm{misrate} = 0 — below minimum achievable misrate
  • error-invalid-misrate: x=(1,2,3,4,5)\mathbf{x} = (1, 2, 3, 4, 5), misrate=0.001\mathrm{misrate} = 0.001 — below minimum achievable misrate (212=0.52^{1-2} = 0.5)
  • error-constant-sample: x=(1,1,1,1,1)\mathbf{x} = (1, 1, 1, 1, 1), misrate=0.5\mathrm{misrate} = 0.5 — constant sample violates sparity (Spread=0\operatorname{Spread} = 0)

Note: SpreadBounds\operatorname{SpreadBounds} has a minimum misrate constraint. The sign-test inversion requires misrate21m\mathrm{misrate} \geq 2^{1-m}.