Skip to content

Commit 8daa9ee

Browse files
committed
feat: add the JS native files
1 parent 6e8eb2d commit 8daa9ee

File tree

3 files changed

+245
-0
lines changed

3 files changed

+245
-0
lines changed
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
/**
2+
* @license Apache-2.0
3+
*
4+
* Copyright (c) 2025 The Stdlib Authors.
5+
*
6+
* Licensed under the Apache License, Version 2.0 (the "License");
7+
* you may not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing, software
13+
* distributed under the License is distributed on an "AS IS" BASIS,
14+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
* See the License for the specific language governing permissions and
16+
* limitations under the License.
17+
*/
18+
19+
'use strict';
20+
21+
// MODULES //
22+
23+
var resolve = require( 'path' ).resolve;
24+
var bench = require( '@stdlib/bench' );
25+
var Float64Array = require( '@stdlib/array/float64' );
26+
var randu = require( '@stdlib/random/base/randu' );
27+
var isnan = require( '@stdlib/math/base/assert/is-nan' );
28+
var tryRequire = require( '@stdlib/utils/try-require' );
29+
var round = require( '@stdlib/math/base/special/round' );
30+
var pkg = require( './../package.json' ).name;
31+
32+
33+
// VARIABLES //
34+
35+
var pmf = tryRequire( resolve( __dirname, './../lib/native.js' ) );
36+
var opts = {
37+
'skip': ( pmf instanceof Error )
38+
};
39+
40+
41+
// MAIN //
42+
43+
bench( pkg+'::native', opts, function benchmark( b ) {
44+
var len;
45+
var N;
46+
var K;
47+
var n;
48+
var x;
49+
var y;
50+
var i;
51+
52+
len = 100;
53+
N = new Float64Array( len );
54+
K = new Float64Array( len );
55+
n = new Float64Array( len );
56+
x = new Float64Array( len );
57+
for ( i = 0; i < len; i++ ) {
58+
N[ i ] = round( ( randu() * 90.0 ) + 10.0 );
59+
K[ i ] = round( randu() * N[ i ] );
60+
n[ i ] = round( randu() * N[ i ] );
61+
x[ i ] = round( randu() * n[ i ] );
62+
}
63+
64+
b.tic();
65+
for ( i = 0; i < b.iterations; i++ ) {
66+
y = pmf( x[ i % len ], N[ i % len ], K[ i % len ], n[ i % len ] );
67+
if ( isnan( y ) ) {
68+
b.fail( 'should not return NaN' );
69+
}
70+
}
71+
b.toc();
72+
if ( isnan( y ) ) {
73+
b.fail( 'should not return NaN' );
74+
}
75+
b.pass( 'benchmark finished' );
76+
b.end();
77+
});
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
/**
2+
* @license Apache-2.0
3+
*
4+
* Copyright (c) 2025 The Stdlib Authors.
5+
*
6+
* Licensed under the Apache License, Version 2.0 (the "License");
7+
* you may not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing, software
13+
* distributed under the License is distributed on an "AS IS\" BASIS,
14+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
* See the License for the specific language governing permissions and
16+
* limitations under the License.
17+
*/
18+
19+
'use strict';
20+
21+
// MODULES //
22+
23+
var addon = require( './../src/addon.node' );
24+
25+
26+
// MAIN //
27+
28+
/**
29+
* Evaluates the probability mass function (PMF) for a hypergeometric distribution.
30+
*
31+
* @private
32+
* @param {number} x - number of successes
33+
* @param {number} N - population size
34+
* @param {number} K - subpopulation size
35+
* @param {number} n - number of draws
36+
* @returns {number} evaluated PMF
37+
*
38+
* @example
39+
* var p = pmf( 2, 10, 5, 4 );
40+
* // returns ~0.238
41+
*/
42+
function pmf( x, N, K, n ) {
43+
return addon( x, N, K, n );
44+
}
45+
46+
47+
// EXPORTS //
48+
49+
module.exports = pmf;
Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
/**
2+
* @license Apache-2.0
3+
*
4+
* Copyright (c) 2025 The Stdlib Authors.
5+
*
6+
* Licensed under the Apache License, Version 2.0 (the "License");
7+
* you may not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing, software
13+
* distributed under the License is distributed on an "AS IS" BASIS,
14+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
* See the License for the specific language governing permissions and
16+
* limitations under the License.
17+
*/
18+
19+
'use strict';
20+
21+
// MODULES //
22+
23+
var resolve = require( 'path' ).resolve;
24+
var tape = require( 'tape' );
25+
var tryRequire = require( '@stdlib/utils/try-require' );
26+
var isnan = require( '@stdlib/math/base/assert/is-nan' );
27+
var abs = require( '@stdlib/math/base/special/abs' );
28+
29+
30+
// VARIABLES //
31+
32+
var pmf = tryRequire(resolve(__dirname, './../lib/native.js'));
33+
var opts = {
34+
'skip': (pmf instanceof Error)
35+
};
36+
37+
38+
// TESTS //
39+
40+
tape('main export is a function', opts, function test(t) {
41+
t.ok(true, __filename);
42+
t.strictEqual(typeof pmf, 'function', 'main export is a function');
43+
t.end();
44+
});
45+
46+
tape('if provided `NaN` for any parameter, the function returns `NaN`', opts, function test(t) {
47+
var v;
48+
49+
v = pmf(NaN, 10, 5, 2);
50+
t.equal(isnan(v), true, 'returns NaN');
51+
52+
v = pmf(2, NaN, 5, 2);
53+
t.equal(isnan(v), true, 'returns NaN');
54+
55+
v = pmf(2, 10, NaN, 2);
56+
t.equal(isnan(v), true, 'returns NaN');
57+
58+
v = pmf(2, 10, 5, NaN);
59+
t.equal(isnan(v), true, 'returns NaN');
60+
61+
t.end();
62+
});
63+
64+
tape('if provided invalid inputs, the function returns `NaN`', opts, function test(t) {
65+
var v;
66+
67+
v = pmf(2, -10, 5, 2);
68+
t.equal(isnan(v), true, 'returns NaN');
69+
70+
v = pmf(2, 10.5, 5, 2);
71+
t.equal(isnan(v), true, 'returns NaN');
72+
73+
v = pmf(2, 10, -5, 2);
74+
t.equal(isnan(v), true, 'returns NaN');
75+
76+
v = pmf(2, 10, 5.5, 2);
77+
t.equal(isnan(v), true, 'returns NaN');
78+
79+
v = pmf(2, 10, 5, -2);
80+
t.equal(isnan(v), true, 'returns NaN');
81+
82+
v = pmf(2, 10, 5, 2.5);
83+
t.equal(isnan(v), true, 'returns NaN');
84+
85+
t.end();
86+
});
87+
88+
tape('the function evaluates the PMF for a hypergeometric distribution', opts, function test(t) {
89+
var testCases = [{
90+
'x': 1.0,
91+
'N': 8,
92+
'K': 4,
93+
'n': 2,
94+
'expected': 0.571
95+
},
96+
{
97+
'x': 2.0,
98+
'N': 8,
99+
'K': 4,
100+
'n': 2,
101+
'expected': 0.214
102+
},
103+
{
104+
'x': 0.0,
105+
'N': 8,
106+
'K': 4,
107+
'n': 2,
108+
'expected': 0.214
109+
}];
110+
var tol = 1e-3;
111+
112+
testCases.forEach(function evaluateTestCase(testCase) {
113+
var computedPMF = pmf(testCase.x, testCase.N, testCase.K, testCase.n);
114+
var delta = abs(computedPMF - testCase.expected);
115+
t.ok(delta <= tol, 'within tolerance. x: ' + testCase.x + ', N: ' + testCase.N + ', K: ' + testCase.K + ', n: ' + testCase.n + ', y: ' + computedPMF + ', expected: ' + testCase.expected + ', Δ: ' + delta + ', tol: ' + tol);
116+
});
117+
118+
t.end();
119+
});

0 commit comments

Comments
 (0)