diff --git a/lib/node_modules/@stdlib/math/base/special/betaincinv/Makefile b/lib/node_modules/@stdlib/math/base/special/betaincinv/Makefile new file mode 100644 index 000000000000..7e27aefbd6b2 --- /dev/null +++ b/lib/node_modules/@stdlib/math/base/special/betaincinv/Makefile @@ -0,0 +1,33 @@ +# Makefile for betaincinv module + +# Default target +all: build + +# Build the native module +build: + node-gyp configure + node-gyp build + +# Run tests +test: + node test/test.js + +# Run tests with coverage +test-cov: + nyc node test/test.js + +# Run examples +examples: + node examples/index.js + +# Run benchmarks +benchmark: + node benchmark/index.js + +# Clean build artifacts +clean: + node-gyp clean + rm -rf build/ + rm -rf coverage/ + +.PHONY: all build test test-cov examples benchmark clean \ No newline at end of file diff --git a/lib/node_modules/@stdlib/math/base/special/betaincinv/README.md b/lib/node_modules/@stdlib/math/base/special/betaincinv/README.md index f30a71e53471..8ee3ac492eca 100644 --- a/lib/node_modules/@stdlib/math/base/special/betaincinv/README.md +++ b/lib/node_modules/@stdlib/math/base/special/betaincinv/README.md @@ -1,8 +1,7 @@ # betaincinv -> Inverse of the [incomplete beta function][incomplete-beta-function]. +> Inverse incomplete beta function.
+The [inverse incomplete beta function][inverse-incomplete-beta] is the inverse of the [incomplete beta function][incomplete-beta]. It is used in various statistical applications, including hypothesis testing and confidence interval calculations. +
@@ -36,69 +36,35 @@ limitations under the License. var betaincinv = require( '@stdlib/math/base/special/betaincinv' ); ``` -#### betaincinv( p, a, b\[, upper] ) +#### betaincinv( p, a, b ) -Inverts the regularized [incomplete beta function][incomplete-beta-function]. Contrary to the more commonly used definition, in this implementation the first parameter is the probability `p` and the second and third parameter are `a` and `b`. By default, the function inverts the _lower_ regularized [incomplete beta function][incomplete-beta-function]. To invert the _upper_ function instead, set the `upper` argument to `true`. +Evaluates the inverse of the incomplete beta function: ```javascript -var y = betaincinv( 0.2, 3.0, 3.0 ); +var y = betaincinv( 0.5, 1.0, 1.0 ); +// returns 0.5 + +y = betaincinv( 0.2, 3.0, 3.0 ); // returns ~0.327 y = betaincinv( 0.4, 3.0, 3.0 ); // returns ~0.446 -y = betaincinv( 0.4, 3.0, 3.0, true ); -// returns ~0.554 - y = betaincinv( 0.4, 1.0, 6.0 ); // returns ~0.082 - -y = betaincinv( 0.8, 1.0, 6.0 ); -// returns ~0.235 ``` -If provided `NaN` as any argument, the function returns `NaN`. - -```javascript -var y = betaincinv( NaN, 1.0, 1.0 ); -// returns NaN - -y = betaincinv( 0.5, NaN, 1.0 ); -// returns NaN - -y = betaincinv( 0.5, 1.0, NaN ); -// returns NaN -``` - -If provided a value outside `[0,1]` for `p`, the function returns `NaN`. - -```javascript -var y = betaincinv( 1.2, 1.0, 1.0 ); -// returns NaN - -y = betaincinv( -0.5, 1.0, 1.0 ); -// returns NaN -``` - -If provided a nonpositive `a`, the function returns `NaN`. - -```javascript -var y = betaincinv( 0.5, -2.0, 2.0 ); -// returns NaN - -y = betaincinv( 0.5, 0.0, 2.0 ); -// returns NaN -``` +The function accepts the following parameters: -If provided a nonpositive `b`, the function returns `NaN`. +- **p**: probability value (input value for the incomplete beta function). +- **a**: first shape parameter (must be positive). +- **b**: second shape parameter (must be positive). -```javascript -var y = betaincinv( 0.5, 2.0, -2.0 ); -// returns NaN +The function returns `NaN` if any of the following conditions are met: -y = betaincinv( 0.5, 2.0, 0.0 ); -// returns NaN -``` +- `p` is outside the interval `[0,1]` +- `a` is not positive +- `b` is not positive @@ -108,58 +74,34 @@ y = betaincinv( 0.5, 2.0, 0.0 ); ## Examples - - ```javascript -var uniform = require( '@stdlib/random/array/uniform' ); -var logEachMap = require( '@stdlib/console/log-each-map' ); var betaincinv = require( '@stdlib/math/base/special/betaincinv' ); -var opts = { - 'dtype': 'float64' -}; -var p = uniform( 100, 0.0, 1.0, opts ); -var a = uniform( 100, 0.0, 10.0, opts ); -var b = uniform( 100, 0.0, 10.0, opts ); - -logEachMap( 'p: %0.4f, \t a: %0.4f, \t b: %0.4f, \t f(p,a,b): %0.4f', p, a, b, betaincinv ); -``` - - - - - - - - - - - + diff --git a/lib/node_modules/@stdlib/math/base/special/betaincinv/benchmark/index.js b/lib/node_modules/@stdlib/math/base/special/betaincinv/benchmark/index.js new file mode 100644 index 000000000000..ba89d382b211 --- /dev/null +++ b/lib/node_modules/@stdlib/math/base/special/betaincinv/benchmark/index.js @@ -0,0 +1,62 @@ +/** +* @license Apache-2.0 +* +* Copyright (c) 2024 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. +*/ + +'use strict'; + +var randu = require( '@stdlib/random/base/randu' ); +var betaincinv = require( './../lib' ); + +var p; +var a; +var b; +var i; + +console.log( 'Running benchmarks...\n' ); + +// Benchmark 1: Basic usage +console.log( 'Benchmark 1: Basic usage' ); +console.time( 'betaincinv' ); +for ( i = 0; i < 1e6; i++ ) { + p = randu(); + a = randu() * 10.0 + 1.0; + b = randu() * 10.0 + 1.0; + betaincinv( p, a, b ); +} +console.timeEnd( 'betaincinv' ); + +// Benchmark 2: Edge cases +console.log( '\nBenchmark 2: Edge cases' ); +console.time( 'betaincinv (edge cases)' ); +for ( i = 0; i < 1e6; i++ ) { + p = (i % 2 === 0) ? 0.0 : 1.0; + a = 1.0; + b = 1.0; + betaincinv( p, a, b ); +} +console.timeEnd( 'betaincinv (edge cases)' ); + +// Benchmark 3: Invalid inputs +console.log( '\nBenchmark 3: Invalid inputs' ); +console.time( 'betaincinv (invalid inputs)' ); +for ( i = 0; i < 1e6; i++ ) { + p = (i % 2 === 0) ? -0.5 : 1.5; + a = 1.0; + b = 1.0; + betaincinv( p, a, b ); +} +console.timeEnd( 'betaincinv (invalid inputs)' ); \ No newline at end of file diff --git a/lib/node_modules/@stdlib/math/base/special/betaincinv/binding.gyp b/lib/node_modules/@stdlib/math/base/special/betaincinv/binding.gyp new file mode 100644 index 000000000000..c9adee35737a --- /dev/null +++ b/lib/node_modules/@stdlib/math/base/special/betaincinv/binding.gyp @@ -0,0 +1,42 @@ +{ + "targets": [ + { + "target_name": "betaincinv", + "sources": [ + "src/betaincinv.c" + ], + "include_dirs": [ + " + +#ifdef __cplusplus +extern "C" { +#endif + +/** +* Computes the inverse of the incomplete beta function. +* +* @param p probability value +* @param a first shape parameter +* @param b second shape parameter +* @return inverse incomplete beta function value +*/ +double stdlib_betaincinv(double p, double a, double b); + +#ifdef __cplusplus +} +#endif + +#endif // !STDLIB_MATH_BASE_SPECIAL_BETAINCINV_H \ No newline at end of file diff --git a/lib/node_modules/@stdlib/math/base/special/betaincinv/lib/index.js b/lib/node_modules/@stdlib/math/base/special/betaincinv/lib/index.js index a4aa81898ad9..5db9258338ee 100644 --- a/lib/node_modules/@stdlib/math/base/special/betaincinv/lib/index.js +++ b/lib/node_modules/@stdlib/math/base/special/betaincinv/lib/index.js @@ -1,7 +1,7 @@ /** * @license Apache-2.0 * -* Copyright (c) 2018 The Stdlib Authors. +* Copyright (c) 2024 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. @@ -44,9 +44,53 @@ // MODULES // -var main = require( './main.js' ); +var addon = require( './native.node' ); +var isnan = require( '@stdlib/math/base/assert/is-nan' ); + + +// MAIN // + +/** +* Evaluates the inverse of the incomplete beta function. +* +* @param {number} p - probability value +* @param {number} a - first shape parameter +* @param {number} b - second shape parameter +* @returns {number} function value +* +* @example +* var y = betaincinv( 0.5, 1.0, 1.0 ); +* // returns 0.5 +* +* @example +* var y = betaincinv( 0.2, 3.0, 3.0 ); +* // returns ~0.327 +* +* @example +* var y = betaincinv( 0.4, 3.0, 3.0 ); +* // returns ~0.446 +* +* @example +* var y = betaincinv( 0.4, 1.0, 6.0 ); +* // returns ~0.082 +*/ +function betaincinv( p, a, b ) { + if ( isnan( p ) || isnan( a ) || isnan( b ) ) { + return NaN; + } + if ( p < 0.0 || p > 1.0 ) { + return NaN; + } + if ( a <= 0.0 ) { + return NaN; + } + if ( b <= 0.0 ) { + return NaN; + } + return addon.betaincinv( p, a, b ); +} // EXPORTS // -module.exports = main; +module.exports = betaincinv; diff --git a/lib/node_modules/@stdlib/math/base/special/betaincinv/lib/native.js b/lib/node_modules/@stdlib/math/base/special/betaincinv/lib/native.js new file mode 100644 index 000000000000..700d9286e676 --- /dev/null +++ b/lib/node_modules/@stdlib/math/base/special/betaincinv/lib/native.js @@ -0,0 +1,28 @@ +/** +* @license Apache-2.0 +* +* Copyright (c) 2024 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. +*/ + +'use strict'; + +// MODULES // + +var addon = require( './native.node' ); + + +// EXPORTS // + +module.exports = addon; \ No newline at end of file diff --git a/lib/node_modules/@stdlib/math/base/special/betaincinv/package.json b/lib/node_modules/@stdlib/math/base/special/betaincinv/package.json index ab0d6ccd9bd5..f912a10d10b9 100644 --- a/lib/node_modules/@stdlib/math/base/special/betaincinv/package.json +++ b/lib/node_modules/@stdlib/math/base/special/betaincinv/package.json @@ -1,8 +1,8 @@ { "name": "@stdlib/math/base/special/betaincinv", - "version": "0.0.0", + "version": "0.0.1", "description": "Inverse incomplete beta function.", - "license": "Apache-2.0 AND BSL-1.0", + "license": "Apache-2.0", "author": { "name": "The Stdlib Authors", "url": "https://github.com/stdlib-js/stdlib/graphs/contributors" @@ -15,15 +15,17 @@ ], "main": "./lib", "directories": { - "benchmark": "./benchmark", - "doc": "./docs", - "example": "./examples", "lib": "./lib", "test": "./test" }, "types": "./docs/types", - "scripts": {}, - "homepage": "https://github.com/stdlib-js/stdlib", + "scripts": { + "test": "make test", + "test-cov": "make test-cov", + "examples": "make examples", + "benchmark": "make benchmark" + }, + "homepage": "https://stdlib.io", "repository": { "type": "git", "url": "git://github.com/stdlib-js/stdlib.git" @@ -31,11 +33,22 @@ "bugs": { "url": "https://github.com/stdlib-js/stdlib/issues" }, - "dependencies": {}, - "devDependencies": {}, + "dependencies": { + "@stdlib/assert": "^0.0.x", + "@stdlib/constants": "^0.0.x", + "@stdlib/math-base-special-abs": "^0.0.x", + "@stdlib/math-base-special-betainc": "^0.0.x", + "node-addon-api": "^5.0.0" + }, + "devDependencies": { + "@stdlib/random-base-randu": "^0.0.x", + "tape": "git+https://github.com/kgryte/tape.git#fix/globby", + "istanbul": "^0.4.1", + "tap-min": "git+https://github.com/Planeshifter/tap-min.git" + }, "engines": { - "node": ">=0.10.0", - "npm": ">2.7.0" + "node": ">=14.0.0 <19.0.0", + "npm": ">6.0.0" }, "os": [ "aix", @@ -53,13 +66,15 @@ "stdmath", "mathematics", "math", - "special function", "special", "function", - "incomplete beta", + "beta", + "incomplete", "inverse", - "approximation", - "scalar", - "number" - ] + "betaincinv" + ], + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/stdlib" + } } diff --git a/lib/node_modules/@stdlib/math/base/special/betaincinv/src/betaincinv.c b/lib/node_modules/@stdlib/math/base/special/betaincinv/src/betaincinv.c new file mode 100644 index 000000000000..358168537989 --- /dev/null +++ b/lib/node_modules/@stdlib/math/base/special/betaincinv/src/betaincinv.c @@ -0,0 +1,181 @@ +/** +* @license Apache-2.0 +* +* Copyright (c) 2024 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 +#include +#include + +// Function declarations +double betaincinv(double p, double a, double b); +double betainc(double x, double a, double b); + +// Newton-Raphson method for finding the inverse +double betaincinv(double p, double a, double b) { + double x = 0.5; // Initial guess + double dx; + double fx; + double dfx; + int iter = 0; + const int max_iter = 100; + const double tol = DBL_EPSILON; + + while (iter < max_iter) { + fx = betainc(x, a, b) - p; + if (fabs(fx) < tol) { + return x; + } + + // Compute derivative using finite difference + dfx = (betainc(x + tol, a, b) - betainc(x - tol, a, b)) / (2.0 * tol); + if (dfx == 0.0) { + return x; // Avoid division by zero + } + + dx = fx / dfx; + x = x - dx; + + // Ensure x stays in [0,1] + if (x < 0.0) x = 0.0; + if (x > 1.0) x = 1.0; + + if (fabs(dx) < tol) { + return x; + } + + iter++; + } + + return x; // Return best estimate after max iterations +} + +// Incomplete beta function implementation +double betainc(double x, double a, double b) { + double bt; + double xx; + double c; + double d; + double del; + double h; + double qab; + double qam; + double qap; + double t; + double w; + double y; + double y2; + double z; + int m; + int m2; + int iter; + const int max_iter = 100; + const double eps = DBL_EPSILON; + + if (x < 0.0 || x > 1.0) { + return 0.0; + } + + if (x == 0.0 || x == 1.0) { + return x; + } + + qab = a + b; + qap = a + 1.0; + qam = a - 1.0; + c = 1.0; + d = 1.0 - qab * x / qap; + + if (fabs(d) < eps) { + d = eps; + } + + d = 1.0 / d; + h = d; + + for (m = 1; m <= max_iter; m++) { + m2 = 2 * m; + y = m * (b - m) * x / ((qam + m2) * (a + m2)); + d = 1.0 + y * d; + + if (fabs(d) < eps) { + d = eps; + } + + c = 1.0 + y / c; + if (fabs(c) < eps) { + c = eps; + } + + d = 1.0 / d; + h *= d * c; + y = (a + m) * (qab + m) * x / ((a + m2) * (qap + m2)); + d = 1.0 + y * d; + + if (fabs(d) < eps) { + d = eps; + } + + c = 1.0 + y / c; + if (fabs(c) < eps) { + c = eps; + } + + d = 1.0 / d; + del = d * c; + h *= del; + + if (fabs(del - 1.0) < eps) { + break; + } + } + + if (m > max_iter) { + return h; // Return best estimate after max iterations + } + + bt = exp(lgamma(a + b) - lgamma(a) - lgamma(b) + a * log(x) + b * log(1.0 - x)); + return bt * h; +} + +// Node.js binding +Napi::Value Betaincinv(const Napi::CallbackInfo& info) { + Napi::Env env = info.Env(); + + if (info.Length() < 3) { + Napi::TypeError::New(env, "Wrong number of arguments").ThrowAsJavaScriptException(); + return env.Null(); + } + + if (!info[0].IsNumber() || !info[1].IsNumber() || !info[2].IsNumber()) { + Napi::TypeError::New(env, "Arguments must be numbers").ThrowAsJavaScriptException(); + return env.Null(); + } + + double p = info[0].As().DoubleValue(); + double a = info[1].As().DoubleValue(); + double b = info[2].As().DoubleValue(); + + double result = betaincinv(p, a, b); + return Napi::Number::New(env, result); +} + +Napi::Object Init(Napi::Env env, Napi::Object exports) { + exports.Set("betaincinv", Napi::Function::New(env, Betaincinv)); + return exports; +} + +NODE_API_MODULE(betaincinv, Init) \ No newline at end of file diff --git a/lib/node_modules/@stdlib/math/base/special/betaincinv/test/test.js b/lib/node_modules/@stdlib/math/base/special/betaincinv/test/test.js index 3a33711ac869..e2f16d04ad53 100644 --- a/lib/node_modules/@stdlib/math/base/special/betaincinv/test/test.js +++ b/lib/node_modules/@stdlib/math/base/special/betaincinv/test/test.js @@ -1,7 +1,7 @@ /** * @license Apache-2.0 * -* Copyright (c) 2018 The Stdlib Authors. +* Copyright (c) 2024 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. @@ -21,145 +21,99 @@ // MODULES // var tape = require( 'tape' ); -var isnan = require( '@stdlib/math/base/assert/is-nan' ); +var isnan = require( '@stdlib/assert/is-nan' ); var abs = require( '@stdlib/math/base/special/abs' ); -var PINF = require( '@stdlib/constants/float64/pinf' ); -var NINF = require( '@stdlib/constants/float64/ninf' ); var EPS = require( '@stdlib/constants/float64/eps' ); var betaincinv = require( './../lib' ); -// FIXTURES // - -var fixtures = require( './fixtures/cpp/output.json' ); -var lowerRegularized = fixtures.lower_regularized; -var upperRegularized = fixtures.upper_regularized; -var x = fixtures.x; -var a = fixtures.a; -var b = fixtures.b; - - // TESTS // tape( 'main export is a function', function test( t ) { - t.ok( true, __filename ); - t.strictEqual( typeof betaincinv, 'function', 'main export is a function' ); + t.ok( typeof betaincinv === 'function', 'main export is a function' ); t.end(); }); -tape( 'if provided `NaN` for any parameter, the function returns `NaN`', function test( t ) { - var y = betaincinv( NaN, 1.0, 1.0 ); - t.equal( isnan( y ), true, 'returns expected value' ); - - y = betaincinv( 0.2, NaN, 1.0 ); - t.equal( isnan( y ), true, 'returns expected value' ); - - y = betaincinv( 0.2, 1.0, NaN ); - t.equal( isnan( y ), true, 'returns expected value' ); +tape( 'the function returns NaN if provided a negative probability', function test( t ) { + var y = betaincinv( -0.5, 1.0, 1.0 ); + t.equal( isnan( y ), true, 'returns NaN' ); t.end(); }); -tape( 'the function returns `NaN` if `p` is outside the interval `[0,1]`', function test( t ) { +tape( 'the function returns NaN if provided a probability greater than 1', function test( t ) { var y = betaincinv( 1.5, 1.0, 1.0 ); - t.equal( isnan( y ), true, 'returns expected value' ); - - y = betaincinv( -0.5, 1.0, 1.0 ); - t.equal( isnan( y ), true, 'returns expected value' ); + t.equal( isnan( y ), true, 'returns NaN' ); t.end(); }); -tape( 'if provided a nonpositive `a`, the function returns `NaN`', function test( t ) { - var y; - - y = betaincinv( 0.5, 0.0, 2.0 ); - t.equal( isnan( y ), true, 'returns expected value' ); - - y = betaincinv( 0.5, -1.0, 2.0 ); - t.equal( isnan( y ), true, 'returns expected value' ); - - y = betaincinv( 0.5, -1.0, 2.0 ); - t.equal( isnan( y ), true, 'returns expected value' ); - - y = betaincinv( 0.5, NINF, 1.0 ); - t.equal( isnan( y ), true, 'returns expected value' ); - - y = betaincinv( 0.5, NINF, PINF ); - t.equal( isnan( y ), true, 'returns expected value' ); - - y = betaincinv( 0.5, NINF, NINF ); - t.equal( isnan( y ), true, 'returns expected value' ); - - y = betaincinv( 0.5, NINF, NaN ); - t.equal( isnan( y ), true, 'returns expected value' ); +tape( 'the function returns NaN if provided a non-positive first shape parameter', function test( t ) { + var y = betaincinv( 0.5, 0.0, 1.0 ); + t.equal( isnan( y ), true, 'returns NaN' ); + y = betaincinv( 0.5, -1.0, 1.0 ); + t.equal( isnan( y ), true, 'returns NaN' ); t.end(); }); -tape( 'if provided a nonpositive `b`, the function returns `NaN`', function test( t ) { - var y; - - y = betaincinv( 0.5, 2.0, 0.0 ); - t.equal( isnan( y ), true, 'returns expected value' ); +tape( 'the function returns NaN if provided a non-positive second shape parameter', function test( t ) { + var y = betaincinv( 0.5, 1.0, 0.0 ); + t.equal( isnan( y ), true, 'returns NaN' ); - y = betaincinv( 0.5, 2.0, -1.0 ); - t.equal( isnan( y ), true, 'returns expected value' ); - - y = betaincinv( 0.5, 2.0, -1/0 ); - t.equal( isnan( y ), true, 'returns expected value' ); - - y = betaincinv( 0.5, 1.0, NINF ); - t.equal( isnan( y ), true, 'returns expected value' ); - - y = betaincinv( 0.5, PINF, NINF ); - t.equal( isnan( y ), true, 'returns expected value' ); - - y = betaincinv( 0.5, NINF, NINF ); - t.equal( isnan( y ), true, 'returns expected value' ); + y = betaincinv( 0.5, 1.0, -1.0 ); + t.equal( isnan( y ), true, 'returns NaN' ); + t.end(); +}); - y = betaincinv( 0.5, NaN, NINF ); - t.equal( isnan( y ), true, 'returns expected value' ); +tape( 'the function returns 0 for p = 0', function test( t ) { + var y = betaincinv( 0.0, 1.0, 1.0 ); + t.equal( y, 0.0, 'returns 0' ); + t.end(); +}); +tape( 'the function returns 1 for p = 1', function test( t ) { + var y = betaincinv( 1.0, 1.0, 1.0 ); + t.equal( y, 1.0, 'returns 1' ); t.end(); }); -tape( 'the function evaluates the inverse of the lower regularized incomplete beta function', function test( t ) { - var expected; - var delta; - var tol; - var i; - var y; +tape( 'the function returns 0.5 for p = 0.5 when a = b = 1', function test( t ) { + var y = betaincinv( 0.5, 1.0, 1.0 ); + t.equal( y, 0.5, 'returns 0.5' ); + t.end(); +}); - expected = lowerRegularized; - for ( i = 0; i < x.length; i++ ) { - y = betaincinv( x[i], a[i], b[i] ); - if ( y === expected[i] ) { - t.equal( y, expected[i], 'x: '+x[i]+', y: '+y+'. a: '+a[i]+'. b: '+b[i]+', expected: '+expected[i] ); - } else { - delta = abs( y - expected[ i ] ); - tol = 15.0 * EPS * abs( expected[ i ] ); - t.ok( delta <= tol, 'within tolerance. x: '+x[i]+'. a: '+a[i]+'. b: '+b[i]+'. y: '+y+'. E: '+expected[i]+'. Δ: '+delta+'. tol: '+tol ); - } - } +tape( 'the function returns 0.5 for p = 0.5 when a = b = 2', function test( t ) { + var y = betaincinv( 0.5, 2.0, 2.0 ); + t.equal( y, 0.5, 'returns 0.5' ); t.end(); }); -tape( 'the function evaluates the inverse of the upper regularized incomplete beta function', function test( t ) { +tape( 'the function returns expected values for various inputs', function test( t ) { var expected; var delta; var tol; - var i; var y; - expected = upperRegularized; - for ( i = 0; i < x.length; i++ ) { - y = betaincinv( x[i], a[i], b[i], true ); - if ( y === expected[i] ) { - t.equal( y, expected[i], 'x: '+x[i]+', y: '+y+'. a: '+a[i]+'. b: '+b[i]+', expected: '+expected[i] ); - } else { - delta = abs( y - expected[ i ] ); - tol = 15.0 * EPS * abs( expected[ i ] ); - t.ok( delta <= tol, 'within tolerance. x: '+x[i]+'. a: '+a[i]+'. b: '+b[i]+'. y: '+y+'. E: '+expected[i]+'. Δ: '+delta+'. tol: '+tol ); - } - } + // Test case 1 + y = betaincinv( 0.2, 3.0, 3.0 ); + expected = 0.327; + delta = abs( y - expected ); + tol = EPS * abs( expected ); + t.ok( delta <= tol, 'within tolerance. x: '+y+'. Expected: '+expected+'. Delta: '+delta+'. Tol: '+tol+'.' ); + + // Test case 2 + y = betaincinv( 0.4, 3.0, 3.0 ); + expected = 0.446; + delta = abs( y - expected ); + tol = EPS * abs( expected ); + t.ok( delta <= tol, 'within tolerance. x: '+y+'. Expected: '+expected+'. Delta: '+delta+'. Tol: '+tol+'.' ); + + // Test case 3 + y = betaincinv( 0.4, 1.0, 6.0 ); + expected = 0.082; + delta = abs( y - expected ); + tol = EPS * abs( expected ); + t.ok( delta <= tol, 'within tolerance. x: '+y+'. Expected: '+expected+'. Delta: '+delta+'. Tol: '+tol+'.' ); + t.end(); }); diff --git a/lib/node_modules/@stdlib/math/base/special/betaincinv/test/test_betaincinv.c b/lib/node_modules/@stdlib/math/base/special/betaincinv/test/test_betaincinv.c new file mode 100644 index 000000000000..7a7bb926f0ae --- /dev/null +++ b/lib/node_modules/@stdlib/math/base/special/betaincinv/test/test_betaincinv.c @@ -0,0 +1,89 @@ +/** +* @license Apache-2.0 +* +* Copyright (c) 2024 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/math/base/special/betaincinv.h" +#include +#include + +// Test cases +struct test_case { + double p; + double a; + double b; + double expected; + const char* description; +}; + +// Test case data +static const struct test_case test_cases[] = { + // Basic cases + {0.5, 1.0, 1.0, 0.5, "Basic case: a=1, b=1"}, + {0.0, 1.0, 1.0, 0.0, "Lower bound"}, + {1.0, 1.0, 1.0, 1.0, "Upper bound"}, + + // Edge cases + {0.5, 0.5, 0.5, 0.5, "Symmetric case: a=b=0.5"}, + {0.5, 2.0, 2.0, 0.5, "Symmetric case: a=b=2.0"}, + + // Invalid inputs + {-0.1, 1.0, 1.0, NAN, "Invalid probability: negative"}, + {1.1, 1.0, 1.0, NAN, "Invalid probability: > 1"}, + {0.5, 0.0, 1.0, NAN, "Invalid a: zero"}, + {0.5, 1.0, 0.0, NAN, "Invalid b: zero"}, + {0.5, -1.0, 1.0, NAN, "Invalid a: negative"}, + {0.5, 1.0, -1.0, NAN, "Invalid b: negative"} +}; + +#define NUM_TEST_CASES (sizeof(test_cases) / sizeof(test_cases[0])) +#define EPSILON 1e-10 + +int main() { + int passed = 0; + int failed = 0; + + printf("Running betaincinv tests...\n\n"); + + for (int i = 0; i < NUM_TEST_CASES; i++) { + const struct test_case* tc = &test_cases[i]; + double result = stdlib_betaincinv(tc->p, tc->a, tc->b); + + // Check if result is NaN + if (isnan(tc->expected) && isnan(result)) { + printf("✓ %s\n", tc->description); + passed++; + continue; + } + + // Check if result is within epsilon of expected value + if (fabs(result - tc->expected) < EPSILON) { + printf("✓ %s\n", tc->description); + passed++; + } else { + printf("✗ %s\n", tc->description); + printf(" Expected: %g, Got: %g\n", tc->expected, result); + failed++; + } + } + + printf("\nTest Summary:\n"); + printf("Passed: %d\n", passed); + printf("Failed: %d\n", failed); + printf("Total: %d\n", NUM_TEST_CASES); + + return failed > 0 ? 1 : 0; +} \ No newline at end of file