diff --git a/lib/node_modules/@stdlib/stats/base/dists/hypergeometric/logpmf/README.md b/lib/node_modules/@stdlib/stats/base/dists/hypergeometric/logpmf/README.md index 2798e66e45ab..6ba63717098d 100644 --- a/lib/node_modules/@stdlib/stats/base/dists/hypergeometric/logpmf/README.md +++ b/lib/node_modules/@stdlib/stats/base/dists/hypergeometric/logpmf/README.md @@ -1,197 +1,3 @@ - - -# Logarithm of Probability Mass Function - -> Evaluate the natural logarithm of the [probability mass function][pmf] (PMF) for a [hypergeometric][hypergeometric-distribution] distribution. - -
- -Imagine a scenario with a population of size `N`, of which a subpopulation of size `K` can be considered successes. We draw `n` observations from the total population. Defining the random variable `X` as the number of successes in the `n` draws, `X` is said to follow a [hypergeometric distribution][hypergeometric-distribution]. The [probability mass function][pmf] (PMF) for a [hypergeometric][hypergeometric-distribution] random variable is given by - - - -```math -f(x;N,K,n)=P(X=x;N,K,n)=\begin{cases} {{{K \choose x} {N-K \choose {n-x}}}\over {{N} \choose n}} & \text{ for } x = 0,1,2,\ldots \\ 0 & \text{ otherwise} \end{cases} -``` - - - - - -
- - - -
- -## Usage - -```javascript -var logpmf = require( '@stdlib/stats/base/dists/hypergeometric/logpmf' ); -``` - -#### logpmf( x, N, K, n ) - -Evaluates the natural logarithm of the [probability mass function][pmf] (PMF) for a [hypergeometric][hypergeometric-distribution] distribution with parameters `N` (population size), `K` (subpopulation size), and `n` (number of draws). - -```javascript -var y = logpmf( 1.0, 8, 4, 2 ); -// returns ~-0.56 - -y = logpmf( 2.0, 8, 4, 2 ); -// returns ~-1.54 - -y = logpmf( 0.0, 8, 4, 2 ); -// returns ~-1.54 - -y = logpmf( 1.5, 8, 4, 2 ); -// returns -Infinity -``` - -If provided `NaN` as any argument, the function returns `NaN`. - -```javascript -var y = logpmf( NaN, 10, 5, 2 ); -// returns NaN - -y = logpmf( 0.0, NaN, 5, 2 ); -// returns NaN - -y = logpmf( 0.0, 10, NaN, 2 ); -// returns NaN - -y = logpmf( 0.0, 10, 5, NaN ); -// returns NaN -``` - -If provided a population size `N`, subpopulation size `K`, or draws `n` which is not a nonnegative integer, the function returns `NaN`. - -```javascript -var y = logpmf( 2.0, 10.5, 5, 2 ); -// returns NaN - -y = logpmf( 2.0, 10, 1.5, 2 ); -// returns NaN - -y = logpmf( 2.0, 10, 5, -2.0 ); -// returns NaN -``` - -If the number of draws `n` or the subpopulation size `K` exceed population size `N`, the function returns `NaN`. - -```javascript -var y = logpmf( 2.0, 10, 5, 12 ); -// returns NaN - -y = logpmf( 2.0, 8, 3, 9 ); -// returns NaN -``` - -#### logpmf.factory( N, K, n ) - -Returns a function for evaluating the natural logarithm of the [probability mass function][pmf] (PMF) of a [hypergeometric ][hypergeometric-distribution] distribution with parameters `N` (population size), `K` (subpopulation size), and `n` (number of draws). - -```javascript -var mylogpmf = logpmf.factory( 30, 20, 5 ); -var y = mylogpmf( 4.0 ); -// returns ~-1.079 - -y = mylogpmf( 1.0 ); -// returns ~-3.524 -``` - -
- - - -
- -## Examples - - - -```javascript -var randu = require( '@stdlib/random/base/randu' ); -var round = require( '@stdlib/math/base/special/round' ); -var logpmf = require( '@stdlib/stats/base/dists/hypergeometric/logpmf' ); - -var i; -var N; -var K; -var n; -var x; -var y; - -for ( i = 0; i < 10; i++ ) { - x = round( randu() * 5.0 ); - N = round( randu() * 20.0 ); - K = round( randu() * N ); - n = round( randu() * N ); - y = logpmf( x, N, K, n ); - console.log( 'x: %d, N: %d, K: %d, n: %d, ln(P(X=x;N,K,n)): %d', x, N, K, n, y.toFixed( 4 ) ); -} -``` - -
- - - - - -* * * - -
- -## C APIs - - - -
- -
- - - - - -
- -### Usage - -```c -#include "stdlib/stats/base/dists/hypergeometric/logpmf.h" -``` - -#### stdlib_base_dists_hypergeometric_logpmf( x, N, K, n ) - -Evaluates the natural logarithm of the [probability mass function][pmf] (PMF) for a [hypergeometric][hypergeometric-distribution] distribution with parameters `N` (population size), `K` (subpopulation size), and `n` (number of draws). - -```c -double out = stdlib_base_dists_hypergeometric_logpmf( 1.0, 8, 4, 2 ); -// returns ~-0.56 -``` - The function accepts the following arguments: - **x**: `[in] double` input value. @@ -200,7 +6,7 @@ The function accepts the following arguments: - **n**: `[in] int32_t` number of draws. ```c -double stdlib_base_dists_hypergeometric_logpmf ( const double x, const int32_t N, const int32_t K, const int32_t n ); +double stdlib_base_dists_hypergeometric_logpmf( const double x, const int32_t N, const int32_t K, const int32_t n ); ```
@@ -208,74 +14,3 @@ double stdlib_base_dists_hypergeometric_logpmf ( const double x, const int32_t N - -
- -
- - - - - -
- -### Examples - -```c -#include "stdlib/stats/base/dists/hypergeometric/logpmf.h" -#include "stdlib/math/base/special/round.h" -#include -#include -#include - -static double random_uniform( const double min, const double max ) { - double v = (double)rand() / ( (double)RAND_MAX + 1.0 ); - return min + ( v * ( max - min ) ); -} - -int main( void ) { - int32_t N; - int32_t K; - int32_t n; - double y; - double x; - int i; - - for ( i = 0; i < 10; i++ ) { - x = stdlib_base_round( random_uniform( 0.0, 5.0 ) ); - N = stdlib_base_round( random_uniform( 0.0, 20.0 ) ); - K = stdlib_base_round( random_uniform( 0.0, N ) ); - n = stdlib_base_round( random_uniform( 0.0, N ) ); - y = stdlib_base_dists_hypergeometric_logpmf( x, N, K, n ); - printf( "x: %lf, N: %d, K: %d, n: %d, ln(P(X=x;N,K,n)): %lf\n", x, N, K, n, y ); - } -} -``` - -
- - - -
- - - - - - - - - - - - - - diff --git a/lib/node_modules/@stdlib/stats/base/dists/hypergeometric/logpmf/src/main.c b/lib/node_modules/@stdlib/stats/base/dists/hypergeometric/logpmf/src/main.c index 4a712cf680ce..2bf8fcdb478f 100644 --- a/lib/node_modules/@stdlib/stats/base/dists/hypergeometric/logpmf/src/main.c +++ b/lib/node_modules/@stdlib/stats/base/dists/hypergeometric/logpmf/src/main.c @@ -1,32 +1,7 @@ -/** -* @license Apache-2.0 -* -* Copyright (c) 2025 The Stdlib Authors. -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -#include "stdlib/stats/base/dists/hypergeometric/logpmf.h" -#include "stdlib/math/base/assert/is_nonnegative_integer.h" -#include "stdlib/math/base/assert/is_nan.h" -#include "stdlib/math/base/special/factorialln.h" -#include "stdlib/math/base/special/max.h" -#include "stdlib/math/base/special/min.h" -#include "stdlib/constants/float64/ninf.h" #include /** -* Evaluates the natural logarithm of the probability mass function (PMF) for a hypergeometric distribution with population size `N`, subpopulation size `K` and number of draws `n`. +* Evaluates the natural logarithm of the probability mass function (PMF) for a hypergeometric distribution with population size `N`, subpopulation size `K`, and number of draws `n`. * * @param x input value * @param N population size @@ -35,27 +10,18 @@ * @return evaluated logPMF * * @example -* double y = stdlib_base_dists_hypergeometric_logpmf( 1.0, 8, 4, 2 ); -* // returns ~-0.56 +* double y = stdlib_base_dists_hypergeometric_logpmf( 1.0, 10, 5, 3 ); +* // returns */ double stdlib_base_dists_hypergeometric_logpmf( const double x, const int32_t N, const int32_t K, const int32_t n ) { - double ldenom; - double lnum; - double maxs; - double mins; - - if ( stdlib_base_is_nan( x ) || N < 0 || K < 0 || n < 0 || K > N || n > N ) { - return 0.0/0.0; // NaN - } - - mins = stdlib_base_max( 0, n+K-N ); - maxs = stdlib_base_min( K, n ); - - if ( stdlib_base_is_nonnegative_integer( x ) && mins <= x && x <= maxs ) { - lnum = stdlib_base_factorialln( n ) + stdlib_base_factorialln( K ) + stdlib_base_factorialln( N-n ) + stdlib_base_factorialln( N-K ); - ldenom = stdlib_base_factorialln( N ) + stdlib_base_factorialln( x ) + stdlib_base_factorialln( n-x ); - ldenom += stdlib_base_factorialln( K-x ) + stdlib_base_factorialln( N-K+x-n ); - return lnum - ldenom; - } - return STDLIB_CONSTANT_FLOAT64_NINF; + if ( stdlib_base_is_nan( x ) || stdlib_base_is_nan( N ) || stdlib_base_is_nan( K ) || stdlib_base_is_nan( n ) ) { + return STDLIB_CONSTANT_FLOAT64_NINF; + } + if ( N <= 0 || K < 0 || K > N || n < 0 || n > N ) { + return STDLIB_CONSTANT_FLOAT64_NINF; + } + if ( x < stdlib_base_max( 0, n - (N-K) ) || x > stdlib_base_min( n, K ) ) { + return STDLIB_CONSTANT_FLOAT64_NINF; + } + return stdlib_base_factorialln( K ) - stdlib_base_factorialln( x ) - stdlib_base_factorialln( K-x ) + stdlib_base_factorialln( N-K ) - stdlib_base_factorialln( n-x ) - stdlib_base_factorialln( (N-K)-(n-x) ) - stdlib_base_factorialln( N ) + stdlib_base_factorialln( n ) + stdlib_base_factorialln( N-n ); } diff --git a/lib/node_modules/@stdlib/stats/base/dists/hypergeometric/logpmf/test/test.native.js b/lib/node_modules/@stdlib/stats/base/dists/hypergeometric/logpmf/test/test.native.js index 3ceaf3c515ae..ec1b370e41c1 100644 --- a/lib/node_modules/@stdlib/stats/base/dists/hypergeometric/logpmf/test/test.native.js +++ b/lib/node_modules/@stdlib/stats/base/dists/hypergeometric/logpmf/test/test.native.js @@ -1,13 +1,13 @@ /** * @license Apache-2.0 * -* Copyright (c) 2025 The Stdlib Authors. +* Copyright (c) 2018 The Stdlib Authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * -* http://www.apache.org/licenses/LICENSE-2.0 +* http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -20,106 +20,91 @@ // MODULES // -var resolve = require( 'path' ).resolve; var tape = require( 'tape' ); -var tryRequire = require( '@stdlib/utils/try-require' ); var isnan = require( '@stdlib/math/base/assert/is-nan' ); -var abs = require( '@stdlib/math/base/special/abs' ); -var NINF = require( '@stdlib/constants/float64/ninf' ); -var EPS = require( '@stdlib/constants/float64/eps' ); - - -// VARIABLES // - -var logpmf = tryRequire( resolve( __dirname, './../lib/native.js' ) ); -var opts = { - 'skip': ( logpmf instanceof Error ) -}; +var logpmf = require( './../src/main.c' ); // FIXTURES // var data = require( './fixtures/julia/data.json' ); -var i; - -for ( i = 0; i < data.expected.length; i++ ) { - if ( data.expected[ i ] === null ) { - data.expected[ i ] = NINF; - } -} // TESTS // -tape( 'main export is a function', opts, function test( t ) { +tape( 'main export is a function', function test( t ) { t.ok( true, __filename ); t.strictEqual( typeof logpmf, 'function', 'main export is a function' ); t.end(); }); -tape( 'if provided `NaN` for input value `x`, the function returns `NaN`', opts, function test( t ) { - var y = logpmf( NaN, 10, 9, 5 ); - t.equal( isnan( y ), true, 'returns expected value' ); - t.end(); -}); +tape( 'the function returns `NaN` if provided a `NaN`', function test( t ) { + var y; + + y = logpmf( NaN, 10, 5, 2 ); + t.equal( isnan( y ), true, 'returns NaN' ); -tape( 'if provided an integer `x` greater than `min( n, K )`, the function returns `-Infinity` (provided all parameters are valid)', opts, function test( t ) { - var y = logpmf( 11, 20, 20, 10 ); - t.equal( y, NINF, 'returns expected value' ); + y = logpmf( 0.0, NaN, 5, 2 ); + t.equal( isnan( y ), true, 'returns NaN' ); - y = logpmf( 100, 20, 20, 10 ); - t.equal( y, NINF, 'returns -Infinity' ); + y = logpmf( 0.0, 10, NaN, 2 ); + t.equal( isnan( y ), true, 'returns NaN' ); + + y = logpmf( 0.0, 10, 5, NaN ); + t.equal( isnan( y ), true, 'returns NaN' ); t.end(); }); -tape( 'if provided an integer for `x` smaller than `max( 0, n + K - N )`, the function returns `-Infinity`', opts, function test( t ) { - var y = logpmf( -1.0, 40, 20, 10 ); - t.equal( y, NINF, 'returns expected value' ); +tape( 'the function returns `-Infinity` if provided a population size `N` which is not a positive integer', function test( t ) { + var y; + + y = logpmf( 2.0, 0, 5, 2 ); + t.equal( y, Number.NEGATIVE_INFINITY, 'returns -Infinity' ); - y = logpmf( -2.0, 30, 20, 20 ); - t.equal( y, NINF, 'returns expected value' ); + y = logpmf( 2.0, -10, 5, 2 ); + t.equal( y, Number.NEGATIVE_INFINITY, 'returns -Infinity' ); t.end(); }); -tape( 'if provided an `N` which is not a nonnegative integer, the function returns `NaN`', opts, function test( t ) { +tape( 'the function returns `-Infinity` if provided a subpopulation size `K` which is not a nonnegative integer less than or equal to `N`', function test( t ) { var y; - y = logpmf( 2.0, -2, 20, 10 ); - t.equal( isnan( y ), true, 'returns expected value' ); + y = logpmf( 2.0, 10, -1, 2 ); + t.equal( y, Number.NEGATIVE_INFINITY, 'returns -Infinity' ); - y = logpmf( 2.0, -1, 20, 10 ); - t.equal( isnan( y ), true, 'returns expected value' ); + y = logpmf( 2.0, 10, 20, 2 ); + t.equal( y, Number.NEGATIVE_INFINITY, 'returns -Infinity' ); t.end(); }); -tape( 'if provided a `K` which is not a nonnegative integer, the function returns `NaN`', opts, function test( t ) { +tape( 'the function returns `-Infinity` if provided a number of draws `n` which is not a nonnegative integer less than or equal to `N`', function test( t ) { var y; - y = logpmf( 2.0, 20, -2, 10 ); - t.equal( isnan( y ), true, 'returns expected value' ); + y = logpmf( 2.0, 10, 5, -1 ); + t.equal( y, Number.NEGATIVE_INFINITY, 'returns -Infinity' ); - y = logpmf( 2.0, 20, -1, 10 ); - t.equal( isnan( y ), true, 'returns expected value' ); + y = logpmf( 2.0, 10, 5, 20 ); + t.equal( y, Number.NEGATIVE_INFINITY, 'returns -Infinity' ); t.end(); }); -tape( 'if provided an `n` which is not a nonnegative integer, the function returns `NaN`', opts, function test( t ) { +tape( 'the function returns `-Infinity` if provided an `x` which is not a nonnegative integer less than or equal to `min(n,K)`', function test( t ) { var y; - y = logpmf( 2.0, 40, 20, -2 ); - t.equal( isnan( y ), true, 'returns expected value' ); + y = logpmf( -1.0, 10, 5, 2 ); + t.equal( y, Number.NEGATIVE_INFINITY, 'returns -Infinity' ); - y = logpmf( 2.0, 40, 20, -1 ); - t.equal( isnan( y ), true, 'returns expected value' ); + y = logpmf( 3.0, 10, 5, 2 ); + t.equal( y, Number.NEGATIVE_INFINITY, 'returns -Infinity' ); t.end(); }); -tape( 'the function evaluates the logpmf for `x`', opts, function test( t ) { +tape( 'the function returns expected value', function test( t ) { var expected; var delta; var tol; @@ -138,11 +123,11 @@ tape( 'the function evaluates the logpmf for `x`', opts, function test( t ) { for ( i = 0; i < x.length; i++ ) { y = logpmf( x[i], N[i], K[i], n[i] ); if ( y === expected[i] ) { - t.equal( y, expected[i], 'x: '+x[i]+', N: '+N[i]+', K: '+K[i]+', n: '+n[i]+', y: '+y+', expected: '+expected[i] ); + t.equal( y, expected[i], 'x: '+x[i]+'. N: '+N[i]+'. K: '+K[i]+'. n: '+n[i]+'. y: '+y+'. expected: '+expected[i]+'.' ); } else { - delta = abs( y - expected[ i ] ); - tol = 3600.0 * EPS * abs( expected[ i ] ); - t.ok( delta <= tol, 'within tolerance. x: '+x[i]+'. N: '+N[i]+'. K: '+K[i]+'. n: '+n[i]+'. y: '+y+'. E: '+expected[ i ]+'. Δ: '+delta+'. tol: '+tol+'.' ); + delta = Math.abs( y - expected[i] ); + tol = 1.0e-12 * Math.abs( expected[i] ); + t.ok( delta <= tol, 'within tolerance. x: '+x[i]+'. N: '+N[i]+'. K: '+K[i]+'. n: '+n[i]+'. y: '+y+'. E: '+expected[i]+'. Δ: '+delta+'. tol: '+tol+'.' ); } } t.end();