Problem
test/dist-cross-limits.js contains 6 cases across 165 distributions. Its own header explains why that is a problem:
Per-distribution mpmath refVals can't catch a parameterization bug (e.g. rate vs. scale) that is consistent within a single distribution's own formula; comparing two independently-written implementations against each other at a shared limit can.
This is the key point and it is worth stating plainly: a parameterization bug is invisible to every other test in the repo. If a distribution confuses rate with scale, or nu with nu/2, its _pdf, _cdf, _q, and the hand-written mpmath reference in test/precision-continuous.js will all agree with each other, because they were all derived from the same (wrong) reading of the parameterization. A perfect 1-ULP differential sweep passes. Only a comparison against a different distribution class, written at a different time from a different source, catches it.
That makes cross-limit coverage complementary to the differential-testing harness rather than redundant with it, and it is currently the thinnest verification layer in the library relative to its bug-catching power.
Scope
Expand test/dist-cross-limits.js to cover the exact parameter identities — cases where a parameter substitution makes one distribution literally equal another, so the assertion can use a tight tolerance with no convergence argument needed.
The library's distribution set is dense in these. A non-exhaustive list to work from (verify each against the actual implementations and their parameter conventions before asserting — the conventions are exactly what is under test):
Gamma(1, theta) = Exponential; Gamma(n, theta) = Erlang(n, theta)
ChiSquare(k) = Gamma(k/2, 2)
StudentT(1) = Cauchy
Beta(1, 1) = Uniform(0, 1)
Weibull(k=1) = Exponential; Weibull(k=2) = Rayleigh
Chi(1) = HalfNormal; Chi(2) = Rayleigh; Chi(3) = MaxwellBoltzmann
Rice(nu=0) = Rayleigh; Hoyt(q=1) = Rayleigh; Nakagami(m=1) = Rayleigh
NoncentralChi2(lambda=0) = ChiSquare; NoncentralF(lambda=0) = F; NoncentralT(mu=0) = StudentT; NoncentralBeta(lambda=0) = Beta
DoublyNoncentralBeta/Chi2/F/T with both noncentrality parameters 0 = their central counterparts, and with one parameter 0 = the singly-noncentral versions
GeneralizedNormal(beta=2) = Normal; GeneralizedNormal(beta=1) = Laplace
Gilbrat = LogNormal(0, 1)
Geometric = NegativeBinomial(r=1); Bernoulli = Binomial(n=1)
Zipf = ZipfMandelbrot(q=0)
Kumaraswamy(1, 1) = Uniform(0, 1)
ExponentiatedWeibull(a=1) = Weibull
InverseChi2 / InverseGamma correspondence
LogLogistic / Fisk correspondence
HalfGeneralizedNormal(beta=2) = HalfNormal
Lomax / Pareto shift relationship
BetaBinomial(1, 1) = DiscreteUniform
Assert agreement of pdf/pmf, cdf, and q at a spread of points — including at least one point in each tail, not only near the median. A parameterization bug frequently shows up as a scale error that is small near the centre and large in the tails.
Critical methodological requirement
The existing file already encodes this lesson in its second test and it must not be lost in the expansion: an asymptotic limit taken to an extreme is too forgiving to catch a scaling bug. The current comment says it directly —
nu=1e6 above is too extreme to catch a nu-scaling bug (e.g. nu confused with nu/2): both the correct and a scaled-nu formula would land within 1e-5 of the normal limit.
Exact identities do not have this problem, which is precisely why this issue covers them first: there is no convergence tolerance to hide behind, so the assertion can be tight and a parameterization bug cannot survive it.
Out of scope — file as a follow-up
Asymptotic limits (Gamma(k) -> Normal as k -> Infinity, Binomial -> Poisson, NegativeBinomial -> Poisson, GEV(xi -> 0) -> Gumbel, GeneralizedPareto(xi -> 0) -> Exponential, Beta -> Normal, F(d1, d2 -> Infinity) -> ChiSquare/d1). These are valuable but need per-case convergence analysis: each requires a moderate-parameter companion test with a computed, documented bound on the expected gap, following the Cornish-Fisher pattern already used for StudentT. That is a different kind of work and belongs in its own issue.
Also out of scope: fixing any disagreement found. A cross-limit failure means one of the two distributions has a genuine bug — file it separately with both implementations named.
Expected outcome
This should find real parameterization bugs. Distributions with multiple competing conventions in the literature are the likely candidates — rate versus scale in the exponential family, Lomax/Pareto shift conventions, and the noncentrality parameter conventions across the noncentral and doubly-noncentral families. Anything found this way has been silently wrong since it shipped, because no existing test could see it.
Sizing
Test-only: the production diff is zero, so the ~400-line cap does not bind. Still, split by family if the file becomes unreviewable, and keep test/dist-cross-limits.js within CodeScene's per-file thresholds — the repo already split dist-base.js for exactly this reason (issue #1072).
Acceptance criteria
- Exact-identity coverage for the families listed above, each verified against the actual parameter conventions in the implementations.
pdf/pmf, cdf, and q asserted at a spread of points including both tails.
- Tolerances tight (exact identities admit no convergence slack); any loosening names the specific numerical mechanism.
- A comment on each case naming the identity and its source.
npm run standard and npm test pass with coverage thresholds met.
Notes
Complements the differential-testing harness (#1264, #1265) rather than duplicating it: the harness measures accuracy against an external reference, while this catches parameterization bugs that are self-consistent across a distribution's own formulas and therefore invisible to that reference.
Problem
test/dist-cross-limits.jscontains 6 cases across 165 distributions. Its own header explains why that is a problem:This is the key point and it is worth stating plainly: a parameterization bug is invisible to every other test in the repo. If a distribution confuses rate with scale, or
nuwithnu/2, its_pdf,_cdf,_q, and the hand-written mpmath reference intest/precision-continuous.jswill all agree with each other, because they were all derived from the same (wrong) reading of the parameterization. A perfect 1-ULP differential sweep passes. Only a comparison against a different distribution class, written at a different time from a different source, catches it.That makes cross-limit coverage complementary to the differential-testing harness rather than redundant with it, and it is currently the thinnest verification layer in the library relative to its bug-catching power.
Scope
Expand
test/dist-cross-limits.jsto cover the exact parameter identities — cases where a parameter substitution makes one distribution literally equal another, so the assertion can use a tight tolerance with no convergence argument needed.The library's distribution set is dense in these. A non-exhaustive list to work from (verify each against the actual implementations and their parameter conventions before asserting — the conventions are exactly what is under test):
Gamma(1, theta)=Exponential;Gamma(n, theta)=Erlang(n, theta)ChiSquare(k)=Gamma(k/2, 2)StudentT(1)=CauchyBeta(1, 1)=Uniform(0, 1)Weibull(k=1)=Exponential;Weibull(k=2)=RayleighChi(1)=HalfNormal;Chi(2)=Rayleigh;Chi(3)=MaxwellBoltzmannRice(nu=0)=Rayleigh;Hoyt(q=1)=Rayleigh;Nakagami(m=1)=RayleighNoncentralChi2(lambda=0)=ChiSquare;NoncentralF(lambda=0)=F;NoncentralT(mu=0)=StudentT;NoncentralBeta(lambda=0)=BetaDoublyNoncentralBeta/Chi2/F/Twith both noncentrality parameters 0 = their central counterparts, and with one parameter 0 = the singly-noncentral versionsGeneralizedNormal(beta=2)=Normal;GeneralizedNormal(beta=1)=LaplaceGilbrat=LogNormal(0, 1)Geometric=NegativeBinomial(r=1);Bernoulli=Binomial(n=1)Zipf=ZipfMandelbrot(q=0)Kumaraswamy(1, 1)=Uniform(0, 1)ExponentiatedWeibull(a=1)=WeibullInverseChi2/InverseGammacorrespondenceLogLogistic/ Fisk correspondenceHalfGeneralizedNormal(beta=2)=HalfNormalLomax/Paretoshift relationshipBetaBinomial(1, 1)=DiscreteUniformAssert agreement of
pdf/pmf,cdf, andqat a spread of points — including at least one point in each tail, not only near the median. A parameterization bug frequently shows up as a scale error that is small near the centre and large in the tails.Critical methodological requirement
The existing file already encodes this lesson in its second test and it must not be lost in the expansion: an asymptotic limit taken to an extreme is too forgiving to catch a scaling bug. The current comment says it directly —
Exact identities do not have this problem, which is precisely why this issue covers them first: there is no convergence tolerance to hide behind, so the assertion can be tight and a parameterization bug cannot survive it.
Out of scope — file as a follow-up
Asymptotic limits (
Gamma(k) -> Normalask -> Infinity,Binomial -> Poisson,NegativeBinomial -> Poisson,GEV(xi -> 0) -> Gumbel,GeneralizedPareto(xi -> 0) -> Exponential,Beta -> Normal,F(d1, d2 -> Infinity) -> ChiSquare/d1). These are valuable but need per-case convergence analysis: each requires a moderate-parameter companion test with a computed, documented bound on the expected gap, following the Cornish-Fisher pattern already used forStudentT. That is a different kind of work and belongs in its own issue.Also out of scope: fixing any disagreement found. A cross-limit failure means one of the two distributions has a genuine bug — file it separately with both implementations named.
Expected outcome
This should find real parameterization bugs. Distributions with multiple competing conventions in the literature are the likely candidates — rate versus scale in the exponential family,
Lomax/Paretoshift conventions, and the noncentrality parameter conventions across the noncentral and doubly-noncentral families. Anything found this way has been silently wrong since it shipped, because no existing test could see it.Sizing
Test-only: the production diff is zero, so the ~400-line cap does not bind. Still, split by family if the file becomes unreviewable, and keep
test/dist-cross-limits.jswithin CodeScene's per-file thresholds — the repo already splitdist-base.jsfor exactly this reason (issue #1072).Acceptance criteria
pdf/pmf,cdf, andqasserted at a spread of points including both tails.npm run standardandnpm testpass with coverage thresholds met.Notes
Complements the differential-testing harness (#1264, #1265) rather than duplicating it: the harness measures accuracy against an external reference, while this catches parameterization bugs that are self-consistent across a distribution's own formulas and therefore invisible to that reference.