From bd54a76fd7902af207af6c2cc3126fa33721edc4 Mon Sep 17 00:00:00 2001 From: Abhist17 Date: Mon, 28 Sep 2026 04:37:25 +0530 Subject: [PATCH] fix: return the limiting density at `x = 0` in `stats/base/dists/betaprime/logpdf` and `pdf` Both treated `x = 0` as outside the support and returned `-Infinity` (`0`). The density `x^(alpha-1) (1+x)^(-alpha-beta) / B(alpha, beta)` tends to `+Infinity`, `beta`, or `0` there for `alpha` less than, equal to, or greater than one. `pdf` (JavaScript and C) delegates to `logpdf`, so the fix is in `logpdf`; the `pdf` tests asserted `pdf( 0, 1, 1 ) = 0` where the density is `1`. --- .../base/dists/betaprime/logpdf/lib/factory.js | 15 +++++++++++++-- .../base/dists/betaprime/logpdf/lib/main.js | 15 +++++++++++++-- .../base/dists/betaprime/logpdf/manifest.json | 3 +++ .../base/dists/betaprime/logpdf/src/main.c | 15 +++++++++++++-- .../betaprime/logpdf/test/test.factory.js | 16 ++++++++++++++++ .../dists/betaprime/logpdf/test/test.logpdf.js | 8 ++++++++ .../dists/betaprime/logpdf/test/test.native.js | 8 ++++++++ .../dists/betaprime/pdf/test/test.factory.js | 18 +++++++++++++++--- .../dists/betaprime/pdf/test/test.native.js | 10 +++++++--- .../base/dists/betaprime/pdf/test/test.pdf.js | 10 +++++++--- 10 files changed, 103 insertions(+), 15 deletions(-) diff --git a/lib/node_modules/@stdlib/stats/base/dists/betaprime/logpdf/lib/factory.js b/lib/node_modules/@stdlib/stats/base/dists/betaprime/logpdf/lib/factory.js index 0ad2e9d7b822..1009bcbe71a6 100644 --- a/lib/node_modules/@stdlib/stats/base/dists/betaprime/logpdf/lib/factory.js +++ b/lib/node_modules/@stdlib/stats/base/dists/betaprime/logpdf/lib/factory.js @@ -25,6 +25,7 @@ var betaln = require( '@stdlib/math/base/special/betaln' ); var isnan = require( '@stdlib/math/base/assert/is-nan' ); var log1p = require( '@stdlib/math/base/special/log1p' ); var ln = require( '@stdlib/math/base/special/ln' ); +var PINF = require( '@stdlib/constants/float64/pinf' ); var NINF = require( '@stdlib/constants/float64/ninf' ); @@ -75,10 +76,20 @@ function factory( alpha, beta ) { if ( isnan( x ) ) { return NaN; } - if ( x <= 0.0 ) { - // Support of the beta prime distribution: (0,∞) + if ( x < 0.0 ) { + // Support of the beta prime distribution: [0,∞) return NINF; } + // At `x = 0`, the density is infinite for `alpha < 1`, `1/B(1,beta) = beta` for `alpha = 1`, and `0` for `alpha > 1`: + if ( x === 0.0 ) { + if ( alpha < 1.0 ) { + return PINF; + } + if ( alpha > 1.0 ) { + return NINF; + } + return ln( beta ); + } out = ( alpha-1.0 ) * ln( x ); out -= ( alpha+beta ) * log1p( x ); out -= betalnAB; diff --git a/lib/node_modules/@stdlib/stats/base/dists/betaprime/logpdf/lib/main.js b/lib/node_modules/@stdlib/stats/base/dists/betaprime/logpdf/lib/main.js index 72e11be3a76f..1cd8d0b216b9 100644 --- a/lib/node_modules/@stdlib/stats/base/dists/betaprime/logpdf/lib/main.js +++ b/lib/node_modules/@stdlib/stats/base/dists/betaprime/logpdf/lib/main.js @@ -24,6 +24,7 @@ var betaln = require( '@stdlib/math/base/special/betaln' ); var isnan = require( '@stdlib/math/base/assert/is-nan' ); var log1p = require( '@stdlib/math/base/special/log1p' ); var ln = require( '@stdlib/math/base/special/ln' ); +var PINF = require( '@stdlib/constants/float64/pinf' ); var NINF = require( '@stdlib/constants/float64/ninf' ); @@ -89,10 +90,20 @@ function logpdf( x, alpha, beta ) { ) { return NaN; } - if ( x <= 0.0 ) { - // Support of the beta prime distribution: (0,∞) + if ( x < 0.0 ) { + // Support of the beta prime distribution: [0,∞) return NINF; } + // At `x = 0`, the density is infinite for `alpha < 1`, `1/B(1,beta) = beta` for `alpha = 1`, and `0` for `alpha > 1`: + if ( x === 0.0 ) { + if ( alpha < 1.0 ) { + return PINF; + } + if ( alpha > 1.0 ) { + return NINF; + } + return ln( beta ); + } out = ( alpha-1.0 ) * ln( x ); out -= ( alpha+beta ) * log1p( x ); out -= betaln( alpha, beta ); diff --git a/lib/node_modules/@stdlib/stats/base/dists/betaprime/logpdf/manifest.json b/lib/node_modules/@stdlib/stats/base/dists/betaprime/logpdf/manifest.json index 2e552b6f15a9..deead4e9c63b 100644 --- a/lib/node_modules/@stdlib/stats/base/dists/betaprime/logpdf/manifest.json +++ b/lib/node_modules/@stdlib/stats/base/dists/betaprime/logpdf/manifest.json @@ -43,6 +43,7 @@ "@stdlib/math/base/special/betaln", "@stdlib/math/base/special/log1p", "@stdlib/math/base/special/ln", + "@stdlib/constants/float64/pinf", "@stdlib/constants/float64/ninf" ] }, @@ -62,6 +63,7 @@ "@stdlib/math/base/special/betaln", "@stdlib/math/base/special/log1p", "@stdlib/math/base/special/ln", + "@stdlib/constants/float64/pinf", "@stdlib/constants/float64/ninf", "@stdlib/constants/float64/eps" ] @@ -82,6 +84,7 @@ "@stdlib/math/base/special/betaln", "@stdlib/math/base/special/log1p", "@stdlib/math/base/special/ln", + "@stdlib/constants/float64/pinf", "@stdlib/constants/float64/ninf", "@stdlib/constants/float64/eps" ] diff --git a/lib/node_modules/@stdlib/stats/base/dists/betaprime/logpdf/src/main.c b/lib/node_modules/@stdlib/stats/base/dists/betaprime/logpdf/src/main.c index 1bda2b4b87f2..e1f7b94207ab 100644 --- a/lib/node_modules/@stdlib/stats/base/dists/betaprime/logpdf/src/main.c +++ b/lib/node_modules/@stdlib/stats/base/dists/betaprime/logpdf/src/main.c @@ -20,6 +20,7 @@ #include "stdlib/math/base/special/betaln.h" #include "stdlib/math/base/special/log1p.h" #include "stdlib/math/base/special/ln.h" +#include "stdlib/constants/float64/pinf.h" #include "stdlib/constants/float64/ninf.h" /** @@ -45,10 +46,20 @@ double stdlib_base_dists_betaprime_logpdf( const double x, const double alpha, c ) { return 0.0 / 0.0; } - if ( x <= 0.0 ) { - // Support of the beta prime distribution: (0,∞) + if ( x < 0.0 ) { + // Support of the beta prime distribution: [0,∞) return STDLIB_CONSTANT_FLOAT64_NINF; } + // At `x = 0`, the density is infinite for `alpha < 1`, `1/B(1,beta) = beta` for `alpha = 1`, and `0` for `alpha > 1`: + if ( x == 0.0 ) { + if ( alpha < 1.0 ) { + return STDLIB_CONSTANT_FLOAT64_PINF; + } + if ( alpha > 1.0 ) { + return STDLIB_CONSTANT_FLOAT64_NINF; + } + return stdlib_base_ln( beta ); + } out = ( alpha-1.0 ) * stdlib_base_ln( x ); out -= ( alpha+beta ) * stdlib_base_log1p( x ); out -= stdlib_base_betaln( alpha, beta ); diff --git a/lib/node_modules/@stdlib/stats/base/dists/betaprime/logpdf/test/test.factory.js b/lib/node_modules/@stdlib/stats/base/dists/betaprime/logpdf/test/test.factory.js index dfdd21d01249..43b17c3a572e 100644 --- a/lib/node_modules/@stdlib/stats/base/dists/betaprime/logpdf/test/test.factory.js +++ b/lib/node_modules/@stdlib/stats/base/dists/betaprime/logpdf/test/test.factory.js @@ -21,6 +21,7 @@ // MODULES // var tape = require( 'tape' ); +var ln = require( '@stdlib/math/base/special/ln' ); var isnan = require( '@stdlib/math/base/assert/is-nan' ); var abs = require( '@stdlib/math/base/special/abs' ); var PINF = require( '@stdlib/constants/float64/pinf' ); @@ -94,6 +95,21 @@ tape( 'if provided a valid `alpha` and `beta`, the function returns a function w t.end(); }); +tape( 'the created function returns `+infinity`, `ln(beta)`, or `-infinity` at `x = 0` when `alpha` is less than, equal to, or greater than one', function test( t ) { + var logpdf; + + logpdf = factory( 0.5, 2.0 ); + t.strictEqual( logpdf( 0.0 ), PINF, 'returns expected value' ); + + logpdf = factory( 1.0, 2.0 ); + t.strictEqual( logpdf( 0.0 ), ln( 2.0 ), 'returns expected value' ); + + logpdf = factory( 3.0, 2.0 ); + t.strictEqual( logpdf( 0.0 ), NINF, 'returns expected value' ); + + t.end(); +}); + tape( 'if provided `beta <= 0`, the created function always returns `NaN`', function test( t ) { var logpdf; var y; diff --git a/lib/node_modules/@stdlib/stats/base/dists/betaprime/logpdf/test/test.logpdf.js b/lib/node_modules/@stdlib/stats/base/dists/betaprime/logpdf/test/test.logpdf.js index 5dd308cc1843..5617ac3a9ebb 100644 --- a/lib/node_modules/@stdlib/stats/base/dists/betaprime/logpdf/test/test.logpdf.js +++ b/lib/node_modules/@stdlib/stats/base/dists/betaprime/logpdf/test/test.logpdf.js @@ -21,6 +21,7 @@ // MODULES // var tape = require( 'tape' ); +var ln = require( '@stdlib/math/base/special/ln' ); var isnan = require( '@stdlib/math/base/assert/is-nan' ); var abs = require( '@stdlib/math/base/special/abs' ); var PINF = require( '@stdlib/constants/float64/pinf' ); @@ -69,6 +70,13 @@ tape( 'if provided a number smaller than zero for `x` and a valid `alpha` and `b t.end(); }); +tape( 'the function returns `+infinity`, `ln(beta)`, or `-infinity` at `x = 0` when `alpha` is less than, equal to, or greater than one', function test( t ) { + t.strictEqual( logpdf( 0.0, 0.5, 2.0 ), PINF, 'returns expected value' ); + t.strictEqual( logpdf( 0.0, 1.0, 2.0 ), ln( 2.0 ), 'returns expected value' ); + t.strictEqual( logpdf( 0.0, 3.0, 2.0 ), NINF, 'returns expected value' ); + t.end(); +}); + tape( 'if provided `alpha <= 0`, the function returns `NaN`', function test( t ) { var y; diff --git a/lib/node_modules/@stdlib/stats/base/dists/betaprime/logpdf/test/test.native.js b/lib/node_modules/@stdlib/stats/base/dists/betaprime/logpdf/test/test.native.js index 40a28551a640..294348bca821 100644 --- a/lib/node_modules/@stdlib/stats/base/dists/betaprime/logpdf/test/test.native.js +++ b/lib/node_modules/@stdlib/stats/base/dists/betaprime/logpdf/test/test.native.js @@ -22,6 +22,7 @@ var resolve = require( 'path' ).resolve; var tape = require( 'tape' ); +var ln = require( '@stdlib/math/base/special/ln' ); var isnan = require( '@stdlib/math/base/assert/is-nan' ); var tryRequire = require( '@stdlib/utils/try-require' ); var abs = require( '@stdlib/math/base/special/abs' ); @@ -78,6 +79,13 @@ tape( 'if provided a number smaller than zero for `x` and a valid `alpha` and `b t.end(); }); +tape( 'the function returns `+infinity`, `ln(beta)`, or `-infinity` at `x = 0` when `alpha` is less than, equal to, or greater than one', opts, function test( t ) { + t.strictEqual( logpdf( 0.0, 0.5, 2.0 ), PINF, 'returns expected value' ); + t.strictEqual( logpdf( 0.0, 1.0, 2.0 ), ln( 2.0 ), 'returns expected value' ); + t.strictEqual( logpdf( 0.0, 3.0, 2.0 ), NINF, 'returns expected value' ); + t.end(); +}); + tape( 'if provided `alpha <= 0`, the function returns `NaN`', opts, function test( t ) { var y; diff --git a/lib/node_modules/@stdlib/stats/base/dists/betaprime/pdf/test/test.factory.js b/lib/node_modules/@stdlib/stats/base/dists/betaprime/pdf/test/test.factory.js index 83f5bdca0822..f12f4d466734 100644 --- a/lib/node_modules/@stdlib/stats/base/dists/betaprime/pdf/test/test.factory.js +++ b/lib/node_modules/@stdlib/stats/base/dists/betaprime/pdf/test/test.factory.js @@ -76,7 +76,7 @@ tape( 'if provided `NaN` for any parameter, the created function returns `NaN`', t.end(); }); -tape( 'if provided a valid `alpha` and `beta`, the function returns a function which returns `0` when provided a nonpositive number for `x`', function test( t ) { +tape( 'if provided a valid `alpha` and `beta`, the function returns a function which returns `0` when provided a negative number for `x`', function test( t ) { var pdf; var y; @@ -90,8 +90,20 @@ tape( 'if provided a valid `alpha` and `beta`, the function returns a function w y = pdf( -0.5 ); t.strictEqual( y, 0.0, 'returns expected value' ); - y = pdf( 0.0 ); - t.strictEqual( y, 0.0, 'returns expected value' ); + t.end(); +}); + +tape( 'the created function returns `+infinity`, `beta`, or `0` at `x = 0` when `alpha` is less than, equal to, or greater than one', function test( t ) { + var pdf; + + pdf = factory( 0.5, 2.0 ); + t.strictEqual( pdf( 0.0 ), PINF, 'returns expected value' ); + + pdf = factory( 1.0, 2.0 ); + t.strictEqual( pdf( 0.0 ), 2.0, 'returns expected value' ); + + pdf = factory( 3.0, 2.0 ); + t.strictEqual( pdf( 0.0 ), 0.0, 'returns expected value' ); t.end(); }); diff --git a/lib/node_modules/@stdlib/stats/base/dists/betaprime/pdf/test/test.native.js b/lib/node_modules/@stdlib/stats/base/dists/betaprime/pdf/test/test.native.js index b68ba162c2c3..18ac65742304 100644 --- a/lib/node_modules/@stdlib/stats/base/dists/betaprime/pdf/test/test.native.js +++ b/lib/node_modules/@stdlib/stats/base/dists/betaprime/pdf/test/test.native.js @@ -62,7 +62,7 @@ tape( 'if provided `NaN` for any parameter, the function returns `NaN`', opts, f t.end(); }); -tape( 'if provided a nonpositive number for `x` and a valid `alpha` and `beta`, the function returns `0`', opts, function test( t ) { +tape( 'if provided a negative number for `x` and a valid `alpha` and `beta`, the function returns `0`', opts, function test( t ) { var y; y = pdf( NINF, 1.0, 1.0 ); @@ -74,9 +74,13 @@ tape( 'if provided a nonpositive number for `x` and a valid `alpha` and `beta`, y = pdf( -0.5, 1.0, 1.0 ); t.strictEqual( y, 0.0, 'returns expected value' ); - y = pdf( 0.0, 1.0, 1.0 ); - t.strictEqual( y, 0.0, 'returns expected value' ); + t.end(); +}); +tape( 'the function returns `+infinity`, `beta`, or `0` at `x = 0` when `alpha` is less than, equal to, or greater than one', opts, function test( t ) { + t.strictEqual( pdf( 0.0, 0.5, 2.0 ), PINF, 'returns expected value' ); + t.strictEqual( pdf( 0.0, 1.0, 2.0 ), 2.0, 'returns expected value' ); + t.strictEqual( pdf( 0.0, 3.0, 2.0 ), 0.0, 'returns expected value' ); t.end(); }); diff --git a/lib/node_modules/@stdlib/stats/base/dists/betaprime/pdf/test/test.pdf.js b/lib/node_modules/@stdlib/stats/base/dists/betaprime/pdf/test/test.pdf.js index 6732924525c0..713bba4af22b 100644 --- a/lib/node_modules/@stdlib/stats/base/dists/betaprime/pdf/test/test.pdf.js +++ b/lib/node_modules/@stdlib/stats/base/dists/betaprime/pdf/test/test.pdf.js @@ -53,7 +53,7 @@ tape( 'if provided `NaN` for any parameter, the function returns `NaN`', functio t.end(); }); -tape( 'if provided a nonpositive number for `x` and a valid `alpha` and `beta`, the function returns `0`', function test( t ) { +tape( 'if provided a negative number for `x` and a valid `alpha` and `beta`, the function returns `0`', function test( t ) { var y; y = pdf( NINF, 1.0, 1.0 ); @@ -65,9 +65,13 @@ tape( 'if provided a nonpositive number for `x` and a valid `alpha` and `beta`, y = pdf( -0.5, 1.0, 1.0 ); t.strictEqual( y, 0.0, 'returns expected value' ); - y = pdf( 0.0, 1.0, 1.0 ); - t.strictEqual( y, 0.0, 'returns expected value' ); + t.end(); +}); +tape( 'the function returns `+infinity`, `beta`, or `0` at `x = 0` when `alpha` is less than, equal to, or greater than one', function test( t ) { + t.strictEqual( pdf( 0.0, 0.5, 2.0 ), PINF, 'returns expected value' ); + t.strictEqual( pdf( 0.0, 1.0, 2.0 ), 2.0, 'returns expected value' ); + t.strictEqual( pdf( 0.0, 3.0, 2.0 ), 0.0, 'returns expected value' ); t.end(); });