From 55bc746c2cf34ecda6817e6c06489c9dbb348dd6 Mon Sep 17 00:00:00 2001 From: sagar7162 Date: Tue, 4 Nov 2025 16:44:08 +0000 Subject: [PATCH] feat: add stats/incr/nanmcv --- type: pre_commit_static_analysis_report description: Results of running static analysis checks when committing changes. report: - task: lint_filenames status: passed - task: lint_editorconfig status: passed - task: lint_markdown status: passed - task: lint_package_json status: passed - task: lint_repl_help status: na - task: lint_javascript_src status: passed - task: lint_javascript_cli status: na - task: lint_javascript_examples status: passed - task: lint_javascript_tests status: passed - task: lint_javascript_benchmarks status: passed - task: lint_python status: na - task: lint_r status: na - task: lint_c_src status: na - task: lint_c_examples status: na - task: lint_c_benchmarks status: na - task: lint_c_tests_fixtures status: na - task: lint_shell status: na - task: lint_typescript_declarations status: passed - task: lint_typescript_tests status: passed - task: lint_license_headers status: passed --- --- .../@stdlib/stats/incr/nanmcv/README.md | 233 ++++++++ .../stats/incr/nanmcv/benchmark/benchmark.js | 97 +++ .../docs/img/equation_arithmetic_mean.svg | 43 ++ .../img/equation_coefficient_of_variation.svg | 26 + ...on_corrected_sample_standard_deviation.svg | 73 +++ .../stats/incr/nanmcv/docs/types/index.d.ts | 84 +++ .../stats/incr/nanmcv/docs/types/test.ts | 67 +++ .../stats/incr/nanmcv/examples/index.js | 41 ++ .../@stdlib/stats/incr/nanmcv/lib/index.js | 57 ++ .../@stdlib/stats/incr/nanmcv/lib/main.js | 91 +++ .../@stdlib/stats/incr/nanmcv/package.json | 79 +++ .../@stdlib/stats/incr/nanmcv/test/test.js | 564 ++++++++++++++++++ 12 files changed, 1455 insertions(+) create mode 100644 lib/node_modules/@stdlib/stats/incr/nanmcv/README.md create mode 100644 lib/node_modules/@stdlib/stats/incr/nanmcv/benchmark/benchmark.js create mode 100644 lib/node_modules/@stdlib/stats/incr/nanmcv/docs/img/equation_arithmetic_mean.svg create mode 100644 lib/node_modules/@stdlib/stats/incr/nanmcv/docs/img/equation_coefficient_of_variation.svg create mode 100644 lib/node_modules/@stdlib/stats/incr/nanmcv/docs/img/equation_corrected_sample_standard_deviation.svg create mode 100644 lib/node_modules/@stdlib/stats/incr/nanmcv/docs/types/index.d.ts create mode 100644 lib/node_modules/@stdlib/stats/incr/nanmcv/docs/types/test.ts create mode 100644 lib/node_modules/@stdlib/stats/incr/nanmcv/examples/index.js create mode 100644 lib/node_modules/@stdlib/stats/incr/nanmcv/lib/index.js create mode 100644 lib/node_modules/@stdlib/stats/incr/nanmcv/lib/main.js create mode 100644 lib/node_modules/@stdlib/stats/incr/nanmcv/package.json create mode 100644 lib/node_modules/@stdlib/stats/incr/nanmcv/test/test.js diff --git a/lib/node_modules/@stdlib/stats/incr/nanmcv/README.md b/lib/node_modules/@stdlib/stats/incr/nanmcv/README.md new file mode 100644 index 000000000000..55b1582d2863 --- /dev/null +++ b/lib/node_modules/@stdlib/stats/incr/nanmcv/README.md @@ -0,0 +1,233 @@ + + +# incrnanmcv + +> Compute a moving [coefficient of variation][coefficient-of-variation] (CV) incrementally, ignoring `NaN` values. + +
+ +For a window of size `W`, the [corrected sample standard deviation][standard-deviation] is defined as + + + +```math +s = \sqrt{\frac{1}{W-1} \sum_{i=0}^{W-1} ( x_i - \bar{x} )^2} +``` + + + + + +and the [arithmetic mean][arithmetic-mean] is defined as + + + +```math +\bar{x} = \frac{1}{W} \sum_{i=0}^{W-1} x_i +``` + + + + + +The [coefficient of variation][coefficient-of-variation] (also known as **relative standard deviation**, RSD) is defined as + + + +
+ +
+
+ + + +
+ + + +
+ +## Usage + +```javascript +var incrnanmcv = require( '@stdlib/stats/incr/nanmcv' ); +``` + +#### incrnanmcv( window\[, mean] ) + +Returns an accumulator `function` which incrementally computes a moving [coefficient of variation][coefficient-of-variation]. The `window` parameter defines the number of values over which to compute the moving [coefficient of variation][coefficient-of-variation]. + +```javascript +var accumulator = incrnanmcv( 3 ); +``` + +If the mean is already known, provide a `mean` argument. + +```javascript +var accumulator = incrnanmcv( 3, 5.0 ); +``` + +#### accumulator( \[x] ) + +If provided an input value `x`, the accumulator function returns an updated accumulated value. If not provided an input value `x`, the accumulator function returns the current accumulated value. + +```javascript +var incrnanmcv = require( '@stdlib/stats/incr/nanmcv' ); + +// Create an accumulator with a window size of 3: +var accumulator = incrnanmcv( 3 ); + +var cv = accumulator(); +// returns null + +// Fill the window (ignores NaN)... +cv = accumulator( 2.0 ); // [2.0] +// returns 0.0 + +cv = accumulator( NaN ); // still [2.0] +// returns 0.0 (NaN ignored, window unchanged) + +cv = accumulator( 3.0 ); // [2.0, 3.0] +// returns ~0.28 + +cv = accumulator( 1.0 ); // [2.0, 3.0, 1.0] +// returns ~0.50 + +// Window begins sliding only when valid number is added... +cv = accumulator( NaN ); // still [2.0, 3.0, 1.0] +// returns ~0.50 (no change) + +cv = accumulator( 7.0 ); // [3.0, 1.0, 7.0] +// returns ~0.83 + +cv = accumulator( 5.0 ); // [1.0, 7.0, 5.0] +// returns ~0.71 + +cv = accumulator( NaN ); // still [1.0, 7.0, 5.0] +// returns ~0.71 + +cv = accumulator(); +// returns ~0.71 +``` + +
+ + + +
+ +## Notes + +- Input values are not type checked. If provided a `NaN` value, the window remains same and the value is ignored and does not affect the accumulated result. Computations are performed only over valid numeric inputs currently within the moving window. If all window values are `NaN` (or if no valid numeric values have been provided), the accumulated value is `NaN`. If non-numeric inputs are possible, you are advised to type check and handle them accordingly before passing values to the accumulator function. +- As `W` values are needed to fill the window buffer, the first `W-1` returned values are calculated from smaller sample sizes. Until the window is full, each returned value is calculated from all provided values. +- The [coefficient of variation][coefficient-of-variation] is typically computed on nonnegative values. The measure may lack meaning for data which can assume both positive and negative values. +- For small and moderately sized samples, the accumulated value tends to be too low and is thus a **biased** estimator. Provided the generating distribution is known (e.g., a normal distribution), you may want to adjust the accumulated value or use an alternative implementation providing an unbiased estimator. + +
+ + + +
+ +## Examples + + + +```javascript +var randu = require( '@stdlib/random/base/randu' ); +var incrnanmcv = require( '@stdlib/stats/incr/nanmcv' ); + +var accumulator; +var v; +var i; + +// Initialize an accumulator with window size 5: +accumulator = incrnanmcv( 5 ); + +// For each simulated datum, update the moving coefficient of variation... +for ( i = 0; i < 100; i++ ) { + // Introduce NaN values randomly: + if ( randu() < 0.2 ) { + v = NaN; + } else { + v = randu() * 100.0; + } + accumulator( v ); +} +console.log( accumulator() ); +``` + +
+ + + + + + + + + + + + + + diff --git a/lib/node_modules/@stdlib/stats/incr/nanmcv/benchmark/benchmark.js b/lib/node_modules/@stdlib/stats/incr/nanmcv/benchmark/benchmark.js new file mode 100644 index 000000000000..fd484e7888e0 --- /dev/null +++ b/lib/node_modules/@stdlib/stats/incr/nanmcv/benchmark/benchmark.js @@ -0,0 +1,97 @@ +/** +* @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. +*/ + +'use strict'; + +// MODULES // + +var bench = require( '@stdlib/bench' ); +var randu = require( '@stdlib/random/base/randu' ); +var isnan = require( '@stdlib/assert/is-nan' ); +var pkg = require( './../package.json' ).name; +var incrnanmcv = require( './../lib' ); + + +// MAIN // + +bench( pkg, function benchmark( b ) { + var f; + var i; + b.tic(); + for ( i = 0; i < b.iterations; i++ ) { + f = incrnanmcv( (i % 5) + 1 ); + if ( typeof f !== 'function' ) { + b.fail( 'should return a function' ); + } + } + b.toc(); + if ( typeof f !== 'function' ) { + b.fail( 'should return a function' ); + } + b.pass( 'benchmark finished' ); + b.end(); +}); + +bench( pkg+'::accumulator', function benchmark( b ) { + var acc; + var v; + var x; + var i; + + acc = incrnanmcv( 5 ); + + b.tic(); + for ( i = 0; i < b.iterations; i++ ) { + // Randomly introduce NaN values: + x = ( randu() < 0.1 ) ? NaN : randu(); + v = acc( x ); + if ( isnan( v ) ) { + b.fail( 'should not return NaN' ); + } + } + b.toc(); + if ( isnan( v ) ) { + b.fail( 'should not return NaN' ); + } + b.pass( 'benchmark finished' ); + b.end(); +}); + +bench( pkg+'::accumulator,known_mean', function benchmark( b ) { + var acc; + var v; + var x; + var i; + + acc = incrnanmcv( 5, 0.5 ); + + b.tic(); + for ( i = 0; i < b.iterations; i++ ) { + x = ( randu() < 0.1 ) ? NaN : randu(); + v = acc( x ); + if ( isnan( v ) ) { + b.fail( 'should not return NaN' ); + } + } + b.toc(); + if ( isnan( v ) ) { + b.fail( 'should not return NaN' ); + } + b.pass( 'benchmark finished' ); + b.end(); +}); diff --git a/lib/node_modules/@stdlib/stats/incr/nanmcv/docs/img/equation_arithmetic_mean.svg b/lib/node_modules/@stdlib/stats/incr/nanmcv/docs/img/equation_arithmetic_mean.svg new file mode 100644 index 000000000000..1a89a2bfb996 --- /dev/null +++ b/lib/node_modules/@stdlib/stats/incr/nanmcv/docs/img/equation_arithmetic_mean.svg @@ -0,0 +1,43 @@ + +x overbar equals StartFraction 1 Over upper W EndFraction sigma-summation Underscript i equals 0 Overscript upper W minus 1 Endscripts x Subscript i + + + \ No newline at end of file diff --git a/lib/node_modules/@stdlib/stats/incr/nanmcv/docs/img/equation_coefficient_of_variation.svg b/lib/node_modules/@stdlib/stats/incr/nanmcv/docs/img/equation_coefficient_of_variation.svg new file mode 100644 index 000000000000..66781875b998 --- /dev/null +++ b/lib/node_modules/@stdlib/stats/incr/nanmcv/docs/img/equation_coefficient_of_variation.svg @@ -0,0 +1,26 @@ + +c Subscript v Baseline equals StartFraction s Over x overbar EndFraction + + + \ No newline at end of file diff --git a/lib/node_modules/@stdlib/stats/incr/nanmcv/docs/img/equation_corrected_sample_standard_deviation.svg b/lib/node_modules/@stdlib/stats/incr/nanmcv/docs/img/equation_corrected_sample_standard_deviation.svg new file mode 100644 index 000000000000..dfe5a3d60cbb --- /dev/null +++ b/lib/node_modules/@stdlib/stats/incr/nanmcv/docs/img/equation_corrected_sample_standard_deviation.svg @@ -0,0 +1,73 @@ + +s equals StartRoot StartFraction 1 Over upper W minus 1 EndFraction sigma-summation Underscript i equals 0 Overscript upper W minus 1 Endscripts left-parenthesis x Subscript i Baseline minus x overbar right-parenthesis squared EndRoot + + + \ No newline at end of file diff --git a/lib/node_modules/@stdlib/stats/incr/nanmcv/docs/types/index.d.ts b/lib/node_modules/@stdlib/stats/incr/nanmcv/docs/types/index.d.ts new file mode 100644 index 000000000000..6ef0545c63e2 --- /dev/null +++ b/lib/node_modules/@stdlib/stats/incr/nanmcv/docs/types/index.d.ts @@ -0,0 +1,84 @@ +/* +* @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. +*/ + +// TypeScript Version: 4.1 + +/// + +/** +* If provided a value, the accumulator function returns an updated accumulated value. +* If not provided a value, the accumulator function returns the current accumulated value. +* +* ## Notes +* +* - `NaN` values are ignored and do not affect the accumulated value. +* +* @param x - value +* @returns accumulated value or null +*/ +type accumulator = ( x?: number ) => number | null; + +/** +* Returns an accumulator function which incrementally computes a moving coefficient of variation (CV), ignoring `NaN` values. +* +* ## Notes +* +* - The `W` parameter defines the number of values over which to compute the moving coefficient of variation. +* - As `W` values are needed to fill the window buffer, the first `W-1` returned values are calculated from smaller sample sizes. Until the window is full, each returned value is calculated from all provided (non-NaN) values. +* +* @param W - window size +* @param mean - mean value +* @throws first argument must be a positive integer +* @returns accumulator function +* +* @example +* var accumulator = incrnanmcv( 3 ); +* +* var cv = accumulator(); +* // returns null +* +* cv = accumulator( 2.0 ); +* // returns 0.0 +* +* cv = accumulator( NaN ); +* // returns 0.0 (NaN ignored) +* +* cv = accumulator( 1.0 ); +* // returns ~0.47 +* +* cv = accumulator( 3.0 ); +* // returns 0.5 +* +* cv = accumulator( NaN ); +* // returns 0.5 (NaN ignored) +* +* cv = accumulator( 7.0 ); +* // returns ~0.83 +* +* cv = accumulator(); +* // returns ~0.83 +* +* @example +* var accumulator = incrnanmcv( 3, 2.0 ); +*/ +declare function incrnanmcv( W: number, mean?: number ): accumulator; + + +// EXPORTS // + +export = incrnanmcv; diff --git a/lib/node_modules/@stdlib/stats/incr/nanmcv/docs/types/test.ts b/lib/node_modules/@stdlib/stats/incr/nanmcv/docs/types/test.ts new file mode 100644 index 000000000000..132e1f64ffc0 --- /dev/null +++ b/lib/node_modules/@stdlib/stats/incr/nanmcv/docs/types/test.ts @@ -0,0 +1,67 @@ +/* +* @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. +*/ + +import incrnanmcv = require( './index' ); + + +// TESTS // + +// The function returns an accumulator function... +{ + incrnanmcv( 3 ); // $ExpectType accumulator + incrnanmcv( 3, 0.0 ); // $ExpectType accumulator +} + +// The compiler throws an error if the function is provided an argument that is not a number... +{ + incrnanmcv( '5' ); // $ExpectError + incrnanmcv( true ); // $ExpectError + incrnanmcv( false ); // $ExpectError + incrnanmcv( null ); // $ExpectError + incrnanmcv( [] ); // $ExpectError + incrnanmcv( {} ); // $ExpectError + incrnanmcv( ( x: number ): number => x ); // $ExpectError +} + +// The compiler throws an error if the function is provided an invalid number of arguments... +{ + incrnanmcv(); // $ExpectError + incrnanmcv( 2, 3, 1 ); // $ExpectError +} + +// The function returns an accumulator function which returns an accumulated result... +{ + const acc = incrnanmcv( 3 ); + + acc(); // $ExpectType number | null + acc( 3.14 ); // $ExpectType number | null + acc( NaN ); // $ExpectType number | null +} + +// The compiler throws an error if the returned accumulator function is provided invalid arguments... +{ + const acc = incrnanmcv( 3 ); + + acc( '5' ); // $ExpectError + acc( true ); // $ExpectError + acc( false ); // $ExpectError + acc( null ); // $ExpectError + acc( [] ); // $ExpectError + acc( {} ); // $ExpectError + acc( ( x: number ): number => x ); // $ExpectError +} diff --git a/lib/node_modules/@stdlib/stats/incr/nanmcv/examples/index.js b/lib/node_modules/@stdlib/stats/incr/nanmcv/examples/index.js new file mode 100644 index 000000000000..a890849c740e --- /dev/null +++ b/lib/node_modules/@stdlib/stats/incr/nanmcv/examples/index.js @@ -0,0 +1,41 @@ +/** +* @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. +*/ + +'use strict'; + +var randu = require( '@stdlib/random/base/randu' ); +var incrnanmcv = require( './../lib' ); + +var accumulator; +var v; +var i; + +// Initialize an accumulator with window size 5: +accumulator = incrnanmcv( 5 ); + +// For each simulated datum, update the moving coefficient of variation... +for ( i = 0; i < 100; i++ ) { + // Introduce NaN values randomly: + if ( randu() < 0.2 ) { + v = NaN; + } else { + v = randu() * 100.0; + } + accumulator( v ); +} +console.log( accumulator() ); diff --git a/lib/node_modules/@stdlib/stats/incr/nanmcv/lib/index.js b/lib/node_modules/@stdlib/stats/incr/nanmcv/lib/index.js new file mode 100644 index 000000000000..cacee8d9af68 --- /dev/null +++ b/lib/node_modules/@stdlib/stats/incr/nanmcv/lib/index.js @@ -0,0 +1,57 @@ +/** +* @license Apache-2.0 +* +* 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 +* +* 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'; + +/** +* Compute a sum incrementally. +* +* @module @stdlib/stats/incr/nanmcv +* +* @example +* var incrnanmcv = require( '@stdlib/stats/incr/nanmcv' ); +* +* var accumulator = incrnanmcv( 3 ); +* +* var cv = accumulator(); +* // returns null +* +* cv = accumulator( 2.0 ); +* // returns 0.0 +* +* cv = accumulator( NaN ); +* // returns 0.0 +* +* cv = accumulator( 1.0 ); +* // returns ~0.47 +* +* cv = accumulator( 3.0 ); +* // returns 0.5 +* +* cv = accumulator(); +* // returns 0.5 +*/ + +// MODULES // + +var main = require( './main.js' ); + + +// EXPORTS // + +module.exports = main; diff --git a/lib/node_modules/@stdlib/stats/incr/nanmcv/lib/main.js b/lib/node_modules/@stdlib/stats/incr/nanmcv/lib/main.js new file mode 100644 index 000000000000..138e72fbbc76 --- /dev/null +++ b/lib/node_modules/@stdlib/stats/incr/nanmcv/lib/main.js @@ -0,0 +1,91 @@ +/** +* @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. +*/ + +'use strict'; + +// MODULES // + +var isnan = require( '@stdlib/math/base/assert/is-nan' ); +var incrmcv = require( '@stdlib/stats/incr/mcv' ); + + +// MAIN // + +/** +* Returns an accumulator function which incrementally computes a moving coefficient of variation (CV), ignoring `NaN` values. +* +* @param {PositiveInteger} W - window size +* @param {number} [mean] - mean value +* @throws {TypeError} first argument must be a positive integer +* @throws {TypeError} second argument must be a number +* @returns {Function} accumulator function +* +* @example +* var accumulator = incrnanmcv( 3 ); +* +* var cv = accumulator(); +* // returns null +* +* cv = accumulator( 2.0 ); +* // returns 0.0 +* +* cv = accumulator( NaN ); +* // returns 0.0 +* +* cv = accumulator( 1.0 ); +* // returns ~0.47 +* +* cv = accumulator( 3.0 ); +* // returns 0.5 +* +* cv = accumulator(); +* // returns 0.5 +* +* @example +* var accumulator = incrnanmcv( 3, 2.0 ); +*/ +function incrnanmcv( W, mean ) { + var acc; + if ( arguments.length > 1 ) { + acc = incrmcv( W, mean ); + } else { + acc = incrmcv( W ); + } + return accumulator; + + /** + * If provided a value, the accumulator function returns an updated accumulated value. If not provided a value, the accumulator function returns the current accumulated value. + * + * @private + * @param {number} [x] - input value + * @returns {(number|null)} accumulated value or null + */ + function accumulator( x ) { + if ( arguments.length === 0 || isnan( x ) ) { + // If no argument or x is NaN, just return the current accumulated CV: + return acc(); + } + // Otherwise, update the accumulator: + return acc( x ); + } +} + + +// EXPORTS // + +module.exports = incrnanmcv; diff --git a/lib/node_modules/@stdlib/stats/incr/nanmcv/package.json b/lib/node_modules/@stdlib/stats/incr/nanmcv/package.json new file mode 100644 index 000000000000..c52f2f9c726d --- /dev/null +++ b/lib/node_modules/@stdlib/stats/incr/nanmcv/package.json @@ -0,0 +1,79 @@ +{ + "name": "@stdlib/stats/incr/nanmcv", + "version": "0.0.0", + "description": "Compute a moving coefficient of variation (CV) incrementally, ignoring NaN values.", + "license": "Apache-2.0", + "author": { + "name": "The Stdlib Authors", + "url": "https://github.com/stdlib-js/stdlib/graphs/contributors" + }, + "contributors": [ + { + "name": "The Stdlib Authors", + "url": "https://github.com/stdlib-js/stdlib/graphs/contributors" + } + ], + "main": "./lib", + "directories": { + "benchmark": "./benchmark", + "doc": "./docs", + "example": "./examples", + "lib": "./lib", + "test": "./test" + }, + "types": "./docs/types", + "scripts": {}, + "homepage": "https://github.com/stdlib-js/stdlib", + "repository": { + "type": "git", + "url": "git://github.com/stdlib-js/stdlib.git" + }, + "bugs": { + "url": "https://github.com/stdlib-js/stdlib/issues" + }, + "dependencies": {}, + "devDependencies": {}, + "engines": { + "node": ">=0.10.0", + "npm": ">2.7.0" + }, + "os": [ + "aix", + "darwin", + "freebsd", + "linux", + "macos", + "openbsd", + "sunos", + "win32", + "windows" + ], + "keywords": [ + "stdlib", + "stdmath", + "statistics", + "stats", + "mathematics", + "math", + "stdev", + "std", + "variance", + "var", + "standard", + "deviation", + "dispersion", + "relative", + "rsd", + "cv", + "mean", + "ratio", + "incremental", + "accumulator", + "sliding window", + "sliding", + "window", + "moving", + "nan", + "ignore" + ] +} diff --git a/lib/node_modules/@stdlib/stats/incr/nanmcv/test/test.js b/lib/node_modules/@stdlib/stats/incr/nanmcv/test/test.js new file mode 100644 index 000000000000..280d6ad2c228 --- /dev/null +++ b/lib/node_modules/@stdlib/stats/incr/nanmcv/test/test.js @@ -0,0 +1,564 @@ +/** +* @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. +*/ + +'use strict'; + +// MODULES // + +var tape = require( 'tape' ); +var randu = require( '@stdlib/random/base/randu' ); +var abs = require( '@stdlib/math/base/special/abs' ); +var EPS = require( '@stdlib/constants/float64/eps' ); +var sqrt = require( '@stdlib/math/base/special/sqrt' ); +var zeros = require( '@stdlib/array/base/zeros' ); +var incrnanmcv = require( './../lib' ); + + +// TESTS // + +tape( 'main export is a function', function test( t ) { + t.ok( true, __filename ); + t.strictEqual( typeof incrnanmcv, 'function', 'main export is a function' ); + t.end(); +}); + +tape( 'the function throws an error if not provided a positive integer for the window size', function test( t ) { + var values; + var i; + + values = [ + '5', + -5.0, + 0.0, + 3.14, + true, + null, + void 0, + NaN, + [], + {}, + function noop() {} + ]; + + for ( i = 0; i < values.length; i++ ) { + t.throws( badValue( values[i] ), TypeError, 'throws an error when provided '+values[i] ); + } + t.end(); + + function badValue( value ) { + return function badValue() { + incrnanmcv( value ); + }; + } +}); + +tape( 'the function throws an error if not provided a positive integer for the window size (known mean)', function test( t ) { + var values; + var i; + + values = [ + '5', + -5.0, + 0.0, + 3.14, + true, + null, + void 0, + NaN, + [], + {}, + function noop() {} + ]; + + for ( i = 0; i < values.length; i++ ) { + t.throws( badValue( values[i] ), TypeError, 'throws an error when provided '+values[i] ); + } + t.end(); + + function badValue( value ) { + return function badValue() { + incrnanmcv( value, 3.0 ); + }; + } +}); + +tape( 'the function throws an error if not provided a number as the mean value', function test( t ) { + var values; + var i; + + values = [ + '5', + true, + false, + null, + void 0, + [], + {}, + function noop() {} + ]; + + for ( i = 0; i < values.length; i++ ) { + t.throws( badValue( values[i] ), TypeError, 'throws an error when provided '+values[i] ); + } + t.end(); + + function badValue( value ) { + return function badValue() { + incrnanmcv( 3, value ); + }; + } +}); + +tape( 'the function returns an accumulator function', function test( t ) { + t.strictEqual( typeof incrnanmcv( 3 ), 'function', 'returns expected value' ); + t.end(); +}); + +tape( 'the function returns an accumulator function (known mean)', function test( t ) { + t.strictEqual( typeof incrnanmcv( 3, 3.0 ), 'function', 'returns expected value' ); + t.end(); +}); + +tape( 'the accumulator function computes a moving coefficient of variation incrementally', function test( t ) { + var expected; + var actual; + var data; + var acc; + var N; + var i; + + data = [ 2.0, 3.0, 4.0, -1.0, 3.0, 1.0 ]; + N = data.length; + + expected = [ + 0.0/2.0, + sqrt( 0.5 )/2.5, + sqrt( 1.0 )/3.0, + sqrt( 7.0 )/2.0, + sqrt( 7.0 )/2.0, + sqrt( 4.0 )/1.0 + ]; + + acc = incrnanmcv( 3 ); + + actual = zeros( N ); + for ( i = 0; i < N; i++ ) { + actual[ i ] = acc( data[ i ] ); + } + t.deepEqual( actual, expected, 'returns expected results' ); + t.end(); +}); + +tape( 'the accumulator function computes a moving coefficient of variation incrementally (known mean)', function test( t ) { + var expected; + var actual; + var data; + var acc; + var N; + var i; + + data = [ 2.0, 3.0, 4.0, -1.0, 3.0, 1.0 ]; + N = data.length; + + acc = incrnanmcv( 3, 2.0 ); + + actual = zeros( N ); + for ( i = 0; i < N; i++ ) { + actual[ i ] = acc( data[ i ] ); + } + expected = [ + 0.0/2.0, + sqrt( 0.5 )/2.0, + sqrt( 1.6666666666666667 )/2.0, + sqrt( 4.666666666666667 )/2.0, + sqrt( 4.666666666666667 )/2.0, + sqrt( 3.6666666666666665 )/2.0 + ]; + t.deepEqual( actual, expected, 'returns expected results' ); + t.end(); +}); + +tape( 'if not provided an input value, the accumulator function returns the current accumulated value', function test( t ) { + var expected; + var actual; + var delta; + var data; + var tol; + var acc; + var i; + + data = [ 2.0, 3.0, 10.0 ]; + acc = incrnanmcv( 3 ); + for ( i = 0; i < data.length-1; i++ ) { + acc( data[ i ] ); + } + t.strictEqual( acc(), sqrt( 0.5 )/2.5, 'returns expected value' ); + + acc( data[ data.length-1 ] ); + + expected = sqrt( 19.0 )/5.0; + actual = acc(); + delta = abs( actual - expected ); + tol = EPS * expected; + + t.strictEqual( delta < tol, true, 'expected: '+expected+'. actual: '+actual+'. tol: '+tol+'. delta: '+delta+'.' ); + t.end(); +}); + +tape( 'if not provided an input value, the accumulator function returns the current accumulated value (known mean)', function test( t ) { + var expected; + var actual; + var delta; + var data; + var tol; + var acc; + var i; + + data = [ 2.0, 3.0, 10.0 ]; + acc = incrnanmcv( 3, 5.0 ); + for ( i = 0; i < data.length-1; i++ ) { + acc( data[ i ] ); + } + t.strictEqual( acc(), sqrt( 6.5 )/5.0, 'returns expected value' ); + + acc( data[ data.length-1 ] ); + + expected = sqrt( 12.666666666666666 )/5.0; + actual = acc(); + delta = abs( actual - expected ); + tol = EPS * expected; + + t.strictEqual( delta < tol, true, 'expected: '+expected+'. actual: '+actual+'. tol: '+tol+'. delta: '+delta+'.' ); + t.end(); +}); + +tape( 'if data has yet to be provided, the accumulator function returns `null`', function test( t ) { + var acc = incrnanmcv( 3 ); + t.strictEqual( acc(), null, 'returns expected value' ); + t.end(); +}); + +tape( 'if data has yet to be provided, the accumulator function returns `null` (known mean)', function test( t ) { + var acc = incrnanmcv( 3, 3.0 ); + t.strictEqual( acc(), null, 'returns expected value' ); + t.end(); +}); + +tape( 'if only one datum has been provided and the mean is unknown, the accumulator function returns `0`', function test( t ) { + var acc = incrnanmcv( 3 ); + acc( 2.0 ); + t.strictEqual( acc(), 0.0, 'returns expected value' ); + t.end(); +}); + +tape( 'if only one datum has been provided and the mean is known, the accumulator function may not return `0`', function test( t ) { + var acc = incrnanmcv( 3, 30 ); + acc( 2.0 ); + t.notEqual( acc(), 0.0, 'does not return 0' ); + t.end(); +}); + +tape( 'if the window size is `1` and the mean is unknown, the accumulator function always returns `0`', function test( t ) { + var acc; + var cv; + var i; + + acc = incrnanmcv( 1 ); + for ( i = 0; i < 100; i++ ) { + cv = acc( randu() * 100.0 ); + t.strictEqual( cv, 0.0, 'returns expected value' ); + } + t.end(); +}); + +tape( 'if the window size is `1` and the mean is known, the accumulator function may not always return `0`', function test( t ) { + var acc; + var cv; + var i; + + acc = incrnanmcv( 1, 500.0 ); // mean is outside the range of simulated values so the variance should never be zero + for ( i = 0; i < 100; i++ ) { + cv = acc( randu() * 100.0 ); + t.notEqual( cv, 0.0, 'does not return 0' ); + } + t.end(); +}); + +tape( 'if provided `NaN`, the value is ignored (unknown mean)', function test( t ) { + var expected; + var data; + var acc; + var v; + var i; + + acc = incrnanmcv( 3 ); + + data = [ + NaN, + 3.14, + 3.14, + NaN, + 3.14, + 3.14, + 3.14, + NaN, + 3.14, + 3.14, + 3.14, + NaN, + 3.14, + 3.14, + NaN, + NaN, + NaN, + NaN, + 3.14 + ]; + + expected = [ + null, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ]; + + for ( i = 0; i < data.length; i++ ) { + v = acc( data[ i ] ); + if ( expected[ i ] === null ) { + t.strictEqual( v, null, 'returns expected value for window '+i ); + t.strictEqual( acc(), null, 'returns expected value for window '+i ); + } else { + t.strictEqual( v, expected[ i ], 'returns expected value for window '+i ); + t.strictEqual( acc(), expected[ i ], 'returns expected value for window '+i ); + } + } + t.end(); +}); + +tape( 'if provided `NaN`, the value is ignored (known mean)', function test( t ) { + var expected; + var data; + var acc; + var v; + var i; + + acc = incrnanmcv( 3, 3.14 ); + + data = [ + NaN, + 3.14, + 3.14, + NaN, + 3.14, + 3.14, + 3.14, + NaN, + 3.14, + 3.14, + 3.14, + NaN, + 3.14, + 3.14, + NaN, + NaN, + NaN, + NaN, + 3.14 + ]; + + expected = [ + null, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ]; + + for ( i = 0; i < data.length; i++ ) { + v = acc( data[ i ] ); + if ( expected[ i ] === null ) { + t.strictEqual( v, null, 'returns expected value for window '+i ); + t.strictEqual( acc(), null, 'returns expected value for window '+i ); + } else { + t.strictEqual( v, expected[ i ], 'returns expected value for window '+i ); + t.strictEqual( acc(), expected[ i ], 'returns expected value for window '+i ); + } + } + t.end(); +}); + +tape( 'if provided `NaN`, the value is ignored (unknown mean, W=1)', function test( t ) { + var expected; + var data; + var acc; + var v; + var i; + + acc = incrnanmcv( 1 ); + + data = [ + NaN, + 3.14, + 3.14, + NaN, + 3.14, + 3.14, + 3.14, + NaN, + 3.14, + 3.14, + 3.14, + NaN, + 3.14, + 3.14, + NaN, + NaN, + NaN, + NaN, + 3.14 + ]; + + expected = [ + null, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ]; + + for ( i = 0; i < data.length; i++ ) { + v = acc( data[ i ] ); + if ( expected[ i ] === null ) { + t.strictEqual( v, null, 'returns expected value for window '+i ); + t.strictEqual( acc(), null, 'returns expected value for window '+i ); + } else { + t.strictEqual( v, expected[ i ], 'returns expected value for window '+i ); + t.strictEqual( acc(), expected[ i ], 'returns expected value for window '+i ); + } + } + t.end(); +}); + +tape( 'if provided `NaN`, the value is ignored (known mean, W=1)', function test( t ) { + var expected; + var data; + var acc; + var v; + var i; + + acc = incrnanmcv( 1, 3.14 ); + + data = [ + NaN, + 3.14, + 3.14, + NaN, + 3.14, + 3.14, + 3.14, + NaN, + 3.14, + 3.14, + 3.14, + NaN, + 3.14, + 3.14, + NaN, + NaN, + NaN, + NaN, + 3.14 + ]; + + expected = [ + null, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ]; + + for ( i = 0; i < data.length; i++ ) { + v = acc( data[ i ] ); + if ( expected[ i ] === null ) { + t.strictEqual( v, null, 'returns expected value for window '+i ); + t.strictEqual( acc(), null, 'returns expected value for window '+i ); + } else { + t.strictEqual( v, expected[ i ], 'returns expected value for window '+i ); + t.strictEqual( acc(), expected[ i ], 'returns expected value for window '+i ); + } + } + t.end(); +});